From 82e8e4bb46630b9581c39c7b98885df4411027ce Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Tue, 21 May 2019 11:56:22 +0200 Subject: [PATCH 001/349] Initial version of bounded_error_hausdorff method. --- .../Polygon_mesh_processing/CMakeLists.txt | 9 +- ...usdorff_bounded_error_distance_example.cpp | 33 +++ .../CGAL/Polygon_mesh_processing/distance.h | 201 +++++++++++++++++- 3 files changed, 237 insertions(+), 6 deletions(-) create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index 2f853f6cbe6..4053c3a4ced 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -20,7 +20,7 @@ find_package( CGAL QUIET COMPONENTS ) if ( NOT CGAL_FOUND ) message(STATUS "This project requires the CGAL library, and will not be compiled.") - return() + return() endif() @@ -31,7 +31,7 @@ if ( NOT Boost_FOUND ) message(STATUS "This project requires the Boost library, and will not be compiled.") - return() + return() endif() @@ -55,8 +55,10 @@ find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) find_package( TBB ) create_single_source_cgal_program( "hausdorff_distance_remeshing_example.cpp") +create_single_source_cgal_program( "hausdorff_bounded_error_distance_example.cpp") if( TBB_FOUND ) CGAL_target_use_TBB(hausdorff_distance_remeshing_example) + CGAL_target_use_TBB(hausdorff_bounded_error_distance_example) else() message( STATUS "NOTICE: Intel TBB was not found. hausdorff_distance_example will use sequential code." ) endif() @@ -118,6 +120,3 @@ target_link_libraries( stitch_borders_example_OM PRIVATE ${OPENMESH_LIBRARIES} ) create_single_source_cgal_program( "triangulate_faces_example_OM.cpp") target_link_libraries( triangulate_faces_example_OM PRIVATE ${OPENMESH_LIBRARIES} ) endif(OpenMesh_FOUND) - - - diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp new file mode 100644 index 00000000000..dd32a2b5e4e --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +#if defined(CGAL_LINKED_WITH_TBB) +#define TAG CGAL::Parallel_tag +#else +#define TAG CGAL::Sequential_tag +#endif + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::Point_3 Point; +typedef CGAL::Surface_mesh Mesh; + +namespace PMP = CGAL::Polygon_mesh_processing; + +int main() +{ + Mesh tm1, tm2; + CGAL::make_tetrahedron(Point(.0,.0,.0), + Point(2,.0,.0), + Point(1,1,1), + Point(1,.0,2), + tm1); + tm2=tm1; + CGAL::Polygon_mesh_processing::isotropic_remeshing(tm2.faces(),.05, tm2); + + std::cout << "Approximated Hausdorff distance: " + << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance + (tm1, tm2, 0.001) + << std::endl; +} diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 944fe523fb3..1ef31ac4f8c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -809,8 +810,206 @@ double approximate_symmetric_Hausdorff_distance(const TriangleMesh& tm1, tm1, tm2, parameters::all_default(), parameters::all_default()); } +//////////////////////////////////////////////////////////////////////// + +namespace internal { +/* +#if defined(CGAL_LINKED_WITH_TBB) +template +struct Distance_computation{ + const AABB_tree& tree; + const std::vector& sample_points; + Point_3 initial_hint; + tbb::atomic* distance; + + Distance_computation( + const AABB_tree& tree, + const Point_3& p, + const std::vector& sample_points, + tbb::atomic* d) + : tree(tree) + , sample_points(sample_points) + , initial_hint(p) + , distance(d) + {} + + void + operator()(const tbb::blocked_range& range) const + { + Point_3 hint = initial_hint; + double hdist = 0; + for( std::size_t i = range.begin(); i != range.end(); ++i) + { + hint = tree.closest_point(sample_points[i], hint); + typename Kernel_traits::Kernel::Compute_squared_distance_3 squared_distance; + double d = to_double(CGAL::approximate_sqrt( squared_distance(hint,sample_points[i]) )); + if (d>hdist) hdist=d; + } + + // update max value stored in distance + double current_value = *distance; + while( current_value < hdist ) + { + current_value = distance->compare_and_swap(hdist, current_value); + } + } +}; +#endif +*/ +template +double bounded_error_Hausdorff_impl( + const TriangleMesh& tm1, + const TriangleMesh& tm2, + const typename Kernel::FT& error_bound, + VPM1 vpm1, + VPM2 vpm2) +{ + CGAL_assertion_code( bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2) ); + CGAL_assertion_msg (is_triangle, + "One of the meshes is not triangulated. Distance computing impossible."); + + typedef typename Kernel::Point_3 Point_3; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef CGAL::Spatial_sort_traits_adapter_3 Search_traits_3; + + std::vector tm1_vertices; + tm1_vertices.reserve(num_vertices(tm1)); + tm1_vertices.insert(tm1_vertices.end(),vertices(tm1).begin(),vertices(tm1).end()); + + // Sort vertices along a Hilbert curve + spatial_sort( tm1_vertices.begin(), + tm1_vertices.end(), + Search_traits_3(vpm1) ); + + typedef AABB_face_graph_triangle_primitive TM2_primitive; + typedef AABB_tree< AABB_traits > TM2_tree; + + // Build an AABB tree on the second mesh + TM2_tree tm2_tree( faces(tm2).begin(), faces(tm2).end(), tm2, vpm2 ); + tm2_tree.build(); + tm2_tree.accelerate_distance_queries(); + Point_3 hint = get(vpm2, *vertices(tm2).begin()); + +#if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg (!(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); +#else + // if (boost::is_convertible::value) + // { + // tbb::atomic distance; + // distance=0; + // Distance_computation f(tm2_tree + // , hint, sample_points, &distance); + // tbb::parallel_for(tbb::blocked_range(0, sample_points.size()), f); + // return distance; + // } + // else +#endif + { + double hdist = 0; + for(const typename Kernel::Point_3& pt : sample_points) + { + hint = tree.closest_point(pt, hint); + typename Kernel::Compute_squared_distance_3 squared_distance; + typename Kernel::FT dist = squared_distance(hint,pt); + double d = to_double(CGAL::approximate_sqrt(dist)); + if(d>hdist) + hdist=d; + } + return hdist; + } + return 0.; } -} // end of namespace CGAL::Polygon_mesh_processing + +} //end of namespace internal + +/** + * \ingroup PMP_distance_grp + * computes the approximate Hausdorff distance from `tm1` to `tm2` by returning + * the distance of the farthest point from `tm2` amongst a sampling of `tm1` + * generated with the function `sample_triangle_mesh()` with + * `tm1` and `np1` as parameter. + * + * A parallel version is provided and requires the executable to be + * linked against the Intel TBB library. + * To control the number of threads used, the user may use the `tbb::task_scheduler_init` class. + * See the TBB documentation + * for more details. + * + * @tparam Concurrency_tag enables sequential versus parallel algorithm. + * Possible values are `Sequential_tag` + * and `Parallel_tag`. + * @tparam TriangleMesh a model of the concept `FaceListGraph` + * @tparam NamedParameters1 a sequence of \ref pmp_namedparameters "Named Parameters" for `tm1` + * @tparam NamedParameters2 a sequence of \ref pmp_namedparameters "Named Parameters" for `tm2` + * + * @param tm1 the triangle mesh that will be sampled + * @param tm2 the triangle mesh to compute the distance to + * @param np1 optional sequence of \ref pmp_namedparameters "Named Parameters" for `tm1` passed to `sample_triangle_mesh()`. + * + * @param np2 optional sequence of \ref pmp_namedparameters "Named Parameters" for `tm2` among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm2` + * If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` must be available in `TriangleMesh` + * and in all places where `vertex_point_map` is used. + * \cgalParamEnd + * \cgalNamedParamsEnd + * The function `CGAL::parameters::all_default()` can be used to indicate to use the default values for + * `np1` and specify custom values for `np2` + */ +template< class Concurrency_tag, + class TriangleMesh, + class NamedParameters1, + class NamedParameters2> +double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, + const TriangleMesh& tm2, + double error_bound, + const NamedParameters1& np1, + const NamedParameters2& np2) +{ + typedef typename GetGeomTraits::type Geom_traits; + + typedef typename GetVertexPointMap::const_type Vpm1; + typedef typename GetVertexPointMap::const_type Vpm2; + + using boost::choose_param; + using boost::get_param; + + Vpm1 vpm1 = choose_param(get_param(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, tm1)); + Vpm2 vpm2 = choose_param(get_param(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, tm2)); + + return internal::bounded_error_Hausdorff_impl(tm1, tm2, error_bound, vpm1, vpm2); +} + +template< class Concurrency_tag, + class TriangleMesh, + class NamedParameters1> +double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, + const TriangleMesh& tm2, + double error_bound, + const NamedParameters1& np1) +{ + return bounded_error_Hausdorff_distance(tm1, tm2, error_bound, np1, parameters::all_default()); +} + +template< class Concurrency_tag, + class TriangleMesh> +double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, + const TriangleMesh& tm2, + double error_bound) +{ + return bounded_error_Hausdorff_distance(tm1, tm2, error_bound, parameters::all_default() ); +} + +} } // end of namespace CGAL::Polygon_mesh_processing #endif //CGAL_POLYGON_MESH_PROCESSING_DISTANCE_H From 04a05c0db1ca947481a6964802cab22bf8ec490f Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Tue, 21 May 2019 14:00:43 +0200 Subject: [PATCH 002/349] Implemented distance computation from mesh_1 vertices to mesh_2 triangles. --- .../CGAL/Polygon_mesh_processing/distance.h | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 1ef31ac4f8c..fe37c15ff3c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -874,7 +874,10 @@ double bounded_error_Hausdorff_impl( typedef typename Kernel::Point_3 Point_3; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef CGAL::Spatial_sort_traits_adapter_3 Search_traits_3; + typedef CGAL::dynamic_vertex_property_t> Vertex_property_tag; + typedef typename boost::property_map::const_type Vertex_closest_triangle_map; std::vector tm1_vertices; tm1_vertices.reserve(num_vertices(tm1)); @@ -892,7 +895,9 @@ double bounded_error_Hausdorff_impl( TM2_tree tm2_tree( faces(tm2).begin(), faces(tm2).end(), tm2, vpm2 ); tm2_tree.build(); tm2_tree.accelerate_distance_queries(); - Point_3 hint = get(vpm2, *vertices(tm2).begin()); + std::pair hint = tm2_tree.any_reference_point_and_id(); + + Vertex_closest_triangle_map vctm = get(Vertex_property_tag(), tm1); #if !defined(CGAL_LINKED_WITH_TBB) CGAL_static_assertion_msg (!(boost::is_convertible::value), @@ -910,17 +915,17 @@ double bounded_error_Hausdorff_impl( // else #endif { - double hdist = 0; - for(const typename Kernel::Point_3& pt : sample_points) + for(vertex_descriptor vd : tm1_vertices) { - hint = tree.closest_point(pt, hint); + typename boost::property_traits::reference pt = get(vpm1, vd); + hint = tm2_tree.closest_point_and_primitive(pt, hint); typename Kernel::Compute_squared_distance_3 squared_distance; - typename Kernel::FT dist = squared_distance(hint,pt); + typename Kernel::FT dist = squared_distance(hint.first, pt); double d = to_double(CGAL::approximate_sqrt(dist)); - if(d>hdist) - hdist=d; + + + put(vctm, vd, std::make_pair(d, hint.second)); } - return hdist; } return 0.; } From 951e4a7f44cf635b630b39cf70fa1e6f1c111066 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Tue, 21 May 2019 17:11:18 +0200 Subject: [PATCH 003/349] Implement first rough approximation. --- .../CGAL/Polygon_mesh_processing/distance.h | 78 ++++++++++++++++--- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index fe37c15ff3c..ef9998b13ea 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -49,6 +49,8 @@ #include +#include + namespace CGAL{ namespace Polygon_mesh_processing { namespace internal{ @@ -864,7 +866,7 @@ template TM2_primitive; + typedef AABB_tree< AABB_traits > TM2_tree; typedef typename Kernel::Point_3 Point_3; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef std::pair Hausdorff_bounds; typedef CGAL::Spatial_sort_traits_adapter_3 Search_traits_3; typedef CGAL::dynamic_vertex_property_t> Vertex_property_tag; + typedef CGAL::dynamic_face_property_t Face_property_tag; + typedef typename boost::property_map::const_type Vertex_closest_triangle_map; + typedef typename boost::property_map::const_type Triangle_hausdorff_bounds; + + typename Kernel::Compute_squared_distance_3 squared_distance; + typename Kernel::Construct_projected_point_3 project_point; + typename Kernel::FT dist; std::vector tm1_vertices; tm1_vertices.reserve(num_vertices(tm1)); @@ -888,9 +903,6 @@ double bounded_error_Hausdorff_impl( tm1_vertices.end(), Search_traits_3(vpm1) ); - typedef AABB_face_graph_triangle_primitive TM2_primitive; - typedef AABB_tree< AABB_traits > TM2_tree; - // Build an AABB tree on the second mesh TM2_tree tm2_tree( faces(tm2).begin(), faces(tm2).end(), tm2, vpm2 ); tm2_tree.build(); @@ -898,11 +910,13 @@ double bounded_error_Hausdorff_impl( std::pair hint = tm2_tree.any_reference_point_and_id(); Vertex_closest_triangle_map vctm = get(Vertex_property_tag(), tm1); + Triangle_hausdorff_bounds thb = get(Face_property_tag(), tm1); #if !defined(CGAL_LINKED_WITH_TBB) CGAL_static_assertion_msg (!(boost::is_convertible::value), "Parallel_tag is enabled but TBB is unavailable."); #else + // TODO implement parallelized version of the below here. // if (boost::is_convertible::value) // { // tbb::atomic distance; @@ -915,19 +929,61 @@ double bounded_error_Hausdorff_impl( // else #endif { + // For each vertex in the first mesh, find the closest triangle in the + // second mesh, store it and also store the distance to this triangle + // in a dynamic vertex property for(vertex_descriptor vd : tm1_vertices) { typename boost::property_traits::reference pt = get(vpm1, vd); hint = tm2_tree.closest_point_and_primitive(pt, hint); - typename Kernel::Compute_squared_distance_3 squared_distance; - typename Kernel::FT dist = squared_distance(hint.first, pt); - double d = to_double(CGAL::approximate_sqrt(dist)); - - + dist = squared_distance(hint.first, pt); + double d = to_double(dist); put(vctm, vd, std::make_pair(d, hint.second)); } + + Triangle_from_face_descriptor_map face_to_triangle_map(&tm2, vpm2); + double h_lower = 0.; + double h_upper = std::numeric_limits::infinity(); + + for(face_descriptor fd : faces(tm1)) + { + double h_triangle_lower = 0.; + double h_triangle_upper = std::numeric_limits::infinity(); + halfedge_descriptor hd = halfedge(fd, tm1); + + std::array face_vertices = {source(hd,tm1), target(hd,tm1), target(next(hd, tm1),tm1)}; + + std::array,3> vertex_properties = { + get(vctm, face_vertices[0]), + get(vctm, face_vertices[1]), + get(vctm, face_vertices[2])}; + + std::array triangles_in_B = { + get(face_to_triangle_map, vertex_properties[0].second), + get(face_to_triangle_map, vertex_properties[1].second), + get(face_to_triangle_map, vertex_properties[2].second)}; + + for(int i=0; i<3; ++i) + { + // Iterate over the vertices by i + h_triangle_lower = (std::max)(h_triangle_lower, vertex_properties[i].first); + // Iterate over the triangles by i + double face_distance_1 = vertex_properties[i].second==vertex_properties[(i+1)%3].second + ? vertex_properties[(i+1)%3].first + : squared_distance(project_point(triangles_in_B[i], get(vpm1, face_vertices[(i+1)%3])), get(vpm1, face_vertices[(i+1)%3])); + double face_distance_2 = vertex_properties[i].second==vertex_properties[(i+2)%3].second + ? vertex_properties[(i+2)%3].first + : squared_distance(project_point(triangles_in_B[i], get(vpm1, face_vertices[(i+2)%3])), get(vpm1, face_vertices[(i+2)%3])); + + h_triangle_upper = (std::min)((std::max)((std::max)(face_distance_1, face_distance_2), vertex_properties[i].first), h_triangle_upper); + } + put(thb, fd, Hausdorff_bounds(h_triangle_lower, h_triangle_upper)); + h_lower = (std::max)(h_lower, h_triangle_lower); + h_upper = (std::max)(h_upper, h_triangle_upper); + } + + return (h_lower+h_upper)/2.; } - return 0.; } } //end of namespace internal @@ -991,7 +1047,7 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, Vpm2 vpm2 = choose_param(get_param(np2, internal_np::vertex_point), get_const_property_map(vertex_point, tm2)); - return internal::bounded_error_Hausdorff_impl(tm1, tm2, error_bound, vpm1, vpm2); + return internal::bounded_error_Hausdorff_impl(tm1, tm2, error_bound*error_bound, vpm1, vpm2); } template< class Concurrency_tag, From 9df0d3fc8029142890f2d17a7888dbd32944a187 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Tue, 21 May 2019 18:30:15 +0200 Subject: [PATCH 004/349] Fix initialization of global upper bound, include TODOs for further steps. --- .../CGAL/Polygon_mesh_processing/distance.h | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index ef9998b13ea..36cce31a096 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -943,8 +943,11 @@ double bounded_error_Hausdorff_impl( Triangle_from_face_descriptor_map face_to_triangle_map(&tm2, vpm2); double h_lower = 0.; - double h_upper = std::numeric_limits::infinity(); + double h_upper = 0.; + // For each triangle in the first mesh, initialize its local upper and + // lower bound and store these in a dynamic face property for furture + // reference for(face_descriptor fd : faces(tm1)) { double h_triangle_lower = 0.; @@ -982,7 +985,26 @@ double bounded_error_Hausdorff_impl( h_upper = (std::max)(h_upper, h_triangle_upper); } - return (h_lower+h_upper)/2.; + // Initialize an array of candidate triangles in A to be procesed in the + // following + std::vector candidate_triangles; + + for(face_descriptor fd : faces(tm1)) + { + Hausdorff_bounds triangle_bounds = get(thb, fd); + if (triangle_bounds.second > h_lower) { + + // TODO culling on B + + candidate_triangles.push_back(fd); + } + } + + // TODO Iterate over candidate_triangles and kill those which cannot contribute anymore + + // TODO Send the remaining triangles to the Subdivision + + return (CGAL::approximate_sqrt(h_lower)+CGAL::approximate_sqrt(h_upper))/2.; } } From c28f0076fa758910398dffdc952e932354d0d2c4 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Thu, 6 Jun 2019 09:51:16 +0200 Subject: [PATCH 005/349] Add detailed comments on the code written so far and merge face processing loop into previous loop. --- .../CGAL/Polygon_mesh_processing/distance.h | 66 +++++++++++++------ 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 36cce31a096..22a6be53523 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -894,6 +894,7 @@ double bounded_error_Hausdorff_impl( typename Kernel::Construct_projected_point_3 project_point; typename Kernel::FT dist; + // Store all vertices of tm1 in a vector std::vector tm1_vertices; tm1_vertices.reserve(num_vertices(tm1)); tm1_vertices.insert(tm1_vertices.end(),vertices(tm1).begin(),vertices(tm1).end()); @@ -903,13 +904,16 @@ double bounded_error_Hausdorff_impl( tm1_vertices.end(), Search_traits_3(vpm1) ); - // Build an AABB tree on the second mesh + // Build an AABB tree on tm2 TM2_tree tm2_tree( faces(tm2).begin(), faces(tm2).end(), tm2, vpm2 ); tm2_tree.build(); tm2_tree.accelerate_distance_queries(); std::pair hint = tm2_tree.any_reference_point_and_id(); + // For each vertex in tm1, store the distance to the closest triangle of tm2 Vertex_closest_triangle_map vctm = get(Vertex_property_tag(), tm1); + // For each triangle in tm1, sotre its respective local lower and upper bound + // on the Hausdorff measure Triangle_hausdorff_bounds thb = get(Face_property_tag(), tm1); #if !defined(CGAL_LINKED_WITH_TBB) @@ -929,38 +933,55 @@ double bounded_error_Hausdorff_impl( // else #endif { - // For each vertex in the first mesh, find the closest triangle in the - // second mesh, store it and also store the distance to this triangle - // in a dynamic vertex property + /* + / For each vertex in the first mesh, find the closest triangle in the + / second mesh, store it and also store the distance to this triangle + / in a dynamic vertex property + */ for(vertex_descriptor vd : tm1_vertices) { + // Get the point represented by the vertex typename boost::property_traits::reference pt = get(vpm1, vd); + // Use the AABB tree to find the closest point and face in tm2 hint = tm2_tree.closest_point_and_primitive(pt, hint); + // Compute the distance of the point to the closest point in tm2 dist = squared_distance(hint.first, pt); double d = to_double(dist); + // Store the distance and the closest triangle in the corresponding map put(vctm, vd, std::make_pair(d, hint.second)); } + // Maps the faces of tm2 to actual triangles Triangle_from_face_descriptor_map face_to_triangle_map(&tm2, vpm2); + // Initialize global bounds on the Hausdorff measure double h_lower = 0.; double h_upper = 0.; + // Initialize an array of candidate triangles in A to be procesed in the + // following + std::vector candidate_triangles; - // For each triangle in the first mesh, initialize its local upper and - // lower bound and store these in a dynamic face property for furture - // reference + /* + / For each triangle in the first mesh, initialize its local upper and + / lower bound and store these in a dynamic face property for furture + / reference + */ for(face_descriptor fd : faces(tm1)) { + // Initialize the local bounds for the current face fd double h_triangle_lower = 0.; double h_triangle_upper = std::numeric_limits::infinity(); - halfedge_descriptor hd = halfedge(fd, tm1); + // Create a halfedge descriptor for the current face and store the vertices + halfedge_descriptor hd = halfedge(fd, tm1); std::array face_vertices = {source(hd,tm1), target(hd,tm1), target(next(hd, tm1),tm1)}; + // Get the distance and closest triangle in tm2 for each vertex of fd std::array,3> vertex_properties = { get(vctm, face_vertices[0]), get(vctm, face_vertices[1]), get(vctm, face_vertices[2])}; + // Convert the closest faces of tm2 to triangles std::array triangles_in_B = { get(face_to_triangle_map, vertex_properties[0].second), get(face_to_triangle_map, vertex_properties[1].second), @@ -968,9 +989,13 @@ double bounded_error_Hausdorff_impl( for(int i=0; i<3; ++i) { - // Iterate over the vertices by i + // Iterate over the vertices by i, the distance to the closest point in + // tm2 computed above is a lower bound for the local triangle h_triangle_lower = (std::max)(h_triangle_lower, vertex_properties[i].first); - // Iterate over the triangles by i + + // Iterate over the triangles by i, if the triangles are the same, we do + // not need to compute the distance, only compute it if the triangles + // differ double face_distance_1 = vertex_properties[i].second==vertex_properties[(i+1)%3].second ? vertex_properties[(i+1)%3].first : squared_distance(project_point(triangles_in_B[i], get(vpm1, face_vertices[(i+1)%3])), get(vpm1, face_vertices[(i+1)%3])); @@ -978,21 +1003,22 @@ double bounded_error_Hausdorff_impl( ? vertex_properties[(i+2)%3].first : squared_distance(project_point(triangles_in_B[i], get(vpm1, face_vertices[(i+2)%3])), get(vpm1, face_vertices[(i+2)%3])); - h_triangle_upper = (std::min)((std::max)((std::max)(face_distance_1, face_distance_2), vertex_properties[i].first), h_triangle_upper); + // Update the local lower bound of the triangle + h_triangle_upper = (std::min)( + (std::max)( + (std::max)(face_distance_1, face_distance_2), + vertex_properties[i].first), + h_triangle_upper); } + + // Store the computed lower and upper bound in a dynamic face property put(thb, fd, Hausdorff_bounds(h_triangle_lower, h_triangle_upper)); h_lower = (std::max)(h_lower, h_triangle_lower); h_upper = (std::max)(h_upper, h_triangle_upper); - } - // Initialize an array of candidate triangles in A to be procesed in the - // following - std::vector candidate_triangles; - - for(face_descriptor fd : faces(tm1)) - { - Hausdorff_bounds triangle_bounds = get(thb, fd); - if (triangle_bounds.second > h_lower) { + // Only process the triangle further if it can still contribute to a + // Hausdorff distance + if (h_triangle_upper > h_lower) { // TODO culling on B From a67fa389f505447c5564dd67a89f2cec7357965a Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Sun, 9 Jun 2019 17:17:54 +0200 Subject: [PATCH 006/349] Add traversal trait for Hausdorff-based AABB traversal on the first triangle mesh. --- .../CGAL/Polygon_mesh_processing/distance.h | 20 ++++- ...traversal_traits_with_Hausdorff_distance.h | 80 +++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 22a6be53523..85d4ff65c29 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -17,14 +17,13 @@ // SPDX-License-Identifier: GPL-3.0+ // // -// Author(s) : Maxime Gimeno and Sebastien Loriot +// Author(s) : Maxime Gimeno, Sebastien Loriot, Martin Skrodzki #ifndef CGAL_POLYGON_MESH_PROCESSING_DISTANCE_H #define CGAL_POLYGON_MESH_PROCESSING_DISTANCE_H #include - #include #include #include @@ -41,6 +40,8 @@ #include #include +#include + #ifdef CGAL_LINKED_WITH_TBB #include #include @@ -874,8 +875,12 @@ double bounded_error_Hausdorff_impl( CGAL_assertion_msg (is_triangle, "One of the meshes is not triangulated. Distance computing impossible."); + typedef AABB_face_graph_triangle_primitive TM1_primitive; typedef AABB_face_graph_triangle_primitive TM2_primitive; + typedef AABB_tree< AABB_traits > TM1_tree; typedef AABB_tree< AABB_traits > TM2_tree; + typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; + typedef typename Kernel::Point_3 Point_3; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -904,6 +909,15 @@ double bounded_error_Hausdorff_impl( tm1_vertices.end(), Search_traits_3(vpm1) ); + // Build an AABB tree on tm1 + TM1_tree tm1_tree( faces(tm1).begin(), faces(tm1).end(), tm1, vpm1 ); + tm1_tree.build(); + tm1_tree.accelerate_distance_queries(); + + // Build traversal traits for tm1_tree + Hausdorff_primitive_traits traversal_traits( tm1_tree.traits() ); + tm1_tree.traversal( Point_3(0,0,0), traversal_traits ); + // Build an AABB tree on tm2 TM2_tree tm2_tree( faces(tm2).begin(), faces(tm2).end(), tm2, vpm2 ); tm2_tree.build(); @@ -1026,6 +1040,8 @@ double bounded_error_Hausdorff_impl( } } + + // TODO Iterate over candidate_triangles and kill those which cannot contribute anymore // TODO Send the remaining triangles to the Subdivision diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h new file mode 100644 index 00000000000..58bf1d85805 --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -0,0 +1,80 @@ +// Copyright (c) 2019 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0+ +// +// +// Author(s) : Sebastien Loriot, Martin Skrodzki +// + +#ifndef CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_HAUSDORFF_DISTANCE +#define CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_HAUSDORFF_DISTANCE + +#include + +namespace CGAL { + + /** + * @class Hausdorff_primitive_traits + */ + template + class Hausdorff_primitive_traits + { + typedef typename AABBTraits::Primitive Primitive; + typedef ::CGAL::AABB_node Node; + + public: + Hausdorff_primitive_traits(const AABBTraits& traits) + : m_traits(traits) {} + + // Explore the whole tree, i.e. always enter children if the methods + // do_intersect() below determines that it is worthwhile. + bool go_further() const { return true; } + + // Compute the explicit Hausdorff distance to the given primitive + void intersection(const Query& query, const Primitive& primitive) + { + // Have reached a single triangle + std::cout << "Reached Triangle " << primitive.id() << '\n'; + + /* TODO implement handling of a single triangle + / - Call Culling on B (First maybe don't cull, but only consider closest + / triangle), obtain local bounds for the triangle + / - Update global Hausdorff bounds according to the obtained local bounds + / - return the current best known global bounds + */ + } + + bool do_intersect(const Query& query, const Node& node) const + { + // Have reached a node, determine whether or not to enter it + + /* TODO implement processing of an AABB node + / - Determine distance of the node's bounding box (node.bbox()) to the + / closest point in B (First maybe any point) + / - If the distance is larger than the global lower bound, enter the + / node, i.e. return true. + */ + return true; + //return m_traits.do_intersect_object()(query, node.bbox()); + } + + private: + const AABBTraits& m_traits; + }; +} + +#endif //CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_HAUSDORFF_DISTANCE From 04c84efb3a5f383c87d7c8f0921a351954de9f98 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Sun, 9 Jun 2019 18:08:07 +0200 Subject: [PATCH 007/349] Add second traversal trait for Hausdorff-based AABB traversal on the second triangle mesh. --- .../CGAL/Polygon_mesh_processing/distance.h | 10 +- ...traversal_traits_with_Hausdorff_distance.h | 101 +++++++++++++++++- 2 files changed, 102 insertions(+), 9 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 85d4ff65c29..57a3df15b13 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -882,6 +882,7 @@ double bounded_error_Hausdorff_impl( typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; typedef typename Kernel::Point_3 Point_3; + typedef typename Kernel::Triangle_3 Triangle_3; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; @@ -914,16 +915,17 @@ double bounded_error_Hausdorff_impl( tm1_tree.build(); tm1_tree.accelerate_distance_queries(); - // Build traversal traits for tm1_tree - Hausdorff_primitive_traits traversal_traits( tm1_tree.traits() ); - tm1_tree.traversal( Point_3(0,0,0), traversal_traits ); - // Build an AABB tree on tm2 TM2_tree tm2_tree( faces(tm2).begin(), faces(tm2).end(), tm2, vpm2 ); tm2_tree.build(); tm2_tree.accelerate_distance_queries(); std::pair hint = tm2_tree.any_reference_point_and_id(); + // Build traversal traits for tm1_tree and tm2_tree + Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits() ); + Hausdorff_primitive_traits_tm2 traversal_traits_tm2( tm2_tree.traits() ); + tm1_tree.traversal( Point_3(0,0,0), traversal_traits_tm1 ); + // For each vertex in tm1, store the distance to the closest triangle of tm2 Vertex_closest_triangle_map vctm = get(Vertex_property_tag(), tm1); // For each triangle in tm1, sotre its respective local lower and upper bound diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 58bf1d85805..5ff34e3208d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -27,18 +27,24 @@ namespace CGAL { + typedef std::pair Hausdorff_bounds; + /** - * @class Hausdorff_primitive_traits + * @class Hausdorff_primitive_traits_tm1 */ template - class Hausdorff_primitive_traits + class Hausdorff_primitive_traits_tm1 { typedef typename AABBTraits::Primitive Primitive; typedef ::CGAL::AABB_node Node; public: - Hausdorff_primitive_traits(const AABBTraits& traits) - : m_traits(traits) {} + Hausdorff_primitive_traits_tm1(const AABBTraits& traits) + : m_traits(traits) { + // Initialize the global bounds with 0., they will only grow. + h_lower = 0.; + h_upper = 0.; + } // Explore the whole tree, i.e. always enter children if the methods // do_intersect() below determines that it is worthwhile. @@ -48,7 +54,7 @@ namespace CGAL { void intersection(const Query& query, const Primitive& primitive) { // Have reached a single triangle - std::cout << "Reached Triangle " << primitive.id() << '\n'; + std::cout << "Reached Triangle in TM1: " << primitive.id() << '\n'; /* TODO implement handling of a single triangle / - Call Culling on B (First maybe don't cull, but only consider closest @@ -58,6 +64,8 @@ namespace CGAL { */ } + // Determine whether child nodes will still contribute to a larger + // Hausdorff distance and thus have to be entered bool do_intersect(const Query& query, const Node& node) const { // Have reached a node, determine whether or not to enter it @@ -74,6 +82,89 @@ namespace CGAL { private: const AABBTraits& m_traits; + // Global Hausdorff bounds to be taken track of during the traversal + double h_lower; + double h_upper; + }; + + + /** + * @class Hausdorff_primitive_traits_tm2 + */ + template + class Hausdorff_primitive_traits_tm2 + { + typedef typename AABBTraits::Primitive Primitive; + typedef ::CGAL::AABB_node Node; + + public: + Hausdorff_primitive_traits_tm2(const AABBTraits& traits) + : m_traits(traits) { + // Initialize the global bounds with 0., they will only grow. + h_local_upper = std::numeric_limits::infinity(); + h_local_lower_0 = std::numeric_limits::infinity(); + h_local_lower_1 = std::numeric_limits::infinity(); + h_local_lower_2 = std::numeric_limits::infinity(); + } + + // Explore the whole tree, i.e. always enter children if the methods + // do_intersect() below determines that it is worthwhile. + bool go_further() const { return true; } + + // Compute the explicit Hausdorff distance to the given primitive + void intersection(const Query& query, const Primitive& primitive) + { + // Have reached a single triangle + std::cout << "Reached Triangle in TM2:" << primitive.id() << '\n'; + + double distance = std::numeric_limits::infinity(); + /* + / TODO Determine the distance accroding to + / min_{b \in primitive} ( max_{vertex in query} ( d(vertex, b))) + */ + + // Update local upper bound + if ( distance < h_local_upper ) h_local_upper = distance; + + double vertex_distance = std::numeric_limits::infinity(); + /* + / TODO For all vertices v of the query triangle, determine the distance by + / min_{b \in primitive} ( d(v, b) ) + / Update h_local_lower_i accordingly + */ + + h_local_lower = std::max( std::max (h_local_lower_0, h_local_lower_1), h_local_lower_2 ); + } + + // Determine whether child nodes will still contribute to a smaller + // Hausdorff distance and thus have to be entered + bool do_intersect(const Query& query, const Node& node) const + { + // Have reached a node, determine whether or not to enter it + double distance = std::numeric_limits::infinity(); + + /* TODO Determine distance of the node's bounding box (node.bbox()) to + / the triangle given by the query object. + */ + + if (distance <= h_local_upper) return true; + else return false; + } + + Hausdorff_bounds get_local_bounds() + { + return Hausdorff_bounds( h_local_lower, h_local_upper ); + } + + private: + const AABBTraits& m_traits; + // Local Hausdorff bounds for the query triangle + double h_local_upper; + double h_local_lower; + // Local Hausdorff bounds for the query triangle's vertices + double h_local_lower_0; + double h_local_lower_1; + double h_local_lower_2; }; } From 14006623d98b9a756936ac19149093dafdeed28b Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Sun, 9 Jun 2019 18:26:45 +0200 Subject: [PATCH 008/349] Fixed initialization of local Hausdorff bounds. --- .../internal/AABB_traversal_traits_with_Hausdorff_distance.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 5ff34e3208d..6461ea2b8e8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -126,7 +126,7 @@ namespace CGAL { // Update local upper bound if ( distance < h_local_upper ) h_local_upper = distance; - double vertex_distance = std::numeric_limits::infinity(); + double vertex_distance = 0.; /* / TODO For all vertices v of the query triangle, determine the distance by / min_{b \in primitive} ( d(v, b) ) @@ -141,7 +141,7 @@ namespace CGAL { bool do_intersect(const Query& query, const Node& node) const { // Have reached a node, determine whether or not to enter it - double distance = std::numeric_limits::infinity(); + double distance = 0.; /* TODO Determine distance of the node's bounding box (node.bbox()) to / the triangle given by the query object. From d93aa73e7ef2069166bbb79b8c61d4883ee7ec57 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Tue, 18 Jun 2019 06:12:33 +0200 Subject: [PATCH 009/349] Pass tm2_tree instance to the traversal of tm1 --- .../CGAL/Polygon_mesh_processing/distance.h | 3 +- ...traversal_traits_with_Hausdorff_distance.h | 125 +++++++++--------- 2 files changed, 67 insertions(+), 61 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 57a3df15b13..31ff50ccff7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -922,8 +922,7 @@ double bounded_error_Hausdorff_impl( std::pair hint = tm2_tree.any_reference_point_and_id(); // Build traversal traits for tm1_tree and tm2_tree - Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits() ); - Hausdorff_primitive_traits_tm2 traversal_traits_tm2( tm2_tree.traits() ); + Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits(), tm2_tree ); tm1_tree.traversal( Point_3(0,0,0), traversal_traits_tm1 ); // For each vertex in tm1, store the distance to the closest triangle of tm2 diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 6461ea2b8e8..7684159ba4c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -29,65 +29,6 @@ namespace CGAL { typedef std::pair Hausdorff_bounds; - /** - * @class Hausdorff_primitive_traits_tm1 - */ - template - class Hausdorff_primitive_traits_tm1 - { - typedef typename AABBTraits::Primitive Primitive; - typedef ::CGAL::AABB_node Node; - - public: - Hausdorff_primitive_traits_tm1(const AABBTraits& traits) - : m_traits(traits) { - // Initialize the global bounds with 0., they will only grow. - h_lower = 0.; - h_upper = 0.; - } - - // Explore the whole tree, i.e. always enter children if the methods - // do_intersect() below determines that it is worthwhile. - bool go_further() const { return true; } - - // Compute the explicit Hausdorff distance to the given primitive - void intersection(const Query& query, const Primitive& primitive) - { - // Have reached a single triangle - std::cout << "Reached Triangle in TM1: " << primitive.id() << '\n'; - - /* TODO implement handling of a single triangle - / - Call Culling on B (First maybe don't cull, but only consider closest - / triangle), obtain local bounds for the triangle - / - Update global Hausdorff bounds according to the obtained local bounds - / - return the current best known global bounds - */ - } - - // Determine whether child nodes will still contribute to a larger - // Hausdorff distance and thus have to be entered - bool do_intersect(const Query& query, const Node& node) const - { - // Have reached a node, determine whether or not to enter it - - /* TODO implement processing of an AABB node - / - Determine distance of the node's bounding box (node.bbox()) to the - / closest point in B (First maybe any point) - / - If the distance is larger than the global lower bound, enter the - / node, i.e. return true. - */ - return true; - //return m_traits.do_intersect_object()(query, node.bbox()); - } - - private: - const AABBTraits& m_traits; - // Global Hausdorff bounds to be taken track of during the traversal - double h_lower; - double h_upper; - }; - - /** * @class Hausdorff_primitive_traits_tm2 */ @@ -166,6 +107,72 @@ namespace CGAL { double h_local_lower_1; double h_local_lower_2; }; + + /** + * @class Hausdorff_primitive_traits_tm1 + */ + template + class Hausdorff_primitive_traits_tm1 + { + typedef AABB_face_graph_triangle_primitive TM2_primitive; + typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; + typedef typename AABBTraits::Primitive Primitive; + typedef ::CGAL::AABB_node Node; + typedef typename Kernel::Triangle_3 Triangle_3; + typedef AABB_tree< AABB_traits > TM2_tree; + + public: + Hausdorff_primitive_traits_tm1(const AABBTraits& traits, const TM2_tree& tree) + : m_traits(traits), tm2_tree(tree) { + // Initialize the global bounds with 0., they will only grow. + h_lower = 0.; + h_upper = 0.; + } + + // Explore the whole tree, i.e. always enter children if the methods + // do_intersect() below determines that it is worthwhile. + bool go_further() const { return true; } + + // Compute the explicit Hausdorff distance to the given primitive + void intersection(const Query& query, const Primitive& primitive) + { + // Have reached a single triangle + std::cout << "Reached Triangle in TM1: " << primitive.id() << '\n'; + + + Hausdorff_primitive_traits_tm2 traversal_traits_tm2( tm2_tree.traits() ); + /* TODO implement handling of a single triangle + / - Call Culling on B (First maybe don't cull, but only consider closest + / triangle), obtain local bounds for the triangle + / - Update global Hausdorff bounds according to the obtained local bounds + / - return the current best known global bounds + */ + } + + // Determine whether child nodes will still contribute to a larger + // Hausdorff distance and thus have to be entered + bool do_intersect(const Query& query, const Node& node) const + { + // Have reached a node, determine whether or not to enter it + + /* TODO implement processing of an AABB node + / - Determine distance of the node's bounding box (node.bbox()) to the + / closest point in B (First maybe any point) + / - If the distance is larger than the global lower bound, enter the + / node, i.e. return true. + */ + return true; + //return m_traits.do_intersect_object()(query, node.bbox()); + } + + private: + const AABBTraits& m_traits; + // AABB tree for the second triangle meshes + const TM2_tree& tm2_tree; + // Global Hausdorff bounds to be taken track of during the traversal + double h_lower; + double h_upper; + }; } #endif //CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_HAUSDORFF_DISTANCE From a4112c4c8b32a17a1b05e3fe07ca60243ebb3efe Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Tue, 18 Jun 2019 07:01:06 +0200 Subject: [PATCH 010/349] Implement calling of TM2_tree traversal. --- ..._traversal_traits_with_Hausdorff_distance.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 7684159ba4c..c77a3a227cf 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -139,14 +139,18 @@ namespace CGAL { // Have reached a single triangle std::cout << "Reached Triangle in TM1: " << primitive.id() << '\n'; + // Call Culling on B with the single triangle found. + Hausdorff_primitive_traits_tm2 traversal_traits_tm2( tm2_tree.traits() ); + tm2_tree.traversal(primitive, traversal_traits_tm2); - Hausdorff_primitive_traits_tm2 traversal_traits_tm2( tm2_tree.traits() ); - /* TODO implement handling of a single triangle - / - Call Culling on B (First maybe don't cull, but only consider closest - / triangle), obtain local bounds for the triangle - / - Update global Hausdorff bounds according to the obtained local bounds - / - return the current best known global bounds - */ + // Update global Hausdorff bounds according to the obtained local bounds + Hausdorff_bounds local_bounds = traversal_traits_tm2.get_local_bounds(); + if (local_bounds.first > h_lower) { + h_lower = local_bounds.first; + } + if (local_bounds.second > h_upper) { + h_upper = local_bounds.second; + } } // Determine whether child nodes will still contribute to a larger From c76db1e3ab663de7a005c8378b4d4970b174e1b0 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Tue, 18 Jun 2019 07:27:33 +0200 Subject: [PATCH 011/349] Finish traversal traits of tm1, i.e. finish implementation of CullingOnA. --- ...traversal_traits_with_Hausdorff_distance.h | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index c77a3a227cf..6be21480eb3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -117,7 +117,9 @@ namespace CGAL { typedef AABB_face_graph_triangle_primitive TM2_primitive; typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; typedef typename AABBTraits::Primitive Primitive; + typedef typename AABBTraits::Bounding_box Bounding_box; typedef ::CGAL::AABB_node Node; + typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Triangle_3 Triangle_3; typedef AABB_tree< AABB_traits > TM2_tree; @@ -157,16 +159,30 @@ namespace CGAL { // Hausdorff distance and thus have to be entered bool do_intersect(const Query& query, const Node& node) const { - // Have reached a node, determine whether or not to enter it + /* Have reached a node, determine whether or not to enter it */ - /* TODO implement processing of an AABB node - / - Determine distance of the node's bounding box (node.bbox()) to the - / closest point in B (First maybe any point) - / - If the distance is larger than the global lower bound, enter the - / node, i.e. return true. - */ - return true; - //return m_traits.do_intersect_object()(query, node.bbox()); + // Get the bounding box of the nodes + Bounding_box bbox = node.bbox(); + // Compute its center + Point_3 center = Point_3( + (bbox.min(0) + bbox.max(0)) / 2, + (bbox.min(1) + bbox.max(1)) / 2, + (bbox.min(2) + bbox.max(2)) / 2); + // Find the point from TM2 closest to the center + Point_3 closest = tm2_tree.closest_point(center); + // Compute the distance of the center to the closest point in tm2 + double dist = approximate_sqrt(squared_distance(center, closest)); + // Compute the radius of the circumsphere of the bounding boxes + double radius = approximate_sqrt(squared_distance( + Point_3(bbox.min(0),bbox.min(1),bbox.min(2)), + Point_3(bbox.max(0),bbox.max(1),bbox.max(2))) + )/2.; + // If the distance is larger than the global lower bound, enter the node, i.e. return true. + if (dist + radius > h_lower) { + return true; + } else { + return false; + } } private: From 453ec1571ceb38dbbc283d3cfcea9de22a1db652 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Wed, 19 Jun 2019 18:47:41 +0200 Subject: [PATCH 012/349] Implement vertex (TM1) to triangle (TM2) distance in traversal processing. --- .../CGAL/Polygon_mesh_processing/distance.h | 2 +- ...traversal_traits_with_Hausdorff_distance.h | 62 ++++++++++++++++--- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 31ff50ccff7..4c269ce9823 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -922,7 +922,7 @@ double bounded_error_Hausdorff_impl( std::pair hint = tm2_tree.any_reference_point_and_id(); // Build traversal traits for tm1_tree and tm2_tree - Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits(), tm2_tree ); + Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2 ); tm1_tree.traversal( Point_3(0,0,0), traversal_traits_tm1 ); // For each vertex in tm1, store the distance to the closest triangle of tm2 diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 6be21480eb3..86cf640af02 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -32,15 +32,18 @@ namespace CGAL { /** * @class Hausdorff_primitive_traits_tm2 */ - template + template class Hausdorff_primitive_traits_tm2 { typedef typename AABBTraits::Primitive Primitive; typedef ::CGAL::AABB_node Node; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typename Kernel::Construct_projected_point_3 project_point; public: - Hausdorff_primitive_traits_tm2(const AABBTraits& traits) - : m_traits(traits) { + Hausdorff_primitive_traits_tm2(const AABBTraits& traits, const TriangleMesh& tm1, const TriangleMesh& tm2, const VPM1& vpm1, const VPM2& vpm2) + : m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2) { // Initialize the global bounds with 0., they will only grow. h_local_upper = std::numeric_limits::infinity(); h_local_lower_0 = std::numeric_limits::infinity(); @@ -58,12 +61,39 @@ namespace CGAL { // Have reached a single triangle std::cout << "Reached Triangle in TM2:" << primitive.id() << '\n'; - double distance = std::numeric_limits::infinity(); /* - / TODO Determine the distance accroding to + / Determine the distance accroding to / min_{b \in primitive} ( max_{vertex in query} ( d(vertex, b))) + / + / Here, we only have one triangle in B, i.e. tm2. Thus, it suffices to + / compute the distance of the vertices of the query triangles to the + / primitive triangle and use the maximum of the obtained distances. */ + // The query object is a triangle from TM1, get its vertices + halfedge_descriptor hd = halfedge(query.id(), m_tm1); + vertex_descriptor v0 = source(hd,m_tm1); + vertex_descriptor v1 = target(hd,m_tm1); + vertex_descriptor v2 = target(next(hd, m_tm1), m_tm1); + + // Compute distances of the vertices to the primitive triangle in TM2 + Triangle_from_face_descriptor_map face_to_triangle_map(&m_tm2, m_vpm2); + double v0_dist = squared_distance( + project_point(get(face_to_triangle_map, primitive.id()), get(m_vpm1, v0)), + get(m_vpm1, v0) + ); + double v1_dist = squared_distance( + project_point(get(face_to_triangle_map, primitive.id()), get(m_vpm1, v1)), + get(m_vpm1, v1) + ); + double v2_dist = squared_distance( + project_point(get(face_to_triangle_map, primitive.id()), get(m_vpm1, v2)), + get(m_vpm1, v2) + ); + + // Get the distance as maximizers over all vertices + double distance = approximate_sqrt(std::max(std::max(v0_dist,v1_dist),v2_dist)); + // Update local upper bound if ( distance < h_local_upper ) h_local_upper = distance; @@ -99,6 +129,12 @@ namespace CGAL { private: const AABBTraits& m_traits; + // The two triangle meshes + const TriangleMesh& m_tm1; + const TriangleMesh& m_tm2; + // Their respective vertex-point Maps + const VPM1& m_vpm1; + const VPM2& m_vpm2; // Local Hausdorff bounds for the query triangle double h_local_upper; double h_local_lower; @@ -111,7 +147,7 @@ namespace CGAL { /** * @class Hausdorff_primitive_traits_tm1 */ - template + template class Hausdorff_primitive_traits_tm1 { typedef AABB_face_graph_triangle_primitive TM2_primitive; @@ -122,10 +158,12 @@ namespace CGAL { typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Triangle_3 Triangle_3; typedef AABB_tree< AABB_traits > TM2_tree; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; public: - Hausdorff_primitive_traits_tm1(const AABBTraits& traits, const TM2_tree& tree) - : m_traits(traits), tm2_tree(tree) { + Hausdorff_primitive_traits_tm1(const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2 ) + : m_traits(traits), tm2_tree(tree), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2) { // Initialize the global bounds with 0., they will only grow. h_lower = 0.; h_upper = 0.; @@ -142,7 +180,7 @@ namespace CGAL { std::cout << "Reached Triangle in TM1: " << primitive.id() << '\n'; // Call Culling on B with the single triangle found. - Hausdorff_primitive_traits_tm2 traversal_traits_tm2( tm2_tree.traits() ); + Hausdorff_primitive_traits_tm2 traversal_traits_tm2( tm2_tree.traits(), m_tm1, m_tm2, m_vpm1, m_vpm2 ); tm2_tree.traversal(primitive, traversal_traits_tm2); // Update global Hausdorff bounds according to the obtained local bounds @@ -187,6 +225,12 @@ namespace CGAL { private: const AABBTraits& m_traits; + // The two triangle meshes + const TriangleMesh& m_tm1; + const TriangleMesh& m_tm2; + // Their vertex-point-maps + const VPM1 m_vpm1; + const VPM2 m_vpm2; // AABB tree for the second triangle meshes const TM2_tree& tm2_tree; // Global Hausdorff bounds to be taken track of during the traversal From 6221ebe148e95b4625650bf9495a1a2bb7777d1c Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Fri, 21 Jun 2019 07:22:04 +0200 Subject: [PATCH 013/349] Finish implementation of Culling on B (i.e. TM2) traversal. --- ...traversal_traits_with_Hausdorff_distance.h | 68 +++++++++++++------ 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 86cf640af02..a140d9aa034 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -37,9 +37,11 @@ namespace CGAL { { typedef typename AABBTraits::Primitive Primitive; typedef ::CGAL::AABB_node Node; + typedef typename AABBTraits::Bounding_box Bounding_box; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typename Kernel::Construct_projected_point_3 project_point; + typedef typename Kernel::Point_3 Point_3; public: Hausdorff_primitive_traits_tm2(const AABBTraits& traits, const TriangleMesh& tm1, const TriangleMesh& tm2, const VPM1& vpm1, const VPM2& vpm2) @@ -72,8 +74,8 @@ namespace CGAL { // The query object is a triangle from TM1, get its vertices halfedge_descriptor hd = halfedge(query.id(), m_tm1); - vertex_descriptor v0 = source(hd,m_tm1); - vertex_descriptor v1 = target(hd,m_tm1); + vertex_descriptor v0 = source(hd, m_tm1); + vertex_descriptor v1 = target(hd, m_tm1); vertex_descriptor v2 = target(next(hd, m_tm1), m_tm1); // Compute distances of the vertices to the primitive triangle in TM2 @@ -94,32 +96,60 @@ namespace CGAL { // Get the distance as maximizers over all vertices double distance = approximate_sqrt(std::max(std::max(v0_dist,v1_dist),v2_dist)); - // Update local upper bound + // Since we are at the level of a single triangle in TM2, distance is + // actually the correct Hausdorff distance from the query triangle in + // TM1 to the primitive triangle in TM2 if ( distance < h_local_upper ) h_local_upper = distance; - - double vertex_distance = 0.; - /* - / TODO For all vertices v of the query triangle, determine the distance by - / min_{b \in primitive} ( d(v, b) ) - / Update h_local_lower_i accordingly - */ - - h_local_lower = std::max( std::max (h_local_lower_0, h_local_lower_1), h_local_lower_2 ); + if ( distance < h_local_lower ) h_local_lower = distance; } // Determine whether child nodes will still contribute to a smaller // Hausdorff distance and thus have to be entered bool do_intersect(const Query& query, const Node& node) const { - // Have reached a node, determine whether or not to enter it - double distance = 0.; + /* Have reached a node, determine whether or not to enter it */ - /* TODO Determine distance of the node's bounding box (node.bbox()) to - / the triangle given by the query object. - */ + // Get the bounding box of the nodes + Bounding_box bbox = node.bbox(); + // Compute its center + Point_3 bb_center = Point_3( + (bbox.min(0) + bbox.max(0)) / 2, + (bbox.min(1) + bbox.max(1)) / 2, + (bbox.min(2) + bbox.max(2)) / 2); - if (distance <= h_local_upper) return true; - else return false; + // Get the center of the query triangle + // The query object is a triangle from TM1, get its vertices + halfedge_descriptor hd = halfedge(query.id(), m_tm1); + Point_3 v0 = get(m_vpm1, source(hd, m_tm1)); + Point_3 v1 = get(m_vpm1, target(hd, m_tm1)); + Point_3 v2 = get(m_vpm1, target(next(hd, m_tm1), m_tm1)); + // Compute the barycenter of the triangle + Point_3 tri_center = Point_3( 0.3*(v0.x()+v1.x()+v2.x()), 0.3*(v0.y()+v1.y()+v2.y()), 0.3*(v0.z()+v1.z()+v2.z()) ); + + // Compute the distance of the center to the closest point in tm2 + double dist = approximate_sqrt(squared_distance(bb_center, tri_center)); + + // Compute the radius of the circumsphere of the bounding boxes + double bb_radius = approximate_sqrt(squared_distance( + Point_3(bbox.min(0),bbox.min(1),bbox.min(2)), + Point_3(bbox.max(0),bbox.max(1),bbox.max(2))) + )/2.; + + // Compute the radius of the circumcircle of the triangle + double tri_radius = approximate_sqrt( std::max( + std::max( + squared_distance(tri_center, v0), + squared_distance(tri_center, v1) + ), + squared_distance(tri_center, v2) + )); + + // If triangles in the node can still lower the upper bound, enter it + if (tri_radius + bb_radius >= dist) { + return true; + } else { + return false; + } } Hausdorff_bounds get_local_bounds() From 48e159ba3f48979ab6540b79b8f8bc2487ac16da Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Fri, 21 Jun 2019 22:55:56 +0200 Subject: [PATCH 014/349] Store candidate triangles in a set to be processed later. --- .../CGAL/Polygon_mesh_processing/distance.h | 37 +++++++----- ...traversal_traits_with_Hausdorff_distance.h | 56 +++++++++++++++---- 2 files changed, 67 insertions(+), 26 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 4c269ce9823..45ab6e038dc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -896,20 +896,14 @@ double bounded_error_Hausdorff_impl( typedef typename boost::property_map::const_type Vertex_closest_triangle_map; typedef typename boost::property_map::const_type Triangle_hausdorff_bounds; + typedef std::pair Hausdorff_bounds; + typedef std::pair Candidate_triangle; + typedef typename std::vector Candidate_set; + typename Kernel::Compute_squared_distance_3 squared_distance; typename Kernel::Construct_projected_point_3 project_point; typename Kernel::FT dist; - // Store all vertices of tm1 in a vector - std::vector tm1_vertices; - tm1_vertices.reserve(num_vertices(tm1)); - tm1_vertices.insert(tm1_vertices.end(),vertices(tm1).begin(),vertices(tm1).end()); - - // Sort vertices along a Hilbert curve - spatial_sort( tm1_vertices.begin(), - tm1_vertices.end(), - Search_traits_3(vpm1) ); - // Build an AABB tree on tm1 TM1_tree tm1_tree( faces(tm1).begin(), faces(tm1).end(), tm1, vpm1 ); tm1_tree.build(); @@ -925,11 +919,8 @@ double bounded_error_Hausdorff_impl( Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2 ); tm1_tree.traversal( Point_3(0,0,0), traversal_traits_tm1 ); - // For each vertex in tm1, store the distance to the closest triangle of tm2 - Vertex_closest_triangle_map vctm = get(Vertex_property_tag(), tm1); - // For each triangle in tm1, sotre its respective local lower and upper bound - // on the Hausdorff measure - Triangle_hausdorff_bounds thb = get(Face_property_tag(), tm1); + Candidate_set candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); + Hausdorff_bounds global_bounds = traversal_traits_tm1.get_global_bounds(); #if !defined(CGAL_LINKED_WITH_TBB) CGAL_static_assertion_msg (!(boost::is_convertible::value), @@ -948,6 +939,22 @@ double bounded_error_Hausdorff_impl( // else #endif { + // Store all vertices of tm1 in a vector + std::vector tm1_vertices; + tm1_vertices.reserve(num_vertices(tm1)); + tm1_vertices.insert(tm1_vertices.end(),vertices(tm1).begin(),vertices(tm1).end()); + + // Sort vertices along a Hilbert curve + spatial_sort( tm1_vertices.begin(), + tm1_vertices.end(), + Search_traits_3(vpm1) ); + + // For each vertex in tm1, store the distance to the closest triangle of tm2 + Vertex_closest_triangle_map vctm = get(Vertex_property_tag(), tm1); + // For each triangle in tm1, sotre its respective local lower and upper bound + // on the Hausdorff measure + Triangle_hausdorff_bounds thb = get(Face_property_tag(), tm1); + /* / For each vertex in the first mesh, find the closest triangle in the / second mesh, store it and also store the distance to this triangle diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index a140d9aa034..662399c4de1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -44,13 +44,17 @@ namespace CGAL { typedef typename Kernel::Point_3 Point_3; public: - Hausdorff_primitive_traits_tm2(const AABBTraits& traits, const TriangleMesh& tm1, const TriangleMesh& tm2, const VPM1& vpm1, const VPM2& vpm2) + Hausdorff_primitive_traits_tm2( + const AABBTraits& traits, + const TriangleMesh& tm1, const TriangleMesh& tm2, + const VPM1& vpm1, const VPM2& vpm2, + const double h_lower_init, const double h_upper_init + ) : m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2) { - // Initialize the global bounds with 0., they will only grow. - h_local_upper = std::numeric_limits::infinity(); - h_local_lower_0 = std::numeric_limits::infinity(); - h_local_lower_1 = std::numeric_limits::infinity(); - h_local_lower_2 = std::numeric_limits::infinity(); + // Initialize the global bounds with infinity, triangles from TM2_tree + // try to minimize them. + h_local_lower = h_lower_init; + h_local_upper = h_upper_init; } // Explore the whole tree, i.e. always enter children if the methods @@ -152,6 +156,7 @@ namespace CGAL { } } + // Return the local Hausdorff bounds computed for the passed query triangle Hausdorff_bounds get_local_bounds() { return Hausdorff_bounds( h_local_lower, h_local_upper ); @@ -168,12 +173,9 @@ namespace CGAL { // Local Hausdorff bounds for the query triangle double h_local_upper; double h_local_lower; - // Local Hausdorff bounds for the query triangle's vertices - double h_local_lower_0; - double h_local_lower_1; - double h_local_lower_2; }; + /** * @class Hausdorff_primitive_traits_tm1 */ @@ -187,6 +189,8 @@ namespace CGAL { typedef ::CGAL::AABB_node Node; typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Triangle_3 Triangle_3; + typedef std::pair Candidate_triangle; + typedef typename std::vector Candidate_set; typedef AABB_tree< AABB_traits > TM2_tree; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; @@ -209,8 +213,18 @@ namespace CGAL { // Have reached a single triangle std::cout << "Reached Triangle in TM1: " << primitive.id() << '\n'; + // Map to transform faces of TM1 to actual triangles + Triangle_from_face_descriptor_map m_face_to_triangle_map( &m_tm1, m_vpm1 ); + Triangle_3 candidate_triangle = get(m_face_to_triangle_map, primitive.id()); + // Call Culling on B with the single triangle found. - Hausdorff_primitive_traits_tm2 traversal_traits_tm2( tm2_tree.traits(), m_tm1, m_tm2, m_vpm1, m_vpm2 ); + Hausdorff_primitive_traits_tm2< + Tree_traits, Primitive, Kernel, TriangleMesh, VPM1, VPM2 + > traversal_traits_tm2( + tm2_tree.traits(), m_tm1, m_tm2, m_vpm1, m_vpm2, + std::numeric_limits::infinity(), + std::numeric_limits::infinity() + ); tm2_tree.traversal(primitive, traversal_traits_tm2); // Update global Hausdorff bounds according to the obtained local bounds @@ -221,6 +235,12 @@ namespace CGAL { if (local_bounds.second > h_upper) { h_upper = local_bounds.second; } + + m_candidiate_triangles.push_back(Candidate_triangle(candidate_triangle, local_bounds)); + /* TODO Store the triangle given here is primitive as candidate triangle + together with the local bounds it optained to send it to + subdivision later. + */ } // Determine whether child nodes will still contribute to a larger @@ -253,6 +273,18 @@ namespace CGAL { } } + // Return those triangles from TM1 which are candidates for including a + // point realizing the Hausdorff distance + Candidate_set get_candidate_triangles() { + return m_candidiate_triangles; + } + + // Return the local Hausdorff bounds computed for the passed query triangle + Hausdorff_bounds get_global_bounds() + { + return Hausdorff_bounds( h_lower, h_upper ); + } + private: const AABBTraits& m_traits; // The two triangle meshes @@ -266,6 +298,8 @@ namespace CGAL { // Global Hausdorff bounds to be taken track of during the traversal double h_lower; double h_upper; + // List of candidate triangles with their Hausdorff bounds attached + Candidate_set m_candidiate_triangles; }; } From 7ec6c4ca328faefabf8faf766eec3aaccacd5735 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Sat, 22 Jun 2019 09:02:27 +0200 Subject: [PATCH 015/349] Correct implementation of Culling on second mesh. --- ...traversal_traits_with_Hausdorff_distance.h | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 662399c4de1..16e9e49f39d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -48,13 +48,16 @@ namespace CGAL { const AABBTraits& traits, const TriangleMesh& tm1, const TriangleMesh& tm2, const VPM1& vpm1, const VPM2& vpm2, - const double h_lower_init, const double h_upper_init + const double h_lower_init, const double h_upper_init, + const double h_v0_lower_init, const double h_v1_lower_init, const double h_v2_lower_init ) : m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2) { - // Initialize the global bounds with infinity, triangles from TM2_tree - // try to minimize them. + // Initialize the global and local bounds with the given values h_local_lower = h_lower_init; h_local_upper = h_upper_init; + h_v0_lower = h_v0_lower_init; + h_v1_lower = h_v1_lower_init; + h_v2_lower = h_v2_lower_init; } // Explore the whole tree, i.e. always enter children if the methods @@ -84,27 +87,33 @@ namespace CGAL { // Compute distances of the vertices to the primitive triangle in TM2 Triangle_from_face_descriptor_map face_to_triangle_map(&m_tm2, m_vpm2); - double v0_dist = squared_distance( + double v0_dist = approximate_sqrt(squared_distance( project_point(get(face_to_triangle_map, primitive.id()), get(m_vpm1, v0)), get(m_vpm1, v0) - ); - double v1_dist = squared_distance( + )); + if (v0_dist < h_v0_lower) h_v0_lower = v0_dist; + + double v1_dist = approximate_sqrt(squared_distance( project_point(get(face_to_triangle_map, primitive.id()), get(m_vpm1, v1)), get(m_vpm1, v1) - ); - double v2_dist = squared_distance( + )); + if (v1_dist < h_v1_lower) h_v1_lower = v1_dist; + + double v2_dist = approximate_sqrt(squared_distance( project_point(get(face_to_triangle_map, primitive.id()), get(m_vpm1, v2)), get(m_vpm1, v2) - ); + )); + if (v2_dist < h_v2_lower) h_v2_lower = v2_dist; // Get the distance as maximizers over all vertices - double distance = approximate_sqrt(std::max(std::max(v0_dist,v1_dist),v2_dist)); + double distance_upper = std::max(std::max(v0_dist,v1_dist),v2_dist); + double distance_lower = std::max(std::max(h_v0_lower,h_v1_lower),h_v2_lower); - // Since we are at the level of a single triangle in TM2, distance is + // Since we are at the level of a single triangle in TM2, distance_upper is // actually the correct Hausdorff distance from the query triangle in // TM1 to the primitive triangle in TM2 - if ( distance < h_local_upper ) h_local_upper = distance; - if ( distance < h_local_lower ) h_local_lower = distance; + if ( distance_upper < h_local_upper ) h_local_upper = distance_upper; + if ( distance_lower < h_local_lower ) h_local_lower = distance_lower; } // Determine whether child nodes will still contribute to a smaller @@ -173,6 +182,9 @@ namespace CGAL { // Local Hausdorff bounds for the query triangle double h_local_upper; double h_local_lower; + double h_v0_lower; + double h_v1_lower; + double h_v2_lower; }; @@ -223,6 +235,9 @@ namespace CGAL { > traversal_traits_tm2( tm2_tree.traits(), m_tm1, m_tm2, m_vpm1, m_vpm2, std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), std::numeric_limits::infinity() ); tm2_tree.traversal(primitive, traversal_traits_tm2); @@ -257,6 +272,7 @@ namespace CGAL { (bbox.min(1) + bbox.max(1)) / 2, (bbox.min(2) + bbox.max(2)) / 2); // Find the point from TM2 closest to the center + // TODO Insert a hint here to accelerate the query Point_3 closest = tm2_tree.closest_point(center); // Compute the distance of the center to the closest point in tm2 double dist = approximate_sqrt(squared_distance(center, closest)); From 2a523825a7502a5e6866e76ae4e2758a52989c17 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Mon, 24 Jun 2019 03:42:48 +0200 Subject: [PATCH 016/349] Implement a non-trivial toy example to test subdivision with. Intended solution is: Hausdorff distance will be attained at Point (0,0,1) and should be sqrt(3). --- ...usdorff_bounded_error_distance_example.cpp | 36 +++++++++++++++---- ...traversal_traits_with_Hausdorff_distance.h | 17 ++++----- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index dd32a2b5e4e..eb68fec8e2b 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -10,21 +10,45 @@ #endif typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef K::Point_3 Point; -typedef CGAL::Surface_mesh Mesh; +typedef K::Point_3 Point_3; +typedef K::Triangle_3 Triangle_3; +typedef CGAL::Surface_mesh Mesh; +typedef Mesh::Vertex_index Vertex_index; namespace PMP = CGAL::Polygon_mesh_processing; int main() { Mesh tm1, tm2; - CGAL::make_tetrahedron(Point(.0,.0,.0), - Point(2,.0,.0), - Point(1,1,1), - Point(1,.0,2), +/* + CGAL::make_tetrahedron(Point_3(.0,.0,.0), + Point_3(2,.0,.0), + Point_3(1,1,1), + Point_3(1,.0,2), tm1); tm2=tm1; CGAL::Polygon_mesh_processing::isotropic_remeshing(tm2.faces(),.05, tm2); +*/ + tm1 = Mesh(); + tm1.add_vertex( Point_3(-1.,1.,1.) ); + tm1.add_vertex( Point_3(0.,-1.,1.) ); + tm1.add_vertex( Point_3(1.,1.,1.) ); + tm1.add_face( tm1.vertices() ); + + std::cout << "TM1 is valid: " << (tm1.is_valid() ? "true" : "false") << std::endl; + + tm2 = Mesh(); + Vertex_index w0 = tm2.add_vertex( Point_3(-1.,1.,0.) ); + Vertex_index w1 = tm2.add_vertex( Point_3(0.,-1.,0.) ); + Vertex_index w2 = tm2.add_vertex( Point_3(1.,1.,0.) ); + Vertex_index w3 = tm2.add_vertex( Point_3(0.,1.,-1.) ); + Vertex_index w4 = tm2.add_vertex( Point_3(-0.5,0.,-1.) ); + Vertex_index w5 = tm2.add_vertex( Point_3(0.5,0.,-1.) ); + tm2.add_face( w0, w3, w4 ); + tm2.add_face( w1, w4, w5 ); + tm2.add_face( w2, w5, w3 ); + + std::cout << "TM2 is valid: " << (tm2.is_valid() ? "true" : "false") << std::endl; std::cout << "Approximated Hausdorff distance: " << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 16e9e49f39d..2ffd206d9d1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -67,8 +67,7 @@ namespace CGAL { // Compute the explicit Hausdorff distance to the given primitive void intersection(const Query& query, const Primitive& primitive) { - // Have reached a single triangle - std::cout << "Reached Triangle in TM2:" << primitive.id() << '\n'; + /* Have reached a single triangle, process it */ /* / Determine the distance accroding to @@ -222,8 +221,7 @@ namespace CGAL { // Compute the explicit Hausdorff distance to the given primitive void intersection(const Query& query, const Primitive& primitive) { - // Have reached a single triangle - std::cout << "Reached Triangle in TM1: " << primitive.id() << '\n'; + /* Have reached a single triangle, process it */ // Map to transform faces of TM1 to actual triangles Triangle_from_face_descriptor_map m_face_to_triangle_map( &m_tm1, m_vpm1 ); @@ -251,11 +249,14 @@ namespace CGAL { h_upper = local_bounds.second; } + std::cout << "Processed triangle: " << primitive.id() + << ", found bounds (low., up.): (" << local_bounds.first + << ", " << local_bounds.second << ")" << std::endl; + + // Store the triangle given as primitive here as candidate triangle + // together with the local bounds it obtained to sind it to subdivision + // later m_candidiate_triangles.push_back(Candidate_triangle(candidate_triangle, local_bounds)); - /* TODO Store the triangle given here is primitive as candidate triangle - together with the local bounds it optained to send it to - subdivision later. - */ } // Determine whether child nodes will still contribute to a larger From 68e9776af60865e723f746968b6d94be5472c180 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Mon, 24 Jun 2019 04:43:29 +0200 Subject: [PATCH 017/349] Implement subdivision of a triangle from the candidate set. --- .../CGAL/Polygon_mesh_processing/distance.h | 54 +++++++++++++++---- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 45ab6e038dc..2a7a8f1e6dd 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -867,7 +867,7 @@ template traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2 ); tm1_tree.traversal( Point_3(0,0,0), traversal_traits_tm1 ); + // TODO Implement the candidate_triangles set as Stack instead of Vector Candidate_set candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); Hausdorff_bounds global_bounds = traversal_traits_tm1.get_global_bounds(); + while ( (global_bounds.second - global_bounds.first > error_bound) && candidate_triangles.size() > 0 ) { + // Get the first triangle and its Hausdorff bounds from the candidate set + Candidate_triangle triangle_and_bound = candidate_triangles.front(); + // Remove it from the candidate set as it will be processed now + candidate_triangles.erase (candidate_triangles.begin(),candidate_triangles.begin()+1); + // Only process the triangle if it can contribute to the Hausdorff distance, + // i.e. if its Upper Bound is higher than the currently known best lower bound + if (triangle_and_bound.second.second > global_bounds.first) { + // Subdivide the triangle into four smaller triangles + Triangle_3 triangle_for_subdivision = triangle_and_bound.first; + Point_3 v0 = triangle_for_subdivision.vertex(0); + Point_3 v1 = triangle_for_subdivision.vertex(0); + Point_3 v2 = triangle_for_subdivision.vertex(0); + Point_3 v01 = Point_3( (v0.x()+ v1.x())/2., (v0.y()+v1.y())/2., (v0.z()+v1.z())/2. ); + Point_3 v02 = Point_3( (v0.x()+ v2.x())/2., (v0.y()+v2.y())/2., (v0.z()+v2.z())/2. ); + Point_3 v12 = Point_3( (v1.x()+ v2.x())/2., (v1.y()+v2.y())/2., (v1.z()+v2.z())/2. ); + Triangle_3 t0 = Triangle_3( v0, v01, v1); + Triangle_3 t1 = Triangle_3( v0, v02, v2); + Triangle_3 t2 = Triangle_3( v1, v12, v2); + Triangle_3 t3 = Triangle_3( v01, v02, v12); + + // TODO send each of the four triangles to Culling on B with the bounds of the parent triangle + // TODO add those triangles to the candidate set which still contribute to the Hausdorff distance + } + } + + // Print result found + std::cout << "Processing candidates finished, found distance (lower, upper): (" + << global_bounds.first << ", " << global_bounds.second << ")" << std::endl; + + // Return linear interpolation between found upper and lower bound + return (global_bounds.first + global_bounds.second) / 2.; + #if !defined(CGAL_LINKED_WITH_TBB) CGAL_static_assertion_msg (!(boost::is_convertible::value), "Parallel_tag is enabled but TBB is unavailable."); @@ -938,6 +972,7 @@ double bounded_error_Hausdorff_impl( // } // else #endif +/* { // Store all vertices of tm1 in a vector std::vector tm1_vertices; @@ -955,11 +990,9 @@ double bounded_error_Hausdorff_impl( // on the Hausdorff measure Triangle_hausdorff_bounds thb = get(Face_property_tag(), tm1); - /* - / For each vertex in the first mesh, find the closest triangle in the - / second mesh, store it and also store the distance to this triangle - / in a dynamic vertex property - */ + // For each vertex in the first mesh, find the closest triangle in the + // second mesh, store it and also store the distance to this triangle + // in a dynamic vertex property for(vertex_descriptor vd : tm1_vertices) { // Get the point represented by the vertex @@ -982,11 +1015,9 @@ double bounded_error_Hausdorff_impl( // following std::vector candidate_triangles; - /* - / For each triangle in the first mesh, initialize its local upper and - / lower bound and store these in a dynamic face property for furture - / reference - */ + // For each triangle in the first mesh, initialize its local upper and + // lower bound and store these in a dynamic face property for furture + // reference for(face_descriptor fd : faces(tm1)) { // Initialize the local bounds for the current face fd @@ -1056,6 +1087,7 @@ double bounded_error_Hausdorff_impl( return (CGAL::approximate_sqrt(h_lower)+CGAL::approximate_sqrt(h_upper))/2.; } +*/ } } //end of namespace internal From 17b00036a90ceda4f66879b19d214e8d901cf763 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Mon, 24 Jun 2019 04:48:43 +0200 Subject: [PATCH 018/349] Fix typo in vertex lookup. --- .../include/CGAL/Polygon_mesh_processing/distance.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 2a7a8f1e6dd..cc3759de006 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -934,8 +934,8 @@ double bounded_error_Hausdorff_impl( // Subdivide the triangle into four smaller triangles Triangle_3 triangle_for_subdivision = triangle_and_bound.first; Point_3 v0 = triangle_for_subdivision.vertex(0); - Point_3 v1 = triangle_for_subdivision.vertex(0); - Point_3 v2 = triangle_for_subdivision.vertex(0); + Point_3 v1 = triangle_for_subdivision.vertex(1); + Point_3 v2 = triangle_for_subdivision.vertex(2); Point_3 v01 = Point_3( (v0.x()+ v1.x())/2., (v0.y()+v1.y())/2., (v0.z()+v1.z())/2. ); Point_3 v02 = Point_3( (v0.x()+ v2.x())/2., (v0.y()+v2.y())/2., (v0.z()+v2.z())/2. ); Point_3 v12 = Point_3( (v1.x()+ v2.x())/2., (v1.y()+v2.y())/2., (v1.z()+v2.z())/2. ); From 3c73230272cbf9200bbca9f3ac019b93d7979946 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Mon, 24 Jun 2019 23:41:12 +0200 Subject: [PATCH 019/349] Finish first working prototype giving correct answer on the toy example. --- .../CGAL/Polygon_mesh_processing/distance.h | 77 +++++++++++++++++-- ...traversal_traits_with_Hausdorff_distance.h | 54 +++++-------- 2 files changed, 90 insertions(+), 41 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index cc3759de006..88cfd3d2f70 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -880,6 +880,7 @@ double bounded_error_Hausdorff_impl( typedef AABB_tree< AABB_traits > TM1_tree; typedef AABB_tree< AABB_traits > TM2_tree; typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; + typedef typename Tree_traits::Point_and_primitive_id Point_and_primitive_id; typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Triangle_3 Triangle_3; @@ -924,28 +925,88 @@ double bounded_error_Hausdorff_impl( Hausdorff_bounds global_bounds = traversal_traits_tm1.get_global_bounds(); while ( (global_bounds.second - global_bounds.first > error_bound) && candidate_triangles.size() > 0 ) { + + // TODO Why does it only stop because of triangles, not because of the global bound condition? + std::cout << "There are currently " << candidate_triangles.size() + << " candidates. Global bounds are: " + << global_bounds.first << ", " << global_bounds.second << std::endl; + // Get the first triangle and its Hausdorff bounds from the candidate set Candidate_triangle triangle_and_bound = candidate_triangles.front(); // Remove it from the candidate set as it will be processed now candidate_triangles.erase (candidate_triangles.begin(),candidate_triangles.begin()+1); + // Only process the triangle if it can contribute to the Hausdorff distance, // i.e. if its Upper Bound is higher than the currently known best lower bound - if (triangle_and_bound.second.second > global_bounds.first) { - // Subdivide the triangle into four smaller triangles + // and the difference between the bounds to be obtained is larger than the + // user given error. + Hausdorff_bounds triangle_bounds = triangle_and_bound.second; + if ( (triangle_bounds.second > global_bounds.first) && (triangle_bounds.second - triangle_bounds.first > error_bound) ) { + // Get the triangle that is to be subdivided and read its vertices Triangle_3 triangle_for_subdivision = triangle_and_bound.first; Point_3 v0 = triangle_for_subdivision.vertex(0); Point_3 v1 = triangle_for_subdivision.vertex(1); Point_3 v2 = triangle_for_subdivision.vertex(2); + + // Check second stopping condition: All three vertices of the triangle + // are projected onto the same triangle in TM2 + Point_and_primitive_id closest_triangle_v0 = tm2_tree.closest_point_and_primitive(v0); + Point_and_primitive_id closest_triangle_v1 = tm2_tree.closest_point_and_primitive(v1); + Point_and_primitive_id closest_triangle_v2 = tm2_tree.closest_point_and_primitive(v2); + if( (closest_triangle_v0.second == closest_triangle_v1.second) && (closest_triangle_v1.second == closest_triangle_v2.second)) { + // The upper bound of this triangle is the actual Hausdorff distance of + // the triangle to the second mesh. Use it as new global lower bound. + global_bounds.first = triangle_bounds.second; + } + + // Subdivide the triangle into four smaller triangles Point_3 v01 = Point_3( (v0.x()+ v1.x())/2., (v0.y()+v1.y())/2., (v0.z()+v1.z())/2. ); Point_3 v02 = Point_3( (v0.x()+ v2.x())/2., (v0.y()+v2.y())/2., (v0.z()+v2.z())/2. ); Point_3 v12 = Point_3( (v1.x()+ v2.x())/2., (v1.y()+v2.y())/2., (v1.z()+v2.z())/2. ); - Triangle_3 t0 = Triangle_3( v0, v01, v1); - Triangle_3 t1 = Triangle_3( v0, v02, v2); - Triangle_3 t2 = Triangle_3( v1, v12, v2); - Triangle_3 t3 = Triangle_3( v01, v02, v12); + std::array sub_triangles = { + Triangle_3( v0, v01, v02), Triangle_3( v1, v01, v12), + Triangle_3( v2, v02, v12), Triangle_3( v01, v02, v12) + }; - // TODO send each of the four triangles to Culling on B with the bounds of the parent triangle - // TODO add those triangles to the candidate set which still contribute to the Hausdorff distance + // Send each of the four triangles to Culling on B with the bounds of the parent triangle + for (int i=0; i<4; i++) { + // Call Culling on B with the single triangle found. + Hausdorff_primitive_traits_tm2 traversal_traits_tm2( + tm2_tree.traits(), tm2, vpm2, + triangle_bounds.first, + triangle_bounds.second, + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity() + ); + tm2_tree.traversal(sub_triangles[i], traversal_traits_tm2); + + // Get the highest current bound from all candidate triangles + double current_max = 0.; + for(auto&& ct: candidate_triangles) { + if (ct.second.second > current_max) { + current_max = ct.second.second; + } + } + + // Update global Hausdorff bounds according to the obtained local bounds + Hausdorff_bounds local_bounds = traversal_traits_tm2.get_local_bounds(); + if (local_bounds.first > global_bounds.first) { + global_bounds.first = local_bounds.first; + } + global_bounds.second = std::max(current_max, local_bounds.second); + + // Add the subtriangle to the candidate list + candidate_triangles.push_back(Candidate_triangle(sub_triangles[i], local_bounds)); + + // std::cout << "Split triangle (" << v0 << ", " << v1 << ", " << v2 + // << ") with bounds: (" << triangle_bounds.first << ", " + // << triangle_bounds.second << "), sub-triangle " << i + // << " (" << sub_triangles[i].vertex(0) << ", " << sub_triangles[i].vertex(1) << ", " << sub_triangles[i].vertex(2) + // << ") has bounds: (" + // << local_bounds.first << ", " << local_bounds.second << "), gobal bounds are: (" + // << global_bounds.first << ", " << global_bounds.second << ")" << std::endl; + } } } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 2ffd206d9d1..950d8ab1f38 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -32,26 +32,24 @@ namespace CGAL { /** * @class Hausdorff_primitive_traits_tm2 */ - template + template class Hausdorff_primitive_traits_tm2 { typedef typename AABBTraits::Primitive Primitive; typedef ::CGAL::AABB_node Node; typedef typename AABBTraits::Bounding_box Bounding_box; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typename Kernel::Construct_projected_point_3 project_point; typedef typename Kernel::Point_3 Point_3; public: Hausdorff_primitive_traits_tm2( const AABBTraits& traits, - const TriangleMesh& tm1, const TriangleMesh& tm2, - const VPM1& vpm1, const VPM2& vpm2, + const TriangleMesh& tm2, + const VPM2& vpm2, const double h_lower_init, const double h_upper_init, const double h_v0_lower_init, const double h_v1_lower_init, const double h_v2_lower_init ) - : m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2) { + : m_traits(traits), m_tm2(tm2), m_vpm2(vpm2) { // Initialize the global and local bounds with the given values h_local_lower = h_lower_init; h_local_upper = h_upper_init; @@ -79,29 +77,22 @@ namespace CGAL { */ // The query object is a triangle from TM1, get its vertices - halfedge_descriptor hd = halfedge(query.id(), m_tm1); - vertex_descriptor v0 = source(hd, m_tm1); - vertex_descriptor v1 = target(hd, m_tm1); - vertex_descriptor v2 = target(next(hd, m_tm1), m_tm1); + Point_3 v0 = query.vertex(0); + Point_3 v1 = query.vertex(1); + Point_3 v2 = query.vertex(2); // Compute distances of the vertices to the primitive triangle in TM2 Triangle_from_face_descriptor_map face_to_triangle_map(&m_tm2, m_vpm2); double v0_dist = approximate_sqrt(squared_distance( - project_point(get(face_to_triangle_map, primitive.id()), get(m_vpm1, v0)), - get(m_vpm1, v0) - )); + project_point( get(face_to_triangle_map, primitive.id()), v0), v0 ) ); if (v0_dist < h_v0_lower) h_v0_lower = v0_dist; double v1_dist = approximate_sqrt(squared_distance( - project_point(get(face_to_triangle_map, primitive.id()), get(m_vpm1, v1)), - get(m_vpm1, v1) - )); + project_point( get(face_to_triangle_map, primitive.id()), v1), v1 ) ); if (v1_dist < h_v1_lower) h_v1_lower = v1_dist; double v2_dist = approximate_sqrt(squared_distance( - project_point(get(face_to_triangle_map, primitive.id()), get(m_vpm1, v2)), - get(m_vpm1, v2) - )); + project_point( get(face_to_triangle_map, primitive.id()), v2), v2 ) ); if (v2_dist < h_v2_lower) h_v2_lower = v2_dist; // Get the distance as maximizers over all vertices @@ -131,10 +122,9 @@ namespace CGAL { // Get the center of the query triangle // The query object is a triangle from TM1, get its vertices - halfedge_descriptor hd = halfedge(query.id(), m_tm1); - Point_3 v0 = get(m_vpm1, source(hd, m_tm1)); - Point_3 v1 = get(m_vpm1, target(hd, m_tm1)); - Point_3 v2 = get(m_vpm1, target(next(hd, m_tm1), m_tm1)); + Point_3 v0 = query.vertex(0); + Point_3 v1 = query.vertex(1); + Point_3 v2 = query.vertex(2); // Compute the barycenter of the triangle Point_3 tri_center = Point_3( 0.3*(v0.x()+v1.x()+v2.x()), 0.3*(v0.y()+v1.y()+v2.y()), 0.3*(v0.z()+v1.z()+v2.z()) ); @@ -172,11 +162,9 @@ namespace CGAL { private: const AABBTraits& m_traits; - // The two triangle meshes - const TriangleMesh& m_tm1; + // the mesh of this tree const TriangleMesh& m_tm2; - // Their respective vertex-point Maps - const VPM1& m_vpm1; + // its vertex point map const VPM2& m_vpm2; // Local Hausdorff bounds for the query triangle double h_local_upper; @@ -208,7 +196,7 @@ namespace CGAL { public: Hausdorff_primitive_traits_tm1(const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2 ) - : m_traits(traits), tm2_tree(tree), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2) { + : m_traits(traits), m_tm2_tree(tree), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2) { // Initialize the global bounds with 0., they will only grow. h_lower = 0.; h_upper = 0.; @@ -229,16 +217,16 @@ namespace CGAL { // Call Culling on B with the single triangle found. Hausdorff_primitive_traits_tm2< - Tree_traits, Primitive, Kernel, TriangleMesh, VPM1, VPM2 + Tree_traits, Triangle_3, Kernel, TriangleMesh, VPM2 > traversal_traits_tm2( - tm2_tree.traits(), m_tm1, m_tm2, m_vpm1, m_vpm2, + m_tm2_tree.traits(), m_tm2, m_vpm2, std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity() ); - tm2_tree.traversal(primitive, traversal_traits_tm2); + m_tm2_tree.traversal(candidate_triangle, traversal_traits_tm2); // Update global Hausdorff bounds according to the obtained local bounds Hausdorff_bounds local_bounds = traversal_traits_tm2.get_local_bounds(); @@ -274,7 +262,7 @@ namespace CGAL { (bbox.min(2) + bbox.max(2)) / 2); // Find the point from TM2 closest to the center // TODO Insert a hint here to accelerate the query - Point_3 closest = tm2_tree.closest_point(center); + Point_3 closest = m_tm2_tree.closest_point(center); // Compute the distance of the center to the closest point in tm2 double dist = approximate_sqrt(squared_distance(center, closest)); // Compute the radius of the circumsphere of the bounding boxes @@ -311,7 +299,7 @@ namespace CGAL { const VPM1 m_vpm1; const VPM2 m_vpm2; // AABB tree for the second triangle meshes - const TM2_tree& tm2_tree; + const TM2_tree& m_tm2_tree; // Global Hausdorff bounds to be taken track of during the traversal double h_lower; double h_upper; From d8b6e7dfb1ccea8746d53f6c25be2fb8efffa2ca Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Fri, 12 Jul 2019 18:04:08 +0200 Subject: [PATCH 020/349] Results of Code Review with Sebastien. --- ...usdorff_bounded_error_distance_example.cpp | 4 ++++ .../CGAL/Polygon_mesh_processing/distance.h | 20 +++++++++---------- ...traversal_traits_with_Hausdorff_distance.h | 9 +++++++-- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index eb68fec8e2b..0c84ea03ca2 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -20,6 +20,10 @@ namespace PMP = CGAL::Polygon_mesh_processing; int main() { Mesh tm1, tm2; + // TODO Read real meshes and try method with it. + // std::ofstream(argv[1]) >> tm1; + // http://www.pmp-book.org/download/meshes/iphi_fullres.zip + // https://doc.cgal.org/latest/Polygon_mesh_processing/group__PMP__meshing__grp.html#ga028a80dc84395650f67714fa7618ec53 /* CGAL::make_tetrahedron(Point_3(.0,.0,.0), Point_3(2,.0,.0), diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 88cfd3d2f70..1e74027ecf3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -916,25 +916,23 @@ double bounded_error_Hausdorff_impl( tm2_tree.accelerate_distance_queries(); std::pair hint = tm2_tree.any_reference_point_and_id(); - // Build traversal traits for tm1_tree and tm2_tree + // Build traversal traits for tm1_tree Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2 ); - tm1_tree.traversal( Point_3(0,0,0), traversal_traits_tm1 ); + // Find candidate triangles in TM1 which might realise the Hausdorff bound + tm1_tree.traversal( Point_3(0,0,0), traversal_traits_tm1 ); // dummy point given as query as not needed // TODO Implement the candidate_triangles set as Stack instead of Vector + // check: https://www.boost.org/doc/libs/1_55_0/doc/html/heap.html + // Can already build a sorted structure while collecting the candidates Candidate_set candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); Hausdorff_bounds global_bounds = traversal_traits_tm1.get_global_bounds(); while ( (global_bounds.second - global_bounds.first > error_bound) && candidate_triangles.size() > 0 ) { - // TODO Why does it only stop because of triangles, not because of the global bound condition? - std::cout << "There are currently " << candidate_triangles.size() - << " candidates. Global bounds are: " - << global_bounds.first << ", " << global_bounds.second << std::endl; - // Get the first triangle and its Hausdorff bounds from the candidate set - Candidate_triangle triangle_and_bound = candidate_triangles.front(); + Candidate_triangle triangle_and_bound = candidate_triangles.back(); // Remove it from the candidate set as it will be processed now - candidate_triangles.erase (candidate_triangles.begin(),candidate_triangles.begin()+1); + candidate_triangles.pop_back(); // Only process the triangle if it can contribute to the Hausdorff distance, // i.e. if its Upper Bound is higher than the currently known best lower bound @@ -960,6 +958,7 @@ double bounded_error_Hausdorff_impl( } // Subdivide the triangle into four smaller triangles + // TODO Use CGAL::midpoint here. Point_3 v01 = Point_3( (v0.x()+ v1.x())/2., (v0.y()+v1.y())/2., (v0.z()+v1.z())/2. ); Point_3 v02 = Point_3( (v0.x()+ v2.x())/2., (v0.y()+v2.y())/2., (v0.z()+v2.z())/2. ); Point_3 v12 = Point_3( (v1.x()+ v2.x())/2., (v1.y()+v2.y())/2., (v1.z()+v2.z())/2. ); @@ -996,6 +995,7 @@ double bounded_error_Hausdorff_impl( } global_bounds.second = std::max(current_max, local_bounds.second); + // TODO Additionally store the face descriptor of the parent from TM1 in the Candidate_triangle. // Add the subtriangle to the candidate list candidate_triangles.push_back(Candidate_triangle(sub_triangles[i], local_bounds)); @@ -1212,7 +1212,7 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, Vpm2 vpm2 = choose_param(get_param(np2, internal_np::vertex_point), get_const_property_map(vertex_point, tm2)); - return internal::bounded_error_Hausdorff_impl(tm1, tm2, error_bound*error_bound, vpm1, vpm2); + return internal::bounded_error_Hausdorff_impl(tm1, tm2, error_bound, vpm1, vpm2); } template< class Concurrency_tag, diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 950d8ab1f38..818430dbeb4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -125,7 +125,8 @@ namespace CGAL { Point_3 v0 = query.vertex(0); Point_3 v1 = query.vertex(1); Point_3 v2 = query.vertex(2); - // Compute the barycenter of the triangle + // Compute the centroid of the triangle + // TODO Use the centroid() method from the kernel here. Point_3 tri_center = Point_3( 0.3*(v0.x()+v1.x()+v2.x()), 0.3*(v0.y()+v1.y()+v2.y()), 0.3*(v0.z()+v1.z()+v2.z()) ); // Compute the distance of the center to the closest point in tm2 @@ -249,10 +250,14 @@ namespace CGAL { // Determine whether child nodes will still contribute to a larger // Hausdorff distance and thus have to be entered - bool do_intersect(const Query& query, const Node& node) const + // TODO Document Query object, explain why I don't need it here. + bool do_intersect(const Query& /*query*/, const Node& node) const { /* Have reached a node, determine whether or not to enter it */ + // TODO What's the closest distance of TM2 to the box given by node? + // Can we have a sharper bound on this than the one implemented below? + // Get the bounding box of the nodes Bounding_box bbox = node.bbox(); // Compute its center From 519d37d9d7bef230016c46a43a16ad9bf746c8f1 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Fri, 12 Jul 2019 18:17:24 +0200 Subject: [PATCH 021/349] Use Kernel method instead of computations by hand. --- .../include/CGAL/Polygon_mesh_processing/distance.h | 7 +++---- .../AABB_traversal_traits_with_Hausdorff_distance.h | 7 +------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 1e74027ecf3..2ef4798ff4c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -958,10 +958,9 @@ double bounded_error_Hausdorff_impl( } // Subdivide the triangle into four smaller triangles - // TODO Use CGAL::midpoint here. - Point_3 v01 = Point_3( (v0.x()+ v1.x())/2., (v0.y()+v1.y())/2., (v0.z()+v1.z())/2. ); - Point_3 v02 = Point_3( (v0.x()+ v2.x())/2., (v0.y()+v2.y())/2., (v0.z()+v2.z())/2. ); - Point_3 v12 = Point_3( (v1.x()+ v2.x())/2., (v1.y()+v2.y())/2., (v1.z()+v2.z())/2. ); + Point_3 v01 = midpoint( v0, v1 ); + Point_3 v02 = midpoint( v0, v2 ); + Point_3 v12 = midpoint( v1, v2 ); std::array sub_triangles = { Triangle_3( v0, v01, v02), Triangle_3( v1, v01, v12), Triangle_3( v2, v02, v12), Triangle_3( v01, v02, v12) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 818430dbeb4..6393c74a912 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -126,8 +126,7 @@ namespace CGAL { Point_3 v1 = query.vertex(1); Point_3 v2 = query.vertex(2); // Compute the centroid of the triangle - // TODO Use the centroid() method from the kernel here. - Point_3 tri_center = Point_3( 0.3*(v0.x()+v1.x()+v2.x()), 0.3*(v0.y()+v1.y()+v2.y()), 0.3*(v0.z()+v1.z()+v2.z()) ); + Point_3 tri_center = centroid( query ); // Compute the distance of the center to the closest point in tm2 double dist = approximate_sqrt(squared_distance(bb_center, tri_center)); @@ -238,10 +237,6 @@ namespace CGAL { h_upper = local_bounds.second; } - std::cout << "Processed triangle: " << primitive.id() - << ", found bounds (low., up.): (" << local_bounds.first - << ", " << local_bounds.second << ")" << std::endl; - // Store the triangle given as primitive here as candidate triangle // together with the local bounds it obtained to sind it to subdivision // later From 0332d9f00f02a275cf7378904287126e28e4d1b2 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Fri, 12 Jul 2019 18:55:55 +0200 Subject: [PATCH 022/349] Enable reading of real meshes and perturbation of them for distance computation. --- ...usdorff_bounded_error_distance_example.cpp | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 0c84ea03ca2..6f162f97058 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #if defined(CGAL_LINKED_WITH_TBB) #define TAG CGAL::Parallel_tag @@ -17,14 +18,11 @@ typedef Mesh::Vertex_index Vertex_index; namespace PMP = CGAL::Polygon_mesh_processing; -int main() +int main(int argc, char** argv) { Mesh tm1, tm2; - // TODO Read real meshes and try method with it. - // std::ofstream(argv[1]) >> tm1; - // http://www.pmp-book.org/download/meshes/iphi_fullres.zip - // https://doc.cgal.org/latest/Polygon_mesh_processing/group__PMP__meshing__grp.html#ga028a80dc84395650f67714fa7618ec53 /* + // Easy Example CGAL::make_tetrahedron(Point_3(.0,.0,.0), Point_3(2,.0,.0), Point_3(1,1,1), @@ -33,6 +31,10 @@ int main() tm2=tm1; CGAL::Polygon_mesh_processing::isotropic_remeshing(tm2.faces(),.05, tm2); */ + +/* + // Example with point realizing the Hausdorff distance strictly lying in the + // interior of a triangle tm1 = Mesh(); tm1.add_vertex( Point_3(-1.,1.,1.) ); tm1.add_vertex( Point_3(0.,-1.,1.) ); @@ -53,6 +55,19 @@ int main() tm2.add_face( w2, w5, w3 ); std::cout << "TM2 is valid: " << (tm2.is_valid() ? "true" : "false") << std::endl; +*/ + + // Read a real mesh given by the user + std::ifstream input( argv[1] ); + input >> tm1; + std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl; + // Copy the mesh and perturb it slightly + tm2 = tm1; + bool do_project = false; + CGAL::Polygon_mesh_processing::random_perturbation( tm2.vertices(), tm2, 0.001, do_project ); + std::cout << "Perturbed the input mesh, now computing the Hausdorff distance." << std::endl; + +// https://doc.cgal.org/latest/Polygon_mesh_processing/group__PMP__meshing__grp.html#ga028a80dc84395650f67714fa7618ec53 std::cout << "Approximated Hausdorff distance: " << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance From e78cbff8a14cfe583a796e82d8758345f08b25ac Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Mon, 15 Jul 2019 14:12:01 +0200 Subject: [PATCH 023/349] Implement naive bounded Hausdoff computation by simple subdivision. --- ...usdorff_bounded_error_distance_example.cpp | 11 +- .../CGAL/Polygon_mesh_processing/distance.h | 158 ++++++++++++++++++ 2 files changed, 168 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 6f162f97058..8280052edec 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -61,16 +61,25 @@ int main(int argc, char** argv) std::ifstream input( argv[1] ); input >> tm1; std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl; + std::ifstream input2( argv[2] ); + input2 >> tm2; + std::cout << "Read a mesh with " << tm2.number_of_faces() << " triangles." << std::endl; // Copy the mesh and perturb it slightly +/* tm2 = tm1; bool do_project = false; CGAL::Polygon_mesh_processing::random_perturbation( tm2.vertices(), tm2, 0.001, do_project ); std::cout << "Perturbed the input mesh, now computing the Hausdorff distance." << std::endl; +*/ // https://doc.cgal.org/latest/Polygon_mesh_processing/group__PMP__meshing__grp.html#ga028a80dc84395650f67714fa7618ec53 std::cout << "Approximated Hausdorff distance: " << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance - (tm1, tm2, 0.001) + (tm1, tm2, 0.01) + << std::endl; + std::cout << "Approximated Hausdorff distance (naive): " + << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance_naive + (tm1, tm2, 0.01) << std::endl; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 2ef4798ff4c..df1279220db 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1150,6 +1150,109 @@ double bounded_error_Hausdorff_impl( */ } +template +double recursive_hausdorff_subdivision( + const Point_3& v0, + const Point_3& v1, + const Point_3& v2, + const TM2_tree& tm2_tree, + const typename Kernel::FT& squared_error_bound) +{ +// std::cout << "Processing points " << v0 << ", " << v1 << ", " << v2 << std::endl; + + // If any edge length of the triangle is larger than (error_bound * 1/sqrt(3)), subdivide the triangle and proceed recursively + double max_edge_length = std::max( std::max( squared_distance( v0, v1 ), squared_distance( v0, v2 )), squared_distance( v1, v2 )); +// std::cout << "Maximum edge lenght: " << max_edge_length << "; Squared error bound: " << squared_error_bound << std::endl; + if ( max_edge_length < squared_error_bound ) { +// std::cout << "Maximum distance: " << std::max(std::max(squared_distance( v0, tm2_tree.closest_point(v0) ),squared_distance( v1, tm2_tree.closest_point(v1) ) ), squared_distance( v2, tm2_tree.closest_point(v2) )); + return std::max( + std::max( + squared_distance( v0, tm2_tree.closest_point(v0) ), + squared_distance( v1, tm2_tree.closest_point(v1) ) ), + squared_distance( v2, tm2_tree.closest_point(v2) ) + ); + } + + // Else return maximum of the distances of the three points to TM2 (via TM2_tree). + Point_3 v01 = midpoint( v0, v1 ); + Point_3 v02 = midpoint( v0, v2 ); + Point_3 v12 = midpoint( v1, v2 ); + + return std::max ( + std::max( + recursive_hausdorff_subdivision( v0,v01,v02,tm2_tree,squared_error_bound ), + recursive_hausdorff_subdivision( v1,v01,v12,tm2_tree,squared_error_bound ) + ), + std::max( + recursive_hausdorff_subdivision( v2,v02,v12,tm2_tree,squared_error_bound ), + recursive_hausdorff_subdivision( v01,v02,v12,tm2_tree,squared_error_bound ) + ) + ); +} + +template +double bounded_error_Hausdorff_naive_impl( + const TriangleMesh& tm1, + const TriangleMesh& tm2, + const typename Kernel::FT& error_bound, + VPM1 vpm1, + VPM2 vpm2) +{ + CGAL_assertion_code( bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2) ); + CGAL_assertion_msg (is_triangle, + "One of the meshes is not triangulated. Distance computing impossible."); + + typedef AABB_face_graph_triangle_primitive TM2_primitive; + typedef AABB_tree< AABB_traits > TM2_tree; + + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef typename Kernel::Point_3 Point_3; + typedef typename Kernel::Triangle_3 Triangle_3; + + double squared_lower_bound = 0.; + double squared_error_bound = error_bound * error_bound; + + // Build an AABB tree on tm2 + TM2_tree tm2_tree( faces(tm2).begin(), faces(tm2).end(), tm2, vpm2 ); + tm2_tree.build(); + tm2_tree.accelerate_distance_queries(); + + Triangle_from_face_descriptor_map face_to_triangle_map( &tm1, vpm1 ); + + // Iterate over the triangles of TM1. + for(face_descriptor fd : faces(tm1)) + { + // Get the vertices of the face and pass them on to a recursive method. + Triangle_3 triangle = get(face_to_triangle_map, fd); + Point_3 v0 = triangle.vertex(0); + Point_3 v1 = triangle.vertex(1); + Point_3 v2 = triangle.vertex(2); + + double triangle_bound = recursive_hausdorff_subdivision( v0, v1, v2, tm2_tree, squared_error_bound ); + + if( triangle_bound > squared_lower_bound ) { + squared_lower_bound = triangle_bound; + } + } + + // Return linear interpolation between found upper and lower bound + return (approximate_sqrt( squared_lower_bound )); + +#if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg (!(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); +#else + // TODO implement parallelized version of the below here. +#endif +} + } //end of namespace internal /** @@ -1187,6 +1290,11 @@ double bounded_error_Hausdorff_impl( * The function `CGAL::parameters::all_default()` can be used to indicate to use the default values for * `np1` and specify custom values for `np2` */ + +/* + * Implementation of Bounded Hausdorff distance computation using AABBTree + * culling. + */ template< class Concurrency_tag, class TriangleMesh, class NamedParameters1, @@ -1234,6 +1342,56 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, return bounded_error_Hausdorff_distance(tm1, tm2, error_bound, parameters::all_default() ); } +/* + * Implementation of naive Bounded Hausdorff distance computation. + */ +template< class Concurrency_tag, + class TriangleMesh, + class NamedParameters1, + class NamedParameters2> +double bounded_error_Hausdorff_distance_naive( const TriangleMesh& tm1, + const TriangleMesh& tm2, + double error_bound, + const NamedParameters1& np1, + const NamedParameters2& np2) +{ + typedef typename GetGeomTraits::type Geom_traits; + + typedef typename GetVertexPointMap::const_type Vpm1; + typedef typename GetVertexPointMap::const_type Vpm2; + + using boost::choose_param; + using boost::get_param; + + Vpm1 vpm1 = choose_param(get_param(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, tm1)); + Vpm2 vpm2 = choose_param(get_param(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, tm2)); + + return internal::bounded_error_Hausdorff_naive_impl(tm1, tm2, error_bound, vpm1, vpm2); +} + +template< class Concurrency_tag, + class TriangleMesh, + class NamedParameters1> +double bounded_error_Hausdorff_distance_naive( const TriangleMesh& tm1, + const TriangleMesh& tm2, + double error_bound, + const NamedParameters1& np1) +{ + return bounded_error_Hausdorff_distance_naive(tm1, tm2, error_bound, np1, parameters::all_default()); +} + +template< class Concurrency_tag, + class TriangleMesh> +double bounded_error_Hausdorff_distance_naive( const TriangleMesh& tm1, + const TriangleMesh& tm2, + double error_bound) +{ + return bounded_error_Hausdorff_distance_naive(tm1, tm2, error_bound, parameters::all_default() ); +} + } } // end of namespace CGAL::Polygon_mesh_processing From 000604faa9a7641421f91030d6428cc1083fc830 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Mon, 15 Jul 2019 14:20:15 +0200 Subject: [PATCH 024/349] Comment naive comparison method. --- ...usdorff_bounded_error_distance_example.cpp | 7 +++-- .../CGAL/Polygon_mesh_processing/distance.h | 27 ++++++++++++------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 8280052edec..0242dcfe4fd 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -74,12 +74,15 @@ int main(int argc, char** argv) // https://doc.cgal.org/latest/Polygon_mesh_processing/group__PMP__meshing__grp.html#ga028a80dc84395650f67714fa7618ec53 + double error_bound = 0.01; + std::cout << "Approximated Hausdorff distance: " << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance - (tm1, tm2, 0.01) + (tm1, tm2, error_bound) << std::endl; std::cout << "Approximated Hausdorff distance (naive): " << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance_naive - (tm1, tm2, 0.01) + (tm1, tm2, error_bound) + << ", the actual distance is at most " << error_bound << " larger." << std::endl; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index df1279220db..25dba12f4b1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1013,7 +1013,7 @@ double bounded_error_Hausdorff_impl( std::cout << "Processing candidates finished, found distance (lower, upper): (" << global_bounds.first << ", " << global_bounds.second << ")" << std::endl; - // Return linear interpolation between found upper and lower bound + // Return linear interpolation between found lower and upper bound return (global_bounds.first + global_bounds.second) / 2.; #if !defined(CGAL_LINKED_WITH_TBB) @@ -1160,13 +1160,16 @@ double recursive_hausdorff_subdivision( const TM2_tree& tm2_tree, const typename Kernel::FT& squared_error_bound) { -// std::cout << "Processing points " << v0 << ", " << v1 << ", " << v2 << std::endl; - - // If any edge length of the triangle is larger than (error_bound * 1/sqrt(3)), subdivide the triangle and proceed recursively - double max_edge_length = std::max( std::max( squared_distance( v0, v1 ), squared_distance( v0, v2 )), squared_distance( v1, v2 )); -// std::cout << "Maximum edge lenght: " << max_edge_length << "; Squared error bound: " << squared_error_bound << std::endl; - if ( max_edge_length < squared_error_bound ) { -// std::cout << "Maximum distance: " << std::max(std::max(squared_distance( v0, tm2_tree.closest_point(v0) ),squared_distance( v1, tm2_tree.closest_point(v1) ) ), squared_distance( v2, tm2_tree.closest_point(v2) )); + // If all edge lengths of the triangle are below the error_bound, + // return maximum of the distances of the three points to TM2 (via TM2_tree). + double max_squared_edge_length = + std::max( + std::max( + squared_distance( v0, v1 ), + squared_distance( v0, v2 )), + squared_distance( v1, v2 ) + ); + if ( max_squared_edge_length < squared_error_bound ) { return std::max( std::max( squared_distance( v0, tm2_tree.closest_point(v0) ), @@ -1175,7 +1178,7 @@ double recursive_hausdorff_subdivision( ); } - // Else return maximum of the distances of the three points to TM2 (via TM2_tree). + // Else subdivide the triangle and proceed recursively Point_3 v01 = midpoint( v0, v1 ); Point_3 v02 = midpoint( v0, v2 ); Point_3 v12 = midpoint( v1, v2 ); @@ -1216,7 +1219,9 @@ double bounded_error_Hausdorff_naive_impl( typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Triangle_3 Triangle_3; + // Initially, no lower bound is known double squared_lower_bound = 0.; + // Work with squares in the following, only draw sqrt at the very end double squared_error_bound = error_bound * error_bound; // Build an AABB tree on tm2 @@ -1224,6 +1229,7 @@ double bounded_error_Hausdorff_naive_impl( tm2_tree.build(); tm2_tree.accelerate_distance_queries(); + // Build a map to obtain actual triangles from the face descriptors of tm1. Triangle_from_face_descriptor_map face_to_triangle_map( &tm1, vpm1 ); // Iterate over the triangles of TM1. @@ -1235,8 +1241,11 @@ double bounded_error_Hausdorff_naive_impl( Point_3 v1 = triangle.vertex(1); Point_3 v2 = triangle.vertex(2); + // Recursively process the current triangle to obtain a lower bound on + // its Hausdorff distance. double triangle_bound = recursive_hausdorff_subdivision( v0, v1, v2, tm2_tree, squared_error_bound ); + // Store the largest lower bound. if( triangle_bound > squared_lower_bound ) { squared_lower_bound = triangle_bound; } From 313402589a3fc3cdecdb32615119063e55826f58 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Mon, 15 Jul 2019 14:54:52 +0200 Subject: [PATCH 025/349] Bugfix computation of upper bound, should not go below lower bound. --- .../include/CGAL/Polygon_mesh_processing/distance.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 25dba12f4b1..d2957a78576 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -954,7 +954,9 @@ double bounded_error_Hausdorff_impl( if( (closest_triangle_v0.second == closest_triangle_v1.second) && (closest_triangle_v1.second == closest_triangle_v2.second)) { // The upper bound of this triangle is the actual Hausdorff distance of // the triangle to the second mesh. Use it as new global lower bound. + // TODO Update the reference to the realizing triangle here as this is the best current guess. global_bounds.first = triangle_bounds.second; + continue; } // Subdivide the triangle into four smaller triangles @@ -992,7 +994,10 @@ double bounded_error_Hausdorff_impl( if (local_bounds.first > global_bounds.first) { global_bounds.first = local_bounds.first; } - global_bounds.second = std::max(current_max, local_bounds.second); + global_bounds.second = std::max( + std::max(current_max, local_bounds.second), + global_bounds.first + ); // TODO Additionally store the face descriptor of the parent from TM1 in the Candidate_triangle. // Add the subtriangle to the candidate list From 30b6c70b3b84334fe9ec94458ef5fb88f4e667ff Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Thu, 18 Jul 2019 09:56:13 +0200 Subject: [PATCH 026/349] Add naive and optimized Hausdorff implementation to test file. --- .../CGAL/Polygon_mesh_processing/distance.h | 2 ++ .../test_pmp_distance.cpp | 23 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index d2957a78576..f81ab7c7874 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1015,8 +1015,10 @@ double bounded_error_Hausdorff_impl( } // Print result found +/* std::cout << "Processing candidates finished, found distance (lower, upper): (" << global_bounds.first << ", " << global_bounds.second << ")" << std::endl; +*/ // Return linear interpolation between found lower and upper bound return (global_bounds.first + global_bounds.second) / 2.; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp index 08936586a6f..e1bc4c828dd 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp @@ -283,7 +283,7 @@ int main(int, char** argv) CGAL::Real_timer time; #if defined(CGAL_LINKED_WITH_TBB) time.start(); - std::cout << "Distance between meshes (parallel) " + std::cout << "Hausdorff distance approximation between meshes (parallel) " << PMP::approximate_Hausdorff_distance( m1,m2,PMP::parameters::number_of_points_per_area_unit(4000)) << "\n"; @@ -293,13 +293,32 @@ int main(int, char** argv) time.reset(); time.start(); - std::cout << "Distance between meshes (sequential) " + std::cout << "Hausdorff distance approximation between meshes (sequential) " << PMP::approximate_Hausdorff_distance( m1,m2,PMP::parameters::number_of_points_per_area_unit(4000)) << "\n"; time.stop(); std::cout << "done in " << time.time() << "s.\n"; + time.reset(); + time.start(); + std::cout << "Lower bound on Hausdorff distance between meshes (sequential), " + << "the actual distance is at most " << 0.01 << " larger " + << PMP::bounded_error_Hausdorff_distance_naive( + m1,m2,0.01) + << "\n"; + time.stop(); + std::cout << "done in " << time.time() << "s.\n"; + + time.reset(); + time.start(); + std::cout << "Bounded Hausdorff distance between meshes (sequential), optimized implementation " + << PMP::bounded_error_Hausdorff_distance( + m1,m2,0.01) + << "\n"; + time.stop(); + std::cout << "done in " << time.time() << "s.\n"; + general_tests(m1,m2); test_concept(); From 98e92a973bdb6771d39ad80cd0439323a6ba911c Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Thu, 18 Jul 2019 11:42:16 +0200 Subject: [PATCH 027/349] Introduce an additional stopping criterion to stop in degenerate cases where a triangle is never projected onto a single triangle in the other mesh. --- .../CGAL/Polygon_mesh_processing/distance.h | 29 +++++++++++++++++++ ...traversal_traits_with_Hausdorff_distance.h | 4 +++ .../test_pmp_distance.cpp | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index f81ab7c7874..2b290837bed 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -927,8 +927,22 @@ double bounded_error_Hausdorff_impl( Candidate_set candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); Hausdorff_bounds global_bounds = traversal_traits_tm1.get_global_bounds(); +/* + std::cout << "Found " << candidate_triangles.size() << " candidates." << std::endl; + for (int i=0; i error_bound) && candidate_triangles.size() > 0 ) { + // std::cout << "Current number candidates: " << candidate_triangles.size() << std::endl; + // std::cout << "Current global bounds: (" << global_bounds.first << ", " << global_bounds.second << ")" << std::endl; + // Get the first triangle and its Hausdorff bounds from the candidate set Candidate_triangle triangle_and_bound = candidate_triangles.back(); // Remove it from the candidate set as it will be processed now @@ -939,6 +953,9 @@ double bounded_error_Hausdorff_impl( // and the difference between the bounds to be obtained is larger than the // user given error. Hausdorff_bounds triangle_bounds = triangle_and_bound.second; + + // std::cout << "Current triangle bounds: (" << triangle_bounds.first << ", " << triangle_bounds.second << ")" << std::endl; + if ( (triangle_bounds.second > global_bounds.first) && (triangle_bounds.second - triangle_bounds.first > error_bound) ) { // Get the triangle that is to be subdivided and read its vertices Triangle_3 triangle_for_subdivision = triangle_and_bound.first; @@ -959,6 +976,18 @@ double bounded_error_Hausdorff_impl( continue; } + // Check third stopping condition: All edge lengths of the triangle are + // smaller than the given error bound, cannot get results beyond this + // bound. + if ( squared_distance( v0, v1 ) < squared_error_bound + && squared_distance( v0, v2 ) < squared_error_bound + && squared_distance( v1, v2 ) < squared_error_bound ) { + // The upper bound of this triangle is within error tolerance of + // the actual upper bound, use it. + global_bounds.first = triangle_bounds.second; + continue; + } + // Subdivide the triangle into four smaller triangles Point_3 v01 = midpoint( v0, v1 ); Point_3 v02 = midpoint( v0, v2 ); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 6393c74a912..ee93fff07eb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -230,6 +230,10 @@ namespace CGAL { // Update global Hausdorff bounds according to the obtained local bounds Hausdorff_bounds local_bounds = traversal_traits_tm2.get_local_bounds(); +/* + std::cout << "Processed triangle " << primitive.id() << " with bounds (" + << local_bounds.first << ", " << local_bounds.second << ")" << std::endl; +*/ if (local_bounds.first > h_lower) { h_lower = local_bounds.first; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp index e1bc4c828dd..33b17e54de2 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp @@ -303,7 +303,7 @@ int main(int, char** argv) time.reset(); time.start(); std::cout << "Lower bound on Hausdorff distance between meshes (sequential), " - << "the actual distance is at most " << 0.01 << " larger " + << "the actual distance is at most " << 0.01 << " larger than " << PMP::bounded_error_Hausdorff_distance_naive( m1,m2,0.01) << "\n"; From 130dcbc1580a33e31fd8559b2c97e5cbe501075a Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Fri, 19 Jul 2019 11:07:06 +0200 Subject: [PATCH 028/349] Bugfix entering nodes of TM2 when traversing it. --- ...BB_traversal_traits_with_Hausdorff_distance.h | 16 ++++++++++------ .../test_pmp_distance.cpp | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index ee93fff07eb..6cf6c307146 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -146,8 +146,15 @@ namespace CGAL { squared_distance(tri_center, v2) )); - // If triangles in the node can still lower the upper bound, enter it - if (tri_radius + bb_radius >= dist) { + // Find a lower bound on the distance of the triangle to the bounding box + // by taking the distance from the triangle center to the bbox center + // and subtracting the radii of both elements. Thereby, each triangle in + // the bounding box has at least distance + // ( dist - triangle_radius - bbox_radius ) + // to the query triangle. Only if this lower bound is lower than the + // current best known lower bound, we enter the node, trying to + // lower the lower bound further. + if ( (dist - tri_radius - bb_radius) <= h_local_lower) { return true; } else { return false; @@ -230,10 +237,7 @@ namespace CGAL { // Update global Hausdorff bounds according to the obtained local bounds Hausdorff_bounds local_bounds = traversal_traits_tm2.get_local_bounds(); -/* - std::cout << "Processed triangle " << primitive.id() << " with bounds (" - << local_bounds.first << ", " << local_bounds.second << ")" << std::endl; -*/ + if (local_bounds.first > h_lower) { h_lower = local_bounds.first; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp index 33b17e54de2..6a6ac16db0a 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp @@ -290,7 +290,7 @@ int main(int, char** argv) time.stop(); std::cout << "done in " << time.time() << "s.\n"; #endif - +/* time.reset(); time.start(); std::cout << "Hausdorff distance approximation between meshes (sequential) " @@ -309,7 +309,7 @@ int main(int, char** argv) << "\n"; time.stop(); std::cout << "done in " << time.time() << "s.\n"; - +*/ time.reset(); time.start(); std::cout << "Bounded Hausdorff distance between meshes (sequential), optimized implementation " From c91c780cae4d1e26e178578a5c8cafeb884ab91c Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Fri, 19 Jul 2019 11:27:59 +0200 Subject: [PATCH 029/349] Add timing to the example file and restore all tests in the test file. --- ...hausdorff_bounded_error_distance_example.cpp | 17 ++++++++++++----- .../test_pmp_distance.cpp | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 0242dcfe4fd..01ec8a43329 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #if defined(CGAL_LINKED_WITH_TBB) #define TAG CGAL::Parallel_tag @@ -61,28 +62,34 @@ int main(int argc, char** argv) std::ifstream input( argv[1] ); input >> tm1; std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl; +/* std::ifstream input2( argv[2] ); input2 >> tm2; std::cout << "Read a mesh with " << tm2.number_of_faces() << " triangles." << std::endl; +*/ // Copy the mesh and perturb it slightly -/* tm2 = tm1; bool do_project = false; - CGAL::Polygon_mesh_processing::random_perturbation( tm2.vertices(), tm2, 0.001, do_project ); + CGAL::Polygon_mesh_processing::random_perturbation( tm2.vertices(), tm2, 0.1, do_project ); std::cout << "Perturbed the input mesh, now computing the Hausdorff distance." << std::endl; -*/ - -// https://doc.cgal.org/latest/Polygon_mesh_processing/group__PMP__meshing__grp.html#ga028a80dc84395650f67714fa7618ec53 + // Set an error bound double error_bound = 0.01; + CGAL::Real_timer time; + + time.start(); std::cout << "Approximated Hausdorff distance: " << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance (tm1, tm2, error_bound) << std::endl; + time.stop(); + std::cout << "Processing took " << time.time() << "s." << std::endl; +/* std::cout << "Approximated Hausdorff distance (naive): " << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance_naive (tm1, tm2, error_bound) << ", the actual distance is at most " << error_bound << " larger." << std::endl; +*/ } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp index 6a6ac16db0a..33b17e54de2 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp @@ -290,7 +290,7 @@ int main(int, char** argv) time.stop(); std::cout << "done in " << time.time() << "s.\n"; #endif -/* + time.reset(); time.start(); std::cout << "Hausdorff distance approximation between meshes (sequential) " @@ -309,7 +309,7 @@ int main(int, char** argv) << "\n"; time.stop(); std::cout << "done in " << time.time() << "s.\n"; -*/ + time.reset(); time.start(); std::cout << "Bounded Hausdorff distance between meshes (sequential), optimized implementation " From 156cac510777f3bb9889d5f3d3c8a5e16eb16000 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Sat, 20 Jul 2019 19:05:55 +0200 Subject: [PATCH 030/349] Implement benchmarking on both time and number of culled triangles. --- ...usdorff_bounded_error_distance_example.cpp | 63 ++++++++++++++++--- .../CGAL/Polygon_mesh_processing/distance.h | 2 + ...traversal_traits_with_Hausdorff_distance.h | 13 ++++ 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 01ec8a43329..f4146d98877 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -21,7 +21,15 @@ namespace PMP = CGAL::Polygon_mesh_processing; int main(int argc, char** argv) { + // Objects to hold the meshes Mesh tm1, tm2; + + // Timer to measure the runtime of h-distance Distance_computation + CGAL::Real_timer time; + + // Set an error bound + double error_bound = 0.01; + /* // Easy Example CGAL::make_tetrahedron(Point_3(.0,.0,.0), @@ -32,7 +40,7 @@ int main(int argc, char** argv) tm2=tm1; CGAL::Polygon_mesh_processing::isotropic_remeshing(tm2.faces(),.05, tm2); */ - +// ---------------------------------------------------------------------------- /* // Example with point realizing the Hausdorff distance strictly lying in the // interior of a triangle @@ -57,27 +65,67 @@ int main(int argc, char** argv) std::cout << "TM2 is valid: " << (tm2.is_valid() ? "true" : "false") << std::endl; */ - +// ---------------------------------------------------------------------------- +/* // Read a real mesh given by the user std::ifstream input( argv[1] ); input >> tm1; std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl; -/* + std::ifstream input2( argv[2] ); input2 >> tm2; std::cout << "Read a mesh with " << tm2.number_of_faces() << " triangles." << std::endl; -*/ + // Copy the mesh and perturb it slightly tm2 = tm1; bool do_project = false; CGAL::Polygon_mesh_processing::random_perturbation( tm2.vertices(), tm2, 0.1, do_project ); std::cout << "Perturbed the input mesh, now computing the Hausdorff distance." << std::endl; +*/ +// ---------------------------------------------------------------------------- - // Set an error bound - double error_bound = 0.01; + // Pairwise computation on a set of benchmark models + std::vector models = {"80","102","128","162","204","256","320","402","504","632","792","992","1242"}; + int num_models = models.size(); + std::string prefix = "/home/martin/Downloads/bunnies/bunny_"; + std::string postfix = ".off"; + std::vector error_bounds = { 0.1, 0.01, 0.001, 0.0001 }; - CGAL::Real_timer time; + std::ifstream input(prefix + models[0] + postfix); + // input >> tm1; + // input >> tm2; + // std::cout << "Initialized with a mesh at " << (prefix + models[0] + postfix) << " with " << tm1.number_of_faces() << " triangles." << std::endl; + for(int i=0; i> tm1; + // std::cout << "Read a mesh at " << (prefix + models[i] + postfix) << " with " << tm1.number_of_faces() << " faces." << std::endl; + + for(int j=0; j> tm2; + // std::cout << "Read a mesh at " << (prefix + models[j] + postfix) << " with " << tm2.number_of_faces() << " faces." << std::endl; + // + // std::cout << "Read two meshes with " << tm1.number_of_faces() << ", " << tm2.number_of_faces() << " triangles respectively." << std::endl; + + for (int k=0; k(tm1, tm2, error_bounds[k]); + time.stop(); + std::cout << models[i] << " " << models[j] << " " << time.time() << " " << error_bounds[k] << " " << h_dist << std::endl; + } + } + } + + +/* time.start(); std::cout << "Approximated Hausdorff distance: " << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance @@ -85,6 +133,7 @@ int main(int argc, char** argv) << std::endl; time.stop(); std::cout << "Processing took " << time.time() << "s." << std::endl; +*/ /* std::cout << "Approximated Hausdorff distance (naive): " << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance_naive diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 2b290837bed..2123aada381 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -927,6 +927,8 @@ double bounded_error_Hausdorff_impl( Candidate_set candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); Hausdorff_bounds global_bounds = traversal_traits_tm1.get_global_bounds(); + // std::cout << "Culled " << traversal_traits_tm1.get_num_culled_triangles() << " out of " << tm1.num_faces() << std::endl; + /* std::cout << "Found " << candidate_triangles.size() << " candidates." << std::endl; for (int i=0; i m_face_to_triangle_map( &m_tm1, m_vpm1 ); Triangle_3 candidate_triangle = get(m_face_to_triangle_map, primitive.id()); // Call Culling on B with the single triangle found. + // TODO If we project the vertices of the triangle onto B and consider + // the edge length of the triangle, can this give us better bounds + // to initialize with here? Hausdorff_primitive_traits_tm2< Tree_traits, Triangle_3, Kernel, TriangleMesh, VPM2 > traversal_traits_tm2( @@ -298,6 +304,11 @@ namespace CGAL { return Hausdorff_bounds( h_lower, h_upper ); } + int get_num_culled_triangles() + { + return (m_tm1.num_faces() - m_investigated_on_tm1); + } + private: const AABBTraits& m_traits; // The two triangle meshes @@ -313,6 +324,8 @@ namespace CGAL { double h_upper; // List of candidate triangles with their Hausdorff bounds attached Candidate_set m_candidiate_triangles; + // Number of triangles investigated in the procedure + int m_investigated_on_tm1; }; } From 680edc46b1d7de2811e1e81f12fc8d99ff7c041e Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Sun, 21 Jul 2019 11:07:21 +0200 Subject: [PATCH 031/349] Modify triangle bounding box distance to have sharper bounds. --- ...traversal_traits_with_Hausdorff_distance.h | 95 ++++++++++++++++++- 1 file changed, 91 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 2606c1bd5b3..9cd60db374a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -40,6 +40,7 @@ namespace CGAL { typedef typename AABBTraits::Bounding_box Bounding_box; typename Kernel::Construct_projected_point_3 project_point; typedef typename Kernel::Point_3 Point_3; + typedef typename Kernel::Vector_3 Vector_3; public: Hausdorff_primitive_traits_tm2( @@ -112,6 +113,7 @@ namespace CGAL { { /* Have reached a node, determine whether or not to enter it */ + /* // Get the bounding box of the nodes Bounding_box bbox = node.bbox(); // Compute its center @@ -159,6 +161,60 @@ namespace CGAL { } else { return false; } + */ + + // Get the bounding box of the nodes + Bounding_box bbox = node.bbox(); + // Get the vertices of the query triangle + Point_3 v0 = query.vertex(0); + Point_3 v1 = query.vertex(1); + Point_3 v2 = query.vertex(2); + // Find the axis aligned bbox of the triangle + Point_3 tri_min = Point_3 ( + std::min(std::min( v0.x(), v1.x()), v2.x() ), + std::min(std::min( v0.y(), v1.y()), v2.y() ), + std::min(std::min( v0.z(), v1.z()), v2.z() ) + ); + Point_3 tri_max = Point_3 ( + std::max(std::max( v0.x(), v1.x()), v2.x() ), + std::max(std::max( v0.y(), v1.y()), v2.y() ), + std::max(std::max( v0.z(), v1.z()), v2.z() ) + ); + + // Compute distance of the bounding boxes + // Distance along the x-axis + double dist_x = 0.; + if ( tri_max.x() < bbox.min(0) ) { + dist_x = bbox.min(0) - tri_max.x(); + } else if ( bbox.max(0) < tri_min.x() ) { + dist_x = tri_min.x() - bbox.max(0); + } + // Distance along the y-axis + double dist_y = 0.; + if ( tri_max.y() < bbox.min(1) ) { + dist_y = bbox.min(1) - tri_max.y(); + } else if ( bbox.max(1) < tri_min.y() ) { + dist_y = tri_min.y() - bbox.max(1); + } + // Distance along the y-axis + double dist_z = 0.; + if ( tri_max.z() < bbox.min(2) ) { + dist_z = bbox.min(2) - tri_max.z(); + } else if ( bbox.max(2) < tri_min.z() ) { + dist_z = tri_min.z() - bbox.max(2); + } + + // Lower bound on the distance between the two bounding boxes is given + // as the length of the diagonal of the bounding box between them + double dist = approximate_sqrt( Vector_3(dist_x,dist_y,dist_z).squared_length() ); + + // Check whether investigating the bbox can still lower the Hausdorff + // distance. If so, enter the box. + if ( dist <= h_local_lower) { + return true; + } else { + return false; + } } // Return the local Hausdorff bounds computed for the passed query triangle @@ -194,6 +250,7 @@ namespace CGAL { typedef typename AABBTraits::Bounding_box Bounding_box; typedef ::CGAL::AABB_node Node; typedef typename Kernel::Point_3 Point_3; + typedef typename Kernel::Vector_3 Vector_3; typedef typename Kernel::Triangle_3 Triangle_3; typedef std::pair Candidate_triangle; typedef typename std::vector Candidate_set; @@ -263,10 +320,7 @@ namespace CGAL { bool do_intersect(const Query& /*query*/, const Node& node) const { /* Have reached a node, determine whether or not to enter it */ - - // TODO What's the closest distance of TM2 to the box given by node? - // Can we have a sharper bound on this than the one implemented below? - +/* // Get the bounding box of the nodes Bounding_box bbox = node.bbox(); // Compute its center @@ -290,6 +344,39 @@ namespace CGAL { } else { return false; } +*/ + // Get the bounding box of the nodes + Bounding_box bbox = node.bbox(); + // Compute its center + Point_3 center = Point_3( + (bbox.min(0) + bbox.max(0)) / 2, + (bbox.min(1) + bbox.max(1)) / 2, + (bbox.min(2) + bbox.max(2)) / 2); + // Find the point from TM2 closest to the center + // TODO Insert a hint here to accelerate the query + Point_3 closest = m_tm2_tree.closest_point(center); + // Compute the difference vector between the bbox center and the closest + // point in tm2 + Vector_3 difference = Vector_3( closest, center ); + // Shift the vector to be the difference between the farthest corner + // of the bounding box away from the closest point on TM2 + double diff_x = (bbox.max(0) - bbox.min(0)) / 2; + if (difference.x() < 0) diff_x = diff_x * -1.; + double diff_y = (bbox.max(1) - bbox.min(1)) / 2; + if (difference.y() < 0) diff_y = diff_y * -1.; + double diff_z = (bbox.max(2) - bbox.min(2)) / 2; + if (difference.z() < 0) diff_z = diff_z * -1.; + difference = difference + Vector_3( diff_x, diff_y, diff_z ); + // Compute distance from the farthest corner of the bbox to the closest + // point in TM2 + double dist = approximate_sqrt( difference.squared_length() ); + + // If the distance is larger than the global lower bound, enter the node, i.e. return true. + if (dist > h_lower) { + return true; + } else { + return false; + } } // Return those triangles from TM1 which are candidates for including a From 405cf122493c4e9c98a9164d8424a1ba287df0b2 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Sun, 21 Jul 2019 14:18:35 +0200 Subject: [PATCH 032/349] Implement Priority Queue for the set of candidate triangles. --- .../CGAL/Polygon_mesh_processing/distance.h | 44 +++++++++---------- ...traversal_traits_with_Hausdorff_distance.h | 41 ++++++++++++++--- .../test_pmp_distance.cpp | 8 ++-- 3 files changed, 63 insertions(+), 30 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 2123aada381..3293fbbc116 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -898,13 +898,19 @@ double bounded_error_Hausdorff_impl( typedef typename boost::property_map::const_type Triangle_hausdorff_bounds; typedef std::pair Hausdorff_bounds; - typedef std::pair Candidate_triangle; - typedef typename std::vector Candidate_set; typename Kernel::Compute_squared_distance_3 squared_distance; typename Kernel::Construct_projected_point_3 project_point; typename Kernel::FT dist; + typedef + #if BOOST_VERSION >= 105000 + boost::heap::priority_queue< Candidate_triangle, boost::heap::compare< std::greater > > > + #else + std::priority_queue< Candidate_triangle > + #endif + Heap_type; + // Build an AABB tree on tm1 TM1_tree tm1_tree( faces(tm1).begin(), faces(tm1).end(), tm1, vpm1 ); tm1_tree.build(); @@ -924,7 +930,7 @@ double bounded_error_Hausdorff_impl( // TODO Implement the candidate_triangles set as Stack instead of Vector // check: https://www.boost.org/doc/libs/1_55_0/doc/html/heap.html // Can already build a sorted structure while collecting the candidates - Candidate_set candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); + Heap_type candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); Hausdorff_bounds global_bounds = traversal_traits_tm1.get_global_bounds(); // std::cout << "Culled " << traversal_traits_tm1.get_num_culled_triangles() << " out of " << tm1.num_faces() << std::endl; @@ -940,27 +946,27 @@ double bounded_error_Hausdorff_impl( double squared_error_bound = error_bound * error_bound; - while ( (global_bounds.second - global_bounds.first > error_bound) && candidate_triangles.size() > 0 ) { + while ( (global_bounds.second - global_bounds.first > error_bound) && !candidate_triangles.empty() ) { // std::cout << "Current number candidates: " << candidate_triangles.size() << std::endl; // std::cout << "Current global bounds: (" << global_bounds.first << ", " << global_bounds.second << ")" << std::endl; // Get the first triangle and its Hausdorff bounds from the candidate set - Candidate_triangle triangle_and_bound = candidate_triangles.back(); + Candidate_triangle triangle_and_bound = candidate_triangles.top(); // Remove it from the candidate set as it will be processed now - candidate_triangles.pop_back(); + candidate_triangles.pop(); // Only process the triangle if it can contribute to the Hausdorff distance, // i.e. if its Upper Bound is higher than the currently known best lower bound // and the difference between the bounds to be obtained is larger than the // user given error. - Hausdorff_bounds triangle_bounds = triangle_and_bound.second; + Hausdorff_bounds triangle_bounds = triangle_and_bound.m_bounds; // std::cout << "Current triangle bounds: (" << triangle_bounds.first << ", " << triangle_bounds.second << ")" << std::endl; if ( (triangle_bounds.second > global_bounds.first) && (triangle_bounds.second - triangle_bounds.first > error_bound) ) { // Get the triangle that is to be subdivided and read its vertices - Triangle_3 triangle_for_subdivision = triangle_and_bound.first; + Triangle_3 triangle_for_subdivision = triangle_and_bound.m_triangle; Point_3 v0 = triangle_for_subdivision.vertex(0); Point_3 v1 = triangle_for_subdivision.vertex(1); Point_3 v2 = triangle_for_subdivision.vertex(2); @@ -1012,27 +1018,17 @@ double bounded_error_Hausdorff_impl( ); tm2_tree.traversal(sub_triangles[i], traversal_traits_tm2); - // Get the highest current bound from all candidate triangles - double current_max = 0.; - for(auto&& ct: candidate_triangles) { - if (ct.second.second > current_max) { - current_max = ct.second.second; - } - } - - // Update global Hausdorff bounds according to the obtained local bounds + // Update global lower Hausdorff bound according to the obtained local bounds Hausdorff_bounds local_bounds = traversal_traits_tm2.get_local_bounds(); if (local_bounds.first > global_bounds.first) { global_bounds.first = local_bounds.first; } - global_bounds.second = std::max( - std::max(current_max, local_bounds.second), - global_bounds.first - ); // TODO Additionally store the face descriptor of the parent from TM1 in the Candidate_triangle. // Add the subtriangle to the candidate list - candidate_triangles.push_back(Candidate_triangle(sub_triangles[i], local_bounds)); + candidate_triangles.push( + Candidate_triangle(sub_triangles[i], local_bounds) + ); // std::cout << "Split triangle (" << v0 << ", " << v1 << ", " << v2 // << ") with bounds: (" << triangle_bounds.first << ", " @@ -1042,6 +1038,10 @@ double bounded_error_Hausdorff_impl( // << local_bounds.first << ", " << local_bounds.second << "), gobal bounds are: (" // << global_bounds.first << ", " << global_bounds.second << ")" << std::endl; } + + // Update global upper Hausdorff bound after subdivision + double current_max = candidate_triangles.top().m_bounds.second; + global_bounds.second = std::max(current_max, global_bounds.first); } } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 9cd60db374a..ccafde7ecc8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -29,6 +29,28 @@ namespace CGAL { typedef std::pair Hausdorff_bounds; + /** + * @struct Candidate_triangle + */ + template + struct Candidate_triangle { + typedef typename Kernel::Triangle_3 Triangle_3; + + Candidate_triangle(const Triangle_3& triangle, const Hausdorff_bounds& bounds) + : m_triangle(triangle), m_bounds(bounds) {} + + Triangle_3 m_triangle; + Hausdorff_bounds m_bounds; + + #if BOOST_VERSION >= 105000 + bool operator<(const Candidate_triangle& other) const { return m_bounds.second < other.m_bounds.second; } + bool operator>(const Candidate_triangle& other) const { return m_bounds.second > other.m_bounds.second; } + #else + bool operator>(const Candidate_triangle& other) const { return m_bounds.second < other.m_bounds.second; } + bool operator<(const Candidate_triangle& other) const { return m_bounds.second > other.m_bounds.second; } + #endif + }; + /** * @class Hausdorff_primitive_traits_tm2 */ @@ -252,11 +274,17 @@ namespace CGAL { typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Vector_3 Vector_3; typedef typename Kernel::Triangle_3 Triangle_3; - typedef std::pair Candidate_triangle; - typedef typename std::vector Candidate_set; + typedef typename std::vector> Candidate_set; typedef AABB_tree< AABB_traits > TM2_tree; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef + #if BOOST_VERSION >= 105000 + boost::heap::priority_queue< Candidate_triangle, boost::heap::compare< std::greater > > > + #else + std::priority_queue< Candidate_triangle > + #endif + Heap_type; public: Hausdorff_primitive_traits_tm1(const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2 ) @@ -311,7 +339,8 @@ namespace CGAL { // Store the triangle given as primitive here as candidate triangle // together with the local bounds it obtained to sind it to subdivision // later - m_candidiate_triangles.push_back(Candidate_triangle(candidate_triangle, local_bounds)); + m_candidiate_triangles.push( Candidate_triangle(candidate_triangle, local_bounds) ); + pq.push( Candidate_triangle(candidate_triangle, local_bounds) ); } // Determine whether child nodes will still contribute to a larger @@ -381,7 +410,7 @@ namespace CGAL { // Return those triangles from TM1 which are candidates for including a // point realizing the Hausdorff distance - Candidate_set get_candidate_triangles() { + Heap_type get_candidate_triangles() { return m_candidiate_triangles; } @@ -410,7 +439,9 @@ namespace CGAL { double h_lower; double h_upper; // List of candidate triangles with their Hausdorff bounds attached - Candidate_set m_candidiate_triangles; + Heap_type m_candidiate_triangles; + // Heap of candidate triangles with their Hausdorff bounds attached + Heap_type pq; // Number of triangles investigated in the procedure int m_investigated_on_tm1; }; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp index 33b17e54de2..6a499023c7b 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp @@ -300,12 +300,14 @@ int main(int, char** argv) time.stop(); std::cout << "done in " << time.time() << "s.\n"; + double error_bound = 0.001; + time.reset(); time.start(); std::cout << "Lower bound on Hausdorff distance between meshes (sequential), " - << "the actual distance is at most " << 0.01 << " larger than " + << "the actual distance is at most " << error_bound << " larger than " << PMP::bounded_error_Hausdorff_distance_naive( - m1,m2,0.01) + m1,m2,error_bound) << "\n"; time.stop(); std::cout << "done in " << time.time() << "s.\n"; @@ -314,7 +316,7 @@ int main(int, char** argv) time.start(); std::cout << "Bounded Hausdorff distance between meshes (sequential), optimized implementation " << PMP::bounded_error_Hausdorff_distance( - m1,m2,0.01) + m1,m2,error_bound) << "\n"; time.stop(); std::cout << "done in " << time.time() << "s.\n"; From e7e724e4f9eef0e0d2adac11b575a7a7a41b96bd Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Fri, 23 Aug 2019 07:44:08 +0200 Subject: [PATCH 033/349] Include Benchmark examples in the Hausdorff examples file. --- ...usdorff_bounded_error_distance_example.cpp | 157 +++++++++--------- 1 file changed, 82 insertions(+), 75 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index f4146d98877..c0a18953ac2 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -1,8 +1,13 @@ +#include +#include +#include #include #include +#include #include #include #include +#include #include #if defined(CGAL_LINKED_WITH_TBB) @@ -14,6 +19,7 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_3 Point_3; typedef K::Triangle_3 Triangle_3; +typedef K::Vector_3 Vector_3; typedef CGAL::Surface_mesh Mesh; typedef Mesh::Vertex_index Vertex_index; @@ -28,21 +34,35 @@ int main(int argc, char** argv) CGAL::Real_timer time; // Set an error bound - double error_bound = 0.01; + double error_bound = 0.0001; -/* - // Easy Example +// ---------------------------------------------------------------------------- + + // Easy Example of a tetrahedron and a remeshed version of itself + + // Create the Tetrahedron CGAL::make_tetrahedron(Point_3(.0,.0,.0), Point_3(2,.0,.0), Point_3(1,1,1), Point_3(1,.0,2), tm1); + // Copy it and remesh it tm2=tm1; - CGAL::Polygon_mesh_processing::isotropic_remeshing(tm2.faces(),.05, tm2); -*/ + PMP::isotropic_remeshing(tm2.faces(),.05, tm2); + // Compute the Hausdorff distance + time.reset(); + time.start(); + std::cout << "Approximated Hausdorff distance: " + << PMP::bounded_error_Hausdorff_distance + (tm1, tm2, error_bound) + << std::endl; + time.stop(); + std::cout << "Processing took " << time.time() << "s." << std::endl; + // ---------------------------------------------------------------------------- -/* + // Example with point realizing the Hausdorff distance strictly lying in the + // interior of a triangle tm1 = Mesh(); tm1.add_vertex( Point_3(-1.,1.,1.) ); @@ -50,8 +70,6 @@ int main(int argc, char** argv) tm1.add_vertex( Point_3(1.,1.,1.) ); tm1.add_face( tm1.vertices() ); - std::cout << "TM1 is valid: " << (tm1.is_valid() ? "true" : "false") << std::endl; - tm2 = Mesh(); Vertex_index w0 = tm2.add_vertex( Point_3(-1.,1.,0.) ); Vertex_index w1 = tm2.add_vertex( Point_3(0.,-1.,0.) ); @@ -63,82 +81,71 @@ int main(int argc, char** argv) tm2.add_face( w1, w4, w5 ); tm2.add_face( w2, w5, w3 ); - std::cout << "TM2 is valid: " << (tm2.is_valid() ? "true" : "false") << std::endl; -*/ + // Compute the Hausdorff distance + time.reset(); + time.start(); + std::cout << "Approximated Hausdorff distance: " + << PMP::bounded_error_Hausdorff_distance + (tm1, tm2, error_bound) + << std::endl; + time.stop(); + std::cout << "Processing took " << time.time() << "s." << std::endl; + // ---------------------------------------------------------------------------- -/* - // Read a real mesh given by the user + + // Read a real meshes given by the user, perturb it slightly and compute the + // Hausdorff distance between the original mesh and its pertubation + std::ifstream input( argv[1] ); input >> tm1; std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl; + // Copy the mesh and perturb it slightly + tm2 = tm1; + bool do_project = false; + PMP::random_perturbation( tm2.vertices(), tm2, 0.1, do_project ); + std::cout << "Perturbed the input mesh, now computing the Hausdorff distance." << std::endl; + + // Compute the Hausdorff distance + time.reset(); + time.start(); + std::cout << "Approximated Hausdorff distance: " + << PMP::bounded_error_Hausdorff_distance + (tm1, tm2, error_bound) + << std::endl; + time.stop(); + std::cout << "Processing took " << time.time() << "s." << std::endl; + +// ---------------------------------------------------------------------------- + + // Read two meshes given by the user, initially place them at their originally + // given position. Move the second mesh in 300 steps away from the first one. + // Print how the Hausdorff distance changes. + + std::ifstream input1( argv[1] ); + input1 >> tm1; + std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl; + std::ifstream input2( argv[2] ); input2 >> tm2; std::cout << "Read a mesh with " << tm2.number_of_faces() << " triangles." << std::endl; - // Copy the mesh and perturb it slightly - tm2 = tm1; - bool do_project = false; - CGAL::Polygon_mesh_processing::random_perturbation( tm2.vertices(), tm2, 0.1, do_project ); - std::cout << "Perturbed the input mesh, now computing the Hausdorff distance." << std::endl; -*/ -// ---------------------------------------------------------------------------- + CGAL::Bbox_3 bb = PMP::bbox(tm2); + double dist = CGAL::approximate_sqrt( Vector_3(bb.xmax() - bb.xmin(), bb.ymax() - bb.ymin(), bb.zmax() - bb.zmin()).squared_length() ); - // Pairwise computation on a set of benchmark models - std::vector models = {"80","102","128","162","204","256","320","402","504","632","792","992","1242"}; - int num_models = models.size(); - std::string prefix = "/home/martin/Downloads/bunnies/bunny_"; - std::string postfix = ".off"; - std::vector error_bounds = { 0.1, 0.01, 0.001, 0.0001 }; - - std::ifstream input(prefix + models[0] + postfix); - // input >> tm1; - // input >> tm2; - // std::cout << "Initialized with a mesh at " << (prefix + models[0] + postfix) << " with " << tm1.number_of_faces() << " triangles." << std::endl; - - for(int i=0; i> tm1; - // std::cout << "Read a mesh at " << (prefix + models[i] + postfix) << " with " << tm1.number_of_faces() << " faces." << std::endl; - - for(int j=0; j> tm2; - // std::cout << "Read a mesh at " << (prefix + models[j] + postfix) << " with " << tm2.number_of_faces() << " faces." << std::endl; - // - // std::cout << "Read two meshes with " << tm1.number_of_faces() << ", " << tm2.number_of_faces() << " triangles respectively." << std::endl; - - for (int k=0; k(tm1, tm2, error_bounds[k]); - time.stop(); - std::cout << models[i] << " " << models[j] << " " << time.time() << " " << error_bounds[k] << " " << h_dist << std::endl; - } - } + for (int i=0; i<300; i++) { + PMP::transform( + CGAL::Aff_transformation_3 ( CGAL::Translation(), Vector_3( 0.01*dist, 0.01*dist, 0.01*dist ) ), + tm2 + ); + time.reset(); + time.start(); + std::cout << "Position: " << i << std::endl; + std::cout << "Approximated Hausdorff distance: " + << PMP::bounded_error_Hausdorff_distance + (tm1, tm2, error_bound) + << std::endl; + time.stop(); + std::cout << "Processing took " << time.time() << "s." << std::endl; } - - -/* - time.start(); - std::cout << "Approximated Hausdorff distance: " - << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance - (tm1, tm2, error_bound) - << std::endl; - time.stop(); - std::cout << "Processing took " << time.time() << "s." << std::endl; -*/ -/* - std::cout << "Approximated Hausdorff distance (naive): " - << CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance_naive - (tm1, tm2, error_bound) - << ", the actual distance is at most " << error_bound << " larger." - << std::endl; -*/ } From 1e37c32d6e1dc29398403f6412f1466699928cf7 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Fri, 23 Aug 2019 07:46:52 +0200 Subject: [PATCH 034/349] Write first lines of documentation to test linking and inclusion of example. --- .../Polygon_mesh_processing.txt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 004aad17948..47f486bbc62 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -729,10 +729,12 @@ which enables to treat one or several connected components as a face graph. \cgalExample{Polygon_mesh_processing/face_filtered_graph_example.cpp} -\section PMPDistance Approximate Hausdorff Distance +\section PMPDistance (Approximate) Hausdorff Distance This package provides methods to compute (approximate) distances between meshes and point sets. +\subsection Approximate Hausdorff Distance + The function \link approximate_Hausdorff_distance() `approximate_Hausdorff_distance()`\endlink computes an approximation of the Hausdorff distance from a mesh `tm1` to a mesh `tm2`. Given a a sampling of `tm1`, it computes the distance to `tm2` of the farthest sample point to `tm2` \cgalCite{cignoni1998metro}. @@ -757,12 +759,12 @@ computes an approximation of the Hausdorff distance from a mesh to a point set. For each triangle, a lower and upper bound of the Hausdorff distance to the point set are computed. Triangles are refined until the difference between the bounds is lower than a user-defined precision threshold. -\subsection AHDExample Approximate Hausdorff Distance Example +\subsubsection AHDExample Approximate Hausdorff Distance Example In the following example, a mesh is isotropically remeshed and the approximate distance between the input and the output is computed. \cgalExample{Polygon_mesh_processing/hausdorff_distance_remeshing_example.cpp} -\subsection PoissonDistanceExample Max Distance Between Point Set and Surface Example +\subsubsection PoissonDistanceExample Max Distance Between Point Set and Surface Example In \ref Poisson_surface_reconstruction_3/poisson_reconstruction_example.cpp, a triangulated surface mesh is constructed from a point set using the \link PkgPoissonSurfaceReconstruction3 Poisson reconstruction algorithm \endlink, @@ -771,6 +773,14 @@ with the following code: \snippet Poisson_surface_reconstruction_3/poisson_reconstruction_example.cpp PMP_distance_snippet +\subsection Bounded Hausdorff Distance + +The function \link bounded_error_Hausdorff_distance() `bounded_error_Hausdorff_distance()`\endlink +computes an estimate of the Hausdorff distance of two triangle meshes which is +bounded by a user-given error bound. + +\cgalExample{POlygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp} + \section PMPDetectFeatures Feature Detection This package provides methods to detect some features of a polygon mesh. From ba0a67190f02f55209c59a7120aa847ecaafab44 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Fri, 23 Aug 2019 07:47:46 +0200 Subject: [PATCH 035/349] Clean up Code. --- .../CGAL/Polygon_mesh_processing/distance.h | 238 +----------------- ...traversal_traits_with_Hausdorff_distance.h | 93 +------ 2 files changed, 15 insertions(+), 316 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 3293fbbc116..1bd5f39fe85 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -816,49 +816,7 @@ double approximate_symmetric_Hausdorff_distance(const TriangleMesh& tm1, //////////////////////////////////////////////////////////////////////// namespace internal { -/* -#if defined(CGAL_LINKED_WITH_TBB) -template -struct Distance_computation{ - const AABB_tree& tree; - const std::vector& sample_points; - Point_3 initial_hint; - tbb::atomic* distance; - Distance_computation( - const AABB_tree& tree, - const Point_3& p, - const std::vector& sample_points, - tbb::atomic* d) - : tree(tree) - , sample_points(sample_points) - , initial_hint(p) - , distance(d) - {} - - void - operator()(const tbb::blocked_range& range) const - { - Point_3 hint = initial_hint; - double hdist = 0; - for( std::size_t i = range.begin(); i != range.end(); ++i) - { - hint = tree.closest_point(sample_points[i], hint); - typename Kernel_traits::Kernel::Compute_squared_distance_3 squared_distance; - double d = to_double(CGAL::approximate_sqrt( squared_distance(hint,sample_points[i]) )); - if (d>hdist) hdist=d; - } - - // update max value stored in distance - double current_value = *distance; - while( current_value < hdist ) - { - current_value = distance->compare_and_swap(hdist, current_value); - } - } -}; -#endif -*/ template hint = tm2_tree.any_reference_point_and_id(); // Build traversal traits for tm1_tree - Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2 ); + Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, hint.first ); // Find candidate triangles in TM1 which might realise the Hausdorff bound tm1_tree.traversal( Point_3(0,0,0), traversal_traits_tm1 ); // dummy point given as query as not needed - // TODO Implement the candidate_triangles set as Stack instead of Vector - // check: https://www.boost.org/doc/libs/1_55_0/doc/html/heap.html - // Can already build a sorted structure while collecting the candidates + // TODO Is there a better/faster data structure than the Heap used here? + // Can already build a sorted structure while collecting the candidates Heap_type candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); Hausdorff_bounds global_bounds = traversal_traits_tm1.get_global_bounds(); - // std::cout << "Culled " << traversal_traits_tm1.get_num_culled_triangles() << " out of " << tm1.num_faces() << std::endl; - -/* - std::cout << "Found " << candidate_triangles.size() << " candidates." << std::endl; - for (int i=0; i(sub_triangles[i], local_bounds) ); - - // std::cout << "Split triangle (" << v0 << ", " << v1 << ", " << v2 - // << ") with bounds: (" << triangle_bounds.first << ", " - // << triangle_bounds.second << "), sub-triangle " << i - // << " (" << sub_triangles[i].vertex(0) << ", " << sub_triangles[i].vertex(1) << ", " << sub_triangles[i].vertex(2) - // << ") has bounds: (" - // << local_bounds.first << ", " << local_bounds.second << "), gobal bounds are: (" - // << global_bounds.first << ", " << global_bounds.second << ")" << std::endl; } // Update global upper Hausdorff bound after subdivision @@ -1045,12 +985,6 @@ double bounded_error_Hausdorff_impl( } } - // Print result found -/* - std::cout << "Processing candidates finished, found distance (lower, upper): (" - << global_bounds.first << ", " << global_bounds.second << ")" << std::endl; -*/ - // Return linear interpolation between found lower and upper bound return (global_bounds.first + global_bounds.second) / 2.; @@ -1058,134 +992,8 @@ double bounded_error_Hausdorff_impl( CGAL_static_assertion_msg (!(boost::is_convertible::value), "Parallel_tag is enabled but TBB is unavailable."); #else - // TODO implement parallelized version of the below here. - // if (boost::is_convertible::value) - // { - // tbb::atomic distance; - // distance=0; - // Distance_computation f(tm2_tree - // , hint, sample_points, &distance); - // tbb::parallel_for(tbb::blocked_range(0, sample_points.size()), f); - // return distance; - // } - // else + // TODO implement parallelized version of the above here. #endif -/* - { - // Store all vertices of tm1 in a vector - std::vector tm1_vertices; - tm1_vertices.reserve(num_vertices(tm1)); - tm1_vertices.insert(tm1_vertices.end(),vertices(tm1).begin(),vertices(tm1).end()); - - // Sort vertices along a Hilbert curve - spatial_sort( tm1_vertices.begin(), - tm1_vertices.end(), - Search_traits_3(vpm1) ); - - // For each vertex in tm1, store the distance to the closest triangle of tm2 - Vertex_closest_triangle_map vctm = get(Vertex_property_tag(), tm1); - // For each triangle in tm1, sotre its respective local lower and upper bound - // on the Hausdorff measure - Triangle_hausdorff_bounds thb = get(Face_property_tag(), tm1); - - // For each vertex in the first mesh, find the closest triangle in the - // second mesh, store it and also store the distance to this triangle - // in a dynamic vertex property - for(vertex_descriptor vd : tm1_vertices) - { - // Get the point represented by the vertex - typename boost::property_traits::reference pt = get(vpm1, vd); - // Use the AABB tree to find the closest point and face in tm2 - hint = tm2_tree.closest_point_and_primitive(pt, hint); - // Compute the distance of the point to the closest point in tm2 - dist = squared_distance(hint.first, pt); - double d = to_double(dist); - // Store the distance and the closest triangle in the corresponding map - put(vctm, vd, std::make_pair(d, hint.second)); - } - - // Maps the faces of tm2 to actual triangles - Triangle_from_face_descriptor_map face_to_triangle_map(&tm2, vpm2); - // Initialize global bounds on the Hausdorff measure - double h_lower = 0.; - double h_upper = 0.; - // Initialize an array of candidate triangles in A to be procesed in the - // following - std::vector candidate_triangles; - - // For each triangle in the first mesh, initialize its local upper and - // lower bound and store these in a dynamic face property for furture - // reference - for(face_descriptor fd : faces(tm1)) - { - // Initialize the local bounds for the current face fd - double h_triangle_lower = 0.; - double h_triangle_upper = std::numeric_limits::infinity(); - - // Create a halfedge descriptor for the current face and store the vertices - halfedge_descriptor hd = halfedge(fd, tm1); - std::array face_vertices = {source(hd,tm1), target(hd,tm1), target(next(hd, tm1),tm1)}; - - // Get the distance and closest triangle in tm2 for each vertex of fd - std::array,3> vertex_properties = { - get(vctm, face_vertices[0]), - get(vctm, face_vertices[1]), - get(vctm, face_vertices[2])}; - - // Convert the closest faces of tm2 to triangles - std::array triangles_in_B = { - get(face_to_triangle_map, vertex_properties[0].second), - get(face_to_triangle_map, vertex_properties[1].second), - get(face_to_triangle_map, vertex_properties[2].second)}; - - for(int i=0; i<3; ++i) - { - // Iterate over the vertices by i, the distance to the closest point in - // tm2 computed above is a lower bound for the local triangle - h_triangle_lower = (std::max)(h_triangle_lower, vertex_properties[i].first); - - // Iterate over the triangles by i, if the triangles are the same, we do - // not need to compute the distance, only compute it if the triangles - // differ - double face_distance_1 = vertex_properties[i].second==vertex_properties[(i+1)%3].second - ? vertex_properties[(i+1)%3].first - : squared_distance(project_point(triangles_in_B[i], get(vpm1, face_vertices[(i+1)%3])), get(vpm1, face_vertices[(i+1)%3])); - double face_distance_2 = vertex_properties[i].second==vertex_properties[(i+2)%3].second - ? vertex_properties[(i+2)%3].first - : squared_distance(project_point(triangles_in_B[i], get(vpm1, face_vertices[(i+2)%3])), get(vpm1, face_vertices[(i+2)%3])); - - // Update the local lower bound of the triangle - h_triangle_upper = (std::min)( - (std::max)( - (std::max)(face_distance_1, face_distance_2), - vertex_properties[i].first), - h_triangle_upper); - } - - // Store the computed lower and upper bound in a dynamic face property - put(thb, fd, Hausdorff_bounds(h_triangle_lower, h_triangle_upper)); - h_lower = (std::max)(h_lower, h_triangle_lower); - h_upper = (std::max)(h_upper, h_triangle_upper); - - // Only process the triangle further if it can still contribute to a - // Hausdorff distance - if (h_triangle_upper > h_lower) { - - // TODO culling on B - - candidate_triangles.push_back(fd); - } - } - - - - // TODO Iterate over candidate_triangles and kill those which cannot contribute anymore - - // TODO Send the remaining triangles to the Subdivision - - return (CGAL::approximate_sqrt(h_lower)+CGAL::approximate_sqrt(h_upper))/2.; - } -*/ } template Intel TBB library. - * To control the number of threads used, the user may use the `tbb::task_scheduler_init` class. - * See the TBB documentation - * for more details. - * - * @tparam Concurrency_tag enables sequential versus parallel algorithm. - * Possible values are `Sequential_tag` - * and `Parallel_tag`. - * @tparam TriangleMesh a model of the concept `FaceListGraph` - * @tparam NamedParameters1 a sequence of \ref pmp_namedparameters "Named Parameters" for `tm1` - * @tparam NamedParameters2 a sequence of \ref pmp_namedparameters "Named Parameters" for `tm2` - * - * @param tm1 the triangle mesh that will be sampled - * @param tm2 the triangle mesh to compute the distance to - * @param np1 optional sequence of \ref pmp_namedparameters "Named Parameters" for `tm1` passed to `sample_triangle_mesh()`. - * - * @param np2 optional sequence of \ref pmp_namedparameters "Named Parameters" for `tm2` among the ones listed below - * - * \cgalNamedParamsBegin - * \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm2` - * If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` must be available in `TriangleMesh` - * and in all places where `vertex_point_map` is used. - * \cgalParamEnd - * \cgalNamedParamsEnd - * The function `CGAL::parameters::all_default()` can be used to indicate to use the default values for - * `np1` and specify custom values for `np2` - */ - /* * Implementation of Bounded Hausdorff distance computation using AABBTree * culling. diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index ccafde7ecc8..bfc57ee5895 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -133,58 +133,6 @@ namespace CGAL { // Hausdorff distance and thus have to be entered bool do_intersect(const Query& query, const Node& node) const { - /* Have reached a node, determine whether or not to enter it */ - - /* - // Get the bounding box of the nodes - Bounding_box bbox = node.bbox(); - // Compute its center - Point_3 bb_center = Point_3( - (bbox.min(0) + bbox.max(0)) / 2, - (bbox.min(1) + bbox.max(1)) / 2, - (bbox.min(2) + bbox.max(2)) / 2); - - // Get the center of the query triangle - // The query object is a triangle from TM1, get its vertices - Point_3 v0 = query.vertex(0); - Point_3 v1 = query.vertex(1); - Point_3 v2 = query.vertex(2); - // Compute the centroid of the triangle - Point_3 tri_center = centroid( query ); - - // Compute the distance of the center to the closest point in tm2 - double dist = approximate_sqrt(squared_distance(bb_center, tri_center)); - - // Compute the radius of the circumsphere of the bounding boxes - double bb_radius = approximate_sqrt(squared_distance( - Point_3(bbox.min(0),bbox.min(1),bbox.min(2)), - Point_3(bbox.max(0),bbox.max(1),bbox.max(2))) - )/2.; - - // Compute the radius of the circumcircle of the triangle - double tri_radius = approximate_sqrt( std::max( - std::max( - squared_distance(tri_center, v0), - squared_distance(tri_center, v1) - ), - squared_distance(tri_center, v2) - )); - - // Find a lower bound on the distance of the triangle to the bounding box - // by taking the distance from the triangle center to the bbox center - // and subtracting the radii of both elements. Thereby, each triangle in - // the bounding box has at least distance - // ( dist - triangle_radius - bbox_radius ) - // to the query triangle. Only if this lower bound is lower than the - // current best known lower bound, we enter the node, trying to - // lower the lower bound further. - if ( (dist - tri_radius - bb_radius) <= h_local_lower) { - return true; - } else { - return false; - } - */ - // Get the bounding box of the nodes Bounding_box bbox = node.bbox(); // Get the vertices of the query triangle @@ -287,8 +235,12 @@ namespace CGAL { Heap_type; public: - Hausdorff_primitive_traits_tm1(const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2 ) - : m_traits(traits), m_tm2_tree(tree), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2) { + Hausdorff_primitive_traits_tm1( + const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, + const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2, + const Point_3 hint ) + : m_traits(traits), m_tm2_tree(tree), m_tm1(tm1), m_tm2(tm2), + m_vpm1(vpm1), m_vpm2(vpm2) { // Initialize the global bounds with 0., they will only grow. h_lower = 0.; h_upper = 0.; @@ -310,10 +262,11 @@ namespace CGAL { Triangle_from_face_descriptor_map m_face_to_triangle_map( &m_tm1, m_vpm1 ); Triangle_3 candidate_triangle = get(m_face_to_triangle_map, primitive.id()); + // TODO Can we initialize the bounds here, s.t. we don't start with infty? + // Can we initialize the bounds depending on the closest points in tm2 + // seen from the three vertices? + // Call Culling on B with the single triangle found. - // TODO If we project the vertices of the triangle onto B and consider - // the edge length of the triangle, can this give us better bounds - // to initialize with here? Hausdorff_primitive_traits_tm2< Tree_traits, Triangle_3, Kernel, TriangleMesh, VPM2 > traversal_traits_tm2( @@ -349,7 +302,6 @@ namespace CGAL { bool do_intersect(const Query& /*query*/, const Node& node) const { /* Have reached a node, determine whether or not to enter it */ -/* // Get the bounding box of the nodes Bounding_box bbox = node.bbox(); // Compute its center @@ -358,31 +310,6 @@ namespace CGAL { (bbox.min(1) + bbox.max(1)) / 2, (bbox.min(2) + bbox.max(2)) / 2); // Find the point from TM2 closest to the center - // TODO Insert a hint here to accelerate the query - Point_3 closest = m_tm2_tree.closest_point(center); - // Compute the distance of the center to the closest point in tm2 - double dist = approximate_sqrt(squared_distance(center, closest)); - // Compute the radius of the circumsphere of the bounding boxes - double radius = approximate_sqrt(squared_distance( - Point_3(bbox.min(0),bbox.min(1),bbox.min(2)), - Point_3(bbox.max(0),bbox.max(1),bbox.max(2))) - )/2.; - // If the distance is larger than the global lower bound, enter the node, i.e. return true. - if (dist + radius > h_lower) { - return true; - } else { - return false; - } -*/ - // Get the bounding box of the nodes - Bounding_box bbox = node.bbox(); - // Compute its center - Point_3 center = Point_3( - (bbox.min(0) + bbox.max(0)) / 2, - (bbox.min(1) + bbox.max(1)) / 2, - (bbox.min(2) + bbox.max(2)) / 2); - // Find the point from TM2 closest to the center - // TODO Insert a hint here to accelerate the query Point_3 closest = m_tm2_tree.closest_point(center); // Compute the difference vector between the bbox center and the closest // point in tm2 From 68f7fac25435fb6957f9e865375056d48d71511a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 23 Aug 2019 09:49:08 +0200 Subject: [PATCH 036/349] update doc to make links working --- .../doc/Polygon_mesh_processing/PackageDescription.txt | 1 + .../doc/Polygon_mesh_processing/Polygon_mesh_processing.txt | 4 ++-- .../doc/Polygon_mesh_processing/examples.txt | 1 + .../include/CGAL/Polygon_mesh_processing/distance.h | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index 032167d48e0..9051cce6097 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -176,6 +176,7 @@ and provides a list of the parameters that are used in this package. - \link measure_grp `CGAL::Polygon_mesh_processing::centroid()` \endlink \cgalCRPSection{Distance Functions} +- `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` - `CGAL::Polygon_mesh_processing::approximate_Hausdorff_distance()` - `CGAL::Polygon_mesh_processing::approximate_symmetric_Hausdorff_distance()` - `CGAL::Polygon_mesh_processing::approximate_max_distance_to_point_set()` diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 47f486bbc62..214b290b46d 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -775,11 +775,11 @@ with the following code: \subsection Bounded Hausdorff Distance -The function \link bounded_error_Hausdorff_distance() `bounded_error_Hausdorff_distance()`\endlink +The function `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` computes an estimate of the Hausdorff distance of two triangle meshes which is bounded by a user-given error bound. -\cgalExample{POlygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp} +\cgalExample{Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp} \section PMPDetectFeatures Feature Detection diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt index f5aa23b864b..a8bde70c86b 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt @@ -23,4 +23,5 @@ \example Polygon_mesh_processing/detect_features_example.cpp \example Polygon_mesh_processing/manifoldness_repair_example.cpp \example Polygon_mesh_processing/repair_polygon_soup_example.cpp +\example Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp */ diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 1bd5f39fe85..409f7cadd5f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1110,7 +1110,8 @@ double bounded_error_Hausdorff_naive_impl( } //end of namespace internal -/* +/** + * \ingroup PMP_distance_grp * Implementation of Bounded Hausdorff distance computation using AABBTree * culling. */ From 316cae0dd95f5f819727b05873c6b370e6a23443 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Fri, 23 Aug 2019 17:30:07 +0200 Subject: [PATCH 037/349] Finalize documentation of bounded Hausdorff Distance computation and make print outs optional via a debug parameter. --- Documentation/doc/biblio/geom.bib | 11 ++++ .../Polygon_mesh_processing.txt | 31 +++++++++- .../CGAL/Polygon_mesh_processing/distance.h | 59 ++++++++++++++++--- 3 files changed, 90 insertions(+), 11 deletions(-) diff --git a/Documentation/doc/biblio/geom.bib b/Documentation/doc/biblio/geom.bib index d4bf473db7f..56f88ba33b6 100644 --- a/Documentation/doc/biblio/geom.bib +++ b/Documentation/doc/biblio/geom.bib @@ -152016,3 +152016,14 @@ pages = {179--189} HAL_ID = {inria-00412437}, HAL_VERSION = {v1}, } + +@inproceedings{tang2009interactive, + title={Interactive Hausdorff distance computation for general polygonal models}, + author={Tang, Min and Lee, Minkyoung and Kim, Young J}, + booktitle={ACM Transactions on Graphics (TOG)}, + volume={28}, + number={3}, + pages={74}, + year={2009}, + organization={ACM} +} diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 214b290b46d..bf0ab568159 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -733,7 +733,7 @@ which enables to treat one or several connected components as a face graph. This package provides methods to compute (approximate) distances between meshes and point sets. -\subsection Approximate Hausdorff Distance +\subsection ApproxHD Approximate Hausdorff Distance The function \link approximate_Hausdorff_distance() `approximate_Hausdorff_distance()`\endlink computes an approximation of the Hausdorff distance from a mesh `tm1` to a mesh `tm2`. Given a @@ -773,11 +773,36 @@ with the following code: \snippet Poisson_surface_reconstruction_3/poisson_reconstruction_example.cpp PMP_distance_snippet -\subsection Bounded Hausdorff Distance +\subsection BoundedHD Bounded Hausdorff Distance The function `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` computes an estimate of the Hausdorff distance of two triangle meshes which is -bounded by a user-given error bound. +bounded by a user-given error bound. Given two meshes tm1 and tm2, it follows +the procedure given by \cgalCite{tang2009interactive}. Namely, an AABB tree is +built on tm1 and tm2 respectively. The tree on tm1 is used to iterate over all +triangles in tm1. For each triangle t in tm1, by traversing the tree on tm2, +by keeping track of current global bounds on the distance, it +is estimated whether this triangle can still contribute to the actual +Hausdorff distance. From this process, a set of candidate triangles is selected. + +The candidate triangles are subsequently subdivided and for each smaller +triangle, the tree on tm2 is traversed again. This is repeated until the +triangle is smaller than the user-given error bound, all vertices of the +triangle are projected onto the same triangle in tm2, or the triangle's upper +bound is lower than the global lower bound. After creation, the subdivided +triangles are added to the list of candidate triangles. Thereby, all candidate +triangles are processed until a triangle is found in which the Hausdorff +distance is realized or in which it is guaranteed to be realized within the +user-given error bound. + +\subsubsection BHDExample Bounded Hausdorff Distance Example + +In the following examples: (a) the distance of a tetrahedron to a remeshed +version of itself is computed, (b) the distance of two geometries is computed +which is realized strictly in the interior of a triangle of the first geometry, +(c) a perturbation of a user-given mesh is compared to the original user-given +mesh, (d) two user-given meshes are compared, where the second mesh is gradually +moved away from the first one. \cgalExample{Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp} diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 409f7cadd5f..111e60cfd16 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -890,15 +890,14 @@ double bounded_error_Hausdorff_impl( Heap_type candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); Hausdorff_bounds global_bounds = traversal_traits_tm1.get_global_bounds(); - std::cout << "Culled " << traversal_traits_tm1.get_num_culled_triangles() << " out of " << tm1.num_faces() << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout << "Culled " << traversal_traits_tm1.get_num_culled_triangles() << " out of " << tm1.num_faces() << std::endl; + #endif double squared_error_bound = error_bound * error_bound; while ( (global_bounds.second - global_bounds.first > error_bound) && !candidate_triangles.empty() ) { - // std::cout << "Current number candidates: " << candidate_triangles.size() << std::endl; - // std::cout << "Current global bounds: (" << global_bounds.first << ", " << global_bounds.second << ")" << std::endl; - // Get the first triangle and its Hausdorff bounds from the candidate set Candidate_triangle triangle_and_bound = candidate_triangles.top(); // Remove it from the candidate set as it will be processed now @@ -910,8 +909,6 @@ double bounded_error_Hausdorff_impl( // user given error. Hausdorff_bounds triangle_bounds = triangle_and_bound.m_bounds; - // std::cout << "Current triangle bounds: (" << triangle_bounds.first << ", " << triangle_bounds.second << ")" << std::endl; - if ( (triangle_bounds.second > global_bounds.first) && (triangle_bounds.second - triangle_bounds.first > error_bound) ) { // Get the triangle that is to be subdivided and read its vertices Triangle_3 triangle_for_subdivision = triangle_and_bound.m_triangle; @@ -1112,8 +1109,21 @@ double bounded_error_Hausdorff_naive_impl( /** * \ingroup PMP_distance_grp - * Implementation of Bounded Hausdorff distance computation using AABBTree - * culling. + * returns an estimate on the Hausdorff distance between `tm1` and `tm2` that + * is at most `error_bound` away from the actual Hausdorff distance between + * the two given meshes. + * @tparam Concurrency_tag enables sequential versus parallel algorithm. + * Possible values are `Sequential_tag` + * and `Parallel_tag`. Currently, parall computation is + * not implemented, though. + * @tparam TriangleMesh a model of the concept `FaceListGraph` + * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" + * @param tm1 a triangle mesh + * @param tm2 a second triangle mesh + * @param error_bound Maximum bound by which the Hausdorff distance estimate is + * allowed to deviate from the actual Hausdorff distance. + * @param np1 an optional sequence of \ref pmp_namedparameters "Named Parameters" + * @param np2 an optional sequence of \ref pmp_namedparameters "Named Parameters" */ template< class Concurrency_tag, class TriangleMesh, @@ -1142,6 +1152,23 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, return internal::bounded_error_Hausdorff_impl(tm1, tm2, error_bound, vpm1, vpm2); } +/** + * \ingroup PMP_distance_grp + * returns an estimate on the Hausdorff distance between `tm1` and `tm2` that + * is at most `error_bound` away from the actual Hausdorff distance between + * the two given meshes. + * @tparam Concurrency_tag enables sequential versus parallel algorithm. + * Possible values are `Sequential_tag` + * and `Parallel_tag`. Currently, parall computation is + * not implemented, though. + * @tparam TriangleMesh a model of the concept `FaceListGraph` + * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" + * @param tm1 a triangle mesh + * @param tm2 a second triangle mesh + * @param error_bound Maximum bound by which the Hausdorff distance estimate is + * allowed to deviate from the actual Hausdorff distance. + * @param np1 an optional sequence of \ref pmp_namedparameters "Named Parameters" + */ template< class Concurrency_tag, class TriangleMesh, class NamedParameters1> @@ -1153,6 +1180,22 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, return bounded_error_Hausdorff_distance(tm1, tm2, error_bound, np1, parameters::all_default()); } +/** + * \ingroup PMP_distance_grp + * returns an estimate on the Hausdorff distance between `tm1` and `tm2` that + * is at most `error_bound` away from the actual Hausdorff distance between + * the two given meshes. + * @tparam Concurrency_tag enables sequential versus parallel algorithm. + * Possible values are `Sequential_tag` + * and `Parallel_tag`. Currently, parall computation is + * not implemented, though. + * @tparam TriangleMesh a model of the concept `FaceListGraph` + * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" + * @param tm1 a triangle mesh + * @param tm2 a second triangle mesh + * @param error_bound Maximum bound by which the Hausdorff distance estimate is + * allowed to deviate from the actual Hausdorff distance. + */ template< class Concurrency_tag, class TriangleMesh> double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, From c5c6ef03baef04fe0cb010c4cd8c0ff2897d5479 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Sat, 24 Aug 2019 11:09:25 +0200 Subject: [PATCH 038/349] Improve text in documentation. --- .../Polygon_mesh_processing/Polygon_mesh_processing.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index bf0ab568159..5bf0d10fae8 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -780,10 +780,11 @@ computes an estimate of the Hausdorff distance of two triangle meshes which is bounded by a user-given error bound. Given two meshes tm1 and tm2, it follows the procedure given by \cgalCite{tang2009interactive}. Namely, an AABB tree is built on tm1 and tm2 respectively. The tree on tm1 is used to iterate over all -triangles in tm1. For each triangle t in tm1, by traversing the tree on tm2, -by keeping track of current global bounds on the distance, it -is estimated whether this triangle can still contribute to the actual -Hausdorff distance. From this process, a set of candidate triangles is selected. +triangles in tm1. Throughout the traversal, the procedure keeps track of a global +lower and upper bound on the Hausdorff distance respectively. For each triangle +t in tm1, by traversing the tree on tm2, it is estimated via the global bounds +whether t can still contribute to the actual Hausdorff distance. From this +process, a set of candidate triangles is selected. The candidate triangles are subsequently subdivided and for each smaller triangle, the tree on tm2 is traversed again. This is repeated until the From 5f2069a6b3618f2526fcfa083cc7315abe8699d8 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Sat, 24 Aug 2019 11:09:36 +0200 Subject: [PATCH 039/349] Document named parameters. --- .../CGAL/Polygon_mesh_processing/distance.h | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 111e60cfd16..fa3a8ae912e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1122,8 +1122,15 @@ double bounded_error_Hausdorff_naive_impl( * @param tm2 a second triangle mesh * @param error_bound Maximum bound by which the Hausdorff distance estimate is * allowed to deviate from the actual Hausdorff distance. - * @param np1 an optional sequence of \ref pmp_namedparameters "Named Parameters" - * @param np2 an optional sequence of \ref pmp_namedparameters "Named Parameters" + * @param np1 an optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below + * @param np2 an optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below + * \cgalNamedParamsBegin + * \cgalParamBegin{vertex_point_map} the property map with the points + * associated to the vertices of `tm`. If this parameter is omitted, + * an internal property map for `CGAL::vertex_point_t` + * must be available for `TriangleMesh`. + * \cgalParamEnd + * \cgalNamedParamsEnd */ template< class Concurrency_tag, class TriangleMesh, @@ -1167,7 +1174,14 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, * @param tm2 a second triangle mesh * @param error_bound Maximum bound by which the Hausdorff distance estimate is * allowed to deviate from the actual Hausdorff distance. - * @param np1 an optional sequence of \ref pmp_namedparameters "Named Parameters" + * @param np1 an optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below + * \cgalNamedParamsBegin + * \cgalParamBegin{vertex_point_map} the property map with the points + * associated to the vertices of `tm`. If this parameter is omitted, + * an internal property map for `CGAL::vertex_point_t` + * must be available for `TriangleMesh`. + * \cgalParamEnd + * \cgalNamedParamsEnd */ template< class Concurrency_tag, class TriangleMesh, From 677908e405b024e01e4495b75ef581a6dca5e024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 30 Aug 2019 13:57:56 +0200 Subject: [PATCH 040/349] Fix NP usage --- .../hausdorff_bounded_error_distance_example.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index c0a18953ac2..491573b68f2 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -103,7 +103,7 @@ int main(int argc, char** argv) // Copy the mesh and perturb it slightly tm2 = tm1; bool do_project = false; - PMP::random_perturbation( tm2.vertices(), tm2, 0.1, do_project ); + PMP::random_perturbation( tm2.vertices(), tm2, 0.1, CGAL::parameters::do_project(do_project)); std::cout << "Perturbed the input mesh, now computing the Hausdorff distance." << std::endl; // Compute the Hausdorff distance From 6027b2d5f78f3e1847b9daeffd9c0a33a8eaab55 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 26 Sep 2019 15:15:50 +0200 Subject: [PATCH 041/349] Add Traits::intersection_with_priority() --- AABB_tree/include/CGAL/AABB_tree.h | 16 +++++ .../CGAL/internal/AABB_tree/AABB_node.h | 68 +++++++++++++++++++ .../CGAL/Polygon_mesh_processing/distance.h | 4 +- ...traversal_traits_with_Hausdorff_distance.h | 15 ++++ 4 files changed, 101 insertions(+), 2 deletions(-) diff --git a/AABB_tree/include/CGAL/AABB_tree.h b/AABB_tree/include/CGAL/AABB_tree.h index b57f0260a05..f7e7e131434 100644 --- a/AABB_tree/include/CGAL/AABB_tree.h +++ b/AABB_tree/include/CGAL/AABB_tree.h @@ -520,6 +520,22 @@ public: } } + + template + void traversal_with_priority(const Query& query, Traversal_traits& traits) const + { + switch(size()) + { + case 0: + break; + case 1: + traits.intersection(query, singleton_data()); + break; + default: // if(size() >= 2) + root_node()->template traversal_with_priority(query, traits, m_primitives.size()); + } + } + private: typedef AABB_node Node; diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h index 5d0cf5ce4d2..d4868b80157 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h @@ -86,6 +86,11 @@ public: Traversal_traits& traits, const std::size_t nb_primitives) const; + template + void traversal_with_priority(const Query& query, + Traversal_traits& traits, + const std::size_t nb_primitives) const; + private: typedef AABBTraits AABB_traits; typedef AABB_node Node; @@ -201,6 +206,69 @@ AABB_node::traversal(const Query& query, } } + + +template +template +void +AABB_node::traversal_with_priority(const Query& query, + Traversal_traits& traits, + const std::size_t nb_primitives) const +{ + // Recursive traversal + switch(nb_primitives) + { + case 2: + traits.intersection(query, left_data()); + if( traits.go_further() ) + { + traits.intersection(query, right_data()); + } + break; + case 3: + traits.intersection(query, left_data()); + if( traits.go_further() && traits.do_intersect(query, right_child()) ) + { + right_child().traversal_with_priority(query, traits, 2); + } + break; + default: + bool ileft, iright; + typename Traversal_traits::Priority pleft, pright; + std::tie(ileft,pleft) = traits.do_intersect_with_priority(query, left_child()); + std::tie(iright,pright) = traits.do_intersect_with_priority(query, right_child()); + + if(pleft >= pright) + { + if( ileft ) + { + left_child().traversal_with_priority(query, traits, nb_primitives/2); + if( traits.go_further() && traits.do_intersect(query, right_child()) ) + { + right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); + } + } + else if( iright ) + { + right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); + } + }else{ + if( iright ) + { + right_child().traversal_with_priority(query, traits, nb_primitives/2); + if( traits.go_further() && traits.do_intersect(query, left_child()) ) + { + left_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); + } + } + else if( ileft ) + { + left_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); + } + } + } +} + } // end namespace CGAL #endif // CGAL_AABB_NODE_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index fa3a8ae912e..f9307b1e8c4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -883,7 +883,7 @@ double bounded_error_Hausdorff_impl( // Build traversal traits for tm1_tree Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, hint.first ); // Find candidate triangles in TM1 which might realise the Hausdorff bound - tm1_tree.traversal( Point_3(0,0,0), traversal_traits_tm1 ); // dummy point given as query as not needed + tm1_tree.traversal_with_priority( Point_3(0,0,0), traversal_traits_tm1 ); // dummy point given as query as not needed // TODO Is there a better/faster data structure than the Heap used here? // Can already build a sorted structure while collecting the candidates @@ -961,7 +961,7 @@ double bounded_error_Hausdorff_impl( std::numeric_limits::infinity(), std::numeric_limits::infinity() ); - tm2_tree.traversal(sub_triangles[i], traversal_traits_tm2); + tm2_tree.traversal_with_priority(sub_triangles[i], traversal_traits_tm2); // Update global lower Hausdorff bound according to the obtained local bounds Hausdorff_bounds local_bounds = traversal_traits_tm2.get_local_bounds(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index bfc57ee5895..b6a7e0804ef 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -65,6 +65,8 @@ namespace CGAL { typedef typename Kernel::Vector_3 Vector_3; public: + typedef int Priority; + Hausdorff_primitive_traits_tm2( const AABBTraits& traits, const TriangleMesh& tm2, @@ -187,6 +189,12 @@ namespace CGAL { } } + std::pair do_intersect_with_priority(const Query& query, const Node& node) const + { + bool b = do_intersect(query, node); + return std::make_pair(b, Priority(0)); + } + // Return the local Hausdorff bounds computed for the passed query triangle Hausdorff_bounds get_local_bounds() { @@ -235,6 +243,7 @@ namespace CGAL { Heap_type; public: + typedef int Priority; Hausdorff_primitive_traits_tm1( const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2, @@ -335,6 +344,12 @@ namespace CGAL { } } + std::pair do_intersect_with_priority(const Query& query, const Node& node) const + { + bool b = do_intersect(query, node); + return std::make_pair(b, Priority(0)); + } + // Return those triangles from TM1 which are candidates for including a // point realizing the Hausdorff distance Heap_type get_candidate_triangles() { From a4aa6a7b770b58ad9be00a651293d59f53e1b967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 26 Sep 2019 15:54:43 +0200 Subject: [PATCH 042/349] rework expression --- .../CGAL/internal/AABB_tree/AABB_node.h | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h index d4868b80157..94eacd277d7 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h @@ -206,8 +206,6 @@ AABB_node::traversal(const Query& query, } } - - template template void @@ -238,34 +236,27 @@ AABB_node::traversal_with_priority(const Query& query, std::tie(ileft,pleft) = traits.do_intersect_with_priority(query, left_child()); std::tie(iright,pright) = traits.do_intersect_with_priority(query, right_child()); - if(pleft >= pright) + if (ileft) { - if( ileft ) + if (iright) + { + if(pleft >= pright) { left_child().traversal_with_priority(query, traits, nb_primitives/2); - if( traits.go_further() && traits.do_intersect(query, right_child()) ) - { - right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); - } + if( traits.go_further() /* && traits.do_intersect(query, right_child()) */ ) // TODO shall we call again do_intersect? + right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); } - else if( iright ) - { - right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); - } - }else{ - if( iright ) + else { right_child().traversal_with_priority(query, traits, nb_primitives/2); - if( traits.go_further() && traits.do_intersect(query, left_child()) ) - { - left_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); - } - } - else if( ileft ) - { - left_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); + if( traits.go_further() /* && traits.do_intersect(query, left_child()) */ ) // TODO shall we call again do_intersect? + left_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); } + } } + else + if (iright) + right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); } } From 3e5e721542ac6ad7852251818e68ff248670f207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 26 Sep 2019 16:06:24 +0200 Subject: [PATCH 043/349] plug do_intersect_with_priority --- ...traversal_traits_with_Hausdorff_distance.h | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index b6a7e0804ef..0683688cf67 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -65,8 +65,8 @@ namespace CGAL { typedef typename Kernel::Vector_3 Vector_3; public: - typedef int Priority; - + typedef double Priority; + Hausdorff_primitive_traits_tm2( const AABBTraits& traits, const TriangleMesh& tm2, @@ -133,7 +133,7 @@ namespace CGAL { // Determine whether child nodes will still contribute to a smaller // Hausdorff distance and thus have to be entered - bool do_intersect(const Query& query, const Node& node) const + std::pair do_intersect_with_priority(const Query& query, const Node& node) const { // Get the bounding box of the nodes Bounding_box bbox = node.bbox(); @@ -183,18 +183,18 @@ namespace CGAL { // Check whether investigating the bbox can still lower the Hausdorff // distance. If so, enter the box. if ( dist <= h_local_lower) { - return true; + return std::make_pair(true, -dist); } else { - return false; + return std::make_pair(false, 0); } } - std::pair do_intersect_with_priority(const Query& query, const Node& node) const + bool do_intersect(const Query& /*query*/, const Node& /* node */) const { - bool b = do_intersect(query, node); - return std::make_pair(b, Priority(0)); + CGAL_assertion(false); + return false; } - + // Return the local Hausdorff bounds computed for the passed query triangle Hausdorff_bounds get_local_bounds() { @@ -243,7 +243,7 @@ namespace CGAL { Heap_type; public: - typedef int Priority; + typedef double Priority; Hausdorff_primitive_traits_tm1( const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2, @@ -308,7 +308,7 @@ namespace CGAL { // Determine whether child nodes will still contribute to a larger // Hausdorff distance and thus have to be entered // TODO Document Query object, explain why I don't need it here. - bool do_intersect(const Query& /*query*/, const Node& node) const + std::pair do_intersect_with_priority(const Query& /*query*/, const Node& node) const { /* Have reached a node, determine whether or not to enter it */ // Get the bounding box of the nodes @@ -338,18 +338,18 @@ namespace CGAL { // If the distance is larger than the global lower bound, enter the node, i.e. return true. if (dist > h_lower) { - return true; + return std::make_pair(true, dist); } else { - return false; + return std::make_pair(false, 0); } } - std::pair do_intersect_with_priority(const Query& query, const Node& node) const + bool do_intersect(const Query& /*query*/, const Node& /* node */) const { - bool b = do_intersect(query, node); - return std::make_pair(b, Priority(0)); + CGAL_assertion(false); + return false; } - + // Return those triangles from TM1 which are candidates for including a // point realizing the Hausdorff distance Heap_type get_candidate_triangles() { From 89094af48d1c5b02c6c70667c144cc55ffca5d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 26 Sep 2019 17:59:54 +0200 Subject: [PATCH 044/349] use do_intersect correctly as it is still needed --- .../AABB_traversal_traits_with_Hausdorff_distance.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 0683688cf67..2cdc3ae9793 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -189,10 +189,9 @@ namespace CGAL { } } - bool do_intersect(const Query& /*query*/, const Node& /* node */) const + bool do_intersect(const Query& query, const Node& node ) const { - CGAL_assertion(false); - return false; + return this->do_intersect_with_priority(query, node).first; } // Return the local Hausdorff bounds computed for the passed query triangle @@ -286,7 +285,7 @@ namespace CGAL { std::numeric_limits::infinity(), std::numeric_limits::infinity() ); - m_tm2_tree.traversal(candidate_triangle, traversal_traits_tm2); + m_tm2_tree.traversal_with_priority(candidate_triangle, traversal_traits_tm2); // Update global Hausdorff bounds according to the obtained local bounds Hausdorff_bounds local_bounds = traversal_traits_tm2.get_local_bounds(); @@ -344,10 +343,9 @@ namespace CGAL { } } - bool do_intersect(const Query& /*query*/, const Node& /* node */) const + bool do_intersect(const Query& query, const Node& node ) const { - CGAL_assertion(false); - return false; + return this->do_intersect_with_priority(query, node).first; } // Return those triangles from TM1 which are candidates for including a From 6e73f92fd21c01a71944d2d503a58c72d4d6c197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 27 Sep 2019 07:15:17 +0200 Subject: [PATCH 045/349] fix nb of primitives --- AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h index 94eacd277d7..2bbac2230c6 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h @@ -248,9 +248,9 @@ AABB_node::traversal_with_priority(const Query& query, } else { - right_child().traversal_with_priority(query, traits, nb_primitives/2); + right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); if( traits.go_further() /* && traits.do_intersect(query, left_child()) */ ) // TODO shall we call again do_intersect? - left_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); + left_child().traversal_with_priority(query, traits, nb_primitives/2); } } } From 16e0a475f40b81200907de3cdcf253f36f84a093 Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Mon, 14 Oct 2019 00:28:08 +0200 Subject: [PATCH 046/349] Fix traversal order, add comment on benchmark results. --- AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h index 2bbac2230c6..87e74fb18f0 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h @@ -240,22 +240,29 @@ AABB_node::traversal_with_priority(const Query& query, { if (iright) { + // Both children have to be inspected if(pleft >= pright) { + // Inspect left first, has higher priority left_child().traversal_with_priority(query, traits, nb_primitives/2); - if( traits.go_further() /* && traits.do_intersect(query, right_child()) */ ) // TODO shall we call again do_intersect? + if( traits.go_further() ) //&& traits.do_intersect(query, right_child()) ) // TODO shall we call again do_intersect? (Benchmarks show it slows down the Hausdorff Distance) right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); } else { + // Inspect right first, has higher priority right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); - if( traits.go_further() /* && traits.do_intersect(query, left_child()) */ ) // TODO shall we call again do_intersect? + if( traits.go_further() ) //&& traits.do_intersect(query, left_child()) ) // TODO shall we call again do_intersect? (Benchmarks show it slows down the Hausdorff Distance) left_child().traversal_with_priority(query, traits, nb_primitives/2); } } + else + // Only the left child has to be inspected + left_child().traversal_with_priority(query, traits, nb_primitives/2); } else if (iright) + // Only the right child has to be inspected right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); } } From fed345c07a479f3887bcb2ef1b13bff69b62701e Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Mon, 14 Oct 2019 00:32:55 +0200 Subject: [PATCH 047/349] Add notes from skype meeting. --- .../include/CGAL/Polygon_mesh_processing/distance.h | 5 +++++ .../internal/AABB_traversal_traits_with_Hausdorff_distance.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index f9307b1e8c4..1e2d7ce0b0f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -882,7 +883,11 @@ double bounded_error_Hausdorff_impl( // Build traversal traits for tm1_tree Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, hint.first ); + // Find candidate triangles in TM1 which might realise the Hausdorff bound +// TODO Initialize the distances on all the vertices first and store those. +// TODO Do not traverse TM1, but only TM2, i.e. reduce to Culling on TM2 (Can do this for all triangles in TM1 in parallel) + tm1_tree.traversal_with_priority( Point_3(0,0,0), traversal_traits_tm1 ); // dummy point given as query as not needed // TODO Is there a better/faster data structure than the Heap used here? diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 2cdc3ae9793..9e03cb17942 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -91,6 +91,7 @@ namespace CGAL { void intersection(const Query& query, const Primitive& primitive) { /* Have reached a single triangle, process it */ + // TODO Already perform these computations once we have <=k /* / Determine the distance accroding to @@ -285,6 +286,7 @@ namespace CGAL { std::numeric_limits::infinity(), std::numeric_limits::infinity() ); + // TODO Pass on the current global bounds to the TM2 tree traversal. There, only enter subtrees that can still be better than the current global bound. m_tm2_tree.traversal_with_priority(candidate_triangle, traversal_traits_tm2); // Update global Hausdorff bounds according to the obtained local bounds From 2d4c2543627c276e98e278af5a636b3e313c1d7d Mon Sep 17 00:00:00 2001 From: Martin Skrodzki Date: Mon, 14 Oct 2019 00:51:40 +0200 Subject: [PATCH 048/349] Keep current global bounds in mind when traversing tm2. --- .../AABB_traversal_traits_with_Hausdorff_distance.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 9e03cb17942..a1d7e6ab1a2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -71,11 +71,13 @@ namespace CGAL { const AABBTraits& traits, const TriangleMesh& tm2, const VPM2& vpm2, + const double h_upper_current_global, const double h_lower_init, const double h_upper_init, const double h_v0_lower_init, const double h_v1_lower_init, const double h_v2_lower_init ) : m_traits(traits), m_tm2(tm2), m_vpm2(vpm2) { // Initialize the global and local bounds with the given values + h_upper_global = h_upper_current_global; h_local_lower = h_lower_init; h_local_upper = h_upper_init; h_v0_lower = h_v0_lower_init; @@ -182,8 +184,8 @@ namespace CGAL { double dist = approximate_sqrt( Vector_3(dist_x,dist_y,dist_z).squared_length() ); // Check whether investigating the bbox can still lower the Hausdorff - // distance. If so, enter the box. - if ( dist <= h_local_lower) { + // distance and improve the current global bound. If so, enter the box. + if ( dist <= std::min(h_local_lower, h_upper_global) ) { return std::make_pair(true, -dist); } else { return std::make_pair(false, 0); @@ -207,6 +209,8 @@ namespace CGAL { const TriangleMesh& m_tm2; // its vertex point map const VPM2& m_vpm2; + // Current global upper bound on the Hausdorff distance + double h_upper_global; // Local Hausdorff bounds for the query triangle double h_local_upper; double h_local_lower; @@ -280,13 +284,13 @@ namespace CGAL { Tree_traits, Triangle_3, Kernel, TriangleMesh, VPM2 > traversal_traits_tm2( m_tm2_tree.traits(), m_tm2, m_vpm2, + (h_upper == 0.) ? std::numeric_limits::infinity() : h_upper, // Only pass current global bounds if they have been established yet std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity() ); - // TODO Pass on the current global bounds to the TM2 tree traversal. There, only enter subtrees that can still be better than the current global bound. m_tm2_tree.traversal_with_priority(candidate_triangle, traversal_traits_tm2); // Update global Hausdorff bounds according to the obtained local bounds From 511103e14cde5d25192a73b208ca1eb2265ee923 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 11 Nov 2020 16:20:43 +0100 Subject: [PATCH 049/349] Use a constructor for RefCounted --- STL_Extension/include/CGAL/Handle_for.h | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/STL_Extension/include/CGAL/Handle_for.h b/STL_Extension/include/CGAL/Handle_for.h index 537096b6e73..c2a615290df 100644 --- a/STL_Extension/include/CGAL/Handle_for.h +++ b/STL_Extension/include/CGAL/Handle_for.h @@ -40,6 +40,8 @@ class Handle_for struct RefCounted { T t; unsigned int count; + template + RefCounted(U&&...u ) : t(std::forward(u)...), count(1) {} }; @@ -60,24 +62,21 @@ public: Handle_for() { pointer p = allocator.allocate(1); - new (&(p->t)) element_type(); // we get the warning here - p->count = 1; + new (p) RefCounted(); ptr_ = p; } Handle_for(const element_type& t) { pointer p = allocator.allocate(1); - new (&(p->t)) element_type(t); - p->count = 1; + new (p) RefCounted(t); ptr_ = p; } Handle_for(element_type && t) { pointer p = allocator.allocate(1); - new (&(p->t)) element_type(std::move(t)); - p->count = 1; + new (p) RefCounted(std::move(t)); ptr_ = p; } @@ -87,8 +86,7 @@ public: Handle_for(const T1& t1) { pointer p = allocator.allocate(1); - new (&(p->t)) T(t1); - p->count = 1; + new (p) RefCounted(t1); ptr_ = p; } */ @@ -97,8 +95,7 @@ public: Handle_for(T1 && t1, T2 && t2, Args && ... args) { pointer p = allocator.allocate(1); - new (&(p->t)) element_type(std::forward(t1), std::forward(t2), std::forward(args)...); - p->count = 1; + new (&(p->t)) RefCounted(std::forward(t1), std::forward(t2), std::forward(args)...); ptr_ = p; } From 695fe3739409a5dc9814a96936b8004f38de6694 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 11 Nov 2020 16:43:10 +0100 Subject: [PATCH 050/349] Constructor for Rep --- STL_Extension/include/CGAL/Handle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STL_Extension/include/CGAL/Handle.h b/STL_Extension/include/CGAL/Handle.h index 0d652ccb4cb..f07fe24e7a5 100644 --- a/STL_Extension/include/CGAL/Handle.h +++ b/STL_Extension/include/CGAL/Handle.h @@ -27,7 +27,7 @@ class Rep { friend class Handle; protected: - Rep() { count = 1; } + Rep() : count(1) { } virtual ~Rep() {} int count; From 3edf7a836dcfb7bee6765df445ce055fdfc4ea88 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 11 Nov 2020 16:43:28 +0100 Subject: [PATCH 051/349] atomic count in Handle_for --- STL_Extension/include/CGAL/Handle_for.h | 28 ++++++++++++------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/STL_Extension/include/CGAL/Handle_for.h b/STL_Extension/include/CGAL/Handle_for.h index c2a615290df..ba3d339caf6 100644 --- a/STL_Extension/include/CGAL/Handle_for.h +++ b/STL_Extension/include/CGAL/Handle_for.h @@ -26,6 +26,7 @@ #include #include #include +#include #if defined(BOOST_MSVC) # pragma warning(push) @@ -39,7 +40,7 @@ class Handle_for // Wrapper that adds the reference counter. struct RefCounted { T t; - unsigned int count; + std::atomic_uint count; template RefCounted(U&&...u ) : t(std::forward(u)...), count(1) {} }; @@ -62,22 +63,19 @@ public: Handle_for() { pointer p = allocator.allocate(1); - new (p) RefCounted(); - ptr_ = p; + ptr_ = new (p) RefCounted(); } Handle_for(const element_type& t) { pointer p = allocator.allocate(1); - new (p) RefCounted(t); - ptr_ = p; + ptr_ = new (p) RefCounted(t); } Handle_for(element_type && t) { pointer p = allocator.allocate(1); - new (p) RefCounted(std::move(t)); - ptr_ = p; + ptr_ = new (p) RefCounted(std::move(t)); } /* I comment this one for now, since it's preventing the automatic conversions @@ -86,8 +84,7 @@ public: Handle_for(const T1& t1) { pointer p = allocator.allocate(1); - new (p) RefCounted(t1); - ptr_ = p; + ptr_ = new (p) RefCounted(t1); } */ @@ -95,15 +92,14 @@ public: Handle_for(T1 && t1, T2 && t2, Args && ... args) { pointer p = allocator.allocate(1); - new (&(p->t)) RefCounted(std::forward(t1), std::forward(t2), std::forward(args)...); - ptr_ = p; + ptr_ = new (&(p->t)) RefCounted(std::forward(t1), std::forward(t2), std::forward(args)...); } Handle_for(const Handle_for& h) noexcept : ptr_(h.ptr_) { - CGAL_assume (ptr_->count > 0); - ++(ptr_->count); + // CGAL_assume (ptr_->count > 0); + ptr_->count.fetch_add(1, std::memory_order_relaxed); } Handle_for& @@ -148,9 +144,11 @@ public: ~Handle_for() { - if (--(ptr_->count) == 0) { + if (ptr_->count.load(std::memory_order_relaxed) == 1 + || ptr_->count.fetch_sub(1, std::memory_order_release) == 1) { + std::atomic_thread_fence(std::memory_order_acquire); Allocator_traits::destroy(allocator, ptr_); - allocator.deallocate( ptr_, 1); + allocator.deallocate(ptr_, 1); } } From 29c9fd3f0299333002c1e08a92627c04163c860c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 11 Nov 2020 16:54:08 +0100 Subject: [PATCH 052/349] Refactor ++ and -- in Handle --- STL_Extension/include/CGAL/Handle.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/STL_Extension/include/CGAL/Handle.h b/STL_Extension/include/CGAL/Handle.h index f07fe24e7a5..1c62cf75d76 100644 --- a/STL_Extension/include/CGAL/Handle.h +++ b/STL_Extension/include/CGAL/Handle.h @@ -48,22 +48,17 @@ class Handle CGAL_precondition( x.PTR != static_cast(0) ); PTR = x.PTR; CGAL_assume (PTR->count > 0); - PTR->count++; + incref(); } - ~Handle() - { - if ( PTR && (--PTR->count == 0)) - delete PTR; - } + ~Handle() { reset(); } Handle& operator=(const Handle& x) noexcept { CGAL_precondition( x.PTR != static_cast(0) ); - x.PTR->count++; - if ( PTR && (--PTR->count == 0)) - delete PTR; + x.incref(); + reset(); PTR = x.PTR; return *this; } @@ -80,6 +75,11 @@ class Handle } } + void incref() const noexcept + { + PTR->count++; + } + int refs() const noexcept { return PTR->count; } From 0bd0e7e47dfc69ede9b1e77c691028a0fc8a097c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 11 Nov 2020 18:33:37 +0100 Subject: [PATCH 053/349] atomic count in Handle --- STL_Extension/include/CGAL/Handle.h | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/STL_Extension/include/CGAL/Handle.h b/STL_Extension/include/CGAL/Handle.h index 1c62cf75d76..60cd005969b 100644 --- a/STL_Extension/include/CGAL/Handle.h +++ b/STL_Extension/include/CGAL/Handle.h @@ -18,6 +18,7 @@ #define CGAL_HANDLE_H #include +#include #include #include @@ -30,7 +31,7 @@ class Rep Rep() : count(1) { } virtual ~Rep() {} - int count; + std::atomic_int count; }; class Handle @@ -47,10 +48,12 @@ class Handle { CGAL_precondition( x.PTR != static_cast(0) ); PTR = x.PTR; - CGAL_assume (PTR->count > 0); + //CGAL_assume (PTR->count > 0); incref(); } + Handle(Handle&& x) noexcept : PTR(x.PTR) { x.PTR = 0; } + ~Handle() { reset(); } Handle& @@ -63,21 +66,33 @@ class Handle return *this; } + Handle& + operator=(Handle&& x) noexcept + { + swap(*this, x); + return *this; + } + friend void swap(Handle& a, Handle& b) noexcept { std::swap(a.PTR, b.PTR); } void reset() { if (PTR) { - if (--PTR->count==0) + // TODO: the first condition tries to avoid the expensive + // release synchronization, check that it is still safe. + if (PTR->count.load(std::memory_order_relaxed) == 1 + || PTR->count.fetch_sub(1, std::memory_order_release) == 1) { + std::atomic_thread_fence(std::memory_order_acquire); delete PTR; + } PTR=0; } } void incref() const noexcept { - PTR->count++; + PTR->count.fetch_add(1, std::memory_order_relaxed); } int From c4f3946a4fe7fa4e07766082950e1d4ea8a13edb Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 11 Nov 2020 19:45:57 +0100 Subject: [PATCH 054/349] Use reset() to clear subtrees That's cheaper than the current t=T() which includes several atomic ops For the cases I changed, it was clear that T was Lazy_*. In Lazy.h, there are other cases where one would need to check what the valid types are, and maybe create a reset utility which does t=T() by default and is overloaded for types that derive from Handle. --- Number_types/include/CGAL/Lazy_exact_nt.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index 1a511325de9..a2f015d036f 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -184,7 +184,7 @@ public: prune_dag(); } - void prune_dag() const { l = Lazy_exact_nt(); } + void prune_dag() const { l.reset(); } }; @@ -203,7 +203,7 @@ struct Lazy_exact_unary : public Lazy_exact_nt_rep this->set_depth(op1.depth() + 1); } - void prune_dag() const { op1 = Lazy_exact_nt(); } + void prune_dag() const { op1.reset(); } #ifdef CGAL_LAZY_KERNEL_DEBUG void @@ -234,8 +234,8 @@ struct Lazy_exact_binary : public Lazy_exact_nt_rep void prune_dag() const { - op1 = Lazy_exact_nt(); - op2 = Lazy_exact_nt(); + op1.reset(); + op2.reset(); } #ifdef CGAL_LAZY_KERNEL_DEBUG From c862e7b90344fd2d649658a746d46c8ad02aac1e Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 11 Nov 2020 21:18:10 +0100 Subject: [PATCH 055/349] atomic update_exact --- Filtered_kernel/include/CGAL/Lazy.h | 101 +++++++++++++++------- Number_types/include/CGAL/Lazy_exact_nt.h | 90 ++++++++++++++----- 2 files changed, 135 insertions(+), 56 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 4969dc77eab..1cbaa7de979 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -52,6 +52,7 @@ #include #include #include +#include namespace CGAL { @@ -242,7 +243,7 @@ public: typedef AT_ AT; mutable AT at; - mutable ET *et; + mutable std::atomic et; Lazy_rep () : at(), et(nullptr){} @@ -267,14 +268,14 @@ public: const ET & exact() const { - if (et==nullptr) + if (et.load(std::memory_order_relaxed)==nullptr) update_exact(); return *et; } ET & exact() { - if (et==nullptr) + if (et.load(std::memory_order_relaxed)==nullptr) update_exact(); return *et; } @@ -324,9 +325,16 @@ class Lazy_rep_n : const EC& ec() const { return *this; } template void update_exact_helper(std::index_sequence) const { - this->et = new ET(ec()( CGAL::exact( std::get(l) ) ... ) ); - this->at = E2A()(*(this->et)); - l = std::tuple{}; + ET* other = nullptr; + ET* pet = new ET(ec()( CGAL::exact( std::get(l) ) ... ) ); + // TODO: find the right memory_orders for this + bool updated = this->et.compare_exchange_strong(other, pet); + if (!updated) { // some other thread was faster + pet->~ET(); + } else { + this->at = E2A()(*pet); + l = std::tuple{}; + } } public: void update_exact() const { @@ -372,7 +380,12 @@ public: void update_exact() const { - this->et = new ET(); + ET* other = nullptr; + ET* pet = new ET(); + bool updated = this->et.compare_exchange_strong(other, pet); + if (!updated) { + pet->~ET(); + } } Lazy_rep_0() @@ -483,16 +496,20 @@ public: void update_exact() const { + ET* other = nullptr; + ET* pet = new ET(); // TODO : This looks really unfinished... std::vector vec; - this->et = new ET(); //this->et->reserve(this->at.size()); - ec()(CGAL::exact(l1_), std::back_inserter(*(this->et))); - if(this->et==nullptr) - E2A()(*(this->et)); - this->at = E2A()(*(this->et)); - // Prune lazy tree - l1_ = L1(); + ec()(CGAL::exact(l1_), std::back_inserter(pet)); + bool updated = this->et.compare_exchange_strong(other, pet); + if (!updated) { + pet->~ET(); + } else { + this->at = E2A()(*pet); + // Prune lazy tree + l1_ = L1(); + } } Lazy_rep_with_vector_1(const AC& ac, const EC& /*ec*/, const L1& l1) @@ -536,13 +553,19 @@ public: void update_exact() const { - this->et = new ET(); - this->et->reserve(this->at.size()); - ec()(CGAL::exact(l1_), CGAL::exact(l2_), std::back_inserter(*(this->et))); - this->at = E2A()(*(this->et)); - // Prune lazy tree - l1_ = L1(); - l2_ = L2(); + ET* other = nullptr; + ET* pet = new ET(); + pet->reserve(this->at.size()); + ec()(CGAL::exact(l1_), CGAL::exact(l2_), std::back_inserter(pet)); + bool updated = this->et.compare_exchange_strong(other, pet); + if (!updated) { + pet->~ET(); + } else { + this->at = E2A()(*pet); + // Prune lazy tree + l1_ = L1(); + l2_ = L2(); + } } Lazy_rep_with_vector_2(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) @@ -586,12 +609,18 @@ public: void update_exact() const { - this->et = new ET(); - ec()(CGAL::exact(l1_), CGAL::exact(l2_), *(this->et)); - this->at = E2A()(*(this->et)); - // Prune lazy tree - l1_ = L1(); - l2_ = L2(); + ET* other = nullptr; + ET* pet = new ET(); + ec()(CGAL::exact(l1_), CGAL::exact(l2_), pet); + bool updated = this->et.compare_exchange_strong(other, pet); + if (!updated) { + pet->~ET(); + } else { + this->at = E2A()(*pet); + // Prune lazy tree + l1_ = L1(); + l2_ = L2(); + } } Lazy_rep_2_1(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) @@ -638,12 +667,18 @@ public: void update_exact() const { - this->et = new ET(); - ec()(CGAL::exact(l1_), CGAL::exact(l2_), this->et->first, this->et->second ); - this->at = E2A()(*(this->et)); - // Prune lazy tree - l1_ = L1(); - l2_ = L2(); + ET* other = nullptr; + ET* pet = new ET(); + ec()(CGAL::exact(l1_), CGAL::exact(l2_), pet->first, pet->second ); + bool updated = this->et.compare_exchange_strong(other, pet); + if (!updated) { + pet->~ET(); + } else { + this->at = E2A()(*pet); + // Prune lazy tree + l1_ = L1(); + l2_ = L2(); + } } Lazy_rep_2_2(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index a2f015d036f..c578543da71 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -129,7 +129,14 @@ struct Lazy_exact_Int_Cst : public Lazy_exact_nt_rep Lazy_exact_Int_Cst (int i) : Lazy_exact_nt_rep(double(i)) {} - void update_exact() const { this->et = new ET((int)this->approx().inf()); } + void update_exact() const { + ET* other = nullptr; + ET* pet = new ET((int)this->approx().inf()); + bool updated = this->et.compare_exchange_strong(other, pet); + if (!updated) { + pet->~ET(); + } + } }; // double constant @@ -139,7 +146,14 @@ struct Lazy_exact_Cst : public Lazy_exact_nt_rep Lazy_exact_Cst (X x) : Lazy_exact_nt_rep(x), cste(x) {} - void update_exact() const { this->et = new ET(cste); } + void update_exact() const { + ET* other = nullptr; + ET* pet = new ET(cste); + bool updated = this->et.compare_exchange_strong(other, pet); + if (!updated) { + pet->~ET(); + } + } private: X cste; @@ -179,9 +193,15 @@ public: void update_exact() const { - this->et = new ET(l.exact()); - this->at = l.approx(); - prune_dag(); + ET* other = nullptr; + ET* pet = new ET(l.exact()); + bool updated = this->et.compare_exchange_strong(other, pet); + if (!updated) { + pet->~ET(); + } else { + this->at = l.approx(); + prune_dag(); + } } void prune_dag() const { l.reset(); } @@ -267,11 +287,17 @@ struct NAME : public Lazy_exact_unary \ \ void update_exact() const \ { \ - this->et = new ET(OP(this->op1.exact())); \ - if (!this->approx().is_point()) \ - this->at = CGAL_NTS to_interval(*(this->et)); \ - this->prune_dag(); \ - } \ + ET* other = nullptr; \ + ET* pet = new ET(OP(this->op1.exact())); \ + bool updated = this->et.compare_exchange_strong(other, pet); \ + if (!updated) { \ + pet->~ET(); \ + } else { \ + if (!this->approx().is_point()) \ + this->at = CGAL_NTS to_interval(*(this->et)); \ + this->prune_dag(); \ + } \ + } \ }; CGAL_LAZY_UNARY_OP(opposite, Lazy_exact_Opp) @@ -290,11 +316,17 @@ struct NAME : public Lazy_exact_binary \ \ void update_exact() const \ { \ - this->et = new ET(this->op1.exact() OP this->op2.exact()); \ - if (!this->approx().is_point()) \ - this->at = CGAL_NTS to_interval(*(this->et)); \ - this->prune_dag(); \ - } \ + ET* other = nullptr; \ + ET* pet = new ET(this->op1.exact() OP this->op2.exact()); \ + bool updated = this->et.compare_exchange_strong(other, pet); \ + if (!updated) { \ + pet->~ET(); \ + } else { \ + if (!this->approx().is_point()) \ + this->at = CGAL_NTS to_interval(*(this->et)); \ + this->prune_dag(); \ + } \ + } \ }; CGAL_LAZY_BINARY_OP(+, Lazy_exact_Add) @@ -311,10 +343,16 @@ struct Lazy_exact_Min : public Lazy_exact_binary void update_exact() const { - this->et = new ET((CGAL::min)(this->op1.exact(), this->op2.exact())); - if (!this->approx().is_point()) - this->at = CGAL_NTS to_interval(*(this->et)); - this->prune_dag(); + ET* other = nullptr; + ET* pet = new ET((CGAL::min)(this->op1.exact(), this->op2.exact())); + bool updated = this->et.compare_exchange_strong(other, pet); + if (!updated) { + pet->~ET(); + } else { + if (!this->approx().is_point()) + this->at = CGAL_NTS to_interval(*(this->et)); + this->prune_dag(); + } } }; @@ -327,10 +365,16 @@ struct Lazy_exact_Max : public Lazy_exact_binary void update_exact() const { - this->et = new ET((CGAL::max)(this->op1.exact(), this->op2.exact())); - if (!this->approx().is_point()) - this->at = CGAL_NTS to_interval(*(this->et)); - this->prune_dag(); + ET* other = nullptr; + ET* pet = new ET((CGAL::max)(this->op1.exact(), this->op2.exact())); + bool updated = this->et.compare_exchange_strong(other, pet); + if (!updated) { + pet->~ET(); + } else { + if (!this->approx().is_point()) + this->at = CGAL_NTS to_interval(*(this->et)); + this->prune_dag(); + } } }; From 7151181f8c8aa4f72013419dbb6805e4507178d4 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 11 Nov 2020 23:19:22 +0100 Subject: [PATCH 056/349] Indirection for the approximate value in Lazy --- Filtered_kernel/include/CGAL/Lazy.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 1cbaa7de979..8f0087e161f 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -56,6 +56,21 @@ namespace CGAL { +// It would be nice to provide a specialization for Interval_nt, but I believe that would require making approx() return by value for this AT. +// The approximate value is set once at construction, and possibly updated once during update_exact(). +template +struct Indirect_AT { + std::atomic p; // no atomic ?? + std::unique_ptr old; + Indirect_AT():p(new AT()){} + Indirect_AT(AT const& a):p(new AT(a)){} + Indirect_AT(AT&& a):p(new AT(std::move(a))){} + Indirect_AT& operator=(AT const& a){ old.reset(p.load(std::memory_order_relaxed)); p.store(new AT(a), std::memory_order_relaxed); return *this; } + Indirect_AT& operator=(AT&& a){ old.reset(p.load(std::memory_order_relaxed)); p.store(new AT(std::move(a)), std::memory_order_relaxed); return *this; } + operator AT const&()const{return *p.load(std::memory_order_relaxed);} + ~Indirect_AT() { delete p.load(std::memory_order_relaxed); } +}; + template & l) return l.approx(); } +#if 0 // Where is this one (non-const) needed ? Is it ? template inline @@ -83,6 +99,7 @@ approx(Lazy& l) { return l.approx(); } +#endif template @@ -242,7 +259,7 @@ public: typedef AT_ AT; - mutable AT at; + mutable Indirect_AT at; mutable std::atomic et; Lazy_rep () @@ -261,7 +278,7 @@ public: return at; } - AT& approx() + Indirect_AT& approx() { return at; } @@ -781,8 +798,10 @@ public : const ET& exact() const { return ptr()->exact(); } +#if 0 AT& approx() { return ptr()->approx(); } +#endif ET& exact() { return ptr()->exact(); } From ba054d51c266b04b0227ad8322bf26c71c9d9ad5 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 12 Nov 2020 19:29:06 +0100 Subject: [PATCH 057/349] set_exact minor refactor --- Filtered_kernel/include/CGAL/Lazy.h | 31 ++++++++++++----------- Number_types/include/CGAL/Lazy_exact_nt.h | 23 ++++++----------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 8f0087e161f..e19b19ee9cd 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -287,14 +287,22 @@ public: { if (et.load(std::memory_order_relaxed)==nullptr) update_exact(); - return *et; + return *et.load(std::memory_order_consume); + // Should we return the pointer from update_exact, to avoid an extra load and synchronization? } + // ??? Is this needed? Safe? ET & exact() { if (et.load(std::memory_order_relaxed)==nullptr) update_exact(); - return *et; + return *et.load(std::memory_order_consume); + } + + bool set_exact(ET* pet) const + { + ET* other = nullptr; + return this->et.compare_exchange_strong(other, pet, std::memory_order_release); } #ifdef CGAL_LAZY_KERNEL_DEBUG @@ -342,10 +350,8 @@ class Lazy_rep_n : const EC& ec() const { return *this; } template void update_exact_helper(std::index_sequence) const { - ET* other = nullptr; ET* pet = new ET(ec()( CGAL::exact( std::get(l) ) ... ) ); - // TODO: find the right memory_orders for this - bool updated = this->et.compare_exchange_strong(other, pet); + bool updated = this->set_exact(pet); if (!updated) { // some other thread was faster pet->~ET(); } else { @@ -397,9 +403,8 @@ public: void update_exact() const { - ET* other = nullptr; ET* pet = new ET(); - bool updated = this->et.compare_exchange_strong(other, pet); + bool updated = this->set_exact(pet); if (!updated) { pet->~ET(); } @@ -513,13 +518,12 @@ public: void update_exact() const { - ET* other = nullptr; ET* pet = new ET(); // TODO : This looks really unfinished... std::vector vec; //this->et->reserve(this->at.size()); ec()(CGAL::exact(l1_), std::back_inserter(pet)); - bool updated = this->et.compare_exchange_strong(other, pet); + bool updated = this->set_exact(pet); if (!updated) { pet->~ET(); } else { @@ -570,11 +574,10 @@ public: void update_exact() const { - ET* other = nullptr; ET* pet = new ET(); pet->reserve(this->at.size()); ec()(CGAL::exact(l1_), CGAL::exact(l2_), std::back_inserter(pet)); - bool updated = this->et.compare_exchange_strong(other, pet); + bool updated = this->set_exact(pet); if (!updated) { pet->~ET(); } else { @@ -626,10 +629,9 @@ public: void update_exact() const { - ET* other = nullptr; ET* pet = new ET(); ec()(CGAL::exact(l1_), CGAL::exact(l2_), pet); - bool updated = this->et.compare_exchange_strong(other, pet); + bool updated = this->set_exact(pet); if (!updated) { pet->~ET(); } else { @@ -684,10 +686,9 @@ public: void update_exact() const { - ET* other = nullptr; ET* pet = new ET(); ec()(CGAL::exact(l1_), CGAL::exact(l2_), pet->first, pet->second ); - bool updated = this->et.compare_exchange_strong(other, pet); + bool updated = this->set_exact(pet); if (!updated) { pet->~ET(); } else { diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index c578543da71..c505e839eb7 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -130,9 +130,8 @@ struct Lazy_exact_Int_Cst : public Lazy_exact_nt_rep : Lazy_exact_nt_rep(double(i)) {} void update_exact() const { - ET* other = nullptr; ET* pet = new ET((int)this->approx().inf()); - bool updated = this->et.compare_exchange_strong(other, pet); + bool updated = this->set_exact(pet); if (!updated) { pet->~ET(); } @@ -147,9 +146,8 @@ struct Lazy_exact_Cst : public Lazy_exact_nt_rep : Lazy_exact_nt_rep(x), cste(x) {} void update_exact() const { - ET* other = nullptr; ET* pet = new ET(cste); - bool updated = this->et.compare_exchange_strong(other, pet); + bool updated = this->set_exact(pet); if (!updated) { pet->~ET(); } @@ -193,9 +191,8 @@ public: void update_exact() const { - ET* other = nullptr; ET* pet = new ET(l.exact()); - bool updated = this->et.compare_exchange_strong(other, pet); + bool updated = this->set_exact(pet); if (!updated) { pet->~ET(); } else { @@ -287,9 +284,8 @@ struct NAME : public Lazy_exact_unary \ \ void update_exact() const \ { \ - ET* other = nullptr; \ ET* pet = new ET(OP(this->op1.exact())); \ - bool updated = this->et.compare_exchange_strong(other, pet); \ + bool updated = this->set_exact(pet); \ if (!updated) { \ pet->~ET(); \ } else { \ @@ -316,9 +312,8 @@ struct NAME : public Lazy_exact_binary \ \ void update_exact() const \ { \ - ET* other = nullptr; \ ET* pet = new ET(this->op1.exact() OP this->op2.exact()); \ - bool updated = this->et.compare_exchange_strong(other, pet); \ + bool updated = this->set_exact(pet); \ if (!updated) { \ pet->~ET(); \ } else { \ @@ -343,9 +338,8 @@ struct Lazy_exact_Min : public Lazy_exact_binary void update_exact() const { - ET* other = nullptr; ET* pet = new ET((CGAL::min)(this->op1.exact(), this->op2.exact())); - bool updated = this->et.compare_exchange_strong(other, pet); + bool updated = this->set_exact(pet); if (!updated) { pet->~ET(); } else { @@ -365,9 +359,8 @@ struct Lazy_exact_Max : public Lazy_exact_binary void update_exact() const { - ET* other = nullptr; ET* pet = new ET((CGAL::max)(this->op1.exact(), this->op2.exact())); - bool updated = this->et.compare_exchange_strong(other, pet); + bool updated = this->set_exact(pet); if (!updated) { pet->~ET(); } else { @@ -1341,7 +1334,7 @@ operator>> (std::istream & is, Lazy_exact_nt & a) ET e; internal::read_float_or_quotient(is, e); if (is) - a = e; + a = std::move(e); return is; } From bf0a42d7407acb35e053df4544cc56ddc44110ed Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 13 Nov 2020 01:03:57 +0100 Subject: [PATCH 058/349] lock-like protection for update_exact The exact choice of memory_order_* is hard, and even for versions that seem to work on x86_64 TSAN complains like crazy. TODO: a version that, instead of blocking if another thread is updating, also does the computation, with suitable protection to ensure that pruning the tree cannot happen while anyone is computing on it. TODO: try having AT in Lazy instead of Lazy_rep (i.e. not shared) to avoid the indirection. We can possibly choose one or the other depending on the type. --- Filtered_kernel/include/CGAL/Lazy.h | 216 ++++++++++++++-------- Number_types/include/CGAL/Lazy_exact_nt.h | 68 +++---- STL_Extension/include/CGAL/Handle.h | 7 +- 3 files changed, 174 insertions(+), 117 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index e19b19ee9cd..6e14b66831c 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -53,6 +53,7 @@ #include #include #include +#include namespace CGAL { @@ -65,10 +66,10 @@ struct Indirect_AT { Indirect_AT():p(new AT()){} Indirect_AT(AT const& a):p(new AT(a)){} Indirect_AT(AT&& a):p(new AT(std::move(a))){} - Indirect_AT& operator=(AT const& a){ old.reset(p.load(std::memory_order_relaxed)); p.store(new AT(a), std::memory_order_relaxed); return *this; } - Indirect_AT& operator=(AT&& a){ old.reset(p.load(std::memory_order_relaxed)); p.store(new AT(std::move(a)), std::memory_order_relaxed); return *this; } - operator AT const&()const{return *p.load(std::memory_order_relaxed);} - ~Indirect_AT() { delete p.load(std::memory_order_relaxed); } + Indirect_AT& operator=(AT const& a){ old.reset(p.load(std::memory_order_relaxed)); p.store(new AT(a), std::memory_order_release); return *this; } + Indirect_AT& operator=(AT&& a){ old.reset(p.load(std::memory_order_relaxed)); p.store(new AT(std::move(a)), std::memory_order_release); return *this; } + operator AT const&()const{return *p.load(std::memory_order_acquire);} + ~Indirect_AT() { delete p.load(std::memory_order_acquire); } }; template & l) return l.approx(); } -#if 0 -// Where is this one (non-const) needed ? Is it ? -template -inline -AT& -approx(Lazy& l) -{ - return l.approx(); -} -#endif - - template inline const ET& @@ -259,8 +248,8 @@ public: typedef AT_ AT; - mutable Indirect_AT at; - mutable std::atomic et; + mutable Indirect_AT at{}; + mutable std::atomic et { nullptr }; Lazy_rep () : at(), et(nullptr){} @@ -283,6 +272,69 @@ public: return at; } +#if 1 +#define CGAL_UPDATE_EXACT_BEGIN \ + if (!this->start_update()) return; +#define CGAL_UPDATE_EXACT_MIDDLE \ + this->et.store(pet, std::memory_order_release); +#define CGAL_UPDATE_EXACT_END + + // true if you should update + bool start_update() const + { + ET* other = nullptr; + // TODO specify memory_order_* + bool doit = et.compare_exchange_strong(other, (ET*)1); + if (!doit) { + // Wait until it becomes available + while ((uintptr_t)other == 1) { + std::this_thread::yield(); // or do nothing? + other = et.load(std::memory_order_relaxed); + } + return false; + } + return true; + } + + const ET & exact() const + { + uintptr_t pet = (uintptr_t) et.load(std::memory_order_relaxed); + if (pet <= 1) { + if (pet == 0) + update_exact(); + else + // Wait until it becomes available + while((uintptr_t)et.load(std::memory_order_relaxed)==1) + std::this_thread::yield(); // or do nothing? + } + return *et.load(std::memory_order_consume); + // Should we return the pointer from update_exact, to avoid an extra load and synchronization? + } + +#elif 1 + mutable std::atomic worker{}; // thread that is allowed to updatee + +#define CGAL_UPDATE_EXACT_BEGIN \ + if (!this->start_update()) return; +#define CGAL_UPDATE_EXACT_MIDDLE \ + this->et.store(pet, std::memory_order_release); +#define CGAL_UPDATE_EXACT_END + + // true if you should update + bool start_update() const + { + std::thread::id none{}; + // TODO specify memory_order_* + bool doit = worker.compare_exchange_strong(none, std::this_thread::get_id()); + if (!doit) { + // Wait until it becomes available + while(et.load(std::memory_order_relaxed)==nullptr) + std::this_thread::yield(); // or do nothing? + return false; + } + return true; + } + const ET & exact() const { if (et.load(std::memory_order_relaxed)==nullptr) @@ -291,20 +343,53 @@ public: // Should we return the pointer from update_exact, to avoid an extra load and synchronization? } - // ??? Is this needed? Safe? - ET & exact() - { - if (et.load(std::memory_order_relaxed)==nullptr) - update_exact(); - return *et.load(std::memory_order_consume); +#else + mutable std::atomic_uint workers{}; // number of threads running update_exact + // not written yet +#define CGAL_UPDATE_EXACT_BEGIN \ + workers.fetch_add(1, std::memory_order_relaxed); \ + if (et.load(std::memory_order_relaxed)!=nullptr) \ + if (!this->start_update()) return; +#define CGAL_UPDATE_EXACT_MIDDLE \ + bool updated = this->set_exact(pet); \ + if (!updated) { /* some other thread was faster */ \ + pet->~ET(); \ + } else if (this->end_update()) { +#define CGAL_UPDATE_EXACT_END \ } - bool set_exact(ET* pet) const { ET* other = nullptr; return this->et.compare_exchange_strong(other, pet, std::memory_order_release); } + // true if you should update + bool start_update() const + { + unsigned int w = workers.fetch_add(1, std::memory_order_relaxed); + ??? + } + + // true if you are the last one and can clean-up + bool end_update() const + { + bool b = workers.load(std::memory_order_relaxed) == 1 + || workers.fetch_sub(1, std::memory_order_release) == 1; + // unneeded for Lazy_rep_0? + if(b) std::atomic_thread_fence(std::memory_order_acquire); + return b; + } + + const ET & exact() const + { + if (et.load(std::memory_order_relaxed)==nullptr) + update_exact(); + return *et.load(std::memory_order_consume); + // Should we return the pointer from update_exact, to avoid an extra load and synchronization? + } + +#endif + #ifdef CGAL_LAZY_KERNEL_DEBUG void print_at_et(std::ostream& os, int level) const { @@ -350,14 +435,12 @@ class Lazy_rep_n : const EC& ec() const { return *this; } template void update_exact_helper(std::index_sequence) const { - ET* pet = new ET(ec()( CGAL::exact( std::get(l) ) ... ) ); - bool updated = this->set_exact(pet); - if (!updated) { // some other thread was faster - pet->~ET(); - } else { + CGAL_UPDATE_EXACT_BEGIN + ET* pet = new ET(ec()( CGAL::exact( std::get(l) ) ... ) ); + CGAL_UPDATE_EXACT_MIDDLE this->at = E2A()(*pet); l = std::tuple{}; - } + CGAL_UPDATE_EXACT_END } public: void update_exact() const { @@ -403,11 +486,10 @@ public: void update_exact() const { - ET* pet = new ET(); - bool updated = this->set_exact(pet); - if (!updated) { - pet->~ET(); - } + CGAL_UPDATE_EXACT_BEGIN + ET* pet = new ET(); + CGAL_UPDATE_EXACT_MIDDLE + CGAL_UPDATE_EXACT_END } Lazy_rep_0() @@ -518,19 +600,17 @@ public: void update_exact() const { - ET* pet = new ET(); + CGAL_UPDATE_EXACT_BEGIN + ET* pet = new ET(); // TODO : This looks really unfinished... - std::vector vec; - //this->et->reserve(this->at.size()); - ec()(CGAL::exact(l1_), std::back_inserter(pet)); - bool updated = this->set_exact(pet); - if (!updated) { - pet->~ET(); - } else { + std::vector vec; + //this->et->reserve(this->at.size()); + ec()(CGAL::exact(l1_), std::back_inserter(*pet)); + CGAL_UPDATE_EXACT_MIDDLE this->at = E2A()(*pet); // Prune lazy tree l1_ = L1(); - } + CGAL_UPDATE_EXACT_END } Lazy_rep_with_vector_1(const AC& ac, const EC& /*ec*/, const L1& l1) @@ -574,18 +654,16 @@ public: void update_exact() const { - ET* pet = new ET(); - pet->reserve(this->at.size()); - ec()(CGAL::exact(l1_), CGAL::exact(l2_), std::back_inserter(pet)); - bool updated = this->set_exact(pet); - if (!updated) { - pet->~ET(); - } else { + CGAL_UPDATE_EXACT_BEGIN + ET* pet = new ET(); + pet->reserve(this->at.size()); + ec()(CGAL::exact(l1_), CGAL::exact(l2_), std::back_inserter(*pet)); + CGAL_UPDATE_EXACT_MIDDLE this->at = E2A()(*pet); // Prune lazy tree l1_ = L1(); l2_ = L2(); - } + CGAL_UPDATE_EXACT_END } Lazy_rep_with_vector_2(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) @@ -629,17 +707,15 @@ public: void update_exact() const { - ET* pet = new ET(); - ec()(CGAL::exact(l1_), CGAL::exact(l2_), pet); - bool updated = this->set_exact(pet); - if (!updated) { - pet->~ET(); - } else { + CGAL_UPDATE_EXACT_BEGIN + ET* pet = new ET(); + ec()(CGAL::exact(l1_), CGAL::exact(l2_), *pet); + CGAL_UPDATE_EXACT_MIDDLE this->at = E2A()(*pet); // Prune lazy tree l1_ = L1(); l2_ = L2(); - } + CGAL_UPDATE_EXACT_END } Lazy_rep_2_1(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) @@ -686,17 +762,15 @@ public: void update_exact() const { - ET* pet = new ET(); - ec()(CGAL::exact(l1_), CGAL::exact(l2_), pet->first, pet->second ); - bool updated = this->set_exact(pet); - if (!updated) { - pet->~ET(); - } else { + CGAL_UPDATE_EXACT_BEGIN + ET* pet = new ET(); + ec()(CGAL::exact(l1_), CGAL::exact(l2_), pet->first, pet->second ); + CGAL_UPDATE_EXACT_MIDDLE this->at = E2A()(*pet); // Prune lazy tree l1_ = L1(); l2_ = L2(); - } + CGAL_UPDATE_EXACT_END } Lazy_rep_2_2(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) @@ -799,14 +873,6 @@ public : const ET& exact() const { return ptr()->exact(); } -#if 0 - AT& approx() - { return ptr()->approx(); } -#endif - - ET& exact() - { return ptr()->exact(); } - unsigned depth() const { return ptr()->depth(); diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index c505e839eb7..c9e196e7cd6 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -130,11 +130,10 @@ struct Lazy_exact_Int_Cst : public Lazy_exact_nt_rep : Lazy_exact_nt_rep(double(i)) {} void update_exact() const { - ET* pet = new ET((int)this->approx().inf()); - bool updated = this->set_exact(pet); - if (!updated) { - pet->~ET(); - } + CGAL_UPDATE_EXACT_BEGIN + ET* pet = new ET((int)this->approx().inf()); + CGAL_UPDATE_EXACT_MIDDLE + CGAL_UPDATE_EXACT_END } }; @@ -146,11 +145,10 @@ struct Lazy_exact_Cst : public Lazy_exact_nt_rep : Lazy_exact_nt_rep(x), cste(x) {} void update_exact() const { - ET* pet = new ET(cste); - bool updated = this->set_exact(pet); - if (!updated) { - pet->~ET(); - } + CGAL_UPDATE_EXACT_BEGIN + ET* pet = new ET(cste); + CGAL_UPDATE_EXACT_MIDDLE + CGAL_UPDATE_EXACT_END } private: @@ -191,14 +189,12 @@ public: void update_exact() const { - ET* pet = new ET(l.exact()); - bool updated = this->set_exact(pet); - if (!updated) { - pet->~ET(); - } else { + CGAL_UPDATE_EXACT_BEGIN + ET* pet = new ET(l.exact()); + CGAL_UPDATE_EXACT_MIDDLE this->at = l.approx(); prune_dag(); - } + CGAL_UPDATE_EXACT_END } void prune_dag() const { l.reset(); } @@ -284,15 +280,13 @@ struct NAME : public Lazy_exact_unary \ \ void update_exact() const \ { \ - ET* pet = new ET(OP(this->op1.exact())); \ - bool updated = this->set_exact(pet); \ - if (!updated) { \ - pet->~ET(); \ - } else { \ + CGAL_UPDATE_EXACT_BEGIN \ + ET* pet = new ET(OP(this->op1.exact())); \ + CGAL_UPDATE_EXACT_MIDDLE \ if (!this->approx().is_point()) \ this->at = CGAL_NTS to_interval(*(this->et)); \ this->prune_dag(); \ - } \ + CGAL_UPDATE_EXACT_END \ } \ }; @@ -312,15 +306,13 @@ struct NAME : public Lazy_exact_binary \ \ void update_exact() const \ { \ - ET* pet = new ET(this->op1.exact() OP this->op2.exact()); \ - bool updated = this->set_exact(pet); \ - if (!updated) { \ - pet->~ET(); \ - } else { \ + CGAL_UPDATE_EXACT_BEGIN \ + ET* pet = new ET(this->op1.exact() OP this->op2.exact()); \ + CGAL_UPDATE_EXACT_MIDDLE \ if (!this->approx().is_point()) \ this->at = CGAL_NTS to_interval(*(this->et)); \ this->prune_dag(); \ - } \ + CGAL_UPDATE_EXACT_END \ } \ }; @@ -338,15 +330,13 @@ struct Lazy_exact_Min : public Lazy_exact_binary void update_exact() const { - ET* pet = new ET((CGAL::min)(this->op1.exact(), this->op2.exact())); - bool updated = this->set_exact(pet); - if (!updated) { - pet->~ET(); - } else { + CGAL_UPDATE_EXACT_BEGIN + ET* pet = new ET((CGAL::min)(this->op1.exact(), this->op2.exact())); + CGAL_UPDATE_EXACT_MIDDLE if (!this->approx().is_point()) this->at = CGAL_NTS to_interval(*(this->et)); this->prune_dag(); - } + CGAL_UPDATE_EXACT_END } }; @@ -359,15 +349,13 @@ struct Lazy_exact_Max : public Lazy_exact_binary void update_exact() const { - ET* pet = new ET((CGAL::max)(this->op1.exact(), this->op2.exact())); - bool updated = this->set_exact(pet); - if (!updated) { - pet->~ET(); - } else { + CGAL_UPDATE_EXACT_BEGIN + ET* pet = new ET((CGAL::max)(this->op1.exact(), this->op2.exact())); + CGAL_UPDATE_EXACT_MIDDLE if (!this->approx().is_point()) this->at = CGAL_NTS to_interval(*(this->et)); this->prune_dag(); - } + CGAL_UPDATE_EXACT_END } }; diff --git a/STL_Extension/include/CGAL/Handle.h b/STL_Extension/include/CGAL/Handle.h index 60cd005969b..2d58f2ec8e9 100644 --- a/STL_Extension/include/CGAL/Handle.h +++ b/STL_Extension/include/CGAL/Handle.h @@ -79,11 +79,14 @@ class Handle { if (PTR) { - // TODO: the first condition tries to avoid the expensive - // release synchronization, check that it is still safe. + // The advanced version seems to work in practice on x86_64, but TSAN complains like crazy, even if I remove the questionable first test. +#if 0 if (PTR->count.load(std::memory_order_relaxed) == 1 || PTR->count.fetch_sub(1, std::memory_order_release) == 1) { std::atomic_thread_fence(std::memory_order_acquire); +#else + if (PTR->count.fetch_sub(1, std::memory_order_acq_rel) == 1) { +#endif delete PTR; } PTR=0; From 6338f89ae4e8ef93e991413d97c09e7c27874672 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 13 Nov 2020 19:36:18 +0100 Subject: [PATCH 059/349] conditional code for TSAN --- Filtered_kernel/include/CGAL/Lazy.h | 4 ++++ STL_Extension/include/CGAL/Handle.h | 4 ++-- STL_Extension/include/CGAL/Handle_for.h | 5 +++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 6e14b66831c..1612e290c21 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -373,10 +373,14 @@ public: // true if you are the last one and can clean-up bool end_update() const { +#if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) bool b = workers.load(std::memory_order_relaxed) == 1 || workers.fetch_sub(1, std::memory_order_release) == 1; // unneeded for Lazy_rep_0? if(b) std::atomic_thread_fence(std::memory_order_acquire); +#else + bool b = workers.fetch_sub(1, std::memory_order_acq_rel) == 1; +#endif return b; } diff --git a/STL_Extension/include/CGAL/Handle.h b/STL_Extension/include/CGAL/Handle.h index 2d58f2ec8e9..620851173ca 100644 --- a/STL_Extension/include/CGAL/Handle.h +++ b/STL_Extension/include/CGAL/Handle.h @@ -79,8 +79,8 @@ class Handle { if (PTR) { - // The advanced version seems to work in practice on x86_64, but TSAN complains like crazy, even if I remove the questionable first test. -#if 0 + // TSAN does not support fences :-( +#if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) if (PTR->count.load(std::memory_order_relaxed) == 1 || PTR->count.fetch_sub(1, std::memory_order_release) == 1) { std::atomic_thread_fence(std::memory_order_acquire); diff --git a/STL_Extension/include/CGAL/Handle_for.h b/STL_Extension/include/CGAL/Handle_for.h index ba3d339caf6..66d37c04ae2 100644 --- a/STL_Extension/include/CGAL/Handle_for.h +++ b/STL_Extension/include/CGAL/Handle_for.h @@ -144,9 +144,14 @@ public: ~Handle_for() { + // TSAN does not support fences :-( +#if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) if (ptr_->count.load(std::memory_order_relaxed) == 1 || ptr_->count.fetch_sub(1, std::memory_order_release) == 1) { std::atomic_thread_fence(std::memory_order_acquire); +#else + if (ptr_->count.fetch_sub(1, std::memory_order_acq_rel) == 1) { +#endif Allocator_traits::destroy(allocator, ptr_); allocator.deallocate(ptr_, 1); } From 6c2bf2c90bbae833b54a90eb73e8cc7064c03db4 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 13 Nov 2020 21:12:22 +0100 Subject: [PATCH 060/349] alternate (not working) version --- Filtered_kernel/include/CGAL/Lazy.h | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 1612e290c21..235db7c1e68 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -287,6 +287,7 @@ public: bool doit = et.compare_exchange_strong(other, (ET*)1); if (!doit) { // Wait until it becomes available + // Using a lock would let the implementation choose how to wait... while ((uintptr_t)other == 1) { std::this_thread::yield(); // or do nothing? other = et.load(std::memory_order_relaxed); @@ -311,7 +312,8 @@ public: // Should we return the pointer from update_exact, to avoid an extra load and synchronization? } -#elif 1 +#elif 0 + // This version seems strictly less interesting than the previous one mutable std::atomic worker{}; // thread that is allowed to updatee #define CGAL_UPDATE_EXACT_BEGIN \ @@ -344,17 +346,25 @@ public: } #else - mutable std::atomic_uint workers{}; // number of threads running update_exact + // number of references to the arguments, 1 when et is null, plus 1 per thread running update_exact. + // Don't care about the case where et is non-null from construction, update_exact will never be called. + // This is used to decide who can prune the tree. + mutable std::atomic_uint n_arg_refs{1}; // not written yet #define CGAL_UPDATE_EXACT_BEGIN \ - workers.fetch_add(1, std::memory_order_relaxed); \ - if (et.load(std::memory_order_relaxed)!=nullptr) \ - if (!this->start_update()) return; -#define CGAL_UPDATE_EXACT_MIDDLE \ + n_arg_refs.fetch_add(1, std::memory_order_relaxed); \ + if (et.load(std::memory_order_relaxed)==nullptr) { +#define CGAL_UPDATE_EXACT_MIDDLE_1 \ bool updated = this->set_exact(pet); \ if (!updated) { /* some other thread was faster */ \ pet->~ET(); \ - } else if (this->end_update()) { + } \ + if (updated) { +#define CGAL_UPDATE_EXACT_MIDDLE_2 \ + } \ + int dec = 1 + updated; \ + bool do_clean = n_arg_refs.fetch_sub(dec, std::memory_order_relaxed) == dec; \ + if (do_clean) { #define CGAL_UPDATE_EXACT_END \ } bool set_exact(ET* pet) const @@ -366,7 +376,7 @@ public: // true if you should update bool start_update() const { - unsigned int w = workers.fetch_add(1, std::memory_order_relaxed); + unsigned int w = n_arg_refs.fetch_add(1, std::memory_order_relaxed); ??? } From b88dd3be85ab57a3d232a63480ba01916ae00fe7 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 13 Nov 2020 23:13:43 +0100 Subject: [PATCH 061/349] Use default-constructed Lazy more. --- Filtered_kernel/include/CGAL/Lazy.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 235db7c1e68..0dc586ab0a1 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -267,11 +267,6 @@ public: return at; } - Indirect_AT& approx() - { - return at; - } - #if 1 #define CGAL_UPDATE_EXACT_BEGIN \ if (!this->start_update()) return; @@ -1782,7 +1777,7 @@ struct Lazy_construction { operator()() const { typedef Lazy Handle; - return result_type( Handle(new Lazy_rep_0()) ); + return result_type( Handle() ); } #undef CGAL_CONSTRUCTION_OPERATOR @@ -1853,7 +1848,7 @@ struct result { \ typedef Lazy Handle; typedef typename Type_mapper< typename cpp11::result_of::type ,AK, LK>::type result_type; - return result_type( Handle(new Lazy_rep_0()) ); + return result_type( Handle() ); } }; From 9d554b9ae6f5198ef7d17610b988639e1d27bfbf Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 14 Nov 2020 00:01:47 +0100 Subject: [PATCH 062/349] mention std::call_once --- Filtered_kernel/include/CGAL/Lazy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 0dc586ab0a1..d2c6ecc7f96 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -282,7 +282,7 @@ public: bool doit = et.compare_exchange_strong(other, (ET*)1); if (!doit) { // Wait until it becomes available - // Using a lock would let the implementation choose how to wait... + // TODO: try std::call_once or similar, hoping that it waits better. while ((uintptr_t)other == 1) { std::this_thread::yield(); // or do nothing? other = et.load(std::memory_order_relaxed); From 2112f0087cd6950ebaf853d4b976d62958fc185d Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 14 Nov 2020 10:59:44 +0100 Subject: [PATCH 063/349] call_once version --- Filtered_kernel/include/CGAL/Lazy.h | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index d2c6ecc7f96..49a35589ad3 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -54,6 +54,7 @@ #include #include #include +#include namespace CGAL { @@ -61,6 +62,7 @@ namespace CGAL { // The approximate value is set once at construction, and possibly updated once during update_exact(). template struct Indirect_AT { + typedef AT const& reference; std::atomic p; // no atomic ?? std::unique_ptr old; Indirect_AT():p(new AT()){} @@ -68,7 +70,7 @@ struct Indirect_AT { Indirect_AT(AT&& a):p(new AT(std::move(a))){} Indirect_AT& operator=(AT const& a){ old.reset(p.load(std::memory_order_relaxed)); p.store(new AT(a), std::memory_order_release); return *this; } Indirect_AT& operator=(AT&& a){ old.reset(p.load(std::memory_order_relaxed)); p.store(new AT(std::move(a)), std::memory_order_release); return *this; } - operator AT const&()const{return *p.load(std::memory_order_acquire);} + operator reference()const{return *p.load(std::memory_order_acquire);} ~Indirect_AT() { delete p.load(std::memory_order_acquire); } }; @@ -85,7 +87,7 @@ class Lazy_exact_nt; template inline -const AT& +decltype(auto) approx(const Lazy& l) { return l.approx(); @@ -262,12 +264,28 @@ public: Lazy_rep (A&& a, E&& e) : at(std::forward(a)), et(new ET(std::forward(e))) {} - const AT& approx() const + typename Indirect_AT::reference approx() const { return at; } #if 1 + mutable std::once_flag once; + +#define CGAL_UPDATE_EXACT_BEGIN +#define CGAL_UPDATE_EXACT_MIDDLE \ + this->et.store(pet, std::memory_order_relaxed); +#define CGAL_UPDATE_EXACT_END + + const ET & exact() const + { + // The test is unnecessary, only use it if benchmark says so + //if (et.load(std::memory_order_relaxed) == nullptr) + std::call_once(once, [this](){this->update_exact();}); + return *et.load(std::memory_order_consume); + } + +#elif 1 #define CGAL_UPDATE_EXACT_BEGIN \ if (!this->start_update()) return; #define CGAL_UPDATE_EXACT_MIDDLE \ @@ -876,7 +894,7 @@ public : friend void swap(Lazy& a, Lazy& b) noexcept { swap(static_cast(a), static_cast(b)); } - const AT& approx() const + decltype(auto) approx() const { return ptr()->approx(); } const ET& exact() const From d7555a383cf70d45cb67609f4b8f9ba52027c47e Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 14 Nov 2020 13:24:22 +0100 Subject: [PATCH 064/349] improve approximate type --- Filtered_kernel/include/CGAL/Lazy.h | 97 ++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 49a35589ad3..b29b5d5d044 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -55,11 +55,40 @@ #include #include #include +#include namespace CGAL { -// It would be nice to provide a specialization for Interval_nt, but I believe that would require making approx() return by value for this AT. +// It would be nice to provide a specialization for Interval_nt with a single AT (atomic by pieces?), possibly making approx() return by value for this AT. +// // The approximate value is set once at construction, and possibly updated once during update_exact(). +#if 0 + // Roughly sorted from fastest to slowest for building a DT3 with Epeck +#elif 1 +template +struct Indirect_AT { + typedef AT const& reference; + // TODO: we could store the second one with ET, so it doesn't take any space until needed. + std::aligned_storage_t at[2]; + std::atomic current{(AT*)&at[0]}; + Indirect_AT(){new(&at[0])AT();} + Indirect_AT(AT const& a){new(&at[0])AT(a);} + Indirect_AT(AT&& a){new(&at[0])AT(std::move(a));} + Indirect_AT& operator=(AT const& a){ new(&at[1])AT(a); current.store((AT*)&at[1], std::memory_order_release); return *this; } + Indirect_AT& operator=(AT&& a){ new(&at[1])AT(std::move(a)); current.store((AT*)&at[1], std::memory_order_release); return *this; } + operator reference()const{ + return *current.load(std::memory_order_consume); + } + ~Indirect_AT(){ + reinterpret_cast(&at[0])->~AT(); + if (current.load(std::memory_order_relaxed) == (AT*)&at[1]) { + std::atomic_thread_fence(std::memory_order_acquire); + reinterpret_cast(&at[1])->~AT(); + } + } +}; +#elif 1 +// Surprisingly fast, despite the allocation template struct Indirect_AT { typedef AT const& reference; @@ -73,6 +102,72 @@ struct Indirect_AT { operator reference()const{return *p.load(std::memory_order_acquire);} ~Indirect_AT() { delete p.load(std::memory_order_acquire); } }; +#elif 1 +template +struct Indirect_AT { + typedef AT const& reference; + AT orig{}; + std::optional fine{std::nullopt}; + std::atomic current{&orig}; + Indirect_AT(){} + Indirect_AT(AT const& a):orig(a){} + Indirect_AT(AT&& a):orig(std::move(a)){} + Indirect_AT& operator=(AT const& a){ fine=a; current.store(fine.operator->(), std::memory_order_release); return *this; } + Indirect_AT& operator=(AT&& a){ fine=std::move(a); current.store(fine.operator->(), std::memory_order_release); return *this; } + operator reference()const{ + // could be memory_order_relaxed when current points to old + return *current.load(std::memory_order_consume); + } +}; +#elif 1 +template +struct Indirect_AT { + typedef AT const& reference; + std::aligned_storage_t at[2]; + // TODO: could we use et!=nullptr for that? + std::atomic_int updated{}; + Indirect_AT(){new(&at[0])AT();} + Indirect_AT(AT const& a){new(&at[0])AT(a);} + Indirect_AT(AT&& a){new(&at[0])AT(std::move(a));} + Indirect_AT& operator=(AT const& a){ new(&at[1])AT(a); updated.store(1, std::memory_order_release); return *this; } + Indirect_AT& operator=(AT&& a){ new(&at[1])AT(std::move(a)); updated.store(1, std::memory_order_release); return *this; } + operator reference()const{ + return *reinterpret_cast(&at[updated.load(std::memory_order_acquire)]); + } + ~Indirect_AT(){ + reinterpret_cast(&at[0])->~AT(); + if (updated.load(std::memory_order_acquire)) + reinterpret_cast(&at[1])->~AT(); + } +}; +#elif 1 +template +struct Indirect_AT { + typedef AT const& reference; + AT orig{}; + std::optional fine{std::nullopt}; + // TODO: could we use et!=nullptr for that? + std::atomic_int updated{}; + std::unique_ptr old; + Indirect_AT(){} + Indirect_AT(AT const& a):orig(a){} + Indirect_AT(AT&& a):orig(std::move(a)){} + Indirect_AT& operator=(AT const& a){ fine=a; updated.store(1, std::memory_order_release); return *this; } + Indirect_AT& operator=(AT&& a){ fine=std::move(a); updated.store(1, std::memory_order_release); return *this; } + operator reference()const{ + #if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) + if (updated.load(std::memory_order_relaxed)) { + std::atomic_thread_fence(std::memory_order_acquire); + #else + if (updated.load(std::memory_order_acquire)) { + #endif + return *fine; + } else { + return orig; + } + } +}; +#endif template Date: Sat, 14 Nov 2020 15:00:47 +0100 Subject: [PATCH 065/349] Special-case intervals --- Filtered_kernel/include/CGAL/Lazy.h | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index b29b5d5d044..66a7a60e82d 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -59,8 +59,6 @@ namespace CGAL { -// It would be nice to provide a specialization for Interval_nt with a single AT (atomic by pieces?), possibly making approx() return by value for this AT. -// // The approximate value is set once at construction, and possibly updated once during update_exact(). #if 0 // Roughly sorted from fastest to slowest for building a DT3 with Epeck @@ -68,7 +66,7 @@ namespace CGAL { template struct Indirect_AT { typedef AT const& reference; - // TODO: we could store the second one with ET, so it doesn't take any space until needed. + // TODO: we could store the second one with ET, so it doesn't take any space until needed. It would make the specialization for Interval_nt less convenient though. std::aligned_storage_t at[2]; std::atomic current{(AT*)&at[0]}; Indirect_AT(){new(&at[0])AT();} @@ -169,6 +167,20 @@ struct Indirect_AT { }; #endif +// Specialization for Lazy_exact_nt, where we don't need the indirection. +template +struct Indirect_AT> { + typedef Interval_nt AT; + typedef AT reference; + std::atomic x, y; + Indirect_AT():x(),y(){} + Indirect_AT(AT a):x(-a.inf()),y(a.sup()){} + Indirect_AT& operator=(AT a){ x.store(-a.inf(), std::memory_order_relaxed); y.store(a.sup(), std::memory_order_relaxed); return *this; } + operator reference()const{ + return AT(-x.load(std::memory_order_relaxed), y.load(std::memory_order_relaxed)); + } +}; + template (a)),et_(std::forward(e)){} + ET const& et()const{return et_;} +}; + // Abstract base class for lazy numbers and lazy objects template class Lazy_rep : public Rep, public Depth_base @@ -356,174 +254,51 @@ class Lazy_rep : public Rep, public Depth_base public: typedef AT_ AT; + typedef AT_ET_wrap Indirect; - mutable Indirect_AT at{}; - mutable std::atomic et { nullptr }; + AT_wrap at_orig{}; + mutable std::atomic*> ptr_ { &at_orig }; + mutable std::once_flag once; - Lazy_rep () - : at(), et(nullptr){} + Lazy_rep () {} template Lazy_rep (A&& a) - : at(std::forward(a)), et(nullptr){} + : at_orig(std::forward(a)){} template Lazy_rep (A&& a, E&& e) - : at(std::forward(a)), et(new ET(std::forward(e))) {} + : ptr_(new AT_ET_wrap(std::forward(a), std::forward(e))) {} - typename Indirect_AT::reference approx() const + AT const& approx() const { - return at; + return ptr_.load(std::memory_order_consume)->at(); } - // I think we should have different code for cases where there is some cleanup to do (say, a sum of 2 Lazy_exact_nt) and for cases where there isn't (a Lazy_exact_nt constructed from a double). Objects can be hidden in a tuple in Lazy_rep_n, so checking if there is something to clean requires some code. It isn't clear if we also need to restrict that to cases where update_exact doesn't touch AT. The special version would be basically: if(et==0){pet=new ET(...);if(!et.exchange(0,pet))delete pet; update at?} -#if 1 - mutable std::once_flag once; - -#define CGAL_UPDATE_EXACT_BEGIN -#define CGAL_UPDATE_EXACT_MIDDLE \ - this->et.store(pet, std::memory_order_relaxed); -#define CGAL_UPDATE_EXACT_END - const ET & exact() const { // The test is unnecessary, only use it if benchmark says so - //if (et.load(std::memory_order_relaxed) == nullptr) + //if (ptr_.load(std::memory_order_relaxed) == &at_orig) std::call_once(once, [this](){this->update_exact();}); - return *et.load(std::memory_order_consume); + return static_cast*>(ptr_.load(std::memory_order_relaxed))->et(); // call_once already synchronized memory } -#elif 1 -#define CGAL_UPDATE_EXACT_BEGIN \ - if (!this->start_update()) return; -#define CGAL_UPDATE_EXACT_MIDDLE \ - this->et.store(pet, std::memory_order_release); -#define CGAL_UPDATE_EXACT_END - - // true if you should update - bool start_update() const - { - ET* other = nullptr; - // TODO specify memory_order_* - bool doit = et.compare_exchange_strong(other, (ET*)1); - if (!doit) { - // Wait until it becomes available - while ((uintptr_t)other == 1) { - std::this_thread::yield(); // or do nothing? - other = et.load(std::memory_order_relaxed); - } - return false; - } - return true; + template + void set_at(AT_ET_wrap* p, A&& a) const { + p->at_ = std::forward(a); + } + void set_at(AT_ET_wrap* p) const { + p->at_ = E2A()(p->et()); + } + void keep_at(AT_ET_wrap* p) const { + p->at_ = at_orig.at(); // do not move! } - const ET & exact() const - { - uintptr_t pet = (uintptr_t) et.load(std::memory_order_relaxed); - if (pet <= 1) { - if (pet == 0) - update_exact(); - else - // Wait until it becomes available - while((uintptr_t)et.load(std::memory_order_relaxed)==1) - std::this_thread::yield(); // or do nothing? - } - return *et.load(std::memory_order_consume); - // Should we return the pointer from update_exact, to avoid an extra load and synchronization? + void set_ptr(AT_ET_wrap* p) const { + ptr_.store(p, std::memory_order_release); } -#elif 0 - // This version seems strictly less interesting than the previous one - mutable std::atomic worker{}; // thread that is allowed to updatee - -#define CGAL_UPDATE_EXACT_BEGIN \ - if (!this->start_update()) return; -#define CGAL_UPDATE_EXACT_MIDDLE \ - this->et.store(pet, std::memory_order_release); -#define CGAL_UPDATE_EXACT_END - - // true if you should update - bool start_update() const - { - std::thread::id none{}; - // TODO specify memory_order_* - bool doit = worker.compare_exchange_strong(none, std::this_thread::get_id()); - if (!doit) { - // Wait until it becomes available - while(et.load(std::memory_order_relaxed)==nullptr) - std::this_thread::yield(); // or do nothing? - return false; - } - return true; - } - - const ET & exact() const - { - if (et.load(std::memory_order_relaxed)==nullptr) - update_exact(); - return *et.load(std::memory_order_consume); - // Should we return the pointer from update_exact, to avoid an extra load and synchronization? - } - -#else - // COMPLETE NONSENSE - // number of references to the arguments, 1 when et is null, plus 1 per thread running update_exact. - // Don't care about the case where et is non-null from construction, update_exact will never be called. - // This is used to decide who can prune the tree. - mutable std::atomic_uint n_arg_refs{1}; - // not written yet -#define CGAL_UPDATE_EXACT_BEGIN \ - n_arg_refs.fetch_add(1, std::memory_order_relaxed); \ - if (et.load(std::memory_order_relaxed)==nullptr) { -#define CGAL_UPDATE_EXACT_MIDDLE_1 \ - bool updated = this->set_exact(pet); \ - if (!updated) { /* some other thread was faster */ \ - pet->~ET(); \ - } \ - if (updated) { -#define CGAL_UPDATE_EXACT_MIDDLE_2 \ - } \ - int dec = 1 + updated; \ - bool do_clean = n_arg_refs.fetch_sub(dec, std::memory_order_relaxed) == dec; \ - if (do_clean) { -#define CGAL_UPDATE_EXACT_END \ - } - bool set_exact(ET* pet) const - { - ET* other = nullptr; - return this->et.compare_exchange_strong(other, pet, std::memory_order_release); - } - - // true if you should update - bool start_update() const - { - unsigned int w = n_arg_refs.fetch_add(1, std::memory_order_relaxed); - ??? - } - - // true if you are the last one and can clean-up - bool end_update() const - { -#if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) - bool b = workers.load(std::memory_order_relaxed) == 1 - || workers.fetch_sub(1, std::memory_order_release) == 1; - // unneeded for Lazy_rep_0? - if(b) std::atomic_thread_fence(std::memory_order_acquire); -#else - bool b = workers.fetch_sub(1, std::memory_order_acq_rel) == 1; -#endif - return b; - } - - const ET & exact() const - { - if (et.load(std::memory_order_relaxed)==nullptr) - update_exact(); - return *et.load(std::memory_order_consume); - // Should we return the pointer from update_exact, to avoid an extra load and synchronization? - } - -#endif + // I think we should have different code for cases where there is some cleanup to do (say, a sum of 2 Lazy_exact_nt) and for cases where there isn't (a Lazy_exact_nt constructed from a double). Objects can be hidden in a tuple in Lazy_rep_n, so checking if there is something to clean requires some code. It isn't clear if we also need to restrict that to cases where update_exact doesn't touch AT. The special version would be basically: if(et==0){pet=new ET(...);if(!et.exchange(0,pet))delete pet; update at?} #ifdef CGAL_LAZY_KERNEL_DEBUG void print_at_et(std::ostream& os, int level) const @@ -553,9 +328,121 @@ public: virtual void print_dag(std::ostream& os, int level) const {} #endif - bool is_lazy() const { return et == nullptr; } + bool is_lazy() const { return ptr_.load(std::memory_order_relaxed) == &at_orig; } virtual void update_exact() const = 0; - virtual ~Lazy_rep() { delete et.load(std::memory_order_consume); } + virtual ~Lazy_rep() { + #if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) + auto* p = ptr_.load(std::memory_order_relaxed); + if (p != &at_orig) { + std::atomic_thread_fence(std::memory_order_acquire); + delete p; + } +#else + auto* p = ptr_.load(std::memory_order_consume); + if (p != &at_orig) delete p; +#endif + } +}; +// do we need to (forward) declare Interval_nt? +template +class Lazy_rep, ET, E2A> : public Rep, public Depth_base +{ + Lazy_rep (const Lazy_rep&) = delete; // cannot be copied. + +public: + + typedef Interval_nt AT; + typedef ET Indirect; + + mutable std::atomic x, y; + mutable std::atomic ptr_ { nullptr }; + mutable std::once_flag once; + + Lazy_rep () {} + + Lazy_rep (AT a) + : x(-a.inf()), y(a.sup()) {} + + template + Lazy_rep (AT a, E&& e) + : x(-a.inf()), y(a.sup()), ptr_(new ET(std::forward(e))) {} + + AT approx() const + { + return AT(-x.load(std::memory_order_relaxed), y.load(std::memory_order_relaxed)); + } + + const ET & exact() const + { + // The test is unnecessary, only use it if benchmark says so + //if (ptr_.load(std::memory_order_relaxed) == nullptr) + std::call_once(once, [this](){this->update_exact();}); + return *ptr_.load(std::memory_order_relaxed); // call_once already synchronized memory + } + + template + void set_at(ET*, A&& a_) const { + AT a = a_; + x.store(-a.inf(), std::memory_order_relaxed); + y.store(a.sup(), std::memory_order_relaxed); + } + void set_at(ET* p) const { + set_at(p, E2A()(*p)); + } + void keep_at(ET*) const { } + + void set_ptr(ET* p) const { + ptr_.store(p, std::memory_order_release); + } + + bool is_point() const { + return x.load(std::memory_order_relaxed) == y.load(std::memory_order_relaxed); + } + + // I think we should have different code for cases where there is some cleanup to do (say, a sum of 2 Lazy_exact_nt) and for cases where there isn't (a Lazy_exact_nt constructed from a double). Objects can be hidden in a tuple in Lazy_rep_n, so checking if there is something to clean requires some code. It isn't clear if we also need to restrict that to cases where update_exact doesn't touch AT. The special version would be basically: if(et==0){pet=new ET(...);if(!et.exchange(0,pet))delete pet; update at?} + +#ifdef CGAL_LAZY_KERNEL_DEBUG + void print_at_et(std::ostream& os, int level) const + { + for(int i = 0; i < level; i++){ + os << " "; + } + os << "Approximation: "; + print_at(os, at); + os << std::endl; + if(! is_lazy()){ + for(int i = 0; i < level; i++){ + os << " "; + } + os << "Exact: "; + print_at(os, *et); + os << std::endl; +#ifdef CGAL_LAZY_KERNEL_DEBUG_SHOW_TYPEID + for(int i = 0; i < level; i++){ + os << " "; + } + os << " (type: " << typeid(*et).name() << ")" << std::endl; +#endif // CGAL_LAZY_KERNEL_DEBUG_SHOW_TYPEID + } + } + + virtual void print_dag(std::ostream& os, int level) const {} +#endif + + bool is_lazy() const { return ptr_.load(std::memory_order_relaxed) == nullptr; } + virtual void update_exact() const = 0; + virtual ~Lazy_rep() { + #if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) + auto* p = ptr_.load(std::memory_order_relaxed); + if (p != nullptr) { + std::atomic_thread_fence(std::memory_order_acquire); + delete p; + } +#else + auto* p = ptr_.load(std::memory_order_consume); + if (p != nullptr) delete p; +#endif + } }; @@ -563,6 +450,7 @@ template, private EC { + typedef Lazy_rep< AT, ET, E2A > Base; // Lazy_rep_0 does not inherit from EC or take a parameter AC. It has different constructors. static_assert(sizeof...(L)>0, "Use Lazy_rep_0 instead"); template friend class Lazy_kernel_base; @@ -570,13 +458,11 @@ class Lazy_rep_n : const EC& ec() const { return *this; } template void update_exact_helper(std::index_sequence) const { - CGAL_UPDATE_EXACT_BEGIN - ET* pet = new ET(ec()( CGAL::exact( std::get(l) ) ... ) ); - CGAL_UPDATE_EXACT_MIDDLE - this->at = E2A()(*pet); - // TODO: apply some reset-like function to each element instead. - l = std::tuple{}; - CGAL_UPDATE_EXACT_END + auto* p = new typename Base::Indirect(ec()( CGAL::exact( std::get(l) ) ... ) ); + this->set_at(p); + this->set_ptr(p); + // TODO: apply some reset-like function to each element instead. + l = std::tuple{}; } public: void update_exact() const { @@ -622,10 +508,8 @@ public: void update_exact() const { - CGAL_UPDATE_EXACT_BEGIN - ET* pet = new ET(); - CGAL_UPDATE_EXACT_MIDDLE - CGAL_UPDATE_EXACT_END + auto* p = new typename Base::Indirect(); + this->set_ptr(p); } Lazy_rep_0() @@ -736,23 +620,21 @@ public: void update_exact() const { - CGAL_UPDATE_EXACT_BEGIN - ET* pet = new ET(); -// TODO : This looks really unfinished... - std::vector vec; - //this->et->reserve(this->at.size()); - ec()(CGAL::exact(l1_), std::back_inserter(*pet)); - CGAL_UPDATE_EXACT_MIDDLE - this->at = E2A()(*pet); - // Prune lazy tree - l1_ = L1(); - CGAL_UPDATE_EXACT_END + auto* p = new AT_ET_wrap(); + // TODO : This looks really unfinished... + std::vector vec; + //this->et->reserve(this->at.size()); + ec()(CGAL::exact(l1_), std::back_inserter(p->et_)); + this->set_at(p); + this->set_ptr(p); + // Prune lazy tree + l1_ = L1(); } Lazy_rep_with_vector_1(const AC& ac, const EC& /*ec*/, const L1& l1) : l1_(l1) { - ac(CGAL::approx(l1), std::back_inserter(this->at)); + ac(CGAL::approx(l1), std::back_inserter(this->at_orig.at_)); } #ifdef CGAL_LAZY_KERNEL_DEBUG @@ -790,22 +672,20 @@ public: void update_exact() const { - CGAL_UPDATE_EXACT_BEGIN - ET* pet = new ET(); - pet->reserve(this->at.size()); - ec()(CGAL::exact(l1_), CGAL::exact(l2_), std::back_inserter(*pet)); - CGAL_UPDATE_EXACT_MIDDLE - this->at = E2A()(*pet); - // Prune lazy tree - l1_ = L1(); - l2_ = L2(); - CGAL_UPDATE_EXACT_END + auto* p = new AT_ET_wrap(); + p->et_.reserve(this->at_orig.at().size()); + ec()(CGAL::exact(l1_), CGAL::exact(l2_), std::back_inserter(p->et_)); + this->set_at(p); + this->set_ptr(p); + // Prune lazy tree + l1_ = L1(); + l2_ = L2(); } Lazy_rep_with_vector_2(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) : l1_(l1), l2_(l2) { - ac(CGAL::approx(l1), CGAL::approx(l2), std::back_inserter(this->at)); + ac(CGAL::approx(l1), CGAL::approx(l2), std::back_inserter(this->at_orig.at_)); } #ifdef CGAL_LAZY_KERNEL_DEBUG @@ -843,21 +723,19 @@ public: void update_exact() const { - CGAL_UPDATE_EXACT_BEGIN - ET* pet = new ET(); - ec()(CGAL::exact(l1_), CGAL::exact(l2_), *pet); - CGAL_UPDATE_EXACT_MIDDLE - this->at = E2A()(*pet); - // Prune lazy tree - l1_ = L1(); - l2_ = L2(); - CGAL_UPDATE_EXACT_END + auto* p = new AT_ET_wrap(); + ec()(CGAL::exact(l1_), CGAL::exact(l2_), p->et_); + this->set_at(p); + this->set_ptr(p); + // Prune lazy tree + l1_ = L1(); + l2_ = L2(); } Lazy_rep_2_1(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) : Lazy_rep(), l1_(l1), l2_(l2) { - ac(CGAL::approx(l1), CGAL::approx(l2), this->at); + ac(CGAL::approx(l1), CGAL::approx(l2), this->at_orig.at_); } #ifdef CGAL_LAZY_KERNEL_DEBUG @@ -898,21 +776,19 @@ public: void update_exact() const { - CGAL_UPDATE_EXACT_BEGIN - ET* pet = new ET(); - ec()(CGAL::exact(l1_), CGAL::exact(l2_), pet->first, pet->second ); - CGAL_UPDATE_EXACT_MIDDLE - this->at = E2A()(*pet); - // Prune lazy tree - l1_ = L1(); - l2_ = L2(); - CGAL_UPDATE_EXACT_END + auto* p = new AT_ET_wrap(); + ec()(CGAL::exact(l1_), CGAL::exact(l2_), p->et_.first, p->et_.second ); + this->set_at(p); + this->set_ptr(p); + // Prune lazy tree + l1_ = L1(); + l2_ = L2(); } Lazy_rep_2_2(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) : Lazy_rep(), l1_(l1), l2_(l2) { - ac(CGAL::approx(l1), CGAL::approx(l2), this->at.first, this->at.second); + ac(CGAL::approx(l1), CGAL::approx(l2), this->at_orig.at_.first, this->at_orig.at_.second); } #ifdef CGAL_LAZY_KERNEL_DEBUG diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index c9e196e7cd6..09d1f44c459 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -130,10 +130,8 @@ struct Lazy_exact_Int_Cst : public Lazy_exact_nt_rep : Lazy_exact_nt_rep(double(i)) {} void update_exact() const { - CGAL_UPDATE_EXACT_BEGIN - ET* pet = new ET((int)this->approx().inf()); - CGAL_UPDATE_EXACT_MIDDLE - CGAL_UPDATE_EXACT_END + ET* pet = new ET((int)this->approx().inf()); + this->set_ptr(pet); } }; @@ -145,10 +143,8 @@ struct Lazy_exact_Cst : public Lazy_exact_nt_rep : Lazy_exact_nt_rep(x), cste(x) {} void update_exact() const { - CGAL_UPDATE_EXACT_BEGIN - ET* pet = new ET(cste); - CGAL_UPDATE_EXACT_MIDDLE - CGAL_UPDATE_EXACT_END + ET* pet = new ET(cste); + this->set_ptr(pet); } private: @@ -189,12 +185,10 @@ public: void update_exact() const { - CGAL_UPDATE_EXACT_BEGIN - ET* pet = new ET(l.exact()); - CGAL_UPDATE_EXACT_MIDDLE - this->at = l.approx(); - prune_dag(); - CGAL_UPDATE_EXACT_END + ET* pet = new ET(l.exact()); + this->set_at(pet, l.approx()); + this->set_ptr(pet); + this->prune_dag(); } void prune_dag() const { l.reset(); } @@ -280,13 +274,11 @@ struct NAME : public Lazy_exact_unary \ \ void update_exact() const \ { \ - CGAL_UPDATE_EXACT_BEGIN \ - ET* pet = new ET(OP(this->op1.exact())); \ - CGAL_UPDATE_EXACT_MIDDLE \ - if (!this->approx().is_point()) \ - this->at = CGAL_NTS to_interval(*(this->et)); \ - this->prune_dag(); \ - CGAL_UPDATE_EXACT_END \ + ET* pet = new ET(OP(this->op1.exact())); \ + if (!this->is_point()) \ + this->set_at(pet); \ + this->set_ptr(pet); \ + this->prune_dag(); \ } \ }; @@ -306,13 +298,11 @@ struct NAME : public Lazy_exact_binary \ \ void update_exact() const \ { \ - CGAL_UPDATE_EXACT_BEGIN \ - ET* pet = new ET(this->op1.exact() OP this->op2.exact()); \ - CGAL_UPDATE_EXACT_MIDDLE \ - if (!this->approx().is_point()) \ - this->at = CGAL_NTS to_interval(*(this->et)); \ - this->prune_dag(); \ - CGAL_UPDATE_EXACT_END \ + ET* pet = new ET(this->op1.exact() OP this->op2.exact()); \ + if (!this->is_point()) \ + this->set_at(pet); \ + this->set_ptr(pet); \ + this->prune_dag(); \ } \ }; @@ -330,13 +320,11 @@ struct Lazy_exact_Min : public Lazy_exact_binary void update_exact() const { - CGAL_UPDATE_EXACT_BEGIN - ET* pet = new ET((CGAL::min)(this->op1.exact(), this->op2.exact())); - CGAL_UPDATE_EXACT_MIDDLE - if (!this->approx().is_point()) - this->at = CGAL_NTS to_interval(*(this->et)); - this->prune_dag(); - CGAL_UPDATE_EXACT_END + ET* pet = new ET((CGAL::min)(this->op1.exact(), this->op2.exact())); + if (!this->is_point()) + this->set_at(pet); + this->set_ptr(pet); + this->prune_dag(); } }; @@ -349,13 +337,11 @@ struct Lazy_exact_Max : public Lazy_exact_binary void update_exact() const { - CGAL_UPDATE_EXACT_BEGIN - ET* pet = new ET((CGAL::max)(this->op1.exact(), this->op2.exact())); - CGAL_UPDATE_EXACT_MIDDLE - if (!this->approx().is_point()) - this->at = CGAL_NTS to_interval(*(this->et)); - this->prune_dag(); - CGAL_UPDATE_EXACT_END + ET* pet = new ET((CGAL::max)(this->op1.exact(), this->op2.exact())); + if (!this->is_point()) + this->set_at(pet); + this->set_ptr(pet); + this->prune_dag(); } }; From 3aced7f7e76bcbee31a776893de8b6d3de6429bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 19 Nov 2020 19:39:40 +0100 Subject: [PATCH 068/349] add projected segment overlapping case + clean up --- ...Triangulation_2_projection_traits_base_3.h | 80 ++++++++++++++++--- 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h b/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h index 984d2381035..337c915289e 100644 --- a/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h +++ b/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h @@ -202,36 +202,94 @@ public: Object planes_intersection = intersection(plane_1, plane_2); if(planes_intersection.empty()) { +#ifdef CGAL_T2_PTB_3_DEBUG std::cerr << "planes_intersection is empty\n"; +#endif return planes_intersection; } if(const Line* line = object_cast(&planes_intersection)) { + // check if the intersection line intersects both segments by + // checking if a point on the intersection line is between + // the segments endpoints const Point& pi = line->point(0); - if(cross_product(normal, pi - s1.source()) + if( cross_product(normal, pi - s1.source()) * cross_product(normal, pi - s1.target()) > FT(0) || - cross_product(normal, pi - s2.source()) + cross_product(normal, pi - s2.source()) * cross_product(normal, pi - s2.target()) > FT(0) ) { - // the intersection of the lines is not inside the segments + // the intersection of the supporting lines is not inside both segments +#ifdef CGAL_T2_PTB_3_DEBUG std::cerr << "intersection not inside\n"; return Object(); +#endif } else { - // Let the plane passing through s1.source() and with normal - // the cross product of s1.to_vector() and s2.to_vector(). That - // plane should intersect *l, now. - return intersection(*line, Plane_3(s1.source(), - cross_product(s1.to_vector(), - s2.to_vector()))); + // Let the plane passing through s1.source() and with normal the traits' normal. + // The segment intersection point computed as the intersection + // of the *l and that plane. Note that if segments are not coplanar the positive + // of the intersection point is somehow arbitrary. + return intersection(*line, Plane_3(s1.source(), normal)); } } if(object_cast(&planes_intersection)) { - std::cerr << "coplanar lines\n"; - CGAL_error(); +#ifdef CGAL_T2_PTB_3_DEBUG + std::cerr << "coplanar supporting lines\n"; +#endif + auto is_inside_segment = [](const Segment& s, const Point& q) + { + return Vector_3(q,s.source()) * Vector_3(q,s.target()) <=0; + }; + + bool src2_in_s1 = is_inside_segment(s1, s2.source()); + bool tgt2_in_s1 = is_inside_segment(s1, s2.target()); + bool src1_in_s2 = is_inside_segment(s2, s1.source()); + bool tgt1_in_s2 = is_inside_segment(s2, s1.target()); + + if (src1_in_s2 && tgt1_in_s2) return make_object(s1); + if (src2_in_s1 && tgt2_in_s1) return make_object(s2); + + if (src1_in_s2) + { + if (src2_in_s1) + { + if (cross_product(normal, Vector_3(s1.source(), s2.source())) != NULL_VECTOR) + return make_object(Segment(s1.source(), s2.source())); + else + return make_object(s1.source()); + } + if (tgt2_in_s1) + { + if (cross_product(normal, Vector_3(s1.source(), s2.target())) != NULL_VECTOR) + return make_object(Segment(s1.source(), s2.target())); + else + return make_object(s1.source()); + } + // should never get here with a Kernel with exact constructions + return make_object(s1.source()); + } + if (tgt1_in_s2) + { + if (src2_in_s1) + { + if (cross_product(normal, Vector_3(s1.target(), s2.source())) != NULL_VECTOR) + return make_object(Segment(s1.target(), s2.source())); + else + return make_object(s1.target()); + } + if (tgt2_in_s1) + { + if (cross_product(normal, Vector_3(s1.target(), s2.target())) != NULL_VECTOR) + return make_object(Segment(s1.target(), s2.target())); + else + return make_object(s1.target()); + } + // should never get here with a Kernel with exact constructions + return make_object(s1.target()); + } return Object(); } return Object(); From bbc78910e85420727dd3c01ba1ff46c8eac2d5e6 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 9 Jan 2021 20:19:34 +0100 Subject: [PATCH 069/349] unsafe version for intervals --- Filtered_kernel/include/CGAL/Lazy.h | 67 ++++++++++++++++------- Number_types/include/CGAL/Lazy_exact_nt.h | 3 + 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 553872bc505..0d5bfea7cf0 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -354,24 +354,64 @@ public: typedef Interval_nt AT; typedef ET Indirect; - mutable std::atomic x, y; mutable std::atomic ptr_ { nullptr }; mutable std::once_flag once; Lazy_rep () {} +#ifdef CGAL_USE_SSE2 + // How (un)safe is this? The interval is aligned, so load/store instructions will not slice any double. On recent hardware, they should even be atomic, although without an official guarantee, and we don't need 128-bit atomicity anyway. The main danger is the unpredictable optimizations a compiler could apply (volatile would disable most of them, but it doesn't seem great). The goal is to minimize the overhead compared to a single-thread version by making the fast path almost identical. + mutable AT i; + + Lazy_rep (AT a) + : i(a) {} + + template + Lazy_rep (AT a, E&& e) + : ptr_(new ET(std::forward(e))), i(a) {} + + AT approx() const + { + return i; + } + + bool is_point() const { + return i.is_point(); + } + + void set_at(ET*, AT a) const { + i = a; + } +#else + mutable std::atomic x, y; + Lazy_rep (AT a) : x(-a.inf()), y(a.sup()) {} template Lazy_rep (AT a, E&& e) - : x(-a.inf()), y(a.sup()), ptr_(new ET(std::forward(e))) {} + : ptr_(new ET(std::forward(e))), x(-a.inf()), y(a.sup()) {} AT approx() const { return AT(-x.load(std::memory_order_relaxed), y.load(std::memory_order_relaxed)); } + bool is_point() const { + return x.load(std::memory_order_relaxed) == y.load(std::memory_order_relaxed); + } + + void set_at(ET*, AT a) const { + x.store(-a.inf(), std::memory_order_relaxed); + y.store(a.sup(), std::memory_order_relaxed); + } +#endif + + void set_at(ET* p) const { + set_at(p, E2A()(*p)); + } + void keep_at(ET*) const { } + const ET & exact() const { // The test is unnecessary, only use it if benchmark says so @@ -380,25 +420,10 @@ public: return *ptr_.load(std::memory_order_relaxed); // call_once already synchronized memory } - template - void set_at(ET*, A&& a_) const { - AT a = a_; - x.store(-a.inf(), std::memory_order_relaxed); - y.store(a.sup(), std::memory_order_relaxed); - } - void set_at(ET* p) const { - set_at(p, E2A()(*p)); - } - void keep_at(ET*) const { } - void set_ptr(ET* p) const { ptr_.store(p, std::memory_order_release); } - bool is_point() const { - return x.load(std::memory_order_relaxed) == y.load(std::memory_order_relaxed); - } - // I think we should have different code for cases where there is some cleanup to do (say, a sum of 2 Lazy_exact_nt) and for cases where there isn't (a Lazy_exact_nt constructed from a double). Objects can be hidden in a tuple in Lazy_rep_n, so checking if there is something to clean requires some code. It isn't clear if we also need to restrict that to cases where update_exact doesn't touch AT. The special version would be basically: if(et==0){pet=new ET(...);if(!et.exchange(0,pet))delete pet; update at?} #ifdef CGAL_LAZY_KERNEL_DEBUG @@ -620,7 +645,7 @@ public: void update_exact() const { - auto* p = new AT_ET_wrap(); + auto* p = new typename Base::Indirect(); // TODO : This looks really unfinished... std::vector vec; //this->et->reserve(this->at.size()); @@ -672,7 +697,7 @@ public: void update_exact() const { - auto* p = new AT_ET_wrap(); + auto* p = new typename Base::Indirect(); p->et_.reserve(this->at_orig.at().size()); ec()(CGAL::exact(l1_), CGAL::exact(l2_), std::back_inserter(p->et_)); this->set_at(p); @@ -723,7 +748,7 @@ public: void update_exact() const { - auto* p = new AT_ET_wrap(); + auto* p = new typename Base::Indirect(); ec()(CGAL::exact(l1_), CGAL::exact(l2_), p->et_); this->set_at(p); this->set_ptr(p); @@ -776,7 +801,7 @@ public: void update_exact() const { - auto* p = new AT_ET_wrap(); + auto* p = new typename Base::Indirect(); ec()(CGAL::exact(l1_), CGAL::exact(l2_), p->et_.first, p->et_.second ); this->set_at(p); this->set_ptr(p); diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index 09d1f44c459..94b1bd8b3da 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -131,6 +131,7 @@ struct Lazy_exact_Int_Cst : public Lazy_exact_nt_rep void update_exact() const { ET* pet = new ET((int)this->approx().inf()); + this->keep_at(pet); this->set_ptr(pet); } }; @@ -144,6 +145,7 @@ struct Lazy_exact_Cst : public Lazy_exact_nt_rep void update_exact() const { ET* pet = new ET(cste); + this->keep_at(pet); this->set_ptr(pet); } @@ -320,6 +322,7 @@ struct Lazy_exact_Min : public Lazy_exact_binary void update_exact() const { + // Should we test is_point earlier, and construct ET from double in that case? Constructing from double is not free, but if op1 or op2 is not exact yet, we may be able to skip a whole tree of exact constructions. ET* pet = new ET((CGAL::min)(this->op1.exact(), this->op2.exact())); if (!this->is_point()) this->set_at(pet); From d41c42174deb827d25c4d2f909a6c0f47a8bb80c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 9 Jan 2021 21:18:58 +0100 Subject: [PATCH 070/349] More uniform interface --- Number_types/include/CGAL/Lazy_exact_nt.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index 94b1bd8b3da..4899c83774a 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -130,7 +130,7 @@ struct Lazy_exact_Int_Cst : public Lazy_exact_nt_rep : Lazy_exact_nt_rep(double(i)) {} void update_exact() const { - ET* pet = new ET((int)this->approx().inf()); + ET* pet = new typename Lazy_exact_nt_rep::Indirect((int)this->approx().inf()); this->keep_at(pet); this->set_ptr(pet); } @@ -144,7 +144,7 @@ struct Lazy_exact_Cst : public Lazy_exact_nt_rep : Lazy_exact_nt_rep(x), cste(x) {} void update_exact() const { - ET* pet = new ET(cste); + ET* pet = new typename Lazy_exact_nt_rep::Indirect(cste); this->keep_at(pet); this->set_ptr(pet); } @@ -187,7 +187,7 @@ public: void update_exact() const { - ET* pet = new ET(l.exact()); + ET* pet = new typename Lazy_exact_nt_rep::Indirect(l.exact()); this->set_at(pet, l.approx()); this->set_ptr(pet); this->prune_dag(); @@ -276,7 +276,7 @@ struct NAME : public Lazy_exact_unary \ \ void update_exact() const \ { \ - ET* pet = new ET(OP(this->op1.exact())); \ + ET* pet = new typename Lazy_exact_nt_rep::Indirect(OP(this->op1.exact())); \ if (!this->is_point()) \ this->set_at(pet); \ this->set_ptr(pet); \ @@ -294,13 +294,13 @@ CGAL_LAZY_UNARY_OP(CGAL_NTS sqrt, Lazy_exact_Sqrt) template \ struct NAME : public Lazy_exact_binary \ { \ - typedef typename Lazy_exact_binary::AT::Protector P; \ + typedef typename Lazy_exact_binary::AT::Protector P; \ NAME (const Lazy_exact_nt &a, const Lazy_exact_nt &b) \ : Lazy_exact_binary((P(), a.approx() OP b.approx()), a, b) {} \ \ void update_exact() const \ { \ - ET* pet = new ET(this->op1.exact() OP this->op2.exact()); \ + ET* pet = new typename Lazy_exact_nt_rep::Indirect(this->op1.exact() OP this->op2.exact()); \ if (!this->is_point()) \ this->set_at(pet); \ this->set_ptr(pet); \ @@ -323,7 +323,7 @@ struct Lazy_exact_Min : public Lazy_exact_binary void update_exact() const { // Should we test is_point earlier, and construct ET from double in that case? Constructing from double is not free, but if op1 or op2 is not exact yet, we may be able to skip a whole tree of exact constructions. - ET* pet = new ET((CGAL::min)(this->op1.exact(), this->op2.exact())); + ET* pet = new typename Lazy_exact_nt_rep::Indirect((CGAL::min)(this->op1.exact(), this->op2.exact())); if (!this->is_point()) this->set_at(pet); this->set_ptr(pet); @@ -340,7 +340,7 @@ struct Lazy_exact_Max : public Lazy_exact_binary void update_exact() const { - ET* pet = new ET((CGAL::max)(this->op1.exact(), this->op2.exact())); + ET* pet = new typename Lazy_exact_nt_rep::Indirect((CGAL::max)(this->op1.exact(), this->op2.exact())); if (!this->is_point()) this->set_at(pet); this->set_ptr(pet); From acec5990621f3288d6ef21c5216ef6b5b497125c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 9 Jan 2021 23:47:52 +0100 Subject: [PATCH 071/349] General unsafe version --- Filtered_kernel/include/CGAL/Lazy.h | 116 +++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 3 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 0d5bfea7cf0..422be8f1a1f 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -246,6 +246,7 @@ struct AT_ET_wrap : AT_wrap { }; // Abstract base class for lazy numbers and lazy objects +#if 1 template class Lazy_rep : public Rep, public Depth_base { @@ -298,7 +299,7 @@ public: ptr_.store(p, std::memory_order_release); } - // I think we should have different code for cases where there is some cleanup to do (say, a sum of 2 Lazy_exact_nt) and for cases where there isn't (a Lazy_exact_nt constructed from a double). Objects can be hidden in a tuple in Lazy_rep_n, so checking if there is something to clean requires some code. It isn't clear if we also need to restrict that to cases where update_exact doesn't touch AT. The special version would be basically: if(et==0){pet=new ET(...);if(!et.exchange(0,pet))delete pet; update at?} + // I think we should have different code for cases where there is some cleanup to do (say, a sum of 2 Lazy_exact_nt) and for cases where there isn't (a Lazy_exact_nt constructed from a double), but it may require making exact() virtual. Objects can be hidden in a tuple in Lazy_rep_n, so checking if there is something to clean requires some code. It isn't clear if we also need to restrict that to cases where update_exact doesn't touch AT. The special version would be basically: if(et==0){pet=new ET(...);if(!et.exchange(0,pet))delete pet; update at?} #ifdef CGAL_LAZY_KERNEL_DEBUG void print_at_et(std::ostream& os, int level) const @@ -343,7 +344,115 @@ public: #endif } }; +#else +/* How (un)safe is this? The goal is to minimize the overhead compared to a single-thread version by making the fast path almost identical. + * For scalars on x86_64, the interval is aligned, so load/store instructions will not slice any double. On recent hardware, they should even be atomic, although without an official guarantee, and we don't need 128-bit atomicity anyway. The main danger is the unpredictable optimizations a compiler could apply (volatile would disable most of them, but it doesn't seem great). + * For aggregate-like types (Simple_cartesian::Point_3), it should be ok for the same reason. + * This is definitely NOT safe for a std::vector like a Point_d with Dynamic_dimension_tag, so it should only be enabled on a case by case basis, if at all. Storing a Point_3 piecewise with 6 atomic_double would be doable, but painful, and I didn't benchmark to check the performance. */ +template +class Lazy_rep : public Rep, public Depth_base +{ + Lazy_rep (const Lazy_rep&) = delete; // cannot be copied. + +public: + + typedef AT_ AT; + typedef ET Indirect; + + mutable AT at; + mutable std::atomic ptr_ { nullptr }; + mutable std::once_flag once; + + Lazy_rep () {} + + template + Lazy_rep (A&& a) + : at(std::forward(a)) {} + + template + Lazy_rep (A&& a, E&& e) + : at(std::forward(a)), ptr_(new ET(std::forward(e))) {} + + AT const& approx() const + { + return at; + } + + // FIXME: Uh? + bool is_point() const { + return at.is_point(); + } + + template + void set_at(ET*, A&& a) const { + at = std::forward(a); + } + + void set_at(ET* p) const { + set_at(p, E2A()(*p)); + } + void keep_at(ET*) const { } + + const ET & exact() const + { + // The test is unnecessary, only use it if benchmark says so + //if (ptr_.load(std::memory_order_relaxed) == nullptr) + std::call_once(once, [this](){this->update_exact();}); + return *ptr_.load(std::memory_order_relaxed); // call_once already synchronized memory + } + + void set_ptr(ET* p) const { + ptr_.store(p, std::memory_order_release); + } + + // I think we should have different code for cases where there is some cleanup to do (say, a sum of 2 Lazy_exact_nt) and for cases where there isn't (a Lazy_exact_nt constructed from a double). Objects can be hidden in a tuple in Lazy_rep_n, so checking if there is something to clean requires some code. It isn't clear if we also need to restrict that to cases where update_exact doesn't touch AT. The special version would be basically: if(et==0){pet=new ET(...);if(!et.exchange(0,pet))delete pet; update at?} + +#ifdef CGAL_LAZY_KERNEL_DEBUG + void print_at_et(std::ostream& os, int level) const + { + for(int i = 0; i < level; i++){ + os << " "; + } + os << "Approximation: "; + print_at(os, at); + os << std::endl; + if(! is_lazy()){ + for(int i = 0; i < level; i++){ + os << " "; + } + os << "Exact: "; + print_at(os, *et); + os << std::endl; +#ifdef CGAL_LAZY_KERNEL_DEBUG_SHOW_TYPEID + for(int i = 0; i < level; i++){ + os << " "; + } + os << " (type: " << typeid(*et).name() << ")" << std::endl; +#endif // CGAL_LAZY_KERNEL_DEBUG_SHOW_TYPEID + } + } + + virtual void print_dag(std::ostream& os, int level) const {} +#endif + + bool is_lazy() const { return ptr_.load(std::memory_order_relaxed) == nullptr; } + virtual void update_exact() const = 0; + virtual ~Lazy_rep() { + #if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) + auto* p = ptr_.load(std::memory_order_relaxed); + if (p != nullptr) { + std::atomic_thread_fence(std::memory_order_acquire); + delete p; + } +#else + auto* p = ptr_.load(std::memory_order_consume); + if (p != nullptr) delete p; +#endif + } +}; +#endif // do we need to (forward) declare Interval_nt? +#if 1 template class Lazy_rep, ET, E2A> : public Rep, public Depth_base { @@ -469,6 +578,7 @@ public: #endif } }; +#endif template @@ -581,7 +691,7 @@ struct Approx_converter //typedef Converter Number_type_converter; template < typename T > - const typename T::AT& + decltype(auto) operator()(const T&t) const { return t.approx(); } @@ -606,7 +716,7 @@ struct Exact_converter //typedef Converter Number_type_converter; template < typename T > - const typename T::ET& + decltype(auto) operator()(const T&t) const { return t.exact(); } From 5ccab34c186c19e230496222f5f0437b3d2eadac Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 9 Jan 2021 23:54:52 +0100 Subject: [PATCH 072/349] Mark some classes `final` --- Filtered_kernel/include/CGAL/Lazy.h | 12 ++++++------ Number_types/include/CGAL/Lazy_exact_nt.h | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 422be8f1a1f..ddb2601cf83 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -582,7 +582,7 @@ public: template -class Lazy_rep_n : +class Lazy_rep_n final : public Lazy_rep< AT, ET, E2A >, private EC { typedef Lazy_rep< AT, ET, E2A > Base; @@ -634,7 +634,7 @@ class Lazy_rep_n : // The rep for the leaf node template -class Lazy_rep_0 : public Lazy_rep +class Lazy_rep_0 final : public Lazy_rep { typedef Lazy_rep Base; @@ -738,7 +738,7 @@ struct Exact_converter template -class Lazy_rep_with_vector_1 +class Lazy_rep_with_vector_1 final : public Lazy_rep, std::vector, E2A> , private EC { @@ -789,7 +789,7 @@ public: template -class Lazy_rep_with_vector_2 +class Lazy_rep_with_vector_2 final : public Lazy_rep, std::vector, E2A> , private EC { @@ -840,7 +840,7 @@ public: template -class Lazy_rep_2_1 +class Lazy_rep_2_1 final : public Lazy_rep , private EC { @@ -893,7 +893,7 @@ public: // The following rep class stores two non-const reference parameters of type R1 and R2 template -class Lazy_rep_2_2 +class Lazy_rep_2_2 final : public Lazy_rep, std::pair, E2A> , private EC { diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index 4899c83774a..43d9904828c 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -124,7 +124,7 @@ struct Lazy_exact_nt_rep : public Lazy_exact_nt::Self_rep // int constant template -struct Lazy_exact_Int_Cst : public Lazy_exact_nt_rep +struct Lazy_exact_Int_Cst final : public Lazy_exact_nt_rep { Lazy_exact_Int_Cst (int i) : Lazy_exact_nt_rep(double(i)) {} @@ -138,7 +138,7 @@ struct Lazy_exact_Int_Cst : public Lazy_exact_nt_rep // double constant template -struct Lazy_exact_Cst : public Lazy_exact_nt_rep +struct Lazy_exact_Cst final : public Lazy_exact_nt_rep { Lazy_exact_Cst (X x) : Lazy_exact_nt_rep(x), cste(x) {} @@ -155,7 +155,7 @@ struct Lazy_exact_Cst : public Lazy_exact_nt_rep // Exact constant template -struct Lazy_exact_Ex_Cst : public Lazy_exact_nt_rep +struct Lazy_exact_Ex_Cst final : public Lazy_exact_nt_rep { Lazy_exact_Ex_Cst (const ET & e) : Lazy_exact_nt_rep(CGAL_NTS to_interval(e)) @@ -173,7 +173,7 @@ struct Lazy_exact_Ex_Cst : public Lazy_exact_nt_rep // Construction from a Lazy_exact_nt (which keeps the lazyness). template -class Lazy_lazy_exact_Cst : public Lazy_exact_nt_rep +class Lazy_lazy_exact_Cst final : public Lazy_exact_nt_rep { mutable Lazy_exact_nt l; @@ -268,7 +268,7 @@ struct Lazy_exact_binary : public Lazy_exact_nt_rep // Macro for unary operations #define CGAL_LAZY_UNARY_OP(OP, NAME) \ template \ -struct NAME : public Lazy_exact_unary \ +struct NAME final : public Lazy_exact_unary \ { \ typedef typename Lazy_exact_unary::AT::Protector P; \ NAME (const Lazy_exact_nt &a) \ @@ -292,7 +292,7 @@ CGAL_LAZY_UNARY_OP(CGAL_NTS sqrt, Lazy_exact_Sqrt) // A macro for +, -, * and / #define CGAL_LAZY_BINARY_OP(OP, NAME) \ template \ -struct NAME : public Lazy_exact_binary \ +struct NAME final : public Lazy_exact_binary \ { \ typedef typename Lazy_exact_binary::AT::Protector P; \ NAME (const Lazy_exact_nt &a, const Lazy_exact_nt &b) \ @@ -315,7 +315,7 @@ CGAL_LAZY_BINARY_OP(/, Lazy_exact_Div) // Minimum template -struct Lazy_exact_Min : public Lazy_exact_binary +struct Lazy_exact_Min final : public Lazy_exact_binary { Lazy_exact_Min (const Lazy_exact_nt &a, const Lazy_exact_nt &b) : Lazy_exact_binary((CGAL::min)(a.approx(), b.approx()), a, b) {} @@ -333,7 +333,7 @@ struct Lazy_exact_Min : public Lazy_exact_binary // Maximum template -struct Lazy_exact_Max : public Lazy_exact_binary +struct Lazy_exact_Max final : public Lazy_exact_binary { Lazy_exact_Max (const Lazy_exact_nt &a, const Lazy_exact_nt &b) : Lazy_exact_binary((CGAL::max)(a.approx(), b.approx()), a, b) {} From b752dd3d80550e3b4ab7a8e724c1b98fa122b951 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sun, 10 Jan 2021 18:10:42 +0100 Subject: [PATCH 073/349] Missing Lazy_exact_Ex_Cst --- Filtered_kernel/include/CGAL/Lazy.h | 10 +++++-- Number_types/include/CGAL/Lazy_exact_nt.h | 34 +++++++++++------------ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index ddb2601cf83..437873eb1db 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -280,6 +280,10 @@ public: { // The test is unnecessary, only use it if benchmark says so //if (ptr_.load(std::memory_order_relaxed) == &at_orig) +#if defined(__gnu_linux__) && !defined(_REENTRANT) + // That shouldn't be needed, but I was getting a mysterious std::system_error with gcc-10 without it. + static_assert(false, "Please pass -pthread to the compiler"); +#endif std::call_once(once, [this](){this->update_exact();}); return static_cast*>(ptr_.load(std::memory_order_relaxed))->et(); // call_once already synchronized memory } @@ -332,7 +336,7 @@ public: bool is_lazy() const { return ptr_.load(std::memory_order_relaxed) == &at_orig; } virtual void update_exact() const = 0; virtual ~Lazy_rep() { - #if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) +#if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) auto* p = ptr_.load(std::memory_order_relaxed); if (p != &at_orig) { std::atomic_thread_fence(std::memory_order_acquire); @@ -438,7 +442,7 @@ public: bool is_lazy() const { return ptr_.load(std::memory_order_relaxed) == nullptr; } virtual void update_exact() const = 0; virtual ~Lazy_rep() { - #if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) +#if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) auto* p = ptr_.load(std::memory_order_relaxed); if (p != nullptr) { std::atomic_thread_fence(std::memory_order_acquire); @@ -566,7 +570,7 @@ public: bool is_lazy() const { return ptr_.load(std::memory_order_relaxed) == nullptr; } virtual void update_exact() const = 0; virtual ~Lazy_rep() { - #if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) +#if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) auto* p = ptr_.load(std::memory_order_relaxed); if (p != nullptr) { std::atomic_thread_fence(std::memory_order_acquire); diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index 43d9904828c..add772e9e52 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -113,6 +113,10 @@ struct Lazy_exact_nt_rep : public Lazy_exact_nt::Self_rep Lazy_exact_nt_rep (const Interval_nt & i) : Base(i) {} + template + Lazy_exact_nt_rep (const Interval_nt & i, T&& e) + : Base(i, std::forward(e)) {} + #ifdef CGAL_LAZY_KERNEL_DEBUG void print_dag(std::ostream& os, int level) const @@ -123,6 +127,8 @@ struct Lazy_exact_nt_rep : public Lazy_exact_nt::Self_rep }; // int constant +// Unused. This would make even more sense for a double constant but may not be worth the trouble. +// Could be recycled as a partial specialization of Lazy_exact_Cst. template struct Lazy_exact_Int_Cst final : public Lazy_exact_nt_rep { @@ -130,7 +136,7 @@ struct Lazy_exact_Int_Cst final : public Lazy_exact_nt_rep : Lazy_exact_nt_rep(double(i)) {} void update_exact() const { - ET* pet = new typename Lazy_exact_nt_rep::Indirect((int)this->approx().inf()); + auto* pet = new typename Lazy_exact_nt_rep::Indirect((int)this->approx().sup()); this->keep_at(pet); this->set_ptr(pet); } @@ -144,7 +150,7 @@ struct Lazy_exact_Cst final : public Lazy_exact_nt_rep : Lazy_exact_nt_rep(x), cste(x) {} void update_exact() const { - ET* pet = new typename Lazy_exact_nt_rep::Indirect(cste); + auto* pet = new typename Lazy_exact_nt_rep::Indirect(cste); this->keep_at(pet); this->set_ptr(pet); } @@ -157,16 +163,10 @@ struct Lazy_exact_Cst final : public Lazy_exact_nt_rep template struct Lazy_exact_Ex_Cst final : public Lazy_exact_nt_rep { - Lazy_exact_Ex_Cst (const ET & e) - : Lazy_exact_nt_rep(CGAL_NTS to_interval(e)) - { - this->et = new ET(e); - } - Lazy_exact_Ex_Cst (ET&& e) - : Lazy_exact_nt_rep(CGAL_NTS to_interval(e)) - { - this->et = new ET(std::move(e)); - } + template + Lazy_exact_Ex_Cst (T&& e) + : Lazy_exact_nt_rep(CGAL_NTS to_interval(e), std::forward(e)) + { } void update_exact() const { CGAL_error(); } }; @@ -187,7 +187,7 @@ public: void update_exact() const { - ET* pet = new typename Lazy_exact_nt_rep::Indirect(l.exact()); + auto* pet = new typename Lazy_exact_nt_rep::Indirect(l.exact()); this->set_at(pet, l.approx()); this->set_ptr(pet); this->prune_dag(); @@ -276,7 +276,7 @@ struct NAME final : public Lazy_exact_unary \ \ void update_exact() const \ { \ - ET* pet = new typename Lazy_exact_nt_rep::Indirect(OP(this->op1.exact())); \ + auto* pet = new typename Lazy_exact_nt_rep::Indirect(OP(this->op1.exact())); \ if (!this->is_point()) \ this->set_at(pet); \ this->set_ptr(pet); \ @@ -300,7 +300,7 @@ struct NAME final : public Lazy_exact_binary \ \ void update_exact() const \ { \ - ET* pet = new typename Lazy_exact_nt_rep::Indirect(this->op1.exact() OP this->op2.exact()); \ + auto* pet = new typename Lazy_exact_nt_rep::Indirect(this->op1.exact() OP this->op2.exact()); \ if (!this->is_point()) \ this->set_at(pet); \ this->set_ptr(pet); \ @@ -323,7 +323,7 @@ struct Lazy_exact_Min final : public Lazy_exact_binary void update_exact() const { // Should we test is_point earlier, and construct ET from double in that case? Constructing from double is not free, but if op1 or op2 is not exact yet, we may be able to skip a whole tree of exact constructions. - ET* pet = new typename Lazy_exact_nt_rep::Indirect((CGAL::min)(this->op1.exact(), this->op2.exact())); + auto* pet = new typename Lazy_exact_nt_rep::Indirect((CGAL::min)(this->op1.exact(), this->op2.exact())); if (!this->is_point()) this->set_at(pet); this->set_ptr(pet); @@ -340,7 +340,7 @@ struct Lazy_exact_Max final : public Lazy_exact_binary void update_exact() const { - ET* pet = new typename Lazy_exact_nt_rep::Indirect((CGAL::max)(this->op1.exact(), this->op2.exact())); + auto* pet = new typename Lazy_exact_nt_rep::Indirect((CGAL::max)(this->op1.exact(), this->op2.exact())); if (!this->is_point()) this->set_at(pet); this->set_ptr(pet); From e9ee3ae6062fb178a8beba5b2c7e9336abaad0e2 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sun, 10 Jan 2021 22:13:03 +0100 Subject: [PATCH 074/349] comment on Lazy_exact_nt --- Number_types/include/CGAL/Lazy_exact_nt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index add772e9e52..9aa2f98eb44 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -265,6 +265,8 @@ struct Lazy_exact_binary : public Lazy_exact_nt_rep // function objects plus, minus, multiplies, divides...). But it would require // a template template parameter, and GCC 2.95 seems to crash easily with them. +// Instead of having nodes only for simple operations, we should use expression templates to build nodes for arbitrary expressions, a*d-b*c should be a single node, that stores a tuple (a,b,c,d) and knows how to update_exact. + // Macro for unary operations #define CGAL_LAZY_UNARY_OP(OP, NAME) \ template \ From 398a228ddf54f14de782c86e14d7cad57e78ee24 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sun, 10 Jan 2021 23:24:48 +0100 Subject: [PATCH 075/349] comment on static filters in Epeck_d --- NewKernel_d/include/CGAL/Epeck_d.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NewKernel_d/include/CGAL/Epeck_d.h b/NewKernel_d/include/CGAL/Epeck_d.h index 62466490326..eade53339e8 100644 --- a/NewKernel_d/include/CGAL/Epeck_d.h +++ b/NewKernel_d/include/CGAL/Epeck_d.h @@ -22,7 +22,7 @@ #include #include -// TODO: add static filters somewhere +// TODO: In Kernel_23, Epeck predicates first see if they can convert their arguments to Epick types exactly, and in that case use the Epick predicates (including static filters, Mpzf, etc). namespace CGAL { #define CGAL_KA Cartesian_base_d #define CGAL_KE Cartesian_base_d::Type, Dim> From a513a4802a360f72f2f5b040cbfa70bd6f858879 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sun, 10 Jan 2021 23:50:41 +0100 Subject: [PATCH 076/349] comment about __libc_single_threaded --- STL_Extension/include/CGAL/Handle.h | 1 + 1 file changed, 1 insertion(+) diff --git a/STL_Extension/include/CGAL/Handle.h b/STL_Extension/include/CGAL/Handle.h index 620851173ca..0265b48fcc4 100644 --- a/STL_Extension/include/CGAL/Handle.h +++ b/STL_Extension/include/CGAL/Handle.h @@ -95,6 +95,7 @@ class Handle void incref() const noexcept { + // TODO: on linux, we could check __libc_single_threaded and in that case do load, +1, store. PTR->count.fetch_add(1, std::memory_order_relaxed); } From 60891a92d1f7278747d42590952b998ffd2dc89a Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 11 Jan 2021 09:12:50 +0100 Subject: [PATCH 077/349] selector for the Lazy_rep implementation --- Filtered_kernel/include/CGAL/Lazy.h | 65 ++++++++++++----------------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 437873eb1db..28c40faf9d3 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -224,6 +224,19 @@ struct Depth_base { #endif }; +// 0: safe default, AT is behind a pointer that can be atomically changed, and it doesn't disappear during update_exact +// 1: use plain AT without protection +// 2: split an interval as 2 atomic_double +// FIXME: CGAL_USE_SSE2 is clearly not the right condition +templatestruct Lazy_rep_selector { static constexpr int value = 0; }; +#ifdef CGAL_USE_SSE2 +templatestruct Lazy_rep_selector> { static constexpr int value = 1; }; +templatestruct Lazy_rep_selector,N>> { static constexpr int value = 1; }; +templatestruct Lazy_rep_selector>>> { static constexpr int value = 1; }; +templatestruct Lazy_rep_selector>>> { static constexpr int value = 1; }; +#else +templatestruct Lazy_rep_selector> { static constexpr int value = 2; }; +#endif template struct AT_wrap { @@ -246,8 +259,7 @@ struct AT_ET_wrap : AT_wrap { }; // Abstract base class for lazy numbers and lazy objects -#if 1 -template +template ::value /* 0 */> class Lazy_rep : public Rep, public Depth_base { Lazy_rep (const Lazy_rep&) = delete; // cannot be copied. @@ -276,6 +288,11 @@ public: return ptr_.load(std::memory_order_consume)->at(); } + // FIXME: Uh? + bool is_point() const { + return approx().is_point(); + } + const ET & exact() const { // The test is unnecessary, only use it if benchmark says so @@ -348,13 +365,13 @@ public: #endif } }; -#else + /* How (un)safe is this? The goal is to minimize the overhead compared to a single-thread version by making the fast path almost identical. * For scalars on x86_64, the interval is aligned, so load/store instructions will not slice any double. On recent hardware, they should even be atomic, although without an official guarantee, and we don't need 128-bit atomicity anyway. The main danger is the unpredictable optimizations a compiler could apply (volatile would disable most of them, but it doesn't seem great). * For aggregate-like types (Simple_cartesian::Point_3), it should be ok for the same reason. * This is definitely NOT safe for a std::vector like a Point_d with Dynamic_dimension_tag, so it should only be enabled on a case by case basis, if at all. Storing a Point_3 piecewise with 6 atomic_double would be doable, but painful, and I didn't benchmark to check the performance. */ template -class Lazy_rep : public Rep, public Depth_base +class Lazy_rep : public Rep, public Depth_base { Lazy_rep (const Lazy_rep&) = delete; // cannot be copied. @@ -409,8 +426,6 @@ public: ptr_.store(p, std::memory_order_release); } - // I think we should have different code for cases where there is some cleanup to do (say, a sum of 2 Lazy_exact_nt) and for cases where there isn't (a Lazy_exact_nt constructed from a double). Objects can be hidden in a tuple in Lazy_rep_n, so checking if there is something to clean requires some code. It isn't clear if we also need to restrict that to cases where update_exact doesn't touch AT. The special version would be basically: if(et==0){pet=new ET(...);if(!et.exchange(0,pet))delete pet; update at?} - #ifdef CGAL_LAZY_KERNEL_DEBUG void print_at_et(std::ostream& os, int level) const { @@ -454,11 +469,10 @@ public: #endif } }; -#endif + // do we need to (forward) declare Interval_nt? -#if 1 template -class Lazy_rep, ET, E2A> : public Rep, public Depth_base +class Lazy_rep, ET, E2A, 2> : public Rep, public Depth_base { Lazy_rep (const Lazy_rep&) = delete; // cannot be copied. @@ -467,43 +481,18 @@ public: typedef Interval_nt AT; typedef ET Indirect; + mutable std::atomic x, y; // -inf, +sup mutable std::atomic ptr_ { nullptr }; mutable std::once_flag once; Lazy_rep () {} -#ifdef CGAL_USE_SSE2 - // How (un)safe is this? The interval is aligned, so load/store instructions will not slice any double. On recent hardware, they should even be atomic, although without an official guarantee, and we don't need 128-bit atomicity anyway. The main danger is the unpredictable optimizations a compiler could apply (volatile would disable most of them, but it doesn't seem great). The goal is to minimize the overhead compared to a single-thread version by making the fast path almost identical. - mutable AT i; - - Lazy_rep (AT a) - : i(a) {} - - template - Lazy_rep (AT a, E&& e) - : ptr_(new ET(std::forward(e))), i(a) {} - - AT approx() const - { - return i; - } - - bool is_point() const { - return i.is_point(); - } - - void set_at(ET*, AT a) const { - i = a; - } -#else - mutable std::atomic x, y; - Lazy_rep (AT a) : x(-a.inf()), y(a.sup()) {} template Lazy_rep (AT a, E&& e) - : ptr_(new ET(std::forward(e))), x(-a.inf()), y(a.sup()) {} + : x(-a.inf()), y(a.sup()), ptr_(new ET(std::forward(e))) {} AT approx() const { @@ -511,14 +500,13 @@ public: } bool is_point() const { - return x.load(std::memory_order_relaxed) == y.load(std::memory_order_relaxed); + return -x.load(std::memory_order_relaxed) == y.load(std::memory_order_relaxed); } void set_at(ET*, AT a) const { x.store(-a.inf(), std::memory_order_relaxed); y.store(a.sup(), std::memory_order_relaxed); } -#endif void set_at(ET* p) const { set_at(p, E2A()(*p)); @@ -582,7 +570,6 @@ public: #endif } }; -#endif template From f90cec8862c12643b017728a9e13800cfe79f21f Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 11 Jan 2021 09:14:59 +0100 Subject: [PATCH 078/349] Remove is_point wrapper This doesn't seem to provide anything useful with the current implementations. It probably helped avoid an atomic operation in some earlier version. --- Filtered_kernel/include/CGAL/Lazy.h | 14 -------------- Number_types/include/CGAL/Lazy_exact_nt.h | 8 ++++---- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 28c40faf9d3..3087ae38137 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -288,11 +288,6 @@ public: return ptr_.load(std::memory_order_consume)->at(); } - // FIXME: Uh? - bool is_point() const { - return approx().is_point(); - } - const ET & exact() const { // The test is unnecessary, only use it if benchmark says so @@ -399,11 +394,6 @@ public: return at; } - // FIXME: Uh? - bool is_point() const { - return at.is_point(); - } - template void set_at(ET*, A&& a) const { at = std::forward(a); @@ -499,10 +489,6 @@ public: return AT(-x.load(std::memory_order_relaxed), y.load(std::memory_order_relaxed)); } - bool is_point() const { - return -x.load(std::memory_order_relaxed) == y.load(std::memory_order_relaxed); - } - void set_at(ET*, AT a) const { x.store(-a.inf(), std::memory_order_relaxed); y.store(a.sup(), std::memory_order_relaxed); diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index 9aa2f98eb44..5f7a88485d9 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -279,7 +279,7 @@ struct NAME final : public Lazy_exact_unary \ void update_exact() const \ { \ auto* pet = new typename Lazy_exact_nt_rep::Indirect(OP(this->op1.exact())); \ - if (!this->is_point()) \ + if (!this->approx().is_point()) \ this->set_at(pet); \ this->set_ptr(pet); \ this->prune_dag(); \ @@ -303,7 +303,7 @@ struct NAME final : public Lazy_exact_binary \ void update_exact() const \ { \ auto* pet = new typename Lazy_exact_nt_rep::Indirect(this->op1.exact() OP this->op2.exact()); \ - if (!this->is_point()) \ + if (!this->approx().is_point()) \ this->set_at(pet); \ this->set_ptr(pet); \ this->prune_dag(); \ @@ -326,7 +326,7 @@ struct Lazy_exact_Min final : public Lazy_exact_binary { // Should we test is_point earlier, and construct ET from double in that case? Constructing from double is not free, but if op1 or op2 is not exact yet, we may be able to skip a whole tree of exact constructions. auto* pet = new typename Lazy_exact_nt_rep::Indirect((CGAL::min)(this->op1.exact(), this->op2.exact())); - if (!this->is_point()) + if (!this->approx().is_point()) this->set_at(pet); this->set_ptr(pet); this->prune_dag(); @@ -343,7 +343,7 @@ struct Lazy_exact_Max final : public Lazy_exact_binary void update_exact() const { auto* pet = new typename Lazy_exact_nt_rep::Indirect((CGAL::max)(this->op1.exact(), this->op2.exact())); - if (!this->is_point()) + if (!this->approx().is_point()) this->set_at(pet); this->set_ptr(pet); this->prune_dag(); From 40ff696e19cda21c8541f55bf1fa6e9aff0d92df Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 11 Jan 2021 16:38:14 +0100 Subject: [PATCH 079/349] Unused #include --- Filtered_kernel/include/CGAL/Lazy.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 3087ae38137..c36d971ca4f 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -55,7 +55,6 @@ #include #include #include -#include namespace CGAL { From 9f0f7eb0335f9af47305d347796ab121c73a7325 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 11 Jan 2021 19:40:13 +0100 Subject: [PATCH 080/349] is_currently_single_threaded --- Filtered_kernel/include/CGAL/Lazy.h | 4 ++-- Installation/include/CGAL/config.h | 10 ++++++++ STL_Extension/include/CGAL/Handle.h | 28 +++++++++++++++------- STL_Extension/include/CGAL/Handle_for.h | 31 ++++++++++++++++++------- 4 files changed, 54 insertions(+), 19 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index c36d971ca4f..38a731af1cc 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -289,12 +289,12 @@ public: const ET & exact() const { - // The test is unnecessary, only use it if benchmark says so - //if (ptr_.load(std::memory_order_relaxed) == &at_orig) #if defined(__gnu_linux__) && !defined(_REENTRANT) // That shouldn't be needed, but I was getting a mysterious std::system_error with gcc-10 without it. static_assert(false, "Please pass -pthread to the compiler"); #endif + // The test is unnecessary, only use it if benchmark says so + //if (ptr_.load(std::memory_order_relaxed) == &at_orig) std::call_once(once, [this](){this->update_exact();}); return static_cast*>(ptr_.load(std::memory_order_relaxed))->et(); // call_once already synchronized memory } diff --git a/Installation/include/CGAL/config.h b/Installation/include/CGAL/config.h index 6a00defb2e8..36ba68c6d6b 100644 --- a/Installation/include/CGAL/config.h +++ b/Installation/include/CGAL/config.h @@ -613,6 +613,16 @@ using std::max; #define CGAL_CAN_USE_CXX11_ATOMIC #endif +#ifndef CGAL_HAS_THREADS +inline bool is_currently_single_threaded(){ return true; } +#elif __has_include() +#include +inline bool is_currently_single_threaded(){ return ::__libc_single_threaded; } +#else +/* This is the conservative default */ +inline bool is_currently_single_threaded(){ return false; } +#endif + // Support for LEDA with threads // Not that, if CGAL_HAS_THREADS is defined, and you want to use LEDA, // you must link with a version of LEDA libraries that support threads. diff --git a/STL_Extension/include/CGAL/Handle.h b/STL_Extension/include/CGAL/Handle.h index 0265b48fcc4..5779a99ec64 100644 --- a/STL_Extension/include/CGAL/Handle.h +++ b/STL_Extension/include/CGAL/Handle.h @@ -79,24 +79,36 @@ class Handle { if (PTR) { + if (is_currently_single_threaded()) { + auto c = PTR->count.load(std::memory_order_relaxed); + if (c == 1) + delete PTR; + else + PTR->count.store(c - 1, std::memory_order_relaxed); + PTR = 0; + } else { // TSAN does not support fences :-( #if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) - if (PTR->count.load(std::memory_order_relaxed) == 1 - || PTR->count.fetch_sub(1, std::memory_order_release) == 1) { - std::atomic_thread_fence(std::memory_order_acquire); + if (PTR->count.load(std::memory_order_relaxed) == 1 + || PTR->count.fetch_sub(1, std::memory_order_release) == 1) { + std::atomic_thread_fence(std::memory_order_acquire); #else - if (PTR->count.fetch_sub(1, std::memory_order_acq_rel) == 1) { + if (PTR->count.fetch_sub(1, std::memory_order_acq_rel) == 1) { #endif - delete PTR; + delete PTR; + } + PTR=0; } - PTR=0; } } void incref() const noexcept { - // TODO: on linux, we could check __libc_single_threaded and in that case do load, +1, store. - PTR->count.fetch_add(1, std::memory_order_relaxed); + if (is_currently_single_threaded()) { + PTR->count.store(PTR->count.load(std::memory_order_relaxed) + 1, std::memory_order_relaxed); + } else { + PTR->count.fetch_add(1, std::memory_order_relaxed); + } } int diff --git a/STL_Extension/include/CGAL/Handle_for.h b/STL_Extension/include/CGAL/Handle_for.h index 66d37c04ae2..e76246ef905 100644 --- a/STL_Extension/include/CGAL/Handle_for.h +++ b/STL_Extension/include/CGAL/Handle_for.h @@ -99,7 +99,10 @@ public: : ptr_(h.ptr_) { // CGAL_assume (ptr_->count > 0); - ptr_->count.fetch_add(1, std::memory_order_relaxed); + if (is_currently_single_threaded()) + ptr_->count.store(ptr_->count.load(std::memory_order_relaxed) + 1, std::memory_order_relaxed); + else + ptr_->count.fetch_add(1, std::memory_order_relaxed); } Handle_for& @@ -144,16 +147,26 @@ public: ~Handle_for() { + if (is_currently_single_threaded()) { + auto c = ptr_->count.load(std::memory_order_relaxed); + if (c == 1) { + Allocator_traits::destroy(allocator, ptr_); + allocator.deallocate(ptr_, 1); + } else { + ptr_->count.store(c - 1, std::memory_order_relaxed); + } + } else { // TSAN does not support fences :-( #if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) - if (ptr_->count.load(std::memory_order_relaxed) == 1 - || ptr_->count.fetch_sub(1, std::memory_order_release) == 1) { - std::atomic_thread_fence(std::memory_order_acquire); + if (ptr_->count.load(std::memory_order_relaxed) == 1 + || ptr_->count.fetch_sub(1, std::memory_order_release) == 1) { + std::atomic_thread_fence(std::memory_order_acquire); #else - if (ptr_->count.fetch_sub(1, std::memory_order_acq_rel) == 1) { + if (ptr_->count.fetch_sub(1, std::memory_order_acq_rel) == 1) { #endif - Allocator_traits::destroy(allocator, ptr_); - allocator.deallocate(ptr_, 1); + Allocator_traits::destroy(allocator, ptr_); + allocator.deallocate(ptr_, 1); + } } } @@ -190,7 +203,7 @@ public: bool is_shared() const noexcept { - return ptr_->count > 1; + return ptr_->count.load(std::memory_order_relaxed) > 1; } bool @@ -202,7 +215,7 @@ public: long use_count() const noexcept { - return ptr_->count; + return ptr_->count.load(std::memory_order_relaxed); } void From 9efa9b5117dd4e7896a242dedc2094691b033e2c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 11 Jan 2021 22:27:46 +0100 Subject: [PATCH 081/349] CGAL_HAS_THREADS --- Filtered_kernel/include/CGAL/Lazy.h | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 38a731af1cc..b0459b6f958 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -227,14 +227,18 @@ struct Depth_base { // 1: use plain AT without protection // 2: split an interval as 2 atomic_double // FIXME: CGAL_USE_SSE2 is clearly not the right condition +#ifdef CGAL_HAS_THREADS templatestruct Lazy_rep_selector { static constexpr int value = 0; }; -#ifdef CGAL_USE_SSE2 +# ifdef CGAL_USE_SSE2 templatestruct Lazy_rep_selector> { static constexpr int value = 1; }; templatestruct Lazy_rep_selector,N>> { static constexpr int value = 1; }; templatestruct Lazy_rep_selector>>> { static constexpr int value = 1; }; templatestruct Lazy_rep_selector>>> { static constexpr int value = 1; }; -#else +# else templatestruct Lazy_rep_selector> { static constexpr int value = 2; }; +# endif +#else +templatestruct Lazy_rep_selector { static constexpr int value = 1; }; #endif template @@ -289,8 +293,10 @@ public: const ET & exact() const { -#if defined(__gnu_linux__) && !defined(_REENTRANT) - // That shouldn't be needed, but I was getting a mysterious std::system_error with gcc-10 without it. +#if defined(CGAL_HAS_THREADS) && defined(__gnu_linux__) && __GNUC__ < 11 && !defined(_REENTRANT) + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55394 + // -pthread or -lpthread is just needed for linking, but I can't test that here... + // We could take the lack of _REENTRANT on that platform as forcing CGAL_HAS_NO_THREADS static_assert(false, "Please pass -pthread to the compiler"); #endif // The test is unnecessary, only use it if benchmark says so @@ -376,7 +382,9 @@ public: mutable AT at; mutable std::atomic ptr_ { nullptr }; +#ifdef CGAL_HAS_THREADS mutable std::once_flag once; +#endif Lazy_rep () {} @@ -405,9 +413,14 @@ public: const ET & exact() const { +#ifdef CGAL_HAS_THREADS // The test is unnecessary, only use it if benchmark says so //if (ptr_.load(std::memory_order_relaxed) == nullptr) std::call_once(once, [this](){this->update_exact();}); +#else + if (ptr_.load(std::memory_order_relaxed) == nullptr) + this->update_exact(); +#endif return *ptr_.load(std::memory_order_relaxed); // call_once already synchronized memory } From 93f415f717c340a7c2574effaa600d98c92c2c10 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 14 Jan 2021 00:26:45 +0100 Subject: [PATCH 082/349] comment --- Filtered_kernel/include/CGAL/Lazy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index b0459b6f958..c3c0235d036 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -367,7 +367,7 @@ public: }; /* How (un)safe is this? The goal is to minimize the overhead compared to a single-thread version by making the fast path almost identical. - * For scalars on x86_64, the interval is aligned, so load/store instructions will not slice any double. On recent hardware, they should even be atomic, although without an official guarantee, and we don't need 128-bit atomicity anyway. The main danger is the unpredictable optimizations a compiler could apply (volatile would disable most of them, but it doesn't seem great). + * For scalars on x86_64, the interval is aligned, so load/store instructions will not slice any double (although Intel does not explicitly guarantee it). On recent hardware, they should even be atomic, although without an official guarantee, and we don't need 128-bit atomicity anyway. The main danger is the unpredictable optimizations a compiler could apply (volatile would disable most of them, but it doesn't seem great), including replacing load/store with memcpy, where I fear some implementation/hardware combinations might slice sometimes. Making Interval_nt a pair of atomic_double would avoid this problem, but would likely incur a penalty since compilers don't optimize those pairs of loads or stores (TODO: benchmark). * For aggregate-like types (Simple_cartesian::Point_3), it should be ok for the same reason. * This is definitely NOT safe for a std::vector like a Point_d with Dynamic_dimension_tag, so it should only be enabled on a case by case basis, if at all. Storing a Point_3 piecewise with 6 atomic_double would be doable, but painful, and I didn't benchmark to check the performance. */ template From a3c1a20f1d3a01564cf21b8a327eaed5bbcaf8f0 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 14 Jan 2021 01:01:06 +0100 Subject: [PATCH 083/349] comment --- Filtered_kernel/include/CGAL/Lazy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index c3c0235d036..c7e10706227 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -367,7 +367,7 @@ public: }; /* How (un)safe is this? The goal is to minimize the overhead compared to a single-thread version by making the fast path almost identical. - * For scalars on x86_64, the interval is aligned, so load/store instructions will not slice any double (although Intel does not explicitly guarantee it). On recent hardware, they should even be atomic, although without an official guarantee, and we don't need 128-bit atomicity anyway. The main danger is the unpredictable optimizations a compiler could apply (volatile would disable most of them, but it doesn't seem great), including replacing load/store with memcpy, where I fear some implementation/hardware combinations might slice sometimes. Making Interval_nt a pair of atomic_double would avoid this problem, but would likely incur a penalty since compilers don't optimize those pairs of loads or stores (TODO: benchmark). + * For scalars on x86_64, the interval is aligned, so load/store instructions will not slice any double (although Intel does not explicitly guarantee it). On recent hardware, they should even be atomic, although without an official guarantee, and we don't need 128-bit atomicity anyway. The main danger is the unpredictable optimizations a compiler could apply (volatile would disable most of them, but it doesn't seem great), including replacing load/store with memcpy, where I fear some implementation/hardware combinations might slice sometimes. Making Interval_nt a pair of atomic_double would avoid this problem, but would likely incur a penalty since compilers don't optimize atomics much, and we shouldn't need to store/load all the time (TODO: benchmark). * For aggregate-like types (Simple_cartesian::Point_3), it should be ok for the same reason. * This is definitely NOT safe for a std::vector like a Point_d with Dynamic_dimension_tag, so it should only be enabled on a case by case basis, if at all. Storing a Point_3 piecewise with 6 atomic_double would be doable, but painful, and I didn't benchmark to check the performance. */ template From 35cc50717938721d08d9274c1f07b3ac7f397704 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 30 Jan 2021 11:55:30 +0100 Subject: [PATCH 084/349] comment --- Filtered_kernel/include/CGAL/Lazy_kernel.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Filtered_kernel/include/CGAL/Lazy_kernel.h b/Filtered_kernel/include/CGAL/Lazy_kernel.h index 696b81556f7..2b9fecfe436 100644 --- a/Filtered_kernel/include/CGAL/Lazy_kernel.h +++ b/Filtered_kernel/include/CGAL/Lazy_kernel.h @@ -329,6 +329,7 @@ public: LR * lr = dynamic_cast(p.ptr()); if(lr && (! lr->et)){ + // FIXME: this is not thread-safe at all, some other thread could update_exact and clear l between the 2 lines. Same for the following functors. return std::get<2>(lr->l); } return BaseClass().compute_weight_2_object()(p); From 3082808434e497a85819f944726d6fe4bbffed4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 1 Feb 2021 10:12:16 +0100 Subject: [PATCH 085/349] restore original code --- .../Triangulation_2_projection_traits_base_3.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h b/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h index 337c915289e..3e586a1eb8a 100644 --- a/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h +++ b/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h @@ -227,11 +227,12 @@ public: } else { - // Let the plane passing through s1.source() and with normal the traits' normal. - // The segment intersection point computed as the intersection - // of the *l and that plane. Note that if segments are not coplanar the positive - // of the intersection point is somehow arbitrary. - return intersection(*line, Plane_3(s1.source(), normal)); + // Let the plane passing through s1.source() and with normal + // the cross product of s1.to_vector() and s2.to_vector(). That + // plane should intersect *l, now. + return intersection(*line, Plane_3(s1.source(), + cross_product(s1.to_vector(), + s2.to_vector()))); } } if(object_cast(&planes_intersection)) From 2c1b967db15c3b43b04eb034d14ed938faaa0c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 1 Feb 2021 11:19:30 +0100 Subject: [PATCH 086/349] add tests for intersection of segments --- ...t_cdt_2_projection_traits_special_case.cpp | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/Triangulation_2/test/Triangulation_2/test_cdt_2_projection_traits_special_case.cpp b/Triangulation_2/test/Triangulation_2/test_cdt_2_projection_traits_special_case.cpp index 26693b95a28..bf163771380 100644 --- a/Triangulation_2/test/Triangulation_2/test_cdt_2_projection_traits_special_case.cpp +++ b/Triangulation_2/test/Triangulation_2/test_cdt_2_projection_traits_special_case.cpp @@ -60,6 +60,67 @@ bool test(std::string test_name) return cdt.is_valid(); } + +template +bool test_segment_intersections(std::string test_name) +{ + std::cerr << "Testing " << test_name << std::endl; + + CDT_2_traits traits(typename K::Vector_3(0,0,1)); + typename CDT_2_traits::Intersect_2 intersect = traits.intersect_2_object(); + + typedef typename CDT_2_traits::Segment_2 Segment_2; + typedef typename CDT_2_traits::Point_2 Point_2; + + // test point intersection + Segment_2 s1( Point_2(0,0,0), Point_2(1,1,0) ), + s2( Point_2(0,1,0), Point_2(1,0,0) ); + + CGAL::Object o = intersect(s1,s2); + assert( o.is() ); + +// test segment overlap + Point_2 pts[4] = { Point_2(0,0,0), Point_2(1,0,1), Point_2(2,0,2), Point_2(4,0,3) }; + + o = intersect( Segment_2(pts[0], pts[1]), Segment_2(pts[2], pts[3]) ); + assert( o.empty() ); + + // pure overlap + o = intersect( Segment_2(pts[0], pts[2]), Segment_2(pts[1], pts[3]) ); + assert( o.is() ); + o = intersect( Segment_2(pts[0], pts[2]), Segment_2(pts[3], pts[1]) ); + assert( o.is() ); + o = intersect( Segment_2(pts[2], pts[0]), Segment_2(pts[1], pts[3]) ); + assert( o.is() ); + o = intersect( Segment_2(pts[2], pts[0]), Segment_2(pts[3], pts[1]) ); + assert( o.is() ); + // segment fully included + o = intersect( Segment_2(pts[0], pts[3]), Segment_2(pts[1], pts[2]) ); + assert( o.is() ); + assert( CGAL::object_cast(o) == Segment_2(pts[1], pts[2]) ); + // segment fully included with shared vertex + o = intersect( Segment_2(pts[0], pts[1]), Segment_2(pts[0], pts[2]) ); + assert( o.is() ); + assert( CGAL::object_cast(o) == Segment_2(pts[0], pts[1]) ); + // segment sharing a vertex + o = intersect( Segment_2(pts[0], pts[1]), Segment_2(pts[1], pts[2]) ); + assert( o.is() ); + assert( CGAL::object_cast(o) == pts[1]); + + // degenerate segment + Segment_2 sd(Point_2(1,0,6), Point_2(1,0,7)); + o = intersect( Segment_2(pts[0], pts[2]), sd ); + assert( o.is() ); + o = intersect( Segment_2(pts[0], pts[1]), sd ); + assert( o.is() ); + o = intersect( Segment_2(pts[1], pts[0]), sd ); + assert( o.is() ); + o = intersect( Segment_2(pts[2], pts[3]), sd ); + assert( o.empty() ); + + return true; +} + int main() { std::cerr.precision(17); @@ -75,5 +136,12 @@ int main() test > ("CDT_2 in a 3D plane, with Epeck"); + ok = ok && test_segment_intersections > + ("CDT_2 traits intersection with Epick"); + ok = ok && test_segment_intersections > + ("CDT_2 traits intersection with Epeck"); + return ok ? 0 : 1; } From a3713f7c27e9a7b0fc80f7579ba4b5ad92220d63 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 15 Feb 2021 23:22:19 +0100 Subject: [PATCH 087/349] reset operation to prune trees --- Filtered_kernel/include/CGAL/Lazy.h | 34 +++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index c7e10706227..10cf0468772 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -223,6 +223,23 @@ struct Depth_base { #endif }; +template::value> struct Lazy_reset_member_1 { + void operator()(T& t)const{ t = T(); } +}; +template struct Lazy_reset_member_1 { + void operator()(T& t)const{ t.reset(); } +}; +templatevoid lazy_reset_member(T&t) { + Lazy_reset_member_1()(t); +} +templatevoid lazy_reset_member_tuple(std::tuple&t, std::index_sequence) { + using ignore = int[]; + ignore { (lazy_reset_member(std::get(t)), 0) ... }; +} +templatevoid lazy_reset_member(std::tuple&t) { + lazy_reset_member_tuple(t, std::make_index_sequence()); +} + // 0: safe default, AT is behind a pointer that can be atomically changed, and it doesn't disappear during update_exact // 1: use plain AT without protection // 2: split an interval as 2 atomic_double @@ -585,8 +602,7 @@ class Lazy_rep_n final : auto* p = new typename Base::Indirect(ec()( CGAL::exact( std::get(l) ) ... ) ); this->set_at(p); this->set_ptr(p); - // TODO: apply some reset-like function to each element instead. - l = std::tuple{}; + lazy_reset_member(l); } public: void update_exact() const { @@ -752,7 +768,7 @@ public: this->set_at(p); this->set_ptr(p); // Prune lazy tree - l1_ = L1(); + lazy_reset_member(l1_); } Lazy_rep_with_vector_1(const AC& ac, const EC& /*ec*/, const L1& l1) @@ -802,8 +818,8 @@ public: this->set_at(p); this->set_ptr(p); // Prune lazy tree - l1_ = L1(); - l2_ = L2(); + lazy_reset_member(l1_); + lazy_reset_member(l2_); } Lazy_rep_with_vector_2(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) @@ -852,8 +868,8 @@ public: this->set_at(p); this->set_ptr(p); // Prune lazy tree - l1_ = L1(); - l2_ = L2(); + lazy_reset_member(l1_); + lazy_reset_member(l2_); } Lazy_rep_2_1(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) @@ -905,8 +921,8 @@ public: this->set_at(p); this->set_ptr(p); // Prune lazy tree - l1_ = L1(); - l2_ = L2(); + lazy_reset_member(l1_); + lazy_reset_member(l2_); } Lazy_rep_2_2(const AC& ac, const EC& /*ec*/, const L1& l1, const L2& l2) From 4335b167b7c1119d3c23c7658b8a23ce2b3b2ccc Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 15 Feb 2021 23:50:39 +0100 Subject: [PATCH 088/349] Don't prune Construct_weighted_point_[23] arguments Another thread might try to access them in one of the special cases in Lazy_kernel.h. We could instead restrict the special cases to single-thread, but I think that would be worse. --- Filtered_kernel/include/CGAL/Lazy.h | 46 +++++++++++++--------- Filtered_kernel/include/CGAL/Lazy_kernel.h | 6 +++ 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 10cf0468772..51a0dee6f6e 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -587,7 +587,7 @@ public: }; -template +template class Lazy_rep_n final : public Lazy_rep< AT, ET, E2A >, private EC { @@ -602,7 +602,8 @@ class Lazy_rep_n final : auto* p = new typename Base::Indirect(ec()( CGAL::exact( std::get(l) ) ... ) ); this->set_at(p); this->set_ptr(p); - lazy_reset_member(l); + if(!noprune || is_currently_single_threaded()) + lazy_reset_member(l); } public: void update_exact() const { @@ -1117,7 +1118,7 @@ struct Lazy_construction_nt { CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); Protect_FPU_rounding P; try { - return new Lazy_rep_n, L... >(ac, ec, l...); + return new Lazy_rep_n, false, L... >(ac, ec, l...); } catch (Uncertain_conversion_exception&) { CGAL_BRANCH_PROFILER_BRANCH(tmp); Protect_FPU_rounding P2(CGAL_FE_TONEAREST); @@ -1408,8 +1409,8 @@ public: typedef Lazy, std::pair, E2A> Lazy_pair; Lazy_pair lv(new Lazy_rep_2_2(ac, ec, l1, l2)); // lv->approx() is a std::pair; - r1 = R1(Handle_1(new Lazy_rep_n >, First >, E2A, Lazy_pair>(First >(), First >(), lv))); - r2 = R2(Handle_2(new Lazy_rep_n >, Second >, E2A, Lazy_pair>(Second >(), Second >(), lv))); + r1 = R1(Handle_1(new Lazy_rep_n >, First >, E2A, false, Lazy_pair>(First >(), First >(), lv))); + r2 = R2(Handle_2(new Lazy_rep_n >, Second >, E2A, false, Lazy_pair>(Second >(), Second >(), lv))); } catch (Uncertain_conversion_exception&) { CGAL_BRANCH_PROFILER_BRANCH(tmp); Protect_FPU_rounding P2(CGAL_FE_TONEAREST); @@ -1456,7 +1457,7 @@ public: // FIXME : I'm not sure how this work... #define CGAL_Kernel_obj(X) if (object_cast(& (lv.approx()[i]))) { \ *it++ = make_object(typename LK::X(new Lazy_rep_n, \ - Ith, E2A, Lazy_vector> \ + Ith, E2A, false, Lazy_vector> \ (Ith(i), Ith(i), lv))); \ continue; \ } @@ -1527,14 +1528,14 @@ public: CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); Protect_FPU_rounding P; try { - Lazy_object lo(new Lazy_rep_n(ac, ec, l1)); + Lazy_object lo(new Lazy_rep_n(ac, ec, l1)); if(lo.approx().is_empty()) return Object(); #define CGAL_Kernel_obj(X) \ if (object_cast(& (lo.approx()))) { \ - typedef Lazy_rep_n< typename AK::X, typename EK::X, Object_cast, Object_cast, E2A, Lazy_object> Lcr; \ + typedef Lazy_rep_n< typename AK::X, typename EK::X, Object_cast, Object_cast, E2A, false, Lazy_object> Lcr; \ Lcr * lcr = new Lcr(Object_cast(), Object_cast(), lo); \ return make_object(typename LK::X(lcr)); \ } @@ -1560,14 +1561,14 @@ public: CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); Protect_FPU_rounding P; try { - Lazy_object lo(new Lazy_rep_n(ac, ec, l1, l2)); + Lazy_object lo(new Lazy_rep_n(ac, ec, l1, l2)); if(lo.approx().is_empty()) return Object(); #define CGAL_Kernel_obj(X) \ if (object_cast(& (lo.approx()))) { \ - typedef Lazy_rep_n, Object_cast, E2A, Lazy_object> Lcr; \ + typedef Lazy_rep_n, Object_cast, E2A, false, Lazy_object> Lcr; \ Lcr * lcr = new Lcr(Object_cast(), Object_cast(), lo); \ return make_object(typename LK::X(lcr)); \ } @@ -1584,7 +1585,7 @@ public: V.resize(v_ptr->size()); \ for (unsigned int i = 0; i < v_ptr->size(); i++) { \ V[i] = typename LK::X(new Lazy_rep_n, \ - Ith_for_intersection, E2A, Lazy_object> \ + Ith_for_intersection, E2A, false, Lazy_object> \ (Ith_for_intersection(i), Ith_for_intersection(i), lo)); \ } \ return make_object(V); \ @@ -1614,14 +1615,14 @@ CGAL_Kernel_obj(Point_3) CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); Protect_FPU_rounding P; try { - Lazy_object lo(new Lazy_rep_n(ac, ec, l1, l2, l3)); + Lazy_object lo(new Lazy_rep_n(ac, ec, l1, l2, l3)); if(lo.approx().is_empty()) return Object(); #define CGAL_Kernel_obj(X) \ if (object_cast(& (lo.approx()))) { \ - typedef Lazy_rep_n, Object_cast, E2A, Lazy_object> Lcr; \ + typedef Lazy_rep_n, Object_cast, E2A, false, Lazy_object> Lcr; \ Lcr * lcr = new Lcr(Object_cast(), Object_cast(), lo); \ return make_object(typename LK::X(lcr)); \ } @@ -1692,7 +1693,7 @@ struct Fill_lazy_variant_visitor_2 : boost::static_visitor<> { typedef typename Type_mapper::type EKT; typedef typename Type_mapper::type LKT; - typedef Lazy_rep_n, Variant_cast, typename LK::E2A, Origin> Lcr; + typedef Lazy_rep_n, Variant_cast, typename LK::E2A, false, Origin> Lcr; Lcr * lcr = new Lcr(Variant_cast(), Variant_cast(), *o); *r = LKT(lcr); @@ -1708,7 +1709,7 @@ struct Fill_lazy_variant_visitor_2 : boost::static_visitor<> { V.resize(t.size()); for (unsigned int i = 0; i < t.size(); i++) { V[i] = LKT(new Lazy_rep_n, - Ith_for_intersection, typename LK::E2A, Origin> + Ith_for_intersection, typename LK::E2A, false, Origin> (Ith_for_intersection(i), Ith_for_intersection(i), *o)); } @@ -1788,7 +1789,7 @@ struct Lazy_construction_variant { Protect_FPU_rounding P; try { - Lazy lazy(new Lazy_rep_n(AC(), EC(), l1, l2)); + Lazy lazy(new Lazy_rep_n(AC(), EC(), l1, l2)); // the approximate result requires the trait with types from the AK AT approx_v = lazy.approx(); @@ -1837,7 +1838,7 @@ struct Lazy_construction_variant { CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); Protect_FPU_rounding P; try { - Lazy lazy(new Lazy_rep_n(AC(), EC(), l1, l2, l3)); + Lazy lazy(new Lazy_rep_n(AC(), EC(), l1, l2, l3)); // the approximate result requires the trait with types from the AK AT approx_v = lazy.approx(); @@ -1876,6 +1877,9 @@ template::value && internal::has_result_type::value > struct Lazy_construction; +template struct Disable_lazy_pruning { static const bool value = false; }; +template struct Disable_lazy_pruning { static const bool value = true; }; +template struct Disable_lazy_pruning { static const bool value = true; }; // we have a result type, low effort template @@ -1893,6 +1897,8 @@ struct Lazy_construction { typedef typename Type_mapper::type result_type; + static const bool noprune = Disable_lazy_pruning::value; + CGAL_NO_UNIQUE_ADDRESS AC ac; CGAL_NO_UNIQUE_ADDRESS EC ec; @@ -1904,7 +1910,7 @@ struct Lazy_construction { CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); \ Protect_FPU_rounding P; \ try { \ - return result_type( Handle(new Lazy_rep_n(ac, ec, BOOST_PP_ENUM_PARAMS(n, l)))); \ + return result_type( Handle(new Lazy_rep_n(ac, ec, BOOST_PP_ENUM_PARAMS(n, l)))); \ } catch (Uncertain_conversion_exception&) { \ CGAL_BRANCH_PROFILER_BRANCH(tmp); \ Protect_FPU_rounding P2(CGAL_FE_TONEAREST); \ @@ -1943,6 +1949,8 @@ struct Lazy_construction // you are on your own }; + static const bool noprune = Disable_lazy_pruning::value; + CGAL_NO_UNIQUE_ADDRESS AC ac; CGAL_NO_UNIQUE_ADDRESS EC ec; @@ -1971,7 +1979,7 @@ struct result { \ CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); \ Protect_FPU_rounding P; \ try { \ - return result_type( Handle(new Lazy_rep_n(ac, ec, BOOST_PP_ENUM_PARAMS(n, l)))); \ + return result_type( Handle(new Lazy_rep_n(ac, ec, BOOST_PP_ENUM_PARAMS(n, l)))); \ } catch (Uncertain_conversion_exception&) { \ CGAL_BRANCH_PROFILER_BRANCH(tmp); \ Protect_FPU_rounding P2(CGAL_FE_TONEAREST); \ diff --git a/Filtered_kernel/include/CGAL/Lazy_kernel.h b/Filtered_kernel/include/CGAL/Lazy_kernel.h index 2b9fecfe436..5ceff094b05 100644 --- a/Filtered_kernel/include/CGAL/Lazy_kernel.h +++ b/Filtered_kernel/include/CGAL/Lazy_kernel.h @@ -321,6 +321,7 @@ public: typename Approximate_kernel::Construct_weighted_point_2, typename Exact_kernel::Construct_weighted_point_2, E2A_, + true, Return_base_tag, Point_2, FT @@ -352,6 +353,7 @@ public: typename Approximate_kernel::Construct_weighted_point_3, typename Exact_kernel::Construct_weighted_point_3, E2A_, + true, Return_base_tag, Point_3, FT @@ -389,6 +391,7 @@ public: typename Approximate_kernel::Construct_weighted_point_2, typename Exact_kernel::Construct_weighted_point_2, E2A_, + true, Return_base_tag, Point_2, FT @@ -399,6 +402,7 @@ public: typename Approximate_kernel::Construct_weighted_point_2, typename Exact_kernel::Construct_weighted_point_2, E2A_, + true, Return_base_tag, Point_2, int @@ -441,6 +445,7 @@ public: typename Approximate_kernel::Construct_weighted_point_3, typename Exact_kernel::Construct_weighted_point_3, E2A_, + true, Return_base_tag, Point_3, FT @@ -451,6 +456,7 @@ public: typename Approximate_kernel::Construct_weighted_point_3, typename Exact_kernel::Construct_weighted_point_3, E2A_, + true, Return_base_tag, Point_3, int From 62e6c410964085a76e7efc99a316837f958c4755 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Tue, 16 Feb 2021 00:01:30 +0100 Subject: [PATCH 089/349] Minor optimization for Lazy_kernel if a dynamic_cast succeeded, don't try again with a different type. --- Filtered_kernel/include/CGAL/Lazy_kernel.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy_kernel.h b/Filtered_kernel/include/CGAL/Lazy_kernel.h index 5ceff094b05..d9b00aa5a85 100644 --- a/Filtered_kernel/include/CGAL/Lazy_kernel.h +++ b/Filtered_kernel/include/CGAL/Lazy_kernel.h @@ -329,8 +329,9 @@ public: LR * lr = dynamic_cast(p.ptr()); + // Another thread could reset lr->l between the next 2 lines, so we disable reset for Construct_weighted_point_2 in MT-mode. + // We could also always disable reset for Construct_weighted_point_2 and return lr->l here even if update_exact has run. if(lr && (! lr->et)){ - // FIXME: this is not thread-safe at all, some other thread could update_exact and clear l between the 2 lines. Same for the following functors. return std::get<2>(lr->l); } return BaseClass().compute_weight_2_object()(p); @@ -409,8 +410,9 @@ public: > LRint; LR * lr = dynamic_cast(p.ptr()); - if(lr && (! lr->et)){ - return std::get<1>(lr->l); + if(lr){ + if(! lr->et) + return std::get<1>(lr->l); } else { LRint* lrint = dynamic_cast(p.ptr()); if(lrint && (! lrint->et)){ @@ -464,8 +466,9 @@ public: LR * lr = dynamic_cast(p.ptr()); - if(lr && (! lr->et)){ - return std::get<1>(lr->l); + if(lr){ + if(! lr->et) + return std::get<1>(lr->l); }else{ LRint* lrint = dynamic_cast(p.ptr()); if(lrint && (! lrint->et)){ From 005da847faca9361112e64d8e9af5a9cae94c9ac Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Tue, 16 Feb 2021 20:56:22 +0100 Subject: [PATCH 090/349] Use is_lazy instead of looking at private et. --- Filtered_kernel/include/CGAL/Lazy_kernel.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy_kernel.h b/Filtered_kernel/include/CGAL/Lazy_kernel.h index d9b00aa5a85..dde86cccd48 100644 --- a/Filtered_kernel/include/CGAL/Lazy_kernel.h +++ b/Filtered_kernel/include/CGAL/Lazy_kernel.h @@ -331,7 +331,7 @@ public: LR * lr = dynamic_cast(p.ptr()); // Another thread could reset lr->l between the next 2 lines, so we disable reset for Construct_weighted_point_2 in MT-mode. // We could also always disable reset for Construct_weighted_point_2 and return lr->l here even if update_exact has run. - if(lr && (! lr->et)){ + if(lr && lr->is_lazy()){ return std::get<2>(lr->l); } return BaseClass().compute_weight_2_object()(p); @@ -362,7 +362,7 @@ public: LR * lr = dynamic_cast(p.ptr()); - if(lr && (! lr->et)){ + if(lr && lr->is_lazy()){ return std::get<2>(lr->l); } return BaseClass().compute_weight_3_object()(p); @@ -411,11 +411,11 @@ public: LR * lr = dynamic_cast(p.ptr()); if(lr){ - if(! lr->et) + if(lr->is_lazy()) return std::get<1>(lr->l); } else { LRint* lrint = dynamic_cast(p.ptr()); - if(lrint && (! lrint->et)){ + if(lrint && lrint->is_lazy()){ return std::get<1>(lrint->l); } } @@ -467,11 +467,11 @@ public: LR * lr = dynamic_cast(p.ptr()); if(lr){ - if(! lr->et) + if(lr->is_lazy()) return std::get<1>(lr->l); }else{ LRint* lrint = dynamic_cast(p.ptr()); - if(lrint && (! lrint->et)){ + if(lrint && lrint->is_lazy()){ return std::get<1>(lrint->l); } } From 612037fb1221311af592aa93418ad51f2c7c35c2 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Tue, 16 Feb 2021 21:16:59 +0100 Subject: [PATCH 091/349] Missed one occurence in a search&replace --- STL_Extension/include/CGAL/Handle_for.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STL_Extension/include/CGAL/Handle_for.h b/STL_Extension/include/CGAL/Handle_for.h index e76246ef905..6c28d4136a2 100644 --- a/STL_Extension/include/CGAL/Handle_for.h +++ b/STL_Extension/include/CGAL/Handle_for.h @@ -92,7 +92,7 @@ public: Handle_for(T1 && t1, T2 && t2, Args && ... args) { pointer p = allocator.allocate(1); - ptr_ = new (&(p->t)) RefCounted(std::forward(t1), std::forward(t2), std::forward(args)...); + ptr_ = new (p) RefCounted(std::forward(t1), std::forward(t2), std::forward(args)...); } Handle_for(const Handle_for& h) noexcept From 52b07799b44ae922c6c01ab7e805c9bcbb9a9cfa Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 17 Feb 2021 00:25:16 +0100 Subject: [PATCH 092/349] Bug fixing --- .../CGAL/Test/_test_algebraic_structure.h | 1 + Filtered_kernel/include/CGAL/Lazy.h | 14 ++-- Number_types/include/CGAL/Lazy_exact_nt.h | 5 +- STL_Extension/include/CGAL/Handle.h | 64 ++++++++++--------- 4 files changed, 47 insertions(+), 37 deletions(-) diff --git a/Algebraic_foundations/include/CGAL/Test/_test_algebraic_structure.h b/Algebraic_foundations/include/CGAL/Test/_test_algebraic_structure.h index db74015c675..5abb39fff25 100644 --- a/Algebraic_foundations/include/CGAL/Test/_test_algebraic_structure.h +++ b/Algebraic_foundations/include/CGAL/Test/_test_algebraic_structure.h @@ -338,6 +338,7 @@ void test_algebraic_structure_intern( const CGAL::Field_tag& ) { test_algebraic_structure_intern< AS >( CGAL::Integral_domain_tag()); AS a(1); AS b(3); + AS& b_ref = b; b = b_ref; // to exercise self-copy AS c = a / b; (void)c; // avoid warnings for unused variables diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 51a0dee6f6e..b9f119d3687 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -316,8 +316,8 @@ public: // We could take the lack of _REENTRANT on that platform as forcing CGAL_HAS_NO_THREADS static_assert(false, "Please pass -pthread to the compiler"); #endif - // The test is unnecessary, only use it if benchmark says so - //if (ptr_.load(std::memory_order_relaxed) == &at_orig) + // The test is unnecessary, only use it if benchmark says so, or in order to avoid calling Lazy_exact_Ex_Cst::update_exact() (which used to contain an assertion) + //if (is_lazy()) std::call_once(once, [this](){this->update_exact();}); return static_cast*>(ptr_.load(std::memory_order_relaxed))->et(); // call_once already synchronized memory } @@ -431,11 +431,11 @@ public: const ET & exact() const { #ifdef CGAL_HAS_THREADS - // The test is unnecessary, only use it if benchmark says so - //if (ptr_.load(std::memory_order_relaxed) == nullptr) + // The test is unnecessary, only use it if benchmark says so, or in order to avoid calling Lazy_exact_Ex_Cst::update_exact() (which used to contain an assertion) + //if (is_lazy()) std::call_once(once, [this](){this->update_exact();}); #else - if (ptr_.load(std::memory_order_relaxed) == nullptr) + if (is_lazy()) this->update_exact(); #endif return *ptr_.load(std::memory_order_relaxed); // call_once already synchronized memory @@ -530,8 +530,8 @@ public: const ET & exact() const { - // The test is unnecessary, only use it if benchmark says so - //if (ptr_.load(std::memory_order_relaxed) == nullptr) + // The test is unnecessary, only use it if benchmark says so, or in order to avoid calling Lazy_exact_Ex_Cst::update_exact() (which used to contain an assertion) + //if (is_lazy()) std::call_once(once, [this](){this->update_exact();}); return *ptr_.load(std::memory_order_relaxed); // call_once already synchronized memory } diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index 5f7a88485d9..3d62ac6a779 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -168,7 +168,10 @@ struct Lazy_exact_Ex_Cst final : public Lazy_exact_nt_rep : Lazy_exact_nt_rep(CGAL_NTS to_interval(e), std::forward(e)) { } - void update_exact() const { CGAL_error(); } + void update_exact() const { + // Currently we do not check is_lazy() before calling call_once, so this is called. + // CGAL_error(); + } }; // Construction from a Lazy_exact_nt (which keeps the lazyness). diff --git a/STL_Extension/include/CGAL/Handle.h b/STL_Extension/include/CGAL/Handle.h index 5779a99ec64..9fa41830523 100644 --- a/STL_Extension/include/CGAL/Handle.h +++ b/STL_Extension/include/CGAL/Handle.h @@ -61,7 +61,7 @@ class Handle { CGAL_precondition( x.PTR != static_cast(0) ); x.incref(); - reset(); + if(PTR) decref(); // not reset() in case this==&x PTR = x.PTR; return *this; } @@ -75,33 +75,7 @@ class Handle friend void swap(Handle& a, Handle& b) noexcept { std::swap(a.PTR, b.PTR); } - void reset() - { - if (PTR) - { - if (is_currently_single_threaded()) { - auto c = PTR->count.load(std::memory_order_relaxed); - if (c == 1) - delete PTR; - else - PTR->count.store(c - 1, std::memory_order_relaxed); - PTR = 0; - } else { - // TSAN does not support fences :-( -#if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) - if (PTR->count.load(std::memory_order_relaxed) == 1 - || PTR->count.fetch_sub(1, std::memory_order_release) == 1) { - std::atomic_thread_fence(std::memory_order_acquire); -#else - if (PTR->count.fetch_sub(1, std::memory_order_acq_rel) == 1) { -#endif - delete PTR; - } - PTR=0; - } - } - } - + private: void incref() const noexcept { if (is_currently_single_threaded()) { @@ -111,8 +85,40 @@ class Handle } } + void decref() + { + if (is_currently_single_threaded()) { + auto c = PTR->count.load(std::memory_order_relaxed); + if (c == 1) + delete PTR; + else + PTR->count.store(c - 1, std::memory_order_relaxed); + } else { + // TSAN does not support fences :-( +#if !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) + if (PTR->count.load(std::memory_order_relaxed) == 1 + || PTR->count.fetch_sub(1, std::memory_order_release) == 1) { + std::atomic_thread_fence(std::memory_order_acquire); +#else + if (PTR->count.fetch_sub(1, std::memory_order_acq_rel) == 1) { +#endif + delete PTR; + } + } + } + + public: + void reset() + { + if (PTR) + { + decref(); + PTR=0; + } + } + int - refs() const noexcept { return PTR->count; } + refs() const noexcept { return PTR->count.load(std::memory_order_relaxed); } Id_type id() const noexcept { return PTR - static_cast(0); } From 78f7d6917a43ed3438ef7d68401003b90d9fb149 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 17 Feb 2021 22:39:47 +0100 Subject: [PATCH 093/349] missing declarations --- Filtered_kernel/include/CGAL/Lazy.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index b9f119d3687..4e7ce3a7eeb 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -249,6 +249,10 @@ templatestruct Lazy_rep_selector { static constexpr int value = 0; }; # ifdef CGAL_USE_SSE2 templatestruct Lazy_rep_selector> { static constexpr int value = 1; }; templatestruct Lazy_rep_selector,N>> { static constexpr int value = 1; }; + // Need some declarations, including Simple_cartesian.h would also be possible. + templatestruct Simple_cartesian; + templateclass Point_2; + templateclass Point_3; templatestruct Lazy_rep_selector>>> { static constexpr int value = 1; }; templatestruct Lazy_rep_selector>>> { static constexpr int value = 1; }; # else From cdbd4c7fd2032dcb477308366ba24b139f8cecbb Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 17 Feb 2021 23:25:52 +0100 Subject: [PATCH 094/349] Root_of_traits_specializations --- .../CGAL/Root_of_traits_specializations.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Number_types/include/CGAL/Root_of_traits_specializations.h b/Number_types/include/CGAL/Root_of_traits_specializations.h index 709d6936b64..b07aa7b3478 100644 --- a/Number_types/include/CGAL/Root_of_traits_specializations.h +++ b/Number_types/include/CGAL/Root_of_traits_specializations.h @@ -52,21 +52,26 @@ struct Lazy_exact_ro2 void update_exact() const { + typedef typename Base::Indirect I; + I* pet; if (old_rep) - this->et = new RO2(make_root_of_2(op1.exact(), op2.exact(), - op3.exact(), smaller)); + pet = new I(make_root_of_2(op1.exact(), op2.exact(), + op3.exact(), smaller)); else - this->et = new RO2(make_root_of_2(op1.exact(), op2.exact(), - op3.exact())); + pet = new I(make_root_of_2(op1.exact(), op2.exact(), + op3.exact())); if (!this->approx().is_point()) - this->at = to_interval(*(this->et)); + this->set_at(pet); + this->set_ptr(pet); this->prune_dag(); } void prune_dag() const { - op1 = op2 = op3 = Lazy_exact_nt(); + op1.reset(); + op2.reset(); + op3.reset(); } }; From 2941c925fdb16676f84f62b92e188c36b369c717 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 17 Feb 2021 23:26:29 +0100 Subject: [PATCH 095/349] AT_wrap needs to be virtual :-( --- Filtered_kernel/include/CGAL/Lazy.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 4e7ce3a7eeb..5a06225dffe 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -269,6 +269,7 @@ struct AT_wrap { AT_wrap(AT const& a):at_(a){} AT_wrap(AT&& a):at_(std::move(a)){} AT const& at()const{return at_;} + virtual ~AT_wrap()=default; // TODO: check how costly this is. }; // TODO: avoid initializing AT for nothing From b7d2119c96d82adacf462e40c9d4649e37bd907f Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 17 Feb 2021 23:35:29 +0100 Subject: [PATCH 096/349] NewKernel_d --- NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h b/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h index 56ecd5df953..b9513de350d 100644 --- a/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h +++ b/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h @@ -109,6 +109,7 @@ template, private EC { + typedef Lazy_rep< AT, ET, E2A > Base; // `default_construct()` is the same as `T{}`. But, this is a // workaround to a MSVC-2015 bug (fixed in MSVC-2017): its parser // seemed confused by `T{}` somewhere below. @@ -129,9 +130,10 @@ class Lazy_rep_XXX : const EC& ec() const { return *this; } template void update_exact_helper(Lazy_internal::typelist) const { - this->et = new ET(ec()( CGAL::exact( Lazy_internal::do_extract(T{},l) ) ... ) ); - this->at = E2A()(*(this->et)); - l = LL(); // There should be a nicer way to clear. Destruction for instance. With this->et as a witness of whether l has already been destructed. + auto* p = new typename Base::Indirect(ec()( CGAL::exact( Lazy_internal::do_extract(T{},l) ) ... ) ); + this->set_at(p); + this->set_ptr(p); + lazy_reset_member(l); } public: void update_exact() const { From 03e67005d026efc0d7d63961067a4ede2db2dc2f Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 18 Feb 2021 00:01:42 +0100 Subject: [PATCH 097/349] Actually no need for virtual --- Filtered_kernel/include/CGAL/Lazy.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 5a06225dffe..28233b28f65 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -269,7 +269,6 @@ struct AT_wrap { AT_wrap(AT const& a):at_(a){} AT_wrap(AT&& a):at_(std::move(a)){} AT const& at()const{return at_;} - virtual ~AT_wrap()=default; // TODO: check how costly this is. }; // TODO: avoid initializing AT for nothing @@ -379,11 +378,11 @@ public: auto* p = ptr_.load(std::memory_order_relaxed); if (p != &at_orig) { std::atomic_thread_fence(std::memory_order_acquire); - delete p; + delete static_cast(p); } #else auto* p = ptr_.load(std::memory_order_consume); - if (p != &at_orig) delete p; + if (p != &at_orig) delete static_cast(p); #endif } }; From 2b7b07dcbc2bac72f31147c007b00d1f52b1c3a4 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 19 Feb 2021 11:10:09 +0100 Subject: [PATCH 098/349] Fix Lazy_rep_0::update_exact --- Filtered_kernel/include/CGAL/Lazy.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index a4021f39639..e02f0e9f9d5 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -725,6 +725,13 @@ public: void update_exact() const { +#ifdef CGAL_HAS_THREADS + // Unless we add is_lazy before call_once in Lazy_rep. This test is + // necessary because this class can be used either for default + // construction, or to store a non-lazy exact value, and only the first one + // should have a non-empty update_exact. + if(!this->is_lazy()) return; +#endif auto* p = new typename Base::Indirect(); this->set_ptr(p); } @@ -732,6 +739,8 @@ public: Lazy_rep_0() : Lazy_rep() {} + // TODO: the case where the exact value is provided at construction should + // actually use a different class from the lazy default construction. template Lazy_rep_0(A&& a, E&& e) : Lazy_rep(std::forward(a), std::forward(e)) {} From 8abb28530209cefac209be8db3811afd5709cdc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 19 Feb 2021 11:13:16 +0100 Subject: [PATCH 099/349] post merge/cgal update fixes --- .../CGAL/Polygon_mesh_processing/distance.h | 24 +++++++++---------- ...traversal_traits_with_Hausdorff_distance.h | 4 ++++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 1b42bf08a05..577a18d9844 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1652,13 +1652,13 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, typedef typename GetVertexPointMap::const_type Vpm1; typedef typename GetVertexPointMap::const_type Vpm2; - using boost::choose_param; - using boost::get_param; + using parameters::choose_parameter; + using parameters::get_parameter; - Vpm1 vpm1 = choose_param(get_param(np1, internal_np::vertex_point), - get_const_property_map(vertex_point, tm1)); - Vpm2 vpm2 = choose_param(get_param(np2, internal_np::vertex_point), - get_const_property_map(vertex_point, tm2)); + Vpm1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, tm1)); + Vpm2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, tm2)); return internal::bounded_error_Hausdorff_impl(tm1, tm2, error_bound, vpm1, vpm2); } @@ -1742,13 +1742,13 @@ double bounded_error_Hausdorff_distance_naive( const TriangleMesh& tm1, typedef typename GetVertexPointMap::const_type Vpm1; typedef typename GetVertexPointMap::const_type Vpm2; - using boost::choose_param; - using boost::get_param; + using parameters::choose_parameter; + using parameters::get_parameter; - Vpm1 vpm1 = choose_param(get_param(np1, internal_np::vertex_point), - get_const_property_map(vertex_point, tm1)); - Vpm2 vpm2 = choose_param(get_param(np2, internal_np::vertex_point), - get_const_property_map(vertex_point, tm2)); + Vpm1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, tm1)); + Vpm2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, tm2)); return internal::bounded_error_Hausdorff_naive_impl(tm1, tm2, error_bound, vpm1, vpm2); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index a1d7e6ab1a2..5e6389dc79e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -24,6 +24,10 @@ #define CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_HAUSDORFF_DISTANCE #include +#include +#include +#include +#include namespace CGAL { From 5d0d98f35ebd158f0a5c5faf8ff52bcb6b8d5c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 19 Feb 2021 11:13:35 +0100 Subject: [PATCH 100/349] add missing parameter not added in 2d4c254362 ? --- .../include/CGAL/Polygon_mesh_processing/distance.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 577a18d9844..b9fb7a7e942 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1463,6 +1463,7 @@ double bounded_error_Hausdorff_impl( triangle_bounds.second, std::numeric_limits::infinity(), std::numeric_limits::infinity(), + std::numeric_limits::infinity(), std::numeric_limits::infinity() ); tm2_tree.traversal_with_priority(sub_triangles[i], traversal_traits_tm2); From 0d698f1bfcc484e37bb7db9e00aaba255e255cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 19 Feb 2021 13:13:42 +0100 Subject: [PATCH 101/349] update header --- ...AABB_traversal_traits_with_Hausdorff_distance.h | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 5e6389dc79e..8bf9c7865f4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -2,27 +2,19 @@ // All rights reserved. // // This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ -// SPDX-License-Identifier: GPL-3.0+ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // // Author(s) : Sebastien Loriot, Martin Skrodzki -// #ifndef CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_HAUSDORFF_DISTANCE #define CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_HAUSDORFF_DISTANCE +#include + #include #include #include From 35387df8060ca5b6746a8617224ab8d699f6c28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 19 Feb 2021 13:37:28 +0100 Subject: [PATCH 102/349] do not document all overloads --- .../CGAL/Polygon_mesh_processing/distance.h | 41 +------------------ 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index b9fb7a7e942..0b39d9c48a7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1664,30 +1664,7 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, return internal::bounded_error_Hausdorff_impl(tm1, tm2, error_bound, vpm1, vpm2); } -/** - * \ingroup PMP_distance_grp - * returns an estimate on the Hausdorff distance between `tm1` and `tm2` that - * is at most `error_bound` away from the actual Hausdorff distance between - * the two given meshes. - * @tparam Concurrency_tag enables sequential versus parallel algorithm. - * Possible values are `Sequential_tag` - * and `Parallel_tag`. Currently, parall computation is - * not implemented, though. - * @tparam TriangleMesh a model of the concept `FaceListGraph` - * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" - * @param tm1 a triangle mesh - * @param tm2 a second triangle mesh - * @param error_bound Maximum bound by which the Hausdorff distance estimate is - * allowed to deviate from the actual Hausdorff distance. - * @param np1 an optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below - * \cgalNamedParamsBegin - * \cgalParamBegin{vertex_point_map} the property map with the points - * associated to the vertices of `tm`. If this parameter is omitted, - * an internal property map for `CGAL::vertex_point_t` - * must be available for `TriangleMesh`. - * \cgalParamEnd - * \cgalNamedParamsEnd - */ + template< class Concurrency_tag, class TriangleMesh, class NamedParameters1> @@ -1699,22 +1676,6 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, return bounded_error_Hausdorff_distance(tm1, tm2, error_bound, np1, parameters::all_default()); } -/** - * \ingroup PMP_distance_grp - * returns an estimate on the Hausdorff distance between `tm1` and `tm2` that - * is at most `error_bound` away from the actual Hausdorff distance between - * the two given meshes. - * @tparam Concurrency_tag enables sequential versus parallel algorithm. - * Possible values are `Sequential_tag` - * and `Parallel_tag`. Currently, parall computation is - * not implemented, though. - * @tparam TriangleMesh a model of the concept `FaceListGraph` - * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" - * @param tm1 a triangle mesh - * @param tm2 a second triangle mesh - * @param error_bound Maximum bound by which the Hausdorff distance estimate is - * allowed to deviate from the actual Hausdorff distance. - */ template< class Concurrency_tag, class TriangleMesh> double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, From 6e4b5ead81c06d006cbe37bb12bed3d27d62575e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 19 Feb 2021 13:42:01 +0100 Subject: [PATCH 103/349] use new macros --- .../CGAL/Polygon_mesh_processing/distance.h | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 0b39d9c48a7..58fe1360d4f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1619,22 +1619,26 @@ double bounded_error_Hausdorff_naive_impl( * the two given meshes. * @tparam Concurrency_tag enables sequential versus parallel algorithm. * Possible values are `Sequential_tag` - * and `Parallel_tag`. Currently, parall computation is + * and `Parallel_tag`. Currently, parallel computation is * not implemented, though. * @tparam TriangleMesh a model of the concept `FaceListGraph` - * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" + * @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * @param tm1 a triangle mesh * @param tm2 a second triangle mesh * @param error_bound Maximum bound by which the Hausdorff distance estimate is * allowed to deviate from the actual Hausdorff distance. - * @param np1 an optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below - * @param np2 an optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below + * @param np1 an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below + * @param np2 an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below + * * \cgalNamedParamsBegin - * \cgalParamBegin{vertex_point_map} the property map with the points - * associated to the vertices of `tm`. If this parameter is omitted, - * an internal property map for `CGAL::vertex_point_t` - * must be available for `TriangleMesh`. - * \cgalParamEnd + * \cgalParamNBegin{vertex_point_map} + * \cgalParamDescription{a property map associating points to the vertices of `tm1` and `tm2` (`np1` and `np2`, respectively)} + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * as key type and `%Point_3` as value type} + * \cgalParamDefault{`boost::get(CGAL::vertex_point, tm)`} + * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` + * must be available in `TriangleMesh`.} + * \cgalParamNEnd * \cgalNamedParamsEnd */ template< class Concurrency_tag, From a02cf218336f0a73dbcc51c93a6dd69b7707ea41 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 19 Feb 2021 21:33:41 +0100 Subject: [PATCH 104/349] Disable "unsafe" path with thread sanitizer --- Filtered_kernel/include/CGAL/Lazy.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index e02f0e9f9d5..763d275c049 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -246,7 +246,7 @@ templatevoid lazy_reset_member(std::tuple&t) { // FIXME: CGAL_USE_SSE2 is clearly not the right condition #ifdef CGAL_HAS_THREADS templatestruct Lazy_rep_selector { static constexpr int value = 0; }; -# ifdef CGAL_USE_SSE2 +# if defined CGAL_USE_SSE2 && !defined __SANITIZE_THREAD__ && !__has_feature(thread_sanitizer) templatestruct Lazy_rep_selector> { static constexpr int value = 1; }; templatestruct Lazy_rep_selector,N>> { static constexpr int value = 1; }; // Need some declarations, including Simple_cartesian.h would also be possible. @@ -730,6 +730,7 @@ public: // necessary because this class can be used either for default // construction, or to store a non-lazy exact value, and only the first one // should have a non-empty update_exact. + // An alternative would be to add in the constructors taking an ET: std::call_once(this->once, [](){}); if(!this->is_lazy()) return; #endif auto* p = new typename Base::Indirect(); From 0675a0d55ec2f55a5d6a369fda5f047cf3735270 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 12 Mar 2021 17:00:44 +0100 Subject: [PATCH 105/349] WIP --- .../compare_meshes_example.cpp | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp new file mode 100644 index 00000000000..266bcda23cf --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp @@ -0,0 +1,123 @@ +#include +#include + +#include +#include + +#include +#include + +namespace CGAL{ +namespace Polygon_mesh_processing{ +namespace internal { +template +void diff(const TriangleMesh& m1, const TriangleMesh& m2, bool compute_common = false) +{ + std::map point_id_map; + std::vector m1_vertex_id(num_vertices(m1), -1); + std::vector m2_vertex_id(num_vertices(m2), -1); + + //iterate both meshes to set ids to all points, and set vertex/point_id maps. + std::size_t id =0; + for(auto v : vertices(m1)) + { + Point_3 p = m1->point(v); + auto res = point_id_map.insert(std::make_pair(p, id)); + if(res.second) + id++; + m1_vertex_id[(std::size_t)v]=res.first->second; + } + for(auto v : vertices(m2)) + { + Point_3 p = m2->point(v); + auto res = point_id_map.insert(std::make_pair(p, id)); + if(res.second) + id++; + m2_vertex_id[(std::size_t)v]=res.first->second; + } + + //fill a set with the "faces point-ids" of m1 and then iterate faces of m2 to compare. + std::set > m1_faces; + for(auto f : m1->faces()) + { + std::vector ids; + for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) + { + ids.push_back(m1_vertex_id[(std::size_t)v]); + } + std::sort(ids.begin(), ids.end()); + m1_faces.insert(ids); + } + + std::vector common_faces; + id = 0; + + for(auto f : faces(m2)) + { + std::vector ids; + for(auto v : CGAL::vertices_around_face(halfedge(f, m2), m2)) + { + ids.push_back(m2_vertex_id[(std::size_t)v]); + } + std::sort(ids.begin(), ids.end()); + if(!((m1_faces.find(ids) != m1_faces.end()) ^ compute_common)) + { + common_faces.push_back(f); + } + } +} + +} +template +void compare_meshes(const TriangleMesh& tm1, const TriangleMesh& tm2, + FacePairRange& common, FaceRange tm1_only, FaceRange tm2_only) +{ + + SMesh* m1_over_m2 = diff(m1, m2); + SMesh* m2_over_m1 = diff(m2, m1); + SMesh* common = diff(m2, m1, true); + + Scene_surface_mesh_item* m1_over_m2_item = new Scene_surface_mesh_item(m1_over_m2); + m1_over_m2_item->setColor(QColor(Qt::blue)); + m1_over_m2_item->setName(QString("%2 - %1").arg(m1_item->name()).arg(m2_item->name())); + CGAL::Three::Three::scene()->addItem(m1_over_m2_item); + Scene_surface_mesh_item* m2_over_m1_item = new Scene_surface_mesh_item(m2_over_m1); + m2_over_m1_item->setColor(QColor(Qt::red)); + m2_over_m1_item->setName(QString("%1 - %2").arg(m1_item->name()).arg(m2_item->name())); + CGAL::Three::Three::scene()->addItem(m2_over_m1_item); + Scene_surface_mesh_item* common_item = new Scene_surface_mesh_item(common); + common_item->setColor(QColor(Qt::green)); + CGAL::Three::Three::scene()->addItem(common_item); + common_item->setName(QString("%1 && %2").arg(m1_item->name()).arg(m2_item->name())); +} + +} +} +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; + +typedef K::Point_3 Point; + +typedef CGAL::Surface_mesh Surface_mesh; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; +namespace PMP = CGAL::Polygon_mesh_processing; + +int main(int argc, char* argv[]) +{ + const char* filename1 = (argc > 1) ? argv[1] : "data/eight.off"; + const char* filename2 = (argc > 2) ? argv[2] : "data/eight-bis.off"; + + Surface_mesh mesh1, mesh2; + if(!PMP::read_polygon_mesh(filename1, mesh1)) + { + std::cerr << "Invalid input." << std::endl; + return 1; + } + if(!PMP::read_polygon_mesh(filename2, mesh2)) + { + std::cerr << "Invalid input." << std::endl; + return 1; + } + + return 0; +} From 70de7333575c62e4eaf53f3eb47804d63582dbd7 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 13 Mar 2021 01:16:18 +0100 Subject: [PATCH 106/349] New call_once was reverted from gcc-11 This test is unlikely to remain as is anyway... --- Filtered_kernel/include/CGAL/Lazy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 763d275c049..06e916ddd19 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -318,7 +318,7 @@ public: const ET & exact() const { -#if defined(CGAL_HAS_THREADS) && defined(__gnu_linux__) && __GNUC__ < 11 && !defined(_REENTRANT) +#if defined(CGAL_HAS_THREADS) && defined(__gnu_linux__) && !defined(_REENTRANT) // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55394 // -pthread or -lpthread is just needed for linking, but I can't test that here... // We could take the lack of _REENTRANT on that platform as forcing CGAL_HAS_NO_THREADS From 995ae60c897203fe07e3bdac58b822da9bb22729 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sun, 14 Mar 2021 16:41:12 +0100 Subject: [PATCH 107/349] Fix CGAL_LAZY_KERNEL_DEBUG [skip ci] --- Filtered_kernel/include/CGAL/Lazy.h | 48 +++++++++++++++++++---------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 06e916ddd19..4a3e175f5d1 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -316,6 +316,12 @@ public: return ptr_.load(std::memory_order_consume)->at(); } + const ET & exact_unsafe() const + { + CGAL_assertion(!is_lazy()); + return static_cast*>(ptr_.load(std::memory_order_relaxed))->et(); + } + const ET & exact() const { #if defined(CGAL_HAS_THREADS) && defined(__gnu_linux__) && !defined(_REENTRANT) @@ -327,7 +333,7 @@ public: // The test is unnecessary, only use it if benchmark says so, or in order to avoid calling Lazy_exact_Ex_Cst::update_exact() (which used to contain an assertion) //if (is_lazy()) std::call_once(once, [this](){this->update_exact();}); - return static_cast*>(ptr_.load(std::memory_order_relaxed))->et(); // call_once already synchronized memory + return exact_unsafe(); // call_once already synchronized memory } template @@ -354,20 +360,20 @@ public: os << " "; } os << "Approximation: "; - print_at(os, at); + print_at(os, approx()); os << std::endl; if(! is_lazy()){ for(int i = 0; i < level; i++){ os << " "; } os << "Exact: "; - print_at(os, *et); + print_at(os, exact_unsafe()); os << std::endl; #ifdef CGAL_LAZY_KERNEL_DEBUG_SHOW_TYPEID for(int i = 0; i < level; i++){ os << " "; } - os << " (type: " << typeid(*et).name() << ")" << std::endl; + os << " (type: " << typeid(exact_unsafe()).name() << ")" << std::endl; #endif // CGAL_LAZY_KERNEL_DEBUG_SHOW_TYPEID } } @@ -440,6 +446,11 @@ public: } void keep_at(ET*) const { } + const ET & exact_unsafe() const + { + return *ptr_.load(std::memory_order_relaxed); + } + const ET & exact() const { #ifdef CGAL_HAS_THREADS @@ -450,7 +461,7 @@ public: if (is_lazy()) this->update_exact(); #endif - return *ptr_.load(std::memory_order_relaxed); // call_once already synchronized memory + return exact_unsafe(); // call_once already synchronized memory } void set_ptr(ET* p) const { @@ -464,20 +475,20 @@ public: os << " "; } os << "Approximation: "; - print_at(os, at); + print_at(os, approx()); os << std::endl; if(! is_lazy()){ for(int i = 0; i < level; i++){ os << " "; } os << "Exact: "; - print_at(os, *et); + print_at(os, exact_unsafe()); os << std::endl; #ifdef CGAL_LAZY_KERNEL_DEBUG_SHOW_TYPEID for(int i = 0; i < level; i++){ os << " "; } - os << " (type: " << typeid(*et).name() << ")" << std::endl; + os << " (type: " << typeid(exact_unsafe()).name() << ")" << std::endl; #endif // CGAL_LAZY_KERNEL_DEBUG_SHOW_TYPEID } } @@ -540,12 +551,17 @@ public: } void keep_at(ET*) const { } + const ET & exact_unsafe() const + { + return *ptr_.load(std::memory_order_relaxed); + } + const ET & exact() const { // The test is unnecessary, only use it if benchmark says so, or in order to avoid calling Lazy_exact_Ex_Cst::update_exact() (which used to contain an assertion) //if (is_lazy()) std::call_once(once, [this](){this->update_exact();}); - return *ptr_.load(std::memory_order_relaxed); // call_once already synchronized memory + return exact_unsafe(); // call_once already synchronized memory } void set_ptr(ET* p) const { @@ -561,20 +577,20 @@ public: os << " "; } os << "Approximation: "; - print_at(os, at); + print_at(os, approx()); os << std::endl; if(! is_lazy()){ for(int i = 0; i < level; i++){ os << " "; } os << "Exact: "; - print_at(os, *et); + print_at(os, exact_unsafe()); os << std::endl; #ifdef CGAL_LAZY_KERNEL_DEBUG_SHOW_TYPEID for(int i = 0; i < level; i++){ os << " "; } - os << " (type: " << typeid(*et).name() << ")" << std::endl; + os << " (type: " << typeid(exact_unsafe()).name() << ")" << std::endl; #endif // CGAL_LAZY_KERNEL_DEBUG_SHOW_TYPEID } } @@ -643,7 +659,7 @@ class Lazy_rep_n final : } public: void print_dag(std::ostream& os, int level) const { - print_dag_helper(os, level, std::make_index_sequence{}); + print_dag_helper(os, level, std::make_index_sequence{}); } #endif }; @@ -707,7 +723,7 @@ class Lazy_rep_optional_n : public: void print_dag(std::ostream& os, int level) const { - print_dag_helper(os, level, std::make_index_sequence{}); + print_dag_helper(os, level, std::make_index_sequence{}); } #endif }; @@ -869,7 +885,7 @@ public: print_dag(std::ostream& os, int level) const { this->print_at_et(os, level); - os << "A Lazy_rep_with_vector_1 of size " << this->at.size() << std::endl; + os << "A Lazy_rep_with_vector_1 of size " << this->approx().size() << std::endl; if(this->is_lazy()){ CGAL::msg(os, level, "DAG with one child node:"); CGAL::print_dag(l1_, os, level+1); @@ -920,7 +936,7 @@ public: print_dag(std::ostream& os, int level) const { this->print_at_et(os, level); - os << "A Lazy_rep_with_vector_2 of size " << this->at.size() << std::endl; + os << "A Lazy_rep_with_vector_2 of size " << this->approx().size() << std::endl; if(this->is_lazy()){ CGAL::msg(os, level, "DAG with two child nodes:"); CGAL::print_dag(l1_, os, level+1); From 96a88df41b0df75978d96088d86b02a7ceb06b7c Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 16 Mar 2021 16:00:10 +0100 Subject: [PATCH 108/349] Working example. --- .../Polygon_mesh_processing/CMakeLists.txt | 1 + .../compare_meshes_example.cpp | 109 +++++++++++------- 2 files changed, 68 insertions(+), 42 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index f979cf8cad3..991bfddca85 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -90,6 +90,7 @@ create_single_source_cgal_program("locate_example.cpp") create_single_source_cgal_program("orientation_pipeline_example.cpp") #create_single_source_cgal_program( "self_snapping_example.cpp") #create_single_source_cgal_program( "snapping_example.cpp") +create_single_source_cgal_program("compare_meshes_example.cpp") if(OpenMesh_FOUND) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp index 266bcda23cf..05b989e0b29 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp @@ -3,16 +3,33 @@ #include #include +#include +#include #include #include namespace CGAL{ namespace Polygon_mesh_processing{ -namespace internal { -template -void diff(const TriangleMesh& m1, const TriangleMesh& m2, bool compute_common = false) +//todo face_descriptor ça doit etre le facerange::value_type je pense. checker le c++20 de value_type par contre +template +void compare_meshes(const TriangleMesh& m1, const TriangleMesh& m2, + FacePairRange& common, FaceRange& tm1_only, FaceRange& tm2_only, + const NamedParameters1& np1,const NamedParameters2& np2) { + using parameters::choose_parameter; + using parameters::get_parameter; + typedef typename GetVertexPointMap < TriangleMesh, NamedParameters1>::const_type VPMap1; + typedef typename GetVertexPointMap < TriangleMesh, NamedParameters2>::const_type VPMap2; + VPMap1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, m1)); + VPMap2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, m2)); + typedef typename boost::property_traits::value_type Point_3; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + + std::map point_id_map; std::vector m1_vertex_id(num_vertices(m1), -1); std::vector m2_vertex_id(num_vertices(m2), -1); @@ -21,7 +38,7 @@ void diff(const TriangleMesh& m1, const TriangleMesh& m2, bool compute_common = std::size_t id =0; for(auto v : vertices(m1)) { - Point_3 p = m1->point(v); + const Point_3& p = get(vpm1, v); auto res = point_id_map.insert(std::make_pair(p, id)); if(res.second) id++; @@ -29,7 +46,7 @@ void diff(const TriangleMesh& m1, const TriangleMesh& m2, bool compute_common = } for(auto v : vertices(m2)) { - Point_3 p = m2->point(v); + const Point_3& p = get(vpm2, v); auto res = point_id_map.insert(std::make_pair(p, id)); if(res.second) id++; @@ -38,7 +55,7 @@ void diff(const TriangleMesh& m1, const TriangleMesh& m2, bool compute_common = //fill a set with the "faces point-ids" of m1 and then iterate faces of m2 to compare. std::set > m1_faces; - for(auto f : m1->faces()) + for(auto f : faces(m1)) { std::vector ids; for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) @@ -48,10 +65,7 @@ void diff(const TriangleMesh& m1, const TriangleMesh& m2, bool compute_common = std::sort(ids.begin(), ids.end()); m1_faces.insert(ids); } - - std::vector common_faces; - id = 0; - + std::map, face_descriptor> m2_faces_map; for(auto f : faces(m2)) { std::vector ids; @@ -60,39 +74,33 @@ void diff(const TriangleMesh& m1, const TriangleMesh& m2, bool compute_common = ids.push_back(m2_vertex_id[(std::size_t)v]); } std::sort(ids.begin(), ids.end()); - if(!((m1_faces.find(ids) != m1_faces.end()) ^ compute_common)) + m2_faces_map.insert({ids, f}); + if(m1_faces.find(ids) == m1_faces.end()) { + tm2_only.push_back(f); + } + } + + for(auto f : faces(m1)) + { + std::vector ids; + for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) { - common_faces.push_back(f); + ids.push_back(m1_vertex_id[(std::size_t)v]); + } + std::sort(ids.begin(), ids.end()); + auto m2_face_it = m2_faces_map.find(ids); + if(m2_face_it == m2_faces_map.end()) + { + tm1_only.push_back(f); + } + else + { + common.push_back(std::make_pair(f, m2_face_it->second)); } } } - -} -template -void compare_meshes(const TriangleMesh& tm1, const TriangleMesh& tm2, - FacePairRange& common, FaceRange tm1_only, FaceRange tm2_only) -{ - - SMesh* m1_over_m2 = diff(m1, m2); - SMesh* m2_over_m1 = diff(m2, m1); - SMesh* common = diff(m2, m1, true); - - Scene_surface_mesh_item* m1_over_m2_item = new Scene_surface_mesh_item(m1_over_m2); - m1_over_m2_item->setColor(QColor(Qt::blue)); - m1_over_m2_item->setName(QString("%2 - %1").arg(m1_item->name()).arg(m2_item->name())); - CGAL::Three::Three::scene()->addItem(m1_over_m2_item); - Scene_surface_mesh_item* m2_over_m1_item = new Scene_surface_mesh_item(m2_over_m1); - m2_over_m1_item->setColor(QColor(Qt::red)); - m2_over_m1_item->setName(QString("%1 - %2").arg(m1_item->name()).arg(m2_item->name())); - CGAL::Three::Three::scene()->addItem(m2_over_m1_item); - Scene_surface_mesh_item* common_item = new Scene_surface_mesh_item(common); - common_item->setColor(QColor(Qt::green)); - CGAL::Three::Three::scene()->addItem(common_item); - common_item->setName(QString("%1 && %2").arg(m1_item->name()).arg(m2_item->name())); -} - -} -} +}//pmp +}//cgal typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_3 Point; @@ -104,8 +112,8 @@ namespace PMP = CGAL::Polygon_mesh_processing; int main(int argc, char* argv[]) { - const char* filename1 = (argc > 1) ? argv[1] : "data/eight.off"; - const char* filename2 = (argc > 2) ? argv[2] : "data/eight-bis.off"; + const char* filename1 = (argc > 1) ? argv[1] : "data/tet.off"; + const char* filename2 = (argc > 2) ? argv[2] : "data/tet-bis.off"; Surface_mesh mesh1, mesh2; if(!PMP::read_polygon_mesh(filename1, mesh1)) @@ -118,6 +126,23 @@ int main(int argc, char* argv[]) std::cerr << "Invalid input." << std::endl; return 1; } - + std::vector > common; + std::vector m1_only, m2_only; + PMP::compare_meshes(mesh1, mesh2, common, m1_only, m2_only, CGAL::parameters::all_default(), CGAL::parameters::all_default()); + std::cout<<"Faces only in m1 : "< Date: Mon, 22 Mar 2021 14:02:18 +0100 Subject: [PATCH 109/349] doc + example + tests --- .../compare_meshes_example.cpp | 92 ------------- .../Polygon_mesh_processing/data/tet-bis.off | 35 +++++ .../Polygon_mesh_processing/data/tet.off | 35 +++++ .../CGAL/Polygon_mesh_processing/measure.h | 121 ++++++++++++++++++ .../data/cube_quad2.off | 41 ++++++ .../Polygon_mesh_processing/data/tri1.off | 61 +++++++++ .../Polygon_mesh_processing/data/tri2.off | 61 +++++++++ .../Polygon_mesh_processing/measures_test.cpp | 87 +++++++++++++ 8 files changed, 441 insertions(+), 92 deletions(-) create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/data/cube_quad2.off create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1.off create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2.off diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp index 05b989e0b29..d821caf6fef 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp @@ -9,98 +9,6 @@ #include #include -namespace CGAL{ -namespace Polygon_mesh_processing{ -//todo face_descriptor ça doit etre le facerange::value_type je pense. checker le c++20 de value_type par contre -template -void compare_meshes(const TriangleMesh& m1, const TriangleMesh& m2, - FacePairRange& common, FaceRange& tm1_only, FaceRange& tm2_only, - const NamedParameters1& np1,const NamedParameters2& np2) -{ - using parameters::choose_parameter; - using parameters::get_parameter; - typedef typename GetVertexPointMap < TriangleMesh, NamedParameters1>::const_type VPMap1; - typedef typename GetVertexPointMap < TriangleMesh, NamedParameters2>::const_type VPMap2; - VPMap1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), - get_const_property_map(vertex_point, m1)); - VPMap2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), - get_const_property_map(vertex_point, m2)); - typedef typename boost::property_traits::value_type Point_3; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - - - - std::map point_id_map; - std::vector m1_vertex_id(num_vertices(m1), -1); - std::vector m2_vertex_id(num_vertices(m2), -1); - - //iterate both meshes to set ids to all points, and set vertex/point_id maps. - std::size_t id =0; - for(auto v : vertices(m1)) - { - const Point_3& p = get(vpm1, v); - auto res = point_id_map.insert(std::make_pair(p, id)); - if(res.second) - id++; - m1_vertex_id[(std::size_t)v]=res.first->second; - } - for(auto v : vertices(m2)) - { - const Point_3& p = get(vpm2, v); - auto res = point_id_map.insert(std::make_pair(p, id)); - if(res.second) - id++; - m2_vertex_id[(std::size_t)v]=res.first->second; - } - - //fill a set with the "faces point-ids" of m1 and then iterate faces of m2 to compare. - std::set > m1_faces; - for(auto f : faces(m1)) - { - std::vector ids; - for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) - { - ids.push_back(m1_vertex_id[(std::size_t)v]); - } - std::sort(ids.begin(), ids.end()); - m1_faces.insert(ids); - } - std::map, face_descriptor> m2_faces_map; - for(auto f : faces(m2)) - { - std::vector ids; - for(auto v : CGAL::vertices_around_face(halfedge(f, m2), m2)) - { - ids.push_back(m2_vertex_id[(std::size_t)v]); - } - std::sort(ids.begin(), ids.end()); - m2_faces_map.insert({ids, f}); - if(m1_faces.find(ids) == m1_faces.end()) { - tm2_only.push_back(f); - } - } - - for(auto f : faces(m1)) - { - std::vector ids; - for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) - { - ids.push_back(m1_vertex_id[(std::size_t)v]); - } - std::sort(ids.begin(), ids.end()); - auto m2_face_it = m2_faces_map.find(ids); - if(m2_face_it == m2_faces_map.end()) - { - tm1_only.push_back(f); - } - else - { - common.push_back(std::make_pair(f, m2_face_it->second)); - } - } -} -}//pmp -}//cgal typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_3 Point; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off new file mode 100644 index 00000000000..18a3647c547 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off @@ -0,0 +1,35 @@ +# Output of a CGAL tool +#CBP +# polyhedral_surface 0 +# halfedges 0 +# triangulated 0 +# non_empty_facets 0 +# terrain 0 +# normalized_to_sphere 0 +# radius 0 +# rounded 0 +# rounded_bits 0 +# ENDCBP + +NOFF +4 4 0 + +# 4 vertices +# ------------------------------------------ + + +0 0 0 -0.57735 -0.57735 -0.57735 +1 0 0 0.935113 -0.250563 -0.250563 +0 1 0 -0.250563 0.935113 -0.250563 +0 0 1 -0.250563 -0.250563 0.935113 + +# 4 facets +# ------------------------------------------ + +3 2 1 0 +3 0 3 2 +3 2 3 1 +3 1 3 0 + + +# End of OFF # diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off new file mode 100644 index 00000000000..d198868a0c5 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off @@ -0,0 +1,35 @@ +# Output of a CGAL tool +#CBP +# polyhedral_surface 0 +# halfedges 0 +# triangulated 0 +# non_empty_facets 0 +# terrain 0 +# normalized_to_sphere 0 +# radius 0 +# rounded 0 +# rounded_bits 0 +# ENDCBP + +NOFF +4 4 0 + +# 4 vertices +# ------------------------------------------ + + +0.0521823 0.0693697 0.0558329 -0.57735 -0.57735 -0.57735 +1 0 0 0.935113 -0.250563 -0.250563 +0 1 0 -0.250563 0.935113 -0.250563 +0 0 1 -0.250563 -0.250563 0.935113 + +# 4 facets +# ------------------------------------------ + +3 2 1 0 +3 0 3 2 +3 2 3 1 +3 1 3 0 + + +# End of OFF # diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 911087ac7b9..6ac978da837 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -820,6 +820,127 @@ centroid(const TriangleMesh& tmesh) return centroid(tmesh, CGAL::Polygon_mesh_processing::parameters::all_default()); } + +/** + * \ingroup measure_grp + * given two meshes, separates the faces that are only in one, the faces + * that are only in the other one, and the faces that are common to both. + * + * @tparam PolygonMesh a model of `HalfedgeListGraph` and `FaceListGraph` + * \tparam FaceRange a range of `boost::graph_traits::%face_descriptor` + * @tparam FacePairRange a range of `std::pair::%face_descriptor, boost::graph_traits::%face_descriptor>` + * + * @tparam NamedParameters1 a sequence of \ref bgl_namedparameters "Named Parameters" + * @tparam NamedParameters2 a sequence of \ref bgl_namedparameters "Named Parameters" + * + * @param m1 the first `PolygonMesh` + * @param m2 the second `PolygonMesh` + * @param common the range containing the faces that are common to both meshes. + * @param m1_only the range containing the faces that are only in `m1` + * @param m2_only the range containing the faces that are only in `m2` + * @param np1 an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below + * @param np2 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 `m1` (`m2`)} + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * as key type and `%Point_3` as value type} + * \cgalParamDefault{`boost::get(CGAL::vertex_point, m1 (m2))`} + * \cgalParamNEnd + * \cgalNamedParamsEnd + * + */ +template +void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, + FacePairRange& common, FaceRange& m1_only, FaceRange& m2_only, + const NamedParameters1& np1,const NamedParameters2& np2) +{ + using parameters::choose_parameter; + using parameters::get_parameter; + typedef typename GetVertexPointMap < PolygonMesh, NamedParameters1>::const_type VPMap1; + typedef typename GetVertexPointMap < PolygonMesh, NamedParameters2>::const_type VPMap2; + typedef typename GetInitializedVertexIndexMap::type VIMap1; + typedef typename GetInitializedVertexIndexMap::type VIMap2; + VPMap1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, m1)); + VPMap2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, m2)); + VIMap1 vim1 = get_initialized_vertex_index_map(m1, np1); + VIMap1 vim2 = get_initialized_vertex_index_map(m2, np2); + typedef typename boost::property_traits::value_type Point_3; + typedef typename FaceRange::value_type face_descriptor; + + std::map point_id_map; + std::vector m1_vertex_id(num_vertices(m1), -1); + std::vector m2_vertex_id(num_vertices(m2), -1); + + //iterate both meshes to set ids to all points, and set vertex/point_id maps. + std::size_t id =0; + for(auto v : vertices(m1)) + { + const Point_3& p = get(vpm1, v); + auto res = point_id_map.insert(std::make_pair(p, id)); + if(res.second) + id++; + m1_vertex_id[(std::size_t)get(vim1, v)]=res.first->second; + } + for(auto v : vertices(m2)) + { + const Point_3& p = get(vpm2, v); + auto res = point_id_map.insert(std::make_pair(p, id)); + if(res.second) + id++; + m2_vertex_id[(std::size_t)get(vim2, v)]=res.first->second; + } + + //fill a set with the "faces point-ids" of m1 and then iterate faces of m2 to compare. + std::set > m1_faces; + for(auto f : faces(m1)) + { + std::vector ids; + for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) + { + ids.push_back(m1_vertex_id[(std::size_t)get(vim1, v)]); + } + std::sort(ids.begin(), ids.end()); + m1_faces.insert(ids); + } + std::map, face_descriptor> m2_faces_map; + for(auto f : faces(m2)) + { + std::vector ids; + for(auto v : CGAL::vertices_around_face(halfedge(f, m2), m2)) + { + ids.push_back(m2_vertex_id[(std::size_t)get(vim2, v)]); + } + std::sort(ids.begin(), ids.end()); + m2_faces_map.insert({ids, f}); + if(m1_faces.find(ids) == m1_faces.end()) { + m2_only.push_back(f); + } + } + + for(auto f : faces(m1)) + { + std::vector ids; + for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) + { + ids.push_back(m1_vertex_id[(std::size_t)get(vim1, v)]); + } + std::sort(ids.begin(), ids.end()); + auto m2_face_it = m2_faces_map.find(ids); + if(m2_face_it == m2_faces_map.end()) + { + m1_only.push_back(f); + } + else + { + common.push_back(std::make_pair(f, m2_face_it->second)); + } + } +} + } // namespace Polygon_mesh_processing } // namespace CGAL diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/cube_quad2.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/cube_quad2.off new file mode 100644 index 00000000000..295769c43c5 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/cube_quad2.off @@ -0,0 +1,41 @@ +# Output of a CGAL tool +#CBP +# polyhedral_surface 0 +# halfedges 0 +# triangulated 0 +# non_empty_facets 0 +# terrain 0 +# normalized_to_sphere 0 +# radius 0 +# rounded 0 +# rounded_bits 0 +# ENDCBP + +NOFF +8 6 0 + +# 8 vertices +# ------------------------------------------ + + +-1 -1 -1 -0.57735 -0.57735 -0.57735 +-1 1 -1 -0.57735 0.57735 -0.57735 +1 1 -1 0.57735 0.57735 -0.57735 +1 -1 -1 0.57735 -0.57735 -0.57735 +-1.53485 -0.408879 0.387354 -0.57735 -0.57735 0.57735 +-1 1 1 -0.57735 0.57735 0.57735 +1 1 1 0.57735 0.57735 0.57735 +1 -1 1 0.57735 -0.57735 0.57735 + +# 6 facets +# ------------------------------------------ + +4 0 3 7 4 +4 3 2 6 7 +4 2 1 5 6 +4 1 0 4 5 +4 4 7 6 5 +4 0 1 2 3 + + +# End of OFF # diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1.off new file mode 100644 index 00000000000..799cae68183 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1.off @@ -0,0 +1,61 @@ +# Output of a CGAL tool +#CBP +# polyhedral_surface 0 +# halfedges 0 +# triangulated 0 +# non_empty_facets 0 +# terrain 0 +# normalized_to_sphere 0 +# radius 0 +# rounded 0 +# rounded_bits 0 +# ENDCBP + +NOFF +16 18 0 + +# 16 vertices +# ------------------------------------------ + + +0 0 0 0 -0.707107 0.707107 +0.333333 0 0 0 -0.707107 0.707107 +0.666667 0 0 0 -0.707107 0.707107 +1 0 0 0 -0.707107 0.707107 +0 0.333333 0.333333 0 -0.707107 0.707107 +0.333333 0.333333 0.333333 0 -0.707107 0.707107 +0.666667 0.333333 0.333333 0 -0.707107 0.707107 +1 0.333333 0.333333 0 -0.707107 0.707107 +0 0.666667 0.666667 0 -0.707107 0.707107 +0.333333 0.666667 0.666667 0 -0.707107 0.707107 +0.666667 0.666667 0.666667 0 -0.707107 0.707107 +1 0.666667 0.666667 0 -0.707107 0.707107 +0 1 1 0 -0.707107 0.707107 +0.333333 1 1 0 -0.707107 0.707107 +0.666667 1 1 0 -0.707107 0.707107 +1 1 1 0 -0.707107 0.707107 + +# 18 facets +# ------------------------------------------ + +3 0 1 4 +3 1 5 4 +3 4 5 8 +3 5 9 8 +3 8 9 12 +3 9 13 12 +3 1 2 5 +3 2 6 5 +3 5 6 9 +3 6 10 9 +3 9 10 13 +3 10 14 13 +3 2 3 6 +3 3 7 6 +3 6 7 10 +3 7 11 10 +3 10 11 14 +3 11 15 14 + + +# End of OFF # diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2.off new file mode 100644 index 00000000000..7746b80a1c1 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2.off @@ -0,0 +1,61 @@ +# Output of a CGAL tool +#CBP +# polyhedral_surface 0 +# halfedges 0 +# triangulated 0 +# non_empty_facets 0 +# terrain 0 +# normalized_to_sphere 0 +# radius 0 +# rounded 0 +# rounded_bits 0 +# ENDCBP + +NOFF +16 18 0 + +# 16 vertices +# ------------------------------------------ + + +0 0 0 0 -0.707107 0.707107 +0.333333 0 0 0 -0.707107 0.707107 +0.666667 0 0 0 -0.707107 0.707107 +1 0 0 0 -0.707107 0.707107 +0 0.333333 0.333333 0 -0.707107 0.707107 +0.333333 0.333333 0.333333 0 -0.707107 0.707107 +0.670394 0.279285 0.333333 0 -0.707107 0.707107 +1 0.333333 0.333333 0 -0.707107 0.707107 +0 0.666667 0.666667 0 -0.707107 0.707107 +0.333333 0.666667 0.666667 0 -0.707107 0.707107 +0.666667 0.666667 0.666667 0 -0.707107 0.707107 +1 0.666667 0.666667 0 -0.707107 0.707107 +0 1 1 0 -0.707107 0.707107 +0.377961 1.08385 1 0 -0.707107 0.707107 +0.735637 1.01488 0.948966 0 -0.707107 0.707107 +0.963486 1.09061 1 0 -0.707107 0.707107 + +# 18 facets +# ------------------------------------------ + +3 0 1 4 +3 1 5 4 +3 4 5 8 +3 5 9 8 +3 8 9 12 +3 9 13 12 +3 1 2 5 +3 2 6 5 +3 5 6 9 +3 6 10 9 +3 9 10 13 +3 10 14 13 +3 2 3 6 +3 3 7 6 +3 6 7 10 +3 7 11 10 +3 10 11 14 +3 11 15 14 + + +# End of OFF # diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp index b1537349cc1..c85f69ffb14 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp @@ -203,6 +203,89 @@ void test_centroid(const char* filename) } +template +void test_compare() +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + namespace PMP = CGAL::Polygon_mesh_processing; + + PolygonMesh mesh1, mesh2; + std::vector > common; + std::vector m1_only, m2_only; + /************************* + * triangulated and open * + * **********************/ + + std::ifstream input("data/tri1.off"); + if(! (input >> mesh1)) + { + std::cerr << "Invalid input." << std::endl; + assert (false); + return; + } + input.close(); + input.open("data/tri2.off"); + if(! (input >> mesh2)) + { + std::cerr << "Invalid input." << std::endl; + assert (false); + return; + } + input.close(); + PMP::compare_meshes(mesh1, mesh2, common, m1_only, m2_only, CGAL::parameters::all_default(), CGAL::parameters::all_default()); + assert(common.size() == 7); + assert(m1_only.size() == 11); + assert(m2_only.size() == 11); + /************************* + **** quad and closed **** + * **********************/ + CGAL::clear(mesh1); + CGAL::clear(mesh2); + common.clear(); + m1_only.clear(); + m2_only.clear(); + input.open("data/cube_quad.off"); + if(! (input >> mesh1)) + { + std::cerr << "Invalid input." << std::endl; + assert (false); + return; + } + input.close(); + input.open("data/cube_quad2.off"); + if(! (input >> mesh2)) + { + std::cerr << "Invalid input." << std::endl; + assert (false); + return; + } + input.close(); + std::unordered_map fim1; + std::unordered_map fim2; + std::size_t id = 0; + for(const auto& f : faces(mesh1)) + { + fim1.insert(std::make_pair(f, id++)); + } + id = 0; + for(const auto& f : faces(mesh2)) + { + fim2.insert(std::make_pair(f, id++)); + } + PMP::compare_meshes(mesh1, mesh2, common, m1_only, m2_only, CGAL::parameters::all_default(), CGAL::parameters::all_default()); + assert(common.size() == 3); + assert(m1_only.size() == 3); + assert(fim1[m1_only[0]] == 0); + assert(fim1[m1_only[1]] == 3); + assert(fim1[m1_only[2]] == 4); + assert(m2_only.size() == 3); + assert(fim2[m2_only[0]] == 0); + assert(fim2[m2_only[1]] == 3); + assert(fim2[m2_only[2]] == 4); + +} + int main(int argc, char* argv[]) { const char* filename_polyhedron = @@ -219,6 +302,10 @@ int main(int argc, char* argv[]) // leading to a stackoverflow when the destructor is called. test_centroid,Epic>(filename_surface_mesh); + test_compare >(); + test_compare >(); + test_compare >(); + test_compare >(); std::cerr << "All done." << std::endl; return 0; } From 836a7b8ae858f296fb9ad1d9bdbeb61e6af91056 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 22 Mar 2021 14:13:10 +0100 Subject: [PATCH 110/349] update CHANGES.md --- Installation/CHANGES.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 5787fc1441b..26086f5a684 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -1,5 +1,14 @@ Release History =============== +[Release 5.4](https://github.com/CGAL/cgal/releases/tag/v5.4) +----------- + +Release date: December 2021 + +### [Polygon Mesh Processing](https://doc.cgal.org/5.4/Manual/packages.html#PkgPolygonMeshProcessing) + +- Added the function `CGAL::Polygon_mesh_processing::compare_meshes()` which allows, given two meshes, to geometrically detect which faces are only in the first, only in the second, or in both meshes. + [Release 5.3](https://github.com/CGAL/cgal/releases/tag/v5.3) ----------- From 7d4a66167136586a3dc3387265ba77ee1ab27ea1 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 22 Mar 2021 14:59:01 +0100 Subject: [PATCH 111/349] Overloads, plugin and data sets --- .../Polygon_mesh_processing/data/tet-bis.off | 33 +---- .../Polygon_mesh_processing/data/tet.off | 33 +---- .../CGAL/Polygon_mesh_processing/measure.h | 15 ++ .../data/cube_quad2.off | 41 ++---- .../Polygon_mesh_processing/data/tri1.off | 57 +++----- .../Polygon_mesh_processing/data/tri2.off | 57 +++----- .../Diff_between_meshes_plugin.cpp | 136 +++++------------- 7 files changed, 102 insertions(+), 270 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off index 18a3647c547..7ea52d418d4 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off @@ -1,35 +1,12 @@ -# Output of a CGAL tool -#CBP -# polyhedral_surface 0 -# halfedges 0 -# triangulated 0 -# non_empty_facets 0 -# terrain 0 -# normalized_to_sphere 0 -# radius 0 -# rounded 0 -# rounded_bits 0 -# ENDCBP - -NOFF +OFF 4 4 0 -# 4 vertices -# ------------------------------------------ - - -0 0 0 -0.57735 -0.57735 -0.57735 -1 0 0 0.935113 -0.250563 -0.250563 -0 1 0 -0.250563 0.935113 -0.250563 -0 0 1 -0.250563 -0.250563 0.935113 - -# 4 facets -# ------------------------------------------ +0 0 0 +1 0 0 +0 1 0 +0 0 1 3 2 1 0 3 0 3 2 3 2 3 1 3 1 3 0 - - -# End of OFF # diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off index d198868a0c5..0e1fcb3bab7 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off @@ -1,35 +1,12 @@ -# Output of a CGAL tool -#CBP -# polyhedral_surface 0 -# halfedges 0 -# triangulated 0 -# non_empty_facets 0 -# terrain 0 -# normalized_to_sphere 0 -# radius 0 -# rounded 0 -# rounded_bits 0 -# ENDCBP - -NOFF +OFF 4 4 0 -# 4 vertices -# ------------------------------------------ - - -0.0521823 0.0693697 0.0558329 -0.57735 -0.57735 -0.57735 -1 0 0 0.935113 -0.250563 -0.250563 -0 1 0 -0.250563 0.935113 -0.250563 -0 0 1 -0.250563 -0.250563 0.935113 - -# 4 facets -# ------------------------------------------ +0.0521823 0.0693697 0.0558329 +1 0 0 +0 1 0 +0 0 1 3 2 1 0 3 0 3 2 3 2 3 1 3 1 3 0 - - -# End of OFF # diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 6ac978da837..f84a1d872ce 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -941,6 +941,21 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, } } +template +void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, + FacePairRange& common, FaceRange& m1_only, FaceRange& m2_only, + const NamedParameters& np) +{ + compare_meshes(m1, m2, common, m1_only, m2_only, np, parameters::all_default()); +} + +template +void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, + FacePairRange& common, FaceRange& m1_only, FaceRange& m2_only) +{ + compare_meshes(m1, m2, common, m1_only, m2_only, parameters::all_default(), parameters::all_default()); +} + } // namespace Polygon_mesh_processing } // namespace CGAL diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/cube_quad2.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/cube_quad2.off index 295769c43c5..45cb8852a90 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/cube_quad2.off +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/cube_quad2.off @@ -1,34 +1,14 @@ -# Output of a CGAL tool -#CBP -# polyhedral_surface 0 -# halfedges 0 -# triangulated 0 -# non_empty_facets 0 -# terrain 0 -# normalized_to_sphere 0 -# radius 0 -# rounded 0 -# rounded_bits 0 -# ENDCBP - -NOFF +OFF 8 6 0 -# 8 vertices -# ------------------------------------------ - - --1 -1 -1 -0.57735 -0.57735 -0.57735 --1 1 -1 -0.57735 0.57735 -0.57735 -1 1 -1 0.57735 0.57735 -0.57735 -1 -1 -1 0.57735 -0.57735 -0.57735 --1.53485 -0.408879 0.387354 -0.57735 -0.57735 0.57735 --1 1 1 -0.57735 0.57735 0.57735 -1 1 1 0.57735 0.57735 0.57735 -1 -1 1 0.57735 -0.57735 0.57735 - -# 6 facets -# ------------------------------------------ +-1 -1 -1 +-1 1 -1 +1 1 -1 +1 -1 -1 +-1.53485 -0.408879 0.387354 +-1 1 1 +1 1 1 +1 -1 1 4 0 3 7 4 4 3 2 6 7 @@ -36,6 +16,3 @@ NOFF 4 1 0 4 5 4 4 7 6 5 4 0 1 2 3 - - -# End of OFF # diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1.off index 799cae68183..2aada48783f 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1.off +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1.off @@ -1,42 +1,22 @@ -# Output of a CGAL tool -#CBP -# polyhedral_surface 0 -# halfedges 0 -# triangulated 0 -# non_empty_facets 0 -# terrain 0 -# normalized_to_sphere 0 -# radius 0 -# rounded 0 -# rounded_bits 0 -# ENDCBP - -NOFF +OFF 16 18 0 -# 16 vertices -# ------------------------------------------ - - -0 0 0 0 -0.707107 0.707107 -0.333333 0 0 0 -0.707107 0.707107 -0.666667 0 0 0 -0.707107 0.707107 -1 0 0 0 -0.707107 0.707107 -0 0.333333 0.333333 0 -0.707107 0.707107 -0.333333 0.333333 0.333333 0 -0.707107 0.707107 -0.666667 0.333333 0.333333 0 -0.707107 0.707107 -1 0.333333 0.333333 0 -0.707107 0.707107 -0 0.666667 0.666667 0 -0.707107 0.707107 -0.333333 0.666667 0.666667 0 -0.707107 0.707107 -0.666667 0.666667 0.666667 0 -0.707107 0.707107 -1 0.666667 0.666667 0 -0.707107 0.707107 -0 1 1 0 -0.707107 0.707107 -0.333333 1 1 0 -0.707107 0.707107 -0.666667 1 1 0 -0.707107 0.707107 -1 1 1 0 -0.707107 0.707107 - -# 18 facets -# ------------------------------------------ +0 0 0 +0.333333 0 0 +0.666667 0 0 +1 0 0 +0 0.333333 0.333333 +0.333333 0.333333 0.333333 +0.666667 0.333333 0.333333 +1 0.333333 0.333333 +0 0.666667 0.666667 +0.333333 0.666667 0.666667 +0.666667 0.666667 0.666667 +1 0.666667 0.666667 +0 1 1 +0.333333 1 1 +0.666667 1 1 +1 1 1 3 0 1 4 3 1 5 4 @@ -56,6 +36,3 @@ NOFF 3 7 11 10 3 10 11 14 3 11 15 14 - - -# End of OFF # diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2.off index 7746b80a1c1..462ea37293a 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2.off +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2.off @@ -1,42 +1,22 @@ -# Output of a CGAL tool -#CBP -# polyhedral_surface 0 -# halfedges 0 -# triangulated 0 -# non_empty_facets 0 -# terrain 0 -# normalized_to_sphere 0 -# radius 0 -# rounded 0 -# rounded_bits 0 -# ENDCBP - -NOFF +OFF 16 18 0 -# 16 vertices -# ------------------------------------------ - - -0 0 0 0 -0.707107 0.707107 -0.333333 0 0 0 -0.707107 0.707107 -0.666667 0 0 0 -0.707107 0.707107 -1 0 0 0 -0.707107 0.707107 -0 0.333333 0.333333 0 -0.707107 0.707107 -0.333333 0.333333 0.333333 0 -0.707107 0.707107 -0.670394 0.279285 0.333333 0 -0.707107 0.707107 -1 0.333333 0.333333 0 -0.707107 0.707107 -0 0.666667 0.666667 0 -0.707107 0.707107 -0.333333 0.666667 0.666667 0 -0.707107 0.707107 -0.666667 0.666667 0.666667 0 -0.707107 0.707107 -1 0.666667 0.666667 0 -0.707107 0.707107 -0 1 1 0 -0.707107 0.707107 -0.377961 1.08385 1 0 -0.707107 0.707107 -0.735637 1.01488 0.948966 0 -0.707107 0.707107 -0.963486 1.09061 1 0 -0.707107 0.707107 - -# 18 facets -# ------------------------------------------ +0 0 0 +0.333333 0 0 +0.666667 0 0 +1 0 0 +0 0.333333 0.333333 +0.333333 0.333333 0.333333 +0.670394 0.279285 0.333333 +1 0.333333 0.333333 +0 0.666667 0.666667 +0.333333 0.666667 0.666667 +0.666667 0.666667 0.666667 +1 0.666667 0.666667 +0 1 1 +0.377961 1.08385 1 +0.735637 1.01488 0.948966 +0.963486 1.09061 1 3 0 1 4 3 1 5 4 @@ -56,6 +36,3 @@ NOFF 3 7 11 10 3 10 11 14 3 11 15 14 - - -# End of OFF # diff --git a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp index 3147fca83cf..a4cb6d7875e 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp @@ -8,10 +8,12 @@ #include "Scene_surface_mesh_item.h" #include +#include #include #include #include +#include #include "Messages_interface.h" using namespace CGAL::Three; @@ -48,7 +50,6 @@ public Q_SLOTS: private: CGAL::Three::Scene_interface* scene; QAction* actionDiff; - SMesh* diff(SMesh* m1, SMesh* m2, bool compute_common); }; // end Polyhedron_demo_diff_between_meshes_plugin @@ -67,95 +68,12 @@ QList Polyhedron_demo_diff_between_meshes_plugin::actions() const { return QList() << actionDiff; } -SMesh* Polyhedron_demo_diff_between_meshes_plugin::diff(SMesh* m1, SMesh* m2, bool compute_common = false) -{ - std::map point_id_map; - std::vector m1_vertex_id(num_vertices(*m1), -1); - std::vector m2_vertex_id(num_vertices(*m2), -1); - - //iterate both meshes to set ids to all points, and set vertex/point_id maps. - std::size_t id =0; - for(auto v : m1->vertices()) - { - Point_3 p = m1->point(v); - auto res = point_id_map.insert(std::make_pair(p, id)); - if(res.second) - id++; - m1_vertex_id[(std::size_t)v]=res.first->second; - } - for(auto v : m2->vertices()) - { - Point_3 p = m2->point(v); - auto res = point_id_map.insert(std::make_pair(p, id)); - if(res.second) - id++; - m2_vertex_id[(std::size_t)v]=res.first->second; - } - - //fill a set with the "faces point-ids" of m1 and then iterate faces of m2 to compare. - std::set > m1_faces; - for(auto f : m1->faces()) - { - std::vector ids; - for(auto v : CGAL::vertices_around_face(halfedge(f, *m1), *m1)) - { - ids.push_back(m1_vertex_id[(std::size_t)v]); - } - std::sort(ids.begin(), ids.end()); - m1_faces.insert(ids); - } - - std::vector common_faces; - std::vector common_points; - std::map id_map; - id = 0; - - for(auto f : m2->faces()) - { - std::vector ids; - for(auto v : CGAL::vertices_around_face(halfedge(f, *m2), *m2)) - { - ids.push_back(m2_vertex_id[(std::size_t)v]); - } - std::sort(ids.begin(), ids.end()); - if(!((m1_faces.find(ids) != m1_faces.end()) ^ compute_common)) - { - common_faces.push_back(f); - for(auto v : CGAL::vertices_around_face(halfedge(f, *m2), *m2)) - { - auto res = id_map.insert(std::make_pair(v,id)); - if(res.second) - { - common_points.push_back(m2->point(v)); - id++; - } - } - } - } - - //iterate m1_faces and fill a polygon vector using the id_map previously filled. - std::vector > polygons(common_faces.size()); - id = 0; - for(auto f : common_faces) - { - for(auto v : vertices_around_face(halfedge(f, *m2),*m2)) - { - polygons[id].push_back(id_map[v]); - } - ++id; - } - - SMesh* common = new SMesh(); - CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh( - common_points, polygons, *common); - return common; - -} - void Polyhedron_demo_diff_between_meshes_plugin::diff() { + typedef CGAL::Face_filtered_graph Filtered_graph; + QCursor c(Qt::WaitCursor); CGAL::Three::Three::CursorScopeGuard guard(c); @@ -166,22 +84,36 @@ void Polyhedron_demo_diff_between_meshes_plugin::diff() *m2_item = qobject_cast( scene->item(scene->selectionIndices().back())); - SMesh* m1=m1_item->face_graph(), - *m2=m2_item->face_graph(); + SMesh m1=*m1_item->face_graph(), + m2=*m2_item->face_graph(); + std::vector m1_only, m2_only; + std::vector > common; + CGAL::Polygon_mesh_processing::compare_meshes(m1, m2, common, m1_only, m2_only); - SMesh* m1_over_m2 = diff(m1, m2); - SMesh* m2_over_m1 = diff(m2, m1); - SMesh* common = diff(m2, m1, true); + Filtered_graph filter1(m1, m1_only); + SMesh mesh1_only, mesh2_only, common_mesh; + CGAL::copy_face_graph(filter1, mesh1_only); - Scene_surface_mesh_item* m1_over_m2_item = new Scene_surface_mesh_item(m1_over_m2); - m1_over_m2_item->setColor(QColor(Qt::blue)); - m1_over_m2_item->setName(QString("%2 - %1").arg(m1_item->name()).arg(m2_item->name())); - CGAL::Three::Three::scene()->addItem(m1_over_m2_item); - Scene_surface_mesh_item* m2_over_m1_item = new Scene_surface_mesh_item(m2_over_m1); - m2_over_m1_item->setColor(QColor(Qt::red)); - m2_over_m1_item->setName(QString("%1 - %2").arg(m1_item->name()).arg(m2_item->name())); - CGAL::Three::Three::scene()->addItem(m2_over_m1_item); - Scene_surface_mesh_item* common_item = new Scene_surface_mesh_item(common); + Scene_surface_mesh_item* mesh1_only_item = new Scene_surface_mesh_item(mesh1_only); + mesh1_only_item->setColor(QColor(Qt::blue)); + mesh1_only_item->setName(QString("%1_only").arg(m1_item->name())); + CGAL::Three::Three::scene()->addItem(mesh1_only_item); + + Filtered_graph filter2(m2, m2_only); + CGAL::copy_face_graph(filter2, mesh2_only); + Scene_surface_mesh_item* mesh2_only_item = new Scene_surface_mesh_item(mesh2_only); + mesh2_only_item->setColor(QColor(Qt::red)); + mesh2_only_item->setName(QString("%1_only").arg(m2_item->name())); + CGAL::Three::Three::scene()->addItem(mesh2_only_item); + m1_only.clear(); + m1_only.reserve(common.size()); + for(const auto& f_pair : common) + { + m1_only.push_back(f_pair.first); + } + Filtered_graph filter_common(m1, m1_only); + CGAL::copy_face_graph(filter_common, common_mesh); + Scene_surface_mesh_item* common_item = new Scene_surface_mesh_item(common_mesh); common_item->setColor(QColor(Qt::green)); CGAL::Three::Three::scene()->addItem(common_item); common_item->setName(QString("%1 && %2").arg(m1_item->name()).arg(m2_item->name())); @@ -189,8 +121,8 @@ void Polyhedron_demo_diff_between_meshes_plugin::diff() Scene_group_item* group = new Scene_group_item(); group->setName("Diff result"); CGAL::Three::Three::scene()->addItem(group); - CGAL::Three::Three::scene()->changeGroup(m1_over_m2_item, group); - CGAL::Three::Three::scene()->changeGroup(m2_over_m1_item, group); + CGAL::Three::Three::scene()->changeGroup(mesh1_only_item, group); + CGAL::Three::Three::scene()->changeGroup(mesh2_only_item, group); CGAL::Three::Three::scene()->changeGroup(common_item, group); m1_item->setVisible(false); From c1895e74b65198871e16fd12ab76d0e426a970d6 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 22 Mar 2021 14:59:40 +0100 Subject: [PATCH 112/349] mutbale ranges in doc --- .../include/CGAL/Polygon_mesh_processing/measure.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index f84a1d872ce..7ffe2acffd9 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -827,8 +827,8 @@ centroid(const TriangleMesh& tmesh) * that are only in the other one, and the faces that are common to both. * * @tparam PolygonMesh a model of `HalfedgeListGraph` and `FaceListGraph` - * \tparam FaceRange a range of `boost::graph_traits::%face_descriptor` - * @tparam FacePairRange a range of `std::pair::%face_descriptor, boost::graph_traits::%face_descriptor>` + * \tparam FaceRange a mutable range of `boost::graph_traits::%face_descriptor` + * @tparam FacePairRange a mutable range of `std::pair::%face_descriptor, boost::graph_traits::%face_descriptor>` * * @tparam NamedParameters1 a sequence of \ref bgl_namedparameters "Named Parameters" * @tparam NamedParameters2 a sequence of \ref bgl_namedparameters "Named Parameters" From 22e13faee98ad4bfcd4e17ac055dfbceda3fc695 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 22 Mar 2021 16:28:10 +0100 Subject: [PATCH 113/349] 1st pass after review --- .../CGAL/Polygon_mesh_processing/measure.h | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 7ffe2acffd9..87fe506d7e8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -28,6 +28,7 @@ #include // needed for CGAL::exact(FT)/CGAL::exact(Lazy_exact_nt) +#include #include #include @@ -825,6 +826,7 @@ centroid(const TriangleMesh& tmesh) * \ingroup measure_grp * given two meshes, separates the faces that are only in one, the faces * that are only in the other one, and the faces that are common to both. + * The orientation of the faces is ignored during the comparison. * * @tparam PolygonMesh a model of `HalfedgeListGraph` and `FaceListGraph` * \tparam FaceRange a mutable range of `boost::graph_traits::%face_descriptor` @@ -835,9 +837,9 @@ centroid(const TriangleMesh& tmesh) * * @param m1 the first `PolygonMesh` * @param m2 the second `PolygonMesh` - * @param common the range containing the faces that are common to both meshes. - * @param m1_only the range containing the faces that are only in `m1` - * @param m2_only the range containing the faces that are only in `m2` + * @param common output range containing the faces that are common to both meshes. + * @param m1_only output range containing the faces that are only in `m1` + * @param m2_only output range containing the faces that are only in `m2` * @param np1 an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * @param np2 an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * @@ -845,9 +847,20 @@ centroid(const TriangleMesh& tmesh) * \cgalParamNBegin{vertex_point_map} * \cgalParamDescription{a property map associating points to the vertices of `m1` (`m2`)} * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` - * as key type and `%Point_3` as value type} + * as key type and `%Point_3` as value type. `%Point_3` must be LessThanComparable.} * \cgalParamDefault{`boost::get(CGAL::vertex_point, m1 (m2))`} * \cgalParamNEnd + * + * \cgalParamNBegin{vertex_index_map} + * \cgalParamDescription{a property map associating to each vertex of `m1` (`m2`) a unique index between `0` and `num_vertices(m1 (m2)) - 1`} + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * as key type and `std::size_t` as value type} + * \cgalParamDefault{an automatically indexed internal map} + * \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize + * a face index property map, either using the internal property map if it exists + * or using an external map. The latter might result in - slightly - worsened performance + * in case of non-constant complexity for index access.} + * \cgalParamNEnd * \cgalNamedParamsEnd * */ @@ -860,8 +873,8 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, using parameters::get_parameter; typedef typename GetVertexPointMap < PolygonMesh, NamedParameters1>::const_type VPMap1; typedef typename GetVertexPointMap < PolygonMesh, NamedParameters2>::const_type VPMap2; - typedef typename GetInitializedVertexIndexMap::type VIMap1; - typedef typename GetInitializedVertexIndexMap::type VIMap2; + typedef typename GetInitializedVertexIndexMap::const_type VIMap1; + typedef typename GetInitializedVertexIndexMap::const_type VIMap2; VPMap1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), get_const_property_map(vertex_point, m1)); VPMap2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), @@ -883,7 +896,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, auto res = point_id_map.insert(std::make_pair(p, id)); if(res.second) id++; - m1_vertex_id[(std::size_t)get(vim1, v)]=res.first->second; + m1_vertex_id[static_cast(get(vim1, v))]=res.first->second; } for(auto v : vertices(m2)) { @@ -891,28 +904,28 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, auto res = point_id_map.insert(std::make_pair(p, id)); if(res.second) id++; - m2_vertex_id[(std::size_t)get(vim2, v)]=res.first->second; + m2_vertex_id[static_cast(get(vim2, v))]=res.first->second; } //fill a set with the "faces point-ids" of m1 and then iterate faces of m2 to compare. - std::set > m1_faces; + std::set > m1_faces; for(auto f : faces(m1)) { - std::vector ids; + boost::container::small_vector ids; for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) { - ids.push_back(m1_vertex_id[(std::size_t)get(vim1, v)]); + ids.push_back(m1_vertex_id[static_cast(get(vim1, v))]); } std::sort(ids.begin(), ids.end()); m1_faces.insert(ids); } - std::map, face_descriptor> m2_faces_map; + std::map, face_descriptor> m2_faces_map; for(auto f : faces(m2)) { - std::vector ids; + boost::container::small_vector ids; for(auto v : CGAL::vertices_around_face(halfedge(f, m2), m2)) { - ids.push_back(m2_vertex_id[(std::size_t)get(vim2, v)]); + ids.push_back(m2_vertex_id[static_cast(get(vim2, v))]); } std::sort(ids.begin(), ids.end()); m2_faces_map.insert({ids, f}); @@ -923,10 +936,10 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, for(auto f : faces(m1)) { - std::vector ids; + boost::container::small_vector ids; for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) { - ids.push_back(m1_vertex_id[(std::size_t)get(vim1, v)]); + ids.push_back(m1_vertex_id[static_cast(get(vim1, v))]); } std::sort(ids.begin(), ids.end()); auto m2_face_it = m2_faces_map.find(ids); From 27701711e77239b3403e227c28e8b80e08700157 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 23 Mar 2021 09:25:06 +0100 Subject: [PATCH 114/349] Only 2 loops for faces --- .../CGAL/Polygon_mesh_processing/measure.h | 51 +++++++++---------- .../Polygon_mesh_processing/measures_test.cpp | 5 +- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 87fe506d7e8..6e36010f15a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -885,6 +885,8 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, typedef typename FaceRange::value_type face_descriptor; std::map point_id_map; + //0 = never seen, 1 = seen only once, 2 = seen in both meshes + std::vector shared_vertices(num_vertices(m1) + num_vertices(m2), 0); std::vector m1_vertex_id(num_vertices(m1), -1); std::vector m2_vertex_id(num_vertices(m2), -1); @@ -897,6 +899,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, if(res.second) id++; m1_vertex_id[static_cast(get(vim1, v))]=res.first->second; + ++shared_vertices[res.first->second]; } for(auto v : vertices(m2)) { @@ -905,52 +908,46 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, if(res.second) id++; m2_vertex_id[static_cast(get(vim2, v))]=res.first->second; + ++shared_vertices[res.first->second]; } //fill a set with the "faces point-ids" of m1 and then iterate faces of m2 to compare. - std::set > m1_faces; + std::map, face_descriptor> m1_faces_map; for(auto f : faces(m1)) { + bool all_shared = true; boost::container::small_vector ids; for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) { - ids.push_back(m1_vertex_id[static_cast(get(vim1, v))]); + std::size_t vid = m1_vertex_id[static_cast(get(vim1, v))]; + ids.push_back(vid); + if(shared_vertices[vid] != 2) + all_shared = false; } std::sort(ids.begin(), ids.end()); - m1_faces.insert(ids); + if(all_shared) + m1_faces_map.insert({ids, f}); + else + m1_only.push_back(f); } - std::map, face_descriptor> m2_faces_map; for(auto f : faces(m2)) { boost::container::small_vector ids; + bool all_shared = true; for(auto v : CGAL::vertices_around_face(halfedge(f, m2), m2)) { - ids.push_back(m2_vertex_id[static_cast(get(vim2, v))]); + std::size_t vid = m2_vertex_id[static_cast(get(vim2, v))]; + ids.push_back(vid); + if(shared_vertices[vid] != 2) + { + all_shared = false; + } } std::sort(ids.begin(), ids.end()); - m2_faces_map.insert({ids, f}); - if(m1_faces.find(ids) == m1_faces.end()) { - m2_only.push_back(f); - } - } - - for(auto f : faces(m1)) - { - boost::container::small_vector ids; - for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) - { - ids.push_back(m1_vertex_id[static_cast(get(vim1, v))]); - } - std::sort(ids.begin(), ids.end()); - auto m2_face_it = m2_faces_map.find(ids); - if(m2_face_it == m2_faces_map.end()) - { - m1_only.push_back(f); - } + if(all_shared) + common.push_back(std::make_pair(m1_faces_map[ids], f)); else - { - common.push_back(std::make_pair(f, m2_face_it->second)); - } + m2_only.push_back(f); } } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp index c85f69ffb14..352c15be8aa 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp @@ -212,6 +212,7 @@ void test_compare() PolygonMesh mesh1, mesh2; std::vector > common; + common.clear(); std::vector m1_only, m2_only; /************************* * triangulated and open * @@ -288,7 +289,7 @@ void test_compare() int main(int argc, char* argv[]) { - const char* filename_polyhedron = +/* const char* filename_polyhedron = (argc > 1) ? argv[1] : "data/mech-holes-shark.off"; test_polyhedron,Epic>(filename_polyhedron); test_polyhedron,Epec>(filename_polyhedron); @@ -301,7 +302,7 @@ int main(int argc, char* argv[]) // It won't work with Epec for large meshes as it builds up a deep DAG // leading to a stackoverflow when the destructor is called. test_centroid,Epic>(filename_surface_mesh); - +*/ test_compare >(); test_compare >(); test_compare >(); From 8c5fcd92098f60214c540f3ae4d4b04c4e16dc52 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 23 Mar 2021 09:45:48 +0100 Subject: [PATCH 115/349] Replace by bitset --- .../include/CGAL/Polygon_mesh_processing/measure.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 6e36010f15a..0690212befb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -885,8 +886,8 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, typedef typename FaceRange::value_type face_descriptor; std::map point_id_map; - //0 = never seen, 1 = seen only once, 2 = seen in both meshes - std::vector shared_vertices(num_vertices(m1) + num_vertices(m2), 0); + + boost::dynamic_bitset<> shared_vertices(num_vertices(m1) + num_vertices(m2)); std::vector m1_vertex_id(num_vertices(m1), -1); std::vector m2_vertex_id(num_vertices(m2), -1); @@ -899,7 +900,6 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, if(res.second) id++; m1_vertex_id[static_cast(get(vim1, v))]=res.first->second; - ++shared_vertices[res.first->second]; } for(auto v : vertices(m2)) { @@ -907,8 +907,9 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, auto res = point_id_map.insert(std::make_pair(p, id)); if(res.second) id++; + else + shared_vertices.set(res.first->second); m2_vertex_id[static_cast(get(vim2, v))]=res.first->second; - ++shared_vertices[res.first->second]; } //fill a set with the "faces point-ids" of m1 and then iterate faces of m2 to compare. @@ -921,7 +922,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, { std::size_t vid = m1_vertex_id[static_cast(get(vim1, v))]; ids.push_back(vid); - if(shared_vertices[vid] != 2) + if(!shared_vertices.test(vid)) all_shared = false; } std::sort(ids.begin(), ids.end()); @@ -938,7 +939,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, { std::size_t vid = m2_vertex_id[static_cast(get(vim2, v))]; ids.push_back(vid); - if(shared_vertices[vid] != 2) + if(!shared_vertices.test(vid)) { all_shared = false; } From dd90a3ce84c28523aa9fec3991ca822093d29063 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 23 Mar 2021 10:14:21 +0100 Subject: [PATCH 116/349] OutputIterators --- .../compare_meshes_example.cpp | 2 +- .../CGAL/Polygon_mesh_processing/measure.h | 35 +++++++++++-------- .../Polygon_mesh_processing/measures_test.cpp | 4 +-- .../Diff_between_meshes_plugin.cpp | 2 +- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp index d821caf6fef..ad60ec7091d 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp @@ -36,7 +36,7 @@ int main(int argc, char* argv[]) } std::vector > common; std::vector m1_only, m2_only; - PMP::compare_meshes(mesh1, mesh2, common, m1_only, m2_only, CGAL::parameters::all_default(), CGAL::parameters::all_default()); + PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::all_default(), CGAL::parameters::all_default()); std::cout<<"Faces only in m1 : "<::%face_descriptor` - * @tparam FacePairRange a mutable range of `std::pair::%face_descriptor, boost::graph_traits::%face_descriptor>` + * @tparam OutputFaceIterator model of `OutputIterator` + holding `boost::graph_traits::%face_descriptor` + for faces that are only in one mesh. + * @tparam OutputFacePairIterator model of `OutputIterator` + holding `std::pair::%face_descriptor, + boost::graph_traits::%face_descriptor` + for faces that are shared by both meshes. * * @tparam NamedParameters1 a sequence of \ref bgl_namedparameters "Named Parameters" * @tparam NamedParameters2 a sequence of \ref bgl_namedparameters "Named Parameters" * * @param m1 the first `PolygonMesh` * @param m2 the second `PolygonMesh` - * @param common output range containing the faces that are common to both meshes. - * @param m1_only output range containing the faces that are only in `m1` - * @param m2_only output range containing the faces that are only in `m2` + * @param common output iterator collecting the faces that are common to both meshes. + * @param m1_only output iterator collecting the faces that are only in `m1` + * @param m2_only output iterator collecting the faces that are only in `m2` * @param np1 an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * @param np2 an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * @@ -865,9 +870,9 @@ centroid(const TriangleMesh& tmesh) * \cgalNamedParamsEnd * */ -template +template void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, - FacePairRange& common, FaceRange& m1_only, FaceRange& m2_only, + OutputFacePairIterator common, OutputFaceIterator m1_only, OutputFaceIterator m2_only, const NamedParameters1& np1,const NamedParameters2& np2) { using parameters::choose_parameter; @@ -883,7 +888,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, VIMap1 vim1 = get_initialized_vertex_index_map(m1, np1); VIMap1 vim2 = get_initialized_vertex_index_map(m2, np2); typedef typename boost::property_traits::value_type Point_3; - typedef typename FaceRange::value_type face_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; std::map point_id_map; @@ -929,7 +934,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, if(all_shared) m1_faces_map.insert({ids, f}); else - m1_only.push_back(f); + *m1_only++ = f; } for(auto f : faces(m2)) { @@ -946,23 +951,23 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, } std::sort(ids.begin(), ids.end()); if(all_shared) - common.push_back(std::make_pair(m1_faces_map[ids], f)); + *common++ = std::make_pair(m1_faces_map[ids], f); else - m2_only.push_back(f); + *m2_only++ = f; } } -template +template void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, - FacePairRange& common, FaceRange& m1_only, FaceRange& m2_only, + OutputFacePairIterator common, OutputFaceIterator m1_only, OutputFaceIterator m2_only, const NamedParameters& np) { compare_meshes(m1, m2, common, m1_only, m2_only, np, parameters::all_default()); } -template +template void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, - FacePairRange& common, FaceRange& m1_only, FaceRange& m2_only) + OutputFacePairIterator common, OutputFaceIterator m1_only, OutputFaceIterator m2_only) { compare_meshes(m1, m2, common, m1_only, m2_only, parameters::all_default(), parameters::all_default()); } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp index 352c15be8aa..b0609f34987 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp @@ -234,7 +234,7 @@ void test_compare() return; } input.close(); - PMP::compare_meshes(mesh1, mesh2, common, m1_only, m2_only, CGAL::parameters::all_default(), CGAL::parameters::all_default()); + PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::all_default(), CGAL::parameters::all_default()); assert(common.size() == 7); assert(m1_only.size() == 11); assert(m2_only.size() == 11); @@ -274,7 +274,7 @@ void test_compare() { fim2.insert(std::make_pair(f, id++)); } - PMP::compare_meshes(mesh1, mesh2, common, m1_only, m2_only, CGAL::parameters::all_default(), CGAL::parameters::all_default()); + PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::all_default(), CGAL::parameters::all_default()); assert(common.size() == 3); assert(m1_only.size() == 3); assert(fim1[m1_only[0]] == 0); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp index a4cb6d7875e..c3c5d59302a 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp @@ -88,7 +88,7 @@ void Polyhedron_demo_diff_between_meshes_plugin::diff() m2=*m2_item->face_graph(); std::vector m1_only, m2_only; std::vector > common; - CGAL::Polygon_mesh_processing::compare_meshes(m1, m2, common, m1_only, m2_only); + CGAL::Polygon_mesh_processing::compare_meshes(m1, m2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only)); Filtered_graph filter1(m1, m1_only); SMesh mesh1_only, mesh2_only, common_mesh; From 8f92a01b1203e49a4d37bc00a9099ba854e5c4f0 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 23 Mar 2021 10:38:19 +0100 Subject: [PATCH 117/349] clean-up --- .../CGAL/Polygon_mesh_processing/measure.h | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 0b175578eab..f753c3e8064 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -892,9 +892,9 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, std::map point_id_map; - boost::dynamic_bitset<> shared_vertices(num_vertices(m1) + num_vertices(m2)); - std::vector m1_vertex_id(num_vertices(m1), -1); - std::vector m2_vertex_id(num_vertices(m2), -1); + boost::dynamic_bitset<> shared_vertices(vertices(m1).size() + vertices(m2).size()); + std::vector m1_vertex_id(vertices(m1).size(), -1); + std::vector m2_vertex_id(vertices(m2).size(), -1); //iterate both meshes to set ids to all points, and set vertex/point_id maps. std::size_t id =0; @@ -904,7 +904,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, auto res = point_id_map.insert(std::make_pair(p, id)); if(res.second) id++; - m1_vertex_id[static_cast(get(vim1, v))]=res.first->second; + m1_vertex_id[get(vim1, v)]=res.first->second; } for(auto v : vertices(m2)) { @@ -914,7 +914,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, id++; else shared_vertices.set(res.first->second); - m2_vertex_id[static_cast(get(vim2, v))]=res.first->second; + m2_vertex_id[get(vim2, v)]=res.first->second; } //fill a set with the "faces point-ids" of m1 and then iterate faces of m2 to compare. @@ -925,14 +925,19 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, boost::container::small_vector ids; for(auto v : CGAL::vertices_around_face(halfedge(f, m1), m1)) { - std::size_t vid = m1_vertex_id[static_cast(get(vim1, v))]; + std::size_t vid = m1_vertex_id[get(vim1, v)]; ids.push_back(vid); if(!shared_vertices.test(vid)) + { all_shared = false; + break; + } } - std::sort(ids.begin(), ids.end()); if(all_shared) + { + std::sort(ids.begin(), ids.end()); m1_faces_map.insert({ids, f}); + } else *m1_only++ = f; } @@ -942,16 +947,19 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, bool all_shared = true; for(auto v : CGAL::vertices_around_face(halfedge(f, m2), m2)) { - std::size_t vid = m2_vertex_id[static_cast(get(vim2, v))]; + std::size_t vid = m2_vertex_id[get(vim2, v)]; ids.push_back(vid); if(!shared_vertices.test(vid)) { all_shared = false; + break; } } - std::sort(ids.begin(), ids.end()); if(all_shared) + { + std::sort(ids.begin(), ids.end()); *common++ = std::make_pair(m1_faces_map[ids], f); + } else *m2_only++ = f; } From aa2b52715601087aa69eab6762bda8a8107dcadb Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 23 Mar 2021 11:13:47 +0100 Subject: [PATCH 118/349] Fix holes situation --- .../CGAL/Polygon_mesh_processing/measure.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index f753c3e8064..6a87d56e85f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -958,11 +958,25 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, if(all_shared) { std::sort(ids.begin(), ids.end()); - *common++ = std::make_pair(m1_faces_map[ids], f); + auto it = m1_faces_map.find(ids); + if(it != m1_faces_map.end()) + { + *common++ = std::make_pair(m1_faces_map[ids], f); + m1_faces_map.erase(it); + } + else + { + *m2_only++ = f; + } } else *m2_only++ = f; } + //all real shared vertices have benn removed from the map, so all that remains must go in m1_only + for(const auto& it : m1_faces_map) + { + *m1_only++ = it.second; + } } template From 277117613bfb9c346e7e70f17e906b0ee05ea343 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 23 Mar 2021 11:49:47 +0100 Subject: [PATCH 119/349] Add a NP for orientation requirement --- .../CGAL/Polygon_mesh_processing/measure.h | 30 ++++++++++++++++--- .../Diff_between_meshes_plugin.cpp | 16 +++++++++- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 6a87d56e85f..c74e18103d7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -34,6 +34,7 @@ #include #include +#include #ifdef DOXYGEN_RUNNING #define CGAL_PMP_NP_TEMPLATE_PARAMETERS NamedParameters @@ -51,7 +52,20 @@ public: }; namespace Polygon_mesh_processing { - +namespace pmp_internal { +void rearrange_face_ids(boost::container::small_vector& ids, bool orientation_counts) +{ + if(!orientation_counts) + { + std::sort(ids.begin(), ids.end()); + } + else + { + auto min_elem = std::min_element(ids.begin(), ids.end()); + std::rotate(ids.begin(), min_elem, ids.end()); + } +} +}//end pmp_internal /** * \ingroup measure_grp * computes the length of an edge of a given polygon mesh. @@ -827,7 +841,6 @@ centroid(const TriangleMesh& tmesh) * \ingroup measure_grp * given two meshes, separates the faces that are only in one, the faces * that are only in the other one, and the faces that are common to both. - * The orientation of the faces is ignored during the comparison. * * @tparam PolygonMesh a model of `HalfedgeListGraph` and `FaceListGraph` * @tparam OutputFaceIterator model of `OutputIterator` @@ -867,6 +880,14 @@ centroid(const TriangleMesh& tmesh) * or using an external map. The latter might result in - slightly - worsened performance * in case of non-constant complexity for index access.} * \cgalParamNEnd + * \cgalParamNBegin{require_same_orientation} + * \cgalParamDescription{Parameter (np1 only) to indicate if face orientation should be taken + * into account when determining whether two faces are duplicates, + * that is, whether e.g. the triangles `0,1,2` and `0,2,1` are duplicates.} + * \cgalParamType{Boolean} + * \cgalParamDefault{`false`} + *\cgalParamNEnd + * \cgalNamedParamsEnd * */ @@ -887,6 +908,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, get_const_property_map(vertex_point, m2)); VIMap1 vim1 = get_initialized_vertex_index_map(m1, np1); VIMap1 vim2 = get_initialized_vertex_index_map(m2, np2); + const bool same_orientation = choose_parameter(get_parameter(np1, internal_np::require_same_orientation), false); typedef typename boost::property_traits::value_type Point_3; typedef typename boost::graph_traits::face_descriptor face_descriptor; @@ -935,7 +957,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, } if(all_shared) { - std::sort(ids.begin(), ids.end()); + pmp_internal::rearrange_face_ids(ids, same_orientation); m1_faces_map.insert({ids, f}); } else @@ -957,7 +979,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, } if(all_shared) { - std::sort(ids.begin(), ids.end()); + pmp_internal::rearrange_face_ids(ids, same_orientation); auto it = m1_faces_map.find(ids); if(it != m1_faces_map.end()) { diff --git a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp index c3c5d59302a..11d61ac8916 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp @@ -75,6 +75,14 @@ void Polyhedron_demo_diff_between_meshes_plugin::diff() typedef CGAL::Face_filtered_graph Filtered_graph; QCursor c(Qt::WaitCursor); + + QMessageBox msgBox; + msgBox.setText("Require the Same Orientation ?"); + msgBox.setInformativeText("Should face orientation count for duplicate detection ?"); + msgBox.setStandardButtons(QMessageBox::Yes| QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::No); + int ret = msgBox.exec(); + bool same_orientation = (ret == QMessageBox::Yes); CGAL::Three::Three::CursorScopeGuard guard(c); //Get the two meshes. No need to check their existance, applicable() @@ -88,7 +96,13 @@ void Polyhedron_demo_diff_between_meshes_plugin::diff() m2=*m2_item->face_graph(); std::vector m1_only, m2_only; std::vector > common; - CGAL::Polygon_mesh_processing::compare_meshes(m1, m2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only)); + CGAL::Polygon_mesh_processing::compare_meshes( + m1, + m2, + std::back_inserter(common), + std::back_inserter(m1_only), + std::back_inserter(m2_only), + CGAL::parameters::require_same_orientation(same_orientation)); Filtered_graph filter1(m1, m1_only); SMesh mesh1_only, mesh2_only, common_mesh; From f4da3182d787db9be8676f4f0ecd9c2d809dbc7d Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 23 Mar 2021 12:04:25 +0100 Subject: [PATCH 120/349] add new tests --- .../data/tri1-hole.off | 37 ++++++++++++ .../Polygon_mesh_processing/data/tri2-out.off | 38 +++++++++++++ .../Polygon_mesh_processing/measures_test.cpp | 57 +++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1-hole.off create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2-out.off diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1-hole.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1-hole.off new file mode 100644 index 00000000000..7ba3bb6021b --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri1-hole.off @@ -0,0 +1,37 @@ +OFF +16 17 0 + +0 0 0 +0.333333 0 0 +0.666667 0 0 +1 0 0 +0 0.333333 0.333333 +0.333333 0.333333 0.333333 +0.666667 0.333333 0.333333 +1 0.333333 0.333333 +0 0.666667 0.666667 +0.333333 0.666667 0.666667 +0.666667 0.666667 0.666667 +1 0.666667 0.666667 +0 1 1 +0.333333 1 1 +0.666667 1 1 +1 1 1 + +3 0 1 4 +3 1 5 4 +3 4 5 8 +3 5 9 8 +3 8 9 12 +3 9 13 12 +3 2 6 5 +3 5 6 9 +3 6 10 9 +3 9 10 13 +3 10 14 13 +3 2 3 6 +3 3 7 6 +3 6 7 10 +3 7 11 10 +3 10 11 14 +3 11 15 14 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2-out.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2-out.off new file mode 100644 index 00000000000..1127abddf90 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tri2-out.off @@ -0,0 +1,38 @@ +OFF +16 18 0 + +0 0 0 +0.33333299999999999 0 0 +0.66666700000000001 0 0 +1 0 0 +0 0.33333299999999999 0.33333299999999999 +0.33333299999999999 0.33333299999999999 0.33333299999999999 +0.67039400000000005 0.27928500000000001 0.33333299999999999 +1 0.33333299999999999 0.33333299999999999 +0 0.66666700000000001 0.66666700000000001 +0.33333299999999999 0.66666700000000001 0.66666700000000001 +0.66666700000000001 0.66666700000000001 0.66666700000000001 +1 0.66666700000000001 0.66666700000000001 +0 1 1 +0.37796099999999999 1.08385 1 +0.73563699999999999 1.01488 0.94896599999999998 +0.96348599999999995 1.0906100000000001 1 + +3 4 1 0 +3 4 5 1 +3 8 5 4 +3 8 9 5 +3 12 9 8 +3 12 13 9 +3 5 2 1 +3 5 6 2 +3 9 6 5 +3 9 10 6 +3 13 10 9 +3 13 14 10 +3 6 3 2 +3 6 7 3 +3 10 7 6 +3 10 11 7 +3 14 11 10 +3 14 15 11 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp index b0609f34987..ed8d1b30019 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp @@ -284,6 +284,63 @@ void test_compare() assert(fim2[m2_only[0]] == 0); assert(fim2[m2_only[1]] == 3); assert(fim2[m2_only[2]] == 4); + /************************* + **** tri and hole**** + * **********************/ + CGAL::clear(mesh1); + CGAL::clear(mesh2); + common.clear(); + m1_only.clear(); + m2_only.clear(); + input.open("data/tri1.off"); + if(! (input >> mesh1)) + { + std::cerr << "Invalid input." << std::endl; + assert (false); + return; + } + input.close(); + input.open("data/tri1-hole.off"); + if(! (input >> mesh2)) + { + std::cerr << "Invalid input." << std::endl; + assert (false); + return; + } + input.close(); + PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::all_default(), CGAL::parameters::all_default()); + assert(common.size() == 17); + assert(m1_only.size() == 1); + assert(m2_only.size() == 0); + + /************************* + **** tri and orient**** + * **********************/ + CGAL::clear(mesh1); + CGAL::clear(mesh2); + common.clear(); + m1_only.clear(); + m2_only.clear(); + input.open("data/tri2.off"); + if(! (input >> mesh1)) + { + std::cerr << "Invalid input." << std::endl; + assert (false); + return; + } + input.close(); + input.open("data/tri2-out.off"); + if(! (input >> mesh2)) + { + std::cerr << "Invalid input." << std::endl; + assert (false); + return; + } + input.close(); + PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::require_same_orientation(true), CGAL::parameters::all_default()); + assert(common.size() == 0); + assert(m1_only.size() == 18); + assert(m2_only.size() == 18); } From cc4d27439957c82608efc5e4a397fe4a4a2f3e0d Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 23 Mar 2021 12:10:34 +0100 Subject: [PATCH 121/349] Clarify np --- .../include/CGAL/Polygon_mesh_processing/measure.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index c74e18103d7..6b4416c72fe 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -882,8 +882,9 @@ centroid(const TriangleMesh& tmesh) * \cgalParamNEnd * \cgalParamNBegin{require_same_orientation} * \cgalParamDescription{Parameter (np1 only) to indicate if face orientation should be taken - * into account when determining whether two faces are duplicates, - * that is, whether e.g. the triangles `0,1,2` and `0,2,1` are duplicates.} + * into account when determining whether two faces are duplicates. + * If `true`, then the triangles `0,1,2` and `0,2,1` will not be considered + * as "shared" between the two meshes.} * \cgalParamType{Boolean} * \cgalParamDefault{`false`} *\cgalParamNEnd From c3036b1e3e350a9f4bbc9b3e879fb6ebbeba9ee8 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 23 Mar 2021 12:11:43 +0100 Subject: [PATCH 122/349] clean-up --- .../include/CGAL/Polygon_mesh_processing/measure.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 6b4416c72fe..0bd7dc17237 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -915,9 +915,9 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, std::map point_id_map; - boost::dynamic_bitset<> shared_vertices(vertices(m1).size() + vertices(m2).size()); std::vector m1_vertex_id(vertices(m1).size(), -1); std::vector m2_vertex_id(vertices(m2).size(), -1); + boost::dynamic_bitset<> shared_vertices(m1_vertex_id.size() + m2_vertex_id.size()); //iterate both meshes to set ids to all points, and set vertex/point_id maps. std::size_t id =0; @@ -984,7 +984,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, auto it = m1_faces_map.find(ids); if(it != m1_faces_map.end()) { - *common++ = std::make_pair(m1_faces_map[ids], f); + *common++ = std::make_pair(it->second, f); m1_faces_map.erase(it); } else @@ -995,7 +995,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, else *m2_only++ = f; } - //all real shared vertices have benn removed from the map, so all that remains must go in m1_only + //all real shared vertices have been removed from the map, so all that remains must go in m1_only for(const auto& it : m1_faces_map) { *m1_only++ = it.second; From 5f4437bef1c15a926797bb1adf641794cd516e08 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 23 Mar 2021 12:43:53 +0100 Subject: [PATCH 123/349] Fix missing inline and doc --- .../doc/Polygon_mesh_processing/PackageDescription.txt | 1 + .../include/CGAL/Polygon_mesh_processing/measure.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index 860b966cdcd..acdaa96e9ca 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -198,6 +198,7 @@ The page \ref bgl_namedparameters "Named Parameters" describes their usage. - \link measure_grp `CGAL::Polygon_mesh_processing::edge_length()` \endlink - \link measure_grp `CGAL::Polygon_mesh_processing::face_border_length()` \endlink - \link measure_grp `CGAL::Polygon_mesh_processing::centroid()` \endlink +- \link measure_grp `CGAL::Polygon_mesh_processing::compare_meshes()` \endlink \cgalCRPSection{Distance Functions} - `CGAL::Polygon_mesh_processing::approximate_Hausdorff_distance()` diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 0bd7dc17237..1e6e12d84e0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -52,8 +52,10 @@ public: }; namespace Polygon_mesh_processing { + namespace pmp_internal { -void rearrange_face_ids(boost::container::small_vector& ids, bool orientation_counts) + +inline void rearrange_face_ids(boost::container::small_vector& ids, bool orientation_counts) { if(!orientation_counts) { From 9e6eaa504a8ae59398efb7f4ccf1cd368a9f288c Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 23 Mar 2021 13:42:10 +0100 Subject: [PATCH 124/349] Orientation requirements always on, as it won't work without it on non triangle meshes --- .../compare_meshes_example.cpp | 2 +- .../CGAL/Polygon_mesh_processing/measure.h | 24 ++++--------------- .../Polygon_mesh_processing/measures_test.cpp | 7 +++--- .../Diff_between_meshes_plugin.cpp | 11 +-------- 4 files changed, 10 insertions(+), 34 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp index ad60ec7091d..08d3553947a 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp @@ -36,7 +36,7 @@ int main(int argc, char* argv[]) } std::vector > common; std::vector m1_only, m2_only; - PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::all_default(), CGAL::parameters::all_default()); + PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only)); std::cout<<"Faces only in m1 : "<& ids, bool orientation_counts) +inline void rearrange_face_ids(boost::container::small_vector& ids) { - if(!orientation_counts) - { - std::sort(ids.begin(), ids.end()); - } - else - { auto min_elem = std::min_element(ids.begin(), ids.end()); std::rotate(ids.begin(), min_elem, ids.end()); - } } }//end pmp_internal /** @@ -843,6 +836,7 @@ centroid(const TriangleMesh& tmesh) * \ingroup measure_grp * given two meshes, separates the faces that are only in one, the faces * that are only in the other one, and the faces that are common to both. + * Faces with different orientations will be considered as not shared. * * @tparam PolygonMesh a model of `HalfedgeListGraph` and `FaceListGraph` * @tparam OutputFaceIterator model of `OutputIterator` @@ -882,15 +876,6 @@ centroid(const TriangleMesh& tmesh) * or using an external map. The latter might result in - slightly - worsened performance * in case of non-constant complexity for index access.} * \cgalParamNEnd - * \cgalParamNBegin{require_same_orientation} - * \cgalParamDescription{Parameter (np1 only) to indicate if face orientation should be taken - * into account when determining whether two faces are duplicates. - * If `true`, then the triangles `0,1,2` and `0,2,1` will not be considered - * as "shared" between the two meshes.} - * \cgalParamType{Boolean} - * \cgalParamDefault{`false`} - *\cgalParamNEnd - * \cgalNamedParamsEnd * */ @@ -911,7 +896,6 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, get_const_property_map(vertex_point, m2)); VIMap1 vim1 = get_initialized_vertex_index_map(m1, np1); VIMap1 vim2 = get_initialized_vertex_index_map(m2, np2); - const bool same_orientation = choose_parameter(get_parameter(np1, internal_np::require_same_orientation), false); typedef typename boost::property_traits::value_type Point_3; typedef typename boost::graph_traits::face_descriptor face_descriptor; @@ -960,7 +944,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, } if(all_shared) { - pmp_internal::rearrange_face_ids(ids, same_orientation); + pmp_internal::rearrange_face_ids(ids); m1_faces_map.insert({ids, f}); } else @@ -982,7 +966,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, } if(all_shared) { - pmp_internal::rearrange_face_ids(ids, same_orientation); + pmp_internal::rearrange_face_ids(ids); auto it = m1_faces_map.find(ids); if(it != m1_faces_map.end()) { diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp index ed8d1b30019..3ce828e8faa 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp @@ -337,7 +337,8 @@ void test_compare() return; } input.close(); - PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::require_same_orientation(true), CGAL::parameters::all_default()); + PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), + std::back_inserter(m2_only)); assert(common.size() == 0); assert(m1_only.size() == 18); assert(m2_only.size() == 18); @@ -346,7 +347,7 @@ void test_compare() int main(int argc, char* argv[]) { -/* const char* filename_polyhedron = + const char* filename_polyhedron = (argc > 1) ? argv[1] : "data/mech-holes-shark.off"; test_polyhedron,Epic>(filename_polyhedron); test_polyhedron,Epec>(filename_polyhedron); @@ -359,7 +360,6 @@ int main(int argc, char* argv[]) // It won't work with Epec for large meshes as it builds up a deep DAG // leading to a stackoverflow when the destructor is called. test_centroid,Epic>(filename_surface_mesh); -*/ test_compare >(); test_compare >(); test_compare >(); @@ -367,3 +367,4 @@ int main(int argc, char* argv[]) std::cerr << "All done." << std::endl; return 0; } + diff --git a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp index 11d61ac8916..1fba8c28759 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp @@ -75,14 +75,6 @@ void Polyhedron_demo_diff_between_meshes_plugin::diff() typedef CGAL::Face_filtered_graph Filtered_graph; QCursor c(Qt::WaitCursor); - - QMessageBox msgBox; - msgBox.setText("Require the Same Orientation ?"); - msgBox.setInformativeText("Should face orientation count for duplicate detection ?"); - msgBox.setStandardButtons(QMessageBox::Yes| QMessageBox::No); - msgBox.setDefaultButton(QMessageBox::No); - int ret = msgBox.exec(); - bool same_orientation = (ret == QMessageBox::Yes); CGAL::Three::Three::CursorScopeGuard guard(c); //Get the two meshes. No need to check their existance, applicable() @@ -101,8 +93,7 @@ void Polyhedron_demo_diff_between_meshes_plugin::diff() m2, std::back_inserter(common), std::back_inserter(m1_only), - std::back_inserter(m2_only), - CGAL::parameters::require_same_orientation(same_orientation)); + std::back_inserter(m2_only)); Filtered_graph filter1(m1, m1_only); SMesh mesh1_only, mesh2_only, common_mesh; From ca5867f17255faf921562f2347b5a0d0de6537f3 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 25 Mar 2021 13:27:16 +0100 Subject: [PATCH 125/349] Changes after review --- Installation/CHANGES.md | 16 +++---- .../compare_meshes_example.cpp | 14 +++---- .../Polygon_mesh_processing/data/tet-bis.off | 12 ------ .../Polygon_mesh_processing/data/tet.off | 12 ------ .../CGAL/Polygon_mesh_processing/measure.h | 42 +++++++++---------- 5 files changed, 34 insertions(+), 62 deletions(-) delete mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off delete mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 26086f5a684..51f5f044456 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -7,7 +7,7 @@ Release date: December 2021 ### [Polygon Mesh Processing](https://doc.cgal.org/5.4/Manual/packages.html#PkgPolygonMeshProcessing) -- Added the function `CGAL::Polygon_mesh_processing::compare_meshes()` which allows, given two meshes, to geometrically detect which faces are only in the first, only in the second, or in both meshes. +- Added the function `CGAL::Polygon_mesh_processing::compare_meshes()` that given two polygon meshes identifies faces present in only one of the two meshes as well as faces present in both. [Release 5.3](https://github.com/CGAL/cgal/releases/tag/v5.3) @@ -439,7 +439,7 @@ Release date: November 2019 - LLVM Clang version 8.0 or later (on Linux or MacOS), and - Apple Clang compiler versions 7.0.2 and 10.0.1 (on MacOS). - Since CGAL 4.9, CGAL can be used as a header-only library, with - dependencies. Since CGAL 5.0, that is now the default, unless + dependencies. Since CGAL 5.0, that is now the default, unless specified differently in the (optional) CMake configuration. - The section "Getting Started with CGAL" of the documentation has been updated and reorganized. @@ -2279,14 +2279,14 @@ Release date: October 2014 - Changes in the set of supported platforms: - The Microsoft Windows Visual C++ compiler 2008 (VC9) is no longer supported since CGAL-4.5. -- Since CGAL version 4.0, Eigen was the recommended third-party +- Since CGAL version 4.0, Eigen was the recommended third-party library to use with *Planar Parameterization of Triangulated Surface Meshes*, *Surface Reconstruction from Point Sets*, *Approximation of Ridges and Umbilics on Triangulated Surface Meshes*, and *Estimation of Local Differential Properties of Point-Sampled Surfaces* - packages. From CGAL version 4.5, Taucs, Blas and Lapack are no + packages. From CGAL version 4.5, Taucs, Blas and Lapack are no longer supported. -- CGAL is now compatible with the new CMake version 3.0. +- CGAL is now compatible with the new CMake version 3.0. ### Triangulated Surface Mesh Deformation (new package) @@ -2425,7 +2425,7 @@ Release date: April 2014 - Additional supported platforms: - The Apple Clang compiler version 5.0 is now supported on - OS X Mavericks. + OS X Mavericks. - The Microsoft Windows Visual C++ compiler 2013 (VC12) is now supported. @@ -2563,7 +2563,7 @@ Release date: October 2013 transparent to the user thanks to the implicit constructor added to `CGAL::Object`. However, it is recommended to upgrade your code. The previous behavior can be restored by defining the macro - `CGAL_INTERSECTION_VERSION` to 1. + `CGAL_INTERSECTION_VERSION` to 1. #### 2D Arrangements @@ -2824,7 +2824,7 @@ Release date: October 2012 - Additional supported platforms: - The Apple Clang compiler versions 3.1 and 3.2 are now supported - on Mac OS X. + on Mac OS X. - Improved configuration for essential and optional external third party software - Added more general script to create CMakeLists.txt files: diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp index 08d3553947a..3f9d726b405 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp @@ -1,10 +1,12 @@ #include #include +#include +#include #include -#include #include #include +#include #include #include @@ -20,8 +22,7 @@ namespace PMP = CGAL::Polygon_mesh_processing; int main(int argc, char* argv[]) { - const char* filename1 = (argc > 1) ? argv[1] : "data/tet.off"; - const char* filename2 = (argc > 2) ? argv[2] : "data/tet-bis.off"; + const char* filename1 = (argc > 1) ? argv[1] : "data/P.off"; Surface_mesh mesh1, mesh2; if(!PMP::read_polygon_mesh(filename1, mesh1)) @@ -29,11 +30,8 @@ int main(int argc, char* argv[]) std::cerr << "Invalid input." << std::endl; return 1; } - if(!PMP::read_polygon_mesh(filename2, mesh2)) - { - std::cerr << "Invalid input." << std::endl; - return 1; - } + mesh2 = mesh1; + CGAL::Euler::add_center_vertex(*halfedges(mesh2).begin(),mesh2); std::vector > common; std::vector m1_only, m2_only; PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only)); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off deleted file mode 100644 index 7ea52d418d4..00000000000 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet-bis.off +++ /dev/null @@ -1,12 +0,0 @@ -OFF -4 4 0 - -0 0 0 -1 0 0 -0 1 0 -0 0 1 - -3 2 1 0 -3 0 3 2 -3 2 3 1 -3 1 3 0 diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off deleted file mode 100644 index 0e1fcb3bab7..00000000000 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tet.off +++ /dev/null @@ -1,12 +0,0 @@ -OFF -4 4 0 - -0.0521823 0.0693697 0.0558329 -1 0 0 -0 1 0 -0 0 1 - -3 2 1 0 -3 0 3 2 -3 2 3 1 -3 1 3 0 diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 0ae79f683c4..739d3990e32 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -834,18 +834,16 @@ centroid(const TriangleMesh& tmesh) /** * \ingroup measure_grp - * given two meshes, separates the faces that are only in one, the faces - * that are only in the other one, and the faces that are common to both. - * Faces with different orientations will be considered as not shared. + * identifies faces only present in `m1` and `m2` as well as the faces present + * in both polygon meshes. Two faces are identical if they have the same + * orientation and the same points. * * @tparam PolygonMesh a model of `HalfedgeListGraph` and `FaceListGraph` - * @tparam OutputFaceIterator model of `OutputIterator` - holding `boost::graph_traits::%face_descriptor` - for faces that are only in one mesh. - * @tparam OutputFacePairIterator model of `OutputIterator` + * @tparam FaceOutputIterator model of `OutputIterator` + holding `boost::graph_traits::%face_descriptor`. + * @tparam FacePairOutputIterator model of `OutputIterator` holding `std::pair::%face_descriptor, - boost::graph_traits::%face_descriptor` - for faces that are shared by both meshes. + boost::graph_traits::%face_descriptor`. * * @tparam NamedParameters1 a sequence of \ref bgl_namedparameters "Named Parameters" * @tparam NamedParameters2 a sequence of \ref bgl_namedparameters "Named Parameters" @@ -879,10 +877,10 @@ centroid(const TriangleMesh& tmesh) * \cgalNamedParamsEnd * */ -template +template void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, - OutputFacePairIterator common, OutputFaceIterator m1_only, OutputFaceIterator m2_only, - const NamedParameters1& np1,const NamedParameters2& np2) + FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only, + const NamedParameters1& np1, const NamedParameters2& np2) { using parameters::choose_parameter; using parameters::get_parameter; @@ -895,7 +893,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, VPMap2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), get_const_property_map(vertex_point, m2)); VIMap1 vim1 = get_initialized_vertex_index_map(m1, np1); - VIMap1 vim2 = get_initialized_vertex_index_map(m2, np2); + VIMap2 vim2 = get_initialized_vertex_index_map(m2, np2); typedef typename boost::property_traits::value_type Point_3; typedef typename boost::graph_traits::face_descriptor face_descriptor; @@ -905,14 +903,14 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, std::vector m2_vertex_id(vertices(m2).size(), -1); boost::dynamic_bitset<> shared_vertices(m1_vertex_id.size() + m2_vertex_id.size()); - //iterate both meshes to set ids to all points, and set vertex/point_id maps. - std::size_t id =0; + //iterate both meshes to set ids of all points, and set vertex/point_id maps. + std::size_t id = 0; for(auto v : vertices(m1)) { const Point_3& p = get(vpm1, v); auto res = point_id_map.insert(std::make_pair(p, id)); if(res.second) - id++; + ++id; m1_vertex_id[get(vim1, v)]=res.first->second; } for(auto v : vertices(m2)) @@ -920,7 +918,7 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, const Point_3& p = get(vpm2, v); auto res = point_id_map.insert(std::make_pair(p, id)); if(res.second) - id++; + ++id; else shared_vertices.set(res.first->second); m2_vertex_id[get(vim2, v)]=res.first->second; @@ -981,24 +979,24 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, else *m2_only++ = f; } - //all real shared vertices have been removed from the map, so all that remains must go in m1_only + //all shared faces have been removed from the map, so all that remains must go in m1_only for(const auto& it : m1_faces_map) { *m1_only++ = it.second; } } -template +template void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, - OutputFacePairIterator common, OutputFaceIterator m1_only, OutputFaceIterator m2_only, + FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only, const NamedParameters& np) { compare_meshes(m1, m2, common, m1_only, m2_only, np, parameters::all_default()); } -template +template void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, - OutputFacePairIterator common, OutputFaceIterator m1_only, OutputFaceIterator m2_only) + FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only) { compare_meshes(m1, m2, common, m1_only, m2_only, parameters::all_default(), parameters::all_default()); } From 34e2180b22a57441eda3bc6caba7aee5ba5b3ce5 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 1 Apr 2021 13:36:57 +0200 Subject: [PATCH 126/349] rename match_faces --- Installation/CHANGES.md | 2 +- .../PackageDescription.txt | 2 +- .../compare_meshes_example.cpp | 2 +- .../CGAL/Polygon_mesh_processing/measure.h | 20 +++++++++---------- .../Polygon_mesh_processing/measures_test.cpp | 8 ++++---- .../Diff_between_meshes_plugin.cpp | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 51f5f044456..141e0c86abf 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -7,7 +7,7 @@ Release date: December 2021 ### [Polygon Mesh Processing](https://doc.cgal.org/5.4/Manual/packages.html#PkgPolygonMeshProcessing) -- Added the function `CGAL::Polygon_mesh_processing::compare_meshes()` that given two polygon meshes identifies faces present in only one of the two meshes as well as faces present in both. +- Added the function `CGAL::Polygon_mesh_processing::match_faces()` that given two polygon meshes identifies faces present in only one of the two meshes as well as faces present in both. [Release 5.3](https://github.com/CGAL/cgal/releases/tag/v5.3) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index acdaa96e9ca..8e64ce9b07f 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -198,7 +198,7 @@ The page \ref bgl_namedparameters "Named Parameters" describes their usage. - \link measure_grp `CGAL::Polygon_mesh_processing::edge_length()` \endlink - \link measure_grp `CGAL::Polygon_mesh_processing::face_border_length()` \endlink - \link measure_grp `CGAL::Polygon_mesh_processing::centroid()` \endlink -- \link measure_grp `CGAL::Polygon_mesh_processing::compare_meshes()` \endlink +- \link measure_grp `CGAL::Polygon_mesh_processing::match_faces()` \endlink \cgalCRPSection{Distance Functions} - `CGAL::Polygon_mesh_processing::approximate_Hausdorff_distance()` diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp index 3f9d726b405..40748393a9e 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp @@ -34,7 +34,7 @@ int main(int argc, char* argv[]) CGAL::Euler::add_center_vertex(*halfedges(mesh2).begin(),mesh2); std::vector > common; std::vector m1_only, m2_only; - PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only)); + PMP::match_faces(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only)); std::cout<<"Faces only in m1 : "< -void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, - FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only, - const NamedParameters1& np1, const NamedParameters2& np2) +void match_faces(const PolygonMesh& m1, const PolygonMesh& m2, + FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only, + const NamedParameters1& np1, const NamedParameters2& np2) { using parameters::choose_parameter; using parameters::get_parameter; @@ -987,18 +987,18 @@ void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, } template -void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, - FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only, - const NamedParameters& np) +void match_faces(const PolygonMesh& m1, const PolygonMesh& m2, + FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only, + const NamedParameters& np) { - compare_meshes(m1, m2, common, m1_only, m2_only, np, parameters::all_default()); + match_faces(m1, m2, common, m1_only, m2_only, np, parameters::all_default()); } template -void compare_meshes(const PolygonMesh& m1, const PolygonMesh& m2, - FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only) +void match_faces(const PolygonMesh& m1, const PolygonMesh& m2, + FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only) { - compare_meshes(m1, m2, common, m1_only, m2_only, parameters::all_default(), parameters::all_default()); + match_faces(m1, m2, common, m1_only, m2_only, parameters::all_default(), parameters::all_default()); } } // namespace Polygon_mesh_processing diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp index 3ce828e8faa..701b9a2a3a6 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/measures_test.cpp @@ -234,7 +234,7 @@ void test_compare() return; } input.close(); - PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::all_default(), CGAL::parameters::all_default()); + PMP::match_faces(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::all_default(), CGAL::parameters::all_default()); assert(common.size() == 7); assert(m1_only.size() == 11); assert(m2_only.size() == 11); @@ -274,7 +274,7 @@ void test_compare() { fim2.insert(std::make_pair(f, id++)); } - PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::all_default(), CGAL::parameters::all_default()); + PMP::match_faces(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::all_default(), CGAL::parameters::all_default()); assert(common.size() == 3); assert(m1_only.size() == 3); assert(fim1[m1_only[0]] == 0); @@ -308,7 +308,7 @@ void test_compare() return; } input.close(); - PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::all_default(), CGAL::parameters::all_default()); + PMP::match_faces(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only), CGAL::parameters::all_default(), CGAL::parameters::all_default()); assert(common.size() == 17); assert(m1_only.size() == 1); assert(m2_only.size() == 0); @@ -337,7 +337,7 @@ void test_compare() return; } input.close(); - PMP::compare_meshes(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), + PMP::match_faces(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only)); assert(common.size() == 0); assert(m1_only.size() == 18); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp index 1fba8c28759..095002379b7 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp @@ -88,7 +88,7 @@ void Polyhedron_demo_diff_between_meshes_plugin::diff() m2=*m2_item->face_graph(); std::vector m1_only, m2_only; std::vector > common; - CGAL::Polygon_mesh_processing::compare_meshes( + CGAL::Polygon_mesh_processing::match_faces( m1, m2, std::back_inserter(common), From 0dd0b965868811fe106c768f829050c9596f0a26 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 1 Apr 2021 15:39:45 +0200 Subject: [PATCH 127/349] Don't add empty items in plugin --- .../Diff_between_meshes_plugin.cpp | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp index 095002379b7..8ab19827c47 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Diff_between_meshes_plugin.cpp @@ -98,18 +98,25 @@ void Polyhedron_demo_diff_between_meshes_plugin::diff() Filtered_graph filter1(m1, m1_only); SMesh mesh1_only, mesh2_only, common_mesh; CGAL::copy_face_graph(filter1, mesh1_only); - - Scene_surface_mesh_item* mesh1_only_item = new Scene_surface_mesh_item(mesh1_only); - mesh1_only_item->setColor(QColor(Qt::blue)); - mesh1_only_item->setName(QString("%1_only").arg(m1_item->name())); - CGAL::Three::Three::scene()->addItem(mesh1_only_item); + Scene_surface_mesh_item* mesh1_only_item = nullptr; + if(mesh1_only.faces().size() > 0) + { + mesh1_only_item = new Scene_surface_mesh_item(mesh1_only); + mesh1_only_item->setColor(QColor(Qt::blue)); + mesh1_only_item->setName(QString("%1_only").arg(m1_item->name())); + CGAL::Three::Three::scene()->addItem(mesh1_only_item); + } Filtered_graph filter2(m2, m2_only); CGAL::copy_face_graph(filter2, mesh2_only); - Scene_surface_mesh_item* mesh2_only_item = new Scene_surface_mesh_item(mesh2_only); - mesh2_only_item->setColor(QColor(Qt::red)); - mesh2_only_item->setName(QString("%1_only").arg(m2_item->name())); - CGAL::Three::Three::scene()->addItem(mesh2_only_item); + Scene_surface_mesh_item* mesh2_only_item = nullptr; + if(mesh2_only.faces().size() > 0) + { + mesh2_only_item = new Scene_surface_mesh_item(mesh2_only); + mesh2_only_item->setColor(QColor(Qt::red)); + mesh2_only_item->setName(QString("%1_only").arg(m2_item->name())); + CGAL::Three::Three::scene()->addItem(mesh2_only_item); + } m1_only.clear(); m1_only.reserve(common.size()); for(const auto& f_pair : common) @@ -118,17 +125,23 @@ void Polyhedron_demo_diff_between_meshes_plugin::diff() } Filtered_graph filter_common(m1, m1_only); CGAL::copy_face_graph(filter_common, common_mesh); - Scene_surface_mesh_item* common_item = new Scene_surface_mesh_item(common_mesh); - common_item->setColor(QColor(Qt::green)); - CGAL::Three::Three::scene()->addItem(common_item); - common_item->setName(QString("%1 && %2").arg(m1_item->name()).arg(m2_item->name())); - + Scene_surface_mesh_item* common_item = nullptr; + if(common_mesh.faces().size() > 0) + { + common_item = new Scene_surface_mesh_item(common_mesh); + common_item->setColor(QColor(Qt::green)); + CGAL::Three::Three::scene()->addItem(common_item); + common_item->setName(QString("%1 && %2").arg(m1_item->name()).arg(m2_item->name())); + } Scene_group_item* group = new Scene_group_item(); group->setName("Diff result"); CGAL::Three::Three::scene()->addItem(group); - CGAL::Three::Three::scene()->changeGroup(mesh1_only_item, group); - CGAL::Three::Three::scene()->changeGroup(mesh2_only_item, group); - CGAL::Three::Three::scene()->changeGroup(common_item, group); + if(mesh1_only_item) + CGAL::Three::Three::scene()->changeGroup(mesh1_only_item, group); + if(mesh2_only_item) + CGAL::Three::Three::scene()->changeGroup(mesh2_only_item, group); + if(common_item) + CGAL::Three::Three::scene()->changeGroup(common_item, group); m1_item->setVisible(false); m2_item->setVisible(false); From f8f37393f33820e21ff24f1a6b086ba51800a9cb Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 7 Apr 2021 12:44:17 +0200 Subject: [PATCH 128/349] fixed warnings --- .../hausdorff_bounded_error_distance_example.cpp | 6 +++--- .../include/CGAL/Polygon_mesh_processing/distance.h | 12 ------------ .../AABB_traversal_traits_with_Hausdorff_distance.h | 8 ++++---- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 491573b68f2..9bdc74ca3eb 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -96,7 +96,7 @@ int main(int argc, char** argv) // Read a real meshes given by the user, perturb it slightly and compute the // Hausdorff distance between the original mesh and its pertubation - std::ifstream input( argv[1] ); + std::ifstream input( argc > 1 ? argv[1] : "data/blobby.off" ); input >> tm1; std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl; @@ -122,11 +122,11 @@ int main(int argc, char** argv) // given position. Move the second mesh in 300 steps away from the first one. // Print how the Hausdorff distance changes. - std::ifstream input1( argv[1] ); + std::ifstream input1( argc > 1 ? argv[1] : "data/blobby.off" ); input1 >> tm1; std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl; - std::ifstream input2( argv[2] ); + std::ifstream input2( argc > 2 ? argv[2] : "data/blobby.off" ); input2 >> tm2; std::cout << "Read a mesh with " << tm2.number_of_faces() << " triangles." << std::endl; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 58fe1360d4f..2b0d2af3fd5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1343,23 +1343,11 @@ double bounded_error_Hausdorff_impl( typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Triangle_3 Triangle_3; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - - typedef std::pair Hausdorff_bounds; - typedef CGAL::Spatial_sort_traits_adapter_3 Search_traits_3; - typedef CGAL::dynamic_vertex_property_t> Vertex_property_tag; - typedef CGAL::dynamic_face_property_t Face_property_tag; - - typedef typename boost::property_map::const_type Vertex_closest_triangle_map; - typedef typename boost::property_map::const_type Triangle_hausdorff_bounds; typedef std::pair Hausdorff_bounds; typename Kernel::Compute_squared_distance_3 squared_distance; - typename Kernel::Construct_projected_point_3 project_point; - typename Kernel::FT dist; typedef #if BOOST_VERSION >= 105000 diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 8bf9c7865f4..b27075adcb2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -247,9 +247,9 @@ namespace CGAL { Hausdorff_primitive_traits_tm1( const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2, - const Point_3 hint ) - : m_traits(traits), m_tm2_tree(tree), m_tm1(tm1), m_tm2(tm2), - m_vpm1(vpm1), m_vpm2(vpm2) { + const Point_3& ) + : m_traits(traits), m_tm1(tm1), m_tm2(tm2), + m_vpm1(vpm1), m_vpm2(vpm2), m_tm2_tree(tree) { // Initialize the global bounds with 0., they will only grow. h_lower = 0.; h_upper = 0.; @@ -262,7 +262,7 @@ namespace CGAL { bool go_further() const { return true; } // Compute the explicit Hausdorff distance to the given primitive - void intersection(const Query& query, const Primitive& primitive) + void intersection(const Query&, const Primitive& primitive) { /* Have reached a single triangle, process it */ m_investigated_on_tm1++; From 4033bc14f3730e74396412a02dddb48863ea7468 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 7 Apr 2021 12:52:08 +0200 Subject: [PATCH 129/349] added new tests with test data --- .../data/tetrahedron-remeshed.off | 340 ++++++++ .../data/tetrahedron.off | 10 + ...usdorff_bounded_error_distance_example.cpp | 756 +++++++++++++++--- 3 files changed, 977 insertions(+), 129 deletions(-) create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron-remeshed.off create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron.off diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron-remeshed.off b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron-remeshed.off new file mode 100644 index 00000000000..82fe31012a0 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron-remeshed.off @@ -0,0 +1,340 @@ +OFF +114 224 0 +0 0 0 +1 0 0 +0 1 0 +0 0 1 +0.5 0.5 0 +0.5 0 0 +0 0 0.5 +0 0.5 0.5 +0.5 0 0.5 +0.5 0.25 0 +0.25 0 0 +0.25 0.25 0 +0 0.25 0.5 +0 0.25 0.25 +0 0 0.25 +0.25 0.25 0.5 +0.5 0.25 0.25 +0.25 0.5 0.25 +0.25 0 0.5 +0.25 0 0.25 +0.5 0 0.25 +0.25 0.75 0 +0 0.5 0 +0.75 0.25 0 +0.75 0 0 +0 0 0.75 +0 0.25 0.75 +0 0.75 0.25 +0.25 0 0.75 +0.75 0 0.25 +0.375 0.125 0 +0.25 0.125 0 +0.375 0.25 0 +0 0.25 0.375 +0 0.125 0.25 +0 0.125 0.375 +0.375 0.25 0.375 +0.375 0.375 0.25 +0.25 0.375 0.375 +0.25 0 0.375 +0.375 0 0.25 +0.375 0 0.375 +0.25 0.5 0 +0.125 0.375 0 +0.125 0.625 0 +0.75 0.125 0 +0.625 0.125 0 +0.625 0.25 0 +0 0.125 0.75 +0 0.25 0.625 +0 0.125 0.625 +0 0.5 0.25 +0 0.625 0.125 +0 0.375 0.125 +0.125 0.625 0.25 +0.25 0.625 0.125 +0.125 0.7500001 0.125 +0.125 0.125 0.75 +0.25 0.125 0.625 +0.125 0.25 0.625 +0.625 0.125 0.25 +0.7500001 0.125 0.125 +0.625 0.25 0.125 +0.625 0 0.25 +0.625 0 0.125 +0.75 0 0.125 +0.125 0 0.75 +0.125 0 0.625 +0.25 0 0.625 +0.125 0 0.25 +0.125 0 0.125 +0.25 0 0.125 +0.5 0.375 0 +0.375 0.375 0 +0.5 0.125 0 +0.375 0 0 +0.125 0 0 +0.125 0.125 0 +0 0.125 0.5 +0 0 0.375 +0 0.375 0.5 +0 0.375 0.375 +0 0.125 0.125 +0 0 0.125 +0.125 0.375 0.5 +0.125 0.5 0.375 +0.375 0.125 0.5 +0.5 0.125 0.375 +0.5 0.375 0.125 +0.375 0.5 0.125 +0.375 0 0.5 +0.5 0 0.375 +0.125 0 0.5 +0.125 0 0.375 +0.375 0 0.125 +0.5 0 0.125 +0.125 0.875 0 +0 0.75 0 +0.375 0.625 0 +0 0.25 0 +0.625 0.375 0 +0.875 0.125 0 +0.875 0 0 +0.625 0 0 +0 0 0.625 +0 0 0.875 +0 0.125 0.875 +0 0.375 0.625 +0 0.625 0.375 +0 0.875 0.125 +0.125 0 0.875 +0.375 0 0.625 +0.625 0 0.375 +0.875 0 0.125 +3 30 31 32 +3 33 34 35 +3 36 37 38 +3 39 40 41 +3 42 43 44 +3 45 46 47 +3 48 49 50 +3 51 52 53 +3 54 55 56 +3 57 58 59 +3 60 61 62 +3 63 64 65 +3 66 67 68 +3 69 70 71 +3 72 32 73 +3 74 75 30 +3 31 76 77 +3 78 35 79 +3 80 81 33 +3 34 82 83 +3 84 38 85 +3 86 87 36 +3 37 88 89 +3 90 41 91 +3 92 93 39 +3 40 94 95 +3 96 44 97 +3 98 73 42 +3 43 77 99 +3 100 47 72 +3 101 102 45 +3 46 103 74 +3 104 50 78 +3 105 106 48 +3 49 107 80 +3 82 53 99 +3 81 108 51 +3 52 109 97 +3 109 56 96 +3 108 85 54 +3 55 89 98 +3 107 59 84 +3 106 110 57 +3 58 111 86 +3 88 62 100 +3 87 112 60 +3 61 113 101 +3 113 65 102 +3 112 91 63 +3 64 95 103 +3 111 68 90 +3 110 105 66 +3 67 104 92 +3 94 71 75 +3 93 79 69 +3 70 83 76 +3 9 30 32 +3 30 10 31 +3 32 31 11 +3 12 33 35 +3 33 13 34 +3 35 34 14 +3 15 36 38 +3 36 16 37 +3 38 37 17 +3 18 39 41 +3 39 19 40 +3 41 40 20 +3 21 42 44 +3 42 11 43 +3 44 43 22 +3 23 45 47 +3 45 24 46 +3 47 46 9 +3 25 48 50 +3 48 26 49 +3 50 49 12 +3 13 51 53 +3 51 27 52 +3 53 52 22 +3 27 54 56 +3 54 17 55 +3 56 55 21 +3 26 57 59 +3 57 28 58 +3 59 58 15 +3 16 60 62 +3 60 29 61 +3 62 61 23 +3 29 63 65 +3 63 20 64 +3 65 64 24 +3 28 66 68 +3 66 25 67 +3 68 67 18 +3 19 69 71 +3 69 14 70 +3 71 70 10 +3 4 72 73 +3 72 9 32 +3 73 32 11 +3 9 74 30 +3 74 5 75 +3 30 75 10 +3 11 31 77 +3 31 10 76 +3 77 76 0 +3 6 78 79 +3 78 12 35 +3 79 35 14 +3 12 80 33 +3 80 7 81 +3 33 81 13 +3 14 34 83 +3 34 13 82 +3 83 82 0 +3 7 84 85 +3 84 15 38 +3 85 38 17 +3 15 86 36 +3 86 8 87 +3 36 87 16 +3 17 37 89 +3 37 16 88 +3 89 88 4 +3 8 90 91 +3 90 18 41 +3 91 41 20 +3 18 92 39 +3 92 6 93 +3 39 93 19 +3 20 40 95 +3 40 19 94 +3 95 94 5 +3 2 96 97 +3 96 21 44 +3 97 44 22 +3 21 98 42 +3 98 4 73 +3 42 73 11 +3 22 43 99 +3 43 11 77 +3 99 77 0 +3 4 100 72 +3 100 23 47 +3 72 47 9 +3 23 101 45 +3 101 1 102 +3 45 102 24 +3 9 46 74 +3 46 24 103 +3 74 103 5 +3 6 104 78 +3 104 25 50 +3 78 50 12 +3 25 105 48 +3 105 3 106 +3 48 106 26 +3 12 49 80 +3 49 26 107 +3 80 107 7 +3 0 82 99 +3 82 13 53 +3 99 53 22 +3 13 81 51 +3 81 7 108 +3 51 108 27 +3 22 52 97 +3 52 27 109 +3 97 109 2 +3 2 109 96 +3 109 27 56 +3 96 56 21 +3 27 108 54 +3 108 7 85 +3 54 85 17 +3 21 55 98 +3 55 17 89 +3 98 89 4 +3 7 107 84 +3 107 26 59 +3 84 59 15 +3 26 106 57 +3 106 3 110 +3 57 110 28 +3 15 58 86 +3 58 28 111 +3 86 111 8 +3 4 88 100 +3 88 16 62 +3 100 62 23 +3 16 87 60 +3 87 8 112 +3 60 112 29 +3 23 61 101 +3 61 29 113 +3 101 113 1 +3 1 113 102 +3 113 29 65 +3 102 65 24 +3 29 112 63 +3 112 8 91 +3 63 91 20 +3 24 64 103 +3 64 20 95 +3 103 95 5 +3 8 111 90 +3 111 28 68 +3 90 68 18 +3 28 110 66 +3 110 3 105 +3 66 105 25 +3 18 67 92 +3 67 25 104 +3 92 104 6 +3 5 94 75 +3 94 19 71 +3 75 71 10 +3 19 93 69 +3 93 6 79 +3 69 79 14 +3 10 70 76 +3 70 14 83 +3 76 83 0 diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron.off b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron.off new file mode 100644 index 00000000000..70848d1c605 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron.off @@ -0,0 +1,10 @@ +OFF +4 4 0 +0 0 0 +1 0 0 +0 1 0 +0 0 1 +3 2 1 0 +3 0 3 2 +3 2 3 1 +3 1 3 0 diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 9bdc74ca3eb..1c3c89a692d 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -1,151 +1,649 @@ -#include -#include #include +#include +#include #include +#include +#include +#include + #include #include #include #include #include #include -#include -#if defined(CGAL_LINKED_WITH_TBB) -#define TAG CGAL::Parallel_tag -#else -#define TAG CGAL::Sequential_tag -#endif +using SCK = CGAL::Simple_cartesian; +using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; +using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef K::Point_3 Point_3; -typedef K::Triangle_3 Triangle_3; -typedef K::Vector_3 Vector_3; -typedef CGAL::Surface_mesh Mesh; -typedef Mesh::Vertex_index Vertex_index; +using Kernel = EPICK; +using FT = typename Kernel::FT; +using Point_3 = typename Kernel::Point_3; +using Vector_3 = typename Kernel::Vector_3; + +using TAG = CGAL::Parallel_if_available_tag; +using Surface_mesh = CGAL::Surface_mesh; +using Affine_transformation_3 = CGAL::Aff_transformation_3; +using Timer = CGAL::Real_timer; namespace PMP = CGAL::Polygon_mesh_processing; -int main(int argc, char** argv) -{ - // Objects to hold the meshes - Mesh tm1, tm2; +struct Approximate_hd_wrapper { + const std::size_t m_num_samples; + std::string name() const { return "approximate"; } + Approximate_hd_wrapper(const std::size_t num_samples) : m_num_samples(num_samples) { } + double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { + return PMP::approximate_Hausdorff_distance(tm1, tm2, + PMP::parameters::number_of_points_per_area_unit(m_num_samples), + PMP::parameters::number_of_points_per_area_unit(m_num_samples)); + } +}; - // Timer to measure the runtime of h-distance Distance_computation - CGAL::Real_timer time; +struct Naive_bounded_error_hd_wrapper { + const double m_error_bound; + std::string name() const { return "naive bounded error"; } + Naive_bounded_error_hd_wrapper(const double error_bound) : m_error_bound(error_bound) { } + double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { + return PMP::bounded_error_Hausdorff_distance_naive(tm1, tm2, m_error_bound); + } +}; - // Set an error bound - double error_bound = 0.0001; +struct Bounded_error_hd_wrapper { + const double m_error_bound; + std::string name() const { return "bounded error"; } + Bounded_error_hd_wrapper(const double error_bound) : m_error_bound(error_bound) { } + double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { + return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound); + } +}; -// ---------------------------------------------------------------------------- +void get_meshes( + const std::string filepath1, const std::string filepath2, + Surface_mesh& mesh1, Surface_mesh& mesh2) { - // Easy Example of a tetrahedron and a remeshed version of itself + mesh1.clear(); + std::ifstream input1(filepath1); + input1 >> mesh1; + std::cout << "* getting mesh with " << mesh1.number_of_faces() << " faces" << std::endl; - // Create the Tetrahedron - CGAL::make_tetrahedron(Point_3(.0,.0,.0), - Point_3(2,.0,.0), - Point_3(1,1,1), - Point_3(1,.0,2), - tm1); - // Copy it and remesh it - tm2=tm1; - PMP::isotropic_remeshing(tm2.faces(),.05, tm2); - // Compute the Hausdorff distance - time.reset(); - time.start(); - std::cout << "Approximated Hausdorff distance: " - << PMP::bounded_error_Hausdorff_distance - (tm1, tm2, error_bound) - << std::endl; - time.stop(); - std::cout << "Processing took " << time.time() << "s." << std::endl; + mesh2.clear(); + std::ifstream input2(filepath2); + input2 >> mesh2; + std::cout << "* getting mesh with " << mesh2.number_of_faces() << " faces" << std::endl; +} -// ---------------------------------------------------------------------------- +void save_mesh(const Surface_mesh& mesh, const std::string filepath) { - // Example with point realizing the Hausdorff distance strictly lying in the - - // interior of a triangle - tm1 = Mesh(); - tm1.add_vertex( Point_3(-1.,1.,1.) ); - tm1.add_vertex( Point_3(0.,-1.,1.) ); - tm1.add_vertex( Point_3(1.,1.,1.) ); - tm1.add_face( tm1.vertices() ); - - tm2 = Mesh(); - Vertex_index w0 = tm2.add_vertex( Point_3(-1.,1.,0.) ); - Vertex_index w1 = tm2.add_vertex( Point_3(0.,-1.,0.) ); - Vertex_index w2 = tm2.add_vertex( Point_3(1.,1.,0.) ); - Vertex_index w3 = tm2.add_vertex( Point_3(0.,1.,-1.) ); - Vertex_index w4 = tm2.add_vertex( Point_3(-0.5,0.,-1.) ); - Vertex_index w5 = tm2.add_vertex( Point_3(0.5,0.,-1.) ); - tm2.add_face( w0, w3, w4 ); - tm2.add_face( w1, w4, w5 ); - tm2.add_face( w2, w5, w3 ); - - // Compute the Hausdorff distance - time.reset(); - time.start(); - std::cout << "Approximated Hausdorff distance: " - << PMP::bounded_error_Hausdorff_distance - (tm1, tm2, error_bound) - << std::endl; - time.stop(); - std::cout << "Processing took " << time.time() << "s." << std::endl; - -// ---------------------------------------------------------------------------- - - // Read a real meshes given by the user, perturb it slightly and compute the - // Hausdorff distance between the original mesh and its pertubation - - std::ifstream input( argc > 1 ? argv[1] : "data/blobby.off" ); - input >> tm1; - std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl; - - // Copy the mesh and perturb it slightly - tm2 = tm1; - bool do_project = false; - PMP::random_perturbation( tm2.vertices(), tm2, 0.1, CGAL::parameters::do_project(do_project)); - std::cout << "Perturbed the input mesh, now computing the Hausdorff distance." << std::endl; - - // Compute the Hausdorff distance - time.reset(); - time.start(); - std::cout << "Approximated Hausdorff distance: " - << PMP::bounded_error_Hausdorff_distance - (tm1, tm2, error_bound) - << std::endl; - time.stop(); - std::cout << "Processing took " << time.time() << "s." << std::endl; - -// ---------------------------------------------------------------------------- - - // Read two meshes given by the user, initially place them at their originally - // given position. Move the second mesh in 300 steps away from the first one. - // Print how the Hausdorff distance changes. - - std::ifstream input1( argc > 1 ? argv[1] : "data/blobby.off" ); - input1 >> tm1; - std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl; - - std::ifstream input2( argc > 2 ? argv[2] : "data/blobby.off" ); - input2 >> tm2; - std::cout << "Read a mesh with " << tm2.number_of_faces() << " triangles." << std::endl; - - CGAL::Bbox_3 bb = PMP::bbox(tm2); - double dist = CGAL::approximate_sqrt( Vector_3(bb.xmax() - bb.xmin(), bb.ymax() - bb.ymin(), bb.zmax() - bb.zmin()).squared_length() ); - - for (int i=0; i<300; i++) { - PMP::transform( - CGAL::Aff_transformation_3 ( CGAL::Translation(), Vector_3( 0.01*dist, 0.01*dist, 0.01*dist ) ), - tm2 - ); - time.reset(); - time.start(); - std::cout << "Position: " << i << std::endl; - std::cout << "Approximated Hausdorff distance: " - << PMP::bounded_error_Hausdorff_distance - (tm1, tm2, error_bound) - << std::endl; - time.stop(); - std::cout << "Processing took " << time.time() << "s." << std::endl; + if (!CGAL::write_PLY(filepath + ".ply", mesh)) { + std::cerr << "ERROR: cannot save this file: " << filepath << std::endl; + exit(EXIT_FAILURE); } } + +// An easy example of a tetrahedron and its remeshed version. +void remeshing_tetrahedon_example(const double error_bound) { + + Timer timer; + Surface_mesh mesh1, mesh2; + std::cout << std::endl << "* (E1) remeshing tetrahedron example:" << std::endl; + + CGAL::make_tetrahedron( + Point_3(0, 0, 0), Point_3(2, 0, 0), + Point_3(1, 1, 1), Point_3(1, 0, 2), mesh1); + mesh2 = mesh1; + + // TODO: How to preserve edges? + const double target_edge_length = 0.05; + PMP::isotropic_remeshing(mesh2.faces(), target_edge_length, mesh2); + + // save_mesh(mesh1, "1-mesh1"); + // save_mesh(mesh2, "1-mesh2"); + + timer.reset(); + timer.start(); + std::cout << "* bounded Hausdorff distance: " << + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; + timer.stop(); + std::cout << "* processing time: " << timer.time() << " s." << std::endl; +} + +// Example with a point realizing the Hausdorff distance strictly +// lying in the interior of a triangle. +void interior_triangle_example(const double error_bound) { + + Timer timer; + Surface_mesh mesh1, mesh2; + std::cout << std::endl << "* (E2) interior triangle example:" << std::endl; + + mesh1.add_vertex(Point_3(-1, 1, 1)); + mesh1.add_vertex(Point_3( 0, -1, 1)); + mesh1.add_vertex(Point_3( 1, 1, 1)); + mesh1.add_face(mesh1.vertices()); + + auto v0 = mesh2.add_vertex(Point_3(-1.0, 1, 0)); + auto v1 = mesh2.add_vertex(Point_3( 0.0, -1, 0)); + auto v2 = mesh2.add_vertex(Point_3( 1.0, 1, 0)); + auto v3 = mesh2.add_vertex(Point_3( 0.0, 1, -1)); + auto v4 = mesh2.add_vertex(Point_3(-0.5, 0, -1)); + auto v5 = mesh2.add_vertex(Point_3( 0.5, 0, -1)); + mesh2.add_face(v0, v3, v4); + mesh2.add_face(v1, v4, v5); + mesh2.add_face(v2, v5, v3); + + // save_mesh(mesh1, "2-mesh1"); + // save_mesh(mesh2, "2-mesh2"); + + timer.reset(); + timer.start(); + std::cout << "* bounded Hausdorff distance: " << + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; + timer.stop(); + std::cout << "* processing time: " << timer.time() << " s." << std::endl; +} + +// Read a real mesh given by the user, perturb it slightly, and compute the +// Hausdorff distance between the original mesh and its pertubation. +void perturbing_mesh_example( + const std::string filepath, const double error_bound) { + + Timer timer; + std::cout << std::endl << "* (E3) perturbing mesh example:" << std::endl; + + Surface_mesh mesh1, mesh2; + get_meshes(filepath, filepath, mesh1, mesh2); + + const double max_size = 0.1; + PMP::random_perturbation( + mesh2.vertices(), mesh2, max_size, CGAL::parameters::do_project(false)); + std::cout << "* perturbing the second mesh" << std::endl; + + // save_mesh(mesh2, "3-mesh1"); + // save_mesh(mesh2, "3-mesh2"); + + timer.reset(); + timer.start(); + std::cout << "* bounded Hausdorff distance: " << + PMP::bounded_error_Hausdorff_distance(mesh2, mesh2, error_bound) << std::endl; + timer.stop(); + std::cout << "* processing time: " << timer.time() << " s." << std::endl; +} + +// Read two meshes given by the user, initially place them at their originally +// given position. Move the second mesh in 300 steps away from the first one. +// Print how the Hausdorff distance changes. +void moving_mesh_example( + const std::string filepath1, const std::string filepath2, + const std::size_t n, const double error_bound) { + + Timer timer; + std::cout << std::endl << "* (E4) moving mesh example:" << std::endl; + + Surface_mesh mesh1, mesh2; + get_meshes(filepath1, filepath2, mesh1, mesh2); + + const auto bbox = PMP::bbox(mesh2); + const FT distance = static_cast(CGAL::sqrt(CGAL::to_double( + CGAL::squared_distance( + Point_3(bbox.xmin(), bbox.ymin(), bbox.zmin()), + Point_3(bbox.xmax(), bbox.ymax(), bbox.zmax()))))); + + const FT t = FT(1) / FT(100); + // save_mesh(mesh2, "4-mesh-0"); + + for (std::size_t i = 0; i < n; ++i) { + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(t * distance, t * distance, t * distance)), mesh2); + + timer.reset(); + timer.start(); + std::cout << "* position: " << i << std::endl; + std::cout << "* bounded Hausdorff distance: " << + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; + timer.stop(); + std::cout << "* processing time: " << timer.time() << " s." << std::endl; + // save_mesh(mesh2, "4-mesh-" + std::to_string(i + 1)); + } +} + +template +void test_0(const FunctionWrapper& functor, const bool save = false) { + + // The same triangle. + // Expected distance is 0. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 0 ----" << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2 = mesh1; + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 0): " << dista << std::endl; + std::cout << "* HInverted distance (expected 0): " << distb << std::endl; + // assert(dista == 0.0); + // assert(dista == distb); +} + +template +void test_1(const FunctionWrapper& functor, const bool save = false) { + + // Two triangles are parallel and 1 unit distance away from each other. + // Expected distance is 1. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 1 ----" << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2.add_vertex(Point_3(0, 0, 1)); + mesh2.add_vertex(Point_3(2, 0, 1)); + mesh2.add_vertex(Point_3(1, 1, 1)); + mesh2.add_face(mesh2.vertices()); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; + std::cout << "* HInverted distance (expected 1): " << distb << std::endl; + // assert(dista == 1.0); + // assert(dista == distb); +} + +template +void test_2(const FunctionWrapper& functor, const bool save = false) { + + // One triangle is orthogonal to the other one and shares a common edge. + // Expected distance is 1. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 2 ----" << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2.add_vertex(Point_3(0, 0, 0)); + mesh2.add_vertex(Point_3(2, 0, 0)); + mesh2.add_vertex(Point_3(1, 0, 1)); + mesh2.add_face(mesh2.vertices()); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; + std::cout << "* HInverted distance (expected 1): " << distb << std::endl; + // assert(dista == 1.0); + // assert(dista == distb); +} + +template +void test_3(const FunctionWrapper& functor, const bool save = false) { + + // One triangle is orthogonal to the other one and shares a common edge + // that is moved 1 unit distance away. + // Expected distances are 1.4142135623730951455 and 2. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 3 ----" << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2.add_vertex(Point_3(0, 0, 1)); + mesh2.add_vertex(Point_3(2, 0, 1)); + mesh2.add_vertex(Point_3(1, 0, 2)); + mesh2.add_face(mesh2.vertices()); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1.41): " << dista << std::endl; + std::cout << "* HInverted distance (expected 2.00): " << distb << std::endl; + // assert(dista == 1.4142135623730951455); + // assert(distb == 2.0); +} + +template +void test_4(const FunctionWrapper& functor, const bool save = false) { + + // One triangle is orthogonal to the other one and shares a common vertex. + // Expected distance is 1.2247448713915889407. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 4 ----" << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2.add_vertex(Point_3(0, 1, 1)); + mesh2.add_vertex(Point_3(2, 1, 1)); + mesh2.add_vertex(Point_3(1, 1, 0)); + mesh2.add_face(mesh2.vertices()); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1.22): " << dista << std::endl; + std::cout << "* HInverted distance (expected 1.22): " << distb << std::endl; + // assert(dista == 1.2247448713915889407); + // assert(dista == distb); +} + +template +void test_5(const FunctionWrapper& functor, const bool save = false) { + + // One triangle is orthogonal to the other one and shares a common vertex + // that is moved 1 unit distance away. + // Expected distances are 1.7320508075688771932 and 2.1213203435596423851. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 5 ----" << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2.add_vertex(Point_3(0, 1, 2)); + mesh2.add_vertex(Point_3(2, 1, 2)); + mesh2.add_vertex(Point_3(1, 1, 1)); + mesh2.add_face(mesh2.vertices()); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1.73): " << dista << std::endl; + std::cout << "* HInverted distance (expected 2.12): " << distb << std::endl; + // assert(dista == 1.7320508075688771932); + // assert(distb == 2.1213203435596423851); +} + +template +void test_6(const FunctionWrapper& functor, const bool save = false) { + + // The first and second mesh have different number of triangles. + // They are parallel and lie at the same plane. The middle triangle is overlapping. + // Expected distances are 0 and 0.70710678118654757274. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 6 ----" << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + const auto v0 = mesh2.add_vertex(Point_3(0, 0, 0)); + const auto v1 = mesh2.add_vertex(Point_3(2, 0, 0)); + const auto v2 = mesh2.add_vertex(Point_3(1, 1, 0)); + const auto v3 = mesh2.add_vertex(Point_3(2, 1, 0)); + const auto v4 = mesh2.add_vertex(Point_3(0, 1, 0)); + + mesh2.add_face(v0, v1, v2); + mesh2.add_face(v2, v1, v3); + mesh2.add_face(v0, v2, v4); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 0.0): " << dista << std::endl; + std::cout << "* HInverted distance (expected 0.7): " << distb << std::endl; + // assert(dista == 0.0); + // assert(distb == 0.70710678118654757274); +} + +template +void test_7(const FunctionWrapper& functor, const bool save = false) { + + // One triangle is moved to 0.5 unit distance away from 3 other triangles. + // The first and second meshes are parallel. + // Expected distances are 0.5 and 0.86602540378443859659. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 7 ----" << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + const auto v0 = mesh2.add_vertex(Point_3(0, 0, 0.5)); + const auto v1 = mesh2.add_vertex(Point_3(2, 0, 0.5)); + const auto v2 = mesh2.add_vertex(Point_3(1, 1, 0.5)); + const auto v3 = mesh2.add_vertex(Point_3(2, 1, 0.5)); + const auto v4 = mesh2.add_vertex(Point_3(0, 1, 0.5)); + + mesh2.add_face(v0, v1, v2); + mesh2.add_face(v2, v1, v3); + mesh2.add_face(v0, v2, v4); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 0.50): " << dista << std::endl; + std::cout << "* HInverted distance (expected 0.86): " << distb << std::endl; + // assert(dista == 0.5); + // assert(distb == 0.86602540378443859659); +} + +template +void test_8(const FunctionWrapper& functor, const bool save = false) { + + // One mesh has one triangle at zero level, another mesh has two triangles + // where the first one is at level 1 and the second one is at level 2. + // Expected distances are 1 and 2. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 8 ----" << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + const auto v0 = mesh2.add_vertex(Point_3(0, 0, 1)); + const auto v1 = mesh2.add_vertex(Point_3(2, 0, 1)); + const auto v2 = mesh2.add_vertex(Point_3(1, 1, 1)); + const auto v3 = mesh2.add_vertex(Point_3(0, 0, 2)); + const auto v4 = mesh2.add_vertex(Point_3(2, 0, 2)); + const auto v5 = mesh2.add_vertex(Point_3(1, 1, 2)); + + mesh2.add_face(v0, v1, v2); + mesh2.add_face(v3, v4, v5); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; + std::cout << "* HInverted distance (expected 2): " << distb << std::endl; + // assert(dista == 1.0); + // assert(distb == 2.0); +} + +template +void test_synthetic_data(const FunctionWrapper& functor) { + + std::cout << std::endl << "* testing synthetic data:" << std::endl; + std::cout << "* name -> " << functor.name() << std::endl; + + test_0(functor); // 1 parallel + test_1(functor); + test_2(functor); // 1 edge touching + test_3(functor); + test_4(functor); // 1 vertex touching + test_5(functor); + test_6(functor); // 1 to multiple + test_7(functor); + test_8(functor); +} + +template< +typename FunctionWrapper1, +typename FunctionWrapper2> +void test_one_versus_another( + const FunctionWrapper1& functor1, + const FunctionWrapper2& functor2) { + + std::cout.precision(20); + const std::string filepath1 = "data/tetrahedron.off"; + const std::string filepath2 = "data/tetrahedron-remeshed.off"; + + std::cout << std::endl << "* testing one versus another (tetrahedron):" << std::endl; + std::cout << "* name 1 -> " << functor1.name() << std::endl; + std::cout << "* name 2 -> " << functor2.name() << std::endl; + + Surface_mesh mesh1, mesh2; + get_meshes(filepath1, filepath2, mesh1, mesh2); + + // TEST 0. + // Load and compare. + // The expected distance is 0. + std::cout << " ---- testing 0 ----" << std::endl; + const double dista0 = functor1(mesh1, mesh2); + const double distb0 = functor2(mesh1, mesh2); + std::cout << "* Hausdorff distance1: " << dista0 << std::endl; + std::cout << "* Hausdorff distance2: " << distb0 << std::endl; + // assert(dista0 == distb0); + + std::cout << "* traslating by 1 unit ..." << std::endl; + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(FT(0), FT(0), FT(1))), mesh2); + + // TEST 1. + // Translate by 1 unit distance and compare. + // The expected distance is 1. + std::cout << " ---- testing 1 ----" << std::endl; + const double dista1 = functor1(mesh1, mesh2); + const double distb1 = functor2(mesh1, mesh2); + std::cout << "* Hausdorff distance1: " << dista1 << std::endl; + std::cout << "* Hausdorff distance2: " << distb1 << std::endl; + // assert(dista1 == distb1); +} + +template< +typename FunctionWrapper1, +typename FunctionWrapper2> +void test_real_meshes( + const std::string filepath1, + const std::string filepath2, + const FunctionWrapper1& functor1, + const FunctionWrapper2& functor2) { + + std::cout.precision(20); + std::cout << std::endl << "* testing real meshes:" << std::endl; + std::cout << "* input path 1: " << filepath1 << std::endl; + std::cout << "* input path 2: " << filepath2 << std::endl; + + Surface_mesh mesh1, mesh2; + get_meshes(filepath1, filepath2, mesh1, mesh2); + + std::cout << std::endl; + std::cout << "* name 1 -> " << functor1.name() << std::endl; + std::cout << "* name 2 -> " << functor2.name() << std::endl; + + // Load and compare. + std::cout << std::endl; + std::cout << " ---- testing ----" << std::endl; + const double dista0 = functor1(mesh1, mesh2); + const double dista1 = functor1(mesh2, mesh1); + const double distb0 = functor2(mesh1, mesh2); + const double distb1 = functor2(mesh2, mesh1); + std::cout << std::endl; + std::cout << "* Hausdorff distance1 f: " << dista0 << std::endl; + std::cout << "* Hausdorff distance1 b: " << dista1 << std::endl; + std::cout << std::endl; + std::cout << "* Hausdorff distance2 f: " << distb0 << std::endl; + std::cout << "* Hausdorff distance2 b: " << distb1 << std::endl; + // assert(dista0 == distb0); + // assert(dista1 == distb1); +} + +int main(int argc, char** argv) { + + const double error_bound = 0.05; + const std::size_t num_samples = 1000; + std::cout << std::endl << "* error bound: " << error_bound << std::endl; + std::cout << std::endl << "* number of samples: " << num_samples << std::endl; + const std::string filepath = (argc > 1 ? argv[1] : "data/blobby.off"); + + // ------------------------------------------------------------------------ // + // Examples. + + // remeshing_tetrahedon_example(error_bound); + // interior_triangle_example(error_bound); + // perturbing_mesh_example(filepath, error_bound); + // moving_mesh_example(filepath, filepath, 5, error_bound); + + // ------------------------------------------------------------------------ // + // Tests. + + Approximate_hd_wrapper apprx_hd(num_samples); + // Naive_bounded_error_hd_wrapper naive_hd(error_bound); + Bounded_error_hd_wrapper bound_hd(error_bound); + + // --- Testing basic properties. + + // test_synthetic_data(apprx_hd); + // test_synthetic_data(naive_hd); + // test_synthetic_data(bound_hd); + + // --- Compare on common meshes. + + // test_one_versus_another(apprx_hd, naive_hd); + // test_one_versus_another(naive_hd, bound_hd); + // test_one_versus_another(bound_hd, apprx_hd); + + // --- Compare on real meshes. + + const std::string filepath1 = (argc > 1 ? argv[1] : "data/blobby.off"); + const std::string filepath2 = (argc > 2 ? argv[2] : "data/tetrahedron-remeshed.off"); + + // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); + // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); + test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + + // ------------------------------------------------------------------------ // + std::cout << std::endl; +} From 841ad3b8b1b16996da0d5080503507dee36fb81c Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 7 Apr 2021 13:53:10 +0200 Subject: [PATCH 130/349] fixed bug introduced in 2d4c254 --- .../hausdorff_bounded_error_distance_example.cpp | 6 +++--- .../AABB_traversal_traits_with_Hausdorff_distance.h | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 1c3c89a692d..5f3e82b28e9 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -620,20 +620,20 @@ int main(int argc, char** argv) { // Tests. Approximate_hd_wrapper apprx_hd(num_samples); - // Naive_bounded_error_hd_wrapper naive_hd(error_bound); + Naive_bounded_error_hd_wrapper naive_hd(error_bound); Bounded_error_hd_wrapper bound_hd(error_bound); // --- Testing basic properties. // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); - // test_synthetic_data(bound_hd); + test_synthetic_data(bound_hd); // --- Compare on common meshes. // test_one_versus_another(apprx_hd, naive_hd); // test_one_versus_another(naive_hd, bound_hd); - // test_one_versus_another(bound_hd, apprx_hd); + test_one_versus_another(bound_hd, apprx_hd); // --- Compare on real meshes. diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index b27075adcb2..0f2f33c99ef 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -67,13 +67,13 @@ namespace CGAL { const AABBTraits& traits, const TriangleMesh& tm2, const VPM2& vpm2, - const double h_upper_current_global, + const double /*h_upper_current_global*/, const double h_lower_init, const double h_upper_init, const double h_v0_lower_init, const double h_v1_lower_init, const double h_v2_lower_init ) : m_traits(traits), m_tm2(tm2), m_vpm2(vpm2) { // Initialize the global and local bounds with the given values - h_upper_global = h_upper_current_global; + // h_upper_global = h_upper_current_global; h_local_lower = h_lower_init; h_local_upper = h_upper_init; h_v0_lower = h_v0_lower_init; @@ -181,7 +181,8 @@ namespace CGAL { // Check whether investigating the bbox can still lower the Hausdorff // distance and improve the current global bound. If so, enter the box. - if ( dist <= std::min(h_local_lower, h_upper_global) ) { + // if ( dist <= std::min(h_local_lower, h_upper_global) ) { + if ( dist <= h_local_lower ) { return std::make_pair(true, -dist); } else { return std::make_pair(false, 0); @@ -206,7 +207,7 @@ namespace CGAL { // its vertex point map const VPM2& m_vpm2; // Current global upper bound on the Hausdorff distance - double h_upper_global; + // double h_upper_global; // Local Hausdorff bounds for the query triangle double h_local_upper; double h_local_lower; From 3b7931dcd91095383c102f165236c431afbfe4c6 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 8 Apr 2021 15:50:49 +0200 Subject: [PATCH 131/349] added timings test --- ...usdorff_bounded_error_distance_example.cpp | 61 +++++++++++++++---- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 5f3e82b28e9..f9918452a8a 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -58,19 +58,20 @@ struct Bounded_error_hd_wrapper { } }; +void get_mesh(const std::string filepath, Surface_mesh& mesh) { + + mesh.clear(); + std::ifstream input(filepath); + input >> mesh; + std::cout << "* getting mesh with " << mesh.number_of_faces() << " faces" << std::endl; +} + void get_meshes( const std::string filepath1, const std::string filepath2, Surface_mesh& mesh1, Surface_mesh& mesh2) { - mesh1.clear(); - std::ifstream input1(filepath1); - input1 >> mesh1; - std::cout << "* getting mesh with " << mesh1.number_of_faces() << " faces" << std::endl; - - mesh2.clear(); - std::ifstream input2(filepath2); - input2 >> mesh2; - std::cout << "* getting mesh with " << mesh2.number_of_faces() << " faces" << std::endl; + get_mesh(filepath1, mesh1); + get_mesh(filepath2, mesh2); } void save_mesh(const Surface_mesh& mesh, const std::string filepath) { @@ -600,13 +601,40 @@ void test_real_meshes( // assert(dista1 == distb1); } +template< +typename FunctionWrapper> +void test_timings(const std::string filepath, const FunctionWrapper& functor) { + + std::cout.precision(20); + std::cout << std::endl << "* testing timing: " << functor.name() << std::endl; + + Timer timer; + Surface_mesh mesh1, mesh2; + get_meshes(filepath, filepath, mesh1, mesh2); + + timer.reset(); + timer.start(); + functor(mesh1, mesh2); + timer.stop(); + std::cout << "* time 0 (sec.): " << timer.time() << std::endl; + + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(FT(0), FT(0), FT(1))), mesh2); + + timer.reset(); + timer.start(); + functor(mesh1, mesh2); + timer.stop(); + std::cout << "* time 1 (sec.): " << timer.time() << std::endl; +} + int main(int argc, char** argv) { const double error_bound = 0.05; const std::size_t num_samples = 1000; std::cout << std::endl << "* error bound: " << error_bound << std::endl; std::cout << std::endl << "* number of samples: " << num_samples << std::endl; - const std::string filepath = (argc > 1 ? argv[1] : "data/blobby.off"); + std::string filepath = (argc > 1 ? argv[1] : "data/blobby.off"); // ------------------------------------------------------------------------ // // Examples. @@ -627,13 +655,13 @@ int main(int argc, char** argv) { // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); - test_synthetic_data(bound_hd); + // test_synthetic_data(bound_hd); // --- Compare on common meshes. // test_one_versus_another(apprx_hd, naive_hd); // test_one_versus_another(naive_hd, bound_hd); - test_one_versus_another(bound_hd, apprx_hd); + // test_one_versus_another(bound_hd, apprx_hd); // --- Compare on real meshes. @@ -642,7 +670,14 @@ int main(int argc, char** argv) { // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); - test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + + // --- Compare timings. + + filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); + // test_timings(filepath, apprx_hd); + // test_timings(filepath, naive_hd); + test_timings(filepath, bound_hd); // ------------------------------------------------------------------------ // std::cout << std::endl; From 0333778b96a8df5e9e8cd37d119ed643fc6d135e Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 8 Apr 2021 16:22:32 +0200 Subject: [PATCH 132/349] added face matching, not finished --- .../CGAL/boost/graph/parameters_interface.h | 1 + ...usdorff_bounded_error_distance_example.cpp | 3 +- .../CGAL/Polygon_mesh_processing/distance.h | 51 +++++++++++++++---- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/parameters_interface.h b/BGL/include/CGAL/boost/graph/parameters_interface.h index eebd236eaca..af56fba11a8 100644 --- a/BGL/include/CGAL/boost/graph/parameters_interface.h +++ b/BGL/include/CGAL/boost/graph/parameters_interface.h @@ -120,6 +120,7 @@ CGAL_add_named_parameter(do_not_modify_t, do_not_modify, do_not_modify) CGAL_add_named_parameter(allow_self_intersections_t, allow_self_intersections, allow_self_intersections) CGAL_add_named_parameter(non_manifold_feature_map_t, non_manifold_feature_map, non_manifold_feature_map) CGAL_add_named_parameter(polyhedral_envelope_epsilon_t, polyhedral_envelope_epsilon, polyhedral_envelope_epsilon) +CGAL_add_named_parameter(match_faces_t, match_faces, match_faces) // List of named parameters that we use in the package 'Surface Mesh Simplification' CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index f9918452a8a..d8ffb99f8aa 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -54,7 +54,8 @@ struct Bounded_error_hd_wrapper { std::string name() const { return "bounded error"; } Bounded_error_hd_wrapper(const double error_bound) : m_error_bound(error_bound) { } double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { - return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound); + return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound, + CGAL::parameters::match_faces(false)); } }; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 2b0d2af3fd5..ac392030750 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1326,6 +1326,7 @@ double bounded_error_Hausdorff_impl( const TriangleMesh& tm1, const TriangleMesh& tm2, const typename Kernel::FT& error_bound, + const bool compare_meshes, VPM1 vpm1, VPM2 vpm2) { @@ -1357,15 +1358,30 @@ double bounded_error_Hausdorff_impl( #endif Heap_type; + std::vector tm1_only, tm2_only; + std::vector< std::pair > common; + + TM1_tree tm1_tree; + TM2_tree tm2_tree; + if (compare_meshes) { + match_faces(tm1, tm2, std::back_inserter(common), + std::back_inserter(tm1_only), std::back_inserter(tm2_only)); + tm1_tree.insert(tm1_only.begin(), tm1_only.end(), tm1, vpm1); + tm2_tree.insert(tm2_only.begin(), tm2_only.end(), tm2, vpm2); + CGAL_assertion_msg(false, "TODO: FINISH MATCHING!"); + } else { + tm1_tree.insert(faces(tm1).begin(), faces(tm1).end(), tm1, vpm1); + tm2_tree.insert(faces(tm2).begin(), faces(tm2).end(), tm2, vpm2); + } + // Build an AABB tree on tm1 - TM1_tree tm1_tree( faces(tm1).begin(), faces(tm1).end(), tm1, vpm1 ); tm1_tree.build(); tm1_tree.accelerate_distance_queries(); // Build an AABB tree on tm2 - TM2_tree tm2_tree( faces(tm2).begin(), faces(tm2).end(), tm2, vpm2 ); tm2_tree.build(); tm2_tree.accelerate_distance_queries(); + std::pair hint = tm2_tree.any_reference_point_and_id(); // Build traversal traits for tm1_tree @@ -1627,6 +1643,12 @@ double bounded_error_Hausdorff_naive_impl( * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` * must be available in `TriangleMesh`.} * \cgalParamNEnd + * \cgalParamNBegin{match_faces} + * \cgalParamDescription{a boolean tag that turns on the preprocessing step that filters out all faces, + * which belong to both meshes and hence do not contribute to the final distance} + * \cgalParamType{Boolean} + * \cgalParamDefault{true} + * \cgalParamNEnd * \cgalNamedParamsEnd */ template< class Concurrency_tag, @@ -1642,18 +1664,25 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, typedef typename GetGeomTraits::type Geom_traits; - typedef typename GetVertexPointMap::const_type Vpm1; - typedef typename GetVertexPointMap::const_type Vpm2; + typedef typename GetVertexPointMap::const_type Vpm1; + typedef typename GetVertexPointMap::const_type Vpm2; - using parameters::choose_parameter; - using parameters::get_parameter; + using parameters::choose_parameter; + using parameters::get_parameter; - Vpm1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), - get_const_property_map(vertex_point, tm1)); - Vpm2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), - get_const_property_map(vertex_point, tm2)); + Vpm1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, tm1)); + Vpm2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, tm2)); - return internal::bounded_error_Hausdorff_impl(tm1, tm2, error_bound, vpm1, vpm2); + const bool match_faces1 = parameters::choose_parameter( + parameters::get_parameter(np1, internal_np::match_faces), true); + const bool match_faces2 = parameters::choose_parameter( + parameters::get_parameter(np2, internal_np::match_faces), true); + const bool match_faces = match_faces1 && match_faces2; + + return internal::bounded_error_Hausdorff_impl( + tm1, tm2, error_bound, match_faces, vpm1, vpm2); } From ffc8953a42860ad91db108c8d2f124a27fd412d5 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 8 Apr 2021 16:25:38 +0200 Subject: [PATCH 133/349] caching data --- .../include/CGAL/Polygon_mesh_processing/distance.h | 4 ++-- .../internal/AABB_traversal_traits_with_Hausdorff_distance.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index ac392030750..4f0257bf12a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1334,8 +1334,8 @@ double bounded_error_Hausdorff_impl( CGAL_assertion_msg (is_triangle, "One of the meshes is not triangulated. Distance computing impossible."); - typedef AABB_face_graph_triangle_primitive TM1_primitive; - typedef AABB_face_graph_triangle_primitive TM2_primitive; + typedef AABB_face_graph_triangle_primitive TM1_primitive; + typedef AABB_face_graph_triangle_primitive TM2_primitive; typedef AABB_tree< AABB_traits > TM1_tree; typedef AABB_tree< AABB_traits > TM2_tree; typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 0f2f33c99ef..4f1df94247d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -223,7 +223,7 @@ namespace CGAL { template class Hausdorff_primitive_traits_tm1 { - typedef AABB_face_graph_triangle_primitive TM2_primitive; + typedef AABB_face_graph_triangle_primitive TM2_primitive; typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; typedef typename AABBTraits::Primitive Primitive; typedef typename AABBTraits::Bounding_box Bounding_box; From a255f692dc5a74599e1c1c93d6790cadd8f7ea91 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 8 Apr 2021 17:07:13 +0200 Subject: [PATCH 134/349] matching faces finished, still needs several more tests --- ...usdorff_bounded_error_distance_example.cpp | 9 +++--- .../CGAL/Polygon_mesh_processing/distance.h | 31 ++++++++++++------- ...traversal_traits_with_Hausdorff_distance.h | 20 ++---------- 3 files changed, 26 insertions(+), 34 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index d8ffb99f8aa..aba8294bd8d 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -54,8 +54,7 @@ struct Bounded_error_hd_wrapper { std::string name() const { return "bounded error"; } Bounded_error_hd_wrapper(const double error_bound) : m_error_bound(error_bound) { } double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { - return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound, - CGAL::parameters::match_faces(false)); + return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound); } }; @@ -656,13 +655,13 @@ int main(int argc, char** argv) { // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); - // test_synthetic_data(bound_hd); + test_synthetic_data(bound_hd); // --- Compare on common meshes. // test_one_versus_another(apprx_hd, naive_hd); // test_one_versus_another(naive_hd, bound_hd); - // test_one_versus_another(bound_hd, apprx_hd); + test_one_versus_another(bound_hd, apprx_hd); // --- Compare on real meshes. @@ -671,7 +670,7 @@ int main(int argc, char** argv) { // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); - // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); // --- Compare timings. diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 4f0257bf12a..7b9aac5296f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1361,31 +1361,45 @@ double bounded_error_Hausdorff_impl( std::vector tm1_only, tm2_only; std::vector< std::pair > common; + const auto faces1 = faces(tm1); + const auto faces2 = faces(tm2); + + CGAL_assertion(faces1.size() > 0); + CGAL_assertion(faces2.size() > 0); + TM1_tree tm1_tree; TM2_tree tm2_tree; if (compare_meshes) { match_faces(tm1, tm2, std::back_inserter(common), std::back_inserter(tm1_only), std::back_inserter(tm2_only)); + + if (tm1_only.size() == 0) return 0.0; + if (tm2_only.size() == 0) return 0.0; + CGAL_assertion(tm1_only.size() > 0); + CGAL_assertion(tm2_only.size() > 0); + tm1_tree.insert(tm1_only.begin(), tm1_only.end(), tm1, vpm1); tm2_tree.insert(tm2_only.begin(), tm2_only.end(), tm2, vpm2); - CGAL_assertion_msg(false, "TODO: FINISH MATCHING!"); } else { - tm1_tree.insert(faces(tm1).begin(), faces(tm1).end(), tm1, vpm1); - tm2_tree.insert(faces(tm2).begin(), faces(tm2).end(), tm2, vpm2); + tm1_tree.insert(faces1.begin(), faces1.end(), tm1, vpm1); + tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); } // Build an AABB tree on tm1 tm1_tree.build(); - tm1_tree.accelerate_distance_queries(); + const bool is_tm1_memory_ok = tm1_tree.accelerate_distance_queries(); + CGAL_assertion(is_tm1_memory_ok); // Build an AABB tree on tm2 tm2_tree.build(); - tm2_tree.accelerate_distance_queries(); + const bool is_tm2_memory_ok = tm2_tree.accelerate_distance_queries(); + CGAL_assertion(is_tm2_memory_ok); std::pair hint = tm2_tree.any_reference_point_and_id(); // Build traversal traits for tm1_tree - Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, hint.first ); + Hausdorff_primitive_traits_tm1 traversal_traits_tm1( + tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, hint.first ); // Find candidate triangles in TM1 which might realise the Hausdorff bound // TODO Initialize the distances on all the vertices first and store those. @@ -1398,12 +1412,7 @@ double bounded_error_Hausdorff_impl( Heap_type candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); Hausdorff_bounds global_bounds = traversal_traits_tm1.get_global_bounds(); - #ifdef CGAL_HAUSDORFF_DEBUG - std::cout << "Culled " << traversal_traits_tm1.get_num_culled_triangles() << " out of " << tm1.num_faces() << std::endl; - #endif - double squared_error_bound = error_bound * error_bound; - while ( (global_bounds.second - global_bounds.first > error_bound) && !candidate_triangles.empty() ) { // Get the first triangle and its Hausdorff bounds from the candidate set diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 4f1df94247d..b463496fd5b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -254,8 +254,6 @@ namespace CGAL { // Initialize the global bounds with 0., they will only grow. h_lower = 0.; h_upper = 0.; - // Initialize number of culled triangles - m_investigated_on_tm1 = 0; } // Explore the whole tree, i.e. always enter children if the methods @@ -265,9 +263,6 @@ namespace CGAL { // Compute the explicit Hausdorff distance to the given primitive void intersection(const Query&, const Primitive& primitive) { - /* Have reached a single triangle, process it */ - m_investigated_on_tm1++; - // Map to transform faces of TM1 to actual triangles Triangle_from_face_descriptor_map m_face_to_triangle_map( &m_tm1, m_vpm1 ); Triangle_3 candidate_triangle = get(m_face_to_triangle_map, primitive.id()); @@ -277,9 +272,8 @@ namespace CGAL { // seen from the three vertices? // Call Culling on B with the single triangle found. - Hausdorff_primitive_traits_tm2< - Tree_traits, Triangle_3, Kernel, TriangleMesh, VPM2 - > traversal_traits_tm2( + Hausdorff_primitive_traits_tm2 + traversal_traits_tm2( m_tm2_tree.traits(), m_tm2, m_vpm2, (h_upper == 0.) ? std::numeric_limits::infinity() : h_upper, // Only pass current global bounds if they have been established yet std::numeric_limits::infinity(), @@ -304,7 +298,6 @@ namespace CGAL { // together with the local bounds it obtained to sind it to subdivision // later m_candidiate_triangles.push( Candidate_triangle(candidate_triangle, local_bounds) ); - pq.push( Candidate_triangle(candidate_triangle, local_bounds) ); } // Determine whether child nodes will still contribute to a larger @@ -363,11 +356,6 @@ namespace CGAL { return Hausdorff_bounds( h_lower, h_upper ); } - int get_num_culled_triangles() - { - return (m_tm1.num_faces() - m_investigated_on_tm1); - } - private: const AABBTraits& m_traits; // The two triangle meshes @@ -383,10 +371,6 @@ namespace CGAL { double h_upper; // List of candidate triangles with their Hausdorff bounds attached Heap_type m_candidiate_triangles; - // Heap of candidate triangles with their Hausdorff bounds attached - Heap_type pq; - // Number of triangles investigated in the procedure - int m_investigated_on_tm1; }; } From 410b03bc1f5ace3012451cdaa42f25498e638663 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 9 Apr 2021 10:46:01 +0200 Subject: [PATCH 135/349] added z-shaped test --- ...usdorff_bounded_error_distance_example.cpp | 69 +++++++++++++++---- .../CGAL/Polygon_mesh_processing/distance.h | 4 ++ 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index aba8294bd8d..f0e53517943 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -215,7 +215,7 @@ void test_0(const FunctionWrapper& functor, const bool save = false) { std::cout.precision(20); Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 0 ----" << std::endl; + std::cout << " ---- testing 0 ---- " << std::endl; mesh1.add_vertex(Point_3(0, 0, 0)); mesh1.add_vertex(Point_3(2, 0, 0)); @@ -243,7 +243,7 @@ void test_1(const FunctionWrapper& functor, const bool save = false) { std::cout.precision(20); Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 1 ----" << std::endl; + std::cout << " ---- testing 1 ---- " << std::endl; mesh1.add_vertex(Point_3(0, 0, 0)); mesh1.add_vertex(Point_3(2, 0, 0)); @@ -274,7 +274,7 @@ void test_2(const FunctionWrapper& functor, const bool save = false) { std::cout.precision(20); Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 2 ----" << std::endl; + std::cout << " ---- testing 2 ---- " << std::endl; mesh1.add_vertex(Point_3(0, 0, 0)); mesh1.add_vertex(Point_3(2, 0, 0)); @@ -306,7 +306,7 @@ void test_3(const FunctionWrapper& functor, const bool save = false) { std::cout.precision(20); Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 3 ----" << std::endl; + std::cout << " ---- testing 3 ---- " << std::endl; mesh1.add_vertex(Point_3(0, 0, 0)); mesh1.add_vertex(Point_3(2, 0, 0)); @@ -337,7 +337,7 @@ void test_4(const FunctionWrapper& functor, const bool save = false) { std::cout.precision(20); Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 4 ----" << std::endl; + std::cout << " ---- testing 4 ---- " << std::endl; mesh1.add_vertex(Point_3(0, 0, 0)); mesh1.add_vertex(Point_3(2, 0, 0)); @@ -369,7 +369,7 @@ void test_5(const FunctionWrapper& functor, const bool save = false) { std::cout.precision(20); Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 5 ----" << std::endl; + std::cout << " ---- testing 5 ---- " << std::endl; mesh1.add_vertex(Point_3(0, 0, 0)); mesh1.add_vertex(Point_3(2, 0, 0)); @@ -401,7 +401,7 @@ void test_6(const FunctionWrapper& functor, const bool save = false) { std::cout.precision(20); Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 6 ----" << std::endl; + std::cout << " ---- testing 6 ---- " << std::endl; mesh1.add_vertex(Point_3(0, 0, 0)); mesh1.add_vertex(Point_3(2, 0, 0)); @@ -438,7 +438,7 @@ void test_7(const FunctionWrapper& functor, const bool save = false) { std::cout.precision(20); Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 7 ----" << std::endl; + std::cout << " ---- testing 7 ---- " << std::endl; mesh1.add_vertex(Point_3(0, 0, 0)); mesh1.add_vertex(Point_3(2, 0, 0)); @@ -475,7 +475,7 @@ void test_8(const FunctionWrapper& functor, const bool save = false) { std::cout.precision(20); Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 8 ----" << std::endl; + std::cout << " ---- testing 8 ---- " << std::endl; mesh1.add_vertex(Point_3(0, 0, 0)); mesh1.add_vertex(Point_3(2, 0, 0)); @@ -503,6 +503,50 @@ void test_8(const FunctionWrapper& functor, const bool save = false) { // assert(distb == 2.0); } +template +void test_9(const FunctionWrapper& functor, const bool save = false) { + + // Two meshes partially overlap, have 2 triangles in common and each one has + // two its own trianles. All triangles form a Z shape where the height is 1. + // The expected result is sqrt(2) = 1.4142135623730951455. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 9 ---- " << std::endl; + + auto v0 = mesh1.add_vertex(Point_3(0, 0, 0)); + auto v1 = mesh1.add_vertex(Point_3(1, 0, 0)); + auto v2 = mesh1.add_vertex(Point_3(0, 1, 0)); + auto v3 = mesh1.add_vertex(Point_3(1, 1, 0)); + auto v4 = mesh1.add_vertex(Point_3(1, 0, 1)); + auto v5 = mesh1.add_vertex(Point_3(1, 1, 1)); + mesh1.add_face(v0, v1, v2); + mesh1.add_face(v2, v1, v3); + mesh1.add_face(v1, v4, v3); + mesh1.add_face(v3, v4, v5); + if (save) save_mesh(mesh1, "mesh1"); + + v0 = mesh2.add_vertex(Point_3(2, 0, 1)); + v1 = mesh2.add_vertex(Point_3(1, 0, 0)); + v2 = mesh2.add_vertex(Point_3(2, 1, 1)); + v3 = mesh2.add_vertex(Point_3(1, 1, 0)); + v4 = mesh2.add_vertex(Point_3(1, 0, 1)); + v5 = mesh2.add_vertex(Point_3(1, 1, 1)); + mesh2.add_face(v1, v4, v3); + mesh2.add_face(v3, v4, v5); + mesh2.add_face(v4, v0, v5); + mesh2.add_face(v5, v0, v2); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected sqrt(2)): " << dista << std::endl; + std::cout << "* HInverted distance (expected sqrt(2)): " << distb << std::endl; + // assert(dista == 1.4142135623730951455); + // assert(distb == 1.4142135623730951455); +} + template void test_synthetic_data(const FunctionWrapper& functor) { @@ -518,6 +562,7 @@ void test_synthetic_data(const FunctionWrapper& functor) { test_6(functor); // 1 to multiple test_7(functor); test_8(functor); + test_9(functor); // overlapping } template< @@ -541,7 +586,7 @@ void test_one_versus_another( // TEST 0. // Load and compare. // The expected distance is 0. - std::cout << " ---- testing 0 ----" << std::endl; + std::cout << " ---- testing 0 ---- " << std::endl; const double dista0 = functor1(mesh1, mesh2); const double distb0 = functor2(mesh1, mesh2); std::cout << "* Hausdorff distance1: " << dista0 << std::endl; @@ -555,7 +600,7 @@ void test_one_versus_another( // TEST 1. // Translate by 1 unit distance and compare. // The expected distance is 1. - std::cout << " ---- testing 1 ----" << std::endl; + std::cout << " ---- testing 1 ---- " << std::endl; const double dista1 = functor1(mesh1, mesh2); const double distb1 = functor2(mesh1, mesh2); std::cout << "* Hausdorff distance1: " << dista1 << std::endl; @@ -586,7 +631,7 @@ void test_real_meshes( // Load and compare. std::cout << std::endl; - std::cout << " ---- testing ----" << std::endl; + std::cout << " ---- testing ---- " << std::endl; const double dista0 = functor1(mesh1, mesh2); const double dista1 = functor1(mesh2, mesh1); const double distb0 = functor2(mesh1, mesh2); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 7b9aac5296f..b97ee5d3326 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1373,6 +1373,10 @@ double bounded_error_Hausdorff_impl( match_faces(tm1, tm2, std::back_inserter(common), std::back_inserter(tm1_only), std::back_inserter(tm2_only)); + // std::cout << "common: " << common.size() << std::endl; + // std::cout << "tm1 only: " << tm1_only.size() << std::endl; + // std::cout << "tm2 only: " << tm2_only.size() << std::endl; + if (tm1_only.size() == 0) return 0.0; if (tm2_only.size() == 0) return 0.0; CGAL_assertion(tm1_only.size() > 0); From dc9e9585039216eb38d725523664de0736744603 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 9 Apr 2021 12:35:18 +0200 Subject: [PATCH 136/349] removed some asserts and types, added const, make it compile with epeck, but epeck gives wrong results --- ...usdorff_bounded_error_distance_example.cpp | 44 ++---- .../CGAL/Polygon_mesh_processing/distance.h | 117 ++++++++------- ...traversal_traits_with_Hausdorff_distance.h | 140 +++++++++--------- 3 files changed, 142 insertions(+), 159 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index f0e53517943..b8c7c10d7e8 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -17,7 +17,7 @@ using SCK = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; -using Kernel = EPICK; +using Kernel = EPECK; using FT = typename Kernel::FT; using Point_3 = typename Kernel::Point_3; using Vector_3 = typename Kernel::Vector_3; @@ -231,8 +231,6 @@ void test_0(const FunctionWrapper& functor, const bool save = false) { std::cout << "* Hausdorff distance (expected 0): " << dista << std::endl; std::cout << "* HInverted distance (expected 0): " << distb << std::endl; - // assert(dista == 0.0); - // assert(dista == distb); } template @@ -262,8 +260,6 @@ void test_1(const FunctionWrapper& functor, const bool save = false) { std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; std::cout << "* HInverted distance (expected 1): " << distb << std::endl; - // assert(dista == 1.0); - // assert(dista == distb); } template @@ -293,8 +289,6 @@ void test_2(const FunctionWrapper& functor, const bool save = false) { std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; std::cout << "* HInverted distance (expected 1): " << distb << std::endl; - // assert(dista == 1.0); - // assert(dista == distb); } template @@ -302,7 +296,7 @@ void test_3(const FunctionWrapper& functor, const bool save = false) { // One triangle is orthogonal to the other one and shares a common edge // that is moved 1 unit distance away. - // Expected distances are 1.4142135623730951455 and 2. + // Expected distances are sqrt(2) and 2. std::cout.precision(20); Surface_mesh mesh1, mesh2; @@ -323,10 +317,8 @@ void test_3(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - std::cout << "* Hausdorff distance (expected 1.41): " << dista << std::endl; - std::cout << "* HInverted distance (expected 2.00): " << distb << std::endl; - // assert(dista == 1.4142135623730951455); - // assert(distb == 2.0); + std::cout << "* Hausdorff distance (expected sqrt(2)): " << dista << std::endl; + std::cout << "* HInverted distance (expected 2 ): " << distb << std::endl; } template @@ -356,8 +348,6 @@ void test_4(const FunctionWrapper& functor, const bool save = false) { std::cout << "* Hausdorff distance (expected 1.22): " << dista << std::endl; std::cout << "* HInverted distance (expected 1.22): " << distb << std::endl; - // assert(dista == 1.2247448713915889407); - // assert(dista == distb); } template @@ -388,8 +378,6 @@ void test_5(const FunctionWrapper& functor, const bool save = false) { std::cout << "* Hausdorff distance (expected 1.73): " << dista << std::endl; std::cout << "* HInverted distance (expected 2.12): " << distb << std::endl; - // assert(dista == 1.7320508075688771932); - // assert(distb == 2.1213203435596423851); } template @@ -425,8 +413,6 @@ void test_6(const FunctionWrapper& functor, const bool save = false) { std::cout << "* Hausdorff distance (expected 0.0): " << dista << std::endl; std::cout << "* HInverted distance (expected 0.7): " << distb << std::endl; - // assert(dista == 0.0); - // assert(distb == 0.70710678118654757274); } template @@ -462,8 +448,6 @@ void test_7(const FunctionWrapper& functor, const bool save = false) { std::cout << "* Hausdorff distance (expected 0.50): " << dista << std::endl; std::cout << "* HInverted distance (expected 0.86): " << distb << std::endl; - // assert(dista == 0.5); - // assert(distb == 0.86602540378443859659); } template @@ -499,8 +483,6 @@ void test_8(const FunctionWrapper& functor, const bool save = false) { std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; std::cout << "* HInverted distance (expected 2): " << distb << std::endl; - // assert(dista == 1.0); - // assert(distb == 2.0); } template @@ -508,7 +490,7 @@ void test_9(const FunctionWrapper& functor, const bool save = false) { // Two meshes partially overlap, have 2 triangles in common and each one has // two its own trianles. All triangles form a Z shape where the height is 1. - // The expected result is sqrt(2) = 1.4142135623730951455. + // The expected result is 1. std::cout.precision(20); Surface_mesh mesh1, mesh2; @@ -541,10 +523,8 @@ void test_9(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - std::cout << "* Hausdorff distance (expected sqrt(2)): " << dista << std::endl; - std::cout << "* HInverted distance (expected sqrt(2)): " << distb << std::endl; - // assert(dista == 1.4142135623730951455); - // assert(distb == 1.4142135623730951455); + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; + std::cout << "* HInverted distance (expected 1): " << distb << std::endl; } template @@ -591,7 +571,6 @@ void test_one_versus_another( const double distb0 = functor2(mesh1, mesh2); std::cout << "* Hausdorff distance1: " << dista0 << std::endl; std::cout << "* Hausdorff distance2: " << distb0 << std::endl; - // assert(dista0 == distb0); std::cout << "* traslating by 1 unit ..." << std::endl; PMP::transform(Affine_transformation_3(CGAL::Translation(), @@ -605,7 +584,6 @@ void test_one_versus_another( const double distb1 = functor2(mesh1, mesh2); std::cout << "* Hausdorff distance1: " << dista1 << std::endl; std::cout << "* Hausdorff distance2: " << distb1 << std::endl; - // assert(dista1 == distb1); } template< @@ -642,8 +620,6 @@ void test_real_meshes( std::cout << std::endl; std::cout << "* Hausdorff distance2 f: " << distb0 << std::endl; std::cout << "* Hausdorff distance2 b: " << distb1 << std::endl; - // assert(dista0 == distb0); - // assert(dista1 == distb1); } template< @@ -706,7 +682,7 @@ int main(int argc, char** argv) { // test_one_versus_another(apprx_hd, naive_hd); // test_one_versus_another(naive_hd, bound_hd); - test_one_versus_another(bound_hd, apprx_hd); + // test_one_versus_another(bound_hd, apprx_hd); // --- Compare on real meshes. @@ -715,14 +691,14 @@ int main(int argc, char** argv) { // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); - test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); // --- Compare timings. filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); - test_timings(filepath, bound_hd); + // test_timings(filepath, bound_hd); // ------------------------------------------------------------------------ // std::cout << std::endl; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index b97ee5d3326..8c19e94abbf 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1330,7 +1330,7 @@ double bounded_error_Hausdorff_impl( VPM1 vpm1, VPM2 vpm2) { - CGAL_assertion_code( bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2) ); + CGAL_assertion_code( const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2) ); CGAL_assertion_msg (is_triangle, "One of the meshes is not triangulated. Distance computing impossible."); @@ -1341,13 +1341,12 @@ double bounded_error_Hausdorff_impl( typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; typedef typename Tree_traits::Point_and_primitive_id Point_and_primitive_id; + typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Triangle_3 Triangle_3; typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef std::pair Hausdorff_bounds; - typename Kernel::Compute_squared_distance_3 squared_distance; typedef @@ -1399,7 +1398,7 @@ double bounded_error_Hausdorff_impl( const bool is_tm2_memory_ok = tm2_tree.accelerate_distance_queries(); CGAL_assertion(is_tm2_memory_ok); - std::pair hint = tm2_tree.any_reference_point_and_id(); + const auto hint = tm2_tree.any_reference_point_and_id(); // Build traversal traits for tm1_tree Hausdorff_primitive_traits_tm1 traversal_traits_tm1( @@ -1414,13 +1413,13 @@ double bounded_error_Hausdorff_impl( // TODO Is there a better/faster data structure than the Heap used here? // Can already build a sorted structure while collecting the candidates Heap_type candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); - Hausdorff_bounds global_bounds = traversal_traits_tm1.get_global_bounds(); + auto global_bounds = traversal_traits_tm1.get_global_bounds(); - double squared_error_bound = error_bound * error_bound; + const FT squared_error_bound = error_bound * error_bound; while ( (global_bounds.second - global_bounds.first > error_bound) && !candidate_triangles.empty() ) { // Get the first triangle and its Hausdorff bounds from the candidate set - Candidate_triangle triangle_and_bound = candidate_triangles.top(); + const Candidate_triangle triangle_and_bound = candidate_triangles.top(); // Remove it from the candidate set as it will be processed now candidate_triangles.pop(); @@ -1428,20 +1427,20 @@ double bounded_error_Hausdorff_impl( // i.e. if its Upper Bound is higher than the currently known best lower bound // and the difference between the bounds to be obtained is larger than the // user given error. - Hausdorff_bounds triangle_bounds = triangle_and_bound.m_bounds; + const auto triangle_bounds = triangle_and_bound.m_bounds; if ( (triangle_bounds.second > global_bounds.first) && (triangle_bounds.second - triangle_bounds.first > error_bound) ) { // Get the triangle that is to be subdivided and read its vertices - Triangle_3 triangle_for_subdivision = triangle_and_bound.m_triangle; - Point_3 v0 = triangle_for_subdivision.vertex(0); - Point_3 v1 = triangle_for_subdivision.vertex(1); - Point_3 v2 = triangle_for_subdivision.vertex(2); + const Triangle_3 triangle_for_subdivision = triangle_and_bound.m_triangle; + const Point_3 v0 = triangle_for_subdivision.vertex(0); + const Point_3 v1 = triangle_for_subdivision.vertex(1); + const Point_3 v2 = triangle_for_subdivision.vertex(2); // Check second stopping condition: All three vertices of the triangle // are projected onto the same triangle in TM2 - Point_and_primitive_id closest_triangle_v0 = tm2_tree.closest_point_and_primitive(v0); - Point_and_primitive_id closest_triangle_v1 = tm2_tree.closest_point_and_primitive(v1); - Point_and_primitive_id closest_triangle_v2 = tm2_tree.closest_point_and_primitive(v2); + const Point_and_primitive_id closest_triangle_v0 = tm2_tree.closest_point_and_primitive(v0); + const Point_and_primitive_id closest_triangle_v1 = tm2_tree.closest_point_and_primitive(v1); + const Point_and_primitive_id closest_triangle_v2 = tm2_tree.closest_point_and_primitive(v2); if( (closest_triangle_v0.second == closest_triangle_v1.second) && (closest_triangle_v1.second == closest_triangle_v2.second)) { // The upper bound of this triangle is the actual Hausdorff distance of // the triangle to the second mesh. Use it as new global lower bound. @@ -1463,10 +1462,10 @@ double bounded_error_Hausdorff_impl( } // Subdivide the triangle into four smaller triangles - Point_3 v01 = midpoint( v0, v1 ); - Point_3 v02 = midpoint( v0, v2 ); - Point_3 v12 = midpoint( v1, v2 ); - std::array sub_triangles = { + const Point_3 v01 = midpoint( v0, v1 ); + const Point_3 v02 = midpoint( v0, v2 ); + const Point_3 v12 = midpoint( v1, v2 ); + const std::array sub_triangles = { Triangle_3( v0, v01, v02), Triangle_3( v1, v01, v12), Triangle_3( v2, v02, v12), Triangle_3( v01, v02, v12) }; @@ -1478,15 +1477,15 @@ double bounded_error_Hausdorff_impl( tm2_tree.traits(), tm2, vpm2, triangle_bounds.first, triangle_bounds.second, - std::numeric_limits::infinity(), - std::numeric_limits::infinity(), - std::numeric_limits::infinity(), - std::numeric_limits::infinity() + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity() ); tm2_tree.traversal_with_priority(sub_triangles[i], traversal_traits_tm2); // Update global lower Hausdorff bound according to the obtained local bounds - Hausdorff_bounds local_bounds = traversal_traits_tm2.get_local_bounds(); + const auto local_bounds = traversal_traits_tm2.get_local_bounds(); if (local_bounds.first > global_bounds.first) { global_bounds.first = local_bounds.first; } @@ -1499,13 +1498,13 @@ double bounded_error_Hausdorff_impl( } // Update global upper Hausdorff bound after subdivision - double current_max = candidate_triangles.top().m_bounds.second; + const FT current_max = candidate_triangles.top().m_bounds.second; global_bounds.second = std::max(current_max, global_bounds.first); } } // Return linear interpolation between found lower and upper bound - return (global_bounds.first + global_bounds.second) / 2.; + return CGAL::to_double((global_bounds.first + global_bounds.second) / FT(2)); #if !defined(CGAL_LINKED_WITH_TBB) CGAL_static_assertion_msg (!(boost::is_convertible::value), @@ -1518,7 +1517,7 @@ double bounded_error_Hausdorff_impl( template -double recursive_hausdorff_subdivision( +typename Kernel::FT recursive_hausdorff_subdivision( const Point_3& v0, const Point_3& v1, const Point_3& v2, @@ -1527,7 +1526,7 @@ double recursive_hausdorff_subdivision( { // If all edge lengths of the triangle are below the error_bound, // return maximum of the distances of the three points to TM2 (via TM2_tree). - double max_squared_edge_length = + const auto max_squared_edge_length = std::max( std::max( squared_distance( v0, v1 ), @@ -1544,9 +1543,9 @@ double recursive_hausdorff_subdivision( } // Else subdivide the triangle and proceed recursively - Point_3 v01 = midpoint( v0, v1 ); - Point_3 v02 = midpoint( v0, v2 ); - Point_3 v12 = midpoint( v1, v2 ); + const Point_3 v01 = midpoint( v0, v1 ); + const Point_3 v02 = midpoint( v0, v2 ); + const Point_3 v12 = midpoint( v1, v2 ); return std::max ( std::max( @@ -1572,7 +1571,7 @@ double bounded_error_Hausdorff_naive_impl( VPM1 vpm1, VPM2 vpm2) { - CGAL_assertion_code( bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2) ); + CGAL_assertion_code( const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2) ); CGAL_assertion_msg (is_triangle, "One of the meshes is not triangulated. Distance computing impossible."); @@ -1581,13 +1580,14 @@ double bounded_error_Hausdorff_naive_impl( typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Triangle_3 Triangle_3; // Initially, no lower bound is known - double squared_lower_bound = 0.; + FT squared_lower_bound = FT(0); // Work with squares in the following, only draw sqrt at the very end - double squared_error_bound = error_bound * error_bound; + const FT squared_error_bound = error_bound * error_bound; // Build an AABB tree on tm2 TM2_tree tm2_tree( faces(tm2).begin(), faces(tm2).end(), tm2, vpm2 ); @@ -1595,20 +1595,21 @@ double bounded_error_Hausdorff_naive_impl( tm2_tree.accelerate_distance_queries(); // Build a map to obtain actual triangles from the face descriptors of tm1. - Triangle_from_face_descriptor_map face_to_triangle_map( &tm1, vpm1 ); + const Triangle_from_face_descriptor_map face_to_triangle_map( &tm1, vpm1 ); // Iterate over the triangles of TM1. - for(face_descriptor fd : faces(tm1)) + for(const face_descriptor& fd : faces(tm1)) { // Get the vertices of the face and pass them on to a recursive method. - Triangle_3 triangle = get(face_to_triangle_map, fd); - Point_3 v0 = triangle.vertex(0); - Point_3 v1 = triangle.vertex(1); - Point_3 v2 = triangle.vertex(2); + const Triangle_3 triangle = get(face_to_triangle_map, fd); + const Point_3 v0 = triangle.vertex(0); + const Point_3 v1 = triangle.vertex(1); + const Point_3 v2 = triangle.vertex(2); // Recursively process the current triangle to obtain a lower bound on // its Hausdorff distance. - double triangle_bound = recursive_hausdorff_subdivision( v0, v1, v2, tm2_tree, squared_error_bound ); + const FT triangle_bound = recursive_hausdorff_subdivision( + v0, v1, v2, tm2_tree, squared_error_bound ); // Store the largest lower bound. if( triangle_bound > squared_lower_bound ) { @@ -1617,7 +1618,7 @@ double bounded_error_Hausdorff_naive_impl( } // Return linear interpolation between found upper and lower bound - return (approximate_sqrt( squared_lower_bound )); + return CGAL::sqrt(CGAL::to_double( squared_lower_bound )); #if !defined(CGAL_LINKED_WITH_TBB) CGAL_static_assertion_msg (!(boost::is_convertible::value), @@ -1660,7 +1661,8 @@ double bounded_error_Hausdorff_naive_impl( * \cgalParamDescription{a boolean tag that turns on the preprocessing step that filters out all faces, * which belong to both meshes and hence do not contribute to the final distance} * \cgalParamType{Boolean} - * \cgalParamDefault{true} + * \cgalParamDefault{false} + * \cgalParamExtra{Both `np1` and `np2` must have this tag true in order to activate this preprocessing.} * \cgalParamNEnd * \cgalNamedParamsEnd */ @@ -1676,6 +1678,7 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, { typedef typename GetGeomTraits::type Geom_traits; + using FT = typename Geom_traits::FT; typedef typename GetVertexPointMap::const_type Vpm1; typedef typename GetVertexPointMap::const_type Vpm2; @@ -1689,13 +1692,14 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, get_const_property_map(vertex_point, tm2)); const bool match_faces1 = parameters::choose_parameter( - parameters::get_parameter(np1, internal_np::match_faces), true); + parameters::get_parameter(np1, internal_np::match_faces), false); const bool match_faces2 = parameters::choose_parameter( - parameters::get_parameter(np2, internal_np::match_faces), true); + parameters::get_parameter(np2, internal_np::match_faces), false); const bool match_faces = match_faces1 && match_faces2; + const FT error_threshold = static_cast(error_bound); return internal::bounded_error_Hausdorff_impl( - tm1, tm2, error_bound, match_faces, vpm1, vpm2); + tm1, tm2, error_threshold, match_faces, vpm1, vpm2); } @@ -1734,19 +1738,22 @@ double bounded_error_Hausdorff_distance_naive( const TriangleMesh& tm1, { typedef typename GetGeomTraits::type Geom_traits; + using FT = typename Geom_traits::FT; - typedef typename GetVertexPointMap::const_type Vpm1; - typedef typename GetVertexPointMap::const_type Vpm2; + typedef typename GetVertexPointMap::const_type Vpm1; + typedef typename GetVertexPointMap::const_type Vpm2; - using parameters::choose_parameter; - using parameters::get_parameter; + using parameters::choose_parameter; + using parameters::get_parameter; - Vpm1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), - get_const_property_map(vertex_point, tm1)); - Vpm2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), - get_const_property_map(vertex_point, tm2)); + Vpm1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, tm1)); + Vpm2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, tm2)); - return internal::bounded_error_Hausdorff_naive_impl(tm1, tm2, error_bound, vpm1, vpm2); + const FT error_threshold = static_cast(error_bound); + return internal::bounded_error_Hausdorff_naive_impl( + tm1, tm2, error_threshold, vpm1, vpm2); } template< class Concurrency_tag, diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index b463496fd5b..0c948b63525 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -23,20 +23,19 @@ namespace CGAL { - typedef std::pair Hausdorff_bounds; - /** * @struct Candidate_triangle */ template struct Candidate_triangle { + using FT = typename Kernel::FT; typedef typename Kernel::Triangle_3 Triangle_3; - Candidate_triangle(const Triangle_3& triangle, const Hausdorff_bounds& bounds) + Candidate_triangle(const Triangle_3& triangle, const std::pair& bounds) : m_triangle(triangle), m_bounds(bounds) {} Triangle_3 m_triangle; - Hausdorff_bounds m_bounds; + std::pair m_bounds; #if BOOST_VERSION >= 105000 bool operator<(const Candidate_triangle& other) const { return m_bounds.second < other.m_bounds.second; } @@ -57,20 +56,20 @@ namespace CGAL { typedef ::CGAL::AABB_node Node; typedef typename AABBTraits::Bounding_box Bounding_box; typename Kernel::Construct_projected_point_3 project_point; + typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Vector_3 Vector_3; public: - typedef double Priority; + typedef FT Priority; Hausdorff_primitive_traits_tm2( const AABBTraits& traits, const TriangleMesh& tm2, const VPM2& vpm2, - const double /*h_upper_current_global*/, - const double h_lower_init, const double h_upper_init, - const double h_v0_lower_init, const double h_v1_lower_init, const double h_v2_lower_init - ) + const FT /*h_upper_current_global*/, + const FT h_lower_init, const FT h_upper_init, + const FT h_v0_lower_init, const FT h_v1_lower_init, const FT h_v2_lower_init) : m_traits(traits), m_tm2(tm2), m_vpm2(vpm2) { // Initialize the global and local bounds with the given values // h_upper_global = h_upper_current_global; @@ -101,27 +100,27 @@ namespace CGAL { */ // The query object is a triangle from TM1, get its vertices - Point_3 v0 = query.vertex(0); - Point_3 v1 = query.vertex(1); - Point_3 v2 = query.vertex(2); + const Point_3 v0 = query.vertex(0); + const Point_3 v1 = query.vertex(1); + const Point_3 v2 = query.vertex(2); // Compute distances of the vertices to the primitive triangle in TM2 - Triangle_from_face_descriptor_map face_to_triangle_map(&m_tm2, m_vpm2); - double v0_dist = approximate_sqrt(squared_distance( - project_point( get(face_to_triangle_map, primitive.id()), v0), v0 ) ); + const Triangle_from_face_descriptor_map face_to_triangle_map(&m_tm2, m_vpm2); + const FT v0_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( + project_point( get(face_to_triangle_map, primitive.id()), v0), v0 ) ))); if (v0_dist < h_v0_lower) h_v0_lower = v0_dist; - double v1_dist = approximate_sqrt(squared_distance( - project_point( get(face_to_triangle_map, primitive.id()), v1), v1 ) ); + const FT v1_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( + project_point( get(face_to_triangle_map, primitive.id()), v1), v1 ) ))); if (v1_dist < h_v1_lower) h_v1_lower = v1_dist; - double v2_dist = approximate_sqrt(squared_distance( - project_point( get(face_to_triangle_map, primitive.id()), v2), v2 ) ); + const FT v2_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( + project_point( get(face_to_triangle_map, primitive.id()), v2), v2 ) ))); if (v2_dist < h_v2_lower) h_v2_lower = v2_dist; // Get the distance as maximizers over all vertices - double distance_upper = std::max(std::max(v0_dist,v1_dist),v2_dist); - double distance_lower = std::max(std::max(h_v0_lower,h_v1_lower),h_v2_lower); + const FT distance_upper = std::max(std::max(v0_dist,v1_dist),v2_dist); + const FT distance_lower = std::max(std::max(h_v0_lower,h_v1_lower),h_v2_lower); // Since we are at the level of a single triangle in TM2, distance_upper is // actually the correct Hausdorff distance from the query triangle in @@ -135,18 +134,18 @@ namespace CGAL { std::pair do_intersect_with_priority(const Query& query, const Node& node) const { // Get the bounding box of the nodes - Bounding_box bbox = node.bbox(); + const Bounding_box bbox = node.bbox(); // Get the vertices of the query triangle - Point_3 v0 = query.vertex(0); - Point_3 v1 = query.vertex(1); - Point_3 v2 = query.vertex(2); + const Point_3 v0 = query.vertex(0); + const Point_3 v1 = query.vertex(1); + const Point_3 v2 = query.vertex(2); // Find the axis aligned bbox of the triangle - Point_3 tri_min = Point_3 ( + const Point_3 tri_min = Point_3 ( std::min(std::min( v0.x(), v1.x()), v2.x() ), std::min(std::min( v0.y(), v1.y()), v2.y() ), std::min(std::min( v0.z(), v1.z()), v2.z() ) ); - Point_3 tri_max = Point_3 ( + const Point_3 tri_max = Point_3 ( std::max(std::max( v0.x(), v1.x()), v2.x() ), std::max(std::max( v0.y(), v1.y()), v2.y() ), std::max(std::max( v0.z(), v1.z()), v2.z() ) @@ -154,21 +153,21 @@ namespace CGAL { // Compute distance of the bounding boxes // Distance along the x-axis - double dist_x = 0.; + FT dist_x = FT(0); if ( tri_max.x() < bbox.min(0) ) { dist_x = bbox.min(0) - tri_max.x(); } else if ( bbox.max(0) < tri_min.x() ) { dist_x = tri_min.x() - bbox.max(0); } // Distance along the y-axis - double dist_y = 0.; + FT dist_y = FT(0); if ( tri_max.y() < bbox.min(1) ) { dist_y = bbox.min(1) - tri_max.y(); } else if ( bbox.max(1) < tri_min.y() ) { dist_y = tri_min.y() - bbox.max(1); } // Distance along the y-axis - double dist_z = 0.; + FT dist_z = FT(0); if ( tri_max.z() < bbox.min(2) ) { dist_z = bbox.min(2) - tri_max.z(); } else if ( bbox.max(2) < tri_min.z() ) { @@ -177,7 +176,7 @@ namespace CGAL { // Lower bound on the distance between the two bounding boxes is given // as the length of the diagonal of the bounding box between them - double dist = approximate_sqrt( Vector_3(dist_x,dist_y,dist_z).squared_length() ); + const FT dist = static_cast(CGAL::sqrt( CGAL::to_double(Vector_3(dist_x,dist_y,dist_z).squared_length() ))); // Check whether investigating the bbox can still lower the Hausdorff // distance and improve the current global bound. If so, enter the box. @@ -185,7 +184,7 @@ namespace CGAL { if ( dist <= h_local_lower ) { return std::make_pair(true, -dist); } else { - return std::make_pair(false, 0); + return std::make_pair(false, FT(0)); } } @@ -195,9 +194,9 @@ namespace CGAL { } // Return the local Hausdorff bounds computed for the passed query triangle - Hausdorff_bounds get_local_bounds() + std::pair get_local_bounds() { - return Hausdorff_bounds( h_local_lower, h_local_upper ); + return std::make_pair( h_local_lower, h_local_upper ); } private: @@ -207,13 +206,13 @@ namespace CGAL { // its vertex point map const VPM2& m_vpm2; // Current global upper bound on the Hausdorff distance - // double h_upper_global; + // FT h_upper_global; // Local Hausdorff bounds for the query triangle - double h_local_upper; - double h_local_lower; - double h_v0_lower; - double h_v1_lower; - double h_v2_lower; + FT h_local_upper; + FT h_local_lower; + FT h_v0_lower; + FT h_v1_lower; + FT h_v2_lower; }; @@ -228,6 +227,7 @@ namespace CGAL { typedef typename AABBTraits::Primitive Primitive; typedef typename AABBTraits::Bounding_box Bounding_box; typedef ::CGAL::AABB_node Node; + typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Vector_3 Vector_3; typedef typename Kernel::Triangle_3 Triangle_3; @@ -244,7 +244,7 @@ namespace CGAL { Heap_type; public: - typedef double Priority; + typedef FT Priority; Hausdorff_primitive_traits_tm1( const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2, @@ -252,8 +252,8 @@ namespace CGAL { : m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2), m_tm2_tree(tree) { // Initialize the global bounds with 0., they will only grow. - h_lower = 0.; - h_upper = 0.; + h_lower = FT(0); + h_upper = FT(0); } // Explore the whole tree, i.e. always enter children if the methods @@ -264,8 +264,8 @@ namespace CGAL { void intersection(const Query&, const Primitive& primitive) { // Map to transform faces of TM1 to actual triangles - Triangle_from_face_descriptor_map m_face_to_triangle_map( &m_tm1, m_vpm1 ); - Triangle_3 candidate_triangle = get(m_face_to_triangle_map, primitive.id()); + const Triangle_from_face_descriptor_map m_face_to_triangle_map( &m_tm1, m_vpm1 ); + const Triangle_3 candidate_triangle = get(m_face_to_triangle_map, primitive.id()); // TODO Can we initialize the bounds here, s.t. we don't start with infty? // Can we initialize the bounds depending on the closest points in tm2 @@ -275,17 +275,17 @@ namespace CGAL { Hausdorff_primitive_traits_tm2 traversal_traits_tm2( m_tm2_tree.traits(), m_tm2, m_vpm2, - (h_upper == 0.) ? std::numeric_limits::infinity() : h_upper, // Only pass current global bounds if they have been established yet - std::numeric_limits::infinity(), - std::numeric_limits::infinity(), - std::numeric_limits::infinity(), - std::numeric_limits::infinity(), - std::numeric_limits::infinity() + (h_upper == FT(0)) ? std::numeric_limits::infinity() : h_upper, // Only pass current global bounds if they have been established yet + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity() ); m_tm2_tree.traversal_with_priority(candidate_triangle, traversal_traits_tm2); // Update global Hausdorff bounds according to the obtained local bounds - Hausdorff_bounds local_bounds = traversal_traits_tm2.get_local_bounds(); + const auto local_bounds = traversal_traits_tm2.get_local_bounds(); if (local_bounds.first > h_lower) { h_lower = local_bounds.first; @@ -307,35 +307,35 @@ namespace CGAL { { /* Have reached a node, determine whether or not to enter it */ // Get the bounding box of the nodes - Bounding_box bbox = node.bbox(); + const Bounding_box bbox = node.bbox(); // Compute its center - Point_3 center = Point_3( - (bbox.min(0) + bbox.max(0)) / 2, - (bbox.min(1) + bbox.max(1)) / 2, - (bbox.min(2) + bbox.max(2)) / 2); + const Point_3 center = Point_3( + (bbox.min(0) + bbox.max(0)) / FT(2), + (bbox.min(1) + bbox.max(1)) / FT(2), + (bbox.min(2) + bbox.max(2)) / FT(2)); // Find the point from TM2 closest to the center - Point_3 closest = m_tm2_tree.closest_point(center); + const Point_3 closest = m_tm2_tree.closest_point(center); // Compute the difference vector between the bbox center and the closest // point in tm2 Vector_3 difference = Vector_3( closest, center ); // Shift the vector to be the difference between the farthest corner // of the bounding box away from the closest point on TM2 - double diff_x = (bbox.max(0) - bbox.min(0)) / 2; - if (difference.x() < 0) diff_x = diff_x * -1.; - double diff_y = (bbox.max(1) - bbox.min(1)) / 2; - if (difference.y() < 0) diff_y = diff_y * -1.; - double diff_z = (bbox.max(2) - bbox.min(2)) / 2; - if (difference.z() < 0) diff_z = diff_z * -1.; + FT diff_x = (bbox.max(0) - bbox.min(0)) / FT(2); + if (difference.x() < 0) diff_x = diff_x * -FT(1); + FT diff_y = (bbox.max(1) - bbox.min(1)) / FT(2); + if (difference.y() < 0) diff_y = diff_y * -FT(1); + FT diff_z = (bbox.max(2) - bbox.min(2)) / FT(2); + if (difference.z() < 0) diff_z = diff_z * -FT(1); difference = difference + Vector_3( diff_x, diff_y, diff_z ); // Compute distance from the farthest corner of the bbox to the closest // point in TM2 - double dist = approximate_sqrt( difference.squared_length() ); + const FT dist = static_cast(CGAL::sqrt(CGAL::to_double( difference.squared_length() ))); // If the distance is larger than the global lower bound, enter the node, i.e. return true. if (dist > h_lower) { return std::make_pair(true, dist); } else { - return std::make_pair(false, 0); + return std::make_pair(false, FT(0)); } } @@ -351,9 +351,9 @@ namespace CGAL { } // Return the local Hausdorff bounds computed for the passed query triangle - Hausdorff_bounds get_global_bounds() + std::pair get_global_bounds() { - return Hausdorff_bounds( h_lower, h_upper ); + return std::make_pair( h_lower, h_upper ); } private: @@ -367,8 +367,8 @@ namespace CGAL { // AABB tree for the second triangle meshes const TM2_tree& m_tm2_tree; // Global Hausdorff bounds to be taken track of during the traversal - double h_lower; - double h_upper; + FT h_lower; + FT h_upper; // List of candidate triangles with their Hausdorff bounds attached Heap_type m_candidiate_triangles; }; From 63db510aef18b08a2d3c3ddd91639bf1bff62c58 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 9 Apr 2021 16:03:55 +0200 Subject: [PATCH 137/349] epeck support, fixed bug with infinity value --- ...ausdorff_bounded_error_distance_example.cpp | 8 ++++---- .../CGAL/Polygon_mesh_processing/distance.h | 8 ++++---- ..._traversal_traits_with_Hausdorff_distance.h | 18 ++++++++++++------ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index b8c7c10d7e8..6b8ea1b4a7a 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -17,7 +17,7 @@ using SCK = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; -using Kernel = EPECK; +using Kernel = EPICK; using FT = typename Kernel::FT; using Point_3 = typename Kernel::Point_3; using Vector_3 = typename Kernel::Vector_3; @@ -682,7 +682,7 @@ int main(int argc, char** argv) { // test_one_versus_another(apprx_hd, naive_hd); // test_one_versus_another(naive_hd, bound_hd); - // test_one_versus_another(bound_hd, apprx_hd); + test_one_versus_another(bound_hd, apprx_hd); // --- Compare on real meshes. @@ -691,14 +691,14 @@ int main(int argc, char** argv) { // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); - // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); // --- Compare timings. filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); - // test_timings(filepath, bound_hd); + test_timings(filepath, bound_hd); // ------------------------------------------------------------------------ // std::cout << std::endl; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 8c19e94abbf..c2019c4f467 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1477,10 +1477,10 @@ double bounded_error_Hausdorff_impl( tm2_tree.traits(), tm2, vpm2, triangle_bounds.first, triangle_bounds.second, - std::numeric_limits::infinity(), - std::numeric_limits::infinity(), - std::numeric_limits::infinity(), - std::numeric_limits::infinity() + infinity_value(), + infinity_value(), + infinity_value(), + infinity_value() ); tm2_tree.traversal_with_priority(sub_triangles[i], traversal_traits_tm2); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 0c948b63525..1f0efe89503 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -23,6 +23,12 @@ namespace CGAL { + // Infinity. + template + static FT infinity_value() { + return FT(1000000000000); + } + /** * @struct Candidate_triangle */ @@ -275,12 +281,12 @@ namespace CGAL { Hausdorff_primitive_traits_tm2 traversal_traits_tm2( m_tm2_tree.traits(), m_tm2, m_vpm2, - (h_upper == FT(0)) ? std::numeric_limits::infinity() : h_upper, // Only pass current global bounds if they have been established yet - std::numeric_limits::infinity(), - std::numeric_limits::infinity(), - std::numeric_limits::infinity(), - std::numeric_limits::infinity(), - std::numeric_limits::infinity() + (h_upper == FT(0)) ? infinity_value() : h_upper, // Only pass current global bounds if they have been established yet + infinity_value(), + infinity_value(), + infinity_value(), + infinity_value(), + infinity_value() ); m_tm2_tree.traversal_with_priority(candidate_triangle, traversal_traits_tm2); From 4d107b3b8d59d33ca58e3077a0292607d712cdbb Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 9 Apr 2021 16:34:03 +0200 Subject: [PATCH 138/349] using std priority queue instead of boost heap --- .../CGAL/Polygon_mesh_processing/distance.h | 29 +++++++------------ ...traversal_traits_with_Hausdorff_distance.h | 28 +++++------------- 2 files changed, 18 insertions(+), 39 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index c2019c4f467..bca0dec0b1e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1334,12 +1334,11 @@ double bounded_error_Hausdorff_impl( CGAL_assertion_msg (is_triangle, "One of the meshes is not triangulated. Distance computing impossible."); - typedef AABB_face_graph_triangle_primitive TM1_primitive; - typedef AABB_face_graph_triangle_primitive TM2_primitive; + typedef AABB_face_graph_triangle_primitive TM1_primitive; + typedef AABB_face_graph_triangle_primitive TM2_primitive; typedef AABB_tree< AABB_traits > TM1_tree; typedef AABB_tree< AABB_traits > TM2_tree; typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; - typedef typename Tree_traits::Point_and_primitive_id Point_and_primitive_id; typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; @@ -1349,14 +1348,6 @@ double bounded_error_Hausdorff_impl( typename Kernel::Compute_squared_distance_3 squared_distance; - typedef - #if BOOST_VERSION >= 105000 - boost::heap::priority_queue< Candidate_triangle, boost::heap::compare< std::greater > > > - #else - std::priority_queue< Candidate_triangle > - #endif - Heap_type; - std::vector tm1_only, tm2_only; std::vector< std::pair > common; @@ -1405,14 +1396,14 @@ double bounded_error_Hausdorff_impl( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, hint.first ); // Find candidate triangles in TM1 which might realise the Hausdorff bound -// TODO Initialize the distances on all the vertices first and store those. -// TODO Do not traverse TM1, but only TM2, i.e. reduce to Culling on TM2 (Can do this for all triangles in TM1 in parallel) + // TODO Initialize the distances on all the vertices first and store those. + // TODO Do not traverse TM1, but only TM2, i.e. reduce to Culling on TM2 (Can do this for all triangles in TM1 in parallel) tm1_tree.traversal_with_priority( Point_3(0,0,0), traversal_traits_tm1 ); // dummy point given as query as not needed // TODO Is there a better/faster data structure than the Heap used here? // Can already build a sorted structure while collecting the candidates - Heap_type candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); + auto candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); auto global_bounds = traversal_traits_tm1.get_global_bounds(); const FT squared_error_bound = error_bound * error_bound; @@ -1427,20 +1418,20 @@ double bounded_error_Hausdorff_impl( // i.e. if its Upper Bound is higher than the currently known best lower bound // and the difference between the bounds to be obtained is larger than the // user given error. - const auto triangle_bounds = triangle_and_bound.m_bounds; + const auto& triangle_bounds = triangle_and_bound.m_bounds; if ( (triangle_bounds.second > global_bounds.first) && (triangle_bounds.second - triangle_bounds.first > error_bound) ) { // Get the triangle that is to be subdivided and read its vertices - const Triangle_3 triangle_for_subdivision = triangle_and_bound.m_triangle; + const Triangle_3& triangle_for_subdivision = triangle_and_bound.m_triangle; const Point_3 v0 = triangle_for_subdivision.vertex(0); const Point_3 v1 = triangle_for_subdivision.vertex(1); const Point_3 v2 = triangle_for_subdivision.vertex(2); // Check second stopping condition: All three vertices of the triangle // are projected onto the same triangle in TM2 - const Point_and_primitive_id closest_triangle_v0 = tm2_tree.closest_point_and_primitive(v0); - const Point_and_primitive_id closest_triangle_v1 = tm2_tree.closest_point_and_primitive(v1); - const Point_and_primitive_id closest_triangle_v2 = tm2_tree.closest_point_and_primitive(v2); + const auto closest_triangle_v0 = tm2_tree.closest_point_and_primitive(v0); + const auto closest_triangle_v1 = tm2_tree.closest_point_and_primitive(v1); + const auto closest_triangle_v2 = tm2_tree.closest_point_and_primitive(v2); if( (closest_triangle_v0.second == closest_triangle_v1.second) && (closest_triangle_v1.second == closest_triangle_v2.second)) { // The upper bound of this triangle is the actual Hausdorff distance of // the triangle to the second mesh. Use it as new global lower bound. diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 1f0efe89503..bc5efe7b439 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -42,14 +42,8 @@ namespace CGAL { Triangle_3 m_triangle; std::pair m_bounds; - - #if BOOST_VERSION >= 105000 - bool operator<(const Candidate_triangle& other) const { return m_bounds.second < other.m_bounds.second; } - bool operator>(const Candidate_triangle& other) const { return m_bounds.second > other.m_bounds.second; } - #else - bool operator>(const Candidate_triangle& other) const { return m_bounds.second < other.m_bounds.second; } - bool operator<(const Candidate_triangle& other) const { return m_bounds.second > other.m_bounds.second; } - #endif + bool operator>(const Candidate_triangle& other) const { return m_bounds.second < other.m_bounds.second; } + bool operator<(const Candidate_triangle& other) const { return m_bounds.second > other.m_bounds.second; } }; /** @@ -200,7 +194,7 @@ namespace CGAL { } // Return the local Hausdorff bounds computed for the passed query triangle - std::pair get_local_bounds() + std::pair get_local_bounds() const { return std::make_pair( h_local_lower, h_local_upper ); } @@ -228,7 +222,7 @@ namespace CGAL { template class Hausdorff_primitive_traits_tm1 { - typedef AABB_face_graph_triangle_primitive TM2_primitive; + typedef AABB_face_graph_triangle_primitive TM2_primitive; typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; typedef typename AABBTraits::Primitive Primitive; typedef typename AABBTraits::Bounding_box Bounding_box; @@ -241,13 +235,7 @@ namespace CGAL { typedef AABB_tree< AABB_traits > TM2_tree; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef - #if BOOST_VERSION >= 105000 - boost::heap::priority_queue< Candidate_triangle, boost::heap::compare< std::greater > > > - #else - std::priority_queue< Candidate_triangle > - #endif - Heap_type; + typedef std::priority_queue< Candidate_triangle > Heap_type; public: typedef FT Priority; @@ -357,7 +345,7 @@ namespace CGAL { } // Return the local Hausdorff bounds computed for the passed query triangle - std::pair get_global_bounds() + std::pair get_global_bounds() const { return std::make_pair( h_lower, h_upper ); } @@ -368,8 +356,8 @@ namespace CGAL { const TriangleMesh& m_tm1; const TriangleMesh& m_tm2; // Their vertex-point-maps - const VPM1 m_vpm1; - const VPM2 m_vpm2; + const VPM1& m_vpm1; + const VPM2& m_vpm2; // AABB tree for the second triangle meshes const TM2_tree& m_tm2_tree; // Global Hausdorff bounds to be taken track of during the traversal From 95f124fd3054d670edd504e1b9bd895f29f66fcb Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 9 Apr 2021 16:50:34 +0200 Subject: [PATCH 139/349] added missing ref --- .../include/CGAL/Polygon_mesh_processing/distance.h | 2 +- .../internal/AABB_traversal_traits_with_Hausdorff_distance.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index bca0dec0b1e..8afb1aba022 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1403,7 +1403,7 @@ double bounded_error_Hausdorff_impl( // TODO Is there a better/faster data structure than the Heap used here? // Can already build a sorted structure while collecting the candidates - auto candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); + auto& candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); auto global_bounds = traversal_traits_tm1.get_global_bounds(); const FT squared_error_bound = error_bound * error_bound; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index bc5efe7b439..5951eb09818 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -340,7 +340,7 @@ namespace CGAL { // Return those triangles from TM1 which are candidates for including a // point realizing the Hausdorff distance - Heap_type get_candidate_triangles() { + Heap_type& get_candidate_triangles() { return m_candidiate_triangles; } From 50fc1cabd9397ae076e523d7e8d0b32d00c34d9a Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 9 Apr 2021 18:19:54 +0200 Subject: [PATCH 140/349] faster queries for close meshes, now traversal traits initial bounds depend on error_bound --- ...usdorff_bounded_error_distance_example.cpp | 7 ++++-- .../CGAL/Polygon_mesh_processing/distance.h | 8 +++--- ...traversal_traits_with_Hausdorff_distance.h | 25 +++++++++---------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 6b8ea1b4a7a..6041eea2afb 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -635,7 +635,7 @@ void test_timings(const std::string filepath, const FunctionWrapper& functor) { timer.reset(); timer.start(); - functor(mesh1, mesh2); + const double dista = functor(mesh1, mesh2); timer.stop(); std::cout << "* time 0 (sec.): " << timer.time() << std::endl; @@ -644,9 +644,12 @@ void test_timings(const std::string filepath, const FunctionWrapper& functor) { timer.reset(); timer.start(); - functor(mesh1, mesh2); + const double distb = functor(mesh1, mesh2); timer.stop(); std::cout << "* time 1 (sec.): " << timer.time() << std::endl; + + std::cout << "dista = " << dista << std::endl; + std::cout << "distb = " << distb << std::endl; } int main(int argc, char** argv) { diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 8afb1aba022..b01c7ca67ef 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1389,11 +1389,9 @@ double bounded_error_Hausdorff_impl( const bool is_tm2_memory_ok = tm2_tree.accelerate_distance_queries(); CGAL_assertion(is_tm2_memory_ok); - const auto hint = tm2_tree.any_reference_point_and_id(); - // Build traversal traits for tm1_tree Hausdorff_primitive_traits_tm1 traversal_traits_tm1( - tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, hint.first ); + tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, error_bound ); // Find candidate triangles in TM1 which might realise the Hausdorff bound // TODO Initialize the distances on all the vertices first and store those. @@ -1405,6 +1403,7 @@ double bounded_error_Hausdorff_impl( // Can already build a sorted structure while collecting the candidates auto& candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); auto global_bounds = traversal_traits_tm1.get_global_bounds(); + // std::cout << candidate_triangles.size() << std::endl; const FT squared_error_bound = error_bound * error_bound; while ( (global_bounds.second - global_bounds.first > error_bound) && !candidate_triangles.empty() ) { @@ -1470,7 +1469,6 @@ double bounded_error_Hausdorff_impl( triangle_bounds.second, infinity_value(), infinity_value(), - infinity_value(), infinity_value() ); tm2_tree.traversal_with_priority(sub_triangles[i], traversal_traits_tm2); @@ -1688,6 +1686,7 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, parameters::get_parameter(np2, internal_np::match_faces), false); const bool match_faces = match_faces1 && match_faces2; + CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); return internal::bounded_error_Hausdorff_impl( tm1, tm2, error_threshold, match_faces, vpm1, vpm2); @@ -1742,6 +1741,7 @@ double bounded_error_Hausdorff_distance_naive( const TriangleMesh& tm1, Vpm2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), get_const_property_map(vertex_point, tm2)); + CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); return internal::bounded_error_Hausdorff_naive_impl( tm1, tm2, error_threshold, vpm1, vpm2); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 5951eb09818..d4fa2108502 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -67,12 +67,10 @@ namespace CGAL { const AABBTraits& traits, const TriangleMesh& tm2, const VPM2& vpm2, - const FT /*h_upper_current_global*/, const FT h_lower_init, const FT h_upper_init, const FT h_v0_lower_init, const FT h_v1_lower_init, const FT h_v2_lower_init) : m_traits(traits), m_tm2(tm2), m_vpm2(vpm2) { // Initialize the global and local bounds with the given values - // h_upper_global = h_upper_current_global; h_local_lower = h_lower_init; h_local_upper = h_upper_init; h_v0_lower = h_v0_lower_init; @@ -125,8 +123,8 @@ namespace CGAL { // Since we are at the level of a single triangle in TM2, distance_upper is // actually the correct Hausdorff distance from the query triangle in // TM1 to the primitive triangle in TM2 - if ( distance_upper < h_local_upper ) h_local_upper = distance_upper; if ( distance_lower < h_local_lower ) h_local_lower = distance_lower; + if ( distance_upper < h_local_upper ) h_local_upper = distance_upper; } // Determine whether child nodes will still contribute to a smaller @@ -180,7 +178,6 @@ namespace CGAL { // Check whether investigating the bbox can still lower the Hausdorff // distance and improve the current global bound. If so, enter the box. - // if ( dist <= std::min(h_local_lower, h_upper_global) ) { if ( dist <= h_local_lower ) { return std::make_pair(true, -dist); } else { @@ -205,11 +202,9 @@ namespace CGAL { const TriangleMesh& m_tm2; // its vertex point map const VPM2& m_vpm2; - // Current global upper bound on the Hausdorff distance - // FT h_upper_global; // Local Hausdorff bounds for the query triangle - FT h_local_upper; FT h_local_lower; + FT h_local_upper; FT h_v0_lower; FT h_v1_lower; FT h_v2_lower; @@ -242,13 +237,15 @@ namespace CGAL { Hausdorff_primitive_traits_tm1( const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2, - const Point_3& ) + const FT& error_bound) : m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2), m_tm2_tree(tree) { - // Initialize the global bounds with 0., they will only grow. - h_lower = FT(0); - h_upper = FT(0); - } + + // Initialize the global bounds with 0., they will only grow. + // If we leave zero here then we are very slow even for big input error bounds! + h_lower = error_bound; // = FT(0); + h_upper = error_bound; // = FT(0); + } // Explore the whole tree, i.e. always enter children if the methods // do_intersect() below determines that it is worthwhile. @@ -269,7 +266,6 @@ namespace CGAL { Hausdorff_primitive_traits_tm2 traversal_traits_tm2( m_tm2_tree.traits(), m_tm2, m_vpm2, - (h_upper == FT(0)) ? infinity_value() : h_upper, // Only pass current global bounds if they have been established yet infinity_value(), infinity_value(), infinity_value(), @@ -314,6 +310,7 @@ namespace CGAL { Vector_3 difference = Vector_3( closest, center ); // Shift the vector to be the difference between the farthest corner // of the bounding box away from the closest point on TM2 + FT diff_x = (bbox.max(0) - bbox.min(0)) / FT(2); if (difference.x() < 0) diff_x = diff_x * -FT(1); FT diff_y = (bbox.max(1) - bbox.min(1)) / FT(2); @@ -321,11 +318,13 @@ namespace CGAL { FT diff_z = (bbox.max(2) - bbox.min(2)) / FT(2); if (difference.z() < 0) diff_z = diff_z * -FT(1); difference = difference + Vector_3( diff_x, diff_y, diff_z ); + // Compute distance from the farthest corner of the bbox to the closest // point in TM2 const FT dist = static_cast(CGAL::sqrt(CGAL::to_double( difference.squared_length() ))); // If the distance is larger than the global lower bound, enter the node, i.e. return true. + // std::cout << dist << " : " << h_lower << std::endl; if (dist > h_lower) { return std::make_pair(true, dist); } else { From ddb8c6a9ffe82da9acf8ae1b6a908be099383f3f Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 9 Apr 2021 18:48:15 +0200 Subject: [PATCH 141/349] fewer candidate triangles for distance > 0 --- .../AABB_traversal_traits_with_Hausdorff_distance.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index d4fa2108502..a421ef3e004 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -239,12 +239,12 @@ namespace CGAL { const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2, const FT& error_bound) : m_traits(traits), m_tm1(tm1), m_tm2(tm2), - m_vpm1(vpm1), m_vpm2(vpm2), m_tm2_tree(tree) { + m_vpm1(vpm1), m_vpm2(vpm2), m_tm2_tree(tree), m_error_bound(error_bound) { // Initialize the global bounds with 0., they will only grow. // If we leave zero here then we are very slow even for big input error bounds! - h_lower = error_bound; // = FT(0); - h_upper = error_bound; // = FT(0); + h_lower = m_error_bound; // = FT(0); + h_upper = m_error_bound; // = FT(0); } // Explore the whole tree, i.e. always enter children if the methods @@ -325,8 +325,8 @@ namespace CGAL { // If the distance is larger than the global lower bound, enter the node, i.e. return true. // std::cout << dist << " : " << h_lower << std::endl; - if (dist > h_lower) { - return std::make_pair(true, dist); + if (dist > h_lower && (dist - h_lower) > m_error_bound) { + return std::make_pair(true, dist); } else { return std::make_pair(false, FT(0)); } @@ -360,6 +360,7 @@ namespace CGAL { // AABB tree for the second triangle meshes const TM2_tree& m_tm2_tree; // Global Hausdorff bounds to be taken track of during the traversal + const FT& m_error_bound; FT h_lower; FT h_upper; // List of candidate triangles with their Hausdorff bounds attached From 56b77cfd9f4d142274a70ebb1c20de715ac1bc02 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 16 Apr 2021 16:17:55 +0200 Subject: [PATCH 142/349] fixed match faces + removed small optimization (not sure about it) --- .../include/CGAL/Polygon_mesh_processing/distance.h | 13 +++++-------- .../AABB_traversal_traits_with_Hausdorff_distance.h | 5 ++--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index b01c7ca67ef..02b50c33973 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1363,21 +1363,18 @@ double bounded_error_Hausdorff_impl( match_faces(tm1, tm2, std::back_inserter(common), std::back_inserter(tm1_only), std::back_inserter(tm2_only)); - // std::cout << "common: " << common.size() << std::endl; + // std::cout << "common t: " << common.size() << std::endl; // std::cout << "tm1 only: " << tm1_only.size() << std::endl; // std::cout << "tm2 only: " << tm2_only.size() << std::endl; if (tm1_only.size() == 0) return 0.0; - if (tm2_only.size() == 0) return 0.0; CGAL_assertion(tm1_only.size() > 0); - CGAL_assertion(tm2_only.size() > 0); tm1_tree.insert(tm1_only.begin(), tm1_only.end(), tm1, vpm1); - tm2_tree.insert(tm2_only.begin(), tm2_only.end(), tm2, vpm2); } else { tm1_tree.insert(faces1.begin(), faces1.end(), tm1, vpm1); - tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); } + tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); // Build an AABB tree on tm1 tm1_tree.build(); @@ -1650,7 +1647,7 @@ double bounded_error_Hausdorff_naive_impl( * \cgalParamDescription{a boolean tag that turns on the preprocessing step that filters out all faces, * which belong to both meshes and hence do not contribute to the final distance} * \cgalParamType{Boolean} - * \cgalParamDefault{false} + * \cgalParamDefault{true} * \cgalParamExtra{Both `np1` and `np2` must have this tag true in order to activate this preprocessing.} * \cgalParamNEnd * \cgalNamedParamsEnd @@ -1681,9 +1678,9 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, get_const_property_map(vertex_point, tm2)); const bool match_faces1 = parameters::choose_parameter( - parameters::get_parameter(np1, internal_np::match_faces), false); + parameters::get_parameter(np1, internal_np::match_faces), true); const bool match_faces2 = parameters::choose_parameter( - parameters::get_parameter(np2, internal_np::match_faces), false); + parameters::get_parameter(np2, internal_np::match_faces), true); const bool match_faces = match_faces1 && match_faces2; CGAL_precondition(error_bound >= 0.0); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index a421ef3e004..eaf710daf53 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -226,7 +226,6 @@ namespace CGAL { typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Vector_3 Vector_3; typedef typename Kernel::Triangle_3 Triangle_3; - typedef typename std::vector> Candidate_set; typedef AABB_tree< AABB_traits > TM2_tree; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; @@ -241,7 +240,7 @@ namespace CGAL { : m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2), m_tm2_tree(tree), m_error_bound(error_bound) { - // Initialize the global bounds with 0., they will only grow. + // Initialize the global bounds with 0.0, they will only grow. // If we leave zero here then we are very slow even for big input error bounds! h_lower = m_error_bound; // = FT(0); h_upper = m_error_bound; // = FT(0); @@ -325,7 +324,7 @@ namespace CGAL { // If the distance is larger than the global lower bound, enter the node, i.e. return true. // std::cout << dist << " : " << h_lower << std::endl; - if (dist > h_lower && (dist - h_lower) > m_error_bound) { + if (dist > h_lower /* && (dist - h_lower) > m_error_bound */) { return std::make_pair(true, dist); } else { return std::make_pair(false, FT(0)); From 81513fc8604df9c9e2cdfdf8d38b993324c38f18 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 16 Apr 2021 18:15:07 +0200 Subject: [PATCH 143/349] face descriptor is now stored in the candidate triangle to remember the realizing triangle --- .../CGAL/Polygon_mesh_processing/distance.h | 19 ++++++---- ...traversal_traits_with_Hausdorff_distance.h | 35 +++++++++++-------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 02b50c33973..8a28f607bcb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1345,6 +1345,7 @@ double bounded_error_Hausdorff_impl( typedef typename Kernel::Triangle_3 Triangle_3; typedef typename boost::graph_traits::face_descriptor face_descriptor; + using Candidate = Candidate_triangle; typename Kernel::Compute_squared_distance_3 squared_distance; @@ -1400,13 +1401,15 @@ double bounded_error_Hausdorff_impl( // Can already build a sorted structure while collecting the candidates auto& candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); auto global_bounds = traversal_traits_tm1.get_global_bounds(); - // std::cout << candidate_triangles.size() << std::endl; + + // std::cout << "number of candidate triangles 1: " << + // candidate_triangles.size() << std::endl; const FT squared_error_bound = error_bound * error_bound; while ( (global_bounds.second - global_bounds.first > error_bound) && !candidate_triangles.empty() ) { // Get the first triangle and its Hausdorff bounds from the candidate set - const Candidate_triangle triangle_and_bound = candidate_triangles.top(); + const Candidate triangle_and_bound = candidate_triangles.top(); // Remove it from the candidate set as it will be processed now candidate_triangles.pop(); @@ -1414,11 +1417,11 @@ double bounded_error_Hausdorff_impl( // i.e. if its Upper Bound is higher than the currently known best lower bound // and the difference between the bounds to be obtained is larger than the // user given error. - const auto& triangle_bounds = triangle_and_bound.m_bounds; + const auto& triangle_bounds = triangle_and_bound.bounds; if ( (triangle_bounds.second > global_bounds.first) && (triangle_bounds.second - triangle_bounds.first > error_bound) ) { // Get the triangle that is to be subdivided and read its vertices - const Triangle_3& triangle_for_subdivision = triangle_and_bound.m_triangle; + const Triangle_3& triangle_for_subdivision = triangle_and_bound.triangle; const Point_3 v0 = triangle_for_subdivision.vertex(0); const Point_3 v1 = triangle_for_subdivision.vertex(1); const Point_3 v2 = triangle_for_subdivision.vertex(2); @@ -1479,16 +1482,18 @@ double bounded_error_Hausdorff_impl( // TODO Additionally store the face descriptor of the parent from TM1 in the Candidate_triangle. // Add the subtriangle to the candidate list candidate_triangles.push( - Candidate_triangle(sub_triangles[i], local_bounds) - ); + Candidate(sub_triangles[i], local_bounds, triangle_and_bound.face) ); } // Update global upper Hausdorff bound after subdivision - const FT current_max = candidate_triangles.top().m_bounds.second; + const FT current_max = candidate_triangles.top().bounds.second; global_bounds.second = std::max(current_max, global_bounds.first); } } + // std::cout << "number of candidate triangles 2: " << + // candidate_triangles.size() << std::endl; + // Return linear interpolation between found lower and upper bound return CGAL::to_double((global_bounds.first + global_bounds.second) / FT(2)); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index eaf710daf53..e0095823213 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -29,21 +29,25 @@ namespace CGAL { return FT(1000000000000); } - /** - * @struct Candidate_triangle - */ - template + // Candidate triangle. + template struct Candidate_triangle { using FT = typename Kernel::FT; - typedef typename Kernel::Triangle_3 Triangle_3; + using Triangle_3 = typename Kernel::Triangle_3; - Candidate_triangle(const Triangle_3& triangle, const std::pair& bounds) - : m_triangle(triangle), m_bounds(bounds) {} + Candidate_triangle( + const Triangle_3& triangle, + const std::pair& bounds, + const FaceDescriptor& face) : + triangle(triangle), bounds(bounds), face(face) + { } - Triangle_3 m_triangle; - std::pair m_bounds; - bool operator>(const Candidate_triangle& other) const { return m_bounds.second < other.m_bounds.second; } - bool operator<(const Candidate_triangle& other) const { return m_bounds.second > other.m_bounds.second; } + Triangle_3 triangle; + std::pair bounds; + FaceDescriptor face; + + bool operator>(const Candidate_triangle& other) const { return bounds.second < other.bounds.second; } + bool operator<(const Candidate_triangle& other) const { return bounds.second > other.bounds.second; } }; /** @@ -229,7 +233,8 @@ namespace CGAL { typedef AABB_tree< AABB_traits > TM2_tree; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef std::priority_queue< Candidate_triangle > Heap_type; + using Candidate = Candidate_triangle; + typedef std::priority_queue Heap_type; public: typedef FT Priority; @@ -255,7 +260,7 @@ namespace CGAL { { // Map to transform faces of TM1 to actual triangles const Triangle_from_face_descriptor_map m_face_to_triangle_map( &m_tm1, m_vpm1 ); - const Triangle_3 candidate_triangle = get(m_face_to_triangle_map, primitive.id()); + const Triangle_3 triangle = get(m_face_to_triangle_map, primitive.id()); // TODO Can we initialize the bounds here, s.t. we don't start with infty? // Can we initialize the bounds depending on the closest points in tm2 @@ -271,7 +276,7 @@ namespace CGAL { infinity_value(), infinity_value() ); - m_tm2_tree.traversal_with_priority(candidate_triangle, traversal_traits_tm2); + m_tm2_tree.traversal_with_priority(triangle, traversal_traits_tm2); // Update global Hausdorff bounds according to the obtained local bounds const auto local_bounds = traversal_traits_tm2.get_local_bounds(); @@ -286,7 +291,7 @@ namespace CGAL { // Store the triangle given as primitive here as candidate triangle // together with the local bounds it obtained to sind it to subdivision // later - m_candidiate_triangles.push( Candidate_triangle(candidate_triangle, local_bounds) ); + m_candidiate_triangles.push( Candidate(triangle, local_bounds, primitive.id()) ); } // Determine whether child nodes will still contribute to a larger From 4ebbaba856136025d31f8db74bd2297a1c8c3acc Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 19 Apr 2021 14:00:03 +0200 Subject: [PATCH 144/349] added bunny benchmarks versus original paper --- ...usdorff_bounded_error_distance_example.cpp | 73 ++++++++++++++++++- .../CGAL/Polygon_mesh_processing/distance.h | 14 +++- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 6041eea2afb..70748051994 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -652,9 +652,74 @@ void test_timings(const std::string filepath, const FunctionWrapper& functor) { std::cout << "distb = " << distb << std::endl; } +template< +typename FunctionWrapper> +void test_bunny(const FunctionWrapper& functor, const bool save = false) { + + std::cout.precision(20); + const std::string filepath1 = "data/bunny1.off"; // approx 16.3K + const std::string filepath2 = "data/bunny2.off"; // approx 69.4K + + std::cout << std::endl << "* testing bunny:" << std::endl; + std::cout << "* name -> " << functor.name() << std::endl; + + Surface_mesh mesh1, mesh2; + get_meshes(filepath1, filepath2, mesh1, mesh2); + if (save) save_mesh(mesh1, "mesh1"); + if (save) save_mesh(mesh2, "mesh2"); + + // Get 3 times longest dimension. + const auto bbox = PMP::bbox(mesh2); + const FT dist1 = static_cast(CGAL::abs(bbox.xmax() - bbox.xmin())); + const FT dist2 = static_cast(CGAL::abs(bbox.ymax() - bbox.ymin())); + const FT dist3 = static_cast(CGAL::abs(bbox.zmax() - bbox.zmin())); + const FT dim = FT(3) * (CGAL::max)((CGAL::max)(dist1, dist2), dist3); + + // Get timings. + const int n = 5; // number of steps + const FT t = FT(1) / static_cast(n); // step + + Timer timer; + std::vector times; + times.reserve(n); + + for (int k = n; k >= 0; --k) { + auto mesh = mesh2; + const FT distance = k * t * dim; + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(distance, distance, distance)), mesh); + if (save) save_mesh(mesh, "mesh2-" + std::to_string(k)); + + timer.reset(); + timer.start(); + const double dista = functor(mesh1, mesh); + const double distb = functor(mesh, mesh1); + const double distc = (CGAL::max)(dista, distb); + timer.stop(); + times.push_back(timer.time()); + std::cout << "* distance / Hausdorff / time (sec.) " << k << " : " << + distance << " / " << distc << " / " << times.back() << std::endl; + } + + double min_time = +std::numeric_limits::infinity(); + double max_time = -std::numeric_limits::infinity(); + double avg_time = 0.0; + for (const double time : times) { + min_time = (CGAL::min)(min_time, time); + max_time = (CGAL::max)(max_time, time); + avg_time += time; + } + avg_time /= static_cast(times.size()); + + std::cout << std::endl << "* timings (msec.): " << std::endl; + std::cout << "avg time: " << avg_time * 1000.0 << std::endl; + std::cout << "min time: " << min_time * 1000.0 << std::endl; + std::cout << "max time: " << max_time * 1000.0 << std::endl; +} + int main(int argc, char** argv) { - const double error_bound = 0.05; + const double error_bound = 1e-4; const std::size_t num_samples = 1000; std::cout << std::endl << "* error bound: " << error_bound << std::endl; std::cout << std::endl << "* number of samples: " << num_samples << std::endl; @@ -703,6 +768,12 @@ int main(int argc, char** argv) { // test_timings(filepath, naive_hd); test_timings(filepath, bound_hd); + // --- Compare with the paper. + + // test_bunny(apprx_hd); + // test_bunny(naive_hd); + test_bunny(bound_hd); + // ------------------------------------------------------------------------ // std::cout << std::endl; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 8a28f607bcb..8ed76101015 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1368,7 +1368,10 @@ double bounded_error_Hausdorff_impl( // std::cout << "tm1 only: " << tm1_only.size() << std::endl; // std::cout << "tm2 only: " << tm2_only.size() << std::endl; - if (tm1_only.size() == 0) return 0.0; + if (tm1_only.size() == 0) { + std::cout << "* culling rate: 100%" << std::endl; + return 0.0; + } CGAL_assertion(tm1_only.size() > 0); tm1_tree.insert(tm1_only.begin(), tm1_only.end(), tm1, vpm1); @@ -1402,9 +1405,14 @@ double bounded_error_Hausdorff_impl( auto& candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); auto global_bounds = traversal_traits_tm1.get_global_bounds(); - // std::cout << "number of candidate triangles 1: " << + // std::cout << "* number of all triangles 1: " << + // tm1_tree.size() << std::endl; + // std::cout << "* number of candidate triangles 1: " << // candidate_triangles.size() << std::endl; + std::cout << "* culling rate: " << + FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)) << "%" << std::endl; + const FT squared_error_bound = error_bound * error_bound; while ( (global_bounds.second - global_bounds.first > error_bound) && !candidate_triangles.empty() ) { @@ -1491,7 +1499,7 @@ double bounded_error_Hausdorff_impl( } } - // std::cout << "number of candidate triangles 2: " << + // std::cout << "* number of candidate triangles 2: " << // candidate_triangles.size() << std::endl; // Return linear interpolation between found lower and upper bound From a0812c1ad70a1e1a01f3bffcafccb853d21e2940 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 19 Apr 2021 17:44:25 +0200 Subject: [PATCH 145/349] added comments with refs to the original paper, checked all the formulas --- .../CGAL/Polygon_mesh_processing/distance.h | 1 + ...traversal_traits_with_Hausdorff_distance.h | 38 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 8ed76101015..6d1f4efb29f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1413,6 +1413,7 @@ double bounded_error_Hausdorff_impl( std::cout << "* culling rate: " << FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)) << "%" << std::endl; + // See Section 5.1. const FT squared_error_bound = error_bound * error_bound; while ( (global_bounds.second - global_bounds.first > error_bound) && !candidate_triangles.empty() ) { diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index e0095823213..7d6f95f69b0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -58,7 +58,6 @@ namespace CGAL { { typedef typename AABBTraits::Primitive Primitive; typedef ::CGAL::AABB_node Node; - typedef typename AABBTraits::Bounding_box Bounding_box; typename Kernel::Construct_projected_point_3 project_point; typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; @@ -110,25 +109,25 @@ namespace CGAL { const Triangle_from_face_descriptor_map face_to_triangle_map(&m_tm2, m_vpm2); const FT v0_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( project_point( get(face_to_triangle_map, primitive.id()), v0), v0 ) ))); - if (v0_dist < h_v0_lower) h_v0_lower = v0_dist; + if (v0_dist < h_v0_lower) h_v0_lower = v0_dist; // it is () part of (11) in the paper const FT v1_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( project_point( get(face_to_triangle_map, primitive.id()), v1), v1 ) ))); - if (v1_dist < h_v1_lower) h_v1_lower = v1_dist; + if (v1_dist < h_v1_lower) h_v1_lower = v1_dist; // it is () part of (11) in the paper const FT v2_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( project_point( get(face_to_triangle_map, primitive.id()), v2), v2 ) ))); - if (v2_dist < h_v2_lower) h_v2_lower = v2_dist; + if (v2_dist < h_v2_lower) h_v2_lower = v2_dist; // it is () part of (11) in the paper // Get the distance as maximizers over all vertices - const FT distance_upper = std::max(std::max(v0_dist,v1_dist),v2_dist); - const FT distance_lower = std::max(std::max(h_v0_lower,h_v1_lower),h_v2_lower); + const FT distance_lower = std::max(std::max(h_v0_lower,h_v1_lower),h_v2_lower); // it is (11) in the paper + const FT distance_upper = std::max(std::max(v0_dist,v1_dist),v2_dist); // it is () part of (10) in the paper // Since we are at the level of a single triangle in TM2, distance_upper is // actually the correct Hausdorff distance from the query triangle in // TM1 to the primitive triangle in TM2 - if ( distance_lower < h_local_lower ) h_local_lower = distance_lower; - if ( distance_upper < h_local_upper ) h_local_upper = distance_upper; + if ( distance_lower < h_local_lower ) h_local_lower = distance_lower; // TODO: do we need this `if` here? + if ( distance_upper < h_local_upper ) h_local_upper = distance_upper; // it is (10) in the paper } // Determine whether child nodes will still contribute to a smaller @@ -136,7 +135,7 @@ namespace CGAL { std::pair do_intersect_with_priority(const Query& query, const Node& node) const { // Get the bounding box of the nodes - const Bounding_box bbox = node.bbox(); + const auto bbox = node.bbox(); // Get the vertices of the query triangle const Point_3 v0 = query.vertex(0); const Point_3 v1 = query.vertex(1); @@ -168,7 +167,7 @@ namespace CGAL { } else if ( bbox.max(1) < tri_min.y() ) { dist_y = tri_min.y() - bbox.max(1); } - // Distance along the y-axis + // Distance along the z-axis FT dist_z = FT(0); if ( tri_max.z() < bbox.min(2) ) { dist_z = bbox.min(2) - tri_max.z(); @@ -180,6 +179,7 @@ namespace CGAL { // as the length of the diagonal of the bounding box between them const FT dist = static_cast(CGAL::sqrt( CGAL::to_double(Vector_3(dist_x,dist_y,dist_z).squared_length() ))); + // See Algorithm 2. // Check whether investigating the bbox can still lower the Hausdorff // distance and improve the current global bound. If so, enter the box. if ( dist <= h_local_lower ) { @@ -224,14 +224,12 @@ namespace CGAL { typedef AABB_face_graph_triangle_primitive TM2_primitive; typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; typedef typename AABBTraits::Primitive Primitive; - typedef typename AABBTraits::Bounding_box Bounding_box; typedef ::CGAL::AABB_node Node; typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Vector_3 Vector_3; typedef typename Kernel::Triangle_3 Triangle_3; typedef AABB_tree< AABB_traits > TM2_tree; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; using Candidate = Candidate_triangle; typedef std::priority_queue Heap_type; @@ -264,7 +262,7 @@ namespace CGAL { // TODO Can we initialize the bounds here, s.t. we don't start with infty? // Can we initialize the bounds depending on the closest points in tm2 - // seen from the three vertices? + // seen from the three vertices? In the paper, they start from infinity. // Call Culling on B with the single triangle found. Hausdorff_primitive_traits_tm2 @@ -281,16 +279,15 @@ namespace CGAL { // Update global Hausdorff bounds according to the obtained local bounds const auto local_bounds = traversal_traits_tm2.get_local_bounds(); - if (local_bounds.first > h_lower) { + if (local_bounds.first > h_lower) { // it is (6) in the paper, see also Algorithm 1 h_lower = local_bounds.first; } - if (local_bounds.second > h_upper) { + if (local_bounds.second > h_upper) { // it is (6) in the paper, see also Algorithm 1 h_upper = local_bounds.second; } // Store the triangle given as primitive here as candidate triangle - // together with the local bounds it obtained to sind it to subdivision - // later + // together with the local bounds it obtained to send it to subdivision later. m_candidiate_triangles.push( Candidate(triangle, local_bounds, primitive.id()) ); } @@ -301,7 +298,7 @@ namespace CGAL { { /* Have reached a node, determine whether or not to enter it */ // Get the bounding box of the nodes - const Bounding_box bbox = node.bbox(); + const auto bbox = node.bbox(); // Compute its center const Point_3 center = Point_3( (bbox.min(0) + bbox.max(0)) / FT(2), @@ -321,12 +318,13 @@ namespace CGAL { if (difference.y() < 0) diff_y = diff_y * -FT(1); FT diff_z = (bbox.max(2) - bbox.min(2)) / FT(2); if (difference.z() < 0) diff_z = diff_z * -FT(1); - difference = difference + Vector_3( diff_x, diff_y, diff_z ); + difference = difference + Vector_3( diff_x, diff_y, diff_z ); // it is (9) in the paper // Compute distance from the farthest corner of the bbox to the closest // point in TM2 const FT dist = static_cast(CGAL::sqrt(CGAL::to_double( difference.squared_length() ))); + // See Algorithm 1 here. // If the distance is larger than the global lower bound, enter the node, i.e. return true. // std::cout << dist << " : " << h_lower << std::endl; if (dist > h_lower /* && (dist - h_lower) > m_error_bound */) { @@ -361,7 +359,7 @@ namespace CGAL { // Their vertex-point-maps const VPM1& m_vpm1; const VPM2& m_vpm2; - // AABB tree for the second triangle meshes + // AABB tree for the second triangle mesh const TM2_tree& m_tm2_tree; // Global Hausdorff bounds to be taken track of during the traversal const FT& m_error_bound; From 33d2f1073a7e7a090fbf1912d5dcb8d852ea6097 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 21 Apr 2021 11:48:56 +0200 Subject: [PATCH 146/349] optimized AABB tree calls --- ...usdorff_bounded_error_distance_example.cpp | 50 +++++++++++++------ .../CGAL/Polygon_mesh_processing/distance.h | 44 +++++++++++----- 2 files changed, 67 insertions(+), 27 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 70748051994..ef6655a1bc1 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -654,7 +654,8 @@ void test_timings(const std::string filepath, const FunctionWrapper& functor) { template< typename FunctionWrapper> -void test_bunny(const FunctionWrapper& functor, const bool save = false) { +void test_bunny( + const FunctionWrapper& functor, const int n = 5, const bool save = false) { std::cout.precision(20); const std::string filepath1 = "data/bunny1.off"; // approx 16.3K @@ -676,29 +677,47 @@ void test_bunny(const FunctionWrapper& functor, const bool save = false) { const FT dim = FT(3) * (CGAL::max)((CGAL::max)(dist1, dist2), dist3); // Get timings. - const int n = 5; // number of steps - const FT t = FT(1) / static_cast(n); // step - Timer timer; std::vector times; times.reserve(n); - for (int k = n; k >= 0; --k) { - auto mesh = mesh2; - const FT distance = k * t * dim; - PMP::transform(Affine_transformation_3(CGAL::Translation(), - Vector_3(distance, distance, distance)), mesh); - if (save) save_mesh(mesh, "mesh2-" + std::to_string(k)); + if (n == 0) { + const FT distance = dim; + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(distance, distance, distance)), mesh2); + if (save) save_mesh(mesh2, "mesh2"); timer.reset(); timer.start(); - const double dista = functor(mesh1, mesh); - const double distb = functor(mesh, mesh1); + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); const double distc = (CGAL::max)(dista, distb); timer.stop(); times.push_back(timer.time()); - std::cout << "* distance / Hausdorff / time (sec.) " << k << " : " << + std::cout << "* distance / Hausdorff / time (sec.) : " << distance << " / " << distc << " / " << times.back() << std::endl; + + } else { + + // t is the step where n is the number of steps. + const FT t = FT(1) / static_cast(n); + for (int k = n; k >= 0; --k) { + auto mesh = mesh2; + const FT distance = k * t * dim; + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(distance, distance, distance)), mesh); + if (save) save_mesh(mesh, "mesh2-" + std::to_string(k)); + + timer.reset(); + timer.start(); + const double dista = functor(mesh1, mesh); + const double distb = functor(mesh, mesh1); + const double distc = (CGAL::max)(dista, distb); + timer.stop(); + times.push_back(timer.time()); + std::cout << "* distance / Hausdorff / time (sec.) " << k << " : " << + distance << " / " << distc << " / " << times.back() << std::endl; + } } double min_time = +std::numeric_limits::infinity(); @@ -719,6 +738,9 @@ void test_bunny(const FunctionWrapper& functor, const bool save = false) { int main(int argc, char** argv) { + // std::string name; + // std::cin >> name; + const double error_bound = 1e-4; const std::size_t num_samples = 1000; std::cout << std::endl << "* error bound: " << error_bound << std::endl; @@ -772,7 +794,7 @@ int main(int argc, char** argv) { // test_bunny(apprx_hd); // test_bunny(naive_hd); - test_bunny(bound_hd); + test_bunny(bound_hd, 0); // ------------------------------------------------------------------------ // std::cout << std::endl; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 6d1f4efb29f..1519628ac93 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1332,7 +1332,7 @@ double bounded_error_Hausdorff_impl( { CGAL_assertion_code( const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2) ); CGAL_assertion_msg (is_triangle, - "One of the meshes is not triangulated. Distance computing impossible."); + "One of the meshes is not triangulated. Distance computing impossible."); typedef AABB_face_graph_triangle_primitive TM1_primitive; typedef AABB_face_graph_triangle_primitive TM2_primitive; @@ -1344,11 +1344,11 @@ double bounded_error_Hausdorff_impl( typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Triangle_3 Triangle_3; + typename Kernel::Compute_squared_distance_3 squared_distance; typedef typename boost::graph_traits::face_descriptor face_descriptor; using Candidate = Candidate_triangle; - typename Kernel::Compute_squared_distance_3 squared_distance; - + std::cout.precision(20); std::vector tm1_only, tm2_only; std::vector< std::pair > common; @@ -1358,6 +1358,9 @@ double bounded_error_Hausdorff_impl( CGAL_assertion(faces1.size() > 0); CGAL_assertion(faces2.size() > 0); + CGAL::Real_timer timer; + timer.start(); + TM1_tree tm1_tree; TM2_tree tm2_tree; if (compare_meshes) { @@ -1369,7 +1372,9 @@ double bounded_error_Hausdorff_impl( // std::cout << "tm2 only: " << tm2_only.size() << std::endl; if (tm1_only.size() == 0) { - std::cout << "* culling rate: 100%" << std::endl; + timer.stop(); + // std::cout << "* culling rate: 100%" << std::endl; + // std::cout << "* AABB tree build time (sec.): " << timer.time() << std::endl; return 0.0; } CGAL_assertion(tm1_only.size() > 0); @@ -1380,17 +1385,26 @@ double bounded_error_Hausdorff_impl( } tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); - // Build an AABB tree on tm1 - tm1_tree.build(); - const bool is_tm1_memory_ok = tm1_tree.accelerate_distance_queries(); - CGAL_assertion(is_tm1_memory_ok); + // Build an AABB tree on tm1. + // tm1_tree.build(); // by default it is also built but only in case we actually need it + tm1_tree.do_not_accelerate_distance_queries(); // here, we do not need that - // Build an AABB tree on tm2 - tm2_tree.build(); + // By default it has lazy initialization, which is slightly better, but it is off for tm1. + // const bool is_tm1_memory_ok = tm1_tree.accelerate_distance_queries(); + // CGAL_assertion(is_tm1_memory_ok); + + // Build an AABB tree on tm2. + // tm2_tree.build(); // by default it is also built but only in case we actually need it + // tm2_tree.do_not_accelerate_distance_queries(); // twice as slow + + // Here, we explicitly accelerate because we use tm2 for distance queries. const bool is_tm2_memory_ok = tm2_tree.accelerate_distance_queries(); CGAL_assertion(is_tm2_memory_ok); - // Build traversal traits for tm1_tree + timer.stop(); + // std::cout << "* AABB tree build time (sec.): " << timer.time() << std::endl; + + // Build traversal traits for tm1_tree. Hausdorff_primitive_traits_tm1 traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, error_bound ); @@ -1398,7 +1412,11 @@ double bounded_error_Hausdorff_impl( // TODO Initialize the distances on all the vertices first and store those. // TODO Do not traverse TM1, but only TM2, i.e. reduce to Culling on TM2 (Can do this for all triangles in TM1 in parallel) + timer.reset(); + timer.start(); tm1_tree.traversal_with_priority( Point_3(0,0,0), traversal_traits_tm1 ); // dummy point given as query as not needed + timer.stop(); + // std::cout << "* TM1 traversal (sec.): " << timer.time() << std::endl; // TODO Is there a better/faster data structure than the Heap used here? // Can already build a sorted structure while collecting the candidates @@ -1410,8 +1428,8 @@ double bounded_error_Hausdorff_impl( // std::cout << "* number of candidate triangles 1: " << // candidate_triangles.size() << std::endl; - std::cout << "* culling rate: " << - FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)) << "%" << std::endl; + // std::cout << "* culling rate: " << + // FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)) << "%" << std::endl; // See Section 5.1. const FT squared_error_bound = error_bound * error_bound; From 2f5ff51c6048a79da288479bbd9e44f806c198cc Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 21 Apr 2021 12:21:15 +0200 Subject: [PATCH 147/349] missing include --- .../include/CGAL/Polygon_mesh_processing/distance.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 1519628ac93..e4dcbb4c36e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef CGAL_LINKED_WITH_TBB #include From 9a9c3ed887af3701965a103390d6f9b352360d74 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 22 Apr 2021 12:19:58 +0200 Subject: [PATCH 148/349] a few comments in addition to the discussion with Sebastien and Martin --- AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h | 7 ++++++- .../include/CGAL/Polygon_mesh_processing/distance.h | 1 + .../AABB_traversal_traits_with_Hausdorff_distance.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h index 209da8536e6..79dbde6b0a4 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h @@ -187,15 +187,20 @@ AABB_node::traversal_with_priority(const Query& query, std::tie(ileft,pleft) = traits.do_intersect_with_priority(query, left_child()); std::tie(iright,pright) = traits.do_intersect_with_priority(query, right_child()); + // Add an assertion, if you intersect one of the two childs, + // you also intersect their father. + if (ileft) { if (iright) { // Both children have to be inspected + // You can compare pright to the updated bound, without calling the method, + // or if it can cull, call do_intersect() with the previous priority. if(pleft >= pright) { // Inspect left first, has higher priority - left_child().traversal_with_priority(query, traits, nb_primitives/2); + left_child().traversal_with_priority(query, traits, nb_primitives/2); // the bound is updated here if( traits.go_further() ) //&& traits.do_intersect(query, right_child()) ) // TODO shall we call again do_intersect? (Benchmarks show it slows down the Hausdorff Distance) right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index e4dcbb4c36e..bbe5a7f74af 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1388,6 +1388,7 @@ double bounded_error_Hausdorff_impl( // Build an AABB tree on tm1. // tm1_tree.build(); // by default it is also built but only in case we actually need it + // It should never be called if we do not compute distance queries. Is it true? tm1_tree.do_not_accelerate_distance_queries(); // here, we do not need that // By default it has lazy initialization, which is slightly better, but it is off for tm1. diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 7d6f95f69b0..12f3da5b4b5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -294,6 +294,7 @@ namespace CGAL { // Determine whether child nodes will still contribute to a larger // Hausdorff distance and thus have to be entered // TODO Document Query object, explain why I don't need it here. + // It does not depend on the error bound but it should. std::pair do_intersect_with_priority(const Query& /*query*/, const Node& node) const { /* Have reached a node, determine whether or not to enter it */ From 34a53d36ad27c717668ee389972d0ed9377096a7 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 22 Apr 2021 12:34:14 +0200 Subject: [PATCH 149/349] Store states on a stack to "read last frame" as it was, not simply apply the last frame, as it might not be the same points that are impacted. --- .../Animate_mesh_plugin.cpp | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Animate_mesh_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Animate_mesh_plugin.cpp index a9045771804..653a69e422c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Animate_mesh_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Animate_mesh_plugin.cpp @@ -107,7 +107,23 @@ public : public Q_SLOTS: - void read_frame() + void read_prev_frame() + { + typedef boost::property_map::type VPmap; + Frame cur_frame = old_frames.back(); + old_frames.pop_back(); + sm_item->redraw(); + + for(auto pp : cur_frame) + { + SMesh::Vertex_index vh(pp.first); + VPmap vpm = get(CGAL::vertex_point, *sm_item->face_graph()); + put(vpm, vh, pp.second); + sm_item->updateVertex(vh); + } + } + + void read_next_frame() { typedef boost::property_map::type VPmap; const CGAL::qglviewer::Vec offset = Three::mainViewer()->offset(); @@ -126,7 +142,7 @@ public Q_SLOTS: timer.stop(); return; } - + Frame cur_frame; if(nb_verts != 0) { EPICK::FT x,y,z; @@ -161,12 +177,14 @@ public Q_SLOTS: { SMesh::Vertex_index vh(id); VPmap vpm = get(CGAL::vertex_point, *sm_item->face_graph()); + cur_frame.push_back(std::make_pair(id, get(vpm, vh))); put(vpm, vh, Point_3(x-offset.x, y-offset.y, z-offset.z)); sm_item->updateVertex(vh); } } + old_frames.push_back(cur_frame); } sm_item->redraw(); @@ -187,7 +205,7 @@ public Q_SLOTS: position = frame_pos[++frame]; dock_widget->frameSlider->setValue(frame); dock_widget->frameLabel->setText(QString("%1/%2").arg(frame).arg(frame_pos.size()-1)); - read_frame(); + read_next_frame(); } void prev_frame() @@ -197,7 +215,7 @@ public Q_SLOTS: position = frame_pos[--frame]; dock_widget->frameSlider->setValue(frame); dock_widget->frameLabel->setText(QString("%1/%2").arg(frame).arg(frame_pos.size()-1)); - read_frame(); + read_prev_frame(); } void start_animation() @@ -281,7 +299,7 @@ public Q_SLOTS: frame = i; position = frame_pos[frame]; dock_widget->frameLabel->setText(QString("%1/%2").arg(frame).arg(frame_pos.size()-1)); - read_frame(); + read_next_frame(); }); QApplication::restoreOverrideCursor(); @@ -297,6 +315,7 @@ public Q_SLOTS: sm_item=nullptr; position=0; frame_pos.clear(); + old_frames.clear(); filepath=""; frame = -1; dock_widget->resetButton->setEnabled(false); @@ -311,6 +330,7 @@ public Q_SLOTS: } private: + typedef std::vector > Frame; QAction* actionAnimate; Messages_interface* messages; Scene_interface* scene; @@ -319,6 +339,8 @@ private: std::streampos position; Scene_surface_mesh_item* sm_item; std::vector frame_pos; + std::vector old_frames; + QTimer timer; int frame; std::vector initial_points; From c64128a282b89190ddf913d6d74a77898dc4c57d Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 22 Apr 2021 12:46:47 +0200 Subject: [PATCH 150/349] Fix offset in points --- .../Operations_on_polyhedra/Animate_mesh_plugin.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Animate_mesh_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Animate_mesh_plugin.cpp index 653a69e422c..611bbc5657d 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Animate_mesh_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Animate_mesh_plugin.cpp @@ -110,17 +110,22 @@ public Q_SLOTS: void read_prev_frame() { typedef boost::property_map::type VPmap; + const CGAL::qglviewer::Vec offset = Three::mainViewer()->offset(); Frame cur_frame = old_frames.back(); old_frames.pop_back(); - sm_item->redraw(); for(auto pp : cur_frame) { SMesh::Vertex_index vh(pp.first); VPmap vpm = get(CGAL::vertex_point, *sm_item->face_graph()); - put(vpm, vh, pp.second); + Point_3 np = pp.second; + put(vpm, vh, Point_3(np.x()-offset.x, + np.y()-offset.y, + np.z()-offset.z)); + sm_item->updateVertex(vh); } + sm_item->redraw(); } void read_next_frame() From 6bf1966012de3b118925efcb5078a68cff906d6f Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 23 Apr 2021 14:37:58 +0200 Subject: [PATCH 151/349] partially fixed issue for match faces + added minimum example for that issue --- ...usdorff_bounded_error_distance_example.cpp | 68 +++++++++++++++---- .../CGAL/Polygon_mesh_processing/distance.h | 31 +++++---- 2 files changed, 71 insertions(+), 28 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index ef6655a1bc1..0ccaf0fc146 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -82,8 +82,34 @@ void save_mesh(const Surface_mesh& mesh, const std::string filepath) { } } +// Match faces minimum example. +void match_faces_issue(const bool save = false) { + + using Traits = CGAL::Exact_predicates_inexact_constructions_kernel; + using Mesh = CGAL::Surface_mesh; + using Face_handle = typename boost::graph_traits::face_descriptor; + + Mesh mesh1, mesh2; + CGAL::make_tetrahedron( + Point_3(0, 0, 0), Point_3(2, 0, 0), + Point_3(1, 1, 1), Point_3(1, 0, 2), mesh1); + + mesh2 = mesh1; + CGAL::PMP::isotropic_remeshing(mesh2.faces(), 0.05, mesh2); + + if (save) save_mesh(mesh1, "mesh1"); + if (save) save_mesh(mesh2, "mesh2"); + + std::vector mesh1_only, mesh2_only; + std::vector< std::pair > common; + + CGAL::PMP::match_faces(mesh1, mesh2, std::back_inserter(common), + std::back_inserter(mesh1_only), std::back_inserter(mesh2_only)); +} + // An easy example of a tetrahedron and its remeshed version. -void remeshing_tetrahedon_example(const double error_bound) { +void remeshing_tetrahedon_example( + const double error_bound, const bool save = false) { Timer timer; Surface_mesh mesh1, mesh2; @@ -94,12 +120,17 @@ void remeshing_tetrahedon_example(const double error_bound) { Point_3(1, 1, 1), Point_3(1, 0, 2), mesh1); mesh2 = mesh1; - // TODO: How to preserve edges? - const double target_edge_length = 0.05; - PMP::isotropic_remeshing(mesh2.faces(), target_edge_length, mesh2); + using edge_descriptor = typename boost::graph_traits::edge_descriptor; + Surface_mesh::Property_map is_constrained_map = + mesh2.add_property_map("e:is_constrained", true).first; - // save_mesh(mesh1, "1-mesh1"); - // save_mesh(mesh2, "1-mesh2"); + const double target_edge_length = 0.05; + PMP::isotropic_remeshing( + mesh2.faces(), target_edge_length, mesh2, + PMP::parameters::edge_is_constrained_map(is_constrained_map)); + + if (save) save_mesh(mesh1, "mesh1"); + if (save) save_mesh(mesh2, "mesh2"); timer.reset(); timer.start(); @@ -111,7 +142,8 @@ void remeshing_tetrahedon_example(const double error_bound) { // Example with a point realizing the Hausdorff distance strictly // lying in the interior of a triangle. -void interior_triangle_example(const double error_bound) { +void interior_triangle_example( + const double error_bound, const bool save = false) { Timer timer; Surface_mesh mesh1, mesh2; @@ -132,8 +164,8 @@ void interior_triangle_example(const double error_bound) { mesh2.add_face(v1, v4, v5); mesh2.add_face(v2, v5, v3); - // save_mesh(mesh1, "2-mesh1"); - // save_mesh(mesh2, "2-mesh2"); + if (save) save_mesh(mesh1, "mesh1"); + if (save) save_mesh(mesh2, "mesh2"); timer.reset(); timer.start(); @@ -146,7 +178,7 @@ void interior_triangle_example(const double error_bound) { // Read a real mesh given by the user, perturb it slightly, and compute the // Hausdorff distance between the original mesh and its pertubation. void perturbing_mesh_example( - const std::string filepath, const double error_bound) { + const std::string filepath, const double error_bound, const bool save = false) { Timer timer; std::cout << std::endl << "* (E3) perturbing mesh example:" << std::endl; @@ -159,8 +191,8 @@ void perturbing_mesh_example( mesh2.vertices(), mesh2, max_size, CGAL::parameters::do_project(false)); std::cout << "* perturbing the second mesh" << std::endl; - // save_mesh(mesh2, "3-mesh1"); - // save_mesh(mesh2, "3-mesh2"); + if (save) save_mesh(mesh2, "mesh1"); + if (save) save_mesh(mesh2, "mesh2"); timer.reset(); timer.start(); @@ -175,7 +207,7 @@ void perturbing_mesh_example( // Print how the Hausdorff distance changes. void moving_mesh_example( const std::string filepath1, const std::string filepath2, - const std::size_t n, const double error_bound) { + const std::size_t n, const double error_bound, const bool save = false) { Timer timer; std::cout << std::endl << "* (E4) moving mesh example:" << std::endl; @@ -190,7 +222,7 @@ void moving_mesh_example( Point_3(bbox.xmax(), bbox.ymax(), bbox.zmax()))))); const FT t = FT(1) / FT(100); - // save_mesh(mesh2, "4-mesh-0"); + if (save) save_mesh(mesh2, "mesh-0"); for (std::size_t i = 0; i < n; ++i) { PMP::transform(Affine_transformation_3(CGAL::Translation(), @@ -203,7 +235,7 @@ void moving_mesh_example( PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; timer.stop(); std::cout << "* processing time: " << timer.time() << " s." << std::endl; - // save_mesh(mesh2, "4-mesh-" + std::to_string(i + 1)); + if (save) save_mesh(mesh2, "mesh-" + std::to_string(i + 1)); } } @@ -755,6 +787,11 @@ int main(int argc, char** argv) { // perturbing_mesh_example(filepath, error_bound); // moving_mesh_example(filepath, filepath, 5, error_bound); + match_faces_issue(); + + std::cout << std::endl; + return EXIT_SUCCESS; + // ------------------------------------------------------------------------ // // Tests. @@ -798,4 +835,5 @@ int main(int argc, char** argv) { // ------------------------------------------------------------------------ // std::cout << std::endl; + return EXIT_SUCCESS; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index bbe5a7f74af..2fb78386299 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1318,22 +1318,27 @@ double approximate_symmetric_Hausdorff_distance(const TriangleMesh& tm1, namespace internal { -template +template< +class Concurrency_tag, +class Kernel, +class TriangleMesh, +class VPM1, +class VPM2, +class NamedParameters1, +class NamedParameters2> double bounded_error_Hausdorff_impl( const TriangleMesh& tm1, const TriangleMesh& tm2, const typename Kernel::FT& error_bound, const bool compare_meshes, - VPM1 vpm1, - VPM2 vpm2) -{ - CGAL_assertion_code( const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2) ); - CGAL_assertion_msg (is_triangle, - "One of the meshes is not triangulated. Distance computing impossible."); + const VPM1& vpm1, const VPM2& vpm2, + const NamedParameters1& np1, + const NamedParameters2& np2) { + + CGAL_assertion_code( + const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2) ); + CGAL_assertion_msg(is_triangle, + "Both meshes must be triangulated to compute this distance!"); typedef AABB_face_graph_triangle_primitive TM1_primitive; typedef AABB_face_graph_triangle_primitive TM2_primitive; @@ -1366,7 +1371,7 @@ double bounded_error_Hausdorff_impl( TM2_tree tm2_tree; if (compare_meshes) { match_faces(tm1, tm2, std::back_inserter(common), - std::back_inserter(tm1_only), std::back_inserter(tm2_only)); + std::back_inserter(tm1_only), std::back_inserter(tm2_only), np1, np2); // std::cout << "common t: " << common.size() << std::endl; // std::cout << "tm1 only: " << tm1_only.size() << std::endl; @@ -1720,7 +1725,7 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); return internal::bounded_error_Hausdorff_impl( - tm1, tm2, error_threshold, match_faces, vpm1, vpm2); + tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); } From 1b892e0558a8faeb342f24e4e243fac28352f075 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 23 Apr 2021 15:41:57 +0200 Subject: [PATCH 152/349] subdivision tested - it works --- ...usdorff_bounded_error_distance_example.cpp | 7 +- .../CGAL/Polygon_mesh_processing/distance.h | 269 +++++++++--------- 2 files changed, 141 insertions(+), 135 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 0ccaf0fc146..2381b5b4963 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -787,10 +787,9 @@ int main(int argc, char** argv) { // perturbing_mesh_example(filepath, error_bound); // moving_mesh_example(filepath, filepath, 5, error_bound); - match_faces_issue(); - - std::cout << std::endl; - return EXIT_SUCCESS; + // match_faces_issue(); + // std::cout << std::endl; + // return EXIT_SUCCESS; // ------------------------------------------------------------------------ // // Tests. diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 2fb78386299..8c9c77dfb88 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -8,7 +8,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // -// Author(s) : Maxime Gimeno, Sebastien Loriot, Martin Skrodzki +// Author(s) : Maxime Gimeno, Sebastien Loriot, Martin Skrodzki, Dmitry Anisimov #ifndef CGAL_POLYGON_MESH_PROCESSING_DISTANCE_H #define CGAL_POLYGON_MESH_PROCESSING_DISTANCE_H @@ -1336,27 +1336,32 @@ double bounded_error_Hausdorff_impl( const NamedParameters2& np2) { CGAL_assertion_code( - const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2) ); + const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2)); CGAL_assertion_msg(is_triangle, "Both meshes must be triangulated to compute this distance!"); - typedef AABB_face_graph_triangle_primitive TM1_primitive; - typedef AABB_face_graph_triangle_primitive TM2_primitive; - typedef AABB_tree< AABB_traits > TM1_tree; - typedef AABB_tree< AABB_traits > TM2_tree; - typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Triangle_3 = typename Kernel::Triangle_3; - typedef typename Kernel::FT FT; - typedef typename Kernel::Point_3 Point_3; - typedef typename Kernel::Triangle_3 Triangle_3; + using TM1_primitive = AABB_face_graph_triangle_primitive; + using TM2_primitive = AABB_face_graph_triangle_primitive; - typename Kernel::Compute_squared_distance_3 squared_distance; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - using Candidate = Candidate_triangle; + using TM1_traits = AABB_traits; + using TM2_traits = AABB_traits; + + using TM1_tree = AABB_tree; + using TM2_tree = AABB_tree; + + using TM1_hd_traits = Hausdorff_primitive_traits_tm1; + using TM2_hd_traits = Hausdorff_primitive_traits_tm2; + + using Face_handle = typename boost::graph_traits::face_descriptor; + using Candidate = Candidate_triangle; std::cout.precision(20); - std::vector tm1_only, tm2_only; - std::vector< std::pair > common; + std::vector tm1_only, tm2_only; + std::vector< std::pair > common; const auto faces1 = faces(tm1); const auto faces2 = faces(tm2); @@ -1391,18 +1396,8 @@ double bounded_error_Hausdorff_impl( } tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); - // Build an AABB tree on tm1. - // tm1_tree.build(); // by default it is also built but only in case we actually need it - // It should never be called if we do not compute distance queries. Is it true? - tm1_tree.do_not_accelerate_distance_queries(); // here, we do not need that - - // By default it has lazy initialization, which is slightly better, but it is off for tm1. - // const bool is_tm1_memory_ok = tm1_tree.accelerate_distance_queries(); - // CGAL_assertion(is_tm1_memory_ok); - - // Build an AABB tree on tm2. - // tm2_tree.build(); // by default it is also built but only in case we actually need it - // tm2_tree.do_not_accelerate_distance_queries(); // twice as slow + // We skip computing internal Kd tree because we do not compute distance queries. + tm1_tree.do_not_accelerate_distance_queries(); // Here, we explicitly accelerate because we use tm2 for distance queries. const bool is_tm2_memory_ok = tm2_tree.accelerate_distance_queries(); @@ -1412,131 +1407,138 @@ double bounded_error_Hausdorff_impl( // std::cout << "* AABB tree build time (sec.): " << timer.time() << std::endl; // Build traversal traits for tm1_tree. - Hausdorff_primitive_traits_tm1 traversal_traits_tm1( - tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, error_bound ); + TM1_hd_traits traversal_traits_tm1( + tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, error_bound); - // Find candidate triangles in TM1 which might realise the Hausdorff bound - // TODO Initialize the distances on all the vertices first and store those. - // TODO Do not traverse TM1, but only TM2, i.e. reduce to Culling on TM2 (Can do this for all triangles in TM1 in parallel) + // TODO: Initialize the distances on all the vertices first and store those. + // TODO: Do not traverse TM1, but only TM2, i.e. reduce to Culling on TM2. + // Can we do this for all triangles in TM1 in parallel? + // Find candidate triangles in TM1 which might realise the Hausdorff bound. timer.reset(); timer.start(); - tm1_tree.traversal_with_priority( Point_3(0,0,0), traversal_traits_tm1 ); // dummy point given as query as not needed + const Point_3 stub(0, 0, 0); // dummy point given as query since it is not needed + tm1_tree.traversal_with_priority(stub, traversal_traits_tm1); timer.stop(); // std::cout << "* TM1 traversal (sec.): " << timer.time() << std::endl; - // TODO Is there a better/faster data structure than the Heap used here? - // Can already build a sorted structure while collecting the candidates + // We build a sorted structure while collecting the candidates. auto& candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); auto global_bounds = traversal_traits_tm1.get_global_bounds(); - // std::cout << "* number of all triangles 1: " << - // tm1_tree.size() << std::endl; - // std::cout << "* number of candidate triangles 1: " << - // candidate_triangles.size() << std::endl; + // std::cout << "* number of all triangles for TM1: " << tm1_tree.size() << std::endl; + // std::cout << "* number of candidate triangles before: " << candidate_triangles.size() << std::endl; // std::cout << "* culling rate: " << // FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)) << "%" << std::endl; - // See Section 5.1. + // See Section 5.1 in the paper. const FT squared_error_bound = error_bound * error_bound; - while ( (global_bounds.second - global_bounds.first > error_bound) && !candidate_triangles.empty() ) { + while ( + (global_bounds.second - global_bounds.first > error_bound) && + !candidate_triangles.empty()) { - // Get the first triangle and its Hausdorff bounds from the candidate set + // Get the first triangle and its Hausdorff bounds from the candidate set. const Candidate triangle_and_bound = candidate_triangles.top(); - // Remove it from the candidate set as it will be processed now + // Remove it from the candidate set as it will be processed now. candidate_triangles.pop(); // Only process the triangle if it can contribute to the Hausdorff distance, - // i.e. if its Upper Bound is higher than the currently known best lower bound + // i.e. if its upper bound is higher than the currently known best lower bound // and the difference between the bounds to be obtained is larger than the // user given error. const auto& triangle_bounds = triangle_and_bound.bounds; - if ( (triangle_bounds.second > global_bounds.first) && (triangle_bounds.second - triangle_bounds.first > error_bound) ) { - // Get the triangle that is to be subdivided and read its vertices + if ( + (triangle_bounds.second > global_bounds.first) && + (triangle_bounds.second - triangle_bounds.first > error_bound)) { + + // Get the triangle that is to be subdivided and read its vertices. const Triangle_3& triangle_for_subdivision = triangle_and_bound.triangle; const Point_3 v0 = triangle_for_subdivision.vertex(0); const Point_3 v1 = triangle_for_subdivision.vertex(1); const Point_3 v2 = triangle_for_subdivision.vertex(2); // Check second stopping condition: All three vertices of the triangle - // are projected onto the same triangle in TM2 + // are projected onto the same triangle in TM2. const auto closest_triangle_v0 = tm2_tree.closest_point_and_primitive(v0); const auto closest_triangle_v1 = tm2_tree.closest_point_and_primitive(v1); const auto closest_triangle_v2 = tm2_tree.closest_point_and_primitive(v2); - if( (closest_triangle_v0.second == closest_triangle_v1.second) && (closest_triangle_v1.second == closest_triangle_v2.second)) { + if ( + (closest_triangle_v0.second == closest_triangle_v1.second) && + (closest_triangle_v1.second == closest_triangle_v2.second)) { + // The upper bound of this triangle is the actual Hausdorff distance of // the triangle to the second mesh. Use it as new global lower bound. - // TODO Update the reference to the realizing triangle here as this is the best current guess. + // TODO: Update the reference to the realizing triangle here as this is the best current guess. global_bounds.first = triangle_bounds.second; continue; } // Check third stopping condition: All edge lengths of the triangle are - // smaller than the given error bound, cannot get results beyond this - // bound. - if ( squared_distance( v0, v1 ) < squared_error_bound - && squared_distance( v0, v2 ) < squared_error_bound - && squared_distance( v1, v2 ) < squared_error_bound ) { - // The upper bound of this triangle is within error tolerance of - // the actual upper bound, use it. - global_bounds.first = triangle_bounds.second; - continue; + // smaller than the given error bound, we cannot get results beyond this bound. + if ( + CGAL::squared_distance(v0, v1) < squared_error_bound && + CGAL::squared_distance(v0, v2) < squared_error_bound && + CGAL::squared_distance(v1, v2) < squared_error_bound) { + + // The upper bound of this triangle is within error tolerance of + // the actual upper bound, use it. + global_bounds.first = triangle_bounds.second; + continue; } - // Subdivide the triangle into four smaller triangles - const Point_3 v01 = midpoint( v0, v1 ); - const Point_3 v02 = midpoint( v0, v2 ); - const Point_3 v12 = midpoint( v1, v2 ); - const std::array sub_triangles = { - Triangle_3( v0, v01, v02), Triangle_3( v1, v01, v12), - Triangle_3( v2, v02, v12), Triangle_3( v01, v02, v12) - }; + // Subdivide the triangle into four smaller triangles. + const Point_3 v01 = CGAL::midpoint(v0, v1); + const Point_3 v02 = CGAL::midpoint(v0, v2); + const Point_3 v12 = CGAL::midpoint(v1, v2); + const std::array sub_triangles = { + Triangle_3(v0, v01, v02), Triangle_3(v1 , v01, v12), + Triangle_3(v2, v02, v12), Triangle_3(v01, v02, v12) }; + + // Send each of the four triangles to Culling on B with the bounds of the parent triangle. + for (std::size_t i = 0; i < 4; ++i) { - // Send each of the four triangles to Culling on B with the bounds of the parent triangle - for (int i=0; i<4; i++) { // Call Culling on B with the single triangle found. - Hausdorff_primitive_traits_tm2 traversal_traits_tm2( + TM2_hd_traits traversal_traits_tm2( tm2_tree.traits(), tm2, vpm2, triangle_bounds.first, triangle_bounds.second, infinity_value(), infinity_value(), - infinity_value() - ); + infinity_value()); tm2_tree.traversal_with_priority(sub_triangles[i], traversal_traits_tm2); - // Update global lower Hausdorff bound according to the obtained local bounds + // Update global lower Hausdorff bound according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); if (local_bounds.first > global_bounds.first) { global_bounds.first = local_bounds.first; } - // TODO Additionally store the face descriptor of the parent from TM1 in the Candidate_triangle. - // Add the subtriangle to the candidate list + // TODO: Additionally store the face descriptor of the parent from TM1 in the Candidate_triangle. + // Add the subtriangle to the candidate list. candidate_triangles.push( - Candidate(sub_triangles[i], local_bounds, triangle_and_bound.face) ); + Candidate(sub_triangles[i], local_bounds, triangle_and_bound.face)); } - // Update global upper Hausdorff bound after subdivision + // Update global upper Hausdorff bound after subdivision. const FT current_max = candidate_triangles.top().bounds.second; global_bounds.second = std::max(current_max, global_bounds.first); } } - // std::cout << "* number of candidate triangles 2: " << - // candidate_triangles.size() << std::endl; + // std::cout << "* number of candidate triangles after: " << candidate_triangles.size() << std::endl; - // Return linear interpolation between found lower and upper bound + // Return linear interpolation between the found lower and upper bounds. return CGAL::to_double((global_bounds.first + global_bounds.second) / FT(2)); -#if !defined(CGAL_LINKED_WITH_TBB) - CGAL_static_assertion_msg (!(boost::is_convertible::value), - "Parallel_tag is enabled but TBB is unavailable."); -#else - // TODO implement parallelized version of the above here. -#endif + #if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg( + !(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable!"); + #else + // TODO: implement the parallel version of the above here. + #endif } template -double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, - const TriangleMesh& tm2, - double error_bound, - const NamedParameters1& np1, - const NamedParameters2& np2) -{ - typedef typename GetGeomTraits::type Geom_traits; - using FT = typename Geom_traits::FT; +template< +class Concurrency_tag, +class TriangleMesh, +class NamedParameters1, +class NamedParameters2> +double bounded_error_Hausdorff_distance( + const TriangleMesh& tm1, + const TriangleMesh& tm2, + const double error_bound, + const NamedParameters1& np1, + const NamedParameters2& np2) { - typedef typename GetVertexPointMap::const_type Vpm1; - typedef typename GetVertexPointMap::const_type Vpm2; + using Traits = typename GetGeomTraits::type; + using FT = typename Traits::FT; - using parameters::choose_parameter; - using parameters::get_parameter; - - Vpm1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), - get_const_property_map(vertex_point, tm1)); - Vpm2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), - get_const_property_map(vertex_point, tm2)); + const auto vpm1 = parameters::choose_parameter( + parameters::get_parameter(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, tm1)); + const auto vpm2 = parameters::choose_parameter( + parameters::get_parameter(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, tm2)); const bool match_faces1 = parameters::choose_parameter( parameters::get_parameter(np1, internal_np::match_faces), true); @@ -1724,29 +1728,32 @@ double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); - return internal::bounded_error_Hausdorff_impl( + return internal::bounded_error_Hausdorff_impl( tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); } - -template< class Concurrency_tag, - class TriangleMesh, - class NamedParameters1> -double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, - const TriangleMesh& tm2, - double error_bound, - const NamedParameters1& np1) -{ - return bounded_error_Hausdorff_distance(tm1, tm2, error_bound, np1, parameters::all_default()); +template< +class Concurrency_tag, +class TriangleMesh, +class NamedParameters1> +double bounded_error_Hausdorff_distance( + const TriangleMesh& tm1, + const TriangleMesh& tm2, + const double error_bound, + const NamedParameters1& np1) { + return bounded_error_Hausdorff_distance( + tm1, tm2, error_bound, np1, parameters::all_default()); } -template< class Concurrency_tag, - class TriangleMesh> -double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, - const TriangleMesh& tm2, - double error_bound) -{ - return bounded_error_Hausdorff_distance(tm1, tm2, error_bound, parameters::all_default() ); +template< +class Concurrency_tag, +class TriangleMesh> +double bounded_error_Hausdorff_distance( + const TriangleMesh& tm1, + const TriangleMesh& tm2, + const double error_bound) { + return bounded_error_Hausdorff_distance( + tm1, tm2, error_bound, parameters::all_default()); } /* From f92e24f9c2f2d06921b401a8ba26f445733a3bba Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 23 Apr 2021 16:01:32 +0200 Subject: [PATCH 153/349] now we can return realizing triangles --- ...usdorff_bounded_error_distance_example.cpp | 35 ++++++++++++++++--- .../CGAL/Polygon_mesh_processing/distance.h | 30 ++++++++++++---- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 2381b5b4963..f64d5957ae2 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -54,7 +54,7 @@ struct Bounded_error_hd_wrapper { std::string name() const { return "bounded error"; } Bounded_error_hd_wrapper(const double error_bound) : m_error_bound(error_bound) { } double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { - return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound); + return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound).first; } }; @@ -135,7 +135,7 @@ void remeshing_tetrahedon_example( timer.reset(); timer.start(); std::cout << "* bounded Hausdorff distance: " << - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound).first << std::endl; timer.stop(); std::cout << "* processing time: " << timer.time() << " s." << std::endl; } @@ -170,7 +170,7 @@ void interior_triangle_example( timer.reset(); timer.start(); std::cout << "* bounded Hausdorff distance: " << - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound).first << std::endl; timer.stop(); std::cout << "* processing time: " << timer.time() << " s." << std::endl; } @@ -197,7 +197,7 @@ void perturbing_mesh_example( timer.reset(); timer.start(); std::cout << "* bounded Hausdorff distance: " << - PMP::bounded_error_Hausdorff_distance(mesh2, mesh2, error_bound) << std::endl; + PMP::bounded_error_Hausdorff_distance(mesh2, mesh2, error_bound).first << std::endl; timer.stop(); std::cout << "* processing time: " << timer.time() << " s." << std::endl; } @@ -232,7 +232,7 @@ void moving_mesh_example( timer.start(); std::cout << "* position: " << i << std::endl; std::cout << "* bounded Hausdorff distance: " << - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound).first << std::endl; timer.stop(); std::cout << "* processing time: " << timer.time() << " s." << std::endl; if (save) save_mesh(mesh2, "mesh-" + std::to_string(i + 1)); @@ -768,6 +768,28 @@ void test_bunny( std::cout << "max time: " << max_time * 1000.0 << std::endl; } +void test_realizing_triangles( + const double error_bound, const bool save = false) { + + // Basic test. + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2 = mesh1; + if (save) save_mesh(mesh2, "mesh2"); + + const auto bound_triangles = + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound).second; + std::cout << "* f1: " << static_cast(bound_triangles.first) << std::endl; + std::cout << "* f2: " << static_cast(bound_triangles.second) << std::endl; +} + int main(int argc, char** argv) { // std::string name; @@ -832,6 +854,9 @@ int main(int argc, char** argv) { // test_bunny(naive_hd); test_bunny(bound_hd, 0); + // --- Testing realizing triangles. + test_realizing_triangles(error_bound); + // ------------------------------------------------------------------------ // std::cout << std::endl; return EXIT_SUCCESS; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 8c9c77dfb88..be0d520dc0b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1326,7 +1326,11 @@ class VPM1, class VPM2, class NamedParameters1, class NamedParameters2> -double bounded_error_Hausdorff_impl( +std::pair::face_descriptor, + typename boost::graph_traits::face_descriptor> > +bounded_error_Hausdorff_impl( const TriangleMesh& tm1, const TriangleMesh& tm2, const typename Kernel::FT& error_bound, @@ -1386,7 +1390,7 @@ double bounded_error_Hausdorff_impl( timer.stop(); // std::cout << "* culling rate: 100%" << std::endl; // std::cout << "* AABB tree build time (sec.): " << timer.time() << std::endl; - return 0.0; + return std::make_pair(0.0, std::make_pair(Face_handle(), Face_handle())); } CGAL_assertion(tm1_only.size() > 0); @@ -1530,7 +1534,9 @@ double bounded_error_Hausdorff_impl( // std::cout << "* number of candidate triangles after: " << candidate_triangles.size() << std::endl; // Return linear interpolation between the found lower and upper bounds. - return CGAL::to_double((global_bounds.first + global_bounds.second) / FT(2)); + const double hdist = CGAL::to_double((global_bounds.first + global_bounds.second) / FT(2)); + const auto realizing_triangles = std::make_pair(Face_handle(), Face_handle()); + return std::make_pair(hdist, realizing_triangles); #if !defined(CGAL_LINKED_WITH_TBB) CGAL_static_assertion_msg( @@ -1703,7 +1709,11 @@ class Concurrency_tag, class TriangleMesh, class NamedParameters1, class NamedParameters2> -double bounded_error_Hausdorff_distance( +std::pair::face_descriptor, + typename boost::graph_traits::face_descriptor> > +bounded_error_Hausdorff_distance( const TriangleMesh& tm1, const TriangleMesh& tm2, const double error_bound, @@ -1736,7 +1746,11 @@ template< class Concurrency_tag, class TriangleMesh, class NamedParameters1> -double bounded_error_Hausdorff_distance( +std::pair::face_descriptor, + typename boost::graph_traits::face_descriptor> > +bounded_error_Hausdorff_distance( const TriangleMesh& tm1, const TriangleMesh& tm2, const double error_bound, @@ -1748,7 +1762,11 @@ double bounded_error_Hausdorff_distance( template< class Concurrency_tag, class TriangleMesh> -double bounded_error_Hausdorff_distance( +std::pair::face_descriptor, + typename boost::graph_traits::face_descriptor> > +bounded_error_Hausdorff_distance( const TriangleMesh& tm1, const TriangleMesh& tm2, const double error_bound) { From ce9bf321dfb3fcf7b2ebde1d731d746eb3cffc79 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 23 Apr 2021 16:16:53 +0200 Subject: [PATCH 154/349] use num_vertices() instead of vertices().size() (garbage probleme in SMesh) --- .../include/CGAL/Polygon_mesh_processing/measure.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 5a3298dbe7d..2b5745cc64d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -899,8 +899,8 @@ void match_faces(const PolygonMesh& m1, const PolygonMesh& m2, std::map point_id_map; - std::vector m1_vertex_id(vertices(m1).size(), -1); - std::vector m2_vertex_id(vertices(m2).size(), -1); + std::vector m1_vertex_id(num_vertices(m1), -1); + std::vector m2_vertex_id(num_vertices(m2), -1); boost::dynamic_bitset<> shared_vertices(m1_vertex_id.size() + m2_vertex_id.size()); //iterate both meshes to set ids of all points, and set vertex/point_id maps. From 69c48308cc6b4acc06eacf5a3a0e087f8b8cd728 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 26 Apr 2021 12:50:22 +0200 Subject: [PATCH 155/349] added test for realizing triangles, updated how the bounds are stored, removed useless types --- .../CGAL/internal/AABB_tree/AABB_node.h | 32 +- ...usdorff_bounded_error_distance_example.cpp | 81 +++- .../CGAL/Polygon_mesh_processing/distance.h | 38 +- ...traversal_traits_with_Hausdorff_distance.h | 393 ++++++++++-------- 4 files changed, 315 insertions(+), 229 deletions(-) diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h index 79dbde6b0a4..33d93989c7b 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h @@ -184,42 +184,48 @@ AABB_node::traversal_with_priority(const Query& query, default: bool ileft, iright; typename Traversal_traits::Priority pleft, pright; - std::tie(ileft,pleft) = traits.do_intersect_with_priority(query, left_child()); - std::tie(iright,pright) = traits.do_intersect_with_priority(query, right_child()); + std::tie(ileft, pleft) = traits.do_intersect_with_priority(query, left_child()); + std::tie(iright, pright) = traits.do_intersect_with_priority(query, right_child()); - // Add an assertion, if you intersect one of the two childs, + // Add an assertion, if you intersect one of the two children, // you also intersect their father. - if (ileft) + if(ileft) { - if (iright) + if(iright) { - // Both children have to be inspected + // Both children have to be inspected. // You can compare pright to the updated bound, without calling the method, // or if it can cull, call do_intersect() with the previous priority. if(pleft >= pright) { - // Inspect left first, has higher priority + // Inspect the left child first, has higher priority. left_child().traversal_with_priority(query, traits, nb_primitives/2); // the bound is updated here - if( traits.go_further() ) //&& traits.do_intersect(query, right_child()) ) // TODO shall we call again do_intersect? (Benchmarks show it slows down the Hausdorff Distance) + if( traits.go_further() ) // && traits.do_intersect(query, right_child()) ) // TODO: shall we call again do_intersect? (Benchmarks show it slows down the Hausdorff Distance) right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); } else { - // Inspect right first, has higher priority + // Inspect the right child first, has higher priority. right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); - if( traits.go_further() ) //&& traits.do_intersect(query, left_child()) ) // TODO shall we call again do_intersect? (Benchmarks show it slows down the Hausdorff Distance) + if( traits.go_further() ) // && traits.do_intersect(query, left_child()) ) // TODO: shall we call again do_intersect? (Benchmarks show it slows down the Hausdorff Distance) left_child().traversal_with_priority(query, traits, nb_primitives/2); } } else - // Only the left child has to be inspected + { + // Only the left child has to be inspected. left_child().traversal_with_priority(query, traits, nb_primitives/2); + } } else - if (iright) - // Only the right child has to be inspected + { + if(iright) + { + // Only the right child has to be inspected. right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); + } + } } } diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index f64d5957ae2..357cf59a0b3 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -17,10 +17,11 @@ using SCK = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; -using Kernel = EPICK; -using FT = typename Kernel::FT; -using Point_3 = typename Kernel::Point_3; -using Vector_3 = typename Kernel::Vector_3; +using Kernel = EPICK; +using FT = typename Kernel::FT; +using Point_3 = typename Kernel::Point_3; +using Vector_3 = typename Kernel::Vector_3; +using Triangle_3 = typename Kernel::Triangle_3; using TAG = CGAL::Parallel_if_available_tag; using Surface_mesh = CGAL::Surface_mesh; @@ -768,26 +769,80 @@ void test_bunny( std::cout << "max time: " << max_time * 1000.0 << std::endl; } +Triangle_3 get_triangle(const int index, const Surface_mesh& mesh) { + + const auto mfaces = faces(mesh); + assert(index > 0); + assert(index < static_cast(mfaces.size())); + const auto face = *(mfaces.begin() + index); + + const auto he = halfedge(face, mesh); + const auto vertices = vertices_around_face(he, mesh); + auto vit = vertices.begin(); + const auto& p0 = mesh.point(*vit); ++vit; + const auto& p1 = mesh.point(*vit); ++vit; + const auto& p2 = mesh.point(*vit); + return Triangle_3(p0, p1, p2); +} + +void compute_realizing_triangles( + const Surface_mesh& mesh1, const Surface_mesh& mesh2, const double error_bound) { + + std::cout << "* getting realizing triangles: " << std::endl; + const auto pair = + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound); + const int tri1 = static_cast(pair.second.first); + const int tri2 = static_cast(pair.second.second); + + std::cout << "* Hausdorff: " << pair.first << std::endl; + std::cout << "* f1: " << tri1 << std::endl; + std::cout << "* f2: " << tri2 << std::endl; + if (tri1 != -1) { + const auto triangle = get_triangle(tri1, mesh1); + std::cout << "* triangle1: " << triangle << std::endl; + } + if (tri2 != -1) { + const auto triangle = get_triangle(tri2, mesh2); + std::cout << "* triangle2: " << triangle << std::endl; + } +} + void test_realizing_triangles( const double error_bound, const bool save = false) { - // Basic test. std::cout.precision(20); + std::cout << std::endl << "* testing realizing triangles:" << std::endl << std::endl; + + // Basic test. + std::cout << "... basic test ..." << std::endl; Surface_mesh mesh1, mesh2; mesh1.add_vertex(Point_3(0, 0, 0)); mesh1.add_vertex(Point_3(2, 0, 0)); mesh1.add_vertex(Point_3(1, 1, 0)); mesh1.add_face(mesh1.vertices()); - if (save) save_mesh(mesh1, "mesh1"); - mesh2 = mesh1; - if (save) save_mesh(mesh2, "mesh2"); + mesh2.add_vertex(Point_3(0, 0, 1)); + mesh2.add_vertex(Point_3(2, 0, 1)); + mesh2.add_vertex(Point_3(1, 1, 1)); + mesh2.add_face(mesh2.vertices()); - const auto bound_triangles = - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound).second; - std::cout << "* f1: " << static_cast(bound_triangles.first) << std::endl; - std::cout << "* f2: " << static_cast(bound_triangles.second) << std::endl; + if (save) save_mesh(mesh1, "1mesh1"); + if (save) save_mesh(mesh2, "1mesh2"); + compute_realizing_triangles(mesh1, mesh2, error_bound); + + // Complex test. + std::cout << std::endl << "... complex test ..." << std::endl; + const std::string filepath1 = "data/tetrahedron.off"; + const std::string filepath2 = "data/tetrahedron-remeshed.off"; + get_meshes(filepath1, filepath2, mesh1, mesh2); + + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(FT(0), FT(0), FT(1))), mesh2); + + if (save) save_mesh(mesh1, "2mesh1"); + if (save) save_mesh(mesh2, "2mesh2"); + compute_realizing_triangles(mesh1, mesh2, error_bound); } int main(int argc, char** argv) { @@ -855,7 +910,7 @@ int main(int argc, char** argv) { test_bunny(bound_hd, 0); // --- Testing realizing triangles. - test_realizing_triangles(error_bound); + test_realizing_triangles(error_bound, true); // ------------------------------------------------------------------------ // std::cout << std::endl; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index be0d520dc0b..3ddbe6786f0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1322,8 +1322,7 @@ template< class Concurrency_tag, class Kernel, class TriangleMesh, -class VPM1, -class VPM2, +class VPM1, class VPM2, class NamedParameters1, class NamedParameters2> std::pair; @@ -1361,7 +1360,7 @@ bounded_error_Hausdorff_impl( using TM2_hd_traits = Hausdorff_primitive_traits_tm2; using Face_handle = typename boost::graph_traits::face_descriptor; - using Candidate = Candidate_triangle; + using Candidate = Candidate_triangle; std::cout.precision(20); std::vector tm1_only, tm2_only; @@ -1439,7 +1438,7 @@ bounded_error_Hausdorff_impl( // See Section 5.1 in the paper. const FT squared_error_bound = error_bound * error_bound; while ( - (global_bounds.second - global_bounds.first > error_bound) && + (global_bounds.upper - global_bounds.lower > error_bound) && !candidate_triangles.empty()) { // Get the first triangle and its Hausdorff bounds from the candidate set. @@ -1454,8 +1453,8 @@ bounded_error_Hausdorff_impl( const auto& triangle_bounds = triangle_and_bound.bounds; if ( - (triangle_bounds.second > global_bounds.first) && - (triangle_bounds.second - triangle_bounds.first > error_bound)) { + (triangle_bounds.upper > global_bounds.lower) && + (triangle_bounds.upper - triangle_bounds.lower > error_bound)) { // Get the triangle that is to be subdivided and read its vertices. const Triangle_3& triangle_for_subdivision = triangle_and_bound.triangle; @@ -1475,7 +1474,7 @@ bounded_error_Hausdorff_impl( // The upper bound of this triangle is the actual Hausdorff distance of // the triangle to the second mesh. Use it as new global lower bound. // TODO: Update the reference to the realizing triangle here as this is the best current guess. - global_bounds.first = triangle_bounds.second; + global_bounds.lower = triangle_bounds.upper; continue; } @@ -1488,7 +1487,7 @@ bounded_error_Hausdorff_impl( // The upper bound of this triangle is within error tolerance of // the actual upper bound, use it. - global_bounds.first = triangle_bounds.second; + global_bounds.lower = triangle_bounds.upper; continue; } @@ -1506,8 +1505,8 @@ bounded_error_Hausdorff_impl( // Call Culling on B with the single triangle found. TM2_hd_traits traversal_traits_tm2( tm2_tree.traits(), tm2, vpm2, - triangle_bounds.first, - triangle_bounds.second, + triangle_bounds.lower, + triangle_bounds.upper, infinity_value(), infinity_value(), infinity_value()); @@ -1515,26 +1514,25 @@ bounded_error_Hausdorff_impl( // Update global lower Hausdorff bound according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); - if (local_bounds.first > global_bounds.first) { - global_bounds.first = local_bounds.first; + if (local_bounds.lower > global_bounds.lower) { + global_bounds.lower = local_bounds.lower; } // TODO: Additionally store the face descriptor of the parent from TM1 in the Candidate_triangle. // Add the subtriangle to the candidate list. - candidate_triangles.push( - Candidate(sub_triangles[i], local_bounds, triangle_and_bound.face)); + candidate_triangles.push(Candidate(sub_triangles[i], local_bounds)); } // Update global upper Hausdorff bound after subdivision. - const FT current_max = candidate_triangles.top().bounds.second; - global_bounds.second = std::max(current_max, global_bounds.first); + const FT current_max = candidate_triangles.top().bounds.upper; + global_bounds.upper = std::max(current_max, global_bounds.lower); } } // std::cout << "* number of candidate triangles after: " << candidate_triangles.size() << std::endl; // Return linear interpolation between the found lower and upper bounds. - const double hdist = CGAL::to_double((global_bounds.first + global_bounds.second) / FT(2)); + const double hdist = CGAL::to_double((global_bounds.lower + global_bounds.upper) / FT(2)); const auto realizing_triangles = std::make_pair(Face_handle(), Face_handle()); return std::make_pair(hdist, realizing_triangles); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 12f3da5b4b5..e5a419be3b9 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 GeometryFactory (France). +// Copyright (c) 2019 GeometryFactory SARL (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -8,18 +8,21 @@ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // -// Author(s) : Sebastien Loriot, Martin Skrodzki +// Author(s) : Sebastien Loriot, Martin Skrodzki, Dmitry Anisimov #ifndef CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_HAUSDORFF_DISTANCE #define CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_HAUSDORFF_DISTANCE #include +// STL includes. +#include #include -#include -#include + +// CGAL includes. #include #include +#include namespace CGAL { @@ -29,235 +32,260 @@ namespace CGAL { return FT(1000000000000); } - // Candidate triangle. - template - struct Candidate_triangle { + // Bounds. + template + struct Bounds { using FT = typename Kernel::FT; + + FT lower = -FT(1); + FT upper = -FT(1); + Face_handle lface; + Face_handle uface; + }; + + // Candidate triangle. + template + struct Candidate_triangle { using Triangle_3 = typename Kernel::Triangle_3; + using Candidate_bounds = Bounds; Candidate_triangle( - const Triangle_3& triangle, - const std::pair& bounds, - const FaceDescriptor& face) : - triangle(triangle), bounds(bounds), face(face) + const Triangle_3& triangle, const Candidate_bounds& bounds) : + triangle(triangle), bounds(bounds) { } Triangle_3 triangle; - std::pair bounds; - FaceDescriptor face; - - bool operator>(const Candidate_triangle& other) const { return bounds.second < other.bounds.second; } - bool operator<(const Candidate_triangle& other) const { return bounds.second > other.bounds.second; } + Candidate_bounds bounds; + bool operator>(const Candidate_triangle& other) const { return bounds.upper < other.bounds.upper; } + bool operator<(const Candidate_triangle& other) const { return bounds.upper > other.bounds.upper; } }; - /** - * @class Hausdorff_primitive_traits_tm2 - */ - template - class Hausdorff_primitive_traits_tm2 - { - typedef typename AABBTraits::Primitive Primitive; - typedef ::CGAL::AABB_node Node; - typename Kernel::Construct_projected_point_3 project_point; - typedef typename Kernel::FT FT; - typedef typename Kernel::Point_3 Point_3; - typedef typename Kernel::Vector_3 Vector_3; + // Hausdorff primitive traits on TM2. + template< + typename AABBTraits, + typename Query, + typename Kernel, + typename TriangleMesh, typename VPM2> + class Hausdorff_primitive_traits_tm2 { + + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Vector_3 = typename Kernel::Vector_3; + + using Project_point_3 = typename Kernel::Construct_projected_point_3; + using Face_handle = typename boost::graph_traits::face_descriptor; + using Local_bounds = Bounds; public: - typedef FT Priority; - + using Priority = FT; Hausdorff_primitive_traits_tm2( const AABBTraits& traits, - const TriangleMesh& tm2, - const VPM2& vpm2, + const TriangleMesh& tm2, const VPM2& vpm2, const FT h_lower_init, const FT h_upper_init, - const FT h_v0_lower_init, const FT h_v1_lower_init, const FT h_v2_lower_init) - : m_traits(traits), m_tm2(tm2), m_vpm2(vpm2) { - // Initialize the global and local bounds with the given values - h_local_lower = h_lower_init; - h_local_upper = h_upper_init; - h_v0_lower = h_v0_lower_init; - h_v1_lower = h_v1_lower_init; - h_v2_lower = h_v2_lower_init; - } + const FT h_v0_lower_init, const FT h_v1_lower_init, const FT h_v2_lower_init) : + m_traits(traits), m_tm2(tm2), m_vpm2(vpm2) { - // Explore the whole tree, i.e. always enter children if the methods + // Initialize the global and local bounds with the given values. + h_local_bounds.lower = h_lower_init; + h_local_bounds.upper = h_upper_init; + h_v0_lower = h_v0_lower_init; + h_v1_lower = h_v1_lower_init; + h_v2_lower = h_v2_lower_init; + } + + // Explore the whole tree, i.e. always enter children if the method // do_intersect() below determines that it is worthwhile. bool go_further() const { return true; } - // Compute the explicit Hausdorff distance to the given primitive - void intersection(const Query& query, const Primitive& primitive) - { - /* Have reached a single triangle, process it */ - // TODO Already perform these computations once we have <=k + // Compute the explicit Hausdorff distance to the given primitive. + template + void intersection(const Query& query, const Primitive& primitive) { + + /* Have reached a single triangle, process it. */ + // TODO: Already perform these computations once we have <= k. /* - / Determine the distance accroding to - / min_{b \in primitive} ( max_{vertex in query} ( d(vertex, b))) + / Determine the distance according to + / min_{b \in primitive} ( max_{vertex in query} ( d(vertex, b) ) ) / / Here, we only have one triangle in B, i.e. tm2. Thus, it suffices to / compute the distance of the vertices of the query triangles to the / primitive triangle and use the maximum of the obtained distances. */ - // The query object is a triangle from TM1, get its vertices + // The query object is a triangle from TM1, get its vertices. const Point_3 v0 = query.vertex(0); const Point_3 v1 = query.vertex(1); const Point_3 v2 = query.vertex(2); - // Compute distances of the vertices to the primitive triangle in TM2 + // Compute distances of the vertices to the primitive triangle in TM2. const Triangle_from_face_descriptor_map face_to_triangle_map(&m_tm2, m_vpm2); const FT v0_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( - project_point( get(face_to_triangle_map, primitive.id()), v0), v0 ) ))); + m_project_point(get(face_to_triangle_map, primitive.id()), v0), v0)))); if (v0_dist < h_v0_lower) h_v0_lower = v0_dist; // it is () part of (11) in the paper const FT v1_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( - project_point( get(face_to_triangle_map, primitive.id()), v1), v1 ) ))); + m_project_point(get(face_to_triangle_map, primitive.id()), v1), v1)))); if (v1_dist < h_v1_lower) h_v1_lower = v1_dist; // it is () part of (11) in the paper const FT v2_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( - project_point( get(face_to_triangle_map, primitive.id()), v2), v2 ) ))); + m_project_point(get(face_to_triangle_map, primitive.id()), v2), v2)))); if (v2_dist < h_v2_lower) h_v2_lower = v2_dist; // it is () part of (11) in the paper - // Get the distance as maximizers over all vertices - const FT distance_lower = std::max(std::max(h_v0_lower,h_v1_lower),h_v2_lower); // it is (11) in the paper - const FT distance_upper = std::max(std::max(v0_dist,v1_dist),v2_dist); // it is () part of (10) in the paper + // Get the distance as maximizers over all vertices. + const FT distance_lower = std::max(std::max(h_v0_lower, h_v1_lower), h_v2_lower); // it is (11) in the paper + const FT distance_upper = std::max(std::max(v0_dist, v1_dist), v2_dist); // it is () part of (10) in the paper // Since we are at the level of a single triangle in TM2, distance_upper is // actually the correct Hausdorff distance from the query triangle in - // TM1 to the primitive triangle in TM2 - if ( distance_lower < h_local_lower ) h_local_lower = distance_lower; // TODO: do we need this `if` here? - if ( distance_upper < h_local_upper ) h_local_upper = distance_upper; // it is (10) in the paper + // TM1 to the primitive triangle in TM2. + if (distance_lower < h_local_bounds.lower) { + h_local_bounds.lower = distance_lower; + } + if (distance_upper < h_local_bounds.upper) { // it is (10) in the paper + h_local_bounds.upper = distance_upper; + } } // Determine whether child nodes will still contribute to a smaller - // Hausdorff distance and thus have to be entered - std::pair do_intersect_with_priority(const Query& query, const Node& node) const - { - // Get the bounding box of the nodes + // Hausdorff distance and thus have to be entered. + template + std::pair + do_intersect_with_priority(const Query& query, const Node& node) const { + + // Get the bounding box of the nodes. const auto bbox = node.bbox(); - // Get the vertices of the query triangle + + // Get the vertices of the query triangle. const Point_3 v0 = query.vertex(0); const Point_3 v1 = query.vertex(1); const Point_3 v2 = query.vertex(2); - // Find the axis aligned bbox of the triangle - const Point_3 tri_min = Point_3 ( - std::min(std::min( v0.x(), v1.x()), v2.x() ), - std::min(std::min( v0.y(), v1.y()), v2.y() ), - std::min(std::min( v0.z(), v1.z()), v2.z() ) - ); - const Point_3 tri_max = Point_3 ( - std::max(std::max( v0.x(), v1.x()), v2.x() ), - std::max(std::max( v0.y(), v1.y()), v2.y() ), - std::max(std::max( v0.z(), v1.z()), v2.z() ) - ); - // Compute distance of the bounding boxes - // Distance along the x-axis + // Find the axis aligned bbox of the triangle. + const Point_3 tri_min = Point_3 ( + std::min(std::min(v0.x(), v1.x()), v2.x()), + std::min(std::min(v0.y(), v1.y()), v2.y()), + std::min(std::min(v0.z(), v1.z()), v2.z())); + + const Point_3 tri_max = Point_3 ( + std::max(std::max(v0.x(), v1.x()), v2.x()), + std::max(std::max(v0.y(), v1.y()), v2.y()), + std::max(std::max(v0.z(), v1.z()), v2.z())); + + // Compute distance of the bounding boxes. + // Distance along the x-axis. FT dist_x = FT(0); - if ( tri_max.x() < bbox.min(0) ) { + if (tri_max.x() < bbox.min(0)) { dist_x = bbox.min(0) - tri_max.x(); - } else if ( bbox.max(0) < tri_min.x() ) { + } else if (bbox.max(0) < tri_min.x()) { dist_x = tri_min.x() - bbox.max(0); } - // Distance along the y-axis + + // Distance along the y-axis. FT dist_y = FT(0); - if ( tri_max.y() < bbox.min(1) ) { + if (tri_max.y() < bbox.min(1)) { dist_y = bbox.min(1) - tri_max.y(); - } else if ( bbox.max(1) < tri_min.y() ) { + } else if (bbox.max(1) < tri_min.y()) { dist_y = tri_min.y() - bbox.max(1); } - // Distance along the z-axis + + // Distance along the z-axis. FT dist_z = FT(0); - if ( tri_max.z() < bbox.min(2) ) { + if (tri_max.z() < bbox.min(2)) { dist_z = bbox.min(2) - tri_max.z(); - } else if ( bbox.max(2) < tri_min.z() ) { + } else if (bbox.max(2) < tri_min.z()) { dist_z = tri_min.z() - bbox.max(2); } // Lower bound on the distance between the two bounding boxes is given - // as the length of the diagonal of the bounding box between them - const FT dist = static_cast(CGAL::sqrt( CGAL::to_double(Vector_3(dist_x,dist_y,dist_z).squared_length() ))); + // as the length of the diagonal of the bounding box between them. + const FT dist = static_cast(CGAL::sqrt( + CGAL::to_double(Vector_3(dist_x, dist_y, dist_z).squared_length()))); // See Algorithm 2. // Check whether investigating the bbox can still lower the Hausdorff // distance and improve the current global bound. If so, enter the box. - if ( dist <= h_local_lower ) { - return std::make_pair(true, -dist); + if (dist <= h_local_bounds.lower) { + return std::make_pair(true , -dist); } else { return std::make_pair(false, FT(0)); } } - bool do_intersect(const Query& query, const Node& node ) const - { + template + bool do_intersect(const Query& query, const Node& node) const { return this->do_intersect_with_priority(query, node).first; } - // Return the local Hausdorff bounds computed for the passed query triangle - std::pair get_local_bounds() const - { - return std::make_pair( h_local_lower, h_local_upper ); + // Return the local Hausdorff bounds computed for the passed query triangle. + Local_bounds get_local_bounds() const { + return h_local_bounds; } private: + // Input data. const AABBTraits& m_traits; - // the mesh of this tree const TriangleMesh& m_tm2; - // its vertex point map const VPM2& m_vpm2; - // Local Hausdorff bounds for the query triangle - FT h_local_lower; - FT h_local_upper; - FT h_v0_lower; - FT h_v1_lower; - FT h_v2_lower; + + // Local Hausdorff bounds for the query triangle. + Local_bounds h_local_bounds; + FT h_v0_lower, h_v1_lower, h_v2_lower; + Project_point_3 m_project_point; }; + // Hausdorff primitive traits on TM1. + template< + typename AABBTraits, + typename Query, + typename Kernel, + typename TriangleMesh, + typename VPM1, typename VPM2> + class Hausdorff_primitive_traits_tm1 { - /** - * @class Hausdorff_primitive_traits_tm1 - */ - template - class Hausdorff_primitive_traits_tm1 - { - typedef AABB_face_graph_triangle_primitive TM2_primitive; - typedef typename AABB_tree< AABB_traits >::AABB_traits Tree_traits; - typedef typename AABBTraits::Primitive Primitive; - typedef ::CGAL::AABB_node Node; - typedef typename Kernel::FT FT; - typedef typename Kernel::Point_3 Point_3; - typedef typename Kernel::Vector_3 Vector_3; - typedef typename Kernel::Triangle_3 Triangle_3; - typedef AABB_tree< AABB_traits > TM2_tree; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - using Candidate = Candidate_triangle; - typedef std::priority_queue Heap_type; + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Vector_3 = typename Kernel::Vector_3; + using Triangle_3 = typename Kernel::Triangle_3; + + using TM2_primitive = AABB_face_graph_triangle_primitive; + using TM2_traits = AABB_traits; + using TM2_tree = AABB_tree; + using TM2_hd_traits = Hausdorff_primitive_traits_tm2; + + using Face_handle = typename boost::graph_traits::face_descriptor; + using Global_bounds = Bounds; + using Candidate = Candidate_triangle; + using Heap_type = std::priority_queue; public: - typedef FT Priority; + using Priority = FT; Hausdorff_primitive_traits_tm1( - const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, - const TriangleMesh& tm2 , const VPM1& vpm1, const VPM2& vpm2, - const FT& error_bound) - : m_traits(traits), m_tm1(tm1), m_tm2(tm2), - m_vpm1(vpm1), m_vpm2(vpm2), m_tm2_tree(tree), m_error_bound(error_bound) { + const AABBTraits& traits, const TM2_tree& tree, + const TriangleMesh& tm1, const TriangleMesh& tm2, + const VPM1& vpm1, const VPM2& vpm2, + const FT error_bound) : + m_traits(traits), + m_tm1(tm1), m_tm2(tm2), + m_vpm1(vpm1), m_vpm2(vpm2), + m_tm2_tree(tree), m_error_bound(error_bound) { // Initialize the global bounds with 0.0, they will only grow. - // If we leave zero here then we are very slow even for big input error bounds! - h_lower = m_error_bound; // = FT(0); - h_upper = m_error_bound; // = FT(0); + // If we leave zero here, then we are very slow even for big input error bounds! + h_global_bounds.lower = m_error_bound; // = FT(0); + h_global_bounds.upper = m_error_bound; // = FT(0); } // Explore the whole tree, i.e. always enter children if the methods // do_intersect() below determines that it is worthwhile. bool go_further() const { return true; } - // Compute the explicit Hausdorff distance to the given primitive - void intersection(const Query&, const Primitive& primitive) - { - // Map to transform faces of TM1 to actual triangles - const Triangle_from_face_descriptor_map m_face_to_triangle_map( &m_tm1, m_vpm1 ); + // Compute the explicit Hausdorff distance to the given primitive. + template + void intersection(const Query&, const Primitive& primitive) { + + // Map to transform faces of TM1 to actual triangles. + const Triangle_from_face_descriptor_map m_face_to_triangle_map(&m_tm1, m_vpm1); const Triangle_3 triangle = get(m_face_to_triangle_map, primitive.id()); // TODO Can we initialize the bounds here, s.t. we don't start with infty? @@ -265,110 +293,109 @@ namespace CGAL { // seen from the three vertices? In the paper, they start from infinity. // Call Culling on B with the single triangle found. - Hausdorff_primitive_traits_tm2 - traversal_traits_tm2( + TM2_hd_traits traversal_traits_tm2( m_tm2_tree.traits(), m_tm2, m_vpm2, infinity_value(), infinity_value(), infinity_value(), infinity_value(), - infinity_value() - ); + infinity_value()); m_tm2_tree.traversal_with_priority(triangle, traversal_traits_tm2); - // Update global Hausdorff bounds according to the obtained local bounds + // Update global Hausdorff bounds according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); - if (local_bounds.first > h_lower) { // it is (6) in the paper, see also Algorithm 1 - h_lower = local_bounds.first; + if (local_bounds.lower > h_global_bounds.lower) { // it is (6) in the paper, see also Algorithm 1 + h_global_bounds.lower = local_bounds.lower; } - if (local_bounds.second > h_upper) { // it is (6) in the paper, see also Algorithm 1 - h_upper = local_bounds.second; + if (local_bounds.upper > h_global_bounds.upper) { // it is (6) in the paper, see also Algorithm 1 + h_global_bounds.upper = local_bounds.upper; } // Store the triangle given as primitive here as candidate triangle // together with the local bounds it obtained to send it to subdivision later. - m_candidiate_triangles.push( Candidate(triangle, local_bounds, primitive.id()) ); + m_candidiate_triangles.push(Candidate(triangle, local_bounds)); } // Determine whether child nodes will still contribute to a larger - // Hausdorff distance and thus have to be entered - // TODO Document Query object, explain why I don't need it here. + // Hausdorff distance and thus have to be entered. + // TODO: Document Query object, explain why I don't need it here. // It does not depend on the error bound but it should. - std::pair do_intersect_with_priority(const Query& /*query*/, const Node& node) const - { - /* Have reached a node, determine whether or not to enter it */ - // Get the bounding box of the nodes + template + std::pair + do_intersect_with_priority(const Query&, const Node& node) const { + + // Have reached a node, determine whether or not to enter it. + // Get the bounding box of the nodes. const auto bbox = node.bbox(); - // Compute its center + + // Compute its center. const Point_3 center = Point_3( (bbox.min(0) + bbox.max(0)) / FT(2), (bbox.min(1) + bbox.max(1)) / FT(2), (bbox.min(2) + bbox.max(2)) / FT(2)); - // Find the point from TM2 closest to the center - const Point_3 closest = m_tm2_tree.closest_point(center); - // Compute the difference vector between the bbox center and the closest - // point in tm2 - Vector_3 difference = Vector_3( closest, center ); - // Shift the vector to be the difference between the farthest corner - // of the bounding box away from the closest point on TM2 + // Find the point from TM2 closest to the center. + const Point_3 closest = m_tm2_tree.closest_point(center); + + // Compute the difference vector between the bbox center and the closest point in tm2. + Vector_3 difference = Vector_3(closest, center); + + // Shift the vector to be the difference between the farthest corner + // of the bounding box away from the closest point on TM2. FT diff_x = (bbox.max(0) - bbox.min(0)) / FT(2); if (difference.x() < 0) diff_x = diff_x * -FT(1); FT diff_y = (bbox.max(1) - bbox.min(1)) / FT(2); if (difference.y() < 0) diff_y = diff_y * -FT(1); FT diff_z = (bbox.max(2) - bbox.min(2)) / FT(2); if (difference.z() < 0) diff_z = diff_z * -FT(1); - difference = difference + Vector_3( diff_x, diff_y, diff_z ); // it is (9) in the paper + difference = difference + Vector_3(diff_x, diff_y, diff_z); // it is (9) in the paper - // Compute distance from the farthest corner of the bbox to the closest - // point in TM2 - const FT dist = static_cast(CGAL::sqrt(CGAL::to_double( difference.squared_length() ))); + // Compute distance from the farthest corner of the bbox to the closest point in TM2. + const FT dist = static_cast(CGAL::sqrt( + CGAL::to_double(difference.squared_length()))); // See Algorithm 1 here. // If the distance is larger than the global lower bound, enter the node, i.e. return true. - // std::cout << dist << " : " << h_lower << std::endl; - if (dist > h_lower /* && (dist - h_lower) > m_error_bound */) { - return std::make_pair(true, dist); + if (dist > h_global_bounds.lower) { + return std::make_pair(true , +dist); } else { return std::make_pair(false, FT(0)); } } - bool do_intersect(const Query& query, const Node& node ) const - { + template + bool do_intersect(const Query& query, const Node& node) const { return this->do_intersect_with_priority(query, node).first; } // Return those triangles from TM1 which are candidates for including a - // point realizing the Hausdorff distance + // point realizing the Hausdorff distance. Heap_type& get_candidate_triangles() { return m_candidiate_triangles; } - // Return the local Hausdorff bounds computed for the passed query triangle - std::pair get_global_bounds() const - { - return std::make_pair( h_lower, h_upper ); + // Return the global Hausdorff bounds computed for the passed query triangle. + Global_bounds get_global_bounds() const { + return h_global_bounds; } private: + // Input data. const AABBTraits& m_traits; - // The two triangle meshes const TriangleMesh& m_tm1; const TriangleMesh& m_tm2; - // Their vertex-point-maps const VPM1& m_vpm1; const VPM2& m_vpm2; - // AABB tree for the second triangle mesh const TM2_tree& m_tm2_tree; - // Global Hausdorff bounds to be taken track of during the traversal - const FT& m_error_bound; - FT h_lower; - FT h_upper; - // List of candidate triangles with their Hausdorff bounds attached + + // Global Hausdorff bounds for the query triangle. + const FT m_error_bound; + Global_bounds h_global_bounds; + + // All candidate triangles. Heap_type m_candidiate_triangles; }; } -#endif //CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_HAUSDORFF_DISTANCE +#endif // CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_HAUSDORFF_DISTANCE From 4cf4e2c50ac1d1e7ca47a38db7235ddc6db17a3d Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 26 Apr 2021 15:21:58 +0200 Subject: [PATCH 156/349] return a pair of realizing triangles, still to be discussed --- ...usdorff_bounded_error_distance_example.cpp | 92 ++++++++----------- .../CGAL/Polygon_mesh_processing/distance.h | 24 ++++- ...traversal_traits_with_Hausdorff_distance.h | 26 ++++-- 3 files changed, 77 insertions(+), 65 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 357cf59a0b3..4e08421ffad 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -83,31 +83,6 @@ void save_mesh(const Surface_mesh& mesh, const std::string filepath) { } } -// Match faces minimum example. -void match_faces_issue(const bool save = false) { - - using Traits = CGAL::Exact_predicates_inexact_constructions_kernel; - using Mesh = CGAL::Surface_mesh; - using Face_handle = typename boost::graph_traits::face_descriptor; - - Mesh mesh1, mesh2; - CGAL::make_tetrahedron( - Point_3(0, 0, 0), Point_3(2, 0, 0), - Point_3(1, 1, 1), Point_3(1, 0, 2), mesh1); - - mesh2 = mesh1; - CGAL::PMP::isotropic_remeshing(mesh2.faces(), 0.05, mesh2); - - if (save) save_mesh(mesh1, "mesh1"); - if (save) save_mesh(mesh2, "mesh2"); - - std::vector mesh1_only, mesh2_only; - std::vector< std::pair > common; - - CGAL::PMP::match_faces(mesh1, mesh2, std::back_inserter(common), - std::back_inserter(mesh1_only), std::back_inserter(mesh2_only)); -} - // An easy example of a tetrahedron and its remeshed version. void remeshing_tetrahedon_example( const double error_bound, const bool save = false) { @@ -681,8 +656,8 @@ void test_timings(const std::string filepath, const FunctionWrapper& functor) { timer.stop(); std::cout << "* time 1 (sec.): " << timer.time() << std::endl; - std::cout << "dista = " << dista << std::endl; - std::cout << "distb = " << distb << std::endl; + std::cout << "* dista = " << dista << std::endl; + std::cout << "* distb = " << distb << std::endl; } template< @@ -764,15 +739,15 @@ void test_bunny( avg_time /= static_cast(times.size()); std::cout << std::endl << "* timings (msec.): " << std::endl; - std::cout << "avg time: " << avg_time * 1000.0 << std::endl; - std::cout << "min time: " << min_time * 1000.0 << std::endl; - std::cout << "max time: " << max_time * 1000.0 << std::endl; + std::cout << "* avg time: " << avg_time * 1000.0 << std::endl; + std::cout << "* min time: " << min_time * 1000.0 << std::endl; + std::cout << "* max time: " << max_time * 1000.0 << std::endl; } Triangle_3 get_triangle(const int index, const Surface_mesh& mesh) { const auto mfaces = faces(mesh); - assert(index > 0); + assert(index >= 0); assert(index < static_cast(mfaces.size())); const auto face = *(mfaces.begin() + index); @@ -786,24 +761,38 @@ Triangle_3 get_triangle(const int index, const Surface_mesh& mesh) { } void compute_realizing_triangles( - const Surface_mesh& mesh1, const Surface_mesh& mesh2, const double error_bound) { + const Surface_mesh& mesh1, const Surface_mesh& mesh2, + const double error_bound, const std::string prefix, const bool save = false) { std::cout << "* getting realizing triangles: " << std::endl; - const auto pair = + const auto data = PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound); - const int tri1 = static_cast(pair.second.first); - const int tri2 = static_cast(pair.second.second); + const auto& faces = data.second; + const int f1 = static_cast(faces.first); + const int f2 = static_cast(faces.second); - std::cout << "* Hausdorff: " << pair.first << std::endl; - std::cout << "* f1: " << tri1 << std::endl; - std::cout << "* f2: " << tri2 << std::endl; - if (tri1 != -1) { - const auto triangle = get_triangle(tri1, mesh1); - std::cout << "* triangle1: " << triangle << std::endl; + std::cout << "* Hausdorff: " << data.first << std::endl; + std::cout << "* f1: " << f1 << std::endl; + std::cout << "* f2: " << f2 << std::endl; + + if (f1 != -1 && save) { + const auto triangle = get_triangle(f1, mesh1); + Surface_mesh sm1; + sm1.add_vertex(triangle[0]); + sm1.add_vertex(triangle[1]); + sm1.add_vertex(triangle[2]); + sm1.add_face(sm1.vertices()); + save_mesh(sm1, prefix + "triangle1"); } - if (tri2 != -1) { - const auto triangle = get_triangle(tri2, mesh2); - std::cout << "* triangle2: " << triangle << std::endl; + + if (f2 != -1 && save) { + const auto triangle = get_triangle(f2, mesh2); + Surface_mesh sm2; + sm2.add_vertex(triangle[0]); + sm2.add_vertex(triangle[1]); + sm2.add_vertex(triangle[2]); + sm2.add_face(sm2.vertices()); + save_mesh(sm2, prefix + "triangle2"); } } @@ -829,7 +818,7 @@ void test_realizing_triangles( if (save) save_mesh(mesh1, "1mesh1"); if (save) save_mesh(mesh2, "1mesh2"); - compute_realizing_triangles(mesh1, mesh2, error_bound); + compute_realizing_triangles(mesh1, mesh2, error_bound, "1", save); // Complex test. std::cout << std::endl << "... complex test ..." << std::endl; @@ -842,7 +831,7 @@ void test_realizing_triangles( if (save) save_mesh(mesh1, "2mesh1"); if (save) save_mesh(mesh2, "2mesh2"); - compute_realizing_triangles(mesh1, mesh2, error_bound); + compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); } int main(int argc, char** argv) { @@ -864,7 +853,6 @@ int main(int argc, char** argv) { // perturbing_mesh_example(filepath, error_bound); // moving_mesh_example(filepath, filepath, 5, error_bound); - // match_faces_issue(); // std::cout << std::endl; // return EXIT_SUCCESS; @@ -879,13 +867,13 @@ int main(int argc, char** argv) { // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); - test_synthetic_data(bound_hd); + // test_synthetic_data(bound_hd); // --- Compare on common meshes. // test_one_versus_another(apprx_hd, naive_hd); // test_one_versus_another(naive_hd, bound_hd); - test_one_versus_another(bound_hd, apprx_hd); + // test_one_versus_another(bound_hd, apprx_hd); // --- Compare on real meshes. @@ -894,14 +882,14 @@ int main(int argc, char** argv) { // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); - test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); // --- Compare timings. filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); - test_timings(filepath, bound_hd); + // test_timings(filepath, bound_hd); // --- Compare with the paper. @@ -910,7 +898,7 @@ int main(int argc, char** argv) { test_bunny(bound_hd, 0); // --- Testing realizing triangles. - test_realizing_triangles(error_bound, true); + // test_realizing_triangles(error_bound); // ------------------------------------------------------------------------ // std::cout << std::endl; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 3ddbe6786f0..fa389684ace 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1475,6 +1475,7 @@ bounded_error_Hausdorff_impl( // the triangle to the second mesh. Use it as new global lower bound. // TODO: Update the reference to the realizing triangle here as this is the best current guess. global_bounds.lower = triangle_bounds.upper; + global_bounds.lpair.second = triangle_bounds.uface; continue; } @@ -1488,6 +1489,7 @@ bounded_error_Hausdorff_impl( // The upper bound of this triangle is within error tolerance of // the actual upper bound, use it. global_bounds.lower = triangle_bounds.upper; + global_bounds.lpair.second = triangle_bounds.uface; continue; } @@ -1505,8 +1507,7 @@ bounded_error_Hausdorff_impl( // Call Culling on B with the single triangle found. TM2_hd_traits traversal_traits_tm2( tm2_tree.traits(), tm2, vpm2, - triangle_bounds.lower, - triangle_bounds.upper, + triangle_bounds, infinity_value(), infinity_value(), infinity_value()); @@ -1516,6 +1517,7 @@ bounded_error_Hausdorff_impl( const auto local_bounds = traversal_traits_tm2.get_local_bounds(); if (local_bounds.lower > global_bounds.lower) { global_bounds.lower = local_bounds.lower; + global_bounds.lpair.second = local_bounds.lface; } // TODO: Additionally store the face descriptor of the parent from TM1 in the Candidate_triangle. @@ -1525,15 +1527,29 @@ bounded_error_Hausdorff_impl( // Update global upper Hausdorff bound after subdivision. const FT current_max = candidate_triangles.top().bounds.upper; - global_bounds.upper = std::max(current_max, global_bounds.lower); + // global_bounds.upper = std::max(current_max, global_bounds.lower); + + if (current_max > global_bounds.lower) { + global_bounds.upper = current_max; + global_bounds.upair.second = candidate_triangles.top().bounds.uface; + } else { + global_bounds.upper = global_bounds.lower; + global_bounds.upair.second = global_bounds.lpair.second; + } } } // std::cout << "* number of candidate triangles after: " << candidate_triangles.size() << std::endl; + // std::cout << "* found lface 1:" << static_cast(global_bounds.lpair.first) << std::endl; + // std::cout << "* found lface 2:" << static_cast(global_bounds.lpair.second) << std::endl; + + // std::cout << "* found uface 1:" << static_cast(global_bounds.upair.first) << std::endl; + // std::cout << "* found uface 2:" << static_cast(global_bounds.upair.second) << std::endl; + // Return linear interpolation between the found lower and upper bounds. const double hdist = CGAL::to_double((global_bounds.lower + global_bounds.upper) / FT(2)); - const auto realizing_triangles = std::make_pair(Face_handle(), Face_handle()); + const auto realizing_triangles = global_bounds.upair; return std::make_pair(hdist, realizing_triangles); #if !defined(CGAL_LINKED_WITH_TBB) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index e5a419be3b9..bb7fe813762 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -37,10 +37,12 @@ namespace CGAL { struct Bounds { using FT = typename Kernel::FT; - FT lower = -FT(1); - FT upper = -FT(1); + FT lower = infinity_value(); + FT upper = infinity_value(); Face_handle lface; Face_handle uface; + std::pair lpair; + std::pair upair; }; // Candidate triangle. @@ -81,13 +83,14 @@ namespace CGAL { Hausdorff_primitive_traits_tm2( const AABBTraits& traits, const TriangleMesh& tm2, const VPM2& vpm2, - const FT h_lower_init, const FT h_upper_init, - const FT h_v0_lower_init, const FT h_v1_lower_init, const FT h_v2_lower_init) : - m_traits(traits), m_tm2(tm2), m_vpm2(vpm2) { + const Local_bounds& local_bounds, + const FT h_v0_lower_init, + const FT h_v1_lower_init, + const FT h_v2_lower_init) : + m_traits(traits), m_tm2(tm2), m_vpm2(vpm2), + h_local_bounds(local_bounds) { // Initialize the global and local bounds with the given values. - h_local_bounds.lower = h_lower_init; - h_local_bounds.upper = h_upper_init; h_v0_lower = h_v0_lower_init; h_v1_lower = h_v1_lower_init; h_v2_lower = h_v2_lower_init; @@ -141,9 +144,11 @@ namespace CGAL { // TM1 to the primitive triangle in TM2. if (distance_lower < h_local_bounds.lower) { h_local_bounds.lower = distance_lower; + h_local_bounds.lface = primitive.id(); } if (distance_upper < h_local_bounds.upper) { // it is (10) in the paper h_local_bounds.upper = distance_upper; + h_local_bounds.uface = primitive.id(); } } @@ -295,8 +300,7 @@ namespace CGAL { // Call Culling on B with the single triangle found. TM2_hd_traits traversal_traits_tm2( m_tm2_tree.traits(), m_tm2, m_vpm2, - infinity_value(), - infinity_value(), + Bounds(), infinity_value(), infinity_value(), infinity_value()); @@ -307,9 +311,13 @@ namespace CGAL { if (local_bounds.lower > h_global_bounds.lower) { // it is (6) in the paper, see also Algorithm 1 h_global_bounds.lower = local_bounds.lower; + h_global_bounds.lpair.first = primitive.id(); + h_global_bounds.lpair.second = local_bounds.lface; } if (local_bounds.upper > h_global_bounds.upper) { // it is (6) in the paper, see also Algorithm 1 h_global_bounds.upper = local_bounds.upper; + h_global_bounds.upair.first = primitive.id(); + h_global_bounds.upair.second = local_bounds.uface; } // Store the triangle given as primitive here as candidate triangle From d5e1c1fdd92efff0d750267f883de98a4606939b Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 26 Apr 2021 15:38:06 +0200 Subject: [PATCH 157/349] shorter bunny test --- .../hausdorff_bounded_error_distance_example.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 4e08421ffad..baf911a288e 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -697,9 +697,9 @@ void test_bunny( if (save) save_mesh(mesh2, "mesh2"); timer.reset(); timer.start(); - const double dista = functor(mesh1, mesh2); + // const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double distc = (CGAL::max)(dista, distb); + const double distc = distb; // (CGAL::max)(dista, distb); timer.stop(); times.push_back(timer.time()); std::cout << "* distance / Hausdorff / time (sec.) : " << From 5e99e80134b81d2894a897f610e2bfdb6dbde0aa Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 26 Apr 2021 17:07:19 +0200 Subject: [PATCH 158/349] refined and debugged aabb tree with priority traversal --- .../include/CGAL/internal/AABB_tree/AABB_node.h | 12 ++++-------- .../CGAL/Polygon_mesh_processing/distance.h | 3 +++ ...BB_traversal_traits_with_Hausdorff_distance.h | 16 ++++++++++++---- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h index 33d93989c7b..3f64d69c22e 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h @@ -186,29 +186,25 @@ AABB_node::traversal_with_priority(const Query& query, typename Traversal_traits::Priority pleft, pright; std::tie(ileft, pleft) = traits.do_intersect_with_priority(query, left_child()); std::tie(iright, pright) = traits.do_intersect_with_priority(query, right_child()); - - // Add an assertion, if you intersect one of the two children, - // you also intersect their father. + CGAL_precondition( (ileft || iright) ? traits.do_intersect(query, *this) : true ); if(ileft) { if(iright) { // Both children have to be inspected. - // You can compare pright to the updated bound, without calling the method, - // or if it can cull, call do_intersect() with the previous priority. if(pleft >= pright) { // Inspect the left child first, has higher priority. - left_child().traversal_with_priority(query, traits, nb_primitives/2); // the bound is updated here - if( traits.go_further() ) // && traits.do_intersect(query, right_child()) ) // TODO: shall we call again do_intersect? (Benchmarks show it slows down the Hausdorff Distance) + left_child().traversal_with_priority(query, traits, nb_primitives/2); + if( traits.go_further() ) right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); } else { // Inspect the right child first, has higher priority. right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2); - if( traits.go_further() ) // && traits.do_intersect(query, left_child()) ) // TODO: shall we call again do_intersect? (Benchmarks show it slows down the Hausdorff Distance) + if( traits.go_further() ) left_child().traversal_with_priority(query, traits, nb_primitives/2); } } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index fa389684ace..c6973582fb7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1515,6 +1515,9 @@ bounded_error_Hausdorff_impl( // Update global lower Hausdorff bound according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); + CGAL_precondition(local_bounds.lpair == traversal_traits_tm1.default_face_pair()); + CGAL_precondition(local_bounds.upair == traversal_traits_tm1.default_face_pair()); + if (local_bounds.lower > global_bounds.lower) { global_bounds.lower = local_bounds.lower; global_bounds.lpair.second = local_bounds.lface; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index bb7fe813762..500aa383b04 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -39,10 +39,12 @@ namespace CGAL { FT lower = infinity_value(); FT upper = infinity_value(); - Face_handle lface; - Face_handle uface; - std::pair lpair; - std::pair upair; + Face_handle lface = Face_handle(); + Face_handle uface = Face_handle(); + std::pair lpair = + std::make_pair(Face_handle(), Face_handle()); + std::pair upair = + std::make_pair(Face_handle(), Face_handle()); }; // Candidate triangle. @@ -285,6 +287,10 @@ namespace CGAL { // do_intersect() below determines that it is worthwhile. bool go_further() const { return true; } + const std::pair default_face_pair() const { + return std::make_pair(Face_handle(), Face_handle()); + } + // Compute the explicit Hausdorff distance to the given primitive. template void intersection(const Query&, const Primitive& primitive) { @@ -308,6 +314,8 @@ namespace CGAL { // Update global Hausdorff bounds according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); + CGAL_assertion(local_bounds.lpair == default_face_pair()); + CGAL_assertion(local_bounds.upair == default_face_pair()); if (local_bounds.lower > h_global_bounds.lower) { // it is (6) in the paper, see also Algorithm 1 h_global_bounds.lower = local_bounds.lower; From 95ab1a57a0baef52fb272c650433bfaeeef8fe5f Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 27 Apr 2021 11:22:55 +0200 Subject: [PATCH 159/349] tests moved to the test folder --- ...usdorff_bounded_error_distance_example.cpp | 727 +---------------- ...traversal_traits_with_Hausdorff_distance.h | 4 +- .../Polygon_mesh_processing/CMakeLists.txt | 2 + .../data/tetrahedron-remeshed.off | 0 .../data/tetrahedron.off | 0 .../test_hausdorff_bounded_error_distance.cpp | 769 ++++++++++++++++++ .../test_pmp_distance.cpp | 29 +- 7 files changed, 785 insertions(+), 746 deletions(-) rename Polygon_mesh_processing/{examples => test}/Polygon_mesh_processing/data/tetrahedron-remeshed.off (100%) rename Polygon_mesh_processing/{examples => test}/Polygon_mesh_processing/data/tetrahedron.off (100%) create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index baf911a288e..43cc1697cc3 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -1,8 +1,6 @@ #include #include -#include #include -#include #include #include @@ -13,15 +11,10 @@ #include #include -using SCK = CGAL::Simple_cartesian; -using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; -using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; - -using Kernel = EPICK; -using FT = typename Kernel::FT; -using Point_3 = typename Kernel::Point_3; -using Vector_3 = typename Kernel::Vector_3; -using Triangle_3 = typename Kernel::Triangle_3; +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using FT = typename Kernel::FT; +using Point_3 = typename Kernel::Point_3; +using Vector_3 = typename Kernel::Vector_3; using TAG = CGAL::Parallel_if_available_tag; using Surface_mesh = CGAL::Surface_mesh; @@ -30,35 +23,6 @@ using Timer = CGAL::Real_timer; namespace PMP = CGAL::Polygon_mesh_processing; -struct Approximate_hd_wrapper { - const std::size_t m_num_samples; - std::string name() const { return "approximate"; } - Approximate_hd_wrapper(const std::size_t num_samples) : m_num_samples(num_samples) { } - double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { - return PMP::approximate_Hausdorff_distance(tm1, tm2, - PMP::parameters::number_of_points_per_area_unit(m_num_samples), - PMP::parameters::number_of_points_per_area_unit(m_num_samples)); - } -}; - -struct Naive_bounded_error_hd_wrapper { - const double m_error_bound; - std::string name() const { return "naive bounded error"; } - Naive_bounded_error_hd_wrapper(const double error_bound) : m_error_bound(error_bound) { } - double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { - return PMP::bounded_error_Hausdorff_distance_naive(tm1, tm2, m_error_bound); - } -}; - -struct Bounded_error_hd_wrapper { - const double m_error_bound; - std::string name() const { return "bounded error"; } - Bounded_error_hd_wrapper(const double error_bound) : m_error_bound(error_bound) { } - double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { - return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound).first; - } -}; - void get_mesh(const std::string filepath, Surface_mesh& mesh) { mesh.clear(); @@ -215,692 +179,17 @@ void moving_mesh_example( } } -template -void test_0(const FunctionWrapper& functor, const bool save = false) { - - // The same triangle. - // Expected distance is 0. - - std::cout.precision(20); - Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 0 ---- " << std::endl; - - mesh1.add_vertex(Point_3(0, 0, 0)); - mesh1.add_vertex(Point_3(2, 0, 0)); - mesh1.add_vertex(Point_3(1, 1, 0)); - mesh1.add_face(mesh1.vertices()); - if (save) save_mesh(mesh1, "mesh1"); - - mesh2 = mesh1; - if (save) save_mesh(mesh2, "mesh2"); - - const double dista = functor(mesh1, mesh2); - const double distb = functor(mesh2, mesh1); - - std::cout << "* Hausdorff distance (expected 0): " << dista << std::endl; - std::cout << "* HInverted distance (expected 0): " << distb << std::endl; -} - -template -void test_1(const FunctionWrapper& functor, const bool save = false) { - - // Two triangles are parallel and 1 unit distance away from each other. - // Expected distance is 1. - - std::cout.precision(20); - Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 1 ---- " << std::endl; - - mesh1.add_vertex(Point_3(0, 0, 0)); - mesh1.add_vertex(Point_3(2, 0, 0)); - mesh1.add_vertex(Point_3(1, 1, 0)); - mesh1.add_face(mesh1.vertices()); - if (save) save_mesh(mesh1, "mesh1"); - - mesh2.add_vertex(Point_3(0, 0, 1)); - mesh2.add_vertex(Point_3(2, 0, 1)); - mesh2.add_vertex(Point_3(1, 1, 1)); - mesh2.add_face(mesh2.vertices()); - if (save) save_mesh(mesh2, "mesh2"); - - const double dista = functor(mesh1, mesh2); - const double distb = functor(mesh2, mesh1); - - std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; - std::cout << "* HInverted distance (expected 1): " << distb << std::endl; -} - -template -void test_2(const FunctionWrapper& functor, const bool save = false) { - - // One triangle is orthogonal to the other one and shares a common edge. - // Expected distance is 1. - - std::cout.precision(20); - Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 2 ---- " << std::endl; - - mesh1.add_vertex(Point_3(0, 0, 0)); - mesh1.add_vertex(Point_3(2, 0, 0)); - mesh1.add_vertex(Point_3(1, 1, 0)); - mesh1.add_face(mesh1.vertices()); - if (save) save_mesh(mesh1, "mesh1"); - - mesh2.add_vertex(Point_3(0, 0, 0)); - mesh2.add_vertex(Point_3(2, 0, 0)); - mesh2.add_vertex(Point_3(1, 0, 1)); - mesh2.add_face(mesh2.vertices()); - if (save) save_mesh(mesh2, "mesh2"); - - const double dista = functor(mesh1, mesh2); - const double distb = functor(mesh2, mesh1); - - std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; - std::cout << "* HInverted distance (expected 1): " << distb << std::endl; -} - -template -void test_3(const FunctionWrapper& functor, const bool save = false) { - - // One triangle is orthogonal to the other one and shares a common edge - // that is moved 1 unit distance away. - // Expected distances are sqrt(2) and 2. - - std::cout.precision(20); - Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 3 ---- " << std::endl; - - mesh1.add_vertex(Point_3(0, 0, 0)); - mesh1.add_vertex(Point_3(2, 0, 0)); - mesh1.add_vertex(Point_3(1, 1, 0)); - mesh1.add_face(mesh1.vertices()); - if (save) save_mesh(mesh1, "mesh1"); - - mesh2.add_vertex(Point_3(0, 0, 1)); - mesh2.add_vertex(Point_3(2, 0, 1)); - mesh2.add_vertex(Point_3(1, 0, 2)); - mesh2.add_face(mesh2.vertices()); - if (save) save_mesh(mesh2, "mesh2"); - - const double dista = functor(mesh1, mesh2); - const double distb = functor(mesh2, mesh1); - - std::cout << "* Hausdorff distance (expected sqrt(2)): " << dista << std::endl; - std::cout << "* HInverted distance (expected 2 ): " << distb << std::endl; -} - -template -void test_4(const FunctionWrapper& functor, const bool save = false) { - - // One triangle is orthogonal to the other one and shares a common vertex. - // Expected distance is 1.2247448713915889407. - - std::cout.precision(20); - Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 4 ---- " << std::endl; - - mesh1.add_vertex(Point_3(0, 0, 0)); - mesh1.add_vertex(Point_3(2, 0, 0)); - mesh1.add_vertex(Point_3(1, 1, 0)); - mesh1.add_face(mesh1.vertices()); - if (save) save_mesh(mesh1, "mesh1"); - - mesh2.add_vertex(Point_3(0, 1, 1)); - mesh2.add_vertex(Point_3(2, 1, 1)); - mesh2.add_vertex(Point_3(1, 1, 0)); - mesh2.add_face(mesh2.vertices()); - if (save) save_mesh(mesh2, "mesh2"); - - const double dista = functor(mesh1, mesh2); - const double distb = functor(mesh2, mesh1); - - std::cout << "* Hausdorff distance (expected 1.22): " << dista << std::endl; - std::cout << "* HInverted distance (expected 1.22): " << distb << std::endl; -} - -template -void test_5(const FunctionWrapper& functor, const bool save = false) { - - // One triangle is orthogonal to the other one and shares a common vertex - // that is moved 1 unit distance away. - // Expected distances are 1.7320508075688771932 and 2.1213203435596423851. - - std::cout.precision(20); - Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 5 ---- " << std::endl; - - mesh1.add_vertex(Point_3(0, 0, 0)); - mesh1.add_vertex(Point_3(2, 0, 0)); - mesh1.add_vertex(Point_3(1, 1, 0)); - mesh1.add_face(mesh1.vertices()); - if (save) save_mesh(mesh1, "mesh1"); - - mesh2.add_vertex(Point_3(0, 1, 2)); - mesh2.add_vertex(Point_3(2, 1, 2)); - mesh2.add_vertex(Point_3(1, 1, 1)); - mesh2.add_face(mesh2.vertices()); - if (save) save_mesh(mesh2, "mesh2"); - - const double dista = functor(mesh1, mesh2); - const double distb = functor(mesh2, mesh1); - - std::cout << "* Hausdorff distance (expected 1.73): " << dista << std::endl; - std::cout << "* HInverted distance (expected 2.12): " << distb << std::endl; -} - -template -void test_6(const FunctionWrapper& functor, const bool save = false) { - - // The first and second mesh have different number of triangles. - // They are parallel and lie at the same plane. The middle triangle is overlapping. - // Expected distances are 0 and 0.70710678118654757274. - - std::cout.precision(20); - Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 6 ---- " << std::endl; - - mesh1.add_vertex(Point_3(0, 0, 0)); - mesh1.add_vertex(Point_3(2, 0, 0)); - mesh1.add_vertex(Point_3(1, 1, 0)); - mesh1.add_face(mesh1.vertices()); - if (save) save_mesh(mesh1, "mesh1"); - - const auto v0 = mesh2.add_vertex(Point_3(0, 0, 0)); - const auto v1 = mesh2.add_vertex(Point_3(2, 0, 0)); - const auto v2 = mesh2.add_vertex(Point_3(1, 1, 0)); - const auto v3 = mesh2.add_vertex(Point_3(2, 1, 0)); - const auto v4 = mesh2.add_vertex(Point_3(0, 1, 0)); - - mesh2.add_face(v0, v1, v2); - mesh2.add_face(v2, v1, v3); - mesh2.add_face(v0, v2, v4); - if (save) save_mesh(mesh2, "mesh2"); - - const double dista = functor(mesh1, mesh2); - const double distb = functor(mesh2, mesh1); - - std::cout << "* Hausdorff distance (expected 0.0): " << dista << std::endl; - std::cout << "* HInverted distance (expected 0.7): " << distb << std::endl; -} - -template -void test_7(const FunctionWrapper& functor, const bool save = false) { - - // One triangle is moved to 0.5 unit distance away from 3 other triangles. - // The first and second meshes are parallel. - // Expected distances are 0.5 and 0.86602540378443859659. - - std::cout.precision(20); - Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 7 ---- " << std::endl; - - mesh1.add_vertex(Point_3(0, 0, 0)); - mesh1.add_vertex(Point_3(2, 0, 0)); - mesh1.add_vertex(Point_3(1, 1, 0)); - mesh1.add_face(mesh1.vertices()); - if (save) save_mesh(mesh1, "mesh1"); - - const auto v0 = mesh2.add_vertex(Point_3(0, 0, 0.5)); - const auto v1 = mesh2.add_vertex(Point_3(2, 0, 0.5)); - const auto v2 = mesh2.add_vertex(Point_3(1, 1, 0.5)); - const auto v3 = mesh2.add_vertex(Point_3(2, 1, 0.5)); - const auto v4 = mesh2.add_vertex(Point_3(0, 1, 0.5)); - - mesh2.add_face(v0, v1, v2); - mesh2.add_face(v2, v1, v3); - mesh2.add_face(v0, v2, v4); - if (save) save_mesh(mesh2, "mesh2"); - - const double dista = functor(mesh1, mesh2); - const double distb = functor(mesh2, mesh1); - - std::cout << "* Hausdorff distance (expected 0.50): " << dista << std::endl; - std::cout << "* HInverted distance (expected 0.86): " << distb << std::endl; -} - -template -void test_8(const FunctionWrapper& functor, const bool save = false) { - - // One mesh has one triangle at zero level, another mesh has two triangles - // where the first one is at level 1 and the second one is at level 2. - // Expected distances are 1 and 2. - - std::cout.precision(20); - Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 8 ---- " << std::endl; - - mesh1.add_vertex(Point_3(0, 0, 0)); - mesh1.add_vertex(Point_3(2, 0, 0)); - mesh1.add_vertex(Point_3(1, 1, 0)); - mesh1.add_face(mesh1.vertices()); - if (save) save_mesh(mesh1, "mesh1"); - - const auto v0 = mesh2.add_vertex(Point_3(0, 0, 1)); - const auto v1 = mesh2.add_vertex(Point_3(2, 0, 1)); - const auto v2 = mesh2.add_vertex(Point_3(1, 1, 1)); - const auto v3 = mesh2.add_vertex(Point_3(0, 0, 2)); - const auto v4 = mesh2.add_vertex(Point_3(2, 0, 2)); - const auto v5 = mesh2.add_vertex(Point_3(1, 1, 2)); - - mesh2.add_face(v0, v1, v2); - mesh2.add_face(v3, v4, v5); - if (save) save_mesh(mesh2, "mesh2"); - - const double dista = functor(mesh1, mesh2); - const double distb = functor(mesh2, mesh1); - - std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; - std::cout << "* HInverted distance (expected 2): " << distb << std::endl; -} - -template -void test_9(const FunctionWrapper& functor, const bool save = false) { - - // Two meshes partially overlap, have 2 triangles in common and each one has - // two its own trianles. All triangles form a Z shape where the height is 1. - // The expected result is 1. - - std::cout.precision(20); - Surface_mesh mesh1, mesh2; - std::cout << " ---- testing 9 ---- " << std::endl; - - auto v0 = mesh1.add_vertex(Point_3(0, 0, 0)); - auto v1 = mesh1.add_vertex(Point_3(1, 0, 0)); - auto v2 = mesh1.add_vertex(Point_3(0, 1, 0)); - auto v3 = mesh1.add_vertex(Point_3(1, 1, 0)); - auto v4 = mesh1.add_vertex(Point_3(1, 0, 1)); - auto v5 = mesh1.add_vertex(Point_3(1, 1, 1)); - mesh1.add_face(v0, v1, v2); - mesh1.add_face(v2, v1, v3); - mesh1.add_face(v1, v4, v3); - mesh1.add_face(v3, v4, v5); - if (save) save_mesh(mesh1, "mesh1"); - - v0 = mesh2.add_vertex(Point_3(2, 0, 1)); - v1 = mesh2.add_vertex(Point_3(1, 0, 0)); - v2 = mesh2.add_vertex(Point_3(2, 1, 1)); - v3 = mesh2.add_vertex(Point_3(1, 1, 0)); - v4 = mesh2.add_vertex(Point_3(1, 0, 1)); - v5 = mesh2.add_vertex(Point_3(1, 1, 1)); - mesh2.add_face(v1, v4, v3); - mesh2.add_face(v3, v4, v5); - mesh2.add_face(v4, v0, v5); - mesh2.add_face(v5, v0, v2); - if (save) save_mesh(mesh2, "mesh2"); - - const double dista = functor(mesh1, mesh2); - const double distb = functor(mesh2, mesh1); - - std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; - std::cout << "* HInverted distance (expected 1): " << distb << std::endl; -} - -template -void test_synthetic_data(const FunctionWrapper& functor) { - - std::cout << std::endl << "* testing synthetic data:" << std::endl; - std::cout << "* name -> " << functor.name() << std::endl; - - test_0(functor); // 1 parallel - test_1(functor); - test_2(functor); // 1 edge touching - test_3(functor); - test_4(functor); // 1 vertex touching - test_5(functor); - test_6(functor); // 1 to multiple - test_7(functor); - test_8(functor); - test_9(functor); // overlapping -} - -template< -typename FunctionWrapper1, -typename FunctionWrapper2> -void test_one_versus_another( - const FunctionWrapper1& functor1, - const FunctionWrapper2& functor2) { - - std::cout.precision(20); - const std::string filepath1 = "data/tetrahedron.off"; - const std::string filepath2 = "data/tetrahedron-remeshed.off"; - - std::cout << std::endl << "* testing one versus another (tetrahedron):" << std::endl; - std::cout << "* name 1 -> " << functor1.name() << std::endl; - std::cout << "* name 2 -> " << functor2.name() << std::endl; - - Surface_mesh mesh1, mesh2; - get_meshes(filepath1, filepath2, mesh1, mesh2); - - // TEST 0. - // Load and compare. - // The expected distance is 0. - std::cout << " ---- testing 0 ---- " << std::endl; - const double dista0 = functor1(mesh1, mesh2); - const double distb0 = functor2(mesh1, mesh2); - std::cout << "* Hausdorff distance1: " << dista0 << std::endl; - std::cout << "* Hausdorff distance2: " << distb0 << std::endl; - - std::cout << "* traslating by 1 unit ..." << std::endl; - PMP::transform(Affine_transformation_3(CGAL::Translation(), - Vector_3(FT(0), FT(0), FT(1))), mesh2); - - // TEST 1. - // Translate by 1 unit distance and compare. - // The expected distance is 1. - std::cout << " ---- testing 1 ---- " << std::endl; - const double dista1 = functor1(mesh1, mesh2); - const double distb1 = functor2(mesh1, mesh2); - std::cout << "* Hausdorff distance1: " << dista1 << std::endl; - std::cout << "* Hausdorff distance2: " << distb1 << std::endl; -} - -template< -typename FunctionWrapper1, -typename FunctionWrapper2> -void test_real_meshes( - const std::string filepath1, - const std::string filepath2, - const FunctionWrapper1& functor1, - const FunctionWrapper2& functor2) { - - std::cout.precision(20); - std::cout << std::endl << "* testing real meshes:" << std::endl; - std::cout << "* input path 1: " << filepath1 << std::endl; - std::cout << "* input path 2: " << filepath2 << std::endl; - - Surface_mesh mesh1, mesh2; - get_meshes(filepath1, filepath2, mesh1, mesh2); - - std::cout << std::endl; - std::cout << "* name 1 -> " << functor1.name() << std::endl; - std::cout << "* name 2 -> " << functor2.name() << std::endl; - - // Load and compare. - std::cout << std::endl; - std::cout << " ---- testing ---- " << std::endl; - const double dista0 = functor1(mesh1, mesh2); - const double dista1 = functor1(mesh2, mesh1); - const double distb0 = functor2(mesh1, mesh2); - const double distb1 = functor2(mesh2, mesh1); - std::cout << std::endl; - std::cout << "* Hausdorff distance1 f: " << dista0 << std::endl; - std::cout << "* Hausdorff distance1 b: " << dista1 << std::endl; - std::cout << std::endl; - std::cout << "* Hausdorff distance2 f: " << distb0 << std::endl; - std::cout << "* Hausdorff distance2 b: " << distb1 << std::endl; -} - -template< -typename FunctionWrapper> -void test_timings(const std::string filepath, const FunctionWrapper& functor) { - - std::cout.precision(20); - std::cout << std::endl << "* testing timing: " << functor.name() << std::endl; - - Timer timer; - Surface_mesh mesh1, mesh2; - get_meshes(filepath, filepath, mesh1, mesh2); - - timer.reset(); - timer.start(); - const double dista = functor(mesh1, mesh2); - timer.stop(); - std::cout << "* time 0 (sec.): " << timer.time() << std::endl; - - PMP::transform(Affine_transformation_3(CGAL::Translation(), - Vector_3(FT(0), FT(0), FT(1))), mesh2); - - timer.reset(); - timer.start(); - const double distb = functor(mesh1, mesh2); - timer.stop(); - std::cout << "* time 1 (sec.): " << timer.time() << std::endl; - - std::cout << "* dista = " << dista << std::endl; - std::cout << "* distb = " << distb << std::endl; -} - -template< -typename FunctionWrapper> -void test_bunny( - const FunctionWrapper& functor, const int n = 5, const bool save = false) { - - std::cout.precision(20); - const std::string filepath1 = "data/bunny1.off"; // approx 16.3K - const std::string filepath2 = "data/bunny2.off"; // approx 69.4K - - std::cout << std::endl << "* testing bunny:" << std::endl; - std::cout << "* name -> " << functor.name() << std::endl; - - Surface_mesh mesh1, mesh2; - get_meshes(filepath1, filepath2, mesh1, mesh2); - if (save) save_mesh(mesh1, "mesh1"); - if (save) save_mesh(mesh2, "mesh2"); - - // Get 3 times longest dimension. - const auto bbox = PMP::bbox(mesh2); - const FT dist1 = static_cast(CGAL::abs(bbox.xmax() - bbox.xmin())); - const FT dist2 = static_cast(CGAL::abs(bbox.ymax() - bbox.ymin())); - const FT dist3 = static_cast(CGAL::abs(bbox.zmax() - bbox.zmin())); - const FT dim = FT(3) * (CGAL::max)((CGAL::max)(dist1, dist2), dist3); - - // Get timings. - Timer timer; - std::vector times; - times.reserve(n); - - if (n == 0) { - - const FT distance = dim; - PMP::transform(Affine_transformation_3(CGAL::Translation(), - Vector_3(distance, distance, distance)), mesh2); - if (save) save_mesh(mesh2, "mesh2"); - timer.reset(); - timer.start(); - // const double dista = functor(mesh1, mesh2); - const double distb = functor(mesh2, mesh1); - const double distc = distb; // (CGAL::max)(dista, distb); - timer.stop(); - times.push_back(timer.time()); - std::cout << "* distance / Hausdorff / time (sec.) : " << - distance << " / " << distc << " / " << times.back() << std::endl; - - } else { - - // t is the step where n is the number of steps. - const FT t = FT(1) / static_cast(n); - for (int k = n; k >= 0; --k) { - auto mesh = mesh2; - const FT distance = k * t * dim; - PMP::transform(Affine_transformation_3(CGAL::Translation(), - Vector_3(distance, distance, distance)), mesh); - if (save) save_mesh(mesh, "mesh2-" + std::to_string(k)); - - timer.reset(); - timer.start(); - const double dista = functor(mesh1, mesh); - const double distb = functor(mesh, mesh1); - const double distc = (CGAL::max)(dista, distb); - timer.stop(); - times.push_back(timer.time()); - std::cout << "* distance / Hausdorff / time (sec.) " << k << " : " << - distance << " / " << distc << " / " << times.back() << std::endl; - } - } - - double min_time = +std::numeric_limits::infinity(); - double max_time = -std::numeric_limits::infinity(); - double avg_time = 0.0; - for (const double time : times) { - min_time = (CGAL::min)(min_time, time); - max_time = (CGAL::max)(max_time, time); - avg_time += time; - } - avg_time /= static_cast(times.size()); - - std::cout << std::endl << "* timings (msec.): " << std::endl; - std::cout << "* avg time: " << avg_time * 1000.0 << std::endl; - std::cout << "* min time: " << min_time * 1000.0 << std::endl; - std::cout << "* max time: " << max_time * 1000.0 << std::endl; -} - -Triangle_3 get_triangle(const int index, const Surface_mesh& mesh) { - - const auto mfaces = faces(mesh); - assert(index >= 0); - assert(index < static_cast(mfaces.size())); - const auto face = *(mfaces.begin() + index); - - const auto he = halfedge(face, mesh); - const auto vertices = vertices_around_face(he, mesh); - auto vit = vertices.begin(); - const auto& p0 = mesh.point(*vit); ++vit; - const auto& p1 = mesh.point(*vit); ++vit; - const auto& p2 = mesh.point(*vit); - return Triangle_3(p0, p1, p2); -} - -void compute_realizing_triangles( - const Surface_mesh& mesh1, const Surface_mesh& mesh2, - const double error_bound, const std::string prefix, const bool save = false) { - - std::cout << "* getting realizing triangles: " << std::endl; - const auto data = - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound); - const auto& faces = data.second; - const int f1 = static_cast(faces.first); - const int f2 = static_cast(faces.second); - - std::cout << "* Hausdorff: " << data.first << std::endl; - std::cout << "* f1: " << f1 << std::endl; - std::cout << "* f2: " << f2 << std::endl; - - if (f1 != -1 && save) { - const auto triangle = get_triangle(f1, mesh1); - Surface_mesh sm1; - sm1.add_vertex(triangle[0]); - sm1.add_vertex(triangle[1]); - sm1.add_vertex(triangle[2]); - sm1.add_face(sm1.vertices()); - save_mesh(sm1, prefix + "triangle1"); - } - - if (f2 != -1 && save) { - const auto triangle = get_triangle(f2, mesh2); - Surface_mesh sm2; - sm2.add_vertex(triangle[0]); - sm2.add_vertex(triangle[1]); - sm2.add_vertex(triangle[2]); - sm2.add_face(sm2.vertices()); - save_mesh(sm2, prefix + "triangle2"); - } -} - -void test_realizing_triangles( - const double error_bound, const bool save = false) { - - std::cout.precision(20); - std::cout << std::endl << "* testing realizing triangles:" << std::endl << std::endl; - - // Basic test. - std::cout << "... basic test ..." << std::endl; - Surface_mesh mesh1, mesh2; - - mesh1.add_vertex(Point_3(0, 0, 0)); - mesh1.add_vertex(Point_3(2, 0, 0)); - mesh1.add_vertex(Point_3(1, 1, 0)); - mesh1.add_face(mesh1.vertices()); - - mesh2.add_vertex(Point_3(0, 0, 1)); - mesh2.add_vertex(Point_3(2, 0, 1)); - mesh2.add_vertex(Point_3(1, 1, 1)); - mesh2.add_face(mesh2.vertices()); - - if (save) save_mesh(mesh1, "1mesh1"); - if (save) save_mesh(mesh2, "1mesh2"); - compute_realizing_triangles(mesh1, mesh2, error_bound, "1", save); - - // Complex test. - std::cout << std::endl << "... complex test ..." << std::endl; - const std::string filepath1 = "data/tetrahedron.off"; - const std::string filepath2 = "data/tetrahedron-remeshed.off"; - get_meshes(filepath1, filepath2, mesh1, mesh2); - - PMP::transform(Affine_transformation_3(CGAL::Translation(), - Vector_3(FT(0), FT(0), FT(1))), mesh2); - - if (save) save_mesh(mesh1, "2mesh1"); - if (save) save_mesh(mesh2, "2mesh2"); - compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); -} - int main(int argc, char** argv) { - // std::string name; - // std::cin >> name; - const double error_bound = 1e-4; - const std::size_t num_samples = 1000; std::cout << std::endl << "* error bound: " << error_bound << std::endl; - std::cout << std::endl << "* number of samples: " << num_samples << std::endl; std::string filepath = (argc > 1 ? argv[1] : "data/blobby.off"); - // ------------------------------------------------------------------------ // - // Examples. + remeshing_tetrahedon_example(error_bound); + interior_triangle_example(error_bound); + perturbing_mesh_example(filepath, error_bound); + moving_mesh_example(filepath, filepath, 5, error_bound); - // remeshing_tetrahedon_example(error_bound); - // interior_triangle_example(error_bound); - // perturbing_mesh_example(filepath, error_bound); - // moving_mesh_example(filepath, filepath, 5, error_bound); - - // std::cout << std::endl; - // return EXIT_SUCCESS; - - // ------------------------------------------------------------------------ // - // Tests. - - Approximate_hd_wrapper apprx_hd(num_samples); - Naive_bounded_error_hd_wrapper naive_hd(error_bound); - Bounded_error_hd_wrapper bound_hd(error_bound); - - // --- Testing basic properties. - - // test_synthetic_data(apprx_hd); - // test_synthetic_data(naive_hd); - // test_synthetic_data(bound_hd); - - // --- Compare on common meshes. - - // test_one_versus_another(apprx_hd, naive_hd); - // test_one_versus_another(naive_hd, bound_hd); - // test_one_versus_another(bound_hd, apprx_hd); - - // --- Compare on real meshes. - - const std::string filepath1 = (argc > 1 ? argv[1] : "data/blobby.off"); - const std::string filepath2 = (argc > 2 ? argv[2] : "data/tetrahedron-remeshed.off"); - - // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); - // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); - // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); - - // --- Compare timings. - - filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); - // test_timings(filepath, apprx_hd); - // test_timings(filepath, naive_hd); - // test_timings(filepath, bound_hd); - - // --- Compare with the paper. - - // test_bunny(apprx_hd); - // test_bunny(naive_hd); - test_bunny(bound_hd, 0); - - // --- Testing realizing triangles. - // test_realizing_triangles(error_bound); - - // ------------------------------------------------------------------------ // std::cout << std::endl; return EXIT_SUCCESS; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 500aa383b04..a5f337b7f63 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -169,12 +169,12 @@ namespace CGAL { const Point_3 v2 = query.vertex(2); // Find the axis aligned bbox of the triangle. - const Point_3 tri_min = Point_3 ( + const Point_3 tri_min = Point_3( std::min(std::min(v0.x(), v1.x()), v2.x()), std::min(std::min(v0.y(), v1.y()), v2.y()), std::min(std::min(v0.z(), v1.z()), v2.z())); - const Point_3 tri_max = Point_3 ( + const Point_3 tri_max = Point_3( std::max(std::max(v0.x(), v1.x()), v2.x()), std::max(std::max(v0.y(), v1.y()), v2.y()), std::max(std::max(v0.z(), v1.z()), v2.z())); diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index 08a65b9ffc4..6ca77b516c4 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -54,6 +54,7 @@ else() message(STATUS "Examples that use OpenMesh will not be compiled.") endif() +create_single_source_cgal_program("test_hausdorff_bounded_error_distance.cpp") create_single_source_cgal_program("test_pmp_read_polygon_mesh.cpp") create_single_source_cgal_program("connected_component_polyhedron.cpp") create_single_source_cgal_program("connected_component_surface_mesh.cpp") @@ -108,6 +109,7 @@ create_single_source_cgal_program("test_pmp_polyhedral_envelope.cpp") # create_single_source_cgal_program("test_pmp_repair_self_intersections.cpp") if(TARGET CGAL::TBB_support) + target_link_libraries(test_hausdorff_bounded_error_distance PUBLIC CGAL::TBB_support) target_link_libraries(test_pmp_distance PUBLIC CGAL::TBB_support) target_link_libraries(orient_polygon_soup_test PUBLIC CGAL::TBB_support) target_link_libraries(self_intersection_surface_mesh_test diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron-remeshed.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tetrahedron-remeshed.off similarity index 100% rename from Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron-remeshed.off rename to Polygon_mesh_processing/test/Polygon_mesh_processing/data/tetrahedron-remeshed.off diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/tetrahedron.off similarity index 100% rename from Polygon_mesh_processing/examples/Polygon_mesh_processing/data/tetrahedron.off rename to Polygon_mesh_processing/test/Polygon_mesh_processing/data/tetrahedron.off diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp new file mode 100644 index 00000000000..a613baab0b8 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -0,0 +1,769 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using SCK = CGAL::Simple_cartesian; +using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; +using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; + +using Kernel = EPICK; +using FT = typename Kernel::FT; +using Point_3 = typename Kernel::Point_3; +using Vector_3 = typename Kernel::Vector_3; +using Triangle_3 = typename Kernel::Triangle_3; + +using TAG = CGAL::Parallel_if_available_tag; +using Surface_mesh = CGAL::Surface_mesh; +using Affine_transformation_3 = CGAL::Aff_transformation_3; +using Timer = CGAL::Real_timer; + +namespace PMP = CGAL::Polygon_mesh_processing; + +struct Approximate_hd_wrapper { + const std::size_t m_num_samples; + std::string name() const { return "approximate"; } + Approximate_hd_wrapper(const std::size_t num_samples) : m_num_samples(num_samples) { } + double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { + return PMP::approximate_Hausdorff_distance(tm1, tm2, + PMP::parameters::number_of_points_per_area_unit(m_num_samples), + PMP::parameters::number_of_points_per_area_unit(m_num_samples)); + } +}; + +struct Naive_bounded_error_hd_wrapper { + const double m_error_bound; + std::string name() const { return "naive bounded error"; } + Naive_bounded_error_hd_wrapper(const double error_bound) : m_error_bound(error_bound) { } + double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { + return PMP::bounded_error_Hausdorff_distance_naive(tm1, tm2, m_error_bound); + } +}; + +struct Bounded_error_hd_wrapper { + const double m_error_bound; + std::string name() const { return "bounded error"; } + Bounded_error_hd_wrapper(const double error_bound) : m_error_bound(error_bound) { } + double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { + return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound).first; + } +}; + +void get_mesh(const std::string filepath, Surface_mesh& mesh) { + + mesh.clear(); + std::ifstream input(filepath); + input >> mesh; + std::cout << "* getting mesh with " << mesh.number_of_faces() << " faces" << std::endl; +} + +void get_meshes( + const std::string filepath1, const std::string filepath2, + Surface_mesh& mesh1, Surface_mesh& mesh2) { + + get_mesh(filepath1, mesh1); + get_mesh(filepath2, mesh2); +} + +void save_mesh(const Surface_mesh& mesh, const std::string filepath) { + + if (!CGAL::write_PLY(filepath + ".ply", mesh)) { + std::cerr << "ERROR: cannot save this file: " << filepath << std::endl; + exit(EXIT_FAILURE); + } +} + +template +void test_0(const FunctionWrapper& functor, const bool save = false) { + + // The same triangle. + // Expected distance is 0. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 0 ---- " << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2 = mesh1; + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 0): " << dista << std::endl; + std::cout << "* HInverted distance (expected 0): " << distb << std::endl; +} + +template +void test_1(const FunctionWrapper& functor, const bool save = false) { + + // Two triangles are parallel and 1 unit distance away from each other. + // Expected distance is 1. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 1 ---- " << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2.add_vertex(Point_3(0, 0, 1)); + mesh2.add_vertex(Point_3(2, 0, 1)); + mesh2.add_vertex(Point_3(1, 1, 1)); + mesh2.add_face(mesh2.vertices()); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; + std::cout << "* HInverted distance (expected 1): " << distb << std::endl; +} + +template +void test_2(const FunctionWrapper& functor, const bool save = false) { + + // One triangle is orthogonal to the other one and shares a common edge. + // Expected distance is 1. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 2 ---- " << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2.add_vertex(Point_3(0, 0, 0)); + mesh2.add_vertex(Point_3(2, 0, 0)); + mesh2.add_vertex(Point_3(1, 0, 1)); + mesh2.add_face(mesh2.vertices()); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; + std::cout << "* HInverted distance (expected 1): " << distb << std::endl; +} + +template +void test_3(const FunctionWrapper& functor, const bool save = false) { + + // One triangle is orthogonal to the other one and shares a common edge + // that is moved 1 unit distance away. + // Expected distances are sqrt(2) and 2. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 3 ---- " << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2.add_vertex(Point_3(0, 0, 1)); + mesh2.add_vertex(Point_3(2, 0, 1)); + mesh2.add_vertex(Point_3(1, 0, 2)); + mesh2.add_face(mesh2.vertices()); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected sqrt(2)): " << dista << std::endl; + std::cout << "* HInverted distance (expected 2 ): " << distb << std::endl; +} + +template +void test_4(const FunctionWrapper& functor, const bool save = false) { + + // One triangle is orthogonal to the other one and shares a common vertex. + // Expected distance is 1.2247448713915889407. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 4 ---- " << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2.add_vertex(Point_3(0, 1, 1)); + mesh2.add_vertex(Point_3(2, 1, 1)); + mesh2.add_vertex(Point_3(1, 1, 0)); + mesh2.add_face(mesh2.vertices()); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1.22): " << dista << std::endl; + std::cout << "* HInverted distance (expected 1.22): " << distb << std::endl; +} + +template +void test_5(const FunctionWrapper& functor, const bool save = false) { + + // One triangle is orthogonal to the other one and shares a common vertex + // that is moved 1 unit distance away. + // Expected distances are 1.7320508075688771932 and 2.1213203435596423851. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 5 ---- " << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + mesh2.add_vertex(Point_3(0, 1, 2)); + mesh2.add_vertex(Point_3(2, 1, 2)); + mesh2.add_vertex(Point_3(1, 1, 1)); + mesh2.add_face(mesh2.vertices()); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1.73): " << dista << std::endl; + std::cout << "* HInverted distance (expected 2.12): " << distb << std::endl; +} + +template +void test_6(const FunctionWrapper& functor, const bool save = false) { + + // The first and second mesh have different number of triangles. + // They are parallel and lie at the same plane. The middle triangle is overlapping. + // Expected distances are 0 and 0.70710678118654757274. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 6 ---- " << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + const auto v0 = mesh2.add_vertex(Point_3(0, 0, 0)); + const auto v1 = mesh2.add_vertex(Point_3(2, 0, 0)); + const auto v2 = mesh2.add_vertex(Point_3(1, 1, 0)); + const auto v3 = mesh2.add_vertex(Point_3(2, 1, 0)); + const auto v4 = mesh2.add_vertex(Point_3(0, 1, 0)); + + mesh2.add_face(v0, v1, v2); + mesh2.add_face(v2, v1, v3); + mesh2.add_face(v0, v2, v4); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 0.0): " << dista << std::endl; + std::cout << "* HInverted distance (expected 0.7): " << distb << std::endl; +} + +template +void test_7(const FunctionWrapper& functor, const bool save = false) { + + // One triangle is moved to 0.5 unit distance away from 3 other triangles. + // The first and second meshes are parallel. + // Expected distances are 0.5 and 0.86602540378443859659. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 7 ---- " << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + const auto v0 = mesh2.add_vertex(Point_3(0, 0, 0.5)); + const auto v1 = mesh2.add_vertex(Point_3(2, 0, 0.5)); + const auto v2 = mesh2.add_vertex(Point_3(1, 1, 0.5)); + const auto v3 = mesh2.add_vertex(Point_3(2, 1, 0.5)); + const auto v4 = mesh2.add_vertex(Point_3(0, 1, 0.5)); + + mesh2.add_face(v0, v1, v2); + mesh2.add_face(v2, v1, v3); + mesh2.add_face(v0, v2, v4); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 0.50): " << dista << std::endl; + std::cout << "* HInverted distance (expected 0.86): " << distb << std::endl; +} + +template +void test_8(const FunctionWrapper& functor, const bool save = false) { + + // One mesh has one triangle at zero level, another mesh has two triangles + // where the first one is at level 1 and the second one is at level 2. + // Expected distances are 1 and 2. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 8 ---- " << std::endl; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + if (save) save_mesh(mesh1, "mesh1"); + + const auto v0 = mesh2.add_vertex(Point_3(0, 0, 1)); + const auto v1 = mesh2.add_vertex(Point_3(2, 0, 1)); + const auto v2 = mesh2.add_vertex(Point_3(1, 1, 1)); + const auto v3 = mesh2.add_vertex(Point_3(0, 0, 2)); + const auto v4 = mesh2.add_vertex(Point_3(2, 0, 2)); + const auto v5 = mesh2.add_vertex(Point_3(1, 1, 2)); + + mesh2.add_face(v0, v1, v2); + mesh2.add_face(v3, v4, v5); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; + std::cout << "* HInverted distance (expected 2): " << distb << std::endl; +} + +template +void test_9(const FunctionWrapper& functor, const bool save = false) { + + // Two meshes partially overlap, have 2 triangles in common and each one has + // two its own trianles. All triangles form a Z shape where the height is 1. + // The expected result is 1. + + std::cout.precision(20); + Surface_mesh mesh1, mesh2; + std::cout << " ---- testing 9 ---- " << std::endl; + + auto v0 = mesh1.add_vertex(Point_3(0, 0, 0)); + auto v1 = mesh1.add_vertex(Point_3(1, 0, 0)); + auto v2 = mesh1.add_vertex(Point_3(0, 1, 0)); + auto v3 = mesh1.add_vertex(Point_3(1, 1, 0)); + auto v4 = mesh1.add_vertex(Point_3(1, 0, 1)); + auto v5 = mesh1.add_vertex(Point_3(1, 1, 1)); + mesh1.add_face(v0, v1, v2); + mesh1.add_face(v2, v1, v3); + mesh1.add_face(v1, v4, v3); + mesh1.add_face(v3, v4, v5); + if (save) save_mesh(mesh1, "mesh1"); + + v0 = mesh2.add_vertex(Point_3(2, 0, 1)); + v1 = mesh2.add_vertex(Point_3(1, 0, 0)); + v2 = mesh2.add_vertex(Point_3(2, 1, 1)); + v3 = mesh2.add_vertex(Point_3(1, 1, 0)); + v4 = mesh2.add_vertex(Point_3(1, 0, 1)); + v5 = mesh2.add_vertex(Point_3(1, 1, 1)); + mesh2.add_face(v1, v4, v3); + mesh2.add_face(v3, v4, v5); + mesh2.add_face(v4, v0, v5); + mesh2.add_face(v5, v0, v2); + if (save) save_mesh(mesh2, "mesh2"); + + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; + std::cout << "* HInverted distance (expected 1): " << distb << std::endl; +} + +template +void test_synthetic_data(const FunctionWrapper& functor) { + + std::cout << std::endl << "-- testing synthetic data:" << std::endl; + std::cout << "* name -> " << functor.name() << std::endl; + + test_0(functor); // 1 parallel + test_1(functor); + test_2(functor); // 1 edge touching + test_3(functor); + test_4(functor); // 1 vertex touching + test_5(functor); + test_6(functor); // 1 to multiple + test_7(functor); + test_8(functor); + test_9(functor); // overlapping +} + +template< +typename FunctionWrapper1, +typename FunctionWrapper2> +void test_one_versus_another( + const FunctionWrapper1& functor1, + const FunctionWrapper2& functor2) { + + std::cout.precision(20); + const std::string filepath1 = "data/tetrahedron.off"; + const std::string filepath2 = "data/tetrahedron-remeshed.off"; + + std::cout << std::endl << "-- testing one versus another (tetrahedron):" << std::endl; + std::cout << "* name 1 -> " << functor1.name() << std::endl; + std::cout << "* name 2 -> " << functor2.name() << std::endl; + + Surface_mesh mesh1, mesh2; + get_meshes(filepath1, filepath2, mesh1, mesh2); + + // TEST 0. + // Load and compare. + // The expected distance is 0. + std::cout << " ---- testing 0 ---- " << std::endl; + const double dista0 = functor1(mesh1, mesh2); + const double distb0 = functor2(mesh1, mesh2); + std::cout << "* Hausdorff distance1: " << dista0 << std::endl; + std::cout << "* Hausdorff distance2: " << distb0 << std::endl; + + std::cout << "* traslating by 1 unit ..." << std::endl; + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(FT(0), FT(0), FT(1))), mesh2); + + // TEST 1. + // Translate by 1 unit distance and compare. + // The expected distance is 1. + std::cout << " ---- testing 1 ---- " << std::endl; + const double dista1 = functor1(mesh1, mesh2); + const double distb1 = functor2(mesh1, mesh2); + std::cout << "* Hausdorff distance1: " << dista1 << std::endl; + std::cout << "* Hausdorff distance2: " << distb1 << std::endl; +} + +template< +typename FunctionWrapper1, +typename FunctionWrapper2> +void test_real_meshes( + const std::string filepath1, + const std::string filepath2, + const FunctionWrapper1& functor1, + const FunctionWrapper2& functor2) { + + std::cout.precision(20); + std::cout << std::endl << "-- testing real meshes:" << std::endl; + std::cout << "* input path 1: " << filepath1 << std::endl; + std::cout << "* input path 2: " << filepath2 << std::endl; + + Surface_mesh mesh1, mesh2; + get_meshes(filepath1, filepath2, mesh1, mesh2); + + std::cout << std::endl; + std::cout << "* name 1 -> " << functor1.name() << std::endl; + std::cout << "* name 2 -> " << functor2.name() << std::endl; + + // Load and compare. + std::cout << std::endl; + std::cout << " ---- testing ---- " << std::endl; + const double dista0 = functor1(mesh1, mesh2); + const double dista1 = functor1(mesh2, mesh1); + const double distb0 = functor2(mesh1, mesh2); + const double distb1 = functor2(mesh2, mesh1); + std::cout << std::endl; + std::cout << "* Hausdorff distance1 f: " << dista0 << std::endl; + std::cout << "* Hausdorff distance1 b: " << dista1 << std::endl; + std::cout << std::endl; + std::cout << "* Hausdorff distance2 f: " << distb0 << std::endl; + std::cout << "* Hausdorff distance2 b: " << distb1 << std::endl; +} + +template +void test_timings(const std::string filepath, const FunctionWrapper& functor) { + + std::cout.precision(20); + std::cout << std::endl << "-- testing timing: " << functor.name() << std::endl; + + Timer timer; + Surface_mesh mesh1, mesh2; + get_meshes(filepath, filepath, mesh1, mesh2); + + timer.reset(); + timer.start(); + const double dista = functor(mesh1, mesh2); + timer.stop(); + std::cout << "* time 0 (sec.): " << timer.time() << std::endl; + + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(FT(0), FT(0), FT(1))), mesh2); + + timer.reset(); + timer.start(); + const double distb = functor(mesh1, mesh2); + timer.stop(); + std::cout << "* time 1 (sec.): " << timer.time() << std::endl; + + std::cout << "* dista = " << dista << std::endl; + std::cout << "* distb = " << distb << std::endl; +} + +template +void test_bunny( + const FunctionWrapper& functor, const int n = 5, const bool save = false) { + + std::cout.precision(20); + const std::string filepath1 = "data/bunny1.off"; // approx 16.3K + const std::string filepath2 = "data/bunny2.off"; // approx 69.4K + + std::cout << std::endl << "-- testing bunny:" << std::endl; + std::cout << "* name -> " << functor.name() << std::endl; + + Surface_mesh mesh1, mesh2; + get_meshes(filepath1, filepath2, mesh1, mesh2); + if (save) save_mesh(mesh1, "mesh1"); + if (save) save_mesh(mesh2, "mesh2"); + + // Get 3 times longest dimension. + const auto bbox = PMP::bbox(mesh2); + const FT dist1 = static_cast(CGAL::abs(bbox.xmax() - bbox.xmin())); + const FT dist2 = static_cast(CGAL::abs(bbox.ymax() - bbox.ymin())); + const FT dist3 = static_cast(CGAL::abs(bbox.zmax() - bbox.zmin())); + const FT dim = FT(3) * (CGAL::max)((CGAL::max)(dist1, dist2), dist3); + + // Get timings. + Timer timer; + std::vector times; + times.reserve(n); + + if (n == 0) { + + const FT distance = dim; + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(distance, distance, distance)), mesh2); + if (save) save_mesh(mesh2, "mesh2"); + timer.reset(); + timer.start(); + const double dista = functor(mesh1, mesh2); + const double distb = functor(mesh2, mesh1); + const double distc = (CGAL::max)(dista, distb); + timer.stop(); + times.push_back(timer.time()); + std::cout << "* distance / Hausdorff / time (sec.) : " << + distance << " / " << distc << " / " << times.back() << std::endl; + + } else { + + // t is the step where n is the number of steps. + const FT t = FT(1) / static_cast(n); + for (int k = n; k >= 0; --k) { + auto mesh = mesh2; + const FT distance = k * t * dim; + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(distance, distance, distance)), mesh); + if (save) save_mesh(mesh, "mesh2-" + std::to_string(k)); + + timer.reset(); + timer.start(); + const double dista = functor(mesh1, mesh); + const double distb = functor(mesh, mesh1); + const double distc = (CGAL::max)(dista, distb); + timer.stop(); + times.push_back(timer.time()); + std::cout << "* distance / Hausdorff / time (sec.) " << k << " : " << + distance << " / " << distc << " / " << times.back() << std::endl; + } + } + + double min_time = +std::numeric_limits::infinity(); + double max_time = -std::numeric_limits::infinity(); + double avg_time = 0.0; + for (const double time : times) { + min_time = (CGAL::min)(min_time, time); + max_time = (CGAL::max)(max_time, time); + avg_time += time; + } + avg_time /= static_cast(times.size()); + + std::cout << std::endl << "* timings (msec.): " << std::endl; + std::cout << "* avg time: " << avg_time * 1000.0 << std::endl; + std::cout << "* min time: " << min_time * 1000.0 << std::endl; + std::cout << "* max time: " << max_time * 1000.0 << std::endl; +} + +Triangle_3 get_triangle(const int index, const Surface_mesh& mesh) { + + const auto mfaces = faces(mesh); + assert(index >= 0); + assert(index < static_cast(mfaces.size())); + const auto face = *(mfaces.begin() + index); + + const auto he = halfedge(face, mesh); + const auto vertices = vertices_around_face(he, mesh); + auto vit = vertices.begin(); + const auto& p0 = mesh.point(*vit); ++vit; + const auto& p1 = mesh.point(*vit); ++vit; + const auto& p2 = mesh.point(*vit); + return Triangle_3(p0, p1, p2); +} + +void compute_realizing_triangles( + const Surface_mesh& mesh1, const Surface_mesh& mesh2, + const double error_bound, const std::string prefix, const bool save = false) { + + std::cout << "* getting realizing triangles: " << std::endl; + const auto data = + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound); + const auto& faces = data.second; + const int f1 = static_cast(faces.first); + const int f2 = static_cast(faces.second); + + std::cout << "* Hausdorff: " << data.first << std::endl; + std::cout << "* f1: " << f1 << std::endl; + std::cout << "* f2: " << f2 << std::endl; + + if (f1 != -1 && save) { + const auto triangle = get_triangle(f1, mesh1); + Surface_mesh sm1; + sm1.add_vertex(triangle[0]); + sm1.add_vertex(triangle[1]); + sm1.add_vertex(triangle[2]); + sm1.add_face(sm1.vertices()); + save_mesh(sm1, prefix + "triangle1"); + } + + if (f2 != -1 && save) { + const auto triangle = get_triangle(f2, mesh2); + Surface_mesh sm2; + sm2.add_vertex(triangle[0]); + sm2.add_vertex(triangle[1]); + sm2.add_vertex(triangle[2]); + sm2.add_face(sm2.vertices()); + save_mesh(sm2, prefix + "triangle2"); + } +} + +void test_realizing_triangles( + const double error_bound, const bool save = false) { + + std::cout.precision(20); + std::cout << std::endl << "- test realizing triangles:" << std::endl << std::endl; + + // Basic test. + std::cout << " ---- basic test ---- " << std::endl; + Surface_mesh mesh1, mesh2; + + mesh1.add_vertex(Point_3(0, 0, 0)); + mesh1.add_vertex(Point_3(2, 0, 0)); + mesh1.add_vertex(Point_3(1, 1, 0)); + mesh1.add_face(mesh1.vertices()); + + mesh2.add_vertex(Point_3(0, 0, 1)); + mesh2.add_vertex(Point_3(2, 0, 1)); + mesh2.add_vertex(Point_3(1, 1, 1)); + mesh2.add_face(mesh2.vertices()); + + if (save) save_mesh(mesh1, "1mesh1"); + if (save) save_mesh(mesh2, "1mesh2"); + compute_realizing_triangles(mesh1, mesh2, error_bound, "1", save); + + // Complex test. + std::cout << std::endl << " ---- complex test ---- " << std::endl; + const std::string filepath1 = "data/tetrahedron.off"; + const std::string filepath2 = "data/tetrahedron-remeshed.off"; + get_meshes(filepath1, filepath2, mesh1, mesh2); + + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(FT(0), FT(0), FT(1))), mesh2); + + if (save) save_mesh(mesh1, "2mesh1"); + if (save) save_mesh(mesh2, "2mesh2"); + compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); +} + +int main(int argc, char** argv) { + + // std::string name; + // std::cin >> name; + + const double error_bound = 1e-4; + const std::size_t num_samples = 1000; + std::cout << std::endl << "* error bound: " << error_bound << std::endl; + std::cout << std::endl << "* number of samples: " << num_samples << std::endl; + std::string filepath = (argc > 1 ? argv[1] : "data/blobby.off"); + + // ------------------------------------------------------------------------ // + // Tests. + + Approximate_hd_wrapper apprx_hd(num_samples); + Naive_bounded_error_hd_wrapper naive_hd(error_bound); + Bounded_error_hd_wrapper bound_hd(error_bound); + + + // --- Testing basic properties. + + // test_synthetic_data(apprx_hd); + // test_synthetic_data(naive_hd); + // test_synthetic_data(bound_hd); + + + // --- Compare on common meshes. + + // test_one_versus_another(apprx_hd, naive_hd); + // test_one_versus_another(naive_hd, bound_hd); + // test_one_versus_another(bound_hd, apprx_hd); + + + // --- Compare on real meshes. + + const std::string filepath1 = (argc > 1 ? argv[1] : "data/blobby.off"); + const std::string filepath2 = (argc > 2 ? argv[2] : "data/tetrahedron-remeshed.off"); + + // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); + // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); + // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + + + // --- Compare timings. + + filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); + // test_timings(filepath, apprx_hd); + // test_timings(filepath, naive_hd); + // test_timings(filepath, bound_hd); + + + // --- Compare with the paper. + + // test_bunny(apprx_hd); + // test_bunny(naive_hd); + // test_bunny(bound_hd, 0); + + + // --- Test realizing triangles. + // test_realizing_triangles(error_bound); + + + // ------------------------------------------------------------------------ // + + std::cout << std::endl; + return EXIT_SUCCESS; +} diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp index 83f7dc1bd86..7a908e33b8c 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_distance.cpp @@ -169,10 +169,10 @@ struct Custom_traits_Hausdorff Construct_cartesian_const_iterator_3(){} Construct_cartesian_const_iterator_3(const Point_3&){} const FT* operator()(const Point_3&) const - { return 0; } + { return nullptr; } const FT* operator()(const Point_3&, int) const - { return 0; } + { return nullptr; } typedef const FT* result_type; }; // } end of requirements from SearchGeomTraits_3 @@ -294,7 +294,7 @@ int main(int argc, char** argv) CGAL::Real_timer time; #if defined(CGAL_LINKED_WITH_TBB) time.start(); - std::cout << "Hausdorff distance approximation between meshes (parallel) " + std::cout << "Distance between meshes (parallel) " << PMP::approximate_Hausdorff_distance( m1,m2,PMP::parameters::number_of_points_per_area_unit(4000)) << "\n"; @@ -304,34 +304,13 @@ int main(int argc, char** argv) time.reset(); time.start(); - std::cout << "Hausdorff distance approximation between meshes (sequential) " + std::cout << "Distance between meshes (sequential) " << PMP::approximate_Hausdorff_distance( m1,m2,PMP::parameters::number_of_points_per_area_unit(4000)) << "\n"; time.stop(); std::cout << "done in " << time.time() << "s.\n"; - double error_bound = 0.001; - - time.reset(); - time.start(); - std::cout << "Lower bound on Hausdorff distance between meshes (sequential), " - << "the actual distance is at most " << error_bound << " larger than " - << PMP::bounded_error_Hausdorff_distance_naive( - m1,m2,error_bound) - << "\n"; - time.stop(); - std::cout << "done in " << time.time() << "s.\n"; - - time.reset(); - time.start(); - std::cout << "Bounded Hausdorff distance between meshes (sequential), optimized implementation " - << PMP::bounded_error_Hausdorff_distance( - m1,m2,error_bound) - << "\n"; - time.stop(); - std::cout << "done in " << time.time() << "s.\n"; - general_tests(m1,m2); test_concept(); From 930d364c3f1a078b441c01374ff6966285cc5d6d Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 27 Apr 2021 12:43:47 +0200 Subject: [PATCH 160/349] face to triangle map made global --- .../CGAL/Polygon_mesh_processing/distance.h | 10 ------ ...traversal_traits_with_Hausdorff_distance.h | 36 ++++++++++--------- .../test_hausdorff_bounded_error_distance.cpp | 6 ++-- 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index c6973582fb7..22994132d39 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1414,8 +1414,6 @@ bounded_error_Hausdorff_impl( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, error_bound); // TODO: Initialize the distances on all the vertices first and store those. - // TODO: Do not traverse TM1, but only TM2, i.e. reduce to Culling on TM2. - // Can we do this for all triangles in TM1 in parallel? // Find candidate triangles in TM1 which might realise the Hausdorff bound. timer.reset(); @@ -1523,7 +1521,6 @@ bounded_error_Hausdorff_impl( global_bounds.lpair.second = local_bounds.lface; } - // TODO: Additionally store the face descriptor of the parent from TM1 in the Candidate_triangle. // Add the subtriangle to the candidate list. candidate_triangles.push(Candidate(sub_triangles[i], local_bounds)); } @@ -1669,13 +1666,6 @@ double bounded_error_Hausdorff_naive_impl( // Return linear interpolation between found upper and lower bound return CGAL::sqrt(CGAL::to_double( squared_lower_bound )); - -#if !defined(CGAL_LINKED_WITH_TBB) - CGAL_static_assertion_msg (!(boost::is_convertible::value), - "Parallel_tag is enabled but TBB is unavailable."); -#else - // TODO implement parallelized version of the below here. -#endif } } // end of namespace internal diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index a5f337b7f63..c5944c673e4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -80,6 +80,8 @@ namespace CGAL { using Face_handle = typename boost::graph_traits::face_descriptor; using Local_bounds = Bounds; + using TM2_face_to_triangle_map = Triangle_from_face_descriptor_map; + public: using Priority = FT; Hausdorff_primitive_traits_tm2( @@ -90,6 +92,7 @@ namespace CGAL { const FT h_v1_lower_init, const FT h_v2_lower_init) : m_traits(traits), m_tm2(tm2), m_vpm2(vpm2), + m_face_to_triangle_map(&m_tm2, m_vpm2), h_local_bounds(local_bounds) { // Initialize the global and local bounds with the given values. @@ -106,10 +109,7 @@ namespace CGAL { template void intersection(const Query& query, const Primitive& primitive) { - /* Have reached a single triangle, process it. */ - // TODO: Already perform these computations once we have <= k. - - /* + /* Have reached a single triangle, process it. / Determine the distance according to / min_{b \in primitive} ( max_{vertex in query} ( d(vertex, b) ) ) / @@ -124,17 +124,16 @@ namespace CGAL { const Point_3 v2 = query.vertex(2); // Compute distances of the vertices to the primitive triangle in TM2. - const Triangle_from_face_descriptor_map face_to_triangle_map(&m_tm2, m_vpm2); const FT v0_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( - m_project_point(get(face_to_triangle_map, primitive.id()), v0), v0)))); + m_project_point(get(m_face_to_triangle_map, primitive.id()), v0), v0)))); if (v0_dist < h_v0_lower) h_v0_lower = v0_dist; // it is () part of (11) in the paper const FT v1_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( - m_project_point(get(face_to_triangle_map, primitive.id()), v1), v1)))); + m_project_point(get(m_face_to_triangle_map, primitive.id()), v1), v1)))); if (v1_dist < h_v1_lower) h_v1_lower = v1_dist; // it is () part of (11) in the paper const FT v2_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( - m_project_point(get(face_to_triangle_map, primitive.id()), v2), v2)))); + m_project_point(get(m_face_to_triangle_map, primitive.id()), v2), v2)))); if (v2_dist < h_v2_lower) h_v2_lower = v2_dist; // it is () part of (11) in the paper // Get the distance as maximizers over all vertices. @@ -234,6 +233,7 @@ namespace CGAL { const AABBTraits& m_traits; const TriangleMesh& m_tm2; const VPM2& m_vpm2; + const TM2_face_to_triangle_map m_face_to_triangle_map; // Local Hausdorff bounds for the query triangle. Local_bounds h_local_bounds; @@ -260,6 +260,8 @@ namespace CGAL { using TM2_tree = AABB_tree; using TM2_hd_traits = Hausdorff_primitive_traits_tm2; + using TM1_face_to_triangle_map = Triangle_from_face_descriptor_map; + using Face_handle = typename boost::graph_traits::face_descriptor; using Global_bounds = Bounds; using Candidate = Candidate_triangle; @@ -275,16 +277,19 @@ namespace CGAL { m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2), - m_tm2_tree(tree), m_error_bound(error_bound) { + m_tm2_tree(tree), + m_face_to_triangle_map(&m_tm1, m_vpm1), + m_error_bound(error_bound) { - // Initialize the global bounds with 0.0, they will only grow. + // Initialize the global bounds with 0, they will only grow. // If we leave zero here, then we are very slow even for big input error bounds! + // The error_bound here makes the code faster for close meshes. h_global_bounds.lower = m_error_bound; // = FT(0); h_global_bounds.upper = m_error_bound; // = FT(0); } // Explore the whole tree, i.e. always enter children if the methods - // do_intersect() below determines that it is worthwhile. + // do_intersect() below determine that it is worthwhile. bool go_further() const { return true; } const std::pair default_face_pair() const { @@ -296,10 +301,9 @@ namespace CGAL { void intersection(const Query&, const Primitive& primitive) { // Map to transform faces of TM1 to actual triangles. - const Triangle_from_face_descriptor_map m_face_to_triangle_map(&m_tm1, m_vpm1); const Triangle_3 triangle = get(m_face_to_triangle_map, primitive.id()); - // TODO Can we initialize the bounds here, s.t. we don't start with infty? + // TODO: Can we initialize the bounds here, s.t. we don't start with infinity? // Can we initialize the bounds depending on the closest points in tm2 // seen from the three vertices? In the paper, they start from infinity. @@ -335,8 +339,7 @@ namespace CGAL { // Determine whether child nodes will still contribute to a larger // Hausdorff distance and thus have to be entered. - // TODO: Document Query object, explain why I don't need it here. - // It does not depend on the error bound but it should. + // TODO: It does not depend on the error bound but it should. template std::pair do_intersect_with_priority(const Query&, const Node& node) const { @@ -385,7 +388,7 @@ namespace CGAL { return this->do_intersect_with_priority(query, node).first; } - // Return those triangles from TM1 which are candidates for including a + // Return those triangles from TM1, which are candidates for including a // point realizing the Hausdorff distance. Heap_type& get_candidate_triangles() { return m_candidiate_triangles; @@ -404,6 +407,7 @@ namespace CGAL { const VPM1& m_vpm1; const VPM2& m_vpm2; const TM2_tree& m_tm2_tree; + const TM1_face_to_triangle_map m_face_to_triangle_map; // Global Hausdorff bounds for the query triangle. const FT m_error_bound; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index a613baab0b8..1304f3d2045 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -563,9 +563,9 @@ void test_bunny( if (save) save_mesh(mesh2, "mesh2"); timer.reset(); timer.start(); - const double dista = functor(mesh1, mesh2); + // const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double distc = (CGAL::max)(dista, distb); + const double distc = distb; // (CGAL::max)(dista, distb); timer.stop(); times.push_back(timer.time()); std::cout << "* distance / Hausdorff / time (sec.) : " << @@ -755,7 +755,7 @@ int main(int argc, char** argv) { // test_bunny(apprx_hd); // test_bunny(naive_hd); - // test_bunny(bound_hd, 0); + test_bunny(bound_hd, 0); // --- Test realizing triangles. From 860cad669a65416e6f247699e5b868cc04f00a76 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 27 Apr 2021 16:46:02 +0200 Subject: [PATCH 161/349] added tighter bounds, changed std min/max to CGAL one, added missing realizing triangles --- .../CGAL/Polygon_mesh_processing/distance.h | 16 ++- ...traversal_traits_with_Hausdorff_distance.h | 135 ++++++++++++------ .../test_hausdorff_bounded_error_distance.cpp | 19 ++- 3 files changed, 122 insertions(+), 48 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 22994132d39..f9e3fb913bb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1465,6 +1465,9 @@ bounded_error_Hausdorff_impl( const auto closest_triangle_v0 = tm2_tree.closest_point_and_primitive(v0); const auto closest_triangle_v1 = tm2_tree.closest_point_and_primitive(v1); const auto closest_triangle_v2 = tm2_tree.closest_point_and_primitive(v2); + CGAL_assertion(closest_triangle_v0.second != Face_handle()); + CGAL_assertion(closest_triangle_v1.second != Face_handle()); + CGAL_assertion(closest_triangle_v2.second != Face_handle()); if ( (closest_triangle_v0.second == closest_triangle_v1.second) && (closest_triangle_v1.second == closest_triangle_v2.second)) { @@ -1513,8 +1516,8 @@ bounded_error_Hausdorff_impl( // Update global lower Hausdorff bound according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); - CGAL_precondition(local_bounds.lpair == traversal_traits_tm1.default_face_pair()); - CGAL_precondition(local_bounds.upair == traversal_traits_tm1.default_face_pair()); + CGAL_precondition(local_bounds.lpair == local_bounds.default_face_pair()); + CGAL_precondition(local_bounds.upair == local_bounds.default_face_pair()); if (local_bounds.lower > global_bounds.lower) { global_bounds.lower = local_bounds.lower; @@ -1522,7 +1525,8 @@ bounded_error_Hausdorff_impl( } // Add the subtriangle to the candidate list. - candidate_triangles.push(Candidate(sub_triangles[i], local_bounds)); + candidate_triangles.push( + Candidate(sub_triangles[i], local_bounds, triangle_and_bound.face)); } // Update global upper Hausdorff bound after subdivision. @@ -1549,6 +1553,12 @@ bounded_error_Hausdorff_impl( // Return linear interpolation between the found lower and upper bounds. const double hdist = CGAL::to_double((global_bounds.lower + global_bounds.upper) / FT(2)); + + CGAL_precondition(global_bounds.lpair.first != Face_handle()); + CGAL_precondition(global_bounds.lpair.second != Face_handle()); + CGAL_precondition(global_bounds.upair.first != Face_handle()); + CGAL_precondition(global_bounds.upair.second != Face_handle()); + const auto realizing_triangles = global_bounds.upair; return std::make_pair(hdist, realizing_triangles); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index c5944c673e4..a4d02b42920 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -41,10 +41,12 @@ namespace CGAL { FT upper = infinity_value(); Face_handle lface = Face_handle(); Face_handle uface = Face_handle(); - std::pair lpair = - std::make_pair(Face_handle(), Face_handle()); - std::pair upair = - std::make_pair(Face_handle(), Face_handle()); + std::pair lpair = default_face_pair(); + std::pair upair = default_face_pair(); + + const std::pair default_face_pair() const { + return std::make_pair(Face_handle(), Face_handle()); + } }; // Candidate triangle. @@ -54,12 +56,13 @@ namespace CGAL { using Candidate_bounds = Bounds; Candidate_triangle( - const Triangle_3& triangle, const Candidate_bounds& bounds) : - triangle(triangle), bounds(bounds) + const Triangle_3& triangle, const Candidate_bounds& bounds, const Face_handle& fh) : + triangle(triangle), bounds(bounds), face(fh) { } Triangle_3 triangle; Candidate_bounds bounds; + Face_handle face; bool operator>(const Candidate_triangle& other) const { return bounds.upper < other.bounds.upper; } bool operator<(const Candidate_triangle& other) const { return bounds.upper > other.bounds.upper; } }; @@ -72,9 +75,10 @@ namespace CGAL { typename TriangleMesh, typename VPM2> class Hausdorff_primitive_traits_tm2 { - using FT = typename Kernel::FT; - using Point_3 = typename Kernel::Point_3; - using Vector_3 = typename Kernel::Vector_3; + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Vector_3 = typename Kernel::Vector_3; + using Triangle_3 = typename Kernel::Triangle_3; using Project_point_3 = typename Kernel::Construct_projected_point_3; using Face_handle = typename boost::graph_traits::face_descriptor; @@ -123,22 +127,25 @@ namespace CGAL { const Point_3 v1 = query.vertex(1); const Point_3 v2 = query.vertex(2); + CGAL_assertion(primitive.id() != Face_handle()); + const Triangle_3 triangle = get(m_face_to_triangle_map, primitive.id()); + // Compute distances of the vertices to the primitive triangle in TM2. - const FT v0_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( - m_project_point(get(m_face_to_triangle_map, primitive.id()), v0), v0)))); + const FT v0_dist = static_cast(CGAL::sqrt(CGAL::to_double( + CGAL::squared_distance(m_project_point(triangle, v0), v0)))); if (v0_dist < h_v0_lower) h_v0_lower = v0_dist; // it is () part of (11) in the paper - const FT v1_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( - m_project_point(get(m_face_to_triangle_map, primitive.id()), v1), v1)))); + const FT v1_dist = static_cast(CGAL::sqrt(CGAL::to_double( + CGAL::squared_distance(m_project_point(triangle, v1), v1)))); if (v1_dist < h_v1_lower) h_v1_lower = v1_dist; // it is () part of (11) in the paper - const FT v2_dist = static_cast(CGAL::sqrt(CGAL::to_double(squared_distance( - m_project_point(get(m_face_to_triangle_map, primitive.id()), v2), v2)))); + const FT v2_dist = static_cast(CGAL::sqrt(CGAL::to_double( + CGAL::squared_distance(m_project_point(triangle, v2), v2)))); if (v2_dist < h_v2_lower) h_v2_lower = v2_dist; // it is () part of (11) in the paper // Get the distance as maximizers over all vertices. - const FT distance_lower = std::max(std::max(h_v0_lower, h_v1_lower), h_v2_lower); // it is (11) in the paper - const FT distance_upper = std::max(std::max(v0_dist, v1_dist), v2_dist); // it is () part of (10) in the paper + const FT distance_lower = (CGAL::max)((CGAL::max)(h_v0_lower, h_v1_lower), h_v2_lower); // it is (11) in the paper + const FT distance_upper = (CGAL::max)((CGAL::max)(v0_dist, v1_dist), v2_dist); // it is () part of (10) in the paper // Since we are at the level of a single triangle in TM2, distance_upper is // actually the correct Hausdorff distance from the query triangle in @@ -169,14 +176,14 @@ namespace CGAL { // Find the axis aligned bbox of the triangle. const Point_3 tri_min = Point_3( - std::min(std::min(v0.x(), v1.x()), v2.x()), - std::min(std::min(v0.y(), v1.y()), v2.y()), - std::min(std::min(v0.z(), v1.z()), v2.z())); + (CGAL::min)((CGAL::min)(v0.x(), v1.x()), v2.x()), + (CGAL::min)((CGAL::min)(v0.y(), v1.y()), v2.y()), + (CGAL::min)((CGAL::min)(v0.z(), v1.z()), v2.z())); const Point_3 tri_max = Point_3( - std::max(std::max(v0.x(), v1.x()), v2.x()), - std::max(std::max(v0.y(), v1.y()), v2.y()), - std::max(std::max(v0.z(), v1.z()), v2.z())); + (CGAL::max)((CGAL::max)(v0.x(), v1.x()), v2.x()), + (CGAL::max)((CGAL::max)(v0.y(), v1.y()), v2.y()), + (CGAL::max)((CGAL::max)(v0.z(), v1.z()), v2.z())); // Compute distance of the bounding boxes. // Distance along the x-axis. @@ -205,8 +212,8 @@ namespace CGAL { // Lower bound on the distance between the two bounding boxes is given // as the length of the diagonal of the bounding box between them. - const FT dist = static_cast(CGAL::sqrt( - CGAL::to_double(Vector_3(dist_x, dist_y, dist_z).squared_length()))); + const FT dist = static_cast(CGAL::sqrt(CGAL::to_double( + Vector_3(dist_x, dist_y, dist_z).squared_length()))); // See Algorithm 2. // Check whether investigating the bbox can still lower the Hausdorff @@ -292,25 +299,44 @@ namespace CGAL { // do_intersect() below determine that it is worthwhile. bool go_further() const { return true; } - const std::pair default_face_pair() const { - return std::make_pair(Face_handle(), Face_handle()); - } - // Compute the explicit Hausdorff distance to the given primitive. template void intersection(const Query&, const Primitive& primitive) { // Map to transform faces of TM1 to actual triangles. + CGAL_assertion(primitive.id() != Face_handle()); const Triangle_3 triangle = get(m_face_to_triangle_map, primitive.id()); - // TODO: Can we initialize the bounds here, s.t. we don't start with infinity? - // Can we initialize the bounds depending on the closest points in tm2 - // seen from the three vertices? In the paper, they start from infinity. + const Point_3 v0 = triangle.vertex(0); + const Point_3 v1 = triangle.vertex(1); + const Point_3 v2 = triangle.vertex(2); + + const auto pair0 = m_tm2_tree.closest_point_and_primitive(v0); + const auto pair1 = m_tm2_tree.closest_point_and_primitive(v1); + const auto pair2 = m_tm2_tree.closest_point_and_primitive(v2); + + const auto sq_dist0 = std::make_pair( + CGAL::squared_distance(v0, pair0.first), pair0.second); + const auto sq_dist1 = std::make_pair( + CGAL::squared_distance(v1, pair1.first), pair1.second); + const auto sq_dist2 = std::make_pair( + CGAL::squared_distance(v2, pair2.first), pair2.second); + + const auto mdist1 = (sq_dist0.first > sq_dist1.first) ? sq_dist0 : sq_dist1; + const auto mdist2 = (mdist1.first > sq_dist2.first) ? mdist1 : sq_dist2; + const FT max_dist = static_cast(CGAL::sqrt(CGAL::to_double(mdist2.first))); + + Bounds initial_bounds; + initial_bounds.lower = max_dist + m_error_bound; + initial_bounds.upper = max_dist + m_error_bound; + initial_bounds.lface = mdist2.second; + initial_bounds.uface = mdist2.second; // Call Culling on B with the single triangle found. TM2_hd_traits traversal_traits_tm2( m_tm2_tree.traits(), m_tm2, m_vpm2, - Bounds(), + initial_bounds, // tighter bounds, in the paper, they start from infinity, see below + // Bounds(), // starting from infinity infinity_value(), infinity_value(), infinity_value()); @@ -318,8 +344,8 @@ namespace CGAL { // Update global Hausdorff bounds according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); - CGAL_assertion(local_bounds.lpair == default_face_pair()); - CGAL_assertion(local_bounds.upair == default_face_pair()); + CGAL_assertion(local_bounds.lpair == initial_bounds.default_face_pair()); + CGAL_assertion(local_bounds.upair == initial_bounds.default_face_pair()); if (local_bounds.lower > h_global_bounds.lower) { // it is (6) in the paper, see also Algorithm 1 h_global_bounds.lower = local_bounds.lower; @@ -334,12 +360,11 @@ namespace CGAL { // Store the triangle given as primitive here as candidate triangle // together with the local bounds it obtained to send it to subdivision later. - m_candidiate_triangles.push(Candidate(triangle, local_bounds)); + m_candidiate_triangles.push(Candidate(triangle, local_bounds, primitive.id())); } // Determine whether child nodes will still contribute to a larger // Hausdorff distance and thus have to be entered. - // TODO: It does not depend on the error bound but it should. template std::pair do_intersect_with_priority(const Query&, const Node& node) const { @@ -371,8 +396,7 @@ namespace CGAL { difference = difference + Vector_3(diff_x, diff_y, diff_z); // it is (9) in the paper // Compute distance from the farthest corner of the bbox to the closest point in TM2. - const FT dist = static_cast(CGAL::sqrt( - CGAL::to_double(difference.squared_length()))); + const FT dist = static_cast(CGAL::sqrt(CGAL::to_double(difference.squared_length()))); // See Algorithm 1 here. // If the distance is larger than the global lower bound, enter the node, i.e. return true. @@ -395,7 +419,8 @@ namespace CGAL { } // Return the global Hausdorff bounds computed for the passed query triangle. - Global_bounds get_global_bounds() const { + Global_bounds get_global_bounds() { + update_global_bounds(); return h_global_bounds; } @@ -415,6 +440,36 @@ namespace CGAL { // All candidate triangles. Heap_type m_candidiate_triangles; + + // In case, we did not enter any loop, we set the realizing triangles here. + void update_global_bounds() { + + if (m_candidiate_triangles.size() > 0) { + const auto top = m_candidiate_triangles.top(); + + if (h_global_bounds.lpair.first == Face_handle()) + h_global_bounds.lpair.first = top.face; + if (h_global_bounds.lpair.second == Face_handle()) + h_global_bounds.lpair.second = top.bounds.lface; + + if (h_global_bounds.upair.first == Face_handle()) + h_global_bounds.upair.first = top.face; + if (h_global_bounds.upair.second == Face_handle()) + h_global_bounds.upair.second = top.bounds.uface; + + } else { + + if (h_global_bounds.lpair.first == Face_handle()) + h_global_bounds.lpair.first = *(faces(m_tm1).begin()); + if (h_global_bounds.lpair.second == Face_handle()) + h_global_bounds.lpair.first = *(faces(m_tm2).begin()); + + if (h_global_bounds.upair.first == Face_handle()) + h_global_bounds.upair.first = *(faces(m_tm1).begin()); + if (h_global_bounds.upair.second == Face_handle()) + h_global_bounds.upair.first = *(faces(m_tm2).begin()); + } + } }; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 1304f3d2045..d44f277fb04 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -638,8 +638,7 @@ void compute_realizing_triangles( const int f2 = static_cast(faces.second); std::cout << "* Hausdorff: " << data.first << std::endl; - std::cout << "* f1: " << f1 << std::endl; - std::cout << "* f2: " << f2 << std::endl; + std::cout << "* f1 / f2: " << f1 << " / " << f2 << std::endl; if (f1 != -1 && save) { const auto triangle = get_triangle(f1, mesh1); @@ -677,12 +676,22 @@ void test_realizing_triangles( mesh1.add_vertex(Point_3(1, 1, 0)); mesh1.add_face(mesh1.vertices()); + mesh2.add_vertex(Point_3(0, 0, error_bound / 2.0)); + mesh2.add_vertex(Point_3(2, 0, error_bound / 2.0)); + mesh2.add_vertex(Point_3(1, 1, error_bound / 2.0)); + mesh2.add_face(mesh2.vertices()); + + if (save) save_mesh(mesh1, "1mesh1"); + if (save) save_mesh(mesh2, "1mesh2"); + + compute_realizing_triangles(mesh1, mesh2, error_bound, "1", save); + + mesh2.clear(); mesh2.add_vertex(Point_3(0, 0, 1)); mesh2.add_vertex(Point_3(2, 0, 1)); mesh2.add_vertex(Point_3(1, 1, 1)); mesh2.add_face(mesh2.vertices()); - if (save) save_mesh(mesh1, "1mesh1"); if (save) save_mesh(mesh2, "1mesh2"); compute_realizing_triangles(mesh1, mesh2, error_bound, "1", save); @@ -755,11 +764,11 @@ int main(int argc, char** argv) { // test_bunny(apprx_hd); // test_bunny(naive_hd); - test_bunny(bound_hd, 0); + // test_bunny(bound_hd, 3); // --- Test realizing triangles. - // test_realizing_triangles(error_bound); + test_realizing_triangles(error_bound); // ------------------------------------------------------------------------ // From 85f88c218a63ca886ae56c51da705ef485e2ed6f Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 27 Apr 2021 18:25:58 +0200 Subject: [PATCH 162/349] added inexact check with distances + more precise realizing triangles --- .../CGAL/Polygon_mesh_processing/distance.h | 48 +++++++---- ...traversal_traits_with_Hausdorff_distance.h | 79 ++++++++++++------- .../test_hausdorff_bounded_error_distance.cpp | 10 +-- 3 files changed, 88 insertions(+), 49 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index f9e3fb913bb..710a74b9e9d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1361,6 +1361,7 @@ bounded_error_Hausdorff_impl( using Face_handle = typename boost::graph_traits::face_descriptor; using Candidate = Candidate_triangle; + using Timer = CGAL::Real_timer; std::cout.precision(20); std::vector tm1_only, tm2_only; @@ -1369,15 +1370,14 @@ bounded_error_Hausdorff_impl( const auto faces1 = faces(tm1); const auto faces2 = faces(tm2); - CGAL_assertion(faces1.size() > 0); - CGAL_assertion(faces2.size() > 0); + CGAL_precondition(faces1.size() > 0); + CGAL_precondition(faces2.size() > 0); - CGAL::Real_timer timer; + Timer timer; timer.start(); TM1_tree tm1_tree; - TM2_tree tm2_tree; - if (compare_meshes) { + if (compare_meshes) { // exact check match_faces(tm1, tm2, std::back_inserter(common), std::back_inserter(tm1_only), std::back_inserter(tm2_only), np1, np2); @@ -1388,8 +1388,11 @@ bounded_error_Hausdorff_impl( if (tm1_only.size() == 0) { timer.stop(); // std::cout << "* culling rate: 100%" << std::endl; - // std::cout << "* AABB tree build time (sec.): " << timer.time() << std::endl; - return std::make_pair(0.0, std::make_pair(Face_handle(), Face_handle())); + // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; + const auto lface = *(faces1.begin()); + const auto uface = *(faces2.begin()); + CGAL_assertion(lface == uface); + return std::make_pair(0.0, std::make_pair(lface, uface)); } CGAL_assertion(tm1_only.size() > 0); @@ -1397,23 +1400,40 @@ bounded_error_Hausdorff_impl( } else { tm1_tree.insert(faces1.begin(), faces1.end(), tm1, vpm1); } - tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); - - // We skip computing internal Kd tree because we do not compute distance queries. - tm1_tree.do_not_accelerate_distance_queries(); // Here, we explicitly accelerate because we use tm2 for distance queries. + TM2_tree tm2_tree(faces2.begin(), faces2.end(), tm2, vpm2); const bool is_tm2_memory_ok = tm2_tree.accelerate_distance_queries(); CGAL_assertion(is_tm2_memory_ok); - timer.stop(); - // std::cout << "* AABB tree build time (sec.): " << timer.time() << std::endl; - // Build traversal traits for tm1_tree. TM1_hd_traits traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, error_bound); + // We skip computing internal Kd tree because we do not compute distance queries. + tm1_tree.do_not_accelerate_distance_queries(); + // TODO: Initialize the distances on all the vertices first and store those. + if (false) { // inexact check + FT max_dist = -FT(1); + std::pair fpair; + for (const auto& face1 : faces1) { + const FT dist = traversal_traits_tm1.get_maximum_distance(face1, fpair); + CGAL_assertion(fpair.first == face1); + max_dist = (CGAL::max)(max_dist, dist); + } + + if (max_dist <= error_bound) { + timer.stop(); + // std::cout << "* culling rate: 100%" << std::endl; + // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; + traversal_traits_tm1.get_maximum_distance(*(faces1.begin()), fpair); + return std::make_pair(error_bound, fpair); + } + } + + timer.stop(); + // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; // Find candidate triangles in TM1 which might realise the Hausdorff bound. timer.reset(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index a4d02b42920..76c262ccfe4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -303,34 +303,17 @@ namespace CGAL { template void intersection(const Query&, const Primitive& primitive) { - // Map to transform faces of TM1 to actual triangles. + // Set initial tight bounds. CGAL_assertion(primitive.id() != Face_handle()); - const Triangle_3 triangle = get(m_face_to_triangle_map, primitive.id()); - - const Point_3 v0 = triangle.vertex(0); - const Point_3 v1 = triangle.vertex(1); - const Point_3 v2 = triangle.vertex(2); - - const auto pair0 = m_tm2_tree.closest_point_and_primitive(v0); - const auto pair1 = m_tm2_tree.closest_point_and_primitive(v1); - const auto pair2 = m_tm2_tree.closest_point_and_primitive(v2); - - const auto sq_dist0 = std::make_pair( - CGAL::squared_distance(v0, pair0.first), pair0.second); - const auto sq_dist1 = std::make_pair( - CGAL::squared_distance(v1, pair1.first), pair1.second); - const auto sq_dist2 = std::make_pair( - CGAL::squared_distance(v2, pair2.first), pair2.second); - - const auto mdist1 = (sq_dist0.first > sq_dist1.first) ? sq_dist0 : sq_dist1; - const auto mdist2 = (mdist1.first > sq_dist2.first) ? mdist1 : sq_dist2; - const FT max_dist = static_cast(CGAL::sqrt(CGAL::to_double(mdist2.first))); + std::pair fpair; + const FT max_dist = get_maximum_distance(primitive.id(), fpair); + CGAL_assertion(fpair.first == primitive.id()); Bounds initial_bounds; initial_bounds.lower = max_dist + m_error_bound; initial_bounds.upper = max_dist + m_error_bound; - initial_bounds.lface = mdist2.second; - initial_bounds.uface = mdist2.second; + initial_bounds.lface = fpair.second; + initial_bounds.uface = fpair.second; // Call Culling on B with the single triangle found. TM2_hd_traits traversal_traits_tm2( @@ -340,6 +323,8 @@ namespace CGAL { infinity_value(), infinity_value(), infinity_value()); + + const Triangle_3 triangle = get(m_face_to_triangle_map, fpair.first); m_tm2_tree.traversal_with_priority(triangle, traversal_traits_tm2); // Update global Hausdorff bounds according to the obtained local bounds. @@ -349,18 +334,18 @@ namespace CGAL { if (local_bounds.lower > h_global_bounds.lower) { // it is (6) in the paper, see also Algorithm 1 h_global_bounds.lower = local_bounds.lower; - h_global_bounds.lpair.first = primitive.id(); + h_global_bounds.lpair.first = fpair.first; h_global_bounds.lpair.second = local_bounds.lface; } if (local_bounds.upper > h_global_bounds.upper) { // it is (6) in the paper, see also Algorithm 1 h_global_bounds.upper = local_bounds.upper; - h_global_bounds.upair.first = primitive.id(); + h_global_bounds.upair.first = fpair.first; h_global_bounds.upair.second = local_bounds.uface; } // Store the triangle given as primitive here as candidate triangle // together with the local bounds it obtained to send it to subdivision later. - m_candidiate_triangles.push(Candidate(triangle, local_bounds, primitive.id())); + m_candidiate_triangles.push(Candidate(triangle, local_bounds, fpair.first)); } // Determine whether child nodes will still contribute to a larger @@ -424,6 +409,36 @@ namespace CGAL { return h_global_bounds; } + // Here, we return the maximum distance from one of the face corners + // to the second mesh. We also return a pair of realizing this distance faces. + FT get_maximum_distance( + const Face_handle lface, + std::pair& fpair) const { + + const auto triangle = get(m_face_to_triangle_map, lface); + const Point_3 v0 = triangle.vertex(0); + const Point_3 v1 = triangle.vertex(1); + const Point_3 v2 = triangle.vertex(2); + + const auto pair0 = m_tm2_tree.closest_point_and_primitive(v0); + const auto pair1 = m_tm2_tree.closest_point_and_primitive(v1); + const auto pair2 = m_tm2_tree.closest_point_and_primitive(v2); + + const auto sq_dist0 = std::make_pair( + CGAL::squared_distance(v0, pair0.first), pair0.second); + const auto sq_dist1 = std::make_pair( + CGAL::squared_distance(v1, pair1.first), pair1.second); + const auto sq_dist2 = std::make_pair( + CGAL::squared_distance(v2, pair2.first), pair2.second); + + const auto mdist1 = (sq_dist0.first > sq_dist1.first) ? sq_dist0 : sq_dist1; + const auto mdist2 = (mdist1.first > sq_dist2.first) ? mdist1 : sq_dist2; + + const auto uface = mdist2.second; + fpair = std::make_pair(lface, uface); + return static_cast(CGAL::sqrt(CGAL::to_double(mdist2.first))); + } + private: // Input data. const AABBTraits& m_traits; @@ -459,15 +474,19 @@ namespace CGAL { } else { + std::pair fpair; + get_maximum_distance(*(faces(m_tm1).begin()), fpair); + CGAL_assertion(fpair.first == *(faces(m_tm1).begin())); + if (h_global_bounds.lpair.first == Face_handle()) - h_global_bounds.lpair.first = *(faces(m_tm1).begin()); + h_global_bounds.lpair.first = fpair.first; if (h_global_bounds.lpair.second == Face_handle()) - h_global_bounds.lpair.first = *(faces(m_tm2).begin()); + h_global_bounds.lpair.second = fpair.second; if (h_global_bounds.upair.first == Face_handle()) - h_global_bounds.upair.first = *(faces(m_tm1).begin()); + h_global_bounds.upair.first = fpair.first; if (h_global_bounds.upair.second == Face_handle()) - h_global_bounds.upair.first = *(faces(m_tm2).begin()); + h_global_bounds.upair.second = fpair.second; } } }; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index d44f277fb04..f77ce7be97f 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -732,14 +732,14 @@ int main(int argc, char** argv) { // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); - // test_synthetic_data(bound_hd); + test_synthetic_data(bound_hd); // --- Compare on common meshes. // test_one_versus_another(apprx_hd, naive_hd); // test_one_versus_another(naive_hd, bound_hd); - // test_one_versus_another(bound_hd, apprx_hd); + test_one_versus_another(bound_hd, apprx_hd); // --- Compare on real meshes. @@ -749,7 +749,7 @@ int main(int argc, char** argv) { // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); - // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); // --- Compare timings. @@ -757,14 +757,14 @@ int main(int argc, char** argv) { filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); - // test_timings(filepath, bound_hd); + test_timings(filepath, bound_hd); // --- Compare with the paper. // test_bunny(apprx_hd); // test_bunny(naive_hd); - // test_bunny(bound_hd, 3); + test_bunny(bound_hd, 3); // --- Test realizing triangles. From 1a9a821193754e3ae5f19ba77093aa2cab767b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 27 Apr 2021 19:24:07 +0200 Subject: [PATCH 163/349] add a way to get a direct access to primitive in a box when below a given nb of primitives --- AABB_tree/include/CGAL/AABB_tree.h | 16 ++++ .../CGAL/internal/AABB_tree/AABB_node.h | 88 +++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/AABB_tree/include/CGAL/AABB_tree.h b/AABB_tree/include/CGAL/AABB_tree.h index 3364403c245..48be3009460 100644 --- a/AABB_tree/include/CGAL/AABB_tree.h +++ b/AABB_tree/include/CGAL/AABB_tree.h @@ -542,6 +542,22 @@ public: } } + template + void traversal_with_priority_and_group_traversal(const Query& query, Traversal_traits& traits, double group_traversal_bound) const + { + switch(size()) + { + case 0: + break; + case 1: + traits.intersection(query, singleton_data()); + break; + default: // if(size() >= 2) + if ( traits.do_intersect(query, *root_node()) && traits.go_further() ) + root_node()->template traversal_with_priority_and_group_traversal(m_primitives, query, traits, m_primitives.size(), 0, group_traversal_bound); + } + } + private: typedef AABB_node Node; diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h index 3f64d69c22e..bfef12b85ab 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h @@ -73,6 +73,15 @@ public: Traversal_traits& traits, const std::size_t nb_primitives) const; + template + void traversal_with_priority_and_group_traversal(const Primitive_vector& primitives, + const Query& query, + Traversal_traits& traits, + const std::size_t nb_primitives, + std::size_t first_primitive_index, + const std::size_t group_size_bound) const; + + private: typedef AABBTraits AABB_traits; typedef AABB_node Node; @@ -225,6 +234,85 @@ AABB_node::traversal_with_priority(const Query& query, } } + +//TODO: find a better name +template +template +void +AABB_node::traversal_with_priority_and_group_traversal(const Primitive_vector& primitives, + const Query& query, + Traversal_traits& traits, + const std::size_t nb_primitives, + std::size_t first_primitive_index, + const std::size_t group_size_bound) const +{ + if (nb_primitives <= group_size_bound) + { + traits.traverse_group(query, primitives.begin()+first_primitive_index, primitives.begin()+first_primitive_index+nb_primitives); + return; + } + + // Recursive traversal + switch(nb_primitives) + { + case 2: + traits.intersection(query, left_data()); + if( traits.go_further() ) + { + traits.intersection(query, right_data()); + } + break; + case 3: + traits.intersection(query, left_data()); + if( traits.go_further() && traits.do_intersect(query, right_child()) ) + { + right_child().traversal_with_priority_and_group_traversal(primitives, query, traits, 2, first_primitive_index+1, group_size_bound); + } + break; + default: + bool ileft, iright; + typename Traversal_traits::Priority pleft, pright; + std::tie(ileft, pleft) = traits.do_intersect_with_priority(query, left_child()); + std::tie(iright, pright) = traits.do_intersect_with_priority(query, right_child()); + CGAL_precondition( (ileft || iright) ? traits.do_intersect(query, *this) : true ); + + if(ileft) + { + if(iright) + { + // Both children have to be inspected. + if(pleft >= pright) + { + // Inspect the left child first, has higher priority. + left_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives/2, first_primitive_index, group_size_bound); + if( traits.go_further() ) + right_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives-nb_primitives/2, first_primitive_index+nb_primitives/2, group_size_bound); + } + else + { + // Inspect the right child first, has higher priority. + right_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives-nb_primitives/2, first_primitive_index+nb_primitives/2, group_size_bound); + if( traits.go_further() ) + left_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives/2, first_primitive_index, group_size_bound); + } + } + else + { + // Only the left child has to be inspected. + left_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives/2, first_primitive_index, group_size_bound); + } + } + else + { + if(iright) + { + // Only the right child has to be inspected. + right_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives-nb_primitives/2, first_primitive_index+nb_primitives/2, group_size_bound); + } + } + } +} + } // end namespace CGAL #endif // CGAL_AABB_NODE_H From c3e5294df33e7f3368ab4b16a334bc795a497083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 27 Apr 2021 19:24:56 +0200 Subject: [PATCH 164/349] add extra function for group traversal not activate for now --- .../CGAL/Polygon_mesh_processing/distance.h | 2 ++ ...AABB_traversal_traits_with_Hausdorff_distance.h | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 710a74b9e9d..7fc73588dd5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1440,6 +1440,7 @@ bounded_error_Hausdorff_impl( timer.start(); const Point_3 stub(0, 0, 0); // dummy point given as query since it is not needed tm1_tree.traversal_with_priority(stub, traversal_traits_tm1); + //tm1_tree.traversal_with_priority_and_group_traversal(stub, traversal_traits_tm1, 10); //TODO: experiment with group traversal timer.stop(); // std::cout << "* TM1 traversal (sec.): " << timer.time() << std::endl; @@ -1533,6 +1534,7 @@ bounded_error_Hausdorff_impl( infinity_value(), infinity_value()); tm2_tree.traversal_with_priority(sub_triangles[i], traversal_traits_tm2); + //tm2_tree.traversal_with_priority_and_group_traversal(sub_triangles[i], traversal_traits_tm2, 10); //TODO: experiment with group traversal // Update global lower Hausdorff bound according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 76c262ccfe4..55af69a636c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -235,6 +235,13 @@ namespace CGAL { return h_local_bounds; } + template + void traverse_group(const Query& query, PrimitiveConstIterator group_begin, PrimitiveConstIterator group_end) + { + for (PrimitiveConstIterator it=group_begin; it!=group_end; ++it) + this->intersection(query, *it); + } + private: // Input data. const AABBTraits& m_traits; @@ -397,6 +404,13 @@ namespace CGAL { return this->do_intersect_with_priority(query, node).first; } + template + void traverse_group(const Query& query, PrimitiveConstIterator group_begin, PrimitiveConstIterator group_end) + { + for (PrimitiveConstIterator it=group_begin; it!=group_end; ++it) + this->intersection(query, *it); + } + // Return those triangles from TM1, which are candidates for including a // point realizing the Hausdorff distance. Heap_type& get_candidate_triangles() { From 87174f30072b368c3bb2405525e71630b568f299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 28 Apr 2021 08:37:08 +0200 Subject: [PATCH 165/349] remove useless check (go further is updated with primitives not bbox) --- AABB_tree/include/CGAL/AABB_tree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AABB_tree/include/CGAL/AABB_tree.h b/AABB_tree/include/CGAL/AABB_tree.h index 48be3009460..a2bee59757b 100644 --- a/AABB_tree/include/CGAL/AABB_tree.h +++ b/AABB_tree/include/CGAL/AABB_tree.h @@ -553,7 +553,7 @@ public: traits.intersection(query, singleton_data()); break; default: // if(size() >= 2) - if ( traits.do_intersect(query, *root_node()) && traits.go_further() ) + if ( traits.do_intersect(query, *root_node()) ) root_node()->template traversal_with_priority_and_group_traversal(m_primitives, query, traits, m_primitives.size(), 0, group_traversal_bound); } } From 4ce1370043606621d2e9fc65d02166966471eb1e Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 28 Apr 2021 11:37:49 +0200 Subject: [PATCH 166/349] tested group traversal, its sequential version is slower due to more candidate triangles --- AABB_tree/include/CGAL/AABB_tree.h | 5 +-- .../CGAL/internal/AABB_tree/AABB_node.h | 25 ++++++----- .../CGAL/Polygon_mesh_processing/distance.h | 41 +++++++++++++------ ...traversal_traits_with_Hausdorff_distance.h | 30 +++++++++----- .../test_hausdorff_bounded_error_distance.cpp | 10 ++--- 5 files changed, 69 insertions(+), 42 deletions(-) diff --git a/AABB_tree/include/CGAL/AABB_tree.h b/AABB_tree/include/CGAL/AABB_tree.h index a2bee59757b..f3c8fe9ad35 100644 --- a/AABB_tree/include/CGAL/AABB_tree.h +++ b/AABB_tree/include/CGAL/AABB_tree.h @@ -543,7 +543,7 @@ public: } template - void traversal_with_priority_and_group_traversal(const Query& query, Traversal_traits& traits, double group_traversal_bound) const + void traversal_with_priority_and_group_traversal(const Query& query, Traversal_traits& traits, const std::size_t group_traversal_bound) const { switch(size()) { @@ -553,8 +553,7 @@ public: traits.intersection(query, singleton_data()); break; default: // if(size() >= 2) - if ( traits.do_intersect(query, *root_node()) ) - root_node()->template traversal_with_priority_and_group_traversal(m_primitives, query, traits, m_primitives.size(), 0, group_traversal_bound); + root_node()->template traversal_with_priority_and_group_traversal(m_primitives, query, traits, m_primitives.size(), 0, group_traversal_bound); } } diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h index bfef12b85ab..a5c09f42fb4 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h @@ -234,8 +234,7 @@ AABB_node::traversal_with_priority(const Query& query, } } - -//TODO: find a better name +// TODO: find a better name template template void @@ -244,10 +243,14 @@ AABB_node::traversal_with_priority_and_group_traversal(const Primitive_vecto Traversal_traits& traits, const std::size_t nb_primitives, std::size_t first_primitive_index, - const std::size_t group_size_bound) const + const std::size_t group_traversal_bound) const { - if (nb_primitives <= group_size_bound) + // Group traversal + CGAL_assertion(group_traversal_bound >= 2); + if ( nb_primitives <= group_traversal_bound ) { + if ( !traits.do_intersect(query, *this) ) return; + CGAL_assertion(traits.do_intersect(query, *this)); traits.traverse_group(query, primitives.begin()+first_primitive_index, primitives.begin()+first_primitive_index+nb_primitives); return; } @@ -266,7 +269,7 @@ AABB_node::traversal_with_priority_and_group_traversal(const Primitive_vecto traits.intersection(query, left_data()); if( traits.go_further() && traits.do_intersect(query, right_child()) ) { - right_child().traversal_with_priority_and_group_traversal(primitives, query, traits, 2, first_primitive_index+1, group_size_bound); + right_child().traversal_with_priority_and_group_traversal(primitives, query, traits, 2, first_primitive_index+1, group_traversal_bound); } break; default: @@ -284,22 +287,22 @@ AABB_node::traversal_with_priority_and_group_traversal(const Primitive_vecto if(pleft >= pright) { // Inspect the left child first, has higher priority. - left_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives/2, first_primitive_index, group_size_bound); + left_child().traversal_with_priority_and_group_traversal(primitives, query, traits, nb_primitives/2, first_primitive_index, group_traversal_bound); if( traits.go_further() ) - right_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives-nb_primitives/2, first_primitive_index+nb_primitives/2, group_size_bound); + right_child().traversal_with_priority_and_group_traversal(primitives, query, traits, nb_primitives-nb_primitives/2, first_primitive_index+nb_primitives/2, group_traversal_bound); } else { // Inspect the right child first, has higher priority. - right_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives-nb_primitives/2, first_primitive_index+nb_primitives/2, group_size_bound); + right_child().traversal_with_priority_and_group_traversal(primitives, query, traits, nb_primitives-nb_primitives/2, first_primitive_index+nb_primitives/2, group_traversal_bound); if( traits.go_further() ) - left_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives/2, first_primitive_index, group_size_bound); + left_child().traversal_with_priority_and_group_traversal(primitives, query, traits, nb_primitives/2, first_primitive_index, group_traversal_bound); } } else { // Only the left child has to be inspected. - left_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives/2, first_primitive_index, group_size_bound); + left_child().traversal_with_priority_and_group_traversal(primitives, query, traits, nb_primitives/2, first_primitive_index, group_traversal_bound); } } else @@ -307,7 +310,7 @@ AABB_node::traversal_with_priority_and_group_traversal(const Primitive_vecto if(iright) { // Only the right child has to be inspected. - right_child().traversal_with_priority_and_group_traversal(primitives,query, traits, nb_primitives-nb_primitives/2, first_primitive_index+nb_primitives/2, group_size_bound); + right_child().traversal_with_priority_and_group_traversal(primitives, query, traits, nb_primitives-nb_primitives/2, first_primitive_index+nb_primitives/2, group_traversal_bound); } } } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 7fc73588dd5..8588520aefb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1366,6 +1366,7 @@ bounded_error_Hausdorff_impl( std::cout.precision(20); std::vector tm1_only, tm2_only; std::vector< std::pair > common; + const std::size_t group_traversal_bound = 1; // TODO: Should we put it in the NP? const auto faces1 = faces(tm1); const auto faces2 = faces(tm2); @@ -1408,26 +1409,35 @@ bounded_error_Hausdorff_impl( // Build traversal traits for tm1_tree. TM1_hd_traits traversal_traits_tm1( - tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, error_bound); + tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, error_bound, group_traversal_bound); // We skip computing internal Kd tree because we do not compute distance queries. tm1_tree.do_not_accelerate_distance_queries(); - // TODO: Initialize the distances on all the vertices first and store those. if (false) { // inexact check FT max_dist = -FT(1); - std::pair fpair; - for (const auto& face1 : faces1) { - const FT dist = traversal_traits_tm1.get_maximum_distance(face1, fpair); - CGAL_assertion(fpair.first == face1); - max_dist = (CGAL::max)(max_dist, dist); + + // super slow version with all distances + if (false) { + std::pair stub; + for (const auto& face1 : faces1) { + const FT dist = traversal_traits_tm1.get_maximum_distance(face1, stub); + max_dist = (CGAL::max)(max_dist, dist); + } + } + + // fast version with bboxes only + if (true) { + CGAL_assertion_msg(false, "TODO: ADD BBOX COMPARISON!"); } if (max_dist <= error_bound) { timer.stop(); // std::cout << "* culling rate: 100%" << std::endl; // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; + std::pair fpair; traversal_traits_tm1.get_maximum_distance(*(faces1.begin()), fpair); + CGAL_assertion(fpair.first == *(faces1.begin())); return std::make_pair(error_bound, fpair); } } @@ -1439,8 +1449,11 @@ bounded_error_Hausdorff_impl( timer.reset(); timer.start(); const Point_3 stub(0, 0, 0); // dummy point given as query since it is not needed - tm1_tree.traversal_with_priority(stub, traversal_traits_tm1); - //tm1_tree.traversal_with_priority_and_group_traversal(stub, traversal_traits_tm1, 10); //TODO: experiment with group traversal + if (group_traversal_bound > 1) { + tm1_tree.traversal_with_priority_and_group_traversal(stub, traversal_traits_tm1, group_traversal_bound); // with group traversal + } else { + tm1_tree.traversal_with_priority(stub, traversal_traits_tm1); + } timer.stop(); // std::cout << "* TM1 traversal (sec.): " << timer.time() << std::endl; @@ -1449,7 +1462,7 @@ bounded_error_Hausdorff_impl( auto global_bounds = traversal_traits_tm1.get_global_bounds(); // std::cout << "* number of all triangles for TM1: " << tm1_tree.size() << std::endl; - // std::cout << "* number of candidate triangles before: " << candidate_triangles.size() << std::endl; + std::cout << "* number of candidate triangles before: " << candidate_triangles.size() << std::endl; // std::cout << "* culling rate: " << // FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)) << "%" << std::endl; @@ -1533,8 +1546,12 @@ bounded_error_Hausdorff_impl( infinity_value(), infinity_value(), infinity_value()); - tm2_tree.traversal_with_priority(sub_triangles[i], traversal_traits_tm2); - //tm2_tree.traversal_with_priority_and_group_traversal(sub_triangles[i], traversal_traits_tm2, 10); //TODO: experiment with group traversal + + if (group_traversal_bound > 1) { + tm2_tree.traversal_with_priority_and_group_traversal(sub_triangles[i], traversal_traits_tm2, group_traversal_bound); // with group traversal + } else { + tm2_tree.traversal_with_priority(sub_triangles[i], traversal_traits_tm2); // without group traversal + } // Update global lower Hausdorff bound according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 55af69a636c..cc27fc91635 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -235,11 +235,11 @@ namespace CGAL { return h_local_bounds; } - template - void traverse_group(const Query& query, PrimitiveConstIterator group_begin, PrimitiveConstIterator group_end) - { - for (PrimitiveConstIterator it=group_begin; it!=group_end; ++it) + template + void traverse_group(const Query& query, PrimitiveConstIterator group_begin, PrimitiveConstIterator group_end) { + for (PrimitiveConstIterator it = group_begin; it != group_end; ++it) { this->intersection(query, *it); + } } private: @@ -287,13 +287,15 @@ namespace CGAL { const AABBTraits& traits, const TM2_tree& tree, const TriangleMesh& tm1, const TriangleMesh& tm2, const VPM1& vpm1, const VPM2& vpm2, - const FT error_bound) : + const FT error_bound, + const std::size_t group_traversal_bound) : m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2), m_tm2_tree(tree), m_face_to_triangle_map(&m_tm1, m_vpm1), - m_error_bound(error_bound) { + m_error_bound(error_bound), + m_group_traversal_bound(group_traversal_bound) { // Initialize the global bounds with 0, they will only grow. // If we leave zero here, then we are very slow even for big input error bounds! @@ -332,7 +334,12 @@ namespace CGAL { infinity_value()); const Triangle_3 triangle = get(m_face_to_triangle_map, fpair.first); - m_tm2_tree.traversal_with_priority(triangle, traversal_traits_tm2); + + if (m_group_traversal_bound > 1) { + m_tm2_tree.traversal_with_priority_and_group_traversal(triangle, traversal_traits_tm2, m_group_traversal_bound); // with group traversal + } else { + m_tm2_tree.traversal_with_priority(triangle, traversal_traits_tm2); // without group traversal + } // Update global Hausdorff bounds according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); @@ -404,11 +411,11 @@ namespace CGAL { return this->do_intersect_with_priority(query, node).first; } - template - void traverse_group(const Query& query, PrimitiveConstIterator group_begin, PrimitiveConstIterator group_end) - { - for (PrimitiveConstIterator it=group_begin; it!=group_end; ++it) + template + void traverse_group(const Query& query, PrimitiveConstIterator group_begin, PrimitiveConstIterator group_end) { + for (PrimitiveConstIterator it = group_begin; it != group_end; ++it) { this->intersection(query, *it); + } } // Return those triangles from TM1, which are candidates for including a @@ -465,6 +472,7 @@ namespace CGAL { // Global Hausdorff bounds for the query triangle. const FT m_error_bound; + const std::size_t m_group_traversal_bound; Global_bounds h_global_bounds; // All candidate triangles. diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index f77ce7be97f..bc8248736c8 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -732,14 +732,14 @@ int main(int argc, char** argv) { // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); - test_synthetic_data(bound_hd); + // test_synthetic_data(bound_hd); // --- Compare on common meshes. // test_one_versus_another(apprx_hd, naive_hd); // test_one_versus_another(naive_hd, bound_hd); - test_one_versus_another(bound_hd, apprx_hd); + // test_one_versus_another(bound_hd, apprx_hd); // --- Compare on real meshes. @@ -749,7 +749,7 @@ int main(int argc, char** argv) { // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); - test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); // --- Compare timings. @@ -757,7 +757,7 @@ int main(int argc, char** argv) { filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); - test_timings(filepath, bound_hd); + // test_timings(filepath, bound_hd); // --- Compare with the paper. @@ -768,7 +768,7 @@ int main(int argc, char** argv) { // --- Test realizing triangles. - test_realizing_triangles(error_bound); + // test_realizing_triangles(error_bound); // ------------------------------------------------------------------------ // From b45de72547021d5c72cf0d2428fbc23ec684de49 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 28 Apr 2021 15:23:35 +0200 Subject: [PATCH 167/349] tested bbox comparisons but I do not think we can use them so they are off --- .../CGAL/Polygon_mesh_processing/distance.h | 84 ++++++++++++------- .../test_hausdorff_bounded_error_distance.cpp | 24 ++++-- 2 files changed, 72 insertions(+), 36 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 8588520aefb..5a519637361 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -31,6 +31,10 @@ #include #include +#include +#include +#include + #ifdef CGAL_LINKED_WITH_TBB #include #include @@ -1393,6 +1397,7 @@ bounded_error_Hausdorff_impl( const auto lface = *(faces1.begin()); const auto uface = *(faces2.begin()); CGAL_assertion(lface == uface); + std::cout << "* exact check succeeded, early return" << std::endl; return std::make_pair(0.0, std::make_pair(lface, uface)); } CGAL_assertion(tm1_only.size() > 0); @@ -1414,34 +1419,6 @@ bounded_error_Hausdorff_impl( // We skip computing internal Kd tree because we do not compute distance queries. tm1_tree.do_not_accelerate_distance_queries(); - if (false) { // inexact check - FT max_dist = -FT(1); - - // super slow version with all distances - if (false) { - std::pair stub; - for (const auto& face1 : faces1) { - const FT dist = traversal_traits_tm1.get_maximum_distance(face1, stub); - max_dist = (CGAL::max)(max_dist, dist); - } - } - - // fast version with bboxes only - if (true) { - CGAL_assertion_msg(false, "TODO: ADD BBOX COMPARISON!"); - } - - if (max_dist <= error_bound) { - timer.stop(); - // std::cout << "* culling rate: 100%" << std::endl; - // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; - std::pair fpair; - traversal_traits_tm1.get_maximum_distance(*(faces1.begin()), fpair); - CGAL_assertion(fpair.first == *(faces1.begin())); - return std::make_pair(error_bound, fpair); - } - } - timer.stop(); // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; @@ -1462,7 +1439,7 @@ bounded_error_Hausdorff_impl( auto global_bounds = traversal_traits_tm1.get_global_bounds(); // std::cout << "* number of all triangles for TM1: " << tm1_tree.size() << std::endl; - std::cout << "* number of candidate triangles before: " << candidate_triangles.size() << std::endl; + // std::cout << "* number of candidate triangles before: " << candidate_triangles.size() << std::endl; // std::cout << "* culling rate: " << // FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)) << "%" << std::endl; @@ -1717,6 +1694,30 @@ double bounded_error_Hausdorff_naive_impl( return CGAL::sqrt(CGAL::to_double( squared_lower_bound )); } +template +bool create_mesh_from_bbox(const CGAL::Bbox_3& bbox, TriangleMesh& tm) { + + if (bbox.xmax() == bbox.xmin()) return false; + if (bbox.ymax() == bbox.ymin()) return false; + if (bbox.zmax() == bbox.zmin()) return false; + + using Point_3 = typename TriangleMesh::Point; + const Point_3 v0(bbox.xmin(), bbox.ymin(), bbox.zmin()); + const Point_3 v1(bbox.xmax(), bbox.ymin(), bbox.zmin()); + const Point_3 v2(bbox.xmax(), bbox.ymax(), bbox.zmin()); + const Point_3 v3(bbox.xmin(), bbox.ymax(), bbox.zmin()); + + const Point_3 v4(bbox.xmin(), bbox.ymax(), bbox.zmax()); + const Point_3 v5(bbox.xmin(), bbox.ymin(), bbox.zmax()); + const Point_3 v6(bbox.xmax(), bbox.ymin(), bbox.zmax()); + const Point_3 v7(bbox.xmax(), bbox.ymax(), bbox.zmax()); + + CGAL::make_hexahedron(v0, v1, v2, v3, v4, v5, v6, v7, tm); + CGAL::Polygon_mesh_processing::triangulate_faces(tm); + CGAL_assertion(is_triangle_mesh(tm)); + return true; +} + } // end of namespace internal /** @@ -1794,6 +1795,31 @@ bounded_error_Hausdorff_distance( CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); + + // TODO: we cannot use it because two meshes can have the same bboxes but different configurations. + // The version with precomputing all distances from tm1 to tm2 is very slow! + if (false) { // inexact check + const auto bbox1 = bbox(tm1); + const auto bbox2 = bbox(tm2); + + using Point_3 = typename Traits::Point_3; + CGAL::Surface_mesh bbox_tm1, bbox_tm2; // TODO: Can we avoid SM here? + const bool success1 = internal::create_mesh_from_bbox(bbox1, bbox_tm1); + const bool success2 = internal::create_mesh_from_bbox(bbox2, bbox_tm2); + + if (success1 && success2) { + const auto bbox_vpm1 = get_const_property_map(vertex_point, bbox_tm1); + const auto bbox_vpm2 = get_const_property_map(vertex_point, bbox_tm2); + + const auto result = internal::bounded_error_Hausdorff_impl( + bbox_tm1, bbox_tm2, error_threshold, match_faces, + bbox_vpm1, bbox_vpm2, CGAL::parameters::all_default(), CGAL::parameters::all_default()); + if (result.first <= error_bound) { + std::cout << "* inexact check succeeded, early return" << std::endl; + return result; + } + } + } return internal::bounded_error_Hausdorff_impl( tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index bc8248736c8..f599fcd9d20 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -406,7 +406,7 @@ void test_9(const FunctionWrapper& functor, const bool save = false) { template void test_synthetic_data(const FunctionWrapper& functor) { - std::cout << std::endl << "-- testing synthetic data:" << std::endl; + std::cout << std::endl << "-- test synthetic data:" << std::endl << std::endl; std::cout << "* name -> " << functor.name() << std::endl; test_0(functor); // 1 parallel @@ -432,7 +432,7 @@ void test_one_versus_another( const std::string filepath1 = "data/tetrahedron.off"; const std::string filepath2 = "data/tetrahedron-remeshed.off"; - std::cout << std::endl << "-- testing one versus another (tetrahedron):" << std::endl; + std::cout << std::endl << "-- test one versus another (tetrahedron):" << std::endl << std::endl; std::cout << "* name 1 -> " << functor1.name() << std::endl; std::cout << "* name 2 -> " << functor2.name() << std::endl; @@ -472,7 +472,7 @@ void test_real_meshes( const FunctionWrapper2& functor2) { std::cout.precision(20); - std::cout << std::endl << "-- testing real meshes:" << std::endl; + std::cout << std::endl << "-- test real meshes:" << std::endl << std::endl; std::cout << "* input path 1: " << filepath1 << std::endl; std::cout << "* input path 2: " << filepath2 << std::endl; @@ -502,7 +502,7 @@ template void test_timings(const std::string filepath, const FunctionWrapper& functor) { std::cout.precision(20); - std::cout << std::endl << "-- testing timing: " << functor.name() << std::endl; + std::cout << std::endl << "-- test timings: " << functor.name() << std::endl << std::endl; Timer timer; Surface_mesh mesh1, mesh2; @@ -535,7 +535,7 @@ void test_bunny( const std::string filepath1 = "data/bunny1.off"; // approx 16.3K const std::string filepath2 = "data/bunny2.off"; // approx 69.4K - std::cout << std::endl << "-- testing bunny:" << std::endl; + std::cout << std::endl << "-- test bunny:" << std::endl << std::endl; std::cout << "* name -> " << functor.name() << std::endl; Surface_mesh mesh1, mesh2; @@ -665,7 +665,7 @@ void test_realizing_triangles( const double error_bound, const bool save = false) { std::cout.precision(20); - std::cout << std::endl << "- test realizing triangles:" << std::endl << std::endl; + std::cout << std::endl << "-- test realizing triangles:" << std::endl << std::endl; // Basic test. std::cout << " ---- basic test ---- " << std::endl; @@ -701,10 +701,19 @@ void test_realizing_triangles( const std::string filepath2 = "data/tetrahedron-remeshed.off"; get_meshes(filepath1, filepath2, mesh1, mesh2); + PMP::transform(Affine_transformation_3( + CGAL::Translation(), Vector_3(0, 0, error_bound / 2.0)), mesh2); + + if (save) save_mesh(mesh1, "2mesh1"); + if (save) save_mesh(mesh2, "2mesh2"); + + compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); + + mesh2.clear(); + get_mesh(filepath2, mesh2); PMP::transform(Affine_transformation_3(CGAL::Translation(), Vector_3(FT(0), FT(0), FT(1))), mesh2); - if (save) save_mesh(mesh1, "2mesh1"); if (save) save_mesh(mesh2, "2mesh2"); compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); } @@ -755,6 +764,7 @@ int main(int argc, char** argv) { // --- Compare timings. filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); + // filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); // test_timings(filepath, bound_hd); From 5c3ae06de7685bcd86ec060ab4d19e7b69289518 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 28 Apr 2021 15:44:34 +0200 Subject: [PATCH 168/349] group traversal should be called only on TM2 --- .../include/CGAL/Polygon_mesh_processing/distance.h | 8 ++++---- .../AABB_traversal_traits_with_Hausdorff_distance.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 5a519637361..569daef776f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1426,11 +1426,11 @@ bounded_error_Hausdorff_impl( timer.reset(); timer.start(); const Point_3 stub(0, 0, 0); // dummy point given as query since it is not needed - if (group_traversal_bound > 1) { - tm1_tree.traversal_with_priority_and_group_traversal(stub, traversal_traits_tm1, group_traversal_bound); // with group traversal - } else { + // if (group_traversal_bound > 1) { + // tm1_tree.traversal_with_priority_and_group_traversal(stub, traversal_traits_tm1, group_traversal_bound); // with group traversal + // } else { tm1_tree.traversal_with_priority(stub, traversal_traits_tm1); - } + // } timer.stop(); // std::cout << "* TM1 traversal (sec.): " << timer.time() << std::endl; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index cc27fc91635..d4c7a7b0b48 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -413,6 +413,7 @@ namespace CGAL { template void traverse_group(const Query& query, PrimitiveConstIterator group_begin, PrimitiveConstIterator group_end) { + CGAL_assertion_msg(false, "ERROR: we should not call the group traversal on TM1!"); for (PrimitiveConstIterator it = group_begin; it != group_end; ++it) { this->intersection(query, *it); } From 4db22ca4ae4a1adb11fb1b364a45b5b62a213c55 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 28 Apr 2021 16:55:15 +0200 Subject: [PATCH 169/349] removed internal test code that did not prove to be useful --- .../CGAL/Polygon_mesh_processing/distance.h | 71 +++---------------- 1 file changed, 9 insertions(+), 62 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 569daef776f..497e454dbc4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -31,10 +31,6 @@ #include #include -#include -#include -#include - #ifdef CGAL_LINKED_WITH_TBB #include #include @@ -1370,7 +1366,7 @@ bounded_error_Hausdorff_impl( std::cout.precision(20); std::vector tm1_only, tm2_only; std::vector< std::pair > common; - const std::size_t group_traversal_bound = 1; // TODO: Should we put it in the NP? + const std::size_t group_traversal_bound = 1; const auto faces1 = faces(tm1); const auto faces2 = faces(tm2); @@ -1577,14 +1573,6 @@ bounded_error_Hausdorff_impl( const auto realizing_triangles = global_bounds.upair; return std::make_pair(hdist, realizing_triangles); - - #if !defined(CGAL_LINKED_WITH_TBB) - CGAL_static_assertion_msg( - !(boost::is_convertible::value), - "Parallel_tag is enabled but TBB is unavailable!"); - #else - // TODO: implement the parallel version of the above here. - #endif } template -bool create_mesh_from_bbox(const CGAL::Bbox_3& bbox, TriangleMesh& tm) { - - if (bbox.xmax() == bbox.xmin()) return false; - if (bbox.ymax() == bbox.ymin()) return false; - if (bbox.zmax() == bbox.zmin()) return false; - - using Point_3 = typename TriangleMesh::Point; - const Point_3 v0(bbox.xmin(), bbox.ymin(), bbox.zmin()); - const Point_3 v1(bbox.xmax(), bbox.ymin(), bbox.zmin()); - const Point_3 v2(bbox.xmax(), bbox.ymax(), bbox.zmin()); - const Point_3 v3(bbox.xmin(), bbox.ymax(), bbox.zmin()); - - const Point_3 v4(bbox.xmin(), bbox.ymax(), bbox.zmax()); - const Point_3 v5(bbox.xmin(), bbox.ymin(), bbox.zmax()); - const Point_3 v6(bbox.xmax(), bbox.ymin(), bbox.zmax()); - const Point_3 v7(bbox.xmax(), bbox.ymax(), bbox.zmax()); - - CGAL::make_hexahedron(v0, v1, v2, v3, v4, v5, v6, v7, tm); - CGAL::Polygon_mesh_processing::triangulate_faces(tm); - CGAL_assertion(is_triangle_mesh(tm)); - return true; -} - } // end of namespace internal /** @@ -1795,33 +1759,16 @@ bounded_error_Hausdorff_distance( CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); - - // TODO: we cannot use it because two meshes can have the same bboxes but different configurations. - // The version with precomputing all distances from tm1 to tm2 is very slow! - if (false) { // inexact check - const auto bbox1 = bbox(tm1); - const auto bbox2 = bbox(tm2); - - using Point_3 = typename Traits::Point_3; - CGAL::Surface_mesh bbox_tm1, bbox_tm2; // TODO: Can we avoid SM here? - const bool success1 = internal::create_mesh_from_bbox(bbox1, bbox_tm1); - const bool success2 = internal::create_mesh_from_bbox(bbox2, bbox_tm2); - - if (success1 && success2) { - const auto bbox_vpm1 = get_const_property_map(vertex_point, bbox_tm1); - const auto bbox_vpm2 = get_const_property_map(vertex_point, bbox_tm2); - - const auto result = internal::bounded_error_Hausdorff_impl( - bbox_tm1, bbox_tm2, error_threshold, match_faces, - bbox_vpm1, bbox_vpm2, CGAL::parameters::all_default(), CGAL::parameters::all_default()); - if (result.first <= error_bound) { - std::cout << "* inexact check succeeded, early return" << std::endl; - return result; - } - } - } return internal::bounded_error_Hausdorff_impl( tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); + + #if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg( + !(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable!"); + #else + // TODO: implement the parallel version of the above here. + #endif } template< From 1f114461c4b77b5bad75417b4fe6d1124084e205 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 28 Apr 2021 17:14:22 +0200 Subject: [PATCH 170/349] removed return with realizing triangles + added naive version of symmetric distance --- .../CGAL/Polygon_mesh_processing/distance.h | 135 +++++++++++++++--- .../test_hausdorff_bounded_error_distance.cpp | 16 ++- 2 files changed, 121 insertions(+), 30 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 497e454dbc4..70f8c03cfae 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1325,11 +1325,7 @@ class TriangleMesh, class VPM1, class VPM2, class NamedParameters1, class NamedParameters2> -std::pair::face_descriptor, - typename boost::graph_traits::face_descriptor> > -bounded_error_Hausdorff_impl( +double bounded_error_Hausdorff_impl( const TriangleMesh& tm1, const TriangleMesh& tm2, const typename Kernel::FT error_bound, @@ -1394,7 +1390,8 @@ bounded_error_Hausdorff_impl( const auto uface = *(faces2.begin()); CGAL_assertion(lface == uface); std::cout << "* exact check succeeded, early return" << std::endl; - return std::make_pair(0.0, std::make_pair(lface, uface)); + // return std::make_pair(0.0, std::make_pair(lface, uface)); // off for the moment + return 0.0; } CGAL_assertion(tm1_only.size() > 0); @@ -1571,8 +1568,34 @@ bounded_error_Hausdorff_impl( CGAL_precondition(global_bounds.upair.first != Face_handle()); CGAL_precondition(global_bounds.upair.second != Face_handle()); - const auto realizing_triangles = global_bounds.upair; - return std::make_pair(hdist, realizing_triangles); + // Off for the moment. + // const auto realizing_triangles = global_bounds.upair; + // return std::make_pair(hdist, realizing_triangles); + + return hdist; +} + +template< +class Concurrency_tag, +class Kernel, +class TriangleMesh, +class VPM1, class VPM2, +class NamedParameters1, +class NamedParameters2> +double bounded_error_symmetric_Hausdorff_impl( + const TriangleMesh& tm1, + const TriangleMesh& tm2, + const typename Kernel::FT error_bound, + const bool compare_meshes, + const VPM1& vpm1, const VPM2& vpm2, + const NamedParameters1& np1, + const NamedParameters2& np2) { + + const double hdist1 = bounded_error_Hausdorff_impl( + tm1, tm2, error_bound, compare_meshes, vpm1, vpm2, np1, np2); + const double hdist2 = bounded_error_Hausdorff_impl( + tm2, tm1, error_bound, compare_meshes, vpm2, vpm1, np2, np1); + return (CGAL::max)(hdist1, hdist2); } template -std::pair::face_descriptor, - typename boost::graph_traits::face_descriptor> > -bounded_error_Hausdorff_distance( +double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, const TriangleMesh& tm2, const double error_bound, @@ -1775,11 +1796,7 @@ template< class Concurrency_tag, class TriangleMesh, class NamedParameters1> -std::pair::face_descriptor, - typename boost::graph_traits::face_descriptor> > -bounded_error_Hausdorff_distance( +double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, const TriangleMesh& tm2, const double error_bound, @@ -1791,11 +1808,7 @@ bounded_error_Hausdorff_distance( template< class Concurrency_tag, class TriangleMesh> -std::pair::face_descriptor, - typename boost::graph_traits::face_descriptor> > -bounded_error_Hausdorff_distance( +double bounded_error_Hausdorff_distance( const TriangleMesh& tm1, const TriangleMesh& tm2, const double error_bound) { @@ -1803,6 +1816,82 @@ bounded_error_Hausdorff_distance( tm1, tm2, error_bound, parameters::all_default()); } +/** + * \ingroup PMP_distance_grp + * returns the maximum of `bounded_error_Hausdorff_distance(tm1, tm2, error_bound, np1, np2)` + * and `bounded_error_Hausdorff_distance(tm2, tm1, error_bound, np2, np1)`. + * + * This function optimizes all internal calls to shared data structures in order to + * speed the computation. + * + * @return the symmetric Hausdorff distance + */ +template< +class Concurrency_tag, +class TriangleMesh, +class NamedParameters1, +class NamedParameters2> +double bounded_error_symmetric_Hausdorff_distance( + const TriangleMesh& tm1, + const TriangleMesh& tm2, + const double error_bound, + const NamedParameters1& np1, + const NamedParameters2& np2) { + + using Traits = typename GetGeomTraits::type; + using FT = typename Traits::FT; + + const auto vpm1 = parameters::choose_parameter( + parameters::get_parameter(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, tm1)); + const auto vpm2 = parameters::choose_parameter( + parameters::get_parameter(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, tm2)); + + const bool match_faces1 = parameters::choose_parameter( + parameters::get_parameter(np1, internal_np::match_faces), true); + const bool match_faces2 = parameters::choose_parameter( + parameters::get_parameter(np2, internal_np::match_faces), true); + const bool match_faces = match_faces1 && match_faces2; + + CGAL_precondition(error_bound >= 0.0); + const FT error_threshold = static_cast(error_bound); + return internal::bounded_error_symmetric_Hausdorff_impl( + tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); + + #if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg( + !(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable!"); + #else + // TODO: implement the parallel version of the above here. + #endif +} + +template< +class Concurrency_tag, +class TriangleMesh, +class NamedParameters1> +double bounded_error_symmetric_Hausdorff_distance( + const TriangleMesh& tm1, + const TriangleMesh& tm2, + const double error_bound, + const NamedParameters1& np1) { + return bounded_error_symmetric_Hausdorff_distance( + tm1, tm2, error_bound, np1, parameters::all_default()); +} + +template< +class Concurrency_tag, +class TriangleMesh> +double bounded_error_symmetric_Hausdorff_distance( + const TriangleMesh& tm1, + const TriangleMesh& tm2, + const double error_bound) { + return bounded_error_symmetric_Hausdorff_distance( + tm1, tm2, error_bound, parameters::all_default()); +} + /* * Implementation of naive Bounded Hausdorff distance computation. */ diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index f599fcd9d20..8e88424a120 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -28,6 +28,7 @@ using Surface_mesh = CGAL::Surface_mesh; using Affine_transformation_3 = CGAL::Aff_transformation_3; using Timer = CGAL::Real_timer; +using Face_handle = typename boost::graph_traits::face_descriptor; namespace PMP = CGAL::Polygon_mesh_processing; struct Approximate_hd_wrapper { @@ -55,7 +56,7 @@ struct Bounded_error_hd_wrapper { std::string name() const { return "bounded error"; } Bounded_error_hd_wrapper(const double error_bound) : m_error_bound(error_bound) { } double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { - return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound).first; + return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound); } }; @@ -631,8 +632,9 @@ void compute_realizing_triangles( const double error_bound, const std::string prefix, const bool save = false) { std::cout << "* getting realizing triangles: " << std::endl; - const auto data = + const double hdist = PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound); + const auto data = std::make_pair(hdist, std::make_pair(Face_handle(), Face_handle())); const auto& faces = data.second; const int f1 = static_cast(faces.first); const int f2 = static_cast(faces.second); @@ -741,14 +743,14 @@ int main(int argc, char** argv) { // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); - // test_synthetic_data(bound_hd); + test_synthetic_data(bound_hd); // --- Compare on common meshes. // test_one_versus_another(apprx_hd, naive_hd); // test_one_versus_another(naive_hd, bound_hd); - // test_one_versus_another(bound_hd, apprx_hd); + test_one_versus_another(bound_hd, apprx_hd); // --- Compare on real meshes. @@ -758,7 +760,7 @@ int main(int argc, char** argv) { // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); - // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); // --- Compare timings. @@ -767,14 +769,14 @@ int main(int argc, char** argv) { // filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); - // test_timings(filepath, bound_hd); + test_timings(filepath, bound_hd); // --- Compare with the paper. // test_bunny(apprx_hd); // test_bunny(naive_hd); - test_bunny(bound_hd, 3); + // test_bunny(bound_hd, 3); // --- Test realizing triangles. From b4787adc1983208d7d1da521fd9d88b991d01d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 29 Apr 2021 10:35:26 +0200 Subject: [PATCH 171/349] allow difference mesh types --- .../compare_meshes_example.cpp | 40 +++++++----- .../CGAL/Polygon_mesh_processing/measure.h | 65 +++++++++++-------- 2 files changed, 60 insertions(+), 45 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp index 40748393a9e..5babc6b1ffb 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compare_meshes_example.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -16,39 +17,42 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_3 Point; typedef CGAL::Surface_mesh Surface_mesh; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; -typedef boost::graph_traits::face_descriptor face_descriptor; +typedef CGAL::Polyhedron_3 Polyhedron; +typedef boost::graph_traits::face_descriptor face_descriptor_1; +typedef boost::graph_traits::face_descriptor face_descriptor_2; namespace PMP = CGAL::Polygon_mesh_processing; int main(int argc, char* argv[]) { const char* filename1 = (argc > 1) ? argv[1] : "data/P.off"; - Surface_mesh mesh1, mesh2; + Surface_mesh mesh1; + Polyhedron mesh2; if(!PMP::read_polygon_mesh(filename1, mesh1)) { std::cerr << "Invalid input." << std::endl; return 1; } - mesh2 = mesh1; + CGAL::copy_face_graph(mesh1, mesh2); CGAL::Euler::add_center_vertex(*halfedges(mesh2).begin(),mesh2); - std::vector > common; - std::vector m1_only, m2_only; + std::vector > common; + std::vector m1_only; + std::vector m2_only; + PMP::match_faces(mesh1, mesh2, std::back_inserter(common), std::back_inserter(m1_only), std::back_inserter(m2_only)); - std::cout<<"Faces only in m1 : "<::%face_descriptor`. + * @tparam PolygonMesh1 a model of `HalfedgeListGraph` and `FaceListGraph` + * @tparam PolygonMesh2 a model of `HalfedgeListGraph` and `FaceListGraph` + * @tparam FaceOutputIterator1 model of `OutputIterator` + holding `boost::graph_traits::%face_descriptor`. + * @tparam FaceOutputIterator2 model of `OutputIterator` + holding `boost::graph_traits::%face_descriptor`. * @tparam FacePairOutputIterator model of `OutputIterator` - holding `std::pair::%face_descriptor, - boost::graph_traits::%face_descriptor`. + holding `std::pair::%face_descriptor, + boost::graph_traits::%face_descriptor`. * * @tparam NamedParameters1 a sequence of \ref bgl_namedparameters "Named Parameters" * @tparam NamedParameters2 a sequence of \ref bgl_namedparameters "Named Parameters" * - * @param m1 the first `PolygonMesh` - * @param m2 the second `PolygonMesh` + * @param m1 the first `PolygonMesh1` + * @param m2 the second `PolygonMesh2` * @param common output iterator collecting the faces that are common to both meshes. * @param m1_only output iterator collecting the faces that are only in `m1` * @param m2_only output iterator collecting the faces that are only in `m2` @@ -858,36 +861,43 @@ centroid(const TriangleMesh& tmesh) * * \cgalNamedParamsBegin * \cgalParamNBegin{vertex_point_map} - * \cgalParamDescription{a property map associating points to the vertices of `m1` (`m2`)} - * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * \cgalParamDescription{a property map associating points to the vertices of `m1`} + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` * as key type and `%Point_3` as value type. `%Point_3` must be LessThanComparable.} - * \cgalParamDefault{`boost::get(CGAL::vertex_point, m1 (m2))`} + * \cgalParamDefault{`boost::get(CGAL::vertex_point, m1)`} + * \cgalParamExtra{The same holds for `m2` and `PolygonMesh2` and the point type must be the same for both meshes.} * \cgalParamNEnd * * \cgalParamNBegin{vertex_index_map} - * \cgalParamDescription{a property map associating to each vertex of `m1` (`m2`) a unique index between `0` and `num_vertices(m1 (m2)) - 1`} + * \cgalParamDescription{a property map associating to each vertex of `m1` a unique index between `0` and `num_vertices(m1) - 1`, and similarly for `m2`.} * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` * as key type and `std::size_t` as value type} * \cgalParamDefault{an automatically indexed internal map} * \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize * a face index property map, either using the internal property map if it exists * or using an external map. The latter might result in - slightly - worsened performance - * in case of non-constant complexity for index access.} + * in case of non-constant complexity for index access. The same holds for `m2` and `PolygonMesh2`.} * \cgalParamNEnd * \cgalNamedParamsEnd * */ -template -void match_faces(const PolygonMesh& m1, const PolygonMesh& m2, - FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only, +template< typename PolygonMesh1, + typename PolygonMesh2, + typename FaceOutputIterator1, + typename FaceOutputIterator2, + typename FacePairOutputIterator, + typename NamedParameters1, + typename NamedParameters2 > +void match_faces(const PolygonMesh1& m1, const PolygonMesh2& m2, + FacePairOutputIterator common, FaceOutputIterator1 m1_only, FaceOutputIterator2 m2_only, const NamedParameters1& np1, const NamedParameters2& np2) { using parameters::choose_parameter; using parameters::get_parameter; - typedef typename GetVertexPointMap < PolygonMesh, NamedParameters1>::const_type VPMap1; - typedef typename GetVertexPointMap < PolygonMesh, NamedParameters2>::const_type VPMap2; - typedef typename GetInitializedVertexIndexMap::const_type VIMap1; - typedef typename GetInitializedVertexIndexMap::const_type VIMap2; + typedef typename GetVertexPointMap < PolygonMesh1, NamedParameters1>::const_type VPMap1; + typedef typename GetVertexPointMap < PolygonMesh2, NamedParameters2>::const_type VPMap2; + typedef typename GetInitializedVertexIndexMap::const_type VIMap1; + typedef typename GetInitializedVertexIndexMap::const_type VIMap2; VPMap1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), get_const_property_map(vertex_point, m1)); VPMap2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), @@ -895,7 +905,8 @@ void match_faces(const PolygonMesh& m1, const PolygonMesh& m2, VIMap1 vim1 = get_initialized_vertex_index_map(m1, np1); VIMap2 vim2 = get_initialized_vertex_index_map(m2, np2); typedef typename boost::property_traits::value_type Point_3; - typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor_1; + typedef typename boost::graph_traits::face_descriptor face_descriptor_2; std::map point_id_map; @@ -925,7 +936,7 @@ void match_faces(const PolygonMesh& m1, const PolygonMesh& m2, } //fill a set with the "faces point-ids" of m1 and then iterate faces of m2 to compare. - std::map, face_descriptor> m1_faces_map; + std::map, face_descriptor_1> m1_faces_map; for(auto f : faces(m1)) { bool all_shared = true; @@ -986,17 +997,17 @@ void match_faces(const PolygonMesh& m1, const PolygonMesh& m2, } } -template -void match_faces(const PolygonMesh& m1, const PolygonMesh& m2, - FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only, +template +void match_faces(const PolygonMesh1& m1, const PolygonMesh2& m2, + FacePairOutputIterator common, FaceOutputIterator1 m1_only, FaceOutputIterator2 m2_only, const NamedParameters& np) { match_faces(m1, m2, common, m1_only, m2_only, np, parameters::all_default()); } -template -void match_faces(const PolygonMesh& m1, const PolygonMesh& m2, - FacePairOutputIterator common, FaceOutputIterator m1_only, FaceOutputIterator m2_only) +template +void match_faces(const PolygonMesh1& m1, const PolygonMesh2& m2, + FacePairOutputIterator common, FaceOutputIterator1 m1_only, FaceOutputIterator2 m2_only) { match_faces(m1, m2, common, m1_only, m2_only, parameters::all_default(), parameters::all_default()); } From d7ee3066ee34d0eba24af2f83f50511907e68a1b Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 29 Apr 2021 13:28:48 +0200 Subject: [PATCH 172/349] Add a pop-up to ask if the user wants to export the internal properties in the off plugin. --- .../demo/Polyhedron/Scene_surface_mesh_item.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp index b275fc3db75..c036f28af2c 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp @@ -1513,11 +1513,20 @@ bool Scene_surface_mesh_item::hasPatchIds() bool Scene_surface_mesh_item::save(std::ostream& out) const { + QMessageBox::StandardButton save_internal_properties = + QMessageBox::question(CGAL::Three::Three::mainWindow(), tr("Internal Properties"), tr("Do you wish to export the internal properties ?")); QApplication::setOverrideCursor(Qt::WaitCursor); out.precision(17); + if(save_internal_properties == QMessageBox::Yes) + { out << *(d->smesh_); - QApplication::restoreOverrideCursor(); - return (bool) out; + } + else + { + CGAL::IO::internal::write_OFF_BGL(out,*d->smesh_, CGAL::parameters::all_default()); + } + QApplication::restoreOverrideCursor(); + return (bool) out; } bool From d6c68a9fe2761dc1d484bf10786554ca43b68470 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 29 Apr 2021 14:57:28 +0200 Subject: [PATCH 173/349] List concerned properties --- .../Polyhedron/Scene_surface_mesh_item.cpp | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp index c036f28af2c..4e3175355af 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp @@ -1513,8 +1513,30 @@ bool Scene_surface_mesh_item::hasPatchIds() bool Scene_surface_mesh_item::save(std::ostream& out) const { + std::vector internal_properties; + std::vector vprop = d->smesh_->properties(); + std::vector fprop = d->smesh_->properties(); + for(auto s : vprop) + if (s.compare("v:normal") == 0 + || s.compare("v:texcoord") == 0 + || s.compare("v:color") == 0) + { + internal_properties.push_back(s); + } + for(auto s : fprop) + if(s.compare("f:color") == 0) + { + internal_properties.push_back(s); + } + QString message = tr("Do you wish to export the following internal properties ? \n"); + for(auto s : internal_properties) + { + message.append(tr(" -")); + message.append(s.c_str()); + message.append(tr("\n")); + } QMessageBox::StandardButton save_internal_properties = - QMessageBox::question(CGAL::Three::Three::mainWindow(), tr("Internal Properties"), tr("Do you wish to export the internal properties ?")); + QMessageBox::question(CGAL::Three::Three::mainWindow(), tr("Internal Properties"), message); QApplication::setOverrideCursor(Qt::WaitCursor); out.precision(17); if(save_internal_properties == QMessageBox::Yes) From d4e7879464b3dd8ddd45a4eeaa89980f19f7cd01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 29 Apr 2021 15:45:06 +0200 Subject: [PATCH 174/349] make the code work with different input mesh types --- ...usdorff_bounded_error_distance_example.cpp | 43 +++- .../CGAL/Polygon_mesh_processing/distance.h | 202 +++++++++--------- ...traversal_traits_with_Hausdorff_distance.h | 90 ++++---- 3 files changed, 190 insertions(+), 145 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 43cc1697cc3..600b432c73c 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -18,17 +19,19 @@ using Vector_3 = typename Kernel::Vector_3; using TAG = CGAL::Parallel_if_available_tag; using Surface_mesh = CGAL::Surface_mesh; +using Polyhedron = CGAL::Polyhedron_3; using Affine_transformation_3 = CGAL::Aff_transformation_3; using Timer = CGAL::Real_timer; namespace PMP = CGAL::Polygon_mesh_processing; -void get_mesh(const std::string filepath, Surface_mesh& mesh) { +template +void get_mesh(const std::string filepath, Mesh& mesh) { mesh.clear(); std::ifstream input(filepath); input >> mesh; - std::cout << "* getting mesh with " << mesh.number_of_faces() << " faces" << std::endl; + std::cout << "* getting mesh with " << num_faces(mesh) << " faces" << std::endl; } void get_meshes( @@ -75,7 +78,7 @@ void remeshing_tetrahedon_example( timer.reset(); timer.start(); std::cout << "* bounded Hausdorff distance: " << - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound).first << std::endl; + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; timer.stop(); std::cout << "* processing time: " << timer.time() << " s." << std::endl; } @@ -110,7 +113,7 @@ void interior_triangle_example( timer.reset(); timer.start(); std::cout << "* bounded Hausdorff distance: " << - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound).first << std::endl; + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; timer.stop(); std::cout << "* processing time: " << timer.time() << " s." << std::endl; } @@ -131,13 +134,12 @@ void perturbing_mesh_example( mesh2.vertices(), mesh2, max_size, CGAL::parameters::do_project(false)); std::cout << "* perturbing the second mesh" << std::endl; - if (save) save_mesh(mesh2, "mesh1"); if (save) save_mesh(mesh2, "mesh2"); timer.reset(); timer.start(); std::cout << "* bounded Hausdorff distance: " << - PMP::bounded_error_Hausdorff_distance(mesh2, mesh2, error_bound).first << std::endl; + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; timer.stop(); std::cout << "* processing time: " << timer.time() << " s." << std::endl; } @@ -172,13 +174,39 @@ void moving_mesh_example( timer.start(); std::cout << "* position: " << i << std::endl; std::cout << "* bounded Hausdorff distance: " << - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound).first << std::endl; + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; timer.stop(); std::cout << "* processing time: " << timer.time() << " s." << std::endl; if (save) save_mesh(mesh2, "mesh-" + std::to_string(i + 1)); } } +void perturbing_mesh_example_with_polyhedron( + const std::string filepath, const double error_bound) { + + Timer timer; + std::cout << std::endl << "* (E3) perturbing mesh example:" << std::endl; + + Surface_mesh mesh1; + Polyhedron mesh2; + get_mesh(filepath, mesh1); + get_mesh(filepath, mesh2); + + const double max_size = 0.1; + PMP::random_perturbation( + vertices(mesh2), mesh2, max_size, CGAL::parameters::do_project(false)); + std::cout << "* perturbing the second mesh" << std::endl; + + timer.reset(); + timer.start(); + std::cout << "* bounded Hausdorff distance 1->2: " << + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; + std::cout << "* bounded Hausdorff distance 2->1: " << + PMP::bounded_error_Hausdorff_distance(mesh2, mesh1, error_bound) << std::endl; + timer.stop(); + std::cout << "* processing time: " << timer.time() << " s." << std::endl; +} + int main(int argc, char** argv) { const double error_bound = 1e-4; @@ -188,6 +216,7 @@ int main(int argc, char** argv) { remeshing_tetrahedon_example(error_bound); interior_triangle_example(error_bound); perturbing_mesh_example(filepath, error_bound); + perturbing_mesh_example_with_polyhedron(filepath, error_bound); moving_mesh_example(filepath, filepath, 5, error_bound); std::cout << std::endl; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 70f8c03cfae..1eb14eb425d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1321,13 +1321,14 @@ namespace internal { template< class Concurrency_tag, class Kernel, -class TriangleMesh, +class TriangleMesh1, +class TriangleMesh2, class VPM1, class VPM2, class NamedParameters1, class NamedParameters2> double bounded_error_Hausdorff_impl( - const TriangleMesh& tm1, - const TriangleMesh& tm2, + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, const typename Kernel::FT error_bound, const bool compare_meshes, const VPM1& vpm1, const VPM2& vpm2, @@ -1343,8 +1344,8 @@ double bounded_error_Hausdorff_impl( using Point_3 = typename Kernel::Point_3; using Triangle_3 = typename Kernel::Triangle_3; - using TM1_primitive = AABB_face_graph_triangle_primitive; - using TM2_primitive = AABB_face_graph_triangle_primitive; + using TM1_primitive = AABB_face_graph_triangle_primitive; + using TM2_primitive = AABB_face_graph_triangle_primitive; using TM1_traits = AABB_traits; using TM2_traits = AABB_traits; @@ -1352,16 +1353,19 @@ double bounded_error_Hausdorff_impl( using TM1_tree = AABB_tree; using TM2_tree = AABB_tree; - using TM1_hd_traits = Hausdorff_primitive_traits_tm1; - using TM2_hd_traits = Hausdorff_primitive_traits_tm2; + using TM1_hd_traits = Hausdorff_primitive_traits_tm1; + using TM2_hd_traits = Hausdorff_primitive_traits_tm2; - using Face_handle = typename boost::graph_traits::face_descriptor; - using Candidate = Candidate_triangle; + using Face_handle_1 = typename boost::graph_traits::face_descriptor; + using Face_handle_2 = typename boost::graph_traits::face_descriptor; + using Candidate = Candidate_triangle; using Timer = CGAL::Real_timer; std::cout.precision(20); - std::vector tm1_only, tm2_only; - std::vector< std::pair > common; + std::vector tm1_only; + std::vector tm2_only; + + std::vector< std::pair > common; const std::size_t group_traversal_bound = 1; const auto faces1 = faces(tm1); @@ -1386,11 +1390,6 @@ double bounded_error_Hausdorff_impl( timer.stop(); // std::cout << "* culling rate: 100%" << std::endl; // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; - const auto lface = *(faces1.begin()); - const auto uface = *(faces2.begin()); - CGAL_assertion(lface == uface); - std::cout << "* exact check succeeded, early return" << std::endl; - // return std::make_pair(0.0, std::make_pair(lface, uface)); // off for the moment return 0.0; } CGAL_assertion(tm1_only.size() > 0); @@ -1469,9 +1468,9 @@ double bounded_error_Hausdorff_impl( const auto closest_triangle_v0 = tm2_tree.closest_point_and_primitive(v0); const auto closest_triangle_v1 = tm2_tree.closest_point_and_primitive(v1); const auto closest_triangle_v2 = tm2_tree.closest_point_and_primitive(v2); - CGAL_assertion(closest_triangle_v0.second != Face_handle()); - CGAL_assertion(closest_triangle_v1.second != Face_handle()); - CGAL_assertion(closest_triangle_v2.second != Face_handle()); + CGAL_assertion(closest_triangle_v0.second != boost::graph_traits::null_face()); + CGAL_assertion(closest_triangle_v1.second != boost::graph_traits::null_face()); + CGAL_assertion(closest_triangle_v2.second != boost::graph_traits::null_face()); if ( (closest_triangle_v0.second == closest_triangle_v1.second) && (closest_triangle_v1.second == closest_triangle_v2.second)) { @@ -1563,10 +1562,10 @@ double bounded_error_Hausdorff_impl( // Return linear interpolation between the found lower and upper bounds. const double hdist = CGAL::to_double((global_bounds.lower + global_bounds.upper) / FT(2)); - CGAL_precondition(global_bounds.lpair.first != Face_handle()); - CGAL_precondition(global_bounds.lpair.second != Face_handle()); - CGAL_precondition(global_bounds.upair.first != Face_handle()); - CGAL_precondition(global_bounds.upair.second != Face_handle()); + CGAL_precondition(global_bounds.lpair.first != boost::graph_traits::null_face()); + CGAL_precondition(global_bounds.lpair.second != boost::graph_traits::null_face()); + CGAL_precondition(global_bounds.upair.first != boost::graph_traits::null_face()); + CGAL_precondition(global_bounds.upair.second != boost::graph_traits::null_face()); // Off for the moment. // const auto realizing_triangles = global_bounds.upair; @@ -1578,13 +1577,14 @@ double bounded_error_Hausdorff_impl( template< class Concurrency_tag, class Kernel, -class TriangleMesh, +class TriangleMesh1, +class TriangleMesh2, class VPM1, class VPM2, class NamedParameters1, class NamedParameters2> double bounded_error_symmetric_Hausdorff_impl( - const TriangleMesh& tm1, - const TriangleMesh& tm2, + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, const typename Kernel::FT error_bound, const bool compare_meshes, const VPM1& vpm1, const VPM2& vpm2, @@ -1645,12 +1645,13 @@ typename Kernel::FT recursive_hausdorff_subdivision( template double bounded_error_Hausdorff_naive_impl( - const TriangleMesh& tm1, - const TriangleMesh& tm2, + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, const typename Kernel::FT& error_bound, VPM1 vpm1, VPM2 vpm2) @@ -1659,10 +1660,10 @@ double bounded_error_Hausdorff_naive_impl( CGAL_assertion_msg (is_triangle, "One of the meshes is not triangulated. Distance computing impossible."); - typedef AABB_face_graph_triangle_primitive TM2_primitive; + typedef AABB_face_graph_triangle_primitive TM2_primitive; typedef AABB_tree< AABB_traits > TM2_tree; - typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor_1; typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; @@ -1679,10 +1680,10 @@ double bounded_error_Hausdorff_naive_impl( tm2_tree.accelerate_distance_queries(); // Build a map to obtain actual triangles from the face descriptors of tm1. - const Triangle_from_face_descriptor_map face_to_triangle_map( &tm1, vpm1 ); + const Triangle_from_face_descriptor_map face_to_triangle_map( &tm1, vpm1 ); // Iterate over the triangles of TM1. - for(const face_descriptor& fd : faces(tm1)) + for(face_descriptor_1 fd : faces(tm1)) { // Get the vertices of the face and pass them on to a recursive method. const Triangle_3 triangle = get(face_to_triangle_map, fd); @@ -1717,7 +1718,8 @@ double bounded_error_Hausdorff_naive_impl( * Possible values are `Sequential_tag` and `Parallel_tag`. * Currently, parallel computation is not implemented, though. * - * @tparam TriangleMesh a model of the concept `FaceListGraph` + * @tparam TriangleMesh1 a model of the concept `FaceListGraph` + * @tparam TriangleMesh2 a model of the concept `FaceListGraph` * * @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * @@ -1733,11 +1735,11 @@ double bounded_error_Hausdorff_naive_impl( * \cgalNamedParamsBegin * \cgalParamNBegin{vertex_point_map} * \cgalParamDescription{a property map associating points to the vertices of `tm1` and `tm2` (`np1` and `np2`, respectively)} - * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` * as key type and `%Point_3` as value type} * \cgalParamDefault{`boost::get(CGAL::vertex_point, tm)`} * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` - * must be available in `TriangleMesh`.} + * must be available in `TriangleMeshX`.} * \cgalParamNEnd * \cgalParamNBegin{match_faces} * \cgalParamDescription{a boolean tag that turns on the preprocessing step that filters out all faces, @@ -1750,19 +1752,20 @@ double bounded_error_Hausdorff_naive_impl( * * @return the one-sided Hausdorff distance */ -template< -class Concurrency_tag, -class TriangleMesh, -class NamedParameters1, -class NamedParameters2> +template< class Concurrency_tag, + class TriangleMesh1, + class TriangleMesh2, + class NamedParameters1, + class NamedParameters2 > double bounded_error_Hausdorff_distance( - const TriangleMesh& tm1, - const TriangleMesh& tm2, + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, const double error_bound, const NamedParameters1& np1, - const NamedParameters2& np2) { + const NamedParameters2& np2) +{ - using Traits = typename GetGeomTraits::type; + using Traits = typename GetGeomTraits::type; using FT = typename Traits::FT; const auto vpm1 = parameters::choose_parameter( @@ -1792,26 +1795,28 @@ double bounded_error_Hausdorff_distance( #endif } -template< -class Concurrency_tag, -class TriangleMesh, -class NamedParameters1> +template< class Concurrency_tag, + class TriangleMesh1, + class TriangleMesh2, + class NamedParameters1 > double bounded_error_Hausdorff_distance( - const TriangleMesh& tm1, - const TriangleMesh& tm2, + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, const double error_bound, - const NamedParameters1& np1) { + const NamedParameters1& np1) +{ return bounded_error_Hausdorff_distance( tm1, tm2, error_bound, np1, parameters::all_default()); } -template< -class Concurrency_tag, -class TriangleMesh> +template< class Concurrency_tag, + class TriangleMesh1, + class TriangleMesh2 > double bounded_error_Hausdorff_distance( - const TriangleMesh& tm1, - const TriangleMesh& tm2, - const double error_bound) { + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + const double error_bound) +{ return bounded_error_Hausdorff_distance( tm1, tm2, error_bound, parameters::all_default()); } @@ -1826,19 +1831,19 @@ double bounded_error_Hausdorff_distance( * * @return the symmetric Hausdorff distance */ -template< -class Concurrency_tag, -class TriangleMesh, -class NamedParameters1, -class NamedParameters2> +template< class Concurrency_tag, + class TriangleMesh1, + class TriangleMesh2, + class NamedParameters1, + class NamedParameters2 > double bounded_error_symmetric_Hausdorff_distance( - const TriangleMesh& tm1, - const TriangleMesh& tm2, + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, const double error_bound, const NamedParameters1& np1, - const NamedParameters2& np2) { - - using Traits = typename GetGeomTraits::type; + const NamedParameters2& np2) +{ + using Traits = typename GetGeomTraits::type; using FT = typename Traits::FT; const auto vpm1 = parameters::choose_parameter( @@ -1868,25 +1873,27 @@ double bounded_error_symmetric_Hausdorff_distance( #endif } -template< -class Concurrency_tag, -class TriangleMesh, -class NamedParameters1> +template< class Concurrency_tag, + class TriangleMesh1, + class TriangleMesh2, + class NamedParameters1 > double bounded_error_symmetric_Hausdorff_distance( - const TriangleMesh& tm1, - const TriangleMesh& tm2, + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, const double error_bound, - const NamedParameters1& np1) { + const NamedParameters1& np1) +{ return bounded_error_symmetric_Hausdorff_distance( tm1, tm2, error_bound, np1, parameters::all_default()); } template< class Concurrency_tag, -class TriangleMesh> +class TriangleMesh1, +class TriangleMesh2> double bounded_error_symmetric_Hausdorff_distance( - const TriangleMesh& tm1, - const TriangleMesh& tm2, + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, const double error_bound) { return bounded_error_symmetric_Hausdorff_distance( tm1, tm2, error_bound, parameters::all_default()); @@ -1896,21 +1903,22 @@ double bounded_error_symmetric_Hausdorff_distance( * Implementation of naive Bounded Hausdorff distance computation. */ template< class Concurrency_tag, - class TriangleMesh, + class TriangleMesh1, + class TriangleMesh2, class NamedParameters1, class NamedParameters2> -double bounded_error_Hausdorff_distance_naive( const TriangleMesh& tm1, - const TriangleMesh& tm2, - double error_bound, - const NamedParameters1& np1, - const NamedParameters2& np2) +double bounded_error_Hausdorff_distance_naive( const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + double error_bound, + const NamedParameters1& np1, + const NamedParameters2& np2) { - typedef typename GetGeomTraits::type Geom_traits; using FT = typename Geom_traits::FT; - typedef typename GetVertexPointMap::const_type Vpm1; - typedef typename GetVertexPointMap::const_type Vpm2; + typedef typename GetVertexPointMap::const_type Vpm1; + typedef typename GetVertexPointMap::const_type Vpm2; using parameters::choose_parameter; using parameters::get_parameter; @@ -1927,21 +1935,23 @@ double bounded_error_Hausdorff_distance_naive( const TriangleMesh& tm1, } template< class Concurrency_tag, - class TriangleMesh, + class TriangleMesh1, + class TriangleMesh2, class NamedParameters1> -double bounded_error_Hausdorff_distance_naive( const TriangleMesh& tm1, - const TriangleMesh& tm2, - double error_bound, - const NamedParameters1& np1) +double bounded_error_Hausdorff_distance_naive( const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + double error_bound, + const NamedParameters1& np1) { return bounded_error_Hausdorff_distance_naive(tm1, tm2, error_bound, np1, parameters::all_default()); } template< class Concurrency_tag, - class TriangleMesh> -double bounded_error_Hausdorff_distance_naive( const TriangleMesh& tm1, - const TriangleMesh& tm2, - double error_bound) + class TriangleMesh1, + class TriangleMesh2> +double bounded_error_Hausdorff_distance_naive( const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + double error_bound) { return bounded_error_Hausdorff_distance_naive(tm1, tm2, error_bound, parameters::all_default() ); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index d4c7a7b0b48..338c8d07fe1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -33,36 +33,38 @@ namespace CGAL { } // Bounds. - template + template struct Bounds { using FT = typename Kernel::FT; FT lower = infinity_value(); FT upper = infinity_value(); - Face_handle lface = Face_handle(); - Face_handle uface = Face_handle(); - std::pair lpair = default_face_pair(); - std::pair upair = default_face_pair(); + // TODO: update + Face_handle_2 lface = Face_handle_2(); + Face_handle_2 uface = Face_handle_2(); + std::pair lpair = default_face_pair(); + std::pair upair = default_face_pair(); - const std::pair default_face_pair() const { - return std::make_pair(Face_handle(), Face_handle()); + const std::pair default_face_pair() const { + return std::make_pair(Face_handle_1(), Face_handle_2()); } }; // Candidate triangle. - template + template struct Candidate_triangle { using Triangle_3 = typename Kernel::Triangle_3; - using Candidate_bounds = Bounds; + using Candidate_bounds = Bounds; Candidate_triangle( - const Triangle_3& triangle, const Candidate_bounds& bounds, const Face_handle& fh) : + const Triangle_3& triangle, const Candidate_bounds& bounds, const Face_handle_1& fh) : triangle(triangle), bounds(bounds), face(fh) { } Triangle_3 triangle; Candidate_bounds bounds; - Face_handle face; + Face_handle_1 face; + // TODO: no need to use bounds.lower? bool operator>(const Candidate_triangle& other) const { return bounds.upper < other.bounds.upper; } bool operator<(const Candidate_triangle& other) const { return bounds.upper > other.bounds.upper; } }; @@ -72,7 +74,8 @@ namespace CGAL { typename AABBTraits, typename Query, typename Kernel, - typename TriangleMesh, typename VPM2> + typename TriangleMesh1, + typename TriangleMesh2, typename VPM2> class Hausdorff_primitive_traits_tm2 { using FT = typename Kernel::FT; @@ -81,16 +84,17 @@ namespace CGAL { using Triangle_3 = typename Kernel::Triangle_3; using Project_point_3 = typename Kernel::Construct_projected_point_3; - using Face_handle = typename boost::graph_traits::face_descriptor; - using Local_bounds = Bounds; + using Face_handle_1 = typename boost::graph_traits::face_descriptor; + using Face_handle_2 = typename boost::graph_traits::face_descriptor; + using Local_bounds = Bounds; - using TM2_face_to_triangle_map = Triangle_from_face_descriptor_map; + using TM2_face_to_triangle_map = Triangle_from_face_descriptor_map; public: using Priority = FT; Hausdorff_primitive_traits_tm2( const AABBTraits& traits, - const TriangleMesh& tm2, const VPM2& vpm2, + const TriangleMesh2& tm2, const VPM2& vpm2, const Local_bounds& local_bounds, const FT h_v0_lower_init, const FT h_v1_lower_init, @@ -127,7 +131,7 @@ namespace CGAL { const Point_3 v1 = query.vertex(1); const Point_3 v2 = query.vertex(2); - CGAL_assertion(primitive.id() != Face_handle()); + CGAL_assertion(primitive.id() != Face_handle_2()); const Triangle_3 triangle = get(m_face_to_triangle_map, primitive.id()); // Compute distances of the vertices to the primitive triangle in TM2. @@ -245,7 +249,7 @@ namespace CGAL { private: // Input data. const AABBTraits& m_traits; - const TriangleMesh& m_tm2; + const TriangleMesh2& m_tm2; const VPM2& m_vpm2; const TM2_face_to_triangle_map m_face_to_triangle_map; @@ -260,7 +264,8 @@ namespace CGAL { typename AABBTraits, typename Query, typename Kernel, - typename TriangleMesh, + typename TriangleMesh1, + typename TriangleMesh2, typename VPM1, typename VPM2> class Hausdorff_primitive_traits_tm1 { @@ -269,23 +274,24 @@ namespace CGAL { using Vector_3 = typename Kernel::Vector_3; using Triangle_3 = typename Kernel::Triangle_3; - using TM2_primitive = AABB_face_graph_triangle_primitive; + using TM2_primitive = AABB_face_graph_triangle_primitive; using TM2_traits = AABB_traits; using TM2_tree = AABB_tree; - using TM2_hd_traits = Hausdorff_primitive_traits_tm2; + using TM2_hd_traits = Hausdorff_primitive_traits_tm2; - using TM1_face_to_triangle_map = Triangle_from_face_descriptor_map; + using TM1_face_to_triangle_map = Triangle_from_face_descriptor_map; - using Face_handle = typename boost::graph_traits::face_descriptor; - using Global_bounds = Bounds; - using Candidate = Candidate_triangle; + using Face_handle_1 = typename boost::graph_traits::face_descriptor; + using Face_handle_2 = typename boost::graph_traits::face_descriptor; + using Global_bounds = Bounds; + using Candidate = Candidate_triangle; using Heap_type = std::priority_queue; public: using Priority = FT; Hausdorff_primitive_traits_tm1( const AABBTraits& traits, const TM2_tree& tree, - const TriangleMesh& tm1, const TriangleMesh& tm2, + const TriangleMesh1& tm1, const TriangleMesh2& tm2, const VPM1& vpm1, const VPM2& vpm2, const FT error_bound, const std::size_t group_traversal_bound) : @@ -313,12 +319,12 @@ namespace CGAL { void intersection(const Query&, const Primitive& primitive) { // Set initial tight bounds. - CGAL_assertion(primitive.id() != Face_handle()); - std::pair fpair; + CGAL_assertion(primitive.id() != Face_handle_1()); + std::pair fpair; const FT max_dist = get_maximum_distance(primitive.id(), fpair); CGAL_assertion(fpair.first == primitive.id()); - Bounds initial_bounds; + Bounds initial_bounds; initial_bounds.lower = max_dist + m_error_bound; initial_bounds.upper = max_dist + m_error_bound; initial_bounds.lface = fpair.second; @@ -434,8 +440,8 @@ namespace CGAL { // Here, we return the maximum distance from one of the face corners // to the second mesh. We also return a pair of realizing this distance faces. FT get_maximum_distance( - const Face_handle lface, - std::pair& fpair) const { + const Face_handle_1 lface, + std::pair& fpair) const { const auto triangle = get(m_face_to_triangle_map, lface); const Point_3 v0 = triangle.vertex(0); @@ -464,8 +470,8 @@ namespace CGAL { private: // Input data. const AABBTraits& m_traits; - const TriangleMesh& m_tm1; - const TriangleMesh& m_tm2; + const TriangleMesh1& m_tm1; + const TriangleMesh2& m_tm2; const VPM1& m_vpm1; const VPM2& m_vpm2; const TM2_tree& m_tm2_tree; @@ -485,30 +491,30 @@ namespace CGAL { if (m_candidiate_triangles.size() > 0) { const auto top = m_candidiate_triangles.top(); - if (h_global_bounds.lpair.first == Face_handle()) + if (h_global_bounds.lpair.first == Face_handle_1()) h_global_bounds.lpair.first = top.face; - if (h_global_bounds.lpair.second == Face_handle()) + if (h_global_bounds.lpair.second == Face_handle_2()) h_global_bounds.lpair.second = top.bounds.lface; - if (h_global_bounds.upair.first == Face_handle()) + if (h_global_bounds.upair.first == Face_handle_1()) h_global_bounds.upair.first = top.face; - if (h_global_bounds.upair.second == Face_handle()) + if (h_global_bounds.upair.second == Face_handle_2()) h_global_bounds.upair.second = top.bounds.uface; } else { - std::pair fpair; + std::pair fpair; get_maximum_distance(*(faces(m_tm1).begin()), fpair); CGAL_assertion(fpair.first == *(faces(m_tm1).begin())); - if (h_global_bounds.lpair.first == Face_handle()) + if (h_global_bounds.lpair.first == Face_handle_1()) h_global_bounds.lpair.first = fpair.first; - if (h_global_bounds.lpair.second == Face_handle()) + if (h_global_bounds.lpair.second == Face_handle_2()) h_global_bounds.lpair.second = fpair.second; - if (h_global_bounds.upair.first == Face_handle()) + if (h_global_bounds.upair.first == Face_handle_1()) h_global_bounds.upair.first = fpair.first; - if (h_global_bounds.upair.second == Face_handle()) + if (h_global_bounds.upair.second == Face_handle_2()) h_global_bounds.upair.second = fpair.second; } } From 11bb420ac2755b04140a01a05d18b7c006199afa Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 29 Apr 2021 15:49:48 +0200 Subject: [PATCH 175/349] Clean-up --- .../Polyhedron/Scene_surface_mesh_item.cpp | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp index 4e3175355af..78999e5f8f3 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp @@ -1516,27 +1516,33 @@ Scene_surface_mesh_item::save(std::ostream& out) const std::vector internal_properties; std::vector vprop = d->smesh_->properties(); std::vector fprop = d->smesh_->properties(); + + QString message = tr("Do you want to save the following properties ? \n"); + for(auto s : vprop) - if (s.compare("v:normal") == 0 - || s.compare("v:texcoord") == 0 - || s.compare("v:color") == 0) + { + if (s.compare("v:normal") == 0) { - internal_properties.push_back(s); + message.append(tr(" - Vertex Normals\n")); } + else if(s.compare("v:texcoord") == 0 ) + { + message.append(tr(" - Vertex UV Coordinates\n")); + } + else if(s.compare("v:color") == 0) + { + message.append(tr(" - Vertex Color\n")); + } + } for(auto s : fprop) + { if(s.compare("f:color") == 0) { - internal_properties.push_back(s); + message.append(tr(" - Face Color\n")); } - QString message = tr("Do you wish to export the following internal properties ? \n"); - for(auto s : internal_properties) - { - message.append(tr(" -")); - message.append(s.c_str()); - message.append(tr("\n")); } QMessageBox::StandardButton save_internal_properties = - QMessageBox::question(CGAL::Three::Three::mainWindow(), tr("Internal Properties"), message); + QMessageBox::question(CGAL::Three::Three::mainWindow(), tr("Save Properties"), message); QApplication::setOverrideCursor(Qt::WaitCursor); out.precision(17); if(save_internal_properties == QMessageBox::Yes) From e24c6bd3d8a7c5b32080a938a55c290c1894cefb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 29 Apr 2021 15:51:02 +0200 Subject: [PATCH 176/349] rename variables to make it clear from which mesh the faces are from --- .../CGAL/Polygon_mesh_processing/distance.h | 10 +++--- ...traversal_traits_with_Hausdorff_distance.h | 36 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 1eb14eb425d..e11c08dca98 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1479,7 +1479,7 @@ double bounded_error_Hausdorff_impl( // the triangle to the second mesh. Use it as new global lower bound. // TODO: Update the reference to the realizing triangle here as this is the best current guess. global_bounds.lower = triangle_bounds.upper; - global_bounds.lpair.second = triangle_bounds.uface; + global_bounds.lpair.second = triangle_bounds.tm2_uface; continue; } @@ -1493,7 +1493,7 @@ double bounded_error_Hausdorff_impl( // The upper bound of this triangle is within error tolerance of // the actual upper bound, use it. global_bounds.lower = triangle_bounds.upper; - global_bounds.lpair.second = triangle_bounds.uface; + global_bounds.lpair.second = triangle_bounds.tm2_uface; continue; } @@ -1529,12 +1529,12 @@ double bounded_error_Hausdorff_impl( if (local_bounds.lower > global_bounds.lower) { global_bounds.lower = local_bounds.lower; - global_bounds.lpair.second = local_bounds.lface; + global_bounds.lpair.second = local_bounds.tm2_lface; } // Add the subtriangle to the candidate list. candidate_triangles.push( - Candidate(sub_triangles[i], local_bounds, triangle_and_bound.face)); + Candidate(sub_triangles[i], local_bounds, triangle_and_bound.tm1_face)); } // Update global upper Hausdorff bound after subdivision. @@ -1543,7 +1543,7 @@ double bounded_error_Hausdorff_impl( if (current_max > global_bounds.lower) { global_bounds.upper = current_max; - global_bounds.upair.second = candidate_triangles.top().bounds.uface; + global_bounds.upair.second = candidate_triangles.top().bounds.tm2_uface; } else { global_bounds.upper = global_bounds.lower; global_bounds.upair.second = global_bounds.lpair.second; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 338c8d07fe1..d5d67ed8bcd 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -40,8 +40,8 @@ namespace CGAL { FT lower = infinity_value(); FT upper = infinity_value(); // TODO: update - Face_handle_2 lface = Face_handle_2(); - Face_handle_2 uface = Face_handle_2(); + Face_handle_2 tm2_lface = Face_handle_2(); + Face_handle_2 tm2_uface = Face_handle_2(); std::pair lpair = default_face_pair(); std::pair upair = default_face_pair(); @@ -58,12 +58,12 @@ namespace CGAL { Candidate_triangle( const Triangle_3& triangle, const Candidate_bounds& bounds, const Face_handle_1& fh) : - triangle(triangle), bounds(bounds), face(fh) + triangle(triangle), bounds(bounds), tm1_face(fh) { } Triangle_3 triangle; Candidate_bounds bounds; - Face_handle_1 face; + Face_handle_1 tm1_face; // TODO: no need to use bounds.lower? bool operator>(const Candidate_triangle& other) const { return bounds.upper < other.bounds.upper; } bool operator<(const Candidate_triangle& other) const { return bounds.upper > other.bounds.upper; } @@ -156,11 +156,11 @@ namespace CGAL { // TM1 to the primitive triangle in TM2. if (distance_lower < h_local_bounds.lower) { h_local_bounds.lower = distance_lower; - h_local_bounds.lface = primitive.id(); + h_local_bounds.tm2_lface = primitive.id(); } if (distance_upper < h_local_bounds.upper) { // it is (10) in the paper h_local_bounds.upper = distance_upper; - h_local_bounds.uface = primitive.id(); + h_local_bounds.tm2_uface = primitive.id(); } } @@ -327,8 +327,8 @@ namespace CGAL { Bounds initial_bounds; initial_bounds.lower = max_dist + m_error_bound; initial_bounds.upper = max_dist + m_error_bound; - initial_bounds.lface = fpair.second; - initial_bounds.uface = fpair.second; + initial_bounds.tm2_lface = fpair.second; + initial_bounds.tm2_uface = fpair.second; // Call Culling on B with the single triangle found. TM2_hd_traits traversal_traits_tm2( @@ -355,12 +355,12 @@ namespace CGAL { if (local_bounds.lower > h_global_bounds.lower) { // it is (6) in the paper, see also Algorithm 1 h_global_bounds.lower = local_bounds.lower; h_global_bounds.lpair.first = fpair.first; - h_global_bounds.lpair.second = local_bounds.lface; + h_global_bounds.lpair.second = local_bounds.tm2_lface; } if (local_bounds.upper > h_global_bounds.upper) { // it is (6) in the paper, see also Algorithm 1 h_global_bounds.upper = local_bounds.upper; h_global_bounds.upair.first = fpair.first; - h_global_bounds.upair.second = local_bounds.uface; + h_global_bounds.upair.second = local_bounds.tm2_uface; } // Store the triangle given as primitive here as candidate triangle @@ -440,10 +440,10 @@ namespace CGAL { // Here, we return the maximum distance from one of the face corners // to the second mesh. We also return a pair of realizing this distance faces. FT get_maximum_distance( - const Face_handle_1 lface, + const Face_handle_1 tm1_lface, std::pair& fpair) const { - const auto triangle = get(m_face_to_triangle_map, lface); + const auto triangle = get(m_face_to_triangle_map, tm1_lface); const Point_3 v0 = triangle.vertex(0); const Point_3 v1 = triangle.vertex(1); const Point_3 v2 = triangle.vertex(2); @@ -462,8 +462,8 @@ namespace CGAL { const auto mdist1 = (sq_dist0.first > sq_dist1.first) ? sq_dist0 : sq_dist1; const auto mdist2 = (mdist1.first > sq_dist2.first) ? mdist1 : sq_dist2; - const auto uface = mdist2.second; - fpair = std::make_pair(lface, uface); + Face_handle_2 tm2_uface = mdist2.second; + fpair = std::make_pair(tm1_lface, tm2_uface); return static_cast(CGAL::sqrt(CGAL::to_double(mdist2.first))); } @@ -492,14 +492,14 @@ namespace CGAL { const auto top = m_candidiate_triangles.top(); if (h_global_bounds.lpair.first == Face_handle_1()) - h_global_bounds.lpair.first = top.face; + h_global_bounds.lpair.first = top.tm1_face; if (h_global_bounds.lpair.second == Face_handle_2()) - h_global_bounds.lpair.second = top.bounds.lface; + h_global_bounds.lpair.second = top.bounds.tm2_lface; if (h_global_bounds.upair.first == Face_handle_1()) - h_global_bounds.upair.first = top.face; + h_global_bounds.upair.first = top.tm1_face; if (h_global_bounds.upair.second == Face_handle_2()) - h_global_bounds.upair.second = top.bounds.uface; + h_global_bounds.upair.second = top.bounds.tm2_uface; } else { From 7fd291c5889a961cfe0e552237dcadfe96bb9fd1 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 29 Apr 2021 17:43:00 +0200 Subject: [PATCH 177/349] added input-dependent infinity value + assertions --- ...usdorff_bounded_error_distance_example.cpp | 56 ++++----- .../CGAL/Polygon_mesh_processing/distance.h | 92 ++++++++------ ...traversal_traits_with_Hausdorff_distance.h | 114 +++++++++++------- .../test_hausdorff_bounded_error_distance.cpp | 28 ++--- 4 files changed, 168 insertions(+), 122 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 600b432c73c..27adbf71733 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -124,7 +124,7 @@ void perturbing_mesh_example( const std::string filepath, const double error_bound, const bool save = false) { Timer timer; - std::cout << std::endl << "* (E3) perturbing mesh example:" << std::endl; + std::cout << std::endl << "* (E3) perturbing mesh example (Surface Mesh):" << std::endl; Surface_mesh mesh1, mesh2; get_meshes(filepath, filepath, mesh1, mesh2); @@ -144,6 +144,34 @@ void perturbing_mesh_example( std::cout << "* processing time: " << timer.time() << " s." << std::endl; } +// Read two meshes and store them in two different face graph containers, +// perturb the second mesh, and compute the Hausdorff distance. +void perturbing_mesh_example_with_polyhedron( + const std::string filepath, const double error_bound) { + + Timer timer; + std::cout << std::endl << "* (E3) perturbing mesh example (Polyhedron):" << std::endl; + + Surface_mesh mesh1; + Polyhedron mesh2; + get_mesh(filepath, mesh1); + get_mesh(filepath, mesh2); + + const double max_size = 0.1; + PMP::random_perturbation( + vertices(mesh2), mesh2, max_size, CGAL::parameters::do_project(false)); + std::cout << "* perturbing the second mesh" << std::endl; + + timer.reset(); + timer.start(); + std::cout << "* bounded Hausdorff distance 1->2: " << + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; + std::cout << "* bounded Hausdorff distance 2->1: " << + PMP::bounded_error_Hausdorff_distance(mesh2, mesh1, error_bound) << std::endl; + timer.stop(); + std::cout << "* processing time: " << timer.time() << " s." << std::endl; +} + // Read two meshes given by the user, initially place them at their originally // given position. Move the second mesh in 300 steps away from the first one. // Print how the Hausdorff distance changes. @@ -181,32 +209,6 @@ void moving_mesh_example( } } -void perturbing_mesh_example_with_polyhedron( - const std::string filepath, const double error_bound) { - - Timer timer; - std::cout << std::endl << "* (E3) perturbing mesh example:" << std::endl; - - Surface_mesh mesh1; - Polyhedron mesh2; - get_mesh(filepath, mesh1); - get_mesh(filepath, mesh2); - - const double max_size = 0.1; - PMP::random_perturbation( - vertices(mesh2), mesh2, max_size, CGAL::parameters::do_project(false)); - std::cout << "* perturbing the second mesh" << std::endl; - - timer.reset(); - timer.start(); - std::cout << "* bounded Hausdorff distance 1->2: " << - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; - std::cout << "* bounded Hausdorff distance 2->1: " << - PMP::bounded_error_Hausdorff_distance(mesh2, mesh1, error_bound) << std::endl; - timer.stop(); - std::cout << "* processing time: " << timer.time() << " s." << std::endl; -} - int main(int argc, char** argv) { const double error_bound = 1e-4; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index e11c08dca98..fec551ddb16 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1318,23 +1318,24 @@ double approximate_symmetric_Hausdorff_distance(const TriangleMesh& tm1, namespace internal { -template< -class Concurrency_tag, -class Kernel, -class TriangleMesh1, -class TriangleMesh2, -class VPM1, class VPM2, -class NamedParameters1, -class NamedParameters2> +template< class Concurrency_tag, + class Kernel, + class TriangleMesh1, + class TriangleMesh2, + class VPM1, + class VPM2, + class NamedParameters1, + class NamedParameters2> double bounded_error_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const typename Kernel::FT error_bound, const bool compare_meshes, - const VPM1& vpm1, const VPM2& vpm2, + const VPM1& vpm1, + const VPM2& vpm2, const NamedParameters1& np1, - const NamedParameters2& np2) { - + const NamedParameters2& np2) +{ CGAL_assertion_code( const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2)); CGAL_assertion_msg(is_triangle, @@ -1404,9 +1405,21 @@ double bounded_error_Hausdorff_impl( const bool is_tm2_memory_ok = tm2_tree.accelerate_distance_queries(); CGAL_assertion(is_tm2_memory_ok); + // Compute the max value that is used as infinity value for the given meshes. + // In our case, it is twice the length of the diagonal of the bbox of two input meshes. + const auto bbox1 = bbox(tm1); + const auto bbox2 = bbox(tm2); + const auto bb = bbox1 + bbox2; + const FT sq_dist = CGAL::squared_distance( + Point_3(bb.xmin(), bb.ymin(), bb.zmin()), + Point_3(bb.xmax(), bb.ymax(), bb.zmax())); + const FT dist = static_cast(CGAL::sqrt(CGAL::to_double(sq_dist))); + const FT infinity_value = dist * FT(2); + // Build traversal traits for tm1_tree. TM1_hd_traits traversal_traits_tm1( - tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, error_bound, group_traversal_bound); + tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, + error_bound, infinity_value, group_traversal_bound); // We skip computing internal Kd tree because we do not compute distance queries. tm1_tree.do_not_accelerate_distance_queries(); @@ -1418,11 +1431,7 @@ double bounded_error_Hausdorff_impl( timer.reset(); timer.start(); const Point_3 stub(0, 0, 0); // dummy point given as query since it is not needed - // if (group_traversal_bound > 1) { - // tm1_tree.traversal_with_priority_and_group_traversal(stub, traversal_traits_tm1, group_traversal_bound); // with group traversal - // } else { - tm1_tree.traversal_with_priority(stub, traversal_traits_tm1); - // } + tm1_tree.traversal_with_priority(stub, traversal_traits_tm1); // here we do not use group traversal timer.stop(); // std::cout << "* TM1 traversal (sec.): " << timer.time() << std::endl; @@ -1437,6 +1446,8 @@ double bounded_error_Hausdorff_impl( // FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)) << "%" << std::endl; // See Section 5.1 in the paper. + CGAL_assertion(global_bounds.lower >= FT(0)); + CGAL_assertion(global_bounds.upper >= FT(0)); const FT squared_error_bound = error_bound * error_bound; while ( (global_bounds.upper - global_bounds.lower > error_bound) && @@ -1453,6 +1464,9 @@ double bounded_error_Hausdorff_impl( // user given error. const auto& triangle_bounds = triangle_and_bound.bounds; + CGAL_assertion(triangle_bounds.lower >= FT(0)); + CGAL_assertion(triangle_bounds.upper >= FT(0)); + if ( (triangle_bounds.upper > global_bounds.lower) && (triangle_bounds.upper - triangle_bounds.lower > error_bound)) { @@ -1512,9 +1526,9 @@ double bounded_error_Hausdorff_impl( TM2_hd_traits traversal_traits_tm2( tm2_tree.traits(), tm2, vpm2, triangle_bounds, - infinity_value(), - infinity_value(), - infinity_value()); + infinity_value, + infinity_value, + infinity_value); if (group_traversal_bound > 1) { tm2_tree.traversal_with_priority_and_group_traversal(sub_triangles[i], traversal_traits_tm2, group_traversal_bound); // with group traversal @@ -1524,6 +1538,10 @@ double bounded_error_Hausdorff_impl( // Update global lower Hausdorff bound according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); + + CGAL_assertion(local_bounds.lower >= FT(0)); + CGAL_assertion(local_bounds.upper >= FT(0)); + CGAL_precondition(local_bounds.lpair == local_bounds.default_face_pair()); CGAL_precondition(local_bounds.upair == local_bounds.default_face_pair()); @@ -1539,7 +1557,7 @@ double bounded_error_Hausdorff_impl( // Update global upper Hausdorff bound after subdivision. const FT current_max = candidate_triangles.top().bounds.upper; - // global_bounds.upper = std::max(current_max, global_bounds.lower); + CGAL_assertion(current_max >= FT(0)); if (current_max > global_bounds.lower) { global_bounds.upper = current_max; @@ -1560,6 +1578,8 @@ double bounded_error_Hausdorff_impl( // std::cout << "* found uface 2:" << static_cast(global_bounds.upair.second) << std::endl; // Return linear interpolation between the found lower and upper bounds. + CGAL_assertion(global_bounds.lower >= FT(0)); + CGAL_assertion(global_bounds.upper >= FT(0)); const double hdist = CGAL::to_double((global_bounds.lower + global_bounds.upper) / FT(2)); CGAL_precondition(global_bounds.lpair.first != boost::graph_traits::null_face()); @@ -1574,14 +1594,13 @@ double bounded_error_Hausdorff_impl( return hdist; } -template< -class Concurrency_tag, -class Kernel, -class TriangleMesh1, -class TriangleMesh2, -class VPM1, class VPM2, -class NamedParameters1, -class NamedParameters2> +template< class Concurrency_tag, + class Kernel, + class TriangleMesh1, + class TriangleMesh2, + class VPM1, class VPM2, + class NamedParameters1, + class NamedParameters2> double bounded_error_symmetric_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, @@ -1589,8 +1608,8 @@ double bounded_error_symmetric_Hausdorff_impl( const bool compare_meshes, const VPM1& vpm1, const VPM2& vpm2, const NamedParameters1& np1, - const NamedParameters2& np2) { - + const NamedParameters2& np2) +{ const double hdist1 = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, compare_meshes, vpm1, vpm2, np1, np2); const double hdist2 = bounded_error_Hausdorff_impl( @@ -1764,7 +1783,6 @@ double bounded_error_Hausdorff_distance( const NamedParameters1& np1, const NamedParameters2& np2) { - using Traits = typename GetGeomTraits::type; using FT = typename Traits::FT; @@ -1887,14 +1905,14 @@ double bounded_error_symmetric_Hausdorff_distance( tm1, tm2, error_bound, np1, parameters::all_default()); } -template< -class Concurrency_tag, -class TriangleMesh1, -class TriangleMesh2> +template< class Concurrency_tag, + class TriangleMesh1, + class TriangleMesh2> double bounded_error_symmetric_Hausdorff_distance( const TriangleMesh1& tm1, const TriangleMesh2& tm2, - const double error_bound) { + const double error_bound) +{ return bounded_error_symmetric_Hausdorff_distance( tm1, tm2, error_bound, parameters::all_default()); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index d5d67ed8bcd..83e2b13094d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -26,19 +26,19 @@ namespace CGAL { - // Infinity. - template - static FT infinity_value() { - return FT(1000000000000); - } - // Bounds. - template + template< class Kernel, + class Face_handle_1, + class Face_handle_2> struct Bounds { using FT = typename Kernel::FT; - FT lower = infinity_value(); - FT upper = infinity_value(); + FT m_infinity_value = -FT(1); + Bounds(const FT infinity_value) : + m_infinity_value(infinity_value) { } + + FT lower = m_infinity_value; + FT upper = m_infinity_value; // TODO: update Face_handle_2 tm2_lface = Face_handle_2(); Face_handle_2 tm2_uface = Face_handle_2(); @@ -51,8 +51,11 @@ namespace CGAL { }; // Candidate triangle. - template + template< class Kernel, + class Face_handle_1, + class Face_handle_2> struct Candidate_triangle { + using FT = typename Kernel::FT; using Triangle_3 = typename Kernel::Triangle_3; using Candidate_bounds = Bounds; @@ -65,27 +68,35 @@ namespace CGAL { Candidate_bounds bounds; Face_handle_1 tm1_face; // TODO: no need to use bounds.lower? - bool operator>(const Candidate_triangle& other) const { return bounds.upper < other.bounds.upper; } - bool operator<(const Candidate_triangle& other) const { return bounds.upper > other.bounds.upper; } + bool operator>(const Candidate_triangle& other) const { + CGAL_assertion(bounds.upper >= FT(0)); + CGAL_assertion(other.bounds.upper >= FT(0)); + return bounds.upper < other.bounds.upper; + } + bool operator<(const Candidate_triangle& other) const { + CGAL_assertion(bounds.upper >= FT(0)); + CGAL_assertion(other.bounds.upper >= FT(0)); + return bounds.upper > other.bounds.upper; + } }; // Hausdorff primitive traits on TM2. - template< - typename AABBTraits, - typename Query, - typename Kernel, - typename TriangleMesh1, - typename TriangleMesh2, typename VPM2> - class Hausdorff_primitive_traits_tm2 { - + template< class AABBTraits, + class Query, + class Kernel, + class TriangleMesh1, + class TriangleMesh2, + class VPM2> + class Hausdorff_primitive_traits_tm2 + { using FT = typename Kernel::FT; using Point_3 = typename Kernel::Point_3; using Vector_3 = typename Kernel::Vector_3; using Triangle_3 = typename Kernel::Triangle_3; using Project_point_3 = typename Kernel::Construct_projected_point_3; - using Face_handle_1 = typename boost::graph_traits::face_descriptor; - using Face_handle_2 = typename boost::graph_traits::face_descriptor; + using Face_handle_1 = typename boost::graph_traits::face_descriptor; + using Face_handle_2 = typename boost::graph_traits::face_descriptor; using Local_bounds = Bounds; using TM2_face_to_triangle_map = Triangle_from_face_descriptor_map; @@ -114,7 +125,7 @@ namespace CGAL { bool go_further() const { return true; } // Compute the explicit Hausdorff distance to the given primitive. - template + template void intersection(const Query& query, const Primitive& primitive) { /* Have reached a single triangle, process it. @@ -154,10 +165,12 @@ namespace CGAL { // Since we are at the level of a single triangle in TM2, distance_upper is // actually the correct Hausdorff distance from the query triangle in // TM1 to the primitive triangle in TM2. + CGAL_assertion(h_local_bounds.lower >= FT(0)); if (distance_lower < h_local_bounds.lower) { h_local_bounds.lower = distance_lower; h_local_bounds.tm2_lface = primitive.id(); } + CGAL_assertion(h_local_bounds.upper >= FT(0)); if (distance_upper < h_local_bounds.upper) { // it is (10) in the paper h_local_bounds.upper = distance_upper; h_local_bounds.tm2_uface = primitive.id(); @@ -166,7 +179,7 @@ namespace CGAL { // Determine whether child nodes will still contribute to a smaller // Hausdorff distance and thus have to be entered. - template + template std::pair do_intersect_with_priority(const Query& query, const Node& node) const { @@ -222,6 +235,7 @@ namespace CGAL { // See Algorithm 2. // Check whether investigating the bbox can still lower the Hausdorff // distance and improve the current global bound. If so, enter the box. + CGAL_assertion(h_local_bounds.lower >= FT(0)); if (dist <= h_local_bounds.lower) { return std::make_pair(true , -dist); } else { @@ -229,7 +243,7 @@ namespace CGAL { } } - template + template bool do_intersect(const Query& query, const Node& node) const { return this->do_intersect_with_priority(query, node).first; } @@ -260,15 +274,15 @@ namespace CGAL { }; // Hausdorff primitive traits on TM1. - template< - typename AABBTraits, - typename Query, - typename Kernel, - typename TriangleMesh1, - typename TriangleMesh2, - typename VPM1, typename VPM2> - class Hausdorff_primitive_traits_tm1 { - + template< class AABBTraits, + class Query, + class Kernel, + class TriangleMesh1, + class TriangleMesh2, + class VPM1, + class VPM2> + class Hausdorff_primitive_traits_tm1 + { using FT = typename Kernel::FT; using Point_3 = typename Kernel::Point_3; using Vector_3 = typename Kernel::Vector_3; @@ -294,6 +308,7 @@ namespace CGAL { const TriangleMesh1& tm1, const TriangleMesh2& tm2, const VPM1& vpm1, const VPM2& vpm2, const FT error_bound, + const FT infinity_value, const std::size_t group_traversal_bound) : m_traits(traits), m_tm1(tm1), m_tm2(tm2), @@ -301,11 +316,14 @@ namespace CGAL { m_tm2_tree(tree), m_face_to_triangle_map(&m_tm1, m_vpm1), m_error_bound(error_bound), - m_group_traversal_bound(group_traversal_bound) { + m_infinity_value(infinity_value), + m_group_traversal_bound(group_traversal_bound), + h_global_bounds(m_infinity_value) { // Initialize the global bounds with 0, they will only grow. // If we leave zero here, then we are very slow even for big input error bounds! // The error_bound here makes the code faster for close meshes. + CGAL_assertion(m_error_bound >= FT(0)); h_global_bounds.lower = m_error_bound; // = FT(0); h_global_bounds.upper = m_error_bound; // = FT(0); } @@ -315,16 +333,17 @@ namespace CGAL { bool go_further() const { return true; } // Compute the explicit Hausdorff distance to the given primitive. - template + template void intersection(const Query&, const Primitive& primitive) { // Set initial tight bounds. CGAL_assertion(primitive.id() != Face_handle_1()); std::pair fpair; const FT max_dist = get_maximum_distance(primitive.id(), fpair); + CGAL_assertion(max_dist >= FT(0)); CGAL_assertion(fpair.first == primitive.id()); - Bounds initial_bounds; + Bounds initial_bounds(m_infinity_value); initial_bounds.lower = max_dist + m_error_bound; initial_bounds.upper = max_dist + m_error_bound; initial_bounds.tm2_lface = fpair.second; @@ -334,10 +353,10 @@ namespace CGAL { TM2_hd_traits traversal_traits_tm2( m_tm2_tree.traits(), m_tm2, m_vpm2, initial_bounds, // tighter bounds, in the paper, they start from infinity, see below - // Bounds(), // starting from infinity - infinity_value(), - infinity_value(), - infinity_value()); + // Bounds(m_infinity_value), // starting from infinity + m_infinity_value, + m_infinity_value, + m_infinity_value); const Triangle_3 triangle = get(m_face_to_triangle_map, fpair.first); @@ -349,14 +368,19 @@ namespace CGAL { // Update global Hausdorff bounds according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); + + CGAL_assertion(local_bounds.lower >= FT(0)); + CGAL_assertion(local_bounds.upper >= FT(0)); CGAL_assertion(local_bounds.lpair == initial_bounds.default_face_pair()); CGAL_assertion(local_bounds.upair == initial_bounds.default_face_pair()); + CGAL_assertion(h_global_bounds.lower >= FT(0)); if (local_bounds.lower > h_global_bounds.lower) { // it is (6) in the paper, see also Algorithm 1 h_global_bounds.lower = local_bounds.lower; h_global_bounds.lpair.first = fpair.first; h_global_bounds.lpair.second = local_bounds.tm2_lface; } + CGAL_assertion(h_global_bounds.upper >= FT(0)); if (local_bounds.upper > h_global_bounds.upper) { // it is (6) in the paper, see also Algorithm 1 h_global_bounds.upper = local_bounds.upper; h_global_bounds.upair.first = fpair.first; @@ -370,7 +394,7 @@ namespace CGAL { // Determine whether child nodes will still contribute to a larger // Hausdorff distance and thus have to be entered. - template + template std::pair do_intersect_with_priority(const Query&, const Node& node) const { @@ -405,6 +429,7 @@ namespace CGAL { // See Algorithm 1 here. // If the distance is larger than the global lower bound, enter the node, i.e. return true. + CGAL_assertion(h_global_bounds.lower >= FT(0)); if (dist > h_global_bounds.lower) { return std::make_pair(true , +dist); } else { @@ -412,7 +437,7 @@ namespace CGAL { } } - template + template bool do_intersect(const Query& query, const Node& node) const { return this->do_intersect_with_priority(query, node).first; } @@ -477,8 +502,9 @@ namespace CGAL { const TM2_tree& m_tm2_tree; const TM1_face_to_triangle_map m_face_to_triangle_map; - // Global Hausdorff bounds for the query triangle. + // Internal bounds and values. const FT m_error_bound; + const FT m_infinity_value; const std::size_t m_group_traversal_bound; Global_bounds h_global_bounds; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 8e88424a120..62fcc558081 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -84,7 +84,7 @@ void save_mesh(const Surface_mesh& mesh, const std::string filepath) { } } -template +template void test_0(const FunctionWrapper& functor, const bool save = false) { // The same triangle. @@ -110,7 +110,7 @@ void test_0(const FunctionWrapper& functor, const bool save = false) { std::cout << "* HInverted distance (expected 0): " << distb << std::endl; } -template +template void test_1(const FunctionWrapper& functor, const bool save = false) { // Two triangles are parallel and 1 unit distance away from each other. @@ -139,7 +139,7 @@ void test_1(const FunctionWrapper& functor, const bool save = false) { std::cout << "* HInverted distance (expected 1): " << distb << std::endl; } -template +template void test_2(const FunctionWrapper& functor, const bool save = false) { // One triangle is orthogonal to the other one and shares a common edge. @@ -168,7 +168,7 @@ void test_2(const FunctionWrapper& functor, const bool save = false) { std::cout << "* HInverted distance (expected 1): " << distb << std::endl; } -template +template void test_3(const FunctionWrapper& functor, const bool save = false) { // One triangle is orthogonal to the other one and shares a common edge @@ -198,7 +198,7 @@ void test_3(const FunctionWrapper& functor, const bool save = false) { std::cout << "* HInverted distance (expected 2 ): " << distb << std::endl; } -template +template void test_4(const FunctionWrapper& functor, const bool save = false) { // One triangle is orthogonal to the other one and shares a common vertex. @@ -227,7 +227,7 @@ void test_4(const FunctionWrapper& functor, const bool save = false) { std::cout << "* HInverted distance (expected 1.22): " << distb << std::endl; } -template +template void test_5(const FunctionWrapper& functor, const bool save = false) { // One triangle is orthogonal to the other one and shares a common vertex @@ -257,7 +257,7 @@ void test_5(const FunctionWrapper& functor, const bool save = false) { std::cout << "* HInverted distance (expected 2.12): " << distb << std::endl; } -template +template void test_6(const FunctionWrapper& functor, const bool save = false) { // The first and second mesh have different number of triangles. @@ -292,7 +292,7 @@ void test_6(const FunctionWrapper& functor, const bool save = false) { std::cout << "* HInverted distance (expected 0.7): " << distb << std::endl; } -template +template void test_7(const FunctionWrapper& functor, const bool save = false) { // One triangle is moved to 0.5 unit distance away from 3 other triangles. @@ -327,7 +327,7 @@ void test_7(const FunctionWrapper& functor, const bool save = false) { std::cout << "* HInverted distance (expected 0.86): " << distb << std::endl; } -template +template void test_8(const FunctionWrapper& functor, const bool save = false) { // One mesh has one triangle at zero level, another mesh has two triangles @@ -362,7 +362,7 @@ void test_8(const FunctionWrapper& functor, const bool save = false) { std::cout << "* HInverted distance (expected 2): " << distb << std::endl; } -template +template void test_9(const FunctionWrapper& functor, const bool save = false) { // Two meshes partially overlap, have 2 triangles in common and each one has @@ -404,7 +404,7 @@ void test_9(const FunctionWrapper& functor, const bool save = false) { std::cout << "* HInverted distance (expected 1): " << distb << std::endl; } -template +template void test_synthetic_data(const FunctionWrapper& functor) { std::cout << std::endl << "-- test synthetic data:" << std::endl << std::endl; @@ -499,7 +499,7 @@ void test_real_meshes( std::cout << "* Hausdorff distance2 b: " << distb1 << std::endl; } -template +template void test_timings(const std::string filepath, const FunctionWrapper& functor) { std::cout.precision(20); @@ -528,7 +528,7 @@ void test_timings(const std::string filepath, const FunctionWrapper& functor) { std::cout << "* distb = " << distb << std::endl; } -template +template void test_bunny( const FunctionWrapper& functor, const int n = 5, const bool save = false) { @@ -776,7 +776,7 @@ int main(int argc, char** argv) { // test_bunny(apprx_hd); // test_bunny(naive_hd); - // test_bunny(bound_hd, 3); + test_bunny(bound_hd, 3); // --- Test realizing triangles. From d0608093ec9ef3e0a90bee0a7981ddfa233eed6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 29 Apr 2021 17:46:14 +0200 Subject: [PATCH 178/349] remove unused typedef --- .../include/CGAL/Polygon_mesh_processing/measure.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 88f5bbb934c..f6cf6936f42 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -906,7 +906,6 @@ void match_faces(const PolygonMesh1& m1, const PolygonMesh2& m2, VIMap2 vim2 = get_initialized_vertex_index_map(m2, np2); typedef typename boost::property_traits::value_type Point_3; typedef typename boost::graph_traits::face_descriptor face_descriptor_1; - typedef typename boost::graph_traits::face_descriptor face_descriptor_2; std::map point_id_map; From 26621062e2e758467bfc68885996d9fbcaa1d146 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 30 Apr 2021 08:36:55 +0200 Subject: [PATCH 179/349] add an `s` --- Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp index 78999e5f8f3..bcbd2f141cb 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp @@ -1531,14 +1531,14 @@ Scene_surface_mesh_item::save(std::ostream& out) const } else if(s.compare("v:color") == 0) { - message.append(tr(" - Vertex Color\n")); + message.append(tr(" - Vertex Colors\n")); } } for(auto s : fprop) { if(s.compare("f:color") == 0) { - message.append(tr(" - Face Color\n")); + message.append(tr(" - Face Colors\n")); } } QMessageBox::StandardButton save_internal_properties = From 5fe5bb049cb0e259b0b8df8487613293b55ba2ed Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 30 Apr 2021 09:27:21 +0200 Subject: [PATCH 180/349] Update Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp Co-authored-by: Sebastien Loriot --- .../hausdorff_bounded_error_distance_example.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 27adbf71733..3107e29fca1 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -186,10 +186,9 @@ void moving_mesh_example( get_meshes(filepath1, filepath2, mesh1, mesh2); const auto bbox = PMP::bbox(mesh2); - const FT distance = static_cast(CGAL::sqrt(CGAL::to_double( - CGAL::squared_distance( + const FT distance = CGAL::approximate_sqrt(CGAL::squared_distance( Point_3(bbox.xmin(), bbox.ymin(), bbox.zmin()), - Point_3(bbox.xmax(), bbox.ymax(), bbox.zmax()))))); + Point_3(bbox.xmax(), bbox.ymax(), bbox.zmax()))); const FT t = FT(1) / FT(100); if (save) save_mesh(mesh2, "mesh-0"); From 5d77b22f7a510c5dd0743041f2cc2d6474296681 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 30 Apr 2021 10:25:22 +0200 Subject: [PATCH 181/349] changed sqrt to approximate sqrt --- .../CGAL/Polygon_mesh_processing/distance.h | 2 +- ...BB_traversal_traits_with_Hausdorff_distance.h | 16 ++++++---------- .../test_hausdorff_bounded_error_distance.cpp | 1 + 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index fec551ddb16..f23f6f015c2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1413,7 +1413,7 @@ double bounded_error_Hausdorff_impl( const FT sq_dist = CGAL::squared_distance( Point_3(bb.xmin(), bb.ymin(), bb.zmin()), Point_3(bb.xmax(), bb.ymax(), bb.zmax())); - const FT dist = static_cast(CGAL::sqrt(CGAL::to_double(sq_dist))); + const FT dist = CGAL::approximate_sqrt(sq_dist); const FT infinity_value = dist * FT(2); // Build traversal traits for tm1_tree. diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 83e2b13094d..4da3b658a1f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -146,16 +146,13 @@ namespace CGAL { const Triangle_3 triangle = get(m_face_to_triangle_map, primitive.id()); // Compute distances of the vertices to the primitive triangle in TM2. - const FT v0_dist = static_cast(CGAL::sqrt(CGAL::to_double( - CGAL::squared_distance(m_project_point(triangle, v0), v0)))); + const FT v0_dist = CGAL::approximate_sqrt(CGAL::squared_distance(m_project_point(triangle, v0), v0)); if (v0_dist < h_v0_lower) h_v0_lower = v0_dist; // it is () part of (11) in the paper - const FT v1_dist = static_cast(CGAL::sqrt(CGAL::to_double( - CGAL::squared_distance(m_project_point(triangle, v1), v1)))); + const FT v1_dist = CGAL::approximate_sqrt(CGAL::squared_distance(m_project_point(triangle, v1), v1)); if (v1_dist < h_v1_lower) h_v1_lower = v1_dist; // it is () part of (11) in the paper - const FT v2_dist = static_cast(CGAL::sqrt(CGAL::to_double( - CGAL::squared_distance(m_project_point(triangle, v2), v2)))); + const FT v2_dist = CGAL::approximate_sqrt(CGAL::squared_distance(m_project_point(triangle, v2), v2)); if (v2_dist < h_v2_lower) h_v2_lower = v2_dist; // it is () part of (11) in the paper // Get the distance as maximizers over all vertices. @@ -229,8 +226,7 @@ namespace CGAL { // Lower bound on the distance between the two bounding boxes is given // as the length of the diagonal of the bounding box between them. - const FT dist = static_cast(CGAL::sqrt(CGAL::to_double( - Vector_3(dist_x, dist_y, dist_z).squared_length()))); + const FT dist = CGAL::approximate_sqrt(Vector_3(dist_x, dist_y, dist_z).squared_length()); // See Algorithm 2. // Check whether investigating the bbox can still lower the Hausdorff @@ -425,7 +421,7 @@ namespace CGAL { difference = difference + Vector_3(diff_x, diff_y, diff_z); // it is (9) in the paper // Compute distance from the farthest corner of the bbox to the closest point in TM2. - const FT dist = static_cast(CGAL::sqrt(CGAL::to_double(difference.squared_length()))); + const FT dist = CGAL::approximate_sqrt(difference.squared_length()); // See Algorithm 1 here. // If the distance is larger than the global lower bound, enter the node, i.e. return true. @@ -489,7 +485,7 @@ namespace CGAL { Face_handle_2 tm2_uface = mdist2.second; fpair = std::make_pair(tm1_lface, tm2_uface); - return static_cast(CGAL::sqrt(CGAL::to_double(mdist2.first))); + return CGAL::approximate_sqrt(mdist2.first); } private: diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 62fcc558081..c78c8d1601f 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -734,6 +734,7 @@ int main(int argc, char** argv) { // ------------------------------------------------------------------------ // // Tests. + // Approximate_hd_wrapper does not work with EPECK! Approximate_hd_wrapper apprx_hd(num_samples); Naive_bounded_error_hd_wrapper naive_hd(error_bound); Bounded_error_hd_wrapper bound_hd(error_bound); From c78c4d2963861fcec09d9fc0b3489fc2cfa9e570 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 30 Apr 2021 14:51:14 +0200 Subject: [PATCH 182/349] all preprocessing steps are moved to their own function --- .../CGAL/Polygon_mesh_processing/distance.h | 327 ++++++++++++------ ...traversal_traits_with_Hausdorff_distance.h | 17 +- .../test_hausdorff_bounded_error_distance.cpp | 63 ++++ 3 files changed, 286 insertions(+), 121 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index f23f6f015c2..c0f8e41377d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1318,92 +1318,40 @@ double approximate_symmetric_Hausdorff_distance(const TriangleMesh& tm1, namespace internal { -template< class Concurrency_tag, - class Kernel, +template< class Kernel, class TriangleMesh1, class TriangleMesh2, class VPM1, class VPM2, class NamedParameters1, - class NamedParameters2> -double bounded_error_Hausdorff_impl( + class NamedParameters2, + class TM1Tree, + class TM2Tree, + class FaceHandle1, + class FaceHandle2> +std::pair preprocess_bounded_error_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, - const typename Kernel::FT error_bound, const bool compare_meshes, const VPM1& vpm1, const VPM2& vpm2, const NamedParameters1& np1, - const NamedParameters2& np2) + const NamedParameters2& np2, + const bool is_one_sided_distance, + TM1Tree& tm1_tree, + TM2Tree& tm2_tree, + std::vector& tm1_only, + std::vector& tm2_only) { - CGAL_assertion_code( - const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2)); - CGAL_assertion_msg(is_triangle, - "Both meshes must be triangulated to compute this distance!"); - - using FT = typename Kernel::FT; - using Point_3 = typename Kernel::Point_3; - using Triangle_3 = typename Kernel::Triangle_3; - - using TM1_primitive = AABB_face_graph_triangle_primitive; - using TM2_primitive = AABB_face_graph_triangle_primitive; - - using TM1_traits = AABB_traits; - using TM2_traits = AABB_traits; - - using TM1_tree = AABB_tree; - using TM2_tree = AABB_tree; - - using TM1_hd_traits = Hausdorff_primitive_traits_tm1; - using TM2_hd_traits = Hausdorff_primitive_traits_tm2; - - using Face_handle_1 = typename boost::graph_traits::face_descriptor; - using Face_handle_2 = typename boost::graph_traits::face_descriptor; - using Candidate = Candidate_triangle; - using Timer = CGAL::Real_timer; - - std::cout.precision(20); - std::vector tm1_only; - std::vector tm2_only; - - std::vector< std::pair > common; - const std::size_t group_traversal_bound = 1; - - const auto faces1 = faces(tm1); - const auto faces2 = faces(tm2); - - CGAL_precondition(faces1.size() > 0); - CGAL_precondition(faces2.size() > 0); + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Timer = CGAL::Real_timer; Timer timer; timer.start(); - TM1_tree tm1_tree; - if (compare_meshes) { // exact check - match_faces(tm1, tm2, std::back_inserter(common), - std::back_inserter(tm1_only), std::back_inserter(tm2_only), np1, np2); - - // std::cout << "common t: " << common.size() << std::endl; - // std::cout << "tm1 only: " << tm1_only.size() << std::endl; - // std::cout << "tm2 only: " << tm2_only.size() << std::endl; - - if (tm1_only.size() == 0) { - timer.stop(); - // std::cout << "* culling rate: 100%" << std::endl; - // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; - return 0.0; - } - CGAL_assertion(tm1_only.size() > 0); - - tm1_tree.insert(tm1_only.begin(), tm1_only.end(), tm1, vpm1); - } else { - tm1_tree.insert(faces1.begin(), faces1.end(), tm1, vpm1); - } - - // Here, we explicitly accelerate because we use tm2 for distance queries. - TM2_tree tm2_tree(faces2.begin(), faces2.end(), tm2, vpm2); - const bool is_tm2_memory_ok = tm2_tree.accelerate_distance_queries(); - CGAL_assertion(is_tm2_memory_ok); + // std::cout << "* preprocessing begin ...." << std::endl; + std::cout.precision(20); // Compute the max value that is used as infinity value for the given meshes. // In our case, it is twice the length of the diagonal of the bbox of two input meshes. @@ -1413,37 +1361,136 @@ double bounded_error_Hausdorff_impl( const FT sq_dist = CGAL::squared_distance( Point_3(bb.xmin(), bb.ymin(), bb.zmin()), Point_3(bb.xmax(), bb.ymax(), bb.zmax())); - const FT dist = CGAL::approximate_sqrt(sq_dist); - const FT infinity_value = dist * FT(2); + FT infinity_value = CGAL::approximate_sqrt(sq_dist) * FT(2); + + // Compare meshes and build trees. + tm1_only.clear(); + tm2_only.clear(); + std::vector< std::pair > common; + + const auto faces1 = faces(tm1); + const auto faces2 = faces(tm2); + + CGAL_precondition(faces1.size() > 0); + CGAL_precondition(faces2.size() > 0); + + // Compare meshes. + bool rebuild = false; + if (compare_meshes) { // exact check + match_faces(tm1, tm2, std::back_inserter(common), + std::back_inserter(tm1_only), std::back_inserter(tm2_only), np1, np2); + + // std::cout << "- common: " << common.size() << std::endl; + // std::cout << "- tm1 only: " << tm1_only.size() << std::endl; + // std::cout << "- tm2 only: " << tm2_only.size() << std::endl; + + if (is_one_sided_distance) { // one-sided distance + + if (tm1_only.size() > 0) { // create TM1 and and full TM2 + tm1_tree.insert(tm1_only.begin(), tm1_only.end(), tm1, vpm1); + tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); + } else { // do not create trees + CGAL_assertion(tm1_only.size() == 0); + infinity_value = -FT(1); + } + + } else { // symmetric distance + + if (tm1_only.size() == 0 && tm2_only.size() == 0) { // do not create trees + infinity_value = -FT(1); + } else if (tm1_only.size() == 0) { // create TM2 and full TM1 + CGAL_assertion(tm2_only.size() > 0); + tm1_tree.insert(faces1.begin(), faces1.end(), tm1, vpm1); + tm2_tree.insert(tm2_only.begin(), tm2_only.end(), tm2, vpm2); + } else if (tm2_only.size() == 0) { // create TM1 and full TM2 + CGAL_assertion(tm1_only.size() > 0); + tm1_tree.insert(tm1_only.begin(), tm1_only.end(), tm1, vpm1); + tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); + } else { // create TM1 and full TM2 and set tag to rebuild them later + CGAL_assertion(tm1_only.size() > 0); + CGAL_assertion(tm2_only.size() > 0); + tm1_tree.insert(tm1_only.begin(), tm1_only.end(), tm1, vpm1); + tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); + rebuild = true; + } + } + } else { // create full TM1 and TM2 + tm1_tree.insert(faces1.begin(), faces1.end(), tm1, vpm1); + tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); + } + + timer.stop(); + // std::cout << "* .... end preprocessing" << std::endl; + // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; + return std::make_pair(infinity_value, rebuild); +} + +template< class Concurrency_tag, + class Kernel, + class TriangleMesh1, + class TriangleMesh2, + class VPM1, + class VPM2, + class TM1Tree, + class TM2Tree> +double bounded_error_Hausdorff_impl( + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + const typename Kernel::FT error_bound, + const VPM1& vpm1, + const VPM2& vpm2, + const typename Kernel::FT infinity_value, + TM1Tree& tm1_tree, + TM2Tree& tm2_tree) +{ + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Triangle_3 = typename Kernel::Triangle_3; + + using TM1_tree = TM1Tree; + using TM2_tree = TM2Tree; + + using TM1_traits = typename TM1_tree::AABB_traits; + using TM2_traits = typename TM2_tree::AABB_traits; + + using TM1_hd_traits = Hausdorff_primitive_traits_tm1; + using TM2_hd_traits = Hausdorff_primitive_traits_tm2; + + using Face_handle_1 = typename boost::graph_traits::face_descriptor; + using Face_handle_2 = typename boost::graph_traits::face_descriptor; + + using Candidate = Candidate_triangle; + using Timer = CGAL::Real_timer; + std::cout.precision(20); + + // First, we apply culling. + + Timer timer; + timer.start(); // Build traversal traits for tm1_tree. TM1_hd_traits traversal_traits_tm1( - tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, - error_bound, infinity_value, group_traversal_bound); - - // We skip computing internal Kd tree because we do not compute distance queries. - tm1_tree.do_not_accelerate_distance_queries(); - - timer.stop(); - // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; - - // Find candidate triangles in TM1 which might realise the Hausdorff bound. - timer.reset(); - timer.start(); - const Point_3 stub(0, 0, 0); // dummy point given as query since it is not needed - tm1_tree.traversal_with_priority(stub, traversal_traits_tm1); // here we do not use group traversal - timer.stop(); - // std::cout << "* TM1 traversal (sec.): " << timer.time() << std::endl; + tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, error_bound, infinity_value); + // Find candidate triangles in TM1, which might realise the Hausdorff bound. // We build a sorted structure while collecting the candidates. + const Point_3 stub(0, 0, 0); // dummy point given as query since it is not needed + + tm1_tree.traversal_with_priority(stub, traversal_traits_tm1); auto& candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); auto global_bounds = traversal_traits_tm1.get_global_bounds(); - // std::cout << "* number of all triangles for TM1: " << tm1_tree.size() << std::endl; - // std::cout << "* number of candidate triangles before: " << candidate_triangles.size() << std::endl; + // std::cout << "- number of candidate triangles: " << candidate_triangles.size() << std::endl; + // const FT culling_rate = FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)); + // std::cout << "- culling rate: " << culling_rate << "%" << std::endl; - // std::cout << "* culling rate: " << - // FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)) << "%" << std::endl; + timer.stop(); + // std::cout << "* culling (sec.): " << timer.time() << std::endl; + + // Second, we apply subdivision. + + timer.reset(); + timer.start(); // See Section 5.1 in the paper. CGAL_assertion(global_bounds.lower >= FT(0)); @@ -1529,12 +1576,7 @@ double bounded_error_Hausdorff_impl( infinity_value, infinity_value, infinity_value); - - if (group_traversal_bound > 1) { - tm2_tree.traversal_with_priority_and_group_traversal(sub_triangles[i], traversal_traits_tm2, group_traversal_bound); // with group traversal - } else { - tm2_tree.traversal_with_priority(sub_triangles[i], traversal_traits_tm2); // without group traversal - } + tm2_tree.traversal_with_priority(sub_triangles[i], traversal_traits_tm2); // Update global lower Hausdorff bound according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); @@ -1569,19 +1611,21 @@ double bounded_error_Hausdorff_impl( } } - // std::cout << "* number of candidate triangles after: " << candidate_triangles.size() << std::endl; + timer.stop(); + // std::cout << "* subdivision (sec.): " << timer.time() << std::endl; - // std::cout << "* found lface 1:" << static_cast(global_bounds.lpair.first) << std::endl; - // std::cout << "* found lface 2:" << static_cast(global_bounds.lpair.second) << std::endl; - - // std::cout << "* found uface 1:" << static_cast(global_bounds.upair.first) << std::endl; - // std::cout << "* found uface 2:" << static_cast(global_bounds.upair.second) << std::endl; - - // Return linear interpolation between the found lower and upper bounds. + // Compute linear interpolation between the found lower and upper bounds. CGAL_assertion(global_bounds.lower >= FT(0)); CGAL_assertion(global_bounds.upper >= FT(0)); const double hdist = CGAL::to_double((global_bounds.lower + global_bounds.upper) / FT(2)); + // Get realizing triangles. + // std::cout << "- found lface 1:" << static_cast(global_bounds.lpair.first) << std::endl; + // std::cout << "- found lface 2:" << static_cast(global_bounds.lpair.second) << std::endl; + + // std::cout << "- found uface 1:" << static_cast(global_bounds.upair.first) << std::endl; + // std::cout << "- found uface 2:" << static_cast(global_bounds.upair.second) << std::endl; + CGAL_precondition(global_bounds.lpair.first != boost::graph_traits::null_face()); CGAL_precondition(global_bounds.lpair.second != boost::graph_traits::null_face()); CGAL_precondition(global_bounds.upair.first != boost::graph_traits::null_face()); @@ -1594,6 +1638,58 @@ double bounded_error_Hausdorff_impl( return hdist; } +template< class Concurrency_tag, + class Kernel, + class TriangleMesh1, + class TriangleMesh2, + class VPM1, + class VPM2, + class NamedParameters1, + class NamedParameters2> +double bounded_error_one_sided_Hausdorff_impl( + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + const typename Kernel::FT error_bound, + const bool compare_meshes, + const VPM1& vpm1, + const VPM2& vpm2, + const NamedParameters1& np1, + const NamedParameters2& np2) +{ + using FT = typename Kernel::FT; + + using TM1_primitive = AABB_face_graph_triangle_primitive; + using TM2_primitive = AABB_face_graph_triangle_primitive; + + using TM1_traits = AABB_traits; + using TM2_traits = AABB_traits; + + using TM1_tree = AABB_tree; + using TM2_tree = AABB_tree; + + using Face_handle_1 = typename boost::graph_traits::face_descriptor; + using Face_handle_2 = typename boost::graph_traits::face_descriptor; + + std::cout.precision(20); + std::vector tm1_only; + std::vector tm2_only; + + TM1_tree tm1_tree; + TM2_tree tm2_tree; + FT infinity_value = -FT(1); + bool rebuild = false; + std::tie(infinity_value, rebuild) = preprocess_bounded_error_Hausdorff_impl( + tm1, tm2, compare_meshes, vpm1, vpm2, np1, np2, true, tm1_tree, tm2_tree, tm1_only, tm2_only); + CGAL_assertion(!rebuild); + + if (infinity_value < FT(0)) { + // std::cout << "* culling rate: 100%" << std::endl; + return 0.0; // TM1 is part of TM2 so the distance is zero + } + return bounded_error_Hausdorff_impl( + tm1, tm2, error_bound, vpm1, vpm2, infinity_value, tm1_tree, tm2_tree); +} + template< class Concurrency_tag, class Kernel, class TriangleMesh1, @@ -1610,11 +1706,14 @@ double bounded_error_symmetric_Hausdorff_impl( const NamedParameters1& np1, const NamedParameters2& np2) { - const double hdist1 = bounded_error_Hausdorff_impl( + // Naive version. + const double hdist1 = bounded_error_one_sided_Hausdorff_impl( tm1, tm2, error_bound, compare_meshes, vpm1, vpm2, np1, np2); - const double hdist2 = bounded_error_Hausdorff_impl( + const double hdist2 = bounded_error_one_sided_Hausdorff_impl( tm2, tm1, error_bound, compare_meshes, vpm2, vpm1, np2, np1); return (CGAL::max)(hdist1, hdist2); + + // return -1.0; } template ::type; using FT = typename Traits::FT; @@ -1801,7 +1905,7 @@ double bounded_error_Hausdorff_distance( CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); - return internal::bounded_error_Hausdorff_impl( + return internal::bounded_error_one_sided_Hausdorff_impl( tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); #if !defined(CGAL_LINKED_WITH_TBB) @@ -1861,6 +1965,11 @@ double bounded_error_symmetric_Hausdorff_distance( const NamedParameters1& np1, const NamedParameters2& np2) { + CGAL_assertion_code( + const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2)); + CGAL_assertion_msg(is_triangle, + "Both meshes must be triangulated to compute this distance!"); + using Traits = typename GetGeomTraits::type; using FT = typename Traits::FT; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 4da3b658a1f..0a97201ff6e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -291,8 +291,9 @@ namespace CGAL { using TM1_face_to_triangle_map = Triangle_from_face_descriptor_map; - using Face_handle_1 = typename boost::graph_traits::face_descriptor; - using Face_handle_2 = typename boost::graph_traits::face_descriptor; + using Face_handle_1 = typename boost::graph_traits::face_descriptor; + using Face_handle_2 = typename boost::graph_traits::face_descriptor; + using Global_bounds = Bounds; using Candidate = Candidate_triangle; using Heap_type = std::priority_queue; @@ -304,8 +305,7 @@ namespace CGAL { const TriangleMesh1& tm1, const TriangleMesh2& tm2, const VPM1& vpm1, const VPM2& vpm2, const FT error_bound, - const FT infinity_value, - const std::size_t group_traversal_bound) : + const FT infinity_value) : m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2), @@ -313,7 +313,6 @@ namespace CGAL { m_face_to_triangle_map(&m_tm1, m_vpm1), m_error_bound(error_bound), m_infinity_value(infinity_value), - m_group_traversal_bound(group_traversal_bound), h_global_bounds(m_infinity_value) { // Initialize the global bounds with 0, they will only grow. @@ -355,12 +354,7 @@ namespace CGAL { m_infinity_value); const Triangle_3 triangle = get(m_face_to_triangle_map, fpair.first); - - if (m_group_traversal_bound > 1) { - m_tm2_tree.traversal_with_priority_and_group_traversal(triangle, traversal_traits_tm2, m_group_traversal_bound); // with group traversal - } else { - m_tm2_tree.traversal_with_priority(triangle, traversal_traits_tm2); // without group traversal - } + m_tm2_tree.traversal_with_priority(triangle, traversal_traits_tm2); // Update global Hausdorff bounds according to the obtained local bounds. const auto local_bounds = traversal_traits_tm2.get_local_bounds(); @@ -501,7 +495,6 @@ namespace CGAL { // Internal bounds and values. const FT m_error_bound; const FT m_infinity_value; - const std::size_t m_group_traversal_bound; Global_bounds h_global_bounds; // All candidate triangles. diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index c78c8d1601f..6e7c0f9181c 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -40,6 +40,11 @@ struct Approximate_hd_wrapper { PMP::parameters::number_of_points_per_area_unit(m_num_samples), PMP::parameters::number_of_points_per_area_unit(m_num_samples)); } + double symmetric(const Surface_mesh& tm1, const Surface_mesh& tm2) const { + return PMP::approximate_symmetric_Hausdorff_distance(tm1, tm2, + PMP::parameters::number_of_points_per_area_unit(m_num_samples), + PMP::parameters::number_of_points_per_area_unit(m_num_samples)); + } }; struct Naive_bounded_error_hd_wrapper { @@ -49,6 +54,11 @@ struct Naive_bounded_error_hd_wrapper { double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { return PMP::bounded_error_Hausdorff_distance_naive(tm1, tm2, m_error_bound); } + double symmetric(const Surface_mesh& tm1, const Surface_mesh& tm2) const { + const double dista = operator()(tm1, tm2); + const double distb = operator()(tm2, tm1); + return (CGAL::max)(dista, distb); + } }; struct Bounded_error_hd_wrapper { @@ -58,6 +68,9 @@ struct Bounded_error_hd_wrapper { double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { return PMP::bounded_error_Hausdorff_distance(tm1, tm2, m_error_bound); } + double symmetric(const Surface_mesh& tm1, const Surface_mesh& tm2) const { + return PMP::bounded_error_symmetric_Hausdorff_distance(tm1, tm2, m_error_bound); + } }; void get_mesh(const std::string filepath, Surface_mesh& mesh) { @@ -106,8 +119,13 @@ void test_0(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); + const double naive = (CGAL::max)(dista, distb); + const double distc = functor.symmetric(mesh1, mesh2); + assert(distc == naive); + std::cout << "* Hausdorff distance (expected 0): " << dista << std::endl; std::cout << "* HInverted distance (expected 0): " << distb << std::endl; + std::cout << "* Symmetric distance (expected 0): " << distc << std::endl; } template @@ -135,8 +153,13 @@ void test_1(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); + const double naive = (CGAL::max)(dista, distb); + const double distc = functor.symmetric(mesh1, mesh2); + assert(distc == naive); + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; std::cout << "* HInverted distance (expected 1): " << distb << std::endl; + std::cout << "* Symmetric distance (expected 1): " << distc << std::endl; } template @@ -164,8 +187,13 @@ void test_2(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); + const double naive = (CGAL::max)(dista, distb); + const double distc = functor.symmetric(mesh1, mesh2); + assert(distc == naive); + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; std::cout << "* HInverted distance (expected 1): " << distb << std::endl; + std::cout << "* Symmetric distance (expected 1): " << distc << std::endl; } template @@ -194,8 +222,13 @@ void test_3(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); + const double naive = (CGAL::max)(dista, distb); + const double distc = functor.symmetric(mesh1, mesh2); + assert(distc == naive); + std::cout << "* Hausdorff distance (expected sqrt(2)): " << dista << std::endl; std::cout << "* HInverted distance (expected 2 ): " << distb << std::endl; + std::cout << "* Symmetric distance (expected 2 ): " << distc << std::endl; } template @@ -223,8 +256,13 @@ void test_4(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); + const double naive = (CGAL::max)(dista, distb); + const double distc = functor.symmetric(mesh1, mesh2); + assert(distc == naive); + std::cout << "* Hausdorff distance (expected 1.22): " << dista << std::endl; std::cout << "* HInverted distance (expected 1.22): " << distb << std::endl; + std::cout << "* Symmetric distance (expected 1.22): " << distc << std::endl; } template @@ -253,8 +291,13 @@ void test_5(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); + const double naive = (CGAL::max)(dista, distb); + const double distc = functor.symmetric(mesh1, mesh2); + assert(distc == naive); + std::cout << "* Hausdorff distance (expected 1.73): " << dista << std::endl; std::cout << "* HInverted distance (expected 2.12): " << distb << std::endl; + std::cout << "* Symmetric distance (expected 2.12): " << distc << std::endl; } template @@ -288,8 +331,13 @@ void test_6(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); + const double naive = (CGAL::max)(dista, distb); + const double distc = functor.symmetric(mesh1, mesh2); + assert(distc == naive); + std::cout << "* Hausdorff distance (expected 0.0): " << dista << std::endl; std::cout << "* HInverted distance (expected 0.7): " << distb << std::endl; + std::cout << "* Symmetric distance (expected 0.7): " << distc << std::endl; } template @@ -323,8 +371,13 @@ void test_7(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); + const double naive = (CGAL::max)(dista, distb); + const double distc = functor.symmetric(mesh1, mesh2); + assert(distc == naive); + std::cout << "* Hausdorff distance (expected 0.50): " << dista << std::endl; std::cout << "* HInverted distance (expected 0.86): " << distb << std::endl; + std::cout << "* Symmetric distance (expected 0.86): " << distc << std::endl; } template @@ -358,8 +411,13 @@ void test_8(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); + const double naive = (CGAL::max)(dista, distb); + const double distc = functor.symmetric(mesh1, mesh2); + assert(distc == naive); + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; std::cout << "* HInverted distance (expected 2): " << distb << std::endl; + std::cout << "* Symmetric distance (expected 2): " << distc << std::endl; } template @@ -400,8 +458,13 @@ void test_9(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); + const double naive = (CGAL::max)(dista, distb); + const double distc = functor.symmetric(mesh1, mesh2); + assert(distc == naive); + std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; std::cout << "* HInverted distance (expected 1): " << distb << std::endl; + std::cout << "* Symmetric distance (expected 1): " << distc << std::endl; } template From 9afa43dad09cf9c39fc2134623e7278ed6894abe Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 30 Apr 2021 15:02:27 +0200 Subject: [PATCH 183/349] propagate lower bound for culling on TM1 to accelerate symmetric distance --- .../include/CGAL/Polygon_mesh_processing/distance.h | 9 +++++++-- .../AABB_traversal_traits_with_Hausdorff_distance.h | 11 +++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index c0f8e41377d..b4a8df3ffb7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1440,6 +1440,7 @@ double bounded_error_Hausdorff_impl( const VPM1& vpm1, const VPM2& vpm2, const typename Kernel::FT infinity_value, + const typename Kernel::FT initial_lower_bound, TM1Tree& tm1_tree, TM2Tree& tm2_tree) { @@ -1470,7 +1471,8 @@ double bounded_error_Hausdorff_impl( // Build traversal traits for tm1_tree. TM1_hd_traits traversal_traits_tm1( - tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, error_bound, infinity_value); + tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, + error_bound, infinity_value, initial_lower_bound); // Find candidate triangles in TM1, which might realise the Hausdorff bound. // We build a sorted structure while collecting the candidates. @@ -1686,8 +1688,11 @@ double bounded_error_one_sided_Hausdorff_impl( // std::cout << "* culling rate: 100%" << std::endl; return 0.0; // TM1 is part of TM2 so the distance is zero } + + const FT initial_lower_bound = error_bound; return bounded_error_Hausdorff_impl( - tm1, tm2, error_bound, vpm1, vpm2, infinity_value, tm1_tree, tm2_tree); + tm1, tm2, error_bound, vpm1, vpm2, + infinity_value, initial_lower_bound, tm1_tree, tm2_tree); } template< class Concurrency_tag, diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 0a97201ff6e..1e8626f1148 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -305,7 +305,8 @@ namespace CGAL { const TriangleMesh1& tm1, const TriangleMesh2& tm2, const VPM1& vpm1, const VPM2& vpm2, const FT error_bound, - const FT infinity_value) : + const FT infinity_value, + const FT initial_lower_bound) : m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2), @@ -317,10 +318,12 @@ namespace CGAL { // Initialize the global bounds with 0, they will only grow. // If we leave zero here, then we are very slow even for big input error bounds! - // The error_bound here makes the code faster for close meshes. + // Instead, we can use m_error_bound as our initial guess to filter out all pairs, + // which are already within this bound. It makes the code faster for close meshes. + // We also use initial_lower_bound here to accelerate the symmetric distance computation. CGAL_assertion(m_error_bound >= FT(0)); - h_global_bounds.lower = m_error_bound; // = FT(0); - h_global_bounds.upper = m_error_bound; // = FT(0); + h_global_bounds.lower = initial_lower_bound; // = FT(0); + h_global_bounds.upper = m_error_bound; // = FT(0); } // Explore the whole tree, i.e. always enter children if the methods From f158e3e5ebec1b1be76c46183d61e5bf5cfe42d5 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 30 Apr 2021 16:14:19 +0200 Subject: [PATCH 184/349] added symmetric distance, it is approx 2 times faster than naive version --- .../CGAL/Polygon_mesh_processing/distance.h | 94 +++++++++++++++++-- ...traversal_traits_with_Hausdorff_distance.h | 5 +- .../test_hausdorff_bounded_error_distance.cpp | 60 ++++++++---- 3 files changed, 134 insertions(+), 25 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index b4a8df3ffb7..0c86c2993b3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1398,17 +1398,22 @@ std::pair preprocess_bounded_error_Hausdorff_impl( if (tm1_only.size() == 0 && tm2_only.size() == 0) { // do not create trees infinity_value = -FT(1); + } else if (common.size() == 0) { // create full TM1 and TM2 + tm1_tree.insert(faces1.begin(), faces1.end(), tm1, vpm1); + tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); } else if (tm1_only.size() == 0) { // create TM2 and full TM1 CGAL_assertion(tm2_only.size() > 0); + CGAL_assertion(tm2_only.size() < faces2.size()); tm1_tree.insert(faces1.begin(), faces1.end(), tm1, vpm1); tm2_tree.insert(tm2_only.begin(), tm2_only.end(), tm2, vpm2); } else if (tm2_only.size() == 0) { // create TM1 and full TM2 CGAL_assertion(tm1_only.size() > 0); + CGAL_assertion(tm1_only.size() < faces1.size()); tm1_tree.insert(tm1_only.begin(), tm1_only.end(), tm1, vpm1); tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); } else { // create TM1 and full TM2 and set tag to rebuild them later CGAL_assertion(tm1_only.size() > 0); - CGAL_assertion(tm2_only.size() > 0); + CGAL_assertion(tm1_only.size() < faces1.size()); tm1_tree.insert(tm1_only.begin(), tm1_only.end(), tm1, vpm1); tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); rebuild = true; @@ -1462,7 +1467,11 @@ double bounded_error_Hausdorff_impl( using Candidate = Candidate_triangle; using Timer = CGAL::Real_timer; + std::cout.precision(20); + CGAL_precondition(error_bound >= FT(0)); + CGAL_precondition(tm1_tree.size() > 0); + CGAL_precondition(tm2_tree.size() > 0); // First, we apply culling. @@ -1540,7 +1549,7 @@ double bounded_error_Hausdorff_impl( // The upper bound of this triangle is the actual Hausdorff distance of // the triangle to the second mesh. Use it as new global lower bound. - // TODO: Update the reference to the realizing triangle here as this is the best current guess. + // TODO: update the reference to the realizing triangle here as this is the best current guess. global_bounds.lower = triangle_bounds.upper; global_bounds.lpair.second = triangle_bounds.tm2_uface; continue; @@ -1688,6 +1697,7 @@ double bounded_error_one_sided_Hausdorff_impl( // std::cout << "* culling rate: 100%" << std::endl; return 0.0; // TM1 is part of TM2 so the distance is zero } + CGAL_assertion(infinity_value > FT(0)); const FT initial_lower_bound = error_bound; return bounded_error_Hausdorff_impl( @@ -1712,13 +1722,81 @@ double bounded_error_symmetric_Hausdorff_impl( const NamedParameters2& np2) { // Naive version. - const double hdist1 = bounded_error_one_sided_Hausdorff_impl( - tm1, tm2, error_bound, compare_meshes, vpm1, vpm2, np1, np2); - const double hdist2 = bounded_error_one_sided_Hausdorff_impl( - tm2, tm1, error_bound, compare_meshes, vpm2, vpm1, np2, np1); - return (CGAL::max)(hdist1, hdist2); + // const double hdist1 = bounded_error_one_sided_Hausdorff_impl( + // tm1, tm2, error_bound, compare_meshes, vpm1, vpm2, np1, np2); + // const double hdist2 = bounded_error_one_sided_Hausdorff_impl( + // tm2, tm1, error_bound, compare_meshes, vpm2, vpm1, np2, np1); + // return (CGAL::max)(hdist1, hdist2); - // return -1.0; + // Optimized version. + // -- We compare meshes only if it is required. + // -- We first build trees and rebuild them only if it is required. + // -- We provide better initial lower bound in the second call to the Hausdorff distance. + using FT = typename Kernel::FT; + + using TM1_primitive = AABB_face_graph_triangle_primitive; + using TM2_primitive = AABB_face_graph_triangle_primitive; + + using TM1_traits = AABB_traits; + using TM2_traits = AABB_traits; + + using TM1_tree = AABB_tree; + using TM2_tree = AABB_tree; + + using Face_handle_1 = typename boost::graph_traits::face_descriptor; + using Face_handle_2 = typename boost::graph_traits::face_descriptor; + + std::cout.precision(20); + std::vector tm1_only; + std::vector tm2_only; + + TM1_tree tm1_tree; + TM2_tree tm2_tree; + FT infinity_value = -FT(1); + bool rebuild = false; + std::tie(infinity_value, rebuild) = preprocess_bounded_error_Hausdorff_impl( + tm1, tm2, compare_meshes, vpm1, vpm2, np1, np2, false, tm1_tree, tm2_tree, tm1_only, tm2_only); + + if (infinity_value < FT(0)) { + // std::cout << "* culling rate: 100%" << std::endl; + return 0.0; // TM1 and TM2 are equal so the distance is zero + } + CGAL_assertion(infinity_value > FT(0)); + + // Compute the first one-sided distance. + FT initial_lower_bound = error_bound; + double dista = CGAL::to_double(error_bound); + + if (!compare_meshes || (compare_meshes && tm1_only.size() > 0)) { + dista = bounded_error_Hausdorff_impl( + tm1, tm2, error_bound, vpm1, vpm2, + infinity_value, initial_lower_bound, tm1_tree, tm2_tree); + } + + // In case this is true, we need to rebuild trees in order to accelerate + // computations for the second call. + if (rebuild) { + CGAL_assertion(compare_meshes); + tm1_tree.clear(); + tm2_tree.clear(); + CGAL_assertion(tm2_only.size() > 0); + CGAL_assertion(tm2_only.size() < faces(tm2).size()); + tm1_tree.insert(faces(tm1).begin(), faces(tm1).end(), tm1, vpm1); + tm2_tree.insert(tm2_only.begin(), tm2_only.end(), tm2, vpm2); + } + + // Compute the second one-sided distance. + initial_lower_bound = static_cast(dista); // TODO: we should better test this optimization! + double distb = CGAL::to_double(error_bound); + + if (!compare_meshes || (compare_meshes && tm2_only.size() > 0)) { + distb = bounded_error_Hausdorff_impl( + tm2, tm1, error_bound, vpm2, vpm1, + infinity_value, initial_lower_bound, tm2_tree, tm1_tree); + } + + // Return the maximum. + return (CGAL::max)(dista, distb); } template = FT(0)); + CGAL_precondition(m_infinity_value > FT(0)); + CGAL_precondition(initial_lower_bound >= m_error_bound); + // Initialize the global bounds with 0, they will only grow. // If we leave zero here, then we are very slow even for big input error bounds! // Instead, we can use m_error_bound as our initial guess to filter out all pairs, // which are already within this bound. It makes the code faster for close meshes. // We also use initial_lower_bound here to accelerate the symmetric distance computation. - CGAL_assertion(m_error_bound >= FT(0)); h_global_bounds.lower = initial_lower_bound; // = FT(0); h_global_bounds.upper = m_error_bound; // = FT(0); } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 6e7c0f9181c..4343784b9cf 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -574,21 +574,56 @@ void test_timings(const std::string filepath, const FunctionWrapper& functor) { timer.reset(); timer.start(); - const double dista = functor(mesh1, mesh2); + const double dista1 = functor(mesh1, mesh2); timer.stop(); - std::cout << "* time 0 (sec.): " << timer.time() << std::endl; + double timea = timer.time(); + + timer.reset(); + timer.start(); + const double distb1 = functor(mesh2, mesh1); + timer.stop(); + double timeb = timer.time(); + + timer.reset(); + timer.start(); + const double distc1 = functor.symmetric(mesh1, mesh2); + timer.stop(); + double timeab = timer.time(); + + std::cout << "* time a1 (sec.): " << timea << std::endl; + std::cout << "* time b1 (sec.): " << timeb << std::endl; + std::cout << "* time ab1 naive (sec.): " << timea + timeb << std::endl; + std::cout << "* time ab1 optimized (sec.): " << timeab << std::endl; PMP::transform(Affine_transformation_3(CGAL::Translation(), Vector_3(FT(0), FT(0), FT(1))), mesh2); timer.reset(); timer.start(); - const double distb = functor(mesh1, mesh2); + const double dista2 = functor(mesh1, mesh2); timer.stop(); - std::cout << "* time 1 (sec.): " << timer.time() << std::endl; + timea = timer.time(); - std::cout << "* dista = " << dista << std::endl; - std::cout << "* distb = " << distb << std::endl; + timer.reset(); + timer.start(); + const double distb2 = functor(mesh2, mesh1); + timer.stop(); + timeb = timer.time(); + + timer.reset(); + timer.start(); + const double distc2 = functor.symmetric(mesh1, mesh2); + timer.stop(); + timeab = timer.time(); + + std::cout << "* time a2 (sec.): " << timea << std::endl; + std::cout << "* time b2 (sec.): " << timeb << std::endl; + std::cout << "* time ab2 naive (sec.): " << timea + timeb << std::endl; + std::cout << "* time ab2 optimized (sec.): " << timeab << std::endl; + + std::cout << "* dista = " << dista1 << " , " << dista2 << std::endl; + std::cout << "* distb = " << distb1 << " , " << distb2 << std::endl; + std::cout << "* distab = " << distc1 << " , " << distc2 << std::endl; } template @@ -802,20 +837,17 @@ int main(int argc, char** argv) { Naive_bounded_error_hd_wrapper naive_hd(error_bound); Bounded_error_hd_wrapper bound_hd(error_bound); - // --- Testing basic properties. // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); test_synthetic_data(bound_hd); - // --- Compare on common meshes. // test_one_versus_another(apprx_hd, naive_hd); // test_one_versus_another(naive_hd, bound_hd); - test_one_versus_another(bound_hd, apprx_hd); - + // test_one_versus_another(bound_hd, apprx_hd); // --- Compare on real meshes. @@ -824,8 +856,7 @@ int main(int argc, char** argv) { // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); - test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); - + // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); // --- Compare timings. @@ -835,18 +866,15 @@ int main(int argc, char** argv) { // test_timings(filepath, naive_hd); test_timings(filepath, bound_hd); - // --- Compare with the paper. // test_bunny(apprx_hd); // test_bunny(naive_hd); - test_bunny(bound_hd, 3); - + // test_bunny(bound_hd, 3); // --- Test realizing triangles. // test_realizing_triangles(error_bound); - // ------------------------------------------------------------------------ // std::cout << std::endl; From 482bc457e45277bf672d70befc086bce5fe318ed Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 30 Apr 2021 17:16:15 +0200 Subject: [PATCH 185/349] added test for parallel version + METIS partition of tm1 and partially filtered face graph --- .../Polygon_mesh_processing/CMakeLists.txt | 8 + .../test_hausdorff_bounded_error_distance.cpp | 143 +++++++++++++++++- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index 38cdf1f1adc..ee7be943420 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -109,6 +109,14 @@ create_single_source_cgal_program("triangulate_hole_with_cdt_2_test.cpp") create_single_source_cgal_program("test_pmp_polyhedral_envelope.cpp") # create_single_source_cgal_program("test_pmp_repair_self_intersections.cpp") +find_package(METIS) +include(CGAL_METIS_support) +if(TARGET CGAL::METIS_support) + target_link_libraries(test_hausdorff_bounded_error_distance PUBLIC CGAL::METIS_support) +else() + message(STATUS "Tests, which use the METIS library will not be compiled.") +endif() + if(TARGET CGAL::TBB_support) target_link_libraries(test_hausdorff_bounded_error_distance PUBLIC CGAL::TBB_support) target_link_libraries(test_pmp_distance PUBLIC CGAL::TBB_support) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 4343784b9cf..438659e329f 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -13,6 +13,9 @@ #include #include +#include // METIS related +#include + using SCK = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; @@ -818,6 +821,141 @@ void test_realizing_triangles( compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); } +// TODO: in case we keep it, put this test and all METIS-related stuff in a separate +// file or exclude it from this test suite if METIS is unavailable! +double bounded_error_Hausdorff_distance_parallel( + const Surface_mesh& tm1, const Surface_mesh& /* tm2 */, + const double /* error_bound */, const int nb_cores = 4) { + + Timer timer; + + // (1) -- Create partition of tm1. + std::cout << "* computing partition ... " << std::endl; + + timer.reset(); + timer.start(); + using Face_property_tag = CGAL::dynamic_face_property_t; + auto partition_id_map = get(Face_property_tag(), tm1); + + // Set some custom options for METIS. + idx_t options[METIS_NOPTIONS]; + + // Set all options to default ahead of manually editing some values. + METIS_SetDefaultOptions(options); + + // See METIS documentation for details on these options. + options[METIS_OPTION_PTYPE] = METIS_PTYPE_KWAY; + options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL; + options[METIS_OPTION_CTYPE] = METIS_CTYPE_SHEM; + options[METIS_OPTION_NCUTS] = 3; + options[METIS_OPTION_NITER] = 10; + options[METIS_OPTION_SEED] = 12345; + options[METIS_OPTION_MINCONN] = 1; + options[METIS_OPTION_CONTIG] = 1; + options[METIS_OPTION_UFACTOR] = 25; + + // Partition the mesh and output its parts. + CGAL::METIS::partition_graph( + tm1, nb_cores, CGAL::parameters:: + face_partition_id_map(partition_id_map). + METIS_options(&options)); + + int max_id = 0; + for (const auto& face : faces(tm1)) { + const auto id = get(partition_id_map, face); + max_id = (CGAL::max)(max_id, id); + } + assert(nb_cores == (max_id + 1)); + timer.stop(); + const double time1 = timer.time(); + std::cout << " ... done in " << time1 << " sec." << std::endl; + std::cout << "* number of detected parts: " << max_id + 1 << std::endl; + + // (2) -- Create a face filtered graph for each part. + std::cout << "* creating graphs ... " << std::endl; + + timer.reset(); + timer.start(); + + std::vector graphs(nb_cores); + using Filtered_graph = CGAL::Face_filtered_graph; + + Filtered_graph graph(tm1, 0 /* id of the part */, partition_id_map); + CGAL_assertion(graph.is_selection_valid()); + Surface_mesh part_sm; + CGAL::copy_face_graph(graph, graphs[0]); // TODO: do not copy in the future + // finish + + timer.stop(); + const double time2 = timer.time(); + std::cout << " ... done in " << time2 << " sec." << std::endl; + + // (3) -- Run all parts in parallel. + std::cout << "* computing distance for all graphs in parallel ... " << std::endl; + + timer.reset(); + timer.start(); + std::vector all_dists(nb_cores, -1.0); + // todo + timer.stop(); + const double time3 = timer.time(); + std::cout << " ... done in " << time3 << " sec." << std::endl; + + // (4) -- Find the max distance among the given distances. + std::cout << "* computing the final distance ... " << std::endl; + + timer.reset(); + timer.start(); + double hdist = -1.0; + assert(all_dists.size() == static_cast(nb_cores)); + for (int i = 0; i < nb_cores; ++i) { + hdist = (CGAL::max)(hdist, all_dists[i]); + } + assert(hdist >= 0.0); + timer.stop(); + const double time4 = timer.time(); + std::cout << " ... done in " << time4 << " sec." << std::endl; + + return hdist; +} + +void test_parallel_version( + const std::string filepath, const double error_bound) { + + std::cout.precision(20); + std::cout << std::endl << "-- test parallel version:" << std::endl << std::endl; + + Timer timer; + Surface_mesh mesh1, mesh2; + get_meshes(filepath, filepath, mesh1, mesh2); + + // One-sided distance. + std::cout << " ---- one-sided distance ---- " << std::endl; + + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(FT(0), FT(0), FT(1))), mesh2); + + timer.reset(); + timer.start(); + const double dista = PMP::bounded_error_Hausdorff_distance( + mesh1, mesh2, error_bound); + timer.stop(); + const double timea = timer.time(); + + timer.reset(); + timer.start(); + const double distb = bounded_error_Hausdorff_distance_parallel( + mesh1, mesh2, error_bound); + timer.stop(); + const double timeb = timer.time(); + + std::cout << "* time a (sec.): " << timea << std::endl; + std::cout << "* time b (sec.): " << timeb << std::endl; + + std::cout << "* dista = " << dista << std::endl; + std::cout << "* distb = " << distb << std::endl; +} + int main(int argc, char** argv) { // std::string name; @@ -864,7 +1002,7 @@ int main(int argc, char** argv) { // filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); - test_timings(filepath, bound_hd); + // test_timings(filepath, bound_hd); // --- Compare with the paper. @@ -875,6 +1013,9 @@ int main(int argc, char** argv) { // --- Test realizing triangles. // test_realizing_triangles(error_bound); + // --- Test parallelization. + // test_parallel_version(filepath, error_bound); + // ------------------------------------------------------------------------ // std::cout << std::endl; From 887a715a2619fe159b9671c45a60be3354c931fa Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 3 May 2021 14:22:14 +0200 Subject: [PATCH 186/349] added naive parallel version --- .../test_hausdorff_bounded_error_distance.cpp | 154 +++++++++++------- 1 file changed, 97 insertions(+), 57 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 438659e329f..1ce1aa7a12b 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -26,12 +26,14 @@ using Point_3 = typename Kernel::Point_3; using Vector_3 = typename Kernel::Vector_3; using Triangle_3 = typename Kernel::Triangle_3; -using TAG = CGAL::Parallel_if_available_tag; +using TAG = CGAL::Parallel_tag; using Surface_mesh = CGAL::Surface_mesh; using Affine_transformation_3 = CGAL::Aff_transformation_3; using Timer = CGAL::Real_timer; using Face_handle = typename boost::graph_traits::face_descriptor; +using Face_index = typename Surface_mesh::Face_index; + namespace PMP = CGAL::Polygon_mesh_processing; struct Approximate_hd_wrapper { @@ -821,11 +823,59 @@ void test_realizing_triangles( compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); } +#if defined(CGAL_LINKED_WITH_TBB) +template +struct Bounded_error_distance_computation { + + const std::vector& tm1_parts; + const TriangleMesh2& tm2; + const double error_bound; + double distance; + + // Constructor. + Bounded_error_distance_computation( + const std::vector& tm1_parts, + const TriangleMesh2& tm2, + const double error_bound) : + tm1_parts(tm1_parts), tm2(tm2), + error_bound(error_bound), distance(-1.0) + { } + + // Split constructor. + Bounded_error_distance_computation( + Bounded_error_distance_computation& s, tbb::split) : + tm1_parts(s.tm1_parts), tm2(s.tm2), + error_bound(s.error_bound), distance(-1.0) + { } + + void operator()(const tbb::blocked_range& range) { + + // std::cout << "* range size: " << range.size() << std::endl; + double hdist = 0.0; + for (std::size_t i = range.begin(); i != range.end(); ++i) { + CGAL_assertion(i < tm1_parts.size()); + const auto& tm1 = tm1_parts[i]; + // std::cout << "part size: " << tm1.number_of_faces() << std::endl; + const double dist = PMP::bounded_error_Hausdorff_distance( + tm1, tm2, error_bound, + CGAL::parameters::match_faces(false), + CGAL::parameters::match_faces(false)); + if (dist > hdist) hdist = dist; + } + if (hdist > distance) distance = hdist; + } + + void join(Bounded_error_distance_computation& rhs) { + distance = (CGAL::max)(rhs.distance, distance); + } +}; +#endif + // TODO: in case we keep it, put this test and all METIS-related stuff in a separate // file or exclude it from this test suite if METIS is unavailable! double bounded_error_Hausdorff_distance_parallel( - const Surface_mesh& tm1, const Surface_mesh& /* tm2 */, - const double /* error_bound */, const int nb_cores = 4) { + Surface_mesh& tm1, const Surface_mesh& tm2, + const double error_bound, const int nb_cores = 4) { Timer timer; @@ -834,35 +884,16 @@ double bounded_error_Hausdorff_distance_parallel( timer.reset(); timer.start(); - using Face_property_tag = CGAL::dynamic_face_property_t; - auto partition_id_map = get(Face_property_tag(), tm1); - - // Set some custom options for METIS. - idx_t options[METIS_NOPTIONS]; - - // Set all options to default ahead of manually editing some values. - METIS_SetDefaultOptions(options); - - // See METIS documentation for details on these options. - options[METIS_OPTION_PTYPE] = METIS_PTYPE_KWAY; - options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL; - options[METIS_OPTION_CTYPE] = METIS_CTYPE_SHEM; - options[METIS_OPTION_NCUTS] = 3; - options[METIS_OPTION_NITER] = 10; - options[METIS_OPTION_SEED] = 12345; - options[METIS_OPTION_MINCONN] = 1; - options[METIS_OPTION_CONTIG] = 1; - options[METIS_OPTION_UFACTOR] = 25; // Partition the mesh and output its parts. + auto face_pid_map = tm1.add_property_map("f:pid").first; CGAL::METIS::partition_graph( tm1, nb_cores, CGAL::parameters:: - face_partition_id_map(partition_id_map). - METIS_options(&options)); + face_partition_id_map(face_pid_map)); int max_id = 0; for (const auto& face : faces(tm1)) { - const auto id = get(partition_id_map, face); + const int id = static_cast(get(face_pid_map, face)); max_id = (CGAL::max)(max_id, id); } assert(nb_cores == (max_id + 1)); @@ -877,14 +908,15 @@ double bounded_error_Hausdorff_distance_parallel( timer.reset(); timer.start(); - std::vector graphs(nb_cores); using Filtered_graph = CGAL::Face_filtered_graph; - - Filtered_graph graph(tm1, 0 /* id of the part */, partition_id_map); - CGAL_assertion(graph.is_selection_valid()); - Surface_mesh part_sm; - CGAL::copy_face_graph(graph, graphs[0]); // TODO: do not copy in the future - // finish + std::vector tm1_parts(nb_cores); + for (int i = 0; i < nb_cores; ++i) { + // std::cout << "selection " << i << std::endl; + Filtered_graph tm1_part(tm1, i, face_pid_map); + CGAL_assertion(tm1_part.is_selection_valid()); + CGAL::copy_face_graph(tm1_part, tm1_parts[i]); // TODO: do not copy in the future + std::cout << "part " << i << " size: " << tm1_parts[i].number_of_faces() << std::endl; + } timer.stop(); const double time2 = timer.time(); @@ -895,27 +927,33 @@ double bounded_error_Hausdorff_distance_parallel( timer.reset(); timer.start(); - std::vector all_dists(nb_cores, -1.0); - // todo + + std::atomic hdist; + #if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg( + !(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); + hdist = -1.0; + #else + if (boost::is_convertible::value) { + std::cout << "* executing parallel version " << std::endl; + Bounded_error_distance_computation f( + tm1_parts, tm2, error_bound); + tbb::parallel_reduce(tbb::blocked_range(0, tm1_parts.size()), f); + hdist = f.distance; + } else + #endif + { + std::cout << "* executing sequential version " << std::endl; + hdist = PMP::bounded_error_Hausdorff_distance( + tm1, tm2, error_bound, + CGAL::parameters::match_faces(false), + CGAL::parameters::match_faces(false)); + } + timer.stop(); const double time3 = timer.time(); std::cout << " ... done in " << time3 << " sec." << std::endl; - - // (4) -- Find the max distance among the given distances. - std::cout << "* computing the final distance ... " << std::endl; - - timer.reset(); - timer.start(); - double hdist = -1.0; - assert(all_dists.size() == static_cast(nb_cores)); - for (int i = 0; i < nb_cores; ++i) { - hdist = (CGAL::max)(hdist, all_dists[i]); - } - assert(hdist >= 0.0); - timer.stop(); - const double time4 = timer.time(); - std::cout << " ... done in " << time4 << " sec." << std::endl; - return hdist; } @@ -938,7 +976,9 @@ void test_parallel_version( timer.reset(); timer.start(); const double dista = PMP::bounded_error_Hausdorff_distance( - mesh1, mesh2, error_bound); + mesh1, mesh2, error_bound, + CGAL::parameters::match_faces(false), + CGAL::parameters::match_faces(false)); timer.stop(); const double timea = timer.time(); @@ -949,11 +989,11 @@ void test_parallel_version( timer.stop(); const double timeb = timer.time(); - std::cout << "* time a (sec.): " << timea << std::endl; - std::cout << "* time b (sec.): " << timeb << std::endl; + std::cout << "* time a seq (sec.): " << timea << std::endl; + std::cout << "* time b par (sec.): " << timeb << std::endl; - std::cout << "* dista = " << dista << std::endl; - std::cout << "* distb = " << distb << std::endl; + std::cout << "* dista seq = " << dista << std::endl; + std::cout << "* distb par = " << distb << std::endl; } int main(int argc, char** argv) { @@ -979,7 +1019,7 @@ int main(int argc, char** argv) { // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); - test_synthetic_data(bound_hd); + // test_synthetic_data(bound_hd); // --- Compare on common meshes. @@ -1014,7 +1054,7 @@ int main(int argc, char** argv) { // test_realizing_triangles(error_bound); // --- Test parallelization. - // test_parallel_version(filepath, error_bound); + test_parallel_version(filepath, error_bound); // ------------------------------------------------------------------------ // From bafc127499ed6849a41f051bf90deefacdffd7b3 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 3 May 2021 14:53:04 +0200 Subject: [PATCH 187/349] cout a few more timings for parallel version --- .../test_hausdorff_bounded_error_distance.cpp | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 1ce1aa7a12b..21c8026d4c3 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -850,19 +850,26 @@ struct Bounded_error_distance_computation { void operator()(const tbb::blocked_range& range) { + Timer timer; + timer.reset(); + timer.start(); + // std::cout << "* range size: " << range.size() << std::endl; double hdist = 0.0; for (std::size_t i = range.begin(); i != range.end(); ++i) { CGAL_assertion(i < tm1_parts.size()); const auto& tm1 = tm1_parts[i]; // std::cout << "part size: " << tm1.number_of_faces() << std::endl; - const double dist = PMP::bounded_error_Hausdorff_distance( + const double dist = PMP::bounded_error_Hausdorff_distance( tm1, tm2, error_bound, CGAL::parameters::match_faces(false), CGAL::parameters::match_faces(false)); if (dist > hdist) hdist = dist; } if (hdist > distance) distance = hdist; + + timer.stop(); + std::cout << "* time operator() (sec.): " << timer.time() << std::endl; } void join(Bounded_error_distance_computation& rhs) { @@ -954,6 +961,18 @@ double bounded_error_Hausdorff_distance_parallel( timer.stop(); const double time3 = timer.time(); std::cout << " ... done in " << time3 << " sec." << std::endl; + + for (const auto& tm1_part : tm1_parts) { + timer.reset(); + timer.start(); + hdist = PMP::bounded_error_Hausdorff_distance( + tm1_part, tm2, error_bound, + CGAL::parameters::match_faces(false), + CGAL::parameters::match_faces(false)); + timer.stop(); + std::cout << "* manual call seq. time (sec.): " << timer.time() << std::endl; + } + return hdist; } @@ -1038,8 +1057,8 @@ int main(int argc, char** argv) { // --- Compare timings. - filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); - // filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; + // filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); + filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); // test_timings(filepath, bound_hd); From b31201294b184cdcd1d78af2513d8437106b3430 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 3 May 2021 15:46:12 +0200 Subject: [PATCH 188/349] cleanup --- .../CGAL/Polygon_mesh_processing/distance.h | 3 +++ .../test_hausdorff_bounded_error_distance.cpp | 26 +++++++++---------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 0c86c2993b3..b5d8501f3b3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1424,6 +1424,9 @@ std::pair preprocess_bounded_error_Hausdorff_impl( tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); } + // tm1_tree.build(); + // tm2_tree.build(); + timer.stop(); // std::cout << "* .... end preprocessing" << std::endl; // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 21c8026d4c3..ff85429b350 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -869,7 +869,7 @@ struct Bounded_error_distance_computation { if (hdist > distance) distance = hdist; timer.stop(); - std::cout << "* time operator() (sec.): " << timer.time() << std::endl; + // std::cout << "* time operator() (sec.): " << timer.time() << std::endl; } void join(Bounded_error_distance_computation& rhs) { @@ -962,16 +962,16 @@ double bounded_error_Hausdorff_distance_parallel( const double time3 = timer.time(); std::cout << " ... done in " << time3 << " sec." << std::endl; - for (const auto& tm1_part : tm1_parts) { - timer.reset(); - timer.start(); - hdist = PMP::bounded_error_Hausdorff_distance( - tm1_part, tm2, error_bound, - CGAL::parameters::match_faces(false), - CGAL::parameters::match_faces(false)); - timer.stop(); - std::cout << "* manual call seq. time (sec.): " << timer.time() << std::endl; - } + // for (const auto& tm1_part : tm1_parts) { + // timer.reset(); + // timer.start(); + // hdist = PMP::bounded_error_Hausdorff_distance( + // tm1_part, tm2, error_bound, + // CGAL::parameters::match_faces(false), + // CGAL::parameters::match_faces(false)); + // timer.stop(); + // std::cout << "* manual call seq. time (sec.): " << timer.time() << std::endl; + // } return hdist; } @@ -1057,8 +1057,8 @@ int main(int argc, char** argv) { // --- Compare timings. - // filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); - filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; + filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); + // filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); // test_timings(filepath, bound_hd); From 74f5d8af05996b5e04740149c1fc113212c85e33 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 3 May 2021 18:17:41 +0200 Subject: [PATCH 189/349] added one-sided parallel hausdorff distance, still with the seg fault --- .../CGAL/Polygon_mesh_processing/distance.h | 327 +++++++++++++++--- .../test_hausdorff_bounded_error_distance.cpp | 17 +- 2 files changed, 285 insertions(+), 59 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index b5d8501f3b3..a5fbf0d56d6 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -35,6 +35,8 @@ #include #include #include +#include // METIS related +#include #endif // CGAL_LINKED_WITH_TBB #include @@ -1323,8 +1325,6 @@ template< class Kernel, class TriangleMesh2, class VPM1, class VPM2, - class NamedParameters1, - class NamedParameters2, class TM1Tree, class TM2Tree, class FaceHandle1, @@ -1335,8 +1335,6 @@ std::pair preprocess_bounded_error_Hausdorff_impl( const bool compare_meshes, const VPM1& vpm1, const VPM2& vpm2, - const NamedParameters1& np1, - const NamedParameters2& np2, const bool is_one_sided_distance, TM1Tree& tm1_tree, TM2Tree& tm2_tree, @@ -1378,7 +1376,7 @@ std::pair preprocess_bounded_error_Hausdorff_impl( bool rebuild = false; if (compare_meshes) { // exact check match_faces(tm1, tm2, std::back_inserter(common), - std::back_inserter(tm1_only), std::back_inserter(tm2_only), np1, np2); + std::back_inserter(tm1_only), std::back_inserter(tm2_only)); // std::cout << "- common: " << common.size() << std::endl; // std::cout << "- tm1 only: " << tm1_only.size() << std::endl; @@ -1652,23 +1650,162 @@ double bounded_error_Hausdorff_impl( return hdist; } +#if defined(CGAL_LINKED_WITH_TBB) // TODO: && METIS! + +template< class TriangleMesh1, + class TriangleMesh2, + class VPM1, + class VPM2, + class TM1Tree, + class TM2Tree, + class Kernel> +struct Bounded_error_preprocessing { + + using FT = typename Kernel::FT; + using Timer = CGAL::Real_timer; + + using Face_handle_1 = typename boost::graph_traits::face_descriptor; + using Face_handle_2 = typename boost::graph_traits::face_descriptor; + + const std::vector& tm1_parts; const TriangleMesh2& tm2; + const bool compare_meshes; const VPM1& vpm1; const VPM2& vpm2; + const bool is_one_sided_distance; + std::vector& tm1_trees; TM2Tree& tm2_tree; + FT infinity_value; + + // Constructor. + Bounded_error_preprocessing( + const std::vector& tm1_parts, const TriangleMesh2& tm2, + const bool compare_meshes, const VPM1& vpm1, const VPM2& vpm2, + const bool is_one_sided_distance, + std::vector& tm1_trees, TM2Tree& tm2_tree) : + tm1_parts(tm1_parts), tm2(tm2), + compare_meshes(compare_meshes), vpm1(vpm1), vpm2(vpm2), + is_one_sided_distance(is_one_sided_distance), + tm1_trees(tm1_trees), tm2_tree(tm2_tree), + infinity_value(-FT(1)) + { } + + // Split constructor. + Bounded_error_preprocessing( + Bounded_error_preprocessing& s, tbb::split) : + tm1_parts(s.tm1_parts), tm2(s.tm2), + compare_meshes(s.compare_meshes), vpm1(s.vpm1), vpm2(s.vpm2), + is_one_sided_distance(s.is_one_sided_distance), + tm1_trees(s.tm1_trees), tm2_tree(s.tm2_tree), + infinity_value(s.infinity_value) + { } + + void operator()(const tbb::blocked_range& range) { + + FT inf_value = -FT(1); + std::vector tm1_only; + std::vector tm2_only; + CGAL_assertion(tm1_parts.size() == tm1_trees.size()); + + Timer timer; + timer.reset(); + timer.start(); + FT max_inf_value = -FT(1); + for (std::size_t i = range.begin(); i != range.end(); ++i) { + CGAL_assertion(i < tm1_parts.size()); + CGAL_assertion(i < tm1_trees.size()); + tm2_tree.clear(); + inf_value = preprocess_bounded_error_Hausdorff_impl( + tm1_parts[i], tm2, compare_meshes, vpm1, vpm2, is_one_sided_distance, + tm1_trees[i], tm2_tree, tm1_only, tm2_only).first; + if (inf_value > max_inf_value) max_inf_value = inf_value; + } + if (max_inf_value > infinity_value) infinity_value = max_inf_value; + timer.stop(); + // std::cout << "* time operator() preprocessing (sec.): " << timer.time() << std::endl; + } + + void join(Bounded_error_preprocessing& rhs) { + infinity_value = (CGAL::max)(rhs.infinity_value, infinity_value); + } +}; + +template< class TriangleMesh1, + class TriangleMesh2, + class VPM1, + class VPM2, + class TM1Tree, + class TM2Tree, + class Kernel> +struct Bounded_error_distance_computation { + + using FT = typename Kernel::FT; + using Timer = CGAL::Real_timer; + + const std::vector& tm1_parts; const TriangleMesh2& tm2; + const FT error_bound; const VPM1& vpm1; const VPM2& vpm2; + const FT infinity_value; const FT initial_lower_bound; + std::vector& tm1_trees; TM2Tree& tm2_tree; + double distance; + + // Constructor. + Bounded_error_distance_computation( + const std::vector& tm1_parts, const TriangleMesh2& tm2, + const FT error_bound, const VPM1& vpm1, const VPM2& vpm2, + const FT infinity_value, const FT initial_lower_bound, + std::vector& tm1_trees, TM2Tree& tm2_tree) : + tm1_parts(tm1_parts), tm2(tm2), + error_bound(error_bound), vpm1(vpm1), vpm2(vpm2), + infinity_value(infinity_value), initial_lower_bound(initial_lower_bound), + tm1_trees(tm1_trees), tm2_tree(tm2_tree), distance(-1.0) + { } + + // Split constructor. + Bounded_error_distance_computation( + Bounded_error_distance_computation& s, tbb::split) : + tm1_parts(s.tm1_parts), tm2(s.tm2), + error_bound(s.error_bound), vpm1(s.vpm1), vpm2(s.vpm2), + infinity_value(s.infinity_value), initial_lower_bound(s.initial_lower_bound), + tm1_trees(s.tm1_trees), tm2_tree(s.tm2_tree), distance(-1.0) + { } + + void operator()(const tbb::blocked_range& range) { + + double hdist = -1.0; + CGAL_assertion(tm1_parts.size() == tm1_trees.size()); + + Timer timer; + timer.reset(); + timer.start(); + for (std::size_t i = range.begin(); i != range.end(); ++i) { + CGAL_assertion(i < tm1_parts.size()); + CGAL_assertion(i < tm1_trees.size()); + const double dist = bounded_error_Hausdorff_impl( + tm1_parts[i], tm2, error_bound, vpm1, vpm2, + infinity_value, initial_lower_bound, tm1_trees[i], tm2_tree); + if (dist > hdist) hdist = dist; + } + if (hdist > distance) distance = hdist; + timer.stop(); + // std::cout << "* time operator() computation (sec.): " << timer.time() << std::endl; + } + + void join(Bounded_error_distance_computation& rhs) { + distance = (CGAL::max)(rhs.distance, distance); + } +}; + +#endif // defined(CGAL_LINKED_WITH_TBB) && METIS + template< class Concurrency_tag, class Kernel, class TriangleMesh1, class TriangleMesh2, class VPM1, - class VPM2, - class NamedParameters1, - class NamedParameters2> + class VPM2> double bounded_error_one_sided_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const typename Kernel::FT error_bound, const bool compare_meshes, const VPM1& vpm1, - const VPM2& vpm2, - const NamedParameters1& np1, - const NamedParameters2& np2) + const VPM2& vpm2) { using FT = typename Kernel::FT; @@ -1684,51 +1821,154 @@ double bounded_error_one_sided_Hausdorff_impl( using Face_handle_1 = typename boost::graph_traits::face_descriptor; using Face_handle_2 = typename boost::graph_traits::face_descriptor; - std::cout.precision(20); - std::vector tm1_only; - std::vector tm2_only; + using Timer = CGAL::Real_timer; + + Timer timer; + std::cout.precision(20); + + const int nb_cores = 4; // TODO: add to NP! - TM1_tree tm1_tree; TM2_tree tm2_tree; - FT infinity_value = -FT(1); - bool rebuild = false; - std::tie(infinity_value, rebuild) = preprocess_bounded_error_Hausdorff_impl( - tm1, tm2, compare_meshes, vpm1, vpm2, np1, np2, true, tm1_tree, tm2_tree, tm1_only, tm2_only); - CGAL_assertion(!rebuild); + std::vector tm1_trees; + std::vector tm1_parts; + std::atomic infinity_value; + + #if !defined(CGAL_LINKED_WITH_TBB) // TODO: && METIS! + + CGAL_static_assertion_msg( + !(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); + infinity_value = -FT(1); + + #else + + if (boost::is_convertible::value) { + + // (1) -- Create partition of tm1. + timer.reset(); + timer.start(); + using Face_property_tag = CGAL::dynamic_face_property_t; + auto face_pid_map = get(Face_property_tag(), tm1); + CGAL::METIS::partition_graph( + tm1, nb_cores, CGAL::parameters:: + face_partition_id_map(face_pid_map)); + timer.stop(); + std::cout << "* computing partition time (sec.): " << timer.time() << std::endl; + + // (2) -- Create a filtered face graph for each part. + timer.reset(); + timer.start(); + using Filtered_graph = CGAL::Face_filtered_graph; + tm1_parts.resize(nb_cores); + for (int i = 0; i < nb_cores; ++i) { + Filtered_graph tm1_part(tm1, i, face_pid_map); + CGAL_assertion(tm1_part.is_selection_valid()); + CGAL::copy_face_graph(tm1_part, tm1_parts[i]); // TODO: do not copy in the future! + std::cout << "* part " << i << " size: " << tm1_parts[i].number_of_faces() << std::endl; + } + timer.stop(); + std::cout << "* creating graphs time (sec.): " << timer.time() << std::endl; + + // (3) -- Preprocess all input data. + timer.reset(); + timer.start(); + // std::cout << "* preprocessing parallel version " << std::endl; + tm1_trees.resize(tm1_parts.size()); + Bounded_error_preprocessing bep( + tm1_parts, tm2, compare_meshes, vpm1, vpm2, + true, tm1_trees, tm2_tree); + tbb::parallel_reduce(tbb::blocked_range(0, tm1_parts.size()), bep); + infinity_value = bep.infinity_value; // TODO: check if it is equal to the seq. version! + tm2_tree.build(); + + timer.stop(); + std::cout << "* preprocessing parallel time (sec.) " << timer.time() << std::endl; + + } else // sequential version + + #endif // defined(CGAL_LINKED_WITH_TBB) && METIS + + { + // std::cout << "* preprocessing sequential version " << std::endl; + timer.reset(); + timer.start(); + bool rebuild = false; + std::vector tm1_only; + std::vector tm2_only; + tm1_trees.resize(1); + std::tie(infinity_value, rebuild) = preprocess_bounded_error_Hausdorff_impl( + tm1, tm2, compare_meshes, vpm1, vpm2, + true, tm1_trees[0], tm2_tree, tm1_only, tm2_only); + CGAL_assertion(!rebuild); + timer.stop(); + std::cout << "* preprocessing sequential time (sec.) " << timer.time() << std::endl; + } if (infinity_value < FT(0)) { // std::cout << "* culling rate: 100%" << std::endl; return 0.0; // TM1 is part of TM2 so the distance is zero } + CGAL_assertion(error_bound >= FT(0)); CGAL_assertion(infinity_value > FT(0)); - const FT initial_lower_bound = error_bound; - return bounded_error_Hausdorff_impl( - tm1, tm2, error_bound, vpm1, vpm2, - infinity_value, initial_lower_bound, tm1_tree, tm2_tree); + std::atomic hdist; + + timer.reset(); + timer.start(); + + #if !defined(CGAL_LINKED_WITH_TBB) // TODO: && METIS! + + CGAL_static_assertion_msg( + !(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); + hdist = -1.0; + + #else + + if (boost::is_convertible::value) { + // std::cout << "* executing parallel version " << std::endl; + Bounded_error_distance_computation bedc( + tm1_parts, tm2, error_bound, vpm1, vpm2, + infinity_value, initial_lower_bound, tm1_trees, tm2_tree); + tbb::parallel_reduce(tbb::blocked_range(0, tm1_parts.size()), bedc); + hdist = bedc.distance; + } else + + #endif // defined(CGAL_LINKED_WITH_TBB) && METIS + + { + std::cout << "* executing sequential version " << std::endl; + hdist = bounded_error_Hausdorff_impl( + tm1, tm2, error_bound, vpm1, vpm2, + infinity_value, initial_lower_bound, tm1_trees[0], tm2_tree); + } + + timer.stop(); + // std::cout << "* computation time (sec.) " << timer.time() << std::endl; + + CGAL_assertion(hdist >= 0.0); + return hdist; } template< class Concurrency_tag, class Kernel, class TriangleMesh1, class TriangleMesh2, - class VPM1, class VPM2, - class NamedParameters1, - class NamedParameters2> + class VPM1, + class VPM2> double bounded_error_symmetric_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const typename Kernel::FT error_bound, const bool compare_meshes, - const VPM1& vpm1, const VPM2& vpm2, - const NamedParameters1& np1, - const NamedParameters2& np2) + const VPM1& vpm1, + const VPM2& vpm2) { // Naive version. // const double hdist1 = bounded_error_one_sided_Hausdorff_impl( - // tm1, tm2, error_bound, compare_meshes, vpm1, vpm2, np1, np2); + // tm1, tm2, error_bound, compare_meshes, vpm1, vpm2); // const double hdist2 = bounded_error_one_sided_Hausdorff_impl( - // tm2, tm1, error_bound, compare_meshes, vpm2, vpm1, np2, np1); + // tm2, tm1, error_bound, compare_meshes, vpm2, vpm1); // return (CGAL::max)(hdist1, hdist2); // Optimized version. @@ -1758,7 +1998,8 @@ double bounded_error_symmetric_Hausdorff_impl( FT infinity_value = -FT(1); bool rebuild = false; std::tie(infinity_value, rebuild) = preprocess_bounded_error_Hausdorff_impl( - tm1, tm2, compare_meshes, vpm1, vpm2, np1, np2, false, tm1_tree, tm2_tree, tm1_only, tm2_only); + tm1, tm2, compare_meshes, vpm1, vpm2, + false, tm1_tree, tm2_tree, tm1_only, tm2_only); if (infinity_value < FT(0)) { // std::cout << "* culling rate: 100%" << std::endl; @@ -1992,15 +2233,7 @@ double bounded_error_Hausdorff_distance( CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); return internal::bounded_error_one_sided_Hausdorff_impl( - tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); - - #if !defined(CGAL_LINKED_WITH_TBB) - CGAL_static_assertion_msg( - !(boost::is_convertible::value), - "Parallel_tag is enabled but TBB is unavailable!"); - #else - // TODO: implement the parallel version of the above here. - #endif + tm1, tm2, error_threshold, match_faces, vpm1, vpm2); } template< class Concurrency_tag, @@ -2075,15 +2308,7 @@ double bounded_error_symmetric_Hausdorff_distance( CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); return internal::bounded_error_symmetric_Hausdorff_impl( - tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); - - #if !defined(CGAL_LINKED_WITH_TBB) - CGAL_static_assertion_msg( - !(boost::is_convertible::value), - "Parallel_tag is enabled but TBB is unavailable!"); - #else - // TODO: implement the parallel version of the above here. - #endif + tm1, tm2, error_threshold, match_faces, vpm1, vpm2); } template< class Concurrency_tag, diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index ff85429b350..72e019b3489 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -26,14 +26,12 @@ using Point_3 = typename Kernel::Point_3; using Vector_3 = typename Kernel::Vector_3; using Triangle_3 = typename Kernel::Triangle_3; -using TAG = CGAL::Parallel_tag; +using TAG = CGAL::Parallel_if_available_tag; using Surface_mesh = CGAL::Surface_mesh; using Affine_transformation_3 = CGAL::Aff_transformation_3; using Timer = CGAL::Real_timer; using Face_handle = typename boost::graph_traits::face_descriptor; -using Face_index = typename Surface_mesh::Face_index; - namespace PMP = CGAL::Polygon_mesh_processing; struct Approximate_hd_wrapper { @@ -823,6 +821,7 @@ void test_realizing_triangles( compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); } +// TODO: remove that! #if defined(CGAL_LINKED_WITH_TBB) template struct Bounded_error_distance_computation { @@ -878,8 +877,7 @@ struct Bounded_error_distance_computation { }; #endif -// TODO: in case we keep it, put this test and all METIS-related stuff in a separate -// file or exclude it from this test suite if METIS is unavailable! +// TODO: remove that! double bounded_error_Hausdorff_distance_parallel( Surface_mesh& tm1, const Surface_mesh& tm2, const double error_bound, const int nb_cores = 4) { @@ -893,6 +891,7 @@ double bounded_error_Hausdorff_distance_parallel( timer.start(); // Partition the mesh and output its parts. + using Face_index = typename Surface_mesh::Face_index; auto face_pid_map = tm1.add_property_map("f:pid").first; CGAL::METIS::partition_graph( tm1, nb_cores, CGAL::parameters:: @@ -921,7 +920,7 @@ double bounded_error_Hausdorff_distance_parallel( // std::cout << "selection " << i << std::endl; Filtered_graph tm1_part(tm1, i, face_pid_map); CGAL_assertion(tm1_part.is_selection_valid()); - CGAL::copy_face_graph(tm1_part, tm1_parts[i]); // TODO: do not copy in the future + CGAL::copy_face_graph(tm1_part, tm1_parts[i]); // TODO: do not copy in the future! std::cout << "part " << i << " size: " << tm1_parts[i].number_of_faces() << std::endl; } @@ -1003,8 +1002,10 @@ void test_parallel_version( timer.reset(); timer.start(); - const double distb = bounded_error_Hausdorff_distance_parallel( - mesh1, mesh2, error_bound); + const double distb = 0.0; // PMP::bounded_error_Hausdorff_distance( + // mesh1, mesh2, error_bound, + // CGAL::parameters::match_faces(false), + // CGAL::parameters::match_faces(false)); timer.stop(); const double timeb = timer.time(); From 27cc88524d697d61cad2d65b3cc828b2bc2cc13f Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 4 May 2021 13:23:13 +0200 Subject: [PATCH 190/349] fixed parallel preprocessing, computation is still buggy --- .../CGAL/Polygon_mesh_processing/distance.h | 82 ++++++++++++------- .../test_hausdorff_bounded_error_distance.cpp | 10 ++- 2 files changed, 59 insertions(+), 33 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index a5fbf0d56d6..0819e81b20f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1431,8 +1431,7 @@ std::pair preprocess_bounded_error_Hausdorff_impl( return std::make_pair(infinity_value, rebuild); } -template< class Concurrency_tag, - class Kernel, +template< class Kernel, class TriangleMesh1, class TriangleMesh2, class VPM1, @@ -1447,8 +1446,8 @@ double bounded_error_Hausdorff_impl( const VPM2& vpm2, const typename Kernel::FT infinity_value, const typename Kernel::FT initial_lower_bound, - TM1Tree& tm1_tree, - TM2Tree& tm2_tree) + const TM1Tree& tm1_tree, + const TM2Tree& tm2_tree) { using FT = typename Kernel::FT; using Point_3 = typename Kernel::Point_3; @@ -1475,6 +1474,7 @@ double bounded_error_Hausdorff_impl( CGAL_precondition(tm2_tree.size() > 0); // First, we apply culling. + std::cout << "- applying culling" << std::endl; Timer timer; timer.start(); @@ -1500,6 +1500,7 @@ double bounded_error_Hausdorff_impl( // std::cout << "* culling (sec.): " << timer.time() << std::endl; // Second, we apply subdivision. + std::cout << "- applying subdivision" << std::endl; timer.reset(); timer.start(); @@ -1670,7 +1671,7 @@ struct Bounded_error_preprocessing { const std::vector& tm1_parts; const TriangleMesh2& tm2; const bool compare_meshes; const VPM1& vpm1; const VPM2& vpm2; const bool is_one_sided_distance; - std::vector& tm1_trees; TM2Tree& tm2_tree; + std::vector& tm1_trees; FT infinity_value; // Constructor. @@ -1678,11 +1679,11 @@ struct Bounded_error_preprocessing { const std::vector& tm1_parts, const TriangleMesh2& tm2, const bool compare_meshes, const VPM1& vpm1, const VPM2& vpm2, const bool is_one_sided_distance, - std::vector& tm1_trees, TM2Tree& tm2_tree) : + std::vector& tm1_trees) : tm1_parts(tm1_parts), tm2(tm2), compare_meshes(compare_meshes), vpm1(vpm1), vpm2(vpm2), is_one_sided_distance(is_one_sided_distance), - tm1_trees(tm1_trees), tm2_tree(tm2_tree), + tm1_trees(tm1_trees), infinity_value(-FT(1)) { } @@ -1692,13 +1693,13 @@ struct Bounded_error_preprocessing { tm1_parts(s.tm1_parts), tm2(s.tm2), compare_meshes(s.compare_meshes), vpm1(s.vpm1), vpm2(s.vpm2), is_one_sided_distance(s.is_one_sided_distance), - tm1_trees(s.tm1_trees), tm2_tree(s.tm2_tree), + tm1_trees(s.tm1_trees), infinity_value(s.infinity_value) { } void operator()(const tbb::blocked_range& range) { - FT inf_value = -FT(1); + TM2Tree tm2_tree; std::vector tm1_only; std::vector tm2_only; CGAL_assertion(tm1_parts.size() == tm1_trees.size()); @@ -1710,8 +1711,10 @@ struct Bounded_error_preprocessing { for (std::size_t i = range.begin(); i != range.end(); ++i) { CGAL_assertion(i < tm1_parts.size()); CGAL_assertion(i < tm1_trees.size()); + tm1_only.clear(); + tm2_only.clear(); tm2_tree.clear(); - inf_value = preprocess_bounded_error_Hausdorff_impl( + const FT inf_value = preprocess_bounded_error_Hausdorff_impl( tm1_parts[i], tm2, compare_meshes, vpm1, vpm2, is_one_sided_distance, tm1_trees[i], tm2_tree, tm1_only, tm2_only).first; if (inf_value > max_inf_value) max_inf_value = inf_value; @@ -1741,7 +1744,7 @@ struct Bounded_error_distance_computation { const std::vector& tm1_parts; const TriangleMesh2& tm2; const FT error_bound; const VPM1& vpm1; const VPM2& vpm2; const FT infinity_value; const FT initial_lower_bound; - std::vector& tm1_trees; TM2Tree& tm2_tree; + const std::vector& tm1_trees; const TM2Tree& tm2_tree; double distance; // Constructor. @@ -1749,7 +1752,7 @@ struct Bounded_error_distance_computation { const std::vector& tm1_parts, const TriangleMesh2& tm2, const FT error_bound, const VPM1& vpm1, const VPM2& vpm2, const FT infinity_value, const FT initial_lower_bound, - std::vector& tm1_trees, TM2Tree& tm2_tree) : + const std::vector& tm1_trees, const TM2Tree& tm2_tree) : tm1_parts(tm1_parts), tm2(tm2), error_bound(error_bound), vpm1(vpm1), vpm2(vpm2), infinity_value(infinity_value), initial_lower_bound(initial_lower_bound), @@ -1766,17 +1769,18 @@ struct Bounded_error_distance_computation { { } void operator()(const tbb::blocked_range& range) { - - double hdist = -1.0; CGAL_assertion(tm1_parts.size() == tm1_trees.size()); Timer timer; timer.reset(); timer.start(); + double hdist = -1.0; + // std::cout << "* range size: " << range.size() << std::endl; for (std::size_t i = range.begin(); i != range.end(); ++i) { CGAL_assertion(i < tm1_parts.size()); CGAL_assertion(i < tm1_trees.size()); - const double dist = bounded_error_Hausdorff_impl( + // std::cout << "* part " << i << " size: " << tm1_parts[i].number_of_faces() << std::endl; + const double dist = bounded_error_Hausdorff_impl( tm1_parts[i], tm2, error_bound, vpm1, vpm2, infinity_value, initial_lower_bound, tm1_trees[i], tm2_tree); if (dist > hdist) hdist = dist; @@ -1833,6 +1837,10 @@ double bounded_error_one_sided_Hausdorff_impl( std::vector tm1_parts; std::atomic infinity_value; + bool rebuild = false; + std::vector tm1_only; + std::vector tm2_only; + #if !defined(CGAL_LINKED_WITH_TBB) // TODO: && METIS! CGAL_static_assertion_msg( @@ -1842,7 +1850,7 @@ double bounded_error_one_sided_Hausdorff_impl( #else - if (boost::is_convertible::value) { + if (boost::is_convertible::value && nb_cores > 1) { // (1) -- Create partition of tm1. timer.reset(); @@ -1874,12 +1882,20 @@ double bounded_error_one_sided_Hausdorff_impl( timer.start(); // std::cout << "* preprocessing parallel version " << std::endl; tm1_trees.resize(tm1_parts.size()); + + FT inf_value = -FT(1); + std::tie(inf_value, rebuild) = preprocess_bounded_error_Hausdorff_impl( + tm1_parts[0], tm2, compare_meshes, vpm1, vpm2, + true, tm1_trees[0], tm2_tree, tm1_only, tm2_only); + CGAL_assertion(!rebuild); + Bounded_error_preprocessing bep( - tm1_parts, tm2, compare_meshes, vpm1, vpm2, - true, tm1_trees, tm2_tree); - tbb::parallel_reduce(tbb::blocked_range(0, tm1_parts.size()), bep); - infinity_value = bep.infinity_value; // TODO: check if it is equal to the seq. version! + tm1_parts, tm2, compare_meshes, vpm1, vpm2, true, tm1_trees); + tbb::parallel_reduce(tbb::blocked_range(1, tm1_parts.size()), bep); + infinity_value = (CGAL::max)(inf_value, bep.infinity_value); + tm2_tree.build(); + for (auto& tm1_tree : tm1_trees) tm1_tree.build(); timer.stop(); std::cout << "* preprocessing parallel time (sec.) " << timer.time() << std::endl; @@ -1892,18 +1908,21 @@ double bounded_error_one_sided_Hausdorff_impl( // std::cout << "* preprocessing sequential version " << std::endl; timer.reset(); timer.start(); - bool rebuild = false; - std::vector tm1_only; - std::vector tm2_only; tm1_trees.resize(1); std::tie(infinity_value, rebuild) = preprocess_bounded_error_Hausdorff_impl( tm1, tm2, compare_meshes, vpm1, vpm2, true, tm1_trees[0], tm2_tree, tm1_only, tm2_only); CGAL_assertion(!rebuild); + + tm2_tree.build(); + tm1_trees[0].build(); + timer.stop(); std::cout << "* preprocessing sequential time (sec.) " << timer.time() << std::endl; } + // std::cout << "* infinity_value: " << infinity_value << std::endl; + if (infinity_value < FT(0)) { // std::cout << "* culling rate: 100%" << std::endl; return 0.0; // TM1 is part of TM2 so the distance is zero @@ -1925,8 +1944,8 @@ double bounded_error_one_sided_Hausdorff_impl( #else - if (boost::is_convertible::value) { - // std::cout << "* executing parallel version " << std::endl; + if (boost::is_convertible::value && nb_cores > 1) { + std::cout << "* executing parallel version " << std::endl; Bounded_error_distance_computation bedc( tm1_parts, tm2, error_bound, vpm1, vpm2, infinity_value, initial_lower_bound, tm1_trees, tm2_tree); @@ -1938,13 +1957,13 @@ double bounded_error_one_sided_Hausdorff_impl( { std::cout << "* executing sequential version " << std::endl; - hdist = bounded_error_Hausdorff_impl( + hdist = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, vpm1, vpm2, infinity_value, initial_lower_bound, tm1_trees[0], tm2_tree); } timer.stop(); - // std::cout << "* computation time (sec.) " << timer.time() << std::endl; + std::cout << "* computation time (sec.) " << timer.time() << std::endl; CGAL_assertion(hdist >= 0.0); return hdist; @@ -2011,8 +2030,11 @@ double bounded_error_symmetric_Hausdorff_impl( FT initial_lower_bound = error_bound; double dista = CGAL::to_double(error_bound); + tm1_tree.build(); + tm2_tree.build(); + if (!compare_meshes || (compare_meshes && tm1_only.size() > 0)) { - dista = bounded_error_Hausdorff_impl( + dista = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, vpm1, vpm2, infinity_value, initial_lower_bound, tm1_tree, tm2_tree); } @@ -2027,6 +2049,8 @@ double bounded_error_symmetric_Hausdorff_impl( CGAL_assertion(tm2_only.size() < faces(tm2).size()); tm1_tree.insert(faces(tm1).begin(), faces(tm1).end(), tm1, vpm1); tm2_tree.insert(tm2_only.begin(), tm2_only.end(), tm2, vpm2); + tm1_tree.build(); + tm2_tree.build(); } // Compute the second one-sided distance. @@ -2034,7 +2058,7 @@ double bounded_error_symmetric_Hausdorff_impl( double distb = CGAL::to_double(error_bound); if (!compare_meshes || (compare_meshes && tm2_only.size() > 0)) { - distb = bounded_error_Hausdorff_impl( + distb = bounded_error_Hausdorff_impl( tm2, tm1, error_bound, vpm2, vpm1, infinity_value, initial_lower_bound, tm2_tree, tm1_tree); } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 72e019b3489..26936191c99 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -991,6 +991,7 @@ void test_parallel_version( PMP::transform(Affine_transformation_3(CGAL::Translation(), Vector_3(FT(0), FT(0), FT(1))), mesh2); + std::cout << " ---- SEQUENTIAL ---- " << std::endl; timer.reset(); timer.start(); const double dista = PMP::bounded_error_Hausdorff_distance( @@ -1000,12 +1001,13 @@ void test_parallel_version( timer.stop(); const double timea = timer.time(); + std::cout << " ---- PARALLEL ---- " << std::endl; timer.reset(); timer.start(); - const double distb = 0.0; // PMP::bounded_error_Hausdorff_distance( - // mesh1, mesh2, error_bound, - // CGAL::parameters::match_faces(false), - // CGAL::parameters::match_faces(false)); + const double distb = PMP::bounded_error_Hausdorff_distance( + mesh1, mesh2, error_bound, + CGAL::parameters::match_faces(false), + CGAL::parameters::match_faces(false)); timer.stop(); const double timeb = timer.time(); From 9117c7ea2fc3d05302ccc274ab712f33b2874852 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 4 May 2021 13:58:50 +0200 Subject: [PATCH 191/349] fixed bug with parallel computation, now works --- .../include/CGAL/Polygon_mesh_processing/distance.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 0819e81b20f..f3bde6ce5ed 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1474,7 +1474,7 @@ double bounded_error_Hausdorff_impl( CGAL_precondition(tm2_tree.size() > 0); // First, we apply culling. - std::cout << "- applying culling" << std::endl; + // std::cout << "- applying culling" << std::endl; Timer timer; timer.start(); @@ -1500,7 +1500,7 @@ double bounded_error_Hausdorff_impl( // std::cout << "* culling (sec.): " << timer.time() << std::endl; // Second, we apply subdivision. - std::cout << "- applying subdivision" << std::endl; + // std::cout << "- applying subdivision" << std::endl; timer.reset(); timer.start(); @@ -1714,8 +1714,9 @@ struct Bounded_error_preprocessing { tm1_only.clear(); tm2_only.clear(); tm2_tree.clear(); + const auto tm1_part_vpm = get_const_property_map(CGAL::vertex_point, tm1_parts[i]); const FT inf_value = preprocess_bounded_error_Hausdorff_impl( - tm1_parts[i], tm2, compare_meshes, vpm1, vpm2, is_one_sided_distance, + tm1_parts[i], tm2, compare_meshes, tm1_part_vpm, vpm2, is_one_sided_distance, tm1_trees[i], tm2_tree, tm1_only, tm2_only).first; if (inf_value > max_inf_value) max_inf_value = inf_value; } @@ -1780,8 +1781,9 @@ struct Bounded_error_distance_computation { CGAL_assertion(i < tm1_parts.size()); CGAL_assertion(i < tm1_trees.size()); // std::cout << "* part " << i << " size: " << tm1_parts[i].number_of_faces() << std::endl; + const auto tm1_part_vpm = get_const_property_map(CGAL::vertex_point, tm1_parts[i]); const double dist = bounded_error_Hausdorff_impl( - tm1_parts[i], tm2, error_bound, vpm1, vpm2, + tm1_parts[i], tm2, error_bound, tm1_part_vpm, vpm2, infinity_value, initial_lower_bound, tm1_trees[i], tm2_tree); if (dist > hdist) hdist = dist; } @@ -1884,8 +1886,9 @@ double bounded_error_one_sided_Hausdorff_impl( tm1_trees.resize(tm1_parts.size()); FT inf_value = -FT(1); + const auto tm1_part_vpm = get_const_property_map(CGAL::vertex_point, tm1_parts[0]); std::tie(inf_value, rebuild) = preprocess_bounded_error_Hausdorff_impl( - tm1_parts[0], tm2, compare_meshes, vpm1, vpm2, + tm1_parts[0], tm2, compare_meshes, tm1_part_vpm, vpm2, true, tm1_trees[0], tm2_tree, tm1_only, tm2_only); CGAL_assertion(!rebuild); From e3c693caacd9db58a4674ff1f869ef6acfca93b5 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 4 May 2021 15:58:17 +0200 Subject: [PATCH 192/349] optimized one-sided parallel version --- .../CGAL/Polygon_mesh_processing/distance.h | 248 ++++++++---------- .../test_hausdorff_bounded_error_distance.cpp | 159 +---------- 2 files changed, 111 insertions(+), 296 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index f3bde6ce5ed..424f47c5728 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1325,6 +1325,8 @@ template< class Kernel, class TriangleMesh2, class VPM1, class VPM2, + class NamedParameters1, + class NamedParameters2, class TM1Tree, class TM2Tree, class FaceHandle1, @@ -1336,6 +1338,8 @@ std::pair preprocess_bounded_error_Hausdorff_impl( const VPM1& vpm1, const VPM2& vpm2, const bool is_one_sided_distance, + const NamedParameters1& np1, + const NamedParameters2& np2, TM1Tree& tm1_tree, TM2Tree& tm2_tree, std::vector& tm1_only, @@ -1376,7 +1380,7 @@ std::pair preprocess_bounded_error_Hausdorff_impl( bool rebuild = false; if (compare_meshes) { // exact check match_faces(tm1, tm2, std::back_inserter(common), - std::back_inserter(tm1_only), std::back_inserter(tm2_only)); + std::back_inserter(tm1_only), std::back_inserter(tm2_only), np1, np2); // std::cout << "- common: " << common.size() << std::endl; // std::cout << "- tm1 only: " << tm1_only.size() << std::endl; @@ -1651,83 +1655,50 @@ double bounded_error_Hausdorff_impl( return hdist; } -#if defined(CGAL_LINKED_WITH_TBB) // TODO: && METIS! - +// TODO: && METIS! +#if defined(CGAL_LINKED_WITH_TBB) template< class TriangleMesh1, - class TriangleMesh2, class VPM1, - class VPM2, class TM1Tree, - class TM2Tree, class Kernel> struct Bounded_error_preprocessing { - using FT = typename Kernel::FT; using Timer = CGAL::Real_timer; - - using Face_handle_1 = typename boost::graph_traits::face_descriptor; - using Face_handle_2 = typename boost::graph_traits::face_descriptor; - - const std::vector& tm1_parts; const TriangleMesh2& tm2; - const bool compare_meshes; const VPM1& vpm1; const VPM2& vpm2; - const bool is_one_sided_distance; - std::vector& tm1_trees; - FT infinity_value; + const std::vector& tm1_parts; + const VPM1& vpm1; std::vector& tm1_trees; // Constructor. Bounded_error_preprocessing( - const std::vector& tm1_parts, const TriangleMesh2& tm2, - const bool compare_meshes, const VPM1& vpm1, const VPM2& vpm2, - const bool is_one_sided_distance, + const std::vector& tm1_parts, const VPM1& vpm1, std::vector& tm1_trees) : - tm1_parts(tm1_parts), tm2(tm2), - compare_meshes(compare_meshes), vpm1(vpm1), vpm2(vpm2), - is_one_sided_distance(is_one_sided_distance), - tm1_trees(tm1_trees), - infinity_value(-FT(1)) - { } + tm1_parts(tm1_parts), vpm1(vpm1), tm1_trees(tm1_trees) { + CGAL_assertion(tm1_parts.size() == tm1_trees.size()); + } // Split constructor. Bounded_error_preprocessing( Bounded_error_preprocessing& s, tbb::split) : - tm1_parts(s.tm1_parts), tm2(s.tm2), - compare_meshes(s.compare_meshes), vpm1(s.vpm1), vpm2(s.vpm2), - is_one_sided_distance(s.is_one_sided_distance), - tm1_trees(s.tm1_trees), - infinity_value(s.infinity_value) - { } + tm1_parts(s.tm1_parts), vpm1(s.vpm1), tm1_trees(s.tm1_trees) { + CGAL_assertion(tm1_parts.size() == tm1_trees.size()); + } void operator()(const tbb::blocked_range& range) { - - TM2Tree tm2_tree; - std::vector tm1_only; - std::vector tm2_only; - CGAL_assertion(tm1_parts.size() == tm1_trees.size()); - Timer timer; timer.reset(); timer.start(); - FT max_inf_value = -FT(1); for (std::size_t i = range.begin(); i != range.end(); ++i) { CGAL_assertion(i < tm1_parts.size()); CGAL_assertion(i < tm1_trees.size()); - tm1_only.clear(); - tm2_only.clear(); - tm2_tree.clear(); - const auto tm1_part_vpm = get_const_property_map(CGAL::vertex_point, tm1_parts[i]); - const FT inf_value = preprocess_bounded_error_Hausdorff_impl( - tm1_parts[i], tm2, compare_meshes, tm1_part_vpm, vpm2, is_one_sided_distance, - tm1_trees[i], tm2_tree, tm1_only, tm2_only).first; - if (inf_value > max_inf_value) max_inf_value = inf_value; + const auto& tm1 = tm1_parts[i]; + auto& tm1_tree = tm1_trees[i]; + tm1_tree.insert(faces(tm1).begin(), faces(tm1).end(), tm1, vpm1); + tm1_tree.build(); } - if (max_inf_value > infinity_value) infinity_value = max_inf_value; timer.stop(); // std::cout << "* time operator() preprocessing (sec.): " << timer.time() << std::endl; } - void join(Bounded_error_preprocessing& rhs) { - infinity_value = (CGAL::max)(rhs.infinity_value, infinity_value); - } + void join(Bounded_error_preprocessing&) { } }; template< class TriangleMesh1, @@ -1757,8 +1728,9 @@ struct Bounded_error_distance_computation { tm1_parts(tm1_parts), tm2(tm2), error_bound(error_bound), vpm1(vpm1), vpm2(vpm2), infinity_value(infinity_value), initial_lower_bound(initial_lower_bound), - tm1_trees(tm1_trees), tm2_tree(tm2_tree), distance(-1.0) - { } + tm1_trees(tm1_trees), tm2_tree(tm2_tree), distance(-1.0) { + CGAL_assertion(tm1_parts.size() == tm1_trees.size()); + } // Split constructor. Bounded_error_distance_computation( @@ -1766,25 +1738,23 @@ struct Bounded_error_distance_computation { tm1_parts(s.tm1_parts), tm2(s.tm2), error_bound(s.error_bound), vpm1(s.vpm1), vpm2(s.vpm2), infinity_value(s.infinity_value), initial_lower_bound(s.initial_lower_bound), - tm1_trees(s.tm1_trees), tm2_tree(s.tm2_tree), distance(-1.0) - { } + tm1_trees(s.tm1_trees), tm2_tree(s.tm2_tree), distance(-1.0) { + CGAL_assertion(tm1_parts.size() == tm1_trees.size()); + } void operator()(const tbb::blocked_range& range) { - CGAL_assertion(tm1_parts.size() == tm1_trees.size()); - Timer timer; timer.reset(); timer.start(); double hdist = -1.0; - // std::cout << "* range size: " << range.size() << std::endl; for (std::size_t i = range.begin(); i != range.end(); ++i) { CGAL_assertion(i < tm1_parts.size()); CGAL_assertion(i < tm1_trees.size()); - // std::cout << "* part " << i << " size: " << tm1_parts[i].number_of_faces() << std::endl; - const auto tm1_part_vpm = get_const_property_map(CGAL::vertex_point, tm1_parts[i]); + const auto& tm1 = tm1_parts[i]; + const auto& tm1_tree = tm1_trees[i]; const double dist = bounded_error_Hausdorff_impl( - tm1_parts[i], tm2, error_bound, tm1_part_vpm, vpm2, - infinity_value, initial_lower_bound, tm1_trees[i], tm2_tree); + tm1, tm2, error_bound, vpm1, vpm2, + infinity_value, initial_lower_bound, tm1_tree, tm2_tree); if (dist > hdist) hdist = dist; } if (hdist > distance) distance = hdist; @@ -1796,7 +1766,6 @@ struct Bounded_error_distance_computation { distance = (CGAL::max)(rhs.distance, distance); } }; - #endif // defined(CGAL_LINKED_WITH_TBB) && METIS template< class Concurrency_tag, @@ -1804,28 +1773,46 @@ template< class Concurrency_tag, class TriangleMesh1, class TriangleMesh2, class VPM1, - class VPM2> + class VPM2, + class NamedParameters1, + class NamedParameters2> double bounded_error_one_sided_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const typename Kernel::FT error_bound, const bool compare_meshes, const VPM1& vpm1, - const VPM2& vpm2) + const VPM2& vpm2, + const NamedParameters1& np1, + const NamedParameters2& np2) { - using FT = typename Kernel::FT; + #if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg( + !(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); + #endif - using TM1_primitive = AABB_face_graph_triangle_primitive; - using TM2_primitive = AABB_face_graph_triangle_primitive; + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + + using TM1 = TriangleMesh1; + using TM2 = TriangleMesh2; + using TMF = CGAL::Face_filtered_graph; + + using TM1_primitive = AABB_face_graph_triangle_primitive; + using TM2_primitive = AABB_face_graph_triangle_primitive; + using TMF_primitive = AABB_face_graph_triangle_primitive; using TM1_traits = AABB_traits; using TM2_traits = AABB_traits; + using TMF_traits = AABB_traits; using TM1_tree = AABB_tree; using TM2_tree = AABB_tree; + using TMF_tree = AABB_tree; - using Face_handle_1 = typename boost::graph_traits::face_descriptor; - using Face_handle_2 = typename boost::graph_traits::face_descriptor; + using Face_handle_1 = typename boost::graph_traits::face_descriptor; + using Face_handle_2 = typename boost::graph_traits::face_descriptor; using Timer = CGAL::Real_timer; @@ -1834,24 +1821,14 @@ double bounded_error_one_sided_Hausdorff_impl( const int nb_cores = 4; // TODO: add to NP! + TM1_tree tm1_tree; TM2_tree tm2_tree; - std::vector tm1_trees; - std::vector tm1_parts; - std::atomic infinity_value; - - bool rebuild = false; - std::vector tm1_only; - std::vector tm2_only; - - #if !defined(CGAL_LINKED_WITH_TBB) // TODO: && METIS! - - CGAL_static_assertion_msg( - !(boost::is_convertible::value), - "Parallel_tag is enabled but TBB is unavailable."); - infinity_value = -FT(1); - - #else + std::vector tm1_parts; + std::vector tm1_trees; + FT infinity_value = -FT(1); + // TODO: && METIS! + #if defined(CGAL_LINKED_WITH_TBB) if (boost::is_convertible::value && nb_cores > 1) { // (1) -- Create partition of tm1. @@ -1863,69 +1840,67 @@ double bounded_error_one_sided_Hausdorff_impl( tm1, nb_cores, CGAL::parameters:: face_partition_id_map(face_pid_map)); timer.stop(); - std::cout << "* computing partition time (sec.): " << timer.time() << std::endl; + const double time1 = timer.time(); + std::cout << "- computing partition time (sec.): " << time1 << std::endl; // (2) -- Create a filtered face graph for each part. timer.reset(); timer.start(); - using Filtered_graph = CGAL::Face_filtered_graph; - tm1_parts.resize(nb_cores); + tm1_parts.reserve(nb_cores); for (int i = 0; i < nb_cores; ++i) { - Filtered_graph tm1_part(tm1, i, face_pid_map); - CGAL_assertion(tm1_part.is_selection_valid()); - CGAL::copy_face_graph(tm1_part, tm1_parts[i]); // TODO: do not copy in the future! - std::cout << "* part " << i << " size: " << tm1_parts[i].number_of_faces() << std::endl; + tm1_parts.emplace_back(tm1, i, face_pid_map); + CGAL_assertion(tm1_parts.back().is_selection_valid()); + std::cout << "* part " << i << " size: " << tm1_parts.back().number_of_faces() << std::endl; } + CGAL_assertion(tm1_parts.size() == nb_cores); timer.stop(); - std::cout << "* creating graphs time (sec.): " << timer.time() << std::endl; + const double time2 = timer.time(); + std::cout << "- creating graphs time (sec.): " << time2 << std::endl; // (3) -- Preprocess all input data. timer.reset(); timer.start(); - // std::cout << "* preprocessing parallel version " << std::endl; tm1_trees.resize(tm1_parts.size()); - FT inf_value = -FT(1); - const auto tm1_part_vpm = get_const_property_map(CGAL::vertex_point, tm1_parts[0]); - std::tie(inf_value, rebuild) = preprocess_bounded_error_Hausdorff_impl( - tm1_parts[0], tm2, compare_meshes, tm1_part_vpm, vpm2, - true, tm1_trees[0], tm2_tree, tm1_only, tm2_only); - CGAL_assertion(!rebuild); - - Bounded_error_preprocessing bep( - tm1_parts, tm2, compare_meshes, vpm1, vpm2, true, tm1_trees); - tbb::parallel_reduce(tbb::blocked_range(1, tm1_parts.size()), bep); - infinity_value = (CGAL::max)(inf_value, bep.infinity_value); + // Compute infinity value. + const auto bbox1 = bbox(tm1); + const auto bbox2 = bbox(tm2); + const auto bb = bbox1 + bbox2; + const FT sq_dist = CGAL::squared_distance( + Point_3(bb.xmin(), bb.ymin(), bb.zmin()), + Point_3(bb.xmax(), bb.ymax(), bb.zmax())); + infinity_value = CGAL::approximate_sqrt(sq_dist) * FT(2); + Bounded_error_preprocessing bep(tm1_parts, vpm1, tm1_trees); + tbb::parallel_reduce(tbb::blocked_range(0, tm1_parts.size()), bep); + tm2_tree.insert(faces(tm2).begin(), faces(tm2).end(), tm2, vpm2); tm2_tree.build(); - for (auto& tm1_tree : tm1_trees) tm1_tree.build(); timer.stop(); - std::cout << "* preprocessing parallel time (sec.) " << timer.time() << std::endl; + const double time3 = timer.time(); + std::cout << "- creating trees time (sec.) " << time3 << std::endl; + std::cout << "* preprocessing parallel time (sec.) " << time1 + time2 + time3 << std::endl; } else // sequential version - #endif // defined(CGAL_LINKED_WITH_TBB) && METIS - { // std::cout << "* preprocessing sequential version " << std::endl; timer.reset(); timer.start(); - tm1_trees.resize(1); + bool rebuild = false; + std::vector tm1_only; + std::vector tm2_only; std::tie(infinity_value, rebuild) = preprocess_bounded_error_Hausdorff_impl( - tm1, tm2, compare_meshes, vpm1, vpm2, - true, tm1_trees[0], tm2_tree, tm1_only, tm2_only); + tm1, tm2, compare_meshes, vpm1, vpm2, true, np1, np2, + tm1_tree, tm2_tree, tm1_only, tm2_only); CGAL_assertion(!rebuild); - + tm1_tree.build(); tm2_tree.build(); - tm1_trees[0].build(); - timer.stop(); std::cout << "* preprocessing sequential time (sec.) " << timer.time() << std::endl; } - // std::cout << "* infinity_value: " << infinity_value << std::endl; - + std::cout << "* infinity_value: " << infinity_value << std::endl; if (infinity_value < FT(0)) { // std::cout << "* culling rate: 100%" << std::endl; return 0.0; // TM1 is part of TM2 so the distance is zero @@ -1938,31 +1913,24 @@ double bounded_error_one_sided_Hausdorff_impl( timer.reset(); timer.start(); - #if !defined(CGAL_LINKED_WITH_TBB) // TODO: && METIS! - - CGAL_static_assertion_msg( - !(boost::is_convertible::value), - "Parallel_tag is enabled but TBB is unavailable."); - hdist = -1.0; - - #else - + // TODO: && METIS! + #if defined(CGAL_LINKED_WITH_TBB) if (boost::is_convertible::value && nb_cores > 1) { + std::cout << "* executing parallel version " << std::endl; - Bounded_error_distance_computation bedc( + Bounded_error_distance_computation bedc( tm1_parts, tm2, error_bound, vpm1, vpm2, infinity_value, initial_lower_bound, tm1_trees, tm2_tree); tbb::parallel_reduce(tbb::blocked_range(0, tm1_parts.size()), bedc); hdist = bedc.distance; - } else + } else // sequential version #endif // defined(CGAL_LINKED_WITH_TBB) && METIS - { std::cout << "* executing sequential version " << std::endl; hdist = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, vpm1, vpm2, - infinity_value, initial_lower_bound, tm1_trees[0], tm2_tree); + infinity_value, initial_lower_bound, tm1_tree, tm2_tree); } timer.stop(); @@ -1977,20 +1945,24 @@ template< class Concurrency_tag, class TriangleMesh1, class TriangleMesh2, class VPM1, - class VPM2> + class VPM2, + class NamedParameters1, + class NamedParameters2> double bounded_error_symmetric_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const typename Kernel::FT error_bound, const bool compare_meshes, const VPM1& vpm1, - const VPM2& vpm2) + const VPM2& vpm2, + const NamedParameters1& np1, + const NamedParameters2& np2) { // Naive version. // const double hdist1 = bounded_error_one_sided_Hausdorff_impl( - // tm1, tm2, error_bound, compare_meshes, vpm1, vpm2); + // tm1, tm2, error_bound, compare_meshes, vpm1, vpm2, np1, np2); // const double hdist2 = bounded_error_one_sided_Hausdorff_impl( - // tm2, tm1, error_bound, compare_meshes, vpm2, vpm1); + // tm2, tm1, error_bound, compare_meshes, vpm2, vpm1, np1, np2); // return (CGAL::max)(hdist1, hdist2); // Optimized version. @@ -2020,8 +1992,8 @@ double bounded_error_symmetric_Hausdorff_impl( FT infinity_value = -FT(1); bool rebuild = false; std::tie(infinity_value, rebuild) = preprocess_bounded_error_Hausdorff_impl( - tm1, tm2, compare_meshes, vpm1, vpm2, - false, tm1_tree, tm2_tree, tm1_only, tm2_only); + tm1, tm2, compare_meshes, vpm1, vpm2, false, np1, np2, + tm1_tree, tm2_tree, tm1_only, tm2_only); if (infinity_value < FT(0)) { // std::cout << "* culling rate: 100%" << std::endl; @@ -2260,7 +2232,7 @@ double bounded_error_Hausdorff_distance( CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); return internal::bounded_error_one_sided_Hausdorff_impl( - tm1, tm2, error_threshold, match_faces, vpm1, vpm2); + tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); } template< class Concurrency_tag, @@ -2335,7 +2307,7 @@ double bounded_error_symmetric_Hausdorff_distance( CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); return internal::bounded_error_symmetric_Hausdorff_impl( - tm1, tm2, error_threshold, match_faces, vpm1, vpm2); + tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); } template< class Concurrency_tag, diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 26936191c99..3ee7ac06b8d 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -13,9 +13,6 @@ #include #include -#include // METIS related -#include - using SCK = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; @@ -26,7 +23,7 @@ using Point_3 = typename Kernel::Point_3; using Vector_3 = typename Kernel::Vector_3; using Triangle_3 = typename Kernel::Triangle_3; -using TAG = CGAL::Parallel_if_available_tag; +using TAG = CGAL::Sequential_tag; using Surface_mesh = CGAL::Surface_mesh; using Affine_transformation_3 = CGAL::Aff_transformation_3; using Timer = CGAL::Real_timer; @@ -821,160 +818,6 @@ void test_realizing_triangles( compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); } -// TODO: remove that! -#if defined(CGAL_LINKED_WITH_TBB) -template -struct Bounded_error_distance_computation { - - const std::vector& tm1_parts; - const TriangleMesh2& tm2; - const double error_bound; - double distance; - - // Constructor. - Bounded_error_distance_computation( - const std::vector& tm1_parts, - const TriangleMesh2& tm2, - const double error_bound) : - tm1_parts(tm1_parts), tm2(tm2), - error_bound(error_bound), distance(-1.0) - { } - - // Split constructor. - Bounded_error_distance_computation( - Bounded_error_distance_computation& s, tbb::split) : - tm1_parts(s.tm1_parts), tm2(s.tm2), - error_bound(s.error_bound), distance(-1.0) - { } - - void operator()(const tbb::blocked_range& range) { - - Timer timer; - timer.reset(); - timer.start(); - - // std::cout << "* range size: " << range.size() << std::endl; - double hdist = 0.0; - for (std::size_t i = range.begin(); i != range.end(); ++i) { - CGAL_assertion(i < tm1_parts.size()); - const auto& tm1 = tm1_parts[i]; - // std::cout << "part size: " << tm1.number_of_faces() << std::endl; - const double dist = PMP::bounded_error_Hausdorff_distance( - tm1, tm2, error_bound, - CGAL::parameters::match_faces(false), - CGAL::parameters::match_faces(false)); - if (dist > hdist) hdist = dist; - } - if (hdist > distance) distance = hdist; - - timer.stop(); - // std::cout << "* time operator() (sec.): " << timer.time() << std::endl; - } - - void join(Bounded_error_distance_computation& rhs) { - distance = (CGAL::max)(rhs.distance, distance); - } -}; -#endif - -// TODO: remove that! -double bounded_error_Hausdorff_distance_parallel( - Surface_mesh& tm1, const Surface_mesh& tm2, - const double error_bound, const int nb_cores = 4) { - - Timer timer; - - // (1) -- Create partition of tm1. - std::cout << "* computing partition ... " << std::endl; - - timer.reset(); - timer.start(); - - // Partition the mesh and output its parts. - using Face_index = typename Surface_mesh::Face_index; - auto face_pid_map = tm1.add_property_map("f:pid").first; - CGAL::METIS::partition_graph( - tm1, nb_cores, CGAL::parameters:: - face_partition_id_map(face_pid_map)); - - int max_id = 0; - for (const auto& face : faces(tm1)) { - const int id = static_cast(get(face_pid_map, face)); - max_id = (CGAL::max)(max_id, id); - } - assert(nb_cores == (max_id + 1)); - timer.stop(); - const double time1 = timer.time(); - std::cout << " ... done in " << time1 << " sec." << std::endl; - std::cout << "* number of detected parts: " << max_id + 1 << std::endl; - - // (2) -- Create a face filtered graph for each part. - std::cout << "* creating graphs ... " << std::endl; - - timer.reset(); - timer.start(); - - using Filtered_graph = CGAL::Face_filtered_graph; - std::vector tm1_parts(nb_cores); - for (int i = 0; i < nb_cores; ++i) { - // std::cout << "selection " << i << std::endl; - Filtered_graph tm1_part(tm1, i, face_pid_map); - CGAL_assertion(tm1_part.is_selection_valid()); - CGAL::copy_face_graph(tm1_part, tm1_parts[i]); // TODO: do not copy in the future! - std::cout << "part " << i << " size: " << tm1_parts[i].number_of_faces() << std::endl; - } - - timer.stop(); - const double time2 = timer.time(); - std::cout << " ... done in " << time2 << " sec." << std::endl; - - // (3) -- Run all parts in parallel. - std::cout << "* computing distance for all graphs in parallel ... " << std::endl; - - timer.reset(); - timer.start(); - - std::atomic hdist; - #if !defined(CGAL_LINKED_WITH_TBB) - CGAL_static_assertion_msg( - !(boost::is_convertible::value), - "Parallel_tag is enabled but TBB is unavailable."); - hdist = -1.0; - #else - if (boost::is_convertible::value) { - std::cout << "* executing parallel version " << std::endl; - Bounded_error_distance_computation f( - tm1_parts, tm2, error_bound); - tbb::parallel_reduce(tbb::blocked_range(0, tm1_parts.size()), f); - hdist = f.distance; - } else - #endif - { - std::cout << "* executing sequential version " << std::endl; - hdist = PMP::bounded_error_Hausdorff_distance( - tm1, tm2, error_bound, - CGAL::parameters::match_faces(false), - CGAL::parameters::match_faces(false)); - } - - timer.stop(); - const double time3 = timer.time(); - std::cout << " ... done in " << time3 << " sec." << std::endl; - - // for (const auto& tm1_part : tm1_parts) { - // timer.reset(); - // timer.start(); - // hdist = PMP::bounded_error_Hausdorff_distance( - // tm1_part, tm2, error_bound, - // CGAL::parameters::match_faces(false), - // CGAL::parameters::match_faces(false)); - // timer.stop(); - // std::cout << "* manual call seq. time (sec.): " << timer.time() << std::endl; - // } - - return hdist; -} - void test_parallel_version( const std::string filepath, const double error_bound) { From 7d0ae6b13d511c9890101962280af2fc44351168 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 4 May 2021 17:19:12 +0200 Subject: [PATCH 193/349] testing bunny dense --- .../include/CGAL/Polygon_mesh_processing/distance.h | 2 +- .../test_hausdorff_bounded_error_distance.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 424f47c5728..97b6e70fa8e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1850,7 +1850,7 @@ double bounded_error_one_sided_Hausdorff_impl( for (int i = 0; i < nb_cores; ++i) { tm1_parts.emplace_back(tm1, i, face_pid_map); CGAL_assertion(tm1_parts.back().is_selection_valid()); - std::cout << "* part " << i << " size: " << tm1_parts.back().number_of_faces() << std::endl; + std::cout << "- part " << i << " size: " << tm1_parts.back().number_of_faces() << std::endl; } CGAL_assertion(tm1_parts.size() == nb_cores); timer.stop(); diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 3ee7ac06b8d..478d1401e71 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -903,8 +903,8 @@ int main(int argc, char** argv) { // --- Compare timings. - filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); - // filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; + // filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); + filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); // test_timings(filepath, bound_hd); From fb8538393d411057421940b6e64146f14228a720 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 5 May 2021 10:04:48 +0200 Subject: [PATCH 194/349] corrected includes --- .../include/CGAL/Polygon_mesh_processing/distance.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 97b6e70fa8e..6aea9371f90 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -31,12 +31,13 @@ #include #include +#include // METIS related +#include + #ifdef CGAL_LINKED_WITH_TBB #include #include #include -#include // METIS related -#include #endif // CGAL_LINKED_WITH_TBB #include From 3c0fc281e807b6b34dfcc595f3f3c382924bb4cd Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 5 May 2021 13:17:23 +0200 Subject: [PATCH 195/349] more optimizations, using boost any and factoring out kd tree, adding metis check --- .../cmake/modules/CGAL_METIS_support.cmake | 1 + .../Polygon_mesh_processing/CMakeLists.txt | 8 ++ .../CGAL/Polygon_mesh_processing/distance.h | 94 +++++++++++++------ 3 files changed, 73 insertions(+), 30 deletions(-) diff --git a/Installation/cmake/modules/CGAL_METIS_support.cmake b/Installation/cmake/modules/CGAL_METIS_support.cmake index 563bec6fc7f..c3fa73714d4 100644 --- a/Installation/cmake/modules/CGAL_METIS_support.cmake +++ b/Installation/cmake/modules/CGAL_METIS_support.cmake @@ -1,6 +1,7 @@ if(METIS_FOUND AND NOT TARGET CGAL::METIS_support) add_library(CGAL::METIS_support INTERFACE IMPORTED) set_target_properties(CGAL::METIS_support PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "CGAL_METIS_ENABLED" INTERFACE_INCLUDE_DIRECTORIES "${METIS_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${METIS_LIBRARIES}") endif() diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index b49e5d3a343..8da59823454 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -123,6 +123,14 @@ if(OpenMesh_FOUND) PRIVATE ${OPENMESH_LIBRARIES}) endif(OpenMesh_FOUND) +find_package(METIS) +include(CGAL_METIS_support) +if(TARGET CGAL::METIS_support) + target_link_libraries(hausdorff_bounded_error_distance_example PUBLIC CGAL::METIS_support) +else() + message(STATUS "Tests, which use the METIS library will not be compiled.") +endif() + find_package(TBB) include(CGAL_TBB_support) if(TARGET CGAL::TBB_support) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 6aea9371f90..670945fa3a9 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -31,8 +31,10 @@ #include #include -#include // METIS related #include +#if defined(CGAL_METIS_ENABLED) +#include +#endif // CGAL_METIS_ENABLED #ifdef CGAL_LINKED_WITH_TBB #include @@ -41,6 +43,7 @@ #endif // CGAL_LINKED_WITH_TBB #include +#include #include #include @@ -1656,31 +1659,48 @@ double bounded_error_Hausdorff_impl( return hdist; } -// TODO: && METIS! -#if defined(CGAL_LINKED_WITH_TBB) -template< class TriangleMesh1, - class VPM1, - class TM1Tree, - class Kernel> +#if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) + +template +struct Triangle_mesh_wrapper { + + const TriangleMesh& tm; const VPM& vpm; + const bool is_tm2; TMTree& tm_tree; + Triangle_mesh_wrapper( + const TriangleMesh& tm, const VPM& vpm, + const bool is_tm2, TMTree& tm_tree) : + tm(tm), vpm(vpm), is_tm2(is_tm2), tm_tree(tm_tree) { } + + void build_tree() { + tm_tree.insert(faces(tm).begin(), faces(tm).end(), tm, vpm); + tm_tree.build(); + if (is_tm2) tm_tree.accelerate_distance_queries(); + else tm_tree.do_not_accelerate_distance_queries(); + } +}; + +template struct Bounded_error_preprocessing { using Timer = CGAL::Real_timer; - const std::vector& tm1_parts; - const VPM1& vpm1; std::vector& tm1_trees; + std::vector& tm_wrappers; // Constructor. Bounded_error_preprocessing( - const std::vector& tm1_parts, const VPM1& vpm1, - std::vector& tm1_trees) : - tm1_parts(tm1_parts), vpm1(vpm1), tm1_trees(tm1_trees) { - CGAL_assertion(tm1_parts.size() == tm1_trees.size()); - } + std::vector& tm_wrappers) : + tm_wrappers(tm_wrappers) { } // Split constructor. Bounded_error_preprocessing( Bounded_error_preprocessing& s, tbb::split) : - tm1_parts(s.tm1_parts), vpm1(s.vpm1), tm1_trees(s.tm1_trees) { - CGAL_assertion(tm1_parts.size() == tm1_trees.size()); + tm_wrappers(s.tm_wrappers) { } + + bool is_tm1_wrapper(const boost::any& operand) const { + return operand.type() == typeid(TM1Wrapper); + } + + bool is_tm2_wrapper(const boost::any& operand) const { + return operand.type() == typeid(TM2Wrapper); } void operator()(const tbb::blocked_range& range) { @@ -1688,12 +1708,17 @@ struct Bounded_error_preprocessing { timer.reset(); timer.start(); for (std::size_t i = range.begin(); i != range.end(); ++i) { - CGAL_assertion(i < tm1_parts.size()); - CGAL_assertion(i < tm1_trees.size()); - const auto& tm1 = tm1_parts[i]; - auto& tm1_tree = tm1_trees[i]; - tm1_tree.insert(faces(tm1).begin(), faces(tm1).end(), tm1, vpm1); - tm1_tree.build(); + CGAL_assertion(i < tm_wrappers.size()); + auto& tm_wrapper = tm_wrappers[i]; + if (is_tm1_wrapper(tm_wrapper)) { + TM1Wrapper& object = boost::any_cast(tm_wrapper); + object.build_tree(); + } else if (is_tm2_wrapper(tm_wrapper)) { + TM2Wrapper& object = boost::any_cast(tm_wrapper); + object.build_tree(); + } else { + CGAL_assertion_msg(false, "Error: wrong boost any type!"); + } } timer.stop(); // std::cout << "* time operator() preprocessing (sec.): " << timer.time() << std::endl; @@ -1817,19 +1842,23 @@ double bounded_error_one_sided_Hausdorff_impl( using Timer = CGAL::Real_timer; + using TM1_wrapper = Triangle_mesh_wrapper; + using TM2_wrapper = Triangle_mesh_wrapper; + Timer timer; std::cout.precision(20); const int nb_cores = 4; // TODO: add to NP! + std::cout << "* num cores: " << nb_cores << std::endl; TM1_tree tm1_tree; TM2_tree tm2_tree; std::vector tm1_parts; std::vector tm1_trees; + std::vector tm_wrappers; FT infinity_value = -FT(1); - // TODO: && METIS! - #if defined(CGAL_LINKED_WITH_TBB) + #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) if (boost::is_convertible::value && nb_cores > 1) { // (1) -- Create partition of tm1. @@ -1872,10 +1901,16 @@ double bounded_error_one_sided_Hausdorff_impl( Point_3(bb.xmax(), bb.ymax(), bb.zmax())); infinity_value = CGAL::approximate_sqrt(sq_dist) * FT(2); - Bounded_error_preprocessing bep(tm1_parts, vpm1, tm1_trees); - tbb::parallel_reduce(tbb::blocked_range(0, tm1_parts.size()), bep); - tm2_tree.insert(faces(tm2).begin(), faces(tm2).end(), tm2, vpm2); - tm2_tree.build(); + CGAL_assertion(tm1_trees.size() == tm1_parts.size()); + tm_wrappers.reserve(tm1_parts.size() + 1); + for (std::size_t i = 0; i < tm1_parts.size(); ++i) { + tm_wrappers.push_back(TM1_wrapper(tm1_parts[i], vpm1, false, tm1_trees[i])); + } + tm_wrappers.push_back(TM2_wrapper(tm2, vpm2, true, tm2_tree)); + CGAL_assertion(tm_wrappers.size() == tm1_parts.size() + 1); + + Bounded_error_preprocessing bep(tm_wrappers); + tbb::parallel_reduce(tbb::blocked_range(0, tm_wrappers.size()), bep); timer.stop(); const double time3 = timer.time(); @@ -1914,8 +1949,7 @@ double bounded_error_one_sided_Hausdorff_impl( timer.reset(); timer.start(); - // TODO: && METIS! - #if defined(CGAL_LINKED_WITH_TBB) + #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) if (boost::is_convertible::value && nb_cores > 1) { std::cout << "* executing parallel version " << std::endl; From 13ef4342d13d2d5c399582e1e09ba62934844105 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 5 May 2021 13:43:31 +0200 Subject: [PATCH 196/349] fixing build errors when tbb and/or metis is unavailable --- .../CGAL/Polygon_mesh_processing/distance.h | 25 +++++++++++-------- .../Polygon_mesh_processing/CMakeLists.txt | 14 +++++------ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 670945fa3a9..9d5310a954f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1818,32 +1818,38 @@ double bounded_error_one_sided_Hausdorff_impl( "Parallel_tag is enabled but TBB is unavailable."); #endif - using FT = typename Kernel::FT; - using Point_3 = typename Kernel::Point_3; + using FT = typename Kernel::FT; using TM1 = TriangleMesh1; using TM2 = TriangleMesh2; - using TMF = CGAL::Face_filtered_graph; using TM1_primitive = AABB_face_graph_triangle_primitive; using TM2_primitive = AABB_face_graph_triangle_primitive; - using TMF_primitive = AABB_face_graph_triangle_primitive; using TM1_traits = AABB_traits; using TM2_traits = AABB_traits; - using TMF_traits = AABB_traits; using TM1_tree = AABB_tree; using TM2_tree = AABB_tree; - using TMF_tree = AABB_tree; using Face_handle_1 = typename boost::graph_traits::face_descriptor; using Face_handle_2 = typename boost::graph_traits::face_descriptor; using Timer = CGAL::Real_timer; - using TM1_wrapper = Triangle_mesh_wrapper; - using TM2_wrapper = Triangle_mesh_wrapper; + #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) + using Point_3 = typename Kernel::Point_3; + using TMF = CGAL::Face_filtered_graph; + using TMF_primitive = AABB_face_graph_triangle_primitive; + using TMF_traits = AABB_traits; + using TMF_tree = AABB_tree; + using TM1_wrapper = Triangle_mesh_wrapper; + using TM2_wrapper = Triangle_mesh_wrapper; + + std::vector tm1_parts; + std::vector tm1_trees; + std::vector tm_wrappers; + #endif // defined(CGAL_LINKED_WITH_TBB) && METIS Timer timer; std::cout.precision(20); @@ -1853,9 +1859,6 @@ double bounded_error_one_sided_Hausdorff_impl( TM1_tree tm1_tree; TM2_tree tm2_tree; - std::vector tm1_parts; - std::vector tm1_trees; - std::vector tm_wrappers; FT infinity_value = -FT(1); #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index ee7be943420..a067b8d6d0e 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -109,13 +109,13 @@ create_single_source_cgal_program("triangulate_hole_with_cdt_2_test.cpp") create_single_source_cgal_program("test_pmp_polyhedral_envelope.cpp") # create_single_source_cgal_program("test_pmp_repair_self_intersections.cpp") -find_package(METIS) -include(CGAL_METIS_support) -if(TARGET CGAL::METIS_support) - target_link_libraries(test_hausdorff_bounded_error_distance PUBLIC CGAL::METIS_support) -else() - message(STATUS "Tests, which use the METIS library will not be compiled.") -endif() +# find_package(METIS) +# include(CGAL_METIS_support) +# if(TARGET CGAL::METIS_support) +# target_link_libraries(test_hausdorff_bounded_error_distance PUBLIC CGAL::METIS_support) +# else() +# message(STATUS "Tests, which use the METIS library will not be compiled.") +# endif() if(TARGET CGAL::TBB_support) target_link_libraries(test_hausdorff_bounded_error_distance PUBLIC CGAL::TBB_support) From c4e23b5cede85fa44c74ff4792d15bd7e89f8575 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Wed, 5 May 2021 15:29:48 +0200 Subject: [PATCH 197/349] tested with different concurrency tags, cleanup, added empty test for the new function --- ...usdorff_bounded_error_distance_example.cpp | 2 +- .../CGAL/Polygon_mesh_processing/distance.h | 52 ++++++++++++------- .../Polygon_mesh_processing/CMakeLists.txt | 14 ++--- .../test_hausdorff_bounded_error_distance.cpp | 24 +++++++-- 4 files changed, 61 insertions(+), 31 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 3107e29fca1..ea083195a58 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -17,7 +17,7 @@ using FT = typename Kernel::FT; using Point_3 = typename Kernel::Point_3; using Vector_3 = typename Kernel::Vector_3; -using TAG = CGAL::Parallel_if_available_tag; +using TAG = CGAL::Sequential_tag; using Surface_mesh = CGAL::Surface_mesh; using Polyhedron = CGAL::Polyhedron_3; using Affine_transformation_3 = CGAL::Aff_transformation_3; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 9d5310a954f..04f0c1375ea 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1559,7 +1559,7 @@ double bounded_error_Hausdorff_impl( // The upper bound of this triangle is the actual Hausdorff distance of // the triangle to the second mesh. Use it as new global lower bound. - // TODO: update the reference to the realizing triangle here as this is the best current guess. + // Here, we update the reference to the realizing triangle as this is the best current guess. global_bounds.lower = triangle_bounds.upper; global_bounds.lpair.second = triangle_bounds.tm2_uface; continue; @@ -1703,6 +1703,7 @@ struct Bounded_error_preprocessing { return operand.type() == typeid(TM2Wrapper); } + // TODO: make AABB tree build parallel! void operator()(const tbb::blocked_range& range) { Timer timer; timer.reset(); @@ -1854,15 +1855,19 @@ double bounded_error_one_sided_Hausdorff_impl( Timer timer; std::cout.precision(20); - const int nb_cores = 4; // TODO: add to NP! - std::cout << "* num cores: " << nb_cores << std::endl; + // TODO: add to NP! + const int nb_cores = 4; + const std::size_t min_nb_faces_to_split = 100; // TODO: increase this number? + // std::cout << "* num cores: " << nb_cores << std::endl; TM1_tree tm1_tree; TM2_tree tm2_tree; FT infinity_value = -FT(1); #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) - if (boost::is_convertible::value && nb_cores > 1) { + if ( + boost::is_convertible::value && + nb_cores > 1 && faces(tm1).size() >= min_nb_faces_to_split) { // (1) -- Create partition of tm1. timer.reset(); @@ -1873,8 +1878,8 @@ double bounded_error_one_sided_Hausdorff_impl( tm1, nb_cores, CGAL::parameters:: face_partition_id_map(face_pid_map)); timer.stop(); - const double time1 = timer.time(); - std::cout << "- computing partition time (sec.): " << time1 << std::endl; + // const double time1 = timer.time(); + // std::cout << "- computing partition time (sec.): " << time1 << std::endl; // (2) -- Create a filtered face graph for each part. timer.reset(); @@ -1882,13 +1887,13 @@ double bounded_error_one_sided_Hausdorff_impl( tm1_parts.reserve(nb_cores); for (int i = 0; i < nb_cores; ++i) { tm1_parts.emplace_back(tm1, i, face_pid_map); - CGAL_assertion(tm1_parts.back().is_selection_valid()); - std::cout << "- part " << i << " size: " << tm1_parts.back().number_of_faces() << std::endl; + // CGAL_assertion(tm1_parts.back().is_selection_valid()); // TODO: why is it triggered sometimes? + // std::cout << "- part " << i << " size: " << tm1_parts.back().number_of_faces() << std::endl; } CGAL_assertion(tm1_parts.size() == nb_cores); timer.stop(); - const double time2 = timer.time(); - std::cout << "- creating graphs time (sec.): " << time2 << std::endl; + // const double time2 = timer.time(); + // std::cout << "- creating graphs time (sec.): " << time2 << std::endl; // (3) -- Preprocess all input data. timer.reset(); @@ -1916,9 +1921,9 @@ double bounded_error_one_sided_Hausdorff_impl( tbb::parallel_reduce(tbb::blocked_range(0, tm_wrappers.size()), bep); timer.stop(); - const double time3 = timer.time(); - std::cout << "- creating trees time (sec.) " << time3 << std::endl; - std::cout << "* preprocessing parallel time (sec.) " << time1 + time2 + time3 << std::endl; + // const double time3 = timer.time(); + // std::cout << "- creating trees time (sec.) " << time3 << std::endl; + // std::cout << "* preprocessing parallel time (sec.) " << time1 + time2 + time3 << std::endl; } else // sequential version #endif // defined(CGAL_LINKED_WITH_TBB) && METIS @@ -1936,10 +1941,10 @@ double bounded_error_one_sided_Hausdorff_impl( tm1_tree.build(); tm2_tree.build(); timer.stop(); - std::cout << "* preprocessing sequential time (sec.) " << timer.time() << std::endl; + // std::cout << "* preprocessing sequential time (sec.) " << timer.time() << std::endl; } - std::cout << "* infinity_value: " << infinity_value << std::endl; + // std::cout << "* infinity_value: " << infinity_value << std::endl; if (infinity_value < FT(0)) { // std::cout << "* culling rate: 100%" << std::endl; return 0.0; // TM1 is part of TM2 so the distance is zero @@ -1953,9 +1958,11 @@ double bounded_error_one_sided_Hausdorff_impl( timer.start(); #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) - if (boost::is_convertible::value && nb_cores > 1) { + if ( + boost::is_convertible::value && + nb_cores > 1 && faces(tm1).size() >= min_nb_faces_to_split) { - std::cout << "* executing parallel version " << std::endl; + // std::cout << "* executing parallel version " << std::endl; Bounded_error_distance_computation bedc( tm1_parts, tm2, error_bound, vpm1, vpm2, infinity_value, initial_lower_bound, tm1_trees, tm2_tree); @@ -1965,19 +1972,20 @@ double bounded_error_one_sided_Hausdorff_impl( } else // sequential version #endif // defined(CGAL_LINKED_WITH_TBB) && METIS { - std::cout << "* executing sequential version " << std::endl; + // std::cout << "* executing sequential version " << std::endl; hdist = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, vpm1, vpm2, infinity_value, initial_lower_bound, tm1_tree, tm2_tree); } timer.stop(); - std::cout << "* computation time (sec.) " << timer.time() << std::endl; + // std::cout << "* computation time (sec.) " << timer.time() << std::endl; CGAL_assertion(hdist >= 0.0); return hdist; } +// TODO: should we add a parallel version here? template< class Concurrency_tag, class Kernel, class TriangleMesh1, @@ -1996,6 +2004,12 @@ double bounded_error_symmetric_Hausdorff_impl( const NamedParameters1& np1, const NamedParameters2& np2) { + #if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg( + !(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); + #endif + // Naive version. // const double hdist1 = bounded_error_one_sided_Hausdorff_impl( // tm1, tm2, error_bound, compare_meshes, vpm1, vpm2, np1, np2); diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index a067b8d6d0e..ee7be943420 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -109,13 +109,13 @@ create_single_source_cgal_program("triangulate_hole_with_cdt_2_test.cpp") create_single_source_cgal_program("test_pmp_polyhedral_envelope.cpp") # create_single_source_cgal_program("test_pmp_repair_self_intersections.cpp") -# find_package(METIS) -# include(CGAL_METIS_support) -# if(TARGET CGAL::METIS_support) -# target_link_libraries(test_hausdorff_bounded_error_distance PUBLIC CGAL::METIS_support) -# else() -# message(STATUS "Tests, which use the METIS library will not be compiled.") -# endif() +find_package(METIS) +include(CGAL_METIS_support) +if(TARGET CGAL::METIS_support) + target_link_libraries(test_hausdorff_bounded_error_distance PUBLIC CGAL::METIS_support) +else() + message(STATUS "Tests, which use the METIS library will not be compiled.") +endif() if(TARGET CGAL::TBB_support) target_link_libraries(test_hausdorff_bounded_error_distance PUBLIC CGAL::TBB_support) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 478d1401e71..d4ea584c212 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -861,6 +861,17 @@ void test_parallel_version( std::cout << "* distb par = " << distb << std::endl; } +void test_early_quit( + const std::string filepath, const double /*error_bound*/, const double /*max_distance*/) { + + std::cout.precision(20); + std::cout << std::endl << "-- test early quit:" << std::endl << std::endl; + + Timer timer; + Surface_mesh mesh1, mesh2; + get_meshes(filepath, filepath, mesh1, mesh2); +} + int main(int argc, char** argv) { // std::string name; @@ -868,8 +879,10 @@ int main(int argc, char** argv) { const double error_bound = 1e-4; const std::size_t num_samples = 1000; + const double max_distance = 1.0; std::cout << std::endl << "* error bound: " << error_bound << std::endl; std::cout << std::endl << "* number of samples: " << num_samples << std::endl; + std::cout << std::endl << "* max distance: " << max_distance << std::endl; std::string filepath = (argc > 1 ? argv[1] : "data/blobby.off"); // ------------------------------------------------------------------------ // @@ -884,7 +897,7 @@ int main(int argc, char** argv) { // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); - // test_synthetic_data(bound_hd); + test_synthetic_data(bound_hd); // --- Compare on common meshes. @@ -903,8 +916,8 @@ int main(int argc, char** argv) { // --- Compare timings. - // filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); - filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; + filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); + // filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); // test_timings(filepath, bound_hd); @@ -919,7 +932,10 @@ int main(int argc, char** argv) { // test_realizing_triangles(error_bound); // --- Test parallelization. - test_parallel_version(filepath, error_bound); + // test_parallel_version(filepath, error_bound); + + // --- Test early quit. + test_early_quit(filepath, error_bound, max_distance); // ------------------------------------------------------------------------ // From 00f4a52b0aabc8a4b0e9880e29cc897379d89da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 6 May 2021 15:50:19 +0200 Subject: [PATCH 198/349] missing header --- .../include/CGAL/Polygon_mesh_processing/distance.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 9d5310a954f..8e55f4bf239 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1773,6 +1774,7 @@ struct Bounded_error_distance_computation { timer.reset(); timer.start(); double hdist = -1.0; + for (std::size_t i = range.begin(); i != range.end(); ++i) { CGAL_assertion(i < tm1_parts.size()); CGAL_assertion(i < tm1_trees.size()); @@ -1812,10 +1814,10 @@ double bounded_error_one_sided_Hausdorff_impl( const NamedParameters1& np1, const NamedParameters2& np2) { - #if !defined(CGAL_LINKED_WITH_TBB) + #if !defined(CGAL_LINKED_WITH_TBB) || !defined(CGAL_METIS_ENABLED) CGAL_static_assertion_msg( !(boost::is_convertible::value), - "Parallel_tag is enabled but TBB is unavailable."); + "Parallel_tag is enabled but at least TBB or METIS is unavailable."); #endif using FT = typename Kernel::FT; From dbfca543580339a007118ded8f8a3c8ae2070b43 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Sun, 9 May 2021 16:08:42 +0200 Subject: [PATCH 199/349] hide the parallel version behind ifdefs --- .../CGAL/Polygon_mesh_processing/distance.h | 38 ++++++++++--------- .../test_hausdorff_bounded_error_distance.cpp | 4 ++ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 5a25097198d..27d217be6cd 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1323,6 +1323,9 @@ double approximate_symmetric_Hausdorff_distance(const TriangleMesh& tm1, //////////////////////////////////////////////////////////////////////// +// Use this def in order to get back the parallel version of the one-sided Hausdorff code! +// #define USE_PARALLEL_BEHD + namespace internal { template< class Kernel, @@ -1588,10 +1591,10 @@ double bounded_error_Hausdorff_impl( Triangle_3(v0, v01, v02), Triangle_3(v1 , v01, v12), Triangle_3(v2, v02, v12), Triangle_3(v01, v02, v12) }; - // Send each of the four triangles to Culling on B with the bounds of the parent triangle. + // Send each of the four triangles to culling on B with the bounds of the parent triangle. for (std::size_t i = 0; i < 4; ++i) { - // Call Culling on B with the single triangle found. + // Call culling on B with the single triangle found. TM2_hd_traits traversal_traits_tm2( tm2_tree.traits(), tm2, vpm2, triangle_bounds, @@ -1660,7 +1663,7 @@ double bounded_error_Hausdorff_impl( return hdist; } -#if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) +#if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) && defined(USE_PARALLEL_BEHD) template struct Triangle_mesh_wrapper { @@ -1795,7 +1798,8 @@ struct Bounded_error_distance_computation { distance = (CGAL::max)(rhs.distance, distance); } }; -#endif // defined(CGAL_LINKED_WITH_TBB) && METIS + +#endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) template< class Concurrency_tag, class Kernel, @@ -1840,7 +1844,7 @@ double bounded_error_one_sided_Hausdorff_impl( using Timer = CGAL::Real_timer; - #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) + #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) && defined(USE_PARALLEL_BEHD) using Point_3 = typename Kernel::Point_3; using TMF = CGAL::Face_filtered_graph; using TMF_primitive = AABB_face_graph_triangle_primitive; @@ -1852,21 +1856,21 @@ double bounded_error_one_sided_Hausdorff_impl( std::vector tm1_parts; std::vector tm1_trees; std::vector tm_wrappers; - #endif // defined(CGAL_LINKED_WITH_TBB) && METIS + #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) Timer timer; std::cout.precision(20); - // TODO: add to NP! - const int nb_cores = 4; - const std::size_t min_nb_faces_to_split = 100; // TODO: increase this number? - // std::cout << "* num cores: " << nb_cores << std::endl; - TM1_tree tm1_tree; TM2_tree tm2_tree; FT infinity_value = -FT(1); - #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) + #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) && defined(USE_PARALLEL_BEHD) + // TODO: add to NP! + const int nb_cores = 4; + const std::size_t min_nb_faces_to_split = 100; // TODO: increase this number? + // std::cout << "* num cores: " << nb_cores << std::endl; + if ( boost::is_convertible::value && nb_cores > 1 && faces(tm1).size() >= min_nb_faces_to_split) { @@ -1928,7 +1932,7 @@ double bounded_error_one_sided_Hausdorff_impl( // std::cout << "* preprocessing parallel time (sec.) " << time1 + time2 + time3 << std::endl; } else // sequential version - #endif // defined(CGAL_LINKED_WITH_TBB) && METIS + #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) { // std::cout << "* preprocessing sequential version " << std::endl; timer.reset(); @@ -1959,7 +1963,7 @@ double bounded_error_one_sided_Hausdorff_impl( timer.reset(); timer.start(); - #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) + #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) && defined(USE_PARALLEL_BEHD) if ( boost::is_convertible::value && nb_cores > 1 && faces(tm1).size() >= min_nb_faces_to_split) { @@ -1972,7 +1976,7 @@ double bounded_error_one_sided_Hausdorff_impl( hdist = bedc.distance; } else // sequential version - #endif // defined(CGAL_LINKED_WITH_TBB) && METIS + #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) { // std::cout << "* executing sequential version " << std::endl; hdist = bounded_error_Hausdorff_impl( @@ -2006,10 +2010,10 @@ double bounded_error_symmetric_Hausdorff_impl( const NamedParameters1& np1, const NamedParameters2& np2) { - #if !defined(CGAL_LINKED_WITH_TBB) + #if !defined(CGAL_LINKED_WITH_TBB) || !defined(CGAL_METIS_ENABLED) CGAL_static_assertion_msg( !(boost::is_convertible::value), - "Parallel_tag is enabled but TBB is unavailable."); + "Parallel_tag is enabled but at least TBB or METIS is unavailable."); #endif // Naive version. diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index d4ea584c212..0b2ece23fc3 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -818,6 +818,7 @@ void test_realizing_triangles( compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); } +#if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) && defined(USE_PARALLEL_BEHD) void test_parallel_version( const std::string filepath, const double error_bound) { @@ -860,6 +861,7 @@ void test_parallel_version( std::cout << "* dista seq = " << dista << std::endl; std::cout << "* distb par = " << distb << std::endl; } +#endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) void test_early_quit( const std::string filepath, const double /*error_bound*/, const double /*max_distance*/) { @@ -931,8 +933,10 @@ int main(int argc, char** argv) { // --- Test realizing triangles. // test_realizing_triangles(error_bound); + #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) && defined(USE_PARALLEL_BEHD) // --- Test parallelization. // test_parallel_version(filepath, error_bound); + #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) // --- Test early quit. test_early_quit(filepath, error_bound, max_distance); From 80c776c298caae96eee03443e68737fbde229b15 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Sun, 9 May 2021 17:02:35 +0200 Subject: [PATCH 200/349] added functions are_within_tolerance, not finished, fixing max funcs in naive --- .../CGAL/Polygon_mesh_processing/distance.h | 254 +++++++++++------- .../test_hausdorff_bounded_error_distance.cpp | 53 +++- 2 files changed, 199 insertions(+), 108 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 27d217be6cd..4374ef7c414 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1338,7 +1338,7 @@ template< class Kernel, class TM1Tree, class TM2Tree, class FaceHandle1, - class FaceHandle2> + class FaceHandle2 > std::pair preprocess_bounded_error_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, @@ -1449,7 +1449,7 @@ template< class Kernel, class VPM1, class VPM2, class TM1Tree, - class TM2Tree> + class TM2Tree > double bounded_error_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, @@ -1738,7 +1738,7 @@ template< class TriangleMesh1, class VPM2, class TM1Tree, class TM2Tree, - class Kernel> + class Kernel > struct Bounded_error_distance_computation { using FT = typename Kernel::FT; @@ -1808,7 +1808,7 @@ template< class Concurrency_tag, class VPM1, class VPM2, class NamedParameters1, - class NamedParameters2> + class NamedParameters2 > double bounded_error_one_sided_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, @@ -1999,7 +1999,7 @@ template< class Concurrency_tag, class VPM1, class VPM2, class NamedParameters1, - class NamedParameters2> + class NamedParameters2 > double bounded_error_symmetric_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, @@ -2100,112 +2100,103 @@ double bounded_error_symmetric_Hausdorff_impl( return (CGAL::max)(dista, distb); } -template +template typename Kernel::FT recursive_hausdorff_subdivision( - const Point_3& v0, - const Point_3& v1, - const Point_3& v2, + const typename Kernel::Point_3& v0, + const typename Kernel::Point_3& v1, + const typename Kernel::Point_3& v2, const TM2_tree& tm2_tree, - const typename Kernel::FT& squared_error_bound) + const typename Kernel::FT squared_error_bound) { // If all edge lengths of the triangle are below the error_bound, // return maximum of the distances of the three points to TM2 (via TM2_tree). const auto max_squared_edge_length = - std::max( - std::max( - squared_distance( v0, v1 ), - squared_distance( v0, v2 )), - squared_distance( v1, v2 ) - ); - if ( max_squared_edge_length < squared_error_bound ) { - return std::max( - std::max( - squared_distance( v0, tm2_tree.closest_point(v0) ), - squared_distance( v1, tm2_tree.closest_point(v1) ) ), - squared_distance( v2, tm2_tree.closest_point(v2) ) - ); + (CGAL::max)( + (CGAL::max)( + CGAL::squared_distance(v0, v1), + CGAL::squared_distance(v0, v2)), + CGAL::squared_distance(v1, v2)); + + if (max_squared_edge_length < squared_error_bound) { + return (CGAL::max)( + (CGAL::max)( + CGAL::squared_distance(v0, tm2_tree.closest_point(v0)), + CGAL::squared_distance(v1, tm2_tree.closest_point(v1))), + CGAL::squared_distance(v2, tm2_tree.closest_point(v2))); } - // Else subdivide the triangle and proceed recursively - const Point_3 v01 = midpoint( v0, v1 ); - const Point_3 v02 = midpoint( v0, v2 ); - const Point_3 v12 = midpoint( v1, v2 ); + // Else subdivide the triangle and proceed recursively. + const auto v01 = midpoint(v0, v1); + const auto v02 = midpoint(v0, v2); + const auto v12 = midpoint(v1, v2); - return std::max ( - std::max( - recursive_hausdorff_subdivision( v0,v01,v02,tm2_tree,squared_error_bound ), - recursive_hausdorff_subdivision( v1,v01,v12,tm2_tree,squared_error_bound ) - ), - std::max( - recursive_hausdorff_subdivision( v2,v02,v12,tm2_tree,squared_error_bound ), - recursive_hausdorff_subdivision( v01,v02,v12,tm2_tree,squared_error_bound ) - ) - ); + return (CGAL::max)( + (CGAL::max)( + recursive_hausdorff_subdivision(v0, v01, v02, tm2_tree, squared_error_bound), + recursive_hausdorff_subdivision(v1, v01, v12, tm2_tree, squared_error_bound)), + (CGAL::max)( + recursive_hausdorff_subdivision(v2 , v02, v12, tm2_tree, squared_error_bound), + recursive_hausdorff_subdivision(v01, v02, v12, tm2_tree, squared_error_bound))); } -template + class VPM2 > double bounded_error_Hausdorff_naive_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, - const typename Kernel::FT& error_bound, - VPM1 vpm1, - VPM2 vpm2) + const typename Kernel::FT error_bound, + const VPM1& vpm1, + const VPM2& vpm2) { - CGAL_assertion_code( const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2) ); - CGAL_assertion_msg (is_triangle, - "One of the meshes is not triangulated. Distance computing impossible."); + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Triangle_3 = typename Kernel::Triangle_3; - typedef AABB_face_graph_triangle_primitive TM2_primitive; - typedef AABB_tree< AABB_traits > TM2_tree; + using TM2_primitive = AABB_face_graph_triangle_primitive; + using TM2_traits = AABB_traits; + using TM2_tree = AABB_tree; - typedef typename boost::graph_traits::face_descriptor face_descriptor_1; + using TM1_face_to_triangle_map = Triangle_from_face_descriptor_map; - typedef typename Kernel::FT FT; - typedef typename Kernel::Point_3 Point_3; - typedef typename Kernel::Triangle_3 Triangle_3; - - // Initially, no lower bound is known + // Initially, no lower bound is known. FT squared_lower_bound = FT(0); - // Work with squares in the following, only draw sqrt at the very end + + // Work with squares in the following, only draw sqrt at the very end. const FT squared_error_bound = error_bound * error_bound; - // Build an AABB tree on tm2 - TM2_tree tm2_tree( faces(tm2).begin(), faces(tm2).end(), tm2, vpm2 ); + // Build an AABB tree on tm2. + TM2_tree tm2_tree(faces(tm2).begin(), faces(tm2).end(), tm2, vpm2); tm2_tree.build(); tm2_tree.accelerate_distance_queries(); // Build a map to obtain actual triangles from the face descriptors of tm1. - const Triangle_from_face_descriptor_map face_to_triangle_map( &tm1, vpm1 ); + const TM1_face_to_triangle_map face_to_triangle_map(&tm1, vpm1); + + // Iterate over the faces of TM1. + for (const auto& face : faces(tm1)) { - // Iterate over the triangles of TM1. - for(face_descriptor_1 fd : faces(tm1)) - { // Get the vertices of the face and pass them on to a recursive method. - const Triangle_3 triangle = get(face_to_triangle_map, fd); + const Triangle_3 triangle = get(face_to_triangle_map, face); const Point_3 v0 = triangle.vertex(0); const Point_3 v1 = triangle.vertex(1); const Point_3 v2 = triangle.vertex(2); - // Recursively process the current triangle to obtain a lower bound on - // its Hausdorff distance. - const FT triangle_bound = recursive_hausdorff_subdivision( - v0, v1, v2, tm2_tree, squared_error_bound ); + // Recursively process the current triangle to obtain a lower bound on its Hausdorff distance. + const FT triangle_bound = recursive_hausdorff_subdivision( + v0, v1, v2, tm2_tree, squared_error_bound); // Store the largest lower bound. - if( triangle_bound > squared_lower_bound ) { + if (triangle_bound > squared_lower_bound) { squared_lower_bound = triangle_bound; } } - // Return linear interpolation between found upper and lower bound - return CGAL::sqrt(CGAL::to_double( squared_lower_bound )); + // Return linear interpolation between found upper and lower bound. + return CGAL::sqrt(CGAL::to_double(squared_lower_bound)); } } // end of namespace internal @@ -2313,7 +2304,7 @@ template< class Concurrency_tag, double bounded_error_Hausdorff_distance( const TriangleMesh1& tm1, const TriangleMesh2& tm2, - const double error_bound) + const double error_bound = 0.0001) { return bounded_error_Hausdorff_distance( tm1, tm2, error_bound, parameters::all_default()); @@ -2388,67 +2379,128 @@ template< class Concurrency_tag, double bounded_error_symmetric_Hausdorff_distance( const TriangleMesh1& tm1, const TriangleMesh2& tm2, - const double error_bound) + const double error_bound = 0.0001) { return bounded_error_symmetric_Hausdorff_distance( tm1, tm2, error_bound, parameters::all_default()); } -/* - * Implementation of naive Bounded Hausdorff distance computation. +/** + * \ingroup PMP_distance_grp + * returns `true` if two meshes are within the user-defined max distance, + * otherwise it returns `false`. The distance used to compute the proximity + * of the meshes is the `bounded_error_Hausdorff_distance`. + * + * Instead of computing the full distance and checking it against the user-provided + * value, this function early quits in case certain criteria show that the meshes + * do not satisfy the provided max distance. + * + * @return Boolean `true` or `false` */ template< class Concurrency_tag, class TriangleMesh1, class TriangleMesh2, class NamedParameters1, - class NamedParameters2> -double bounded_error_Hausdorff_distance_naive( const TriangleMesh1& tm1, - const TriangleMesh2& tm2, - double error_bound, - const NamedParameters1& np1, - const NamedParameters2& np2) + class NamedParameters2 > +bool are_within_tolerance( + const TriangleMesh1& /* tm1 */, + const TriangleMesh2& /* tm2 */, + const double /* max_distance */, + const double /* error_bound */, + const NamedParameters1& /* np1 */, + const NamedParameters2& /* np2 */) { - typedef typename GetGeomTraits::type Geom_traits; - using FT = typename Geom_traits::FT; + CGAL_assertion_msg(false, "TODO: FINISH THE DISTANCE TOLERANCE FUNCTION!"); + return false; +} - typedef typename GetVertexPointMap::const_type Vpm1; - typedef typename GetVertexPointMap::const_type Vpm2; +template< class Concurrency_tag, + class TriangleMesh1, + class TriangleMesh2, + class NamedParameters1 > +double are_within_tolerance( + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + const double max_distance, + const double error_bound, + const NamedParameters1& np1) +{ + return are_within_tolerance( + tm1, tm2, max_distance, error_bound, np1, parameters::all_default()); +} + +template< class Concurrency_tag, + class TriangleMesh1, + class TriangleMesh2 > +double are_within_tolerance( + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + const double max_distance = 1.0, + const double error_bound = 0.0001) +{ + return are_within_tolerance( + tm1, tm2, max_distance, error_bound, parameters::all_default()); +} + +// Implementation of the naive Bounded Error Hausdorff distance. +template< class Concurrency_tag, + class TriangleMesh1, + class TriangleMesh2, + class NamedParameters1, + class NamedParameters2 > +double bounded_error_Hausdorff_distance_naive( + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + const double error_bound, + const NamedParameters1& np1, + const NamedParameters2& np2) +{ + CGAL_assertion_code( + const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2)); + CGAL_assertion_msg(is_triangle, + "Both meshes must be triangulated to compute this distance!"); + + using Traits = typename GetGeomTraits::type; + using FT = typename Traits::FT; using parameters::choose_parameter; using parameters::get_parameter; - Vpm1 vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), - get_const_property_map(vertex_point, tm1)); - Vpm2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), - get_const_property_map(vertex_point, tm2)); + const auto vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, tm1)); + const auto vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, tm2)); CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); - return internal::bounded_error_Hausdorff_naive_impl( + return internal::bounded_error_Hausdorff_naive_impl( tm1, tm2, error_threshold, vpm1, vpm2); } template< class Concurrency_tag, class TriangleMesh1, class TriangleMesh2, - class NamedParameters1> -double bounded_error_Hausdorff_distance_naive( const TriangleMesh1& tm1, - const TriangleMesh2& tm2, - double error_bound, - const NamedParameters1& np1) + class NamedParameters1 > +double bounded_error_Hausdorff_distance_naive( + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + const double error_bound, + const NamedParameters1& np1) { - return bounded_error_Hausdorff_distance_naive(tm1, tm2, error_bound, np1, parameters::all_default()); + return bounded_error_Hausdorff_distance_naive( + tm1, tm2, error_bound, np1, parameters::all_default()); } template< class Concurrency_tag, class TriangleMesh1, - class TriangleMesh2> -double bounded_error_Hausdorff_distance_naive( const TriangleMesh1& tm1, - const TriangleMesh2& tm2, - double error_bound) + class TriangleMesh2 > +double bounded_error_Hausdorff_distance_naive( + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + const double error_bound = 0.0001) { - return bounded_error_Hausdorff_distance_naive(tm1, tm2, error_bound, parameters::all_default() ); + return bounded_error_Hausdorff_distance_naive( + tm1, tm2, error_bound, parameters::all_default()); } } } // end of namespace CGAL::Polygon_mesh_processing diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 0b2ece23fc3..d4225a35e34 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -863,8 +863,7 @@ void test_parallel_version( } #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) -void test_early_quit( - const std::string filepath, const double /*error_bound*/, const double /*max_distance*/) { +void test_early_quit(const std::string filepath) { std::cout.precision(20); std::cout << std::endl << "-- test early quit:" << std::endl << std::endl; @@ -872,6 +871,48 @@ void test_early_quit( Timer timer; Surface_mesh mesh1, mesh2; get_meshes(filepath, filepath, mesh1, mesh2); + + std::cout << std::endl; + std::cout << " ---- distance 0.0 = 0.0 ---- " << std::endl; + timer.reset(); + timer.start(); + assert(PMP::are_within_tolerance(mesh1, mesh2, 0.0)); + timer.stop(); + const double timea = timer.time(); + + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(0.0, 0.0, 0.5)), mesh2); + + std::cout << " ---- distance 0.5 < 0.8 ---- " << std::endl; + timer.reset(); + timer.start(); + assert(PMP::are_within_tolerance(mesh1, mesh2, 0.8)); + timer.stop(); + const double timeb = timer.time(); + std::cout << " ---- distance 0.5 < 0.6 ---- " << std::endl; + timer.reset(); + timer.start(); + assert(PMP::are_within_tolerance(mesh1, mesh2, 0.6)); + timer.stop(); + const double timec = timer.time(); + std::cout << " ---- distance 0.5 > 0.4 ---- " << std::endl; + timer.reset(); + timer.start(); + assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.4)); + timer.stop(); + const double timed = timer.time(); + std::cout << " ---- distance 0.5 > 0.2 ---- " << std::endl; + timer.reset(); + timer.start(); + assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.2)); + timer.stop(); + const double timee = timer.time(); + + std::cout << "* timea 0.0 = 0.0 = " << timea << std::endl; + std::cout << "* timeb 0.5 < 0.8 = " << timeb << std::endl; + std::cout << "* timec 0.5 < 0.6 = " << timec << std::endl; + std::cout << "* timed 0.5 > 0.4 = " << timed << std::endl; + std::cout << "* timee 0.5 > 0.2 = " << timee << std::endl; } int main(int argc, char** argv) { @@ -881,10 +922,8 @@ int main(int argc, char** argv) { const double error_bound = 1e-4; const std::size_t num_samples = 1000; - const double max_distance = 1.0; std::cout << std::endl << "* error bound: " << error_bound << std::endl; - std::cout << std::endl << "* number of samples: " << num_samples << std::endl; - std::cout << std::endl << "* max distance: " << max_distance << std::endl; + // std::cout << std::endl << "* number of samples: " << num_samples << std::endl; std::string filepath = (argc > 1 ? argv[1] : "data/blobby.off"); // ------------------------------------------------------------------------ // @@ -899,7 +938,7 @@ int main(int argc, char** argv) { // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); - test_synthetic_data(bound_hd); + // test_synthetic_data(bound_hd); // --- Compare on common meshes. @@ -939,7 +978,7 @@ int main(int argc, char** argv) { #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) // --- Test early quit. - test_early_quit(filepath, error_bound, max_distance); + test_early_quit(filepath); // ------------------------------------------------------------------------ // From 77c2dc4d9604e2a8dfbbac48f3698cff34c23de6 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 10 May 2021 13:15:09 +0200 Subject: [PATCH 201/349] testing early quit --- .../CGAL/Polygon_mesh_processing/distance.h | 55 +++++++++++++++++-- ...traversal_traits_with_Hausdorff_distance.h | 2 + .../test_hausdorff_bounded_error_distance.cpp | 8 +-- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 4374ef7c414..ac9fbf3cc8e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -2385,6 +2385,9 @@ double bounded_error_symmetric_Hausdorff_distance( tm1, tm2, error_bound, parameters::all_default()); } +// TODO: Find better name! +// TODO: Should we use one-sided or symmetric distance here? + /** * \ingroup PMP_distance_grp * returns `true` if two meshes are within the user-defined max distance, @@ -2403,13 +2406,53 @@ template< class Concurrency_tag, class NamedParameters1, class NamedParameters2 > bool are_within_tolerance( - const TriangleMesh1& /* tm1 */, - const TriangleMesh2& /* tm2 */, - const double /* max_distance */, - const double /* error_bound */, - const NamedParameters1& /* np1 */, - const NamedParameters2& /* np2 */) + const TriangleMesh1& tm1, + const TriangleMesh2& tm2, + const double max_distance, + const double error_bound, + const NamedParameters1& np1, + const NamedParameters2& np2) { + CGAL_assertion_code( + const bool is_triangle = is_triangle_mesh(tm1) && is_triangle_mesh(tm2)); + CGAL_assertion_msg(is_triangle, + "Both meshes must be triangulated in order to be compared!"); + + using Traits = typename GetGeomTraits::type; + using FT = typename Traits::FT; + + const auto vpm1 = parameters::choose_parameter( + parameters::get_parameter(np1, internal_np::vertex_point), + get_const_property_map(vertex_point, tm1)); + const auto vpm2 = parameters::choose_parameter( + parameters::get_parameter(np2, internal_np::vertex_point), + get_const_property_map(vertex_point, tm2)); + + const bool match_faces1 = parameters::choose_parameter( + parameters::get_parameter(np1, internal_np::match_faces), true); + const bool match_faces2 = parameters::choose_parameter( + parameters::get_parameter(np2, internal_np::match_faces), true); + const bool match_faces = match_faces1 && match_faces2; + + // Naive version. + const bool use_one_sided = true; // TODO: Put in the NP! + CGAL_precondition(error_bound >= 0.0); + const FT error_threshold = static_cast(error_bound); + + double hdist = -1.0; + if (use_one_sided) { + hdist = internal::bounded_error_one_sided_Hausdorff_impl( + tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); + } else { + hdist = internal::bounded_error_symmetric_Hausdorff_impl( + tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); + } + CGAL_assertion(hdist >= 0.0); + + std::cout << "- fin distance: " << hdist << std::endl; + std::cout << "- max distance: " << max_distance << std::endl; + // return hdist <= max_distance; + CGAL_assertion_msg(false, "TODO: FINISH THE DISTANCE TOLERANCE FUNCTION!"); return false; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 714383a0cda..f25318cfc61 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -426,6 +426,8 @@ namespace CGAL { // See Algorithm 1 here. // If the distance is larger than the global lower bound, enter the node, i.e. return true. CGAL_assertion(h_global_bounds.lower >= FT(0)); + // const FT hdist = (h_global_bounds.lower + h_global_bounds.upper) / FT(2); + // std::cout << "- distance: " << hdist << std::endl; if (dist > h_global_bounds.lower) { return std::make_pair(true , +dist); } else { diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index d4225a35e34..617329d5b23 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -876,7 +876,7 @@ void test_early_quit(const std::string filepath) { std::cout << " ---- distance 0.0 = 0.0 ---- " << std::endl; timer.reset(); timer.start(); - assert(PMP::are_within_tolerance(mesh1, mesh2, 0.0)); + // assert(PMP::are_within_tolerance(mesh1, mesh2, 0.0)); timer.stop(); const double timea = timer.time(); @@ -892,19 +892,19 @@ void test_early_quit(const std::string filepath) { std::cout << " ---- distance 0.5 < 0.6 ---- " << std::endl; timer.reset(); timer.start(); - assert(PMP::are_within_tolerance(mesh1, mesh2, 0.6)); + // assert(PMP::are_within_tolerance(mesh1, mesh2, 0.6)); timer.stop(); const double timec = timer.time(); std::cout << " ---- distance 0.5 > 0.4 ---- " << std::endl; timer.reset(); timer.start(); - assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.4)); + // assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.4)); timer.stop(); const double timed = timer.time(); std::cout << " ---- distance 0.5 > 0.2 ---- " << std::endl; timer.reset(); timer.start(); - assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.2)); + // assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.2)); timer.stop(); const double timee = timer.time(); From 559815e6be47f4a0586113356216757b41e000cc Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 11 May 2021 10:37:03 +0200 Subject: [PATCH 202/349] added more assertions --- .../CGAL/Polygon_mesh_processing/distance.h | 16 ++++++++----- ...traversal_traits_with_Hausdorff_distance.h | 23 +++++++++++++++---- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index ac9fbf3cc8e..4cb5057c292 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1520,6 +1520,7 @@ double bounded_error_Hausdorff_impl( // See Section 5.1 in the paper. CGAL_assertion(global_bounds.lower >= FT(0)); CGAL_assertion(global_bounds.upper >= FT(0)); + CGAL_assertion(global_bounds.upper >= global_bounds.lower); const FT squared_error_bound = error_bound * error_bound; while ( (global_bounds.upper - global_bounds.lower > error_bound) && @@ -1538,6 +1539,7 @@ double bounded_error_Hausdorff_impl( CGAL_assertion(triangle_bounds.lower >= FT(0)); CGAL_assertion(triangle_bounds.upper >= FT(0)); + CGAL_assertion(triangle_bounds.upper >= triangle_bounds.lower); if ( (triangle_bounds.upper > global_bounds.lower) && @@ -1608,9 +1610,10 @@ double bounded_error_Hausdorff_impl( CGAL_assertion(local_bounds.lower >= FT(0)); CGAL_assertion(local_bounds.upper >= FT(0)); + CGAL_assertion(local_bounds.upper >= local_bounds.lower); - CGAL_precondition(local_bounds.lpair == local_bounds.default_face_pair()); - CGAL_precondition(local_bounds.upair == local_bounds.default_face_pair()); + CGAL_assertion(local_bounds.lpair == local_bounds.default_face_pair()); + CGAL_assertion(local_bounds.upair == local_bounds.default_face_pair()); if (local_bounds.lower > global_bounds.lower) { global_bounds.lower = local_bounds.lower; @@ -1642,6 +1645,7 @@ double bounded_error_Hausdorff_impl( // Compute linear interpolation between the found lower and upper bounds. CGAL_assertion(global_bounds.lower >= FT(0)); CGAL_assertion(global_bounds.upper >= FT(0)); + CGAL_assertion(global_bounds.upper >= global_bounds.lower); const double hdist = CGAL::to_double((global_bounds.lower + global_bounds.upper) / FT(2)); // Get realizing triangles. @@ -1651,10 +1655,10 @@ double bounded_error_Hausdorff_impl( // std::cout << "- found uface 1:" << static_cast(global_bounds.upair.first) << std::endl; // std::cout << "- found uface 2:" << static_cast(global_bounds.upair.second) << std::endl; - CGAL_precondition(global_bounds.lpair.first != boost::graph_traits::null_face()); - CGAL_precondition(global_bounds.lpair.second != boost::graph_traits::null_face()); - CGAL_precondition(global_bounds.upair.first != boost::graph_traits::null_face()); - CGAL_precondition(global_bounds.upair.second != boost::graph_traits::null_face()); + CGAL_assertion(global_bounds.lpair.first != boost::graph_traits::null_face()); + CGAL_assertion(global_bounds.lpair.second != boost::graph_traits::null_face()); + CGAL_assertion(global_bounds.upair.first != boost::graph_traits::null_face()); + CGAL_assertion(global_bounds.upair.second != boost::graph_traits::null_face()); // Off for the moment. // const auto realizing_triangles = global_bounds.upair; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index f25318cfc61..6e10604ab49 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -159,6 +159,10 @@ namespace CGAL { const FT distance_lower = (CGAL::max)((CGAL::max)(h_v0_lower, h_v1_lower), h_v2_lower); // it is (11) in the paper const FT distance_upper = (CGAL::max)((CGAL::max)(v0_dist, v1_dist), v2_dist); // it is () part of (10) in the paper + CGAL_assertion(distance_lower >= FT(0)); + CGAL_assertion(distance_upper >= FT(0)); + CGAL_assertion(distance_upper >= distance_lower); + // Since we are at the level of a single triangle in TM2, distance_upper is // actually the correct Hausdorff distance from the query triangle in // TM1 to the primitive triangle in TM2. @@ -172,6 +176,7 @@ namespace CGAL { h_local_bounds.upper = distance_upper; h_local_bounds.tm2_uface = primitive.id(); } + CGAL_assertion(h_local_bounds.upper >= h_local_bounds.lower); } // Determine whether child nodes will still contribute to a smaller @@ -317,8 +322,8 @@ namespace CGAL { h_global_bounds(m_infinity_value) { CGAL_precondition(m_error_bound >= FT(0)); - CGAL_precondition(m_infinity_value > FT(0)); - CGAL_precondition(initial_lower_bound >= m_error_bound); + CGAL_precondition(m_infinity_value >= FT(0)); + CGAL_precondition(m_error_bound <= initial_lower_bound); // Initialize the global bounds with 0, they will only grow. // If we leave zero here, then we are very slow even for big input error bounds! @@ -326,7 +331,7 @@ namespace CGAL { // which are already within this bound. It makes the code faster for close meshes. // We also use initial_lower_bound here to accelerate the symmetric distance computation. h_global_bounds.lower = initial_lower_bound; // = FT(0); - h_global_bounds.upper = m_error_bound; // = FT(0); + h_global_bounds.upper = initial_lower_bound; // = FT(0); } // Explore the whole tree, i.e. always enter children if the methods @@ -367,6 +372,7 @@ namespace CGAL { CGAL_assertion(local_bounds.lower >= FT(0)); CGAL_assertion(local_bounds.upper >= FT(0)); + CGAL_assertion(local_bounds.upper >= local_bounds.lower); CGAL_assertion(local_bounds.lpair == initial_bounds.default_face_pair()); CGAL_assertion(local_bounds.upair == initial_bounds.default_face_pair()); @@ -382,6 +388,7 @@ namespace CGAL { h_global_bounds.upair.first = fpair.first; h_global_bounds.upair.second = local_bounds.tm2_uface; } + CGAL_assertion(h_global_bounds.upper >= h_global_bounds.lower); // Store the triangle given as primitive here as candidate triangle // together with the local bounds it obtained to send it to subdivision later. @@ -425,9 +432,12 @@ namespace CGAL { // See Algorithm 1 here. // If the distance is larger than the global lower bound, enter the node, i.e. return true. - CGAL_assertion(h_global_bounds.lower >= FT(0)); + + // CGAL_assertion(h_global_bounds.upper >= h_global_bounds.lower); // const FT hdist = (h_global_bounds.lower + h_global_bounds.upper) / FT(2); // std::cout << "- distance: " << hdist << std::endl; + + CGAL_assertion(h_global_bounds.lower >= FT(0)); if (dist > h_global_bounds.lower) { return std::make_pair(true , +dist); } else { @@ -456,6 +466,11 @@ namespace CGAL { // Return the global Hausdorff bounds computed for the passed query triangle. Global_bounds get_global_bounds() { + + CGAL_assertion(h_global_bounds.lower >= FT(0)); + CGAL_assertion(h_global_bounds.upper >= FT(0)); + CGAL_assertion(h_global_bounds.upper >= h_global_bounds.lower); + update_global_bounds(); return h_global_bounds; } From acce02aae3b0e60e18e6449df7ca29e530b9a6a7 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 11 May 2021 12:39:38 +0200 Subject: [PATCH 203/349] do not build if inf value < 0 and added distance_bound, not finished --- .../CGAL/Polygon_mesh_processing/distance.h | 109 ++++++++++-------- ...traversal_traits_with_Hausdorff_distance.h | 13 ++- .../test_hausdorff_bounded_error_distance.cpp | 3 + 3 files changed, 73 insertions(+), 52 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 4cb5057c292..125b2184d33 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1434,9 +1434,6 @@ std::pair preprocess_bounded_error_Hausdorff_impl( tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); } - // tm1_tree.build(); - // tm2_tree.build(); - timer.stop(); // std::cout << "* .... end preprocessing" << std::endl; // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; @@ -1457,7 +1454,8 @@ double bounded_error_Hausdorff_impl( const VPM1& vpm1, const VPM2& vpm2, const typename Kernel::FT infinity_value, - const typename Kernel::FT initial_lower_bound, + const typename Kernel::FT initial_bound, + const typename Kernel::FT distance_bound, const TM1Tree& tm1_tree, const TM2Tree& tm2_tree) { @@ -1494,7 +1492,7 @@ double bounded_error_Hausdorff_impl( // Build traversal traits for tm1_tree. TM1_hd_traits traversal_traits_tm1( tm1_tree.traits(), tm2_tree, tm1, tm2, vpm1, vpm2, - error_bound, infinity_value, initial_lower_bound); + error_bound, infinity_value, initial_bound, distance_bound); // Find candidate triangles in TM1, which might realise the Hausdorff bound. // We build a sorted structure while collecting the candidates. @@ -1750,7 +1748,7 @@ struct Bounded_error_distance_computation { const std::vector& tm1_parts; const TriangleMesh2& tm2; const FT error_bound; const VPM1& vpm1; const VPM2& vpm2; - const FT infinity_value; const FT initial_lower_bound; + const FT infinity_value; const FT initial_bound; const std::vector& tm1_trees; const TM2Tree& tm2_tree; double distance; @@ -1758,11 +1756,11 @@ struct Bounded_error_distance_computation { Bounded_error_distance_computation( const std::vector& tm1_parts, const TriangleMesh2& tm2, const FT error_bound, const VPM1& vpm1, const VPM2& vpm2, - const FT infinity_value, const FT initial_lower_bound, + const FT infinity_value, const FT initial_bound, const std::vector& tm1_trees, const TM2Tree& tm2_tree) : tm1_parts(tm1_parts), tm2(tm2), error_bound(error_bound), vpm1(vpm1), vpm2(vpm2), - infinity_value(infinity_value), initial_lower_bound(initial_lower_bound), + infinity_value(infinity_value), initial_bound(initial_bound), tm1_trees(tm1_trees), tm2_tree(tm2_tree), distance(-1.0) { CGAL_assertion(tm1_parts.size() == tm1_trees.size()); } @@ -1772,7 +1770,7 @@ struct Bounded_error_distance_computation { Bounded_error_distance_computation& s, tbb::split) : tm1_parts(s.tm1_parts), tm2(s.tm2), error_bound(s.error_bound), vpm1(s.vpm1), vpm2(s.vpm2), - infinity_value(s.infinity_value), initial_lower_bound(s.initial_lower_bound), + infinity_value(s.infinity_value), initial_bound(s.initial_bound), tm1_trees(s.tm1_trees), tm2_tree(s.tm2_tree), distance(-1.0) { CGAL_assertion(tm1_parts.size() == tm1_trees.size()); } @@ -1788,9 +1786,12 @@ struct Bounded_error_distance_computation { CGAL_assertion(i < tm1_trees.size()); const auto& tm1 = tm1_parts[i]; const auto& tm1_tree = tm1_trees[i]; + // TODO: add distance_bound (now it is -FT(1)) in case we use parallel + // for checking if two meshes are close. const double dist = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, vpm1, vpm2, - infinity_value, initial_lower_bound, tm1_tree, tm2_tree); + infinity_value, initial_bound, -FT(1), + tm1_tree, tm2_tree); if (dist > hdist) hdist = dist; } if (hdist > distance) distance = hdist; @@ -1817,6 +1818,7 @@ double bounded_error_one_sided_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const typename Kernel::FT error_bound, + const typename Kernel::FT distance_bound, const bool compare_meshes, const VPM1& vpm1, const VPM2& vpm2, @@ -1879,6 +1881,21 @@ double bounded_error_one_sided_Hausdorff_impl( boost::is_convertible::value && nb_cores > 1 && faces(tm1).size() >= min_nb_faces_to_split) { + // (0) -- Compute infinity value. + timer.reset(); + timer.start(); + const auto bbox1 = bbox(tm1); + const auto bbox2 = bbox(tm2); + const auto bb = bbox1 + bbox2; + const FT sq_dist = CGAL::squared_distance( + Point_3(bb.xmin(), bb.ymin(), bb.zmin()), + Point_3(bb.xmax(), bb.ymax(), bb.zmax())); + infinity_value = CGAL::approximate_sqrt(sq_dist) * FT(2); + CGAL_assertion(infinity_value >= FT(0)); + timer.stop(); + // const double time0 = timer.time(); + // std::cout << "- computing infinity (sec.): " << time0 << std::endl; + // (1) -- Create partition of tm1. timer.reset(); timer.start(); @@ -1909,31 +1926,21 @@ double bounded_error_one_sided_Hausdorff_impl( timer.reset(); timer.start(); tm1_trees.resize(tm1_parts.size()); - - // Compute infinity value. - const auto bbox1 = bbox(tm1); - const auto bbox2 = bbox(tm2); - const auto bb = bbox1 + bbox2; - const FT sq_dist = CGAL::squared_distance( - Point_3(bb.xmin(), bb.ymin(), bb.zmin()), - Point_3(bb.xmax(), bb.ymax(), bb.zmax())); - infinity_value = CGAL::approximate_sqrt(sq_dist) * FT(2); - - CGAL_assertion(tm1_trees.size() == tm1_parts.size()); tm_wrappers.reserve(tm1_parts.size() + 1); for (std::size_t i = 0; i < tm1_parts.size(); ++i) { tm_wrappers.push_back(TM1_wrapper(tm1_parts[i], vpm1, false, tm1_trees[i])); } tm_wrappers.push_back(TM2_wrapper(tm2, vpm2, true, tm2_tree)); CGAL_assertion(tm_wrappers.size() == tm1_parts.size() + 1); - Bounded_error_preprocessing bep(tm_wrappers); tbb::parallel_reduce(tbb::blocked_range(0, tm_wrappers.size()), bep); - timer.stop(); // const double time3 = timer.time(); // std::cout << "- creating trees time (sec.) " << time3 << std::endl; - // std::cout << "* preprocessing parallel time (sec.) " << time1 + time2 + time3 << std::endl; + + // Final timing. + // std::cout << "* preprocessing parallel time (sec.) " << + // time0 + time1 + time2 + time3 << std::endl; } else // sequential version #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) @@ -1948,8 +1955,12 @@ double bounded_error_one_sided_Hausdorff_impl( tm1, tm2, compare_meshes, vpm1, vpm2, true, np1, np2, tm1_tree, tm2_tree, tm1_only, tm2_only); CGAL_assertion(!rebuild); - tm1_tree.build(); - tm2_tree.build(); + if (infinity_value >= FT(0)) { + tm1_tree.build(); + tm2_tree.build(); + tm1_tree.do_not_accelerate_distance_queries(); + tm2_tree.accelerate_distance_queries(); + } timer.stop(); // std::cout << "* preprocessing sequential time (sec.) " << timer.time() << std::endl; } @@ -1961,7 +1972,7 @@ double bounded_error_one_sided_Hausdorff_impl( } CGAL_assertion(error_bound >= FT(0)); CGAL_assertion(infinity_value > FT(0)); - const FT initial_lower_bound = error_bound; + const FT initial_bound = error_bound; std::atomic hdist; timer.reset(); @@ -1975,7 +1986,7 @@ double bounded_error_one_sided_Hausdorff_impl( // std::cout << "* executing parallel version " << std::endl; Bounded_error_distance_computation bedc( tm1_parts, tm2, error_bound, vpm1, vpm2, - infinity_value, initial_lower_bound, tm1_trees, tm2_tree); + infinity_value, initial_bound, tm1_trees, tm2_tree); tbb::parallel_reduce(tbb::blocked_range(0, tm1_parts.size()), bedc); hdist = bedc.distance; @@ -1985,7 +1996,8 @@ double bounded_error_one_sided_Hausdorff_impl( // std::cout << "* executing sequential version " << std::endl; hdist = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, vpm1, vpm2, - infinity_value, initial_lower_bound, tm1_tree, tm2_tree); + infinity_value, initial_bound, distance_bound, + tm1_tree, tm2_tree); } timer.stop(); @@ -2008,6 +2020,7 @@ double bounded_error_symmetric_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const typename Kernel::FT error_bound, + const typename Kernel::FT distance_bound, const bool compare_meshes, const VPM1& vpm1, const VPM2& vpm2, @@ -2021,10 +2034,11 @@ double bounded_error_symmetric_Hausdorff_impl( #endif // Naive version. + // TODO: we can use it for parallel version to simplify our life. // const double hdist1 = bounded_error_one_sided_Hausdorff_impl( - // tm1, tm2, error_bound, compare_meshes, vpm1, vpm2, np1, np2); + // tm1, tm2, error_bound, distance_bound, compare_meshes, vpm1, vpm2, np1, np2); // const double hdist2 = bounded_error_one_sided_Hausdorff_impl( - // tm2, tm1, error_bound, compare_meshes, vpm2, vpm1, np1, np2); + // tm2, tm1, error_bound, distance_bound, compare_meshes, vpm2, vpm1, np1, np2); // return (CGAL::max)(hdist1, hdist2); // Optimized version. @@ -2049,6 +2063,7 @@ double bounded_error_symmetric_Hausdorff_impl( std::vector tm1_only; std::vector tm2_only; + // All trees below are built and/or accelerated lazily. TM1_tree tm1_tree; TM2_tree tm2_tree; FT infinity_value = -FT(1); @@ -2064,16 +2079,14 @@ double bounded_error_symmetric_Hausdorff_impl( CGAL_assertion(infinity_value > FT(0)); // Compute the first one-sided distance. - FT initial_lower_bound = error_bound; + FT initial_bound = error_bound; double dista = CGAL::to_double(error_bound); - tm1_tree.build(); - tm2_tree.build(); - if (!compare_meshes || (compare_meshes && tm1_only.size() > 0)) { dista = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, vpm1, vpm2, - infinity_value, initial_lower_bound, tm1_tree, tm2_tree); + infinity_value, initial_bound, distance_bound, + tm1_tree, tm2_tree); } // In case this is true, we need to rebuild trees in order to accelerate @@ -2086,18 +2099,17 @@ double bounded_error_symmetric_Hausdorff_impl( CGAL_assertion(tm2_only.size() < faces(tm2).size()); tm1_tree.insert(faces(tm1).begin(), faces(tm1).end(), tm1, vpm1); tm2_tree.insert(tm2_only.begin(), tm2_only.end(), tm2, vpm2); - tm1_tree.build(); - tm2_tree.build(); } // Compute the second one-sided distance. - initial_lower_bound = static_cast(dista); // TODO: we should better test this optimization! + initial_bound = static_cast(dista); // TODO: we should better test this optimization! double distb = CGAL::to_double(error_bound); if (!compare_meshes || (compare_meshes && tm2_only.size() > 0)) { distb = bounded_error_Hausdorff_impl( tm2, tm1, error_bound, vpm2, vpm1, - infinity_value, initial_lower_bound, tm2_tree, tm1_tree); + infinity_value, initial_bound, distance_bound, + tm2_tree, tm1_tree); } // Return the maximum. @@ -2285,7 +2297,7 @@ double bounded_error_Hausdorff_distance( CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); return internal::bounded_error_one_sided_Hausdorff_impl( - tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); + tm1, tm2, error_threshold, -FT(1), match_faces, vpm1, vpm2, np1, np2); } template< class Concurrency_tag, @@ -2360,7 +2372,7 @@ double bounded_error_symmetric_Hausdorff_distance( CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); return internal::bounded_error_symmetric_Hausdorff_impl( - tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); + tm1, tm2, error_threshold, -FT(1), match_faces, vpm1, vpm2, np1, np2); } template< class Concurrency_tag, @@ -2412,7 +2424,7 @@ template< class Concurrency_tag, bool are_within_tolerance( const TriangleMesh1& tm1, const TriangleMesh2& tm2, - const double max_distance, + const double distance_bound, const double error_bound, const NamedParameters1& np1, const NamedParameters2& np2) @@ -2438,24 +2450,25 @@ bool are_within_tolerance( parameters::get_parameter(np2, internal_np::match_faces), true); const bool match_faces = match_faces1 && match_faces2; - // Naive version. const bool use_one_sided = true; // TODO: Put in the NP! CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); + CGAL_precondition(distance_bound >= 0.0); + const FT distance_threshold = static_cast(distance_bound); double hdist = -1.0; if (use_one_sided) { hdist = internal::bounded_error_one_sided_Hausdorff_impl( - tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); + tm1, tm2, error_threshold, distance_threshold, match_faces, vpm1, vpm2, np1, np2); } else { hdist = internal::bounded_error_symmetric_Hausdorff_impl( - tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2); + tm1, tm2, error_threshold, distance_threshold, match_faces, vpm1, vpm2, np1, np2); } CGAL_assertion(hdist >= 0.0); std::cout << "- fin distance: " << hdist << std::endl; - std::cout << "- max distance: " << max_distance << std::endl; - // return hdist <= max_distance; + std::cout << "- max distance: " << distance_bound << std::endl; + // return hdist <= distance_bound; CGAL_assertion_msg(false, "TODO: FINISH THE DISTANCE TOLERANCE FUNCTION!"); return false; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 6e10604ab49..51f238b89e8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -311,7 +311,8 @@ namespace CGAL { const VPM1& vpm1, const VPM2& vpm2, const FT error_bound, const FT infinity_value, - const FT initial_lower_bound) : + const FT initial_bound, + const FT distance_bound) : m_traits(traits), m_tm1(tm1), m_tm2(tm2), m_vpm1(vpm1), m_vpm2(vpm2), @@ -319,19 +320,21 @@ namespace CGAL { m_face_to_triangle_map(&m_tm1, m_vpm1), m_error_bound(error_bound), m_infinity_value(infinity_value), + m_initial_bound(initial_bound), + m_distance_bound(distance_bound), h_global_bounds(m_infinity_value) { CGAL_precondition(m_error_bound >= FT(0)); CGAL_precondition(m_infinity_value >= FT(0)); - CGAL_precondition(m_error_bound <= initial_lower_bound); + CGAL_precondition(m_initial_bound >= m_error_bound); // Initialize the global bounds with 0, they will only grow. // If we leave zero here, then we are very slow even for big input error bounds! // Instead, we can use m_error_bound as our initial guess to filter out all pairs, // which are already within this bound. It makes the code faster for close meshes. // We also use initial_lower_bound here to accelerate the symmetric distance computation. - h_global_bounds.lower = initial_lower_bound; // = FT(0); - h_global_bounds.upper = initial_lower_bound; // = FT(0); + h_global_bounds.lower = m_initial_bound; // = FT(0); + h_global_bounds.upper = m_initial_bound; // = FT(0); } // Explore the whole tree, i.e. always enter children if the methods @@ -518,6 +521,8 @@ namespace CGAL { // Internal bounds and values. const FT m_error_bound; const FT m_infinity_value; + const FT m_initial_bound; + const FT m_distance_bound; Global_bounds h_global_bounds; // All candidate triangles. diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 617329d5b23..4537e06b23a 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -1,3 +1,6 @@ +// Use it to include parallel computations in the bounded error Hausdorff distance. +// #define USE_PARALLEL_BEHD + #include #include #include From 73e9e867c20742e2b8dcc65a0606118094c00c46 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 11 May 2021 14:18:49 +0200 Subject: [PATCH 204/349] added early quit option to accelerate distance vs user defined distance check --- .../CGAL/Polygon_mesh_processing/distance.h | 31 ++++++++++++----- ...traversal_traits_with_Hausdorff_distance.h | 33 ++++++++++++++----- .../test_hausdorff_bounded_error_distance.cpp | 8 ++--- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 125b2184d33..f8ef099978a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1509,6 +1509,18 @@ double bounded_error_Hausdorff_impl( timer.stop(); // std::cout << "* culling (sec.): " << timer.time() << std::endl; + CGAL_assertion(global_bounds.lower >= FT(0)); + CGAL_assertion(global_bounds.upper >= FT(0)); + CGAL_assertion(global_bounds.upper >= global_bounds.lower); + + // If we already reached the user-defined max distance bound, we quit. + if (traversal_traits_tm1.early_quit()) { + CGAL_assertion(distance_bound >= FT(0)); + const double hdist = CGAL::to_double((global_bounds.lower + global_bounds.upper) / FT(2)); + return hdist; + } + CGAL_assertion(!traversal_traits_tm1.early_quit()); + // Second, we apply subdivision. // std::cout << "- applying subdivision" << std::endl; @@ -1516,14 +1528,18 @@ double bounded_error_Hausdorff_impl( timer.start(); // See Section 5.1 in the paper. - CGAL_assertion(global_bounds.lower >= FT(0)); - CGAL_assertion(global_bounds.upper >= FT(0)); - CGAL_assertion(global_bounds.upper >= global_bounds.lower); const FT squared_error_bound = error_bound * error_bound; while ( (global_bounds.upper - global_bounds.lower > error_bound) && !candidate_triangles.empty()) { + // Check if we can early quit. + if (distance_bound >= FT(0)) { + const FT hdist = (global_bounds.lower + global_bounds.upper) / FT(2); + const bool early_quit = (hdist >= distance_bound); + if (early_quit) break; + } + // Get the first triangle and its Hausdorff bounds from the candidate set. const Candidate triangle_and_bound = candidate_triangles.top(); // Remove it from the candidate set as it will be processed now. @@ -2466,12 +2482,9 @@ bool are_within_tolerance( } CGAL_assertion(hdist >= 0.0); - std::cout << "- fin distance: " << hdist << std::endl; - std::cout << "- max distance: " << distance_bound << std::endl; - // return hdist <= distance_bound; - - CGAL_assertion_msg(false, "TODO: FINISH THE DISTANCE TOLERANCE FUNCTION!"); - return false; + // std::cout << "- fin distance: " << hdist << std::endl; + // std::cout << "- max distance: " << distance_bound << std::endl; + return hdist <= distance_bound; } template< class Concurrency_tag, diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index 51f238b89e8..c9e051290fa 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -322,7 +322,8 @@ namespace CGAL { m_infinity_value(infinity_value), m_initial_bound(initial_bound), m_distance_bound(distance_bound), - h_global_bounds(m_infinity_value) { + h_global_bounds(m_infinity_value), + m_early_quit(false) { CGAL_precondition(m_error_bound >= FT(0)); CGAL_precondition(m_infinity_value >= FT(0)); @@ -402,7 +403,23 @@ namespace CGAL { // Hausdorff distance and thus have to be entered. template std::pair - do_intersect_with_priority(const Query&, const Node& node) const { + do_intersect_with_priority(const Query&, const Node& node) { + + // Check if we can stop already here. Since our bounds only grow, in case, we are + // above the user-defined max distance bound, we return. This way, the user can + // early detect that he is behind his thresholds. + if (m_distance_bound >= FT(0) && !m_early_quit) { + + CGAL_assertion(h_global_bounds.lower >= FT(0)); + CGAL_assertion(h_global_bounds.upper >= FT(0)); + CGAL_assertion(h_global_bounds.upper >= h_global_bounds.lower); + + const FT hdist = (h_global_bounds.lower + h_global_bounds.upper) / FT(2); + m_early_quit = (hdist >= m_distance_bound); + // std::cout << "- hdist: " << hdist << std::endl; + // std::cout << "- early quit: " << m_early_quit << std::endl; + } + if (m_early_quit) return std::make_pair(false, FT(0)); // Have reached a node, determine whether or not to enter it. // Get the bounding box of the nodes. @@ -435,11 +452,6 @@ namespace CGAL { // See Algorithm 1 here. // If the distance is larger than the global lower bound, enter the node, i.e. return true. - - // CGAL_assertion(h_global_bounds.upper >= h_global_bounds.lower); - // const FT hdist = (h_global_bounds.lower + h_global_bounds.upper) / FT(2); - // std::cout << "- distance: " << hdist << std::endl; - CGAL_assertion(h_global_bounds.lower >= FT(0)); if (dist > h_global_bounds.lower) { return std::make_pair(true , +dist); @@ -449,7 +461,7 @@ namespace CGAL { } template - bool do_intersect(const Query& query, const Node& node) const { + bool do_intersect(const Query& query, const Node& node) { return this->do_intersect_with_priority(query, node).first; } @@ -461,6 +473,10 @@ namespace CGAL { } } + bool early_quit() const { + return m_early_quit; + } + // Return those triangles from TM1, which are candidates for including a // point realizing the Hausdorff distance. Heap_type& get_candidate_triangles() { @@ -524,6 +540,7 @@ namespace CGAL { const FT m_initial_bound; const FT m_distance_bound; Global_bounds h_global_bounds; + bool m_early_quit; // All candidate triangles. Heap_type m_candidiate_triangles; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 4537e06b23a..42440171860 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -879,7 +879,7 @@ void test_early_quit(const std::string filepath) { std::cout << " ---- distance 0.0 = 0.0 ---- " << std::endl; timer.reset(); timer.start(); - // assert(PMP::are_within_tolerance(mesh1, mesh2, 0.0)); + assert(PMP::are_within_tolerance(mesh1, mesh2, 0.0)); timer.stop(); const double timea = timer.time(); @@ -895,19 +895,19 @@ void test_early_quit(const std::string filepath) { std::cout << " ---- distance 0.5 < 0.6 ---- " << std::endl; timer.reset(); timer.start(); - // assert(PMP::are_within_tolerance(mesh1, mesh2, 0.6)); + assert(PMP::are_within_tolerance(mesh1, mesh2, 0.6)); timer.stop(); const double timec = timer.time(); std::cout << " ---- distance 0.5 > 0.4 ---- " << std::endl; timer.reset(); timer.start(); - // assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.4)); + assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.4)); timer.stop(); const double timed = timer.time(); std::cout << " ---- distance 0.5 > 0.2 ---- " << std::endl; timer.reset(); timer.start(); - // assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.2)); + assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.2)); timer.stop(); const double timee = timer.time(); From 56862524754b59f6ec95abdb5aa8c159b0cbf34a Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 11 May 2021 16:11:42 +0200 Subject: [PATCH 205/349] is_further_than function finished --- .../CGAL/Polygon_mesh_processing/distance.h | 20 ++++++++--------- ...traversal_traits_with_Hausdorff_distance.h | 6 ++++- .../test_hausdorff_bounded_error_distance.cpp | 22 +++++++++---------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index f8ef099978a..36be87b21c4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -2422,13 +2422,13 @@ double bounded_error_symmetric_Hausdorff_distance( /** * \ingroup PMP_distance_grp - * returns `true` if two meshes are within the user-defined max distance, - * otherwise it returns `false`. The distance used to compute the proximity - * of the meshes is the `bounded_error_Hausdorff_distance`. + * returns `true` if the Hausdorff distance between two meshes is larger than + * the user-defined max distance, otherwise it returns `false`. The distance used + * to compute the proximity of the meshes is the `bounded_error_Hausdorff_distance`. * * Instead of computing the full distance and checking it against the user-provided * value, this function early quits in case certain criteria show that the meshes - * do not satisfy the provided max distance. + * do not satisfy the provided distance bound. * * @return Boolean `true` or `false` */ @@ -2437,7 +2437,7 @@ template< class Concurrency_tag, class TriangleMesh2, class NamedParameters1, class NamedParameters2 > -bool are_within_tolerance( +bool is_further_than( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const double distance_bound, @@ -2484,34 +2484,34 @@ bool are_within_tolerance( // std::cout << "- fin distance: " << hdist << std::endl; // std::cout << "- max distance: " << distance_bound << std::endl; - return hdist <= distance_bound; + return hdist > distance_bound; } template< class Concurrency_tag, class TriangleMesh1, class TriangleMesh2, class NamedParameters1 > -double are_within_tolerance( +double is_further_than( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const double max_distance, const double error_bound, const NamedParameters1& np1) { - return are_within_tolerance( + return is_further_than( tm1, tm2, max_distance, error_bound, np1, parameters::all_default()); } template< class Concurrency_tag, class TriangleMesh1, class TriangleMesh2 > -double are_within_tolerance( +double is_further_than( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const double max_distance = 1.0, const double error_bound = 0.0001) { - return are_within_tolerance( + return is_further_than( tm1, tm2, max_distance, error_bound, parameters::all_default()); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h index c9e051290fa..a7f5ddd01ea 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_Hausdorff_distance.h @@ -340,12 +340,16 @@ namespace CGAL { // Explore the whole tree, i.e. always enter children if the methods // do_intersect() below determine that it is worthwhile. - bool go_further() const { return true; } + bool go_further() const { + return !m_early_quit; + } // Compute the explicit Hausdorff distance to the given primitive. template void intersection(const Query&, const Primitive& primitive) { + if (m_early_quit) return; + // Set initial tight bounds. CGAL_assertion(primitive.id() != Face_handle_1()); std::pair fpair; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 42440171860..0c2256b74ae 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -879,43 +879,43 @@ void test_early_quit(const std::string filepath) { std::cout << " ---- distance 0.0 = 0.0 ---- " << std::endl; timer.reset(); timer.start(); - assert(PMP::are_within_tolerance(mesh1, mesh2, 0.0)); + assert(!PMP::is_further_than(mesh1, mesh2, 0.0)); timer.stop(); const double timea = timer.time(); PMP::transform(Affine_transformation_3(CGAL::Translation(), Vector_3(0.0, 0.0, 0.5)), mesh2); - std::cout << " ---- distance 0.5 < 0.8 ---- " << std::endl; + std::cout << " ---- distance 0.5 < 1.0 ---- " << std::endl; timer.reset(); timer.start(); - assert(PMP::are_within_tolerance(mesh1, mesh2, 0.8)); + assert(!PMP::is_further_than(mesh1, mesh2, 1.0)); timer.stop(); const double timeb = timer.time(); std::cout << " ---- distance 0.5 < 0.6 ---- " << std::endl; timer.reset(); timer.start(); - assert(PMP::are_within_tolerance(mesh1, mesh2, 0.6)); + assert(!PMP::is_further_than(mesh1, mesh2, 0.6)); timer.stop(); const double timec = timer.time(); std::cout << " ---- distance 0.5 > 0.4 ---- " << std::endl; timer.reset(); timer.start(); - assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.4)); + assert(PMP::is_further_than(mesh1, mesh2, 0.4)); timer.stop(); const double timed = timer.time(); - std::cout << " ---- distance 0.5 > 0.2 ---- " << std::endl; + std::cout << " ---- distance 0.5 > 0.0 ---- " << std::endl; timer.reset(); timer.start(); - assert(!PMP::are_within_tolerance(mesh1, mesh2, 0.2)); + assert(PMP::is_further_than(mesh1, mesh2, 0.0)); timer.stop(); const double timee = timer.time(); std::cout << "* timea 0.0 = 0.0 = " << timea << std::endl; - std::cout << "* timeb 0.5 < 0.8 = " << timeb << std::endl; + std::cout << "* timeb 0.5 < 1.0 = " << timeb << std::endl; std::cout << "* timec 0.5 < 0.6 = " << timec << std::endl; std::cout << "* timed 0.5 > 0.4 = " << timed << std::endl; - std::cout << "* timee 0.5 > 0.2 = " << timee << std::endl; + std::cout << "* timee 0.5 > 0.0 = " << timee << std::endl; } int main(int argc, char** argv) { @@ -973,7 +973,7 @@ int main(int argc, char** argv) { // test_bunny(bound_hd, 3); // --- Test realizing triangles. - // test_realizing_triangles(error_bound); + test_realizing_triangles(error_bound); #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) && defined(USE_PARALLEL_BEHD) // --- Test parallelization. @@ -981,7 +981,7 @@ int main(int argc, char** argv) { #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) // --- Test early quit. - test_early_quit(filepath); + // test_early_quit(filepath); // ------------------------------------------------------------------------ // From 6ae21a4379c52ef9d4839da5962b539679b51f99 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 11 May 2021 17:38:15 +0200 Subject: [PATCH 206/349] added visitor to save pairs of realizing triangles --- .../CGAL/Polygon_mesh_processing/distance.h | 72 ++++++++++++++----- .../test_hausdorff_bounded_error_distance.cpp | 27 +++---- 2 files changed, 67 insertions(+), 32 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 36be87b21c4..433cbd2d6d6 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #if defined(CGAL_METIS_ENABLED) @@ -1372,6 +1373,7 @@ std::pair preprocess_bounded_error_Hausdorff_impl( Point_3(bb.xmin(), bb.ymin(), bb.zmin()), Point_3(bb.xmax(), bb.ymax(), bb.zmax())); FT infinity_value = CGAL::approximate_sqrt(sq_dist) * FT(2); + CGAL_assertion(infinity_value >= FT(0)); // Compare meshes and build trees. tm1_only.clear(); @@ -1446,7 +1448,8 @@ template< class Kernel, class VPM1, class VPM2, class TM1Tree, - class TM2Tree > + class TM2Tree, + class OutputIterator > double bounded_error_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, @@ -1457,7 +1460,8 @@ double bounded_error_Hausdorff_impl( const typename Kernel::FT initial_bound, const typename Kernel::FT distance_bound, const TM1Tree& tm1_tree, - const TM2Tree& tm2_tree) + const TM2Tree& tm2_tree, + OutputIterator& out) { using FT = typename Kernel::FT; using Point_3 = typename Kernel::Point_3; @@ -1674,9 +1678,9 @@ double bounded_error_Hausdorff_impl( CGAL_assertion(global_bounds.upair.first != boost::graph_traits::null_face()); CGAL_assertion(global_bounds.upair.second != boost::graph_traits::null_face()); - // Off for the moment. - // const auto realizing_triangles = global_bounds.upair; - // return std::make_pair(hdist, realizing_triangles); + // Output face pairs, which realize the Hausdorff distance. + *out++ = global_bounds.lpair; + *out++ = global_bounds.upair; return hdist; } @@ -1796,6 +1800,7 @@ struct Bounded_error_distance_computation { timer.reset(); timer.start(); double hdist = -1.0; + auto stub = CGAL::Emptyset_iterator(); for (std::size_t i = range.begin(); i != range.end(); ++i) { CGAL_assertion(i < tm1_parts.size()); @@ -1807,7 +1812,7 @@ struct Bounded_error_distance_computation { const double dist = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, vpm1, vpm2, infinity_value, initial_bound, -FT(1), - tm1_tree, tm2_tree); + tm1_tree, tm2_tree, stub); if (dist > hdist) hdist = dist; } if (hdist > distance) distance = hdist; @@ -1829,7 +1834,8 @@ template< class Concurrency_tag, class VPM1, class VPM2, class NamedParameters1, - class NamedParameters2 > + class NamedParameters2, + class OutputIterator > double bounded_error_one_sided_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, @@ -1839,7 +1845,8 @@ double bounded_error_one_sided_Hausdorff_impl( const VPM1& vpm1, const VPM2& vpm2, const NamedParameters1& np1, - const NamedParameters2& np2) + const NamedParameters2& np2, + OutputIterator& out) { #if !defined(CGAL_LINKED_WITH_TBB) || !defined(CGAL_METIS_ENABLED) CGAL_static_assertion_msg( @@ -1984,6 +1991,10 @@ double bounded_error_one_sided_Hausdorff_impl( // std::cout << "* infinity_value: " << infinity_value << std::endl; if (infinity_value < FT(0)) { // std::cout << "* culling rate: 100%" << std::endl; + const auto face1 = *(faces(tm1).begin()); + const auto face2 = *(faces(tm2).begin()); + *out++ = std::make_pair(face1, face2); + *out++ = std::make_pair(face1, face2); return 0.0; // TM1 is part of TM2 so the distance is zero } CGAL_assertion(error_bound >= FT(0)); @@ -2013,7 +2024,7 @@ double bounded_error_one_sided_Hausdorff_impl( hdist = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, vpm1, vpm2, infinity_value, initial_bound, distance_bound, - tm1_tree, tm2_tree); + tm1_tree, tm2_tree, out); } timer.stop(); @@ -2031,7 +2042,9 @@ template< class Concurrency_tag, class VPM1, class VPM2, class NamedParameters1, - class NamedParameters2 > + class NamedParameters2, + class OutputIterator1, + class OutputIterator2 > double bounded_error_symmetric_Hausdorff_impl( const TriangleMesh1& tm1, const TriangleMesh2& tm2, @@ -2041,7 +2054,9 @@ double bounded_error_symmetric_Hausdorff_impl( const VPM1& vpm1, const VPM2& vpm2, const NamedParameters1& np1, - const NamedParameters2& np2) + const NamedParameters2& np2, + OutputIterator1& out1, + OutputIterator2& out2) { #if !defined(CGAL_LINKED_WITH_TBB) || !defined(CGAL_METIS_ENABLED) CGAL_static_assertion_msg( @@ -2052,9 +2067,9 @@ double bounded_error_symmetric_Hausdorff_impl( // Naive version. // TODO: we can use it for parallel version to simplify our life. // const double hdist1 = bounded_error_one_sided_Hausdorff_impl( - // tm1, tm2, error_bound, distance_bound, compare_meshes, vpm1, vpm2, np1, np2); + // tm1, tm2, error_bound, distance_bound, compare_meshes, vpm1, vpm2, np1, np2, out1); // const double hdist2 = bounded_error_one_sided_Hausdorff_impl( - // tm2, tm1, error_bound, distance_bound, compare_meshes, vpm2, vpm1, np1, np2); + // tm2, tm1, error_bound, distance_bound, compare_meshes, vpm2, vpm1, np1, np2, out2); // return (CGAL::max)(hdist1, hdist2); // Optimized version. @@ -2090,6 +2105,12 @@ double bounded_error_symmetric_Hausdorff_impl( if (infinity_value < FT(0)) { // std::cout << "* culling rate: 100%" << std::endl; + const auto face1 = *(faces(tm1).begin()); + const auto face2 = *(faces(tm2).begin()); + *out1++ = std::make_pair(face1, face2); + *out1++ = std::make_pair(face1, face2); + *out2++ = std::make_pair(face2, face1); + *out2++ = std::make_pair(face2, face1); return 0.0; // TM1 and TM2 are equal so the distance is zero } CGAL_assertion(infinity_value > FT(0)); @@ -2102,7 +2123,7 @@ double bounded_error_symmetric_Hausdorff_impl( dista = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, vpm1, vpm2, infinity_value, initial_bound, distance_bound, - tm1_tree, tm2_tree); + tm1_tree, tm2_tree, out1); } // In case this is true, we need to rebuild trees in order to accelerate @@ -2125,7 +2146,7 @@ double bounded_error_symmetric_Hausdorff_impl( distb = bounded_error_Hausdorff_impl( tm2, tm1, error_bound, vpm2, vpm1, infinity_value, initial_bound, distance_bound, - tm2_tree, tm1_tree); + tm2_tree, tm1_tree, out2); } // Return the maximum. @@ -2310,10 +2331,14 @@ double bounded_error_Hausdorff_distance( parameters::get_parameter(np2, internal_np::match_faces), true); const bool match_faces = match_faces1 && match_faces2; + auto out = parameters::choose_parameter( + parameters::get_parameter(np1, internal_np::output_iterator), + CGAL::Emptyset_iterator()); + CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); return internal::bounded_error_one_sided_Hausdorff_impl( - tm1, tm2, error_threshold, -FT(1), match_faces, vpm1, vpm2, np1, np2); + tm1, tm2, error_threshold, -FT(1), match_faces, vpm1, vpm2, np1, np2, out); } template< class Concurrency_tag, @@ -2385,10 +2410,18 @@ double bounded_error_symmetric_Hausdorff_distance( parameters::get_parameter(np2, internal_np::match_faces), true); const bool match_faces = match_faces1 && match_faces2; + // TODO: should we return a union of these realizing triangles? + auto out1 = parameters::choose_parameter( + parameters::get_parameter(np1, internal_np::output_iterator), + CGAL::Emptyset_iterator()); + auto out2 = parameters::choose_parameter( + parameters::get_parameter(np2, internal_np::output_iterator), + CGAL::Emptyset_iterator()); + CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); return internal::bounded_error_symmetric_Hausdorff_impl( - tm1, tm2, error_threshold, -FT(1), match_faces, vpm1, vpm2, np1, np2); + tm1, tm2, error_threshold, -FT(1), match_faces, vpm1, vpm2, np1, np2, out1, out2); } template< class Concurrency_tag, @@ -2471,14 +2504,15 @@ bool is_further_than( const FT error_threshold = static_cast(error_bound); CGAL_precondition(distance_bound >= 0.0); const FT distance_threshold = static_cast(distance_bound); + auto stub = CGAL::Emptyset_iterator(); double hdist = -1.0; if (use_one_sided) { hdist = internal::bounded_error_one_sided_Hausdorff_impl( - tm1, tm2, error_threshold, distance_threshold, match_faces, vpm1, vpm2, np1, np2); + tm1, tm2, error_threshold, distance_threshold, match_faces, vpm1, vpm2, np1, np2, stub); } else { hdist = internal::bounded_error_symmetric_Hausdorff_impl( - tm1, tm2, error_threshold, distance_threshold, match_faces, vpm1, vpm2, np1, np2); + tm1, tm2, error_threshold, distance_threshold, match_faces, vpm1, vpm2, np1, np2, stub, stub); } CGAL_assertion(hdist >= 0.0); diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 0c2256b74ae..fa1a6fcf816 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -733,14 +733,15 @@ void compute_realizing_triangles( const double error_bound, const std::string prefix, const bool save = false) { std::cout << "* getting realizing triangles: " << std::endl; + std::vector< std::pair > fpairs; const double hdist = - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound); - const auto data = std::make_pair(hdist, std::make_pair(Face_handle(), Face_handle())); - const auto& faces = data.second; - const int f1 = static_cast(faces.first); - const int f2 = static_cast(faces.second); + PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound, + CGAL::parameters::output_iterator(std::back_inserter(fpairs))); + assert(fpairs.size() == 2); // lower bound face pair + upper bound face pair + const int f1 = static_cast(fpairs.back().first); // f1 / f2: upper bound + const int f2 = static_cast(fpairs.back().second); - std::cout << "* Hausdorff: " << data.first << std::endl; + std::cout << "* Hausdorff: " << hdist << std::endl; std::cout << "* f1 / f2: " << f1 << " / " << f2 << std::endl; if (f1 != -1 && save) { @@ -941,13 +942,13 @@ int main(int argc, char** argv) { // test_synthetic_data(apprx_hd); // test_synthetic_data(naive_hd); - // test_synthetic_data(bound_hd); + test_synthetic_data(bound_hd); // --- Compare on common meshes. // test_one_versus_another(apprx_hd, naive_hd); // test_one_versus_another(naive_hd, bound_hd); - // test_one_versus_another(bound_hd, apprx_hd); + test_one_versus_another(bound_hd, apprx_hd); // --- Compare on real meshes. @@ -956,7 +957,7 @@ int main(int argc, char** argv) { // test_real_meshes(filepath1, filepath2, apprx_hd, naive_hd); // test_real_meshes(filepath1, filepath2, naive_hd, bound_hd); - // test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); + test_real_meshes(filepath1, filepath2, bound_hd, apprx_hd); // --- Compare timings. @@ -964,24 +965,24 @@ int main(int argc, char** argv) { // filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); - // test_timings(filepath, bound_hd); + test_timings(filepath, bound_hd); // --- Compare with the paper. // test_bunny(apprx_hd); // test_bunny(naive_hd); - // test_bunny(bound_hd, 3); + test_bunny(bound_hd, 3); // --- Test realizing triangles. test_realizing_triangles(error_bound); #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) && defined(USE_PARALLEL_BEHD) // --- Test parallelization. - // test_parallel_version(filepath, error_bound); + test_parallel_version(filepath, error_bound); #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) // --- Test early quit. - // test_early_quit(filepath); + test_early_quit(filepath); // ------------------------------------------------------------------------ // From 393ae7dae64546dbfc99a59f427916c129d85d9c Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 12 May 2021 15:03:53 +0200 Subject: [PATCH 207/349] Clean-up boost_version reqs --- .../AABB_tree/AABB_ray_intersection.h | 14 --- .../Curved_kernel_via_analysis_2/Point_2.h | 23 ---- .../boost/graph/alpha_expansion_graphcut.h | 7 +- .../Sum_of_weighted_features_classifier.h | 4 - .../CGAL/Filtered_predicate_with_state.h | 4 - .../CGAL/random_convex_hull_in_disc_2.h | 15 --- .../demo/Alpha_shapes_2/Alpha_shapes_2.cpp | 6 +- .../Apollonius_graph_2/Apollonius_graph_2.cpp | 10 +- .../Bounding_volumes/Bounding_volumes.cpp | 10 +- .../Circular_kernel_2/Circular_kernel_2.cpp | 6 +- .../L1_voronoi_diagram_2.cpp | 10 +- .../Periodic_2_Delaunay_triangulation_2.cpp | 10 +- GraphicsView/demo/Polygon/Polygon_2.cpp | 10 +- .../Segment_voronoi_2.cpp | 10 +- .../Segment_voronoi_linf_2.cpp | 10 +- .../demo/Snap_rounding_2/Snap_rounding_2.cpp | 10 +- .../Spatial_searching_2.cpp | 6 +- .../demo/Stream_lines_2/Stream_lines_2.cpp | 10 +- .../Constrained_Delaunay_triangulation_2.cpp | 10 +- .../Delaunay_triangulation_2.cpp | 10 +- .../Regular_triangulation_2.cpp | 10 +- Installation/include/CGAL/config.h | 108 ++++-------------- Mesh_3/benchmark/Mesh_3/CMakeLists.txt | 2 +- .../CGAL/Mesh_3/Is_mesh_domain_field_3.h | 13 +-- Mesh_3/include/CGAL/Mesh_cell_criteria_3.h | 2 - .../test_mesh_capsule_var_distance_bound.cpp | 12 -- Mesher_level/include/CGAL/Double_map.h | 6 - Number_types/include/CGAL/boost_mp.h | 5 +- .../normal_estimation_test.cpp | 9 -- .../Polyline_simplification_2.cpp | 10 +- .../points_and_vertices.cpp | 4 +- .../Polyline_simplification_2/simplify.cpp | 2 +- .../simplify_polygon.cpp | 2 +- .../simplify_polyline.cpp | 4 +- Property_map/include/CGAL/property_map.h | 8 +- STL_Extension/include/CGAL/demangle.h | 8 -- STL_Extension/include/CGAL/iterator.h | 8 -- .../Straight_skeleton_builder_2_impl.h | 4 - .../Stream_support/Linestring_WKT.cpp | 2 +- .../examples/Stream_support/Point_WKT.cpp | 2 +- .../examples/Stream_support/Polygon_WKT.cpp | 2 +- .../examples/Stream_support/read_WKT.cpp | 2 +- Stream_support/include/CGAL/IO/WKT.h | 2 +- .../include/CGAL/IO/WKT/traits_linestring.h | 2 +- .../CGAL/IO/WKT/traits_multilinestring.h | 2 +- .../include/CGAL/IO/WKT/traits_multipoint.h | 2 +- .../include/CGAL/IO/WKT/traits_multipolygon.h | 2 +- .../include/CGAL/IO/WKT/traits_point.h | 2 +- .../include/CGAL/IO/WKT/traits_point_3.h | 2 +- .../include/CGAL/IO/WKT/traits_polygon.h | 2 +- .../CGAL/internal/Geometry_container.h | 2 +- .../test/Stream_support/test_WKT.cpp | 2 +- .../include/CGAL/Path_on_surface.h | 11 +- .../CGAL/Triangulation_data_structure_3.h | 2 - .../CGAL/Constrained_triangulation_plus_2.h | 10 -- 55 files changed, 122 insertions(+), 341 deletions(-) diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_ray_intersection.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_ray_intersection.h index efa329b1b7b..9e6898d2c8a 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_ray_intersection.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_ray_intersection.h @@ -21,7 +21,6 @@ #include #include #include -#if BOOST_VERSION >= 105000 # if defined(BOOST_MSVC) # pragma warning(push) # pragma warning(disable: 4996) @@ -30,9 +29,6 @@ # if defined(BOOST_MSVC) # pragma warning(pop) # endif -#else -# include -#endif #include @@ -54,11 +50,7 @@ public: // BVH_node::traversal this is done through the function parameter // nb_primitives in the recursion. typedef -#if BOOST_VERSION >= 105000 boost::heap::priority_queue< Node_ptr_with_ft, boost::heap::compare< std::greater > > -#else - std::priority_queue< Node_ptr_with_ft> -#endif Heap_type; typename AABB_traits::Intersection @@ -167,14 +159,8 @@ private: const Node* node; size_type nb_primitives; FT value; -#if BOOST_VERSION >= 105000 bool operator<(const Node_ptr_with_ft& other) const { return value < other.value; } bool operator>(const Node_ptr_with_ft& other) const { return value > other.value; } -#else - bool operator>(const Node_ptr_with_ft& other) const { return value < other.value; } - bool operator<(const Node_ptr_with_ft& other) const { return value > other.value; } - -#endif }; struct as_ray_param_visitor { diff --git a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h index 09e245ec4ff..d68dfade144 100644 --- a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h @@ -738,35 +738,12 @@ public: // read values is >> rep._m_xy; -#if BOOST_VERSION < 104300 - // EBEB: This fixes a bug in optional_io.hpp, reported to Fernando on - // April 27, 2010, don't know whether the fix makes it into - // boost 1_43. - if (!rep._m_xy) { - swallow(is, '-'); - } -#endif swallow(is, ','); is >> rep._m_x; -#if BOOST_VERSION < 104300 - if (!rep._m_x) { - swallow(is, '-'); - } -#endif swallow(is, ','); is >> rep._m_curve; -#if BOOST_VERSION < 104300 - if (!rep._m_curve) { - swallow(is, '-'); - } -#endif swallow(is, ','); is >> rep._m_arcno; -#if BOOST_VERSION < 104300 - if (!rep._m_arcno) { - swallow(is, '-'); - } -#endif swallow(is, ','); is >> rep._m_location; diff --git a/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h b/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h index 6d5a321abf4..fa2054185b8 100644 --- a/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h +++ b/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h @@ -27,12 +27,7 @@ #include #include - -#if BOOST_VERSION >= 104400 // at this version kolmogorov_max_flow become depricated. -# include -#else -# include -#endif +#include #include diff --git a/Classification/include/CGAL/Classification/Sum_of_weighted_features_classifier.h b/Classification/include/CGAL/Classification/Sum_of_weighted_features_classifier.h index 57bdaf8a93f..2d30a534a42 100644 --- a/Classification/include/CGAL/Classification/Sum_of_weighted_features_classifier.h +++ b/Classification/include/CGAL/Classification/Sum_of_weighted_features_classifier.h @@ -692,11 +692,7 @@ public: } // Write property tree to XML file boost::property_tree::write_xml(output, tree, -#if BOOST_VERSION >= 105600 boost::property_tree::xml_writer_make_settings(' ', 3)); -#else - boost::property_tree::xml_writer_make_settings(' ', 3)); -#endif } /*! diff --git a/Filtered_kernel/include/CGAL/Filtered_predicate_with_state.h b/Filtered_kernel/include/CGAL/Filtered_predicate_with_state.h index 56ef70f0ef9..be16571ff04 100644 --- a/Filtered_kernel/include/CGAL/Filtered_predicate_with_state.h +++ b/Filtered_kernel/include/CGAL/Filtered_predicate_with_state.h @@ -75,11 +75,7 @@ Filtered_predicate_with_state:: CGAL_BRANCH_PROFILER_BRANCH(tmp); Protect_FPU_rounding p(CGAL_FE_TONEAREST); if(! oep){ - #if BOOST_VERSION < 105600 - oep = EP(c2e(o1)); - #else oep.emplace(c2e(o1)); - #endif } return (*oep)(c2e(args)...); } diff --git a/Generator/include/CGAL/random_convex_hull_in_disc_2.h b/Generator/include/CGAL/random_convex_hull_in_disc_2.h index 0bac0f466e3..8dde064451f 100644 --- a/Generator/include/CGAL/random_convex_hull_in_disc_2.h +++ b/Generator/include/CGAL/random_convex_hull_in_disc_2.h @@ -68,19 +68,6 @@ void generate_points_annulus(long n, double a, double b, double small_radius, } if (n == 1) // generation of a point { - - #if BOOST_VERSION < 104700 - - boost::uniform_real random_squared_radius_distribution( - small_radius * small_radius / (big_radius * big_radius), 1); - boost::uniform_real random_angle_distribution(a, b); - boost::variate_generator< - GEN&, boost::uniform_real > random_angle(gen, random_angle_distribution); - boost::variate_generator< - GEN&, boost::uniform_real > random_squared_radius(gen, random_squared_radius_distribution); - - #else - boost::random::uniform_real_distribution random_squared_radius_distribution( small_radius * small_radius / (big_radius * big_radius), 1); @@ -90,8 +77,6 @@ void generate_points_annulus(long n, double a, double b, double small_radius, boost::random::variate_generator< GEN&, boost::random::uniform_real_distribution > random_squared_radius(gen, random_squared_radius_distribution); - #endif - double alpha = random_angle(); double r = big_radius * std::sqrt(random_squared_radius()); typedef Creator_uniform_2 Creator; diff --git a/GraphicsView/demo/Alpha_shapes_2/Alpha_shapes_2.cpp b/GraphicsView/demo/Alpha_shapes_2/Alpha_shapes_2.cpp index 374e297f3cc..792c948ac9e 100644 --- a/GraphicsView/demo/Alpha_shapes_2/Alpha_shapes_2.cpp +++ b/GraphicsView/demo/Alpha_shapes_2/Alpha_shapes_2.cpp @@ -7,7 +7,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif #include @@ -253,7 +253,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wktk *.WKT);;" #endif "All files (*)")); @@ -274,7 +274,7 @@ MainWindow::open(QString fileName) std::ifstream ifs(qPrintable(fileName)); if(fileName.endsWith(".wkt",Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, points); #endif } diff --git a/GraphicsView/demo/Apollonius_graph_2/Apollonius_graph_2.cpp b/GraphicsView/demo/Apollonius_graph_2/Apollonius_graph_2.cpp index 8292f28262d..b92b9e3600d 100644 --- a/GraphicsView/demo/Apollonius_graph_2/Apollonius_graph_2.cpp +++ b/GraphicsView/demo/Apollonius_graph_2/Apollonius_graph_2.cpp @@ -7,7 +7,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -220,7 +220,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.wpts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All files (*)")); @@ -241,7 +241,7 @@ MainWindow::open(QString fileName) std::vector points; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector point_3_s; CGAL::read_multi_point_WKT(ifs, point_3_s); for(const K::Point_3& point_3 : point_3_s) @@ -270,7 +270,7 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".reg.cgal", tr("Weighted Points (*.wpts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files(*.wkt *.WKT);;" #endif "All (*)")); @@ -278,7 +278,7 @@ MainWindow::on_actionSavePoints_triggered() std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt",Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector points; for(Apollonius::Sites_iterator vit = ag.sites_begin(), diff --git a/GraphicsView/demo/Bounding_volumes/Bounding_volumes.cpp b/GraphicsView/demo/Bounding_volumes/Bounding_volumes.cpp index 12928ca9897..574e61bd33d 100644 --- a/GraphicsView/demo/Bounding_volumes/Bounding_volumes.cpp +++ b/GraphicsView/demo/Bounding_volumes/Bounding_volumes.cpp @@ -15,7 +15,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -479,7 +479,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt);;" #endif "All files (*)")); @@ -497,7 +497,7 @@ MainWindow::open(QString fileName) std::ifstream ifs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, points); for(K::Point_2 p : points) { @@ -532,7 +532,7 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".", tr("CGAL files (*.pts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt);;" #endif "All files (*)")); @@ -540,7 +540,7 @@ MainWindow::on_actionSavePoints_triggered() std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector out_pts; out_pts.reserve(std::distance(mc.points_begin(), mc.points_end())); diff --git a/GraphicsView/demo/Circular_kernel_2/Circular_kernel_2.cpp b/GraphicsView/demo/Circular_kernel_2/Circular_kernel_2.cpp index b54014b9f0b..4c6df0c026c 100644 --- a/GraphicsView/demo/Circular_kernel_2/Circular_kernel_2.cpp +++ b/GraphicsView/demo/Circular_kernel_2/Circular_kernel_2.cpp @@ -10,7 +10,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -216,7 +216,7 @@ MainWindow::on_actionLoadLineAndCircularArcs_triggered() tr("Open Line and Circular Arc File"), ".", tr("Edge files (*.arc)\n" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT)\n" #endif )); @@ -236,7 +236,7 @@ MainWindow::open(QString fileName) double x,y; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) //read pairs as Line_arc_2 and triplets as circular_arc_2 do { diff --git a/GraphicsView/demo/L1_Voronoi_diagram_2/L1_voronoi_diagram_2.cpp b/GraphicsView/demo/L1_Voronoi_diagram_2/L1_voronoi_diagram_2.cpp index c240f8c62a3..4e1399bd680 100644 --- a/GraphicsView/demo/L1_Voronoi_diagram_2/L1_voronoi_diagram_2.cpp +++ b/GraphicsView/demo/L1_Voronoi_diagram_2/L1_voronoi_diagram_2.cpp @@ -24,7 +24,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -275,7 +275,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All files (*)")); @@ -295,7 +295,7 @@ MainWindow::open(QString fileName) std::ifstream ifs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, m_sites); #endif } @@ -322,14 +322,14 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".", tr("CGAL files (*.pts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All files (*)")); if(! fileName.isEmpty()) { std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)){ -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::write_multi_point_WKT(ofs, m_sites); #endif }else diff --git a/GraphicsView/demo/Periodic_2_triangulation_2/Periodic_2_Delaunay_triangulation_2.cpp b/GraphicsView/demo/Periodic_2_triangulation_2/Periodic_2_Delaunay_triangulation_2.cpp index e956d72a171..a945124a01b 100644 --- a/GraphicsView/demo/Periodic_2_triangulation_2/Periodic_2_Delaunay_triangulation_2.cpp +++ b/GraphicsView/demo/Periodic_2_triangulation_2/Periodic_2_Delaunay_triangulation_2.cpp @@ -8,7 +8,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -355,7 +355,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All files (*)")); @@ -376,7 +376,7 @@ MainWindow::open(QString fileName) std::vector points; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, points); #endif } @@ -404,7 +404,7 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".", tr("CGAL files (*.pts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All files (*)")); @@ -412,7 +412,7 @@ MainWindow::on_actionSavePoints_triggered() std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector points; points.reserve(std::distance(triang.unique_vertices_begin(), triang.unique_vertices_end())); diff --git a/GraphicsView/demo/Polygon/Polygon_2.cpp b/GraphicsView/demo/Polygon/Polygon_2.cpp index 98d66af08c5..98b001a7c28 100644 --- a/GraphicsView/demo/Polygon/Polygon_2.cpp +++ b/GraphicsView/demo/Polygon/Polygon_2.cpp @@ -13,7 +13,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -234,7 +234,7 @@ MainWindow::on_actionLoadPolygon_triggered() ".", tr( "Polyline files (*.polygons.cgal);;" "WSL files (*.wsl);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All file (*)")); @@ -251,7 +251,7 @@ MainWindow::open(QString fileName) poly.clear(); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::Polygon_with_holes_2 P; CGAL::read_polygon_WKT(ifs, P); poly = Polygon2(P.outer_boundary().begin(), @@ -276,7 +276,7 @@ MainWindow::on_actionSavePolygon_triggered() tr("Save Polygon"), ".", tr( "Polyline files (*.polygons.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All file (*)")); @@ -284,7 +284,7 @@ MainWindow::on_actionSavePolygon_triggered() std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::Polygon_2 P(poly.begin(), poly.end()); CGAL::Polygon_with_holes_2 Pwh(P); diff --git a/GraphicsView/demo/Segment_Delaunay_graph_2/Segment_voronoi_2.cpp b/GraphicsView/demo/Segment_Delaunay_graph_2/Segment_voronoi_2.cpp index ac6d7af1f48..1e53c0603bb 100644 --- a/GraphicsView/demo/Segment_Delaunay_graph_2/Segment_voronoi_2.cpp +++ b/GraphicsView/demo/Segment_Delaunay_graph_2/Segment_voronoi_2.cpp @@ -25,7 +25,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif //#include @@ -248,7 +248,7 @@ MainWindow::open(QString fileName) loadEdgConstraints(fileName); this->addToRecentFiles(fileName); } else if(fileName.endsWith(".wkt", Qt::CaseInsensitive)){ -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) loadWKTConstraints(fileName); this->addToRecentFiles(fileName); #endif @@ -264,7 +264,7 @@ MainWindow::on_actionLoadSegments_triggered() ".", tr("Edge files (*.edg);;" "Polyline files (*.polygons.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT)" #endif )); @@ -342,12 +342,12 @@ MainWindow::loadEdgConstraints(QString fileName) void MainWindow::loadWKTConstraints(QString - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) fileName #endif ) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) typedef CGAL::Polygon_with_holes_2 Polygon; typedef std::vector LineString; diff --git a/GraphicsView/demo/Segment_Delaunay_graph_Linf_2/Segment_voronoi_linf_2.cpp b/GraphicsView/demo/Segment_Delaunay_graph_Linf_2/Segment_voronoi_linf_2.cpp index ae4f72bc55e..76f7d443e5b 100644 --- a/GraphicsView/demo/Segment_Delaunay_graph_Linf_2/Segment_voronoi_linf_2.cpp +++ b/GraphicsView/demo/Segment_Delaunay_graph_Linf_2/Segment_voronoi_linf_2.cpp @@ -23,7 +23,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif //#include @@ -270,7 +270,7 @@ MainWindow::open(QString fileName) loadSitesInput(fileName); this->addToRecentFiles(fileName); } else if(fileName.endsWith(".wkt", Qt::CaseInsensitive)){ -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) loadWKT(fileName); this->addToRecentFiles(fileName); #endif @@ -291,7 +291,7 @@ MainWindow::on_actionLoadSegments_triggered() "Pts files (*.pts);;" "Edge files (*.edg);;" "Polylines files (*.polygons.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt)" #endif )); @@ -389,12 +389,12 @@ MainWindow::loadPoints(QString fileName) void MainWindow::loadWKT(QString - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) fileName #endif ) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::ifstream ifs(qPrintable(fileName)); //Points do diff --git a/GraphicsView/demo/Snap_rounding_2/Snap_rounding_2.cpp b/GraphicsView/demo/Snap_rounding_2/Snap_rounding_2.cpp index 0225624b96e..b5db6faf4aa 100644 --- a/GraphicsView/demo/Snap_rounding_2/Snap_rounding_2.cpp +++ b/GraphicsView/demo/Snap_rounding_2/Snap_rounding_2.cpp @@ -20,7 +20,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -252,7 +252,7 @@ MainWindow::on_actionLoadSegments_triggered() tr("Open segment file"), ".", tr("Edge files (*.edg);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All files (*)")); @@ -270,7 +270,7 @@ MainWindow::open(QString fileName) std::ifstream ifs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector > mls; CGAL::read_multi_linestring_WKT(ifs, mls); for(const std::vector& ls : mls) @@ -304,7 +304,7 @@ MainWindow::on_actionSaveSegments_triggered() tr("Save points"), ".", tr("Edge files (*.edg);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All files (*)")); @@ -313,7 +313,7 @@ MainWindow::on_actionSaveSegments_triggered() ofs.precision(12); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector >mls; for(const Segment_2& seg : input) { diff --git a/GraphicsView/demo/Spatial_searching_2/Spatial_searching_2.cpp b/GraphicsView/demo/Spatial_searching_2/Spatial_searching_2.cpp index 1af26ec7514..ba7171f1a85 100644 --- a/GraphicsView/demo/Spatial_searching_2/Spatial_searching_2.cpp +++ b/GraphicsView/demo/Spatial_searching_2/Spatial_searching_2.cpp @@ -17,7 +17,7 @@ // GraphicsView items and event filters (input classes) #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -249,7 +249,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All files (*)")); @@ -271,7 +271,7 @@ MainWindow::open(QString fileName) std::vector points; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, points); #endif } diff --git a/GraphicsView/demo/Stream_lines_2/Stream_lines_2.cpp b/GraphicsView/demo/Stream_lines_2/Stream_lines_2.cpp index b0e1fb852ec..75aebdee97e 100644 --- a/GraphicsView/demo/Stream_lines_2/Stream_lines_2.cpp +++ b/GraphicsView/demo/Stream_lines_2/Stream_lines_2.cpp @@ -21,7 +21,7 @@ // for viewportsBbox #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif // the two base classes @@ -167,12 +167,12 @@ MainWindow::generate() void MainWindow::on_actionLoadPoints_triggered() { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #endif QString fileName = QFileDialog::getOpenFileName(this, tr("Open grid file"), "." - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) ,tr("WKT files (*.wkt *.WKT)") #endif ); @@ -194,7 +194,7 @@ MainWindow::open(QString fileName) iXSize = iYSize = 512; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector > mp; int size= -1; do @@ -248,7 +248,7 @@ MainWindow::open(QString fileName) void MainWindow::on_actionSavePoints_triggered() { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) QString fileName = QFileDialog::getSaveFileName(this, tr("Save points"), ".", diff --git a/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp b/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp index 60dd77c388d..43bf20943e2 100644 --- a/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp +++ b/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp @@ -25,7 +25,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -528,7 +528,7 @@ MainWindow::open(QString fileName) } else if(fileName.endsWith(".poly")){ loadPolyConstraints(fileName); } else if(fileName.endsWith(".wkt")){ -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) loadWKT(fileName); #endif } @@ -549,7 +549,7 @@ MainWindow::on_actionLoadConstraints_triggered() "Poly files (*.poly);;" "Plg files (*.plg);;" "CGAL files (*.cpts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt);;" #endif "All (*)")); @@ -558,12 +558,12 @@ MainWindow::on_actionLoadConstraints_triggered() void MainWindow::loadWKT(QString - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) filename #endif ) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) //Polygons todo : make it multipolygons std::ifstream ifs(qPrintable(filename)); do diff --git a/GraphicsView/demo/Triangulation_2/Delaunay_triangulation_2.cpp b/GraphicsView/demo/Triangulation_2/Delaunay_triangulation_2.cpp index 9d810c04398..266bdddbac5 100644 --- a/GraphicsView/demo/Triangulation_2/Delaunay_triangulation_2.cpp +++ b/GraphicsView/demo/Triangulation_2/Delaunay_triangulation_2.cpp @@ -23,7 +23,7 @@ #include "TriangulationPointInputAndConflictZone.h" #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -322,7 +322,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt);;" #endif "All files (*)")); @@ -343,7 +343,7 @@ MainWindow::open(QString fileName) std::vector points; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, points); #endif } @@ -370,7 +370,7 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".", tr("CGAL files (*.pts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt);;" #endif "All files (*)")); @@ -378,7 +378,7 @@ MainWindow::on_actionSavePoints_triggered() std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector points; points.reserve(dt.number_of_vertices()); for(Delaunay::Finite_vertices_iterator diff --git a/GraphicsView/demo/Triangulation_2/Regular_triangulation_2.cpp b/GraphicsView/demo/Triangulation_2/Regular_triangulation_2.cpp index 483a8ab3d27..9022ebdf2d7 100644 --- a/GraphicsView/demo/Triangulation_2/Regular_triangulation_2.cpp +++ b/GraphicsView/demo/Triangulation_2/Regular_triangulation_2.cpp @@ -5,7 +5,7 @@ // CGAL headers #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -248,7 +248,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("Weighted Points (*.wpts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All (*)")); @@ -258,7 +258,7 @@ MainWindow::on_actionLoadPoints_triggered() std::vector points; if(fileName.endsWith(".wkt",Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector points_3; CGAL::read_multi_point_WKT(ifs, points_3); for(const K::Point_3& p : points_3) @@ -289,7 +289,7 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".reg.cgal", tr("Weighted Points (*.wpts.cgal);;" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" #endif "All (*)")); @@ -297,7 +297,7 @@ MainWindow::on_actionSavePoints_triggered() std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt",Qt::CaseInsensitive)) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector points_3; for(Regular::Finite_vertices_iterator vit = dt.finite_vertices_begin(), diff --git a/Installation/include/CGAL/config.h b/Installation/include/CGAL/config.h index 76d6fd9366c..a2bf589f727 100644 --- a/Installation/include/CGAL/config.h +++ b/Installation/include/CGAL/config.h @@ -127,20 +127,6 @@ #include #include -// bug-fix for g++-5.x and Boost.Config<1.57 -// https://svn.boost.org/trac/boost/ticket/10500 -#if BOOST_VERSION < 105700 && BOOST_GCC < 60000 && \ - ! defined(__GXX_EXPERIMENTAL_CXX0X__) && defined(BOOST_HAS_VARIADIC_TMPL) -# undef BOOST_HAS_VARIADIC_TMPL -# define BOOST_NO_CXX11_VARIADIC_TEMPLATES -#endif - -// workaround for the bug https://svn.boost.org/trac10/ticket/12534 -// That bug was introduced in Boost 1.62 and fixed in 1.63. -#if BOOST_VERSION >= 106200 && BOOST_VERSION < 106300 -# include -#endif - // Hack: Boost<1.55 does not detect correctly the C++11 features of ICC. // We declare by hand two features that we need (variadic templates and // rvalue references). @@ -187,68 +173,50 @@ // feature is not available, even if that is wrong. // ----------------------------------------------------------------------// -#if defined(BOOST_NO_CXX11_RANGE_BASED_FOR) || BOOST_VERSION < 105000 -#define CGAL_CFG_NO_CPP0X_RANGE_BASED_FOR 1 -#endif -#if defined(BOOST_NO_0X_HDR_ARRAY) || \ - defined(BOOST_NO_CXX11_HDR_ARRAY) || BOOST_VERSION < 104000 +#if defined(BOOST_NO_0X_HDR_ARRAY) #define CGAL_CFG_NO_CPP0X_ARRAY 1 #endif #if defined(BOOST_NO_0X_HDR_UNORDERED_SET) || \ defined(BOOST_NO_0X_HDR_UNORDERED_MAP) || \ - defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) || \ - defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) || \ (defined(_MSC_VER) && (_MSC_VER == 1800)) // std::unordered_set is very bad in MSVC2013 #define CGAL_CFG_NO_CPP0X_UNORDERED 1 #endif -#if defined( BOOST_NO_0X_HDR_THREAD) || \ - defined( BOOST_NO_CXX11_HDR_THREAD) +#if defined( BOOST_NO_0X_HDR_THREAD) #define CGAL_CFG_NO_STD_THREAD 1 #endif -#if defined(BOOST_NO_DECLTYPE) || \ - defined(BOOST_NO_CXX11_DECLTYPE) || (BOOST_VERSION < 103600) +#if defined(BOOST_NO_DECLTYPE) #define CGAL_CFG_NO_CPP0X_DECLTYPE 1 #endif #if defined(BOOST_NO_DELETED_FUNCTIONS) || \ defined(BOOST_NO_DEFAULTED_FUNCTIONS) || \ - defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || \ - defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || (BOOST_VERSION < 103600) || \ (defined(_MSC_VER) && _MSC_VER < 1900) // MSVC 2013 has only partial support #define CGAL_CFG_NO_CPP0X_DELETED_AND_DEFAULT_FUNCTIONS 1 #endif -#if defined(BOOST_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS) || \ - defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) || \ - (BOOST_VERSION < 104100) +#if defined(BOOST_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS) #define CGAL_CFG_NO_CPP0X_DEFAULT_TEMPLATE_ARGUMENTS_FOR_FUNCTION_TEMPLATES 1 #endif -#if defined(BOOST_NO_INITIALIZER_LISTS) || \ - defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) || (BOOST_VERSION < 103900) +#if defined(BOOST_NO_INITIALIZER_LISTS) #define CGAL_CFG_NO_CPP0X_INITIALIZER_LISTS 1 #endif #if defined(BOOST_MSVC) #define CGAL_CFG_NO_CPP0X_ISFINITE 1 // used in #endif -#if defined(BOOST_NO_LONG_LONG) || (BOOST_VERSION < 103600) +#if defined(BOOST_NO_LONG_LONG) #define CGAL_CFG_NO_CPP0X_LONG_LONG 1 #endif -#if defined(BOOST_NO_LAMBDAS) || \ - defined(BOOST_NO_CXX11_LAMBDAS) || BOOST_VERSION < 104000 +#if defined(BOOST_NO_LAMBDAS) #define CGAL_CFG_NO_CPP0X_LAMBDAS 1 #endif -#if defined(BOOST_NO_RVALUE_REFERENCES) || \ - defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || (BOOST_VERSION < 103600) +#if defined(BOOST_NO_RVALUE_REFERENCES) #define CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE 1 #endif -#if defined(BOOST_NO_STATIC_ASSERT) || \ - defined(BOOST_NO_CXX11_STATIC_ASSERT) || (BOOST_VERSION < 103600) +#if defined(BOOST_NO_STATIC_ASSERT) #define CGAL_CFG_NO_CPP0X_STATIC_ASSERT 1 #endif -#if defined(BOOST_NO_0X_HDR_TUPLE) || \ - defined(BOOST_NO_CXX11_HDR_TUPLE) || (BOOST_VERSION < 104000) +#if defined(BOOST_NO_0X_HDR_TUPLE) #define CGAL_CFG_NO_CPP0X_TUPLE 1 #endif -#if defined(BOOST_NO_VARIADIC_TEMPLATES) || \ - defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || (BOOST_VERSION < 103600) +#if defined(BOOST_NO_VARIADIC_TEMPLATES) #define CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES 1 #endif // never use TR1 @@ -258,7 +226,7 @@ #if !defined(__GNUC__) || defined(__INTEL_COMPILER) #define CGAL_CFG_NO_STATEMENT_EXPRESSIONS 1 #endif -#if defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) || (BOOST_VERSION < 105100) || _MSC_VER==1800 +#if _MSC_VER==1800 #define CGAL_CFG_NO_CPP0X_UNIFIED_INITIALIZATION_SYNTAX #endif #if __cplusplus < 201103L && !(_MSC_VER >= 1600) @@ -266,13 +234,10 @@ #define CGAL_CFG_NO_CPP0X_NEXT_PREV 1 #endif #if defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATIONS) \ - || defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATORS) \ - || defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) \ - || (BOOST_VERSION < 103600) + || defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATORS) #define CGAL_CFG_NO_CPP0X_EXPLICIT_CONVERSION_OPERATORS 1 #endif -#if defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) || \ - defined(BOOST_NO_TEMPLATE_ALIASES) || (BOOST_VERSION < 103900) +#if defined(BOOST_NO_TEMPLATE_ALIASES) #define CGAL_CFG_NO_CPP0X_TEMPLATE_ALIASES 1 #endif @@ -303,11 +268,6 @@ # define CGAL_CXX20 1 #endif -#if defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) || BOOST_VERSION < 105000 -#define CGAL_CFG_NO_STD_HASH 1 -#define CGAL_CFG_NO_STD_FUNCTION 1 -#endif - //----------------------------------------------------------------------// // As std::unary_function and std::binary_function are deprecated @@ -365,31 +325,10 @@ // Big endian or little endian machine. // ==================================== -#if (BOOST_VERSION >= 105500) -# include -# if BOOST_ENDIAN_BIG_BYTE -# define CGAL_BIG_ENDIAN -# elif BOOST_ENDIAN_LITTLE_BYTE -# define CGAL_LITTLE_ENDIAN -# endif -#elif defined (__GLIBC__) -# include -# if (__BYTE_ORDER == __LITTLE_ENDIAN) -# define CGAL_LITTLE_ENDIAN -# elif (__BYTE_ORDER == __BIG_ENDIAN) -# define CGAL_BIG_ENDIAN -# endif -#elif defined(__sparc) || defined(__sparc__) \ - || defined(_POWER) || defined(__powerpc__) \ - || defined(__ppc__) || defined(__hppa) \ - || defined(_MIPSEB) || defined(_POWER) \ - || defined(__s390__) +#include +#if BOOST_ENDIAN_BIG_BYTE # define CGAL_BIG_ENDIAN -#elif defined(__i386__) || defined(__alpha__) \ - || defined(__x86_64) || defined(__x86_64__) \ - || defined(__ia64) || defined(__ia64__) \ - || defined(_M_IX86) || defined(_M_IA64) \ - || defined(_M_ALPHA) || defined(_WIN64) +#elif BOOST_ENDIAN_LITTLE_BYTE # define CGAL_LITTLE_ENDIAN #endif @@ -576,15 +515,13 @@ using std::max; #define CGAL_CAN_USE_CXX11_THREAD_LOCAL #endif -#if ( BOOST_VERSION >= 105000 && ! defined(BOOST_NO_CXX11_HDR_MUTEX) ) || \ - (__has_include() && __cplusplus >= 201103L ) | \ +#if (__has_include() && __cplusplus >= 201103L ) | \ ( (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 && __cplusplus >= 201103L ) || \ ( _MSC_VER >= 1700 ) #define CGAL_CAN_USE_CXX11_MUTEX #endif -#if ( BOOST_VERSION >= 105600 && ! defined(BOOST_NO_CXX11_HDR_ATOMIC) ) || \ - (__has_include() && __cplusplus >= 201103L ) || \ +#if (__has_include() && __cplusplus >= 201103L ) || \ ( (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 && __cplusplus >= 201103L ) || \ ( _MSC_VER >= 1700 ) #define CGAL_CAN_USE_CXX11_ATOMIC @@ -656,7 +593,7 @@ typedef const void * Nullptr_t; // Anticipate C++0x's std::nullptr_t } //namespace CGAL //Support for c++11 noexcept -#if BOOST_VERSION > 104600 && !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_NOEXCEPT) +#if !defined(BOOST_NO_NOEXCEPT) #define CGAL_NOEXCEPT(x) noexcept(x) #else #define CGAL_NOEXCEPT(x) @@ -679,11 +616,6 @@ typedef const void * Nullptr_t; // Anticipate C++0x's std::nullptr_t # define CGAL_FALLTHROUGH while(false){} #endif -// https://svn.boost.org/trac/boost/ticket/2839 -#if defined(BOOST_MSVC) && BOOST_VERSION < 105600 -#define CGAL_CFG_BOOST_VARIANT_SWAP_BUG 1 -#endif - #ifndef CGAL_NO_ASSERTIONS # define CGAL_NO_ASSERTIONS_BOOL false #else diff --git a/Mesh_3/benchmark/Mesh_3/CMakeLists.txt b/Mesh_3/benchmark/Mesh_3/CMakeLists.txt index 018035b2122..c7227a64841 100644 --- a/Mesh_3/benchmark/Mesh_3/CMakeLists.txt +++ b/Mesh_3/benchmark/Mesh_3/CMakeLists.txt @@ -79,7 +79,7 @@ if(Boost_PROGRAM_OPTIONS_FOUND) list(APPEND CGAL_3RD_PARTY_LIBRARIES ${Boost_LIBRARIES}) endif() -if(Boost_FOUND AND Boost_VERSION GREATER 103400) +if(Boost_FOUND ) # Compilable benchmark set(BENCHMARK_SOURCE_FILES "concurrency.cpp") add_msvc_precompiled_header("StdAfx.h" "StdAfx.cpp" BENCHMARK_SOURCE_FILES) diff --git a/Mesh_3/include/CGAL/Mesh_3/Is_mesh_domain_field_3.h b/Mesh_3/include/CGAL/Mesh_3/Is_mesh_domain_field_3.h index 25020b3c6b5..aab7f327d52 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Is_mesh_domain_field_3.h +++ b/Mesh_3/include/CGAL/Mesh_3/Is_mesh_domain_field_3.h @@ -21,17 +21,12 @@ #include #include -#if BOOST_VERSION >= 106600 -# include -#else -# include -#endif +#include #include namespace CGAL { namespace Mesh_3 { -#if BOOST_VERSION >= 106600 template struct Is_mesh_domain_field_3 : public CGAL::Boolean_tag @@ -45,12 +40,6 @@ namespace CGAL { >::value > {}; -#else // Boost before 1.66 - BOOST_MPL_HAS_XXX_TRAIT_DEF(FT) - template - struct Is_mesh_domain_field_3 : public Boolean_tag::value> - {}; -#endif // Boost before 1.66 } // end namespace Mesh_3 } // end namespace CGAL diff --git a/Mesh_3/include/CGAL/Mesh_cell_criteria_3.h b/Mesh_3/include/CGAL/Mesh_cell_criteria_3.h index e7e4466949b..1a5508d034b 100644 --- a/Mesh_3/include/CGAL/Mesh_cell_criteria_3.h +++ b/Mesh_3/include/CGAL/Mesh_cell_criteria_3.h @@ -21,9 +21,7 @@ #include #include -#if BOOST_VERSION >= 106600 # include -#endif #include diff --git a/Mesh_3/test/Mesh_3/test_mesh_capsule_var_distance_bound.cpp b/Mesh_3/test/Mesh_3/test_mesh_capsule_var_distance_bound.cpp index b0c54cb5e74..68de83c5e41 100644 --- a/Mesh_3/test/Mesh_3/test_mesh_capsule_var_distance_bound.cpp +++ b/Mesh_3/test/Mesh_3/test_mesh_capsule_var_distance_bound.cpp @@ -40,24 +40,12 @@ FT capsule_function(const Point& p) else if(z < FT(-5)) return base+CGAL::square(z+5); else return base; } -#if BOOST_VERSION >= 106600 auto field = [](const Point& p, const int, const Mesh_domain::Index) { if(p.z() > 2) return 0.025; if(p.z() < -3) return 0.01; else return 1.; }; -#else -struct Field { - typedef ::FT FT; - - FT operator()(const Point& p, const int, const Mesh_domain::Index) const { - if(p.z() > 2) return 0.025; - if(p.z() < -3) return 0.01; - else return 1; - } -} field; -#endif int main() { diff --git a/Mesher_level/include/CGAL/Double_map.h b/Mesher_level/include/CGAL/Double_map.h index 927324a69a1..1c277fc678f 100644 --- a/Mesher_level/include/CGAL/Double_map.h +++ b/Mesher_level/include/CGAL/Double_map.h @@ -22,13 +22,7 @@ #include // for CGAL::Identity #include -#if BOOST_VERSION >= 103500 # define CGAL_USE_BOOST_BIMAP -#endif - -#if defined(CGAL_USE_BOOST_BIMAP) && BOOST_VERSION == 104100 -#include -#endif #ifdef CGAL_USE_BOOST_BIMAP # if defined(BOOST_MSVC) diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index e184ec02eee..3548fdc249a 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -13,14 +13,13 @@ #define CGAL_BOOST_MP_H #include -// This could check BOOST_VERSION >= 105300, but before 1.56 there is no -// implicit conversion from double, which makes it hard to use in CGAL. + // It is easier to disable this number type completely for old versions. // Before 1.63, I/O is broken. Again, disabling the whole file is just the // easy solution. // MSVC had trouble with versions <= 1.69: // https://github.com/boostorg/multiprecision/issues/98 -#if !defined CGAL_DO_NOT_USE_BOOST_MP && BOOST_VERSION >= 106300 && \ +#if !defined CGAL_DO_NOT_USE_BOOST_MP && \ (!defined _MSC_VER || BOOST_VERSION >= 107000) #define CGAL_USE_BOOST_MP 1 diff --git a/Point_set_processing_3/test/Point_set_processing_3/normal_estimation_test.cpp b/Point_set_processing_3/test/Point_set_processing_3/normal_estimation_test.cpp index cd011c9b71f..aa1fd02b250 100644 --- a/Point_set_processing_3/test/Point_set_processing_3/normal_estimation_test.cpp +++ b/Point_set_processing_3/test/Point_set_processing_3/normal_estimation_test.cpp @@ -226,15 +226,6 @@ bool run_mst_orient_normals(PointList& points, // input points + input/output no unsigned int nb_neighbors_mst, // number of neighbors const std::vector& original_normals) // may be empty { -#if (BOOST_VERSION / 100) == 1054 - std::cerr << - "In run_mst_orient_normals():\n" - "NOTICE: This function is incompatible with Boost 1.54, " - "and will not be tested. See the following bug:\n" - " https://svn.boost.org/trac/boost/ticket/9012\n"; - return true; -#endif // Boost version is 1.54 - std::cerr << "Orients Normals with a Minimum Spanning Tree (k="<< nb_neighbors_mst << ")...\n"; CGAL::Timer task_timer; task_timer.start(); diff --git a/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp b/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp index 0bf0684ae3f..b4060dc87a7 100644 --- a/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp +++ b/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp @@ -11,7 +11,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -342,7 +342,7 @@ MainWindow::open(QString fileName) this->addToRecentFiles(fileName); } else if(fileName.endsWith(".wkt")){ -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) loadWKT(fileName); this->addToRecentFiles(fileName); #endif @@ -356,7 +356,7 @@ MainWindow::on_actionLoadConstraints_triggered() QString fileName = QFileDialog::getOpenFileName(this, tr("Open Constraint File"), "../data" - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) ,tr("Polylines (*.osm *.wkt);;") #endif ); @@ -376,12 +376,12 @@ std::string trim_right ( std::string str ) } void MainWindow::loadWKT(QString - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) fileName #endif ) { -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) typedef std::vector MultiPoint; typedef std::vector LineString; diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp index 1ccdb7ab524..73c02b71ef0 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp @@ -9,7 +9,7 @@ #include #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #endif @@ -56,7 +56,7 @@ void print(const CT& ct, Constraint_id cid) int main(int argc, char* argv[]) { std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) const bool remove_points = false; CT ct; Polygon_with_holes_2 P; diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp index f815a9b9dd2..2654f8b212c 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp @@ -1,7 +1,7 @@ #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include #include diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp index 989b6b68ba4..ddc6d108a90 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp @@ -1,6 +1,6 @@ #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include #include diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp index f1dfd1da732..58cf2dc6e15 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp @@ -1,7 +1,7 @@ #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include #include @@ -20,7 +20,7 @@ typedef PS::Squared_distance_cost Cost; #endif int main(int argc, char* argv[]) { - #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) Polyline_2 polyline; std::ifstream ifs( (argc==1)?"data/polyline.wkt":argv[1]); CGAL::read_linestring_WKT(ifs, polyline); diff --git a/Property_map/include/CGAL/property_map.h b/Property_map/include/CGAL/property_map.h index bd2cf5dd2ca..2d9023ef6ae 100644 --- a/Property_map/include/CGAL/property_map.h +++ b/Property_map/include/CGAL/property_map.h @@ -15,13 +15,7 @@ #include #include -#if BOOST_VERSION >= 104000 - #include -#else - #include - #include - -#endif +#include #include #include diff --git a/STL_Extension/include/CGAL/demangle.h b/STL_Extension/include/CGAL/demangle.h index 43eccf5d819..ded39262f14 100644 --- a/STL_Extension/include/CGAL/demangle.h +++ b/STL_Extension/include/CGAL/demangle.h @@ -12,22 +12,14 @@ #ifndef CGAL_DEMANGLE_H #define CGAL_DEMANGLE_H -#if BOOST_VERSION >= 105600 #include -#else -#include -#endif namespace CGAL { inline std::string demangle(const char* name) { -#if BOOST_VERSION >= 105600 return boost::core::demangle(name); -#else - return boost::units::detail::demangle(name); -#endif } diff --git a/STL_Extension/include/CGAL/iterator.h b/STL_Extension/include/CGAL/iterator.h index 8395606f4b5..e395ab3c76f 100644 --- a/STL_Extension/include/CGAL/iterator.h +++ b/STL_Extension/include/CGAL/iterator.h @@ -1379,22 +1379,14 @@ public: template Self& operator=(const boost::variant& t) { internal::Output_visitor visitor(this); - #if BOOST_VERSION==105800 t.apply_visitor(visitor); - #else - boost::apply_visitor(visitor, t); - #endif return *this; } template Self& operator=(const boost::optional< boost::variant >& t) { internal::Output_visitor visitor(this); - #if BOOST_VERSION==105800 - if(t) t->apply_visitor(visitor); - #else if(t) boost::apply_visitor(visitor, *t); - #endif return *this; } diff --git a/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_2_impl.h b/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_2_impl.h index 5adacb71a4f..6d15298d618 100644 --- a/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_2_impl.h +++ b/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_2_impl.h @@ -19,10 +19,6 @@ #include #include -#if BOOST_VERSION == 106000 -//ice_not is deprecated in boost 1.60 but used within adjacency_matrix.hpp -#include -#endif #include #if defined(BOOST_MSVC) diff --git a/Stream_support/examples/Stream_support/Linestring_WKT.cpp b/Stream_support/examples/Stream_support/Linestring_WKT.cpp index 6988a1d0ad7..2f0c12b8629 100644 --- a/Stream_support/examples/Stream_support/Linestring_WKT.cpp +++ b/Stream_support/examples/Stream_support/Linestring_WKT.cpp @@ -8,7 +8,7 @@ #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include diff --git a/Stream_support/examples/Stream_support/Point_WKT.cpp b/Stream_support/examples/Stream_support/Point_WKT.cpp index ce6020f4e23..064671a6895 100644 --- a/Stream_support/examples/Stream_support/Point_WKT.cpp +++ b/Stream_support/examples/Stream_support/Point_WKT.cpp @@ -8,7 +8,7 @@ #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include //typedef CGAL::Simple_cartesian Kernel; diff --git a/Stream_support/examples/Stream_support/Polygon_WKT.cpp b/Stream_support/examples/Stream_support/Polygon_WKT.cpp index 19945cf0c57..fe8350a33e5 100644 --- a/Stream_support/examples/Stream_support/Polygon_WKT.cpp +++ b/Stream_support/examples/Stream_support/Polygon_WKT.cpp @@ -9,7 +9,7 @@ #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include diff --git a/Stream_support/examples/Stream_support/read_WKT.cpp b/Stream_support/examples/Stream_support/read_WKT.cpp index 1c9467e7be8..94e5a63320e 100644 --- a/Stream_support/examples/Stream_support/read_WKT.cpp +++ b/Stream_support/examples/Stream_support/read_WKT.cpp @@ -8,7 +8,7 @@ #include #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include diff --git a/Stream_support/include/CGAL/IO/WKT.h b/Stream_support/include/CGAL/IO/WKT.h index 9f81d43f7a9..69ee1bb8387 100644 --- a/Stream_support/include/CGAL/IO/WKT.h +++ b/Stream_support/include/CGAL/IO/WKT.h @@ -15,7 +15,7 @@ #ifndef CGAL_IO_WKT_H #define CGAL_IO_WKT_H -#if defined(DOXYGEN_RUNNING) || (BOOST_VERSION >= 105600 && (!defined(BOOST_GCC) || BOOST_GCC >= 40500)) +#if defined(DOXYGEN_RUNNING) || (!defined(BOOST_GCC) || BOOST_GCC >= 40500)) #include #include diff --git a/Stream_support/include/CGAL/IO/WKT/traits_linestring.h b/Stream_support/include/CGAL/IO/WKT/traits_linestring.h index f16904cdb45..90b28309eb7 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_linestring.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_linestring.h @@ -15,7 +15,7 @@ #ifndef CGAL_IO_WKT_TRAITS_LINESTRING_H #define CGAL_IO_WKT_TRAITS_LINESTRING_H -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include diff --git a/Stream_support/include/CGAL/IO/WKT/traits_multilinestring.h b/Stream_support/include/CGAL/IO/WKT/traits_multilinestring.h index 87d3527fbaf..009124169ca 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_multilinestring.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_multilinestring.h @@ -15,7 +15,7 @@ #ifndef CGAL_IO_WKT_TRAITS_MULTILINESTRING_H #define CGAL_IO_WKT_TRAITS_MULTILINESTRING_H -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include diff --git a/Stream_support/include/CGAL/IO/WKT/traits_multipoint.h b/Stream_support/include/CGAL/IO/WKT/traits_multipoint.h index ac465fdbd42..84bdb29609b 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_multipoint.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_multipoint.h @@ -15,7 +15,7 @@ #ifndef CGAL_IO_WKT_TRAITS_MULTIPOINT_H #define CGAL_IO_WKT_TRAITS_MULTIPOINT_H -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include diff --git a/Stream_support/include/CGAL/IO/WKT/traits_multipolygon.h b/Stream_support/include/CGAL/IO/WKT/traits_multipolygon.h index ab9211492a0..08931e55ff0 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_multipolygon.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_multipolygon.h @@ -15,7 +15,7 @@ #ifndef CGAL_IO_WKT_TRAITS_MULTIPOLYGON_H #define CGAL_IO_WKT_TRAITS_MULTIPOLYGON_H -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include diff --git a/Stream_support/include/CGAL/IO/WKT/traits_point.h b/Stream_support/include/CGAL/IO/WKT/traits_point.h index 788b0f6a7e2..fe9540f76b2 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_point.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_point.h @@ -15,7 +15,7 @@ #ifndef CGAL_IO_WKT_TRAITS_POINT_H #define CGAL_IO_WKT_TRAITS_POINT_H -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include diff --git a/Stream_support/include/CGAL/IO/WKT/traits_point_3.h b/Stream_support/include/CGAL/IO/WKT/traits_point_3.h index 20030835d45..fcc7eeffb82 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_point_3.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_point_3.h @@ -15,7 +15,7 @@ #ifndef CGAL_IO_WKT_TRAITS_POINT_3_H #define CGAL_IO_WKT_TRAITS_POINT_3_H -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include diff --git a/Stream_support/include/CGAL/IO/WKT/traits_polygon.h b/Stream_support/include/CGAL/IO/WKT/traits_polygon.h index bbc8bbd204f..639ef39d33a 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_polygon.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_polygon.h @@ -15,7 +15,7 @@ #ifndef CGAL_IO_WKT_TRAITS_POLYGON_H #define CGAL_IO_WKT_TRAITS_POLYGON_H -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include diff --git a/Stream_support/include/CGAL/internal/Geometry_container.h b/Stream_support/include/CGAL/internal/Geometry_container.h index 944492c6d80..d1214ceca17 100644 --- a/Stream_support/include/CGAL/internal/Geometry_container.h +++ b/Stream_support/include/CGAL/internal/Geometry_container.h @@ -14,7 +14,7 @@ #ifndef GEOMETRY_CONTAINER_H #define GEOMETRY_CONTAINER_H -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include #include diff --git a/Stream_support/test/Stream_support/test_WKT.cpp b/Stream_support/test/Stream_support/test_WKT.cpp index 426469bff3b..b3fba823b45 100644 --- a/Stream_support/test/Stream_support/test_WKT.cpp +++ b/Stream_support/test/Stream_support/test_WKT.cpp @@ -1,6 +1,6 @@ #include -#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500) +#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include diff --git a/Surface_mesh_topology/include/CGAL/Path_on_surface.h b/Surface_mesh_topology/include/CGAL/Path_on_surface.h index 71b4156eaec..3df8fa857d8 100644 --- a/Surface_mesh_topology/include/CGAL/Path_on_surface.h +++ b/Surface_mesh_topology/include/CGAL/Path_on_surface.h @@ -882,10 +882,7 @@ public: return boost::algorithm::knuth_morris_pratt_search(pp2.m_path.begin(), pp2.m_path.end(), pp1.m_path.begin(), - pp1.m_path.end()) -#if BOOST_VERSION>=106200 - .first -#endif + pp1.m_path.end()).first !=pp2.m_path.end(); } bool operator!=(const Self& other) const @@ -1118,11 +1115,7 @@ public: auto itMatch = boost::algorithm::knuth_morris_pratt_search(pp2.m_path.begin() + 1, pp2.m_path.end(), pp1.m_path.begin(), - pp1.m_path.end()) -#if BOOST_VERSION>=106200 - .first -#endif - ; + pp1.m_path.end()).first; /// It can be proved that the first match location is the length of match auto primitiveSize = itMatch - pp2.m_path.begin(); auto originalLength = pp1.length(); diff --git a/TDS_3/include/CGAL/Triangulation_data_structure_3.h b/TDS_3/include/CGAL/Triangulation_data_structure_3.h index b3927cf03ae..193e9dae561 100644 --- a/TDS_3/include/CGAL/Triangulation_data_structure_3.h +++ b/TDS_3/include/CGAL/Triangulation_data_structure_3.h @@ -1009,9 +1009,7 @@ public: Vertex_extractor(Vertex_handle _v, OutputIterator _output, const Tds* _t, Filter _filter): v(_v), treat(_output), t(_t), filter(_filter) { -#if ( BOOST_VERSION >= 105000 ) tmp_vertices.reserve(64); -#endif } void operator()(Cell_handle c) { diff --git a/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h b/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h index 4bf3477f31c..c6c79d6bae1 100644 --- a/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h +++ b/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h @@ -29,12 +29,7 @@ #include #include #include - -#if defined(BOOST_MSVC) && (BOOST_VERSION == 105500) -#include -#else #include -#endif namespace CGAL { @@ -987,12 +982,7 @@ insert_subconstraint(Vertex_handle vaa, // edges may contain mirror edges. They no longer exist after triangulate_hole // so we have to remove them before calling get_bounded_faces if(! edges.empty()){ - -#if defined(BOOST_MSVC) && (BOOST_VERSION == 105500) - std::set faces(intersected_faces.begin(), intersected_faces.end()); -#else boost::container::flat_set faces(intersected_faces.begin(), intersected_faces.end()); -#endif for(typename List_edges::iterator it = edges.begin(); it!= edges.end();){ if(faces.find(it->first) != faces.end()){ typename List_edges::iterator it2 = it; From e6c767d5c9869ab050102efe0dd4629ece65a447 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 12 May 2021 15:45:07 +0200 Subject: [PATCH 208/349] Simplify the GNUC versions tests --- Apollonius_graph_2/include/CGAL/Hyperbola_ray_2.h | 10 +--------- .../CGAL/Arr_point_location/Td_X_trapezoid.h | 5 ----- .../CGAL/Arr_point_location/Td_active_edge.h | 6 ------ .../Td_active_fictitious_vertex.h | 6 ------ .../CGAL/Arr_point_location/Td_active_trapezoid.h | 6 ------ .../CGAL/Arr_point_location/Td_active_vertex.h | 6 ------ .../CGAL/Arr_point_location/Td_inactive_edge.h | 6 ------ .../Td_inactive_fictitious_vertex.h | 6 ------ .../CGAL/Arr_point_location/Td_inactive_vertex.h | 6 ------ .../Trapezoidal_decomposition_2_misc.h | 2 -- BGL/include/CGAL/boost/parameter.h | 2 +- .../benchmark/parser/benchmark_parser.cpp | 2 +- Combinatorial_map/include/CGAL/Combinatorial_map.h | 4 ++-- .../include/CGAL/Combinatorial_map_storages.h | 4 ++-- Generalized_map/include/CGAL/Generalized_map.h | 4 ++-- .../include/CGAL/Generalized_map_storages.h | 4 ++-- .../demo/Alpha_shapes_2/Alpha_shapes_2.cpp | 6 ------ .../demo/Apollonius_graph_2/Apollonius_graph_2.cpp | 10 ---------- .../demo/Bounding_volumes/Bounding_volumes.cpp | 10 ---------- .../demo/Circular_kernel_2/Circular_kernel_2.cpp | 6 ------ .../L1_Voronoi_diagram_2/L1_voronoi_diagram_2.cpp | 10 ---------- .../Periodic_2_Delaunay_triangulation_2.cpp | 10 ---------- GraphicsView/demo/Polygon/Polygon_2.cpp | 10 ---------- .../Segment_Delaunay_graph_2/Segment_voronoi_2.cpp | 11 +---------- .../Segment_voronoi_linf_2.cpp | 14 +------------- .../demo/Snap_rounding_2/Snap_rounding_2.cpp | 10 ---------- .../Spatial_searching_2/Spatial_searching_2.cpp | 6 ------ .../demo/Stream_lines_2/Stream_lines_2.cpp | 13 ------------- .../Constrained_Delaunay_triangulation_2.cpp | 14 +------------- .../Triangulation_2/Delaunay_triangulation_2.cpp | 10 ---------- .../Triangulation_2/Regular_triangulation_2.cpp | 10 ---------- Installation/CMakeLists.txt | 5 ----- .../config/support/CGAL_test_cpp_version.cpp | 2 +- Installation/include/CGAL/config.h | 10 +++++----- Installation/include/CGAL/export/helpers.h | 2 +- .../CGAL/CMap_linear_cell_complex_storages.h | 4 ++-- .../CGAL/GMap_linear_cell_complex_storages.h | 4 ++-- NewKernel_d/include/CGAL/NewKernel_d/Vector/avx4.h | 2 +- NewKernel_d/include/CGAL/NewKernel_d/Vector/sse2.h | 2 +- NewKernel_d/test/NewKernel_d/Epick_d.cpp | 11 ----------- Number_types/include/CGAL/FPU.h | 5 ++--- .../CGAL/Partition_2/partition_approx_convex_2.h | 4 ++-- ...cls_periodic_3_regular_triangulation_traits_3.h | 2 +- .../_test_cls_periodic_3_triangulation_traits_3.h | 2 +- .../Polyline_simplification_2.cpp | 14 +------------- .../points_and_vertices.cpp | 6 ------ .../Polyline_simplification_2/simplify.cpp | 8 -------- .../Polyline_simplification_2/simplify_polygon.cpp | 7 ------- .../simplify_polyline.cpp | 5 ----- .../examples/Stream_support/Linestring_WKT.cpp | 8 -------- .../examples/Stream_support/Point_WKT.cpp | 8 -------- .../examples/Stream_support/Polygon_WKT.cpp | 8 -------- .../examples/Stream_support/read_WKT.cpp | 10 ---------- Stream_support/include/CGAL/IO/WKT.h | 4 ---- .../include/CGAL/IO/WKT/traits_linestring.h | 3 --- .../include/CGAL/IO/WKT/traits_multilinestring.h | 3 --- .../include/CGAL/IO/WKT/traits_multipoint.h | 4 ---- .../include/CGAL/IO/WKT/traits_multipolygon.h | 3 --- Stream_support/include/CGAL/IO/WKT/traits_point.h | 3 --- .../include/CGAL/IO/WKT/traits_point_3.h | 3 --- .../include/CGAL/IO/WKT/traits_polygon.h | 3 --- .../include/CGAL/internal/Geometry_container.h | 2 -- Stream_support/test/Stream_support/test_WKT.cpp | 8 +------- .../Triangulation/delaunay_triangulation.cpp | 11 ----------- .../examples/Triangulation/triangulation.cpp | 9 --------- Triangulation/test/Triangulation/test_delaunay.cpp | 11 ----------- Triangulation/test/Triangulation/test_torture.cpp | 10 ---------- .../test/Triangulation/test_triangulation.cpp | 10 ---------- 68 files changed, 35 insertions(+), 410 deletions(-) diff --git a/Apollonius_graph_2/include/CGAL/Hyperbola_ray_2.h b/Apollonius_graph_2/include/CGAL/Hyperbola_ray_2.h index bbd6c7b089b..490d320d11d 100644 --- a/Apollonius_graph_2/include/CGAL/Hyperbola_ray_2.h +++ b/Apollonius_graph_2/include/CGAL/Hyperbola_ray_2.h @@ -44,20 +44,12 @@ public: using Base::f; protected: -#if defined(__POWERPC__) && \ - defined(__GNUC__) && (__GNUC__ == 3 ) && (__GNUC_MINOR__ == 4) - // hack to avoid nasty warning for G++ 3.4 on Darwin - static FT OFFSET() - { - return FT(10000); - } -#else + static const FT& OFFSET() { static const FT offset_(10000); return offset_; } -#endif template< class Stream > inline diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_X_trapezoid.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_X_trapezoid.h index e7202ffe935..98f95bac53f 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_X_trapezoid.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_X_trapezoid.h @@ -124,13 +124,8 @@ public: friend class Trapezoidal_decomposition_2::In_face_iterator; #elif defined(__GNUC__) -#if ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ <= 2))) - friend typename Trapezoidal_decomposition_2::Around_point_circulator; - friend typename Trapezoidal_decomposition_2::In_face_iterator; -#else friend class Trapezoidal_decomposition_2::Around_point_circulator; friend class Trapezoidal_decomposition_2::In_face_iterator; -#endif #else friend class Around_point_circulator; diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_edge.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_edge.h index 61259f33547..572d3aa9505 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_edge.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_edge.h @@ -95,13 +95,7 @@ public: #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; #elif defined(__GNUC__) - -#if ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ <= 2))) - friend typename Trapezoidal_decomposition_2::In_face_iterator; -#else friend class Trapezoidal_decomposition_2::In_face_iterator; -#endif - #else friend class In_face_iterator; #endif diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_fictitious_vertex.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_fictitious_vertex.h index b75de1b9d97..7905bf6a21e 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_fictitious_vertex.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_fictitious_vertex.h @@ -95,13 +95,7 @@ public: #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; #elif defined(__GNUC__) - -#if ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ <= 2))) - friend typename Trapezoidal_decomposition_2::In_face_iterator; -#else friend class Trapezoidal_decomposition_2::In_face_iterator; -#endif - #else friend class In_face_iterator; #endif diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_trapezoid.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_trapezoid.h index 8b92b739626..d7d55a86846 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_trapezoid.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_trapezoid.h @@ -92,13 +92,7 @@ public: #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; #elif defined(__GNUC__) - -#if ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ <= 2))) - friend typename Trapezoidal_decomposition_2::In_face_iterator; -#else friend class Trapezoidal_decomposition_2::In_face_iterator; -#endif - #else friend class In_face_iterator; #endif diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_vertex.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_vertex.h index 3b3e86aa0c6..77ff7b59286 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_vertex.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_vertex.h @@ -97,13 +97,7 @@ public: #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; #elif defined(__GNUC__) - -#if ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ <= 2))) - friend typename Trapezoidal_decomposition_2::In_face_iterator; -#else friend class Trapezoidal_decomposition_2::In_face_iterator; -#endif - #else friend class In_face_iterator; #endif diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_edge.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_edge.h index bb57f7c6d1c..1dbda6937db 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_edge.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_edge.h @@ -94,13 +94,7 @@ public: #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; #elif defined(__GNUC__) - -#if ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ <= 2))) - friend typename Trapezoidal_decomposition_2::In_face_iterator; -#else friend class Trapezoidal_decomposition_2::In_face_iterator; -#endif - #else friend class In_face_iterator; #endif diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_fictitious_vertex.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_fictitious_vertex.h index 03ca8d563c7..c61205c26cd 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_fictitious_vertex.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_fictitious_vertex.h @@ -97,13 +97,7 @@ public: #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; #elif defined(__GNUC__) - -#if ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ <= 2))) - friend typename Trapezoidal_decomposition_2::In_face_iterator; -#else friend class Trapezoidal_decomposition_2::In_face_iterator; -#endif - #else friend class In_face_iterator; #endif diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_vertex.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_vertex.h index 409a6f576ee..6a7e6c0eb05 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_vertex.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_vertex.h @@ -93,13 +93,7 @@ public: #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; #elif defined(__GNUC__) - -#if ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ <= 2))) - friend typename Trapezoidal_decomposition_2::In_face_iterator; -#else friend class Trapezoidal_decomposition_2::In_face_iterator; -#endif - #else friend class In_face_iterator; #endif diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Trapezoidal_decomposition_2_misc.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Trapezoidal_decomposition_2_misc.h index a6eca6682ed..4f939643501 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Trapezoidal_decomposition_2_misc.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Trapezoidal_decomposition_2_misc.h @@ -46,9 +46,7 @@ #define CGAL_TD_DEFAULT_SIZE_THRESHOLD 12 #ifndef _MSC_VER -#if !defined __GNUC__ || __GNUC__> 3 || ((__GNUC__== 3) && (__GNUC_MINOR__> 4)) #define CGAL_PM_FRIEND_CLASS #endif -#endif #endif diff --git a/BGL/include/CGAL/boost/parameter.h b/BGL/include/CGAL/boost/parameter.h index d4f213919d2..9c28ac96b7a 100644 --- a/BGL/include/CGAL/boost/parameter.h +++ b/BGL/include/CGAL/boost/parameter.h @@ -25,7 +25,7 @@ #include -#if defined(__clang__) || (BOOST_GCC >= 40600) +#if defined(__clang__) || defined(BOOST_GCC) # define CGAL_IGNORE_UNUSED_VARIABLES \ _Pragma("GCC diagnostic ignored \"-Wunused-variable\"") \ _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") diff --git a/Circular_kernel_2/benchmark/parser/benchmark_parser.cpp b/Circular_kernel_2/benchmark/parser/benchmark_parser.cpp index 1c8177b2793..daab78244d1 100644 --- a/Circular_kernel_2/benchmark/parser/benchmark_parser.cpp +++ b/Circular_kernel_2/benchmark/parser/benchmark_parser.cpp @@ -232,7 +232,7 @@ union yyalloc /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY -# if defined (__GNUC__) && 1 < __GNUC__ +# if defined (__GNUC__) # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map.h b/Combinatorial_map/include/CGAL/Combinatorial_map.h index 580444e9812..0d151b33edd 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map.h @@ -55,7 +55,7 @@ #endif #include -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Warray-bounds\"") #endif @@ -4824,7 +4824,7 @@ namespace CGAL { } // namespace CGAL -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic pop") #endif diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map_storages.h b/Combinatorial_map/include/CGAL/Combinatorial_map_storages.h index 08eabb22f24..949eb1ebc36 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map_storages.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map_storages.h @@ -19,7 +19,7 @@ #include #include -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Warray-bounds\"") #endif @@ -439,7 +439,7 @@ namespace CGAL { } // namespace CGAL -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic pop") #endif diff --git a/Generalized_map/include/CGAL/Generalized_map.h b/Generalized_map/include/CGAL/Generalized_map.h index 3c79b6d2c37..eb616218dac 100644 --- a/Generalized_map/include/CGAL/Generalized_map.h +++ b/Generalized_map/include/CGAL/Generalized_map.h @@ -42,7 +42,7 @@ #endif #include -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Warray-bounds\"") #endif @@ -3890,7 +3890,7 @@ namespace CGAL { } // namespace CGAL -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic pop") #endif diff --git a/Generalized_map/include/CGAL/Generalized_map_storages.h b/Generalized_map/include/CGAL/Generalized_map_storages.h index 56040f48759..837717fe68f 100644 --- a/Generalized_map/include/CGAL/Generalized_map_storages.h +++ b/Generalized_map/include/CGAL/Generalized_map_storages.h @@ -19,7 +19,7 @@ #include #include -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Warray-bounds\"") #endif @@ -426,7 +426,7 @@ namespace CGAL { } // namespace CGAL -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic pop") #endif #endif // CGAL_GENERALIZED_MAP_STORAGES_H // diff --git a/GraphicsView/demo/Alpha_shapes_2/Alpha_shapes_2.cpp b/GraphicsView/demo/Alpha_shapes_2/Alpha_shapes_2.cpp index 792c948ac9e..2d3510d149d 100644 --- a/GraphicsView/demo/Alpha_shapes_2/Alpha_shapes_2.cpp +++ b/GraphicsView/demo/Alpha_shapes_2/Alpha_shapes_2.cpp @@ -7,9 +7,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif #include // Qt headers @@ -253,9 +251,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wktk *.WKT);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ open(fileName); @@ -274,9 +270,7 @@ MainWindow::open(QString fileName) std::ifstream ifs(qPrintable(fileName)); if(fileName.endsWith(".wkt",Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, points); -#endif } else { diff --git a/GraphicsView/demo/Apollonius_graph_2/Apollonius_graph_2.cpp b/GraphicsView/demo/Apollonius_graph_2/Apollonius_graph_2.cpp index b92b9e3600d..de99028b06f 100644 --- a/GraphicsView/demo/Apollonius_graph_2/Apollonius_graph_2.cpp +++ b/GraphicsView/demo/Apollonius_graph_2/Apollonius_graph_2.cpp @@ -7,9 +7,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif #include #include @@ -220,9 +218,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.wpts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ open(fileName); @@ -241,14 +237,12 @@ MainWindow::open(QString fileName) std::vector points; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector point_3_s; CGAL::read_multi_point_WKT(ifs, point_3_s); for(const K::Point_3& point_3 : point_3_s) { points.push_back(Apollonius_site_2(K::Point_2(point_3.x(), point_3.y()), point_3.z())); } -#endif } else{ K::Weighted_point_2 p; while(ifs >> p) { @@ -270,15 +264,12 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".reg.cgal", tr("Weighted Points (*.wpts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files(*.wkt *.WKT);;" - #endif "All (*)")); if(! fileName.isEmpty()){ std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt",Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector points; for(Apollonius::Sites_iterator vit = ag.sites_begin(), @@ -290,7 +281,6 @@ MainWindow::on_actionSavePoints_triggered() vit->weight())); } CGAL::write_multi_point_WKT(ofs, points); -#endif } else for(Apollonius::Sites_iterator diff --git a/GraphicsView/demo/Bounding_volumes/Bounding_volumes.cpp b/GraphicsView/demo/Bounding_volumes/Bounding_volumes.cpp index 574e61bd33d..fa6f3c1dd50 100644 --- a/GraphicsView/demo/Bounding_volumes/Bounding_volumes.cpp +++ b/GraphicsView/demo/Bounding_volumes/Bounding_volumes.cpp @@ -15,9 +15,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif // Qt headers #include @@ -479,9 +477,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ open(fileName); @@ -497,14 +493,12 @@ MainWindow::open(QString fileName) std::ifstream ifs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, points); for(K::Point_2 p : points) { mc.insert(p); me.insert(p); } -#endif } else { @@ -532,15 +526,12 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".", tr("CGAL files (*.pts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector out_pts; out_pts.reserve(std::distance(mc.points_begin(), mc.points_end())); @@ -548,7 +539,6 @@ MainWindow::on_actionSavePoints_triggered() pit != mc.points_end(); ++pit) out_pts.push_back(*pit); CGAL::write_multi_point_WKT(ofs, out_pts); -#endif } else { diff --git a/GraphicsView/demo/Circular_kernel_2/Circular_kernel_2.cpp b/GraphicsView/demo/Circular_kernel_2/Circular_kernel_2.cpp index 4c6df0c026c..8cd2cd19f77 100644 --- a/GraphicsView/demo/Circular_kernel_2/Circular_kernel_2.cpp +++ b/GraphicsView/demo/Circular_kernel_2/Circular_kernel_2.cpp @@ -10,9 +10,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif // Qt headers #include @@ -216,9 +214,7 @@ MainWindow::on_actionLoadLineAndCircularArcs_triggered() tr("Open Line and Circular Arc File"), ".", tr("Edge files (*.arc)\n" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT)\n" - #endif )); if(! fileName.isEmpty()){ open(fileName); @@ -236,7 +232,6 @@ MainWindow::open(QString fileName) double x,y; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) //read pairs as Line_arc_2 and triplets as circular_arc_2 do { @@ -279,7 +274,6 @@ MainWindow::open(QString fileName) } }while(ifs.good() && !ifs.eof()); ifs.close(); -#endif } else { diff --git a/GraphicsView/demo/L1_Voronoi_diagram_2/L1_voronoi_diagram_2.cpp b/GraphicsView/demo/L1_Voronoi_diagram_2/L1_voronoi_diagram_2.cpp index 4e1399bd680..5028c398dcc 100644 --- a/GraphicsView/demo/L1_Voronoi_diagram_2/L1_voronoi_diagram_2.cpp +++ b/GraphicsView/demo/L1_Voronoi_diagram_2/L1_voronoi_diagram_2.cpp @@ -24,9 +24,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif #include @@ -275,9 +273,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ open(fileName); @@ -295,9 +291,7 @@ MainWindow::open(QString fileName) std::ifstream ifs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, m_sites); -#endif } else { @@ -322,16 +316,12 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".", tr("CGAL files (*.pts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All files (*)")); if(! fileName.isEmpty()) { std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)){ -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::write_multi_point_WKT(ofs, m_sites); -#endif }else for(Points::iterator it = m_sites.begin(); it != m_sites.end(); ++it) diff --git a/GraphicsView/demo/Periodic_2_triangulation_2/Periodic_2_Delaunay_triangulation_2.cpp b/GraphicsView/demo/Periodic_2_triangulation_2/Periodic_2_Delaunay_triangulation_2.cpp index a945124a01b..ebf0581fa31 100644 --- a/GraphicsView/demo/Periodic_2_triangulation_2/Periodic_2_Delaunay_triangulation_2.cpp +++ b/GraphicsView/demo/Periodic_2_triangulation_2/Periodic_2_Delaunay_triangulation_2.cpp @@ -8,9 +8,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif // Qt headers #include @@ -355,9 +353,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ open(fileName); @@ -376,9 +372,7 @@ MainWindow::open(QString fileName) std::vector points; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, points); -#endif } else { @@ -404,15 +398,12 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".", tr("CGAL files (*.pts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector points; points.reserve(std::distance(triang.unique_vertices_begin(), triang.unique_vertices_end())); @@ -424,7 +415,6 @@ MainWindow::on_actionSavePoints_triggered() points.push_back(vit->point()); } CGAL::write_multi_point_WKT(ofs, points); -#endif } else { diff --git a/GraphicsView/demo/Polygon/Polygon_2.cpp b/GraphicsView/demo/Polygon/Polygon_2.cpp index 98b001a7c28..58cb263d020 100644 --- a/GraphicsView/demo/Polygon/Polygon_2.cpp +++ b/GraphicsView/demo/Polygon/Polygon_2.cpp @@ -13,9 +13,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif // Qt headers #include @@ -234,9 +232,7 @@ MainWindow::on_actionLoadPolygon_triggered() ".", tr( "Polyline files (*.polygons.cgal);;" "WSL files (*.wsl);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All file (*)")); if(! fileName.isEmpty()){ open(fileName); @@ -251,12 +247,10 @@ MainWindow::open(QString fileName) poly.clear(); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::Polygon_with_holes_2 P; CGAL::read_polygon_WKT(ifs, P); poly = Polygon2(P.outer_boundary().begin(), P.outer_boundary().end()); -#endif } else { @@ -276,20 +270,16 @@ MainWindow::on_actionSavePolygon_triggered() tr("Save Polygon"), ".", tr( "Polyline files (*.polygons.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All file (*)")); if(! fileName.isEmpty()){ std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::Polygon_2 P(poly.begin(), poly.end()); CGAL::Polygon_with_holes_2 Pwh(P); CGAL::write_polygon_WKT(ofs, Pwh); -#endif } else ofs << poly; diff --git a/GraphicsView/demo/Segment_Delaunay_graph_2/Segment_voronoi_2.cpp b/GraphicsView/demo/Segment_Delaunay_graph_2/Segment_voronoi_2.cpp index 1e53c0603bb..b5af8b11c16 100644 --- a/GraphicsView/demo/Segment_Delaunay_graph_2/Segment_voronoi_2.cpp +++ b/GraphicsView/demo/Segment_Delaunay_graph_2/Segment_voronoi_2.cpp @@ -25,9 +25,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif //#include // the two base classes @@ -248,10 +246,8 @@ MainWindow::open(QString fileName) loadEdgConstraints(fileName); this->addToRecentFiles(fileName); } else if(fileName.endsWith(".wkt", Qt::CaseInsensitive)){ -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) loadWKTConstraints(fileName); this->addToRecentFiles(fileName); -#endif } } } @@ -264,9 +260,7 @@ MainWindow::on_actionLoadSegments_triggered() ".", tr("Edge files (*.edg);;" "Polyline files (*.polygons.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT)" - #endif )); open(fileName); } @@ -342,12 +336,10 @@ MainWindow::loadEdgConstraints(QString fileName) void MainWindow::loadWKTConstraints(QString - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) fileName - #endif ) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) + typedef CGAL::Polygon_with_holes_2 Polygon; typedef std::vector LineString; @@ -414,7 +406,6 @@ MainWindow::loadWKTConstraints(QString }while(ifs.good() && !ifs.eof()); Q_EMIT( changed()); actionRecenter->trigger(); -#endif } void diff --git a/GraphicsView/demo/Segment_Delaunay_graph_Linf_2/Segment_voronoi_linf_2.cpp b/GraphicsView/demo/Segment_Delaunay_graph_Linf_2/Segment_voronoi_linf_2.cpp index 76f7d443e5b..32c060483a0 100644 --- a/GraphicsView/demo/Segment_Delaunay_graph_Linf_2/Segment_voronoi_linf_2.cpp +++ b/GraphicsView/demo/Segment_Delaunay_graph_Linf_2/Segment_voronoi_linf_2.cpp @@ -23,9 +23,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif //#include // the two base classes @@ -270,10 +268,8 @@ MainWindow::open(QString fileName) loadSitesInput(fileName); this->addToRecentFiles(fileName); } else if(fileName.endsWith(".wkt", Qt::CaseInsensitive)){ -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) loadWKT(fileName); this->addToRecentFiles(fileName); -#endif } } } @@ -291,9 +287,7 @@ MainWindow::on_actionLoadSegments_triggered() "Pts files (*.pts);;" "Edge files (*.edg);;" "Polylines files (*.polygons.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt)" - #endif )); open(fileName); } @@ -388,13 +382,8 @@ MainWindow::loadPoints(QString fileName) } void -MainWindow::loadWKT(QString - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) - fileName - #endif - ) +MainWindow::loadWKT(QString fileName ) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::ifstream ifs(qPrintable(fileName)); //Points do @@ -479,7 +468,6 @@ MainWindow::loadWKT(QString Q_EMIT( changed()); actionRecenter->trigger(); -#endif } void diff --git a/GraphicsView/demo/Snap_rounding_2/Snap_rounding_2.cpp b/GraphicsView/demo/Snap_rounding_2/Snap_rounding_2.cpp index b5db6faf4aa..072987b8c62 100644 --- a/GraphicsView/demo/Snap_rounding_2/Snap_rounding_2.cpp +++ b/GraphicsView/demo/Snap_rounding_2/Snap_rounding_2.cpp @@ -20,9 +20,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif // for viewportsBbox #include @@ -252,9 +250,7 @@ MainWindow::on_actionLoadSegments_triggered() tr("Open segment file"), ".", tr("Edge files (*.edg);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ open(fileName); @@ -270,7 +266,6 @@ MainWindow::open(QString fileName) std::ifstream ifs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector > mls; CGAL::read_multi_linestring_WKT(ifs, mls); for(const std::vector& ls : mls) @@ -280,7 +275,6 @@ MainWindow::open(QString fileName) Segment_2 seg(ls[0], ls[1]); input.push_back(seg); } -#endif } else { std::copy(std::istream_iterator(ifs), @@ -304,16 +298,13 @@ MainWindow::on_actionSaveSegments_triggered() tr("Save points"), ".", tr("Edge files (*.edg);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ std::ofstream ofs(qPrintable(fileName)); ofs.precision(12); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector >mls; for(const Segment_2& seg : input) { @@ -323,7 +314,6 @@ MainWindow::on_actionSaveSegments_triggered() mls.push_back(ls); } CGAL::write_multi_linestring_WKT(ofs, mls); -#endif } else std::copy(input.begin(), input.end(), std::ostream_iterator(ofs, "\n")); diff --git a/GraphicsView/demo/Spatial_searching_2/Spatial_searching_2.cpp b/GraphicsView/demo/Spatial_searching_2/Spatial_searching_2.cpp index ba7171f1a85..011daef2925 100644 --- a/GraphicsView/demo/Spatial_searching_2/Spatial_searching_2.cpp +++ b/GraphicsView/demo/Spatial_searching_2/Spatial_searching_2.cpp @@ -17,9 +17,7 @@ // GraphicsView items and event filters (input classes) #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif // the two base classes #include "ui_Spatial_searching_2.h" @@ -249,9 +247,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ open(fileName); @@ -271,9 +267,7 @@ MainWindow::open(QString fileName) std::vector points; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, points); -#endif } else{ while(ifs >> p) { diff --git a/GraphicsView/demo/Stream_lines_2/Stream_lines_2.cpp b/GraphicsView/demo/Stream_lines_2/Stream_lines_2.cpp index 75aebdee97e..afd277fecbb 100644 --- a/GraphicsView/demo/Stream_lines_2/Stream_lines_2.cpp +++ b/GraphicsView/demo/Stream_lines_2/Stream_lines_2.cpp @@ -21,9 +21,7 @@ // for viewportsBbox #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif // the two base classes #include "ui_Stream_lines_2.h" #include @@ -167,14 +165,10 @@ MainWindow::generate() void MainWindow::on_actionLoadPoints_triggered() { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) -#endif QString fileName = QFileDialog::getOpenFileName(this, tr("Open grid file"), "." - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) ,tr("WKT files (*.wkt *.WKT)") - #endif ); if(! fileName.isEmpty()){ open(fileName); @@ -194,7 +188,6 @@ MainWindow::open(QString fileName) iXSize = iYSize = 512; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector > mp; int size= -1; do @@ -216,10 +209,6 @@ MainWindow::open(QString fileName) { regular_grid->set_field(i, j, Vector(mp[j][i].x(), mp[j][i].y())); } -#else - QApplication::restoreOverrideCursor(); - return; -#endif } else{ unsigned int x_samples, y_samples; @@ -248,7 +237,6 @@ MainWindow::open(QString fileName) void MainWindow::on_actionSavePoints_triggered() { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) QString fileName = QFileDialog::getSaveFileName(this, tr("Save points"), ".", @@ -270,7 +258,6 @@ MainWindow::on_actionSavePoints_triggered() } ofs.close(); } -#endif } diff --git a/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp b/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp index 43bf20943e2..be4315874a2 100644 --- a/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp +++ b/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp @@ -25,9 +25,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif // Qt headers #include @@ -528,9 +526,7 @@ MainWindow::open(QString fileName) } else if(fileName.endsWith(".poly")){ loadPolyConstraints(fileName); } else if(fileName.endsWith(".wkt")){ -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) loadWKT(fileName); -#endif } this->addToRecentFiles(fileName); } @@ -549,21 +545,14 @@ MainWindow::on_actionLoadConstraints_triggered() "Poly files (*.poly);;" "Plg files (*.plg);;" "CGAL files (*.cpts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt);;" - #endif "All (*)")); open(fileName); } void -MainWindow::loadWKT(QString - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) - filename - #endif - ) +MainWindow::loadWKT(QString filename) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) //Polygons todo : make it multipolygons std::ifstream ifs(qPrintable(filename)); do @@ -651,7 +640,6 @@ MainWindow::loadWKT(QString discoverComponents(cdt, m_seeds); Q_EMIT( changed()); actionRecenter->trigger(); -#endif } void diff --git a/GraphicsView/demo/Triangulation_2/Delaunay_triangulation_2.cpp b/GraphicsView/demo/Triangulation_2/Delaunay_triangulation_2.cpp index 266bdddbac5..05e7791b0f5 100644 --- a/GraphicsView/demo/Triangulation_2/Delaunay_triangulation_2.cpp +++ b/GraphicsView/demo/Triangulation_2/Delaunay_triangulation_2.cpp @@ -23,9 +23,7 @@ #include "TriangulationPointInputAndConflictZone.h" #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif // for viewportsBbox #include @@ -322,9 +320,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("CGAL files (*.pts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ open(fileName); @@ -343,9 +339,7 @@ MainWindow::open(QString fileName) std::vector points; if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) CGAL::read_multi_point_WKT(ifs, points); -#endif } else while(ifs >> p) { @@ -370,15 +364,12 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".", tr("CGAL files (*.pts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.WKT *.wkt);;" - #endif "All files (*)")); if(! fileName.isEmpty()){ std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt", Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector points; points.reserve(dt.number_of_vertices()); for(Delaunay::Finite_vertices_iterator @@ -389,7 +380,6 @@ MainWindow::on_actionSavePoints_triggered() points.push_back(vit->point()); } CGAL::write_multi_point_WKT(ofs, points); -#endif } else for(Delaunay::Finite_vertices_iterator diff --git a/GraphicsView/demo/Triangulation_2/Regular_triangulation_2.cpp b/GraphicsView/demo/Triangulation_2/Regular_triangulation_2.cpp index 9022ebdf2d7..1be86bffe21 100644 --- a/GraphicsView/demo/Triangulation_2/Regular_triangulation_2.cpp +++ b/GraphicsView/demo/Triangulation_2/Regular_triangulation_2.cpp @@ -5,9 +5,7 @@ // CGAL headers #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif #include // Qt headers @@ -248,9 +246,7 @@ MainWindow::on_actionLoadPoints_triggered() tr("Open Points file"), ".", tr("Weighted Points (*.wpts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All (*)")); if(! fileName.isEmpty()){ @@ -258,14 +254,12 @@ MainWindow::on_actionLoadPoints_triggered() std::vector points; if(fileName.endsWith(".wkt",Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector points_3; CGAL::read_multi_point_WKT(ifs, points_3); for(const K::Point_3& p : points_3) { points.push_back(Weighted_point_2(K::Point_2(p.x(), p.y()), p.z())); } -#endif } else { @@ -289,15 +283,12 @@ MainWindow::on_actionSavePoints_triggered() tr("Save points"), ".reg.cgal", tr("Weighted Points (*.wpts.cgal);;" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) "WKT files (*.wkt *.WKT);;" - #endif "All (*)")); if(! fileName.isEmpty()){ std::ofstream ofs(qPrintable(fileName)); if(fileName.endsWith(".wkt",Qt::CaseInsensitive)) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) std::vector points_3; for(Regular::Finite_vertices_iterator vit = dt.finite_vertices_begin(), @@ -309,7 +300,6 @@ MainWindow::on_actionSavePoints_triggered() vit->point().weight())); } CGAL::write_multi_point_WKT(ofs, points_3); -#endif } else { diff --git a/Installation/CMakeLists.txt b/Installation/CMakeLists.txt index e4d90fb23b6..562687a290a 100644 --- a/Installation/CMakeLists.txt +++ b/Installation/CMakeLists.txt @@ -469,11 +469,6 @@ if(CMAKE_COMPILER_IS_GNUCXX) uniquely_add_flags(CGAL_CXX_FLAGS "-frounding-math") endif() - if("${GCC_VERSION}" MATCHES "^4.2") - message(STATUS "Using gcc version 4.2. Adding -fno-strict-aliasing") - uniquely_add_flags(CGAL_CXX_FLAGS "-fno-strict-aliasing") - endif() - if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "alpha") message(STATUS "Using gcc on alpha. Adding -mieee -mfp-rounding-mode=d") uniquely_add_flags(CGAL_CXX_FLAGS "-mieee -mfp-rounding-mode=d") diff --git a/Installation/cmake/modules/config/support/CGAL_test_cpp_version.cpp b/Installation/cmake/modules/config/support/CGAL_test_cpp_version.cpp index 08c507a9883..61d55a338b9 100644 --- a/Installation/cmake/modules/config/support/CGAL_test_cpp_version.cpp +++ b/Installation/cmake/modules/config/support/CGAL_test_cpp_version.cpp @@ -18,7 +18,7 @@ int main() { #endif #if __has_feature(cxx_thread_local) || \ - ( (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 && __cplusplus >= 201103L ) + ( defined(__GNUC__) && __cplusplus >= 201103L ) return 0; #else return 1; diff --git a/Installation/include/CGAL/config.h b/Installation/include/CGAL/config.h index a2bf589f727..1dc3ee4cd68 100644 --- a/Installation/include/CGAL/config.h +++ b/Installation/include/CGAL/config.h @@ -489,7 +489,7 @@ using std::max; // Macro CGAL_ASSUME // Call a builtin of the compiler to pass a hint to the compiler -#if __has_builtin(__builtin_unreachable) || (CGAL_GCC_VERSION >= 40500 && !__STRICT_ANSI__) +#if __has_builtin(__builtin_unreachable) || (!__STRICT_ANSI__) // From g++ 4.5, there exists a __builtin_unreachable() // Also in LLVM/clang # define CGAL_ASSUME(EX) if(!(EX)) { __builtin_unreachable(); } @@ -509,20 +509,20 @@ using std::max; #endif #if __has_feature(cxx_thread_local) || \ - ( (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 && __cplusplus >= 201103L ) || \ + ( defined(__GNUC__) && __cplusplus >= 201103L ) || \ ( _MSC_VER >= 1900 ) // see also Installation/cmake/modules/config/support/CGAL_test_cpp_version.cpp #define CGAL_CAN_USE_CXX11_THREAD_LOCAL #endif #if (__has_include() && __cplusplus >= 201103L ) | \ - ( (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 && __cplusplus >= 201103L ) || \ + ( defined(__GNUC__) && __cplusplus >= 201103L ) || \ ( _MSC_VER >= 1700 ) #define CGAL_CAN_USE_CXX11_MUTEX #endif #if (__has_include() && __cplusplus >= 201103L ) || \ - ( (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 && __cplusplus >= 201103L ) || \ + ( defined(__GNUC__) && __cplusplus >= 201103L ) || \ ( _MSC_VER >= 1700 ) #define CGAL_CAN_USE_CXX11_ATOMIC #endif @@ -537,7 +537,7 @@ using std::max; #define LEDA_NUMBERS_DLL 1 // Helper macros to disable macros -#if defined(__clang__) || (BOOST_GCC >= 40600) +#if defined(__clang__) || defined(BOOST_GCC) # define CGAL_PRAGMA_DIAG_PUSH _Pragma("GCC diagnostic push") # define CGAL_PRAGMA_DIAG_POP _Pragma("GCC diagnostic pop") #else diff --git a/Installation/include/CGAL/export/helpers.h b/Installation/include/CGAL/export/helpers.h index 89ef455859f..4b384c71f4b 100644 --- a/Installation/include/CGAL/export/helpers.h +++ b/Installation/include/CGAL/export/helpers.h @@ -23,7 +23,7 @@ # define CGAL_DLL_EXPORT __declspec(dllexport) # define CGAL_DLL_LOCAL # else - #if __GNUC__ >= 4 + #ifdef __GNUC__ #define CGAL_DLL_IMPORT __attribute__ ((visibility ("default"))) #define CGAL_DLL_EXPORT __attribute__ ((visibility ("default"))) #define CGAL_DLL_LOCAL __attribute__ ((visibility ("hidden"))) diff --git a/Linear_cell_complex/include/CGAL/CMap_linear_cell_complex_storages.h b/Linear_cell_complex/include/CGAL/CMap_linear_cell_complex_storages.h index c3095592caa..b426792ea16 100644 --- a/Linear_cell_complex/include/CGAL/CMap_linear_cell_complex_storages.h +++ b/Linear_cell_complex/include/CGAL/CMap_linear_cell_complex_storages.h @@ -19,7 +19,7 @@ #include #include -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Warray-bounds\"") #endif @@ -476,7 +476,7 @@ namespace CGAL { } // namespace CGAL -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic pop") #endif diff --git a/Linear_cell_complex/include/CGAL/GMap_linear_cell_complex_storages.h b/Linear_cell_complex/include/CGAL/GMap_linear_cell_complex_storages.h index c48ec047dfd..c1baa30409e 100644 --- a/Linear_cell_complex/include/CGAL/GMap_linear_cell_complex_storages.h +++ b/Linear_cell_complex/include/CGAL/GMap_linear_cell_complex_storages.h @@ -18,7 +18,7 @@ #include #include -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Warray-bounds\"") #endif @@ -460,7 +460,7 @@ namespace CGAL { Items_, Alloc_, Concurrent_tag>::null_handle = nullptr; } // namespace CGAL -#if (BOOST_GCC >= 40900) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic pop") #endif #endif // CGAL_GMAP_LINEAR_CELL_COMPLEX_STORAGES_H // diff --git a/NewKernel_d/include/CGAL/NewKernel_d/Vector/avx4.h b/NewKernel_d/include/CGAL/NewKernel_d/Vector/avx4.h index 1752de0ebb6..950910925a3 100644 --- a/NewKernel_d/include/CGAL/NewKernel_d/Vector/avx4.h +++ b/NewKernel_d/include/CGAL/NewKernel_d/Vector/avx4.h @@ -12,7 +12,7 @@ #ifndef CGAL_VECTOR_AVX4_H #define CGAL_VECTOR_AVX4_H -#if !defined __AVX__ || (__GNUC__ * 100 + __GNUC_MINOR__ < 408) +#if !defined __AVX__ #error Requires AVX and gcc 4.8+ #endif #include diff --git a/NewKernel_d/include/CGAL/NewKernel_d/Vector/sse2.h b/NewKernel_d/include/CGAL/NewKernel_d/Vector/sse2.h index 0359b7b4f45..1330bf6fa77 100644 --- a/NewKernel_d/include/CGAL/NewKernel_d/Vector/sse2.h +++ b/NewKernel_d/include/CGAL/NewKernel_d/Vector/sse2.h @@ -13,7 +13,7 @@ #define CGAL_VECTOR_SSE2_H // Check what needs adapting for clang, intel and microsoft -#if !defined __SSE2__ || (__GNUC__ * 100 + __GNUC_MINOR__ < 408) +#if !defined __SSE2__ #error Requires SSE2 and gcc 4.8+ #endif #include // FIXME: other platforms call it differently diff --git a/NewKernel_d/test/NewKernel_d/Epick_d.cpp b/NewKernel_d/test/NewKernel_d/Epick_d.cpp index 9a1ae6be859..3f13d8970d5 100644 --- a/NewKernel_d/test/NewKernel_d/Epick_d.cpp +++ b/NewKernel_d/test/NewKernel_d/Epick_d.cpp @@ -1,13 +1,4 @@ #include -#if defined(BOOST_GCC) && (__GNUC__ <= 4) && (__GNUC_MINOR__ < 4) - -#include -int main() -{ - std::cerr << "NOTICE: This test requires G++ >= 4.4, and will not be compiled." << std::endl; -} - -#else //#define BOOST_RESULT_OF_USE_DECLTYPE 1 #include @@ -768,5 +759,3 @@ int main(){ test4>(); #endif } - -#endif diff --git a/Number_types/include/CGAL/FPU.h b/Number_types/include/CGAL/FPU.h index 0a324d451a6..8a8cd8a5fea 100644 --- a/Number_types/include/CGAL/FPU.h +++ b/Number_types/include/CGAL/FPU.h @@ -172,7 +172,7 @@ inline double IA_opacify(double x) // Intel has a bug where -mno-sse still defines __SSE__ and __SSE2__ // (-mno-sse2 works though), no work-around for now. # if defined __SSE2_MATH__ || (defined __INTEL_COMPILER && defined __SSE2__) -# if __GNUC__ * 100 + __GNUC_MINOR__ >= 409 +# if defined(__GNUC__) // ICEs in reload/LRA with older versions. asm volatile ("" : "+gx"(x) ); # else @@ -275,8 +275,7 @@ inline __m128d IA_opacify128_weak(__m128d x) inline __m128d swap_m128d(__m128d x){ # ifdef __llvm__ return __builtin_shufflevector(x, x, 1, 0); -# elif defined __GNUC__ && !defined __INTEL_COMPILER \ - && __GNUC__ * 100 + __GNUC_MINOR__ >= 407 +# elif defined __GNUC__ && !defined __INTEL_COMPILER return __builtin_shuffle(x, (__m128i){ 1, 0 }); # else return _mm_shuffle_pd(x, x, 1); diff --git a/Partition_2/include/CGAL/Partition_2/partition_approx_convex_2.h b/Partition_2/include/CGAL/Partition_2/partition_approx_convex_2.h index 72e81ce0786..076e78cee57 100644 --- a/Partition_2/include/CGAL/Partition_2/partition_approx_convex_2.h +++ b/Partition_2/include/CGAL/Partition_2/partition_approx_convex_2.h @@ -17,7 +17,7 @@ #include -#if (BOOST_GCC >= 40800) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") #endif @@ -264,7 +264,7 @@ OutputIterator partition_approx_convex_2(InputIterator first, } } -#if (BOOST_GCC >= 40800) +#if defined(BOOST_GCC) _Pragma("GCC diagnostic pop") #endif #endif // CGAL_PARTITION_APPROX_CONVEX_H diff --git a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h index c59d2d48472..61a9aaf0a80 100644 --- a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h +++ b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h @@ -10,7 +10,7 @@ // Author(s) : Aymeric PELLE // Mael Rouxel-Labbé -#if (__GNUC__>4) || (__GNUC__ == 4 && __GNUC_MINOR__ >=6) +#if defined(__GNUC__) # pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif diff --git a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h index 37ebb32353b..c8ee3c576c6 100644 --- a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h +++ b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h @@ -11,7 +11,7 @@ // Author(s) : Mariette Yvinec // Manuel Caroli -#if (__GNUC__>4) || (__GNUC__ == 4 && __GNUC_MINOR__ >=6) +#if defined(__GNUC__) # pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif diff --git a/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp b/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp index b4060dc87a7..0420f3316d1 100644 --- a/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp +++ b/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp @@ -11,9 +11,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif //#define CGAL_TESTING_POLYLINE_SIMPLIFICATION //#define CGAL_POLYLINE_SIMPLIFICATION_TRACE_LEVEL 15 @@ -342,10 +340,8 @@ MainWindow::open(QString fileName) this->addToRecentFiles(fileName); } else if(fileName.endsWith(".wkt")){ -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) loadWKT(fileName); this->addToRecentFiles(fileName); -#endif } } } @@ -356,9 +352,7 @@ MainWindow::on_actionLoadConstraints_triggered() QString fileName = QFileDialog::getOpenFileName(this, tr("Open Constraint File"), "../data" - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) ,tr("Polylines (*.osm *.wkt);;") - #endif ); open(fileName); } @@ -375,13 +369,8 @@ std::string trim_right ( std::string str ) return std::string("") ; } -void MainWindow::loadWKT(QString - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) - fileName - #endif - ) +void MainWindow::loadWKT(QString fileName) { -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) typedef std::vector MultiPoint; typedef std::vector LineString; @@ -419,7 +408,6 @@ void MainWindow::loadWKT(QString Q_EMIT( changed()); actionRecenter->trigger(); -#endif } diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp index 73c02b71ef0..405f6df707d 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp @@ -9,9 +9,7 @@ #include #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include -#endif namespace PS = CGAL::Polyline_simplification_2; @@ -56,7 +54,6 @@ void print(const CT& ct, Constraint_id cid) int main(int argc, char* argv[]) { std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) const bool remove_points = false; CT ct; Polygon_with_holes_2 P; @@ -75,9 +72,6 @@ int main(int argc, char* argv[]) PS::simplify(ct, cid, Cost(), Stop(0.5), remove_points); ct.remove_points_without_corresponding_vertex(cid); print(ct, cid); -#else - ifs.close(); -#endif return 0; } diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp index 2654f8b212c..b76d665234b 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp @@ -1,7 +1,6 @@ #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include #include @@ -58,10 +57,3 @@ int main(int argc, char* argv[]) return 0; } -#else - -int main() -{ - return 0; -} -#endif diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp index ddc6d108a90..8bdacfd5ff3 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp @@ -1,6 +1,5 @@ #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include #include @@ -30,9 +29,3 @@ int main(int argc, char* argv[]) return 0; } -#else -int main() -{ - return 0; -} -#endif diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp index 58cf2dc6e15..8277f62cc20 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp @@ -1,7 +1,5 @@ #include #include - -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include #include @@ -17,10 +15,8 @@ typedef K::Point_2 Point_2; typedef std::deque Polyline_2; typedef PS::Stop_above_cost_threshold Stop; typedef PS::Squared_distance_cost Cost; -#endif int main(int argc, char* argv[]) { - #if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) Polyline_2 polyline; std::ifstream ifs( (argc==1)?"data/polyline.wkt":argv[1]); CGAL::read_linestring_WKT(ifs, polyline); @@ -32,6 +28,5 @@ int main(int argc, char* argv[]) for(std::size_t i=0; i < result.size(); ++i){ std::cout << result[i] << std::endl; } -#endif return 0; } diff --git a/Stream_support/examples/Stream_support/Linestring_WKT.cpp b/Stream_support/examples/Stream_support/Linestring_WKT.cpp index 2f0c12b8629..04fb6d5dc8c 100644 --- a/Stream_support/examples/Stream_support/Linestring_WKT.cpp +++ b/Stream_support/examples/Stream_support/Linestring_WKT.cpp @@ -8,8 +8,6 @@ #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) - #include //typedef CGAL::Simple_cartesian Kernel; @@ -42,9 +40,3 @@ int main(int argc, char* argv[]) } return 0; } -#else -int main() -{ - return 0; -} -#endif diff --git a/Stream_support/examples/Stream_support/Point_WKT.cpp b/Stream_support/examples/Stream_support/Point_WKT.cpp index 064671a6895..10255ff6226 100644 --- a/Stream_support/examples/Stream_support/Point_WKT.cpp +++ b/Stream_support/examples/Stream_support/Point_WKT.cpp @@ -7,8 +7,6 @@ #include #include #include - -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include //typedef CGAL::Simple_cartesian Kernel; @@ -29,9 +27,3 @@ int main(int argc, char* argv[]) is.close(); return 0; } -#else -int main() -{ - return 0; -} -#endif diff --git a/Stream_support/examples/Stream_support/Polygon_WKT.cpp b/Stream_support/examples/Stream_support/Polygon_WKT.cpp index fe8350a33e5..712e1aa39e5 100644 --- a/Stream_support/examples/Stream_support/Polygon_WKT.cpp +++ b/Stream_support/examples/Stream_support/Polygon_WKT.cpp @@ -9,8 +9,6 @@ #include #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) - #include //typedef CGAL::Simple_cartesian Kernel; @@ -44,9 +42,3 @@ int main(int argc, char* argv[]) } return 0; } -#else -int main() -{ - return 0; -} -#endif diff --git a/Stream_support/examples/Stream_support/read_WKT.cpp b/Stream_support/examples/Stream_support/read_WKT.cpp index 94e5a63320e..f9a61ba31cd 100644 --- a/Stream_support/examples/Stream_support/read_WKT.cpp +++ b/Stream_support/examples/Stream_support/read_WKT.cpp @@ -7,11 +7,7 @@ #include #include #include - -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) - #include - //typedef CGAL::Simple_cartesian Kernel; typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; @@ -44,9 +40,3 @@ int main(int argc, char* argv[]) } return 0; } -#else -int main() -{ - return 0; -} -#endif diff --git a/Stream_support/include/CGAL/IO/WKT.h b/Stream_support/include/CGAL/IO/WKT.h index 69ee1bb8387..2a11ea581ee 100644 --- a/Stream_support/include/CGAL/IO/WKT.h +++ b/Stream_support/include/CGAL/IO/WKT.h @@ -15,8 +15,6 @@ #ifndef CGAL_IO_WKT_H #define CGAL_IO_WKT_H -#if defined(DOXYGEN_RUNNING) || (!defined(BOOST_GCC) || BOOST_GCC >= 40500)) - #include #include #include @@ -576,6 +574,4 @@ bool read_WKT(std::istream& is, } // namespace CGAL -#endif // BOOST VERSION CHECKS - #endif // CGAL_IO_WKT_H diff --git a/Stream_support/include/CGAL/IO/WKT/traits_linestring.h b/Stream_support/include/CGAL/IO/WKT/traits_linestring.h index 90b28309eb7..9893446e078 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_linestring.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_linestring.h @@ -15,8 +15,6 @@ #ifndef CGAL_IO_WKT_TRAITS_LINESTRING_H #define CGAL_IO_WKT_TRAITS_LINESTRING_H -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) - #include #include @@ -36,5 +34,4 @@ struct tag > } // namespace geometry } // namespace boost -#endif // BOOST VERSION CHECKS #endif // CGAL_IO_WKT_TRAITS_LINESTRING_H diff --git a/Stream_support/include/CGAL/IO/WKT/traits_multilinestring.h b/Stream_support/include/CGAL/IO/WKT/traits_multilinestring.h index 009124169ca..5f74d539049 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_multilinestring.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_multilinestring.h @@ -15,8 +15,6 @@ #ifndef CGAL_IO_WKT_TRAITS_MULTILINESTRING_H #define CGAL_IO_WKT_TRAITS_MULTILINESTRING_H -#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) - #include #include @@ -37,5 +35,4 @@ struct tag > } // namespace geometry } // namespace boost -#endif // BOOST VERSION CHECKS #endif // CGAL_IO_WKT_TRAITS_MULTILINESTRING_H diff --git a/Stream_support/include/CGAL/IO/WKT/traits_multipoint.h b/Stream_support/include/CGAL/IO/WKT/traits_multipoint.h index 84bdb29609b..08ed5526cd8 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_multipoint.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_multipoint.h @@ -15,8 +15,6 @@ #ifndef CGAL_IO_WKT_TRAITS_MULTIPOINT_H #define CGAL_IO_WKT_TRAITS_MULTIPOINT_H -#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) - #include #include @@ -36,6 +34,4 @@ struct tag > } // namespace traits } // namespace geometry } // namespace boost - -#endif // BOOST VERSION CHECKS #endif // CGAL_IO_WKT_TRAITS_MULTIPOINT_H diff --git a/Stream_support/include/CGAL/IO/WKT/traits_multipolygon.h b/Stream_support/include/CGAL/IO/WKT/traits_multipolygon.h index 08931e55ff0..5d5bb653340 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_multipolygon.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_multipolygon.h @@ -15,8 +15,6 @@ #ifndef CGAL_IO_WKT_TRAITS_MULTIPOLYGON_H #define CGAL_IO_WKT_TRAITS_MULTIPOLYGON_H -#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) - #include #include @@ -37,6 +35,5 @@ struct tag > } // namespace geometry } // namespace boost -#endif // BOOST VERSION CHECKS #endif // CGAL_IO_WKT_TRAITS_MULTIPOLYGON_H diff --git a/Stream_support/include/CGAL/IO/WKT/traits_point.h b/Stream_support/include/CGAL/IO/WKT/traits_point.h index fe9540f76b2..a4c486ba1da 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_point.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_point.h @@ -15,8 +15,6 @@ #ifndef CGAL_IO_WKT_TRAITS_POINT_H #define CGAL_IO_WKT_TRAITS_POINT_H -#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) - #include #include @@ -69,5 +67,4 @@ struct access, 1> } // namespace geometry } // namespace boost -#endif // BOOST VERSION CHECKS #endif // CGAL_IO_WKT_TRAITS_POINT_H diff --git a/Stream_support/include/CGAL/IO/WKT/traits_point_3.h b/Stream_support/include/CGAL/IO/WKT/traits_point_3.h index fcc7eeffb82..dfb9c4d9a77 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_point_3.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_point_3.h @@ -15,8 +15,6 @@ #ifndef CGAL_IO_WKT_TRAITS_POINT_3_H #define CGAL_IO_WKT_TRAITS_POINT_3_H -#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) - #include #include @@ -76,5 +74,4 @@ struct access, 2> } // namespace geometry } // namespace boost -#endif // BOOST VERSION CHECKS #endif // CGAL_IO_WKT_TRAITS_POINT_3_H diff --git a/Stream_support/include/CGAL/IO/WKT/traits_polygon.h b/Stream_support/include/CGAL/IO/WKT/traits_polygon.h index 639ef39d33a..fcc0129f063 100644 --- a/Stream_support/include/CGAL/IO/WKT/traits_polygon.h +++ b/Stream_support/include/CGAL/IO/WKT/traits_polygon.h @@ -15,8 +15,6 @@ #ifndef CGAL_IO_WKT_TRAITS_POLYGON_H #define CGAL_IO_WKT_TRAITS_POLYGON_H -#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) - #include #include #include @@ -101,5 +99,4 @@ struct range_value > } // namespace boost -#endif // BOOST VERSION CHECKS #endif // CGAL_IO_WKT_TRAITS_POLYGON_H diff --git a/Stream_support/include/CGAL/internal/Geometry_container.h b/Stream_support/include/CGAL/internal/Geometry_container.h index d1214ceca17..e5be891d9b2 100644 --- a/Stream_support/include/CGAL/internal/Geometry_container.h +++ b/Stream_support/include/CGAL/internal/Geometry_container.h @@ -14,7 +14,6 @@ #ifndef GEOMETRY_CONTAINER_H #define GEOMETRY_CONTAINER_H -#if(! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include #include @@ -118,4 +117,3 @@ struct range_mutable_iterator > }//end boost #endif // GEOMETRY_CONTAINER_H -#endif diff --git a/Stream_support/test/Stream_support/test_WKT.cpp b/Stream_support/test/Stream_support/test_WKT.cpp index b3fba823b45..65dc900a336 100644 --- a/Stream_support/test/Stream_support/test_WKT.cpp +++ b/Stream_support/test/Stream_support/test_WKT.cpp @@ -1,6 +1,5 @@ #include -#if (! defined(BOOST_GCC) || BOOST_GCC >= 40500) #include #include @@ -279,9 +278,4 @@ int main() return EXIT_SUCCESS; } -#else -int main(int, char**) -{ - return EXIT_SUCCESS; -} -#endif + diff --git a/Triangulation/examples/Triangulation/delaunay_triangulation.cpp b/Triangulation/examples/Triangulation/delaunay_triangulation.cpp index f9db18d22c0..a21e34a08c1 100644 --- a/Triangulation/examples/Triangulation/delaunay_triangulation.cpp +++ b/Triangulation/examples/Triangulation/delaunay_triangulation.cpp @@ -1,13 +1,4 @@ #include -#if defined(BOOST_GCC) && (__GNUC__ <= 4) && (__GNUC_MINOR__ < 4) - -#include -int main() -{ - std::cerr << "NOTICE: This test requires G++ >= 4.4, and will not be compiled." << std::endl; -} - -#else #include #include @@ -48,5 +39,3 @@ int main() } return 0; } - -#endif diff --git a/Triangulation/examples/Triangulation/triangulation.cpp b/Triangulation/examples/Triangulation/triangulation.cpp index 0666542b0dd..966b771cbdb 100644 --- a/Triangulation/examples/Triangulation/triangulation.cpp +++ b/Triangulation/examples/Triangulation/triangulation.cpp @@ -1,12 +1,4 @@ #include -#if defined(BOOST_GCC) && (__GNUC__ <= 4) && (__GNUC_MINOR__ < 4) -#include -int main() -{ - std::cerr << "NOTICE: This test requires G++ >= 4.4, and will not be compiled." << std::endl; -} - -#else #include #include @@ -50,4 +42,3 @@ int main() return 0; } -#endif diff --git a/Triangulation/test/Triangulation/test_delaunay.cpp b/Triangulation/test/Triangulation/test_delaunay.cpp index bc92fa6c796..0af45e570e6 100644 --- a/Triangulation/test/Triangulation/test_delaunay.cpp +++ b/Triangulation/test/Triangulation/test_delaunay.cpp @@ -1,13 +1,4 @@ #include -#if defined(BOOST_GCC) && (__GNUC__ <= 4) && (__GNUC_MINOR__ < 4) - -#include -int main() -{ - std::cerr << "NOTICE: This test requires G++ >= 4.4, and will not be compiled." << std::endl; -} - -#else #include #include @@ -145,5 +136,3 @@ int main(int argc, char **argv) cerr << endl; return 0; } - -#endif diff --git a/Triangulation/test/Triangulation/test_torture.cpp b/Triangulation/test/Triangulation/test_torture.cpp index e66fc6e3ea3..b5c39b84295 100644 --- a/Triangulation/test/Triangulation/test_torture.cpp +++ b/Triangulation/test/Triangulation/test_torture.cpp @@ -1,13 +1,4 @@ #include -#if defined(BOOST_GCC) && (__GNUC__ <= 4) && (__GNUC_MINOR__ < 4) - -#include -int main() -{ - std::cerr << "NOTICE: This test requires G++ >= 4.4, and will not be compiled." << std::endl; -} - -#else #include #include @@ -152,4 +143,3 @@ int main(int argc, char **argv) return 0; } -#endif diff --git a/Triangulation/test/Triangulation/test_triangulation.cpp b/Triangulation/test/Triangulation/test_triangulation.cpp index c86d6c4edd1..e913825dbaa 100644 --- a/Triangulation/test/Triangulation/test_triangulation.cpp +++ b/Triangulation/test/Triangulation/test_triangulation.cpp @@ -1,12 +1,4 @@ #include -#if defined(BOOST_GCC) && (__GNUC__ <= 4) && (__GNUC_MINOR__ < 4) -#include -int main() -{ - std::cerr << "NOTICE: This test requires G++ >= 4.4, and will not be compiled." << std::endl; -} - -#else #include #include #include @@ -166,5 +158,3 @@ int main(int argc, char **argv) cerr << std::endl; return 0; } - -#endif From 915f58550510b7b9e761d0ec25ae545fbcd41a57 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 12 May 2021 15:48:13 +0200 Subject: [PATCH 209/349] misisng tests --- .../boost/graph/alpha_expansion_graphcut.h | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h b/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h index fa2054185b8..b76f5ca4aa9 100644 --- a/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h +++ b/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h @@ -237,12 +237,8 @@ public: double max_flow() { -#if BOOST_VERSION >= 104400 return boost::boykov_kolmogorov_max_flow(graph, cluster_source, cluster_sink); -#else - return boost::kolmogorov_max_flow(graph, cluster_source, cluster_sink); -#endif } template @@ -347,13 +343,8 @@ public: void init_vertices() { -#if BOOST_VERSION >= 104000 graph = Graph(boost::edges_are_unsorted, edge_map.begin(), edge_map.end(), edge_map_weights.begin(), nb_vertices); -#else - graph= Graph(edge_map.begin(), edge_map.end(), - edge_map_weights.begin(), nb_vertices); -#endif // PERFORMANCE PROBLEM // need to set reverse edge map, I guess there is no way to do that before creating the graph @@ -374,7 +365,6 @@ public: double max_flow() { -#if BOOST_VERSION >= 104400 // since properties are bundled, defaults does not work need to specify them return boost::boykov_kolmogorov_max_flow (graph, @@ -387,19 +377,6 @@ public: boost::get(boost::vertex_index, graph), // this is not bundled, get it from graph (CRS provides one) 0, 1); -#else - return boost::kolmogorov_max_flow - (graph, - boost::get(&EdgeP::edge_capacity, graph), - boost::get(&EdgeP::edge_residual_capacity, graph), - boost::get(&EdgeP::edge_reverse, graph), - boost::get(&VertexP::vertex_predecessor, graph), - boost::get(&VertexP::vertex_color, graph), - boost::get(&VertexP::vertex_distance_t, graph), - boost::get(boost::vertex_index, - graph), // this is not bundled, get it from graph - 0, 1); -#endif } template From 516d921ea87016d057f5371b3352e43ce881aa3d Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 12 May 2021 16:29:05 +0200 Subject: [PATCH 210/349] add misisng dependency --- Apollonius_graph_2/TODO | 2 - .../archive/generators/README.txt | 70 - .../gen_integral_sites_in_square.cpp | 62 - .../gen_integral_sites_on_parabola.cpp | 61 - .../generators/gen_sites_in_0x1_box.cpp | 52 - .../CGAL/Apollonius_graph_2/make_degenerate.h | 39 - .../random_integral_sites_in_square_2.h | 54 - .../random_integral_sites_on_parabola_2.h | 54 - .../random_sites_in_0x1_box.h | 37 - .../archive/generators/include/CGAL/bits.h | 23 - .../generators/include/CGAL/random_integer.h | 110 -- .../archive/generators/mk_degen.cpp | 44 - ...Apollonius_graph_mixed_filtered_traits_2.h | 407 ----- .../Apollonius_graph_mixed_traits_2.h | 206 --- .../Apollonius_graph_new_filtered_traits_2.h | 410 ----- .../Apollonius_graph_new_traits_2.h | 209 --- .../Delage_traits/Conflict_2.h | 181 --- .../Delage_traits/Edge_conflict_2.h | 104 -- .../Delage_traits/Finite_edge_conflict_2.h | 83 - .../Delage_traits/Infinite_edge_conflict_2.h | 62 - .../Delage_traits/New_predicates_C2.h | 25 - .../Delage_traits/Orientation_2.h | 92 -- .../Delage_traits/Vertex_conflict_2.h | 320 ---- .../test_ag_new_traits_2.cpp | 194 --- .../Apollonius_graph_2/Apollonius_graph_2.txt | 438 ------ .../CGAL/Apollonius_graph_2.h | 743 --------- .../CGAL/Apollonius_graph_filtered_traits_2.h | 78 - .../CGAL/Apollonius_graph_hierarchy_2.h | 231 --- ...Apollonius_graph_hierarchy_vertex_base_2.h | 49 - .../CGAL/Apollonius_graph_traits_2.h | 54 - .../CGAL/Apollonius_graph_vertex_base_2.h | 54 - .../CGAL/Apollonius_site_2.h | 76 - .../Concepts/ApolloniusGraphDataStructure_2.h | 68 - .../ApolloniusGraphHierarchyVertexBase_2.h | 85 -- .../Concepts/ApolloniusGraphTraits_2.h | 397 ----- .../Concepts/ApolloniusGraphVertexBase_2.h | 166 -- .../Concepts/ApolloniusSite_2.h | 78 - .../doc/Apollonius_graph_2/Doxyfile.in | 9 - .../Apollonius_graph_2/PackageDescription.txt | 63 - .../doc/Apollonius_graph_2/dependencies | 10 - .../doc/Apollonius_graph_2/examples.txt | 6 - .../Apollonius_graph_2/fig/CircleVoronoi.png | Bin 4955 -> 0 bytes .../fig/CircleVoronoiLarge.png | Bin 106801 -> 0 bytes .../fig/apollonius-both_vertices.png | Bin 6802 -> 0 bytes .../fig/apollonius-both_vertices_bw.png | Bin 2798 -> 0 bytes .../fig/apollonius-entire_edge.png | Bin 6513 -> 0 bytes .../fig/apollonius-entire_edge_bw.png | Bin 2657 -> 0 bytes .../fig/apollonius-interior.png | Bin 6808 -> 0 bytes .../fig/apollonius-interior_bw.png | Bin 2791 -> 0 bytes .../fig/apollonius-left_vertex.png | Bin 6294 -> 0 bytes .../fig/apollonius-left_vertex_bw.png | Bin 3174 -> 0 bytes .../fig/apollonius-no_conflict.png | Bin 5970 -> 0 bytes .../fig/apollonius-no_conflict_bw.png | Bin 3098 -> 0 bytes .../fig/apollonius-right_vertex.png | Bin 6792 -> 0 bytes .../fig/apollonius-right_vertex_bw.png | Bin 3236 -> 0 bytes .../fig/apollonius-vertex_conflict-false.png | Bin 5985 -> 0 bytes .../apollonius-vertex_conflict-false_bw.png | Bin 2864 -> 0 bytes .../fig/apollonius-vertex_conflict-true.png | Bin 6126 -> 0 bytes .../apollonius-vertex_conflict-true_bw.png | Bin 3064 -> 0 bytes .../fig/apollonius_diagram.png | Bin 12363 -> 0 bytes .../fig/apollonius_diagram_bw.png | Bin 5396 -> 0 bytes .../fig/apollonius_graph.png | Bin 15732 -> 0 bytes .../fig/apollonius_graph_bw.png | Bin 6515 -> 0 bytes .../fig/insert_degree_2.png | Bin 5244 -> 0 bytes .../fig_src/insert_degree_2.fig | Bin 2599 -> 0 bytes .../Apollonius_graph_2/CMakeLists.txt | 18 - .../examples/Apollonius_graph_2/README | 23 - .../Apollonius_graph_2/ag2_exact_traits.cpp | 54 - .../ag2_exact_traits_sqrt.cpp | 71 - .../ag2_filtered_traits_no_hidden.cpp | 59 - .../Apollonius_graph_2/ag2_hierarchy.cpp | 61 - .../Apollonius_graph_2/data/hierarchy.cin | 500 ------ .../Apollonius_graph_2/data/sites.cin | 9 - .../include/CGAL/Apollonius_graph_2.h | 1343 ----------------- .../Bounded_side_of_ccw_circle_C2.h | 98 -- .../Apollonius_graph_2/Compare_weight_2.h | 52 - .../CGAL/Apollonius_graph_2/Compare_x_2.h | 52 - .../CGAL/Apollonius_graph_2/Compare_y_2.h | 52 - .../Apollonius_graph_2/Constructions_C2.h | 430 ------ .../Apollonius_graph_2/Constructions_ftC2.h | 182 --- .../Apollonius_graph_2/Constructions_rtH2.h | 79 - .../Apollonius_graph_2/Finite_edge_test8_C2.h | 752 --------- .../Apollonius_graph_2/Finite_edge_test_C2.h | 632 -------- .../CGAL/Apollonius_graph_2/Incircle8_C2.h | 132 -- .../CGAL/Apollonius_graph_2/Incircle_C2.h | 243 --- .../Infinite_edge_test_C2.h | 316 ---- .../Is_degenerate_edge_C2.h | 95 -- .../CGAL/Apollonius_graph_2/Is_hidden_C2.h | 85 -- .../Apollonius_graph_2/Kernel_wrapper_2.h | 82 - .../CGAL/Apollonius_graph_2/Orientation8_C2.h | 318 ---- .../CGAL/Apollonius_graph_2/Orientation_2.h | 109 -- .../Oriented_side_of_bisector_C2.h | 125 -- .../Predicate_constructions_C2.h | 358 ----- .../CGAL/Apollonius_graph_2/Predicates_C2.h | 33 - .../Apollonius_graph_2/Traits_wrapper_2.h | 50 - .../include/CGAL/Apollonius_graph_2/basic.h | 25 - .../Apollonius_graph_2/compare_quadratic.h | 986 ------------ .../uncertain/Uncertain_is_hidden_C2.h | 93 -- .../Uncertain_oriented_side_of_bisector_C2.h | 121 -- .../uncertain/Uncertain_vertex_conflict_2.h | 403 ----- .../uncertain/uncertain_functions_on_signs.h | 144 -- .../CGAL/Apollonius_graph_data_structure_2.h | 36 - .../CGAL/Apollonius_graph_filtered_traits_2.h | 409 ----- .../CGAL/Apollonius_graph_hierarchy_2.h | 359 ----- ...Apollonius_graph_hierarchy_vertex_base_2.h | 66 - .../include/CGAL/Apollonius_graph_traits_2.h | 221 --- .../CGAL/Apollonius_graph_vertex_base_2.h | 150 -- .../include/CGAL/Apollonius_site_2.h | 81 - Apollonius_graph_2/include/CGAL/Hyperbola_2.h | 313 ---- .../include/CGAL/Hyperbola_segment_2.h | 191 --- Apollonius_graph_2/include/CGAL/Parabola_2.h | 331 ---- .../include/CGAL/Parabola_segment_2.h | 189 --- .../include/CGAL/functions_on_signs.h | 137 -- .../include/CGAL/in_place_edge_list.h | 201 --- .../include/CGAL/more_functions_on_signs.h | 59 - .../package_info/Apollonius_graph_2/copyright | 2 - .../Apollonius_graph_2/dependencies | 24 - .../Apollonius_graph_2/description.txt | 3 - .../Apollonius_graph_2/license.txt | 1 - .../Apollonius_graph_2/maintainer | 1 - .../test/Apollonius_graph_2/CMakeLists.txt | 18 - .../test/Apollonius_graph_2/data/algo.dat | 9 - .../Apollonius_graph_2/data/hierarchy.dat | 500 ------ .../test/Apollonius_graph_2/data/traits.dat | 4 - .../include/IO/Null_output_stream.h | 51 - .../test/Apollonius_graph_2/include/test.h | 984 ------------ .../include/test_three_sites.h | 103 -- .../test/Apollonius_graph_2/test_ag2.cpp | 33 - .../test_ag_hierarchy_2.cpp | 33 - .../test_ag_three_sites_2.cpp | 131 -- .../Apollonius_graph_2/test_ag_traits_2.cpp | 34 - .../package_info/Stream_support/dependencies | 1 + 132 files changed, 1 insertion(+), 18365 deletions(-) delete mode 100644 Apollonius_graph_2/TODO delete mode 100644 Apollonius_graph_2/archive/generators/README.txt delete mode 100644 Apollonius_graph_2/archive/generators/gen_integral_sites_in_square.cpp delete mode 100644 Apollonius_graph_2/archive/generators/gen_integral_sites_on_parabola.cpp delete mode 100644 Apollonius_graph_2/archive/generators/gen_sites_in_0x1_box.cpp delete mode 100644 Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/make_degenerate.h delete mode 100644 Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_integral_sites_in_square_2.h delete mode 100644 Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_integral_sites_on_parabola_2.h delete mode 100644 Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_sites_in_0x1_box.h delete mode 100644 Apollonius_graph_2/archive/generators/include/CGAL/bits.h delete mode 100644 Apollonius_graph_2/archive/generators/include/CGAL/random_integer.h delete mode 100644 Apollonius_graph_2/archive/generators/mk_degen.cpp delete mode 100644 Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_mixed_filtered_traits_2.h delete mode 100644 Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_mixed_traits_2.h delete mode 100644 Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_new_filtered_traits_2.h delete mode 100644 Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_new_traits_2.h delete mode 100644 Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Conflict_2.h delete mode 100644 Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Edge_conflict_2.h delete mode 100644 Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Finite_edge_conflict_2.h delete mode 100644 Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Infinite_edge_conflict_2.h delete mode 100644 Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/New_predicates_C2.h delete mode 100644 Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Orientation_2.h delete mode 100644 Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Vertex_conflict_2.h delete mode 100644 Apollonius_graph_2/archive/test/Apollonius_graph_2/test_ag_new_traits_2.cpp delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_filtered_traits_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_vertex_base_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_traits_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_vertex_base_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_site_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphDataStructure_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphHierarchyVertexBase_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphTraits_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphVertexBase_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusSite_2.h delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/Doxyfile.in delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/PackageDescription.txt delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/dependencies delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/examples.txt delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/CircleVoronoi.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/CircleVoronoiLarge.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-both_vertices.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-both_vertices_bw.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-entire_edge.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-entire_edge_bw.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-interior.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-interior_bw.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-left_vertex.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-left_vertex_bw.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-no_conflict.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-no_conflict_bw.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-right_vertex.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-right_vertex_bw.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-false.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-false_bw.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-true.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-true_bw.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_diagram.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_diagram_bw.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_graph.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_graph_bw.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig/insert_degree_2.png delete mode 100644 Apollonius_graph_2/doc/Apollonius_graph_2/fig_src/insert_degree_2.fig delete mode 100644 Apollonius_graph_2/examples/Apollonius_graph_2/CMakeLists.txt delete mode 100644 Apollonius_graph_2/examples/Apollonius_graph_2/README delete mode 100644 Apollonius_graph_2/examples/Apollonius_graph_2/ag2_exact_traits.cpp delete mode 100644 Apollonius_graph_2/examples/Apollonius_graph_2/ag2_exact_traits_sqrt.cpp delete mode 100644 Apollonius_graph_2/examples/Apollonius_graph_2/ag2_filtered_traits_no_hidden.cpp delete mode 100644 Apollonius_graph_2/examples/Apollonius_graph_2/ag2_hierarchy.cpp delete mode 100644 Apollonius_graph_2/examples/Apollonius_graph_2/data/hierarchy.cin delete mode 100644 Apollonius_graph_2/examples/Apollonius_graph_2/data/sites.cin delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Bounded_side_of_ccw_circle_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Compare_weight_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Compare_x_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Compare_y_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Constructions_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Constructions_ftC2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Constructions_rtH2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Finite_edge_test8_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Finite_edge_test_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Incircle8_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Incircle_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Infinite_edge_test_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Is_degenerate_edge_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Is_hidden_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Kernel_wrapper_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Orientation8_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Orientation_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Oriented_side_of_bisector_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Predicate_constructions_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Predicates_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/Traits_wrapper_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/basic.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/compare_quadratic.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/uncertain/Uncertain_is_hidden_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/uncertain/Uncertain_oriented_side_of_bisector_C2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/uncertain/Uncertain_vertex_conflict_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_2/uncertain/uncertain_functions_on_signs.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_data_structure_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_filtered_traits_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_hierarchy_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_hierarchy_vertex_base_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_traits_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_graph_vertex_base_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Apollonius_site_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Hyperbola_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Hyperbola_segment_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Parabola_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/Parabola_segment_2.h delete mode 100644 Apollonius_graph_2/include/CGAL/functions_on_signs.h delete mode 100644 Apollonius_graph_2/include/CGAL/in_place_edge_list.h delete mode 100644 Apollonius_graph_2/include/CGAL/more_functions_on_signs.h delete mode 100644 Apollonius_graph_2/package_info/Apollonius_graph_2/copyright delete mode 100644 Apollonius_graph_2/package_info/Apollonius_graph_2/dependencies delete mode 100644 Apollonius_graph_2/package_info/Apollonius_graph_2/description.txt delete mode 100644 Apollonius_graph_2/package_info/Apollonius_graph_2/license.txt delete mode 100644 Apollonius_graph_2/package_info/Apollonius_graph_2/maintainer delete mode 100644 Apollonius_graph_2/test/Apollonius_graph_2/CMakeLists.txt delete mode 100644 Apollonius_graph_2/test/Apollonius_graph_2/data/algo.dat delete mode 100644 Apollonius_graph_2/test/Apollonius_graph_2/data/hierarchy.dat delete mode 100644 Apollonius_graph_2/test/Apollonius_graph_2/data/traits.dat delete mode 100644 Apollonius_graph_2/test/Apollonius_graph_2/include/IO/Null_output_stream.h delete mode 100644 Apollonius_graph_2/test/Apollonius_graph_2/include/test.h delete mode 100644 Apollonius_graph_2/test/Apollonius_graph_2/include/test_three_sites.h delete mode 100644 Apollonius_graph_2/test/Apollonius_graph_2/test_ag2.cpp delete mode 100644 Apollonius_graph_2/test/Apollonius_graph_2/test_ag_hierarchy_2.cpp delete mode 100644 Apollonius_graph_2/test/Apollonius_graph_2/test_ag_three_sites_2.cpp delete mode 100644 Apollonius_graph_2/test/Apollonius_graph_2/test_ag_traits_2.cpp diff --git a/Apollonius_graph_2/TODO b/Apollonius_graph_2/TODO deleted file mode 100644 index c252c825d8f..00000000000 --- a/Apollonius_graph_2/TODO +++ /dev/null @@ -1,2 +0,0 @@ -- rename file names if needed to match the names of the classes - they contain diff --git a/Apollonius_graph_2/archive/generators/README.txt b/Apollonius_graph_2/archive/generators/README.txt deleted file mode 100644 index 2c382e1dce1..00000000000 --- a/Apollonius_graph_2/archive/generators/README.txt +++ /dev/null @@ -1,70 +0,0 @@ -Below you can find a description of the various generators in the -include/CGAL directory: - -make_degenerate.h -================= -PROVIDES: make_degenerate (function) -INPUT: A input range of sites, an output iterator, and a traits class. -OUTPUT: Computes the Apollonius graph of the input range, then writes - the Voronoi circles of the Apollonius diagram of the input - sites to the output iterator. The output is a set of sites for - the Apollonius diagram. -EXAMPLE: mk_degen.cpp -USAGE: Can be used to generate a set of sites in almost degenerate or - degenerate configuration using the input set of sites. - -random_sites_in_0x1_box.h -========================= -PROVIDES: Random_sites_in_0x1_box (functor) -INPUT: at construction time the max radius and a seed need to be passed. -OUTPUT: using operator*(), the user can get one random site with its - center in the box [0,1]x[0,1] and its radius between 0 and the - max radius passed at construction time; the random number - generator used is CGAL::Random. -EXAMPLE: gen_sites_in_0x1_box.cpp -USAGE: Can be used to generate random sites within the [0,1]x[0,1] box - with a prespecified max radius and seed for the random number - generator. There is no guarantee as to whether the site - returned is hidden or not by previously generated sites. - -random_integral_sites_in_square_2.h -=================================== -PROVIDES: Random_integral_sites_in_square_2 (functor) -INPUT: at construction two unsigned integers b and B and a seed need - to be passed. -OUTPUT: using operator*(), the user can get one random site with its - center in [-M,M]x[-M,M], where M = 2^b-1, and its weight in - [0,R], where R = 2^B-1; the random number generator used is - CGAL::Random. Zero bit size means that the corresponding - number is zero. -EXAMPLE: gen_integral_sites_in_square.cpp -USAGE: Can be used to generate sites with integer coordinates and - weight; the bit size of the coordinates and the weight can be - prescribed; allowed values of bit sizes are between 0 and 52, - inclusive. There is no guarantee as to whether the site - returned is hidden or not by previously generated sites. - -random_integral_sites_on_parabola_2.h -===================================== -PROVIDES: Random_integral_sites_on_parabola_2 (functor) -INPUT: at construction an unsigned integer b, an unsigned integer p - and a seed need to be passed. By default p is set to 0. -OUTPUT: using operator*(), the user can get one random site of the - form {(t, t^2), w}, where t is in [-M, M], M = 2^b-1; the - weight w is equal to t^2 unless p is not equal to zero, - in which case w is equal t^2 + e, where e is an integer of bit - size at most p; the random number generator used is - CGAL::Random. Zero bit size means that the corresponding - number is zero. -EXAMPLE: gen_integral_sites_on_parabola.cpp -USAGE: Can be used to generate sites with integer coordinates and - weight with prescribed bit size; allowed values of bit sizes - are between 0 and 26, inclusive. There is no guarantee as to - whether the site returned is hidden or not by previously - generated sites. If p is equal to 0, the Apollonius diagram - created has a vertex of degree n-2, where n is the number of - sites created; all sites are tangent to the x-axis and all lie - above it. If p is non-zero, but small with respect to b, then - the centers of the sites still lie on the parabola y = x^2, but - the weights are perturbed by just a fe bits, thus providing a - set of input sites that are in almost degenerate configuration. diff --git a/Apollonius_graph_2/archive/generators/gen_integral_sites_in_square.cpp b/Apollonius_graph_2/archive/generators/gen_integral_sites_in_square.cpp deleted file mode 100644 index d1bc078f1e9..00000000000 --- a/Apollonius_graph_2/archive/generators/gen_integral_sites_in_square.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -#include -#include - -typedef CGAL::Simple_cartesian K; -typedef CGAL::Apollonius_site_2 Site_2; -typedef CGAL::Random Random; - -int usage (int argc, char *argv[]) -{ - std::cerr << "usage: " << argv[0] - << " " - << "[bit size of weights] [seed]" << std::endl; - return 2; -} - -int main(int argc, char *argv[]) -{ - int num, seed = 17; - unsigned int b, B; - - if ( argc < 3 ) { - return usage(argc, argv); - } - - { - std::istringstream is(argv[1]); - if ( !(is >> num) ) { return usage(argc, argv); } - } - - { - std::istringstream is(argv[2]); - if ( !(is >> b) ) { return usage(argc, argv); } - B = b; - } - - if ( argc > 3 ) { - std::istringstream is(argv[3]); - if ( !(is >> B) ) { return usage(argc, argv); } - } - - if ( argc > 4 ) { - std::istringstream is(argv[4]); - if ( !(is >> seed) ) { return usage(argc, argv); } - } - - CGAL::Random_integral_sites_in_square_2 g(b, B, seed); - - std::cout << std::setprecision(17); - for (int i = 0; i < num; ++i) { - std::cout << *g << std::endl; - } - - return 0; -} diff --git a/Apollonius_graph_2/archive/generators/gen_integral_sites_on_parabola.cpp b/Apollonius_graph_2/archive/generators/gen_integral_sites_on_parabola.cpp deleted file mode 100644 index e79e6182507..00000000000 --- a/Apollonius_graph_2/archive/generators/gen_integral_sites_on_parabola.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -#include -#include - -typedef CGAL::Simple_cartesian K; -typedef CGAL::Apollonius_site_2 Site_2; -typedef CGAL::Random Random; - -int usage (int argc, char *argv[]) -{ - std::cerr << "usage: " << argv[0] - << " " - << "[bit size of perturbation] [seed]" << std::endl; - return 2; -} - -int main(int argc, char *argv[]) -{ - int num, seed = 17; - unsigned int b, p = 0; - - if ( argc < 3 ) { - return usage(argc, argv); - } - - { - std::istringstream is(argv[1]); - if ( !(is >> num) ) { return usage(argc, argv); } - } - - { - std::istringstream is(argv[2]); - if ( !(is >> b) ) { return usage(argc, argv); } - } - - if ( argc > 3 ) { - std::istringstream is(argv[3]); - if ( !(is >> p) ) { return usage(argc, argv); } - } - - if ( argc > 4 ) { - std::istringstream is(argv[4]); - if ( !(is >> seed) ) { return usage(argc, argv); } - } - - CGAL::Random_integral_sites_on_parabola_2 g(b, p, seed); - - std::cout << std::setprecision(17); - for (int i = 0; i < num; ++i) { - std::cout << *g << std::endl; - } - - return 0; -} diff --git a/Apollonius_graph_2/archive/generators/gen_sites_in_0x1_box.cpp b/Apollonius_graph_2/archive/generators/gen_sites_in_0x1_box.cpp deleted file mode 100644 index 72216777c56..00000000000 --- a/Apollonius_graph_2/archive/generators/gen_sites_in_0x1_box.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include - -#include -#include -#include - -#include -#include - -typedef CGAL::Simple_cartesian K; -typedef CGAL::Apollonius_site_2 Site_2; - -int usage (int argc, char **argv) -{ - std::cerr << "usage: " << argv[0] - << " [seed]" << std::endl; - return 2; -} - - -int main (int argc, char **argv) -{ - int num, seed = 42; - double rmax; - - if (argc < 3) - return usage (argc, argv); - - { - std::istringstream is(argv[1]); - if ( !(is >> num) ) { return usage(argc, argv); } - } - { - std::istringstream is(argv[2]); - if ( !(is >> rmax) ) { return usage(argc, argv); } - } - if (argc > 3) { - std::istringstream is(argv[3]); - if ( !(is >> seed) ) { return usage(argc, argv); } - } - - CGAL::Random_sites_in_0x1_box g(rmax, seed); - - std::cout << std::setprecision(17); - - for (int i = 0; i < num; ++i) { - std::cout << *g << std::endl; - } - - return 0; -} diff --git a/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/make_degenerate.h b/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/make_degenerate.h deleted file mode 100644 index 54e2198b1fa..00000000000 --- a/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/make_degenerate.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef CGAL_APOLLONIUS_GRAPH_2_MAKE_DEGENERATE_H -#define CGAL_APOLLONIUS_GRAPH_2_MAKE_DEGENERATE_H 1 - -#include -#include - -namespace CGAL { - -template -OutputIterator -make_degenerate(InputIterator first, - InputIterator beyond, - OutputIterator oit, - const Traits& tr = Traits()) -{ - typedef CGAL::Apollonius_graph_hierarchy_2 Apollonius_graph; - - typedef typename Apollonius_graph::Site_2 Site_2; - - typedef typename Apollonius_graph::Finite_faces_iterator - Finite_faces_iterator; - - Apollonius_graph ag; - Site_2 site; - - for (InputIterator it = first; it != beyond; ++it) { - ag.insert(*it); - } - - for (Finite_faces_iterator f = ag.finite_faces_begin(); - f != ag.finite_faces_end(); ++f) { - *oit++ = ag.dual(f); - } - return oit; -} - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_2_MAKE_DEGENERATE_H diff --git a/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_integral_sites_in_square_2.h b/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_integral_sites_in_square_2.h deleted file mode 100644 index a434fd09175..00000000000 --- a/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_integral_sites_in_square_2.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef CGAL_APOLLONIUS_GRAPH_2_RANDOM_INTEGRAL_SITES_IN_SQUARE_2_H -#define CGAL_APOLLONIUS_GRAPH_2_RANDOM_INTEGRAL_SITES_IN_SQUARE_2_H 1 - -#include -#include - -namespace CGAL { - -// creates a random site with x, y in [-M,M]x[-M,M] -// where M = 2^b - 1 and r in [0,R], R = 2^B - 1 - -template -class Random_integral_sites_in_square_2 -{ -public: - typedef Site Site_2; - typedef R Random; - -public: - Random_integral_sites_in_square_2(unsigned int b) - : b_(b), B_(b), r_(0) { - CGAL_precondition( b >= 0 && b <= 52 ); - } - - Random_integral_sites_in_square_2(unsigned int b, int seed) - : b_(b), B_(b), r_(seed) { - CGAL_precondition( b >= 0 && b <= 52 ); - } - - Random_integral_sites_in_square_2(unsigned int b, unsigned int B, int seed) - : b_(b), B_(B), r_(seed) { - CGAL_precondition( b >= 0 && b <= 52 ); - CGAL_precondition( B >= 0 && B <= 52 ); - } - - Site_2 operator*() - { - double x = random_integer(r_, b_, true); - double y = random_integer(r_, b_, true); - double w = random_integer(r_, B_, false); - CGAL_assertion( w >= 0 ); - - typename Site_2::Point_2 p(x, y); - return Site_2(p, w); - } - -private: - unsigned int b_, B_; - Random r_; -}; - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_2_RANDOM_INTEGRAL_SITES_IN_SQUARE_2_H diff --git a/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_integral_sites_on_parabola_2.h b/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_integral_sites_on_parabola_2.h deleted file mode 100644 index 357d33f01f1..00000000000 --- a/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_integral_sites_on_parabola_2.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef CGAL_APOLLONIUS_GRAPH_2_RANDOM_INTEGRAL_SITES_ON_PARABOLA_2_H -#define CGAL_APOLLONIUS_GRAPH_2_RANDOM_INTEGRAL_SITES_ON_PARABOLA_2_H 1 - -#include -#include - -namespace CGAL { - -// creates a random site of the form {(t, t^2), t^2}, where t is in -// the range [-M, M], M = 2^b - 1 - -template -class Random_integral_sites_on_parabola_2 -{ -public: - typedef Site Site_2; - typedef R Random; - -public: - Random_integral_sites_on_parabola_2(unsigned int b) - : b_(b), p_(0), r_(0) { - CGAL_precondition( b >= 0 && b <= 26 ); - } - - Random_integral_sites_on_parabola_2(unsigned int b, int seed) - : b_(b), p_(0), r_(seed) { - CGAL_precondition( b >= 0 && b <= 26 ); - } - - Random_integral_sites_on_parabola_2(unsigned int b, unsigned int p, - int seed) - : b_(b), p_(p), r_(seed) { - CGAL_precondition( b >= 0 && b <= 26 ); - CGAL_precondition( p >= 0 && p <= 26 ); - } - - Site_2 operator*() - { - double t = random_integer(r_, b_, true); - double t2 = t * t; - double perb = random_integer(r_, p_, true); - - typename Site_2::Point_2 p(t, t2); - return Site_2(p, t2 + perb); - } - -private: - unsigned int b_, p_; - Random r_; -}; - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_2_RANDOM_INTEGRAL_SITES_ON_PARABOLA_2_H diff --git a/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_sites_in_0x1_box.h b/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_sites_in_0x1_box.h deleted file mode 100644 index 6941db05a0c..00000000000 --- a/Apollonius_graph_2/archive/generators/include/CGAL/Apollonius_graph_2/random_sites_in_0x1_box.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef CGAL_APOLLONIUS_GRAPH_2_RANDOM_SITES_IN_0X1_BOX_H -#define CGAL_APOLLONIUS_GRAPH_2_RANDOM_SITES_IN_0X1_BOX_H 1 - -#include -#include - -namespace CGAL { - -template -class Random_sites_in_0x1_box -{ -public: - typedef Site Site_2; - typedef Site_2 result_type; - -private: - typedef typename Site_2::Point_2 Point_2; - -public: - Random_sites_in_0x1_box(double rmax = 0.125, int seed = 0) - : rmax_(rmax), random_(seed) {} - - Site_2 operator*() { - double x = random_.get_double(0, 1); - double y = random_.get_double(0, 1); - double w = random_.get_double(0, rmax_); - return Site_2(Point_2(x,y),w); - } - -private: - double rmax_; - Random random_; -}; - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_2_RANDOM_SITES_IN_0X1_BOX_H diff --git a/Apollonius_graph_2/archive/generators/include/CGAL/bits.h b/Apollonius_graph_2/archive/generators/include/CGAL/bits.h deleted file mode 100644 index 9d9a9cf1e9a..00000000000 --- a/Apollonius_graph_2/archive/generators/include/CGAL/bits.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CGAL_BITS_H -#define CGAL_BITS_H - -#include -#include - -namespace CGAL { - -double log2(double x) -{ - return log10(x) / log10(2.0); -} - -unsigned int bits(double x) -{ - CGAL_precondition( static_cast(x) == x ); - if ( x == 0 ) { return 1; } - return static_cast(log2( CGAL::abs(x) )) + 1; -} - -} //namespace CGAL - -#endif // CGAL_BITS_H diff --git a/Apollonius_graph_2/archive/generators/include/CGAL/random_integer.h b/Apollonius_graph_2/archive/generators/include/CGAL/random_integer.h deleted file mode 100644 index f7c29dee82f..00000000000 --- a/Apollonius_graph_2/archive/generators/include/CGAL/random_integer.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef CGAL_RANDOM_INTEGER_H -#define CGAL_RANDOM_INTEGER_H - -#include -#include -#include - -// type "man {rand, random, drand48}" for C functions that produce -// random numbers - -//extern "C" int getpid(); -//extern "C" int srandom(unsigned); -//extern "C" long random(); - -namespace CGAL { - -// powers of 2 from 2^0 to 2^53 -double -P2[54]={1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, - 512.0, 1024.0, 2048.0, 4096.0, 8192.0, 16384.0, 32768.0, - 65536.0, 131072.0, 262144.0, 524288.0, 1048576.0, - 2097152.0, 4194304.0, 8388608.0, 16777216.0, 33554432.0, - 67108864.0, 134217728.0, 268435456.0, 536870912.0, - 1073741824.0, 2147483648.0, 4294967296.0, 8589934592.0, - 17179869184.0, 34359738368.0, 68719476736.0, - 137438953472.0, 274877906944.0, 549755813888.0, - 1099511627776.0, 2199023255552.0, 4398046511104.0, - 8796093022208.0, 17592186044416.0, 35184372088832.0, - 70368744177664.0, 140737488355328.0, 281474976710656.0, - 562949953421312.0, 1125899906842624.0, 2251799813685248.0, - 4503599627370496.0, 9007199254740992.0}; - -// set the random number generator seed -void set_seed(unsigned int seed) -{ - srandom(seed); -} - -// return random integer of b bits -double random_integer(int b, bool allow_negative = true) -{ - double value; - - if (b > 27) { - value = ((int)random()) % ((int)P2[27]); - value += ( ((int)random()) % ((int)P2[b - 27]) ) * P2[27]; - } else { - value = ((int)random()) % (int)P2[b]; - } - if ( allow_negative ) { - value *= ( ((int) random()) % 2 == 0 ) ? 1 : -1; - } - return value; -} - -template -double random_integer(Random& r, unsigned int b, bool allow_negative = true) -{ - // returns random integers in the range [0, 2^b - 1). - // b is required to be at least 1 and at most 52 - // and if allow_negative is true then the range includes negative - // numbers as well and becomes: [-2^b + 1, 2^b - 1). - CGAL_precondition( b >= 0 && b <= 52 ); - - if ( b == 0 ) { return 0; } - - double M = pow(2.0,b); - CGAL::Gmpz z; - - if ( allow_negative ) { - z = r.get_double(-M, M); - } else { - z = r.get_double(0, M); - } - return CGAL::to_double(z); -} - - -template -double random_even_integer(Random& r, unsigned int b, - bool allow_negative = true) -{ - // returns random even integers in the range [0, 2^b - 1). - // b is required to be at least 1 and at most 52 - // and if allow_negative is true then the range includes negative - // numbers as well and becomes: [-2^b + 1, 2^b - 1). - CGAL_precondition( b >= 0 && b <= 52 ); - - if ( b == 0 ) { return 0; } - - double M = pow(2.0,b); - CGAL::Gmpz z; - CGAL::Gmpz two(2); - - do { - if ( allow_negative ) { - z = r.get_double(-M, M); - } else { - z = r.get_double(0, M); - } - } while ( z % two != 0 ); - - return CGAL::to_double(z); -} - - -} //namespace CGAL - - -#endif // CGAL_RANDOM_INTEGER_H diff --git a/Apollonius_graph_2/archive/generators/mk_degen.cpp b/Apollonius_graph_2/archive/generators/mk_degen.cpp deleted file mode 100644 index 368f2f2594b..00000000000 --- a/Apollonius_graph_2/archive/generators/mk_degen.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -#include -#include -#include - -#include -#include - -#include - -typedef CGAL::Simple_cartesian CK; -typedef CGAL::Simple_cartesian EK; - -typedef CGAL::Field_with_sqrt_tag CM; -typedef CGAL::Integral_domain_without_division_tag EM; -typedef CGAL::Apollonius_graph_filtered_traits_2 Traits; - -typedef Traits::Site_2 Site; -typedef std::vector Site_vector; - -int main() -{ - Site_vector input, output; - Site site; - - std::back_insert_iterator oit(output); - - while (std::cin >> site) { input.push_back(site); } - - oit = CGAL::make_degenerate(input.begin(), input.end(), oit, Traits()); - - std::cout << std::setprecision(17); - for (std::vector::iterator it = output.begin(); - it != output.end(); ++it) - { - std::cout << (*it) << std::endl; - } - - return 0; -} - - diff --git a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_mixed_filtered_traits_2.h b/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_mixed_filtered_traits_2.h deleted file mode 100644 index c221d5fdd52..00000000000 --- a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_mixed_filtered_traits_2.h +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright (c) 2003,2004 INRIA Sophia-Antipolis (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) : Menelaos Karavelas - - - -#ifndef CGAL_APOLLONIUS_GRAPH_MIXED_FILTERED_TRAITS_2_H -#define CGAL_APOLLONIUS_GRAPH_MIXED_FILTERED_TRAITS_2_H - - -#include - -#include -#include - -// includes for the default parameters of the filtered traits -#include -#include -#include -#include -#include - - -namespace CGAL { - - -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -// the filtered Traits class -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- - -template, - class EK_MTag = CK_MTag, - class FK_t = Simple_cartesian< Interval_nt >, - class FK_MTag = CK_MTag, - class C2E_t = Cartesian_converter, - class C2F_t = - Cartesian_converter > > -class Apollonius_graph_mixed_filtered_traits_2 -{ -private: - typedef Apollonius_graph_mixed_traits_2 CK_traits; - typedef Apollonius_graph_mixed_traits_2 FK_traits; - typedef Apollonius_graph_mixed_traits_2 EK_traits; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Apollonius_graph_kernel_wrapper_2 CK; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Apollonius_graph_kernel_wrapper_2 FK; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Apollonius_graph_kernel_wrapper_2 EK; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS:: - Apollonius_graph_cartesian_converter C2E; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS:: - Apollonius_graph_cartesian_converter C2F; - -#if 0 - // the following typedefs have been made in the direction of - // providing filtered constructions; however, there is a problem, - // namely, the Construct_Apollonius_site_2 functor has two - // different operator()'s with two different return types; this - // functor should be split in two (along with the appropriate - // changes in the spec/concept); see also changes needed for the - // filtered construction below. - typedef Cartesian_converter > F2C_t; - typedef Cartesian_converter > E2C_t; - - typedef - Apollonius_graph_cartesian_converter F2C; - typedef - Apollonius_graph_cartesian_converter E2C; -#endif - - // Types for the construction kernel - typedef typename CK::Point_2 CK_Point_2; - typedef typename CK::Site_2 CK_Site_2; - - typedef typename CK::Line_2 CK_Line_2; - typedef typename CK::Ray_2 CK_Ray_2; - typedef typename CK::Segment_2 CK_Segment_2; - - typedef typename CK::FT CK_FT; - typedef typename CK::RT CK_RT; - - // Types for the exact kernel - typedef typename EK::Point_2 EK_Point_2; - typedef typename EK::Site_2 EK_Site_2; - - typedef typename EK::Line_2 EK_Line_2; - typedef typename EK::Ray_2 EK_Ray_2; - typedef typename EK::Segment_2 EK_Segment_2; - - typedef typename EK::FT EK_FT; - typedef typename EK::RT EK_RT; - - // Types for the filtering kernel - typedef typename FK::Point_2 FK_Point_2; - typedef typename FK::Site_2 FK_Site_2; - - typedef typename FK::Line_2 FK_Line_2; - typedef typename FK::Ray_2 FK_Ray_2; - typedef typename FK::Segment_2 FK_Segment_2; - - typedef typename FK::FT FK_FT; - typedef typename FK::RT FK_RT; - -public: - //----------------------------------------------------------------------- - // TYPE DEFINITIONS - //----------------------------------------------------------------------- - - // BASIC TYPES - //------------ - typedef CK_t R; - typedef CK_MTag Method_tag; - - typedef CK_traits Construction_traits; - typedef FK_traits Filtering_traits; - typedef EK_traits Exact_traits; - - typedef CK_MTag Construction_traits_method_tag; - typedef FK_MTag Filtering_traits_method_tag; - typedef EK_MTag Exact_traits_method_tag; - - typedef typename CK::Point_2 Point_2; - typedef typename CK::Site_2 Site_2; - - typedef typename CK::Line_2 Line_2; - typedef typename CK::Ray_2 Ray_2; - typedef typename CK::Segment_2 Segment_2; - - typedef typename CK::Object_2 Object_2; - typedef typename CK::FT FT; - typedef typename CK::RT RT; - - -public: - // OBJECT CONSTRUCTION & ASSIGNMENT - //--------------------------------- - typedef typename CK_traits::Construct_object_2 Construct_object_2; - typedef typename CK_traits::Assign_2 Assign_2; - - // CONSTRUCTIONS - //-------------- - // vertex and dual site -protected: - typedef typename CK_traits::Construct_Apollonius_vertex_2 - CK_Construct_Apollonius_vertex_2; - - typedef typename CK_traits::Construct_Apollonius_site_2 - CK_Construct_Apollonius_site_2; - - typedef typename FK_traits::Construct_Apollonius_vertex_2 - FK_Construct_Apollonius_vertex_2; - - typedef typename FK_traits::Construct_Apollonius_site_2 - FK_Construct_Apollonius_site_2; - - typedef typename EK_traits::Construct_Apollonius_vertex_2 - EK_Construct_Apollonius_vertex_2; - - typedef typename EK_traits::Construct_Apollonius_site_2 - EK_Construct_Apollonius_site_2; - -public: -#if 0 - // the following typedefs have been made in the direction of - // providing filtered constructions; however, there is a problem, - // namely, the Construct_Apollonius_site_2 functor has two - // different operator()'s with two different return types; this - // functor should be split in two (along with the appropriate - // changes in the spec/concept); see also changes needed for the - // filtered construction above. - typedef Filtered_construction - Construct_Apollonius_vertex_2; - - typedef Filtered_construction - Construct_Apollonius_site_2; -#else - typedef typename CK_traits::Construct_Apollonius_vertex_2 - Construct_Apollonius_vertex_2; - - typedef typename CK_traits::Construct_Apollonius_site_2 - Construct_Apollonius_site_2; -#endif - -private: - // PREDICATES FOR THE TWO KERNELS - //------------------------------- - - // Predicates for the filtering kernel - typedef typename FK_traits::Compare_x_2 FK_Compare_x_2; - typedef typename FK_traits::Compare_y_2 FK_Compare_y_2; - typedef typename FK_traits::Compare_weight_2 FK_Compare_weight_2; - typedef typename FK_traits::Orientation_2 FK_Orientation_2; - typedef typename FK_traits::Orientation_new_2 FK_Orientation_new_2; - typedef typename FK_traits::Is_hidden_2 FK_Is_hidden_2; - typedef typename FK_traits::Vertex_conflict_2 FK_Vertex_conflict_2; - - typedef typename FK_traits::Oriented_side_of_bisector_2 - FK_Oriented_side_of_bisector_2; - - typedef typename FK_traits::Finite_edge_interior_conflict_2 - FK_Finite_edge_interior_conflict_2; - - typedef typename FK_traits::Infinite_edge_interior_conflict_2 - FK_Infinite_edge_interior_conflict_2; - - typedef typename FK_traits::Is_degenerate_edge_2 - FK_Is_degenerate_edge_2; - - - // Predicates for the exact kernel - typedef typename EK_traits::Compare_x_2 EK_Compare_x_2; - typedef typename EK_traits::Compare_y_2 EK_Compare_y_2; - typedef typename EK_traits::Compare_weight_2 EK_Compare_weight_2; - typedef typename EK_traits::Orientation_2 EK_Orientation_2; - typedef typename EK_traits::Orientation_new_2 EK_Orientation_new_2; - typedef typename EK_traits::Is_hidden_2 EK_Is_hidden_2; - typedef typename EK_traits::Vertex_conflict_2 EK_Vertex_conflict_2; - - typedef typename EK_traits::Oriented_side_of_bisector_2 - EK_Oriented_side_of_bisector_2; - - typedef typename EK_traits::Finite_edge_interior_conflict_2 - EK_Finite_edge_interior_conflict_2; - - typedef typename EK_traits::Infinite_edge_interior_conflict_2 - EK_Infinite_edge_interior_conflict_2; - - typedef typename EK_traits::Is_degenerate_edge_2 - EK_Is_degenerate_edge_2; - -public: - // PREDICATES - //----------- - - typedef - Filtered_predicate - Compare_x_2; - - typedef - Filtered_predicate - Compare_y_2; - - typedef - Filtered_predicate - Compare_weight_2; - - typedef - Filtered_predicate - Orientation_2; - - typedef - Filtered_predicate - Orientation_new_2; - - typedef - Filtered_predicate - Is_hidden_2; - - typedef - Filtered_predicate - Oriented_side_of_bisector_2; - - typedef - Filtered_predicate - Vertex_conflict_2; - - typedef - Filtered_predicate - Finite_edge_interior_conflict_2; - - typedef - Filtered_predicate - Infinite_edge_interior_conflict_2; - - typedef - Filtered_predicate - Is_degenerate_edge_2; - -public: - //----------------------------------------------------------------------- - // ACCESS TO OBJECTS - //----------------------------------------------------------------------- - - // OBJECT CONSTRUCTION & ASSIGNMENT - Assign_2 - assign_2_object() const { - return Assign_2(); - } - - Construct_object_2 - construct_object_2_object() const { - return Construct_object_2(); - } - - - // CONSTRUCTIONS - //-------------- - Construct_Apollonius_vertex_2 - construct_Apollonius_vertex_2_object() const { - return Construct_Apollonius_vertex_2(); - } - - Construct_Apollonius_site_2 - construct_Apollonius_site_2_object() const { - return Construct_Apollonius_site_2(); - } - - // PREDICATES - //----------- - Compare_x_2 - compare_x_2_object() const { - return Compare_x_2(); - } - - Compare_y_2 - compare_y_2_object() const { - return Compare_y_2(); - } - - Compare_weight_2 - compare_weight_2_object() const { - return Compare_weight_2(); - } - - Orientation_2 - orientation_2_object() const { - return Orientation_2(); - } - - Orientation_new_2 - orientation_new_2_object() const { - return Orientation_new_2(); - } - - Is_hidden_2 - is_hidden_2_object() const { - return Is_hidden_2(); - } - - Oriented_side_of_bisector_2 - oriented_side_of_bisector_2_object() const { - return Oriented_side_of_bisector_2(); - } - - Vertex_conflict_2 - vertex_conflict_2_object() const { - return Vertex_conflict_2(); - } - - Finite_edge_interior_conflict_2 - finite_edge_interior_conflict_2_object() const { - return Finite_edge_interior_conflict_2(); - } - - Infinite_edge_interior_conflict_2 - infinite_edge_interior_conflict_2_object() const { - return Infinite_edge_interior_conflict_2(); - } - - Is_degenerate_edge_2 - is_degenerate_edge_2_object() const { - return Is_degenerate_edge_2(); - } - -}; - - - -} //namespace CGAL - - -#endif // CGAL_APOLLONIUS_GRAPH_UNCERTAIN_FILTERED_TRAITS_2_H diff --git a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_mixed_traits_2.h b/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_mixed_traits_2.h deleted file mode 100644 index 08f0ce66720..00000000000 --- a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_mixed_traits_2.h +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (c) 2006 INRIA Sophia-Antipolis (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) : Menelaos Karavelas -// Christophe Delage -// David Millman - -#ifndef CGAL_APOLLONIUS_GRAPH_MIXED_TRAITS_2_H -#define CGAL_APOLLONIUS_GRAPH_MIXED_TRAITS_2_H - -#include -#include -#include - -namespace CGAL { - -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -// the Traits class -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -template < class Rep, class MTag = Integral_domain_without_division_tag > -class Apollonius_graph_mixed_traits_2 -{ -public: - //----------------------------------------------------------------------- - // TYPE DEFINITIONS - //----------------------------------------------------------------------- - - // BASIC TYPES - //------------ -private: - typedef Apollonius_graph_new_traits_2 Self; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Apollonius_graph_kernel_wrapper_2 Kernel; - -public: - typedef Rep R; - typedef MTag Method_tag; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Site_2 Site_2; - - typedef typename Kernel::Line_2 Line_2; - typedef typename Kernel::Ray_2 Ray_2; - typedef typename Rep::Segment_2 Segment_2; - - typedef typename Kernel::Object_2 Object_2; - typedef typename Kernel::FT FT; - typedef typename Kernel::RT RT; - - -public: - // OBJECT CONSTRUCTION & ASSIGNMENT - //--------------------------------- - typedef typename Kernel::Construct_object_2 Construct_object_2; - typedef typename Kernel::Assign_2 Assign_2; - - // CONSTRUCTIONS - //-------------- - // vertex and dual site - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Construct_Apollonius_vertex_2 - /* */ Construct_Apollonius_vertex_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Construct_Apollonius_site_2 - /* */ Construct_Apollonius_site_2; - - - // PREDICATES - //----------- - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Compare_x_2 Compare_x_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Compare_y_2 Compare_y_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Compare_weight_2 - Compare_weight_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Orientation_2 - Orientation_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Orientation_new_2 - Orientation_new_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Is_hidden_2 Is_hidden_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Oriented_side_of_bisector_2 - /* */ Oriented_side_of_bisector_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Vertex_conflict_new_2 - Vertex_conflict_2; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Finite_edge_interior_conflict_2 - /* */ Finite_edge_interior_conflict_2; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Infinite_edge_interior_conflict_2 - /* */ Infinite_edge_interior_conflict_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Is_degenerate_edge_2 - /* */ Is_degenerate_edge_2; - - -public: - //----------------------------------------------------------------------- - // ACCESS TO OBJECTS - //----------------------------------------------------------------------- - - // OBJECT CONSTRUCTION & ASSIGNMENT - Assign_2 - assign_2_object() const { - return Assign_2(); - } - - Construct_object_2 - construct_object_2_object() const { - return Construct_object_2(); - } - - - // CONSTRUCTIONS - //-------------- - Construct_Apollonius_vertex_2 - construct_Apollonius_vertex_2_object() const { - return Construct_Apollonius_vertex_2(); - } - - Construct_Apollonius_site_2 - construct_Apollonius_site_2_object() const { - return Construct_Apollonius_site_2(); - } - - - // PREDICATES - //----------- - Compare_x_2 - compare_x_2_object() const { - return Compare_x_2(); - } - - Compare_y_2 - compare_y_2_object() const { - return Compare_y_2(); - } - - Compare_weight_2 - compare_weight_2_object() const { - return Compare_weight_2(); - } - - Orientation_2 - orientation_2_object() const { - return Orientation_2(); - } - - Orientation_new_2 - orientation_new_2_object() const { - return Orientation_new_2(); - } - - Is_hidden_2 - is_hidden_2_object() const { - return Is_hidden_2(); - } - - Oriented_side_of_bisector_2 - oriented_side_of_bisector_2_object() const { - return Oriented_side_of_bisector_2(); - } - - Vertex_conflict_2 - vertex_conflict_2_object() const { - return Vertex_conflict_2(); - } - - Finite_edge_interior_conflict_2 - finite_edge_interior_conflict_2_object() const { - return Finite_edge_interior_conflict_2(); - } - - Infinite_edge_interior_conflict_2 - infinite_edge_interior_conflict_2_object() const { - return Infinite_edge_interior_conflict_2(); - } - - Is_degenerate_edge_2 - is_degenerate_edge_2_object() const { - return Is_degenerate_edge_2(); - } - -}; - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_NEW_TRAITS_2_H diff --git a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_new_filtered_traits_2.h b/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_new_filtered_traits_2.h deleted file mode 100644 index b6fc3246cf3..00000000000 --- a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_new_filtered_traits_2.h +++ /dev/null @@ -1,410 +0,0 @@ -// Copyright (c) 2003,2004,2006 INRIA Sophia-Antipolis (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) : Menelaos Karavelas - - - -#ifndef CGAL_APOLLONIUS_GRAPH_NEW_FILTERED_TRAITS_2_H -#define CGAL_APOLLONIUS_GRAPH_NEW_FILTERED_TRAITS_2_H - - -#include - -#include -#include - -// includes for the default parameters of the filtered traits -#include -#include -#include -#include -#include - - -namespace CGAL { - - -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -// the filtered Traits class -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- - -template, - class EK_MTag = CK_MTag, - class FK_t = Simple_cartesian< Interval_nt >, - class FK_MTag = CK_MTag, - class C2E_t = Cartesian_converter, - class C2F_t = - Cartesian_converter > > -class Apollonius_graph_new_filtered_traits_2 -{ -private: - typedef Apollonius_graph_new_traits_2 CK_traits; - typedef Apollonius_graph_new_traits_2 FK_traits; - typedef Apollonius_graph_new_traits_2 EK_traits; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Apollonius_graph_kernel_wrapper_2 CK; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Apollonius_graph_kernel_wrapper_2 FK; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Apollonius_graph_kernel_wrapper_2 EK; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS:: - Apollonius_graph_cartesian_converter C2E; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS:: - Apollonius_graph_cartesian_converter C2F; - -#if 0 - // the following typedefs have been made in the direction of - // providing filtered constructions; however, there is a problem, - // namely, the Construct_Apollonius_site_2 functor has two - // different operator()'s with two different return types; this - // functor should be split in two (along with the appropriate - // changes in the spec/concept); see also changes needed for the - // filtered construction below. - typedef Cartesian_converter > F2C_t; - typedef Cartesian_converter > E2C_t; - - typedef - Apollonius_graph_cartesian_converter F2C; - typedef - Apollonius_graph_cartesian_converter E2C; -#endif - - // Types for the construction kernel - typedef typename CK::Point_2 CK_Point_2; - typedef typename CK::Site_2 CK_Site_2; - - typedef typename CK::Line_2 CK_Line_2; - typedef typename CK::Ray_2 CK_Ray_2; - typedef typename CK::Segment_2 CK_Segment_2; - - typedef typename CK::FT CK_FT; - typedef typename CK::RT CK_RT; - - // Types for the exact kernel - typedef typename EK::Point_2 EK_Point_2; - typedef typename EK::Site_2 EK_Site_2; - - typedef typename EK::Line_2 EK_Line_2; - typedef typename EK::Ray_2 EK_Ray_2; - typedef typename EK::Segment_2 EK_Segment_2; - - typedef typename EK::FT EK_FT; - typedef typename EK::RT EK_RT; - - // Types for the filtering kernel - typedef typename FK::Point_2 FK_Point_2; - typedef typename FK::Site_2 FK_Site_2; - - typedef typename FK::Line_2 FK_Line_2; - typedef typename FK::Ray_2 FK_Ray_2; - typedef typename FK::Segment_2 FK_Segment_2; - - typedef typename FK::FT FK_FT; - typedef typename FK::RT FK_RT; - -public: - //----------------------------------------------------------------------- - // TYPE DEFINITIONS - //----------------------------------------------------------------------- - - // BASIC TYPES - //------------ - typedef CK_t R; - typedef CK_MTag Method_tag; - - typedef CK_traits Construction_traits; - typedef FK_traits Filtering_traits; - typedef EK_traits Exact_traits; - - typedef CK_MTag Construction_traits_method_tag; - typedef FK_MTag Filtering_traits_method_tag; - typedef EK_MTag Exact_traits_method_tag; - - typedef typename CK::Point_2 Point_2; - typedef typename CK::Site_2 Site_2; - - typedef typename CK::Line_2 Line_2; - typedef typename CK::Ray_2 Ray_2; - typedef typename CK::Segment_2 Segment_2; - - typedef typename CK::Object_2 Object_2; - typedef typename CK::FT FT; - typedef typename CK::RT RT; - - -public: - // OBJECT CONSTRUCTION & ASSIGNMENT - //--------------------------------- - typedef typename CK_traits::Construct_object_2 Construct_object_2; - typedef typename CK_traits::Assign_2 Assign_2; - - // CONSTRUCTIONS - //-------------- - // vertex and dual site -protected: - typedef typename CK_traits::Construct_Apollonius_vertex_2 - CK_Construct_Apollonius_vertex_2; - - typedef typename CK_traits::Construct_Apollonius_site_2 - CK_Construct_Apollonius_site_2; - - typedef typename FK_traits::Construct_Apollonius_vertex_2 - FK_Construct_Apollonius_vertex_2; - - typedef typename FK_traits::Construct_Apollonius_site_2 - FK_Construct_Apollonius_site_2; - - typedef typename EK_traits::Construct_Apollonius_vertex_2 - EK_Construct_Apollonius_vertex_2; - - typedef typename EK_traits::Construct_Apollonius_site_2 - EK_Construct_Apollonius_site_2; - -public: -#if 0 - // the following typedefs have been made in the direction of - // providing filtered constructions; however, there is a problem, - // namely, the Construct_Apollonius_site_2 functor has two - // different operator()'s with two different return types; this - // functor should be split in two (along with the appropriate - // changes in the spec/concept); see also changes needed for the - // filtered construction above. - typedef Filtered_construction - Construct_Apollonius_vertex_2; - - typedef Filtered_construction - Construct_Apollonius_site_2; -#else - typedef typename CK_traits::Construct_Apollonius_vertex_2 - Construct_Apollonius_vertex_2; - - typedef typename CK_traits::Construct_Apollonius_site_2 - Construct_Apollonius_site_2; -#endif - -private: - // PREDICATES FOR THE TWO KERNELS - //------------------------------- - - // Predicates for the filtering kernel - typedef typename FK_traits::Compare_x_2 FK_Compare_x_2; - typedef typename FK_traits::Compare_y_2 FK_Compare_y_2; - typedef typename FK_traits::Compare_weight_2 FK_Compare_weight_2; - typedef typename FK_traits::Orientation_2 FK_Orientation_2; - typedef typename FK_traits::Orientation_new_2 FK_Orientation_new_2; - typedef typename FK_traits::Is_hidden_2 FK_Is_hidden_2; - - typedef typename FK_traits::Oriented_side_of_bisector_2 - FK_Oriented_side_of_bisector_2; - - typedef typename FK_traits::Vertex_conflict_2 FK_Vertex_conflict_2; - - typedef typename FK_traits::Finite_edge_interior_conflict_2 - FK_Finite_edge_interior_conflict_2; - - typedef typename FK_traits::Infinite_edge_interior_conflict_2 - FK_Infinite_edge_interior_conflict_2; - - typedef typename FK_traits::Is_degenerate_edge_2 - FK_Is_degenerate_edge_2; - - - // Predicates for the exact kernel - typedef typename EK_traits::Compare_x_2 EK_Compare_x_2; - typedef typename EK_traits::Compare_y_2 EK_Compare_y_2; - typedef typename EK_traits::Compare_weight_2 EK_Compare_weight_2; - typedef typename EK_traits::Orientation_2 EK_Orientation_2; - typedef typename EK_traits::Orientation_new_2 EK_Orientation_new_2; - typedef typename EK_traits::Is_hidden_2 EK_Is_hidden_2; - - typedef typename EK_traits::Oriented_side_of_bisector_2 - EK_Oriented_side_of_bisector_2; - - typedef typename EK_traits::Vertex_conflict_2 EK_Vertex_conflict_2; - - typedef typename EK_traits::Finite_edge_interior_conflict_2 - EK_Finite_edge_interior_conflict_2; - - typedef typename EK_traits::Infinite_edge_interior_conflict_2 - EK_Infinite_edge_interior_conflict_2; - - typedef typename EK_traits::Is_degenerate_edge_2 - EK_Is_degenerate_edge_2; - -public: - // PREDICATES - //----------- - - typedef - Filtered_predicate - Compare_x_2; - - typedef - Filtered_predicate - Compare_y_2; - - typedef - Filtered_predicate - Compare_weight_2; - - typedef - Filtered_predicate - Orientation_2; - - typedef - Filtered_predicate - Orientation_new_2; - - typedef - Filtered_predicate - Is_hidden_2; - - typedef - Filtered_predicate - Oriented_side_of_bisector_2; - - typedef - Filtered_predicate - Vertex_conflict_2; - - typedef - Filtered_predicate - Finite_edge_interior_conflict_2; - - typedef - Filtered_predicate - Infinite_edge_interior_conflict_2; - - typedef - Filtered_predicate - Is_degenerate_edge_2; - -public: - //----------------------------------------------------------------------- - // ACCESS TO OBJECTS - //----------------------------------------------------------------------- - - // OBJECT CONSTRUCTION & ASSIGNMENT - Assign_2 - assign_2_object() const { - return Assign_2(); - } - - Construct_object_2 - construct_object_2_object() const { - return Construct_object_2(); - } - - - // CONSTRUCTIONS - //-------------- - Construct_Apollonius_vertex_2 - construct_Apollonius_vertex_2_object() const { - return Construct_Apollonius_vertex_2(); - } - - Construct_Apollonius_site_2 - construct_Apollonius_site_2_object() const { - return Construct_Apollonius_site_2(); - } - - // PREDICATES - //----------- - Compare_x_2 - compare_x_2_object() const { - return Compare_x_2(); - } - - Compare_y_2 - compare_y_2_object() const { - return Compare_y_2(); - } - - Compare_weight_2 - compare_weight_2_object() const { - return Compare_weight_2(); - } - - Orientation_2 - orientation_2_object() const { - return Orientation_2(); - } - - Orientation_new_2 - orientation_new_2_object() const { - return Orientation_new_2(); - } - - Is_hidden_2 - is_hidden_2_object() const { - return Is_hidden_2(); - } - - Oriented_side_of_bisector_2 - oriented_side_of_bisector_2_object() const { - return Oriented_side_of_bisector_2(); - } - - Vertex_conflict_2 - vertex_conflict_2_object() const { - return Vertex_conflict_2(); - } - - Finite_edge_interior_conflict_2 - finite_edge_interior_conflict_2_object() const { - return Finite_edge_interior_conflict_2(); - } - - Infinite_edge_interior_conflict_2 - infinite_edge_interior_conflict_2_object() const { - return Infinite_edge_interior_conflict_2(); - } - - Is_degenerate_edge_2 - is_degenerate_edge_2_object() const { - return Is_degenerate_edge_2(); - } - -}; - - - -} //namespace CGAL - - -#endif // CGAL_APOLLONIUS_GRAPH_NEW_FILTERED_TRAITS_2_H diff --git a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_new_traits_2.h b/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_new_traits_2.h deleted file mode 100644 index f3e33e91f09..00000000000 --- a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Apollonius_graph_new_traits_2.h +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright (c) 2006 INRIA Sophia-Antipolis (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) : Menelaos Karavelas -// Christophe Delage -// David Millman - -#ifndef CGAL_APOLLONIUS_GRAPH_NEW_TRAITS_2_H -#define CGAL_APOLLONIUS_GRAPH_NEW_TRAITS_2_H - -#include -#include -#include - -namespace CGAL { - -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -// the Traits class -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -//----------------------------------------------------------------------- -template < class Rep, class MTag = Integral_domain_without_division_tag > -class Apollonius_graph_new_traits_2 -{ -public: - //----------------------------------------------------------------------- - // TYPE DEFINITIONS - //----------------------------------------------------------------------- - - // BASIC TYPES - //------------ -private: - typedef Apollonius_graph_new_traits_2 Self; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Apollonius_graph_kernel_wrapper_2 Kernel; - -public: - typedef Rep R; - typedef MTag Method_tag; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Site_2 Site_2; - - typedef typename Kernel::Line_2 Line_2; - typedef typename Kernel::Ray_2 Ray_2; - typedef typename Rep::Segment_2 Segment_2; - - typedef typename Kernel::Object_2 Object_2; - typedef typename Kernel::FT FT; - typedef typename Kernel::RT RT; - - -public: - // OBJECT CONSTRUCTION & ASSIGNMENT - //--------------------------------- - typedef typename Kernel::Construct_object_2 Construct_object_2; - typedef typename Kernel::Assign_2 Assign_2; - - // CONSTRUCTIONS - //-------------- - // vertex and dual site - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Construct_Apollonius_vertex_2 - /* */ Construct_Apollonius_vertex_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Construct_Apollonius_site_2 - /* */ Construct_Apollonius_site_2; - - - // PREDICATES - //----------- - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Compare_x_2 Compare_x_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Compare_y_2 Compare_y_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Compare_weight_2 - Compare_weight_2; - - // the following seems to be buggy - // typedef CGAL::AG2_Orientation_test_new_2 Orientation_2; - // use the old one: - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Orientation_new_2 - Orientation_new_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Orientation_2 - Orientation_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Is_hidden_2 Is_hidden_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Oriented_side_of_bisector_2 - /* */ Oriented_side_of_bisector_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Vertex_conflict_new_2 - Vertex_conflict_2; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Finite_edge_interior_conflict_new_2 - /* */ Finite_edge_interior_conflict_2; - - typedef - CGAL_APOLLONIUS_GRAPH_2_NS::Infinite_edge_interior_conflict_new_2 - /* */ Infinite_edge_interior_conflict_2; - - typedef CGAL_APOLLONIUS_GRAPH_2_NS::Is_degenerate_edge_2 - /* */ Is_degenerate_edge_2; - - -public: - //----------------------------------------------------------------------- - // ACCESS TO OBJECTS - //----------------------------------------------------------------------- - - // OBJECT CONSTRUCTION & ASSIGNMENT - Assign_2 - assign_2_object() const { - return Assign_2(); - } - - Construct_object_2 - construct_object_2_object() const { - return Construct_object_2(); - } - - - // CONSTRUCTIONS - //-------------- - Construct_Apollonius_vertex_2 - construct_Apollonius_vertex_2_object() const { - return Construct_Apollonius_vertex_2(); - } - - Construct_Apollonius_site_2 - construct_Apollonius_site_2_object() const { - return Construct_Apollonius_site_2(); - } - - - // PREDICATES - //----------- - Compare_x_2 - compare_x_2_object() const { - return Compare_x_2(); - } - - Compare_y_2 - compare_y_2_object() const { - return Compare_y_2(); - } - - Compare_weight_2 - compare_weight_2_object() const { - return Compare_weight_2(); - } - - Orientation_2 - orientation_2_object() const { - return Orientation_2(); - } - - Orientation_new_2 - orientation_new_2_object() const { - return Orientation_new_2(); - } - - Is_hidden_2 - is_hidden_2_object() const { - return Is_hidden_2(); - } - - Oriented_side_of_bisector_2 - oriented_side_of_bisector_2_object() const { - return Oriented_side_of_bisector_2(); - } - - Vertex_conflict_2 - vertex_conflict_2_object() const { - return Vertex_conflict_2(); - } - - Finite_edge_interior_conflict_2 - finite_edge_interior_conflict_2_object() const { - return Finite_edge_interior_conflict_2(); - } - - Infinite_edge_interior_conflict_2 - infinite_edge_interior_conflict_2_object() const { - return Infinite_edge_interior_conflict_2(); - } - - Is_degenerate_edge_2 - is_degenerate_edge_2_object() const { - return Is_degenerate_edge_2(); - } - -}; - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_NEW_TRAITS_2_H diff --git a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Conflict_2.h b/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Conflict_2.h deleted file mode 100644 index 4fba67aa2b2..00000000000 --- a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Conflict_2.h +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) 2006 INRIA Sophia-Antipolis (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) : Menelaos Karavelas -// Christophe Delage -// David Millman - -#ifndef CGAL_APOLLONIUS_GRAPH_2_CONFLICT_2_H -#define CGAL_APOLLONIUS_GRAPH_2_CONFLICT_2_H 1 - -#include -#include - -namespace CGAL { - -namespace ApolloniusGraph_2 { - -//----------------------------------------------------------------------- -// Conflict Base -//----------------------------------------------------------------------- -template < class K, class Method_tag > -class Conflict_2 -{ -public: - typedef Inverted_weighted_point_2 Inverted_weighted_point; - typedef typename K::RT RT; - typedef typename K::Sign Sign; - typedef Sign result_type; - -protected: - - Sign orientation(const Inverted_weighted_point &p1, - const Inverted_weighted_point &p2, - const Inverted_weighted_point &p3) const - { - return sign_of_determinant( p1.p(), p2.p(), p3.p(), - p1.x(), p2.x(), p3.x(), - p1.y(), p2.y(), p3.y() ); - } - - Sign radical_intersection(const Inverted_weighted_point &p1, - const Inverted_weighted_point &p2, - const Inverted_weighted_point &p3, int i) const - { - Sign s = CGAL::sign( - CGAL::square(determinant( - p1.p(), p1.weight(), p1.y(), - p2.p(), p2.weight(), p2.y(), - p3.p(), p3.weight(), p3.y())) - + CGAL::square(determinant( - p1.p(), p1.x(), p1.weight(), - p2.p(), p2.x(), p2.weight(), - p3.p(), p3.x(), p3.weight())) - - CGAL::square(determinant( - p1.p(), p1.x(), p1.y(), - p2.p(), p2.x(), p2.y(), - p3.p(), p3.x(), p3.y()))); - - if (s != ZERO || i < 0) { return s; } - - // perturbation - switch (i) { - case (1) : return radical_side(p3, p2, p1, 3); - case (2) : return radical_side(p1, p3, p2, 3); - case (3) : return radical_side(p1, p2, p3, 3); - default : - CGAL_error_msg( "Case should not hapen"); - return ZERO; - } - } - - Sign radical_side(const Inverted_weighted_point &p1, - const Inverted_weighted_point &p2, - const Inverted_weighted_point &p3, int i) const - { - CGAL_assertion(i == -1 || i == 1 || i == 2 || i == 3); - - Sign s = -CGAL::sign( - determinant( - p1.p(), p1.x(), - p2.p(), p2.x()) - * determinant( - p1.p(), p1.weight(), p1.x(), - p2.p(), p2.weight(), p2.x(), - p3.p(), p3.weight(), p3.x()) - + determinant( - p1.p(), p1.y(), - p2.p(), p2.y()) - * determinant( - p1.p(), p1.weight(), p1.y(), - p2.p(), p2.weight(), p2.y(), - p3.p(), p3.weight(), p3.y())); - - if (s != ZERO || i < 1) { return s; } - - // perturbation - return POSITIVE; - } - - Sign power_test(const Inverted_weighted_point &p1, - const Inverted_weighted_point &p2, - const Inverted_weighted_point &p3, int i) const - { - CGAL_assertion(i == -1 || i == 1 || i == 2 || i == 3); - Sign s; - - Sign s_xTest = sign_of_determinant(p2.p(), p2.x(), p1.p(), p1.x()); - if ( s_xTest != ZERO ) { - s = s_xTest * - sign_of_determinant( p1.p(), p1.x(), p1.weight(), - p2.p(), p2.x(), p2.weight(), - p3.p(), p3.x(), p3.weight() ); - } else { - s = sign_determinant2x2( p2.p(), p2.y(), p1.p(), p1.y() ) * - sign_of_determinant( p1.p(), p1.y(), p1.weight(), - p2.p(), p2.y(), p2.weight(), - p3.p(), p3.y(), p3.weight() ); - } - if (s != ZERO || i < 1) { return s; } - - switch (i) { - case 1: - return ordered_on_line (p1, p2, p3) ? NEGATIVE : POSITIVE; - case 2: - return ordered_on_line (p2, p1, p3) ? NEGATIVE : POSITIVE; - case 3: - return NEGATIVE; - default: - CGAL_error_msg( "this should not happen."); - } - - // perturbation - bool ool; - if (i == 1) { - ool = ordered_on_line(p2, p1, p3); - } else if (i == 2) { - ool = ordered_on_line(p1, p2, p3); - } else if (i == 3) { - ool = ordered_on_line(p1, p3, p2); - } else { - CGAL_error_msg( "this does not happen."); - ool = false; - } - - if (ool) { return NEGATIVE; } - - return POSITIVE; - } - - Sign ordered_on_line_test(const Inverted_weighted_point &p1, - const Inverted_weighted_point &p2) const - { - Sign s_det = sign_of_determinant( p1.p(), p1.x(), p2.p(), p2.x() ); - if ( s_det != ZERO ) { return s_det; } - return sign_of_determinant( p1.p(), p1.y(), p2.p(), p2.y() ); - } - - bool ordered_on_line(const Inverted_weighted_point &p1, - const Inverted_weighted_point &p2, - const Inverted_weighted_point &p3) const - { - if (ordered_on_line_test(p1, p2) == POSITIVE) { - return ordered_on_line_test(p2, p3) == POSITIVE; - } - return ordered_on_line_test(p3, p2) == POSITIVE; - } -}; - - -} //namespace ApolloniusGraph_2 - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_2_CONFLICT_2_H diff --git a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Edge_conflict_2.h b/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Edge_conflict_2.h deleted file mode 100644 index f4631da2d2b..00000000000 --- a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Edge_conflict_2.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2006 INRIA Sophia-Antipolis (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) : Menelaos Karavelas -// Christophe Delage -// David Millman - -#ifndef CGAL_APOLLONIUS_GRAPH_2_EDGE_CONFLICT_2_H -#define CGAL_APOLLONIUS_GRAPH_2_EDGE_CONFLICT_2_H 1 - - -#include - -namespace CGAL { - -namespace ApolloniusGraph_2 { - -//----------------------------------------------------------------------- -// Edge Conflict Base -//----------------------------------------------------------------------- - -template < class K, class Method_tag > -class Edge_conflict_2 : public Conflict_2 -{ -private: - typedef Conflict_2 Base; -public: - typedef typename Base::Inverted_weighted_point Inverted_weighted_point; - typedef bool result_type; - typedef typename Base::Sign Sign; - -protected: - - bool edge_conflict_test(const Inverted_weighted_point &p2, - const Inverted_weighted_point &p3, - const Inverted_weighted_point &p4, - const Inverted_weighted_point &q, - bool b, int /*i23Q*/, int /*i24Q*/) const - { - - // orientations - Sign orient23Q = this->orientation(p2, p3, q); - Sign orient42Q = this->orientation(p4, p2, q); - Sign orient234 = this->orientation(p2, p3, p4); - - // radical intersections - Sign radInt23Q = this->radical_intersection(p2, p3, q, -1); - Sign radInt24Q = this->radical_intersection(p2, p4, q, -1); - - // radical side - Sign radSid2Q3 = this->radical_side(p2, q, p3, -1); - Sign radSid2Q4 = this->radical_side(p2, q, p4, -1); - - // order of a line - bool oolQ24 = this->ordered_on_line(q, p2, p4); - bool oolQ23 = this->ordered_on_line(q, p2, p3); - - if ( b ) - { - if ( CGAL::sign(q.p()) != POSITIVE ) { return true; } - // degenerate case - if (orient234 == ZERO && orient23Q == ZERO && orient42Q == ZERO) { - return (oolQ23 || oolQ24); - } else if (! ((radInt23Q != NEGATIVE && radSid2Q3 == NEGATIVE) && - (radInt24Q != NEGATIVE && radSid2Q4 == NEGATIVE))) { - // non degenerate case - return true; - } else if (orient234 != NEGATIVE) { - return orient23Q != POSITIVE && orient42Q != POSITIVE; - } else { - return orient23Q != POSITIVE || orient42Q != POSITIVE; - } - } - else - { - CGAL_assertion ( CGAL::sign(q.p()) == POSITIVE ); - // degenerate case - if (orient234 == ZERO && orient23Q == ZERO && orient42Q == ZERO) { - return (oolQ23 && oolQ24); - } else if (! ((radInt23Q != NEGATIVE && radSid2Q3 == NEGATIVE) && - (radInt24Q != NEGATIVE && radSid2Q4 == NEGATIVE))) { - // non degenerate case - return false; - } else if (orient234 != NEGATIVE) { - return orient23Q != POSITIVE || orient42Q != POSITIVE; - } else { - return orient23Q != POSITIVE && orient42Q != POSITIVE; - } - } - } -}; - -} //namespace ApolloniusGraph_2 - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_2_EDGE_CONFLICT_2_H diff --git a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Finite_edge_conflict_2.h b/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Finite_edge_conflict_2.h deleted file mode 100644 index 5c6ab3904dc..00000000000 --- a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Finite_edge_conflict_2.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2006 INRIA Sophia-Antipolis (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) : Menelaos Karavelas -// Christophe Delage -// David Millman - -#ifndef CGAL_APOLLONIUS_GRAPH_2_FINITE_EDGE_CONFLICT_2_H -#define CGAL_APOLLONIUS_GRAPH_2_FINITE_EDGE_CONFLICT_2_H - -#include - -namespace CGAL { - -namespace ApolloniusGraph_2 { - -//----------------------------------------------------------------------- -// Finite edge interior conflict -//----------------------------------------------------------------------- - -template < class K, class Method_tag > -class Finite_edge_interior_conflict_new_2 - : public Edge_conflict_2 -{ -private: - typedef Edge_conflict_2 Base; - - using Base::edge_conflict_test; - -public: - typedef typename Base::Inverted_weighted_point Inverted_weighted_point; - typedef Weighted_point_inverter_2 Weighted_point_inverter; - typedef typename K::Site_2 Site_2; - typedef typename K::Point_2 Point_2; - typedef bool result_type; - - inline - bool operator()(const Site_2& p1, const Site_2& p2, - const Site_2& q, bool b) const - { - Weighted_point_inverter inverter(p1); - Point_2 origin(0,0); - Site_2 origin_site(origin,0); - return edge_conflict_test(inverter(p2), - Inverted_weighted_point(origin_site,1), - Inverted_weighted_point(origin_site,1), - inverter(q), b, 2, 2); - } - - inline - bool operator()(const Site_2& p1, const Site_2& p2, - const Site_2& p3, const Site_2& q, bool b) const - { - Weighted_point_inverter inverter(p2); - Point_2 origin(0,0); - Site_2 origin_site(origin,0); - return edge_conflict_test(inverter(p1), - Inverted_weighted_point(origin_site,1), - inverter(p3), inverter(q), b, 2, 1); - } - - inline - bool operator()(const Site_2& p1, const Site_2& p2, const Site_2& p3, - const Site_2& p4, const Site_2& q, bool b) const - { - Weighted_point_inverter inverter(p2); - return edge_conflict_test(inverter(p1), inverter(p4), inverter(p3), - inverter(q), b, 1, 1); - } -}; - -} //namespace ApolloniusGraph_2 - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_2_FINITE_EDGE_CONFLICT_2_H diff --git a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Infinite_edge_conflict_2.h b/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Infinite_edge_conflict_2.h deleted file mode 100644 index 6be7d9522dd..00000000000 --- a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Infinite_edge_conflict_2.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2006 INRIA Sophia-Antipolis (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) : Menelaos Karavelas -// Christophe Delage -// David Millman - -#ifndef CGAL_APOLLONIUS_GRAPH_2_INFINITE_EDGE_CONFLICT_2_H -#define CGAL_APOLLONIUS_GRAPH_2_INFINITE_EDGE_CONFLICT_2_H - - -#include - -namespace CGAL { - -namespace ApolloniusGraph_2 { - -//----------------------------------------------------------------------- -// Infinite edge interior conflict -//----------------------------------------------------------------------- - -template < class K, class Method_tag > -class Infinite_edge_interior_conflict_new_2 - : public Edge_conflict_2 -{ -private: - typedef Edge_conflict_2 Base; - using Base::edge_conflict_test; - -public: - typedef Weighted_point_inverter_2 Weighted_point_inverter; - typedef typename Base::Inverted_weighted_point Inverted_weighted_point; - typedef typename K::Site_2 Site_2; - typedef typename K::Point_2 Point_2; - typedef bool result_type; - - inline - bool operator()(const Site_2& p2, const Site_2& p3, - const Site_2& p4, const Site_2& q, bool b) const - { - Weighted_point_inverter inverter(p2); - Point_2 origin(0,0); - Site_2 origin_site(origin,0); - return edge_conflict_test(Inverted_weighted_point(origin_site, 1), - inverter(p4), inverter(p3), inverter(q), - b, 1, 1); - } -}; - - -} //namespace ApolloniusGraph_2 - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_2_INFINITE_EDGE_CONFLICT_2_H diff --git a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/New_predicates_C2.h b/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/New_predicates_C2.h deleted file mode 100644 index 6fee61f3626..00000000000 --- a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/New_predicates_C2.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2006 INRIA Sophia-Antipolis (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) : Menelaos Karavelas - - - -#ifndef CGAL_APOLLONIUS_GRAPH_2_NEW_PREDICATES_C2_H -#define CGAL_APOLLONIUS_GRAPH_2_NEW_PREDICATES_C2_H 1 - -#include - -#include -#include -#include -#include - -#endif // CGAL_APOLLONIUS_GRAPH_2_NEW_PREDICATES_C2_H diff --git a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Orientation_2.h b/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Orientation_2.h deleted file mode 100644 index 2894971a591..00000000000 --- a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Orientation_2.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2006 INRIA Sophia-Antipolis (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) : Menelaos Karavelas -// Christophe Delage -// David Millman - -#ifndef CGAL_APOLLONIUS_GRAPH_2_ORIENTATION_NEW_2_H -#define CGAL_APOLLONIUS_GRAPH_2_ORIENTATION_NEW_2_H - - -#include - -namespace CGAL { - -namespace ApolloniusGraph_2 { - - -template -class Orientation_new_2 : public Orientation_2 -{ -private: - typedef Orientation_2 Base; -public: - typedef K Kernel; - typedef typename K::RT RT; - typedef typename K::Site_2 Site_2; - typedef typename K::Point_2 Point_2; - - typedef typename Base::Orientation Orientation; - typedef Orientation result_type; - typedef Site_2 argument_type; - - Orientation operator() (const Site_2 &s0, const Site_2 &s1, - const Site_2 &s2, const Point_2 &q) const - { - RT x1 = s1.x() - s0.x(); - RT y1 = s1.y() - s0.y(); - RT w1 = s1.weight() - s0.weight(); - - RT x2 = s2.x() - s0.x(); - RT y2 = s2.y() - s0.y(); - RT w2 = s2.weight() - s0.weight(); - - RT xq = q.x() - s0.x(); - RT yq = q.y() - s0.y(); - - RT a1 = CGAL::square(x1) + CGAL::square(y1) - CGAL::square(w1); - RT a2 = CGAL::square(x2) + CGAL::square(y2) - CGAL::square(w2); - - CGAL_assertion (CGAL::sign(a1) == POSITIVE); - CGAL_assertion (CGAL::sign(a2) == POSITIVE); - - RT x = a1 * x2 - a2 * x1; - RT y = a1 * y2 - a2 * y1; - RT w = a1 * w2 - a2 * w1; - RT s = x * xq + y * yq; - - Sign W = CGAL::sign (w); - Sign S = CGAL::sign (s); - - if (W == ZERO) { return -S; } - - RT o = x * yq - y * xq; - - Sign O = CGAL::sign(o); - - if (S == 0) { return O * W; } - - if (W * S * O != POSITIVE) { return -S; } - - RT i = CGAL::square(w) * (CGAL::square(xq) + CGAL::square(yq)) - - CGAL::square(s); - - Sign I = CGAL::sign(i); - - return S * I; - } -}; - -} //namespace ApolloniusGraph_2 - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_2_ORIENTATION_NEW_2_H diff --git a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Vertex_conflict_2.h b/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Vertex_conflict_2.h deleted file mode 100644 index 2990c589105..00000000000 --- a/Apollonius_graph_2/archive/include/CGAL/Apollonius_graph_2/Delage_traits/Vertex_conflict_2.h +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright (c) 2006 INRIA Sophia-Antipolis (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) : Menelaos Karavelas -// Christophe Delage -// David Millman - -#ifndef CGAL_APOLLONIUS_GRAPH_2_VERTEX_CONFLICT_2_H -#define CGAL_APOLLONIUS_GRAPH_2_VERTEX_CONFLICT_2_H - - -#include - - -namespace CGAL { - -namespace ApolloniusGraph_2 { - -//----------------------------------------------------------------------- -// Vertex conflict -//----------------------------------------------------------------------- - -template < class K, class Method_tag > -class Vertex_conflict_new_2 -{ -public: - typedef typename K::Site_2 Site_2; - typedef typename K::RT RT; - typedef Sign result_type; - -private: - - inline - bool is_less (const Site_2 &p0, const Site_2 &p1) const - { - if (p0.weight() < p1.weight()) return true; - if (p0.weight() > p1.weight()) return false; - - if (p0.x() < p1.x()) return true; - if (p0.x() > p1.x()) return false; - - return p0.y() < p1.y(); - } - - inline - int max_radius(const Site_2 &p0, const Site_2 &p1, - const Site_2 &p2, const Site_2 &p3) const - { - int i = 0; - const Site_2 *p = &p0; - - if (is_less (*p, p1)) { i = 1; p = &p1; } - if (is_less (*p, p2)) { i = 2; p = &p2; } - if (is_less (*p, p3)) { i = 3; } - - return i; - } - - inline - Sign predicate (const Site_2 &p1, const Site_2 &p2, - const Site_2 &p3, const Site_2 &q, bool perturb) const - { - RT xq = q.x() - p1.x(); - RT yq = q.y() - p1.y(); - RT wq = q.weight() - p1.weight(); - RT aq = CGAL::square(xq) + CGAL::square(yq) - CGAL::square(wq); - - // q is hiding p1 - if (CGAL::sign(aq) != POSITIVE){ - // I BELIEVE MENELAOS RETURNS -1 in this case even when degernate - //if (sign (aq) == ZERO && ! perturb) return ZERO; - - //return NEGATIVE; - return POSITIVE; - } - - RT x2 = p2.x() - p1.x(); - RT y2 = p2.y() - p1.y(); - RT w2 = p2.weight() - p1.weight(); - RT a2 = CGAL::square(x2) + CGAL::square(y2) - CGAL::square(w2); - - CGAL_assertion (a2 > 0); - - RT x3 = p3.x() - p1.x(); - RT y3 = p3.y() - p1.y(); - RT w3 = p3.weight() - p1.weight(); - RT a3 = CGAL::square(x3) + CGAL::square(y3) - CGAL::square(w3); - - CGAL_assertion (a3 > 0); - - RT ax3q = a3 * xq - x3 * aq; - RT ax2q = a2 * xq - x2 * aq; - RT ax23 = a2 * x3 - x2 * a3; - - RT ay23 = a2 * y3 - y2 * a3; - RT ay2q = a2 * yq - y2 * aq; - RT ay3q = a3 * yq - y3 * aq; - - RT axw23q = ax23 * wq - ax2q * w3 + ax3q * w2; - RT ayw23q = ay23 * wq - ay2q * w3 + ay3q * w2; - - RT axy23q = y2 * ax3q - y3 * ax2q + yq * ax23; - - // orientation - Sign orient = CGAL::sign(axy23q); - - // orientation degenerate - if (orient == ZERO) { - Sign orient1 = CGAL::sign(ax23); - - Sign power_test = - ( orient1 == ZERO ? - (CGAL::sign(ay23) * CGAL::sign(ayw23q)) : - (orient1 * CGAL::sign(axw23q)) - ); - - if (power_test != ZERO || !perturb) { - return -power_test; - } - - int i = max_radius (p1, p2, p3, q); - - if (i == 3) { return NEGATIVE; } - - Sign o23, o2q, o3q; - - if (orient1 == ZERO) { - o23 = CGAL::sign(ay23); - o2q = CGAL::sign(ay2q); - o3q = CGAL::sign(ay3q); - } else { - o23 = CGAL::sign(ax23); - o2q = CGAL::sign(ax2q); - o3q = CGAL::sign(ax3q); - } - - if (o23 != o2q) { return i == 2 ? NEGATIVE : POSITIVE; } - - if (o23 == o3q) { return i == 1 ? NEGATIVE : POSITIVE; } - - return i == 0 ? NEGATIVE : POSITIVE; - } - - - // radical side - RT rs23q = ax23 * axw23q + ay23 * ayw23q; - Sign radSide = CGAL::sign(rs23q); - - if (radSide == ZERO || radSide != orient) { return orient; } - - // radical intersection - Sign radInt = - CGAL::sign(CGAL::square(axw23q) + CGAL::square(ayw23q) - - CGAL::square( axy23q)); - - // radical intersection degenerate - if (radInt == ZERO) { - Sign radSideQ = CGAL::sign(ax23 * axw23q + ay23 * ayw23q); - - CGAL_assertion (radSideQ != ZERO); - - if (!perturb) { return (radSideQ == orient) ? ZERO : orient; } - - int i = max_radius (p1, p2, p3, q); - - if (i == 3) { - radInt = radSideQ; - } else if (i == 2) { - radInt = -CGAL::sign(ax2q * axw23q + ay2q * ayw23q); - if (radInt == ZERO) { return NEGATIVE; } - } else if (i == 1) { - radInt = CGAL::sign(ax3q * axw23q + ay3q * ayw23q); - if (radInt == ZERO) { return NEGATIVE; } - } else { - CGAL_assertion (i == 0); - Sign radSide1 = -CGAL::sign(ax2q * axw23q + ay2q * ayw23q); - if (radSide1 == ZERO) { return NEGATIVE; } - - Sign radSide2 = CGAL::sign(ax3q * axw23q + ay3q * ayw23q); - if (radSide2 == ZERO) { return NEGATIVE; } - - radInt = Sign (-(radSideQ + radSide1 + radSide2)); - } - } - - CGAL_assertion (!perturb || radInt != ZERO); - - if (radInt == NEGATIVE) { return orient; } - - return -radSide; - } - - - inline - Sign predicate(const Site_2 &p1, const Site_2 &p2, - const Site_2 &q, bool perturb) const - { - // NOTE:*************************************** - // * the perturb boolean variable is not used - // * for consistancy with Menelaos - // NOTE:*************************************** - RT x2 = p2.x() - p1.x(); - RT y2 = p2.y() - p1.y(); - RT w2 = p2.weight() - p1.weight(); - RT xq = q.x() - p1.x(); - RT yq = q.y() - p1.y(); - RT wq = q.weight() - p1.weight(); - - RT xw2q = x2 * wq - xq * w2; - RT yw2q = y2 * wq - yq * w2; - RT xy2q = x2 * yq - xq * y2; - - // orientation - Sign orient = CGAL::sign(xy2q); - - // orientation degenerate - if (orient == ZERO) { - Sign o12 = CGAL::sign(x2); - Sign o1q, o2q; - - Sign power_test; - if (o12 != ZERO) { - power_test = o12 * CGAL::sign(xw2q); - - // this results is consistant with Menelaos - if (power_test != ZERO) { return -power_test; } - - // this result is consistant with the perturb on off idea - //if (power_test != ZERO || ! perturb) return -power_test; - o1q = CGAL::sign(xq); - o2q = CGAL::sign(q.x() - p2.x()); - } else { - o12 = CGAL::sign(y2); - power_test = o12 * CGAL::sign(yw2q); - - // this results is consistant with Menelaos - if (power_test != ZERO) { return -power_test; } - - // this result is consistant with the perturb on off idea - //if (power_test != ZERO || ! perturb) return -power_test; - o1q = CGAL::sign(yq); - o2q = CGAL::sign(q.y() - p2.y()); - } - - if (o1q != o12) { return POSITIVE; } - if (o2q == o12) { return POSITIVE; } - - return NEGATIVE; - } - - // radical side - RT rs12q = x2 * xw2q + y2 * yw2q; - Sign radSide = CGAL::sign(rs12q); - - if (radSide == ZERO || radSide == orient) { - return -orient; - } - - // radical intersection - Sign radInt = - CGAL::sign(CGAL::square(xw2q) + CGAL::square(yw2q) - - CGAL::square(xy2q)); - - // radical intersection degerate - if (radInt == ZERO) { - CGAL_assertion (radSide != ZERO); - - // this result is consistant with the perturb on off idea - //if (! perturb) return (radSide == orient) ? ZERO : orient; - - RT rs2q1 = (p2.x() - q.x()) * xw2q + (p2.y() - q.y()) * yw2q; - Sign radSide1 = CGAL::sign(rs2q1); - if (radSide1 == ZERO) { return NEGATIVE; } - - RT rsq12 = xq * xw2q + yq * yw2q; - Sign radSide2 = CGAL::sign(rsq12); - if (radSide2 == ZERO) { return NEGATIVE; } - - return -(radSide1 * radSide2); - } - - CGAL_assertion (!perturb || radInt != ZERO); - - if (radInt == POSITIVE) { return orient; } - return radSide; - } - -public: - inline - Sign operator()(const Site_2 &p1, const Site_2 &p2, - const Site_2 &p3, const Site_2 &q, - bool perturb = true) const - { - Sign newPred = predicate(p1, p2, p3, q, perturb); - CGAL_assertion (!perturb || newPred != ZERO); - return newPred; - } - - inline - Sign operator()(const Site_2 &p1, const Site_2 &p2, - const Site_2 &q, bool perturb = true) const - { - Sign newPred = predicate(p1, p2, q, perturb); - CGAL_assertion (!perturb || newPred != ZERO); - return newPred; - } -}; - -} //namespace ApolloniusGraph_2 - -} //namespace CGAL - -#endif // CGAL_APOLLONIUS_GRAPH_2_VERTEX_CONFLICT_2_H diff --git a/Apollonius_graph_2/archive/test/Apollonius_graph_2/test_ag_new_traits_2.cpp b/Apollonius_graph_2/archive/test/Apollonius_graph_2/test_ag_new_traits_2.cpp deleted file mode 100644 index e240628d93b..00000000000 --- a/Apollonius_graph_2/archive/test/Apollonius_graph_2/test_ag_new_traits_2.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include - -#include -#include - -#include -#include - -#include -#include -#include - -typedef CGAL::Sign Sign; - -template -class Check_traits : public GT -{ - GT_test test; -public: - - typedef typename GT::Site_2 Site_2; - - Check_traits (const GT > = GT(), const GT_test >_test = GT_test()) - : GT(gt), test (gt_test) - {} - - template - struct Checked_predicate : public Predicate - { - New_predicate newp; - typedef typename Predicate::result_type result_type; - - Checked_predicate (const Predicate &p, const New_predicate &np) - : Predicate (p), newp (np) - {} - - template - result_type operator() (const T1 &t1) const - { - result_type r1 = Predicate::operator() (t1); - result_type r2 = newp (t1); - assert(r1 == r2); - return r1; - } - template - result_type operator() (const T1 &t1, const T2 &t2) const - { - result_type r1 = Predicate::operator() (t1, t2); - result_type r2 = newp (t1, t2); - assert(r1 == r2); - return r1; - } - template - result_type operator() (const T1 &t1, const T2 &t2, const T3 &t3) const - { - result_type r1 = Predicate::operator() (t1, t2, t3); - result_type r2 = newp (t1, t2, t3); - assert(r1 == r2); - return r1; - } - template - result_type operator() (const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) const - { - result_type r1 = Predicate::operator() (t1, t2, t3, t4); - result_type r2 = newp (t1, t2, t3, t4); - assert(r1 == r2); - return r1; - } - template - result_type operator() (const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5) const - { - result_type r1 = Predicate::operator() (t1, t2, t3, t4, t5); - result_type r2 = newp (t1, t2, t3, t4, t5); - assert(r1 == r2); - return r1; - } - template - result_type operator() (const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6) const - { - result_type r1 = Predicate::operator() (t1, t2, t3, t4, t5, t6); - result_type r2 = newp (t1, t2, t3, t4, t5, t6); - assert(r1 == r2); - return r1; - } - }; - - typedef Checked_predicate - Vertex_conflict_2; - - typedef Checked_predicate - Finite_edge_interior_conflict_2; - - typedef Checked_predicate - Infinite_edge_interior_conflict_2; - - Vertex_conflict_2 - vertex_conflict_2_object() const - { - return Vertex_conflict_2 ( - GT::vertex_conflict_2_object(), - test.vertex_conflict_2_object()); - } - Finite_edge_interior_conflict_2 - finite_edge_interior_conflict_2_object() const - { - return Finite_edge_interior_conflict_2 ( - GT::finite_edge_interior_conflict_2_object(), - test.finite_edge_interior_conflict_2_object()); - } - Infinite_edge_interior_conflict_2 - infinite_edge_interior_conflict_2_object() const - { - return Infinite_edge_interior_conflict_2 ( - GT::infinite_edge_interior_conflict_2_object(), - test.infinite_edge_interior_conflict_2_object()); - } -}; - -typedef CGAL::MP_Float NT; -typedef CGAL::Simple_cartesian K; -typedef CGAL::Apollonius_graph_traits_2 GT_old; -typedef CGAL::Apollonius_graph_new_traits_2 GT_new; -typedef Check_traits GT; -typedef CGAL::Apollonius_graph_2 AG; - -typedef AG::Site_2 Site; -typedef AG::Finite_faces_iterator Finite_faces_iterator; -typedef AG::Finite_vertices_iterator Finite_vertices_iterator; -typedef AG::Vertex_handle Vertex_handle; - -void test_orientation (const AG &ag, - Vertex_handle v0, Vertex_handle v1, Vertex_handle v2) -{ - const Site &s0 = v0->site(); - const Site &s1 = v1->site(); - const Site &s2 = v2->site(); - - GT gt; - GT_new gt_new; - - GT::Orientation_2 orientation1 = gt.orientation_2_object(); - GT_new::Orientation_new_2 orientation2 = gt_new.orientation_new_2_object(); - - for (Finite_vertices_iterator _v = ag.finite_vertices_begin(); - _v != ag.finite_vertices_end(); ++_v) - { - Vertex_handle v = _v; - if (v == v0) continue; - - Sign o1 = orientation1 (s0, s1, s2, s0, v->site()); - Sign o2 = orientation2 (s0, s1, s2, v->site().point()); - - assert(o1 == o2); - } -} - -void test_file (const char *filename) -{ - std::ifstream is (filename); - - assert(is); - - std::cout << "File " << filename << ": construction... " << std::flush; - AG ag; - Site s; while (is >> s) ag.insert (s); - - std::cout << "validation... " << std::flush; - assert(ag.is_valid()); - - std::cout << "OK" << std::endl; - - std::cout << "Test orientation... " << std::flush; - - for (Finite_faces_iterator f = ag.finite_faces_begin(); - f != ag.finite_faces_end(); ++f) - { - test_orientation (ag, f->vertex(0), f->vertex(1), f->vertex(2)); - test_orientation (ag, f->vertex(1), f->vertex(2), f->vertex(0)); - test_orientation (ag, f->vertex(2), f->vertex(0), f->vertex(1)); - } - - std::cout << "OK" << std::endl; -} - -int main (void) -{ - test_file ("data/traits.dat"); - test_file ("data/algo.dat"); - - return 0; -} diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt b/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt deleted file mode 100644 index 0b2f6aa2082..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt +++ /dev/null @@ -1,438 +0,0 @@ -namespace CGAL { -/*! - -\mainpage User Manual -\anchor Chapter_2D_Apollonius_Graphs -\anchor chapterapollonius2 -\cgalAutoToc -\authors Menelaos Karavelas and Mariette Yvinec - -This chapter describes the two-dimensional Apollonius graph -of \cgal. We start with a few definitions in -Section \ref secapollonius2definitions. -The software design of the 2D Apollonius graph package is described -in Section \ref secapollonius2design. -In Section \ref secapollonius2traits we discuss the geometric -traits of the 2D Apollonius graph package and in Section -\ref secapollonius2hierarchy the Apollonius graph hierarchy, a data -structure suitable for fast nearest neighbor queries, is briefly -described. - -\section secapollonius2definitions Definitions - -\cgalFigureBegin{figapollonius,apollonius_diagram.png,apollonius_graph.png} -The Apollonius diagram (left) and its dual the Apollonius graph (right). -\cgalFigureEnd - -The 2D Apollonius graph class of \cgal is designed to compute the -dual of the Apollonius diagram or, as it is also known, the -Additively weighted Voronoi diagram. The algorithm that has been -implemented is dynamic, which means that we can perform insertions and -deletions on line. The corresponding \cgal class is called -`Apollonius_graph_2` -and will be discussed in more detail in the sequel. The interested -reader may want to refer to the paper by Karavelas and Yvinec -\cgalCite{cgal:ky-dawvd-02} for the general idea as well as the details of the -algorithm implemented. - -Before describing the details of the implementation we make a brief -introduction to the theory of Apollonius diagrams. -The Apollonius diagram is defined over a set of sites -\f$ P_i=(c_i,w_i)\f$, \f$ i=1,\ldots,n\f$, where \f$ c_i\f$ is the point and \f$ w_i\f$ -the weight of \f$ P_i\f$. It is a subdivision of the plane into connected -regions, called cells, associated with the sites (see -\cgalFigureRef{figapollonius} (left)). The cell of a -site \f$ P_i\f$ is the locus of points on the plane that are -closer to \f$ P_i\f$ than any other site \f$ P_j\f$, \f$ j\neq i\f$. -The distance \f$ \delta(x, P_i)\f$ of a point \f$ x\f$ in the plane to a -site \f$ P_i\f$ is defined as: -\f[ \delta(x,P_i)=\|x-c_i\|-w_i, \f] -where \f$ \|\cdot\|\f$ denotes the Euclidean norm. -It can easily be seen that it is a generalization of the Voronoi -diagram for points, which can actually be obtained if all the weights -\f$ w_i\f$ are equal. Unlike the case of points, however, it is -possible that a site \f$ P_i\f$ might have an empty cell. This -can also happen in the case of the power diagram, whose dual is the -regular triangulation (see Section -\ref Section_2D_Triangulations_Regular ). If this is -the case we call the site hidden (these are the black -circles in \cgalFigureRef{figapollonius} ). A site which is not -hidden will be referred to as visible. - -If all weights \f$ w_i\f$ are non-negative, the Apollonius -diagram can be viewed as the Voronoi diagram of the set of circles -\f$ \{P_1,\ldots, P_n\}\f$, where \f$ c_i\f$ is the center of the circle \f$ P_i\f$ -and \f$ w_i\f$ its radius. If the weights are allowed to be negative, -we need to go to 3D in order to explain what the Apollonius diagram -means geometrically. We identify the 2D Euclidean plane with the -\f$ xy\f$-plane in 3D. Then the Voronoi diagram of a set of points can be -seen as the vertical projection on the \f$ xy\f$-plane of the lower -envelope of a set of 3D cones defined as follows: for each point \f$ p\f$ -in the set of 2D points we have a cone \f$ C_p\f$ whose apex is the point -\f$ p\f$. The axis of -\f$ C_p\f$ is a line parallel to the \f$ z\f$-axis passing through \f$ p\f$, the -angle of \f$ C_p\f$ is \f$ 45^\circ\f$ and, finally \f$ C_p\f$ is facing in the -positive \f$ z\f$-direction (that is, \f$ C_p\f$ is contained in the positive -\f$ z\f$-halfspace). -The Apollonius diagram corresponds to shifting the -apexes of these cones in the \f$ z\f$-direction by a quantity equal to the -weight. Sites with negative weight will give rise to -cones whose apex is in the negative \f$ z\f$-halfspace and sites -with positive weight will give rise to cones whose apex is in the -positive \f$ z\f$-halfspace. In a manner analogous to the case of points, -the Apollonius diagram can then be defined as the vertical projection -on the \f$ xy\f$-plane of the lower envelope of the set of shifted cones. -Notice that when all apexes are translated along the \f$ z\f$-direction by -the same amount, the projection of the lower envelope of the set of -cones does not change. In particular, we can translate all cones by a -large enough amount so that all apexes are in the positive -\f$ z\f$-halfspace. Algebraically, this means that the Apollonius diagram -does not change if we add to all weights the same quantity, which in -particular, implies that we can assume without loss of generality that -all weights are positive. Given the observations above and in order to -simplify our discussion of Apollonius diagrams, we will, from now on, -assume that all weights are positive, and we will refer to the -sites as circles. - -The Apollonius diagram is a planar graph, and so is its dual, the -Apollonius graph. There are many ways to embed it on the plane and one -such way is shown in \cgalFigureRef{figapollonius} (right). -The Apollonius graph is uniquely defined once we have -the Apollonius diagram. If the circles are in general position -(see precise definition below), then the Apollonius graph is a graph -with triangular faces away from -the convex hull of the set of circles (by triangular we mean that -every face has exactly three edges). Near the convex hull we may -have some spikes (i.e., vertices of degree 1). To unify our approach -and handling of the Apollonius graph we add to the set of (finite) -circles a fictitious circle at infinity, which we call the -site at infinity. We can then connect all vertices of the outer -face of the Apollonius graph to the site at infinity which gives us -a graph with the property that all of its faces are now -triangular. However, the Apollonius graph is not a triangulation for -two main reasons: we cannot always embed it on the plane with straight -line segments that yield a triangulation and, moreover, we may have two -faces of the graph that have two edges in common, which is not allowed -in a triangulation. Both of these particularities appear when we -consider the Apollonius graph of the set of circles in -\cgalFigureRef{figapollonius}. - -We would like to finish our brief introduction to the theory of -Apollonius graphs by discussing the concept of general position. We say -that a set of circles is in general position if no two triplets of -circles have the same tritangent circle. This statement is rather -technical and it is best understood in the context of points. The -equivalent statement for points is that we have no two triplets of -points that define the same circumcircle, or equivalently that no -four points are co-circular. The statement about general position made -above is a direct generalization of the (much simpler to understand) -statement about points. On the contrary, when we have circles in -degenerate position, the Apollonius graph has faces with more than -three edges on their boundary. We can get a triangulated version of -the graph by simply triangulating the corresponding faces in an -arbitrary way. In fact the algorithm that has been implemented in -\cgal has the property that it always returns a valid -triangulated version of the Apollonius graph. By valid we mean -that it contains the actual Apollonius graph (i.e., the actual dual of -the Apollonius diagram) and whenever there are faces with more than -three faces then they are triangulated. The way that they are -triangulated depends on the order of insertion and deletion of the -circles in the diagram. - -One final point has to be made about hidden circles. First of all we -would like to be more precise about our definition of hidden circles: -we say that a circle is hidden if its cell has empty interior. This -definition allows us to guarantee that all visible circles have -cells that are two-dimensional regions. -Geometrically the fact that a circle is hidden means that it is -contained in the closure of the disk of another circle (see again -\cgalFigureRef{figapollonius} ). Note that a circle contained in the union -of several disks, but not in the closure of any one of them, is not -hidden. - -Hidden circles pose an additional -difficulty to our algorithm and software design. Since we allow -circles to be inserted and deleted at wish, it is possible that a -circle that was hidden at some point in time, may become visible at -a later point in time; for example this can happen if we delete the -circle that hides it. For this purpose we store hidden circles and -have them reappear when they become visible. We will discuss this -issue in detail below. For the time being it suffices to say that the -user has the ability to control this behavior. More specifically it is -possible to discard the circles that become hidden. This choice is -totally natural when for example we expect to do only insertions, -since in this case a circle that becomes hidden will never -reappear. On the other hand if deletions are expected as well, then we -lose the ability to have the hidden circles reappear. - -Degenerate Dimensions. - -The dimension of the Apollonius graph is in general 2. The exceptions -to this rule are as follows: -
    -
  • The dimension is \f$ -1\f$ if the Apollonius graph contains no circles. -
  • The dimension is \f$ 0\f$ if the Apollonius graph contains exactly -one visible circle. -
  • The dimension is \f$ 1\f$ is the Apollonius graph contains exactly -two visible circles. -
- -\section secapollonius2design Software Design - -The 2D Apollonius graph class -`Apollonius_graph_2` -follows the design of the triangulation packages of \cgal. It is -parametrized by two arguments: -
    -
  • the geometric traits class. It provides the basic -geometric objects involved in the algorithm, such as sites, points -etc. It also provides the geometric predicates for the computation -of the Apollonius graph, as well as some basic constructions that -can be used, for example, to visualize the Apollonius graph or the -Apollonius diagram. The geometric traits for the Apollonius graph -will be discussed in more detail in the next section. -
  • the Apollonius graph data structure. This is essentially -the same as the triangulation data structure (discussed in Chapter -\ref Chapter_2D_Triangulation_Data_Structure ), augmented with some -additional operations that are specific to Apollonius graphs. The -corresponding concept is that of -`ApolloniusGraphDataStructure_2`, which in fact is a refinement -of the `TriangulationDataStructure_2` concept. The class -`Triangulation_data_structure_2` is a model of -the concept `ApolloniusGraphDataStructure_2`. A default value -for the corresponding template parameter is provided, so the user -does not need to specify it. -
- -Storing Hidden Sites. - -As we have already mentioned a circle is hidden if it is contained -inside some visible circle. This creates a parent-child relationship -between visible and hidden circles: the parent of a hidden circle is the -visible circle that contains it. If more than one visible circles -contain a hidden circle then the hidden circle can be assigned to any of -the visible circles arbitrarily. - -To store hidden circles we assign to every visible circle a list. This -list comprises the hidden circles that are contained in the -visible circle. The user can access the hidden circles associated with -a visible circle through an iterator called -`Hidden_sites_iterator`. This iterator is defined in the -`ApolloniusGraphVertexBase_2` concept and is implemented by its -model, the `Apollonius_graph_vertex_base_2` -class. It is also possible to iterate through the entire set of hidden -sites using an homonymous iterator defined by the -`Apollonius_graph_2` class. - -Since storing hidden sites may not be of interest in some cases (e.g., -for example this is the case if we only perform insertions in the -Apollonius graph), the user has the possibility of controlling this -behavior. More precisely, the class -`Apollonius_graph_vertex_base_2` has two template -parameters, the second of which is a Boolean value. This value is by -default `true` and it indicates that hidden sites should be -stored. The user can indicate that hidden sites may be discarded -by setting this value to `false`. - -\section secapollonius2traits The Geometric Traits - -The predicates required for the computation of the Apollonius graph -are rather complicated. It is not the purpose of this document to -discuss them in detail. The interested reader may refer to the papers -by Karavelas and Emiris for the details -\cgalCite{cgal:ke-ppawv-02}, \cgalCite{cgal:ke-rctac-03}. However, we would like to give a brief -overview of what they -compute. There are several predicates needed by this algorithm. We -will discuss the most important/complicated ones. It turns out that -it is much easier to describe them in terms of the Apollonius diagram, -rather than the Apollonius graph. Whenever it is applicable we will also -describe their meaning in terms of the Apollonius graph. - -The first two geometric predicates are called -`Is_hidden_2` and `Oriented_side_of_bisector_2`. The first one -involves two circles, say \f$ P_1\f$ and \f$ P_2\f$. It determines if \f$ P_1\f$ is -hidden with respect to \f$ P_2\f$; more precisely it checks whether the -circle \f$ P_1\f$ is contained in the closure of the disk defined by the -circle \f$ P_2\f$. As its name indicates, it determines if a circle is -hidden or not. The second predicate involves two circles \f$ P_1\f$ and -\f$ P_2\f$ and a point \f$ q\f$. It answers the question whether \f$ q\f$ is closer -to \f$ P_1\f$ or \f$ P_2\f$. Its name stems from the fact that answering the -aforementioned question is equivalent to determining the oriented -side of the bisector of \f$ P_1\f$ and \f$ P_2\f$ that contains the query point -\f$ q\f$. This predicate is used by the algorithm for closest neighbor -queries for points. - -The next geometric predicate is called `Vertex_conflict_2` and it -involves four circles \f$ P_1\f$, \f$ P_2\f$, \f$ P_3\f$, and \f$ P_4\f$ (see -\cgalFigureRef{figag2vc} ). The first three (red circles in -\cgalFigureRef{figag2vc} ) define a tritangent circle (yellow -circle in \cgalFigureRef{figag2vc} ). What we want to determine is -the sign of the distance of the green circle from the yellow -circle. The distance between two circles \f$ K_1=(c_1,r_1)\f$ and -\f$ K_2=(c_2, r_2)\f$ is defined as the distance of their centers minus -their radii: -\f[ \delta(K_1, K_2) = \|c_1-c_2\|-r_1-r_2. \f] -This predicate determines if a vertex in the Apollonius diagram -(the center of the yellow circle) is destroyed when a new circle is -inserted in the diagram (the green circle). In the Apollonius graph -it tells us if a triangular face of the diagram is to be destroyed or -not. - -\cgalFigureBegin{figag2vc,apollonius-vertex_conflict-false.png,apollonius-vertex_conflict-true.png} -The `Vertex_conflict_2` predicate. The left-most, bottom-most and top-most circles define the tritangent circle in the middle. We want to determine the sign of the distance of the left-most circle from the one in the middle. The almost horizontal curve is the bisector of the top-most and bottom-most circles. Left: the predicate returns `NEGATIVE`. Right: the predicate returns `POSITIVE`. -\cgalFigureEnd - -What we essentially want to compute when we construct incrementally a -Voronoi diagram, is whether the object to be inserted destroys an edge -of the Voronoi diagram or not. In the case of points this is really -easy and it amounts to the well known incircle test. -In the case -of circles the situation is more complicated. We can have six possible -outcomes as to what portion of an edge of the Apollonius diagram the -new circle destroys (see \cgalFigureRef{figag2edgeconflict} ). The first -two can be answered directly by the `Vertex_conflict_2` predicate -evaluated for the two endpoints of the Apollonius diagram edge. This -is due to the fact that the value of the `Vertex_conflict_2` -predicate is different for the two endpoints. If the two values are -the same then we need an additional test which determines if the interior -of the Apollonius diagram edge is destroyed by the new circle. This is -what the `Finite_edge_interior_conflict_2` and -`Infinite_edge_interior_conflict_2` predicates do. In essence, it -is the same predicate (same idea) applied to two different types of -edges in the Apollonius diagram: a finite or an infinite edge. An edge -is infinite if its dual edge in the Apollonius graph connects the -site at infinity with the vertex corresponding to a (finite) circle; -otherwise it is a finite edge. - -\cgalFigureAnchor{figag2edgeconflict} -
- - - - - - - - - - - - - -
-\image html ./apollonius-left_vertex.png -\image latex ./apollonius-left_vertex.png - -\image html ./apollonius-right_vertex.png -\image latex ./apollonius-right_vertex.png -
-\image html ./apollonius-no_conflict.png -\image latex ./apollonius-no_conflict.png - -\image html ./apollonius-entire_edge.png -\image latex ./apollonius-entire_edge.png -
-\image html ./apollonius-interior.png -\image latex ./apollonius-interior.png - -\image html ./apollonius-both_vertices.png -\image latex ./apollonius-both_vertices.png -
-
-\cgalFigureCaptionBegin{figag2edgeconflict} -The 6 possible outcomes of the -`Finite_edge_interior_conflict_2` predicate. Top left: only a -neighborhood around the left-most endpoint of the edge will be -destroyed. Top right: only a neighborhood around the right-most -endpoint of the edge will be destroyed. Middle left: no portion of the -edge is destroyed. Middle right: the entire edge will be -destroyed. Bottom left: a neighborhood in the interior of the edge -will be destroyed; the regions near the endpoints remain -unaffected. Bottom right: The neighborhood around the two endpoints -will be destroyed, but an interval in the interior of the edge will -remain in the new diagram. -\cgalFigureCaptionEnd - -The last predicate that we want to discuss is called -`Is_degenerate_edge_2`. It tells us whether an edge in the -Apollonius diagram is degenerate, that is if its two endpoints -coincide. In the Apollonius graph such an edge corresponds to one of -the additional edges that we use to triangulate the non-triangular -faces. - -The aforementioned predicates are part of the -`ApolloniusGraphTraits_2` concept of \cgal. \cgal also provides -a model for this concept, the -`Apollonius_graph_traits_2` class. The first -template parameter of this class must be a model of the `Kernel` -concept. The second template parameter is a tag that indicates what -operations are allowed in the computations that take place within the -traits class. -The two possible values of the `Method_tag` parameter are -`Integral_domain_without_division_tag` and `Field_with_sqrt_tag`. When -`Integral_domain_without_division_tag` is used, only ring operations are used during the -evaluation of the predicates, whereas if `Field_with_sqrt_tag` is -chosen, all four field operations, as well as square roots, are used -during the predicate evaluation. - -The `Apollonius_graph_traits_2` class provides exact -predicates if the number type in the kernel `K` is an exact number -type. This is to be associated with the type of operations allowed for -the predicate evaluation. For example `MP_Float` as number -type, with `Integral_domain_without_division_tag` as tag will give exact predicates, -whereas `MP_Float` with `Field_with_sqrt_tag` will give -inexact predicates. - -Although exact number types provide exact predicates and constructions, -their use often results in unacceptably large runtimes. -The class `Apollonius_graph_filtered_traits_2` -aims to paliate this shortcoming. Similar to a filtered kernel, it takes a -constructions kernel `CK`, a filtering kernel `FK` and an -exact kernel `EK`, as well as the corresponding tags -(`CM`, `FM` and `EM`, respectively). -Predicates are evaluated by first using the filtering kernel, and -if this fails the evaluation is performed using the exact kernel, -thus yielding exact predicates at a generally much cheaper cost -than directly using an exact number type. The constructions -are done using the kernel `CK`, which means that -they are not necessarily exact. All template parameters except -`CK` have default values, which are explained in the reference -manual. - -\section secapollonius2hierarchy The Apollonius Graph Hierarchy - -The `Apollonius_graph_hierarchy_2` class is nothing but the equivalent of the `Triangulation_hierarchy_2` -class, applied to the Apollonius graph. It consists of a series of -Apollonius graphs constructed in a manner analogous to the Delaunay -hierarchy by Devillers \cgalCite{d-iirdt-98}. The class -`Apollonius_graph_hierarchy_2` -has exactly the same interface and functionality as the -`Apollonius_graph_2` -class. Using the Apollonius graph hierarchy involves an additional -cost in space and time for maintaining the hierarchy. Our experiments -have shown that it usually pays off to use the hierarchy for inputs -consisting of more than 1,000 circles. This threshold holds for both -the construction of the Apollonius diagram itself, as well as for -nearest neighbor queries. - -\section secapollonius2examples Examples - -\subsection Apollonius_graph_2FirstExample First Example - -\cgalExample{Apollonius_graph_2/ag2_exact_traits.cpp} - -\subsection Apollonius_graph_2SecondExample Second Example - -\cgalExample{Apollonius_graph_2/ag2_exact_traits_sqrt.cpp} - -\subsection Apollonius_graph_2ThirdExample Third Example - -\cgalExample{Apollonius_graph_2/ag2_filtered_traits_no_hidden.cpp} - -\subsection Apollonius_graph_2FourthExample Fourth Example - -\cgalExample{Apollonius_graph_2/ag2_hierarchy.cpp} - -*/ -} /* namespace CGAL */ - diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_2.h deleted file mode 100644 index fb82e23c709..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_2.h +++ /dev/null @@ -1,743 +0,0 @@ - -namespace CGAL { - -/*! -\ingroup PkgApolloniusGraph2Ref - -The class `Apollonius_graph_2` represents the Apollonius graph. -It supports insertions and deletions of sites. - -\tparam Gt is the geometric traits class and must be a model of `ApolloniusGraphTraits_2`. - -\tparam Agds is the Apollonius graph data structure and must be a model of `ApolloniusGraphDataStructure_2` -whose vertex and face must be models of `ApolloniusGraphVertexBase_2` and `TriangulationFaceBase_2`, -respectively. -It defaults to: -\code - CGAL::Triangulation_data_structure_2< - CGAL::Apollonius_graph_vertex_base_2, - CGAL::Triangulation_face_base_2 >` -\endcode - -\cgalHeading{Traversal of the Apollonius Graph} - -An Apollonius graph can be seen as a container of faces and vertices. -Therefore the Apollonius graph provides several iterators and -circulators that allow to traverse it (completely or partially). - -\cgalHeading{Traversal of the Convex Hull} - -Applied on the `infinite_vertex` the `incident_*` functions allow to -visit the vertices on the convex hull and the infinite edges and -faces. Note that a counterclockwise traversal of the vertices adjacent -to the `infinite_vertex` is a clockwise traversal of the convex hull. - -\code{.cpp} -CGAL::Apollonius_graph_2 ag; -CGAL::Apollonius_graph_2::Face f; - -ag.incident_vertices(ag.infinite_vertex()); -ag.incident_vertices(ag.infinite_vertex(), f); - -ag.incident_faces(ag.infinite_vertex()); -ag.incident_faces(ag.infinite_vertex(), f); - -ag.incident_edges(ag.infinite_vertex()); -ag.incident_edges(ag.infinite_vertex(), f); -\endcode - -\cgalModels `DelaunayGraph_2` - -\sa `CGAL::Apollonius_graph_traits_2` -\sa `CGAL::Apollonius_graph_filtered_traits_2` -\sa `CGAL::Apollonius_graph_hierarchy_2` -*/ -template< typename Gt, typename Agds > -class Apollonius_graph_2 { -public: - -/// \name Types -/// @{ - -/*! -A type for the underlying -data structure. -*/ -typedef Agds Data_structure; - -/*! -Same as the `Data_structure` type. This type has been introduced -in order for the `Apollonius_graph_2` class to be a -model of the `DelaunayGraph_2` concept. -*/ -typedef Data_structure Triangulation_data_structure; - -/*! -A type for the geometric traits. -*/ -typedef Gt Geom_traits; - -/*! -A type for the -point defined in the geometric traits. -*/ -typedef Gt::Point_2 Point_2; - -/*! -A type for the Apollonius site, defined in the geometric traits. -*/ -typedef Gt::Site_2 Site_2; - -/// @} - -/// \name Handles And Iterators -/// The vertices and faces of the Apollonius graph are accessed -/// through `handles`, `iterators`, and `circulators`. The iterators -/// and circulators are all bidirectional and non-mutable. The -/// circulators and iterators are assignable to the corresponding -/// handle types, and they are also convertible to the corresponding -/// handles. The edges of the Apollonius graph can also be visited -/// through iterators and circulators, the edge circulators and -/// iterators are also bidirectional and non-mutable. In the -/// following, we call infinite any face or edge incident to -/// the infinite vertex and the infinite vertex itself. Any other -/// feature (face, edge or vertex) of the Apollonius graph is said to -/// be finite. Some iterators (the `All` iterators ) allow to -/// visit finite or infinite features while the others (the `Finite` -/// iterators) visit only finite features. Circulators visit both -/// infinite and finite features. -/// @{ - -/*! -the edge type. -The `Edge(f,i)` is the edge common to faces `f` and -`f.neighbor(i)`. It is also the edge joining the vertices -`vertex(cw(i))` and `vertex(ccw(i))` of `f`. -\pre `i` must be `0`, `1` or `2`. -*/ -typedef Data_structure::Edge Edge; - -/*! -A type for a vertex. -*/ -typedef Data_structure::Vertex Vertex; - -/*! -A type for a face. -*/ -typedef Data_structure::Face Face; - -/*! -A type for a handle to a vertex. -*/ -typedef Data_structure::Vertex_handle Vertex_handle; - -/*! -A type for a handle to a face. -*/ -typedef Data_structure::Face_handle Face_handle; - -/*! -A type for a circulator over vertices incident to a given vertex. -*/ -typedef Data_structure::Vertex_circulator Vertex_circulator; - -/*! -A type for a circulator over faces incident to a given vertex. -*/ -typedef Data_structure::Face_circulator Face_circulator; - -/*! -A type for a circulator over edges incident to a given vertex. -*/ -typedef Data_structure::Edge_circulator Edge_circulator; - -/*! -A type for an iterator over all vertices. -*/ -typedef Data_structure::Vertex_iterator -All_vertices_iterator; - -/*! -A type for an iterator over all faces. -*/ -typedef Data_structure::Face_iterator -All_faces_iterator; - -/*! -A type for an iterator over all edges. -*/ -typedef Data_structure::Edge_iterator -All_edges_iterator; - -/*! -An unsigned integral type. -*/ -typedef Data_structure::size_type size_type; - -/*! -A type for an iterator over finite vertices. -*/ -typedef unspecified_type Finite_vertices_iterator; - -/*! -A type for an iterator over finite faces. -*/ -typedef unspecified_type Finite_faces_iterator; - -/*! -A type for an iterator over finite edges. -*/ -typedef unspecified_type Finite_edges_iterator; - -/// @} - -/// \name Site Iterators -/// In addition to iterators and circulators for vertices and faces, -/// iterators for sites are provided. In particular there are -/// iterators for the entire set of sites, the hidden sites and the -/// visible sites of the Apollonius graph. -/// @{ - -/*! -A type for an iterator over all sites. -*/ -typedef unspecified_type Sites_iterator; - -/*! -A type for an iterator over all visible sites. -*/ -typedef unspecified_type Visible_sites_iterator; - -/*! -A type for an iterator over all hidden sites. -*/ -typedef unspecified_type Hidden_sites_iterator; - -/// @} - -/// \name Creation -/// @{ - -/*! -Creates an -Apollonius graph `ag` using `gt` as geometric traits. -*/ -Apollonius_graph_2(Gt gt=Gt()); - -/*! -Creates an Apollonius graph `ag` using `gt` as -geometric traits and inserts all sites in the range -[`first`, `beyond`). -\pre `Input_iterator` must be a model of `InputIterator`. The value type of `Input_iterator` must be `Site_2`. -*/ -template< class Input_iterator > -Apollonius_graph_2(Input_iterator first, Input_iterator beyond, -Gt gt=Gt()); - -/*! -Copy constructor. All faces and vertices are duplicated. After the -construction, -`ag` and `other` refer to two different Apollonius graphs : if -`other` is modified, `ag` is not. -*/ -Apollonius_graph_2(const Apollonius_graph_2& other); - -/*! -Assignment. If `ag` and `other` are the same object -nothing is done. Otherwise, all the vertices and faces are -duplicated. After the assignment, `ag` and `other` refer to -different Apollonius graphs : if `other` is modified, `ag` is -not. -*/ -Apollonius_graph_2 -operator=(const Apollonius_graph_2& other); - -/// @} - -/// \name Access Functions -/// @{ - -/*! -Returns a reference to the Apollonius graph traits object. -*/ -const Geom_traits& geom_traits() const; - -/*! -Returns a reference to the -underlying data structure. -*/ -const Data_structure& data_structure() const; - -/*! -Same as `data_structure()`. This -method has been added in compliance with the `DelaunayGraph_2` -concept. -*/ -const Data_structure& tds() const; - -/*! -Returns the dimension of the Apollonius graph. -*/ -int dimension() const; - -/*! -Returns the number of finite vertices. -*/ -size_type number_of_vertices() const; - -/*! -Returns the number of visible sites. -*/ -size_type number_of_visible_sites() const; - -/*! -Returns the number of hidden sites. -*/ -size_type number_of_hidden_sites() const; - -/*! -Returns the number of faces (both finite and infinite) of the -Apollonius graph. -*/ -size_type number_of_faces() const; - -/*! -Returns a face incident to the `infinite_vertex`. -*/ -Face_handle infinite_face() const; - -/*! -Returns the `infinite_vertex`. -*/ -Vertex_handle infinite_vertex() const; - -/*! -Returns a vertex distinct from the `infinite_vertex`. -\pre The number of (visible) vertices in the Apollonius graph must be at least one. -*/ -Vertex_handle finite_vertex() const; - -/// @} - -/// \name Face, Edge and Vertex Iterators -/// The following iterators allow respectively to visit finite faces, -/// finite edges and finite vertices of the Apollonius graph. These -/// iterators are non-mutable, bidirectional and their value types are -/// respectively `Face`, `Edge` and `Vertex`. They are all invalidated -/// by any change in the Apollonius graph. The following iterators -/// allow respectively to visit all (both finite and infinite) faces, -/// edges and vertices of the Apollonius graph. These iterators are -/// non-mutable, bidirectional and their value types are respectively -/// `Face`, `Edge` and `Vertex`. They are all invalidated by any -/// change in the Apollonius graph. -/// @{ - -/*! -Starts at an arbitrary finite vertex. -*/ -Finite_vertices_iterator finite_vertices_begin() const; - -/*! -Past-the-end iterator. -*/ -Finite_vertices_iterator finite_vertices_end() const; - -/*! -Starts at an arbitrary finite edge. -*/ -Finite_edges_iterator finite_edges_begin() const; - -/*! -Past-the-end iterator. -*/ -Finite_edges_iterator finite_edges_end() const; - -/*! -Starts at an arbitrary finite face. -*/ -Finite_faces_iterator finite_faces_begin() const; - -/*! -Past-the-end iterator. -*/ -Finite_faces_iterator finite_faces_end() const; - -/*! -Starts at an arbitrary vertex. -*/ -All_vertices_iterator all_vertices_begin() const; - -/*! -Past-the-end iterator. -*/ -All_vertices_iterator all_vertices_end() const; - -/*! -Starts at an arbitrary edge. -*/ -All_edges_iterator all_edges_begin() const; - -/*! -Past-the-end iterator. -*/ -All_edges_iterator all_edges_end() const; - -/*! -Starts at an arbitrary face. -*/ -All_faces_iterator all_faces_begin() const; - -/*! -Past-the-end iterator. -*/ -All_faces_iterator all_faces_end() const; - -/// @} - -/// \name Site Iterators -/// The following iterators allow respectively to visit all sites, the -/// visible sites and the hidden sites. These iterators are -/// non-mutable, bidirectional and their value type is `Site_2`. They -/// are all invalidated by any change in the Apollonius graph. -/// @{ - -/*! -Starts at an arbitrary site. -*/ -Sites_iterator sites_begin() const; - -/*! -Past-the-end iterator. -*/ -Sites_iterator sites_end() const; - -/*! -Starts at an arbitrary visible site. -*/ -Visible_sites_iterator visible_sites_begin() const; - -/*! -Past-the-end iterator. -*/ -Visible_sites_iterator visible_sites_end() const; - -/*! -Starts at an arbitrary hidden site. -*/ -Hidden_sites_iterator hidden_sites_begin() const; - -/*! -Past-the-end iterator. -*/ -Hidden_sites_iterator hidden_sites_end() const; - -/// @} - -/// \name Face, Edge and Vertex Circulators -/// The Apollonius graph also provides circulators that allow to visit -/// respectively all faces or edges incident to a given vertex or all -/// vertices adjacent to a given vertex. These circulators are -/// non-mutable and bidirectional. The operator `operator++` moves the -/// circulator counterclockwise around the vertex while the -/// `operator--` moves clockwise. A face circulator is invalidated by -/// any modification of the face pointed to. An edge circulator is -/// invalidated by any modification in one of the two faces incident -/// to the edge pointed to. A vertex circulator is invalidated by any -/// modification in any of the faces adjacent to the vertex pointed -/// to. -/// @{ - -/*! -Starts at an arbitrary face incident -to `v`. -*/ -Face_circulator incident_faces(Vertex_handle v) const; - -/*! -Starts at face `f`. -\pre Face `f` is incident to vertex `v`. -*/ -Face_circulator incident_faces(Vertex_handle v, Face_handle f) const; - -/*! -Starts at an arbitrary edge incident -to `v`. -*/ -Edge_circulator incident_edges(Vertex_handle v) const; - -/*! -Starts at the first edge of `f` incident to -`v`, in counterclockwise order around `v`. -\pre Face `f` is incident to vertex `v`. -*/ -Edge_circulator incident_edges(Vertex_handle v, Face_handle f) const; - -/*! -Starts at an arbitrary vertex incident -to `v`. -*/ -Vertex_circulator incident_vertices(Vertex_handle v) const; - -/*! -Starts at the first vertex of `f` adjacent to `v` -in counterclockwise order around `v`. -\pre Face `f` is incident to vertex `v`. -*/ -Vertex_circulator incident_vertices(Vertex_handle v, Face_handle f) const; - -/// @} - -/// \name Predicates -/// The class `Apollonius_graph_2` provides methods to test the finite -/// or infinite character of any feature. -/// @{ - -/*! -`true`, iff `v` is the `infinite_vertex`. -*/ -bool -is_infinite(Vertex_handle v) const; - -/*! -`true`, iff face `f` is infinite. -*/ -bool -is_infinite(Face_handle f) const; - -/*! -`true`, iff edge `(f,i)` is infinite. -*/ -bool is_infinite(Face_handle f, int i) const; - -/*! -`true`, iff edge `e` is infinite. -*/ -bool -is_infinite(const Edge& e) const; - -/*! -`true`, iff edge `*ec` is infinite. -*/ -bool -is_infinite(Edge_circulator ec) const; - -/// @} - -/// \name Insertion -/// @{ - -/*! -Inserts the sites in the range -[`first`,`beyond`). The number of sites in the range -[`first`, `beyond`) is returned. -\pre `Input_iterator` must be a model of `InputIterator` and its value type must be `Site_2`. -*/ -template< class Input_iterator > -unsigned int insert(Input_iterator first, Input_iterator beyond); - -/*! -Inserts the -site `s` in the Apollonius graph. If `s` is visible then the -vertex handle of `s` is returned, otherwise -`Vertex_handle(nullptr)` is returned. -*/ -Vertex_handle insert(const Site_2& s); - -/*! -Inserts `s` in the Apollonius graph using the site -associated with `vnear` as an estimate for the nearest neighbor of -the center of `s`. If `s` is visible then the vertex handle of -`s` is returned, otherwise `Vertex_handle(nullptr)` is -returned. -*/ -Vertex_handle insert(const Site_2& s, Vertex_handle vnear); - -/// @} - -/// \name Removal -/// @{ - -/*! -Removes the site -associated to the vertex handle `v` from the Apollonius -graph. -\pre `v` must correspond to a valid finite vertex of the Apollonius graph. -*/ -void remove(Vertex_handle v); - -/// @} - -/// \name Nearest Neighbor Location -/// @{ - -/*! -Finds the nearest neighbor of the point `p`. In other words it -finds the site whose Apollonius cell contains `p`. Ties are broken -arbitrarily and one of the nearest neighbors of `p` is -returned. If there are no visible sites in the Apollonius diagram -`Vertex_handle(nullptr)` is returned. -*/ -Vertex_handle nearest_neighbor(const Point_2& p) const; - -/*! -Finds the nearest neighbor of the point -`p` using the site associated with `vnear` as an -estimate for the nearest neighbor of `p`. Ties are broken -arbitrarily and one of the nearest neighbors of `p` is -returned. If there are no visible sites in the Apollonius diagram -`Vertex_handle(nullptr)` is returned. -*/ -Vertex_handle nearest_neighbor(const Point_2& p, Vertex_handle vnear) const; - -/// @} - -/// \name Access to the Dual -/// The `Apollonius_graph_2` class provides access to the duals of the -/// faces of the graph. The dual of a face of the Apollonius graph is -/// a site. If the originating face is infinite, its dual is a site -/// with center at infinity (or equivalently with infinite weight), -/// which means that it can be represented geometrically as a line. If -/// the originating face is finite, its dual is a site with finite -/// center and weight. In the following three methods the returned -/// object is assignable to either `Site_2` or `Gt::Line_2`, depending -/// on whether the corresponding face of the Apollonius graph is -/// finite or infinite, respectively. -/// @{ - -/*! -Returns the -dual corresponding to the face handle `f`. The returned object can -be assignable to one of the following: `Site_2`, `Gt::Line_2`. -*/ -Gt::Object_2 dual(Face_handle f) const; - -/*! -Returns the -dual of the face to which `it` points to. The returned object can -be assignable to one of the following: `Site_2`, `Gt::Line_2`. -*/ -Gt::Object_2 dual(All_faces_iterator it) const; - -/*! -Returns -the dual of the face to which `it` points to. The returned -object can be assignable to one of the following: `Site_2`, -`Gt::Line_2`. -*/ -Gt::Object_2 dual(Finite_faces_iterator it) const; - -/// @} - -/// \name I/O -/// @{ - -/*! -Draws the Apollonius graph to -the stream `str`. -\pre The following operators must be defined: -`Stream& operator<<(Stream&, Gt::Segment_2)`, -`Stream& operator<<(Stream&, Gt::Ray_2)`. - -*/ -template< class Stream > -Stream& draw_primal(Stream& str) const; - -/*! -Draws the dual of the -Apollonius graph, i.e., the Apollonius diagram, to the stream -`str`. -\pre The following operators must be defined: -`Stream& operator<<(Stream&, Gt::Segment_2)`, -`Stream& operator<<(Stream&, Gt::Ray_2)`, -`Stream& operator<<(Stream&, Gt::Line_2)`. - -*/ -template < class Stream > -Stream& draw_dual(Stream& str) const; - -/*! -Draws the edge -`e` of the Apollonius graph to the stream `str`. -\pre The following operators must be defined: -`Stream& operator<<(Stream&, Gt::Segment_2)`, -`Stream& operator<<(Stream&, Gt::Ray_2)`. - -*/ -template< class Stream > -Stream& draw_primal_edge(const Edge& e, Stream& str) const; - -/*! -Draws the dual of the -edge `e` to the stream `str`. The dual of `e` is an edge -of the Apollonius diagram. -\pre The following operators must be defined: -`Stream& operator<<(Stream&, Gt::Segment_2)`, -`Stream& operator<<(Stream&, Gt::Ray_2)`, -`Stream& operator<<(Stream&, Gt::Line_2)`. - -*/ -template< class Stream > -Stream& draw_dual_edge(const Edge& e, Stream& str) const; - -/*! -Writes the current -state of the Apollonius graph to an output stream. In particular, -all visible and hidden sites are written as well as the -underlying combinatorial data structure. -*/ -void file_output(std::ostream& os) const; - -/*! -Reads the state of the -Apollonius graph from an input stream. -*/ -void file_input(std::istream& is); - -/*! -Writes the current state of the Apollonius graph to an output stream. -*/ -std::ostream& operator<<(std::ostream& os, const Apollonius_graph_2& ag) const; - -/*! -Reads the state of the Apollonius graph from an input stream. -*/ -std::istream& operator>>(std::istream& is, const Apollonius_graph_2& ag); - -/// @} - -/// \name Validity Check -/// @{ - -/*! -Checks the validity of the Apollonius graph. If `verbose` is -`true` a short message is sent to `std::cerr`. If `level` -is 0, only the data structure is validated. If `level` is 1, then -both the data structure and the Apollonius graph are -validated. Negative values of `level` always return true, and -values greater than 1 are equivalent to `level` being 1. -*/ -bool is_valid(bool verbose = false, int level = 1) const; - -/// @} - -/// \name Miscellaneous -/// @{ - -/*! -Clears all contents of the Apollonius graph. -*/ -void clear(); - -/*! -The Apollonius graphs -`other` and `ag` are swapped. `ag.swap(other)` should -be preferred to `ag = other` or to `ag(other)` if -`other` is deleted afterwards. -*/ -void swap(Apollonius_graph_2& other); - -/// @} - -}; /* end Apollonius_graph_2 */ -} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_filtered_traits_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_filtered_traits_2.h deleted file mode 100644 index 155a7b240cb..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_filtered_traits_2.h +++ /dev/null @@ -1,78 +0,0 @@ - -namespace CGAL { - -/*! -\ingroup PkgApolloniusGraph2Ref - -The class `Apollonius_graph_filtered_traits_2` provides a model for the -`ApolloniusGraphTraits_2` concept. - -The class `Apollonius_graph_filtered_traits_2` uses the filtering technique \cgalCite{cgal:bbp-iayed-01} -to achieve traits for the `Apollonius_graph_2` class -with efficient and exact predicates given an exact -kernel `EK` and a filtering kernel `FK`. The geometric -constructions associated provided by this class are equivalent -to those provided by the traits class -`Apollonius_graph_traits_2`, which means that they may -be inexact. - -This class has six template parameters. The first, third and fifth -template parameters must be a models of the `Kernel` concept. The -second, fourth and sixth template parameters correspond to how -predicates are evaluated. There are two predefined possible values for -`Method_tag`, namely `CGAL::Field_with_sqrt_tag` and -`CGAL::Integral_domain_without_division_tag`. The first one must be used when the number type -used in the representation supports the exact evaluation of signs of -expressions involving all four basic operations and square roots, -whereas the second one requires the exact evaluation of signs of -ring-type expressions, i.e., expressions involving only additions, -subtractions and multiplications. -The way the predicates are evaluated is discussed in -\cgalCite{cgal:ke-ppawv-02}, \cgalCite{cgal:ke-rctac-03}. - -The default values for the template parameters are as follows: -`CM = CGAL::Integral_domain_without_division_tag`, -`EK = CGAL::Simple_cartesian`, -`EM = CM`, -`FK = CGAL::Simple_cartesian >`, -`FM = CM`. - -\cgalModels `ApolloniusGraphTraits_2` - -\sa `Kernel` -\sa `ApolloniusGraphTraits_2` -\sa `CGAL::Integral_domain_without_division_tag` -\sa `CGAL::Field_with_sqrt_tag` -\sa `CGAL::Apollonius_graph_2` -\sa `CGAL::Apollonius_graph_traits_2` - -*/ -template< typename CK, typename CM, typename EK, typename EM, typename FK, typename FM > -class Apollonius_graph_filtered_traits_2 { -public: - -/// \name Creation -/// @{ - -/*! -%Default constructor. -*/ -Apollonius_graph_filtered_traits_2(); - -/*! -Copy -constructor. -*/ -Apollonius_graph_filtered_traits_2 -(Apollonius_graph_filtered_traits_2 other); - -/*! -Assignment -operator. -*/ -Apollonius_graph_filtered_traits_2 operator=(other); - -/// @} - -}; /* end Apollonius_graph_filtered_traits_2 */ -} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_2.h deleted file mode 100644 index 778dd9160e1..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_2.h +++ /dev/null @@ -1,231 +0,0 @@ - -namespace CGAL { - -/*! -\ingroup PkgApolloniusGraph2Ref - -We provide an alternative to the class -`Apollonius_graph_2` for the dynamic -construction of the Apollonius graph. The `Apollonius_graph_hierarchy_2` class maintains -a hierarchy of Apollonius graphs. The bottom-most level of the -hierarchy contains the full Apollonius diagram. A site that -is in level \f$ i\f$, is in level \f$ i+1\f$ with probability \f$ 1/\alpha\f$ -where \f$ \alpha > 1\f$ is some constant. The difference between the -`Apollonius_graph_2` class and the -`Apollonius_graph_hierarchy_2` is on how the nearest neighbor location is done. Given a -point \f$ p\f$ the location is done as follows: at the top most level we -find the nearest neighbor of \f$ p\f$ as in the -`Apollonius_graph_2` class. At every subsequent level \f$ i\f$ -we use the nearest neighbor found at level \f$ i+1\f$ to find the nearest -neighbor at level \f$ i\f$. This is a variant of the corresponding -hierarchy for points found in \cgalCite{d-iirdt-98}. - -The class has two template parameters which have essentially the same -meaning as in the `Apollonius_graph_2` class. - -\tparam Gt is the geometric traits class and must be a model of `ApolloniusGraphTraits_2`. - -\tparam Agds is the Apollonius graph data structure and must be a model of `ApolloniusGraphDataStructure_2` -whose vertex and face must be models of `ApolloniusGraphHierarchyVertexBase_2` and `TriangulationFaceBase_2`, respectively. -It defaults to: -\code - CGAL::Triangulation_data_structure_2< - CGAL::Apollonius_graph_hierarchy_vertex_base_2 >, - CGAL::Triangulation_face_base_2 > -\endcode - -\cgalHeading{Heritage} - -The `Apollonius_graph_hierarchy_2` class derives publicly from the -`Apollonius_graph_2` class. The interface is -the same with its base class. In the sequel only the methods -overridden are documented. - -`Apollonius_graph_hierarchy_2` does not introduce other types than those introduced by -its base class `Apollonius_graph_2`. - -\sa `CGAL::Apollonius_graph_2` -\sa `CGAL::Apollonius_graph_traits_2` -\sa `CGAL::Apollonius_graph_filtered_traits_2` -*/ -template< typename Gt, typename Agds > -class Apollonius_graph_hierarchy_2 : public CGAL::Apollonius_graph_2 { -public: - -/// \name Creation -/// @{ - -/*! -Creates an hierarchy of Apollonius graphs using `gt` as -geometric traits. -*/ -Apollonius_graph_hierarchy_2(Gt gt=Gt()); - -/*! -Creates an Apollonius graph hierarchy using -`gt` as geometric traits and inserts all sites in the -range [`first`, `beyond`). -*/ -template< class Input_iterator > -Apollonius_graph_hierarchy_2(Input_iterator first, Input_iterator beyond, Gt gt=Gt()); - -/*! -Copy constructor. All faces, vertices, and inter-level pointers -are duplicated. After the construction, `agh` and `other` refer -to two different Apollonius graph hierarchies: if -`other` is modified, `agh` is not. -*/ -Apollonius_graph_hierarchy_2(const Apollonius_graph_hierarchy_2& other); - -/*! -Assignment. All faces, vertices and inter-level pointers -are duplicated. After the construction, `agh` and `other` refer -to two different Apollonius graph hierarchies: if -`other` is modified, `agh` is not. -*/ -Apollonius_graph_hierarchy_2 -operator=(Apollonius_graph_hierarchy_2 -other); - -/// @} - -/// \name Insertion -/// @{ - -/*! -Inserts the sites in the range -[`first`,`beyond`). The number of sites in the range -[`first`, `beyond`) is returned. -\pre `Input_iterator` must be a model of `InputIterator` and its value type must be `Site_2`. -*/ -template< class Input_iterator > -unsigned int insert(Input_iterator first, Input_iterator beyond); - -/*! -Inserts the -site `s` in the Apollonius graph hierarchy. If `s` -is visible then the vertex handle of `s` is returned, otherwise -`Vertex_handle(nullptr)` is returned. -*/ -Vertex_handle insert(const Site_2& s); - -/*! -Inserts `s` in the Apollonius graph hierarchy using the -site associated with `vnear` as -an estimate for the nearest neighbor of the center of `s`. -If `s` is visible then the vertex handle of `s` is -returned, otherwise `Vertex_handle(nullptr)` is returned. -A call to this method is equivalent to `agh.insert(s);` and it has -been added for the sake of conformity with the interface of the -`Apollonius_graph_2` class. -*/ -Vertex_handle insert(const Site_2& s, Vertex_handle vnear); - -/// @} - -/// \name Removal -/// @{ - -/*! -Removes the site -associated to the vertex handle `v` from the Apollonius -graph hierarchy. -\pre `v` must correspond to a valid finite vertex of the Apollonius graph hierarchy. -*/ -void remove(Vertex_handle v); - -/// @} - -/// \name Nearest Neighbor Location -/// @{ - -/*! -Finds the nearest neighbor of the point `p`. In other words it -finds the site whose Apollonius cell contains `p`. Ties are broken -arbitrarily and one of the nearest neighbors of `p` is -returned. If there are no visible sites in the Apollonius diagram -`Vertex_handle(nullptr)` is returned. -*/ -Vertex_handle nearest_neighbor(const Point_2& p) const; - -/*! -Finds the nearest neighbor of the point -`p`. If there are no visible sites in the Apollonius diagram -`Vertex_handle(nullptr)` is returned. -A call to this method is equivalent to -`agh.nearest_neighbor(p);` and it has been added for the sake of -conformity with the interface of the -`Apollonius_graph_2` class. -*/ -Vertex_handle nearest_neighbor(const Point_2& p, Vertex_handle vnear) const; - -/// @} - -/// \name I/O -/// @{ - -/*! -Writes the current -state of the Apollonius graph hierarchy to an output stream. In particular, -all visible and hidden sites are written as well as the -underlying combinatorial hierarchical data structure. -*/ -void file_output(std::ostream& os) const; - -/*! -Reads the state of the -Apollonius graph hierarchy from an input stream. -*/ -void file_input(std::istream& is); - -/*! -Writes the current state of the Apollonius graph hierarchy to an -output stream. -*/ -std::ostream& operator<<(std::ostream& os, Apollonius_graph_hierarchy_2 agh) const; - -/*! -Reads the state of the Apollonius graph hierarchy from an input stream. -*/ -std::istream& operator>>(std::istream& is, Apollonius_graph_hierarchy_2 agh); - -/// @} - -/// \name Validity Check -/// @{ - -/*! -Checks the validity of the Apollonius graph hierarchy. If -`verbose` is `true` a short message is sent to -`std::cerr`. If `level` is 0, the data structure at all levels -is validated, as well as the inter-level pointers. If `level` is -1, then the data structure at all levels is validated, the inter-level -pointers are validated and all levels of the Apollonius graph -hierarchy are also validated. Negative values of `level` always -return `true`, and values greater than 1 are equivalent to -`level` being 1. -*/ -bool is_valid(bool verbose = false, int level = 1) const; - -/// @} - -/// \name Miscellaneous -/// @{ - -/*! -Clears all contents of the Apollonius graph -hierarchy. -*/ -void clear(); - -/*! -The Apollonius graph hierarchies `other` and `agh` are -swapped. `agh.swap(other)` should be preferred to `agh = other` -or to `agh(other)` if `other` is deleted afterwards. -*/ -void swap(Apollonius_graph_hierarchy_2& other); - -/// @} - -}; /* end Apollonius_graph_hierarchy_2 */ -} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_vertex_base_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_vertex_base_2.h deleted file mode 100644 index c09d6255ab5..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_vertex_base_2.h +++ /dev/null @@ -1,49 +0,0 @@ - -namespace CGAL { - -/*! -\ingroup PkgApolloniusGraph2Ref - -The class `Apollonius_graph_hierarchy_vertex_base_2` provides a model for the -`ApolloniusGraphHierarchyVertexBase_2` concept, which is the -vertex base required by the -`Apollonius_graph_hierarchy_2` class. The class -`Apollonius_graph_hierarchy_vertex_base_2` is templated by a class `Agvb` which must be a model -of the `ApolloniusGraphVertexBase_2` concept. - -\cgalModels `ApolloniusGraphHierarchyVertexBase_2` - -\sa `CGAL::Apollonius_graph_vertex_base_2` -\sa `CGAL::Triangulation_data_structure_2` -\sa `CGAL::Apollonius_graph_hierarchy_2` -*/ -template< typename Agvb > -class Apollonius_graph_hierarchy_vertex_base_2 : Agvb { -public: - -/// \name Creation -/// @{ - -/*! -%Default constructor. -*/ -Apollonius_graph_hierarchy_vertex_base_2(); - -/*! -Constructs a vertex associated with the site `s` and -embedded at the center of `s`. -*/ -Apollonius_graph_hierarchy_vertex_base_2(const Site_2& s); - -/*! -Constructs a vertex associated with -the site `s`, embedded at the center of `s`, -and pointing to the face associated with the face -handle `f`. -*/ -Apollonius_graph_hierarchy_vertex_base_2(const Site_2& s, Face_handle f); - -/// @} - -}; /* end Apollonius_graph_hierarchy_vertex_base_2 */ -} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_traits_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_traits_2.h deleted file mode 100644 index 3fe29ef740b..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_traits_2.h +++ /dev/null @@ -1,54 +0,0 @@ - -namespace CGAL { - -/*! -\ingroup PkgApolloniusGraph2Ref - -The class `Apollonius_graph_traits_2` provides a model for the -`ApolloniusGraphTraits_2` concept. -This class has two template parameters. The first template parameter -must be a model of the `Kernel` concept. The second template -parameter corresponds to how predicates are evaluated. There are two -predefined possible values for `Method_tag`, namely -`CGAL::Field_with_sqrt_tag` and `CGAL::Integral_domain_without_division_tag`. The first one -must be used when the number type used in the representation supports -the exact evaluation of signs of expressions involving all four basic -operations and square roots, whereas the second one requires the exact -evaluation of signs of ring-type expressions, i.e., expressions -involving only additions, subtractions and multiplications. The -default value for `Method_tag` is `CGAL::Integral_domain_without_division_tag`. -The way the predicates are evaluated is discussed in -\cgalCite{cgal:ke-ppawv-02}, \cgalCite{cgal:ke-rctac-03}. - -\cgalModels `ApolloniusGraphTraits_2` - -\sa `CGAL::Apollonius_graph_2` -\sa `CGAL::Apollonius_graph_filtered_traits_2` -*/ -template< typename K, typename Method_tag > -class Apollonius_graph_traits_2 { -public: - -/// \name Creation -/// @{ - -/*! -%Default constructor. -*/ -Apollonius_graph_traits_2(); - -/*! -Copy constructor. -*/ -Apollonius_graph_traits_2(const Apollonius_graph_traits_2& other); - -/*! -Assignment operator. -*/ -Apollonius_graph_traits_2 -operator=(const Apollonius_graph_traits_2& other); - -/// @} - -}; /* end Apollonius_graph_traits_2 */ -} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_vertex_base_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_vertex_base_2.h deleted file mode 100644 index ae9eca3dc6e..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_vertex_base_2.h +++ /dev/null @@ -1,54 +0,0 @@ - -namespace CGAL { - -/*! -\ingroup PkgApolloniusGraph2Ref - -The class `Apollonius_graph_vertex_base_2` provides a model for the -`ApolloniusGraphVertexBase_2` concept which is the vertex base -required by the `ApolloniusGraphDataStructure_2` concept. The -class `Apollonius_graph_vertex_base_2` has two template arguments, the first being the -geometric traits of the Apollonius graph and should be a model of the -concept `ApolloniusGraphTraits_2`. The second is a Boolean which -controls whether hidden sites are actually stored. Such a -control is important if the user is not interested in hidden sites -and/or if only insertions are made, in which case no hidden -site can become visible. If `StoreHidden` is set to -`true`, hidden sites are stored, otherwise they are -discarded. By default `StoreHidden` is set to `true`. - -\cgalModels `ApolloniusGraphVertexBase_2` - -\sa `CGAL::Triangulation_data_structure_2` -\sa `CGAL::Apollonius_graph_hierarchy_vertex_base_2` -*/ -template< typename Gt, typename StoreHidden > -class Apollonius_graph_vertex_base_2 { -public: - -/// \name Creation -/// @{ - -/*! -%Default constructor. -*/ -Apollonius_graph_vertex_base_2(); - -/*! -Constructs a vertex associated with the site `s` and -embedded at the center of `s`. -*/ -Apollonius_graph_vertex_base_2(const Site_2& s); - -/*! -Constructs a vertex associated with -the site `s`, embedded at the center of `s`, -and pointing to the face associated with the face -handle `f`. -*/ -Apollonius_graph_vertex_base_2(const Site_2& s, Face_handle f); - -/// @} - -}; /* end Apollonius_graph_vertex_base_2 */ -} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_site_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_site_2.h deleted file mode 100644 index 162a6e46259..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_site_2.h +++ /dev/null @@ -1,76 +0,0 @@ - -namespace CGAL { - -/*! -\ingroup PkgApolloniusGraph2Ref - -The class `Apollonius_site_2` is a model for the concept -`ApolloniusSite_2`. It is parametrized by a template parameter -`K` which must be a model of the `Kernel` concept. - -\cgalModels `ApolloniusSite_2` - -\cgalHeading{Types} - -The class `Apollonius_site_2` does not introduce any types in addition to the -concept `ApolloniusSite_2`. - -\cgalHeading{I/O} - -The I/O operators are defined for `iostream`. - -The information output in the `iostream` is: the point of the -Apollonius site and its weight. - -\sa `CGAL::Qt_widget` -\sa `CGAL::Apollonius_graph_traits_2` -\sa `CGAL::Apollonius_graph_filtered_traits_2` -*/ -template< typename K > -class Apollonius_site_2 { -public: - -/// \name Creation -/// @{ - -/*! - -*/ -Apollonius_site_2(Point_2 p=Point_2(), Weight w= Weight(0)); - -/*! -Copy constructor. -*/ -Apollonius_site_2(const Apollonius_site_2& other); - -/// @} - -}; /* end Apollonius_site_2 */ - -/*! -Inserts the -Apollonius site `s` into the stream `os`. -\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`. -\pre The insert operator must be defined for `Point_2` and `Weight`. -\relates Apollonius_site_2 -*/ -std::ostream& operator<<(std::ostream& os, const Apollonius_site_2& s) const; - -/*! -Reads an Apollonius site from the stream `is` and assigns it -to `s`. -\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`. -\pre The extract operator must be defined for `Point_2` and `Weight`. -\relates Apollonius_site_2 -*/ -std::istream& operator>>(std::istream& is, const Apollonius_site_2& s); - -/*! -Inserts the Apollonius site `s` into the `Qt_widget` stream `w`. -\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`. -\pre The insert operator must be defined for `K::Circle_2`. -\relates Apollonius_site_2 -*/ -Qt_widget& operator<<(Qt_widget& w, const Apollonius_site_2& s) const; - -} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphDataStructure_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphDataStructure_2.h deleted file mode 100644 index 8c3209da2e8..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphDataStructure_2.h +++ /dev/null @@ -1,68 +0,0 @@ - -/*! -\ingroup PkgApolloniusGraph2Concepts -\cgalConcept - -The concept `ApolloniusGraphDataStructure_2` refines the concept -`TriangulationDataStructure_2`. In addition -it provides two methods for the insertion and removal of a degree 2 -vertex in the data structure. The insertion method adds a new vertex -to the specified edge, thus creating two new edges. Moreover, it -creates two new faces that have the two newly created edges in -common (see figure below). The removal method performs the reverse -operation. - -\image html insert_degree_2.png -\image latex insert_degree_2.png - -
Insertion and removal of degree 2 vertices. Left to right: -The edge `(f,i)` is replaced by two edges by means of inserting a -vertex `v` on the edge. The faces \f$ f_1\f$ and \f$ f_2\f$ are -created. Right to left: the faces \f$ f_1\f$ and \f$ f_2\f$ are -destroyed. The vertex `v` is deleted and its two adjacent edges are -merged.
- -We only describe the additional requirements with respect to the -`TriangulationDataStructure_2` concept. - -\cgalRefines `TriangulationDataStructure_2` - -\cgalHasModel `CGAL::Triangulation_data_structure_2` - -\sa `TriangulationDataStructure_2` -\sa `ApolloniusGraphVertexBase_2` -\sa `TriangulationFaceBase_2` - -*/ - -class ApolloniusGraphDataStructure_2 { -public: - -/// \name Insertion -/// @{ - -/*! -inserts a degree two vertex and two faces adjacent to it that have two common edges. - -The edge defined by the face handle `f` and the integer `i` is duplicated. It returns a handle -to the vertex created. -*/ -Vertex_handle insert_degree_2(Face_handle f, int i); - -/// @} - -/// \name Removal -/// @{ - -/*! -Removes a degree 2 -vertex and the two faces adjacent to it. The two edges of the star of -`v` that are not incident to it are collapsed. -\pre The degree of `v` must be equal to 2. -*/ -void remove_degree_2(Vertex_handle v); - -/// @} - -}; /* end ApolloniusGraphDataStructure_2 */ - diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphHierarchyVertexBase_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphHierarchyVertexBase_2.h deleted file mode 100644 index 8145923b669..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphHierarchyVertexBase_2.h +++ /dev/null @@ -1,85 +0,0 @@ - -/*! -\ingroup PkgApolloniusGraph2Concepts -\cgalConcept - -The vertex of an Apollonius graph -included in an Apollonius graph hierarchy has to provide -some pointers to the corresponding vertices in the -graphs of the next and preceding levels. -Therefore, the concept `ApolloniusGraphHierarchyVertexBase_2` -refines the concept `ApolloniusGraphVertexBase_2`, by -adding two vertex handles to the corresponding vertices for the -next and previous level graphs. - -\cgalRefines `ApolloniusGraphVertexBase_2` - -\cgalHeading{Types} - -`ApolloniusGraphHierarchyVertexBase_2` does not introduce any -types in addition to those of `ApolloniusGraphVertexBase_2`. - -\cgalHasModel `CGAL::Apollonius_graph_hierarchy_vertex_base_2 >` - -\sa `ApolloniusGraphDataStructure_2` -\sa `CGAL::Apollonius_graph_hierarchy_2` -\sa `CGAL::Triangulation_data_structure_2` -*/ -class ApolloniusGraphHierarchyVertexBase_2 { -public: - -/// \name Creation -/// @{ - -/*! -%Default constructor. -*/ -ApolloniusGraphHierarchyVertexBase_2(); - -/*! -Constructs a vertex associated with the site `s` and -embedded at the center of `s`. -*/ -ApolloniusGraphHierarchyVertexBase_2(Site_2 s).; - -/*! -Constructs a vertex associated with -the site `s`, embedded at the center of `s`, -and pointing to face `f`. -*/ -ApolloniusGraphHierarchyVertexBase_2(Site_2 s, Face_handle f).; - -/// @} - -/// \name Operations -/// @{ - -/*! -Returns a handle to the corresponding -vertex of the next level Apollonius graph. If such a vertex does not -exist `Vertex_handle(nullptr)` is returned. -*/ -Vertex_handle up(); - -/*! -Returns a handle to the corresponding -vertex of the previous level Apollonius graph. -*/ -Vertex_handle down(); - -/*! -Sets the handle for the -vertex of the next level Apollonius graph. -*/ -void set_up(Vertex_handle u); - -/*! -Sets the handle for the -vertex of the previous level Apollonius graph; -*/ -void set_down(Vertex_handle d); - -/// @} - -}; /* end ApolloniusGraphHierarchyVertexBase_2 */ - diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphTraits_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphTraits_2.h deleted file mode 100644 index 5ef6ff44848..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphTraits_2.h +++ /dev/null @@ -1,397 +0,0 @@ - -/*! -\ingroup PkgApolloniusGraph2Concepts -\cgalConcept - -\cgalRefines `TriangulationTraits_2` - -The concept `ApolloniusGraphTraits_2` provides the traits -requirements for the `Apollonius_graph_2` class. In particular, -it provides a type `Site_2`, which must be a model of the concept -`ApolloniusSite_2`. It also provides -constructions for sites and several function object -types for the predicates. - -\cgalHasModel `CGAL::Apollonius_graph_traits_2` -\cgalHasModel `CGAL::Apollonius_graph_filtered_traits_2` - -\sa `CGAL::Apollonius_graph_2` -\sa `CGAL::Apollonius_graph_traits_2` -\sa `CGAL::Apollonius_graph_filtered_traits_2` - -*/ - -class ApolloniusGraphTraits_2 { -public: - -/// \name Types -/// @{ - -/*! -A type for a point. -*/ -typedef unspecified_type Point_2; - -/*! -A type for an Apollonius site. Must be a model -of the concept `ApolloniusSite_2`. -*/ -typedef unspecified_type Site_2; - -/*! -A type for a line. Only required if access to -the dual of the Apollonius graph is required or if the primal -or dual diagram are inserted in a stream. -*/ -typedef unspecified_type Line_2; - -/*! -A type for a ray. Only required if access to -the dual of the Apollonius graph is required or if the primal -or dual diagram are inserted in a stream. -*/ -typedef unspecified_type Ray_2; - -/*! -A type for a segment. Only required if access to -the dual of the Apollonius graph is required or if the primal -or dual diagram are inserted in a stream. -*/ -typedef unspecified_type Segment_2; - -/*! -A type representing different types of objects -in two dimensions, namely: `Point_2`, `Site_2`, -`Line_2`, `Ray_2` and `Segment_2`. -*/ -typedef unspecified_type Object_2; - -/*! -A type for the field number type of sites. -*/ -typedef unspecified_type FT; - -/*! -A type for the ring number type of sites. -*/ -typedef unspecified_type RT; - -/*! -Must provide `template bool operator() ( T& t, -Object_2 o)` which assigns `o` to `t` if `o` was -constructed from an object of type `T`. Returns -`true`, if the assignment was possible. -*/ -typedef unspecified_type Assign_2; - -/*! -Must provide `template -Object_2 operator()( T t)` that constructs an object of type -`Object_2` that contains `t` and returns it. -*/ -typedef unspecified_type Construct_object_2; - -/*! - -A constructor for a point of the Apollonius diagram equidistant -from three sites. Must provide -`Point_2 operator()(Site_2 s1, Site_2 s2, Site_2 s3)`, which -constructs a point equidistant from the sites `s1`, `s2` and -`s3`. - -*/ -typedef unspecified_type Construct_Apollonius_vertex_2; - -/*! -A constructor for -a dual Apollonius site (a site whose center is a -vertex of the Apollonius diagram and its weight is the common -distance of its center from the three defining sites). -Must provide `Site_2 operator()(Site_2 s1, -Site_2 s2, Site_2 s3)`, which constructs a -dual site whose center \f$ c\f$ is equidistant from `s1`, `s2` and -`s3`, and its weight is equal to the (signed) distance of \f$ c\f$ -from `s1` (or `s2` or `s3`). - -Must also provide `Line_2 operator()(Site_2 s1, Site_2 s2)`, which -constructs a line bitangent to `s1` and `s2`. This line is the -dual site of `s1`, `s2` and the site at infinity; it can be -viewed as a dual Apollonius site whose center is at infinity -and its weight is infinite. - -*/ -typedef unspecified_type Construct_Apollonius_site_2; - -/*! -A predicate object type. Must -provide `Comparison_result operator()(Site_2 s1, -Site_2 s2)`, which compares the \f$ x\f$-coordinates of the centers of -`s1` and `s2`. -*/ -typedef unspecified_type Compare_x_2; - -/*! -A predicate object type. Must -provide `Comparison_result operator()(Site_2 s1, -Site_2 s2)`, which compares the \f$ y\f$-coordinates of the centers of -`s1` and `s2`. -*/ -typedef unspecified_type Compare_y_2; - -/*! -A predicate object type. Must -provide `Comparison_result operator()(Site_2 s1, -Site_2 s2)`, which compares the weights of `s1` -and `s2`. -*/ -typedef unspecified_type Compare_weight_2; - -/*! -A predicate object type. Must -provide `Orientation operator()(Site_2 s1, -Site_2 s2, Site_2 s3)`, which performs the -usual orientation test for the centers of the three sites -`s1`, `s2` and `s3`. - -Must also provide `Orientation operator()(Site_2 s1, Site_2 s2, -Site_2 s3, Site_2 p1, Site_2 p2)`, -which performs the usual orientation test for the Apollonius vertex of -`s1`, `s2`, `s3` and the centers of `p1` and -`p2`. -\pre the Apollonius vertex of `s1`, `s2` and `s3` must exist. -*/ -typedef unspecified_type Orientation_2; - -/*! -A predicate object type. Must -provide `bool operator()(Site_2 s1, -Site_2 s2)`, which returns `true` if the circle -corresponding to `s2` is contained in the closure of the disk -corresponding to `s1`, `false` otherwise. -*/ -typedef unspecified_type Is_hidden_2; - -/*! -A predicate object type. -Must provide `Oriented_side operator()(Site_2 s1, -Site_2 s2, Point_2 p)`, which returns -the oriented side of the bisector of `s1` and `s2` that -contains `p`. Returns `ON_POSITIVE_SIDE` if `p` lies in -the half-space of `s1` (i.e., `p` is closer to `s1` than -`s2`); returns `ON_NEGATIVE_SIDE` if `p` lies in the -half-space of `s2`; returns `ON_ORIENTED_BOUNDARY` if `p` -lies on the bisector of `s1` and `s2`. -*/ -typedef unspecified_type Oriented_side_of_bisector_2; - -/*! -A predicate object type. -Must provide `Sign operator()(Site_2 s1, Site_2 -s2, Site_2 s3, Site_2 q)`, which -returns the sign of the distance of `q` from the dual Apollonius -site of `s1`, `s2`, `s3`. -\pre the dual Apollonius site of `s1`, `s2`, `s3` must exist. - -Must also provide `Sign operator()(Site_2 s1, -Site_2 s2, Site_2 q)`, which returns the sign of the distance of -`q` from the bitangent line of `s1`, `s2` (a degenerate -dual Apollonius site, with its center at infinity). -*/ -typedef unspecified_type Vertex_conflict_2; - -/*! -A predicate object type. -Must provide `bool operator()(Site_2 s1, Site_2 s2, Site_2 s3, Site_2 s4, Site_2 q, bool b)`. -The sites `s1`, `s2`, `s3` and `s4` define an Apollonius edge that lies on the -bisector of `s1` and `s2` and has as endpoints the Apollonius -vertices defined by the triplets `s1`, `s2`, `s3` and -`s1`, `s4` and `s2`. The Boolean `b` denotes if the -two Apollonius vertices are in conflict with the site -`q` (in which case `b` should be `true`, otherwise -`false`). In case that `b` is `true`, the predicate -returns `true` if and only if the entire Apollonius edge is in -conflict with `q`. If `b` is `false`, the predicate returns -`false` if and only if `q` is not in conflict with the -Apollonius edge. -\pre the Apollonius vertices of `s1`, `s2`, `s3`, and `s1`, `s4`, `s2` must exist. - -Must also provide `bool operator()(Site_2 s1, -Site_2 s2, Site_2 s3, Site_2 q, bool b)`. The -sites `s1`, `s2`, `s3` and the site at infinity -\f$ s_\infty\f$ define an Apollonius edge that lies on the bisector of -`s1` and `s2` and has as endpoints the Apollonius vertices -defined by the triplets `s1`, `s2`, `s3` and `s1`, -\f$ s_\infty\f$ and `s2` (the second Apollonius vertex is actually at -infinity). The Boolean `b` denotes if the two Apollonius vertices -are in conflict with the site `q` (in which case `b` -should be `true`, otherwise `false`). -In case that `b` is `true`, the predicate -returns `true` if and only if the entire Apollonius edge is in -conflict with `q`. If `b` is `false`, the predicate returns -`false` if and only if `q` is not in conflict with the -Apollonius edge. -\pre the Apollonius vertex of `s1`, `s2`, `s3` must exist. - -Must finally provide `bool operator()(Site_2 s1, -Site_2 s2, Site_2 q, bool b)`. The -sites `s1`, `s2` and the site at infinity -\f$ s_\infty\f$ define an Apollonius edge that lies on the bisector of -`s1` and `s2` and has as endpoints the Apollonius vertices -defined by the triplets `s1`, `s2`, \f$ s_\infty\f$ and `s1`, -\f$ s_\infty\f$ and `s2` (both Apollonius vertices are actually at -infinity). The Boolean `b` denotes if the two Apollonius vertices -are in conflict with the site `q` (in which case `b` -should be `true`, otherwise `false`). -In case that `b` is `true`, the predicate -returns `true` if and only if the entire Apollonius edge is in -conflict with `q`. If `b` is `false`, the predicate returns -`false` if and only if `q` is not in conflict with the -Apollonius edge. -*/ -typedef unspecified_type Finite_edge_interior_conflict_2; - -/*! -A predicate -object type. Must provide `bool operator()(Site_2 s1, -Site_2 s2, Site_2 s3, Site_2 q, bool b)`. The -sites \f$ s_\infty\f$, `s1`, `s2` and `s3` define an -Apollonius edge that lies on the bisector of \f$ s_\infty\f$ and `s1` -and has as endpoints the Apollonius vertices defined by the triplets -\f$ s_\infty\f$, `s1`, `s2` and \f$ s_\infty\f$, `s3` and -`s1`. The Boolean `b` denotes if the two Apollonius vertices -are in conflict with the site `q` (in which case `b` -should be `true`, otherwise `false`. -In case that `b` is `true`, the predicate -returns `true` if and only if the entire Apollonius edge is in -conflict with `q`. If `b` is `false`, the predicate returns -`false` if and only if `q` is not in conflict with the -Apollonius edge. -*/ -typedef unspecified_type Infinite_edge_interior_conflict_2; - -/*! -A predicate object type. -Must provide `bool operator()(Site_2 s1, Site_2 -s2, Site_2 s3, Site_2 s4)`. It returns `true` if -the Apollonius edge defined by `s1`, `s2`, `s3` and -`s4` is degenerate, `false` otherwise. An Apollonius edge is -called degenerate if its two endpoints coincide. -\pre the Apollonius vertices of `s1`, `s2`, `s3`, and `s1`, `s4`, `s2` must exist. -*/ -typedef unspecified_type Is_degenerate_edge_2; - -/// @} - -/// \name Creation -/// @{ - -/*! -Default constructor. -*/ -ApolloniusGraphTraits_2(); - -/*! -Copy constructor. -*/ -ApolloniusGraphTraits_2(ApolloniusGraphTraits_2 other); - -/*! -Assignment operator. -*/ -ApolloniusGraphTraits_2 operator=(ApolloniusGraphTraits_2 other); - -/// @} - -/// \name Access to predicate objects -/// @{ - -/*! - -*/ -Compare_x_2 compare_x_2_object(); - -/*! - -*/ -Compare_y_2 compare_y_2_object(); - -/*! - -*/ -Compare_weight_2 compare_weight_2_object(); - -/*! - -*/ -Orientation_2 orientation_2_object(); - -/*! - -*/ -Is_hidden_2 is_hidden_2_object(); - -/*! - -*/ -Oriented_side_of_bisector_2 -oriented_side_of_bisector_test_2_object(); - -/*! - -*/ -Vertex_conflict_2 vertex_conflict_2_object(); - -/*! - -*/ -Finite_edge_interior_conflict_2 -finite_edge_interior_conflict_2_object(); - -/*! - -*/ -Infinite_edge_interior_conflict_2 -infinite_edge_interior_conflict_2_object(); - -/*! - -*/ -Is_degenerate_edge_2 is_degenerate_edge_2_object(); - -/// @} - -/// \name Access to constructor objects -/// @{ - -/*! - -*/ -Construct_object_2 -construct_object_2_object(); - -/*! - -*/ -Construct_Apollonius_vertex_2 -construct_Apollonius_vertex_2_object(); - -/*! - -*/ -Construct_Apollonius_site_2 -construct_Apollonius_site_2_object(); - -/// @} - -/// \name Access to other objects -/// @{ - -/*! - -*/ -Assign_2 assign_2_object(); - -/// @} - -}; /* end ApolloniusGraphTraits_2 */ - diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphVertexBase_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphVertexBase_2.h deleted file mode 100644 index e25279179aa..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphVertexBase_2.h +++ /dev/null @@ -1,166 +0,0 @@ - -/*! -\ingroup PkgApolloniusGraph2Concepts -\cgalConcept - -The concept `ApolloniusGraphVertexBase_2` describes the -requirements for the vertex base class of the -`ApolloniusGraphDataStructure_2` concept. A vertex stores an -Apollonius site and provides access to one of its incident faces -through a `Face_handle`. In addition, it maintains a container of -sites. The container stores the hidden sites related to the vertex. - -\cgalRefines `TriangulationVertexBase_2` - -\cgalHasModel `CGAL::Apollonius_graph_vertex_base_2` - -\sa `ApolloniusGraphDataStructure_2` -\sa `CGAL::Apollonius_graph_2` -\sa `CGAL::Triangulation_data_structure_2` -*/ -class ApolloniusGraphVertexBase_2 { -public: - -/// \name Types -/// @{ - -/*! -A type for the geometric traits that defines -the site stored. \pre The type `Geom_traits` must define the type `Site_2`. -*/ -typedef unspecified_type Geom_traits; - -/*! -A Boolean that indicates if -hidden sites are actually stored or not. Its value is `true` if -hidden sites are stored, `false` otherwise. -*/ -typedef unspecified_type Store_hidden; - -/*! -A type for the site stored. -\pre This type must coincide with the type `Geom_traits::Site_2`. -*/ -typedef unspecified_type Site_2; - -/*! -A type for the -Apollonius graph data structure, to which the vertex belongs to. -*/ -typedef unspecified_type Apollonius_graph_data_structure_2; - -/*! -A type for the vertex handle of the -Apollonius graph data structure. -*/ -typedef unspecified_type Vertex_handle; - -/*! -A type for the face handle of the -Apollonius graph data structure. -*/ -typedef unspecified_type Face_handle; - -/*! -An iterator that -iterates over the hidden sites in the hidden sites -container of the vertex. -\pre Must be a model of `Iterator`. -*/ -typedef unspecified_type Hidden_sites_iterator; - -/// @} - -/// \name Creation -/// @{ - -/*! -%Default constructor. -*/ -ApolloniusGraphVertexBase_2(); - -/*! -Constructs a vertex associated with the Apollonius site `s` and -embedded at the center of `s`. -*/ -ApolloniusGraphVertexBase_2(Site_2 s); - -/*! -Constructs a vertex associated with -the site `s`, embedded at the center of `s`, -and pointing to the face associated with the face handle `f`. -*/ -ApolloniusGraphVertexBase_2(Site_2 s, -Face_handle f); - -/// @} - -/// \name Access Functions -/// @{ - -/*! -Returns the Apollonius site. -*/ -Site_2 site(); - -/*! -Returns a handle to an incident face. -*/ -Face_handle face(); - -/*! -Returns the number of hidden sites in the hidden -sites container. -*/ -unsigned int number_of_hidden_sites(); - -/*! -Starts at an arbitrary hidden site. -*/ -Hidden_sites_iterator -hidden_sites_begin(); - -/*! -Past-the-end iterator. -*/ -Hidden_sites_iterator hidden_sites_end(); - -/// @} - -/// \name Setting and unsetting -/// @{ - -/*! -Sets the Apollonius site. -*/ -void set_site(Site_2 s); - -/*! -Sets the incident face. -*/ -void set_face(Face_handle f); - -/*! -Adds a hidden site to the container of hidden sites. -*/ -void add_hidden_site(Site_2 s); - -/*! -Clears the container of hidden sites. -*/ -void clear_hidden_sites_container(); - -/// @} - -/// \name Checking -/// @{ - -/*! -Performs any required tests on a vertex. -*/ -bool is_valid(bool verbose, int level) const; - -/// @} - -}; /* end ApolloniusGraphVertexBase_2 */ - diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusSite_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusSite_2.h deleted file mode 100644 index 9f1dd5ff9dd..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusSite_2.h +++ /dev/null @@ -1,78 +0,0 @@ - -/*! -\ingroup PkgApolloniusGraph2Concepts -\cgalConcept - -The concept `ApolloniusSite_2` provides the requirements for an -Apollonius site class. - -\sa `ApolloniusGraphTraits_2` -\sa `CGAL::Apollonius_site_2` -\sa `CGAL::Apollonius_graph_traits_2` -\sa `CGAL::Apollonius_graph_filtered_traits_2` - -*/ - -class ApolloniusSite_2 { -public: - -/// \name Types -/// @{ - -/*! -The point type. -*/ -typedef unspecified_type Point_2; - -/*! -The field number type. -*/ -typedef unspecified_type FT; - -/*! -The ring number type. -*/ -typedef unspecified_type RT; - -/*! -The weight type. -\pre It must be the same as `FT`. -*/ -typedef unspecified_type Weight; - -/// @} - -/// \name Creation -/// @{ - -/*! - -*/ -ApolloniusSite2(Point_2 p=Point_2(), Weight w= Weight(0)); - -/*! -Copy constructor. -*/ -ApolloniusSite_2(ApolloniusSite_2 other); - -/// @} - -/// \name Access Functions -/// @{ - -/*! -Returns the center of the Apollonius -site. -*/ -Point_2 point() const; - -/*! -Returns the weight of the -Apollonius site. -*/ -Weight weight() const; - -/// @} - -}; /* end ApolloniusSite_2 */ - diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Doxyfile.in b/Apollonius_graph_2/doc/Apollonius_graph_2/Doxyfile.in deleted file mode 100644 index 22e3143eadf..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/Doxyfile.in +++ /dev/null @@ -1,9 +0,0 @@ -@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} - -PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Apollonius Graphs (Delaunay Graphs of Disks)" -EXCLUDE_SYMBOLS += Agvb - - - - - diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/PackageDescription.txt b/Apollonius_graph_2/doc/Apollonius_graph_2/PackageDescription.txt deleted file mode 100644 index f82d98db1ed..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/PackageDescription.txt +++ /dev/null @@ -1,63 +0,0 @@ -/// \defgroup PkgApolloniusGraph2Ref 2D Apollonius Graphs (Delaunay Graphs of Disks) Reference -/// \defgroup PkgApolloniusGraph2Concepts Concepts -/// \ingroup PkgApolloniusGraph2Ref -/*! -\addtogroup PkgApolloniusGraph2Ref -\todo check generated documentation -\cgalPkgDescriptionBegin{2D Apollonius Graphs (Delaunay Graphs of Disks),PkgApolloniusGraph2} -\cgalPkgPicture{CircleVoronoi.png} -\cgalPkgSummaryBegin -\cgalPkgAuthors{Menelaos Karavelas and Mariette Yvinec} -\cgalPkgDesc{Algorithms for computing the Apollonius graph in two dimensions. The Apollonius graph is the dual of the Apollonius diagram, also known as the additively weighted Voronoi diagram. The latter can be thought of as the Voronoi diagram of a set of disks under the Euclidean metric, and it is a generalization of the standard Voronoi diagram for points. The algorithms provided are dynamic.} -\cgalPkgManuals{Chapter_2D_Apollonius_Graphs,PkgApolloniusGraph2Ref} -\cgalPkgSummaryEnd -\cgalPkgShortInfoBegin -\cgalPkgSince{3.0} -\cgalPkgDependsOn{\ref PkgTDS2} -\cgalPkgBib{cgal:ky-ag2} -\cgalPkgLicense{\ref licensesGPL "GPL"} -\cgalPkgDemo{2D Apollonius Graph,apollonius_graph_2.zip} -\cgalPkgShortInfoEnd -\cgalPkgDescriptionEnd - -An Apollonius graph is the dual of the Apollonius diagram, also known -as the additively weighted Voronoi diagram. It is essentially the -Voronoi diagram of a set of disks, where the distance of a -point of the plane from a disk is defined as the Euclidean -distance of the point and the center of the circle, minus the radius -of the disk. - -\cgal provides the class `CGAL::Apollonius_graph_2` for -computing the 2D Apollonius graph. The two template parameters must be -models of the `ApolloniusGraphTraits_2` and -`ApolloniusGraphDataStructure_2` concepts. The first concept is -related to the geometric objects and predicates associated with -Apollonius graphs, whereas the second concept refers to the data -structure used to represent the Apollonius graph. The classes -`Apollonius_graph_traits_2` and -`Triangulation_data_structure_2` are models of the -aforementioned concepts. - -\cgalClassifedRefPages - -\cgalCRPSection{Concepts} - -- `ApolloniusSite_2` -- `ApolloniusGraphTraits_2` -- `ApolloniusGraphDataStructure_2` -- `ApolloniusGraphVertexBase_2` -- `ApolloniusGraphHierarchyVertexBase_2` - -\cgalCRPSection{Classes} - -- `CGAL::Apollonius_graph_2` -- `CGAL::Apollonius_site_2` -- `CGAL::Apollonius_graph_traits_2` -- `CGAL::Apollonius_graph_filtered_traits_2` -- `CGAL::Apollonius_graph_vertex_base_2` -- `CGAL::Apollonius_graph_hierarchy_2` -- `CGAL::Apollonius_graph_hierarchy_vertex_base_2` - - -*/ - diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies b/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies deleted file mode 100644 index 6270b1d0d3b..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies +++ /dev/null @@ -1,10 +0,0 @@ -Manual -Kernel_23 -STL_Extension -Algebraic_foundations -Circulator -Stream_support -Voronoi_diagram_2 -Number_types -TDS_2 -Triangulation_2 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/examples.txt b/Apollonius_graph_2/doc/Apollonius_graph_2/examples.txt deleted file mode 100644 index 3638b5b2a55..00000000000 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/examples.txt +++ /dev/null @@ -1,6 +0,0 @@ -/*! -\example Apollonius_graph_2/ag2_exact_traits.cpp -\example Apollonius_graph_2/ag2_exact_traits_sqrt.cpp -\example Apollonius_graph_2/ag2_filtered_traits_no_hidden.cpp -\example Apollonius_graph_2/ag2_hierarchy.cpp -*/ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/CircleVoronoi.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/CircleVoronoi.png deleted file mode 100644 index c2d17a7b6b94f5683e278418d67fdf80730e3aa5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4955 zcmV-h6Qt~kP)Px#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU^*-1n}RCr$9-DRvaMHU9&yMGBGAwX~^NCF7~5+F!$0>M25cXxMZ zad&rjcXxMpcX!)ow>NiZXQr#GyQ^oK@BU)`t0nWG91lPI za7%<46=US$i!c7^r=Qv;RvmeE*=3ja-g~dk3{5;ca>f~F?7Hi&AAImZ6SEI~&Yyq& zdBY7i{QdXe2mk8u8~<&i@4fflEwU_uqei;cUz-EgAFShac{+!wxMGCS*D~ z|BV?DVr{k6R&7gz1#lFn9DD4se>0#nabJG<r{$0 zdK6j4n#sQQ+H2dHhXOI6+bJ6iO8{;3mtTH)zySvwe)!?ve*0}g)fSHKv(G*&t+bN3 zuJW``J@r%z)6k>KDF?L2kn2k>xn$dIw|(uk*D8b3^&pg&TW+}vF1TQlNhYbBc)RMV zt7IZmiIjYv(m-btJo)64&go4z-IV00(q$-{cAk0Wx#NyIDlF0o+kX4)I9rpIyZ`Z_{#h}X-Q1)Kj`M?7Ygs(pV?P;f-mgJn(Tv6BKwSdm%di2ppnUULX zzkMjnd*Ou_a3Nkg6UJ7_9JJ6_Cji>=WLDWnS=Iq3bUy$5b1MA&^Ursx4^yUQbjvNb zq*ck9v!ww#Gb87od+v@q?pWW9L@r6GbB{gtxcTOrd&k>=efQn>?z``foQm+zKKpE= z^}J+257>+_Q~a=EN}j#?_~Vap&<7rPpb%?)Ak$4Z-ApshG~t93Zm_`yKreix!hpm; zlfVj@krPfhp*|Z4tmm@JF5>{hpwQ5*x89ly3Cv>#DBpPFjhTI4am5w+_6j%_K9U}2 zuN3KV{p+l=&UM#aS13V+0rV7Wj)_jyLbZos{dsR;G3fH>zp^&-&O2`fkqRGa1nBIo zDDB#7uT8tt5?gg{Bqu(AeCw^ZU=7f|SkQVFW0Y2EzFB_x(`fG3YXsr<`)ihPs@Z1=_;C`|dl7q}r@%1x4t5 z#BQy>{`wNO73NW~)xq@0Baiex%S^M&ECyX}2xTvA9O!IeC^oEj+ikbXL5+yt;h@eH zP|hB)PaYo@za9|K)~SVo2b0PC`s=UDg5_AOx88c2Zn|krb8okH-g##Q{>uAZR`SvD zg9F+t!F2iMmy4M5TvOj=@KoCASkh{lkghrHnHc@V6Hjc2FX!#VK!MJL;FMIwq$6UM zYHv2#WE1KPpvv0R^`H$C>~IAoxSsCE3zGtXo(g%x_b zK%?NIR-*rJG|L>blFl)2zWL@_YppfTIOEJb^UQP3Ij8cCgvN2l9hc`7m}~}05u>@w z55osK1L&^1?h;Vw(Pl1$B%+(mH{V>QqAbM5YlxV1(n*g#`smJ%A3R6+H{X2onZ&bk%x_gu*IAri^529@x>Rz9M0#xknTTGx_MFkBa8b{r6-*(`6`U z?^$~3rNsh;G67CLFD5eyYb-*Oc{r)G?6S+oBvBV!a6!!xh2nJ%V7s*CBSQ44u(Cr) zdWNb}BW=Wd#;v#Bnha;%~h1#wfWh;ojX`A~PRjdy)aooUs^m z8Om}%h485%`Km@K_C~GnGqFtG*)T`okKG#Zv-ZC~G!=lvsq*6gj?Ym?+tiq?mneh||p{Ga$Vzg)+`M z>#V>k``#aZ_yNll#c-jKM6>r5LjW4YELR1k7?s|EP^n?x`vw#a*6ORTKK=C5GnyiM zMA$jQ{A4`Je#gUJnn9}8!o zDfBmyYZ;*w&c%KA-N)FcnzZk`(G0{W`9*DM)r8-`K>j3HkTZ0mvN`Ur(Qbaz3;a}x z8sB30yhGD*{nOp~J}8TE@iuwqX<@r1iT zNFw4**%2v;M=;e;@sQt9f`dA6PiJa~t?NPESRxthX$+ zm$A+eKV=O8O(u)+r`N(k6CLFpG)TE?rS4a%^eOeOhg^f!SYwTakcl(Vh8bs^aqO|j z_CHr$byWo?#5Qk{A~Z~nY8zGvguS`?>Z|F2c)HG!EqqZ(qXQ31>kO z$y*53As!-7xiT4p@93CVjSftzwMCr9$iSLe_h}L;DTj;aMn)x;y5^c|N)!7$LChlv zlCBJe!9aM)Ljqb;BwN=TL)tSooi{410F**AFgO9wU9(F^Warm^#7L=*CI29*F3TAh z8TS$$rof8?9YSa7FMb&{4m=(L7n7cikw0=wdZ4ox>pzc)BUqcsC!buH8!2wrFbNG_ zS}HtXwc%^yvqFhlIH%$?RI9I76Eb_MDWK0e=bXX@S-K46nhkJpWCWI4YN>Gj#V|@u zwT09P+xX(4ZwhFhEnL3i%29CZ)dwJn` z&=sB|t!xe2Xj20^&mZE;m|R+w0kJNmaCw_o41YXD88G|Kf;~%{?P*G*GoZyay=bCk zqLLWCTy`e}u38BKPicM(ew=wc`j;Rhb?GS?dL=Se+S3SineLwdnk5T8_N#PYLrUdTU z@f^bLKs0ERR$h5!{zH#ISt!HfD*_E=6j)Kt`C4X~Wmt*c*GRNVr*-}R7Aad4p8zSl zT5+IUW8f)`*hxxLWd*AUG+l;r_A-%zZi?P6MOCX_6CotyZOTd+Kc1O($O7XfWQOwH zkZ94nhD?mk{c|UfU#h}Yj?pr{@ zSbHySs+Gv%R|7HTDF+Kh3ycJ@On`nY0tNKr!XO3cVqW10e5g(cu{C{*%aJy6xge}5*=v{c9olOnffp!k%6*X*Wyj1#P9y_OXCVoQMj6sHojcBy;ie-nr4SzWI+;hiV zYKy^6yf@7>)0Apq#!WQ?4a_Ar0<`!grec(R!lC|BH78d1x|jD#Kk4y|*~t21(gV%) zyJjL2U5KFcu}*WoUObGs}S zHX~@SP60J+)zui)$i~?bNom@Uz}r2QdMF)I%%2Q)0S4eH00 zY1CO<>gypcZNM5vg&kQ6cj|s@z4C%AzWlPxr)Oo0GI8m6 zOGY_Zf8Q)ks7wVmTEm7)4;rsGu2GG%Bt7BGQRKydF1g*t&|dAp@yv>?I`~!Gu@ud7 zD2gO4M{>_S_sAgnE(s8sV0>A-mvz|#=1cf0iO8$trq;{%m?!>+F5*=x8~I<2&f*Jh zo%NKdNEIwG=p0~P8qZ6`3+e-LqGtuDgwztxpg9nw~UQd7lnrIt=6Y^Hc+sw0NX23-Qx-)Aqg;4*Z8UtGqA7MXGSO zjb@aqJz4ma!r*8V^a2Yk5XiElH0)#FKt{zxwuB<*wNe&}QEdQ=$9zk_q|(1~kzpyJ zCDmq|Z8l7f-`8prCK%X4R|BUN@)nXL1Gv`OcU_WYa*!HglboRjfhN6-lJBm%$y0b0 zj(zAfAQs6=Fl)n&Yj`Y7kznyZ`;w=N%>rHO1Y`z8l!S^owhU!q6xz^zlP(2_BqIy zzvk|n1*pdS+6A=0L`WS8^bm*H17p z{8|LG+=ytf&Vq;dY$5Y&5zxNkA4rxC5ybdcXUtDaUvJK@ML_G1DfNZC`1KERWFGTt z3((U4e>=*Nw||(Qv}IS$uPs2UKNS8B!XOp1{=1~nm5fJ!RH7|F6D#?b8|s5qbB0dl Z_b=m@J*Bva^#cF^002ovPDHLkV1k3zqYnT8 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/CircleVoronoiLarge.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/CircleVoronoiLarge.png deleted file mode 100644 index 3853018ed35968221f8c4d91854dbabca3063e50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106801 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
CmKq)@Gd@pBvdvV1RDZlnGll!Wqd*W&DQ*&h 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 L1yUjTDd_(IgK8Tq$jq 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 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-entire_edge.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-entire_edge.png deleted file mode 100644 index 384060402368173afd71586a7d5564768e568432..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6513 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 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-entire_edge_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-entire_edge_bw.png deleted file mode 100644 index 5ba40cca5d0bd26c1d2e20d11de50472800b837d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2657 zcmV-n3ZC_eP)J!bfvIPS6d1h&rV>0wG)Je6-H*(SZVt!qNM*)mGp<&@ z+8lo&P?-~+qpvdKvl+23kvZ+rKe{nC^B za}#q^B(G`~FKUi)yr!9=sw>qDkL6X(1mw(Sq7k=6n&Hu~xfru}S#t!0&A-SjdRdxz zNCULdoy?#c^WDrnAQ3jFn=1hNX67QVL1GA-U(8%$yN=uZY<5N?GMY>5-zc*miOnUM z&)L=y*j$jA-?jZxvq+93_q*c~-_e&ieuHG3Om1_DL@u18vdzHIIi9(~<>s}ytOzAro%FQK-( zZk}d|b4&4aRIZzMj4m9AgMH~a>G-+-h@^n|U`^>QyYkK{)C6;PzpR)9`7>zO=SD~> zajVEWcX1q#=J+icmhF!@z1t(rtle+bkDg0tE;W1co2?`ra(bgW&=F?6cr9`HuAt>J z?HX_te&f%2J!!wk!_CsTo_cT5uw0(b>$THQm(k#}q2cEJ&Qk}Bzjif=?yU{8C)sH8 z;a7j>9?iuNDiY_|6w94|{4`PjJ}QjCDlc0&vA#&h9tY-Jn?!YqO2u{<5TQ^jWw$uWc3!<^lv&K5VRKJzw%rE<=5}umUxaRRPh~c%jc!O*-+rks+Q(4mwJ_2(I2R`|J8HWLEdV)jS*o+-&9- z&b+-ko%*M`&|}Ja@BXUi0zPGYX7k)nDVP3=K#$B+K`ZlI(X7S9X%_V6T|a-wEKRfM zx5C{uy{)TUIO7t#-y+PtMh2MGv(;ptn|0s1I*)nxCAz_iqteWe?d*Q5%I|6H(Gj=# zEg{s6v_5wm=2>mI2V^jZDvq%ZSLTPwsV%pz&e^cTJ;Nf*y=q1cX7jzscnu!zVx6l|Uulix_)cP^hT}|7+VKoObdU_fAK6m9hGO*X#ovX76+4p4&!Tx8h&s;dS z+RF84wr+QgS$H;6MPxABYiNn=%e95@`xJE-Y63B>Y)AjIc?@`S4=|67%HYM?uO)=` z-GtQ)dp`&yM`Kfnes5)GHJ}fH=DJxPm7n^bD_V1S zT!H!-7TH4F-5f0=3)0M;&)jG~!_DgE`Bc7?_uYf$ zAe*N!<@J-+EGtjfrsqi(K1810>?;Aj4ugnc{XfKJ=_|CJa}YTbfz<5pdvTWN?m}~* zZg7omgI<6qnMEKi+uhJQ3n8O9loo6bLPm3VuG-k_Fnx%rK&0kyVwF)4Is}=}3|V4f zna`$_Ip!_}JfPIpsbRV1h^3o_-fqQZbM7^8me~j?vj?v+D>Y6`YNk7~OlAow&OObd z+_~5L!q1*R!wlQ5M055p&i-X)FomFSys#O5%1bm8BuHeASw`kQ=8OqmU>0n~o52t^ zvw4VGSih3;-sVaQ;HI}RJK|2id9&Gwy1cSc;x*_>kj*bc7D6lgB*9Z-qy+Q9ELOEi-tMP!D)qc6}*ky6$%C(z0zn;AB? z=XPe1yhUzvFc*okIrEr60g5N5IgpQ3*_?Nbs{qE6)9la5dz!s0GBUB*KQ{iJX73yX zDl)a%MGMXKxY+EPQzIf{%4fFcC@GoVZ1G82@(JdHP*#+M`4qEt&LeTI(3`g@rP^}l zH#hGlJ5y)!X=eRP8_3D0nN?oXi_bKl7ud{ZHnW+{_Y7=iGn?7W=6eP&3M`&+zbaP{JX>fEPC}d@JX=7zQaBgjKVRtDC?=+M4 P00000NkvXXu0mjf?`bzq diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-interior.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-interior.png deleted file mode 100644 index 1423065e66a2812d47a90dffbc5d67e8a70b7a08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6808 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 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-left_vertex.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-left_vertex.png deleted file mode 100644 index 35f6078cf9f311737a5dd424e233fb46a9e8e993..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6294 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 IjaktD08A?3 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 j0qYkX=<8<~h6{=Cj!^_}XytDIdmyYW?9Jd(`U diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-no_conflict.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-no_conflict.png deleted file mode 100644 index 4d544baf562c0f0877201f2d1ddbc75c6fe8fd8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5970 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 Mf+n>7m1V^L0A}S8;Q#;t diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-right_vertex_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-right_vertex_bw.png deleted file mode 100644 index 908c9e41ad17883386fc53633b098c149d572b61..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3236 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 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-false.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-false.png deleted file mode 100644 index 2b67ce1e7fcbb916bb1cfd27ca2095ac4e447e76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5985 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 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-false_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-false_bw.png deleted file mode 100644 index 93a0a00da0a033a76b985da9aa8434d367f0ef8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2864 zcmd7U`#;l*1IKZf<2Iy7kxLsVg(OpBF1gJuWki>$T!+dSGxuBQ=5FQMi6Ye65JGc3 z#dkirOb(LED4Xjr+uSYAIX`^=hx5bx@pwO8f59`w$T=2PuZ+WjU^-BX~89eX>ROs%ct~V z@dn(RLcM+_{ZAE3wD}V$ae^QO3Py-N0PY`DJg6r8UyIp1btK33$&^jcI5}B(umu@TwIhD>B9BG$P^==ZwC1d^6)f^rzwYtS% zVE{gkna4mxyQq!KDIJn^mj-Qk8uhLR(sW^H~b#&K{AbzhdN=JHq zxLH}Hy<2!sA8l~79bc;V;EUt>PNmfTh5ffn;JSXyn(5G{p*n%pHSx0gIAY(u#usLO zEs!@=m6|M>{j7TH*9jj+tSIv@)$wb%hu>32e+ZO~du-QMFBjaBpM+~4C}|{x9hmu* zu@p{sJcaogtHGQcG58fkdP*kt3x0Kjj!Z$H@_KUY#emSjy2`Hu zgJ-$(u8Skmi*Rsbu7aFvTj>3B1{-Iq_~u z%ECQ2U0IYpOnJ@GeD14vhcy-6L7x+hz5i`c>uTpv3 zlrd)K5#7No5$o5lj?6mm_gM0GE}7F!FW`DjcIoAtJ329n%%aNVtWiJ3=$|O&CO4tG zkbMt@$lSl4V z7E}DeCl=~8SnY*c(o7l8joJfd(;G)(79HS+ah66F^aRN_Nt~AE32lAkRQsrkZaTq% zwvIfLOK_k{1B1KOq3Ux*V)0$AVE^`}heWVJEA7xxxc#pskFNcO-fG5F{*T3gZ73iy zpQzL(pPt|`cN)^z>KP%*%)uMrh~>$bRkxvCOd~uA9|Ac}JJap3ea!!;2CWiEa68%K z2qd?Y;xEL!@1ZU*9;V{TdKN9_)4;le56o$(xtbm-(c|^vsiXdJezG7q-MF&uC!Y@;t1u2&sCXm5siA}%W5ohL< z$1`SW^|15WuX-z+*5tSO)+gezL7&tZ#4KctI}kj>AX$y&t%s&5sbRU1^8{IV20v~( zAiAD+7?@Y;Le>Wm;9=2vnNr(^R?5t=|Jg07`*i@b$9q%C_)*VFemINyh%jlH)u|I} z+5wt4Y}a+03vIif??PCRj+{5#m^0AsVrnV?$e5=PBCsjOaA>e5k`*I;LWT}*RwU75 zWwsN)jF^c4O1{?_gAk+=dRwq#-LoW8$v&OyHZ$|prRRabKl`(POHoj|Bvw*wITb!7QA<_45zY8Y-K& zu9Mx#G8F<*c_tB>q)Np=*}$3BJ3FNIP47rPznU0!9(k`51~eTtjGAUAt5WzY-5rK7 z?(de9Q`4G06X6bR_pCk8*0W(wU(RGje9>GANdomB0WNlr+xy1wRf|c+^1nDm&(%_Q z$1W zBBL`)uTa@NN;HW^OagaoK45@gTzy?WEbL*$UE4R%dTb!z!--^bKAL z40}Pvze_vLrvZQ)!sakr8Rf%4RX}?&RT|Rk?6W+vs8u-yL>4_5R!-%#6pHe7Kmru^>Q37Z8@={J0E4r^{0xb#_y;8b%%pUn$i%qU! z&kKR;r#}vb5f{(t6RK|n6IoZ*jrFG@1Pcn;U?Hi?=+2?o4v6Qywy-051|Jj%%K`Ka zh7{kEmMhx6Jh!!#;`)`z$DH>LzX4GjAED?%S7|z%tweEbR`SCA#?!)hb2LJ7R-mN= zG7o!NB^Q0fLn6}3m8TlHk4DHlt3=%0RN$5sK!2~ zH}J$ngiw}7NuK-*TFij3 zwmPAikIAo;F)Fr*y}gttRySk%-($ZtC!$@1oqVPsucKO&>|nz>@&v) zYI9<&edfAYYsp-WLt_jsjcQI9&qU-ob|ALw#^}gYn=~Xy5R=KE9^GL4i20 W2u%?C+_Q~;DQs`;h^VskO!^y^`CrKZ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-true.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-true.png deleted file mode 100644 index 4e2caf6b1ddb3a682f7a9b0ca57c5c0f1bab6024..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6126 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 Q9s+>(vZ|13X|vG(1DQJF$N&HU diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-true_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-true_bw.png deleted file mode 100644 index da68029a930de9299201b34fb4f9b121865a4cc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3064 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 DI1bOh diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_diagram.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_diagram.png deleted file mode 100644 index 13d893e7cc822105443644da2107fa24d9fdcc40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12363 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 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_diagram_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_diagram_bw.png deleted file mode 100644 index 76437491b4b6694cb961115fd87297c57d2749cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5396 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 W|2zCBXomiC07!_)3fBng2mTMg&tMz? diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_graph_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_graph_bw.png deleted file mode 100644 index fbcca9aa0cd3af6275f501b7f9df7e70b4d9b4da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6515 zcmV-(8I0zMP)ANkl)#Rbqr5)sU+PsO?1%Xs z9_16laeZ2-{4f`UM|ojbuKX~+1$Kf*d099^`RA{Hu$n!}>xzGp@-H(#$|nR|`h|B_ zf13GGULSH(_LVCIep?y-{U|Rg`Dx0(%A84C`6w?b_Q}dW$jp@bQ9h&4YgZ%wBJ-ns zLST!$cxCOQ{0@)u^a3*_Ua$O9%tCn|#GD`H^+74= z`kiQx@}uku$)S|BFYPJHw`EREFpBvoheHxVPccu}A$&jPWCpH`N+BO*5_nM^`g-MC zUH|Mhn1i+|(xVK6>pBMx10}p%`8LchV&+J*O?;G(;1U=wM5Aktkew2NoA9*jEb?!+|hx%&eVPm`NcTPdRS$PEc>y*Egd8oD6 zN7iN(zpgxnTsKLf#DL)1E;2mC9qtR9TAbry`Pu zr>TA)^Q=Z0#wVn7TA996d8j;$G9Tfo%3sAiyC!Q<{_TOp`OGJ_f0Ocx_Ck*LQSK~>P?WDw{ubsXjj|l`qdd7FY|DJ=FKK)Y^EzZc?w?ei zGpDS?PF^~-cweMEQU+7Gjr~`Zhst2Bak*IeOPE)-7aLcZe^Gg9d$E0o^7YJ%t1`p< zC@;wW)ym(%Jh+mmCxu5jn0Z(3uU0<$`j^cRjLdc5Pbu5PA!`3;(tcg8P(Fv*Pwa#a z)cjvi*7=&PO@8Y@&M#M9&TOgCYo8A~l!L@?aP%HGP~MXr5~qI2fHIp zlkta?o!2qFx6CuUHbOOtT&%pLGw1Irc*Z1EI@R4~&h5iTB7aXg((iSS{1Ej2{|A-r z7`{V!>Z7V+V+*Hp0?HW^JNLtn7i=g1kfek_Yy(|c>6p?`e1u6GV#L!ZuOB4H%*hA= zWOv$jyeR$JX2gb!RQZJA7?lx3gVgcNTTwEpCQUhe{8PS&*+O(d_hemFPAu}?Hur{q z?Q-neF(ZJ>iNT>W_vKqll}&HYE|;`ld5d18M~U|@VB~O4rZ>y7viOmz&2KV4fYQe} z%Nbm}qo>f4_hr{m=H5^e5o$u=$e4-f39*b#r z811Yzf1~%=D5o>iD_Cdu;OMvxWyMrtNE|uCf1xgPRQ*0w@59C8-Bm*0@ICGrSJmq(eEE7j|^cUD75g-#QdKUr~1)j2h41|10pA`U8#Gb<#$%A-#Mz~5(AWPasz z`~$z^EL;Difl!9m>;D*EH8`^opwTiV{Glc8EbYc#UwujR&wsIn_`qUj%NgZh8nZJV zXW>VbOBuU{#m#GgH8;$fG)a4ext{9%w7eyM$Hq(^d2`motRugU*c{B6Rqkb0dIL)O z?wALZJDfFSl6Bpgru)6hX-K)0maA2s5fx!1d6%HsLQY_IN8zqqe4i?sPg0>12sAxP z2><>x%-S&^QQ4{^NS7(C*zTC;?8Ao82?v<~`_-12+7oE0nHp#`(s7wuqD)`x$z!e1 z(6$}PqtuWcy#CSVxK);~1!KyQ59tc!$}GY*Mc^uO)0Y#Ol@g9K&sI(om5+p*Y9?K~ zxrz)k&$k+$0**3A3hR$`=JPQqGg1aeQsgH03bS6m{-*gZ%EfuVUT$F^zH#+3dm|f%fUgl6IBXqN5k@EkOi{n$S#L&URbJ( znT4w#uDK2Jy2^~tpv*Z#hh|hnK+Vd5C z3{x3&I3zHvY+Ws3Ol-o8K-;Do+(pf%iKQ9EcGF3U5%1zg<{NDx2k}!6zon`pYGjkU7Vr9g9 z3`;&`F39VZkEv!A9=P73gutOPBHXo1DW}K_64kunjT70IKc(c$Q z><`97Zm$<|ZRRKGu2E)~(HE3P6Ja%dZRMmZZ{lObE>L!jjknTc8hZqxsp@B@S2!BE zkRCr5`W4Eh%QOJnce_MX&P2HmyGxc`KW^|n%6l-$&A7$9b zAPvKMW$qSqQ+Ju3T$xJJ1j@_vjA_68k(>BL z;JbyKdzC43k{%weDbo#jrzsnixe6B4c7=)AONMFpXPQxF^2!&XEaOr>=e5d8%M9%* zDg1Zd@1^*pyOo=43msuic{4X$tyfkakpqzH-T0Py^VR41zwdNRJ@{r!CrIG~a|1l%>jy zc0MuHlTijsjXchy%C%wTuYSVzos6E{bfI!(&H@?K1CDU_1HZDazSTV@q0D?;mWL&z zhq7Loty3?#TB6K1{f=h!GgrdmJgy8|j1*PIv0S5!mThTyuYbJI8&balI8Ref9m-8C zrzmsGLeC)c$}jS047sDMcJHG34k~jK9xT8)$`S*;68`&7U2D|Fz^6IG+3YZLS462} zy>`{hCMfR)=2KFSelnx1GLKj2nr%s$S&_jXcZM=e%HWnHF7N9lw+OG}5w;lB!AvV%(3!B9%I|}u z6zBzTzH+V1Oj%#Rnew++NU86~T!*-WywFKf&VurOj2Qh%%Al1bZ^NaYuO{e&7QtEV zJbI|Ph7>Q9<2upCO7Sz4)gLo2%8l_q8e5rM7Nucd_Cj-=f<#w>H;LwJl{ekE=J|!1 zX;P3vB>`3tH5toV7!;E(1pG_vVDM3{P~LpVyq@bgP@R*myxGvAvb==ZKt4m+(-`K6 zvOG_;SydSwEl5kVl`SP|rt`JRdqEuai+`Cv6!lY)vwt#9u$Dijh8cXUo{g0-(%H%d z*;MwvOggSOsnC>XW~7xb1K!&XKW@hbb(ymJdo1NqY#kEk9Ox3;*xI30c2D0t#9EDaB-SZ!Uy68^ZxOP_EN7DMW+mYR1cS^0<$XUx zD-B0XJM;VhoyaScxv!i!T*zVNO;#Rhn~?^A22b4G|E|_<<^A9Z%2KN)DCej$ed8T- z{S=3smH9jnt+z|U?%)F(l+bdv=euSCHBiB;v%2^G=%KC@PH5$4H)41<% zpfyxYht7LNaw<2^qdCGp#hk$tCyY=NS%@qt8xisb8LkIRB<5~rMj1>Kw#=?g%rxF1 zWwV*0%(+(?wLgiExQAI+#?VPeCPkm1Y!Y)E)+vT^=3^aUrV;VGG^ld(LoCf%bCg}k z1jIT;RnBlUBIIb9^3i4qb(b(tXfd+WxHYlQpTgpLZmvW64FhdP`MI2J@FfPoV6FFsYtuD+;_U0>Rtc-tCNNA=9 zl>3YiEzg-WdNk2_v>9pyqsm+J0xI+8-{L05g59m$(^!Dgyn*_Z>jG|%a=0~9m78Yh zB`9xVt&S;=7;nv;r2rDXln`u>Nl1^fp z468CvR^E^@TxR|Mf5@+RACU%?XBgMACtbSf4ROaVt;}@SI6C+kkQ_&~O~>BHgTvj; zqddjfgIA9<4m(YmDR^mjRpmC%o@@TNG0kt=4%Df)EG*b^JBBmdD!-I?ng<;SEk;mz z60)?=f(yBMDxotv_q!96>t;mZ>epsmRi0%m6x>wqbR2Fn$d3$)%Iw=A<$1<>xfy0x zgn>KZdcdD3TzC>oeS>E*eG6~sNyN?U%A27KwoQhuyh+Ob9m125gN438xv9)*+=_Ck$|QO|`xA-d zWp*a792PDBtbd>K>%VBjmg-enWfDD?!KudaB44D8Hd1JlZc=3yE`3|8Jii|I6xmz( z<-ES%utty#MD5{x=8u_MQ^$*3H{UgP@AFS)(I z$}5a}mEFv|7q6^2?{61^cJnfNfhfP!s=PIA{&eGx>wV;dktU&v@}^8oQRmFawL9|b zo4MJqFYodg-aEHK+0Tp*M5A1`O% zcmvO-v5`0Jc_FiqJ9n4H4s86y^A+fKUZYDVUN~kU(Y45ZRk@>OZs{D8fLu%++qzM# zQi@BBdyylpdF@X46HfdI@F~B+;^`+2@BQ>`^dkbymc#YN%$&w>$7hm>$fX=wiEJ) zx*HrJ8Hckll;@7@S8zFvo^N)?#3Liqr~KrDGE77>CUzoUuk74^%vNS^63U~_$Xs4K z!FRdxcu!narlX2@>c^;B8BoZTVDWgg;5_{&tP9Bb` z4JKaLm(2GoOR+FA?U82kwfcuf)g8rLr#x$dMDA!Y2WI@Y8F7}Qn_13#DD(Syj3bTo z-IK!;3c6HzT0|r+9)&3TSM2}1GQ%vHpySlib5X7<=`!W1^VZD`9kJq}qqH3G6GZ*F zGmf~2^5#?~m063ff#_%cGs=ir194Sm@q*f&H{*y^%JXk@)mB6G00~QZP-fwJb7mZI zALYudY5+nZ58@ouqg-RPrp<9>7UJM7I+-2w;PWZu0#1q6oZLs1nU6uRc$7hj+=Dvi zK<(^D8RXck&x*2sVkh&TRE7_p(2LF8Ke2AU^p*7*<#ou-gY4CEGjpMOzWSRCBhPCn zR#xS7q#!%*Z_uewds)|#(%x2?aVF2krE_$Sl?N+Idt>DdK$D+9D$Mv;JMu@FaS)jI zwJgn~hHI%(S79$vUNiFJ96*nQGUEY?b4AyR(%xDb*IYQ61YSGxv5!u4C?}8dcJO*z&t3Vc%fayW zbuXRxj0aaMd*(-$V60d6W#YK{`7`q^^Kgxx{*;PLNQKvL~(Jv_J-Bt>?lrvHGHX3WH@-3AeY2yWnsrVT|Ddw%fH>>j6Bl#1!SH@X)>vFumoX+#_AqxTdvd+RBJ|v$P;gDg5rhPu>0&&k zAY4jUt`|szG7t>9a?1$s19I;(u}91JTgv;4C{DFiwwODVeYsvB5zIm;B!!vI3lU}A zIoK=*2JZ7A!g+`UQTh0Ndo~a7oN3CDNvQb{9l7uaZnmi0eqwiKA7{14^Kr+D_dCkq z9v`=IpqxccVdD;!&Rx94&w828+$fXV)g%YytX7EKR~af>;NHM&hW@Ph@++;{;*!dO zGVi<&`2^*;%yj)BoEBozKh84q7HBWRS*VuB+U;OyIxo>p!6l$^Z>_#KA z#!@P}GHy14$gym%R-Rg$dE!moas4i&AP8e}EBBOVxw30huQ!eo740-gr@afQKIq|n zR1;xc)6bp|&Hs93*REdsY|v#(+%Q8p^)R!d#}OtNCY0n13Iu`1in9@+4*VN}tRIl;f6Jj<6~l2q+!& zsgys4n!VGMML{J9S+1*Vk0GF(;N}?9pnR&Ni0etHt_q zU6`{&*^Ek1-x5j8weFCv>%QXay4qx}_Ug(y8TA!qdH5m>4+oRf;3q_03b z4K)M#FDW;VbkLM#WIEgTmLcY*4GOf%LkZ-JJ6B$Ro zuQC{q@W!livXSBE;QaYMGyDZ*>RgV%WlbJr9NYLD#yiHVwR(e4`UXg9Oe_@?$vE>} zmCgQxr0j;VE}@ZdQ)SPvPUz@OPRbSjrgAxE$TyId5$>t%D)^iW*Y7I($~_5r2J@pl zD>*IPQQ2AQY0BfwH&vc^m@lTWxNfNIE%H3&VdncOyGuM#d9=;Ar?U6J3sPmn?Uen+ zovwVV6a$$63WFTUBAVEe@Odv;SZ*z2WV{&P5bRZ~XWp-&}Wj%0i ZZE|6EDGKj2llA}r002ovPDHLkV1h0$0<{1D diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/insert_degree_2.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/insert_degree_2.png deleted file mode 100644 index dbf53288ceb90b3633985932fb3d7562bbdb35c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5244 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 YN-EMWZ`Ga)bs})i+QEu)#w+pv0R31M;Q#;t diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig_src/insert_degree_2.fig b/Apollonius_graph_2/doc/Apollonius_graph_2/fig_src/insert_degree_2.fig deleted file mode 100644 index acc8413f6f46b2db4ffd5cfe697b4ba01528bc18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2599 zcmbtW%Wm5+5ImP(L7?XZBt?qixj>5mx%JwMk*cYSR4HsD-`|-fB|5Hb(vQD3*y^UJ8Bvd$Ro zRIl>`wzc;z=xBnO-+Ic}P_~rURvR4*zO1%`CLs3+Q9dzf-$CN-n=uv&lobUCV6`aV zoi#yQ%8FSd3U@tBdkZ&wKkxV&=#i=mblEgv+Fq- z%m@^zE6L%P4aCEfYJhPO!p<)+b?pYk&7EeLzR#`@k+8BB7(TVYc$8dRFG1CHE(L>f zQhSH|#9Yw3k`pO07x;7P!%;>S7$`HbMVUWq$^ptX4>hqhs0FafU1*FX1?t$Lu0uy{ zOG}>VVHZSRtaStAe_WCG(gT9uC*=LtWqCW~84&}44n5C(*Xzh`7cZ@0OQLWbLU}En z9a9;H3jvoQjFIDW!w^PJ&FK(gI^l;*VRor)46Tv5yJ(j53)x@C~p*(V8mk@OY{m@PAkY#E7fw9F80vdo&gxd|FrBXu6^=#wvVTGz=t zD?2UYJ{abSoCSyRU)O`20*xG&(E7(5R@bQmYAc6{+7XAg8e znP82HNMkiA6{wxZYAz~H4Xh&SMNp9;kxzWq2-fKCol~M00vf1-L7<#gJgf5a&9JCk zhu*jbd-f_&W>Ng>0vc_eh%>Z1(_#*&heD>svj*n7Mk2VdRzC1?b;xHFFCA+sM5XBi zic2|<9I;3FgKGnRkUlRg%Zowe&4*Wn{|C)bLUIC+rxQXsxfu1y=$3Ux6^*y9k#ENDE

    +
  • The dimension is \f$ -1\f$ if the Apollonius graph contains no circles. +
  • The dimension is \f$ 0\f$ if the Apollonius graph contains exactly +one visible circle. +
  • The dimension is \f$ 1\f$ is the Apollonius graph contains exactly +two visible circles. +
+ +\section secapollonius2design Software Design + +The 2D Apollonius graph class +`Apollonius_graph_2` +follows the design of the triangulation packages of \cgal. It is +parametrized by two arguments: +
    +
  • the geometric traits class. It provides the basic +geometric objects involved in the algorithm, such as sites, points +etc. It also provides the geometric predicates for the computation +of the Apollonius graph, as well as some basic constructions that +can be used, for example, to visualize the Apollonius graph or the +Apollonius diagram. The geometric traits for the Apollonius graph +will be discussed in more detail in the next section. +
  • the Apollonius graph data structure. This is essentially +the same as the triangulation data structure (discussed in Chapter +\ref Chapter_2D_Triangulation_Data_Structure ), augmented with some +additional operations that are specific to Apollonius graphs. The +corresponding concept is that of +`ApolloniusGraphDataStructure_2`, which in fact is a refinement +of the `TriangulationDataStructure_2` concept. The class +`Triangulation_data_structure_2` is a model of +the concept `ApolloniusGraphDataStructure_2`. A default value +for the corresponding template parameter is provided, so the user +does not need to specify it. +
+ +Storing Hidden Sites. + +As we have already mentioned a circle is hidden if it is contained +inside some visible circle. This creates a parent-child relationship +between visible and hidden circles: the parent of a hidden circle is the +visible circle that contains it. If more than one visible circles +contain a hidden circle then the hidden circle can be assigned to any of +the visible circles arbitrarily. + +To store hidden circles we assign to every visible circle a list. This +list comprises the hidden circles that are contained in the +visible circle. The user can access the hidden circles associated with +a visible circle through an iterator called +`Hidden_sites_iterator`. This iterator is defined in the +`ApolloniusGraphVertexBase_2` concept and is implemented by its +model, the `Apollonius_graph_vertex_base_2` +class. It is also possible to iterate through the entire set of hidden +sites using an homonymous iterator defined by the +`Apollonius_graph_2` class. + +Since storing hidden sites may not be of interest in some cases (e.g., +for example this is the case if we only perform insertions in the +Apollonius graph), the user has the possibility of controlling this +behavior. More precisely, the class +`Apollonius_graph_vertex_base_2` has two template +parameters, the second of which is a Boolean value. This value is by +default `true` and it indicates that hidden sites should be +stored. The user can indicate that hidden sites may be discarded +by setting this value to `false`. + +\section secapollonius2traits The Geometric Traits + +The predicates required for the computation of the Apollonius graph +are rather complicated. It is not the purpose of this document to +discuss them in detail. The interested reader may refer to the papers +by Karavelas and Emiris for the details +\cgalCite{cgal:ke-ppawv-02}, \cgalCite{cgal:ke-rctac-03}. However, we would like to give a brief +overview of what they +compute. There are several predicates needed by this algorithm. We +will discuss the most important/complicated ones. It turns out that +it is much easier to describe them in terms of the Apollonius diagram, +rather than the Apollonius graph. Whenever it is applicable we will also +describe their meaning in terms of the Apollonius graph. + +The first two geometric predicates are called +`Is_hidden_2` and `Oriented_side_of_bisector_2`. The first one +involves two circles, say \f$ P_1\f$ and \f$ P_2\f$. It determines if \f$ P_1\f$ is +hidden with respect to \f$ P_2\f$; more precisely it checks whether the +circle \f$ P_1\f$ is contained in the closure of the disk defined by the +circle \f$ P_2\f$. As its name indicates, it determines if a circle is +hidden or not. The second predicate involves two circles \f$ P_1\f$ and +\f$ P_2\f$ and a point \f$ q\f$. It answers the question whether \f$ q\f$ is closer +to \f$ P_1\f$ or \f$ P_2\f$. Its name stems from the fact that answering the +aforementioned question is equivalent to determining the oriented +side of the bisector of \f$ P_1\f$ and \f$ P_2\f$ that contains the query point +\f$ q\f$. This predicate is used by the algorithm for closest neighbor +queries for points. + +The next geometric predicate is called `Vertex_conflict_2` and it +involves four circles \f$ P_1\f$, \f$ P_2\f$, \f$ P_3\f$, and \f$ P_4\f$ (see +\cgalFigureRef{figag2vc} ). The first three (red circles in +\cgalFigureRef{figag2vc} ) define a tritangent circle (yellow +circle in \cgalFigureRef{figag2vc} ). What we want to determine is +the sign of the distance of the green circle from the yellow +circle. The distance between two circles \f$ K_1=(c_1,r_1)\f$ and +\f$ K_2=(c_2, r_2)\f$ is defined as the distance of their centers minus +their radii: +\f[ \delta(K_1, K_2) = \|c_1-c_2\|-r_1-r_2. \f] +This predicate determines if a vertex in the Apollonius diagram +(the center of the yellow circle) is destroyed when a new circle is +inserted in the diagram (the green circle). In the Apollonius graph +it tells us if a triangular face of the diagram is to be destroyed or +not. + +\cgalFigureBegin{figag2vc,apollonius-vertex_conflict-false.png,apollonius-vertex_conflict-true.png} +The `Vertex_conflict_2` predicate. The left-most, bottom-most and top-most circles define the tritangent circle in the middle. We want to determine the sign of the distance of the left-most circle from the one in the middle. The almost horizontal curve is the bisector of the top-most and bottom-most circles. Left: the predicate returns `NEGATIVE`. Right: the predicate returns `POSITIVE`. +\cgalFigureEnd + +What we essentially want to compute when we construct incrementally a +Voronoi diagram, is whether the object to be inserted destroys an edge +of the Voronoi diagram or not. In the case of points this is really +easy and it amounts to the well known incircle test. +In the case +of circles the situation is more complicated. We can have six possible +outcomes as to what portion of an edge of the Apollonius diagram the +new circle destroys (see \cgalFigureRef{figag2edgeconflict} ). The first +two can be answered directly by the `Vertex_conflict_2` predicate +evaluated for the two endpoints of the Apollonius diagram edge. This +is due to the fact that the value of the `Vertex_conflict_2` +predicate is different for the two endpoints. If the two values are +the same then we need an additional test which determines if the interior +of the Apollonius diagram edge is destroyed by the new circle. This is +what the `Finite_edge_interior_conflict_2` and +`Infinite_edge_interior_conflict_2` predicates do. In essence, it +is the same predicate (same idea) applied to two different types of +edges in the Apollonius diagram: a finite or an infinite edge. An edge +is infinite if its dual edge in the Apollonius graph connects the +site at infinity with the vertex corresponding to a (finite) circle; +otherwise it is a finite edge. + +\cgalFigureAnchor{figag2edgeconflict} +
+ + + + + + + + + + + + + +
+\image html ./apollonius-left_vertex.png +\image latex ./apollonius-left_vertex.png + +\image html ./apollonius-right_vertex.png +\image latex ./apollonius-right_vertex.png +
+\image html ./apollonius-no_conflict.png +\image latex ./apollonius-no_conflict.png + +\image html ./apollonius-entire_edge.png +\image latex ./apollonius-entire_edge.png +
+\image html ./apollonius-interior.png +\image latex ./apollonius-interior.png + +\image html ./apollonius-both_vertices.png +\image latex ./apollonius-both_vertices.png +
+
+\cgalFigureCaptionBegin{figag2edgeconflict} +The 6 possible outcomes of the +`Finite_edge_interior_conflict_2` predicate. Top left: only a +neighborhood around the left-most endpoint of the edge will be +destroyed. Top right: only a neighborhood around the right-most +endpoint of the edge will be destroyed. Middle left: no portion of the +edge is destroyed. Middle right: the entire edge will be +destroyed. Bottom left: a neighborhood in the interior of the edge +will be destroyed; the regions near the endpoints remain +unaffected. Bottom right: The neighborhood around the two endpoints +will be destroyed, but an interval in the interior of the edge will +remain in the new diagram. +\cgalFigureCaptionEnd + +The last predicate that we want to discuss is called +`Is_degenerate_edge_2`. It tells us whether an edge in the +Apollonius diagram is degenerate, that is if its two endpoints +coincide. In the Apollonius graph such an edge corresponds to one of +the additional edges that we use to triangulate the non-triangular +faces. + +The aforementioned predicates are part of the +`ApolloniusGraphTraits_2` concept of \cgal. \cgal also provides +a model for this concept, the +`Apollonius_graph_traits_2` class. The first +template parameter of this class must be a model of the `Kernel` +concept. The second template parameter is a tag that indicates what +operations are allowed in the computations that take place within the +traits class. +The two possible values of the `Method_tag` parameter are +`Integral_domain_without_division_tag` and `Field_with_sqrt_tag`. When +`Integral_domain_without_division_tag` is used, only ring operations are used during the +evaluation of the predicates, whereas if `Field_with_sqrt_tag` is +chosen, all four field operations, as well as square roots, are used +during the predicate evaluation. + +The `Apollonius_graph_traits_2` class provides exact +predicates if the number type in the kernel `K` is an exact number +type. This is to be associated with the type of operations allowed for +the predicate evaluation. For example `MP_Float` as number +type, with `Integral_domain_without_division_tag` as tag will give exact predicates, +whereas `MP_Float` with `Field_with_sqrt_tag` will give +inexact predicates. + +Although exact number types provide exact predicates and constructions, +their use often results in unacceptably large runtimes. +The class `Apollonius_graph_filtered_traits_2` +aims to paliate this shortcoming. Similar to a filtered kernel, it takes a +constructions kernel `CK`, a filtering kernel `FK` and an +exact kernel `EK`, as well as the corresponding tags +(`CM`, `FM` and `EM`, respectively). +Predicates are evaluated by first using the filtering kernel, and +if this fails the evaluation is performed using the exact kernel, +thus yielding exact predicates at a generally much cheaper cost +than directly using an exact number type. The constructions +are done using the kernel `CK`, which means that +they are not necessarily exact. All template parameters except +`CK` have default values, which are explained in the reference +manual. + +\section secapollonius2hierarchy The Apollonius Graph Hierarchy + +The `Apollonius_graph_hierarchy_2` class is nothing but the equivalent of the `Triangulation_hierarchy_2` +class, applied to the Apollonius graph. It consists of a series of +Apollonius graphs constructed in a manner analogous to the Delaunay +hierarchy by Devillers \cgalCite{d-iirdt-98}. The class +`Apollonius_graph_hierarchy_2` +has exactly the same interface and functionality as the +`Apollonius_graph_2` +class. Using the Apollonius graph hierarchy involves an additional +cost in space and time for maintaining the hierarchy. Our experiments +have shown that it usually pays off to use the hierarchy for inputs +consisting of more than 1,000 circles. This threshold holds for both +the construction of the Apollonius diagram itself, as well as for +nearest neighbor queries. + +\section secapollonius2examples Examples + +\subsection Apollonius_graph_2FirstExample First Example + +\cgalExample{Apollonius_graph_2/ag2_exact_traits.cpp} + +\subsection Apollonius_graph_2SecondExample Second Example + +\cgalExample{Apollonius_graph_2/ag2_exact_traits_sqrt.cpp} + +\subsection Apollonius_graph_2ThirdExample Third Example + +\cgalExample{Apollonius_graph_2/ag2_filtered_traits_no_hidden.cpp} + +\subsection Apollonius_graph_2FourthExample Fourth Example + +\cgalExample{Apollonius_graph_2/ag2_hierarchy.cpp} + +*/ +} /* namespace CGAL */ + diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_2.h new file mode 100644 index 00000000000..fb82e23c709 --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_2.h @@ -0,0 +1,743 @@ + +namespace CGAL { + +/*! +\ingroup PkgApolloniusGraph2Ref + +The class `Apollonius_graph_2` represents the Apollonius graph. +It supports insertions and deletions of sites. + +\tparam Gt is the geometric traits class and must be a model of `ApolloniusGraphTraits_2`. + +\tparam Agds is the Apollonius graph data structure and must be a model of `ApolloniusGraphDataStructure_2` +whose vertex and face must be models of `ApolloniusGraphVertexBase_2` and `TriangulationFaceBase_2`, +respectively. +It defaults to: +\code + CGAL::Triangulation_data_structure_2< + CGAL::Apollonius_graph_vertex_base_2, + CGAL::Triangulation_face_base_2 >` +\endcode + +\cgalHeading{Traversal of the Apollonius Graph} + +An Apollonius graph can be seen as a container of faces and vertices. +Therefore the Apollonius graph provides several iterators and +circulators that allow to traverse it (completely or partially). + +\cgalHeading{Traversal of the Convex Hull} + +Applied on the `infinite_vertex` the `incident_*` functions allow to +visit the vertices on the convex hull and the infinite edges and +faces. Note that a counterclockwise traversal of the vertices adjacent +to the `infinite_vertex` is a clockwise traversal of the convex hull. + +\code{.cpp} +CGAL::Apollonius_graph_2 ag; +CGAL::Apollonius_graph_2::Face f; + +ag.incident_vertices(ag.infinite_vertex()); +ag.incident_vertices(ag.infinite_vertex(), f); + +ag.incident_faces(ag.infinite_vertex()); +ag.incident_faces(ag.infinite_vertex(), f); + +ag.incident_edges(ag.infinite_vertex()); +ag.incident_edges(ag.infinite_vertex(), f); +\endcode + +\cgalModels `DelaunayGraph_2` + +\sa `CGAL::Apollonius_graph_traits_2` +\sa `CGAL::Apollonius_graph_filtered_traits_2` +\sa `CGAL::Apollonius_graph_hierarchy_2` +*/ +template< typename Gt, typename Agds > +class Apollonius_graph_2 { +public: + +/// \name Types +/// @{ + +/*! +A type for the underlying +data structure. +*/ +typedef Agds Data_structure; + +/*! +Same as the `Data_structure` type. This type has been introduced +in order for the `Apollonius_graph_2` class to be a +model of the `DelaunayGraph_2` concept. +*/ +typedef Data_structure Triangulation_data_structure; + +/*! +A type for the geometric traits. +*/ +typedef Gt Geom_traits; + +/*! +A type for the +point defined in the geometric traits. +*/ +typedef Gt::Point_2 Point_2; + +/*! +A type for the Apollonius site, defined in the geometric traits. +*/ +typedef Gt::Site_2 Site_2; + +/// @} + +/// \name Handles And Iterators +/// The vertices and faces of the Apollonius graph are accessed +/// through `handles`, `iterators`, and `circulators`. The iterators +/// and circulators are all bidirectional and non-mutable. The +/// circulators and iterators are assignable to the corresponding +/// handle types, and they are also convertible to the corresponding +/// handles. The edges of the Apollonius graph can also be visited +/// through iterators and circulators, the edge circulators and +/// iterators are also bidirectional and non-mutable. In the +/// following, we call infinite any face or edge incident to +/// the infinite vertex and the infinite vertex itself. Any other +/// feature (face, edge or vertex) of the Apollonius graph is said to +/// be finite. Some iterators (the `All` iterators ) allow to +/// visit finite or infinite features while the others (the `Finite` +/// iterators) visit only finite features. Circulators visit both +/// infinite and finite features. +/// @{ + +/*! +the edge type. +The `Edge(f,i)` is the edge common to faces `f` and +`f.neighbor(i)`. It is also the edge joining the vertices +`vertex(cw(i))` and `vertex(ccw(i))` of `f`. +\pre `i` must be `0`, `1` or `2`. +*/ +typedef Data_structure::Edge Edge; + +/*! +A type for a vertex. +*/ +typedef Data_structure::Vertex Vertex; + +/*! +A type for a face. +*/ +typedef Data_structure::Face Face; + +/*! +A type for a handle to a vertex. +*/ +typedef Data_structure::Vertex_handle Vertex_handle; + +/*! +A type for a handle to a face. +*/ +typedef Data_structure::Face_handle Face_handle; + +/*! +A type for a circulator over vertices incident to a given vertex. +*/ +typedef Data_structure::Vertex_circulator Vertex_circulator; + +/*! +A type for a circulator over faces incident to a given vertex. +*/ +typedef Data_structure::Face_circulator Face_circulator; + +/*! +A type for a circulator over edges incident to a given vertex. +*/ +typedef Data_structure::Edge_circulator Edge_circulator; + +/*! +A type for an iterator over all vertices. +*/ +typedef Data_structure::Vertex_iterator +All_vertices_iterator; + +/*! +A type for an iterator over all faces. +*/ +typedef Data_structure::Face_iterator +All_faces_iterator; + +/*! +A type for an iterator over all edges. +*/ +typedef Data_structure::Edge_iterator +All_edges_iterator; + +/*! +An unsigned integral type. +*/ +typedef Data_structure::size_type size_type; + +/*! +A type for an iterator over finite vertices. +*/ +typedef unspecified_type Finite_vertices_iterator; + +/*! +A type for an iterator over finite faces. +*/ +typedef unspecified_type Finite_faces_iterator; + +/*! +A type for an iterator over finite edges. +*/ +typedef unspecified_type Finite_edges_iterator; + +/// @} + +/// \name Site Iterators +/// In addition to iterators and circulators for vertices and faces, +/// iterators for sites are provided. In particular there are +/// iterators for the entire set of sites, the hidden sites and the +/// visible sites of the Apollonius graph. +/// @{ + +/*! +A type for an iterator over all sites. +*/ +typedef unspecified_type Sites_iterator; + +/*! +A type for an iterator over all visible sites. +*/ +typedef unspecified_type Visible_sites_iterator; + +/*! +A type for an iterator over all hidden sites. +*/ +typedef unspecified_type Hidden_sites_iterator; + +/// @} + +/// \name Creation +/// @{ + +/*! +Creates an +Apollonius graph `ag` using `gt` as geometric traits. +*/ +Apollonius_graph_2(Gt gt=Gt()); + +/*! +Creates an Apollonius graph `ag` using `gt` as +geometric traits and inserts all sites in the range +[`first`, `beyond`). +\pre `Input_iterator` must be a model of `InputIterator`. The value type of `Input_iterator` must be `Site_2`. +*/ +template< class Input_iterator > +Apollonius_graph_2(Input_iterator first, Input_iterator beyond, +Gt gt=Gt()); + +/*! +Copy constructor. All faces and vertices are duplicated. After the +construction, +`ag` and `other` refer to two different Apollonius graphs : if +`other` is modified, `ag` is not. +*/ +Apollonius_graph_2(const Apollonius_graph_2& other); + +/*! +Assignment. If `ag` and `other` are the same object +nothing is done. Otherwise, all the vertices and faces are +duplicated. After the assignment, `ag` and `other` refer to +different Apollonius graphs : if `other` is modified, `ag` is +not. +*/ +Apollonius_graph_2 +operator=(const Apollonius_graph_2& other); + +/// @} + +/// \name Access Functions +/// @{ + +/*! +Returns a reference to the Apollonius graph traits object. +*/ +const Geom_traits& geom_traits() const; + +/*! +Returns a reference to the +underlying data structure. +*/ +const Data_structure& data_structure() const; + +/*! +Same as `data_structure()`. This +method has been added in compliance with the `DelaunayGraph_2` +concept. +*/ +const Data_structure& tds() const; + +/*! +Returns the dimension of the Apollonius graph. +*/ +int dimension() const; + +/*! +Returns the number of finite vertices. +*/ +size_type number_of_vertices() const; + +/*! +Returns the number of visible sites. +*/ +size_type number_of_visible_sites() const; + +/*! +Returns the number of hidden sites. +*/ +size_type number_of_hidden_sites() const; + +/*! +Returns the number of faces (both finite and infinite) of the +Apollonius graph. +*/ +size_type number_of_faces() const; + +/*! +Returns a face incident to the `infinite_vertex`. +*/ +Face_handle infinite_face() const; + +/*! +Returns the `infinite_vertex`. +*/ +Vertex_handle infinite_vertex() const; + +/*! +Returns a vertex distinct from the `infinite_vertex`. +\pre The number of (visible) vertices in the Apollonius graph must be at least one. +*/ +Vertex_handle finite_vertex() const; + +/// @} + +/// \name Face, Edge and Vertex Iterators +/// The following iterators allow respectively to visit finite faces, +/// finite edges and finite vertices of the Apollonius graph. These +/// iterators are non-mutable, bidirectional and their value types are +/// respectively `Face`, `Edge` and `Vertex`. They are all invalidated +/// by any change in the Apollonius graph. The following iterators +/// allow respectively to visit all (both finite and infinite) faces, +/// edges and vertices of the Apollonius graph. These iterators are +/// non-mutable, bidirectional and their value types are respectively +/// `Face`, `Edge` and `Vertex`. They are all invalidated by any +/// change in the Apollonius graph. +/// @{ + +/*! +Starts at an arbitrary finite vertex. +*/ +Finite_vertices_iterator finite_vertices_begin() const; + +/*! +Past-the-end iterator. +*/ +Finite_vertices_iterator finite_vertices_end() const; + +/*! +Starts at an arbitrary finite edge. +*/ +Finite_edges_iterator finite_edges_begin() const; + +/*! +Past-the-end iterator. +*/ +Finite_edges_iterator finite_edges_end() const; + +/*! +Starts at an arbitrary finite face. +*/ +Finite_faces_iterator finite_faces_begin() const; + +/*! +Past-the-end iterator. +*/ +Finite_faces_iterator finite_faces_end() const; + +/*! +Starts at an arbitrary vertex. +*/ +All_vertices_iterator all_vertices_begin() const; + +/*! +Past-the-end iterator. +*/ +All_vertices_iterator all_vertices_end() const; + +/*! +Starts at an arbitrary edge. +*/ +All_edges_iterator all_edges_begin() const; + +/*! +Past-the-end iterator. +*/ +All_edges_iterator all_edges_end() const; + +/*! +Starts at an arbitrary face. +*/ +All_faces_iterator all_faces_begin() const; + +/*! +Past-the-end iterator. +*/ +All_faces_iterator all_faces_end() const; + +/// @} + +/// \name Site Iterators +/// The following iterators allow respectively to visit all sites, the +/// visible sites and the hidden sites. These iterators are +/// non-mutable, bidirectional and their value type is `Site_2`. They +/// are all invalidated by any change in the Apollonius graph. +/// @{ + +/*! +Starts at an arbitrary site. +*/ +Sites_iterator sites_begin() const; + +/*! +Past-the-end iterator. +*/ +Sites_iterator sites_end() const; + +/*! +Starts at an arbitrary visible site. +*/ +Visible_sites_iterator visible_sites_begin() const; + +/*! +Past-the-end iterator. +*/ +Visible_sites_iterator visible_sites_end() const; + +/*! +Starts at an arbitrary hidden site. +*/ +Hidden_sites_iterator hidden_sites_begin() const; + +/*! +Past-the-end iterator. +*/ +Hidden_sites_iterator hidden_sites_end() const; + +/// @} + +/// \name Face, Edge and Vertex Circulators +/// The Apollonius graph also provides circulators that allow to visit +/// respectively all faces or edges incident to a given vertex or all +/// vertices adjacent to a given vertex. These circulators are +/// non-mutable and bidirectional. The operator `operator++` moves the +/// circulator counterclockwise around the vertex while the +/// `operator--` moves clockwise. A face circulator is invalidated by +/// any modification of the face pointed to. An edge circulator is +/// invalidated by any modification in one of the two faces incident +/// to the edge pointed to. A vertex circulator is invalidated by any +/// modification in any of the faces adjacent to the vertex pointed +/// to. +/// @{ + +/*! +Starts at an arbitrary face incident +to `v`. +*/ +Face_circulator incident_faces(Vertex_handle v) const; + +/*! +Starts at face `f`. +\pre Face `f` is incident to vertex `v`. +*/ +Face_circulator incident_faces(Vertex_handle v, Face_handle f) const; + +/*! +Starts at an arbitrary edge incident +to `v`. +*/ +Edge_circulator incident_edges(Vertex_handle v) const; + +/*! +Starts at the first edge of `f` incident to +`v`, in counterclockwise order around `v`. +\pre Face `f` is incident to vertex `v`. +*/ +Edge_circulator incident_edges(Vertex_handle v, Face_handle f) const; + +/*! +Starts at an arbitrary vertex incident +to `v`. +*/ +Vertex_circulator incident_vertices(Vertex_handle v) const; + +/*! +Starts at the first vertex of `f` adjacent to `v` +in counterclockwise order around `v`. +\pre Face `f` is incident to vertex `v`. +*/ +Vertex_circulator incident_vertices(Vertex_handle v, Face_handle f) const; + +/// @} + +/// \name Predicates +/// The class `Apollonius_graph_2` provides methods to test the finite +/// or infinite character of any feature. +/// @{ + +/*! +`true`, iff `v` is the `infinite_vertex`. +*/ +bool +is_infinite(Vertex_handle v) const; + +/*! +`true`, iff face `f` is infinite. +*/ +bool +is_infinite(Face_handle f) const; + +/*! +`true`, iff edge `(f,i)` is infinite. +*/ +bool is_infinite(Face_handle f, int i) const; + +/*! +`true`, iff edge `e` is infinite. +*/ +bool +is_infinite(const Edge& e) const; + +/*! +`true`, iff edge `*ec` is infinite. +*/ +bool +is_infinite(Edge_circulator ec) const; + +/// @} + +/// \name Insertion +/// @{ + +/*! +Inserts the sites in the range +[`first`,`beyond`). The number of sites in the range +[`first`, `beyond`) is returned. +\pre `Input_iterator` must be a model of `InputIterator` and its value type must be `Site_2`. +*/ +template< class Input_iterator > +unsigned int insert(Input_iterator first, Input_iterator beyond); + +/*! +Inserts the +site `s` in the Apollonius graph. If `s` is visible then the +vertex handle of `s` is returned, otherwise +`Vertex_handle(nullptr)` is returned. +*/ +Vertex_handle insert(const Site_2& s); + +/*! +Inserts `s` in the Apollonius graph using the site +associated with `vnear` as an estimate for the nearest neighbor of +the center of `s`. If `s` is visible then the vertex handle of +`s` is returned, otherwise `Vertex_handle(nullptr)` is +returned. +*/ +Vertex_handle insert(const Site_2& s, Vertex_handle vnear); + +/// @} + +/// \name Removal +/// @{ + +/*! +Removes the site +associated to the vertex handle `v` from the Apollonius +graph. +\pre `v` must correspond to a valid finite vertex of the Apollonius graph. +*/ +void remove(Vertex_handle v); + +/// @} + +/// \name Nearest Neighbor Location +/// @{ + +/*! +Finds the nearest neighbor of the point `p`. In other words it +finds the site whose Apollonius cell contains `p`. Ties are broken +arbitrarily and one of the nearest neighbors of `p` is +returned. If there are no visible sites in the Apollonius diagram +`Vertex_handle(nullptr)` is returned. +*/ +Vertex_handle nearest_neighbor(const Point_2& p) const; + +/*! +Finds the nearest neighbor of the point +`p` using the site associated with `vnear` as an +estimate for the nearest neighbor of `p`. Ties are broken +arbitrarily and one of the nearest neighbors of `p` is +returned. If there are no visible sites in the Apollonius diagram +`Vertex_handle(nullptr)` is returned. +*/ +Vertex_handle nearest_neighbor(const Point_2& p, Vertex_handle vnear) const; + +/// @} + +/// \name Access to the Dual +/// The `Apollonius_graph_2` class provides access to the duals of the +/// faces of the graph. The dual of a face of the Apollonius graph is +/// a site. If the originating face is infinite, its dual is a site +/// with center at infinity (or equivalently with infinite weight), +/// which means that it can be represented geometrically as a line. If +/// the originating face is finite, its dual is a site with finite +/// center and weight. In the following three methods the returned +/// object is assignable to either `Site_2` or `Gt::Line_2`, depending +/// on whether the corresponding face of the Apollonius graph is +/// finite or infinite, respectively. +/// @{ + +/*! +Returns the +dual corresponding to the face handle `f`. The returned object can +be assignable to one of the following: `Site_2`, `Gt::Line_2`. +*/ +Gt::Object_2 dual(Face_handle f) const; + +/*! +Returns the +dual of the face to which `it` points to. The returned object can +be assignable to one of the following: `Site_2`, `Gt::Line_2`. +*/ +Gt::Object_2 dual(All_faces_iterator it) const; + +/*! +Returns +the dual of the face to which `it` points to. The returned +object can be assignable to one of the following: `Site_2`, +`Gt::Line_2`. +*/ +Gt::Object_2 dual(Finite_faces_iterator it) const; + +/// @} + +/// \name I/O +/// @{ + +/*! +Draws the Apollonius graph to +the stream `str`. +\pre The following operators must be defined: +`Stream& operator<<(Stream&, Gt::Segment_2)`, +`Stream& operator<<(Stream&, Gt::Ray_2)`. + +*/ +template< class Stream > +Stream& draw_primal(Stream& str) const; + +/*! +Draws the dual of the +Apollonius graph, i.e., the Apollonius diagram, to the stream +`str`. +\pre The following operators must be defined: +`Stream& operator<<(Stream&, Gt::Segment_2)`, +`Stream& operator<<(Stream&, Gt::Ray_2)`, +`Stream& operator<<(Stream&, Gt::Line_2)`. + +*/ +template < class Stream > +Stream& draw_dual(Stream& str) const; + +/*! +Draws the edge +`e` of the Apollonius graph to the stream `str`. +\pre The following operators must be defined: +`Stream& operator<<(Stream&, Gt::Segment_2)`, +`Stream& operator<<(Stream&, Gt::Ray_2)`. + +*/ +template< class Stream > +Stream& draw_primal_edge(const Edge& e, Stream& str) const; + +/*! +Draws the dual of the +edge `e` to the stream `str`. The dual of `e` is an edge +of the Apollonius diagram. +\pre The following operators must be defined: +`Stream& operator<<(Stream&, Gt::Segment_2)`, +`Stream& operator<<(Stream&, Gt::Ray_2)`, +`Stream& operator<<(Stream&, Gt::Line_2)`. + +*/ +template< class Stream > +Stream& draw_dual_edge(const Edge& e, Stream& str) const; + +/*! +Writes the current +state of the Apollonius graph to an output stream. In particular, +all visible and hidden sites are written as well as the +underlying combinatorial data structure. +*/ +void file_output(std::ostream& os) const; + +/*! +Reads the state of the +Apollonius graph from an input stream. +*/ +void file_input(std::istream& is); + +/*! +Writes the current state of the Apollonius graph to an output stream. +*/ +std::ostream& operator<<(std::ostream& os, const Apollonius_graph_2& ag) const; + +/*! +Reads the state of the Apollonius graph from an input stream. +*/ +std::istream& operator>>(std::istream& is, const Apollonius_graph_2& ag); + +/// @} + +/// \name Validity Check +/// @{ + +/*! +Checks the validity of the Apollonius graph. If `verbose` is +`true` a short message is sent to `std::cerr`. If `level` +is 0, only the data structure is validated. If `level` is 1, then +both the data structure and the Apollonius graph are +validated. Negative values of `level` always return true, and +values greater than 1 are equivalent to `level` being 1. +*/ +bool is_valid(bool verbose = false, int level = 1) const; + +/// @} + +/// \name Miscellaneous +/// @{ + +/*! +Clears all contents of the Apollonius graph. +*/ +void clear(); + +/*! +The Apollonius graphs +`other` and `ag` are swapped. `ag.swap(other)` should +be preferred to `ag = other` or to `ag(other)` if +`other` is deleted afterwards. +*/ +void swap(Apollonius_graph_2& other); + +/// @} + +}; /* end Apollonius_graph_2 */ +} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_filtered_traits_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_filtered_traits_2.h new file mode 100644 index 00000000000..155a7b240cb --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_filtered_traits_2.h @@ -0,0 +1,78 @@ + +namespace CGAL { + +/*! +\ingroup PkgApolloniusGraph2Ref + +The class `Apollonius_graph_filtered_traits_2` provides a model for the +`ApolloniusGraphTraits_2` concept. + +The class `Apollonius_graph_filtered_traits_2` uses the filtering technique \cgalCite{cgal:bbp-iayed-01} +to achieve traits for the `Apollonius_graph_2` class +with efficient and exact predicates given an exact +kernel `EK` and a filtering kernel `FK`. The geometric +constructions associated provided by this class are equivalent +to those provided by the traits class +`Apollonius_graph_traits_2`, which means that they may +be inexact. + +This class has six template parameters. The first, third and fifth +template parameters must be a models of the `Kernel` concept. The +second, fourth and sixth template parameters correspond to how +predicates are evaluated. There are two predefined possible values for +`Method_tag`, namely `CGAL::Field_with_sqrt_tag` and +`CGAL::Integral_domain_without_division_tag`. The first one must be used when the number type +used in the representation supports the exact evaluation of signs of +expressions involving all four basic operations and square roots, +whereas the second one requires the exact evaluation of signs of +ring-type expressions, i.e., expressions involving only additions, +subtractions and multiplications. +The way the predicates are evaluated is discussed in +\cgalCite{cgal:ke-ppawv-02}, \cgalCite{cgal:ke-rctac-03}. + +The default values for the template parameters are as follows: +`CM = CGAL::Integral_domain_without_division_tag`, +`EK = CGAL::Simple_cartesian`, +`EM = CM`, +`FK = CGAL::Simple_cartesian >`, +`FM = CM`. + +\cgalModels `ApolloniusGraphTraits_2` + +\sa `Kernel` +\sa `ApolloniusGraphTraits_2` +\sa `CGAL::Integral_domain_without_division_tag` +\sa `CGAL::Field_with_sqrt_tag` +\sa `CGAL::Apollonius_graph_2` +\sa `CGAL::Apollonius_graph_traits_2` + +*/ +template< typename CK, typename CM, typename EK, typename EM, typename FK, typename FM > +class Apollonius_graph_filtered_traits_2 { +public: + +/// \name Creation +/// @{ + +/*! +%Default constructor. +*/ +Apollonius_graph_filtered_traits_2(); + +/*! +Copy +constructor. +*/ +Apollonius_graph_filtered_traits_2 +(Apollonius_graph_filtered_traits_2 other); + +/*! +Assignment +operator. +*/ +Apollonius_graph_filtered_traits_2 operator=(other); + +/// @} + +}; /* end Apollonius_graph_filtered_traits_2 */ +} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_2.h new file mode 100644 index 00000000000..778dd9160e1 --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_2.h @@ -0,0 +1,231 @@ + +namespace CGAL { + +/*! +\ingroup PkgApolloniusGraph2Ref + +We provide an alternative to the class +`Apollonius_graph_2` for the dynamic +construction of the Apollonius graph. The `Apollonius_graph_hierarchy_2` class maintains +a hierarchy of Apollonius graphs. The bottom-most level of the +hierarchy contains the full Apollonius diagram. A site that +is in level \f$ i\f$, is in level \f$ i+1\f$ with probability \f$ 1/\alpha\f$ +where \f$ \alpha > 1\f$ is some constant. The difference between the +`Apollonius_graph_2` class and the +`Apollonius_graph_hierarchy_2` is on how the nearest neighbor location is done. Given a +point \f$ p\f$ the location is done as follows: at the top most level we +find the nearest neighbor of \f$ p\f$ as in the +`Apollonius_graph_2` class. At every subsequent level \f$ i\f$ +we use the nearest neighbor found at level \f$ i+1\f$ to find the nearest +neighbor at level \f$ i\f$. This is a variant of the corresponding +hierarchy for points found in \cgalCite{d-iirdt-98}. + +The class has two template parameters which have essentially the same +meaning as in the `Apollonius_graph_2` class. + +\tparam Gt is the geometric traits class and must be a model of `ApolloniusGraphTraits_2`. + +\tparam Agds is the Apollonius graph data structure and must be a model of `ApolloniusGraphDataStructure_2` +whose vertex and face must be models of `ApolloniusGraphHierarchyVertexBase_2` and `TriangulationFaceBase_2`, respectively. +It defaults to: +\code + CGAL::Triangulation_data_structure_2< + CGAL::Apollonius_graph_hierarchy_vertex_base_2 >, + CGAL::Triangulation_face_base_2 > +\endcode + +\cgalHeading{Heritage} + +The `Apollonius_graph_hierarchy_2` class derives publicly from the +`Apollonius_graph_2` class. The interface is +the same with its base class. In the sequel only the methods +overridden are documented. + +`Apollonius_graph_hierarchy_2` does not introduce other types than those introduced by +its base class `Apollonius_graph_2`. + +\sa `CGAL::Apollonius_graph_2` +\sa `CGAL::Apollonius_graph_traits_2` +\sa `CGAL::Apollonius_graph_filtered_traits_2` +*/ +template< typename Gt, typename Agds > +class Apollonius_graph_hierarchy_2 : public CGAL::Apollonius_graph_2 { +public: + +/// \name Creation +/// @{ + +/*! +Creates an hierarchy of Apollonius graphs using `gt` as +geometric traits. +*/ +Apollonius_graph_hierarchy_2(Gt gt=Gt()); + +/*! +Creates an Apollonius graph hierarchy using +`gt` as geometric traits and inserts all sites in the +range [`first`, `beyond`). +*/ +template< class Input_iterator > +Apollonius_graph_hierarchy_2(Input_iterator first, Input_iterator beyond, Gt gt=Gt()); + +/*! +Copy constructor. All faces, vertices, and inter-level pointers +are duplicated. After the construction, `agh` and `other` refer +to two different Apollonius graph hierarchies: if +`other` is modified, `agh` is not. +*/ +Apollonius_graph_hierarchy_2(const Apollonius_graph_hierarchy_2& other); + +/*! +Assignment. All faces, vertices and inter-level pointers +are duplicated. After the construction, `agh` and `other` refer +to two different Apollonius graph hierarchies: if +`other` is modified, `agh` is not. +*/ +Apollonius_graph_hierarchy_2 +operator=(Apollonius_graph_hierarchy_2 +other); + +/// @} + +/// \name Insertion +/// @{ + +/*! +Inserts the sites in the range +[`first`,`beyond`). The number of sites in the range +[`first`, `beyond`) is returned. +\pre `Input_iterator` must be a model of `InputIterator` and its value type must be `Site_2`. +*/ +template< class Input_iterator > +unsigned int insert(Input_iterator first, Input_iterator beyond); + +/*! +Inserts the +site `s` in the Apollonius graph hierarchy. If `s` +is visible then the vertex handle of `s` is returned, otherwise +`Vertex_handle(nullptr)` is returned. +*/ +Vertex_handle insert(const Site_2& s); + +/*! +Inserts `s` in the Apollonius graph hierarchy using the +site associated with `vnear` as +an estimate for the nearest neighbor of the center of `s`. +If `s` is visible then the vertex handle of `s` is +returned, otherwise `Vertex_handle(nullptr)` is returned. +A call to this method is equivalent to `agh.insert(s);` and it has +been added for the sake of conformity with the interface of the +`Apollonius_graph_2` class. +*/ +Vertex_handle insert(const Site_2& s, Vertex_handle vnear); + +/// @} + +/// \name Removal +/// @{ + +/*! +Removes the site +associated to the vertex handle `v` from the Apollonius +graph hierarchy. +\pre `v` must correspond to a valid finite vertex of the Apollonius graph hierarchy. +*/ +void remove(Vertex_handle v); + +/// @} + +/// \name Nearest Neighbor Location +/// @{ + +/*! +Finds the nearest neighbor of the point `p`. In other words it +finds the site whose Apollonius cell contains `p`. Ties are broken +arbitrarily and one of the nearest neighbors of `p` is +returned. If there are no visible sites in the Apollonius diagram +`Vertex_handle(nullptr)` is returned. +*/ +Vertex_handle nearest_neighbor(const Point_2& p) const; + +/*! +Finds the nearest neighbor of the point +`p`. If there are no visible sites in the Apollonius diagram +`Vertex_handle(nullptr)` is returned. +A call to this method is equivalent to +`agh.nearest_neighbor(p);` and it has been added for the sake of +conformity with the interface of the +`Apollonius_graph_2` class. +*/ +Vertex_handle nearest_neighbor(const Point_2& p, Vertex_handle vnear) const; + +/// @} + +/// \name I/O +/// @{ + +/*! +Writes the current +state of the Apollonius graph hierarchy to an output stream. In particular, +all visible and hidden sites are written as well as the +underlying combinatorial hierarchical data structure. +*/ +void file_output(std::ostream& os) const; + +/*! +Reads the state of the +Apollonius graph hierarchy from an input stream. +*/ +void file_input(std::istream& is); + +/*! +Writes the current state of the Apollonius graph hierarchy to an +output stream. +*/ +std::ostream& operator<<(std::ostream& os, Apollonius_graph_hierarchy_2 agh) const; + +/*! +Reads the state of the Apollonius graph hierarchy from an input stream. +*/ +std::istream& operator>>(std::istream& is, Apollonius_graph_hierarchy_2 agh); + +/// @} + +/// \name Validity Check +/// @{ + +/*! +Checks the validity of the Apollonius graph hierarchy. If +`verbose` is `true` a short message is sent to +`std::cerr`. If `level` is 0, the data structure at all levels +is validated, as well as the inter-level pointers. If `level` is +1, then the data structure at all levels is validated, the inter-level +pointers are validated and all levels of the Apollonius graph +hierarchy are also validated. Negative values of `level` always +return `true`, and values greater than 1 are equivalent to +`level` being 1. +*/ +bool is_valid(bool verbose = false, int level = 1) const; + +/// @} + +/// \name Miscellaneous +/// @{ + +/*! +Clears all contents of the Apollonius graph +hierarchy. +*/ +void clear(); + +/*! +The Apollonius graph hierarchies `other` and `agh` are +swapped. `agh.swap(other)` should be preferred to `agh = other` +or to `agh(other)` if `other` is deleted afterwards. +*/ +void swap(Apollonius_graph_hierarchy_2& other); + +/// @} + +}; /* end Apollonius_graph_hierarchy_2 */ +} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_vertex_base_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_vertex_base_2.h new file mode 100644 index 00000000000..c09d6255ab5 --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_hierarchy_vertex_base_2.h @@ -0,0 +1,49 @@ + +namespace CGAL { + +/*! +\ingroup PkgApolloniusGraph2Ref + +The class `Apollonius_graph_hierarchy_vertex_base_2` provides a model for the +`ApolloniusGraphHierarchyVertexBase_2` concept, which is the +vertex base required by the +`Apollonius_graph_hierarchy_2` class. The class +`Apollonius_graph_hierarchy_vertex_base_2` is templated by a class `Agvb` which must be a model +of the `ApolloniusGraphVertexBase_2` concept. + +\cgalModels `ApolloniusGraphHierarchyVertexBase_2` + +\sa `CGAL::Apollonius_graph_vertex_base_2` +\sa `CGAL::Triangulation_data_structure_2` +\sa `CGAL::Apollonius_graph_hierarchy_2` +*/ +template< typename Agvb > +class Apollonius_graph_hierarchy_vertex_base_2 : Agvb { +public: + +/// \name Creation +/// @{ + +/*! +%Default constructor. +*/ +Apollonius_graph_hierarchy_vertex_base_2(); + +/*! +Constructs a vertex associated with the site `s` and +embedded at the center of `s`. +*/ +Apollonius_graph_hierarchy_vertex_base_2(const Site_2& s); + +/*! +Constructs a vertex associated with +the site `s`, embedded at the center of `s`, +and pointing to the face associated with the face +handle `f`. +*/ +Apollonius_graph_hierarchy_vertex_base_2(const Site_2& s, Face_handle f); + +/// @} + +}; /* end Apollonius_graph_hierarchy_vertex_base_2 */ +} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_traits_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_traits_2.h new file mode 100644 index 00000000000..3fe29ef740b --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_traits_2.h @@ -0,0 +1,54 @@ + +namespace CGAL { + +/*! +\ingroup PkgApolloniusGraph2Ref + +The class `Apollonius_graph_traits_2` provides a model for the +`ApolloniusGraphTraits_2` concept. +This class has two template parameters. The first template parameter +must be a model of the `Kernel` concept. The second template +parameter corresponds to how predicates are evaluated. There are two +predefined possible values for `Method_tag`, namely +`CGAL::Field_with_sqrt_tag` and `CGAL::Integral_domain_without_division_tag`. The first one +must be used when the number type used in the representation supports +the exact evaluation of signs of expressions involving all four basic +operations and square roots, whereas the second one requires the exact +evaluation of signs of ring-type expressions, i.e., expressions +involving only additions, subtractions and multiplications. The +default value for `Method_tag` is `CGAL::Integral_domain_without_division_tag`. +The way the predicates are evaluated is discussed in +\cgalCite{cgal:ke-ppawv-02}, \cgalCite{cgal:ke-rctac-03}. + +\cgalModels `ApolloniusGraphTraits_2` + +\sa `CGAL::Apollonius_graph_2` +\sa `CGAL::Apollonius_graph_filtered_traits_2` +*/ +template< typename K, typename Method_tag > +class Apollonius_graph_traits_2 { +public: + +/// \name Creation +/// @{ + +/*! +%Default constructor. +*/ +Apollonius_graph_traits_2(); + +/*! +Copy constructor. +*/ +Apollonius_graph_traits_2(const Apollonius_graph_traits_2& other); + +/*! +Assignment operator. +*/ +Apollonius_graph_traits_2 +operator=(const Apollonius_graph_traits_2& other); + +/// @} + +}; /* end Apollonius_graph_traits_2 */ +} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_vertex_base_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_vertex_base_2.h new file mode 100644 index 00000000000..ae9eca3dc6e --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_vertex_base_2.h @@ -0,0 +1,54 @@ + +namespace CGAL { + +/*! +\ingroup PkgApolloniusGraph2Ref + +The class `Apollonius_graph_vertex_base_2` provides a model for the +`ApolloniusGraphVertexBase_2` concept which is the vertex base +required by the `ApolloniusGraphDataStructure_2` concept. The +class `Apollonius_graph_vertex_base_2` has two template arguments, the first being the +geometric traits of the Apollonius graph and should be a model of the +concept `ApolloniusGraphTraits_2`. The second is a Boolean which +controls whether hidden sites are actually stored. Such a +control is important if the user is not interested in hidden sites +and/or if only insertions are made, in which case no hidden +site can become visible. If `StoreHidden` is set to +`true`, hidden sites are stored, otherwise they are +discarded. By default `StoreHidden` is set to `true`. + +\cgalModels `ApolloniusGraphVertexBase_2` + +\sa `CGAL::Triangulation_data_structure_2` +\sa `CGAL::Apollonius_graph_hierarchy_vertex_base_2` +*/ +template< typename Gt, typename StoreHidden > +class Apollonius_graph_vertex_base_2 { +public: + +/// \name Creation +/// @{ + +/*! +%Default constructor. +*/ +Apollonius_graph_vertex_base_2(); + +/*! +Constructs a vertex associated with the site `s` and +embedded at the center of `s`. +*/ +Apollonius_graph_vertex_base_2(const Site_2& s); + +/*! +Constructs a vertex associated with +the site `s`, embedded at the center of `s`, +and pointing to the face associated with the face +handle `f`. +*/ +Apollonius_graph_vertex_base_2(const Site_2& s, Face_handle f); + +/// @} + +}; /* end Apollonius_graph_vertex_base_2 */ +} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_site_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_site_2.h new file mode 100644 index 00000000000..162a6e46259 --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_site_2.h @@ -0,0 +1,76 @@ + +namespace CGAL { + +/*! +\ingroup PkgApolloniusGraph2Ref + +The class `Apollonius_site_2` is a model for the concept +`ApolloniusSite_2`. It is parametrized by a template parameter +`K` which must be a model of the `Kernel` concept. + +\cgalModels `ApolloniusSite_2` + +\cgalHeading{Types} + +The class `Apollonius_site_2` does not introduce any types in addition to the +concept `ApolloniusSite_2`. + +\cgalHeading{I/O} + +The I/O operators are defined for `iostream`. + +The information output in the `iostream` is: the point of the +Apollonius site and its weight. + +\sa `CGAL::Qt_widget` +\sa `CGAL::Apollonius_graph_traits_2` +\sa `CGAL::Apollonius_graph_filtered_traits_2` +*/ +template< typename K > +class Apollonius_site_2 { +public: + +/// \name Creation +/// @{ + +/*! + +*/ +Apollonius_site_2(Point_2 p=Point_2(), Weight w= Weight(0)); + +/*! +Copy constructor. +*/ +Apollonius_site_2(const Apollonius_site_2& other); + +/// @} + +}; /* end Apollonius_site_2 */ + +/*! +Inserts the +Apollonius site `s` into the stream `os`. +\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`. +\pre The insert operator must be defined for `Point_2` and `Weight`. +\relates Apollonius_site_2 +*/ +std::ostream& operator<<(std::ostream& os, const Apollonius_site_2& s) const; + +/*! +Reads an Apollonius site from the stream `is` and assigns it +to `s`. +\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`. +\pre The extract operator must be defined for `Point_2` and `Weight`. +\relates Apollonius_site_2 +*/ +std::istream& operator>>(std::istream& is, const Apollonius_site_2& s); + +/*! +Inserts the Apollonius site `s` into the `Qt_widget` stream `w`. +\note Included through `CGAL/IO/Qt_widget_Apollonius_site_2.h`. +\pre The insert operator must be defined for `K::Circle_2`. +\relates Apollonius_site_2 +*/ +Qt_widget& operator<<(Qt_widget& w, const Apollonius_site_2& s) const; + +} /* end namespace CGAL */ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphDataStructure_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphDataStructure_2.h new file mode 100644 index 00000000000..8c3209da2e8 --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphDataStructure_2.h @@ -0,0 +1,68 @@ + +/*! +\ingroup PkgApolloniusGraph2Concepts +\cgalConcept + +The concept `ApolloniusGraphDataStructure_2` refines the concept +`TriangulationDataStructure_2`. In addition +it provides two methods for the insertion and removal of a degree 2 +vertex in the data structure. The insertion method adds a new vertex +to the specified edge, thus creating two new edges. Moreover, it +creates two new faces that have the two newly created edges in +common (see figure below). The removal method performs the reverse +operation. + +\image html insert_degree_2.png +\image latex insert_degree_2.png + +
Insertion and removal of degree 2 vertices. Left to right: +The edge `(f,i)` is replaced by two edges by means of inserting a +vertex `v` on the edge. The faces \f$ f_1\f$ and \f$ f_2\f$ are +created. Right to left: the faces \f$ f_1\f$ and \f$ f_2\f$ are +destroyed. The vertex `v` is deleted and its two adjacent edges are +merged.
+ +We only describe the additional requirements with respect to the +`TriangulationDataStructure_2` concept. + +\cgalRefines `TriangulationDataStructure_2` + +\cgalHasModel `CGAL::Triangulation_data_structure_2` + +\sa `TriangulationDataStructure_2` +\sa `ApolloniusGraphVertexBase_2` +\sa `TriangulationFaceBase_2` + +*/ + +class ApolloniusGraphDataStructure_2 { +public: + +/// \name Insertion +/// @{ + +/*! +inserts a degree two vertex and two faces adjacent to it that have two common edges. + +The edge defined by the face handle `f` and the integer `i` is duplicated. It returns a handle +to the vertex created. +*/ +Vertex_handle insert_degree_2(Face_handle f, int i); + +/// @} + +/// \name Removal +/// @{ + +/*! +Removes a degree 2 +vertex and the two faces adjacent to it. The two edges of the star of +`v` that are not incident to it are collapsed. +\pre The degree of `v` must be equal to 2. +*/ +void remove_degree_2(Vertex_handle v); + +/// @} + +}; /* end ApolloniusGraphDataStructure_2 */ + diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphHierarchyVertexBase_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphHierarchyVertexBase_2.h new file mode 100644 index 00000000000..8145923b669 --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphHierarchyVertexBase_2.h @@ -0,0 +1,85 @@ + +/*! +\ingroup PkgApolloniusGraph2Concepts +\cgalConcept + +The vertex of an Apollonius graph +included in an Apollonius graph hierarchy has to provide +some pointers to the corresponding vertices in the +graphs of the next and preceding levels. +Therefore, the concept `ApolloniusGraphHierarchyVertexBase_2` +refines the concept `ApolloniusGraphVertexBase_2`, by +adding two vertex handles to the corresponding vertices for the +next and previous level graphs. + +\cgalRefines `ApolloniusGraphVertexBase_2` + +\cgalHeading{Types} + +`ApolloniusGraphHierarchyVertexBase_2` does not introduce any +types in addition to those of `ApolloniusGraphVertexBase_2`. + +\cgalHasModel `CGAL::Apollonius_graph_hierarchy_vertex_base_2 >` + +\sa `ApolloniusGraphDataStructure_2` +\sa `CGAL::Apollonius_graph_hierarchy_2` +\sa `CGAL::Triangulation_data_structure_2` +*/ +class ApolloniusGraphHierarchyVertexBase_2 { +public: + +/// \name Creation +/// @{ + +/*! +%Default constructor. +*/ +ApolloniusGraphHierarchyVertexBase_2(); + +/*! +Constructs a vertex associated with the site `s` and +embedded at the center of `s`. +*/ +ApolloniusGraphHierarchyVertexBase_2(Site_2 s).; + +/*! +Constructs a vertex associated with +the site `s`, embedded at the center of `s`, +and pointing to face `f`. +*/ +ApolloniusGraphHierarchyVertexBase_2(Site_2 s, Face_handle f).; + +/// @} + +/// \name Operations +/// @{ + +/*! +Returns a handle to the corresponding +vertex of the next level Apollonius graph. If such a vertex does not +exist `Vertex_handle(nullptr)` is returned. +*/ +Vertex_handle up(); + +/*! +Returns a handle to the corresponding +vertex of the previous level Apollonius graph. +*/ +Vertex_handle down(); + +/*! +Sets the handle for the +vertex of the next level Apollonius graph. +*/ +void set_up(Vertex_handle u); + +/*! +Sets the handle for the +vertex of the previous level Apollonius graph; +*/ +void set_down(Vertex_handle d); + +/// @} + +}; /* end ApolloniusGraphHierarchyVertexBase_2 */ + diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphTraits_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphTraits_2.h new file mode 100644 index 00000000000..5ef6ff44848 --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphTraits_2.h @@ -0,0 +1,397 @@ + +/*! +\ingroup PkgApolloniusGraph2Concepts +\cgalConcept + +\cgalRefines `TriangulationTraits_2` + +The concept `ApolloniusGraphTraits_2` provides the traits +requirements for the `Apollonius_graph_2` class. In particular, +it provides a type `Site_2`, which must be a model of the concept +`ApolloniusSite_2`. It also provides +constructions for sites and several function object +types for the predicates. + +\cgalHasModel `CGAL::Apollonius_graph_traits_2` +\cgalHasModel `CGAL::Apollonius_graph_filtered_traits_2` + +\sa `CGAL::Apollonius_graph_2` +\sa `CGAL::Apollonius_graph_traits_2` +\sa `CGAL::Apollonius_graph_filtered_traits_2` + +*/ + +class ApolloniusGraphTraits_2 { +public: + +/// \name Types +/// @{ + +/*! +A type for a point. +*/ +typedef unspecified_type Point_2; + +/*! +A type for an Apollonius site. Must be a model +of the concept `ApolloniusSite_2`. +*/ +typedef unspecified_type Site_2; + +/*! +A type for a line. Only required if access to +the dual of the Apollonius graph is required or if the primal +or dual diagram are inserted in a stream. +*/ +typedef unspecified_type Line_2; + +/*! +A type for a ray. Only required if access to +the dual of the Apollonius graph is required or if the primal +or dual diagram are inserted in a stream. +*/ +typedef unspecified_type Ray_2; + +/*! +A type for a segment. Only required if access to +the dual of the Apollonius graph is required or if the primal +or dual diagram are inserted in a stream. +*/ +typedef unspecified_type Segment_2; + +/*! +A type representing different types of objects +in two dimensions, namely: `Point_2`, `Site_2`, +`Line_2`, `Ray_2` and `Segment_2`. +*/ +typedef unspecified_type Object_2; + +/*! +A type for the field number type of sites. +*/ +typedef unspecified_type FT; + +/*! +A type for the ring number type of sites. +*/ +typedef unspecified_type RT; + +/*! +Must provide `template bool operator() ( T& t, +Object_2 o)` which assigns `o` to `t` if `o` was +constructed from an object of type `T`. Returns +`true`, if the assignment was possible. +*/ +typedef unspecified_type Assign_2; + +/*! +Must provide `template +Object_2 operator()( T t)` that constructs an object of type +`Object_2` that contains `t` and returns it. +*/ +typedef unspecified_type Construct_object_2; + +/*! + +A constructor for a point of the Apollonius diagram equidistant +from three sites. Must provide +`Point_2 operator()(Site_2 s1, Site_2 s2, Site_2 s3)`, which +constructs a point equidistant from the sites `s1`, `s2` and +`s3`. + +*/ +typedef unspecified_type Construct_Apollonius_vertex_2; + +/*! +A constructor for +a dual Apollonius site (a site whose center is a +vertex of the Apollonius diagram and its weight is the common +distance of its center from the three defining sites). +Must provide `Site_2 operator()(Site_2 s1, +Site_2 s2, Site_2 s3)`, which constructs a +dual site whose center \f$ c\f$ is equidistant from `s1`, `s2` and +`s3`, and its weight is equal to the (signed) distance of \f$ c\f$ +from `s1` (or `s2` or `s3`). + +Must also provide `Line_2 operator()(Site_2 s1, Site_2 s2)`, which +constructs a line bitangent to `s1` and `s2`. This line is the +dual site of `s1`, `s2` and the site at infinity; it can be +viewed as a dual Apollonius site whose center is at infinity +and its weight is infinite. + +*/ +typedef unspecified_type Construct_Apollonius_site_2; + +/*! +A predicate object type. Must +provide `Comparison_result operator()(Site_2 s1, +Site_2 s2)`, which compares the \f$ x\f$-coordinates of the centers of +`s1` and `s2`. +*/ +typedef unspecified_type Compare_x_2; + +/*! +A predicate object type. Must +provide `Comparison_result operator()(Site_2 s1, +Site_2 s2)`, which compares the \f$ y\f$-coordinates of the centers of +`s1` and `s2`. +*/ +typedef unspecified_type Compare_y_2; + +/*! +A predicate object type. Must +provide `Comparison_result operator()(Site_2 s1, +Site_2 s2)`, which compares the weights of `s1` +and `s2`. +*/ +typedef unspecified_type Compare_weight_2; + +/*! +A predicate object type. Must +provide `Orientation operator()(Site_2 s1, +Site_2 s2, Site_2 s3)`, which performs the +usual orientation test for the centers of the three sites +`s1`, `s2` and `s3`. + +Must also provide `Orientation operator()(Site_2 s1, Site_2 s2, +Site_2 s3, Site_2 p1, Site_2 p2)`, +which performs the usual orientation test for the Apollonius vertex of +`s1`, `s2`, `s3` and the centers of `p1` and +`p2`. +\pre the Apollonius vertex of `s1`, `s2` and `s3` must exist. +*/ +typedef unspecified_type Orientation_2; + +/*! +A predicate object type. Must +provide `bool operator()(Site_2 s1, +Site_2 s2)`, which returns `true` if the circle +corresponding to `s2` is contained in the closure of the disk +corresponding to `s1`, `false` otherwise. +*/ +typedef unspecified_type Is_hidden_2; + +/*! +A predicate object type. +Must provide `Oriented_side operator()(Site_2 s1, +Site_2 s2, Point_2 p)`, which returns +the oriented side of the bisector of `s1` and `s2` that +contains `p`. Returns `ON_POSITIVE_SIDE` if `p` lies in +the half-space of `s1` (i.e., `p` is closer to `s1` than +`s2`); returns `ON_NEGATIVE_SIDE` if `p` lies in the +half-space of `s2`; returns `ON_ORIENTED_BOUNDARY` if `p` +lies on the bisector of `s1` and `s2`. +*/ +typedef unspecified_type Oriented_side_of_bisector_2; + +/*! +A predicate object type. +Must provide `Sign operator()(Site_2 s1, Site_2 +s2, Site_2 s3, Site_2 q)`, which +returns the sign of the distance of `q` from the dual Apollonius +site of `s1`, `s2`, `s3`. +\pre the dual Apollonius site of `s1`, `s2`, `s3` must exist. + +Must also provide `Sign operator()(Site_2 s1, +Site_2 s2, Site_2 q)`, which returns the sign of the distance of +`q` from the bitangent line of `s1`, `s2` (a degenerate +dual Apollonius site, with its center at infinity). +*/ +typedef unspecified_type Vertex_conflict_2; + +/*! +A predicate object type. +Must provide `bool operator()(Site_2 s1, Site_2 s2, Site_2 s3, Site_2 s4, Site_2 q, bool b)`. +The sites `s1`, `s2`, `s3` and `s4` define an Apollonius edge that lies on the +bisector of `s1` and `s2` and has as endpoints the Apollonius +vertices defined by the triplets `s1`, `s2`, `s3` and +`s1`, `s4` and `s2`. The Boolean `b` denotes if the +two Apollonius vertices are in conflict with the site +`q` (in which case `b` should be `true`, otherwise +`false`). In case that `b` is `true`, the predicate +returns `true` if and only if the entire Apollonius edge is in +conflict with `q`. If `b` is `false`, the predicate returns +`false` if and only if `q` is not in conflict with the +Apollonius edge. +\pre the Apollonius vertices of `s1`, `s2`, `s3`, and `s1`, `s4`, `s2` must exist. + +Must also provide `bool operator()(Site_2 s1, +Site_2 s2, Site_2 s3, Site_2 q, bool b)`. The +sites `s1`, `s2`, `s3` and the site at infinity +\f$ s_\infty\f$ define an Apollonius edge that lies on the bisector of +`s1` and `s2` and has as endpoints the Apollonius vertices +defined by the triplets `s1`, `s2`, `s3` and `s1`, +\f$ s_\infty\f$ and `s2` (the second Apollonius vertex is actually at +infinity). The Boolean `b` denotes if the two Apollonius vertices +are in conflict with the site `q` (in which case `b` +should be `true`, otherwise `false`). +In case that `b` is `true`, the predicate +returns `true` if and only if the entire Apollonius edge is in +conflict with `q`. If `b` is `false`, the predicate returns +`false` if and only if `q` is not in conflict with the +Apollonius edge. +\pre the Apollonius vertex of `s1`, `s2`, `s3` must exist. + +Must finally provide `bool operator()(Site_2 s1, +Site_2 s2, Site_2 q, bool b)`. The +sites `s1`, `s2` and the site at infinity +\f$ s_\infty\f$ define an Apollonius edge that lies on the bisector of +`s1` and `s2` and has as endpoints the Apollonius vertices +defined by the triplets `s1`, `s2`, \f$ s_\infty\f$ and `s1`, +\f$ s_\infty\f$ and `s2` (both Apollonius vertices are actually at +infinity). The Boolean `b` denotes if the two Apollonius vertices +are in conflict with the site `q` (in which case `b` +should be `true`, otherwise `false`). +In case that `b` is `true`, the predicate +returns `true` if and only if the entire Apollonius edge is in +conflict with `q`. If `b` is `false`, the predicate returns +`false` if and only if `q` is not in conflict with the +Apollonius edge. +*/ +typedef unspecified_type Finite_edge_interior_conflict_2; + +/*! +A predicate +object type. Must provide `bool operator()(Site_2 s1, +Site_2 s2, Site_2 s3, Site_2 q, bool b)`. The +sites \f$ s_\infty\f$, `s1`, `s2` and `s3` define an +Apollonius edge that lies on the bisector of \f$ s_\infty\f$ and `s1` +and has as endpoints the Apollonius vertices defined by the triplets +\f$ s_\infty\f$, `s1`, `s2` and \f$ s_\infty\f$, `s3` and +`s1`. The Boolean `b` denotes if the two Apollonius vertices +are in conflict with the site `q` (in which case `b` +should be `true`, otherwise `false`. +In case that `b` is `true`, the predicate +returns `true` if and only if the entire Apollonius edge is in +conflict with `q`. If `b` is `false`, the predicate returns +`false` if and only if `q` is not in conflict with the +Apollonius edge. +*/ +typedef unspecified_type Infinite_edge_interior_conflict_2; + +/*! +A predicate object type. +Must provide `bool operator()(Site_2 s1, Site_2 +s2, Site_2 s3, Site_2 s4)`. It returns `true` if +the Apollonius edge defined by `s1`, `s2`, `s3` and +`s4` is degenerate, `false` otherwise. An Apollonius edge is +called degenerate if its two endpoints coincide. +\pre the Apollonius vertices of `s1`, `s2`, `s3`, and `s1`, `s4`, `s2` must exist. +*/ +typedef unspecified_type Is_degenerate_edge_2; + +/// @} + +/// \name Creation +/// @{ + +/*! +Default constructor. +*/ +ApolloniusGraphTraits_2(); + +/*! +Copy constructor. +*/ +ApolloniusGraphTraits_2(ApolloniusGraphTraits_2 other); + +/*! +Assignment operator. +*/ +ApolloniusGraphTraits_2 operator=(ApolloniusGraphTraits_2 other); + +/// @} + +/// \name Access to predicate objects +/// @{ + +/*! + +*/ +Compare_x_2 compare_x_2_object(); + +/*! + +*/ +Compare_y_2 compare_y_2_object(); + +/*! + +*/ +Compare_weight_2 compare_weight_2_object(); + +/*! + +*/ +Orientation_2 orientation_2_object(); + +/*! + +*/ +Is_hidden_2 is_hidden_2_object(); + +/*! + +*/ +Oriented_side_of_bisector_2 +oriented_side_of_bisector_test_2_object(); + +/*! + +*/ +Vertex_conflict_2 vertex_conflict_2_object(); + +/*! + +*/ +Finite_edge_interior_conflict_2 +finite_edge_interior_conflict_2_object(); + +/*! + +*/ +Infinite_edge_interior_conflict_2 +infinite_edge_interior_conflict_2_object(); + +/*! + +*/ +Is_degenerate_edge_2 is_degenerate_edge_2_object(); + +/// @} + +/// \name Access to constructor objects +/// @{ + +/*! + +*/ +Construct_object_2 +construct_object_2_object(); + +/*! + +*/ +Construct_Apollonius_vertex_2 +construct_Apollonius_vertex_2_object(); + +/*! + +*/ +Construct_Apollonius_site_2 +construct_Apollonius_site_2_object(); + +/// @} + +/// \name Access to other objects +/// @{ + +/*! + +*/ +Assign_2 assign_2_object(); + +/// @} + +}; /* end ApolloniusGraphTraits_2 */ + diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphVertexBase_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphVertexBase_2.h new file mode 100644 index 00000000000..e25279179aa --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusGraphVertexBase_2.h @@ -0,0 +1,166 @@ + +/*! +\ingroup PkgApolloniusGraph2Concepts +\cgalConcept + +The concept `ApolloniusGraphVertexBase_2` describes the +requirements for the vertex base class of the +`ApolloniusGraphDataStructure_2` concept. A vertex stores an +Apollonius site and provides access to one of its incident faces +through a `Face_handle`. In addition, it maintains a container of +sites. The container stores the hidden sites related to the vertex. + +\cgalRefines `TriangulationVertexBase_2` + +\cgalHasModel `CGAL::Apollonius_graph_vertex_base_2` + +\sa `ApolloniusGraphDataStructure_2` +\sa `CGAL::Apollonius_graph_2` +\sa `CGAL::Triangulation_data_structure_2` +*/ +class ApolloniusGraphVertexBase_2 { +public: + +/// \name Types +/// @{ + +/*! +A type for the geometric traits that defines +the site stored. \pre The type `Geom_traits` must define the type `Site_2`. +*/ +typedef unspecified_type Geom_traits; + +/*! +A Boolean that indicates if +hidden sites are actually stored or not. Its value is `true` if +hidden sites are stored, `false` otherwise. +*/ +typedef unspecified_type Store_hidden; + +/*! +A type for the site stored. +\pre This type must coincide with the type `Geom_traits::Site_2`. +*/ +typedef unspecified_type Site_2; + +/*! +A type for the +Apollonius graph data structure, to which the vertex belongs to. +*/ +typedef unspecified_type Apollonius_graph_data_structure_2; + +/*! +A type for the vertex handle of the +Apollonius graph data structure. +*/ +typedef unspecified_type Vertex_handle; + +/*! +A type for the face handle of the +Apollonius graph data structure. +*/ +typedef unspecified_type Face_handle; + +/*! +An iterator that +iterates over the hidden sites in the hidden sites +container of the vertex. +\pre Must be a model of `Iterator`. +*/ +typedef unspecified_type Hidden_sites_iterator; + +/// @} + +/// \name Creation +/// @{ + +/*! +%Default constructor. +*/ +ApolloniusGraphVertexBase_2(); + +/*! +Constructs a vertex associated with the Apollonius site `s` and +embedded at the center of `s`. +*/ +ApolloniusGraphVertexBase_2(Site_2 s); + +/*! +Constructs a vertex associated with +the site `s`, embedded at the center of `s`, +and pointing to the face associated with the face handle `f`. +*/ +ApolloniusGraphVertexBase_2(Site_2 s, +Face_handle f); + +/// @} + +/// \name Access Functions +/// @{ + +/*! +Returns the Apollonius site. +*/ +Site_2 site(); + +/*! +Returns a handle to an incident face. +*/ +Face_handle face(); + +/*! +Returns the number of hidden sites in the hidden +sites container. +*/ +unsigned int number_of_hidden_sites(); + +/*! +Starts at an arbitrary hidden site. +*/ +Hidden_sites_iterator +hidden_sites_begin(); + +/*! +Past-the-end iterator. +*/ +Hidden_sites_iterator hidden_sites_end(); + +/// @} + +/// \name Setting and unsetting +/// @{ + +/*! +Sets the Apollonius site. +*/ +void set_site(Site_2 s); + +/*! +Sets the incident face. +*/ +void set_face(Face_handle f); + +/*! +Adds a hidden site to the container of hidden sites. +*/ +void add_hidden_site(Site_2 s); + +/*! +Clears the container of hidden sites. +*/ +void clear_hidden_sites_container(); + +/// @} + +/// \name Checking +/// @{ + +/*! +Performs any required tests on a vertex. +*/ +bool is_valid(bool verbose, int level) const; + +/// @} + +}; /* end ApolloniusGraphVertexBase_2 */ + diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusSite_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusSite_2.h new file mode 100644 index 00000000000..9f1dd5ff9dd --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/Concepts/ApolloniusSite_2.h @@ -0,0 +1,78 @@ + +/*! +\ingroup PkgApolloniusGraph2Concepts +\cgalConcept + +The concept `ApolloniusSite_2` provides the requirements for an +Apollonius site class. + +\sa `ApolloniusGraphTraits_2` +\sa `CGAL::Apollonius_site_2` +\sa `CGAL::Apollonius_graph_traits_2` +\sa `CGAL::Apollonius_graph_filtered_traits_2` + +*/ + +class ApolloniusSite_2 { +public: + +/// \name Types +/// @{ + +/*! +The point type. +*/ +typedef unspecified_type Point_2; + +/*! +The field number type. +*/ +typedef unspecified_type FT; + +/*! +The ring number type. +*/ +typedef unspecified_type RT; + +/*! +The weight type. +\pre It must be the same as `FT`. +*/ +typedef unspecified_type Weight; + +/// @} + +/// \name Creation +/// @{ + +/*! + +*/ +ApolloniusSite2(Point_2 p=Point_2(), Weight w= Weight(0)); + +/*! +Copy constructor. +*/ +ApolloniusSite_2(ApolloniusSite_2 other); + +/// @} + +/// \name Access Functions +/// @{ + +/*! +Returns the center of the Apollonius +site. +*/ +Point_2 point() const; + +/*! +Returns the weight of the +Apollonius site. +*/ +Weight weight() const; + +/// @} + +}; /* end ApolloniusSite_2 */ + diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Doxyfile.in b/Apollonius_graph_2/doc/Apollonius_graph_2/Doxyfile.in new file mode 100644 index 00000000000..22e3143eadf --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/Doxyfile.in @@ -0,0 +1,9 @@ +@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} + +PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Apollonius Graphs (Delaunay Graphs of Disks)" +EXCLUDE_SYMBOLS += Agvb + + + + + diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/PackageDescription.txt b/Apollonius_graph_2/doc/Apollonius_graph_2/PackageDescription.txt new file mode 100644 index 00000000000..f82d98db1ed --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/PackageDescription.txt @@ -0,0 +1,63 @@ +/// \defgroup PkgApolloniusGraph2Ref 2D Apollonius Graphs (Delaunay Graphs of Disks) Reference +/// \defgroup PkgApolloniusGraph2Concepts Concepts +/// \ingroup PkgApolloniusGraph2Ref +/*! +\addtogroup PkgApolloniusGraph2Ref +\todo check generated documentation +\cgalPkgDescriptionBegin{2D Apollonius Graphs (Delaunay Graphs of Disks),PkgApolloniusGraph2} +\cgalPkgPicture{CircleVoronoi.png} +\cgalPkgSummaryBegin +\cgalPkgAuthors{Menelaos Karavelas and Mariette Yvinec} +\cgalPkgDesc{Algorithms for computing the Apollonius graph in two dimensions. The Apollonius graph is the dual of the Apollonius diagram, also known as the additively weighted Voronoi diagram. The latter can be thought of as the Voronoi diagram of a set of disks under the Euclidean metric, and it is a generalization of the standard Voronoi diagram for points. The algorithms provided are dynamic.} +\cgalPkgManuals{Chapter_2D_Apollonius_Graphs,PkgApolloniusGraph2Ref} +\cgalPkgSummaryEnd +\cgalPkgShortInfoBegin +\cgalPkgSince{3.0} +\cgalPkgDependsOn{\ref PkgTDS2} +\cgalPkgBib{cgal:ky-ag2} +\cgalPkgLicense{\ref licensesGPL "GPL"} +\cgalPkgDemo{2D Apollonius Graph,apollonius_graph_2.zip} +\cgalPkgShortInfoEnd +\cgalPkgDescriptionEnd + +An Apollonius graph is the dual of the Apollonius diagram, also known +as the additively weighted Voronoi diagram. It is essentially the +Voronoi diagram of a set of disks, where the distance of a +point of the plane from a disk is defined as the Euclidean +distance of the point and the center of the circle, minus the radius +of the disk. + +\cgal provides the class `CGAL::Apollonius_graph_2` for +computing the 2D Apollonius graph. The two template parameters must be +models of the `ApolloniusGraphTraits_2` and +`ApolloniusGraphDataStructure_2` concepts. The first concept is +related to the geometric objects and predicates associated with +Apollonius graphs, whereas the second concept refers to the data +structure used to represent the Apollonius graph. The classes +`Apollonius_graph_traits_2` and +`Triangulation_data_structure_2` are models of the +aforementioned concepts. + +\cgalClassifedRefPages + +\cgalCRPSection{Concepts} + +- `ApolloniusSite_2` +- `ApolloniusGraphTraits_2` +- `ApolloniusGraphDataStructure_2` +- `ApolloniusGraphVertexBase_2` +- `ApolloniusGraphHierarchyVertexBase_2` + +\cgalCRPSection{Classes} + +- `CGAL::Apollonius_graph_2` +- `CGAL::Apollonius_site_2` +- `CGAL::Apollonius_graph_traits_2` +- `CGAL::Apollonius_graph_filtered_traits_2` +- `CGAL::Apollonius_graph_vertex_base_2` +- `CGAL::Apollonius_graph_hierarchy_2` +- `CGAL::Apollonius_graph_hierarchy_vertex_base_2` + + +*/ + diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies b/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies new file mode 100644 index 00000000000..6270b1d0d3b --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies @@ -0,0 +1,10 @@ +Manual +Kernel_23 +STL_Extension +Algebraic_foundations +Circulator +Stream_support +Voronoi_diagram_2 +Number_types +TDS_2 +Triangulation_2 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/examples.txt b/Apollonius_graph_2/doc/Apollonius_graph_2/examples.txt new file mode 100644 index 00000000000..3638b5b2a55 --- /dev/null +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/examples.txt @@ -0,0 +1,6 @@ +/*! +\example Apollonius_graph_2/ag2_exact_traits.cpp +\example Apollonius_graph_2/ag2_exact_traits_sqrt.cpp +\example Apollonius_graph_2/ag2_filtered_traits_no_hidden.cpp +\example Apollonius_graph_2/ag2_hierarchy.cpp +*/ diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/CircleVoronoi.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/CircleVoronoi.png new file mode 100644 index 0000000000000000000000000000000000000000..c2d17a7b6b94f5683e278418d67fdf80730e3aa5 GIT binary patch literal 4955 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 Z_b=m@J*Bva^#cF^002ovPDHLkV1k3zqYnT8 literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/CircleVoronoiLarge.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/CircleVoronoiLarge.png new file mode 100644 index 0000000000000000000000000000000000000000..3853018ed35968221f8c4d91854dbabca3063e50 GIT binary patch literal 106801 zcmX_o2{=|=`@JOdRD>cVN#>-?WGIxWNXAIUC_;v0u8=875qgM7k};H-Ov#io&q`z_ zlF)xWy}$2&uIu&r>1*&P3THCpuvy(p|*J7yoeC zXSBh(HnDQ=QiAIQvk;jQ8*V$))!lu;(9q7>`i}d4l71k=nW;?1h zPTayMEna42U6dg6X zs3M+2j4WX%OBwx_|2?xuK(vYfrT=~%U+)GGC&B|?*~p2v89I;KV1VKOrYkCt`vnFu z6HoGgL%OHRvxlAi%<0q5Fk#XE?w^VYlaZC}zzpdB`?F^wA|eC?1c3 zaOA%~M%spN$5M6q%gf8{9&aNdsgltbh*jk|{9i0ouU#zj%)8oO^zx-Zp&8Fug9 z@vD9B8z?wK5GyTJK{^&QTZ)IN$ZDEm4&fhH=ZA;Ce7SQ?3!$pHBYlwc@~`2@^uj_n zef@_;MXO!eCe0r{=)NKbZYDW7`R6ZRh|}!&_o#MrTU({ipVgKGNpDZjwCB%L&i@Pd z-K?zm#53%WUb2e6pI#XiI7=nwaQ8Zp3LBqfxDJeOeZ++&{rTv2ce&^}j+_nAt z_g}hnsgP!yRDVv_i-pC-Z1YOrUvq;)Lqi_(L)J#b2m9FB*GK*CX;shWAJ-P#%HhhD znkZ%bvoJq@V_-ghBM!UQKV;|Z{p6IC>tpXj=jP^;WIc9;s@imuVP)i0d3MgY(}WMI zOS0`^Vxpm@ej;<@2PVhW)ivIj_}t6>L-+${XWD}6ERzxw={ckr+1NbihvX>(<1Vn^ z7h(|mj7NUVUd_(V)=8AQKHZhQu;5I6rzZRf@%|LFL!==VRvw<#*567>q$mRi1_qua zB<#!~&b-%&d8QL&LBUxeAt7sPYacPR{-Ub{1s~-iK74orJB2%Nk?wb{;mphPS#CFO zs3EiNv`pA8E; zswb>_h)sMY3EL*)pe4pW;+REEiJ9{=g%XPhN}LUpAY6%$7O76eD>_w zGiPX`8fd7fQq1^Fh&kw7?#CXv7nPNNCp%KDt*sFcFJHb4G3O%jRMXMXId!VOz_x9u z-1{+sASx;vRXd8*YHejT(%%^n5D*y|`RLIjB+z&7WaQ=L+1V4OIy2f5BpKWaDp@L~T^$|Q2THCBWhJ)E4wib< z-P_G{NLv+2a{P#(!lk!w-zq6730`<@T7L7GCo?t4fsUaePA)D&T%4Va&FXi8pNMgx zx~XYmz_f1W=L{Xf#S-WJ!on?0O-+M?W|+3cE7GlxgiQtp2kB^O+fhe6Kbmb=+1Naa zi(5l-7#Xq16<{Xu&CbaY<>h_f*!bejo0XO6ZU#;{XE!%1A=x8r;mOI#<>fxeictDsjkW98fUK;K@7^W1k)$Bu_|cjqTVG#~ zibYWLiwq5|9$!>9GrD+jsI4vM#S3)<1D1-^=bcmPW{Kl&?(V0FnS4hTU7W0^ELmW3 zf3Xum)}s|gs;}?K4q;M~jLDf9M6|GwkettY;hj4>^!i`EemzulmHm#gwBJ@4?yA>s zse)98WzjryW_#NM|Gdi`t>+De+HEpar zNviJ74ZJPzTpTMYDY<{25%=hlxL0Rc?AYt_cWV>7v;O`2-1M`@w{hMgrL+vcoSfXJPoE}Q5*pUK8lt%V;ybLlr%dWC@{%+9dVDf7eIB{VE-xWeZT9&&Va zbkd+^@4t_FO(tb#+FM!@$Ge@BbbWnY_Z1n5A>YxXowc>&)j<@*>e?MxZ6Ri9X<6(v zTyg97(zoWv9k1_9A!Ac2|Ndy`<@Foc<@$L2@AdVrFJDqjXi3CO&YWrf@g+-7PY=bZ znOfzvN@dwJvFPS;Nw9O>U0t_FDQ^=YS888hnf93JIb!{R zxzOP^3ulxf67`c~4kg~F<$8{8JHfcVNM%yue975)Aw?y)>ZPu~Ns_edT}{6E-U5nQ zWnah9nme5tI=_~eRZ1E8e$31~eDsJ|?$6|&xn;TK#k{`s?M$wcNR>~B>a)s9KNlBq zE-v=XcAo>{;!E`r?9$TGcC0l*77HvV7`-=n1^M~k*Vj|i(3HM=cl`MAXJ+&y-1Tj3 zPR);m9akEcy-~2j!ovs3y(NnyNdPDq-(Oq|t+u#*`!*_WrA0L!g=h9(U6R*T|1dFs^a zuV1OSuh@&XZ-3*y3CFK0m)?)gFD{;+oAdp%D%^L6`&DKpRZzA6=GeBhT&G)>Vr>7) zQb~1nHKMzyurQhUd7gs@>;B7PcC6y(428Pt>b`w#im_u26kFIs${m(Hj+99(S?lYq zPmVR$)!muycH2Hc5txjHz1EYvZC3e|ZOfBmD8#d~vjB*^Z;Fdk%}A@x_sA<8VWVXU zyW!?GQ0Z5Rec_T!RvxqbRMae2ZUk%1ox8P$Xm`jDt6^4Dg5{1|)hN9lj{x+d`v&!7K- zDQazPmG@pPeDj95G#jNqfBt;y`W+eS0QTnNM~~{YmWQz9YXIlKL7a)q1UA}Jnwmml zV$OgKsLFrVR|NaMkyPc-($o7QH-1XfK-^H$(a~+&7C^*uG)kH}It;|k&B1~X-;IiD z>+SVwdnyma0xFt+^r zg>ySc_F0J=X=>8qZio2zPVvQH-j9G{JbU(xi0>KZLifmVqAVI-yjbD)cdNBkyRdm1 z32nrw@yX1m8ygz~5~5M3QZ>}oLE37#DS-_HgoU4X*x7a0xRxA3n1!dMeMLq?nZ(X) z)0+N5LVu8-UrJ02j}<g6j}eti9EWoa3B%}Xw@|0Y3&l1v%-{LioXpuj+W zW@?0JnYxNfYEcmjX7+-fUTS7$DAqBh!;V9K=gktteJIl*dh0`)nwlS*nx>Ee?atRZ zlpH6{81hx#<%aj~-Q`EfT{iw5DxA+xcnfmd?fA~3&O(v=JSWxk;Tekqv@(K#P z!8h`)n~^=9%6qf0vU-fx?AWtsPhr;hZc`W0{LGNgyOFY`(v^t*-8QMa33i*-@L1CrU*)1HTPW91TzD zoci8I@LOBBWM}sRA%>+ija28|%f<#7fRctL)vS5a(Ac=Xp}}?1Xjt*<F=M^c6kg-1m>4Zgdvz_N@%VqZE-@7S@!!C{($fioFdm3jAWM~P_0FB!)ptHz+r?$+E**P`W980kH&>~0w{u2d zp;J>+W00!|g!$=d;JGk-rrQ{B1Yku&gR1XNxW0$SFQAe)UduLEC$>o+(#EkV$(V-^ zKLgstK743uY6@tMv_GO97#Jw)F(>D_z)k!d0{OwgGr%wawwIuGaEEK5oI4AA2QPY^72V1xRcGAD?vrXB_wWvX-KlyTo1TI!+Np&=6O?7j#*_A zk?PL!w*7#Rv{Y2mo(m(O)m58h{!+-9{{AE&5`{FsJyKFq9J*eOR?NKjuQnmEA8Gmd z7u#dku3Z3e^qg{y9kvprGxnS7D=jT8l1@XarT5K=xF}Ze0uoWX$nC=bM~$RT>3`4Z z>xV}~JU^FN>OOnr>eZ8_9R67g%gbPNHxWvXrK!KFs;Yo@E?Zib*k`1Sme_YH`0w+V z?EK5PbLZm9N)p&7I7g-L<~_{ng(Js~-Eeg^DZaMP`*rNn>gsVxN%JDdJ$-k?Xp*$& zfBg8Dmi;qT6jxCyr@M2&aGZw9yzIJ3of%}3=0FDQ?e{P;`nwDN9S1%G5(FaK&BUZq z%98#fJ9}km>Br<`duM0N{rlXElw_nz=H}+c#(QT!k!bH2Th4$6hDp!RN+`lgicM_i zex8-(@ZsTMBpdTmcj3M_8bosLkvOy}aQ}=G&kV)FodU9G_eR6ubHh}sQ^V%^+!e2{gXE6nZt>y1+ zcv2Ju;uZ+~^y!?eZ0U;^FMwlH4Nn;ublux6*h)}r8$5J_NWzXDU2cp%Q0d#dAR#Ow zA|fn&r}J}7jk1c0in%$#G8za@e#MPPZ}F4(qqcSueZR`v%!4`$F%>B(`(we?CaP&2IJS;TW3 z{Wk;FI5I)Qz{-#i3Tpk?tM&n@q7qhA_};oz_TmM9b06v&xL9UpCdP5;Z^Zrju@A9= z<`uWD-?-tkwc%xBW8>x~QM=4G>2}k{M_%qD%`dHk2M-1-O75`#;BewrBpxRSjQ-A@ zJ6Ty-h~x%PTl)haPQynp|GQj*Wt#+|tF zS{MWapfA~5Yq_sqi;M|>n)-=~gxSZ|#8)JC{FW!n1CV~)dwI)fTcQ6N$1#~CUu5|U zIT!B)2fKdjN+uBibOz(u+WO-pDw-3)E(wT#!1FqOZ@iw)&(F`*br~}aZc8TGdJWU) z=H_N()C>Gj`L@Al>1z|B5!EGh#(bW^;YDU0pzEk&$c%1x0gH(`-*(Q0)0?dup9Y;lqb_valfN?h+DE z8j$+}Z(L8Le1B*hWR#SY)Zn%0+bdrLL^vt78|J)vCB(-!fmi{R!S(?ac>MS=*O%Ql zZ{B>0oHX0_2F#(iw|91^Jb{&d99k0Q5ut}v&cnl_cuVWTg$t^xw}XPV-(rgM)8|Bz{JoOzfVknvKA#LS9Nu{Bf$a(=jZ41Zyh$g ztDFL49(wQI`tRSH>%m7*%%!BH4j&HH+OmNPg`f^zPv5k7ZbCLM2j?2Q&aQd!-t}x;~?@ockUEo=^q{* z9vl=tc<@f`DB?OkzBf%H=2dpK*Gr1d{{HE2-=4pG`Oaxr!Pj@o&&LP5SV^fG#I(m* zQClFEdYGyjX%kSA>Ti2T$2N~2ju41RC*9V6FMsD!xW&f8QXj72L!tv*ZTE*FUUP18 zGP%PJQ;thw@72j)R^s^0Ha8hFWX%7BF%1n36_xE#4daWR5Wx!na=hyN^5xsql)aTz zq3ie7o%Q=8PW6KWfucnlH`K^&-@g6Zw{I%;#^&at0s^N~J0y-B%g~I^_gu6TqX}Ix zHZf_k5)aXNFXy+l(UW%>l4xhT7ILirV8_%?K-4Eso^*9}frk_o72z9PU|{0$LV#U| zh*xm!D7H1$0~fdmz8O6+J3XD+VFx0?Oua)}Paqa|9SKumQ`6k44^PDF)_tFcp&95=5XW23V5%A??%tS0By$MfD>ZJjvW&dLk)&1=O`u9VuVF1 zKyEvF6x{%@xkK7emd8{tU%m`cm61T{;N5F3H;2bF>E8FJ!OAA zkui02qV5u}dR=o}Ev>7(PEn9U52!_=68H4=AqmbOwQc>}-oCbF4NL_vTn5D-dKqZ+ z*z9a}YU*-}1LRFe_rW!#$;tleyg#O=+0l+cvPIz*5OC>|H#aj&3Jz{Sa=GxzuzKNS zB&U2|clY=4@meFlRl;Er5#*@X+1bRRDj@JNz(7*u56$k5jrdF)W*zb&%_@982vb{t*vnL=OjQ6Xp!$==8vhV!vX^9>kL9H zG-{d1KLIB!mg$Y4en2RZbnMBss1D3C4OUKZL?o{K__DgXs{W;30bPs4)P)>Ivg(*- zv^xRF`(+HEbYa4W=<1|~z-`}+0k#_#V0%r_7RHc~f|Kgd+>vwg>i>bJu-HVP$O#1zDLTp+IQ?nNafYq}RPfv9Z< zr1)0BwjfY~L1`r%kNB1!#icj|cA%_WGgcR-_NRQ|^m{-TTu7vl1goX5*x01Mc+u#r z5dt;Z)!8}s@nhCNc3-fPX+TseDyp&qKB&PEch}75awHMj`%dct&d>R-O7uleFa)ew zy!adL7Jiw_xxTC;mIwWP#QUEOYS&n~RlP+k)>3pZzHDZec_o?=rp7-(38q}(Rk z4e7t7cTORCP+!35wwAtyfuzL8?@3I*JgnzjI8@=oj(y6^EaAK1NhV68bRU8(Kw?&w zVBq6#+-@@ED8!R=q9P(gU0uf?rVr%xxC!lR;UZmZa)XMcprC-gi3!~9`k~hVyy5!w z#qJ#QQJwo+TfS1FqZ9$J_LM_5k2`Yt6gc|lOuguLHqc7Zt=U?i7FB&srNlTOh)f45 zANBkA-{AcGrJkI>4rteehK8c@AQOd{mjPizV&vrHG_4d~PzOS~ckf<`Y$GPjQ;%Ls z>rG*ylwIp_p8p0$4RstUIAR89+rpOTxYF};&CSir%gdt-A;?}xW>TUMK=jX_HgBZh)Zj|(AWBX_d&#&p;7GmjB_ zC?h*7r69FSqWq)wj?PgQKhx!3P;zu0cAE^|f!tbuO~t`kZ5f0uK0Y4LYG7ah6vS~x zZ8`YFt$fNPZQ>?PRf|HA#@cp>1hZBbTn26#p%O>QLg7)7{4CWu7j61KF8~MqAo~>n zHk6{YG+rCi4K#y9FP4?um}ZGlm;g@04hG^vmc&CNiDtig#ito(VQDG8s-#F62sMUF z{-ztSqzwZrLE4p1QStA>XsyNDucB@q9<>yC)l4@5UwMI*Kj~k*$eAr+eeu7sLPo!d zHVnd-joXq=Jf1eE#b1vptZpwmJ24Nkvm-Yaw7t$n)+O%Awl>>Odgu2>9EWxdB#$yB zKE7UiHWO5$2Ac+gVcxrUeLX#FbFpKKp5)?Gfypt4bbQwq_6rEy+d(4?n(*4J)TZs} z?8r#fOi>AWsH(u;y9B5Kw=Yg;G5hDGr~X#qRxrv2I2s=IgSd)_ zrNa=8O14Yj0&=6PgB12ZdD#)C$plW0)^w1eRRSJ#?J!-a?H;`E5N{1?1B7# zZSH>+e(CzZ`FfW8_H8dh@AGH3@2yFuZ|M$)-EeoOUlAQmNlPjF8nPz{I}?kD9r*F0 zfSCQKG>A43V8!3W66~*C+xj_$4;myYm+I5urjkvqSZpnw2G16o?zk1Z|OAt=LYE90S-|BWma_*_cL6HOj| z{t(Fvf>Ap*(u5TiE3r(;$s}QQXnE9l+1uGQUXLjNS81|Z0%DCHZ0{|w#T?z5`gG7n z@}~nM*?9v48}uQqt?>*17AF5Lm^A1k=FagmgF*l_;H&;Me-ZPF4e%!PUV?g;D4(6n zM4CgKz`S5&WCV(Vil*YzNzj_K4*r+&ROzrW5IEq~5dMj+c#+^i{N8RBmKrZ3eSKa* zL5B^7&$gT4(dgcsK7B7Xc6R|gsC(7;B8oji?Bg|u+kgPquFatq0yBf`U?%{yMudlB z=K`rfkqqmqgb4=l2f_x(>B;9L7m*SGe($Dp(-GRUGBVV7qDPKBnQ8CX*w0AdFa3|f zf>U5x(E=*3nl2eF``FfYXjdozAOIpCgxgc6K0b}A5=Rcgx~cL+AJdaZ)jDwCK<~0< z`NYHoq94)~cQ^W~QYTI*%%&P$G@)lXXw7a8re-kIraIiZ*ESM z`zEeN25>VH9FLsi8=a>T`rOPojTY{#w# zAnWerJav~6T@K>fEh7vNm$X^kFiD9IojDFt#O1kI&DyT~l!f&+V!7`4Bnfko2{{nkj|0dXlQ2>wqWKc`47M7BgMWb%t?7dSdSy?pn&5-iYox$b?PKRLtfG5wF!d-j+ z;lsTh9o6|0>bwsM3niMLu)jr)LiTNFfa28{rE&T+7^wHno5<@N^ug}Zrei37!Swqe ziDrU_9BTaySs;>6=P5Si%wqVHe7zAviY?sS+m>chnM@5Mz$s3=e3;x-l=xUiov zqjs!~+aUS^n>OT60C)7bo~uVqvH2K>LLcD1UlBOC7?2$i1xY3MOA{MP4ZuD0V+t}d zpdQH4L8!Qg_w7r%eVa^5X>f3`*H*b@Ayg5PFaSo7n)PE*^VXiHBXa01-PXu>wV~_l ztH4fgFLC@h5ji7&VO~Ws;84|Pu=yZ_Xwr*+{`#fpxsVJ!4+wT~tj@Hc>n&D?pI;rg zR$AH!vhl178%2?pg#$D7K_Q`685xJ9q}b}%FM5tKI9gboP*x_5)CA{;xw=wnGYFi;3Yxh|O>)giaP$jZtwujHIn-rAR>&A`BraV~S)wr!f_Mrc_W zn5Ppx4#Z9^fnMk zkfa+%oxyE1*AsYmg#zImK76>qrX{cv+sw+=)&oK>oFGS2PqJ{wG=ZG}&SUH{GBS3L zgCKq;j-oe&k3eF<*44a1I<$BQ1{OpwJQOffy?;-pttGY?oC&uD+9~A@-LH?7ra-e> zV`H+BlyG4r1HctFE^LHvWY+jpN^!9VDlW03?&4xuzXHt-$ser-xs5QGMiAjAeH#4g zA7V$5lScx+x3om`9-_&k4bh2Qgd7j654Qcs_@fljG|G&a6Qln%@@uyE9=DdCP?zMU4 zP-`pwVi>TRC!95B9trK)szYJ&TAnzsug^Wip{K<76K!1c66fl{!6bQ)Fe|n=nfFIf zvd~^AFDnDzglg2>qm-gA@aEMkM}G0&YilDS6E$~efO4uvQ(rJLG4p0f%7ZA z`!t#dc#K{F*~82q@Do5|X%V6mBr(wxE(xG3D=RDCKeLinqFc3t!tY8;5AyQfzZ%j@ zoGwl|Xl^KrhHvF59pLy1ev7Gxdi(X;H=kR#pc|Z85?*l8^rYDC$-*^I2PBNAAWO}k zNiHt#?&(=W4;ifMV~H`#Sa=k`!WG)%|!E)C5t} zk_80isNz%a)tTt~_bI8Ulydi{e`so=qM=CuJx6Em?NS%VdkhBhyS4RmNX_WS_-!o{ zhW-9-{*m>d48$yrZhc$$7KczmNw$#Y^M2H}$HsKk;}Dc6M*5+n9vw?@u%A zjc|uXg24Co@-i|pfybc0f9>W z)CiylxIjw0+C@`44}lyR8HqsUk>zFFv*$Oq9C62g>4y-n|zR;_2<}`s>IsZUyO&=pHP3mO-l| z4?-&q>8;}C%FDDgE9jD#p3Ka{9Pu2Bm&tDhoqi6JRpX~m;&O5vnPl?V>tMxb8PyqZ zSwYi+28%rU{fS1LZQD~Idj?us)z!tXcq$*CavKce!4ny?A z1|jZK_#}|8U}Yh;PqMS=W{umGQgolCrgpzF(lay+aTgYh4Ab z7ZDmP;d_p{!+!I~Pm2D$nOQksAp@kPJ&ca7z7~99Wn~4d;fPZuC-bE| zLtESLU$QRD!yQys#xd(+2sHqaH4nclta89OiQPN>_IQ84 z$;FFX5cN&pw%?=pHZcJw*g%C(|A!A(pv3?xqA3B030@2J6=ML3112q;Vs1Cps?o_%XXsy*4)@gybEF$2Hg->3lN8vjxN4XN2nBc`nkA>{?W-RkF{2}wf(MipM8>%@%Z~@l``1165U3Ffa&rKJQXME>TOD zmY2tqo}LCQMfo+zxw!dfz7icmOGphMEOru4K+8(yjckvIRWxY$u8u6TgJ{4igNliS zC=EqN^5~6ikt9mG9v&X(#;K^(qQePiG+-t!G$Y!DbHc-E0SZ_B78e&s7uPT#pyujo zC8C^l_ALGqE_?$%LVX9Orh{N5o0W0v$q!FI=ah91?>_b0S!w{q8e#BfeI0{r+0mv4 z(G~Te1kD+!%5&yjznxCZ$Hbs`l->F*4m%L9=w0r~pHrQP8abD*lu^UH`O=hu>b&Q0 z8(bJD_zku=8gVRPV7)NAPS4NhWM#!XdSsxhtBVdKdRORxva%kER)^3J$fuz(6-=;} z*bCcclqMg;W*>SGm?+F-M~4zmG{6I@lm;(GlmYD;4JBl=c+E#>=0HBh_4skHADU1{ z9z{9=Ey74*k`!An4nrrR8(%RiK$v!qYq94%)}Oo((Z z+K<@OzJ?w$XbBkT#BTEN(_r8Kc&{~@G#l)+CW6}?rkGE^xT=FXiwc_*N+goI29adlclqqod!`Ps>^9$QtP z+sLAUK|w(6zh?Uzb|%c_lZWVNyR84TM|-B@8q-bqHZfh0wp|*i<~cH8IfLeha!^vj zM&Asg1<2koeqAaNScX10COZ1}irNqK&7p8Y1%T{6IXNliv+f24oAS56qhk?60*mU0GRK(4x`5%uGyrYdgKXyslrruBfPpa6lwkof(rtFrb42 z#*L}|maHZ~>?lS>5xd-8#0AkeFjg^2TOf_f&aOoK> ztt9jj;{Ng`Z)g2*0UcGvdKB&%e(esw0qY%4@vbDTG?32XA4a7ML!hYY= z{A183Tc64&#KwLD!!tNkmrn&S`ySTF)Or8S=GPIM3-mxMxGXu~JW@f8PmqwveLqBtuoVXVLz!rWLzK?RVNm0X;nM@? z2HHY1Rn+X=!vLqY=4KPLDS$1BLTt{}+kO50*xRV2wKzIrK<7vkn2bsfLJUC_0Q{+z z@aAtnJ?wg(^K6gdvRJr$ zro<2T%|ggvzv9AxQd1A`@zn>4!{?v`aDhilbv;ZtfZiqv7f(dXK>0 zr~<$yCv%IUiDycV95Kqbq7uk{kBx&v&UNA=*dd-t>{1OG zOL1!o&`vnooya=q3^GM$MXSTWf;Mv|5XHjC+86i4iez78F z34G8Vdiwj(WjIzpZ3=w`!3dx($#Xt}noJ2iUm+uIw|2x>kt*{wvS`#yS%T?yX~ zAnxGZmy~2Rus79Ll%H{O%6am{7=Zp)f|!_zm)BcpK2mi)h5tEvkfd;1G{!LaI2lzp zfTho$^$#7&Kol&EB>gl5x@Uv-si~zE5gB=E;R(1rH}?r$-S**OLi6zh2VKw9+i*`#9PL%-z|W+Q2Ni5&?T#u)V#X>^H~mX-{; z2x!1tScEZHUT)FcoX-`KC zPQgjnQ%0HW5e9EJHy@syw1dfwSXSEaK4PYR4lFxo%7T?YcC30l53vY;nwZ%Aprs{t zC}xxjqPHoWqTlsVuKfDN3TNYv9eE{YB1pJM0Jw^rhPPm)#U6V2kQqP+^QM_36Pq_q z37GTWQ7s{1VbHaEo-JkD-ydqQI5p1%AK>@7xu*{w7J^yT1~b4WawIi2kBBwkWDyVu z=#e)M8iTBBNF-V zzy#0!{i72T?ms6xM*E{vLry=ZpEpMf)c(qqU6f?NNa!lcaYn6g81jMpPR`Ap`f&xQ z{uMzI#~&zge-_Dm+~@S4SLNC$!k6eMfqnoD=jh#hPdexC8z_-GEx51fr6UtbSgrvW|<2nq!VPm`iMqH^xr*RKnnWoX->MTXdb z@k$^-;NZa>I)`y264Ejp7J`D)Xdr^6;VGP-z}8SL$`{k*xAof=j#iYTvhs2xbKwif z=0^+}VFI@SuR%^iO@em&ae9UxZeL)HgLz4jQ^1mR zIz<;7tKRnw{x8lXMr_I)0EazmU{Jqh>xNT2L&So(`3EL3?4TGvE!b#1oSorpLA&_R zC4RWEpb&xhU`OJ)fwb^z5adJ*b4Q@=s9E=rht*v{(Y3c1Hhae$m<+gvc}ER|=Nlh0 zHZ+8f2x6Q?UJteu@^jaP#_Xz^-H~~yplbl?iLwyl%xiPEm_P|fT*o*lUe7yE~!o1#auX#6T7LW^jrvlv0d5sfX6&L}bJLt@{Ef&~$ukP?NHGCd=M!shWt zJ9J9;PwF`dh*_LW5V}ZjZek*9+sa{3B&BR6E`9LeH&}CEE<(9iK+m*i*cWX#7@~0D zTpENsd=NYqRMHh3&gu?TZLXmZJ*+v-0F~F>+{k)Er7$*H&`~tVaiHSzHW zVt8cE-yTZ;dU_I^Cg;vUJD{HrR^w(wF_W^pN_!8}4XT)Pv0Ua6oqDM17&0=NtVVCI zUIc%^6J8sxXfcS<8*zP!l$@@e^ka1NlD&OXSrLo_!1(y!J9Hl*-9i|cc(alN2UOq= z8o-jsYkN$oekw?B-x!Ih>n}wuf+CM>00>C*Cm<*kZ|xyd0+Vt!tjWZoS<3I&@ zV6@Qq=nrJFedy@oI1X0m@~dGIrFKYr5HPC8gl%E3Q9XGQ5+I1X$84Xqo!#2kCMHaQ zjU-S$IN4~nI+%WKO-P*oQX4|Ja)+SCA68}$~xe0c?kAS^5_D{C6Rk5Gti+g%!zP!-T)9>lEUw*dK2WYC4q)EAKJwXF`^0SJIu8yPuj1A95q{RCGI z0z_?PLmWCY46%?!goaM@C@K=PGv6$RwS#HMnpeVxQf)lj1+|lZGbOF>g*H+2KXt9&8ZoD#xo=!DFsjS)ok>mo$zm8lOA21o(=o z5BxLq?uNrm#%=NRXU_spKYs_0s!$a5} zaNb$G^dy{WJw1(qcRiWB%gg-<5b94@4{ak4+R4bs#z_zZo#Ff)I0ZCV=NxV zgo!wEgDVeZ(tSG6m1#k;c~84>N#JkWAMI^h^8k`)c%v4f`-?Lqwd-#M24FDtaCe7E zk0-hZX<=|si!bKzU$kaGxERT>(P=hSR8`+MHEAFy zIj**8_h6JziO>-PVQ(pu9fxF)doSFJxKEkA3AGvYoA)7pgM`9$f+M5(Ao+Wa+T^~J zm{ZE=OnCAH)CIr>{mjt6b`B0qX#YYD!gb+7M&}gvIBGS7A$)@ikg}j4Mw5?tE|8Y? ze$!W!E-W}&g}XxE<17?V#aci1C+2%}`o+taJPOGkaFJpBKv7nrvb$heD^oA5pbY3L~c19n%(mkO%;NAI>B`tb21M9)J#zc+2+tT}V$ z%%CF1j1~rrIq=@$UPRC1moLCYqaUF;{p}5`gS3Q5hQ0xzk5DcNzXo#UKTTo(u2B3U zf)3mOjsX`JmmjroP9GK&jQXZh_WZdu`a86Ke+(h*ql!ac%l*FGYTi@qWDa7Fnh&`9 zA$%JBq?BW}fvlh;Bv2Nh5r!n1)sgJqpJM(?A-HNe)bjFW$*X-hNYD^C*wJGS2L@&U zH%4m5SG2A}LMWrvIZmHGdh}?CtW?bnG=?@2Mp_ygO>J!#&Ym6p{@uyWuD!k8u+%*} zEUa1bzy|UHO7CzE3r=!4+p^NnqjiguFR-E0X*mRYIOo%cNc7NdAXqu`X+4$eMU2A5Ix3q2TQ_DLSWqRH9!P^~ zP6$8@dL+P4{pZi<;JWh?YVZ({hK4nbQ_f|gdO9zH{gj}{UcH))xabnYqT+QP!yZfU z5W=>k+Qs!0hYPVN32|{R;L;sSkLKayb4POl`wmH)rvlxyGHbjZgM*~bOC>IvZpfFI zSQoT=v6W2a2rmE-esCd30DqA(RLYA{c#xtnex74q-_f3d8-mzvk@PM`&Wuk;XsE9T zuXt^k_Y4><@3$<5yztvV#T@7iFJ`FN%`YqrD{Ic{*T==gAar-)9Gv+ps9wp*_a8l4 zMePb-WN7q+^AS_c|&L8iuuRj}{INJX4_NcFbc>w#>vt$o%9m1@g!Vz!Nz zpi>A8#4_I%A+@%+tb4Ae64T@MyV#P!3jH^cmOPiffnu#XmJFY8!z!z z3p61chWMd8%dP(DcdDfGiB{#Qmj8?gMaS&?g$wZJqVi%^BFgK|HZ?bwx=npTf-@Wt zIa>1ety!7pB1j!2{U{o)Lqqg82_NB2*q&VSjS)$kmDSc!m;R}a#HE_s2ue8g(CgBU z*CA74??L#ao?2?RwEk=CXrdvp@iTU@}%V3${R z$hmcq(kZ1hVesMPj1(aqIKMRNT~90Z0s9!U85_9V3(4WO*oaBXVaX59vzF$Eu8f~ z%o3Ia&ygUz^){Rk1gy$POXGI2xB^HVqLU7Sw@sHIBT+x}oe_l=B)@h!6t8}O6nd}G zIv7+x*!GS7mdeSKIB3B@-wgc&93Op~)*o*mNks?{0Ec0b)!=;qJ#_iyUS-~0Mz_3K z_w9rH(c0=EN4xyJ>a?IpCK>!dlNb4+PKrYt3VlJ%k~i%@HK17TOkxCzqruak=gyyB0cOR%&wF*! zV6UPt^sg&7Z@x=P8e|i#YirX_Tvh&(QoFqUR z69~393`bEFz*k`Ep}w6Zz-w{FaqfISFq zWqOOU8@+UNSmjsOm>C)2#?c>GRjT#D+en}SH!DzA27fMSb3!=%SzAM$^YZj0I&lC= z{-#H%qjV=E1P5Eg?Vgy(F;I{wZha4l4hV$RFPuJJ+SSI`nAj^+TU!T&`Ur*m*yRKm z6TuXYrM_pQB@awKgB@4tn{=!tWelVkplN<;3aSTN^9^*CdSTNk1to)hI&Y>YbN)!` zFKH{Z+rg`$z#@lW@(xC;FPuB$`6LQ36fJuCU?}azZ(W{4gfwRV`)s;R@o!;X-r}!c zTut8(lPN*f!bgSpX@jak;qQfp=FRZI`N|bk9rxr(e!8?i>|Vf;E9h{beZ9B&1{oO{ zThGGRU>u`<{W|?zCZ?F*mnDy#kuXC)7;QrPsZF60WE!qlZ;T8_OwR^RX46*A6@qgjK)&Uq4kAAsVn54S*{c3?_Y(b z1PTEeMpF|Cd3+zoA!-H&g1Gf**ne^!OUS{}ASbthMwHMWH=L8O{Z`nIAjhoRn8K^H zh2}Gi$pBig(M`_HU$V8uZIM0=xAyIv@&PHh8ysx@)}`*#r(HqSkXo4W3NWpO3?=LA% zAF;4ZjE&(9B0hj4k9OlsNmG7wKU@YV<1mq0iJF+3&!f$RgpVEroI14y7j0V;_+ap0}XH)^?it>cI!SvQZF+T1jR z5Z+G!(Fqq2*d?tn4%M?~7xC;U7vK{RqYBl`PD+aP>V-*|um zE|)E9>*(M(98cmm6{tLre$Z&y4$|J+KfT{2p>3iwTV7rcviR1?B>o7_ zYr$O51C;`bH0V9149+bePpATTHA)In^7;d4*|W2=Mx9-#tT<*KHL?RQBZB$Mef{SY z5-G!987{72ob|-NDPlU!2`;sASYA8{Y6Y$Nr5TzFIA!CvW?=#oT1kng(1i(lZiU`` zp{mLojDu$b2+1HrkFF|Mz+*SgVZ@BMk*pM#!MC+*Eb@k((ko-R6+7@earvErv-%opO;f6$WAbcD244j!=i|{CF z$GqTZ0~T|*)Ptd3sXsI*s1{wPv`}uJReLzlK%nQ%+dh7L`1iLPKUqTAN!gGKLu1Y* zt^0l-rh}x2)10srO<(4}T%f~SY zlnG!9)A1svy%FfM@oACaj0{k?y*533&p^t1j$Qez_;-Vek?{oYE@Ii>lz(#nzW-YA zuDw+X58CNZ&*&-C6%V6;yH2*J09!&Qy0oc>mu4yH@-w@V*rEM0F`OVJI`wd*-Klajy*)eR zz2$YJ2e<*k>Hv9BGG4Dg1_=Z*0~Ugm7jPmOARS8x(;9qCz5C-e4fOOJ`hTNS1p;Fz zG~q0T(K;Sy&%a0>gclvbE0P5#!M_6x$mxffPd6WkJ^ck@MR)gnJ6|h&xn7U%qr1SS zGxDjU1C~)Q$WJ5HL4NLZVRhK=F{P!lra|tMSii%zKFHd{BQT$W7U|-Ap6xxJke!tk zR!GfT(8jV285VCF7=bK<<))i&RWz#l=3*qo64PXrXNY$jeDgxn3%L*_{sg!Gtt^=2 z@b*4sG)9@H$^+DSm4gX5ltVB(z)TG?zrXG7#vkYuqyfpfxr`6go}Z&L-sYph7gK3I z{?K(5n`6X`6jr4bfO7(x(FM6^K0uE>@nh@!dXW<9Y{+N%8%$zx zX>l?LFQcJlKaQQE#k=cydOG&i<2pAcB7 zZwv7qO+)-upb<;)c=-0=Hxd^P1OqJ2&9(Ef^1yz;yF6x2ZE(uVmt(b8x!8v|5uV`c zxA4*J6!e-;Bs2gmo4;W_KwzV@E0-F-rL3%kVA$ zU9Ur@7gkn~sxH2{@}=l%zs&WYmt9?tTE&2{-dR$gjIJGpvwqJOwB;}WL$o&9#m4(c zleD>xUD0=Tc1BORu&Niwk+`@N?b?X|6=ktWiwZ*jqUX|v9bSrKn`f9C41NjW5KWLW zU4E;AUPuNZtkc^_sx0%cO`j*$`rFvS34^dvjB~rR!9YwOSFZ|(Uo}XJ20*`Wu*gMD z&rt#kBHZ+7`x9T}qgZyg?YoM#EQq4;@g@r~APyitll&&%&2^N*=%vTW&l4w3Ku#DimcuBa=3^Ta?*y2`OGB+#&5exSMm!Ld)-yGwJ@Yi8 zVI0eTC0$|L|-1qY2z8P^qqg5x~><=VS+fTNIft;N`Mk5g4!iN7^{4S)@M zH2^|DKs97asEOb+z@N;8!5yHh05HbhwlpFlB4I4T0M^pJ8zloj@#aA|0zb4U!1n?? zB}B+${EmpqeWis1#j1S@ZWP3&3*jmzRpQ;XGpB5GKaQ88*8%%71;8^3?t?~%Fv@S_ zpoUOiiBTlJtOJQ^qqh{sayWRU+-Kqj-c61=Rx&GOQi zH{Rreq9QvrZgGpj2G!1;q+No0_M)|5w>Ao_ia}tuGk_IIeLbDDb4N8)T zWUN!ER0vTasbqM+cjtM3e>|UadQRNGeeb>YwXSuoYhB!h@Z@B<4e1h0l#*oLmrfC5 zgm5_r2aoVkz}Esu@7X-(*n}0I-=)|49W7DTEyqWez$Wye0Ll4;y-=}ZYyaNWS@`aR zxhn5PyS4ha8p+|g{sE{`a5&1_WG*KfV|D7>xz6O79WsK?&4mju6nDEd_ei#EQIVCz z8MD0fx$O({3WK>X4i1}khYdrTJ!^5GcEhc^cc~GzxqJhr5*3b`tKP0-lX+bqHI#^s zpt@=*;((n$uM@J_sEMYVHg3%PwBEVfny6ZFi)qE$)&9*5{Z$MMmTSn7T&ZZ9?%Nv_ zgdNYfpe}hO$**h)oaCCz0^kk4tZtlRc4){Csx{jW@0SE7D@@y=yS$hT_+5r?pQXA7 z<$0y!G~A|&Y3%puC%ISC?k2@goDAjMG;cgCFW>oKPd5&3`vqBBl`wQo$u`%t)<=;S z>~5~=DOLaALp2G4_Bn0r>du@v5vcgPhdvwiB=3LNv>i$b7^Tv4J^E1(ZlV`J6COY) zHOHmq2CvRJ3|hx@MREGBDO|a5_0y-nD=nR%sriMU>Gky}4pLR_QG#6S*)uAf%?gX2 z$;r!8*v`7q*t46*o6#B?d&Ve9h_Np5_$sN5*)A34V`5`x2V`}m+R07irm2IMPaR@k z%6A+H7?DVNYSH1qwR+=z`g>^vvVz}T4%B?k8v3q$7La!gR*~yu+t1|=`B67S%5V9v ztV-`5(_1bVqhpkE+}QjWJGOn$xivc*O9&deEny2t6T4DO5t<_WIW_lFpFW2cc$=ye z15O=Q?b)z-vmmubF!jE7c|qn4%NA=pyO4dmoA#W4#s1@TpkD*d8rzx=oW*zTbm>X! z2+n35B=BCtmQJT3B%el!*2P1Sx4?k}+W0R}5?&oEr;%joJ?YE3?gqm$h)__x6nvEu z;>QG(87Fdl4YxO|p3FbdRiq;>mPrHUKd8J~bGZk&6o`m>r+ICa09%iW;i^;1kP>!YVAR z?+J?&S&t@$nVUY!qT!CCw+WlMWm9_lzqz|L)Ld0YQE!oaCRq~on%a*aRYKms?f-Oo zvGkfKYsa-~hhXkRr!I_{MxI`T&DiTCmmofh|3ce4+3-KBKsga}X&n=YDycv!@jNxV zM71CN@W^(snhPte0U$R1Zs+{ae`6wDgMJTrDv}DT`dtVZRQowBT1S1RZ1`j14T&h1 zSjf?W6(uOXC|}47pFTD=LCBNPzennAUORA|*dZl0ww$aOvG^Rv7rNSw{v+X?Who!7 zpo5DNBDn(}OlgVaJTLK<1)w%TJmq)9O#fxr-_Y^V{^9qvoS*60LZ?^5yQdi3^OgL3*niYVmoDv}PsPT2 zdQ{Zevw~)8>Z@qu0IE)|xjIK_*3$eZE zjV`MX(QEA%TsrAP(EAOyCZbqcaYq;2p{u*dv(iGfAAtH|sa^XG7<{~@NJ)^WKiW^r zxjZqrL|5+;&*$lR6MRxraR5LU7&x9xHU}-@ZErp-D{FC4 z$#xv?Kfw=M5_$_D-e%967r52h_SqgKB+?}m?w~O8y`won7!ypUigneq_UHuRowq!F zBPw;yM^q&G{CUik`wtuDiH!Ec2jviDBU#YI%&wA`FS!e@$H$9DRPX859eo$#&G&7` z*RNfB8h)6VPQ4c?K7@nb)-@A{g~B}Z83OCu5^Syt3$>@$MCz4VT8E!Fk<4=o%`glB zS)g!odYQWhL-m70Cw~QeLwNk|_*v2SxUw2sR*=(^0XR>SJz{}05TRBJ78g8sU3C^dX5W=E~IH)^hUfUjnVgH~3xHLdX(nO*XL8*raj-5Nm2eG=6EwctQIo*wji5jg*lB!taIgjGv~5?nvVZ@baje9*t0N7pkRAOcXzoa% zDDv;WKRJLEuMQl;Be49E^OAG9#~|dVAuErQ*q!$NjG~&@1|b>e!0+ z4|dS$MkNI)s8NBfoxWPjauj!&nK8F+o#Ms=^p6>XH+1dPF!Q}S^R-T1rQ>TAC&bZ`MS-*g~?F9Q0(I;Oh8L~ zr2Lj)7W!>AF&a1Ucbt`mdA{2?Q9mU#{h;pVr;*U)C@};N&cljh(v0tpW)~j^A0beQ zTik9aCfY4DC&cu;meodC3>y0NyFt?w-}7UJ(O3NB%g&h$O0s$Cm?V4&q8KJAn>O(e zsH_m2uW25qI|R?eBDyW-j?90!1jdV!`k=Z4z5dM65FW`V&?b zD_bJ;^zF@J*B4%JX3I7E!hL6K%GSk7EImI za;e?L8}nn3s2%eWXz{3txjRS*1}U!~kVi)qej8G+#tXn~r@gsa`rsciN?CzIdR?I_ zd5wGU+O@szKR68RzAHp3S66K)l}VFmi9vM=Y~wcaXfgYx3{dB@p{`2}plKB}qBg1e zz`1iP-P|rCka=@FB@`u9!SI3p10kmLKyH2WWTWE>zd&8JP5=CjV& zt!hH>cTKhotRGS#!3vTVg5-B$&vh-Qgrav@Spz7#e&Fw2(*rV*X+w*W1k9f^=jyd< zPUH_R({ty!=?>wWSYPIi=~%Rh3tWfrVQI50_q?MNl5qL5a+(SJ$_}oFW^|6nU#iOl zl_xp`a4DTU`7aHhs6@h+v}ls)!rXF?!mG~Okl(Ps?})<+Q~h6EJWhb(7Va6871mXk z<3VJ7So1w>Nw=XSpXipT-VU9x=3x86wItx{U*jl^a_2v`E@u8t-X^4nbCL~+g!Gbp z`|=`441-}6A060p6u1%sNO4K7-ue2y{$OJE@}-ol7*r<E-!VtXo^%=gKW-_Yqanf@0FJf(hB^^y%l)KO2U>$EAcC@KCX#Xrh z3>Z?}x**obUj5(bFxdGNk5%;+>!M`YH_NrskU3^$p)yh#KYk;A!`$<ao#DNgD+tuzkHEKot~uiYm{F zh|vGiOJPbQl#sdf0((x$2==B%N}*P`5Br2zPEUO89LNw)Pr_6cF`hP{)$PBUy!EEh z+<}xIsE0M&jPf^|k;So}iH>3NqAm6Re&cDBBvmx4at;m}ukyDx`r}LaR+0n-nOQOc zNN|Qv+fnxH*>!4(6DDke=F@PWsza58jBt)>zqmjRAwY+H{=D{Ya9KMrpF{(4V_R#( ztDp2+UF|bO*A=G}4h4-9*aNOa@U*vQe|kxTUb-LkOMlPt5T+6Qwcjg1JaOji*`Qv7 zo9A^4I|Db}!&tT;0*v0q3RPtI7Jk^k=@fb~kxRxV@w(9tyRBaR{Xg-Pg8r6X9$hEx zY6;Igu%3&Ioaq0y%LBfpQPw~8EpVA^h4MbB=3aPV4BPyTpS{Xpbnz?1ECiA5drdy@*XV9(L8XbD zenG5RZ#wUIIf{C%=(P~_P!2~QglObVL4gO>qX?X&%2t?a$jv`z@Vh8xMxw%uvbW&k zLqZP$n+=ZD)Hb&ZJH^Ed7DP<)7*b+l{|RY5qS(3?w=kF{_;TTa{82rz4qBsyi_55$o;8Zt#x%Z zn*REteb*&99`UZOT;y)tlj<^5efR~u2JMA-;dctfyg5W1m)(G`V+A2iFgiD>%qEh0UE)G?|5fKx&_dboH;tj1p<(VZ5 z5*zw&j^6NznJ+pK*EZzaet87x0tQg+xA~HL+%yVk+@-iJ!+~g>j0_8F;@i@h0n6&T zb}bLU2g@FBjZd`L0->i-g&<)EiGjzEG%r$;rCU;TWs@S_`%UavaLxWR2Eod`3B@D( z9e}^yv~}w&+YlAMSL&aQ9GKK00x>^iOKrX=`)Mz z`W-y%pYWY`Wcp4;#1!`OuCi8Ey3THkPFa;ZeiFzJuB6L@J;& zC5Iy~&THEbU22ts0u4!vpnOR=(nYr;c~2Vk3fS^_0Cmt(>={a!1b=2EHFwXC2jW~;0E^oTSk|_XDrH)?xi}2q?16%dXrNJ zrpRZDBwLpGJv{8gWRa^^w>td6^E^PJ_m1DqYW}UShOkdAB}$5jQ1QN48bU{lloagd zDvGTuR(SmFWjF$xq9hBmNghr`1fYf$42RT6$+dGJRlb!S^tZLq7(C>iQ*@H-H z@q5U2Od_;`M!5#7C=9-4HO}T{BOf?(>QrrIWxzw3x zT#o_57+`8jUAF#8`I$QgL}#!-Sl0rRU=VVxXzHszGC}ptJ!za)PyZ6+)J@W#eTpWC z@{w`P+k@;SRHl5TBl7;mgCR<1#unr28=N95&YSmc0^)eTRxj%PX+4ph;a2bUMEY$Z zuTg-CvA5R-{~=B5J$(9dOG~B&RZ-|SpYuo1U2!`|=iAF2#~p^+ki)e0-97(%9)6gR z%hMz?I51~=fRf<&uRLQPnW z3sxuE6&?-;jZfSB`FKo>1A6>3si}S^PtpTC+s$oMiHWve0RKkCf6Lza<-)$;=gD&l zk=p`sMrc-b@xIErSLn|w&we>Y;VT%4#&ndxVUag)(mU14HNW$xmhhvx4-2IO<~C1O zVq(>sL|s(Oc;qoRd;2{pM~0Uwj$98l-rQ_b*m?q+CYps9=dx-gw>MSTW<08LS1#I# zM15yV?SiG#M&8Vy;8kV*x6y2WifoJjEA?QbFBdE&X>eJTaQ%rS%12f!Ca$58m{0!r zC4Cz=<)znJj;O1Ng*bA?1=@Q{z{0V!A3ZXS3ydB}JQq9d;;BrQ7#6Oy2@dmsXdt)@ju6Au74WeqqUIloWyAZL!4$6-7Y zw>Y_85XOwjja(G{i;$K*!Y{j9Q`na@II`=x6{ z!xG^KaMmdXhb?JZnCs*<`N?$99SDhw@QA!9HKeqRLs?)|{*+MRH2QKZz0sh?UW=!W zH~RyVbTch21EYr$lOm3whCefDA|pp6e7uMT-}9)D^GF5y@4G&Rz`>64sL2LaN8)Nd zw%S`lDzF4pb1mq~M;-bzC_};f^R+hfR16n_j)#hxVVi4NH(f{`i|SsPUllP69ad1; zBs8b3TKSs`jT*#QgjF(E^zyjhXr~ECO|Tg{qAI!5Mei|x zyf<#d+}0#Lct9woWH|z$=F;(4{@5`IZv@J>+y-isJ-*~Te=ba3D>uG$Ywx~&^hn6g zG0NzcY?)$ZZC!HiZIfh)&uBKJQojR?I{2RjQRT;vn3%As_vNm!nl&p2!*&XfD>)k??z1n!Md$CBl7xDO~akKl6>n|NaX~o^n&Pt+$1_^n+i%wcdJdUykKe zA__9NZ}(<1u2{;ybzKNi^sw8ZczYYidU9 zI&Mp}=rs?{>1#n!qE+i%RCTTwl3lwra=dh15i4GNb0-Vt*?i(CC27;1l3jS*> zwAVxfOjg(gh}$+q550K`WYR`jy6OBgpMP3 zgmUCqGz@=5m(YU%d%ys%u&fM=lACYb)zsB#*cvfulDtQ1=AbWrw9yWo)W8pCz=8QX zV`=V8alNzC*OqBOP>Npqb@R{5n#mDV_3lt7LN?Z-Ch3oM08i(I)V+Bng4ow`cc{wGc*Zp2!(pse3iN2ndawa)E|ry2{n0C2Ie z@bEd;Yp@QvnV_)7-YYC}cdtSCRGgjQGT+=>GJKB-yIv~#hTU;4(zouv`-^4XR9{2g z3*wm%;-LIAIu`ZLQc6K<)5QUR8rRfJAd^H3RN|_O@@dGSkx`>64nuK~UkM))jnSi{ z)xkg5vySZgSXG4`=vsI8H@AD~z&4Qh^Rp>?Cf4U1nTXC&ppy_s>Pe?p3q|qhJ9kc- ztDZN!nw*kS<#pTq>XH6uU%L8beW1wCN8p>5lHBrr2^W;3P!Z8m$i2VU1dsKAH*z|Q zsAJro=LX#jUE)q^*=d<^cVB))$O>N_n3tQ2!$D}7@TXhqmJ|DEC zH#<%6Lt&pUTu7ao?(s`7T^51o=%S@T0uj@I0Vi6=bTd9uSd;w9T_&isnVCR9JEaVY zK9gLtsj>*)w0G}Oa={A05BbK7`XNHxUsEt-S!iH4eHIOyGEm4e?2!KVU`Lp&NLyq| z@G8(TNIh(cvbudz;qdd9FVhHF)V8muSSG>*`4EubsktLVvI)U-hp}$t0C2lx6^Lk0K?d`d|vDpVP(&yiDDK>USyfw;v<&3hD5|b^Tw-ukC z`Crw^!)K0Pj0W{)q0XeLDt0#VU^S@ZlF$GEe-E!Uk$wO6!_yn`Rcj_7JNRqRDs+rh zWRN;;HyCy@--D9NFa$d`W2tZiLr5d63o~a=aU}l3<{INXo);DEM?MFD4GEdilKO!M>OuTf5zkEEfMb zM#$X4!YwY<-uu*l&CyD#s&SDO9UKt@O34kyu|YgbiOFvI)#v|wGCgTnf{rsJ1zn#$ z>}hxo#1)2=b`F?6T!OP}`L8HVew& zVM7)RzlE)dkIPKknRjcK980TxGX1V9-<2GV%`u11IsXwiqIn z+A4ymIXSZ^wpRO6t!GxQ=07Q&)>zClAE8rRXKC&1`hmoJr+88r-gfc;277(i*ITsj zg#?8N)NZGA-K@9HHyZ!P^c*Q3b)yjp=T~@NEr}6iQ0>1KJoAuxEg_c4JAm56ZZbA@ zwY`0GQExdeX;j3lz<11}#=JPoj9`bq)GtAdE1w#NW741<(s$~Sjufp;L8cvO!ps~> zdYm?{fdT1;mszcA%!Z1{sTA~t&!3YJ2>H{$|0dgvt(`4R-r}`{v_mI?19CX0@<&Sx zCq~$ZrCa_;OG4g*sz~Dta7cVSd{z=%lS6c1VYt~Ojahgm-M_zbtbG3MISMMoZV>DU zLAt@L*$+Gbv={~Ni84XVGnk@q7yvYB5{;dl37#DreI?E033KU6K&=j20-Bj=n{Ua6 zgb!e`3D}@z?yzgun0_g}wiG6o-ZM9r6nAvsX-(G<`jr+hPVJau2v>0AHdh|iI@0?Y zKfA$l6%98C$|^1^bKkg7D2`x0m9NNXr&4*X<(Qwm@#t^$bb4Rh1}<_!q>>t$N6WS< zE34WtWyPAC3B4&Y98~PC*W+aVTR0oCZ_0y{=*z_r1*eVhtuzKgjltD@AqW$G6cy*i zTlZa5-jm8??D_MU`{Mtw@0|V~b_Fl7y?vKP26vtC1}0BV`)ksS7twhP+LzxORDF=+ zNCFyY^81xIP0s~uXyygx81FkxU8MO;el?rJWXW1*XEGdAE@@6r`emOs*dzUP`iG#L zN?uM4Y)f~EUbnV2od?wq9XMQn%iN@A(R;20-3cHMKq1^$p##F1IVPM4EPeH!yK#o#sVj?Vm z7hDci54mcIr8}Z;F9(}MeTnhkC3m9)84okiFx4dsnz!IWk-b>5<*!!^K?S&xKXDNg zW4G6p#7C`Q8b_V?o%3UNndEx@o}jKS7%otY5%qh(ow=4_5D%bWA#&ty@F#qo+L_2 z5AyTppwpwU2Q@^YRiKVxNhWuG#zo1N&(G@-7!>_>h7{CU z*uxN!2uE=RBZ{b%&yBn+CFak*${h!_iU~Bj8+xMzRPOG6&E}_q2Ibm5s6$7Oph1Lr zkyRj-yZLK1_II01ESW4yD4tfag5ONIJ6(X#2W( zbBX-w%`PNpWjc9D1?uH5ioL zGhEMG@_OHLmZy-HP;GF@T$O@0u9o|BjmaI1VvFUT4clh$?)a#MG(0;TfTQFmcKxah zrR$m6b;Fz6-)R5^?IeojxCX!pK(Vr3#5Nya%Qq*8q~i$-h(3I`M;IyLdBzBySNC>q zr4er2KQ-TfBlAZ72GWJK-=NXa2gT%2J#US%F+j8@lIctTUkiZvhIYr2R_9(4SubBQ zZ%izlUIiYT#jG}P-L*@YauXja_!2C>x@7k7S8!LbfrUro&dFgY6m%33 z7aI9`hw|b1d>s~R3V$fD90@ap^s*NRi6cNrSpVk+Aq!y5I7xtyPQ(09dwloF6a&GD-iR-Rj=*G2}&_jSaxs;O!$xrpBM~@zs^oUT! z;>y7-M@D7*>rf-5TaZ!YudLhK?5}Qew<=G5eCVWuzIivMx09}q8aHk@TqV->xVi%q zv71I`6S!|5`r!Me#`h^OlN<6f%!iLAJ33qQl&W+|oi|=Q9np#=&+c{%GuWohOrTrm zxlAF_MR>Xy3m0x8oMJD~S1Qmjoq!Kj#$2nN&;#_caP**l2rM5V{h^{|zj^yL^#-ES zhlR#bwVxXplK)Pia~Cx3d37g_fVf=-7Fwcmwi7qgo@%XGoh&=u)yvbjCH)9F zvhM4vWOWu4`6gbplP0yYO?euA-OF?Rk5l%bj~P!83R$SPwxF#K*UAi*zWHt8JAeUg zV(ZIqCLCHfY5lu55Wbwb2Ri53^zY@}p#bE~yFkQ}=OcHobuCO@fUdTXe8LdIila=|j{ z@VVCAgA^YY6>WeB<)RXbW{|BMmD&#yj^JTX z&WhBvC+^-A41G|L#D`+b`@}IRE_4FPCtEP}VqFPnL!!^Hu{B+52pwLY%K0BQu+`oN zQ>bD|aU-xzd$L%LQX2ogB2J5N)$Z;Mm6e-5myLQl@va1!1TY1eT1RE5;s5%ehfk6; zHRQ2QKo(PIgsDy0Sb!|>#Xqb1tS^_r8A;64Fc!JrE{tT03%E8H%&!LP7;{fH? zo-N}3LiS9RJ#KgsmlYtf`b-)c*ljK;lqx??ibAzSdIKGlwLH0=oKm9Kpdv(+!hL}o zHlu)n;~r@}W+}gXeX%|F$&>92?xV&x^j~-={Kj{|b|;2T_pY^4koif!&79$E&2HhV zN8*deV;T~LZceL2WVOuz0}i7$BD0YaDdW-aZl|fxhNlekFRb~#&0tXJvZ>!0ry=UM zXS>V5eMU-x0*+0=0pLpSVogX)!{ncL)Bbb3zx$+}JTL{ab@~ag79W{(=Cq*kK-LG$ zYK7;ko5B0#OUjDH_esSO6&9BMQ>~MKI_@e-3Sr^O)#KlvGNUNDeds%!5Rt(@9H7aW zWjTX)p4)=2;vuscw&MGq;ujT3uPnk2vOzq%*)YCKybn#1`;iguNOL_Scy*y#R=rp( z_%D_$E$=)?N377tv7;O#Tl#+CF-qnYX!bNme|B#3pC8XYib;R5T4D#|fi4jVg5Lk4_5RCTdom0{L zJdi7OlaVY=kNBJ;gjiC(G}!b!FhypNwvm|yx>U3#apO)?!Qyh_GT5+Rl==vQCt)-= z%mI_l7HY_mH*k%i9Hn4G?$QN&6zCi+lUehE}enUU7*jDRk7-a81DErMMQWY#XEDFl#}+l-zy_|G;ZS^zJ81UHRo;Yn^G?SgmV~ z8&`;qHg5_K<*oM?cUgJZ*Oo8kkiOrQBoTj0i;0dt5!}$Z)pX?gd2{EoJCB??rP1+m zEA!$*vaR1Vd_frlz>-RrQ`p^3EvAxE*+#A?p<4P?E&rQ&WG*hX@L_ZIY3U5?Hfx%l+2ys)~Vou7rrqv z4Yr}a_9v;EaPtDP_m|maW=HvUGE@l8Px#$?4;+~7?cD-2qaR8@HK=sr1~{~i>aO&y zmz30y32WvC-A{s{CIJttJG9urL3w#cQnZ*{xRr*O@gFe}QjZp-&rAcsN)vk&*TOXF ze+bl`k!sOyPCxa@RFjBi#G_Lu*XLNtDJUw2DooX(n#GI55cLxYgJf{#==Bc!vKo+~t3wBE zNY%Y@^XAuw&u7pQ(WD|y-bP)A6>wo)*uPD!t;5g_^SfXkhK1thsX2D+F1T}m8wEE( zb5dO$c+LJ60syA>n%Rm=T!BI1swbR5v=tS|d+(jt;+cQoMbQa(oF8@-25uiB(`@e} zru@BI3te*WWXqS>`(SjBVT`1V%vW!88AtGPyk?UmYUZH19IJe|u8KH5n39}~>Xk}2Iy&mT)m*rs0aSk|Lk=A(0NL=LA8qo%CZJ=t;_zu%U64R8);3)OiF3_m00vhQS`E2IW-FbVc&4Yv2YzK1YC zP?GYwFl#7*7Tqp|6JNZJSP8UYPtb5or4$auu5o*7rjaswCi+gXOCd4CTGd!>MPq$A+(RwY5SdwlwiA8UzWlv~jg?O$K;uwkJs zy(fT0VZ;BMF3ipmy53l~Q423T=qD?(heHI}omy;Utt5*&Kd-Bq;wk_IwvB}%pTw*d z+ZeJ5{Qhasp@v1lo7Z!B&TAJM5a-@icTDjcE7Oo=<&EwMl8rI}l@ysfrXDa-!pC%?va$n5wq(DlGUz(l@^_Y#PERqDfiHIkbQ?jm zen%uFQcKw@g@2_3mBoWX}zmR4CZS&4IcWxC3ESrh|; zxRS#z^liR=rrsNY%RZ7VfVm6h8Wg@ahC0&}=A^@HGiK;+fr?S=XoVbRTVO1$iTQMX zwHC^4X16R{_?>N|ZF`o%etaD?BdC1e2Op52e!Lf&LhPrqeYDibV}t2yxqSJ+m7e8Y zB97iiD7BAKQc@Z>&T@LzJ>M?wa!-_wLhjNY&SoNGW!5QIhrbd!1c8I&JWyK7H&Ko% z>?18rN#y9v4RNQqbdEhSwVj!^noY||5H7oOz!8Q8VDN{IBrdgG?plpU4w>0noH9u8 ztG9&Wp>ZZ6LLl)oe7n#BOrsX-a`DFg?2m%kDEbH*6{jd@sjIt`U0R?Lrhxj36519T>WePWk>tWHZHJX#Qm#;LE zJs1+Q6DA$zjao!pAB`|`3Mpsj3kk3=>TICa$?}&k_vcj7-%MP)ch3h`O>X6Znzpo@ z#1r~^h>O#`j<$^12j;Yt=Ts)yTqDC4)Dbo|RQNtsRi(%&fC$&Qx{h6T16ph9*s*g} z`}H28TTA(@@!Vrv%!dydf})rT%0Y)P>hja0Lg&59i(u{#^FH}6U>v|Kp0DO58P+9SV^2RRiWz0;8=b+A54otD$_oA z-4;{=PoG}9as@j&dc2YUa$n-%@t-V_Ksr}i)k642`_ip*qeGge_7;JcNghvoGhTftpdDUK6`oi+?f#0RtgwBc24hAypXmLdW z5p_1ETelPWq9RK2Aq23EyhTm}E*%t2P1Z$tgua7;VRHcQXY58Xi=huQS!iwx%5v+n zES}FHuYr~!+SFa$-Z$uP+p|i-`SO_B%`+g+xMRq{Nuzk}AjZgPJ8zo26!{4Bpu>PW z#ED)msgwf>$%U(E+owauiGh~f_^XDAj0!Wim@|joxKq?Hnkr{W1h5Ewa1?=}Jqg1i~Z5NBw97MdlrA!xOzhn8222{UKh8?w*xwrpMtEyNTA=EPpDhv<2`GONq~N)cdB zu-Mpud6(|emz}-F{%Ie@F@rn(@%=kJexE1*WMstzef>Y69&R5z9_;MOaf#H>$Yli7 z?v~??*`0lO|9$`*8H(&zLs66IZ%{lM+%y4Y!3m4SZz8%-C$RZa&s|ZImE;NE zatqnm4Dx?y72-et@2{sEvT!6yIr@%A>YlkpUvRXlJyrRMvqtm|IS%A3VMEk4Og5GKHaS zjJvPInkd8fG@b};Ldk0|)!M?HLR-T8`G?8pxpsNgB(YF4RrY;^hISblr1F>mBfT1; zZEuusM;e9-gHe3G48i(oAtss$3qW@2oY1%v5^KYh<@l_?rnk>Jc@9|&w#;yAh~8d8 zK3H_{ZiL}9$;qS;gZuZVEcd=;ob?vf$F4Ea(MB;}N*_KvpP1MfdB~37m3XGDDBJ3m zRCyFa=HGpkBmp0|hM;OlNl!mx7W?Dt+o2Y^R7?AYu@gxVxhN<9^Zj>wV`C#aTM(b` z_ZK{!;34bVwR^i;dml7ed^mM8oxI)Xfonn++J_kgX2)`@>z?$Ne4G&n7vlXKL_K3-)$SMD-KBU}~2Q_w|_mVi~%>t~rHgtB{O|lTWDx)yK zXLvVZY*ej}BS|})+VbTJ-not3N`rbm=C%)8oJ#!;_aLO%PR{Lk;iYpwq1yjR=dXMd zqHT;}Q3dcpQSE1R3Z1yXge^))h&HM(01k6~?iuX*Fx*syrCO=%c|qTF;Oz7I!Y~e) zGNxq=9X>oXcUYfW+T+I$CX^9mV#Xn0ajp_mB=c>gQ4e=~H)W3|N-4ZhP|K^1$HJUi zte70K_VII=&9_oRjzr1pWugOZ+;h#%5mD<583@^!Tl0OY!ZXkuhY_;eFGZ!-DF{v` zR{34LSi_sTb8f5X+X;V=4f6xBHASir9~n8c#LIq9VGTn$H&Gsd?HD}SQ{jemlqN01 z-q7L*J#<5vJDE2)DI(!7Sy0NM;0N6e_D(7^4mr zp_a94dQ=YcIMQK8sOzxRAurgoME3Qg-)qaA)G}}=KmFA?3RDPq*MoOuo*TPsK-$x9 zJGquOb3O@{93p8owLwCikSYxqcbI&0cQP{A7-n96sILz>F2SP#ZMhv#`vxd+OAC{! z$unY|RO0BNC$A;eeO+aHZic0~Dnh&{DBm~ST9)M*Ul(3`hHTY z4}Sn~FzFa(Hn%f(P$Ir2A3uIXI&$(%qQ|_+H;^QiK-_Q>5QCAEjL_^su~daE5^oI? zd?dU(H7NNI7)|c1!#A(_7pxfvFF>5qSmw^KXx^A_DnZz{0MFA{@hH1Xd-Oq+=!E;FFKroX4ZQy=Gq%7p+WDT?EjRBGF-@ktl z93r*tBQKgYc{dbtK$*T&*q}qX{-8(VEX^o)6OK`5;dF(&eaJFoPf~$Q1MM@-1W6() zJwCki+try$lF#U@sLne9&(=J+Z}%_0#+J zzpnPWnK5JW=l+2v0%W_rsmE%wU()LiIS$D_Viz1i*oKx5TK>7e$R2Px_a*9hwT>{6 zfK0Lyp~Gt8M76c$o4l0O)dvn8iW#AW|D{T2`6ndr6uBYRFhlEDI@sMe$f7ktN%j(E zl%NI}EK(l&T5L=DSfo?!MyeITXp%Igt{@=^M~Z?m$JndbqEjfM25D`4dfbphog9Ob zwax+hP=POjxf?f*zb(E@VyL-lGdw;nV`PaP`RhI|3}{o}ZaRFJMl=FW@18xE(R*}T zO=T!mU>5Dm=g%tqsvekBK$LcM{t0cFL;1Q9287$Y%wainmIDnnhbx>}Fgvd~Nl()u ze+hruNS&Y#{>IUxn4z7C$rm)IgJX+$gJ-yfd{Y!Yc1 z7|Qe-^lih2F(Z8c9o?S%vY4->>XKr5EH}U6vQCWW0pMj?; zL_#Fi@g%Tp#LVMSedarE+rE8N!OsK6%a_C8{O0eQp7ve47XBokl8TKD)Sioa@YJw>y@gkr=Qt|x zBGH_|1od1uplkT!MaRCH*}y;(p!V|ihG`JV6j$m-M<{P3*;jvb_tjBQ+PleT5g9zn&VHgvKc$^vr7W z>1-F~W%cQU-EJoNd3c9MTopHl(20`hFoW0$CcT{Tvz|UxP*6Y(*OjA=ppK$LKQYmb8#W-L zQ`$dBH5PjCbCzN^ky}u#EDg~HIvqGkNR!7OeEs@WHa6z&Ilpy?BG<1!D=q!bZ@0F# zX4~)p(sBtjLT}?+Bqfc9x}(51{^0IKJps$kW_=J*0MG<9e?M^s^Ca;OWeK1+pn7a< zY&N8aVa|-xJlg&@Z$Qes!W@qr&B$z8Mhk#ROk8~Y_%71_#Y>jVpFO*{w3O!Z34hDw z7yV_mrNj=Ip?F{%1wse1__GWmHZxoE`%$Q3-o$rwR^UC7WuF)wtz=Q3HunRaFZ|gt zyWra&Dl7ZT%WI7u{gBbv{SG`OcPJ>BsI84r+2gEJxZczK?Z!-Dcmx0@y^d-hX07-1 z6d0B#n&KOuJbfyV&Ib*9^zK~%B!q3oe&R$#1cd{E$>R%G2lO>&LKP1MZH^@0p5{4F#y1`^P}2_j~@}h4W!UDVFJFQ zE8F)z;=cqk?SW^OjxEI|O)$t&dZ7g9hm~ zCN0FL5Fo`~=f*t$HEq8V+K@N*b`oM1&77%*dXa|zyNg(n4)*WA zi3ZqBo4z}re5^t(g_bR9BJnSc3Yc32k-rD!?jmrFePkjoc4o($7 z?$oez4EK5Zl&O_&!bQOt3Iq$>MSF7Y5znZxm#M(|&R_jUG3%^Q0;c|Xjv@1}~;ZCoR+&^keoD@zET?0C?Q`)N)L+6%;rQyDA^|Ce~Bpv9w(8 z?3~JN4$uWI)8)4yS6MwYIA=TmC;Lo?N3gX$&CX<>ta5&Vg<@`gKJ6b4Yu2OH7W1BL%r!3TAb9~3*qbONt!xk zisTgaLA~Bl6r(DEZh!pk!9Xv>GZ)%UI}-(|fp9tzr*V?Dy|hOwgYG8v>vKuz%gfMt33@FNnBkTZyCNvyrFxFyO-Pn@;7 ztVTsVdM<(h=wW(<&EtMEN{J)^ViI163ljrpW%lN0ecNs#Rx4NTW@i9C;9EbE{E|le zn#aa3$jVAql{#=lv1H~u;wnM`%*SW|meVn)jiGhQj!>f;% z@@lK8=whBJp*qXe6tf|UZu7d@|MUS{pZczk4+l**XcES-#bJ#sCfpzfv*p0PbT_jo zAEp(ulVAfG=Yb-h6-bTVN$!a*H-@zH=V!Tms5ak@Hu4HH|5P02A#yN1jz^E_?R_aW zM6%xjj02xCOD4t&!U7piNXrk#YvO%U%-DQ9+sZ2oor;A_3#5(6>Z4GR+kv?o#3+4_Xedg><2Y#OeVx z&vY&|GTQUS*Pb3ehhJiPej+D_ z$+F|9shcKzZU36Il)8{@xVmbHh`{+1c}-WW8{BKd zly+bXmVX*@YrVX1y(9ZWOG!$`?&5=X_um&UO0a0)Poe%26R&Z%{bkIV=HLQXj`kP= zJZ|i7CQb%{&m?;EIOd)$j=L?Pg8z`rA!*TxER%KXFa)SXQ^MG|4L=_ckV{{`*3;EZ zxpu9Aw3upyTx5O-@xcH&ytJgGQb!4m5iF8Gt?KG>d%_FbnutH6g^0QuRWrhR0)0+4 zS-U}x*fcCYttTnd_qn>LAG}#^p`g2m)wY{-p?@SfHU}0?fuhX%=E&Lq{3r+*o9mcz%wS*)2HDNa(h2#%G9a+v*Vq*0v#Kr@HQZiq_lK7 zLts)uRY*9pEIr>jj z9w4%Z!H;rM&Vch*)+F+n7NQ$tiiDy3zW7}F`6vJnZWor}yWDrzLRVQDxrqm$Za)@I2YnYBK=sK+-XEAeTHUEdNN5TO^e=`B9vS}be=a~QKDe{0j3OGhN z574QhTybV}-Ip(d?uaiUCnY!_01)Kl;+!JY4+~A-e}_mPvy(mJ>gmZd5LD7BqJJB5 zSSj7-&m^)*EiF&I5nE0J`2iwa9(q%zJiTbl`$p)9W8lRL7qF6!nzqx-ZSgLYXKZ02 z=cvX_cPNY6;L0U%1>1H>s+`M%w<$Ug3*_|i|$f^WH}l1*rui~CIbcSnwa>XHprta z7y{iC5;7u9>6U0fCVY~fzCLJVVALSJd5BO^3YeSc?&{--dWN5kEPnOs2{j|0XJ=!X zOx8jD69vu2O0yEDeeVHiplR~j;|=y%i_-H83cx#REBAb5+Rw;qn4NCIo2N4rUKvt` zQU&|vShMW%B}=xD@RHyWEYwUna1aKh3ltPXle)=12+)~0ky-Y~a0a!vPka+|?ES&e zP$W1Xz!St{jxfYI@HyV1G&nJF!}|5(=-T_`aM+x%wFCIOb0^w{0rK)p(jL3}8NZp} zOx4k0Y73|wgpR6!3m3NL+3ssxZ*zaH2@4M=ak5Rf7ZZdRO0upjQr zBcua?2laYUTB`3|TjZbqOhiN&G=1U(m0zlf#BV%<1y7VLzb?Pu-xG+?>`JgNWkjl@ zly>N3Rk^3O=Jw)OyO@5#L8Q}l%&1ZGGH%%jL(2KT@1Xd{Qo!F^d!>Xha1a8XvFTE8RRYY3c_BUbA*zOAqnv@R zC};Xno^{HUmk3?|_S$&wlRy?fd+uB|JHS^sp(!bk>{R``ix`=i?L*)$e%ixj#;jRe zq5PntXf)(3Ks}*TYvxxBDwGo-sXGe}9nSwg8_ps#4w;0Dt&GbS@m_#Y2#e6L6S~aJ z&7b~`M~_BZwQASqlULt9>n0UwF@HW}*CF`HgV$&Mx@tM7SNNGT?J&ReHVq^4&E7Rw zV>r`qR<6WKzaC`hb^oN?-~s!VVsMTcScL$6g~jMDO0o!iRE3LQqT;;3eET}ltB(wi0iXy zkH5Kapat{W#;w3IAMrHa5Rl0gCJxO@odX z`fRU%#iia(EdemW)*No7aU7BX;13`e+_!I1bkIntKs~faFtwmi|7ZVLX|(VLfPlcp z33J=HQ0=u(m7E!cIE&t+M6msB@ysaB23})K!AP)84L09?o&(GmJ|7~M&T~cO+d=^v!z8y*p&CS@8mWil$^Tat|V*DtekOaendO? zvM@U-15n(d;NTr_;Z$-Vo=_fcw0u^I!vSrNvu7{6^kv{C31)k5rQq@X`=4nK!$mjE zfNw(G>ict;=1i~!>E^t$Z=)tm_)dIj`V@s;Iov0zlsNw8*2XMGI?kW(d4Ih0{&LgU zVoJa~3er?U-?A5Hx3R1FjdSN7q&*ltLysOonBjYQ-GD)^xTbHcRD>>!VtdfOeYu*F zolNXD(9}E>7?_RLh*=LO?NH&2ziZvD7du{CTVQ7BV#&+9a`*1g(81>9)ccUHihuqg z4xKZj;oGQXWi{9|!U&1KI6HDYOHbNCy2gU#oYyzL6*V1I0DFm*ra7YV`st37JRb;7 z=p|mz7e5Doe-kn@3O~7;1I1xuM-ZNtF5OB3?v?Lv$X+JqK*Vg`v zUcC5JUw@Zqk-n4`m86?Damb?;gPQ!2yLa{9E$kag&mP7gY(pqZ4egD|kF@5P%Kx~% zt3}Muh-Mjh4{}jz)xJ-|JCoZO!gfkUnix+IStirh76e3PE|x(Z#|)#Rqc_k-iJ)X$ z#<5K*oJ0I#-olC-jo< zjs)Nh2uI9=Ud^{`7cYMOn(ew40VeIUCNVT*aU#j*FUOk8hRHHsHX%VRO>VDWP>{Ng z4ox{@k^dfR_@xgi2VxbzZRjwyvS5~&&BH~+btC;{w8bJ?kqMbGm~MI+%S-nho2DeY zKQJ(!&ghp{pS~YgXp2Jkz}2f)vA!VDJY4Ns%du7%Joxq}-)k%H4f)P~m;viW1_kIv z0zbpO_%aSpH$gODw0+pbaP?x+hw>%At>3JhP(7m_nkb5&faeCALrixU6=f(MKc9UH zD&|%Jz0pFI68$dNRhOGwfBg6+i0lnh@L?)II+&Q2whBpX%OGXt7_Ktnl$xq4c>$&s z3r)ffVUJ0f~rSR5x8Ra;&e!l)fw?4e^5KK(pW^6OOH;=w-ZrOOeWg~ zyR-bG6&6>3)VMe&Bclf?YBLrs(p6G=kK~noO_xjL0#6epMimu;BdCgsiMe?#x%ng4 zJ_n?U@(UPpdswUqSH+UDmXY@a(AQSJOJFoPv~(5oWwsfl)TH(zH{c%PL-ZUWyPr2o zrVNo!!a#M9&v$4^Fz8$!sB<{oa|?g;~GDngB4~c zYtj$V?UgHSf6f`LSaFXL&vc=ysC*24^^>cSj=Wzhw$2wiE{`0MWnKpO)UkIyJTi(&lI2Drx(9xkhG?l zD6(o2tGBeN-FTro7U389aaFkJP!SOd7-vb6asteuZG3$0B`1GB_%DZyI{=+6xGiyA zYE_jJPK>_|1j@kM%WJKhTg3O=XAd6O<9K!L8iZ&ir176{&Rxhc8L6o%tc6Y*4~0+Kb81C`hbcJ;S-+p@tM1a*hMh#-iT( zK(|9?)YgS56(2T`A0yRisDvO#tVP;1Xz*Z{iz4GB7bV_r-xYHm$iN*_@<5 z*h$NW{G?h1ML;e~j>H~ePLTP*&leyG;5k}+LA{76843~dUOFt0CFBtt)qNb5lG@sL zj!gsG(eKGjL<;jOs&30z#%Di!Mk9#lx^*1ut&qR4(R0(ko(X^@IDRzqlJ(O*EL-V6 zMvyNLavN5U`4mKN#t~;bU7r`kPTnB0A~vw?i_?z;DKk@Rkpj_B2(Uh%GFhS2;QECN z5(i8n#8=(g(Cu#IBsDc*E;6b2x$mP{2GTI9^cfi$r1iVh*23AjtgEPSaCAHk&Wvq@ z2PeuSo8iKFdEe)5M8qo=AhE*#cPB@c5*Uk%%)m&A^MyIR*(}GEkJ?EjGV}88H2Xpf zcu=HSJJ+A+$&DVjT|Ox>@raF2XYXZW$RfV~_#wDul$9-Sujtz~VR(-oIVlo2XXNPg z>m?yfX+yx*)KoC_|7bezxE}lVjen(*3LzCjnns#Nlm?ZEL>Xn2kex_~hDwq`8A%#O z$d;lc(IP}fB&(u!(=CmSG_H*OvsX9q?^Xf?7=F=dQ!W>X3*j#O&)OVFN%UV7 z$`mkItJ6BTI)32fps3hb|FYr6!hGXb%QtK|urezFit)ycBTHtTnY=dZ@8UycCuNko zGj{-UN+#E+kX)WJa1uo^14>L@vI-TVtheQq*I$Wd-4-((rck7bg zVu73a7-=sUQ6ldg5S=-Pte^cJol5DRE&Z< z1UonwakI9T3~%FGaE6RVD{(8N)vk=``+qHftSsOv#v)fzQVuV2Vv-94%XJ1wqwG6)I=gqT$^KFIQtb$RTypZq z^)+3qIS<3tg+FXdCDnoi>vws^OUTT~V6LOn;tG;^EilB{V8#x_OHk7LjdAm@u0&g^bLWpgbloT0|M)@dC%Eky+MPt^#0HcO3FEh7c^&pP zMI;@flN=!v^6c%~5rYR?#9p=W`AwTm`PnFONqYrBlh8?h#mJ(?_hn*>-Y+P;VmLfbt%6Vxj83d$+db{4a#H)Q@-ANJYcP^gc|A$LiI1t3f3c4D{8T z#DwY`xx%nZyM>%N@Q()7&CS8w0O$7X-A?HAFYFp0Db-NO|S%z)&i zM(XL=)A_)$?A!PB&6^^2c%u|!dV-4urk?OJYCkpke*wH5hpQ_HDQ+zKnxv5z=)iN7p90iE}|y zZsVSHGJD~0v|>Ysa089makBaJ$_eiC2)UduAOw(Y*KY<>R=ApE@S>^w$%`Dzs_2hv zmqqp4bL7Z8JG<_UgL%W8M5VnercRaZ6&7b2!`D1m(d8NSE?z-!juOv<5<5Yh<2XW$ zLA61bg0=atKhMFe7-6X}>T~LW-;^o4sIORvVspNT`|&)v_{ozQeBRksJ!B<88Kc}s z413`GslFa{5H5MN%c?7bO~e$3zl1nIasp)lI)b%PeU)Vhqp`WUZpfyP^Z^uU?l|Uq zSR&=5Om=>CJZ4w9cIahI6<$0F9BQ0{%mLG zDEpEe*j^ijcLv=Q6%VnQPxGMHxVvc-A@pA$I%GkH84HqMv%a9s-xN2b8-9PT-MZB= z=tj5cc6OBVn3|-bXyM!;LZr-N*9tumoCuvWS~KPaAzgnhm`63tIl}YbjD86)9u0Zp z(w$I`fG-0E_+c~w9P>ld&EnW&`u_bhM7aj0raHJXT&cF%_*-1GE#J6v5Sa=GEKMdu ztE;WtS}A`x^1m$EfmL~cb692XvVqU?UI%3Tqh?C`hc{BZPw1tQ#{tS zE1FBt0kb*=3F? z4KO=evpbQ)N#96Sz)NL*SYEk&IqCFi2Ec{kYZCK76;_}Obp%EC{`q+p^I443**iX; zymF=x5TUtMRu?$d>lqlpXkkHn` zy$vRf56=+8d_NY-tz5YonrOe#=svQN;9c~9Zn|kzb^^vMkc$wz*RI{UIZaGo>i?8g zXlXE+|(3-?J_O#8fF`}Fi) zmOXMRzw?&&J@0$_2=R#9iGX2WY1!D$1|~_=3ba&2IW~N4dV0xj2raH+@7{U$?tQAP z1kU7ADImWT%v2*IE2^sAq%5A~>Z&sI&#MoGGspS~Eu_y6%11oSvB>=|&l7bcc@^@fOt=$>v`QfAQ)S zAYD79(faV_4$8Y@L-LHo#pqOj{QSu~id%=~cUr2|7aCIL{V|C-CXQ`p0F0;aw|ji= zTA5`xATEhY$B(=5C68^->A7;8A8LgC3;p(0G)<0n81)sFo0$&E3g9LKN2}J}OI~lV znKA{n3xB93B5fsuzN0awJD?uH3?VYzzPpY{1az~+!$Vjj2#K?P-8wXy)Y@o}@ORoj zFSDbERY-TvFRF2NZJ~+)8(6X9v;*~!xESzQxl0?Hvgxxr$&~Z@c<;1+4}FjloWxi1 zku3l;kp{je#x7aCGq#mamOmXcjBVbOk912^vtTIPy~d`d`AZs3Aoc^qU+3l3d&&gm z!8xDy?@OJ1)SkJVI$WK(bRkB@%gi4c-e5HoEizqGZTKITVN%l4d}iVR=EKPD5gM=N z;u2k5GB>QaQ%AnLcj(ofG{GHEfn?A@wZ<~gAp$<4QX8c(s#f%QSYzVji*AN*;Yq?d9g zDcy75(Pe!LX5aYR@F5hY1kHSWT-=ZsJ1pGyx6m-ry?{1EXX2H|Bs**+WG%`+zo!3M$^e zr<0Fud`fZ~I$~c1pKb2h$#P*pA$Wocga6c+NO0&GX(Bmz&=@4=&8JuGAAU7heA=8L z4t@%K`cM|bydnpPYPz828QM1R15!Ii;h`#kY9i-FTXm8Q2F3=7frdf;GSu(~$mFl? z;_}`VH0USd=35gDN%I5<2sq3V5Q((;_X)G?-lIqH&dVB4jmMU!@vb3sQJQ08?q-SlX@Ml%GT@-lh@#gS#8~-DqX8NBS{^J}fJay&^xh3!4 z8zgqPcg5*q522UViB1JXvSW@_uyg zKecGJcDP3USe`mY61Av)5jft%GdMiq;WUY@>eaUMn0}rdTYg6xsh+p*Ng^6b&1%zw?ei@kNp{4 zW;5BzVXSSm_js4}i-ubG{Li%Z+
CmKq)@Gd@pBvdvV1RDZlnGll!Wqd*W&DQ*&h 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 L1yUjTDd_(IgK8Tq$jq zm`Rq9WXpF3aqU~-YnhODEUCe(`v<(wdCqg5bDnd4IX`{UT%GM@q*SFuL_}m9F4(w< zi0r}rO0nI6NbgZc{BGGB=xA>vau8vNED{ls@^i4Uz7jROIL3WZVkRdtS+cZnyL|A> zn=MmO3Gt`C)*35)01z+DPDLbyJU@w#7!$J6Hg5Ju| z`(8kx5+(0Gy+scXyb2jb_|pS`@NkfO){vtybGe+sLz+zkM@OxHizpX=GP4Wj?ik>u zI}Po1FA_Im2=!BRSo0YDXK+sdKJVL|z@}5&iZtQQCa_sXNBU%CZYWQiFhErY0RsXo zg}|gJFq?AGy;;XO^p5@U*>G51i<9weu^p*pg}@Zt4?+L}P;CmsbD=Ll`f5MzHRZ$R%(&-rZ6 z55hwN#S!b>$0G!a%MvYm;N;PUN^Z_qtVM^f+t3WNV3xuDxmj1%mwQc88c3N_$oHwQ zJ--I&GHxSVbwOb@pxY|Et4_LiDz`!oH^*)zN9+qZ!ZJ{CO#f72SuT7m%gEW^*2a*& zsBN*tui$3l^^^P8?5Hv4^e7=Pq0uYaen3AB5m2?$l%=|U>l(>gOn&%J@x5GAKVzfk z^%sy%v!XVF^iD1+7EcDPu!x@nLNABKlWon`=aWEnLVn8nxbtNG9fCf+L2T4#=I_O7 z=}aOlCE>~*3YCu97(4sI+vgU`|I6s?)l}fn zvEoz+aZrfcVQ7G_7~b+S?2D`nrqu;^wIp#?$eF?n)>DU%!H;S*fwYFRsQUUxx@mVc zlvxE0&7%!DSRmHHc>J{DF!j>Z<4t=mSXHlq@#9M>#kBVT9x+)p5e~m^ojn+*?{M7m|8$5 z-|+yazK*(?HtU8*^7lr)l7H6UT?!dy!L^DfKh)UWxW|BM95J?Pg&r0;RBw&E+;2bbgHwM!V>U`iqX#SNm8+D8PZkL`?n&_j#$ z7o$7N=facmlTHfwZ|0OI8%S1n*7WL$Mfy|)#6_d>+(akzpyOTH!jWSF?^tkwQ?oA~ z0=_HE1h<@6GY_LeoI1iwqOVwur>`9Go3}R^gLTJVjq5B^on%+n>@Q`+c%5&HJd+kd zpGazGnn~}mpbd0%y+go)=%gYS`s}#A=a~1}2Xl17m@a;7Zn0W|{&~D&g^Aq(M`+dc zOET>6)*$u+#_L+O0gd$)pL&zHsm27%4;slFcaTk9%0J9D+%RFFw)*1DOG?-JIDf}L zN%%yYcNRw;1d-GQuQ=0w32(W0BQrT}(kMN{*684pVoin4K-`2+(@L$FwJA5$opVHh z^VR+Y3~xI!o+fJ0JbB74BQxr}64b4{{rP8gSL%AwE3cAv)FamyTciDNj8$27%X)W7 z+!od0x+2MQi48Il*+b+>^C?EF0`kTu3o&jpaeJFfOeo!eC2+4?u~JK1-B=Dz0xT<= z*YQdVi}`xt0h4{l@Hkc~WXpWQ!dvf~c>`oamnh%}>sk?QVOAyac2TzY0>h%l#g8(W z1V~3{F_{-1$(dEH_4MgZJOrFQ7M%y`zD&FmHZK3+g{`o3cq5UzL>KIhQXP+VJ1<5pE* zZL&#sp))1M>eIHg7}v4Tk)BjOWXY?E2b-oL02cN$2TnzdW_N5ByMEva*}(A;I2HfTkW>+7S?H?|o9;VN=@N*!)V`li3fl*ae`;t$OTd#scMJBso_CQo6-^qqn%A0)zhNj9 zIgx%ztItz%#=o{ibCLlHT}MuD>d^C)I)3!pcDWemK~>C*Vl-7k@{6Bv)J|QR1t zWhb#suGII9WYcr7W4Z^7d9)$P>(uSY#Aq^*u1Wiiqp2lr5JYl`2GVSElSCU}QN_@vY*$ zF~m~cg#x8=IMoL_gZ^)mVwo%fmU>ki_`R?t46nF+9=+c!F&PdWw6@NRt%5gfi?E$7 zj`Y)^IvS=r8blrO8?NtxAZJ-!hdjmLucjFgC`mKM`!D%+LTi`;k2owBt;BXtg^&7M zx;6uWc0qz_G0`yvf_7a0f!=4mp;3Sg$tX%i!URyq2hj_ypa7t> zYDQ^g^X+OH!NpWF8sY;Ey&QKk`*imC?*wM>$owT5N2o)NI08})7 z+DuRjv{2-n4V1gq%$jqLL+>)em)!b3K=7uNy;*S^Um;-iy(|Ec_^QJzvKVf7*?lDw z!bOG2p4DOWs#k`mGI}izbgwS2@?UhBghnkTK78}0i*ETvD+tdP7>eII7pNX^boFyk z0{aP4B#stsb~+=&M5FGHUyNhZ`M$phvTM3q`u{Rc4@CSw;{CfCSVlRtE56;kfto)y zQQ(dUZsJ*6iih^)U3XeW*m_1_$=9#rND(5M4%aaRoF)NB!rjC~;DR&*qcyGVT%9!S uiDXIy1$#62Mug_6ARILqi?h5zx_%QAsVlW?{BZpjWF2gsZOYCEB>xZnHiUx! literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-entire_edge.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-entire_edge.png new file mode 100644 index 0000000000000000000000000000000000000000..384060402368173afd71586a7d5564768e568432 GIT binary patch literal 6513 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 literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-entire_edge_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-entire_edge_bw.png new file mode 100644 index 0000000000000000000000000000000000000000..5ba40cca5d0bd26c1d2e20d11de50472800b837d GIT binary patch literal 2657 zcmV-n3ZC_eP)J!bfvIPS6d1h&rV>0wG)Je6-H*(SZVt!qNM*)mGp<&@ z+8lo&P?-~+qpvdKvl+23kvZ+rKe{nC^B za}#q^B(G`~FKUi)yr!9=sw>qDkL6X(1mw(Sq7k=6n&Hu~xfru}S#t!0&A-SjdRdxz zNCULdoy?#c^WDrnAQ3jFn=1hNX67QVL1GA-U(8%$yN=uZY<5N?GMY>5-zc*miOnUM z&)L=y*j$jA-?jZxvq+93_q*c~-_e&ieuHG3Om1_DL@u18vdzHIIi9(~<>s}ytOzAro%FQK-( zZk}d|b4&4aRIZzMj4m9AgMH~a>G-+-h@^n|U`^>QyYkK{)C6;PzpR)9`7>zO=SD~> zajVEWcX1q#=J+icmhF!@z1t(rtle+bkDg0tE;W1co2?`ra(bgW&=F?6cr9`HuAt>J z?HX_te&f%2J!!wk!_CsTo_cT5uw0(b>$THQm(k#}q2cEJ&Qk}Bzjif=?yU{8C)sH8 z;a7j>9?iuNDiY_|6w94|{4`PjJ}QjCDlc0&vA#&h9tY-Jn?!YqO2u{<5TQ^jWw$uWc3!<^lv&K5VRKJzw%rE<=5}umUxaRRPh~c%jc!O*-+rks+Q(4mwJ_2(I2R`|J8HWLEdV)jS*o+-&9- z&b+-ko%*M`&|}Ja@BXUi0zPGYX7k)nDVP3=K#$B+K`ZlI(X7S9X%_V6T|a-wEKRfM zx5C{uy{)TUIO7t#-y+PtMh2MGv(;ptn|0s1I*)nxCAz_iqteWe?d*Q5%I|6H(Gj=# zEg{s6v_5wm=2>mI2V^jZDvq%ZSLTPwsV%pz&e^cTJ;Nf*y=q1cX7jzscnu!zVx6l|Uulix_)cP^hT}|7+VKoObdU_fAK6m9hGO*X#ovX76+4p4&!Tx8h&s;dS z+RF84wr+QgS$H;6MPxABYiNn=%e95@`xJE-Y63B>Y)AjIc?@`S4=|67%HYM?uO)=` z-GtQ)dp`&yM`Kfnes5)GHJ}fH=DJxPm7n^bD_V1S zT!H!-7TH4F-5f0=3)0M;&)jG~!_DgE`Bc7?_uYf$ zAe*N!<@J-+EGtjfrsqi(K1810>?;Aj4ugnc{XfKJ=_|CJa}YTbfz<5pdvTWN?m}~* zZg7omgI<6qnMEKi+uhJQ3n8O9loo6bLPm3VuG-k_Fnx%rK&0kyVwF)4Is}=}3|V4f zna`$_Ip!_}JfPIpsbRV1h^3o_-fqQZbM7^8me~j?vj?v+D>Y6`YNk7~OlAow&OObd z+_~5L!q1*R!wlQ5M055p&i-X)FomFSys#O5%1bm8BuHeASw`kQ=8OqmU>0n~o52t^ zvw4VGSih3;-sVaQ;HI}RJK|2id9&Gwy1cSc;x*_>kj*bc7D6lgB*9Z-qy+Q9ELOEi-tMP!D)qc6}*ky6$%C(z0zn;AB? z=XPe1yhUzvFc*okIrEr60g5N5IgpQ3*_?Nbs{qE6)9la5dz!s0GBUB*KQ{iJX73yX zDl)a%MGMXKxY+EPQzIf{%4fFcC@GoVZ1G82@(JdHP*#+M`4qEt&LeTI(3`g@rP^}l zH#hGlJ5y)!X=eRP8_3D0nN?oXi_bKl7ud{ZHnW+{_Y7=iGn?7W=6eP&3M`&+zbaP{JX>fEPC}d@JX=7zQaBgjKVRtDC?=+M4 P00000NkvXXu0mjf?`bzq literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-interior.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-interior.png new file mode 100644 index 0000000000000000000000000000000000000000..1423065e66a2812d47a90dffbc5d67e8a70b7a08 GIT binary patch literal 6808 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 literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-left_vertex.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-left_vertex.png new file mode 100644 index 0000000000000000000000000000000000000000..35f6078cf9f311737a5dd424e233fb46a9e8e993 GIT binary patch literal 6294 zcmbuDRaDdu(DxS=X^<3=4ry3A7E~lxB$n<5VPPq05Tv_H8l$NraNeb7*R1F9aU-T9X=S}JL%fIvPkK%h?{AkfXf(kB!M1Nap0010b11~xt zrN;@zAr2#65QB{i>Rd?@UWP+g7{%r}6_ymh$gVkzEz~vqFw?A@B~s3+ECM6OaE4DR z5bntpX4BQYeu+;q2~iG79)1;-ffGn-5r4SdBZbLY-svhjdfd^%6A$jgD}zRqOXJ13)Yu}`T) zL(I%top8mntO64pl9m!eAb7frPsVv_7lCKxTu|OJw%G!W^MXqZm|jhpcV}nTx5h-f z11|h;@c+s3rzYJx%Jv4@oh(JBR4T01>i(#{U;fsp;bsg8)*&zA!Req&uSiw5S$I?k z%Z#HOnaidzSMg--a2&@Fr)R4&4mS%`RAoLxH3%IcjVuV0e=RyLW6`;ODxScorl+b# zR~H3l1~)x!P=0Fj?ZgB zG2SwXZ=w~g#2Z0|J#pWijIdS9gfb)EiZWH34L%X7W;_qBW2h-WaGEp*Xu3Rc=};fdQr@7cvXuOhXM0JC67*q zyi~YjY61`HR|*0nqQTa`U?|zAGDL95RJ>pQDJ(>ufP?3$evk!T^Xoorb;?QGRvO+t z;yWZWYUy$C%j&7Hg7^n08?8c5;7@)(wz~YjA>N7(ML;C>2Xlg2Tg0Mkf;68$(GwU2 zQ@`fF0SU9`pD#b~fCV+g6AC%{>JD^%AEAOGq9<85pIQ|q={&;|Dlxm$5OB1koOx8z zhHA6SY%__coL!nu>)jOin_~kp0-jgbit4^x<(BrEw`eAxdaxpV2v^hKgFG6O1XX2l z9yF2dW;bp7I8wJQ3y(G1dAL8b+*2*n54O7DzT=QiD&0Y8{+OIXZl5KO$Pd05v@89i zXQ!;=y3Fvi^1G_@Jg<;4XAG)fJC|%W^LI&Q5!;8i#ne1)WXaYE&DvT?Y+u)>Gb{G8 zL`9I+*EYQ|3-ubss(tfJ;3_#>2e68lOeo0SkvzKhEiGs2fp8TXQEB)lme-)q20UYm z%Md2@!|zLUEtz5(XEcv~*#KV)VG7(zxLQHMU{|Uw${2ZdPUG~we446>s_pCGPg~KF zA4UO8`NO_Jw3%lmB^`A3-Wl$S517c^r^<#IqRpFh+Z!{lEa93gh<7u(jdGQ(GKNwk znrqD0Rd3(_tT#=(4D`9XH|Sbn(IxffNw*M_SJqiQow1G}jPuy275(Av1pf6|klJg{ zbdaAo-J&O}m)GR>9ab%|kYPZMOuVms*7IkCUAaOgg6g!I6gBS3LwKCgNc9b%ZZ8?P1@`eCoXbZ5~Cx$0|3er{$5 zrV0{nNoK^@sGY?}X0w_+-|Zn^G^bm?Q@+H9aQf1$;^&f%@x`5i*t#hBHht0wzDUM_ zj$TdQWo(`fCmx>~8Qq5C0YbdP@``-!sz_rNZUDmkV7WMV5mQ2!q&1Y7zoy3n#o_#c zp-gEr8|t$W%*xdNKILS_%xCgv0eS0o_#3&>o}3a8!g{Dz!s`ou=`0ujyU+2T#F|Tmz_FR|F{Lrj|U5%#(ty12b4nAK! z>!jgQA4Mqk4j24f2ofo{Xg}o3cjUL5~RW6D7LsI zC>RA{4sV5FL{ND0SLZNTOK8r@?7MG&*F1k7bF7)TtJ^1J#Wk|^nOpLE>P<(EJMzj!jQBX_8x& zlZ4<38t?yn5*6J2H^Ws{f83RsJw(%VdP0-9xKh0*65P_!(tYep-Ax&*^s&nzqt}CmetaI3LCSC6`z|x-s z_~`dE%U4jn)6_DfxyN8{eeEQ8nALEa-v)ZKi9}$0@qb@wL{f z@-Dt*lh3Z(=& zj48^^;|6Sg3TiF@YK{&Z*}3OPu;>UtQ%R0s_K{U$UfSjzbWb$8W(l-bhG% zfZ2<^Z47c}#ph&HpFg#n$ELfwAJM$ZH@R+E)R>VZe{b*VH;OjKbB?nZ@aucC`wk
+\f{eqnarray*}{ +& \mbox{minimize} & \mathbf{q}^{T}\mathbf{x} + r \\ +& \mbox{subject to} & \mathbf{l} \leq A\mathbf{x} \leq \mathbf{u} +\f} +
+in \f$ n \f$ real variables \f$ \mathbf{x} = (x_0, \ldots, x_{n-1}) \f$ and \f$ m \f$ constraints. + +Here, +
    +
  • \f$ \mathbf{q} \f$ is an \f$ n \f$-dimensional vector (the linear objective function), +
  • \f$ r \f$ is a constant, +
  • \f$ A \f$ is an \f$ m\times n\f$ matrix (the constraint matrix), +
  • \f$ \mathbf{l} \f$ is an \f$ m \f$-dimensional vector of lower constraint bounds, +where \f$ l_i \in \mathbb{R} \cup \{-\infty\} \f$ for all \f$ i \f$, +
  • \f$ \mathbf{u} \f$ is an \f$ m \f$-dimensional vector of upper constraint bounds, +where \f$ u_i \in \mathbb{R} \cup \{+\infty\} \f$ for all \f$ i \f$. +
+*/ +class LinearProgramTraits { + +public: + + /// \name Memory + /// @{ + + /*! + Allocates memory for `n` values in the vector `q`. + */ + void reserve_q(const std::size_t n) { } + + /*! + Allocates memory for `k` non-zero values in the matrix `A`. + */ + void reserve_A(const std::size_t k) { } + + /*! + Allocates memory for `m` values in the vector `l`. + */ + void reserve_l(const std::size_t m) { } + + /*! + Allocates memory for `m` values in the vector `u`. + */ + void reserve_u(const std::size_t m) { } + + /// @} + + /// \name Initialization + /// @{ + + /*! + Sets the entry `qj` of `lp` to `value`. + */ + void set_q(const std::size_t j, const FT value) + { } + + /*! + Sets the entry `r` of `lp` to `value`. + */ + void set_r(const FT value) + { } + + /*! + Sets the entry `Aij` in the row `i` and column `j` of + the constraint matrix `A` of `lp` to `value`. + */ + void set_A(const std::size_t i, const std::size_t j, const FT value) + { } + + /*! + Sets the entry `li` of `lp` to `value`. + */ + void set_l(const std::size_t i, const FT value) + { } + + /*! + Sets the entry `ui` of `lp` to `value`. + */ + void set_u(const std::size_t i, const FT value) + { } + + /// @} + + /// \name Solution + /// @{ + + /*! + \brief Solves the linear program. + + Number of values in `solution` equals to the number `n` of values in the vector `x`. + + \tparam OutIterator + a model of `OutputIterator` that accepts values of type `FT` + + \param solution + an output iterator with the solution + + \returns a status of the computation `success == true` + */ + template + bool solve(OutIterator solution) + { } + + /// @} +}; diff --git a/Solver_interface/doc/Solver_interface/Concepts/QuadraticProgramTraits.h b/Solver_interface/doc/Solver_interface/Concepts/QuadraticProgramTraits.h new file mode 100644 index 00000000000..504bdcb1296 --- /dev/null +++ b/Solver_interface/doc/Solver_interface/Concepts/QuadraticProgramTraits.h @@ -0,0 +1,129 @@ +/*! +\ingroup PkgSolverInterfaceConcepts +\cgalConcept + +A concept that describes the set of methods used to define and solve a +quadratic programming (QP) problem of the general form: +
+\f{eqnarray*}{ +& \mbox{minimize} & \frac{1}{2}\mathbf{x}^{T}P\mathbf{x} + \mathbf{q}^{T}\mathbf{x} + r \\ +& \mbox{subject to} & \mathbf{l} \leq A\mathbf{x} \leq \mathbf{u} +\f} +
+in \f$ n \f$ real variables \f$ \mathbf{x} = (x_0, \ldots, x_{n-1}) \f$ and \f$ m \f$ constraints. + +Here, +
    +
  • \f$ P \f$ is a symmetric positive-semidefinite \f$ n \times n\f$ matrix (the quadratic objective function), +
  • \f$ \mathbf{q} \f$ is an \f$ n \f$-dimensional vector (the linear objective function), +
  • \f$ r \f$ is a constant, +
  • \f$ A \f$ is an \f$ m\times n\f$ matrix (the constraint matrix), +
  • \f$ \mathbf{l} \f$ is an \f$ m \f$-dimensional vector of lower constraint bounds, +where \f$ l_i \in \mathbb{R} \cup \{-\infty\} \f$ for all \f$ i \f$, +
  • \f$ \mathbf{u} \f$ is an \f$ m \f$-dimensional vector of upper constraint bounds, +where \f$ u_i \in \mathbb{R} \cup \{+\infty\} \f$ for all \f$ i \f$. +
+ +\cgalHasModel +`CGAL::OSQP_quadratic_program_traits` +*/ +class QuadraticProgramTraits { + +public: + + /// \name Memory + /// @{ + + /*! + Allocates memory for `k` non-zero values in the matrix `P`. + */ + void reserve_P(const std::size_t k) { } + + /*! + Allocates memory for `n` values in the vector `q`. + */ + void reserve_q(const std::size_t n) { } + + /*! + Allocates memory for `k` non-zero values in the matrix `A`. + */ + void reserve_A(const std::size_t k) { } + + /*! + Allocates memory for `m` values in the vector `l`. + */ + void reserve_l(const std::size_t m) { } + + /*! + Allocates memory for `m` values in the vector `u`. + */ + void reserve_u(const std::size_t m) { } + + /// @} + + /// \name Initialization + /// @{ + + /*! + Sets the entries `Pij` and `Pji` of `qp` to `value`. + + Note that you should define only the upper triangular part of the matrix! + */ + void set_P(const std::size_t i, const std::size_t j, const FT value) + { } + + /*! + Sets the entry `qj` of `qp` to `value`. + */ + void set_q(const std::size_t j, const FT value) + { } + + /*! + Sets the entry `r` of `qp` to `value`. + */ + void set_r(const FT value) + { } + + /*! + Sets the entry `Aij` in the row `i` and column `j` of + the constraint matrix `A` of `qp` to `value`. + */ + void set_A(const std::size_t i, const std::size_t j, const FT value) + { } + + /*! + Sets the entry `li` of `qp` to `value`. + */ + void set_l(const std::size_t i, const FT value) + { } + + /*! + Sets the entry `ui` of `qp` to `value`. + */ + void set_u(const std::size_t i, const FT value) + { } + + /// @} + + /// \name Solution + /// @{ + + /*! + \brief Solves the quadratic program. + + Number of values in `solution` equals to the number `n` of values in the vector `x`. + + \tparam OutIterator + a model of `OutputIterator` that accepts values of type `FT` + + \param solution + an output iterator with the solution + + \returns a status of the computation `success == true` + */ + template + bool solve(OutIterator solution) + { } + + /// @} +}; diff --git a/Solver_interface/doc/Solver_interface/PackageDescription.txt b/Solver_interface/doc/Solver_interface/PackageDescription.txt index dcc72642a69..55f61bed124 100644 --- a/Solver_interface/doc/Solver_interface/PackageDescription.txt +++ b/Solver_interface/doc/Solver_interface/PackageDescription.txt @@ -1,17 +1,35 @@ -/// \defgroup PkgSolverInterfaceRef CGAL and Solvers Reference - -/// \defgroup PkgSolverInterfaceConcepts Concepts -/// \ingroup PkgSolverInterfaceRef -/// - /*! +\defgroup PkgSolverInterfaceRef CGAL and Solvers Reference + +\defgroup PkgSolverInterfaceConcepts Concepts +\ingroup PkgSolverInterfaceRef + +Concepts that describe various solvers. + +\defgroup PkgSolverInterfaceLS Linear Systems +\ingroup PkgSolverInterfaceRef + +Classes to define and solve linear systems. + +\defgroup PkgSolverInterfaceMIP Mixed Integer Programming +\ingroup PkgSolverInterfaceRef + +Classes to define and solve mixed integer programs. + +\defgroup PkgSolverInterfaceNLP Nonlinear Programming +\ingroup PkgSolverInterfaceRef + +Classes to define and solve nonlinear programs. + \addtogroup PkgSolverInterfaceRef -\cgalPkgDescriptionBegin{CGAL and Solvers,PkgSolverInterface} +\cgalPkgDescriptionBegin{CGAL and Solvers, PkgSolverInterface} \cgalPkgPicture{solver.png} \cgalPkgSummaryBegin \cgalPkgAuthors{Simon Giraudot, Pierre Alliez, Frédéric Cazals, Gaël Guennebaud, Bruno Lévy, Marc Pouget, Laurent Saboret, and Liangliang Nan} -\cgalPkgDesc{This package provides concepts and models for solving linear systems with dense or sparse matrices, Mixed Integer Programming (MIP) problems with or without constraints.} -\cgalPkgManuals{Chapter_CGAL_and_Solvers,PkgSolverInterfaceRef} +\cgalPkgDesc{This package provides concepts and models for solving linear systems with +dense or sparse matrices, mixed integer programming problems with or without constraints, +and nonlinear programming problems with or without constraints.} +\cgalPkgManuals{Chapter_CGAL_and_Solvers, PkgSolverInterfaceRef} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin \cgalPkgSince{4.8} @@ -23,16 +41,16 @@ \cgalClassifedRefPages \cgalCRPSection{Concepts} - - `DiagonalizeTraits` - `NormalEquationSparseLinearAlgebraTraits_d` - `SparseLinearAlgebraTraits_d` - `SparseLinearAlgebraWithFactorTraits_d` - `SvdTraits` - `MixedIntegerProgramTraits` +- `LinearProgramTraits` +- `QuadraticProgramTraits` -\cgalCRPSection{Classes} - +\cgalCRPSection{Linear Systems} - `CGAL::Eigen_solver_traits` - `CGAL::Eigen_diagonalize_traits` - `CGAL::Eigen_vector` @@ -40,10 +58,15 @@ - `CGAL::Eigen_sparse_matrix` - `CGAL::Eigen_sparse_symmetric_matrix` - `CGAL::Eigen_svd` -- `CGAL::Mixed_integer_program_traits` -- `CGAL::GLPK_mixed_integer_program_traits` -- `CGAL::SCIP_mixed_integer_program_traits` + +\cgalCRPSection{Mixed Integer Programming} - `CGAL::Variable` - `CGAL::Linear_constraint` - `CGAL::Linear_objective` +- `CGAL::Mixed_integer_program_traits` +- `CGAL::GLPK_mixed_integer_program_traits` +- `CGAL::SCIP_mixed_integer_program_traits` + +\cgalCRPSection{Nonlinear Programming} +- `CGAL::OSQP_quadratic_program_traits` */ diff --git a/Solver_interface/doc/Solver_interface/Solver_interface.txt b/Solver_interface/doc/Solver_interface/Solver_interface.txt index e5fded45ffa..4a42e373609 100644 --- a/Solver_interface/doc/Solver_interface/Solver_interface.txt +++ b/Solver_interface/doc/Solver_interface/Solver_interface.txt @@ -7,9 +7,9 @@ \cgalAutoToc \authors Simon Giraudot, Pierre Alliez, Frédéric Cazals, Gaël Guennebaud, Bruno Lévy, Marc Pouget, Laurent Saboret, and Liangliang Nan -Several \cgal packages have to solve linear systems with dense or -sparse matrices, linear integer programs. This package provides -concepts and models for that purpose. +Several \cgal packages have to solve linear systems with dense or sparse matrices, +linear integer programs, and quadratic programs. This package provides concepts and +models for that purpose. For linear systems, we generally provide models using the \ref thirdpartyEigen library. Wrappers for the Eigen classes @@ -20,29 +20,31 @@ href="https://software.intel.com/en-us/mkl">Intel Math Kernel Library (MKL). For mixed integer programs (either constrained or unconstrained), -we provide models using \ref thirdpartySCIP and \ref thirdpartyGLPK +we provide models using the \ref thirdpartySCIP and \ref thirdpartyGLPK libraries. It is also possible to derive new models from other -high performance libraries, e.g., - CBC , - Gurobi . +high performance libraries such as CBC or +Gurobi. +For linear and quadratic programs, we provide a model using the built-in +\ref PkgQPSolver "CGAL Linear and Quadratic Programming Solver" and a model using +the external \ref thirdpartyOSQP library. It is also possible to derive new models +from other quadratic programming libraries such as +OOQP for example. \section SectionSolverDiagonalize Matrix Diagonalization -The concept `DiagonalizeTraits` defines an interface for the +The concept `DiagonalizeTraits` defines an interface for the diagonalization and computation of eigenvectors and eigenvalues of a symmetric matrix. `T` is the number type and `dim` is the dimension of the matrices and vector (set to 3 by default). We provide the model -`Eigen_diagonalize_traits` that uses the \ref thirdpartyEigen library. +`Eigen_diagonalize_traits` that uses the \ref thirdpartyEigen library. -This is an example of an eigen decomposition of a matrix using this -class: +This is an example of an eigen decomposition of a matrix using this class: \cgalExample{Solver_interface/diagonalize_matrix.cpp} - \section SectionSolverSVD Singular Value Decomposition The concept `SvdTraits` defines an interface for solving in the least @@ -50,13 +52,12 @@ square sense a linear system with a singular value decomposition. The field type is `double`. We provide the model `Eigen_svd` that uses the \ref thirdpartyEigen library. -Here is a simple example that shows how to handle matrices, vectors +Here is a simple example that shows how to handle matrices, vectors, and this solver: \cgalExample{Solver_interface/singular_value_decomposition.cpp} - \section SectionSolverSparse Sparse Solvers We define 3 concepts for sparse linear algebra: @@ -78,24 +79,22 @@ and solver is required: typedef CGAL::Eigen_sparse_matrix::EigenType EigenMatrix; -//iterative general solver +// iterative general solver typedef CGAL::Eigen_solver_traits< Eigen::BiCGSTAB > Iterative_general_solver; -//iterative symmetric solver +// iterative symmetric solver typedef CGAL::Eigen_solver_traits< Eigen::ConjugateGradient > Iterative_symmetric_solver; -//direct symmetric solver +// direct symmetric solver typedef CGAL::Eigen_solver_traits< Eigen::SimplicialCholesky > Direct_symmetric_solver; \endcode -Here is an example that shows how to fill the sparse matrix and call -the solver: +Here is an example that shows how to fill the sparse matrix and call the solver: \cgalExample{Solver_interface/sparse_solvers.cpp} - \section SectionMIPSolver Mixed Integer Program Solvers The concept `MixedIntegerProgramTraits` defines an interface for @@ -107,11 +106,23 @@ The field type is `double`. We provide two models of this concept: `CGAL::SCIP_mixed_integer_program_traits` using \ref thirdpartySCIP. Here is an example that shows how to formulate and solve a simple -mixed integer program using this solver. +mixed integer program using this solver: \cgalExample{Solver_interface/mixed_integer_program.cpp} +\section SectionQPSolver Quadratic Program Solvers + +The concept `QuadraticProgramTraits` defines an interface for quadratic programs (QP) +whereas a similar concept `LinearProgramTraits` gives an interface for linear programs (LP). +The model `CGAL::OSQP_quadratic_program_traits` provides a way to solve convex quadratic programs +with the dense or sparse interface. + +Here is an example that shows how to formulate and solve a simple convex quadratic +program using the latter solver: + +\cgalExample{Solver_interface/osqp_quadratic_program.cpp} + \section SolversHistory Implementation History This package is the result of the increasing needs for linear solvers @@ -125,10 +136,11 @@ PkgSurfaceMeshSkeletonization and \ref PkgSurfaceMeshDeformation extended the existing concepts. Liangliang Nan introduced the concept `MixedIntegerProgramTraits` and two models for solving mixed integer programs when implementing the \ref PkgPolygonalSurfaceReconstruction -package. +package. The concepts and models for solving linear and quadratic programs +were later introduced by Dmitry Anisimov. -Simon Giraudot was responsible for gathering all concepts and classes, and also wrote this user manual -with the help of Andreas Fabri. +Simon Giraudot was responsible for gathering all concepts and classes, +and also wrote this user manual with the help of Andreas Fabri. */ } /* namespace CGAL */ diff --git a/Solver_interface/doc/Solver_interface/dependencies b/Solver_interface/doc/Solver_interface/dependencies index 2dd25947f0a..b00ac4fc10c 100644 --- a/Solver_interface/doc/Solver_interface/dependencies +++ b/Solver_interface/doc/Solver_interface/dependencies @@ -9,3 +9,4 @@ Surface_mesh_deformation Jet_fitting_3 Poisson_surface_reconstruction_3 Polygonal_surface_reconstruction +QP_solver diff --git a/Solver_interface/doc/Solver_interface/examples.txt b/Solver_interface/doc/Solver_interface/examples.txt index 680c5416f6b..64cf531f9e7 100644 --- a/Solver_interface/doc/Solver_interface/examples.txt +++ b/Solver_interface/doc/Solver_interface/examples.txt @@ -3,4 +3,5 @@ \example Solver_interface/singular_value_decomposition.cpp \example Solver_interface/sparse_solvers.cpp \example Solver_interface/mixed_integer_program.cpp +\example Solver_interface/osqp_quadratic_program.cpp */ diff --git a/Solver_interface/examples/Solver_interface/CMakeLists.txt b/Solver_interface/examples/Solver_interface/CMakeLists.txt index 8b1a72ef9b0..b700decef6d 100644 --- a/Solver_interface/examples/Solver_interface/CMakeLists.txt +++ b/Solver_interface/examples/Solver_interface/CMakeLists.txt @@ -20,6 +20,21 @@ if(TARGET CGAL::Eigen3_support) endif() create_single_source_cgal_program("mixed_integer_program.cpp") +create_single_source_cgal_program("osqp_quadratic_program.cpp") + +find_package(OSQP QUIET) +include(CGAL_OSQP_support) + +if(TARGET CGAL::OSQP_support) + + target_link_libraries(osqp_quadratic_program PUBLIC CGAL::OSQP_support) + message("OSQP found and used") + +else() + + message(STATUS "NOTICE: OSQP was not found. Complete OSQP examples won't be available.") + +endif() find_package(SCIP QUIET) include(CGAL_SCIP_support) diff --git a/Solver_interface/examples/Solver_interface/osqp_quadratic_program.cpp b/Solver_interface/examples/Solver_interface/osqp_quadratic_program.cpp new file mode 100644 index 00000000000..a7f72d8b3ee --- /dev/null +++ b/Solver_interface/examples/Solver_interface/osqp_quadratic_program.cpp @@ -0,0 +1,80 @@ +/* +* This example shows how to formulate and solve the following QP problem: +* https://osqp.org/docs/examples/setup-and-solve.html +* +* Minimize +* Objective: +* 1/2(4x1^2 + 2x1x2 + 2x2^2) + (x1 + x2) + 0 or in the matrix form +* 1/2 x^T|4 1|x + |1|^Tx + 0 +* |1 2| |1| +* Subject to +* 1 <= x1 + x2 <= 1 +* 0 <= x1 <= 0.7 +* 0 <= x2 <= 0.7 or in the matrix form +* |1| |1 1| |1.0| +* |0| <= |1 0|x <= |0.7| +* |0| |0 1| |0.7| +* +* Expected results: x1 = 0.3; x2 = 0.7; +*/ + +#include +#include +#include + +#if defined(CGAL_USE_OSQP) +#include +#endif + +using Kernel = CGAL::Simple_cartesian; +using FT = typename Kernel::FT; + +#if defined(CGAL_USE_OSQP) + +int main(void) { + + CGAL::OSQP_quadratic_program_traits osqp; + + osqp.reserve_P(3); + osqp.set_P(0, 0, 4); + osqp.set_P(0, 1, 1); + osqp.set_P(1, 1, 2); + + osqp.reserve_q(2); + osqp.set_q(0, 1); + osqp.set_q(1, 1); + + osqp.set_r(0); + + osqp.reserve_A(4); + osqp.set_A(0, 0, 1); + osqp.set_A(0, 1, 1); + osqp.set_A(1, 0, 1); + osqp.set_A(2, 1, 1); + + osqp.reserve_l(3); + osqp.set_l(0, 1); + osqp.set_l(1, 0); + osqp.set_l(2, 0); + + osqp.reserve_u(3); + osqp.set_u(0, 1); + osqp.set_u(1, 0.7); + osqp.set_u(2, 0.7); + + std::vector x; x.reserve(2); + osqp.solve(std::back_inserter(x)); + + std::cout << "solution (x1 x2): "; + for (const FT value : x) { + std::cout << value << "; "; + } + std::cout << std::endl; +} + +#else +int main(void) { + std::cout << "This example requires the OSQP library." << std::endl; + return EXIT_SUCCESS; +} +#endif // defined(CGAL_USE_OSQP) diff --git a/Solver_interface/include/CGAL/Default_diagonalize_traits.h b/Solver_interface/include/CGAL/Default_diagonalize_traits.h index cbf009379a8..930dd681ce2 100644 --- a/Solver_interface/include/CGAL/Default_diagonalize_traits.h +++ b/Solver_interface/include/CGAL/Default_diagonalize_traits.h @@ -21,7 +21,7 @@ namespace CGAL { -/// \ingroup PkgSolverInterfaceRef +/// \ingroup PkgSolverInterfaceLS /// /// The class `Default_diagonalize_traits` is a wrapper designed to automatically /// use `Eigen_diagonalize_traits` if Eigen is available and otherwise use diff --git a/Solver_interface/include/CGAL/Diagonalize_traits.h b/Solver_interface/include/CGAL/Diagonalize_traits.h index 929752edba0..c4754bed5e9 100644 --- a/Solver_interface/include/CGAL/Diagonalize_traits.h +++ b/Solver_interface/include/CGAL/Diagonalize_traits.h @@ -29,7 +29,7 @@ lead to precision issues, please use CGAL::Eigen_diagonalize_traits") namespace CGAL { -/// \ingroup PkgSolverInterfaceRef +/// \ingroup PkgSolverInterfaceLS /// /// The class `Diagonalize_traits` provides an internal /// implementation for the diagonalization of Variance-Covariance diff --git a/Solver_interface/include/CGAL/Eigen_diagonalize_traits.h b/Solver_interface/include/CGAL/Eigen_diagonalize_traits.h index 38ee3c7c4c7..e0321f57395 100644 --- a/Solver_interface/include/CGAL/Eigen_diagonalize_traits.h +++ b/Solver_interface/include/CGAL/Eigen_diagonalize_traits.h @@ -40,7 +40,7 @@ struct Restricted_FT { typedef float type; }; } -/// \ingroup PkgSolverInterfaceRef +/// \ingroup PkgSolverInterfaceLS /// /// The class `Eigen_diagonalize_traits` provides an interface to the /// diagonalization of covariance matrices of \ref thirdpartyEigen diff --git a/Solver_interface/include/CGAL/Eigen_matrix.h b/Solver_interface/include/CGAL/Eigen_matrix.h index 644ae53babb..4a34a022d0d 100644 --- a/Solver_interface/include/CGAL/Eigen_matrix.h +++ b/Solver_interface/include/CGAL/Eigen_matrix.h @@ -20,7 +20,7 @@ namespace CGAL { /*! -\ingroup PkgSolverInterfaceRef +\ingroup PkgSolverInterfaceLS The class `Eigen_matrix` is a wrapper around `Eigen` matrix type `Eigen::Matrix`. diff --git a/Solver_interface/include/CGAL/Eigen_solver_traits.h b/Solver_interface/include/CGAL/Eigen_solver_traits.h index c7efdfda81d..e2fc4f64c0d 100644 --- a/Solver_interface/include/CGAL/Eigen_solver_traits.h +++ b/Solver_interface/include/CGAL/Eigen_solver_traits.h @@ -63,7 +63,7 @@ struct Get_eigen_matrix< ::Eigen::SparseLU, FT> } //internal /*! -\ingroup PkgSolverInterfaceRef +\ingroup PkgSolverInterfaceLS The class `Eigen_solver_traits` provides an interface to the sparse solvers of \ref thirdpartyEigen "Eigen". \ref thirdpartyEigen "Eigen" version 3.1 (or later) must be available on the system. diff --git a/Solver_interface/include/CGAL/Eigen_sparse_matrix.h b/Solver_interface/include/CGAL/Eigen_sparse_matrix.h index 54d8663d5ca..ff83d2a65fd 100644 --- a/Solver_interface/include/CGAL/Eigen_sparse_matrix.h +++ b/Solver_interface/include/CGAL/Eigen_sparse_matrix.h @@ -18,7 +18,7 @@ namespace CGAL { /*! -\ingroup PkgSolverInterfaceRef +\ingroup PkgSolverInterfaceLS The class `Eigen_sparse_matrix` is a wrapper around `Eigen` matrix type `Eigen::SparseMatrix` @@ -298,7 +298,7 @@ private: /*! -\ingroup PkgSolverInterfaceRef +\ingroup PkgSolverInterfaceRefLS The class `Eigen_sparse_symmetric_matrix` is a wrapper around `Eigen` matrix type `Eigen::SparseMatrix` diff --git a/Solver_interface/include/CGAL/Eigen_svd.h b/Solver_interface/include/CGAL/Eigen_svd.h index 9697401afe8..0841976072a 100644 --- a/Solver_interface/include/CGAL/Eigen_svd.h +++ b/Solver_interface/include/CGAL/Eigen_svd.h @@ -25,7 +25,7 @@ namespace CGAL { /*! -\ingroup PkgSolverInterfaceRef +\ingroup PkgSolverInterfaceLS The class `Eigen_svd` provides an algorithm to solve in the least square sense a linear system with a singular value decomposition using diff --git a/Solver_interface/include/CGAL/Eigen_vector.h b/Solver_interface/include/CGAL/Eigen_vector.h index d113f85e78c..d080777a2f8 100644 --- a/Solver_interface/include/CGAL/Eigen_vector.h +++ b/Solver_interface/include/CGAL/Eigen_vector.h @@ -17,7 +17,7 @@ namespace CGAL { /*! -\ingroup PkgSolverInterfaceRef +\ingroup PkgSolverInterfaceLS The class `Eigen_vector` is a wrapper around `Eigen` vector type, diff --git a/Solver_interface/include/CGAL/GLPK_mixed_integer_program_traits.h b/Solver_interface/include/CGAL/GLPK_mixed_integer_program_traits.h index 8b6a8e28f65..1218679b04a 100644 --- a/Solver_interface/include/CGAL/GLPK_mixed_integer_program_traits.h +++ b/Solver_interface/include/CGAL/GLPK_mixed_integer_program_traits.h @@ -46,7 +46,7 @@ int bound_type(FT lb, FT ub) } // namespace internal -/// \ingroup PkgSolverInterfaceRef +/// \ingroup PkgSolverInterfaceMIP /// /// This class provides an interface for formulating and solving /// constrained or unconstrained mixed integer programs using diff --git a/Solver_interface/include/CGAL/Mixed_integer_program_traits.h b/Solver_interface/include/CGAL/Mixed_integer_program_traits.h index df11eea5377..1b495e95824 100644 --- a/Solver_interface/include/CGAL/Mixed_integer_program_traits.h +++ b/Solver_interface/include/CGAL/Mixed_integer_program_traits.h @@ -96,7 +96,7 @@ namespace CGAL { }; /// \endcond - /// \ingroup PkgSolverInterfaceRef + /// \ingroup PkgSolverInterfaceMIP /// /// The variable of a mixed integer program. /// @@ -195,7 +195,7 @@ namespace CGAL { }; /// \endcond - /// \ingroup PkgSolverInterfaceRef + /// \ingroup PkgSolverInterfaceMIP /// /// The linear constraint of a mixed integer program. /// @@ -227,7 +227,7 @@ namespace CGAL { }; - /// \ingroup PkgSolverInterfaceRef + /// \ingroup PkgSolverInterfaceMIP /// /// The linear objective of a mixed integer program. /// @@ -263,7 +263,7 @@ namespace CGAL { /// \endcond }; - /// \ingroup PkgSolverInterfaceRef + /// \ingroup PkgSolverInterfaceMIP /// /// The class `CGAL::Mixed_integer_program_traits` provides an interface for /// formulating and solving (constrained or unconstrained) mixed integer diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h new file mode 100644 index 00000000000..31dbcb85744 --- /dev/null +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -0,0 +1,281 @@ +// Copyright (c) 2020 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Dmitry Anisimov +// + +#ifndef CGAL_OSQP_QUADRATIC_PROGRAM_TRAITS_H +#define CGAL_OSQP_QUADRATIC_PROGRAM_TRAITS_H + +#if defined(CGAL_USE_OSQP) || defined(DOXYGEN_RUNNING) + +// STL includes. +#include +#include +#include + +// CGAL includes. +#include + +// OSQP includes. +#include + +namespace CGAL { + + /*! + \ingroup PkgSolverInterfaceNLP + + \brief wraps the external OSQP solver. + + This class provides an interface for formulating and solving + constrained or unconstrained quadratic programs using the \ref thirdpartyOSQP "OSQP" + library, which must be available on the system. + + \tparam FT + number type + + \cgalModels `QuadraticProgramTraits` + */ + template + class OSQP_quadratic_program_traits { + // row, col, value + using Triplet = std::tuple; + + public: + /// \cond SKIP_IN_MANUAL + void reserve_P(const std::size_t k) { + P_vec.reserve(k); + } + + void reserve_q(const std::size_t n) { + q_vec.reserve(n); + } + + void reserve_A(const std::size_t k) { + A_vec.reserve(k); + } + + void reserve_l(const std::size_t m) { + l_vec.reserve(m); + } + + void reserve_u(const std::size_t m) { + u_vec.reserve(m); + } + + void set_P(const std::size_t i, const std::size_t j, const FT value) { + P_vec.push_back(std::make_tuple(i, j, value)); + } + + void set_q(const std::size_t, const FT value) { + q_vec.push_back(value); + } + + void set_r(const FT) { + // is not used here + } + + void set_A(const std::size_t i, const std::size_t j, const FT value) { + A_vec.push_back(std::make_tuple(i, j, value)); + } + + void set_l(const std::size_t, const FT value) { + l_vec.push_back(value); + } + + void set_u(const std::size_t, const FT value) { + u_vec.push_back(value); + } + + std::size_t P_size() const { + return P_vec.size(); + } + + std::size_t q_size() const { + return q_vec.size(); + } + + std::size_t A_size() const { + return A_vec.size(); + } + + std::size_t l_size() const { + return l_vec.size(); + } + + std::size_t u_size() const { + return u_vec.size(); + } + + template + bool solve(OutIterator solution) { + + const std::size_t num_cols = std::get<1>(P_vec.back()) + 1; + CGAL_precondition(q_vec.size() == num_cols); + CGAL_precondition(l_vec.size() == u_vec.size()); + + const c_int P_nnz = static_cast(P_vec.size()); + c_float P_x[P_nnz]; + c_int P_i[P_nnz]; + c_int P_p[P_nnz + 1]; + set_matrix_from_triplets("P", P_vec, P_x, P_i, P_p); + // std::cout << "P_nnz: " << P_nnz << std::endl; + + const c_int A_nnz = static_cast(A_vec.size()); + c_float A_x[A_nnz]; + c_int A_i[A_nnz]; + c_int A_p[P_nnz + 1]; + set_matrix_from_triplets("A", A_vec, A_x, A_i, A_p); + // std::cout << "A_nnz: " << A_nnz << std::endl; + + const c_int q_size = static_cast(q_vec.size()); + const c_int l_size = static_cast(l_vec.size()); + const c_int u_size = static_cast(u_vec.size()); + + c_float q_x[q_size]; + c_float l_x[l_size]; + c_float u_x[u_size]; + set_qlu_data(q_x, l_x, u_x); + + // Problem settings. + OSQPSettings *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings)); + + // Structures. + OSQPWorkspace *work; + OSQPData *data; + + // Populate data. + const c_int n = q_size; // number of variables + const c_int m = l_size; // number of constraints + // std::cout << "n: " << n << std::endl; + // std::cout << "m: " << m << std::endl; + + data = (OSQPData *)c_malloc(sizeof(OSQPData)); + data->n = n; + data->m = m; + data->P = csc_matrix(n, n, P_nnz, P_x, P_i, P_p); + data->q = q_x; + data->A = csc_matrix(m, n, A_nnz, A_x, A_i, A_p); + data->l = l_x; + data->u = u_x; + + // Set solver settings. + osqp_set_default_settings(settings); + settings->eps_rel = 1.0e-15; + settings->verbose = false; + + // Set workspace. + osqp_setup(&work, data, settings); + + // Solve problem. + const int exitflag = osqp_solve(work); + const bool success = exitflag == 0 ? true : false; + + // Create solution. + const c_float *x = work->solution->x; + for (c_int i = 0; i < n; ++i) { + const FT value = static_cast(x[i]); + *(++solution) = value; + } + + // Clean workspace. + osqp_cleanup(work); + c_free(data->A); + c_free(data->P); + c_free(data); + c_free(settings); + + return success; + } + /// \endcond + + private: + std::vector P_vec, A_vec; + std::vector q_vec, l_vec, u_vec; + + void set_matrix_from_triplets( + const std::string /* name */, + const std::vector& triplets, + c_float *M_x, c_int *M_i, c_int *M_p) const { + + M_p[0] = 0; + std::size_t count = 0; + const std::size_t num_cols = std::get<1>(triplets.back()); + std::size_t ref_col = 0; + for (ref_col = 0; ref_col <= num_cols; ++ref_col) { + std::size_t num_rows = 0; + for (std::size_t i = 0; i < triplets.size(); ++i) { + const std::size_t row = std::get<0>(triplets[i]); + const std::size_t col = std::get<1>(triplets[i]); + const double value = CGAL::to_double(std::get<2>(triplets[i])); + + if (col == ref_col) { + M_i[count] = row; M_x[count] = value; + ++count; ++num_rows; + } + } + M_p[ref_col + 1] = M_p[ref_col] + num_rows; + } + + // std::cout << name + "_x: "; + // for (std::size_t i = 0; i < count; ++i) + // std::cout << M_x[i] << " "; + // std::cout << std::endl; + + // std::cout << name + "_i: "; + // for (std::size_t i = 0; i < count; ++i) + // std::cout << M_i[i] << " "; + // std::cout << std::endl; + + // std::cout << name + "_p: "; + // for (std::size_t i = 0; i <= ref_col; ++i) + // std::cout << M_p[i] << " "; + // std::cout << std::endl; + } + + void set_qlu_data( + c_float *q_x, c_float *l_x, c_float *u_x) const { + + CGAL_assertion(q_vec.size() > 1); + CGAL_assertion(l_vec.size() == u_vec.size()); + const std::size_t n = q_vec.size(); // number of variables + const std::size_t m = l_vec.size(); // number of constraints + + CGAL_assertion(n > 1); + for (std::size_t i = 0; i < n; ++i) + q_x[i] = CGAL::to_double(q_vec[i]); + + CGAL_assertion(m >= 0); + for (std::size_t i = 0; i < m; ++i) { + l_x[i] = CGAL::to_double(l_vec[i]); + u_x[i] = CGAL::to_double(u_vec[i]); + } + + // std::cout << "q_x: "; + // for (std::size_t i = 0; i < n; ++i) + // std::cout << q_x[i] << " "; + // std::cout << std::endl; + + // std::cout << "l_x: "; + // for (std::size_t i = 0; i < m; ++i) + // std::cout << l_x[i] << " "; + // std::cout << std::endl; + + // std::cout << "u_x: "; + // for (std::size_t i = 0; i < m; ++i) + // std::cout << u_x[i] << " "; + // std::cout << std::endl; + } + }; + +} // namespace CGAL + +#endif // CGAL_USE_OSQP or DOXYGEN_RUNNING + +#endif // CGAL_OSQP_QUADRATIC_PROGRAM_TRAITS_H diff --git a/Solver_interface/include/CGAL/SCIP_mixed_integer_program_traits.h b/Solver_interface/include/CGAL/SCIP_mixed_integer_program_traits.h index ecc9320e103..2b1d7927447 100644 --- a/Solver_interface/include/CGAL/SCIP_mixed_integer_program_traits.h +++ b/Solver_interface/include/CGAL/SCIP_mixed_integer_program_traits.h @@ -25,7 +25,7 @@ namespace CGAL { -/// \ingroup PkgSolverInterfaceRef +/// \ingroup PkgSolverInterfaceMIP /// /// This class provides an interface for formulating and solving /// constrained or unconstrained mixed integer programs using diff --git a/Solver_interface/package_info/Solver_interface/description.txt b/Solver_interface/package_info/Solver_interface/description.txt index 90a6f6a11f7..f31a09e2cf3 100644 --- a/Solver_interface/package_info/Solver_interface/description.txt +++ b/Solver_interface/package_info/Solver_interface/description.txt @@ -1,2 +1,2 @@ -Solver_interface: contains classes to interface third party linear algebra solvers (such as Eigen for example), -mixed integer program solvers (such as SCIP for example) to CGAL. +This package contains classes to interface third party linear algebra solvers (such as Eigen for example), +mixed integer program solvers (such as SCIP for example), and nonlinear program solvers (such as OSQP for example). From 83347121fc943b1295b7add78c3915b8b0ff2975 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 8 Jun 2021 16:24:12 +0200 Subject: [PATCH 223/349] fixed num_cols issue + added clear function for multiple use --- .../CGAL/OSQP_quadratic_program_traits.h | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 31dbcb85744..e67aa160db3 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -49,6 +49,9 @@ namespace CGAL { public: /// \cond SKIP_IN_MANUAL + OSQP_quadratic_program_traits() : + m_largest_col(0) { } + void reserve_P(const std::size_t k) { P_vec.reserve(k); } @@ -70,6 +73,7 @@ namespace CGAL { } void set_P(const std::size_t i, const std::size_t j, const FT value) { + m_largest_col = (CGAL::max)(j, m_largest_col); P_vec.push_back(std::make_tuple(i, j, value)); } @@ -116,8 +120,7 @@ namespace CGAL { template bool solve(OutIterator solution) { - const std::size_t num_cols = std::get<1>(P_vec.back()) + 1; - CGAL_precondition(q_vec.size() == num_cols); + CGAL_precondition(q_vec.size() == m_largest_col + 1); CGAL_precondition(l_vec.size() == u_vec.size()); const c_int P_nnz = static_cast(P_vec.size()); @@ -193,9 +196,16 @@ namespace CGAL { return success; } + + void clear() { + m_largest_col = 0; + P_vec.clear(); A_vec.clear(); + q_vec.clear(); l_vec.clear(); u_vec.clear(); + } /// \endcond private: + std::size_t m_largest_col; std::vector P_vec, A_vec; std::vector q_vec, l_vec, u_vec; @@ -206,9 +216,8 @@ namespace CGAL { M_p[0] = 0; std::size_t count = 0; - const std::size_t num_cols = std::get<1>(triplets.back()); std::size_t ref_col = 0; - for (ref_col = 0; ref_col <= num_cols; ++ref_col) { + for (ref_col = 0; ref_col <= m_largest_col; ++ref_col) { std::size_t num_rows = 0; for (std::size_t i = 0; i < triplets.size(); ++i) { const std::size_t row = std::get<0>(triplets[i]); @@ -248,8 +257,9 @@ namespace CGAL { const std::size_t m = l_vec.size(); // number of constraints CGAL_assertion(n > 1); - for (std::size_t i = 0; i < n; ++i) + for (std::size_t i = 0; i < n; ++i) { q_x[i] = CGAL::to_double(q_vec[i]); + } CGAL_assertion(m >= 0); for (std::size_t i = 0; i < m; ++i) { From f99d0c348091b60dc7227d040ce1b718148bc685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 10 Jun 2021 15:55:45 +0200 Subject: [PATCH 224/349] Improvements and fixes for OSQP_quadratic_program_traits - Fix wrong array sizes - Fix to_CSC matrix conversion - Rework the reserve() / insertion / size mechanisms - Enable passing some options via solve() --- .../CGAL/OSQP_quadratic_program_traits.h | 510 ++++++++++-------- 1 file changed, 279 insertions(+), 231 deletions(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 31dbcb85744..51e68a4f583 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 GeometryFactory SARL (France). +// Copyright (c) 2020-2021 GeometryFactory SARL (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org) @@ -8,6 +8,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Dmitry Anisimov +// Mael Rouxel-Labbé // #ifndef CGAL_OSQP_QUADRATIC_PROGRAM_TRAITS_H @@ -28,251 +29,298 @@ namespace CGAL { - /*! - \ingroup PkgSolverInterfaceNLP +/*! + \ingroup PkgSolverInterfaceNLP - \brief wraps the external OSQP solver. + \brief wraps the external OSQP solver. - This class provides an interface for formulating and solving - constrained or unconstrained quadratic programs using the \ref thirdpartyOSQP "OSQP" - library, which must be available on the system. + This class provides an interface for formulating and solving + constrained or unconstrained quadratic programs using the \ref thirdpartyOSQP "OSQP" + library, which must be available on the system. - \tparam FT - number type + \tparam FT + number type - \cgalModels `QuadraticProgramTraits` - */ - template - class OSQP_quadratic_program_traits { - // row, col, value - using Triplet = std::tuple; + \cgalModels `QuadraticProgramTraits` +*/ +template +class OSQP_quadratic_program_traits +{ + using Triplet = std::tuple; // row, col, value - public: - /// \cond SKIP_IN_MANUAL - void reserve_P(const std::size_t k) { - P_vec.reserve(k); +private: + std::size_t n; // number of variables + std::size_t m; // number of constraints + + std::vector P_vec, A_vec; + std::vector q_vec, l_vec, u_vec; + +public: + /// Default constructor + OSQP_quadratic_program_traits() : n(0), m(0) { } + + /// Constructor + /// \param n the number of variables + OSQP_quadratic_program_traits(const std::size_t n) + : n(n), m(0) + { + // 6*n, just guessing that this is some kind of sparse problem on a nice 2D mesh + P_vec.reserve(6 * n); + q_vec.reserve(n); + } + + /// Constructor + /// \param n the number of variables + /// \param m the number of constraints + OSQP_quadratic_program_traits(const std::size_t n, const std::size_t m) + : n(n), m(m) + { + P_vec.reserve(6 * n); + q_vec.reserve(n); + + A_vec.reserve(m); + l_vec.reserve(m); + u_vec.reserve(m); + } + +public: + /// \cond SKIP_IN_MANUAL + + void set_P(const std::size_t i, const std::size_t j, const FT value) + { + if(j < i) + return; + if(j >= n) // no need to test i since j >= i + n = j+1; + + P_vec.emplace_back(i, j, value); + } + + void set_q(const std::size_t i, const FT value) + { + if(i >= n) + n = i+1; + if(i >= q_vec.size()) + q_vec.resize(n); + + q_vec[i] = value; + } + + void set_r(const FT) { + // is not used here + } + + void set_A(const std::size_t i, const std::size_t j, const FT value) + { + if(i >= m) + m = i+1; + if(j >= n) + n = j+1; + + A_vec.emplace_back(i, j, value); + } + + void set_l(const std::size_t i, const FT value) + { + if(i >= m) + m = i+1; + if(i >= l_vec.size()) + l_vec.resize(m); + + l_vec[i] = value; + } + + void set_u(const std::size_t i, const FT value) + { + if(i >= m) + m = i+1; + if(i >= u_vec.size()) + u_vec.resize(m); + + u_vec[i] = value; + } + + template + bool solve(OutIterator solution, + const FT eps_abs = 1e-10, + const FT eps_rel = 1e-15, + const bool verbose = false) + { + std::cout << "num variables = " << n << std::endl; + std::cout << "num constraints = " << m << std::endl; + + CGAL_precondition(n >= 1 && m >= 0); + + CGAL_precondition(q_vec.size() == n); + CGAL_precondition(l_vec.size() == m && l_vec.size() == m); + + const c_int P_nnz = static_cast(P_vec.size()); + c_float P_x[P_nnz]; + c_int P_i[P_nnz]; + c_int P_p[n + 1]; + set_matrix_from_triplets("P", P_vec, P_x, P_i, P_p); + std::cout << "P_nnz: " << P_nnz << std::endl; + + const c_int A_nnz = static_cast(A_vec.size()); + c_float A_x[A_nnz]; + c_int A_i[A_nnz]; + c_int A_p[n + 1]; + set_matrix_from_triplets("A", A_vec, A_x, A_i, A_p); + std::cout << "A_nnz: " << A_nnz << std::endl; + + const c_int q_size = static_cast(q_vec.size()); + const c_int l_size = static_cast(l_vec.size()); + const c_int u_size = static_cast(u_vec.size()); + + c_float q_x[q_size]; + c_float l_x[l_size]; + c_float u_x[u_size]; + set_qlu_data(q_x, l_x, u_x); + + // Problem settings. + OSQPSettings *settings = (OSQPSettings *) malloc(sizeof(OSQPSettings)); + CGAL_assertion(settings); + + // Structures. + OSQPWorkspace *work; + OSQPData *data = (OSQPData *) malloc(sizeof(OSQPData)); + CGAL_assertion(data); + + // Populate data. + data->n = static_cast(n); + data->m = static_cast(m); + data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p); + CGAL_assertion(data->P); + + data->q = q_x; + data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p); + CGAL_assertion(data->A); + + data->l = l_x; + data->u = u_x; + + // Set solver settings. + osqp_set_default_settings(settings); + settings->eps_abs = eps_abs; + settings->eps_rel = eps_rel; + settings->verbose = verbose; + + // Set workspace. + osqp_setup(&work, data, settings); + + // Solve problem. + const int exitflag = osqp_solve(work); + const bool success = (exitflag == 0); + + // Create solution. + const c_float *x = work->solution->x; + for(c_int i=0; iA); + c_free(data->P); + c_free(data); + c_free(settings); + + return success; + } + /// \endcond + +public: + // Based on the code in scipy, function coo_tocsr() + void set_matrix_from_triplets(const std::string name, + const std::vector& triplets, + c_float *M_x, + c_int *M_i, + c_int *M_p) const + { + const std::size_t nnz = triplets.size(); + + // Compute the number of non-zero entries in each column of the sparse matrix A + std::fill(M_p, M_p + n, 0); + for(std::size_t k=0; k(triplets[k])]++; + + // Fill M_p + c_int cumsum = 0; + for(std::size_t j=0; j(std::get<1>(triplets[k])); + const c_int dest = M_p[col]; + + M_i[dest] = static_cast(std::get<0>(triplets[k])); + M_x[dest] = c_float(CGAL::to_double(std::get<2>(triplets[k]))); + + M_p[col]++; } - void reserve_A(const std::size_t k) { - A_vec.reserve(k); + c_int last = 0; + for(std::size_t j=0; j<=n; ++j) + { + const c_int tmp = M_p[j]; + M_p[j] = last; + last = tmp; } - void reserve_l(const std::size_t m) { - l_vec.reserve(m); +// std::cout << name + "_x: "; +// for(std::size_t i=0; i - bool solve(OutIterator solution) { - - const std::size_t num_cols = std::get<1>(P_vec.back()) + 1; - CGAL_precondition(q_vec.size() == num_cols); - CGAL_precondition(l_vec.size() == u_vec.size()); - - const c_int P_nnz = static_cast(P_vec.size()); - c_float P_x[P_nnz]; - c_int P_i[P_nnz]; - c_int P_p[P_nnz + 1]; - set_matrix_from_triplets("P", P_vec, P_x, P_i, P_p); - // std::cout << "P_nnz: " << P_nnz << std::endl; - - const c_int A_nnz = static_cast(A_vec.size()); - c_float A_x[A_nnz]; - c_int A_i[A_nnz]; - c_int A_p[P_nnz + 1]; - set_matrix_from_triplets("A", A_vec, A_x, A_i, A_p); - // std::cout << "A_nnz: " << A_nnz << std::endl; - - const c_int q_size = static_cast(q_vec.size()); - const c_int l_size = static_cast(l_vec.size()); - const c_int u_size = static_cast(u_vec.size()); - - c_float q_x[q_size]; - c_float l_x[l_size]; - c_float u_x[u_size]; - set_qlu_data(q_x, l_x, u_x); - - // Problem settings. - OSQPSettings *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings)); - - // Structures. - OSQPWorkspace *work; - OSQPData *data; - - // Populate data. - const c_int n = q_size; // number of variables - const c_int m = l_size; // number of constraints - // std::cout << "n: " << n << std::endl; - // std::cout << "m: " << m << std::endl; - - data = (OSQPData *)c_malloc(sizeof(OSQPData)); - data->n = n; - data->m = m; - data->P = csc_matrix(n, n, P_nnz, P_x, P_i, P_p); - data->q = q_x; - data->A = csc_matrix(m, n, A_nnz, A_x, A_i, A_p); - data->l = l_x; - data->u = u_x; - - // Set solver settings. - osqp_set_default_settings(settings); - settings->eps_rel = 1.0e-15; - settings->verbose = false; - - // Set workspace. - osqp_setup(&work, data, settings); - - // Solve problem. - const int exitflag = osqp_solve(work); - const bool success = exitflag == 0 ? true : false; - - // Create solution. - const c_float *x = work->solution->x; - for (c_int i = 0; i < n; ++i) { - const FT value = static_cast(x[i]); - *(++solution) = value; - } - - // Clean workspace. - osqp_cleanup(work); - c_free(data->A); - c_free(data->P); - c_free(data); - c_free(settings); - - return success; - } - /// \endcond - - private: - std::vector P_vec, A_vec; - std::vector q_vec, l_vec, u_vec; - - void set_matrix_from_triplets( - const std::string /* name */, - const std::vector& triplets, - c_float *M_x, c_int *M_i, c_int *M_p) const { - - M_p[0] = 0; - std::size_t count = 0; - const std::size_t num_cols = std::get<1>(triplets.back()); - std::size_t ref_col = 0; - for (ref_col = 0; ref_col <= num_cols; ++ref_col) { - std::size_t num_rows = 0; - for (std::size_t i = 0; i < triplets.size(); ++i) { - const std::size_t row = std::get<0>(triplets[i]); - const std::size_t col = std::get<1>(triplets[i]); - const double value = CGAL::to_double(std::get<2>(triplets[i])); - - if (col == ref_col) { - M_i[count] = row; M_x[count] = value; - ++count; ++num_rows; - } - } - M_p[ref_col + 1] = M_p[ref_col] + num_rows; - } - - // std::cout << name + "_x: "; - // for (std::size_t i = 0; i < count; ++i) - // std::cout << M_x[i] << " "; - // std::cout << std::endl; - - // std::cout << name + "_i: "; - // for (std::size_t i = 0; i < count; ++i) - // std::cout << M_i[i] << " "; - // std::cout << std::endl; - - // std::cout << name + "_p: "; - // for (std::size_t i = 0; i <= ref_col; ++i) - // std::cout << M_p[i] << " "; - // std::cout << std::endl; - } - - void set_qlu_data( - c_float *q_x, c_float *l_x, c_float *u_x) const { - - CGAL_assertion(q_vec.size() > 1); - CGAL_assertion(l_vec.size() == u_vec.size()); - const std::size_t n = q_vec.size(); // number of variables - const std::size_t m = l_vec.size(); // number of constraints - - CGAL_assertion(n > 1); - for (std::size_t i = 0; i < n; ++i) - q_x[i] = CGAL::to_double(q_vec[i]); - - CGAL_assertion(m >= 0); - for (std::size_t i = 0; i < m; ++i) { - l_x[i] = CGAL::to_double(l_vec[i]); - u_x[i] = CGAL::to_double(u_vec[i]); - } - - // std::cout << "q_x: "; - // for (std::size_t i = 0; i < n; ++i) - // std::cout << q_x[i] << " "; - // std::cout << std::endl; - - // std::cout << "l_x: "; - // for (std::size_t i = 0; i < m; ++i) - // std::cout << l_x[i] << " "; - // std::cout << std::endl; - - // std::cout << "u_x: "; - // for (std::size_t i = 0; i < m; ++i) - // std::cout << u_x[i] << " "; - // std::cout << std::endl; - } - }; +// std::cout << "u_x: "; +// for(std::size_t i=0; i Date: Thu, 10 Jun 2021 16:14:43 +0200 Subject: [PATCH 225/349] Add clear() and resize() to OSQP traits --- .../CGAL/OSQP_quadratic_program_traits.h | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 51e68a4f583..4249e3e39e7 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -84,8 +84,29 @@ public: } public: - /// \cond SKIP_IN_MANUAL + /// Reset the problem, removing all existing entries and setting sizes to `0`. + void clear() + { + n = m = 0; + P_vec.clear(); + A_vec.clear(); + q_vec.clear(); + l_vec.clear(); + u_vec.clear(); + } + /// Change the number of variables and the number of constraints of the problem. + /// + /// \warning Calling this function also clears all previous entries. + void resize(const int new_n, + const int new_m = 0) + { + clear(); + n = new_n; + m = new_m; + } + + /// \cond SKIP_IN_MANUAL void set_P(const std::size_t i, const std::size_t j, const FT value) { if(j < i) From 04ce897efee1ffc374712dd5782c56106e110755 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 10 Jun 2021 17:02:08 +0200 Subject: [PATCH 226/349] added try catch in osqp --- .../CGAL/OSQP_quadratic_program_traits.h | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 4249e3e39e7..55234f88393 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -20,6 +20,7 @@ #include #include #include +#include // CGAL includes. #include @@ -230,7 +231,16 @@ public: osqp_setup(&work, data, settings); // Solve problem. - const int exitflag = osqp_solve(work); + int exitflag = -1; + try + { + exitflag = osqp_solve(work); + } + catch (std::exception& e) + { + std::cerr << "ERROR: OSQP solver has thrown an exception!" << std::endl; + std::cerr << e.what() << std::endl; + } const bool success = (exitflag == 0); // Create solution. @@ -265,7 +275,9 @@ public: // Compute the number of non-zero entries in each column of the sparse matrix A std::fill(M_p, M_p + n, 0); for(std::size_t k=0; k(triplets[k])]++; + } // Fill M_p c_int cumsum = 0; @@ -297,20 +309,20 @@ public: last = tmp; } -// std::cout << name + "_x: "; -// for(std::size_t i=0; i Date: Thu, 10 Jun 2021 17:06:29 +0200 Subject: [PATCH 227/349] fixed osqp example --- .../examples/Solver_interface/osqp_quadratic_program.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Solver_interface/examples/Solver_interface/osqp_quadratic_program.cpp b/Solver_interface/examples/Solver_interface/osqp_quadratic_program.cpp index a7f72d8b3ee..3bc9136db58 100644 --- a/Solver_interface/examples/Solver_interface/osqp_quadratic_program.cpp +++ b/Solver_interface/examples/Solver_interface/osqp_quadratic_program.cpp @@ -33,31 +33,28 @@ using FT = typename Kernel::FT; int main(void) { - CGAL::OSQP_quadratic_program_traits osqp; + const std::size_t n = 2; // number of variables + const std::size_t m = 3; // number of constraints + CGAL::OSQP_quadratic_program_traits osqp(n, m); - osqp.reserve_P(3); osqp.set_P(0, 0, 4); osqp.set_P(0, 1, 1); osqp.set_P(1, 1, 2); - osqp.reserve_q(2); osqp.set_q(0, 1); osqp.set_q(1, 1); osqp.set_r(0); - osqp.reserve_A(4); osqp.set_A(0, 0, 1); osqp.set_A(0, 1, 1); osqp.set_A(1, 0, 1); osqp.set_A(2, 1, 1); - osqp.reserve_l(3); osqp.set_l(0, 1); osqp.set_l(1, 0); osqp.set_l(2, 0); - osqp.reserve_u(3); osqp.set_u(0, 1); osqp.set_u(1, 0.7); osqp.set_u(2, 0.7); From 25a08a264ee7b263671fbd26aee1e4587b923e72 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 10 Jun 2021 17:07:53 +0200 Subject: [PATCH 228/349] fixed warnings --- Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 55234f88393..3f921becc30 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -245,7 +245,7 @@ public: // Create solution. const c_float *x = work->solution->x; - for(c_int i=0; i(n); ++i) { const FT value{x[i]}; *(++solution) = value; @@ -264,7 +264,7 @@ public: public: // Based on the code in scipy, function coo_tocsr() - void set_matrix_from_triplets(const std::string name, + void set_matrix_from_triplets(const std::string /* name */, const std::vector& triplets, c_float *M_x, c_int *M_i, From 55bcd9861d3685412c1ff9defd976b158224c80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 10 Jun 2021 18:13:26 +0200 Subject: [PATCH 229/349] Tiny size_type change --- Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 3f921becc30..065c4bf8c5a 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -245,7 +245,7 @@ public: // Create solution. const c_float *x = work->solution->x; - for(c_int i=0; i(n); ++i) + for(std::size_t i=0; i Date: Fri, 11 Jun 2021 11:30:51 +0200 Subject: [PATCH 230/349] fixed resize method --- .../include/CGAL/OSQP_quadratic_program_traits.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 3f921becc30..1ecc6d9557a 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -105,6 +105,14 @@ public: clear(); n = new_n; m = new_m; + P_vec.reserve(6 * n); + q_vec.reserve(n); + if(m > 0) + { + A_vec.reserve(m); + l_vec.reserve(m); + u_vec.reserve(m); + } } /// \cond SKIP_IN_MANUAL From 8bd23baef614d64bdff2f5aeab3488a31bbab294 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 11 Jun 2021 11:34:58 +0200 Subject: [PATCH 231/349] fixed verbose --- .../include/CGAL/OSQP_quadratic_program_traits.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 1ecc6d9557a..b8e7ccc75f1 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -176,9 +176,11 @@ public: const FT eps_rel = 1e-15, const bool verbose = false) { - std::cout << "num variables = " << n << std::endl; - std::cout << "num constraints = " << m << std::endl; - + if(verbose) + { + std::cout << "num variables = " << n << std::endl; + std::cout << "num constraints = " << m << std::endl; + } CGAL_precondition(n >= 1 && m >= 0); CGAL_precondition(q_vec.size() == n); @@ -189,14 +191,14 @@ public: c_int P_i[P_nnz]; c_int P_p[n + 1]; set_matrix_from_triplets("P", P_vec, P_x, P_i, P_p); - std::cout << "P_nnz: " << P_nnz << std::endl; + if(verbose) std::cout << "P_nnz: " << P_nnz << std::endl; const c_int A_nnz = static_cast(A_vec.size()); c_float A_x[A_nnz]; c_int A_i[A_nnz]; c_int A_p[n + 1]; set_matrix_from_triplets("A", A_vec, A_x, A_i, A_p); - std::cout << "A_nnz: " << A_nnz << std::endl; + if(verbose) std::cout << "A_nnz: " << A_nnz << std::endl; const c_int q_size = static_cast(q_vec.size()); const c_int l_size = static_cast(l_vec.size()); @@ -244,7 +246,7 @@ public: { exitflag = osqp_solve(work); } - catch (std::exception& e) + catch(std::exception& e) { std::cerr << "ERROR: OSQP solver has thrown an exception!" << std::endl; std::cerr << e.what() << std::endl; From 0a0c92d27245f9c4fbd92d19971985a0a7e60597 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 11 Jun 2021 12:20:30 +0200 Subject: [PATCH 232/349] changed FT to double because it fails with exact types --- Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 4becf9c5c17..cfe2915d077 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -172,8 +172,8 @@ public: template bool solve(OutIterator solution, - const FT eps_abs = 1e-10, - const FT eps_rel = 1e-15, + const double eps_abs = 1e-10, + const double eps_rel = 1e-15, const bool verbose = false) { if(verbose) From ff0734d8cc6410c1709d6f0b61fb72dc005bad30 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 11 Jun 2021 13:36:55 +0200 Subject: [PATCH 233/349] fixed private section --- Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index cfe2915d077..b82173b59f9 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -272,7 +272,7 @@ public: } /// \endcond -public: +private: // Based on the code in scipy, function coo_tocsr() void set_matrix_from_triplets(const std::string /* name */, const std::vector& triplets, From f865eaaf351944252b5eba80157b38b00d9995ad Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 11 Jun 2021 13:58:20 +0200 Subject: [PATCH 234/349] updated docs and fixed concepts --- .../Concepts/LinearProgramTraits.h | 43 ++++------------ .../Concepts/QuadraticProgramTraits.h | 51 +++++-------------- .../doc/Solver_interface/Solver_interface.txt | 2 +- .../CGAL/OSQP_quadratic_program_traits.h | 6 +-- 4 files changed, 27 insertions(+), 75 deletions(-) diff --git a/Solver_interface/doc/Solver_interface/Concepts/LinearProgramTraits.h b/Solver_interface/doc/Solver_interface/Concepts/LinearProgramTraits.h index 9d44b4a667f..49bc506ab92 100644 --- a/Solver_interface/doc/Solver_interface/Concepts/LinearProgramTraits.h +++ b/Solver_interface/doc/Solver_interface/Concepts/LinearProgramTraits.h @@ -3,7 +3,7 @@ \cgalConcept A concept that describes the set of methods used to define and solve a -linear programming (LP) problem of the general form: +linear programming (`lp`) problem of the general form:
\f{eqnarray*}{ & \mbox{minimize} & \mathbf{q}^{T}\mathbf{x} + r \\ @@ -31,24 +31,9 @@ public: /// @{ /*! - Allocates memory for `n` values in the vector `q`. + Allocates memory for `n` variables and `m` constraints in `lp`. */ - void reserve_q(const std::size_t n) { } - - /*! - Allocates memory for `k` non-zero values in the matrix `A`. - */ - void reserve_A(const std::size_t k) { } - - /*! - Allocates memory for `m` values in the vector `l`. - */ - void reserve_l(const std::size_t m) { } - - /*! - Allocates memory for `m` values in the vector `u`. - */ - void reserve_u(const std::size_t m) { } + void resize(const std::size_t n, const std::size_t m) { } /// @} @@ -56,35 +41,30 @@ public: /// @{ /*! - Sets the entry `qj` of `lp` to `value`. + Sets the entry `qi` of `lp` to `value`. */ - void set_q(const std::size_t j, const FT value) - { } + void set_q(const std::size_t i, const FT value) { } /*! Sets the entry `r` of `lp` to `value`. */ - void set_r(const FT value) - { } + void set_r(const FT value) { } /*! Sets the entry `Aij` in the row `i` and column `j` of the constraint matrix `A` of `lp` to `value`. */ - void set_A(const std::size_t i, const std::size_t j, const FT value) - { } + void set_A(const std::size_t i, const std::size_t j, const FT value) { } /*! Sets the entry `li` of `lp` to `value`. */ - void set_l(const std::size_t i, const FT value) - { } + void set_l(const std::size_t i, const FT value) { } /*! Sets the entry `ui` of `lp` to `value`. */ - void set_u(const std::size_t i, const FT value) - { } + void set_u(const std::size_t i, const FT value) { } /// @} @@ -97,7 +77,7 @@ public: Number of values in `solution` equals to the number `n` of values in the vector `x`. \tparam OutIterator - a model of `OutputIterator` that accepts values of type `FT` + a model of `OutputIterator` that accepts values of type `FieldNumberType` \param solution an output iterator with the solution @@ -105,8 +85,7 @@ public: \returns a status of the computation `success == true` */ template - bool solve(OutIterator solution) - { } + bool solve(OutIterator solution) { } /// @} }; diff --git a/Solver_interface/doc/Solver_interface/Concepts/QuadraticProgramTraits.h b/Solver_interface/doc/Solver_interface/Concepts/QuadraticProgramTraits.h index 504bdcb1296..0d1cec8fe95 100644 --- a/Solver_interface/doc/Solver_interface/Concepts/QuadraticProgramTraits.h +++ b/Solver_interface/doc/Solver_interface/Concepts/QuadraticProgramTraits.h @@ -3,7 +3,7 @@ \cgalConcept A concept that describes the set of methods used to define and solve a -quadratic programming (QP) problem of the general form: +quadratic programming (`qp`) problem of the general form:
\f{eqnarray*}{ & \mbox{minimize} & \frac{1}{2}\mathbf{x}^{T}P\mathbf{x} + \mathbf{q}^{T}\mathbf{x} + r \\ @@ -35,29 +35,9 @@ public: /// @{ /*! - Allocates memory for `k` non-zero values in the matrix `P`. + Allocates memory for `n` variables and `m` constraints in `qp`. */ - void reserve_P(const std::size_t k) { } - - /*! - Allocates memory for `n` values in the vector `q`. - */ - void reserve_q(const std::size_t n) { } - - /*! - Allocates memory for `k` non-zero values in the matrix `A`. - */ - void reserve_A(const std::size_t k) { } - - /*! - Allocates memory for `m` values in the vector `l`. - */ - void reserve_l(const std::size_t m) { } - - /*! - Allocates memory for `m` values in the vector `u`. - */ - void reserve_u(const std::size_t m) { } + void resize(const std::size_t n, const std::size_t m) { } /// @} @@ -69,39 +49,33 @@ public: Note that you should define only the upper triangular part of the matrix! */ - void set_P(const std::size_t i, const std::size_t j, const FT value) - { } + void set_P(const std::size_t i, const std::size_t j, const FT value) { } /*! - Sets the entry `qj` of `qp` to `value`. + Sets the entry `qi` of `qp` to `value`. */ - void set_q(const std::size_t j, const FT value) - { } + void set_q(const std::size_t i, const FT value) { } /*! Sets the entry `r` of `qp` to `value`. */ - void set_r(const FT value) - { } + void set_r(const FT value) { } /*! Sets the entry `Aij` in the row `i` and column `j` of the constraint matrix `A` of `qp` to `value`. */ - void set_A(const std::size_t i, const std::size_t j, const FT value) - { } + void set_A(const std::size_t i, const std::size_t j, const FT value) { } /*! Sets the entry `li` of `qp` to `value`. */ - void set_l(const std::size_t i, const FT value) - { } + void set_l(const std::size_t i, const FT value) { } /*! Sets the entry `ui` of `qp` to `value`. */ - void set_u(const std::size_t i, const FT value) - { } + void set_u(const std::size_t i, const FT value) { } /// @} @@ -114,7 +88,7 @@ public: Number of values in `solution` equals to the number `n` of values in the vector `x`. \tparam OutIterator - a model of `OutputIterator` that accepts values of type `FT` + a model of `OutputIterator` that accepts values of type `FieldNumberType` \param solution an output iterator with the solution @@ -122,8 +96,7 @@ public: \returns a status of the computation `success == true` */ template - bool solve(OutIterator solution) - { } + bool solve(OutIterator solution) { } /// @} }; diff --git a/Solver_interface/doc/Solver_interface/Solver_interface.txt b/Solver_interface/doc/Solver_interface/Solver_interface.txt index 4a42e373609..1a4e0d0e484 100644 --- a/Solver_interface/doc/Solver_interface/Solver_interface.txt +++ b/Solver_interface/doc/Solver_interface/Solver_interface.txt @@ -137,7 +137,7 @@ extended the existing concepts. Liangliang Nan introduced the concept `MixedIntegerProgramTraits` and two models for solving mixed integer programs when implementing the \ref PkgPolygonalSurfaceReconstruction package. The concepts and models for solving linear and quadratic programs -were later introduced by Dmitry Anisimov. +were later introduced by Dmitry Anisimov and Mael Rouxel-Labbé. Simon Giraudot was responsible for gathering all concepts and classes, and also wrote this user manual with the help of Andreas Fabri. diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index b82173b59f9..3dfc8af4fc1 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -57,7 +57,7 @@ private: std::vector q_vec, l_vec, u_vec; public: - /// Default constructor + /// %Default constructor OSQP_quadratic_program_traits() : n(0), m(0) { } /// Constructor @@ -85,7 +85,7 @@ public: } public: - /// Reset the problem, removing all existing entries and setting sizes to `0`. + /// Resets the problem, removing all existing entries and setting sizes to `0`. void clear() { n = m = 0; @@ -96,7 +96,7 @@ public: u_vec.clear(); } - /// Change the number of variables and the number of constraints of the problem. + /// Changes the number of variables and the number of constraints of the problem. /// /// \warning Calling this function also clears all previous entries. void resize(const int new_n, From b905482f26dc7028f931285036b0071f2edd3874 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 11 Jun 2021 15:24:49 +0200 Subject: [PATCH 235/349] fixed typos --- Solver_interface/include/CGAL/Eigen_solver_traits.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Solver_interface/include/CGAL/Eigen_solver_traits.h b/Solver_interface/include/CGAL/Eigen_solver_traits.h index e2fc4f64c0d..9fe3457e84d 100644 --- a/Solver_interface/include/CGAL/Eigen_solver_traits.h +++ b/Solver_interface/include/CGAL/Eigen_solver_traits.h @@ -70,7 +70,7 @@ The class `Eigen_solver_traits` provides an interface to the sparse solvers of \ \cgalModels `SparseLinearAlgebraWithFactorTraits_d` and `NormalEquationSparseLinearAlgebraTraits_d` -\tparam EigenSolverT A sparse solver of \ref thirdpartyEigen "Eigen". The default solver is the iterative bi-congugate gradient stabilized solver `Eigen::BiCGSTAB` for `double`. +\tparam EigenSolverT A sparse solver of \ref thirdpartyEigen "Eigen". The default solver is the iterative bi-conjugate gradient stabilized solver `Eigen::BiCGSTAB` for `double`. \sa `CGAL::Eigen_sparse_matrix` \sa `CGAL::Eigen_sparse_symmetric_matrix` @@ -230,7 +230,7 @@ protected: }; // Specialization of the solver for BiCGSTAB as for surface parameterization, -// the intializer should be a vector of one's (this was the case in 3.1-alpha +// the initializer should be a vector of one's (this was the case in 3.1-alpha // but not in the official 3.1). template<> class Eigen_solver_traits::EigenType> > From d5a306b817e10cfdcd3067a50924d031a40c770f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 11 Jun 2021 17:26:36 +0200 Subject: [PATCH 236/349] Add VD2's removal policy for ToS2 (+ caching) --- ...gulation_on_sphere_adaptation_policies_2.h | 65 ++++++++++++++ .../Cached_degeneracy_testers.h | 40 ++------- ...iangulation_on_sphere_degeneracy_testers.h | 90 +++++++++++++++++++ 3 files changed, 163 insertions(+), 32 deletions(-) create mode 100644 Voronoi_diagram_2/include/CGAL/Delaunay_triangulation_on_sphere_adaptation_policies_2.h create mode 100644 Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Delaunay_triangulation_on_sphere_degeneracy_testers.h diff --git a/Voronoi_diagram_2/include/CGAL/Delaunay_triangulation_on_sphere_adaptation_policies_2.h b/Voronoi_diagram_2/include/CGAL/Delaunay_triangulation_on_sphere_adaptation_policies_2.h new file mode 100644 index 00000000000..bc445e779ed --- /dev/null +++ b/Voronoi_diagram_2/include/CGAL/Delaunay_triangulation_on_sphere_adaptation_policies_2.h @@ -0,0 +1,65 @@ +// Copyright (c) 2021 GeometryFactory +// 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) : Menelaos Karavelas +// Mael Rouxel-Labbé + +#ifndef CGAL_DELAUNAY_TRIANGULATION_ON_SPHERE_ADAPTATION_POLICIES_2_H +#define CGAL_DELAUNAY_TRIANGULATION_ON_SPHERE_ADAPTATION_POLICIES_2_H 1 + +#include + +#include +#include +#include +#include +#include + +#include + +namespace CGAL { + +//========================================================================= +//========================================================================= + +template +struct Delaunay_triangulation_on_sphere_degeneracy_removal_policy_2 + : public CGAL_VORONOI_DIAGRAM_2_INS::Policy_base + , + CGAL_VORONOI_DIAGRAM_2_INS::Identity_face_rejector, + CGAL_VORONOI_DIAGRAM_2_INS::Default_site_inserter, + CGAL_VORONOI_DIAGRAM_2_INS::Default_site_remover > +{ + typedef typename DToS2::Point Site_2; +}; + + +//========================================================================= +//========================================================================= + +template +struct Delaunay_triangulation_on_sphere_caching_degeneracy_removal_policy_2 + : public CGAL_VORONOI_DIAGRAM_2_INS::Caching_policy_base + , + CGAL_VORONOI_DIAGRAM_2_INS::Identity_face_rejector, + CGAL_VORONOI_DIAGRAM_2_INS::Default_site_inserter, + CGAL_VORONOI_DIAGRAM_2_INS::Default_site_remover > +{ + typedef typename DToS2::Point Site_2; +}; + +//========================================================================= +//========================================================================= + +} // namespace CGAL + +#endif // CGAL_DELAUNAY_TRIANGULATION_ON_SPHERE_ADAPTATION_POLICIES_2_H diff --git a/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Cached_degeneracy_testers.h b/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Cached_degeneracy_testers.h index 12f9938f02f..22a07f94aa1 100644 --- a/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Cached_degeneracy_testers.h +++ b/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Cached_degeneracy_testers.h @@ -52,9 +52,6 @@ public: typedef typename Edge_rejector::Delaunay_graph Delaunay_graph; typedef typename Edge_rejector::Edge Edge; typedef typename Edge_rejector::Face_handle Face_handle; - typedef typename Edge_rejector::Edge_circulator Edge_circulator; - typedef typename Edge_rejector::All_edges_iterator All_edges_iterator; - typedef typename Edge_rejector::Finite_edges_iterator Finite_edges_iterator; typedef typename Edge_rejector::result_type result_type; private: @@ -99,18 +96,9 @@ public: return operator()(dual, Edge(f,i)); } + template bool operator()(const Delaunay_graph& dual, - const Edge_circulator& ec) const { - return operator()(dual, *ec); - } - - bool operator()(const Delaunay_graph& dual, - const All_edges_iterator& eit) const { - return operator()(dual, *eit); - } - - bool operator()(const Delaunay_graph& dual, - const Finite_edges_iterator& eit) const { + const EdgeIterator eit) const { return operator()(dual, *eit); } @@ -167,9 +155,6 @@ public: typedef typename Edge_rejector::Delaunay_graph Delaunay_graph; typedef typename Edge_rejector::Edge Edge; typedef typename Edge_rejector::Face_handle Face_handle; - typedef typename Edge_rejector::Edge_circulator Edge_circulator; - typedef typename Edge_rejector::All_edges_iterator All_edges_iterator; - typedef typename Edge_rejector::Finite_edges_iterator Finite_edges_iterator; typedef typename Edge_rejector::result_type result_type; private: @@ -214,18 +199,9 @@ public: return operator()(dual, Edge(f,i)); } + template bool operator()(const Delaunay_graph& dual, - const Edge_circulator& ec) const { - return operator()(dual, *ec); - } - - bool operator()(const Delaunay_graph& dual, - const All_edges_iterator& eit) const { - return operator()(dual, *eit); - } - - bool operator()(const Delaunay_graph& dual, - const Finite_edges_iterator& eit) const { + const EdgeIterator eit) const { return operator()(dual, *eit); } @@ -250,11 +226,11 @@ public: bool is_valid() const { return true; } - bool is_valid(const Delaunay_graph& dual) const { + bool is_valid(const Delaunay_graph& dual) const + { bool valid = true; - All_edges_iterator eit; - for (eit = dual.all_edges_begin(); eit != dual.all_edges_end(); ++eit) { - Edge e = *eit; + for (auto eit = dual.all_edges_begin(); eit != dual.all_edges_end(); ++eit) { + const Edge& e = *eit; bool b = !emap.is_defined(e) || (emap[e] != UNDEFINED); valid = valid && b; } diff --git a/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Delaunay_triangulation_on_sphere_degeneracy_testers.h b/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Delaunay_triangulation_on_sphere_degeneracy_testers.h new file mode 100644 index 00000000000..74c0de1cccb --- /dev/null +++ b/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Delaunay_triangulation_on_sphere_degeneracy_testers.h @@ -0,0 +1,90 @@ +// Copyright (c) 2021 GeometryFactory. +// 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) : Menelaos Karavelas +// Mael Rouxel-Labbé + +#ifndef CGAL_VORONOI_DIAGRAM_2_DELAUNAY_TRIANGULATION_ON_SPHERE_DEGENERACY_TESTERS_H +#define CGAL_VORONOI_DIAGRAM_2_DELAUNAY_TRIANGULATION_ON_SPHERE_DEGENERACY_TESTERS_H 1 + +#include + +#include +#include +#include + +namespace CGAL { +namespace VoronoiDiagram_2 { +namespace Internal { + +//========================================================================= +//========================================================================= + +// tests whether a dual edge has zero length +template +class Delaunay_triangulation_on_sphere_edge_tester_2 + : public CGAL_VORONOI_DIAGRAM_2_INS::Rejector_base +{ +public: + typedef DG Delaunay_graph; + + typedef typename Delaunay_graph::Edge Edge; + typedef typename Delaunay_graph::Face_handle Face_handle; + + typedef bool result_type; + + private: + typedef typename Delaunay_graph::Geom_traits Geom_traits; + typedef typename Delaunay_graph::Vertex_handle Vertex_handle; + typedef typename Delaunay_graph::Point Point; + + public: + bool operator()(const Delaunay_graph& dual, + const Face_handle f, int i) const + { + if(dual.dimension() == 1) + return false; + + const Vertex_handle v3 = f->vertex(i); + const Vertex_handle v4 = dual.tds().mirror_vertex(f, i); + + const Vertex_handle v1 = f->vertex(dual.ccw(i)); + const Vertex_handle v2 = f->vertex(dual.cw(i)); + + const Point& p1 = v1->point(); + const Point& p2 = v2->point(); + const Point& p3 = v3->point(); + const Point& p4 = v4->point(); + const Oriented_side os = dual.geom_traits().side_of_oriented_circle_on_sphere_2_object()(p1,p2,p3,p4); + + return (os == ON_ORIENTED_BOUNDARY); + } + + bool operator()(const Delaunay_graph& dual, const Edge& e) const + { + return operator()(dual, e.first, e.second); + } + + template + bool operator()(const Delaunay_graph& dual, + const EdgeIterator eit) const + { + return operator()(dual, *eit); + } +}; + +//========================================================================= +//========================================================================= + +} // namespace Internal +} // namespace VoronoiDiagram_2 +} // namespace CGAL + +#endif // CGAL_VORONOI_DIAGRAM_2_DELAUNAY_TRIANGULATION_ON_SPHERE_DEGENERACY_TESTERS_H From dbe94c282ecd7aedd6451ec1e66d9fb36b0fb5db Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 11 Jun 2021 22:44:30 +0200 Subject: [PATCH 237/349] Move is_currently_single_threaded to namespace CGAL --- Installation/include/CGAL/config.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Installation/include/CGAL/config.h b/Installation/include/CGAL/config.h index 089c7a73e7b..36d5c79fe46 100644 --- a/Installation/include/CGAL/config.h +++ b/Installation/include/CGAL/config.h @@ -591,13 +591,13 @@ using std::max; #endif #ifndef CGAL_HAS_THREADS -inline bool is_currently_single_threaded(){ return true; } + namespace CGAL { inline bool is_currently_single_threaded(){ return true; } } #elif __has_include() -#include -inline bool is_currently_single_threaded(){ return ::__libc_single_threaded; } +# include + namespace CGAL { inline bool is_currently_single_threaded(){ return ::__libc_single_threaded; } } #else -/* This is the conservative default */ -inline bool is_currently_single_threaded(){ return false; } + /* This is the conservative default */ + namespace CGAL { inline bool is_currently_single_threaded(){ return false; } } #endif // Support for LEDA with threads From bed3189719a4c00148a573d08c706bab1a6911d6 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 14 Jun 2021 19:06:48 +0200 Subject: [PATCH 238/349] andreas review --- .../Concepts/LinearProgramTraits.h | 2 +- .../Concepts/QuadraticProgramTraits.h | 4 +--- .../doc/Solver_interface/Solver_interface.txt | 8 ++------ .../examples/Solver_interface/CMakeLists.txt | 8 ++++---- .../Solver_interface/mixed_integer_program.cpp | 15 --------------- .../Solver_interface/osqp_quadratic_program.cpp | 12 ------------ 6 files changed, 8 insertions(+), 41 deletions(-) diff --git a/Solver_interface/doc/Solver_interface/Concepts/LinearProgramTraits.h b/Solver_interface/doc/Solver_interface/Concepts/LinearProgramTraits.h index 49bc506ab92..9000a626aa3 100644 --- a/Solver_interface/doc/Solver_interface/Concepts/LinearProgramTraits.h +++ b/Solver_interface/doc/Solver_interface/Concepts/LinearProgramTraits.h @@ -72,7 +72,7 @@ public: /// @{ /*! - \brief Solves the linear program. + \brief solves the linear program. Number of values in `solution` equals to the number `n` of values in the vector `x`. diff --git a/Solver_interface/doc/Solver_interface/Concepts/QuadraticProgramTraits.h b/Solver_interface/doc/Solver_interface/Concepts/QuadraticProgramTraits.h index 0d1cec8fe95..189f0da26b7 100644 --- a/Solver_interface/doc/Solver_interface/Concepts/QuadraticProgramTraits.h +++ b/Solver_interface/doc/Solver_interface/Concepts/QuadraticProgramTraits.h @@ -46,8 +46,6 @@ public: /*! Sets the entries `Pij` and `Pji` of `qp` to `value`. - - Note that you should define only the upper triangular part of the matrix! */ void set_P(const std::size_t i, const std::size_t j, const FT value) { } @@ -83,7 +81,7 @@ public: /// @{ /*! - \brief Solves the quadratic program. + \brief solves the quadratic program. Number of values in `solution` equals to the number `n` of values in the vector `x`. diff --git a/Solver_interface/doc/Solver_interface/Solver_interface.txt b/Solver_interface/doc/Solver_interface/Solver_interface.txt index 1a4e0d0e484..860815a9e33 100644 --- a/Solver_interface/doc/Solver_interface/Solver_interface.txt +++ b/Solver_interface/doc/Solver_interface/Solver_interface.txt @@ -21,15 +21,11 @@ Library (MKL). For mixed integer programs (either constrained or unconstrained), we provide models using the \ref thirdpartySCIP and \ref thirdpartyGLPK -libraries. It is also possible to derive new models from other -high performance libraries such as CBC or -Gurobi. +libraries. For linear and quadratic programs, we provide a model using the built-in \ref PkgQPSolver "CGAL Linear and Quadratic Programming Solver" and a model using -the external \ref thirdpartyOSQP library. It is also possible to derive new models -from other quadratic programming libraries such as -OOQP for example. +the external \ref thirdpartyOSQP library. \section SectionSolverDiagonalize Matrix Diagonalization diff --git a/Solver_interface/examples/Solver_interface/CMakeLists.txt b/Solver_interface/examples/Solver_interface/CMakeLists.txt index b700decef6d..c8626a2ce33 100644 --- a/Solver_interface/examples/Solver_interface/CMakeLists.txt +++ b/Solver_interface/examples/Solver_interface/CMakeLists.txt @@ -19,20 +19,18 @@ if(TARGET CGAL::Eigen3_support) target_link_libraries(diagonalize_matrix PUBLIC CGAL::Eigen3_support) endif() -create_single_source_cgal_program("mixed_integer_program.cpp") -create_single_source_cgal_program("osqp_quadratic_program.cpp") - find_package(OSQP QUIET) include(CGAL_OSQP_support) if(TARGET CGAL::OSQP_support) + create_single_source_cgal_program("osqp_quadratic_program.cpp") target_link_libraries(osqp_quadratic_program PUBLIC CGAL::OSQP_support) message("OSQP found and used") else() - message(STATUS "NOTICE: OSQP was not found. Complete OSQP examples won't be available.") + message(STATUS "NOTICE: OSQP was not found. OSQP examples won't be available.") endif() @@ -41,6 +39,7 @@ include(CGAL_SCIP_support) if(TARGET CGAL::SCIP_support) + create_single_source_cgal_program("mixed_integer_program.cpp") target_link_libraries(mixed_integer_program PUBLIC CGAL::SCIP_support) message("SCIP found and used") @@ -51,6 +50,7 @@ else() if(TARGET CGAL::GLPK_support) + create_single_source_cgal_program("mixed_integer_program.cpp") target_link_libraries(mixed_integer_program PUBLIC CGAL::GLPK_support) message("GLPK found and used") diff --git a/Solver_interface/examples/Solver_interface/mixed_integer_program.cpp b/Solver_interface/examples/Solver_interface/mixed_integer_program.cpp index f2b444037dd..582f5e73e2d 100644 --- a/Solver_interface/examples/Solver_interface/mixed_integer_program.cpp +++ b/Solver_interface/examples/Solver_interface/mixed_integer_program.cpp @@ -32,9 +32,6 @@ typedef CGAL::GLPK_mixed_integer_program_traits M #endif - -#if defined(CGAL_USE_GLPK) || defined(CGAL_USE_SCIP) - typedef typename MIP_Solver::Variable Variable; typedef typename MIP_Solver::Linear_objective Linear_objective; typedef typename MIP_Solver::Linear_constraint Linear_constraint; @@ -99,15 +96,3 @@ int main() return EXIT_FAILURE; } } - - -#else - -int main(int , char**) -{ - std::cerr << "This test requires either GLPK or SCIP.\n"; - return EXIT_SUCCESS; -} - -#endif // defined(CGAL_USE_GLPK) || defined(CGAL_USE_SCIP) - diff --git a/Solver_interface/examples/Solver_interface/osqp_quadratic_program.cpp b/Solver_interface/examples/Solver_interface/osqp_quadratic_program.cpp index 3bc9136db58..1bab6078616 100644 --- a/Solver_interface/examples/Solver_interface/osqp_quadratic_program.cpp +++ b/Solver_interface/examples/Solver_interface/osqp_quadratic_program.cpp @@ -21,16 +21,11 @@ #include #include #include - -#if defined(CGAL_USE_OSQP) #include -#endif using Kernel = CGAL::Simple_cartesian; using FT = typename Kernel::FT; -#if defined(CGAL_USE_OSQP) - int main(void) { const std::size_t n = 2; // number of variables @@ -68,10 +63,3 @@ int main(void) { } std::cout << std::endl; } - -#else -int main(void) { - std::cout << "This example requires the OSQP library." << std::endl; - return EXIT_SUCCESS; -} -#endif // defined(CGAL_USE_OSQP) From aa6dbfe4f24382197b3025ffa82a39f236c26374 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Tue, 15 Jun 2021 12:56:05 +0200 Subject: [PATCH 239/349] Make CGAL unconditionally depend on Threads::Threads --- Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake index 0745228def8..78586fc0473 100644 --- a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake +++ b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake @@ -144,6 +144,12 @@ function(CGAL_setup_CGAL_dependencies target) if ( RUNNING_CGAL_AUTO_TEST ) target_compile_options(${target} INTERFACE "-Wall") endif() + if(NOT CGAL_HAS_NO_THREADS) + if(NOT TARGET Threads::Threads) + find_package(Threads REQUIRED) + endif() + target_link_libraries(${target} INTERFACE Threads::Threads) + endif() if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3) message( STATUS "Using gcc version 4 or later. Adding -frounding-math" ) if(CMAKE_VERSION VERSION_LESS 3.3) From 6652df3298f232d294f76ddd93331510a38007ff Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Tue, 15 Jun 2021 12:56:41 +0200 Subject: [PATCH 240/349] Remove the offensive static assert It seems `_REENTRANT` is defined by `-pthread, but `Threads::Threads` on Linux only add `-lpthread` at link time, and not `-pthread`. --- Filtered_kernel/include/CGAL/Lazy.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 198aca4a8e3..f4677265af2 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -324,12 +324,6 @@ public: const ET & exact() const { -#if defined(CGAL_HAS_THREADS) && defined(__gnu_linux__) && !defined(_REENTRANT) - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55394 - // -pthread or -lpthread is just needed for linking, but I can't test that here... - // We could take the lack of _REENTRANT on that platform as forcing CGAL_HAS_NO_THREADS - static_assert(false, "Please pass -pthread to the compiler"); -#endif // The test is unnecessary, only use it if benchmark says so, or in order to avoid calling Lazy_exact_Ex_Cst::update_exact() (which used to contain an assertion) //if (is_lazy()) std::call_once(once, [this](){this->update_exact();}); From 530616534ad9c68954067b4722d65d6fba217ec2 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Wed, 16 Jun 2021 17:12:59 +0200 Subject: [PATCH 241/349] Fix and document the CMake CGAL_HAS_NO_THREADS option --- Documentation/doc/Documentation/Preliminaries.txt | 7 +++++-- .../cmake/modules/CGAL_SetupCGALDependencies.cmake | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Documentation/doc/Documentation/Preliminaries.txt b/Documentation/doc/Documentation/Preliminaries.txt index 0fa310a54af..e07d90e9e37 100644 --- a/Documentation/doc/Documentation/Preliminaries.txt +++ b/Documentation/doc/Documentation/Preliminaries.txt @@ -33,8 +33,11 @@ are: If the macro `CGAL_HAS_THREADS` is not defined, then \cgal assumes it can use any thread-unsafe code (such as static variables). By default, this macro is not defined, unless `BOOST_HAS_THREADS` or `_OPENMP` is defined. It is possible -to force its definition on the command line, and it is possible to prevent its default -definition by setting `CGAL_HAS_NO_THREADS` from the command line. +to force its definition in the compiler options, and it is possible to prevent its +default definition by defining the macro `CGAL_HAS_NO_THREADS`. +If you are using CMake, then you can set the CMake option `CGAL_HAS_NO_THREADS` to +`TRUE`. In addition to defining the preprocessor macro CGAL_HAS_NO_THREADS`, it will +also avoid CMake to link with the native threads support library on your system. \section Preliminaries_cc0x C++14 Support diff --git a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake index 78586fc0473..2d9617e447a 100644 --- a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake +++ b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake @@ -144,7 +144,9 @@ function(CGAL_setup_CGAL_dependencies target) if ( RUNNING_CGAL_AUTO_TEST ) target_compile_options(${target} INTERFACE "-Wall") endif() - if(NOT CGAL_HAS_NO_THREADS) + if(CGAL_HAS_NO_THREADS) + target_compile_definitions(${target} INTERFACE CGAL_HAS_NO_THREADS) + else() if(NOT TARGET Threads::Threads) find_package(Threads REQUIRED) endif() From a00340d23221f6502b8597972884d690975e34f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 17 Jun 2021 17:49:47 +0200 Subject: [PATCH 242/349] TWS --- .../internal/Triangulation_2_projection_traits_base_3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h b/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h index 9a728577a4b..bee57e6ba20 100644 --- a/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h +++ b/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h @@ -239,7 +239,7 @@ public: if(! inter){ return boost::none; } - if(const Point* point = boost::get(&*inter)){ + if(const Point* point = boost::get(&*inter)){ return boost::make_optional(variant_type(*point)); } } From 76d143275ad83afc0d71bd72f8e2ef89c57af45b Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 18 Jun 2021 10:16:37 +0200 Subject: [PATCH 243/349] removed trailing whitespaces --- Solver_interface/doc/Solver_interface/Solver_interface.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Solver_interface/doc/Solver_interface/Solver_interface.txt b/Solver_interface/doc/Solver_interface/Solver_interface.txt index fa49ee9f6e4..6389747c4af 100644 --- a/Solver_interface/doc/Solver_interface/Solver_interface.txt +++ b/Solver_interface/doc/Solver_interface/Solver_interface.txt @@ -23,9 +23,9 @@ For mixed integer programs (either constrained or unconstrained), we provide models using the \ref thirdpartySCIP and \ref thirdpartyGLPK libraries. -For linear and quadratic programs, CGAl has the built-in -\ref PkgQPSolver "CGAL Linear and Quadratic Programming Solver" and we also provide -a model using the external \ref thirdpartyOSQP library. +For linear and quadratic programs, CGAL provides the built-in +\ref PkgQPSolver "CGAL Linear and Quadratic Programming Solver" +and we also provide a model using the \ref thirdpartyOSQP library. \section SectionSolverDiagonalize Matrix Diagonalization From 3b905bb34487e1a625633247e090d095f14b2796 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 18 Jun 2021 10:20:59 +0200 Subject: [PATCH 244/349] fixed typo --- Solver_interface/doc/Solver_interface/Solver_interface.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Solver_interface/doc/Solver_interface/Solver_interface.txt b/Solver_interface/doc/Solver_interface/Solver_interface.txt index 6389747c4af..8b3450f8afc 100644 --- a/Solver_interface/doc/Solver_interface/Solver_interface.txt +++ b/Solver_interface/doc/Solver_interface/Solver_interface.txt @@ -23,7 +23,7 @@ For mixed integer programs (either constrained or unconstrained), we provide models using the \ref thirdpartySCIP and \ref thirdpartyGLPK libraries. -For linear and quadratic programs, CGAL provides the built-in +For linear and quadratic programs, \cgal provides the built-in \ref PkgQPSolver "CGAL Linear and Quadratic Programming Solver" and we also provide a model using the \ref thirdpartyOSQP library. From 859bae90369c7f722564a17277063bd11c7385cc Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 18 Jun 2021 14:44:09 +0200 Subject: [PATCH 245/349] sebastien review --- .../PackageDescription.txt | 1 + .../Polygon_mesh_processing.txt | 6 +- ...usdorff_bounded_error_distance_example.cpp | 200 ++---------- .../CGAL/Polygon_mesh_processing/distance.h | 215 +++++++----- .../test_hausdorff_bounded_error_distance.cpp | 306 ++++++++++++++++-- 5 files changed, 448 insertions(+), 280 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index 211a96b0119..299a8a8dce2 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -202,6 +202,7 @@ The page \ref bgl_namedparameters "Named Parameters" describes their usage. \cgalCRPSection{Distance Functions} - `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` +- `CGAL::Polygon_mesh_processing::bounded_error_symmetric_Hausdorff_distance()` - `CGAL::Polygon_mesh_processing::approximate_Hausdorff_distance()` - `CGAL::Polygon_mesh_processing::approximate_symmetric_Hausdorff_distance()` - `CGAL::Polygon_mesh_processing::approximate_max_distance_to_point_set()` diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 0505ebe38a3..88b04d01d89 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -959,7 +959,7 @@ with the following code: The function `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` computes an estimate of the Hausdorff distance of two triangle meshes which is bounded by a user-given error bound. Given two meshes tm1 and tm2, it follows -the procedure given by \cgalCite{tang2009interactive}. Namely, an AABB tree is +the procedure given by \cgalCite{tang2009interactive}. Namely, bounded volume hierarchy (BVH) is built on tm1 and tm2 respectively. The tree on tm1 is used to iterate over all triangles in tm1. Throughout the traversal, the procedure keeps track of a global lower and upper bound on the Hausdorff distance respectively. For each triangle @@ -977,6 +977,10 @@ triangles are processed until a triangle is found in which the Hausdorff distance is realized or in which it is guaranteed to be realized within the user-given error bound. +In the current implementation, the BVH used is an AABB-tree and not the swept sphere +volumes as used in the original implementation. This should explain the runtime difference +observed with the original implementation. + \subsubsection BHDExample Bounded Hausdorff Distance Example In the following examples: (a) the distance of a tetrahedron to a remeshed diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index ea083195a58..5ee5f76eae3 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -1,15 +1,11 @@ -#include -#include #include #include #include #include #include -#include -#include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; @@ -21,43 +17,19 @@ using TAG = CGAL::Sequential_tag; using Surface_mesh = CGAL::Surface_mesh; using Polyhedron = CGAL::Polyhedron_3; using Affine_transformation_3 = CGAL::Aff_transformation_3; -using Timer = CGAL::Real_timer; namespace PMP = CGAL::Polygon_mesh_processing; -template -void get_mesh(const std::string filepath, Mesh& mesh) { +int main(int argc, char** argv) { - mesh.clear(); - std::ifstream input(filepath); - input >> mesh; - std::cout << "* getting mesh with " << num_faces(mesh) << " faces" << std::endl; -} + const double error_bound = 1e-4; + const std::string filepath = (argc > 1 ? argv[1] : "data/blobby.off"); -void get_meshes( - const std::string filepath1, const std::string filepath2, - Surface_mesh& mesh1, Surface_mesh& mesh2) { + // We create a tetrahedron, remesh it, and compute the distance. + // The expected distance is error_bound. + std::cout << std::endl << "* remeshing tetrahedron example:" << std::endl; - get_mesh(filepath1, mesh1); - get_mesh(filepath2, mesh2); -} - -void save_mesh(const Surface_mesh& mesh, const std::string filepath) { - - if (!CGAL::write_PLY(filepath + ".ply", mesh)) { - std::cerr << "ERROR: cannot save this file: " << filepath << std::endl; - exit(EXIT_FAILURE); - } -} - -// An easy example of a tetrahedron and its remeshed version. -void remeshing_tetrahedon_example( - const double error_bound, const bool save = false) { - - Timer timer; Surface_mesh mesh1, mesh2; - std::cout << std::endl << "* (E1) remeshing tetrahedron example:" << std::endl; - CGAL::make_tetrahedron( Point_3(0, 0, 0), Point_3(2, 0, 0), Point_3(1, 1, 1), Point_3(1, 0, 2), mesh1); @@ -72,154 +44,26 @@ void remeshing_tetrahedon_example( mesh2.faces(), target_edge_length, mesh2, PMP::parameters::edge_is_constrained_map(is_constrained_map)); - if (save) save_mesh(mesh1, "mesh1"); - if (save) save_mesh(mesh2, "mesh2"); - - timer.reset(); - timer.start(); - std::cout << "* bounded Hausdorff distance: " << + std::cout << "* one-sided bounded-error Hausdorff distance: " << PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; - timer.stop(); - std::cout << "* processing time: " << timer.time() << " s." << std::endl; -} -// Example with a point realizing the Hausdorff distance strictly -// lying in the interior of a triangle. -void interior_triangle_example( - const double error_bound, const bool save = false) { + // We load a mesh, save it in two different containers, and + // translate the second mesh by 1 unit. The expected distance is 1. + std::cout << std::endl << "* moving mesh example:" << std::endl; - Timer timer; - Surface_mesh mesh1, mesh2; - std::cout << std::endl << "* (E2) interior triangle example:" << std::endl; + Surface_mesh surface_mesh; + std::ifstream sm_input(filepath); + sm_input >> surface_mesh; - mesh1.add_vertex(Point_3(-1, 1, 1)); - mesh1.add_vertex(Point_3( 0, -1, 1)); - mesh1.add_vertex(Point_3( 1, 1, 1)); - mesh1.add_face(mesh1.vertices()); + Polyhedron polyhedron; + std::ifstream poly_input(filepath); + poly_input >> polyhedron; - auto v0 = mesh2.add_vertex(Point_3(-1.0, 1, 0)); - auto v1 = mesh2.add_vertex(Point_3( 0.0, -1, 0)); - auto v2 = mesh2.add_vertex(Point_3( 1.0, 1, 0)); - auto v3 = mesh2.add_vertex(Point_3( 0.0, 1, -1)); - auto v4 = mesh2.add_vertex(Point_3(-0.5, 0, -1)); - auto v5 = mesh2.add_vertex(Point_3( 0.5, 0, -1)); - mesh2.add_face(v0, v3, v4); - mesh2.add_face(v1, v4, v5); - mesh2.add_face(v2, v5, v3); + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(FT(0), FT(0), FT(1))), polyhedron); - if (save) save_mesh(mesh1, "mesh1"); - if (save) save_mesh(mesh2, "mesh2"); - - timer.reset(); - timer.start(); - std::cout << "* bounded Hausdorff distance: " << - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; - timer.stop(); - std::cout << "* processing time: " << timer.time() << " s." << std::endl; -} - -// Read a real mesh given by the user, perturb it slightly, and compute the -// Hausdorff distance between the original mesh and its pertubation. -void perturbing_mesh_example( - const std::string filepath, const double error_bound, const bool save = false) { - - Timer timer; - std::cout << std::endl << "* (E3) perturbing mesh example (Surface Mesh):" << std::endl; - - Surface_mesh mesh1, mesh2; - get_meshes(filepath, filepath, mesh1, mesh2); - - const double max_size = 0.1; - PMP::random_perturbation( - mesh2.vertices(), mesh2, max_size, CGAL::parameters::do_project(false)); - std::cout << "* perturbing the second mesh" << std::endl; - - if (save) save_mesh(mesh2, "mesh2"); - - timer.reset(); - timer.start(); - std::cout << "* bounded Hausdorff distance: " << - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; - timer.stop(); - std::cout << "* processing time: " << timer.time() << " s." << std::endl; -} - -// Read two meshes and store them in two different face graph containers, -// perturb the second mesh, and compute the Hausdorff distance. -void perturbing_mesh_example_with_polyhedron( - const std::string filepath, const double error_bound) { - - Timer timer; - std::cout << std::endl << "* (E3) perturbing mesh example (Polyhedron):" << std::endl; - - Surface_mesh mesh1; - Polyhedron mesh2; - get_mesh(filepath, mesh1); - get_mesh(filepath, mesh2); - - const double max_size = 0.1; - PMP::random_perturbation( - vertices(mesh2), mesh2, max_size, CGAL::parameters::do_project(false)); - std::cout << "* perturbing the second mesh" << std::endl; - - timer.reset(); - timer.start(); - std::cout << "* bounded Hausdorff distance 1->2: " << - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; - std::cout << "* bounded Hausdorff distance 2->1: " << - PMP::bounded_error_Hausdorff_distance(mesh2, mesh1, error_bound) << std::endl; - timer.stop(); - std::cout << "* processing time: " << timer.time() << " s." << std::endl; -} - -// Read two meshes given by the user, initially place them at their originally -// given position. Move the second mesh in 300 steps away from the first one. -// Print how the Hausdorff distance changes. -void moving_mesh_example( - const std::string filepath1, const std::string filepath2, - const std::size_t n, const double error_bound, const bool save = false) { - - Timer timer; - std::cout << std::endl << "* (E4) moving mesh example:" << std::endl; - - Surface_mesh mesh1, mesh2; - get_meshes(filepath1, filepath2, mesh1, mesh2); - - const auto bbox = PMP::bbox(mesh2); - const FT distance = CGAL::approximate_sqrt(CGAL::squared_distance( - Point_3(bbox.xmin(), bbox.ymin(), bbox.zmin()), - Point_3(bbox.xmax(), bbox.ymax(), bbox.zmax()))); - - const FT t = FT(1) / FT(100); - if (save) save_mesh(mesh2, "mesh-0"); - - for (std::size_t i = 0; i < n; ++i) { - PMP::transform(Affine_transformation_3(CGAL::Translation(), - Vector_3(t * distance, t * distance, t * distance)), mesh2); - - timer.reset(); - timer.start(); - std::cout << "* position: " << i << std::endl; - std::cout << "* bounded Hausdorff distance: " << - PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound) << std::endl; - timer.stop(); - std::cout << "* processing time: " << timer.time() << " s." << std::endl; - if (save) save_mesh(mesh2, "mesh-" + std::to_string(i + 1)); - } -} - -int main(int argc, char** argv) { - - const double error_bound = 1e-4; - std::cout << std::endl << "* error bound: " << error_bound << std::endl; - std::string filepath = (argc > 1 ? argv[1] : "data/blobby.off"); - - remeshing_tetrahedon_example(error_bound); - interior_triangle_example(error_bound); - perturbing_mesh_example(filepath, error_bound); - perturbing_mesh_example_with_polyhedron(filepath, error_bound); - moving_mesh_example(filepath, filepath, 5, error_bound); - - std::cout << std::endl; + std::cout << "* symmetric bounded-error Hausdorff distance: " << + PMP::bounded_error_symmetric_Hausdorff_distance(surface_mesh, polyhedron, error_bound) + << std::endl << std::endl; return EXIT_SUCCESS; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 433cbd2d6d6..b9445ed98e1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -1031,12 +1031,12 @@ double approximate_Hausdorff_distance( CGAL_assertion_code( bool is_triangle = is_triangle_mesh(tm) ); CGAL_assertion_msg (is_triangle, "Mesh is not triangulated. Distance computing impossible."); - #ifdef CGAL_HAUSDORFF_DEBUG - std::cout << "Nb sample points " << sample_points.size() << "\n"; - #endif typedef typename Kernel::Point_3 Point_3; std::vector sample_points (boost::begin(original_sample_points), boost::end(original_sample_points) ); + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout << "Nb sample points " << sample_points.size() << "\n"; + #endif spatial_sort(sample_points.begin(), sample_points.end()); @@ -1327,6 +1327,9 @@ double approximate_symmetric_Hausdorff_distance(const TriangleMesh& tm1, // Use this def in order to get back the parallel version of the one-sided Hausdorff code! // #define USE_PARALLEL_BEHD +// Use this def in order to get all DEBUG info related to the bounded-error Hausdorff code! +// #define CGAL_HAUSDORFF_DEBUG + namespace internal { template< class Kernel, @@ -1356,13 +1359,14 @@ std::pair preprocess_bounded_error_Hausdorff_impl( { using FT = typename Kernel::FT; using Point_3 = typename Kernel::Point_3; - using Timer = CGAL::Real_timer; + #ifdef CGAL_HAUSDORFF_DEBUG + using Timer = CGAL::Real_timer; Timer timer; timer.start(); - - // std::cout << "* preprocessing begin ...." << std::endl; - std::cout.precision(20); + std::cout << "* preprocessing begin ...." << std::endl; + std::cout.precision(17); + #endif // Compute the max value that is used as infinity value for the given meshes. // In our case, it is twice the length of the diagonal of the bbox of two input meshes. @@ -1392,9 +1396,11 @@ std::pair preprocess_bounded_error_Hausdorff_impl( match_faces(tm1, tm2, std::back_inserter(common), std::back_inserter(tm1_only), std::back_inserter(tm2_only), np1, np2); - // std::cout << "- common: " << common.size() << std::endl; - // std::cout << "- tm1 only: " << tm1_only.size() << std::endl; - // std::cout << "- tm2 only: " << tm2_only.size() << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout << "- common: " << common.size() << std::endl; + std::cout << "- tm1 only: " << tm1_only.size() << std::endl; + std::cout << "- tm2 only: " << tm2_only.size() << std::endl; + #endif if (is_one_sided_distance) { // one-sided distance @@ -1436,9 +1442,11 @@ std::pair preprocess_bounded_error_Hausdorff_impl( tm2_tree.insert(faces2.begin(), faces2.end(), tm2, vpm2); } + #ifdef CGAL_HAUSDORFF_DEBUG timer.stop(); - // std::cout << "* .... end preprocessing" << std::endl; - // std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; + std::cout << "* .... end preprocessing" << std::endl; + std::cout << "* preprocessing time (sec.): " << timer.time() << std::endl; + #endif return std::make_pair(infinity_value, rebuild); } @@ -1480,18 +1488,19 @@ double bounded_error_Hausdorff_impl( using Face_handle_2 = typename boost::graph_traits::face_descriptor; using Candidate = Candidate_triangle; - using Timer = CGAL::Real_timer; - std::cout.precision(20); CGAL_precondition(error_bound >= FT(0)); CGAL_precondition(tm1_tree.size() > 0); CGAL_precondition(tm2_tree.size() > 0); // First, we apply culling. - // std::cout << "- applying culling" << std::endl; - + #ifdef CGAL_HAUSDORFF_DEBUG + using Timer = CGAL::Real_timer; Timer timer; timer.start(); + std::cout << "- applying culling" << std::endl; + std::cout.precision(17); + #endif // Build traversal traits for tm1_tree. TM1_hd_traits traversal_traits_tm1( @@ -1506,12 +1515,16 @@ double bounded_error_Hausdorff_impl( auto& candidate_triangles = traversal_traits_tm1.get_candidate_triangles(); auto global_bounds = traversal_traits_tm1.get_global_bounds(); - // std::cout << "- number of candidate triangles: " << candidate_triangles.size() << std::endl; - // const FT culling_rate = FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)); - // std::cout << "- culling rate: " << culling_rate << "%" << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout << "- number of candidate triangles: " << candidate_triangles.size() << std::endl; + const FT culling_rate = FT(100) - (FT(candidate_triangles.size()) / FT(tm1_tree.size()) * FT(100)); + std::cout << "- culling rate: " << culling_rate << "%" << std::endl; + #endif + #ifdef CGAL_HAUSDORFF_DEBUG timer.stop(); - // std::cout << "* culling (sec.): " << timer.time() << std::endl; + std::cout << "* culling (sec.): " << timer.time() << std::endl; + #endif CGAL_assertion(global_bounds.lower >= FT(0)); CGAL_assertion(global_bounds.upper >= FT(0)); @@ -1526,10 +1539,11 @@ double bounded_error_Hausdorff_impl( CGAL_assertion(!traversal_traits_tm1.early_quit()); // Second, we apply subdivision. - // std::cout << "- applying subdivision" << std::endl; - + #ifdef CGAL_HAUSDORFF_DEBUG timer.reset(); timer.start(); + std::cout << "- applying subdivision" << std::endl; + #endif // See Section 5.1 in the paper. const FT squared_error_bound = error_bound * error_bound; @@ -1657,8 +1671,10 @@ double bounded_error_Hausdorff_impl( } } + #ifdef CGAL_HAUSDORFF_DEBUG timer.stop(); - // std::cout << "* subdivision (sec.): " << timer.time() << std::endl; + std::cout << "* subdivision (sec.): " << timer.time() << std::endl; + #endif // Compute linear interpolation between the found lower and upper bounds. CGAL_assertion(global_bounds.lower >= FT(0)); @@ -1667,12 +1683,6 @@ double bounded_error_Hausdorff_impl( const double hdist = CGAL::to_double((global_bounds.lower + global_bounds.upper) / FT(2)); // Get realizing triangles. - // std::cout << "- found lface 1:" << static_cast(global_bounds.lpair.first) << std::endl; - // std::cout << "- found lface 2:" << static_cast(global_bounds.lpair.second) << std::endl; - - // std::cout << "- found uface 1:" << static_cast(global_bounds.upair.first) << std::endl; - // std::cout << "- found uface 2:" << static_cast(global_bounds.upair.second) << std::endl; - CGAL_assertion(global_bounds.lpair.first != boost::graph_traits::null_face()); CGAL_assertion(global_bounds.lpair.second != boost::graph_traits::null_face()); CGAL_assertion(global_bounds.upair.first != boost::graph_traits::null_face()); @@ -1708,7 +1718,9 @@ struct Triangle_mesh_wrapper { template struct Bounded_error_preprocessing { + #ifdef CGAL_HAUSDORFF_DEBUG using Timer = CGAL::Real_timer; + #endif std::vector& tm_wrappers; // Constructor. @@ -1731,9 +1743,14 @@ struct Bounded_error_preprocessing { // TODO: make AABB tree build parallel! void operator()(const tbb::blocked_range& range) { + + #ifdef CGAL_HAUSDORFF_DEBUG Timer timer; timer.reset(); timer.start(); + std::cout.precision(17); + #endif + for (std::size_t i = range.begin(); i != range.end(); ++i) { CGAL_assertion(i < tm_wrappers.size()); auto& tm_wrapper = tm_wrappers[i]; @@ -1747,8 +1764,11 @@ struct Bounded_error_preprocessing { CGAL_assertion_msg(false, "Error: wrong boost any type!"); } } + + #ifdef CGAL_HAUSDORFF_DEBUG timer.stop(); - // std::cout << "* time operator() preprocessing (sec.): " << timer.time() << std::endl; + std::cout << "* time operator() preprocessing (sec.): " << timer.time() << std::endl; + #endif } void join(Bounded_error_preprocessing&) { } @@ -1764,7 +1784,9 @@ template< class TriangleMesh1, struct Bounded_error_distance_computation { using FT = typename Kernel::FT; + #ifdef CGAL_HAUSDORFF_DEBUG using Timer = CGAL::Real_timer; + #endif const std::vector& tm1_parts; const TriangleMesh2& tm2; const FT error_bound; const VPM1& vpm1; const VPM2& vpm2; @@ -1796,9 +1818,14 @@ struct Bounded_error_distance_computation { } void operator()(const tbb::blocked_range& range) { + + #ifdef CGAL_HAUSDORFF_DEBUG Timer timer; timer.reset(); timer.start(); + std::cout.precision(17); + #endif + double hdist = -1.0; auto stub = CGAL::Emptyset_iterator(); @@ -1816,8 +1843,11 @@ struct Bounded_error_distance_computation { if (dist > hdist) hdist = dist; } if (hdist > distance) distance = hdist; + + #ifdef CGAL_HAUSDORFF_DEBUG timer.stop(); - // std::cout << "* time operator() computation (sec.): " << timer.time() << std::endl; + std::cout << "* time operator() computation (sec.): " << timer.time() << std::endl; + #endif } void join(Bounded_error_distance_computation& rhs) { @@ -1871,8 +1901,11 @@ double bounded_error_one_sided_Hausdorff_impl( using Face_handle_1 = typename boost::graph_traits::face_descriptor; using Face_handle_2 = typename boost::graph_traits::face_descriptor; - using Timer = CGAL::Real_timer; - + // This is parallel version: we split the tm1 into parts, build trees for all parts, and + // run in parallel all BHD computations. The final distance is obtained by taking the max + // between BHDs computed for these parts with respect to tm2. + // This is off by default because the parallel version does not show much of runtime improvement. + // The slowest part is building AABB trees and this is what should be accelerated in the future. #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) && defined(USE_PARALLEL_BEHD) using Point_3 = typename Kernel::Point_3; using TMF = CGAL::Face_filtered_graph; @@ -1887,8 +1920,11 @@ double bounded_error_one_sided_Hausdorff_impl( std::vector tm_wrappers; #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) + #ifdef CGAL_HAUSDORFF_DEBUG + using Timer = CGAL::Real_timer; Timer timer; - std::cout.precision(20); + std::cout.precision(17); + #endif TM1_tree tm1_tree; TM2_tree tm2_tree; @@ -1898,15 +1934,19 @@ double bounded_error_one_sided_Hausdorff_impl( // TODO: add to NP! const int nb_cores = 4; const std::size_t min_nb_faces_to_split = 100; // TODO: increase this number? - // std::cout << "* num cores: " << nb_cores << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout << "* num cores: " << nb_cores << std::endl; + #endif if ( boost::is_convertible::value && nb_cores > 1 && faces(tm1).size() >= min_nb_faces_to_split) { // (0) -- Compute infinity value. + #ifdef CGAL_HAUSDORFF_DEBUG timer.reset(); timer.start(); + #endif const auto bbox1 = bbox(tm1); const auto bbox2 = bbox(tm2); const auto bb = bbox1 + bbox2; @@ -1915,39 +1955,54 @@ double bounded_error_one_sided_Hausdorff_impl( Point_3(bb.xmax(), bb.ymax(), bb.zmax())); infinity_value = CGAL::approximate_sqrt(sq_dist) * FT(2); CGAL_assertion(infinity_value >= FT(0)); + #ifdef CGAL_HAUSDORFF_DEBUG timer.stop(); - // const double time0 = timer.time(); - // std::cout << "- computing infinity (sec.): " << time0 << std::endl; + const double time0 = timer.time(); + std::cout << "- computing infinity (sec.): " << time0 << std::endl; + #endif // (1) -- Create partition of tm1. + #ifdef CGAL_HAUSDORFF_DEBUG timer.reset(); timer.start(); + #endif using Face_property_tag = CGAL::dynamic_face_property_t; auto face_pid_map = get(Face_property_tag(), tm1); CGAL::METIS::partition_graph( tm1, nb_cores, CGAL::parameters:: face_partition_id_map(face_pid_map)); + #ifdef CGAL_HAUSDORFF_DEBUG timer.stop(); - // const double time1 = timer.time(); - // std::cout << "- computing partition time (sec.): " << time1 << std::endl; + const double time1 = timer.time(); + std::cout << "- computing partition time (sec.): " << time1 << std::endl; + #endif // (2) -- Create a filtered face graph for each part. + #ifdef CGAL_HAUSDORFF_DEBUG timer.reset(); timer.start(); + #endif tm1_parts.reserve(nb_cores); for (int i = 0; i < nb_cores; ++i) { tm1_parts.emplace_back(tm1, i, face_pid_map); - // CGAL_assertion(tm1_parts.back().is_selection_valid()); // TODO: why is it triggered sometimes? - // std::cout << "- part " << i << " size: " << tm1_parts.back().number_of_faces() << std::endl; + // TODO: why is it triggered sometimes? + // CGAL_assertion(tm1_parts.back().is_selection_valid()); + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout << "- part " << i << " size: " << tm1_parts.back().number_of_faces() << std::endl; + #endif } CGAL_assertion(tm1_parts.size() == nb_cores); + #ifdef CGAL_HAUSDORFF_DEBUG timer.stop(); - // const double time2 = timer.time(); - // std::cout << "- creating graphs time (sec.): " << time2 << std::endl; + const double time2 = timer.time(); + std::cout << "- creating graphs time (sec.): " << time2 << std::endl; + #endif // (3) -- Preprocess all input data. + #ifdef CGAL_HAUSDORFF_DEBUG timer.reset(); timer.start(); + #endif tm1_trees.resize(tm1_parts.size()); tm_wrappers.reserve(tm1_parts.size() + 1); for (std::size_t i = 0; i < tm1_parts.size(); ++i) { @@ -1957,20 +2012,26 @@ double bounded_error_one_sided_Hausdorff_impl( CGAL_assertion(tm_wrappers.size() == tm1_parts.size() + 1); Bounded_error_preprocessing bep(tm_wrappers); tbb::parallel_reduce(tbb::blocked_range(0, tm_wrappers.size()), bep); + #ifdef CGAL_HAUSDORFF_DEBUG timer.stop(); - // const double time3 = timer.time(); - // std::cout << "- creating trees time (sec.) " << time3 << std::endl; + const double time3 = timer.time(); + std::cout << "- creating trees time (sec.) " << time3 << std::endl; + #endif // Final timing. - // std::cout << "* preprocessing parallel time (sec.) " << - // time0 + time1 + time2 + time3 << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout << "* preprocessing parallel time (sec.) " << + time0 + time1 + time2 + time3 << std::endl; + #endif } else // sequential version #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) { - // std::cout << "* preprocessing sequential version " << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG timer.reset(); timer.start(); + std::cout << "* preprocessing sequential version " << std::endl; + #endif bool rebuild = false; std::vector tm1_only; std::vector tm2_only; @@ -1984,13 +2045,19 @@ double bounded_error_one_sided_Hausdorff_impl( tm1_tree.do_not_accelerate_distance_queries(); tm2_tree.accelerate_distance_queries(); } + #ifdef CGAL_HAUSDORFF_DEBUG timer.stop(); - // std::cout << "* preprocessing sequential time (sec.) " << timer.time() << std::endl; + std::cout << "* preprocessing sequential time (sec.) " << timer.time() << std::endl; + #endif } - // std::cout << "* infinity_value: " << infinity_value << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout << "* infinity_value: " << infinity_value << std::endl; + #endif if (infinity_value < FT(0)) { - // std::cout << "* culling rate: 100%" << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout << "* culling rate: 100%" << std::endl; + #endif const auto face1 = *(faces(tm1).begin()); const auto face2 = *(faces(tm2).begin()); *out++ = std::make_pair(face1, face2); @@ -2002,15 +2069,19 @@ double bounded_error_one_sided_Hausdorff_impl( const FT initial_bound = error_bound; std::atomic hdist; + #ifdef CGAL_HAUSDORFF_DEBUG timer.reset(); timer.start(); + #endif #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) && defined(USE_PARALLEL_BEHD) if ( boost::is_convertible::value && nb_cores > 1 && faces(tm1).size() >= min_nb_faces_to_split) { - // std::cout << "* executing parallel version " << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout << "* executing parallel version " << std::endl; + #endif Bounded_error_distance_computation bedc( tm1_parts, tm2, error_bound, vpm1, vpm2, infinity_value, initial_bound, tm1_trees, tm2_tree); @@ -2020,21 +2091,24 @@ double bounded_error_one_sided_Hausdorff_impl( } else // sequential version #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) { - // std::cout << "* executing sequential version " << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout << "* executing sequential version " << std::endl; + #endif hdist = bounded_error_Hausdorff_impl( tm1, tm2, error_bound, vpm1, vpm2, infinity_value, initial_bound, distance_bound, tm1_tree, tm2_tree, out); } + #ifdef CGAL_HAUSDORFF_DEBUG timer.stop(); - // std::cout << "* computation time (sec.) " << timer.time() << std::endl; + std::cout << "* computation time (sec.) " << timer.time() << std::endl; + #endif CGAL_assertion(hdist >= 0.0); return hdist; } -// TODO: should we add a parallel version here? template< class Concurrency_tag, class Kernel, class TriangleMesh1, @@ -2064,14 +2138,6 @@ double bounded_error_symmetric_Hausdorff_impl( "Parallel_tag is enabled but at least TBB or METIS is unavailable."); #endif - // Naive version. - // TODO: we can use it for parallel version to simplify our life. - // const double hdist1 = bounded_error_one_sided_Hausdorff_impl( - // tm1, tm2, error_bound, distance_bound, compare_meshes, vpm1, vpm2, np1, np2, out1); - // const double hdist2 = bounded_error_one_sided_Hausdorff_impl( - // tm2, tm1, error_bound, distance_bound, compare_meshes, vpm2, vpm1, np1, np2, out2); - // return (CGAL::max)(hdist1, hdist2); - // Optimized version. // -- We compare meshes only if it is required. // -- We first build trees and rebuild them only if it is required. @@ -2090,7 +2156,6 @@ double bounded_error_symmetric_Hausdorff_impl( using Face_handle_1 = typename boost::graph_traits::face_descriptor; using Face_handle_2 = typename boost::graph_traits::face_descriptor; - std::cout.precision(20); std::vector tm1_only; std::vector tm2_only; @@ -2104,7 +2169,10 @@ double bounded_error_symmetric_Hausdorff_impl( tm1_tree, tm2_tree, tm1_only, tm2_only); if (infinity_value < FT(0)) { - // std::cout << "* culling rate: 100%" << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout.precision(17); + std::cout << "* culling rate: 100%" << std::endl; + #endif const auto face1 = *(faces(tm1).begin()); const auto face2 = *(faces(tm2).begin()); *out1++ = std::make_pair(face1, face2); @@ -2470,7 +2538,7 @@ template< class Concurrency_tag, class TriangleMesh2, class NamedParameters1, class NamedParameters2 > -bool is_further_than( +bool is_Hausdorff_distance_larger( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const double distance_bound, @@ -2516,8 +2584,11 @@ bool is_further_than( } CGAL_assertion(hdist >= 0.0); - // std::cout << "- fin distance: " << hdist << std::endl; - // std::cout << "- max distance: " << distance_bound << std::endl; + #ifdef CGAL_HAUSDORFF_DEBUG + std::cout.precision(17); + std::cout << "- fin distance: " << hdist << std::endl; + std::cout << "- max distance: " << distance_bound << std::endl; + #endif return hdist > distance_bound; } @@ -2525,27 +2596,27 @@ template< class Concurrency_tag, class TriangleMesh1, class TriangleMesh2, class NamedParameters1 > -double is_further_than( +double is_Hausdorff_distance_larger( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const double max_distance, const double error_bound, const NamedParameters1& np1) { - return is_further_than( + return is_Hausdorff_distance_larger( tm1, tm2, max_distance, error_bound, np1, parameters::all_default()); } template< class Concurrency_tag, class TriangleMesh1, class TriangleMesh2 > -double is_further_than( +double is_Hausdorff_distance_larger( const TriangleMesh1& tm1, const TriangleMesh2& tm2, const double max_distance = 1.0, const double error_bound = 0.0001) { - return is_further_than( + return is_Hausdorff_distance_larger( tm1, tm2, max_distance, error_bound, parameters::all_default()); } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index fa1a6fcf816..8079da33ace 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -1,6 +1,9 @@ // Use it to include parallel computations in the bounded error Hausdorff distance. // #define USE_PARALLEL_BEHD +// Use this def in order to get all DEBUG info related to the bounded-error Hausdorff code! +// #define CGAL_HAUSDORFF_DEBUG + #include #include #include @@ -10,6 +13,7 @@ #include #include +#include #include #include #include @@ -28,6 +32,7 @@ using Triangle_3 = typename Kernel::Triangle_3; using TAG = CGAL::Sequential_tag; using Surface_mesh = CGAL::Surface_mesh; +using Polyhedron = CGAL::Polyhedron_3; using Affine_transformation_3 = CGAL::Aff_transformation_3; using Timer = CGAL::Real_timer; @@ -76,23 +81,26 @@ struct Bounded_error_hd_wrapper { } }; -void get_mesh(const std::string filepath, Surface_mesh& mesh) { +template +void get_mesh(const std::string filepath, PolygonMesh& mesh) { mesh.clear(); std::ifstream input(filepath); input >> mesh; - std::cout << "* getting mesh with " << mesh.number_of_faces() << " faces" << std::endl; + std::cout << "* getting mesh with " << faces(mesh).size() << " faces" << std::endl; } +template void get_meshes( const std::string filepath1, const std::string filepath2, - Surface_mesh& mesh1, Surface_mesh& mesh2) { + PolygonMesh1& mesh1, PolygonMesh2& mesh2) { get_mesh(filepath1, mesh1); get_mesh(filepath2, mesh2); } -void save_mesh(const Surface_mesh& mesh, const std::string filepath) { +template +void save_mesh(const PolygonMesh& mesh, const std::string filepath) { if (!CGAL::write_PLY(filepath + ".ply", mesh)) { std::cerr << "ERROR: cannot save this file: " << filepath << std::endl; @@ -100,6 +108,176 @@ void save_mesh(const Surface_mesh& mesh, const std::string filepath) { } } +// An easy example of a tetrahedron and its remeshed version. +void remeshing_tetrahedon_example( + const double error_bound, const bool save = false) { + + Timer timer; + Surface_mesh mesh1, mesh2; + std::cout << std::endl << "* (E1) remeshing Tetrahedron example:" << std::endl; + + CGAL::make_tetrahedron( + Point_3(0, 0, 0), Point_3(2, 0, 0), + Point_3(1, 1, 1), Point_3(1, 0, 2), mesh1); + mesh2 = mesh1; + + using edge_descriptor = typename boost::graph_traits::edge_descriptor; + Surface_mesh::Property_map is_constrained_map = + mesh2.add_property_map("e:is_constrained", true).first; + + const double target_edge_length = 0.05; + PMP::isotropic_remeshing( + mesh2.faces(), target_edge_length, mesh2, + PMP::parameters::edge_is_constrained_map(is_constrained_map)); + + if (save) save_mesh(mesh1, "mesh1"); + if (save) save_mesh(mesh2, "mesh2"); + + timer.reset(); + timer.start(); + const double hdist = PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound); + std::cout << "* bounded-error Hausdorff distance: " << hdist << std::endl; + timer.stop(); + std::cout << "* processing time: " << timer.time() << " s." << std::endl; + assert(hdist == error_bound); +} + +// Example with a point realizing the Hausdorff distance strictly +// lying in the interior of a triangle. +void interior_triangle_example( + const double error_bound, const bool save = false) { + + Timer timer; + Surface_mesh mesh1, mesh2; + std::cout << std::endl << "* (E2) interior Triangle example:" << std::endl; + + mesh1.add_vertex(Point_3(-1, 1, 1)); + mesh1.add_vertex(Point_3( 0, -1, 1)); + mesh1.add_vertex(Point_3( 1, 1, 1)); + mesh1.add_face(mesh1.vertices()); + + auto v0 = mesh2.add_vertex(Point_3(-1.0, 1, 0)); + auto v1 = mesh2.add_vertex(Point_3( 0.0, -1, 0)); + auto v2 = mesh2.add_vertex(Point_3( 1.0, 1, 0)); + auto v3 = mesh2.add_vertex(Point_3( 0.0, 1, -1)); + auto v4 = mesh2.add_vertex(Point_3(-0.5, 0, -1)); + auto v5 = mesh2.add_vertex(Point_3( 0.5, 0, -1)); + mesh2.add_face(v0, v3, v4); + mesh2.add_face(v1, v4, v5); + mesh2.add_face(v2, v5, v3); + + if (save) save_mesh(mesh1, "mesh1"); + if (save) save_mesh(mesh2, "mesh2"); + + timer.reset(); + timer.start(); + const double hdist = PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound); + std::cout << "* bounded-error Hausdorff distance: " << hdist << std::endl; + timer.stop(); + std::cout << "* processing time: " << timer.time() << " s." << std::endl; + assert(hdist >= 1.0); +} + +// Read a real mesh given by the user, perturb it slightly, and compute the +// Hausdorff distance between the original mesh and its pertubation. +void perturbing_surface_mesh_example( + const std::string filepath, const double error_bound, const bool save = false) { + + Timer timer; + std::cout << std::endl << "* (E3) perturbing Surface Mesh example:" << std::endl; + + Surface_mesh mesh1, mesh2; + get_meshes(filepath, filepath, mesh1, mesh2); + + const double max_size = 0.1; + PMP::random_perturbation( + mesh2.vertices(), mesh2, max_size, CGAL::parameters::do_project(false)); + std::cout << "* perturbing the second mesh" << std::endl; + + if (save) save_mesh(mesh2, "mesh2"); + + timer.reset(); + timer.start(); + const double hdist = PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound); + std::cout << "* bounded-error Hausdorff distance: " << hdist << std::endl; + timer.stop(); + std::cout << "* processing time: " << timer.time() << " s." << std::endl; + assert(hdist > 0.0); +} + +// Read two meshes and store them in two different face graph containers, +// perturb the second mesh, and compute the Hausdorff distance. +void perturbing_polyhedron_mesh_example( + const std::string filepath, const double error_bound) { + + Timer timer; + std::cout << std::endl << "* (E3) perturbing Polyhedron mesh example:" << std::endl; + + Surface_mesh mesh1; + Polyhedron mesh2; + get_mesh(filepath, mesh1); + get_mesh(filepath, mesh2); + + const double max_size = 0.1; + PMP::random_perturbation( + vertices(mesh2), mesh2, max_size, CGAL::parameters::do_project(false)); + std::cout << "* perturbing the second mesh" << std::endl; + + timer.reset(); + timer.start(); + const double hdist1 = PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound); + const double hdist2 = PMP::bounded_error_Hausdorff_distance(mesh2, mesh1, error_bound); + std::cout << "* bounded-error Hausdorff distance 1->2: " << hdist1 << std::endl; + std::cout << "* bounded-error Hausdorff distance 2->1: " << hdist2 << std::endl; + timer.stop(); + std::cout << "* processing time: " << timer.time() << " s." << std::endl; + assert(hdist1 > 0.0); + assert(hdist2 > 0.0); + assert(hdist2 > hdist1); + + const double hdist3 = PMP::bounded_error_symmetric_Hausdorff_distance(mesh1, mesh2, error_bound); + assert(hdist3 == (CGAL::max)(hdist1, hdist2)); +} + +// Read two meshes given by the user, initially place them at their originally +// given position. Move the second mesh in 300 steps away from the first one. +// Print how the Hausdorff distance changes. +void moving_surface_mesh_example( + const std::string filepath1, const std::string filepath2, + const std::size_t n, const double error_bound, const bool save = false) { + + Timer timer; + std::cout << std::endl << "* (E4) moving Surface Mesh example:" << std::endl; + + Surface_mesh mesh1, mesh2; + get_meshes(filepath1, filepath2, mesh1, mesh2); + + const auto bbox = PMP::bbox(mesh2); + const FT distance = CGAL::approximate_sqrt(CGAL::squared_distance( + Point_3(bbox.xmin(), bbox.ymin(), bbox.zmin()), + Point_3(bbox.xmax(), bbox.ymax(), bbox.zmax()))); + + const FT t = FT(1) / FT(100); + if (save) save_mesh(mesh2, "mesh-0"); + + double curr_dist = 0.0; + for (std::size_t i = 0; i < n; ++i) { + PMP::transform(Affine_transformation_3(CGAL::Translation(), + Vector_3(t * distance, t * distance, t * distance)), mesh2); + + timer.reset(); + timer.start(); + const double hdist = PMP::bounded_error_Hausdorff_distance(mesh1, mesh2, error_bound); + std::cout << "* position: " << i << std::endl; + std::cout << "* bounded-error Hausdorff distance: " << hdist << std::endl; + timer.stop(); + std::cout << "* processing time: " << timer.time() << " s." << std::endl; + if (save) save_mesh(mesh2, "mesh-" + std::to_string(i + 1)); + assert(hdist > curr_dist); + curr_dist = hdist; + } +} + template void test_0(const FunctionWrapper& functor, const bool save = false) { @@ -121,14 +299,16 @@ void test_0(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double naive = (CGAL::max)(dista, distb); const double distc = functor.symmetric(mesh1, mesh2); - assert(distc == naive); std::cout << "* Hausdorff distance (expected 0): " << dista << std::endl; std::cout << "* HInverted distance (expected 0): " << distb << std::endl; std::cout << "* Symmetric distance (expected 0): " << distc << std::endl; + + assert(dista == 0.0); + assert(distb == 0.0); + assert(distc == naive); } template @@ -155,14 +335,16 @@ void test_1(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double naive = (CGAL::max)(dista, distb); const double distc = functor.symmetric(mesh1, mesh2); - assert(distc == naive); std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; std::cout << "* HInverted distance (expected 1): " << distb << std::endl; std::cout << "* Symmetric distance (expected 1): " << distc << std::endl; + + assert(dista == 1.0); + assert(distb == 1.0); + assert(distc == naive); } template @@ -189,14 +371,16 @@ void test_2(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double naive = (CGAL::max)(dista, distb); const double distc = functor.symmetric(mesh1, mesh2); - assert(distc == naive); std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; std::cout << "* HInverted distance (expected 1): " << distb << std::endl; std::cout << "* Symmetric distance (expected 1): " << distc << std::endl; + + assert(dista == 1.0); + assert(distb == 1.0); + assert(distc == naive); } template @@ -224,14 +408,16 @@ void test_3(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double naive = (CGAL::max)(dista, distb); const double distc = functor.symmetric(mesh1, mesh2); - assert(distc == naive); std::cout << "* Hausdorff distance (expected sqrt(2)): " << dista << std::endl; std::cout << "* HInverted distance (expected 2 ): " << distb << std::endl; std::cout << "* Symmetric distance (expected 2 ): " << distc << std::endl; + + assert(CGAL::abs(dista - CGAL::sqrt(2.0)) < 1e-5); // error bound is 1e-4 + assert(distb == 2.0); + assert(distc == naive); } template @@ -258,14 +444,17 @@ void test_4(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double naive = (CGAL::max)(dista, distb); const double distc = functor.symmetric(mesh1, mesh2); - assert(distc == naive); std::cout << "* Hausdorff distance (expected 1.22): " << dista << std::endl; std::cout << "* HInverted distance (expected 1.22): " << distb << std::endl; std::cout << "* Symmetric distance (expected 1.22): " << distc << std::endl; + + assert(CGAL::abs(dista - 1.224744) < 1e-5); // error bound is 1e-4 + assert(CGAL::abs(distb - 1.224744) < 1e-5); // error bound is 1e-4 + assert(dista == distb); + assert(distc == naive); } template @@ -293,14 +482,16 @@ void test_5(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double naive = (CGAL::max)(dista, distb); const double distc = functor.symmetric(mesh1, mesh2); - assert(distc == naive); std::cout << "* Hausdorff distance (expected 1.73): " << dista << std::endl; std::cout << "* HInverted distance (expected 2.12): " << distb << std::endl; std::cout << "* Symmetric distance (expected 2.12): " << distc << std::endl; + + assert(CGAL::abs(dista - 1.732050) < 1e-5); // error bound is 1e-4 + assert(CGAL::abs(distb - 2.121320) < 1e-5); // error bound is 1e-4 + assert(distc == naive); } template @@ -333,14 +524,16 @@ void test_6(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double naive = (CGAL::max)(dista, distb); const double distc = functor.symmetric(mesh1, mesh2); - assert(distc == naive); std::cout << "* Hausdorff distance (expected 0.0): " << dista << std::endl; std::cout << "* HInverted distance (expected 0.7): " << distb << std::endl; std::cout << "* Symmetric distance (expected 0.7): " << distc << std::endl; + + assert(dista == 0.0); + assert(CGAL::abs(distb - 0.707106) < 1e-5); // error bound is 1e-4 + assert(distc == naive); } template @@ -373,14 +566,16 @@ void test_7(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double naive = (CGAL::max)(dista, distb); const double distc = functor.symmetric(mesh1, mesh2); - assert(distc == naive); std::cout << "* Hausdorff distance (expected 0.50): " << dista << std::endl; std::cout << "* HInverted distance (expected 0.86): " << distb << std::endl; std::cout << "* Symmetric distance (expected 0.86): " << distc << std::endl; + + assert(dista == 0.5); + assert(CGAL::abs(distb - 0.866025) < 1e-5); // error bound is 1e-4 + assert(distc == naive); } template @@ -413,14 +608,16 @@ void test_8(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double naive = (CGAL::max)(dista, distb); const double distc = functor.symmetric(mesh1, mesh2); - assert(distc == naive); std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; std::cout << "* HInverted distance (expected 2): " << distb << std::endl; std::cout << "* Symmetric distance (expected 2): " << distc << std::endl; + + assert(dista == 1.0); + assert(distb == 2.0); + assert(distc == naive); } template @@ -460,14 +657,16 @@ void test_9(const FunctionWrapper& functor, const bool save = false) { const double dista = functor(mesh1, mesh2); const double distb = functor(mesh2, mesh1); - const double naive = (CGAL::max)(dista, distb); const double distc = functor.symmetric(mesh1, mesh2); - assert(distc == naive); std::cout << "* Hausdorff distance (expected 1): " << dista << std::endl; std::cout << "* HInverted distance (expected 1): " << distb << std::endl; std::cout << "* Symmetric distance (expected 1): " << distc << std::endl; + + assert(dista == 1.0); + assert(distb == 1.0); + assert(distc == naive); } template @@ -527,6 +726,9 @@ void test_one_versus_another( const double distb1 = functor2(mesh1, mesh2); std::cout << "* Hausdorff distance1: " << dista1 << std::endl; std::cout << "* Hausdorff distance2: " << distb1 << std::endl; + + assert(CGAL::abs(dista0 - distb0) < 1e-3); // error bound is 1e-4 + assert(CGAL::abs(dista1 - distb1) < 1e-3); // error bound is 1e-4 } template< @@ -563,6 +765,9 @@ void test_real_meshes( std::cout << std::endl; std::cout << "* Hausdorff distance2 f: " << distb0 << std::endl; std::cout << "* Hausdorff distance2 b: " << distb1 << std::endl; + + assert(CGAL::abs(dista0 - distb0) < 1e-3); // error bound is 1e-4 + assert(CGAL::abs(dista1 - distb1) < 1e-3); // error bound is 1e-4 } template @@ -598,6 +803,10 @@ void test_timings(const std::string filepath, const FunctionWrapper& functor) { std::cout << "* time ab1 naive (sec.): " << timea + timeb << std::endl; std::cout << "* time ab1 optimized (sec.): " << timeab << std::endl; + assert(timea > 0.0); + assert(timeb > 0.0); + assert(timeab < timea + timeb); + PMP::transform(Affine_transformation_3(CGAL::Translation(), Vector_3(FT(0), FT(0), FT(1))), mesh2); @@ -624,9 +833,16 @@ void test_timings(const std::string filepath, const FunctionWrapper& functor) { std::cout << "* time ab2 naive (sec.): " << timea + timeb << std::endl; std::cout << "* time ab2 optimized (sec.): " << timeab << std::endl; + assert(timea > 0.0); + assert(timeb > 0.0); + assert(timeab < timea + timeb); + std::cout << "* dista = " << dista1 << " , " << dista2 << std::endl; std::cout << "* distb = " << distb1 << " , " << distb2 << std::endl; std::cout << "* distab = " << distc1 << " , " << distc2 << std::endl; + + assert(dista1 == distb1 && distb1 == distc1); + assert(dista2 == distb2 && distb2 == distc2); } template @@ -672,10 +888,12 @@ void test_bunny( times.push_back(timer.time()); std::cout << "* distance / Hausdorff / time (sec.) : " << distance << " / " << distc << " / " << times.back() << std::endl; + assert(distc > 0.0); } else { // t is the step where n is the number of steps. + double curr_dist = 1.0; const FT t = FT(1) / static_cast(n); for (int k = n; k >= 0; --k) { auto mesh = mesh2; @@ -693,6 +911,8 @@ void test_bunny( times.push_back(timer.time()); std::cout << "* distance / Hausdorff / time (sec.) " << k << " : " << distance << " / " << distc << " / " << times.back() << std::endl; + assert(distc < curr_dist); + curr_dist = distc; } } @@ -710,6 +930,10 @@ void test_bunny( std::cout << "* avg time: " << avg_time * 1000.0 << std::endl; std::cout << "* min time: " << min_time * 1000.0 << std::endl; std::cout << "* max time: " << max_time * 1000.0 << std::endl; + + assert(min_time <= max_time); + assert(min_time <= avg_time); + assert(avg_time <= max_time); } Triangle_3 get_triangle(const int index, const Surface_mesh& mesh) { @@ -721,6 +945,7 @@ Triangle_3 get_triangle(const int index, const Surface_mesh& mesh) { const auto he = halfedge(face, mesh); const auto vertices = vertices_around_face(he, mesh); + assert(vertices.size() >= 3); auto vit = vertices.begin(); const auto& p0 = mesh.point(*vit); ++vit; const auto& p1 = mesh.point(*vit); ++vit; @@ -744,6 +969,9 @@ void compute_realizing_triangles( std::cout << "* Hausdorff: " << hdist << std::endl; std::cout << "* f1 / f2: " << f1 << " / " << f2 << std::endl; + assert(f1 == 0); + assert(f2 == 0 || f2 == 161); + if (f1 != -1 && save) { const auto triangle = get_triangle(f1, mesh1); Surface_mesh sm1; @@ -864,6 +1092,10 @@ void test_parallel_version( std::cout << "* dista seq = " << dista << std::endl; std::cout << "* distb par = " << distb << std::endl; + + assert(timea > 0.0); + assert(timeb > 0.0); + assert(dista == distb); } #endif // defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) @@ -880,7 +1112,7 @@ void test_early_quit(const std::string filepath) { std::cout << " ---- distance 0.0 = 0.0 ---- " << std::endl; timer.reset(); timer.start(); - assert(!PMP::is_further_than(mesh1, mesh2, 0.0)); + assert(!PMP::is_Hausdorff_distance_larger(mesh1, mesh2, 0.0)); timer.stop(); const double timea = timer.time(); @@ -890,25 +1122,25 @@ void test_early_quit(const std::string filepath) { std::cout << " ---- distance 0.5 < 1.0 ---- " << std::endl; timer.reset(); timer.start(); - assert(!PMP::is_further_than(mesh1, mesh2, 1.0)); + assert(!PMP::is_Hausdorff_distance_larger(mesh1, mesh2, 1.0)); timer.stop(); const double timeb = timer.time(); std::cout << " ---- distance 0.5 < 0.6 ---- " << std::endl; timer.reset(); timer.start(); - assert(!PMP::is_further_than(mesh1, mesh2, 0.6)); + assert(!PMP::is_Hausdorff_distance_larger(mesh1, mesh2, 0.6)); timer.stop(); const double timec = timer.time(); std::cout << " ---- distance 0.5 > 0.4 ---- " << std::endl; timer.reset(); timer.start(); - assert(PMP::is_further_than(mesh1, mesh2, 0.4)); + assert(PMP::is_Hausdorff_distance_larger(mesh1, mesh2, 0.4)); timer.stop(); const double timed = timer.time(); std::cout << " ---- distance 0.5 > 0.0 ---- " << std::endl; timer.reset(); timer.start(); - assert(PMP::is_further_than(mesh1, mesh2, 0.0)); + assert(PMP::is_Hausdorff_distance_larger(mesh1, mesh2, 0.0)); timer.stop(); const double timee = timer.time(); @@ -917,6 +1149,21 @@ void test_early_quit(const std::string filepath) { std::cout << "* timec 0.5 < 0.6 = " << timec << std::endl; std::cout << "* timed 0.5 > 0.4 = " << timed << std::endl; std::cout << "* timee 0.5 > 0.0 = " << timee << std::endl; + + assert(timea > 0.0); + assert(timeb > 0.0); + assert(timec > 0.0); + assert(timed > 0.0); + assert(timee > 0.0); +} + +void run_examples(const double error_bound, const std::string filepath) { + + remeshing_tetrahedon_example(error_bound); + interior_triangle_example(error_bound); + perturbing_surface_mesh_example(filepath, error_bound); + perturbing_polyhedron_mesh_example(filepath, error_bound); + moving_surface_mesh_example(filepath, filepath, 5, error_bound); } int main(int argc, char** argv) { @@ -929,6 +1176,7 @@ int main(int argc, char** argv) { std::cout << std::endl << "* error bound: " << error_bound << std::endl; // std::cout << std::endl << "* number of samples: " << num_samples << std::endl; std::string filepath = (argc > 1 ? argv[1] : "data/blobby.off"); + run_examples(error_bound, filepath); // ------------------------------------------------------------------------ // // Tests. From ad6a7183c5bd7d13f71cae09e0c8d429de7bb2af Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 18 Jun 2021 14:47:32 +0200 Subject: [PATCH 246/349] added missing IO ns --- .../test_hausdorff_bounded_error_distance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 8079da33ace..f7d54f0a9e2 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -102,7 +102,7 @@ void get_meshes( template void save_mesh(const PolygonMesh& mesh, const std::string filepath) { - if (!CGAL::write_PLY(filepath + ".ply", mesh)) { + if (!CGAL::IO::write_PLY(filepath + ".ply", mesh)) { std::cerr << "ERROR: cannot save this file: " << filepath << std::endl; exit(EXIT_FAILURE); } From d37eb48ade3e51c2c1e3451f62a057db6121fcf1 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 18 Jun 2021 14:59:26 +0200 Subject: [PATCH 247/349] using new OFF reader from IO --- .../hausdorff_bounded_error_distance_example.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp index 5ee5f76eae3..fee57a590a3 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include @@ -52,12 +52,10 @@ int main(int argc, char** argv) { std::cout << std::endl << "* moving mesh example:" << std::endl; Surface_mesh surface_mesh; - std::ifstream sm_input(filepath); - sm_input >> surface_mesh; + CGAL::IO::read_OFF(filepath, surface_mesh); Polyhedron polyhedron; - std::ifstream poly_input(filepath); - poly_input >> polyhedron; + CGAL::IO::read_OFF(filepath, polyhedron); PMP::transform(Affine_transformation_3(CGAL::Translation(), Vector_3(FT(0), FT(0), FT(1))), polyhedron); From 610f3750f020e2499b93d976282e5adce8193610 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 18 Jun 2021 15:14:52 +0200 Subject: [PATCH 248/349] backticked tms --- .../Polygon_mesh_processing.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index c7e57087a81..b3c1387a4be 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -958,19 +958,19 @@ with the following code: The function `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` computes an estimate of the Hausdorff distance of two triangle meshes which is -bounded by a user-given error bound. Given two meshes tm1 and tm2, it follows +bounded by a user-given error bound. Given two meshes `tm1` and `tm2`, it follows the procedure given by \cgalCite{tang2009interactive}. Namely, bounded volume hierarchy (BVH) is -built on tm1 and tm2 respectively. The tree on tm1 is used to iterate over all -triangles in tm1. Throughout the traversal, the procedure keeps track of a global +built on `tm1` and `tm2` respectively. The tree on `tm1` is used to iterate over all +triangles in `tm1`. Throughout the traversal, the procedure keeps track of a global lower and upper bound on the Hausdorff distance respectively. For each triangle -t in tm1, by traversing the tree on tm2, it is estimated via the global bounds -whether t can still contribute to the actual Hausdorff distance. From this +`t` in `tm1`, by traversing the tree on `tm2`, it is estimated via the global bounds +whether `t` can still contribute to the actual Hausdorff distance. From this process, a set of candidate triangles is selected. The candidate triangles are subsequently subdivided and for each smaller -triangle, the tree on tm2 is traversed again. This is repeated until the +triangle, the tree on `tm2` is traversed again. This is repeated until the triangle is smaller than the user-given error bound, all vertices of the -triangle are projected onto the same triangle in tm2, or the triangle's upper +triangle are projected onto the same triangle in `tm2`, or the triangle's upper bound is lower than the global lower bound. After creation, the subdivided triangles are added to the list of candidate triangles. Thereby, all candidate triangles are processed until a triangle is found in which the Hausdorff From cd022545b5f09b2dbb43ea2fbd67fe5d85f94fa7 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 18 Jun 2021 15:57:00 +0200 Subject: [PATCH 249/349] missing article --- .../doc/Polygon_mesh_processing/Polygon_mesh_processing.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index b3c1387a4be..37b0ef5f658 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -959,7 +959,7 @@ with the following code: The function `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` computes an estimate of the Hausdorff distance of two triangle meshes which is bounded by a user-given error bound. Given two meshes `tm1` and `tm2`, it follows -the procedure given by \cgalCite{tang2009interactive}. Namely, bounded volume hierarchy (BVH) is +the procedure given by \cgalCite{tang2009interactive}. Namely, a bounded volume hierarchy (BVH) is built on `tm1` and `tm2` respectively. The tree on `tm1` is used to iterate over all triangles in `tm1`. Throughout the traversal, the procedure keeps track of a global lower and upper bound on the Hausdorff distance respectively. For each triangle From 7e039fa21a622552586d03b55f3494909718cb0b Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Mon, 21 Jun 2021 07:07:50 +0200 Subject: [PATCH 250/349] Update Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h Co-authored-by: Laurent Rineau --- .../internal/Triangulation_2_projection_traits_base_3.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h b/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h index bee57e6ba20..5087c9516ae 100644 --- a/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h +++ b/Triangulation_2/include/CGAL/Triangulation_2/internal/Triangulation_2_projection_traits_base_3.h @@ -224,7 +224,6 @@ public: // the intersection of the supporting lines is not inside both segments #ifdef CGAL_T2_PTB_3_DEBUG std::cerr << "intersection not inside\n"; - return boost::none; #endif return boost::none; } From a34debc92bb418c254a15f9f1e683a4a290961e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 23 Jun 2021 22:56:35 +0200 Subject: [PATCH 251/349] Uniformize os/is/s/i stream parameter name in Stream_support/io + remove extra backticks in NP doc --- BGL/include/CGAL/boost/graph/IO/GOCAD.h | 4 +- BGL/include/CGAL/boost/graph/IO/OBJ.h | 2 +- BGL/include/CGAL/boost/graph/IO/OFF.h | 2 +- BGL/include/CGAL/boost/graph/IO/PLY.h | 2 +- BGL/include/CGAL/boost/graph/IO/STL.h | 2 +- BGL/include/CGAL/boost/graph/IO/VTK.h | 2 +- BGL/include/CGAL/boost/graph/IO/WRL.h | 2 +- Point_set_3/include/CGAL/Point_set_3/IO/OFF.h | 2 +- Point_set_3/include/CGAL/Point_set_3/IO/PLY.h | 2 +- Point_set_3/include/CGAL/Point_set_3/IO/XYZ.h | 2 +- .../include/CGAL/IO/write_off_points.h | 2 +- .../include/CGAL/IO/write_ply_points.h | 2 +- .../include/CGAL/IO/write_xyz_points.h | 2 +- Stream_support/include/CGAL/IO/GOCAD.h | 2 +- Stream_support/include/CGAL/IO/OBJ.h | 2 +- Stream_support/include/CGAL/IO/OFF.h | 2 +- Stream_support/include/CGAL/IO/PLY.h | 2 +- Stream_support/include/CGAL/IO/STL.h | 2 +- Stream_support/include/CGAL/IO/VTK.h | 2 +- .../include/CGAL/IO/binary_file_io.h | 28 ++++---- Stream_support/include/CGAL/IO/io.h | 72 +++++++++---------- .../include/CGAL/Surface_mesh/IO/OFF.h | 2 +- .../include/CGAL/Surface_mesh/IO/PLY.h | 2 +- 23 files changed, 72 insertions(+), 72 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/IO/GOCAD.h b/BGL/include/CGAL/boost/graph/IO/GOCAD.h index e3baecc25e3..a3d8b48cf88 100644 --- a/BGL/include/CGAL/boost/graph/IO/GOCAD.h +++ b/BGL/include/CGAL/boost/graph/IO/GOCAD.h @@ -270,7 +270,7 @@ bool read_GOCAD(const std::string& fname, Graph& g, /// \cgalParamNBegin{stream_precision} /// \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} /// \cgalParamType{int} -/// \cgalParamDefault{`the precision of the stream `os``} +/// \cgalParamDefault{the precision of the stream `os`} /// \cgalParamNEnd /// \cgalNamedParamsEnd /// @@ -378,7 +378,7 @@ bool write_GOCAD(std::ostream& os, const char* name, const Graph& g, /// \cgalParamNBegin{stream_precision} /// \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} /// \cgalParamType{int} -/// \cgalParamDefault{`the precision of the stream `os``} +/// \cgalParamDefault{the precision of the stream `os`} /// \cgalParamNEnd /// \cgalNamedParamsEnd /// diff --git a/BGL/include/CGAL/boost/graph/IO/OBJ.h b/BGL/include/CGAL/boost/graph/IO/OBJ.h index b97515bb7b6..ba09a85e6da 100644 --- a/BGL/include/CGAL/boost/graph/IO/OBJ.h +++ b/BGL/include/CGAL/boost/graph/IO/OBJ.h @@ -230,7 +230,7 @@ bool read_OBJ(const std::string& fname, Graph& g, \cgalParamNBegin{stream_precision} \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} - \cgalParamDefault{`the precision of the stream `os``} + \cgalParamDefault{the precision of the stream `os`} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/BGL/include/CGAL/boost/graph/IO/OFF.h b/BGL/include/CGAL/boost/graph/IO/OFF.h index e368a1ab92a..03e7dd1c7dc 100644 --- a/BGL/include/CGAL/boost/graph/IO/OFF.h +++ b/BGL/include/CGAL/boost/graph/IO/OFF.h @@ -392,7 +392,7 @@ bool write_OFF_BGL(std::ostream& os, \cgalParamNBegin{stream_precision} \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} - \cgalParamDefault{`the precision of the stream `os``} + \cgalParamDefault{the precision of the stream `os`} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/BGL/include/CGAL/boost/graph/IO/PLY.h b/BGL/include/CGAL/boost/graph/IO/PLY.h index 881d3f86b0d..dce7685d1c6 100644 --- a/BGL/include/CGAL/boost/graph/IO/PLY.h +++ b/BGL/include/CGAL/boost/graph/IO/PLY.h @@ -310,7 +310,7 @@ bool read_PLY(const std::string& fname, Graph& g, \cgalParamNBegin{stream_precision} \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} - \cgalParamDefault{`the precision of the stream `os``} + \cgalParamDefault{the precision of the stream `os`} \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/BGL/include/CGAL/boost/graph/IO/STL.h b/BGL/include/CGAL/boost/graph/IO/STL.h index 7bce5d9734b..b22ce1c4fef 100644 --- a/BGL/include/CGAL/boost/graph/IO/STL.h +++ b/BGL/include/CGAL/boost/graph/IO/STL.h @@ -230,7 +230,7 @@ bool read_STL(const std::string& fname, Graph& g) { return read_STL(fname, g, pa \cgalParamNBegin{stream_precision} \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} - \cgalParamDefault{`the precision of the stream `os``} + \cgalParamDefault{the precision of the stream `os`} \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/BGL/include/CGAL/boost/graph/IO/VTK.h b/BGL/include/CGAL/boost/graph/IO/VTK.h index fa3446ad28f..89684b6014b 100644 --- a/BGL/include/CGAL/boost/graph/IO/VTK.h +++ b/BGL/include/CGAL/boost/graph/IO/VTK.h @@ -417,7 +417,7 @@ void write_polys_points(std::ostream& os, * \cgalParamNBegin{stream_precision} * \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} * \cgalParamType{int} - * \cgalParamDefault{`the precision of the stream `os``} + * \cgalParamDefault{the precision of the stream `os`} * \cgalParamNEnd * \cgalNamedParamsEnd * diff --git a/BGL/include/CGAL/boost/graph/IO/WRL.h b/BGL/include/CGAL/boost/graph/IO/WRL.h index db2c263b1ad..b149c35c149 100644 --- a/BGL/include/CGAL/boost/graph/IO/WRL.h +++ b/BGL/include/CGAL/boost/graph/IO/WRL.h @@ -61,7 +61,7 @@ namespace IO { \cgalParamNBegin{stream_precision} \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} - \cgalParamDefault{`the precision of the stream `os``} + \cgalParamDefault{the precision of the stream `os`} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/Point_set_3/include/CGAL/Point_set_3/IO/OFF.h b/Point_set_3/include/CGAL/Point_set_3/IO/OFF.h index 44f0c2fb584..873ddf0593f 100644 --- a/Point_set_3/include/CGAL/Point_set_3/IO/OFF.h +++ b/Point_set_3/include/CGAL/Point_set_3/IO/OFF.h @@ -140,7 +140,7 @@ namespace IO { \cgalParamNBegin{stream_precision} \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} - \cgalParamDefault{`the precision of the stream `os``} + \cgalParamDefault{the precision of the stream `os`} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h b/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h index fafccda8376..1dd7488afed 100644 --- a/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h +++ b/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h @@ -458,7 +458,7 @@ namespace IO { \cgalParamNBegin{stream_precision} \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} - \cgalParamDefault{`the precision of the stream `os``} + \cgalParamDefault{the precision of the stream `os`} \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/Point_set_3/include/CGAL/Point_set_3/IO/XYZ.h b/Point_set_3/include/CGAL/Point_set_3/IO/XYZ.h index 33499ce8620..f4d8f98b734 100644 --- a/Point_set_3/include/CGAL/Point_set_3/IO/XYZ.h +++ b/Point_set_3/include/CGAL/Point_set_3/IO/XYZ.h @@ -138,7 +138,7 @@ namespace IO { \cgalParamNBegin{stream_precision} \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} - \cgalParamDefault{`the precision of the stream `os``} + \cgalParamDefault{the precision of the stream `os`} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/Point_set_processing_3/include/CGAL/IO/write_off_points.h b/Point_set_processing_3/include/CGAL/IO/write_off_points.h index 8985e286e39..e9e1737ee38 100644 --- a/Point_set_processing_3/include/CGAL/IO/write_off_points.h +++ b/Point_set_processing_3/include/CGAL/IO/write_off_points.h @@ -126,7 +126,7 @@ namespace IO { \cgalParamNBegin{stream_precision} \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} - \cgalParamDefault{`the precision of the stream `os``} + \cgalParamDefault{the precision of the stream `os`} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/Point_set_processing_3/include/CGAL/IO/write_ply_points.h b/Point_set_processing_3/include/CGAL/IO/write_ply_points.h index 33c1b8da3b5..e14ca846adb 100644 --- a/Point_set_processing_3/include/CGAL/IO/write_ply_points.h +++ b/Point_set_processing_3/include/CGAL/IO/write_ply_points.h @@ -177,7 +177,7 @@ template (s32); } inline void -I_Binary_read_integer32(std::istream& in, std::int32_t& i) { - in.read( (char*)(&i), 4); +I_Binary_read_integer32(std::istream& is, std::int32_t& i) { + is.read( (char*)(&i), 4); } inline void -I_Binary_read_float32(std::istream& in, float& f) { - in.read( (char*)(&f), 4); +I_Binary_read_float32(std::istream& is, float& f) { + is.read( (char*)(&f), 4); } inline void -I_Binary_read_bool(std::istream& in, bool& b) { +I_Binary_read_bool(std::istream& is, bool& b) { char c; - in.read(&c, 1); + is.read(&c, 1); b = (c != 0); } @@ -130,13 +130,13 @@ I_Binary_write_big_endian_float32(std::ostream& out, float f) { } inline void -I_Binary_read_big_endian_integer32(std::istream& in, std::int32_t& i) { - in.read( (char*)(&i), 4); +I_Binary_read_big_endian_integer32(std::istream& is, std::int32_t& i) { + is.read( (char*)(&i), 4); I_swap_to_big_endian( i); } inline void -I_Binary_read_big_endian_float32(std::istream& in, float& f) { - in.read( (char*)(&f), 4); +I_Binary_read_big_endian_float32(std::istream& is, float& f) { + is.read( (char*)(&f), 4); I_swap_to_big_endian( f); } diff --git a/Stream_support/include/CGAL/IO/io.h b/Stream_support/include/CGAL/IO/io.h index 7b103f9b9cf..2676f6ace5f 100644 --- a/Stream_support/include/CGAL/IO/io.h +++ b/Stream_support/include/CGAL/IO/io.h @@ -161,7 +161,7 @@ template< class F > struct Output_rep< Some_type, F > { static const bool is_specialized = true; Output_rep( const Some_type& t ); - std::ostream& operator()( std::ostream& out ) const; + std::ostream& operator()( std::ostream& os ) const; }; \endcode @@ -184,7 +184,7 @@ public: //! initialize with a const reference to \a t. Output_rep( const T& tt) : t(tt) {} //! perform the output, calls \c operator\<\< by default. - std::ostream& operator()( std::ostream& out) const { return (out << t); } + std::ostream& operator()( std::ostream& os) const { return (os << t); } }; /*! @@ -197,7 +197,7 @@ public: The output operator is defined for all classes in the \cgal `Kernel` and for the class `Color` as well. */ template -std::ostream& operator<<( std::ostream& out, Output_rep rep) { return rep( out); } +std::ostream& operator<<( std::ostream& os, Output_rep rep) { return rep(os); } namespace IO { @@ -239,7 +239,7 @@ public: Input_rep( T& tt) : t(tt) {} //! perform the input, calls \c operator\>\> by default. - std::istream& operator()( std::istream& in) const { return (in >> t); } + std::istream& operator()( std::istream& is) const { return (is >> t); } }; #if CGAL_FORCE_IFORMAT_DOUBLE || \ @@ -396,7 +396,7 @@ as `std::cin`, as well as from `std::istringstream` and `std::ifstream`. The input operator is defined for all classes in the \cgal `Kernel`. */ template -std::istream& operator>>( std::istream& in, Input_rep rep) { return rep(in); } +std::istream& operator>>( std::istream& is, Input_rep rep) { return rep(is); } namespace IO { @@ -419,14 +419,14 @@ public: //! initialize with a const reference to \a t. Benchmark_rep( const T& tt) : t(tt) {} //! perform the output, calls \c operator\<\< by default. - std::ostream& operator()( std::ostream& out) const { return out << t; } + std::ostream& operator()( std::ostream& os) const { return os << t; } // static function to get the benchmark name static std::string get_benchmark_name() { return ""; } }; template -std::ostream& operator<<( std::ostream& out, Benchmark_rep rep) { return rep( out); } +std::ostream& operator<<( std::ostream& os, Benchmark_rep rep) { return rep(os); } namespace IO { @@ -450,9 +450,9 @@ returns the printing mode of the %IO stream `s`. \sa `CGAL::IO::is_binary()` \sa `CGAL::IO::is_pretty()` */ -inline Mode get_mode(std::ios& i) +inline Mode get_mode(std::ios& s) { - return static_cast(i.iword(Static::get_mode())); + return static_cast(s.iword(Static::get_mode())); } /*! @@ -470,10 +470,10 @@ Returns the previous mode of `s`. \sa `CGAL::IO::is_binary()` \sa `CGAL::IO::is_pretty()` */ -inline Mode set_ascii_mode(std::ios& i) +inline Mode set_ascii_mode(std::ios& s) { - Mode m = get_mode(i); - i.iword(Static::get_mode()) = ASCII; + Mode m = get_mode(s); + s.iword(Static::get_mode()) = ASCII; return m; } @@ -492,10 +492,10 @@ Returns the previous mode of `s`. \sa `CGAL::IO::is_binary()` \sa `CGAL::IO::is_pretty()` */ -inline Mode set_binary_mode(std::ios& i) +inline Mode set_binary_mode(std::ios& s) { - Mode m = get_mode(i); - i.iword(Static::get_mode()) = BINARY; + Mode m = get_mode(s); + s.iword(Static::get_mode()) = BINARY; return m; } @@ -514,10 +514,10 @@ Returns the previous mode of `s`. \sa `CGAL::IO::is_binary()` \sa `CGAL::IO::is_pretty()` */ -inline Mode set_pretty_mode(std::ios& i) +inline Mode set_pretty_mode(std::ios& s) { - Mode m = get_mode(i); - i.iword(Static::get_mode()) = PRETTY; + Mode m = get_mode(s); + s.iword(Static::get_mode()) = PRETTY; return m; } @@ -535,10 +535,10 @@ sets the printing mode of the %IO stream `s`. \sa `CGAL::IO::is_binary()` \sa `CGAL::IO::is_pretty()` */ -inline Mode set_mode(std::ios& i, Mode m) +inline Mode set_mode(std::ios& s, Mode m) { - Mode old = get_mode(i); - i.iword(Static::get_mode()) = m; + Mode old = get_mode(s); + s.iword(Static::get_mode()) = m; return old; } @@ -556,7 +556,7 @@ checks if the %IO stream `s` is in `PRETTY` mode. \sa `CGAL::IO::is_ascii()` \sa `CGAL::IO::is_binary()` */ -inline bool is_pretty(std::ios& i) { return i.iword(Static::get_mode()) == PRETTY; } +inline bool is_pretty(std::ios& s) { return s.iword(Static::get_mode()) == PRETTY; } /*! \ingroup PkgStreamSupportRef @@ -572,7 +572,7 @@ checks if the %IO stream `s` is in `ASCII` mode. \sa `CGAL::IO::is_binary()` \sa `CGAL::IO::is_pretty()` */ -inline bool is_ascii(std::ios& i) { return i.iword(Static::get_mode()) == ASCII; } +inline bool is_ascii(std::ios& s) { return s.iword(Static::get_mode()) == ASCII; } /*! \ingroup PkgStreamSupportRef @@ -588,7 +588,7 @@ checks if the %IO stream `s` is in `BINARY` mode. \sa `CGAL::IO::is_ascii()` \sa `CGAL::IO::is_pretty()` */ -inline bool is_binary(std::ios& i) { return i.iword(Static::get_mode()) == BINARY; } +inline bool is_binary(std::ios& s) { return s.iword(Static::get_mode()) == BINARY; } } // namespace IO @@ -642,23 +642,23 @@ inline void read(std::istream& is, T& t) namespace IO { -inline std::ostream& operator<<( std::ostream& out, const Color& col) +inline std::ostream& operator<<( std::ostream& os, const Color& col) { - switch(get_mode(out)) + switch(get_mode(os)) { case ASCII : - return out << static_cast(col.red()) << ' ' - << static_cast(col.green()) << ' ' - << static_cast(col.blue()) << ' ' - << static_cast(col.alpha()); + return os << static_cast(col.red()) << ' ' + << static_cast(col.green()) << ' ' + << static_cast(col.blue()) << ' ' + << static_cast(col.alpha()); case BINARY : - out.write(reinterpret_cast(col.to_rgba().data()), 4); - return out; + os.write(reinterpret_cast(col.to_rgba().data()), 4); + return os; default: - return out << "Color(" << static_cast(col.red()) << ", " - << static_cast(col.green()) << ", " - << static_cast(col.blue()) << ", " - << static_cast(col.alpha()) << ")"; + return os << "Color(" << static_cast(col.red()) << ", " + << static_cast(col.green()) << ", " + << static_cast(col.blue()) << ", " + << static_cast(col.alpha()) << ")"; } } diff --git a/Surface_mesh/include/CGAL/Surface_mesh/IO/OFF.h b/Surface_mesh/include/CGAL/Surface_mesh/IO/OFF.h index eea075e92ac..c1988eb2cca 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/IO/OFF.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/IO/OFF.h @@ -580,7 +580,7 @@ bool write_OFF_with_or_without_vnormals(std::ostream& os, /// \cgalParamNBegin{stream_precision} /// \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} /// \cgalParamType{int} -/// \cgalParamDefault{`the precision of the stream `os``} +/// \cgalParamDefault{the precision of the stream `os`} /// \cgalParamNEnd /// \cgalNamedParamsEnd /// diff --git a/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h b/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h index b6196d5908c..773f5d8b26b 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h @@ -902,7 +902,7 @@ namespace IO { /// \cgalParamNBegin{stream_precision} /// \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} /// \cgalParamType{int} -/// \cgalParamDefault{`the precision of the stream `os``} +/// \cgalParamDefault{the precision of the stream `os`} /// \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} /// \cgalParamNEnd /// \cgalNamedParamsEnd From 78ff9185b3c6f14a1983971c810a26de70ce013b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 23 Jun 2021 23:34:14 +0200 Subject: [PATCH 252/349] Harmonize ASCII usage across all packages --- .../Arrangement_on_surface_2.txt | 4 ++-- .../include/CGAL/IO/Arr_text_formatter.h | 6 +++--- .../CGAL/IO/Arr_with_history_text_formatter.h | 2 +- BGL/include/CGAL/boost/graph/IO/PLY.h | 8 ++++---- BGL/include/CGAL/boost/graph/IO/STL.h | 8 ++++---- BGL/include/CGAL/boost/graph/IO/VTK.h | 4 ++-- .../CGAL/boost/graph/IO/polygon_mesh_io.h | 2 +- .../CGAL/General_polygon_2.h | 6 +++--- Bounding_volumes/include/CGAL/Min_annulus_d.h | 2 +- .../CGAL/Min_circle_2/Min_circle_2_adapterC2.h | 2 +- .../CGAL/Min_circle_2/Min_circle_2_adapterH2.h | 2 +- .../CGAL/Min_circle_2/Min_circle_2_impl.h | 2 +- .../Min_circle_2/Optimisation_circle_2_impl.h | 2 +- .../CGAL/Min_ellipse_2/Min_ellipse_2_adapterC2.h | 2 +- .../CGAL/Min_ellipse_2/Min_ellipse_2_adapterH2.h | 2 +- .../CGAL/Min_ellipse_2/Min_ellipse_2_impl.h | 2 +- .../Min_ellipse_2/Optimisation_ellipse_2_impl.h | 2 +- .../CGAL/Min_sphere_d/Min_sphere_d_impl.h | 2 +- CGAL_ImageIO/include/CGAL/ImageIO.h | 2 +- CGAL_ImageIO/include/CGAL/ImageIO/gis.h | 2 +- CGAL_ImageIO/include/CGAL/ImageIO/gis_impl.h | 14 +++++++------- CGAL_ImageIO/include/CGAL/ImageIO/pnm_impl.h | 2 +- .../ETHZ/Random_forest_classifier.h | 2 +- .../include/CGAL/Classification/Evaluation.h | 2 +- .../doc/resources/1.8.13/BaseDoxyfile.in | 1 + .../doc/resources/1.8.14/BaseDoxyfile.in | 3 ++- .../doc/resources/1.8.20/BaseDoxyfile.in | 3 ++- .../doc/scripts/generate_how_to_cite.py | 2 +- Geomview/doc/Geomview/CGAL/IO/Geomview_stream.h | 16 ++++++++-------- .../examples/Kernel_23/MyPointC2_iostream.h | 2 +- Kernel_23/include/CGAL/Circle_2.h | 2 +- Kernel_23/include/CGAL/Direction_2.h | 4 ++-- Kernel_23/include/CGAL/Direction_3.h | 4 ++-- Kernel_23/include/CGAL/Line_2.h | 2 +- Kernel_23/include/CGAL/Plane_3.h | 2 +- Kernel_23/include/CGAL/Point_2.h | 4 ++-- Kernel_23/include/CGAL/Point_3.h | 4 ++-- Kernel_23/include/CGAL/Sphere_3.h | 4 ++-- Kernel_23/include/CGAL/Vector_2.h | 4 ++-- Kernel_23/include/CGAL/Vector_3.h | 4 ++-- Kernel_23/include/CGAL/Weighted_point_2.h | 4 ++-- Kernel_23/include/CGAL/Weighted_point_3.h | 4 ++-- Kernel_d/include/CGAL/Kernel_d/Matrix__.h | 2 +- Kernel_d/include/CGAL/Kernel_d/Pair_d.h | 2 +- Kernel_d/include/CGAL/Kernel_d/Tuple_d.h | 2 +- Kernel_d/include/CGAL/Kernel_d/Vector__.h | 2 +- Mesh_2/doc/Mesh_2/CGAL/IO/write_VTU.h | 2 +- Mesh_3/archive/applications/nb2mesh.c | 2 +- .../include/CGAL/Filtered_extended_homogeneous.h | 4 ++-- .../Nef_3/CGAL/IO/Nef_polyhedron_iostream_3.h | 4 ++-- .../Optimal_transportation_reconstruction_2.txt | 2 +- .../include/interface_test.h | 2 +- .../CGAL/_test_cls_periodic_3_triangulation_3.h | 2 +- Point_set_3/include/CGAL/Point_set_3/IO.h | 8 ++++---- Point_set_3/include/CGAL/Point_set_3/IO/PLY.h | 14 +++++++------- .../Point_set_processing_3.txt | 4 ++-- .../include/CGAL/IO/read_ply_points.h | 2 +- .../include/CGAL/IO/read_points.h | 4 ++-- .../include/CGAL/IO/write_ply_points.h | 6 +++--- .../include/CGAL/IO/write_points.h | 6 +++--- .../include/CGAL/General_polygon_with_holes_2.h | 5 ++--- Polygon/include/CGAL/Polygon_with_holes_2.h | 5 ++--- .../doc/Polyhedron/CGAL/IO/Polyhedron_iostream.h | 6 +++--- .../benchmark/Spatial_searching/binary.cpp | 2 +- .../doc/Stream_lines_2/CGAL/Stream_lines_2.h | 2 +- .../Stream_lines_2/stl_triangular_field.cpp | 2 +- .../File_formats/Supported_file_formats.txt | 14 +++++++------- Stream_support/doc/Stream_support/IOstream.txt | 8 ++++---- .../doc/Stream_support/PackageDescription.txt | 2 +- Stream_support/include/CGAL/IO/PLY.h | 10 +++++----- Stream_support/include/CGAL/IO/STL.h | 10 +++++----- Stream_support/include/CGAL/IO/VTK.h | 4 ++-- Stream_support/include/CGAL/IO/io.h | 10 +++++----- Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h | 2 +- 74 files changed, 153 insertions(+), 152 deletions(-) diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt index 93cf048521b..e1f9a0d89ad 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt @@ -3475,7 +3475,7 @@ This package provides an inserter (the `<<` operator) and an `Arrangement_2` class that inserts and an arrangement object into an output stream and extracts an arrangement object from an input stream respectively. The arrangement is written using a simple -predefined ASCII format that encodes the arrangement topology, as well +predefined \ascii format that encodes the arrangement topology, as well as all geometric entities associated with vertices and edges. The ability to use the input/output operators, requires that the @@ -3560,7 +3560,7 @@ with the basic arrangement structure. The arrangement package supplies an inserter and an extractor for the `Arrangement_with_history_2` class. The arrangement is -represented using a simple predefined ASCII format. An object of the +represented using a simple predefined \ascii format. An object of the `Arrangement_with_history_2` type can be saved and restored, as long as the `Curve_2` type defined by the traits class - as well as the `Point_2` type and the `X_monotone_curve_2` diff --git a/Arrangement_on_surface_2/include/CGAL/IO/Arr_text_formatter.h b/Arrangement_on_surface_2/include/CGAL/IO/Arr_text_formatter.h index a0096d36b76..4bd39b80c49 100644 --- a/Arrangement_on_surface_2/include/CGAL/IO/Arr_text_formatter.h +++ b/Arrangement_on_surface_2/include/CGAL/IO/Arr_text_formatter.h @@ -27,7 +27,7 @@ namespace CGAL { /*! \class - * A class defining a textual (ASCII) input/output format for arrangements + * A class defining a textual (\ascii) input/output format for arrangements * and supports reading and writing an arrangement from or to input/output * streams. */ @@ -489,7 +489,7 @@ protected: }; /*! \class - * A class defining a textual (ASCII) input/output format for arrangements + * A class defining a textual (\ascii) input/output format for arrangements * that store auxiliary dat with their face records, as they are templated * by a face-extended DCEL class. */ @@ -546,7 +546,7 @@ public: }; /*! \class - * A class defining a textual (ASCII) input/output format for arrangements + * A class defining a textual (\ascii) input/output format for arrangements * that store auxiliary dat with all their DCEL records, as they are templated * by a extended DCEL class. */ diff --git a/Arrangement_on_surface_2/include/CGAL/IO/Arr_with_history_text_formatter.h b/Arrangement_on_surface_2/include/CGAL/IO/Arr_with_history_text_formatter.h index 92398665ec7..2244c550660 100644 --- a/Arrangement_on_surface_2/include/CGAL/IO/Arr_with_history_text_formatter.h +++ b/Arrangement_on_surface_2/include/CGAL/IO/Arr_with_history_text_formatter.h @@ -26,7 +26,7 @@ namespace CGAL { /*! \class - * A class defining a textual (ASCII) input/output format for arrangements + * A class defining a textual (\ascii) input/output format for arrangements * with history and supports reading and writing an arrangement from or to * input/output streams. */ diff --git a/BGL/include/CGAL/boost/graph/IO/PLY.h b/BGL/include/CGAL/boost/graph/IO/PLY.h index dce7685d1c6..38af496f723 100644 --- a/BGL/include/CGAL/boost/graph/IO/PLY.h +++ b/BGL/include/CGAL/boost/graph/IO/PLY.h @@ -175,7 +175,7 @@ bool read_PLY(std::istream& is, Graph& g, \cgalNamedParamsBegin \cgalParamNBegin{use_binary_mode} - \cgalParamDescription{indicates whether data should be read in binary (`true`) or in ASCII (`false`)} + \cgalParamDescription{indicates whether data should be read in binary (`true`) or in \ascii (`false`)} \cgalParamType{Boolean} \cgalParamDefault{`true`} \cgalParamNEnd @@ -311,7 +311,7 @@ bool read_PLY(const std::string& fname, Graph& g, \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} \cgalParamDefault{the precision of the stream `os`} - \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} + \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} \cgalParamNEnd \cgalNamedParamsEnd @@ -482,7 +482,7 @@ bool write_PLY(std::ostream& os, const Graph& g, \cgalNamedParamsBegin \cgalParamNBegin{use_binary_mode} - \cgalParamDescription{indicates whether data should be written in binary (`true`) or in ASCII (`false`)} + \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)} \cgalParamType{Boolean} \cgalParamDefault{`true`} \cgalParamNEnd @@ -521,7 +521,7 @@ bool write_PLY(std::ostream& os, const Graph& g, \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} \cgalParamDefault{`6`} - \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} + \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/BGL/include/CGAL/boost/graph/IO/STL.h b/BGL/include/CGAL/boost/graph/IO/STL.h index b22ce1c4fef..11e9ed59ac1 100644 --- a/BGL/include/CGAL/boost/graph/IO/STL.h +++ b/BGL/include/CGAL/boost/graph/IO/STL.h @@ -135,7 +135,7 @@ bool read_STL(std::istream& is, \cgalNamedParamsBegin \cgalParamNBegin{use_binary_mode} - \cgalParamDescription{indicates whether data should be read in binary (`true`) or in ASCII (`false`)} + \cgalParamDescription{indicates whether data should be read in binary (`true`) or in \ascii (`false`)} \cgalParamType{Boolean} \cgalParamDefault{`true`} \cgalParamNEnd @@ -231,7 +231,7 @@ bool read_STL(const std::string& fname, Graph& g) { return read_STL(fname, g, pa \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} \cgalParamDefault{the precision of the stream `os`} - \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} + \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} \cgalParamNEnd \cgalNamedParamsEnd @@ -328,7 +328,7 @@ bool write_STL(std::ostream& os, \cgalNamedParamsBegin \cgalParamNBegin{use_binary_mode} - \cgalParamDescription{indicates whether data should be written in binary (`true`) or in ASCII (`false`)} + \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)} \cgalParamType{Boolean} \cgalParamDefault{`true`} \cgalParamNEnd @@ -346,7 +346,7 @@ bool write_STL(std::ostream& os, \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} \cgalParamDefault{`6`} - \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} + \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/BGL/include/CGAL/boost/graph/IO/VTK.h b/BGL/include/CGAL/boost/graph/IO/VTK.h index 89684b6014b..58cf152f21c 100644 --- a/BGL/include/CGAL/boost/graph/IO/VTK.h +++ b/BGL/include/CGAL/boost/graph/IO/VTK.h @@ -393,7 +393,7 @@ void write_polys_points(std::ostream& os, * * \cgalNamedParamsBegin * \cgalParamNBegin{use_binary_mode} - * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in ASCII (`false`)} + * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)} * \cgalParamType{Boolean} * \cgalParamDefault{`true`} * \cgalParamNEnd @@ -492,7 +492,7 @@ bool write_VTP(std::ostream& os, * * \cgalNamedParamsBegin * \cgalParamNBegin{use_binary_mode} - * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in ASCII (`false`)} + * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)} * \cgalParamType{Boolean} * \cgalParamDefault{`true`} * \cgalParamNEnd diff --git a/BGL/include/CGAL/boost/graph/IO/polygon_mesh_io.h b/BGL/include/CGAL/boost/graph/IO/polygon_mesh_io.h index bd54d53014e..958982f28b0 100644 --- a/BGL/include/CGAL/boost/graph/IO/polygon_mesh_io.h +++ b/BGL/include/CGAL/boost/graph/IO/polygon_mesh_io.h @@ -214,7 +214,7 @@ bool read_polygon_mesh(const std::string& fname, Graph& g) * \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} * \cgalParamType{int} * \cgalParamDefault{`6`} - * \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} + * \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} * \cgalParamNEnd * * \cgalParamNBegin{verbose} diff --git a/Boolean_set_operations_2/doc/Boolean_set_operations_2/CGAL/General_polygon_2.h b/Boolean_set_operations_2/doc/Boolean_set_operations_2/CGAL/General_polygon_2.h index 37b09e10ec0..0fe122e7778 100644 --- a/Boolean_set_operations_2/doc/Boolean_set_operations_2/CGAL/General_polygon_2.h +++ b/Boolean_set_operations_2/doc/Boolean_set_operations_2/CGAL/General_polygon_2.h @@ -84,7 +84,7 @@ Orientation orientation(); /*! This operator imports a general polygon from the input stream `in`. -Both ASCII and binary formats are supported, and the format is automatically detected. +Both \ascii and binary formats are supported, and the format is automatically detected. The format consists of the number of points of the outer boundary followed by the points themselves in counterclockwise order, followed by the number of holes, @@ -100,11 +100,11 @@ std::istream& operator>>(std::istream& in, CGAL::General_polygon_2& P /*! This operator exports a general polygon to the output stream `out`. -An ASCII and a binary format exist. The format can be selected with +An \ascii and a binary format exist. The format can be selected with the \cgal modifiers for streams, `set_ascii_mode` and `set_binary_mode` respectively. The modifier `set_pretty_mode` can be used to allow for (a few) structuring comments in the output. Otherwise, the output would -be free of comments. The default for writing is ASCII without +be free of comments. The default for writing is \ascii without comments. The number of curves of the outer boundary is exported followed by the diff --git a/Bounding_volumes/include/CGAL/Min_annulus_d.h b/Bounding_volumes/include/CGAL/Min_annulus_d.h index 4f8e1d3a784..8dae7e73d26 100644 --- a/Bounding_volumes/include/CGAL/Min_annulus_d.h +++ b/Bounding_volumes/include/CGAL/Min_annulus_d.h @@ -847,7 +847,7 @@ operator >> ( std::istream& is, CGAL::Min_annulus_d& min_annulus) case CGAL::IO::PRETTY: cerr << endl; - cerr << "Stream must be in ascii or binary mode" << endl; + cerr << "Stream must be in ASCII or binary mode" << endl; break; case CGAL::IO::ASCII: diff --git a/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_adapterC2.h b/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_adapterC2.h index 3f28aef6732..47d93bb8288 100644 --- a/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_adapterC2.h +++ b/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_adapterC2.h @@ -309,7 +309,7 @@ operator >> ( std::istream& is, case CGAL::IO::PRETTY: std::cerr << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; case CGAL::IO::ASCII: diff --git a/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_adapterH2.h b/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_adapterH2.h index 74afdd668d6..43b90b757d0 100644 --- a/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_adapterH2.h +++ b/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_adapterH2.h @@ -348,7 +348,7 @@ operator >> ( std::istream& is, case CGAL::IO::PRETTY: std::cerr << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; case CGAL::IO::ASCII: diff --git a/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_impl.h b/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_impl.h index f0a8cc7f072..ccb2d79af91 100644 --- a/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_impl.h +++ b/Bounding_volumes/include/CGAL/Min_circle_2/Min_circle_2_impl.h @@ -77,7 +77,7 @@ operator >> ( std::istream& is, CGAL::Min_circle_2& min_circle) case CGAL::IO::PRETTY: cerr << endl; - cerr << "Stream must be in ascii or binary mode" << endl; + cerr << "Stream must be in ASCII or binary mode" << endl; break; case CGAL::IO::ASCII: diff --git a/Bounding_volumes/include/CGAL/Min_circle_2/Optimisation_circle_2_impl.h b/Bounding_volumes/include/CGAL/Min_circle_2/Optimisation_circle_2_impl.h index 55057c6ac37..33cf439dd26 100644 --- a/Bounding_volumes/include/CGAL/Min_circle_2/Optimisation_circle_2_impl.h +++ b/Bounding_volumes/include/CGAL/Min_circle_2/Optimisation_circle_2_impl.h @@ -60,7 +60,7 @@ operator >> ( std::istream& is, CGAL::Optimisation_circle_2& c) case CGAL::IO::PRETTY: std::cerr << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; case CGAL::IO::ASCII: { diff --git a/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_adapterC2.h b/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_adapterC2.h index b50c7e45fed..e2fad6bc1bb 100644 --- a/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_adapterC2.h +++ b/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_adapterC2.h @@ -378,7 +378,7 @@ operator >> ( std::istream& is, case CGAL::IO::PRETTY: std::cerr << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; case CGAL::IO::ASCII: diff --git a/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_adapterH2.h b/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_adapterH2.h index 23454106cfc..f971e915fc4 100644 --- a/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_adapterH2.h +++ b/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_adapterH2.h @@ -386,7 +386,7 @@ operator >> ( std::istream& is, case CGAL::IO::PRETTY: std::cerr << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; case CGAL::IO::ASCII: diff --git a/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_impl.h b/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_impl.h index e28a847f1c5..708c6644d9c 100644 --- a/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_impl.h +++ b/Bounding_volumes/include/CGAL/Min_ellipse_2/Min_ellipse_2_impl.h @@ -77,7 +77,7 @@ operator >> ( std::istream& is, CGAL::Min_ellipse_2& min_ellipse) case CGAL::IO::PRETTY: cerr << endl; - cerr << "Stream must be in ascii or binary mode" << endl; + cerr << "Stream must be in ASCII or binary mode" << endl; break; case CGAL::IO::ASCII: diff --git a/Bounding_volumes/include/CGAL/Min_ellipse_2/Optimisation_ellipse_2_impl.h b/Bounding_volumes/include/CGAL/Min_ellipse_2/Optimisation_ellipse_2_impl.h index 47b42ef90d8..f2b1d2e8e87 100644 --- a/Bounding_volumes/include/CGAL/Min_ellipse_2/Optimisation_ellipse_2_impl.h +++ b/Bounding_volumes/include/CGAL/Min_ellipse_2/Optimisation_ellipse_2_impl.h @@ -79,7 +79,7 @@ operator >> ( std::istream& is, CGAL::Optimisation_ellipse_2& e) case CGAL::IO::PRETTY: std::cerr << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; case CGAL::IO::ASCII: diff --git a/Bounding_volumes/include/CGAL/Min_sphere_d/Min_sphere_d_impl.h b/Bounding_volumes/include/CGAL/Min_sphere_d/Min_sphere_d_impl.h index 684d1fb7e0b..0415adbf47f 100644 --- a/Bounding_volumes/include/CGAL/Min_sphere_d/Min_sphere_d_impl.h +++ b/Bounding_volumes/include/CGAL/Min_sphere_d/Min_sphere_d_impl.h @@ -77,7 +77,7 @@ operator >> ( std::istream& is, Min_sphere_d& min_sphere) case IO::PRETTY: std::cerr << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; case IO::ASCII: diff --git a/CGAL_ImageIO/include/CGAL/ImageIO.h b/CGAL_ImageIO/include/CGAL/ImageIO.h index a1295258725..9c6b4281cc6 100644 --- a/CGAL_ImageIO/include/CGAL/ImageIO.h +++ b/CGAL_ImageIO/include/CGAL/ImageIO.h @@ -93,7 +93,7 @@ typedef enum { typedef enum { /** data are binary */ DM_BINARY, - /** data are ascii */ + /** data are \ascii */ DM_ASCII } DATA_MODE; diff --git a/CGAL_ImageIO/include/CGAL/ImageIO/gis.h b/CGAL_ImageIO/include/CGAL/ImageIO/gis.h index b3fc5254993..9b29a1548dd 100644 --- a/CGAL_ImageIO/include/CGAL/ImageIO/gis.h +++ b/CGAL_ImageIO/include/CGAL/ImageIO/gis.h @@ -88,7 +88,7 @@ exemple : -a age (entier) -s sexe (1/2) -l lateralite - -txt texte libre (ascii) + -txt texte libre (ASCII) -endtxt (fin du texte) diff --git a/CGAL_ImageIO/include/CGAL/ImageIO/gis_impl.h b/CGAL_ImageIO/include/CGAL/ImageIO/gis_impl.h index 95f61aeb996..6bacde694e1 100644 --- a/CGAL_ImageIO/include/CGAL/ImageIO/gis_impl.h +++ b/CGAL_ImageIO/include/CGAL/ImageIO/gis_impl.h @@ -109,19 +109,19 @@ int writeGis( char *name, _image* im) { switch( im->wordKind ) { default : - fprintf(stderr, "writeGis: such word kind not handled in ascii mode for file \'%s\'\n", outputName); + fprintf(stderr, "writeGis: such word kind not handled in ASCII mode for file \'%s\'\n", outputName); if ( outputName != nullptr ) ImageIO_free( outputName ); return( -3 ); case WK_FIXED : switch ( im->wdim ) { default : - fprintf(stderr, "writeGis: such word dim not handled in ascii mode for file \'%s\'\n", outputName); + fprintf(stderr, "writeGis: such word dim not handled in ASCII mode for file \'%s\'\n", outputName); if ( outputName != nullptr ) ImageIO_free( outputName ); return( -3 ); case 1 : switch ( im->sign ) { default : - fprintf(stderr, "writeGis: such sign not handled in ascii mode for file \'%s\'\n", outputName); + fprintf(stderr, "writeGis: such sign not handled in ASCII mode for file \'%s\'\n", outputName); if ( outputName != nullptr ) ImageIO_free( outputName ); return( -3 ); case SGN_UNSIGNED : @@ -169,7 +169,7 @@ int writeGis( char *name, _image* im) { case 2 : switch ( im->sign ) { default : - fprintf(stderr, "writeGis: such sign not handled in ascii mode for file \'%s\'\n", outputName); + fprintf(stderr, "writeGis: such sign not handled in ASCII mode for file \'%s\'\n", outputName); if ( outputName != nullptr ) ImageIO_free( outputName ); return( -3 ); case SGN_UNSIGNED : @@ -502,7 +502,7 @@ int readGisHeader( const char* name,_image* im) - /* read data if ascii + /* read data if ASCII only U8 and S8 */ if ( im->dataMode == DM_ASCII ) { @@ -512,7 +512,7 @@ int readGisHeader( const char* name,_image* im) int ret, iv=0; if ( im->wdim != 1 || im->wordKind != WK_FIXED ) { - fprintf(stderr, "readGisHeader: error: unable to read such ascii type\n" ); + fprintf(stderr, "readGisHeader: error: unable to read such ASCII type\n" ); return -1; } @@ -550,7 +550,7 @@ int readGisHeader( const char* name,_image* im) } if ( ret != 1 ) { - fprintf( stderr, "readGisHeader: error in reading ascii data\n" ); + fprintf( stderr, "readGisHeader: error in reading ASCII data\n" ); ImageIO_free( im->data ); im->data = nullptr; ImageIO_free( str ); return -1; diff --git a/CGAL_ImageIO/include/CGAL/ImageIO/pnm_impl.h b/CGAL_ImageIO/include/CGAL/ImageIO/pnm_impl.h index 2fd559ed58f..1298dd4e84a 100644 --- a/CGAL_ImageIO/include/CGAL/ImageIO/pnm_impl.h +++ b/CGAL_ImageIO/include/CGAL/ImageIO/pnm_impl.h @@ -366,7 +366,7 @@ int readPgmAsciiImage(const char *name,_image *im) switch ( im->wordKind ) { case WK_FIXED : if ( sscanf( tmp, "%d", &iv ) != 1 ) { - fprintf( stderr, "readAsciiPgmImage: error in reading ascii data\n" ); + fprintf( stderr, "readAsciiPgmImage: error in reading ASCII data\n" ); ImageIO_free( im->data ); im->data = nullptr; return 0; } diff --git a/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h b/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h index 5c71cff0d43..fbf3b43a4bc 100644 --- a/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h +++ b/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h @@ -324,7 +324,7 @@ public: /// @{ /*! - \brief converts a deprecated configuration (in compressed ASCII + \brief converts a deprecated configuration (in compressed \ascii format) to a new configuration (in binary format). The input file should be a GZIP container written by the diff --git a/Classification/include/CGAL/Classification/Evaluation.h b/Classification/include/CGAL/Classification/Evaluation.h index afdde15e216..29109f7ebf4 100644 --- a/Classification/include/CGAL/Classification/Evaluation.h +++ b/Classification/include/CGAL/Classification/Evaluation.h @@ -333,7 +333,7 @@ public: /// @{ /*! - \brief outputs the evaluation in a simple ASCII format to the stream `os`. + \brief outputs the evaluation in a simple \ascii format to the stream `os`. */ friend std::ostream& operator<< (std::ostream& os, const Evaluation& evaluation) { diff --git a/Documentation/doc/resources/1.8.13/BaseDoxyfile.in b/Documentation/doc/resources/1.8.13/BaseDoxyfile.in index 90cb15aabb7..10a57f45443 100644 --- a/Documentation/doc/resources/1.8.13/BaseDoxyfile.in +++ b/Documentation/doc/resources/1.8.13/BaseDoxyfile.in @@ -237,6 +237,7 @@ ALIASES = "cgal=%CGAL" \ "iso=ISO" \ "lisp=Lisp" \ "ieee=IEEE" \ + "ascii=ASCII" \ "exacus=Exacus" \ "mpir=MPIR" \ "mpfr=MPFR" \ diff --git a/Documentation/doc/resources/1.8.14/BaseDoxyfile.in b/Documentation/doc/resources/1.8.14/BaseDoxyfile.in index 96fd516d1ca..e52f0092d91 100644 --- a/Documentation/doc/resources/1.8.14/BaseDoxyfile.in +++ b/Documentation/doc/resources/1.8.14/BaseDoxyfile.in @@ -235,10 +235,11 @@ ALIASES = "cgal=%CGAL" \ "stl=STL" \ "gmp=GMP" \ "gmpxx=GMPXX" \ - "exacus=Exacus" \ "iso=ISO" \ "lisp=Lisp" \ "ieee=IEEE" \ + "ascii=ASCII" \ + "exacus=Exacus" \ "mpir=MPIR" \ "mpfr=MPFR" \ "leda=LEDA" \ diff --git a/Documentation/doc/resources/1.8.20/BaseDoxyfile.in b/Documentation/doc/resources/1.8.20/BaseDoxyfile.in index afb52c9c5af..2e9db38956c 100644 --- a/Documentation/doc/resources/1.8.20/BaseDoxyfile.in +++ b/Documentation/doc/resources/1.8.20/BaseDoxyfile.in @@ -257,10 +257,11 @@ ALIASES = "cgal=%CGAL" \ "stl=STL" \ "gmp=GMP" \ "gmpxx=GMPXX" \ - "exacus=Exacus" \ "iso=ISO" \ "lisp=Lisp" \ "ieee=IEEE" \ + "ascii=ASCII" \ + "exacus=Exacus" \ "mpir=MPIR" \ "mpfr=MPFR" \ "leda=LEDA" \ diff --git a/Documentation/doc/scripts/generate_how_to_cite.py b/Documentation/doc/scripts/generate_how_to_cite.py index 6d6aada97c1..0f02a1a8500 100644 --- a/Documentation/doc/scripts/generate_how_to_cite.py +++ b/Documentation/doc/scripts/generate_how_to_cite.py @@ -161,7 +161,7 @@ def protect_accentuated_letters(authors): try: res.encode('ascii') except UnicodeEncodeError: - stderr.write("WARNING: a non ascii character has been found in author string for bibtex (probably a non-handled accentuated letter)." + stderr.write("WARNING: a non-ASCII character has been found in author string for bibtex (probably a non-handled accentuated letter)." "Check the new package added and update the function protect_accentuated_letters in Documentation/scripts/generate_how_to_cite.py\n\n") return res diff --git a/Geomview/doc/Geomview/CGAL/IO/Geomview_stream.h b/Geomview/doc/Geomview/CGAL/IO/Geomview_stream.h index 8420d438d25..27f91c6d009 100644 --- a/Geomview/doc/Geomview/CGAL/IO/Geomview_stream.h +++ b/Geomview/doc/Geomview/CGAL/IO/Geomview_stream.h @@ -152,33 +152,33 @@ public: /*! Inserts `i` into the stream. Puts whitespace around if the - stream is in ascii mode. + stream is in \ascii mode. */ Geomview_stream& operator<<(int i); /*! Inserts `i` into the stream. Puts whitespace around if the - stream is in ascii mode. + stream is in \ascii mode. */ Geomview_stream& operator<<(unsigned int i); /*! Inserts `i` into the stream. Puts whitespace around if the - stream is in ascii mode. Currently implemented by converting to int, so it + stream is in \ascii mode. Currently implemented by converting to int, so it can be truncated on 64 bit platforms. */ Geomview_stream& operator<<(long i); /*! Inserts `i` into the stream. Puts whitespace around if the - stream is in ascii mode. Currently implemented by converting to unsigned int, + stream is in \ascii mode. Currently implemented by converting to unsigned int, so it can be truncated on 64 bit platforms. */ Geomview_stream& operator<<(unsigned long i); /*! Inserts double `d` into the stream. Puts whitespace around if the - stream is in ascii mode. + stream is in \ascii mode. */ Geomview_stream& operator<<(double d); @@ -196,7 +196,7 @@ public: /*! Sets raw mode. In raw mode, kernel points are output without headers and - footers, just the coordinates (in binary or ascii mode). This allows the + footers, just the coordinates (in binary or \ascii mode). This allows the implementation of the stream functions for other objects to re-use the code for points internally, by temporary saving the raw mode to true, and restoring it after. @@ -227,7 +227,7 @@ public: bool set_binary_mode(bool b = true); /*! - Sets whether we are in ascii mode. + Sets whether we are in \ascii mode. */ bool set_ascii_mode(bool b = true); @@ -237,7 +237,7 @@ public: bool get_binary_mode(); /*! - Returns `true` iff `gs` is in ascii mode. + Returns `true` iff `gs` is in \ascii mode. */ bool get_ascii_mode(); diff --git a/Kernel_23/examples/Kernel_23/MyPointC2_iostream.h b/Kernel_23/examples/Kernel_23/MyPointC2_iostream.h index 76473c6264c..dd3dbf49ca7 100644 --- a/Kernel_23/examples/Kernel_23/MyPointC2_iostream.h +++ b/Kernel_23/examples/Kernel_23/MyPointC2_iostream.h @@ -35,7 +35,7 @@ operator>>(std::istream &is, MyPointC2 &p) break; default: std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) { diff --git a/Kernel_23/include/CGAL/Circle_2.h b/Kernel_23/include/CGAL/Circle_2.h index a94c4f2f598..8abf760e8d8 100644 --- a/Kernel_23/include/CGAL/Circle_2.h +++ b/Kernel_23/include/CGAL/Circle_2.h @@ -276,7 +276,7 @@ extract(std::istream& is, Circle_2& c) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) diff --git a/Kernel_23/include/CGAL/Direction_2.h b/Kernel_23/include/CGAL/Direction_2.h index 9d512db64de..e5b87eaad4d 100644 --- a/Kernel_23/include/CGAL/Direction_2.h +++ b/Kernel_23/include/CGAL/Direction_2.h @@ -233,7 +233,7 @@ extract(std::istream& is, Direction_2& d, const Cartesian_tag&) break; default: is.setstate(std::ios::failbit); - std::cerr << std::endl << "Stream must be in ascii or binary mode" + std::cerr << std::endl << "Stream must be in ASCII or binary mode" << std::endl; break; } @@ -259,7 +259,7 @@ extract(std::istream& is, Direction_2& d, const Homogeneous_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } d = Direction_2(x, y); diff --git a/Kernel_23/include/CGAL/Direction_3.h b/Kernel_23/include/CGAL/Direction_3.h index aedb284da3f..d7268f79645 100644 --- a/Kernel_23/include/CGAL/Direction_3.h +++ b/Kernel_23/include/CGAL/Direction_3.h @@ -192,7 +192,7 @@ extract(std::istream& is, Direction_3& d, const Cartesian_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) @@ -218,7 +218,7 @@ extract(std::istream& is, Direction_3& d, const Homogeneous_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) diff --git a/Kernel_23/include/CGAL/Line_2.h b/Kernel_23/include/CGAL/Line_2.h index 605193d46c7..9fe90a50231 100644 --- a/Kernel_23/include/CGAL/Line_2.h +++ b/Kernel_23/include/CGAL/Line_2.h @@ -279,7 +279,7 @@ extract(std::istream& is, Line_2& l) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) diff --git a/Kernel_23/include/CGAL/Plane_3.h b/Kernel_23/include/CGAL/Plane_3.h index 058c96b919e..c13d57d3a05 100644 --- a/Kernel_23/include/CGAL/Plane_3.h +++ b/Kernel_23/include/CGAL/Plane_3.h @@ -262,7 +262,7 @@ operator>>(std::istream &is, Plane_3 &p) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) diff --git a/Kernel_23/include/CGAL/Point_2.h b/Kernel_23/include/CGAL/Point_2.h index 297817303ee..ac7f41cd637 100644 --- a/Kernel_23/include/CGAL/Point_2.h +++ b/Kernel_23/include/CGAL/Point_2.h @@ -246,7 +246,7 @@ extract(std::istream& is, Point_2& p, const Cartesian_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) @@ -273,7 +273,7 @@ extract(std::istream& is, Point_2& p, const Homogeneous_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) diff --git a/Kernel_23/include/CGAL/Point_3.h b/Kernel_23/include/CGAL/Point_3.h index 77858d83689..7d37a288313 100644 --- a/Kernel_23/include/CGAL/Point_3.h +++ b/Kernel_23/include/CGAL/Point_3.h @@ -277,7 +277,7 @@ extract(std::istream& is, Point_3& p, const Cartesian_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) @@ -305,7 +305,7 @@ extract(std::istream& is, Point_3& p, const Homogeneous_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) diff --git a/Kernel_23/include/CGAL/Sphere_3.h b/Kernel_23/include/CGAL/Sphere_3.h index 59f3d142cd1..5f2987c2cc6 100644 --- a/Kernel_23/include/CGAL/Sphere_3.h +++ b/Kernel_23/include/CGAL/Sphere_3.h @@ -295,7 +295,7 @@ extract(std::istream& is, Sphere_3& c, const Cartesian_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) @@ -323,7 +323,7 @@ extract(std::istream& is, Sphere_3& c, const Homogeneous_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) diff --git a/Kernel_23/include/CGAL/Vector_2.h b/Kernel_23/include/CGAL/Vector_2.h index bc8e6a72a03..c86a92dfca4 100644 --- a/Kernel_23/include/CGAL/Vector_2.h +++ b/Kernel_23/include/CGAL/Vector_2.h @@ -347,7 +347,7 @@ extract(std::istream& is, Vector_2& v, const Cartesian_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) @@ -374,7 +374,7 @@ extract(std::istream& is, Vector_2& v, const Homogeneous_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } v = Vector_2(hx, hy, hw); diff --git a/Kernel_23/include/CGAL/Vector_3.h b/Kernel_23/include/CGAL/Vector_3.h index 75e071c0a7c..ae59f074c98 100644 --- a/Kernel_23/include/CGAL/Vector_3.h +++ b/Kernel_23/include/CGAL/Vector_3.h @@ -328,7 +328,7 @@ extract(std::istream& is, Vector_3& v, const Cartesian_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) @@ -355,7 +355,7 @@ extract(std::istream& is, Vector_3& v, const Homogeneous_tag&) default: is.setstate(std::ios::failbit); std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) diff --git a/Kernel_23/include/CGAL/Weighted_point_2.h b/Kernel_23/include/CGAL/Weighted_point_2.h index 006fbe8cbc0..3c090e5a00d 100644 --- a/Kernel_23/include/CGAL/Weighted_point_2.h +++ b/Kernel_23/include/CGAL/Weighted_point_2.h @@ -294,7 +294,7 @@ extract(std::istream& is, Weighted_point_2& p, const Cartesian_tag&) break; default: std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) @@ -322,7 +322,7 @@ extract(std::istream& is, Weighted_point_2& p, const Homogeneous_tag&) break; default: std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) diff --git a/Kernel_23/include/CGAL/Weighted_point_3.h b/Kernel_23/include/CGAL/Weighted_point_3.h index 25e2eeaa62e..66853dea7d4 100644 --- a/Kernel_23/include/CGAL/Weighted_point_3.h +++ b/Kernel_23/include/CGAL/Weighted_point_3.h @@ -315,7 +315,7 @@ extract(std::istream& is, Weighted_point_3& p, const Cartesian_tag&) break; default: std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) @@ -344,7 +344,7 @@ extract(std::istream& is, Weighted_point_3& p, const Homogeneous_tag&) break; default: std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } if (is) diff --git a/Kernel_d/include/CGAL/Kernel_d/Matrix__.h b/Kernel_d/include/CGAL/Kernel_d/Matrix__.h index 779137a2ccc..f0702737ae9 100644 --- a/Kernel_d/include/CGAL/Kernel_d/Matrix__.h +++ b/Kernel_d/include/CGAL/Kernel_d/Matrix__.h @@ -804,7 +804,7 @@ std::istream& operator>>(std::istream& is, Matrix_& M) is >> M(i/rdim,i%cdim); break; default: - std::cerr<<"\nStream must be in ascii or binary mode"<::read(std::istream& is) CGAL::read(is, d); v = Vector(d); while (i < d) { CGAL::read(is, v[i]); ++i; } break; default: - CGAL_error_msg("\nStream must be in ascii or binary mode\n"); + CGAL_error_msg("\nStream must be in ASCII or binary mode\n"); } } diff --git a/Kernel_d/include/CGAL/Kernel_d/Vector__.h b/Kernel_d/include/CGAL/Kernel_d/Vector__.h index efeb82ad8e1..6550c08ca38 100644 --- a/Kernel_d/include/CGAL/Kernel_d/Vector__.h +++ b/Kernel_d/include/CGAL/Kernel_d/Vector__.h @@ -444,7 +444,7 @@ std::istream& operator>>(std::istream& is, Vector_& v) } break; default: - std::cerr<<"\nStream must be in ascii or binary mode"< void write_VTU(std::ostream& os, diff --git a/Mesh_3/archive/applications/nb2mesh.c b/Mesh_3/archive/applications/nb2mesh.c index b53d962e765..2648471a47f 100644 --- a/Mesh_3/archive/applications/nb2mesh.c +++ b/Mesh_3/archive/applications/nb2mesh.c @@ -408,7 +408,7 @@ int loadNoboite(char *name) { fread(&no,sizeof(int),1,in); } - /* read ascii file */ + /* read ASCII file */ else { fscanf(in,"%d %d %d %d %d",&ne,&np,&npfixe,&icube,&npbli); fscanf(in,"%d %d %d %d",&nbele,&loele,&nbelef,&loelef); diff --git a/Nef_2/include/CGAL/Filtered_extended_homogeneous.h b/Nef_2/include/CGAL/Filtered_extended_homogeneous.h index f1d2ae85290..5997110aebf 100644 --- a/Nef_2/include/CGAL/Filtered_extended_homogeneous.h +++ b/Nef_2/include/CGAL/Filtered_extended_homogeneous.h @@ -164,7 +164,7 @@ std::istream& operator>>(std::istream& is, SPolynomial& p) case CGAL::IO::BINARY : CGAL::read(is,m);CGAL::read(is,n);break; default: - CGAL_error_msg("\nStream must be in ascii or binary mode\n"); + CGAL_error_msg("\nStream must be in ASCII or binary mode\n"); break; } return is; @@ -333,7 +333,7 @@ std::istream& operator>>(std::istream& is, Extended_point& p) case CGAL::IO::BINARY : CGAL::read(is,x);CGAL::read(is,y);CGAL::read(is,w); break; default: - CGAL_error_msg("\nStream must be in ascii or binary mode\n"); + CGAL_error_msg("\nStream must be in ASCII or binary mode\n"); break; } p = Extended_point(x,y,w); diff --git a/Nef_3/doc/Nef_3/CGAL/IO/Nef_polyhedron_iostream_3.h b/Nef_3/doc/Nef_3/CGAL/IO/Nef_polyhedron_iostream_3.h index b8f12487b88..a8264515e18 100644 --- a/Nef_3/doc/Nef_3/CGAL/IO/Nef_polyhedron_iostream_3.h +++ b/Nef_3/doc/Nef_3/CGAL/IO/Nef_polyhedron_iostream_3.h @@ -32,8 +32,8 @@ using a proprietary file format. It includes the complete incidence structure, the geometric data, and the marks of each item. Using \cgal stream modifiers the following output formats can be -chosen: ASCII (`set_ascii_mode()`), binary (`set_binary_mode()`) or -pretty (`set_pretty_mode()`). The mandatory format is the ASCII +chosen: \ascii (`set_ascii_mode()`), binary (`set_binary_mode()`) or +pretty (`set_pretty_mode()`). The mandatory format is the \ascii format. It is recommended to use this format for file input and output. diff --git a/Optimal_transportation_reconstruction_2/doc/Optimal_transportation_reconstruction_2/Optimal_transportation_reconstruction_2.txt b/Optimal_transportation_reconstruction_2/doc/Optimal_transportation_reconstruction_2/Optimal_transportation_reconstruction_2.txt index 692f7a379f0..35e83175200 100644 --- a/Optimal_transportation_reconstruction_2/doc/Optimal_transportation_reconstruction_2/Optimal_transportation_reconstruction_2.txt +++ b/Optimal_transportation_reconstruction_2/doc/Optimal_transportation_reconstruction_2/Optimal_transportation_reconstruction_2.txt @@ -53,7 +53,7 @@ The output of the reconstruction can be obtained in two ways: either as a sequen \cgalExample{Optimal_transportation_reconstruction_2/otr2_indexed_output_example.cpp} \subsection Optimal_transportation_reconstruction_2Mass_example Example with Mass Attributes -The following example first reads a set of input points and masses from an ASCII file. Using two property maps, the points and their initial mass are passed to the Optimal_transportation_reconstruction_2 object. After initialization 100 iterations of the reconstruction process are performed, then the segments and isolated points of the reconstructed shape are extracted and printed to the console. +The following example first reads a set of input points and masses from an \ascii file. Using two property maps, the points and their initial mass are passed to the Optimal_transportation_reconstruction_2 object. After initialization 100 iterations of the reconstruction process are performed, then the segments and isolated points of the reconstructed shape are extracted and printed to the console. \cgalExample{Optimal_transportation_reconstruction_2/otr2_mass_example.cpp} diff --git a/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/include/interface_test.h b/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/include/interface_test.h index 30cae39bae1..9e91d900d03 100644 --- a/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/include/interface_test.h +++ b/Periodic_2_triangulation_2/test/Periodic_2_triangulation_2/include/interface_test.h @@ -488,7 +488,7 @@ template void test_io(T &pt1, bool ex) { std::cout << "I/O" << std::endl; - std::cout << " ascii" << std::endl; + std::cout << " ASCII" << std::endl; std::stringstream ss1; ss1 << pt1; diff --git a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_3.h b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_3.h index ddac2399a7c..0cb56c38824 100644 --- a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_3.h +++ b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_3.h @@ -636,7 +636,7 @@ _test_cls_periodic_3_triangulation_3(const PeriodicTriangulation &, if(test_input_ouput) { std::cout << "I/O" << std::endl; - std::cout << " ascii" << std::endl; + std::cout << " ASCII" << std::endl; std::stringstream ss1; std::stringstream ss3; diff --git a/Point_set_3/include/CGAL/Point_set_3/IO.h b/Point_set_3/include/CGAL/Point_set_3/IO.h index ba6c41ceaa7..5baf100079a 100644 --- a/Point_set_3/include/CGAL/Point_set_3/IO.h +++ b/Point_set_3/include/CGAL/Point_set_3/IO.h @@ -113,11 +113,11 @@ namespace IO { \cgalNamedParamsBegin \cgalParamNBegin{use_binary_mode} - \cgalParamDescription{indicates whether data should be read in binary (`true`) or in ASCII (`false`)} + \cgalParamDescription{indicates whether data should be read in binary (`true`) or in \ascii (`false`)} \cgalParamType{Boolean} \cgalParamDefault{`true`} \cgalParamExtra{This parameter is only relevant for `PLY` writing: the `OFF` and `XYZ` formats - are always ASCII, and the `LAS` format is always binary.} + are always \ascii, and the `LAS` format is always binary.} \cgalParamNEnd \cgalNamedParamsEnd @@ -207,11 +207,11 @@ namespace IO { \cgalNamedParamsBegin \cgalParamNBegin{use_binary_mode} - \cgalParamDescription{indicates whether data should be written in binary (`true`) or in ASCII (`false`)} + \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)} \cgalParamType{Boolean} \cgalParamDefault{`true`} \cgalParamExtra{This parameter is only relevant for `PLY` writing: the `OFF` and `XYZ` formats - are always ASCII, and the `LAS` format is always binary.} + are always \ascii, and the `LAS` format is always binary.} \cgalParamNEnd \cgalParamNBegin{stream_precision} diff --git a/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h b/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h index 1dd7488afed..dd96c762556 100644 --- a/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h +++ b/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h @@ -221,7 +221,7 @@ public: /*! \ingroup PkgPointSet3IOPLY - \brief reads a point set with properties from an input stream in ASCII or Binary \ref IOStreamPLY. + \brief reads a point set with properties from an input stream in \ascii or binary \ref IOStreamPLY. - the operator reads the vertex `point` property; - if three PLY properties `nx`, `ny` and `nz` with type `float` @@ -307,7 +307,7 @@ bool read_PLY(std::istream& is, CGAL::Point_set_3& point_set) /*! \ingroup PkgPointSet3IOPLY - \brief reads a point set with properties from an input stream in ASCII or Binary \ref IOStreamPLY. + \brief reads a point set with properties from an input stream in \ascii or binary \ref IOStreamPLY. - the operator reads the vertex `point` property; - if three PLY properties `nx`, `ny` and `nz` with type `float` @@ -331,7 +331,7 @@ bool read_PLY(std::istream& is, CGAL::Point_set_3& point_set) \cgalNamedParamsBegin \cgalParamNBegin{use_binary_mode} - \cgalParamDescription{indicates whether data should be read in binary (`true`) or in ASCII (`false`)} + \cgalParamDescription{indicates whether data should be read in binary (`true`) or in \ascii (`false`)} \cgalParamType{Boolean} \cgalParamDefault{`true`} \cgalParamNEnd @@ -394,7 +394,7 @@ bool read_PLY(const std::string& fname, CGAL::Point_set_3& point_ \deprecated This function is deprecated since \cgal 5.3, \link PkgPointSet3IO `CGAL::IO::read_PLY()` \endlink should be used instead. - \brief reads a point set with properties from an input stream in ASCII or Binary PLY format. + \brief reads a point set with properties from an input stream in \ascii or binary PLY format. - the operator reads the vertex `point` property; - if three PLY properties `nx`, `ny` and `nz` with type `float` @@ -459,7 +459,7 @@ namespace IO { \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} \cgalParamDefault{the precision of the stream `os`} - \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} + \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} \cgalParamNEnd \cgalNamedParamsEnd @@ -725,7 +725,7 @@ bool write_PLY(std::ostream& os, const CGAL::Point_set_3& point_s \cgalNamedParamsBegin \cgalParamNBegin{use_binary_mode} - \cgalParamDescription{indicates whether data should be read in binary (`true`) or in ASCII (`false`)} + \cgalParamDescription{indicates whether data should be read in binary (`true`) or in \ascii (`false`)} \cgalParamType{Boolean} \cgalParamDefault{`true`} \cgalParamNEnd @@ -734,7 +734,7 @@ bool write_PLY(std::ostream& os, const CGAL::Point_set_3& point_s \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} \cgalParamType{int} \cgalParamDefault{`6`} - \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} + \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/Point_set_processing_3/doc/Point_set_processing_3/Point_set_processing_3.txt b/Point_set_processing_3/doc/Point_set_processing_3/Point_set_processing_3.txt index 80efdab78a2..f23e9786f21 100644 --- a/Point_set_processing_3/doc/Point_set_processing_3/Point_set_processing_3.txt +++ b/Point_set_processing_3/doc/Point_set_processing_3/Point_set_processing_3.txt @@ -150,7 +150,7 @@ the detailed API of the Point Set Processing functions. \cgal provides functions to read and write sets of points (possibly with normals) from the following file formats: -- \link IOStreamXYZ XYZ \endlink (ASCII file three point coordinates `x y z` per line or three +- \link IOStreamXYZ XYZ \endlink (\ascii file three point coordinates `x y z` per line or three point coordinates and three normal vector coordinates `x y z nx ny nz` per line) - \link IOStreamOFF OFF (%Object File Format) \endlink -- \cgalCite{cgal:p-gmgv16-96} @@ -161,7 +161,7 @@ not handle normals and requires the \ref thirdpartyLASlib library. All of the functions in \ref PkgPointSetProcessing3IO (with the exception of the LAS format) can read and write either points alone or points with normals (depending on whether the `normal_map` named parameter is used by the user or not). -Note that the %PLY format handles both ASCII and binary formats. In +Note that the %PLY format handles both \ascii and binary formats. In addition, %PLY and %LAS are extensible formats that can embed additional properties. These can also be read by \cgal (see Section \ref Point_set_processing_3Properties_io). diff --git a/Point_set_processing_3/include/CGAL/IO/read_ply_points.h b/Point_set_processing_3/include/CGAL/IO/read_ply_points.h index 53fad444a93..55c79e8a989 100644 --- a/Point_set_processing_3/include/CGAL/IO/read_ply_points.h +++ b/Point_set_processing_3/include/CGAL/IO/read_ply_points.h @@ -296,7 +296,7 @@ bool read_PLY(std::istream& is, \cgalNamedParamsBegin \cgalParamNBegin{use_binary_mode} - \cgalParamDescription{indicates whether data should be read in binary (`true`) or in ASCII (`false`)} + \cgalParamDescription{indicates whether data should be read in binary (`true`) or in \ascii (`false`)} \cgalParamType{Boolean} \cgalParamDefault{`true`} \cgalParamNEnd diff --git a/Point_set_processing_3/include/CGAL/IO/read_points.h b/Point_set_processing_3/include/CGAL/IO/read_points.h index b9c31d64f69..1547b95f19a 100644 --- a/Point_set_processing_3/include/CGAL/IO/read_points.h +++ b/Point_set_processing_3/include/CGAL/IO/read_points.h @@ -73,11 +73,11 @@ namespace IO { \cgalParamNEnd \cgalParamNBegin{use_binary_mode} - \cgalParamDescription{indicates whether data should be read in binary (`true`) or in ASCII (`false`)} + \cgalParamDescription{indicates whether data should be read in binary (`true`) or in \ascii (`false`)} \cgalParamType{Boolean} \cgalParamDefault{`true`} \cgalParamExtra{This parameter is only relevant for `PLY` reading: the `OFF` and `XYZ` formats - are always ASCII, and the `LAS` format is always binary.} + are always \ascii, and the `LAS` format is always binary.} \cgalParamNEnd \cgalNamedParamsEnd diff --git a/Point_set_processing_3/include/CGAL/IO/write_ply_points.h b/Point_set_processing_3/include/CGAL/IO/write_ply_points.h index e14ca846adb..41281a1360f 100644 --- a/Point_set_processing_3/include/CGAL/IO/write_ply_points.h +++ b/Point_set_processing_3/include/CGAL/IO/write_ply_points.h @@ -178,7 +178,7 @@ template >( std::istream& in, Polyhedron_3& P); writes the polyhedral surface \f$P\f$ to the output stream `out` using the %Object File Format, OFF, with file extension -.off. The output is in ASCII format. From the polyhedral surface, only the point +.off. The output is in \ascii format. From the polyhedral surface, only the point coordinates and facets are written. Neither normal vectors nor color attributes are used. -For OFF an ASCII and a binary format exist. The format can be selected +For `OFF` an \ascii and a binary format exist. The format can be selected with the \cgal modifiers for streams, `set_ascii_mode()` and `set_binary_mode()` respectively. The modifier `set_pretty_mode()` can be used to allow for (a few) structuring comments in the output. Otherwise, -the output would be free of comments. The default for writing is ASCII +the output would be free of comments. The default for writing is \ascii without comments. This function overloads the generic function \link PkgBGLIoFuncsOFF `write_OFF(std::istream&,FaceGraph)` \endlink diff --git a/Spatial_searching/benchmark/Spatial_searching/binary.cpp b/Spatial_searching/benchmark/Spatial_searching/binary.cpp index fa04ed04b2c..262934b8cd2 100644 --- a/Spatial_searching/benchmark/Spatial_searching/binary.cpp +++ b/Spatial_searching/benchmark/Spatial_searching/binary.cpp @@ -12,7 +12,7 @@ typedef CGAL::Simple_cartesian::Point_3 Point_3; int main(int argc, char* argv[]) { #if 0 - std::cerr << "ascii to binary\n"; + std::cerr << "ASCII to binary\n"; int d; int N; Point_3 p; diff --git a/Stream_lines_2/doc/Stream_lines_2/CGAL/Stream_lines_2.h b/Stream_lines_2/doc/Stream_lines_2/CGAL/Stream_lines_2.h index 22f8003cba3..896788fa70d 100644 --- a/Stream_lines_2/doc/Stream_lines_2/CGAL/Stream_lines_2.h +++ b/Stream_lines_2/doc/Stream_lines_2/CGAL/Stream_lines_2.h @@ -109,7 +109,7 @@ returns the saturation ratio. FT get_saturation_ratio() const; /*! -prints the streamlines to an ASCII file: line by line, and point by point. +prints the streamlines to an \ascii file: line by line, and point by point. */ void print_stream_lines(std::ofstream & fw); diff --git a/Stream_lines_2/examples/Stream_lines_2/stl_triangular_field.cpp b/Stream_lines_2/examples/Stream_lines_2/stl_triangular_field.cpp index 538e835c033..f7684d2f1b0 100644 --- a/Stream_lines_2/examples/Stream_lines_2/stl_triangular_field.cpp +++ b/Stream_lines_2/examples/Stream_lines_2/stl_triangular_field.cpp @@ -18,7 +18,7 @@ int main() { Runge_kutta_integrator runge_kutta_integrator(1); - /*datap.tri.cin and datav.tri.cin are ascii files where are stored the vector values*/ + /*datap.tri.cin and datav.tri.cin are ASCII files where are stored the vector values*/ std::ifstream inp("data/datap.tri.cin"); std::ifstream inv("data/datav.tri.cin"); std::istream_iterator beginp(inp); diff --git a/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt b/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt index ecd026afb2f..2bc5e41c1a6 100644 --- a/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt +++ b/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt @@ -31,7 +31,7 @@ users to provide more properties such as associating normals or colors to vertic A precise specification of the format is available at geomview.org. -Note that the format defines both ASCII and binary OFF formats, but only the ASCII OFF format is supported in \cgal. +Note that the format defines both \ascii and binary OFF formats, but only the \ascii OFF format is supported in \cgal. The following table lists some \cgal data structures that have I/O functions compatible with this file format. @@ -104,7 +104,7 @@ which offers combinatorial repairing while reading bad inputs. \section IOStreamOBJ Wavefront Advanced Visualizer Object Format (OBJ) -The `OBJ` file format, using the file extension `.obj`, is a simple ASCII data format that represents 3D geometry. +The `OBJ` file format, using the file extension `.obj`, is a simple \ascii data format that represents 3D geometry. Vertices are stored in a counter-clockwise order by default, making explicit declaration of face normals unnecessary. A precise specification of the format is available here. @@ -144,7 +144,7 @@ which offers combinatorial repairing while reading bad inputs. \section IOStreamSTL STereoLithography (STL) File Format -The `STL` file format, using the file extension `.stl`, is an ASCII or binary format native +The `STL` file format, using the file extension `.stl`, is an \ascii or binary format native to the stereolithography CAD software created by 3D Systems. STL files describe the surface geometry of a three-dimensional object. @@ -188,7 +188,7 @@ which offers combinatorial repairing while reading bad inputs. \section IOStreamPLY Polygon File Format (PLY) -The `PLY` file format, using the file extension `.ply`, is an ASCII or binary format +The `PLY` file format, using the file extension `.ply`, is an \ascii or binary format conceived to store the data obtained during 3D scans. Objects are stored as a simple list of polygons and external properties can be stored. @@ -291,7 +291,7 @@ A precise specification of those formats is available \section IOStreamXYZ XYZ File Format -The `XYZ` format, using the file extension `.xyz`, is a non-standard ASCII data format +The `XYZ` format, using the file extension `.xyz`, is a non-standard \ascii data format regularly used to describe point sets. Each line represent a point, and is composed of its coordinates and other properties. Only coordinates and normals are currently supported in \cgal. @@ -324,7 +324,7 @@ of its coordinates and other properties. Only coordinates and normals are curren \section IOStreamGocad GOCAD (TS) File Format -The `GOCAD` format, using the file extension `.ts`, is an ASCII file format +The `GOCAD` format, using the file extension `.ts`, is an \ascii file format that enables a range of primitive types to be imported into the GOCAD package. A precise specification of the format is available here. @@ -408,7 +408,7 @@ which offers combinatorial repairing while reading bad inputs. \section IOStreamWRL Virtual Reality Modeling Language (VRML) File Format -The `VRML` format, using the file extension `.wrl`, is an ASCII format often used by browser plug-ins +The `VRML` format, using the file extension `.wrl`, is an \ascii format often used by browser plug-ins to display virtual reality environments. VRML files are known as “worlds,” which is what "WRL" stands for. A WRL file includes data specifying 3-D details such as vertices, edges for a 3-D polygon, surface color, ... diff --git a/Stream_support/doc/Stream_support/IOstream.txt b/Stream_support/doc/Stream_support/IOstream.txt index 5571d483637..0a979c0d106 100644 --- a/Stream_support/doc/Stream_support/IOstream.txt +++ b/Stream_support/doc/Stream_support/IOstream.txt @@ -53,14 +53,14 @@ I/O streams. Classes external to \cgal are also supported, by means of `oformat( (Section \ref seciofornoncgaltypes "I/O for Non CGAL Types"). The basic task of such an operator is to produce a representation of an object that can be written as a sequence of -characters on devices as a console, a file, or a pipe. In \cgal we distinguish between a raw ascii, +characters on devices as a console, a file, or a pipe. In \cgal we distinguish between a raw \ascii, a raw binary, and a pretty printing format. \code{.cpp} enum Mode {ASCII = 0, BINARY, PRETTY}; \endcode -In `ASCII` mode, objects are written as +In \ascii mode, objects are written as a set of numbers, e.g. the coordinates of a point or the coefficients of a line, in a machine independent format. In `BINARY` mode, @@ -72,7 +72,7 @@ object is written, as well as the data defining the object. For example for a point at the origin with Cartesian double coordinates, the output would be `PointC2(0.0, 0.0)`. At the moment \cgal does not provide input operations for pretty printed data. By default a stream -is in Ascii mode. +is in \ascii mode. \cgal provides the following functions to modify the mode of an I/O stream. @@ -322,7 +322,7 @@ All of these functions (with the exception of the LAS format) can read and write either points alone or points with normals (depending on whether the `normal_map` named parameter is used by the user or not). -Note that the %PLY format handles both ASCII and binary formats. In +Note that the %PLY format handles both \ascii and binary formats. In addition, %PLY and %LAS are extensible formats that can embed additional properties. These can also be read by \cgal (see Section \ref Point_set_processing_3Properties_io). diff --git a/Stream_support/doc/Stream_support/PackageDescription.txt b/Stream_support/doc/Stream_support/PackageDescription.txt index cb40fcd8607..9efed4d7e45 100644 --- a/Stream_support/doc/Stream_support/PackageDescription.txt +++ b/Stream_support/doc/Stream_support/PackageDescription.txt @@ -45,7 +45,7 @@ \cgalPkgPicture{io.png} \cgalPkgSummaryBegin \cgalPkgAuthors{Andreas Fabri, Geert-Jan Giezeman, and Lutz Kettner} -\cgalPkgDesc{All classes in the \cgal kernel provide input and output operators for I/O streams. The basic task of such an operator is to produce a representation of an object that can be written as a sequence of characters on devices as a console, a file, or a pipe. In \cgal we distinguish between a raw ascii, a raw binary and a pretty printing format.} +\cgalPkgDesc{All classes in the \cgal kernel provide input and output operators for I/O streams. The basic task of such an operator is to produce a representation of an object that can be written as a sequence of characters on devices as a console, a file, or a pipe. In \cgal we distinguish between a raw \ascii, a raw binary and a pretty printing format.} \cgalPkgManuals{Chapter_IO_Streams,PkgStreamSupportRef} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin diff --git a/Stream_support/include/CGAL/IO/PLY.h b/Stream_support/include/CGAL/IO/PLY.h index f2b07798a9a..86745f0e6a6 100644 --- a/Stream_support/include/CGAL/IO/PLY.h +++ b/Stream_support/include/CGAL/IO/PLY.h @@ -294,7 +294,7 @@ bool read_PLY(std::istream& is, * * \cgalNamedParamsBegin * \cgalParamNBegin{use_binary_mode} - * \cgalParamDescription{indicates whether data should be read in binary (`true`) or in ASCII (`false`)} + * \cgalParamDescription{indicates whether data should be read in binary (`true`) or in \ascii (`false`)} * \cgalParamType{Boolean} * \cgalParamDefault{`true`} * \cgalParamNEnd @@ -365,7 +365,7 @@ bool read_PLY(std::istream& is, PointRange& points, PolygonRange& polygons, * * \cgalNamedParamsBegin * \cgalParamNBegin{use_binary_mode} - * \cgalParamDescription{indicates whether data should be read in binary (`true`) or in ASCII (`false`)} + * \cgalParamDescription{indicates whether data should be read in binary (`true`) or in \ascii (`false`)} * \cgalParamType{Boolean} * \cgalParamDefault{`true`} * \cgalParamNEnd @@ -445,7 +445,7 @@ bool read_PLY(const std::string& fname, PointRange& points, PolygonRange& polygo * \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} * \cgalParamType{int} * \cgalParamDefault{the precision of the stream `os`} - * \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} + * \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} * \cgalParamNEnd * \cgalNamedParamsEnd * @@ -526,7 +526,7 @@ bool write_PLY(std::ostream& out, const PointRange& points, const PolygonRange& * * \cgalNamedParamsBegin * \cgalParamNBegin{use_binary_mode} - * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in ASCII (`false`)} + * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)} * \cgalParamType{Boolean} * \cgalParamDefault{`true`} * \cgalParamNEnd @@ -535,7 +535,7 @@ bool write_PLY(std::ostream& out, const PointRange& points, const PolygonRange& * \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} * \cgalParamType{int} * \cgalParamDefault{`6`} - * \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} + * \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} * \cgalParamNEnd * \cgalNamedParamsEnd * diff --git a/Stream_support/include/CGAL/IO/STL.h b/Stream_support/include/CGAL/IO/STL.h index 5bb690d9410..88a3c3d7933 100644 --- a/Stream_support/include/CGAL/IO/STL.h +++ b/Stream_support/include/CGAL/IO/STL.h @@ -188,7 +188,7 @@ bool read_STL(std::istream& is, PointRange& points, TriangleRange& facets, * * \brief reads the content of a file named `fname` into `points` and `facets`, using the \ref IOStreamSTL. * - * If `use_binary_mode` is `true`, but the reading fails, ASCII reading will be automatically tested. + * If `use_binary_mode` is `true`, but the reading fails, \ascii reading will be automatically tested. * \attention The polygon soup is not cleared, and the data from the file are appended. * * \tparam PointRange a model of the concept `RandomAccessContainer` whose value type is the point type. @@ -204,7 +204,7 @@ bool read_STL(std::istream& is, PointRange& points, TriangleRange& facets, * * \cgalNamedParamsBegin * \cgalParamNBegin{use_binary_mode} - * \cgalParamDescription{indicates whether data should be read in binary (`true`) or in ASCII (`false`)} + * \cgalParamDescription{indicates whether data should be read in binary (`true`) or in \ascii (`false`)} * \cgalParamType{Boolean} * \cgalParamDefault{`true`} * \cgalParamNEnd @@ -287,7 +287,7 @@ bool read_STL(const std::string& fname, PointRange& points, TriangleRange& facet * \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} * \cgalParamType{int} * \cgalParamDefault{the precision of the stream `os`} - * \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} + * \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} * \cgalParamNEnd * \cgalNamedParamsEnd * @@ -398,7 +398,7 @@ bool write_STL(std::ostream& os, const PointRange& points, const TriangleRange& * * \cgalNamedParamsBegin * \cgalParamNBegin{use_binary_mode} - * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in ASCII (`false`)} + * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)} * \cgalParamType{Boolean} * \cgalParamDefault{`true`} * \cgalParamNEnd @@ -407,7 +407,7 @@ bool write_STL(std::ostream& os, const PointRange& points, const TriangleRange& * \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} * \cgalParamType{int} * \cgalParamDefault{`6`} - * \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} + * \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} * \cgalParamNEnd * \cgalNamedParamsEnd * diff --git a/Stream_support/include/CGAL/IO/VTK.h b/Stream_support/include/CGAL/IO/VTK.h index cb44f89c81c..34e31698fca 100644 --- a/Stream_support/include/CGAL/IO/VTK.h +++ b/Stream_support/include/CGAL/IO/VTK.h @@ -363,7 +363,7 @@ void write_soup_polys_points(std::ostream& os, * * \cgalNamedParamsBegin * \cgalParamNBegin{use_binary_mode} - * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in ASCII (`false`)} + * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)} * \cgalParamType{Boolean} * \cgalParamDefault{`true`} * \cgalParamNEnd @@ -461,7 +461,7 @@ bool write_VTP(std::ostream& os, const PointRange& points, const PolygonRange& p * * \cgalNamedParamsBegin * \cgalParamNBegin{use_binary_mode} - * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in ASCII (`false`)} + * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)} * \cgalParamType{Boolean} * \cgalParamDefault{`true`} * \cgalParamNEnd diff --git a/Stream_support/include/CGAL/IO/io.h b/Stream_support/include/CGAL/IO/io.h index 2676f6ace5f..63d20c73cbf 100644 --- a/Stream_support/include/CGAL/IO/io.h +++ b/Stream_support/include/CGAL/IO/io.h @@ -55,7 +55,7 @@ IOStreams. The basic task of such an operator is to produce a representation of an object that can be written as a sequence of characters on devices as a console, a file, or a pipe. The enum `Mode` distinguish between three different printing formats. -In `ASCII` mode, numbers +In \ascii mode, numbers e.g. the coordinates of a point or the coefficients of a line, are written in a machine independent format. @@ -68,7 +68,7 @@ object is written, as well as the data defining the object. For example for a point at the origin with %Cartesian double coordinates, the output would be `PointC2(0.0, 0.0)`. At the moment \cgal does not provide input operations for pretty printed data. By default a stream -is in Ascii mode. +is in \ascii mode. \sa `CGAL::IO::set_mode()` \sa `CGAL::IO::set_ascii_mode()` @@ -458,7 +458,7 @@ inline Mode get_mode(std::ios& s) /*! \ingroup PkgStreamSupportRef -sets the mode of the %IO stream `s` to be the `ASCII` mode. +sets the mode of the %IO stream `s` to be the \ascii mode. Returns the previous mode of `s`. \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink @@ -561,7 +561,7 @@ inline bool is_pretty(std::ios& s) { return s.iword(Static::get_mode()) == PRETT /*! \ingroup PkgStreamSupportRef -checks if the %IO stream `s` is in `ASCII` mode. +checks if the %IO stream `s` is in \ascii mode. \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink \sa `CGAL::IO::set_mode()` @@ -684,7 +684,7 @@ inline std::istream &operator>>(std::istream &is, Color& col) break; default: std::cerr << "" << std::endl; - std::cerr << "Stream must be in ascii or binary mode" << std::endl; + std::cerr << "Stream must be in ASCII or binary mode" << std::endl; break; } diff --git a/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h b/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h index 773f5d8b26b..a57834da89c 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h @@ -903,7 +903,7 @@ namespace IO { /// \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} /// \cgalParamType{int} /// \cgalParamDefault{the precision of the stream `os`} -/// \cgalParamExtra{This parameter is only meaningful while using ASCII encoding.} +/// \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} /// \cgalParamNEnd /// \cgalNamedParamsEnd /// From e102b0f5de4e2e8e462c56eac263f791b6b18464 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 24 Jun 2021 17:31:17 +0200 Subject: [PATCH 253/349] added note about c_float type --- .../include/CGAL/OSQP_quadratic_program_traits.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 3dfc8af4fc1..63d3abf0f02 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -40,7 +40,14 @@ namespace CGAL { library, which must be available on the system. \tparam FT - number type + number type that `FieldNumberType` + + \cgalModifBegin + \note The `FT` type is provided for convenience. Internally, this FT type is converted + to `c_float` type that can be set either to `float` or `double`. By default, usually + the `double` type is used. After the optimization is complete, the `c_float` type is + converted back to `FT`. See more about `c_float` here. + \cgalModifEnd \cgalModels `QuadraticProgramTraits` */ From 76dc3a0eab829c35883beea852abb06eb00b1e94 Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Fri, 25 Jun 2021 10:27:37 +0200 Subject: [PATCH 254/349] tree -> BVH --- .../doc/Polygon_mesh_processing/Polygon_mesh_processing.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 37b0ef5f658..1180203240b 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -960,15 +960,15 @@ The function `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` computes an estimate of the Hausdorff distance of two triangle meshes which is bounded by a user-given error bound. Given two meshes `tm1` and `tm2`, it follows the procedure given by \cgalCite{tang2009interactive}. Namely, a bounded volume hierarchy (BVH) is -built on `tm1` and `tm2` respectively. The tree on `tm1` is used to iterate over all +built on `tm1` and `tm2` respectively. The BVH on `tm1` is used to iterate over all triangles in `tm1`. Throughout the traversal, the procedure keeps track of a global lower and upper bound on the Hausdorff distance respectively. For each triangle -`t` in `tm1`, by traversing the tree on `tm2`, it is estimated via the global bounds +`t` in `tm1`, by traversing the BVH on `tm2`, it is estimated via the global bounds whether `t` can still contribute to the actual Hausdorff distance. From this process, a set of candidate triangles is selected. The candidate triangles are subsequently subdivided and for each smaller -triangle, the tree on `tm2` is traversed again. This is repeated until the +triangle, the BVH on `tm2` is traversed again. This is repeated until the triangle is smaller than the user-given error bound, all vertices of the triangle are projected onto the same triangle in `tm2`, or the triangle's upper bound is lower than the global lower bound. After creation, the subdivided From 95cc9992cf6b6bc41311a96901446630a8359f7a Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 25 Jun 2021 11:47:34 +0200 Subject: [PATCH 255/349] fixed typo --- .../include/CGAL/Polygon_mesh_processing/distance.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index b9445ed98e1..5161b616bcb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -2441,7 +2441,7 @@ double bounded_error_Hausdorff_distance( * and `bounded_error_Hausdorff_distance(tm2, tm1, error_bound, np2, np1)`. * * This function optimizes all internal calls to shared data structures in order to - * speed the computation. + * speed up the computation. * * @return the symmetric Hausdorff distance */ From abb11ad1e4dcf227d4da9ae2bb7f69e3f0929cd8 Mon Sep 17 00:00:00 2001 From: Giles Bathgate Date: Thu, 24 Jun 2021 19:59:41 +0100 Subject: [PATCH 256/349] Remove update/bytes/leafs functions, and Objects_around_box --- Nef_3/include/CGAL/Nef_3/K3_tree.h | 219 ------------------- Nef_3/include/CGAL/Nef_3/SNC_point_locator.h | 143 ------------ 2 files changed, 362 deletions(-) diff --git a/Nef_3/include/CGAL/Nef_3/K3_tree.h b/Nef_3/include/CGAL/Nef_3/K3_tree.h index dbbe1d5bb25..be2c8b79f5e 100644 --- a/Nef_3/include/CGAL/Nef_3/K3_tree.h +++ b/Nef_3/include/CGAL/Nef_3/K3_tree.h @@ -120,7 +120,6 @@ private: public: friend class Objects_along_ray; friend class Objects_around_segment; - friend class Objects_around_box; public: @@ -190,55 +189,6 @@ public: } } - std::size_t bytes() { - // bytes used for the Kd-tree - std::size_t s = sizeof(Node); - if(left_node != nullptr) - s += left_node->bytes(); - if(right_node != nullptr) - s += right_node->bytes(); - typename Object_list::iterator o; - for(o = object_list.begin(); o != object_list.end(); ++o) - s += sizeof(*o); - return s; - } - - std::size_t leafs(int mask = 255, int lower_limit = 0) { - std::size_t s = 0; - Halffacet_handle f; - Halfedge_handle e; - Vertex_handle v; - typename Object_list::iterator o; - if(mask == 0) - s = 1; - else { - for(o = object_list.begin(); o != object_list.end(); ++o) { - if((mask & 1) && assign(v,*o)) - ++s; - else if((mask&2) && assign(e,*o)) - ++s; - else if(((mask&4) || (mask&8)) && assign(f,*o)) { - if(mask&4) - ++s; - else { - int length = 0; - typename Traits::SHalfedge_around_facet_circulator safc(f->facet_cycles_begin()), - send(safc); - while(++length < lower_limit && ++safc != send) ; - if(length >= lower_limit) - ++s; - } - } - } - } - - if(left_node != nullptr) - s += left_node->leafs(mask, lower_limit); - if(right_node != nullptr) - s += right_node->leafs(mask, lower_limit); - return s; - } - template void add_facet(Halffacet_handle f, Depth depth) { if(left_node == nullptr) { @@ -512,120 +462,6 @@ void divide_segment_by_plane( Segment_3 s, Plane_3 pl, } }; -class Objects_around_box { - - public: - class Iterator; - protected: - Node_handle root_node; - Bounding_box_3 box; - bool initialized; - - public: - Objects_around_box() : initialized(false) {} - Objects_around_box(const K3_tree& k, const Bounding_box_3& b) : - root_node(k.root), box(b), initialized(true) {} - - void initialize( const K3_tree& k, const Bounding_box_3& b) { - root_node = k.root; - box = b; - initialized = true; - } - - public: - Iterator begin() const { - CGAL_assertion( initialized == true); - return Iterator( root_node, box); - } - - Iterator end() const { - return Iterator(); - } - - class Iterator { - - friend class K3_tree; - typedef Iterator Self; - typedef std::pair< const Node_handle, Bounding_box_3> Candidate; - - protected: - std::list S; - const Node_handle node; - - public: - Iterator() : node(nullptr) {} - - Iterator( const Node_handle root, const Bounding_box_3& s) { - S.push_front( Candidate( root, s)); - ++(*this); // place the interator in the first intersected cell - } - - Iterator( const Self& i) : S(i.S), node(i.node) {} - - const Object_list& operator*() const { - CGAL_assertion( node != nullptr); - return node->objects(); - } - - Self& operator++() { - - if(S.empty()) - node = nullptr; // end of the iterator - else { - while( !S.empty()) { - const Node_handle n = S.front().first; - Bounding_box_3 b = S.front().second; - S.pop_front(); - if( n->is_leaf()) { - node = n; - break; - } else { - Point_3 pmin(b.min_coord(0), b.min_coord(1), b.min_coord(2)); - Point_3 pmax(b.max_coord(0), b.max_coord(1), b.max_coord(2)); - Oriented_side src_side = - n->plane().oriented_side(pmax); - Oriented_side tgt_side = - n->plane().oriented_side(pmin); - if( src_side == tgt_side && - src_side != ON_ORIENTED_BOUNDARY) - S.push_front( Candidate( get_child_by_side( n, src_side), b)); - else { - S.push_front( Candidate( get_child_by_side( n, tgt_side), b)); - S.push_front( Candidate( get_child_by_side( n, src_side), b)); - } - } - } - } - return *this; - } - - bool operator==(const Self& i) const { - return (node == i.node); - } - - bool operator!=(const Self& i) const { - return !(*this == i); - } - - private: - Node_handle get_node() const { - CGAL_assertion( node != nullptr); - return node; - } - - inline - Node_handle get_child_by_side( const Node_handle node, Oriented_side side) { - CGAL_assertion( node != nullptr); - CGAL_assertion( side != ON_ORIENTED_BOUNDARY); - if( side == ON_NEGATIVE_SIDE) { - return node->left(); - } - CGAL_assertion( side == ON_POSITIVE_SIDE); - return node->right(); - } - }; -}; - private: #ifdef CGAL_NEF_EXPLOIT_REFERENCE_COUNTING bool reference_counted; @@ -779,9 +615,6 @@ typename Object_list::difference_type n_vertices = std::distance(objects.begin() V.post_visit(current); } - size_t bytes() { return root->bytes();} - size_t leafs(int mask = 255, int lower_limit=0) { return root->leafs(mask, lower_limit);} - void transform(const Aff_transformation_3& t) { if(root == nullptr){ return; @@ -830,57 +663,6 @@ std::string dump_object_list( const Object_list& O, int level = 0) { return os.str(); } -bool update( Unique_hash_map& V, - Unique_hash_map& E, - Unique_hash_map& F) { - return update( root, V, E, F); -} - -bool update( Node_handle node, - Unique_hash_map& V, - Unique_hash_map& E, - Unique_hash_map& F) { - CGAL_assertion( node != nullptr); - if( node->is_leaf()) { - bool updated = false; - Object_list* O = &node->object_list; - typename Object_list::iterator onext, o = O->begin(); - while( o != O->end()) { - onext = o; - onext++; - Vertex_handle v; - Halfedge_handle e; - Halffacet_handle f; - if( CGAL::assign( v, *o)) { - if( !V[v]) { - O->erase(o); - updated = true; - } - } - else if( CGAL::assign( e, *o)) { - if( !E[e]) { - O->erase(o); - updated = true; - } - } - else if( CGAL::assign( f, *o)) { - if( !F[f]) { - O->erase(o); - updated = true; - } - } - else CGAL_error_msg( "wrong handle"); - o = onext; - } - return updated; - } - // TODO: protect the code below from optimizations! - bool left_updated = update( node->left_node, V, E, F); - CGAL_NEF_TRACEN("k3_tree::update(): left node updated? "<right_node, V, E, F); - CGAL_NEF_TRACEN("k3_tree::update(): right node updated? "< diff --git a/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h b/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h index 26116cc643a..4f03db30ade 100644 --- a/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h +++ b/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h @@ -108,10 +108,6 @@ public: virtual void transform(const Aff_transformation_3& t) = 0; - //virtual bool update( Unique_hash_map& V, - // Unique_hash_map& E, - // Unique_hash_map& F) = 0; - virtual void add_facet(Halffacet_handle) {} virtual void add_edge(Halfedge_handle) {} @@ -187,8 +183,6 @@ public: typedef typename SNC_candidate_provider::Objects_along_ray Objects_along_ray; typedef typename Objects_along_ray::Iterator Objects_along_ray_iterator; - // typedef typename SNC_candidate_provider::Objects_around_box Objects_around_box; - using Base::get_visible_facet; public: SNC_point_locator_by_spatial_subdivision() : @@ -238,16 +232,6 @@ public: candidate_provider->transform(t); } - virtual bool update( Unique_hash_map& V, - Unique_hash_map& E, - Unique_hash_map& F) { - CGAL_NEF_TIMER(ct_t.start()); - CGAL_assertion( initialized); - bool updated = candidate_provider->update( V, E, F); - CGAL_NEF_TIMER(ct_t.stop()); - return updated; - } - virtual ~SNC_point_locator_by_spatial_subdivision() noexcept(!CGAL_ASSERTIONS_ENABLED) { CGAL_destructor_warning(initialized || @@ -256,125 +240,6 @@ public: delete candidate_provider; } - /* - template - bool point_in_box(const Box& box, const Point_3& p) { - if(p.x() < box.min_coord(0)) return true; - if(p.x() > box.max_coord(0)) return true; - if(p.y() < box.min_coord(1)) return true; - if(p.y() > box.max_coord(1)) return true; - if(p.z() < box.min_coord(2)) return true; - if(p.z() > box.max_coord(2)) return true; - return false; - } - - template - bool in_range(const Box& box) const { - Vertex_handle v; - Halfedge_handle e; - Halffacet_handle f; - - Objects_around_box oab; - typename Objects_around_box::Iterator - objects_iterator(oab.begin()); - for( ; objects_iterator != oab.end(); ++objects_iterator) { - Object_list candidates = *objects_iterator; - Object_list_iterator o; - CGAL_for_each( o, candidates) { - if(CGAL::assign(v, *o)) { - if(point_in_box(box, v->point())) - return true; - } else if(CGAL::assign(e, *o)) { - Point_3 ip; - Point_3 pmin(box.min_coord(0), box.min_coord(1), box.min_coord(2)); - Point_3 pmax(box.max_coord(0), box.max_coord(1), box.max_coord(2)); - Segment_3 seg(e->source()->point(), - e->twin()->source()->point()); - - Plane_3 pl(pmin, Vector_3(1,0,0)); - Object o = intersection(pl, seg); - if(CGAL::assign(ip,o) && point_in_box(box, ip)) - return true; - pl = Plane_3(pmin, Vector_3(0,1,0)); - o = intersection(pl, seg); - if(CGAL::assign(ip,o) && point_in_box(box, ip)) - return true; - pl = Plane_3(pmin, Vector_3(0,0,1)); - o = intersection(pl, seg); - if(CGAL::assign(ip,o) && point_in_box(box, ip)) - return true; - pl = Plane_3(pmax, Vector_3(1,0,0)); - o = intersection(pl, seg); - if(CGAL::assign(ip,o) && point_in_box(box, ip)) - return true; - pl = Plane_3(pmax, Vector_3(0,1,0)); - o = intersection(pl, seg); - if(CGAL::assign(ip,o) && point_in_box(box, ip)) - return true; - pl = Plane_3(pmax, Vector_3(0,0,1)); - o = intersection(pl, seg); - if(CGAL::assign(ip,o) && point_in_box(box, ip)) - return true; - } else if(CGAL::assign(f, *o)) { - Segment_3 seg(Point_3(box.min_coord(0), box.min_coord(1), box.min_coord(2)), - Point_3(box.min_coord(0), box.min_coord(1), box.max_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - seg = Segment_3(Point_3(box.max_coord(0), box.min_coord(1), box.min_coord(2)), - Point_3(box.max_coord(0), box.min_coord(1), box.max_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - seg = Segment_3(Point_3(box.min_coord(0), box.max_coord(1), box.min_coord(2)), - Point_3(box.min_coord(0), box.max_coord(1), box.max_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - seg = Segment_3(Point_3(box.max_coord(0), box.max_coord(1), box.min_coord(2)), - Point_3(box.max_coord(0), box.max_coord(1), box.max_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - - seg = Segment_3(Point_3(box.min_coord(0), box.min_coord(1), box.min_coord(2)), - Point_3(box.min_coord(0), box.max_coord(1), box.min_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - seg = Segment_3(Point_3(box.max_coord(0), box.min_coord(1), box.min_coord(2)), - Point_3(box.max_coord(0), box.max_coord(1), box.min_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - seg = Segment_3(Point_3(box.min_coord(0), box.min_coord(1), box.max_coord(2)), - Point_3(box.min_coord(0), box.max_coord(1), box.max_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - seg = Segment_3(Point_3(box.max_coord(0), box.min_coord(1), box.max_coord(2)), - Point_3(box.max_coord(0), box.max_coord(1), box.max_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - - seg = Segment_3(Point_3(box.min_coord(0), box.min_coord(1), box.min_coord(2)), - Point_3(box.max_coord(0), box.min_coord(1), box.min_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - seg = Segment_3(Point_3(box.min_coord(0), box.max_coord(1), box.min_coord(2)), - Point_3(box.max_coord(0), box.max_coord(1), box.min_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - seg = Segment_3(Point_3(box.min_coord(0), box.min_coord(1), box.max_coord(2)), - Point_3(box.max_coord(0), box.min_coord(1), box.max_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - seg = Segment_3(Point_3(box.min_coord(0), box.max_coord(1), box.max_coord(2)), - Point_3(box.max_coord(0), box.max_coord(1), box.max_coord(2))); - if(is.does_intersect_internally(seg, f)) - return true; - - } else - CGAL_assertion_msg(false, "wrong handle"); - } - } - return false; - } - */ - virtual Object_handle shoot(const Ray_3& ray, int mask=255) const { CGAL_NEF_TIMER(rs_t.start()); CGAL_assertion( initialized); @@ -916,14 +781,6 @@ public: return new Self; } - virtual bool update( Unique_hash_map& V, - Unique_hash_map& E, - Unique_hash_map& F) { - CGAL_NEF_TIMER(ct_t.start()); - CGAL_assertion( initialized); - CGAL_NEF_TIMER(ct_t.stop()); - return false; - } virtual ~SNC_point_locator_naive() {} From 0f6fa73a467a32c58a910b52fe67db4311aacaf1 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Mon, 28 Jun 2021 18:06:23 +0200 Subject: [PATCH 257/349] fixed typo --- .../include/CGAL/OSQP_quadratic_program_traits.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 63d3abf0f02..7cbce58a670 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -44,9 +44,9 @@ namespace CGAL { \cgalModifBegin \note The `FT` type is provided for convenience. Internally, this FT type is converted - to `c_float` type that can be set either to `float` or `double`. By default, usually - the `double` type is used. After the optimization is complete, the `c_float` type is - converted back to `FT`. See more about `c_float` here. + to `c_float` type that can be set either to `float` or `double`. By default, the `double` + type is used. After the optimization is complete, the `c_float` type is converted back to `FT`. + See more about `c_float` here. \cgalModifEnd \cgalModels `QuadraticProgramTraits` From 20e02ec0184849fcc7ee32e1a8492dd0ee00da5d Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 29 Jun 2021 13:16:12 +0200 Subject: [PATCH 258/349] removed tmp modifs --- Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 7cbce58a670..5adb75eb791 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -42,12 +42,10 @@ namespace CGAL { \tparam FT number type that `FieldNumberType` - \cgalModifBegin \note The `FT` type is provided for convenience. Internally, this FT type is converted to `c_float` type that can be set either to `float` or `double`. By default, the `double` type is used. After the optimization is complete, the `c_float` type is converted back to `FT`. See more about `c_float` here. - \cgalModifEnd \cgalModels `QuadraticProgramTraits` */ From 7f19456fa237cb1d972c7583aafd61716e15142c Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 29 Jun 2021 13:57:17 +0200 Subject: [PATCH 259/349] better explained concurrency tag --- .../include/CGAL/Polygon_mesh_processing/distance.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 5161b616bcb..c658b02807f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -2330,7 +2330,8 @@ double bounded_error_Hausdorff_naive_impl( * * @tparam Concurrency_tag enables sequential versus parallel algorithm. * Possible values are `Sequential_tag` and `Parallel_tag`. - * Currently, parallel computation is not implemented, though. + * Currently, the parallel version is not implemented and the + * sequential version is always used whatever tag is chosen! * * @tparam TriangleMesh1 a model of the concept `FaceListGraph` * @tparam TriangleMesh2 a model of the concept `FaceListGraph` From 73581e15adccbbd02a7fc99144b5402ca3e026c3 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 29 Jun 2021 14:17:00 +0200 Subject: [PATCH 260/349] added named param for choosing between one sided and symmetric dist in the is_larger_HD function --- .../CGAL/boost/graph/parameters_interface.h | 1 + .../CGAL/Polygon_mesh_processing/distance.h | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/parameters_interface.h b/BGL/include/CGAL/boost/graph/parameters_interface.h index 1fa00d7848b..a69d0d4a965 100644 --- a/BGL/include/CGAL/boost/graph/parameters_interface.h +++ b/BGL/include/CGAL/boost/graph/parameters_interface.h @@ -123,6 +123,7 @@ CGAL_add_named_parameter(non_manifold_feature_map_t, non_manifold_feature_map, n CGAL_add_named_parameter(polyhedral_envelope_epsilon_t, polyhedral_envelope_epsilon, polyhedral_envelope_epsilon) CGAL_add_named_parameter(match_faces_t, match_faces, match_faces) CGAL_add_named_parameter(face_epsilon_map_t, face_epsilon_map, face_epsilon_map) +CGAL_add_named_parameter(use_one_sided_hausdorff_t, use_one_sided_hausdorff, use_one_sided_hausdorff) // List of named parameters that we use in the package 'Surface Mesh Simplification' CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index c658b02807f..e0dfa4e2faf 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -2530,7 +2530,16 @@ double bounded_error_symmetric_Hausdorff_distance( * * Instead of computing the full distance and checking it against the user-provided * value, this function early quits in case certain criteria show that the meshes - * do not satisfy the provided distance bound. + * do not satisfy the provided `distance_bound`. + * + * \cgalNamedParamsBegin + * \cgalParamNBegin{use_one_sided_hausdorff} + * \cgalParamDescription{a boolean tag indicating if the one-sided Hausdorff distance should be used.} + * \cgalParamType{Boolean} + * \cgalParamDefault{`true`} + * \cgalParamExtra{If this tag is set to `false`, the symmetric Hausdorff distance is used.} + * \cgalParamNEnd + * \cgalNamedParamsEnd * * @return Boolean `true` or `false` */ @@ -2568,7 +2577,8 @@ bool is_Hausdorff_distance_larger( parameters::get_parameter(np2, internal_np::match_faces), true); const bool match_faces = match_faces1 && match_faces2; - const bool use_one_sided = true; // TODO: Put in the NP! + const bool use_one_sided = parameters::choose_parameter( + parameters::get_parameter(np1, internal_np::use_one_sided_hausdorff), true); CGAL_precondition(error_bound >= 0.0); const FT error_threshold = static_cast(error_bound); CGAL_precondition(distance_bound >= 0.0); From d7782632fc658911cb56937abc94468b836def3b Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 29 Jun 2021 14:27:38 +0200 Subject: [PATCH 261/349] fixed ref to the bounded error distance function --- .../include/CGAL/Polygon_mesh_processing/distance.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index e0dfa4e2faf..73be7ed3545 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -2440,6 +2440,7 @@ double bounded_error_Hausdorff_distance( * \ingroup PMP_distance_grp * returns the maximum of `bounded_error_Hausdorff_distance(tm1, tm2, error_bound, np1, np2)` * and `bounded_error_Hausdorff_distance(tm2, tm1, error_bound, np2, np1)`. + * See more in `CGAL::PMP::bounded_error_Hausdorff_distance()`. * * This function optimizes all internal calls to shared data structures in order to * speed up the computation. @@ -2526,7 +2527,7 @@ double bounded_error_symmetric_Hausdorff_distance( * \ingroup PMP_distance_grp * returns `true` if the Hausdorff distance between two meshes is larger than * the user-defined max distance, otherwise it returns `false`. The distance used - * to compute the proximity of the meshes is the `bounded_error_Hausdorff_distance`. + * to compute the proximity of the meshes is the `CGAL::PMP::bounded_error_Hausdorff_distance()`. * * Instead of computing the full distance and checking it against the user-provided * value, this function early quits in case certain criteria show that the meshes From dcd8fe8fe46b99e8d462289e8265e3cb2aa6c782 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 29 Jun 2021 14:40:54 +0200 Subject: [PATCH 262/349] added missing user docs for is_hausdorff_larger and symmetric distance + better user ref --- .../doc/Polygon_mesh_processing/PackageDescription.txt | 1 + .../doc/Polygon_mesh_processing/Polygon_mesh_processing.txt | 6 ++++++ .../include/CGAL/Polygon_mesh_processing/distance.h | 5 +++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index 3bed198d608..e678bf1627f 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -203,6 +203,7 @@ The page \ref bgl_namedparameters "Named Parameters" describes their usage. \cgalCRPSection{Distance Functions} - `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` - `CGAL::Polygon_mesh_processing::bounded_error_symmetric_Hausdorff_distance()` +- `CGAL::Polygon_mesh_processing::is_Hausdorff_distance_larger()` - `CGAL::Polygon_mesh_processing::approximate_Hausdorff_distance()` - `CGAL::Polygon_mesh_processing::approximate_symmetric_Hausdorff_distance()` - `CGAL::Polygon_mesh_processing::approximate_max_distance_to_point_set()` diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 1180203240b..8757bba98d4 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -981,6 +981,12 @@ In the current implementation, the BVH used is an AABB-tree and not the swept sp volumes as used in the original implementation. This should explain the runtime difference observed with the original implementation. +The function `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` computes +the one-sided Hausdorff distance from `tm1` to `tm2`. This component also provides +the symmetric distance `CGAL::Polygon_mesh_processing::bounded_error_symmetric_Hausdorff_distance()` +and an utility function called `CGAL::Polygon_mesh_processing::is_Hausdorff_distance_larger()` +that returns `true` if the Hausdorff distance between two meshes is larger than the user-defined max distance. + \subsubsection BHDExample Bounded Hausdorff Distance Example In the following examples: (a) the distance of a tetrahedron to a remeshed diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index 73be7ed3545..b65c7a414b9 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -2440,12 +2440,12 @@ double bounded_error_Hausdorff_distance( * \ingroup PMP_distance_grp * returns the maximum of `bounded_error_Hausdorff_distance(tm1, tm2, error_bound, np1, np2)` * and `bounded_error_Hausdorff_distance(tm2, tm1, error_bound, np2, np1)`. - * See more in `CGAL::PMP::bounded_error_Hausdorff_distance()`. * * This function optimizes all internal calls to shared data structures in order to * speed up the computation. * * @return the symmetric Hausdorff distance + * @see `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` */ template< class Concurrency_tag, class TriangleMesh1, @@ -2527,7 +2527,7 @@ double bounded_error_symmetric_Hausdorff_distance( * \ingroup PMP_distance_grp * returns `true` if the Hausdorff distance between two meshes is larger than * the user-defined max distance, otherwise it returns `false`. The distance used - * to compute the proximity of the meshes is the `CGAL::PMP::bounded_error_Hausdorff_distance()`. + * to compute the proximity of the meshes is the bounded-error Hausdorff distance. * * Instead of computing the full distance and checking it against the user-provided * value, this function early quits in case certain criteria show that the meshes @@ -2543,6 +2543,7 @@ double bounded_error_symmetric_Hausdorff_distance( * \cgalNamedParamsEnd * * @return Boolean `true` or `false` +* @see `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` */ template< class Concurrency_tag, class TriangleMesh1, From 1ab891ee35366555521ef5c786f516b25a045a32 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Tue, 29 Jun 2021 15:49:05 +0200 Subject: [PATCH 263/349] Do not clear pos buffer of clipping plane. --- GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h index 0d44fbc3356..422f5ea7799 100644 --- a/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h +++ b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h @@ -245,7 +245,10 @@ public: void clear() { for (unsigned int i=0; i Date: Tue, 29 Jun 2021 17:39:30 +0200 Subject: [PATCH 264/349] Do not delete clipping plane frame, but only hide it, to keep its position. --- .../include/CGAL/Qt/Basic_viewer_qt.h | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h index 422f5ea7799..5e524650dd2 100644 --- a/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h +++ b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h @@ -962,7 +962,7 @@ protected: if(m_frame_plane) { for(int i=0; i< 16 ; i++) - clipping_mMatrix.data()[i] = m_frame_plane->matrix()[i]; + { clipping_mMatrix.data()[i] = m_frame_plane->matrix()[i]; } } rendering_program_clipping_plane.bind(); @@ -986,11 +986,11 @@ protected: QMatrix4x4 clipping_mMatrix; clipping_mMatrix.setToIdentity(); - if(m_frame_plane) - { - for(int i=0; i< 16 ; i++) - clipping_mMatrix.data()[i] = m_frame_plane->matrix()[i]; - } + if(m_frame_plane==nullptr) + { m_frame_plane=new CGAL::qglviewer::ManipulatedFrame; } + + for(int i=0; i< 16 ; i++) + { clipping_mMatrix.data()[i] = m_frame_plane->matrix()[i]; } QVector4D clipPlane = clipping_mMatrix * QVector4D(0.0, 0.0, 1.0, 0.0); QVector4D plane_point = clipping_mMatrix * QVector4D(0,0,0,1); if(!m_are_buffers_initialized) @@ -1426,17 +1426,10 @@ protected: { // toggle clipping plane m_use_clipping_plane = (m_use_clipping_plane + 1) % CLIPPING_PLANE_END_INDEX; - if (m_use_clipping_plane==CLIPPING_PLANE_OFF && m_frame_plane) - { - setManipulatedFrame(nullptr); - delete m_frame_plane; - m_frame_plane=nullptr; - } - else if (m_frame_plane==nullptr) - { - m_frame_plane=new CGAL::qglviewer::ManipulatedFrame; - setManipulatedFrame(m_frame_plane); - } + if (m_use_clipping_plane==CLIPPING_PLANE_OFF) + { setManipulatedFrame(nullptr); } + else + { setManipulatedFrame(m_frame_plane); } switch(m_use_clipping_plane) { From 8b3fab7a91a352893227f3a9c2a815ebee0f3834 Mon Sep 17 00:00:00 2001 From: Giles Bathgate Date: Tue, 29 Jun 2021 17:33:46 +0100 Subject: [PATCH 265/349] Remove code related to CGAL_NEF3_POINT_LOCATOR_NAIVE --- Nef_3/include/CGAL/Nef_3/Binary_operation.h | 12 -- Nef_3/include/CGAL/Nef_3/SNC_point_locator.h | 136 ------------------- 2 files changed, 148 deletions(-) diff --git a/Nef_3/include/CGAL/Nef_3/Binary_operation.h b/Nef_3/include/CGAL/Nef_3/Binary_operation.h index 58c1af82722..61c86bca0d7 100644 --- a/Nef_3/include/CGAL/Nef_3/Binary_operation.h +++ b/Nef_3/include/CGAL/Nef_3/Binary_operation.h @@ -530,18 +530,6 @@ class Binary_operation : public CGAL::SNC_decorator { } CGAL_NEF_TRACEN("\nnumber of vertices (so far...) = " << this->sncp()->number_of_vertices()); -#elif defined CGAL_NEF3_INTERSECTION_NAIVE - - CGAL::SNC_point_locator_naive pln1; - CGAL::SNC_point_locator_naive pln2; - pln1.initialize(const_cast(&snc1)); - pln2.initialize(const_cast(&snc2)); - Halfedge_iterator e0; - CGAL_forall_edges(e0,const_cast(snc1)) - pln2.intersect_with_edges_and_facets(e0,call_back0); - CGAL_forall_edges(e0,const_cast(snc2)) - pln1.intersect_with_facets( e0, call_back1); - #else CGAL_NEF_TRACEN("intersection by fast box intersection"); binop_intersection_test_segment_tree binop_box_intersection; diff --git a/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h b/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h index 26116cc643a..36013bf3538 100644 --- a/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h +++ b/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h @@ -870,142 +870,6 @@ private: SNC_intersection is; }; -#ifdef CGAL_NEF3_POINT_LOCATOR_NAIVE -template -class SNC_point_locator_naive : - public SNC_ray_shooter, - public SNC_point_locator -{ - typedef typename SNC_decorator::SNC_structure SNC_structure; - typedef SNC_ray_shooter Base; - typedef SNC_point_locator_naive Self; - typedef SNC_point_locator SNC_point_locator; - typedef CGAL::SNC_intersection SNC_intersection; - typedef typename SNC_decorator::Decorator_traits Decorator_traits; - typedef typename Decorator_traits::SM_decorator SM_decorator; - -public: - typedef typename SNC_decorator::Object_handle Object_handle; - typedef typename SNC_decorator::Point_3 Point_3; - typedef typename SNC_decorator::Segment_3 Segment_3; - typedef typename SNC_decorator::Ray_3 Ray_3; - typedef typename SNC_structure::Aff_transformation_3 - Aff_transformation_3; - - typedef typename Decorator_traits::Vertex_handle Vertex_handle; - typedef typename Decorator_traits::Halfedge_handle Halfedge_handle; - typedef typename Decorator_traits::Halffacet_handle Halffacet_handle; - typedef typename Decorator_traits::Volume_handle Volume_handle; - typedef typename Decorator_traits::Vertex_iterator Vertex_iterator; - typedef typename Decorator_traits::Halfedge_iterator Halfedge_iterator; - typedef typename Decorator_traits::Halffacet_iterator Halffacet_iterator; - -public: - SNC_point_locator_naive() : initialized(false) {} - virtual void initialize(SNC_structure* W) { - CGAL_NEF_TIMER(ct_t.start()); - this->version_ = std::string("Naive Point Locator (tm)"); - CGAL_NEF_CLOG(version()); - CGAL_assertion( W != nullptr); - Base::initialize(W); - initialized = true; - CGAL_NEF_TIMER(ct_t.stop()); - } - - virtual Self* clone() const { - return new Self; - } - - virtual bool update( Unique_hash_map& V, - Unique_hash_map& E, - Unique_hash_map& F) { - CGAL_NEF_TIMER(ct_t.start()); - CGAL_assertion( initialized); - CGAL_NEF_TIMER(ct_t.stop()); - return false; - } - - virtual ~SNC_point_locator_naive() {} - - virtual Object_handle locate(const Point_3& p) const { - CGAL_NEF_TIMER(pl_t.start()); - CGAL_assertion( initialized); - CGAL_NEF_TIMER(pl_t.stop()); - return Base::locate(p); - } - - virtual Object_handle shoot(const Ray_3& r, int mask=0) const { - CGAL_NEF_TIMER(rs_t.start()); - CGAL_assertion( initialized); - CGAL_NEF_TIMER(rs_t.stop()); - return Base::shoot(r); - } - - virtual void transform(const Aff_transformation_3& aff) {} - - virtual void intersect_with_edges_and_facets(Halfedge_handle e0, - const typename SNC_point_locator::Intersection_call_back& call_back) const { - intersect_with_edges(e0,call_back); - intersect_with_facets(e0,call_back); - } - - virtual void intersect_with_edges( Halfedge_handle e0, - const typename SNC_point_locator::Intersection_call_back& call_back) const { - CGAL_NEF_TIMER(it_t.start()); - CGAL_assertion( initialized); - CGAL_NEF_TRACEN( "intersecting edge: "<< Segment_3(e0->source()->point(), - e0->twin()->source()->point())); - SNC_intersection is(*this->sncp()); - Segment_3 s(Segment_3(e0->source()->point(),e0->twin()->source()->point())); - Halfedge_iterator e; - CGAL_forall_edges( e, *this->sncp()) { - -#ifdef CGAL_NEF3_DUMP_STATISTICS - ++number_of_intersection_candidates; -#endif - - Point_3 q; - if( is.does_intersect_internally( s, Segment_3(e->source()->point(), - e->twin()->source()->point()), q)) { - q = normalized(q); - CGAL_NEF_TRACEN("edge intersects edge "<< Segment_3(e->source()->point(), - e->twin()->source()->point()) <<" on "<source()->point(), - e0->twin()->source()->point())); - SNC_intersection is(*this->sncp()); - Segment_3 s(Segment_3(e0->source()->point(), - e0->twin()->source()->point())); - Halffacet_iterator f; - CGAL_forall_facets( f, *this->sncp()) { - -#ifdef CGAL_NEF3_DUMP_STATISTICS - ++number_of_intersection_candidates; -#endif - - Point_3 q; - if( is.does_intersect_internally( s, f, q) ) { - q = normalized(q); - CGAL_NEF_TRACEN("edge intersects facet on plane "<plane()<<" on "< Date: Tue, 29 Jun 2021 19:54:13 +0200 Subject: [PATCH 266/349] trailling --- GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h index 5e524650dd2..474420f328a 100644 --- a/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h +++ b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h @@ -962,7 +962,7 @@ protected: if(m_frame_plane) { for(int i=0; i< 16 ; i++) - { clipping_mMatrix.data()[i] = m_frame_plane->matrix()[i]; } + { clipping_mMatrix.data()[i] = m_frame_plane->matrix()[i]; } } rendering_program_clipping_plane.bind(); @@ -988,7 +988,7 @@ protected: clipping_mMatrix.setToIdentity(); if(m_frame_plane==nullptr) { m_frame_plane=new CGAL::qglviewer::ManipulatedFrame; } - + for(int i=0; i< 16 ; i++) { clipping_mMatrix.data()[i] = m_frame_plane->matrix()[i]; } QVector4D clipPlane = clipping_mMatrix * QVector4D(0.0, 0.0, 1.0, 0.0); From c71138c3b07f0cd124c1591a0b93d1ae2bccb27e Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Wed, 30 Jun 2021 18:40:13 +0200 Subject: [PATCH 267/349] Regenerate clipping plane in initialize_buffers, to adapt it to the possible new bounding box; add methods to retreive the clipping plane as a cgal plane_3. --- .../include/CGAL/Qt/Basic_viewer_qt.h | 85 ++++++++++--------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h index 474420f328a..02d557a8a44 100644 --- a/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h +++ b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h @@ -316,6 +316,17 @@ public: m_buffer_for_colored_lines.has_zero_z(); } + Local_kernel::Plane_3 clipping_plane() const + { + CGAL::qglviewer::Vec n=m_frame_plane->inverseTransformOf + (CGAL::qglviewer::Vec(0.f, 0.f, 1.f)); + const CGAL::qglviewer::Vec& pos=m_frame_plane->position(); + return Local_kernel::Plane_3(n[0], n[1], n[2], -n*pos); + } + + bool is_clipping_plane_enabled() const + { return (m_use_clipping_plane!=CLIPPING_PLANE_OFF); } + template void add_point(const KPoint& p) { m_buffer_for_mono_points.add_point(p); } @@ -543,11 +554,9 @@ protected: if(!rendering_program_face.link()) { std::cerr<<"linking Program FAILED"<matrix()[i]; } - } + for(int i=0; i< 16 ; i++) + { clipping_mMatrix.data()[i] = m_frame_plane->matrix()[i]; } rendering_program_clipping_plane.bind(); int vpLocation = rendering_program_clipping_plane.uniformLocation("vp_matrix"); @@ -986,9 +994,6 @@ protected: QMatrix4x4 clipping_mMatrix; clipping_mMatrix.setToIdentity(); - if(m_frame_plane==nullptr) - { m_frame_plane=new CGAL::qglviewer::ManipulatedFrame; } - for(int i=0; i< 16 ; i++) { clipping_mMatrix.data()[i] = m_frame_plane->matrix()[i]; } QVector4D clipPlane = clipping_mMatrix * QVector4D(0.0, 0.0, 1.0, 0.0); @@ -1380,35 +1385,40 @@ protected: bb.ymax(), bb.zmax())); - // init clipping plane array - auto generate_clipping_plane = [this](qreal size, int nbSubdivisions) - { - for (int i = 0; i <= nbSubdivisions; i++) - { - const float pos = float(size*(2.0*i/nbSubdivisions-1.0)); - arrays[POS_CLIPPING_PLANE].push_back(pos); - arrays[POS_CLIPPING_PLANE].push_back(float(-size)); - arrays[POS_CLIPPING_PLANE].push_back(0.f); - - arrays[POS_CLIPPING_PLANE].push_back(pos); - arrays[POS_CLIPPING_PLANE].push_back(float(+size)); - arrays[POS_CLIPPING_PLANE].push_back(0.f); - - arrays[POS_CLIPPING_PLANE].push_back(float(-size)); - arrays[POS_CLIPPING_PLANE].push_back(pos); - arrays[POS_CLIPPING_PLANE].push_back(0.f); - - arrays[POS_CLIPPING_PLANE].push_back(float(size)); - arrays[POS_CLIPPING_PLANE].push_back(pos); - arrays[POS_CLIPPING_PLANE].push_back(0.f); - } - }; - clipping_plane_rendering_size = ((bb.xmax() - bb.xmin()) + (bb.ymax() - bb.ymin()) + (bb.zmax() - bb.zmin())) / 3; - generate_clipping_plane(3.0 * clipping_plane_rendering_size, 30); + m_frame_plane=new CGAL::qglviewer::ManipulatedFrame; this->showEntireScene(); } + void generate_clipping_plane() + { + qreal size=((bounding_box().xmax() - bounding_box().xmin()) + + (bounding_box().ymax() - bounding_box().ymin()) + + (bounding_box().zmax() - bounding_box().zmin())); + const unsigned int nbSubdivisions=30; + + arrays[POS_CLIPPING_PLANE].clear(); + for (unsigned int i=0; i<=nbSubdivisions; ++i) + { + const float pos = float(size*(2.0*i/nbSubdivisions-1.0)); + arrays[POS_CLIPPING_PLANE].push_back(pos); + arrays[POS_CLIPPING_PLANE].push_back(float(-size)); + arrays[POS_CLIPPING_PLANE].push_back(0.f); + + arrays[POS_CLIPPING_PLANE].push_back(pos); + arrays[POS_CLIPPING_PLANE].push_back(float(+size)); + arrays[POS_CLIPPING_PLANE].push_back(0.f); + + arrays[POS_CLIPPING_PLANE].push_back(float(-size)); + arrays[POS_CLIPPING_PLANE].push_back(pos); + arrays[POS_CLIPPING_PLANE].push_back(0.f); + + arrays[POS_CLIPPING_PLANE].push_back(float(size)); + arrays[POS_CLIPPING_PLANE].push_back(pos); + arrays[POS_CLIPPING_PLANE].push_back(0.f); + } + } + void negate_all_normals() { m_buffer_for_mono_faces.negate_normals(); @@ -1433,7 +1443,7 @@ protected: switch(m_use_clipping_plane) { - case CLIPPING_PLANE_OFF: displayMessage(QString("Draw clipping = flase")); break; + case CLIPPING_PLANE_OFF: displayMessage(QString("Draw clipping = false")); break; case CLIPPING_PLANE_SOLID_HALF_TRANSPARENT_HALF: clipping_plane_rendering=true; displayMessage(QString("Draw clipping = solid half & transparent half")); break; case CLIPPING_PLANE_SOLID_HALF_WIRE_HALF: displayMessage(QString("Draw clipping = solid half & wireframe half")); break; case CLIPPING_PLANE_SOLID_HALF_ONLY: displayMessage(QString("Draw clipping = solid half only")); break; @@ -1785,7 +1795,6 @@ protected: // variables for clipping plane bool clipping_plane_rendering = true; // will be toggled when alt+c is pressed, which is used for indicating whether or not to render the clipping plane ; float clipping_plane_rendering_transparency = 0.5f; // to what extent the transparent part should be rendered; - float clipping_plane_rendering_size; // to what extent the size of clipping plane should be rendered; std::vector > m_texts; }; From f6c6c2ea2452101709ae07a240e432ff955a8f32 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 1 Jul 2021 10:45:02 +0200 Subject: [PATCH 268/349] updated changes.md --- Installation/CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 216493431f7..e5f4cf23726 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -1,6 +1,11 @@ Release History =============== +### [CGAL and Solvers](https://doc.cgal.org/5.4/Manual/packages.html#PkgSolverInterface) + +- Added the [OSQP solver](https://osqp.org/) support. This solver enables to efficiently compute the convex Quadratic Programming (QP) problems arising in the context of several packages. + + [Release 5.3](https://github.com/CGAL/cgal/releases/tag/v5.3) ----------- From 32689639144ee3ee98002778b0ad5ced91e5390e Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 1 Jul 2021 11:36:26 +0200 Subject: [PATCH 269/349] Remove bibref in Three package as it is not in the package overview. --- Three/doc/Three/PackageDescription.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Three/doc/Three/PackageDescription.txt b/Three/doc/Three/PackageDescription.txt index 09d6ce5f654..e8173a1e95e 100644 --- a/Three/doc/Three/PackageDescription.txt +++ b/Three/doc/Three/PackageDescription.txt @@ -12,7 +12,6 @@ \cgalPkgSummaryEnd \cgalPkgShortInfoBegin \cgalPkgSince{4.8} -\cgalPkgBib{cgal:rlfg-pd} \cgalPkgLicense{\ref licensesGPL "GPL"} \cgalPkgShortInfoEnd \cgalPkgDescriptionEnd From cb9747b5b49f44fc825ef8dcdc1563425fb8d57d Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 1 Jul 2021 13:20:21 +0200 Subject: [PATCH 270/349] updated changes.md --- Installation/CHANGES.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index dd07172543d..7ac7d589dba 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -7,7 +7,17 @@ Release date: December 2021 ### [Polygon Mesh Processing](https://doc.cgal.org/5.4/Manual/packages.html#PkgPolygonMeshProcessing) -- Added the function `CGAL::Polygon_mesh_processing::match_faces()`, which, given two polygon meshes, identifies their common faces as well as as faces present in only either of them. +- Added the function `CGAL::Polygon_mesh_processing::match_faces()`, which, given two polygon meshes, + identifies their common faces as well as faces present in only either of them. + +- Added the functions: `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()` that + computes an estimate of the one-sided Hausdorff distance between two triangle meshes which + is bounded by a user-specified error bound; `CGAL::Polygon_mesh_processing::bounded_error_symmetric_Hausdorff_distance()` that computes + an estimate of the symmetric Hausdorff distance bounded by a user-specified error bound; + and `CGAL::Polygon_mesh_processing::is_Hausdorff_distance_larger()` that returns `true` + if the bounded-error Hausdorff distance between two meshes is larger than the user-specified + max distance. + [Release 5.3](https://github.com/CGAL/cgal/releases/tag/v5.3) ----------- From 1a304f526a7b2076991f07a843a99a39b902bab7 Mon Sep 17 00:00:00 2001 From: Giles Bathgate Date: Thu, 1 Jul 2021 14:28:36 +0100 Subject: [PATCH 271/349] Fix grammar in Triangulation_on_sphere_2 --- .../doc/Triangulation_on_sphere_2/Triangulation_on_sphere_2.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Triangulation_on_sphere_2/doc/Triangulation_on_sphere_2/Triangulation_on_sphere_2.txt b/Triangulation_on_sphere_2/doc/Triangulation_on_sphere_2/Triangulation_on_sphere_2.txt index 56dcd30e101..9b0f6801436 100644 --- a/Triangulation_on_sphere_2/doc/Triangulation_on_sphere_2/Triangulation_on_sphere_2.txt +++ b/Triangulation_on_sphere_2/doc/Triangulation_on_sphere_2/Triangulation_on_sphere_2.txt @@ -12,7 +12,7 @@ namespace CGAL {
-This chapter describes two-dimensional triangulations on the sphere of \cgal. It is organized as follows: +This chapter describes two-dimensional triangulations on the sphere. It is organized as follows:
  • Section \ref Section_2D_ToS_Definitions introduces the main definitions about triangulations on the sphere.
  • Section \ref Section_2D_ToS_Implementation details the way two-dimensional triangulations on the sphere From 01d6ce249ca2fd0d1787441225b5b8f96befc974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 6 Jul 2021 10:11:39 +0200 Subject: [PATCH 272/349] Minor doc fix --- .../Concepts/AdaptationPolicy_2.h | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Voronoi_diagram_2/doc/Voronoi_diagram_2/Concepts/AdaptationPolicy_2.h b/Voronoi_diagram_2/doc/Voronoi_diagram_2/Concepts/AdaptationPolicy_2.h index e653378c469..eb747a669a4 100644 --- a/Voronoi_diagram_2/doc/Voronoi_diagram_2/Concepts/AdaptationPolicy_2.h +++ b/Voronoi_diagram_2/doc/Voronoi_diagram_2/Concepts/AdaptationPolicy_2.h @@ -65,14 +65,12 @@ typedef Delaunay_graph::Edge Delaunay_edge; /*! */ -typedef Delaunay_graph::All_edges_iterator -All_Delaunay_edges_iterator; +typedef Delaunay_graph::All_edges_iterator All_Delaunay_edges_iterator; /*! */ -typedef Delaunay_graph::Finite_edges_iterator -Finite_Delaunay_edges_iterator; +typedef Delaunay_graph::Finite_edges_iterator Finite_Delaunay_edges_iterator; /*! @@ -93,13 +91,9 @@ model of the concepts `DefaultConstructible`, `bool operator()(Delaunay_graph dg, Delaunay_edge_circulator ec)` -`bool operator()(Delaunay_graph dg,` +`bool operator()(Delaunay_graph dg, All_Delaunay_edges_iterator eit)` -`All_Delaunay_edges_iterator eit)` - -`bool operator()(Delaunay_graph dg,` - -`Finite_Delaunay_edges_iterator eit)` +`bool operator()(Delaunay_graph dg, Finite_Delaunay_edges_iterator eit)` The functor returns `true` iff the edge is rejected. */ From 326a05590f3646ebacc2ed7f3c95c68254f57818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 6 Jul 2021 10:11:49 +0200 Subject: [PATCH 273/349] Restore some typedefs to please tests --- .../CGAL/Voronoi_diagram_2/Cached_degeneracy_testers.h | 6 ++++++ .../Delaunay_triangulation_on_sphere_degeneracy_testers.h | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Cached_degeneracy_testers.h b/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Cached_degeneracy_testers.h index 22a07f94aa1..e9ddbd43390 100644 --- a/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Cached_degeneracy_testers.h +++ b/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Cached_degeneracy_testers.h @@ -52,6 +52,9 @@ public: typedef typename Edge_rejector::Delaunay_graph Delaunay_graph; typedef typename Edge_rejector::Edge Edge; typedef typename Edge_rejector::Face_handle Face_handle; + typedef typename Edge_rejector::Edge_circulator Edge_circulator; + typedef typename Edge_rejector::All_edges_iterator All_edges_iterator; + typedef typename Edge_rejector::Finite_edges_iterator Finite_edges_iterator; typedef typename Edge_rejector::result_type result_type; private: @@ -155,6 +158,9 @@ public: typedef typename Edge_rejector::Delaunay_graph Delaunay_graph; typedef typename Edge_rejector::Edge Edge; typedef typename Edge_rejector::Face_handle Face_handle; + typedef typename Edge_rejector::Edge_circulator Edge_circulator; + typedef typename Edge_rejector::All_edges_iterator All_edges_iterator; + typedef typename Edge_rejector::Finite_edges_iterator Finite_edges_iterator; typedef typename Edge_rejector::result_type result_type; private: diff --git a/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Delaunay_triangulation_on_sphere_degeneracy_testers.h b/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Delaunay_triangulation_on_sphere_degeneracy_testers.h index 74c0de1cccb..6bb29809e55 100644 --- a/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Delaunay_triangulation_on_sphere_degeneracy_testers.h +++ b/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Delaunay_triangulation_on_sphere_degeneracy_testers.h @@ -37,7 +37,9 @@ public: typedef typename Delaunay_graph::Edge Edge; typedef typename Delaunay_graph::Face_handle Face_handle; - + typedef typename Delaunay_graph::Edge_circulator Edge_circulator; + typedef typename Delaunay_graph::All_edges_iterator All_edges_iterator; + typedef typename Delaunay_graph::Finite_edges_iterator Finite_edges_iterator; typedef bool result_type; private: From 4d2bf2f15edc4d549c2fc6edd2b8f05d63994aa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 6 Jul 2021 10:12:18 +0200 Subject: [PATCH 274/349] Add a test for ToS2-based VD2 --- .../test/Voronoi_diagram_2/CMakeLists.txt | 21 +- .../test/Voronoi_diagram_2/data/radar.xyz | 20950 ++++++++++++++++ .../test/Voronoi_diagram_2/vda_tos2.cpp | 201 + 3 files changed, 21164 insertions(+), 8 deletions(-) create mode 100644 Voronoi_diagram_2/test/Voronoi_diagram_2/data/radar.xyz create mode 100644 Voronoi_diagram_2/test/Voronoi_diagram_2/vda_tos2.cpp diff --git a/Voronoi_diagram_2/test/Voronoi_diagram_2/CMakeLists.txt b/Voronoi_diagram_2/test/Voronoi_diagram_2/CMakeLists.txt index b99bc919a9b..ab76fa8aad6 100644 --- a/Voronoi_diagram_2/test/Voronoi_diagram_2/CMakeLists.txt +++ b/Voronoi_diagram_2/test/Voronoi_diagram_2/CMakeLists.txt @@ -8,11 +8,16 @@ find_package(CGAL REQUIRED) include_directories(BEFORE "include") -# create a target per cppfile -file( - GLOB cppfiles - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) -foreach(cppfile ${cppfiles}) - create_single_source_cgal_program("${cppfile}") -endforeach() +create_single_source_cgal_program("vda_ag.cpp") +create_single_source_cgal_program("vda_dt.cpp") +create_single_source_cgal_program("vda_pt.cpp") +create_single_source_cgal_program("vda_rt.cpp") +create_single_source_cgal_program("vda_sdg.cpp") + +find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) +include(CGAL_Eigen3_support) + +if(TARGET CGAL::Eigen3_support) + create_single_source_cgal_program("vda_tos2.cpp") + target_link_libraries(vda_tos2 PUBLIC CGAL::Eigen3_support) +endif() diff --git a/Voronoi_diagram_2/test/Voronoi_diagram_2/data/radar.xyz b/Voronoi_diagram_2/test/Voronoi_diagram_2/data/radar.xyz new file mode 100644 index 00000000000..25dc3fbf276 --- /dev/null +++ b/Voronoi_diagram_2/test/Voronoi_diagram_2/data/radar.xyz @@ -0,0 +1,20950 @@ +-99.7385919424 5.52386828797 -4.65834267608 +-99.7287156624 6.97371114549 -2.35597648336 +-99.2838348297 6.7162681875 -9.87987262748 +-99.2573830768 11.9235855464 2.40832150206 +-99.2121060152 12.3047712224 2.35597648336 +-99.2099569164 12.322086814 2.35597648336 +-99.0821903002 4.93260362911 -12.5852686403 +-99.0683971079 12.5503838637 5.28588302466 +-98.97015634 2.79906117641 -14.0382837472 +-98.8924217999 1.34636189967 -14.780941113 +-98.8874901975 1.32903247771 -14.8154633781 +-98.8872567315 1.34629158031 -14.8154633781 +-98.84198762 -14.3842517201 -4.83267894527 +-98.4034708143 14.302897427 10.5916975449 +-98.32342093 18.1699236326 -1.5358293575 +-98.3228877602 18.1698251041 -1.57073173118 +-98.3157987179 14.8688665975 10.6264071336 +-98.2412989025 0.857338827114 -18.6524036009 +-98.1165276418 14.8737640158 12.3255080026 +-98.1001954478 14.9238378812 12.3947858395 +-98.0899160503 15.0624329764 12.3081876034 +-98.0522828925 -12.8740096019 -14.832723834 +-98.0506948105 15.3017351844 12.3255080026 +-97.8482281356 17.8702595391 10.3139747302 +-97.7387742206 19.5656162492 8.01989243289 +-97.7336747392 -13.8747569416 -15.9881187692 +-97.7288255812 -13.9088715839 -15.9881187692 +-97.5388483357 15.7105069634 15.4710386299 +-97.5198572073 -14.9748962197 -16.2981573648 +-97.5146240412 -15.0089361586 -16.2981573648 +-97.5002245266 5.02445543788 -21.6439613938 +-97.401793514 22.6302694645 -0.872653549837 +-97.4014908696 22.6301991483 -0.907558751868 +-97.4013350969 22.6301629561 -0.92501131168 +-97.3169847332 19.216334553 12.6545236492 +-97.2124787805 16.7041589345 16.4531165327 +-97.128511117 -6.5023510993 -22.8860603507 +-96.9623466537 -15.1318881953 -19.2179419046 +-96.8407906238 -3.17869926892 -24.7337247968 +-96.5836180881 21.0056651845 15.1778373678 +-96.5502738771 17.2851661305 19.474795149 +-96.4985628449 17.5715600551 19.474795149 +-96.4719330903 -12.2385614663 -23.3105928507 +-96.4336650965 -12.4732055623 -23.3445363856 +-96.3917121827 -12.9470255469 -23.2596722241 +-96.3074524313 21.4037591739 16.3325962242 +-96.1600755702 -13.5144172857 -23.8872432853 +-96.1553522903 -13.5479826602 -23.8872432853 +-96.115721896 -13.8847362443 -23.8533457579 +-96.1001926131 -13.9338647887 -23.8872432853 +-96.0633762325 -0.0335324454787 -27.7817678054 +-96.0489886259 -7.35684186995 -26.8415473035 +-95.930320774 -14.422478507 -24.2768546132 +-95.9116865372 0.970938503622 -28.284371374 +-95.8906604154 1.08789170627 -28.3513268955 +-95.7920278525 -0.217345589782 -28.7026159226 +-95.7857516747 2.45805117178 -28.6190104747 +-95.7476291942 24.3523811445 15.4710386299 +-95.7296030255 21.2578030415 19.5946144243 +-95.7254045023 1.11943576124 -28.9031796944 +-95.6968262643 4.04434905258 -28.736051985 +-95.6503751891 -15.4405884613 -24.7506354292 +-95.6205551281 -15.6241954301 -24.7506354292 +-95.619785047 -15.521280914 -24.8182704141 +-95.6058612034 2.16960049958 -29.2371704723 +-95.58358341 -15.875183154 -24.7337247968 +-95.5823507432 -10.4342064645 -27.479839189 +-95.5397051827 22.3206927654 19.3378232506 +-95.5050628457 23.8120865807 17.6569392453 +-95.496301864 -1.7502570758 -29.6208192067 +-95.4137788042 5.16742554726 -29.4874299918 +-95.4040346297 2.96485775804 -29.8207946716 +-95.32960344 -17.6682976553 -24.4968970675 +-95.2589406357 24.1042176451 -18.5666615386 +-95.2568910029 1.94544968741 -30.3700500819 +-95.2322175204 29.0608952077 9.28919349936 +-95.2246795594 4.24086011077 -30.236989075 +-95.2103270992 -24.0565570048 -18.8752663223 +-95.1884422117 29.1928835853 9.32394858855 +-95.1452714542 4.23732364662 -30.4864299028 +-95.0490373133 2.37274636363 -30.9846829984 +-94.9996166915 2.60379979766 -31.1174075894 +-94.9896559639 2.57034455091 -31.1505792684 +-94.9600074457 -1.98912859683 -31.2832279878 +-94.9281032233 4.27745598089 -31.1505792684 +-94.8858091781 24.4508170304 19.9709980514 +-94.8093960082 20.9319506336 -23.9380841177 +-94.6685420008 22.5183097988 -23.0389426677 +-94.632055268 -30.6565440431 10.2445313747 +-94.4768458142 0.412235622721 -32.7712628196 +-94.47520124 3.01851958188 -32.6393150999 +-94.2635098349 -9.95739835756 -31.8628456287 +-94.2600283044 -9.99030192248 -31.8628456287 +-94.2264628151 -9.93685612404 -31.9786271707 +-94.1696459665 -17.4193138843 28.7861995122 +-93.9869562345 21.2670769332 -26.7238376078 +-93.9791281523 -34.1684592955 -0.663220253582 +-93.9667049272 21.3142206593 -26.7574730274 +-93.8772919837 -33.4651289829 8.193850863 +-93.8244988406 32.856872208 10.8346373271 +-93.7552339236 20.270599078 -28.2676303383 +-93.6309842119 -9.26309934079 -33.8737920245 +-93.5971987738 -8.68274960925 -34.1199976689 +-93.5395512019 -2.09004134557 -35.2984997999 +-93.4946805438 30.5226538148 -18.0862465458 +-93.4330114362 -8.50307014939 -34.6117057077 +-93.4290331297 29.7271965669 19.6801817247 +-93.4224811388 29.7251118581 19.7144044521 +-93.3763150511 -35.1536596396 6.71446210994 +-93.336740065 -35.2317872846 6.85376675848 +-93.3111399524 34.3688004797 10.5743422663 +-93.2971718935 19.3209154724 -30.3700500819 +-93.2912132085 32.615290671 -15.264087019 +-93.2867853244 19.3187645174 -30.4033060925 +-93.2607691751 19.3133768319 -30.4864299028 +-93.2435962605 19.3437669722 -30.5196729298 +-93.1693557567 32.1171644 16.9693517489 +-93.1568475054 -31.8947177967 -17.4507518327 +-93.1320153303 -28.3311835641 -22.8860603507 +-93.0531555608 -16.5417813365 -32.6723080054 +-93.0504252643 -16.5245429231 -32.6888029655 +-93.0264186209 -31.9407861606 -18.0519145251 +-93.0007308864 -31.9864117765 -18.10341173 +-92.9466273392 -7.83762059643 -36.0485252079 +-92.9102760606 -7.58964073735 -36.1949990445 +-92.8796780321 -7.88095482001 -36.211268409 +-92.804948472 33.4484359196 -16.3842507806 +-92.7315041388 33.6598925707 -16.3670330935 +-92.6844156856 33.7893373231 -16.3670330935 +-92.6699304646 33.820708361 -16.3842507806 +-92.603707681 17.6148554073 -33.3806859234 +-92.5926667368 17.5792670496 -33.4300379384 +-92.3395516036 16.6644265514 -34.5789545441 +-92.3320549637 35.0183474899 -15.7641036938 +-92.3194370504 -38.2777229534 3.45506413745 +-92.2647822393 -38.4061220333 3.48994967025 +-92.1752772946 36.8301632739 12.1349630774 +-92.1733091291 36.8293768607 12.1522872021 +-92.1244862816 -38.7823404705 3.00151544833 +-91.8409520268 21.7949235163 33.0184923902 +-91.6169322309 -36.8855049922 -15.6779223773 +-91.6091215172 -36.919526491 -15.643446504 +-91.6015118248 -36.9164596977 -15.6951595979 +-91.4440764072 13.9439127872 -37.9940546168 +-91.2605322662 38.2312651504 -14.4874295681 +-91.188418146 20.6672955964 -35.4617440174 +-91.0311970321 19.2994664963 -36.6176427403 +-91.0201355992 21.7176329976 -35.2658380374 +-91.0006874377 -27.5093918096 -31.0178698193 +-90.9965718102 39.7932570901 -11.6670737099 +-90.7378580075 27.6028699938 -31.6973609677 +-90.6007023037 40.8697186085 -11.0081262225 +-90.4443290183 42.6177276685 1.88484397154 +-90.4222226287 23.7724364697 -35.4780625061 +-90.4044551983 -42.1562897903 -7.06269859312 +-90.352774363 23.6698999646 -35.7227098715 +-90.3284509724 26.4994762887 -33.7423873096 +-90.291467866 40.9960354393 -12.9141747261 +-90.234168149 42.7113136038 -5.79125104807 +-90.1833312071 41.8234519753 -10.8519877105 +-90.1798892207 41.8218557185 -10.8866874852 +-90.1225526447 25.3662546667 -35.1351480571 +-90.115173032 20.0605742499 -38.429532266 +-90.0370117461 22.0818890966 -37.4930218808 +-90.0268097639 22.6632901938 -37.1691915613 +-89.9854492461 21.6534332095 -37.8648617352 +-89.9790572377 24.2445208202 -36.2763348316 +-89.9650303716 21.6817446771 -37.897166886 +-89.9522354132 41.6209364599 13.2775371347 +-89.4049207598 44.2449259836 -7.01046850308 +-89.3894709206 44.2761314921 -7.01046850308 +-89.3280920814 43.9161460323 9.58457525202 +-89.2841065359 44.068800803 9.28919349936 +-89.1846728663 -31.0573890139 32.8866646739 +-88.9153809096 45.2655612611 6.71446210994 +-88.8372945246 -21.6890536836 40.4662829014 +-88.8094001234 -32.7283024669 -32.2761315426 +-88.6671534397 45.9018027609 -5.58215049932 +-88.5937337001 46.0600365692 -5.4427364735 +-88.4789351569 46.1573991765 -6.4009792035 +-88.4464135795 -36.0943127975 29.5708050044 +-88.3432112121 46.2436294223 -7.55008414395 +-88.3027482906 42.6301907264 -19.6288431388 +-88.2377385202 45.5038938538 11.9790293837 +-88.2020332824 46.5430108432 -7.35863210847 +-88.0244171061 47.158725439 -5.26845405152 +-88.0210327042 -4.04319554842 47.2858369012 +-87.915343251 44.8917863231 -15.9881187692 +-87.7876826945 45.2136276104 -15.7813385186 +-87.5822256617 44.1067436307 -19.5946144243 +-87.5091703759 -32.1624284414 -36.1624570082 +-87.4866954414 -32.2235135246 -36.1624570082 +-87.4593210811 34.4158814927 -34.1528074559 +-87.4309481131 -27.9027748025 39.7147890635 +-87.4244569782 44.8722177641 -18.532360751 +-87.4232436049 46.777752554 13.0007055036 +-87.4186964574 44.8692610704 -18.5666615386 +-87.2323347985 46.5777290086 14.8672433897 +-87.2214149757 48.7064532012 -4.48399221677 +-87.1921140362 -3.16671335719 -48.8621241497 +-87.0110469241 -32.0655680337 37.4282922379 +-86.9859595209 -32.0390801016 37.5092014374 +-86.9803989927 -32.2613455524 37.3311635797 +-86.9644209977 -32.3417782601 37.2987782576 +-86.9613657641 -32.0300216128 37.5739082333 +-86.9422626343 -32.4199306965 37.282583892 +-86.9132407521 48.2759945249 -10.7478804698 +-86.8977274373 -32.5761903926 37.2501917543 +-86.8745708683 -32.6193996383 37.2663883908 +-86.8391948588 -32.2089724269 37.7032668542 +-86.7736584012 -32.7025250984 37.4282922379 +-86.7622377802 -32.7328128263 37.4282922379 +-86.6952757477 -32.7248360248 37.5900820721 +-86.6830387427 -32.495707968 37.8163953596 +-86.6499962116 -36.1576630576 -34.4151356056 +-86.6484683793 -32.5690180831 37.8325519707 +-86.6278018402 -36.1484017 -34.4806757891 +-86.5568175582 47.8213593302 -14.8672433897 +-86.5535464046 49.1692577148 -9.5324551175 +-86.5520984839 49.1684351814 -9.54982878676 +-86.5475959703 47.8754301917 -14.7464170468 +-86.5404512618 50.0245877392 -2.87939523683 +-86.5269083189 46.5315159508 -18.6524036009 +-86.4954742774 -36.6795231366 34.2512118325 +-86.4157148173 -34.7914648819 36.3576429927 +-86.3976781092 -34.8192550358 36.3739013043 +-86.3871635418 -34.6748863078 36.5364233984 +-86.3764191379 -34.4606969621 36.7637672416 +-86.3367754845 -34.9699943214 36.3739013043 +-86.3250020316 -34.965225582 36.4064146031 +-86.3243349375 -35.0175812074 36.3576429927 +-86.3127916064 -34.9953565614 36.4064146031 +-86.3054944788 -35.0976788175 36.3251230473 +-86.3010093018 -34.9905794485 36.4389234658 +-86.2969114162 -34.81366571 36.6176427403 +-86.2920524301 -34.6541982488 36.7799977044 +-86.2748331172 -35.1729811958 36.3251230473 +-86.2630862803 -35.168192183 36.3576429927 +-86.2383337696 -34.6326252642 36.9260213935 +-86.2026255191 -38.9582084247 32.4247644548 +-86.1957016815 -35.3162896626 36.3739013043 +-86.1778485027 -34.7656336727 36.9422406303 +-86.1568551225 -38.810833298 32.7217898979 +-86.1557801064 -35.212157676 36.5689144775 +-86.1544880415 -38.9545627409 32.5568154457 +-86.1199403658 47.7370624553 -17.4507518327 +-86.1118918934 -35.3697442124 36.5201761892 +-86.0519211771 48.0927931906 -16.7973243363 +-86.0411561902 -38.3619848937 33.545156975 +-86.0351283831 48.1228280471 -16.7973243363 +-86.0345023276 -39.0813110722 32.7217898979 +-86.034455087 -38.3050073296 33.627354213 +-86.0306497481 -36.606480092 35.4780625061 +-86.0248558413 -38.2108163467 33.7588165017 +-86.0202358354 -42.0478358268 -28.8530506031 +-85.9850424986 -34.8275277948 -37.3311635797 +-85.9755376388 -36.1761075581 36.0485252079 +-85.9224567335 -37.2175817374 35.1024648492 +-85.9209166259 -39.1926443711 32.8866646739 +-85.913345678 -36.291218074 36.0810826488 +-85.7901503178 -36.4687832622 36.1949990445 +-85.7773275012 -36.9770542335 35.7064076459 +-85.7532535494 -37.3755916855 35.3474843779 +-85.7468668039 -37.9977811192 34.6935651573 +-85.7319024234 -38.6194060652 34.0379550213 +-85.7041397337 -36.3792489618 36.4876784338 +-85.6957737556 48.9791698895 -16.0398029092 +-85.69254188 -37.3135412366 35.5596387288 +-85.6899654653 -39.3224186503 33.3313247568 +-85.6879697583 48.1448585105 -18.4294448562 +-85.6876888049 -37.0271184797 35.8693808751 +-85.6844131183 -39.5010554955 33.1337888463 +-85.6820990437 50.4102027119 -10.8346373271 +-85.6805933919 -38.7763205272 33.9887169865 +-85.6787864365 -39.4440791429 33.2161131884 +-85.6666567742 -38.9502960477 33.8245229816 +-85.6526459846 -37.2961691631 35.673799932 +-85.6396219476 -37.326065304 35.673799932 +-85.6351702793 -37.5377453036 35.4617440174 +-85.6279339671 -38.339102135 34.6117057077 +-85.6268112674 -38.5181468067 34.4151356056 +-85.6265874757 -37.3559568968 35.673799932 +-85.6236342146 -38.7145383478 34.2020143326 +-85.6230494401 -38.5703713716 34.3659694586 +-85.6011119761 -37.5228160181 35.5596387288 +-85.5968183699 -38.3789862457 34.6444526541 +-85.585247775 48.5204466436 -17.9145644884 +-85.5036014579 18.2835619466 -48.5267503577 +-85.489095912 -37.669543116 35.673799932 +-85.4870316912 18.2800187701 -48.5572685227 +-85.483439154 48.6995894191 -17.9145644884 +-85.4335373746 -38.9883422941 34.3659694586 +-85.3980039089 50.70562414 11.6670737099 +-85.3640797948 -39.6790269467 33.7423873096 +-85.3502240011 -39.7088222138 33.7423873096 +-85.3297194257 49.9626044667 14.9190193254 +-85.2962069803 -40.1009874285 33.4135882844 +-85.2180175309 49.3594225253 -17.3648177667 +-85.1901978182 50.7835500884 12.7930151302 +-84.9253351546 50.384886657 -15.7813385186 +-84.7672317687 50.1711476478 -17.2444878725 +-84.7568508445 50.1650034943 -17.3132509753 +-84.672458194 -43.8900335479 30.0705799504 +-84.6380069716 50.1545227778 -17.9145644884 +-84.4920454086 -45.3992136347 -28.284371374 +-84.4833431317 -45.3945377326 -28.31785086 +-84.3824465032 44.8669426724 -29.4373942013 +-84.2408756916 53.7707644916 -3.48994967025 +-84.2327414661 40.3575676241 -35.7227098715 +-84.2195023586 53.7985068299 -3.57716163253 +-84.2184449348 53.797831359 -3.6120456584 +-84.2090541592 53.8125294311 -3.6120456584 +-84.2082244554 53.0287490594 -9.84513622389 +-84.1916220469 51.330297473 -16.6424559018 +-84.151310738 53.8584059584 -4.22244108312 +-84.1423203507 -45.7426134469 -28.769484546 +-84.1203162218 52.2178033641 -14.0382837472 +-84.1180255655 52.8285337489 -11.5457263478 +-84.0455409526 52.008958841 -15.212338619 +-83.7959356754 54.4593123724 -3.52483477781 +-83.7264239212 43.8083371431 -32.7217898979 +-83.6592879715 51.9113939745 -17.5023058975 +-83.6263802418 38.0578691747 -39.4743856384 +-83.3847306436 53.6966056597 12.7930151302 +-83.2891645282 54.0886158757 -11.7190744019 +-83.2801111037 53.9794699027 -12.2735456807 +-83.1993343975 53.7622892115 -13.6925897678 +-83.1049144399 48.0386804476 -28.0331656578 +-83.1048197275 48.0192765782 -28.0666708921 +-83.0508791897 54.5127412006 -11.4417005998 +-83.042757721 54.8606460589 -9.70617865584 +-82.951399542 53.4175568566 -16.2981573648 +-82.9394100373 53.4098360701 -16.3842507806 +-82.8976956184 54.4536080413 -12.7583945876 +-82.8741120154 54.541702974 -12.5333233564 +-82.6461184582 55.0139691256 -11.9617015862 +-82.4013865894 -48.4800284783 -29.3206126622 +-82.3650424006 55.9752250137 -9.09802039036 +-82.3612323494 55.7208281661 -10.5743422663 +-82.3027872795 55.7231761755 -11.0081262225 +-82.2799408498 55.770560494 -10.9387346587 +-82.2554655958 55.4820121012 -12.4813746365 +-82.2457991745 -48.2533237736 -30.1205123289 +-82.2313750361 42.8616833526 -37.4282922379 +-82.1648106395 56.1120968747 -10.0188061612 +-82.0672393617 -42.2130517448 -38.5100829128 +-82.0358421775 56.6561552443 -7.75890914711 +-81.8954531601 39.9961757962 41.1514358605 +-81.8840031327 55.7110094929 -13.8308876163 +-81.8324257903 56.4945782788 -10.5743422663 +-81.8121649727 56.6494287645 -9.87987262748 +-81.8095329265 10.5090697131 -56.5398954378 +-81.7814343679 -48.8095747217 -30.4864299028 +-81.7591602507 10.3575799697 -56.6406236925 +-81.6304267841 -51.6644564581 -25.8313252067 +-81.4335925997 57.0839825125 -10.4875610524 +-81.411065251 46.2855179329 -35.0697773643 +-81.3497938143 8.52149879245 -57.5290805133 +-81.3447196758 8.07626834274 -57.6004381105 +-81.282780924 9.57729800604 -57.4576791052 +-81.2512195227 9.58795741037 -57.5005252043 +-81.2096145941 51.0019682045 -28.3513268955 +-81.1847549478 8.64748600682 -57.7430216549 +-81.1752261801 49.8417351971 -30.4365583986 +-81.1402330925 57.6633622314 -9.54982878676 +-81.132859238 -44.2901956849 -38.1554415263 +-81.1179544168 41.8322460358 -40.8649074736 +-81.0963248117 7.92298503778 -57.9707892832 +-81.0765931734 8.42135815023 -57.9281172343 +-81.0726111022 40.9527227022 -41.8342710268 +-81.0189682388 8.77286289385 -57.9565670322 +-80.9420764207 43.1827411486 -39.7948631308 +-80.9344220442 52.3187596311 -26.690198932 +-80.8281246137 48.2406113128 -33.7588165017 +-80.7883154378 58.0522937516 -10.1577201628 +-80.7784522238 58.5168306875 -7.11492674688 +-80.7456079426 7.95986303978 -58.4532922799 +-80.7081178177 6.919126454 -58.6372356736 +-80.70429898 58.1629622634 -10.1924455795 +-80.7000690386 46.0865251588 -36.9260213935 +-80.6997684091 7.79893555605 -58.5382266806 +-80.5462668237 57.3471072625 14.9535343444 +-80.4840324938 8.70072765332 -58.7079028057 +-80.4814514055 57.9383545045 -12.8795596578 +-80.4770838966 43.0068685302 -40.9126902895 +-80.4549226554 41.2063085502 -42.7673421689 +-80.4250026433 41.2973548286 -42.7357863387 +-80.4245005169 6.35779357081 -59.088731392 +-80.4058740926 44.0574168972 -39.9229185776 +-80.4046099508 59.1278994372 -6.24421386623 +-80.382898285 45.2010617664 -38.6710961637 +-80.374521365 6.96118796159 -59.088731392 +-80.3246196627 48.3593543902 -34.7753981862 +-80.3238117003 42.1351837845 -42.1035813367 +-80.2592311548 8.08167961938 -59.1028110073 +-80.258667337 40.5767404107 -43.7272735822 +-80.24826956 7.44440688711 -59.2013178799 +-80.2361239189 44.9343884263 -39.2818680211 +-80.2349463769 58.5512403266 -11.5803987891 +-80.2081289422 40.7271166225 -43.6801788368 +-80.206368025 41.3621441145 -43.0826132274 +-80.2014078675 43.96358429 -40.4343595529 +-80.1724152779 45.9523470308 -38.2199637738 +-80.1506361976 44.0267585141 -40.4662829014 +-80.150046003 58.4035749293 12.84494302 +-80.1428365894 47.7368104842 -36.03224484 +-80.1104115012 7.47392692838 -59.3840246647 +-80.0951551144 58.9003327037 -10.7478804698 +-80.0824564117 47.7766207688 -36.1136356933 +-80.0323809504 47.8604567093 -36.1136356933 +-80.0107642863 40.9964547367 -43.7900479257 +-79.963917332 7.13658949692 -59.6224874966 +-79.9551386672 7.23427850131 -59.6224874966 +-79.890047431 48.899163823 -35.0207381259 +-79.8761821676 6.31444739081 -59.8324600571 +-79.8735751627 45.2271076525 -39.6827509647 +-79.870915537 49.4834758442 -34.2348137086 +-79.8436110035 40.6297062906 -44.4322489715 +-79.8070414496 54.2775432621 26.1683861269 +-79.8070095253 54.1960731051 26.3367972734 +-79.7784863047 54.3600056006 26.084150629 +-79.771552166 6.04005922259 -60.0001429133 +-79.7714679376 6.69859732011 -59.9303069992 +-79.7597042915 54.3064496676 26.2526016964 +-79.7500125378 54.4017700649 26.084150629 +-79.7425175936 7.49576315225 -59.874405405 +-79.7404539499 40.4546412224 -44.7759087839 +-79.7284064687 54.5298837417 25.8819045103 +-79.7248812203 7.1152560923 -59.9442778349 +-79.7188879943 54.5437981431 25.8819045103 +-79.7147725117 46.8993860597 -38.0263412733 +-79.7110145533 54.5792707623 25.8313252067 +-79.7065858106 46.9132981977 -38.0263412733 +-79.6971293443 39.7876390603 -45.4456967411 +-79.6952693146 41.2571780094 -44.1192623644 +-79.6876897738 7.29421984319 -59.9722140278 +-79.6851387559 7.32203564944 -59.9722140278 +-79.6825600024 59.3935497725 -11.0948581284 +-79.6647228558 55.2653847097 24.4799751878 +-79.6454267442 55.2931895764 24.4799751878 +-79.6178378565 30.4349445658 -52.2944934419 +-79.6007821046 30.4284247848 -52.3242434579 +-79.585247678 40.6732600969 -44.8539214018 +-79.5586395597 53.1995627995 -28.9867105645 +-79.5505302741 55.8675748524 23.4633163303 +-79.5348644637 7.23823969132 -60.1815023152 +-79.5245901177 6.99945972665 -60.2233105213 +-79.5184660114 53.635882571 -28.284371374 +-79.513938769 7.23633530391 -60.2093762865 +-79.5084250245 50.6914794888 -33.298412235 +-79.493781706 40.7315597174 -44.9630816679 +-79.4831120545 56.0483946796 23.2596722241 +-79.4696072491 56.0181071911 23.378477076 +-79.4693658319 55.9971777622 23.4293827692 +-79.4666044704 39.5340386827 -46.0664580728 +-79.4633658682 56.0552383444 23.3105928507 +-79.4585994029 40.7485572098 -45.0098441037 +-79.4580831471 60.2682632576 -7.35863210847 +-79.4502135477 7.58021508228 -60.2511734868 +-79.4433391535 54.968158985 -25.8313252067 +-79.408485894 43.8358392944 -42.1035813367 +-79.4083463572 42.6676436014 -43.287258152 +-79.4047639315 59.6621372686 11.6324048041 +-79.4033320953 40.510401614 -45.3212777096 +-79.3873587678 40.0145229438 -45.7873915117 +-79.366797505 59.9810984803 -10.1577201628 +-79.3498738154 53.5826370793 -28.8530506031 +-79.3422339021 -55.4941410791 -25.0042041528 +-79.3362668429 50.7766881986 -33.5780389393 +-79.3312624901 42.8584727048 -43.2400521409 +-79.3246214862 42.8548849227 -43.2557887958 +-79.3132546668 56.3025176213 23.2257215962 +-79.2823290554 40.2222211981 -45.7873915117 +-79.2781824933 49.8275701 -35.1024648492 +-79.2662852018 44.7189535776 -41.4375580993 +-79.2605693173 56.5360146516 22.8350870111 +-79.2474618478 5.98646629502 -60.6959801962 +-79.2472841218 2.35200448481 -60.9453528518 +-79.242251479 39.8027275511 -46.2212987705 +-79.2034966711 40.1474702454 -45.9889850721 +-79.1961777037 40.1263880503 -46.0199784784 +-79.1475583004 55.0089860268 -26.6397348219 +-79.1340262852 54.2450808404 -28.20065759 +-79.1283517204 55.0366103846 -26.6397348219 +-79.118352038 2.00269739183 -61.125081382 +-79.1164073244 53.8280341809 -29.0368184947 +-79.1018008299 53.858499145 -29.0201167351 +-79.097017372 2.00215735429 -61.1527040186 +-79.0899764362 -46.6247508514 -39.6346847517 +-79.0815632947 53.2809636166 -30.1205123289 +-79.0719412451 59.1533696627 -15.7641036938 +-79.0697369445 59.1517206351 -15.7813385186 +-79.0686784543 40.2353693928 -46.1438959919 +-79.0560622137 60.9913420457 -5.49501799124 +-79.0434577353 39.9277235808 -46.4532956732 +-79.0230877409 53.3017457084 -30.236989075 +-79.0210629374 39.5190634701 -46.8392488698 +-78.9997822414 5.27485817147 -61.0836334633 +-78.996973107 52.4457251499 -31.763566447 +-78.982920407 40.2438080228 -46.2831956524 +-78.9803385558 5.2458682988 -61.1112672705 +-78.9709219153 51.736198895 -32.9690645263 +-78.9528577642 51.7637617945 -32.9690645263 +-78.8930065053 39.3346020476 -47.2089250705 +-78.8606187518 45.861131385 -40.960461889 +-78.8550040759 51.54232024 -33.545156975 +-78.8448913563 42.2231225305 -44.7290848419 +-78.8312226898 5.0701547577 -61.3182832438 +-78.8295343212 39.6816086318 -47.0241901057 +-78.7893127955 51.4601383041 -33.8245229816 +-78.7845189537 54.0054992805 -29.6041487076 +-78.7748008215 39.8265352503 -46.9933808689 +-78.7730078023 4.2386165069 -61.4560604976 +-78.7706352202 40.5695429947 -46.3605350294 +-78.7521586933 53.0790147255 -31.3163806484 +-78.7421895732 40.6070723961 -46.37599867 +-78.728010234 40.634556131 -46.37599867 +-78.7165194248 52.7359173042 -31.9786271707 +-78.7158729227 54.2416354385 -29.3539832896 +-78.7104506943 59.1619490211 -17.4507518327 +-78.6998432263 6.42882102497 -61.3596360516 +-78.6965244494 7.09270578912 -61.2907053653 +-78.6958907305 54.2886586244 -29.3206126622 +-78.6922865015 39.4405246419 -47.4549160903 +-78.6905178964 54.2241637642 -29.4540736955 +-78.6868079007 54.120395467 -29.6541574976 +-78.6784909848 6.42707680626 -61.3871952452 +-78.6715711687 52.0123591578 -33.249035846 +-78.6553655997 49.0920814803 -37.4606593416 +-78.6399302621 38.9858915381 -47.9151503112 +-78.5860889353 4.50372301036 -61.6761145412 +-78.5366580753 54.2192820821 -29.8707681332 +-78.5212352264 41.1721384645 -46.2522500293 +-78.5097437772 5.04947833302 -61.7310529686 +-78.4990156956 5.97126578135 -61.6623752364 +-78.4488089785 38.993537745 -48.2212441148 +-78.4403299333 47.3742668678 -40.0349032557 +-78.4379276934 45.6519640662 -41.9927336103 +-78.4257431883 3.39671437827 -61.950505541 +-78.3519070084 39.1502288001 -48.2518212408 +-78.3419878808 52.2871299343 -33.5944783874 +-78.2819424041 7.26199623199 -61.7996836899 +-78.2661045616 39.4151094334 -48.1753674102 +-78.2373198886 39.4348556286 -48.2059533482 +-78.2246057186 41.7329657154 -46.2522500293 +-78.2159837454 58.3003975205 -21.9846204353 +-78.2105085966 41.7079109921 -46.2986663495 +-78.1921617739 42.0493450361 -46.0199784784 +-78.1912959479 58.2819958034 -22.120809279 +-78.166608792 6.60505188652 -62.0189854765 +-78.1259523417 52.162654987 -34.2840049499 +-78.0690417834 42.529278075 -45.7873915117 +-78.0679196393 39.0935020458 -48.7554922136 +-78.0627800092 53.4507010161 32.3917418198 +-78.0541480688 39.6848141163 -48.2976759048 +-78.0490426363 2.75281043929 -62.4561364338 +-78.0272501251 2.75204181164 -62.4833938242 +-78.0134179492 42.7642053544 -45.6632167098 +-77.9781993078 62.4276401582 -4.71064507096 +-77.9104942812 45.3449904899 -43.287258152 +-77.8865700614 41.2388160632 -47.2550764869 +-77.8819393811 48.326493528 -39.9869171297 +-77.8752877457 59.7990106135 -18.9609569425 +-77.8565284122 39.038646676 -49.1359852787 +-77.8441851957 49.3442665981 -38.7998219728 +-77.8387142528 59.8357404314 -18.9952291512 +-77.8366764087 56.4064915274 -27.5637355817 +-77.8268534957 5.34664348928 -62.5651203016 +-77.8155520411 3.8738876607 -62.6875813454 +-77.8143421266 41.3397845659 -47.2858369012 +-77.8059924813 5.33156671949 -62.5923472184 +-77.7772337611 60.1130774983 -18.3608230249 +-77.7562456005 60.1402232117 -18.3608230249 +-77.7314968662 62.5424143865 -6.80152906652 +-77.7312555461 40.5505851124 -48.0988768919 +-77.7259244403 57.5141586064 -25.5108257352 +-77.7131585842 47.3804809874 -41.4216731225 +-77.7114979015 58.135628012 -24.1075060833 +-77.6992419367 7.3173772241 -62.5242656336 +-77.693224283 60.2216163712 -18.3608230249 +-77.6904470957 58.2892417911 -23.8024940184 +-77.5968037457 62.1667623928 -10.6784690876 +-77.584463397 6.37860400151 -62.7691361291 +-77.5811129328 6.41922625533 -62.7691361291 +-77.5788674737 6.44630678086 -62.7691361291 +-77.5421693309 44.4447714623 -44.8539214018 +-77.5329676589 2.77525576053 -63.0946660302 +-77.5285807444 44.4369829051 -44.8851168881 +-77.4956132166 61.3562267651 -15.1605860484 +-77.4736627868 62.3349622404 -10.5916975449 +-77.4705442869 41.2785783249 -47.8998302645 +-77.4680915153 48.2571666609 -40.8649074736 +-77.4365230141 39.5069648101 -49.4245347472 +-77.4339898268 41.2938109393 -47.9457860256 +-77.362793338 39.5374407577 -49.5155428655 +-77.3399137061 63.2569162094 -4.13525085224 +-77.2921474819 7.87830942704 -62.959162782 +-77.258732313 6.03969263441 -63.2029302665 +-77.1862998533 41.0061297208 -48.5877807712 +-77.1569566973 53.5855487776 34.2840049499 +-77.1486403062 6.03108620427 -63.3380872628 +-77.1012684684 4.24313954417 -63.5404608684 +-77.0805934917 4.21501455584 -63.5674111417 +-77.0731626813 4.14715127294 -63.580883374 +-77.0626614879 63.5707481331 -4.48399221677 +-77.0509961305 4.14595853559 -63.6078220278 +-77.0238941461 -53.9327113034 -34.0379550213 +-76.9975370277 5.83001923635 -63.5404608684 +-76.9954972762 5.85689609136 -63.5404608684 +-76.9953195643 39.028167078 -50.4828974973 +-76.9764319047 5.81490945406 -63.5674111417 +-76.9203127053 42.7254186229 -47.5163560978 +-76.7952727388 60.1719096801 -21.9505665171 +-76.7897716221 46.9278822578 -43.6016609893 +-76.7742168379 7.73075713018 -63.6078220278 +-76.7682868763 60.2373101742 -21.8654200292 +-76.7535919375 5.6633686942 -63.8499207495 +-76.7323653973 42.2363095864 -48.2518212408 +-76.6974740765 39.5526197493 -50.5280886365 +-76.6676734217 7.6794807786 -63.7423989749 +-76.6005448992 8.82234300456 -63.675134747 +-76.5820521555 63.5119377469 -10.0709012153 +-76.5043171782 63.5151078447 -10.6264071336 +-76.4999710906 46.3665348043 -44.6978620671 +-76.4962606944 41.1889926377 -49.5155428655 +-76.4924721123 38.8404251981 -51.3840741921 +-76.4810377007 41.1807959002 -49.5458668432 +-76.4797310277 41.128452332 -49.5913414893 +-76.4709193576 53.0893136489 -36.5201761892 +-76.4085770755 4.98129713727 -64.3188621489 +-76.369472172 56.4073673923 -31.3992455967 +-76.3670137649 41.9310655183 -49.0903753615 +-76.349777634 56.43402193 -31.3992455967 +-76.3487859361 6.65279931653 -64.238642166 +-76.3451350111 43.4935323845 -47.7465496226 +-76.3279595502 45.7356387043 -45.63215909 +-76.1889225211 63.0737671106 -14.7291543397 +-76.1874890006 39.1214381517 -51.6234403806 +-76.161330415 39.1920314198 -51.6084917685 +-76.1590423912 4.45798838881 -64.6523518642 +-76.1303571063 6.1654245954 -64.5457687724 +-76.0676699124 40.9924775482 -50.3321604797 +-76.021577591 5.82284866339 -64.7055961569 +-76.0195404019 5.84938484474 -64.7055961569 +-75.9996071253 41.9194305931 -49.667102347 +-75.9734532764 38.8441219106 -52.1456478554 +-75.9703233236 41.9724781083 -49.667102347 +-75.939526461 38.9104064566 -52.1456478554 +-75.9386269304 4.91073071876 -64.8784221735 +-75.9198508781 -63.254035051 -15.3330783737 +-75.8913803779 47.4590405551 -44.5885394908 +-75.8388880414 54.6363895447 -35.5433256487 +-75.8196953274 40.8759229292 -50.7989441341 +-75.7886904162 -63.3691812377 -15.5055239918 +-75.78399549 40.9420725225 -50.7989441341 +-75.734261068 60.0262356585 -25.7132793155 +-75.7104853958 6.02502810458 -65.0509141939 +-75.6828521252 59.6635498036 -26.690198932 +-75.6567462708 5.68865932764 -65.1436558597 +-75.6437162968 6.28550811803 -65.1039213298 +-75.5941534336 40.0250439382 -51.8027009373 +-75.5542807266 39.7510300595 -52.071165467 +-75.4320661103 7.92822962303 -65.170135625 +-75.4301689398 50.4008275402 -42.0719169633 +-75.4217826786 4.96984568326 -65.4740813717 +-75.4175201663 9.260107098 -65.0111380342 +-75.3486892211 52.2128277098 -39.9549202878 +-75.3347477587 39.18337056 -52.814195551 +-75.3290642644 45.9810572078 -47.0241901057 +-75.3270123266 46.0159034297 -46.9933808689 +-75.3106089001 5.72872994537 -65.5400170912 +-75.2954177245 6.6139805128 -65.4740813717 +-75.2910200286 39.2274338571 -52.8438334722 +-75.2857887492 5.75327438951 -65.5663774065 +-75.2831116255 43.7279108031 -49.1967775447 +-75.2756856537 43.7235974554 -49.2119718658 +-75.2733722495 5.76554011218 -65.5795545685 +-75.2608268313 43.7149667646 -49.2423560103 +-75.2456492416 41.110484052 -51.4589192581 +-75.2234902446 65.5061200167 -7.09751757832 +-75.2122701772 63.5592961694 17.4163797974 +-75.1735448396 42.3235505378 -50.5732659231 +-75.1724696767 63.5256621388 17.708474032 +-75.1591340222 5.75679007134 -65.7112162503 +-75.1386749075 10.0923857618 -65.209840383 +-75.1132996489 58.1589305493 -31.2334918512 +-75.1111192098 65.9402904658 -3.19340951597 +-75.0883825719 39.0552302436 -53.2580866475 +-75.0654628669 6.87112388797 -65.7112162503 +-75.0129227999 51.6128035253 -41.3422293217 +-75.000533562 7.31422091418 -65.7375245794 +-74.9814415453 5.96701091362 -65.8952062334 +-74.9709292953 51.6610648441 -41.3581206025 +-74.9683109515 45.0811299172 -48.4504290844 +-74.9366269071 7.94227989659 -65.7375245794 +-74.8401891462 56.0895423412 -35.3964592652 +-74.8365855246 6.85017357988 -65.9739387103 +-74.8256250906 56.1398359274 -35.3474843779 +-74.7966912699 7.03085755567 -66.0001667961 +-74.7909120669 41.747850838 -51.6084917685 +-74.7863505846 6.76661059244 -66.0394938452 +-74.7827973442 6.8057677047 -66.0394938452 +-74.7732950712 9.53888898674 -65.7112162503 +-74.7377706426 7.85525622885 -65.9739387103 +-74.7127238521 8.09001270972 -65.9739387103 +-74.6286015692 43.3825873836 -50.4828974973 +-74.6254577493 8.85892017967 -65.9739387103 +-74.6010376932 8.86922533153 -66.0001667961 +-74.5603429958 43.4823068681 -50.4979627488 +-74.5439024823 6.22032179044 -66.3665141432 +-74.4937497046 53.5686292317 -39.7628371371 +-74.4801645219 49.7284578156 -44.4947814477 +-74.4581567612 42.5563426274 -51.4289859311 +-74.4443297004 7.99523011636 -66.2881442707 +-74.4415343032 8.02121560199 -66.2881442707 +-74.4347675643 42.5429746001 -51.4738835705 +-74.4297428158 47.4535092368 -46.9933808689 +-74.4105782049 42.4946970353 -51.5486816038 +-74.40351786 -64.6096261713 -17.0209499166 +-74.4012016576 39.2771029161 -54.0534030235 +-74.3256521068 41.7437322861 -52.2796160442 +-74.2560876996 7.45101269726 -66.5621202286 +-74.2469291544 7.54172803931 -66.5621202286 +-74.2451526645 41.4942133035 -52.5917062677 +-74.2367471263 45.3498802247 -49.3182901134 +-74.2347911829 41.4374274046 -52.651072051 +-74.2232448145 40.3838404391 -53.4794854183 +-74.1515552503 53.028595486 -41.1037092578 +-74.1317154711 59.8594905909 -30.3534206887 +-74.1171446272 59.8690982922 -30.3700500819 +-74.100212667 39.6822458012 -54.1708210283 +-74.0813798544 40.0556526628 -53.9211818177 +-74.0650305374 41.1732876068 -53.0954954695 +-74.0380584777 41.2598453547 -53.0659123936 +-74.0254054218 41.3205494942 -53.0363228518 +-73.9792741607 39.6673387664 -54.3467499475 +-73.9678952736 9.2787461341 -66.6532470249 +-73.9609216871 40.0405828688 -54.0974471368 +-73.9310878329 55.549396438 -38.0586232965 +-73.9266276279 39.8053877858 -54.3174449951 +-73.8806389078 9.94966610541 -66.6532470249 +-73.8772755545 55.6098967085 -38.0747625693 +-73.8451981496 46.1794506349 -49.1359852787 +-73.8293398937 -59.8925731851 -31.0178698193 +-73.828109049 40.6377003215 -53.832960413 +-73.8226633951 10.9406818766 -66.5621202286 +-73.8053919952 10.898632083 -66.5881666001 +-73.7676890081 40.3364424507 -54.141476419 +-73.7485765169 40.2925578996 -54.200159037 +-73.7065159497 8.723741047 -67.0167579691 +-73.6932018497 41.0171099645 -53.7299608347 +-73.5659855979 44.0806666136 -51.4289859311 +-73.5246447346 39.7878015684 -54.8731032748 +-73.5168341295 45.7246020344 -50.0453381281 +-73.486199833 57.9318487675 -35.2658380374 +-73.4713574947 43.6761477213 -51.9071647088 +-73.4245927173 43.6483476997 -51.9966434242 +-73.3916619406 65.8968294431 16.470331719 +-73.3884174154 67.3660074097 -8.71557427477 +-73.3873795914 65.8929844119 16.5047605861 +-73.3761776726 8.10080543225 -67.4560116039 +-73.3513053946 57.7217855571 -35.8856721967 +-73.2732009357 40.2489821191 -54.8731032748 +-73.2606611288 40.1921750159 -54.9314536351 +-73.2493417999 40.0530082994 -55.0480740085 +-73.1310008963 9.17376368949 -67.5847524792 +-73.0289122517 41.7732880788 -54.0534030235 +-73.0068699892 44.9492630033 -51.4738835705 +-72.9863402777 44.6035234984 -51.8027009373 +-72.9791375579 43.1597416383 -53.0215256573 +-72.9356523616 40.0635666282 -55.4553986878 +-72.9321538643 66.876855526 14.4356201001 +-72.8753518994 49.7494790087 -47.0549936128 +-72.8724467342 39.8964992221 -55.6585649903 +-72.8585157895 39.9219340736 -55.6585649903 +-72.8515469879 39.9346496753 -55.6585649903 +-72.8499954897 39.9172654793 -55.6730641675 +-72.8430275031 39.9299795941 -55.6730641675 +-72.8424788651 9.09883279023 -67.9057031084 +-72.7963550947 42.8290046342 -53.5384632481 +-72.7949912743 39.9366997854 -55.7310439129 +-72.7911168246 39.9841732323 -55.7020574338 +-72.7810463016 39.9621075974 -55.7310439129 +-72.7794786639 61.9401913788 -29.4373942013 +-72.7674585363 -63.658240831 -25.5445757936 +-72.7601122153 40.0002101844 -55.7310439129 +-72.7592386479 40.0824539864 -55.6730641675 +-72.7018738888 42.6198299647 -53.832960413 +-72.7010509868 39.8851623789 -55.8903480703 +-72.6935976775 40.2615540988 -55.62956155 +-72.6933452905 40.6602444993 -55.3391549243 +-72.6918513182 39.9626834387 -55.8469218875 +-72.6879905396 40.0101372576 -55.8179625922 +-72.6861891723 40.1746026894 -55.7020574338 +-72.6795393154 40.2869264979 -55.62956155 +-72.6786289197 40.0876643426 -55.774510898 +-72.6778972818 39.9880552464 -55.8469218875 +-72.663998619 42.6658170759 -53.8476680827 +-72.6630532646 39.9138278964 -55.9192903471 +-72.6062423656 40.3789265926 -55.6585649903 +-72.5920322112 40.6035761129 -55.5134800412 +-72.5634303341 40.2556847425 -55.8034803938 +-72.5592562836 11.5182219597 -67.8416162135 +-72.5545423366 52.2317965369 -44.8071179262 +-72.5457100469 47.3460988951 -49.9546481641 +-72.5313943279 40.4534007779 -55.7020574338 +-72.5210550741 40.7302112031 -55.5134800412 +-72.512721999 40.3269165739 -55.8179625922 +-72.4852841241 62.6338799921 -28.6858965796 +-72.4771575023 40.2905774712 -55.8903480703 +-72.4746942476 61.7899367656 -30.4864299028 +-72.4531210759 61.8152314414 -30.4864299028 +-72.4525259132 40.1941588005 -55.9916162217 +-72.4040792734 40.5814395835 -55.774510898 +-72.4040393073 10.7304386514 -68.1359873953 +-72.3753261987 68.970281918 -2.21638664806 +-72.3255383684 41.5050857386 -55.1936985312 +-72.3117674283 41.2960996014 -55.3682259884 +-72.2700029797 43.4757171076 -53.7299608347 +-72.2581142345 40.5825349742 -55.9626909856 +-72.249329087 41.2102897369 -55.5134800412 +-72.2117305957 68.8384356509 -6.83635440257 +-72.1985308155 43.4670509842 -53.832960413 +-72.1956135058 44.1029887755 -53.3171620737 +-72.1954323123 59.5133217449 -35.2984997999 +-72.1737960127 69.1396759055 -3.26318629583 +-72.159392083 69.1983690934 -2.14659009304 +-72.1443641356 11.8528837014 -68.2253609109 +-72.142971977 40.104801314 -56.4534897583 +-72.0821137923 40.1533525579 -56.4967003425 +-72.0640254134 69.3003271847 -2.05934293201 +-72.0296314842 58.5368936466 -37.2177950778 +-72.0270222341 42.1735550875 -55.0772123421 +-71.9810577371 -51.6665086767 -46.3605350294 +-71.9489251951 9.40838748724 -68.810133034 +-71.9450178208 42.2943293859 -55.0917789925 +-71.9439891125 9.44605856497 -68.810133034 +-71.9369216677 41.7339303709 -55.5279961531 +-71.9005744482 10.7071279346 -68.6706983029 +-71.8949866472 45.0122591926 -52.9623207325 +-71.8814894485 9.91045238642 -68.810133034 +-71.8656046969 -4.30736637399 -69.4030363635 +-71.8655137474 9.39748020518 -68.8987322062 +-71.8653078851 40.1970906408 -56.7412674039 +-71.8451025579 40.0706308577 -56.8561850734 +-71.8190933056 40.0561245502 -56.8992506345 +-71.8095295073 9.17353642503 -68.9872285383 +-71.8078242021 10.5140302525 -68.797467622 +-71.7987418382 12.466331513 -68.4801522272 +-71.798222221 54.7946709341 -42.9250430767 +-71.7953259178 10.179637489 -68.8607737173 +-71.740197775 8.65611014113 -69.1260861067 +-71.7327703267 48.4754968299 -50.0453381281 +-71.6862641192 42.9373373437 -54.9314536351 +-71.6745409136 40.7168061872 -56.6118528114 +-71.6742925375 42.8452242907 -55.0189289674 +-71.6668135436 42.857733162 -55.0189289674 +-71.6457577879 40.6673817875 -56.6837670727 +-71.63173043 46.1635001073 -52.3242434579 +-71.61654882 12.3960722619 -68.6833846544 +-71.5010347605 10.0233648105 -69.189118986 +-71.4988743671 67.259424894 -19.0808995377 +-71.479857727 44.3539401982 -54.0680860418 +-71.475309908 12.5773018709 -68.797467622 +-71.4180950852 39.9142242267 -57.5005252043 +-71.3600258875 40.3242504986 -57.2861373028 +-71.3269641139 41.479959507 -56.4967003425 +-71.3094406949 10.3393768294 -69.3401828276 +-71.2817882621 52.1321818551 -46.9163327338 +-71.2685650442 52.1225110091 -46.9471562786 +-71.2550234866 66.8661298504 -21.251877723 +-71.2112728676 44.0668727645 -54.654051463 +-71.2046153809 69.972580656 -5.80867495977 +-71.1988614215 43.6307183938 -55.0189289674 +-71.1845221773 12.4236879368 -69.1260861067 +-71.1434552628 12.3781388366 -69.1765166238 +-71.1394643224 62.4975464909 -32.1439465303 +-71.1334613063 44.1561951017 -54.6832800472 +-71.1198865054 60.7850688189 -35.3148290685 +-71.0512468498 10.9993141489 -69.5034920658 +-71.0432480214 59.7604225992 -37.1691915613 +-71.0118314559 66.3355557492 -23.5990219443 +-71.0025511799 41.4074640053 -56.9566471151 +-70.9876052155 43.1611404967 -55.6585649903 +-70.9574804808 40.1785146329 -57.885429304 +-70.9275397507 63.9756085099 -29.6041487076 +-70.9250152014 43.2079045584 -55.7020574338 +-70.9021300833 41.3820737815 -57.1000168056 +-70.8934917611 40.798501458 -57.5290805133 +-70.8928546191 11.4567429638 -69.5912796592 +-70.8769483975 56.7425340588 41.9135182781 +-70.7668855149 13.7556890831 -69.3024453563 +-70.7616864723 44.3543095543 -55.0043539327 +-70.7325104163 10.9120511805 -69.8415285431 +-70.7306048268 10.9243961661 -69.8415285431 +-70.615729683 10.8688003366 -69.9663340513 +-70.563572481 12.3153148661 -69.7790459842 +-70.5603816293 47.8987963221 -52.2200905326 +-70.5554134075 14.200838845 -69.4281629815 +-70.5192267985 43.7749081761 -55.774510898 +-70.4975747746 47.9101023434 -52.2944934419 +-70.4784964082 70.9227229014 -1.65798681877 +-70.4636223138 45.3585055152 -54.5663257682 +-70.455704688 45.3708030464 -54.5663257682 +-70.453048882 59.3269759732 -38.9445480794 +-70.4380342979 40.3729011406 -58.3824646426 +-70.4089058145 41.0118711093 -57.9707892832 +-70.4071913237 50.872728339 -49.5458668432 +-70.3569581204 66.8363085051 -24.1413816807 +-70.3350788979 66.9323898064 -23.9380841177 +-70.3341180046 54.5960681119 45.5234136597 +-70.3015028891 42.3751150604 -57.1143442153 +-70.2892432329 43.4963035139 -56.2804927695 +-70.2574575508 40.3182868072 -58.6372356736 +-70.2397005086 40.3080966644 -58.665507888 +-70.1956420553 12.5037482697 -70.1158192968 +-70.1599672672 65.88459467 -27.1440449865 +-70.1360712824 44.1670412611 -55.9482258102 +-70.1104741812 11.9212416158 -70.3022432673 +-70.1029460256 41.7897429753 -57.7857624384 +-70.0171081191 42.0705229269 -57.6860093202 +-70.001452065 40.0415497491 -59.1309648364 +-69.9997959102 62.7631328901 -34.0707751944 +-69.9582981885 40.17907835 -59.088731392 +-69.925900562 41.8497881528 -57.9565670322 +-69.9187880493 42.6786105016 -57.3576436351 +-69.8920558104 10.9698004262 -70.673644403 +-69.8508999363 -61.1498403658 -37.1691915613 +-69.8501304193 68.4739846118 -20.7911690818 +-69.8423469195 68.4663544579 -20.842381918 +-69.834200516 71.561764062 1.44857261386 +-69.8074315228 42.0274921221 -57.9707892832 +-69.8046017027 13.404346374 -70.3394702811 +-69.8037655068 13.2779050329 -70.3642775775 +-69.8035204339 43.5672771542 -56.8274660389 +-69.7827004787 44.8857412322 -55.8179625922 +-69.7761129001 54.8689581957 -46.0509662773 +-69.7552379778 12.5258124313 -70.5500588065 +-69.7435037138 44.9466210274 -55.8179625922 +-69.6078956867 46.2999286724 -54.8731032748 +-69.604837634 44.3090219748 -56.4967003425 +-69.588431229 42.1940682564 -58.1129145979 +-69.5881971153 44.2984289595 -56.5254987944 +-69.5735698404 70.6751029904 12.827634114 +-69.5419823468 14.8831207364 -70.3022432673 +-69.5203842402 71.864855133 -1.5358293575 +-69.5011684541 43.2606672923 -57.4291062871 +-69.4934297543 70.7664227479 12.7583945876 +-69.4681704608 66.3852256256 -27.6979261222 +-69.4326470783 61.8187693876 -36.844908347 +-69.3365630513 40.3224483679 -59.7205256328 +-69.3229617343 13.814351891 -70.7353564932 +-69.2480562636 43.1534412357 -57.8142474935 +-69.2343823462 59.1944712826 -41.2627540369 +-69.2303438769 41.4006910295 -59.1028110073 +-69.1955711247 12.9746005423 -71.0185375623 +-69.1848318298 40.1050442573 -60.0420225326 +-69.1494419579 71.2321983127 12.0136838835 +-69.089593294 66.5328673247 -28.284371374 +-69.0597938225 41.5445404172 -59.2013178799 +-69.0137697962 69.2550947352 -20.9959860863 +-69.009494957 72.0882588985 -6.4009792035 +-68.9705014521 39.7399271494 -60.5293988043 +-68.9524540923 42.4530183827 -58.6796413149 +-68.9521900075 39.7293763275 -60.5571808277 +-68.921336466 43.9923365128 -57.5719003324 +-68.8430640614 11.2364744888 -71.65454746 +-68.8382546213 44.1594489771 -57.5433555394 +-68.8144271293 42.9666338086 -58.4674524674 +-68.7668144078 -65.3257352998 -31.6808071828 +-68.7550746836 47.2187255169 -55.1645870628 +-68.693123297 40.9005861193 -60.0699331346 +-68.6655593011 53.5509814121 -49.1663844071 +-68.6408822652 11.4619146074 -71.8126297763 +-68.6359483637 51.5708021796 -51.2792253721 +-68.6323210147 53.6214459226 -49.1359852787 +-68.6269465154 51.582780627 -51.2792253721 +-68.6209899538 40.8576371912 -60.1815023152 +-68.5999733121 15.9889585478 -70.9816657042 +-68.5879279855 45.2769501702 -56.9709918989 +-68.5865520062 39.7262538853 -60.9730238396 +-68.5838159621 46.1385556958 -56.2804927695 +-68.5732613947 45.3532365296 -56.9279523431 +-68.5696904135 42.1513677929 -59.3418886604 +-68.5680982794 45.5048032714 -56.8131039249 +-68.5672784685 68.1615945452 -25.5445757936 +-68.5469535074 11.8647575597 -71.83691734 +-68.5401945053 12.8888663133 -71.6667207449 +-68.5387349159 11.8386951855 -71.8490578396 +-68.5267135722 46.1001410676 -56.3814377303 +-68.513451871 42.5961117381 -59.088731392 +-68.5046925904 42.5906659273 -59.1028110073 +-68.4769408568 42.2427057078 -59.3840246647 +-68.4272480138 15.0071501487 -71.3617346599 +-68.4268558277 39.9373783718 -61.0145163901 +-68.4190502621 50.8495359616 -52.2796160442 +-68.39303474 42.2403991774 -59.4822786751 +-68.3782858927 42.2642702763 -59.4822786751 +-68.3735359077 50.8342367149 -52.3539870984 +-68.3660447376 13.9713702047 -71.6301943425 +-68.3593770102 42.8817563601 -59.060566762 +-68.2497285111 58.6004823782 -43.6801788368 +-68.2170630341 70.0756961947 -20.8765206353 +-68.2166416144 48.9825313368 -54.2881334243 +-68.184146084 48.9952792829 -54.3174449951 +-68.1724701581 40.9297713301 -60.640482612 +-68.1072611845 65.8853755195 -31.9455515932 +-68.0637310938 68.7082586822 -25.4264369988 +-68.0636379487 43.3112342433 -59.088731392 +-68.0499931873 13.3138792908 -72.055111168 +-68.0383487258 13.3732590356 -72.055111168 +-67.9205265223 40.3763731997 -61.2907053653 +-67.8995299786 69.5063876228 -23.6329411694 +-67.8172514794 68.9390954501 -25.4601948206 +-67.8140844231 12.1772432624 -72.4773392198 +-67.7867658283 43.9707960283 -58.9196357353 +-67.7723536881 56.4657963114 -47.1011881219 +-67.7703233994 43.1744576031 -59.5243603663 +-67.7511541967 44.0822200971 -58.8773214093 +-67.7378509986 43.9894747854 -58.9619339082 +-67.7297713523 41.8797657186 -60.4877119416 +-67.5467955019 73.071711697 -9.89724037811 +-67.5116719064 13.9441341107 -72.4412539946 +-67.5092371676 13.9559169079 -72.4412539946 +-67.4412408099 41.3766338558 -61.1527040186 +-67.4267935315 41.4001727686 -61.1527040186 +-67.4237587747 -64.1619142999 -36.5689144775 +-67.3771308556 44.5959500681 -58.9196357353 +-67.3751656095 16.0137534388 -72.1397723859 +-67.3683115387 47.4351251849 -56.669387672 +-67.3627242526 44.8404704465 -58.7502816283 +-67.3605889608 47.3945255431 -56.7125206934 +-67.3422384039 42.7366840309 -60.3207987745 +-67.3279837726 43.4398356884 -59.8324600571 +-67.3273575458 44.2594577008 -59.2294464767 +-67.2981336277 43.2544108805 -60.0001429133 +-67.2684659292 71.1841653617 -20.1932685142 +-67.184385846 43.0819497233 -60.2511734868 +-67.1820825214 69.4962255111 -25.6289373133 +-67.1580388238 41.8347297416 -61.1527040186 +-67.151757898 73.9283199871 -5.02443181798 +-67.1449430843 74.1025199741 -0.610861439068 +-67.1130140712 73.5496718308 9.28919349936 +-67.095368352 43.3561232696 -60.153621011 +-67.0686937853 45.1873291892 -58.8208772008 +-67.0142061764 74.2181557729 -0.872653549837 +-67.0072684741 45.9323866849 -58.3115925445 +-66.9462338931 44.6475879212 -59.3699811383 +-66.9453929432 41.8321243018 -61.3871952452 +-66.9219705013 45.8224295401 -58.4957674987 +-66.9132055883 51.4929060718 -53.5826794979 +-66.9103714951 71.8028226517 -19.1665553932 +-66.8663207059 14.054381995 -73.0162276621 +-66.8096605418 44.2706736761 -59.8044873781 +-66.6890567698 71.3902522683 -21.3541936916 +-66.6205198109 42.3276147805 -61.4009720373 +-66.6061527474 46.7248061225 -58.141318432 +-66.5895340421 46.7131479535 -58.1697151818 +-66.5761646569 44.956926803 -59.5524057617 +-66.4617158372 71.0722491562 -23.0559260896 +-66.414499002 71.4705128621 -21.9335385547 +-66.4116754776 44.0737063353 -60.3903781253 +-66.4103458228 42.9134709383 -61.2217280034 +-66.4073191956 63.7936669287 -38.9927687788 +-66.3847313844 72.2434497442 -19.3378232506 +-66.3557510549 52.8384981294 -52.9623207325 +-66.3412846993 52.8269786983 -52.9919264233 +-66.3351143463 45.6420186788 -59.2997363872 +-66.314252726 -65.2806872325 -36.6176427403 +-66.3102306688 50.7530369921 -55.0189289674 +-66.2331751039 14.7441932615 -73.4559410853 +-66.2281507102 45.6877408955 -59.3840246647 +-66.2042195877 48.8634875175 -56.8274660389 +-66.128674799 45.0592045417 -59.9722140278 +-66.124318131 45.8378900729 -59.3840246647 +-66.0949994586 42.7096983654 -61.7035875141 +-66.0487839852 46.1277019345 -59.243508069 +-65.9671525745 70.1987615244 -26.8415473035 +-65.9491038698 75.1476084914 1.88484397154 +-65.9468381887 44.6158020465 -60.5016094056 +-65.941236617 46.5681525504 -59.0183063249 +-65.9327605118 69.7707084916 -28.0164117595 +-65.8854102002 44.72526609 -60.4877119416 +-65.8406859577 72.7396223839 -19.3378232506 +-65.7551619015 75.3234643296 -1.62308493153 +-65.7512357972 75.1599519894 5.26845405152 +-65.6876091663 43.8578985748 -61.3320693815 +-65.6676579036 69.1267480255 -30.1537959944 +-65.6673094174 45.673972032 -60.0141046146 +-65.641129449 67.5474140626 -33.5944783874 +-65.6329529495 67.5390001093 -33.627354213 +-65.6075227298 47.8067582087 -58.3966337286 +-65.5662420082 48.4633597375 -57.8996603779 +-65.4907739545 43.3967282429 -61.8682673481 +-65.4730901285 56.2561243715 -50.4828974973 +-65.3949226495 44.1592688012 -61.4285200099 +-65.3623298706 42.9023727053 -62.3470308046 +-65.3610600541 74.3989334119 -13.8827423723 +-65.3228657512 73.1366822848 -19.5946144243 +-65.3191999841 66.7017708972 -35.8367949545 +-65.2515716049 71.5097026173 -25.0717936073 +-65.2422212633 72.7647260878 -21.183654123 +-65.2379438954 75.4989296452 -6.62739004 +-65.2226472092 50.8110199446 -56.2516359159 +-65.1959208524 44.925289394 -61.0836334633 +-65.1426400687 43.4118950908 -62.2241416936 +-65.1347172246 71.6574577213 -24.9535040626 +-65.1021212368 44.9109451935 -61.1941240013 +-65.1017803669 46.745924769 -59.8044873781 +-65.0681258024 45.6119844016 -60.709849971 +-65.0520241119 43.9938743262 -61.909394931 +-65.0253175287 46.3307574672 -60.2093762865 +-64.9926102143 -65.0607059776 -39.2818680211 +-64.9610582492 41.7042581985 -63.5674111417 +-64.959074139 42.2171610287 -63.2299770811 +-64.9355316242 40.2146797359 -64.5457687724 +-64.9152208174 44.8991618976 -61.4009720373 +-64.8690137758 40.5346585971 -64.4123629761 +-64.8640833322 40.5001019717 -64.4390598453 +-64.8612706879 44.9958645286 -61.3871952452 +-64.848553714 45.2389776794 -61.2217280034 +-64.8353161491 45.313908703 -61.1803192039 +-64.8069417548 45.4288974822 -61.125081382 +-64.7910801301 45.4515166042 -61.125081382 +-64.7752106108 50.0278642575 -57.4576791052 +-64.7615934908 72.3556191098 -23.8872432853 +-64.7306467164 46.6337115537 -60.2929541689 +-64.720375583 45.5706703593 -61.1112672705 +-64.684447397 45.3430303903 -61.3182832438 +-64.6842339663 48.1263899269 -59.1591114605 +-64.6550057232 58.0727545799 -49.4700455876 +-64.6527762294 45.3881776001 -61.3182832438 +-64.6506137427 51.8505097405 -55.9626909856 +-64.6473675425 44.8140564723 -61.7447828754 +-64.6464714286 45.0980031244 -61.5386370179 +-64.6421548268 58.0612119786 -49.5003786139 +-64.6260205258 42.9049161851 -63.108205791 +-64.5387415095 45.3081218249 -61.4973571877 +-64.5121382442 44.9708210897 -61.772237046 +-64.4974339791 65.22193112 -39.8268842755 +-64.4967877491 44.3274141109 62.2514636638 +-64.4663362548 44.1410216796 -62.4152360803 +-64.4661429604 45.5601654051 -61.3871952452 +-64.4552570777 50.3579659076 -57.5290805133 +-64.4181987457 73.3256969063 -21.7632222696 +-64.4106690671 73.3171260529 -21.8143241397 +-64.3860685367 57.1244479088 -50.904141575 +-64.3840062858 44.5483577518 -62.2104778651 +-64.364000989 44.7674742139 -62.0737354217 +-64.3484370596 40.0222168287 -65.2495272634 +-64.3466748019 47.2154798281 -60.2511734868 +-64.300896002 71.6142136388 -27.1440449865 +-64.298216039 48.4521811106 -59.3137889518 +-64.2811411838 49.5925670878 -58.3824646426 +-64.2461130718 39.6017986961 -65.6059028991 +-64.2248053039 44.7205730665 -62.2514636638 +-64.1763395377 45.3553525954 -61.8408395358 +-64.1555950966 73.7245713165 -21.183654123 +-64.1488440483 54.6528881253 -53.832960413 +-64.1276007515 45.2370460942 -61.9779031795 +-64.1109550973 45.7636733191 -61.6073992379 +-64.1029668531 45.7748620945 -61.6073992379 +-64.0895197295 45.6639983875 -61.7035875141 +-64.0712933507 52.3484423834 -56.1650242447 +-64.0127595176 73.3016903157 -23.0049737188 +-64.0013007343 73.4436612862 -22.5801266869 +-63.98695897 46.8656833407 -60.9038324474 +-63.9869341836 45.473147208 -61.950505541 +-63.9845305474 52.4080395937 -56.2083377852 +-63.9657445801 54.0935301314 54.6101961014 +-63.9511850757 54.0812176821 54.6394346734 +-63.9500117936 73.4883247217 -22.5801266869 +-63.9472260116 45.8999910733 -61.6761145412 +-63.9445817324 76.4768616867 -7.89810696443 +-63.9418086038 73.8164428511 -21.5076237017 +-63.9338492178 73.0825052858 -23.9041909578 +-63.9259347791 46.2236680796 -61.4560604976 +-63.9209475512 73.8444301002 -21.4735327167 +-63.9160379093 73.8387582552 -21.5076237017 +-63.9006923956 73.8470728583 -21.5246682117 +-63.8774135638 49.1922307647 -59.1591114605 +-63.8751987793 39.4809350647 -66.0394938452 +-63.8505189721 39.5427296459 -66.02638684 +-63.8158324494 45.8056795025 -61.8819784276 +-63.7929556126 63.2386720557 -43.9468903432 +-63.791178624 53.2998806529 -55.5860436814 +-63.7705792051 66.8955336063 -38.1877049766 +-63.7545609699 47.6077887215 -60.5710690725 +-63.7364227697 52.3536878969 -56.5398954378 +-63.7308699028 39.4071004122 -66.2227805105 +-63.5613927999 40.6492065505 -65.6322432357 +-63.5593800561 74.6292232629 -19.7657340379 +-63.5465768749 48.2869408944 -60.2511734868 +-63.5295074962 47.9076952973 -60.5710690725 +-63.5194063489 56.3555300338 -52.814195551 +-63.4961101059 48.3185538987 -60.2790291109 +-63.4729866319 40.4679076331 -65.829540632 +-63.4664798289 65.9053706161 -40.3545296352 +-63.4631257256 49.0498775869 -59.7205256328 +-63.4224670024 45.943957345 -62.1831445234 +-63.4204537378 65.9496625132 -40.3545296352 +-63.3731960555 46.4161477031 -61.8819784276 +-63.3666374021 39.6420184525 -66.4317667789 +-63.3565954073 39.1298308476 -66.744274333 +-63.3516718239 49.1937444728 -59.7205256328 +-63.3245412865 77.3123947729 3.57716163253 +-63.3207562692 73.6691707378 -23.7346815507 +-63.307968765 49.2839090384 -59.6925238263 +-63.2413170437 76.2557404486 -13.6234308163 +-63.2375704974 53.5345551066 -55.9916162217 +-63.222101053 58.6058259951 -50.6786256511 +-63.2139524158 39.072222055 -66.9130606359 +-63.2098325697 39.9132892726 -66.4187202975 +-63.20477819 74.34419561 -21.8654200292 +-63.1830686881 62.1983054301 -46.2522500293 +-63.1619634498 50.0077306508 -59.243508069 +-63.1361981977 73.1439896086 -25.7638751216 +-63.1034739462 41.2937562606 -65.6717387452 +-63.0964482659 46.5187136509 -62.0874181818 +-63.0890558618 41.3157810122 -65.6717387452 +-63.0541936526 53.720278871 56.0205346355 +-63.0331428007 55.2785826247 -54.507808722 +-63.0077306189 50.3344303611 -59.1309648364 +-62.9756438947 40.7095954023 -66.1573663187 +-62.9709150039 51.2298451367 58.3966337286 +-62.9700807231 53.7435264222 56.0928007986 +-62.9699378674 51.8715044352 -57.8284873795 +-62.963134004 72.5585864458 -27.7650011593 +-62.9619281164 72.3783712537 -28.2341456843 +-62.9482106913 51.1931186039 -58.4532922799 +-62.9465539779 74.9636244462 -20.4496051842 +-62.9413090971 39.223253763 -67.0815024682 +-62.9400094776 -51.82841436 57.8996603779 +-62.9279988631 52.206735688 57.5719003324 +-62.9255448009 40.552746342 -66.3012109666 +-62.9202346931 40.5182460176 -66.327338299 +-62.9052844128 58.9069240575 -50.723756673 +-62.8844072762 39.6004247182 -66.9130606359 +-62.8732189021 49.2457624976 -60.1815023152 +-62.8358566184 40.3708838182 -66.4969688239 +-62.7967917396 46.467181524 -62.4288714333 +-62.7613548045 71.8940161226 -29.8707681332 +-62.7442051932 74.4583720219 -22.7841074111 +-62.7207568928 41.6242505635 -65.829540632 +-62.7138643025 49.920612342 -59.7904983058 +-62.6739539813 47.6238636343 -61.6761145412 +-62.6618763793 77.7132067047 -5.84352225182 +-62.6466415681 39.9103122825 -66.9519624339 +-62.6463618022 52.8092207726 57.3290463408 +-62.6458174926 40.5584233096 -66.5621202286 +-62.6198034397 46.3023989503 -62.7283673359 +-62.6094787475 52.8529433109 57.3290463408 +-62.5789683539 52.7337292578 -57.4719628891 +-62.5301108611 53.879390585 56.4534897583 +-62.5163233382 53.3939842894 56.9279523431 +-62.5110874565 54.1870075924 -56.179463803 +-62.5054603265 73.2362415423 -27.0096344686 +-62.4990752496 51.740489122 58.4532922799 +-62.4554484774 42.2060779318 -65.7112162503 +-62.4508015166 48.6691597714 -61.0836334633 +-62.4395293964 41.6105072932 -66.1049986881 +-62.4283146194 56.6661298153 -53.7741133403 +-62.4238044431 -0.795378709554 78.1193702712 +-62.4101701968 0.795204987537 78.1302649748 +-62.3927435621 39.169250267 -67.623334614 +-62.386301357 58.584636481 -51.7280366086 +-62.3857832812 56.7269003862 -53.7593974759 +-62.378256879 52.1563183602 58.2122970157 +-62.3691932053 52.4825396928 57.9281172343 +-62.3686897366 42.4972004412 -65.6059028991 +-62.3679935518 38.9415832131 -67.7774776543 +-62.3572887492 53.5033218235 56.9996762596 +-62.3346299527 53.483880297 57.0426897773 +-62.3184951702 54.9411439901 -55.6585649903 +-62.3075725047 48.5575385352 -61.3182832438 +-62.2853980094 49.9535804723 -60.2093762865 +-62.2359293832 47.8416550405 -61.950505541 +-62.2319547385 52.8325802137 57.7572703422 +-62.2313915865 41.8177596954 -66.1704531892 +-62.2192257039 47.863376563 -61.950505541 +-62.2174523567 55.9815327256 -54.7271104292 +-62.2165815519 52.8195289586 57.7857624384 +-62.2125107921 54.0805105578 -56.6118528114 +-62.2117218248 51.5575231408 -58.9196357353 +-62.2111977249 51.4290115187 59.0323949356 +-62.2102726305 39.6781232365 -67.49465546 +-62.1937210643 51.5792359869 -58.9196357353 +-62.1887018715 40.8969697908 -66.7832555471 +-62.1827640595 52.8281803651 57.8142474935 +-62.1695067322 -1.30226552228 78.3151105291 +-62.1492876305 52.1124863325 58.4957674987 +-62.1317892162 51.7662551679 58.8208772008 +-62.1286359582 40.7333186338 -66.9389972068 +-62.12678284 52.4083371571 58.2548628905 +-62.1247552865 52.5366716836 58.141318432 +-62.1128752281 52.2668527851 58.3966337286 +-62.0980595276 52.7562185224 57.9707892832 +-62.0967415464 51.2432349633 59.3137889518 +-62.0646763777 52.1338491382 58.5665238866 +-62.0570231079 43.2915789551 -65.3816876087 +-62.0527360649 51.8289594325 58.8491028904 +-62.0480883838 50.2814230805 60.1815023152 +-62.0440627878 50.1527063115 -60.2929541689 +-62.0419077157 43.3132383047 -65.3816876087 +-62.029648518 1.44014540619 78.4235212544 +-62.0185548216 50.4011123325 60.1117853128 +-62.0147109571 52.4621779794 58.3257705184 +-61.9996665914 54.2192893641 -56.7125206934 +-61.988469432 45.2359219403 -64.1181801339 +-61.9835822656 53.3707825015 -57.5290805133 +-61.9820550279 54.0132677825 -56.9279523431 +-61.9817046928 55.3791203886 -55.6005513314 +-61.9812990977 54.1650567636 56.7843745053 +-61.978070338 52.5054596268 58.3257705184 +-61.9736642733 51.6345104323 59.1028110073 +-61.9730706837 39.9389186605 -67.5590207616 +-61.9633304736 41.9050292578 -66.3665141432 +-61.9595745058 53.993677492 -56.9709918989 +-61.949072943 48.0006949122 -62.1147780278 +-61.9468171473 39.5861817258 -67.7903094969 +-61.9363079567 49.4077174779 -61.0145163901 +-61.9295409973 51.0870916826 -59.6224874966 +-61.9250083179 51.0107434182 -59.6925238263 +-61.9195706633 45.2353484542 -64.1851230356 +-61.9166306324 52.9378914014 57.9992284871 +-61.8981480505 52.9595011571 57.9992284871 +-61.8913633687 51.7492121954 59.088731392 +-61.8798016865 54.4010169401 -56.669387672 +-61.8780343947 53.6004347978 57.4291062871 +-61.8774658791 43.8441234601 -65.1833725301 +-61.8752469903 49.518250558 -60.9868565477 +-61.8728042101 -2.12821049293 78.5316930881 +-61.8687389421 50.5849029675 -60.1117853128 +-61.852136603 39.4041567972 -67.9825391166 +-61.8449525878 61.8449525878 48.4809620246 +-61.8443638271 50.5649734707 -60.153621011 +-61.8418951109 56.6081160032 -54.507808722 +-61.8242882115 15.0711369096 -77.1402503197 +-61.8131843483 72.0423041701 -31.4489530921 +-61.8039340724 56.5931959279 -54.5663257682 +-61.8021577646 52.7280899576 58.3115925445 +-61.7980609283 52.967344269 58.0987100252 +-61.7941425527 43.0280707592 -65.8032603517 +-61.7932539674 42.4217060928 -66.1966208828 +-61.7896407709 38.6104527832 -68.4928699156 +-61.7354892983 38.8317839067 -68.4165325029 +-61.7246403348 52.6619539818 58.4532922799 +-61.719442063 65.4950809635 -43.6016609893 +-61.6902798459 68.9968232479 -37.8648617352 +-61.6898177864 74.7559492267 -24.6153293029 +-61.6889093305 54.3478307538 -56.9279523431 +-61.6849863244 39.555462866 -68.0465121782 +-61.6744574806 0.452105483834 78.7150360167 +-61.6693864866 43.6643595461 -65.5004616457 +-61.6657841907 53.7376586337 57.5290805133 +-61.6633065228 48.8386979387 -61.7447828754 +-61.6623249576 50.2547337895 -60.5988400266 +-61.6591721128 52.8483021568 58.3541211356 +-61.6560195824 40.4696334553 -67.5332808121 +-61.6411401192 40.8767832809 -67.301251351 +-61.6406650353 54.4775424639 -56.8561850734 +-61.6380103287 -3.62958607185 78.6611834876 +-61.6284714976 53.8567230038 -57.4576791052 +-61.6255670928 -3.6072678165 78.671958787 +-61.6237359979 54.2713128483 -57.0713567684 +-61.615975752 41.2950373094 -67.0685576537 +-61.5958788757 39.6502041756 -68.0720868959 +-61.5945597305 52.9235935864 -58.3541211356 +-61.5768986412 52.7405116664 58.5382266806 +-61.5745152126 62.1142125242 -48.4809620246 +-61.5743704647 52.8688961858 58.4249665637 +-61.5549928325 54.0773825463 -57.3290463408 +-61.5516354724 74.880880479 -24.5814952628 +-61.547557975 78.5509638339 -6.4532308253 +-61.5453367201 40.1209002584 -67.8416162135 +-61.539949009 49.3557221007 -61.4560604976 +-61.53840852 78.7655710437 3.00151544833 +-61.5373481754 2.63297684484 78.7795799206 +-61.524439518 54.2029331113 -57.2432125595 +-61.5241137417 62.1283987241 -48.5267503577 +-61.524093282 54.489375367 -56.9709918989 +-61.5203750623 53.7054722385 -57.7145190037 +-61.5163375039 53.6641215592 -57.7572703422 +-61.5144474106 50.1342137352 -60.8484459368 +-61.5108079247 48.7878348794 61.9368038909 +-61.4920897256 39.3712128741 -68.3273773681 +-61.485788453 40.0820812315 -67.9185142834 +-61.4743214633 44.1737811766 -65.342060399 +-61.4578441858 53.6697882872 57.8142474935 +-61.4549138652 78.885489224 0.610861439068 +-61.4457331238 51.7971226536 59.5103349486 +-61.4317347953 54.2928915356 -57.2575225515 +-61.4219006164 51.7770324822 59.5524057617 +-61.416755008 54.2796525156 -57.2861373028 +-61.4107528567 42.1591151357 -66.7182766905 +-61.4050787449 39.7703500513 -68.1743027916 +-61.3881706624 78.9133903368 2.04189330948 +-61.3835741664 53.9837600769 -57.6004381105 +-61.3819883793 54.8432886928 56.7843745053 +-61.3758502227 50.7204127426 60.5016094056 +-61.3747229297 48.8721494543 -62.0052932662 +-61.3717683182 55.2981914278 -56.3526048938 +-61.3542665039 55.8280869945 -55.8469218875 +-61.3495607224 48.7122928777 -62.1558036049 +-61.3188643625 40.4016379858 -67.8800745533 +-61.3103899275 51.3908448786 60.0001429133 +-61.3037600848 53.7998230762 57.8569618666 +-61.3032401123 64.3297645997 -45.8649554484 +-61.3011295021 78.9435543132 3.17596507649 +-61.2952572811 54.6120821399 57.1000168056 +-61.2909440835 52.5698152744 58.9901237104 +-61.2784832222 54.4055832714 57.3147450739 +-61.2705957926 51.0125123792 60.3625519008 +-61.256604831 49.9952836261 -61.2217280034 +-61.240009907 53.6115759887 -58.0987100252 +-61.233660374 52.4465286592 59.1591114605 +-61.2284165092 41.9710781718 -67.0038029434 +-61.2271790137 53.6569969557 58.0702955711 +-61.2231311677 54.1656509193 -57.6004381105 +-61.2070689397 54.860140915 56.9566471151 +-61.2005013751 50.6834563535 60.709849971 +-61.1468364284 53.004422489 58.7502816283 +-61.1435812971 58.0636689264 -53.7593974759 +-61.136429919 48.9795162797 62.1558036049 +-61.1109832287 39.8073587306 -68.4165325029 +-61.1024225067 54.0588569173 -57.8284873795 +-61.0933441078 49.0852081209 62.1147780278 +-61.0717926106 48.0070043169 62.9727217439 +-61.0620421558 49.5883937574 61.7447828754 +-61.0573941662 40.1072114869 -68.2891367963 +-61.0484481634 53.7835854869 -58.141318432 +-61.0299058374 39.6030033588 -68.6072351756 +-61.0296704315 53.8048921382 -58.141318432 +-61.0134512516 55.5763942685 -56.4678950066 +-60.9939916438 50.3153356704 61.2217280034 +-60.9782948541 49.5203826981 61.8819784276 +-60.9765851645 39.9475738854 -68.4547105929 +-60.9722331672 55.1506575176 -56.9279523431 +-60.9584154704 39.3603502929 -68.810133034 +-60.9514594806 51.6540295054 -60.13967761 +-60.9494962692 -6.19102406296 79.0368909154 +-60.9449875951 48.0969180128 63.026938405 +-60.9436956356 52.0508333432 59.8044873781 +-60.9382419101 42.2271171361 -67.1073859667 +-60.9274638328 49.5144067386 61.9368038909 +-60.8950722917 49.8953069016 -61.6623752364 +-60.894246939 40.9964166128 -67.9057031084 +-60.8912885045 53.7774037974 58.3115925445 +-60.8724628943 79.3305381512 -1.09953527232 +-60.8636512327 4.28802623018 79.2289643355 +-60.8547546267 51.4262548322 -60.4321036641 +-60.8276403 55.3100932702 56.9279523431 +-60.827306496 47.3868758138 63.675134747 +-60.8179027729 51.4861551741 -60.4181969914 +-60.810575077 52.7315295532 59.3418886604 +-60.808965411 42.3105687086 -67.1720589323 +-60.7744972625 40.5775422595 -68.26363268 +-60.7715624396 55.2978670922 56.9996762596 +-60.7193845226 51.0942557464 60.8484459368 +-60.7130648267 54.13139565 -58.1697151818 +-60.7123775863 73.310468845 -30.6526078098 +-60.690499199 79.4660766556 1.34386307119 +-60.6508483399 57.7166655215 -54.6832800472 +-60.6485867092 47.4350293254 63.8096146601 +-60.6072231065 55.4779362775 -56.9996762596 +-60.574750186 48.8253165875 62.8234677493 +-60.5369872186 50.5808838061 61.4560604976 +-60.5268632546 55.0173038221 -57.5290805133 +-60.5087607214 -8.05209584768 79.207661425 +-60.4660026343 50.1107707456 61.909394931 +-60.4604774041 68.2180883218 -41.1196193781 +-60.3837970425 53.3292021918 59.243508069 +-60.3587333761 54.0997743533 -58.5665238866 +-60.3580074852 71.8809008517 -34.4970582103 +-60.3549378036 39.6910370179 69.1513055782 +-60.3534149745 61.2447923551 -51.0542917912 +-60.3478198051 57.2679426736 -55.4844427448 +-60.3425057697 71.8624397175 -34.562577382 +-60.3417515027 49.9722789824 62.1421303053 +-60.3401171541 56.4652829547 56.3093427655 +-60.3337672781 57.2546073233 -55.5134800412 +-60.3236497716 54.6406183314 58.0987100252 +-60.3127253021 32.2445906373 72.9565729819 +-60.301608554 51.8309547895 60.640482612 +-60.2975433709 55.4464334296 -57.3576436351 +-60.2923895333 41.4378112748 -68.1743027916 +-60.2764817526 56.0123633774 56.8274660389 +-60.2502130423 6.22625384588 79.5684962244 +-60.2410753784 34.0827605779 72.1760228098 +-60.2345727417 49.7949669617 62.3879596709 +-60.2337066433 53.8551493251 58.9196357353 +-60.2325648082 75.1287713682 -26.9760236013 +-60.2112225566 66.4503254782 -44.2601730913 +-60.1971727365 79.6527062692 -5.6344279679 +-60.1967113795 53.9735030186 58.8491028904 +-60.1941241176 75.0808238523 -27.1944353017 +-60.1912624108 67.4386118867 -42.7673421689 +-60.1766569438 40.1783799153 -69.0251240234 +-60.1480279222 66.4971144151 -44.2758231039 +-60.1369765863 48.4724561211 63.5135028529 +-60.0350051748 54.7618763977 -58.2832312683 +-60.0216630147 49.7955624393 62.5923472184 +-60.0055260411 41.1174145498 68.6199319824 +-59.9906848882 7.17469541783 79.6846376179 +-59.9883334055 68.4517702544 41.4216731225 +-59.9369769744 48.2422589047 63.8767817516 +-59.9363413641 56.5206646665 56.6837670727 +-59.9257720413 54.0901226085 59.0183063249 +-59.9055677357 53.5241433584 59.5524057617 +-59.9022509878 53.9930488499 59.1309648364 +-59.8843314991 54.6244370291 58.5665238866 +-59.8771989763 54.8289053786 -58.3824646426 +-59.8650777326 7.17027129737 79.7794439539 +-59.8611949826 78.8642119385 -14.0382837472 +-59.822872735 56.1774167757 57.1429938149 +-59.7937689187 53.4617996016 59.7205256328 +-59.7872806697 57.3339408142 56.0205346355 +-59.7862012917 58.2004786761 55.1209072583 +-59.7811218858 58.6442846726 -54.654051463 +-59.7786479326 52.2401741437 60.8068865901 +-59.7550614043 55.7810197652 57.6004381105 +-59.7372688737 49.1561123049 63.3650955225 +-59.7330015894 58.8020106376 -54.5370705676 +-59.7238553433 11.4253472474 -79.3884282702 +-59.7198635062 11.4461941093 -79.3884282702 +-59.6884376511 54.9440389191 -58.4674524674 +-59.6632725501 37.3252021621 71.043107985 +-59.6572938103 55.7677468739 57.7145190037 +-59.6550777925 30.1078158034 74.396176791 +-59.6352098679 55.7471027644 -57.7572703422 +-59.6343357304 56.5513225668 56.9709918989 +-59.6206713791 51.6086291548 61.4973571877 +-59.6195641601 44.5200401512 66.8092328522 +-59.6004896462 79.9601911418 7.35863210847 +-59.5845315706 42.4698599855 68.161533069 +-59.5822012469 75.0394132041 -28.6190104747 +-59.5818869286 51.7025277732 61.4560604976 +-59.5588993504 59.2478632627 -54.2441536663 +-59.5487165524 56.3518098043 57.2575225515 +-59.5349570813 52.0822179581 61.1803192039 +-59.5198428055 75.772197735 -26.7574730274 +-59.5081363879 47.2840573223 64.984610692 +-59.5043372331 53.1096515302 60.3207987745 +-59.5031399822 55.7405208119 57.8996603779 +-59.4916774316 75.8180295005 -26.690198932 +-59.491256683 50.3096166091 62.6875813454 +-59.4857159296 50.1804103473 62.7963057649 +-59.470908869 42.6083963225 68.1743027916 +-59.468918026 -10.6680043359 79.6846376179 +-59.4604284702 40.5915753534 69.4030363635 +-59.4408391813 47.3322149167 65.0111380342 +-59.3962675751 67.5380001451 43.7115766651 +-59.3910344339 55.8304420774 57.9281172343 +-59.3688099841 55.3042224672 -58.4532922799 +-59.3359731986 68.3304548135 -42.5463421407 +-59.3284886148 41.5885668121 68.9240273721 +-59.3234819411 67.6931184114 43.5702445497 +-59.3172456382 44.1815112517 67.301251351 +-59.3134544048 67.6816761431 43.6016609893 +-59.3026538765 68.1718242597 -42.8462089374 +-59.2947366063 54.8114907243 58.9901237104 +-59.2884819346 42.7602017671 68.2381202461 +-59.2675362301 47.312652587 65.1833725301 +-59.2392051663 56.9076747756 57.0283536751 +-59.2383889529 58.6622133301 -55.2228032744 +-59.2332365736 47.3191335744 65.209840383 +-59.2273724693 58.467322725 55.4408741251 +-59.1973725756 49.2863936162 63.7692910769 +-59.1586006154 75.1231979787 -29.2705500237 +-59.1138894025 -11.6512654353 79.8110023334 +-59.0915881095 57.3037435665 -56.7843745053 +-59.0735699322 47.2084745384 65.4344960034 +-59.0342279427 56.1782544144 57.9565670322 +-59.0196639442 44.8308431407 67.1332612883 +-59.0085434125 49.3388005722 63.9036349704 +-58.9846312631 57.2999873646 56.8992506345 +-58.9766864778 56.4578949507 57.7430216549 +-58.9761126425 57.2517116511 -56.9566471151 +-58.9669098915 55.7622347102 -58.4249665637 +-58.9213849879 79.4245597707 -14.832723834 +-58.9182965628 79.4203966506 -14.8672433897 +-58.9053410186 52.2618504444 61.6348909921 +-58.8669800532 57.506085607 56.8131039249 +-58.8478853789 54.5319079593 59.6925238263 +-58.8375396482 58.5711473305 55.7455346062 +-58.8338323663 43.9813079594 67.8544377272 +-58.8314926012 57.4714185585 56.8848971802 +-58.8286734813 54.475948945 59.7625146976 +-58.810844693 57.5918341307 56.7843745053 +-58.8084563386 48.6851730737 64.5857521893 +-58.8048184505 56.5496186937 -57.8284873795 +-58.7701030268 51.9588340005 62.0189854765 +-58.7660655026 52.4507188176 61.6073992379 +-58.7397974675 80.8483952464 -3.62948750656 +-58.7388455293 58.9854069877 -55.4118199338 +-58.7339181927 57.9802008211 -56.4678950066 +-58.7244176901 80.0314011801 12.1003137194 +-58.698496827 48.9057437915 64.5191033296 +-58.690069247 79.6052733907 -14.780941113 +-58.6794510396 55.7236613503 58.7502816283 +-58.6737466609 57.6182846846 56.8992506345 +-58.6532865312 43.8463406855 68.0976533192 +-58.6527508995 46.7046671828 66.1704531892 +-58.6417238701 57.1661471122 57.3862339406 +-58.641053492 47.9971461365 65.2495272634 +-58.6358141254 58.288890525 56.2516359159 +-58.6340238598 43.9117550509 68.0720868959 +-58.6247202826 54.572866419 59.874405405 +-58.6246036056 54.8023861903 59.6645147464 +-58.6224017837 60.2406520402 -54.1708210283 +-58.620945871 79.744390721 14.2974422091 +-58.6201838913 47.8605870603 65.3684805299 +-58.6124868767 79.7037302258 14.5565026779 +-58.5905552146 79.5574748821 -15.419307054 +-58.5843447863 58.075317752 56.5254987944 +-58.5832507978 47.0684834789 65.9739387103 +-58.5705172206 47.1761180019 65.9083333334 +-58.5540460809 47.1965600947 65.9083333334 +-58.544420617 48.3118023065 65.1039213298 +-58.5324489994 57.6201697073 57.0426897773 +-58.521929203 56.3759590188 58.2832312683 +-58.5069324426 61.2240075674 -53.1842058656 +-58.4642254755 79.5311977697 16.0225753504 +-58.4388366154 42.1939505025 69.315026625 +-58.4352266483 26.7784129147 76.6044443119 +-58.4216588578 42.1350292471 69.3653305813 +-58.4064781007 57.9596620027 56.8274660389 +-58.4000431166 61.2618247413 -53.2580866475 +-58.38387749 55.9294728942 58.8491028904 +-58.3820539667 41.9826712325 69.4909425092 +-58.374683835 55.1443251376 59.5944602483 +-58.3571534811 57.9107147219 56.9279523431 +-58.3441248346 -69.2858756328 -42.3725209904 +-58.3389623484 -12.5067898375 80.2505182542 +-58.324484621 55.8725768468 58.9619339082 +-58.322518106 55.5009758649 59.3137889518 +-58.3128072157 42.4912595239 69.2395073545 +-58.3053545608 70.9821003508 -39.5224880204 +-58.2910945188 58.4949247815 56.3958515726 +-58.2820208558 59.9745895325 54.829322952 +-58.2803699146 79.7175734537 15.7641036938 +-58.2420261252 58.9991471117 55.9192903471 +-58.207912228 43.5450817964 68.6706983029 +-58.1721135749 55.8825816625 59.1028110073 +-58.1488336614 54.2816150391 60.5988400266 +-58.1453364383 54.3163459916 60.5710690725 +-58.142521149 59.0012451868 56.0205346355 +-58.1424596383 58.9188510352 56.107248907 +-58.0633349975 46.7174993982 66.679264985 +-58.0604048711 48.8394664942 65.1436558597 +-58.0439939573 75.1814765228 -31.2832279878 +-58.0206357314 54.2947506286 60.709849971 +-57.9616125626 57.1978349846 58.0418740413 +-57.9484251371 24.9925121244 77.5716079622 +-57.945223005 25.6414988149 77.3619070953 +-57.9332808829 57.269751711 57.9992284871 +-57.9242249695 79.6966012873 17.1241322388 +-57.9232845433 57.2798621036 57.9992284871 +-57.9144246144 81.2830192277 6.24421386623 +-57.842994635 77.7438283646 -24.6999012723 +-57.8337936739 80.6326335504 12.3947858395 +-57.8137398976 47.1181407761 66.614204858 +-57.7954668301 59.6402951999 55.7020574338 +-57.7721028863 73.9981471158 -34.447907796 +-57.7696809469 80.6918365215 12.3081876034 +-57.7657089422 81.4949244672 4.65834267608 +-57.7439526446 79.536101836 -18.4294448562 +-57.7178031774 58.366144992 57.1143442153 +-57.7110922251 47.1519401005 66.679264985 +-57.6738921967 53.9325247183 61.3596360516 +-57.6364903997 47.0406855342 66.8222184522 +-57.6322233401 44.3827868391 68.6199319824 +-57.6290173794 45.7581364852 67.7132874795 +-57.6092968903 45.4970811938 67.9057031084 +-57.6023674523 57.1417525591 58.4532922799 +-57.5967608493 81.7091507198 2.49556172556 +-57.5797386367 45.0347937023 68.2381202461 +-57.5601675243 60.2964504308 55.2373531229 +-57.5575674351 45.5051818103 67.9441304262 +-57.5468978143 45.4804268749 67.9697382902 +-57.5318244271 78.0913239597 -24.3276447751 +-57.5202236718 80.4323404102 -14.9017611339 +-57.4609707274 59.4610261096 56.2372049186 +-57.4570633485 42.6713810666 69.8415285431 +-57.4530299384 80.4867344653 -14.8672433897 +-57.4456250569 46.5517609462 67.3270652459 +-57.4237650374 59.3602955551 56.3814377303 +-57.4071734067 60.3889077117 55.2955356864 +-57.3995074103 61.5103744959 54.0534030235 +-57.3944795361 80.4047104068 15.5227659645 +-57.3857796557 42.6650789426 69.9039579147 +-57.3753857932 23.1462223643 78.564098005 +-57.3741595677 57.7156388758 58.1129145979 +-57.3510778279 57.7528680273 58.0987100252 +-57.3470830294 44.0835284547 69.0503771677 +-57.3102973156 47.1254846926 67.0426618959 +-57.3071936396 61.5189896563 54.141476419 +-57.3039736365 79.6882042789 19.1322947989 +-57.3036627726 -13.7045141477 80.7989883898 +-57.2995888634 78.4334831687 -23.7685892326 +-57.2863460914 81.2687834862 10.6611154275 +-57.2784647396 -13.3818187012 80.8709119852 +-57.2519861488 45.085239635 68.4801522272 +-57.2283430839 80.1719675815 17.2444878725 +-57.222927923 80.2235862066 17.0209499166 +-57.2228043082 81.9659781416 2.67003640471 +-57.1899429476 44.0899078411 69.1765166238 +-57.1612493681 44.0677868666 69.214317387 +-57.1528086788 47.7363415428 66.744274333 +-57.1461716601 59.6956697082 56.3093427655 +-57.1083240312 77.6867114185 -26.5219568533 +-57.1047087873 24.8535395783 78.2390810577 +-57.0627314821 59.2555389369 56.8561850734 +-57.0550189864 44.6565029897 68.9240273721 +-57.0545127014 45.6602566105 68.26363268 +-57.0291340145 45.5583615916 68.3528606764 +-56.9267713911 61.6909512744 54.3467499475 +-56.9214620938 59.2535573565 56.9996762596 +-56.9057651888 61.9930467842 54.0240320478 +-56.8915145261 81.0085306298 14.1765136802 +-56.8749089634 58.8545651777 57.4576791052 +-56.8620472014 42.8953236462 70.1904466245 +-56.8366827526 44.4856129813 69.214317387 +-56.834864163 22.3076758251 79.1970063504 +-56.8019808006 58.3496001264 58.0418740413 +-56.7765564177 79.8038504589 20.1932685142 +-56.7437584097 46.328575061 68.0720868959 +-56.7324838641 45.9082794232 68.3655992076 +-56.7055313527 58.3726979927 58.1129145979 +-56.6891918254 43.5463248811 69.9289147602 +-56.6860844502 45.8707327284 68.4292606175 +-56.6751638852 81.6360504434 11.1122034978 +-56.6477686904 81.6574211294 11.0948581284 +-56.5718644868 61.62929591 54.7855275974 +-56.5571926799 77.4740281076 -28.2676303383 +-56.5372459519 81.1951494512 14.5219670077 +-56.5029219544 67.5048788736 47.4395524734 +-56.501570536 60.0629383861 56.5686835572 +-56.4844657863 81.6957298965 11.6324048041 +-56.4576935988 80.9302058471 -16.2120515372 +-56.4450830538 44.689720771 69.4030363635 +-56.4421400228 65.0438063609 50.8290082898 +-56.4317901815 20.5060363482 79.9684658487 +-56.4295918467 64.9606025492 50.9492029423 +-56.4226460777 48.2747107038 66.9778867692 +-56.419439797 60.9701298932 55.6730641675 +-56.4084474543 64.0954944619 52.056264229 +-56.4048778397 48.2595083585 67.0038029434 +-56.3958405764 46.9372379493 67.9441304262 +-56.3938391592 64.8736909306 51.0993065504 +-56.3601079043 63.8830267215 52.3688565266 +-56.3408431395 61.0559869099 55.6585649903 +-56.3324940322 80.3615509507 19.2008136522 +-56.3264012675 12.3841625002 81.6943635719 +-56.3251435407 -25.1954542968 78.6935021961 +-56.2555325959 80.3412267451 19.5090322016 +-56.2271701841 43.0200258681 70.6242359774 +-56.2240014525 80.8054220008 17.5882186689 +-56.2216409704 65.4329569901 50.5732659231 +-56.2173651626 63.654017475 52.7993741769 +-56.2061939885 81.3843163122 14.7464170468 +-56.2018437922 81.1355102923 16.0742565604 +-56.1968192761 67.6413396721 47.6084726767 +-56.1772988088 64.4426424406 51.8773258161 +-56.1681408759 60.4018226084 56.5398954378 +-56.1583293953 81.4973937363 -14.2974422091 +-56.1535241381 63.6488682583 52.8734649546 +-56.1429269157 80.8392837194 17.6912963085 +-56.1328068033 63.0463757675 53.6121488374 +-56.1325093301 71.1271163756 -42.3092745435 +-56.0988696721 44.3042176545 69.9289147602 +-56.0888842708 63.5085406298 53.1102845816 +-56.0774401855 21.9200751608 79.8425388323 +-56.0678216984 46.2680728428 68.6706983029 +-56.0527371149 80.8298055292 18.0175803048 +-56.0522249837 21.8313122625 79.884553446 +-56.022309606 67.8397902039 47.5317124823 +-56.022048254 62.9440922683 53.8476680827 +-55.9815452706 80.3073882156 20.4154350213 +-55.9630868966 67.8886530541 47.5317124823 +-55.9365727554 60.8305658834 56.3093427655 +-55.9359054672 -15.061249811 81.5127795729 +-55.9338792847 59.2519091511 57.9707892832 +-55.9312943981 60.8887819203 56.2516359159 +-55.9288561618 62.0717009731 54.946037043 +-55.9208063276 21.9376454175 79.9475023575 +-55.9111108245 82.8916306146 1.71033926951 +-55.9100367965 60.9083019152 56.2516359159 +-55.9007041673 -51.0443573415 65.342060399 +-55.8897455949 64.1127816367 52.5917062677 +-55.8734222671 65.0276863676 51.4738835705 +-55.855664197 64.4815424233 -52.1754296948 +-55.8510244852 64.5216823534 52.1307545528 +-55.8321840421 44.5224036709 70.0037341608 +-55.8244200597 64.6047945552 52.056264229 +-55.7974406411 82.0418241209 12.4813746365 +-55.795696039 59.3125716969 58.0418740413 +-55.7831207918 82.0515613618 12.4813746365 +-55.7748839637 65.5352669577 -50.9341840379 +-55.7540158256 22.0183142967 80.0417613178 +-55.7272870303 81.4791356021 -15.9881187692 +-55.7263776939 59.2803333333 58.141318432 +-55.7217902399 22.0618174563 80.0522223488 +-55.7152268113 81.7367420308 14.6600990296 +-55.7124735693 59.2655424717 58.1697151818 +-55.7119998449 60.8629273342 56.4967003425 +-55.6894466815 60.9236327087 56.4534897583 +-55.6874022287 80.8139806589 19.1836848149 +-55.6706154153 81.2136303485 17.4679370533 +-55.6692272145 81.8533053775 14.1765136802 +-55.6390003903 76.636755858 -32.1108904756 +-55.6348917753 61.2922135124 56.107248907 +-55.6298309572 59.5097588851 57.9992284871 +-55.6217250597 61.2777079186 56.1361399958 +-55.6055953147 59.421434909 58.1129145979 +-55.5822120601 41.2037848815 72.2001787667 +-55.5577647979 62.5322378674 54.8001277184 +-55.5486099661 23.4075475304 79.7899658444 +-55.5454846332 22.724257734 79.989419596 +-55.5258348663 82.1038838674 13.2602381688 +-55.5180289783 62.2464199176 55.1645870628 +-55.514630259 22.2042679423 80.1566984871 +-55.50904785 68.8422747419 46.6849741903 +-55.4964013034 24.4421270306 79.5156077043 +-55.4949315155 69.2689975148 46.0664580728 +-55.4804281886 80.3334365205 21.6439613938 +-55.4736820907 59.6967916486 57.9565670322 +-55.4587689875 80.5423452242 20.9106568088 +-55.4438549343 64.413933632 52.6955795497 +-55.4306510271 80.5616990793 20.9106568088 +-55.401443446 64.7522479197 52.3242434579 +-55.399076995 13.8330830727 82.0949942494 +-55.3877050617 58.7143804886 59.0323949356 +-55.3735617318 58.6993876875 59.060566762 +-55.3647947817 80.8279775063 20.0393999665 +-55.3200426779 69.7965232787 45.4767876649 +-55.3088154236 23.9686521732 79.7899658444 +-55.2831102056 65.1876060144 51.9071647088 +-55.2659422807 77.2801077405 -31.2003296688 +-55.2602609617 56.627293328 61.1527040186 +-55.2239388877 64.0905359794 53.3171620737 +-55.1848982115 63.3042303381 54.2881334243 +-55.179181676 43.4217342798 71.2026045991 +-55.1753215547 -16.4379925545 81.7647619217 +-55.1653525992 66.8495781954 49.8790313429 +-55.1353423339 82.2049164409 14.2283427941 +-55.0821803031 70.7307048719 44.3071190824 +-55.0686153319 43.5217922744 71.2271100259 +-55.0674032256 20.0646670108 81.0246273656 +-55.0403681257 64.8554668734 52.5768608156 +-55.0223440101 70.5014468069 44.7446941857 +-54.9800466972 70.9565336393 44.0722679139 +-54.9754367819 81.5965626073 17.8802215116 +-54.9684278389 62.0213605024 55.9626909856 +-54.9613011789 63.561057745 54.2148255651 +-54.9532946747 60.882069605 57.2145873446 +-54.931707857 70.9452837856 44.1505852792 +-54.9220078864 81.88684205 16.6768746716 +-54.9091883255 70.8650847459 44.3071190824 +-54.9073357267 70.837154604 44.3540529265 +-54.8986437982 70.9025809618 44.2601730913 +-54.8984456984 42.7680589284 71.8126297763 +-54.885856823 44.1293618723 70.9939584863 +-54.8854852128 70.8344938168 44.3853354011 +-54.8704776042 81.6558850402 17.9317351584 +-54.8511382897 44.1329803077 71.0185375623 +-54.8465204519 70.8352627273 44.4322489715 +-54.8461933053 70.9626819178 44.2288690219 +-54.844990867 71.0123425631 44.1505852792 +-54.838768741 -11.6563401298 82.8060334622 +-54.8278271329 18.6969553187 81.5127795729 +-54.8231163673 63.6927678166 54.200159037 +-54.8184299484 61.3110773906 56.8848971802 +-54.8172119165 71.0532474003 44.1192623644 +-54.8040374297 62.0100900481 56.1361399958 +-54.7999314062 70.851697878 44.4635179185 +-54.7908854922 81.383935154 19.3549468051 +-54.7461484466 22.5312065585 80.5928282249 +-54.7442312222 63.1316445962 54.9314536351 +-54.7436943775 -16.6324060469 82.0151875874 +-54.7399054438 62.3530095831 55.8179625922 +-54.7344763601 41.4704943664 72.6934329537 +-54.7211066249 70.5968963671 44.9630816679 +-54.7199996231 64.752375243 53.0363228518 +-54.7114259628 80.1438426976 24.1583183765 +-54.6790101368 80.3671711946 23.4802820391 +-54.6485895489 62.7553218197 55.4553986878 +-54.6358454645 82.6397393702 13.6234308163 +-54.6136307337 79.4039332719 -26.690198932 +-54.5734315654 66.2735362902 51.2792253721 +-54.569797889 81.9168459771 -17.6569392453 +-54.564078509 83.797002772 0.907558751868 +-54.5526895642 61.8778801136 56.5254987944 +-54.5423402221 44.1202508666 71.2638518925 +-54.4954150988 -16.9525660772 82.1149209134 +-54.4860825582 80.778939328 22.4951054344 +-54.4618727419 81.6004125619 19.37206977 +-54.4436386394 62.740737467 55.6730641675 +-54.4390536911 82.3420809241 16.0053473036 +-54.4261816035 64.7936686728 53.2876276071 +-54.4122711363 62.4839472398 55.9916162217 +-54.401536194 -17.3931358552 82.0850271661 +-54.3938887497 65.5177556753 52.4283182828 +-54.3932032291 64.4797165546 53.7005176466 +-54.3873433666 41.4020584534 72.9923724601 +-54.3868177029 71.3929031839 44.1035988909 +-54.3859693229 80.9959194675 21.9505665171 +-54.3761537703 64.1862600011 54.0680860418 +-54.3570786496 82.5935821435 14.9535343444 +-54.3452255427 62.6715068943 55.8469218875 +-54.2831490037 63.1099829334 55.4118199338 +-54.2756986532 21.9288056814 81.0757424702 +-54.273686596 -2.17985643344 83.9619864534 +-54.1951100497 20.8578348448 -81.4115518356 +-54.1844813637 -9.87629984983 83.4655658378 +-54.1806306379 82.4821272381 16.1603821103 +-54.1801238564 63.6164253982 54.9314536351 +-54.1519461105 63.8537830964 54.6832800472 +-54.1347971194 84.0651922181 -1.57073173118 +-54.1076522885 71.2841993684 44.619781311 +-54.0977703856 71.1937443311 44.7759087839 +-54.0863238512 42.3329292615 72.6814465487 +-54.0828293455 81.339588882 21.4223913346 +-54.0827141686 62.9880575953 55.7455346062 +-54.0777516015 63.7662959344 54.8585115048 +-54.0763366023 80.992144615 22.7161248969 +-54.0750819141 63.3137861966 55.3827589908 +-54.0670473746 61.8691465473 56.9996762596 +-54.0561785275 63.5832167355 55.0917789925 +-54.0511451704 63.3977055976 55.3100771174 +-53.9867887199 40.9782029974 73.5269577966 +-53.9736499415 63.463694198 55.3100771174 +-53.9267276732 64.5643099107 54.0680860418 +-53.9090026492 40.889508467 73.6333316555 +-53.8987060753 38.2047960393 75.0687887408 +-53.867695794 64.3793609785 54.3467499475 +-53.8540829029 83.0231525554 -14.3838066745 +-53.8393293457 21.0668893965 81.5935829999 +-53.8356516598 21.0762858112 81.5935829999 +-53.7449291064 -17.8785583206 82.4126188622 +-53.7284774749 41.9018315419 73.1948578909 +-53.6877485539 71.7658947147 44.3540529265 +-53.6610055286 83.8428815409 -9.5324551175 +-53.6422211258 -18.9746366359 82.234270698 +-53.6122579555 82.3352405332 -18.6181084768 +-53.5966780819 80.8224150336 -24.3953546137 +-53.5689649931 71.8159489701 44.4166124676 +-53.5684624721 80.8411188792 -24.3953546137 +-53.5140354061 64.3893383864 54.6832800472 +-53.5037336502 72.095400909 -44.0409315668 +-53.5027965315 64.3986773667 54.6832800472 +-53.4905953044 64.3839913514 54.7125019684 +-53.4896382283 84.1887151389 -7.14974443327 +-53.4558370924 -9.21421118274 84.0093553899 +-53.441440653 83.3395515306 14.0901231938 +-53.424994768 82.4877328575 18.4809053369 +-53.4161884729 66.2467122919 -52.5174629961 +-53.4126862283 20.4283728484 82.0351542489 +-53.396366211 -9.12720802558 84.0566603496 +-53.37987454 83.4677835354 13.5542652249 +-53.3304944073 15.9796257803 83.0693079675 +-53.3270806098 81.2754283927 23.4633163303 +-53.324833275 81.2720032456 23.4802820391 +-53.3059840195 23.811430983 81.1879783112 +-53.2801050413 23.7998710144 81.2083526892 +-53.2008746439 63.8990148512 55.557023302 +-53.1896185252 64.4095644602 54.9751988372 +-53.059096094 79.1989137925 -30.2037146025 +-53.0378977456 16.5397775347 83.1469612303 +-53.0079412226 67.554956002 -51.2492545011 +-52.9963141224 82.3919982907 20.0735972635 +-52.9843568655 67.573455148 -51.2492545011 +-52.9717336941 64.9960712217 54.4931753083 +-52.9125914736 79.4291489738 -29.8541112219 +-52.899118575 -18.0392422628 82.923271719 +-52.8969557776 82.808158709 18.5666615386 +-52.8921841664 41.0273835525 74.2911209563 +-52.8634117117 79.5056070027 -29.7374874078 +-52.7876687786 81.3480337779 24.4122802168 +-52.7814468173 65.5765387938 53.9799632428 +-52.7637178205 65.5545119962 54.0240320478 +-52.7572905147 83.6152448167 -15.0053034553 +-52.7571909902 38.3725640842 75.790666473 +-52.7511328323 -19.4086378059 82.7080574275 +-52.74738446 81.3792363315 24.3953546137 +-52.7473425383 83.8911860673 13.4159142573 +-52.734609006 -18.6018291012 82.9037572555 +-52.7109429507 84.1262616119 12.0136838835 +-52.7039680481 64.9679745557 54.7855275974 +-52.6893696609 80.6713577543 -26.7574730274 +-52.6581450874 39.8973271404 75.0687887408 +-52.6540784518 -36.8687826495 76.6044443119 +-52.6297749849 66.5214203672 52.9623207325 +-52.4650713086 74.0990774446 41.9135182781 +-52.4443062044 82.7027996167 20.2445469766 +-52.4392026552 74.1173866946 41.9135182781 +-52.4114186698 19.1591131601 82.9817544761 +-52.4082767762 19.2098275184 82.9720136676 +-52.3857015867 64.0028205057 56.2083377852 +-52.3803100401 18.2100072412 83.2147748683 +-52.3694145567 63.9146140857 56.3237651908 +-52.3234858644 63.9268077467 56.3526048938 +-52.3023612449 82.0350561787 23.1238527491 +-52.2812816691 81.5930001385 24.6829883811 +-52.2626181459 80.4159068046 -28.31785086 +-52.254041864 74.2122331865 41.9768931003 +-52.2498231493 74.2062416836 41.9927336103 +-52.2319091148 39.2168266667 75.7223096347 +-52.2009408299 20.3313078113 82.8353770991 +-52.1472914255 84.9967170085 -7.49787268263 +-52.1092047272 82.5242460887 21.7802568899 +-51.9757439772 85.3172693599 -4.41424817878 +-51.9579910938 59.9819455217 60.8484459368 +-51.9566633538 83.374531536 18.6866964522 +-51.9500683941 85.375702897 -3.48994967025 +-51.8569352108 83.538975353 -18.2235525492 +-51.7817743758 84.1700729563 -15.2985836284 +-51.7768285944 83.0213743948 20.6545736898 +-51.753160337 71.2321142151 47.4088209047 +-51.7402497602 74.7224101184 41.7074091841 +-51.7289816801 81.7323773662 25.3757944585 +-51.6465716301 40.3071931128 75.5510544084 +-51.587588607 63.4106476169 57.6004381105 +-51.5680171041 62.8917492558 58.1839108989 +-51.5672077929 40.1728929408 75.6766922719 +-51.5543771205 62.9423012822 58.141318432 +-51.5481198058 67.1060361555 -53.2876276071 +-51.5367279809 46.8948142824 71.7275544155 +-51.5211145003 63.5552071972 57.5005252043 +-51.483707319 62.2994991258 58.8914279787 +-51.475195489 63.5665725414 57.5290805133 +-51.4604874909 46.5307577248 72.0187948577 +-51.4365963536 23.3002086264 82.5310658693 +-51.4285996372 82.2390712438 24.3276447751 +-51.4178673983 37.6735495976 77.0513242776 +-51.3965314807 62.5044075273 58.7502816283 +-51.3907722361 45.7392619112 72.5734693176 +-51.3856216209 62.5133769623 58.7502816283 +-51.3765876882 48.5844238158 70.7106781187 +-51.365929851 63.5903355867 57.6004381105 +-51.3596119517 63.5825141118 57.6147043678 +-51.3106630432 82.6589577245 23.1238527491 +-51.3094186332 62.5095829841 58.8208772008 +-51.2910314377 49.7913343316 69.9289147602 +-51.2644476431 80.6864305374 29.3539832896 +-51.2512500381 62.7954747523 58.5665238866 +-51.2169466521 85.2393134617 10.5396307434 +-51.1961727686 85.8823788038 1.78014180529 +-51.1900354716 75.3804365227 41.1991511814 +-51.1768783239 75.3893697212 41.1991511814 +-51.1585600676 15.3288405522 84.5448305879 +-51.1536155263 75.3268059412 41.3422293217 +-51.1464683971 44.4923008193 73.5151272753 +-51.1445920181 51.5568643012 68.7467850211 +-51.1353789405 63.827386394 57.5433555394 +-51.1228169386 63.8117064525 57.5719003324 +-51.1191512473 82.4467507295 -24.2768546132 +-51.0844855703 85.9335517802 -2.40832150206 +-51.0464356065 50.2508323653 69.7790459842 +-51.0375013008 81.2976942119 28.0331656578 +-51.0206082743 64.3027932222 57.1143442153 +-50.974362824 83.2478133138 21.712114433 +-50.9591000671 63.9039588833 57.6147043678 +-50.933431692 43.45515861 74.2794367659 +-50.9056449972 83.2987270154 21.6780392341 +-50.900299755 51.5619814946 68.9240273721 +-50.8767444265 80.4168885963 -30.73566178 +-50.8575776743 82.6678126586 24.0736275485 +-50.8112048146 83.1441911679 22.4780991261 +-50.8066371492 82.6496401585 24.2429908069 +-50.8057205345 38.8720151572 76.8618578918 +-50.794658531 52.7834600075 68.0720868959 +-50.7924517601 75.8728585899 40.7852445573 +-50.7839998084 -19.8815851875 83.8194961444 +-50.7812097812 62.7543484684 59.0183063249 +-50.7437027518 82.3216563897 25.4601948206 +-50.7360391868 80.4739866657 -30.8186923436 +-50.7267081683 61.7117732501 60.153621011 +-50.7167303176 39.3824787872 76.6605089369 +-50.6660393932 16.3646848297 84.6472063486 +-50.6430123383 50.5194190513 69.8789925516 +-50.6271641575 84.1579057905 18.8238450464 +-50.6048518125 63.2782680925 58.6089563144 +-50.6028816404 75.7325642705 41.2786516097 +-50.5971763891 51.1655324828 69.4407231184 +-50.5920712127 63.2622867352 58.6372356736 +-50.5717124535 63.3047560556 58.6089563144 +-50.5593808006 63.3800049712 58.5382266806 +-50.5354031668 82.85530265 24.1075060833 +-50.5244744053 47.7285333465 71.8975979477 +-50.5118183423 37.3086079274 77.8243148526 +-50.5081444202 86.1924165706 -4.44912046883 +-50.5075495567 41.9321755345 75.436596508 +-50.4763148421 51.9603398783 68.936671806 +-50.4742129477 81.9484877779 27.1440449865 +-50.4726719119 64.4164798149 57.4719628891 +-50.4494899366 38.3626835878 77.3508466216 +-50.4432150021 64.2863897649 57.643231617 +-50.4242037854 44.7687030371 73.8455340626 +-50.3834053911 81.99322155 27.1776393577 +-50.3821879225 82.6365388921 25.1562632376 +-50.36491696 38.3400090334 77.4171741084 +-50.3591785902 83.2184311135 23.2087452208 +-50.3558089421 83.7068300285 21.3882938162 +-50.3497377076 42.2035410844 75.3907489863 +-50.3408465545 81.3499015356 29.1203140148 +-50.3148233518 64.9824948208 56.9709918989 +-50.2835735936 46.972296461 72.561460789 +-50.2369611055 62.6611398194 59.5804439009 +-50.2126959621 -18.2759267125 84.5261833222 +-50.1961972012 49.3276656084 71.043107985 +-50.1243696667 81.0633020135 30.2702598633 +-50.1064808407 65.0176303983 57.1143442153 +-50.1048396664 85.2311322829 -15.0053034553 +-50.0853242677 62.0714227983 60.3207987745 +-50.0682016126 68.1595970596 -53.3614515916 +-50.067105864 61.5416942886 60.8761429009 +-50.0290139384 83.09791492 24.3276447751 +-49.9972584683 50.5235892058 70.3394702811 +-49.9258245843 21.4704743643 83.9430209734 +-49.9183734119 53.7750047563 67.9441304262 +-49.9165181867 69.594264242 -51.6234403806 +-49.9004557125 38.0552674415 77.8571842519 +-49.8915818225 80.5296364044 -32.0282332298 +-49.887747349 82.9615442826 25.0717936073 +-49.862849981 82.9201408478 25.2576015004 +-49.8587852683 82.9789533369 25.0717936073 +-49.8452854893 43.360402114 75.0687887408 +-49.8407068238 82.9488657527 25.2069358243 +-49.8284618226 52.7474168489 68.810133034 +-49.8263003936 67.164612213 54.829322952 +-49.8230530169 82.985086029 25.1224776808 +-49.8162752622 82.9737970268 25.1731548668 +-49.8129187295 38.6806523786 77.6046407067 +-49.7925288518 62.9352822399 59.6645147464 +-49.7804652123 85.086750898 -16.7973243363 +-49.7771451175 82.5490878449 26.6060880235 +-49.7748852252 53.3396882451 68.3910700219 +-49.7707358639 80.8063425154 31.5152163383 +-49.7566317386 80.8150279167 31.5152163383 +-49.755906943 21.5313036143 84.028285053 +-49.7510217179 50.6800603346 70.4014724456 +-49.7473701821 83.0559913291 25.0380004054 +-49.7293777237 63.2628985335 59.3699811383 +-49.725802295 51.7269350198 69.6539214946 +-49.7200904472 63.2965469528 59.3418886604 +-49.7100359865 81.9196039656 28.6022867677 +-49.706064633 61.4915210331 61.2217280034 +-49.6994620173 19.4269913046 84.5727821704 +-49.6787379848 19.3989024438 84.591403678 +-49.6687421103 63.5730908456 59.088731392 +-49.6645745763 41.4965823597 76.232956683 +-49.652384238 61.5348743377 61.2217280034 +-49.6250490499 66.9910180943 55.2228032744 +-49.6237668038 40.6455171773 76.7165151815 +-49.6228388991 45.502830398 73.9396124237 +-49.6106278218 79.486180893 34.9389847328 +-49.5985045196 76.3166649242 41.4216731225 +-49.5970407509 -24.0509452151 83.4367160369 +-49.5921789483 82.6332201244 26.690198932 +-49.5893297382 79.5138370183 34.906275922 +-49.5878489337 86.8310817237 -1.18679602985 +-49.578027079 67.0497939848 55.1936985312 +-49.5759518687 47.425496463 72.7533317557 +-49.5656330193 62.3795549049 60.4321036641 +-49.5597651255 -20.4473026013 84.4140835231 +-49.5594386004 61.7056437586 61.125081382 +-49.5573173271 82.9684680166 25.6964124795 +-49.5551377439 83.7931617946 22.8690699339 +-49.5508414233 37.0687654009 78.5532987588 +-49.5455440031 78.5857057696 -37.0071063192 +-49.545213354 76.3512726118 41.4216731225 +-49.5318274555 78.5943519014 -37.0071063192 +-49.5022332861 67.4631311345 54.7563223493 +-49.4997058469 -16.0165960382 85.4005138885 +-49.4792115889 61.4957580115 61.4009720373 +-49.4779659547 -2.59303031913 86.8631514438 +-49.4333386929 82.5970901756 27.0936472296 +-49.4139372133 86.4914950093 8.80250533245 +-49.4049680289 61.7336954534 61.2217280034 +-49.4003616079 86.5027809876 8.76773371009 +-49.3769819455 61.9199440311 61.0559922132 +-49.3453306441 62.5942535182 60.3903781253 +-49.3408255253 37.0057568681 78.7150360167 +-49.3392424466 67.4876410299 54.8731032748 +-49.330495366 79.4071324217 35.5106962408 +-49.3216537977 83.3651511047 24.8520833726 +-49.310857568 66.1555906656 56.4967003425 +-49.3053196813 43.2396048609 75.4938542041 +-49.2803500416 80.5128185112 33.0020174407 +-49.2027753918 84.5388323906 20.7911690818 +-49.2004065255 49.2519560667 71.7883334625 +-49.1479255735 52.5757700546 69.4281629815 +-49.1461517389 51.8254565875 69.9912695896 +-49.1368935082 61.5086756204 61.6623752364 +-49.1253310121 86.6522037108 -8.83727588225 +-49.105627899 -23.7597384728 83.8099763533 +-49.0868131296 83.100543586 26.1683861269 +-49.0811475105 65.3699509602 57.6004381105 +-49.0751074309 61.4753252803 61.7447828754 +-49.069063293 -6.28589198008 86.9063552887 +-49.0616579675 61.4584774284 61.772237046 +-49.0199318562 65.4786314465 57.5290805133 +-49.0176418631 63.0112978444 60.2233105213 +-49.0109889267 86.6972274682 -9.02849454487 +-48.999966224 83.2518744705 25.8481857621 +-48.9957712193 50.2604536388 71.2271100259 +-48.9953325489 75.5327497832 -43.5231099372 +-48.9918146167 62.9780973832 60.2790291109 +-48.968116693 64.6301488921 58.5240754026 +-48.962178881 61.3997708343 61.909394931 +-48.9614807504 82.7893426394 27.3623490961 +-48.9512645841 14.9192049816 85.9138581274 +-48.9421237 14.8977500993 85.9227884191 +-48.9180927258 48.374701604 72.5734693176 +-48.9050138637 73.3854559682 -47.147369718 +-48.9043597598 -16.0600213674 85.734703068 +-48.9040868522 63.7330468214 59.5524057617 +-48.8999972899 62.7018511181 60.640482612 +-48.8972574638 64.6068761996 58.6089563144 +-48.8941326006 61.8662982258 61.4973571877 +-48.8914291163 63.7165509388 59.5804439009 +-48.8802942115 38.3270464196 78.3693457326 +-48.8766786438 36.5910435748 79.1970063504 +-48.8726703412 63.9922132617 59.2997363872 +-48.8614368001 61.383251794 62.0052932662 +-48.8416896362 66.41698829 56.597464784 +-48.8348355121 62.6182976556 60.7791710969 +-48.8347857202 18.5798601976 85.2640164354 +-48.8280345035 82.5636973589 28.2676303383 +-48.8090086934 63.6091385525 59.7625146976 +-48.8073201598 82.627381524 28.11692233 +-48.8014722842 53.8771890273 68.6706983029 +-48.7985475357 45.7448142788 74.3378350842 +-48.7978416229 63.7096251207 59.6645147464 +-48.7927276806 40.3218412098 77.4171741084 +-48.7761575934 83.2034773736 26.4209727938 +-48.7751225787 54.3035344594 68.3528606764 +-48.768726007 54.0681961925 68.5437198009 +-48.7558063605 53.9023563358 68.6833846544 +-48.7452703883 83.4844178312 25.5783227395 +-48.7351965449 83.5006303285 25.5445757936 +-48.73499307 66.1508681482 56.9996762596 +-48.7261861516 64.427566904 58.9478363128 +-48.7234468233 66.1593730015 56.9996762596 +-48.7231886498 66.1348453154 57.0283536751 +-48.7066981188 61.298564438 62.2104778651 +-48.7055321923 83.9876639187 23.9550296042 +-48.698798364 61.3325653718 62.1831445234 +-48.6936516291 66.0947529826 57.1000168056 +-48.6540211162 64.3788449957 59.060566762 +-48.6464153105 63.9038103873 59.5804439009 +-48.6422805721 61.9689499121 61.5936505456 +-48.632821748 51.1945898798 70.8093398915 +-48.5929485176 65.9580627353 57.3433458613 +-48.5870389342 46.6258628695 73.927860508 +-48.571756393 7.62350553013 87.07850851 +-48.5709935009 62.4596300145 61.1527040186 +-48.5487748596 8.84906980353 86.9753437661 +-48.5295921036 82.9487088336 27.6476109834 +-48.5219249298 83.5366113699 25.8313252067 +-48.5147863138 -12.09609478 86.6025403784 +-48.5039240238 78.9963870175 37.5092014374 +-48.4843491348 62.8900647936 60.7791710969 +-48.4788698612 61.6720732378 62.0189854765 +-48.4650193673 51.8270990816 70.4634209964 +-48.4551289172 63.721729297 59.9303069992 +-48.4490594857 -17.2519340613 85.7616429769 +-48.4485576606 62.0113259695 61.7035875141 +-48.4401602928 62.0452074371 61.6761145412 +-48.4348188913 87.3787262978 -4.36193873653 +-48.4271237733 64.7810038912 58.8067616682 +-48.4132736765 47.3601474673 73.5742574804 +-48.4125221894 65.9539028147 57.5005252043 +-48.4046280039 45.0591369201 75.011106963 +-48.4040941957 83.0331690991 27.6140633457 +-48.3962240018 52.2265871378 70.2153052995 +-48.3875506692 65.5593817094 57.9707892832 +-48.3838931077 53.9626128735 68.8987322062 +-48.3826680806 -23.1291980271 84.4047251522 +-48.3818344679 85.4797893836 18.7724186097 +-48.3611488904 64.8814587274 58.7502816283 +-48.3500211343 82.7411446839 28.5688367405 +-48.3445914413 41.9956936354 76.8060036355 +-48.3369192959 -20.150418529 85.1909787835 +-48.3161047893 82.7494000561 28.6022867677 +-48.3071825701 64.9982637951 58.665507888 +-48.2958374973 65.0066939989 58.665507888 +-48.2895318977 62.4342994032 61.4009720373 +-48.2873093348 62.4089151211 61.4285200099 +-48.2826019127 9.28028599791 87.07850851 +-48.2631126122 81.8364917964 31.2003296688 +-48.2627770012 80.8011588597 -33.7916718003 +-48.2488529377 39.3788570866 78.2390810577 +-48.2483217568 17.6754781614 85.7885593737 +-48.2208173549 61.321762004 62.5651203016 +-48.2139652943 82.2444769819 30.1870759858 +-48.2095182285 78.6707836568 38.5583992277 +-48.1772179541 83.5463829936 26.4378054854 +-48.1719799908 -13.7858003994 86.5413892373 +-48.1409429091 -18.4313914537 85.689750991 +-48.1317134077 50.3141914207 71.7761820252 +-48.1269751713 -18.426043722 85.6987466281 +-48.1169485484 63.8069943572 60.1117853128 +-48.1106309574 63.7986167169 60.1257323772 +-48.1039167869 62.6449555443 61.3320693815 +-48.0909274832 83.3967426233 27.0600445976 +-48.0817124228 62.2553669828 61.7447828754 +-48.0739488193 10.0869625529 87.104240031 +-48.059485395 55.6774497146 67.7518077755 +-48.0449232686 46.999809727 74.0452782677 +-48.0444917499 62.2296224344 61.7996836899 +-48.0337964214 64.8429167689 59.060566762 +-48.0331446124 63.6727434138 60.3207987745 +-48.0314244921 38.0283070315 79.0368909154 +-48.0269658644 -11.7343569053 86.9236182972 +-48.0263415427 63.8489600149 60.13967761 +-48.0005738124 11.967887204 86.9063552887 +-47.9801408931 77.2334713698 41.628079226 +-47.9761786931 53.8094540545 69.3024453563 +-47.9378848915 58.7776540426 65.170135625 +-47.9226400725 63.3191355694 60.7791710969 +-47.9217342887 56.3078473051 67.3270652459 +-47.9045963584 63.5715465293 60.5293988043 +-47.8943256456 62.3044471645 61.8408395358 +-47.8882054402 77.7803184077 40.7055505812 +-47.8844799625 77.774267464 40.7214918582 +-47.8824709081 78.5365192066 39.2337116604 +-47.881166744 62.2873291013 61.8682673481 +-47.8796470252 77.8272554738 40.625825606 +-47.8790428654 -15.6677839459 86.3835505204 +-47.8759309507 77.821215081 40.641773078 +-47.8737591123 63.3693949745 60.7653105729 +-47.8712259548 76.4021103193 43.2557887958 +-47.8696901617 63.5713820365 60.5571808277 +-47.8673654622 63.3609318467 60.7791710969 +-47.8581946295 62.100278402 62.0737354217 +-47.8570085661 -18.8320823332 85.7616429769 +-47.8478337081 53.0100180436 70.0037341608 +-47.8290692486 -20.2825346269 85.4458830133 +-47.8281861951 77.1991246514 41.8659737537 +-47.8161644365 62.4731263663 61.7310529686 +-47.8147116777 77.2074710688 41.8659737537 +-47.8095126083 62.6001506651 61.6073992379 +-47.788547948 42.3243641388 76.9733907611 +-47.7841572519 49.0175654034 72.8968627421 +-47.7834041864 62.4303242037 61.7996836899 +-47.7800652817 77.2117251113 41.8976713794 +-47.7654669226 63.9657176894 60.2233105213 +-47.7615530223 62.5826296436 61.6623752364 +-47.7535275563 57.274898824 66.6272209433 +-47.7522541537 63.5538155665 60.6682351002 +-47.7316633966 -20.5861362641 85.4277431699 +-47.7274733907 78.8695440985 38.7515586452 +-47.7244745716 -20.6027965032 85.4277431699 +-47.7172799316 -20.619454232 85.4277431699 +-47.7143563392 63.0896880737 61.1803192039 +-47.7137073316 78.8778729128 38.7515586452 +-47.7102907388 63.3596981594 60.9038324474 +-47.7100816977 11.8777716793 87.07850851 +-47.7073639971 64.8270597102 59.3418886604 +-47.7054419969 62.8951752029 61.3871952452 +-47.7044611792 6.38208334564 87.6558805544 +-47.703645623 78.9234345158 38.6710961637 +-47.6999474667 76.9321395728 42.4989518979 +-47.6952425569 66.9898433695 56.8992506345 +-47.6863446113 -56.2298074987 67.5590207616 +-47.6785017241 39.5553486919 78.4992666412 +-47.6677647447 62.572885437 61.7447828754 +-47.6677514107 63.4182994171 60.8761429009 +-47.6672500914 63.3255369703 60.9730238396 +-47.6547009758 62.5557367892 61.772237046 +-47.64797652 64.3925445919 59.8604254456 +-47.6439144701 63.409625509 60.9038324474 +-47.621777433 63.4262525091 60.9038324474 +-47.609813463 52.7463183835 70.3642775775 +-47.6002154558 78.9700908096 38.7032846937 +-47.5996960529 64.7517487793 59.5103349486 +-47.588820011 63.54389627 60.8068865901 +-47.5855574152 64.4256959829 59.874405405 +-47.5757578719 47.8756282318 73.7866619677 +-47.5652225207 62.9609921773 61.4285200099 +-47.5454217321 51.0397756717 71.65454746 +-47.5410298177 -13.0057540344 87.0097744272 +-47.540901022 79.6557458018 37.3473545352 +-47.5381703829 -12.6666995475 87.0613408995 +-47.53749183 63.3830865467 61.0145163901 +-47.5303197776 62.9604743467 61.4560604976 +-47.5233992813 48.6480512109 73.3136660803 +-47.5128382022 62.59585267 61.8408395358 +-47.5113742972 63.0955353236 61.3320693815 +-47.4963123294 79.3605549658 38.0263412733 +-47.4922654808 64.2993887978 60.083885691 +-47.4886533001 86.7397998714 -14.8672433897 +-47.4825366314 47.366656424 74.1741772739 +-47.4713861496 53.9975192735 69.5034920658 +-47.4711992462 62.3148563375 62.1558036049 +-47.4569929526 63.4832590826 60.9730238396 +-47.4560145349 62.3400539427 62.1421303053 +-47.4230407666 62.7044998407 61.7996836899 +-47.4215040256 38.1278681396 79.3565789779 +-47.4062694362 79.6827749255 37.4606593416 +-47.4009420507 35.8880814795 80.4064443961 +-47.4001733807 63.2459776512 61.2631200187 +-47.3990620521 47.2668833713 74.2911209563 +-47.3948175649 77.1900300097 42.3725209904 +-47.3824929969 35.7961135149 80.4582973635 +-47.373975166 86.4228785244 16.9349503849 +-47.3698480705 77.2400335407 42.3092745435 +-47.3678702746 77.206569219 42.3725209904 +-47.3478233422 79.679452267 37.5415571225 +-47.3477177665 63.6840658986 60.8484459368 +-47.3321856358 -24.6395762726 84.5727821704 +-47.331004206 60.1901986433 64.3188621489 +-47.3093208918 63.193673866 61.3871952452 +-47.2840851344 61.3553200985 63.2434975995 +-47.2698025516 35.9447931153 80.4582973635 +-47.2673610742 45.837264232 75.2644789048 +-47.2638275059 46.478475452 74.8724377134 +-47.2477417834 63.2263515415 61.4009720373 +-47.2302155498 53.6098763152 69.9663340513 +-47.2120514641 44.6930673041 75.9838925793 +-47.2076873943 40.8925815903 78.0975737252 +-47.2067802875 -29.1555017379 83.195412213 +-47.1944116008 77.2259031156 42.5305466885 +-47.1706251743 78.6605110319 39.8428930284 +-47.1537239322 63.8410401712 60.8345946742 +-47.1314363329 63.8574960362 60.8345946742 +-47.114380143 52.3625659952 70.9816657042 +-47.1138898911 61.5555854691 63.1758757508 +-47.1125143276 36.1507037152 80.4582973635 +-47.111210617 77.4843292372 42.1510682766 +-47.0971424836 36.9023365976 80.1253812691 +-47.0884515142 -19.5335671801 86.0297476877 +-47.0813015316 38.8522511275 79.207661425 +-47.0615927669 74.100018535 -47.8998302645 +-47.0393704653 77.5795302977 42.0560828539 +-47.0306999242 53.8174249774 69.9413899879 +-47.0291991051 70.0660513035 -53.6563405971 +-47.0141733041 46.6382264572 74.9302565154 +-46.9869939376 79.6091425755 38.1393080575 +-46.9866178277 64.5529918153 60.2093762865 +-46.9850699144 42.0095009473 77.6376521753 +-46.9827315663 46.6884538901 74.9186973186 +-46.9692303896 63.3133529911 61.5248789485 +-46.9629701635 77.453527346 42.3725209904 +-46.9606734637 44.145302144 76.4584033736 +-46.9582791099 46.7130475898 74.9186973186 +-46.9571148468 77.4743668778 42.3409003465 +-46.9502768056 78.7598220629 39.906915898 +-46.9456173177 77.4553971478 42.3883293765 +-46.9400059993 88.2813115664 1.74524064373 +-46.9019602743 -19.590666302 86.1185921638 +-46.8894837255 78.5020021385 40.4822427269 +-46.8686679615 63.6408523599 61.2631200187 +-46.8604086398 72.3797516702 50.6485305836 +-46.8593795687 64.5674703239 60.2929541689 +-46.8156541865 60.9452487174 63.9841478951 +-46.8057347061 87.7699273238 10.2792536787 +-46.8032829197 79.6786488155 38.2199637738 +-46.7945975712 79.5049111887 38.5906042324 +-46.7875485832 79.5246826248 38.5583992277 +-46.7644127031 55.1036979256 69.1134732122 +-46.7471857388 59.5118675452 65.3684805299 +-46.735276175 63.7388742168 61.2631200187 +-46.734675222 60.7958889465 64.1851230356 +-46.7195376433 87.5714761425 12.1869343405 +-46.7132479722 77.8361867592 41.9452082446 +-46.7059055081 13.7197261192 87.3517458663 +-46.6850669231 43.6565563707 76.9064991547 +-46.6666658803 4.01715450435 88.3520501477 +-46.6592345508 74.294749566 47.9917286421 +-46.6548228971 79.6804528138 38.3973038094 +-46.6513681777 77.8562155052 41.9768931003 +-46.6476017932 77.8499298065 41.9927336103 +-46.6323296172 88.1475353828 7.44565916573 +-46.6041024414 -20.8470224715 85.9852271597 +-46.5944678516 72.2450658078 51.0843031866 +-46.5842499541 62.8861107712 62.2514636638 +-46.5809574488 56.5675400166 68.0465121782 +-46.565093336 43.5291340332 77.0513242776 +-46.5585018399 78.4758413762 40.9126902895 +-46.5405267429 79.7084260634 38.4778661699 +-46.5351123369 -15.147117237 87.2069272432 +-46.5299987775 79.722346529 38.46175604 +-46.5213178486 55.9358048765 68.6072351756 +-46.5122862635 72.8132030701 50.3472410885 +-46.5064785415 78.4817686823 40.960461889 +-46.4991867489 78.4694634552 40.9923033842 +-46.4926914745 -19.4769236074 86.3659602288 +-46.4756769513 79.6292740259 38.7193771905 +-46.4753442093 79.0571576831 39.8749068925 +-46.4741032786 43.2317703588 77.2733573497 +-46.4513584586 44.6231307902 76.4921400918 +-46.4359929741 74.6606212242 47.6391666061 +-46.4325505689 78.4506426546 41.1037092578 +-46.408910681 37.9852532543 80.0208319415 +-46.3963035395 79.1438682797 39.7948631308 +-46.3922739917 59.017624121 66.0657018202 +-46.3892755666 79.131879804 39.8268842755 +-46.3810136841 -15.1775736963 87.2836916401 +-46.3742476414 -15.2470768323 87.2751728945 +-46.3731776546 51.178378677 72.3208265315 +-46.3624683155 38.0419240719 80.0208319415 +-46.3572914101 81.669955775 -34.3659694586 +-46.3566268355 58.9722758274 66.1311865324 +-46.3370251082 40.1808765302 78.9833986695 +-46.3309980063 79.5407472685 39.0731128489 +-46.3203644275 79.5863544979 38.9927687788 +-46.3028413207 78.5439184578 41.0718852613 +-46.2960629468 35.2426168597 81.3303910756 +-46.2933290277 0.702988810539 88.6365246062 +-46.2925807276 79.6025185063 38.9927687788 +-46.2838894782 -11.4112499243 87.9066831927 +-46.2737210618 45.983884293 75.790666473 +-46.2697066546 80.955196304 -36.1299105657 +-46.2452201827 62.1558493513 63.2299770811 +-46.2403974561 38.8003004509 79.7267980545 +-46.2090011172 42.4615953082 77.8571842519 +-46.2080819894 16.6632688114 87.104240031 +-46.205048296 88.4949309688 5.80867495977 +-46.1932032778 74.0683299446 48.7859659139 +-46.1886165067 58.484932472 66.679264985 +-46.1881775662 -78.6943709956 40.9126902895 +-46.1711538881 64.2539597212 61.1527040186 +-46.1592216016 83.4450916781 -30.1038691196 +-46.1221766303 72.5369264096 51.0993065504 +-46.1167595504 53.1448590889 71.0553899503 +-46.1159905432 60.6456061789 64.7721071713 +-46.0658856858 88.6806049674 3.69925378826 +-46.0650061256 72.8676341922 50.6786256511 +-46.0505467982 -47.9707619531 74.6870345992 +-46.0434649025 -48.0136812513 74.6638182285 +-46.0360902039 -8.96518737463 88.3193286551 +-46.0321465881 73.3246589636 50.0453381281 +-46.0225966604 79.2974222083 39.9229185776 +-45.9648576588 63.9668681393 61.6073992379 +-45.9125009301 41.0793609882 78.7688286008 +-45.8872288664 -11.4154543672 88.1138447042 +-45.8750862374 46.7154342181 75.5853469168 +-45.8546904083 88.7278153533 4.97213738687 +-45.8212789058 82.3245898684 -33.5122709234 +-45.7999571988 87.4956257297 15.7123963403 +-45.779099251 47.6879955893 75.0341865315 +-45.7632318736 76.0124745488 46.1284112175 +-45.7612014178 74.9100707878 47.8998302645 +-45.7333187278 63.4808424873 62.2787780488 +-45.7101005757 75.4169227298 47.147369718 +-45.6966126545 75.9018203949 46.37599867 +-45.6898124172 -11.7566536072 88.1715494774 +-45.6774520307 42.8939825633 77.9337964931 +-45.6592782715 46.0916475237 76.0972426325 +-45.6294874687 88.9762831865 -1.08208301821 +-45.6276563163 -21.3541372703 86.3835505204 +-45.6031227911 79.6275411332 -39.7468223232 +-45.5670246699 22.0770386173 86.2336977557 +-45.5596253954 -24.2755047437 85.6447336576 +-45.5534182121 87.8064210957 -14.6600990296 +-45.5381514055 48.4932058551 74.6638182285 +-45.5299857648 74.795420304 -48.2976759048 +-45.5230969163 -22.845978875 86.0564285593 +-45.5159375436 79.7332502421 -39.6346847517 +-45.4912530159 -52.3317002744 72.055111168 +-45.4897070737 76.6133983831 45.399049974 +-45.4736892625 79.8209470664 39.5064550964 +-45.4347770492 39.6771949523 79.7583928825 +-45.4344832963 43.7990110134 77.5716079622 +-45.4321912545 77.220985067 44.4166124676 +-45.4201663488 50.4796295895 73.4085518544 +-45.4184726427 63.0206209027 62.9727217439 +-45.4096767501 54.8908698901 70.1780140797 +-45.3983234423 87.957640316 14.2283427941 +-45.3881405488 76.4423408595 -45.7873915117 +-45.3778864755 78.5968049157 41.9927336103 +-45.3567026824 23.7623331436 85.8959896931 +-45.3529290157 49.2863991965 74.2560615973 +-45.349006096 0.5540701958 89.124411091 +-45.3172874601 63.2285467448 62.8370458711 +-45.2977057975 79.6736138448 40.0029137237 +-45.2928143951 73.9980974604 49.727683803 +-45.2904882679 -43.8895364893 77.6046407067 +-45.2816911777 74.9755306152 48.2518212408 +-45.2567795022 38.4484888449 80.4582973635 +-45.2488080322 79.7495042942 39.906915898 +-45.2474359191 73.9239594113 49.8790313429 +-45.2453701744 79.7434451854 39.9229185776 +-45.2323569332 89.1578460737 -2.21638664806 +-45.2232018754 45.8110838138 76.5258558393 +-45.2167952646 89.1657392513 -2.21638664806 +-45.1992344126 62.9477466971 63.2029302665 +-45.1839738709 61.6231648314 64.5057676599 +-45.1740161302 63.6130302374 62.5515039842 +-45.1737913608 58.2377009026 67.5847524792 +-45.1581986657 79.816845926 39.8749068925 +-45.1187311571 58.7998752343 67.1332612883 +-45.1035590345 76.1142790833 46.6077834922 +-45.0931238558 76.9208747789 45.2745977805 +-45.0818347716 72.7662589556 51.6981598438 +-45.0371196298 76.1536103766 46.6077834922 +-45.034191619 64.9649276756 61.2493245459 +-45.0301440477 75.9299418953 46.977974103 +-45.0195637804 75.1626565444 48.2059533482 +-45.0181373635 60.6169733829 65.5663774065 +-45.0068491215 74.844784638 48.7097705254 +-45.0047145422 77.2637926946 -44.7759087839 +-44.9708210897 64.5121382442 61.772237046 +-44.9592280893 64.9778211811 61.2907053653 +-44.9571019899 81.1047589283 -37.4282922379 +-44.9542292259 57.1266353752 68.6706983029 +-44.9463423739 -13.1262012186 88.3602237931 +-44.9430571271 48.2799296723 75.1609606571 +-44.9428785005 11.1222379864 88.6365246062 +-44.9305485801 21.2385730144 86.7765453369 +-44.918746339 82.2842678275 -34.8081239861 +-44.9130341917 64.8143072062 61.4973571877 +-44.9075641011 -13.1489085953 88.3765630089 +-44.8950305976 62.5932403953 63.7692910769 +-44.8881718085 -16.0457808083 87.9066831927 +-44.8686644799 64.8711276425 61.4698279336 +-44.8636862092 -13.4597509046 88.3520501477 +-44.8552100199 77.6915027386 44.1819028143 +-44.8513537383 77.684823463 44.1975595633 +-44.8474355374 -14.5458584156 88.1880123865 +-44.8365541624 59.6732896567 66.5490940013 +-44.8335663322 77.4353791803 44.6510176944 +-44.8259246453 73.2927520157 -51.1743000114 +-44.8213291544 78.3258379485 43.0826132274 +-44.8133467193 25.3851559357 85.7167300702 +-44.8094879366 -15.1497434441 88.1055904267 +-44.8056944642 88.5849158777 12.0483369194 +-44.8041620543 75.9108133135 47.2243103147 +-44.7989670785 64.8671089156 61.5248789485 +-44.7811816477 -21.5517273003 86.7765453369 +-44.7794786283 77.779630101 44.1035988909 +-44.7788954521 58.823286897 67.3399691173 +-44.7727276214 74.4554489347 -49.5155428655 +-44.7537907005 -24.0974335078 86.1185921638 +-44.7530350118 59.6487995403 66.6272209433 +-44.749345131 74.0940942931 50.0755559253 +-44.6995813881 40.9165838786 79.5473480855 +-44.687133227 76.7801823334 45.9114770487 +-44.6599610549 60.3104336104 66.0919017453 +-44.6592419765 73.1635832913 51.503807491 +-44.6559025124 64.2035898596 62.3197353969 +-44.6358731932 72.8391249768 51.9817342621 +-44.6176612809 73.0094744366 51.7579070704 +-44.6148397272 72.9476170366 51.8474806022 +-44.5878761681 -16.6441192849 87.948249511 +-44.5791379277 37.698973983 81.1879783112 +-44.5733938076 47.4160667185 75.9271307335 +-44.5731347565 76.8926924122 -45.8339340618 +-44.5655326969 71.9328995624 -53.2876276071 +-44.5597945005 72.8005106395 52.1009631841 +-44.5479351331 74.6705818896 49.3941866584 +-44.5180718511 71.9404024667 -53.3171620737 +-44.5108545581 43.08884964 78.4992666412 +-44.5093366375 15.7353601295 88.1550758248 +-44.4921674377 75.8350634059 47.6391666061 +-44.4527977355 60.8483905757 65.7375245794 +-44.425289091 73.7027990349 50.9341840379 +-44.4187811591 -24.147552954 86.2778509623 +-44.412963382 24.3153872064 86.2336977557 +-44.4025680243 72.175344223 53.0954954695 +-44.3965303089 -24.1254189142 86.2954938496 +-44.3860128558 73.4345673856 51.3541252058 +-44.3839953966 5.66997446235 89.4310479768 +-44.359509603 19.8243877094 87.4026747859 +-44.3446232164 -38.7524796777 80.8195502996 +-44.3057285481 89.567104335 -3.83878090875 +-44.2932021278 46.5449668734 76.6268771648 +-44.2895295663 -7.57054793036 89.3371388328 +-44.2795826462 48.3735107066 75.4938542041 +-44.2699587245 59.1338298873 67.4044576967 +-44.2383027083 41.9805817618 79.2502575922 +-44.2298581575 24.7394976757 86.2071743077 +-44.2248335832 62.576692135 64.2520170576 +-44.2239996195 78.0702483483 44.1505852792 +-44.2000650999 25.0071936276 86.1451943641 +-44.1980977724 24.5801419732 86.2690255763 +-44.1816884137 15.6455564331 88.3356947831 +-44.1779579816 74.10921397 50.5582083675 +-44.1571827866 44.0340445235 78.1738199863 +-44.1449084959 9.39939684567 89.2349617181 +-44.1174509501 78.9388837666 42.6884428311 +-44.1041350627 89.5525142634 -5.9306373576 +-44.1017746932 77.8544802036 44.6510176944 +-44.1015945257 50.7867630628 73.9983382104 +-44.0992234071 79.0682143154 -42.467351929 +-44.0922182336 -12.2278543182 88.9176915468 +-44.0712680721 -8.59053669769 89.3528175816 +-44.0118598124 77.3805180313 45.5544907234 +-44.0084441402 16.6996635272 88.2291226435 +-44.001277521 -19.9876510917 87.5464527 +-43.9920306197 53.271815262 72.296714591 +-43.9800521955 71.432671822 -54.4346250585 +-43.9773002872 45.6194299616 77.3619070953 +-43.9541115719 74.6192741584 50.0 +-43.9445504143 75.961030083 47.9457860256 +-43.938106873 16.8838586223 88.2291226435 +-43.9280621623 78.3429514201 43.96256723 +-43.9214469564 81.4687593071 -37.8648617352 +-43.9019823078 -17.399753853 88.1468349704 +-43.8875326808 70.7006593433 -55.4553986878 +-43.8723867528 70.5388092245 -55.6730641675 +-43.8608198167 42.6527835305 79.1010021561 +-43.8552992208 76.2051345732 47.6391666061 +-43.790592877 -16.1378386398 88.4418121677 +-43.789694084 25.1496905311 86.313126222 +-43.7882828335 60.4467068921 66.5490940013 +-43.7822055767 18.8555966466 87.9066831927 +-43.7729323288 58.6190654499 68.1743027916 +-43.743774845 24.5277874496 86.515142057 +-43.7379596672 -6.35729152244 89.7027074767 +-43.7309251859 51.7485617118 73.5506121195 +-43.7303350449 -7.31794836243 89.6331714747 +-43.7174309832 24.5130160531 86.532642813 +-43.680534335 89.3603628113 10.331334785 +-43.6686799647 48.9610139329 75.4709580223 +-43.6664902993 -18.3826120752 88.0642787868 +-43.6634442109 77.2377713181 46.1284112175 +-43.660070897 -18.3978534355 88.0642787868 +-43.6497613993 72.4161768704 53.3909698101 +-43.6084407525 75.4711829411 49.0143289315 +-43.577613667 24.2052030345 86.6896748936 +-43.5713958614 62.3884909175 64.8784221735 +-43.5576679125 77.6188513289 45.5855622364 +-43.5350124353 73.5550742244 51.9071647088 +-43.5328691931 59.3279023608 67.7132874795 +-43.5072447454 61.2885769256 65.9608216527 +-43.4884294455 -65.7786558337 61.4973571877 +-43.4849434248 54.2198773946 71.8975979477 +-43.4777613372 72.7901235477 53.0215256573 +-43.4695413955 2.71963827255 90.0166792241 +-43.4688032134 25.99493792 86.2248592329 +-43.4651396131 72.7113274207 53.1398579518 +-43.4636008698 -22.9836627869 87.07850851 +-43.460764563 88.8321577317 -14.832723834 +-43.4499712326 -62.6795804955 64.678977951 +-43.4267451247 79.7164808129 41.9452082446 +-43.4249308853 50.3082666379 74.7218420912 +-43.4223866073 74.6970659136 50.3472410885 +-43.4210344866 44.7601120737 78.1738199863 +-43.3932413245 -25.5911861162 86.3835505204 +-43.3642787374 46.0170547869 77.472382165 +-43.3459544809 80.0664354793 41.3581206025 +-43.3372929228 55.5291110678 70.9816657042 +-43.3343458667 -64.245809778 63.2029302665 +-43.3299581248 74.5979859164 -50.5732659231 +-43.2937708148 62.9928274208 64.4790904261 +-43.2626577117 41.7345082781 79.9160388565 +-43.262085354 80.1117833471 41.3581206025 +-43.2448529646 79.5808533803 42.3883293765 +-43.242656598 89.9319263193 6.5054806779 +-43.2330347564 62.2505408023 65.2363002904 +-43.2301317699 76.9407645664 47.0241901057 +-43.2209651463 -15.5775495476 88.8216647103 +-43.2185837662 50.1930553894 74.9186973186 +-43.1935013554 63.129778524 64.4123629761 +-43.1888619752 73.9681402948 51.6084917685 +-43.183836701 -64.6780415775 62.8641963719 +-43.1780432464 75.9145232269 48.7097705254 +-43.1738256735 76.0924175836 -48.4351604003 +-43.1700776895 63.2138425796 64.3455864734 +-43.1682225702 -64.7280191269 62.8234677493 +-43.1678020264 -22.6636027409 87.3092319232 +-43.1510712939 63.1860115595 64.3856582585 +-43.1453366034 -65.6824976298 61.8408395358 +-43.1340047046 -62.760366288 64.8119901063 +-43.1296579547 -21.2224227263 87.6894599045 +-43.1257110317 63.1488765875 64.4390598453 +-43.114777526 -62.7323905695 64.8518552727 +-43.110436727 49.4532581374 75.4709580223 +-43.1074060814 -23.8653278215 87.018375467 +-43.0931221477 -66.3575889766 61.1527040186 +-43.0788329619 -23.6338570688 87.0956655104 +-43.0722741503 74.2438295186 51.309189995 +-43.0563448934 47.6012729191 76.6829184428 +-43.0512527392 40.3289515479 80.7475405485 +-43.0401663788 26.0352596523 86.4274801954 +-43.0400551014 -64.2439442911 63.4055934345 +-43.0092418207 -64.1979507002 63.4730513202 +-42.9936701375 -23.4409099194 87.1898392604 +-42.9832093338 81.6284814286 -38.5906042324 +-42.9724626683 -67.7137660872 59.7345238075 +-42.9541821057 -5.0991669885 90.1606163225 +-42.9465714235 57.9331594653 69.2772764861 +-42.9412081411 -66.0731573438 61.5661475326 +-42.917480919 -66.8508468516 60.7375839723 +-42.9160309169 23.0403132569 87.3347482699 +-42.9144750541 72.8543215847 53.3909698101 +-42.9064096524 -23.4419303644 87.2325392932 +-42.9029999088 -25.3222548492 86.7070701164 +-42.901647025 -63.4369902503 64.3054970475 +-42.8952246801 -66.1286311186 61.5386370179 +-42.8941429571 66.8658238054 60.7375839723 +-42.8767061709 -25.3370160514 86.7157637662 +-42.8766720842 -62.385945002 65.342060399 +-42.8760343859 -5.08988993436 90.1983297839 +-42.8740426574 77.0927658326 47.1011881219 +-42.8508734151 79.5827082389 42.78311813 +-42.8464578223 77.7765665488 45.9889850721 +-42.8398926497 -62.8244850593 64.944804833 +-42.8390459089 80.2978513061 41.4375580993 +-42.8132834977 22.3537078346 87.5633171036 +-42.8102079249 24.0239682517 87.121381112 +-42.8058742576 81.3605845074 -39.3460597474 +-42.8009116002 79.2247165772 43.4916802325 +-42.787602941 -65.7614221375 62.0052932662 +-42.7581929969 79.013688258 43.915532554 +-42.7220671378 45.8940385617 77.9009769128 +-42.7162388718 -66.5373801477 61.2217280034 +-42.6990234918 78.5437176099 -44.8071179262 +-42.6930103426 -66.552286874 61.2217280034 +-42.691513059 -67.2710603415 60.4321036641 +-42.6907602463 -62.5823141569 65.2759752463 +-42.6873597113 -66.4923962322 61.2907053653 +-42.6826589962 81.4020168036 -39.3941909591 +-42.6690751084 -67.7573414001 59.9023598516 +-42.6665926892 83.1987174153 -35.4617440174 +-42.6654972503 -62.709718282 65.170135625 +-42.6637677546 83.1932088682 -35.4780625061 +-42.6549439765 1.69082988759 90.4306189775 +-42.6394379187 28.4047253232 85.8781107925 +-42.6268439019 -66.9107420709 60.8761429009 +-42.6191044089 -69.0062107648 58.4957674987 +-42.6014498077 -62.6155813953 65.3024152754 +-42.5907582171 81.1922895769 39.9229185776 +-42.5905206784 -62.6230157972 65.3024152754 +-42.587073643 45.1607106645 78.4018582101 +-42.5866871622 71.5817854542 -55.3391549243 +-42.5711951102 1.80659159981 90.4678372333 +-42.5644538988 -68.4358913552 59.2013178799 +-42.5488432727 71.6604192484 -55.2664477717 +-42.5462478853 64.9679745557 62.9998339126 +-42.5436371016 72.5719023724 54.0680860418 +-42.5203977436 -65.6762482217 62.2787780488 +-42.5166456538 -62.6318607832 65.342060399 +-42.5049299015 60.816218396 67.0426618959 +-42.4944464817 -13.7089532553 89.4778554664 +-42.4936422125 44.0342047028 79.0903229713 +-42.4896585655 -13.7237857799 89.4778554664 +-42.4878672625 38.8920506788 81.7446605564 +-42.4836995876 -67.9353515695 59.8324600571 +-42.4823111949 75.7955523274 -49.5003786139 +-42.4782573779 -66.6261741807 61.2907053653 +-42.4753597073 -64.9091532804 63.108205791 +-42.4745029793 90.0588326729 9.23705874466 +-42.4441568552 73.6638185322 52.651072051 +-42.4431174155 -68.1082040882 59.6645147464 +-42.4346657386 79.4730667973 43.3973593378 +-42.4318628506 46.7138379196 77.5716079622 +-42.4200989054 -66.6632180793 61.2907053653 +-42.4182402131 -66.8920512889 61.0421687982 +-42.4174865651 -65.7686255385 62.2514636638 +-42.4086105183 -66.6451640701 61.3182832438 +-42.4007953597 72.5021547758 54.2734751581 +-42.3955832368 -65.8860392126 62.1421303053 +-42.3907528549 -66.7198944474 61.2493245459 +-42.3890226775 75.1670340987 50.5280886365 +-42.3833188078 79.1108516685 44.1035988909 +-42.3754386252 -68.2116009858 59.5944602483 +-42.3699492974 -68.2027648333 59.6084747803 +-42.3644586789 -68.1939266032 59.6224874966 +-42.3518965315 80.8398050567 40.8808363244 +-42.3411687213 83.6398226677 -34.8081239861 +-42.3379266506 -67.754845907 60.13967761 +-42.3343274885 -62.4101549933 65.6717387452 +-42.333216884 -66.6550359078 61.3596360516 +-42.3312148291 -62.522943028 65.5663774065 +-42.3278565227 -66.5695515255 61.4560604976 +-42.3271793809 -28.1967109021 86.1008442465 +-42.3244989496 77.9520299314 46.1748613235 +-42.3231440916 -67.0781236129 60.9038324474 +-42.3109025912 -66.2870896348 61.772237046 +-42.3036850904 -66.7371535473 61.2907053653 +-42.299341147 -66.39666572 61.6623752364 +-42.297135059 -67.9531891868 59.9442778349 +-42.2851191971 4.2578876112 90.5198270413 +-42.2748976153 -28.1938519671 86.1274621876 +-42.2568657716 -66.7921209481 61.2631200187 +-42.2501399953 78.4014505865 45.4767876649 +-42.24648426 52.3566418823 73.9865975598 +-42.240982467 76.614193445 48.4351604003 +-42.2336069365 75.5062398101 50.1510737159 +-42.2253282098 -68.1821701259 59.7345238075 +-42.2025078018 77.6303902091 46.8238278148 +-42.1990826016 -67.2189669543 60.8345946742 +-42.1968981711 77.7170185325 46.6849741903 +-42.1956356048 -23.3413093009 87.6054314299 +-42.1950036557 -68.0535741215 59.9023598516 +-42.1935977162 78.7897585136 44.8539214018 +-42.1869936779 -70.853663314 56.5686835572 +-42.1864729051 7.1201615682 90.3858661687 +-42.1847281038 80.520719863 41.6756810089 +-42.1809258667 -69.4300199334 58.3115925445 +-42.1758633754 -71.0322495084 56.3526048938 +-42.1721269232 76.0179391709 49.4245347472 +-42.1701021186 62.755732428 65.44769312 +-42.1687156833 -66.9109752233 61.1941240013 +-42.1644123485 19.0113903772 88.66075438 +-42.1502810405 48.9178091599 76.3570674869 +-42.1450833644 -67.3154438386 60.7653105729 +-42.127786014 83.5074587449 -35.3801353804 +-42.126363284 83.5771732255 -35.2168373381 +-42.1181821214 -70.3743542051 57.2145873446 +-42.1169341666 -61.5102309981 66.6532470249 +-42.113988928 -67.6589526226 60.4042884784 +-42.1104101418 18.9428397008 88.7010833178 +-42.1047031243 67.3031687072 60.8068865901 +-42.0995569992 -67.9525862697 60.083885691 +-42.0977939695 90.6919336138 -1.65798681877 +-42.0972112952 -61.4814264709 66.6922709185 +-42.0859189798 -67.0387084916 61.1112672705 +-42.0823415557 90.6586442377 3.17596507649 +-42.0751789066 -70.8626775369 56.6406236925 +-42.06876231 83.5717365476 35.2984997999 +-42.0623883772 78.0204394903 46.2986663495 +-42.0548959769 83.5441903715 35.3801353804 +-42.0439571871 -66.5841263098 61.6348909921 +-42.0355553661 89.4516452549 -15.212338619 +-42.0320353567 -67.4485432889 60.6959801962 +-42.0283043204 -68.3160336531 59.7205256328 +-42.002739971 -70.825125544 56.7412674039 +-41.9951276774 90.3468584265 8.59385965819 +-41.9946574779 89.648994077 -14.1246806796 +-41.9914870381 74.2801886513 52.1456478554 +-41.9817600694 68.8311800907 59.1591114605 +-41.980089266 81.7897284968 39.3460597474 +-41.9780919963 90.3514605478 8.62863657979 +-41.9757415984 90.719049379 -2.84450295045 +-41.9729655549 -70.8312621574 56.7556381667 +-41.9692582894 -66.4401378998 61.8408395358 +-41.9628860193 -69.1799174717 58.7644043238 +-41.9610666394 53.6497905594 73.2186373775 +-41.9580634079 2.36051212748 90.7411091929 +-41.9510030963 -70.8787932729 56.7125206934 +-41.9482382235 -70.8459091707 56.7556381667 +-41.9473296782 -61.6541560824 66.6272209433 +-41.9460041641 40.9333909531 81.0246273656 +-41.9454929227 -69.1784691602 58.7785252292 +-41.9247975363 -67.5651035678 60.640482612 +-41.9167162203 -70.1210235288 57.6717518425 +-41.9131032972 -61.7195904137 66.5881666001 +-41.9118048937 74.5334781542 -51.8474806022 +-41.9117521807 78.8245415353 45.0565941999 +-41.8859095605 -70.8252051454 56.8274660389 +-41.8857852489 74.5481035928 -51.8474806022 +-41.8834593069 49.7734595337 75.9498424128 +-41.880473792 -71.2410263281 56.3093427655 +-41.8775030677 71.8085404716 55.5860436814 +-41.8546719694 11.8200120042 90.0470640862 +-41.8409908419 -70.8056491967 56.8848971802 +-41.8387286077 -70.830043113 56.8561850734 +-41.8279112722 -66.808846664 61.5386370179 +-41.8248952962 25.9325337825 87.052753116 +-41.823809774 -61.357408843 66.9778867692 +-41.8148559832 -70.2286526975 57.6147043678 +-41.8146697624 -70.0057888103 57.885429304 +-41.8090819475 48.0619533979 77.0846891561 +-41.8040515567 -61.3284226501 67.0167579691 +-41.8033691921 -70.7701820938 56.9566471151 +-41.7996781717 16.4821882624 89.3371388328 +-41.7992285811 80.8114125751 41.501085379 +-41.7909766537 90.6516360965 -5.98290425741 +-41.7881960527 -70.7444950294 56.9996762596 +-41.7788788962 -24.1404956707 87.5885937035 +-41.7778849121 -25.2517826797 87.2751728945 +-41.7760902433 -66.7778903764 61.6073992379 +-41.770033798 55.8961495541 71.6301943425 +-41.7692360559 -24.0960433118 87.6054314299 +-41.7685269691 21.836058205 88.1962398116 +-41.7646822163 -66.7596549703 61.6348909921 +-41.7614767952 76.9150721191 48.3740709141 +-41.7578879939 62.4243144227 66.02638684 +-41.7561866637 -72.2364621111 55.1209072583 +-41.7476783495 -70.67590139 57.1143442153 +-41.7475802132 -24.1029766741 87.6138462904 +-41.74721184 -61.268010024 67.1073859667 +-41.7471397926 79.247535567 44.4635179185 +-41.7436628257 -25.1019592569 87.3347482699 +-41.734954202 -24.124832351 87.6138462904 +-41.7236302528 -70.7479343974 57.0426897773 +-41.7205512028 61.6673535633 66.7572701047 +-41.7186647291 72.1134410668 -55.3100771174 +-41.7174531935 -67.2309518768 61.1527040186 +-41.7157896329 -25.383546501 87.2666514903 +-41.7049767274 -70.885847593 56.8848971802 +-41.6885982973 -70.1279318061 57.8284873795 +-41.676827133 -72.5368047684 54.7855275974 +-41.6752580548 -68.2750328697 60.0141046146 +-41.66662995 -10.830050478 90.258528435 +-41.664739115 -10.8373225119 90.258528435 +-41.656997011 43.1823082945 79.9998928149 +-41.6494388779 -24.2113664682 87.6306680044 +-41.6489357094 71.7615579982 -55.8179625922 +-41.6399095457 -10.8075896316 90.273550608 +-41.6367561275 -24.2331707436 87.6306680044 +-41.6364103205 -71.7688260158 55.8179625922 +-41.6308577326 -24.151983121 87.6558805544 +-41.6267120302 -10.9205634679 90.2660408963 +-41.6174981018 -70.2873258877 57.6860093202 +-41.6125707691 -60.3884784478 67.9825391166 +-41.6096278106 -18.5432062634 89.0212804611 +-41.6058594781 80.2658397022 42.7357863387 +-41.6045203794 79.5144928452 44.1192623644 +-41.599762589 -21.4252856055 88.3765630089 +-41.5960595922 29.3427922307 86.0742027004 +-41.5877679767 -67.3363347738 61.125081382 +-41.5809207378 78.1036540901 46.5923410914 +-41.5764165414 -14.478440082 89.7873953312 +-41.5706473 -24.1946944872 87.6726755708 +-41.5657406385 -73.1689358025 54.0240320478 +-41.5641698944 -70.7029757222 57.2145873446 +-41.5602441336 73.517348215 53.5532036295 +-41.5554449026 58.8649644898 69.3401828276 +-41.5458845623 -66.6166030334 61.9368038909 +-41.5327503288 -70.7908590657 57.1286698852 +-41.5289486958 77.2891320809 47.9764158979 +-41.524984738 77.2817547967 47.9917286421 +-41.5098430509 -21.9968857049 88.278366258 +-41.4992794964 -77.1047618729 48.2976759048 +-41.4969714664 76.9716622435 48.5114890576 +-41.4828832923 -66.5155838678 62.0874181818 +-41.4807513483 -24.2879782864 87.6894599045 +-41.4756633057 -27.296259998 86.8025549363 +-41.4604079693 68.5402366241 59.8604254456 +-41.4447973736 84.5993570554 -33.545156975 +-41.4381297694 61.8995392282 66.7182766905 +-41.437248493 49.5232539533 76.3570674869 +-41.4343348854 -69.7833731962 58.4249665637 +-41.4314023155 -20.3149708217 88.7171959808 +-41.3932042535 -18.7593708294 89.0768693192 +-41.3914799397 -73.1591931169 54.1708210283 +-41.3905698394 -69.90406929 58.3115925445 +-41.3828241349 55.762674737 71.9582238024 +-41.3428467507 -63.5894837624 65.170135625 +-41.3369151912 73.2117475113 54.141476419 +-41.3249173416 -20.4958905187 88.7252482586 +-41.3228939566 -66.907467187 61.772237046 +-41.3210214822 -26.0212359687 87.2666514903 +-41.3102639624 -59.7709763708 68.7087510804 +-41.3093544878 50.1479090256 76.0179219143 +-41.3078608468 14.1992484123 89.9557778955 +-41.3067790855 67.6713674116 60.9453528518 +-41.3033710472 79.8527597695 43.7900479257 +-41.296349615 -65.7045795031 63.0675807431 +-41.2909807827 48.947857068 76.8060036355 +-41.2837449725 -44.7387659143 79.3353340291 +-41.2799117852 76.2501468273 49.8185105339 +-41.2641367446 57.4674430049 70.673644403 +-41.2634167655 81.2643203593 -41.1514358605 +-41.2438796022 -71.2353648647 56.7843745053 +-41.2394963103 78.1184927971 46.8700866991 +-41.238687934 77.6240467976 47.6851966153 +-41.237398341 75.8550970347 50.4527623815 +-41.2308005879 83.3143321516 -36.861133203 +-41.2275499416 -24.2655023384 87.8150016915 +-41.2176599224 4.84196222159 90.9816460192 +-41.2090641064 82.0420916366 39.6346847517 +-41.2078366672 82.0039616534 39.7147890635 +-41.2016147333 77.9807903286 -47.1319772882 +-41.2012434666 78.0460318127 -47.0241901057 +-41.1919574588 -70.3505793998 57.9138896882 +-41.1727084811 -22.6536072584 88.2701657102 +-41.167648474 36.8728215413 83.3403848725 +-41.1619681065 80.368348364 -42.9723278732 +-41.1609611867 -67.6978881788 61.0145163901 +-41.1570497215 67.8247188253 60.8761429009 +-41.1401256522 80.6724151042 42.4199422745 +-41.1352368263 -27.1236911636 87.018375467 +-41.1285241555 -71.9599925617 55.9482258102 +-41.1242799108 60.2181857345 68.4292606175 +-41.1171666127 -72.8225511388 54.829322952 +-41.116481484 65.5961416343 63.2975604037 +-41.1012143254 -12.542373931 90.2960632428 +-41.100594918 -66.5995222889 62.2514636638 +-41.0980946017 38.6612269301 82.5606210755 +-41.0935573924 76.4788294604 49.6216503675 +-41.0888201758 62.2435263116 66.614204858 +-41.0680160746 40.6118250401 81.6339250717 +-41.0650342001 -60.0413849013 68.6199319824 +-41.0537306434 -71.5390202906 56.5398954378 +-41.051986469 69.7481057162 58.7361571432 +-41.0461296129 79.2875933752 45.0410122064 +-41.0446141645 66.1466189438 62.7691361291 +-41.0405566633 -68.0068691429 60.7514481979 +-41.0402647436 -71.6603418578 56.3958515726 +-41.0370180021 62.2359045449 66.6532470249 +-41.0334945021 -24.1416445082 87.9399416044 +-41.0300970995 -26.9517362176 87.121381112 +-41.0190016979 8.2187427296 90.8289258312 +-41.0113224451 -23.6302032311 88.0890738205 +-41.0095964753 -60.0502550514 68.6453193248 +-41.0025540304 -29.1389984396 86.4274801954 +-41.0011986501 63.1845840117 65.7769720534 +-40.999115104 -60.0574116615 68.6453193248 +-40.9881626984 -27.5636752676 86.9494929505 +-40.9794178428 78.821466546 45.9114770487 +-40.9621216915 34.1525842406 84.591403678 +-40.9589497702 21.4856944616 88.66075438 +-40.9355721652 -67.4597351084 61.4285200099 +-40.9282651835 68.6033453145 60.153621011 +-40.9233949594 43.9926023864 79.9370169588 +-40.9059230619 -41.8739709289 81.0757424702 +-40.9040190175 -19.6242625626 89.1164942482 +-40.9034972899 15.7669443084 89.8794046299 +-40.8934534036 -66.4713598154 62.5242656336 +-40.8837056371 -6.45340099561 91.0322812467 +-40.8809635163 -71.6719587593 56.4967003425 +-40.8798075573 -66.7097829319 62.2787780488 +-40.87847978 -60.0380890133 68.7341091345 +-40.8691027576 28.8834261844 86.5763485696 +-40.8614072707 90.9207545559 7.98509779831 +-40.8550286138 74.315021166 52.9919264233 +-40.8545705824 90.1470310593 -14.2974422091 +-40.8466594777 83.8223118986 -36.1299105657 +-40.8213286797 -26.6313987716 87.317740032 +-40.821042167 69.6334608113 59.0323949356 +-40.8174162121 69.7667510884 58.8773214093 +-40.8140966532 69.6494725962 59.0183063249 +-40.813545312 66.2637042531 62.7963057649 +-40.8038496005 76.2585778256 50.1963660617 +-40.8031156994 -24.4395096464 87.9648572867 +-40.7966251207 30.519774888 86.0475375565 +-40.7904874908 65.32915847 63.7827342144 +-40.7873060878 -64.6439676994 64.4790904261 +-40.7822675305 73.8769501861 -53.6563405971 +-40.7714782765 -9.51032688719 90.8143173825 +-40.7666916819 22.9708502249 88.3765630089 +-40.7642643975 77.2182780981 48.7402531354 +-40.7607060593 82.4730215635 39.2016014434 +-40.7582671823 49.4965117961 76.7389013234 +-40.7545325361 74.2857035332 53.1102845816 +-40.7422750047 -24.4514033188 87.9897488528 +-40.7356970506 -67.9297918017 61.0421687982 +-40.7339092071 -46.5299696453 78.5856893175 +-40.7245351043 68.7244797711 60.153621011 +-40.7223438556 79.3392654932 45.2434709312 +-40.697163479 -9.89080379427 90.8070090085 +-40.6839180132 54.0482396048 73.645139763 +-40.6833395548 -66.7023551886 62.4152360803 +-40.6805735607 30.5993882989 86.0742027004 +-40.6800361049 -9.89416094722 90.8143173825 +-40.6782269659 -66.6416337369 62.4833938242 +-40.6765124352 55.0113011647 72.9326955506 +-40.6764016208 67.9653145332 61.0421687982 +-40.6674695115 91.3406320245 -1.74524064373 +-40.6556570814 -13.1706105124 90.4082549661 +-40.653874374 -72.0607559631 56.1650242447 +-40.6503663585 -72.2311826264 55.9482258102 +-40.6398538367 64.7101863599 64.5057676599 +-40.6367192719 32.1275095708 85.5364260161 +-40.6324714208 -64.2742140476 64.944804833 +-40.6297512879 -66.824201382 62.3197353969 +-40.6291235833 -66.1192451262 63.0675807431 +-40.6190097554 -59.8364270048 69.0630005849 +-40.6023540329 41.317255636 81.5127795729 +-40.5991935138 74.4023818696 53.0659123936 +-40.587465298 89.5992436388 18.0175803048 +-40.5821558006 -43.8707965912 80.1775644244 +-40.5819151776 -27.8911775651 87.035569594 +-40.5689305398 -71.9395256748 56.3814377303 +-40.5616009526 75.1738358791 51.9966434242 +-40.5597485471 -24.4865187309 88.0642787868 +-40.5421114945 -65.2605004717 64.0109699485 +-40.5414963335 -48.4870855931 77.4944488704 +-40.5257708122 91.1079476747 7.55008414395 +-40.5223894011 77.2492839369 -48.8925770283 +-40.508666765 78.0824182156 47.562420907 +-40.503963209 47.5415391274 78.0975737252 +-40.4885447088 -61.4741162118 67.6875969683 +-40.4869253192 43.5386331638 80.4064443961 +-40.4835309711 -66.4530038862 62.8098877137 +-40.4704001001 -46.5230613302 78.7257993304 +-40.4691723834 43.1707257623 80.6134884728 +-40.4664467109 -65.7001648969 63.6078220278 +-40.462459972 50.5958282277 76.1764497661 +-40.4549792527 -65.7072266235 63.6078220278 +-40.4502175237 -66.1901372119 63.108205791 +-40.4423007671 -8.65531330659 91.0467235008 +-40.4355413797 -67.0307629662 62.2241416936 +-40.4314045694 -26.5584687313 87.5211360941 +-40.419354542 -68.4271420303 60.6959801962 +-40.4189611155 72.8277798275 55.3391549243 +-40.4173690618 64.1816928784 65.170135625 +-40.4091327621 -15.7386151191 90.1077021322 +-40.4089814464 -66.3827739143 62.932039105 +-40.4079933 -68.5444357251 60.5710690725 +-40.40509561 75.1031982909 -52.2200905326 +-40.4047295986 -26.571241336 87.5295776291 +-40.4030565522 84.4032800829 -35.2658380374 +-40.389485436 -72.2092758433 56.1650242447 +-40.3889309427 -72.1196255601 56.2804927695 +-40.3866440718 73.3720052826 -54.6394346734 +-40.3861222496 72.7686100312 55.4408741251 +-40.3840881404 -8.54707574463 91.082780597 +-40.3834953085 89.3148098407 19.7999507521 +-40.3825656431 -15.7201510122 90.1228341999 +-40.3808230404 -72.848933162 55.3391549243 +-40.3759000357 72.5411749821 -55.7455346062 +-40.3699664631 57.9336102094 70.8093398915 +-40.35037175 21.0767334012 89.0371765543 +-40.3499674124 -45.5272230539 79.3671978264 +-40.3499247046 -72.1976892965 56.2083377852 +-40.3497841269 -59.5515944742 69.4658370459 +-40.3497694058 81.6415544285 -41.3104429825 +-40.3295993302 -58.6799311482 70.2153052995 +-40.3188453706 77.451781337 48.7402531354 +-40.3186709094 90.684975892 -12.2735456807 +-40.3043976119 74.5414240138 -53.0954954695 +-40.2998963656 23.7195086994 88.3928914562 +-40.2970566997 45.8691770853 79.1970063504 +-40.2970058207 -23.1718060716 88.5393625754 +-40.2933744015 67.8078478729 61.4698279336 +-40.2872315033 -72.322449325 56.0928007986 +-40.2813012657 -7.77153920461 91.1976970473 +-40.2785401532 89.3317607035 19.9367934417 +-40.2739699558 25.2442277658 87.9814543441 +-40.2738688905 -10.2132960403 90.9599036311 +-40.2643477244 68.8489908243 60.3207987745 +-40.2616884955 -72.2469321349 56.2083377852 +-40.2605986896 63.3183491699 66.1049986881 +-40.2574763798 78.8395861301 46.5151078077 +-40.2355233281 45.1276363157 79.6529918024 +-40.2322410338 67.5438070975 61.7996836899 +-40.2240065758 -72.0314155301 56.5111004292 +-40.2213321037 80.1453774196 44.2601730913 +-40.2200098168 -69.8037073658 59.243508069 +-40.2038278028 81.1678612193 42.3725209904 +-40.1890872669 -72.2648880688 56.2372049186 +-40.1777398882 -13.7559149945 90.534656459 +-40.1680663088 -45.8351664472 79.2821793707 +-40.1609993103 70.8976849007 57.9707892832 +-40.1547031497 -26.810245043 87.5717453046 +-40.1538193613 -63.4680000595 66.02638684 +-40.1530314002 -62.9064243146 66.5621202286 +-40.1472837808 -66.6054683907 62.8641963719 +-40.1471589571 82.2410010844 40.3066169295 +-40.1453421626 -26.824260045 87.5717453046 +-40.1451838086 75.9171530701 -51.2342667236 +-40.124767477 81.8325263054 41.1514358605 +-40.1189664639 -62.4437561424 67.0167579691 +-40.1143735715 -72.1601911398 56.424674103 +-40.1116744679 -73.631157917 54.4931753083 +-40.109906865 -0.630096767951 91.6013010243 +-40.1047602955 -13.6762106128 90.5790785166 +-40.0976940951 -62.052816361 67.3915640857 +-40.0870835661 -69.0982460735 60.153621011 +-40.0852444147 73.3082955298 54.946037043 +-40.0793185642 84.406848853 -35.6248802122 +-40.0742722039 48.9089225909 77.472382165 +-40.0631625003 84.4488899412 -35.5433256487 +-40.0629394416 -19.6439753496 89.4934361602 +-40.0595970408 74.3987454486 53.4794854183 +-40.055485094 -60.8628366461 68.4928699156 +-40.0468967227 68.8904023445 60.4181969914 +-40.0360943559 60.4879403678 68.8354575694 +-40.0339589499 -62.9133973027 66.6272209433 +-40.0289863969 -71.3308148231 57.5290805133 +-40.0239974075 59.4050870975 69.7790459842 +-40.0135197151 82.1490141988 40.625825606 +-40.0083908927 60.2174692164 69.0882411077 +-39.9863225272 68.3735887545 61.0421687982 +-39.9722248336 80.6295008097 43.6016609893 +-39.9695813537 45.7695918207 79.4202557977 +-39.9584018378 71.7027043244 57.1143442153 +-39.9553517939 -62.5485732398 67.0167579691 +-39.9551345438 -72.6180642284 55.9482258102 +-39.9397824391 63.7930683031 65.8426777644 +-39.9340959338 -25.2648023095 88.1303452065 +-39.9339295266 73.6410738265 -54.6101961014 +-39.9283083858 -44.97233608 79.8950510167 +-39.9260331982 69.9127049486 59.3137889518 +-39.9077756939 90.8262956044 -12.5679539283 +-39.9036263585 -44.5827755969 80.1253812691 +-39.9018078419 -59.0012451868 70.1904466245 +-39.8958445885 -44.5897394145 80.1253812691 +-39.884447046 56.2891515768 72.3931094691 +-39.8830045685 -42.6945273374 81.1573981965 +-39.8822070283 -62.8443023757 66.7832555471 +-39.8812100916 -59.0151699505 70.1904466245 +-39.8777431304 77.860911402 48.4504290844 +-39.8743468394 -58.9606396747 70.240155419 +-39.862105668 77.5632689545 48.9382451749 +-39.8607389815 79.0136233347 46.5614520325 +-39.8566792006 -11.2783033906 91.0178279005 +-39.8548796755 -69.5342495141 59.8044873781 +-39.8537632647 -58.9745548551 70.240155419 +-39.8507068316 -25.3388367871 88.1468349704 +-39.8468985224 -58.9643965893 70.2525772694 +-39.8397487578 -70.0452198625 59.2153830802 +-39.8347314746 68.3880003685 61.125081382 +-39.8346385405 -70.0362352101 59.2294464767 +-39.8285793538 -25.3736034365 88.1468349704 +-39.8062033677 77.6878092322 48.7859659139 +-39.7986018815 23.3216982599 88.7252482586 +-39.7973213246 4.6399054023 91.6222925562 +-39.7934697283 -72.8955455747 55.7020574338 +-39.7838032411 54.9995774623 73.4322509436 +-39.7783924834 37.9466991795 83.5327930385 +-39.774039086 83.3880070557 38.2683432365 +-39.7728891342 -72.7069082521 55.9626909856 +-39.7676361318 -7.13383274431 91.4748246616 +-39.7569570802 79.2200596944 46.2986663495 +-39.7330174904 -73.423408182 55.0480740085 +-39.7127504385 -69.5674271342 59.8604254456 +-39.7067155752 -11.5133254761 91.0539404678 +-39.7013483651 22.9031100416 88.8777277411 +-39.6971216323 62.2400597092 67.4560116039 +-39.6962764922 -64.3490877785 65.44769312 +-39.6842722629 25.427973141 88.1962398116 +-39.6721161061 -49.1661924552 77.5165061333 +-39.6495210107 -73.5448740354 54.946037043 +-39.6164424019 68.8951049019 60.6959801962 +-39.6130742673 77.1780776529 49.7428253812 +-39.6096598779 75.3813391125 -52.4283182828 +-39.6055831931 -67.1833003776 62.5923472184 +-39.6053089622 82.2202938661 40.8808363244 +-39.5999971904 40.537140028 82.3928425343 +-39.5723317985 79.9630943 45.1656296979 +-39.5716961264 -30.3644303979 86.6722691078 +-39.5656458832 -71.2316450444 57.9707892832 +-39.5582540329 -72.8572405801 55.9192903471 +-39.5559290709 -73.1571604053 55.5279961531 +-39.5535700115 19.1891223561 89.8181088787 +-39.5531748761 -70.1955769781 59.2294464767 +-39.5467761074 72.8967705869 -55.875874378 +-39.5410935348 -72.9774338831 55.774510898 +-39.5396994532 63.7710068573 66.1049986881 +-39.5395041647 -25.5107827069 88.2373366331 +-39.5360470264 75.8510458802 51.8027009373 +-39.5236330948 -73.0974302471 55.62956155 +-39.5191491367 -66.5578327788 63.3110712854 +-39.5129585588 77.9517230486 48.6030346756 +-39.5065889439 73.7412733542 54.7855275974 +-39.5042445951 -73.3060311971 55.3682259884 +-39.5041345388 83.3080619408 38.7193771905 +-39.5018009194 13.965048913 90.7996978683 +-39.5001178149 74.6972913298 -53.4794854183 +-39.4980628375 57.9019947834 71.3250449154 +-39.495147207 -72.0497762203 56.9996762596 +-39.4912781248 -73.037590982 55.7310439129 +-39.4853577016 -72.8745672774 55.9482258102 +-39.4831466242 -72.9312538981 55.875874378 +-39.4821088037 13.0421715882 90.9453948514 +-39.4814289965 30.4817081559 86.6722691078 +-39.4738394528 22.4880958601 89.0847997329 +-39.4737160402 -72.490200966 56.4534897583 +-39.4710866165 74.2343172157 54.141476419 +-39.4634983756 -72.9862134106 55.8179625922 +-39.4622650551 84.1664214263 -36.861133203 +-39.4573206835 -73.188366605 55.557023302 +-39.4571989285 51.7013185514 75.9611947823 +-39.45478439 52.990536379 75.0687887408 +-39.451330989 84.1431008892 -36.9260213935 +-39.4446488717 73.5023400844 55.1500288078 +-39.4342982618 -73.1456629087 55.62956155 +-39.4301413667 -72.6817771848 56.2372049186 +-39.4289616566 75.1648434202 52.8734649546 +-39.4133350025 -50.5740056518 76.7389013234 +-39.4104537266 -22.9098149593 89.0053735209 +-39.4072134581 -73.2483792393 55.5134800412 +-39.4029665056 -43.5775380439 80.9222120842 +-39.3945488503 75.7407634487 52.071165467 +-39.389839064 -73.2467215767 55.5279961531 +-39.3789219569 -73.0429468289 55.8034803938 +-39.3720525983 -58.4374466648 70.9570736537 +-39.3586886268 84.3281155193 -36.6014011008 +-39.3550920169 -73.2433880577 55.557023302 +-39.3399880442 -72.6971214995 56.2804927695 +-39.3396757393 -8.08958748753 91.5802843794 +-39.3296172408 -60.056190597 69.6163427557 +-39.3167364757 -73.2639842947 55.557023302 +-39.3153486827 -62.9666082069 67.0038029434 +-39.3011003739 -49.532348128 77.472382165 +-39.2998550888 -72.7746120115 56.2083377852 +-39.2943405321 -42.987569688 81.2897512265 +-39.2933814231 -70.6833401988 58.8208772008 +-39.2883167261 -74.2027178615 54.3174449951 +-39.2837014907 -73.4792115523 55.2955356864 +-39.282519992 21.4887326406 89.4154236839 +-39.2745113891 -16.7276987805 90.4306189775 +-39.2689610217 -72.9914017468 55.9482258102 +-39.2475287166 81.7327941431 42.1827198174 +-39.2451739621 -50.1773556337 77.0846891561 +-39.2436289794 -73.281166287 55.5860436814 +-39.2177886911 49.3565410928 77.626650717 +-39.2115096609 62.4358568761 67.5590207616 +-39.1984294493 46.8475549606 79.175688964 +-39.1951465414 -73.2520622974 55.6585649903 +-39.1790226911 54.1634916184 74.3728469045 +-39.172035709 76.7138767973 50.7989441341 +-39.1649182933 -3.7711527052 91.9341480754 +-39.1576010321 -49.9036550723 77.3065811677 +-39.154403809 -58.9991125207 70.6118784917 +-39.1382655573 -59.6276630546 70.09092643 +-39.1336526508 71.3312296347 58.141318432 +-39.1283521126 -27.1746620197 87.9233177551 +-39.0928379302 -48.7958380969 78.0430407338 +-39.0809367309 -73.3460686548 55.6150572878 +-39.0805968026 -73.4999126882 55.4118199338 +-39.0799683963 -49.9302047756 77.3287186058 +-39.0669953515 -58.3135376354 71.2271100259 +-39.0661870267 -66.7734805189 63.3650955225 +-39.0645200674 -58.0903268055 71.4106238843 +-39.0610133079 -44.7291809084 80.4582973635 +-39.0603056721 91.8865175997 5.58215049932 +-39.059188735 -51.0503563849 76.6044443119 +-39.0581408775 -58.1246455404 71.3861836212 +-39.0558165188 -9.7015152403 91.5452008468 +-39.0553388329 69.9386157577 59.8604254456 +-39.0440395775 -39.5239903305 83.1469612303 +-39.0382784173 -46.8551970413 79.2502575922 +-39.0318156478 75.7849530811 52.2796160442 +-39.027021289 -72.9990974561 56.107248907 +-39.0253245751 -63.0642217776 67.0815024682 +-39.0238679367 80.1883162896 -45.2434709312 +-39.0229372106 -38.3075904773 83.7241833838 +-39.0179772913 -0.735558663038 92.0709313603 +-38.9885295117 50.6825111755 76.8841832073 +-38.9799851775 -63.0647247221 67.1073859667 +-38.9728776481 63.2752489064 66.9130606359 +-38.9690138031 75.6630157648 -52.5026095407 +-38.9616225337 -71.9079564639 57.5433555394 +-38.9565349427 92.0884901746 1.44857261386 +-38.9560276009 92.0872908807 1.5358293575 +-38.9550602243 91.995496241 -4.39681183179 +-38.9548283972 -73.3251122667 55.7310439129 +-38.9503337317 75.7241239251 -52.4283182828 +-38.9491707846 -73.6243168216 55.3391549243 +-38.9462027921 29.5832099273 87.2240046001 +-38.9412206207 -20.4706147516 89.8027575761 +-38.9372313255 83.3871423593 -39.1213050121 +-38.9359706087 -40.1367316267 82.9037572555 +-38.9289817264 76.3365430619 51.5486816038 +-38.9289648346 -40.1435266242 82.9037572555 +-38.9287871622 64.4820864858 65.7769720534 +-38.9225489177 -73.1102929668 56.0349912828 +-38.9220547445 -43.7619854968 81.0553038353 +-38.9125233866 48.3628385529 78.4018582101 +-38.9044172307 -72.9534082598 56.2516359159 +-38.9042173126 -57.2458173725 72.1760228098 +-38.9027477638 73.3197118824 55.774510898 +-38.9001621234 -73.5627361043 55.4553986878 +-38.8987673471 -67.0499412527 63.1758757508 +-38.8983839716 -57.2802330922 72.1518580586 +-38.888628774 -67.4114124934 62.7963057649 +-38.8822948747 50.7640573419 76.8841832073 +-38.8784253009 64.5258659828 65.7638248986 +-38.8751193314 -73.8268967246 55.1209072583 +-38.874174987 72.0464868689 57.4291062871 +-38.8616690237 -72.4159979752 56.9709918989 +-38.8585059031 75.5131949099 52.7993741769 +-38.8436333603 -74.6815620865 53.9799632428 +-38.8400084889 24.1005993659 88.9416373291 +-38.8397567192 -73.5727525059 55.4844427448 +-38.8355553017 -17.7229454593 90.4306189775 +-38.8333519317 -57.141542131 72.296714591 +-38.8328660779 -66.9094401531 63.3650955225 +-38.8318322834 68.1347010521 62.0463642292 +-38.8149958401 67.3652399234 62.8913392129 +-38.7985574395 -41.8546497298 82.1149209134 +-38.7983043716 -25.6022040579 88.5393625754 +-38.7957973708 -74.7488612472 53.9211818177 +-38.7878416573 -5.56868393278 92.0026798459 +-38.7794337727 -26.1866115984 88.3765630089 +-38.7714372264 -12.6574811474 91.3047853423 +-38.7709513971 -52.300419695 75.9044098026 +-38.7682339377 -49.7104328669 77.626650717 +-38.7615127174 77.1693229945 -50.4226211181 +-38.7591044006 -73.8878705139 55.1209072583 +-38.7568006037 -41.3440431754 82.3928425343 +-38.7526927449 -52.3139501236 75.9044098026 +-38.7426310551 -65.5885663656 64.7854034566 +-38.7417376021 -12.0148036023 91.4041698281 +-38.7341945571 -40.3916446108 82.8744666206 +-38.7331754284 -45.1429130387 80.3856860617 +-38.7313521502 -72.598357173 56.8274660389 +-38.7290455135 59.4555912855 70.4634209964 +-38.7254559501 -32.7603197859 86.1806272255 +-38.7248015089 -73.6661334966 55.4408741251 +-38.7223052257 -12.0235953657 91.4112478445 +-38.7135898821 -57.2227491282 72.296714591 +-38.6992547729 50.6165240445 77.0735698776 +-38.6977506785 -57.2639177134 72.2725938412 +-38.697388045 50.4314179629 77.1957527377 +-38.6950828877 -73.9539805618 55.0772123421 +-38.6734082913 -38.2037863914 83.9335343977 +-38.6682194525 -32.8278585259 86.1806272255 +-38.6642379913 61.2317364569 68.9619543736 +-38.661236794 -74.0150405312 55.0189289674 +-38.6606810063 -52.0187063052 76.1538307537 +-38.6523740986 -72.1770928776 57.4148172537 +-38.6518978863 -41.3043187716 82.4620157442 +-38.6399932347 -57.3941208564 72.2001787667 +-38.6372413391 46.0134426167 79.9370169588 +-38.6329428399 -55.6891569761 73.5269577966 +-38.626194466 -74.5174831672 54.3613999406 +-38.6237291087 -53.3565890819 75.2414908896 +-38.6228098885 76.6928449687 -51.2492545011 +-38.6189881378 -57.5144746351 72.1155944485 +-38.6129890414 -72.164064389 57.4576791052 +-38.6079815973 -41.2862661298 82.4916237326 +-38.6074227742 -74.2590754777 54.7271104292 +-38.6049529109 -57.4935722568 72.1397723859 +-38.6016023461 81.9583092441 -42.3409003465 +-38.5959850424 -74.6185079697 54.2441536663 +-38.5940567946 -73.2621181641 56.0638994563 +-38.5812424324 76.6436008856 -51.3541252058 +-38.5784457647 74.5208415431 54.3906949587 +-38.5670488174 37.0491309766 84.4981931132 +-38.5655580302 76.2476009966 -51.951911188 +-38.5655305486 -59.3857093026 70.6118784917 +-38.5530752599 73.7452313332 -55.4553986878 +-38.5477638364 92.1513956825 -4.71064507096 +-38.5415726944 -73.5980388153 55.6585649903 +-38.527308143 -49.7946051843 77.6926239858 +-38.5264074507 -23.0301899035 89.3606528733 +-38.5224170523 -13.1516247119 91.3403424117 +-38.5155255974 -13.1717931986 91.3403424117 +-38.511114374 -59.0083703231 70.9570736537 +-38.5076386958 65.7661072863 64.7455086819 +-38.5000304495 -74.8486802954 53.9946544894 +-38.4990772938 -74.272249282 54.7855275974 +-38.4887057334 73.7788471538 -55.4553986878 +-38.4778608954 -0.0201469626936 -92.300887401 +-38.4766421066 -26.4937307209 88.417363932 +-38.4742378518 -74.7664521421 54.1268016402 +-38.4735006965 -57.5361753639 72.1760228098 +-38.4710957077 -56.5447898023 72.9565729819 +-38.4706288678 49.0281565477 78.2064612424 +-38.465173688 -49.8939824645 77.6596479968 +-38.4610186461 -73.4754156654 55.875874378 +-38.4600658296 -50.3583028602 77.3619070953 +-38.4570383096 -73.3120310933 56.0928007986 +-38.4570203729 -74.6689190916 54.2734751581 +-38.4541400785 -73.5559857857 55.774510898 +-38.435269815 -74.5627361957 54.4346250585 +-38.434247878 -74.3058177798 54.7855275974 +-38.4174757146 -74.8486952545 54.0534030235 +-38.4165205845 -75.0078883808 53.832960413 +-38.4131672166 -74.840301016 54.0680860418 +-38.4084045001 18.6666901818 90.4231670614 +-38.4056830708 -56.5122465123 73.0162276621 +-38.3990667087 -74.2378012139 54.9022817998 +-38.3986281973 91.4360584856 -12.84494302 +-38.3891818235 -49.4375631401 77.9884483093 +-38.3835361007 91.4448246728 -12.827634114 +-38.3828334793 -74.4291122665 54.654051463 +-38.3813272833 -46.2633813016 79.9160388565 +-38.381245327 75.0681339958 -53.7741133403 +-38.3780201411 78.9662498886 47.8691857941 +-38.3731504886 74.2512004937 -54.9022817998 +-38.3680038219 -72.4645492541 57.2432125595 +-38.3607261631 -73.439727676 55.9916162217 +-38.3603054783 -23.0947823336 89.4154236839 +-38.3569515319 73.4637426683 55.9626909856 +-38.3531042616 75.5327405193 -53.1398579518 +-38.3479079284 -73.4464217671 55.9916162217 +-38.3444175074 75.2551566276 -53.5384632481 +-38.343652905 90.86060696 16.5564001146 +-38.3416322531 -18.148574014 90.5568799011 +-38.3397838321 74.6652474194 -54.3613999406 +-38.3386770853 -55.7831213064 73.609708712 +-38.3353476338 -66.7480636952 63.8364873308 +-38.3288621803 12.2101909751 -91.5522231315 +-38.326640017 -74.7359254929 54.2734751581 +-38.3243571566 -66.9722974476 63.6078220278 +-38.3221331748 -74.7914224313 54.200159037 +-38.3207001343 -56.8769907198 72.7772757657 +-38.3166326602 50.2977699631 77.472382165 +-38.3165601203 91.5089490411 -12.5679539283 +-38.3135955536 -74.7426136151 54.2734751581 +-38.3090833045 -66.8914302333 63.70204626 +-38.3087877596 -57.6157180503 72.2001787667 +-38.3072507303 47.1875214513 79.4096490407 +-38.3062257895 -36.1864224515 84.9892692987 +-38.2999094839 -36.193107598 84.9892692987 +-38.2964512786 -53.1384257884 75.5624875464 +-38.2937697847 78.4443543254 -48.7859659139 +-38.2927005448 -56.5580823565 73.0400739673 +-38.2912448046 72.3806613131 -57.4005264714 +-38.2871762905 -53.1451089706 75.5624875464 +-38.2865319759 -56.4852416475 73.0996507877 +-38.2846942103 -72.429433759 57.3433458613 +-38.2778449128 -47.7443965416 79.0903229713 +-38.2774788975 91.8201974642 -10.1924455795 +-38.2767271857 -72.4449625689 57.3290463408 +-38.2760604925 72.138599164 57.7145190037 +-38.2699508189 10.7932424004 91.754655374 +-38.258917628 78.4424057873 -48.8164336698 +-38.2550741817 -75.079810478 53.8476680827 +-38.2416501113 -75.1182751639 53.8035401546 +-38.238988083 -73.6131856809 55.8469218875 +-38.2385441454 75.7980409087 -52.8438334722 +-38.2362845753 77.9466378793 49.6216503675 +-38.227486947 72.5048806264 -57.2861373028 +-38.224691214 83.1829115845 40.2427161349 +-38.217850017 91.3627113103 -13.8654578758 +-38.209324095 76.0699845227 -52.4728978323 +-38.2053674856 -53.4632007683 75.3792813636 +-38.1960948583 84.0857668751 38.3489523534 +-38.1949197733 -69.3902135169 61.0421687982 +-38.1914261237 -44.1204989109 81.2083526892 +-38.1880750432 77.2676982564 50.7087145436 +-38.1857020186 35.3355966261 85.4005138885 +-38.1758679271 -56.1740837974 73.3966989553 +-38.171665368 -56.9771190493 72.7772757657 +-38.1704901843 -74.6559275873 54.4931753083 +-38.1668689262 -51.3542724438 76.8506917219 +-38.1615406585 -74.7671557886 54.3467499475 +-38.1599772821 72.9003102697 -56.8274660389 +-38.1581214512 -28.8273655645 87.8233497535 +-38.1532799971 -50.7600225099 77.2511963678 +-38.1305200641 -49.0337545889 78.3693457326 +-38.128928859 -36.373189139 84.9892692987 +-38.1224041999 -55.5099427016 73.927860508 +-38.1095723789 69.5221148907 60.9453528518 +-38.1088361865 -74.8897142034 54.2148255651 +-38.1063291816 84.3961639501 37.7517574003 +-38.1060653424 -59.1970869775 71.0185375623 +-38.1029499045 -64.5056308898 66.2358572986 +-38.100691873 84.1877167284 38.2199637738 +-38.0986459205 -55.1653124084 74.1975840976 +-38.0964178165 78.1784816009 49.3638325511 +-38.0891284325 -56.6185424571 73.0996507877 +-38.0890731612 -58.7642348178 71.3861836212 +-38.0839253753 -55.1439976489 74.2209818805 +-38.0806188076 71.1691142237 59.0323949356 +-38.0765476062 81.9165614251 42.8935133403 +-38.0738761051 -75.9324430823 52.7697266042 +-38.0461598193 -64.5122968125 66.2620048216 +-38.0397049364 -56.6517599292 73.0996507877 +-38.0359243869 79.636637303 47.0241901057 +-38.0331308403 83.7658367281 39.2016014434 +-38.0303150422 -42.879775427 81.9452255907 +-38.0273322761 -47.9441634847 79.0903229713 +-38.026614931 81.5483388831 43.6330721162 +-38.0153191707 71.7378793289 58.3824646426 +-38.0123895224 66.5078877362 64.2787609687 +-38.0107184946 84.1844097509 38.3167122078 +-38.0077366058 84.2954590319 38.0747625693 +-38.0040974572 -73.7895149094 55.774510898 +-38.002919815 -53.8326693568 75.2184937064 +-38.0009499193 -58.5834628005 71.5814619265 +-37.994664897 84.345028457 37.9779095522 +-37.9908211168 -44.2933512435 81.2083526892 +-37.984847894 -55.1651035215 74.2560615973 +-37.9823220456 57.5594854307 72.4171861437 +-37.9684909448 72.7197375409 57.1859551582 +-37.9665071071 75.2261455888 53.8476680827 +-37.9656295774 -22.9928025579 89.6099436521 +-37.9638820076 70.4182257182 60.0001429133 +-37.9575563671 -74.7537470831 54.507808722 +-37.9428221917 -42.7660877181 82.0451338314 +-37.9368860769 84.3346540134 38.0586232965 +-37.9267274885 64.5154829184 66.327338299 +-37.9263574911 -71.8425332403 58.3115925445 +-37.922248773 78.1672185941 -49.5155428655 +-37.9215478833 84.2612456505 38.2360914263 +-37.9164429217 -44.5989611882 81.0757424702 +-37.9065073604 -22.8486240681 89.6718299017 +-37.9063187667 73.9163102688 -55.6730641675 +-37.8992715025 84.3297035585 38.107037635 +-37.8958295124 84.4402649886 37.8648617352 +-37.8890236015 -73.6292134161 56.0638994563 +-37.8885313058 -72.5357337949 57.4719628891 +-37.8866101472 64.4987641124 66.3665141432 +-37.8822856471 84.41008627 37.9456159529 +-37.8776218861 -44.4274457739 81.1879783112 +-37.8775717086 -48.2030154438 79.0048027881 +-37.8768600226 84.3979967823 37.9779095522 +-37.8661991306 24.6187950438 89.219201375 +-37.8643195586 -73.1101281674 56.7556381667 +-37.8584372378 76.499858596 52.1009631841 +-37.8579405284 -58.5867064038 71.65454746 +-37.8561968925 84.3125586461 38.1877049766 +-37.8539249447 -72.5311654912 57.5005252043 +-37.8524219087 -48.2402945225 78.9941019319 +-37.8509688239 79.2849706627 -47.7618842395 +-37.8454097461 -37.5558881235 84.6007105668 +-37.8452654315 -66.5385706626 64.3455864734 +-37.8437301845 -44.4190898064 81.2083526892 +-37.83940376 -54.5859499234 74.7566290977 +-37.8377315568 82.3787190688 42.2143662183 +-37.8358729953 -48.3233171231 78.9512744476 +-37.8300743082 -39.2426641489 83.8385280663 +-37.8224601607 -42.4509986749 82.2640518021 +-37.8218249206 8.05997755433 92.220097167 +-37.814020001 84.4551965841 37.9133177301 +-37.8128573977 -66.9430014481 63.9439001981 +-37.8029717671 83.8022846224 39.3460597474 +-37.8026591604 -43.9496458521 81.4824373094 +-37.7980327467 84.4985605313 -37.8325519707 +-37.7933848532 -43.9388634753 81.4925538797 +-37.7928988029 75.2082049157 -53.9946544894 +-37.7901942164 84.2836329703 38.3167122078 +-37.7863711027 56.189673964 73.5860767993 +-37.7840012478 75.2232199392 -53.9799632428 +-37.7834354842 -47.4662696363 79.4944353388 +-37.776050022 84.3703930632 38.1393080575 +-37.7754727197 -16.3234289958 91.1403276635 +-37.7685348826 84.5117493855 -37.8325519707 +-37.7627940344 -69.9283159724 60.6959801962 +-37.7454649157 82.9015380291 41.2627540369 +-37.7449271196 -22.6615117847 89.7873953312 +-37.7433456187 63.5670387921 67.3399691173 +-37.7422347164 -40.3322315107 83.3596714243 +-37.7419486992 -54.6692321672 74.7450357056 +-37.7417245766 55.5978582753 74.057007644 +-37.7337826329 -58.8893851356 71.4716864679 +-37.7334161596 -71.9325642416 58.3257705184 +-37.7180238328 -54.2085364632 75.0918454472 +-37.7160864077 53.4065716991 75.6652821672 +-37.7146073256 -58.1865048687 72.055111168 +-37.7132994811 -38.2702983206 84.3391445813 +-37.7129591518 77.3230250264 -50.9792360946 +-37.7111647508 84.3043646944 38.3489523534 +-37.7056226987 73.5249582906 56.3237651908 +-37.7038889552 -16.4880996794 91.1403276635 +-37.7037731808 -54.6955676934 74.7450357056 +-37.6973124587 84.4710864567 -37.9940546168 +-37.6958167209 -58.9433058314 71.4472679633 +-37.6880719216 84.5693362455 37.7840786818 +-37.6856212692 84.842472549 37.1691915613 +-37.661969418 -0.821787096104 92.6331513311 +-37.6501514603 -58.1982732651 72.0793110676 +-37.6458350679 83.1826600227 40.7852445573 +-37.6438873501 -59.0208483642 71.4106238843 +-37.6374300957 -37.0508179058 84.915609568 +-37.6311937883 61.84379963 68.9872285383 +-37.6297918603 -73.9483185516 55.8179625922 +-37.6236397359 48.7671971775 78.7795799206 +-37.6105010437 -72.465120309 57.7430216549 +-37.6088869038 -73.2418538961 56.7556381667 +-37.6076902705 -61.4905579459 69.315026625 +-37.6034545413 -2.74163054419 92.6199960512 +-37.5876838298 80.9757330527 45.0565941999 +-37.5870411939 47.0002931396 79.8635510047 +-37.5730543321 80.6859473747 45.5855622364 +-37.5604459263 84.4811611219 38.107037635 +-37.5562406612 84.4320031536 38.2199637738 +-37.5421754242 -75.3967918723 53.9064823539 +-37.5232307864 -59.1271506108 71.3861836212 +-37.5082448993 84.5624618292 37.9779095522 +-37.4991556851 -36.5555803786 85.1909787835 +-37.4904881591 -11.7272525691 91.961594401 +-37.4840933411 84.5876644455 37.9456159529 +-37.4792319435 -74.0356586306 55.8034803938 +-37.4762881099 -37.1506645349 84.9432513748 +-37.4727434574 -68.6443302672 62.3197353969 +-37.4690262059 -11.7420810532 91.9684489797 +-37.462761365 43.9408472921 81.6440043737 +-37.455228271 -37.1297876804 84.9616663089 +-37.4474604762 79.7604998256 47.2858369012 +-37.4236375202 84.6505971658 37.8648617352 +-37.4195904639 -63.9078604766 67.1979137981 +-37.4093209911 -51.5273275849 77.1069206683 +-37.4087103058 73.3554153874 -56.7412674039 +-37.3785020565 81.9059612324 43.5231099372 +-37.3760929422 -25.6878769861 89.124411091 +-37.3706086574 77.9984771824 50.1963660617 +-37.3671364685 -75.2096781103 54.2881334243 +-37.3497400908 -51.6535607894 77.0513242776 +-37.3460912308 -57.551908641 72.7533317557 +-37.3406793459 76.1209004345 -53.0215256573 +-37.3358598015 76.4820865582 -52.5026095407 +-37.3287855779 67.6209784211 63.5135028529 +-37.3245711887 -73.7301451436 56.3093427655 +-37.3223842263 -53.4407306281 75.8361915289 +-37.3119817102 -25.6438145571 89.163954577 +-37.3069050083 -39.1350580289 84.1227797435 +-37.302837473 -40.0444119997 83.6955398099 +-37.3027290726 -48.6666031659 78.9941019319 +-37.3024464891 -57.8820666777 72.5134045749 +-37.3000740839 -39.141568716 84.1227797435 +-37.2935506166 -28.4409435203 88.3193286551 +-37.289588254 -13.5723001725 91.7893200535 +-37.2819451921 -53.5818020138 75.7564984384 +-37.2627779685 76.2311040675 -52.9179000974 +-37.2552462796 13.9884865602 91.7407699357 +-37.2502106466 33.8713225606 86.4011302865 +-37.2399076197 75.5150624014 53.9505758171 +-37.2283876259 77.4586402932 51.1293086077 +-37.2239450202 70.0965762926 60.8345946742 +-37.2185356465 -22.257192563 90.1077021322 +-37.2177289981 -40.1633599869 83.6764313459 +-37.2155108586 -40.79906559 83.3693108915 +-37.2152417989 76.744005175 -52.2052051767 +-37.2050042763 46.3564745819 80.4168198895 +-37.1995444837 77.8854906156 -50.4979627488 +-37.1670608535 81.5556716391 44.3540529265 +-37.1649439612 -72.6266685712 57.8284873795 +-37.1643895397 76.2996603578 -52.8882782801 +-37.1632647013 49.8220400878 78.3368117696 +-37.1550859313 -52.5343134346 76.5483213493 +-37.1546506632 92.7523782614 4.06549639693 +-37.1439448801 -37.2738285288 85.0352224996 +-37.1330657988 -56.8534953985 73.4085518544 +-37.1291011155 76.1934301118 -53.0659123936 +-37.121490349 -67.7476368188 63.5000209429 +-37.1117346783 -19.6496520386 90.755772951 +-37.1036787393 92.8598076259 -0.610861439068 +-37.0961157666 -26.9716950398 88.8617232655 +-37.0956089275 79.9156484222 47.301214948 +-37.0932520072 75.8172030845 -53.6268810577 +-37.083927565 71.0860334621 59.7625146976 +-37.0729980426 45.6671480477 80.8709119852 +-37.0696785943 -74.350272845 55.6585649903 +-37.0688651203 -67.7638118323 63.5135028529 +-37.0652034303 -57.2940812771 73.0996507877 +-37.063957559 -55.1154194034 74.7566290977 +-37.0528931523 -61.3022662761 69.7790459842 +-37.0474898669 -26.9857926721 88.8777277411 +-37.0411414574 84.9049737357 37.6709340802 +-37.039628137 47.7856342889 79.6529918024 +-37.0361482428 78.4568746951 -49.727683803 +-37.0351920675 76.3727127462 -52.8734649546 +-37.0306161629 84.8808478634 37.7355950342 +-37.027099223 -37.1176842097 85.1543976671 +-37.0251047887 78.2211842565 50.105767621 +-37.0190511867 -37.0837180686 85.1726934143 +-37.0149254511 48.730032897 79.0903229713 +-37.014007372 -45.9868123499 80.7166423246 +-37.0065155564 -52.0155257698 76.9733907611 +-37.0004665311 -27.8818514102 88.6203579231 +-36.9905763277 -53.0247476611 76.2894055451 +-36.9798202806 49.7026963937 78.4992666412 +-36.9766056101 84.9187512042 37.7032668542 +-36.9758347252 76.2164230546 -53.1398579518 +-36.9757565115 -53.4396206685 76.0065811178 +-36.9757325528 -73.2630429347 57.1429938149 +-36.9734923236 75.5724188244 -54.0534030235 +-36.9687192049 84.9006396533 37.7517574003 +-36.9617470952 23.0693619719 90.0090761528 +-36.957720169 76.348670601 -52.9623207325 +-36.953900685 84.9070906189 37.7517574003 +-36.9115619202 70.0090067252 61.125081382 +-36.9084350406 76.5874143364 -52.651072051 +-36.9075121493 -55.2359953683 74.7450357056 +-36.9073023446 -17.4696503226 91.2834177233 +-36.9065406466 91.7153817798 15.0398139113 +-36.9060277753 -59.3381724851 71.5326946227 +-36.8897990449 76.4122933546 -52.9179000974 +-36.8653410118 -22.0809328365 90.2960632428 +-36.8619713303 66.6378346595 64.8119901063 +-36.8540920534 73.2125287902 -57.2861373028 +-36.8532676757 -52.8279203243 76.4921400918 +-36.8495888447 76.3290032937 -53.0659123936 +-36.8462482833 -13.0986240102 92.0368406481 +-36.8458064092 -55.6679410602 74.4544618419 +-36.8371773512 -20.7143504934 90.6307787037 +-36.8367356905 74.9611853208 -54.9897772225 +-36.8303805921 37.583693271 85.0352224996 +-36.8284728135 83.8180956031 40.2267378703 +-36.8244376288 -37.381356319 85.1269345923 +-36.8212948856 -59.3172973569 71.5936483022 +-36.8208602677 76.1676077972 -53.3171620737 +-36.8127037456 -37.3303281648 85.1543976671 +-36.8101020768 -37.3537613276 85.1452459024 +-36.808550332 -60.850022301 70.3022432673 +-36.8076734819 71.8357259378 59.0323949356 +-36.7962921722 76.3547105568 -53.0659123936 +-36.7943140106 -10.1003056664 92.4346378904 +-36.7734153678 83.2583984828 41.4216731225 +-36.7719199328 49.5495571783 78.6935021961 +-36.7706081057 -55.702069403 74.4661120495 +-36.7624874318 79.379313674 48.4504290844 +-36.7455640081 -55.4533837855 74.6638182285 +-36.7414375312 -55.7213148119 74.4661120495 +-36.7379692789 72.5713845047 58.1697151818 +-36.737173244 71.7907312928 59.1309648364 +-36.7347299912 -53.5895060652 76.0179219143 +-36.7220400287 -74.727784543 55.3827589908 +-36.7007105259 -74.6843799149 55.4553986878 +-36.6995265639 -71.7171632293 59.243508069 +-36.6987537067 93.0223500645 0.209439357122 +-36.6913287514 -55.6453208583 74.5475999683 +-36.6906895611 -45.8302427593 80.9529625656 +-36.6847352764 37.8292783671 84.9892692987 +-36.6698217721 70.3521101085 60.8761429009 +-36.6689983314 -57.38183466 73.2305237754 +-36.6680881969 76.2928623831 53.243313734 +-36.6645960058 77.4595544355 -51.5337251359 +-36.641611869 9.02038869603 92.6068294858 +-36.632590996 75.947221542 -53.7593974759 +-36.6179708142 79.6131784841 -48.1753674102 +-36.6114325036 -57.3579186308 73.2780470562 +-36.6023419377 9.04460591506 92.6199960512 +-36.5986579741 -36.3440388948 85.6717518865 +-36.5971193291 -67.2075700256 64.3723029576 +-36.5901128509 -36.3101943901 85.689750991 +-36.5883784503 73.9334738019 56.5254987944 +-36.5879501075 -53.898217092 75.8703110659 +-36.5843498658 61.1279942803 70.1780140797 +-36.5778090747 -72.9805563552 57.7572703422 +-36.5776919315 -53.1810936272 76.3796028635 +-36.5737146937 75.3875533165 -54.5809508754 +-36.5690323724 -17.6230751163 91.3900054426 +-36.5606247537 93.0526059663 2.12914078949 +-36.5605775734 -54.696103054 75.3104274202 +-36.5579991078 -34.5953621139 86.4099162217 +-36.5553001871 -55.3759095367 74.8145618928 +-36.5508068912 -55.1594723585 74.976470474 +-36.5491657412 -23.1054234492 90.1681645086 +-36.5477055426 -56.8197721381 73.727733681 +-36.5439794053 73.7789611306 -56.7556381667 +-36.5428651771 -59.5625100602 71.5326946227 +-36.5364691202 -53.1608924457 76.4133884775 +-36.5330645341 74.4745359935 -55.8469218875 +-36.5296393903 78.2310949309 -50.4527623815 +-36.5280526001 -57.1832675922 73.4559410853 +-36.5276881737 -10.0957047635 92.5408274331 +-36.5261357056 -54.4181518496 75.5281812285 +-36.5223532358 84.3981786468 39.2818680211 +-36.5218825289 -55.24136815 74.9302565154 +-36.5207202987 -57.370230562 73.3136660803 +-36.5150862526 41.8138128165 83.1760394207 +-36.5143098964 80.5700948858 46.638664034 +-36.5141452746 -55.4186917419 74.8029798903 +-36.509559853 71.4997274405 59.6224874966 +-36.5081501245 83.8429181424 40.4662829014 +-36.5022555748 -75.2737092472 54.7855275974 +-36.5014459251 76.5268728118 -53.0215256573 +-36.500247206 80.576466608 46.638664034 +-36.4947259315 -54.2485027788 75.6652821672 +-36.4843339455 -11.1683075987 92.4346378904 +-36.4805095824 -35.8242741631 85.9406411501 +-36.4720957399 -40.9785616739 83.609471446 +-36.4657694453 -55.450535239 74.8029798903 +-36.4633881257 -18.0213288799 91.3545457643 +-36.4628286164 75.6627518899 54.2734751581 +-36.4580257678 -75.3163828121 54.7563223493 +-36.4560909458 -55.4568988718 74.8029798903 +-36.4510640213 -55.491441594 74.7798090499 +-36.4455607966 -35.9025838695 85.9227884191 +-36.4344697805 72.9168200452 57.9281172343 +-36.4339078249 -74.1414478028 56.3526048938 +-36.4296848784 74.198276215 -56.2804927695 +-36.42083832 83.0871610967 -42.0719169633 +-36.4207799331 -55.8693636024 74.5126901925 +-36.4172969704 -75.7371985337 54.200159037 +-36.4152221832 -55.4368776102 74.8377190605 +-36.4083447093 84.4175338297 39.3460597474 +-36.4069948926 83.3323188066 41.596338363 +-36.3991702514 24.9043739158 89.7489418593 +-36.3967704366 -55.1357602539 75.0687887408 +-36.3948594593 -49.0057198347 79.207661425 +-36.3782221471 -57.2787017371 73.4559410853 +-36.372286665 -57.6911985838 73.1353701619 +-36.370413238 79.5131909851 48.5267503577 +-36.3689345127 -55.5140955248 74.8029798903 +-36.3666943947 88.5390868939 28.9533008618 +-36.3661511503 -75.1265847163 55.0772123421 +-36.3646589113 -56.6003088665 73.9865975598 +-36.3586656211 92.2074482781 -13.2602381688 +-36.3576783889 -56.5894439297 73.9983382104 +-36.3347998757 -54.2762760474 75.7223096347 +-36.3258528357 -74.3801656079 56.107248907 +-36.3228181066 36.1331284488 85.8781107925 +-36.3146219601 67.8686313193 63.8364873308 +-36.3137441541 83.1980257628 41.9452082446 +-36.2929624588 44.9302031305 81.6339250717 +-36.2901119567 75.0028766604 -55.2955356864 +-36.2809702414 -75.7921096638 54.2148255651 +-36.275832789 -55.3719836358 74.9533680611 +-36.2736516581 54.3489379158 75.6995055652 +-36.2636744865 -53.9253700917 76.0065811178 +-36.2526535313 -57.1912092303 73.5860767993 +-36.2526375082 -24.7298726007 89.8564392509 +-36.2453881895 80.762717764 -46.5151078077 +-36.2401458362 -75.9790457829 53.9799632428 +-36.2396061888 -45.4290852465 81.3811351416 +-36.2266953541 -24.684391163 89.8794046299 +-36.2223865634 -24.6907135382 89.8794046299 +-36.2136333689 74.0847946533 -56.5686835572 +-36.2060430238 -57.0076000706 73.7513117358 +-36.2001996337 -59.8443278843 71.4716864679 +-36.189441563 -31.4035977033 87.7732212617 +-36.187385088 -45.379866711 81.4318172325 +-36.1844175508 -15.2476988029 91.9684489797 +-36.1784774349 -31.416228288 87.7732212617 +-36.1715243767 -56.9532493306 73.8102175512 +-36.1590557642 75.3010637312 -54.9751988372 +-36.1370055047 69.2708823258 62.4152360803 +-36.1346877246 -57.1594237844 73.6687492475 +-36.1311467461 -57.4197276663 73.4677827999 +-36.116291364 77.5576336862 51.7728399366 +-36.1139789048 -56.145468557 74.4544618419 +-36.1123251428 -56.838115851 73.927860508 +-36.1078627638 -35.7317082123 86.1363295878 +-36.1037144017 -55.5311678113 74.9186973186 +-36.1030160946 68.5334388475 63.2434975995 +-36.094045849 74.7639968549 55.7455346062 +-36.0888743642 -55.5719932169 74.8955720789 +-36.0886474537 -25.2977138105 89.7643314515 +-36.0858399545 -57.0380633476 73.7866619677 +-36.0781399473 81.5301741892 45.2901591366 +-36.0726406658 -55.5045692866 74.9533680611 +-36.0709933664 -32.9604401363 87.2496007073 +-36.0707179523 -55.8636748628 74.6870345992 +-36.0613447043 -56.9773333627 73.8455340626 +-36.051215654 -55.876262515 74.6870345992 +-36.0485080497 -32.9398938229 87.2666514903 +-36.0463460486 -0.396366249812 93.2764913059 +-36.0406587254 -14.6712441315 92.1185405566 +-36.0376673873 -56.5024988649 74.2209818805 +-36.0300960828 -22.6279341924 90.4975622348 +-36.022332385 73.7586825696 -57.1143442153 +-36.0205525949 -57.1554116162 73.727733681 +-36.0172517074 26.9934000395 89.2978943411 +-36.0147836059 69.6282117057 62.0874181818 +-36.0106129635 -77.7558305139 51.5486816038 +-36.0022423526 79.6619747382 48.5572685227 +-35.9946846507 68.851481456 62.959162782 +-35.9943234697 -42.9267862622 82.8353770991 +-35.9849322211 82.4446883058 -43.6801788368 +-35.9847775703 20.0288702567 91.1259575503 +-35.983707493 73.7775337072 -57.1143442153 +-35.9710392418 74.9095202068 -55.62956155 +-35.9542477073 -56.1552887158 74.5243290547 +-35.95298459 85.6542858288 37.0233199244 +-35.9474270181 -22.6110254221 90.534656459 +-35.9467646605 -54.7237191893 75.5853469168 +-35.9465730795 -56.9278279796 73.9396124237 +-35.9442678548 -56.0534882014 74.6057375062 +-35.9392717718 -26.7590463465 89.3997884961 +-35.9373151242 -55.2330298481 75.2184937064 +-35.9358625337 -23.2746518948 90.3709265369 +-35.9266993292 -56.9403722322 73.9396124237 +-35.9230647974 -76.4096189847 53.5826794979 +-35.921996874 20.076125472 91.1403276635 +-35.9188106974 -8.42468099082 92.9454882621 +-35.917680932 -22.7764702728 90.504986594 +-35.9146199523 -29.2182576383 88.6365246062 +-35.911052514 -76.1767842503 53.9211818177 +-35.9038363165 82.4550791815 -43.7272735822 +-35.9031735199 84.8707167306 38.8319916157 +-35.8958681606 -55.338202375 75.1609606571 +-35.8910353108 82.543730072 43.5702445497 +-35.883936979 -73.312992431 57.7715172702 +-35.8753119157 47.0930784051 80.5928282249 +-35.8739249833 -55.9437916197 74.7218420912 +-35.8703664268 -75.9872982896 54.2148255651 +-35.8695306034 32.3197493585 87.5717453046 +-35.8661971971 -73.2767490137 57.8284873795 +-35.8595639449 84.2752861818 40.1468281767 +-35.8546915014 -55.3805172086 75.1494471773 +-35.854394731 -55.9563105733 74.7218420912 +-35.8495209688 10.1781899178 92.7966394667 +-35.8484676665 -70.114389239 61.6348909921 +-35.8412138057 64.7391801835 67.2625151337 +-35.8331676755 58.7733299475 72.5374371012 +-35.831232029 85.3224914855 37.897166886 +-35.8293369135 76.7313421151 53.1842058656 +-35.8227355321 67.4579524784 64.5457687724 +-35.819753787 -56.2257508954 74.5359656467 +-35.8188155384 75.1970104837 -55.3391549243 +-35.8100165484 80.7338004115 46.9009188174 +-35.7907864568 -56.6592044905 74.2209818805 +-35.7897911523 -56.6138513558 74.2560615973 +-35.7774880207 -28.0228960533 89.0768693192 +-35.7647311966 -54.7167456015 75.6766922719 +-35.7598215513 -54.6883901738 75.6995055652 +-35.7582305162 -11.0006681028 92.7379871015 +-35.7513663496 -54.4884059367 75.8475670184 +-35.7307467299 67.9129789837 64.1181801339 +-35.7268217943 -27.1968416312 89.3528175816 +-35.7109484704 47.2354713397 80.5824944182 +-35.6937405592 75.1708430262 -55.4553986878 +-35.6909352141 74.3927415408 56.4967003425 +-35.6840626194 5.8626761673 93.2323801216 +-35.6812904573 -54.9443690389 75.5510544084 +-35.6707504002 -54.3035276361 76.0179219143 +-35.6702701926 -54.5098864716 75.8703110659 +-35.6631952263 81.8243908579 45.0877540689 +-35.6517927203 -54.3159757683 76.0179219143 +-35.65124048 -54.5223344236 75.8703110659 +-35.6383239311 68.9003935346 63.108205791 +-35.6346309536 81.8368346762 45.0877540689 +-35.6302881367 -54.6150698075 75.8134336198 +-35.6225663218 75.2581077042 -55.3827589908 +-35.618673348 -23.5576095459 90.4231670614 +-35.6134144387 27.9044149539 89.1797529605 +-35.6130087819 68.8514511729 63.1758757508 +-35.6027214033 46.1810356504 81.2388957023 +-35.6016937476 -70.5405474754 61.2907053653 +-35.6011607115 75.2468442369 -55.4118199338 +-35.598270037 52.2242622221 77.4944488704 +-35.5965968028 77.6780613814 51.951911188 +-35.5898907491 -22.6732609816 90.6602609357 +-35.5884463691 -35.6133004684 86.4011302865 +-35.5878829417 48.3585262134 79.9684658487 +-35.5836626848 -55.3209996516 75.3219088147 +-35.5729130455 84.0900213097 40.7852445573 +-35.5728626447 -75.1531011009 55.557023302 +-35.5666036326 71.1178499016 60.640482612 +-35.5569591734 85.0016469945 38.8641565272 +-35.5537850242 48.9355869116 79.6318824597 +-35.5510316498 92.3725826278 -14.2628933706 +-35.5455039044 -55.9675596021 74.8608671094 +-35.5234397951 5.83628680648 93.2953534825 +-35.5091750415 -56.453144183 74.5126901925 +-35.5075422233 63.9782764299 68.161533069 +-35.5057390724 -55.1363806423 75.4938542041 +-35.5023314363 -56.5955656998 74.4078383351 +-35.4982440539 -56.4139167942 74.5475999683 +-35.4860977438 -55.2116674179 75.4480526445 +-35.4856163875 71.1109627106 60.6959801962 +-35.4759178317 0.390093811191 93.4949575154 +-35.4405090778 -71.8030472927 59.9023598516 +-35.4367752627 69.0414022032 63.0675807431 +-35.424670028 79.4531246314 49.3182901134 +-35.4204416845 -55.5347671247 75.2414908896 +-35.4058245062 70.0005216516 62.0189854765 +-35.384034918 66.6880206298 65.5795545685 +-35.3700994633 92.5282067772 -13.6925897678 +-35.35959364 78.4953871781 50.8740929096 +-35.3291900381 -54.0504077325 76.3570674869 +-35.3254354197 73.8290506796 57.4576791052 +-35.3245621681 62.6909984003 69.4407231184 +-35.3221412007 89.1226411114 28.4517342588 +-35.3184797861 89.1134028567 28.4851964518 +-35.3053219679 -54.9514882813 75.7223096347 +-35.2860185541 -68.6591664335 63.5674111417 +-35.2812197487 -54.9983671597 75.6995055652 +-35.2753632757 -57.9494058315 73.4677827999 +-35.2691438735 -61.7832703457 70.2774145499 +-35.2603963733 -20.4973320507 91.3047853423 +-35.255689047 75.5372173819 -55.2373531229 +-35.2519960074 -66.8613598876 65.4740813717 +-35.2498256666 80.6836630979 -47.4088209047 +-35.226215166 -55.3153843201 75.4938542041 +-35.2216452641 82.8563492213 43.5231099372 +-35.2093472936 -41.5909607768 83.8480401967 +-35.20925491 -72.1257604886 59.6505074801 +-35.208975503 71.1773868922 60.7791710969 +-35.1890501616 -76.6473878057 53.7299608347 +-35.1839382248 70.4141135434 61.6761145412 +-35.180587706 78.5368394134 50.9341840379 +-35.1756721329 -76.6535282861 53.7299608347 +-35.1754942234 -63.3278760614 68.936671806 +-35.1704504438 75.1491481498 -55.8179625922 +-35.1686166205 85.0304507008 39.1534271632 +-35.1676361411 85.6623731952 37.7517574003 +-35.1571483547 79.4114401194 49.5761847839 +-35.1553009008 75.0485312063 -55.9626909856 +-35.137845842 51.9960637928 77.8571842519 +-35.1277126482 80.3277153032 48.0988768919 +-35.1269850995 -68.7032742648 63.6078220278 +-35.1243865362 92.7092334998 -13.0872263805 +-35.1236465833 76.9649899571 53.3171620737 +-35.1213711587 -66.8396547098 65.5663774065 +-35.1102857209 -55.3890405586 75.4938542041 +-35.1047667053 -71.8163075828 60.083885691 +-35.1032308709 -55.3779110173 75.5052988457 +-35.099002493 -72.2835427119 59.5243603663 +-35.0955540599 -71.7974606218 60.1117853128 +-35.0768106214 -76.5437961277 53.9505758171 +-35.0672465785 73.7517627828 57.7145190037 +-35.0649127096 -63.3891723954 68.936671806 +-35.0529430324 74.7281384679 -56.4534897583 +-35.0500896597 -76.5560355808 53.9505758171 +-35.0450509714 -71.0330770193 61.0421687982 +-35.0386803801 -51.1727020662 78.445174743 +-35.0150639078 -53.7129995738 76.7389013234 +-34.9816213875 -8.63764049472 93.2827815397 +-34.9626094209 -36.6246544538 86.2336977557 +-34.9226409169 -59.2159573268 72.6214813211 +-34.9222493328 -53.8372408859 76.694119692 +-34.9185891967 40.3111219429 84.591403678 +-34.9177083559 72.9442118917 58.8208772008 +-34.9107344792 -53.8606594577 76.6829184428 +-34.8919314358 -53.8728423213 76.6829184428 +-34.8849787583 85.0583672509 39.3460597474 +-34.8770293697 50.1814687883 79.1543619303 +-34.8743237697 -53.8044846206 76.7389013234 +-34.872396519 92.6782666737 13.951876124 +-34.8670384399 -53.7932447349 76.750090888 +-34.8524645943 -53.7707600478 76.7724630032 +-34.8480195272 55.9421481337 75.2069916777 +-34.8360815437 48.2658978959 80.3545301958 +-34.8288908582 3.6606639388 93.6672189248 +-34.8233682087 -75.6418705314 55.3682259884 +-34.8177778693 -45.9039922407 81.7346061384 +-34.8024296717 -19.6261698798 91.6711751032 +-34.7955742001 -45.1829739944 82.1447921484 +-34.7933470713 83.0946884093 43.4130827946 +-34.7848392403 -75.1778867632 56.0205346355 +-34.7760304746 -72.6808115976 59.2294464767 +-34.7756384514 -59.1553043739 72.7413564262 +-34.731078049 93.7394333323 2.58280004859 +-34.723067917 -47.827302071 80.6650961137 +-34.719610861 86.0637661036 37.2501917543 +-34.712456786 -76.5231862433 54.2148255651 +-34.7046368583 -76.5059473084 54.2441536663 +-34.6876849257 84.4513366118 40.8011796273 +-34.6820993105 -72.4844984145 59.5243603663 +-34.6684057932 -60.4854812838 71.691060765 +-34.6399401706 65.8396967346 66.8222184522 +-34.63207735 93.023448063 -12.1349630774 +-34.6253391047 -58.7118427764 73.1710694857 +-34.6252632364 -34.5407609547 87.2240046001 +-34.6125907863 -55.4994374211 75.6424550435 +-34.6096407316 35.3052028822 86.9236182972 +-34.6055988396 -62.5073165987 69.9663340513 +-34.5849690201 92.8473493723 -13.5369727936 +-34.5689846247 83.9538104411 41.9135182781 +-34.5663882058 93.0456163511 -12.1522872021 +-34.550885215 -18.5881806939 91.9821497322 +-34.5485066786 81.0762507304 47.2550764869 +-34.5369533181 -53.7349244201 76.9399555047 +-34.5308715638 84.6153177849 40.5939269498 +-34.5302115025 69.5606600068 62.9998339126 +-34.511729747 77.3329215556 53.1842058656 +-34.5103966412 68.6162860998 64.0377842023 +-34.4948141453 75.6219973865 55.6005513314 +-34.4910608148 36.8837493437 86.313126222 +-34.4881087618 4.82857433914 93.7403606985 +-34.4575655052 -18.6933607246 91.9958392769 +-34.4567441048 74.5029158527 57.1143442153 +-34.4558736393 20.0699021283 91.7060074385 +-34.4503962123 -50.825678234 78.9298462742 +-34.4388735401 70.3606428874 62.1558036049 +-34.4242121119 81.4142302086 46.7621293358 +-34.4211534985 -65.0926395418 67.6618982095 +-34.4190719771 -67.9318292312 64.8119901063 +-34.4089999457 29.5442053611 89.124411091 +-34.4060293287 -50.8557225193 78.9298462742 +-34.3988770416 -73.1676181605 58.8491028904 +-34.3911254069 -67.7300052119 65.037657455 +-34.384050445 25.7225561235 90.3110579136 +-34.3729965736 -73.145723164 58.8914279787 +-34.3685007589 -55.4955773007 75.7564984384 +-34.3674022825 11.6126710607 93.1881297762 +-34.3665940551 76.2199509874 54.8585115048 +-34.3655205945 -73.2626467094 58.7502816283 +-34.3634146235 -9.99650370769 93.3767939535 +-34.3563365602 16.9650397163 92.36790333 +-34.3499190321 -72.9972936825 59.088731392 +-34.3328848421 45.8937143986 81.9452255907 +-34.3182712494 2.35162031906 93.8974235021 +-34.3166108897 -67.729605037 65.0774217266 +-34.3096586783 -19.2930714641 91.9272794923 +-34.3038205469 -77.0476424337 53.7299608347 +-34.2966786609 26.7955020747 90.0318771402 +-34.2922759395 81.9783244071 45.8649554484 +-34.2871891163 69.6807691511 62.9998339126 +-34.2414945726 81.1795239816 47.301214948 +-34.2335198864 82.3217322556 45.2901591366 +-34.221368455 -74.6770702302 57.0283536751 +-34.1955249838 5.85743411488 93.7888934612 +-34.1807355265 68.5559494661 64.2787609687 +-34.1787682893 -73.6655166596 58.3541211356 +-34.1678737836 -47.4272472263 81.1369990919 +-34.1669348878 -52.4119722842 78.0102924084 +-34.1620399476 -67.6293441896 65.2627522489 +-34.1596920124 80.1638050592 49.0599612724 +-34.146945317 5.65299013954 93.8191335922 +-34.1464906822 68.8479919259 63.9841478951 +-34.1398344472 -78.3292450355 51.951911188 +-34.1385472244 76.6044568467 54.4639035015 +-34.1350059446 93.9381682838 -3.22829810258 +-34.1289612476 -78.3042979458 51.9966434242 +-34.1288169755 -73.0895449629 59.1028110073 +-34.1126604537 5.65954893361 93.8312096407 +-34.0920309907 8.15331339096 93.6549886748 +-34.0759023145 63.8989963179 68.9619543736 +-34.0678408426 -60.7827291086 71.7275544155 +-34.0638086398 71.8028894194 60.6959801962 +-34.0482114145 -58.5006844645 73.609708712 +-34.0236269003 -55.5215129595 75.8930458688 +-34.0042441637 -55.5333860629 75.8930458688 +-33.9950609552 -64.8885723089 68.0720868959 +-33.9898108145 -74.343004313 57.6004381105 +-33.9687161299 74.8141913729 56.9996762596 +-33.9633621501 4.30261561435 93.9573175987 +-33.956915315 -59.7749809956 72.6214813211 +-33.9519933206 68.7570514962 64.1851230356 +-33.939878836 58.9042464458 73.3374009306 +-33.9160421662 81.7594601322 46.5305573002 +-33.9098992036 72.2257390786 60.2790291109 +-33.8859090395 -35.7707631965 -87.018375467 +-33.8810760389 85.7924918411 38.622804535 +-33.8637944975 -88.4488293618 32.0943609807 +-33.8580343661 -23.9994499208 90.9816460192 +-33.8538472595 71.3603131377 61.3320693815 +-33.8370780056 -24.0289874876 90.9816460192 +-33.8338078173 -35.7782486161 87.035569594 +-33.8285099375 -48.6185072307 80.5721581569 +-33.8204975145 -55.8003114326 75.7792794364 +-33.8105728203 -60.2497321564 72.296714591 +-33.8092644835 -37.8534745281 86.1629160442 +-33.8087138611 6.77405860069 93.8673691819 +-33.808523593 39.3476894657 85.4911870673 +-33.8052379809 13.1597246881 93.1881297762 +-33.7928833991 86.6742639159 36.6825981389 +-33.7830899459 -23.8578493054 91.0467235008 +-33.779752585 -69.3508942602 63.6347529312 +-33.7654669536 -36.5272763603 86.7505119472 +-33.752714472 -36.5390605061 86.7505119472 +-33.7416167506 78.0844222994 52.5768608156 +-33.7397451835 -32.3778679806 88.3928914562 +-33.7321797991 79.9330814469 49.727683803 +-33.714975161 67.2392909344 65.8952062334 +-33.713051134 -82.2009124437 45.8959712465 +-33.7118619089 -61.195090668 71.5448897181 +-33.70583622 -61.1841526018 71.5570826341 +-33.6830526383 -40.0992406271 85.1909787835 +-33.6803358434 75.7539962283 55.9192903471 +-33.6620521088 -40.1168715347 85.1909787835 +-33.6542462823 94.1479637081 1.88484397154 +-33.6537958927 30.3552340667 89.1402366318 +-33.6485121023 5.34746254299 94.016925485 +-33.6451808773 33.0284161755 88.1880123865 +-33.6395430711 -60.3887151908 72.2605301639 +-33.6372514279 83.6752912944 43.2085748802 +-33.6295916232 85.0687610943 40.4024312775 +-33.6248991537 25.1546383988 90.755772951 +-33.6136639085 70.251501977 62.7283673359 +-33.5574412948 -19.2185278377 92.220097167 +-33.530099507 82.1630007197 46.0974374535 +-33.5240601819 -84.2422431903 42.1827198174 +-33.5127080524 -53.7776322422 77.3619070953 +-33.507766611 -54.5087218581 76.8506917219 +-33.5007418785 -54.4972943824 76.8618578918 +-33.4615823977 84.6437682241 41.4216731225 +-33.4594781878 54.1755120368 77.1069206683 +-33.4559733237 48.1906595174 80.9836908534 +-33.4510686892 87.9218548566 33.9230517808 +-33.4147811279 -59.0123527791 73.491459515 +-33.4049117047 31.3144869899 88.9017141486 +-33.4024817502 -84.6671081864 41.4216731225 +-33.3610698323 -82.6961835058 45.2590350452 +-33.3491490904 80.9913328813 48.2518212408 +-33.343634734 31.3117571863 88.9256761832 +-33.3350129283 80.9971521723 48.2518212408 +-33.331399371 73.5810465406 58.9478363128 +-33.3250977342 -61.6334789178 71.3495069184 +-33.3211214873 -19.1450205801 92.3210217113 +-33.3173740966 85.4546456223 39.8428930284 +-33.3142924059 76.7274652491 54.8001277184 +-33.3125250652 -19.0628238398 92.3411307113 +-33.2850013125 84.1541291802 42.5463421407 +-33.2778508796 -45.8871887391 82.3829506054 +-33.2713459494 -59.2403781055 73.3729864503 +-33.2159993586 94.3219425576 -0.261799088742 +-33.1994208595 49.4059503665 80.3545301958 +-33.1951657618 83.7133297457 43.4759633927 +-33.1932253146 -26.7166655768 90.4678372333 +-33.1931152261 83.8362391358 43.2400521409 +-33.1759457457 10.5877948596 93.7403606985 +-33.1542062614 -24.0261087814 91.233462633 +-33.1425074943 -74.6144600406 57.7430216549 +-33.1341885304 -10.1174922846 93.8070461122 +-33.1314097686 88.7556241788 32.0116988518 +-33.0901344276 -28.6332608666 89.9176255008 +-33.0883596674 72.6057787229 60.2790291109 +-33.0866289446 -62.7013142146 70.5253158862 +-33.0539890543 79.4071085748 51.0092630351 +-33.0508803546 83.3919362794 44.1975595633 +-33.0391566113 86.3852504759 38.0263412733 +-33.0356694378 94.3350635826 3.08874143851 +-33.0340273586 -62.1279695103 71.0553899503 +-33.0302706552 66.3354324554 67.1461958818 +-33.0204105414 88.4582687158 32.9361075947 +-33.0196202859 80.0322985289 50.0453381281 +-33.0017260354 -55.9811191874 76.0065811178 +-33.0013862912 51.7619188491 78.9405615633 +-32.9992376681 63.1217198433 70.1904466245 +-32.9755860183 -10.1320161823 93.861349739 +-32.9750113553 85.9925490644 38.9606228328 +-32.9722161251 75.2912565521 56.9566471151 +-32.9509094231 80.3426189359 49.5913414893 +-32.9470764859 -61.1126825301 71.9703423989 +-32.9334453096 -78.269080283 52.814195551 +-32.9242362076 -54.1082985156 77.3840209727 +-32.9213388822 -37.6322394524 86.6025403784 +-32.919993756 -68.128620539 65.3816876087 +-32.8801443496 80.6507970093 49.1359852787 +-32.8720391947 -72.0644341378 61.0421687982 +-32.8520497603 -61.0639319166 72.055111168 +-32.8491384513 -36.4187012449 87.1470728289 +-32.8464811042 88.0861656834 34.0871837244 +-32.8456559697 -68.1264764734 65.4212968936 +-32.8430149183 48.7468091181 80.9016994375 +-32.8403022769 79.010338577 51.7579070704 +-32.8071924471 -17.6427013089 92.803142265 +-32.8022588469 71.3172256734 61.950505541 +-32.7999862596 -19.1437330561 92.5077206834 +-32.7959073981 -77.7523348309 53.6563405971 +-32.7850692039 68.7353269851 64.8119901063 +-32.7773624409 71.3286714766 61.950505541 +-32.7771927707 12.3331963804 -93.6672189248 +-32.7754819 -53.4847254349 77.879085327 +-32.746659218 81.1731684117 48.3587948575 +-32.7461917665 -48.0942243132 81.3303910756 +-32.7246536559 -83.7184541805 43.8214270959 +-32.7201032786 -39.2301016249 85.9674006117 +-32.719528527 -66.7888674081 66.8481835454 +-32.7106750454 -57.7453542512 74.8029798903 +-32.6974004383 76.2152653152 55.875874378 +-32.6789228557 -22.6532827241 91.754655374 +-32.6719529568 88.0874450645 34.2512118325 +-32.6686964945 -64.0606367322 69.4909425092 +-32.668419421 -57.694236698 74.8608671094 +-32.6644570396 79.9221622229 50.4527623815 +-32.6633252908 87.7352840561 35.1514880558 +-32.6385197029 -0.22786355466 94.5234103797 +-32.6321372097 78.1245098805 53.2137630417 +-32.6229291739 79.149158907 51.683219099 +-32.6221448534 -20.0065429105 92.3879532511 +-32.5847220159 79.9261637348 50.4979627488 +-32.5783507958 -0.8644740308 94.5404873273 +-32.5744752639 81.6485671107 47.6698547309 +-32.5700766532 93.7919810367 -11.9270448985 +-32.5647897541 71.7221223014 61.6073992379 +-32.5572463017 -51.9611159736 78.9941019319 +-32.5451209326 82.7476342471 45.7563561703 +-32.5451108913 -77.8779390142 53.6268810577 +-32.5295709624 36.1531193055 87.3772223035 +-32.5294681254 -70.2391767902 63.3110712854 +-32.5166926643 78.0011961945 53.464736887 +-32.5090558478 82.5290462179 46.1748613235 +-32.5010323 81.9628271637 47.1781502685 +-32.4937995834 87.3731940174 36.1949990445 +-32.4876933738 -67.263931667 66.4839324646 +-32.4829750958 74.7057281861 57.9992284871 +-32.4812858497 46.9614521576 82.0949942494 +-32.4601685043 56.6786492804 75.7223096347 +-32.4357949606 -77.4643000006 54.2881334243 +-32.4345792473 89.1132740914 31.7304656405 +-32.4323659389 -64.6813256911 69.0251240234 +-32.4106946984 56.706954536 75.7223096347 +-32.3891290733 -92.9044778069 17.8802215116 +-32.3717719558 87.4184787366 36.1949990445 +-32.3686715876 40.6929972727 85.4186693447 +-32.3561085781 -77.4256710632 54.3906949587 +-32.3307283271 -50.7100071867 79.8950510167 +-32.3293897604 81.2401689895 48.5267503577 +-32.3244051058 87.9973143859 34.8081239861 +-32.2947699972 81.2357033849 48.5572685227 +-32.2936716376 93.6813893038 -13.4505044618 +-32.2866208274 59.1686997739 73.8690671568 +-32.2688243221 -49.7846918389 80.499735623 +-32.2166855503 -57.1054727532 75.5052988457 +-32.2060048296 -18.9102655637 92.7640830776 +-32.2002547772 92.3627136917 20.7911690818 +-32.191734331 77.4118274497 54.507808722 +-32.1748520691 -38.1142579888 86.6722691078 +-32.173736955 92.28665038 21.1665966084 +-32.1623073274 -28.7362262507 90.2209248913 +-32.1618284032 91.9426380679 22.6311311886 +-32.1389329878 88.8797461518 32.6723080054 +-32.1068890514 37.9933724792 86.7505119472 +-32.0988721384 -54.6019752898 77.3840209727 +-32.0986199044 -56.5037894925 76.0065811178 +-32.0909914154 80.0305855264 50.6485305836 +-32.090928104 32.4854073964 88.9655587276 +-32.0822423678 -56.3603837546 76.1198848376 +-32.0764443073 -65.0732235499 68.8227963499 +-32.0675171374 15.3297861307 93.4701663732 +-32.0515084018 66.6576505419 67.301251351 +-32.05028606 -72.2234629417 61.2907053653 +-32.0270962713 -33.90324597 88.4580975215 +-32.0146892152 -46.2350829081 82.6884319778 +-32.0112397922 -64.9981459564 68.9240273721 +-32.0027993724 45.9090798719 82.8744666206 +-31.9996878929 -18.9094890487 92.8356138488 +-31.9989793535 -60.4866020619 72.9207535023 +-31.9952859832 -33.8695722328 88.4825053421 +-31.9933768488 86.1656634425 39.3941909591 +-31.9834613231 -33.8807386309 88.4825053421 +-31.9800506868 23.8980289109 91.6851164162 +-31.9734860088 91.7122536575 23.8024940184 +-31.9729404855 85.4245991502 40.9923033842 +-31.9712724889 89.2923011414 31.6973609677 +-31.9673165142 -79.802785934 51.0843031866 +-31.9620381122 33.6456609768 88.579893978 +-31.9573569361 -66.402483012 67.59761525 +-31.9493033774 88.1147961012 34.8572047322 +-31.9396232049 -73.1069090245 60.2929541689 +-31.93164644 69.8413575165 64.0511884034 +-31.9046467697 -10.5205747286 94.1881681629 +-31.9039798485 49.3160443038 80.9324647101 +-31.8947472383 50.2580797049 80.3545301958 +-31.8917718997 -30.9376733735 89.5866912623 +-31.8852281797 -65.7526324739 68.26363268 +-31.871187494 55.0470928464 77.1624583388 +-31.8578272322 68.6945923669 65.3156323064 +-31.8415310784 -73.1955699739 60.2372429215 +-31.828680546 -49.6163531576 80.7784166349 +-31.820020374 -49.6219075545 80.7784166349 +-31.8075883213 92.6384845891 20.159079796 +-31.801512259 -68.2918966844 65.7638248986 +-31.7898929042 -34.6925803745 88.2373366331 +-31.7793160199 -77.1788556143 55.0772123421 +-31.7766174586 62.4459321765 71.3495069184 +-31.7665432604 -85.6005289452 40.7852445573 +-31.758462504 82.9499136907 45.942484457 +-31.7461049036 34.5236297248 88.3193286551 +-31.7406074922 -66.5455674689 67.5590207616 +-31.7389969734 -77.0809372744 55.2373531229 +-31.736506263 89.5218063763 31.2832279878 +-31.7302875404 84.6412623749 42.7673421689 +-31.7089101048 -52.7724884951 78.8010753607 +-31.7059147694 -34.685916654 88.2701657102 +-31.685956021 74.214888296 59.060566762 +-31.6766665941 91.7355816678 24.1075060833 +-31.6552932414 -49.7271537065 80.7784166349 +-31.6521408039 -85.5668550698 40.9445392696 +-31.6476476605 23.0524891536 -92.0163525759 +-31.6393760557 64.6696870747 69.4030363635 +-31.6321409368 21.1918664696 -92.4678995938 +-31.6313407783 -77.1251781232 55.2373531229 +-31.629724833 76.4741413378 56.1361399958 +-31.6281812952 9.9844664661 94.3396447807 +-31.6242336775 88.4689907952 34.2512118325 +-31.6098066264 86.9889209659 37.8648617352 +-31.6002954646 -18.6288575273 93.0289578238 +-31.5907714926 81.0261389452 49.3638325511 +-31.5873060768 72.4037998646 61.3182832438 +-31.5861502396 88.8022929378 33.4135882844 +-31.572000361 91.5360223511 24.9873048837 +-31.5679198043 -56.0697863187 76.5483213493 +-31.5674817392 89.54094858 31.3992455967 +-31.5488573344 82.3163835125 47.2089250705 +-31.5446675241 43.2585367039 84.4608368004 +-31.5356595197 -82.497309003 46.9009188174 +-31.5208925833 30.5778895651 89.8411153119 +-31.509440993 86.1968135023 39.7147890635 +-31.4926333656 -82.5575144519 46.8238278148 +-31.4800795139 87.8238440017 35.999680812 +-31.4680143934 83.5863820767 44.9786705168 +-31.4568774088 94.6731861716 6.88859084345 +-31.4557099205 -64.0957918051 70.0161965996 +-31.450379327 80.046218431 51.0242741749 +-31.4404955782 89.0320619457 32.9361075947 +-31.4259210582 91.4229779185 25.5783227395 +-31.4194104644 -18.4557792959 93.1246737264 +-31.4052443088 -86.6143047343 38.8802372073 +-31.4041378279 -86.5641040516 38.9927687788 +-31.3882121825 -76.0404783972 56.8561850734 +-31.3874188314 -81.5542279628 48.6182870995 +-31.3816424752 87.5011392757 36.861133203 +-31.3673688882 76.0276044725 56.8848971802 +-31.3580793723 84.771903725 42.78311813 +-31.3541615848 81.2562090059 49.1359852787 +-31.3410008556 -61.4571343846 72.3931094691 +-31.32537796 -82.5948888763 46.8700866991 +-31.3199045422 75.8749976232 57.1143442153 +-31.2901582615 -77.3680934456 55.0917789925 +-31.2803339141 -59.7067971642 73.8690671568 +-31.2670431455 -77.1172533829 55.4553986878 +-31.2480656563 -81.6168083979 48.6030346756 +-31.2431531649 -73.53288079 60.13967761 +-31.2344518488 -60.9849679842 72.8370969882 +-31.2342395683 80.1116818466 51.0542917912 +-31.233661493 50.8690061874 80.2296865209 +-31.230019316 -38.8145576471 86.7070701164 +-31.2282658121 44.7646692474 83.7909291125 +-31.223598883 -59.6491457393 73.9396124237 +-31.2214243183 -57.670621992 75.4938542041 +-31.2087404571 -55.8414659594 76.8618578918 +-31.1911128952 -51.0591593432 80.1253812691 +-31.1884217059 -77.3884224837 55.1209072583 +-31.1845757407 78.4829702349 53.5532036295 +-31.1734820299 -63.6329938625 70.5624270432 +-31.1665235569 -11.3436868803 94.3396447807 +-31.1507836404 73.4579289664 60.2790291109 +-31.1492561821 -59.7607458891 73.8808303288 +-31.1467070463 47.6515938679 82.2144041031 +-31.146494555 -16.4703456115 93.5875183578 +-31.1352202975 76.6768012074 56.1361399958 +-31.13222888 94.3007631303 -11.7537397458 +-31.1223664635 -77.9297799793 54.3906949587 +-31.1134323704 -47.6733267573 82.2144041031 +-31.1093492208 49.9209774117 80.8709119852 +-31.0867059274 -77.2526780473 55.3682259884 +-31.0775701544 91.3943240459 26.1009993198 +-31.0769646052 -77.6193660526 54.8585115048 +-31.0763903096 -34.8181536819 88.4418121677 +-31.0648652509 91.9356722795 24.1413816807 +-31.0604561631 94.1937971975 -12.7583945876 +-31.0599335127 82.7212770632 46.8238278148 +-31.0598403781 82.7649215969 46.7467011537 +-31.0354030178 71.3084607465 62.8641963719 +-31.0342591064 -72.7588022429 61.1803192039 +-31.0314238742 91.9425167459 24.1583183765 +-31.0312532397 75.2874636321 58.0418740413 +-31.0254087263 -86.5553930657 39.3139662794 +-30.9808847687 -55.7532237885 77.017938275 +-30.9772658238 -55.2460161477 77.3840209727 +-30.9710170722 55.7125616767 77.0513242776 +-30.9549494731 -58.5131072446 74.9533680611 +-30.937865164 78.540346295 53.6121488374 +-30.9132524471 92.8204751082 20.7058016949 +-30.9071772205 91.3113216839 26.5892634084 +-30.9004105064 -59.817207768 73.9396124237 +-30.9001044431 79.7891132993 51.7579070704 +-30.8997261063 91.2893083151 26.6733783743 +-30.8888612001 54.3300627711 78.0648610647 +-30.8839168382 -77.4897283724 55.1500288078 +-30.8710462047 92.9100580032 20.364175114 +-30.870115318 -77.6915601416 54.8731032748 +-30.8665783825 -77.6826586512 54.8876933733 +-30.8584531059 -69.2116685524 65.2495272634 +-30.8423977035 -59.4248414188 74.2794367659 +-30.8200085221 -75.5598200029 57.8000058462 +-30.8195515785 86.312931442 40.0029137237 +-30.795035935 -76.9930825096 55.8903480703 +-30.7916687142 -73.00069813 61.0145163901 +-30.7830636989 -73.0158826988 61.000687398 +-30.7537166891 24.5679505646 -91.9272794923 +-30.7513990236 -37.6378325329 87.3941932872 +-30.7379718837 -21.0703770296 92.7966394667 +-30.7141441373 -60.0723991111 73.8102175512 +-30.7035837286 4.74219205664 -95.0515731628 +-30.6818842008 -66.4930943355 68.0976533192 +-30.6663115008 -78.1307592145 54.3613999406 +-30.6606960186 56.753112523 76.4133884775 +-30.6569042389 -78.5498657256 53.7593974759 +-30.6418125337 82.3933509125 47.6698547309 +-30.6380416958 -72.1087098911 62.1421303053 +-30.6373901136 -75.2623098234 58.2832312683 +-30.634600515 83.3971286953 45.8959712465 +-30.6337999341 -72.0987266172 62.1558036049 +-30.621036463 -62.4225618986 71.8733322724 +-30.6159213664 -79.840491695 51.8474806022 +-30.5961242448 89.772793701 31.6973609677 +-30.5763214994 -76.5624943663 56.597464784 +-30.5758937346 -78.9519483311 53.2137630417 +-30.5730644704 88.1901709936 35.8856721967 +-30.567581866 70.0330556057 64.5057676599 +-30.5607426495 -67.1215091566 67.5332808121 +-30.5592718573 72.982721892 61.1527040186 +-30.5454483112 -12.1863981898 94.4376370237 +-30.5352049224 41.5686443013 85.6717518865 +-30.5281601284 40.2631243252 86.2954938496 +-30.5219115025 -74.9786307316 58.7079028057 +-30.5076039238 80.8640552764 50.301994663 +-30.5040624971 93.3272965589 18.9609569425 +-30.4918122545 21.1135317931 92.8680147341 +-30.4578412584 -40.3163446649 86.2954938496 +-30.4541953571 92.4637638511 22.8690699339 +-30.4531763489 -57.9310330047 75.6081970773 +-30.4513213181 95.1299007769 -4.79781285213 +-30.4497338043 -76.2069023719 57.1429938149 +-30.4491125207 87.9317905359 36.6176427403 +-30.4228723105 -18.4102348411 93.463961469 +-30.4134881881 -68.6319370209 66.0657018202 +-30.4098062411 86.2572098547 40.4343595529 +-30.4055180472 63.9762278456 70.5871570679 +-30.4033401069 -66.8686188811 67.8544377272 +-30.3991687908 91.3832727591 26.9256011385 +-30.3952992284 20.3325180654 93.0737046321 +-30.385008539 42.8349760784 85.0994481795 +-30.3841680591 76.4685650117 56.8274660389 +-30.3733284019 -79.7486385561 52.1307545528 +-30.3718918718 84.4536603647 44.1035988909 +-30.361392719 -75.8321182671 57.6860093202 +-30.3530351187 -70.3100014831 64.3054970475 +-30.3462621476 25.4454915205 -91.8239148313 +-30.3407448249 -34.5604680441 88.7975971074 +-30.333478873 65.1988417738 69.4909425092 +-30.3247965343 -59.9808592921 74.0452782677 +-30.3182401302 83.2986801553 46.2831956524 +-30.3098196388 72.9941433201 61.2631200187 +-30.3031493795 55.6954972729 77.3287186058 +-30.292902717 70.2380775706 64.4123629761 +-30.2923510764 80.1663809828 51.5337251359 +-30.2921422985 52.4041432959 79.6002002535 +-30.2906673933 -70.1655324095 64.4924300253 +-30.2775693161 92.7439562769 21.9505665171 +-30.2738779717 67.996243213 66.7832555471 +-30.2703052005 -83.393341975 46.1438959919 +-30.2684392176 72.2881452099 62.1147780278 +-30.2613344992 85.9317169276 41.2309551211 +-30.2548624638 -79.1053446913 53.1694248471 +-30.2528906937 50.6090135734 80.7681270663 +-30.2459195133 -78.9993033451 53.3319268711 +-30.2437392019 38.8218290915 87.052753116 +-30.2417147088 -57.7733673439 75.8134336198 +-30.2339304349 -65.0442273603 69.6789633789 +-30.2233144385 34.5603094481 88.8376962511 +-30.221158006 -79.0585720553 53.2580866475 +-30.2082883928 -64.989061962 69.7415309387 +-30.2077012135 56.6930148672 76.6380900901 +-30.200472307 25.4942842959 -91.8584396813 +-30.1998924352 -76.0047941263 57.5433555394 +-30.196693528 33.4193429102 89.2821775016 +-30.1950636564 37.3810858003 87.6978480647 +-30.1835642017 55.4065820417 77.5826212405 +-30.1811070334 42.4689432756 85.3550797275 +-30.1756004906 -41.8857103528 85.6447336576 +-30.1712854812 89.548746492 32.7217898979 +-30.1692698425 -79.0883347896 53.243313734 +-30.1552944697 94.660118592 -11.4070225565 +-30.1449175773 37.0272459835 87.8650499296 +-30.1416176742 42.4604422619 85.3732611941 +-30.1201315231 -83.5246386952 46.0044824759 +-30.0993668983 83.9719004476 45.196770322 +-30.0987133605 91.2772203761 27.6140633457 +-30.0962134341 71.9473141029 62.5923472184 +-30.0860150222 -76.9681077941 56.3093427655 +-30.0855841401 82.0795303383 48.5572685227 +-30.0838265925 92.3143082427 23.9380841177 +-30.0827775974 66.1635788363 68.6833846544 +-30.0734379925 -77.015204889 56.2516359159 +-30.065056734 29.135066877 90.8143173825 +-30.0634209828 79.2675165321 53.0363228518 +-30.0400409642 81.7785484448 49.0903753615 +-30.0245994339 -41.1438273918 86.0564285593 +-30.0231274335 -53.5443700046 78.9405615633 +-30.0192590816 94.6326948745 -11.9790293837 +-30.0190475084 91.3034516994 27.6140633457 +-30.0160350439 91.2942892363 27.6476109834 +-30.0159970802 92.2701353829 24.19218956 +-29.9918212723 14.4663372746 94.2932433562 +-29.9863946178 92.2886330544 24.1583183765 +-29.9849594251 94.6391758619 -12.0136838835 +-29.9840948709 -41.0431740792 86.1185921638 +-29.9697212258 92.127881926 24.7844544316 +-29.9614625302 5.16447329446 -95.2661481254 +-29.9590251524 93.3114377694 19.8854819736 +-29.9567724328 87.8968568058 37.1043710237 +-29.9535463141 35.9896639945 88.3602237931 +-29.9338136528 35.9659548871 88.3765630089 +-29.9273853716 57.5635411397 76.0972426325 +-29.9260837024 -62.9391138909 71.7153920498 +-29.9152145706 -79.4617837574 52.8290153162 +-29.8851211735 83.5577991133 46.0974374535 +-29.8648653876 91.4797928725 27.1944353017 +-29.8630748434 85.5147135048 42.3725209904 +-29.8501969036 -66.1108578528 68.8354575694 +-29.8491053269 78.5783243669 54.1708210283 +-29.8341546794 81.0868579324 50.3472410885 +-29.8317120048 -73.283120499 61.1527040186 +-29.8297965507 -56.5294049633 76.9064991547 +-29.817225085 62.879879873 71.8126297763 +-29.8121584187 82.6706137965 47.715876026 +-29.8072979995 74.0359445096 60.2511734868 +-29.796298765 58.9355183844 75.0918454472 +-29.7954939752 36.0806270665 88.3765630089 +-29.7947240989 36.0412424299 88.3928914562 +-29.7869058027 -57.711072746 76.04059656 +-29.7817259851 -40.3507000213 86.515142057 +-29.7773813627 -76.7706723468 56.7412674039 +-29.7711320785 -70.3753197746 64.5057676599 +-29.7643859022 80.5932525104 51.1743000114 +-29.757807826 -55.4980770588 77.6816343556 +-29.7551449727 -59.4974419214 74.6638182285 +-29.73843353 -55.508461112 77.6816343556 +-29.7330474689 77.3361804144 55.9916162217 +-29.7306153734 -79.8152755616 52.398590597 +-29.7103771013 77.8853536454 55.2373531229 +-29.7006395765 -71.4214637334 63.3785967573 +-29.693380556 -67.4194910011 67.623334614 +-29.6598922675 82.928066626 47.3627127217 +-29.6266860602 -16.4223402477 94.0880768954 +-29.6230632432 54.6270856167 78.3476588107 +-29.6165857607 57.4548762563 76.3006883472 +-29.6144912476 87.8961743567 37.3797330327 +-29.6099601724 -18.0172977078 93.8009980858 +-29.6046362551 -71.4014090254 63.4460739636 +-29.5976190518 -79.8841900038 52.3688565266 +-29.5948340737 -83.8988464513 -45.6632167098 +-29.5922304551 -16.4167473139 94.099895347 +-29.5854932953 -47.3834832286 82.9427760785 +-29.5802586769 -42.7990715342 85.4005138885 +-29.5729787056 92.1090438728 25.3251449612 +-29.5682187234 -48.0061137988 82.5901536471 +-29.5633692253 -69.3774454 65.6717387452 +-29.5602411268 69.4036903719 65.6454104053 +-29.5530978671 -47.9815640092 82.6098294496 +-29.5512601266 -69.3826041246 65.6717387452 +-29.5460498984 -72.3282050133 62.4152360803 +-29.527690956 55.6975633692 77.626650717 +-29.4895995819 92.5146105821 23.9041909578 +-29.4642623892 -12.6405751128 94.7210277746 +-29.4576029013 -85.1646137508 43.3501810375 +-29.4356715335 18.7309303957 93.7160257794 +-29.4302713338 -85.2300241703 43.2400521409 +-29.4233574446 92.4741030086 24.1413816807 +-29.4205844002 -60.8594019116 73.6923497556 +-29.4199378116 -16.3547567875 94.1646918414 +-29.4063835383 61.2934762592 73.3374009306 +-29.3966463718 69.6594332978 65.44769312 +-29.389968025 -12.6877359236 94.7378020466 +-29.3855373792 -12.6979941845 94.7378020466 +-29.371700211 76.4361353518 57.4005264714 +-29.3715395882 -13.8525173902 94.5802327348 +-29.3601238072 43.9903751912 84.8694881602 +-29.3576406773 93.6803453236 19.0294990453 +-29.3259635814 -68.2580289268 66.9389972068 +-29.3238386979 51.3476726493 80.6444604267 +-29.3103741036 52.4017789747 79.9684658487 +-29.2935644867 -60.9491793544 73.6687492475 +-29.2820345122 -67.8942467385 67.3270652459 +-29.2768524934 -85.1226670553 43.5545343388 +-29.2732086347 82.7567853222 47.8998302645 +-29.2657331695 -43.0147543249 85.4005138885 +-29.2504473072 -65.0244816717 70.1158192968 +-29.2415111263 -45.5133806014 84.1039012964 +-29.2320993675 -74.4003430559 60.083885691 +-29.226162744 -58.6186138275 75.5624875464 +-29.1937138291 53.1031683182 79.5473480855 +-29.1904127335 -14.7131792541 94.506307518 +-29.1558657588 -24.6124604606 92.4346378904 +-29.1208717188 64.9484056544 70.240155419 +-29.1145719443 78.1614357256 55.1645870628 +-29.0791964904 -13.4241593889 94.7322135083 +-29.077839712 93.8193771948 18.7724186097 +-29.0590258709 69.1286908397 66.1573663187 +-29.0554987548 -81.2382025822 50.5582083675 +-29.0546405393 91.4257123604 28.2341456843 +-29.0406294294 -17.0516652889 94.1588155895 +-29.0325445526 70.6832179192 64.5057676599 +-29.0264544601 93.9434248575 18.2235525492 +-28.9968898431 50.4271369776 81.3405448449 +-28.9879932658 -76.5931876901 57.3862339406 +-28.9845771168 -44.8033347567 84.5727821704 +-28.9703764045 91.4369270424 28.284371374 +-28.9498195825 -34.4643875962 89.2978943411 +-28.9433023395 48.8042690375 82.3433577977 +-28.931350709 -70.5419220898 64.7055961569 +-28.9311251834 72.2232780728 62.8234677493 +-28.9241915381 78.9536603842 54.1268016402 +-28.9237428097 94.0180953665 18.0004123711 +-28.9222924928 38.6612263291 87.5717453046 +-28.9214411848 95.0127866702 -11.6670737099 +-28.8974358081 95.112660773 -10.8866874852 +-28.8946064124 94.0401754277 17.9317351584 +-28.8913009854 -60.9272502775 73.8455340626 +-28.8903451233 -46.6862774858 83.5807361368 +-28.8840056272 25.3484352399 -92.3210217113 +-28.880468995 95.0568164154 -11.4070225565 +-28.8793478462 -16.7407724043 94.2641491092 +-28.8745110875 94.0332269144 18.0004123711 +-28.8735024549 -16.7508521783 94.2641491092 +-28.8728844616 -17.7141279488 94.0880768954 +-28.872615707 82.0796741472 49.2879209759 +-28.8631282593 95.1190998506 -10.9213859333 +-28.8593956209 87.673194874 38.4778661699 +-28.8558032129 95.1547271152 -10.6264071336 +-28.829915554 93.3073313939 21.5076237017 +-28.8198871937 95.1558824998 -10.7131754314 +-28.7923244386 81.3973022987 50.4527623815 +-28.7915416908 57.3203578624 76.7165151815 +-28.7850417156 95.1605545523 -10.7652324982 +-28.7839858292 81.4189255601 50.4226211181 +-28.7814034395 91.449885102 28.435001862 +-28.7746386179 81.1220595332 50.904141575 +-28.7613701479 46.9710858571 83.4655658378 +-28.7596231483 -17.7415095026 94.1176015256 +-28.7350659146 68.0254282447 67.4302387584 +-28.7171293118 26.9671794115 91.9135339255 +-28.7170401514 55.0007538039 78.4235212544 +-28.7066417727 -69.47538587 65.9477025858 +-28.7011991793 88.4908365847 36.6825981389 +-28.6952695325 88.4725544424 36.7313029567 +-28.6747535068 5.26280209107 -95.6559534241 +-28.6745938116 80.3943860293 52.1009631841 +-28.6672432282 93.9422245362 18.7895613278 +-28.6629555855 -17.4273501595 94.2057452787 +-28.6415987214 74.8872529855 59.7625146976 +-28.6343700929 95.1415953898 -11.3203213768 +-28.633267603 91.480760652 28.4851964518 +-28.6111215063 -80.3493638967 52.2052051767 +-28.6105561632 -70.6360756381 64.7455086819 +-28.6080645944 -17.5173113416 94.2057452787 +-28.6039113473 95.2210277607 -10.7131754314 +-28.5978184223 80.7577479428 51.5785898285 +-28.5929256051 89.4317787288 34.4151356056 +-28.5853981343 -61.6382987506 73.3729864503 +-28.5773163798 89.4367677736 34.4151356056 +-28.5710691045 85.2415726796 43.7900479257 +-28.5682097554 93.6176929911 20.4837728554 +-28.5652529896 -64.5219531002 70.8586190225 +-28.5630125603 -85.5643164861 43.1613491188 +-28.5604670216 74.016180319 60.8761429009 +-28.5576952799 -64.444102294 70.9324729572 +-28.5492786385 52.1031387064 80.437563527 +-28.5302380819 84.4345081546 45.3523907604 +-28.5083057457 87.0668671896 40.0828784059 +-28.4891589245 95.2612641193 -10.6611154275 +-28.4832418765 95.2414788573 -10.8519877105 +-28.4712613212 54.2297615347 79.0475821431 +-28.4683103572 -69.5858194355 65.93458151 +-28.4616298451 57.0353316255 77.0513242776 +-28.453330113 95.3232503568 -10.1924455795 +-28.4527242121 -69.6170530985 65.9083333334 +-28.4341903981 -51.5722513158 80.8195502996 +-28.4252208516 -37.4217138174 88.2701657102 +-28.4078350264 93.9727251664 19.0294990453 +-28.40408286 -47.7809201359 83.1275631055 +-28.3970468295 -53.2500291275 79.7373320929 +-28.3953210977 -18.5601503733 94.0703277228 +-28.3811850807 -42.0768372408 86.1629160442 +-28.3732533969 68.4315204454 67.1720589323 +-28.3659745779 -55.7194335871 78.0430407338 +-28.3533977375 33.4331790308 89.8794046299 +-28.3497872918 34.4155112476 89.5090059495 +-28.342881687 93.8761532192 19.5946144243 +-28.329311485 -70.223345742 65.3156323064 +-28.3271537342 -53.2083988847 79.7899658444 +-28.3133726928 78.0020801177 55.8034803938 +-28.311700596 -77.6592154415 56.2804927695 +-28.309133495 -53.1074964734 79.8635510047 +-28.3090579446 -70.2438025557 65.3024152754 +-28.3070982721 -52.5061065976 80.2609304542 +-28.3047971877 -70.2332302588 65.3156323064 +-28.3016647702 77.4216629406 56.6118528114 +-28.3011062322 -79.1289463243 54.200159037 +-28.2996836461 94.0295540771 18.909544299 +-28.2932295494 -48.6516909063 82.6589749127 +-28.2916594824 -63.0990100311 72.236396206 +-28.2871932922 91.4942042607 28.7861995122 +-28.2702974138 -66.7625726796 68.8734286451 +-28.2643135343 -77.6555632119 56.3093427655 +-28.2575411471 -70.9359790482 64.5724263505 +-28.2416271849 94.7346548155 15.091576158 +-28.2296592936 26.1226532697 92.3076016497 +-28.2246084931 -27.0664264158 92.0368406481 +-28.2225047398 -79.1268729272 54.2441536663 +-28.2103086426 -69.7528525408 65.8689460119 +-28.2080897734 94.0224597858 19.0808995377 +-28.2057901525 -18.6690052441 94.1058002733 +-28.1887985047 82.9463878351 48.2212441148 +-28.1878234894 -58.3612942666 76.1538307537 +-28.187620935 39.7813530063 87.3092319232 +-28.1838076751 -69.8626675675 65.7638248986 +-28.1762605087 -58.3373537691 76.1764497661 +-28.1759124701 94.0941775883 18.7724186097 +-28.1610458479 -67.3541645818 68.3401200631 +-28.153888563 -67.3700828319 68.3273773681 +-28.1498378821 86.3797297608 41.7867073801 +-28.1460853196 91.4902801891 28.9365946873 +-28.1421477628 -67.607167754 68.0976533192 +-28.1359617983 -51.9280097821 80.6960312144 +-28.1236287844 -68.5724925374 67.1332612883 +-28.1194558837 -69.3540221976 66.327338299 +-28.109754289 88.6131730766 36.844908347 +-28.104047727 17.6433093992 94.3338546589 +-28.1029898049 84.8265774741 44.8851168881 +-28.1024074261 -17.6149402359 94.3396447807 +-28.0929262682 93.8170430527 20.2274547718 +-28.0513955309 -70.0271326093 65.6454104053 +-28.0438314725 -22.8312683225 93.2323801216 +-28.0430448021 -74.2137646514 60.8761429009 +-28.0165432615 -49.721354236 82.1149209134 +-28.0141954016 -84.8063915902 44.9786705168 +-27.9927284505 92.5412437858 25.5445757936 +-27.9851322582 -19.7194026825 93.9573175987 +-27.9836456132 58.0161019232 76.4921400918 +-27.9830969798 37.5422047121 88.3602237931 +-27.9579340306 83.8979565281 46.6849741903 +-27.9566657601 70.3234426972 65.3684805299 +-27.9432906491 -14.751529252 94.8765771538 +-27.9392694609 95.8552910266 5.58215049932 +-27.9291106695 85.5503356872 43.6016609893 +-27.9144629991 94.116993801 19.0466331231 +-27.8890564558 72.0888079289 63.4460739636 +-27.8856482226 -43.6035728756 85.5635381204 +-27.8834769165 83.0938764126 48.1447756021 +-27.8829017598 87.6326345275 39.2818680211 +-27.8783452591 16.7509997898 94.5632162717 +-27.8704260058 -43.6133041464 85.5635381204 +-27.8679750872 -62.358027225 73.0400739673 +-27.8647214316 15.9582764318 94.7042275343 +-27.8537933486 55.550072502 78.3476588107 +-27.847629761 60.6286892588 74.4894056592 +-27.8159414385 -66.5614014409 69.2520991747 +-27.8132616495 -52.8643150994 80.1984205923 +-27.7950571868 -38.5387972411 87.9897488528 +-27.7618449231 95.9944930397 -3.78645910098 +-27.758379466 60.7696138191 74.4078383351 +-27.7568616446 94.309725404 18.3093507769 +-27.7536305319 -69.2137950243 66.6272209433 +-27.7386835755 -73.3308721092 62.0737354217 +-27.7350254162 91.6893025623 28.7026159226 +-27.7250457212 53.3047386214 79.9370169588 +-27.7232398297 76.4594957206 58.1839108989 +-27.7173483339 -75.2119997985 59.7904983058 +-27.7077320719 -62.2618281621 73.1829648029 +-27.6635424267 83.892332148 46.8700866991 +-27.660823577 -55.8446797733 78.2064612424 +-27.6455965266 -71.2008758813 64.5457687724 +-27.6234336876 95.5158967353 -10.6611154275 +-27.6183280376 54.2040207511 79.3671978264 +-27.615763596 82.2009323947 49.8033765367 +-27.6027899216 -80.2553176376 52.8882782801 +-27.5779810584 -49.9986687817 82.0949942494 +-27.5709974725 -70.3528934911 65.5004616457 +-27.5661392026 91.7663348342 28.6190104747 +-27.5583204843 94.1201343595 19.5432668772 +-27.5476835931 32.049759441 90.6307787037 +-27.5322961872 -48.1715274136 83.195412213 +-27.5249556157 -49.1896127931 82.5999928064 +-27.5179154194 -49.1770313183 82.6098294496 +-27.4995256915 55.0832697717 78.8010753607 +-27.4934932498 48.6936840036 82.9037572555 +-27.4816810302 70.5960640787 65.2759752463 +-27.4722950672 40.6833867429 87.121381112 +-27.4703409402 74.4616173572 60.8345946742 +-27.4324177866 79.5342195282 54.0534030235 +-27.3859475592 -28.1615878726 91.961594401 +-27.3830664932 -41.418403228 86.8025549363 +-27.3802443485 78.846831896 55.0772123421 +-27.3678644819 -20.1552195744 94.0466220425 +-27.350265316 -20.179094864 94.0466220425 +-27.3434350872 -60.6436377963 74.6638182285 +-27.3405705872 -77.7243443256 56.669387672 +-27.3000104872 -22.7859020871 93.463961469 +-27.2907089144 -72.0325948616 63.7692910769 +-27.2861727958 88.5301269274 37.6547659716 +-27.2759620185 -86.6137101216 41.8818232045 +-27.2690973583 -79.3301199042 54.4346250585 +-27.2596873406 69.0966292401 66.9519624339 +-27.2495809627 91.4069019276 30.0372871173 +-27.2461200918 -67.2000207068 68.8607737173 +-27.2318008831 92.3471744753 27.0264386684 +-27.2227449104 -39.6538033209 87.6726755708 +-27.2103426737 92.333804922 27.0936472296 +-27.2014964717 56.8247979558 77.6596479968 +-27.1836744195 -58.6157812858 76.3232469783 +-27.1762149357 -20.981445543 93.9214154743 +-27.1639050039 -23.8221053314 93.2449975201 +-27.1426516136 94.2230597063 19.6288431388 +-27.1411531996 85.8195292045 43.5702445497 +-27.1281036236 94.7942395137 16.6768746716 +-27.1247755595 -66.4009684664 69.6789633789 +-27.1152863034 63.0215357408 72.7533317557 +-27.105401008 67.0882216916 69.0251240234 +-27.1032887142 -65.015497189 70.9816657042 +-27.1025490242 -27.244830456 92.3210217113 +-27.0961851213 55.481663315 78.6611834876 +-27.0898698072 74.1468220071 61.3871952452 +-27.0841837211 -53.6175704313 79.9475023575 +-27.0783998097 43.758206487 85.7436856497 +-27.0568058386 -56.5478745201 77.9119191464 +-27.0552195108 -65.9019076891 70.1780140797 +-27.0519134491 -68.3950767372 67.7518077755 +-27.0418498896 81.5282736227 51.2042864871 +-27.0412801268 94.6156969818 17.7943545474 +-27.0357561915 86.2712029194 42.7357863387 +-27.0303420458 85.3137487434 44.619781311 +-27.025333847 -56.5327754017 77.9337964931 +-26.9982271243 -65.0189438137 71.0185375623 +-26.9956391424 -66.2168568807 69.9039579147 +-26.984052418 76.5400822911 58.4249665637 +-26.9772169205 -63.0945705469 72.7413564262 +-26.9753309015 87.5758987625 40.0349032557 +-26.9741764009 92.6645967644 26.1852308371 +-26.9720159613 -70.154688809 65.9608216527 +-26.969449017 84.1008479969 46.9009188174 +-26.9522949136 67.045939612 69.1260861067 +-26.9381125525 22.6839970949 93.5936662809 +-26.9305300913 83.4781436906 48.0223497443 +-26.9256536361 92.6787077072 26.1852308371 +-26.8908850698 89.5184467135 35.5433256487 +-26.8895779186 86.3324952771 42.7042253013 +-26.8534247234 38.5651581887 88.2701657102 +-26.8515293257 80.3439535356 53.1398579518 +-26.8465963196 54.5594879268 79.3884282702 +-26.8399795413 -58.9494814705 76.1877557918 +-26.8210001618 22.5693829477 93.6549886748 +-26.8125952575 78.0020830455 56.5398954378 +-26.8100127845 75.0838567371 60.3625519008 +-26.8057098265 -59.038071889 76.1312024621 +-26.8041248845 -57.0133139029 77.6596479968 +-26.8019779162 78.1930950494 56.2804927695 +-26.8015635999 59.0837190123 76.0972426325 +-26.799681363 78.1419285693 56.3526048938 +-26.7985979932 75.6769061889 59.6224874966 +-26.7965179378 -72.9486468723 62.932039105 +-26.790391128 -66.9807562147 69.2520991747 +-26.7840344646 88.8811677511 37.1853938664 +-26.7827753957 86.5211677844 42.3883293765 +-26.7809735798 -54.7151031531 79.3034484816 +-26.7787177868 -83.3060212187 48.4046186062 +-26.7685296403 -22.3264538752 93.7281989492 +-26.7607894456 27.0613923417 92.4745434851 +-26.7606213496 94.7593816224 17.4507518327 +-26.7602416655 75.7786876392 59.5103349486 +-26.7537858248 89.5724589175 35.5106962408 +-26.7534064805 -49.7280444837 82.5310658693 +-26.7509591851 93.4763766536 23.378477076 +-26.7371637391 27.0847352288 92.4745434851 +-26.7233808245 82.0998153797 50.4527623815 +-26.7223042428 -39.9927545215 87.6726755708 +-26.72048907 94.4282064471 19.2179419046 +-26.700587456 57.7324315495 77.1624583388 +-26.6808973364 77.2678409612 57.6004381105 +-26.6754387546 94.7738901571 17.5023058975 +-26.6724344125 34.848264916 89.8564392509 +-26.6693213574 79.6138333931 54.3174449951 +-26.6508183298 88.5509744448 38.0586232965 +-26.6493045885 -70.2655959627 65.9739387103 +-26.6221344976 -89.1316864164 36.6988341962 +-26.619887059 -56.9049181794 77.8023900658 +-26.6047324742 -82.0270616236 50.6334807353 +-26.5978349051 -64.2128537577 71.8975979477 +-26.5977503599 74.7777491411 60.8345946742 +-26.5918640416 9.33839797487 -95.9461676674 +-26.5781663635 94.6816954029 -18.1377404435 +-26.5740794694 -49.0862837083 82.9720136676 +-26.5714490013 85.154037194 45.196770322 +-26.567184716 -49.0735480716 82.9817544761 +-26.5664586796 64.5509723059 71.605832497 +-26.5519015098 92.7196242596 26.4209727938 +-26.5492709197 -76.7997471777 58.2832312683 +-26.5433704303 -23.88298627 93.4079892355 +-26.5065462486 78.0857672471 56.5686835572 +-26.4868044977 93.291563717 24.3953546137 +-26.4799445451 73.9556169792 61.8819784276 +-26.4629321444 -53.1460994117 80.4686606055 +-26.4596814599 -53.1163346516 80.4893797356 +-26.4509675725 -31.0029601349 91.3190165155 +-26.4443790442 -53.1553334796 80.4686606055 +-26.4282011511 -74.7138107203 60.9868565477 +-26.4139962752 -74.6736528448 61.0421687982 +-26.4114602329 -24.4145027101 93.3079140576 +-26.4057830814 -59.8699247292 75.619618703 +-26.3839309812 -59.314992784 76.0632619404 +-26.3692042466 -58.0766928403 77.017938275 +-26.3636466316 -59.3530606716 76.04059656 +-26.3628109675 -24.3951428161 93.3267336023 +-26.3608260535 81.9569003831 50.8740929096 +-26.3572490486 87.7419983889 40.0828784059 +-26.3462157975 -73.3802889299 62.6195665085 +-26.3455820727 -77.4782794526 57.4719628891 +-26.3120999408 -22.937338456 93.7099349122 +-26.2946393445 93.0472445162 25.5108257352 +-26.2907265281 81.8860253251 51.0242741749 +-26.2553131116 82.9178446213 49.3486532416 +-26.2517700805 92.8955456529 26.1009993198 +-26.2492324701 79.603302247 54.5370705676 +-26.2401858904 72.1726950345 64.0511884034 +-26.2367523625 -26.2367523625 92.8615402141 +-26.2340890061 -80.0267375657 53.9211818177 +-26.2306393599 -63.5458417955 72.6214813211 +-26.2296163131 -77.0489916966 58.0987100252 +-26.2286082998 27.7553763807 92.4213134976 +-26.228296051 80.578811403 53.0954954695 +-26.2250141628 92.6772352467 26.8919820615 +-26.1970784681 29.4857424189 91.892894577 +-26.1903751746 -40.5617266955 87.5717453046 +-26.182387732 15.6822513814 95.2289323906 +-26.1645344823 -59.2669016936 76.1764497661 +-26.1630702696 -70.312811425 66.1180936173 +-26.1598764106 -69.7820642231 66.679264985 +-26.1526692727 -50.8875907753 82.0151875874 +-26.1324448042 -42.1473187671 86.8371973828 +-26.1293595946 79.2397763134 55.1209072583 +-26.1191719864 87.6150204095 40.514158678 +-26.1178684462 53.9552906857 80.0417613178 +-26.1154447599 -76.4947355617 58.8773214093 +-26.1152662287 -69.8484523749 66.6272209433 +-26.1062934321 96.2198564335 -7.75890914711 +-26.081565221 96.1287157694 -8.88942968664 +-26.0656981747 90.0118396653 34.906275922 +-26.0623584048 69.967415465 66.5230354654 +-26.0611484704 57.1331126242 77.8243148526 +-26.0605986215 86.1538100688 43.5702445497 +-26.0597749196 -71.6764810963 64.678977951 +-26.0575927002 94.2800570157 20.7911690818 +-26.05749524 86.4701921085 42.9408059837 +-26.0514604444 -66.3051110288 70.1780140797 +-26.0496277505 -64.5724135211 71.7761820252 +-26.0135602121 -67.4157170448 69.1260861067 +-26.0028695435 91.2837827696 31.4820866332 +-25.9953635585 88.2109739105 39.2818680211 +-25.981778001 -88.1648735642 39.3941909591 +-25.9704522014 82.8718137531 49.5761847839 +-25.9669507477 -60.8198265457 75.011106963 +-25.9617559487 34.9320529982 90.0318771402 +-25.9606903808 52.0236048728 81.3608449501 +-25.9553407631 71.3892386752 65.037657455 +-25.9239312377 -58.5558502178 76.8060036355 +-25.9114851921 -57.2011446814 77.8243148526 +-25.9064175657 85.3751920812 45.1656296979 +-25.8821326398 26.0634576929 93.009738109 +-25.873265434 55.4096322363 79.1223532967 +-25.8648702963 48.0965903448 83.771871662 +-25.8562578869 56.6577454841 78.2390810577 +-25.8501340171 -77.7083697256 57.3862339406 +-25.8388150905 -56.2293063164 78.5532987588 +-25.8248079935 -60.0221971381 75.6995055652 +-25.820943082 88.5876424639 38.5422949633 +-25.8140208549 -50.706617419 82.234270698 +-25.8083865903 -62.9899690107 73.2542898787 +-25.8027529919 83.6134608519 48.4046186062 +-25.8025320544 54.9077780442 79.4944353388 +-25.7999615165 95.2882086656 15.9536602398 +-25.7944583712 49.8263915736 82.7766671236 +-25.7727872898 -57.2935557926 77.8023900658 +-25.772046261 78.2480171121 56.6837670727 +-25.7647775999 -58.8891785211 76.6044443119 +-25.7605124234 -80.9622179888 52.7400726016 +-25.7571330431 51.0568659903 82.0351542489 +-25.7431685297 -88.2634652804 39.3300136124 +-25.7387511801 -63.7056446692 72.6574670971 +-25.7353733521 -80.5425036932 53.3909698101 +-25.728851527 85.6500936446 44.7446941857 +-25.7212993719 81.5775393979 51.8027009373 +-25.7202646784 -55.3589591345 79.207661425 +-25.7090140074 84.7246441364 46.4842045725 +-25.7019651172 53.5961198967 80.4168198895 +-25.6911302837 -55.2962517797 79.2609005996 +-25.6818915207 84.9018411442 46.1748613235 +-25.6799163342 92.2859780046 28.7026159226 +-25.6465278948 85.7561528581 44.5885394908 +-25.6331197944 -67.7288123223 68.9619543736 +-25.625639319 88.3190888442 39.2818680211 +-25.6214950651 95.0894426031 17.3648177667 +-25.6205461498 -66.328251821 70.3146544139 +-25.6106420349 -66.3715301823 70.2774145499 +-25.6065215068 -49.3367439995 83.1275631055 +-25.6042539659 91.2122432323 32.0116988518 +-25.5947502544 90.5705894667 33.7916718003 +-25.5860334169 -42.1976832391 86.9753437661 +-25.5837474235 9.17038433367 -96.2360427228 +-25.5639799849 56.5652857902 78.4018582101 +-25.5615820062 -57.3583607076 77.8243148526 +-25.5588668498 44.6282972928 85.7616429769 +-25.5505224564 -57.3335438692 77.8462301567 +-25.4928050349 89.7905085321 35.8856721967 +-25.4916098135 -56.9872074904 78.1193702712 +-25.4887002244 -95.1251242564 -17.3648177667 +-25.4715652921 -52.7374352973 81.0553038353 +-25.46813882 92.6509513906 27.6979261222 +-25.4614606822 89.7994017292 35.8856721967 +-25.4591344264 -54.3000822251 80.0208319415 +-25.4442788381 48.7325472512 83.5327930385 +-25.4423235569 -26.8293648298 92.9132571534 +-25.4387127265 -26.7880764073 92.9261580892 +-25.4317646847 -71.6977598288 64.9049811691 +-25.426819349 -71.7235469986 64.8784221735 +-25.4188667955 -60.4100575331 75.5281812285 +-25.4161433044 89.8187462346 35.8693808751 +-25.4118391237 -75.379168341 60.5988400266 +-25.408383014 -69.9228517277 66.8222184522 +-25.4045831704 78.4200565875 56.6118528114 +-25.3917239182 -59.6743117998 76.1198848376 +-25.3825247013 -52.8117379224 81.0348553241 +-25.3777612628 7.22904546025 -96.4557418458 +-25.3748812046 58.1361153846 77.3065811677 +-25.3628172968 89.4514987906 36.8124552685 +-25.3613220993 69.1907924068 67.59761525 +-25.3558353932 -68.4722652869 68.3273773681 +-25.3522297274 87.9500738256 40.2746689859 +-25.3432971296 96.6029028277 -5.05929400767 +-25.3333247025 -58.6823060835 76.9064991547 +-25.3257286509 -50.8399876376 82.3037248568 +-25.3104518578 -50.8315474358 82.3136368534 +-25.3089756427 -48.3088792875 83.8194961444 +-25.3088662387 -69.1597274461 67.6490457382 +-25.3048082681 -69.1486385203 67.6618982095 +-25.3032171785 62.2519623725 74.057007644 +-25.3000720865 92.2915986268 29.0201167351 +-25.2947374441 -58.5087146048 77.0513242776 +-25.274354304 92.3874792969 28.736051985 +-25.2652553977 89.1074101195 37.7032668542 +-25.2624794848 93.1741606683 26.084150629 +-25.2513640785 58.7176208641 76.9064991547 +-25.2502762184 73.9605708401 62.3879596709 +-25.2498981265 -56.5262401485 78.5316930881 +-25.238758863 88.3087912106 39.5545502563 +-25.2258554018 79.7634138257 54.7855275974 +-25.2195849397 8.94063187269 -96.3537110712 +-25.2062272683 57.3669719531 77.9337964931 +-25.1976468448 78.1533033857 57.0713567684 +-25.192880401 87.9739028838 40.3225890599 +-25.1872297994 -55.3451073883 79.3884282702 +-25.1862024101 -65.0348856063 71.6667207449 +-25.1739556614 -31.4784898727 91.5170838243 +-25.1722714975 96.7763138663 -0.837748241477 +-25.1686191639 -61.1545128471 75.011106963 +-25.1411887029 81.8243295076 51.6981598438 +-25.1326329284 75.6396258053 60.3903781253 +-25.1267030329 -48.3709624296 83.8385280663 +-25.1251563789 36.0562849969 89.8257804261 +-25.1247623918 -77.7877615325 57.6004381105 +-25.1196578952 73.3685168448 63.1352795449 +-25.1133965411 92.5603405182 28.31785086 +-25.1099603072 94.7026788427 20.0223004021 +-25.1002010962 -59.711018852 76.1877557918 +-25.0854548468 96.7891620734 1.60563391348 +-25.0658056985 -76.103758831 59.8324600571 +-25.0625462395 42.5987489367 86.9322458298 +-25.0502190858 -33.4853189772 90.8362259055 +-25.0487672211 -29.6097516131 92.172782697 +-25.0465603337 -59.9639011593 76.0065811178 +-25.0432974358 -59.6339118483 76.2668329696 +-25.0339161703 8.34223628058 -96.4557418458 +-25.0275089459 -59.6838345898 76.232956683 +-25.0209880977 -33.5071666642 90.8362259055 +-25.0050080117 84.8503658888 46.638664034 +-24.9735833859 77.7836047782 57.6717518425 +-24.9622680961 -25.8943689962 93.3079140576 +-24.9576696504 7.58271980599 -96.5381638833 +-24.952118732 -70.5800339696 66.3012109666 +-24.9485882058 -26.2903264051 93.2007869283 +-24.94028114 81.1704572179 52.814195551 +-24.9199387905 7.29654355372 -96.5699596295 +-24.9155989287 -54.1206266173 80.3129547743 +-24.9033141902 -77.9854005145 57.4291062871 +-24.8800358048 -57.4943704485 77.9447316057 +-24.8778610486 -59.4141778855 76.4921400918 +-24.8746462138 -45.813399197 85.3368878608 +-24.8639008582 -66.785649811 70.1531425771 +-24.8542128324 -69.0352319118 67.9441304262 +-24.8514991376 -57.7878050362 77.7365588364 +-24.8500846849 16.8437548312 -95.3874269196 +-24.8437953916 -54.6917059282 79.9475023575 +-24.842586572 -56.0604829838 78.9941019319 +-24.8330780488 -37.6327490572 89.2585818452 +-24.8329190975 -79.8766056561 54.8001277184 +-24.8296032189 53.1987655481 80.9529625656 +-24.8085932031 80.1436155631 54.4199833495 +-24.7970845764 -24.4276501518 93.74643729 +-24.7941611842 92.5330692704 28.6858965796 +-24.7660481721 -24.4823943692 93.7403606985 +-24.759024944 93.2477157148 26.3031214458 +-24.7485194318 94.5373848819 21.2177672156 +-24.7250443637 47.1542430603 84.6472063486 +-24.7081669347 92.3410547443 29.3706672624 +-24.6854281119 83.4435576173 49.2727341548 +-24.6717694822 86.2110252146 44.2601730913 +-24.6676028512 -54.2033061868 80.3337473792 +-24.6585059855 -62.9534315374 73.6805506238 +-24.6571704686 -34.4788980655 90.571681737 +-24.6562217643 83.3983378982 49.3638325511 +-24.6558465599 -73.5605352683 63.0946660302 +-24.6523215104 72.7067680463 64.0779909518 +-24.6428297683 -62.945758622 73.6923497556 +-24.6271562304 -62.938080235 73.7041466427 +-24.6113749518 78.6311689081 56.669387672 +-24.6083418864 -90.2623529356 35.3148290685 +-24.6056034194 -80.8850583204 53.4057264801 +-24.6013650414 -76.1672921467 59.9442778349 +-24.5862303233 77.365046679 58.3966337286 +-24.5706934574 80.2168712633 54.4199833495 +-24.565128695 -60.6483942031 75.619618703 +-24.5583725897 -70.8403660386 66.1704531892 +-24.5459954001 -25.48034712 93.5320587845 +-24.5455391233 -55.7839810642 79.2821793707 +-24.5428387981 80.1259331047 54.5663257682 +-24.540432263 -40.4732289024 88.0890738205 +-24.5359203836 -41.1920745841 87.7564903719 +-24.5244882448 -40.4469332817 88.1055904267 +-24.5171707894 -86.9894425353 42.7988927879 +-24.509558419 28.7986337193 92.573863709 +-24.4986558738 28.7654734397 92.587058481 +-24.4922895322 -59.7183725489 76.3796028635 +-24.4858724435 56.3674500272 78.886961078 +-24.4841563709 -79.9841989949 54.8001277184 +-24.480867537 24.4211224557 93.8312096407 +-24.4701470632 -82.5040653489 50.9341840379 +-24.4656224673 23.9000230479 93.9692620786 +-24.4548142706 -60.1646884293 76.04059656 +-24.4355769566 -56.95755491 78.4776370533 +-24.4322895386 -70.6759016174 66.3926212652 +-24.4286800597 -59.209748576 76.7948257639 +-24.4162698043 66.361478049 70.7106781187 +-24.4162552376 -75.7297304339 60.5710690725 +-24.4160290175 -55.8860823334 79.2502575922 +-24.4090137802 -62.9954072337 73.727733681 +-24.4078670938 92.2496724634 29.9040792256 +-24.40539301 88.1224421803 40.4822427269 +-24.4040421736 -81.3429088004 52.7993741769 +-24.4013937088 -81.3340810077 52.814195551 +-24.3960945495 81.3164179898 52.8438334722 +-24.3906938821 96.9601640763 1.95464427448 +-24.3790766614 -65.4484509395 71.5692733704 +-24.3781552189 -70.7191017236 66.3665141432 +-24.3760172746 -75.8314504998 60.4599114862 +-24.3724317239 86.9990539111 42.8619783775 +-24.366003532 66.5112857262 70.5871570679 +-24.3594026379 92.7206466802 28.4517342588 +-24.3519836957 68.1999247732 68.9619543736 +-24.3413311063 56.5199384819 78.822561199 +-24.3407943015 92.2565911569 29.9373866742 +-24.3259258719 -75.902908774 60.3903781253 +-24.3174661751 78.8981431416 56.424674103 +-24.3113619801 -84.3391726858 47.9151503112 +-24.2918869872 -54.2036393293 80.4479316705 +-24.2797254044 85.9745270944 44.9318998616 +-24.2787022636 -54.224929601 80.437563527 +-24.2698928469 -53.3788132936 81.0041640446 +-24.2652590523 -73.7598145807 63.0133871185 +-24.2627276455 -75.0292949862 61.4973571877 +-24.2624454704 60.1423051779 76.1198848376 +-24.2597727137 -54.2334011631 80.437563527 +-24.2435915492 92.7407238051 28.4851964518 +-24.2001592089 -59.8373508829 76.3796028635 +-24.1892174399 -59.481494006 76.6605089369 +-24.1514126101 97.0102726216 2.39087323514 +-24.1459967222 -60.8306779266 75.6081970773 +-24.1438123971 95.2755576485 18.4294448562 +-24.1366883387 92.3317794 29.8707681332 +-24.136313275 50.7623444895 82.7080574275 +-24.1248259229 84.5228655333 47.6851966153 +-24.118554874 -84.3335593689 48.0223497443 +-24.0946282578 -79.3047597424 55.9482258102 +-24.0807235657 -85.842415145 45.2901591366 +-24.0802083056 -81.6596451826 52.4580395803 +-24.0635380014 61.245532178 75.2989437316 +-24.0539796153 -74.4725542491 62.2514636638 +-24.0498104663 97.0355107253 2.39087323514 +-24.0429183257 24.2790659692 -93.9811951086 +-24.0401900066 54.9735064741 79.9998928149 +-24.0299765136 -57.5301006335 78.1847027868 +-24.0104735562 -51.5375876493 82.2640518021 +-24.0052405133 68.8562612929 68.4292606175 +-23.9894987959 -57.9157733476 77.9119191464 +-23.9890336377 -35.2723002332 90.4455145454 +-23.9815514011 97.0502145502 2.47811383077 +-23.9710815685 -25.6878546677 93.6243631274 +-23.9646125781 97.0543986423 2.47811383077 +-23.96234407 -81.5221123205 52.7252431902 +-23.9572527755 -80.9821240797 53.5532036295 +-23.9567632439 -77.4875388667 58.4957674987 +-23.9553880667 73.8147657436 63.0675807431 +-23.9547330643 -54.1845366515 80.5618194412 +-23.954555466 -81.4956147688 52.7697266042 +-23.9398234613 -25.6723176034 93.6366219035 +-23.9300308685 54.3336754048 80.4686606055 +-23.9288870756 85.7036429804 45.63215909 +-23.9258649423 -54.7641410938 80.1775644244 +-23.9239954513 55.6310577954 79.5790666583 +-23.9143705552 94.6475857902 21.6780392341 +-23.9140927152 -57.2526635509 78.4235212544 +-23.9092049573 49.7462991172 83.3885822067 +-23.895550022 -54.746835741 80.1984205923 +-23.8846763294 63.4432683453 73.5151272753 +-23.8834763517 36.9465057765 89.8027575761 +-23.8823402865 97.0121657494 4.27475368243 +-23.8725346992 -51.7122977408 82.1945274906 +-23.8707127195 57.7144527177 78.0975737252 +-23.8605077106 -51.6862450732 82.2144041031 +-23.8470062589 85.9895266025 45.1344835704 +-23.8429999752 -89.9877107348 36.5201761892 +-23.8319627563 -79.5874468393 55.6585649903 +-23.815895342 -70.8493012788 66.4317667789 +-23.8109190881 -54.630942006 80.3025548019 +-23.7958325793 -60.4711334328 76.0065811178 +-23.7914077671 82.535386119 51.2042864871 +-23.7799285621 22.788202673 94.4204046619 +-23.7779556043 -80.7905624356 53.9211818177 +-23.7773691305 -46.3254032937 85.3732611941 +-23.7686387007 57.0163229609 78.6396257006 +-23.7637730789 70.9401279973 66.3534575496 +-23.7583480919 95.5025285292 17.7428278601 +-23.7515341974 -78.3229196028 57.4576791052 +-23.7496724732 -91.4380467282 32.7877517976 +-23.7455132446 -80.2663860474 54.7125019684 +-23.7419891709 -81.7204627413 52.5174629961 +-23.7399027024 -81.0266220295 53.5826794979 +-23.7391485627 88.1647131903 40.7852445573 +-23.7351504447 -91.4477280559 32.7712628196 +-23.7292731718 -53.0474545835 81.3811351416 +-23.720655805 -80.4921287462 54.3906949587 +-23.7172074826 -58.554977125 77.5165061333 +-23.7136246386 72.9830321569 64.1181801339 +-23.7108474718 97.118462198 2.40832150206 +-23.703591702 42.2911742478 87.4619707139 +-23.6998156032 -58.9551431832 77.2179372467 +-23.6983327798 -54.4504491151 80.4582973635 +-23.6875428096 76.5220868842 59.8604254456 +-23.6767206771 -53.3039248512 81.2287171722 +-23.6659820462 -62.7958800008 74.1390500932 +-23.665343753 56.6571343449 78.9298462742 +-23.6599377544 -78.2667466909 57.5719003324 +-23.6483585175 -58.9758027228 77.2179372467 +-23.6481589861 87.1599205945 42.9408059837 +-23.6377937451 -60.1619453194 76.3006883472 +-23.6352544768 75.420188752 61.2631200187 +-23.632616065 -78.2750007987 57.5719003324 +-23.6237874975 83.6518504407 49.4397065335 +-23.6233782954 97.1279815546 2.84450295045 +-23.6200040236 -54.5303772847 80.4271929332 +-23.5948433994 -54.3422175962 80.5618194412 +-23.5894727954 97.1362217517 -2.84450295045 +-23.5856301624 86.6899305014 43.915532554 +-23.5780168253 -73.4369238829 63.6482154754 +-23.554520648 -66.9986360647 70.4014724456 +-23.5531021504 -69.464854825 67.9697382902 +-23.542688519 -49.8725124172 83.4174701276 +-23.5241508525 25.9435237691 93.6672189248 +-23.5164912851 92.1245030224 30.9846829984 +-23.5022047275 -72.8511624776 64.3455864734 +-23.4921220485 -54.4173302475 80.541134648 +-23.488279123 -73.4656750506 63.6482154754 +-23.4857626522 -60.0210921777 76.4584033736 +-23.474154631 -56.3930345117 79.175688964 +-23.4542488776 86.804824666 43.7586634199 +-23.4491547246 4.81342019061 -97.0925750445 +-23.4436470829 84.9378893074 47.2858369012 +-23.4389349789 81.9031085683 52.3688565266 +-23.4152961728 -78.4450231449 57.4291062871 +-23.4074712423 54.0397129842 80.8195502996 +-23.3947481276 -54.7952101508 80.3129547743 +-23.3811334949 -64.8370584287 72.4532846102 +-23.3791601919 -91.5865163576 32.6393150999 +-23.3753805129 -78.5613776534 57.2861373028 +-23.3434792206 85.740817815 45.8649554484 +-23.3390878387 77.9414784941 58.141318432 +-23.3268138661 92.6625664836 29.4874299918 +-23.3244134216 -55.4324143582 79.8950510167 +-23.3151756583 58.3807311491 77.7694851116 +-23.3124778672 -78.3499706775 57.6004381105 +-23.306871106 92.6516505626 29.5374576981 +-23.3045572535 23.7148897511 94.3106654378 +-23.2971732249 84.4072047986 48.2976759048 +-23.2970252641 -80.7144374128 54.2441536663 +-23.2892923251 94.4610835055 23.1238527491 +-23.2831589732 19.8856963756 95.1969200546 +-23.2645524395 -80.4964620423 54.5809508754 +-23.2625232374 -66.5390057996 70.9324729572 +-23.2584917062 61.878214382 75.0341865315 +-23.2489208195 53.2907176696 81.3608449501 +-23.2458265742 84.5086512086 48.1447756021 +-23.2367275758 -67.4079103363 70.1158192968 +-23.2367190334 -80.0856449747 55.1936985312 +-23.2299829678 86.999089891 43.4916802325 +-23.2192782904 44.4521687945 86.515142057 +-23.2141962996 59.911791712 76.6268771648 +-23.2036605377 -58.3082241027 77.8571842519 +-23.2019351126 57.4268045711 78.5100778485 +-23.1938206569 55.2298777757 80.0731370949 +-23.1795118637 17.3215686893 95.7218548081 +-23.1749486968 -64.5475784598 72.7772757657 +-23.1579553445 -87.0339944444 43.4602452285 +-23.1555541634 -69.2850207982 68.2891367963 +-23.1505085631 55.1267416135 80.1566984871 +-23.1494856512 88.5553632038 40.2746689859 +-23.1474093739 37.596164961 89.7258369674 +-23.1419459259 82.9969784992 50.7538362961 +-23.1331377394 -80.7812517065 54.2148255651 +-23.1268160201 -69.3197434653 68.26363268 +-23.1197025475 -35.0362513473 90.7631006833 +-23.1088697743 92.8226349725 29.153706017 +-23.1064098799 92.8127541831 29.1870944669 +-23.0959062689 -69.917427329 67.6618982095 +-23.0931761301 -59.5994597625 76.9064991547 +-23.0909028577 -34.9793256033 90.7923839623 +-23.0811419709 50.343925937 83.2631371411 +-23.072214865 -73.7136883935 63.5135028529 +-23.0581429527 91.460438815 33.2161131884 +-23.0476674601 85.1230318617 47.147369718 +-23.0469410317 21.8096528822 94.8323655206 +-23.0466491608 -42.2179336387 87.6726755708 +-23.0368004374 90.8405158147 34.8899199214 +-23.024625898 97.2493811911 3.52483477781 +-23.0190247889 -54.5733618875 80.5721581569 +-23.0187258885 -88.3702497214 40.7533706906 +-23.0077320161 -47.110219968 85.1543976671 +-22.9972617832 -91.7592534872 32.4247644548 +-22.9898056033 -60.1413487354 76.5146195875 +-22.9887546718 95.9764108091 16.1259333635 +-22.9817394158 81.2157452804 53.6268810577 +-22.9703739546 22.0817311808 94.7879690069 +-22.9633983423 -31.5137803764 92.0845480141 +-22.9457800795 -76.0000902615 60.8068865901 +-22.9222890933 -72.4796048202 64.9713440513 +-22.919058587 31.40684 92.1321179324 +-22.9151995865 -80.8728370779 54.1708210283 +-22.9105573825 95.5763011892 18.4465989119 +-22.9038172618 -72.5092234136 64.944804833 +-22.8982354467 -88.3500432971 40.8649074736 +-22.8911616662 -72.5132197794 64.944804833 +-22.8881638831 -61.3150266149 75.6081970773 +-22.8666345696 93.3071365657 27.7650011593 +-22.8591474504 46.8681978328 85.327788028 +-22.8368523376 81.3536896195 53.4794854183 +-22.8316300164 -26.3389709848 93.7281989492 +-22.8193192204 97.1381327063 6.59255979514 +-22.8193081949 -76.6435561786 60.0420225326 +-22.8158504372 -67.0978849982 70.5500588065 +-22.8095064437 93.7105042801 26.4209727938 +-22.8090180081 18.635749375 95.5638924633 +-22.7977600756 88.920260113 39.6667301018 +-22.7924701388 -71.0754626617 66.5490940013 +-22.7892337402 -53.766324557 81.1777874123 +-22.7830363691 90.9044924175 34.8899199214 +-22.7803004493 -74.8378966677 62.2924323959 +-22.7732824298 76.0519569149 60.8068865901 +-22.7510428355 -53.0565837116 81.6540811886 +-22.7450722591 -74.7690054503 62.3879596709 +-22.7440681743 53.2454508363 81.5329953339 +-22.7406515586 80.902444506 54.200159037 +-22.7324506196 -60.0962343645 76.6268771648 +-22.7280453185 93.3758296505 27.6476109834 +-22.7277185649 -60.0837245531 76.6380900901 +-22.713768013 -77.7757994648 58.6089563144 +-22.7114214159 51.9349668992 82.3829506054 +-22.710627235 -64.2397088173 73.1948578909 +-22.6925278828 -55.467926546 80.0522223488 +-22.6755379474 83.9227939467 49.4245347472 +-22.6735543157 77.638100935 58.8067616682 +-22.6531311695 -78.7414509257 57.3290463408 +-22.6474681035 72.2681586018 65.3024152754 +-22.6441096322 22.5101339015 94.7657014468 +-22.6179048381 96.9646392499 9.28919349936 +-22.6149931519 23.8312303168 94.4491108816 +-22.6097620423 38.738519919 89.3763152903 +-22.5990738014 97.2675258449 5.32074048737 +-22.5842514013 -78.6570090349 57.4719628891 +-22.5819441033 83.9837355467 49.3638325511 +-22.5694485613 80.0252282313 55.557023302 +-22.565285266 96.9685363494 9.37607909084 +-22.5619020611 -80.4281548228 54.9751988372 +-22.5616954901 93.9762250378 25.6795448608 +-22.5598626493 52.967691144 81.7647619217 +-22.5513061383 38.5919352304 89.4544639838 +-22.5428391784 -78.101498425 58.2406760395 +-22.5336339366 -54.9426767366 80.4582973635 +-22.5330452832 93.2829059847 28.11692233 +-22.5178811767 -72.6537324873 64.9182577014 +-22.5172535139 79.2048096241 56.7412674039 +-22.4992330071 26.7945415099 -93.6794377618 +-22.496635095 33.8858138106 91.3545457643 +-22.4955316528 -56.0441685261 79.7057226922 +-22.4793728226 -74.1278477287 63.2434975995 +-22.4788488065 -57.2122460887 78.8762337705 +-22.4738142046 -57.199432226 78.886961078 +-22.4726457487 41.1664472474 88.3193286551 +-22.4714761007 87.8387779438 42.1827198174 +-22.4637429472 -57.1737992739 78.9084084835 +-22.4565942758 57.986591867 78.3151105291 +-22.4491302302 97.3929574821 3.26318629583 +-22.4273335258 92.2104201088 31.5317797511 +-22.4103823654 -91.7223395839 32.9361075947 +-22.4085244289 -73.66268465 63.8096146601 +-22.3906912435 -62.2948598356 74.9533680611 +-22.3795218474 -79.7245017522 56.0638994563 +-22.379269848 52.3914324963 82.1845854285 +-22.3772638249 90.4223278157 36.3739013043 +-22.372789205 -53.1708000173 81.6842967082 +-22.3681182868 -55.0860325662 80.4064443961 +-22.3486296093 79.2422632872 56.7556381667 +-22.3474242338 -53.9514546695 81.1777874123 +-22.3453392723 56.5820971862 79.3671978264 +-22.3450716767 77.1635194879 59.5524057617 +-22.3344349579 -80.3719312796 55.1500288078 +-22.3181827427 -54.4986147387 80.8195502996 +-22.3037284213 89.6553266931 38.2683432365 +-22.2928111233 -62.3299541835 74.9533680611 +-22.279210821 -42.4896840139 87.7397487892 +-22.2731240499 -62.3092033357 74.976470474 +-22.2724314503 89.6631067007 38.2683432365 +-22.2408259595 94.8242453648 22.6651307437 +-22.2343775984 -42.5304416961 87.7313739887 +-22.2282882797 -66.0119078631 71.7518725918 +-22.2220453833 -66.1460199668 71.6301943425 +-22.1813908159 81.641081141 53.3171620737 +-22.1803184026 -68.4672451656 69.4281629815 +-22.1784724286 55.6754618998 80.0522223488 +-22.1634201321 -91.7527218579 33.0184923902 +-22.155987421 -66.1022240759 71.691060765 +-22.1277494791 -67.7800456428 70.1158192968 +-22.1249972904 -78.8706866429 57.3576436351 +-22.1233994855 -82.1069075094 52.6213923652 +-22.116116759 93.9237897642 26.2526016964 +-22.1150662389 93.9193283651 26.2694424132 +-22.1104320021 60.2566080674 76.6829184428 +-22.0927912455 89.8103888442 38.0263412733 +-22.0890062463 84.8010010433 48.1753674102 +-22.0604896791 -72.7465411362 64.9713440513 +-22.0519005047 -59.9353104715 76.9511029343 +-22.0443254221 -71.2137091979 66.6532470249 +-22.0341827628 80.1038009909 55.6585649903 +-22.0340682594 95.4400350781 20.1419845156 +-22.0198849882 -78.9727850361 57.2575225515 +-22.0029847524 86.4472128784 45.196770322 +-22.0005805465 75.1387443295 62.2104778651 +-21.9975291574 -75.128322898 62.2241416936 +-21.9703725597 88.9779164917 40.0029137237 +-21.9637588925 6.72757212318 -97.3259115993 +-21.9489046432 18.4696033402 95.7972825159 +-21.9310981472 59.6069792785 77.2401123468 +-21.930941342 -72.8685401811 64.8784221735 +-21.9309347956 -59.9939775805 76.9399555047 +-21.9275564828 77.9053663796 58.7361571432 +-21.9275148689 -91.5458103374 33.7423873096 +-21.9265381533 74.4999855812 62.9998339126 +-21.9152164386 -75.5803584031 61.7035875141 +-21.9022223977 -55.1218487885 80.5100890583 +-21.8881734841 88.9116848898 40.1947776656 +-21.8663720602 75.1666013827 62.2241416936 +-21.8655617265 54.2554331441 81.1063818989 +-21.8578130357 -71.2711769955 66.6532470249 +-21.841965974 58.5123704923 78.0975737252 +-21.8268280089 48.4989621809 84.6843565628 +-21.8223017354 95.4342417834 20.3983490067 +-21.8101049414 37.0262107876 90.2960632428 +-21.8062782016 48.5891965806 84.6379123481 +-21.8015649803 -67.4989443194 70.4881853942 +-21.7960984537 -57.6817008416 78.7257993304 +-21.7750668773 -74.8527358604 62.6331732926 +-21.7698731882 -74.3508077945 63.2299770811 +-21.7668116827 -90.9449532031 35.4291037998 +-21.7503580693 -56.367370451 79.6846376179 +-21.7437750586 44.1308414489 87.0613408995 +-21.7419806591 48.6503600502 84.6193166128 +-21.7375246221 -69.7054483187 68.3273773681 +-21.7283682218 -42.1882338521 88.0229000821 +-21.7258918841 -77.4479647764 59.4121062902 +-21.7150143828 -76.3829202841 60.7791710969 +-21.7129001726 93.527438203 27.9493876371 +-21.7030972458 -82.1429261222 52.7400726016 +-21.6996846451 91.5819119873 33.7916718003 +-21.6861664322 32.9262986614 91.8997771593 +-21.6723253802 41.332265521 88.4418121677 +-21.6684804041 83.4851798385 50.6033764121 +-21.6652416348 77.3355546271 59.5804439009 +-21.6541764343 88.3597099355 41.5169640396 +-21.6512336894 -91.0232936759 35.2984997999 +-21.6337977036 -61.0242549434 76.2103608804 +-21.6282312267 -75.1789364131 62.2924323959 +-21.6282280966 -53.4779900585 81.6842967082 +-21.6203143193 -89.0276634953 40.0828784059 +-21.6145617857 82.5071346689 52.2052051767 +-21.613218426 -26.718694693 93.9094252095 +-21.5990336009 -77.5157215483 59.3699811383 +-21.592600968 -26.6932069774 93.9214154743 +-21.5918647353 -75.2006993452 62.2787780488 +-21.574311721 -73.4451807484 64.3455864734 +-21.5611809922 87.583412642 43.1770923546 +-21.5598038602 -91.1333395258 35.0697773643 +-21.5486306396 -56.48944516 79.6529918024 +-21.5423256104 65.4443542784 72.4773392198 +-21.5197244417 69.6480728922 68.4547105929 +-21.5061092591 23.3304460802 94.8323655206 +-21.5050532921 -73.7804953971 63.9841478951 +-21.5030690704 93.3630270899 28.6524552728 +-21.4948368157 80.6702022944 55.0480740085 +-21.4807954453 -72.1939427828 65.7769720534 +-21.4713034813 -53.9550030537 81.4115518356 +-21.4694938871 -60.7290156054 76.4921400918 +-21.4339219087 76.4071568551 60.8484459368 +-21.4171292531 91.8168250623 33.3313247568 +-21.4150439888 -58.2043851483 78.445174743 +-21.4146283842 85.1294305854 47.8998302645 +-21.4041693873 27.199847515 93.8191335922 +-21.4001326165 97.495643325 6.0525909032 +-21.3821409423 -89.9617502276 38.0747625693 +-21.3473035079 -70.4833259974 67.6490457382 +-21.3437201166 91.574359018 34.0379550213 +-21.3369712773 97.4515263814 6.92341408906 +-21.3367887476 97.6954948871 0.5759554688 +-21.3226946212 -54.7746083712 80.9016994375 +-21.3223953771 39.5503613201 89.3371388328 +-21.3057318068 94.3873517139 25.2407137104 +-21.3052490227 97.4694726359 -6.76670290174 +-21.2991496903 93.5218720859 28.284371374 +-21.296650284 10.9308992269 97.0925750445 +-21.280370048 92.5437888309 31.3495294931 +-21.2803624538 88.0970159669 42.2618261741 +-21.2753657188 -55.8023296592 80.2088450119 +-21.267552129 -90.178956884 37.6224263139 +-21.2408129481 89.2978563079 39.6827509647 +-21.2276572611 -57.2322718297 79.207661425 +-21.2264458207 -55.7909974689 80.2296865209 +-21.209475073 -78.442482878 58.2832312683 +-21.2064162878 -77.6240507051 59.3699811383 +-21.2011170206 97.6464244975 3.96086100934 +-21.1979550382 -43.8891669766 87.317740032 +-21.1902946107 -43.8928660492 87.317740032 +-21.1770420023 -43.8654150405 87.3347482699 +-21.1641247964 81.717913083 53.6121488374 +-21.1605894147 94.8224993412 23.6838146066 +-21.1527232535 -61.5017006773 75.9611947823 +-21.1512851681 88.5780471467 41.3104429825 +-21.1457290804 97.1459788517 10.7478804698 +-21.1433624594 93.0628574408 29.8707681332 +-21.1416548321 83.9823221337 50.0 +-21.1373426791 71.9111961253 66.1966208828 +-21.12559143 92.0914450029 32.7547728433 +-21.1154671056 86.291791754 45.9114770487 +-21.1071805601 79.4381978535 56.9566471151 +-21.1022919967 78.7548258877 57.8996603779 +-21.1019023515 4.8136038436 -97.629600712 +-21.1010392976 -57.6612999133 78.9298462742 +-21.0957966257 -87.7353889184 43.0983630323 +-21.0870547681 92.0709160423 32.837212737 +-21.0668300885 61.5311754907 75.9611947823 +-21.0523910473 -59.4501183513 77.6046407067 +-21.0517735452 -73.5616057547 64.3856582585 +-21.0422956723 68.0607679407 70.1780140797 +-21.0341264903 97.2866880691 9.63669275888 +-21.0312987884 -47.5045844878 85.4458830133 +-20.9916737621 -81.3444615551 54.2441536663 +-20.9710327996 -80.7980260743 55.062644014 +-20.9693110058 -80.9075240575 54.9022817998 +-20.9563853731 92.8396984814 30.6858322026 +-20.955909372 89.1360180331 40.1947776656 +-20.9419562113 83.8066361964 50.3773977046 +-20.9117622521 -73.7531818295 64.2118865129 +-20.9067653754 -87.7574154587 43.1456045681 +-20.9026707128 6.12028980199 -97.5992848837 +-20.901722039 -83.7077390835 50.5582083675 +-20.886322464 6.11550304425 -97.6030847691 +-20.8801325287 -73.9365659998 64.0109699485 +-20.8742515978 -66.0839961912 72.091407724 +-20.8603863334 73.9653506728 63.9841478951 +-20.8574330935 75.0568430506 62.7011785857 +-20.8558218487 -73.8504818625 64.1181801339 +-20.849080215 -71.6696165875 66.5490940013 +-20.8373040729 83.4497564022 51.0092630351 +-20.7995084898 -81.8982605797 53.4794854183 +-20.7797593659 -74.8279528497 62.9998339126 +-20.7725649414 53.6938008865 81.7647619217 +-20.7642318924 92.8938335326 30.6526078098 +-20.7619821287 92.6558563346 31.3661024833 +-20.7618251829 -70.2257518827 68.0976533192 +-20.7607765438 -76.5707867454 60.8761429009 +-20.7553531099 57.7134131022 78.9833986695 +-20.7449709136 83.7012354175 50.6334807353 +-20.7406791378 -71.4830120199 66.7832555471 +-20.7210737292 -67.9027189814 70.4262583022 +-20.7106124106 83.0657293783 51.683219099 +-20.703915322 92.8523348795 30.8186923436 +-20.7023009974 84.4755891169 49.3486532416 +-20.694422178 -40.180703556 89.2034301609 +-20.6905829619 85.3941846722 47.7465496226 +-20.6863353735 -55.0934881798 80.8503746992 +-20.6648177477 -54.5726008265 81.2083526892 +-20.662998168 56.8637428189 79.6213241496 +-20.6480929673 31.3144766728 92.6987583926 +-20.642833409 3.33601514119 -97.7892858744 +-20.6284167368 -68.2385171142 70.1282625266 +-20.6180447267 -70.2804848652 68.0848711445 +-20.6149085543 94.3901970015 25.7976017359 +-20.6110664441 -69.0064544285 69.3779012888 +-20.6105223631 15.9871599091 96.5381638833 +-20.6011932254 -43.5821612119 87.6138462904 +-20.5718300934 87.1608526262 44.4947814477 +-20.5700444085 44.354902339 87.2325392932 +-20.5620357931 -68.4500157093 69.9413899879 +-20.5540728957 83.4924510186 51.0542917912 +-20.5352760422 41.7884105135 88.4987637463 +-20.5320628123 -71.6038124134 66.7182766905 +-20.5232086714 -70.0477290365 68.3528606764 +-20.5022879815 60.3977927692 77.017938275 +-20.4989734161 -56.1070888871 80.1984205923 +-20.4972393323 6.79072202531 -97.6409200803 +-20.4903347551 95.4163583667 21.8143241397 +-20.4868845502 4.82402096292 -97.7599937765 +-20.482635264 93.784552698 28.0164117595 +-20.4801289783 4.85262133839 -97.7599937765 +-20.4720091048 4.73762752598 -97.7673346708 +-20.4716472983 17.1777516976 96.3630453209 +-20.4550985449 -58.8382195287 78.2282101688 +-20.4429314189 -58.7701485833 78.282540777 +-20.4353763168 4.81942180427 -97.7710006508 +-20.4350234403 4.89470002704 -97.7673346708 +-20.4286272168 4.84795026519 -97.7710006508 +-20.426525979 87.9167730964 43.0511096808 +-20.4189141882 48.3854509427 85.0994481795 +-20.402538023 -83.8217228175 50.5732659231 +-20.3939838511 92.3727236403 32.4247644548 +-20.3893924851 94.5443128428 25.4095569259 +-20.3700767152 64.6843516855 73.491459515 +-20.3674238643 92.6363562614 31.6808071828 +-20.3553180633 97.2657866868 11.1815815852 +-20.3529312544 -69.0198823684 69.4407231184 +-20.3502966446 77.6811800515 59.5944602483 +-20.3313895261 86.887933528 45.1344835704 +-20.3301246969 24.2973161801 94.8489665534 +-20.3213405288 89.9532625346 38.6710961637 +-20.2997007083 4.87352695575 -97.7965791128 +-20.2854690017 30.0744445699 93.1881297762 +-20.2851458104 -72.3120259729 66.02638684 +-20.2682024117 4.85848278931 -97.803860435 +-20.2558829279 97.8119589662 4.74551261763 +-20.2543829474 54.6960279909 81.2287171722 +-20.249166821 -79.9066290386 56.6118528114 +-20.249055069 97.7789884826 5.40788129848 +-20.2486710324 97.7771340401 5.4427364735 +-20.2424857401 94.9888193185 23.819445324 +-20.2362268139 -89.8683517074 38.912395014 +-20.2357248733 87.8604130112 43.2557887958 +-20.2212314465 94.4845200946 25.7638751216 +-20.2180404831 86.2000554773 46.4842045725 +-20.2174623377 94.4669087813 25.8313252067 +-20.2129113866 59.1381068367 78.0648610647 +-20.1751572008 -73.899958865 64.2787609687 +-20.1685532178 83.8147144791 50.6786256511 +-20.1670232698 -54.5770891486 81.3303910756 +-20.1637191051 97.7966218829 5.40788129848 +-20.1306296322 -92.9507542868 30.9016994375 +-20.1286179381 47.6511123824 85.5815998251 +-20.1244602066 -33.3606989273 92.0981534477 +-20.1153755033 -72.6814584234 65.6717387452 +-20.0968324655 81.207532229 54.7855275974 +-20.094654375 26.2827168717 94.3685522798 +-20.0718450457 84.7776862348 49.0903753615 +-20.0670213684 -77.5934143007 59.8044873781 +-20.0656553253 -89.9898844668 38.7193771905 +-20.0628923321 84.6739512494 49.2727341548 +-20.0582249907 -2.33145952331 -97.9399403038 +-20.0549149095 94.1086343472 27.2280247041 +-20.0545240439 -70.5421182034 67.9825391166 +-20.0529016677 -91.8169165718 34.1692107891 +-20.0397976312 -38.7765667614 89.9710196736 +-20.0377612928 -79.1884616032 57.6860093202 +-20.0330295384 -38.7800637753 89.9710196736 +-20.0245128013 82.8980158498 52.2200905326 +-20.0068360115 -50.6089033725 83.8955625301 +-20.005009704 -74.0390949572 64.171738364 +-19.9960951482 -72.5953655953 65.8032603517 +-19.9926219954 97.8298097996 5.4427364735 +-19.9924314917 97.8288776087 5.46016381259 +-19.9600822282 -90.0341126404 38.6710961637 +-19.9547177473 -82.9897516258 52.1009631841 +-19.9261580101 55.8665712817 80.5100890583 +-19.8982726938 -51.2477436673 83.5327930385 +-19.8962534242 -75.4642650972 62.5242656336 +-19.8907299696 88.4060073024 42.2934597085 +-19.8865158412 -75.1611996958 62.8913392129 +-19.8772584388 -35.9779031032 91.1618620107 +-19.8742318167 -68.8558913386 69.7415309387 +-19.8506034065 98.0065337598 0.820295548752 +-19.8406791659 -76.0063694444 61.8819784276 +-19.8250342227 -90.7735719961 36.9746757274 +-19.812137604 39.0518565615 89.902345368 +-19.8115577048 88.8503146324 41.3898993841 +-19.8098854228 78.576180977 58.5948139565 +-19.7970734475 -75.3547810559 62.6875813454 +-19.7910962125 -54.1695806822 81.6943635719 +-19.7875555062 -62.4539096043 75.5510544084 +-19.7868485521 -54.2166609836 81.6641555162 +-19.7780511168 -74.3313805306 63.9036349704 +-19.7760660096 28.0655470014 93.9214154743 +-19.7608169101 91.9410746134 34.0051307008 +-19.7596790503 -73.334396066 65.0509141939 +-19.7561110122 -29.2125899255 93.5752139592 +-19.755986662 -74.5100684022 63.70204626 +-19.7556879006 81.847713252 53.9505758171 +-19.7478462267 49.6998785714 84.4981931132 +-19.7383765211 24.462038178 94.9315815758 +-19.7370143242 -64.8400859249 73.5269577966 +-19.7368328571 79.1601129115 57.8284873795 +-19.7219443738 -74.2770067265 63.9841478951 +-19.7210723108 -73.4974124931 64.8784221735 +-19.7179654911 43.5690380312 87.8233497535 +-19.7091136765 86.400918262 46.329603512 +-19.7065123614 -57.7882994705 79.1970063504 +-19.7052082486 -80.225237236 56.3526048938 +-19.6963246666 -77.1030650807 60.5571808277 +-19.6913697103 97.9229042316 -4.83267894527 +-19.6913695923 -31.3907328446 92.8809552872 +-19.6780758752 95.0218342439 24.1583183765 +-19.6723587822 89.6989341794 39.5866076726 +-19.6714971355 97.7358188405 7.79371003014 +-19.6590068707 -92.250817197 33.2161131884 +-19.6546466999 -75.9988797701 61.950505541 +-19.6544387176 97.7392506758 7.79371003014 +-19.6544090957 85.2683827728 48.4046186062 +-19.644059575 61.4418829855 76.4133884775 +-19.6396494936 19.0520947884 96.1836880762 +-19.6380436592 -54.0431090891 81.8149717425 +-19.6282888266 -54.0162641809 81.8350382274 +-19.5890625663 -74.404471511 63.8767817516 +-19.5845507928 77.2839420466 60.3625519008 +-19.5833844617 -74.3829045587 63.9036349704 +-19.5784433556 4.02599989498 -97.9820181493 +-19.5676655601 -74.9604993503 63.2299770811 +-19.5542650476 66.9571246899 71.65454746 +-19.5538164304 24.0781334645 95.0678271124 +-19.5472933169 66.5017010309 72.0793110676 +-19.5114728746 96.7661226075 15.9881187692 +-19.4923921708 46.9428879724 86.1185921638 +-19.4905043447 -19.4905043447 96.1261695938 +-19.4852577166 84.3999237036 49.969766965 +-19.4761180818 -6.23435454987 -97.8867388762 +-19.4756699117 -70.8024982619 67.8800745533 +-19.4745189348 54.9333974858 81.2592453382 +-19.464778945 -60.881136392 76.9064991547 +-19.4599518083 -70.7453561462 67.9441304262 +-19.4554447016 -36.4062185647 91.082780597 +-19.4515391657 91.5122968346 35.3148290685 +-19.4483413947 64.1327363028 74.2209818805 +-19.4370717753 -74.2480753429 64.1047856925 +-19.4217263035 56.3408931387 80.3025548019 +-19.4134424439 -73.8945434929 64.5191033296 +-19.4115727498 -82.76166275 52.6659094883 +-19.4075659447 -60.8853097761 76.9176536145 +-19.3994106087 -60.8597249006 76.9399555047 +-19.3951304025 78.4895662217 58.8491028904 +-19.3943919266 93.4056579719 29.9873410064 +-19.3879440773 -79.9569533779 56.8418264219 +-19.3645361733 -83.017205958 52.2796160442 +-19.3625280314 64.2533560175 74.1390500932 +-19.3608666876 -44.1471491641 87.6138462904 +-19.3584002151 94.8952213557 24.9027971312 +-19.3394520066 -1.8042804727 -98.0955155349 +-19.324090283 53.8220494044 82.0351542489 +-19.3214328935 -27.8828921216 94.0703277228 +-19.3148452029 4.58363687044 -98.0098312815 +-19.3039920687 -74.3751854956 63.9975598965 +-19.3019622556 -27.8963742304 94.0703277228 +-19.2910108561 -74.3785535449 63.9975598965 +-19.2630697362 -75.5720332797 62.5923472184 +-19.2610925456 59.8835347506 77.7365588364 +-19.2602068471 -72.7940612914 65.8032603517 +-19.2512734278 -18.0465602371 -96.4557418458 +-19.2488803865 -81.939354955 53.9946544894 +-19.2475025008 -36.5525149188 91.0683660806 +-19.2475015933 -72.7974217229 65.8032603517 +-19.2439325084 -72.4767131111 66.1573663187 +-19.2371303621 -91.129061178 36.4064146031 +-19.2291926215 78.583224183 58.7785252292 +-19.2278097002 -48.3910901636 85.3732611941 +-19.2260571748 -73.6518539698 64.8518552727 +-19.2243168592 62.103733461 75.9838925793 +-19.2243147118 78.5632898112 58.8067616682 +-19.2235224455 56.6306709773 80.1462618557 +-19.219248001 -79.4428495642 57.6147043678 +-19.2102663915 -49.0692344473 84.9892692987 +-19.2039687293 95.6718923822 21.8654200292 +-19.2025895672 97.4263063718 11.805735075 +-19.1956670781 92.4485758784 32.9361075947 +-19.190988796 97.8172873468 7.96770011589 +-19.1821130727 -75.918397622 62.1968121415 +-19.181494724 -83.6166680727 51.3840741921 +-19.1712192702 60.508615879 77.2733573497 +-19.1703425494 -71.895927369 66.8092328522 +-19.1613839533 -69.4229657804 69.3779012888 +-19.1568429529 97.8239803062 7.96770011589 +-19.1489589842 85.6675179426 47.8998302645 +-19.1458387056 -68.897558216 69.9039579147 +-19.140817482 -71.2851830402 67.4688949446 +-19.1366506794 90.9672768624 36.861133203 +-19.1309490551 -42.0763026926 88.6768940591 +-19.1246426463 -59.1404427225 78.3368117696 +-19.1246330632 95.1045884292 24.2768546132 +-19.1162604895 -42.08297809 88.6768940591 +-19.0933040301 63.5606792029 74.8029798903 +-19.0717758348 -63.8528643621 74.559232019 +-19.0569087996 -63.8437216775 74.5708617985 +-19.053968958 -35.7900829066 91.4112478445 +-19.0218127943 78.5068355754 58.9478363128 +-19.0211713138 78.0279805354 59.5804439009 +-19.0209631917 89.6404455621 40.0349032557 +-19.0142849486 -80.3108573072 56.4678950066 +-19.011881056 -29.9926311987 93.4825676396 +-19.000829123 84.8656616572 49.3638325511 +-18.9914744902 -35.8232838277 91.4112478445 +-18.9679123862 73.3434752064 65.2759752463 +-18.9636585242 87.3413154827 44.8539214018 +-18.9469142999 -57.4583255863 79.6213241496 +-18.9424047257 -43.0906860095 88.2291226435 +-18.9383514822 -93.4187525865 30.236989075 +-18.9177628722 92.5702063512 32.7547728433 +-18.9099747693 24.7959460527 95.0135459478 +-18.9080794502 90.3503063294 38.46175604 +-18.8853346706 57.1709115477 79.8425388323 +-18.8824242409 -63.6236454026 74.8029798903 +-18.8706093239 68.8848480072 69.9912695896 +-18.8483416772 92.6425591189 32.5898182861 +-18.847662265 -66.2969620446 72.4532846102 +-18.8432258656 97.851484528 8.36778433323 +-18.8366904401 52.958061991 82.7080574275 +-18.8265323969 57.4978818616 79.6213241496 +-18.8199708671 58.8643321608 78.6180583316 +-18.8154491141 55.9089757553 80.7475405485 +-18.7841772183 42.1305709394 88.7252482586 +-18.7816791064 86.3577756731 46.7929814261 +-18.7703848511 -81.7590621723 54.4346250585 +-18.7562194746 87.4899471361 44.6510176944 +-18.7319645424 48.1691669101 85.6086728292 +-18.716817707 -91.4242287286 35.9345396006 +-18.7046654381 94.6388324116 26.3367972734 +-18.6984890584 81.1859709322 55.3100771174 +-18.6959962005 36.0682330069 91.3758299214 +-18.6947426725 -46.3409560427 86.6199883945 +-18.6901629097 -72.0102001909 66.8222184522 +-18.681811154 -48.364772064 85.5092904614 +-18.6768275466 91.1479271344 36.6501226724 +-18.6744514001 82.8650759912 52.7697266042 +-18.6744074785 93.8825862087 28.9365946873 +-18.6699239126 53.6730364103 82.2838933425 +-18.6665546142 -80.3417697261 56.5398954378 +-18.6664533812 42.1828619183 88.7252482586 +-18.6542954461 -46.3572526359 86.6199883945 +-18.6489682084 95.7621460408 21.9505665171 +-18.6486443689 63.0780319582 75.3219088147 +-18.6362009519 -67.6583008525 71.239359485 +-18.6357005266 24.7124573403 95.0894585014 +-18.615539778 95.7686499245 21.9505665171 +-18.6118026656 -55.5603547877 81.0348553241 +-18.5941593584 -84.4305506347 50.256734447 +-18.5821090793 95.775142139 21.9505665171 +-18.5819096665 -91.496471994 35.8205003565 +-18.5770319199 -60.1986125925 77.6596479968 +-18.5747401503 -81.5593344161 54.8001277184 +-18.5732675804 94.4941284132 26.942409447 +-18.5584707871 91.4629015882 35.9182515599 +-18.5571528647 -72.6436728304 66.1704531892 +-18.5481827578 94.10610635 28.284371374 +-18.5341394236 95.7961294841 21.8994806262 +-18.5322923793 -15.5504397003 97.0295726276 +-18.5304138974 95.5086969591 23.1238527491 +-18.529743393 88.1586799587 43.4130827946 +-18.5289767862 -55.602938587 81.0246273656 +-18.5275252855 85.8382509659 47.8385354909 +-18.5238292116 59.0013320682 78.5856893175 +-18.5163245622 97.9948787346 7.35863210847 +-18.4984000452 92.3238417148 33.6766602676 +-18.4725874872 -69.1820696359 69.8040453872 +-18.4641244365 -69.2473463111 69.7415309387 +-18.46144427 -82.1203529099 53.9946544894 +-18.4517205105 93.1879981381 31.2334918512 +-18.4135089067 55.7752529863 80.9324647101 +-18.409923865 -76.5651024663 61.6348909921 +-18.4022740434 53.2327233504 82.6294951862 +-18.3937991312 -82.0872110947 54.0680860418 +-18.3806991647 95.7195038391 22.3590358248 +-18.3588656021 -75.3110933191 63.1758757508 +-18.3587208715 83.7092141976 51.5337251359 +-18.3394169057 46.3200796564 86.7070701164 +-18.3387578149 95.0531173982 25.0717936073 +-18.3262841293 -81.1220620623 55.5279961531 +-18.3215677258 -84.5976291325 50.0755559253 +-18.3195745894 -82.4979702567 53.464736887 +-18.3112498215 93.5059783247 30.3534206887 +-18.2996402487 -78.3283141203 59.4121062902 +-18.2959552121 -75.2241774286 63.2975604037 +-18.2940392988 94.8213331955 25.9661875744 +-18.2927505732 79.3609846144 58.027660624 +-18.2877140302 -39.182414738 90.1681645086 +-18.2875788918 79.8477624915 57.3576436351 +-18.2849283449 97.5163786872 12.4986912574 +-18.2666416497 -81.9217187279 54.3613999406 +-18.2611910044 -91.5546450514 35.8367949545 +-18.2605192825 -59.5415790082 78.2390810577 +-18.2590034513 98.039217203 7.41084901954 +-18.254353292 -92.3604160524 33.7095258423 +-18.2534561299 -80.668668656 56.2083377852 +-18.250083927 97.5184610333 12.5333233564 +-18.2452873769 95.6451459198 22.7841074111 +-18.2442777927 -81.4865865226 55.0189289674 +-18.2408074024 -29.5690029496 93.7707150974 +-18.2366993906 -58.0513235703 79.3565789779 +-18.2264591962 -82.8986905136 52.8734649546 +-18.2252683134 94.8207172631 26.0167479254 +-18.1896237884 63.1434994876 75.3792813636 +-18.1715264215 16.6045193909 96.9230909707 +-18.1540608798 22.5549042199 95.7168029617 +-18.1470162149 -71.9803875623 67.0038029434 +-18.1124203941 88.7874061641 42.2934597085 +-18.1056795933 90.6100749305 38.2360914263 +-18.0917840839 80.8054857446 56.0638994563 +-18.0707478028 -69.27552635 69.8165418993 +-18.0618995493 61.17192958 77.017938275 +-18.059979867 41.2787331213 89.2743150022 +-18.0574254105 -80.2577323779 56.8561850734 +-18.0398985216 70.1590859522 68.936671806 +-18.0229673698 -58.8402625182 78.822561199 +-18.010855847 72.3990686439 66.5881666001 +-17.9996959849 -62.8551988224 75.6652821672 +-17.9927329488 -40.6603736668 89.5711760239 +-17.9926834223 60.1634387397 77.8243148526 +-17.9911160577 -56.8873805244 80.2505182542 +-17.9887254091 -62.8583394047 75.6652821672 +-17.9885042888 -48.2922202827 85.6987466281 +-17.9843225909 82.9704369333 52.8438334722 +-17.9794324745 -92.3240910225 33.9558864524 +-17.9715346353 97.6312527848 12.0483369194 +-17.9658576901 24.2794631993 95.3296156722 +-17.9639558408 98.3612602539 -1.5358293575 +-17.9541138968 97.6323182828 12.0656628871 +-17.952267697 84.6767664906 50.0755559253 +-17.9482045941 43.3307989514 88.3193286551 +-17.9470076703 97.7855545822 10.7652324982 +-17.9463282266 97.7818525845 10.7999355706 +-17.9415254391 16.2284842368 97.0295726276 +-17.9368869994 -64.3293969056 74.4311546231 +-17.9355326879 97.9155195392 9.5324551175 +-17.9249284787 97.6652545275 11.8403968307 +-17.9185996614 -82.9468917754 52.9030899945 +-17.9075362476 -60.1463133193 77.8571842519 +-17.9021740708 -82.9409911492 52.9179000974 +-17.9019418464 58.0829417071 79.4096490407 +-17.8958306534 95.6255254066 23.1408326543 +-17.8943163404 94.9755464236 25.6795448608 +-17.8903211887 -68.8297246787 70.3022432673 +-17.8894814325 78.5504500672 59.243508069 +-17.8882193698 95.4006677632 24.0566871809 +-17.8671513334 -25.2533695681 95.0948591076 +-17.8619905594 94.9861902077 25.6626764599 +-17.8576350277 -81.4244416081 55.2373531229 +-17.8549171655 95.4069061174 24.0566871809 +-17.8442227005 98.3856216036 -1.36131476707 +-17.8435749979 -25.2293848403 95.1056516295 +-17.8434001583 57.1830900405 80.0731370949 +-17.8389748296 -29.9846208772 93.7160257794 +-17.8217727226 95.5063418978 23.6838146066 +-17.8194955154 95.4941384131 23.7346815507 +-17.818018326 95.0262746321 25.5445757936 +-17.8013892717 92.6153991262 33.249035846 +-17.7999737725 -73.1293560652 65.8426777644 +-17.7983177087 92.6866886281 33.0514392713 +-17.7981728238 -80.9507323798 55.9482258102 +-17.7929610773 -81.8116704351 54.6832800472 +-17.7843822719 -53.244548649 82.7570769564 +-17.7742856432 -69.2262720102 69.9413899879 +-17.7708436994 -82.8935798031 53.0363228518 +-17.7563378683 -53.284354307 82.7374767055 +-17.7524798767 97.9771718513 9.23705874466 +-17.7418836307 77.6519456827 60.4599114862 +-17.7410073918 -62.1567503532 76.3006883472 +-17.7409234404 86.966321505 46.0664580728 +-17.7259656867 -87.3600133198 45.3212777096 +-17.7148009158 97.7692190439 11.2856384873 +-17.7044355784 92.8099015021 32.7547728433 +-17.6928980998 93.0139888056 32.1769986684 +-17.6792971698 76.0925650977 62.4288714333 +-17.6791947488 92.5021465787 33.627354213 +-17.6566824411 -80.1737466131 57.1000168056 +-17.6480902078 49.1001056603 85.3095805649 +-17.6449202224 -58.7390800487 78.9833986695 +-17.6445290619 64.7193832447 74.1624704726 +-17.6205027621 58.9189513101 78.8547719477 +-17.6193294218 80.8095414796 56.2083377852 +-17.6171292419 77.3545860488 60.8761429009 +-17.6039083119 -58.7513842115 78.9833986695 +-17.5768604732 42.5813637085 88.7574303404 +-17.5747930992 -78.9486632542 58.8067616682 +-17.5646499051 -83.639586901 51.9220817836 +-17.5637396053 -90.8655257079 37.8810148876 +-17.562251444 90.5186338725 38.7032846937 +-17.5467358477 -81.29424152 55.5279961531 +-17.5416373188 -80.4532133204 56.7412674039 +-17.5243373105 -80.1721638706 57.1429938149 +-17.5181824154 -49.4149961329 85.1543976671 +-17.5101189419 -72.3781567768 66.744274333 +-17.4927609417 -63.1624663463 75.5281812285 +-17.4784128714 -58.817599576 78.961984927 +-17.4750312498 -74.3883675142 64.5057676599 +-17.4525047365 49.7530034057 84.9708698939 +-17.4371124413 85.7061458174 48.4809620246 +-17.4329965412 87.8820525961 44.4166124676 +-17.4247060755 -81.6264681265 55.0772123421 +-17.4145049409 -23.0679174204 -95.7319497532 +-17.395416626 -82.333489187 54.0240320478 +-17.3884974692 -81.4568480118 55.3391549243 +-17.3859432644 -80.9602875153 56.0638994563 +-17.3845518848 97.7940270142 11.5803987891 +-17.3789256074 -65.776593363 73.2899222969 +-17.3741167023 57.4733376325 79.9684658487 +-17.3597812283 -0.418200640068 -98.4807753012 +-17.3566794434 -77.5222005099 60.7375839723 +-17.3419003432 91.0821469564 37.4606593416 +-17.2997732917 32.0889033498 93.1183125162 +-17.2973327215 54.4621338441 82.0650854984 +-17.2934642952 -75.085568957 63.7423989749 +-17.2917756184 -80.6589268587 56.5254987944 +-17.2807589481 -76.8057735485 61.6623752364 +-17.2716926391 -88.6898585695 42.8462089374 +-17.2713203202 -30.8780743235 93.5320587845 +-17.2691871162 3.05123951019 -98.4503179974 +-17.250613887 -48.1790961121 85.9138581274 +-17.2481461826 94.9104179166 26.3536339841 +-17.2427988456 97.0949558358 16.5908239462 +-17.2191127651 94.9390254367 26.2694424132 +-17.2129309809 97.1236838439 16.4531165327 +-17.2110621346 25.9243591104 95.0352931542 +-17.197967059 -76.8133245221 61.6761145412 +-17.19736081 -82.1043383501 54.4346250585 +-17.190203622 92.0327021794 35.1351480571 +-17.1791667957 -81.520988693 55.3100771174 +-17.1641676065 75.3656888045 63.4460739636 +-17.1486488128 84.4391612057 50.7538362961 +-17.1384941516 89.419113608 41.3581206025 +-17.1132344815 -61.4998725228 76.9733907611 +-17.1040676527 55.4942348127 81.4115518356 +-17.09799356 86.7484228151 46.7158405181 +-17.0877373993 97.4063629043 14.832723834 +-17.0829074695 -81.9140979024 54.7563223493 +-17.0695626802 94.2081043187 28.8697611798 +-17.0659651643 94.1882493781 28.9365946873 +-17.0514708752 -81.4786938568 55.4118199338 +-17.0372499008 -81.4816686589 55.4118199338 +-17.0304356314 -68.9716423929 70.3766780108 +-17.0302958605 95.3184327271 24.9873048837 +-17.0266234849 95.8776629076 22.75011754 +-17.0225781873 82.1989209297 54.3467499475 +-17.0160091575 -70.2284817714 69.1260861067 +-16.9950567894 -69.2958886387 70.0660250228 +-16.9898246525 94.7099811477 27.2280247041 +-16.9845433652 -66.8767994702 72.3810678237 +-16.9844640357 92.2689428216 34.6117057077 +-16.9584334872 96.1760555251 21.5076237017 +-16.9258567826 -73.4308738498 65.7375245794 +-16.9249462321 50.0601331509 84.8971687629 +-16.9199119669 59.5951484252 78.4992666412 +-16.9184279307 97.238804355 16.0742565604 +-16.9064791872 -81.2810330456 55.7455346062 +-16.8998827622 -92.0802196462 35.1514880558 +-16.8956062588 -82.8964336842 53.3171620737 +-16.8808011673 -75.5203631734 63.3380872628 +-16.8800195976 -79.2781635649 58.5665238866 +-16.8663362973 4.47832998264 -98.4655841422 +-16.8655278552 -92.0740382227 35.1841648405 +-16.8640540212 96.1312857075 21.7802568899 +-16.8527521149 68.0988117341 71.2638518925 +-16.8376014452 -74.592913496 64.4390598453 +-16.8222634983 92.7509636504 33.3806859234 +-16.8156058227 88.7393716322 42.9250430767 +-16.8063888682 -81.0125628826 56.1650242447 +-16.8058104245 -81.7266805823 55.1209072583 +-16.7975104484 97.960617504 11.0254732764 +-16.7764840829 93.5207115851 31.1837471518 +-16.7761210181 -81.0088242748 56.179463803 +-16.7650627138 -82.84689698 53.435234939 +-16.7622783922 52.937551699 83.1663492238 +-16.7595053346 61.1785214687 77.3065811677 +-16.7401734752 96.2142853984 21.5076237017 +-16.7338848203 -82.1029652349 54.5809508754 +-16.718169532 86.5720794757 47.1781502685 +-16.7140144744 34.0123062749 92.5408274331 +-16.7139407136 93.8315275034 30.2702598633 +-16.7099256808 96.439065202 20.5008557553 +-16.7082720782 95.5371702767 24.3615011786 +-16.6960902569 -84.3214174466 51.0993065504 +-16.677743537 -77.2681895296 61.2493245459 +-16.6612527991 96.4583656454 20.4496051842 +-16.6525310373 -82.4388223068 54.0974471368 +-16.6311573348 -61.2973869782 77.2401123468 +-16.6220178049 -71.4288660091 67.9825391166 +-16.6063111521 -70.1402702725 69.315026625 +-16.6022340672 81.7486400283 55.1500288078 +-16.5945022401 -79.9911966083 57.6717518425 +-16.5784977374 -79.9842343308 57.6860093202 +-16.5680867985 98.4789722564 5.23359562429 +-16.5675615816 97.74579484 13.0872263805 +-16.5607905928 36.7122483221 91.5311479119 +-16.5351798295 84.1250684289 51.4738835705 +-16.5255055882 80.5059857844 56.9709918989 +-16.5247284779 50.707275341 84.591403678 +-16.518623419 76.5309840793 62.2104778651 +-16.5162823612 -82.0594573789 54.7125019684 +-16.5094940353 -65.2448851643 73.9631094979 +-16.5089845872 -85.5690699408 49.0447519859 +-16.4906622032 -79.9818251622 57.7145190037 +-16.4705044929 -75.667444478 63.2705328563 +-16.4695209936 -59.7922188732 78.445174743 +-16.4681984778 -78.1472022403 60.1815023152 +-16.4649379492 -68.4235531536 71.043107985 +-16.451318886 -72.4107505198 66.9778867692 +-16.4409189555 -78.1529459649 60.1815023152 +-16.4214452372 -81.5882688416 55.4408741251 +-16.4190033293 -69.9478623126 69.5536691165 +-16.407205148 -81.5911336818 55.4408741251 +-16.4028042532 -60.1647893819 78.1738199863 +-16.3990392349 -43.3301704791 88.6203579231 +-16.3926802144 -68.0188792614 71.4472679633 +-16.3887452395 39.60502771 90.3484964433 +-16.3830599698 35.9493440873 -91.8653362576 +-16.3719047101 78.5733904928 59.6505074801 +-16.3643068217 -75.1795598239 63.8767817516 +-16.3427346487 -43.3183740454 88.6365246062 +-16.3383079824 59.3158530403 78.8333005168 +-16.326438341 97.5629484361 14.6600990296 +-16.3232504455 78.4770527431 59.7904983058 +-16.3083019659 -82.3629434649 54.3174449951 +-16.3018276091 -56.5901997344 80.8195502996 +-16.2899601383 94.1129335863 29.6208192067 +-16.2872361697 -81.2881227796 55.9192903471 +-16.2832588918 80.2498289136 57.4005264714 +-16.277074761 66.2683777676 73.0996507877 +-16.2765921177 -32.0551786521 93.3141900818 +-16.2736511102 61.4629726759 77.1846569558 +-16.2685050355 94.1845986098 29.4040325232 +-16.262655734 -69.8845995117 69.6539214946 +-16.2621101336 76.0502241188 62.8641963719 +-16.2434737242 93.0709078852 32.7712628196 +-16.243292165 -61.9157470551 76.8283523594 +-16.2290894812 -70.0170875326 69.5285848271 +-16.2158369835 87.7492166561 45.1344835704 +-16.2155714147 -94.3690669037 28.8363391474 +-16.215171347 89.9399872859 40.5939269498 +-16.2147188502 -94.3641052705 28.8530506031 +-16.212813437 60.0040715471 78.3368117696 +-16.1819194548 -57.6462479729 80.0940420843 +-16.1718580401 -57.6490713727 80.0940420843 +-16.1484937084 -81.7805659734 55.2373531229 +-16.1326355586 -61.6253906084 77.0846891561 +-16.1268072355 92.5932601827 34.1528074559 +-16.1145215607 56.570467468 80.8709119852 +-16.1073945887 -88.6332673539 43.4130827946 +-16.0813752128 -67.3461116173 72.1518580586 +-16.0765884368 73.3035048816 66.0919017453 +-16.0764241618 -91.3604055124 37.3473545352 +-16.0758249434 57.8499120327 79.9684658487 +-16.074671718 97.4157441119 15.8675054211 +-16.0632051621 95.6821381638 24.2260577957 +-16.0598348428 -82.2374702089 54.5809508754 +-16.0556463726 -86.2922626323 47.9151503112 +-16.0551373679 92.660043439 34.0051307008 +-16.0542475639 -48.0368065699 86.2248592329 +-16.0515643919 -77.1708716716 61.5386370179 +-16.0514270091 -79.6062072797 58.3541211356 +-16.0510804237 92.6366293368 34.0707751944 +-16.0411159163 97.4240804207 15.8502730052 +-16.0321716745 -34.1784238695 92.6002419716 +-16.0262356989 79.2670434332 58.8208772008 +-16.0262061701 -34.1812214908 92.6002419716 +-16.0231749098 -74.2984403539 64.984610692 +-16.0193783277 37.6114649619 -91.2620250784 +-16.0193449952 -34.1665877505 92.6068294858 +-16.0074903711 77.8444489995 60.6959801962 +-15.9956637373 -88.5454333058 43.6330721162 +-15.9948981804 48.5630459393 85.9406411501 +-15.988993457 -78.5884136099 59.7345238075 +-15.9887384876 -86.0997724577 48.2823924874 +-15.9887186791 -80.8971255089 56.5686835572 +-15.9883705019 -76.665693409 62.1831445234 +-15.9846901362 -82.618966603 54.0240320478 +-15.9695511976 -80.8001449946 56.7125206934 +-15.9385510971 -69.9841617443 69.6288711231 +-15.9257416435 88.6891692184 43.3659084588 +-15.9237550868 90.9577838613 38.3811878264 +-15.9105748045 -84.6089846294 50.8740929096 +-15.8947801244 97.5976100112 14.9017611339 +-15.8906423603 -51.5572702572 84.1981910079 +-15.8900756468 44.2089984818 88.278366258 +-15.8762436036 94.5684823585 28.3680636181 +-15.8751614202 -85.9057093584 48.6640354832 +-15.8715077845 -93.0476996004 33.0184923902 +-15.8465709777 -71.3613700368 68.2381202461 +-15.84526939 51.6019754433 84.179353575 +-15.8369178089 -82.6282134376 54.0534030235 +-15.8228638228 98.565114317 5.87836883186 +-15.8067312091 -88.6488634954 43.4916802325 +-15.7827427562 59.6509659871 78.6935021961 +-15.7803008508 25.4014971879 95.4240328516 +-15.7471391289 22.8267776661 96.0779154158 +-15.7432135172 98.6187878334 5.1464467756 +-15.7365328439 -94.0378121884 30.1537959944 +-15.7291565881 -81.9113054908 55.1645870628 +-15.7179464761 -75.23756613 63.9707339446 +-15.7130353687 -64.8014266698 74.5243290547 +-15.710911677 -64.8420827767 74.4894056592 +-15.7045377421 93.6457960045 31.3661024833 +-15.6875286161 97.0724130786 18.1892293686 +-15.6870827895 -93.0438524933 33.1173209479 +-15.6767925083 -75.7003676906 63.432582386 +-15.6733913676 78.6519641747 59.7345238075 +-15.6503671405 -75.7058353115 63.432582386 +-15.6308234521 86.0108657776 48.5572685227 +-15.6185232846 -81.4887524906 55.8179625922 +-15.5939862631 97.9035183363 13.104529362 +-15.5857004869 -92.9371721953 33.4629341909 +-15.5697636078 91.858956541 36.3251230473 +-15.5674111047 -85.8322295122 48.8925770283 +-15.5596970604 -83.9526127164 52.056264229 +-15.5475809662 98.7210629293 3.52483477781 +-15.5470766399 -80.5077823805 57.2432125595 +-15.5450443284 -83.9553271172 52.056264229 +-15.5116342668 98.7170295838 3.78645910098 +-15.4999132519 -79.5178294509 58.6230968869 +-15.4988260401 -79.8089127526 58.2264874145 +-15.4736533956 -74.5883204635 64.7854034566 +-15.4732968309 82.8407475724 53.832960413 +-15.4679789336 -71.724032014 67.9441304262 +-15.464644425 -80.5338294341 57.2289008237 +-15.4532483099 97.7888825228 14.0901231938 +-15.4401096824 85.2150398286 50.0 +-15.4326874871 64.0355386144 75.2414908896 +-15.4309031588 98.7652296071 2.70493038153 +-15.4306419935 -79.9048461898 58.1129145979 +-15.4281002433 -62.8119726778 76.2668329696 +-15.4082260352 -83.952821309 52.1009631841 +-15.3982074918 36.3994816634 -91.8584396813 +-15.3932946568 47.4602302667 86.6635622545 +-15.376564455 24.9259624147 95.6151539415 +-15.3747130467 -82.9545282936 53.6857935987 +-15.3667673854 -73.7494528443 65.7638248986 +-15.360960567 -29.1346541759 94.4204046619 +-15.3519961581 58.4352183333 79.6846376179 +-15.3519774039 97.8122864431 14.0382837472 +-15.3440639311 -82.2283752979 54.8001277184 +-15.3153127448 90.2621224869 40.2267378703 +-15.3115180611 -74.4599346416 64.9713440513 +-15.300554594 -75.0035901175 64.3455864734 +-15.2990564092 -85.2847733115 49.9244059975 +-15.297201669 36.3550759504 -91.892894577 +-15.2912496697 67.4135999927 72.2605301639 +-15.2864489209 94.0692752115 30.2868938746 +-15.2341481842 53.7289439074 82.9525244685 +-15.2330815879 -58.4807009072 79.6740914397 +-15.2328819818 -93.5334030025 31.9290123445 +-15.2302728151 -93.4146140742 32.2761315426 +-15.2274990446 -93.5003505289 32.0282332298 +-15.218359793 59.2715980677 79.0903229713 +-15.216832476 94.4738650691 29.0368184947 +-15.207157706 -67.7551207047 71.9582238024 +-15.199269529 -32.8490511524 93.219751363 +-15.1976691755 59.2769066663 79.0903229713 +-15.1926511338 36.9883345538 91.6572226203 +-15.1876339271 -78.3526123952 60.2511734868 +-15.1838983073 84.3885588275 51.4589192581 +-15.1801063611 -59.9911962289 78.5532987588 +-15.1700727936 79.9030750594 58.1839108989 +-15.1660382868 -66.7535668338 72.8968627421 +-15.1603551112 83.1744673084 53.4057264801 +-15.1554638389 -81.931164089 55.2955356864 +-15.1361029674 36.9423580015 -91.6851164162 +-15.1355862223 59.2927891231 79.0903229713 +-15.1328480013 55.6213903334 81.7144898335 +-15.1251723032 54.6136307337 82.3928425343 +-15.1029386575 66.6373149362 73.0162276621 +-15.0973876651 -55.1867546672 82.0151875874 +-15.0951505196 -93.5104782015 32.0612990586 +-15.0928268538 98.6320651655 6.62739004 +-15.0885511616 80.237641254 57.7430216549 +-15.0836502404 92.4137460389 35.1024648492 +-15.0668394911 -48.7333075333 86.0119473365 +-15.0642865891 79.1197929721 59.2716258391 +-15.0622904814 98.6628320861 6.2267945373 +-15.0505864336 -43.2923706857 88.8777277411 +-15.05019236 -39.9979892484 90.4082549661 +-15.049634437 -55.1255861234 82.0650854984 +-15.0306779823 -93.1110878291 33.2325750233 +-15.0210771508 -80.8103185901 56.9566471151 +-15.0181420555 59.3511195255 79.0689573744 +-15.0177167063 37.0769644297 91.6502421907 +-15.0093393484 -79.0564676163 59.3699811383 +-15.0045223787 -44.533607014 88.2701657102 +-15.0038134761 61.9237467172 77.0735698776 +-14.9975110816 69.5425025832 70.2774145499 +-14.9949273038 -61.745787893 77.2179372467 +-14.9868244355 -81.6567845608 55.7455346062 +-14.9838946994 -80.2982392605 57.6860093202 +-14.9772717341 76.4810954893 62.6603811364 +-14.972728558 94.3209856959 29.6541574976 +-14.9722828835 90.4402293786 39.9549202878 +-14.9521766925 -80.2836640191 57.7145190037 +-14.9399668604 37.8304686518 91.3545457643 +-14.9267606258 37.8356813792 91.3545457643 +-14.9179422674 87.2735568415 46.4842045725 +-14.8811082482 -44.6561813735 88.2291226435 +-14.8779956146 93.618685773 31.8463015219 +-14.8778470684 45.7078580583 87.6894599045 +-14.8654005901 -93.1199837475 33.2819544523 +-14.8611249277 -38.2548452323 91.1905355952 +-14.8550393178 -71.7322716252 68.0720868959 +-14.8482244455 36.7137426023 -91.8239148313 +-14.8228941646 -82.382182157 54.7125019684 +-14.8205047682 94.9670591249 27.5972882649 +-14.8181326477 60.9250419849 77.9009769128 +-14.8156949896 52.6379739228 83.7241833838 +-14.7931484651 2.40921721519 -98.8704123128 +-14.7869059752 83.8607110256 52.4283182828 +-14.7779736774 93.5157128702 32.1935232675 +-14.7625277294 93.5238393766 32.1769986684 +-14.7612530172 97.3743356523 17.3304404339 +-14.7561065039 92.8517075691 34.0707751944 +-14.7548040075 -87.5142833163 46.081948465 +-14.7444516853 -75.8536281308 63.4730513202 +-14.7373643692 -63.8345382158 75.5510544084 +-14.7312307037 89.1773269673 42.78311813 +-14.7195923556 -81.157709583 56.5398954378 +-14.7180066708 -69.1241223658 70.7476924486 +-14.7049397324 -86.0274406874 48.8164336698 +-14.6937203516 97.3876066186 17.3132509753 +-14.6737321257 -77.5102200591 61.4560604976 +-14.6689978068 60.1746473157 78.5100778485 +-14.663380756 60.288776558 78.4235212544 +-14.6628172124 -67.9905484532 71.8490578396 +-14.6594956777 -63.6492813004 75.7223096347 +-14.6383550618 44.4443660302 88.3765630089 +-14.6283032223 60.4661583122 78.2933997461 +-14.6228024551 -79.6733847713 58.6372356736 +-14.6212883006 -84.9132853543 50.7538362961 +-14.6176722033 37.9219906951 -91.3687379856 +-14.6174805401 -74.9907632193 64.5191033296 +-14.6030191524 96.5579644049 21.5246682117 +-14.5901127171 -87.4683951543 46.2212987705 +-14.5874572369 -87.4524754286 46.2522500293 +-14.5792106422 59.1330992239 79.3140794136 +-14.5478757798 -52.1046360415 84.1039012964 +-14.5309501599 -74.6161908678 64.9713440513 +-14.5259397071 -90.3854018839 40.2427161349 +-14.5108177686 95.6096995466 25.4601948206 +-14.5106161705 25.4398182991 95.6151539415 +-14.5086731744 -70.3689243569 69.5536691165 +-14.5059835494 89.3649845376 42.467351929 +-14.4703622048 97.9931010335 13.7098784642 +-14.4647365784 90.5086617633 39.9869171297 +-14.4546520267 43.2004011538 89.0212804611 +-14.4543958453 -30.9975519219 93.9692620786 +-14.4521402392 -70.4053374003 69.5285848271 +-14.4510456122 78.9704138614 59.6224874966 +-14.4497772123 -33.6813810646 93.0417567982 +-14.4477027673 -57.9465707925 80.2088450119 +-14.4457492543 -38.9057889795 90.9816460192 +-14.4390627231 -83.1605140418 53.6268810577 +-14.4296056999 76.5863115392 62.6603811364 +-14.4104886544 -75.3281209913 64.171738364 +-14.4013610954 87.7517901996 45.7408364087 +-14.3638382362 50.5921705333 85.0535856496 +-14.34891777 37.0320540773 -91.7754625684 +-14.3260864967 -87.9654699186 45.3523907604 +-14.3250883448 97.9555268457 14.1246806796 +-14.3128499928 63.5111242035 75.9044098026 +-14.2978669016 -92.0398140254 36.3901585079 +-14.2960167135 -76.2428899503 63.108205791 +-14.2847946927 37.6049874388 -91.5522231315 +-14.2830804948 -92.7986640681 34.4151356056 +-14.281530428 58.2756813624 79.9998928149 +-14.2801917419 72.9890161634 66.8481835454 +-14.2609770273 -90.4489048172 40.1947776656 +-14.2577680127 -72.8744038413 66.9778867692 +-14.2539897122 58.7842417082 79.6318824597 +-14.2424151523 94.7326392963 28.6858965796 +-14.2371562888 -81.323794385 56.424674103 +-14.2263786679 49.0633894269 85.9674006117 +-14.2210687804 -25.1049742451 95.7470702993 +-14.2125602619 97.7819540461 15.3848169873 +-14.1965825107 -91.5985966706 37.5253798515 +-14.1938308822 -83.2122146198 53.6121488374 +-14.1868296771 -82.7355101142 54.3467499475 +-14.1849147407 97.8316539923 15.091576158 +-14.1546650276 21.466676294 -96.6376079321 +-14.1405944149 -75.196612957 64.3856582585 +-14.1393378962 37.6769866864 -91.5452008468 +-14.1338333705 -26.0312828099 95.5123398809 +-14.1286105461 21.4434462784 -96.6465776722 +-14.107427412 37.6718851599 -91.5522231315 +-14.0875798379 -86.7873832961 47.6391666061 +-14.0829017986 76.5060621332 62.8370458711 +-14.0649345521 79.929349416 58.4249665637 +-14.0645930491 76.6319409087 62.6875813454 +-14.058389246 52.4666229388 83.9619864534 +-14.0557963986 61.7172240194 77.4171741084 +-14.0495018114 37.1809276866 -91.7615939008 +-14.0363226297 -75.5125409551 64.0377842023 +-14.025682269 -76.0461107362 63.4055934345 +-14.0239237089 -75.0811114555 64.5457687724 +-13.9977206553 -62.214036205 77.0290692891 +-13.9952497901 33.8376231903 93.0545444358 +-13.985378959 78.2760566455 60.640482612 +-13.9780524898 77.299642913 61.8819784276 +-13.958927866 -74.0171485557 65.7769720534 +-13.9472586413 -49.1902447147 85.9406411501 +-13.9378525212 81.9704424102 55.557023302 +-13.9211436259 34.0787121682 -92.9776485888 +-13.8891154134 -62.2383720665 77.0290692891 +-13.8881324728 -86.0333195864 49.0447519859 +-13.8666890887 95.9907922357 24.3615011786 +-13.8554054249 -84.4251193982 51.7728399366 +-13.8535760121 88.9750087509 43.4916802325 +-13.8081968887 31.0574722261 94.0466220425 +-13.806202774 54.441700133 82.7374767055 +-13.7840949339 -65.8085857944 74.0218127487 +-13.750155872 -93.4544440284 32.8207267568 +-13.7302720264 59.2364506606 79.3884282702 +-13.6968904056 85.5125440694 50.0 +-13.6875568686 -77.8643756451 61.2355272073 +-13.6857062864 -77.8538482422 61.2493245459 +-13.6760805058 -79.4239811598 59.2013178799 +-13.6716733586 -92.92102901 34.3331867922 +-13.6697935933 -85.5345493504 49.969766965 +-13.6645133363 -23.6867221622 96.1884622421 +-13.6533243952 -73.0970013763 66.8611630377 +-13.6384255366 -73.087910643 66.8741404933 +-13.6225072897 54.3539101005 82.8255984098 +-13.6044649668 24.7976651519 95.9166009405 +-13.5895281654 -86.2881928778 48.6792819803 +-13.5811236315 90.0134951542 41.3898993841 +-13.5723281229 86.8694521359 47.6391666061 +-13.5660681569 58.3890249954 80.0417613178 +-13.5508576293 -83.2053861629 53.7888275667 +-13.5411910001 -93.3919686359 33.0843821252 +-13.5387168396 -75.8525524901 63.7423989749 +-13.5095861285 -61.0891591118 78.0102924084 +-13.4834588824 63.4346866382 76.1198848376 +-13.4812078171 -87.7926258732 45.942484457 +-13.4539936921 -95.008125776 28.1504190071 +-13.4531038705 53.5590515014 83.3693108915 +-13.4472260146 66.2728262324 73.6687492475 +-13.437237397 60.4616268997 78.5100778485 +-13.4263144877 90.1604734985 41.1196193781 +-13.4189089575 -72.0509930027 68.03372171 +-13.4100507049 -86.1264541212 49.0143289315 +-13.3942221509 -85.3388107105 50.3773977046 +-13.3643058767 -15.926959541 97.8147600734 +-13.3616644644 60.5204626988 78.4776370533 +-13.3573238501 -87.0871802506 47.301214948 +-13.3544714002 86.2646371549 48.7859659139 +-13.3517108072 89.5522066774 42.4515500038 +-13.3499139909 -66.0297422318 73.9043499209 +-13.3326984373 -81.5965232664 56.2516359159 +-13.3318623468 -81.1463906997 56.8992506345 +-13.3290204597 -76.5295598429 62.9727217439 +-13.3209976369 -79.3478962329 59.3840246647 +-13.3071486136 -79.350219977 59.3840246647 +-13.2922523289 57.2558386206 80.9016994375 +-13.2733976337 -43.4153274063 89.1006524188 +-13.2729872544 99.0806514064 2.61769483079 +-13.2516761019 -81.189699466 56.8561850734 +-13.2219918153 -83.9544806926 52.6955795497 +-13.2104370384 95.5700274954 26.3031214458 +-13.1984827408 80.3345556135 58.0702955711 +-13.1981996348 -76.171615568 63.432582386 +-13.1881449901 57.0332956669 81.0757424702 +-13.1768572108 -75.6559032605 64.0511884034 +-13.1312089836 -74.4707867785 65.4344960034 +-13.1083687296 94.1049657713 31.1837471518 +-13.0715215015 60.6118117091 78.4559979031 +-13.0667578137 64.9208479518 74.9302565154 +-13.0610505878 -65.0686034664 74.8029798903 +-13.0529840817 -90.5814342912 40.3066169295 +-13.0404373316 -80.514091672 57.8569618666 +-13.0135031073 -65.3041550595 74.6057375062 +-13.0074966306 -88.6216711968 44.4635179185 +-13.0002113821 -86.1633025364 49.0599612724 +-12.9973825533 72.0920178134 68.0720868959 +-12.9895201133 77.2083467704 62.2104778651 +-12.9871126172 -83.1237903819 54.0534030235 +-12.9641593761 -86.5385663693 48.4046186062 +-12.9637095598 -84.5208908475 51.8474806022 +-12.9621053922 75.0425863244 64.8119901063 +-12.9619723311 -58.9544310911 79.7267980545 +-12.9569843593 -1.25902858999 -99.1490363207 +-12.9510200267 -79.7855381879 58.8773214093 +-12.9509320762 -84.9321162853 51.1743000114 +-12.9472076199 -85.40777257 50.3773977046 +-12.9212843864 -84.936631839 51.1743000114 +-12.9196980578 84.6281647306 51.683219099 +-12.8944841672 -59.0404220117 79.6740914397 +-12.8881092418 -80.9152463126 57.3290463408 +-12.8853241607 -81.5389376621 56.4390827903 +-12.8837864064 -81.5292066805 56.4534897583 +-12.8772062534 -88.8125455526 44.1192623644 +-12.8742685354 57.9285159439 80.4893797356 +-12.8724846607 -94.3387669195 30.5695304963 +-12.8637902658 -88.9386240632 43.8684858384 +-12.862609241 -74.6218564492 65.3156323064 +-12.8600125801 87.6168442569 46.4532956732 +-12.8578069683 93.5001559467 33.0514392713 +-12.8433791827 68.1019569729 72.091407724 +-12.8410669487 -86.2304154561 48.9838999048 +-12.815803966 -86.060769312 49.2879209759 +-12.8084527167 -86.2179743348 49.0143289315 +-12.7970153809 -75.9021691561 63.8364873308 +-12.7873108082 -67.288616508 72.8610099486 +-12.7862938575 -72.5146758945 67.6618982095 +-12.7804454016 94.9004179426 28.8196268134 +-12.7755665345 -67.2908472899 72.8610099486 +-12.7547487968 -70.3243794832 69.9413899879 +-12.7353242857 -53.9583361409 83.2244523938 +-12.7216662568 81.4248055286 56.6406236925 +-12.7141780453 95.0352698547 28.4015344704 +-12.6923681894 -83.9243736553 52.8734649546 +-12.6890478238 -91.6800976826 37.8648617352 +-12.683165172 99.0075929643 6.0525909032 +-12.682086411 -68.8960630994 71.3617346599 +-12.6744821693 84.1039234138 52.5917062677 +-12.6694237574 -91.6561029226 37.9294674192 +-12.6655555406 -68.8737721549 71.3861836212 +-12.6616266412 -88.63251745 44.5416665749 +-12.6482987318 28.2491667329 95.0894585014 +-12.6455507469 -91.7194278464 37.7840786818 +-12.6399119145 79.0903799725 59.874405405 +-12.6390725382 90.8519297224 39.8268842755 +-12.6364020172 -84.5521401872 51.8773258161 +-12.6326031473 -80.3946919558 58.1129145979 +-12.5886214555 80.2060747831 58.3824646426 +-12.5682402888 -73.9155630485 66.1704531892 +-12.562722264 -88.049945259 45.7097927059 +-12.5453146454 -76.8619997907 62.7283673359 +-12.530345705 -86.1027948582 49.2879209759 +-12.5228655708 -65.2141938856 74.7682202125 +-12.5005670326 58.9116538047 79.8320290977 +-12.4949834998 -78.1835347772 61.0836334633 +-12.487348848 -51.2251636231 84.9708698939 +-12.4811447123 98.7984336331 9.1154011602 +-12.4713714861 78.5636396859 60.5988400266 +-12.4694671323 -51.2295194093 84.9708698939 +-12.4645034055 -75.8670797007 63.9439001981 +-12.4548759419 -75.8912753715 63.9170586601 +-12.451733217 -82.8220171118 54.6394346734 +-12.4436883558 90.4887438966 40.7055505812 +-12.4430342401 -88.8744146947 44.1192623644 +-12.4352745668 80.7932761802 57.6004381105 +-12.4335688983 -71.610048435 68.6833846544 +-12.4307792254 36.8734350661 92.1185405566 +-12.4253187794 -64.0420668686 75.790666473 +-12.4195216689 91.2569194636 38.9606228328 +-12.4189448664 -7.52710662727 -98.9399437751 +-12.4149420283 -81.3218508971 56.8561850734 +-12.3873898242 89.6157472045 42.6095109843 +-12.3851613073 -87.7914411923 46.2522500293 +-12.3760081767 -87.5057215893 46.7929814261 +-12.3584833277 -61.4573083105 77.9119191464 +-12.3530478253 54.2406704206 83.0984469274 +-12.3495047371 -87.6492839108 46.5305573002 +-12.336924194 -75.0905495898 64.8784221735 +-12.3265841856 94.2653015387 31.0178698193 +-12.3047127568 -85.0732326531 51.0993065504 +-12.2915361535 57.5800062115 80.8298275618 +-12.2730009909 92.5981959852 35.7064076459 +-12.2723521498 94.8808140178 29.1036166828 +-12.2645961848 -80.4311306113 58.141318432 +-12.2568399617 -82.0124311719 55.8903480703 +-12.2468173803 -94.0382529309 31.7304656405 +-12.2440120968 -82.1226820809 55.7310439129 +-12.2296497599 -82.026351432 55.875874378 +-12.2220518541 -62.353922217 77.2179372467 +-12.2128461244 -84.7512807646 51.6533328867 +-12.2063313781 18.4277757586 -97.5265223151 +-12.1616515762 -85.9900932271 49.5761847839 +-12.1532355055 -92.8136488412 35.1841648405 +-12.1370362829 -92.8157685673 35.1841648405 +-12.1340513039 -86.0114636412 49.5458668432 +-12.1320330533 37.9004604931 -91.7407699357 +-12.1052320605 -55.287759737 82.4422645251 +-12.0923635448 -77.4856336997 62.0463642292 +-12.0905475217 -83.182575157 54.1708210283 +-12.075209326 -79.1891329994 59.8604254456 +-12.0687936129 -87.8761992947 46.1748613235 +-12.0654341522 -84.2490432595 52.5026095407 +-12.0623231584 67.5127283713 72.7772757657 +-12.0603007511 -81.4753897959 56.7125206934 +-12.0486353109 55.1675045078 82.5310658693 +-12.0372791057 -83.7399793416 53.3171620737 +-12.0363603068 -78.2014886161 61.1527040186 +-12.0281281089 -92.6114564476 35.7553110579 +-12.0246253635 -81.4306035647 56.7843745053 +-12.0211350098 94.7580428902 29.6041487076 +-11.9577135237 -60.2253472751 78.9298462742 +-11.9468828287 -85.3306515381 50.7538362961 +-11.9413444888 -88.9043307182 44.1975595633 +-11.9379030809 -76.9365167503 62.7555484428 +-11.9111483633 -87.1798167459 47.5163560978 +-11.8998315926 1.21503617383 -99.2820109343 +-11.8890359785 -95.4508831389 27.345561459 +-11.8826864926 75.881249042 64.0377842023 +-11.8724434107 -85.8904016502 49.8185105339 +-11.8700615542 -85.8731702678 49.8487739754 +-11.8676842337 -78.6570954102 60.5988400266 +-11.8657994156 -80.1614033162 58.5948139565 +-11.8622318064 84.6184754087 51.951911188 +-11.8582351788 -73.6219782932 66.6272209433 +-11.8576489588 81.9822899188 56.0205346355 +-11.8544910398 -74.846310758 65.2495272634 +-11.8416872197 -34.2547479883 93.2007869283 +-11.8390409877 -87.6786839912 46.6077834922 +-11.8338365628 93.4122201076 33.6766602676 +-11.8196496435 83.0491870944 54.4346250585 +-11.8099207253 60.8702075361 78.4559979031 +-11.8079929546 60.3530963866 78.8547719477 +-11.8027662942 -83.2429891281 54.141476419 +-11.8012385025 -89.278056525 43.4759633927 +-11.7757078465 -89.2047516807 43.6330721162 +-11.7644365636 -83.181547385 54.2441536663 +-11.7535420053 88.6789455111 44.6978620671 +-11.7473747599 -60.4350039981 78.8010753607 +-11.7437532819 -87.2025238284 47.5163560978 +-11.7307344894 91.5727083697 38.429532266 +-11.7232178973 81.1528235985 57.2432125595 +-11.7131270372 -62.5885408047 77.1069206683 +-11.704232493 -56.6171189216 81.5935829999 +-11.6972441529 -93.9110863746 32.3091679739 +-11.6887833923 -71.2232448815 69.214317387 +-11.6692024621 27.1346848363 95.5381525503 +-11.6689783297 -84.855162024 51.6084917685 +-11.6666327121 -20.7472504843 97.1259042609 +-11.6636277771 -92.3271207422 36.6014011008 +-11.6593898448 -20.7513216433 97.1259042609 +-11.6557678784 -20.7533562746 97.1259042609 +-11.640593705 -85.5334650208 50.4828974973 +-11.6374518196 89.6034156427 42.8462089374 +-11.6356946211 83.5326398445 53.7299608347 +-11.630074552 -73.846428214 66.4187202975 +-11.6297792436 51.3962288385 84.9892692987 +-11.6246843867 97.0552724672 -21.0983601077 +-11.6150765683 -89.1873761345 43.7115766651 +-11.6054225094 -42.9222389219 89.5711760239 +-11.6053807966 79.0688839119 60.1117853128 +-11.5939929582 26.5123714402 95.7218548081 +-11.5893071022 49.0262191116 86.3835505204 +-11.5815445858 -84.5473373606 52.1307545528 +-11.5793274648 58.5872030167 80.2088450119 +-11.5760375236 -85.9571606926 49.7731039913 +-11.5683076333 -85.561048536 50.4527623815 +-11.5677876135 -88.7033675593 44.6978620671 +-11.5635323081 -87.7154446976 46.6077834922 +-11.5501908267 -85.6522178626 50.301994663 +-11.5492845004 -87.7255252429 46.5923410914 +-11.5472190874 -92.9711927416 34.9716892865 +-11.5104690309 -63.2125841796 76.6268771648 +-11.4934689609 -85.2315881359 51.0242741749 +-11.4816774288 -83.601245189 53.6563405971 +-11.4779927282 -87.7758533343 46.5151078077 +-11.4751463198 92.7880816579 35.4780625061 +-11.4726553166 88.0937821596 45.9114770487 +-11.4695897412 -84.6084739591 52.056264229 +-11.450852685 63.8329155303 76.1198848376 +-11.4505901536 29.4147434188 -94.8876011644 +-11.4505241406 -89.0154933805 44.1035988909 +-11.4455843768 -84.8764926322 51.6234403806 +-11.4454980822 1.05169353147 -99.33727656 +-11.4309974596 -81.6459385218 56.597464784 +-11.4256109435 90.4430235 41.1037092578 +-11.4165018637 -58.1903962934 80.5204400411 +-11.4151470021 -93.9173545241 32.3917418198 +-11.4117165161 77.0937699298 62.6603811364 +-11.4040845788 51.568266469 84.915609568 +-11.4035050556 -82.9246778758 54.7125019684 +-11.403058377 -59.0487178751 79.8950510167 +-11.4022039623 -82.9152165098 54.7271104292 +-11.3814042534 94.4655485169 30.7688768178 +-11.3595411229 74.9345444365 65.2363002904 +-11.3580190682 54.6057823747 83.0012285095 +-11.3556287822 79.7888065849 59.2013178799 +-11.353748257 -93.5485138089 33.4629341909 +-11.344020443 -81.0247048832 57.5005252043 +-11.3345282023 -80.6493587881 58.027660624 +-11.3343701147 76.0215578155 63.9707339446 +-11.3327750239 -79.3304374333 59.8184746287 +-11.3243109515 -57.7204952868 80.8709119852 +-11.3048622875 54.3502212962 83.1760394207 +-11.288101712 -87.8740320408 46.37599867 +-11.2752321747 -82.5254328778 55.3391549243 +-11.2259440834 62.7050945071 77.0846891561 +-11.2216186644 -87.841713301 46.4532956732 +-11.2119886608 54.2359779454 83.2631371411 +-11.2114921751 -89.1233598579 43.9468903432 +-11.207006586 -94.9715266075 29.2371704723 +-11.2030888575 -78.914466544 60.3903781253 +-11.1906459036 -75.4185339969 64.7055961569 +-11.1874408856 -94.9481060345 29.3206126622 +-11.1320140196 -72.9182610939 67.5204077514 +-11.1309925559 -75.1067918776 65.0774217266 +-11.1280851202 85.6815093024 50.3472410885 +-11.125114496 -63.4172280759 76.5146195875 +-11.1006365189 -79.7933745405 59.243508069 +-11.0907980677 -87.6696491859 46.8084053333 +-11.0842022023 65.8833367084 74.4078383351 +-11.0816155698 -93.6280972055 33.3313247568 +-11.0797270895 -80.6745344294 58.0418740413 +-11.0783485891 -80.6644971896 58.0560856904 +-11.0682993958 93.236748065 34.4151356056 +-11.0633345821 -93.194925643 34.5298198999 +-11.0571645178 -75.0602638822 65.1436558597 +-11.0424636244 -85.2552518326 51.0843031866 +-11.0314826874 -82.8978391416 54.829322952 +-11.0225332055 -84.8688045772 51.7280366086 +-11.0189654979 60.3341125233 78.9833986695 +-10.9795281901 -81.2063418573 57.3147450739 +-10.9584274791 -61.8327492912 77.8243148526 +-10.9520890697 -34.07089808 93.3767939535 +-10.9339698703 -62.4557249711 77.3287186058 +-10.9290488094 -74.7332727225 65.5400170912 +-10.9245933377 -84.926947797 51.6533328867 +-10.9244536575 -83.7701953515 53.5089775931 +-10.9202964894 -83.1722232439 54.4346250585 +-10.9172259821 -87.7736231859 46.6541021741 +-10.9025420908 -83.3751996709 54.1268016402 +-10.9009026363 -87.7674453384 46.669538893 +-10.8995823941 -95.6644069103 27.0096344686 +-10.8986288519 -79.7690060696 59.3137889518 +-10.8845814481 -87.7612617933 46.6849741903 +-10.8696505273 55.7636034972 82.293810353 +-10.8658828667 -84.5872019534 52.2200905326 +-10.8656563748 -95.6635203432 27.0264386684 +-10.846298015 -95.6419440734 27.1104473079 +-10.8425825536 -78.1382814738 61.4560604976 +-10.835600493 -72.2439170974 68.2891367963 +-10.8335656409 -80.6568224792 58.1129145979 +-10.833357842 -86.9753927274 48.1447756021 +-10.8288416713 -87.5620595378 47.0703932165 +-10.8242194554 -63.6587348129 76.3570674869 +-10.815280964 -63.6061663058 76.4021289334 +-10.8064349749 94.8468625036 29.7874744877 +-10.8029970432 -86.9791689838 48.1447756021 +-10.7832596497 -80.8167720182 57.8996603779 +-10.7796007437 -77.9843041132 61.6623752364 +-10.7788409589 -83.3340823225 54.2148255651 +-10.7664563521 70.3591073304 70.240155419 +-10.7639091904 -52.0684741232 84.6936376679 +-10.7548213634 -52.0703519867 84.6936376679 +-10.7416382201 43.1465135791 89.5711760239 +-10.7230478619 -81.2305157574 57.3290463408 +-10.7137070455 73.8911512551 66.5230354654 +-10.7081714307 -83.5903549328 53.832960413 +-10.7021654668 -84.4791991934 52.4283182828 +-10.6892038703 -83.2118160652 54.4199833495 +-10.6857674434 56.9340068891 81.5127795729 +-10.6817600941 84.9123679443 51.7280366086 +-10.6795150647 89.8277894753 42.6252999515 +-10.6770211517 -83.3471889644 54.2148255651 +-10.6716326444 81.3883771896 57.1143442153 +-10.6640001221 -75.1171298881 65.1436558597 +-10.6612780622 -8.94587448988 99.0268068742 +-10.6594956239 93.9947328476 32.4247644548 +-10.6440265693 -60.9875223231 78.5316930881 +-10.6317993335 99.1566647268 7.41084901954 +-10.6047539261 -24.5296288324 96.3630453209 +-10.6040917473 -80.982915806 57.7002650408 +-10.5990569238 -77.3750025143 62.4561364338 +-10.5925682814 -81.0047315694 57.6717518425 +-10.5836410521 -81.046482852 57.6147043678 +-10.5554941977 48.3308074905 86.9063552887 +-10.5529688724 -86.9505410847 48.2518212408 +-10.5435353787 61.8772842981 77.8462301567 +-10.5194471175 -74.8497555164 65.4740813717 +-10.5111803511 89.208665032 43.9468903432 +-10.5061148521 -85.8130654006 50.256734447 +-10.5033838586 -53.6352893983 83.7432663483 +-10.5022591831 91.1865221835 39.6827509647 +-10.4940225748 -53.6371217677 83.7432663483 +-10.4931378467 46.1857187287 88.072546481 +-10.4930962047 -95.6575016434 27.1944353017 +-10.4911374868 -85.8148977565 50.256734447 +-10.4876164698 -86.0354120876 49.8790313429 +-10.4820342789 -62.4373182054 77.406125421 +-10.479836601 -84.4978456802 52.4431797303 +-10.4728441303 -84.0810157377 53.1102845816 +-10.4676721114 -80.8174744619 57.9565670322 +-10.4663726437 -80.8074416967 57.9707892832 +-10.464751558 -63.5566005935 76.4921400918 +-10.4584588091 -83.0202734404 54.7563223493 +-10.4508343996 -73.8936006094 66.5621202286 +-10.4483763324 -79.5779390873 59.6505074801 +-10.4395662132 -80.3802073717 58.5665238866 +-10.433214608 -82.5873976135 55.4118199338 +-10.4263604797 -79.517782116 59.7345238075 +-10.4260504101 89.4261503937 43.5231099372 +-10.4046924129 -83.5338610631 53.9799632428 +-10.3994656237 -84.0901230015 53.1102845816 +-10.3826368662 59.9842114743 79.3353340291 +-10.3775623832 -77.261839237 62.6331732926 +-10.3510645323 -65.9498944266 74.4544618419 +-10.3381265746 -80.9258252125 57.8284873795 +-10.3323689346 89.0278616007 44.3540529265 +-10.3301703466 -81.5427981493 56.9566471151 +-10.328321023 -83.5148474593 54.0240320478 +-10.314265951 82.4558536409 55.62956155 +-10.3003336805 24.3487306642 96.4419122639 +-10.3003206898 95.1253159788 29.0702193598 +-10.2975152334 -65.9845769971 74.4311546231 +-10.2941247369 -67.5087935034 73.0519937827 +-10.2907806691 95.1924435242 28.8530506031 +-10.2845201742 -69.3951875725 71.2638518925 +-10.2760254597 -83.3307774472 54.3174449951 +-10.264576489 -76.4206495945 63.675134747 +-10.2639115466 -77.2328897869 62.6875813454 +-10.2584767898 -69.3864681208 71.2760948402 +-10.2575624558 -82.1189149882 56.1361399958 +-10.2522922865 -78.5091091899 61.0836334633 +-10.2504521489 -79.4670054442 59.8324600571 +-10.247555306 83.2194776184 54.4931753083 +-10.2430627007 57.6207173526 81.0859580832 +-10.2385897059 -78.5108973567 61.0836334633 +-10.2186230686 -70.7374137861 69.9413899879 +-10.2082682615 -83.5010977825 54.0680860418 +-10.2081902019 -87.1607391845 47.9457860256 +-10.1992163909 93.5811267493 33.7423873096 +-10.1945381501 78.816682117 60.6959801962 +-10.1695168371 -93.91731885 32.8042397768 +-10.1671096769 -83.7712778615 53.6563405971 +-10.1090954059 -64.5553332209 75.6995055652 +-10.0962263891 -81.9905490553 56.3526048938 +-10.0874441408 -71.5042167882 69.1765166238 +-10.0865607282 -64.5588580279 75.6995055652 +-10.0864802026 -88.5279005658 45.399049974 +-10.0856572505 -75.7902827826 64.4524053357 +-10.0844938766 -93.8976584899 32.8866646739 +-10.0681559729 -83.5656001108 53.9946544894 +-10.0589210418 90.6772452795 40.9445392696 +-10.0538719847 -73.3950553982 67.1720589323 +-10.050623324 -85.5568786413 50.7839097349 +-10.0399622491 93.1766743661 34.8899199214 +-10.023352247 -78.5708981631 61.0421687982 +-10.0227970219 -74.9178764274 65.4740813717 +-10.022003898 -78.5603287463 61.0559922132 +-10.0198335363 -83.4096800673 54.2441536663 +-10.0126148587 -81.7821988245 56.669387672 +-10.0054327123 -75.2879132316 65.0509141939 +-9.97873143377 -78.1125158432 61.6348909921 +-9.97718476858 -83.3001872527 54.4199833495 +-9.97166274512 22.9113803043 96.8278606324 +-9.96898066599 -77.820068308 62.0052932662 +-9.95000596657 -80.1114030573 59.0183063249 +-9.93735013443 -78.4420110182 61.2217280034 +-9.92759153895 -77.4969756266 62.4152360803 +-9.90659568319 50.5878042325 85.689750991 +-9.9061963206 -79.5316953416 59.8044873781 +-9.89520504224 -85.2610810349 51.309189995 +-9.88815069329 -87.4657385193 47.4549160903 +-9.86941522197 -80.9639833923 57.8569618666 +-9.86036002285 -83.6851357308 53.8476680827 +-9.85402206024 92.2064053599 37.4282922379 +-9.84832833118 -87.3867481857 47.6084726767 +-9.84485722495 -75.5945928678 64.7189023035 +-9.76519952613 92.4440248864 36.861133203 +-9.75916906138 -75.8670291699 64.4123629761 +-9.75252491633 -79.0855848436 60.4181969914 +-9.6810537265 88.8268158188 44.9007125805 +-9.66369589643 92.4093411754 36.9746757274 +-9.66095505173 -82.6130708859 55.5134800412 +-9.65399830962 -59.1476289775 80.0522223488 +-9.64682313228 -65.0923027428 75.2989437316 +-9.64111881814 -80.6135016619 58.3824646426 +-9.63099069091 94.8153367222 30.2868938746 +-9.6163295064 67.7373466158 72.9326955506 +-9.61298351817 -73.7136640853 66.8871159118 +-9.59070463079 -83.1442227022 54.7271104292 +-9.58705761371 -85.8764341817 50.3321604797 +-9.56458423556 -83.5582727304 54.0974471368 +-9.5628464539 -74.3408323292 66.1966208828 +-9.55178152692 -85.5604472889 50.8740929096 +-9.54647745725 -87.1682634133 48.0682704252 +-9.54306199998 -80.3885073616 58.7079028057 +-9.53770539624 -81.5591344509 57.0713567684 +-9.53479699141 69.8778063993 70.8955557081 +-9.50117811412 26.4629729199 95.9658203669 +-9.49716108702 -81.0897489295 57.7430216549 +-9.49380765905 92.9805340359 35.5596387288 +-9.4783127809 -85.4432885297 51.0843031866 +-9.47351629273 -36.7106544528 92.5342117203 +-9.45000740455 -84.2487140461 53.0363228518 +-9.43453807875 -61.2971781632 78.445174743 +-9.42841033239 95.3019401495 28.7861995122 +-9.41680716878 -64.3925039219 75.9271307335 +-9.40792165866 65.286453443 75.1609606571 +-9.40641905222 -8.74710476683 -99.1716060111 +-9.40178024966 99.09124684 9.61932054944 +-9.39965378262 -83.4055436123 54.3613999406 +-9.34720278696 -86.7474646525 48.8621241497 +-9.33836667247 75.72707541 64.6390358665 +-9.33271928549 -63.3540697689 76.8060036355 +-9.32615078699 -76.8422485628 63.3110712854 +-9.31121827757 -34.4372068521 93.4204474321 +-9.30520770934 -34.4388314417 93.4204474321 +-9.27644897347 25.7240592821 -96.1884622421 +-9.27496151763 -94.2545865308 32.0943609807 +-9.2676556837 -77.4908172954 62.5242656336 +-9.26494976497 -63.7425541536 76.4921400918 +-9.24662932632 -82.4355576302 55.8469218875 +-9.22319879137 99.0471483833 10.2271697543 +-9.20270340659 91.8746826399 38.3973038094 +-9.1884039079 -83.6289594292 54.0534030235 +-9.18790861085 -64.7195533216 75.6766922719 +-9.18762286601 -44.0939946778 89.2821775016 +-9.1631542256 84.0749194985 53.3614515916 +-9.14834830349 -77.0635321182 63.0675807431 +-9.14652951078 -47.4081261201 87.5717453046 +-9.14521902972 -75.3514724235 65.1039213298 +-9.1238078992 73.9871663902 66.6532470249 +-9.1134301688 -47.4145000487 87.5717453046 +-9.07604229202 -87.8270457984 46.9471562786 +-9.0722427251 -64.308025057 76.04059656 +-9.06444241769 56.7815663964 81.8149717425 +-9.06394317707 79.9252560849 59.4121062902 +-9.06265618799 -41.1166611509 90.7044014291 +-9.02928100175 56.8160821361 81.7948952887 +-9.02837837356 -87.8154788925 46.977974103 +-9.02344345122 -77.0449987353 63.108205791 +-9.0233790684 58.1532074884 80.8503746992 +-9.00166532462 54.9698937941 83.0498693415 +-8.99994496679 94.856053276 30.3534206887 +-8.99534327742 -73.4732098246 67.2366807435 +-8.96420505959 -75.7381861339 64.678977951 +-8.94747911244 -87.0286036573 48.4351604003 +-8.94068973393 -79.9600005109 59.3840246647 +-8.92679997495 89.4350022018 43.8371146789 +-8.91908948777 -86.3082449066 49.71254071 +-8.917037937 -75.1150280532 65.4080957909 +-8.89109587992 52.7352232825 84.4981931132 +-8.89081730313 -75.1181361103 65.4080957909 +-8.87569399955 -71.359869431 69.4909425092 +-8.8613468277 -83.3306223699 54.5663257682 +-8.8609979746 -62.8106298572 77.3065811677 +-8.85722839708 -72.8722511693 67.9057031084 +-8.85104989663 68.4298175975 72.3810678237 +-8.83958565786 -82.0364831999 56.4967003425 +-8.81652197215 -70.283157281 70.5871570679 +-8.73552293706 87.9847764315 46.7158405181 +-8.72546677477 92.6509776906 36.6014011008 +-8.6825737166 88.2345866477 46.2522500293 +-8.6742202018 -63.4881628991 76.7724630032 +-8.67132399116 -95.6517173657 27.8488259221 +-8.63754231064 -64.9949437191 75.5052988457 +-8.63059244862 -68.8009725843 72.055111168 +-8.6238424332 -56.8212623937 81.8350382274 +-8.62311794371 -66.3943304106 74.2794367659 +-8.61452004805 -66.968615838 73.7630973935 +-8.61263427105 94.272322278 32.2265695231 +-8.60400362309 88.226055799 46.2831956524 +-8.60300383731 47.1987797234 87.7397487892 +-8.57169770044 -86.3347175945 49.727683803 +-8.55859802443 -86.5099171475 49.4245347472 +-8.54870252317 -81.0632649161 57.9281172343 +-8.54427694944 90.8969695448 40.8011796273 +-8.54181378583 -15.0791771288 -98.4868307662 +-8.52445422251 -15.1284690659 -98.4807753012 +-8.51095710716 -74.4685906461 66.1966208828 +-8.50888787361 -95.528520086 28.31785086 +-8.49889210995 -71.0628575535 69.8415285431 +-8.4918958688 -69.3610935941 71.5326946227 +-8.48944445327 -71.9420920823 68.936671806 +-8.48803431788 -71.9301421731 68.9493141399 +-8.47834554009 58.6905136499 80.5204400411 +-8.47246539156 -84.5843916332 52.6659094883 +-8.47202833049 -77.9863460898 62.0189854765 +-8.44293935339 -84.5873439283 52.6659094883 +-8.43357842303 -77.2556354519 62.932039105 +-8.42309740646 -80.4104130016 58.8491028904 +-8.42126775676 -80.8012402398 58.3115925445 +-8.40100739085 -79.6627424853 59.8604254456 +-8.37564629764 -59.5958200716 79.8635510047 +-8.37135927799 -66.4526723308 74.2560615973 +-8.36979533026 -86.1356986228 50.105767621 +-8.35648069024 -85.5334030176 51.1293086077 +-8.35516063411 -2.29041613194 -99.6240196174 +-8.33635637531 82.3558242171 56.107248907 +-8.33261239218 -74.6396932709 66.02638684 +-8.32757573272 -86.9624236835 48.6640354832 +-8.32742097387 84.9296090282 52.1307545528 +-8.31092700154 -86.6292252701 49.2575458328 +-8.30686191686 62.9271347591 77.2733573497 +-8.28463085174 92.2817312901 37.6224263139 +-8.28438312165 -65.1205720459 75.436596508 +-8.28337025135 -66.5028693063 74.2209818805 +-8.27089126393 87.8240880124 47.1011881219 +-8.2669302359 -80.2714601725 59.060566762 +-8.2616793462 -81.6180812506 57.1859551582 +-8.25818804434 -80.3241410465 58.9901237104 +-8.25667912374 -65.0842664939 75.4709580223 +-8.25445969073 -62.2788246136 77.8023900658 +-8.25042318414 51.6244977797 85.2457726006 +-8.24812447873 92.7841998752 36.3739013043 +-8.20586601911 -73.3881915833 67.4302387584 +-8.19726406969 -83.3027429928 54.7125019684 +-8.17373075658 -86.4690393783 49.5610265685 +-8.16814360032 -80.6940308502 58.4957674987 +-8.15111200165 -85.9096713524 50.5280886365 +-8.12540369936 -63.8708916808 76.5146195875 +-8.12007444454 21.3425769254 97.3578902873 +-8.11088116328 -87.1020638578 48.4504290844 +-8.10931258354 -87.0852190133 48.4809620246 +-8.10646891811 -63.9002164773 76.4921400918 +-8.10310805766 -63.8737240905 76.5146195875 +-8.1022506418 -87.339609912 48.0223497443 +-8.09023262436 -67.8467289859 73.0162276621 +-8.08281851713 -87.1301379685 48.4046186062 +-8.07721623831 -86.2513287123 49.9546481641 +-8.06602305254 54.8216112541 83.2437998389 +-8.06281112861 -83.7354951528 54.0680860418 +-8.06100170964 -83.7167036183 54.0974471368 +-8.0452593617 -72.0657175421 68.8607737173 +-8.04116793039 -85.0666711599 51.951911188 +-8.03761701923 -58.2976296572 80.8503746992 +-8.02897837676 -74.1490607989 66.614204858 +-8.02158219313 -74.8126738622 65.8689460119 +-8.01934910056 66.7567320755 74.0218127487 +-8.01712825972 -59.9260089727 79.6529918024 +-8.01112413045 -79.2809142384 60.4181969914 +-7.99897285129 -86.5547910355 49.4397065335 +-7.99824335411 -63.9407580264 76.4696512759 +-7.99604786142 92.8888578987 36.1624570082 +-7.99492971085 -63.9142676019 76.4921400918 +-7.99455918295 -74.560645821 66.1573663187 +-7.98521522729 93.5271048141 34.4806757891 +-7.97352668031 -65.411016479 75.2184937064 +-7.96232220869 -86.6533270795 49.2727341548 +-7.96195002694 95.4154537937 28.8530506031 +-7.94846689276 -84.0859966171 53.5384632481 +-7.94840670437 75.6240382158 64.944804833 +-7.94805401602 -68.6930236671 72.236396206 +-7.94662801823 -67.9534621845 72.9326955506 +-7.92679619813 -72.9673990188 67.9185142834 +-7.92125210362 -71.5209042022 69.4407231184 +-7.91642813056 -77.9357828208 62.1558036049 +-7.90808872839 -82.8867428437 55.3827589908 +-7.90628548554 -69.3925771179 71.5692733704 +-7.90101512442 51.4531690519 85.3823480265 +-7.88402447025 57.704579573 81.2897512265 +-7.87046600499 -74.6318718012 66.0919017453 +-7.86596377115 93.0887029256 35.673799932 +-7.86506525607 -69.8983678489 71.0799473873 +-7.86176787675 35.8468553323 93.0225540858 +-7.85883003125 -63.7291547102 76.6605089369 +-7.84353086078 -71.9669460394 68.9872285383 +-7.84216664216 42.6029590326 90.130396116 +-7.83700512929 -71.9070703311 69.0503771677 +-7.83511653632 -86.5957578246 49.3941866584 +-7.82163721327 -78.0868843582 61.9779031795 +-7.82048019521 -80.3368933783 59.0323949356 +-7.79986689958 -89.1528866168 44.619781311 +-7.79664294429 -79.0898877659 60.6959801962 +-7.79252685734 55.4467096616 82.8549269077 +-7.78995752612 -75.1253800086 65.5400170912 +-7.7854269756 -62.9529954408 77.3065811677 +-7.78139239301 -80.3717315793 58.9901237104 +-7.78112615637 90.3921455145 42.0560828539 +-7.76519654971 -75.5290070368 65.0774217266 +-7.76306293882 88.3768958297 46.1438959919 +-7.75889200208 -70.6181477176 70.3766780108 +-7.75561801188 83.6030236203 54.3174449951 +-7.74371004853 -74.9343331818 65.7638248986 +-7.7435353608 -79.402753968 60.2929541689 +-7.73640090412 -66.6599531378 74.1390500932 +-7.73610124011 -72.7490012061 68.1743027916 +-7.73257486136 35.8251137879 -93.0417567982 +-7.7264779942 -84.5726174617 52.7993741769 +-7.72243460801 -74.7284549995 66.0001667961 +-7.71016522508 42.7229342383 90.0849834449 +-7.71014912651 -62.9758517357 77.2955089162 +-7.7089863842 -86.7193669727 49.1967775447 +-7.70850959126 -62.9624601492 77.3065811677 +-7.70252499052 -88.040263505 46.7929814261 +-7.69647710988 -80.2244862955 59.2013178799 +-7.69637710823 -55.6789279349 82.7080574275 +-7.67457233306 -51.3517625428 85.4640124453 +-7.65867167485 -77.413502791 62.8370458711 +-7.64886119191 -79.1468684855 60.640482612 +-7.64775284213 -62.73852302 77.4944488704 +-7.62123325752 -79.1495336197 60.640482612 +-7.6148255849 -70.3242852046 70.6859911282 +-7.60481105879 -80.9026068906 58.2832312683 +-7.60307808015 -77.2644694475 63.026938405 +-7.60052532916 88.6562917762 45.63215909 +-7.58996107588 -94.7480556612 31.0676429631 +-7.55910604159 -78.7925943757 61.1112672705 +-7.55633461591 -74.7801565529 65.9608216527 +-7.5347364713 89.3547134976 44.2601730913 +-7.53052864331 39.4016851037 -91.6013010243 +-7.52809319445 -94.8072401493 30.9016994375 +-7.52795246155 -22.1512266433 97.2247555406 +-7.5155594054 92.8017547751 36.4876784338 +-7.50767245633 68.5520678412 72.4171861437 +-7.47596619799 -60.6244192259 79.175688964 +-7.46651845331 -76.1494459126 64.3856582585 +-7.46402805579 79.7034916937 59.9303069992 +-7.46200692946 -60.598289066 79.1970063504 +-7.40857975543 39.5873958215 -91.5311479119 +-7.40424763195 -68.7157136066 72.2725938412 +-7.40223166598 -72.4960393215 68.4801522272 +-7.40142363009 -35.6461211424 93.1373876365 +-7.39379296337 88.0503320516 46.8238278148 +-7.3898172903 78.6154289184 61.3596360516 +-7.37662662382 87.8459035661 47.2089250705 +-7.36567931866 -26.9613619363 96.0147474647 +-7.36154855402 -70.0404558904 70.9939584863 +-7.36075479234 -82.9662414549 55.3391549243 +-7.3386891 -15.7378695624 98.4807753012 +-7.29728759535 -86.901080275 48.9382451749 +-7.28822257365 -63.7699916169 76.6829184428 +-7.28278567031 -62.276792057 77.9009769128 +-7.28092867768 -69.6240682096 71.4106238843 +-7.27429675147 -88.8587986198 45.2901591366 +-7.2695854564 -83.4271405837 54.654051463 +-7.26378143151 -69.1102638552 71.9097275004 +-7.26118434238 -64.0286469925 76.4696512759 +-7.26109071538 -83.8372263552 54.0240320478 +-7.26021250986 82.4871413741 56.0638994563 +-7.24965351238 -86.8793420444 48.9838999048 +-7.24695431021 -62.9221340335 77.3840209727 +-7.2468416354 -71.5923826891 69.4407231184 +-7.24170439678 -81.3019649807 57.7715172702 +-7.23881386072 -71.0182144656 70.0286569056 +-7.19419038223 94.5757372744 31.6808071828 +-7.19356717682 -66.433887965 74.396176791 +-7.19355698243 88.8256848272 45.3679452137 +-7.17494773298 74.1079416338 66.7572701047 +-7.15984347457 -84.3811405936 53.1842058656 +-7.15564250319 -75.4177952211 65.2759752463 +-7.14025625665 -69.450459058 71.5936483022 +-7.13706060622 -75.7845580154 64.8518552727 +-7.12559084382 -61.7735333128 78.3151105291 +-7.10424454812 -73.1115927205 67.8544377272 +-7.10258524159 55.2912100737 83.0206924295 +-7.10087127942 -72.0319138048 68.9998624687 +-7.09500376919 58.0353678332 81.1267958321 +-7.08087106875 -85.2156090169 51.8474806022 +-7.06849077203 -77.3704094599 62.959162782 +-7.06052172791 91.342826164 40.0828784059 +-7.05730122616 -80.6653221314 58.6796413149 +-7.05121617809 -70.3954283829 70.673644403 +-7.04475482297 -82.6821807007 55.8034803938 +-7.03566648667 -72.0141073029 69.0251240234 +-7.01005859093 -84.9020726758 52.3688565266 +-7.00895313775 -68.0565683504 72.9326955506 +-6.98988207425 -71.2883320756 69.7790459842 +-6.96997421191 -74.0103586296 66.8871159118 +-6.94920883037 -84.1650929878 53.5532036295 +-6.9485935453 -74.4795465092 66.3665141432 +-6.92984437666 -75.1291282045 65.6322432357 +-6.92257351241 -69.9730562525 71.1044961634 +-6.89155975184 91.6548096003 39.3941909591 +-6.89138686307 88.9526541543 45.1656296979 +-6.87338539791 80.1745714851 59.3699811383 +-6.8685126191 -70.685615311 70.4014724456 +-6.8536983571 52.7705542504 84.6657866138 +-6.85235586015 -24.3454073083 96.7488830021 +-6.84864887137 -84.2014567901 53.5089775931 +-6.84320544917 -24.3128972509 96.7577054629 +-6.84089377873 -88.5014727405 46.0509662773 +-6.81827462351 -81.1966669331 57.9707892832 +-6.81798335346 51.998098073 85.1452459024 +-6.80958403504 8.22552535251 -99.4282168096 +-6.80106429714 -79.6576967884 60.0699331346 +-6.78171475028 -67.1142447365 73.8219919705 +-6.77860609085 86.7107889637 49.3486532416 +-6.77157448134 -63.6787530075 76.8060036355 +-6.76569860273 -87.9281004633 47.147369718 +-6.75872955404 60.5415777276 79.3034484816 +-6.75446212113 -70.7952811495 70.3022432673 +-6.70982024195 -73.3032572877 67.6875969683 +-6.68858064989 30.2201550427 95.0894585014 +-6.67972243442 30.205116777 95.0948591076 +-6.67514545672 -63.2972176824 77.1291427853 +-6.66951545527 92.3663490185 37.7355950342 +-6.66781405034 74.2721595563 66.6272209433 +-6.64512381346 -75.4987910759 65.2363002904 +-6.63915125583 -24.0540856322 96.836576948 +-6.63543151243 -72.6302218702 68.4165325029 +-6.63017636377 -77.0217388354 63.432582386 +-6.62789900875 -77.6294924613 62.6875813454 +-6.6238359186 -74.6601110462 66.1966208828 +-6.62371236334 -81.967076999 56.8992506345 +-6.62005983413 -80.0083357689 59.6224874966 +-6.60504812585 -45.3868645925 88.8617232655 +-6.60285669035 -74.7199334271 66.1311865324 +-6.59639949841 -81.6290859178 57.3862339406 +-6.59203480185 -76.5786541783 63.9707339446 +-6.57061850813 -78.7418339147 61.2907053653 +-6.55650707719 -71.3539514438 69.7540380788 +-6.55611887819 89.9219330359 43.2557887958 +-6.5542503817 -69.59601378 71.5082978952 +-6.55265561967 -69.3198557284 71.7761820252 +-6.54669202683 -72.6382743723 68.4165325029 +-6.5443960871 -50.5271428077 86.0475375565 +-6.53556335044 -65.4779007345 75.2989437316 +-6.53047095696 -95.7924040819 27.9493876371 +-6.52379695417 41.803286781 90.6086380408 +-6.52357922722 91.6817355461 39.3941909591 +-6.52045622068 64.416337564 76.2103608804 +-6.49452726578 89.0771593291 44.9786705168 +-6.48855258556 54.4146366642 83.6477495337 +-6.48136602605 -69.6028392134 71.5082978952 +-6.47524139603 72.1271106994 68.9619543736 +-6.46770762071 -92.4925281297 37.4606593416 +-6.46574396051 -36.3720125622 92.9261580892 +-6.45450759516 -87.8936691572 47.2550764869 +-6.45389801459 98.9969380055 12.5679539283 +-6.42818002543 -71.7434973702 69.3653305813 +-6.4219355037 -77.6138562098 62.7283673359 +-6.41453954956 92.8971141006 36.4551762325 +-6.40986249658 -77.1402742766 63.3110712854 +-6.40352057186 -74.3887133694 66.5230354654 +-6.39944309971 -65.2665695852 75.4938542041 +-6.39868223893 48.4720636457 87.2325392932 +-6.38834600992 88.6879073226 45.7563561703 +-6.36826245553 -86.3067626806 50.105767621 +-6.36642914479 -21.2204134719 97.5149354306 +-6.35654946788 -82.6107329089 55.9916162217 +-6.34470714869 -55.5144848549 82.9330251619 +-6.322235049 -84.0830335265 53.7593974759 +-6.31017232505 -70.9839299545 70.1531425771 +-6.3093966077 -70.2797810517 70.8586190225 +-6.30325585724 -80.4494774337 59.060566762 +-6.28116453161 -72.0838347043 69.0251240234 +-6.26842070481 -68.6129885771 72.4773392198 +-6.25363892676 -79.4600165495 60.3903781253 +-6.2480635342 -70.2852602776 70.8586190225 +-6.23645187427 76.181057789 64.4790904261 +-6.22348343193 -70.7083101206 70.4386480127 +-6.2220427701 -77.3327181878 63.0946660302 +-6.2164141867 -81.346310562 57.8284873795 +-6.21050171581 89.2620652198 44.6510176944 +-6.20691622776 -77.6533089759 62.7011785857 +-6.20528416123 -81.3876295316 57.7715172702 +-6.18775736148 -73.9977995806 66.9778867692 +-6.18073206795 90.6622489675 41.7391322773 +-6.17840629188 -82.5555872989 56.0928007986 +-6.15298917073 89.1092700632 44.9630816679 +-6.15036531872 61.946894472 78.2608156852 +-6.13122633705 -88.1226590408 46.8700866991 +-6.12565325258 -65.4118593186 75.3907489863 +-6.12319915781 -65.3856536397 75.4136773416 +-6.10281983355 -65.4139935898 75.3907489863 +-6.09749345169 98.8437658016 13.8827423723 +-6.08247243549 19.6492936359 97.8616819224 +-6.07430039789 -86.4329599197 49.9244059975 +-6.06080187987 -82.1398604648 56.7125206934 +-6.04429673072 -80.3865722667 59.1731820696 +-6.03827884113 -68.0600447152 73.0162276621 +-6.0316355629 -85.612200942 51.3241699622 +-6.01663461269 -72.4079252078 68.7087510804 +-5.99988584286 43.6303222901 89.7797101061 +-5.98683156396 -81.5251334087 57.6004381105 +-5.98364709669 -86.6568118856 49.5458668432 +-5.96620298065 72.5683326103 68.5437198009 +-5.92672579474 -80.3227756726 59.2716258391 +-5.92512763171 -78.2536413211 61.9779031795 +-5.92412609682 -77.5215078672 62.8913392129 +-5.91166111075 91.9150392363 38.9445480794 +-5.90796743346 -69.3400470537 71.8126297763 +-5.88549497038 -88.6103803704 45.9734862673 +-5.88135521484 -80.6670592184 58.8067616682 +-5.86089385364 -86.63918728 49.5913414893 +-5.83967425735 94.1296968012 33.249035846 +-5.81748999679 -70.0112949683 71.1658301926 +-5.81049494974 19.1606540032 -97.9750350171 +-5.8059274307 -67.3090818013 73.727733681 +-5.80105594912 -77.6956555732 62.6875813454 +-5.79913660554 -80.5080515402 59.0323949356 +-5.7911967761 -83.2354949701 55.1209072583 +-5.78830805142 -77.707576501 62.6739821955 +-5.78409709478 26.0903759514 96.3630453209 +-5.77270250156 -68.7452806178 72.3931094691 +-5.76292117215 -87.9251861989 47.2858369012 +-5.75842837143 63.6436569119 76.9176536145 +-5.75700567948 -80.3143707565 59.2997363872 +-5.74891240289 -75.2287089749 65.6322432357 +-5.73543541079 -86.351125249 50.105767621 +-5.71875228968 -87.7204698015 47.6698547309 +-5.70837683123 -71.7314464287 69.4407231184 +-5.70076519536 96.8109908505 24.3953546137 +-5.65137105883 -84.1965505165 53.6563405971 +-5.64542296861 -88.0153731822 47.1319772882 +-5.64489633284 -88.0071626293 47.147369718 +-5.6178974601 -76.8685527495 63.715499106 +-5.61334735123 -71.3243407 69.8665066769 +-5.60616411072 -79.7717146247 60.0420225326 +-5.59811233617 84.7308791797 52.814195551 +-5.59500135841 -95.5834579344 28.8530506031 +-5.57633959578 -72.1417818623 69.0251240234 +-5.57202185313 89.0608273333 45.1344835704 +-5.56776312124 -64.9451466102 75.8361915289 +-5.56196245598 -84.1837284712 53.6857935987 +-5.53820451354 -70.3695604199 70.8339837725 +-5.51297523488 -84.1117481146 53.8035401546 +-5.48700638692 -89.7117614226 43.8371146789 +-5.457481739 55.3612139617 83.0984469274 +-5.44050362397 -79.8041864041 60.0141046146 +-5.438314962 -72.8373333911 68.3018857343 +-5.41826436821 -74.3154318494 66.6922709185 +-5.41248309112 -70.6639528274 70.5500588065 +-5.40386479954 -64.7595388496 76.0065811178 +-5.39853110506 -84.1661878108 53.7299608347 +-5.38140357347 56.1964144894 82.5409201191 +-5.37113929386 -87.8173511966 47.5317124823 +-5.36971986562 -73.4727890055 67.623334614 +-5.36505012463 -87.7177941597 47.715876026 +-5.32346071813 -82.9957975394 55.5279961531 +-5.31293712668 -65.7465032696 75.1609606571 +-5.30813955793 -86.7873146191 49.3941866584 +-5.2955246481 -95.6156346356 28.8029136015 +-5.27366711973 -69.3282954007 71.8733322724 +-5.2650556152 47.1619364584 88.0229000821 +-5.26128446373 -69.1655114377 72.0309024888 +-5.25787261782 -66.5107752179 74.4894056592 +-5.25340520713 20.6099297039 97.7119876542 +-5.23475149225 -68.3435359121 72.8131751529 +-5.22874422344 -75.7241022485 65.1039213298 +-5.1756107307 -68.5135426657 72.6574670971 +-5.16642593435 -77.7842763441 62.6331732926 +-5.16188757424 -75.7172987362 65.1171681568 +-5.15232411349 -88.0208821444 47.1781502685 +-5.14293180864 -82.2024345686 56.7125206934 +-5.10737263191 43.8068736607 89.7489418593 +-5.10708975891 -28.0746456862 95.8422240132 +-5.09523936546 85.7626349534 51.1743000114 +-5.08413484518 -86.339309744 50.1963660617 +-5.07182014177 -86.6455745258 49.667102347 +-5.05291692426 -70.8385538252 70.4014724456 +-5.04207827303 -86.6559922346 49.6519531995 +-5.03283749346 -78.2510105053 62.0600507707 +-4.99904803327 -57.1393804843 81.9152044289 +-4.99644154385 89.9311334027 43.4445257404 +-4.99620569227 -86.649967531 49.667102347 +-4.9948330335 -68.0166837934 73.1353701619 +-4.99196102427 97.5320585645 21.5076237017 +-4.98786082598 -85.7241807045 51.2492545011 +-4.98589512028 -74.0884844884 66.9778867692 +-4.98166527041 -73.6419121566 67.4688949446 +-4.97509596881 54.4564921458 83.7241833838 +-4.97295094005 -68.0438801831 73.111559473 +-4.97029623373 -69.8520503876 71.3861836212 +-4.96721250165 64.5546876257 76.2103608804 +-4.96661880203 -68.782874676 72.4171861437 +-4.9662802505 66.0494122045 74.9186973186 +-4.96518789252 97.3417712299 22.3590358248 +-4.95190130761 -76.1624362973 64.6123979643 +-4.93650483718 -36.0373641668 93.1500901981 +-4.92697430938 44.0638116319 89.6331714747 +-4.92022271907 -64.384700459 76.3570674869 +-4.9181914926 -64.3581203801 76.3796028635 +-4.89939101882 -71.4990547488 69.7415309387 +-4.88816362154 -70.2564140478 70.9939584863 +-4.88518797805 -87.9286764182 47.3780835594 +-4.88363667316 -85.2152552548 52.1009631841 +-4.87417454362 98.6015852486 15.936430246 +-4.86195837903 -94.9920896931 30.8684994204 +-4.86058064463 61.7595328074 78.4992666412 +-4.85857392301 -86.3610698545 50.1812701416 +-4.858081896 -86.3523240827 50.1963660617 +-4.85723863453 98.6079845705 15.9019688023 +-4.84891274557 56.7930553755 82.1646937942 +-4.84197595777 -74.4717357089 66.5621202286 +-4.8371787865 60.5168372017 79.4626586297 +-4.83036244386 -77.8606018491 62.5651203016 +-4.82827651457 -73.2733459352 67.8800745533 +-4.81471559943 -86.6602415075 49.667102347 +-4.80321421376 -74.2760116844 66.7832555471 +-4.80048368506 -58.7661893148 80.7681270663 +-4.7959311291 -76.6561232979 64.0377842023 +-4.78225543512 -58.7959584353 80.7475405485 +-4.76821363303 90.379293741 42.5305466885 +-4.76575045996 -74.7090158342 66.3012109666 +-4.75803629117 61.8362001597 78.445174743 +-4.7482404426 -86.279359259 50.3321604797 +-4.73373368209 -70.341462469 70.9201693677 +-4.7214256757 -79.4706347713 60.5155050266 +-4.71751029832 93.7728294222 34.4151356056 +-4.71471853651 90.5670631653 42.13524058 +-4.71083290227 -70.3678068026 70.8955557081 +-4.697340059 68.9030699328 72.3208265315 +-4.6943075429 -79.4828203829 60.5016094056 +-4.69360859631 -74.1895124889 66.8871159118 +-4.69162249187 -76.7073496904 63.9841478951 +-4.6790474058 -94.9904810349 30.9016994375 +-4.67623715633 59.8176391683 79.9998928149 +-4.64916255479 -74.5189307492 66.5230354654 +-4.6474174409 97.8225515134 20.2274547718 +-4.64342791817 53.9419877831 84.0755644119 +-4.63744604564 -87.9006543379 47.4549160903 +-4.63024725649 19.8658866538 97.8974328458 +-4.62099065847 -88.1737543869 46.9471562786 +-4.60977712438 78.7521592274 61.4560604976 +-4.6082644983 53.9744545984 84.0566603496 +-4.6040073841 -40.2838290573 91.4112478445 +-4.59959695203 -84.9291242139 52.5917062677 +-4.59318586156 -43.1219742138 90.1077021322 +-4.59287945066 77.7654657436 62.7011785857 +-4.55963894197 -55.2239031679 83.2437998389 +-4.55881332535 -18.9160874912 98.0887295008 +-4.55221008758 -18.9176776648 98.0887295008 +-4.54036188585 -55.2254914177 83.2437998389 +-4.53798067552 -55.1965281953 83.2631371411 +-4.5329717694 -43.1283454748 90.1077021322 +-4.52968370502 -43.0970616319 90.1228341999 +-4.52946000151 -85.5699562756 51.5486816038 +-4.50342119864 73.2108863099 67.9697382902 +-4.48551080855 -80.2292385341 59.5243603663 +-4.47804958706 -85.4462762652 51.7579070704 +-4.45784554033 -82.3117593931 56.6118528114 +-4.44886155275 -71.7111898055 69.5536691165 +-4.44869249574 -85.4568541355 51.7429726276 +-4.44124675453 -85.601595436 51.503807491 +-4.43625849828 90.7058975601 41.8659737537 +-4.43444137694 -75.3061473081 65.6454104053 +-4.43029313472 -80.502000186 59.1591114605 +-4.41630059372 -81.5446539341 57.7145190037 +-4.41452059002 -70.7579806603 70.5253158862 +-4.41406809093 -68.6303281208 72.5974797422 +-4.41354107586 88.6556775401 46.0509662773 +-4.39391593488 -95.6562732553 28.8196268134 +-4.39322246464 -69.8282714734 71.4472679633 +-4.3894589578 81.5763549656 57.6717518425 +-4.37348319807 98.2026110781 18.3608230249 +-4.36362648632 52.5145967133 84.9892692987 +-4.36333223116 89.2148116557 44.9630816679 +-4.35719901577 -77.4491393018 63.108205791 +-4.34428905702 91.4420633553 40.2427161349 +-4.33598966535 89.2945764129 44.8071179262 +-4.32726844206 -80.6830296447 58.9196357353 +-4.31447270544 -77.9018271582 62.5515039842 +-4.30187947138 -94.7347422187 31.7304656405 +-4.29271316167 52.5502034552 84.9708698939 +-4.29250771969 -70.7901462114 70.5005643726 +-4.28439552865 -86.6707146363 49.6973961028 +-4.2822358626 59.0180305692 80.6134884728 +-4.27791583183 -67.0616064149 74.057007644 +-4.26700289417 21.0105267872 97.67471756 +-4.25128492577 -72.1957652961 69.0630005849 +-4.2437767987 56.0479044663 82.7080574275 +-4.23781018631 -72.8333886764 68.3910700219 +-4.20754212202 -73.6429978095 67.5204077514 +-4.20073020734 -64.6090919315 76.2103608804 +-4.19476218061 61.2160837251 78.961984927 +-4.186341909 -62.6974391441 77.7914241173 +-4.16998966497 -67.7903810924 73.3966989553 +-4.16445611949 -62.6988966333 77.7914241173 +-4.1635562444 -62.6853483634 77.8023900658 +-4.15616081696 -88.1311772854 47.0703932165 +-4.14263792705 -71.4126385942 69.8789925516 +-4.12694294452 -70.5035534518 70.7970147154 +-4.11760757566 -84.7972556856 52.8438334722 +-4.1158072648 -83.5560057473 54.7855275974 +-4.098843764 -8.47131785231 -99.5561964603 +-4.09293063487 -22.9312156755 97.2492018808 +-4.08893270065 -75.0150559038 66.0001667961 +-4.08016079006 89.1652775521 45.0877540689 +-4.06988073852 -71.6728741722 69.6163427557 +-4.0243071688 -83.1755042227 55.3682259884 +-4.01839268985 -85.8466442063 51.1293086077 +-4.01783934984 62.6404136109 77.8462301567 +-4.00978743996 -71.0527761012 70.2525772694 +-4.0097364477 90.7476828926 41.8184177516 +-3.99824154556 -96.6040917269 25.5277011532 +-3.99807499165 -71.0657158064 70.240155419 +-3.99508398342 79.6898861425 60.2790291109 +-3.99310319914 -69.8897554961 71.4106238843 +-3.98013027156 -70.7467487083 70.5624270432 +-3.97762723365 -68.5681107307 72.6814465487 +-3.97100589422 -69.5029948338 71.7883334625 +-3.96373564999 17.998145388 98.2871078132 +-3.96140862667 -70.413971785 70.8955557081 +-3.94507621595 89.639066222 44.1505852792 +-3.9348521003 -74.5833096354 66.4969688239 +-3.91293566211 -20.0369389282 97.8938711712 +-3.90127218858 -66.0553476304 74.976470474 +-3.89572354115 -70.7884394322 70.5253158862 +-3.86040669564 -74.9117042121 66.1311865324 +-3.83828169299 -85.5135536767 51.6981598438 +-3.82604407986 46.8373700392 88.2701657102 +-3.80078320743 -85.3431505753 51.9817342621 +-3.79562128576 -84.2349122519 53.7593974759 +-3.79362207019 -96.554129248 25.747010637 +-3.79024247301 87.866538876 47.5931235364 +-3.78449998754 -87.7334148539 47.8385354909 +-3.77994628491 -93.3002553861 35.7879078875 +-3.77863666599 -74.5913871849 66.4969688239 +-3.77854799119 -74.0778721977 67.0685576537 +-3.76692542581 -70.6967295244 70.6242359774 +-3.76099210355 93.6405276912 34.8899199214 +-3.75901598798 -71.2504170956 70.0660250228 +-3.7585222462 -20.7435458358 97.7526409704 +-3.75387501854 -87.7347305486 47.8385354909 +-3.74987911273 93.3638383771 35.6248802122 +-3.74745614441 -70.7964433542 70.5253158862 +-3.73620477248 -79.2260308682 60.9038324474 +-3.71401744401 -36.2491547181 93.1246737264 +-3.69901960223 -93.3159953338 35.7553110579 +-3.69735742412 -72.2383205859 69.0503771677 +-3.68517888162 -51.7911385602 85.4640124453 +-3.68200231895 -51.7464954634 85.4911870673 +-3.67451343491 85.8799092983 51.0993065504 +-3.66604659162 -51.7775419511 85.4730732564 +-3.66413166155 56.2044541334 82.6294951862 +-3.66154752995 89.2227941921 45.0098441037 +-3.61181239903 -24.4002060274 96.910189129 +-3.60187867338 72.3516534043 68.936671806 +-3.5954287474 92.3313284025 38.2360914263 +-3.59435709374 -69.7489763819 71.5692733704 +-3.5630096217 -63.332436165 77.3065811677 +-3.55550821374 58.1320454387 81.2897512265 +-3.55509125742 -74.555881148 66.5490940013 +-3.55073808218 -87.6427189452 48.0223497443 +-3.55038004536 -71.8220280326 69.4909425092 +-3.54580143885 92.2998204643 38.3167122078 +-3.52815808646 -70.6226033258 70.7106781187 +-3.51101523012 -59.9812144908 79.9370169588 +-3.50588925246 82.6140758194 56.2372049186 +-3.50116871385 -78.615578008 61.7035875141 +-3.47580547247 -81.2357510735 58.2122970157 +-3.47325117051 -80.5179513375 59.2013178799 +-3.470131509 -80.4456304079 59.2997363872 +-3.44692111354 -94.9073392205 31.3163806484 +-3.4354738855 -95.9776354476 27.8655883317 +-3.43010521044 -48.2063584799 87.5464527 +-3.40322746187 -76.4163957451 64.4123629761 +-3.39568160228 -85.2875077708 52.1009631841 +-3.3675405482 -68.8543708877 72.4412539946 +-3.36496716545 57.144224381 81.9952109325 +-3.35923769614 92.4930687558 37.8648617352 +-3.34903822365 -66.8032201168 74.3378350842 +-3.34319031694 -67.6307058945 73.5860767993 +-3.33933023028 -72.9756306532 68.2891367963 +-3.32471018852 -87.3394175724 48.5877807712 +-3.30760778912 -93.7789314048 34.562577382 +-3.28775640378 -70.2377482781 71.1044961634 +-3.28048290257 -75.1354112862 65.9083333334 +-3.23656534593 -82.0112170493 57.1286698852 +-3.23547928438 -69.6413920035 71.691060765 +-3.22586415292 -86.7339192295 49.667102347 +-3.22576898396 -93.7817821284 34.562577382 +-3.22129788619 -75.2874564725 65.7375245794 +-3.20265299606 61.1102595812 79.0903229713 +-3.20149772428 -77.6815928282 62.8913392129 +-3.19788577125 -82.1223453675 56.9709918989 +-3.18025005504 91.0704460791 41.1832473288 +-3.17944015997 60.2648241595 79.7373320929 +-3.15793706871 55.1032829423 83.3885822067 +-3.14913699165 -64.3887856124 76.4471531423 +-3.14593520472 -87.0388306584 49.1359852787 +-3.14386165696 -86.5629165598 49.969766965 +-3.14194383793 -71.9623450304 69.3653305813 +-3.13960635006 -67.0727552242 74.1039025868 +-3.13501105364 93.0336577317 36.5364233984 +-3.11316247208 -70.4565710226 70.8955557081 +-3.09960832078 -69.0565580426 72.2605301639 +-3.09486601115 -64.4314819461 76.4133884775 +-3.08492703415 -73.604129238 67.623334614 +-3.08204342665 -71.1603977713 70.1904466245 +-3.08043380422 85.2265983854 52.2200905326 +-3.07611373535 -81.9374892229 57.2432125595 +-3.04210572794 -87.9951663057 47.4088209047 +-3.02607892381 -94.7117974687 31.9455515932 +-3.01804403937 -77.8534427964 62.6875813454 +-3.01673714558 50.3322959681 86.3571611366 +-3.0153689607 -17.1010071663 -98.4807753012 +-2.9970103604 92.7872250236 37.1691915613 +-2.99446856321 89.3261377924 44.8539214018 +-2.99149763986 -68.516560582 72.7772757657 +-2.98686171804 -84.2674660833 53.7593974759 +-2.98612487313 -86.3758785261 50.301994663 +-2.98464029037 -66.4951710402 74.6289766155 +-2.98460513081 19.5044818712 98.0340110326 +-2.98180616551 54.5287295857 83.771871662 +-2.97613708419 -94.7022175682 31.9786271707 +-2.97567602557 90.6555778251 42.1035813367 +-2.97398627432 90.6040986403 42.2143662183 +-2.95932086358 90.1573089787 43.1613491188 +-2.95249151199 -67.6231733743 73.609708712 +-2.93954614129 -79.0356771097 61.1941240013 +-2.93906436077 92.4941438292 37.897166886 +-2.93738095266 92.4411659517 38.0263412733 +-2.93193447803 -78.0970309827 62.3879596709 +-2.88236328396 43.3960623945 90.0470640862 +-2.88191756767 -69.6318683813 71.7153920498 +-2.85072740165 -87.3137160117 48.6640354832 +-2.84024987499 -86.5297469792 50.0453381281 +-2.82692476414 55.8043173409 82.9330251619 +-2.82301973486 92.3981803959 38.1393080575 +-2.8210778034 -96.7605250148 25.0886890629 +-2.81304486592 -88.0441463423 47.3319667185 +-2.78614266505 -82.6807429566 56.179463803 +-2.76718334828 52.8010037085 84.8787176134 +-2.75913802199 -84.0586305543 54.0974471368 +-2.75149079373 91.0987849811 41.1514358605 +-2.75101178998 -72.2684847242 69.0630005849 +-2.74599221558 58.8838427135 80.7784166349 +-2.73921575338 92.2937904586 38.3973038094 +-2.7305453997 -87.8642650442 47.6698547309 +-2.73051465784 90.4042885658 42.6568739901 +-2.69544122658 87.225013952 48.8316653174 +-2.68081988215 55.8115269659 82.9330251619 +-2.6633177557 72.632633237 68.6833846544 +-2.6520634759 -79.9454426883 60.0141046146 +-2.63780197954 -68.3529236419 72.9446353773 +-2.61038716084 -74.0109874279 67.1979137981 +-2.60559092056 -75.3686514815 65.6717387452 +-2.60390890333 49.3558942114 86.9322458298 +-2.60249635647 -68.3670164073 72.9326955506 +-2.58990231256 48.289392687 87.5295776291 +-2.58736025077 -80.1044871176 59.8044873781 +-2.58531900606 32.4871110067 94.5404873273 +-2.56423023159 -96.6349352666 25.5951950439 +-2.54424717276 55.6003836597 83.079023485 +-2.54273241347 -83.2243024509 55.3827589908 +-2.54263329942 22.0427254759 97.5071959883 +-2.5315693971 89.5120910996 44.5104111795 +-2.52717160991 -73.4716771414 67.7903094969 +-2.5234369729 59.7092156105 80.1775644244 +-2.51182434269 -46.8336089191 88.3193286551 +-2.51076460916 -73.7439322616 67.49465546 +-2.49504485064 87.6791233774 48.0223497443 +-2.49002406102 -68.8916867254 72.4412539946 +-2.48594015647 -68.4477416049 72.8610099486 +-2.47610514711 89.7686146243 43.9939169856 +-2.47419337967 -96.4147839481 26.4209727938 +-2.46632083766 -81.6571264554 57.6717518425 +-2.46415075757 84.518236516 53.3909698101 +-2.45754722108 55.618796602 83.0693079675 +-2.45237420519 -68.512550318 72.801210908 +-2.44271520541 61.3523635205 78.9298462742 +-2.4296405704 -78.6236518763 61.7447828754 +-2.37659927367 39.1938281898 91.9684489797 +-2.35378647552 -86.9865354991 49.2727341548 +-2.34707746379 -88.4513707016 46.5923410914 +-2.33970069372 -86.4659813316 50.1812701416 +-2.33742934411 -81.1441285197 58.3966337286 +-2.33395998137 64.2631276965 76.582002125 +-2.31385615043 -88.3626014199 46.7621293358 +-2.31144485125 -70.7962603516 70.5871570679 +-2.30593162132 92.3725283393 38.2360914263 +-2.2898095387 92.3729293934 38.2360914263 +-2.28770625613 -26.25415061 96.4649468762 +-2.28312400761 -26.2545494902 96.4649468762 +-2.28060850773 92.0017517169 39.1213050121 +-2.26960981368 -82.2823412607 56.7843745053 +-2.26322965616 -92.6054993888 37.6709340802 +-2.25524880147 -82.2827361291 56.7843745053 +-2.24899385699 92.0230073347 39.0731128489 +-2.20878423823 -74.421691464 66.7572701047 +-2.20000621263 72.8397468667 68.4801522272 +-2.19784004206 -72.7680273804 68.5564270534 +-2.19007069918 -75.1175279238 65.9739387103 +-2.18166492941 -34.8708042967 93.6977446145 +-2.16800141077 -70.156956656 71.2271100259 +-2.16551610857 59.6252032274 80.2505182542 +-2.16515562192 58.2146128693 81.2795850728 +-2.16161795743 -36.0651888293 93.2449975201 +-2.1442530089 -67.1119497589 74.1039025868 +-2.13994893994 55.7044454874 83.0206924295 +-2.13113152413 -71.8052990477 69.5662080833 +-2.12584970029 -64.0829289806 76.7389013234 +-2.1205841158 53.4964500689 84.4608368004 +-2.11356781584 -46.544377528 88.4825053421 +-2.10453714791 -70.0842281762 71.3005742217 +-2.09657407891 39.7395962326 -91.7407699357 +-2.08077175114 -68.1042081465 73.1948578909 +-2.07882032489 -68.0403374508 73.2542898787 +-2.02180117949 -74.7176865449 66.4317667789 +-2.01576120484 -86.8224545209 49.5761847839 +-2.00345244924 -75.5016048702 65.5400170912 +-1.99474287956 91.41777193 40.4822427269 +-1.99380169844 -87.859091333 47.715876026 +-1.97265215055 -86.9271129616 49.3941866584 +-1.96838046132 65.5500072903 75.4938542041 +-1.95577169455 23.6369522852 97.14663887 +-1.94270072459 -77.8219857335 62.7691361291 +-1.93192622506 -85.132479719 52.4283182828 +-1.9312274443 -94.5605138773 32.4742909981 +-1.91626418464 52.2593721347 85.236646788 +-1.89960765213 -87.0577861831 49.1663844071 +-1.89848837975 -76.0508984912 64.9049811691 +-1.88954301023 91.7351972256 39.7628371371 +-1.88455690067 -99.9670074594 -1.74524064373 +-1.87476448626 -65.8816640721 75.2069916777 +-1.86792446877 -87.7114863637 47.9917286421 +-1.86400798905 -65.9082279622 75.1839807479 +-1.85207957876 69.3406005734 72.0309024888 +-1.8404556974 -87.8624373547 47.715876026 +-1.84028586001 -59.552016283 80.3129547743 +-1.8325892739 66.8620063381 74.3378350842 +-1.83045450255 -70.8472909766 70.5500588065 +-1.82293045673 62.5249356276 78.0212108937 +-1.77817479558 69.2922146451 72.0793110676 +-1.77450863664 92.4176033071 38.1554415263 +-1.7688312718 92.1219223278 38.8641565272 +-1.76048228723 -75.8271331697 65.170135625 +-1.75716783798 -69.4184873675 71.9582238024 +-1.75628074639 59.1752610189 80.5928282249 +-1.72875086187 -86.1189798785 50.7989441341 +-1.726527354 46.4211997066 88.5555832294 +-1.7135345428 86.87218379 49.5003786139 +-1.68977264689 -45.6474782442 88.9575876378 +-1.67382539036 -81.2623483427 58.2548628905 +-1.6675503465 -86.8471436179 49.5458668432 +-1.660023099 -67.9238484089 73.3729864503 +-1.6556969999 56.7889729175 82.293810353 +-1.63655370958 13.7859431208 -99.0316588987 +-1.62542941654 55.7508210264 83.0012285095 +-1.60545656663 -76.6436960204 64.2118865129 +-1.57266577148 -72.0742519212 69.3024453563 +-1.53374734342 -87.8683264559 47.715876026 +-1.51192558293 -74.0298407047 67.2108381607 +-1.51103450683 -72.1360339638 69.2395073545 +-1.50616306432 -75.0306070648 66.0919017453 +-1.50264790176 -87.843864118 47.7618842395 +-1.49844437086 -72.1362965903 69.2395073545 +-1.49354006909 -75.718979769 65.3024152754 +-1.44469826722 59.1133136391 80.6444604267 +-1.42907091122 -73.0975915123 68.2253609109 +-1.42655709886 -83.3956429859 55.1645870628 +-1.38909277676 -97.0533163943 24.0566871809 +-1.37299032647 -84.5802605445 53.3319268711 +-1.36151056912 59.0871268377 80.6650961137 +-1.29734898084 -40.6051054892 91.3758299214 +-1.29684043946 -80.7577151403 58.9619339082 +-1.22325533562 -70.0802512424 71.3250449154 +-1.1649983854 78.5230513801 61.909394931 +-1.16111849388 92.3940101754 38.2360914263 +-1.14939607324 -84.4249687385 53.5826794979 +-1.12231888979 91.8584803163 39.5064550964 +-1.10796720731 -88.1645878225 47.1781502685 +-1.10422865051 -68.7632650051 72.5974797422 +-1.04845656703 -77.0108015473 63.7827342144 +-1.04671656734 92.2613366119 38.5583992277 +-1.02094522 -87.3032625385 48.7554922136 +-1.01704091904 -86.9693972096 49.3486532416 +-0.986736620191 89.7358180397 44.1192623644 +-0.977149310497 -67.4489338739 73.8219919705 +-0.96517521098 60.104036223 79.9160388565 +-0.951544151422 -80.1719177814 59.7625146976 +-0.926211709006 -78.0375444184 62.5242656336 +-0.919755393061 -81.0705252673 58.5382266806 +-0.916942381772 -71.9645009826 69.4281629815 +-0.903490257695 50.745793955 86.1629160442 +-0.90288273043 -94.0541470538 33.9558864524 +-0.902170951322 -73.8400229453 67.4302387584 +-0.889350402308 -87.8522138011 47.7618842395 +-0.885722488476 -78.070743508 62.4833938242 +-0.883894498085 -87.3132662017 48.7402531354 +-0.878332728435 -96.775724258 25.1731548668 +-0.867602158699 -68.0921262267 73.2305237754 +-0.86556233526 -72.92755914 68.4165325029 +-0.862377469755 -76.0130301808 64.9713440513 +-0.862130792183 -73.7226928716 67.5590207616 +-0.828794843407 57.2085841821 82.0151875874 +-0.82095970882 -94.0726648443 33.9066328947 +-0.808641464238 -87.4158897032 48.5572685227 +-0.804281975578 51.1979695413 85.8959896931 +-0.756859012306 -74.7643893721 66.4056717928 +-0.756741678502 -74.7527988511 66.4187202975 +-0.73363075632 -87.5686722613 48.2823924874 +-0.701799782806 -85.5516248937 51.7728399366 +-0.681711826047 90.8336677985 41.8184177516 +-0.680245851658 -74.9502811822 66.1966208828 +-0.674083151829 -72.8698453603 68.4801522272 +-0.669761832462 91.3662831692 40.641773078 +-0.663059091338 54.2694247102 83.9904154905 +-0.657093573363 -80.1017958195 59.8604254456 +-0.649844286489 70.2495716386 71.1658301926 +-0.645029864811 -76.9929672983 63.8096146601 +-0.638511065293 91.4584871467 40.4343595529 +-0.636290262275 -86.8002228003 49.6519531995 +-0.63147160076 -86.1428798895 50.7839097349 +-0.60695983541 91.5150710618 40.3066169295 +-0.595657937947 92.2384093611 38.622804535 +-0.595527263722 92.2181742867 38.6710961637 +-0.593239877926 -79.045356025 61.2493245459 +-0.583812606229 -77.7892333748 62.8370458711 +-0.577380523442 -73.5128598957 67.7903094969 +-0.566998978075 -75.5489267586 65.51364879 +-0.564028168984 -44.8815729479 89.3606528733 +-0.558968934895 -86.5570693387 50.0755559253 +-0.552404313114 55.5252483673 83.1663492238 +-0.546267623687 -69.5515239175 71.8490578396 +-0.538242042274 -96.3708647698 26.690198932 +-0.537838075344 -65.5641714385 75.5052988457 +-0.532765091616 92.4995566213 37.9940546168 +-0.527715920016 54.9726659631 83.5327930385 +-0.521196207971 -78.5839609591 61.8408395358 +-0.515933988719 -68.7448489914 72.6214813211 +-0.50362392418 -77.9868221729 62.5923472184 +-0.502337449393 -82.2327363908 56.8992506345 +-0.488675173044 -99.9957217034 -0.785390088871 +-0.487581890367 -69.8398265543 71.5692733704 +-0.484440354218 55.511366258 83.1760394207 +-0.480622344665 -65.5646158257 75.5052988457 +-0.478610262358 68.5547563816 72.801210908 +-0.478578666523 63.7674952222 77.0290692891 +-0.473632779313 -82.2329067297 56.8992506345 +-0.471223883075 -99.996073528 -0.750484533293 +-0.462737701854 28.8159116372 95.7571360805 +-0.456074650366 -87.1030460276 49.1207834691 +-0.445241385754 -67.1317848066 74.1156206801 +-0.429159914114 -74.5114542973 66.6922709185 +-0.390644404343 -79.9360624325 60.083885691 +-0.382121080829 59.1719482502 80.6134884728 +-0.377949799606 -86.6191638346 49.969766965 +-0.372246922724 92.7307088961 37.4282922379 +-0.36959180137 -70.5861894766 70.8339837725 +-0.362259634874 90.2427681616 43.0826132274 +-0.350344057195 -87.274469708 48.8164336698 +-0.347492667671 66.3656044075 74.8029798903 +-0.339379319187 -72.0179952125 69.3779012888 +-0.329864851752 62.9989703265 77.6596479968 +-0.328304561084 -81.7841943739 57.5433555394 +-0.324448972746 -84.4975702151 53.4794854183 +-0.319527424316 73.2298266736 68.0976533192 +-0.308542443908 -76.8612386066 63.9707339446 +-0.305003424692 -87.3766899716 48.6335380423 +-0.29415614381 -73.2774566462 68.0465121782 +-0.288819169119 91.933694399 39.3460597474 +-0.271932275906 -86.5584470263 50.0755559253 +-0.243110666072 92.8612219828 37.1043710237 +-0.239290017767 -62.3192759925 78.2064612424 +-0.228936788933 -72.8726034864 68.4801522272 +-0.223573681555 -71.1654790036 70.2525772694 +-0.2174411673 -62.292052889 78.2282101688 +-0.204686839431 -78.1844348522 62.3470308046 +-0.199193536236 49.6212505599 86.8198814489 +-0.196633216658 -86.6633391811 49.8941577478 +-0.196265409225 18.1366785351 98.3413563645 +-0.184058891104 -87.8815185201 47.715876026 +-0.173211884081 49.6213480554 86.8198814489 +-0.156096368583 -68.7972905363 72.5734693176 +-0.12964200799 -74.2793236318 66.9519624339 +-0.127598060953 56.2370601631 82.6884319778 +-0.120980795739 -86.6460561679 49.9244059975 +-0.120883347673 -86.5762641771 50.0453381281 +-0.117994727035 -84.5074433813 53.464736887 +-0.116432387614 -83.3885009216 55.1936985312 +-0.0679336427026 -77.8462005151 62.7691361291 +-0.0679145179943 -77.8242852193 62.7963057649 +-0.0454270048299 -86.7591804939 49.727683803 +-0.0422361436288 -80.6650850563 59.1028110073 +-0.0298040613177 85.3823428247 52.056264229 +-0.0194447735106 37.1367784644 92.8485826881 +-0.0166024165638 47.5624180094 87.9648572867 +-0.0144034180352 41.262751523 91.0899836935 +0.0100518089313 1.74521169652 -99.9847695156 +0.0280236159002 -80.2817426281 59.6224874966 +0.0313684868427 89.8640916399 43.8684858384 +0.034906584331 0.0 -99.9999939077 +0.0418823602476 -79.9894086312 60.0141046146 +0.0456748486792 -87.2325273355 48.8925770283 +0.0456837820144 -87.2495887473 48.8621241497 +0.0581647075342 47.6084371459 87.9399416044 +0.0687049888973 32.8041678291 94.4663000898 +0.070626890083 -80.9324338933 58.7361571432 +0.0709462322232 58.0702522325 81.4115518356 +0.076124741615 -87.2325060775 48.8925770283 +0.0791352634294 90.6823090837 42.1510682766 +0.0802653010542 65.6980100518 75.3907489863 +0.0844179342424 60.4598525514 79.6529918024 +0.103030913388 -59.0323050242 80.7166423246 +0.111392719875 91.1761363118 41.0718852613 +0.12533461005 89.7642439514 44.0722679139 +0.126817743668 22.0183064648 97.5457743712 +0.127762732552 -36.6011781125 93.0609340027 +0.133908174468 -59.0181544108 80.7269441918 +0.173168041181 -36.7471276405 93.0033258707 +0.173244530429 -36.763359043 92.9969107993 +0.178844142678 56.9276714151 82.2144041031 +0.179660944352 -36.7633282462 92.9969107993 +0.185061099398 -81.5630904022 57.8569618666 +0.185084008069 -81.5731870787 57.8427255041 +0.200373157029 -95.6709953255 29.1036166828 +0.20474380287 -78.2061932332 62.3197353969 +0.212096667334 -71.4835778026 69.9289147602 +0.217093929537 -95.6811121204 29.0702193598 +0.239866326996 91.6219785717 40.0668879095 +0.239902927556 91.6359589238 40.0349032557 +0.240252711709 -80.973094135 58.6796413149 +0.244793318835 -70.1278352812 71.2883356168 +0.256069670878 -86.303931463 50.513026462 +0.25609582509 -86.312746296 50.4979627488 +0.256544111743 -36.7466401473 93.0033258707 +0.271104843566 -86.2950679987 50.5280886365 +0.271160237206 -86.3127002842 50.4979627488 +0.285482414 -81.784355063 57.5433555394 +0.288422701995 -97.2079708621 23.4633163303 +0.290135476493 -83.1173538622 55.6005513314 +0.312778444474 48.4341504792 87.487343296 +0.31460789061 -81.9346170281 57.3290463408 +0.319216094188 -73.1584755169 68.1743027916 +0.327762730804 -69.5528968423 71.8490578396 +0.346764865202 -86.3828545178 50.3773977046 +0.368943923775 -70.4624551012 70.9570736537 +0.392268926715 -40.8630247035 91.2691587404 +0.407463332603 55.5845502436 83.1275631055 +0.408822785468 -70.9804883758 70.4386480127 +0.411754235885 -78.6385477281 61.772237046 +0.423610525436 -75.8463840716 65.170135625 +0.429695825205 -74.6045000676 66.5881666001 +0.442175199199 -76.7711896265 64.0779909518 +0.446524055904 -77.5262453225 63.1623456061 +0.451053121941 -86.1440135071 50.7839097349 +0.451701516884 -1.68577301087 99.9847695156 +0.469621883588 -70.8077825606 70.6118784917 +0.471005199488 -89.954544804 43.6801788368 +0.476641732099 91.0310333987 41.3898993841 +0.488819334686 -93.3567629208 35.8367949545 +0.498788000916 -75.205337628 65.9083333334 +0.516435491244 -92.4664574301 38.0747625693 +0.536691152415 25.2012217215 96.7709170482 +0.539409285139 -73.5840997522 67.7132874795 +0.539671382823 71.9077023968 69.4909425092 +0.542603367867 -74.0198239946 67.2366807435 +0.554216917684 -93.393875258 35.739011009 +0.564800837334 87.4601470453 48.4809620246 +0.56913424405 -93.1673844315 36.3251230473 +0.571556761273 68.2229667656 73.111559473 +0.575650554613 52.3508222623 85.2001175756 +0.583649562654 -79.6191849526 60.5016094056 +0.584574204944 -71.2614542341 70.1531425771 +0.593024454771 -97.0782164885 23.9889183874 +0.596177565353 -81.3282059609 58.1839108989 +0.607852533037 46.4338606585 88.5636895101 +0.634645985992 -69.9260348083 71.4838924546 +0.639934445062 53.9173843257 84.2170181815 +0.654518352354 55.1461447721 83.4174701276 +0.663134756982 -99.9849098216 -1.60563391348 +0.672976548364 -72.7502191345 68.6072351756 +0.676998659664 -82.5282891277 56.4678950066 +0.691589981464 92.1498677723 38.8319916157 +0.69803990372 -99.9852266193 -1.57073173118 +0.715259493181 -74.509257167 66.6922709185 +0.720116444959 -66.5451977584 74.6405927603 +0.728255266846 -97.0352786232 24.1583183765 +0.732745797576 58.3069885062 81.2388957023 +0.756311153848 92.1967343425 38.7193771905 +0.760205648183 56.5635752651 82.4620157442 +0.776815844727 -66.4272247991 74.7450357056 +0.784335815076 -89.8759822976 43.8371146789 +0.788409570694 -66.4270882074 74.7450357056 +0.792455711378 -96.602870827 25.8313252067 +0.796120608059 -67.076778138 74.1624704726 +0.80564267321 92.3175064097 38.429532266 +0.808244599574 -66.152428972 74.9880182547 +0.816410565235 -75.4436353952 65.6322432357 +0.816539863192 89.9673143078 43.6487756861 +0.821522043395 56.7065702096 82.3631592194 +0.828195194572 -86.2738758802 50.5582083675 +0.829045380416 89.6215971335 44.3540529265 +0.847185131147 -80.897263546 58.7785252292 +0.853392376564 -72.975451807 68.3655992076 +0.866108784148 59.7842248693 80.1566984871 +0.867127870381 -87.1598740743 49.0143289315 +0.870762850401 -87.5252462549 48.3587948575 +0.870930727195 -87.5421204908 48.3282383255 +0.87837301418 -71.8922322056 69.5034920658 +0.880458895198 -76.430829447 64.4790904261 +0.886152613631 -69.5480238477 71.8490578396 +0.893535334024 -76.4081640482 64.5057676599 +0.893798577959 -76.4306746138 64.4790904261 +0.901904963709 -77.1238694195 63.6482154754 +0.903279416087 -66.3473090267 74.8145618928 +0.912943661312 -87.1765110795 48.9838999048 +0.916590840718 -87.5247783268 48.3587948575 +0.943081795033 -69.2708570328 72.1155944485 +0.946685684887 -87.4822211836 48.4351604003 +0.950526180069 -54.4556083852 83.8670567945 +0.97148639972 -95.9658090574 28.1001727065 +0.997349388431 -85.2855312855 52.2052051767 +0.997730502072 90.7356238277 42.0244107924 +1.00174397714 35.2025871364 93.5936662809 +1.01062579067 -65.7954991502 75.2989437316 +1.02027857689 -66.4239314479 74.7450357056 +1.02229181925 73.2115003183 68.1104334195 +1.0345609373 -79.0301196332 61.2631200187 +1.0369592646 57.6766884172 81.6842967082 +1.07309313924 -70.6654971278 70.7476924486 +1.08127152411 -17.3311207936 98.4807753012 +1.08619258768 -79.7825722517 60.2790291109 +1.09795725774 -96.7778740714 25.1562632376 +1.09860646546 39.3307193105 91.9341480754 +1.11362704964 -75.0605280943 66.0657018202 +1.11880796117 -85.4657505708 51.9071647088 +1.12575235674 -77.7064420477 62.932039105 +1.16360528599 -74.0713205062 67.1720589323 +1.17032805771 35.2790932474 93.5628981588 +1.18853986784 57.7022796501 81.6641555162 +1.20006806513 -88.1469070945 47.2089250705 +1.20845915101 -74.4446540367 66.7572701047 +1.2106188252 90.0768485479 43.4130827946 +1.21973943475 -87.3517251472 48.6640354832 +1.22345176667 -71.5222312694 69.8789925516 +1.22532438019 -73.8941913644 67.3657707057 +1.22627083835 -63.865010035 76.9399555047 +1.22678635148 -63.8918583051 76.9176536145 +1.22892607236 -78.2294288964 62.2787780488 +1.23247099343 -17.3210251233 98.4807753012 +1.23286005865 -85.0996830047 52.5026095407 +1.2349107805 -17.3553136487 98.4747078367 +1.24573023467 -73.5755316317 67.7132874795 +1.2742855256 -17.3524670546 98.4747078367 +1.31189692587 -66.5100982858 74.6638182285 +1.33163339539 91.917634148 39.3621046838 +1.35234742797 -79.0573916639 61.2217280034 +1.3544817797 -81.6831342355 57.6717518425 +1.35637889125 -97.1371694052 23.717726625 +1.35891460455 -83.7131544883 54.6832800472 +1.38459749601 -86.2225812557 50.6334807353 +1.38597328705 -96.8353634781 24.9197002009 +1.38659768117 -17.3093686465 98.4807753012 +1.39124195348 -66.4171971947 74.7450357056 +1.40387597568 -78.0849547225 62.4561364338 +1.40717690633 49.4500279433 86.9063552887 +1.42122704103 88.50360078 46.5305573002 +1.4331937528 -80.497331607 59.3137889518 +1.43367380724 -76.049749483 64.9182577014 +1.43657410915 53.7843582093 84.2922242371 +1.4397956949 55.7269379823 83.0206924295 +1.45318364948 -87.6354314162 48.1447756021 +1.47986152464 59.2812680824 80.5204400411 +1.48104206315 92.2284418401 38.622804535 +1.49213366074 -97.1434530106 23.6838146066 +1.50684089317 36.4077543096 93.1246737264 +1.51311234634 91.2494806147 40.8808363244 +1.51817583592 41.0119660586 91.1905355952 +1.52412102005 41.9650656044 90.755772951 +1.53256806771 -81.2956315633 58.2122970157 +1.53842140499 64.3271929916 76.5483213493 +1.54126745198 -76.7793576344 64.0511884034 +1.54472265999 91.2346732617 40.9126902895 +1.54722618631 -78.4407400405 62.0052932662 +1.57758169411 -71.1606056939 70.240155419 +1.5789295254 -86.1484479418 50.7538362961 +1.61264817765 -97.2520705291 23.2257215962 +1.61564757664 45.1367232851 89.219201375 +1.62353928076 -67.886291951 73.4085518544 +1.62537065359 -86.2183785446 50.6334807353 +1.62919653137 -72.9144964938 68.4165325029 +1.63339882458 -82.8094907617 56.0349912828 +1.63464633221 60.409991596 79.6740914397 +1.64758777128 -72.6027892288 68.7467850211 +1.64999378315 56.2563008639 82.6589749127 +1.65124263763 35.2762037341 93.5567359834 +1.66086945634 -86.499198365 50.1510737159 +1.6878508794 -74.3770279087 66.8222184522 +1.69767564656 90.0538232425 43.4445257404 +1.69837246042 -86.8724815351 49.5003786139 +1.70541932473 87.2329316744 48.8621241497 +1.71276350206 -79.7715807204 60.2790291109 +1.71634732385 -84.0391355321 54.1708210283 +1.7287764006 -75.025807932 66.0919017453 +1.73014605853 36.2838966901 93.1691227586 +1.73808114499 -79.6551311635 60.4321036641 +1.74495864782 -0.0313723115154 -99.9847695156 +1.7452167204 0.00913801688769 -99.9847695156 +1.77139128148 -70.9595591803 70.4386480127 +1.77392754793 -82.6202826089 56.3093427655 +1.77957541229 -67.9592431984 73.3374009306 +1.80660329056 -75.5408876619 65.5004616457 +1.81349575712 -71.643772203 69.7415309387 +1.81926791634 43.4064175101 90.0698239323 +1.82117877339 -71.9472966336 69.4281629815 +1.84331836839 -84.4780848315 53.4794854183 +1.85006469428 -71.6062986208 69.7790459842 +1.85156265945 -73.1476392332 68.161533069 +1.8833575947 -65.380975514 75.6424550435 +1.884155197 -64.6248911857 76.2894055451 +1.88638491827 91.5818753973 40.1148557352 +1.89521326554 -66.6002607901 74.5708617985 +1.91549450389 -72.1868438747 69.1765166238 +1.9261876239 90.4473292857 42.6095109843 +1.9463727731 72.8708736785 68.4547105929 +1.95413312656 39.9551557388 91.6502421907 +1.962358854 -77.5247420151 63.1352795449 +1.96791601881 -96.3569312122 26.6733783743 +1.97836712656 -74.5562457119 66.614204858 +1.99167948147 -77.6121011708 63.026938405 +1.99861409197 89.4477353686 44.6666338461 +1.99891200828 -78.9688070748 61.3182832438 +2.01542113531 59.1951468246 80.5721581569 +2.05045216796 85.7371276169 51.4289859311 +2.05869283742 -96.6693309903 25.5108257352 +2.06658884519 91.0665379809 41.2627540369 +2.06730427287 -74.9479644672 66.1704531892 +2.06765680005 -83.4110926578 55.1209072583 +2.07661978951 90.1215897104 43.287258152 +2.10356448569 -84.2659722741 53.8035401546 +2.11189516014 -78.0471997899 62.4833938242 +2.12856510423 -87.0953744895 49.0903753615 +2.13949734075 88.8119295271 45.9114770487 +2.14825303894 92.5291157131 37.8648617352 +2.15311702625 -86.2509805958 50.5582083675 +2.15791141512 -80.7907366531 58.8914279787 +2.15866867796 -67.5631388927 73.6923497556 +2.16145273305 -78.3612188879 62.0874181818 +2.1809177097 -73.482770336 67.7903094969 +2.18286740137 55.5576853214 83.1178602446 +2.21106398494 -86.1611134178 50.7087145436 +2.21384826215 -61.2507097106 79.0155012376 +2.22535072219 91.0555914563 41.2786516097 +2.25168683259 -83.2133409859 55.4118199338 +2.25356669041 67.2247527275 73.9983382104 +2.25785920529 -73.0647727506 68.2381202461 +2.26247341129 -55.8445361829 82.923271719 +2.26287494516 38.314422558 92.3411307113 +2.26576795855 -61.2074019452 79.0475821431 +2.27301679868 -74.3964392506 66.7832555471 +2.27752829565 -80.5296194983 59.243508069 +2.28631980742 -69.6539681919 71.7153920498 +2.28789452489 -86.2210173585 50.6033764121 +2.29121383809 63.3911890353 77.3065811677 +2.29245220598 38.2480731187 92.36790333 +2.29724492103 -81.2267666395 58.2832312683 +2.31164178196 -76.5358757979 64.3188621489 +2.32692493261 28.0036627336 95.9707262339 +2.3282673319 -71.31150895 70.0660250228 +2.33050953862 -77.1605661334 63.5674111417 +2.33817350745 -88.1158184434 47.2243103147 +2.33896354888 56.9947164793 82.1348375719 +2.35183470225 -96.2309885293 27.0936472296 +2.35235282708 -71.2862431915 70.09092643 +2.36571798259 35.1536596396 93.5875183578 +2.36774336878 65.1933176554 75.790666473 +2.37016572614 -72.5947970306 68.7341091345 +2.37037669181 91.7448464165 39.7147890635 +2.37753713484 89.0133743202 45.5078730475 +2.37792247369 -74.8346671928 66.2881442707 +2.41889415535 -82.9659742615 55.774510898 +2.46212072165 -76.2270803111 64.678977951 +2.46769340103 -29.0825888238 95.6457710334 +2.47792641023 -77.9818519274 62.5515039842 +2.47796977536 -67.5779183617 73.6687492475 +2.48069270367 77.6420149138 62.9727217439 +2.48506602116 35.5380997945 -93.4391133833 +2.48946542692 -76.2487767791 64.6523518642 +2.49631128608 92.2536825499 38.5100829128 +2.50542648391 -74.7378262974 66.3926212652 +2.50915285386 89.8290604549 43.8684858384 +2.50920127949 -72.9492312933 68.3528606764 +2.52566396331 -71.2558271715 70.1158192968 +2.52804073028 -15.9614209899 98.6855716407 +2.52913495885 71.7072848237 69.6539214946 +2.53147721738 -93.5532747448 35.2331719779 +2.5380202913 -29.1268019224 95.6304755963 +2.5391414933 -81.7052158063 57.6004381105 +2.54186640753 89.3244938251 44.8851168881 +2.57671055438 -24.1908012067 -96.9956993876 +2.58234927783 -78.6726659477 61.6761145412 +2.60480285911 -39.7416118591 91.7268733191 +2.60688118713 -71.0935241401 70.2774145499 +2.61531865442 -73.0647674116 68.2253609109 +2.61876657632 92.026865843 39.0409787882 +2.62073379698 89.3535420999 44.8227204503 +2.62281925242 92.1692821557 38.7032846937 +2.62640507178 -85.9629306232 51.0242741749 +2.64140839344 -85.9624709197 51.0242741749 +2.65881628769 -73.5616742102 67.6875969683 +2.68213105137 -73.1456997689 68.1359873953 +2.68871671663 89.0204054478 45.4767876649 +2.69186595812 92.328670646 38.3167122078 +2.69509357944 40.7919017598 91.2620250784 +2.69602528527 63.792976317 76.9622480199 +2.70134774671 -72.6312287708 68.6833846544 +2.70326028888 -73.0258093905 68.26363268 +2.70864553031 -72.149352411 69.189118986 +2.71475275815 -86.3848334512 50.301994663 +2.71801694557 -74.124361435 67.0685576537 +2.7240139747 -74.2879093317 66.8871159118 +2.73934370902 -29.1420845982 95.6202640726 +2.74244924924 -87.2661500877 48.7554922136 +2.74373834227 -73.7709861558 67.4560116039 +2.74908131087 -74.2636173929 66.9130606359 +2.75516479102 91.2204269251 40.8808363244 +2.75916971439 46.1698777913 88.66075438 +2.76352602797 -94.7865489693 31.7470165273 +2.76371117782 -84.6485331353 53.1694248471 +2.78518420797 -36.8696269858 92.9132571534 +2.79161912937 -36.8691403179 92.9132571534 +2.79238777157 -73.3554228117 67.9057031084 +2.80202815715 -66.8543665131 74.3144825477 +2.80750662732 -73.0814632808 68.1998360062 +2.80839454036 -79.2324231983 60.9453528518 +2.81124743333 -73.8508620471 67.3657707057 +2.81300291067 -74.2378452514 66.9389972068 +2.82329179587 -74.167264846 67.0167579691 +2.82662227807 -73.5790577351 67.6618982095 +2.82834223899 -75.3376765828 65.6980590831 +2.82885250448 -95.3139671326 30.1205123289 +2.83681253236 -79.252693555 60.917674438 +2.84946902902 15.6796152771 98.7219843349 +2.85387118403 93.4079564635 35.5922616389 +2.85698378762 -67.601554072 73.6333316555 +2.85940805315 24.1590166582 96.9956993876 +2.86451251678 60.2945456905 79.7267980545 +2.86551852355 -86.3799637446 50.301994663 +2.89083103452 -73.5765630253 67.6618982095 +2.89419882182 -86.3350532153 50.3773977046 +2.89825011508 -86.0076103764 50.9341840379 +2.89897606584 -72.1782022123 69.1513055782 +2.90020033721 64.6139228557 76.2668329696 +2.90219753431 -23.3002337779 97.2043021443 +2.90554109971 -71.7173489265 69.6288711231 +2.90864389115 92.554549342 37.7517574003 +2.91692920719 -68.7356026758 72.5734693176 +2.91742190805 -70.4897116394 70.87093341 +2.92417083425 -72.1771858814 69.1513055782 +2.9276382952 -74.5133703665 66.6272209433 +2.92891167398 -87.3705508167 48.5572685227 +2.9340766891 -96.0331037956 27.7314653302 +2.93742261031 21.4437080102 97.629600712 +2.93868809411 -93.5105713818 35.3148290685 +2.94092228059 -68.7345802878 72.5734693176 +2.94544590088 61.770654707 78.5856893175 +2.9485657904 59.6476918383 80.2088450119 +2.95672865938 90.5603834093 42.3092745435 +2.95948678287 72.1153222736 69.214317387 +2.97014358292 -86.3500640525 50.3472410885 +2.97842708211 51.9709882299 85.3823480265 +2.98090196262 -8.18996083191 99.6194698092 +2.9953674478 -95.3141376601 30.1038691196 +2.99824899171 72.1378979242 69.189118986 +3.00498144351 -74.1718307557 67.0038029434 +3.00920419047 -86.1723333783 50.6485305836 +3.02132137472 61.1194930398 79.0903229713 +3.04572397147 75.8319060603 65.1171681568 +3.06702749254 -87.8281761022 47.715876026 +3.06825498423 -71.7105718669 69.6288711231 +3.09549396721 -78.0907190721 62.3879596709 +3.10743376629 -85.9736084075 50.9792360946 +3.11169026113 68.0009293913 73.2542898787 +3.11831712274 -74.4007926173 66.744274333 +3.11855959284 -68.6760150038 72.6214813211 +3.1233668552 -78.4479247862 61.9368038909 +3.12799111885 -76.8763450264 63.8767817516 +3.12799311611 -96.842441712 24.7337247968 +3.1311858817 -68.9540674756 72.3569779188 +3.13871616772 -71.3171485186 70.0286569056 +3.14369043918 -68.7002412332 72.5974797422 +3.15525520065 -68.9529702846 72.3569779188 +3.16049282053 92.8271681147 37.055743751 +3.18069143245 71.9848751298 69.3401828276 +3.18568805624 -77.6272839497 62.959162782 +3.18836756249 -86.1304857854 50.7087145436 +3.19065328248 -97.2049761054 23.2596722241 +3.19131231466 -70.8236919743 70.5253158862 +3.19271924836 -71.1309879412 70.2153052995 +3.19772664583 -78.929352489 61.3182832438 +3.19844580148 -76.3126049748 64.5457687724 +3.20178999057 57.2682095427 81.9152044289 +3.21372681332 -74.5015797774 66.6272209433 +3.2162313458 -74.5596406013 66.5621202286 +3.21673195844 -74.5712459539 66.5490940013 +3.22480369385 58.9724612627 80.6960312144 +3.22622496368 -74.7913156513 66.3012109666 +3.2415522011 -74.2437516271 66.9130606359 +3.26490212242 -77.8982047573 62.6195665085 +3.29660827772 -67.8897466271 73.349265005 +3.30486641678 92.3288241228 38.2683432365 +3.31894436395 -70.9040300297 70.4386480127 +3.33117465063 -65.7583568122 75.2644789048 +3.36511574893 -74.6808515621 66.4187202975 +3.39371657619 -78.6741564949 61.6348909921 +3.40837849978 -78.6950526726 61.6073992379 +3.41204432636 -82.0938174275 56.9996762596 +3.44743298999 91.8282052505 39.4423113706 +3.44989723999 -94.0838247337 33.7095258423 +3.45823912332 -64.4797551714 76.3570674869 +3.46057572793 -82.5668355513 56.3093427655 +3.47402814917 -83.5851487664 54.7855275974 +3.48151823265 -96.3234320371 26.6397348219 +3.49300907091 55.5197893177 83.0984469274 +3.4986606807 -80.1325039643 59.7205256328 +3.5108472745 -86.2857649383 50.4226211181 +3.5206321883 -15.1890475669 98.7770114096 +3.52354229449 -66.128974801 74.9302565154 +3.52804789608 -89.7948151526 43.8684858384 +3.53120949797 -80.2352869008 59.5804439009 +3.53222412068 -69.7271318465 71.5936483022 +3.53811050755 87.331033051 48.5877807712 +3.54038654458 -70.374422638 70.9570736537 +3.55318860456 91.6580282334 39.8268842755 +3.56744061536 -86.1952327065 50.5732659231 +3.58380779656 54.2431389688 83.9335343977 +3.59588611114 92.7594528125 37.1853938664 +3.59958954928 -97.2392267926 23.0559260896 +3.6110415785 88.7482309719 45.942484457 +3.61183237484 -86.1757098177 50.6033764121 +3.61288790512 -80.1795734483 59.6505074801 +3.61546644695 -69.6853188328 71.6301943425 +3.62163653128 -80.6868892611 58.9619339082 +3.63470257726 56.2063649638 82.6294951862 +3.63746295481 -77.1322156811 63.5404608684 +3.64572695991 92.789947332 37.1043710237 +3.67612440842 91.5275065686 40.1148557352 +3.70245271475 64.2122096803 76.5707775321 +3.70710963285 -70.2665560361 71.0553899503 +3.71642586514 -74.6525856312 66.4317667789 +3.71814900739 -73.3973432053 67.8159669868 +3.78888494141 -80.0462019336 59.8184746287 +3.80391274036 -87.1239255719 48.9382451749 +3.83214143217 -82.1747461873 56.8561850734 +3.85266074965 57.7000082994 81.5834912675 +3.87489857349 56.8390629672 82.1845854285 +3.88861192111 55.6097412856 83.0206924295 +3.88981425377 64.5218901057 76.3006883472 +3.89466068931 -75.5764075048 65.3684805299 +3.90490569523 -78.9938662127 61.1941240013 +3.92275619111 -74.8506470751 66.1966208828 +3.93684090173 30.8171984936 95.0515731628 +3.95994047745 -14.5448984629 98.8572951285 +3.98453863636 -86.0884658989 50.723756673 +3.99089058348 -97.2480641753 22.954015041 +3.99183195127 90.3424713317 42.6884428311 +3.99682745795 -74.5218727686 66.5621202286 +4.00282468996 -81.2623189768 58.141318432 +4.00908634584 40.5236613083 91.3332365617 +4.01045805588 -74.5327734207 66.5490940013 +4.02258503283 -96.7834323608 24.8351772716 +4.02433876303 -97.2346434236 23.0049737188 +4.02832975665 -68.818872986 72.4412539946 +4.02833897697 -83.8652946951 54.3174449951 +4.03580926099 -86.2187218754 50.4979627488 +4.05074371293 -76.0233613023 64.8385688589 +4.05777422294 33.6794879783 94.0703277228 +4.06761107431 58.1695484358 81.2388957023 +4.0930695001 -86.1541936168 50.6033764121 +4.10560529218 17.7550520331 98.3254907564 +4.11020792299 -86.1975547772 50.5280886365 +4.11302586032 91.634613041 39.8268842755 +4.12027767609 89.0211933135 45.3679452137 +4.14156505786 -86.2225289535 50.4828974973 +4.14788993248 -67.8174009269 73.3729864503 +4.15253034507e-15 -67.8159669868 73.491459515 +4.16731568426 -95.4472213986 29.5374576981 +4.17846758956 -78.4204515919 61.909394931 +4.18328769992 -86.1498601259 50.6033764121 +4.2077398714 -86.0334946404 50.7989441341 +4.21033620202 -86.0865804781 50.7087145436 +4.22045885037 -65.7993675197 75.1839807479 +4.23235889188 -96.1666336003 27.0936472296 +4.23511463661 59.3735065583 80.3545301958 +4.23580921827 91.5173250208 40.0828784059 +4.25009070982 63.1547138543 77.4171741084 +4.25565150099 66.7125855714 74.3728469045 +4.26287286161 55.6549446402 82.9720136676 +4.26326577462 89.407419776 44.5885394908 +4.26928755648 -66.0194691132 74.9880182547 +4.26991661399 89.546898387 44.3071190824 +4.30994391548 92.4205313413 37.9456159529 +4.32234880455 92.3401888763 38.1393080575 +4.33169920134 61.1789107181 78.9833986695 +4.33713478991 91.9687211141 39.0249099737 +4.34462230043 91.4490777284 40.2267378703 +4.34910901734 62.1951565711 78.1847027868 +4.35778713738 -49.8097349046 86.6025403784 +4.36184122333 -74.9650558181 66.0394938452 +4.37377553179 91.0568787783 41.1037092578 +4.37705671079 -82.1475233555 56.8561850734 +4.39181751371 -85.2238016559 52.1307545528 +4.39319413199 -80.596998663 59.0323949356 +4.3998552745 61.3811462877 78.822561199 +4.42156596434 -85.2222634303 52.1307545528 +4.43278889191 -71.8579774707 69.4030363635 +4.44266907069 74.1230421358 66.9778867692 +4.4507646996 -84.3621953871 53.5089775931 +4.46517118626 53.1743054702 84.5727821704 +4.46921868475 -85.8511505589 51.0843031866 +4.47014544001 -85.8689530008 51.0542917912 +4.47130444944 87.6592596773 47.9151503112 +4.47560873024 66.8541586992 74.2326773808 +4.47572789951 91.5129081224 40.0668879095 +4.47984330248 61.4443052271 78.7688286008 +4.48640629729 92.3922289606 37.9940546168 +4.51905518993 -71.8283253682 69.4281629815 +4.53916837853 -70.1928559745 71.0799473873 +4.54104573698 -82.5144643134 56.3093427655 +4.54451534729 -81.284612028 58.0702955711 +4.55406829645 -74.0342423221 67.0685576537 +4.57216148505 -77.4146744238 63.1352795449 +4.57236302819 -57.2037878311 81.8951778441 +4.61785623453 -86.101113544 50.6485305836 +4.62099065847 -88.1737543869 46.9471562786 +4.62396121772 90.3421429162 42.6252999515 +4.63047518584 -69.349074319 71.8975979477 +4.63086326479 -74.0177487636 67.0815024682 +4.63309373985 55.1740418268 83.2728019878 +4.63510874227 -82.1333670675 56.8561850734 +4.64193345942 -23.8806774205 96.9956993876 +4.65446798886 -71.0134586874 70.2525772694 +4.66381809427 -72.7115917273 68.4928699156 +4.67808089998 -80.6428431613 58.9478363128 +4.68324551643 -71.452518913 69.8040453872 +4.69718445827 91.7727657418 39.4423113706 +4.70118040948 -83.5634027959 54.7271104292 +4.70501699235 -96.894257545 24.2768546132 +4.70644527753 73.3761738964 67.7774776543 +4.71630301379 -83.5721162484 54.7125019684 +4.71724968022 -71.0216032076 70.240155419 +4.72370475094 -83.1870804067 55.2955356864 +4.72851006092 91.7573652143 39.4743856384 +4.74547489769 -83.5704648566 54.7125019684 +4.74555124293 27.968317376 95.8918816509 +4.76239306367 -82.0962538094 56.8992506345 +4.76881416126 -97.5054922887 21.6780392341 +4.7700265122 -72.776541051 68.4165325029 +4.77017093009 63.7388096615 76.9064991547 +4.78788589534 -97.2000377204 23.0049737188 +4.79221997543 -74.5098676698 66.5230354654 +4.81057871846 -68.4511022385 72.7413564262 +4.81316307957 90.3322603792 42.6252999515 +4.83343832237 -96.4125287942 26.1009993198 +4.83357574855 -73.7461150347 67.3657707057 +4.83893068264 -80.4991537059 59.1309648364 +4.84934867874 -96.3934613182 26.1683861269 +4.88038363679 63.7170025816 76.9176536145 +4.88584314138 -97.4578470096 21.8654200292 +4.88677250544 -68.5093189433 72.6814465487 +4.88721476232 54.9768995981 83.3885822067 +4.8979117054 -81.718469222 57.4291062871 +4.90876957217 -85.9163132221 50.9341840379 +4.90949723055 -80.7320358906 58.8067616682 +4.92160633182 -81.6366340829 57.5433555394 +4.9285066905 -67.5980495205 73.5269577966 +4.93394060372 52.1956395504 85.1543976671 +4.9372693567 -81.8964428819 57.1716364519 +4.93846999773 -81.9163583904 57.1429938149 +4.93851955805 60.717164653 79.3034484816 +4.94958474571 -69.3899050146 71.83691734 +4.95503715596 71.3975384558 69.8415285431 +4.95574736843 -76.6347560323 64.0511884034 +4.98225635507 92.8954472264 36.6825981389 +4.98881785402 -79.7391426677 60.13967761 +4.99119034863 -76.7667191571 63.8902093341 +4.99225533708 65.1775700179 75.6766922719 +4.99233850094 -70.5094738179 70.7353564932 +4.99400992507 -86.0889684774 50.6334807353 +4.99451589213 -73.2622023259 67.8800745533 +4.99904803327 -57.1393804843 81.9152044289 +5.00313744256 -76.7435875365 63.9170586601 +5.00796845819 -76.4068336197 64.3188621489 +5.00807729469 -84.7954899504 52.7697266042 +5.01006155279 -86.1057348783 50.6033764121 +5.01279281303e-15 -81.8651192576 57.4291062871 +5.01309648627 -34.8747081887 93.5875183578 +5.01545631578 -93.5144690065 35.0697773643 +5.02505917139 -43.2320468973 90.0318771402 +5.03535721528 74.4356181311 66.5881666001 +5.03657018647 -81.184464009 58.1697151818 +5.06024572553 88.2969311625 46.669538893 +5.06581845503 -72.4445790425 68.7467850211 +5.07986929259 -93.1946566172 35.9019624251 +5.09428328921 -75.6990910051 65.1436558597 +5.10232800095 49.2062156583 86.9063552887 +5.11071751877 68.2891778799 72.8729630997 +5.12900944593 -93.1982392167 35.8856721967 +5.13550818295 -68.3000716323 72.8610099486 +5.14257359443 -97.4751144235 21.7291510406 +5.15674306117 -13.704765267 98.9221280098 +5.18382019128 39.3750235375 91.7754625684 +5.19674775864 -72.854967009 68.3018857343 +5.20001436161 -85.75634594 51.1743000114 +5.20500633285 58.9014338667 80.6444604267 +5.20666454913 -74.4587720277 66.5490940013 +5.20859380322 -5.46574067934 -99.7145738065 +5.20883124364 -80.5483980302 59.0323949356 +5.20931379091 -75.8278538734 64.984610692 +5.22201609858 -85.8711129256 50.9792360946 +5.22672544109 92.6167179854 37.3473545352 +5.22711830629 -58.8005177362 80.7166423246 +5.23117450479 -86.0217142487 50.723756673 +5.25015353812 -18.9314420616 98.051192697 +5.25568028689 -96.1114013605 27.1104473079 +5.2739277819 22.8803262736 -97.2043021443 +5.2811189888 -97.5130680504 21.5246682117 +5.30005277742 -93.0499657421 36.2438038284 +5.30744296463 -84.3593902076 53.435234939 +5.31059613509 -86.0877219142 50.6033764121 +5.32014298181 92.2680620111 38.1877049766 +5.33077608291 -85.9267682214 50.8740929096 +5.33176540987 -97.5027812376 21.5587552642 +5.33251303034 -81.3584269323 57.8996603779 +5.33307284866 93.3427309157 35.4780625061 +5.33666001449 60.3912669479 79.526190254 +5.34688372612 -84.2820574941 53.5532036295 +5.35579257084 89.619818303 44.0409315668 +5.39463461767 -69.6328731748 71.5692733704 +5.39495844312 -85.275397081 51.951911188 +5.40694235285 40.7946767088 91.1403276635 +5.40744017245 -82.5015942123 56.2516359159 +5.4229946031 61.3682553964 78.7688286008 +5.42487842591 88.695978239 45.8649554484 +5.43155027554 93.6314840119 34.6935651573 +5.44169698364 -65.9069174375 75.011106963 +5.44568099916 -85.8393828209 51.0092630351 +5.46540399973 -74.9619861398 65.9608216527 +5.47870155213 -68.8453475487 72.3208265315 +5.48744590328 -70.8308628327 70.3766780108 +5.4892301522 -80.3123638534 59.3278397097 +5.49875281578 -85.4951038877 51.5785898285 +5.49975251119 -11.8373810816 99.1444861374 +5.50327073084 56.1266967304 82.580311972 +5.50352625946e-15 -89.8794046299 43.8371146789 +5.50610581778 -35.773743927 93.219751363 +5.50873580379 -74.6579081827 66.3012109666 +5.51130219831 -97.6593714719 20.7911690818 +5.51312315037 -70.8411879779 70.3642775775 +5.52629366525 -85.9233114951 50.8590662521 +5.5307605249 -73.0452029476 68.0720868959 +5.53147156969 29.8451498535 95.2820541996 +5.5348028413 -77.5942757148 62.8370458711 +5.53513009621 -77.219046755 63.2975604037 +5.54558726968 -78.7132986936 61.4285200099 +5.55914823722 -85.9656348951 50.7839097349 +5.56499212011 56.7561801534 82.1447921484 +5.57842156831 62.7523727505 77.6596479968 +5.58072261382 -78.6247523944 61.5386370179 +5.5870462554 43.7956515494 89.7258369674 +5.60189926569 -81.5424096113 57.6147043678 +5.60480011888 -81.7934124908 57.2575225515 +5.61717048487 -81.349397478 57.885429304 +5.620235388 66.6505756103 74.3378350842 +5.62769756573 -74.845980801 66.0788027892 +5.63829559594 -79.6326722686 60.2233105213 +5.64472930403 -76.8665870503 63.715499106 +5.66116232357 -24.8574476626 -96.6957007154 +5.66959551683 -82.7390013789 55.875874378 +5.67044235869 -72.0498015542 69.1134732122 +5.69740425731 -73.0443097726 68.0593005737 +5.69814264495 91.3324694832 40.3225890599 +5.70402199208 -74.1303815341 66.8741404933 +5.7168228343 -71.3650363546 69.8165418993 +5.72382894627 -73.0541577364 68.0465121782 +5.72960254001 -75.8471586267 64.9182577014 +5.73368162241 91.6447283263 39.6026345721 +5.74510586851 -73.8220630455 67.2108381607 +5.80021631754 -70.0999184742 71.0799473873 +5.80729026948 55.2526761153 83.1469612303 +5.80868188979 53.2965450819 84.4140835231 +5.82263049386 -70.073158909 71.1044961634 +5.82532067041 88.4043685937 46.37599867 +5.82543469969 -95.7937607802 28.1001727065 +5.84006269707 -76.246319478 64.4390598453 +5.85194095113 90.4933269929 42.1510682766 +5.85282948221 -78.3890773623 61.8134041883 +5.8725028822 58.0151319482 81.2388957023 +5.88073048459 -97.5460063937 21.2177672156 +5.89576276343 -84.7383970556 52.7697266042 +5.89941373088 -83.7354625459 54.3467499475 +5.90748141571 87.7829025029 47.5317124823 +5.90985921678 -81.4500329049 57.7145190037 +5.91898207869 -70.4872776419 70.6859911282 +5.93165550632 -78.3398554907 61.8682673481 +5.93787505246 -74.28739638 66.679264985 +5.93911746139 -16.3175911167 98.4807753012 +5.95552233434 -80.7130447807 58.7361571432 +5.96718203501 -78.4453302495 61.7310529686 +5.9839702358 -97.0034912274 23.5481377163 +5.98553950793 67.3320941624 73.6923497556 +6.00006406789 -83.0950937207 55.3100771174 +6.0052724446 -68.2290988665 72.8610099486 +6.0215293579 -10.2552448525 -99.2903375823 +6.02908852667 -68.2269984743 72.8610099486 +6.0532825168 -11.5641099669 99.1444861374 +6.055341606 -11.5239504821 99.1490363207 +6.06135431275 -11.5598811607 99.1444861374 +6.0633718003 -11.5588230788 99.1444861374 +6.06740097527 43.4468720987 89.8640971147 +6.09130319398 -66.6742926408 74.2794367659 +6.10157711173 78.4025604625 61.772237046 +6.108871359 -97.0977297611 23.1238527491 +6.12285074106 -76.0998772203 64.5857521893 +6.12323399574e-15 0.0 -100.0 +6.12664346555 -85.8914898875 50.8440380454 +6.13816807267 61.7144833264 78.445174743 +6.14075308164 91.9679999875 38.7837353782 +6.14852754543 -73.6835252576 67.3270652459 +6.15271888119 -82.2123532713 56.597464784 +6.18025143261 -85.1765945824 52.0264569962 +6.18877198337 -84.0741406756 53.7888275667 +6.19800069836 -29.0844106812 95.4760799503 +6.2030767912 -29.083328483 95.4760799503 +6.20817335571 -86.1866126787 50.3321604797 +6.21402507038 -69.9023572749 71.239359485 +6.22046919232 -77.652224482 62.7011785857 +6.22088732819 -84.1094041683 53.7299608347 +6.24005489384 65.0434206673 75.6995055652 +6.26109334289 71.1356163514 70.0037341608 +6.2696703292 -89.6604629176 43.8371146789 +6.28042111734 69.6838877444 71.4472679633 +6.28814878133 47.2532986676 87.9066831927 +6.31524700153 -75.2062707499 65.6059028991 +6.32890314619 -85.1656782829 52.0264569962 +6.34461905047 -69.7156266956 71.4106238843 +6.34569806038 56.5731727421 82.2144041031 +6.35728632781 50.535888378 86.0564285593 +6.35941864712 -80.4450573262 59.060566762 +6.37823385934 -85.2256742777 51.9220817836 +6.38807932415 -67.5788203797 73.4322509436 +6.40976339844 -69.3583716126 71.7518725918 +6.41681997451 89.5192548354 44.1035988909 +6.41937572456 -74.1187070612 66.8222184522 +6.42603897393 59.3456268301 80.2296865209 +6.42614772918 -89.6493837234 43.8371146789 +6.44371135847 64.3304374733 76.2894055451 +6.44447498008 -68.558550883 72.5134045749 +6.44781065795 -85.1567584525 52.0264569962 +6.45625852956 -74.8484783325 66.0001667961 +6.46394787009 52.1181474871 85.0994481795 +6.48582888256 -19.5198677 97.8616819224 +6.49407301369 -97.2595541461 22.3250116011 +6.50688563159 32.0683016934 94.4948912158 +6.50898295492 -86.1644170313 50.3321604797 +6.51429949739 27.7303140797 -95.8571519664 +6.51577401438 -73.7344793946 67.2366807435 +6.51608847521 -70.5088874317 70.6118784917 +6.51635893152 -69.3232771885 71.7761820252 +6.51722247651 -70.5211581628 70.5995188551 +6.53000967697 -97.5416595963 21.0471759821 +6.5308921254 -70.8039322545 70.3146544139 +6.553874703 -70.3815037361 70.7353564932 +6.56314657566 -64.2782006416 76.3232469783 +6.56548723087 -80.2003723 59.3699811383 +6.5701615047 -97.6300738351 20.6204185397 +6.57254514961 -95.6713327675 28.3513268955 +6.57608599124 -68.5460520379 72.5134045749 +6.60075540143 58.6621997539 80.7166423246 +6.60980532629 -83.9855397421 53.8770785007 +6.62785464209 -71.175968018 69.9289147602 +6.64904742606 -73.3443711476 67.6490457382 +6.64925024542 -72.0870984974 68.9872285383 +6.64934787566 93.4492756595 34.9716892865 +6.66389885733 -68.8294669106 72.236396206 +6.66949048119 -86.2840074859 50.105767621 +6.67570829602 -69.5844684602 71.5082978952 +6.71090919502 -83.9586496914 53.9064823539 +6.72403350781 59.1998029457 80.3129547743 +6.72633058901 59.3123416968 80.2296865209 +6.72729043174 57.9650499608 81.2083526892 +6.73172708923 92.1088579008 38.3489523534 +6.73578982549 -70.5995719433 70.5005643726 +6.73642965053 -69.5786163106 71.5082978952 +6.74497725938 -97.6826032842 20.3129096238 +6.74555471235 -72.4399390749 68.6072351756 +6.75196372439 -85.0328270073 52.1903182306 +6.75551639497 -68.5286010012 72.5134045749 +6.75675789382 -68.5411948838 72.5013849983 +6.76076024802 -22.1134503602 97.2897087776 +6.77690087508 -85.1585164128 51.9817342621 +6.78842167222 -95.8765196053 27.5972882649 +6.79475050208 -35.0539428964 93.4079892355 +6.8008555304 -68.4986757744 72.5374371012 +6.82215159976 93.5707650687 34.6117057077 +6.82282811731 -68.5982050507 72.4412539946 +6.82298930324 -95.6537980439 28.3513268955 +6.82495681331 -95.9172662549 27.4462747688 +6.82858206721 -97.1658498037 22.6311311886 +6.85197365746 -81.5979780252 57.4005264714 +6.85808596975 93.8378008625 33.8737920245 +6.85887121025 -96.3938958263 25.7132793155 +6.87095305702 27.5578875163 95.8819734868 +6.90835499817 -73.0827621028 67.9057031084 +6.91129977509 -81.4519702948 57.6004381105 +6.92189220923 -71.6245305816 69.4407231184 +6.92610840322 -76.549162118 63.9707339446 +6.94290719978 -80.654684847 58.7079028057 +6.95157079798 -82.2674408001 56.424674103 +6.97619272902 56.8165303335 81.9952109325 +6.98773808899 -78.2960700103 61.8134041883 +7.01306091202 -86.5969283022 49.5155428655 +7.01375840205 -86.6055408744 49.5003786139 +7.02825370148 -74.0751649044 66.8092328522 +7.03358688482 49.7316329248 86.471344052 +7.04507983743 56.9665453515 81.8851608095 +7.05227654681 -72.9736872416 68.0081345566 +7.0573532276 57.0657880362 81.8149717425 +7.07534560572 56.8042680499 81.9952109325 +7.10903941452 55.4947342539 82.8842326905 +7.12763719021 -97.7607218585 19.7999507521 +7.13099250001 -73.6539408576 67.2625151337 +7.14697043738 88.2504364796 46.4842045725 +7.16092153984 -73.2961650662 67.6490457382 +7.1711430306 63.4324193325 76.9733907611 +7.18294776433 -79.6977967451 59.9722140278 +7.18424890071 56.4728104995 82.2144041031 +7.20085252385 89.4981792178 44.0252613806 +7.20344666977 -84.5446994516 52.9179000974 +7.20578290065 -83.537838957 54.4931753083 +7.21395497334 -77.3238629443 62.9998339126 +7.21521517086 -85.5654987897 51.2492545011 +7.22397890002 -78.9203234743 60.9868565477 +7.2376636538 -85.8317161642 50.7989441341 +7.25038483719 -12.5226776498 98.9475338965 +7.26158234653 92.6807539391 36.844908347 +7.28700758179 65.7943169035 74.9533680611 +7.28854867508 -74.7372886241 66.0394938452 +7.32580849619 89.4880376936 44.0252613806 +7.33777202854 56.8863462092 81.9152044289 +7.34767012769 32.0045978576 -94.454843495 +7.34949029748 -81.8652877706 56.9566471151 +7.35862466316 91.4591024769 39.7628371371 +7.37535995617 91.0705789297 40.641773078 +7.38264614241 -76.953258721 63.432582386 +7.38542766854 -78.4218325296 61.6073992379 +7.4128016017 -78.4192497513 61.6073992379 +7.42230631106 -83.9930744291 53.7593974759 +7.4303211005 -82.4425069272 56.107248907 +7.43122471814 -97.2429917992 22.1037880265 +7.45064212534 72.7189581691 68.2381202461 +7.4777745278 -72.1147260605 68.8734286451 +7.47967845692 -72.7518850539 68.1998360062 +7.48314270197 -79.4594152304 60.2511734868 +7.48319869763 35.2965474566 -93.2639023143 +7.4925332049 91.5246548158 39.5866076726 +7.50801201716 37.5739296582 92.36790333 +7.52306456931 -86.5107065558 49.5913414893 +7.52648540893 -76.761036237 63.6482154754 +7.54592556978 -77.2369035274 63.0675807431 +7.55874743355 65.1292191221 75.5052988457 +7.55884086479 -69.8072562352 71.2026045991 +7.55979451336 -69.0279909466 71.9582238024 +7.57469946445 74.18515591 66.6272209433 +7.59855652854 -86.5041085035 49.5913414893 +7.60241797514 -85.0158389727 52.1009631841 +7.61167459848 35.7181421506 -93.0928393117 +7.61422715285 -84.1544305682 53.4794854183 +7.61697200528 -83.2136836043 54.9314536351 +7.61725592234 -85.0145108056 52.1009631841 +7.63431981515 -20.289271697 97.6220395964 +7.63874221592 53.8072378701 83.9430209734 +7.65490356489 -84.1132296636 53.5384632481 +7.6579403846 60.3646363527 79.3565789779 +7.65939581934 -87.5472948226 47.715876026 +7.67898139975 51.3812642969 85.4458830133 +7.67911384656 59.1259014799 80.2817475191 +7.68041597938 -74.0689749771 66.744274333 +7.69699303697 -20.2838031774 97.618254578 +7.70317595907 89.8536595636 43.2085748802 +7.71614517207 -73.1685210147 67.7261296414 +7.72615783516 69.0979782133 71.8733322724 +7.74638301253 -76.6609426185 63.7423989749 +7.75431077507 -71.9645026642 68.9998624687 +7.75486243383 -72.2062438983 68.7467850211 +7.76496248951 23.1801335197 -96.9659051809 +7.77579725483 -66.6944420357 74.1039025868 +7.78479554222 88.6243059103 45.6632167098 +7.79002890745 -86.772406308 49.0903753615 +7.79773930373 29.9359822465 95.0948591076 +7.79832447812 56.7817412397 81.9452255907 +7.8000953392 -82.5163895319 55.9482258102 +7.80875224128 -98.1247576379 17.6225800308 +7.83122200314 -97.974626941 18.4294448562 +7.8482071841 61.5204047738 78.445174743 +7.86268714114 -76.3462808671 64.1047856925 +7.89274700428 -97.459248538 20.9618562904 +7.89834232028 -75.4008813331 65.209840383 +7.90285631916 -83.1388351521 55.0043539327 +7.90376464941 -83.1483908767 54.9897772225 +7.9046727389 -83.1579440685 54.9751988372 +7.90915540032 -70.1799684258 70.7970147154 +7.91025740429 -75.0091946445 65.6585755753 +7.91258265915 89.0096473289 44.8851168881 +7.92461547672 -82.6024941844 55.8034803938 +7.9318767653 -83.1360714698 55.0043539327 +7.93365234833 -70.1772033342 70.7970147154 +7.93761334457 -82.7379778943 55.6005513314 +7.96059306938 -76.3811116841 64.0511884034 +7.96207328946 -91.0069141369 40.6736643076 +7.96590566448 -72.7361653967 68.161533069 +7.98340401291 93.122378373 35.5596387288 +7.99393513022 90.461799909 41.8659737537 +7.99940599959 88.7567408749 45.3679452137 +8.00651678216 34.680034279 93.4515431196 +8.01319574985 -86.379627326 49.7428253812 +8.0236558351 -85.358422298 51.4738835705 +8.0244964882 -85.367365456 51.4589192581 +8.03069438301 -82.1987921273 56.3814377303 +8.05041064885 59.5421212934 79.9370169588 +8.0761711972 -74.3424192526 66.3926212652 +8.0806136314 -70.1604332279 70.7970147154 +8.08805161549 -73.6140190606 67.1979137981 +8.089590539 50.7887696131 85.7616429769 +8.09216516469 -87.2308917699 48.2212441148 +8.09425199331 -82.8493409527 55.4118199338 +8.103704948 34.7411854677 93.4204474321 +8.11420264447 90.5608234028 41.628079226 +8.13141864729 -80.4713912697 58.8067616682 +8.15784903732 57.6808334672 81.2795850728 +8.16773661192 47.6330420851 87.5464527 +8.16900154656 -92.4429046926 37.2501917543 +8.17100249279 -79.4761215411 60.13967761 +8.19571237569 -71.1597852737 69.7790459842 +8.20492452998 -70.9130906494 70.0286569056 +8.20771604232 -94.7670501129 -30.8518980011 +8.2155045171 39.91669711 91.3190165155 +8.2288586183 -73.3619273488 67.4560116039 +8.22943757212 39.9138269262 91.3190165155 +8.24228144448 -79.3525328781 60.2929541689 +8.24559439564 -82.610202424 55.7455346062 +8.24656059472 -82.6198824905 55.7310439129 +8.25058830274 63.7874895319 76.5707775321 +8.2538160801 -76.349982215 64.0511884034 +8.25408897858 -74.171114093 66.5621202286 +8.25730721705 21.0161604181 97.417338697 +8.26138872599 60.703536394 79.0368909154 +8.26147446457 92.2044916568 37.8163953596 +8.27075211116 89.6664285564 43.4916802325 +8.27327886834 34.1976360629 -93.6059535739 +8.27843577791 56.0614573499 82.3928425343 +8.2784720151 -72.0997597076 68.797467622 +8.28121088965 -72.1236134087 68.7721305114 +8.30273215468 34.2409264827 -93.5875183578 +8.31242298396 -84.3220095574 53.1102845816 +8.31627089661 -76.8022589422 63.5000209429 +8.31850488191 -74.9880732142 65.6322432357 +8.32991191912 -70.5901656607 70.3394702811 +8.34364151922 -73.5736833381 67.2108381607 +8.35337812669 68.0328053076 72.8131751529 +8.35770094241 -73.0146797336 67.8159669868 +8.36593363759 -21.7940022352 97.2369920398 +8.37809162792 -83.4952686239 54.3906949587 +8.37939727649 89.8158318089 43.1613491188 +8.38318736398 -73.0117578974 67.8159669868 +8.38399632638 66.6467861701 74.0804596287 +8.407056524 63.6861409409 76.6380900901 +8.41863070712 -47.7444272753 87.4619707139 +8.42420936669 94.0207399534 33.0020174407 +8.4254828421 -73.0426229109 67.7774776543 +8.43056082458 -21.7690841158 97.2369920398 +8.44249394382 -21.7098371608 97.2492018808 +8.46333529522 -85.8528784 50.5732659231 +8.493303087 -85.8499189082 50.5732659231 +8.49519566274 -74.3306822373 66.3534575496 +8.50393935886 -80.6387971987 58.5240754026 +8.51218780609 -73.907602991 66.8222184522 +8.51321628086 62.1479944743 77.879085327 +8.51691858688 -74.1764642609 66.5230354654 +8.52152519123 -85.8293766965 50.6033764121 +8.52461615076 -64.489939967 75.9498424128 +8.53559652153 -24.4696333735 -96.5835422553 +8.55060972696 -64.5132381134 75.9271307335 +8.55853153076 -69.4032035109 71.4838924546 +8.56840202994 77.2407984212 62.932039105 +8.57813727508 -81.6155243735 57.1429938149 +8.5843149356 -74.1920661143 66.4969688239 +8.60041076876 -73.544110358 67.2108381607 +8.60140711114 -21.647367721 97.2492018808 +8.62464263201 13.8291530094 98.6629113016 +8.62707054929 -86.1278837108 50.0755559253 +8.64169104469 52.0873793674 84.9248260906 +8.64234822591 -80.4697064813 58.7361571432 +8.64330027059 -84.7972836599 52.2944934419 +8.66296853479 68.0964965425 72.7173991201 +8.71102164409 -82.4644595841 55.8903480703 +8.72384268635 78.3923135428 61.4698279336 +8.7274165499 -84.7427581948 52.3688565266 +8.74820607007 -73.1474777846 67.623334614 +8.74960749025 -73.1591956557 67.6104759618 +8.75448854461 65.3508069516 75.1839807479 +8.75637174376 -81.2642098004 57.6147043678 +8.76202976492 84.0708183701 53.435234939 +8.76560596859 -79.7808317165 59.6505074801 +8.79771709693 70.6322924773 70.240155419 +8.81587325752 -69.7848225485 71.0799473873 +8.82386366571 -73.6710317284 67.0426618959 +8.82400260377 -71.6589337905 69.189118986 +8.84957916895 -73.6679471307 67.0426618959 +8.84980666108 -73.997003609 66.679264985 +8.8750314411 -98.0891694204 17.3132509753 +8.88197579458 -82.160625748 56.3093427655 +8.89215109551 -98.0876189412 17.3132509753 +8.91165628108 42.4724991003 90.0925590851 +8.91580720844 62.8028732622 77.3065811677 +8.92597126115 -68.4455607289 72.3569779188 +8.92690232288 -97.7122429958 19.3035743749 +8.93957491815 -73.6570803535 67.0426618959 +8.94001769331 -92.3388342434 37.3311635797 +8.95984089764 58.3484781543 80.7166423246 +8.96035194492 -98.0783764516 17.3304404339 +8.97216668817 41.4278975118 90.571681737 +8.97392138521 -73.2982376047 67.4302387584 +8.97992079699 56.5054867025 82.0151875874 +8.99107620269 68.9447942689 71.8733322724 +8.99652148007 57.1243954354 81.5834912675 +9.00242460314 -69.0318153458 71.7883334625 +9.01267867235 -71.3426978207 69.4909425092 +9.04795859237 -73.3720860041 67.3399691173 +9.05658428948 -73.4420338696 67.2625151337 +9.06333951306 43.88090352 89.3997884961 +9.10676664268 -82.2249028465 56.179463803 +9.11454168893 -34.74256647 93.3267336023 +9.14268316332 -82.4177185874 55.8903480703 +9.14904066613 89.6039521343 43.4445257404 +9.15837020327 -75.349875134 65.1039213298 +9.16104724878 74.0762667857 66.5490940013 +9.17267351821 44.1766675941 89.2428378124 +9.17660061332 -76.165698991 64.1449631569 +9.18104807571 -73.7098574309 66.9519624339 +9.18455392561 -73.0106476337 67.7132874795 +9.19259986653 -85.312659858 51.3541252058 +9.19558881334 32.3456349102 94.1764357397 +9.19625922982 90.2222274023 42.13524058 +9.2054857105 69.7344972897 71.0799473873 +9.21040477953 87.6311478434 47.2858369012 +9.2162338536 -78.6911038379 61.0145163901 +9.21873916052 -75.957237041 64.3856582585 +9.22979779727 -72.2499379259 68.5182990326 +9.23120834677 -78.7000694373 61.000687398 +9.23674288398 -6.08357305915 99.3864815744 +9.23848161337 -34.7940724269 93.2953534825 +9.24957605463 -85.1437945248 51.6234403806 +9.25005259176 -74.2638587822 66.327338299 +9.25072459498 -71.5198088443 69.2772764861 +9.2785249334 -80.1919478102 59.0183063249 +9.30724925574 -83.6347958244 54.0240320478 +9.31585328322 -64.5677144801 75.790666473 +9.32920792858 -74.1605437012 66.4317667789 +9.34606075843 61.4352952885 78.3476588107 +9.35302494944 93.2113618807 34.9880399656 +9.35461135437 -89.0031817531 44.619781311 +9.36138906325 -81.1562285609 57.6717518425 +9.38758109029 -83.6921709162 53.9211818177 +9.3932187433 -85.0827109959 51.6981598438 +9.39809355928 -73.3635972676 67.301251351 +9.41026483768 -83.4996982308 54.2148255651 +9.42250809921 91.6490234308 38.8802372073 +9.43447331858 90.8303555567 40.7533706906 +9.44359264801 -92.1703401109 37.6224263139 +9.44811585372 47.6292077743 87.4196297957 +9.4534270181 -76.2220106798 64.0377842023 +9.4541969534 -44.2128230139 89.1955404777 +9.45524811452 39.4445943207 91.4041698281 +9.46549374929 -70.9405759692 69.8415285431 +9.46842244184 -76.0170366747 64.2787609687 +9.46955679286 -62.7626938399 77.2733573497 +9.470356857 -74.2360864753 66.327338299 +9.47721010166 69.0061683349 71.7518725918 +9.49773732007 -76.0359868077 64.2520170576 +9.50211758425 61.5219837919 78.2608156852 +9.5035604128 59.6660780275 79.6846376179 +9.51929092667 -92.1162741738 37.7355950342 +9.52048473479 -72.6090213599 68.0976533192 +9.54469309018 64.4807792153 75.8361915289 +9.56833624189 92.2758428157 37.3311635797 +9.58108468102 47.6026379807 87.4196297957 +9.59252190629 59.0301637642 80.1462618557 +9.63120798554 57.5538294664 81.2083526892 +9.64068544001 36.232359487 92.7053035713 +9.64517682482 63.2529979201 76.8506917219 +9.64731466778 -72.4962874113 68.1998360062 +9.6493734414 -82.3893858934 55.8469218875 +9.67669604253 -85.9986837388 50.105767621 +9.68135522737 -45.2751351925 88.6365246062 +9.68186499919 -73.7399609901 66.8481835454 +9.69034291907 92.1974542184 37.4930218808 +9.69170549691 -85.996993527 50.105767621 +9.69330821721 -91.7634528272 38.5422949633 +9.70104987938 -86.2151210335 49.727683803 +9.70825278925 94.4283494359 31.4489530921 +9.71735666819 -73.1202264525 67.5204077514 +9.71899080535 55.2884023223 82.7570769564 +9.73011840714 -73.1185293402 67.5204077514 +9.74380631987 -98.1402746947 16.5391874421 +9.74721367171 -83.6036429363 53.9946544894 +9.76453736466 -73.8701212249 66.6922709185 +9.76908005634 70.1322157836 70.6118784917 +9.77382980092 -72.4793392612 68.1998360062 +9.77597474765 92.546030467 36.6014011008 +9.78762724426 26.9644769188 95.7972825159 +9.79912926715 -72.4759231354 68.1998360062 +9.83580519042 -76.252439723 63.9439001981 +9.85159972567 -75.0327111069 65.3684805299 +9.86974469626 -83.1404054772 54.6832800472 +9.87476708172 -74.0079369226 66.5230354654 +9.90320301781 52.7644862034 84.3672659607 +9.91033744605 30.1779615803 94.8212837214 +9.91653022503 30.6108097182 94.6817868267 +9.91694207454 67.3199976197 73.2780470562 +9.91765898232 -65.4229998974 74.976470474 +9.91851143651 -97.9861161862 17.3304404339 +9.92401428497 -75.5842419099 64.7189023035 +9.92907729876 -65.4212679429 74.976470474 +9.94546646937 -91.9981958269 37.9133177301 +9.96315532615 -82.6940957276 55.3391549243 +9.96983495228 64.5502456588 75.7223096347 +10.0119499217 -47.7164424465 87.3092319232 +10.0357109544 -75.921588202 64.3054970475 +10.0391401354 -97.982938823 17.2788704766 +10.053417328 -85.3236181744 51.1743000114 +10.0861062443 13.345903496 98.5908582005 +10.0870972752 64.0491255228 76.1312024621 +10.0904638381 -94.889033008 29.9040792256 +10.1108539665 79.1467578711 60.2790291109 +10.1121387594 -69.5711869823 71.1167673026 +10.116313374 88.1060855263 46.2058210288 +10.1244603695 -80.368961016 58.6372356736 +10.1252619192 -97.9801342573 17.2444878725 +10.1271257118 -42.2800274094 90.0546534449 +10.1307867328 -42.2953119107 90.0470640862 +10.1477178031 89.7617420548 42.8935133403 +10.1523926381 -85.140522388 51.4589192581 +10.1646393627 -61.7338998037 78.0102924084 +10.1656589288 -77.7400202556 62.0737354217 +10.1707486458 88.1727696775 46.0664580728 +10.1760545303 -91.8794922444 38.1393080575 +10.1806450182 21.8523755361 -97.0506473469 +10.1839170241 32.3583262263 94.0703277228 +10.1939924849 -81.6099931995 56.8848971802 +10.1947425534 -61.7151348938 78.0212108937 +10.1951156336 -74.2334355845 66.2227805105 +10.2139645221 -74.3706795165 66.0657018202 +10.2162845779 -61.7115724975 78.0212108937 +10.2264215739 -77.6773837285 62.1421303053 +10.2543916469 45.5764984094 88.417363932 +10.2570395293 55.9962936101 82.2144041031 +10.2645215189 -19.5759301978 97.5265223151 +10.2868059592 -54.1821677368 83.4174701276 +10.2944902874 60.6714703608 78.822561199 +10.2972644135 -68.7364659765 71.8975979477 +10.299545654 -83.6416865713 53.832960413 +10.3100905149 88.7007100723 45.0098441037 +10.3306477625 -78.6812833137 60.8484459368 +10.3496704649 -82.1567008772 56.0638994563 +10.3581304816 -91.6229495642 38.7032846937 +10.3616977943 59.9878320437 79.3353340291 +10.3696571924 48.2468629703 86.9753437661 +10.373192281 -69.6581275972 70.9939584863 +10.3754422872 35.1847012715 93.0289578238 +10.3855555364 -79.2065787386 60.153621011 +10.3886447317 -82.4660824356 55.6005513314 +10.3993431287 -71.4595214809 69.1765166238 +10.4211269059 -95.9281033805 26.2526016964 +10.4221303871 -73.0469074125 67.49465546 +10.4242865732 -71.4558870719 69.1765166238 +10.4297646065 -73.2833458083 67.2366807435 +10.4343106356 65.1435779683 75.1494471773 +10.4387123181 50.098325988 85.9138581274 +10.4431922673 -81.7482689908 56.6406236925 +10.4437652068 -86.302625298 49.4245347472 +10.4582728199 -85.1757968832 51.3391483659 +10.4605442269 47.7760403968 87.2240046001 +10.4629760808 -71.9849363844 68.6199319824 +10.4740181182 -76.7610900312 63.2299770811 +10.4875754077 -74.6229765169 65.7375245794 +10.5474248929 73.8329163671 66.614204858 +10.5650897222 -80.7945943058 57.9707892832 +10.5853218525 -84.6227694303 52.2200905326 +10.589527059 92.9430861593 35.3474843779 +10.6001021083 -86.7062012844 48.6792819803 +10.6045124941 61.521608425 78.1193702712 +10.6047746296 -74.2343696466 66.1573663187 +10.6064040622 89.2128364831 43.915532554 +10.6193655638 -74.2439468098 66.144277433 +10.6323102057 21.3905205981 97.1050956862 +10.6342660892 -79.7001172218 59.454215154 +10.663791031 -80.7816263189 57.9707892832 +10.681029673 -74.8614876816 65.4344960034 +10.6935141832 -77.0640036228 62.8234677493 +10.6965344207 27.8363781091 95.4500927457 +10.6979581327 92.1779257095 37.2663883908 +10.726454682 -77.1036881061 62.7691361291 +10.7447314349 -74.8408325159 65.44769312 +10.7581810873 58.3299845664 80.5100890583 +10.7716052602 -51.2035054812 85.2183873736 +10.7724135355 -70.234062588 70.3642775775 +10.7750702317 -91.7238012453 38.3489523534 +10.7820201238 -84.990570732 51.5785898285 +10.7833312416 45.7236242894 88.278366258 +10.7857699448 -74.1148695184 66.2620048216 +10.7945493522 11.7472115556 98.7192013995 +10.8012046837 -51.1668644899 85.236646788 +10.8015601502 -75.8957174601 64.2118865129 +10.8057005023 91.2969025707 39.3460597474 +10.8149785289 -74.1339830802 66.2358572986 +10.8280779613 62.8841764734 76.9956692089 +10.8454153965 -74.0710901043 66.3012109666 +10.8517707564 -82.6503108973 55.2373531229 +10.8526941437 71.1718875214 69.4030363635 +10.8952340878 -81.4391231563 56.9996762596 +10.8953262905 -71.8722968856 68.6706983029 +10.8971241255 -74.063500526 66.3012109666 +10.916972724 68.3862043591 72.1397723859 +10.9246140278 -81.3346855051 57.1429938149 +10.9424193318 93.1483762383 34.6935651573 +10.9455534736 39.388293156 91.2620250784 +10.9534771096 -91.4513177275 38.9445480794 +10.969646442 -79.769719326 59.2997363872 +10.9811811132 -67.7998598004 72.6814465487 +10.9863907145 68.7439771743 71.7883334625 +10.9866707979 89.7382060819 42.7357863387 +10.9873053807 -70.1634648372 70.4014724456 +10.991678773 57.7847609014 80.8709119852 +10.9926910421 -48.6991484305 86.6461406284 +11.0165506836 -86.9608475511 48.129477498 +11.0199359732 67.664944406 72.801210908 +11.0234662859 -87.628688254 46.9009188174 +11.0517538694 6.02060820512 -99.2048940993 +11.0539199238 -87.5007861177 47.1319772882 +11.0782536084 -87.4479091362 47.2243103147 +11.0841240187 -73.988923941 66.3534575496 +11.1023736303 -81.2602503981 57.2145873446 +11.1050765118 -81.2800332696 57.1859551582 +11.1078822159 66.0240882287 74.2794367659 +11.1147717224 94.6155422127 30.4033060925 +11.1198782243 -79.4237683176 59.7345238075 +11.1256149428 -84.5074354587 52.2944934419 +11.1271586512 -87.4666135025 47.1781502685 +11.1304865458 -98.1478998871 15.5917291214 +11.1441149855 -87.3563157386 47.3780835594 +11.1531101146 -87.915732228 46.329603512 +11.1575412559 36.26815467 92.5209718386 +11.1645636259 93.3516727043 34.0707751944 +11.1762813293 -74.6040939115 65.6454104053 +11.17862368 -85.7192056269 50.2718227172 +11.1837978143 -87.9118337021 46.329603512 +11.1888958056 -87.9519071873 46.2522500293 +11.1893020298 -74.6021421462 65.6454104053 +11.1894575878 54.2703033644 83.2437998389 +11.194128253 -73.8433790524 66.4969688239 +11.2003271712 -96.3596751829 24.2768546132 +11.2041088838 -90.208677834 41.6756810089 +11.2076415992 89.5978113959 42.9723278732 +11.21972475 -87.2212766813 47.6084726767 +11.2291063313 94.5913478276 30.4365583986 +11.2338789245 -98.1415915079 15.5572484907 +11.2353611864 -83.8701103077 53.2876276071 +11.246247492 -72.229362884 68.2381202461 +11.2480796215 -72.2411297905 68.2253609109 +11.2580501002 -87.640090465 46.8238278148 +11.2582930237 72.058510382 68.4165325029 +11.260141401 -74.7187977676 65.5004616457 +11.2612483659 30.7229526472 -94.4948912158 +11.2828265297 -90.1988660569 41.6756810089 +11.2895719887 -81.8843800608 56.2804927695 +11.2952483485 88.5410176007 45.0877540689 +11.3000679615 -77.6488898619 61.991599167 +11.3043629206 -87.2772906829 47.4856389871 +11.3067558003 -84.7401931757 51.8773258161 +11.3071534731 -87.4186066901 47.2243103147 +11.3494343902 -76.5807363895 63.2975604037 +11.3495829561 -75.2232037749 64.9049811691 +11.3502120402 -87.7515039088 46.5923410914 +11.3525658093 56.6596292798 81.613759008 +11.3673281846 47.2393510775 87.4026747859 +11.3676157766 -87.7656453071 46.5614520325 +11.3803577488 -78.9742116577 60.2790291109 +11.4224565267 -86.4125167224 49.0143289315 +11.4356545061 -90.1429223846 41.754991917 +11.4387357536 -80.6755409913 57.9707892832 +11.4424919667 -74.3430640548 65.8952062334 +11.4490086217 -29.7171183362 -94.7935286788 +11.4531808923 -77.5607891802 62.0737354217 +11.4567868356 -87.8521985084 46.37599867 +11.4642788531 -87.6709789786 46.7158405181 +11.4674718145 55.7170406373 82.2442002381 +11.4705386798 -68.7664056701 71.691060765 +11.4725971931 -68.778746552 71.6788918467 +11.4758716854 89.3357574113 43.4445257404 +11.4807683797 -88.0360922478 46.0199784784 +11.4821358212 -87.5697685909 46.9009188174 +11.4823813735 -81.1872498233 57.2432125595 +11.5194267914 87.4987334268 47.0241901057 +11.5233409345 -76.4653080483 63.4055934345 +11.5368868355 -73.6730186127 66.6272209433 +11.5407818402 -87.6609411266 46.7158405181 +11.5408340195 -81.6005447155 56.6406236925 +11.5452708948 60.1232625503 79.0689573744 +11.5484806072 79.161957063 60.0001429133 +11.5501770112 -87.1445830844 47.6698547309 +11.5510074279 -45.2174754701 88.4418121677 +11.5662141816 -82.6117244222 55.1500288078 +11.5667495103 -71.0225054371 69.4407231184 +11.5855071644 -65.7046761524 74.4894056592 +11.5925987516 -65.6109611637 74.5708617985 +11.6049226014 -86.6288250592 48.5877807712 +11.609768319 -87.5941917501 46.8238278148 +11.6150446317 -78.3729515068 61.0145163901 +11.6338179415 -91.4492809303 38.7515586452 +11.6503833121 37.9172526121 91.796244602 +11.6530014314 -59.0141142301 79.884553446 +11.655630937 -87.5881008827 46.8238278148 +11.6577862492 -87.6042973206 46.7929814261 +11.6661468722 -82.6947523462 55.0043539327 +11.6667216856 -92.0930729649 37.1853938664 +11.6677494147 72.4393454155 67.9441304262 +11.6858575826 -86.0909504378 49.5155428655 +11.6909449176 -92.1552797658 37.0233199244 +11.6987140503 -88.2652757223 45.5234136597 +11.6997578202 -88.273150831 45.5078730475 +11.7009167706 61.8070867054 77.7365588364 +11.7088233123 -87.7535490164 46.4996568983 +11.710985157 -86.8446129679 48.1753674102 +11.714491542 -34.4702438657 93.1373876365 +11.7186510295 -79.8406079123 59.060566762 +11.7397308633 52.0086386176 84.6007105668 +11.7505822672 -34.4579575807 93.1373876365 +11.7517342792 -87.4926664962 46.977974103 +11.778731453 91.9473832846 37.5092014374 +11.7981448273 50.0266503281 85.7795898543 +11.8102615799 -29.7534297988 -94.7378020466 +11.8172809102 -80.22022482 58.5240754026 +11.8201787121 -86.5139936629 48.7402531354 +11.8226399078 -69.6777525385 70.7476924486 +11.8298245607 75.1147627039 64.944804833 +11.8377081563 -6.81248364943 99.0629029058 +11.8520569512 59.0455406967 79.8320290977 +11.860216881 -66.2479712062 73.9631094979 +11.8829019219 86.4107841672 48.9078012338 +11.8964135666 -73.4506756263 66.8092328522 +11.9164827648 -97.7571508507 17.3648177667 +11.9233574206 -22.9338669878 -96.601611233 +11.9297471628 -80.7880896469 57.7145190037 +11.9668288731 -83.7688710126 53.2876276071 +11.9683744749 -85.9209481764 49.7428253812 +11.9698706406 -91.2895317021 39.0249099737 +11.9943583789 93.8906428258 32.2596118519 +11.9946519656 -91.3548338166 38.8641565272 +12.0025843572 -91.415249268 38.7193771905 +12.0035889325 -79.5578498161 59.3840246647 +12.0222379273 -81.7104600077 56.3814377303 +12.0271084514 -79.0588653631 60.0420225326 +12.0287754458 -87.471555826 46.9471562786 +12.0332412272 -72.2953236099 68.03372171 +12.041978142 -71.3479012724 69.0251240234 +12.0455111816 -82.3676870623 55.4118199338 +12.0509362096 -73.5906812432 66.6272209433 +12.0654991249 -55.6640223256 82.1945274906 +12.0849287987 -55.6598072807 82.1945274906 +12.0885315241 -86.8945417592 47.9917286421 +12.0919221412 -92.2203708626 36.7313029567 +12.1009981257 -64.9746513701 75.0457228874 +12.115665598 -70.2884960666 70.09092643 +12.1319763956 -71.5765968293 68.7721305114 +12.1338764937 -83.4806770799 53.7005176466 +12.1350581201 -85.0525213193 51.1743000114 +12.1391521995 29.4956165177 94.776841001 +12.1470703728 64.4715687459 75.4709580223 +12.1499868643 -61.0821087918 78.2390810577 +12.1526230129 67.0045083669 73.2305237754 +12.163909425 -80.2406542192 58.4249665637 +12.169617571 -78.6109470469 60.5988400266 +12.1716038182 -69.2405767517 71.1167673026 +12.1760680282 -91.2553852802 39.0409787882 +12.1851336776 -74.1666537209 65.9608216527 +12.1880286005 -72.8327869838 67.4302387584 +12.1901997389 -60.0239851031 79.0475821431 +12.2005702777 -78.0895396995 61.2631200187 +12.2051247419 -85.5436061403 50.3321604797 +12.2088247826 -91.2578818458 39.0249099737 +12.2352683847 -31.0928623577 94.252491309 +12.2370317859 -31.1451925301 94.234983076 +12.2378894178 57.9226216717 80.5928282249 +12.2383968481 -91.1159109319 39.3460597474 +12.2455996141 -89.6277250304 42.6252999515 +12.2600082681 -87.4559884746 46.9163327338 +12.28468778 39.4415915697 91.0683660806 +12.2858799387 50.8614157055 85.2183873736 +12.2999267419 -83.2949408497 53.9505758171 +12.3043828188 88.4461197408 45.0098441037 +12.3090688275 69.1027179057 71.2271100259 +12.3461019534 39.6387697794 90.9744013277 +12.3556643317 59.8209648534 79.175688964 +12.3567035445 -70.2216758691 70.1158192968 +12.3580586444 -83.9929023817 52.8438334722 +12.3690494224 70.6530160632 69.6789633789 +12.3761491083 94.6443402344 29.8207946716 +12.3840047306 -91.2342744169 39.0249099737 +12.3904105621 -72.2590572886 68.0081345566 +12.3908371894 -91.4043003562 38.622804535 +12.4022317661 -45.0874859272 88.3928914562 +12.4050512669 -86.6204802611 48.4046186062 +12.4144976084 -75.398184247 64.5057676599 +12.4321901003 88.12480185 45.6010959102 +12.4381512273 -85.2604274871 50.7538362961 +12.4400444898 -88.2918800848 45.2745977805 +12.4407079462 -85.2779531577 50.723756673 +12.4483426945 44.9787130168 88.4418121677 +12.4487124543 -83.9981565663 52.814195551 +12.4692653645 -69.7903807156 70.5253158862 +12.4767179459 53.6155011293 83.4847863263 +12.481323888 -79.7040675028 59.088731392 +12.4820560606 88.8144437665 44.2288690219 +12.4962694742 -86.7181025566 48.2059533482 +12.5173028963 -85.4896042977 50.3472410885 +12.5281360506 -80.4623307199 58.0418740413 +12.5326718441 -70.5005488208 69.8040453872 +12.534296662 -82.6839570401 54.829322952 +12.5378599989 -88.6501100133 44.5416665749 +12.5407974349 72.3775081115 67.8544377272 +12.5530517506 -18.6668331607 97.4370064785 +12.5545023077 -74.3845720867 65.6454104053 +12.565466814 -81.1679775941 57.0426897773 +12.571624713 -80.7416379623 57.643231617 +12.5971570388 89.0693752719 43.6801788368 +12.6022270252 -91.1699726362 39.1052421488 +12.6055972435 -21.7895994475 -96.7797100329 +12.6094352885 -67.9021368699 72.3208265315 +12.6125213872 -66.3057525402 73.7866619677 +12.6168288171 -97.8124271724 16.5391874421 +12.6220957915 -84.9635436124 51.2042864871 +12.6254704896 -91.3381259324 38.7032846937 +12.6297449116 -87.4281677509 46.8700866991 +12.6300156023 -74.6731361674 65.3024152754 +12.6326457486 -57.9385450023 80.5204400411 +12.6395616652 -88.4780606466 44.8539214018 +12.6415489668 -21.8078163366 -96.7709170482 +12.6449870342 -67.8955252775 72.3208265315 +12.6473019391 -88.5322432557 44.7446941857 +12.6516425944 -88.6731724592 44.4635179185 +12.6586453412 -73.1335275331 67.0167579691 +12.661406791 -87.3242025682 47.0549936128 +12.6637629277 -87.3404525601 47.0241901057 +12.6689426353 -67.8268303343 72.3810678237 +12.6713945274 -65.3713981179 74.6057375062 +12.6806716801 -84.5455121926 51.8773258161 +12.6810982987 -70.3376976628 69.9413899879 +12.6828040256 -77.0277158891 62.4970196645 +12.6966041002 -73.6587849951 66.4317667789 +12.7128849706 -86.4045184645 48.7097705254 +12.7135430098 -70.5176573338 69.7540380788 +12.7280935588 -85.3694991937 50.4979627488 +12.7291277642 -72.5606913008 67.623334614 +12.7377014284 -71.6539100831 68.5818352927 +12.7436094498 61.8081390785 77.5716079622 +12.7468659375 -80.9376170543 57.3290463408 +12.7523706065 -71.8091576625 68.4165325029 +12.7543277917 74.0708925927 65.9608216527 +12.7579146126 -85.0605119862 51.0092630351 +12.7625518632 -80.1269610779 58.4532922799 +12.7633132346 -81.5979859723 56.3814377303 +12.7647391903 -69.2093797201 71.043107985 +12.7773609314 -91.2623442324 38.8319916157 +12.778204913 -73.0652178089 67.0685576537 +12.7795983182 -79.0785137208 59.8604254456 +12.7797508415 87.2820488184 47.1011881219 +12.786441081 29.7612476655 94.6085358828 +12.7911497666 -74.0528588151 65.9739387103 +12.7955218145 86.8608984118 47.8691857941 +12.8050090631 -81.9582397236 55.8469218875 +12.8062804563 -88.869429734 44.0252613806 +12.8070977952 -86.4163751644 48.6640354832 +12.8073851195 -88.5486459934 44.6666338461 +12.8269469944 56.8251571154 81.2795850728 +12.8270108684 -84.6148806109 51.7280366086 +12.8331868961 85.1570386425 50.8290082898 +12.8413464009 -97.8035102476 16.4186846569 +12.8420917071 -97.8091867206 16.3842507806 +12.8444874045 -84.6304874858 51.6981598438 +12.8495090944 -88.8398858451 44.0722679139 +12.8529726732 -85.2883309085 50.6033764121 +12.8557986725 -53.6307199094 83.4174701276 +12.8559775525 -90.1053208024 41.4216731225 +12.8678580993 -85.2860863426 50.6033764121 +12.8768107262 90.1388252654 41.3422293217 +12.8783841855 -80.672896689 57.6717518425 +12.8861181744 37.1081273257 91.961594401 +12.8877449801 -71.6270751686 68.5818352927 +12.9002683681 -85.2990495252 50.5732659231 +12.907071727 -65.3650829577 74.5708617985 +12.9087356188 -75.3608120389 64.4524053357 +12.9102661685 -69.5221189799 70.7106781187 +12.9108971633 -74.9019966867 64.984610692 +12.9116185229 -78.674344199 60.3625519008 +12.9118842908 -82.2656841882 55.3682259884 +12.916675214 -74.9355177911 64.944804833 +12.9191163268 -71.6579019312 68.5437198009 +12.9232069495 -84.1588000266 52.4431797303 +12.9323787559 94.7777136525 29.153706017 +12.935337522 -91.1164120087 39.1213050121 +12.9434062086 -70.1780977898 70.0535711176 +12.9494722031 87.6936541026 46.2831956524 +12.9555071089 -83.6874846199 53.1842058656 +12.9618270958 45.4426373808 88.1303452065 +12.9637079435 -67.3195808564 72.801210908 +12.9735140649 -90.0299505798 41.5487175664 +12.9880111715 89.3570959855 42.9723278732 +12.9920225169 91.2867082594 38.7032846937 +13.00217531 -81.9074483774 55.875874378 +13.0180470059 -71.1395277069 69.0630005849 +13.0312808905 -70.7930794194 69.4156007298 +13.0383565858 -86.4161227889 48.6030346756 +13.044218128 -83.7768833892 53.0215256573 +13.0495292047 -98.0627721166 14.6083028562 +13.0520750681 -90.0185947735 41.5487175664 +13.0574695262 -71.1445563804 69.0503771677 +13.0586909187 -85.6387979732 49.9546481641 +13.0705481188 -81.1486359791 56.9566471151 +13.1037322589 93.5934525572 32.6888029655 +13.1119713159 -83.1614442158 53.9652703519 +13.1231284691 -87.0810007833 47.3780835594 +13.1253870515 -89.9712578255 41.628079226 +13.1319603045 58.8454921041 79.7794439539 +13.1341918144 -76.5966804729 62.932039105 +13.1354846033 -69.5175879259 70.673644403 +13.1448766958 -76.2594185563 63.3380872628 +13.144969056 -85.4042353163 50.3321604797 +13.1479564968 -80.4658969258 57.8996603779 +13.1588939937 -89.9810432461 41.596338363 +13.1615775967 -85.7111227363 49.8033765367 +13.164818517 -77.8350808655 61.3871952452 +13.188829847 -71.0221916312 69.1513055782 +13.1898184695 44.8151586414 88.417363932 +13.1929209339 60.865368088 78.2390810577 +13.1946066079 -70.9842811502 69.189118986 +13.1971768036 -73.8644953469 66.1049986881 +13.199583559 55.4060524173 82.1945274906 +13.2012253569 -71.0198886644 69.1513055782 +13.2033840688 -79.3255039081 59.4401806766 +13.2141123363 -74.5604145078 65.3156323064 +13.2412906204 -86.8362854598 47.7925491081 +13.2527009221 -78.5213513787 60.4877119416 +13.2562140352 -78.5421663346 60.4599114862 +13.2594305618 -81.8661967095 55.875874378 +13.2650200754 -82.3560171748 55.1500288078 +13.2672214624 -81.9142991828 55.8034803938 +13.2674237063 56.2127898755 81.6339250717 +13.2715232605 -86.932732614 47.6084726767 +13.2778787526 -77.924438904 61.2493245459 +13.2832112858 71.530438133 68.6072351756 +13.2897597667 -71.1505535091 68.9998624687 +13.2984128328 -70.8542397021 69.3024453563 +13.3057308221 -71.098543869 69.0503771677 +13.3059343254 -97.7701564919 16.2464953535 +13.3092993768 -88.3163730496 44.9786705168 +13.3134927426 -87.7206964721 46.1284112175 +13.314595185 -71.1459101731 68.9998624687 +13.3254743797 -75.0363301213 64.7455086819 +13.3290782784 -70.0062301428 70.1531425771 +13.3474049592 -80.8001666766 57.3862339406 +13.3528189192 -87.5676872143 46.4069217127 +13.363469155 -86.6227353203 48.1447756021 +13.3789020314 -71.1460981294 68.9872285383 +13.3875378701 65.334775044 74.5126901925 +13.3905733947 -88.5410404321 44.5104111795 +13.4081746103 -83.7100311312 53.0363228518 +13.4130869952 92.2816038779 36.1136356933 +13.4138710944 -71.676386304 68.4292606175 +13.4211946299 44.2298541116 88.6768940591 +13.4617421335 -86.161648417 48.9382451749 +13.4710628558 -83.821594649 52.8438334722 +13.4760175528 -75.8071898163 63.8096146601 +13.4826920524 -83.7074359421 53.0215256573 +13.4883227886 -88.977302203 43.6016609893 +13.4938257674 -78.6940129447 60.2093762865 +13.4973871947 -83.7986708881 52.8734649546 +13.4994211732 -75.1771864435 64.5457687724 +13.536423947 92.2253179281 36.211268409 +13.53822371 -81.512882255 56.3237651908 +13.5398867957 47.3126794896 87.052753116 +13.543721903 -84.2737042755 52.1009631841 +13.5477768161 -71.9059326691 68.161533069 +13.5528077368 -86.2509326411 48.7554922136 +13.5721363587 -91.0306385298 39.1052421488 +13.5812513634 -91.2009066036 38.7032846937 +13.6034978922 -83.253824234 53.7005176466 +13.6071371161 -89.9730013085 41.4693242656 +13.6072764902 -35.3007650786 -92.5672620929 +13.6233355557 -71.5517115519 68.5182990326 +13.6245740433 68.3084164779 71.7518725918 +13.6299101066 -72.4809046111 67.5332808121 +13.6485709353 -63.1271407343 76.3457963096 +13.6543514091 31.8579887266 93.8009980858 +13.6608191003 46.118152389 87.6726755708 +13.660830105 -91.955611301 36.844908347 +13.6667105202 -82.8230148794 54.3467499475 +13.6690034958 -79.9669640877 58.4674524674 +13.6702940669 -83.4795102785 53.3319268711 +13.6703321056 -72.0037133099 68.03372171 +13.6717980957 -83.4886948349 53.3171620737 +13.679440506 10.2149227213 98.5318641925 +13.6858491939 -83.3919626909 53.464736887 +13.6889891008 -71.6243524839 68.4292606175 +13.697000731 -71.5984969718 68.4547105929 +13.7058275828 -79.596737622 58.9619339082 +13.714066298 -72.4410318764 67.5590207616 +13.7151101486 -91.0092071721 39.1052421488 +13.7164484829 -81.7908656484 55.875874378 +13.7173292607 86.1213274233 48.9382451749 +13.7185142103 -76.6279186555 62.7691361291 +13.7206078263 59.7635070996 78.9941019319 +13.7357735608 -81.9061006417 55.7020574338 +13.7414777414 -83.7309240291 52.9179000974 +13.743403918 -83.2877922975 53.6121488374 +13.7507817638 57.408532926 80.7166423246 +13.7507865908 -86.3313821374 48.5572685227 +13.7608625663 89.9276395685 41.5169640396 +13.7728844231 -75.413137351 64.2118865129 +13.7933119823 -86.3074278628 48.5877807712 +13.8031436844 -80.0783252657 58.2832312683 +13.80328877 -72.8427619455 67.1073859667 +13.8060747892 -71.492312697 68.5437198009 +13.8119668048 74.7410860651 64.984610692 +13.8291522157 59.5685131406 79.1223532967 +13.8358037747 55.3688567455 82.1149209134 +13.8385223294 30.864115971 -94.1058002733 +13.8392149309 52.7519496909 83.8194961444 +13.8461561247 94.9119502305 28.284371374 +13.850583333 -78.3107673162 60.6266035968 +13.8685542159 -81.7355257586 55.9192903471 +13.8798588824 11.8880761368 -98.3159354488 +13.8837647288 69.7983987206 70.2525772694 +13.8916931613 -96.7605274779 21.0812993745 +13.8979485628 92.771811053 34.6444526541 +13.9077682639 -79.036192102 59.6645147464 +13.9088360749 40.3255896132 90.4455145454 +13.9233391749 -77.6158211008 61.4973571877 +13.9403277006 78.4985961124 60.3625519008 +13.9408794331 -80.2912711225 57.9565670322 +13.9776946564 -64.7040699523 74.9533680611 +13.9936255606 -4.19296506163 98.9272332963 +13.9946957209 -71.6625285186 68.3273773681 +13.9958190737 -4.185637442 98.9272332963 +14.0041736547 -17.4301349181 -97.4683205815 +14.0092785788 -91.231540208 38.4778661699 +14.0156526485 94.6850983526 28.9533008618 +14.0189464571 -83.327149115 53.4794854183 +14.0196954198 69.9710319633 70.0535711176 +14.0219806863 -89.7474456148 41.8184177516 +14.0321033786 -89.8122357322 41.6756810089 +14.0335391875 -74.9875534759 64.6523518642 +14.0436138415 -89.4762898367 42.3883293765 +14.0462307031 -88.1862650121 45.0098441037 +14.0479685394 -86.734777218 47.7465496226 +14.0533075998 -89.7425455526 41.8184177516 +14.0553493926 -96.5819215136 21.7802568899 +14.062121229 88.0880735344 45.196770322 +14.0848823401 -93.3523265577 32.9690645263 +14.0968582053 53.543618087 83.2728019878 +14.1036191551 -79.5794423036 58.8914279787 +14.1083245186 -80.6707836419 57.3862339406 +14.1087360485 98.2723075039 11.9790293837 +14.1188796672 49.1412600128 85.9406411501 +14.129749858 87.2397103286 46.7929814261 +14.130481693 -89.7230363662 41.8342710268 +14.1327332139 -71.9022811341 68.0465121782 +14.1345804052 -87.7546916622 45.818421274 +14.1364880849 92.1671810741 36.1299105657 +14.1370731738 -91.1095658647 38.7193771905 +14.1494853511 -65.3335419797 74.3728469045 +14.149927009 -82.6068502122 54.5516989988 +14.1517401122 -82.1006919646 55.3100771174 +14.1523524182 69.1286267132 70.8586190225 +14.153960041 88.1690384938 45.0098441037 +14.155599531 -86.6327031931 47.8998302645 +14.1577282602 -81.2876471607 56.4967003425 +14.1650767282 -57.6698620309 80.4582973635 +14.1788278443 -79.1991064065 59.3840246647 +14.1829539385 52.0224727036 84.2170181815 +14.1858391862 -86.6277566789 47.8998302645 +14.1901951857 68.7029968344 71.2638518925 +14.1946113391 36.7479970917 91.9135339255 +14.196324979 -93.3179699595 33.0184923902 +14.1975996258 -59.595285378 79.0368909154 +14.2129751333 -35.4094486815 -92.4346378904 +14.2386871216 -73.9404538541 65.8032603517 +14.2418901255 -68.5906071702 71.3617346599 +14.2501678197 -79.9999854377 58.2832312683 +14.2703051134 85.5511338969 49.7731039913 +14.2703329398 -75.7409583479 63.715499106 +14.2731866417 86.0309496768 48.9382451749 +14.2835500216 42.271800092 89.4934361602 +14.287315962 63.7609399224 75.6995055652 +14.2921376246 -71.7859458654 68.1359873953 +14.3047809712 98.0557092788 13.4332095642 +14.3093137065 -71.8067712731 68.1104334195 +14.3287980029 -87.0244923266 47.1319772882 +14.3301342347 -87.0326077938 47.1165834227 +14.3313319088 46.1544314813 87.5464527 +14.3320930284 88.7835381954 43.7272735822 +14.3435630124 -80.9333216266 56.9566471151 +14.3510291284 -74.5238376239 65.1171681568 +14.3618520993 -87.0357126804 47.1011881219 +14.3878030424 86.4414547454 48.1753674102 +14.3899303353 -86.922522797 47.301214948 +14.3945191026 -86.7622752805 47.5931235364 +14.400677193 -89.6059753606 41.9927336103 +14.4028514272 -86.7187570293 47.6698547309 +14.4118647195 46.129348304 87.5464527 +14.4189999525 -91.0379827901 38.7837353782 +14.4331211057 -86.7137242026 47.6698547309 +14.4430064307 -84.6730217401 51.2042864871 +14.4448974 -70.1834675034 69.7540380788 +14.4454335341 -33.736239882 93.0225540858 +14.4492528789 -91.5391747358 37.5739082333 +14.4521680937 93.6797411708 31.8628456287 +14.4641064124 -84.0004498878 52.2944934419 +14.4693951712 -70.1784210073 69.7540380788 +14.473141762 -87.1419711755 46.8700866991 +14.4769728301 -34.3219178283 -92.803142265 +14.4867101808 -96.5868656744 21.4735327167 +14.4894314492 -81.1790639074 56.5686835572 +14.4900654883 -73.8564810085 65.8426777644 +14.4904188625 -82.4316149621 54.7271104292 +14.4934494124 89.7830984585 41.5804660306 +14.4945830298 -33.7858201704 92.9969107993 +14.5009743257 -70.0225564477 69.9039579147 +14.5074691277 -27.2845811336 95.1056516295 +14.5112161932 -34.2194886858 -92.8356138488 +14.5141541094 -88.1502337224 44.9318998616 +14.5293538972 83.0782112472 53.7299608347 +14.5323412571 90.5260825941 39.9229185776 +14.5365494386 -82.6940378723 54.3174449951 +14.5381551428 48.674169435 86.1363295878 +14.5451087467 -91.1136085365 38.5583992277 +14.5644885156 73.087285456 66.679264985 +14.5665915036 -15.0736137374 -97.7783236759 +14.5694466462 -80.7310210332 57.1859551582 +14.5871492505 -70.6248825798 69.2772764861 +14.6054082155 -82.6626446529 54.3467499475 +14.610762476 64.9387516757 74.6289766155 +14.6126813772 -82.8726342303 54.0240320478 +14.632191155 -96.1830879939 23.1238527491 +14.6483308532 85.248264089 50.1812701416 +14.6531105506 -23.2867675968 96.1405887546 +14.6555168278 -76.3202088611 62.932039105 +14.6577641133 -81.8743151722 55.5134800412 +14.6602641253 -82.7203025188 54.2441536663 +14.6719190047 -80.9753420193 56.8131039249 +14.6750220618 8.95767172393 98.5109326155 +14.6966153671 -73.0845685339 66.6532470249 +14.7042165456 -91.2912836533 38.0747625693 +14.7418697931 -87.344575631 46.4069217127 +14.747162599 70.8997182241 68.9619543736 +14.7492710515 -81.4022533488 56.179463803 +14.7496305337 0.961571268116 -98.9015863362 +14.7589950371 37.8158560752 91.3900054426 +14.7595035653 -70.4654212933 69.4030363635 +14.7623731015 -45.245748401 87.948249511 +14.7700895189 -74.7999350373 64.7055961569 +14.7739426082 94.8860909055 27.8991106039 +14.7754327825 -79.4888021994 58.8491028904 +14.7775434199 52.5727850576 83.771871662 +14.7831056128 53.7796974178 83.0012285095 +14.7891287708 -89.5278200771 42.0244107924 +14.7895298759 -82.860407268 53.9946544894 +14.8139504324 70.9103811363 68.936671806 +14.81561588 71.2288200636 68.6072351756 +14.8179486396 -82.7690627126 54.1268016402 +14.8230965165 -87.4537477265 46.1748613235 +14.8282547594 -69.0500222171 70.7970147154 +14.8396001217 -89.4449798314 42.1827198174 +14.867828612 -60.1681656268 78.4776370533 +14.8696004838 55.8840669069 81.5834912675 +14.8701118402 -78.9243338802 59.5804439009 +14.8997391017 -78.1071676819 60.640482612 +14.9040325504 69.9378758728 69.9039579147 +14.9223853101 -80.5139862226 57.4005264714 +14.9237038232 72.3818761945 67.3657707057 +14.9268467312 -72.525116204 67.2108381607 +14.9376727674 88.3168245954 44.4635179185 +14.9404935546 -82.6220117254 54.3174449951 +14.9469215428 36.5351427796 91.8791210149 +14.9492620308 -87.4567850043 46.1284112175 +14.9502063055 -73.4826116384 66.1573663187 +14.9583020605 -86.599332414 47.715876026 +14.980016676 88.2860260575 44.5104111795 +14.9836453763 91.4996687039 37.4606593416 +14.9841937406 32.1044441472 93.5135209686 +14.9869128601 -88.8909766208 43.287258152 +14.9962409754 57.7781114035 80.2296865209 +15.0012534492 -75.5542183501 63.7692910769 +15.0054883277 -68.248874863 71.5326946227 +15.0061970158 -88.910696443 43.2400521409 +15.0134731269 -71.5534468299 68.2253609109 +15.0210588342 -82.6555478146 54.2441536663 +15.0229716761 -88.9155160062 43.2243141689 +15.0259367033 -80.2903827049 57.6860093202 +15.0420900126 97.7300280897 14.9190193254 +15.0518307493 -88.8032407871 43.4445257404 +15.0858761077 -89.0041026102 43.0196008887 +15.1026658263 89.0088694506 43.0038445267 +15.1108265758 -87.6647895026 45.6787434334 +15.1149145795 -77.0413634422 61.9368038909 +15.126659348 -89.434180354 42.1035813367 +15.1270590706 74.0211720125 65.51364879 +15.1305454883 -82.6836667205 54.1708210283 +15.132304527 5.76938839195 98.679924591 +15.1382378712 -73.8786605478 65.6717387452 +15.1431073366 -89.3417571244 42.2934597085 +15.1491615127 72.514946075 67.1720589323 +15.1510840538 -80.7253132231 57.0426897773 +15.1598070672 37.2780961369 91.5452008468 +15.1600083203 87.493927788 45.9889850721 +15.1639745462 -98.52192462 -7.96770011589 +15.1849686815 -88.6493925055 43.7115766651 +15.1874809776 72.8890067824 66.7572701047 +15.1896149292 -26.4903905497 -95.2236042525 +15.197826035 -88.7244533505 43.5545343388 +15.2029560159 -88.7544020256 43.4916802325 +15.2106370933 -88.7992439254 43.3973593378 +15.2240789655 55.2706701063 81.9352210326 +15.2251193048 75.3046576807 64.0109699485 +15.2519523214 -88.5758732783 43.8371146789 +15.2619182609 -67.8328678375 71.8733322724 +15.2713427147 -88.7811372644 43.4130827946 +15.2760815918 -78.4424285557 60.1117853128 +15.2842743782 -87.7557952755 45.4456967411 +15.2938667983 -67.8642390766 71.83691734 +15.2962242251 -80.0338248138 57.9707892832 +15.3030520391 -88.4112120593 44.1505852792 +15.3172019417 -81.2973011329 56.179463803 +15.3266262553 -69.883945026 69.8665066769 +15.3273441035 94.6338805101 28.4517342588 +15.3314291911 98.2409685253 10.6611154275 +15.3480895725 56.4903543039 81.0757424702 +15.353341095 -79.5045571799 58.6796413149 +15.3623495342 -88.0222939178 44.9007125805 +15.3664392056 -88.501657472 43.9468903432 +15.3749591535 -98.4071609658 -8.92419753652 +15.379206329 -79.8630861237 58.1839108989 +15.3821510842 88.5921486573 43.7586634199 +15.3890108271 -88.3571473669 44.2288690219 +15.3900671131 68.1247748142 71.5692733704 +15.4038922825 -88.2603231325 44.4166124676 +15.4094002272 -79.1270175629 59.1731820696 +15.4105714216 45.4501958908 87.7313739887 +15.4107809014 -88.7570395759 43.4130827946 +15.4269518092 -87.9392766476 45.0410122064 +15.4365630488 -88.7217736991 43.4759633927 +15.4398748281 -74.6876166208 64.678977951 +15.441371569 -88.2930884763 44.3384096623 +15.4419479908 98.0503348184 12.1522872021 +15.4461206623 -91.3229490599 37.7032668542 +15.4461643007 91.033307468 38.3973038094 +15.451878093 -72.5707995637 67.0426618959 +15.4780097538 -88.0497211648 44.8071179262 +15.4859309591 -82.1140751873 54.9314536351 +15.4991152979 72.2969135603 67.3270652459 +15.5011397606 -70.0947893031 69.6163427557 +15.5011719845 87.0230827257 46.7621293358 +15.5077176864 -88.8552158737 43.1770923546 +15.5080541069 89.5026267467 41.8184177516 +15.5231274932 94.0732751633 30.1537959944 +15.5432980941 86.3860188631 47.9151503112 +15.5456724161 -50.7841943666 84.7307362866 +15.5555994002 -80.2509367969 57.6004381105 +15.557736618 53.0314725481 83.3403848725 +15.5633971071 69.2292349515 70.4634209964 +15.5734810998 -97.7747810395 14.055563991 +15.5841024822 98.0618109544 11.8750571435 +15.5869325952 -71.308722956 68.3528606764 +15.5904033155 84.6956388531 50.8290082898 +15.6074532416 -80.8204319176 56.7843745053 +15.611061377 61.2446336992 77.4944488704 +15.6165507809 -73.97785349 65.44769312 +15.6223630612 66.9742316676 72.5974797422 +15.625378171 94.5901592457 28.435001862 +15.6406978517 -71.1379734628 68.5182990326 +15.6415056795 85.6447335176 49.1967775447 +15.6635347018 -71.9601298731 67.6490457382 +15.666366438 -98.6905705919 -3.83878090875 +15.6692151839 70.9723070495 68.6833846544 +15.679553111 -81.5761088827 55.6730641675 +15.6888330224 -58.9629691308 -79.2289643355 +15.6927236619 44.7362797251 88.0477353509 +15.6968913839 -42.8474216739 88.9814927768 +15.7033572825 -80.2631098533 57.5433555394 +15.7045009351 -82.1700347831 54.7855275974 +15.7055825317 22.997647327 -96.0439633437 +15.7103245482 -73.911265899 65.5004616457 +15.745308575 97.4299480463 16.108708253 +15.7497784577 -77.0683220669 61.7447828754 +15.7674993793 -79.4860600403 58.5948139565 +15.7760958507 70.9854557956 68.6453193248 +15.7829241701 -3.85329935407 98.671431472 +15.7853666451 36.4778300433 91.7615939008 +15.8023946624 -80.3969201437 57.3290463408 +15.8383009654 -91.4086016101 37.3311635797 +15.8398549685 91.7029794065 36.6014011008 +15.852494551 -76.0805945731 62.932039105 +15.8529705703 60.0860023881 78.3476588107 +15.8650571278 89.2463513365 42.2301874901 +15.878877906 -90.7947306101 38.7837353782 +15.9094806337 -78.6895635436 59.6224874966 +15.9115668038 -74.0316838811 65.3156323064 +15.9206006302 -73.9480593429 65.4080957909 +15.9212659783 97.9757927284 12.1349630774 +15.9214612837 85.6542008162 49.0903753615 +15.9229739276 94.8468363533 27.3959218692 +15.9237043126 -52.0840899468 83.8670567945 +15.9248203486 -75.8968811852 63.1352795449 +15.9254050951 -73.9703751376 65.3816876087 +15.9262542792 -79.5585761956 58.4532922799 +15.934210871 -79.9608044734 57.8996603779 +15.9438005656 -77.8791401683 60.6682351002 +15.9696212907 84.7600701482 50.6033764121 +15.9779138535 -81.6664253244 55.4553986878 +15.9790629165 85.9640858035 48.5267503577 +15.9834563648 72.395634339 67.1073859667 +15.9977450922 -81.6921193481 55.4118199338 +16.0036671586 72.3671739553 67.1332612883 +16.0058636456 70.2797226299 69.315026625 +16.0118775895 -78.9123630395 59.2997363872 +16.0171512502 70.1032080223 69.4909425092 +16.039602706 90.5031980855 39.3941909591 +16.0438414815 -70.3330783516 69.2520991747 +16.0648377944 54.1645468571 82.5113498278 +16.0775535745 -91.3668238304 37.3311635797 +16.0828810303 -91.0247396025 38.1554415263 +16.0893806804 77.5563373151 61.0421687982 +16.0924174571 -75.5791363836 63.4730513202 +16.0968252232 34.1301530955 92.6068294858 +16.1223924452 -90.9703378458 38.2683432365 +16.1459235818 -81.6925253777 -55.3682259884 +16.1478857204 97.8594356938 12.7583945876 +16.1571585894 -91.4451304185 37.1043710237 +16.1581607776 -98.6720067699 -1.65798681877 +16.163956181 35.749274835 91.9821497322 +16.1644572409 94.3676173882 28.8697611798 +16.1645686039 -81.0429801967 56.3093427655 +16.1663583866 -77.0480391491 61.6623752364 +16.174017287 -41.1654469155 89.6872741533 +16.1788050051 -98.4747365259 -6.4009792035 +16.1858331416 86.4882345103 47.5163560978 +16.1926028204 -98.6663604964 -1.65798681877 +16.210324801 -79.6051728519 58.3115925445 +16.214696507 -97.627774181 14.3492621991 +16.2432595083 -13.0599159478 -97.803860435 +16.2459257226 -74.0756224612 65.1833725301 +16.250575454 -81.4741857316 55.6585649903 +16.2539303671 52.089285419 83.8004540093 +16.2606166385 -76.8298064934 61.909394931 +16.2658934877 -98.254297592 -9.02849454487 +16.2787174008 63.0358939994 75.9044098026 +16.2880102675 -60.7876818725 77.7145961457 +16.2980595593 -80.6840013054 56.7843745053 +16.3126701028 97.4806726888 15.212338619 +16.3207544726 70.862212132 68.6453193248 +16.3292492511 57.7063434493 80.0208319415 +16.3374655328 94.0941983497 29.6541574976 +16.3430074743 73.1144124958 66.2358572986 +16.351185264 -75.1824147891 63.8767817516 +16.3555231517 -84.1418723132 51.503807491 +16.360203483 -79.2092704429 58.8067616682 +16.3624833854 51.1779037159 84.3391445813 +16.3793870961 69.6697679709 69.8415285431 +16.382008111 88.3894061126 43.805738178 +16.3904124947 97.6311823853 14.1246806796 +16.3917756389 -79.7132288165 58.1129145979 +16.3974182356 54.9339988491 81.9352210326 +16.405986956 56.7654980557 80.6754102716 +16.4090015711 30.474823042 93.8191335922 +16.4149905384 55.0629909629 81.8450677307 +16.4195409205 -77.0494703968 61.5936505456 +16.4201826884 71.6942825031 67.7518077755 +16.424064575 27.5735037599 -94.7098304995 +16.4356054328 -13.8990005282 -97.6559709305 +16.4381329366 -76.4816360427 62.2924323959 +16.4521242594 -74.088339289 65.1171681568 +16.4668791354 97.5651386308 14.4874295681 +16.4768837836 70.9735096463 68.4928699156 +16.4815367062 -24.591961461 95.5175082344 +16.4822987656 93.1904045073 32.3091679739 +16.4827414923 -71.6799258932 67.7518077755 +16.4946451265 54.9795154703 81.8851608095 +16.4957840821 92.1409987573 35.1841648405 +16.4987011162 -24.5804491858 95.5175082344 +16.5046599186 30.4231223409 93.8191335922 +16.5075298901 -82.6121169633 53.8770785007 +16.517386589 -80.2530771119 57.3290463408 +16.5242552924 -78.75375754 59.3699811383 +16.5446804993 -92.6938838349 33.6766602676 +16.5536034481 -81.3635603773 55.7310439129 +16.5537249322 -98.6039697617 -1.797592305 +16.5636606193 97.9302420367 11.6324048041 +16.5647441997 56.1013731103 81.1063818989 +16.5800138366 95.9880422161 22.6141303767 +16.5844412161 89.0478847276 42.3725209904 +16.5858877879 -81.3768340741 55.7020574338 +16.5865253951 97.7541243719 13.0007055036 +16.5881432015 -98.5981854145 -1.797592305 +16.588577085 4.83512928904 98.4958914628 +16.6007468422 94.9223456716 26.7238376078 +16.6086122829 -69.715657211 69.7415309387 +16.6097332324 96.1600991669 21.8483887314 +16.6159032421 -56.7484163826 80.6444604267 +16.6182186878 96.0094007852 22.4951054344 +16.6264547461 -36.8578137581 91.4607159799 +16.6267366193 -76.3851933338 62.3606756598 +16.6295483913 -81.2287462315 55.9048200602 +16.6416032054 -98.6003668591 -1.01227367745 +16.6448741417 -98.4104052132 -6.19195531093 +16.6524564533 -36.8811028296 91.4465961539 +16.6551720797 -78.0215670221 60.2929541689 +16.658131588 86.6673652357 47.0241901057 +16.675960268 -98.5941974282 -1.04717841162 +16.6760202117 -98.5945518368 -1.01227367745 +16.676356585 -78.456089306 59.7205256328 +16.6792331743 -71.5615683914 67.8287926333 +16.6798634618 37.3232492353 91.2620250784 +16.7042698478 -75.1618283824 63.8096146601 +16.7088790107 -75.8070594585 63.0404877715 +16.7139582524 -67.0360250827 72.296714591 +16.7159465606 -66.9444407795 72.3810678237 +16.7205257139 -62.3148354271 76.4021289334 +16.722414311 -34.3316424161 92.4213134976 +16.7231137863 -67.0727459235 72.2605301639 +16.7257739733 -88.5186575094 43.4130827946 +16.725935043 -97.6455079854 13.6234308163 +16.7284060582 -34.3287232814 92.4213134976 +16.7287351476 86.0618815858 48.0988768919 +16.7373323508 -75.063115563 63.9170586601 +16.7484465199 89.9284887343 40.4024312775 +16.7836206758 -75.3945955116 63.5135028529 +16.7898737293 34.4243426068 92.374589451 +16.7985257342 -45.3636448046 87.5211360941 +16.8037126357 -72.2096530276 67.1073859667 +16.8072522772 -88.5263477979 43.3659084588 +16.8075167721 91.1289915986 37.5900820721 +16.8141638989 95.1636020715 25.7132793155 +16.8253137272 84.8186427629 50.2265533143 +16.8316796409 57.6345298434 -79.9684658487 +16.8326763546 68.8936240148 70.5005643726 +16.8344429616 -69.0576603336 70.3394702811 +16.8487396594 -45.3776054271 87.5042450261 +16.8487829019 95.3595362285 24.9535040626 +16.8517617238 -75.8880142481 62.9049077599 +16.8559954107 30.0985455443 93.861349739 +16.8602907636 -76.1776866588 62.5515039842 +16.8720546998 -34.258350538 92.4213134976 +16.8863072502 -34.2872900405 92.4079778435 +16.8887561113 14.0213154673 -97.5611225314 +16.8901192652 87.2987957604 45.7563561703 +16.8912985634 -75.3819034855 63.5000209429 +16.8925655422 98.0014690122 10.5049179362 +16.8986488834 -75.9113198439 62.8641963719 +16.9121967645 -70.067144116 69.315026625 +16.9131876113 -90.8130434523 38.3005903839 +16.9173059503 -70.5741681366 68.797467622 +16.920825977 -97.2525871454 15.9881187692 +16.9311774409 -95.0510875279 26.0504508643 +16.9419399511 -70.5682585833 68.797467622 +16.950880515 -68.5980053283 70.7600262489 +16.9583140638 -97.4680502346 14.5737698481 +16.9656946137 -69.75478498 69.6163427557 +16.9744414706 -79.6533674069 58.027660624 +16.9845013657 -91.1959528849 37.3473545352 +16.9855626651 -97.6246617954 13.4505044618 +16.9906963057 -79.2545173406 58.5665238866 +16.9928545549 97.0645669542 17.0209499166 +16.9936417996 47.7764572676 86.1894788785 +17.0015410157 30.1482632185 93.8191335922 +17.003942832 -79.7918039372 57.8284873795 +17.0106544843 -68.2260086724 71.1044961634 +17.0149853159 -73.2333341847 65.93458151 +17.0289935037 -76.4968478488 62.1147780278 +17.0376302934 -66.2611581072 -72.9326955506 +17.0493213568 -87.7111546557 44.9007125805 +17.0528963613 87.8933368602 44.5416665749 +17.0590965757 -80.119210809 57.3576436351 +17.0595733978 -76.634217418 61.9368038909 +17.0616905124 77.1514624144 -61.2907053653 +17.0852169281 97.0932547628 16.7629126969 +17.0906668593 -46.9562212794 86.6199883945 +17.090971828 85.9221176298 48.2212441148 +17.0922447664 -87.6868265116 44.9318998616 +17.1030366315 -79.1046773714 58.7361571432 +17.1126205593 -78.6174015865 59.3840246647 +17.1235932885 -70.6725030524 68.6453193248 +17.1265918903 70.3628360657 68.9619543736 +17.1317949176 55.9308181432 81.1063818989 +17.1375157049 -81.1828837103 55.8179625922 +17.1399740627 -98.5121425792 -1.25660398834 +17.1517225653 53.4213608302 82.7766671236 +17.1572416324 -98.5095757197 -1.22170008352 +17.1664753773 40.8973609677 89.6254315973 +17.1690184606 -97.1719825364 16.2120515372 +17.1908119343 -73.6982885707 65.3684805299 +17.1996290507 28.7043677022 94.234983076 +17.2053111827 57.6405706758 -79.884553446 +17.205343278 -76.3461291383 62.2514636638 +17.208069688 -84.580364718 50.4979627488 +17.2108657693 84.2178542207 51.0993065504 +17.2132858733 -57.667287177 79.8635510047 +17.2154138783 93.52358929 30.9348956893 +17.2174762812 -77.7915121157 60.4321036641 +17.2195736129 -77.2258575595 61.1527040186 +17.2252588071 84.5138376523 50.6033764121 +17.2272020574 -62.245826327 76.3457963096 +17.232625072 -81.2125113797 55.7455346062 +17.2327540932 31.6071068738 93.2953534825 +17.2420757684 -75.5859042463 63.1623456061 +17.2475165974 50.6063361805 84.5075257572 +17.2510706842 64.247294167 74.6638182285 +17.2620619237 76.4112380241 62.1558036049 +17.2695509271 -67.504966842 71.7275544155 +17.2762017224 96.3063935559 20.6545736898 +17.2794771239 -71.698505236 67.5332808121 +17.2864968281 90.4474488881 38.9927687788 +17.287778145 97.2496417585 15.6089687246 +17.2898178373 96.2855993933 20.7399505455 +17.2904500533 37.079489798 91.2477494148 +17.2924395371 -11.9381659486 -97.7673346708 +17.2999077151 45.2565715838 87.4788884333 +17.3026903202 -97.1367489259 16.2809371901 +17.3041990003 -85.8192640222 48.3282383255 +17.3055166392 -97.3494268317 14.9535343444 +17.3120387467 -76.0762950185 62.5515039842 +17.3121623138 96.7010672729 18.6866964522 +17.3183744587 -64.6330533842 74.3144825477 +17.3227363947 -80.8033459772 56.3093427655 +17.3247522605 -69.1258963462 70.1531425771 +17.3254892318 -68.069867461 71.1780904964 +17.3287728525 -62.1484378394 76.4021289334 +17.3300989423 33.7207255549 -92.5342117203 +17.3327766348 -75.0765038281 63.7423989749 +17.3347302636 96.8271257508 18.0004123711 +17.3372187978 96.6465339743 18.9438199716 +17.3384135307 -69.4373120664 69.8415285431 +17.3515815666 30.4576051825 93.6549886748 +17.354547131 -97.1332645524 16.2464953535 +17.3655147634 -98.1840802848 -7.6370986393 +17.3681108969 93.0751818723 32.1769986684 +17.3713073575 33.9173111848 -92.4546033612 +17.3713226034 -74.3548176396 64.5724263505 +17.3717094588 -69.8298624034 69.4407231184 +17.3720981762 87.735506918 44.7290848419 +17.3759337494 -91.260895285 37.0071063192 +17.3772267805 33.9142788031 -92.4546033612 +17.3840197435 -75.1787259432 63.6078220278 +17.3854450811 -78.2913339063 59.7345238075 +17.3863214202 94.2672234161 28.4851964518 +17.3865879538 96.3411330488 20.3983490067 +17.3932298692 31.6120242918 93.2639023143 +17.4010460768 -77.4034806772 60.8761429009 +17.4033237673 -68.1269032556 71.1044961634 +17.4123268592 -68.8128457447 70.4386480127 +17.4219320178 -74.689117548 64.171738364 +17.4226852747 -98.3072190442 -5.66927875634 +17.4336350055 97.6743756452 12.4813746365 +17.4342887429 -98.1732438386 -7.61969620339 +17.4359331931 -80.8493104306 56.2083377852 +17.4467065778 97.7476109551 11.8750571435 +17.4502773911 92.3529835027 34.1528074559 +17.454182316 -80.8654398769 56.179463803 +17.4601199228 -69.2558040421 69.9912695896 +17.4602433784 -67.8556391442 71.3495069184 +17.460833215 97.7281469331 12.0136838835 +17.4739185287 55.1850079003 81.5430994891 +17.4792476842 -75.8922119309 62.7283673359 +17.480282007 -74.3524274959 64.5457687724 +17.4838140532 97.463730982 13.9691585007 +17.487573887 -75.8678186004 62.7555484428 +17.4910429384 -79.6864446711 57.8284873795 +17.4924931077 -75.8891600708 62.7283673359 +17.5028788451 -64.9586992916 -73.9865975598 +17.5098794941 85.1505694938 49.4245347472 +17.5100806585 -70.8610154647 68.3528606764 +17.513102701 40.6649695108 89.6641036785 +17.5185325939 -97.1692845575 15.8502730052 +17.5282573029 -87.7203586549 44.6978620671 +17.5315906203 -97.2417129456 15.3848169873 +17.5334603563 -97.7404848938 -11.805735075 +17.5416273687 -63.0393890871 -75.619618703 +17.5464981867 69.598424605 69.6288711231 +17.5491673071 -68.4983702494 70.7106781187 +17.5504171532 38.6538090681 90.5420670312 +17.5520722813 40.7163275605 89.6331714747 +17.5586677994 -98.3748893404 -3.7515773182 +17.573917349 95.5648550498 23.6329411694 +17.5822540166 70.7816531594 68.4165325029 +17.5834521336 31.8786642649 -93.1373876365 +17.589780822 89.0796539262 41.8976713794 +17.5926626118 -75.7196856963 62.9049077599 +17.598569422 -80.1763184435 57.1143442153 +17.6038099444 91.5874519262 36.0810826488 +17.6063012709 -76.4438591126 62.0189854765 +17.6199705291 71.6277263051 67.5204077514 +17.6250416179 66.1468465637 72.8968627421 +17.6323486336 -75.8904962873 62.6875813454 +17.6381219278 45.0766431455 87.5042450261 +17.6789997244 90.9505690306 37.6224263139 +17.6793925317 -74.0383410632 64.8518552727 +17.6824604651 27.8846092248 94.3916265369 +17.6910221303 66.0237934281 72.9923724601 +17.6918574198 -69.6618552221 69.5285848271 +17.6955554796 95.756459146 22.75011754 +17.7073262684 65.2638183126 73.6687492475 +17.7161729162 -69.6556753549 69.5285848271 +17.7216661814 91.5967550145 35.999680812 +17.7250531835 -75.8688976769 62.6875813454 +17.7390427747 -80.4808431191 56.6406236925 +17.758279706 -79.3159154993 58.2548628905 +17.7656821313 -75.5663777082 63.0404877715 +17.7660377304 -70.0051509451 69.1639121545 +17.774155633 -64.616756652 74.2209818805 +17.7796705137 46.1970864812 86.8890816908 +17.7905012649 37.6701241301 90.9090744247 +17.7960990142 -47.8522681821 85.9852271597 +17.8057243433 84.3482844089 50.6786256511 +17.8131862366 80.8172270155 56.1361399958 +17.8167811867 88.5208526015 42.9723278732 +17.8265318053 -48.8453241485 85.4186693447 +17.8281844455 -97.138137745 15.6951595979 +17.8335910869 -97.1675962175 15.5055239918 +17.8373822737 93.9521987843 29.2371704723 +17.8391859522 -68.8303190405 70.3146544139 +17.8431005323 89.7033239682 40.4343595529 +17.8456190811 80.8301336118 56.107248907 +17.8601730255 -80.2306336065 56.9566471151 +17.8630446325 -67.6089103299 71.4838924546 +17.8715434859 -97.0880459088 15.9536602398 +17.8721483614 -75.4280785654 63.1758757508 +17.88200907 -97.1449007134 15.5917291214 +17.8919476068 -68.3458233472 70.7723578937 +17.8919814881 -76.8862098061 61.3871952452 +17.8963672137 -78.5806846613 59.2013178799 +17.9005064119 -98.3050530251 -3.96086100934 +17.9031273475 84.4449826304 50.4828974973 +17.9035430817 47.3303797727 86.2513669207 +17.9124219478 -75.3050688377 63.3110712854 +17.9154240975 -97.135975183 15.6089687246 +17.9159179473 -97.1386527965 15.5917291214 +17.9293730305 -98.3661688694 1.62308493153 +17.9390450879 -81.4558714613 55.1645870628 +17.9410934736 -71.8509397723 67.1979137981 +17.946774965 -71.8736931509 67.1720589323 +17.95652911 -77.8402527076 60.153621011 +17.9574270365 67.583902919 71.4838924546 +17.9600482275 56.5145592149 80.5204400411 +17.9606356991 -68.6082064219 70.5005643726 +17.9616746491 -67.3629723972 71.691060765 +17.966281917 -97.1265813742 15.6089687246 +17.9723953728 59.4149950245 78.4018582101 +17.9773673466 -91.2100158545 36.844908347 +17.9806973261 -75.3001551831 63.2975604037 +17.9977793839 -98.3521971124 -1.71033926951 +18.0149983163 -98.3493465366 1.69288850399 +18.015353205 88.3115810804 43.3187222339 +18.0221747004 -87.5643957451 44.8071179262 +18.0384079959 -75.3090665794 63.2705328563 +18.0395587447 -98.2898257283 -3.69925378826 +18.0580446907 -34.4685582477 92.1185405566 +18.0619814678 53.5772769145 82.4817569156 +18.0686973751 -91.0867049909 37.1043710237 +18.0692648548 -90.840328798 37.7032668542 +18.0753856437 -87.5134659111 44.8851168881 +18.1109304385 -74.2940224036 64.4390598453 +18.1159208912 -66.5399471091 72.4171861437 +18.1307271899 96.6939998437 17.9317351584 +18.1384498624 72.7493488722 66.1704531892 +18.1458068066 -73.4337163729 65.4080957909 +18.1494977678 -70.6876267516 68.3655992076 +18.1518680812 -77.209020706 60.9038324474 +18.1601991108 51.6261928113 83.6955398099 +18.1621969463 -75.1883506613 63.3785967573 +18.1723498039 -78.0910208643 59.7625146976 +18.1736235872 -75.5823523412 62.9049077599 +18.1753098485 -37.7149555251 -90.8143173825 +18.2022164294 -75.6431835463 62.8234677493 +18.2104786661 84.7998619446 49.7731039913 +18.2154437356 -97.0522898446 15.7813385186 +18.2169654976 -97.0603978263 15.7296326041 +18.2284706393 -79.2717294742 58.1697151818 +18.2331254159 -97.9002686373 -9.1154011602 +18.243314609 55.3245923841 81.2795850728 +18.2486079524 -76.3042064029 62.0052932662 +18.2544305599 71.7719732634 67.1979137981 +18.2545088045 -98.3010045236 -1.91974423997 +18.2557997018 35.1439104583 91.8239148313 +18.2568454512 -67.9930505028 71.0185375623 +18.2601651758 -75.6517703033 62.7963057649 +18.2672164326 87.8230296246 44.1975595633 +18.2722694308 86.4836830265 46.7621293358 +18.2734122276 -76.2314561652 62.0874181818 +18.2781792626 -67.6011904544 71.3861836212 +18.2898159365 -77.492179556 60.5016094056 +18.2907976722 -68.8385642149 70.1904466245 +18.3241845907 96.9780066691 16.108708253 +18.3249147547 72.2602391379 66.6532470249 +18.3342108998 -75.6112994905 62.8234677493 +18.3415345563 -79.7634203251 57.4576791052 +18.3472856356 95.7259140818 22.3590358248 +18.3535063681 24.0924208947 95.3032216634 +18.3654591083 -80.1878053736 56.8561850734 +18.3660280187 -70.5082674978 68.4928699156 +18.3714352169 -75.5345149438 62.9049077599 +18.3817560541 -76.2722403719 62.0052932662 +18.3940762075 -77.031316848 61.0559922132 +18.3998663142 74.7418745074 63.8364873308 +18.4016639241 -98.0444751556 -6.97564737441 +18.4021119703 -98.046862356 -6.94082539579 +18.4147597193 -70.5943210588 68.3910700219 +18.4287552022 -80.1427243044 56.8992506345 +18.4358867804 -98.03804579 -6.97564737441 +18.4408900196 -76.6350424366 61.5386370179 +18.4436566262 47.8475755396 85.8512728225 +18.445061389 -74.9254608744 63.6078220278 +18.4465963833 -98.2838762988 0.0523598751674 +18.4494449184 -77.5627507907 60.3625519008 +18.4499520793 -96.9939252736 15.8675054211 +18.4514128826 87.0311208841 45.6632167098 +18.4514641391 -76.4443209235 61.772237046 +18.4522702918 -80.1169268201 56.9279523431 +18.4562020931 52.5555687502 83.0498693415 +18.4567291671 -80.1362865728 56.8992506345 +18.458483435 -76.2982257493 61.950505541 +18.4589938682 70.1121699282 68.8734286451 +18.4596260781 -76.1865782705 62.0874181818 +18.4674497138 -73.9040242479 64.7854034566 +18.4784504232 -67.2230516738 71.691060765 +18.4787401252 -66.8586961437 72.0309024888 +18.4826247833 -70.5519004804 68.4165325029 +18.4829380763 54.4489797778 81.8149717425 +18.4840994662 86.0008964162 47.562420907 +18.4955177951 -90.5040363616 38.3005903839 +18.5025833804 -68.3364595283 70.6242359774 +18.5095093894 -72.7748810706 66.0394938452 +18.525329557 96.4726824461 18.7038420242 +18.5254077577 91.7105510794 35.2984997999 +18.5270915366 69.5322432544 69.4407231184 +18.5338050786 90.530284648 38.2199637738 +18.5458625609 87.0273350083 45.63215909 +18.5651973823 61.9989496809 76.232956683 +18.5654745667 39.8501000195 89.8181088787 +18.5818424679 -75.0857416796 63.3785967573 +18.5822977112 -77.4008403841 60.5293988043 +18.5858158358 -78.0150890227 59.7345238075 +18.6061627765 -59.1191271017 -78.4776370533 +18.6118513809 -77.5239402778 60.3625519008 +18.616721386 -77.4251534639 60.4877119416 +18.6280584207 -79.9229234784 57.1429938149 +18.6319774402 -38.3199666361 -90.4678372333 +18.632190667 -38.337418626 -90.4603990929 +18.6347086374 70.9304025736 67.9825391166 +18.6352080985 -79.89052229 57.1859551582 +18.6438915328 -79.990854799 57.0426897773 +18.6629710151 -97.1894654128 14.3492621991 +18.6724866286 -67.7900351708 71.1044961634 +18.6799880584 57.2529927277 79.8320290977 +18.6867382626 -96.8567633531 16.4186846569 +18.6878248399 -68.1709215467 70.7353564932 +18.6917993507 -97.9858436579 -7.02787874735 +18.6918017623 -62.5011313694 75.790666473 +18.7014876741 74.8961854804 63.5674111417 +18.7063679749 -74.3084793359 64.2520170576 +18.7096951757 61.774619164 76.3796028635 +18.7102762274 -90.5075949969 38.1877049766 +18.7194447484 96.303194657 19.37206977 +18.7248091119 -77.3990841535 60.4877119416 +18.7274381524 92.2956342894 33.627354213 +18.7327454672 96.1029416745 20.32999874 +18.7328191722 85.4149689181 48.5114890576 +18.7379804832 -98.2279336323 -0.401424649846 +18.7401460355 75.330630079 63.0404877715 +18.7557618546 96.7604925049 16.9005469575 +18.756715596 94.9893435851 25.0042041528 +18.759583314 -77.6614267886 60.13967761 +18.7614919022 -75.6418076029 62.6603811364 +18.7643938659 42.9500005824 88.3356947831 +18.7677513355 -77.1053703505 60.8484459368 +18.7688481311 7.90126369046 97.9045472485 +18.7756045895 42.2699338191 88.66075438 +18.7760146601 82.4431053286 53.3909698101 +18.78285287 -78.6594485322 58.8208772008 +18.7851101076 -67.3714900509 71.4716864679 +18.8028513234 3.97266574947 98.1359807051 +18.803813839 -66.807170585 71.9945730144 +18.8118684966 -77.3453649811 60.5293988043 +18.8271684857 -77.5261078889 60.2929541689 +18.8383867553 87.352398172 44.8851168881 +18.8394910722 -37.9186684668 90.593863798 +18.8396542493 -97.1932912096 -14.0901231938 +18.8418291155 82.7988298461 52.814195551 +18.8448190438 57.9295766784 79.3034484816 +18.8541644042 -76.6449027496 61.4009720373 +18.8549613952 82.1274562667 53.8476680827 +18.8574225968 70.2297497347 68.6453193248 +18.8665072668 82.8404469178 52.7400726016 +18.8853707988 -75.9143967637 62.2924323959 +18.8865104479 -77.6522568224 60.1117853128 +18.8906457107 -74.2734162221 64.238642166 +18.890915244 -78.6863249227 58.7502816283 +18.8923453075 -34.9698323355 91.7615939008 +18.9009298356 -96.7858430357 16.5908239462 +18.9038524749 -77.7235589053 60.0141046146 +18.923073152 -74.7832569622 63.6347529312 +18.9262766826 86.6583996661 46.1748613235 +18.9271664837 -77.6423572247 60.1117853128 +18.9464438344 -72.8407444418 65.8426777644 +18.949636272 -98.1273347084 -3.45506413745 +18.9569423583 -77.7645027714 59.9442778349 +18.9598552784 -69.9285516697 -68.9240273721 +18.9675506453 -59.1479304115 -78.3693457326 +18.9693113977 -77.933459074 -59.7205256328 +18.9762040457 93.4379594552 30.1537959944 +18.9763310513 -79.9637726842 56.9709918989 +18.9763714942 -91.0729615127 36.6825981389 +18.9799465038 -75.3952324934 62.8913392129 +18.9849467219 -34.7919535716 91.81008531 +18.9863452166 -72.8897018982 65.7769720534 +18.9890443005 -71.2159913845 67.5847524792 +19.0003040572 -67.505271281 71.2883356168 +19.0070597248 49.5926810018 84.7307362866 +19.0111924578 -97.5314335601 -11.2336115762 +19.0117873651 -72.8830699729 65.7769720534 +19.0141858979 83.4888851066 51.6533328867 +19.0149835814 54.974049912 81.3405448449 +19.0266719217 -91.0755415229 36.6501226724 +19.028290035 -60.057499543 -77.6596479968 +19.0297537808 -34.2178218135 -92.0163525759 +19.0319994074 -73.5383308984 65.037657455 +19.0338920278 -67.7152274876 71.0799473873 +19.0509513837 -73.9306557898 64.5857521893 +19.053926267 -97.1186737984 14.3147159753 +19.0570668222 30.6760963475 93.2513019588 +19.0601359354 53.2915024943 82.4422645251 +19.0682271771 93.4727879743 29.9873410064 +19.0691085906 -80.4797605674 56.2083377852 +19.0751546561 -77.6601184975 60.0420225326 +19.0861351709 -73.430399328 65.1436558597 +19.0910203461 -98.0320765212 -5.02443181798 +19.09884515 -66.9582990212 71.7761820252 +19.1073725889 -90.8281016112 37.2177950778 +19.1081298803 -98.0287430164 -5.02443181798 +19.1175255878 -74.2963250571 64.1449631569 +19.1179350597 -67.9231968423 70.8586190225 +19.1242145171 96.5843410537 17.4851217417 +19.1355994849 70.7723283952 68.0081345566 +19.1425038631 -74.5551301462 63.8364873308 +19.1450604673 -93.0201642806 31.3163806484 +19.1525145574 60.4862421342 77.2955089162 +19.1553942428 93.5665011039 29.6374888035 +19.1557448886 -26.9746877344 94.3685522798 +19.1583795677 -76.9544893649 60.917674438 +19.1597423984 -79.6223864585 57.3862339406 +19.1631826107 30.6675028182 93.2323801216 +19.165958584 -77.5621377253 60.13967761 +19.1721119477 -85.0733699971 48.9382451749 +19.1738257916 -80.0493548791 56.7843745053 +19.1783529067 82.8725798233 52.5768608156 +19.1818005472 -98.0421534587 -4.44912046883 +19.1831750728 -80.0267268889 56.8131039249 +19.1922267918 -79.6351627574 57.3576436351 +19.1934747484 -74.6454667127 63.715499106 +19.1990305694 -88.7990332804 41.7867073801 +19.2074871544 73.6332993522 64.8784221735 +19.2132022085 -73.655208428 64.8518552727 +19.2158316435 96.3408490203 18.6866964522 +19.220145187 -77.8397575537 59.7625146976 +19.226086919 -67.1820748549 71.5326946227 +19.2413629086 54.1856101949 81.8149717425 +19.2455230006 -88.7889685195 41.7867073801 +19.2470390223 86.8177825881 45.7408364087 +19.2471041009 91.7307160224 34.8572047322 +19.2474537208 94.4355145661 26.6733783743 +19.2570313354 -77.2357341166 60.5293988043 +19.2588068143 -78.2898326176 59.1591114605 +19.2730749036 83.6140084442 51.3541252058 +19.2934928635 41.3185319359 88.9974159838 +19.2939226999 -67.7318418862 70.9939584863 +19.3044463636 -77.3109295177 60.4181969914 +19.3114390576 -77.5692916159 60.083885691 +19.323202428 96.440355816 18.0519145251 +19.3257125411 -77.6844587917 59.9303069992 +19.3294237009 60.1319821879 77.527531223 +19.3294880623 93.0930733768 30.9846829984 +19.3303879118 42.6136036251 88.3765630089 +19.3319946244 88.2942738059 42.78311813 +19.3329978408 -98.0879461143 2.23383561936 +19.3370161586 -78.3130738582 59.1028110073 +19.3385146712 -77.5625459263 60.083885691 +19.3440560267 89.6212478639 39.9229185776 +19.3448250222 -70.5675786359 68.161533069 +19.3488108315 95.7007657555 21.6098809163 +19.3500660387 -66.6902464496 71.9582238024 +19.3517777473 -37.7841606463 -90.5420670312 +19.3591312199 89.7670570498 39.5866076726 +19.3619093567 -76.9692702114 60.8345946742 +19.3655778836 -37.7948458535 -90.534656459 +19.381740798 62.8841569598 75.2989437316 +19.3825119276 -97.620545064 -9.72354939224 +19.3834986864 95.272939855 23.3954463532 +19.3873197419 -79.7113440225 57.1859551582 +19.3896911111 -77.8836108305 59.6505074801 +19.3932806047 46.6582083737 86.2954938496 +19.3998146492 69.4823283394 69.2520991747 +19.4015982858 -37.8651451008 -90.4975622348 +19.4057465868 90.75153009 37.2501917543 +19.4084026419 -60.8145625786 -76.9733907611 +19.4177543621 -67.4510905241 71.2271100259 +19.4260850304 -67.4357537257 71.239359485 +19.435960738 -49.1397412105 84.8971687629 +19.4406477641 -73.9455790494 64.4524053357 +19.4448806158 -78.1052934701 59.3418886604 +19.4462846224 40.6785887337 89.2585818452 +19.4464084875 -91.4881588917 35.3801353804 +19.4536797714 -68.7478468228 69.9663340513 +19.4552816932 85.6327421978 47.8385354909 +19.4616995227 -75.0905893806 63.108205791 +19.4625682319 -76.7463234347 61.0836334633 +19.4646442767 -98.0342068594 3.22829810258 +19.4676615808 65.0954300388 73.3729864503 +19.4919822667 67.8425336366 70.8339837725 +19.4956390711 84.6470739953 49.5458668432 +19.4991905786 -98.0290508605 3.17596507649 +19.5010344784 -89.0663230146 41.0718852613 +19.5071860396 34.8325870496 91.6851164162 +19.5118257781 83.7146912129 51.0993065504 +19.519944011 92.0711393584 33.7916718003 +19.5211556786 -79.2966504787 57.7145190037 +19.5271942356 -67.7422930091 70.9201693677 +19.5327256952 90.1139743926 38.7032846937 +19.5353312973 92.7017905314 32.0116988518 +19.5378737801 -74.2100428815 64.1181801339 +19.5429632449 -40.3726002721 89.3763152903 +19.5495369093 -66.8542024573 71.7518725918 +19.5552315537 70.6575300517 68.0081345566 +19.5706565002 -40.3938500543 89.3606528733 +19.5760451755 -72.0518161308 66.5230354654 +19.5762763101 -73.6765436924 64.7189023035 +19.576689419 85.6136320531 47.8232081533 +19.5823179907 49.0337305902 84.9248260906 +19.5838154757 -75.3991802036 62.7011785857 +19.5861880839 -87.1234478777 45.0098441037 +19.5863030955 -67.7252265253 70.9201693677 +19.590109202 70.4010232509 68.26363268 +19.5934137167 -91.0075539175 36.5201761892 +19.5960956056 -91.0200107643 36.4876784338 +19.5962739981 -76.7672771112 61.0145163901 +19.5964569821 52.2185306156 83.0012285095 +19.5966809171 -78.597994183 58.6372356736 +19.6010503642 -73.8216943601 64.5457687724 +19.6011243345 -56.6046697774 80.0731370949 +19.6239225585 -67.326628227 71.2883356168 +19.6239818713 -56.6706784052 -80.0208319415 +19.6263860754 5.43181348098 97.9045472485 +19.6328205994 -67.9304965042 70.7106781187 +19.6407753122 -89.1088756433 40.9126902895 +19.6411031702 -75.9465108265 62.0189854765 +19.6482282308 -96.7469757585 -15.936430246 +19.6515520136 -74.1684427264 64.1315726222 +19.6544086568 -88.4361485943 42.3409003465 +19.6701323879 83.7325562518 51.0092630351 +19.6720216954 -98.0036766937 -2.87939523683 +19.6723002024 84.0051675281 50.5582083675 +19.6770002467 -97.8514465509 -6.15711533009 +19.6798588599 -67.8268815636 70.7970147154 +19.6826402851 -89.1507566565 40.8011796273 +19.6838054445 66.5794083649 71.9703423989 +19.6951520129 -76.8188644036 60.917674438 +19.6956713784 -67.2667711189 71.3250449154 +19.6966322503 -67.357229294 71.239359485 +19.6984016636 -60.8059483905 -76.9064991547 +19.7107849034 83.1879079234 51.8773258161 +19.7173115195 -75.533768339 62.4970196645 +19.7199106828 -77.4772757386 60.0699331346 +19.7217662604 -67.7503361305 70.8586190225 +19.7250815532 -77.4975914975 60.0420225326 +19.7326480749 -62.7749286966 75.2989437316 +19.7420843208 -56.8512385757 -79.8635510047 +19.7435812573 83.9793770697 50.5732659231 +19.7521321136 -77.4907014239 60.0420225326 +19.7602476674 -97.9999080965 -2.35597648336 +19.7629603403 95.431725822 22.4100670509 +19.763186011 -98.0144806568 -1.60563391348 +19.7632955884 -98.0150241 -1.57073173118 +19.76997289 91.2854652799 35.7227098715 +19.7756865361 -76.356941242 61.4698279336 +19.7776410062 -73.9143553503 64.3856582585 +19.7828088876 -8.69640303422 -97.6371499317 +19.7840514552 85.6941415738 47.5931235364 +19.791014534 -78.7913314943 58.3115925445 +19.7968132956 -98.0046798806 -1.78014180529 +19.8023657898 -67.066529869 71.4838924546 +19.8107803478 -67.6599036274 70.9201693677 +19.8127119965 -97.9952580171 -2.09424198834 +19.8130439839 -67.2322932519 71.3250449154 +19.8156786066 -79.3583251881 57.5290805133 +19.8232688851 -54.0818683223 81.7446605564 +19.8335331556 -97.2243314609 -12.4121043561 +19.8360877915 33.5142871957 92.1049519564 +19.8399828059 -67.7158119828 70.8586190225 +19.8462556622 -92.7324306078 31.7304656405 +19.846999727 -74.0700113591 64.1851230356 +19.8509009184 -98.0080026377 -0.610861439068 +19.8529265923 -67.3242905872 71.2271100259 +19.8750731912 -66.7973353419 71.7153920498 +19.8781318044 -67.6272441856 70.9324729572 +19.8785945588 -67.109010551 71.4228407531 +19.8834386002 -67.2115082203 71.3250449154 +19.8880579848 -67.4434264769 71.1044961634 +19.8889370656 -78.3128770204 58.9196357353 +19.890614914 70.2919428809 68.2891367963 +19.8906338952 94.1434934234 27.2280247041 +19.9041336764 -74.7002875124 63.432582386 +19.9089243515 -76.3223098771 61.4698279336 +19.9090280704 93.6646129103 28.8196268134 +19.9109277711 82.1763913665 53.3909698101 +19.9113328827 -73.0339233894 65.342060399 +19.942853615 -72.5504275727 65.8689460119 +19.9468094007 -72.7635447362 65.6322432357 +19.9502660332 88.6706202998 41.7074091841 +19.9691275254 -66.8998017087 71.5936483022 +19.9709101447 -97.9850739338 -0.2967055375 +19.9765569462 -73.6275123239 64.6523518642 +19.9783765787 -51.2947845431 -83.4847863263 +19.9880479943 -97.981765942 -0.226892608084 +19.9886185038 -75.1227509482 62.9049077599 +19.9912522778 59.6437528384 77.7365588364 +19.9936087559 -67.1528366595 71.3495069184 +19.9988397544 -26.2522296888 94.3973879132 +20.0014969957 -74.490568428 63.6482154754 +20.0028916874 -78.4744704243 58.665507888 +20.0186052336 -78.3646618483 58.8067616682 +20.0186597967 -75.34148169 62.6331732926 +20.0216069179 -87.2090699141 44.6510176944 +20.0279297433 53.0583832547 82.3631592194 +20.0307289643 -64.6289591937 73.6333316555 +20.0356024461 5.08839479895 97.8400882716 +20.0383368631 -64.6535060078 73.609708712 +20.0476061054 59.4672376171 77.8571842519 +20.0531740361 -73.9098996113 64.3054970475 +20.0644558438 -73.1927047112 65.1171681568 +20.0666821915 -74.0107981765 64.1851230356 +20.0674602185 -73.2036643063 65.1039213298 +20.0785258885 95.8597136698 20.1932685142 +20.0849546788 70.5087812239 68.0081345566 +20.0876869679 30.4993131261 93.0928393117 +20.0894900798 4.87129503756 97.8400882716 +20.094768888 58.1944222872 78.8010753607 +20.1113450459 18.8001219663 -96.1357852961 +20.1165212015 89.6286701643 39.5224880204 +20.1293839003 -75.4926897708 62.4152360803 +20.1305113806 -58.8634527339 78.2933997461 +20.1339089052 -75.8285521369 -62.0052932662 +20.1397412414 -56.3410516339 -80.1253812691 +20.1471431775 -75.8250369519 62.0052932662 +20.1539852614 -67.3903402388 71.0799473873 +20.1590681447 -68.1869587691 70.3146544139 +20.1709269415 -63.0897971023 74.9186973186 +20.1709657873 -79.1338513872 57.7145190037 +20.170968707 -68.1834393095 70.3146544139 +20.1861225494 79.0779749098 57.7857624384 +20.1933411411 83.9177259688 50.4979627488 +20.1943734105 69.4190335801 69.0882411077 +20.1972874853 -75.8004948447 62.0189854765 +20.213094139 -75.0171623505 62.959162782 +20.2187206527 -70.7907602335 67.6747486196 +20.2208065492 91.8166720163 34.0707751944 +20.2232897736 35.1978047034 91.3900054426 +20.2409345011 -68.2010965799 70.2774145499 +20.2436333288 82.8541601979 52.2052051767 +20.2453726794 96.7404240161 15.212338619 +20.2724058819 -75.0807723341 62.8641963719 +20.2752491688 79.9509505573 56.5398954378 +20.2768968604 95.6415139066 21.0130500252 +20.2784808693 96.3950387399 17.2272957823 +20.2785225156 96.0622860132 18.9952291512 +20.2787097684 -97.9221856099 -0.139626294791 +20.2830707916 -73.6372240979 64.5457687724 +20.2855096399 -75.0772329882 62.8641963719 +20.2876608964 -78.5596807338 58.4532922799 +20.2880232551 34.1417718163 91.7754625684 +20.2940697288 -70.4488776914 68.0081345566 +20.2948169538 -96.8923392573 -14.1419587774 +20.2982527745 -72.0684595607 66.2881442707 +20.3002814213 39.9621676437 89.3919668171 +20.3076728908 32.5875952104 92.3344305239 +20.3129391297 -70.4681408806 67.9825391166 +20.3141322174 -26.1134519522 94.3685522798 +20.3149824896 -77.9904189483 59.2013178799 +20.3215203938 -64.7668150386 -73.4322509436 +20.3316455017 -72.9180316109 65.342060399 +20.3319337231 61.0488899955 76.5483213493 +20.3321213801 85.2133584376 48.2212441148 +20.3361053192 -66.1857401496 72.1518580586 +20.3368191537 -73.8323562957 64.3054970475 +20.3412322408 -97.7942451319 -4.74551261763 +20.3485217786 -96.811854383 14.6083028562 +20.3497463949 -75.0029751127 62.932039105 +20.3513364976 96.4072163482 17.072543418 +20.3575117482 -66.5864206074 71.7761820252 +20.3584028793 -97.0271092936 13.0872263805 +20.3640249948 -97.9038255223 0.383971491924 +20.3730399482 -79.0612591187 57.7430216549 +20.3768369487 -43.0103467077 87.948249511 +20.3791065293 42.3446556552 88.2701657102 +20.3895677028 56.6962911964 79.8110023334 +20.3982477931 55.3811517434 80.7269441918 +20.3983462105 -97.8974194262 0.0523598751674 +20.4003721188 51.4729566522 83.2728019878 +20.4091964238 -65.6474306585 72.6214813211 +20.4395079985 81.7959121671 53.7741133403 +20.4441490169 -72.7323765128 65.51364879 +20.4603673711 71.2598913538 67.1073859667 +20.4665086279 -70.5841104373 67.8159669868 +20.470255831 -96.5535442241 16.0742565604 +20.4703636859 -67.1651197339 71.2026045991 +20.4747182689 -91.0015919759 36.0485252079 +20.4771278906 -91.759846943 34.0707751944 +20.4850181928 -72.7802411023 65.44769312 +20.4869449097 -70.5165269062 67.8800745533 +20.5135408521 -69.7889645749 68.6199319824 +20.5136594361 53.9458569343 81.6641555162 +20.5183324103 -72.0301655706 66.2620048216 +20.5298390859 -90.7288337616 36.6988341962 +20.531680733 -74.4382960505 63.5404608684 +20.5446723538 -74.4347114625 63.5404608684 +20.5453075148 92.9040718079 30.7688768178 +20.5493406198 -65.8953135401 72.3569779188 +20.5606706123 -77.8190148626 59.3418886604 +20.569963617 -97.7806203783 -3.97830054534 +20.5707529838 -67.3679987497 70.9816657042 +20.5721062063 -70.0333840649 -68.3528606764 +20.5798488147 -62.7785535016 75.0687887408 +20.580847478 -67.7395453904 70.6242359774 +20.5864084353 86.279093467 46.1748613235 +20.5867774184 -59.8562089393 77.4171741084 +20.5922207026 -69.075230948 69.315026625 +20.6026430916 -73.8401295238 64.2118865129 +20.6070150782 -65.83759284 72.3931094691 +20.6130400045 -70.8121357151 -67.5332808121 +20.6162772622 -73.050999578 65.1039213298 +20.6200765217 -97.8492755187 0.5759554688 +20.6289869834 -66.0290492757 72.2122534463 +20.6474126219 -68.2583424608 70.1033739311 +20.6481889237 63.8518092575 74.1390500932 +20.6497233157 44.0824389196 87.3517458663 +20.6645666631 -97.8065609169 -2.61769483079 +20.6652470737 -75.5394208382 62.1831445234 +20.6806936369 -72.938231593 65.209840383 +20.6854194796 -68.297954542 70.0535711176 +20.6943542276 -73.7212837312 64.3188621489 +20.6957964177 -75.1356150336 62.6603811364 +20.6987063338 -97.7993416638 -2.61769483079 +20.7012944216 -72.1939931721 66.02638684 +20.7057307373 -97.832531276 -0.261799088742 +20.7168011081 -96.0624857509 -18.5152095101 +20.7260822117 -62.9646534732 74.8724377134 +20.7278369341 -75.1494669265 62.6331732926 +20.7278963067 -73.0075936183 65.1171681568 +20.7285773961 92.2050337011 32.6888029655 +20.7316454032 46.1946777264 86.2336977557 +20.7325282157 94.5329283786 25.1731548668 +20.733274686 -65.8376720977 72.3569779188 +20.7427757412 -62.7938777806 75.011106963 +20.7484579247 -79.0884175203 57.5719003324 +20.7524326106 76.540012293 60.917674438 +20.7529600302 -71.8062324079 66.4317667789 +20.7534629924 -73.832796027 64.171738364 +20.7603058227 -74.4553920194 63.4460739636 +20.7646193989 52.2322488296 82.7080574275 +20.7650902873 87.7057542547 43.3187222339 +20.7656301521 -71.4757678022 -66.7832555471 +20.7692217501 39.2262339075 89.6099436521 +20.7692254006 -74.4873814647 63.4055934345 +20.7801496149 -72.7084047051 65.4344960034 +20.7843219554 -38.4718912426 -89.9328946775 +20.7904871757 -91.7319650843 33.9558864524 +20.7955344546 46.0999020918 86.2690255763 +20.8000953495 62.6368745274 75.1264133504 +20.809388901 -67.0998803767 71.1658301926 +20.8110711416 95.2086561859 22.4100670509 +20.8134031067 -87.8414263915 43.0196008887 +20.8199664225 -61.0534442891 76.4133884775 +20.8217852594 55.9880933156 80.1984205923 +20.8561213806 -67.5003374742 70.7723578937 +20.8611891365 -97.4747482309 -7.96770011589 +20.8667058087 83.2583185679 51.309189995 +20.8707440638 -65.9926796969 72.1760228098 +20.8712492088 -87.8122594614 43.0511096808 +20.8775342457 95.1941041168 22.4100670509 +20.8782566849 -76.3180528382 61.1527040186 +20.8864611056 -91.4150028844 34.7426681491 +20.8925911234 -73.4900329412 64.5191033296 +20.8970143784 -72.8765497762 65.209840383 +20.9024157153 -91.411356117 34.7426681491 +20.9054172356 -73.4863853769 64.5191033296 +20.9094325547 -97.7835606152 1.08208301821 +20.9100065494 -72.7780173028 65.3156323064 +20.9153661526 -67.0278789535 -71.2026045991 +20.9181227503 -71.6736903827 66.5230354654 +20.9300206051 79.8941031424 56.3814377303 +20.9315395205 91.1725068288 35.3474843779 +20.9406081706 -97.6792100523 4.50142788612 +20.9434715293 -73.1349056179 64.9049811691 +20.9546731858 -97.7448174864 -2.61769483079 +20.9567126733 -28.4042300028 93.5628981588 +20.9571980766 -97.1771911652 -10.8346373271 +20.9580030546 -73.330702432 64.678977951 +20.9589150829 95.1682034688 22.4440844558 +20.9596086894 -78.7720003382 57.9281172343 +20.9650031506 49.5828223251 84.2734381236 +20.9695382362 -73.4681139795 64.5191033296 +20.9719498627 96.5909445641 15.1778373678 +20.9791114509 -44.6840558462 86.9667294767 +20.9850545043 88.9116444525 40.6736643076 +20.9916963094 68.4470537223 69.8165418993 +20.9941233119 81.9448129083 53.3319268711 +20.9951848317 91.1578716406 35.3474843779 +21.0020670355 -72.7633681149 65.3024152754 +21.0299329649 93.698354025 27.8991106039 +21.0303155925 -53.4706528316 -81.8450677307 +21.0490054419 -77.473210561 59.6224874966 +21.0563225319 55.960119452 80.1566984871 +21.0570145353 -73.9212238633 63.9707339446 +21.0584235012 -73.5363195671 64.4123629761 +21.0591233107 -28.4909585911 93.5135209686 +21.0782734356 75.8515515279 61.6623752364 +21.0826727996 47.285810374 85.5545033584 +21.0874178717 -90.9773517897 35.7553110579 +21.0874746264 -72.9636688799 65.0509141939 +21.0906266119 -72.9745749003 65.037657455 +21.1134365201 -67.29073472 70.8955557081 +21.1184596978 -70.1689592368 68.0465121782 +21.1186132462 -47.4331819648 85.4640124453 +21.1189063469 37.9120375633 90.0925590851 +21.1226539977 -36.6593535198 -90.6086380408 +21.1313968973 -97.7365815198 1.01227367745 +21.1339242617 -59.7798170296 77.3287186058 +21.134413554 -72.3678215538 65.6980590831 +21.1351692632 -47.4258072885 85.4640124453 +21.1429519981 -70.1615832289 68.0465121782 +21.145265942 9.8916685801 97.2369920398 +21.1566579343 81.8067262788 53.4794854183 +21.1575482498 -72.6826891004 65.342060399 +21.1592206373 35.4245995423 91.0899836935 +21.163870358 83.823333471 50.256734447 +21.1717756069 -38.1164106216 -89.993861785 +21.1805883651 89.8102119777 38.5422949633 +21.1820906455 66.7744102349 71.3617346599 +21.1827038171 -72.5802488579 65.44769312 +21.1837760904 87.3630638956 43.805738178 +21.1858804618 -73.065052443 64.9049811691 +21.1880848822 45.0882362801 86.7070701164 +21.1882421192 -96.3696517822 -16.2464953535 +21.1925728729 -72.8503874819 65.1436558597 +21.2049443637 -73.0831079717 64.8784221735 +21.2061531953 -91.1280142357 35.2984997999 +21.2256954307 -88.4113842977 41.628079226 +21.230245856 32.4185125866 92.1863151589 +21.2349631826 -65.2382484213 72.7533317557 +21.2382065715 -70.7009552985 67.4560116039 +21.2399350254 82.6043686046 52.2052051767 +21.2407940385 85.7017688614 46.9471562786 +21.2423450656 78.7276307938 57.885429304 +21.2479490694 28.9997687875 93.3141900818 +21.2578502701 -69.3148947093 68.8734286451 +21.2644258722 31.6806235796 92.4346378904 +21.2782033811 -70.3436754976 67.8159669868 +21.2865103042 -91.3289026553 34.7263015429 +21.2943734381 -68.0336420816 70.1282625266 +21.294701331 -53.5656405401 -81.7144898335 +21.3008569699 -97.6945514584 1.43112113063 +21.3108134577 50.9451394272 83.3693108915 +21.3289807162 83.2518371143 51.1293086077 +21.3348437956 -76.4128239612 60.8761429009 +21.3392527004 -71.947875701 66.0919017453 +21.3434702602 80.6108672556 55.1936985312 +21.3470014002 42.9655910424 87.7397487892 +21.3501851356 96.0663929472 17.7600039637 +21.3694967916 -62.1672481673 75.3563392302 +21.3750426923 60.0944650843 77.017938275 +21.382350736 -65.4967966898 72.4773392198 +21.3956321546 -72.6961217439 65.2495272634 +21.4174201462 -87.8577882884 42.6884428311 +21.420197454 -97.6684546481 1.43112113063 +21.4290970535 96.6604103052 14.055563991 +21.4386736787 58.2686087648 78.3910231054 +21.4424685329 -62.8071233439 74.8029798903 +21.4491905434 -81.7594513928 53.435234939 +21.4502042902 80.5026962603 55.3100771174 +21.4598025488 -66.9598947126 71.1044961634 +21.4607348187 53.0372120878 82.0151875874 +21.4743683232 -68.3992667997 69.7165102855 +21.5046157939 -66.5795719432 -71.4472679633 +21.5073631029 -72.841004214 65.0509141939 +21.507848113 30.1751655254 92.8809552872 +21.523089749 84.6235447848 48.7402531354 +21.525999614 -62.9439877046 74.6638182285 +21.5313728334 -96.4840131008 15.0743225348 +21.5324734489 78.3333311056 58.3115925445 +21.5351415685 44.5872926168 86.8804409216 +21.5489022477 -66.996429903 71.043107985 +21.565871412 -69.9705798865 68.1104334195 +21.571147575 -70.0311200301 68.0465121782 +21.5747490635 -90.7017469841 36.1624570082 +21.5775227882 -72.3803610796 65.5400170912 +21.5907333161 73.1233619362 64.7055961569 +21.5939301614 -65.2940128592 -72.5974797422 +21.6038431673 91.8920062097 33.0020174407 +21.6233698423 -51.6163991287 -82.8744666206 +21.6239077978 -72.628546753 65.2495272634 +21.6280424108 -92.5749400937 31.0178698193 +21.6324018355 82.634062368 51.9966434242 +21.6423150039 -67.4079186289 70.6242359774 +21.6450511935 -62.8617931242 74.6986393721 +21.6667810398 -88.0785957994 42.1035813367 +21.6741224038 79.9394281313 56.0349912828 +21.6763626995 -97.5340477624 -4.15268915247 +21.6769686447 6.01155544599 97.4370064785 +21.6805949988 -64.7964682564 73.0162276621 +21.6817505513 -7.3262167185 97.3459205187 +21.6875524263 -97.0245321505 10.7652324982 +21.6894856687 -91.1841076596 34.8572047322 +21.696452186 75.5649591965 61.7996836899 +21.6998839682 89.1517348041 39.7628371371 +21.7053184391 69.9025491175 68.1359873953 +21.7094654279 -63.8807552858 73.8102175512 +21.7128959126 -88.0672390263 42.1035813367 +21.7150082917 92.9471818833 29.8207946716 +21.7182862641 59.6705010998 77.2511963678 +21.7414934183 -71.6946209409 66.2358572986 +21.7419841278 -75.3268710155 -62.0737354217 +21.74558399 -62.8684644673 74.6638182285 +21.746694616 88.3369852905 41.5169640396 +21.7566450678 94.8423569274 23.0559260896 +21.7566501022 -90.8324621254 35.7227098715 +21.7583956333 -92.6219534461 30.785482931 +21.769516238 80.0147308646 55.8903480703 +21.7769177864 -69.9176334278 -68.0976533192 +21.795824435 -71.7385054342 -66.1704531892 +21.7982922276 -45.0317450682 86.5850818101 +21.8015297244 -72.0737416038 65.8032603517 +21.8038731604 -95.3536491353 -20.7911690818 +21.8366711132 -72.0990924312 65.7638248986 +21.8375359439 -66.733133616 71.2026045991 +21.8423339579 -69.3594447935 68.6453193248 +21.8432645284 -66.0479303372 -71.83691734 +21.8433239446 -72.1210583756 65.7375245794 +21.8451742147 -72.0365181259 65.829540632 +21.8467235996 -72.6806375811 65.1171681568 +21.8506523297 96.5659883896 14.055563991 +21.8569129956 -64.8715866667 72.8968627421 +21.8650362582 -64.89569661 72.8729630997 +21.8676016456 -53.1337264497 -81.8450677307 +21.8733988787 77.9737943526 58.665507888 +21.8752760343 90.2148478989 37.1853938664 +21.8784833633 -72.1463581786 65.6980590831 +21.8919272522 86.5160541286 45.1189084442 +21.8977326099 -72.1644790512 65.6717387452 +21.8990677272 65.8310262712 72.0187948577 +21.9024849654 -64.1545572351 73.5151272753 +21.9026452453 68.962354838 69.0251240234 +21.9086095439 42.9054641387 87.6306680044 +21.9155375786 67.4490892139 70.5005643726 +21.9190357089 -66.7456402066 71.1658301926 +21.9201642364 85.2498524263 47.4549160903 +21.9317204832 34.254147265 91.3545457643 +21.9329144065 -72.189721661 65.6322432357 +21.9368791628 -28.9532018437 93.1691227586 +21.93957305 -72.2116378376 65.6059028991 +21.9424730355 -28.9081406482 93.1817969421 +21.9470226818 71.2072271271 66.6922709185 +21.9594356172 93.9934090264 26.1346943155 +21.9666126069 -58.0716404716 -78.3910231054 +21.9747727513 -72.2368293623 65.5663774065 +21.978267256 -64.8574361002 72.8729630997 +21.9853169012 75.0866142898 62.2787780488 +21.9895596512 -95.2472471152 -21.0812993745 +21.9905212697 -67.760337323 70.1780140797 +21.9912136727 -95.2544114694 -21.0471759821 +21.9940435434 -72.2548836294 65.5400170912 +21.9960890541 95.6562980784 19.1322947989 +21.9965194791 52.5843724362 82.1646937942 +22.0060123221 -72.4303152312 65.342060399 +22.0062376035 -68.9546552877 68.9998624687 +22.0131303868 61.3116464412 -75.8703110659 +22.0154211864 -70.7703783993 67.1332612883 +22.0225586528 -58.0358125607 -78.4018582101 +22.0244432964 32.3715114893 92.0163525759 +22.02591255 81.2369156413 53.9946544894 +22.0283782826 81.2460098623 53.9799632428 +22.0289291359 -97.5119748183 2.47811383077 +22.035673379 50.3179262013 83.5615665335 +22.0435397805 -73.0117262168 64.678977951 +22.0471591839 -67.9348581596 69.9912695896 +22.0487711535 56.698320961 79.3671978264 +22.0586234897 -66.6210986843 71.239359485 +22.0822100275 -64.7549065324 72.9326955506 +22.0919975845 86.9874485636 44.1035988909 +22.0980982585 63.8155002378 73.7513117358 +22.0988733787 -90.6532217915 35.9671123975 +22.1003533164 -71.8383211816 65.9608216527 +22.1029296359 -71.5356025393 66.2881442707 +22.1036024856 -72.6148069243 -65.1039213298 +22.1114636792 -90.8426675895 35.4780625061 +22.1160693252 -96.9525433467 -10.5396307434 +22.1220390057 -71.8195990053 65.9739387103 +22.1231509792 87.7517803876 42.5463421407 +22.1254282741 -71.8306023265 65.9608216527 +22.126915246 -75.1808085368 62.1147780278 +22.1285938626 87.7733696587 42.4989518979 +22.1318845145 95.6352391155 19.0808995377 +22.1324928213 -71.586982776 -66.2227805105 +22.1355724812 -72.6288208107 -65.0774217266 +22.1378177485 48.0647602309 84.8510214982 +22.1384582845 73.651193317 63.9170586601 +22.1425879268 -62.6329421094 74.7450357056 +22.1483466972 -71.0228263286 66.8222184522 +22.1494684511 51.6288020443 82.7276727994 +22.1510622724 74.3991084741 63.0404877715 +22.1553842914 72.2414595028 65.5004616457 +22.1736731187 -64.7639994347 72.8968627421 +22.1983002254 74.1317891933 63.3380872628 +22.2237600538 82.1937795022 52.4431797303 +22.2251292382 37.73078223 89.902345368 +22.2261774669 34.1209163765 91.3332365617 +22.2394275976 -70.66344429 67.1720589323 +22.2439354762 -30.5824638072 92.573863709 +22.2440330912 95.0617795279 21.6439613938 +22.254953882 -71.2334273946 66.5621202286 +22.2802475782 55.423856798 80.1984205923 +22.2813320811 79.8027640722 55.9916162217 +22.2831123549 -27.5861956879 93.5011481814 +22.2856705125 -72.2611626158 65.4344960034 +22.2898687121 -72.3195928225 65.3684805299 +22.2907665064 90.957311109 35.0697773643 +22.2922066785 72.4619502816 65.209840383 +22.2951739311 -91.1128556312 34.6608245445 +22.3029988828 -27.5911065385 93.4949575154 +22.3067263292 -97.2402911295 6.83635440257 +22.3082630702 -69.77486929 68.0720868959 +22.3179424786 28.9073124384 93.0928393117 +22.3225514242 -39.5676907902 -89.0847997329 +22.3245770964 44.0613087994 86.9494929505 +22.3256363901 78.3747554868 57.9565670322 +22.3332671561 96.3523137367 14.7464170468 +22.3338479686 96.3548195336 14.7291543397 +22.3463877615 -53.2900862694 -81.613759008 +22.3499969186 -10.9830297593 -96.8496292974 +22.3525044095 96.2062790472 15.643446504 +22.3536649316 -61.9878364574 -75.2184937064 +22.3601044873 -88.8879754848 39.9869171297 +22.3632019445 -54.6629467285 -80.6960312144 +22.3641373965 -73.1497973636 64.4123629761 +22.3696311804 -72.1754052642 65.5004616457 +22.3780421848 -11.2305250225 -96.8147640378 +22.3790241442 -88.8976018976 39.9549202878 +22.3796759918 -65.0690749178 -72.561460789 +22.3885078345 95.4538902519 19.6801817247 +22.398264565 -65.0492835908 -72.5734693176 +22.4056896228 -71.8039474401 65.8952062334 +22.4061679649 -64.4141387306 73.1353701619 +22.4099211489 87.4709921703 42.9723278732 +22.4150055326 -73.6839897339 -63.7827342144 +22.4174938931 -64.3019933993 73.2305237754 +22.4213731953 -96.8861637345 -10.5049179362 +22.4272893013 -70.1471546487 67.6490457382 +22.4312347892 -56.7416153819 -79.2289643355 +22.4401885193 47.1526859727 85.282249881 +22.4434230667 -68.0618220692 69.7415309387 +22.4524417785 70.2258255339 67.5590207616 +22.4548129599 -72.3163159415 65.3156323064 +22.4648467324 96.3084677739 14.832723834 +22.476907762 95.0840110781 21.3030386275 +22.4775806917 72.5237033505 65.0774217266 +22.4952393673 -97.2053506983 6.71446210994 +22.4960991519 81.2835581877 53.7299608347 +22.5008399883 -64.0015397493 73.4677827999 +22.5011592866 95.4097143309 19.7657340379 +22.5119125262 49.3522238748 84.0093553899 +22.5144144713 -97.365570235 -3.6120456584 +22.5191008419 -76.5133408791 60.3207987745 +22.528358007 -97.4258702846 -0.820295548752 +22.5303273211 40.4291794451 88.6446038978 +22.5427078742 -88.8921713202 39.8749068925 +22.5459640121 60.3661489621 76.4696512759 +22.546134002 -56.8001657477 -79.1543619303 +22.5521319486 -96.0007599207 -16.5908239462 +22.5622983706 -28.3646965114 93.2007869283 +22.5632150511 -71.5613755807 66.1049986881 +22.5732588771 49.3725573001 83.9809417029 +22.5737357215 -88.8842970152 39.8749068925 +22.5794302626 -97.4143341168 -0.785390088871 +22.5815474645 89.1105966144 39.3621046838 +22.5842717561 87.832637274 42.13524058 +22.5949823563 -72.188972685 65.4080957909 +22.6071349206 -68.7599914921 -68.9998624687 +22.6104828114 -68.5684466863 69.189118986 +22.6230054864 -67.809634295 69.9289147602 +22.6272348782 89.4219615733 38.622804535 +22.634535981 -62.5954761165 74.6289766155 +22.6373960325 49.262517312 84.028285053 +22.6489670759 -28.1495067076 93.2449975201 +22.6734997412 -69.7818568836 67.9441304262 +22.680612456 82.7361271636 51.3840741921 +22.6831676799 95.5838965502 18.6866964522 +22.6895891722 -52.9898546369 81.7144898335 +22.6915339269 -39.9118780921 -88.8376962511 +22.6990929643 -97.3895308382 0.17453283659 +22.7021097563 -64.2156161163 73.2186373775 +22.7080847382 -52.981931248 81.7144898335 +22.7161027537 -97.3856210135 -0.139626294791 +22.7171299754 52.2458220686 82.1845854285 +22.7238875799 -96.3541297971 14.1246806796 +22.7284028422 -92.3942418315 30.7688768178 +22.7302689776 -67.5416275993 -70.1531425771 +22.7382041567 85.6368779412 46.3605350294 +22.7433861012 94.2257315137 24.5814952628 +22.7440614938 -69.2579256433 -68.4547105929 +22.783259256 46.2405630672 85.689750991 +22.7850955461 -65.3564163056 72.1760228098 +22.7851212552 57.4607273425 78.6072710546 +22.7888623958 -96.5542038689 -12.5679539283 +22.7900625958 53.6119585286 81.2795850728 +22.7910368134 -96.41287048 13.6061400396 +22.8079566054 -63.4557658097 73.8455340626 +22.8141990432 36.8242313972 90.130396116 +22.8219325025 -89.7302780282 37.7840786818 +22.8314179427 -71.0263502058 66.5881666001 +22.8338914016 35.3363778623 90.7190928252 +22.8405420001 30.4428718811 92.4745434851 +22.8424321056 72.8012248369 64.6390358665 +22.8509297027 -71.0444872062 66.5621202286 +22.8549561714 95.9350644637 16.5564001146 +22.8852258584 -73.3407265008 64.0109699485 +22.8980650221 -59.1265413924 77.3287186058 +22.9146109801 -96.9356259926 8.85466075362 +22.9179122857 85.0555948955 47.3319667185 +22.924277876 82.1055371467 52.2796160442 +22.9370229079 -66.1261733271 71.4228407531 +22.9465104442 -88.2192414422 41.1196193781 +22.9577601002 -67.8257804877 69.8040453872 +22.9591150821 -57.1991155723 78.7473187632 +22.9604991958 28.608189088 93.0289578238 +22.9762219043 -91.1354978583 34.1528074559 +22.9775892277 -67.4190744221 70.1904466245 +22.9802579879 -90.817095319 34.9880399656 +22.9833302732 -90.6960993727 35.2984997999 +22.9874303128 83.3416983888 50.256734447 +23.0016034822 72.2040541047 65.2495272634 +23.0122330808 -91.0771328777 34.2840049499 +23.013946597 -63.8188307045 73.4677827999 +23.0171749296 82.0511011798 52.3242434579 +23.0188700055 -71.9109294715 65.5663774065 +23.0193788928 67.1194047715 70.4634209964 +23.0256107508 -96.8012705186 9.96670836044 +23.0263645103 -70.3245376475 67.2625151337 +23.0380256711 -94.3626172754 -23.7685892326 +23.0479795265 -95.1236329891 -20.5008557553 +23.0558892705 89.9270658291 37.1691915613 +23.0627488917 77.3624529866 59.0183063249 +23.0680704618 72.1948007103 65.2363002904 +23.0703859332 -69.9631467887 67.623334614 +23.0856782282 -68.6769969607 68.9240273721 +23.0858016591 -73.8022796597 -63.4055934345 +23.0956454486 -70.5361277121 -67.0167579691 +23.0978231362 -71.4269809622 66.0657018202 +23.1049174258 -71.44891912 66.0394938452 +23.1155535814 -71.4818100324 66.0001667961 +23.125970158 -71.5993816701 65.8689460119 +23.1305139854 -69.1298193287 68.4547105929 +23.1314441915 50.6401655153 83.0693079675 +23.1336504687 62.3710546931 74.6638182285 +23.13411582 -62.6067954895 74.4661120495 +23.1391444575 -63.6779981675 73.5506121195 +23.1423248235 -71.43681162 66.0394938452 +23.1462084664 95.6749586187 17.6225800308 +23.1532592007 -97.1872095187 4.30962809844 +23.1548733842 95.8571666562 16.5908239462 +23.1628196161 -31.5669866483 92.0163525759 +23.1683287418 -31.5629434929 92.0163525759 +23.170174904 79.752265125 55.7020574338 +23.1742255961 -97.2752172347 -0.698126029796 +23.1747445263 -90.3906482262 35.9508265466 +23.1991587394 75.6448664815 61.1527040186 +23.2010607048 -71.4904244572 65.9608216527 +23.2121387568 92.411397927 30.3534206887 +23.2229618534 -66.7622901385 -70.7353564932 +23.2244039143 -31.5815233729 91.9958392769 +23.2306030405 -63.412010689 73.7513117358 +23.2340912823 -65.9033428766 71.5326946227 +23.246017442 -69.8801064953 67.6490457382 +23.2490966308 36.6629958348 90.0849834449 +23.256742221 90.3825378386 35.9182515599 +23.2575019537 49.1350221978 83.9335343977 +23.2615317293 -68.6049300117 68.936671806 +23.2648166063 -69.6119510272 67.9185142834 +23.2762338999 -74.4110665541 -62.6195665085 +23.2876960931 33.4442885007 91.3190165155 +23.3077058162 27.0499241506 93.4079892355 +23.3104079115 -39.8590353778 -88.7010833178 +23.3170978833 -91.0119082005 34.2512118325 +23.3174280295 -69.4065300206 68.1104334195 +23.322231852 91.6303839863 32.5568154457 +23.3245525726 94.6040986363 22.4951054344 +23.3266792957 -76.6328617403 -59.8604254456 +23.3320285433 -76.7947485277 -59.6505074801 +23.3427011679 95.2497228682 19.5603833222 +23.3436474972 -97.2332895531 0.872653549837 +23.3470047032 -62.6109115911 74.396176791 +23.3568589521 -95.4516042028 -18.532360751 +23.3649177598 -76.5665652949 -59.9303069992 +23.3649504208 -66.6080012818 70.8339837725 +23.3776861792 95.6813692626 17.2788704766 +23.379523522 -74.9708256535 -61.909394931 +23.3832880927 -72.8304148952 64.4123629761 +23.3846043764 -71.672346905 65.6980590831 +23.3971132045 -71.66826443 65.6980590831 +23.3990842632 -96.5727126397 -11.2336115762 +23.408329493 69.4762099173 68.0081345566 +23.4264354363 79.1878150232 56.3958515726 +23.4271927114 89.2991472047 38.429532266 +23.4430416068 95.6591613014 17.3132509753 +23.4454974635 -18.6160084222 95.4135885454 +23.4466040142 -71.3132512455 66.0657018202 +23.4480588433 -95.6796340987 -17.1929100279 +23.4484974721 -69.9989604551 67.4560116039 +23.4629553299 47.4319921352 84.8510214982 +23.4630137834 52.698791784 81.6842967082 +23.4692354151 -62.9387042307 74.0804596287 +23.4705121728 79.1336752114 56.4534897583 +23.4753889942 -59.8099306766 -76.6268771648 +23.4840980045 -97.0716265706 -5.05929400767 +23.4859026342 -64.5971372119 -72.6334787924 +23.4866714072 -68.0173671867 69.4407231184 +23.4966997305 75.0698800415 61.7447828754 +23.5029522184 -97.001396518 6.19195531093 +23.5053137328 69.4434580105 68.0081345566 +23.5292267402 80.568068647 54.3613999406 +23.5668319145 -70.5156278196 -66.8741404933 +23.5783715484 51.5471613639 82.3829506054 +23.5894647871 68.2378411514 69.189118986 +23.6006201056 -65.7331715336 -71.5692733704 +23.6099535768 -70.5627132259 66.8092328522 +23.6108242477 92.7642305323 28.9365946873 +23.6178513543 45.0426655233 86.1008442465 +23.6182464265 80.4033241098 54.5663257682 +23.6185337796 49.8527484489 83.4078433613 +23.6418275996 55.6156735194 79.6740914397 +23.6425851223 23.0960127866 -94.3800951583 +23.6471767343 79.0707775731 56.4678950066 +23.6531745203 27.3541702851 93.2323801216 +23.6563325385 -69.2917512424 -68.1104334195 +23.673794748 -69.8609045126 67.5204077514 +23.6770096956 41.8149095025 87.6978480647 +23.6787286597 -55.4335562599 79.7899658444 +23.6901506065 88.7224732366 39.5866076726 +23.7001678096 57.4155701465 78.3693457326 +23.7068472176 -71.348555389 -65.93458151 +23.7092608455 91.0212542508 33.9558864524 +23.7105545349 87.87522176 41.4216731225 +23.7203654819 -19.0716634974 95.2555295657 +23.728816479 -50.2668033662 83.1275631055 +23.7313157568 77.5248390488 58.5382266806 +23.7346793802 79.5150084617 55.8034803938 +23.7415782694 -96.8773379889 7.14974443327 +23.7457286332 86.3260117833 44.5416665749 +23.7487595433 37.1634747472 89.7489418593 +23.7587155427 65.2765344687 71.9339800339 +23.7610975928 -69.5192444631 67.8416162135 +23.7613466582 -67.211793608 70.1282625266 +23.7665689157 -70.7434403506 66.5621202286 +23.7776509957 -70.653860292 66.6532470249 +23.785718744 -71.4192632559 65.829540632 +23.7858358595 -68.805888717 68.5564270534 +23.8020614358 70.522752711 66.7832555471 +23.815940675 90.9750078636 34.0051307008 +23.8174851846 -74.8555151299 -61.8819784276 +23.8202488608 95.183862921 19.3035743749 +23.822609216 74.0654790716 62.8234677493 +23.826975119 -70.8822622256 66.3926212652 +23.8286195515 48.1078093929 84.3672659607 +23.8418065722 79.2176502188 56.179463803 +23.8532495641 -88.8354566296 39.2337116604 +23.8566102922 -36.3458599883 -90.0546534449 +23.8569476906 -71.1770264193 66.0657018202 +23.8601748846 -38.0363779126 -89.3528175816 +23.8657598128 78.798623369 56.7556381667 +23.8744537174 71.1468269383 66.0919017453 +23.8759459465 71.6067944497 65.5927297328 +23.891589561 72.3685778067 64.7455086819 +23.8917332576 -61.916873964 74.8029798903 +23.8920660194 71.6134847911 65.5795545685 +23.8937217756 -70.7128570157 66.5490940013 +23.9073800367 -32.9056856483 91.3545457643 +23.9178730771 -70.1378908014 67.1461958818 +23.924878421 93.3842131409 26.5892634084 +23.9271557367 -70.8118039664 66.4317667789 +23.9292545093 -96.5490948815 -10.2792536787 +23.9366308186 -90.7889648928 34.4151356056 +23.9438505451 -31.6250138031 91.796244602 +23.9529299282 87.1387486196 42.8146661421 +23.9600509836 94.3429264167 22.9200390922 +23.9638962173 -70.0726198973 67.1979137981 +23.9690581242 -71.0175445671 66.1966208828 +23.9692877441 -95.7794107141 -15.8675054211 +23.9745287196 -70.30403046 -66.9519624339 +23.9827477693 -70.9763271616 66.2358572986 +23.9877285043 -70.95023325 66.2620048216 +23.9904002444 -68.5825649934 68.7087510804 +23.9942724747 -75.73124046 -60.7375839723 +23.9959512219 -70.0864382299 67.1720589323 +23.9963651134 -68.9857004494 68.3018857343 +23.9999136535 -69.8989061564 67.3657707057 +24.0064210659 83.2812942977 49.8790313429 +24.0166659268 -69.8682821303 67.3915640857 +24.0197398728 -64.3464017955 72.6814465487 +24.0253895214 -46.4488396269 85.236646788 +24.025697915 -39.9380936169 -88.4743720969 +24.0261169234 -70.9006003497 66.3012109666 +24.0296631395 -39.8816261551 -88.4987637463 +24.0353942707 -67.7610833215 -69.5034920658 +24.037480411 -69.2987316786 67.9697382902 +24.0377601314 -70.3688209729 66.8611630377 +24.0452118493 87.4744625028 42.0719169633 +24.0505518953 -39.9952098884 -88.4418121677 +24.0538152399 -70.3756657453 66.8481835454 +24.0548645707 -69.9794080311 67.2625151337 +24.0695110889 -39.947761124 -88.4580975215 +24.0698547018 -69.5881428501 67.6618982095 +24.0710606957 -90.784449779 34.3331867922 +24.0723025039 94.6464282203 21.5076237017 +24.0745665815 -67.72142302 -69.5285848271 +24.0883791137 94.0223933344 24.0736275485 +24.0925756579 95.0733688302 19.5090322016 +24.0946673645 -96.9989619521 3.26318629583 +24.0985921862 -70.6678399777 66.5230354654 +24.1157724322 -78.3895434034 57.2145873446 +24.120667008 -68.9549651491 68.2891367963 +24.1252502981 -32.6868475724 91.3758299214 +24.1303099825 -90.8798424191 34.0379550213 +24.1412361636 -39.9405380156 -88.4418121677 +24.1505172221 42.599113226 87.1898392604 +24.1547869918 45.1999154014 85.8691674181 +24.1570517365 -95.8192755086 15.3330783737 +24.1597332859 78.5324403916 56.9996762596 +24.1718641501 -69.490232028 67.7261296414 +24.1779590143 -46.6041876497 85.1086129097 +24.1788716979 -39.8455473732 -88.4743720969 +24.1794571144 79.5839643858 55.5134800412 +24.2064291105 80.3275432337 54.4199833495 +24.2075862049 79.6765481244 55.3682259884 +24.2147566293 57.689165705 78.0102924084 +24.2154266922 -70.4065337755 66.7572701047 +24.2187520906 -69.8607066422 67.3270652459 +24.2229387987 -70.0703074395 67.1073859667 +24.2254067054 -68.7917709485 68.4165325029 +24.2309018813 47.6585929756 84.5075257572 +24.2487904627 -95.479840835 -17.1929100279 +24.2517781477 -67.6581639466 69.5285848271 +24.2525725041 49.222659314 83.5998955561 +24.2531602181 -46.7491416142 85.0076583478 +24.254232189 -39.7816348244 -88.4825053421 +24.266633072 91.8455197935 31.2334918512 +24.2697614596 36.919090116 89.7104200397 +24.2764031951 70.0270053387 67.1332612883 +24.2804924394 -69.025090341 68.161533069 +24.2844353461 -60.5620921701 75.7792794364 +24.2897703958 66.7355956863 70.4014724456 +24.2974041037 -70.9669100472 66.1311865324 +24.3002671511 -60.7550021283 75.619618703 +24.303586129 -71.268973813 -65.8032603517 +24.3077874485 -61.6142861798 74.9186973186 +24.3174218371 -69.7517173825 67.4044576967 +24.3408772493 -67.8321809412 69.3276057822 +24.3452275364 -90.3528115983 35.2658380374 +24.3486266813 -67.816542408 69.3401828276 +24.3551182196 79.2659902422 55.8903480703 +24.3568042319 -67.839318773 69.315026625 +24.3578668029 -88.0105510843 40.7533706906 +24.3674136337 -68.1304734047 69.0251240234 +24.3732601639 -69.4824562006 67.6618982095 +24.3773365616 -70.5967322147 66.4969688239 +24.3840883854 -70.937172212 66.1311865324 +24.3863473223 92.6258353841 28.736051985 +24.3893708128 -68.7971295092 68.3528606764 +24.3915909309 -70.958998304 66.1049986881 +24.3998144695 -37.5437219955 -89.4154236839 +24.4001425631 -87.9840716795 40.7852445573 +24.4012021989 -68.5265369472 68.6199319824 +24.4136707663 -39.7927065536 -88.4336654496 +24.4415853734 94.169508539 23.1238527491 +24.4484066157 -68.3569270731 68.7721305114 +24.450632503 -68.1006521537 69.0251240234 +24.4602509251 -69.9257507895 67.1720589323 +24.4632261081 30.4261169577 92.0641188263 +24.4676946378 -65.721420588 71.2883356168 +24.4730276915 31.9862451303 91.5311479119 +24.5107957746 -65.7319123709 71.2638518925 +24.5158824746 73.39794417 63.3380872628 +24.5222913416 -68.1132845043 68.9872285383 +24.5375608133 -61.4104383758 75.011106963 +24.5437493342 -94.7671587709 -20.4154350213 +24.5478122505 -70.0191859395 67.0426618959 +24.5504010491 61.0094949464 75.3333879147 +24.5560877846 -70.239055791 66.8092328522 +24.5589956049 -61.4018694101 75.011106963 +24.5600325299 -70.0149004716 67.0426618959 +24.5602889498 -94.7628736352 -20.4154350213 +24.5611825272 -94.7663213946 -20.3983490067 +24.5619907934 -96.5717632619 8.40256798546 +24.5751353236 88.3157237904 39.9549202878 +24.589473512 -95.2175412621 18.1377404435 +24.5900374616 -96.611447358 7.84590957278 +24.65804602 35.3859502943 90.2209248913 +24.6643606438 -94.1488310213 -22.9710019669 +24.6643645567 70.5092607043 66.4839324646 +24.664614113 -37.519738817 -89.3528175816 +24.677543395 -77.7934734499 -57.7857624384 +24.6779888155 -68.1721915057 68.8734286451 +24.6785809957 -93.2070461108 -26.5219568533 +24.6790159585 52.6123275895 81.3811351416 +24.6815938829 -60.3298514651 -75.8361915289 +24.7017838956 -68.1635731094 68.8734286451 +24.7043215672 -67.1443798145 69.8665066769 +24.7119393495 -68.0062666755 69.0251240234 +24.7225900661 -96.2881310153 10.8346373271 +24.7240593015 54.3776997138 80.1984205923 +24.7247370297 -70.8802541038 66.0657018202 +24.7278092131 -30.2114792134 92.0641188263 +24.7353086163 -67.7022273757 69.315026625 +24.7465116546 -72.4023284953 -64.3856582585 +24.7558023912 -66.8519038097 70.1282625266 +24.7748622998 -76.3852505772 -59.5944602483 +24.7749899106 50.0184448266 82.9720136676 +24.7785311445 91.2001455865 32.6888029655 +24.783059767 56.53780018 78.671958787 +24.7834148268 -70.651711081 66.2881442707 +24.7854825759 -94.6111778252 -20.842381918 +24.7872434586 94.6853075985 20.5008557553 +24.7960028652 -37.1519369757 -89.4700610308 +24.8006221241 71.8225666052 65.0111380342 +24.8049751546 81.6427866827 52.1456478554 +24.805674548 51.8430808165 81.8350382274 +24.8606430781 34.1174609395 90.6528945196 +24.8612174886 69.4346876405 67.5332808121 +24.8715040757 43.1134569008 86.7331431408 +24.8842836166 89.1254888771 37.9133177301 +24.8910755069 -70.7608686205 66.1311865324 +24.8913328932 78.230490396 57.1000168056 +24.8922651673 -70.2935883577 66.6272209433 +24.8952305236 44.0559780448 86.2513669207 +24.9180751352 -70.4446109866 66.4578536706 +24.9184970813 78.3158641992 56.9709918989 +24.9264382176 -96.5223658954 7.88070807377 +24.9303511964 -94.5580352009 -20.9106568088 +24.9340345233 -51.9714928941 -81.7144898335 +24.9455141029 -67.5088994959 69.4281629815 +24.9710943773 82.96986279 49.9244059975 +24.9760504573 90.2441902012 35.1024648492 +24.9775627093 -96.7901089059 2.79216387236 +24.9789222464 58.7610910648 76.9622480199 +24.986618188 88.7143884971 38.7998219728 +24.9920706873 -96.4288507053 8.76773371009 +24.9958212516 -62.8756024963 73.6333316555 +25.0018871835 -96.8145260762 -1.36131476707 +25.0047581533 70.105341082 66.7832555471 +25.0072308535 -65.3847168802 -71.4106238843 +25.0119534181 -67.8708155189 69.0503771677 +25.0124239531 -96.2307068764 10.6784690876 +25.0143770479 85.3765282769 45.6632167098 +25.033301335 -33.2203129046 90.9381363059 +25.0356186836 93.9587697773 23.3445363856 +25.0370651597 43.0525456 86.7157637662 +25.0558911719 -90.3486247741 34.7753981862 +25.0571406168 64.0040425491 72.6334787924 +25.0632454234 -88.7489721087 38.6710961637 +25.0634985197 48.6012567602 83.7241833838 +25.0706697212 -60.1692078569 75.8361915289 +25.0734130225 -95.4384269797 16.2120515372 +25.0738689109 -33.1897041723 90.9381363059 +25.0754414747 28.5226900696 92.5077206834 +25.0842176032 -63.0338553295 73.4677827999 +25.0965950457 -93.335887814 -25.6626764599 +25.0973056014 40.0395742401 88.1303452065 +25.1070442744 71.4146446509 65.342060399 +25.1078996573 -67.6938637451 69.189118986 +25.1210410291 -69.8528717286 67.0038029434 +25.1277709281 -33.1887346585 90.9236109047 +25.128948838 74.3684798386 61.950505541 +25.1471983706 55.1804906242 79.5156077043 +25.1498528311 75.1649869715 60.9730238396 +25.1631132526 41.7957916732 87.292207727 +25.1699097622 -96.7672340325 -1.60563391348 +25.1734709049 75.2355739535 60.8761429009 +25.1752410597 58.8232812707 76.8506917219 +25.1767568183 79.2232457298 55.5860436814 +25.1777302079 -69.8573159055 66.9778867692 +25.1791936527 69.632689455 67.2108381607 +25.1886988523 43.6281061887 86.3835505204 +25.2140049084 46.827488829 84.6843565628 +25.2173765949 -70.3133745579 66.4839324646 +25.2317155907 76.0709130864 59.8044873781 +25.233044139 8.69828733216 96.372367829 +25.2371979086 45.1196583869 85.5996511019 +25.2409055679 87.3347382138 41.6598150168 +25.2474264384 80.9109164457 53.0659123936 +25.266294756 91.6037977408 31.1505792684 +25.2760810011 77.0135183527 58.5665238866 +25.2813679772 83.577749177 48.7402531354 +25.2847023883 89.6527920872 36.3739013043 +25.2899439289 66.2972475866 70.4634209964 +25.3068203857 76.9711314826 58.6089563144 +25.3417097144 -96.5968519607 5.18130678911 +25.3478021692 76.0653059037 59.7625146976 +25.3724279284 84.570706621 46.9471562786 +25.3809123086 47.5741856367 84.2170181815 +25.3923999071 -9.35264885365 96.2691746426 +25.3926987274 -65.1289043626 71.5082978952 +25.3965098066 72.1172984525 64.4524053357 +25.4081642769 32.8743231032 90.9599036311 +25.4154971525 92.2703804866 28.9867105645 +25.423783556 94.0941270573 22.3590358248 +25.4324636501 77.2623713612 58.1697151818 +25.4471923123 -61.2232878818 74.8608671094 +25.4545369294 77.648724384 57.643231617 +25.4601389801 -96.7043817946 -0.209439357122 +25.4781373242 94.0996002729 22.2739701664 +25.4819433637 -23.9040418459 93.6977446145 +25.4856008818 51.8621103338 81.613759008 +25.4898421382 -67.5638771501 69.1765166238 +25.4917654115 -96.6874165602 1.30895955713 +25.5028194092 94.0605926887 22.4100670509 +25.5052675409 62.2811348731 73.9631094979 +25.5135925267 92.7529629904 27.3119836863 +25.5144736211 38.1130656616 88.8617232655 +25.5233074324 87.2829044688 41.596338363 +25.53392861 49.2599419046 83.195412213 +25.552369468 -96.3712331596 7.72410731868 +25.562613105 77.2942014871 58.0702955711 +25.5689671595 -70.1739343034 66.4969688239 +25.5851892074 -70.1803734478 66.4839324646 +25.5880762616 -63.3964155788 72.9804415237 +25.6039992076 -70.653199755 65.9739387103 +25.6061371731 50.9564408291 82.1447921484 +25.6096852199 -70.1714382565 66.4839324646 +25.6120956274 -58.7075403458 76.7948257639 +25.6182938723 -67.0876800498 69.5912796592 +25.6238664613 -90.2521318062 34.6117057077 +25.6250374995 78.7721851437 56.0205346355 +25.6281016489 -70.6811952854 65.93458151 +25.6284732888 80.5472347378 53.435234939 +25.6302082187 67.4719993428 69.214317387 +25.6303972835 -50.7836022973 82.2442002381 +25.6306488368 -94.9914076056 -17.8802215116 +25.6312891467 -67.1217113095 69.5536691165 +25.6367272511 -66.1639215687 70.4634209964 +25.6369485917 -95.8121612033 -12.7583945876 +25.6452013498 -63.6339246485 72.7533317557 +25.6521367318 -76.8890769936 -58.5665238866 +25.6592570042 92.7127719201 27.3119836863 +25.661129616 48.4041368165 83.6573126862 +25.6632742466 -62.9801772053 73.3136660803 +25.672659363 52.4507520639 81.1777874123 +25.6788622139 -33.525882104 90.6455253421 +25.7045111294 -63.2392414113 73.0758267372 +25.7089298069 -67.0790102871 69.5662080833 +25.7116184799 -58.7956178623 76.694119692 +25.7199054016 87.7845659156 40.4024312775 +25.742667611 -65.9245152132 70.6489444944 +25.7489590087 -58.5744167007 76.8506917219 +25.7553256773 68.4121491004 68.2381202461 +25.7623646029 73.979433955 62.1558036049 +25.7694037682 -58.5654250501 76.8506917219 +25.7753656824 40.42807096 87.7564903719 +25.7807022454 -94.7580060628 18.8752663223 +25.7866414374 73.7175701251 62.4561364338 +25.7917575324 73.9806791298 62.1421303053 +25.8139262266 60.8137991722 75.0687887408 +25.8382578242 78.9589043479 55.6585649903 +25.8391319457 76.119628112 59.4822786751 +25.8432568727 -95.2503836876 16.108708253 +25.8544346531 39.5549044058 88.1303452065 +25.8604937019 34.9484514452 90.0546534449 +25.8663259694 -73.8626323154 62.2514636638 +25.8731620554 93.4856598576 24.3107154615 +25.9137117482 -47.6874160462 83.9904154905 +25.91802372 -67.0635566989 69.5034920658 +25.9180909798 69.2105880426 67.3657707057 +25.9274090917 27.4846513463 92.587058481 +25.939048174 -53.4193613328 80.4582973635 +25.9399868453 -60.0875828869 75.6081970773 +25.9513142783 -53.4446223775 80.437563527 +25.9582151545 81.4359706634 51.9071647088 +25.9759718625 -96.1377912726 9.09802039036 +25.9796060146 93.3629735406 24.6660747381 +25.9881397402 43.5955099937 86.1629160442 +25.9937498378 -91.1310218316 31.9290123445 +25.9979341523 -67.3052601296 -69.2395073545 +26.0017316017 46.0891972639 84.8510214982 +26.0059756918 90.2180008068 34.4151356056 +26.0313543336 92.1770465348 28.736051985 +26.0506061734 -67.3367041957 69.189118986 +26.0624806169 55.0609676906 79.3034484816 +26.0703906476 48.7640338603 83.3210881659 +26.0805852682 77.6313288962 57.3862339406 +26.0916107802 67.6179898199 68.8987322062 +26.1205777242 -94.5079457435 -19.6459565994 +26.1256093086 59.0949617899 76.3232469783 +26.125947509 -71.9758212085 -64.3188621489 +26.1457997333 -96.2325300174 7.46306389888 +26.1491117226 -48.5235857403 83.4367160369 +26.1519396749 81.8462071263 51.1593044351 +26.1571979926 -95.7459117903 12.1869343405 +26.1807990826 85.7405677495 44.3071190824 +26.1861106078 73.1349706187 62.9727217439 +26.1897795655 78.6377229769 55.9482258102 +26.1900441983 -64.1767442374 72.0793110676 +26.2002630229 -71.9846310393 64.2787609687 +26.2004606793 -96.4337157213 3.7515773182 +26.2051023895 91.6899649514 30.1038691196 +26.2168275906 -64.2744395211 71.982458803 +26.2425491382 -89.6263708173 35.7553110579 +26.2480857984 90.2289322086 34.2020143326 +26.2482516217 -78.9972119662 -55.4118199338 +26.2509496609 -96.4199839739 3.7515773182 +26.2525166291 -38.9209564796 88.2947592859 +26.2543016282 91.0794747155 31.8628456287 +26.2634630608 81.801109567 51.1743000114 +26.2637560561 72.0807798197 64.1449631569 +26.2692823708 -96.487320189 -0.349065141522 +26.2693762478 -95.3703689913 -14.6428340844 +26.2881011107 35.918135299 89.5478827032 +26.2894737968 -89.6126179656 35.7553110579 +26.2940125234 35.9525376947 89.5323401835 +26.3137562332 -66.3594261948 70.0286569056 +26.3375154101 36.8829702608 89.1402366318 +26.3480755639 38.0514535055 88.6446038978 +26.3504830993 -95.9919413835 9.54982878676 +26.3596350759 86.6510194477 42.3883293765 +26.373280741 91.0740046784 31.7801153992 +26.3810552671 -77.5826006274 -57.3147450739 +26.3843235066 43.4800194703 86.1008442465 +26.421893495 -79.566213511 -54.507808722 +26.4224649378 -70.6700926451 65.6322432357 +26.4244936316 70.3012260005 66.02638684 +26.4407651146 93.0058262178 25.5108257352 +26.4504797808 -93.0399977159 -25.3757944585 +26.4527989464 -66.5405491072 69.8040453872 +26.4534880936 71.6283095074 64.5724263505 +26.4571467875 70.3135646 66.0001667961 +26.4643489754 27.2614456611 -92.5010908789 +26.4704552228 40.2514723383 87.6306680044 +26.4718943485 45.3921069175 85.0811109424 +26.4761190552 49.9414370411 82.4916237326 +26.4810039403 72.5588821969 63.5135028529 +26.4834955151 -93.715538386 -22.7161248969 +26.4853043342 -79.5250689294 -54.5370705676 +26.4886107956 -61.4468158799 74.3144825477 +26.4955967521 24.9681872991 93.1373876365 +26.4983935029 49.3572228008 82.8353770991 +26.5004424526 61.6814503803 74.1156206801 +26.5063454565 -66.5061209796 69.8165418993 +26.5284367068 46.0785176028 84.6936376679 +26.5346849687 78.982999606 55.2955356864 +26.5372952578 48.0127925133 83.609471446 +26.5781372497 29.2294819423 91.8653362576 +26.5881900441 -66.6438246997 69.6539214946 +26.5906296815 75.1730040801 60.3486360302 +26.6034818714 44.1359216364 85.6987466281 +26.6035448798 53.6394987153 80.0940420843 +26.6105447229 -94.4801007041 19.1151636272 +26.6124671194 70.3164813889 65.93458151 +26.617861036 -91.2032285746 31.2003296688 +26.6275485713 88.5856956334 37.9940546168 +26.6369780862 -66.361947427 69.9039579147 +26.6497351373 -79.7401539269 -54.141476419 +26.6641780525 46.5959874142 84.3672659607 +26.664198808 88.5954329065 37.9456159529 +26.6647985593 69.9014104937 66.3534575496 +26.6664748487 -94.4260087873 19.3035743749 +26.6672679201 -71.2111588649 64.944804833 +26.6719554799 51.7424227759 81.3100761047 +26.6815093956 53.6319846002 80.0731370949 +26.6884556091 52.7654938353 80.6444604267 +26.688928438 -64.4327730002 -71.6667207449 +26.6915881896 68.8150225958 67.4688949446 +26.6988434874 87.4918013491 40.4024312775 +26.7072766632 -79.450798027 -54.5370705676 +26.7106074661 74.2729027416 61.4009720373 +26.7184105842 79.9456415491 53.8035401546 +26.7255378565 41.3588594104 87.035569594 +26.7257197056 -59.1909079253 76.04059656 +26.7308755524 56.3712498008 78.1520472419 +26.7465373052 47.8965450393 83.609471446 +26.7513773763 91.3050811794 30.785482931 +26.7632547236 47.8872058187 83.609471446 +26.7745579627 33.1465454041 90.4678372333 +26.7812933422 78.3556092738 56.0638994563 +26.7877724336 -19.5841546472 94.3338546589 +26.7929726395 47.9207383496 83.5807361368 +26.8051504488 -77.8478095113 -56.7556381667 +26.8090905498 -66.7907392451 69.4281629815 +26.8265285615 67.6525626508 68.5818352927 +26.832508494 40.9263769312 87.2069272432 +26.8336108957 47.6803439369 83.7050902177 +26.8347447233 -4.61105247442 -96.2217993529 +26.8401725959 -69.9210401242 66.2620048216 +26.8547272847 92.5551560067 26.690198932 +26.8584124479 58.2069517279 76.750090888 +26.8584738109 -68.5347474002 67.6875969683 +26.8634714813 -61.2838607109 74.3144825477 +26.8676670546 92.5997530867 26.5219568533 +26.8738841918 -61.3076153141 74.2911209563 +26.8873593755 48.1684707213 83.4078433613 +26.9079579414 -90.1460040444 33.9066328947 +26.9271288071 92.5631719725 26.5892634084 +26.9545529301 84.8174046298 45.6010959102 +26.9740747706 -34.2164507275 90.0090761528 +26.9866319551 -34.1464902197 90.0318771402 +26.989524152 63.8309840001 72.091407724 +26.9944899257 86.2450107356 42.8146661421 +27.0041287722 -88.4369237623 38.0747625693 +27.0080931858 86.8197323332 41.628079226 +27.0124275477 44.6907889079 85.282249881 +27.0168706629 67.6154359258 68.5437198009 +27.027153365 26.2185884701 92.6397247385 +27.0367276873 -29.7859999941 91.5522231315 +27.0832400673 -88.41967711 38.0586232965 +27.0969904896 90.7215181922 32.1769986684 +27.1004040923 90.9064980652 31.6476967182 +27.1058000785 88.2732123758 38.3811878264 +27.1084644173 94.4140539664 18.7381314586 +27.1096717968 92.2891432594 27.345561459 +27.1374721832 50.0434747143 82.2144041031 +27.1428645257 -65.9188266002 70.1282625266 +27.1435667725 49.1704863843 82.7374767055 +27.1578588913 46.1048954397 84.4795201036 +27.1595433763 88.8348635692 37.0233199244 +27.1636711641 50.0292587079 82.2144041031 +27.1657641548 73.3598945207 62.2924323959 +27.1658505076 31.8972010248 90.7996978683 +27.169098339 35.9239874738 89.2821775016 +27.2019818678 77.9819572845 56.3814377303 +27.2053498915 90.5652847891 32.5238086383 +27.2201440499 -95.8745251145 8.193850863 +27.2295825501 59.8328669877 75.3563392302 +27.2393973094 -64.9585896405 70.9816657042 +27.239937506 82.7533736565 49.0903753615 +27.2456256533 -59.318031214 75.7564984384 +27.2480991032 41.1986258377 86.9494929505 +27.2489772937 -64.9814353101 70.9570736537 +27.2495358014 73.1545304931 62.4970196645 +27.2505043489 -78.1210603124 -56.1650242447 +27.2522250954 -94.9147473372 15.7641036938 +27.2637177595 75.2331259389 59.9722140278 +27.2653669669 74.0253496599 61.4560604976 +27.2739925958 -70.0625455503 -65.93458151 +27.2816444778 37.826932964 88.4580975215 +27.2960107408 87.7452669457 39.4423113706 +27.3673261775 -78.0178371571 -56.2516359159 +27.3900344804 49.9874894835 82.1646937942 +27.4049047893 47.3711706571 83.6955398099 +27.4113854029 -65.7545609835 70.1780140797 +27.4288521483 64.8384561224 71.0185375623 +27.4353852527 91.6211680779 29.2037873584 +27.4414083442 50.1227578074 82.0650854984 +27.4438996215 -61.4091061299 -73.9983382104 +27.4442399374 -94.3407638882 -18.6181084768 +27.4665823684 87.8070609452 39.1855445435 +27.4734691603 89.4705697993 35.2168373381 +27.4767001633 73.5680485497 61.909394931 +27.486239491 -65.6435985123 70.2525772694 +27.4892047456 -78.849610511 -55.0189289674 +27.4895229379 91.918708869 28.20065759 +27.5142616049 70.4977103284 65.3684805299 +27.5150784525 49.4754720695 82.4323851484 +27.5229283372 89.0772985607 36.1624570082 +27.5239559408 81.9276582253 50.301994663 +27.5418031473 -92.2107640048 -27.1776393577 +27.5428545372 77.7786218337 56.4967003425 +27.5474899717 -63.8112153591 71.8975979477 +27.5515598932 -34.6991692817 89.6486430383 +27.563991673 43.7370105778 85.5996511019 +27.5650991314 74.1995843821 61.1112672705 +27.5662671997 -78.628904646 -55.2955356864 +27.5674926961 -78.7204019339 -55.1645870628 +27.5736826292 77.7362994369 56.5398954378 +27.5742821601 74.4231889546 60.8345946742 +27.5753131783 71.2039595691 64.5724263505 +27.5958134241 43.4337593661 85.7436856497 +27.6045850768 28.4857220324 91.796244602 +27.6057075651 73.1722316858 62.3197353969 +27.6101001642 -25.1496970101 92.7640830776 +27.610885993 -78.7561734858 -55.0917789925 +27.6206972012 22.8335927689 -93.3580426497 +27.6280727997 -63.8447092598 71.83691734 +27.6299584623 73.3139893641 62.1421303053 +27.6344474928 89.5490413106 34.8899199214 +27.6483180898 48.4726616854 82.9817544761 +27.6638378656 68.8854299955 67.0038029434 +27.6673230907 42.2801013983 86.2954938496 +27.6674132834 -65.1803410399 70.6118784917 +27.6755066008 91.0908181792 30.6027642189 +27.6789858771 -61.4450701907 73.8808303288 +27.679587558 -82.1059931943 -49.9244059975 +27.6849420226 46.8686717378 83.8860631735 +27.6899663371 -95.3094892794 12.221579994 +27.6962778188 42.405068627 86.2248592329 +27.6964997788 52.2434197051 80.6444604267 +27.6968254027 -76.9308920703 -57.5719003324 +27.7006097232 45.4700635401 84.6472063486 +27.7073268304 -95.6808232604 -8.80250533245 +27.7310099246 -63.8683864086 71.7761820252 +27.7314187347 70.4003078147 65.3816876087 +27.7434956821 30.4576510158 91.1187683298 +27.7439616521 -70.4321498654 65.342060399 +27.7507274282 66.7324879481 69.1134732122 +27.7623571499 -55.1513348688 78.6611834876 +27.7662271946 47.1941888858 83.6764313459 +27.7747013911 -55.1758573319 78.6396257006 +27.7757981552 -81.497609884 -50.8590662521 +27.7759602377 80.3028316027 52.7252431902 +27.7788594352 -12.5601503455 95.2395799643 +27.7821261501 -65.2921110707 70.4634209964 +27.7831016613 -78.6751857011 -55.1209072583 +27.787902304 -48.9752444427 82.6393242792 +27.7885570248 -57.5602856685 76.9064991547 +27.7904757886 73.6230720857 61.7035875141 +27.7986027665 57.5554347737 76.9064991547 +27.8097405938 -58.1736317439 76.4359005823 +27.824827757 -78.0119139121 -56.0349912828 +27.8348972512 -93.0735619752 -23.717726625 +27.8389341925 77.410386654 56.8561850734 +27.8443490387 -9.60388899718 -95.5638924633 +27.8478910308 -57.6061294221 76.8506917219 +27.8607451238 90.2823556246 32.7547728433 +27.8624693431 -63.8658025838 71.7275544155 +27.8630462796 -57.5093489309 76.9176536145 +27.8830837076 86.8456372319 40.9923033842 +27.8831662959 -91.7743067165 -28.284371374 +27.8847205356 51.6147670382 80.9836908534 +27.892257913 90.2726248898 32.7547728433 +27.9003499274 53.8252314218 79.526190254 +27.9107177406 90.5564661888 31.9455515932 +27.9135495533 -76.6918470944 57.7857624384 +27.9180938611 89.7450041955 34.1528074559 +27.9181017869 -60.7821179922 74.3378350842 +27.9275578281 -61.9391344234 -73.3729864503 +27.9314990612 -82.0482394234 -49.8790313429 +27.9449562652 90.3872473373 32.3917418198 +27.9468773357 74.2727317005 60.8484459368 +27.9540010642 79.0712149893 54.4639035015 +27.9635024035 79.0980906569 54.4199833495 +27.9653211759 50.9740494814 81.3608449501 +27.973512154 -58.1246649811 76.4133884775 +27.9745889199 72.4225614713 63.026938405 +27.9804347275 26.9261739819 92.1524629468 +27.9916960038 -65.3095199479 70.3642775775 +28.0296329769 50.0915173894 81.8851608095 +28.0329877247 69.4888116224 66.2227805105 +28.0395814453 -34.8492884169 89.438856037 +28.0678124822 75.0707745525 59.8044873781 +28.0847791401 71.7745104778 63.715499106 +28.0916612369 46.8820211838 83.7432663483 +28.098184341 38.2230712478 88.0311811867 +28.1111586399 -65.5250688231 70.1158192968 +28.1126226013 69.5811826155 66.0919017453 +28.1152566607 -55.4181982907 -78.3476588107 +28.1260016492 -95.687260765 7.2715994473 +28.158874233 -49.2279169307 82.3631592194 +28.1590302399 44.6811847163 84.915609568 +28.1674656964 -49.2230015302 82.3631592194 +28.1717332703 -55.005039303 78.6180583316 +28.1732485214 67.7485291972 67.9441304262 +28.1782139952 71.9762735535 63.4460739636 +28.2178571887 -64.7420670281 70.7970147154 +28.2214743066 59.4878693782 75.2644789048 +28.2390006659 27.9253166812 91.7754625684 +28.2439442864 -69.1406736182 66.4969688239 +28.2440957391 -78.7960226423 -54.7125019684 +28.2464355672 -95.6648531174 7.09751757832 +28.2637823711 72.9438926318 62.2924323959 +28.2751887615 95.6392982268 7.32381971276 +28.2772404351 48.1588658263 82.9525244685 +28.2786813737 -60.6438279088 74.3144825477 +28.2812666251 -88.4569845673 37.0881630624 +28.2891079443 78.0626486618 55.7310439129 +28.3039007743 -62.021163824 73.1591719395 +28.314011439 65.9026465225 69.6789633789 +28.3178050903 -94.8088412494 14.470160186 +28.3255485198 -62.0112801205 73.1591719395 +28.3263467458 95.6281439824 7.2715994473 +28.3359909418 -59.141775377 75.4938542041 +28.336157243 -62.0345051079 73.1353701619 +28.343434828 -94.1749233389 18.10341173 +28.362378643 -6.74641032191 -95.6559534241 +28.3799876379 55.8192297635 77.9665947075 +28.3842409577 29.6195023341 91.1976970473 +28.3862467308 95.8303629428 3.28063024361 +28.3893768369 -59.4661373166 75.2184937064 +28.3932719518 88.4346875549 37.055743751 +28.4044252422 -76.2956709057 -58.0702955711 +28.4135614282 45.8621211672 84.1981910079 +28.4138041856 -57.239237365 76.9176536145 +28.4210666507 34.5388766642 89.438856037 +28.4241397508 88.4247710457 37.055743751 +28.4299145739 74.3726778908 60.5016094056 +28.4388018311 37.0621681195 88.417363932 +28.4569082344 73.6329860434 61.3871952452 +28.472315922 -63.0591897514 72.2001787667 +28.482421048 49.1743082072 82.2838933425 +28.4970125636 77.2445325653 56.7556381667 +28.5138549006 -90.5997777335 31.2832279878 +28.5163935749 -92.5789865528 -24.8182704141 +28.5198946782 -20.6601364865 93.5936662809 +28.5255654219 78.8870313303 54.4346250585 +28.5389353798 15.3216874236 94.6085358828 +28.5601359953 -79.0257636526 -54.2148255651 +28.5686438858 -60.7940629316 74.0804596287 +28.5919144394 73.6381054123 61.3182832438 +28.6002838892 16.5656693002 94.3800951583 +28.6044193549 78.4621452792 55.0043539327 +28.6290881001 -79.0008101446 -54.2148255651 +28.6383869002 78.4701873871 54.9751988372 +28.65169603 35.2559040611 89.0847997329 +28.6540695163 15.9028288975 94.4777451743 +28.6815483172 -94.9978712162 12.360147674 +28.6830976438 94.7042384579 14.4356201001 +28.6892140356 72.166127269 62.9998339126 +28.7003782314 73.423276689 61.5248789485 +28.7078386618 41.0295174307 86.5588741769 +28.7087408309 81.6593344246 50.0755559253 +28.719688732 -65.5807132955 69.8165418993 +28.7340184667 -64.1755935548 71.1044961634 +28.7361319224 31.525285419 90.4455145454 +28.7362205163 50.379957677 81.4621967227 +28.7416070466 23.0016714017 92.9776485888 +28.7474002435 15.1760263649 94.5688913069 +28.7537959634 95.0572591276 11.7190744019 +28.7579217802 -95.5521127017 -6.54031292301 +28.758405202 85.3553004413 43.4445257404 +28.7585779802 -95.5542930156 -6.5054806779 +28.7595654117 -59.8113835056 74.8029798903 +28.7616252344 -93.6656009135 19.988099444 +28.7658460674 17.352667753 94.1881681629 +28.7806734488 21.948822102 93.219751363 +28.7876506792 23.0220396443 92.958360888 +28.7888421342 -90.3161981482 31.8463015219 +28.7956456335 -60.3713265346 74.3378350842 +28.7968917488 24.0097004429 92.7053035713 +28.8010515138 16.4478221767 94.3396447807 +28.8025876833 -89.6020862463 33.7916718003 +28.8087106974 20.9845767371 93.4328942457 +28.8091434674 17.3445150997 94.1764357397 +28.8139554944 55.8260160571 77.8023900658 +28.8186763561 -90.3008469591 31.8628456287 +28.8198724812 49.2600722042 82.1149209134 +28.8203666801 -90.3061434444 31.8463015219 +28.8425261337 43.0844511514 85.5092904614 +28.8431209285 23.7764340619 92.7510407403 +28.8468085596 -90.2801818011 31.8959309298 +28.8488054382 74.8412001703 59.7205256328 +28.8506833464 47.1723895652 83.3210881659 +28.8562779296 70.8161195654 64.4390598453 +28.8705000775 72.6590804726 62.3470308046 +28.8739403093 86.7982667908 40.4024312775 +28.8803861396 -78.9193642701 -54.200159037 +28.8946024316 40.2852336229 86.845851382 +28.9011725704 57.966784381 76.1877557918 +28.9125461962 12.9513789306 -94.8489665534 +28.917341745 -82.8995078261 -47.8691857941 +28.9405270785 -93.0889783779 -22.2909846572 +28.9457599758 81.649715898 49.9546481641 +28.9463376254 -62.075621361 72.8610099486 +28.9692823304 -72.1725259069 -62.8641963719 +28.9756405767 76.4798959625 57.5433555394 +28.9845472764 95.6995478991 -1.22170008352 +28.9846691255 95.6999502135 -1.18679602985 +28.9989054774 20.8608600416 93.4017558691 +28.9994083546 76.6637645046 57.2861373028 +29.0000120895 -61.6281627131 73.2186373775 +29.0236870848 35.7136389514 88.7815385136 +29.025630092 51.8714553162 80.4168198895 +29.0261066168 18.9435448841 93.8009980858 +29.0336926143 82.8145294955 47.9457860256 +29.0459368065 20.4289770312 93.4825676396 +29.0649685273 18.1829755518 93.9393794135 +29.0663052961 26.7091186295 91.8791210149 +29.075094878 25.5700807166 92.199836388 +29.1007013789 14.3382515278 94.5915626384 +29.105772098 56.6337074155 77.1069206683 +29.1134439547 87.5182413106 38.6389029217 +29.1137610342 47.8272935212 82.8549269077 +29.1140521028 30.8950816131 90.5420670312 +29.1301214251 93.6988202093 19.2864490548 +29.1517937304 84.2804915766 45.2434709312 +29.1546463457 76.2286839443 57.7857624384 +29.1742591233 88.6297322031 35.9671123975 +29.1835580068 27.4531500709 91.6222925562 +29.2072273185 -65.9098546501 69.3024453563 +29.2081230804 53.0635463827 79.5684962244 +29.2082091064 19.8498784111 93.5567359834 +29.2139334527 76.1843742442 57.8142474935 +29.2150332913 -64.7041263857 -70.4262583022 +29.2208531098 77.0054007205 56.7125206934 +29.2371805922 14.2472944576 94.5632162717 +29.2434851284 61.7813251735 72.9923724601 +29.2454265248 -65.0133203458 70.1282625266 +29.2498423876 -65.9438661302 69.2520991747 +29.2685152417 50.9406478851 80.9222120842 +29.2695228697 95.6169085929 0.837748241477 +29.2807642255 -83.9413582504 -45.7873915117 +29.283970198 -84.0921077161 -45.5078730475 +29.2979548068 28.5109211132 91.2620250784 +29.3112158644 46.5094088517 83.5327930385 +29.3281402039 -49.159389503 81.9952109325 +29.328167267 49.0426380499 82.0650854984 +29.3283670305 -63.3852190701 71.5692733704 +29.3482397699 53.6501074667 79.1223532967 +29.3514736815 -35.5050637529 88.7574303404 +29.3662348875 -63.4089729341 71.5326946227 +29.3754178335 71.3761591604 63.580883374 +29.3826939845 45.1245903267 84.264041216 +29.3832680628 33.6826725679 89.4544639838 +29.3844631339 -62.3603884371 72.4412539946 +29.3858485231 44.062221051 84.8233021205 +29.3860348506 64.7210929786 70.3394702811 +29.3869540704 46.7199238871 83.3885822067 +29.3921500069 -52.0351773414 80.1775644244 +29.3946096312 -53.7348739829 79.0475821431 +29.3999078865 64.5122099716 70.5253158862 +29.4160147083 75.254067023 58.9196357353 +29.4208620151 76.8443360429 56.8274660389 +29.4218938882 46.0588482417 83.7432663483 +29.4450967486 52.4062306501 79.9160388565 +29.463066267 68.4782621507 66.6532470249 +29.4872503075 -51.9491617238 80.1984205923 +29.5027981547 41.0574881644 86.2778509623 +29.5066035527 34.7069441445 89.0212804611 +29.5149632402 -90.9457234189 -29.2872384621 +29.5203343971 44.0969490469 84.7585331506 +29.5237408085 -94.6153039223 -13.2775371347 +29.5244306441 -94.6175146516 -13.2602381688 +29.529987877 77.8610259814 55.3682259884 +29.5324999605 76.8545963646 56.7556381667 +29.5357253373 44.08664182 84.7585331506 +29.5373961876 72.7418349386 61.9368038909 +29.5504318405 77.8739360139 55.3391549243 +29.5634626422 15.8517895862 94.2057452787 +29.5648858523 16.9662494028 94.010977581 +29.5700282027 -90.2029754581 31.4489530921 +29.5778303144 50.2532962 81.2388957023 +29.5820586432 93.6512929121 18.8238450464 +29.5913286046 13.1749083312 94.6085358828 +29.6059710114 -89.2588234658 34.0051307008 +29.6075548391 77.3319589445 56.0638994563 +29.6236583645 73.8028034794 60.6266035968 +29.624098371 -95.4051882378 -4.50142788612 +29.6243757768 -63.3852053749 71.4472679633 +29.6392065453 38.1143917658 87.5717453046 +29.6441373409 82.792864733 47.6084726767 +29.6441946112 -62.6561620424 72.0793110676 +29.6549532504 -62.6789015721 72.055111168 +29.6806407402 71.5494205192 63.2434975995 +29.6835229138 44.0407855943 84.7307362866 +29.6859082165 30.34602035 90.5420670312 +29.7373057672 -78.8222878248 -53.8770785007 +29.7393602279 19.1657098165 93.5320587845 +29.7431424415 -84.5544257051 -44.3384096623 +29.7496157133 -77.6218533196 -55.5860436814 +29.7500514041 -94.47008053 13.7963156715 +29.7547526292 18.7158170677 93.6182294613 +29.7795814479 -83.7232488052 -45.8649554484 +29.7875138395 -22.0416007631 92.8809552872 +29.7922539544 19.6816958438 93.4079892355 +29.7923604125 16.2230916651 94.0703277228 +29.7945394846 41.9559982376 85.7436856497 +29.8240835048 -95.3436828369 4.48399221677 +29.8264363977 46.4059840713 83.4078433613 +29.8608023342 39.1553586296 87.035569594 +29.862544549 31.0101028345 90.258528435 +29.8688509321 -61.2402198096 73.1948578909 +29.8712256484 -94.4519380976 13.6580111242 +29.8738431656 78.4371830895 54.3613999406 +29.8831097288 46.3695095807 83.4078433613 +29.8855588268 18.0993377717 93.6977446145 +29.8864945923 74.0833268709 60.153621011 +29.8975730263 -83.6386468629 -45.942484457 +29.9046006683 78.4356145448 54.3467499475 +29.9066561337 51.3847800275 80.4064443961 +29.9093807344 55.478139017 77.6376521753 +29.9150590697 24.8095123577 92.1389024106 +29.9251088793 36.7310585244 88.0642787868 +29.9276111712 -69.1586289031 65.7375245794 +29.932780932 88.0276761183 36.8124552685 +29.9394231359 78.8160876773 53.7741133403 +29.9456941927 47.7375269325 82.6098294496 +29.9497700887 79.9766156077 52.0264569962 +29.953334897 -64.8249560901 70.0037341608 +29.9550580389 33.1751921058 89.4544639838 +29.9607939314 36.8010854206 88.0229000821 +29.9801909182 36.8249108963 88.0063298291 +29.983535896 -64.0662019586 70.6859911282 +29.9898160356 -53.9253525372 -78.6935021961 +29.9919014242 94.5464526113 -12.7064608601 +30.0055882923 16.9210821981 93.8793994893 +30.0086377072 -53.9148808314 -78.6935021961 +30.0331633745 17.2698348985 93.8070461122 +30.0416122619 19.598826931 93.345527561 +30.0533854407 81.3320971802 49.8185105339 +30.0713395691 -88.0819449743 36.5689144775 +30.0738485643 -92.4479726959 -23.4293827692 +30.0791896233 19.5709943696 93.3392657513 +30.0875559093 70.8131042426 63.8767817516 +30.0929543207 18.6366152712 93.5258823614 +30.1380349485 -94.2645082933 14.3492621991 +30.1402695583 -66.0451225745 68.7721305114 +30.1633826896 52.9894327283 79.2609005996 +30.1812976227 70.9305193559 63.70204626 +30.1837679579 -49.1590868829 81.6842967082 +30.1838189835 50.6338274035 80.7784166349 +30.1862272331 73.7115376892 60.4599114862 +30.1906048351 74.724369124 59.2013178799 +30.2123311372 19.6351143482 93.2827815397 +30.2389146081 -62.7477236471 71.7518725918 +30.2414019304 -56.4472799595 76.8060036355 +30.256821807 22.8996616609 92.5209718386 +30.2581248941 -89.6513213848 32.358715238 +30.259813183 78.0953000167 54.6394346734 +30.2611039053 -56.4367202801 76.8060036355 +30.2638851737 26.0126736551 91.6920828835 +30.2731928374 14.2583926198 94.234983076 +30.2820351372 -29.0698796403 90.7631006833 +30.2866963234 -94.3320139709 13.5715572434 +30.2987712354 13.2876183807 94.3685522798 +30.301232985 -78.3239034325 -54.2881334243 +30.3069134574 -49.1669937465 81.6339250717 +30.308965676 -76.5517089028 -56.7556381667 +30.3161742506 13.2889421938 94.3627765286 +30.3371124879 -62.8392780382 71.6301943425 +30.3414508869 43.9496072672 84.5448305879 +30.3471965451 -89.6569300446 32.2596118519 +30.3725243767 -91.0378495838 -28.1001727065 +30.3835198284 -63.2735372821 71.2271100259 +30.3836842062 -35.7892053097 88.2947592859 +30.3979765717 -61.8585852533 72.4532846102 +30.4036291639 -35.8126986485 88.278366258 +30.4087870994 17.6983367203 93.6059535739 +30.4118977364 48.6314276928 81.9152044289 +30.414036972 -78.330958401 -54.2148255651 +30.4175401951 -90.2796335123 -30.4033060925 +30.4263090948 -12.6964140846 94.4089020393 +30.4267664309 -63.7337790497 70.7970147154 +30.4524316577 -64.861572428 69.7540380788 +30.4575594031 87.3639931846 37.9456159529 +30.461925566 19.5787397602 93.2134327241 +30.4648063289 -90.2636945509 -30.4033060925 +30.4907907771 19.9526143935 93.1246737264 +30.4958711296 -66.2114373933 -68.4547105929 +30.499707911 -90.2631036214 -30.3700500819 +30.5029969302 49.9131444966 81.1063818989 +30.5164684847 -94.3119380596 13.1910382711 +30.5172933989 42.5946839425 85.1726934143 +30.5317127148 47.1587390829 82.7276727994 +30.5542386412 35.2976672913 88.4336654496 +30.5631301281 -61.6500566499 -72.561460789 +30.5683958872 43.1413545127 84.8787176134 +30.5745104056 88.3936951028 35.3801353804 +30.5764958372 73.5276451846 60.4877119416 +30.5839475599 -54.4554049649 -78.0975737252 +30.6029595395 71.8518607218 62.4561364338 +30.6049002175 -93.9132587979 15.6089687246 +30.6176459963 -62.0318483189 72.2122534463 +30.6378490417 63.0401473183 71.3250449154 +30.6596852363 77.5165693332 55.2373531229 +30.6705859505 44.5093870535 84.1322151234 +30.6724507301 51.2093562444 80.2296865209 +30.6747211422 21.5026156817 92.7183854567 +30.6973845239 77.5327429274 55.1936985312 +30.7036560579 56.5020570883 76.582002125 +30.7037999449 -86.4649839632 -39.7628371371 +30.7059634717 73.4049684878 60.5710690725 +30.7093721872 76.3919629029 56.7556381667 +30.7136957248 52.5601909187 79.3353340291 +30.7350013908 46.5766906679 82.9817544761 +30.7352831721 23.2027768657 92.2874504689 +30.7514601937 -61.8670571088 72.296714591 +30.7600243656 45.8275600331 83.3885822067 +30.770853215 -53.4042543252 -78.7473187632 +30.771249429 -89.8754649243 31.2334918512 +30.7766672833 15.291063003 93.9094252095 +30.7808919731 38.7662762238 86.8890816908 +30.7859718936 -65.0400638634 69.4407231184 +30.7943794141 42.4315301923 85.1543976671 +30.8036047208 58.1778854551 75.2759694735 +30.8085836312 -91.6516718066 -25.5108257352 +30.8175759771 -93.3476669362 18.3436661675 +30.8183018041 -77.9175979831 -54.5809508754 +30.8310238624 15.7295308129 93.8191335922 +30.8359253717 20.2554170084 92.9454882621 +30.8364362601 45.0354793161 83.7909291125 +30.851793757 -53.4368742918 -78.6935021961 +30.8630900771 26.5651947114 91.3332365617 +30.8632407368 14.4705378437 94.010977581 +30.8715778693 1.36407770463 -95.1056516295 +30.8985067613 14.3950815969 94.010977581 +30.8991268831 72.1974430097 61.909394931 +30.9026376511 72.8727658237 61.1112672705 +30.9076293381 -66.5847875573 -67.9057031084 +30.9105596162 53.3235134985 78.7473187632 +30.9121301675 50.1096715699 80.8298275618 +30.9450881164 50.9959269364 80.2609304542 +30.9476641496 12.5980143564 94.252491309 +30.9529116519 -93.3197048602 18.2578735093 +30.9624638801 -66.6115688991 -67.8544377272 +30.9743828038 37.1370522524 87.5295776291 +30.9889549154 -66.5469770809 -67.9057031084 +30.9914508825 -12.4899100974 94.252491309 +30.9923030668 76.0201633215 57.1000168056 +30.9938204128 19.2544481537 93.1055815863 +31.0102230056 -64.4344840672 69.9039579147 +31.0256428038 17.3751948229 93.463961469 +31.0418488983 27.7838766952 90.9090744247 +31.0430141616 -60.4810457623 73.3374009306 +31.0529965534 -57.6716731234 75.5624875464 +31.0609877049 29.3523845161 90.4082549661 +31.0700558982 73.9127422269 59.7625146976 +31.0786054864 -12.5376466478 94.2174490079 +31.092886441 -93.8513360639 15.0053034553 +31.1147177913 31.806601718 89.5556498716 +31.1181562821 -94.3687783144 11.2336115762 +31.1256448425 -93.8404768815 15.0053034553 +31.1441455694 24.3324732832 91.8584396813 +31.1466044452 76.5132207741 56.3526048938 +31.1493551909 -75.7615891321 -57.3576436351 +31.1497344822 25.7052644529 91.4818748228 +31.1507559837 86.6194103763 39.0731128489 +31.152692677 -48.6185796667 81.6440043737 +31.1541332618 -61.5945429982 72.3569779188 +31.1590848728 53.8605165162 78.282540777 +31.1652740648 -88.9940528074 33.298412235 +31.1672606719 76.9482763529 55.7455346062 +31.1904778829 84.6820082836 43.0826132274 +31.2130713471 40.2686659518 86.0475375565 +31.2145194639 -90.2950295828 -29.5374576981 +31.2190948858 78.6498369898 53.2876276071 +31.236694795 33.0087905045 89.0768693192 +31.2370577493 -61.6515888086 72.2725938412 +31.2598300801 61.9645421175 71.9945730144 +31.2607391997 73.1129130405 60.640482612 +31.2612506368 58.7938614124 74.6057375062 +31.266995696 86.4684164046 39.3139662794 +31.275135739 -63.2804284707 70.8339837725 +31.2798021997 51.8531206789 79.5790666583 +31.2841039921 -92.2657970175 -22.5461202458 +31.2926344109 69.2410496968 65.0111380342 +31.3086845906 -80.5101488616 -50.3773977046 +31.3093815251 -94.504808778 9.41083133185 +31.3160378524 30.7205114374 89.8640971147 +31.3245206484 12.3201143082 94.1646918414 +31.3304238069 -52.3078787586 -79.2609005996 +31.3396669417 -88.7465390476 33.7916718003 +31.3408124424 -94.4891840901 9.46295754202 +31.3517097887 -62.7994354328 71.2271100259 +31.3591020075 48.1966505066 81.8149717425 +31.3617592099 -1.53384591916 -94.9425477642 +31.3659653263 44.3818143951 83.9430209734 +31.3719768809 87.7149979342 36.3576429927 +31.3760005731 20.9647733263 92.6068294858 +31.3841120219 87.9910081259 35.673799932 +31.3935963644 -79.3721093496 -52.1009631841 +31.426273331 13.5798311546 93.9573175987 +31.4417407492 71.5245079934 62.4152360803 +31.4710194052 47.4035827799 82.234270698 +31.4886579535 86.8916774433 38.1877049766 +31.5005805924 20.3630453227 92.6987583926 +31.5104977163 -63.6726921516 70.3766780108 +31.5174888536 35.3123628465 88.0890738205 +31.5368066326 68.5029383137 65.6717387452 +31.5545222613 51.7352059765 79.5473480855 +31.5876309788 43.1906500554 84.4795201036 +31.5886438349 44.3674922133 83.8670567945 +31.5948233255 -63.4248455166 70.5624270432 +31.5986752596 -62.7451060628 71.1658301926 +31.6038552014 65.7560482212 68.3910700219 +31.6154464273 11.6009048778 94.1588155895 +31.6256021072 -53.9045337454 -78.0648610647 +31.643250184 -63.6890831255 70.3022432673 +31.6481928749 15.1089765415 93.6488692704 +31.6521137512 17.1499479197 93.2953534825 +31.6558351202 60.8102934803 72.801210908 +31.6647504646 18.838546895 92.9647929536 +31.6875126485 21.1089811895 92.4678995938 +31.6931360027 49.7866007252 80.7269441918 +31.7318042994 -63.6998271811 70.2525772694 +31.7370775245 -63.7382837226 70.2153052995 +31.7392055844 -61.1527442433 72.4773392198 +31.7531783136 -88.1013415483 -35.0697773643 +31.7540378001 -63.6887468113 70.2525772694 +31.7755295339 57.9671163195 75.0341865315 +31.7764684895 77.788230082 54.2148255651 +31.7845175216 71.1217733883 62.7011785857 +31.7941381841 36.3565437706 87.5633171036 +31.8331142969 -26.9964441626 90.8726847669 +31.8534318924 11.2798918319 94.1176015256 +31.8552173913 -77.0955215784 -55.1500288078 +31.8639949135 -52.967752128 -78.6072710546 +31.8649820458 20.9871541017 92.4346378904 +31.8749130008 48.7099727472 81.3100761047 +31.8818042271 -68.6834677025 -65.3156323064 +31.882645539 82.6258071857 46.4378391008 +31.8886629199 12.2281410812 93.9871573295 +31.8888191506 69.4909394067 64.4524053357 +31.8968970687 -93.5894212398 14.9535343444 +31.9180801056 -62.7781333015 70.9939584863 +31.9212581126 86.1557088009 39.4743856384 +31.9250339962 -59.7150023497 73.5860767993 +31.9288894235 45.4302143618 83.1663492238 +31.9292435982 26.5364222591 90.9744013277 +31.9486406822 -89.3765214124 -31.4820866332 +31.9490628987 21.2108351204 92.3545226472 +31.9578009813 -55.5090415367 76.7948257639 +31.9647556675 -20.2072797058 92.573863709 +31.9737257575 -36.0762359371 87.6138462904 +31.9775115229 52.7388079283 78.7150360167 +31.981671761 63.2306615587 70.5624270432 +31.9840739267 71.0682464318 62.6603811364 +31.9874558203 67.4261582831 66.5621202286 +31.9888636974 13.929074322 93.7160257794 +31.9944948316 -59.6194999122 73.6333316555 +31.9969083977 12.8497025593 93.8673691819 +31.9988205349 -59.6025911657 73.645139763 +32.0037958029 24.842586572 91.4253955234 +32.0038597156 13.9356041148 93.7099349122 +32.009989486 37.6781787674 86.9236182972 +32.0142932599 -61.9734689634 71.65454746 +32.0409464678 82.5210427411 46.5151078077 +32.0462747161 55.7977667602 76.5483213493 +32.0469137482 -89.5035589856 -31.0178698193 +32.06792887 47.8482853246 81.7446605564 +32.0699646651 54.5092410055 77.4613452723 +32.0786486713 14.5717777587 93.5875183578 +32.0837036992 41.9333980309 84.9248260906 +32.0886025842 -66.378462606 67.5590207616 +32.0946907717 -71.8158242447 -61.7447828754 +32.0962618994 -88.9072836268 32.6393150999 +32.1222523243 46.7906333503 82.3334533242 +32.1323858595 23.8810229612 91.6362729562 +32.14013789 -35.8459335796 87.6474790409 +32.1653354007 -62.1062736927 71.4716864679 +32.1793974022 -54.914312488 77.1291427853 +32.1805687288 -27.2235845023 90.682343613 +32.1936072057 -93.1272614457 17.0553461035 +32.2017922657 72.599046866 60.7653105729 +32.2020358296 -49.6436739643 80.6134884728 +32.2027891301 21.7865375298 92.1321179324 +32.2076741558 75.9871210074 56.4678950066 +32.2125622591 17.650480152 93.009738109 +32.2170325832 -91.8432142569 -22.954015041 +32.2173473329 -49.6672786606 80.5928282249 +32.2326549106 -49.6908773051 80.5721581569 +32.2346481742 72.468273405 60.9038324474 +32.236550621 6.75218390939 -94.4204046619 +32.2459470218 6.70716662632 -94.4204046619 +32.2628997885 -54.7715350935 77.1957527377 +32.2662808084 52.9645323054 78.445174743 +32.273426667 12.369223357 93.8372433776 +32.2777423742 12.3579570526 93.8372433776 +32.2917425465 87.1556489942 36.893579546 +32.2989599502 -4.92512908828 94.5120113509 +32.31249241 81.9042522381 47.4088209047 +32.3390471006 12.4267506746 93.8070461122 +32.3433960971 -52.67638623 -78.6072710546 +32.3553414727 -60.8003375937 72.5013849983 +32.3596081948 16.7879609131 93.1183125162 +32.365941428 20.6591087734 92.3344305239 +32.3995505534 -88.4402631488 33.5944783874 +32.4078740693 -36.5275407875 87.2666514903 +32.4221977658 27.4765719196 90.5198270413 +32.4393848908 47.7869080951 81.6339250717 +32.452387951 -89.0654568037 31.8463015219 +32.4869204552 -89.1118760637 31.6808071828 +32.4876933738 28.9149793135 90.0470640862 +32.4928613054 -93.0452654338 -16.9349503849 +32.4969245716 -27.5593962146 90.4678372333 +32.5011647001 67.321823261 66.4187202975 +32.5071871754 45.3219466467 83.0012285095 +32.5092796343 27.9821411678 90.3335292863 +32.5182378644 60.2668686366 72.8729630997 +32.5300316696 47.0670377715 82.0151875874 +32.5417714914 48.0098282991 81.4621967227 +32.5550869283 52.4650791233 78.6611834876 +32.5826111746 43.9526031161 83.7050902177 +32.5857837344 -94.2084695352 7.93290402346 +32.5925040557 27.8366282048 90.3484964433 +32.6018316466 -93.4621107835 -14.2110668555 +32.6057296734 19.7234051264 92.4546033612 +32.6094672301 46.3469755873 82.3928425343 +32.6149513224 41.105595205 85.1269345923 +32.6184735033 61.6576111653 71.65454746 +32.6238207055 28.0906455484 90.258528435 +32.6251808625 -93.6867577993 12.5852686403 +32.625901481 86.2054083145 38.7837353782 +32.6344570749 -89.0814817528 31.6145823974 +32.6722130827 68.4372299109 65.1833725301 +32.6779273018 44.5344613449 83.3596714243 +32.6829491572 22.3366143677 91.8308253964 +32.6838522253 -62.7316225036 70.6859911282 +32.6880027292 -88.55710769 33.0020174407 +32.7003799218 27.9287628985 90.2810575698 +32.7091219696 -24.36287162 91.3047853423 +32.7166341522 -25.2225008506 91.0683660806 +32.7240917915 -90.6463849108 -26.690198932 +32.7243585834 84.8071575266 41.6756810089 +32.7304723883 63.960951288 69.5536691165 +32.7387061352 53.6346106017 77.7914241173 +32.7423251113 -93.0805647546 16.2464953535 +32.7510872426 -93.6796392091 12.3081876034 +32.7568465363 80.5896721999 49.3182901134 +32.7574261513 53.62317937 77.7914241173 +32.758304127 -4.74972804946 -94.3627765286 +32.7854623808 59.6858764203 73.2305237754 +32.7920405665 -88.9823556989 31.7304656405 +32.7960255749 -61.4214978682 71.7761820252 +32.8050801637 20.7786016926 92.1524629468 +32.8230992697 -88.9709036965 31.7304656405 +32.8501170033 11.2599214791 93.7767774087 +32.8543692435 27.9909356643 90.2058642343 +32.8886310673 82.3524710406 46.2212987705 +32.8945925581 11.2815823114 93.7585819058 +32.9095898711 19.3079416973 92.4346378904 +32.9112506116 38.4389293228 86.2513669207 +32.9329229936 86.3332143242 38.2360914263 +32.9342580903 32.9572585695 88.4825053421 +32.9395076621 -62.8204151117 70.4881853942 +32.9607378279 -88.9612721451 31.6145823974 +32.9608613536 -88.7713260027 32.1439465303 +32.9624556182 -52.4855885187 -78.4776370533 +32.9684280608 69.4939435402 63.9036349704 +32.9735052919 -24.9648170139 91.0467235008 +32.9763171368 27.5040965426 90.3110579136 +32.9778619722 -24.9590616714 91.0467235008 +32.9806074475 14.0198218607 93.3580426497 +32.9815717765 73.1141213535 59.7205256328 +33.0067792644 51.6112623079 79.0368909154 +33.008223759 -62.0011015834 71.1780904964 +33.0193374654 86.3786116242 38.0586232965 +33.0203038159 35.0157984364 87.6558805544 +33.035874841 12.2006805378 93.5936662809 +33.0511978841 12.2063395844 93.5875183578 +33.0597455918 83.371819978 44.2288690219 +33.0686176609 -52.4511479285 -78.4559979031 +33.0809671352 56.2725737616 75.7564984384 +33.1108843823 34.2514164721 87.9233177551 +33.1234121595 82.3970759635 45.9734862673 +33.1255689201 75.4621523113 56.6406236925 +33.1262025476 69.35704653 63.9707339446 +33.1297510506 71.6993504901 61.3320693815 +33.1343514036 65.8230747502 67.59761525 +33.1499383407 -88.4282131146 32.8866646739 +33.1509815903 85.6900536706 39.4743856384 +33.1576484334 -50.8055617088 79.4944353388 +33.1829853222 10.6730598635 93.7281989492 +33.1936977643 -89.8305802407 -28.7861995122 +33.1992721317 49.2199450455 80.4686606055 +33.2024651155 -61.5863963131 71.4472679633 +33.2096251099 -35.7378128907 87.292207727 +33.2182837916 21.4734270185 91.8446381343 +33.218284648 41.761107277 84.5727821704 +33.220188754 -60.6779161751 72.2122534463 +33.2284575973 77.9030286133 53.1694248471 +33.2292393053 -89.3507318348 -30.2037146025 +33.2301737337 14.4695842918 93.2007869283 +33.2301749178 84.0155121659 42.8619783775 +33.2343235939 82.7982223798 45.1656296979 +33.2357372047 77.920095414 53.1398579518 +33.2407317387 -92.077487837 20.4154350213 +33.2459819724 7.06665161739 -94.0466220425 +33.2460701043 -86.2488324823 -38.1554415263 +33.2593682792 -86.1936675609 -38.2683432365 +33.2862620526 29.761353123 89.4778554664 +33.2881556798 -88.4679252681 32.6393150999 +33.2888874814 -60.1785335924 72.5974797422 +33.3177731285 12.0477130532 93.5135209686 +33.3309111763 26.4177546696 90.504986594 +33.3322920328 -60.0094840258 72.7173991201 +33.3592640599 -91.7534655289 21.6439613938 +33.3670941537 20.4233575494 92.0300140941 +33.4253161788 37.4893971169 86.471344052 +33.4292475579 38.428849987 86.0564285593 +33.4294128831 12.6852916063 93.3892806009 +33.4586838561 -93.0369545155 14.9880475413 +33.4663454815 -88.6596971054 31.9290123445 +33.4728607312 -60.3369589486 72.3810678237 +33.4871447587 28.7729963057 89.7258369674 +33.4939774183 -80.58301272 -48.8316653174 +33.4945865083 -61.3569556511 71.5082978952 +33.5021140977 30.9365204765 88.9974159838 +33.5193205265 -59.6575130231 72.9207535023 +33.5245562592 10.9445630387 93.5752139592 +33.5398188516 -76.587363624 -54.8585115048 +33.5422207959 23.286413911 91.2834177233 +33.545211563 -73.3705704195 -59.088731392 +33.5675219842 -84.0098270533 -42.6095109843 +33.5780713686 25.1378920725 90.7777478533 +33.5888157308 52.4608291165 78.2282101688 +33.6155978083 60.8192623665 71.9097275004 +33.6310353978 72.5181366165 60.083885691 +33.6362336855 53.620750988 77.4171741084 +33.6473324965 47.2066671773 81.4824373094 +33.6673453834 -81.5618626009 -47.0549936128 +33.6777060783 -34.874285543 87.4619707139 +33.6811758971 -1.38221659082 -94.1470544812 +33.6892139371 -35.5382722433 87.1898392604 +33.6921252011 10.7979016002 93.5320587845 +33.7055500692 39.6319078788 85.4005138885 +33.7162189221 48.0089408064 80.9836908534 +33.7181780336 49.9328386599 79.8110023334 +33.7235935466 46.0774473848 82.0949942494 +33.7319818297 -34.9915472868 87.3941932872 +33.7369386714 35.3036897045 87.2666514903 +33.7451971587 10.8994017025 93.5011481814 +33.7468917109 39.6945545958 85.3550797275 +33.755602981 -52.418618043 78.1847027868 +33.7773956966 -52.3721009689 78.2064612424 +33.792583689 82.6824199848 44.9630816679 +33.7961711541 11.8220085935 93.3705463631 +33.7987762241 -58.8967506778 73.4085518544 +33.8020072546 -34.9663456495 87.3772223035 +33.8048948037 19.7539855708 92.0163525759 +33.8208081171 13.3428311195 93.1564372227 +33.8415066941 45.0235377324 82.6294951862 +33.8467066121 -34.3465986015 87.6054314299 +33.8541366384 14.6640255108 92.9454882621 +33.8568395117 79.4530899621 50.4075481823 +33.862169904 -34.3742883918 87.5885937035 +33.8664276352 70.5898117509 62.2104778651 +33.870751173 11.3527184209 93.4017558691 +33.8806209964 -29.796298765 89.2428378124 +33.8910238577 43.6920446846 83.3210881659 +33.8942572883 -59.6646829217 72.7413564262 +33.9116185221 48.919848796 80.3545301958 +33.9162365422 61.0106027771 71.605832497 +33.919206949 79.4456115872 50.3773977046 +33.9238443511 -78.3933789109 -51.9966434242 +33.9383967589 57.8928879632 74.1390500932 +33.9434990749 -35.210962669 87.2240046001 +33.9475526574 14.0268416072 93.009738109 +33.9522043633 67.5945916763 65.4080957909 +33.9557879513 -35.1991120077 87.2240046001 +33.9559889754 9.82015603494 93.544403083 +33.9601122707 -60.8143038613 71.7518725918 +33.9606708967 -69.8771540208 -62.959162782 +33.977529941 -89.3525104524 -29.3539832896 +34.007245368 69.2643648593 63.6078220278 +34.0181751577 22.0916612542 91.4041698281 +34.0379618266 40.4213791295 84.8971687629 +34.0387943738 -91.9201959734 19.7999507521 +34.0459911044 50.0971545929 79.5684962244 +34.0513023264 39.6302449043 85.2640164354 +34.0530632075 -93.7126651556 -7.6370986393 +34.0642659741 -93.998963555 1.95464427448 +34.0759023145 63.8989963179 68.9619543736 +34.0780076536 -88.5452104114 31.5980237922 +34.0839938679 45.5610149665 82.234270698 +34.0926202693 -61.4541149069 71.1413030818 +34.1139282079 -71.7790908987 -60.6959801962 +34.1184098204 -88.5119054352 31.6476967182 +34.1214168123 -61.4807249475 71.1044961634 +34.1538404736 -35.3673371428 87.07850851 +34.1683386717 -52.8162101319 77.7365588364 +34.1822002722 -93.2559238742 -11.6150698194 +34.2108560511 22.6694407984 91.1905355952 +34.2160280755 -92.6469976452 15.6779223773 +34.2189955884 -34.9432878025 -87.2240046001 +34.2510610684 -93.9509275181 -0.2967055375 +34.2552657771 31.8319573158 88.3928914562 +34.2694840493 42.4251638664 83.8194961444 +34.2711121103 -31.1296864819 88.6365246062 +34.2797898548 74.5296084798 57.1859551582 +34.2815914041 24.6338223997 90.6528945196 +34.2865900893 46.7267953343 81.4925538797 +34.2960850948 -54.0003087823 76.8618578918 +34.2995521471 -80.1040630833 -49.0599612724 +34.3174275624 -67.409904098 -65.4080957909 +34.3267994757 -57.8589165062 73.9865975598 +34.3290420257 -35.2397473655 87.0613408995 +34.3464310383 -50.5962042422 79.1223532967 +34.3510333449 15.0647502673 92.6987583926 +34.3683778047 62.3868240073 70.1904466245 +34.374792895 47.6267757608 80.9324647101 +34.390098985 17.2588318489 92.300887401 +34.4322728057 15.9464215258 92.5209718386 +34.43246814 76.8667437714 53.9064823539 +34.4338843299 26.0232524429 90.2058642343 +34.4356965438 14.9516325104 92.685659564 +34.438114423 10.3188276647 93.3141900818 +34.4669940024 76.871885216 53.8770785007 +34.4813584512 -54.9253953256 76.1198848376 +34.4837408326 66.1580508104 66.5881666001 +34.4917377983 51.9535743948 78.1738199863 +34.5049213312 11.0916058295 93.2007869283 +34.5151761812 73.2489065334 58.6796413149 +34.5155397511 69.5311039552 63.0404877715 +34.5157937213 29.3233439159 89.1560513111 +34.5188388268 18.8828542253 91.9341480754 +34.5254870374 41.0730280246 84.3860006976 +34.5329238013 56.3526099666 75.0457228874 +34.5433653225 -60.3405338082 71.8733322724 +34.5520202872 -56.4943762919 74.9302565154 +34.5633215545 56.5793900529 74.8608671094 +34.5736991538 -60.0042712391 72.1397723859 +34.5773056792 -57.9349783552 73.8102175512 +34.5777838073 44.3691718448 82.6786154745 +34.5862127729 27.1385556631 89.8181088787 +34.5882562146 -50.5148741636 79.0689573744 +34.5975266947 -57.9229050692 73.8102175512 +34.6036552265 -91.2386456054 -21.8654200292 +34.6245045118 50.322499584 79.175688964 +34.6469472429 -75.6057583122 -55.5279961531 +34.651422924 -91.2205146679 -21.8654200292 +34.657884956 14.0026944542 92.7510407403 +34.6652767094 -60.6025421368 71.5936483022 +34.667894966 10.2888461694 93.2323801216 +34.6714203352 -93.5784167272 -6.4009792035 +34.6766450761 55.971318561 75.2644789048 +34.6791903689 -79.0014007599 -50.5582083675 +34.6985303056 46.6875546474 81.3405448449 +34.7067649468 -78.989290626 -50.5582083675 +34.7138159804 13.8634563395 92.7510407403 +34.7163504167 38.4888144331 85.5183382514 +34.7191728526 -34.381480667 -87.2496007073 +34.7195063252 21.5521818702 91.2691587404 +34.7292409912 24.13745128 90.6160210221 +34.7471923455 44.6026053075 82.4817569156 +34.7473204378 20.6150473084 91.4748246616 +34.7532597743 80.2331940956 48.5267503577 +34.7707994234 -92.1154820056 17.4851217417 +34.7802744524 -35.3926644124 86.8198814489 +34.7897517115 49.2263600768 79.7899658444 +34.7961668235 -89.7098737325 -27.2280247041 +34.8117926496 -51.8054127238 78.1302649748 +34.8128627612 53.6686070975 76.8618578918 +34.8298740288 -51.7932579599 78.1302649748 +34.8313401945 24.0734206628 90.593863798 +34.8373926529 11.7443882318 92.9969107993 +34.8427397693 -93.5892975909 -5.19873655938 +34.8614755064 -93.3902915686 -7.93290402346 +34.866329551 -72.3499120125 -59.5804439009 +34.8729108707 75.7146941312 55.2373531229 +34.8807464142 69.0521411617 63.3650955225 +34.8838029726 77.801496058 52.2498564716 +34.8875201989 48.1421295119 80.4064443961 +34.8924261436 -55.6664491871 75.3907489863 +34.8937170971 52.778677845 77.4392644082 +34.8957395181 41.5871229369 83.9809417029 +34.9184242925 77.8059495778 52.2200905326 +34.9211274218 11.9017255598 92.9454882621 +34.921718095 39.2642097348 85.0811109424 +34.923395655 55.179360967 75.7337082097 +34.9283042609 12.5199005796 92.8615402141 +34.9283074763 14.7040332845 92.5408274331 +34.9301816002 -31.5286351954 88.2373366331 +34.9333095666 43.2933251318 83.0984469274 +34.9419688741 -88.1185104877 31.8463015219 +34.9459800185 11.4693814866 92.990492895 +34.9702866149 -92.2053339827 16.5908239462 +34.9798237147 -55.6115716391 75.3907489863 +34.9899827807 46.1310283528 81.5329953339 +34.9905036337 14.3863353248 92.5672620929 +35.0003002456 11.0355522779 93.0225540858 +35.0017490732 10.4211722327 93.0928393117 +35.0175148402 9.65858265045 93.1691227586 +35.0177018092 60.4573346686 71.5448897181 +35.0220856847 28.5938642576 89.1955404777 +35.071327277 -50.8008356589 78.671958787 +35.0732169942 10.2361948215 93.0864639207 +35.0752263822 -91.2312819063 21.1324796455 +35.0768728211 10.5102213556 93.0545444358 +35.078743393 81.1787838466 46.6849741903 +35.0814693301 10.9938660822 92.9969107993 +35.0870539225 50.9566595422 78.564098005 +35.0895836256 47.6814131471 80.5928282249 +35.0918679792 33.1847299151 87.5633171036 +35.102128397 10.6514594407 93.0289578238 +35.107062404 13.5255732268 92.6528630872 +35.1173655688 -31.6198179832 88.1303452065 +35.1194285064 9.59441325121 93.1373876365 +35.132778807 12.6693624177 92.7640830776 +35.1346577774 58.8688331223 72.801210908 +35.1901544909 -55.0253109986 75.7223096347 +35.194848474 57.3653298979 73.9631094979 +35.2094044425 24.580696844 90.3110579136 +35.2131291511 -35.4969792431 86.6025403784 +35.2262373326 25.4808083921 90.0546534449 +35.2432765408 -51.529364901 78.1193702712 +35.2515005484 83.5740399149 42.1035813367 +35.253009436 -35.4999849808 86.5850818101 +35.2683090527 73.1840457442 58.3115925445 +35.2702524209 -51.5109045019 78.1193702712 +35.2724798014 9.46443012277 93.0928393117 +35.2760844677 69.7742475021 62.3470308046 +35.2830300294 9.10510490274 93.1246737264 +35.293095153 -52.5612897657 77.406125421 +35.3216790002 -62.9424916988 69.214317387 +35.3290908001 11.0173164317 92.9003448964 +35.336594879 9.09262007596 93.1055815863 +35.3594091912 34.4456114154 86.9667294767 +35.3620015453 13.1720909235 92.6068294858 +35.3861780902 67.3436100875 64.9049811691 +35.388625241 9.02044746318 93.0928393117 +35.4000928761 13.115967794 92.6002419716 +35.4387911575 -62.765589022 69.315026625 +35.4456073324 -89.983916465 -25.4264369988 +35.4483809465 -89.0778477366 -28.435001862 +35.4501122202 -76.6507920676 -53.5532036295 +35.476072674 50.8537575863 78.4559979031 +35.4988581152 83.5489711357 41.9452082446 +35.5086171997 -93.4770945254 1.08208301821 +35.5088343132 54.9303347952 75.6424550435 +35.5099385066 66.50420513 65.6980590831 +35.5120156597 51.9222896651 77.7365588364 +35.5156832038 22.9937156407 90.6086380408 +35.52637395 -91.49771609 -19.1322947989 +35.5348875202 15.3773189779 92.199836388 +35.5430136249 83.450480053 42.1035813367 +35.5536217691 19.8539637922 91.3332365617 +35.561140459 36.1493986108 86.1894788785 +35.6074180353 -91.4697890036 -19.1151636272 +35.6266923176 11.9897066142 92.6659901464 +35.6348672712 -89.0034095059 -28.435001862 +35.6395053743 76.778741845 53.243313734 +35.642707119 12.2936471689 92.6199960512 +35.6619962436 -91.704671206 17.8458763563 +35.6775471953 14.5815337727 92.2740022919 +35.6850159037 -76.9823063388 -52.9179000974 +35.7220896825 72.2781560357 59.1591114605 +35.756513104 38.505536374 85.0811109424 +35.7901623592 17.3247653805 91.754655374 +35.8023509632 8.90661985384 92.9454882621 +35.8088664377 -55.6284298059 74.9880182547 +35.82905306 50.286152857 78.6611834876 +35.8367177035 -88.92232753 -28.435001862 +35.8477445704 9.3844208214 92.8809552872 +35.8523999907 -93.1556308457 -6.0525909032 +35.8778254105 21.6685176756 90.7923839623 +35.8928003121 25.3853147157 89.8181088787 +35.8980281718 32.4022316121 87.5295776291 +35.9095886696 74.6146139797 56.0638994563 +35.9175359457 -72.8335579117 -58.3541211356 +35.9248382537 40.9355930831 83.8670567945 +35.9346276883 -76.5382706601 53.3909698101 +35.9737433153 26.843314064 89.3606528733 +35.9804797916 70.0104418574 61.6761145412 +35.9876239614 -62.3826717476 69.3779012888 +35.9883842082 16.0230609874 91.9135339255 +36.0078010158 9.41289203486 92.8161393808 +36.0093974289 -62.3701058967 69.3779012888 +36.0324707073 -80.0637377727 -47.8691857941 +36.0524728611 14.7274242727 92.1049519564 +36.0658478995 -86.6426347301 34.5298198999 +36.0682066317 43.9883620696 82.2442002381 +36.077186148 10.0865077182 92.7183854567 +36.0834363172 37.001902113 85.6086728292 +36.0837790728 -80.177744374 -47.6391666061 +36.0929854823 -89.3332738679 -26.7742895148 +36.0972464857 -56.9240697204 73.8690671568 +36.1025158459 -62.3302435656 69.3653305813 +36.1216550731 -76.3469644964 53.5384632481 +36.1247165993 52.9568541296 76.750090888 +36.1276582977 22.6804145583 90.4455145454 +36.1287734367 46.8633887614 80.6134884728 +36.1489979665 47.0252645484 80.5100890583 +36.149132368 11.3769717864 92.5408274331 +36.1589691101 29.6274032215 88.4010516411 +36.1706746026 55.9541675787 74.5708617985 +36.1711882997 8.7640976399 92.8161393808 +36.1752778232 15.3927651521 91.94787684 +36.1781448345 -90.8193713891 21.0471759821 +36.1967321365 -65.9233507936 65.9083333334 +36.2420747423 82.055394381 44.1975595633 +36.2565661766 30.6174863473 88.0229000821 +36.2642181514 -68.2605462949 -63.4460739636 +36.2762130104 13.3973896012 92.220097167 +36.286675487 41.7430450833 83.3114360053 +36.3022379182 13.6957550814 92.1660122544 +36.3059791418 -62.3799178198 69.214317387 +36.3108402655 -53.1698774551 76.5146195875 +36.3329400559 12.0159710786 92.3879532511 +36.3371192391 13.6944272699 92.1524629468 +36.3624311918 13.718464214 92.1389024106 +36.3997467069 15.8044033041 91.7893200535 +36.4103762254 14.9552595519 91.9272794923 +36.4112150316 -34.1565474562 86.6461406284 +36.4123384092 -75.4232973964 -54.6394346734 +36.4190848767 -68.9873610047 -62.5651203016 +36.443281869 49.4846903446 78.886961078 +36.463082849 -34.145431061 86.6287084447 +36.4838944874 12.4770026064 92.267273987 +36.4870184238 9.62666188931 92.6068294858 +36.4904887215 -91.3714501995 17.8802215116 +36.5179251374 72.6709959761 58.1839108989 +36.5202203518 24.8937296685 89.7027074767 +36.5373465941 45.2812300116 81.3303910756 +36.5839014423 48.7783537176 79.2609005996 +36.595284007 51.2479157848 77.6816343556 +36.5974774303 -76.3164520427 -53.2580866475 +36.6419306235 -54.4673188937 75.436596508 +36.6822709021 8.50249386006 92.6397247385 +36.6869359653 65.1886073632 66.3665141432 +36.6929930871 -61.8718170238 69.4658370459 +36.7134955436 42.4280876882 82.7766671236 +36.7247360855 38.8760738765 84.4981931132 +36.7309717642 -70.2001745221 -61.0145163901 +36.7383202087 37.4243627663 85.1452459024 +36.7420702435 73.4362343181 57.0713567684 +36.7507547945 23.6660929725 89.9405251566 +36.760872118 65.1602405792 66.3534575496 +36.796389197 63.2733195251 68.1359873953 +36.8221685221 40.7233158296 83.5807361368 +36.8293612799 70.5080047594 60.5988400266 +36.8333771382 -91.1658075217 18.2235525492 +36.834474288 -77.3988327939 -51.503807491 +36.8401547259 14.1785091353 91.8791210149 +36.849236217 34.0630835839 86.4976307593 +36.8525520185 72.0782322055 58.7079028057 +36.8557989743 -87.3775007207 31.7304656405 +36.8558875797 43.198480745 82.3136368534 +36.8561858453 54.7033048182 75.1609606571 +36.8563570896 42.8192257248 82.5113498278 +36.8614893327 -77.3859704217 -51.503807491 +36.8618856575 76.8334232762 52.3242434579 +36.8697693048 14.1013202552 91.8791210149 +36.8718423317 42.3863114255 82.7276727994 +36.8744613484 -87.5070345791 31.3495294931 +36.8777427925 50.9446035858 77.7475366299 +36.8801440865 -86.0478230964 -35.1514880558 +36.8814550185 9.12723736636 92.5010908789 +36.9057016916 26.5194369272 89.0768693192 +36.9352824451 76.8487957576 52.2498564716 +36.9410921962 40.0607271843 83.8480401967 +36.9450977448 -89.5024823526 -24.9873048837 +36.9757923251 70.0715318201 61.0145163901 +36.9835542917 -91.2164963613 17.6569392453 +36.9858678818 -91.2222026159 17.6225800308 +36.9898540967 -15.2310144211 91.6502421907 +36.9997786554 44.7568498351 81.4115518356 +37.0225921975 47.7636558509 79.6740914397 +37.0355188424 -76.8511215289 -52.1754296948 +37.035779566 73.0647093238 57.3576436351 +37.037191526 31.3542970602 87.4365741536 +37.0408212366 36.1718746711 85.5545033584 +37.0516748731 8.33636629805 92.5077206834 +37.0566595633 47.8076069045 79.6318824597 +37.0600530092 -87.6054385337 -30.8518980011 +37.0684177025 57.8065499269 72.6934329537 +37.084654075 15.6270481554 91.5452008468 +37.088135383 -92.8679454256 0.122173017247 +37.0901066844 15.6141022173 91.5452008468 +37.0941364815 20.5785456547 90.5568799011 +37.1007804587 18.8793291566 90.9236109047 +37.1027541029 -73.9956908075 -56.107248907 +37.1170162953 49.9416750904 78.282540777 +37.1186741886 -86.5209332703 -33.7095258423 +37.1187485353 38.130081094 84.6657866138 +37.1188594906 29.9832469062 87.8817112662 +37.1266969641 18.9333240635 90.9018020308 +37.1491228591 20.3807067072 90.5790785166 +37.1507341452 -15.9612150203 91.4607159799 +37.1539608893 -76.9251746397 -51.9817342621 +37.1760075098 -76.8338083198 -52.1009631841 +37.2100536263 -91.1804530207 -17.3648177667 +37.2134839285 -91.1888587195 -17.3132509753 +37.2455222595 14.7691089226 91.6222925562 +37.2667282587 -89.4395540159 -24.7337247968 +37.2689432152 27.961976325 88.4825053421 +37.2777381788 -16.0697586005 91.3900054426 +37.2788680044 64.5168737621 66.6922709185 +37.2801263302 73.6423497379 56.4534897583 +37.2873418611 63.6310468222 67.5332808121 +37.2895595718 11.9364821266 92.0163525759 +37.2983966619 -52.8738477934 76.2442511011 +37.3065882465 17.0645400369 91.1976970473 +37.3163247727 63.6550342848 67.49465546 +37.3279731721 10.2257843192 92.2065927899 +37.330822453 -15.946052809 91.3900054426 +37.3321369934 69.8581790195 61.0421687982 +37.3397734456 12.1468395605 91.9684489797 +37.3567125844 13.3388718361 91.796244602 +37.3578344179 75.4882995426 53.9064823539 +37.3598322264 13.4724684586 91.7754625684 +37.3609705918 16.7515125419 91.233462633 +37.3829144681 61.5566772871 69.3779012888 +37.3840357071 -15.6150865396 91.4253955234 +37.3866092358 8.01499453583 92.401305794 +37.3884182236 28.9492064518 88.1138447042 +37.3968312577 17.058485473 91.1618620107 +37.401001833 9.63774309871 92.2403326634 +37.4194673955 -91.0117816883 17.7943545474 +37.4209423563 8.00869322906 92.3879532511 +37.4273377505 -70.0363245015 -60.7791710969 +37.4297905197 -81.0054885454 -45.1344835704 +37.4300169194 9.58950741215 92.2335903075 +37.4595720751 13.7601742882 91.6920828835 +37.461674761 -16.3666032726 91.2620250784 +37.4692892909 -76.4168067342 -52.5026095407 +37.4722402784 17.6890482999 91.0105970685 +37.4803400461 13.515925233 91.7199208195 +37.4893471199 46.5773822812 80.1566984871 +37.4944073807 64.4994998741 66.5881666001 +37.4958651583 61.7426678469 69.1513055782 +37.505664096 64.4929548832 66.5881666001 +37.5175637676 45.3026268954 80.8709119852 +37.5220896523 14.5011457415 91.5522231315 +37.5243427656 9.00879764646 92.2538089456 +37.5374530739 -53.3707825015 75.7792794364 +37.5417018532 24.7729978692 89.3136003 +37.5485113944 25.7388904829 89.0371765543 +37.5644790189 -80.9257425671 -45.1656296979 +37.5748682855 7.90456913194 92.3344305239 +37.5865297703 -90.9663582382 17.6741180461 +37.6080336362 68.4087592277 62.4970196645 +37.6423262792 69.4730502289 61.2907053653 +37.6459183011 31.8132675058 87.0097744272 +37.6569661369 -55.5146906211 74.1624704726 +37.6585452 -82.5577547598 -42.0244107924 +37.6689481991 14.0239257401 91.566259334 +37.6720763219 -80.348247808 -46.0974374535 +37.6948805611 62.5615567632 68.3018857343 +37.7203799256 26.3630680578 88.7815385136 +37.7294738099 -17.2102196696 90.9961270877 +37.736959131 -17.0785514556 91.0178279005 +37.7389675398 -16.8024709027 91.0683660806 +37.7469544214 -87.3116705924 30.8518980011 +37.7925388974 42.3429624306 82.3334533242 +37.7941015541 -54.9496577604 74.5126901925 +37.8056758213 -16.8479864293 91.0322812467 +37.8078667685 41.0438014136 82.9817544761 +37.808075395 16.1265107719 91.1618620107 +37.8124139527 -87.2539602526 30.9348956893 +37.8128613956 43.2237175867 81.8651192576 +37.8221914542 41.0306014782 82.9817544761 +37.8328715201 63.8955124909 66.9778867692 +37.8348614383 78.967447484 48.2976759048 +37.8519753502 16.1452356896 91.1403276635 +37.8576087944 -16.1320218743 91.1403276635 +37.8612424379 61.1353844369 69.4909425092 +37.8642676366 -86.9573144941 31.6973609677 +37.8656223766 28.1420060549 88.1715494774 +37.8733194888 -12.320405107 91.7268733191 +37.875337519 22.5961554905 89.7489418593 +37.8762230534 53.4549334017 75.5510544084 +37.883791699 72.3112442786 57.7572703422 +37.8847420093 44.5144212728 81.1369990919 +37.9120864343 -14.819431511 91.3403424117 +37.9169543407 10.3871323348 91.94787684 +37.9241983015 13.221448339 91.5802843794 +37.9259366861 -60.694186025 69.8415285431 +37.9318794991 -91.2152194235 15.5227659645 +37.9478734614 12.0888217314 91.7268733191 +37.9498723784 63.4850277865 67.301251351 +37.9616607485 17.0049310031 90.9381363059 +37.9660588071 -90.8944368963 17.2272957823 +37.9663410941 -88.8818540583 -25.6626764599 +37.9749242234 47.3665600791 79.4626586297 +37.982270557 -91.2465444665 -15.212338619 +37.9955386758 72.3094970902 57.6860093202 +38.0117828964 -13.9253846351 91.4395320624 +38.0173281824 34.5688564818 85.7885593737 +38.0301530923 10.9912220792 91.8308253964 +38.0328927861 -91.4581272166 13.7444546037 +38.0386124797 -15.9899603292 91.0899836935 +38.046669114 -91.852784578 10.7478804698 +38.0493088517 14.9496780732 91.2620250784 +38.0576992862 15.1449979599 91.2263150732 +38.0610852871 -53.5175770807 75.4136773416 +38.0677317177 -56.0149661972 73.5742574804 +38.0704252866 -53.510933353 75.4136773416 +38.0819280851 -87.1660894101 30.8518980011 +38.084018768 -81.5970665222 -43.4916802325 +38.0843825713 13.5837121811 91.4607159799 +38.0857037409 -91.9470225038 9.75828997591 +38.0958729397 13.2142216365 91.5100475986 +38.0983995638 46.1349675101 80.1253812691 +38.1067909263 40.26863555 83.2244523938 +38.1080195219 -15.8238338853 91.0899836935 +38.110813179 9.11442922006 92.0026798459 +38.1150491474 45.6660103893 80.3856860617 +38.1320794183 -56.8965530459 72.8610099486 +38.1380611905 36.0401622575 85.1269345923 +38.1548279488 11.1934052632 91.754655374 +38.1683796505 -71.4830229652 -58.5948139565 +38.1806160616 46.1032655209 80.1044909195 +38.1930324661 -13.1285509462 91.4818748228 +38.2189683117 28.6956131044 87.8400378515 +38.2273395072 9.51697407374 91.9135339255 +38.2404875419 27.8139440571 88.1138447042 +38.263106291 38.4908405038 83.9904154905 +38.2682624494 41.718604577 82.4323851484 +38.2753081772 -84.3774485404 -37.6224263139 +38.2773572696 11.2874202965 91.6920828835 +38.2861048516 18.1550188756 90.5790785166 +38.2974087888 54.5523951723 74.5475999683 +38.3145813083 -86.7477400824 31.7304656405 +38.3212509235 17.7069038194 90.6528945196 +38.3407681323 15.5919617129 91.0322812467 +38.3438264936 43.7998001557 81.3100761047 +38.3577268454 27.940183471 88.0229000821 +38.3637297381 14.0771056474 91.2691587404 +38.3712422687 -79.7295523528 -46.5923410914 +38.3751333137 -86.7209703209 31.7304656405 +38.3779487315 -82.602699547 -41.2786516097 +38.3835970615 14.0691952577 91.2620250784 +38.3920220413 17.5529302054 90.6528945196 +38.3969888641 -86.7294511825 31.6808071828 +38.4167305267 -10.9795478432 91.6711751032 +38.4291075458 -86.9249254712 31.1008203279 +38.4307846677 20.1595036476 90.0925590851 +38.4368231892 -77.7027049482 -49.8487739754 +38.4379248451 -90.4662640971 18.3951350613 +38.4431527846 75.3513741096 53.3319268711 +38.4555960015 14.7386226191 91.1259575503 +38.4687354313 -15.6988001366 90.9599036311 +38.4708047088 10.4883451863 91.7060074385 +38.4918683428 16.1409799808 90.8726847669 +38.4926704218 30.7833311701 87.0097744272 +38.5022787104 24.4342890691 88.9974159838 +38.5040163753 13.2053993157 91.3403424117 +38.5103486895 8.52343651783 91.892894577 +38.5341758232 -87.2861396371 -29.9373866742 +38.5352776699 -86.8779105978 31.1008203279 +38.5392453493 73.1580709891 56.2372049186 +38.5513848048 27.1950104319 88.1715494774 +38.5572812525 -86.6824909786 31.6145823974 +38.5663775572 26.3081990502 88.4336654496 +38.5705775408 -11.8658590185 91.495966785 +38.5875368002 -86.6690266677 31.6145823974 +38.5950185877 66.714014374 63.715499106 +38.596640608 52.1984627816 76.0632619404 +38.5988799706 -60.2395029012 69.8665066769 +38.6083073599 -90.4284288003 18.2235525492 +38.6099640012 15.8981140332 90.86539853 +38.6103832291 -12.9413371048 91.3332365617 +38.6402280084 -14.2934543594 91.1187683298 +38.6441681854 12.4296086206 91.3900054426 +38.6729713756 -90.7552836627 16.3670330935 +38.6785557869 -90.7683888061 16.2809371901 +38.6865082489 70.4287200117 59.5243603663 +38.7009126426 -55.9537903126 73.2899222969 +38.701435562 48.7066981188 78.2933997461 +38.7069631594 60.8045893576 69.315026625 +38.72778586 -90.4458748704 17.8802215116 +38.7340734627 -85.9063652375 -33.4629341909 +38.7344768747 35.3322637146 85.1543976671 +38.7424674063 77.0308222012 50.6485305836 +38.7446918471 44.2577049602 80.8709119852 +38.747954163 70.3949328515 59.5243603663 +38.7620385621 81.7430972021 42.6095109843 +38.762195869 -13.8178451573 91.1403276635 +38.7735960776 -17.2063868893 90.5568799011 +38.7772658809 43.5685569805 81.2287171722 +38.7854049543 -10.0522569248 91.6222925562 +38.7941022821 -56.2772706408 72.9923724601 +38.8044213248 -56.2082243137 73.0400739673 +38.8116650741 -90.4671720473 17.5882186689 +38.832774134 -52.6330186105 75.6424550435 +38.8330383628 73.903346876 55.0480740085 +38.8392643953 63.9296280429 66.3665141432 +38.8409397354 9.90043139335 91.6152981696 +38.8522511275 47.0813015316 79.207661425 +38.8527899144 -10.6070579233 91.5311479119 +38.8562830608 -52.6648820508 75.6081970773 +38.8628451717 -16.2805947035 90.689698981 +38.8645725074 50.7776267302 76.8841832073 +38.8692421591 -86.8119678242 30.8684994204 +38.8739538482 -55.7245060236 73.3729864503 +38.8858287803 70.3544656982 59.4822786751 +38.9080541779 43.5468730327 81.1777874123 +38.9149574203 -15.525493744 90.7996978683 +38.9257903412 -68.1060077143 -62.0189854765 +38.9297021518 80.1725572917 45.3523907604 +38.937285151 9.78037001944 91.5872927177 +38.9374330806 -53.5338110113 74.9533680611 +38.9444478355 -92.1047148768 -0.226892608084 +38.9661150793 40.4493735926 82.7374767055 +38.9690638862 55.923221028 73.1710694857 +38.9723446739 28.7854204257 87.4788884333 +38.9959791108 13.6332795979 91.0683660806 +39.0050467155 26.4580727533 88.1962398116 +39.0146406622 -15.0544969112 90.8362259055 +39.0171824206 42.624568227 81.613759008 +39.0193873396 -86.137618282 32.5238086383 +39.0212092182 26.5985096546 88.1468349704 +39.0236027033 13.6505808425 91.0539404678 +39.0236170766 49.1121713925 77.879085327 +39.0359553645 -70.6260833016 -59.060566762 +39.0459257976 -70.6441223795 -59.0323949356 +39.0644927075 44.670181993 80.4893797356 +39.0660989663 59.6310884234 70.1282625266 +39.0873846871 -91.6390909443 -8.62863657979 +39.1051412087 69.1744320363 60.709849971 +39.1099838895 -73.4623620394 -55.4408741251 +39.1144337124 38.4644947956 83.609471446 +39.1144983548 8.75746308886 91.6152981696 +39.1239745665 32.0226021343 86.2778509623 +39.1286429451 -12.1123383141 91.2263150732 +39.1326179077 32.7431637257 86.0030432306 +39.1369738921 34.6620185259 85.2457726006 +39.1418973146 58.2932326511 71.2026045991 +39.1497882609 -12.7809991655 91.1259575503 +39.1520318003 72.3497935367 56.8561850734 +39.1524545641 48.8353072266 77.9884483093 +39.158767905 45.7357615982 79.8425388323 +39.1614868097 32.8021947881 85.9674006117 +39.1728680958 -86.436296027 31.5317797511 +39.1844742037 -16.6570415331 90.4827052466 +39.1867097296 -14.046307722 90.9236109047 +39.1872014535 -86.5080779195 31.3163806484 +39.1969125631 -13.7803474897 90.9599036311 +39.2114943038 14.4425630736 90.8508177527 +39.221783404 13.4668690369 90.9961270877 +39.2287407549 11.7841137531 91.2263150732 +39.2331861994 23.5457263772 88.9176915468 +39.2580564965 15.519591339 90.6528945196 +39.2814992695 -55.2335974957 73.5269577966 +39.3051158004 59.0024380096 70.5253158862 +39.3118834836 -74.40416506 -54.0240320478 +39.3203167969 14.9206833625 90.7264343782 +39.3377254226 14.9194354967 90.7190928252 +39.3611390012 23.6038325953 88.8457079624 +39.3628065516 12.6910834902 91.0467235008 +39.3727370595 -16.123858285 90.4975622348 +39.3731982196 -25.5692538923 88.2947592859 +39.3786845912 -12.8481206461 91.0178279005 +39.401255824 36.8968490685 84.179353575 +39.4157004977 47.5270529973 78.6611834876 +39.4174830799 74.6986946383 53.5384632481 +39.4277769671 41.3020861777 82.0949942494 +39.4414618999 39.5379535067 82.9525244685 +39.4540648604 28.1215370216 87.4788884333 +39.4826007766 30.6037760597 86.6287084447 +39.5042445951 26.2664386214 88.0311811867 +39.5053567952 -85.8908058442 -32.5898182861 +39.5055159376 -10.3272387042 91.2834177233 +39.5116168863 15.3493517246 90.571681737 +39.5329938232 -89.5486239268 20.4496051842 +39.5334606048 -86.4282619722 31.1008203279 +39.5370616211 27.1222999759 87.7564903719 +39.5565450321 25.0549515337 88.3602237931 +39.5622940237 -54.2534470148 74.1039025868 +39.5769469941 10.6786798512 91.2120116172 +39.6009537777 41.8475640783 81.7346061384 +39.6132745205 10.6662334041 91.1976970473 +39.6330109232 -52.8246078309 75.0918454472 +39.6403972276 -11.4566041367 91.0899836935 +39.6427923186 -71.1655711147 -57.9992284871 +39.6439632497 45.96039806 79.473253287 +39.6462560631 -52.7654849053 75.1264133504 +39.669687403 40.3681671781 82.4422645251 +39.6758676777 -58.3812664041 70.8339837725 +39.6956625474 17.3426085379 90.130396116 +39.7284268975 -69.4259270269 -60.0141046146 +39.7384699077 -89.7595303142 -19.0808995377 +39.7409293037 17.238626223 90.130396116 +39.7428393057 43.1141755268 81.0041640446 +39.7455239424 18.3061178528 89.9176255008 +39.7484429525 -84.0884811729 -36.7313029567 +39.7608393208 8.79292645626 91.3332365617 +39.7772268579 18.3123051752 89.902345368 +39.7824988746 -10.5258470763 91.1403276635 +39.7893017491 44.815769137 80.0522223488 +39.8132433463 -68.3511096937 -61.1803192039 +39.8204626733 10.0613374562 91.1762043577 +39.8294089983 13.40407704 90.7411091929 +39.8314565859 8.23419907785 91.3545457643 +39.8396056772 -89.9031801571 18.172066947 +39.8399732588 44.1691974925 80.3856860617 +39.8451088262 -82.8660325949 -39.3139662794 +39.8451616167 42.2826584114 81.3912765191 +39.8520596341 -15.7785466174 90.3484964433 +39.8533396992 18.5585191295 89.8181088787 +39.8612252648 -54.8642697823 73.491459515 +39.876301502 -54.8850204426 73.4677827999 +39.8768277334 36.1200711943 84.2922242371 +39.892035341 37.7636083395 83.5615665335 +39.9079170644 22.6984995181 88.8376962511 +39.9177136208 -87.9981112442 -25.747010637 +39.9227201748 15.3808845902 90.3858661687 +39.9369646536 9.38183923999 91.1976970473 +39.9382819072 10.9858382735 91.0178279005 +39.9427396559 65.1295850926 64.5191033296 +39.943497666 38.5729873226 83.1663492238 +39.957221966 -83.0991947414 -38.7032846937 +39.9605923876 8.62518606278 91.2620250784 +39.9644011996 14.1285917235 90.571681737 +39.9716323664 14.060552658 90.5790785166 +39.9789038123 15.4105441266 90.3559758936 +39.9847873667 8.8131762286 91.233462633 +39.9907116821 52.9155816843 74.8377190605 +40.014003636 10.7067510145 91.0178279005 +40.0141389524 -14.2247904644 90.534656459 +40.0230702924 -74.2377609649 -53.7299608347 +40.0309948353 -71.9806185656 -56.7125206934 +40.0627343922 15.845784156 90.2434952642 +40.0780436736 48.3085382276 77.8462301567 +40.1104965235 25.4745395533 87.9897488528 +40.1160948194 77.8902111836 48.2059533482 +40.1166974588 -90.1882900611 16.0225753504 +40.1168308764 38.4975478283 83.1178602446 +40.1314426207 11.530249918 90.86539853 +40.1316212206 21.1590035473 89.1164942482 +40.1356325818 49.8651709212 76.8283523594 +40.1372237097 23.8127934809 88.4418121677 +40.1436974566 38.4695316176 83.1178602446 +40.1470386292 -90.1717251246 16.0398029092 +40.1475293796 -86.0182494249 31.4489530921 +40.1625417848 -86.0112410491 31.4489530921 +40.165972473 -69.2342271579 -59.9442778349 +40.166031358 -68.37928682 -60.917674438 +40.1906637989 56.3036499316 72.2122534463 +40.1909622591 68.5860904449 60.6682351002 +40.1916453462 -86.9030098171 -28.8530506031 +40.1972146364 -16.0614648707 90.1455117112 +40.2014534017 -53.2137401867 74.5126901925 +40.2267605099 34.9932494986 84.6007105668 +40.2317904837 63.8128758731 65.6454104053 +40.2355523036 12.8253290905 90.6455253421 +40.23758545 -85.9761598734 31.4489530921 +40.2558190427 31.4739283078 85.9584834096 +40.2684000891 -69.2714420074 -59.8324600571 +40.2725242951 12.4433252696 90.682343613 +40.2744394873 8.450455453 91.1403276635 +40.2807179543 36.6140979179 83.8860631735 +40.2808920277 15.7210637872 90.1681645086 +40.2828273812 27.9764457274 87.1470728289 +40.300064517 57.7258358314 71.0185375623 +40.3032303532 -13.0797613963 90.5790785166 +40.3036775372 10.8521306774 90.8726847669 +40.3062987342 66.0323174799 63.3650955225 +40.3064161574 12.863418245 90.6086380408 +40.3069215069 31.4572452281 85.9406411501 +40.3139565868 55.32478926 72.8968627421 +40.3192520112 -14.2619589623 90.3933318548 +40.3365448417 12.8730335347 90.593863798 +40.3545676452 -88.3456289166 -23.8024940184 +40.363048829 -91.3856591717 -4.41424817878 +40.3781916808 80.915378546 42.6884428311 +40.3854036281 -88.3315371331 -23.8024940184 +40.4261578519 -86.2222437982 30.5196729298 +40.4275040042 14.47514209 90.3110579136 +40.4288754766 34.872649526 84.5541503578 +40.4395677178 75.5777690642 51.503807491 +40.4675412494 51.5545531019 75.5281812285 +40.4758192671 -16.2957981378 89.9786364517 +40.4772410174 -16.6256904793 89.9176255008 +40.4843461784 -16.2746028156 89.9786364517 +40.4893324646 -59.133178664 69.7415309387 +40.4998343353 -16.8584539199 89.8640971147 +40.5015451862 46.3134490959 78.8333005168 +40.5023020377 76.2700649614 50.4226211181 +40.5030662368 47.8103021281 77.9337964931 +40.5046152593 -10.3998175921 90.8362259055 +40.5143135724 -16.8644810446 89.8564392509 +40.5174047077 -66.9813116194 -62.2241416936 +40.5373748523 -16.8906849946 89.8411153119 +40.5623530589 -86.1993880081 30.4033060925 +40.5627786661 29.4922223942 86.515142057 +40.5693848008 -15.7602701593 90.0318771402 +40.5762755111 8.78772830233 90.9744013277 +40.6202736099 -10.3313303261 90.7923839623 +40.6391973076 -53.9692220479 73.727733681 +40.6488870102 1.41949041338 91.3545457643 +40.6647112088 -9.82280482609 90.8289258312 +40.6665834556 -54.221909476 73.5269577966 +40.6707774087 -53.9131883886 73.7513117358 +40.6708840621 45.2966219943 79.3353340291 +40.671036387 13.7268394884 90.3185511225 +40.6762040959 42.6843773593 80.7681270663 +40.6829998264 -13.6913420913 90.3185511225 +40.6881024306 25.8513492648 87.6138462904 +40.6943783572 26.4070471788 87.4450423376 +40.6957543736 -17.0400964653 89.7412429623 +40.6990188904 13.7916940295 90.2960632428 +40.69959259 80.1192805338 43.8684858384 +40.709832542 -68.4270764664 -60.5016094056 +40.7106792975 17.406582165 89.6641036785 +40.7144829426 -15.1577602411 90.0698239323 +40.7165424018 -82.819905149 -38.5100829128 +40.7167528605 17.3923703969 89.6641036785 +40.7374657418 19.7546978999 89.163954577 +40.7409755759 -16.8088580276 89.7643314515 +40.7434018787 12.7916403146 90.4231670614 +40.7526386645 10.7673115837 90.682343613 +40.7564891963 9.57435881627 90.8143173825 +40.7574523939 -75.2223578416 -51.7728399366 +40.7588006238 10.556123014 90.7044014291 +40.7599497809 27.0296044251 87.2240046001 +40.7619563378 69.5604948712 59.1591114605 +40.7693961582 80.1181230408 43.805738178 +40.7732974867 -76.5222465708 -49.8185105339 +40.7772500694 24.1828901571 88.0477353509 +40.7836639865 66.4747382208 62.5923472184 +40.7844673456 75.0531564689 51.9966434242 +40.7934552876 -85.6406287817 31.6476967182 +40.7981593682 -55.0953163389 72.801210908 +40.7995130111 -53.6540833063 73.8690671568 +40.83071083 9.74231017123 90.7631006833 +40.8409626869 -13.8636387201 90.2209248913 +40.8493363623 -53.7780227975 73.7513117358 +40.8532789821 16.9470484559 89.6872741533 +40.8628056239 25.1389657495 87.7397487892 +40.8673787727 16.9947131284 89.6718299017 +40.87519089 38.2235732508 82.8744666206 +40.8797676671 40.1724358033 81.9452255907 +40.8899874273 14.5843987167 90.0849834449 +40.9190932946 -10.3769224322 90.6528945196 +40.9659257909 -89.2714356535 -18.7724186097 +40.9757136666 -13.7102820061 90.1832526405 +40.9779891539 -73.2614166874 -54.3467499475 +40.9782460917 -87.5587388733 -25.5783227395 +41.0034666824 -11.4715200074 90.4827052466 +41.0127071549 34.5971203729 84.3860006976 +41.0185336871 36.16270193 83.7241833838 +41.0245492183 -15.1347552463 89.9328946775 +41.0295320687 39.3184230944 82.2838933425 +41.039352169 -16.0666229376 89.7643314515 +41.0728267975 -80.1598158809 -43.4445257404 +41.0742913947 -15.8904449179 89.7797101061 +41.0790656157 -89.2302359791 -18.7209870265 +41.079681418 24.6343969677 87.7815826961 +41.0821381338 12.4425579963 90.3185511225 +41.1137654438 33.1983286789 84.8971687629 +41.1454410469 -14.7565109564 89.9405251566 +41.1481625317 22.7618798733 88.2537565484 +41.1617914828 -13.5492316275 90.1228341999 +41.1626101701 34.234581507 84.4608368004 +41.1678605206 -83.1141553441 -37.3797330327 +41.1745566283 8.00352304602 90.7777478533 +41.2016252313 23.1401886786 88.1303452065 +41.2188399099 29.8703676907 86.0742027004 +41.2199472588 -54.8599217394 72.7413564262 +41.2246475846 15.7174343678 89.7412429623 +41.2254344698 35.7483910214 83.8004540093 +41.2276419905 12.6675272904 90.2209248913 +41.2287872538 8.5380713841 90.7044014291 +41.2447751954 -54.8730205501 72.7173991201 +41.2523969742 64.4549948089 64.3723029576 +41.2524651814 33.0258209966 84.8971687629 +41.2541238056 43.625012766 79.9684658487 +41.2543064459 78.6779414758 45.9114770487 +41.2700081426 21.8236853684 88.4336654496 +41.2978756294 41.5872002996 81.0246273656 +41.3309737077 67.1300222161 61.5248789485 +41.3375089122 -15.3732817597 89.7489418593 +41.3380433085 -61.5871313643 67.0685576537 +41.3400078187 -10.1923404971 90.4827052466 +41.3434351202 45.5634843059 78.8333005168 +41.366117238 67.1083721679 61.5248789485 +41.3687297553 -84.5187464575 -33.8409470269 +41.383117533 26.7719393653 87.0097744272 +41.3923096976 15.27042925 89.7412429623 +41.3989595282 5.31801779289 90.8726847669 +41.4136896526 15.302956899 89.7258369674 +41.4165195518 28.1466376223 86.5588741769 +41.427782357 -85.3171504251 -31.6973609677 +41.4441582194 -88.1531783703 -22.6141303767 +41.444607591 58.3182282515 69.8665066769 +41.4448552937 26.5356768258 87.052753116 +41.4482432211 -10.4110790926 90.4082549661 +41.4720477598 13.8119943946 89.9405251566 +41.4817144207 -74.2836644755 -52.5471651072 +41.4840852058 13.7757979509 89.9405251566 +41.4869451126 67.43606682 61.0836334633 +41.5094508497 -69.3572383665 -58.8773214093 +41.5295802843 46.6117790891 78.1193702712 +41.5336018107 45.7249296369 78.6396257006 +41.5410654141 11.5984738656 90.2209248913 +41.5412584703 52.5060864896 74.2794367659 +41.5609392717 -81.2171966449 -40.9445392696 +41.5653127247 11.6287074024 90.2058642343 +41.5738997756 15.7675389054 89.5711760239 +41.5833008884 13.0075092675 90.0090761528 +41.5895643764 -87.9834036576 -23.0049737188 +41.5946362464 12.9712160435 90.0090761528 +41.6220629074 30.7649934771 85.5635381204 +41.6375726746 17.699836261 89.1797529605 +41.6380382228 -9.48285988224 90.4231670614 +41.6587591867 -83.3722643754 -36.2438038284 +41.6852380664 8.27658382257 90.5198270413 +41.721523898 50.2538184341 75.7223096347 +41.7269640703 28.8931197389 86.1629160442 +41.7277521362 8.22448194613 90.504986594 +41.7385832512 16.0804757074 89.438856037 +41.7412219651 10.5389009679 90.258528435 +41.7485693333 10.5097575317 90.258528435 +41.7535517586 20.0766799327 88.6203579231 +41.7807477395 70.1435140871 57.7430216549 +41.8088175403 31.5853616797 85.1726934143 +41.8448455072 -11.3846792197 90.1077021322 +41.8464913564 52.7592892472 73.927860508 +41.8476073266 34.3984826979 84.0566603496 +41.8581706677 7.79574240282 90.4827052466 +41.8646082209 24.2973595463 87.5042450261 +41.8838517548 -73.0741686399 -53.9064823539 +41.8848407625 -84.1182639496 -34.2020143326 +41.8855975089 -73.9722833167 -52.6659094883 +41.8992080795 10.2294219809 90.2209248913 +41.8997489044 11.6592148618 90.0470640862 +41.955021787 -11.3989271326 90.0546534449 +41.9573603634 14.857880559 89.5478827032 +41.9654308057 37.8256495897 82.5113498278 +41.9684447923 53.5628365692 73.2780470562 +41.9695599478 12.2171180044 89.9405251566 +42.0002493413 -15.5196991818 89.4154236839 +42.0027749825 -13.7042850986 89.7104200397 +42.0097450545 9.04446147109 90.2960632428 +42.0423380969 80.1808320454 42.467351929 +42.0487406819 49.1979646169 76.232956683 +42.0618656088 53.4895062712 73.2780470562 +42.0680487148 18.9237839444 88.7252482586 +42.0721266217 16.6405475699 89.1797529605 +42.0793571556 14.1204001373 89.6099436521 +42.0873227098 21.722887089 88.072546481 +42.0889708611 16.8088293789 89.1402366318 +42.1003906213 26.635335578 86.7070701164 +42.1019638162 -88.9869838521 17.5710371841 +42.1103035384 27.9250797163 86.2954938496 +42.1163765111 15.063261943 89.438856037 +42.1297765431 15.4840449006 89.3606528733 +42.1310740844 84.2072155442 -33.6766602676 +42.1660036527 33.3007031045 84.3391445813 +42.1666903695 44.232987811 79.1543619303 +42.175908404 39.6473917932 81.5430994891 +42.1794098205 -12.6143183258 89.7873953312 +42.1825463883 66.0097633569 62.1558036049 +42.1860694264 84.1335751249 -33.7916718003 +42.1905128276 -89.7813946719 -12.6198969136 +42.1939044765 38.1518800615 82.2442002381 +42.1953217373 31.9352309246 84.8510214982 +42.2211122023 8.65139182226 90.2359745553 +42.2281165323 -88.0579825844 -21.5076237017 +42.2529295667 -66.4517129608 -61.6348909921 +42.2606907198 -90.6283437142 -0.733031720946 +42.2609658251 -14.7002865721 89.4310479768 +42.2719004591 17.7955210619 88.8617232655 +42.2872438464 -66.5826498549 -61.4698279336 +42.3004864834 17.8075551363 88.8457079624 +42.3323000543 -14.4935858187 89.4310479768 +42.3431444781 26.7889168238 86.5413892373 +42.3435538614 -14.0694111684 89.4934361602 +42.3440805095 14.5554406744 89.4154236839 +42.3675618275 76.0569969431 49.1967775447 +42.3753518738 53.8108054469 72.8610099486 +42.3837662104 30.3773756615 85.327788028 +42.3910026513 23.4300588394 87.487343296 +42.4003916417 12.8579776797 89.6486430383 +42.4110280957 -13.7638130543 89.5090059495 +42.411186024 24.9621608632 87.052753116 +42.4174647397 48.0286124043 76.7724630032 +42.4215646636 42.4511908454 79.989419596 +42.4227082618 11.8286718189 89.7797101061 +42.4278048898 9.34388511525 90.0698239323 +42.4484402997 47.4259976103 77.1291427853 +42.4635982417 13.854638339 89.4700610308 +42.4728028386 -87.5470461591 -23.0559260896 +42.4918986029 7.83705916109 90.1832526405 +42.5153537661 36.0556420366 83.0206924295 +42.5292114254 16.4106569014 89.0053735209 +42.5423876595 9.40805305808 90.0090761528 +42.5535397181 29.2790548987 85.62670846 +42.5569910499 54.2164556382 -72.4532846102 +42.5631608182 50.011544777 75.4136773416 +42.5715660759 -71.6132468969 -55.3100771174 +42.5796670098 73.839406234 52.2944934419 +42.5882945991 -66.6447023465 -61.1941240013 +42.6065914862 25.6715219422 86.7505119472 +42.6171314968 8.43841927125 90.0698239323 +42.6249716168 11.6848648267 89.7027074767 +42.6319955816 10.4083273332 89.8564392509 +42.6417579414 40.7208807599 80.7681270663 +42.6457055997 9.80634581296 89.9176255008 +42.6556359199 14.7041702746 89.2428378124 +42.6591574735 22.8736395455 87.5042450261 +42.6618852165 -90.2519159334 -5.87836883186 +42.6806667348 -70.418671249 -56.7412674039 +42.7247219549 31.8460262807 84.6193166128 +42.730252879 40.1966081237 80.9836908534 +42.732178527 69.650691074 57.643231617 +42.7523807154 -70.3983234159 -56.7125206934 +42.7559703075 32.9027602802 84.1981910079 +42.7595062268 -86.2518325233 27.0600445976 +42.7664197216 9.77125344808 89.8640971147 +42.7835774808 -70.2284897685 -56.8992506345 +42.7916332339 53.3172699993 72.9804415237 +42.8032128342 79.8276545815 42.3725209904 +42.8032509595 11.0138993393 89.7027074767 +42.8242656458 27.1561411574 86.1894788785 +42.8272622926 19.7889733761 88.1715494774 +42.8320570553 38.2559425102 81.8651192576 +42.832119827 -88.5236233032 18.1377404435 +42.8423842135 66.8107940809 60.8345946742 +42.8578601877 -70.0199393097 -57.1000168056 +42.8642222918 36.8040160432 82.5113498278 +42.8771371743 25.2767282032 86.7331431408 +42.8848001496 59.2865863902 68.161533069 +42.8850129428 10.2957806904 89.7489418593 +42.8861976325 -70.2588703629 -56.7843745053 +42.8867575341 5.87475501922 90.1455117112 +42.8869867531 23.5091341561 87.2240046001 +42.9066856348 11.1763544691 89.6331714747 +42.9164426526 70.5296753318 56.424674103 +42.9233332819 14.1539926348 89.2034301609 +42.923503669 -70.3752154812 -56.6118528114 +42.9339300799 8.69599593008 89.8947011936 +42.9490255813 25.8063780974 86.5413892373 +42.9579479123 43.5619807752 79.1010021561 +42.9590388981 -84.9707289729 -30.5695304963 +42.9851903471 7.11615211618 90.0090761528 +42.9872805117 -84.8059144972 30.9846829984 +42.9874674599 46.0178370333 77.6816343556 +42.9880710269 -70.3705179034 -56.5686835572 +42.9972459512 -84.6789297505 31.3163806484 +43.0016928847 -68.1008720902 -59.2716258391 +43.0066929694 72.1443986329 54.2734751581 +43.0436132738 -70.185788395 -56.7556381667 +43.0539471635 -84.6807334665 31.2334918512 +43.0575805139 25.5657204382 86.5588741769 +43.0707880641 -88.8981396596 15.5572484907 +43.0739782047 -85.0137427776 -30.2868938746 +43.0741436408 -88.2368961064 18.9438199716 +43.0745579782 62.2772079609 65.3156323064 +43.0787889592 44.8437443198 78.3151105291 +43.0850156628 25.4601118162 86.5763485696 +43.0895432282 -88.2293769063 18.9438199716 +43.0984299336 27.4250135701 85.9674006117 +43.1222749043 -70.149112471 -56.7412674039 +43.1338178901 24.6230544364 86.7938877136 +43.1447942723 68.1692639661 59.088731392 +43.1536326293 44.7337446752 78.3368117696 +43.1542690743 64.658190822 62.9049077599 +43.158148233 34.638075998 83.292124071 +43.1589689087 13.8319057246 89.1402366318 +43.1761017006 31.2313223852 84.6193166128 +43.2089222684 25.2492555288 86.5763485696 +43.2670518821 8.94442607039 89.7104200397 +43.3299113448 -66.7987577892 -60.5016094056 +43.3322693564 -84.9710292692 30.0372871173 +43.3332956688 38.9764099624 81.2592453382 +43.3406312422 -77.3269389264 -46.2831956524 +43.3489468558 12.5694237604 89.2349617181 +43.3597421314 22.0262067732 87.3772223035 +43.3766648781 12.585668439 89.219201375 +43.378860831 12.5780975912 89.219201375 +43.423307227 -84.6742905752 30.73566178 +43.4253160053 47.8075445479 76.3457963096 +43.428088088 8.62262585 89.6641036785 +43.4295623413 33.1803926463 83.7432663483 +43.4382933263 7.44845433401 89.7643314515 +43.4485722446 -88.7679869119 -15.2468380166 +43.4486721399 40.972601469 80.2088450119 +43.4526489725 25.3408359047 86.4274801954 +43.4647434744 65.1726334663 62.1558036049 +43.4667942735 29.2084735906 85.1909787835 +43.4947846397 35.9436719992 82.5606210755 +43.5061967402 24.8859915013 86.532642813 +43.5078946807 -70.3628520404 -56.179463803 +43.5143745571 63.4798143286 63.8499207495 +43.5264765387 77.5632689545 45.7097927059 +43.5455764772 -69.4175969505 -57.3147450739 +43.5466761133 44.2361348751 78.4018582101 +43.5512398122 -85.8441832078 -27.0936472296 +43.5685898168 10.12269787 89.438856037 +43.5915035128 10.7635873077 89.3528175816 +43.5915770034 6.49147236203 89.7643314515 +43.5919830671 26.4314495453 86.0297476877 +43.5963746471 18.0314719418 88.1715494774 +43.6071297308 -69.7318199206 -56.8848971802 +43.6192427005 31.7494298725 84.1981910079 +43.6321769813 10.1936719945 89.3997884961 +43.6325112746 10.596129015 89.3528175816 +43.6372882868 43.6830090917 78.6611834876 +43.6473033076 -72.8715916396 -52.7697266042 +43.6516027118 11.2890720466 89.2585818452 +43.6690542265 14.2732470395 88.8216647103 +43.6705539158 -71.600041453 -54.4639035015 +43.6817647467 11.2968724792 89.2428378124 +43.6866438293 7.38904271998 89.6486430383 +43.7132044962 70.4198252012 55.9482258102 +43.7357646284 14.1684272924 88.8056223469 +43.7431898457 28.0826287767 85.4277431699 +43.745068815 19.2482909532 87.8400378515 +43.7503859708 -84.8738282131 29.7041581577 +43.7520172037 20.9906286442 87.4365741536 +43.7574722623 27.5875586559 85.5815998251 +43.7625233167 41.4131073392 79.8110023334 +43.7678111673 55.9598239614 70.3766780108 +43.7842870625 40.3040465973 80.3649179326 +43.8070902602 9.11188787821 89.4310479768 +43.8102682402 9.09659576417 89.4310479768 +43.8196742013 -84.8263991666 29.7374874078 +43.8218748353 13.1638678172 88.9176915468 +43.8223425226 28.8078009583 85.1452459024 +43.839802385 63.8350326931 63.2705328563 +43.8441336379 19.1368080791 87.8150016915 +43.85636181 8.46922121123 89.4700610308 +43.859227803 52.6414802114 72.8370969882 +43.8867848042 52.6185083585 72.8370969882 +43.8906613258 46.8697793671 76.6605089369 +43.9055097541 -69.8017926262 -56.5686835572 +43.9127614244 35.15559596 82.6786154745 +43.9200615218 57.9254986212 68.6706983029 +43.9287209116 9.44156259519 89.3371388328 +43.9510161217 -66.832742194 -60.0141046146 +43.9807342016 45.3529083518 77.5165061333 +43.9914916395 -84.7957319369 29.5708050044 +44.0025391634 8.11567649363 89.4310479768 +44.005369388 8.10031621575 89.4310479768 +44.0055357377 13.8326839726 88.7252482586 +44.0072528399 -77.7192440521 -44.9786705168 +44.0130416577 -77.6346331533 -45.1189084442 +44.0197131057 -81.0742260097 -38.5906042324 +44.0203078874 13.8373274447 88.7171959808 +44.0259078534 -82.522514856 -35.3801353804 +44.0289904648 29.7538653251 84.7121921382 +44.0377479427 -84.5957267099 30.0705799504 +44.0499193193 -75.3824023694 -48.7554922136 +44.0628472931 22.4220888979 86.9236182972 +44.06763575 -75.3523258384 -48.7859659139 +44.0768202047 -68.6040158805 -57.885429304 +44.0835539757 -52.5367338249 72.7772757657 +44.0913658232 25.5897239655 86.0297476877 +44.091810051 -88.6280923088 14.1765136802 +44.1017780267 22.6457782515 86.845851382 +44.1204989109 38.1914261237 81.2083526892 +44.128495195 -67.1281377652 -59.5524057617 +44.1472504651 24.7945487506 86.2336977557 +44.1558515226 34.7098073276 82.7374767055 +44.1600054185 6.16699078671 89.5090059495 +44.1602947691 50.4438983425 74.1975840976 +44.1611151558 20.0788565107 87.4450423376 +44.1820932447 65.379504173 61.4285200099 +44.182432519 30.4452876974 84.3860006976 +44.2005258205 23.3733505769 86.6025403784 +44.2009837558 -87.7693571346 18.5152095101 +44.2021970625 42.3587742336 79.0689573744 +44.2064733439 11.9278219278 88.9017141486 +44.208571607 32.0605008493 83.771871662 +44.2106342459 11.9123902312 88.9017141486 +44.2217745316 -68.7504486295 -57.6004381105 +44.2222681135 13.9686883971 88.5960876527 +44.2241884568 56.5026758284 69.6539214946 +44.2297349323 -70.9751780022 -54.829322952 +44.2388306141 7.68113638295 89.3528175816 +44.241249583 8.69582671846 89.2585818452 +44.2477078948 32.0064659763 83.771871662 +44.2499982502 7.52405295785 89.3606528733 +44.2586442291 6.02333712634 89.4700610308 +44.26322149 13.7864582665 88.6041804419 +44.2742173816 25.0287493752 86.1008442465 +44.2843212803 9.63935174027 89.1402366318 +44.3161830357 12.8582680973 88.7171959808 +44.3233973593 12.9442753671 88.7010833178 +44.3405935133 28.280723736 85.0535856496 +44.3459218618 12.8668967691 88.7010833178 +44.3462325815 17.7372275718 87.8567152464 +44.3636905009 29.0639726599 84.7770514843 +44.3702336119 -85.1255721939 -28.0164117595 +44.3798542245 34.6110156655 82.6589749127 +44.3890572286 14.2090492436 88.4743720969 +44.3948892187 39.6936121217 80.3337473792 +44.3989319901 33.1542550288 83.2437998389 +44.4002885637 22.0888099762 86.8371973828 +44.4032430857 31.9657609812 83.7050902177 +44.4150989325 31.9742959696 83.6955398099 +44.4161123736 43.6171261077 78.2608156852 +44.4202285377 78.7689034157 42.6884428311 +44.43435067 31.6713180713 83.8004540093 +44.447381557 -81.8618933121 -36.3739013043 +44.454801709 34.8194453071 82.5310658693 +44.4560200722 22.65147361 86.6635622545 +44.4561574644 10.9606242954 88.9017141486 +44.4575799235 33.9903864305 82.8744666206 +44.4672135953 -87.9538195335 16.9349503849 +44.4854010132 34.9437413008 82.4620157442 +44.487002243 34.284348905 82.7374767055 +44.5056027552 37.1465171116 81.4824373094 +44.5256580416 10.3368721174 88.9416373291 +44.5326489975 7.05327868764 89.2585818452 +44.5350602135 36.999987617 81.5329953339 +44.5370235502 36.9753493425 81.5430994891 +44.5512180542 41.1394834836 79.5156077043 +44.5644230327 58.3933855885 67.8544377272 +44.586358562 48.5382841988 75.2069916777 +44.5997607708 35.7695031245 82.0451338314 +44.6123944309 64.1410365381 62.4152360803 +44.6178738581 34.1376256581 82.7276727994 +44.6266334682 -79.1349143654 -41.7867073801 +44.6495219998 78.501639261 42.9408059837 +44.6690225385 27.1058282802 85.2640164354 +44.6736668368 36.2018492639 81.8149717425 +44.6921723614 10.0964081562 88.8857259179 +44.6949012395 -71.6658827911 -53.5384632481 +44.7041942645 -84.6815453655 28.8196268134 +44.7059916528 -75.0545532318 -48.6640354832 +44.711715316 19.4412071251 87.3092319232 +44.7146818833 -75.0691428056 -48.6335380423 +44.7189737528 11.3156399705 88.7252482586 +44.7324123072 -53.3100130725 71.8126297763 +44.732532795 24.388968617 86.0475375565 +44.7396938678 -71.6819672722 -53.4794854183 +44.7431181876 -51.4710696035 73.1353701619 +44.7513519801 47.7387658321 75.619618703 +44.7738722483 11.2879662532 88.7010833178 +44.7862947745 12.5635605915 88.5231311332 +44.7908078482 6.1594716654 89.1955404777 +44.8074786225 21.4970006952 86.7765453369 +44.8076461894 34.8818008555 82.3136368534 +44.8079877712 -56.7367532782 69.0882411077 +44.8321352686 52.0669964785 72.6574670971 +44.8594438512 34.2728289357 82.5409201191 +44.864995197 -73.9934488869 -50.1208711795 +44.8803974502 33.5992670599 82.8060334622 +44.8872728447 20.9026726002 86.8804409216 +44.9280669189 49.323394525 74.4894056592 +44.9352812091 24.0133667593 86.0475375565 +44.9541703483 21.0102535324 86.8198814489 +44.9628204712 17.593584046 87.5717453046 +44.9638160821 62.7353689136 63.580883374 +44.9748128032 30.5878065806 83.9145535763 +44.9820091395 7.94773272249 88.9575876378 +44.9824643646 34.2302485187 82.4916237326 +44.9851853001 25.0178694807 85.734703068 +44.9946583038 62.6859290512 63.6078220278 +44.9964504455 44.3260797925 77.527531223 +45.0075466365 9.74742226619 88.7654691022 +45.0085835835 -88.3343189789 -13.0872263805 +45.0366794136 -79.8294680294 -39.9869171297 +45.0632875809 -71.0906280671 -53.9946544894 +45.0648634392 -84.8261000478 -27.8152985584 +45.0822272195 -88.9773600773 -7.11492674688 +45.0917031561 45.6778756685 76.6829184428 +45.1188859603 21.6173480712 86.5850818101 +45.1259856057 10.1447550926 88.66075438 +45.1334581704 52.9379661554 71.83691734 +45.1440614389 28.7267192674 84.4795201036 +45.1456093609 9.08655327964 88.7654691022 +45.1503608804 9.06291384937 88.7654691022 +45.1525601187 21.1221822162 86.6896748936 +45.1593922653 -23.3284670296 -86.1185921638 +45.1607965894 9.08961004558 88.7574303404 +45.1687115736 9.05019635985 88.7574303404 +45.1761953868 19.7839609301 86.9925643966 +45.1797329953 -23.2890491476 -86.1185921638 +45.1849305462 6.59176848971 88.9655587276 +45.1906164641 -84.2095481892 29.4373942013 +45.2017101037 12.5100595372 88.3193286551 +45.2041192085 19.9091256019 86.9494929505 +45.2071254339 14.2797797456 88.0477353509 +45.207703064 21.0039008407 86.6896748936 +45.2445153322 27.5307328222 84.8233021205 +45.2469264018 57.2309111622 68.3910700219 +45.2495259775 38.1306422062 80.6134884728 +45.2501917524 25.915029165 85.327788028 +45.2506745369 31.6025443835 83.3885822067 +45.2531310466 13.4475550491 88.1550758248 +45.2541226142 -72.4780194979 -51.951911188 +45.256343361 32.7962557773 82.923271719 +45.264125685 -51.5230730653 72.7772757657 +45.2926690491 13.4765123155 88.1303452065 +45.2949998774 23.4586423626 86.0119473365 +45.2957780855 40.0461406949 79.6529918024 +45.296768932 35.5810791692 81.7446605564 +45.3035748671 -69.0205929895 -56.424674103 +45.3040999928 -72.3611238909 -52.071165467 +45.3052563571 5.18591309492 88.9974159838 +45.3055172205 56.1076560911 69.2772764861 +45.326856537 13.4694635352 88.1138447042 +45.338509465 -87.9547180759 14.4356201001 +45.344255679 14.2534967082 87.9814543441 +45.366106136 7.73012504451 88.7815385136 +45.3666912166 42.5277179128 78.3151105291 +45.3722562338 -50.7461070292 73.2542898787 +45.3746646443 22.672434793 86.1806272255 +45.3756509326 40.1026489428 79.5790666583 +45.4074727777 36.8096290976 81.1369990919 +45.4077209024 54.1723935619 70.7353564932 +45.4192992306 5.79417628718 88.9017141486 +45.420270313 -87.6994971173 15.6779223773 +45.4335411238 11.6399968588 88.3193286551 +45.4555572754 29.654720004 83.9904154905 +45.4616333223 69.7912446367 55.3391549243 +45.4691339167 60.1646124483 65.6717387452 +45.4771095044 11.0188757078 88.3765630089 +45.4868352038 11.4930457377 88.3111415554 +45.5093815032 -80.7661408354 -37.4930218808 +45.5101078405 56.3610270015 68.936671806 +45.5167547807 -89.0241527554 -1.71033926951 +45.5240139876 43.5493194375 77.6596479968 +45.5411659608 18.6499431059 87.052753116 +45.5429261005 -65.2842535578 60.5293988043 +45.5473175616 10.7249696353 88.3765630089 +45.5513630009 33.9529395832 82.293810353 +45.5688863314 54.7906304497 70.1531425771 +45.6025498419 34.9541461929 81.8450677307 +45.6117542136 -51.5547097397 72.5374371012 +45.6233239381 5.78783731627 88.7975971074 +45.6243334114 5.77987445597 88.7975971074 +45.6316708489 -68.2926215525 -57.0426897773 +45.6387736839 -76.1060352196 -46.0974374535 +45.6493845241 63.5278408163 62.2924323959 +45.6524472484 -68.1948115189 -57.1429938149 +45.6532450802 17.5429255022 87.2240046001 +45.6625816087 14.1087345666 87.8400378515 +45.6635664387 -87.050094072 18.3608230249 +45.6687756346 48.513395085 74.5708617985 +45.6804459372 64.7081949014 61.0421687982 +45.7016646402 -51.475023729 72.5374371012 +45.7169913069 8.66310963304 88.5150113672 +45.7578789381 37.3857552097 80.6754102716 +45.764860924 50.7023184821 73.0400739673 +45.766779713 20.395828583 86.5413892373 +45.7755054473 -84.3782185944 28.0164117595 +45.7844329899 74.4215336665 48.6335380423 +45.7885619294 44.4032068696 77.017938275 +45.7948681852 34.0102705802 82.1348375719 +45.7999510075 33.2756121875 82.4323851484 +45.8039156726 4.91119826851 88.7574303404 +45.8051420071 -50.8717639566 72.8968627421 +45.8118726325 45.9399824731 76.0972426325 +45.8123122712 6.90392684963 88.6203579231 +45.837929036 12.2822360679 88.0229000821 +45.86065734 31.307482574 83.1663492238 +45.8676050754 12.2901877387 88.0063298291 +45.9013646725 -68.0515716649 -57.1143442153 +45.9031411012 39.1772830574 79.7373320929 +45.903408383 24.2328464472 85.4730732564 +45.9100303945 -82.0454227049 -34.0707751944 +45.9289469488 49.6856548863 73.6333316555 +45.9433171058 14.1340098692 87.6894599045 +45.95158734 10.482123069 88.1962398116 +45.9531720987 25.5772074748 85.0535856496 +45.972570553 14.1430094046 87.6726755708 +46.0101514825 -75.8820942039 -46.0974374535 +46.0139190473 -84.2205411273 28.1001727065 +46.019443443 -73.5893319011 -49.667102347 +46.0257326098 22.6774098095 85.833367766 +46.044908898 -68.8590303717 -56.0205346355 +46.0471127106 20.9848782537 86.2513669207 +46.0651289292 10.0438223829 88.1880123865 +46.0679297851 61.1342076641 64.3455864734 +46.0832433816 13.0663085374 87.7815826961 +46.083862019 23.4302665936 85.5996511019 +46.0934614561 9.83951696438 88.1962398116 +46.096071448 6.78221537867 88.4825053421 +46.0962477688 34.0845345572 81.9352210326 +46.1004589775 10.026242807 88.1715494774 +46.1044267114 7.53336531215 88.417363932 +46.1048379644 -69.6568117925 -54.9751988372 +46.1204076904 65.940225463 59.3699811383 +46.1215007499 -84.5928164181 26.7742895148 +46.122990984 12.9819617949 87.7732212617 +46.1454079545 -74.0780475477 -48.8164336698 +46.1460766526 26.5887834044 84.6379123481 +46.1501097041 7.54082981604 88.3928914562 +46.1618899151 10.8016766772 88.0477353509 +46.1622434621 47.3537866566 75.011106963 +46.1673665338 -80.1256229936 -38.0586232965 +46.1709799681 -5.11363742221 88.5555832294 +46.1725782732 -84.6864992229 26.3873049965 +46.1848124047 21.3697317657 86.0830858381 +46.1993478162 10.7764279904 88.0311811867 +46.2011014275 51.4016576225 72.2725938412 +46.2021835282 6.01701633755 88.4825053421 +46.2104766433 7.36036406284 88.3765630089 +46.213542307 -72.9615487342 -50.4075481823 +46.2306101863 7.42977341688 88.3602237931 +46.2319062223 7.42170454013 88.3602237931 +46.2358835819 36.2926727802 80.9016994375 +46.2382710812 -55.1046256764 69.4658370459 +46.2415429565 4.265279048 88.5636895101 +46.2459402381 51.3613199884 72.2725938412 +46.2525279136 -86.1883457888 20.7911690818 +46.2638659031 51.3451739812 72.2725938412 +46.2675757676 -11.0224913303 87.9648572867 +46.2690727449 -84.5121904124 26.7742895148 +46.2865126266 -36.2280799518 -80.9016994375 +46.2994858409 35.6811573416 81.1369990919 +46.2995179675 40.9335502999 78.6180583316 +46.3026471427 -72.9050338031 -50.4075481823 +46.3031999625 14.9733771324 87.3602406733 +46.3178385116 48.1649947005 74.396176791 +46.3185977067 21.1867555348 86.0564285593 +46.3320845795 17.5536565924 86.8631514438 +46.3353213547 41.8378056713 78.1193702712 +46.3376040545 -59.8890192515 -65.3156323064 +46.3567067119 32.495501559 82.4323851484 +46.3620293939 19.6317833041 86.4011302865 +46.3695095807 -70.1098475991 -54.1708210283 +46.3732441405 -6.25342615103 88.3765630089 +46.394350946 8.30587041769 88.1962398116 +46.4029524214 17.5805060159 86.8198814489 +46.4078836762 4.93499677667 88.4418121677 +46.4083162702 28.0837388526 84.0093553899 +46.4088760046 31.6342563749 82.7374767055 +46.4096034876 4.91879706896 88.4418121677 +46.4351911773 39.8982831718 79.0689573744 +46.4590762706 23.0827027428 85.4911870673 +46.4616653227 -5.93539300605 88.3520501477 +46.4669991645 -86.0106642912 21.0471759821 +46.5251529287 -83.9335977047 28.11692233 +46.5398943164 79.9635446124 37.9456159529 +46.5452094899 13.7254862869 87.4365741536 +46.5520596755 -83.0566646645 -30.5695304963 +46.5537370287 20.7757570608 86.0297476877 +46.5539638115 7.45673687073 88.1880123865 +46.5571695117 -83.8877397392 -28.20065759 +46.5712483075 4.54993866106 88.3765630089 +46.5892024185 -5.53068668398 88.3111415554 +46.5942092462 12.2411474063 87.6306680044 +46.5953958594 62.0592406005 63.0675807431 +46.5958173087 15.9260614962 87.035569594 +46.6116824565 14.759239379 87.2325392932 +46.6389428184 14.5710737149 87.2496007073 +46.6508805628 -86.2070605747 -19.7999507521 +46.6575558436 6.4493724653 88.2126866018 +46.6640356046 11.6606063031 87.6726755708 +46.6870598324 15.5126195401 87.0613408995 +46.6878129532 44.5690967831 76.3796028635 +46.7012339983 34.3933895995 81.4621967227 +46.7083466055 -86.457399697 18.532360751 +46.7192529098 -88.1628827717 -6.67963389185 +46.7238706861 4.0713749558 88.3193286551 +46.7281303638 14.4379657232 87.2240046001 +46.7294721355 64.959140839 59.9722140278 +46.7316632065 43.0925447521 77.1957527377 +46.7393658503 38.5700802757 79.5473480855 +46.7468529265 8.34371928351 88.0063298291 +46.7604789057 22.2235138448 85.5545033584 +46.7675304148 -75.6344761569 -45.7408364087 +46.7937440151 5.37284315345 88.2126866018 +46.8026510031 -85.593155821 21.9846204353 +46.8098178205 16.2368062394 86.8631514438 +46.8099229895 16.917239451 86.7331431408 +46.8205656953 5.54157913364 88.1880123865 +46.8211137809 21.5650151729 85.689750991 +46.8234844208 33.1774193176 81.8951778441 +46.8395549295 25.3471869713 84.6379123481 +46.8403966206 13.4755155792 87.317740032 +46.8437539604 16.9572022078 86.7070701164 +46.8556610676 -75.9250480403 -45.1656296979 +46.8564602262 79.5464844282 38.429532266 +46.863265713 79.5580378521 38.3973038094 +46.8637927365 -86.3842640084 18.4809053369 +46.8684584916 18.3486778045 86.4099162217 +46.8698797931 -85.4325096691 22.4610921331 +46.8729888479 20.2352076036 85.9852271597 +46.8904305504 -79.6041545947 38.2683432365 +46.8976942079 16.0749611419 86.845851382 +46.9047970871 45.2638052379 75.8361915289 +46.9071685934 -84.6924794196 25.0380004054 +46.9092146075 25.3425601806 84.6007105668 +46.915471545 -84.6377511283 25.2069358243 +46.9159264604 -85.3397534214 22.7161248969 +46.9204772674 12.6776887751 87.3941932872 +46.9219196105 79.5623216457 38.3167122078 +46.9227815815 20.422084867 85.9138581274 +46.9253743902 10.2056510474 87.7146163706 +46.9317650128 23.6350162595 85.0811109424 +46.9398715114 5.03299799387 88.1550758248 +46.9417847579 -67.2894704182 -57.1716364519 +46.9425346597 -34.7356484114 -81.1777874123 +46.9578665915 14.3116637155 87.121381112 +46.9656206022 9.25685854035 87.7982975428 +46.9689305825 42.2910150529 77.4944488704 +46.97081913 0.819878697646 88.278366258 +46.9768147971 12.166526694 87.4365741536 +46.9781344427 79.4356871836 38.5100829128 +46.981058854 12.1501279513 87.4365741536 +46.9815474259 10.8638200207 87.6054314299 +46.9847036477 28.9617330402 83.3885822067 +46.9960232429 -77.6914340988 -41.8976713794 +47.0051006167 -84.869299 24.2429908069 +47.011040097 5.09043028112 88.1138447042 +47.0121383991 49.1953926986 73.2780470562 +47.0255070127 8.26647996823 87.8650499296 +47.0361906826 17.0918879716 86.5763485696 +47.0367733365 -84.856585353 24.2260577957 +47.0476032406 7.77180838406 87.8983618946 +47.0492799857 29.4910767793 83.1663492238 +47.0560301069 -84.4735968657 25.49394954 +47.0604107017 -67.0845566558 -57.3147450739 +47.064539089 63.9068169381 60.8345946742 +47.0753140058 11.067422976 87.5295776291 +47.0788070705 10.7133257732 87.5717453046 +47.0827654781 -86.3559006491 18.0519145251 +47.0857804849 72.4226972478 50.3773977046 +47.1029800796 15.9893071932 86.7505119472 +47.1044583566 46.079802598 75.2184937064 +47.1063912725 30.5328366667 82.7570769564 +47.120540372 46.0633572332 75.2184937064 +47.1212501909 -84.9390484191 23.7685892326 +47.124257198 -67.1008122113 -57.2432125595 +47.1245264029 -86.2533163049 18.4294448562 +47.1258163574 32.2677199039 82.0850271661 +47.1275598795 -72.9876983781 -49.5155428655 +47.1451502933 6.62581877439 87.9399416044 +47.1460068143 46.0560793409 75.2069916777 +47.1657177113 -84.914364148 23.7685892326 +47.1697435386 -84.9216120089 23.7346815507 +47.1813155036 37.0214792079 80.0208319415 +47.1837838757 -72.8792312938 -49.6216503675 +47.1850609823 20.83076928 85.6717518865 +47.1936407634 74.6529576479 46.9009188174 +47.1999190901 52.0177572678 71.1780904964 +47.2051010094 27.1660674981 83.8670567945 +47.2063163576 -86.2955995164 18.0175803048 +47.2326385038 6.55407020148 87.8983618946 +47.2332192421 -72.8162203391 -49.667102347 +47.2365644352 13.2509162101 87.1385115776 +47.2416150701 -76.282079318 -44.1505852792 +47.2485208064 15.2608564026 86.8025549363 +47.2615599987 9.57252999279 87.6054314299 +47.2856315014 6.39326821261 87.8817112662 +47.2949652689 22.6599505833 85.1452459024 +47.3201075025 -86.1461722205 18.4294448562 +47.3504179961 51.1696171764 71.691060765 +47.3808781034 -74.7467964182 -46.5614520325 +47.4051638575 -87.1280453818 12.7064608601 +47.405374236 24.1750919461 84.6657866138 +47.4098389385 4.17283833599 87.948249511 +47.4122430416 -78.5961734796 -39.6827509647 +47.4135826073 40.3806683897 78.2390810577 +47.4294939738 14.4825499167 86.8371973828 +47.4415030621 3.98377431794 87.9399416044 +47.4497426026 3.88440440152 87.9399416044 +47.4724925594 19.975100407 85.7167300702 +47.4879771444 37.8007147909 79.473253287 +47.4897545295 5.63759281909 87.8233497535 +47.4930329249 8.34866501703 87.6054314299 +47.5071641479 4.92614867115 87.8567152464 +47.5112590054 16.7499990211 86.3835505204 +47.5235823917 8.78223982279 87.5464527 +47.5419490111 4.88782512721 87.8400378515 +47.545188095 -5.56003935196 87.7982975428 +47.546086826 7.47102615193 87.6558805544 +47.5462116119 12.6955085083 87.052753116 +47.5492587619 13.2044525805 86.9753437661 +47.5538650884 13.1878539539 86.9753437661 +47.5638845899 13.2085141801 86.9667294767 +47.5666693334 16.1281935244 86.471344052 +47.5714297821 11.6142584021 87.1898392604 +47.5721386755 51.6437868494 71.2026045991 +47.5754810247 11.5976521332 87.1898392604 +47.5793334147 68.1526648302 55.6005513314 +47.586077174 17.6498486668 86.1629160442 +47.6013720719 -70.5188259691 -52.5471651072 +47.6038444898 79.0072968759 38.622804535 +47.6150659024 -71.9385173116 -50.5732659231 +47.6162772576 17.3497330817 86.2071743077 +47.6221771054 44.0214877083 76.1198848376 +47.6233455587 16.0547910318 86.4538064097 +47.6262678797 47.1301200586 74.2326773808 +47.6266558655 4.81254606765 87.7982975428 +47.6356237242 35.7398430944 80.3337473792 +47.6555832792 26.3072953298 83.8860631735 +47.659505787 40.9936421122 77.7694851116 +47.6649957069 21.6920565685 85.1909787835 +47.6702682348 28.1921180448 83.2631371411 +47.6744583715 75.617919506 44.8227204503 +47.6827400563 -67.0961333667 -56.7843745053 +47.6937850817 7.61369571133 87.5633171036 +47.7095002353 6.90054530499 87.6138462904 +47.7112875529 12.9002974782 86.9322458298 +47.7212624762 21.7478322576 85.1452459024 +47.7223839759 -85.8459460474 18.7895613278 +47.7385507676 13.9778198412 86.7505119472 +47.7748124397 -87.2624802333 -10.14035699 +47.7770380333 78.1792755787 40.0668879095 +47.7903386943 -85.6862422995 19.3378232506 +47.7954322451 -82.0219594803 -31.4323848843 +47.8035354458 15.1641746805 86.515142057 +47.81074011 10.9325581403 87.1470728289 +47.8116410173 3.97284100336 87.7397487892 +47.8134306517 20.8097198341 85.327788028 +47.8202459231 -85.6695551044 19.3378232506 +47.8264646479 33.9257230833 81.0041640446 +47.832318397 15.1733051704 86.4976307593 +47.8387540148 15.202920118 86.4888711581 +47.8407583103 19.3969441155 85.6447336576 +47.8432390784 78.0730704078 40.1947776656 +47.8437145109 7.83470871395 87.4619707139 +47.8451989494 8.46223243424 87.4026747859 +47.8483150416 9.36145120511 87.3092319232 +47.8483532981 5.98527114135 87.6054314299 +47.8765739225 7.82293039907 87.4450423376 +47.8786939738 5.98906640614 87.5885937035 +47.8833824862 7.78114723314 87.4450423376 +47.8968157208 5.58421236956 87.6054314299 +47.9089033491 23.3977937311 84.6007105668 +47.9095715392 39.1019486652 78.5856893175 +47.913532165 16.9670716152 86.1185921638 +47.9280298919 78.1195932164 40.0029137237 +47.931885045 35.5065830328 80.2609304542 +47.9527157977 24.4647639361 84.2734381236 +47.9580170788 6.33082416997 87.5211360941 +47.9635253489 9.16688462749 87.2666514903 +47.9669213976 7.83769298443 87.3941932872 +47.9843199668 10.2168898092 87.1385115776 +47.9933632993 78.8421898113 38.4778661699 +48.001213193 1.42464274906 87.7146163706 +48.0036265524 1.34086270022 87.7146163706 +48.0110626716 22.7767944251 84.7121921382 +48.0119224637 14.3860011517 86.532642813 +48.0157580091 39.1886139757 78.4776370533 +48.0179211028 -81.0969285263 -33.4300379384 +48.0338546446 25.4540883059 83.9335343977 +48.0449196145 8.64464547974 87.2751728945 +48.0477552455 30.3980097535 82.2640518021 +48.0482480511 39.2570652657 78.4235212544 +48.0502009124 41.8430761131 77.0735698776 +48.0686754726 15.572096184 86.2954938496 +48.0767507732 72.8292145874 48.8316653174 +48.0938753435 12.9947353288 86.7070701164 +48.0943819582 64.2423233089 59.6645147464 +48.1026938845 -66.9419820614 -56.6118528114 +48.1197831861 0.965955667071 87.6558805544 +48.1202206458 1.53745984552 87.6474790409 +48.1375628073 1.90815934386 87.6306680044 +48.1421032205 -87.2812650165 8.01989243289 +48.1422251035 15.7353046477 86.2248592329 +48.1664892739 0.924843840941 87.6306680044 +48.1868202738 77.9602286138 40.0029137237 +48.1919185543 78.6420635987 38.6389029217 +48.210509285 46.3454146729 74.3495079559 +48.2217916011 4.5413189469 87.487343296 +48.2252880979 32.552865855 81.3303910756 +48.2296517347 52.5965575605 70.0535711176 +48.2321254175 59.1805938788 64.5857521893 +48.2577673433 -87.5270816759 3.19340951597 +48.2629154332 50.947469555 71.239359485 +48.2692109116 10.8336830492 86.9063552887 +48.2864913976 21.46824363 84.8971687629 +48.3041225275 10.8858041555 86.8804409216 +48.3069671405 1.43371731437 87.5464527 +48.3082953121 37.2023956241 79.2609005996 +48.319332017 0.927778571532 87.5464527 +48.32525829 29.2668167179 82.5113498278 +48.3283552444 80.1148300332 35.2984997999 +48.3363675034 11.8725505895 86.7331431408 +48.3454448049 74.7306796585 45.5855622364 +48.3591499076 16.3686691734 85.9852271597 +48.3613283612 43.0883718253 76.1877557918 +48.3668180817 58.9246518299 64.7189023035 +48.3805644915 12.9182924846 86.5588741769 +48.4047633021 1.7157076295 87.487343296 +48.4151637063 -76.3784575122 -42.6884428311 +48.4169573301 15.6195893759 86.0919663536 +48.4454844505 21.9452680528 84.6843565628 +48.4474558744 16.8048497185 85.8512728225 +48.4648520336 15.8126730867 86.0297476877 +48.4729298618 -75.0713084511 -44.8851168881 +48.4776764738 5.05244093531 87.317740032 +48.4778545416 24.4030269593 83.9904154905 +48.4817101753 -76.2477944479 -42.8462089374 +48.482976402 15.6595746959 86.0475375565 +48.4978636992 15.7111339311 86.0297476877 +48.5013279259 11.179582745 86.7331431408 +48.5031615496 82.737794522 -28.31785086 +48.5134746037 7.79665512782 87.0956655104 +48.5156268974 14.4908011554 86.2336977557 +48.5281996106 45.4436697297 74.6986393721 +48.5321569028 65.3009711823 58.141318432 +48.5469308964 -75.0421297367 -44.8539214018 +48.5492343818 26.8006172422 83.2147748683 +48.5599084561 40.0296994323 77.7145961457 +48.5653622024 29.7842158213 82.1845854285 +48.5735661631 58.5487155251 64.9049811691 +48.5744409705 -70.7555882041 -51.3241699622 +48.5786530548 5.92168119495 87.2069272432 +48.5857675725 15.3376813712 86.0475375565 +48.602282109 42.4732202713 76.3796028635 +48.6072974803 51.4907103032 70.6118784917 +48.6101117755 64.0878979164 59.4121062902 +48.6275382435 0.763902414028 87.3772223035 +48.6292009863 -84.5687724621 -21.9846204353 +48.6296542867 63.7201148485 59.7904983058 +48.6410146019 10.3389668199 86.7591923867 +48.6432478327 20.1486929702 85.0168489882 +48.6501374825 28.0655317309 82.7374767055 +48.6569558373 20.1543710116 85.0076583478 +48.6597356159 49.2578877794 72.1518580586 +48.6663112993 38.2004273429 78.564098005 +48.6670387227 6.43306265314 87.121381112 +48.6684347478 43.5604784499 75.7223096347 +48.6704003951 6.40757977059 87.121381112 +48.6721511084 19.4871820549 85.1543976671 +48.6744571175 -75.5859042876 -43.7900479257 +48.693801051 7.01688392295 87.0613408995 +48.6964192088 4.02068808291 87.2496007073 +48.6992577512 5.54857955572 87.1641873673 +48.7022576438 -74.0575694623 -46.2986663495 +48.7040254249 -0.748098955698 87.3347482699 +48.7063869504 7.03605323747 87.052753116 +48.7225844649 -68.0048213654 -54.7855275974 +48.7362319491 5.4924851173 87.1470728289 +48.7445875314 -75.6948088562 -43.5231099372 +48.7487417243 15.7642084167 85.8781107925 +48.7519990513 49.8360752356 71.691060765 +48.7653656795 77.8291504782 39.5545502563 +48.7667589552 35.4311243339 79.7899658444 +48.7669449995 1.36218411503 87.292207727 +48.7689291193 -75.24123232 -44.2758231039 +48.7710270503 9.5508167111 86.7765453369 +48.7714028045 1.19194741056 87.292207727 +48.803536145 23.1005968141 84.1699310121 +48.8095560353 50.5967651936 71.1167673026 +48.8138485779 23.7237917025 83.9904154905 +48.8190635573 7.31348053363 86.9667294767 +48.8239425145 14.6664634499 86.0297476877 +48.845492747 13.6195289553 86.1894788785 +48.8489301377 58.3191687513 64.9049811691 +48.8500251099 15.9855250517 85.7795898543 +48.8560885971 58.2244191058 64.984610692 +48.8567473115 -0.724857614846 87.2496007073 +48.8785612044 -87.1005716586 4.93727367461 +48.8860798631 11.3941371513 86.4888711581 +48.8875699088 -0.699712001161 87.2325392932 +48.8897308238 6.71444686773 86.9753437661 +48.8979704355 41.8662378935 76.5258558393 +48.8982835758 58.2334112734 64.944804833 +48.8990894021 16.3139704162 85.689750991 +48.9072859948 30.6438098228 81.6641555162 +48.9114142835 10.5928948429 86.5763485696 +48.9167055015 1.45181392646 87.2069272432 +48.919488658 21.01747099 84.6472063486 +48.9304905284 0.871170161134 87.2069272432 +48.9307916431 0.85409014512 87.2069272432 +48.9340390926 5.89567402516 87.0097744272 +48.948964591 8.85141471021 86.7505119472 +48.95497379 -87.0586336897 4.91984159261 +48.9658976685 6.2553041209 86.9667294767 +48.9785004039 16.1696452304 85.6717518865 +48.9832741437 -86.577643945 10.2445313747 +48.9877579736 14.9022992644 85.8959896931 +49.0062780135 47.2092420495 73.2780470562 +49.0167429905 6.4531766383 86.9236182972 +49.0205034498 25.2688725319 83.4174701276 +49.0323450005 12.3888808969 86.2690255763 +49.0362252202 71.9383464876 49.1967775447 +49.0566002218 24.1601136461 83.7241833838 +49.0664026135 -73.990875893 -46.0199784784 +49.0668650822 -75.8458256223 -42.8935133403 +49.0828986596 0.856745182968 87.121381112 +49.099075457 31.2193574047 81.3303910756 +49.1049127903 10.4107014968 86.4888711581 +49.1087170145 -1.08870648623 87.104240031 +49.1178819281 58.2261554103 64.7854034566 +49.1307612943 5.09450393016 86.9494929505 +49.1358083705 51.868915886 69.9663340513 +49.1564802895 5.14053309778 86.9322458298 +49.1597646396 58.1315536426 64.8385688589 +49.1635806655 9.27178214153 86.5850818101 +49.1642605545 22.3225938804 84.1699310121 +49.1665756359 46.0898117827 73.8808303288 +49.1741294264 5.40281460002 86.9063552887 +49.1755031763 79.466727621 35.5922616389 +49.1792941409 -2.49131556687 87.035569594 +49.1796024908 57.8471769429 65.0774217266 +49.1814159688 4.57973786954 86.9494929505 +49.1824065405 5.73409732641 86.8804409216 +49.1825083793 -1.18481657193 87.0613408995 +49.1846273365 -71.6176196791 -49.5155428655 +49.2016336581 9.31453415943 86.5588741769 +49.2052193965 -25.7020009033 -83.1760394207 +49.2064351543 58.1661488496 64.7721071713 +49.2108327743 4.59114066883 86.9322458298 +49.2135856574 -78.3620017958 -37.9133177301 +49.2168931683 56.0224138736 66.6272209433 +49.2256175607 19.9384278241 84.7307362866 +49.2348244208 77.6715321661 39.2818680211 +49.2403876506 -58.6824088833 64.2787609687 +49.2471239259 -84.0068624396 22.75011754 +49.2494929214 74.042307714 45.7408364087 +49.2568209366 77.7062332767 39.1855445435 +49.2571455959 -84.0239576319 22.6651307437 +49.2624318405 36.1868537333 79.1436947965 +49.2638373093 20.506556257 84.5727821704 +49.2660965693 10.0053929525 86.4450336381 +49.2760336814 11.0415916612 86.313126222 +49.2779228834 -35.1496007931 79.6002002535 +49.2811483907 13.5095352702 85.9584834096 +49.2856505237 10.9985860109 86.313126222 +49.289138492 7.93896346647 86.6461406284 +49.2904260101 9.25116741838 86.515142057 +49.3061751415 -1.09308399713 86.9925643966 +49.3080961266 9.15651960262 86.515142057 +49.3149890199 56.4910146814 66.1573663187 +49.3264592906 28.9049550844 82.0451338314 +49.3286080803 58.1662981121 64.678977951 +49.3359513583 -1.11958935746 86.9753437661 +49.3365449001 14.5205348117 85.7616429769 +49.3376463337 13.1277326508 85.9852271597 +49.3503067487 38.3905068582 78.0430407338 +49.352456987 28.7468833874 82.0850271661 +49.3658755088 48.2077935187 72.3810678237 +49.3697895583 4.51906812298 86.845851382 +49.3745148658 15.9189891511 85.4911870673 +49.3820996098 -68.5203706291 -53.5384632481 +49.3833856149 12.8358007265 86.0030432306 +49.3862236775 54.6951855594 67.59761525 +49.3945790624 -78.6806814988 -37.0071063192 +49.3966507517 9.09271974427 86.471344052 +49.3968299736 5.17438345242 86.7938877136 +49.3973861916 55.4424108547 66.9778867692 +49.4045196397 13.2841209514 85.9227884191 +49.4122976775 54.2082974737 67.9697382902 +49.415720692 33.7344012096 80.1253812691 +49.4189464652 77.3337136048 39.7147890635 +49.4205920382 69.0299525319 52.8438334722 +49.4227039823 33.0231950292 80.4168198895 +49.4497527211 14.0208387852 85.7795898543 +49.4501021139 25.7969662331 83.0012285095 +49.4564504322 52.5186278433 69.2520991747 +49.4589411357 8.30321242618 86.515142057 +49.4595876663 11.7190985834 86.1185921638 +49.4608359788 77.6977984191 38.9445480794 +49.4683275731 -83.9135607302 22.6141303767 +49.4727810537 77.7465135036 38.8319916157 +49.4736034654 31.9202370994 80.8298275618 +49.4839907936 17.2321487835 85.1726934143 +49.48857978 44.3568121697 74.7218420912 +49.4891456885 -76.7038904507 -40.8330460381 +49.4898302847 -79.7256855919 -34.562577382 +49.4988260814 54.1132201205 67.9825391166 +49.547693226 11.8679137355 86.0475375565 +49.5561062945 -83.2963258027 -24.6153293029 +49.5617010282 33.6441749338 80.0731370949 +49.5733128965 -77.218370636 -39.7468223232 +49.5888306305 15.0851483063 85.5183382514 +49.5913993099 52.7725493364 68.9619543736 +49.6080766112 12.0656307435 85.9852271597 +49.6092309444 -66.7258672999 -55.557023302 +49.612051836 8.747943307 86.3835505204 +49.6153193048 24.113310766 83.4078433613 +49.6175077946 21.184134423 84.1981910079 +49.6211833801 -76.6439951096 -40.7852445573 +49.6265196758 26.3313633916 82.7276727994 +49.6500449848 -86.5887047554 6.10485395349 +49.6557407388 78.003973405 38.0747625693 +49.6806217739 57.0101969207 65.4344960034 +49.686655159 27.2816009183 82.3829506054 +49.6879153817 54.5489005329 67.49465546 +49.6977681816 15.6410422439 85.3550797275 +49.6980160118 -73.5971858491 -45.9734862673 +49.7071779204 56.2232779806 66.0919017453 +49.7265289614 47.4699143477 72.6214813211 +49.7272559566 -74.7040206645 -44.1192623644 +49.7273448674 -3.47727469299 86.6896748936 +49.7367490592 77.4729486226 39.0409787882 +49.7406242234 -1.79782724177 86.7331431408 +49.7454202946 7.15070045426 86.4538064097 +49.7474211219 12.7452056624 85.8064905724 +49.7481123198 41.9957842305 75.9044098026 +49.7652457677 -66.8869367829 -55.2228032744 +49.7716074048 23.3465111638 83.5327930385 +49.775994849 22.2137693438 83.8385280663 +49.7814560845 1.4774791246 86.7157637662 +49.783423063 8.46492940929 86.313126222 +49.7860011358 -1.79946734682 86.7070701164 +49.7895638407 50.9856442453 70.1531425771 +49.7928148765 -1.02562231461 86.7157637662 +49.7963417005 47.4701580411 72.5734693176 +49.8029352829 14.6294697551 85.4730732564 +49.8045916351 -75.0471574095 -43.4445257404 +49.8109581773 56.6986238833 65.6059028991 +49.8154128225 13.2548564842 85.689750991 +49.8175760931 -85.526481191 14.2628933706 +49.8376449003 55.6425725038 66.4839324646 +49.8439478674 38.0396984349 77.9009769128 +49.8546114195 -86.5250088753 -5.28588302466 +49.8606168935 8.46014829179 86.2690255763 +49.8732119714 6.31813951804 86.4450336381 +49.8737968414 22.1739619167 83.7909291125 +49.8740930912 58.1891028544 64.238642166 +49.8750429302 74.586901747 44.1505852792 +49.8836065132 74.5997083751 44.1192623644 +49.8842632733 6.1073427084 86.4538064097 +49.8872478803 14.6069571035 85.4277431699 +49.8878860255 74.6061082806 44.1035988909 +49.8952229586 -86.490770242 -5.46016381259 +49.9002134174 -73.5086969292 -45.8959712465 +49.9073229463 36.6337589807 78.5316930881 +49.9116165442 53.7489089258 67.9697382902 +49.9247719588 4.42931966073 86.532642813 +49.9310308852 -73.5264757972 -45.8339340618 +49.9312955266 6.45835987332 86.4011302865 +49.9348485698 57.3019307836 64.984610692 +49.9430864238 51.4833000196 69.6789633789 +49.9441541521 62.788407093 59.6925238263 +49.9461139408 38.8400055372 77.4392644082 +49.9535575314 29.3310220801 81.5127795729 +49.9546361452 -86.4542601893 -5.49501799124 +49.95543019 36.5216955883 78.5532987588 +49.9587009801 10.6646250961 85.9674006117 +49.9720797489 5.04954487181 86.471344052 +49.9770232375 62.7622477893 59.6925238263 +49.9785076406 76.1718918882 41.2309551211 +49.9871382126 45.1985500125 73.8808303288 +49.991174044 9.35559392798 86.1008442465 +49.9916554508 1.96417749215 86.5850818101 +49.9941716187 8.11519897663 86.2248592329 +50.0084510839 -75.1833349709 -42.9723278732 +50.0093763269 13.5122945424 85.5364260161 +50.0136447738 26.7384618077 82.3631592194 +50.0238467207 14.4575596956 85.3732611941 +50.0353280829 9.52664931878 86.0564285593 +50.0411141139 10.7096162348 85.9138581274 +50.0464489747 42.5627526401 75.3907489863 +50.0481233174 14.5876976472 85.3368878608 +50.0523498772 -69.1954481465 -52.0264569962 +50.0559091905 28.5282336381 81.7346061384 +50.0559257732 29.9934617624 81.2083526892 +50.0562981527 20.7851931646 84.0377460452 +50.0637682003 76.0122628878 41.4216731225 +50.0638817 73.9440442692 45.0098441037 +50.0639297343 52.904117394 68.5182990326 +50.0639792584 12.8356190829 85.6086728292 +50.0735074123 14.5003250196 85.3368878608 +50.0752445411 1.74866607186 86.5413892373 +50.0828646122 4.6901321214 86.4274801954 +50.0871464529 -69.1926790407 -51.9966434242 +50.0879676983 20.7471155323 84.028285053 +50.0896073041 77.1312313388 39.2658170968 +50.094748167 74.972088786 43.2400521409 +50.1062014887 56.099825025 65.8952062334 +50.1155909769 79.1832017684 -34.906275922 +50.1178344881 19.7722597087 84.2452397007 +50.1252158978 9.85234810909 85.9674006117 +50.130711702 7.22394591088 86.2248592329 +50.1426323215 -77.1539082954 -39.1534271632 +50.1458365328 13.4646817701 85.4640124453 +50.1568913226 45.9281244852 73.3136660803 +50.1597618538 25.1400411829 82.7766671236 +50.1683539505 -1.13847921481 86.4976307593 +50.1707523359 11.3064673507 85.7616429769 +50.1779632988 9.25465041301 86.0030432306 +50.186203569 19.799232367 84.1981910079 +50.1931696619 17.4496482038 84.7121921382 +50.2140360245 6.50384174951 86.2336977557 +50.2145722851 75.3505416369 42.4357467855 +50.2150096284 -86.278024942 5.87836883186 +50.2161356919 5.60601974923 86.2954938496 +50.2318307634 17.2471883649 84.7307362866 +50.2347302755 56.0465311947 65.8426777644 +50.2349407932 7.23896555237 86.1629160442 +50.2565911698 -75.7282448176 -41.7074091841 +50.2782828622 11.8389640901 85.62670846 +50.2789801957 8.1434178381 86.0564285593 +50.2821651902 -81.7324930147 -28.1336710971 +50.2847714796 -73.6318718563 -45.2745977805 +50.3167143383 15.4025709754 85.0352224996 +50.3220877842 15.3850061907 85.0352224996 +50.3229650252 57.7269628557 64.3054970475 +50.32687241 9.19131893232 85.9227884191 +50.3271561914 22.1235132126 83.5327930385 +50.3343438752 7.07403070242 86.1185921638 +50.3380971886 48.9516605411 71.2026045991 +50.3410895067 41.6161811182 75.7223096347 +50.351366829 39.4805146916 76.8506917219 +50.3625596587 -80.0363321016 -32.5238086383 +50.3658912663 9.63514149972 85.8512728225 +50.3733501923 13.9887041618 85.2457726006 +50.3806173535 55.4647341699 66.2227805105 +50.3839182237 9.12906014204 85.8959896931 +50.3891175028 79.4925138251 33.7916718003 +50.39080433 53.9808275221 67.4302387584 +50.392735724 79.1007504574 -34.6935651573 +50.400374234 4.85300406379 86.2336977557 +50.4040845611 52.4142003121 68.6453193248 +50.4203103221 26.2136072189 82.2838933425 +50.4294137975 -72.0742002488 -47.562420907 +50.4300361714 79.5570660139 33.5780389393 +50.4330916083 1.40872380382 86.3395550607 +50.4409376156 58.539589754 63.4730513202 +50.4453450413 61.3694798484 -60.7375839723 +50.4486370521 14.1614729508 85.1726934143 +50.4523614646 12.7008444688 85.4005138885 +50.4614122738 27.6268162488 81.7948952887 +50.4644700034 10.2946322588 85.7167300702 +50.4672622216 11.8834628224 85.5092904614 +50.4680348564 22.7024123271 83.292124071 +50.4686970627 13.1178964415 85.327788028 +50.4855387746 14.0293503481 85.1726934143 +50.486821391 37.1133969073 77.9337964931 +50.5009278874 43.5604784499 74.5126901925 +50.503876901 74.7062051144 43.2243141689 +50.5114738129 23.307490888 83.0984469274 +50.5127218927 33.7770320782 79.4202557977 +50.5189536065 10.7657849136 85.62670846 +50.5212507984 8.51782275417 85.8781107925 +50.524336595 21.780127556 83.5039966425 +50.5283914199 5.08794147742 86.1451943641 +50.5403060738 56.387459939 65.3156323064 +50.5404444601 50.2414177779 70.1531425771 +50.5499045154 13.1013361421 85.282249881 +50.5658468765 -79.8946111931 -32.5568154457 +50.5765069618 -85.7933752093 9.02849454487 +50.5834473702 31.6940412838 80.2296865209 +50.5860358989 1.32464196854 86.2513669207 +50.5867371847 47.7539456809 71.83691734 +50.5923178404 9.40413455582 85.7436856497 +50.5952612602 58.1416779229 63.715499106 +50.5957996292 11.7926305785 85.4458830133 +50.6199043576 76.5363665066 39.7468223232 +50.6424116713 55.9881073328 65.5795545685 +50.6476973114 78.1398162457 36.4551762325 +50.6511572178 78.1451542269 36.4389234658 +50.6637594105 76.6317394303 39.5064550964 +50.6828915032 61.8562853643 60.0420225326 +50.6881956821 -1.44241088133 86.1894788785 +50.7043156772 9.85592055595 85.62670846 +50.7210727564 -72.7881421739 -46.1438959919 +50.7323184205 63.4376572796 58.3257705184 +50.7350123447 43.0264194411 74.6638182285 +50.7359773708 1.3462908279 86.1629160442 +50.736444224 1.32858054915 86.1629160442 +50.7365549128 12.0403731604 85.327788028 +50.7500457046 21.0213572219 83.5615665335 +50.7517578443 25.0830810399 82.4323851484 +50.7554008164 40.9837060737 75.790666473 +50.7601127359 16.8364579304 84.4981931132 +50.7618332368 52.01758317 68.6833846544 +50.7678099701 4.63810129473 86.0297476877 +50.7747947913 57.3299508405 64.3054970475 +50.7766107604 12.6317953247 85.2183873736 +50.7782020157 -79.705811336 -32.6888029655 +50.7815607694 57.4587074926 64.1851230356 +50.786325588 8.7449390876 85.6987466281 +50.7881052663 16.8457426824 84.4795201036 +50.8239101558 28.6728723707 81.2083526892 +50.8323809354 44.3439122084 73.8219919705 +50.8414900002 56.8032268378 64.7189023035 +50.8692226189 4.34314407427 85.9852271597 +50.8816579964 11.2056791066 85.3550797275 +50.8825681244 -73.2104210236 -45.2901591366 +50.8829935198 53.0602950309 67.7903094969 +50.8838435389 21.4941770425 83.3596714243 +50.891029323 7.62387733745 85.7436856497 +50.9037639908 -2.15130007656 86.0475375565 +50.9061787808 17.5085290291 84.2734381236 +50.9125250489 26.7863752279 81.7948952887 +50.9133849649 29.5134569717 80.8503746992 +50.9147835457 6.70305841791 85.8064905724 +50.9236840028 29.49568305 80.8503746992 +50.9243095237 11.01022544 85.3550797275 +50.9379842328 37.8023050945 77.3065811677 +50.9383988009 17.4599795402 84.264041216 +50.9403214911 16.9949769609 84.3578947371 +50.9479295804 49.4237325342 70.4386480127 +50.9485395062 19.7411788811 83.7528040042 +50.9602023283 20.3104422202 83.609471446 +50.9623484339 55.5572144264 65.6980590831 +50.9638114464 5.40148218315 85.8691674181 +50.9880610498 54.8121068264 66.3012109666 +50.9902329312 17.031411057 84.320384149 +51.0032052088 38.9666918987 76.6829184428 +51.0111478258 8.58210748453 85.5815998251 +51.0126788305 56.160579589 65.1436558597 +51.0136102686 34.3443810315 78.8547719477 +51.0238608211 10.3160201815 85.3823480265 +51.0303422666 78.9413068503 34.1199976689 +51.0307933036 13.8934558061 84.8694881602 +51.0326375724 12.0165910458 85.1543976671 +51.0332173918 13.884549041 84.8694881602 +51.0356653246 30.6895730971 80.3337473792 +51.0414346542 24.4549579515 82.4422645251 +51.0443271007 11.2975627706 85.2457726006 +51.0591918681 12.541340399 85.0627633385 +51.0596130056 -5.20445405631 85.8244113158 +51.0691021293 11.5276525278 85.2001175756 +51.0731229278 11.5098253463 85.2001175756 +51.0816954427 77.1175220328 37.9940546168 +51.0837681468 53.325524216 67.4302387584 +51.0897167462 10.4407582602 85.327788028 +51.1009797774 57.860816677 63.5674111417 +51.1316357961 63.481407156 57.9281172343 +51.1354419069 55.1632883034 65.8952062334 +51.1417656662 40.2012592092 75.9498424128 +51.1428521434 14.5394777489 84.6936376679 +51.1607750009 10.0095290371 85.3368878608 +51.1652510858 11.8406503571 85.0994481795 +51.1691135178 74.5072253199 42.78311813 +51.1692439746 4.8549392881 85.7795898543 +51.1786881005 26.5851997339 81.6943635719 +51.1790568244 13.1595926459 84.8971687629 +51.1793282196 -18.6277520817 83.8670567945 +51.1819218231 45.6495236625 72.7772757657 +51.1836472707 13.1417269836 84.8971687629 +51.2041043595 62.9392748479 58.4532922799 +51.2091372829 75.4368908414 41.0718852613 +51.2114314633 -6.74211285717 85.62670846 +51.2143994546 15.1412320953 84.5448305879 +51.22616929 32.2963113942 79.5790666583 +51.2266251662 54.3984058552 66.4578536706 +51.2326325939 -3.94213623322 85.7885593737 +51.2344592013 31.5196496028 79.884553446 +51.2419122053 41.8663983262 74.976470474 +51.2426971317 15.149598135 84.5261833222 +51.244497053 48.544291783 70.8339837725 +51.2492154738 39.6098949851 76.1877557918 +51.2590097342 62.8945668775 58.4532922799 +51.2618377482 23.2318285345 82.6589749127 +51.2771195283 54.3189077295 66.4839324646 +51.2809609564 36.9441935582 77.4944488704 +51.2830083691 75.4040239958 41.0400562604 +51.3021720533 11.2325892904 85.0994481795 +51.3056831243 42.0979937607 74.8029798903 +51.3060416281 57.0812275952 64.1047856925 +51.306089841 11.2146807701 85.0994481795 +51.3142941031 6.16428074694 85.6086728292 +51.3199610426 27.8644653533 81.1777874123 +51.3387954747 1.2546931359 85.8064905724 +51.3425284113 74.3696788986 42.8146661421 +51.3473816799 25.399762237 81.9652272182 +51.3513180471 43.5028799993 73.9631094979 +51.3538171381 58.7230038996 62.5651203016 +51.3538309513 12.5852033332 84.8787176134 +51.3807237325 -81.2134892467 -27.6476109834 +51.3886418102 16.6674392635 84.1510781945 +51.3893530883 50.8007737021 69.1260861067 +51.3938697054 8.27797089735 85.3823480265 +51.397894062 74.4220907216 42.6568739901 +51.4138885422 -69.9915278247 -49.5761847839 +51.4241304068 -70.0054704338 -49.5458668432 +51.4339079986 5.07032981362 85.6086728292 +51.4374107963 7.8067277493 85.4005138885 +51.4441193472 22.1766292622 82.8353770991 +51.4443742384 51.4443742384 68.6072351756 +51.4452233531 5.10771234332 85.5996511019 +51.4530802203 34.6011116709 78.4559979031 +51.487200452 22.25916645 82.7864584251 +51.4875481412 53.8786414775 66.679264985 +51.4943002304 -75.3464947108 -40.8808363244 +51.4943662787 75.2337896592 41.0877978854 +51.5030121575 58.9974260107 62.1831445234 +51.512536078 -2.60951250443 85.6717518865 +51.5126754414 73.1051066007 44.7446941857 +51.5155621843 7.05675422697 85.4186693447 +51.522949033 47.79435865 71.1413030818 +51.5283723324 10.886912648 85.0076583478 +51.5334982989 0.152903416158 85.6987466281 +51.537488931 15.8550018386 84.2170181815 +51.5441944614 11.0971747213 84.9708698939 +51.5480170504 19.8080776364 83.3693108915 +51.5512671408 -71.3987678774 -47.3780835594 +51.551646466 42.4958979307 74.4078383351 +51.5710261032 73.7331966238 43.6330721162 +51.5764645246 60.3242935969 60.8345946742 +51.5800914962 71.9932028798 46.4378391008 +51.5821282384 46.3958751792 72.0187948577 +51.5883976733 44.4514073239 73.2305237754 +51.5906327758 54.2133821484 66.327338299 +51.5929212154 60.6858268753 60.4599114862 +51.6000012805 57.1469416923 63.8096146601 +51.6019098798 55.4331800996 65.3024152754 +51.6082292888 -3.0480158965 85.5996511019 +51.6285583452 28.5946226528 80.7269441918 +51.6328636236 55.621954346 65.1171681568 +51.635880703 16.9969887784 83.9335343977 +51.6530181969 -0.180303779542 85.62670846 +51.6549333996 45.4598973123 72.561460789 +51.663941412 14.6486433943 84.3578947371 +51.6692634655 33.0184656351 78.9941019319 +51.6775635177 64.8513563578 55.8903480703 +51.6793620042 56.8945405239 63.9707339446 +51.7200305422 12.0070845696 84.7400044893 +51.7296754655 12.9744017209 84.591403678 +51.7352680347 30.9629191742 79.7794439539 +51.7555338297 23.8815370466 82.1646937942 +51.7575085099 13.5783281709 84.4795201036 +51.7583131746 12.98158439 84.5727821704 +51.7640659375 58.3032706449 62.6195665085 +51.7808066836 5.04978086436 85.4005138885 +51.7817743758 8.01624220259 85.1726934143 +51.7872373017 1.26565281809 85.5364260161 +51.795737221 21.190195565 82.8744666206 +51.8012814409 35.3761969367 77.879085327 +51.8054208973 -83.7819708868 -17.2272957823 +51.8103819409 10.3997624577 84.8971687629 +51.8122860738 26.2858729817 81.3912765191 +51.8140089863 10.3816765894 84.8971687629 +51.8182691714 70.4904406078 48.4351604003 +51.8217844294 58.0614040549 62.7963057649 +51.8344070048 31.9761013452 79.3140794136 +51.8363705351 14.6877594452 84.2452397007 +51.8372599522 61.7772407782 59.1309648364 +51.8431105232 55.8288995402 64.7721071713 +51.8434986511 -67.3687882137 -52.6659094883 +51.8456222032 73.5776137711 43.5702445497 +51.8489762087 40.2616886556 75.436596508 +51.8501534618 53.318682867 66.8481835454 +51.8551936504 54.1686419735 66.1573663187 +51.8569257444 58.3668120472 62.4833938242 +51.8574186347 29.1367398473 80.3856860617 +51.8581744274 -4.53700237354 85.3823480265 +51.8635926048 45.1638538789 72.5974797422 +51.8652349146 17.0022823679 83.7909291125 +51.8749091142 35.9869049462 77.5495743172 +51.8758914804 56.060107177 64.5457687724 +51.8806637328 68.0291832638 51.7728399366 +51.8819472928 63.8407218317 56.8561850734 +51.8823455966 5.92959278751 85.282249881 +51.8994580674 53.8374042265 66.3926212652 +51.9035251984 38.099042788 76.5146195875 +51.9044649434 51.1847547282 68.4547105929 +51.9077243613 -5.7031576218 85.282249881 +51.914831866 12.1478394754 84.6007105668 +51.9251177114 -72.984777351 -44.4635179185 +51.9273776324 22.9785256311 82.3136368534 +51.9364030116 1.26929834951 85.4458830133 +51.9385392503 1.17865033886 85.4458830133 +51.9423370805 0.997343822584 85.4458830133 +51.9428937748 20.1160380953 83.0498693415 +51.949140308 37.9236449907 76.5707775321 +51.9558821852 55.7548689522 64.7455086819 +51.9584677736 53.7482206279 66.4187202975 +51.9712483709 -3.2242232956 85.3732611941 +51.9727760522 -3.65252161382 85.3550797275 +51.9756976051 55.3484962748 65.0774217266 +51.9763590908 66.2164757743 53.9799632428 +51.9851595343 -73.8303611352 -42.9723278732 +51.9863161722 -78.9912957388 -32.5238086383 +51.9870953786 51.3558016919 68.26363268 +51.9988927453 39.6125409441 75.6766922719 +52.0116656779 12.1226339658 84.5448305879 +52.012516662 53.4856446098 66.5881666001 +52.0255715949 13.4256691277 84.3391445813 +52.0381868413 27.6924992773 80.7784166349 +52.0441792489 -76.2939136478 -38.3489523534 +52.0450046427 -73.7238491212 -43.0826132274 +52.0517196122 -76.3049674071 -38.3167122078 +52.0609637361 41.3074130075 74.7218420912 +52.0685109446 58.6874243342 62.0052932662 +52.0728232402 49.3634713145 69.6539214946 +52.0760010592 26.7979072662 81.0553038353 +52.0862872347 -70.6481213675 -47.9151503112 +52.0918003844 26.3933924221 81.1777874123 +52.0928539593 37.1986402994 76.8283523594 +52.099401508 -76.231879307 -38.3973038094 +52.1063239869 -66.885340827 -53.0215256573 +52.1162819076 43.4524784035 73.4559410853 +52.1162845615 55.1692604151 65.1171681568 +52.1262949761 40.6962308358 75.011106963 +52.1359725292 43.4688956588 73.4322509436 +52.143083482 7.40249060959 85.0076583478 +52.1463555105 31.3574708785 79.3565789779 +52.1485130826 -5.11320641375 85.1726934143 +52.1630032833 27.3049457937 80.8298275618 +52.1724590021 7.40666090405 84.9892692987 +52.1751566782 10.9760100767 84.6007105668 +52.1755418254 78.1747950308 34.1528074559 +52.1791225676 44.2511139724 72.9326955506 +52.1891851063 78.1656874902 34.1528074559 +52.1925295037 6.70453566273 85.0352224996 +52.1992335089 73.2617362466 43.6801788368 +52.2105903734 20.1463901286 82.8744666206 +52.2118080767 11.5750791775 84.4981931132 +52.223545007 30.1877477083 79.7583928825 +52.2475630061 54.9037092039 65.2363002904 +52.2476758398 -2.82963297653 85.2183873736 +52.2486603849 -2.81139492511 85.2183873736 +52.2501304969 22.3081294741 82.293810353 +52.251894551 11.3927554364 84.4981931132 +52.2559902038 52.9537780422 66.8222184522 +52.2588721095 54.8772218478 65.2495272634 +52.262130254 58.6165212256 61.909394931 +52.2633699582 14.9566695531 83.9335343977 +52.2659477738 66.2276850644 53.6857935987 +52.2675468502 11.1098100454 84.5261833222 +52.2707843691 21.3632457252 82.5310658693 +52.2720011279 -73.5538510346 -43.0983630323 +52.2758834776 29.1920610651 80.0940420843 +52.2758863549 -85.0730175611 -5.46016381259 +52.2764270767 73.2347608025 43.6330721162 +52.2831344606 -84.4886038168 11.3203213768 +52.302031825 -73.5417290011 -43.0826132274 +52.310609508 27.2660013253 80.7475405485 +52.3137086886 25.4360304995 81.3405448449 +52.313869649 56.2964284878 63.9841478951 +52.3214310093 52.7247814921 66.9519624339 +52.3245682063 24.7560596164 81.5430994891 +52.3270517106 31.3791470502 79.2289643355 +52.3354442004 54.804201228 65.2495272634 +52.3418384437 24.7195241466 81.5430994891 +52.344581833 35.9485383914 77.2511963678 +52.345425842 48.9497217127 69.7415309387 +52.3458371844 -5.79752979269 85.0076583478 +52.3510094948 -73.3121821196 -43.4130827946 +52.3671298923 7.40632744882 84.8694881602 +52.3739652275 47.3235090549 70.8339837725 +52.3818578647 12.6047829973 84.2452397007 +52.3849353298 9.92664707166 84.6007105668 +52.3894985363 13.1884980879 84.1510781945 +52.3914527099 27.3546696546 80.6650961137 +52.3978185786 34.2881716911 77.9665947075 +52.3978723301 0.274357125183 85.1726934143 +52.3985107894 -0.0914527465021 85.1726934143 +52.3985183902 -84.3457187616 11.8403968307 +52.3998326381 51.5291389521 67.8159669868 +52.4011682923 56.4891505913 63.7423989749 +52.4053407011 23.4200919126 81.8851608095 +52.4126179412 -68.354844418 -50.7989441341 +52.419238695 24.5549656961 81.5430994891 +52.4197845819 -4.06109315419 85.0627633385 +52.431431484 -3.00481481697 85.0994481795 +52.4386597616 20.6349955348 82.6098294496 +52.4411924699 10.7837089773 84.4608368004 +52.4441492994 11.8187994834 84.320384149 +52.4658446881 53.07371564 66.5621202286 +52.4673547142 6.04284212911 84.915609568 +52.4711877929 6.86138486896 84.8510214982 +52.4721039541 -84.2999603175 11.8403968307 +52.474721916 9.84881805604 84.5541503578 +52.476518814 52.4215942854 67.0685576537 +52.4826180416 10.8017751168 84.4327925502 +52.4904376135 6.10120440437 84.8971687629 +52.49976822 -76.1027464651 38.107037635 +52.5033715458 50.0507318382 68.8354575694 +52.5034328351 55.8127928396 64.2520170576 +52.5089521921 -75.2698177847 39.7147890635 +52.5219912428 42.3496425126 73.8102175512 +52.5311730407 51.983928249 67.3657707057 +52.5330154235 54.4565626528 65.3816876087 +52.5355863797 55.9055977996 64.1449631569 +52.5391549006 49.0450109009 69.5285848271 +52.544607142 20.2436741472 82.6393242792 +52.5458845699 0.366845437534 85.0811109424 +52.5548016361 41.8339374933 74.0804596287 +52.5667447442 43.2095494841 73.2780470562 +52.5688824424 55.0678907085 64.8385688589 +52.5905166159 53.2927714725 66.2881442707 +52.6144455548 72.3644383646 44.6666338461 +52.6190292099 72.3707425958 44.6510176944 +52.6206523116 6.50762117215 84.7863067776 +52.624625529 23.243147219 81.7948952887 +52.6534896522 15.3969578804 83.609471446 +52.6634357194 -7.93639285669 84.6379123481 +52.6644376324 55.9839459796 63.9707339446 +52.6692915384 37.1954141128 76.4359005823 +52.6695774622 -1.65520815372 84.9892692987 +52.6768680966 74.2607125454 41.3581206025 +52.6848483811 53.556369686 66.0001667961 +52.7016311057 5.53916463462 84.8048096156 +52.7023710832 15.5411411725 83.5519779135 +52.7072065278 14.5674807965 83.7241833838 +52.709499869 10.6472479588 84.3110000798 +52.7234998949 15.417430308 83.5615665335 +52.7283497508 32.9099537272 78.3368117696 +52.74420111 21.6104683654 82.1646937942 +52.756234871 52.2066454921 67.0167579691 +52.7577378994 47.871363377 70.1780140797 +52.7665055226 -2.85773178774 84.8971687629 +52.7682975038 34.8603896587 77.4613452723 +52.7693916432 54.7972145738 64.9049811691 +52.7729899853 13.874272444 83.8004540093 +52.773502806 9.27690378079 84.4327925502 +52.7875857312 76.7490071374 -36.3739013043 +52.8079120874 -73.3548173199 -42.78311813 +52.8177582304 1.65986492196 84.8971687629 +52.8340949943 1.01446644926 84.8971687629 +52.8408152364 13.9611456002 83.7432663483 +52.8437529865 0.0922298415219 84.8971687629 +52.8499083905 40.8912712201 74.396176791 +52.8513651147 54.3862220706 65.1833725301 +52.8602526237 37.1094742406 76.3457963096 +52.8617529203 13.9962921845 83.7241833838 +52.8629087558 11.3521278225 84.1227797435 +52.8630007702 11.1399815203 84.1510781945 +52.8659883981 52.7738002681 66.4839324646 +52.8687842031 53.6496188651 65.7769720534 +52.8774669718 9.53321446019 84.3391445813 +52.8814950913 74.2741389582 41.0718852613 +52.8907300024 35.6483921612 77.017938275 +52.8920550469 51.0237702896 67.8159669868 +52.8940925678 77.0189632399 -35.6411878713 +52.8953716078 69.0093760791 49.3941866584 +52.9074516409 53.0924565693 66.1966208828 +52.9080896733 -4.08963388159 84.7585331506 +52.9100611175 -5.39306833706 84.6843565628 +52.9108968676 20.8101603493 82.2640518021 +52.9114445809 47.5915372662 70.2525772694 +52.9142673093 42.6202437169 73.3729864503 +52.9228358584 74.0856214453 41.3581206025 +52.9229097457 51.9708976092 67.0685576537 +52.9276542592 -5.21758259866 84.6843565628 +52.9366823347 54.5882770254 64.944804833 +52.9374906012 9.44866945044 84.3110000798 +52.9432334034 12.0089744559 83.9809417029 +52.9655663135 52.5420294044 66.5881666001 +52.9661422726 38.9359719359 75.3563392302 +52.9710705944 55.8784283692 63.8096146601 +52.9714713742 9.83680884317 84.2452397007 +52.9821606536 1.01730945516 84.8048096156 +52.9890208424 0.554920013409 84.8048096156 +52.990246698 52.2190087612 66.8222184522 +52.9906596381 53.8672397225 65.5004616457 +52.9915212434 11.0994659844 84.0755644119 +52.9940490037 43.8716573815 72.5734693176 +53.0079458874 76.9255332852 -35.673799932 +53.0251517941 52.564427417 66.5230354654 +53.0327274073 9.66636764893 84.2264279204 +53.0350844679 37.7597720861 75.9044098026 +53.0480286667 11.5372477334 83.9809417029 +53.0538189674 40.1971160943 74.6289766155 +53.0654175136 -84.2012562852 9.70617865584 +53.0691169697 -3.49693831834 84.6843565628 +53.0715997621 -84.0483707634 -10.9213859333 +53.0865434632 13.1179274221 83.7241833838 +53.0957571252 12.3264669299 83.8385280663 +53.1007944735 -12.2397623122 83.8480401967 +53.1057362344 13.1620154474 83.7050902177 +53.1101624659 30.4534172561 79.0689573744 +53.112905683 20.4094089252 82.234270698 +53.1234999886 21.3232064447 81.9952109325 +53.1256603278 39.3827125388 75.011106963 +53.127283695 14.8533966823 83.4078433613 +53.1302905622 -3.68727787452 84.6379123481 +53.1309695172 48.9763646847 69.1260861067 +53.1358628758 52.0708286621 66.8222184522 +53.1397770152 0.0927465014431 84.7121921382 +53.1432932829 24.2748243458 81.1573981965 +53.162044745 60.0465125051 59.7345238075 +53.1633492987 26.7732659264 80.3545301958 +53.1679990595 42.8552223234 73.0519937827 +53.1934030535 9.68606214157 84.1227797435 +53.1985084897 76.7711319045 -35.7227098715 +53.2053636137 10.0244077908 84.0755644119 +53.2078448992 47.9927016627 69.7540380788 +53.2121334784 -4.54317857238 84.5448305879 +53.2434290828 67.369512189 51.2492545011 +53.2503904262 -71.2590227115 -45.6787434334 +53.2575546608 58.1815531365 61.4698279336 +53.2577543813 28.1747316722 79.8110023334 +53.2592701662 -83.6647411114 -12.7930151302 +53.2613333796 1.67380483261 84.6193166128 +53.2625200124 -74.1772656498 -40.7533706906 +53.2662910347 55.9351159358 63.5135028529 +53.2733683138 54.6866422688 64.5857521893 +53.281667051 51.4175766641 67.2108381607 +53.2873404999 46.5182759856 70.6859911282 +53.2954330593 44.8471358572 71.7518725918 +53.2973061357 55.1331763966 64.1851230356 +53.299545576 11.689411843 83.8004540093 +53.3080579694 45.6421364059 71.239359485 +53.3160936282 -3.09285969451 84.5448305879 +53.3202918508 27.815954055 79.8950510167 +53.3231382871 25.2285080531 80.7475405485 +53.3231990444 -3.88774151197 84.5075257572 +53.3231991536 11.9875674494 83.7432663483 +53.3277030156 56.5306513775 62.932039105 +53.3284069505 34.9902585871 77.017938275 +53.3298565488 -6.89794650734 84.3110000798 +53.3298568122 52.9958237363 65.93458151 +53.3309749622 53.6109489038 65.4344960034 +53.3323543963 -75.6594870848 -37.8325519707 +53.3406305907 -74.0948100018 -40.8011796273 +53.3481704324 65.527989065 53.4794854183 +53.3555420233 57.3571461427 62.1558036049 +53.3596244214 54.0155501964 65.0774217266 +53.3634900692 52.2209122871 66.5230354654 +53.3638175159 -4.49984434336 84.4514912895 +53.3658929391 51.7512820693 66.8871159118 +53.3662157925 15.7065314516 83.0984469274 +53.369418144 31.186569935 78.6072710546 +53.3699228853 33.2198512444 77.7694851116 +53.3702711108 22.4128777105 81.5430994891 +53.3849298178 9.36517527813 84.0377460452 +53.3926139846 32.2720666179 78.1520472419 +53.3986607558 -1.97670495275 84.5261833222 +53.4040572616 25.8740491183 80.4893797356 +53.4051417451 -3.33189409373 84.4795201036 +53.4054945015 52.4264947448 66.327338299 +53.4122951513 56.1472735972 63.2029302665 +53.4146572035 52.5821431622 66.1966208828 +53.4286427667 0.839324190818 84.5261833222 +53.4294056537 58.7181501301 60.8068865901 +53.4321676138 -1.86589240869 84.5075257572 +53.4559430322 50.639210946 67.6618982095 +53.4576029993 -6.34604667429 84.2734381236 +53.4692959038 16.0212154186 82.9720136676 +53.4710994067 -6.35711303793 84.264041216 +53.4793966666 67.3533783644 51.0242741749 +53.4808995697 63.2189256391 56.0638994563 +53.4865528189 54.0496160278 64.944804833 +53.4979174791 -2.08323603438 84.4608368004 +53.5148457985 54.0216031265 64.944804833 +53.5167508582 9.29205081618 83.9619864534 +53.5229273926 36.6204775453 76.1198848376 +53.530150687 -80.7220934295 -24.8689887165 +53.5340058148 -6.92435217965 84.179353575 +53.5517292425 -3.7916657892 84.3672659607 +53.5562396801 1.68307263647 84.4327925502 +53.5590344851 55.5007611823 63.6482154754 +53.5599920137 12.198026642 83.5615665335 +53.5650519905 14.6336448649 83.1663492238 +53.5676052275 14.6242957768 83.1663492238 +53.5827930391 40.8930948634 73.8690671568 +53.5832856426 -5.32943314815 84.264041216 +53.5970412054 23.3269061898 81.1369990919 +53.6081477445 -0.654979667126 84.4140835231 +53.6267146554 34.0062955203 77.2511963678 +53.6308383888 -5.14516875212 84.2452397007 +53.6509851556 11.3060358752 83.6286155848 +53.6538620699 54.942773402 64.0511884034 +53.6687695589 52.9800519461 65.6717387452 +53.6771978529 13.0354750849 83.3596714243 +53.6777383384 8.11799467651 83.9809417029 +53.6850023223 -9.35022357116 83.8480401967 +53.6871896665 49.5758219199 68.26363268 +53.689337562 53.446254198 65.2759752463 +53.6906109833 38.7656413694 74.9302565154 +53.6970287271 50.7787558248 67.3657707057 +53.7029314734 -83.6509126475 10.8866874852 +53.7043246579 -1.6595795652 84.3391445813 +53.7047081157 55.9440863987 63.1352795449 +53.7050739372 -79.9818757995 -26.8079200424 +53.7068116404 -79.9241673969 -26.9760236013 +53.7126759376 53.7126759376 65.037657455 +53.7143498438 -79.8450456164 -27.1944353017 +53.7323801355 55.1000811728 63.8499207495 +53.7330379648 8.24150681512 83.9335343977 +53.7335854708 -73.2297450501 -41.8342710268 +53.7361548317 52.037596643 66.3665141432 +53.739426696 48.2176298912 69.189118986 +53.7419638285 53.55469564 65.1436558597 +53.7438465774 42.398659854 72.8968627421 +53.7471223841 -69.7920608808 -47.3319667185 +53.7480145083 8.80157491805 83.8670567945 +53.7493261191 13.3514019928 83.2631371411 +53.7515051282 21.5208356792 81.5329953339 +53.7647717307 15.2138968792 82.9330251619 +53.7664544177 54.0109941111 64.7455086819 +53.7670085209 14.9917891746 82.9720136676 +53.7676874838 10.9587063858 83.5998955561 +53.7720195361 50.4070545394 67.5847524792 +53.7874440109 -71.7685029231 -44.2288690219 +53.7905298186 10.9926997896 83.5807361368 +53.791318508 38.0159453636 75.2414908896 +53.7943276106 53.6630436 65.0111380342 +53.8020653461 -6.91129303889 84.0093553899 +53.8112356337 50.7091432085 67.3270652459 +53.8137873247 -5.53263775144 84.1039012964 +53.8165297779 56.2174804215 62.7963057649 +53.8181938855 30.0410018893 78.7473187632 +53.8205065533 -5.4668876947 84.1039012964 +53.8393330411 39.4477423172 74.4661120495 +53.8567411625 24.8510963777 80.5100890583 +53.8577066019 20.2223278652 81.7948952887 +53.8583852021 -3.15261390286 84.1981910079 +53.8600765784 70.497042588 46.1438959919 +53.863211043 1.22232725187 84.2452397007 +53.8716640297 -3.41763754071 84.179353575 +53.8780849026 51.2178259225 66.8871159118 +53.8866180583 -84.0337859085 5.87836883186 +53.8964813349 35.0275379006 76.6044443119 +53.8968481612 49.8217339705 67.9185142834 +53.9026668057 15.1513563205 82.8549269077 +53.9028896767 -4.22331773823 84.1227797435 +53.9071912164 19.8019439474 81.8651192576 +53.909252354 -72.854173244 -42.2618261741 +53.9128947233 55.7894515217 63.0946660302 +53.9172234319 -66.3451285594 -51.8773258161 +53.9233679816 82.2468046143 -18.10341173 +53.9289533249 46.4353677738 70.2525772694 +53.9334814865 51.0915866624 66.9389972068 +53.9339207978 52.5951663377 65.7638248986 +53.9396092176 43.6326912383 72.0187948577 +53.9403199216 26.3084518634 79.989419596 +53.9459530613 12.0089299111 83.3403848725 +53.9471982088 -81.5053256508 -21.1324796455 +53.9495784671 52.7760219041 65.6059028991 +53.9531251618 61.3703359452 57.643231617 +53.9567695916 22.8477403225 81.0348553241 +53.9581320625 41.9599040391 -72.9923724601 +53.9596437794 52.8965629073 65.5004616457 +53.9605910431 -7.05614640104 83.8955625301 +53.9643185018 12.3892202233 83.2728019878 +53.9764347534 53.0424947049 65.3684805299 +53.9808128856 -70.7574158092 -45.6010959102 +53.9819080732 -83.8277728919 7.67190281268 +53.9842295545 53.5525469479 64.944804833 +53.9859279453 24.6369505756 80.4893797356 +54.0099435455 51.9204892709 66.2358572986 +54.0193286928 63.6523501179 55.0480740085 +54.0193823464 9.64177338048 83.5998955561 +54.0236161465 14.3241022711 82.923271719 +54.0265422651 55.9852179672 62.8234677493 +54.0350287307 -70.726036123 -45.5855622364 +54.0356103149 54.6616686214 63.9707339446 +54.0364966746 -5.51741406216 83.9619864534 +54.0452064535 31.4929565154 78.0212108937 +54.0498375734 -3.6184125209 84.0566603496 +54.0534183288 49.8790588335 67.7518077755 +54.0692365854 32.3341418332 77.6596479968 +54.0718025797 41.4158340054 73.2186373775 +54.0761799397 41.4941122745 73.1710694857 +54.0819568522 20.2742255198 81.6339250717 +54.0850105802 50.3998034701 67.3399691173 +54.0894188333 -4.4659686533 83.9904154905 +54.0934649424 51.5485279715 66.4578536706 +54.0942356562 55.1813865798 63.4730513202 +54.0948706906 12.3397063041 83.195412213 +54.0954649016 34.3962821502 76.750090888 +54.097765429 36.764803421 75.6424550435 +54.1018211733 -3.49860783525 84.028285053 +54.1244350054 51.3980896819 66.5490940013 +54.1268084759 -83.4435948993 10.3660539498 +54.1301634251 -2.09839425473 84.0566603496 +54.1377723676 -6.34056896038 83.8385280663 +54.146163675 9.08039129684 83.5807361368 +54.1487976665 53.5473029174 64.8119901063 +54.1569010943 51.1778376213 66.6922709185 +54.1572423646 28.6384876326 79.0368909154 +54.158940472 1.1344680794 84.0566603496 +54.1667334042 35.5403080087 76.1764497661 +54.1747200983 49.6072069663 67.8544377272 +54.1769323523 -76.4319367107 -34.9716892865 +54.1787561802 48.322421749 68.7721305114 +54.1792159339 -3.43714874297 83.9809417029 +54.1796991384 11.9617552211 83.195412213 +54.180755207 52.8174279063 65.3816876087 +54.1904291064 24.1838198606 80.4893797356 +54.1913499898 37.9029209753 75.011106963 +54.2027950422 26.9418842923 79.6002002535 +54.2033932684 50.6339879177 67.0685576537 +54.2053971965 61.5488904024 57.2145873446 +54.2111669854 44.9750209332 70.9816657042 +54.2255423165 50.2485733108 67.3399691173 +54.2309843357 -67.4979757478 -50.0302269426 +54.2311841921 74.7799668185 38.3005903839 +54.2380316086 9.6612649165 83.4559517796 +54.2506759136 -76.3945777445 -34.9389847328 +54.2565615531 10.5169281511 83.3403848725 +54.2705206516 42.0965309235 72.6814465487 +54.2755447192 21.161150626 81.2795850728 +54.2787844581 78.009746203 31.1174075894 +54.2804698876 -2.68324777816 83.9430209734 +54.2890379469 -67.4737012384 -50.0 +54.2903151712 -68.3012042514 -48.8621241497 +54.2941988282 53.0760695138 65.0774217266 +54.3059547462 39.8187734595 73.927860508 +54.3084109257 -2.39964710684 83.9335343977 +54.3111061952 61.4955911369 57.1716364519 +54.3205779683 54.0935156895 64.2118865129 +54.3210937724 54.2831837264 64.0511884034 +54.3224116708 12.7712182007 82.9817544761 +54.3276303049 73.7690412311 40.0828784059 +54.3290912183 12.7427733031 82.9817544761 +54.3382368236 7.84962201179 83.5807361368 +54.3457814454 61.4915790736 57.1429938149 +54.3515316966 13.6319936291 82.8255984098 +54.359855341 42.3942312938 72.4412539946 +54.3647912054 55.2255292679 63.2029302665 +54.3707770396 74.8349545192 37.9940546168 +54.3724742013 38.2136149001 74.7218420912 +54.3796597631 33.7168175532 76.8506917219 +54.3808185709 52.9384641145 65.1171681568 +54.3833569531 55.5926550997 62.8641963719 +54.3861937929 -67.4738093438 -49.8941577478 +54.3924836732 49.8939468755 67.4688949446 +54.3936997714 55.1970563609 63.2029302665 +54.3986986617 43.941264245 71.4838924546 +54.3998972143 53.421316055 64.7055961569 +54.4026953314 56.8893982723 61.6761145412 +54.4054722539 62.1906589736 56.3237651908 +54.412518252 19.6648390258 81.5633003474 +54.4164534288 8.78430493616 83.4367160369 +54.4175052165 45.823794367 70.2774145499 +54.4255800718 9.17608802273 83.3885822067 +54.4273252051 1.99575941493 83.8670567945 +54.4291549664 51.6152424916 66.1311865324 +54.4334974226 45.8047962829 70.2774145499 +54.4345089016 -6.56802070729 83.6286155848 +54.4414431587 53.4434529687 64.6523518642 +54.4420216004 52.4823114663 65.4344960034 +54.4437278861 50.1162104688 67.2625151337 +54.4555438213 11.923018731 83.0206924295 +54.4582431503 29.3595343566 78.564098005 +54.4660680352 -74.7738311098 -37.9779095522 +54.4697944952 11.2999825618 83.0984469274 +54.4702710291 -4.47827146747 83.7432663483 +54.4734605743 48.5852707146 68.3528606764 +54.4829471507 45.5548147539 70.4014724456 +54.4927550072 51.2616652377 66.3534575496 +54.493797094 12.3506848305 82.9330251619 +54.4949073594 -5.77573110842 83.6477495337 +54.4958987519 -4.86362939228 83.7050902177 +54.5006324614 -3.45753952188 83.771871662 +54.5037229185 10.2296349709 83.2147748683 +54.5178985854 13.2597931259 82.7766671236 +54.52134723 -4.74123529846 83.6955398099 +54.5238128025 12.2174946277 82.9330251619 +54.5302986248 69.6201100024 46.6849741903 +54.5314818662 52.2572831782 65.5400170912 +54.5316167791 66.7909359209 50.6485305836 +54.5355706672 -5.94372076459 83.609471446 +54.542125407 -3.2595057163 83.7528040042 +54.5490665065 53.0096138478 64.9182577014 +54.551367091 54.4942709232 63.675134747 +54.5600072454 34.7853386272 76.2442511011 +54.5653390106 53.1551999114 64.7854034566 +54.5657582119 30.721135078 77.9665947075 +54.5686435899 24.8108762824 80.0417613178 +54.5700696389 53.5697215399 64.4390598453 +54.5748053885 54.0439895943 64.0377842023 +54.5901805609 9.67484935746 83.2244523938 +54.5980474995 42.8873294137 71.9703423989 +54.6010407546 49.8925637255 67.301251351 +54.6027691697 40.1537554431 73.5269577966 +54.6113627092 53.4793975365 64.4790904261 +54.6162696075 51.9195623666 65.7375245794 +54.625601121 19.8281251061 81.3811351416 +54.6259018158 52.4392889656 65.3156323064 +54.6286636308 52.6990373479 65.1039213298 +54.6300272131 53.460331317 64.4790904261 +54.6312315488 53.7797561348 64.2118865129 +54.6322491822 52.4820388794 65.2759752463 +54.6393505679 50.5080961354 66.8092328522 +54.6403684972 -2.16592871802 83.7241833838 +54.6452245183 21.3822295887 80.9734505573 +54.6461103375 53.4760700821 64.4524053357 +54.6486778344 52.4978209344 65.2495272634 +54.6526002052 50.0447966267 67.1461958818 +54.6529158124 -68.9053944568 -47.5931235364 +54.6531624746 73.536904509 40.0668879095 +54.6557534527 13.9011038814 82.580311972 +54.6715195417 18.1338198271 81.7446605564 +54.6718241787 63.0036980143 55.1500288078 +54.6828491881 50.9569069636 66.4317667789 +54.6977200221 12.4973118827 82.7766671236 +54.7048011939 -3.23090146575 83.6477495337 +54.7050072128 -77.4631508272 -31.7304656405 +54.7136287038 -68.050029819 -48.7402531354 +54.719044312 36.1216837342 75.5052988457 +54.7320457838 -68.0242981833 -48.7554922136 +54.7322219081 1.62441442402 83.6764313459 +54.734201394 38.7826658593 74.1624704726 +54.7384193335 8.13188272199 83.292124071 +54.7386363342 25.9333010021 79.5684962244 +54.7394707696 50.7425701701 66.5490940013 +54.7413491588 32.7879797387 76.9956692089 +54.7485785372 49.9397790018 67.1461958818 +54.7518747836 11.5080918918 82.8842326905 +54.7558031513 48.7513656771 68.0081345566 +54.7598663347 26.5309331146 79.3565789779 +54.7629438675 8.26256451674 83.2631371411 +54.7672024153 -3.84890717305 83.5807361368 +54.7695811955 -3.36904120998 83.5998955561 +54.7770622117 30.0890498755 78.0648610647 +54.7830383266 8.79443565047 83.195412213 +54.7872894563 32.7635472555 76.9733907611 +54.7890753775 50.8597170001 66.4187202975 +54.7897405099 9.87797593968 83.0693079675 +54.790683839 18.6736148123 81.5430994891 +54.791531731 44.6391315302 70.7476924486 +54.7962606914 -6.61166936499 83.3885822067 +54.8007279841 -83.5214039886 -4.58860416543 +54.8029773261 17.7325730427 81.7446605564 +54.8102089474 35.9351476337 75.5281812285 +54.810714044 10.9323663227 82.923271719 +54.8182737612 9.883120165 83.0498693415 +54.8275143551 7.82263785902 83.2631371411 +54.8310895321 18.6873857729 81.5127795729 +54.8311366408 12.8807212509 82.6294951862 +54.8370102771 10.1832396502 83.0012285095 +54.8495978592 40.9581373727 72.8968627421 +54.8581588592 31.9282108876 77.2733573497 +54.8645412999 18.6774133678 81.4925538797 +54.8715297458 50.633990321 66.5230354654 +54.8790752626 41.0249241394 72.8370969882 +54.8795677711 -3.24122329451 83.5327930385 +54.8812411374 -2.34818433708 83.5615665335 +54.8812547382 44.4895632315 70.7723578937 +54.8890255628 52.8208895394 64.7854034566 +54.8935873404 49.2186223155 67.5590207616 +54.9086388246 14.0164503908 82.3928425343 +54.9118651527 12.2038358179 82.6786154745 +54.9139195328 14.8992001232 82.234270698 +54.9147734636 57.4048216498 60.7375839723 +54.9333498682 48.9438293971 67.7261296414 +54.9335723945 9.81483815653 82.9817544761 +54.9469025669 21.7328340495 80.6754102716 +54.9480231401 49.9988540463 66.9389972068 +54.949004241 -81.772745004 -17.1413274698 +54.9505209922 32.3037717575 77.0513242776 +54.9532023069 53.1604458471 64.4524053357 +54.9541299476 12.0120832882 82.6786154745 +54.9568279497 49.5354790044 67.2754292556 +54.9686465818 18.4135901738 81.4824373094 +54.9687492283 8.73570060512 83.079023485 +54.9877126191 19.2348774704 81.2795850728 +55.0064671153 18.4796637685 81.4419462102 +55.0070347533 17.3753215494 81.6842967082 +55.0106771241 38.5475148816 74.0804596287 +55.019940515 18.4841902162 81.4318172325 +55.0322546803 3.1249578855 83.4367160369 +55.0342204292 17.3839088121 81.6641555162 +55.034302293 12.2512077633 82.5901536471 +55.0355074922 13.0808590879 82.4620157442 +55.0443485543 14.5227907168 82.2144041031 +55.0513405181 49.3600667801 67.3270652459 +55.0582086677 -5.27240827667 83.3114360053 +55.0629589335 3.09777839539 83.4174701276 +55.0637241903 -4.18858923437 83.3693108915 +55.0673391315 48.6680879286 67.8159669868 +55.0740059796 44.486752612 70.6242359774 +55.0741849247 37.0083164122 74.8145618928 +55.0752016351 12.7860056692 82.4817569156 +55.0771994131 13.9366740075 82.293810353 +55.0817769501 12.5648317779 82.5113498278 +55.0830630055 31.2661073374 77.3840209727 +55.0894391709 10.6384713069 82.7766671236 +55.0943076721 13.4509206202 82.3631592194 +55.0962955609 13.5635409121 82.3433577977 +55.0971947051 12.366175727 82.5310658693 +55.1226194797 53.3243360675 64.171738364 +55.1285727325 -4.82312515046 83.292124071 +55.1303335004 27.0319384297 78.9298462742 +55.1318643314 -70.5148188782 -44.5885394908 +55.1362006718 34.5198611374 75.9498424128 +55.137865202 35.3571251202 75.5624875464 +55.1392860245 18.6636186351 81.3100761047 +55.1490507135 18.6347452154 81.3100761047 +55.149234218 2.21502205856 83.3885822067 +55.149662044 52.646942954 64.7055961569 +55.1529356717 -4.16633142275 83.3114360053 +55.1566300999 2.02250181141 83.3885822067 +55.1569386263 49.6635306102 67.0167579691 +55.1578465872 18.9170236807 81.2388957023 +55.1592384943 11.3225655844 82.6393242792 +55.1594002789 1.94548668099 83.3885822067 +55.1653203552 17.1081766268 81.6339250717 +55.1665948329 -82.7814041174 10.1924455795 +55.1708340937 48.0100138943 68.1998360062 +55.1708779259 -3.24876564029 83.3403848725 +55.1896940175 -2.91168740676 83.3403848725 +55.1972262244 9.65331368985 82.8255984098 +55.1991219026 23.6241700592 79.9684658487 +55.1999155401 -3.2504755352 83.3210881659 +55.2008180434 34.4665128193 75.9271307335 +55.2033684428 48.2078917072 68.03372171 +55.2043932736 19.4730312534 81.0757424702 +55.208435298 12.462009947 82.4422645251 +55.2261790866 -2.76864774458 83.3210881659 +55.2279868269 44.8825674182 70.2525772694 +55.2367221522 54.1484810401 63.3785967573 +55.2382215937 17.6818941369 81.4621967227 +55.2383600924 46.6800334673 69.0630005849 +55.2406793372 18.451116278 81.2897512265 +55.2460497109 67.8591695273 48.4046186062 +55.2470321068 -2.31553670517 83.3210881659 +55.2537178446 67.8202225437 48.4504290844 +55.2634735807 11.8777313387 82.4916237326 +55.2706849936 10.6134465051 82.6589749127 +55.2864431818 30.2057655642 77.6596479968 +55.2897738792 7.86890009386 82.9525244685 +55.298778214 -2.77228734836 83.2728019878 +55.300730288 10.2993093376 82.6786154745 +55.3030429932 1.99887554284 83.292124071 +55.3131761512 49.7692570747 66.8092328522 +55.3198813484 25.1757495784 79.4096490407 +55.3265144288 8.12058089516 82.9037572555 +55.3292666747 55.2713563186 62.3197353969 +55.3379270977 -3.60764024649 83.2147748683 +55.3408354278 10.8574402487 82.580311972 +55.3413325219 12.8477893926 82.293810353 +55.3468036429 64.2784871411 52.9623207325 +55.3477390384 13.1346606554 82.2442002381 +55.350529169 18.7028243506 81.1573981965 +55.3569554566 43.4366094623 71.0553899503 +55.3572872922 7.90808298952 82.9037572555 +55.3574372817 14.9054920061 81.9352210326 +55.3580192778 39.2391949575 73.4559410853 +55.3686141114 -4.57158720378 83.1469612303 +55.3706546557 14.577876791 81.9852188584 +55.380861663 49.2905559938 67.1073859667 +55.3824474432 14.9225935605 81.9152044289 +55.3833296451 8.42538416128 82.8353770991 +55.3888055999 20.6209234317 80.6650961137 +55.3968645911 12.6061957409 82.293810353 +55.4079171722 17.7575393041 81.3303910756 +55.4142391512 47.5460997485 68.3273773681 +55.4225366671 51.8634925249 65.1039213298 +55.4257793567 45.3170327793 69.8165418993 +55.4282005843 -2.49759217817 83.195412213 +55.4342718542 -68.138929796 -47.7925491081 +55.4362294076 46.9302323727 68.7341091345 +55.4624446651 16.8190634084 81.4925538797 +55.4651719043 29.0951731791 77.9556643439 +55.4683122466 16.7997023387 81.4925538797 +55.4726161155 62.2610994422 55.1936985312 +55.4749267919 33.3326988527 76.232956683 +55.4925968709 19.2485804275 80.9324647101 +55.5124009824 11.9515072325 82.3136368534 +55.5303412109 17.0833635914 81.3912765191 +55.5364351343 35.6127078656 75.1494471773 +55.5391797995 62.292017102 55.0917789925 +55.5549621663 47.1974445956 68.4547105929 +55.5677223988 17.0099697376 81.3811351416 +55.5752063741 47.0811972463 68.5182990326 +55.5761826565 16.589105655 81.4621967227 +55.5808799171 -82.8691977938 6.59255979514 +55.589700544 8.97369913178 82.6393242792 +55.5907420538 49.6166342836 66.6922709185 +55.5978837127 -78.1471346202 -28.31785086 +55.6021721877 16.5017863613 81.4621967227 +55.6082854934 65.5014820763 51.1593044351 +55.6098029246 40.1808727771 72.7533317557 +55.6172839083 12.2791441583 82.1945274906 +55.619101766 32.0082414919 76.694119692 +55.6255869092 38.1589777446 73.8219919705 +55.627699922 9.00972139994 82.6098294496 +55.6308504114 -69.1908235487 -46.0199784784 +55.6311464357 65.4820671327 51.1593044351 +55.6367054952 11.5015555129 82.293810353 +55.6398072526 59.6663883295 57.8284873795 +55.6723961393 34.383972652 75.619618703 +55.6785737759 -3.9422544587 82.9720136676 +55.6788945856 11.5102770963 82.2640518021 +55.6796937004 46.341201859 68.936671806 +55.6882712934 46.6121871362 68.7467850211 +55.7105496391 -82.9685900287 3.5422771708 +55.7125942169 2.62733924847 83.0012285095 +55.7126697427 46.5830224374 68.7467850211 +55.7145926219 -5.98367922238 82.8255984098 +55.7447015193 -2.56060082581 82.9817544761 +55.7463591549 58.2741146522 59.1309648364 +55.7474621652 -3.33153815039 82.9525244685 +55.7508495734 10.1618045132 82.3928425343 +55.7536397237 45.2613019361 69.5912796592 +55.7557316129 -72.3219273089 -40.7533706906 +55.7564733107 67.0874920942 48.8925770283 +55.7655226493 -82.6757872685 -7.41084901954 +55.7664219515 -4.68283728875 82.8744666206 +55.785224484 45.222367526 69.5912796592 +55.7889611659 39.6032035542 72.9326955506 +55.7929278358 -82.6541672458 -7.44565916573 +55.8106745295 44.7447763269 69.8789925516 +55.8116124599 16.3945014853 81.3405448449 +55.8268150814 78.3241250817 -27.3623490961 +55.8310963605 -3.83555231192 82.8744666206 +55.8508675509 49.6390398709 66.4578536706 +55.8581916447 16.3870055236 81.3100761047 +55.8631821344 22.0839703998 79.9475023575 +55.8738938036 42.6879212024 71.1044961634 +55.8881934159 32.4233219674 76.3232469783 +55.8887623375 -4.42798674749 82.8060334622 +55.888862406 11.1981316598 82.1646937942 +55.8920153621 -67.6339126205 -47.9764158979 +55.8958239609 -82.8066022203 4.32706510979 +55.8959378817 -3.27188255307 82.8549269077 +55.9201862306 49.6133688231 66.4187202975 +55.9205696262 44.5290553812 69.9289147602 +55.920912263 28.0275261548 78.0212108937 +55.9248068798 -3.27357240701 82.8353770991 +55.926185466 57.3497275031 59.8604254456 +55.9288445453 49.6908746054 66.3534575496 +55.9396254467 -4.33378411913 82.7766671236 +55.9515095251 -4.17755452088 82.7766671236 +55.9570529805 -4.9940339331 82.7276727994 +55.957894258 36.6178199368 74.3495079559 +55.9655281697 8.43401900994 82.4422645251 +55.9784751835 77.1043459775 30.3534206887 +55.9793106218 -3.78684066476 82.7766671236 +55.9879375932 35.3667570269 74.9302565154 +55.9906352239 9.1989235144 82.3433577977 +55.9962750371 -2.08264976313 82.8255984098 +55.9976546816 56.154248381 60.917674438 +56.0071138588 7.95104751628 82.4620157442 +56.0267300848 77.3410399408 29.6541574976 +56.0319156419 -78.2068614757 -27.2784025857 +56.0330019407 8.27423384866 82.4126188622 +56.0330837965 -69.0717624724 -45.7097927059 +56.0333308995 -6.3841916412 82.580311972 +56.0375967572 11.6864508642 81.9952109325 +56.0401219353 11.0251099144 82.0850271661 +56.0427735357 16.2607191702 81.2083526892 +56.0428801044 24.228697339 79.1970063504 +56.0463255339 -6.13807092536 82.5901536471 +56.0612911772 12.4592889236 81.8651192576 +56.0778387334 7.21358295935 82.4817569156 +56.0791803233 63.1191095636 53.5826794979 +56.0807757781 76.9905852912 30.4531831612 +56.08415245 26.4749391596 78.445174743 +56.0903479203 50.1858013285 65.8426777644 +56.0931156777 77.432680677 29.2872384621 +56.095591093 30.7496253855 76.8618578918 +56.0972538834 9.68967825686 82.2144041031 +56.1066353853 34.5575414386 75.2184937064 +56.1116804998 -5.20532321818 82.6098294496 +56.1156421559 63.2490240886 53.3909698101 +56.1220681404 43.8789221321 70.1780140797 +56.1262298187 4.71305119952 82.6294951862 +56.1385687168 82.2343878144 -9.27181553005 +56.1543300617 9.78030209281 82.1646937942 +56.1675677381 43.520946398 70.3642775775 +56.1699512499 24.867642574 78.9084084835 +56.1873364881 16.2707723738 81.1063818989 +56.200060072 52.4991700901 63.9170586601 +56.2036474469 33.6371890839 75.5624875464 +56.2036503769 15.9570173366 81.1573981965 +56.2082112857 52.5067845295 63.9036349704 +56.2110542946 42.898920442 70.7106781187 +56.2139207086 -70.7212413114 -42.877746512 +56.2152145069 12.7511493283 81.7144898335 +56.2171363903 70.8521324835 42.6568739901 +56.2186958466 70.8033248041 42.7357863387 +56.225133291 -4.74112160208 82.5606210755 +56.2264895047 60.5492803649 56.3237651908 +56.2326024922 70.8208392044 42.6884428311 +56.2331778596 60.5564829323 56.3093427655 +56.23328232 13.4277761658 81.5935829999 +56.2346401835 29.4362614361 77.2733573497 +56.2406804643 49.6351894197 66.1311865324 +56.2451720717 -1.99361104699 82.6589749127 +56.2564133151 24.671421352 78.9084084835 +56.263636414 -3.16532712199 82.6098294496 +56.2709526615 -70.666303143 -42.8935133403 +56.2716625064 65.1913484677 50.8290082898 +56.283574593 9.18653111501 82.1447921484 +56.2945488741 20.8798524148 79.9684658487 +56.303994381 -2.34014851056 82.6098294496 +56.3200655831 24.6290470563 78.8762337705 +56.3285312563 65.1422173616 50.8290082898 +56.3297247793 4.70043830315 82.4916237326 +56.3421388808 77.3210377732 29.1036166828 +56.3435293988 -4.15738433163 82.5113498278 +56.3481182746 77.3292435841 29.0702193598 +56.3482786379 -3.67350799887 82.5310658693 +56.3531461425 -66.5199253604 -48.9838999048 +56.3562602013 10.5162488778 81.9352210326 +56.3567755915 16.4478477854 80.9529625656 +56.3630592431 -7.25027235136 82.2838933425 +56.3665314447 -69.7810136179 -44.1975595633 +56.3736889474 15.7186066873 81.0859580832 +56.3752744563 16.48528392 80.9324647101 +56.3811376016 42.919823072 70.5624270432 +56.3819114626 15.6890873395 81.0859580832 +56.3860657613 9.0013058584 82.0949942494 +56.3882912799 -3.49825043736 82.5113498278 +56.4028490298 71.035252234 42.1035813367 +56.4095698661 82.168568829 -8.14166593065 +56.4100568845 64.1424551674 51.9966434242 +56.4189173337 17.8429606047 80.6134884728 +56.4239101275 82.1587222503 -8.14166593065 +56.4243482491 -2.85833417496 82.5113498278 +56.4293079782 42.1377628683 70.9939584863 +56.4303950367 38.6386978913 72.9565729819 +56.431080547 -4.52051181243 82.4323851484 +56.4439592191 26.9586742693 78.0212108937 +56.4581462196 -68.0766616761 -46.669538893 +56.4597595572 -4.52280919542 82.4126188622 +56.4607141769 -5.6355284787 82.3433577977 +56.4624689678 8.50890811178 82.0949942494 +56.4626779077 -5.61581962855 82.3433577977 +56.4736027134 32.7366024646 75.7564984384 +56.477916566 11.3161570722 81.7446605564 +56.4833898862 31.1547866043 76.4133884775 +56.4907750881 15.4541272838 81.0553038353 +56.5020615248 -1.62759251988 82.4916237326 +56.5166324378 -5.04397506918 82.3433577977 +56.5180552206 -3.72420278053 82.4126188622 +56.5291817383 -5.06498526311 82.3334533242 +56.5310711766 11.1216973085 81.7346061384 +56.5453108659 -74.7120817868 -34.9389847328 +56.5458636924 41.6892061843 71.1658301926 +56.5479027843 10.9610748203 81.7446605564 +56.5524982558 67.8282585936 46.9163327338 +56.5547504565 -80.5290081092 -17.7943545474 +56.5561599738 10.9934038593 81.7346061384 +56.5571583734 -72.2597948512 -39.7468223232 +56.5663391294 9.75037007972 81.8851608095 +56.5755568854 35.5586169864 74.396176791 +56.5800698819 -82.3861060998 -3.35040503011 +56.6040658755 8.53024680098 81.9952109325 +56.6087655084 24.2040944805 78.8010753607 +56.6107625007 70.6617822544 42.4515500038 +56.6156104736 -82.2224172498 5.84352225182 +56.6206365422 15.2456198625 81.0041640446 +56.6357282706 11.4712084736 81.613759008 +56.6500200013 13.5795539041 81.2795850728 +56.6631889931 23.1815226604 79.0689573744 +56.6693746628 -80.7821227765 -16.2120515372 +56.6726279366 37.1986465406 73.5151272753 +56.6769294271 25.9128364071 78.2064612424 +56.6833369532 16.9842511786 80.6134884728 +56.6873855757 -6.60909070813 82.1149209134 +56.7007400493 9.97746389376 81.7647619217 +56.7007655875 -67.3820479062 -47.3780835594 +56.7091752747 14.0551114418 81.1573981965 +56.7102915107 12.0231130282 81.4824373094 +56.711112608 8.39459713783 81.9352210326 +56.7333269561 -80.7233590524 -16.2809371901 +56.7334107347 10.7506584095 81.6440043737 +56.733509997 -1.58471042442 82.3334533242 +56.7408835675 -77.8111733954 -26.942409447 +56.7434418808 13.1837344445 81.2795850728 +56.7656594847 9.16353109025 81.8149717425 +56.7692578792 -6.1370415545 82.0949942494 +56.7725101672 -2.4985967505 82.2838933425 +56.8056875124 -81.6718251685 10.14035699 +56.8104827506 9.50681440666 81.7446605564 +56.8105312849 -3.1762018034 82.234270698 +56.8133634479 -81.7437171728 9.4977069084 +56.8190371901 8.82651752202 81.8149717425 +56.819439102 14.9381033448 80.9222120842 +56.8282944394 -6.99777392121 81.9852188584 +56.8283360797 41.0915249584 71.2883356168 +56.8346825018 11.2020369232 81.5127795729 +56.8382375237 69.1467779529 44.5885394908 +56.8406629649 -7.13025671197 81.9652272182 +56.8418939262 -81.723880588 9.4977069084 +56.8506210827 16.1085399721 80.6754102716 +56.8525068351 39.542960267 72.1397723859 +56.8569558928 69.3420770134 44.2601730913 +56.8586076664 34.7066423484 74.5824893064 +56.8627277689 8.34605948944 81.8350382274 +56.8732197105 -7.21501449091 81.9352210326 +56.8804944957 12.8394381107 81.2388957023 +56.8820909066 -2.28462077274 82.2144041031 +56.893255524 69.312297277 44.2601730913 +56.8998618351 -1.78815019586 82.2144041031 +56.9053130228 -71.2840544094 40.9923033842 +56.9115569798 -2.26590660279 82.1945274906 +56.9118825243 26.1524764457 77.9556643439 +56.9413952582 8.96770078075 81.7144898335 +56.9446770298 10.0716289931 81.5834912675 +56.945544953 33.1830274808 75.2069916777 +56.947959309 11.1417829831 81.4419462102 +56.9488851697 68.1101024722 46.0199784784 +56.9584422053 11.3090711049 81.4115518356 +56.9604151431 11.2991298091 81.4115518356 +56.9641578251 31.8753457649 75.7564984384 +56.9655044613 69.7968516767 43.3973593378 +56.9669453611 22.6123351382 79.0155012376 +56.9733992513 21.8358189237 79.2289643355 +56.9752663701 15.7150021005 80.6650961137 +56.9768521781 53.7298320588 62.1831445234 +56.9787404317 19.1533253588 79.9160388565 +56.9823273301 14.7048047605 80.8503746992 +56.9859214708 27.9541230953 77.2733573497 +57.005921917 -6.59581020665 81.8951778441 +57.0126884475 24.825326157 78.3151105291 +57.0290080212 13.638828819 81.0041640446 +57.0408884281 13.589056434 81.0041640446 +57.0427953196 -66.6000066101 -48.0682704252 +57.0456284285 13.5691445803 81.0041640446 +57.0547933915 29.1085088409 76.7948257639 +57.062395479 -4.17037494739 82.0151875874 +57.0717942349 14.5262036396 80.8195502996 +57.0771895598 57.9808720437 58.141318432 +57.0844490061 14.4763935788 80.8195502996 +57.0844936164 36.3248270177 73.6333316555 +57.0865077763 18.515490342 79.989419596 +57.0962585314 39.786473409 71.8126297763 +57.1000219032 16.9137970504 80.3337473792 +57.1042459801 37.6819188837 72.9326955506 +57.1098298717 18.5340713774 79.9684658487 +57.1130638076 18.5241035495 79.9684658487 +57.1163817079 9.4043535822 81.5430994891 +57.1194121759 69.3653546631 43.8841694139 +57.1260972087 -5.14862127924 81.9152044289 +57.1282206031 21.895156282 79.1010021561 +57.1399237058 10.353180507 81.4115518356 +57.1593030652 14.4104642207 80.7784166349 +57.1602007599 21.8502233712 79.0903229713 +57.1605949596 69.3413464977 43.8684858384 +57.1680255022 27.2677494172 77.3840209727 +57.1699354294 -3.6469178857 81.9652272182 +57.1787216483 -6.71695604799 81.7647619217 +57.1791213927 -6.46419704918 81.7848533243 +57.1825145315 69.491403719 43.6016609893 +57.1902390307 37.6670653047 72.8729630997 +57.19801697 20.513649693 79.4202557977 +57.2002045527 38.4079666052 72.4773392198 +57.2141096183 27.2652193738 77.3508466216 +57.2234665791 9.62726701421 81.4419462102 +57.2281386356 12.2477569389 81.0859580832 +57.2294111994 -2.54872926054 81.9652272182 +57.2345437011 12.217790678 81.0859580832 +57.2360824248 54.8299300795 60.9730238396 +57.267606222 -69.7931990493 -43.0038445267 +57.2699200538 21.9494644958 78.9833986695 +57.2771730113 -5.81800306938 81.7647619217 +57.280809993 -7.6225420385 81.613759008 +57.2842382945 -5.74802147687 81.7647619217 +57.2895185688 -1.70031321704 81.9452255907 +57.2901085998 -1.68031529934 81.9452255907 +57.2985151236 -1.87075358372 81.9352210326 +57.2997125111 69.0668779848 44.1192623644 +57.303315098 9.22980070233 81.4318172325 +57.3114406157 -1.42067902642 81.9352210326 +57.3125794101 9.61140387339 81.3811351416 +57.3167348633 16.5219534933 80.2609304542 +57.3238141739 10.2935258341 81.2897512265 +57.32560986 10.2835207844 81.2897512265 +57.3291959933 10.2635097455 81.2897512265 +57.3338887347 7.21245749648 81.613759008 +57.3344088662 31.2597344962 75.7337082097 +57.3405920646 9.61610163675 81.3608449501 +57.3412894034 -5.14783813252 81.7647619217 +57.3453330283 49.0121706578 65.6454104053 +57.3485866451 -6.85870885769 81.6339250717 +57.3570027101 14.375160611 80.6444604267 +57.3571788196 -4.96767005176 81.7647619217 +57.3571868408 -7.36797599857 81.5834912675 +57.3593964097 68.7960407133 44.4635179185 +57.3638599111 -1.6023176918 81.8951778441 +57.3658356173 19.0052639339 79.6740914397 +57.3686151097 -81.7788891598 -4.58860416543 +57.3708661514 -3.15730980418 81.8450677307 +57.3737296018 15.2659690796 80.4686606055 +57.3758304346 4.74739821619 81.7647619217 +57.3775839201 -1.62274541626 81.8851608095 +57.3805020027 -2.97705862834 81.8450677307 +57.3815376963 -2.95702887365 81.8450677307 +57.3837124764 -6.55833971475 81.6339250717 +57.3859354895 32.3353128439 75.2414908896 +57.3884378623 27.6808964097 77.0735698776 +57.3900164324 34.2792306974 74.3728469045 +57.3949120161 68.327904018 45.1344835704 +57.3961408864 64.8745358427 49.969766965 +57.3988355863 60.3168606602 55.3827589908 +57.4014675211 11.2617201923 81.1063818989 +57.4079482894 10.2259130777 81.2388957023 +57.4167075429 21.718872784 78.9405615633 +57.4194104324 68.7459590079 44.4635179185 +57.4358727151 68.8633255324 44.2601730913 +57.4508391377 64.3682270149 50.5582083675 +57.453194486 60.331797691 55.3100771174 +57.4544184979 17.2918172751 79.9998928149 +57.4722536904 -8.31259787703 81.4115518356 +57.4812218603 40.8195873363 70.9201693677 +57.4838475976 -1.38479751229 81.8149717425 +57.493044685 57.7545335942 57.9565670322 +57.4939224663 78.8438474859 21.8654200292 +57.5028156019 -4.02098857282 81.7144898335 +57.5163697649 -6.26859198672 81.5633003474 +57.5203768959 55.9752016444 59.6505074801 +57.5208193368 9.65664793695 81.2287171722 +57.5209161216 -70.6030559475 -41.3104429825 +57.5405046749 -71.514820825 -39.6827509647 +57.5439848359 12.5255777741 80.8195502996 +57.5455578768 -5.7133808955 81.5834912675 +57.5488033241 -3.2980884182 81.7144898335 +57.5544614368 -5.62298153313 81.5834912675 +57.5572922448 26.0123050096 77.527531223 +57.5652554264 -10.150307683 81.1369990919 +57.5767434198 -2.09111849697 81.7346061384 +57.5857294736 10.5170216267 81.0757424702 +57.5887457027 -1.72931425211 81.7346061384 +57.5891927077 -3.34074161935 81.6842967082 +57.5965247836 -8.14592518893 81.3405448449 +57.6030425189 40.2592161919 71.1413030818 +57.6063064853 -8.17807682889 81.3303910756 +57.6109754159 11.0732708532 80.9836908534 +57.6139024663 -4.4533788506 81.613759008 +57.6223391934 40.919800086 70.7476924486 +57.6233364326 -5.93446414484 81.5127795729 +57.623883308 67.8756722344 45.5234136597 +57.6246013541 -71.4915145575 -39.6026345721 +57.6294353931 33.0982551018 74.7218420912 +57.6310322833 35.0815607266 73.8102175512 +57.634015803 39.4923913893 71.5448897181 +57.6440371281 50.5880715082 64.171738364 +57.6550693921 39.9669411744 71.2638518925 +57.6559592173 8.71964401789 81.2388957023 +57.6587130643 64.8741223618 49.667102347 +57.6590829152 13.2374705351 80.6238149135 +57.6590973475 11.4168087136 80.9016994375 +57.6677965407 58.8473087152 56.669387672 +57.6749199621 12.9130119001 80.6650961137 +57.6778141864 39.7150165389 71.3861836212 +57.6781680427 -4.8940634386 81.5430994891 +57.6858342277 28.4475052962 76.5707775321 +57.6919782909 15.049141376 80.2817475191 +57.6941928659 -7.74929889744 81.3100761047 +57.7053331046 -81.5605171606 -4.23987874556 +57.7069413056 50.4652608793 64.2118865129 +57.7159940922 23.1431953016 78.3151105291 +57.7455034943 13.6717437064 80.4893797356 +57.7465790928 62.2951728242 52.7697266042 +57.7594933691 -6.65235557974 81.3608449501 +57.761399852 -2.4714166737 81.5935829999 +57.7642905278 -2.72409479036 81.5834912675 +57.7654630763 68.404613984 44.5416665749 +57.7697518833 -6.17380546667 81.3912765191 +57.7719311065 21.9454979529 78.6180583316 +57.7866498438 10.1165663931 80.9836908534 +57.7898388323 27.8372201583 76.7165151815 +57.7993693102 68.3963171814 44.5104111795 +57.8087501338 -66.0809311329 -47.8691857941 +57.8109501524 22.8306365273 78.3368117696 +57.8110655246 -3.20177681804 81.5329953339 +57.8143164495 -2.22100200652 81.5633003474 +57.8146098754 30.8701267453 75.5281812285 +57.8162056561 39.2918527899 71.5082978952 +57.8213028997 -72.3796624101 -37.6547659716 +57.8320353498 23.3304426886 78.1738199863 +57.8329523344 36.0258574169 73.1948578909 +57.8359958512 64.4592707366 50.0 +57.8423732594 13.5668061665 80.437563527 +57.8457100363 -1.14099379082 81.5633003474 +57.8504675714 14.0168783538 80.3545301958 +57.8579710962 63.7637088052 50.8590662521 +57.8612364363 -15.5038715762 80.0731370949 +57.8728479921 -3.114021105 81.4925538797 +57.8734636462 36.8694625789 72.7413564262 +57.8741719374 -1.14155519551 81.5430994891 +57.8977245417 -66.136037957 -47.6851966153 +57.9002013526 52.6851295322 62.2241416936 +57.9072519402 23.8676469186 77.9556643439 +57.9076143715 38.2555833084 71.9945730144 +57.9108250993 1.41531008032 81.5127795729 +57.9190881431 -2.44778242291 81.4824373094 +57.9254254758 -3.67480960971 81.4318172325 +57.9273416612 -3.64447942551 81.4318172325 +57.9324865992 -80.9192410504 9.79302937057 +57.938533594 64.9831009124 49.1967775447 +57.9434141999 8.0196986308 81.1063818989 +57.9462142467 -73.3726334221 -35.4780625061 +57.9539897698 9.19974861664 80.9734505573 +57.9579382746 33.827187915 74.1390500932 +57.9586027929 67.6214621697 45.4767876649 +57.9588111004 9.78219014099 80.9016994375 +57.9603479421 65.8588797989 47.9917286421 +57.9638802563 -68.590989597 -43.9939169856 +57.9641063963 -0.880215768996 81.4824373094 +57.9686505135 8.04381497595 81.0859580832 +57.9701758667 -75.6848674004 -30.1870759858 +57.9714548029 8.02357961001 81.0859580832 +57.9739377423 58.8507133715 56.3526048938 +57.9777652369 14.3802667793 80.1984205923 +57.9850072521 29.4556585601 75.9611947823 +58.0027577577 -69.5429981373 -42.4199422745 +58.0059866744 10.9603449658 80.7166423246 +58.0064765614 13.0404132032 80.4064443961 +58.0067816127 -2.71523749529 81.4115518356 +58.0128057787 -6.30220748544 81.2083526892 +58.0147577919 -4.43343724975 81.3303910756 +58.0163018189 -81.0961044521 7.58489063577 +58.0235039697 12.439161421 80.4893797356 +58.0240494071 -1.43834370826 81.4318172325 +58.029837428 10.9858324369 80.6960312144 +58.0326832257 7.56803008352 81.0859580832 +58.0504900712 48.2286855232 65.6059028991 +58.0584698449 9.35143289414 80.8811769332 +58.0587470257 -7.36541210866 81.0859580832 +58.0626964044 -3.02261397743 81.3608449501 +58.0639097053 27.260937037 76.7165151815 +58.0654671219 19.6201960257 79.0155012376 +58.0673264734 3.44983485938 -81.3405448449 +58.077546081 -6.6171005414 81.1369990919 +58.0885047144 57.0834146013 58.027660624 +58.0919951011 63.7304537391 50.6334807353 +58.0955244361 -0.608397148817 81.3912765191 +58.1034680752 13.8636334393 80.1984205923 +58.1048411469 -73.2312630493 -35.5106962408 +58.1063522143 11.695189693 80.541134648 +58.1168947806 18.7152538375 79.1970063504 +58.1257272909 11.7413186008 80.5204400411 +58.1438027384 13.5090933769 80.2296865209 +58.1441650864 21.7739193276 78.3910231054 +58.1537156119 40.1175612257 70.7723578937 +58.1592616819 20.1963066579 78.8010753607 +58.1717728424 22.4699513376 78.1738199863 +58.1723234658 -5.72434808104 81.1369990919 +58.175457605 32.0748463725 74.7450357056 +58.1790838738 6.47442526459 81.0757424702 +58.1880455433 56.9819441433 58.027660624 +58.1892360457 8.30227899683 80.9016994375 +58.1944778447 25.0023208221 77.3840209727 +58.2190074126 -4.55126430017 81.1777874123 +58.2229062768 -9.0341939248 80.7989883898 +58.2231071258 -3.45908993547 81.2287171722 +58.2375514402 64.0022333552 50.1208711795 +58.2402063402 54.4621014536 60.3486360302 +58.2483195354 -67.5289686682 -45.2434709312 +58.2508799705 -0.681199713931 81.2795850728 +58.2563097545 51.8497873041 62.5923472184 +58.2666387876 65.7890110844 47.715876026 +58.2791096154 64.8392082968 48.9838999048 +58.2817392853 10.1508292607 80.6238149135 +58.2835112227 8.91863048632 80.7681270663 +58.2872779766 65.8817830932 47.562420907 +58.3102120796 38.6679074662 71.4472679633 +58.3135583985 65.1057329782 48.5877807712 +58.3149660388 12.2145008625 80.3129547743 +58.3192929588 65.0664202663 48.6335380423 +58.3195930945 -78.5273987185 -20.7911690818 +58.3232434478 64.2539344658 49.6973961028 +58.3333168251 -1.55807627797 81.2083526892 +58.3361754725 65.1309844158 48.5267503577 +58.3393241406 12.1664683083 80.3025548019 +58.3494722808 10.4146394158 80.541134648 +58.3532721646 14.5491048082 79.8950510167 +58.3602194649 -69.5510012118 -41.9135182781 +58.366801387 14.5524780222 79.884553446 +58.3685020551 17.6780835898 79.2502575922 +58.3693515136 8.33837238768 80.7681270663 +58.3752746884 38.2288184948 71.6301943425 +58.3862947714 -6.13664686195 80.9529625656 +58.3896524011 15.9516962136 79.6002002535 +58.3969858647 35.6456724112 72.9326955506 +58.4024310204 10.276905492 80.5204400411 +58.4082075935 51.7115751777 62.5651203016 +58.4122108172 8.03263827395 80.7681270663 +58.4191142198 -2.37699217344 81.1267958321 +58.4201967908 20.5729988857 78.5100778485 +58.4211255461 64.8377042599 48.8164336698 +58.4242472081 9.98663946344 80.541134648 +58.4274403067 8.90934835835 80.6650961137 +58.4280582847 13.5214074888 80.0208319415 +58.432042555 38.822156255 71.2638518925 +58.4331204976 20.5775500413 78.4992666412 +58.4376232669 -80.5802711844 9.58457525202 +58.4388719873 26.4475809717 76.7165151815 +58.4434001616 64.7487139334 48.9078012338 +58.4443108218 12.3481118826 80.1984205923 +58.4444567721 2.4495485044 81.1063818989 +58.4457976833 71.994525301 37.4282922379 +58.447889652 -9.23632348261 80.6134884728 +58.4503427692 17.8366033081 79.1543619303 +58.4509593227 36.9511625991 72.236396206 +58.4512962673 21.2976412043 78.2933997461 +58.465747527 -80.5598676969 9.58457525202 +58.4740676555 -4.73552822579 80.9836908534 +58.4779054535 12.9856570708 80.0731370949 +58.4788012292 -1.40876614647 81.1063818989 +58.4897056412 30.1500150399 75.2989437316 +58.4943983146 -4.09032679069 81.0041640446 +58.496350279 28.1523922078 76.0632619404 +58.4994257027 -4.94318159722 80.9529625656 +58.500050282 8.1175527873 80.6960312144 +58.5146938043 -3.32270510964 81.0246273656 +58.5148967427 10.2861670718 80.437563527 +58.5200616919 35.9314233643 72.6934329537 +58.5215284834 -3.68186249171 81.0041640446 +58.5251091371 8.14185347469 80.6754102716 +58.5352845683 68.9004573753 42.7357863387 +58.5398558837 10.1431576419 80.437563527 +58.5675181 10.1479506537 80.4168198895 +58.5768195148 -1.45204618877 81.0348553241 +58.5823948277 25.6305557644 76.8841832073 +58.5894329188 34.8570496655 73.1591719395 +58.5896797325 11.0494544716 80.2817475191 +58.6049020745 68.8118467701 42.78311813 +58.6088991838 -0.0818335141177 81.0246273656 +58.6094824574 11.0955670743 80.2609304542 +58.6112570623 54.0470431531 60.3625519008 +58.6117912955 39.489516765 70.7476924486 +58.6183156477 -80.7700910864 6.33130764713 +58.6261697848 -66.381468167 -46.4378391008 +58.6297704457 -80.934357777 -3.48994967025 +58.6356277475 32.1020684999 74.3728469045 +58.636977569 -0.173979925281 81.0041640446 +58.6482376815 40.2024077824 70.3146544139 +58.6511900231 -66.4565377005 -46.2986663495 +58.6561183344 -6.2685307141 80.7475405485 +58.6704787901 52.7345005348 61.4560604976 +58.6826960886 30.9137022305 74.8377190605 +58.6855106244 65.3372145464 47.8232081533 +58.6909081063 68.6696717553 42.8935133403 +58.6939319147 -1.28070615033 80.9529625656 +58.6959355597 6.5526860921 80.6960312144 +58.7130335007 7.36513227259 80.6134884728 +58.7155234862 -76.1886315026 -27.345561459 +58.7220858357 9.47935184977 80.3856860617 +58.7263532844 48.358648134 64.9049811691 +58.7314271206 20.4294623326 78.3151105291 +58.7378865743 21.2280394532 78.0975737252 +58.7394583848 68.7264766642 42.7357863387 +58.7408129826 52.5757183547 61.5248789485 +58.7439316911 31.6303483069 74.4894056592 +58.7477314028 60.9413947793 53.243313734 +58.758218524 5.96844218649 80.6960312144 +58.7678650729 33.7657298448 73.5269577966 +58.774138568 0.71809729182 80.9016994375 +58.7749569935 8.86789204216 80.4168198895 +58.7826853688 55.1041611032 59.2294464767 +58.7839622001 -2.08359850475 80.8709119852 +58.7878621622 8.29348676705 80.4686606055 +58.7888180449 32.7617659214 73.9631094979 +58.7908020088 63.9793256939 49.5003786139 +58.8090974575 -3.11293199451 80.8195502996 +58.8134672191 19.2004838044 78.564098005 +58.8145881385 65.7112604565 47.147369718 +58.8171194828 13.3845142065 79.7583928825 +58.8300708479 39.6067315892 70.5005643726 +58.8369089423 8.44708381499 80.4168198895 +58.8413015179 23.4395932939 77.3840209727 +58.8470759461 14.9233888947 79.4626586297 +58.856685208 8.40799059853 80.4064443961 +58.8567351873 15.276196512 79.3884282702 +58.8579320991 39.8947766464 70.3146544139 +58.8672197772 38.771570975 70.9324729572 +58.8683347896 12.9645867522 79.7899658444 +58.8687691831 12.2983266303 79.8950510167 +58.8763862591 64.2973459109 48.9838999048 +58.878909643 8.14917652968 80.4168198895 +58.8805591789 7.92957278918 80.437563527 +58.8849610691 40.1384846058 70.1531425771 +58.8926526692 35.2186105186 72.7413564262 +58.8943191526 4.42828610146 80.6960312144 +58.8961545916 8.32973293131 80.3856860617 +58.9060055978 -76.023325167 -27.3959218692 +58.9254542849 57.5029423039 56.7556381667 +58.9307202333 -3.91417411915 80.6960312144 +58.9324276386 -68.442747238 -42.9250430767 +58.9328721834 -66.963934537 -45.196770322 +58.9374864151 -1.69774711649 80.7681270663 +58.9440242246 -3.70844367068 80.6960312144 +58.9461762386 -0.442394394238 80.7784166349 +58.9491134639 -7.62476889388 80.4168198895 +58.9526330176 80.1662752857 -9.89724037811 +58.9583973259 -74.707880299 -30.7024429971 +58.9602734371 -0.442500194511 80.7681270663 +58.9613155048 37.8524918129 71.3495069184 +58.9669904393 39.5793723551 70.4014724456 +58.9680991035 27.4346528201 75.9611947823 +58.9718371131 -69.5372034855 -41.0718852613 +58.988381594 26.2016622247 76.3796028635 +58.9900338634 -0.10295713622 80.7475405485 +59.0009565814 -1.92633702164 80.7166423246 +59.0027201608 -68.2829953292 -43.0826132274 +59.005362635 -1.23598615186 80.7269441918 +59.0139386224 6.61947381948 80.4582973635 +59.0185113622 -73.3517769661 -33.7095258423 +59.0201849716 -3.12410545413 80.6650961137 +59.0327816661 40.0734678592 70.0660250228 +59.0367424719 29.6536674849 75.0687887408 +59.0389565384 -1.59754721385 80.6960312144 +59.0425039982 28.5422616312 75.4938542041 +59.0511095415 -9.37390791339 80.1566984871 +59.0516472381 75.8005794635 27.6979261222 +59.0555069 -0.773078933129 80.6960312144 +59.055594017 -66.3991165379 -45.8649554484 +59.0561319123 55.5933311495 58.4957674987 +59.0562798618 -2.97099501151 80.6444604267 +59.0610892055 12.2632176308 79.7583928825 +59.0678638373 16.7145206865 78.9405615633 +59.0842288714 -76.5840907387 -25.3757944585 +59.0868991875 25.5447006729 76.5258558393 +59.0906139487 11.6252515375 79.8320290977 +59.091308143 -67.4994575212 -44.1819028143 +59.0974958635 22.3310828116 77.5165061333 +59.1032023307 15.3181480406 79.1970063504 +59.1111922688 15.3973122862 79.175688964 +59.1126928375 55.6076687834 58.4249665637 +59.11276201 39.9772252816 70.0535711176 +59.1195242515 9.02543975855 80.1462618557 +59.1205657575 -5.12039591209 80.4893797356 +59.1384094195 30.2626530347 74.7450357056 +59.1398281535 -70.4052042207 -39.3139662794 +59.1441208931 14.0028783829 79.4096490407 +59.1462765603 40.0149368686 70.0037341608 +59.1618318749 -6.16596509806 80.3856860617 +59.1777715711 6.01105883091 80.3856860617 +59.180600338 34.278200104 72.9565729819 +59.1869744758 14.1221607883 79.3565789779 +59.1914283247 7.4986087249 80.2505182542 +59.1941302266 -77.1432924346 -23.3445363856 +59.2029998978 9.74792043047 79.9998928149 +59.20306737 50.5641963609 62.7555484428 +59.2192153175 7.50212889315 80.2296865209 +59.2218304466 7.48145703076 80.2296865209 +59.2263178937 -6.48633672978 80.3129547743 +59.2342070715 46.9147976315 65.5004616457 +59.2381768181 39.3279516619 70.3146544139 +59.2413959302 -1.89278573982 80.541134648 +59.2433781335 0.124079222436 80.5618194412 +59.2455579721 17.5830817762 78.6180583316 +59.2458901032 6.43616331046 80.3025548019 +59.2460434161 61.8459921322 51.6234403806 +59.2525271127 -67.3271503615 -44.2288690219 +59.2564286434 -2.60791569052 80.5100890583 +59.2592442499 14.1175433367 79.3034484816 +59.2715589608 7.30913676288 80.2088450119 +59.2837937417 14.0140949946 79.3034484816 +59.2858825372 -3.15892262377 80.4686606055 +59.2885957943 -1.72857414286 80.5100890583 +59.2937738493 35.1640882492 72.4412539946 +59.2947752824 8.98866395009 80.0208319415 +59.2976933794 58.007800127 55.8469218875 +59.2979561302 10.2745131123 79.8635510047 +59.3116332654 13.8349906457 79.3140794136 +59.3125522006 0.383029074145 80.5100890583 +59.3135856868 0.155282958974 80.5100890583 +59.3220608629 8.51673599438 80.0522223488 +59.322537661 4.35637485121 80.3856860617 +59.3251667921 -3.2129361851 80.437563527 +59.3257258365 48.904354422 63.9439001981 +59.3349677545 -3.02654512832 80.437563527 +59.3356145045 32.8902681934 73.4677827999 +59.3437840321 10.6562478933 79.7794439539 +59.3484639763 25.3755017699 76.3796028635 +59.3505910068 14.2707294392 79.207661425 +59.3597440333 31.4957204572 74.057007644 +59.3688734275 -0.362668321156 80.4686606055 +59.3721950875 19.9463492195 77.9556643439 +59.3777938769 0.860220718301 80.4582973635 +59.3865736949 -6.69275935258 80.1775644244 +59.3906526011 5.56178265025 80.2609304542 +59.3909339143 -71.8678904095 -36.1624570082 +59.395731393 31.2893250725 74.1156206801 +59.3969126263 -3.18563131176 80.3856860617 +59.4041723055 9.1962517466 79.9160388565 +59.4081857149 -1.95001254413 80.4168198895 +59.4085251515 -1.93964383005 80.4168198895 +59.4103081679 33.749752316 73.0162276621 +59.4111063 16.5096628675 78.7257993304 +59.4121723817 14.945355376 79.0368909154 +59.4123332355 53.6831625719 59.9023598516 +59.4170681763 5.42828971744 80.2505182542 +59.4201391589 51.8720282634 61.4698279336 +59.4275723198 -71.8866714083 -36.0648044776 +59.4365409755 7.4558911371 80.0731370949 +59.4384352637 2.28339435787 80.3856860617 +59.4417927818 54.3158773776 59.2997363872 +59.4460436781 2.07590158848 80.3856860617 +59.4524871759 23.3590456897 76.9399555047 +59.4531821791 24.0810179848 76.7165151815 +59.4605272743 51.9072858965 61.4009720373 +59.4608413894 13.8041556368 79.207661425 +59.464454637 -2.33636478584 80.3649179326 +59.471895971 13.8176616963 79.1970063504 +59.4760282237 33.8145528798 72.9326955506 +59.4770906622 -4.54518745376 80.2609304542 +59.4822342828 0.0726712945844 80.3856860617 +59.4888471629 61.7748854255 51.4289859311 +59.4896724347 56.4141381647 57.2575225515 +59.5012712363 1.03859855274 80.3649179326 +59.5012960737 61.7878127233 51.3990463377 +59.5027155879 -8.23551482631 79.9475023575 +59.5102769393 -0.0830920757066 80.3649179326 +59.5154541751 24.9813326457 76.3796028635 +59.5199180431 -0.727209160313 80.3545301958 +59.5267805475 10.4212067875 79.6740914397 +59.5294610892 54.3578677487 59.1731820696 +59.5392135843 13.1450249868 79.2609005996 +59.5520429481 -0.207876689452 80.3337473792 +59.5583188576 32.2433759253 73.5742574804 +59.5709988553 46.374757336 65.5795545685 +59.571050856 6.01949520353 80.0940420843 +59.5723174193 7.71594868331 79.9475023575 +59.5744553293 2.39275729849 80.2817475191 +59.5757731442 33.0641805071 73.1948578909 +59.5867173908 -2.75792552671 80.2609304542 +59.6004217849 -70.853038899 -37.7840786818 +59.6049115147 6.87543983579 79.9998928149 +59.608697325 29.8237915462 74.5475999683 +59.6091348141 -3.64585087014 80.2088450119 +59.6120025331 5.13151346838 80.1253812691 +59.6233333999 30.3140955543 74.3378350842 +59.6332062867 -1.43657599773 80.2609304542 +59.6381222793 33.0307422279 73.1591719395 +59.6452678147 -2.37474800091 80.2296865209 +59.645550392 -4.72563169476 80.1253812691 +59.6466589607 -2.96938658262 80.2088450119 +59.6479775724 12.0271419901 79.3565789779 +59.6603127703 -0.708096092242 80.2505182542 +59.6612530261 34.3344594561 72.5374371012 +59.6703321058 12.868482349 79.207661425 +59.6784845087 -2.24046169395 80.2088450119 +59.697342803 70.9431199198 37.4606593416 +59.6979750653 20.6722773293 77.5165061333 +59.7018743231 26.3939225327 75.7564984384 +59.717570381 0.59411248787 80.2088450119 +59.7175994135 58.1743097836 55.2228032744 +59.7208604581 -3.65268430326 80.1253812691 +59.7251226929 31.3563904304 73.8219919705 +59.7271304664 8.63873584271 79.7373320929 +59.7315749242 25.9968239568 75.8703110659 +59.7342290297 0.187661232469 80.1984205923 +59.7364055627 27.0599303001 75.4938542041 +59.7565615826 27.4596797707 75.3333879147 +59.7597612574 -0.573670147506 80.1775644244 +59.7735527445 -67.6092510667 -43.0826132274 +59.7785863683 33.0404026408 73.0400739673 +59.7798767698 -3.36314673827 80.0940420843 +59.7822026631 27.1184098361 75.436596508 +59.7841562278 3.76130029611 80.0731370949 +59.7888845355 79.5445404719 -9.89724037811 +59.7981803133 14.3562729249 78.8547719477 +59.7994738843 31.9031252441 73.5269577966 +59.8089579465 3.34383987956 80.0731370949 +59.8111583638 10.567849449 79.4414620535 +59.8592333954 29.1694379184 74.6057375062 +59.8632177422 -3.11634508706 80.0417613178 +59.8636230993 4.97428348825 79.9475023575 +59.864323511 29.1589900671 74.6057375062 +59.8659456245 -9.39616767905 79.5473480855 +59.8669553619 -2.05921622929 80.0731370949 +59.8739551687 32.3332230387 73.2780470562 +59.9008354791 -4.11514018146 79.9684658487 +59.9099883983 58.3209825499 54.8585115048 +59.9168481339 58.3276603432 54.8439180637 +59.92849536 26.4691069298 75.5510544084 +59.9316138666 -4.2749244536 79.9370169588 +59.9374163889 58.3476830618 54.8001277184 +59.9418090902 -0.544029539734 80.0417613178 +59.9433147947 15.3127892977 78.564098005 +59.9440139771 0.177857991751 80.0417613178 +59.9459864676 15.3023269824 78.564098005 +59.9465377297 63.5470240429 48.6640354832 +59.9524740355 13.25821346 78.9298462742 +59.9643197292 -2.07304342021 79.9998928149 +59.9646105869 15.2847875769 78.5532987588 +59.9679937514 62.3595183638 50.1510737159 +59.9696601231 29.7691978136 74.2794367659 +59.9774102407 4.95211891381 79.8635510047 +59.9799711667 23.0001349167 76.6380900901 +59.9822082577 -73.8607535292 -30.7688768178 +59.9977665431 2.30488169821 79.9684658487 +60.0000651443 59.9581918116 52.9623207325 +60.0035594933 28.0183780165 74.9302565154 +60.004841903 58.8637502825 54.1708210283 +60.0079398516 30.8398920201 73.8102175512 +60.0081472985 15.6645082062 78.445174743 +60.0143235649 -3.88095221376 79.8950510167 +60.0289830989 -4.2818698049 79.8635510047 +60.0326337672 52.5916245845 60.2511734868 +60.0364825889 53.7354020029 59.2294464767 +60.0410266532 -0.345815312354 79.9684658487 +60.0459841361 -70.9291811117 -36.9260213935 +60.0503421693 10.2430202713 79.3034484816 +60.0596189721 -4.80063281973 79.8110023334 +60.0622939662 7.72612408109 79.5790666583 +60.0647278972 18.2261601285 77.8462301567 +60.069266161 0.283071843276 79.9475023575 +60.0696687237 -0.178230817983 79.9475023575 +60.0832557335 5.02421166675 79.7794439539 +60.0857399012 5.62687579735 79.7373320929 +60.0907269293 18.2340493263 77.8243148526 +60.0917926083 11.1916055629 79.1436947965 +60.0991758348 23.9771399045 76.2442511011 +60.1000530176 -2.18276208534 79.8950510167 +60.101563154 -68.8471873154 -40.5939269498 +60.1028515949 24.7112698369 76.0065811178 +60.1167575981 30.169875671 73.9983382104 +60.1191771153 26.165519089 75.5052988457 +60.119776731 19.4993035795 77.4944488704 +60.1211641156 8.82431835354 79.4202557977 +60.1217683806 9.98543945033 79.2821793707 +60.1268383178 74.1181176033 29.8541112219 +60.1301503739 48.0012684111 63.8767817516 +60.1318907647 6.92559258602 79.6002002535 +60.1333771045 12.3436096049 78.9405615633 +60.1339739617 60.7034109378 51.951911188 +60.1372847434 -4.13138405954 79.7899658444 +60.1373876754 -0.524811031525 79.8950510167 +60.1383985854 11.0917187291 79.1223532967 +60.1388552934 20.8014390032 77.1402503197 +60.1438700799 -3.5942729929 79.8110023334 +60.1529839178 -7.6737642131 79.5156077043 +60.155014036 1.78535913709 79.8635510047 +60.1671807474 -1.31285255421 79.8635510047 +60.1681643324 11.8917927788 78.9833986695 +60.1723683474 17.4816890381 77.9337964931 +60.1738603404 4.20776621594 79.7583928825 +60.1781657883 12.3309137117 78.9084084835 +60.21000384 12.3812432242 78.8762337705 +60.2145014337 -1.03002292925 79.8320290977 +60.2203303893 -0.599114298852 79.8320290977 +60.2298699443 31.5275814366 73.3374009306 +60.2315212025 25.6039916488 75.6081970773 +60.2325948995 13.5187799852 78.671958787 +60.2348985875 -4.87812929518 79.6740914397 +60.2394560382 1.18820989939 79.8110023334 +60.2519175756 14.1097725913 78.5532987588 +60.2630328072 1.38860629185 79.7899658444 +60.2645561906 -71.7696088538 -34.8899199214 +60.2699290256 50.9320388817 61.4285200099 +60.2751741956 -4.3523015702 79.6740914397 +60.2769541699 1.38892707378 79.7794439539 +60.2800075851 6.20806717923 79.5473480855 +60.2802839268 -79.2725975591 9.06325801978 +60.28040719 51.9042685764 60.5988400266 +60.2817118021 -4.98783701971 79.6318824597 +60.2829911068 31.0078545679 73.5151272753 +60.286303125 50.9458760686 61.4009720373 +60.30044024 32.5363521187 72.8370969882 +60.3036688577 -4.34377937151 79.6529918024 +60.3037132364 -2.66455284795 79.7267980545 +60.3117353549 14.568661316 78.4235212544 +60.3171136831 -5.06496955014 79.6002002535 +60.3364066371 34.3734208559 71.9582238024 +60.3467747362 0.47397220615 79.7373320929 +60.3483382219 0.189590519743 79.7373320929 +60.355235365 7.73168396696 79.3565789779 +60.3623450417 0.158028610818 79.7267980545 +60.3698644535 31.1191909974 73.3966989553 +60.3779545371 21.737401192 76.694119692 +60.3819428941 30.6732718917 73.5742574804 +60.3824764556 44.7949494719 65.93458151 +60.3849247247 0.811563990177 79.7057226922 +60.3855386429 21.716323986 76.694119692 +60.3902474185 29.3239285897 74.1156206801 +60.3936816787 6.1878184197 79.4626586297 +60.393783903 -2.82697060546 79.6529918024 +60.3942763826 -2.81642985868 79.6529918024 +60.3959897107 10.5951067402 78.9941019319 +60.3981091637 44.7738692828 65.93458151 +60.3989873254 5.70938527729 79.4944353388 +60.4019199196 -1.40235435111 79.6846376179 +60.4136658203 9.65507328032 79.1010021561 +60.4184258109 -3.66359688579 79.6002002535 +60.4185234582 29.795118491 73.9043499209 +60.429075524 1.93073256675 79.6529918024 +60.4327368487 5.3403246298 79.4944353388 +60.4392161827 5.26648814623 79.4944353388 +60.4416568377 29.8065266113 73.8808303288 +60.4425893222 -69.3354834509 -39.2337116604 +60.4490517844 5.46938299449 79.473253287 +60.4687717503 7.60681781295 79.2821793707 +60.4725289117 3.91058302437 79.5473480855 +60.474604044 20.858501076 76.8618578918 +60.482802504 0.77064725284 79.6318824597 +60.4848159871 1.42540368965 79.6213241496 +60.4944717071 49.4788983403 62.3879596709 +60.5059913724 57.619076887 54.946037043 +60.5222727234 2.43082557749 79.5684962244 +60.5371970566 32.2831301298 72.7533317557 +60.541761946 44.5211688023 65.9739387103 +60.5441691452 -69.943419766 -37.9779095522 +60.550021305 2.43194007566 79.5473480855 +60.5530404968 -0.708121729405 79.5790666583 +60.5532839888 -0.686984688118 79.5790666583 +60.5616026633 5.75675186489 79.3671978264 +60.5650648755 44.4894631084 65.9739387103 +60.5669948009 58.5297386037 53.9064823539 +60.5788264992 16.1754003352 77.9009769128 +60.5814679229 8.0294913733 79.1543619303 +60.5842670532 8.00834396293 79.1543619303 +60.6005435359 1.77741014881 79.526190254 +60.6031189484 22.900010366 76.1764497661 +60.6083000367 6.65909924875 79.2609005996 +60.6084018691 34.4023860511 71.7153920498 +60.6086922103 16.2740679893 77.8571842519 +60.6114753063 1.35429866595 79.526190254 +60.6184638041 8.57332057918 79.0689573744 +60.6264585104 29.8976607109 73.6923497556 +60.6314244623 27.4653639517 74.6289766155 +60.6409747332 33.1037345741 72.296714591 +60.6461186944 7.85502998639 79.1223532967 +60.647083218 -2.43583848479 79.473253287 +60.651111295 -3.94339167614 79.4096490407 +60.6535366191 -4.31577946456 79.3884282702 +60.6613054336 57.5251993485 54.8731032748 +60.6617056958 5.87311640514 79.2821793707 +60.6652329513 0.603540503172 79.4944353388 +60.6699654019 32.5991483242 72.5013849983 +60.6782867461 -10.9724216719 78.7257993304 +60.6800534455 4.88220117794 79.3353340291 +60.6803129997 7.91330692867 79.0903229713 +60.6803576167 1.37702994924 79.473253287 +60.6841332179 11.5431904285 78.6396257006 +60.6847609994 17.172056465 77.6046407067 +60.6867379573 59.2630780396 52.9623207325 +60.6871844666 28.5831001626 74.1624704726 +60.6911551962 31.5265307271 72.9565729819 +60.6929766743 -0.603816517286 79.473253287 +60.693076354 -3.23390196444 79.4096490407 +60.7048703612 33.5108888123 72.055111168 +60.7077195579 -0.508595700536 79.4626586297 +60.7078074 -0.498000196967 79.4626586297 +60.7079333587 24.0972747609 75.7223096347 +60.7135848228 9.34471447254 78.9084084835 +60.7194734474 42.7852810031 66.9519624339 +60.7231528774 4.86433588032 79.3034484816 +60.7282135019 4.80074408778 79.3034484816 +60.7304202448 -79.4320922869 -1.5358293575 +60.7379323825 1.82388018407 79.4202557977 +60.7467171482 25.12485808 75.3563392302 +60.7509158852 7.35166861277 79.0903229713 +60.7609355871 8.84240203256 78.9298462742 +60.7666869094 5.17749298643 79.2502575922 +60.7669860427 31.9304442889 72.7173991201 +60.7724828946 0.901644080364 79.4096490407 +60.7815726271 11.3969234209 78.5856893175 +60.7946555951 4.83802879685 79.2502575922 +60.8084529637 13.0029039442 78.3151105291 +60.8120313879 11.4575779549 78.5532987588 +60.8336791656 8.22503612444 78.9405615633 +60.8365465386 8.20380066382 78.9405615633 +60.8382956303 -4.2542280575 79.2502575922 +60.8391768311 -78.9157705769 8.41995942791 +60.8438065404 30.8945344744 73.0996507877 +60.845949701 30.1777233641 73.3966989553 +60.848481318 -6.74998526039 79.0689573744 +60.8677751426 1.00931842507 79.3353340291 +60.8692828561 -2.05114879102 79.3140794136 +60.8728050233 -0.637481826288 79.3353340291 +60.8756615011 12.8840073854 78.282540777 +60.8775866144 -15.40439761 77.8243148526 +60.8776532209 -1.78553775852 79.3140794136 +60.8793791615 11.9771660659 78.4235212544 +60.8798739577 11.3933587284 78.5100778485 +60.8826455034 -3.31860100751 79.2609005996 +60.8921817046 14.1924627978 78.0430407338 +60.8927986313 9.53555779492 78.7473187632 +60.8971320989 14.1712065524 78.0430407338 +60.897381006 52.4725405352 59.4822786751 +60.9054043082 1.22261399681 79.3034484816 +60.9073673466 29.142718916 73.7630973935 +60.9141796582 24.6109261072 75.3907489863 +60.917573344 -1.83991633112 79.2821793707 +60.9227253291 9.15932199076 78.7688286008 +60.9256535204 27.5089873756 74.3728469045 +60.9263532875 -3.75843673289 79.207661425 +60.9270622349 17.1602517605 77.4171741084 +60.9283128486 -3.72653525517 79.207661425 +60.9308495082 -1.32951586585 79.2821793707 +60.9384081556 9.94628693484 78.6611834876 +60.938532005 -4.2078015816 79.175688964 +60.940903846 5.08521850211 79.1223532967 +60.9454070417 13.2102698405 78.1738199863 +60.9486533884 1.72374194164 79.2609005996 +60.951893899 14.9373856643 77.8571842519 +60.9530614582 25.2102021405 75.1609606571 +60.9567969352 10.0039080899 78.6396257006 +60.9571043167 14.9161085301 77.8571842519 +60.9838386319 0.606710217082 79.2502575922 +60.9884845106 14.8448377386 77.8462301567 +60.9985810008 -3.70946132086 79.1543619303 +60.9990623281 17.2035148156 77.3508466216 +60.9994975629 20.0556143415 76.6605089369 +61.0002134126 29.1871435385 73.6687492475 +61.0039697523 31.3921708856 72.7533317557 +61.0044890323 7.43637611982 78.886961078 +61.0077612384 63.4629177536 47.4395524734 +61.0218707132 4.58825750687 79.0903229713 +61.0292233506 21.0140468172 76.3796028635 +61.0301059081 8.90332958766 78.7150360167 +61.0344182915 13.4416238142 78.0648610647 +61.0356240289 -1.57695419655 79.1970063504 +61.039543315 -1.4171580849 79.1970063504 +61.0405287699 -0.447458460444 79.207661425 +61.0407526253 18.2202419482 77.0846891561 +61.0417188116 0.234384526237 79.207661425 +61.047240363 9.61433035814 78.6180583316 +61.0480594718 -5.4483941579 79.0155012376 +61.0538496533 0.511495501083 79.1970063504 +61.0555421248 -0.23443760421 79.1970063504 +61.0562642041 7.11845120968 78.8762337705 +61.0662115191 8.14797223633 78.7688286008 +61.0793012079 23.8383894207 75.5052988457 +61.0828102277 16.3899445788 77.4613452723 +61.0834994919 -0.127933169232 79.175688964 +61.0957717346 15.4823008904 77.6376521753 +61.0969057838 -9.10919169396 78.6396257006 +61.1057487718 0.821251753183 79.1543619303 +61.1172016669 0.981445036311 79.1436947965 +61.1261077801 4.48882076164 79.0155012376 +61.126722067 5.64903437987 78.9405615633 +61.1350134776 9.49698013826 78.564098005 +61.1359172422 4.72561984528 78.9941019319 +61.1444023043 -3.07604398132 79.0689573744 +61.1464129094 6.29729580863 78.8762337705 +61.1619927414 25.0469583026 75.0457228874 +61.1720710848 26.5349222374 74.5243290547 +61.1776443789 5.54607057809 78.9084084835 +61.1788022987 30.3694212021 73.0400739673 +61.1817398344 -78.2527374214 -11.5457263478 +61.1912230259 25.6596093769 74.8145618928 +61.192029015 -4.8911476267 78.9405615633 +61.1940783314 0.07476270767 79.0903229713 +61.1951387022 -78.8922974379 -5.58215049932 +61.1994644069 55.8240562434 56.0205346355 +61.2002902929 18.8510549734 76.8060036355 +61.2008726087 -8.87370421112 78.5856893175 +61.205295417 12.2300248519 78.1302649748 +61.218666444 12.2326966468 78.1193702712 +61.2207142402 34.9621756299 70.9201693677 +61.2214064847 -79.0115514563 -3.01896083135 +61.2296586584 31.5353464212 72.5013849983 +61.2317355295 -70.3646103833 -36.0485252079 +61.2385505964 17.9306119229 76.9956692089 +61.2447039732 -2.37419447529 79.0155012376 +61.2490123738 27.1674086381 74.2326773808 +61.2509648919 15.4761292542 77.5165061333 +61.2521470706 45.4401176324 64.678977951 +61.255850708 29.8367815351 73.1948578909 +61.2609701903 -0.51323071063 79.0368909154 +61.2764850831 32.1026919132 72.2122534463 +61.2854889585 28.1234055928 73.8455340626 +61.2888752751 22.2709912283 75.8134336198 +61.290402908 0.192550112976 79.0155012376 +61.2990887811 28.1555539124 73.8219919705 +61.3047128668 19.012159252 76.6829184428 +61.3048564574 -4.30835776442 78.886961078 +61.3095977078 -67.0250189531 -41.8184177516 +61.3135542819 21.9292874961 75.8930458688 +61.3146591799 55.1111563087 56.597464784 +61.3151340843 10.7563497763 78.2608156852 +61.3151882446 22.5839001884 75.6995055652 +61.3211277682 -2.17352837994 78.961984927 +61.3357128524 1.71326159004 78.961984927 +61.3408856339 33.4719188227 71.5326946227 +61.342510435 32.8640018582 71.8126297763 +61.3425427807 31.147776749 72.5734693176 +61.3466245205 29.854506048 73.111559473 +61.3466511521 24.4500130828 75.0918454472 +61.3468801859 32.5089234894 71.9703423989 +61.3471802348 -3.88113687298 78.8762337705 +61.3476456172 4.66659478203 78.8333005168 +61.3486696662 -2.17450460297 78.9405615633 +61.3515071143 -2.4641310711 78.9298462742 +61.3680768224 1.53195534894 78.9405615633 +61.3719903107 22.3133199259 75.7337082097 +61.3737238155 28.7887493078 73.5151272753 +61.3758823293 1.1784771448 78.9405615633 +61.3786824615 11.1765312682 78.1520472419 +61.3794786858 5.29445342957 78.7688286008 +61.3826904018 -3.00211440785 78.886961078 +61.3860863507 9.30569175429 78.3910231054 +61.3862838332 46.2914871721 63.9439001981 +61.3921730421 1.03944999696 78.9298462742 +61.3987549307 7.02807207837 78.6180583316 +61.4055176086 11.1814177182 78.1302649748 +61.406551195 -2.46634186976 78.886961078 +61.4216952489 27.2568334837 74.057007644 +61.4241087667 60.424555964 50.7538362961 +61.4268696015 -0.45029053738 78.9084084835 +61.4284966196 -0.053606489636 78.9084084835 +61.435598001 -72.1100518266 -32.0282332298 +61.4360190237 4.40378860113 78.7795799206 +61.4377152355 1.50150541864 78.886961078 +61.4487805216 -3.05910150842 78.8333005168 +61.449087843 4.782195195 78.7473187632 +61.4643376794 22.6753913176 75.5510544084 +61.4645142146 9.86702694044 78.2608156852 +61.4652929127 3.52254015666 78.8010753607 +61.4662290659 -0.665154569391 78.8762337705 +61.4665363011 12.9866475729 77.8023900658 +61.4693997735 22.47027873 75.6081970773 +61.4748464958 15.3615942823 77.3619070953 +61.4800167961 13.6297915829 77.6816343556 +61.4835833367 15.0449371266 77.4171741084 +61.4841015662 25.0536506933 74.7798090499 +61.4847445095 -5.50900110829 78.671958787 +61.4860357954 22.7687779289 75.5052988457 +61.4955260559 5.54242613271 78.6611834876 +61.4966662271 20.1239712028 76.2442511011 +61.4969111553 44.4346038533 65.1436558597 +61.5037059036 8.8847351679 78.3476588107 +61.5043210865 23.9424414963 75.1264133504 +61.5064203516 -3.97744178464 78.7473187632 +61.5127542529 17.4643475905 76.8841832073 +61.520304506 44.0117386443 65.4080957909 +61.5267140872 23.5932545058 75.2184937064 +61.5279561909 48.6267343434 62.0463642292 +61.5332444707 33.8981480011 71.1658301926 +61.5359223854 3.94699581526 78.7257993304 +61.5378889967 6.77210444028 78.5316930881 +61.5379021863 -0.30073331626 78.822561199 +61.5379537369 -0.289992921655 78.822561199 +61.5436839008 20.532526285 76.0972426325 +61.5486904758 34.3561199917 70.9324729572 +61.553777313 10.1680878438 78.1520472419 +61.5556688901 4.650003022 78.671958787 +61.5611734275 7.74423916776 78.4235212544 +61.5618519638 23.9029941662 75.0918454472 +61.5629258538 8.56446624645 78.3368117696 +61.5663150217 6.7643573877 78.5100778485 +61.5681492548 29.0374243296 73.2542898787 +61.5726011841 -3.57181862977 78.7150360167 +61.5795548973 19.4750559566 76.3457963096 +61.5813920909 14.1040215905 77.5165061333 +61.581829579 3.87440031683 78.6935021961 +61.5821085199 23.9232286124 75.0687887408 +61.5897897268 34.9878701622 70.5871570679 +61.5905665954 67.4030113041 40.7852445573 +61.6050534169 0.537619156412 78.7688286008 +61.6091701938 17.4684845817 76.8060036355 +61.6151433485 14.0778018318 77.4944488704 +61.6309284331 -3.74791579477 78.6611834876 +61.646086456 -73.8063888254 -27.4294913043 +61.6461199178 6.6642548052 78.4559979031 +61.6477012609 -1.34515762674 78.7257993304 +61.6593385907 -2.33638110506 78.6935021961 +61.6616621665 -78.4424751645 6.67963389185 +61.6628495988 48.3151017549 62.1558036049 +61.6717718408 15.2964938921 77.2179372467 +61.6724544699 -78.4280272018 6.74928950989 +61.6735267307 73.0324585726 -29.3706672624 +61.6746598164 8.25106938706 78.282540777 +61.6757649044 10.2656620084 78.0430407338 +61.6796469859 18.1884055988 76.582002125 +61.6859732972 13.2581137362 77.5826212405 +61.6877190163 8.55987837667 78.2390810577 +61.6888810753 31.6629579515 72.055111168 +61.698440678 -2.39178390111 78.6611834876 +61.6990978497 -78.4055677638 6.76670290174 +61.7033159816 29.2593062333 73.0519937827 +61.7112160172 25.0834229431 74.5824893064 +61.7116332085 15.5810673558 77.1291427853 +61.7166705183 34.30874472 70.8093398915 +61.7168496307 -4.87889868475 78.5316930881 +61.7182421704 -1.8101921798 78.6611834876 +61.7242075626 -70.8306197119 -34.2512118325 +61.7295097057 76.6937594938 -17.5366726092 +61.729765815 -0.398638975564 78.671958787 +61.7305555941 0.247803663226 78.671958787 +61.734367865 12.3581553039 77.6926239858 +61.7373211384 -5.45560823232 78.4776370533 +61.7394977694 9.61295578729 78.0757676633 +61.7395803221 6.16242936774 78.4235212544 +61.7429596541 14.4248470333 77.3287186058 +61.7434954355 -0.398727638817 78.6611834876 +61.7457962323 -2.89025690524 78.6072710546 +61.7547970878 26.851749987 73.927860508 +61.7568228831 1.37989023401 78.6396257006 +61.7572970843 6.65446513894 78.3693457326 +61.7574104042 33.9795017671 70.9324729572 +61.7596161683 6.63290737054 78.3693457326 +61.7613285883 9.56115881864 78.0648610647 +61.7638283384 22.7001890278 75.2989437316 +61.7688481653 26.8194115715 73.927860508 +61.7704021356 -4.72044031869 78.4992666412 +61.7721460299 -5.0460338277 78.4776370533 +61.7721884714 -2.91310245943 78.5856893175 +61.7761957144 -2.82684940184 78.5856893175 +61.787298874 30.9677554451 72.2725938412 +61.7880178741 41.3322461547 66.8871159118 +61.7995911715 74.3059318411 -25.6795448608 +61.8048633514 -3.5961155211 78.5316930881 +61.8087072454 11.9808132805 77.6926239858 +61.8286301627 32.0763038983 71.7518725918 +61.8288764837 -8.63446704805 78.1193702712 +61.8293438834 22.0164390197 75.4480526445 +61.8369271283 -3.74961066286 78.4992666412 +61.8401267814 24.4467908411 74.6870345992 +61.8457744188 17.4190092287 76.6268771648 +61.8500519358 72.1616937888 -31.1008203279 +61.8503937319 6.42434884055 78.3151105291 +61.8527478485 66.2130113436 -42.3092745435 +61.8571317373 67.0808991182 40.9126902895 +61.8627496582 27.3750542285 73.645139763 +61.8670303352 21.0251139045 75.6995055652 +61.8813893557 -0.270010211032 78.5532987588 +61.8829399837 3.89334457775 78.4559979031 +61.8847685511 28.2025138463 73.3136660803 +61.8858570181 -1.70700962399 78.5316930881 +61.88735261 6.72311796744 78.2608156852 +61.8876798277 68.3244596621 -38.7515586452 +61.8906452845 29.5468468434 72.7772757657 +61.8913498823 32.9497940115 71.3005742217 +61.8915662954 20.8288132718 75.7337082097 +61.9001969703 2.12915270915 78.5100778485 +61.900464025 4.25251308639 78.4235212544 +61.9104965131 63.0445839884 46.8238278148 +61.9109384187 63.0670483959 46.7929814261 +61.9152794274 13.9759227721 77.2733573497 +61.9170359213 4.00399510241 78.4235212544 +61.9258177952 75.7394406275 20.7058016949 +61.9258541954 5.34158253122 78.3368117696 +61.9269018073 7.57075587079 78.1520472419 +61.9272850259 -70.1686180689 -35.2331719779 +61.9321721003 7.52752089607 78.1520472419 +61.932933629 18.8757152603 76.2103608804 +61.934208008 10.1199179238 77.8571842519 +61.9359173248 69.686575811 -36.1624570082 +61.9359351643 33.9370393923 70.7970147154 +61.9476178595 10.122109065 77.8462301567 +61.948614616 -2.6505735572 78.4559979031 +61.958129662 -4.40860728926 78.3693457326 +61.9631333809 70.7799170634 -33.9230517808 +61.9634695504 4.33290788262 78.3693457326 +61.9708057849 -3.57321417929 78.4018582101 +61.9753734735 -1.92599995968 78.4559979031 +61.9792927631 -2.21851935335 78.445174743 +61.9822778212 26.1568464768 73.9865975598 +61.9839570565 2.78215414282 78.4235212544 +61.9888388621 -1.42837304494 78.4559979031 +61.9992492388 -0.865729086564 78.4559979031 +62.0004791832 -67.5905648459 -39.8428930284 +62.0022429885 9.24417218175 77.9119191464 +62.0026404806 -0.573555976552 78.4559979031 +62.0036273615 -0.454518468307 78.4559979031 +62.0059048828 -4.31412580156 78.3368117696 +62.0075561293 1.19060590137 78.445174743 +62.0139195366 35.1858731319 70.1158192968 +62.0145780503 -5.42557255274 78.2608156852 +62.0240689634 -67.5689184785 -39.8428930284 +62.0352595152 8.33237704323 77.9884483093 +62.0411072223 5.8864619747 78.2064612424 +62.0512370506 14.7026006186 77.0290692891 +62.0610353174 29.3361169982 72.7173991201 +62.0615556158 19.4489126118 75.9611947823 +62.062558679 4.48136359943 78.282540777 +62.0664157448 4.23126373442 78.2933997461 +62.0670047521 17.0727944159 76.5258558393 +62.0674504854 16.0864108466 76.7389013234 +62.0675370472 -1.57109559741 78.3910231054 +62.0681300097 -0.834186007238 78.4018582101 +62.0685516797 48.9836188195 61.2217280034 +62.0721278211 74.4220108891 -24.6660747381 +62.0742057307 19.4528769175 75.9498424128 +62.0759762233 -1.19191963429 78.3910231054 +62.0763884998 -1.17025095869 78.3910231054 +62.0780975698 23.2471046146 74.8724377134 +62.0818115343 0.834369884799 78.3910231054 +62.0818484521 14.2756712796 77.0846891561 +62.0840892041 11.4729852661 77.5495743172 +62.0859051552 -0.433448427556 78.3910231054 +62.0883069484 7.3706128168 78.0430407338 +62.090768989 -75.7791083176 -20.0564989205 +62.1055958403 8.31975537415 77.9337964931 +62.1151068484 50.0311376685 60.3207987745 +62.1181990219 31.9244179197 71.5692733704 +62.1233744617 5.43509100537 78.1738199863 +62.1240346378 28.5082072913 72.9923724601 +62.1256917996 17.8494643102 76.3006883472 +62.1264743175 55.2166630693 55.6005513314 +62.1271740402 19.1484285069 75.9838925793 +62.1291711956 24.9505783559 74.2794367659 +62.1418585484 4.70519246076 78.2064612424 +62.142493738 19.6769541958 75.8361915289 +62.1511648961 0.759357504556 78.3368117696 +62.1513428019 3.529209005 78.2608156852 +62.1585146819 29.9549674217 72.3810678237 +62.1602695124 49.9245753329 60.3625519008 +62.1610677941 -2.80097486609 78.282540777 +62.1630402488 13.9178706967 77.0846891561 +62.1646649938 34.2884319817 70.4262583022 +62.1648177225 31.2248738128 71.83691734 +62.1667591429 13.0099616569 77.2401123468 +62.1679276537 4.34720498596 78.2064612424 +62.1685747493 66.01784423 42.1510682766 +62.1712809937 15.7894939123 76.7165151815 +62.1714110509 32.3643880794 71.3250449154 +62.1753641419 66.372350708 41.5804660306 +62.1761099737 -68.7633962133 -37.4930218808 +62.1766200418 0.900768002003 78.3151105291 +62.1814738404 -0.455822174438 78.3151105291 +62.1828804848 -3.45478941068 78.2390810577 +62.1830028557 13.3876502406 77.1624583388 +62.1893936107 34.4721437828 70.3146544139 +62.1967616347 3.9130885625 78.2064612424 +62.2000991627 27.5632899681 73.2899222969 +62.2060940364 1.49855738388 78.282540777 +62.2140018652 13.3716024668 77.1402503197 +62.214296325 -2.15082799608 78.2608156852 +62.2170388976 7.08873617352 77.9665947075 +62.2240052208 -0.130321842338 78.282540777 +62.2240469208 -0.108601559541 78.282540777 +62.2241379026 0.0217203224945 78.282540777 +62.2270856919 10.6702075662 77.5495743172 +62.2283066841 -2.82577087132 78.2282101688 +62.2453518266 16.0398032297 76.6044443119 +62.2513271311 0.130379065296 78.2608156852 +62.2514172047 -0.0760544914381 78.2608156852 +62.2616364847 32.9936709197 70.9570736537 +62.2725299573 66.1513650581 41.7867073801 +62.2762002722 -3.73261189527 78.1520472419 +62.2768572246 -0.489131350265 78.2390810577 +62.2803702018 43.5282370309 65.0111380342 +62.2813512746 -3.64565430583 78.1520472419 +62.2872393154 3.99518628132 78.1302649748 +62.2887184071 11.8484107788 77.3287186058 +62.2907783738 4.90239057745 78.0757676633 +62.29146086 -0.347904765508 78.2282101688 +62.2915785066 0.326160922996 78.2282101688 +62.3020996101 6.69116942983 77.9337964931 +62.3066628383 3.67987240419 78.1302649748 +62.314396314 0.815740132459 78.2064612424 +62.3248906628 26.1733756204 73.6923497556 +62.3318583651 2.64517384188 78.1520472419 +62.3327229098 54.0323943639 56.5254987944 +62.3429114008 6.29958429067 77.9337964931 +62.3449172561 -2.96192290352 78.1302649748 +62.3456595878 0.413498135803 78.1847027868 +62.3490835191 11.7471735203 77.2955089162 +62.3536790278 50.4029815459 59.7625146976 +62.3565383445 -0.71832752904 78.1738199863 +62.3662271226 30.5934017557 71.9339800339 +62.3667899833 52.6108001644 57.8142474935 +62.3754917383 10.0244355096 77.5165061333 +62.3763990691 41.7258356761 66.0919017453 +62.3825655401 8.98946501942 77.6376521753 +62.3904173968 14.3122357026 76.8283523594 +62.3932643458 -67.1901676422 -39.906915898 +62.3980728279 17.6215924091 76.1312024621 +62.3996270622 6.80080825293 77.8462301567 +62.3996614684 -1.39425377547 78.1302649748 +62.4071787964 12.3003681973 77.1624583388 +62.4091520934 -0.871452782064 78.1302649748 +62.4094524856 -0.849667825666 78.1302649748 +62.4098241379 21.6723512353 75.0687887408 +62.4114686328 12.2785832334 77.1624583388 +62.4156528828 5.97696170682 77.9009769128 +62.4243144227 41.7578879939 66.02638684 +62.4342920428 30.965492411 71.7153920498 +62.4345742378 21.6809459216 75.0457228874 +62.4388004976 1.4714518868 78.0975737252 +62.4398478051 11.1784575966 77.3065811677 +62.4421385117 21.6591508234 75.0457228874 +62.4431107295 23.6825071286 74.4311546231 +62.4524263611 1.47177299807 78.0866718836 +62.4614731722 29.525403105 72.296714591 +62.4658362898 21.022076477 75.2069916777 +62.4697856868 4.88356840955 77.9337964931 +62.473170573 21.0002705064 75.2069916777 +62.4740677923 11.4435963809 77.2401123468 +62.4744407562 -4.45630439901 77.9556643439 +62.4767785424 4.2263758335 77.9665947075 +62.4823131882 13.1443112552 76.9622480199 +62.492724333 1.98574884085 78.0430407338 +62.4944334301 -1.93121290175 78.0430407338 +62.4947984185 -5.08310600519 77.9009769128 +62.4970110976 0.0327233614797 78.0648610647 +62.5025818045 11.4375449788 77.2179372467 +62.5031710935 7.5637147923 77.6926239858 +62.5116167447 28.0545018543 72.8370969882 +62.5242046864 -0.0873003154497 78.0430407338 +62.5293311944 26.6452259067 73.349265005 +62.5326104217 -72.5726668332 -28.6858965796 +62.5342039568 33.7134472822 70.3766780108 +62.5366193523 74.5282407818 -23.1238527491 +62.5382635222 3.18993814203 77.9665947075 +62.5414953861 -3.85807193285 77.9337964931 +62.5417564617 13.1226240181 76.9176536145 +62.5457077624 0.851522860764 78.0212108937 +62.5458554286 -0.840606562516 78.0212108937 +62.546821305 -3.77074379938 77.9337964931 +62.5483066876 4.17638425426 77.9119191464 +62.5495747485 0.491273312732 78.0212108937 +62.5498234044 0.458522366133 78.0212108937 +62.5514954098 0.0327518894014 78.0212108937 +62.555911323 29.9717708051 72.0309024888 +62.5576178936 20.326202203 75.3219088147 +62.5591346186 12.3643503763 77.0290692891 +62.5615984425 31.4652059952 71.3861836212 +62.5624825311 -1.93331576587 77.9884483093 +62.5677314522 31.9211280222 71.1780904964 +62.5683788421 19.6437253717 75.4938542041 +62.5809209479 22.4441887638 74.6986393721 +62.5817868897 3.1374055926 77.9337964931 +62.5836660156 -72.5550617634 -28.6190104747 +62.5837435584 -1.03777286644 77.9884483093 +62.5844054875 -5.47542599367 77.8023900658 +62.5849259751 32.8578207201 70.7353564932 +62.5880842978 28.5626198928 72.5734693176 +62.6057558251 16.8688870184 76.1312024621 +62.6087535603 1.74882083679 77.9556643439 +62.6109591071 -1.03822415868 77.9665947075 +62.6147115897 7.87677159113 77.5716079622 +62.6181892978 -0.41530564779 77.9665947075 +62.621982475 6.63709234087 77.6816343556 +62.6253710325 -67.4637291835 -39.0731128489 +62.6294620209 -1.96821013562 77.9337964931 +62.6330120738 -0.142110040409 77.9556643439 +62.6345846856 -69.0763227436 -36.1299105657 +62.6413715098 10.6512319826 77.2179372467 +62.6493454935 18.7957044089 75.6424550435 +62.6504521105 1.11544363996 77.9337964931 +62.6510913463 10.9907131812 77.1624583388 +62.6545748258 0.853005021516 77.9337964931 +62.6564582395 45.6396424614 63.1758757508 +62.6587452357 -4.54639918287 77.8023900658 +62.658805151 31.1313674231 71.4472679633 +62.6708365624 18.8617809152 75.6081970773 +62.6719341814 -1.91480077051 77.9009769128 +62.6747579127 13.7799392325 76.694119692 +62.6775975662 30.326530583 71.7761820252 +62.6791541927 73.6998642594 -25.2913747716 +62.6798562216 -69.0777782965 -36.0485252079 +62.6825684288 8.89872813794 77.406125421 +62.6837918361 0.689272068258 77.9119191464 +62.6858158543 5.56147791404 77.7145961457 +62.6994999863 -3.94471817861 77.8023900658 +62.7048189657 -1.71864688113 77.879085327 +62.7084001246 -4.96829690075 77.7365588364 +62.7093162126 8.90252538592 77.3840209727 +62.7101734318 1.51070075844 77.879085327 +62.7127119034 -4.91357161337 77.7365588364 +62.7199851102 6.34874524909 77.626650717 +62.728057784 -0.197066653832 77.879085327 +62.7305643909 -67.4588897438 -38.912395014 +62.7337976818 12.1714909052 76.9176536145 +62.7348377155 7.33635054172 77.527531223 +62.736774883 6.04086434047 77.6376521753 +62.7376875423 9.63383650176 77.2733573497 +62.7381293989 1.47850596332 77.8571842519 +62.7489454419 7.8936578686 77.4613452723 +62.7535103035 57.0012754502 53.0363228518 +62.756284505 2.90462651034 77.8023900658 +62.7615953726 29.6270755011 71.9945730144 +62.7664104601 8.78773263565 77.3508466216 +62.7670055776 27.3831017214 72.8729630997 +62.7676585217 -4.90685458463 77.6926239858 +62.7693825143 9.60506525354 77.2511963678 +62.7739896973 25.4898739567 73.5506121195 +62.7844740371 62.8283211761 45.942484457 +62.7849054108 30.6493785873 71.5448897181 +62.7974403037 32.3150769564 70.7970147154 +62.7984402339 7.93328792213 77.4171741084 +62.8054889323 14.1768666976 76.5146195875 +62.8068441568 -68.6618421484 -36.6176427403 +62.8087356112 6.80102990733 77.5165061333 +62.810650708 33.3267389988 70.3146544139 +62.8110296735 18.1532263225 75.6652821672 +62.8122230952 2.55574163846 77.7694851116 +62.813512881 1.11834681294 77.8023900658 +62.8159954187 -3.81998239162 77.7145961457 +62.8170339584 -0.899079921954 77.8023900658 +62.8230046315 -0.241224206395 77.8023900658 +62.8326826604 14.9456808326 76.3457963096 +62.8370219445 -77.7913944965 0.0872664515235 +62.8387136597 24.8796067747 73.7041466427 +62.8418582623 13.3230626163 76.6380900901 +62.8455511308 7.88352720383 77.3840209727 +62.8460330831 23.3472619338 74.1975840976 +62.8510418991 -68.1826185501 -37.4282922379 +62.8619245038 7.75188659506 77.3840209727 +62.8641877546 -77.7694744511 0.0523598751674 +62.865751583 -2.88770216776 77.7145961457 +62.8705649363 4.98114498697 77.6046407067 +62.8719654184 6.71907479513 77.472382165 +62.8731644394 4.94822535485 77.6046407067 +62.8749388012 -4.374589747 77.6376521753 +62.8861300021 1.53690391307 77.7365588364 +62.8882327773 6.29925173491 77.4944488704 +62.8921988904 34.3611725799 69.7415309387 +62.8934279651 4.10020529981 77.6376521753 +62.8944152979 -66.6253481611 -40.0668879095 +62.8966169548 18.1898572594 75.5853469168 +62.8976872041 4.0343412199 77.6376521753 +62.8977868125 28.796855146 72.2122534463 +62.8984344012 4.97230643996 77.5826212405 +62.8990916229 4.01238553989 77.6376521753 +62.9058098792 34.0556233744 69.8789925516 +62.9102156953 27.7204836159 72.6214813211 +62.9103984698 50.9802065466 58.6796413149 +62.9169388571 26.8103946929 72.9565729819 +62.9203902036 22.3059993827 74.4544618419 +62.9213441451 28.3175823768 72.3810678237 +62.9289246671 -4.17973456464 77.6046407067 +62.9299227532 20.2409405371 75.0341865315 +62.9334545053 20.2299568854 75.0341865315 +62.9362543687 2.14279487486 77.6816343556 +62.9398479937 75.6232319676 17.8802215116 +62.9428121992 5.72824464611 77.4944488704 +62.9428202945 27.8661370154 72.5374371012 +62.9441990367 31.8643783121 70.87093341 +62.9655936046 -66.6541227947 -39.906915898 +62.9852943366 12.9633964631 76.582002125 +62.9863502592 26.2186870849 73.111559473 +62.9867898402 -66.6532527784 -39.8749068925 +62.9915350131 1.02254081112 77.6596479968 +62.9941530722 5.45588493181 77.472382165 +63.0001328343 73.4256741543 25.2913747716 +63.000196613 17.4359821493 75.6766922719 +63.0017265831 -69.896872261 -33.8409470269 +63.0067070055 -3.57778010441 77.5716079622 +63.0079520478 -3.55578639713 77.5716079622 +63.0089221995 31.2093951978 71.1044961634 +63.0150812265 11.2473913315 76.8283523594 +63.016751359 14.8616938013 76.2103608804 +63.0208630105 4.79387313931 77.4944488704 +63.0221839252 30.1005555188 71.5692733704 +63.0229180299 11.2033957684 76.8283523594 +63.0234825979 0.660004492485 77.6376521753 +63.0251091114 6.93576962455 77.3287186058 +63.0265150652 -0.231005277243 77.6376521753 +63.027980324 22.9652274029 74.1624704726 +63.0292750229 -72.4302576331 -27.9493876371 +63.0302520352 -70.5698297895 -32.358715238 +63.0314538274 1.06720517034 77.626650717 +63.0402717353 0.165039422524 77.626650717 +63.0420474205 20.2770046005 74.9302565154 +63.045953026 23.735097847 73.9043499209 +63.0487544258 -1.54087836837 77.6046407067 +63.0513976603 5.261328824 77.4392644082 +63.064184826 73.3706682155 25.2913747716 +63.0665971177 0.352233988073 77.6046407067 +63.069189142 43.8342283544 64.0377842023 +63.0745652208 -69.8550079747 -33.7916718003 +63.0773696625 3.52657246367 77.5165061333 +63.0793074708 59.818194005 49.4245347472 +63.082012061 49.2850693143 59.9303069992 +63.0865362067 33.9260031684 69.7790459842 +63.0940802011 -77.4989688301 3.6120456584 +63.0969129837 9.68899822838 76.9733907611 +63.1006581524 15.534045433 76.0065811178 +63.1028555921 10.0848489604 76.9176536145 +63.1043908546 0.693896982401 77.5716079622 +63.1071590547 0.363475162514 77.5716079622 +63.1078836068 21.5697479574 74.5126901925 +63.1082963158 32.5726206131 70.4014724456 +63.1087591363 33.6261979436 69.9039579147 +63.1146933758 34.5113454329 69.4658370459 +63.1189659472 6.02207742794 77.3287186058 +63.1242736937 30.1763810161 71.4472679633 +63.1252619883 -65.9876054745 -40.7533706906 +63.1264623431 -66.104251104 -40.5620233474 +63.1274184969 21.2692576923 74.5824893064 +63.1284835218 21.0612554382 74.6405927603 +63.1340417603 72.499530933 27.53017954 +63.1410529217 26.5420546531 72.8610099486 +63.1429660593 14.1951453889 76.232956683 +63.1437260507 6.04668244582 77.3065811677 +63.145832894 6.02464075945 77.3065811677 +63.1495332333 -66.0822117849 -40.5620233474 +63.1495730725 -72.5684984541 -27.3119836863 +63.1498253337 71.3778930744 -30.2868938746 +63.1568486978 -4.41635708184 77.406125421 +63.1587305228 8.4047358717 77.0735698776 +63.1596148693 -1.43329216691 77.5165061333 +63.1607055519 20.1207192972 74.8724377134 +63.1615545556 -1.34510333973 77.5165061333 +63.1615913858 -0.308668221744 77.527531223 +63.1677316651 -1.01437328619 77.5165061333 +63.1738995645 73.3169195198 25.1731548668 +63.175274362 -0.275655885235 77.5165061333 +63.1772823691 27.2345835962 72.5734693176 +63.1848315806 -3.77600466032 77.4171741084 +63.1865169972 29.3704274283 71.7275544155 +63.1886029384 -1.34567936846 77.4944488704 +63.1908742196 18.2152156355 75.3333879147 +63.1945770976 -66.5233959466 -39.7628371371 +63.1977283209 -2.01919210505 77.472382165 +63.2029797817 64.3832170287 -43.1298587031 +63.2041733444 33.3943011952 69.9289147602 +63.2198043591 12.197103188 76.5146195875 +63.2208449699 30.2632240369 71.3250449154 +63.2266492307 42.039505331 65.0774217266 +63.2282583283 -5.08722487476 77.3065811677 +63.2291103402 0.331069873058 77.472382165 +63.2299530049 0.0551785572978 77.472382165 +63.2427415028 25.4234190764 73.1710694857 +63.2451265756 20.7083528275 74.6405927603 +63.2454027602 -3.4252485759 77.3840209727 +63.2467339025 7.3738345332 77.1069206683 +63.2476709859 6.7592261375 77.1624583388 +63.2620539903 13.6546270658 76.232956683 +63.2629067321 8.12661157347 77.017938275 +63.2678496772 9.98668779492 76.7948257639 +63.2722389845 12.2072194885 76.4696512759 +63.2728816369 1.76737161368 77.4171741084 +63.2735314482 -6.89605331193 77.1291427853 +63.2772504943 18.899849661 75.0918454472 +63.2772981807 13.3923009128 76.2668329696 +63.2783303818 6.85187837687 77.1291427853 +63.2805880867 32.7735222086 70.1531425771 +63.2877968905 28.0849451387 72.1518580586 +63.2895663653 9.40223224336 76.8506917219 +63.2953808492 6.56327233697 77.1402503197 +63.3002711536 -2.18837153836 77.3840209727 +63.3076326613 10.1629065972 76.7389013234 +63.3090251873 16.1725751513 75.6995055652 +63.3091186229 0.497238879034 77.406125421 +63.3093870899 9.63116357694 76.8060036355 +63.3111848099 -1.84585375231 77.3840209727 +63.3194475318 -4.96110964625 77.2401123468 +63.3267925023 72.337612329 27.5134002609 +63.3288667461 7.24900432648 77.0513242776 +63.3296933488 26.3875474191 72.7533317557 +63.3332706571 47.6038403656 61.0145163901 +63.3365437582 0.442179673956 77.3840209727 +63.3425047081 -1.69187111833 77.3619070953 +63.3442811792 -68.9588210702 -35.1024648492 +63.3448052603 -1.60342667678 77.3619070953 +63.3455259883 30.1464384416 71.2638518925 +63.3545002548 -1.74751949587 77.3508466216 +63.3572130944 68.1804813921 -36.5689144775 +63.3601553746 34.5163922247 69.2395073545 +63.3674247861 7.7244152345 76.9733907611 +63.369885023 -1.05080878016 77.3508466216 +63.3709856733 18.1115040122 75.2069916777 +63.3716537382 4.24246946247 77.2401123468 +63.3753422492 9.73175310391 76.7389013234 +63.3769809253 30.5694266842 71.0553899503 +63.3856794993 -4.43235849026 77.2179372467 +63.3873581687 9.56380536594 76.750090888 +63.3874677663 -39.4552237687 66.5230354654 +63.3900748969 -3.24447969076 77.2733573497 +63.3908958337 13.9373923661 76.0745911553 +63.3928221844 -1.27254637877 77.3287186058 +63.3966537971 -5.17873637526 77.1624583388 +63.4025882967 -2.98999016341 77.2733573497 +63.4033195644 48.4229155029 60.2929541689 +63.4036885448 67.35298132 37.9940546168 +63.4102301208 13.2124404798 76.1877557918 +63.4197561821 9.79522998551 76.694119692 +63.4205616595 3.43473484279 77.2401123468 +63.4207952712 30.2773466967 71.1413030818 +63.4251201573 17.0303083605 75.4136773416 +63.4398245238 25.7860410582 72.8729630997 +63.4405432257 19.5774777153 74.7798090499 +63.4458831211 33.6921742826 69.5662080833 +63.4554455578 -2.71504580205 77.2401123468 +63.4563430037 4.93840721249 77.1291427853 +63.4596407418 -5.55199915634 77.0846891561 +63.4624125184 29.9579014204 71.239359485 +63.4624901037 -2.18289019013 77.2511963678 +63.4836601498 16.3943508623 75.5052988457 +63.4836766295 -1.44064615701 77.2511963678 +63.484530675 45.1661544749 62.6875813454 +63.4880139632 18.649422465 74.976470474 +63.4899125287 9.60194650287 76.6605089369 +63.4911567261 27.0158108944 72.3810678237 +63.4918108174 26.1953676577 72.6814465487 +63.5066893528 31.8711287601 70.3642775775 +63.5114364791 27.1292367412 72.3208265315 +63.5178061286 9.68555628635 76.6268771648 +63.5182785495 45.3071477741 62.5515039842 +63.5186538196 62.0285595335 46.0199784784 +63.5213883069 9.57268901124 76.6380900901 +63.5227644868 -2.71792615335 77.1846569558 +63.5237093519 -2.69575236041 77.1846569558 +63.5280758429 -70.9774576366 -30.4365583986 +63.5344555215 9.30265183289 76.6605089369 +63.5419270952 10.5534830837 76.4921400918 +63.5483526483 29.8629532029 71.2026045991 +63.5508432734 -4.57767905805 77.0735698776 +63.5554705813 1.79746760874 77.1846569558 +63.5586472924 10.0325895445 76.5483213493 +63.5641764374 7.88354043087 76.7948257639 +63.5674227581 10.1477165883 76.5258558393 +63.5702538171 25.9037197104 72.7173991201 +63.5835232294 26.2721739669 72.5734693176 +63.5885396671 16.4095975827 75.4136773416 +63.5898574336 27.7420838947 72.0187948577 +63.5912382968 11.4418697149 76.3232469783 +63.5999802303 16.365200412 75.4136773416 +63.6021667768 9.66434644378 76.5595506068 +63.605746695 29.1478453398 71.4472679633 +63.6077244714 -77.1074854852 -2.91428717235 +63.6097739174 31.0245596908 70.6489444944 +63.6104130351 11.1818933709 76.3457963096 +63.614746606 28.5228999338 71.691060765 +63.6225157527 32.3753409448 70.0286569056 +63.6248610235 -3.86917133382 77.0513242776 +63.6283266776 16.3606543726 75.3907489863 +63.6344189189 -70.5492746767 -31.2003296688 +63.6362946383 19.2492929913 74.6986393721 +63.637748852 -67.1775056083 -37.9133177301 +63.6399321897 13.4110371756 75.9611947823 +63.6408151534 12.4051061375 76.1312024621 +63.6447156109 -4.58444084768 76.9956692089 +63.6489219698 5.84851432761 76.9064991547 +63.6507443383 32.3198075053 70.0286569056 +63.6516112937 13.3554957585 75.9611947823 +63.6566052532 24.117330325 73.2542898787 +63.664513947 12.2829017568 76.1312024621 +63.664908014 17.5003784735 75.1033703695 +63.6692623029 9.11817229147 76.5707775321 +63.6713303845 15.4272442401 75.5510544084 +63.6724046481 19.7099017069 74.5475999683 +63.6803343068 21.7778202763 73.9631094979 +63.6874661177 8.89402102773 76.582002125 +63.6886868016 32.9144249091 69.7165102855 +63.6920447404 4.48729501055 76.9622480199 +63.6973353677 34.6280275749 68.8734286451 +63.6996608266 7.3139752707 76.7389013234 +63.7008389218 74.0590575709 -21.3882938162 +63.7023198299 39.4971116918 66.1966208828 +63.7085294024 -5.93249216131 76.8506917219 +63.7128750473 -77.0703956803 0.907558751868 +63.7146679145 27.7700648521 71.8975979477 +63.7248020026 21.4457652494 74.0218127487 +63.7255525191 20.9518956071 74.1624704726 +63.7257496542 28.7331196209 71.5082978952 +63.726277793 10.6641215929 76.3232469783 +63.7367045128 14.8671797112 75.6081970773 +63.7407474681 12.4476819933 76.04059656 +63.7561135802 29.7706153808 71.0553899503 +63.7580655723 12.3586710157 76.04059656 +63.7601750514 5.18602726783 76.8618578918 +63.7677569715 11.2095524134 76.2103608804 +63.7924141011 17.3320153101 75.0341865315 +63.8081118049 -67.4044553233 -37.2177950778 +63.8095813226 32.8922810514 69.6163427557 +63.8208436947 -6.16773327755 76.7389013234 +63.8228821895 7.97218521776 76.5707775321 +63.8252657779 -6.78715459387 76.6829184428 +63.8261936371 15.005560703 75.5052988457 +63.8272841345 -5.66274884022 76.7724630032 +63.8276285756 17.9411372563 74.8608671094 +63.8283018472 8.14262745747 76.5483213493 +63.8351033408 32.0359448543 69.9912695896 +63.8386248696 10.2252910143 76.2894055451 +63.8424505249 22.0201164443 73.7513117358 +63.8488654951 23.529772515 73.2780470562 +63.8518792043 -6.78998465555 76.6605089369 +63.8529497973 31.86374077 70.0535711176 +63.85778027 6.7342608009 76.6605089369 +63.8589321251 22.325549873 73.645139763 +63.8663322716 7.50256974007 76.582002125 +63.870238883 8.84000493227 76.4359005823 +63.8706396326 12.611977063 75.9044098026 +63.8746613552 17.8701830598 74.8377190605 +63.876100848 -4.15307286232 76.8283523594 +63.8810331203 19.3841873523 74.4544618419 +63.8824605904 18.4628841649 74.6870345992 +63.885272927 19.0086096813 74.5475999683 +63.8874740829 3.51594043838 76.8506917219 +63.8887939727 18.7671504462 74.6057375062 +63.8889521694 19.4474937246 74.4311546231 +63.8939222196 22.2252129952 73.645139763 +63.8951324089 28.3544597301 71.5082978952 +63.8953410516 18.744847907 74.6057375062 +63.8967412314 26.8334752197 72.091407724 +63.9023858085 34.6528538879 68.6706983029 +63.902533274 -5.87181793275 76.694119692 +63.9078873357 32.3522283286 69.7790459842 +63.9124228369 -76.1678595272 -10.6611154275 +63.9126764516 8.52777174682 76.4359005823 +63.9146862024 -7.07883028298 76.582002125 +63.9155083446 17.8695828878 74.8029798903 +63.9211001042 11.7086544172 76.0065811178 +63.9230168058 7.36222935344 76.5483213493 +63.9243505788 -6.34669602363 76.6380900901 +63.928340079 13.3902635648 75.7223096347 +63.9332120385 26.2861214118 72.2605301639 +63.9375329607 30.4008087312 70.6242359774 +63.9495578377 7.36528617357 76.5258558393 +63.9506378092 21.9825227877 73.6687492475 +63.9512361463 18.785492656 74.5475999683 +63.9513915716 21.1746683285 73.9043499209 +63.9518300013 75.6232106382 13.8308876163 +63.9535487983 6.04539026412 76.6380900901 +63.9599146796 54.2035801632 54.507808722 +63.9771400392 24.7765669706 72.7533317557 +63.9772142818 4.24936188402 76.7389013234 +63.9790559295 69.7719758868 -32.2265695231 +63.9835557526 -7.06385031839 76.5258558393 +63.9839851363 -65.9572112799 -39.4423113706 +63.9849761393 19.0382756647 74.4544618419 +63.9968304003 -7.06531585314 76.5146195875 +63.9969041544 31.3517598423 70.1531425771 +63.996946808 18.6291743837 74.5475999683 +63.9971615283 25.2478685738 72.5734693176 +63.9992927618 -7.04297631513 76.5146195875 +64.0004115764 3.65661957747 76.750090888 +64.0046733602 42.3959062132 64.0779909518 +64.0221331547 18.8670247404 74.4661120495 +64.029934356 31.478876153 70.0660250228 +64.0300163602 -65.9125259617 -39.4423113706 +64.0307579859 21.2629682029 73.8102175512 +64.0413877708 19.9221504395 74.1741772739 +64.0447170908 25.6419951283 72.3931094691 +64.0541513508 -5.82938443194 76.5707775321 +64.0647540067 12.0241152879 75.8361915289 +64.0657556211 29.4263238197 70.9201693677 +64.0682885148 22.0354683099 73.5506121195 +64.0720907595 2.0471283265 76.750090888 +64.0757395625 68.8813461342 -33.9066328947 +64.0827974691 -5.80943776461 76.5483213493 +64.0839300486 13.7384041953 75.5281812285 +64.0918330577 18.5355167139 74.4894056592 +64.0937508263 12.5746939765 75.7223096347 +64.0946576446 11.2670173518 75.9271307335 +64.0970252076 25.4425334933 72.4171861437 +64.0974466146 7.92696179818 76.3457963096 +64.0978459589 20.4315815578 73.9865975598 +64.1023188083 19.41468618 74.2560615973 +64.1057573895 74.2148453734 19.5603833222 +64.1183758171 17.5768927441 74.6986393721 +64.1260889521 16.584134219 74.9186973186 +64.1328458661 41.6483570788 64.4390598453 +64.1371031287 28.5154484378 71.2271100259 +64.1372112111 7.25082095273 76.3796028635 +64.139170708 -76.7095874903 1.34386307119 +64.1396805354 31.4217052697 69.9912695896 +64.1410998846 27.0942613752 71.7761820252 +64.1445239093 9.55212985527 76.1198848376 +64.1452256608 5.86024991748 76.4921400918 +64.1491822557 16.4945811712 74.9186973186 +64.1504068392 8.25199922219 76.2668329696 +64.1514036147 16.5906810359 74.8955720789 +64.1528933648 48.7300012785 59.243508069 +64.1625609859 43.5557372169 63.1352795449 +64.1682671663 30.7167461339 70.2774145499 +64.1750755423 7.50477513555 76.3232469783 +64.1810501862 16.9933209076 74.7798090499 +64.1824315542 19.0117023658 74.2911209563 +64.1893903878 28.9152119852 71.0185375623 +64.1927017685 18.7469385867 74.3495079559 +64.1967885629 9.65155537681 76.0632619404 +64.2049079352 16.0080814682 74.976470474 +64.2167088716 17.953792932 74.5243290547 +64.2207102443 8.22686271937 76.2103608804 +64.2214277298 -65.1699329312 -40.3545296352 +64.2214954291 18.6945393054 74.3378350842 +64.2272859423 32.2047023416 69.5536691165 +64.2311812066 44.1944029385 62.6195665085 +64.2343317732 44.4779600104 62.4152360803 +64.2377996809 8.09234123317 76.2103608804 +64.2406720773 25.5255133443 72.2605301639 +64.2424942262 -71.4738521594 -27.6476109834 +64.2441724148 -65.147511454 -40.3545296352 +64.2474601696 3.02983330952 76.5707775321 +64.2516623462 14.3266292468 75.2759694735 +64.2637463727 19.6841984445 -74.0452782677 +64.2671559551 69.3293637483 -32.6063182175 +64.2674540381 9.62777119846 76.0065811178 +64.2706780855 18.7575374765 74.2794367659 +64.2840966499 23.0803490608 73.0400739673 +64.293220494 48.8012105041 59.0323949356 +64.2937968486 28.1293680512 71.239359485 +64.2978298629 29.1262050026 70.8339837725 +64.3159950102 26.1814211428 71.9582238024 +64.3286160932 29.3569268067 70.7106781187 +64.3287322875 -3.28126598334 76.4921400918 +64.3298737462 -3.25881082025 76.4921400918 +64.3331087616 8.89262570129 76.04059656 +64.3338976554 19.0932151233 74.1390500932 +64.3371992679 9.78752312594 75.9271307335 +64.3375107304 15.4104455242 74.9880182547 +64.3406037023 31.841035419 69.6163427557 +64.3442758869 -68.8319967503 -33.4958263661 +64.3470046073 29.7597516324 70.5253158862 +64.3604399224 1.23578357816 76.5258558393 +64.361710365 5.21233956032 76.3570674869 +64.3641087199 50.0159448815 57.9281172343 +64.3693070804 13.0142066912 75.4136773416 +64.3753047468 6.91382913022 76.2103608804 +64.3802173194 41.6175593754 64.2118865129 +64.3812164981 12.4794607105 75.4938542041 +64.3825396286 19.1565678602 74.0804596287 +64.4040250363 7.01926350542 76.1764497661 +64.4078389777 15.2847274924 74.9533680611 +64.4118310571 34.1331014927 68.4547105929 +64.4119992622 21.7020661292 73.349265005 +64.4161007787 10.8026748561 75.7223096347 +64.4169424098 17.9612972052 74.3495079559 +64.4185028327 3.60155344867 76.4021289334 +64.4197212616 63.5708432455 42.5305466885 +64.4264361255 18.7785936493 74.1390500932 +64.4273336991 27.853500135 71.2271100259 +64.4290983803 27.9744654137 71.1780904964 +64.4292252573 -65.7240821102 -39.1052421488 +64.4388251975 28.0455487198 71.1413030818 +64.449927695 -71.4032708537 -27.345561459 +64.4512163411 9.19572099775 75.9044098026 +64.4512777243 18.785834315 74.1156206801 +64.4611051289 18.7520851313 74.1156206801 +64.4627240964 9.20884307777 75.8930458688 +64.466336771 8.60164580578 75.9611947823 +64.4675994839 16.408621646 74.6638182285 +64.4769876444 -65.6580885602 -39.1373666837 +64.4786291908 -71.4350688829 -27.1944353017 +64.4801231795 7.9742875915 76.0179219143 +64.4815005936 41.1900848727 64.3856582585 +64.4881647013 15.398934674 74.8608671094 +64.4909697693 41.1961336797 64.3723029576 +64.4933260383 41.4835012675 64.1851230356 +64.4935649844 10.0763594597 75.7564984384 +64.4938466956 28.4451756643 70.9324729572 +64.4959229141 27.2176178957 71.4106238843 +64.4965583392 11.1173061993 75.6081970773 +64.5016167305 0.731779023924 76.4133884775 +64.5028434509 -76.1399251966 -6.48806425783 +64.5127882931 25.1784309829 72.1397723859 +64.515773011 6.18943408844 76.1538307537 +64.5161313922 -76.128666167 -6.48806425783 +64.5162189088 8.52808983817 75.9271307335 +64.5210464977 19.2345593523 73.9396124237 +64.5214630909 18.3550748842 74.1624704726 +64.5250974857 41.3925769302 64.2118865129 +64.5353665158 18.5417930651 74.1039025868 +64.5377406599 17.1721650348 74.4311546231 +64.5412116318 13.4833615986 75.1839807479 +64.5432533459 39.7072743892 65.2495272634 +64.5464871731 25.2305355865 72.091407724 +64.5554608443 -65.8758503261 -38.6389029217 +64.5611950533 -75.006338183 -14.3492621991 +64.5770753306 15.4201653755 74.7798090499 +64.5845312719 16.3184131964 74.5824893064 +64.5927631481 -67.663360078 -35.3474843779 +64.5957446486 16.850011428 74.4544618419 +64.5983846352 74.5218356005 16.5391874421 +64.6032262651 30.8556904533 69.8165418993 +64.6046976766 -2.48186214042 76.2894055451 +64.6156758088 -2.17739324496 76.2894055451 +64.6270096151 18.4094879619 74.057007644 +64.631086586 56.4409113238 51.3541252058 +64.6366611578 51.0469590766 56.7125206934 +64.642596601 13.1869364766 75.1494471773 +64.6496888923 -66.7599181408 -36.9260213935 +64.6630896468 -1.43353623141 76.2668329696 +64.6799127959 29.8589219589 70.1780140797 +64.6901507148 16.1650480804 74.5243290547 +64.6914653668 16.2133682178 74.5126901925 +64.6942499285 71.7998259186 -25.6795448608 +64.7027686673 16.1682011077 74.5126901925 +64.7081013474 72.6778421582 -23.0389426677 +64.7129982826 12.8369950622 75.1494471773 +64.7233220132 -1.69483983393 76.2103608804 +64.7239096807 -1.6722470297 76.2103608804 +64.7312130336 56.2303271197 51.4589192581 +64.737305322 62.0158084545 44.3071190824 +64.7388504454 8.66100840529 75.7223096347 +64.7400187163 18.2951730828 73.9865975598 +64.7488713169 18.3587062887 73.9631094979 +64.7494728758 12.2345399115 75.2184937064 +64.7529434005 32.6381703535 68.8607737173 +64.754475325 -66.658284327 -36.9260213935 +64.7566784551 19.3909820009 73.6923497556 +64.7636139326 -73.2792275925 -20.8765206353 +64.7716290111 8.41236582874 75.7223096347 +64.7817986301 17.661545449 74.1039025868 +64.7842144719 21.0246687453 73.2186373775 +64.7912178469 -64.9497263914 -39.7948631308 +64.7913077562 17.7248960629 74.0804596287 +64.7917308838 15.5312002019 74.5708617985 +64.7934315841 7.58855052899 75.790666473 +64.7978369884 8.4157696507 75.6995055652 +64.799088707 7.87597911951 75.7564984384 +64.7994688913 20.4311940614 73.3729864503 +64.7994890358 17.4478500677 74.1390500932 +64.8119659856 8.09573274409 75.7223096347 +64.8120049893 31.5409431254 69.315026625 +64.8225178714 17.7577572649 74.0452782677 +64.822552422 28.4956016495 70.6118784917 +64.8246778281 26.0593534017 71.5448897181 +64.8256466846 16.319165887 74.3728469045 +64.8257985995 47.3932077797 59.5944602483 +64.8262664057 29.2429440288 70.3022432673 +64.8279897471 44.8555572445 61.5248789485 +64.8357589679 18.3833421601 73.8808303288 +64.8389664789 18.3720259055 73.8808303288 +64.8390348512 20.8549922118 73.2186373775 +64.8446301439 31.556820248 69.2772764861 +64.8470100346 65.7588255899 -38.3489523534 +64.8481635925 18.3868593312 73.8690671568 +64.8603396452 10.1220673972 75.436596508 +64.8680093491 9.54417148299 75.5052988457 +64.8777873287 32.3892969108 68.8607737173 +64.8783323921 69.9396980648 29.9873410064 +64.8818947264 11.207049206 75.2644789048 +64.8914859318 15.7828474945 74.4311546231 +64.8947347421 -75.9819720158 -3.92598157591 +64.8960118358 -1.69936187609 76.0632619404 +64.896469273 70.0082469395 29.7874744877 +64.9008869434 18.6713387633 73.7513117358 +64.9049179013 0.0906244203415 76.0745911553 +64.907400516 18.6486829429 73.7513117358 +64.9117130613 15.0218533503 74.5708617985 +64.9173518005 32.9772028992 68.5437198009 +64.9245810763 27.920651591 70.7476924486 +64.9253191935 10.550496677 75.3219088147 +64.9261932598 18.3477849845 73.8102175512 +64.9322121405 69.8753822236 30.0206393279 +64.933321405 24.4327026454 72.0187948577 +64.9395935934 23.7645165552 72.236396206 +64.9401314442 2.40394567281 76.0065811178 +64.940509924 21.1631227767 73.0400739673 +64.9447563639 0.0793450276094 76.04059656 +64.9567146287 16.5934848279 74.1975840976 +64.9641013461 26.5775155657 71.2271100259 +64.9671588721 -65.4223058144 -38.7193771905 +64.9707057257 -2.95030248309 75.9611947823 +64.9716147509 14.4038602136 74.6405927603 +64.9757968941 26.9404323905 71.0799473873 +64.981792071 6.46313701252 75.7337082097 +64.9827268709 10.5249051415 75.2759694735 +64.9829191115 6.45179545188 75.7337082097 +64.9900448382 48.3010741815 58.6796413149 +64.9940078917 26.9612777364 71.0553899503 +65.0027831194 -73.6793218714 -18.6009600639 +65.0113124037 25.2815167236 71.65454746 +65.0131691999 13.463580098 74.7798090499 +65.0162804591 19.4192686407 73.4559410853 +65.0278900777 13.5850340232 74.7450357056 +65.0293135697 30.8086732828 69.4407231184 +65.0307402562 11.1159080008 75.1494471773 +65.0316648267 71.6445122554 -25.2576015004 +65.0438662549 10.5581090711 75.2184937064 +65.0477386989 22.2074187756 72.6334787924 +65.0486018218 4.58286851346 75.8134336198 +65.0558907652 13.7687304978 74.6870345992 +65.0582072594 29.4432822854 70.0037341608 +65.0620573619 11.3200458994 75.0918454472 +65.0747678805 46.2975308671 60.1815023152 +65.0763740077 18.9433899602 73.5269577966 +65.0796792618 18.9320317018 73.5269577966 +65.0801288679 63.6200094727 41.4375580993 +65.0828473328 46.2861724724 60.1815023152 +65.0850367651 -2.04537968082 75.8930458688 +65.0901149266 1.34071300236 75.9044098026 +65.0911560141 15.1112636014 74.396176791 +65.0949355227 30.3266081961 69.5912796592 +65.0998938408 15.749321826 74.2560615973 +65.1074271835 15.9919179473 74.1975840976 +65.1163701149 18.2420867054 73.6687492475 +65.1168815293 0.193206243784 75.8930458688 +65.1213139957 52.1160512477 55.1645870628 +65.121344301 13.3911833824 74.6986393721 +65.1231591905 -75.3129346113 -9.32394858855 +65.124181083 17.7304696481 73.7866619677 +65.1259410164 6.99444654907 75.5624875464 +65.1377732263 -0.87544153432 75.8703110659 +65.1489021841 64.3128629614 40.2427161349 +65.1497771619 12.5812505159 74.8145618928 +65.1520427056 27.4811086254 70.7106781187 +65.1564782584 46.2187756246 60.153621011 +65.1697274122 16.6478999012 73.9983382104 +65.1715046612 10.5905023172 75.1033703695 +65.1772379337 59.6611833952 46.8238278148 +65.1924327919 17.8713260326 73.6923497556 +65.1946528069 5.2797954874 75.6424550435 +65.1959180367 11.2378552038 74.9880182547 +65.1967869341 46.1618982793 60.153621011 +65.1969745532 15.1718112354 74.2911209563 +65.1987925555 9.37205943345 75.2414908896 +65.2031421546 19.1037983797 73.3729864503 +65.2037684866 5.16600136896 75.6424550435 +65.2055159286 -10.2109113009 75.1264133504 +65.2081385513 17.1678701558 73.8455340626 +65.2128491143 2.87006180294 75.7564984384 +65.212896504 46.1391374955 60.153621011 +65.2160703782 -68.77146032 -31.8959309298 +65.2198275287 -19.939702315 73.1353701619 +65.2200705044 18.6769187464 73.4677827999 +65.2225802908 6.70558471913 75.5052988457 +65.2247856044 9.37579582779 75.2184937064 +65.2265890628 17.8439755534 73.6687492475 +65.2302724283 15.9255511783 74.1039025868 +65.2382392513 -73.4795972955 -18.5666615386 +65.2392988175 24.6518767535 71.6667207449 +65.2397795437 13.3324827489 74.6057375062 +65.2410501038 9.26194287916 75.2184937064 +65.2421473802 7.1451772106 75.4480526445 +65.247368447 17.4219668231 73.7513117358 +65.2531339608 23.453986076 72.055111168 +65.254348622 26.2585427117 71.0799473873 +65.2556545033 24.3591530009 71.7518725918 +65.2556627303 9.25239884638 75.2069916777 +65.265290536 13.3376962071 74.5824893064 +65.2674892257 -2.50732402341 75.7223096347 +65.2679006321 19.1104032649 73.3136660803 +65.2682060268 24.9626697703 71.5326946227 +65.2731253301 17.8199769628 73.6333316555 +65.2885803753 15.5178131147 74.1390500932 +65.2981476241 38.3408410612 65.3156323064 +65.2981762647 -2.39437542755 75.6995055652 +65.29862016 11.7843766909 74.8145618928 +65.3001258874 -67.5730402949 -34.2020143326 +65.3011168526 -69.7090992418 -29.6041487076 +65.3029487468 -70.8425176427 -26.7742895148 +65.315979875 16.6488345042 73.8690671568 +65.3213934299 19.0641910398 73.2780470562 +65.3324395474 26.4623623844 70.9324729572 +65.3505576199 63.373344931 41.3898993841 +65.3575159052 13.5348908725 74.4661120495 +65.366464412 -0.513397567327 75.6766922719 +65.3678931216 30.9690807394 69.0503771677 +65.3679805464 13.0262219484 74.5475999683 +65.3741095538 8.37461657858 75.2069916777 +65.3808016115 15.8535220743 73.9865975598 +65.3879885467 11.5061336809 74.7798090499 +65.3927261496 13.3637391081 74.4661120495 +65.3945698351 49.3320479273 57.3576436351 +65.4075276977 -73.5409088055 -17.708474032 +65.4113168977 10.4186570053 74.9186973186 +65.4115005405 62.3340835878 42.8462089374 +65.4141127532 29.631868792 69.5912796592 +65.4177242672 15.6450405498 73.9983382104 +65.4188468738 17.1257075186 73.6687492475 +65.4197106552 11.4764046524 74.7566290977 +65.4223237761 30.9948681291 68.9872285383 +65.4253663693 28.9515574748 69.8665066769 +65.426146591 17.2496901874 73.6333316555 +65.430095771 34.0317285801 67.5332808121 +65.432585145 2.33069361315 75.5853469168 +65.4434306527 20.29568148 72.8370969882 +65.4444864654 69.7644652868 -29.153706017 +65.4446709467 13.4338616553 74.4078383351 +65.4477210819 19.7598319881 72.9804415237 +65.450347026 13.4707443393 74.396176791 +65.4504434136 15.1104254793 74.0804596287 +65.4520737708 37.1819528707 65.829540632 +65.4593546493 2.32020789964 75.5624875464 +65.459367676 22.5650296291 72.1518580586 +65.462419282 15.1733740666 74.057007644 +65.4643878568 16.055367947 73.8690671568 +65.4665135449 67.0157933082 34.9716892865 +65.468016107 17.5421020459 73.5269577966 +65.4711553521 14.5505753357 74.1741772739 +65.4772241784 34.4492341333 67.2754292556 +65.477532294 16.4832711438 73.7630973935 +65.4825313492 18.1229949917 73.3729864503 +65.4828781561 12.574460121 74.5243290547 +65.4829985912 28.881443632 69.8415285431 +65.4925945819 -65.5383330059 -37.6224263139 +65.4964365637 15.8694583201 73.8808303288 +65.5026256553 27.0249869943 70.5624270432 +65.5096758052 16.2484119706 73.7866619677 +65.5156306077 2.89484429319 75.4938542041 +65.5175524626 25.3205401323 71.1780904964 +65.5180105255 65.9079603753 -36.9260213935 +65.5186786948 13.0681420405 74.4078383351 +65.5207923599 17.8384495734 73.4085518544 +65.5236036167 16.4583916391 73.727733681 +65.5292299095 -72.344758086 -21.7291510406 +65.5322033277 30.391236629 69.1513055782 +65.5384717088 48.9398980523 57.5290805133 +65.5393568777 7.55997943185 75.1494471773 +65.545727019 33.3684014107 67.7518077755 +65.5496208849 20.2533928093 72.7533317557 +65.5498157706 19.1929478531 73.0400739673 +65.556686659 20.2305104417 72.7533317557 +65.5646884889 1.39628104588 75.4938542041 +65.573813201 37.9812350271 65.2495272634 +65.5741983587 37.7068364441 65.4080957909 +65.5803870007 -73.399218915 -17.6569392453 +65.5863798927 2.78328580321 75.436596508 +65.5907343625 28.6967949953 69.8165418993 +65.5940384008 6.29287937397 75.2184937064 +65.6035479603 34.6620250553 67.0426618959 +65.607809457 18.2933452063 73.2186373775 +65.6105262684 8.78928091964 74.9533680611 +65.6124144976 9.7122020997 74.8377190605 +65.6164070952 21.2188187923 72.4171861437 +65.6166596109 12.6357769998 74.396176791 +65.6251701755 74.1757614534 13.8308876163 +65.6310941239 11.4780684234 74.5708617985 +65.6317870275 52.6374216044 54.0534030235 +65.6368285599 18.1410342642 73.2305237754 +65.6377030043 7.15371955429 75.1033703695 +65.6418489956 26.5210285065 70.6242359774 +65.6419615034 6.20499225527 75.1839807479 +65.6422687239 5.91616088063 75.2069916777 +65.6478726401 28.0418264353 70.0286569056 +65.6489737413 15.6761207695 73.7866619677 +65.6737167995 21.1234614383 72.3931094691 +65.6743025253 26.1084277776 70.7476924486 +65.6862705627 18.6740478724 73.0519937827 +65.6866927941 27.3830929002 70.2525772694 +65.6988716196 25.6413425693 70.8955557081 +65.6990530106 17.3216423263 73.3729864503 +65.7050954016 17.2987079756 73.3729864503 +65.7080881892 49.0308398641 57.2575225515 +65.7088504992 -3.98439278791 75.2759694735 +65.7110471086 -0.149093892354 75.3792813636 +65.7130792703 -3.44387655441 75.2989437316 +65.7199237603 4.8031058159 75.2184937064 +65.7332330218 44.4211357578 60.8761429009 +65.7382970783 36.4843426465 65.93458151 +65.741656614 18.1453083997 73.1353701619 +65.7438962123 15.9415651715 73.645139763 +65.75002091 18.7293861443 72.9804415237 +65.7648070354 50.828819062 55.6005513314 +65.7723586953 -4.6223230694 75.1839807479 +65.7751157427 2.67629760251 75.2759694735 +65.7776265408 11.0073996445 74.5126901925 +65.7882420139 2.67683169216 75.2644789048 +65.7934387929 14.7668720731 73.8455340626 +65.7946105301 31.5234954669 68.3910700219 +65.798152688 37.7287228178 65.170135625 +65.7985611819 6.88087673385 74.9880182547 +65.8032290682 -1.86103842389 75.2759694735 +65.8056695164 14.8299481119 73.8219919705 +65.8062533706 2.87316307144 75.2414908896 +65.812399778 9.05028578719 74.7450357056 +65.8136987981 -3.99075048254 75.1839807479 +65.8164717986 21.7030175864 72.091407724 +65.8256691452 14.0156953091 73.9631094979 +65.8333630038 36.5972439276 65.7769720534 +65.8379234245 24.511067952 71.1658301926 +65.8379302373 -4.98504776363 75.1033703695 +65.838073567 13.5146156158 74.0452782677 +65.8423484321 31.6170453727 68.3018857343 +65.8476561417 -64.3029254166 -39.1052421488 +65.8503554202 5.64536689138 75.0457228874 +65.8561334015 15.7498887199 73.5860767993 +65.8583325852 10.4309351472 74.5243290547 +65.8597533825 2.53007651728 75.2069916777 +65.8605058675 49.126679851 56.9996762596 +65.8637851821 -73.6129050133 -15.5917291214 +65.8681837575 2.30016766184 75.2069916777 +65.8713308 26.2799962287 70.5005643726 +65.8748513479 11.8883685572 74.2911209563 +65.8843451567 74.6522869537 9.28919349936 +65.8872947231 45.5035347889 59.9023598516 +65.8911253624 17.8404917296 73.0758267372 +65.8938170359 15.4795238873 73.609708712 +65.8940589363 22.8822819054 71.65454746 +65.8958982622 -39.782326195 63.8364873308 +65.8961872265 1.26527143283 75.2069916777 +65.8987236509 20.1095380555 72.4773392198 +65.904544162 32.6006837601 67.7774776543 +65.9087058694 16.9224794356 73.2780470562 +65.9118503769 -65.9118503769 -36.211268409 +65.9148305721 10.734911836 74.4311546231 +65.9156584922 36.9901423904 65.4740813717 +65.917028706 2.73969259628 75.1494471773 +65.9200714236 17.1340399233 73.2186373775 +65.9263477941 19.128422092 72.7173991201 +65.9287286708 12.6600753181 74.1156206801 +65.9324686537 12.3627485061 74.1624704726 +65.9334410105 12.8400489767 74.0804596287 +65.9355854151 37.001324858 65.44769312 +65.939174663 -64.730414468 -38.2360914263 +65.9395510302 -2.12983541158 75.1494471773 +65.9400328361 14.2206037523 73.8219919705 +65.9431013219 66.5210890557 35.0207381259 +65.9432060521 25.3528486317 70.7723578937 +65.9445152228 40.173756915 63.5404608684 +65.9452029294 14.5593347322 73.7513117358 +65.956104306 18.8876950213 72.7533317557 +65.9647022796 16.9614030596 73.2186373775 +65.9673748078 16.6923120206 73.2780470562 +65.9731975048 16.6692840463 73.2780470562 +65.9735647811 18.358104454 72.8729630997 +65.9738073797 -68.7247824185 -30.4033060925 +65.9792343674 21.7311561767 71.9339800339 +65.9792428527 15.1112638757 73.609708712 +65.9837473044 29.3088878262 69.189118986 +65.9842611259 -4.40580478975 75.011106963 +65.9842990046 26.592429168 70.2774145499 +65.9851335409 15.9269166177 73.4322509436 +65.9868548783 17.5824113149 73.0519937827 +65.9872468153 36.6978665799 65.5663774065 +66.0002034771 15.419455832 73.5269577966 +66.0037102653 47.8314066791 57.9281172343 +66.0046146555 15.4569371439 73.5151272753 +66.0059993265 10.1592949746 74.4311546231 +66.0257522536 59.8055313728 45.4301492025 +66.0259620477 17.9759852117 72.9207535023 +66.0302108808 47.5699527851 58.1129145979 +66.0303269354 28.4781466038 69.4909425092 +66.0308309988 -5.83501743421 74.8724377134 +66.0326968323 3.09092229167 75.0341865315 +66.0378473345 14.1331785762 73.7513117358 +66.0409816438 30.2359220963 68.7341091345 +66.0519258204 26.1918219375 70.3642775775 +66.0591621843 16.1645741475 73.3136660803 +66.0621875333 -4.79334647207 74.9186973186 +66.0627926766 30.2459079668 68.7087510804 +66.0678053559 26.0514447381 70.4014724456 +66.0765122558 2.68856100572 75.011106963 +66.0837554492 29.3809328635 69.0630005849 +66.0910987977 14.4947966188 73.6333316555 +66.093163571 15.0159983467 73.5269577966 +66.0982848712 -39.9202526259 63.5404608684 +66.1026703979 2.68962534399 74.9880182547 +66.1031324897 -5.12117668864 74.8608671094 +66.1037229217 16.0899069482 73.2899222969 +66.1088020348 67.1554787702 -33.4629341909 +66.1114597431 14.935239128 73.5269577966 +66.1128426134 4.99425842475 74.8608671094 +66.1141948922 -2.38963427783 74.9880182547 +66.1229893693 27.7955453141 69.6789633789 +66.1241500816 7.03161708019 74.6870345992 +66.1252218542 23.8717498973 71.1167673026 +66.1276662638 -73.9597698762 -12.5333233564 +66.1300749243 -5.11165299433 74.8377190605 +66.1330426952 10.3561581164 74.2911209563 +66.1359369386 15.0014407179 73.491459515 +66.1408713786 -3.29268762838 74.9302565154 +66.1494200933 16.0643467245 73.2542898787 +66.1530964718 36.398049137 65.5663774065 +66.1567807819 -3.23560638125 74.9186973186 +66.1646811151 39.0050915573 64.0377842023 +66.1690943818 39.0855442181 63.9841478951 +66.1762152617 27.4787682645 69.7540380788 +66.1777671624 15.2783413975 73.3966989553 +66.1798959062 58.4481470638 46.9471562786 +66.1849808246 12.0636518008 73.9865975598 +66.1913942759 -74.9474500582 -1.25660398834 +66.2058808187 54.1310218109 51.832555626 +66.2066717122 70.62635334 25.0717936073 +66.2102067033 23.9285572239 71.0185375623 +66.2113385143 17.5308836461 72.8610099486 +66.2130944952 9.91924347531 74.2794367659 +66.2154334625 38.1832852069 64.4790904261 +66.2339593052 7.46444731558 74.5475999683 +66.2469751044 18.5588211028 72.5734693176 +66.2624051474 28.0585038246 69.4407231184 +66.2675830588 15.4575306944 73.2780470562 +66.2689178793 -74.8507215105 -2.40832150206 +66.2776827524 33.1459974592 67.1461958818 +66.2784911975 1.73556337222 74.8608671094 +66.2784981337 52.1560350663 53.7299608347 +66.2799805251 -74.8368957635 -2.53045728655 +66.2841201772 19.4833383097 72.296714591 +66.2860202891 9.13899326516 74.3144825477 +66.2902927077 59.0210007824 46.0664580728 +66.2924929801 28.4815026953 69.2395073545 +66.2926787293 30.5192659134 68.3655992076 +66.2943875339 13.7892524378 73.5860767993 +66.295187033 15.4517698217 73.2542898787 +66.2981988793 18.6106147753 72.5134045749 +66.301404807 16.7768346045 72.9565729819 +66.3065892704 48.4047962513 57.1000168056 +66.3175618091 12.4109943494 73.8102175512 +66.3203580487 4.66083514504 74.6986393721 +66.3272255455 12.9768223808 73.7041466427 +66.3274493044 63.4503644169 -39.6827509647 +66.3502749604 -5.14032344027 74.6405927603 +66.3533564875 0.115808571637 74.8145618928 +66.3571820325 13.2233453412 73.6333316555 +66.3583632315 34.1475003465 66.5621202286 +66.3621064511 -65.9464455088 -35.3148290685 +66.3692521655 13.7444113796 73.5269577966 +66.3718324195 61.3105393956 42.8462089374 +66.3733868171 12.6013812212 73.727733681 +66.3771186375 14.3269897755 73.4085518544 +66.3777814852 12.5782117713 73.727733681 +66.3782496643 -64.2800846604 -38.2360914263 +66.3789749247 22.6231052896 71.2883356168 +66.3810199859 60.0219568274 44.619781311 +66.3828531969 22.3789997043 71.3617346599 +66.3863283628 53.2425721295 52.5174629961 +66.3874695129 14.8758590134 73.2899222969 +66.3905021811 55.9059939952 49.667102347 +66.3907465827 -69.7658997757 -26.9256011385 +66.3955497771 37.6413203687 64.6123979643 +66.4030167311 15.2693204611 73.1948578909 +66.4125582793 11.1374837157 73.927860508 +66.415851061 9.33413914558 74.1741772739 +66.4222817605 12.5506204316 73.6923497556 +66.4232611338 12.8873135161 73.6333316555 +66.4258423366 22.2902519585 71.3495069184 +66.4269289192 14.15583614 73.3966989553 +66.4282061857 15.5561336575 73.111559473 +66.4283051536 37.6292557535 64.5857521893 +66.4294363319 49.5510565607 55.9626909856 +66.4309202315 15.5445395115 73.111559473 +66.433538138 14.7279608257 73.2780470562 +66.4416624466 22.3213677704 71.3250449154 +66.4457667448 11.0953659003 73.9043499209 +66.4458695882 10.0252697458 74.057007644 +66.4472548652 18.2153128026 72.4773392198 +66.4503424451 42.4151064987 61.5248789485 +66.4506291783 8.8900166421 74.1975840976 +66.4585862744 8.63146332333 74.2209818805 +66.4596879822 69.6677078651 -27.0096344686 +66.4607258515 71.9723739514 -20.0735972635 +66.4647411365 10.7411312388 73.9396124237 +66.468678039 48.0799477162 57.1859551582 +66.4690411034 17.4998380938 72.6334787924 +66.4750349569 28.0528135626 69.2395073545 +66.4751854955 17.5262706837 72.6214813211 +66.4765196783 24.8148873249 70.4634209964 +66.4769265826 17.9617479407 72.5134045749 +66.4794155376 15.6170904512 73.0519937827 +66.4823644887 6.60066710919 74.4078383351 +66.490960067 16.7013747846 72.801210908 +66.4912574231 13.1415053733 73.5269577966 +66.5029858846 20.5861129675 71.7883334625 +66.5037462902 -3.83458188433 74.5824893064 +66.5075070259 -64.0016040753 -38.4778661699 +66.5095074074 16.9901527253 72.7173991201 +66.5145754626 10.5110747187 73.927860508 +66.5177955167 23.6205339169 70.8339837725 +66.5204269676 13.3887085008 73.4559410853 +66.5240203825 5.87859963072 74.4311546231 +66.5274281602 13.353876653 73.4559410853 +66.5318316337 16.2187122958 72.8729630997 +66.5327036571 10.5615532401 73.9043499209 +66.5327164368 24.7697352649 70.4262583022 +66.5337332852 13.9602277873 73.3374009306 +66.5353676008 24.5857799968 70.4881853942 +66.5477162883 10.873755369 73.8455340626 +66.550862586 16.4080533034 72.8131751529 +66.5518596967 19.7767486182 71.9703423989 +66.5546071939 35.2686008902 65.7769720534 +66.5621108565 13.5059239146 73.3966989553 +66.5638746031 72.3116421222 18.4465989119 +66.5662552247 27.8043238588 69.2520991747 +66.5665470068 10.0910125473 73.9396124237 +66.5813002641 16.8105699058 72.6934329537 +66.5832022556 11.4410866465 73.727733681 +66.5844264166 26.8342873969 69.6163427557 +66.5920253382 16.0242126369 72.8610099486 +66.5936164104 15.9631294693 72.8729630997 +66.5960837546 14.7030357352 73.1353701619 +66.6010344899 12.0794448635 73.609708712 +66.6124084589 9.87210615911 73.927860508 +66.6263498067 60.519115173 43.5702445497 +66.6264981916 11.5682809022 73.6687492475 +66.6319770744 65.8918168851 34.906275922 +66.6356533276 -63.4562750796 -39.1534271632 +66.6428858201 17.2350221453 72.5374371012 +66.6463903962 -5.51446406066 74.3495079559 +66.64810856 11.2128672983 73.7041466427 +66.650980752 11.2731695762 73.6923497556 +66.6576478707 18.9627770305 72.091407724 +66.6688507283 57.8522816929 46.9933808689 +66.6699050718 -63.6666353774 -38.7515586452 +66.6729464186 15.2334065331 72.9565729819 +66.6759218692 11.4330587413 73.645139763 +66.6778489057 16.4764010905 72.6814465487 +66.6810843919 11.0150693136 73.7041466427 +66.6827714388 33.2758713528 66.679264985 +66.711042436 15.1808674595 72.9326955506 +66.7145259814 -65.0358167372 -36.3251230473 +66.7163030481 18.1889518876 72.236396206 +66.7231675896 15.7480982068 72.801210908 +66.7403065525 15.2242859811 72.8968627421 +66.7406652846 11.0488454899 73.645139763 +66.7442006432 9.59420551744 73.8455340626 +66.745222372 11.4089697957 73.5860767993 +66.7477670789 -69.2401549314 -27.3959218692 +66.7500051533 28.6366732272 68.7341091345 +66.7560468286 7.46429588225 74.0804596287 +66.7582929089 25.5592881034 69.9289147602 +66.7624379435 16.2378987211 72.6574670971 +66.7653546475 15.5122191497 72.8131751529 +66.7693721594 -66.7693721594 -32.9196276237 +66.7710229874 10.456063164 73.7041466427 +66.7740607884 9.65798068301 73.8102175512 +66.7747196965 -4.8684785303 74.2794367659 +66.7775042811 37.1220989107 64.5191033296 +66.7917602097 -2.01733660171 74.396176791 +66.8008420973 44.9390913935 59.3137889518 +66.8023040487 22.6113324383 70.8955557081 +66.8028371566 1.60929385514 74.396176791 +66.8071416905 20.2338965987 71.605832497 +66.8096085296 33.4120177805 66.4839324646 +66.8114631287 11.9972045063 73.4322509436 +66.8168482591 -69.7977902762 -25.7638751216 +66.817226821 6.23373493481 74.1390500932 +66.8250430862 9.66535459499 73.7630973935 +66.8259538825 13.6201879199 73.1353701619 +66.8264827813 20.7246013149 71.4472679633 +66.8295793406 9.45176390003 73.7866619677 +66.8300909394 48.6440651945 56.2804927695 +66.8355734689 29.1025551582 68.4547105929 +66.8371525859 10.0246596891 73.7041466427 +66.8452884349 15.6168908321 72.7173991201 +66.8488361828 15.4332698884 72.7533317557 +66.8502873728 8.82474799519 73.8455340626 +66.8557166383 13.6019492797 73.111559473 +66.8597257578 9.8729853268 73.7041466427 +66.8619551477 7.67706892242 73.9631094979 +66.8636928404 9.01656058601 73.8102175512 +66.8687127063 -0.852013921554 74.3495079559 +66.8701841404 9.16007580201 73.7866619677 +66.8713333795 16.3262056473 72.5374371012 +66.8750765618 -63.8402523298 -38.107037635 +66.8784144658 38.6434034979 63.5135028529 +66.8792936196 12.4798787918 73.2899222969 +66.8813620256 19.1400292763 71.83691734 +66.8819574111 48.2367890045 56.5686835572 +66.8930994962 5.35859039933 74.1390500932 +66.8975000883 16.9028252857 72.3810678237 +66.9002525917 11.3393528228 73.4559410853 +66.9015287492 10.5363222815 73.5742574804 +66.9024849331 10.022519597 73.645139763 +66.904863271 8.90324583269 73.7866619677 +66.9062920644 8.07285526395 73.8808303288 +66.9066967239 2.07924999836 74.2911209563 +66.9110261582 16.1627595802 72.5374371012 +66.9115518815 9.60634229593 73.6923497556 +66.9147832365 14.7366579228 72.8370969882 +66.9176850984 10.180088625 73.609708712 +66.9197627613 32.9286055446 66.614204858 +66.9210356669 -70.2003721187 -24.3615011786 +66.9217136715 38.5905633481 63.5000209429 +66.9245684934 -63.2210732845 -39.0409787882 +66.9253556221 18.2835981715 72.0187948577 +66.9331105479 12.1879449496 73.2899222969 +66.9334206479 34.9176062033 65.5795545685 +66.9521727438 12.0827916723 73.2899222969 +66.9572376142 10.0904723561 73.5860767993 +66.9582650972 31.6939305542 67.1720589323 +66.9626914738 12.0243602862 73.2899222969 +66.9738745125 11.5924741111 73.349265005 +66.9767753513 -5.1183068242 74.0804596287 +66.978241246 11.0281331582 73.4322509436 +66.9789312481 -63.272427694 -38.8641565272 +66.9814766397 16.514220798 72.3931094691 +66.9816840578 19.2446497479 71.7153920498 +66.9822165794 72.7661077832 14.780941113 +66.9877485215 10.7296988997 73.4677827999 +66.9906608909 14.5083726707 72.8131751529 +66.9913252724 17.3001885628 72.2001787667 +66.9972557873 13.5455261849 72.9923724601 +66.998452676 19.1861898812 71.7153920498 +67.0033947333 0.23388691957 74.2326773808 +67.010261512 9.27460195293 73.645139763 +67.0111042483 9.99096413133 73.5506121195 +67.0161035963 13.4519671952 72.9923724601 +67.0350083409 54.0904329026 50.7989441341 +67.0410828596 9.51748445213 73.5860767993 +67.0431653881 4.15926387052 74.0804596287 +67.0451923796 -73.0901193481 -12.7583945876 +67.0466965951 -73.0917591866 -12.741083733 +67.0480194409 58.9446045721 45.0565941999 +67.050021149 21.7858725042 70.9201693677 +67.0505295578 18.632570693 71.8126297763 +67.0537805336 18.6208678842 71.8126297763 +67.0616163189 12.8897564395 73.0519937827 +67.062686466 26.2545785859 69.3779012888 +67.0763981501 19.322566176 71.605832497 +67.0770334875 49.6706377968 55.0772123421 +67.0825993511 10.54084337 73.4085518544 +67.0929302406 10.0510498052 73.4677827999 +67.0959884411 -3.92748028356 74.0452782677 +67.096756462 11.2522247574 73.2899222969 +67.1023454006 11.6750324335 73.2186373775 +67.1026911696 13.0799079814 72.9804415237 +67.1059131454 12.86183964 73.0162276621 +67.1098206349 65.5354805906 -34.6608245445 +67.121649518 12.2222762778 73.111559473 +67.1220022671 -62.9216171954 -39.1855445435 +67.1220690928 16.5240316246 72.2605301639 +67.1227659729 16.2015084221 72.3328791975 +67.1297625179 9.15982757147 73.5506121195 +67.1359791298 -63.1552228751 -38.7837353782 +67.1406181766 10.2499743084 73.3966989553 +67.1467372148 39.7104696907 62.5651203016 +67.15196899 8.18574676254 73.645139763 +67.1619837684 17.3942842202 72.0187948577 +67.1638722378 12.0604859247 73.0996507877 +67.1677400618 29.4426403409 67.9825391166 +67.1696362336 8.6642140121 73.5742574804 +67.1706500452 67.5704360688 -30.3700500819 +67.1707533128 17.2090340798 72.055111168 +67.1726565226 8.64076685853 73.5742574804 +67.1730213124 48.8040567181 55.7310439129 +67.1746241974 -63.015014392 -38.9445480794 +67.1763868761 39.6173082877 62.5923472184 +67.1774361411 10.7600819338 73.2899222969 +67.1845347298 -63.0243112411 -38.912395014 +67.1980653396 52.8796631024 51.8474806022 +67.2063704462 9.72050853101 73.4085518544 +67.2243235443 22.4016564965 70.5624270432 +67.2284005526 10.011367657 73.349265005 +67.2393332382 11.252005457 73.1591719395 +67.2401199638 -4.11258191622 73.9043499209 +67.244592783 -73.384595755 -9.63669275888 +67.2461931372 10.7349846823 73.2305237754 +67.2495577921 19.7543652031 71.3250449154 +67.2545501973 9.65558579927 73.3729864503 +67.2552489058 9.18890722453 73.4322509436 +67.2607081542 17.8589849432 71.8126297763 +67.2643056546 24.3758985389 69.8665066769 +67.270891342 12.467922753 72.9326955506 +67.2838353634 -63.3607503697 -38.1877049766 +67.2839588085 18.2554291498 71.691060765 +67.2876173346 23.4715389354 70.1531425771 +67.3023884706 -64.473057863 -36.2438038284 +67.3082614695 9.45955924928 73.349265005 +67.3086073108 -73.3258858422 -9.63669275888 +67.3092741655 10.7450547523 73.1710694857 +67.3118030271 1.43348800852 73.9396124237 +67.3161868455 -70.763114553 -21.4735327167 +67.3187211234 10.927370113 73.1353701619 +67.3267916123 29.1070061663 67.9697382902 +67.3286261496 9.85819052536 73.2780470562 +67.332922839 12.2000496152 72.9207535023 +67.3384107106 35.7592543119 64.7055961569 +67.3399549092 48.6564961341 55.6585649903 +67.3482564719 -62.86922542 -38.8802372073 +67.3501413137 31.0488404232 67.0815024682 +67.354269886 -3.19991048838 73.8455340626 +67.35583394 12.2163430124 72.8968627421 +67.3590854992 9.8266278585 73.2542898787 +67.3595548389 31.1958452847 67.0038029434 +67.3644066475 12.5217418657 72.8370969882 +67.3700793882 72.9315981123 11.9270448985 +67.3927041674 -73.8561863731 -1.86739375094 +67.3950620919 16.6785916858 71.9703423989 +67.4005694774 8.77773076369 73.349265005 +67.4037857433 16.6433014292 71.9703423989 +67.4060929288 10.3747899909 73.1353701619 +67.4078265305 48.562424421 55.6585649903 +67.414122486 11.6686764104 72.9326955506 +67.4144904879 10.8946168652 73.0519937827 +67.4205440299 11.7061501518 72.9207535023 +67.4220888284 11.3188821456 72.9804415237 +67.4235511863 28.2730414706 68.2253609109 +67.429459056 10.2218238437 73.1353701619 +67.4330130042 28.526437152 68.1104334195 +67.4354235776 13.6218647079 72.5734693176 +67.4475947943 9.83953996825 73.1710694857 +67.4627777996 5.81918489594 73.5860767993 +67.463171886 6.51973283589 73.5269577966 +67.4642716709 51.0783789085 53.2876276071 +67.4798332271 30.5108585397 67.1979137981 +67.4810965428 26.3776431887 68.9240273721 +67.49206765 27.131637235 68.6199319824 +67.4934619556 9.96656734663 73.111559473 +67.49373026 -0.353399574803 73.7866619677 +67.4969368319 9.94300707722 73.111559473 +67.4994752088 8.61096197603 73.2780470562 +67.5018529444 22.8481166759 70.1531425771 +67.5051470857 11.5146153217 72.8729630997 +67.5106930514 7.07183463339 73.4322509436 +67.5116067596 29.1869062404 67.7518077755 +67.5151181541 10.9108789457 72.9565729819 +67.5156496272 32.0154765843 66.4578536706 +67.5164286294 8.37371810161 73.2899222969 +67.5170618285 22.87953577 70.1282625266 +67.5183549584 63.7820005861 -37.055743751 +67.5193230418 9.78983592341 73.111559473 +67.5253796173 18.7899195143 71.3250449154 +67.5312049292 -63.7495452648 -37.0881630624 +67.5312182378 13.5308439001 72.5013849983 +67.5341035331 -65.7888109783 -33.3313247568 +67.5455199668 12.2385700803 72.7173991201 +67.5476656403 9.40906466287 73.1353701619 +67.5596441248 -67.4418330813 -29.7874744877 +67.5687172736 11.3677503634 72.8370969882 +67.5691728517 17.9156415535 71.5082978952 +67.5707494948 18.2952619324 71.4106238843 +67.5734637706 12.4386281026 72.6574670971 +67.5810467643 -0.707732937512 73.7041466427 +67.5879078498 6.00828026702 73.4559410853 +67.5915604061 10.2584656201 72.9804415237 +67.5959752944 9.52405746924 73.0758267372 +67.5975846471 9.04346068516 73.1353701619 +67.5993247094 15.8303857762 71.9703423989 +67.6128546777 -66.2807863489 -32.1769986684 +67.6178460192 0.861559073328 73.6687492475 +67.6179167396 8.38630515402 73.1948578909 +67.6186209289 8.06303238535 73.2305237754 +67.6214313386 8.03942854318 73.2305237754 +67.6227278519 17.1111807356 71.65454746 +67.6261879244 31.1474813585 66.7572701047 +67.6295301127 25.5550698958 69.0882411077 +67.6310064912 8.28008087627 73.1948578909 +67.6314324507 16.3992545342 71.8126297763 +67.6331537444 14.1046649707 72.296714591 +67.6370114685 8.94061245288 73.111559473 +67.6400098091 16.3638405526 71.8126297763 +67.643507723 29.0899191065 67.6618982095 +67.6457912846 -65.3019686017 -34.0543656265 +67.6527585628 48.2206221658 55.6585649903 +67.6573148085 9.26789929135 73.0519937827 +67.665345541 10.7776767044 72.8370969882 +67.6753782703 8.64540614456 73.111559473 +67.680185071 57.7430791391 45.6632167098 +67.6916807842 10.0199830974 72.9207535023 +67.691855514 9.7545453922 72.9565729819 +67.6978194246 17.6718178391 71.4472679633 +67.6987121198 8.2523941129 73.1353701619 +67.7016999456 15.667511458 71.9097275004 +67.7055730878 -65.2228432268 -34.0871837244 +67.7093230767 -73.5817685629 -1.08208301821 +67.7121987503 -3.75013583109 73.491459515 +67.7139263781 15.6703408962 71.8975979477 +67.7170015012 -65.2794415028 -33.9558864524 +67.7172933863 8.81897844485 73.0519937827 +67.7175536334 8.91518506634 73.0400739673 +67.7347566934 9.7245279751 72.9207535023 +67.7416956588 -2.56685234353 73.5151272753 +67.7465562774 11.4584723061 72.6574670971 +67.7493749563 -1.95158146322 73.5269577966 +67.7508171748 15.1689349373 71.9703423989 +67.7512431885 17.8121271256 71.3617346599 +67.7528529809 10.0411225579 72.8610099486 +67.7552103441 68.5402243746 26.6733783743 +67.7561080043 15.145284517 71.9703423989 +67.7597060329 -65.2521938038 -33.9230517808 +67.7611701507 1.98743087922 73.5151272753 +67.7630738658 15.1716791248 71.9582238024 +67.7638973895 68.5250865855 26.690198932 +67.7653342421 10.5511898463 72.7772757657 +67.7682851855 68.5534507016 26.6060880235 +67.7704740785 7.86528541132 73.111559473 +67.7715748432 16.2454974196 71.7153920498 +67.7762835982 24.7087462554 69.2520991747 +67.7771516922 11.8046287403 72.5734693176 +67.7855129674 11.3798941235 72.6334787924 +67.7919136696 54.3504273957 49.5003786139 +67.7999183839 21.0135178702 70.4386480127 +67.8207532274 11.7756380063 72.5374371012 +67.8302307725 6.44767955806 73.1948578909 +67.8313629053 9.67799094548 72.8370969882 +67.8397827163 9.61879323695 72.8370969882 +67.8426004653 45.6743231518 57.5433555394 +67.8480542049 9.74079384618 72.8131751529 +67.8497829436 17.231649688 71.4106238843 +67.8504733873 -65.2939694818 -33.6602259413 +67.8509979422 -2.72517758892 73.4085518544 +67.8558933709 27.34670316 68.1743027916 +67.8567865322 6.43825378899 73.1710694857 +67.8699102498 10.2885930953 72.7173991201 +67.8752163619 31.1904108319 66.4839324646 +67.8832660697 9.11786252269 72.8610099486 +67.8834461191 71.6092810446 -16.2464953535 +67.8851861533 11.994424564 72.4412539946 +67.898591138 10.2686964552 72.6934329537 +67.900655169 16.6151846141 71.5082978952 +67.904984351 18.4875609024 71.043107985 +67.910810114 7.53341673221 73.0162276621 +67.9112821043 43.8161782174 58.8914279787 +67.9157533903 51.7004842987 52.1009631841 +67.9164061936 29.6437202177 67.1461958818 +67.9170967673 45.3464691335 57.7145190037 +67.9210862444 69.3103147729 24.1413816807 +67.9219358427 48.5914774402 55.0043539327 +67.92408708 45.6430923145 57.4719628891 +67.9244142691 11.6959606443 72.4532846102 +67.9264509477 8.28015521062 72.9207535023 +67.9266409286 11.7573879688 72.4412539946 +67.9288138131 10.9777348348 72.561460789 +67.9417628305 -45.3457957499 57.6860093202 +67.9447605164 9.04162831139 72.8131751529 +67.9502737346 4.66813024476 73.2186373775 +67.958796379 69.5913510431 23.2087452208 +67.9617827951 12.0691269679 72.3569779188 +67.9647030653 8.48954454136 72.8610099486 +67.9658608793 7.83987720958 72.9326955506 +67.9674692921 8.67066435509 72.8370969882 +67.9736209662 9.3958457853 72.7413564262 +67.9740604788 67.0315283527 29.7708130344 +67.9816192078 -1.89889856335 73.3136660803 +67.9912987349 10.9878328016 72.5013849983 +67.9975271629 13.254332766 72.1155944485 +67.9996104363 20.4008608168 70.4262583022 +68.0070272821 11.5880085282 72.3931094691 +68.0089690052 9.95780565011 72.6334787924 +68.0091085583 26.4746293287 68.3655992076 +68.0111851227 38.3223333221 62.4970196645 +68.0137020248 50.9177874506 52.7400726016 +68.0177604576 58.7528011159 43.8371146789 +68.021511162 9.95964206025 72.6214813211 +68.0220248848 10.3845336312 72.561460789 +68.0226537732 24.3824279598 69.1260861067 +68.0232784733 9.49952174261 72.6814465487 +68.0332213075 33.0645097277 65.4080957909 +68.0385948196 10.6910611403 72.5013849983 +68.0492327689 50.8702925246 52.7400726016 +68.0513080343 32.3131367949 65.7638248986 +68.0521730612 2.81653727844 73.2186373775 +68.0564412296 25.8522168652 68.5564270534 +68.0630580096 36.0679587712 63.7692910769 +68.0631229572 3.15024945912 73.1948578909 +68.0636919441 69.0930611513 24.3615011786 +68.064218455 3.12649075578 73.1948578909 +68.0669570551 7.85153867601 72.8370969882 +68.0693014447 49.636988356 53.8770785007 +68.0720426588 66.7076335667 30.2702598633 +68.0782858977 17.5428731298 71.1167673026 +68.0930729294 40.1899668985 61.2217280034 +68.1000371625 3.68816617697 73.1353701619 +68.1010713927 10.7008782281 72.4412539946 +68.101834366 8.82071206847 72.6934329537 +68.1061817054 9.54745770281 72.5974797422 +68.1100609898 16.4398130912 71.3495069184 +68.1109877112 9.96060097508 72.5374371012 +68.1129861096 49.942507709 53.5384632481 +68.1197349722 39.9336546153 61.3596360516 +68.1267036722 39.9217648705 61.3596360516 +68.1268815221 42.5704003043 59.5524057617 +68.138380121 10.207666438 72.4773392198 +68.1440826161 16.5109696889 71.3005742217 +68.1455515981 54.9865283463 48.2976759048 +68.1555714867 44.8039065136 57.8569618666 +68.1574312587 14.2388292389 71.7761820252 +68.1632453745 67.6417889142 27.8991106039 +68.1703192978 17.7316299504 70.9816657042 +68.1745835564 5.74874565685 72.9326955506 +68.1805010165 67.6589125486 27.8152985584 +68.1824757112 45.1289961998 57.5719003324 +68.18346863 45.1638886595 57.5433555394 +68.1906349446 -62.5509204134 -37.9133177301 +68.1929224701 17.8900783073 70.9201693677 +68.1976504053 22.027240897 69.7415309387 +68.201551101 27.9436872969 67.5847524792 +68.2224787196 -51.5962554161 51.8027009373 +68.2254685339 19.408790873 70.4881853942 +68.2313463849 28.6397875062 67.2625151337 +68.2333808343 48.7962840252 54.4346250585 +68.2355327161 9.06820234312 72.5374371012 +68.2398034724 9.68766077249 72.4532846102 +68.2414186846 10.7839619469 72.296714591 +68.2520441323 50.0994400637 53.2137630417 +68.2531906216 8.2232852743 72.6214813211 +68.256583725 8.40504094402 72.5974797422 +68.2611367806 45.0099266555 57.5719003324 +68.2688692363 9.75257115963 72.4171861437 +68.2770053937 -73.0390162699 -1.88484397154 +68.2840535922 49.0670701104 54.1268016402 +68.2844445183 21.2290203422 69.9039579147 +68.2864825226 10.3273595117 72.3208265315 +68.2890815573 6.59954987165 72.7533317557 +68.2929458033 48.7128848278 54.4346250585 +68.2955887769 -9.3796201046 72.4412539946 +68.2973294305 14.1809950625 71.65454746 +68.2999382565 10.817647495 72.236396206 +68.3042767151 7.44434399154 72.6574670971 +68.3050429862 45.4333317654 57.1859551582 +68.3135981388 7.92831914107 72.5974797422 +68.3142990395 14.6453167247 71.5448897181 +68.3191487607 -35.8683549873 63.6078220278 +68.3206043232 39.9713402016 61.1112672705 +68.3222444326 67.0932189273 -28.8196268134 +68.3233184649 49.3670256424 53.8035401546 +68.3303919308 14.7485887704 71.5082978952 +68.3331078865 18.1820341705 70.7106781187 +68.3347966596 2.05200402156 72.9804415237 +68.342940695 27.5014012887 67.623334614 +68.3432089754 17.0018718201 70.9939584863 +68.3443986706 7.99234499473 72.561460789 +68.3529729861 9.1445193958 72.4171861437 +68.3550618653 16.95415512 70.9939584863 +68.3569564773 18.1883797899 70.6859911282 +68.3592645042 66.0829809856 -30.9846829984 +68.3644950709 61.9239435401 38.622804535 +68.3664109892 7.22179335024 72.6214813211 +68.3699359155 8.72200734377 72.4532846102 +68.3780343981 7.58524640754 72.5734693176 +68.3847089276 -61.6387342517 -39.0409787882 +68.393883263 22.7913974963 69.3024453563 +68.3995528443 10.5888102283 72.1760228098 +68.3997222473 8.27727588696 72.4773392198 +68.4107606746 24.8994805891 68.5564270534 +68.4220303347 10.6901358729 72.1397723859 +68.4233057229 48.9862755805 54.0240320478 +68.4249033215 7.73555184774 72.5134045749 +68.4402376966 5.30223813389 72.7173991201 +68.4405839194 10.5707006805 72.1397723859 +68.4408172079 9.43607965597 72.296714591 +68.4515764864 16.5601791951 70.9939584863 +68.4524289998 72.4370469584 8.193850863 +68.4598045701 49.0485607292 53.9211818177 +68.4668150817 8.24902319015 72.4171861437 +68.4732813238 9.65985548154 72.236396206 +68.4742019759 14.9673521901 71.3250449154 +68.4752995341 8.99062864921 72.3208265315 +68.4830158801 22.7149104615 69.2395073545 +68.4846910709 33.9960958842 64.4524053357 +68.4850285522 -61.8809718672 -38.4778661699 +68.486014005 7.29486525091 72.5013849983 +68.486612405 -62.4711431688 -37.5092014374 +68.4909407072 22.6910039959 69.2395073545 +68.5017449506 -36.4690443792 63.0675807431 +68.5058943194 8.65430704926 72.3328791975 +68.5219117641 18.3347573757 70.4881853942 +68.5251349306 -2.78819204278 72.7772757657 +68.5252332846 28.1461702917 67.1720589323 +68.5337756786 7.32414776145 72.4532846102 +68.5349675391 21.5695465145 69.5536691165 +68.5460195347 -72.106306617 -10.1056297183 +68.5461770415 15.0457726009 71.239359485 +68.5462176422 49.3462156601 53.5384632481 +68.5470685636 44.4809761593 57.643231617 +68.5473690463 8.3194220853 72.3328791975 +68.5546843368 7.48374281357 72.4171861437 +68.5581905028 -63.5968011689 -35.4291037998 +68.5637876126 20.1794200804 69.9413899879 +68.5657120301 9.45329916823 72.1760228098 +68.5703193291 -1.25675742676 72.7772757657 +68.5935126032 13.9804443852 71.4106238843 +68.5950314058 26.6062592305 67.7261296414 +68.5961710387 26.5378571475 67.7518077755 +68.5989259772 11.3318781686 71.8733322724 +68.6097506063 24.094029479 68.6453193248 +68.6139904331 -37.5961982332 62.2787780488 +68.6156798459 69.28961763 -22.1548497619 +68.6162777846 10.8309251441 71.9339800339 +68.6236899902 8.82742081189 72.2001787667 +68.6252296205 8.81544358415 72.2001787667 +68.6293145745 22.6571181217 69.1134732122 +68.6294590434 10.747086484 71.9339800339 +68.6408924388 49.8339288822 52.9623207325 +68.6417382535 31.4266414389 65.5795545685 +68.6496419347 -70.9647483466 -15.8502730052 +68.6525705924 -64.9896342763 -32.6063182175 +68.6539342524 39.15951273 61.2631200187 +68.656187128 61.9703585467 38.0263412733 +68.6608353724 35.0146377911 63.715499106 +68.6622157261 16.6365107447 70.7723578937 +68.6662407737 22.3507701388 69.1765166238 +68.6695203771 49.1263007869 53.5826794979 +68.6718725337 18.1054301302 70.4014724456 +68.6729617298 -37.4883732909 62.2787780488 +68.6828797031 8.76192983275 72.1518580586 +68.693545804 10.9045702547 71.8490578396 +68.6954557692 8.45908316675 72.1760228098 +68.7027693755 35.0058094476 63.675134747 +68.7138787331 14.4427133103 71.2026045991 +68.7150515514 18.8885752997 70.1531425771 +68.718864629 9.07141445009 72.0793110676 +68.7189160047 14.4187267624 71.2026045991 +68.7189789288 8.4741556322 72.1518580586 +68.7281294107 33.3725865532 64.5191033296 +68.7331669443 0.359889309413 72.6334787924 +68.7398327163 26.4280534441 67.6490457382 +68.7537715023 17.0403098939 70.5871570679 +68.755910037 7.38430078985 72.236396206 +68.758265333 10.9763674447 71.7761820252 +68.7666945929 40.8793904694 60.0001429133 +68.7670627681 4.83278366403 72.4412539946 +68.7717071556 49.2720257683 53.3171620737 +68.7745384027 -65.4931078098 -31.3163806484 +68.7747163474 -37.232901732 62.3197353969 +68.7789951216 54.944869562 47.4395524734 +68.7810456207 11.5346825269 71.6667207449 +68.7818166697 29.5794459848 66.2881442707 +68.7827458296 8.77466983429 72.055111168 +68.7831445867 28.9844287226 66.5490940013 +68.7869533999 28.4924890126 66.7572701047 +68.7908223723 36.3460404624 62.8234677493 +68.7939990166 9.36245236525 71.9703423989 +68.8036630944 48.499685701 53.9799632428 +68.8096271 10.8122152187 71.7518725918 +68.8121268385 48.4876764578 53.9799632428 +68.8140011256 31.1864565367 65.51364879 +68.8201346283 49.5069442412 53.0363228518 +68.8277521844 -36.8587306544 62.4833938242 +68.8286499189 10.0164783188 71.8490578396 +68.8299314984 48.2489655749 54.1708210283 +68.8346697534 49.9746130222 52.5768608156 +68.8396914704 48.2020708956 54.200159037 +68.8444755162 13.3570728791 71.2883356168 +68.8459389219 5.78115501551 72.296714591 +68.8482108732 19.5469882673 69.8415285431 +68.8512890699 9.40696998146 71.9097275004 +68.8552971228 48.7522678838 53.6857935987 +68.8561055457 13.2969896622 71.2883356168 +68.8586866298 14.2348832443 71.1044961634 +68.8611700368 14.2228649195 71.1044961634 +68.8623254143 8.84590037977 71.9703423989 +68.8715471802 -71.3185748627 -13.052619222 +68.8794357005 26.785747606 67.3657707057 +68.8799653745 11.7738680996 71.5326946227 +68.8971908528 -27.4453842968 67.0815024682 +68.907343278 -67.4084128463 -26.6060880235 +68.9091509383 68.9813502425 22.2059054235 +68.9197128629 36.3833727783 62.6603811364 +68.926517573 9.31923080677 71.8490578396 +68.9277251097 23.908790276 68.3910700219 +68.9601201131 25.5091230114 67.7774776543 +68.9615433093 61.5505306747 38.1554415263 +68.9724630882 48.7810275874 53.5089775931 +68.979720562 -61.6100277598 -38.0263412733 +68.9798776276 13.2459773425 71.1780904964 +68.9802408568 21.1157081632 69.2520991747 +69.0012440068 17.716508272 70.1780140797 +69.0130496584 68.3656629349 23.7346815507 +69.0269702582 17.8130337671 70.1282625266 +69.0396377614 70.4271516997 16.5391874421 +69.0410580115 -68.4889741134 -23.2936200179 +69.0428093246 20.058790373 69.5034920658 +69.04353647 -66.3724854942 -28.769484546 +69.0458572973 66.1432328613 29.2872384621 +69.0527495004 12.5863649952 71.2271100259 +69.0528282463 8.33185446089 71.8490578396 +69.0553635507 23.239697408 68.4928699156 +69.0584272754 50.3952050143 51.8773258161 +69.0613175683 -0.482146784042 72.3208265315 +69.0637068811 12.5261003185 71.2271100259 +69.0662926684 44.8179066147 56.7556381667 +69.0667303159 8.32130221573 71.83691734 +69.0669157273 67.2115647258 26.690198932 +69.0736532148 38.4143274982 61.2631200187 +69.0773379578 10.7184286534 71.5082978952 +69.0841242177 27.7016346017 66.7832555471 +69.0843865555 8.69064026003 71.7761820252 +69.0850934554 28.16497703 66.5881666001 +69.088455845 48.8268931774 53.3171620737 +69.0980343674 -65.9623312047 -29.5708050044 +69.1004416493 67.1503283765 26.7574730274 +69.1010666335 30.1464363206 65.6980590831 +69.1045131901 27.4301948597 66.8741404933 +69.1058975039 63.7021245569 34.1528074559 +69.1141412281 66.116178042 29.1870944669 +69.1180495161 24.5167209542 67.9825391166 +69.1228181781 67.7373477571 25.1731548668 +69.1253460226 -1.89462408644 72.236396206 +69.1256796253 66.1041143418 29.1870944669 +69.1267545281 -69.1267545281 -21.0471759821 +69.1299359407 2.86114363252 72.2001787667 +69.1302035635 4.10709086458 72.1397723859 +69.1310876044 10.6155904251 71.4716864679 +69.1326702507 34.7701108123 63.3380872628 +69.1386188141 49.3160975241 52.7993741769 +69.1450510037 8.40420735522 71.7518725918 +69.1459664724 63.6498260378 34.1692107891 +69.152420548 11.2002481523 71.3617346599 +69.1598523562 7.39105605669 71.8490578396 +69.1646265049 8.02708753664 71.7761820252 +69.1687562358 5.38296832917 72.0187948577 +69.1691802333 27.1071053194 66.9389972068 +69.1795580198 61.4852909074 37.8648617352 +69.1904773335 6.45514811421 71.9097275004 +69.193873052 28.8735009446 66.1704531892 +69.2075885105 48.4956864284 53.464736887 +69.2124012115 11.2967572133 71.2883356168 +69.215218204 2.25982500984 72.1397723859 +69.2248239294 -1.42587890086 72.1518580586 +69.23047812 8.93004208785 71.605832497 +69.236373066 22.2293675002 68.6453193248 +69.2442020193 19.0340295813 69.5912796592 +69.249323472 35.1017981586 63.026938405 +69.2497050913 17.4842936947 69.9912695896 +69.2508419303 19.0098576359 69.5912796592 +69.2586262962 18.84311518 69.6288711231 +69.2595289093 11.3168597863 71.239359485 +69.2624698496 26.2135585438 67.1979137981 +69.2633225527 -1.39039069817 72.1155944485 +69.2653771416 10.5619785992 71.3495069184 +69.2875634508 55.2521618534 46.329603512 +69.3087965738 -35.8035813731 62.5651203016 +69.3274042724 -1.33115416582 72.055111168 +69.3335882192 48.9457206017 52.8882782801 +69.3375729802 44.1388867397 56.9566471151 +69.3433036907 21.4918658608 68.7721305114 +69.3464155098 35.9918457568 62.4152360803 +69.3505356418 5.31188231768 71.8490578396 +69.356260154 32.7105358921 64.1851230356 +69.3677224135 49.937614471 51.9071647088 +69.3680426398 14.2139817148 70.6118784917 +69.3769680188 64.989987602 31.0344618128 +69.3778067542 32.6910985639 64.171738364 +69.3787961893 48.9776349556 52.7993741769 +69.3817227213 -1.7198862431 71.9945730144 +69.3924812462 26.5955985613 66.9130606359 +69.4044482107 28.3941094301 66.1573663187 +69.4068609405 -35.5172851533 62.6195665085 +69.4078678814 67.8032878293 24.19218956 +69.4156668819 -62.2393918228 -36.1624570082 +69.4200356308 34.76296432 63.026938405 +69.4265591799 27.375847587 66.5621202286 +69.4294043298 -35.7125091617 62.4833938242 +69.4299791911 23.8389067466 67.9057031084 +69.4431948168 -67.1073751273 -25.9661875744 +69.4478300367 28.6526942202 66.0001667961 +69.4537144253 8.24497337547 71.4716864679 +69.464358903 -35.5008248332 62.5651203016 +69.466660531 14.2847295325 70.5005643726 +69.4890224141 19.8206958378 69.1260861067 +69.4924361766 28.1473344914 66.1704531892 +69.5202658831 69.5688171341 18.0862465458 +69.5298575185 6.18091141134 71.605832497 +69.5523928945 20.5099606459 68.8607737173 +69.5528236894 48.5207218699 52.9919264233 +69.5582510938 5.99993562903 71.5936483022 +69.5622426921 7.15174881989 71.4838924546 +69.5629817323 48.3115289961 53.1694248471 +69.5671529333 28.8156582407 65.8032603517 +69.5782214163 48.322112965 53.1398579518 +69.5872129969 20.3487251197 68.8734286451 +69.5927381515 18.9079284757 69.2772764861 +69.6022402124 26.5367615369 66.7182766905 +69.6049441104 20.28799108 68.8734286451 +69.6117361083 25.9160360056 66.9519624339 +69.6127101183 21.3093148567 68.5564270534 +69.6141051267 1.43389723611 71.7761820252 +69.6205035771 48.4235605425 52.9919264233 +69.6227963873 7.29308025901 71.4106238843 +69.6348163109 3.85661704329 71.6667207449 +69.6442229284 6.70597593823 71.4472679633 +69.660344518 3.61417071065 71.65454746 +69.6621827066 64.5078884828 31.3992455967 +69.666748366 57.1841977834 43.3187222339 +69.670664897 24.3710210653 67.4688949446 +69.6832621097 14.3292702509 70.2774145499 +69.6897017756 40.4789998359 59.2013178799 +69.6927822803 35.7711081219 62.1558036049 +69.6939408819 66.3222689353 27.2784025857 +69.699128673 35.5441312591 62.2787780488 +69.7239261706 35.4954634299 62.2787780488 +69.7262139969 24.3904523179 67.4044576967 +69.7289693607 15.1778788231 70.0535711176 +69.7312837053 50.9421961873 50.4226211181 +69.7363384838 49.0115195696 52.2944934419 +69.7379357366 20.8958519539 68.5564270534 +69.7400161232 67.6536207102 23.6498997024 +69.7412288065 -62.5093425676 -35.0534320191 +69.7460233942 -61.3381127502 -37.055743751 +69.7465246331 57.0868689422 43.3187222339 +69.7470000307 21.8841251138 68.2381202461 +69.7475547829 15.2074262715 70.0286569056 +69.750080731 24.3578186237 67.3915640857 +69.7517245028 50.1586278443 51.1743000114 +69.7560064612 -63.1400489108 -33.8737920245 +69.7579020733 35.8814790497 62.0189854765 +69.7845119393 -64.7343767086 -30.6526078098 +69.7874009098 49.7237578947 51.5486816038 +69.7893988462 12.6828832884 70.4881853942 +69.7907555487 11.9671657386 70.6118784917 +69.7938217558 12.6585214204 70.4881853942 +69.8035308104 0.268027634497 71.605832497 +69.8117262502 9.37688710746 70.9816657042 +69.8161055809 36.8877549484 61.3596360516 +69.8188815426 68.443351382 -20.9959860863 +69.8207653151 26.4527216611 66.5230354654 +69.8254357281 -1.49921133254 71.5692733704 +69.8330965281 27.6065912776 66.0394938452 +69.8392657337 -67.2547974243 -24.4799751878 +69.8411116063 21.3792313879 68.3018857343 +69.8460562778 13.5134535415 70.2774145499 +69.8563796688 5.25252757203 71.3617346599 +69.8589879755 64.3512349975 31.2832279878 +69.8594392498 35.8258436255 61.9368038909 +69.8654468349 67.7752989413 22.9200390922 +69.8779026929 -0.390275890385 71.5326946227 +69.8936064956 6.02886261889 71.2638518925 +69.8976642456 -60.8682842031 -37.5415571225 +69.8992833884 66.3319431744 26.7238376078 +69.9059704465 -71.2113777294 -6.48806425783 +69.9063868892 13.9686744936 70.1282625266 +69.9112586174 13.9442717107 70.1282625266 +69.9186859978 -1.19602168989 71.4838924546 +69.9189859399 22.8260366313 67.7518077755 +69.9287434045 24.8042805132 67.0426618959 +69.932670118 23.0874048102 67.6490457382 +69.9331741314 29.7136851872 65.0111380342 +69.9348426025 23.7124585639 67.4302387584 +69.9375018064 14.0002811851 70.09092643 +69.9393123836 9.35674588361 70.8586190225 +69.9430765705 10.3906708088 70.7106781187 +69.9432042871 27.1994245849 66.0919017453 +69.9473575608 20.6529719542 68.4165325029 +69.9488189348 6.52589784084 71.1658301926 +69.953178774 23.473906018 67.49465546 +69.9547248692 8.24254829112 70.9816657042 +69.9793402234 9.33723751766 70.8216629106 +69.9845093809 58.1022591239 41.5487175664 +69.9858286196 -68.8229199608 -19.1151636272 +69.9891715108 26.0704623752 66.4969688239 +69.9904087072 29.6659255909 64.9713440513 +69.999032786 27.5310225835 65.8952062334 +70.0216523381 15.2671892034 69.7415309387 +70.0281512802 26.4614333067 66.3012109666 +70.0314265561 9.50596169375 70.7476924486 +70.0345170195 -65.9971902013 -27.1944353017 +70.0526777457 -70.7160396084 -9.58457525202 +70.0608082701 64.1314493147 31.2832279878 +70.0660250228 0.0 71.3495069184 +70.0678933831 37.8381688369 60.4877119416 +70.0718135194 7.17942086564 70.9816657042 +70.0792692357 65.7397970176 27.6979261222 +70.0807888711 62.3300855757 34.6935651573 +70.1059370435 50.061483231 50.7839097349 +70.1061763579 14.9910716791 69.7165102855 +70.1129263777 24.2787775777 67.0426618959 +70.1171913138 26.2575972133 66.2881442707 +70.1184239323 24.9680476566 66.7832555471 +70.137203015 50.5473381688 50.256734447 +70.1496166916 64.2352475013 30.8684994204 +70.1605919656 15.7084666882 69.5034920658 +70.1620316417 10.8365796016 70.4262583022 +70.1666727235 63.9587790289 31.3992455967 +70.1795123883 36.1448239845 61.3871952452 +70.1836693549 -71.1705238206 -3.00151544833 +70.2017900864 70.7429818194 8.193850863 +70.2160222577 4.56527954378 71.0553899503 +70.2287409695 27.4799321693 65.6717387452 +70.2304335888 8.43663772809 70.6859911282 +70.2329168293 48.7767992887 51.8474806022 +70.2333096176 71.0966559875 3.5422771708 +70.2344369625 20.1792050856 68.26363268 +70.2382996002 21.3400270529 67.9057031084 +70.2491815995 9.99793909249 70.4634209964 +70.2553255063 38.5912626167 59.7904983058 +70.2604582724 24.4947833028 66.8092328522 +70.2614547079 64.8354043362 -29.3206126622 +70.2709065713 3.10495878584 71.0799473873 +70.2736139743 38.6013084754 59.7625146976 +70.2926765914 12.305965679 70.0535711176 +70.3032095356 11.0469052675 70.2525772694 +70.3062821604 8.32129685743 70.6242359774 +70.3104266571 48.2327316455 52.2498564716 +70.3329407267 8.20000393936 70.6118784917 +70.3408334145 12.3143963754 70.0037341608 +70.3652935912 15.6253813329 69.315026625 +70.3704758301 62.3023424465 34.1528074559 +70.3840237096 16.9366910893 68.9872285383 +70.3869786478 16.9244065018 68.9872285383 +70.4061364734 -63.238387169 -32.3091679739 +70.421661849 -61.4327311281 -35.5922616389 +70.4235853126 26.7514105503 65.7638248986 +70.4278504765 34.547985726 62.0189854765 +70.4310453775 16.7400760341 68.9872285383 +70.4356956512 26.7841490495 65.7375245794 +70.4445537055 13.3106366056 69.7165102855 +70.4562047931 1.00841690724 70.9570736537 +70.4590766778 4.64283295405 70.8093398915 +70.4603104895 14.1816972775 69.5285848271 +70.4608395591 64.7466853232 29.0368184947 +70.4645701354 64.7501133614 29.0201167351 +70.4763844061 37.9000367499 59.9722140278 +70.4853412384 4.80520849498 70.7723578937 +70.4932992377 26.8905821883 65.6322432357 +70.4968742019 36.9646129176 60.5293988043 +70.5016967759 27.6293128421 65.3156323064 +70.502105593 1.80922298187 70.8955557081 +70.5098412873 64.6783165211 29.0702193598 +70.5155823037 36.9744223985 60.5016094056 +70.521370637 59.8699813723 -37.9779095522 +70.5322221704 35.7366150605 61.2217280034 +70.5431106644 6.13450516794 70.6118784917 +70.5486191538 35.8223272095 61.1527040186 +70.5669794045 1.68764944579 70.8339837725 +70.5725161115 10.988273337 69.9912695896 +70.5763474429 10.9636382127 69.9912695896 +70.5851442818 27.1940878083 65.4080957909 +70.5885432687 13.7210228622 69.4909425092 +70.591204125 17.0517286351 68.7467850211 +70.5933444579 13.6324725896 69.5034920658 +70.601050762 25.3066432814 66.144277433 +70.622480989 11.6028474836 69.8415285431 +70.6226187952 21.4567921521 67.4688949446 +70.6232680802 25.5513257295 66.02638684 +70.6286946216 -57.6033577378 41.1514358605 +70.6330490402 52.4567316156 47.5317124823 +70.6345431701 9.44975648921 70.1531425771 +70.6524732866 25.4364555542 66.0394938452 +70.6588106863 9.45300308936 70.1282625266 +70.6642998332 48.1497194622 51.8474806022 +70.694106303 -66.8988529612 -22.954015041 +70.6972288011 -69.5953508009 -12.5852686403 +70.7064650842 60.4958183302 36.6176427403 +70.7275778003 60.4711334328 36.6176427403 +70.7309742603 15.9788336007 68.8607737173 +70.7337620156 15.9664884735 68.8607737173 +70.7455163507 48.0786032645 51.8027009373 +70.7482801184 65.9276826529 25.4601948206 +70.7499032083 12.4496541691 69.5662080833 +70.750455515 7.08677776376 70.3146544139 +70.7584972929 32.2166806618 62.8913392129 +70.7708106164 2.99092323162 70.5871570679 +70.7814226007 8.06452444047 70.1780140797 +70.7864792622 -70.2449547689 -7.41084901954 +70.7954238955 2.99196344054 70.5624270432 +70.8014416679 14.0190629641 69.214317387 +70.8070288327 9.72453774952 69.9413899879 +70.8202380496 14.0484766627 69.189118986 +70.8225557681 28.2983286731 64.678977951 +70.8247152449 14.0879117783 69.1765166238 +70.8303952522 25.040628812 66.0001667961 +70.8386364289 7.54545748959 70.1780140797 +70.8391317652 25.0159028147 66.0001667961 +70.8420435675 12.2747486261 69.5034920658 +70.8514633849 66.6970344796 23.0559260896 +70.8517172312 68.6121493861 16.5047605861 +70.8568576157 36.775788213 60.2233105213 +70.8598797921 -65.6629276983 -25.8313252067 +70.8631886887 66.7314041279 22.9200390922 +70.8847916245 -68.7401380124 -15.8158067254 +70.8881767651 20.688868889 67.4302387584 +70.9035016221 -65.5425227247 -26.0167479254 +70.9087781084 27.617666872 64.8784221735 +70.9151746928 -0.841677754422 70.5005643726 +70.917248592 0.643642203936 70.5005643726 +70.9219679124 10.2200116994 69.7540380788 +70.9295516748 0.643753866239 70.4881853942 +70.9388567386 16.6777503143 68.4801522272 +70.9536896418 26.867787915 65.1436558597 +70.9674603573 9.72133282877 69.7790459842 +70.9845352264 5.8734113887 70.1904466245 +70.9973378031 1.73513756186 70.4014724456 +70.9997852521 65.2419242022 26.5051281935 +71.0068712184 37.9459968897 59.3137889518 +71.0106618942 -70.2709065713 -4.41424817878 +71.0150735619 37.8866675391 59.3418886604 +71.0231664368 31.2213540358 63.0946660302 +71.0260064331 17.53769794 68.1743027916 +71.0268241508 14.9029762076 68.797467622 +71.0381234155 -64.120338788 -29.0201167351 +71.0560634113 -64.6107176822 -27.8655883317 +71.0741600171 60.2113202128 36.3739013043 +71.0752282826 -61.9373677785 -33.347779495 +71.0810851367 5.43195460245 70.1282625266 +71.0872928807 30.909634647 63.1758757508 +71.0877187962 49.4624730109 50.0 +71.0913363489 13.2786989696 69.0630005849 +71.0973938472 69.3326055339 11.7537397458 +71.1094935867 69.3201956419 11.7537397458 +71.1175808975 13.3349893452 69.0251240234 +71.1372545455 13.0304629974 69.0630005849 +71.1488946522 -1.55247440404 70.2525772694 +71.1527599694 10.1518786773 69.5285848271 +71.152808389 47.6686297436 51.6234403806 +71.1793463035 25.7665636556 65.342060399 +71.1874158534 30.1439764455 63.432582386 +71.1897196695 4.39156527468 70.09092643 +71.1963801887 29.3741087382 63.7827342144 +71.2115066441 25.7782055364 65.3024152754 +71.2209557181 62.0862329553 32.7547728433 +71.2601369634 49.8968850756 49.3182901134 +71.2638839347 10.2311969034 69.4030363635 +71.2651644863 -34.2516620182 61.2217280034 +71.2664726384 -34.2982370595 61.1941240013 +71.26824783 -63.0971828666 -30.6526078098 +71.2744716974 -1.40587313389 70.1282625266 +71.2821319472 36.4769098098 59.9023598516 +71.2854515214 15.8036041264 68.3273773681 +71.2950936407 15.6491552523 68.3528606764 +71.2953647588 49.9215518435 49.2423560103 +71.2970965872 5.94939181781 69.8665066769 +71.3036530706 49.8346798834 49.3182901134 +71.308732574 15.8087654115 68.3018857343 +71.3100310874 31.8985184275 62.4288714333 +71.3198363135 36.4490949903 59.874405405 +71.3268656806 49.9065131748 49.2119718658 +71.3305159384 14.3179879003 68.6072351756 +71.3438184934 67.1605199756 -19.988099444 +71.344313474 12.9011534984 68.8734286451 +71.3471629466 67.0697805863 -20.2787295357 +71.3514243958 13.7142904176 68.7087510804 +71.3538169042 13.701837036 68.7087510804 +71.3725779013 10.0688732093 69.315026625 +71.3803495058 3.09156980394 69.9663340513 +71.3845559508 10.0705630104 69.3024453563 +71.3846933983 -65.6875930334 -24.2768546132 +71.3936300896 -1.55781455028 70.0037341608 +71.4158248045 49.5983295267 49.3941866584 +71.4189343837 30.0217556085 63.2299770811 +71.4192326765 7.50646383373 69.5912796592 +71.4244802583 49.5858643586 49.3941866584 +71.448838782 59.6769651358 36.5201761892 +71.455461183 7.5102716032 69.5536691165 +71.4558340046 67.0311216772 20.0223004021 +71.4638117783 13.1160638564 68.7087510804 +71.4683894896 59.693294679 36.4551762325 +71.4792279263 67.0061748025 20.0223004021 +71.4844428379 1.84691635278 69.9039579147 +71.4888101006 -60.6913009545 -34.7263015429 +71.4995109047 -69.7734502043 -4.41424817878 +71.5043609077 13.2267345169 68.6453193248 +71.5074796517 20.571989684 66.8092328522 +71.521298274 6.04352540543 69.6288711231 +71.542441708 6.88875361779 69.5285848271 +71.5448419779 6.86378017535 69.5285848271 +71.5479856152 59.5480941731 36.5364233984 +71.5549721797 18.1061915186 67.4688949446 +71.5580651795 6.32344847952 69.5662080833 +71.5645637484 66.0841457749 22.6141303767 +71.5648378384 -60.6484615259 -34.6444526541 +71.5703197013 -55.1165660322 42.8935133403 +71.5732160333 -67.1412351362 -19.2179419046 +71.5807841042 -69.6822311648 -4.53629881293 +71.6076664473 28.5975404699 63.675134747 +71.6460385811 3.15319084286 69.6914811375 +71.6482446785 4.4826170724 69.6163427557 +71.6619232241 47.9191575672 50.6786256511 +71.6873665023 17.4754962248 67.49465546 +71.6886341997 3.78213536282 69.6163427557 +71.7101790375 8.70328439335 69.1513055782 +71.7114598494 0.750988103358 69.6914811375 +71.7136712263 25.352892858 64.9182577014 +71.7140692407 14.9426657119 68.0720868959 +71.7145356978 -0.3504661254 69.6914811375 +71.7145957734 -0.337949572431 69.6914811375 +71.7298045194 9.22697641787 69.0630005849 +71.7328715235 17.287759465 67.49465546 +71.750852062 56.5232109869 40.7055505812 +71.7632355978 33.9989761214 60.7791710969 +71.7822779602 19.2340034103 66.9130606359 +71.786421536 9.06873401351 69.0251240234 +71.7893224021 -67.7218388867 -16.1259333635 +71.7894007627 20.5174971816 66.5230354654 +71.7917710788 6.15472589229 69.3401828276 +71.8141804101 -10.3869670195 68.810133034 +71.8239462235 67.4000102666 17.2788704766 +71.8314653903 26.357685606 64.3856582585 +71.8407322237 -10.454819869 68.7721305114 +71.8467587281 56.2743323522 40.8808363244 +71.8767445754 1.73152531084 69.5034920658 +71.8783416871 16.5679972658 67.5204077514 +71.8789364832 5.53078273688 69.3024453563 +71.884147833 3.26424005215 69.4407231184 +71.8888706099 1.73181742946 69.4909425092 +71.8930094666 8.99297729527 68.9240273721 +71.8933259831 17.0213621419 67.3915640857 +71.8992631793 16.9962656004 67.3915640857 +71.8996432399 69.1180995639 7.28900642467 +71.9098908011 -10.6443787776 68.6706983029 +71.9159044177 27.347018939 63.8767817516 +71.932473013 31.3219241621 62.0052932662 +71.9521616156 29.6565409501 62.7963057649 +71.953528219 5.66286548289 69.214317387 +71.9686538666 8.77289503574 68.8734286451 +71.9710209754 19.7835847955 66.5490940013 +71.9726525299 19.8651211996 66.5230354654 +71.9731678325 16.4179660935 67.4560116039 +71.979602112 33.4881982647 60.8068865901 +71.981600349 2.66460588904 69.3653305813 +71.9825260866 2.63947940867 69.3653305813 +72.0002520994 -10.6063926718 68.5818352927 +72.0084593752 33.5016239814 60.7653105729 +72.0124613167 31.7312575074 61.7035875141 +72.0215587701 5.56704671762 69.1513055782 +72.02311068 58.6987638953 36.9746757274 +72.0281597727 -0.628580227548 69.3653305813 +72.0296043807 19.7456129302 66.4969688239 +72.0501564611 15.7489979582 67.5332808121 +72.0575194239 68.5715016481 10.2792536787 +72.0605087567 34.1860251116 60.3207987745 +72.0608633451 20.2825392477 66.3012109666 +72.0659215575 14.0995896643 67.8800745533 +72.0688390452 58.6732595202 36.9260213935 +72.0760621476 66.5564736004 19.37206977 +72.0763241362 -7.61368500739 68.8987322062 +72.0821620064 48.127374256 49.8790313429 +72.0849943357 32.0189607175 61.4698279336 +72.085495147 34.1824672456 60.2929541689 +72.0876488943 21.8744191147 65.7638248986 +72.0975888835 46.4103146506 51.4589192581 +72.0992119112 51.389905303 46.4842045725 +72.1021966501 58.8051166679 36.6501226724 +72.1057482494 30.7557079728 62.0874181818 +72.1147268189 21.7452551909 65.7769720534 +72.1212402398 58.8625809609 36.5201761892 +72.1225373429 31.6145507576 61.6348909921 +72.1278254846 -10.8053168 68.4165325029 +72.1294195699 19.7323762898 66.3926212652 +72.1300122189 58.6184708568 36.893579546 +72.1300167076 8.53715006557 68.7341091345 +72.1304912407 6.43747484329 68.9619543736 +72.1351949036 -7.96379965905 68.797467622 +72.1453552102 53.3457921593 44.1505852792 +72.1516505896 -7.11267487386 68.8734286451 +72.1595646771 11.9071236798 68.1998360062 +72.1688653555 31.4548303684 61.6623752364 +72.173639191 31.7120651534 61.5248789485 +72.1773860648 23.3822377476 65.1436558597 +72.1809211465 -60.7174146938 -33.2161131884 +72.1838678007 15.409005298 67.4688949446 +72.2080266928 20.2287855025 66.1573663187 +72.2190777705 6.78856296964 68.8354575694 +72.2249742994 68.9473690476 5.46016381259 +72.2307219139 19.8007456634 66.2620048216 +72.2313135327 8.07651024567 68.6833846544 +72.2368610312 31.7548868325 61.4285200099 +72.2382850424 -63.4182202124 -27.5637355817 +72.2391091854 20.0744172727 66.1704531892 +72.2462230883 6.21909097268 68.8607737173 +72.2465703932 31.5187122261 61.5386370179 +72.2471265918 45.6727375041 51.9071647088 +72.2491680132 13.2602036983 67.8544377272 +72.2533686472 20.786574519 65.93458151 +72.2537922958 13.2349831737 67.8544377272 +72.2674267084 5.01540798536 68.936671806 +72.2772663639 20.4932854819 66.0001667961 +72.2851682399 33.9070119549 60.2093762865 +72.2952077671 45.5796046184 51.9220817836 +72.2952424225 6.6175515107 68.7721305114 +72.3082157195 -1.35051459528 69.0630005849 +72.3090052119 -33.9798019745 60.13967761 +72.3168611347 0.757328082547 69.0630005849 +72.3361056421 -7.43693184895 68.6453193248 +72.3363005042 -68.9330922666 -3.96086100934 +72.3386497192 20.3607261132 65.9739387103 +72.3582399929 37.2669424361 58.0987100252 +72.3603773627 1.73053957791 68.9998624687 +72.3655206315 20.4773782732 65.9083333334 +72.3709428687 12.0847742605 67.9441304262 +72.3718800344 22.5829071977 65.209840383 +72.3729400488 17.4821176311 66.7572701047 +72.3761992776 -9.46425990119 68.3528606764 +72.3770991239 0.757958916353 68.9998624687 +72.3781856645 27.7833823977 63.1623456061 +72.3822529542 18.9216312321 66.3534575496 +72.386944078 14.4249277986 67.4688949446 +72.395772961 37.2383247429 58.0702955711 +72.4019321167 -4.80893102521 68.810133034 +72.4019888889 8.47965816366 68.4547105929 +72.4182037472 8.02063194211 68.4928699156 +72.419962018 2.88336638143 68.8987322062 +72.4202429388 1.74461829631 68.936671806 +72.4203626753 26.2444010318 63.7692910769 +72.4206267113 7.7778868862 68.5182990326 +72.4268012526 20.0448963918 65.9739387103 +72.431147322 8.2268763977 68.4547105929 +72.4315560739 20.4551086412 65.8426777644 +72.4393419743 49.7861803926 47.6851966153 +72.4515033264 22.0538936457 65.3024152754 +72.4548808602 -68.397501746 -8.48952262753 +72.4589934693 6.40306177831 68.6199319824 +72.460136255 -4.8382024733 68.7467850211 +72.4624849717 20.6825079208 65.7375245794 +72.4628291746 -10.7391514397 68.0720868959 +72.4667876165 7.33535208575 68.5182990326 +72.4697448633 14.3099672281 67.4044576967 +72.4806601441 1.73341620903 68.8734286451 +72.487780474 16.3757136727 66.9130606359 +72.492249167 12.9128363037 67.6618982095 +72.4958749719 66.944137137 16.2120515372 +72.501876853 6.72579576272 68.5437198009 +72.5076534669 4.6634444025 68.7087510804 +72.5114959557 44.9940816556 52.1307545528 +72.5120290328 44.9068168322 52.2052051767 +72.5181924713 21.1096641468 65.5400170912 +72.5262671721 37.1614976543 57.9565670322 +72.5265875141 24.3092903925 64.4123629761 +72.539287955 15.7100558334 67.0167579691 +72.5393667806 22.7324595949 64.9713440513 +72.5471542146 23.7821577975 64.5857521893 +72.5475955497 -1.93773805094 68.797467622 +72.5544935676 -14.3661765875 67.301251351 +72.5633613041 -68.4999074262 -6.5054806779 +72.5659020758 20.9450713919 65.5400170912 +72.5688557031 -3.58729799562 68.7087510804 +72.5731947777 28.9978255712 62.3879596709 +72.5752113806 7.09048548399 68.4292606175 +72.5754543926 20.1542394348 65.7769720534 +72.5796462686 1.60904084784 68.7721305114 +72.594353961 20.6379572096 65.6059028991 +72.5960070514 7.82235656282 68.3273773681 +72.6017794858 -67.7496505874 -11.7884036575 +72.6091670719 23.5921485087 64.5857521893 +72.609913471 16.0972302715 66.8481835454 +72.6107702857 12.0857459503 67.6875969683 +72.6255075122 7.54355092715 68.3273773681 +72.626235626 -2.1301229451 68.7087510804 +72.6290110363 4.25135713009 68.6072351756 +72.6328233581 30.7560274556 61.4698279336 +72.6340785666 8.23708541073 68.2381202461 +72.6380519715 2.51119059428 68.6833846544 +72.6457205111 12.0915632628 67.6490457382 +72.6492262125 7.54601456877 68.3018857343 +72.6528265831 16.3330533966 66.744274333 +72.6606209497 34.62620992 59.3418886604 +72.6626664789 12.1334873743 67.623334614 +72.6696087834 -14.3889700141 67.1720589323 +72.6702906298 21.8021320291 65.1436558597 +72.6720986817 34.5538914283 59.3699811383 +72.6724580353 16.0844838787 66.7832555471 +72.6742509123 49.1302083451 48.0070399244 +72.6752642004 16.0717998971 66.7832555471 +72.6794938064 -0.532778058444 68.6833846544 +72.6812224679 16.2062254808 66.744274333 +72.6815174733 -2.28410870455 68.6453193248 +72.6821362078 -3.72007313749 68.5818352927 +72.6844358036 11.4080741454 67.7261296414 +72.7009548585 -13.6056138876 67.301251351 +72.7017549515 15.2279201872 66.9519624339 +72.7034530975 7.93664138203 68.1998360062 +72.7158480559 15.2176244684 66.9389972068 +72.7196660045 -60.6953316069 -32.0612990586 +72.7306976489 -2.6033607859 68.5818352927 +72.7398568595 12.1724774311 67.5332808121 +72.7402895936 17.1950758202 66.4317667789 +72.7522523714 16.2620550954 66.6532470249 +72.7650796327 19.810752541 65.6717387452 +72.7712888529 45.9685532641 50.904141575 +72.7806278469 16.2417252647 66.6272209433 +72.7861949838 16.3763820368 66.5881666001 +72.7887751855 28.4523583397 62.3879596709 +72.7943090891 18.2441521572 66.0919017453 +72.7953479547 45.9304440068 50.904141575 +72.8000754733 -0.406596551708 68.5564270534 +72.8103711704 45.93992295 50.8740929096 +72.8132309976 2.94993942795 68.4801522272 +72.824871524 11.2738857551 67.59761525 +72.8402595972 22.1027927987 64.8518552727 +72.8557504547 15.7919057342 66.6532470249 +72.859985528 11.1231174222 67.5847524792 +72.8623875198 27.5614710944 62.7011785857 +72.8738709286 -14.5616363166 66.9130606359 +72.8908833076 49.8720657755 46.9009188174 +72.9005033022 24.180132604 64.0377842023 +72.9207535023 0.0 68.4292606175 +72.9489044019 16.7075294622 66.327338299 +72.9511402912 29.0750399741 61.909394931 +72.9515755695 -64.0895251204 -23.8872432853 +72.9647217003 16.1090990654 66.4578536706 +72.9684712048 33.1767768535 59.7904983058 +72.9697001107 44.0181373107 52.3242434579 +72.9703403913 16.0836285918 66.4578536706 +72.9764664218 -11.0627104969 67.4688949446 +72.9770906684 12.2514609523 67.2625151337 +72.995858989 -11.1699360539 67.4302387584 +73.0225610407 -65.450413785 -19.5946144243 +73.0256543187 20.6641772778 65.1171681568 +73.0343635123 46.653561161 49.8941577478 +73.0483172106 18.6469403765 65.6980590831 +73.0489594611 -63.2323751439 -25.7976017359 +73.0506442274 46.628064517 49.8941577478 +73.0526948287 27.7063545655 62.4152360803 +73.0611516366 -67.7027555161 -8.85466075362 +73.0645423057 -67.7058975093 -8.80250533245 +73.0894826274 18.6710369819 65.6454104053 +73.1218921997 1.40401205606 68.1998360062 +73.1254269195 3.92193195539 68.0976533192 +73.1386715117 3.66665268667 68.0976533192 +73.1512247032 18.3336045176 65.6717387452 +73.1520349258 -66.0979357236 -16.728499015 +73.1611919526 12.2167330469 67.0685576537 +73.1670359291 47.0084767804 49.3638325511 +73.1787037457 18.8299453609 65.5004616457 +73.1835030717 -11.2640184615 67.2108381607 +73.1871780203 -1.06028066616 68.1359873953 +73.1954898726 -3.47741896901 68.0465121782 +73.2069254043 -8.44443517135 67.59761525 +73.2078603888 28.7193298603 61.772237046 +73.2183864613 0.191685725443 68.1104334195 +73.2185304259 -11.1124787269 67.1979137981 +73.2208590085 18.8953046772 65.4344960034 +73.2315556695 -10.1226386635 67.3399691173 +73.2333341847 17.0149853159 65.93458151 +73.2356806862 -64.5205179062 -21.7632222696 +73.2371399149 -66.5239341239 -14.5219670077 +73.2528351419 62.9406767913 -25.9324767181 +73.2655323912 18.6751500318 65.44769312 +73.2720467846 18.6495743992 65.44769312 +73.2756109084 -7.24930180768 67.6618982095 +73.2758547767 16.9844311709 65.8952062334 +73.2785822948 -14.9086960664 66.3926212652 +73.2883666223 12.093388445 66.9519624339 +73.2987288994 18.6836117157 65.4080957909 +73.3165996858 12.1374843706 66.9130606359 +73.3181103675 -2.13760822106 67.9697382902 +73.3196887454 30.2201949587 60.917674438 +73.3208320003 12.1118913104 66.9130606359 +73.3453885823 19.5431164659 65.1039213298 +73.3464720897 -0.640084964845 67.9697382902 +73.3483891429 -0.358450703154 67.9697382902 +73.3638060831 3.67793933249 67.8544377272 +73.3679938562 48.7825024159 47.301214948 +73.3788476917 -2.08810842338 67.9057031084 +73.3818652097 35.9494048226 57.643231617 +73.3935588088 -0.678927767736 67.9185142834 +73.3951685615 -0.473971906752 67.9185142834 +73.4041836281 44.2278305992 -51.5337251359 +73.4054683413 44.9829288533 50.8740929096 +73.4069373583 -0.486860383759 67.9057031084 +73.4079603928 -0.294680022239 67.9057031084 +73.4087019068 12.1527317944 66.8092328522 +73.4462587837 65.783956417 16.6768746716 +73.4813577125 1.21847871168 67.8159669868 +73.5082878854 28.6301281916 61.4560604976 +73.512547503 0.615871685969 67.7903094969 +73.5269533171 0.0256657495293 67.7774776543 +73.5319376448 11.3833453738 66.8092328522 +73.5352772581 -4.02114527107 67.6490457382 +73.5432066088 21.1159601323 64.3856582585 +73.5567487995 1.60501396844 67.7261296414 +73.5673365549 11.1522821842 66.8092328522 +73.5941961124 4.02436714336 67.5847524792 +73.6199230013 43.1925522814 52.1009631841 +73.6301813851 0.68111664698 67.6618982095 +73.6406312816 16.9336041244 65.5004616457 +73.642549864 44.248908098 51.1743000114 +73.6426736167 67.3629454209 6.24421386623 +73.651193317 -61.2115711334 -28.7861995122 +73.6622313279 18.6394100575 65.0111380342 +73.6629094928 61.5917524964 -27.9326294767 +73.671435482 -66.4972155089 -12.2735456807 +73.6898358695 27.5515006654 61.7310529686 +73.6994683565 -3.06315214399 67.5204077514 +73.7072783938 2.54815512268 67.5332808121 +73.72565849 -2.99979408371 67.49465546 +73.7326042964 -4.67762266037 67.3915640857 +73.7417131269 2.57511736603 67.49465546 +73.7428096663 1.11982376601 67.5332808121 +73.7522965406 2.92352012789 67.4688949446 +73.761066566 -60.2653191678 -30.4531831612 +73.7645128843 44.3572430325 50.904141575 +73.7737666263 -4.77073548278 67.3399691173 +73.774581322 -66.707241558 -10.3660539498 +73.7808648263 -64.6357705963 -19.4576757325 +73.782062711 12.1748537423 66.3926212652 +73.7849042406 -11.4225066719 66.5230354654 +73.7932983486 35.5619155201 57.3576436351 +73.7935494354 2.77037230639 67.4302387584 +73.7946758903 22.2799262237 63.70204626 +73.8021138135 -60.2988561756 -30.2868938746 +73.8052574316 1.57177414266 67.4560116039 +73.807635314 1.45583922396 67.4560116039 +73.8086785351 67.4674881514 -0.645767334904 +73.8159585504 22.2863518376 63.675134747 +73.8226449324 45.0615349204 50.1963660617 +73.8310707832 34.710791325 57.8284873795 +73.8464547041 28.1696867788 61.2631200187 +73.8555498314 43.4521712231 51.5486816038 +73.8651656565 -11.4349317955 66.4317667789 +73.8747876666 20.1821405377 64.3054970475 +73.8764153248 28.1811156457 61.2217280034 +73.8826337669 34.9557186776 57.6147043678 +73.8859226321 2.48977832117 67.3399691173 +73.8880672396 2.42529975028 67.3399691173 +73.9009060093 67.2446505314 4.10037387439 +73.9163614354 49.352021241 45.8339340618 +73.9403626341 44.8681134853 50.1963660617 +73.9529219352 11.8453389259 66.2620048216 +73.954268623 44.9295495709 50.1208711795 +73.9695300555 29.9156693527 60.2790291109 +73.9728739742 43.9218784117 50.9792360946 +74.0112815091 49.396723233 45.63215909 +74.0237108052 44.865676607 50.0755559253 +74.0339241206 -8.73628870509 66.6532470249 +74.0400557614 44.8049349287 50.105767621 +74.0424983499 40.9073833718 -53.3319268711 +74.0567381786 -1.87457438859 67.1720589323 +74.0590441117 -5.8675921982 66.9389972068 +74.0645011001 63.3241582414 -22.4610921331 +74.0700328723 41.9921793919 -52.4431797303 +74.0714515211 45.089286478 49.8033765367 +74.071919615 1.12482147554 67.1720589323 +74.075106567 -5.95994156238 66.9130606359 +74.0857798583 43.3790072273 -51.2792253721 +74.0866267929 11.9596092805 66.0919017453 +74.0877975094 2.03063758447 67.1332612883 +74.1009174745 43.3531437693 -51.2792253721 +74.1023796251 43.5625780225 -51.0993065504 +74.1140119744 42.7035526 51.8027009373 +74.1248360257 21.1150149855 63.715499106 +74.1322020403 21.0891392507 63.715499106 +74.1414834281 39.1399951893 -54.507808722 +74.1864802928 43.996186624 -50.6033764121 +74.1892410235 42.6090314516 51.7728399366 +74.1941079266 31.5240998718 59.1731820696 +74.200982963 47.089375685 -47.715876026 +74.2037481066 21.8393507232 63.3785967573 +74.2076332037 33.8496549151 57.8569618666 +74.2084719288 12.285132863 65.8952062334 +74.2197508236 -0.427479804138 67.0167579691 +74.2234599561 43.3205700959 -51.1293086077 +74.2338598519 46.5668124998 -48.1753674102 +74.2359597022 -59.4742185894 -30.8518980011 +74.2373617624 43.1724916105 51.2342667236 +74.2471743516 3.67026236188 66.8871159118 +74.258454265 33.2952117746 58.1129145979 +74.271720654 55.2596756514 37.8163953596 +74.282003084 51.205461682 43.1298587031 +74.2870402008 22.8252954482 62.932039105 +74.2910071729 66.5873271311 6.85376675848 +74.2910228349 22.8123295662 62.932039105 +74.2928602405 37.6583171364 -55.3391549243 +74.2942036519 44.5522662784 -49.9546481641 +74.2990637837 50.398863753 44.0409315668 +74.3011338714 -63.302334084 -21.7291510406 +74.3130604624 46.4720305876 -48.1447756021 +74.322134535 33.2770367661 58.0418740413 +74.3441876324 3.59701873819 66.7832555471 +74.3456179176 -11.3499204252 65.9083333334 +74.3490544598 -65.7322342451 -12.3081876034 +74.3496367524 44.7974894191 -49.6519531995 +74.3558052266 33.1519984524 58.0702955711 +74.3638721465 -66.442280808 -7.44565916573 +74.3652694962 44.7715337713 -49.6519531995 +74.3661736066 61.193825068 26.9256011385 +74.3694075233 29.5951816937 59.9442778349 +74.373338918 -6.3106692039 66.5490940013 +74.3907337346 34.2945979865 57.3576436351 +74.3944232118 47.248571843 -47.2550764869 +74.4171835857 44.8027885953 -49.5458668432 +74.4208991991 -10.1017821825 66.02638684 +74.44958379 45.9810001097 -48.4046186062 +74.4530115761 -60.463180138 -28.301111548 +74.463045701 -6.21357468997 66.4578536706 +74.4631431862 -66.5309770271 -5.37302546452 +74.4750179731 -11.2632875034 65.7769720534 +74.4797294697 -10.0965293555 65.9608216527 +74.4838440076 45.1090193441 -49.1663844071 +74.5038052263 3.16171411977 66.6272209433 +74.5088721077 -66.5017109265 -5.09415558091 +74.5131964825 -3.21422791566 66.614204858 +74.5187363749 -7.50364218991 66.2620048216 +74.5334786442 42.4786708904 51.3840741921 +74.5405295423 10.9008619048 65.7638248986 +74.54438015 12.5012022053 65.4740813717 +74.5446440156 45.502245043 -48.7097705254 +74.5448830636 43.3861579852 50.6033764121 +74.5591489752 52.9472686003 -40.4662829014 +74.5649045217 -65.1158967965 -14.1419587774 +74.5807977655 22.2335014547 62.7963057649 +74.5827858921 -62.471557389 -23.1238527491 +74.6235057261 38.4830815081 -54.3174449951 +74.6256957964 47.8720679951 -46.2522500293 +74.6257837482 0.690326475484 66.5621202286 +74.6309157396 -63.6732726019 -19.3891921448 +74.6482148916 22.0834680952 62.7691361291 +74.6618450227 58.7108894879 31.2832279878 +74.6757326185 12.0547070843 65.4080957909 +74.6860963013 -1.36884744188 66.4839324646 +74.686569569 -1.34277699329 66.4839324646 +74.6868027903 -1.32974170745 66.4839324646 +74.6977739393 63.5053778494 -19.6801817247 +74.6985879378 2.63463901324 66.4317667789 +74.6998985499 45.6865369538 -48.2976759048 +74.7017683432 21.7452915904 62.8234677493 +74.7030028153 -11.3644575137 65.5004616457 +74.7069652081 -11.3383805547 65.5004616457 +74.7152221419 21.7775012928 62.7963057649 +74.7334955564 61.1251065577 -26.0504508643 +74.735814596 -1.17404399331 66.4317667789 +74.7521100058 0.821975505328 66.4187202975 +74.7703920595 35.8560659282 -55.8903480703 +74.7864197681 40.8934881604 -52.2944934419 +74.7927243657 53.5068521475 39.2818680211 +74.808327926 44.9849263951 48.7859659139 +74.8134701688 38.8956535404 -53.7593974759 +74.8164191595 37.3020905733 -54.8731032748 +74.8221529184 2.74360379772 66.2881442707 +74.826927376 21.9801958398 62.5923472184 +74.8682570276 44.7190367611 48.9382451749 +74.8790500296 -60.5277416772 -27.0096344686 +74.9362067977 2.78707598379 66.1573663187 +74.9454789714 2.52548282766 66.1573663187 +74.9579193774 43.9775500928 -49.4700455876 +74.9728089583 43.986285758 -49.4397065335 +74.9743944961 -64.1474205146 -16.2464953535 +74.9840463393 42.389386283 -50.7989441341 +74.9913194716 -11.515472424 65.1436558597 +74.9924230833 43.2619996271 -50.0453381281 +75.0029251499 60.8446207173 25.9324767181 +75.0135700157 21.6515544409 62.4833938242 +75.0271282505 56.9899791546 33.5122709234 +75.0338284036 58.0555145955 31.6145823974 +75.0462286614 -64.0502430145 -16.2981573648 +75.0520342455 60.6026247901 26.3536339841 +75.05203874 61.8241385052 23.3445363856 +75.0618979594 -60.9359181621 -25.5445757936 +75.062336811 34.7313742298 -56.2083377852 +75.0750040167 -10.3908082607 65.2363002904 +75.0801064115 -13.0765716741 -64.7455086819 +75.0867790257 57.0559586224 33.2654956558 +75.0901040329 44.1432317315 -49.1207834691 +75.0942662062 58.9873205978 -29.6874921752 +75.0974897159 -60.8778814037 -25.5783227395 +75.100407909 2.71443234408 65.9739387103 +75.1019457598 10.9294169258 65.1171681568 +75.1178729909 45.8521455039 -47.4856389871 +75.1300480852 -63.4448725871 -18.172066947 +75.1346569052 35.7247805458 -55.4844427448 +75.1381869997 57.3021580769 32.7217898979 +75.1391711067 43.8726088952 -49.2879209759 +75.1483456686 59.4125027304 28.6858965796 +75.156432407 47.2919012083 -45.9889850721 +75.1568006404 37.6849552034 -54.141476419 +75.1575363257 56.5735918192 33.9230517808 +75.1612550442 -7.43585232937 65.5400170912 +75.178054034 63.4854120435 -17.8287029629 +75.1804644645 -7.23905536633 65.5400170912 +75.190247568 10.7948961748 65.037657455 +75.1966898817 20.4727737902 62.6603811364 +75.2012953171 64.7290030795 12.4467402546 +75.2092474395 44.4786249457 -48.6335380423 +75.2101490068 44.4437300062 -48.6640354832 +75.2238550784 44.4872638793 -48.6030346756 +75.2238854196 64.7027489324 12.4467402546 +75.2473710505 45.6073355193 -47.5163560978 +75.2525707885 34.7396980184 -55.9482258102 +75.2832447943 1.53752409416 65.8032603517 +75.3102530642 -1.86684710511 65.7638248986 +75.3154606084 1.64338919662 65.7638248986 +75.3329986476 -5.42636844023 65.5400170912 +75.4059922972 40.8910058723 51.3990463377 +75.4065757741 11.6466034654 64.6390358665 +75.4306386369 40.7511725598 -51.4738835705 +75.4312930555 50.1733812476 -42.3409003465 +75.449153797 34.8943683016 -55.5860436814 +75.4626105008 62.7170415379 19.2864490548 +75.4629293605 48.5393872215 44.1505852792 +75.4711889622 -10.0029808039 64.8385688589 +75.4752679614 12.2919279369 64.4390598453 +75.4767808905 63.7151131346 15.6089687246 +75.4928281563 48.5213724598 44.1192623644 +75.5249357404 39.9040493437 -51.9966434242 +75.5260329109 65.4227019681 -3.96086100934 +75.5316082713 -1.71405197314 65.51364879 +75.5360054841 -5.30848866674 65.3156323064 +75.5389976667 -64.9050050837 -9.01111239461 +75.5489973488 39.9167624378 -51.951911188 +75.5558241945 20.0614944994 62.3606756598 +75.5563285179 -11.1841385216 64.5457687724 +75.5821041034 12.9466412713 64.1851230356 +75.587164779 63.6052219357 15.5227659645 +75.6017388576 -2.48154925717 65.4080957909 +75.6022234338 -11.2583617677 64.4790904261 +75.6039408562 46.5118547464 -46.0509662773 +75.608642061 -64.3025028834 -12.1869343405 +75.6151885578 -6.21670013804 65.1436558597 +75.6213177181 41.5731712205 -50.5280886365 +75.6380705683 42.5329413668 -49.6973961028 +75.6508157732 61.3264359189 -22.7161248969 +75.6522527938 53.6044368399 -37.4606593416 +75.6639496916 60.6616302975 24.3953546137 +75.6738107353 0.66039534151 65.3684805299 +75.7036841394 56.6954374875 32.4742909981 +75.7080309258 38.3756531805 -52.8734649546 +75.7092076526 21.067188757 61.8408395358 +75.7095944127 -4.93572842666 65.1436558597 +75.7141477693 -64.4833763945 -10.4528463268 +75.7149305654 -61.5318549691 -21.9335385547 +75.731186646 38.3707783756 -52.8438334722 +75.7315092725 -4.19427299226 65.170135625 +75.7352228036 36.5303349435 -54.1268016402 +75.7683088958 33.5758929102 -55.9626909856 +75.7959728159 48.4176473028 -43.7115766651 +75.7990421622 63.3778366408 15.419307054 +75.8043918625 21.8368221698 61.4560604976 +75.8072389665 21.2370902077 61.6623752364 +75.8218366915 -63.7349123195 -13.7444546037 +75.8357122722 43.5722510933 -48.4809620246 +75.8404157499 45.0844698463 47.0703932165 +75.8457001126 48.6920740825 43.3187222339 +75.8743483676 -11.8544727386 64.0511884034 +75.8773422964 36.3217703012 -54.0680860418 +75.8810822323 45.1444999597 46.9471562786 +75.8898254792 47.7533860288 -44.2758231039 +75.8922098487 -4.74813747436 64.944804833 +75.9083385715 42.9818571824 -48.8925770283 +75.9094475712 41.5592086131 -50.105767621 +75.9254119777 -4.57729538379 64.9182577014 +75.9288046708 12.6380182988 63.8364873308 +75.9332115455 12.6115133766 63.8364873308 +75.9369081356 -4.93723800043 64.8784221735 +75.9512229413 -4.71190725666 64.8784221735 +75.9591293014 39.0712138075 51.9966434242 +75.9640545849 33.6150611664 -55.6730641675 +75.9742262796 -4.88640251529 64.8385688589 +75.9872741164 17.7946727798 62.5242656336 +75.9959375374 45.3026709561 -46.6077834922 +76.0045460123 38.6427416751 -52.2498564716 +76.0099578754 47.091446106 44.7759087839 +76.0107310577 -5.02197800064 64.7854034566 +76.0120686002 63.7816987275 12.4121043561 +76.0181795539 39.7413438737 -51.3990463377 +76.0407673899 59.1535046955 26.8079200424 +76.0456166943 11.3243900074 63.9439001981 +76.0515093967 -64.6105543267 -6.4532308253 +76.0594306592 32.7878446949 -56.0349912828 +76.0667222989 -61.3781073571 -21.1324796455 +76.0751298848 12.9081210831 63.6078220278 +76.0912958676 39.9488234431 51.1293086077 +76.0913479247 -40.7998227824 50.4527623815 +76.1016117611 46.0343299957 45.7097927059 +76.1053905855 -62.2915404173 -18.10341173 +76.1061411512 -4.94824113048 64.678977951 +76.1260613004 57.1155214009 -30.7024429971 +76.1413296891 -9.99715846077 64.0511884034 +76.151366577 -61.6001694011 -20.159079796 +76.16760625 44.3662064351 -47.2243103147 +76.171844845 -0.837586934381 64.7854034566 +76.1764563884 49.1300188954 42.2301874901 +76.1958008938 -1.48964145551 64.7455086819 +76.199146036 42.4641737811 -48.8925770283 +76.2052120685 62.8634185389 -15.5227659645 +76.223085391 32.4804582226 -55.9916162217 +76.2276702883 -60.6776830055 -22.5291159947 +76.2329114167 43.6060085179 -47.8232081533 +76.239174354 63.2275782531 -13.7790290685 +76.2411520506 -4.95701921954 64.5191033296 +76.2726561269 35.0331289473 -54.3613999406 +76.2903610692 -12.6297873752 63.4055934345 +76.2904415412 12.4930389131 63.432582386 +76.32070587 63.6557458413 11.0948581284 +76.324161036 45.8964511246 45.4767876649 +76.3248322724 36.601496161 -53.243313734 +76.3411541078 11.7500274399 63.5135028529 +76.35073142 -11.3153471454 63.580883374 +76.3618330923 -64.3709991509 -5.02443181798 +76.3706246205 64.3100374478 -5.6344279679 +76.3711362371 49.5012962316 41.4375580993 +76.3829972001 12.0568843381 63.4055934345 +76.3851933338 -60.9338557017 -21.2689320059 +76.4032634456 44.0581212918 -47.1319772882 +76.4130873038 38.5990278669 -51.683219099 +76.4349087185 56.2909235899 31.4489530921 +76.4484836803 46.4814066465 -44.6666338461 +76.4653122111 -60.4537003456 -22.3250116011 +76.471001231 12.207605941 63.2705328563 +76.4729818445 -2.84423271761 64.3723029576 +76.4745333032 19.0955992321 61.5386370179 +76.4837968875 63.7691410596 -9.15016186634 +76.4901634789 64.3422791256 3.05385132098 +76.4972187588 -62.6791637393 -14.8154633781 +76.5134584893 45.6111753599 -45.4456967411 +76.5202703966 45.6152360716 -45.4301492025 +76.5358640824 12.8351769902 63.0675807431 +76.5410231098 5.66111584619 64.1047856925 +76.547268664 -5.41983730414 64.1181801339 +76.5475730356 37.2851439872 52.4431797303 +76.552709748 37.3372512871 52.398590597 +76.5555659517 18.1251874805 61.7310529686 +76.5615928606 17.8164407586 61.8134041883 +76.5828537621 18.1034194986 61.7035875141 +76.6042536284 4.14873807735 64.1449631569 +76.614172472 47.6881223569 -43.0826132274 +76.6153922554 38.8355856773 -51.2042864871 +76.6223672801 31.1910352379 -56.179463803 +76.6316822347 -12.1098470852 63.0946660302 +76.6364908424 44.2104375606 -46.6077834922 +76.6413090633 31.5579748043 -55.9482258102 +76.6435358585 44.2145017243 -46.5923410914 +76.6448709001 20.6086354602 60.8345946742 +76.6465326033 47.763963627 -42.9408059837 +76.6604517242 -0.0936584568047 64.2118865129 +76.6661264373 33.3353805152 -54.8731032748 +76.6729574912 43.1677367109 -47.5163560978 +76.717968853 44.150430263 -46.5305573002 +76.7194693292 61.5738839119 -17.9660748593 +76.7251182134 -8.51119708864 63.5674111417 +76.7513901126 63.4266111338 9.28919349936 +76.7533433875 -62.8218836406 -12.741083733 +76.7551930825 11.224735931 63.108205791 +76.7579376595 -9.99636228561 63.3110712854 +76.759622557 20.4671990783 60.7375839723 +76.763193588 20.4538016851 60.7375839723 +76.7686764598 42.4660369772 -47.9917286421 +76.7766098343 -8.44909093966 63.5135028529 +76.7806894906 -61.1178896094 -19.2179419046 +76.7814089043 -17.7263849858 61.5661475326 +76.8047812933 -11.3415433602 63.026938405 +76.8118886764 19.55055298 60.9730238396 +76.8198540512 3.64960762117 63.9170586601 +76.8247447425 49.4722234095 40.625825606 +76.8386063738 63.6116144336 -7.02787874735 +76.846843478 39.3583716068 -50.4527623815 +76.8547847871 38.0173866029 -51.4589192581 +76.8607119503 30.0904378933 -56.4534897583 +76.8684907338 62.1358864517 15.1778373678 +76.8704222072 -12.6293465251 62.7011785857 +76.8814270471 -12.218090064 62.7691361291 +76.9062634746 -62.9470472816 -11.0948581284 +76.9379379459 18.3717785406 61.1803192039 +76.938047201 62.749140138 -11.9617015862 +76.9395822657 35.112051561 -53.3614515916 +76.9657876733 3.62961440919 63.7423989749 +76.9693481643 21.0275555546 60.2790291109 +76.9696488443 35.1582408661 -53.2876276071 +76.9788250063 -12.3713536419 62.6195665085 +77.0004017418 -12.3748212633 62.5923472184 +77.0153470215 63.7805882567 -0.820295548752 +77.0163180958 62.8577551377 -10.8346373271 +77.0166894035 59.2038380936 -23.7346815507 +77.0170251142 17.0742634005 61.4560604976 +77.0194099543 3.67256112817 63.675134747 +77.02188259 61.816596214 15.6951595979 +77.0263188194 3.52468779863 63.675134747 +77.0284231172 -12.4069086155 62.5515039842 +77.0381325994 56.1771725234 30.1537959944 +77.0609265855 42.5399169327 47.4549160903 +77.0655391888 -63.0774129432 -9.06325801978 +77.0711927472 -0.605328178958 63.715499106 +77.0757984123 -12.2489797982 62.5242656336 +77.0998378752 31.4638610236 -55.3682259884 +77.1248896754 28.1016561329 -57.1143442153 +77.1284154118 28.1792081627 -57.0713567684 +77.1356337497 36.1822337748 52.3539870984 +77.1370874738 36.2650753717 52.2944934419 +77.1598622229 -0.632960211061 63.6078220278 +77.1665127631 53.8321049361 -33.8737920245 +77.1829594107 -0.511904277588 63.580883374 +77.1907090562 20.6110070679 60.13967761 +77.194109496 30.0191474073 -56.0349912828 +77.2040868507 -2.35879819123 63.5135028529 +77.2044625478 40.2757694778 -49.1663844071 +77.2052353934 47.4969777185 -42.2301874901 +77.2110129293 28.530585246 -56.7843745053 +77.2167184361 35.3525738876 52.7993741769 +77.2179020933 46.3971964518 -43.4130827946 +77.2656653767 17.9092196121 60.9038324474 +77.2709329878 -9.44661128663 62.7691361291 +77.2730851077 36.082301239 -52.2200905326 +77.2953993269 -9.2442843152 62.7691361291 +77.2979812936 20.1634314341 60.153621011 +77.3303862668 46.6486713776 -42.9408059837 +77.3326941709 62.7793707774 -8.85466075362 +77.3349748579 19.5974830353 60.2929541689 +77.3498591957 37.3923829241 -51.1743000114 +77.3518568331 39.4637693811 -49.5913414893 +77.355784372 20.1496725647 60.083885691 +77.3998869031 28.2171589258 -56.6837670727 +77.4083552664 41.0202163691 -48.2212441148 +77.4184304563 20.9325892132 59.7345238075 +77.4220827032 57.6666124882 26.084150629 +77.4279173398 46.4866088018 -42.9408059837 +77.4301060713 40.9971308213 -48.2059533482 +77.4304759671 34.3609791532 53.1398579518 +77.4314912563 46.3785092158 -43.0511096808 +77.4426879908 -10.7460609816 62.3470308046 +77.4857824643 -10.7520408339 62.2924323959 +77.4978691993 -62.7565370842 -7.46306389888 +77.5009822837 43.2605962244 -46.0664580728 +77.5091519935 -61.0375102525 -16.3325962242 +77.5110193737 -60.167057087 -19.2864490548 +77.5157682321 0.338228490933 63.1758757508 +77.5192040158 44.7196614983 -44.619781311 +77.5226482635 59.313430193 21.7291510406 +77.5342487314 62.8532433887 6.15711533009 +77.5385574323 41.8025960663 -47.3319667185 +77.5473903856 -0.581997560885 63.1352795449 +77.5492901647 31.3791899326 -54.7855275974 +77.5546923098 -5.31434666241 62.9049077599 +77.5702359249 36.0892164428 -51.7728399366 +77.5732693723 57.1919466796 26.6733783743 +77.5902042564 31.3799870541 -54.7271104292 +77.6185478607 41.7932820162 -47.2089250705 +77.6306936094 32.2827498967 54.141476419 +77.6476860414 34.4411499015 52.7697266042 +77.6649709597 55.0509388995 -30.6193796821 +77.6814694369 57.544232656 -25.5783227395 +77.6852139771 56.7529407317 27.2784025857 +77.6856381636 61.7496840121 12.3255080026 +77.6939359061 37.1080544272 -50.8590662521 +77.6971718797 45.0757175324 -43.9468903432 +77.7289492238 -2.51063081224 62.8641963719 +77.7777146397 45.869446722 42.9723278732 +77.7981168963 59.5241942715 20.1077921146 +77.8035005801 43.5363845864 -45.2901591366 +77.8110979276 43.5228046508 -45.2901591366 +77.8154968882 28.1688166314 -56.1361399958 +77.8346023451 1.87505130924 62.7555484428 +77.851946217 46.501203354 -42.1510682766 +77.8681734557 46.4740250657 -42.1510682766 +77.8713712348 60.1207320001 17.9317351584 +77.8843488761 27.1526872341 -56.5398954378 +77.9008582629 0.135962784737 62.7011785857 +77.9096036444 -12.1724573897 61.4973571877 +77.9117269523 -12.1588594133 61.4973571877 +77.9240518229 -61.1661743093 -13.6580111242 +77.9269051499 -6.98221014434 62.2787780488 +77.9498827719 44.0121674846 -44.5729165431 +77.9557379633 46.8961044814 -41.5169640396 +77.973046994 -17.029387421 -60.2511734868 +77.9748674439 -10.8476507741 61.6623752364 +77.9829287475 -62.2529541505 -6.57514437121 +78.0005915018 31.2769961111 54.200159037 +78.003683797 32.4378579909 -53.5089775931 +78.0195275779 -61.4394247899 -11.7537397458 +78.0206575263 32.3970109129 -53.5089775931 +78.0219799333 47.0101667364 -41.2627540369 +78.0310429943 50.6158839923 -36.7313029567 +78.0375781598 -10.7869646993 61.5936505456 +78.0470842561 62.2372893019 -5.9306373576 +78.0505028754 45.9202297286 -42.4199422745 +78.0507197296 46.9903552817 -41.2309551211 +78.0547802048 46.9556856672 -41.2627540369 +78.0580279407 -62.1569177917 -6.59255979514 +78.0739486034 46.6707897733 -41.5487175664 +78.0774210294 44.9509235489 -43.3973593378 +78.0831058861 -61.8435409571 -8.85466075362 +78.0967065856 -0.368024783717 62.4561364338 +78.1142970081 42.4126027838 -45.818421274 +78.1363767858 44.3876398678 -43.8684858384 +78.1364830189 28.2850119886 -55.62956155 +78.1484124534 55.9075175584 -27.6979261222 +78.1509334049 54.7828773532 -29.8541112219 +78.1865155604 29.8096284328 -54.7563223493 +78.2147108518 61.7259381564 -8.50691278224 +78.2251508458 47.2815824304 -40.5620233474 +78.2279420851 -0.204800741361 62.2924323959 +78.2699838918 27.1799288897 -55.9916162217 +78.289937987 -60.1391370158 -15.936430246 +78.2941899544 26.1968695029 -56.424674103 +78.3115931595 16.6027913257 59.9303069992 +78.3186220805 26.7381230041 -56.1361399958 +78.3293090703 -59.1755448411 -19.0466331231 +78.3324941197 38.7143299369 -48.6335380423 +78.3408523901 44.4134152466 -43.4759633927 +78.36583627 -59.1601841663 -18.9438199716 +78.3844781985 37.2699949289 -49.667102347 +78.389556408 55.1953631681 -28.435001862 +78.398165835 38.5426937848 -48.6640354832 +78.3988729076 -0.684176598809 62.0737354217 +78.4133599932 20.3228828451 58.6372356736 +78.4153576681 61.3309393075 -9.46295754202 +78.4207429287 56.1437376307 26.4209727938 +78.4386660506 13.5487102187 60.5293988043 +78.463721542 37.1231456809 -49.6519531995 +78.4701873871 28.6383869002 -54.9751988372 +78.4704413921 55.3958391383 -27.8152985584 +78.4735011483 20.2946273029 58.5665238866 +78.4805805286 20.2672336476 58.5665238866 +78.4876480163 45.8277331757 -41.7074091841 +78.4934284399 -1.61679173909 61.9368038909 +78.4956499421 -0.753527292168 61.950505541 +78.4997429508 33.5153694886 -52.1009631841 +78.5109419646 27.7559280647 -55.3682259884 +78.5199664071 -59.7079698999 -16.4186846569 +78.5292281941 15.378356994 59.9722140278 +78.5617441708 56.3899887617 -25.4601948206 +78.5626020206 26.0125229479 -56.1361399958 +78.5717419618 56.7720258229 24.5645771192 +78.5798661139 35.0188824599 -50.9792360946 +78.5862330502 43.8843681152 -43.5702445497 +78.5898774297 54.9270789803 -28.4015344704 +78.5920852223 34.9914507792 -50.9792360946 +78.6013013949 26.4522604236 -55.875874378 +78.6138088555 60.6501458732 -11.8923867576 +78.6286224357 46.6491444774 -40.514158678 +78.631633178 -60.9929467766 -9.84513622389 +78.6580776043 41.770427473 45.4767876649 +78.6586583131 27.0382877803 -55.5134800412 +78.6611843755 -8.72596691978 61.125081382 +78.6792581548 -6.67603174265 61.3596360516 +78.686576006 43.5628376245 -43.7115766651 +78.6928936866 14.3434908767 60.0141046146 +78.7034037988 39.8767139183 -47.0703932165 +78.705950996 55.253925513 -27.4294913043 +78.7120284068 26.3366762934 -55.774510898 +78.7155510375 55.56887314 -26.7574730274 +78.7313403038 42.5166164321 -44.6510176944 +78.7346380877 40.5510032532 -46.4378391008 +78.7355431464 -59.0518771328 -17.708474032 +78.7370892823 37.5894080151 48.8621241497 +78.7437552899 14.2391905474 59.9722140278 +78.7441459751 26.240491778 -55.774510898 +78.7461405001 48.4828479889 38.0586232965 +78.7515213453 60.7125508352 10.5916975449 +78.7539839157 51.7710592981 33.4300379384 +78.7693175645 14.2154199826 59.9442778349 +78.7726552545 -61.0362998616 -8.33299966141 +78.7731292754 42.7169299633 -44.3853354011 +78.7775959415 40.5383414193 -46.37599867 +78.7828299064 -11.0021043154 60.5988400266 +78.7829753494 30.0527865284 53.7593974759 +78.7846462704 -1.60903388559 61.5661475326 +78.7991530052 55.2372716043 -27.1944353017 +78.8086405033 13.7543095941 60.0001429133 +78.8157148569 52.1076572835 -32.7547728433 +78.8246267869 50.3135848043 35.4291037998 +78.8366023102 -1.69268872252 61.4973571877 +78.8448394841 61.3790328941 4.01317925326 +78.8582462646 48.6658270851 -37.5900820721 +78.8631258046 -5.23808303645 61.2631200187 +78.8638460521 26.188655323 -55.62956155 +78.8855948763 13.7393669876 59.9023598516 +78.8899327453 42.7446409617 -44.1505852792 +78.8911706877 -12.4245710833 60.1815023152 +78.8932827132 42.6574388328 -44.2288690219 +78.8957278599 55.1818424698 -27.0264386684 +78.8969433378 44.3292353014 -42.5463421407 +78.9005348632 61.0252686655 -7.11492674688 +78.9007733508 39.6312059115 -46.9471562786 +78.906335014 37.3325571654 48.7859659139 +78.9208708994 61.283515412 -3.97830054534 +78.953442329 48.0422015838 -38.1877049766 +78.9550263952 43.7654857886 43.0196008887 +78.955884554 13.8226121496 59.7904983058 +78.9608660861 46.1964830699 -40.3864652935 +78.9616035937 42.0376769642 -44.6978620671 +78.9617864099 31.1357188876 -52.8734649546 +78.9762557526 51.0529344242 -34.0051307008 +78.9812024817 42.5269959343 -44.1975595633 +78.9825062235 -60.1032169947 -12.221579994 +78.9838673816 36.0449789604 49.6216503675 +78.9859368748 12.1570984417 60.1117853128 +78.9888672426 -9.58668050683 60.5710690725 +78.9995521782 -8.16380956574 60.7653105729 +79.0045445648 26.7723039838 -55.1500288078 +79.0064348864 41.9200693673 -44.7290848419 +79.0068904159 14.0732706534 59.6645147464 +79.0070985955 53.2307932513 30.4033060925 +79.0152627888 29.8101094838 -53.5532036295 +79.0291867162 -1.10352732441 61.2631200187 +79.0311486876 14.9759528336 59.4121062902 +79.0365395242 -59.7098371505 -13.7098784642 +79.0378904901 -8.30721703697 60.6959801962 +79.0410428563 15.0349977989 59.3840246647 +79.0459149352 50.5908575707 -34.5298198999 +79.0713240894 -11.0705335888 60.2093762865 +79.078659305 42.3127969718 -44.2288690219 +79.0809548431 -11.0015266347 60.2093762865 +79.0811655907 56.2000591241 24.2429908069 +79.0873942179 42.4596193665 -44.0722679139 +79.0878812651 55.8937883749 -24.9197002009 +79.0894953174 -58.9514929801 -16.4186846569 +79.0995103541 45.9446515778 -40.4024312775 +79.1003661525 11.7510682378 60.0420225326 +79.1012744452 53.2139908724 30.1870759858 +79.1188969533 42.868699793 -43.6173672171 +79.1197496555 12.7862623114 59.8044873781 +79.1355030668 27.9145921745 -54.3906949587 +79.1461730558 -60.4461797361 -9.06325801978 +79.1756117855 61.0835739204 0.139626294791 +79.1891628237 42.1056247587 -44.2288690219 +79.2001557309 45.8553373545 -40.3066169295 +79.2033167967 14.0369595914 59.4121062902 +79.2088116741 -9.34694540364 60.3207987745 +79.2381873941 -1.38310770576 60.9868565477 +79.2407439886 59.1072693689 -15.0743225348 +79.24877896 60.9857186696 0.610861439068 +79.2500546626 42.5291300337 -43.7115766651 +79.2572003797 42.141800969 -44.0722679139 +79.2615509404 42.4106572125 -43.805738178 +79.2763502233 42.3829871286 -43.805738178 +79.2820912984 48.2990807162 37.1691915613 +79.2854868798 38.8930494182 -46.9163327338 +79.2974054698 10.8905941351 59.9442778349 +79.3016155971 -7.80353996576 60.4181969914 +79.3104575809 42.5615449459 -43.5702445497 +79.3225993212 -7.80560483327 60.3903781253 +79.3256451982 59.4079695013 13.3467289485 +79.330999289 46.7295297789 -39.0249099737 +79.33524074 25.9001054855 -55.0917789925 +79.354271825 42.4959066459 -43.5545343388 +79.3654769555 42.5553953654 -43.4759633927 +79.3698154071 46.5287599348 -39.1855445435 +79.3797316239 60.5368603002 -5.84352225182 +79.3854054021 60.8045712502 -0.872653549837 +79.4016487321 -58.7970327485 -15.436551383 +79.4070616903 42.542012129 -43.4130827946 +79.4100835806 9.60967601048 60.0141046146 +79.4295967323 58.6676104636 15.7813385186 +79.430676197 42.6260596416 -43.287258152 +79.4449951634 46.3867134831 -39.2016014434 +79.4508980518 17.7593798045 58.0702955711 +79.4575562047 42.1238923538 -43.7272735822 +79.4599304034 12.3010471386 59.454215154 +79.4660051418 29.3480752975 53.1398579518 +79.493431794 56.1388055253 -23.0049737188 +79.5007637568 -5.25256211939 60.4321036641 +79.5219685798 48.8839854024 -35.8693808751 +79.5266850965 26.0240565697 -54.7563223493 +79.5294030392 40.6447198387 -44.9786705168 +79.5318283084 55.523454374 -24.3276447751 +79.5499974162 40.7077903235 -44.8851168881 +79.5651180935 51.3745459932 -32.0943609807 +79.5668433422 -5.04774886203 60.3625519008 +79.5677231287 -5.0338617513 60.3625519008 +79.568381788 36.7152093081 -48.1753674102 +79.5959879544 -59.5887516181 -10.6611154275 +79.5961752653 44.978348455 -40.514158678 +79.6310386185 8.20097503467 59.9303069992 +79.6426273479 44.9679272001 -40.4343595529 +79.6478651237 60.171676095 -5.96548213902 +79.6518433245 8.2031176524 59.9023598516 +79.6570998929 10.7983776683 59.4822786751 +79.6761541178 -8.47273205761 59.8324600571 +79.6784508412 44.9331505508 -40.4024312775 +79.6808659845 25.9206365181 -54.5809508754 +79.7121488527 26.1617800909 -54.4199833495 +79.7130770281 15.1340005403 58.4532922799 +79.726510528 39.9588770754 -45.2434709312 +79.7306325533 6.16293459666 60.0420225326 +79.7343278734 10.4547539292 59.4401806766 +79.7374626113 -8.87353681237 59.6925238263 +79.7513591149 13.1598534562 58.8773214093 +79.7575906165 5.50725632697 60.0699331346 +79.7728898388 44.2552438544 -40.960461889 +79.7758228883 44.2204607141 -40.9923033842 +79.7832811799 5.43907844875 60.0420225326 +79.792682926 45.8272505487 -39.1534271632 +79.7974049916 -59.2195764059 -11.1989252568 +79.7981163427 50.7391614023 -32.5238086383 +79.8034352317 46.3907862355 -38.46175604 +79.8081701257 7.12268942907 59.8324600571 +79.8131853935 15.1530067073 58.3115925445 +79.8319695181 60.2232655759 -0.122173017247 +79.8348269761 11.1774292864 59.1731820696 +79.8387998541 12.2170531499 58.9619339082 +79.84064464 43.0436975884 -42.1035813367 +79.8430833056 7.08366858341 59.7904983058 +79.8457935932 59.3419747445 10.1577201628 +79.8472458583 54.5702632428 -25.4264369988 +79.8595999226 51.3674207568 -31.3661024833 +79.8688235089 45.5563726243 -39.3139662794 +79.8708645236 38.3019923425 -46.4069217127 +79.8723386827 -8.78976884432 59.5243603663 +79.892008858 60.1373876754 -0.872653549837 +79.8967542609 15.6316803593 58.0702955711 +79.9183053712 -6.1774411328 59.7904983058 +79.9215491623 57.176022811 -18.532360751 +79.9218829387 4.56628191326 59.9303069992 +79.9262866122 60.0539923189 -2.30363081876 +79.9303166613 -59.426451827 -8.92419753652 +79.9359879432 52.7681452001 28.736051985 +79.946139244 4.11984501587 59.9303069992 +79.9464590127 -8.68496473599 59.4401806766 +79.9518048987 -3.32301640775 59.9722140278 +79.9606654609 5.45117129585 59.8044873781 +79.9637797505 -6.26520120649 59.7205256328 +79.9719819673 45.3750389048 -39.3139662794 +79.9739469668 55.1291390505 -23.7685892326 +79.9773447232 5.6626997146 59.7625146976 +79.9783207269 48.9531942123 -34.7426681491 +79.9799511565 14.2465991706 58.3115925445 +79.9802409484 59.9854039585 -2.21638664806 +79.9833533777 25.7568606666 -54.2148255651 +79.9872716409 4.33195578367 59.8604254456 +79.9890237193 -2.90510572706 59.9442778349 +79.9911858453 40.4415085733 -44.3384096623 +79.9967525772 -6.50665309292 59.6505074801 +79.9974864749 53.210600338 -27.7314653302 +80.0006715373 35.2011379548 -48.5877807712 +80.0095118372 -57.6622345589 -16.5391874421 +80.0115544562 53.1193010161 -27.8655883317 +80.0170163121 10.989424476 58.9619339082 +80.0309788138 59.9144032362 -2.30363081876 +80.0424315562 9.40282467391 59.2013178799 +80.0545082602 -57.5249998032 -16.7973243363 +80.057800537 41.3209120867 -43.3973593378 +80.0716753075 54.55978071 -24.7337247968 +80.0718047672 4.50474714204 59.7345238075 +80.076004846 9.2934370207 59.1731820696 +80.0842546782 27.3877410401 -53.2580866475 +80.0888342968 -58.1238984074 -14.4010782552 +80.104757743 59.8170597396 -2.26873335728 +80.1129514391 32.0753374178 -50.5280886365 +80.1170152573 12.431407135 58.5382266806 +80.1254130282 59.5497899431 -5.80867495977 +80.1291955628 33.6009603364 -49.5003786139 +80.1399183104 41.3101710099 -43.2557887958 +80.1409196286 33.5729879241 -49.5003786139 +80.1553080467 41.2473014102 -43.287258152 +80.1713176985 46.2869318545 -37.8163953596 +80.1729026408 15.1053543338 57.8284873795 +80.1948354352 48.3384456828 -35.1024648492 +80.1972704397 39.1494816675 -45.1189084442 +80.2233424456 46.1304679021 -37.897166886 +80.2236440383 3.05383724907 59.6224874966 +80.2296123998 9.31126436024 58.9619339082 +80.2583754833 8.39301009992 59.060566762 +80.2641194396 28.8493965802 -52.2052051767 +80.2828261649 8.93422727594 58.9478363128 +80.2883409818 3.95484841737 59.4822786751 +80.2940980596 50.4269975509 -31.7801153992 +80.3255567032 5.4478785325 59.3137889518 +80.3640296129 1.86581563551 59.4822786751 +80.3732572192 -58.1377893902 -12.6545236492 +80.3780301642 7.38570342578 59.0323949356 +80.3821742895 -58.1442395302 -12.5679539283 +80.395780886 -7.52885916726 58.9901237104 +80.4058114893 8.16732449327 58.8914279787 +80.4099738678 10.0440967728 58.5948139565 +80.4115635344 -23.5901789334 54.5663257682 +80.4122908478 41.2730939437 -42.78311813 +80.4192883322 4.96092070166 59.2294464767 +80.4289888104 12.2786338784 58.141318432 +80.4292853869 41.3705348472 -42.6568739901 +80.431300718 57.9022511755 -13.3467289485 +80.4653647398 53.5015562441 -25.747010637 +80.4755437043 26.6614951541 -53.0363228518 +80.4790722591 34.4601263588 48.3282383255 +80.4940368819 42.8535157087 -41.0400562604 +80.5036971048 37.1467915126 -46.2522500293 +80.5155879853 -7.89462242655 58.7785252292 +80.5219980609 3.83957706526 59.1731820696 +80.5225982544 49.209092958 -33.0843821252 +80.5301431263 50.0281489982 31.8132103987 +80.531793634 3.1359488802 59.2013178799 +80.5349068842 39.5931744316 -44.1192623644 +80.5471615148 54.883770724 -22.3590358248 +80.5498763854 6.72149075394 58.8773214093 +80.5592118194 57.5259928285 14.1765136802 +80.5700965207 59.1413308258 -3.28063024361 +80.5721919965 -24.2801531745 54.0240320478 +80.5763398246 39.5960832306 -44.0409315668 +80.5799870049 -24.4820719237 53.9211818177 +80.590243017 -24.2855927875 53.9946544894 +80.6205811051 44.8728397951 -38.5583992277 +80.6210560957 48.1933913636 -34.3167938899 +80.6229256536 43.556289791 -40.0349032557 +80.6525896043 27.3778650295 -52.398590597 +80.6536757691 1.87254036459 59.088731392 +80.65523003 -7.51055666187 58.6372356736 +80.6559186857 53.9536693302 -24.1583183765 +80.6641714456 8.93390883235 58.4249665637 +80.6670029656 58.1146943376 -10.7478804698 +80.6755432393 11.5105630132 57.9565670322 +80.6922368795 53.7540112195 -24.4799751878 +80.6953373083 29.6421406892 51.0843031866 +80.708617453 -8.22654671191 58.4674524674 +80.7105108841 27.0053591764 -52.5026095407 +80.7205738867 50.8718176451 -29.9373866742 +80.7216632847 41.8778904834 -41.596338363 +80.7224730621 35.0154001251 -47.5163560978 +80.7349427425 53.9861375246 -23.819445324 +80.7404890541 49.6136231091 -31.9290123445 +80.7418192232 30.1560093161 -50.7087145436 +80.7419586212 54.728093399 22.0356962886 +80.7477738264 -8.34447069889 58.3966337286 +80.7560244027 12.6749379546 57.6004381105 +80.7707166145 15.2325863521 56.9566471151 +80.7773272677 54.3824930598 22.75011754 +80.7874325858 53.4314901197 24.8689887165 +80.7928552983 55.2786083909 20.4154350213 +80.7965010913 13.4917058977 57.3576436351 +80.796892497 53.7423279738 -24.1583183765 +80.7980912557 58.9189815339 -0.471237153937 +80.8035985186 54.4001799054 22.6141303767 +80.8194478998 48.1398317306 -33.9230517808 +80.8209532014 10.0381335976 58.027660624 +80.8219767359 -57.5009037226 -12.7064608601 +80.849292701 5.32748622553 58.6089563144 +80.8602492542 -4.28016187749 58.6796413149 +80.8685537012 54.710968453 -21.6098809163 +80.8771624883 12.015027256 57.5719003324 +80.9225443024 55.2016170044 -20.1077921146 +80.954972716 53.8270974103 23.4293827692 +80.9787344515 -7.55493740079 58.1839108989 +80.9834269536 34.4922527202 -47.4549160903 +80.9875365665 52.1329092003 -26.8919820615 +80.988463299 6.37393029473 58.3115925445 +80.9910457918 34.4954977161 -47.4395524734 +81.0188094076 43.4783230767 -39.3139662794 +81.0244496588 0.169697458665 58.6089563144 +81.0300814328 37.1498006693 -45.3212777096 +81.0320116715 -0.678868075461 58.5948139565 +81.0337048014 49.5991745367 -31.2003296688 +81.0553032612 44.3764823117 38.2199637738 +81.0599751283 58.5268423601 -1.97209420269 +81.0846000343 42.570366739 -40.1628125633 +81.0850577628 -0.382107161114 58.5240754026 +81.0966519613 -57.6750061413 -9.84513622389 +81.0994549553 42.5420602811 -40.1628125633 +81.1005295717 -57.8057432839 -9.01111239461 +81.1048360765 38.9459875481 -43.6487756861 +81.1063028384 0.113245835885 58.4957674987 +81.1215086994 -3.75464683076 58.3541211356 +81.1238669308 55.8174518313 17.4163797974 +81.1254272148 38.9558752719 -43.6016609893 +81.1290901825 -1.1328494135 58.4532922799 +81.1339337785 48.519200343 -32.6063182175 +81.1557259514 46.9875741708 -34.7263015429 +81.1631308749 9.03219146986 57.7145190037 +81.1692580641 58.1543477739 5.4427364735 +81.1731608604 -56.6693157858 -14.1246806796 +81.1740473056 0.779238850887 58.3966337286 +81.1774384769 51.7755070299 27.0096344686 +81.1815680497 -1.02021137351 58.3824646426 +81.1871150573 51.8215558381 26.8919820615 +81.1872498233 -56.6791516955 -14.0037219771 +81.2269789748 48.0375014548 -33.0843821252 +81.2283163249 0.255187121362 58.3257705184 +81.2286303793 -57.4067202684 -10.3139747302 +81.230740288 7.57844836737 57.8284873795 +81.2346966189 54.8347617216 -19.8512712986 +81.2524193888 -56.5771237595 -14.0382837472 +81.2548458366 38.8088105798 -43.4916802325 +81.2672613998 -8.72800465037 57.6147043678 +81.2729306532 53.7322033378 -22.5291159947 +81.2751284616 -0.851142267941 58.2548628905 +81.300482178 -57.3511813426 -10.0535365033 +81.3089615263 0.425736617614 58.2122970157 +81.3133128716 32.1449786058 48.5267503577 +81.3315165012 45.7718650318 -35.9182515599 +81.3564971501 40.5983175934 -41.628079226 +81.3573640718 -0.752597019066 58.141318432 +81.3643969436 5.97502781581 57.8284873795 +81.3776533953 -0.752784705634 58.1129145979 +81.4017765688 47.9110449803 32.837212737 +81.4095457695 35.2796759646 -46.1284112175 +81.416006649 -56.7332407924 -12.360147674 +81.4267499694 35.3208979223 -46.0664580728 +81.4284635451 -0.739041584098 58.0418740413 +81.4469602106 49.1901300245 -30.7688768178 +81.458864717 45.1162219703 -36.4551762325 +81.4618048662 56.1967349789 14.3492621991 +81.4743034855 41.3700394655 -40.625825606 +81.4891738749 54.1822886586 -20.586260877 +81.495155364 -7.56007698589 57.4576791052 +81.5161536092 12.6485053187 56.5254987944 +81.5186463799 21.9191192668 53.6121488374 +81.5233060337 34.6045903455 -46.4378391008 +81.525745936 -4.20124650465 57.7572703422 +81.5327854667 0.184992339562 57.8996603779 +81.5364573891 2.09238619653 57.8569618666 +81.5382223251 34.6109219355 -46.4069217127 +81.5501518502 -5.48803915987 57.6147043678 +81.5540960416 38.7596240435 -42.9723278732 +81.5615996719 57.8557554917 -0.645767334904 +81.5635750486 50.1390079151 -28.8697611798 +81.5678587266 15.5156426598 55.7310439129 +81.5825673153 49.0585191188 -30.6193796821 +81.5911054947 -1.92280096942 57.7857624384 +81.6030422437 -28.7369675107 50.1510737159 +81.6076154701 20.8015203453 53.9211818177 +81.6304325102 57.7547993007 0.92501131168 +81.6466468851 54.5133306495 -19.0294990453 +81.6586015042 -4.16522418265 57.5719003324 +81.6682976203 -45.8676036535 -35.0207381259 +81.677656551 3.30907083976 57.6004381105 +81.6823061195 57.6846035529 0.698126029796 +81.6940836099 0.213875099385 57.6717518425 +81.7046279518 8.19841496036 57.0713567684 +81.7097057037 -0.884218617903 57.643231617 +81.7167687127 19.2869095596 54.3174449951 +81.7201336688 19.2726469993 54.3174449951 +81.7313699032 39.7218832695 -41.7391322773 +81.7341357005 14.5590670293 55.7455346062 +81.7386330187 -8.05775497227 57.0426897773 +81.739125993 49.0555899578 -30.2037146025 +81.7404722696 -0.82747968153 57.6004381105 +81.7619042662 53.5034909338 -21.2689320059 +81.7714002752 -2.66977494584 57.5005252043 +81.771971107 54.907061261 -17.2788704766 +81.7834937322 46.9326740724 -33.298412235 +81.8098150078 39.7600080102 -41.5487175664 +81.8214298253 -4.31671947211 57.3290463408 +81.868225663 -2.10090002432 57.3862339406 +81.8931711271 52.3124716107 -23.5990219443 +81.8941475549 28.1664445086 -50.0 +81.9022243261 57.3485548693 1.78014180529 +81.9062597138 56.756892137 -8.36778433323 +81.9186216237 52.3488629708 -23.4293827692 +81.9573288902 31.9044014711 -47.5931235364 +81.9652963035 52.5602002598 22.7841074111 +81.9653260986 43.2702762456 -37.5415571225 +81.9719862233 19.1509018827 53.9799632428 +81.972876938 43.2559699385 -37.5415571225 +81.9800130352 24.4081469668 51.8027009373 +81.9882356558 51.8909161448 24.19218956 +82.0230303162 -1.90433273658 57.1716364519 +82.0448526673 0.214793412728 57.1716364519 +82.0553804506 -2.55002351067 57.1000168056 +82.0586648477 47.0525158285 -32.4412742909 +82.0623547461 -9.49493839964 56.3526048938 +82.0656641053 -9.46629265611 56.3526048938 +82.0868266699 49.0307102796 -29.2872384621 +82.0882440333 -2.76617687289 57.0426897773 +82.1036615453 4.80595814175 56.8848971802 +82.1141814952 41.4788577669 -39.2016014434 +82.1212969442 17.5752996421 54.2881334243 +82.1274031843 44.4987876154 -35.7064076459 +82.1292219637 57.0387897344 -1.16934394852 +82.1338568015 57.0420086318 0.488690245402 +82.1393373983 15.1939713238 54.9751988372 +82.1539000902 11.692231434 55.8034803938 +82.1645686503 56.9995894442 -0.17453283659 +82.1779418139 12.9716033137 55.4844427448 +82.1838645538 56.8007642556 4.41424817878 +82.2086140122 56.9239430941 -1.18679602985 +82.2181202578 -8.71402077476 56.2516359159 +82.2538314966 56.7007517573 4.39681183179 +82.2772100065 -9.76727323404 55.9916162217 +82.3123929996 47.2934999674 -31.4323848843 +82.313800684 53.0069673616 20.364175114 +82.3801158958 48.9137333664 -28.6524552728 +82.380633129 44.7290342972 -34.8244852958 +82.3918586831 -0.402645784375 56.669387672 +82.4022689875 28.9860927274 -48.6792819803 +82.4063439638 54.481540097 -15.5227659645 +82.4088226973 44.9680730087 -34.447907796 +82.414146053 54.0742250994 -16.8489379565 +82.4366609541 4.86876330588 56.3958515726 +82.4772204469 45.0053956508 -34.2348137086 +82.4832796947 -10.7127076181 55.5134800412 +82.4861083782 48.0080614873 -29.8541112219 +82.4870071134 -5.7680534342 56.2372049186 +82.4880524578 -6.0285956196 56.2083377852 +82.5204208133 -7.10351326623 56.0349912828 +82.5249262558 35.9342501849 -43.5702445497 +82.5265365304 25.672555409 -50.301994663 +82.530508173 -4.9465824052 56.2516359159 +82.5507053986 15.2253672646 54.3467499475 +82.5741549422 -10.4608267823 55.4263478737 +82.5756326268 -11.1206397945 55.2955356864 +82.5823310713 -7.18144879019 55.9337589306 +82.5966937238 -10.8154035892 55.3246168635 +82.6034043477 51.4761185761 -22.954015041 +82.6247263161 37.9507262268 -41.628079226 +82.6343039323 -8.00044905572 55.7455346062 +82.6587993353 -7.20263455378 55.8179625922 +82.6714749935 33.4853947792 -45.2123385691 +82.6831638952 26.7059342722 -49.5003786139 +82.6869293251 43.044090918 -36.1949990445 +82.7062441474 18.4112696655 53.1102845816 +82.7246303594 -12.3928016988 54.8001277184 +82.7316497763 56.1610687262 1.18679602985 +82.7570151938 0.101106817903 56.1361399958 +82.7767972557 45.6952470628 -32.5568154457 +82.7838266066 -11.0163106718 55.0043539327 +82.7859773645 20.6715592434 52.1456478554 +82.8054273718 9.84463509816 55.1936985312 +82.8343625296 50.324486561 -24.6153293029 +82.853854399 53.9499512709 14.9880475413 +82.8670484129 43.6908382467 -34.9880399656 +82.8804342071 23.3278590019 50.8590662521 +82.9067618508 53.0822709733 -17.5710371841 +83.0188929262 4.24913699008 55.5860436814 +83.0323388322 34.308260063 -43.915532554 +83.0359142106 25.52931948 -49.5307056088 +83.0404576909 48.7780113351 -26.9256011385 +83.0449160604 48.7611370838 -26.942409447 +83.0493338727 -7.51423886692 55.1936985312 +83.0699711651 55.6104986887 -2.61769483079 +83.076231881 53.9915740097 13.5369727936 +83.0868578448 35.6969312704 -42.6884428311 +83.0898101221 55.1420494129 7.44565916573 +83.1191914038 15.2552263169 53.464736887 +83.1330861103 45.9487385823 -31.2666502279 +83.15417502 54.2695879811 11.8403968307 +83.1580961212 27.1802554531 -48.4351604003 +83.1730477563 -19.9680820943 51.8027009373 +83.2087664511 47.3075845387 -28.9533008618 +83.2117769066 1.4524669687 55.4408741251 +83.2352829064 55.3432794882 3.00151544833 +83.2739195495 8.94351728559 54.6394346734 +83.3633512243 54.8636845792 -6.36614381316 +83.3697117243 -10.1922059083 54.2734751581 +83.3701691711 16.1753200559 52.7993741769 +83.4501793063 -13.5608241962 53.4057264801 +83.4940072642 51.0249849604 -20.6204185397 +83.5111891064 25.3248841333 -48.8316653174 +83.5161641585 -18.0568338357 51.951911188 +83.5582584781 37.4999950327 -40.1468281767 +83.6028106458 -26.7614706762 47.8998302645 +83.608325348 -0.437776168455 54.8585115048 +83.6087537535 26.5222589692 -48.0223497443 +83.6929584423 54.7254225163 0.785390088871 +83.6982248643 54.001871611 -8.85466075362 +83.7106278279 54.3623173427 -6.10485395349 +83.7601948399 36.0728389112 41.0241398845 +83.7820426603 31.5249811816 -44.5729165431 +83.7960386303 4.80230219456 54.3613999406 +83.8038280507 4.83209832238 54.3467499475 +83.8050665799 -9.22255658679 53.7741133403 +83.8398173285 50.475675518 20.5691811048 +83.8572042781 20.2562105177 50.5732659231 +83.8650315014 54.2962576696 -4.30962809844 +83.8832774593 -6.9406807494 53.9946544894 +83.8939078386 -11.6113947912 53.1694248471 +83.8972548047 54.2755682135 3.92598157591 +83.9032492031 -19.9885734574 50.6033764121 +83.9344700377 -9.4147592914 53.5384632481 +83.9471769884 51.7456861629 16.5908239462 +83.9487503424 46.3039737502 -28.435001862 +83.9541504667 40.2240891821 -36.5201761892 +83.9785760532 32.455163926 43.5231099372 +83.9970346711 24.0064536521 48.6640354832 +84.0069173351 -14.4803171971 52.2796160442 +84.0118639008 13.5618141988 52.5174629961 +84.0228014596 53.672856424 7.70670605126 +84.0804021669 -0.880520099375 54.1268016402 +84.1165283654 48.9963049359 -22.8860603507 +84.1286365852 49.0230247516 22.7841074111 +84.1663455275 51.0733922345 -17.5366726092 +84.1702171188 -27.1537969664 46.669538893 +84.1759864768 9.51623862245 53.1398579518 +84.1936891657 24.987266089 -47.8232081533 +84.2123494772 -19.4419527942 50.301994663 +84.2167249646 -25.346357298 47.5931235364 +84.2183388514 41.0396436334 -34.9716892865 +84.2235823335 -53.4911598069 -6.71446210994 +84.2246355468 -2.86760181705 53.832960413 +84.2251142937 53.9056416084 0.558502457083 +84.2358553979 39.8540863222 -36.2763348316 +84.2415042487 50.8779030763 -17.7428278601 +84.2471643786 5.59569048397 53.5826794979 +84.301187128 -21.6448659817 49.2423560103 +84.3134628007 -26.1316311213 46.9933808689 +84.3194640891 -11.8953527804 52.4283182828 +84.3228112718 51.936620771 -13.8654578758 +84.3646822682 -24.7019297977 47.6698547309 +84.3859685657 53.6563201663 0.0872664515235 +84.400883852 53.4178977201 4.79781285213 +84.4017173637 51.3775973779 -15.3848169873 +84.410768408 -24.6034953178 47.6391666061 +84.4219062649 -25.0069079061 47.4088209047 +84.4318916924 43.0201975663 -31.9455515932 +84.4582131426 -24.8253719789 47.4395524734 +84.4644659034 -27.607242915 45.8649554484 +84.4928343676 7.98692438296 52.8882782801 +84.5423500946 -21.3925033526 48.9382451749 +84.5802450015 -6.53779484021 52.9475154669 +84.588757121 -25.1687845081 47.0241901057 +84.6087230368 -16.7529782957 50.6033764121 +84.6187985981 9.11783500824 52.5026095407 +84.6193567502 -6.51110464927 52.8882782801 +84.6409522261 47.0718589106 24.9027971312 +84.6428553628 47.7522052411 -23.5650998436 +84.6698813034 43.7575429826 -30.2702598633 +84.7199419556 52.0181970728 10.7999355706 +84.73809457 51.9886210657 10.7999355706 +84.7607682354 34.0392467606 -40.7055505812 +84.7896008013 -21.4550673996 48.4809620246 +84.7989846945 45.9463207604 -26.4209727938 +84.8119520786 19.4712725194 49.2727341548 +84.8543088454 45.7466648157 -26.5892634084 +84.8647386022 45.5994689112 -26.8079200424 +84.8652100947 52.2094255967 8.48952262753 +84.9157540325 -20.2297861321 48.7859659139 +84.9272524179 -20.5460646895 48.6335380423 +84.9479781655 52.7110386523 -2.32107944451 +84.9675169146 -23.0851634128 47.4088209047 +84.9735670856 39.7683633653 -34.6117057077 +85.0181259035 -23.7694807902 46.977974103 +85.026199509 52.5542608988 2.93173300722 +85.0329926208 27.8259229284 -44.6666338461 +85.0343827195 45.0613989403 -27.1776393577 +85.0507135505 -20.5759330809 48.4046186062 +85.0684386835 -14.3424375135 50.5732659231 +85.0874362468 -22.9583522745 47.2550764869 +85.1207457036 46.2167940372 -24.8689887165 +85.1223485148 52.32666792 4.01317925326 +85.1258229123 46.1618555574 -24.9535040626 +85.1273765147 -22.8098117909 47.2550764869 +85.1440325922 -13.2114274461 50.7538362961 +85.1445925265 -24.575723833 46.329603512 +85.1541275119 -14.0971743943 50.4979627488 +85.1583176156 -10.3052887616 51.3990463377 +85.1669346103 -22.9798025792 47.1011881219 +85.1873555518 44.5348732441 -27.5637355817 +85.1879902447 -23.4326926192 46.8392488698 +85.1982809688 -3.34744957613 52.2498564716 +85.2046009393 -22.1941361447 47.4088209047 +85.206912195 -22.8311233122 47.1011881219 +85.2311425673 43.5586811769 -28.9533008618 +85.2502484862 48.6653306355 19.0808995377 +85.3027283164 14.2747811182 50.1963660617 +85.3081494937 48.3240113944 -19.6801817247 +85.3514070467 -42.554641775 30.0705799504 +85.3596612283 -21.0769551895 47.6391666061 +85.4864541924 41.0132955859 -31.7801153992 +85.507297209 46.7169386359 -22.4951054344 +85.5405813766 41.4440646954 -31.0676429631 +85.615597434 41.0752538224 -31.3495294931 +85.6273024213 49.0987759795 16.0398029092 +85.6306756088 -14.6832697148 49.5155428655 +85.6670384015 51.3112877658 5.32074048737 +85.6979154238 41.4649021966 -30.6027642189 +85.7751480297 -15.4024765255 49.0447519859 +85.7884508277 46.4437096807 21.9846204353 +85.7939654933 50.8799892131 7.11492674688 +85.8693096227 -8.828291182 50.4828974973 +85.8982382006 44.1078011257 -25.9998952669 +85.9500444506 47.3491582078 -19.2521966526 +85.9928488773 4.31106969615 50.8590662521 +86.024710913 50.9762514185 -1.08208301821 +86.0365191952 -14.7528605571 48.7859659139 +86.0721887721 45.9968866589 -21.8143241397 +86.0875928264 -19.8748868342 46.8392488698 +86.1032717411 -15.2598173283 48.5114890576 +86.1189283468 47.8938142596 -17.0209499166 +86.1339520755 49.2894594998 -12.3081876034 +86.1769235305 40.4599638283 -30.6027642189 +86.2064657511 23.5025801237 -44.9007125805 +86.2078606968 50.4363765822 -4.93727367461 +86.2386425987 37.354538637 -34.1692107891 +86.2521133091 49.1973368446 11.8403968307 +86.2527506268 10.1323694948 49.5761847839 +86.2637021139 -17.0024557835 47.6391666061 +86.2666706422 22.2297791205 45.4301492025 +86.3054973824 23.2870103923 -44.8227204503 +86.3512568456 50.4191736932 1.16934394852 +86.3586805215 34.2790264366 -36.9746757274 +86.3774777448 50.3132656735 2.73982402877 +86.3803057016 50.3149129054 2.61769483079 +86.4268481933 -3.2748657333 50.1963660617 +86.4465074901 50.1516111722 -3.43762121291 +86.5077549803 27.9912727153 -41.628079226 +86.5147151222 50.1508262305 0.314158748588 +86.5560786821 28.0069087923 -41.5169640396 +86.5887877916 37.506205126 -33.1008520407 +86.5993751829 49.9578755137 -2.18148850346 +86.6078943834 -20.3455958425 45.6632167098 +86.6085246679 49.2604901495 -8.50691278224 +86.6389073947 -20.3528813007 45.6010959102 +86.7182516733 45.7600395108 19.6459565994 +86.7259516006 -40.4409753922 29.0368184947 +86.7405563683 49.0155080506 8.57647080445 +86.7478045485 49.5402906642 -4.53629881293 +86.8498664376 48.4989719137 -10.2445313747 +86.8833100089 45.1900488532 -20.2274547718 +86.8938317442 49.4227647809 -2.61769483079 +86.8974551789 45.1781384095 -20.1932685142 +86.9106604134 49.1716857962 5.35559730177 +86.9364134443 39.2532958078 -30.0206393279 +86.9416172696 39.0366397884 -30.2868938746 +86.965922994 47.7111391508 12.671836439 +87.0101359752 14.7635287949 47.0241901057 +87.0435052536 48.8864971589 -5.79125104807 +87.0600420188 49.155957832 -2.05934293201 +87.2003023012 19.7794153392 44.7759087839 +87.2125419899 48.8413702708 -2.91428717235 +87.2291403299 48.8106752553 -2.93173300722 +87.2323147552 48.892451178 0.226892608084 +87.2485588616 0.426380287809 48.8621241497 +87.3776903294 48.5738917307 2.39087323514 +87.3892001258 30.0393420453 -38.2199637738 +87.4482559722 48.3138658469 -4.30962809844 +87.4642315473 -18.0811337692 44.9786705168 +87.4823778599 46.5543830927 13.3986185418 +87.496312122 42.3916083085 -23.3954463532 +87.5038898119 48.2051585777 -4.39681183179 +87.5621752056 10.4876595069 47.147369718 +87.5700590975 43.432061319 -21.0983601077 +87.6407567132 -12.5823880091 46.4842045725 +87.6851935958 47.4112073135 7.96770011589 +87.6988910638 26.8122417281 -39.8749068925 +87.7435357657 45.4819289591 15.2468380166 +87.7442861555 43.6521231299 19.8854819736 +87.7660497894 40.5536083708 -25.5445757936 +87.8388390458 45.3952658952 -14.9535343444 +87.8441126882 41.5800081304 23.5481377163 +88.0364102153 -25.1276747176 40.2267378703 +88.0419332691 45.6951041962 -12.671836439 +88.0863361221 35.3212192278 -31.5152163383 +88.139228037 27.7394627467 -38.2360914263 +88.1867842359 -37.3422790383 28.7861995122 +88.2364298945 27.1113585384 -38.46175604 +88.2590077124 27.1520161067 -38.3811878264 +88.262300066 37.9569785113 -27.7314653302 +88.3924552551 -0.277694001639 46.7621293358 +88.4763952905 46.3526988493 4.83267894527 +88.513342882 23.7998863511 -39.9869171297 +88.5288114787 13.1043753733 44.619781311 +88.6064132574 -18.2205195781 42.6252999515 +88.6090355617 -38.5650889233 25.7132793155 +88.6276996387 -38.4996402582 25.747010637 +88.6545180763 39.8429202133 -23.5142113103 +88.7101460282 37.9296163158 -26.3031214458 +88.7125041829 45.2012785696 -9.32394858855 +88.7201693852 41.1448955573 20.8765206353 +88.720209738 42.2223716618 -18.6009600639 +88.8157403838 3.90884108635 45.7873915117 +88.833061607 3.87853523121 45.7563561703 +88.8645790206 35.0943013118 29.5207826951 +88.9816058047 45.592994984 1.88484397154 +88.983045454 27.2897804255 36.5689144775 +89.0710066102 23.2842813226 -39.0409787882 +89.0732896474 45.3851079455 -2.47811383077 +89.0962611227 44.4217571421 9.41083133185 +89.1085783516 1.67985608962 45.3523907604 +89.1177681523 15.9545422901 42.467351929 +89.138882428 40.4914807264 -20.364175114 +89.1398753173 42.8618086512 14.7291543397 +89.1529071873 44.6055330683 -7.88070807377 +89.1725411383 37.301681988 -25.6289373133 +89.2256089306 22.9590475775 -38.8802372073 +89.3062326583 -27.3547949692 35.7227098715 +89.3623768562 44.6518487376 -4.53629881293 +89.4050195491 38.8373059884 22.3250116011 +89.416099695 38.1760946834 -23.3954463532 +89.4214858162 42.173910687 -15.0053034553 +89.4311935932 44.7252527927 -1.30895955713 +89.5178632417 25.5505164675 -36.5201761892 +89.5338211556 29.2987595777 -33.545156975 +89.5404510623 32.183595867 -30.7688768178 +89.7561542956 43.525184507 7.02787874735 +89.7715710933 26.8815350138 -34.906275922 +89.8066674096 26.7213366924 34.9389847328 +89.8213383324 43.6536512305 -5.1464467756 +89.8318944016 31.2300451505 30.9016994375 +89.8752309834 37.1356852182 23.3105928507 +89.9137158228 28.7470094406 -33.0020174407 +89.919497677 14.99896739 41.1037092578 +90.00991305 -20.284609972 38.5583992277 +90.0410745381 -19.9286531787 38.6710961637 +90.1001135805 23.8896122404 -36.211268409 +90.148753151 38.080324237 -20.5691811048 +90.1953043824 26.5117138846 -34.0871837244 +90.2028154427 33.4565515047 -27.2784025857 +90.2298432112 26.0946939282 -34.3167938899 +90.2943785207 42.9715261059 -0.610861439068 +90.3527940382 42.7674638145 2.70493038153 +90.4416993163 40.608170735 -13.0872263805 +90.490213773 41.2006251076 -10.6784690876 +90.4938351839 42.5445899125 0.907558751868 +90.6855329729 41.8641914436 4.85011177129 +90.7197885327 38.0978301963 17.8458763563 +90.7345096336 34.5574433418 23.9380841177 +90.8265739009 25.9069106563 -32.8536977169 +90.8372895241 39.9315226026 -12.4121043561 +90.8539040721 38.2847937903 -16.728499015 +90.8987450383 37.3359043744 -18.532360751 +90.9801076479 35.6913548408 21.183654123 +91.0915590676 39.834795494 -10.7478804698 +91.0997137186 41.2288426031 -1.01227367745 +91.1729669099 -23.3583608539 33.7916718003 +91.2288101253 -21.1792612432 35.0534320191 +91.2748126178 39.2525019013 11.3203213768 +91.2807490203 40.297674369 6.62739004 +91.3556336454 37.9902708002 -14.5219670077 +91.3922652338 -26.1200194518 31.0676429631 +91.4096758697 39.6133366699 -8.66341245002 +91.46679148 26.1931307227 -30.785482931 +91.5062899302 26.1526078473 -30.7024429971 +91.5577333283 39.7534453956 -6.07001210504 +91.6144660048 40.0253760329 2.18148850346 +91.7530505778 8.78632914115 38.7837353782 +91.7726339682 8.72355186304 38.7515586452 +91.7844380735 39.490648511 -4.01317925326 +91.7913290939 39.4746285031 -4.01317925326 +91.852126826 38.6676832543 8.24603354897 +91.954928731 37.9386433468 -10.2445313747 +92.0097237497 25.9147571873 -29.3706672624 +92.0368079135 33.3532007758 -20.4154350213 +92.046901083 20.777429947 -33.1008520407 +92.0682255245 34.0205400384 19.1322947989 +92.1298557548 37.1854741866 11.3723431234 +92.1683538259 -27.2140434322 27.6476109834 +92.1791962978 29.3826842215 -25.2913747716 +92.2372807443 -29.0823029082 25.4264369988 +92.2431638174 -24.1651291327 30.1205123289 +92.2502415426 -26.1389704286 28.4015344704 +92.2876815606 38.3211975065 3.80389981962 +92.3338975562 21.1812095559 32.0282332298 +92.4019569747 34.3639797631 -16.7629126969 +92.41581246 30.5993994666 22.8690699339 +92.5088538567 24.7876726836 -28.769484546 +92.5557065683 -24.7482926378 28.6524552728 +92.571370221 34.8875178692 14.6083028562 +92.5997535847 31.3072649208 21.0983601077 +92.6916685354 35.247291061 -12.8795596578 +92.8655036911 35.3690607374 -11.1815815852 +92.8704763598 36.0220837901 8.80250533245 +92.8931956894 -27.0407203448 25.2913747716 +92.9135404871 -18.7852887527 31.8463015219 +92.9206836124 36.7336329228 4.04805747218 +92.9800791819 36.0272618862 7.53268055279 +93.0809432195 -25.150026124 26.5219568533 +93.0878875103 35.0821785523 10.1924455795 +93.1137946434 35.7057497318 7.41084901954 +93.1372862094 1.54441621716 36.3739013043 +93.1738284042 27.5993453506 23.5990219443 +93.1845147339 -21.376339418 29.3206126622 +93.1850813828 -26.8436432381 24.4122802168 +93.2763141845 -27.5411847998 23.2596722241 +93.2856878908 -27.8628648193 22.8350870111 +93.3510185125 35.0511565015 -7.55008414395 +93.3818404103 28.6388256047 21.4394391152 +93.3918748879 -22.4558872243 27.8152985584 +93.3933536547 -27.0979289627 23.3105928507 +93.4316823363 28.4758000103 -21.4394391152 +93.4508542198 35.5919992623 -0.383971491924 +93.4753758639 -26.6800842182 23.4633163303 +93.484507146 -27.1597600143 22.8690699339 +93.5233402625 -28.1473305806 21.4735327167 +93.532578342 25.6227137899 24.3953546137 +93.5840382264 32.0957320999 -14.5565026779 +93.6765536024 -26.1020988834 23.3105928507 +93.691067838 31.1305508398 15.9019688023 +93.7015747177 -27.347008803 21.7291510406 +93.7258457344 -25.5525984025 23.717726625 +93.7293678549 -22.0703364763 26.9760236013 +93.7459128602 9.47277351504 33.4958263661 +93.7492137705 9.4400494418 33.4958263661 +93.7896500816 32.2943663639 -12.671836439 +93.8343431744 19.4663198456 -28.5688367405 +93.8355745895 1.60514147099 34.5298198999 +93.8537602376 26.4694979418 -22.1548497619 +93.908869581 -24.9521202646 23.6329411694 +93.9267707849 22.6712255653 -25.7638751216 +93.9269232049 -18.9389898544 28.6190104747 +93.9457455496 33.7855104602 5.72155364244 +94.0121586389 -24.786430118 23.3954463532 +94.0667482839 33.8661132519 2.12914078949 +94.0687874631 24.7311358728 23.2257215962 +94.1745848614 28.2895652346 18.1892293686 +94.1754206706 -25.1813848811 22.2909846572 +94.2302486519 -26.3982215708 20.586260877 +94.242916311 -26.3662950352 20.5691811048 +94.3003644612 32.102462648 -8.76773371009 +94.3086211724 20.3041149019 -26.3367972734 +94.3194783128 -20.3409047513 26.2694424132 +94.3282444091 -23.9037534176 23.0389426677 +94.3400064938 20.3108719848 -26.2189178641 +94.3706106679 -22.9701789427 23.8024940184 +94.3930873391 22.0006960323 24.6153293029 +94.4107448411 -26.1469300578 20.0735972635 +94.4227314129 25.3534913014 21.0130500252 +94.4371092845 -22.4980929102 23.9889183874 +94.4409184134 -15.9734857042 28.736051985 +94.5418219041 31.6699513465 7.67190281268 +94.5659525319 -24.7559980292 21.0812993745 +94.570011478 31.8814596989 6.33130764713 +94.6164684198 27.7933169043 -16.5908239462 +94.6269128486 25.5677397312 -19.7999507521 +94.7195937209 13.2782559825 29.1870944669 +94.7669724531 -25.4281920007 19.3035743749 +94.7988276337 29.7626719769 11.2856384873 +94.8044958621 -22.4108331648 22.5801266869 +94.8447274736 2.23513988228 31.6145823974 +94.8488982447 17.9561782201 26.1009993198 +94.8597992338 21.5167988931 23.2087452208 +94.8710309138 26.0962102696 17.8458763563 +94.8955823138 -17.707803134 26.1009993198 +94.8983445246 -22.8181147982 21.7632222696 +94.9003679709 30.1588689577 9.18492145756 +94.9028511215 31.3310007725 -3.43762121291 +94.9118606025 25.8403535472 18.0004123711 +94.9246019822 -19.1918857964 24.9197002009 +94.9343289599 22.6515693659 -21.7802568899 +94.9589391978 31.3495175561 0.0872664515235 +94.9676419678 22.8523112308 -21.4223913346 +95.0195065026 27.3720824768 14.9017611339 +95.0298292292 31.0054722141 2.82705667703 +95.0618463556 -12.1271156821 28.5688367405 +95.1352654544 -24.2850443429 18.9609569425 +95.2060000469 -15.6759034941 26.2694424132 +95.225737663 20.2061161078 22.8860603507 +95.2424579697 29.2458261711 -8.57647080445 +95.243462036 23.4821870245 -19.423435122 +95.253323379 23.4846183294 -19.37206977 +95.2918189877 29.7713463253 -5.75640269596 +95.3154822909 24.2070487101 18.1377404435 +95.3171581659 25.4866718774 16.2809371901 +95.3296508566 22.1488291848 20.5350196811 +95.3359179431 24.5668041011 17.5366726092 +95.3639573956 25.4100354781 -16.1259333635 +95.3916007573 -20.6592512304 21.7632222696 +95.445314762 23.3553199358 -18.5666615386 +95.4742475108 17.3506113858 24.1583183765 +95.5117955932 29.5658396034 -1.83249313961 +95.5585047691 26.2673747907 -13.3640258869 +95.6288481743 -18.9870614751 22.2399391499 +95.6409603857 -5.01233034231 28.769484546 +95.6737441913 -9.93755205877 27.345561459 +95.689305577 -9.50046312102 -27.4462747688 +95.7102484959 28.8966276986 -2.12914078949 +95.7373285863 -12.2302691168 26.1683861269 +95.7485224531 25.6557392678 -13.1910382711 +95.76694149 9.72765117831 27.0936472296 +95.7798671267 26.7962870203 10.4007718516 +95.8038325921 -20.8886135895 19.6288431388 +95.8353438753 -23.2204235072 16.6252457562 +95.8608179651 17.7148407298 22.2909846572 +95.9192523061 27.9034307802 -4.571169187 +95.9227426397 -24.6287742767 -13.8654578758 +95.9234913199 -24.6646606888 -13.7963156715 +95.931316154 15.1597033423 23.819445324 +95.9572072153 27.153152676 7.41084901954 +95.9919272134 -21.932194836 17.4507518327 +95.9951751623 -0.0837716148958 28.0164117595 +95.9986759256 22.8347017824 16.2120515372 +96.0040209322 25.9398277557 -10.5049179362 +96.0636678319 27.6365604448 2.82705667703 +96.0819436191 -16.0268904558 22.6141303767 +96.1133766237 18.7347794866 20.2787295357 +96.1140965568 26.5283841845 -7.6370986393 +96.1162685361 3.7260154583 27.345561459 +96.1451136556 27.2969679931 -3.31551783885 +96.1566397413 24.4564085844 -12.4813746365 +96.1725108653 26.3459081749 -7.53268055279 +96.186968647 22.6135903557 -15.3848169873 +96.1883901067 -20.5858874752 18.0004123711 +96.1982480171 26.2266526308 -7.61969620339 +96.213433727 26.2307927305 -7.41084901954 +96.2153197945 25.4571173558 -9.72354939224 +96.2322061678 8.84249754955 25.7132793155 +96.2428663009 24.657260555 11.3723431234 +96.2581475461 -22.5771446798 14.9880475413 +96.2636968768 15.1261364469 22.4610921331 +96.264383031 26.2446831051 -6.66221947733 +96.2927464603 26.9760219578 -0.034906584331 +96.3433237868 24.4680871957 -10.9213859333 +96.3767060822 21.3132645878 16.0398029092 +96.4004571607 -2.82741937464 26.4378054854 +96.4096548437 23.2705224865 12.7930151302 +96.5076789029 11.9864581602 23.2936200179 +96.5370019513 24.1946901405 9.75828997591 +96.5551999766 13.0204565961 22.5291159947 +96.5582706146 -6.92138289938 25.0717936073 +96.5766685849 24.742780139 7.79371003014 +96.6014461535 25.4690992 -4.41424817878 +96.6086938208 -19.7430732104 16.6424559018 +96.6127544587 24.3212316027 -8.62863657979 +96.6800595026 -13.5014710836 21.695077164 +96.7060301271 8.88603585512 23.8533457579 +96.709716708 -20.644509397 14.8672433897 +96.7126641918 22.0968685153 -12.5852686403 +96.7147861132 14.5058964989 20.8765206353 +96.717739022 -10.4215186387 23.1747903494 +96.7435309679 -18.3673332472 17.4163797974 +96.753534811 23.3713964868 -9.61932054944 +96.7554291326 23.1039375903 -10.2271697543 +96.7576332514 -0.118211808183 25.2576015004 +96.7640852315 -15.6203717439 19.8170582048 +96.7675100858 23.1068223647 -10.1056297183 +96.7876803414 -21.4573121413 13.104529362 +96.802853651 -20.7527336371 14.0901231938 +96.8142368477 24.0487814101 -6.97564737441 +96.8210398864 -20.2798827733 14.6428340844 +96.8295900735 23.6582292566 8.01989243289 +96.8404798452 23.6429798695 7.93290402346 +96.8903638514 22.5470939558 -10.1924455795 +96.9134921888 2.45314004956 24.5307385879 +96.950322192 -11.560626006 21.6098809163 +96.9531011872 16.7815633138 17.8458763563 +96.9535833127 24.227170883 3.6120456584 +96.9565546281 -20.2023033935 13.8308876163 +96.9568310051 21.7257286503 11.2856384873 +96.9602867137 -8.19311128592 23.0559260896 +97.0168790279 -0.0507979237135 24.2429908069 +97.020425936 8.91492477164 22.5291159947 +97.0410447034 23.512558775 5.49501799124 +97.0436767769 24.0698128945 1.78014180529 +97.0560313155 -18.8130482057 15.0398139113 +97.0705254138 -15.895908148 18.0175803048 +97.0850539266 11.4048726754 21.0812993745 +97.0971547107 23.0422813992 -6.41839660646 +97.1217036173 -4.1045673649 23.4633163303 +97.1242739854 22.7802928021 6.92341408906 +97.1247360079 21.3898026887 -10.4528463268 +97.1276800717 21.4437797309 -10.3139747302 +97.1567704608 23.5046964794 -2.84450295045 +97.1753983913 3.68214726053 23.3105928507 +97.181635446 -12.7942050261 19.7999507521 +97.1893677023 -17.3120631518 15.9536602398 +97.1951009576 20.3405252924 11.805735075 +97.2164349969 23.4293470842 0.17453283659 +97.2205587519 21.3219669807 9.67143629658 +97.2251108499 23.2160914733 -2.87939523683 +97.2299309864 -9.31079861255 21.4394391152 +97.2390346489 13.1126716158 19.3035743749 +97.2613051559 -18.6415660179 13.8827423723 +97.2907303908 20.9994547545 -9.67143629658 +97.291472371 21.9255802364 -7.32381971276 +97.2952194184 22.9458315152 -2.67003640471 +97.3337282212 15.2420550822 17.1413274698 +97.3986925014 -19.3738045051 11.7537397458 +97.4041152565 21.808101342 -6.07001210504 +97.4608748686 -5.92681566835 21.5928396898 +97.4637791722 12.7448325036 18.3951350613 +97.482971252 22.2728679458 0.994821263837 +97.5048575616 20.5474962743 -8.40256798546 +97.535539514 22.0163613957 -1.44857261386 +97.5460969669 -16.2711176688 14.832723834 +97.5528969823 16.7626534799 14.2283427941 +97.5629488337 -9.70368291733 19.6801817247 +97.6460753746 -18.5386866568 11.0254732764 +97.6515567537 -2.59120651656 21.3882938162 +97.6807415552 5.88885322791 20.586260877 +97.690392379 19.8753349611 -7.84590957278 +97.7445066365 19.4425912134 8.24603354897 +97.7631881067 19.9434586341 6.67963389185 +97.7666674078 19.9263954352 6.67963389185 +97.7677519975 18.5617876855 9.84513622389 +97.7689780928 -12.9930674084 16.5047605861 +97.7765595594 -5.00447526271 20.364175114 +97.7881678698 -17.8592905869 10.8866874852 +97.8018211277 0.631585382965 20.842381918 +97.8147600734 0.0 20.7911690818 +97.8269441749 -7.38998688908 19.37206977 +97.8651898392 8.13197017969 18.8752663223 +97.8958857807 17.4731717502 10.5396307434 +97.916875057 -15.2108352435 13.4505044618 +97.9321935039 20.0491602604 2.70493038153 +97.9348542737 19.8894730655 3.62948750656 +97.9541439657 11.2124225474 16.7112914094 +97.9639445313 12.0284599136 16.0742565604 +97.9729388232 19.986247283 1.36131476707 +97.9791722611 12.4645250411 15.643446504 +97.9800338503 19.347261068 5.05929400767 +97.9835357509 14.8536033961 13.3640258869 +97.9909042595 5.01544601842 19.3035743749 +98.0143966868 17.4060795588 9.4977069084 +98.034645359 19.0915206082 -4.97213738687 +98.0392512675 18.6487914853 6.36614381316 +98.0926663724 -1.9691104304 19.3378232506 +98.1024189923 18.4479920509 -5.96548213902 +98.1037777839 19.1049836356 -3.26318629583 +98.1345418607 17.1801724252 8.62863657979 +98.1539658495 15.1950367263 11.6150698194 +98.1773184713 -9.66097125075 16.3670330935 +98.1777749609 -1.88510958259 18.909544299 +98.1938070416 -8.93633649045 16.6768746716 +98.1968562696 10.3555625822 15.8158067254 +98.1998073776 16.0456397645 9.96670836044 +98.2048239749 0.428502099288 18.8581264713 +98.2271543934 -7.47194650316 17.1929100279 +98.2276429548 -5.457383416 17.9317351584 +98.2277900062 0.428602308139 18.7381314586 +98.3080206822 15.0783624586 10.4007718516 +98.3186547036 -12.9788125838 12.84494302 +98.3214204263 16.8593780745 6.97564737441 +98.3278283586 16.8074835015 7.01046850308 +98.3537213707 2.36936103568 17.9145644884 +98.363276034 0.806896722797 18.0004123711 +98.3718667243 -4.29500845685 17.4507518327 +98.3803885122 17.1701264347 5.1464467756 +98.3921017917 11.610647656 13.5715572434 +98.4025051093 17.7586017084 -1.25660398834 +98.415703718 16.2396760769 7.11492674688 +98.486613693 17.0115920697 3.31551783885 +98.4971154306 13.0898336598 11.2682965267 +98.5016786436 13.0554508836 11.2682965267 +98.5315269757 1.89190196827 16.9693517489 +98.5679489959 14.4673672606 8.66341245002 +98.5682876849 4.51043807182 16.2464953535 +98.5845865098 16.6743347028 1.74524064373 +98.5909120606 7.89779990474 14.7464170468 +98.5935596047 2.01359510786 16.5908239462 +98.6177069659 -1.46313047402 16.5047605861 +98.6192305136 15.2141933661 6.54031292301 +98.642919708 -0.0344328760522 16.4186846569 +98.6484663538 16.3665282956 0.785390088871 +98.6496830662 -11.1873913897 11.9617015862 +98.6681291176 -4.27343674699 15.6951595979 +98.7035936174 -8.756970751 13.4505044618 +98.7291858187 11.7377910938 10.7131754314 +98.754393369 1.9823939263 15.6089687246 +98.7767938102 7.7392100484 13.5369727936 +98.8287748713 15.211203317 -1.22170008352 +98.8432603552 -9.25641841706 12.0136838835 +98.8788945692 -12.7894835948 7.70670605126 +98.880807691 8.35539465601 12.360147674 +98.8925706535 -10.3067825959 10.6784690876 +98.8949849233 12.1778201029 8.45474154281 +98.8980965137 -4.80231993513 14.0037219771 +98.9178995427 9.69898485073 11.0081262225 +98.9275095363 4.26737246272 13.9691585007 +98.9307311815 6.74442063464 12.9314816705 +98.9346726772 6.88348351455 12.827634114 +98.9860695282 -11.5406259384 8.28082075122 +98.993209597 -8.13872333726 11.5803987891 +98.9960949226 11.0167224264 8.85466075362 +99.0200425686 -3.63090013111 13.4850930274 +99.0389281798 9.93777526196 9.61932054944 +99.0666332424 -10.5521945008 8.62863657979 +99.0700270638 -0.0518729496095 13.6061400396 +99.1007777369 -4.0322722487 12.7583945876 +99.1072265552 1.93756390097 13.1910382711 +99.1214984084 12.9088200986 2.87939523683 +99.1532735904 3.58380014635 12.4813746365 +99.173548721 5.77041220544 11.4590390988 +99.1775045168 5.80537976431 11.4070225565 +99.2601265024 1.00483561675 12.1003137194 +99.2742656865 -2.77298132476 11.7017411942 +99.3007494625 4.12721163936 11.0601663763 +99.307240795 2.60045161871 11.4590390988 +99.3108021062 11.7014838343 0.663220253582 +99.3146509488 1.30009999795 11.6150698194 +99.3329044882 -4.04171716204 10.7999355706 +99.3339343767 0.814859257874 11.4937150493 +99.3463321518 -6.82501471054 9.15016186634 +99.3970781592 2.16885196085 10.7478804698 +99.4073604033 -5.73179233706 9.23705874466 +99.4203869942 1.38826069469 10.6611154275 +99.4335763307 0.208253499781 10.6264071336 +99.4365510979 -0.433876556841 10.5916975449 +99.4503367734 -1.70118700245 10.331334785 +99.4855780137 1.0939451509 10.0709012153 +99.5193276492 0.0 9.79302937057 +99.5223019271 -0.295289480647 9.75828997591 +99.5635297448 -3.87705433498 8.48952262753 +99.5710743092 -1.85970830263 9.06325801978 +99.5899651182 -3.07754491024 8.50691278224 diff --git a/Voronoi_diagram_2/test/Voronoi_diagram_2/vda_tos2.cpp b/Voronoi_diagram_2/test/Voronoi_diagram_2/vda_tos2.cpp new file mode 100644 index 00000000000..e0195e7dd6e --- /dev/null +++ b/Voronoi_diagram_2/test/Voronoi_diagram_2/vda_tos2.cpp @@ -0,0 +1,201 @@ +#include +#include "vda_test.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::FT FT; +typedef K::Point_3 Point_3; +typedef K::Segment_3 Segment_3; + +typedef CGAL::Projection_on_sphere_traits_3 Traits; +typedef CGAL::Triangulation_on_sphere_face_base_2 Fb; +typedef CGAL::Triangulation_on_sphere_vertex_base_2 Vb; +typedef CGAL::Triangulation_data_structure_2 Tds; +typedef CGAL::Delaunay_triangulation_on_sphere_2 DToS2; + +typedef Traits::SK SK; +typedef Traits::Point_on_sphere_2 Point_on_sphere_2; +typedef Traits::Arc_on_sphere_2 Arc_on_sphere_2; +typedef DToS2::Face_handle Face_handle; + +typedef CGAL::Delaunay_triangulation_on_sphere_adaptation_traits_2 AT; +typedef CGAL::Delaunay_triangulation_on_sphere_caching_degeneracy_removal_policy_2 AP; +typedef CGAL::Voronoi_diagram_2 VD; + +int main(int argc, char** argv) +{ + const char* filename = (argc > 1) ? argv[1] : "data/radar.xyz"; + const double radius = (argc > 2) ? std::stod(argv[2]) : 1; + const double step = (argc > 3) ? std::stod(argv[3]) : 0.01; + + std::vector points; + double x, y, z; + + std::ifstream in(filename); + if(!in) + { + std::cerr << "Invalid input file: " << filename << std::endl; + return EXIT_FAILURE; + } + + while(in >> x >> y >> z) + points.emplace_back(x, y, z); + + std::cout << points.size() << " points" << std::endl; + + Traits traits(Point_3(1,1,1), radius); // radius is 1 by default + DToS2 dtos(traits); + + Traits::Construct_point_on_sphere_2 cst = traits.construct_point_on_sphere_2_object(); + + for(const auto& pt : points) + { +// std::cout << "----- Inserting (" << pt +// << ") at squared distance " << CGAL::squared_distance(pt, traits.center()) +// << " from the center of the sphere" << std::endl; + + // shenanigans just to get a OFF with pts on the sphere (it should just be 'cst(pt)') + dtos.insert(cst(pt).get_projection(traits.center(), traits.radius())); + +// std::cout << "The triangulation now has dimension: " << dtos.dimension() << " and\n"; +// std::cout << dtos.number_of_vertices() << " vertices" << std::endl; +// std::cout << dtos.number_of_edges() << " edges" << std::endl; +// std::cout << dtos.number_of_faces() << " solid faces" << std::endl; +// std::cout << dtos.number_of_ghost_faces() << " ghost faces" << std::endl; + } + +#ifdef CGAL_VD2_TEST_TOS2_OUTPUT + CGAL::write_OFF("result.off", dtos, CGAL::parameters::stream_precision(17)); + + std::ofstream out_primal("edges_primal.polylines.cgal"); + out_primal.precision(17); + std::ofstream out_dual("edges_dual.polylines.cgal"); + out_dual.precision(17); +#endif + + for(typename DToS2::All_faces_iterator fit = dtos.all_faces_begin(); fit!=dtos.all_faces_end(); ++fit) + { + Face_handle fh = fit; + + const Point_3 c = dtos.dual(fh); + CGAL_USE(c); + + const Point_on_sphere_2 cs = dtos.dual_on_sphere(fh); + const FT r = dtos.geom_traits().radius(); + assert(CGAL::abs(CGAL::squared_distance(dtos.construct_point(cs), + dtos.geom_traits().center()) - r*r) <= 1e-10); + + for(int i=0; i<3; ++i) + { + Face_handle nfh = fh->neighbor(i); + if(/*!dtos.is_ghost(nfh) &&*/ fh > nfh) + continue; + + typename DToS2::Edge e(fh, i); + const bool diametral_edge = CGAL::collinear(dtos.construct_point(dtos.point(fh, (i+1)%3)), + dtos.construct_point(dtos.point(fh, (i+2)%3)), + dtos.geom_traits().center()); + + // primal + if(!diametral_edge) + { + const Arc_on_sphere_2 as = dtos.segment_on_sphere(e); + std::vector discretization_points; + CGAL::Triangulations_on_sphere_2::internal::subsample_arc_on_sphere_2(as, std::back_inserter(discretization_points), step); + assert(discretization_points.size() >= 2); + +#ifdef CGAL_VD2_TEST_TOS2_OUTPUT + for(std::size_t i=0; i discretization_points; + CGAL::Triangulations_on_sphere_2::internal::subsample_arc_on_sphere_2(ad, std::back_inserter(discretization_points), step); + assert(discretization_points.size() >= 2); + +#ifdef CGAL_VD2_TEST_TOS2_OUTPUT + for(std::size_t i=0; ipoint() << std::endl; + std::cout << "valence: " << vit->degree() << std::endl; + DToS2::Face_handle dual_face = vit->dual(); + CGAL_USE(dual_face); + + VD::Halfedge_around_vertex_circulator cir = vd.incident_halfedges(vit), cend = cir; + do { + std::cout << " Incident Halfedge with source: " << cir->source()->point() << std::endl; + VD::Face_handle incident_Voronoi_face = cir->face(); + DToS2::Vertex_handle Voronoi_face_seed = incident_Voronoi_face->dual(); + CGAL_USE(Voronoi_face_seed); + } while(cir != cend); + } + + VD::Halfedge_iterator hit = vd.halfedges_begin(), hend = vd.halfedges_end(); + for(; hit!=hend; ++hit) + { + std::cout << "Halfedge between " << hit->source()->point() << " and " << hit->target()->point() << std::endl; + VD::Halfedge_handle next_h = hit->next(); + VD::Halfedge_handle opposite_h = hit->opposite(); + CGAL_USE(next_h); + CGAL_USE(opposite_h); + } + + return EXIT_SUCCESS; +} From 01b2f0783aa17e3a953350586660c3e4af9d534b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 6 Jul 2021 10:37:07 +0200 Subject: [PATCH 275/349] Harmonization of ASCII/BINARY/PRETTY formatting within io.h --- Stream_support/include/CGAL/IO/io.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Stream_support/include/CGAL/IO/io.h b/Stream_support/include/CGAL/IO/io.h index 63d20c73cbf..e287fe8e16f 100644 --- a/Stream_support/include/CGAL/IO/io.h +++ b/Stream_support/include/CGAL/IO/io.h @@ -55,20 +55,19 @@ IOStreams. The basic task of such an operator is to produce a representation of an object that can be written as a sequence of characters on devices as a console, a file, or a pipe. The enum `Mode` distinguish between three different printing formats. -In \ascii mode, numbers +In `ASCII` mode, numbers e.g. the coordinates of a point or the coefficients of a line, are written in a machine independent format. -In BINARY mode, data are written +In `BINARY` mode, data are written in a binary format, e.g. a double is represented as a sequence of four byte. The format depends on the machine. - The mode PRETTY -serves mainly for debugging as the type of the geometric + The mode `PRETTY` serves mainly for debugging as the type of the geometric object is written, as well as the data defining the object. For example for a point at the origin with %Cartesian double coordinates, the output would be `PointC2(0.0, 0.0)`. At the moment \cgal does not provide input operations for pretty printed data. By default a stream -is in \ascii mode. +is in `ASCII` mode. \sa `CGAL::IO::set_mode()` \sa `CGAL::IO::set_ascii_mode()` @@ -458,7 +457,7 @@ inline Mode get_mode(std::ios& s) /*! \ingroup PkgStreamSupportRef -sets the mode of the %IO stream `s` to be the \ascii mode. +sets the mode of the %IO stream `s` to be the `ASCII` mode. Returns the previous mode of `s`. \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink @@ -561,7 +560,7 @@ inline bool is_pretty(std::ios& s) { return s.iword(Static::get_mode()) == PRETT /*! \ingroup PkgStreamSupportRef -checks if the %IO stream `s` is in \ascii mode. +checks if the %IO stream `s` is in `ASCII` mode. \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink \sa `CGAL::IO::set_mode()` From 5f5f6b1f04c74587cc309376091bd7d3ca0fb65b Mon Sep 17 00:00:00 2001 From: albert-github Date: Tue, 6 Jul 2021 10:50:43 +0200 Subject: [PATCH 276/349] Inconsistent display of CGAL::Interval_nt_advanced in documentation The display of `CGAL::Interval_nt_advanced` is different from the other fields in the list --- .../doc/Algebraic_foundations/Concepts/FieldNumberType.h | 2 +- .../doc/Algebraic_foundations/Concepts/RingNumberType.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Algebraic_foundations/doc/Algebraic_foundations/Concepts/FieldNumberType.h b/Algebraic_foundations/doc/Algebraic_foundations/Concepts/FieldNumberType.h index cb86878a6cb..3c464a42811 100644 --- a/Algebraic_foundations/doc/Algebraic_foundations/Concepts/FieldNumberType.h +++ b/Algebraic_foundations/doc/Algebraic_foundations/Concepts/FieldNumberType.h @@ -14,7 +14,7 @@ for Cartesian kernels. \cgalHasModel double \cgalHasModel `CGAL::Gmpq` \cgalHasModel `CGAL::Interval_nt` -\cgalHasModel \ref CGAL::Interval_nt_advanced +\cgalHasModel `CGAL::Interval_nt_advanced` \cgalHasModel `CGAL::Lazy_exact_nt` \cgalHasModel `CGAL::Quotient` \cgalHasModel `leda_rational` diff --git a/Algebraic_foundations/doc/Algebraic_foundations/Concepts/RingNumberType.h b/Algebraic_foundations/doc/Algebraic_foundations/Concepts/RingNumberType.h index 13178d73def..37b6e85e6df 100644 --- a/Algebraic_foundations/doc/Algebraic_foundations/Concepts/RingNumberType.h +++ b/Algebraic_foundations/doc/Algebraic_foundations/Concepts/RingNumberType.h @@ -14,8 +14,8 @@ for Homogeneous kernels. \cgalHasModel \cpp built-in number types \cgalHasModel `CGAL::Gmpq` \cgalHasModel `CGAL::Gmpz` -\cgalHasModel` CGAL::Interval_nt` -\cgalHasModel \ref CGAL::Interval_nt_advanced +\cgalHasModel `CGAL::Interval_nt` +\cgalHasModel `CGAL::Interval_nt_advanced` \cgalHasModel `CGAL::Lazy_exact_nt` \cgalHasModel `CGAL::MP_Float` \cgalHasModel `CGAL::Gmpzf` From 9e29edb42cf63b0ae3ba696550d9975f71ba8411 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 7 Jul 2021 15:10:09 +0200 Subject: [PATCH 277/349] Fix condition for push --- .github/workflows/delete_doc.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/delete_doc.yml b/.github/workflows/delete_doc.yml index d648a601e91..38dbc242e31 100644 --- a/.github/workflows/delete_doc.yml +++ b/.github/workflows/delete_doc.yml @@ -25,8 +25,8 @@ jobs: if [ -d ${PR_NUMBER} ]; then git rm -r ${PR_NUMBER} fi - #git diff exits with 1 if there is a diff - if ! git diff --quiet; then + #git diff exits with 1 if there is no diff + if git diff --quiet; then git commit -a --amend -m"base commit" && git push -f -u origin master fi From f7a69d5fb05dca4bb4a4894bcf99d7a6a60e3649 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Thu, 8 Jul 2021 13:22:05 +0200 Subject: [PATCH 278/349] fixed warning for using precond >= 0 for size_t --- Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index 5adb75eb791..edcd3c34133 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -186,7 +186,7 @@ public: std::cout << "num variables = " << n << std::endl; std::cout << "num constraints = " << m << std::endl; } - CGAL_precondition(n >= 1 && m >= 0); + CGAL_precondition(n >= 1); // m >= 0 CGAL_precondition(q_vec.size() == n); CGAL_precondition(l_vec.size() == m && l_vec.size() == m); From e599bd44cc2bba4f0beb16be23a8404d3763ca27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 8 Jul 2021 13:50:18 +0200 Subject: [PATCH 279/349] fix validity check: holes can be relatively simple --- .../Gps_polygon_validation.h | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h index 7c28188fb79..a248919084c 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h @@ -474,10 +474,9 @@ is_crossover_outer_boundary(const typename Traits_2::Polygon_with_holes_2& pgn, return is_crossover_outer_boundary(pgn, traits, pl); } -// previously known as Simple template -bool is_relatively_simple_polygon_with_holes -(const typename Traits_2::Polygon_with_holes_2& pgn, const Traits_2& traits) +bool is_relatively_simple_polygon +(const typename Traits_2::Polygon_2& pgn, const Traits_2& traits) { typedef typename Traits_2::Curve_const_iterator Curve_const_iterator; typedef std::pair @@ -487,11 +486,10 @@ bool is_relatively_simple_polygon_with_holes typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; typedef Gps_polygon_validation_visitor Visitor; typedef Ss2::Surface_sweep_2 Surface_sweep; - typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; Construct_curves_2 construct_curves_func = traits.construct_curves_2_object(); // Construct a container of all outer boundary curves. - Cci_pair itr_pair = construct_curves_func (pgn.outer_boundary()); + Cci_pair itr_pair = construct_curves_func (pgn); std::list outer_curves; std::copy(itr_pair.first, itr_pair.second, std::back_inserter(outer_curves)); // Create visitor and sweep to verify outer boundary is relatively simple @@ -502,31 +500,51 @@ bool is_relatively_simple_polygon_with_holes switch (relative_visitor.error_code()) { case Visitor::ERROR_NONE: break; case Visitor::ERROR_EDGE_INTERSECTION: - CGAL_warning_msg(false, "The outer boundary self intersects at edges."); + CGAL_warning_msg(false, "Polygon self intersects at edges."); break; case Visitor::ERROR_EDGE_VERTEX_INTERSECTION: - CGAL_warning_msg(false, "The outer boundary self (weakly) intersects."); + CGAL_warning_msg(false, "Polygon self (weakly) intersects."); break; case Visitor::ERROR_EDGE_OVERLAP: - CGAL_warning_msg(false, "The outer boundary self overlaps."); + CGAL_warning_msg(false, "Polygon self overlaps."); break; case Visitor::ERROR_VERTEX_INTERSECTION: - CGAL_warning_msg(false, "The outer boundary self intersects at vertices."); + CGAL_warning_msg(false, "Polygon self intersects at vertices."); break; } return false; } + return true; +} + +// previously known as Simple +template +bool is_relatively_simple_polygon_with_holes +(const typename Traits_2::Polygon_with_holes_2& pgn, const Traits_2& traits) +{ + bool outer_is_relatively_simple = is_relatively_simple_polygon(pgn.outer_boundary(), traits); + if (!outer_is_relatively_simple) + { + CGAL_warning_msg(false, "Outer boundary is not relatively simple."); + return false; + } + // Verify every hole is simple + typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; typename Polygon_with_holes_2::Hole_const_iterator hoit; std::list hole_curves; for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit) { - bool simple_hole = is_simple_polygon(*hoit, traits); - if (!simple_hole) + bool relatively_simple_hole = is_relatively_simple_polygon(*hoit, traits); + if (!relatively_simple_hole) + { + CGAL_warning_msg(false, "A hole is not relatively simple."); return false; + } } return true; } From 0426fd674ce9b058c0d90d2e9018cab54cebb8ef Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 8 Jul 2021 23:58:14 +0200 Subject: [PATCH 280/349] Add the ASCII alias for doxygen 1.8.4 --- Documentation/doc/resources/1.8.4/BaseDoxyfile.in | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/doc/resources/1.8.4/BaseDoxyfile.in b/Documentation/doc/resources/1.8.4/BaseDoxyfile.in index 9124909bf7c..25a04ca1d48 100644 --- a/Documentation/doc/resources/1.8.4/BaseDoxyfile.in +++ b/Documentation/doc/resources/1.8.4/BaseDoxyfile.in @@ -206,6 +206,7 @@ ALIASES += "gmpxx=GMPXX" ALIASES += "mpir=MPIR" ALIASES += "mpfr=MPFR" ALIASES += "exacus=Exacus" +ALIASES += "ascii=ASCII" ALIASES += "iso=ISO" ALIASES += "lisp=Lisp" ALIASES += "ieee=IEEE" From 32c7364831c41e94691c5a9fe44efd7a3fce98c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 12 Jul 2021 15:38:26 +0200 Subject: [PATCH 281/349] update test to accept a relatively simple hole as being valid --- .../test/Boolean_set_operations_2/data/validation/test1.dat | 2 +- .../test/Boolean_set_operations_2/test_polygon_validation.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/test1.dat b/Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/test1.dat index 7d26f71ef2c..9a5d1ae0078 100644 --- a/Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/test1.dat +++ b/Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/test1.dat @@ -14,4 +14,4 @@ 5 1 3 1 -0 +1 diff --git a/Boolean_set_operations_2/test/Boolean_set_operations_2/test_polygon_validation.cpp b/Boolean_set_operations_2/test/Boolean_set_operations_2/test_polygon_validation.cpp index c613c2884fc..4bd10098f0a 100644 --- a/Boolean_set_operations_2/test/Boolean_set_operations_2/test_polygon_validation.cpp +++ b/Boolean_set_operations_2/test/Boolean_set_operations_2/test_polygon_validation.cpp @@ -21,8 +21,7 @@ typedef Traits_2::Polygon_2 Polygon_2; typedef Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; /* test files: - * 1. test1.dat---invalid polygon with holes. The hole is relatively simple - * instead of strictly simple. + * 1. test1.dat---valid polygon with holes. The hole is relatively simple. * 2. test2.dat---invalid polygon with holes. The hole overlaps the outer * boundary (the intersection results in a polygon). * 3. test3.dat---invalid polygon with holes. Two holes intersect (the From 66d5a6738392cff38ad1c88c180b53124fe45f21 Mon Sep 17 00:00:00 2001 From: Monique Teillaud Date: Tue, 13 Jul 2021 11:17:46 +0200 Subject: [PATCH 282/349] Funding acknowledgement for the package --- .../doc/Triangulation_on_sphere_2/Triangulation_on_sphere_2.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Triangulation_on_sphere_2/doc/Triangulation_on_sphere_2/Triangulation_on_sphere_2.txt b/Triangulation_on_sphere_2/doc/Triangulation_on_sphere_2/Triangulation_on_sphere_2.txt index 56dcd30e101..a61f299c254 100644 --- a/Triangulation_on_sphere_2/doc/Triangulation_on_sphere_2/Triangulation_on_sphere_2.txt +++ b/Triangulation_on_sphere_2/doc/Triangulation_on_sphere_2/Triangulation_on_sphere_2.txt @@ -236,6 +236,8 @@ was developed over the two internships of Oliver Rouiller and Claudia Werner at under the supervision of Monique Teillaud and with the help of SĂ©bastien Loriot. Based on this prototype, Mael Rouxel-LabbĂ© developed the initial version of this package. +The work was partially supported by the grant ANR-17-CE40-0033 of the French National Research Agency ANR (project SoS) and INTER/ANR/16/11554412/SoS of the Luxembourg National Research fund FNR. + */ } /* namespace CGAL */ From f8a2878b0c8587396357ee6e1802cfc2b33a72eb Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Tue, 13 Jul 2021 11:38:43 +0200 Subject: [PATCH 283/349] Port Mesh_3 to oneAPI-TBB The work was already mostly done in PR #4892, but there was still two issues: - `tbb::parallel_do` has been removed, and `tbb::parall_for_each` was to be used instead, - the support for `tbb_hasher` has been removed. This time, I have tested in a container were intel-oneapi-tbb-common-devel-2021.3.0-2021.3.0-511.noarch was installed, but not tbb version 2020. --- Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h | 8 +++---- .../Mesh_complex_3_in_triangulation_3_base.h | 23 ++++++++++++++++--- .../CGAL/Mesh_3/Mesh_global_optimizer.h | 6 ++--- Mesh_3/include/CGAL/Mesh_3/Refine_facets_3.h | 6 ++--- Mesh_3/test/Mesh_3/CMakeLists.txt | 10 +++++--- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h b/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h index 60c7a84589d..2cc517d16c0 100644 --- a/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h +++ b/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h @@ -46,7 +46,7 @@ #include #ifdef CGAL_LINKED_WITH_TBB -# include +# include # include #endif @@ -1941,7 +1941,7 @@ private: // Parallel if (boost::is_convertible::value) { - tbb::parallel_do( + tbb::parallel_for_each( outdated_cells.begin(), outdated_cells.end(), Update_cell_facets(tr_, updater)); } @@ -2831,7 +2831,7 @@ rebuild_restricted_delaunay(ForwardIterator first_cell, // Parallel if (boost::is_convertible::value) { - tbb::parallel_do(first_cell, last_cell, + tbb::parallel_for_each(first_cell, last_cell, Update_cell(c3t3_, updater)); } // Sequential @@ -2853,7 +2853,7 @@ rebuild_restricted_delaunay(ForwardIterator first_cell, // Parallel if (boost::is_convertible::value) { - tbb::parallel_do( + tbb::parallel_for_each( facets.begin(), facets.end(), Update_facet( *this, c3t3_, updater, vertex_to_proj) diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h index c12dac28be1..663c8b0fd62 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h @@ -59,13 +59,29 @@ namespace CGAL { // tbb::interface5::concurrent_hash_map template < class DSC, bool Const > std::size_t tbb_hasher(const std::pair, - CGAL::internal::CC_iterator >& p) + CGAL::internal::CC_iterator >& p) { return boost::hash, CGAL::internal::CC_iterator > >()(p); } - + struct Hash_compare_for_TBB { + template < class DSC, bool Const > + std::size_t hash(const std::pair, + CGAL::internal::CC_iterator >& p) const + { + return tbb_hasher(p); + } + template < class DSC, bool Const > + std::size_t operator()(const CGAL::internal::CC_iterator& it) + { + return CGAL::internal::hash_value(it); + } + template + bool equal(const T& v1, const T& v2) const { + return v1 == v2; + } + }; } #endif @@ -940,7 +956,8 @@ private: typedef typename Base::Pair_of_vertices Pair_of_vertices; #ifdef CGAL_LINKED_WITH_TBB - typedef tbb::concurrent_hash_map Edge_facet_counter; + typedef tbb::concurrent_hash_map Edge_facet_counter; #else // not CGAL_LINKED_WITH_TBB typedef std::map Edge_facet_counter; #endif // not CGAL_LINKED_WITH_TBB diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h index 60d0276330d..8177abbade4 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h @@ -49,7 +49,7 @@ #ifdef CGAL_LINKED_WITH_TBB # include # include -# include +# include # include #endif @@ -794,7 +794,7 @@ compute_moves(Moving_vertices_set& moving_vertices) tbb::concurrent_vector vertices_not_moving_any_more; // Get move for each moving vertex - tbb::parallel_do( + tbb::parallel_for_each( moving_vertices.begin(), moving_vertices.end(), Compute_move( *this, sizing_field_, moves, do_freeze_, vertices_not_moving_any_more, @@ -1033,7 +1033,7 @@ fill_sizing_field() std::vector< std::pair > > Local_list; Local_list local_lists; - tbb::parallel_do( + tbb::parallel_for_each( tr_.finite_vertices_begin(), tr_.finite_vertices_end(), Compute_sizing_field_value(*this, tr_.geom_traits(), local_lists) ); diff --git a/Mesh_3/include/CGAL/Mesh_3/Refine_facets_3.h b/Mesh_3/include/CGAL/Mesh_3/Refine_facets_3.h index 952ae641ed9..eef04d11b70 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Refine_facets_3.h +++ b/Mesh_3/include/CGAL/Mesh_3/Refine_facets_3.h @@ -26,7 +26,7 @@ #include #ifdef CGAL_LINKED_WITH_TBB #include - #include + #include #endif #include @@ -993,8 +993,8 @@ scan_triangulation_impl() # endif add_to_TLS_lists(true); - // PARALLEL_DO - tbb::parallel_do( + // PARALLEL FOR_EACH + tbb::parallel_for_each( this->r_tr_.finite_facets_begin(), this->r_tr_.finite_facets_end(), typename Rf_base::template Scan_facet(*this) ); diff --git a/Mesh_3/test/Mesh_3/CMakeLists.txt b/Mesh_3/test/Mesh_3/CMakeLists.txt index f30b1c82b46..bb118f9314b 100644 --- a/Mesh_3/test/Mesh_3/CMakeLists.txt +++ b/Mesh_3/test/Mesh_3/CMakeLists.txt @@ -127,8 +127,6 @@ if ( CGAL_FOUND ) execution___of__test_meshing_verbose execution___of__test_meshing_polyhedron_with_features execution___of__test_meshing_implicit_function - execution___of__test_meshing_3D_image - execution___of__test_meshing_3D_gray_image execution___of__test_meshing_unit_tetrahedron execution___of__test_meshing_polyhedron execution___of__test_meshing_polyhedral_complex @@ -136,7 +134,13 @@ if ( CGAL_FOUND ) execution___of__test_mesh_3_issue_1554 execution___of__test_mesh_polyhedral_domain_with_features_deprecated execution___of__test_mesh_cell_base_3 - PROPERTY RUN_SERIAL 1) + PROPERTY RUN_SERIAL 1) + if(TARGET test_meshing_3D_image) + set_property(TEST + execution___of__test_meshing_3D_image + execution___of__test_meshing_3D_gray_image + PROPERTY RUN_SERIAL 1) + endif() endif() endif() if(TARGET ITT::ITT) From 5896af796050810cf2584ae4d8f43dc785885f05 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Tue, 13 Jul 2021 11:49:51 +0200 Subject: [PATCH 284/349] Fix indentation --- .../CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h index 663c8b0fd62..7511346f1f3 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h @@ -59,7 +59,7 @@ namespace CGAL { // tbb::interface5::concurrent_hash_map template < class DSC, bool Const > std::size_t tbb_hasher(const std::pair, - CGAL::internal::CC_iterator >& p) + CGAL::internal::CC_iterator >& p) { return boost::hash, CGAL::internal::CC_iterator > >()(p); From f526f4941cb8278034de5b93d3c9a76daca5373a Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Thu, 15 Jul 2021 16:28:22 +0200 Subject: [PATCH 285/349] Do install demo/resources and demo/icons They are copied in cmake/modules/demo/ anyway. --- Installation/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/Installation/CMakeLists.txt b/Installation/CMakeLists.txt index e4d90fb23b6..dd47c660132 100644 --- a/Installation/CMakeLists.txt +++ b/Installation/CMakeLists.txt @@ -660,9 +660,6 @@ cache_get(CGAL_3RD_PARTY_LIBRARIES ) cache_get(CGAL_3RD_PARTY_LIBRARIES_DIRS) install(DIRECTORY "${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/" DESTINATION "${CGAL_INSTALL_INC_DIR}/CGAL/Qt" COMPONENT CGAL_Qt5) -install(DIRECTORY "${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/demo/resources/" DESTINATION "${CGAL_INSTALL_CMAKE_DIR}/demo/resources" COMPONENT CGAL_Qt5) -install(DIRECTORY "${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/demo/icons/" DESTINATION "${CGAL_INSTALL_CMAKE_DIR}/demo/icons" COMPONENT CGAL_Qt5) - # # Variables used when WITH_{demos|examples|tests} are TRUE From 5e17827c64430f0ed21fc01918498c95d72aef69 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Fri, 16 Jul 2021 12:17:55 +0200 Subject: [PATCH 286/349] fixed windows warnings and errors using unique ptrs --- .../CGAL/OSQP_quadratic_program_traits.h | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h index edcd3c34133..0439ce0d331 100644 --- a/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h +++ b/Solver_interface/include/CGAL/OSQP_quadratic_program_traits.h @@ -21,6 +21,7 @@ #include #include #include +#include // CGAL includes. #include @@ -192,27 +193,27 @@ public: CGAL_precondition(l_vec.size() == m && l_vec.size() == m); const c_int P_nnz = static_cast(P_vec.size()); - c_float P_x[P_nnz]; - c_int P_i[P_nnz]; - c_int P_p[n + 1]; - set_matrix_from_triplets("P", P_vec, P_x, P_i, P_p); + auto P_x = std::make_unique(P_nnz); + auto P_i = std::make_unique(P_nnz); + auto P_p = std::make_unique(n + 1); + set_matrix_from_triplets("P", P_vec, P_x.get(), P_i.get(), P_p.get()); if(verbose) std::cout << "P_nnz: " << P_nnz << std::endl; const c_int A_nnz = static_cast(A_vec.size()); - c_float A_x[A_nnz]; - c_int A_i[A_nnz]; - c_int A_p[n + 1]; - set_matrix_from_triplets("A", A_vec, A_x, A_i, A_p); + auto A_x = std::make_unique(A_nnz); + auto A_i = std::make_unique(A_nnz); + auto A_p = std::make_unique(n + 1); + set_matrix_from_triplets("A", A_vec, A_x.get(), A_i.get(), A_p.get()); if(verbose) std::cout << "A_nnz: " << A_nnz << std::endl; const c_int q_size = static_cast(q_vec.size()); const c_int l_size = static_cast(l_vec.size()); const c_int u_size = static_cast(u_vec.size()); - c_float q_x[q_size]; - c_float l_x[l_size]; - c_float u_x[u_size]; - set_qlu_data(q_x, l_x, u_x); + auto q_x = std::make_unique(q_size); + auto l_x = std::make_unique(l_size); + auto u_x = std::make_unique(u_size); + set_qlu_data(q_x.get(), l_x.get(), u_x.get()); // Problem settings. OSQPSettings *settings = (OSQPSettings *) malloc(sizeof(OSQPSettings)); @@ -226,15 +227,15 @@ public: // Populate data. data->n = static_cast(n); data->m = static_cast(m); - data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p); + data->P = csc_matrix(data->n, data->n, P_nnz, P_x.get(), P_i.get(), P_p.get()); CGAL_assertion(data->P); - data->q = q_x; - data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p); + data->q = q_x.get(); + data->A = csc_matrix(data->m, data->n, A_nnz, A_x.get(), A_i.get(), A_p.get()); CGAL_assertion(data->A); - data->l = l_x; - data->u = u_x; + data->l = l_x.get(); + data->u = u_x.get(); // Set solver settings. osqp_set_default_settings(settings); @@ -246,7 +247,7 @@ public: osqp_setup(&work, data, settings); // Solve problem. - int exitflag = -1; + c_int exitflag = -1; try { exitflag = osqp_solve(work); From 049e1a755194d15dba17df4705d545c5bc5f7fdf Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 19 Jul 2021 14:29:51 +0200 Subject: [PATCH 287/349] No more CGAL_NOEXCEPT --- Installation/include/CGAL/config.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Installation/include/CGAL/config.h b/Installation/include/CGAL/config.h index 0e8f442478d..c3d51a8f28a 100644 --- a/Installation/include/CGAL/config.h +++ b/Installation/include/CGAL/config.h @@ -614,10 +614,6 @@ namespace cpp11{ }//namespace cpp11 } //namespace CGAL -//Support for c++11 noexcept -#if !defined(BOOST_NO_NOEXCEPT) -#define CGAL_NOEXCEPT(x) noexcept(x) - // The fallthrough attribute // See for clang: // http://clang.llvm.org/docs/AttributeReference.html#statement-attributes From b2c07c7841a558421037d30b5df4138bf3b5f5cd Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 19 Jul 2021 14:50:59 +0200 Subject: [PATCH 288/349] fix config.h --- Installation/include/CGAL/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Installation/include/CGAL/config.h b/Installation/include/CGAL/config.h index c3d51a8f28a..71ab44bbad1 100644 --- a/Installation/include/CGAL/config.h +++ b/Installation/include/CGAL/config.h @@ -602,7 +602,6 @@ namespace CGAL { // Typedef for the type of nullptr. typedef const void * Nullptr_t; // Anticipate C++0x's std::nullptr_t - namespace cpp11{ #if CGAL_CXX20 || __cpp_lib_is_invocable>=201703L template class result_of; @@ -635,6 +634,7 @@ namespace cpp11{ # define CGAL_NO_ASSERTIONS_BOOL false #else # define CGAL_NO_ASSERTIONS_BOOL true +#endif #if defined( __INTEL_COMPILER) #define CGAL_ADDITIONAL_VARIANT_FOR_ICL ,int From 4296d0c37f8ec825a34f9949d29b7a5444f0cd70 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Tue, 20 Jul 2021 00:03:17 +0200 Subject: [PATCH 289/349] Change "ignore" to a function We don't care about the order, and this is less likely to warn. --- Filtered_kernel/include/CGAL/Lazy.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 8e2ca5a3bd5..0b25b2e30f5 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -233,8 +233,8 @@ templatevoid lazy_reset_member(T&t) { Lazy_reset_member_1()(t); } templatevoid lazy_reset_member_tuple(std::tuple&t, std::index_sequence) { - using ignore = int[]; - ignore { (lazy_reset_member(std::get(t)), 0) ... }; + auto ignore = [](auto&&...){}; + ignore ( (lazy_reset_member(std::get(t)), 0) ... ); } templatevoid lazy_reset_member(std::tuple&t) { lazy_reset_member_tuple(t, std::make_index_sequence()); From 5b0e0936d5a16681f4191df2352de16eb2ca7816 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Tue, 20 Jul 2021 11:52:18 +0200 Subject: [PATCH 290/349] Set CMP0064 to fix #5857 --- Installation/cmake/modules/CGAL_add_test.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/Installation/cmake/modules/CGAL_add_test.cmake b/Installation/cmake/modules/CGAL_add_test.cmake index 7090304dc26..0864203ae20 100644 --- a/Installation/cmake/modules/CGAL_add_test.cmake +++ b/Installation/cmake/modules/CGAL_add_test.cmake @@ -74,6 +74,7 @@ function(expand_list_with_globbing list_name) endfunction() function(cgal_add_compilation_test exe_name) + cmake_policy(SET CMP0064 NEW) if(NOT CMAKE_VS_MSBUILD_COMMAND) if(TEST compilation_of__${exe_name}) return() From e8993704e7e360bfa856e8dbb012db36b86c5ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 20 Jul 2021 12:09:55 +0200 Subject: [PATCH 291/349] remove no longer needed workaround it breaks code using the intel compiler on windows --- Number_types/include/CGAL/FPU.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Number_types/include/CGAL/FPU.h b/Number_types/include/CGAL/FPU.h index 6d5f02a3075..a9acf8c6057 100644 --- a/Number_types/include/CGAL/FPU.h +++ b/Number_types/include/CGAL/FPU.h @@ -326,11 +326,6 @@ inline double IA_bug_sqrt(double d) } # define CGAL_BUG_SQRT(d) IA_bug_sqrt(d) - - -#elif defined __SSE2_MATH__ -// For SSE2, we need to call __builtin_sqrt() instead of libc's sqrt(). -# define CGAL_BUG_SQRT(d) __builtin_sqrt(d) #elif defined __CYGWIN__ inline double IA_bug_sqrt(double d) { From 6bd71a349f12776ea4ca40b787dfdae5d01005e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 20 Jul 2021 20:55:10 +0200 Subject: [PATCH 292/349] fix test --- .../test_hausdorff_bounded_error_distance.cpp | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index f7d54f0a9e2..835f39f2eb1 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -1029,25 +1029,40 @@ void test_realizing_triangles( // Complex test. std::cout << std::endl << " ---- complex test ---- " << std::endl; + mesh1.clear(); + mesh2.clear(); const std::string filepath1 = "data/tetrahedron.off"; const std::string filepath2 = "data/tetrahedron-remeshed.off"; - get_meshes(filepath1, filepath2, mesh1, mesh2); + + std::array vhs1 = { + mesh1.add_vertex(Point_3(0, 1, 3)), + mesh1.add_vertex(Point_3(1, 1, 3)), + mesh1.add_vertex(Point_3(1, 0, 3)) + }; + mesh1.add_face(vhs1); + + std::array vhs2 = { + mesh2.add_vertex(Point_3(0, 1, 3.5)), + mesh2.add_vertex(Point_3(1, 1, 3.5)), + mesh2.add_vertex(Point_3(1, 0, 3.5)) + }; + mesh2.add_face(vhs2); + + Surface_mesh tmp1,tmp2; + get_meshes(filepath1, filepath2, tmp1, tmp2); PMP::transform(Affine_transformation_3( - CGAL::Translation(), Vector_3(0, 0, error_bound / 2.0)), mesh2); + CGAL::Translation(), Vector_3(0, 0, 10 * error_bound)), tmp2); + + + + mesh1.join(tmp1); + mesh2.join(tmp2); if (save) save_mesh(mesh1, "2mesh1"); if (save) save_mesh(mesh2, "2mesh2"); compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); - - mesh2.clear(); - get_mesh(filepath2, mesh2); - PMP::transform(Affine_transformation_3(CGAL::Translation(), - Vector_3(FT(0), FT(0), FT(1))), mesh2); - - if (save) save_mesh(mesh2, "2mesh2"); - compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save); } #if defined(CGAL_LINKED_WITH_TBB) && defined(CGAL_METIS_ENABLED) && defined(USE_PARALLEL_BEHD) From 7fbec6faaa81f84d9b7732414adab66cfae1c4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 20 Jul 2021 21:04:00 +0200 Subject: [PATCH 293/349] do not test the paper bench --- .../test_hausdorff_bounded_error_distance.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 835f39f2eb1..2877d226823 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -850,8 +850,8 @@ void test_bunny( const FunctionWrapper& functor, const int n = 5, const bool save = false) { std::cout.precision(20); - const std::string filepath1 = "data/bunny1.off"; // approx 16.3K - const std::string filepath2 = "data/bunny2.off"; // approx 69.4K + const std::string filepath1 = "data/bunny_16300.off"; // approx 16.3K + const std::string filepath2 = "data/bunny_69400.off"; // approx 69.4K std::cout << std::endl << "-- test bunny:" << std::endl << std::endl; std::cout << "* name -> " << functor.name() << std::endl; @@ -1234,7 +1234,7 @@ int main(int argc, char** argv) { // test_bunny(apprx_hd); // test_bunny(naive_hd); - test_bunny(bound_hd, 3); + // test_bunny(bound_hd, 3); // --- Test realizing triangles. test_realizing_triangles(error_bound); From d8a375badaa34b30fc1019d79ee4f041ae7b46a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 20 Jul 2021 21:41:54 +0200 Subject: [PATCH 294/349] generate the refine version of blobby --- .../test_hausdorff_bounded_error_distance.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 2877d226823..6d0ee789226 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -778,7 +778,11 @@ void test_timings(const std::string filepath, const FunctionWrapper& functor) { Timer timer; Surface_mesh mesh1, mesh2; - get_meshes(filepath, filepath, mesh1, mesh2); + get_mesh(filepath, mesh1); + PMP::isotropic_remeshing(faces(mesh1), 0.005, mesh1); + mesh1.collect_garbage(); + mesh2=mesh1; + timer.reset(); timer.start(); @@ -1224,8 +1228,7 @@ int main(int argc, char** argv) { // --- Compare timings. - filepath = (argc > 1 ? argv[1] : "data/blobby-remeshed.off"); - // filepath = "/Users/monet/Documents/fork/pull-requests/hausdorff/data/bunny-dense.off"; + filepath = (argc > 1 ? argv[1] : "data/blobby.off"); // test_timings(filepath, apprx_hd); // test_timings(filepath, naive_hd); test_timings(filepath, bound_hd); From f9444fa85d8aa3dcd708fc85eed9bfa8064b4fea Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Wed, 21 Jul 2021 11:03:36 +0200 Subject: [PATCH 295/349] CGAL depends on threads-support... for all compilers! --- .../modules/CGAL_SetupCGALDependencies.cmake | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake index 2d9617e447a..84225f4718d 100644 --- a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake +++ b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake @@ -102,6 +102,16 @@ function(CGAL_setup_CGAL_dependencies target) target_include_directories(${target} INTERFACE $) + # Make CGAL depend on threads-support (for Epeck and Epeck_d) + if(CGAL_HAS_NO_THREADS) + target_compile_definitions(${target} INTERFACE CGAL_HAS_NO_THREADS) + else() + if(NOT TARGET Threads::Threads) + find_package(Threads REQUIRED) + endif() + target_link_libraries(${target} INTERFACE Threads::Threads) + endif() + # Now setup compilation flags if(MSVC) target_compile_options(${target} INTERFACE @@ -144,14 +154,6 @@ function(CGAL_setup_CGAL_dependencies target) if ( RUNNING_CGAL_AUTO_TEST ) target_compile_options(${target} INTERFACE "-Wall") endif() - if(CGAL_HAS_NO_THREADS) - target_compile_definitions(${target} INTERFACE CGAL_HAS_NO_THREADS) - else() - if(NOT TARGET Threads::Threads) - find_package(Threads REQUIRED) - endif() - target_link_libraries(${target} INTERFACE Threads::Threads) - endif() if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3) message( STATUS "Using gcc version 4 or later. Adding -frounding-math" ) if(CMAKE_VERSION VERSION_LESS 3.3) From f8ebb779599ca8c1c5ae32cbf150978adf1e1832 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 21 Jul 2021 14:21:05 +0200 Subject: [PATCH 296/349] Fix test on CGAL_GCC_VERSION, that is 0 if the compiler is not GCC, not undefined --- Installation/include/CGAL/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Installation/include/CGAL/config.h b/Installation/include/CGAL/config.h index 71ab44bbad1..2fff6846f8a 100644 --- a/Installation/include/CGAL/config.h +++ b/Installation/include/CGAL/config.h @@ -489,7 +489,7 @@ using std::max; // Macro CGAL_ASSUME // Call a builtin of the compiler to pass a hint to the compiler -#if __has_builtin(__builtin_unreachable) || (!__STRICT_ANSI__) +#if __has_builtin(__builtin_unreachable) || (CGAL_GCC_VERSION > 0 && !__STRICT_ANSI__) // From g++ 4.5, there exists a __builtin_unreachable() // Also in LLVM/clang # define CGAL_ASSUME(EX) if(!(EX)) { __builtin_unreachable(); } From 8aa6bb3953eca55e5e1c84ac198db2be0325ff45 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 22 Jul 2021 09:00:21 +0200 Subject: [PATCH 297/349] fix test WKT. --- Stream_support/test/Stream_support/test_WKT.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Stream_support/test/Stream_support/test_WKT.cpp b/Stream_support/test/Stream_support/test_WKT.cpp index c9e356794d7..27ce052bd5e 100644 --- a/Stream_support/test/Stream_support/test_WKT.cpp +++ b/Stream_support/test/Stream_support/test_WKT.cpp @@ -119,14 +119,14 @@ Poly generate_polygon() border.push_back(br); Poly::Polygon_2 hole1; - hole1.emplace_back((xt+xmax)/2, (ymin+ymid)/2); - hole1.emplace_back((xt+xmax)/2, ymid); - hole1.emplace_back(xt+(xmax-xt)/4, (ymin+ymid)/2); + hole1.push_back(Point((xt+xmax)/2, (ymin+ymid)/2)); + hole1.push_back(Point((xt+xmax)/2, ymid)); + hole1.push_back(Point(xt+(xmax-xt)/4, (ymin+ymid)/2)); Poly::Polygon_2 hole2; - hole2.emplace_back((xt+xmin)/2, (ymin+ymid)/2); - hole2.emplace_back((xt+xmin)/2, ymid); - hole2.emplace_back(xmin+(xt-xmin)/4, (ymin+ymid)/2); + hole2.push_back(Point((xt+xmin)/2, (ymin+ymid)/2)); + hole2.push_back(Point((xt+xmin)/2, ymid)); + hole2.push_back(Point(xmin+(xt-xmin)/4, (ymin+ymid)/2)); Poly::Holes_container holes; holes.push_back(hole1); From 61ab2c1ed92f76a561e983cc911f6154dc18d51b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 22 Jul 2021 11:28:28 +0200 Subject: [PATCH 298/349] fix conversion warning --- .../test_hausdorff_bounded_error_distance.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp index 6d0ee789226..56c1557ca72 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_hausdorff_bounded_error_distance.cpp @@ -40,9 +40,9 @@ using Face_handle = typename boost::graph_traits::face_descriptor; namespace PMP = CGAL::Polygon_mesh_processing; struct Approximate_hd_wrapper { - const std::size_t m_num_samples; + const double m_num_samples; std::string name() const { return "approximate"; } - Approximate_hd_wrapper(const std::size_t num_samples) : m_num_samples(num_samples) { } + Approximate_hd_wrapper(const double num_samples) : m_num_samples(num_samples) { } double operator()(const Surface_mesh& tm1, const Surface_mesh& tm2) const { return PMP::approximate_Hausdorff_distance(tm1, tm2, PMP::parameters::number_of_points_per_area_unit(m_num_samples), @@ -1191,7 +1191,7 @@ int main(int argc, char** argv) { // std::cin >> name; const double error_bound = 1e-4; - const std::size_t num_samples = 1000; + const double num_samples = 10.; std::cout << std::endl << "* error bound: " << error_bound << std::endl; // std::cout << std::endl << "* number of samples: " << num_samples << std::endl; std::string filepath = (argc > 1 ? argv[1] : "data/blobby.off"); From af14540751e37768310857b12920eeb1d23a9a13 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Thu, 22 Jul 2021 17:05:43 +0200 Subject: [PATCH 299/349] Use THREADS_PREFER_PTHREAD_FLAG --- Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake index 84225f4718d..cb16e161fc7 100644 --- a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake +++ b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake @@ -107,6 +107,7 @@ function(CGAL_setup_CGAL_dependencies target) target_compile_definitions(${target} INTERFACE CGAL_HAS_NO_THREADS) else() if(NOT TARGET Threads::Threads) + set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) endif() target_link_libraries(${target} INTERFACE Threads::Threads) From 97cac65a86112bb20097d1a572c19734d8351835 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 23 Jul 2021 10:59:49 +0200 Subject: [PATCH 300/349] Fix __GNUC__ tests --- .../include/CGAL/Arr_point_location/Td_X_trapezoid.h | 2 +- .../include/CGAL/Arr_point_location/Td_active_edge.h | 2 +- .../CGAL/Arr_point_location/Td_active_fictitious_vertex.h | 2 +- .../include/CGAL/Arr_point_location/Td_active_trapezoid.h | 2 +- .../include/CGAL/Arr_point_location/Td_active_vertex.h | 2 +- .../include/CGAL/Arr_point_location/Td_inactive_edge.h | 2 +- .../Arr_point_location/Td_inactive_fictitious_vertex.h | 2 +- .../include/CGAL/Arr_point_location/Td_inactive_vertex.h | 2 +- Circular_kernel_2/benchmark/parser/benchmark_parser.cpp | 2 +- .../modules/config/support/CGAL_test_cpp_version.cpp | 2 +- Installation/include/CGAL/config.h | 8 ++++---- Installation/include/CGAL/internal/deprecation_warning.h | 2 +- Number_types/include/CGAL/FPU.h | 2 +- .../_test_cls_periodic_3_regular_triangulation_traits_3.h | 2 +- .../CGAL/_test_cls_periodic_3_triangulation_traits_3.h | 2 +- 15 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_X_trapezoid.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_X_trapezoid.h index 897f1e477fc..6f6f72a1678 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_X_trapezoid.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_X_trapezoid.h @@ -122,7 +122,7 @@ public: #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::Around_point_circulator; friend class Trapezoidal_decomposition_2::In_face_iterator; -#elif defined(__GNUC__) +#elif (__GNUC__ > 0) friend class Trapezoidal_decomposition_2::Around_point_circulator; friend class Trapezoidal_decomposition_2::In_face_iterator; diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_edge.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_edge.h index aa3087055e7..24ad3b4bf15 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_edge.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_edge.h @@ -94,7 +94,7 @@ public: #ifdef CGAL_PM_FRIEND_CLASS #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; -#elif defined(__GNUC__) +#elif (__GNUC__ > 0) friend class Trapezoidal_decomposition_2::In_face_iterator; #else friend class In_face_iterator; diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_fictitious_vertex.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_fictitious_vertex.h index 548070ce8be..e47760609a0 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_fictitious_vertex.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_fictitious_vertex.h @@ -94,7 +94,7 @@ public: #ifdef CGAL_PM_FRIEND_CLASS #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; -#elif defined(__GNUC__) +#elif (__GNUC__ > 0) friend class Trapezoidal_decomposition_2::In_face_iterator; #else friend class In_face_iterator; diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_trapezoid.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_trapezoid.h index d7d55a86846..e74b291ab06 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_trapezoid.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_trapezoid.h @@ -91,7 +91,7 @@ public: #ifdef CGAL_PM_FRIEND_CLASS #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; -#elif defined(__GNUC__) +#elif (__GNUC__ > 0) friend class Trapezoidal_decomposition_2::In_face_iterator; #else friend class In_face_iterator; diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_vertex.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_vertex.h index 05a416d1342..9486ddcc41d 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_vertex.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_active_vertex.h @@ -96,7 +96,7 @@ public: #ifdef CGAL_PM_FRIEND_CLASS #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; -#elif defined(__GNUC__) +#elif (__GNUC__ > 0) friend class Trapezoidal_decomposition_2::In_face_iterator; #else friend class In_face_iterator; diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_edge.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_edge.h index 5b49445fc5b..72497798323 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_edge.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_edge.h @@ -93,7 +93,7 @@ public: #ifdef CGAL_PM_FRIEND_CLASS #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; -#elif defined(__GNUC__) +#elif (__GNUC__ > 0) friend class Trapezoidal_decomposition_2::In_face_iterator; #else friend class In_face_iterator; diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_fictitious_vertex.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_fictitious_vertex.h index c61205c26cd..db7a89c8275 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_fictitious_vertex.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_fictitious_vertex.h @@ -96,7 +96,7 @@ public: #ifdef CGAL_PM_FRIEND_CLASS #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; -#elif defined(__GNUC__) +#elif (__GNUC__ > 0) friend class Trapezoidal_decomposition_2::In_face_iterator; #else friend class In_face_iterator; diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_vertex.h b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_vertex.h index 6a7e6c0eb05..e9dc3158554 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_vertex.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Td_inactive_vertex.h @@ -92,7 +92,7 @@ public: #ifdef CGAL_PM_FRIEND_CLASS #if defined(__SUNPRO_CC) || defined(__PGI) || defined(__INTEL_COMPILER) friend class Trapezoidal_decomposition_2::In_face_iterator; -#elif defined(__GNUC__) +#elif (__GNUC__ > 0) friend class Trapezoidal_decomposition_2::In_face_iterator; #else friend class In_face_iterator; diff --git a/Circular_kernel_2/benchmark/parser/benchmark_parser.cpp b/Circular_kernel_2/benchmark/parser/benchmark_parser.cpp index daab78244d1..a06431e837f 100644 --- a/Circular_kernel_2/benchmark/parser/benchmark_parser.cpp +++ b/Circular_kernel_2/benchmark/parser/benchmark_parser.cpp @@ -232,7 +232,7 @@ union yyalloc /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY -# if defined (__GNUC__) +# if (__GNUC__ > 0) # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else diff --git a/Installation/cmake/modules/config/support/CGAL_test_cpp_version.cpp b/Installation/cmake/modules/config/support/CGAL_test_cpp_version.cpp index 61d55a338b9..74d1f1c0247 100644 --- a/Installation/cmake/modules/config/support/CGAL_test_cpp_version.cpp +++ b/Installation/cmake/modules/config/support/CGAL_test_cpp_version.cpp @@ -18,7 +18,7 @@ int main() { #endif #if __has_feature(cxx_thread_local) || \ - ( defined(__GNUC__) && __cplusplus >= 201103L ) + ( __GNUC__ > 0 && __cplusplus >= 201103L ) return 0; #else return 1; diff --git a/Installation/include/CGAL/config.h b/Installation/include/CGAL/config.h index 2fff6846f8a..c406e4df1f9 100644 --- a/Installation/include/CGAL/config.h +++ b/Installation/include/CGAL/config.h @@ -223,7 +223,7 @@ #define CGAL_CFG_NO_TR1_ARRAY 1 // never use TR1 #define CGAL_CFG_NO_TR1_TUPLE 1 -#if !defined(__GNUC__) || defined(__INTEL_COMPILER) +#if (__GNUC__ <= 0) || defined(__INTEL_COMPILER) #define CGAL_CFG_NO_STATEMENT_EXPRESSIONS 1 #endif #if _MSC_VER==1800 @@ -509,20 +509,20 @@ using std::max; #endif #if __has_feature(cxx_thread_local) || \ - ( defined(__GNUC__) && __cplusplus >= 201103L ) || \ + ( (__GNUC__ > 0) && __cplusplus >= 201103L ) || \ ( _MSC_VER >= 1900 ) // see also Installation/cmake/modules/config/support/CGAL_test_cpp_version.cpp #define CGAL_CAN_USE_CXX11_THREAD_LOCAL #endif #if (__has_include() && __cplusplus >= 201103L ) | \ - ( defined(__GNUC__) && __cplusplus >= 201103L ) || \ + ( (__GNUC__ > 0) && __cplusplus >= 201103L ) || \ ( _MSC_VER >= 1700 ) #define CGAL_CAN_USE_CXX11_MUTEX #endif #if (__has_include() && __cplusplus >= 201103L ) || \ - ( defined(__GNUC__) && __cplusplus >= 201103L ) || \ + ( (__GNUC__ > 0) && __cplusplus >= 201103L ) || \ ( _MSC_VER >= 1700 ) #define CGAL_CAN_USE_CXX11_ATOMIC #endif diff --git a/Installation/include/CGAL/internal/deprecation_warning.h b/Installation/include/CGAL/internal/deprecation_warning.h index f0048e25b02..0206b562974 100644 --- a/Installation/include/CGAL/internal/deprecation_warning.h +++ b/Installation/include/CGAL/internal/deprecation_warning.h @@ -75,7 +75,7 @@ CGAL_static_assertion_msg(false, CGAL_INTERNAL_DEPRECATED_MESSAGE); #elif !defined(CGAL_NO_DEPRECATION_WARNINGS) // don't trigger on NO_DEPRECATION_WARNINGS # if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__) # pragma message (CGAL_INTERNAL_DEPRECATED_MESSAGE) -# elif defined(__GNUC__) || defined(__HP_aCC) || defined(__SUNPRO_CC) || defined(__IBMCPP__) +# elif (__GNUC__ > 0) || defined(__HP_aCC) || defined(__SUNPRO_CC) || defined(__IBMCPP__) // warning does not expand its arguments, issue a warning and add the message. # warning "A deprecated header has been included." # pragma message (CGAL_INTERNAL_DEPRECATED_MESSAGE) diff --git a/Number_types/include/CGAL/FPU.h b/Number_types/include/CGAL/FPU.h index 8a8cd8a5fea..e5ffa3fcd1f 100644 --- a/Number_types/include/CGAL/FPU.h +++ b/Number_types/include/CGAL/FPU.h @@ -172,7 +172,7 @@ inline double IA_opacify(double x) // Intel has a bug where -mno-sse still defines __SSE__ and __SSE2__ // (-mno-sse2 works though), no work-around for now. # if defined __SSE2_MATH__ || (defined __INTEL_COMPILER && defined __SSE2__) -# if defined(__GNUC__) +# if (__GNUC__ > 0) // ICEs in reload/LRA with older versions. asm volatile ("" : "+gx"(x) ); # else diff --git a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h index 61a9aaf0a80..a7297b25ee9 100644 --- a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h +++ b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h @@ -10,7 +10,7 @@ // Author(s) : Aymeric PELLE // Mael Rouxel-LabbĂ© -#if defined(__GNUC__) +#if (__GNUC__ > 0) # pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif diff --git a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h index c8ee3c576c6..fef5f500309 100644 --- a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h +++ b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h @@ -11,7 +11,7 @@ // Author(s) : Mariette Yvinec // Manuel Caroli -#if defined(__GNUC__) +#if (__GNUC__ > 0) # pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif From eb4d2953d5f774ecacaeeaa1b065aa27c6021842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 23 Jul 2021 12:14:32 +0200 Subject: [PATCH 301/349] Fix index maps for non-const Face_filtered_graph --- .../CGAL/boost/graph/Face_filtered_graph.h | 135 ++++++++++++------ 1 file changed, 88 insertions(+), 47 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h index c7a8182d68d..982adf381bc 100644 --- a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h +++ b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h @@ -1206,40 +1206,6 @@ CGAL_FFG_DYNAMIC_PMAP_SPEC(dynamic_face_property_t) #undef CGAL_FFG_DYNAMIC_PMAP_SPEC -//specializations for indices -template -typename boost::property_map, CGAL::face_index_t >::type -get(CGAL::face_index_t, const Face_filtered_graph& w) -{ - return w.get_face_index_map(); -} - - -template -typename boost::property_map, boost::vertex_index_t >::type -get(boost::vertex_index_t, const Face_filtered_graph& w) -{ - return w.get_vertex_index_map(); -} - - -template -typename boost::property_map, CGAL::halfedge_index_t >::type -get(CGAL::halfedge_index_t, const Face_filtered_graph& w) -{ - return w.get_halfedge_index_map(); -} - - template struct property_map, CGAL::face_index_t> { - typedef typename CGAL::Face_filtered_graph::FIM FIM; + typedef CGAL::Face_filtered_graph FFG; + typedef typename FFG::FIM FIM; + + typedef typename boost::property_traits::value_type Face_index; + typedef typename CGAL::dynamic_face_property_t Face_index_dtag; + typedef typename boost::property_map::type type; + typedef typename CGAL::Property_map_binder::value_type>::type> type; - typedef type const_type; + typename boost::property_traits::value_type>::type> const_type; }; template struct property_map, boost::vertex_index_t> { - typedef typename CGAL::Face_filtered_graph::VIM VIM; + typedef CGAL::Face_filtered_graph FFG; + typedef typename FFG::VIM VIM; + + typedef typename boost::property_traits::value_type Vertex_index; + typedef typename CGAL::dynamic_vertex_property_t Vertex_index_dtag; + typedef typename boost::property_map::type type; + typedef typename CGAL::Property_map_binder::value_type>::type> type; - typedef type const_type; + typename boost::property_traits::value_type>::type> const_type; }; -template +template struct property_map, CGAL::halfedge_index_t> { - typedef typename CGAL::Face_filtered_graph::HIM HIM; + typedef CGAL::Face_filtered_graph FFG; + typedef typename FFG::HIM HIM; + + typedef typename boost::property_traits::value_type Halfedge_index; + typedef typename CGAL::dynamic_halfedge_property_t Halfedge_index_dtag; + typedef typename boost::property_map::type type; + typedef typename CGAL::Property_map_binder::value_type>::type> type; - typedef type const_type; + typename boost::property_traits::value_type>::type> const_type; }; } // namespace boost +namespace CGAL { + +//specializations for indices +template +typename boost::property_map, CGAL::face_index_t >::const_type +get(CGAL::face_index_t, const Face_filtered_graph& w) +{ + return w.get_face_index_map(); +} + +template +typename boost::property_map, boost::vertex_index_t >::const_type +get(boost::vertex_index_t, const Face_filtered_graph& w) +{ + return w.get_vertex_index_map(); +} + +template +typename boost::property_map, CGAL::halfedge_index_t >::const_type +get(CGAL::halfedge_index_t, const Face_filtered_graph& w) +{ + return w.get_halfedge_index_map(); +} + +// non-const (dynamic pmap) +template +typename boost::property_map, CGAL::face_index_t >::type +get(CGAL::face_index_t, Face_filtered_graph& w) +{ + typedef CGAL::Face_filtered_graph FFG; + typedef typename boost::property_map::type result_type; + typedef typename boost::property_traits::value_type Index; + typedef typename CGAL::dynamic_face_property_t Index_dtag; + + return get(Index_dtag(), w.graph()); +} + +template +typename boost::property_map, boost::vertex_index_t >::type +get(boost::vertex_index_t, Face_filtered_graph& w) +{ + typedef CGAL::Face_filtered_graph FFG; + typedef typename boost::property_map::type result_type; + typedef typename boost::property_traits::value_type Index; + typedef typename CGAL::dynamic_vertex_property_t Index_dtag; + + return get(Index_dtag(), w.graph()); +} + +template +typename boost::property_map, CGAL::halfedge_index_t >::type +get(CGAL::halfedge_index_t, Face_filtered_graph& w) +{ + typedef CGAL::Face_filtered_graph FFG; + typedef typename boost::property_map::type result_type; + typedef typename boost::property_traits::value_type Index; + typedef typename CGAL::dynamic_halfedge_property_t Index_dtag; + + return get(Index_dtag(), w.graph()); +} + +} // namespace CGAL + #endif // CGAL_BOOST_GRAPH_FACE_FILTERED_GRAPH_H From 4d471cf1399aa9e7e92d771dc458678b228c713f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 23 Jul 2021 12:15:42 +0200 Subject: [PATCH 302/349] Enhance tests for Face_filtered_graph --- BGL/test/BGL/test_Face_filtered_graph.cpp | 152 +++++++++++++--------- 1 file changed, 87 insertions(+), 65 deletions(-) diff --git a/BGL/test/BGL/test_Face_filtered_graph.cpp b/BGL/test/BGL/test_Face_filtered_graph.cpp index 0a579fe96cc..10e3086476d 100644 --- a/BGL/test/BGL/test_Face_filtered_graph.cpp +++ b/BGL/test/BGL/test_Face_filtered_graph.cpp @@ -1,15 +1,23 @@ -#include -#include #include +#include +#include +#include +#include #include "test_Prefix.h" + #include #include #include -#include + #include +#include +#include +#include typedef boost::unordered_set id_map; +namespace PMP = CGAL::Polygon_mesh_processing; + template void test_halfedge_around_vertex_iterator(const Graph& g) { @@ -17,8 +25,7 @@ void test_halfedge_around_vertex_iterator(const Graph& g) typedef CGAL::Face_filtered_graph Adapter; CGAL_GRAPH_TRAITS_MEMBERS(Adapter); boost::unordered_map map(num_faces(g)); - CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); - + PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); Adapter fg(g, 0, boost::make_assoc_property_map(map)); typename boost::graph_traits::vertex_iterator vit, vend; @@ -45,8 +52,9 @@ void test_halfedge_around_face_iterator(const Graph& g) typedef CGAL::Face_filtered_graph Adapter; CGAL_GRAPH_TRAITS_MEMBERS(Adapter); std::map map; - CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); Adapter fg(g, 0, boost::make_assoc_property_map(map)); + face_iterator fit, fend; for(boost::tie(fit, fend) = faces(fg); fit != fend; ++fit) { halfedge_around_face_iterator hafit, hafend; @@ -65,7 +73,7 @@ void test_edge_iterators(const Graph& g) typedef CGAL::Face_filtered_graph Adapter; CGAL_GRAPH_TRAITS_MEMBERS(Adapter); std::map map; - CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); Adapter fg(g, 0, boost::make_assoc_property_map(map)); // do we iterate as many as that? @@ -91,7 +99,7 @@ void test_vertex_iterators(Graph& g) typedef CGAL::Face_filtered_graph Adapter; CGAL_GRAPH_TRAITS_MEMBERS(Adapter); std::map map; - CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); Adapter fg(g, 0, boost::make_assoc_property_map(map)); vertex_iterator vb, ve; std::size_t count = 0; @@ -121,7 +129,7 @@ void test_out_edges(const Graph& g) typedef CGAL::Face_filtered_graph Adapter; CGAL_GRAPH_TRAITS_MEMBERS(Adapter); std::map map; - CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); Adapter fg(g, 0, boost::make_assoc_property_map(map)); vertex_iterator vb, ve; @@ -150,7 +158,7 @@ void test_in_edges(const Graph& g) typedef CGAL::Face_filtered_graph Adapter; CGAL_GRAPH_TRAITS_MEMBERS(Adapter); std::map map; - CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); Adapter fg(g, 0, boost::make_assoc_property_map(map)); vertex_iterator vb, ve; @@ -177,7 +185,7 @@ void test_in_out_edges(const Graph& g) typedef CGAL::Face_filtered_graph Adapter; CGAL_GRAPH_TRAITS_MEMBERS(Adapter); std::map map; - CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); Adapter fg(g, 0, boost::make_assoc_property_map(map)); // check that the sets of in out edges are the same @@ -219,7 +227,7 @@ void test_edge_find(const Graph& g) typedef CGAL::Face_filtered_graph Adapter; CGAL_GRAPH_TRAITS_MEMBERS(Adapter); std::map map; - CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); Adapter fg(g, 0, boost::make_assoc_property_map(map)); typedef std::pair ret; @@ -243,7 +251,7 @@ void test_faces(const Graph& g) typedef CGAL::Face_filtered_graph Adapter; CGAL_GRAPH_TRAITS_MEMBERS(Adapter); std::map map; - CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); Adapter fg(g, 0, boost::make_assoc_property_map(map)); unsigned int count = 0; @@ -262,6 +270,45 @@ void test_faces(const Graph& g) assert(count == num_faces(fg)); } +template +void test_index_property_maps(const Graph& g) +{ + typedef CGAL::Face_filtered_graph Adapter; + CGAL_GRAPH_TRAITS_MEMBERS(Adapter); + + typedef typename boost::graph_traits::face_descriptor g_face_descriptor; + std::map map; + PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); + Adapter fg(g, 0, boost::make_assoc_property_map(map)); + + // Non const + typedef typename CGAL::GetInitializedVertexIndexMap::type VIMap; + VIMap vim = CGAL::get_initialized_vertex_index_map(fg); + assert(CGAL::BGL::internal::is_index_map_valid(vim, num_vertices(fg), vertices(fg))); + + typedef typename CGAL::GetInitializedHalfedgeIndexMap::type HIMap; + HIMap him = CGAL::get_initialized_halfedge_index_map(fg); + assert(CGAL::BGL::internal::is_index_map_valid(him, num_halfedges(fg), halfedges(fg))); + + typedef typename CGAL::GetInitializedFaceIndexMap::type FIMap; + FIMap fim = CGAL::get_initialized_face_index_map(fg); + assert(CGAL::BGL::internal::is_index_map_valid(fim, num_faces(fg), faces(fg))); + + // Const + const Adapter cfg(g, 0, boost::make_assoc_property_map(map)); + typedef typename CGAL::GetInitializedVertexIndexMap::const_type CVIMap; + CVIMap cvim = CGAL::get_initialized_vertex_index_map(cfg); + assert(CGAL::BGL::internal::is_index_map_valid(cvim, num_vertices(cfg), vertices(cfg))); + + typedef typename CGAL::GetInitializedHalfedgeIndexMap::const_type CHIMap; + CHIMap chim = CGAL::get_initialized_halfedge_index_map(cfg); + assert(CGAL::BGL::internal::is_index_map_valid(chim, num_halfedges(cfg), halfedges(cfg))); + + typedef typename CGAL::GetInitializedFaceIndexMap::const_type CFIMap; + CFIMap cfim = CGAL::get_initialized_face_index_map(cfg); + assert(CGAL::BGL::internal::is_index_map_valid(cfim, num_faces(cfg), faces(cfg))); +} + template void test_read(const Graph& g) { @@ -270,7 +317,7 @@ void test_read(const Graph& g) CGAL_GRAPH_TRAITS_MEMBERS(Adapter); std::map map; - CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); + PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); Adapter fg(g, 0, boost::make_assoc_property_map(map)); assert(fg.is_selection_valid()); assert(CGAL::is_valid_polygon_mesh(fg)); @@ -292,6 +339,7 @@ test_graph_range(const std::vector& graphs) test_edge_iterators(p); test_halfedge_around_face_iterator(p); test_halfedge_around_vertex_iterator(p); + test_index_property_maps(p); } } @@ -356,7 +404,6 @@ struct Constraint : public boost::put_get_helper void test_mesh(Adapter fga) { - CGAL_GRAPH_TRAITS_MEMBERS(Adapter); //check that there is the right number of simplices in fga CGAL_assertion(CGAL::is_valid_polygon_mesh(fga)); @@ -365,31 +412,23 @@ void test_mesh(Adapter fga) CGAL_assertion(num_halfedges(fga) == 10); CGAL_assertion(num_vertices(fga) == 4); halfedge_descriptor h = halfedge(*faces(fga).first, fga); - CGAL_assertion_code( vertex_descriptor v = source(h, fga) ); + CGAL_assertion_code( vertex_descriptor v = source(h, fga)); //check that next() works inside the patch - CGAL_assertion( - next(next(next(h, fga), fga), fga) == h - ); + CGAL_assertion(next(next(next(h, fga), fga), fga) == h); //check that next() works on bordure of the patch h = opposite(h, fga); - CGAL_assertion( - next(next(next(next(h, fga), fga), fga), fga) == h - ); + CGAL_assertion(next(next(next(next(h, fga), fga), fga), fga) == h); //check that prev() works inside the patch h = halfedge(*faces(fga).first, fga); - CGAL_assertion( - prev(prev(prev(h, fga), fga), fga) == h - ); + CGAL_assertion(prev(prev(prev(h, fga), fga), fga) == h); //check that prev() works on bordure of the patch h = opposite(h, fga); - CGAL_assertion( - prev(prev(prev(prev(h, fga), fga), fga), fga) == h - ); + CGAL_assertion(prev(prev(prev(prev(h, fga), fga), fga), fga) == h); //check degree CGAL_assertion(degree(v, fga) == 3); //check in_edges and out_edges - CGAL_assertion(std::distance(in_edges(v, fga).first ,in_edges(v, fga).second) == 3 ); - CGAL_assertion(std::distance(out_edges(v, fga).first ,out_edges(v, fga).second) == 3 ); + CGAL_assertion(std::distance(in_edges(v, fga).first ,in_edges(v, fga).second) == 3); + CGAL_assertion(std::distance(out_edges(v, fga).first ,out_edges(v, fga).second) == 3); Mesh copy; CGAL::copy_face_graph(fga, copy); @@ -454,7 +493,7 @@ int main() { test_graph_range(poly_data()); -#if defined(CGAL_USE_SURFACE_MESH) +#ifdef CGAL_USE_SURFACE_MESH test_graph_range(sm_data()); #endif @@ -464,64 +503,47 @@ int main() test_invalid_selections(); - //Make a tetrahedron and test the adapter for a patch that only contains 2 faces + // Make a tetrahedron and test the adapter for a patch that only contains 2 faces typedef CGAL::Face_filtered_graph SM_Adapter; typedef SM::Property_map::face_descriptor , std::size_t> SM_FCCMap; auto sm = std::make_unique(); - CGAL::make_tetrahedron( - Point_3(1,1,1), - Point_3(0,0,0), - Point_3(0,0,1), - Point_3(1,0,1), - *sm); - SM_FCCMap fccmap = - sm->add_property_map::face_descriptor, std::size_t>("f:CC").first; - SM::Property_map::vertex_descriptor, SM::Point> positions = - sm->points(); - CGAL::Polygon_mesh_processing::connected_components(*sm, fccmap, CGAL::Polygon_mesh_processing::parameters:: - edge_is_constrained_map(Constraint::vertex_descriptor, - SM::Point> >(*sm, positions))); + CGAL::make_tetrahedron(Point_3(1,1,1), Point_3(0,0,0), Point_3(0,0,1), Point_3(1,0,1), *sm); + + SM_FCCMap fccmap = sm->add_property_map::face_descriptor, std::size_t>("f:CC").first; + SM::Property_map::vertex_descriptor, SM::Point> positions = sm->points(); + CGAL::Polygon_mesh_processing::connected_components( + *sm, fccmap, CGAL::parameters::edge_is_constrained_map(Constraint::vertex_descriptor, + SM::Point> >(*sm, positions))); + boost::unordered_set pids; pids.insert(0); pids.insert(2); SM_Adapter sm_adapter(*sm, pids, fccmap); test_mesh(sm_adapter); - - - typedef boost::graph_traits PolyTraits; typedef boost::property_map::const_type VPMap; typedef PolyTraits::face_descriptor poly_face_descriptor; - typedef boost::associative_property_map< std::map > FCMap; + typedef boost::associative_property_map > FCMap; typedef boost::property_map::const_type FIMap; typedef boost::property_map::const_type VIMap; typedef boost::property_map::const_type HIMap; typedef CGAL::Face_filtered_graph Poly_Adapter; - auto poly = std::make_unique(); - CGAL::make_tetrahedron( - Point_3(1,1,1), - Point_3(0,0,0), - Point_3(0,0,1), - Point_3(1,0,1), - *poly); + auto poly = std::make_unique(); + CGAL::make_tetrahedron(Point_3(1,1,1), Point_3(0,0,0), Point_3(0,0,1), Point_3(1,0,1), *poly); FIMap poly_fimap = get(CGAL::face_external_index, *poly); VIMap poly_vimap = get(CGAL::vertex_external_index, *poly); HIMap poly_himap = get(CGAL::halfedge_external_index, *poly); - std::map fc_map; + std::map fc_map; FCMap poly_fccmap(fc_map); VPMap vpmap = get(boost::vertex_point, *poly); - CGAL::Polygon_mesh_processing::connected_components(*poly, poly_fccmap, - CGAL::Polygon_mesh_processing::parameters::edge_is_constrained_map(Constraint(*poly, vpmap)) - .face_index_map(poly_fimap)); - Poly_Adapter poly_adapter(*poly, - pids, - poly_fccmap, + PMP::connected_components(*poly, poly_fccmap, + CGAL::parameters::edge_is_constrained_map(Constraint(*poly, vpmap)) + .face_index_map(poly_fimap)); + Poly_Adapter poly_adapter(*poly, pids, poly_fccmap, CGAL::parameters::face_index_map(poly_fimap) .vertex_index_map(poly_vimap) .halfedge_index_map(poly_himap)); From d8717289fdccb1a5da8ca7bca606820855e53ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 23 Jul 2021 13:09:37 +0200 Subject: [PATCH 303/349] Add missing functions to complete Rule of 3 for ToS2's triangulations --- .../include/CGAL/Delaunay_triangulation_on_sphere_2.h | 10 ++++++++++ .../include/CGAL/Triangulation_on_sphere_2.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/Triangulation_on_sphere_2/include/CGAL/Delaunay_triangulation_on_sphere_2.h b/Triangulation_on_sphere_2/include/CGAL/Delaunay_triangulation_on_sphere_2.h index 33a14b828e7..35600bdd788 100644 --- a/Triangulation_on_sphere_2/include/CGAL/Delaunay_triangulation_on_sphere_2.h +++ b/Triangulation_on_sphere_2/include/CGAL/Delaunay_triangulation_on_sphere_2.h @@ -147,6 +147,16 @@ public: { } + // Assignement + Delaunay_triangulation_on_sphere_2& operator=(Delaunay_triangulation_on_sphere_2 other) // intentional copy + { + Base::swap(static_cast(other)); + return *this; + } + + // Destructor + ~Delaunay_triangulation_on_sphere_2() = default; + // Predicates & Constructions Oriented_side side_of_oriented_circle(const Point& p, const Point& q, const Point& r, const Point& s, bool perturb = false) const; Oriented_side side_of_oriented_circle(const Face_handle f, const Point& p, bool perturb = false) const; diff --git a/Triangulation_on_sphere_2/include/CGAL/Triangulation_on_sphere_2.h b/Triangulation_on_sphere_2/include/CGAL/Triangulation_on_sphere_2.h index 9d8aac545a7..0de37519ad3 100644 --- a/Triangulation_on_sphere_2/include/CGAL/Triangulation_on_sphere_2.h +++ b/Triangulation_on_sphere_2/include/CGAL/Triangulation_on_sphere_2.h @@ -127,6 +127,9 @@ public: void swap(Triangulation_on_sphere_2& tr); Triangulation_on_sphere_2& operator=(Triangulation_on_sphere_2 tr); // intentional copy + // Destructor + ~Triangulation_on_sphere_2() = default; + public: // Members const Geom_traits& geom_traits() const { return _gt; } From 026907a9ce6af096af7b6821f24a3728e190ef79 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 19 Feb 2021 12:44:42 +0100 Subject: [PATCH 304/349] =?UTF-8?q?#=20Ceci=20est=20la=20combinaison=20de?= =?UTF-8?q?=207=20commits.=20#=20Ceci=20est=20le=20premier=20message=20de?= =?UTF-8?q?=20validation=C2=A0:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First step of action # Ceci est le message de validation numĂ©ro 2 : add ssh stuff # Ceci est le message de validation numĂ©ro 3 : Update github action # Ceci est le message de validation numĂ©ro 4 : Fix Logic # Ceci est le message de validation numĂ©ro 5 : Don't override the PATH !!! # Ceci est le message de validation numĂ©ro 6 : Download the known host too, so it is possible to add new IPs in it. # Ceci est le message de validation numĂ©ro 7 : Fix GIT path and better management of VERSION_NUMBER --- .github/workflows/filter_testsuite.yml | 99 +++++++++++++++++++ .../run_testsuite_from_branch_name.sh | 69 +++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 .github/workflows/filter_testsuite.yml create mode 100644 Scripts/developer_scripts/run_testsuite_from_branch_name.sh diff --git a/.github/workflows/filter_testsuite.yml b/.github/workflows/filter_testsuite.yml new file mode 100644 index 00000000000..f2eb2dd589e --- /dev/null +++ b/.github/workflows/filter_testsuite.yml @@ -0,0 +1,99 @@ +name: Filter Testsuite + +on: + issue_comment: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v3 + id: check + with: + result-encoding: string + script: | + const userName = context.payload.comment.user.login + if(userName == 'maxGimeno') { + const body = context.payload.comment.body + if(body.includes("/testme")) { + return 'OK' + } + } + return 'stop' + - uses: actions/github-script@v3 + if: steps.check.result != 'stop' + id: get_label + with: + result-encoding: string + script: | + //get branch name and username + const pr_url = context.payload.issue.pull_request.url + const pr_content = await github.request(pr_url) + const label = pr_content.data.head.label + console.log(label) + return label + - uses: actions/github-script@v3 + if: steps.check.result != 'stop' + id: get_base + with: + result-encoding: string + script: | + //get branch name and username + const pr_url = context.payload.issue.pull_request.url + const pr_content = await github.request(pr_url) + const base = pr_content.data.base.ref + console.log(base) + return base + - name: Run Testsuite + if: steps.check.outputs.result != 'stop' + run: | + mkdir -p ~/.ssh + #ssh key + ( + cat <> ~/.ssh/id_rsa + chmod 600 /home/runner/.ssh/id_rsa + #ssh public key + ( + cat <> ~/.ssh/id_rsa.pub + chmod 644 /home/runner/.ssh/id_rsa.pub + #known hosts + wget --no-check-certificate https://cgal.geometryfactory.com/CGAL/ssh_known_hosts -O ~/.ssh/known_hosts + #config file + wget --no-check-certificate https://cgal.geometryfactory.com/CGAL/ssh_config -O ~/.ssh/config + #list of hosts + wget --no-check-certificate https://cgal.geometryfactory.com/CGAL/ssh_host_list -O ~/ssh_host_list + #ssh command + LABEL="${{ steps.get_label.outputs.result }}" + USER_NAME=$(echo $LABEL | cut -d':' -f 1) + BRANCH_NAME=$(echo $LABEL | cut -d':' -f 2) + BASE="${{ steps.get_base.outputs.result }}" + mapfile -t HOSTS < ~/ssh_host_list; + LAST_INDEX=$((${#HOSTS[@]}-1)) + for i in ${!HOSTS[@]}; do + HOST=$(echo ${HOSTS[$i]}|cut -d' ' -f 1 ) + PATH_TO_SCRIPT=$(echo ${HOSTS[$i]}|cut -d' ' -f 2 ) + if [ "$i" -ne "$LAST_INDEX" ] ; then + ssh ${HOST} "${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE" + else + ssh ${HOST} "${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE y" + fi + done + - name: Post address + uses: actions/github-script@v3 + if: steps.check.outputs.result != 'stop' + with: + script: | + const address = "The testsuite is lauched. results will be found, after it is done, here : https://cgal.geometryfactory.com/~mgimeno/test_suite/TESTRESULTS/index.shtml " + github.issues.createComment({ + owner: "maxGimeno", + repo: "cgal", + issue_number: ${{ github.event.issue.number }}, + body: address + }); diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh new file mode 100644 index 00000000000..99b59fc1fe6 --- /dev/null +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +#To run: $1 = name of the user +# $2 = name of the branch +# $3 = base ref name (master, 5.1.x, 5.2.x, etc...) +# $4 = if given, update the VERSION_NUMBER + + +if uname | grep -q -i cygwin; then + #Is supposed to ignore \r as eol character. + export SHELLOPTS + set -o igncr +fi +source "$(dirname $0)/.autofilterrc" +USER_REPO=$1 +BRANCH_NAME=$2 +BASE_NAME=$3 +cd ${CGAL_ROOT} +scp mgimeno@cgal.geometryfactory.com:public_html/test_suite/VERSION_NUMBER . +cd ${CGAL_GIT_DIR} +if [ ! -d cgal ]; then + git clone --depth 1 --no-single-branch https://github.com/CGAL/cgal.git + cd cgal + git remote rename origin cgal + cd .. +fi +cd cgal +git fetch --depth 1 cgal +git remote add $USER_REPO https://github.com/$USER_REPO/cgal.git +git fetch --depth 1 $USER_REPO +git checkout $BRANCH_NAME +git reset --hard $USER_REPO/$BRANCH_NAME +#setup the list_test_packages +LIST_OF_PKGS=$(git diff --name-only HEAD cgal/$BASE_NAME |cut -s -d/ -f1 |sort -u | xargs -I {} ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true) +if [ "$LIST_OF_PKGS" != "" ]; then + if [ -f ${CGAL_ROOT}/list_test_packages ]; then rm ${CGAL_ROOT}/list_test_packages; fi + for f in $LIST_OF_PKGS + do + echo "echo \"$f\"" >> ${CGAL_ROOT}/list_test_packages + echo "echo \"${f}_Examples\"" >> ${CGAL_ROOT}/list_test_packages + echo "echo \"${f}_Demo\"" >> ${CGAL_ROOT}/list_test_packages + done +fi +( +#create the release from the branch +echo " Create release..." +cmake -DGIT_REPO=${CGAL_GIT_DIR}/cgal -DDESTINATION=${CGAL_ROOT}/CGAL-TEST -DPUBLIC=OFF -DTESTSUITE=ON -DCGAL_VERSION=0.0-Ic-$(cat ${CGAL_ROOT}/VERSION_NUMBER) -P ${CGAL_GIT_DIR}/cgal/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake | tee log +echo "done." +DEST=$(sed -E 's/.*CGAL-TEST\/(.*)/\1/' log); + +cd ${CGAL_ROOT} + +if [ -L CGAL-I ]; then rm CGAL-I; fi +ln -s $PWD/CGAL-TEST/$DEST CGAL-I +echo "starting testsuite..." + +./autotest_cgal -c +)>${CGAL_ROOT}/autotest.log2 2>&1 & +echo "finished." +if [ -n "$4" ]; then + cd ${CGAL_ROOT} + V=$(cat VERSION_NUMBER) + V=$(($V+1)) + echo $V > VERSION_NUMBER + scp VERSION_NUMBER mgimeno@cgal.geometryfactory.com:public_html/test_suite/VERSION_NUMBER +fi + +echo "exit." +exit 0 From 7a526ea537963a09b0886a1139ca190e8f3a0050 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 23 Jul 2021 14:14:31 +0200 Subject: [PATCH 305/349] First step of action add ssh stuff Update github action Fix Logic Don't override the PATH !!! Download the known host too, so it is possible to add new IPs in it. Fix GIT path and better management of VERSION_NUMBER fix autotest_cgal Fixes for scripts --- .github/workflows/filter_testsuite.yml | 9 +++++---- Scripts/developer_scripts/autotest_cgal | 16 ++++++++++------ .../run_testsuite_from_branch_name.sh | 13 ++++++++----- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/.github/workflows/filter_testsuite.yml b/.github/workflows/filter_testsuite.yml index f2eb2dd589e..61ff21ff405 100644 --- a/.github/workflows/filter_testsuite.yml +++ b/.github/workflows/filter_testsuite.yml @@ -75,14 +75,15 @@ jobs: BRANCH_NAME=$(echo $LABEL | cut -d':' -f 2) BASE="${{ steps.get_base.outputs.result }}" mapfile -t HOSTS < ~/ssh_host_list; - LAST_INDEX=$((${#HOSTS[@]}-1)) for i in ${!HOSTS[@]}; do HOST=$(echo ${HOSTS[$i]}|cut -d' ' -f 1 ) PATH_TO_SCRIPT=$(echo ${HOSTS[$i]}|cut -d' ' -f 2 ) - if [ "$i" -ne "$LAST_INDEX" ] ; then - ssh ${HOST} "${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE" - else + if [ "$i" -ne "0" ] ; then + echo "ssh ${HOST} ${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE y" ssh ${HOST} "${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE y" + else + echo "ssh ${HOST} ${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE y" + ssh ${HOST} "${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE" fi done - name: Post address diff --git a/Scripts/developer_scripts/autotest_cgal b/Scripts/developer_scripts/autotest_cgal index 619f9fea761..4ad3e7b8b1a 100755 --- a/Scripts/developer_scripts/autotest_cgal +++ b/Scripts/developer_scripts/autotest_cgal @@ -380,6 +380,8 @@ setup_dirs() CGAL_DIR=`readlink "${CGAL_ROOT}/CGAL-I"` CGAL_TEST_DIR=${CGAL_DIR}/test + CGAL_DATA_DIR=${CGAL_DIR}/data + export CGAL_DATA_DIR=$(echo "$CGAL_DATA_DIR" | sed -E 's/\/cygdrive\/([a-z])\//\U\1:\//') if [ ! -d "${CGAL_DIR}/cmake" ]; then mkdir "${CGAL_DIR}/cmake" @@ -619,28 +621,28 @@ LIST_TEST_PACKAGES='${LIST_TEST_PACKAGES}' CGAL_ROOT='${CGAL_ROOT}' rm -rf '${CGAL_BINARY_DIR}/test'; - if [ -f '${LIST_TEST_PACKAGES}' ]; then - mkdir '${CGAL_BINARY_DIR}/test' cp '${CGAL_TEST_DIR}/collect_cgal_testresults_from_cmake' '${CGAL_BINARY_DIR}/test' cp '${CGAL_TEST_DIR}/makefile2' '${CGAL_BINARY_DIR}/test' cp '${CGAL_TEST_DIR}/run_testsuite_with_cmake' '${CGAL_BINARY_DIR}/test' - # list all packages in CGAL_TEST_DIR. If PACKAGE is found in LIST_TEST_PACKAGES, - # copy it, else prepare for the special "skipped" case in the table. +# list all packages in CGAL_TEST_DIR. If PACKAGE is found in LIST_TEST_PACKAGES, +# copy it, else prepare for the special "skipped" case in the table. for PACKAGE in \$(ls "${CGAL_TEST_DIR}"); do if [ -d "${CGAL_TEST_DIR}/\$PACKAGE" ]; then if source '${LIST_TEST_PACKAGES}' '${CGAL_ROOT}' | egrep -q \$PACKAGE; then - mkdir "\${CGAL_BINARY_DIR}/test/\${PACKAGE}" + mkdir "${CGAL_BINARY_DIR}/test/\${PACKAGE}" + cp -r "${CGAL_TEST_DIR}/\${PACKAGE}" '${CGAL_BINARY_DIR}/test' + elif [ "\$PACKAGE" = "resources" ]; then + mkdir "${CGAL_BINARY_DIR}/test/\${PACKAGE}" cp -r "${CGAL_TEST_DIR}/\${PACKAGE}" '${CGAL_BINARY_DIR}/test' else mkdir "${CGAL_BINARY_DIR}/test/\${PACKAGE}" touch "${CGAL_BINARY_DIR}/test/\${PACKAGE}/skipped" fi fi - done else @@ -768,6 +770,7 @@ run_test_on_host() fi for PLATFORM in ${PLATFORMS}; do + run_test_on_host_and_platform "${HOST}" "${PLATFORM}" publish_results "${HOST}" "${PLATFORM}" done @@ -985,3 +988,4 @@ rm -f "$LOCK_FILE"; ## Local Variables: ## sh-basic-offset: 2 ## End: + diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index 99b59fc1fe6..a19a6ca4ee7 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -11,12 +11,13 @@ if uname | grep -q -i cygwin; then export SHELLOPTS set -o igncr fi -source "$(dirname $0)/.autofilterrc" +source ~/.autofilterrc +echo "CGAL_ROOT = $CGAL_ROOT" > log USER_REPO=$1 BRANCH_NAME=$2 BASE_NAME=$3 cd ${CGAL_ROOT} -scp mgimeno@cgal.geometryfactory.com:public_html/test_suite/VERSION_NUMBER . +scp ${VERSION_NUMBER_SSH_URL} . cd ${CGAL_GIT_DIR} if [ ! -d cgal ]; then git clone --depth 1 --no-single-branch https://github.com/CGAL/cgal.git @@ -44,6 +45,7 @@ fi ( #create the release from the branch echo " Create release..." +echo "CGAL_VERSION=0.0-Ic-$(cat ${CGAL_ROOT}/VERSION_NUMBER)"> log cmake -DGIT_REPO=${CGAL_GIT_DIR}/cgal -DDESTINATION=${CGAL_ROOT}/CGAL-TEST -DPUBLIC=OFF -DTESTSUITE=ON -DCGAL_VERSION=0.0-Ic-$(cat ${CGAL_ROOT}/VERSION_NUMBER) -P ${CGAL_GIT_DIR}/cgal/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake | tee log echo "done." DEST=$(sed -E 's/.*CGAL-TEST\/(.*)/\1/' log); @@ -55,15 +57,16 @@ ln -s $PWD/CGAL-TEST/$DEST CGAL-I echo "starting testsuite..." ./autotest_cgal -c -)>${CGAL_ROOT}/autotest.log2 2>&1 & -echo "finished." + if [ -n "$4" ]; then cd ${CGAL_ROOT} V=$(cat VERSION_NUMBER) V=$(($V+1)) echo $V > VERSION_NUMBER - scp VERSION_NUMBER mgimeno@cgal.geometryfactory.com:public_html/test_suite/VERSION_NUMBER + scp VERSION_NUMBER ${VERSION_NUMBER_SSH_URL} fi +)>${CGAL_ROOT}/autotest.log2 2>&1 & +echo "finished." echo "exit." exit 0 From 4635ac2e15b08743941a4120dae406e4a4ce919c Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 23 Jul 2021 12:05:49 +0200 Subject: [PATCH 306/349] Add files for testresults Add test collection script odifications for "skipped" fixes on conditions --- .github/workflows/filter_testsuite.yml | 4 +- .../filter_testsuite/create_testresult_page | 705 ++++++++++++++++++ .../filter_testsuite/testresult.css | 74 ++ .../filter_testsuite/to_zipped_format | 232 ++++++ .../filter_testsuite/treat_result_collection | 185 +++++ .../run_testsuite_from_branch_name.sh | 2 +- .../test/collect_cgal_testresults_from_cmake | 5 +- 7 files changed, 1203 insertions(+), 4 deletions(-) create mode 100755 Maintenance/test_handling/filter_testsuite/create_testresult_page create mode 100644 Maintenance/test_handling/filter_testsuite/testresult.css create mode 100755 Maintenance/test_handling/filter_testsuite/to_zipped_format create mode 100755 Maintenance/test_handling/filter_testsuite/treat_result_collection diff --git a/.github/workflows/filter_testsuite.yml b/.github/workflows/filter_testsuite.yml index 61ff21ff405..3c2e6364c05 100644 --- a/.github/workflows/filter_testsuite.yml +++ b/.github/workflows/filter_testsuite.yml @@ -78,11 +78,11 @@ jobs: for i in ${!HOSTS[@]}; do HOST=$(echo ${HOSTS[$i]}|cut -d' ' -f 1 ) PATH_TO_SCRIPT=$(echo ${HOSTS[$i]}|cut -d' ' -f 2 ) - if [ "$i" -ne "0" ] ; then + if [ "$i" = "0" ] ; then echo "ssh ${HOST} ${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE y" ssh ${HOST} "${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE y" else - echo "ssh ${HOST} ${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE y" + echo "ssh ${HOST} ${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE" ssh ${HOST} "${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE" fi done diff --git a/Maintenance/test_handling/filter_testsuite/create_testresult_page b/Maintenance/test_handling/filter_testsuite/create_testresult_page new file mode 100755 index 00000000000..399e57d5ddd --- /dev/null +++ b/Maintenance/test_handling/filter_testsuite/create_testresult_page @@ -0,0 +1,705 @@ +#!/usr/bin/env perl +# +# first author: Geert-Jan Giezeman +# recent maintainer: Laurent Rineau (2009-2011) +# +# This script creates a WWW page with a table of test suite results. +# +# Usage: +# create_testresult_page + +# Creates the following files : +# - results-$version.shtml +# - versions.inc (contains the version selector) +# - index.shtml -> results-$version.shtml (symlink) + +use Cwd; +use strict; +use Date::Format; + +my $test_results_url="https://cgal.geometryfactory.com/~mgimeno/test_suite/TESTRESULTS/index.shtml"; + +my ($PLATFORMS_BESIDE_RESULTS, $PLATFORMS_REF_BETWEEN_RESULTS)=(1,1); + +my $TEMPPAGE="tmp$$.html"; +my $TEMPPAGE2="tmp2$$.html"; +my $release_name; +my @platforms_to_do; +my @known_platforms; +my %platform_short_names; +my %platform_is_optimized; +my %platform_is_64bits; +my @available_platforms; +my %test_directories = (); +my @testresults; +my $testresult_dir=cwd()."/TESTRESULTS"; + +# Inspired from +# http://cpansearch.perl.org/src/EDAVIS/Sort-Versions-1.5/Versions.pm +sub sort_releases($$) +{ + # Take arguments in revert order: one wants to sort from the recent to + # the old releases. + my $b = $_[0]; + my $a = $_[1]; + + #take only the numbers from release id, skipping the bug-fix + #number, and I and Ic + my @A = ($a =~ /(\d+)\.(\d+)\.?(:?\d+)?(:?-Ic?-)?(\d+)?/a); + my @B = ($b =~ /(\d+)\.(\d+)\.?(:?\d+)?(:?-Ic?-)?(\d+)?/a); + + while(@A and @B) { + my $av = shift(@A); + my $bv = shift(@B); + #$av and $bv are integers + if($av == $bv) { next; } + return $av <=> $bv; + } + return @A <=> @B; +} + +sub write_selects() +{ + print OUTPUTV "

    You can browse the test results of a different version :

    "; + my %releases; + foreach $_ (glob("results-*.shtml")) { + $_ =~ /results-(\d+.\d+)([^I]*)((-Ic?)-([^I].*))\.shtml/a; + $releases{"$1"}=1; + } + print OUTPUTV "\n"; + print OUTPUTV " \n"; + my $count = 0; + foreach $_ (sort sort_releases (keys %releases)) { + print OUTPUTV " \n"; + $count++ > 3 && last; + } + print OUTPUTV "\n"; + print OUTPUTV "\n"; + write_select("sel"); + $count = 0; + foreach $_ (sort sort_releases (keys %releases)) { + write_select("sel" . $count, $_); + $count++ > 3 && last; + } + print OUTPUTV "\n
    All releases (last one)CGAL-$_
    \n"; +} + +sub write_select() +{ + my $id = shift(@_); + my $pattern = ".*"; + if (@_ != 0) { + $pattern = quotemeta(shift(@_)); + } + my($filename, @result); + print OUTPUTV " "; +} + +sub list_platforms() +{ + my ($filename, @result); + foreach $_ (glob("results_*.txt")) { + ($filename) = m/results_(.*?)\.txt\s*/; + push(@result, $filename) if $filename; + } + return @result; +} + +sub list_packages($) +# +# Fill %test_directories with the packages found in the argument platform. +# Return false if that platform does not have a list of packages. +{ + my ($platform) = @_; + my $test_result="results_${platform}.txt"; + open(TESTRESULT, $test_result) or return 0; + while () { + if (/^\s*(.*?)\s+(\w)\s*$/) { + $test_directories{$1} = ''; + } + } + close TESTRESULT or return 0; + return 1; +} + +sub collect_results_of_platform($) +{ + my ($platform) = @_; +# Create an anonymous hash that hashes packages to their result. + my $platform_results = {}; + my $test_result="results_${platform}.txt"; + my ($yeahs, $nays, $warnings,$reqs, $skips) = (0,0,0,0,0); + my $resulttext; + open(TESTRESULT, $test_result) or return $platform_results; + while () { + if (/^\s*(.*?)\s+(\w)\s*$/) { + #($package,$succes) = ($1,$2); + if ($2 eq 'y' or $2 eq 'Y') { + $resulttext = 'y'; + ++$yeahs; + } elsif ($2 eq 'w' or $2 eq 'W') { + $resulttext = 'w'; + ++$warnings; + } elsif ($2 eq 'n' or $2 eq 'N') { + $resulttext = 'n'; + ++$nays; + } elsif ($2 eq 'r') { + $resulttext = 'r'; + ++$reqs; + } elsif ($2 eq 's') { + $resulttext = 's'; + ++$skips; + } else { + $resulttext = ' '; + } + $platform_results->{$1} = $resulttext; + } + } + close TESTRESULT; + $platform_results->{"y"} = $yeahs; + $platform_results->{"n"} = $nays; + $platform_results->{"w"} = $warnings; + $platform_results->{"r"} = $reqs; + $platform_results->{"s"} = $skips; + return $platform_results; +} + +sub collect_results() +{ + my $platform; + foreach $platform (@platforms_to_do) { + list_packages($platform); + } + foreach $platform (@platforms_to_do) { + push(@testresults, collect_results_of_platform($platform)); + } +} + +sub print_result_table() +{ + my $platform_count = scalar(@platforms_to_do); + + print OUTPUT <<"EOF"; + + + + + + + +EOF + + print_platforms_numbers(); + + print OUTPUT "\n"; + my $test_directory; + my $test_num = 0; + foreach $test_directory (sort keys %test_directories) { + if ($PLATFORMS_REF_BETWEEN_RESULTS) { + $test_num++; + if ($test_num == 15) { + $test_num = 0; + print OUTPUT "\n\n"; + } + } + # my $version; + # if ( -r "$test_directory/version" ) { + # open(VERSION, "$test_directory/version"); + # while() { + # ($version) = /^\s*([^\s]*)\s/; + # last if $version; + # } + # close VERSION; + # } + print OUTPUT "\n\n"; + print OUTPUT "\n"; + # if ( $version ) { + # print OUTPUT "\n"; + # } else { + # print OUTPUT "\n"; + # } + my ($platform_num,$platform)=(0,""); + $platform_num=0; + foreach $platform (@platforms_to_do) { + my ($result,$resulttext); + $resulttext = $testresults[$platform_num]->{$test_directory}; + if (! defined($resulttext)) { + $resulttext = ' '; + } + print OUTPUT '\n"; + ++$platform_num; + + } + print OUTPUT "\n"; + } + print OUTPUT "
    PackageTest Platform
    \n"; + print OUTPUT 'Platform Description'; + print OUTPUT "\n"; + print_platforms_numbers(); + print OUTPUT "\n
    $test_directory$version?.? ', "$resulttext
    \n"; +} + +sub print_resultpage() +{ + my $platform_count = scalar(@platforms_to_do); + + print OUTPUT '

    Test Results

    '."\n"; + print OUTPUT '

    In the table below, each column is numbered, and corresponds to a platform. '; + print OUTPUT 'Each column number is a link to the platform description table.

    ', "\n"; + if ($PLATFORMS_BESIDE_RESULTS) { + print OUTPUT <<"EOF"; + + +\n
    +EOF + } + + print_result_table(); + + if ($PLATFORMS_BESIDE_RESULTS) { + print OUTPUT "\n\n"; + if ($platform_count > 0) { + my $repeat_count = (1 + 1.1/16.5)*scalar(keys %test_directories)/($platform_count+0.25); + while ($repeat_count >= 1) { + $repeat_count--; + print OUTPUT "\n"; + } + } + print OUTPUT "
    \n"; + print_platforms(); + print OUTPUT "
    \n
    \n"; + } +} + +sub sort_pf +{ + # MSVS first + if($a =~ m/^MS/) { + if($b =~ m/^MS/) { + return $a cmp $b; + } + else + { + return -1; + } + } + if($b =~ m/^MS/) { return 1; } + + # g++/gcc second + if($a =~ m/^g[c+][c+]/) { + if($b =~ m/^g[c+][c+]/) { + return $a cmp $b; + } + else + { + return -1; + } + } + if($b =~ m/^g[c+][c+]/) { return 1; } + + # Intel third + if($a =~ m/^[iI]/) { + if($b =~ m/^[iI]/) { + return $a cmp $b; + } + else + { + return -1; + } + } + if($b =~ m/^[iI]/) { return 1; } + + # SunPro last + if($a =~ m/^[Ss][uU[Nn]/) { + if($b =~ m/^[Ss][uU[Nn]/) { + return $a cmp $b; + } + else + { + return 1; + } + } + if($b =~ m/^[Ss][uU[Nn]/) { return -1; } + + return $a cmp $b; +} + +sub parse_platform($) +{ + my ($pf) = @_; + $pf =~ s/_LEDA$//; + my @list = split /_/, $pf; + return @list; +} + +sub parse_platform_2($) +{ + my ($pf) = @_; + my @list = parse_platform($pf); +# if (@list > 3) { +# splice(@list,0,@list-3); +# } + while (@list < 3) { + push(@list,'?'); + } + return @list; +} + +sub short_pfname($) +{ + my @pflist = parse_platform_2($_[0]); + my $shortpf; + if(@pflist < 4) { + $shortpf = join('_', $pflist[1], $pflist[2]); + } + elsif($pflist[2] !~ /Linux/i) { + $shortpf = join('_', $pflist[3], $pflist[2]); + if(@pflist >= 5) { + $shortpf = join('_', $shortpf, $pflist[4]); + } + } + else { + $shortpf = $pflist[3]; + if(@pflist >= 5) { + $shortpf = join('_', $shortpf, $pflist[4]); + } + } + return $shortpf; +} + +sub choose_platforms() +{ + my (%platform_index, $pf); +# List all platforms for which there are results + @available_platforms = list_platforms(); + my $index = 0; +# Put all known platforms in a hash table. + for ($index=0; $index < @known_platforms; $index += 1) { + $pf = $known_platforms[$index]; + $platform_index{$pf} = 1; + } +# Check if there are platforms listed that are not known. Warn about this +# and add those platforms at the end of the list of known platforms. + foreach (@available_platforms) { + $pf = $_; + my $shortpf = short_pfname($pf); + $pf =~ s/^[^_]*_//; + $pf =~ s/_LEDA$//; + if (!exists $platform_index{$shortpf}) { + # print STDERR "Warning: Platform $_ is unknown!\n"; + $platform_index{$shortpf} = 1; + push(@known_platforms,$shortpf); # ??? + $platform_short_names{$shortpf} = $shortpf; + } + } + +# Make a list of all the platforms that are to be treated, in the order they +# appear in the list of known_platforms. + @platforms_to_do = (); + @known_platforms = sort sort_pf @known_platforms; + for ($index=0; $index < @known_platforms; $index += 1) { + $pf = $known_platforms[$index]; + my $ind2 = 0; + foreach (@available_platforms) { + my $apf = short_pfname($_); + if ($apf eq $pf) { + push(@platforms_to_do, $_); + } + } + } +} + +sub print_platform_descriptions() +{ + my ($i,$pf_no,$pf) = (0,1); + print OUTPUT <<'EOF'; +

    Platform Description and Summary

    + + + + + + + + + + + + + + + + + + +EOF + my ($platform_num)=(0); + foreach $pf (@platforms_to_do) { + my $pf_num_plus_one = $platform_num + 1; + print OUTPUT "\n\n"; + print OUTPUT "\n"; + print OUTPUT "\n"; + print OUTPUT "\n"; + print OUTPUT "\n"; + print OUTPUT "\n"; + print OUTPUT "\n"; + $index = 8; + while ($index) { + $index--; + $_ = $tmp[$index]; + if($index > 2) { + print OUTPUT "\n"; + } else { + print OUTPUT "\n"; + } + } + } else { + print OUTPUT ">$pf_short"; + my $index = 12; + while ($index) { + print OUTPUT "\n"; + } + } + ++$platform_num; + } + print OUTPUT "
    OS and compilerTesterywnrsCMakeBOOSTMPFRGMPQT5LEDACXXFLAGSLDFLAGS
    $pf_no\n"; + $pf_no++; + # my $pf_short = join('_',parse_platform_2($pf)); + (my $pf_short) = ($pf =~ m/_(.*)/); + print OUTPUT "; # CGAL_VERSION + $_ = ; # COMPILER + chomp; + my $compiler = $_; + print OUTPUT " title=\"$compiler\">$pf_short"; + $_ = ; # TESTER_NAME + chomp; + my $tester_name = $_; + $_ = ; # TESTER_ADDRESS + chomp; + my $tester_address = $_; + + my $county = $testresults[$platform_num]->{"y"}; + my $countw = $testresults[$platform_num]->{"w"}; + my $countn = $testresults[$platform_num]->{"n"}; + my $countr = $testresults[$platform_num]->{"r"}; + my $counts = $testresults[$platform_num]->{"s"}; + + my $index = 8; + my @tmp; + while ($index) { + $index--; + $_ = ; + chomp; + $tmp[$index] = $_; + } + ($platform_is_optimized{$pf}) = ($tmp[1] =~ m|([-/]x?O[1-9])|); + $_ = ; + chomp; + print OUTPUT "$tester_name$county$countw$countn$countr$counts$_$_?
    \n

    \n"; +} + +sub print_platforms_numbers() +{ + my ($platform_num,$platform)=(0,""); + foreach $platform (@platforms_to_do) { + ++$platform_num; + my $pf_short = short_pfname($platform); + my $class = ""; + my $tag = ""; + if($platform_is_optimized{$platform} || $platform_is_64bits{$platform}) + { + $class = " class=\""; + $tag = " ( "; + if($platform_is_64bits{$platform}) { + $class = "$class os64bits"; + $tag = $tag . "64 bits "; + } + if($platform_is_optimized{$platform}) { + $class = "$class highlight"; + $tag = $tag ." optimized: $platform_is_optimized{$platform}"; + } + $class = $class . "\""; + $tag = $tag . " )"; + } + print OUTPUT "$platform_num\n"; + } +} + +sub print_platforms() +{ + my ($pf_no,$pf) = (1,""); + print OUTPUT '',"\n"; + foreach $pf (@platforms_to_do) { + print OUTPUT "\n\n"; + } + print OUTPUT "
    $pf_no\n"; + $pf_no++; + my $pf_short = short_pfname($pf); + print OUTPUT "$platform_short_names{$pf_short}"; + print OUTPUT "\n
    \n"; +} + +sub result_filename($) +{ + return "results".substr($_[0],4).".shtml"; +# $name =~ s/-Ic?-/-/; +} + + +sub print_little_header(){ + + my $release_version = substr($release_name, 5); + print OUTPUT<<"EOF"; + + + + + ${release_name} Test Results + + + + + +

    Test Results of ${release_name} + +jump to results

    + +

    The results of the tests are presented in a table +('y' = success, 'w' = warning, 'n' = failure, 'r' = a requirement is not found, 's' = package skipped by tester), +and the error + compiler output from each test can be retrieved by clicking +on it.

    +

    N.B. The detection of warnings is not exact. +Look at the output to be sure!

    +
      +EOF + if ( -r "announce.html" ) { + print OUTPUT<<"EOF"; +
    1. Announcement of this release
    2. +EOF + } + + print OUTPUT "
    \n"; +} + + +sub main() +{ + if (scalar(@ARGV) != 1 ) { + print STDERR "usage: $0 directory\n"; + exit 1; + } + + $release_name =shift(@ARGV); + + $release_name =~ s<(\s+)$><>; + $release_name =~ s<(/)$><>; + chdir $testresult_dir or die; + if ( ! -d $release_name ) { + print STDERR "$release_name is not a valid directory\n"; + exit 1; + } + +# init_known_platforms(); + chdir $testresult_dir or die; + chdir $release_name or die; + choose_platforms(); + chdir ".."; + + umask 0022; + unlink $TEMPPAGE; + unlink $TEMPPAGE2; + open(OUTPUT,">$TEMPPAGE") or die; + open(OUTPUTV,">$TEMPPAGE2") or die; + chdir $testresult_dir or die; + chdir $release_name or die; + collect_results(); + print_little_header(); + print_platform_descriptions(); + print_resultpage(); + + print OUTPUT << 'EOF'; +

    This page has been created by the test results + collection scripts (in trunk/Maintenance/test_handling). + See the log here.

    + +

    + ">Valid HTML 4.01 Strict +

    +EOF + print OUTPUT "\n\n"; + + close OUTPUT; + chdir ".."; + + my $WWWPAGE = result_filename($release_name); + rename $TEMPPAGE, $WWWPAGE; + chmod 0644, $WWWPAGE; + unlink "index.shtml"; + symlink $WWWPAGE, "index.shtml"; + + # Deal with the versions.inc file. + write_selects(); + my $VERSIONS_WEBPAGE="versions.inc"; + rename $TEMPPAGE2, $VERSIONS_WEBPAGE; + chmod 0644, $VERSIONS_WEBPAGE; +} + +sub init_known_platforms() +{ + my ($short_name, $full_name); + open(PLATFORMS,'known_platforms') or die; + @known_platforms = (); + while() { + ($short_name, $full_name) =split; + $full_name = short_pfname($full_name); + push(@known_platforms,$full_name); + $platform_short_names{$full_name} = $full_name; + } + close(PLATFORMS); +} + +main(); diff --git a/Maintenance/test_handling/filter_testsuite/testresult.css b/Maintenance/test_handling/filter_testsuite/testresult.css new file mode 100644 index 00000000000..f45f172b5ff --- /dev/null +++ b/Maintenance/test_handling/filter_testsuite/testresult.css @@ -0,0 +1,74 @@ +body {color: black; background-color: #C0C0D0; font-family: sans-serif;} + +P { +width: 80ex +} + +A { + text-decoration: none; +} + +TABLE.result { font-weight: bold; background-color: white; padding: 1em; table-layout: fixed;} + +TABLE.summary TD { white-space: nowrap } +TABLE.result,TABLE.summary { border-collapse: collapse; } +TABLE.result TD,TABLE.summary TD { border-width: 1px; border-style: solid; } +TABLE.result TD { padding: 0;} +TABLE.result TD > a { font-weight: normal; font-family: monospace; display: block; padding: 0.2ex 0.5ex 0.2ex 0.5ex;} + +TABLE.beside TABLE { border-collapse: collapse; font-family: monospace; } + +TABLE.beside TABLE TD { padding: 0.2ex 0.5ex 0.2ex 0.5ex; } + +TD.highlight {background-color: rgb(80%,80%,80%)} +TD.os64bits {font-style:italic} +.cmaketag {font-weight: bold; color: rgb(100%,20%,20%);} + + +TD.ok {background-color: rgb(50%,100%,50%)} +TD.warning {background-color: rgb(100%,100%,50%)} +TD.error {background-color: rgb(100%,50%,50%)} +TD.na {background-color: white;} +TD.requirements { background-color: rgb(65%,65%,100%) } +TD.skip { background-color: rgb(90%,100%,100%) } + +TH.ok {background-color: rgb(50%,100%,50%)} +TH.warning {background-color: rgb(100%,100%,50%)} +TH.error {background-color: rgb(100%,50%,50%)} +TH.requirements { background-color: rgb(65%,65%,100%) } +TH.skip { background-color: rgb(90%,100%,100%) } + +TD.ok A {font-size:large; text-decoration: none} +TD.ok A:link {color: rgb(0%,0%,100%)} +TD.ok A:visited {color: rgb(0%,80%,100%)} + +TD.warning A {font-size:large; text-decoration: none} +TD.warning A:link {color: rgb(0%,0%,100%)} +TD.warning A:visited {color: rgb(80%,80%,100%)} + +TD.error A {font-size: large; text-decoration: none} +TD.error A:link {color: rgb(0%,0%,100%)} +TD.error A:visited {color: rgb(80%,0%,100%)} + +TD.requirements A {font-size: large; text-decoration: none} +TD.requirements A:link {color: rgb(0%,0%,100%)} +TD.requirements A:visited {color: rgb(100%,100%,65%)} +TD.skip A {font-size: large; text-decoration: none} + +SELECT { font-family: monospace; } + +#permalink,#jump_to_results { + font-size: 0.5em; + font-weight: normal; +} +#permalink::before,#jump_to_results::before{ + content: "(" +} +#permalink::after,#jump_to_results::after{ + content: ")" +} + +TABLE.result TD > a.package_name { + color: black; + font-weight: bold; +} diff --git a/Maintenance/test_handling/filter_testsuite/to_zipped_format b/Maintenance/test_handling/filter_testsuite/to_zipped_format new file mode 100755 index 00000000000..d8c7c1cd433 --- /dev/null +++ b/Maintenance/test_handling/filter_testsuite/to_zipped_format @@ -0,0 +1,232 @@ +#!/usr/bin/env perl + +use Cwd; +use strict; + +my $TMPDIR; +my $version = ""; +my $final_version; + +my $original_arguments=join(" ", @ARGV); + +sub print_log +{ + print TESTRESULTSLOG (@_); +} + +sub print_log_err +{ + print TESTRESULTSLOG (@_); + print STDERR (@_); +} + +sub usage { + print STDERR "$0: usage\n"; + print STDERR "$0 [-v version] result1.tar[.gz] ...\n"; + print STDERR "$0: you called it with the arguments:\n"; + print STDERR "$0 $original_arguments\n"; +} + +sub make_tempdir() +{ + my $dirno = 1; + $TMPDIR = "TMP$dirno"; + while ( -f $TMPDIR or -d $TMPDIR ) { + ++$dirno; + $TMPDIR = "TMP$dirno"; + } + mkdir($TMPDIR,0770) or die "Cannot create temporary directory $TMPDIR\n"; +} + +sub reformat_results($) +{ + $_ = shift; + s/\.tar//; + my $platform = $_; +# system("dos2unix ${platform}.txt ${platform}.txt"); + open (PLATFORM_RESULTS,"<${platform}.txt") or return; + my $line; + while ( ($line = ) && /^\s*$/) { + } + $_ = $line; + open (PLATFORM_INFO,">${platform}.info") or return; + open (PLATFORM_NEW_RESULTS,">${platform}.new_results") or return; + my ($CGAL_VERSION,$LEDA_VERSION,$COMPILER,$TESTER_NAME,$TESTER_ADDRESS,$GMP,$MPFR,$ZLIB,$OPENGL,$BOOST,$QT,$QT4,$QT5,$CMAKE) = ("-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","no"); + my ($LDFLAGS,$CXXFLAGS) = ("", ""); + while (! /^------/) { + if(/^\s*$/) { + goto NEXT; + } + if(/^-- USING CMake version: ([\w\.-]+)/) { + $CMAKE = $1; + } + if (/^CGAL_VERSION\s+([\w\.-]+)/) { + $CGAL_VERSION = $1; + } + if (/LEDA_VERSION = '([^']+)'/) { + $LEDA_VERSION="$1"; + } + if (/LEDAWIN_VERSION = '([^']+)'/) { + $LEDA_VERSION="$LEDA_VERSION+win"; + } + if (/COMPILER_VERSION = '([^']+)'/) { + $COMPILER = $1; + } + if (/^TESTER_NAME\s+(.*)$/) { + $TESTER_NAME = $1; + } + if (/^TESTER_ADDRESS\s+(.*)$/) { + $TESTER_ADDRESS = $1; + } + if (/MPFR_VERSION = '([^']+)'/) { + $MPFR="$1"; + } + if (/ZLIB_VERSION = '([^']+)'/) { + $ZLIB="$1"; + } + if (/OPENGL_VERSION = '([^']+)'/) { + $OPENGL="$1"; + } + if (/GMP_VERSION = '([^']+)'/) { + $GMP="$1"; + } + if (/GMPXX_VERSION = '([^']+)'/) { + $GMP="$GMP+gmpxx"; + } + if (/QT_VERSION = '([^']+)'/) { + $QT="$1"; + } + if (/QT4_VERSION = '([^']+)'/) { + $QT4="$1"; + } + if (/Qt5_VERSION = '([^']+)'/) { + $QT5="$1"; + } + if (/BOOST_VERSION = '([^']+)'/) { + $BOOST="$1"; + } +# if (/BOOST_THREAD_VERSION = '([^']+)'/) { +# $BOOST="$BOOST+thread"; +# } +# if (/BOOST_PROGRAM_OPTIONS_VERSION = '([^']+)'/) { +# $BOOST="$BOOST+program_options"; +# } +# if (/BOOST_BIMAP_VERSION = '([^']+)'/) { +# $BOOST="$BOOST+bimap"; +# } + if (/USING +CXXFLAGS = '([^']*)'/) { + $CXXFLAGS="$CXXFLAGS $1"; + } + if (/USING +LDFLAGS = '([^']*)'/) { + $LDFLAGS="$LDFLAGS $1"; + } +# if(/^CGAL_TEST_PLATFORM /) { +# # should be the last one of the header +# last; +# } +# if(! /^[A-Z][a-z]/ ) { +# # the header is finished +# print PLATFORM_NEW_RESULTS $_; +# last; +# } +NEXT: if(! ($_= )) { + # should never happen!! + last; + } + } + while () { + print PLATFORM_NEW_RESULTS $_; + } + rename("${platform}.new_results","${platform}.txt") or die "cannot rename!"; + print PLATFORM_INFO <<"EOF"; +$CGAL_VERSION +$COMPILER +$TESTER_NAME +$TESTER_ADDRESS +$CMAKE +$BOOST +$MPFR +$GMP +$QT5 +$LEDA_VERSION +$CXXFLAGS +$LDFLAGS +EOF + close(PLATFORM_INFO); + close(PLATFORM_RESULTS); + close(PLATFORM_NEW_RESULTS); + $final_version="CGAL-$CGAL_VERSION"; + if ($version + && $version ne "CGAL-$CGAL_VERSION" + && ($version !~ /^CGAL-${CGAL_VERSION}-Ic?-[\d]+$/)) { + die "Wrong version in $platform: $CGAL_VERSION instead of $version.\n"; + } +} + +sub one_archive($) +{ + my $archive = shift; + if (! -f $archive) { + print STDERR "$archive is not a valid filename\n"; + return 0; + } + if ( $archive =~ m/\.gz$/ ) { + system("gunzip", "$archive") == 0 or return 0; + $archive =~ s/\.gz$//; + } + if ( $archive =~ m/.*\.tgz$/ ) { + system("gunzip", "$archive") == 0 or return 0; + $archive =~ s/\.tgz$/.tar/; + } + if ( $archive !~ /\.tar$/) { + print STDERR "$0: $archive not a tar file\n"; + return 0; + } + make_tempdir(); + rename("$archive","$TMPDIR/$archive") or die "cannot rename(\"$archive\",\"$TMPDIR/$archive\")"; + chdir("$TMPDIR") or die "cannot chdir"; + system("gtar", "xf", "$archive") == 0 or die "cannot untar $archive"; + unlink($archive); + + reformat_results($archive); + system('gzip',glob("*/*")) == 0 or die "cannot gzip (while processing $archive)"; + system('chmod','-R','a+r,og+w','.') == 0 or die "cannot chmod"; + system('tar', 'cf', "../$archive", glob("*")) == 0 or die "cannot tar"; + chdir('..') or die; + system('rm', '-rf', "$TMPDIR")== 0 or die "cannot rm -rf"; + return 1; +} + +sub all_archives() { + my $archive; + foreach $archive (@ARGV) { + if (one_archive($archive)) { + my $date=`date`; + chop $date; + print_log("$final_version : $archive successfully reformatted. [ $date ]\n"); + } else { + print_log_err("$final_version : Could not reformat $archive\n"); + } + } +} + +if ($#ARGV < 0) { + usage; + exit 1; +} + +if ($ARGV[0] eq "-v") { + shift; + $version = shift; +} + +if ($#ARGV < 0) { + usage; + exit 1; +} + +open (TESTRESULTSLOG, ">>../test_results.log") + or die "Could not open test_results.log\n"; +all_archives(); +close (TESTRESULTSLOG); +exit 0; diff --git a/Maintenance/test_handling/filter_testsuite/treat_result_collection b/Maintenance/test_handling/filter_testsuite/treat_result_collection new file mode 100755 index 00000000000..7369f88a7a4 --- /dev/null +++ b/Maintenance/test_handling/filter_testsuite/treat_result_collection @@ -0,0 +1,185 @@ +#!/usr/bin/env perl + +use Cwd; +use strict; + +#$ENV{PATH}= +#'/sw/bin:/sbin:/usr/sbin:/usr/bsd:/bin:/usr/bin'; + + + +my $currentdir=cwd(); + +my $scriptsdir; +my $unpack_dir_base; +my $unpack_dir; +my $testresult_dir; +my $lockfile="cgal_testannounce.lock"; +#my $announcements_dir="/private/CGAL/testannouncements"; +my $announcements_dir="/u/termite/0/user/spion/CGAL/testannouncements"; +my $lock_cmd= "/usr/local/bin/lockfile"; +my $ftp_results_dir="$currentdir/incoming/"; +my $check_file="processed_test_results"; + +my ($cgal_version,$tarname,@results); + +$testresult_dir="$currentdir/TESTRESULTS"; +$scriptsdir="$currentdir"; +$unpack_dir_base="$currentdir"; + + +sub make_unpackdir() +{ + my $dirno = 1; + my $TMPDIR; + $TMPDIR = "$unpack_dir_base/TMP$dirno"; + while ( -f $TMPDIR or -d $TMPDIR ) { + ++$dirno; + $TMPDIR = "$unpack_dir_base/TMP$dirno"; + } + mkdir($TMPDIR,0770) or die "Cannot create temporary directory $TMPDIR\n"; + $unpack_dir = $TMPDIR; +} + +sub unpack_results{ + chdir $unpack_dir or die; + my $filename="$ftp_results_dir/$_[0]"; + system "cp $ftp_results_dir/$_[0] $_[0]"; + system "chmod 644 $_[0]"; + system("gunzip", "$_[0]")== 0 + or die "Could not gunzip $_[0]\n"; + @results=grep /tar$|tar\.gz$/, `tar tf ${tarname}`; + chomp @results; + system("tar", "xf", ${tarname}, @results); + if( ($? != 0) || (@results == 0) ) { + print TESTRESULTSLOG "(EE) Cannot read tar file \"${tarname}\"!\n"; + } + else { + print TESTRESULTSLOG "(II) Processing tar file \"${tarname}\"...\n"; + system("$scriptsdir/to_zipped_format", "-v", $cgal_version, @results)==0 + or die "to_zipped_format failed on \"$filename\". Test collection not installed.\n"; + } +} + + +sub install_results() +{ + if (-d $testresult_dir) { + chdir $testresult_dir or die; + } else { + mkdir $testresult_dir or die; + chdir $testresult_dir or die; + } + if (-d $cgal_version) { + chdir $cgal_version or die; + } else { + mkdir $cgal_version or die; + chdir $cgal_version or die; + } + my $resultfile; + for $resultfile (@results) { + $resultfile =~ s/\.gz//; + system('tar','--force-local','-xf',"${unpack_dir}/${resultfile}")==0 or die; +# unlink "${unpack_dir}/$resultfile"; + } + chdir ".." or die; +# system("./create_testresult_page", $cgal_version); + +# clean up stuff in UNPACK_DIR + + chdir $unpack_dir or die; +# unlink $tarname; +# notify(); + +} + +# Save the content of $check_file in the hash %check_file_content, to avoid +# opening, reading, and closing that file at every call of the function +# `exist_in_file` (called thousands of times) +my %check_file_content; +open my $fh, $check_file || die ("Could not open $check_file"); +while (my $contents = <$fh>){ + chop $contents; + $check_file_content{$contents} = 1; +} +close $fh; + +#return 0 if it exists and 1 otherwise +sub exist_in_file{ + if ( $check_file_content{$_[0]} == 1) { + return 0; + } else { + return 1; + } +} + + +#first argument is a string +sub append_to_file{ + chdir($currentdir); + + if ( -w $check_file ) { + open FILE, ">> $check_file" || die ("Could not open $check_file"); + } else { + open FILE, "> $check_file" || die ("Could not open $check_file"); + } + print FILE "$_[0]\n"; + close FILE; +} + + +open (TESTRESULTSLOG, ">>", "./test_results.log") + or die "Could not open test_results.log\n"; + +my $dir_h; +my $i; +my $is_good; +my $res; +chdir($currentdir) || die("Could not chdir to $currentdir"); +opendir($dir_h, $ftp_results_dir) || die("The ftp directory could no be opened"); +while( $i=readdir($dir_h)){ + next if($i eq "."); + next if ($i eq ".."); + $is_good=1; + if ( $i =~ m/^(CGAL-\d+\.\d+-Ic?-\d+)[-_]/ ) { + $cgal_version=$1; + } else { + if ( $i =~ m/^(CGAL-\d+\.\d+\.\d+-Ic?-\d+)[-_]/ ) { + $cgal_version=$1; + } else { + if ( $i =~ m/^(CGAL-\d+\.\d+\.\d+)[-_]/ ) { + $cgal_version=$1; + } else { + if ( $i =~ m/^(CGAL-\d+\.\d+)[-_]/ ) { + $cgal_version=$1; + } else { + # die "$i is not a valid name for a testresult collection.\n"; + $is_good=0; + } + } + } + } + if ( $is_good == 1 ){ + if ( -s "$ftp_results_dir/$i" && + exist_in_file($i) == 1 && + system("fuser", "$ftp_results_dir/$i") != 0 ){ + system "cp $ftp_results_dir/$i $i"; + system "chmod 644 $i"; + $res = system "gunzip -t $i"; + system "rm -rf $i"; + if ( $res == 0 ){ + append_to_file($i); + $tarname=`basename $i .gz`; + chomp $tarname; + make_unpackdir(); + eval {unpack_results($i)} && eval{install_results()}; + $@ && warn $@; + chdir($unpack_dir_base); + system('rm','-rf',$unpack_dir); + system "./create_testresult_page $cgal_version"; + } + } + } +} +closedir($dir_h); +close (TESTRESULTSLOG); diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index a19a6ca4ee7..17578837731 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -58,7 +58,7 @@ echo "starting testsuite..." ./autotest_cgal -c -if [ -n "$4" ]; then +if [ "$4" = "y" ]; then cd ${CGAL_ROOT} V=$(cat VERSION_NUMBER) V=$(($V+1)) diff --git a/Testsuite/test/collect_cgal_testresults_from_cmake b/Testsuite/test/collect_cgal_testresults_from_cmake index 23a0741df38..54b5d502ce0 100755 --- a/Testsuite/test/collect_cgal_testresults_from_cmake +++ b/Testsuite/test/collect_cgal_testresults_from_cmake @@ -30,7 +30,10 @@ RESULT_FILE='' # print timings on fd3 print_testresult() { - if [ ! -f ErrorOutput_$1 ] ; then + if [ -f skipped ]; then + RESULT="s" + TIMING="0" + elif [ ! -f ErrorOutput_$1 ] ; then RESULT="?" TIMING="?" else From 5a20cf1c94212e02b0392d89b73f8fa0e9ad48e7 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 23 Jul 2021 14:18:13 +0200 Subject: [PATCH 307/349] clean-up --- Scripts/developer_scripts/autotest_cgal | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Scripts/developer_scripts/autotest_cgal b/Scripts/developer_scripts/autotest_cgal index 4ad3e7b8b1a..e0b985e0339 100755 --- a/Scripts/developer_scripts/autotest_cgal +++ b/Scripts/developer_scripts/autotest_cgal @@ -628,8 +628,8 @@ if [ -f '${LIST_TEST_PACKAGES}' ]; then cp '${CGAL_TEST_DIR}/makefile2' '${CGAL_BINARY_DIR}/test' cp '${CGAL_TEST_DIR}/run_testsuite_with_cmake' '${CGAL_BINARY_DIR}/test' -# list all packages in CGAL_TEST_DIR. If PACKAGE is found in LIST_TEST_PACKAGES, -# copy it, else prepare for the special "skipped" case in the table. + # list all packages in CGAL_TEST_DIR. If PACKAGE is found in LIST_TEST_PACKAGES, + # copy it, else prepare for the special "skipped" case in the table. for PACKAGE in \$(ls "${CGAL_TEST_DIR}"); do if [ -d "${CGAL_TEST_DIR}/\$PACKAGE" ]; then if source '${LIST_TEST_PACKAGES}' '${CGAL_ROOT}' | egrep -q \$PACKAGE; then @@ -643,6 +643,7 @@ if [ -f '${LIST_TEST_PACKAGES}' ]; then touch "${CGAL_BINARY_DIR}/test/\${PACKAGE}/skipped" fi fi + done else @@ -770,7 +771,6 @@ run_test_on_host() fi for PLATFORM in ${PLATFORMS}; do - run_test_on_host_and_platform "${HOST}" "${PLATFORM}" publish_results "${HOST}" "${PLATFORM}" done @@ -988,4 +988,3 @@ rm -f "$LOCK_FILE"; ## Local Variables: ## sh-basic-offset: 2 ## End: - From a221d9f1a77fd990d22e4c845d154417167c08fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 23 Jul 2021 14:26:20 +0200 Subject: [PATCH 308/349] Using boost:: rather than CGAL:: for FFG's index pmap properties --- .../CGAL/boost/graph/Face_filtered_graph.h | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h index 982adf381bc..5bdc06c873b 100644 --- a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h +++ b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h @@ -1273,14 +1273,14 @@ CGAL_FILTERED_FACE_GRAPH_DYNAMIC_PMAP_SPECIALIZATION(dynamic_face_property_t) //specializations for indices template -struct property_map, CGAL::face_index_t> +struct property_map, boost::face_index_t> { typedef CGAL::Face_filtered_graph FFG; typedef typename FFG::FIM FIM; - typedef typename boost::property_traits::value_type Face_index; - typedef typename CGAL::dynamic_face_property_t Face_index_dtag; - typedef typename boost::property_map::type type; + typedef typename boost::property_traits::value_type Index; + typedef typename CGAL::dynamic_face_property_t Index_dtag; + typedef typename boost::property_map::type type; typedef typename CGAL::Property_map_binder, boost typedef CGAL::Face_filtered_graph FFG; typedef typename FFG::VIM VIM; - typedef typename boost::property_traits::value_type Vertex_index; - typedef typename CGAL::dynamic_vertex_property_t Vertex_index_dtag; - typedef typename boost::property_map::type type; + typedef typename boost::property_traits::value_type Index; + typedef typename CGAL::dynamic_vertex_property_t Index_dtag; + typedef typename boost::property_map::type type; typedef typename CGAL::Property_map_binder, boost }; template -struct property_map, CGAL::halfedge_index_t> +struct property_map, boost::halfedge_index_t> { typedef CGAL::Face_filtered_graph FFG; typedef typename FFG::HIM HIM; - typedef typename boost::property_traits::value_type Halfedge_index; - typedef typename CGAL::dynamic_halfedge_property_t Halfedge_index_dtag; - typedef typename boost::property_map::type type; + typedef typename boost::property_traits::value_type Index; + typedef typename CGAL::dynamic_halfedge_property_t Index_dtag; + typedef typename boost::property_map::type type; typedef typename CGAL::Property_map_binder -typename boost::property_map, CGAL::face_index_t >::const_type -get(CGAL::face_index_t, const Face_filtered_graph& w) +typename boost::property_map, boost::face_index_t >::const_type +get(boost::face_index_t, const Face_filtered_graph& w) { return w.get_face_index_map(); } @@ -1337,19 +1337,19 @@ get(boost::vertex_index_t, const Face_filtered_graph } template -typename boost::property_map, CGAL::halfedge_index_t >::const_type -get(CGAL::halfedge_index_t, const Face_filtered_graph& w) +typename boost::property_map, boost::halfedge_index_t >::const_type +get(boost::halfedge_index_t, const Face_filtered_graph& w) { return w.get_halfedge_index_map(); } // non-const (dynamic pmap) template -typename boost::property_map, CGAL::face_index_t >::type -get(CGAL::face_index_t, Face_filtered_graph& w) +typename boost::property_map, boost::face_index_t >::type +get(boost::face_index_t, Face_filtered_graph& w) { typedef CGAL::Face_filtered_graph FFG; - typedef typename boost::property_map::type result_type; + typedef typename boost::property_map::type result_type; typedef typename boost::property_traits::value_type Index; typedef typename CGAL::dynamic_face_property_t Index_dtag; @@ -1369,11 +1369,11 @@ get(boost::vertex_index_t, Face_filtered_graph& w) } template -typename boost::property_map, CGAL::halfedge_index_t >::type -get(CGAL::halfedge_index_t, Face_filtered_graph& w) +typename boost::property_map, boost::halfedge_index_t >::type +get(boost::halfedge_index_t, Face_filtered_graph& w) { typedef CGAL::Face_filtered_graph FFG; - typedef typename boost::property_map::type result_type; + typedef typename boost::property_map::type result_type; typedef typename boost::property_traits::value_type Index; typedef typename CGAL::dynamic_halfedge_property_t Index_dtag; From 5240e402dee00a2fca3f9f904511f15c2ed068a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 23 Jul 2021 14:26:40 +0200 Subject: [PATCH 309/349] Fix wrong PMap type --- Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp index 94741aac6a7..7facb373c1f 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp @@ -2453,8 +2453,7 @@ QString Scene_polyhedron_selection_item::computeStats(int type) // Extract the part n°0 of the partition into a new, independent mesh if(selected_facets.size() == 0) return QString("n/a"); - boost::vector_property_map::type> + boost::vector_property_map, boost::face_index_t>::type> fccmap(get(boost::face_index, *d->filtered_graph)); return QString::number(CGAL::Polygon_mesh_processing::connected_components(*d->filtered_graph, fccmap)); From f8690f5a6faf4ebefcf7ea0180e915006e82f553 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 23 Jul 2021 14:43:02 +0200 Subject: [PATCH 310/349] Use unsigned long to get a 64bits type and avoid a warning about the wrong size for the type FPU_CW_t --- Number_types/include/CGAL/FPU.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Number_types/include/CGAL/FPU.h b/Number_types/include/CGAL/FPU.h index 6d5f02a3075..626a27eb443 100644 --- a/Number_types/include/CGAL/FPU.h +++ b/Number_types/include/CGAL/FPU.h @@ -450,7 +450,7 @@ typedef unsigned int FPU_CW_t; # elif defined __aarch64__ #define CGAL_IA_SETFPCW(CW) asm volatile ("MSR FPCR, %0" : :"r" (CW)) #define CGAL_IA_GETFPCW(CW) asm volatile ("MRS %0, FPCR" : "=r" (CW)) -typedef unsigned int FPU_CW_t; +typedef unsigned long FPU_CW_t; #define CGAL_FE_TONEAREST (0x0) #define CGAL_FE_TOWARDZERO (0xC00000) #define CGAL_FE_UPWARD (0x400000) From f26796488911911ac96327b6bb07b534159f8214 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 26 Jul 2021 12:24:32 +0200 Subject: [PATCH 311/349] Fix list_test_packages --- .../run_testsuite_from_branch_name.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index 17578837731..6ed259be166 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -32,9 +32,17 @@ git fetch --depth 1 $USER_REPO git checkout $BRANCH_NAME git reset --hard $USER_REPO/$BRANCH_NAME #setup the list_test_packages -LIST_OF_PKGS=$(git diff --name-only HEAD cgal/$BASE_NAME |cut -s -d/ -f1 |sort -u | xargs -I {} ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true) +TMP_LIST=$(git diff --name-only HEAD cgal/$BASE_NAME |cut -s -d/ -f1 |sort -u | xargs -I {} ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true) +LIST_OF_PKGS="" +for PKG in $(ls) ; do + if [ -f $PKG/package_info/$PKG/dependencies ]; then + if [ -n "$(comm -12 <(echo "$LIST_OF_PKGS"|sort) <(cat $PKG/package_info/$PKG/dependencies|sort))" ]; then + LIST_OF_PKGS="$LIST_OF_PKGS $PKG" + fi + fi +done +if [ -f ${CGAL_ROOT}/list_test_packages ]; then rm ${CGAL_ROOT}/list_test_packages; fi if [ "$LIST_OF_PKGS" != "" ]; then - if [ -f ${CGAL_ROOT}/list_test_packages ]; then rm ${CGAL_ROOT}/list_test_packages; fi for f in $LIST_OF_PKGS do echo "echo \"$f\"" >> ${CGAL_ROOT}/list_test_packages From e3b154407029ceba20ed7600e065b3c2a9fef1de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 26 Jul 2021 12:25:46 +0200 Subject: [PATCH 312/349] Revert to binder-pmaps for FFG's index maps (but fix them) --- .../CGAL/boost/graph/Face_filtered_graph.h | 164 ++++++++++-------- 1 file changed, 87 insertions(+), 77 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h index 5bdc06c873b..7cdbbfc9747 100644 --- a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h +++ b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h @@ -393,21 +393,68 @@ struct Face_filtered_graph ///returns a reference to the underlying graph. Graph& graph(){ return _graph; } - ///change the set of selected faces using a patch id - template - void set_selected_faces(typename boost::property_traits::value_type face_patch_id, - FacePatchIndexMap face_patch_index_map) + // Handling of internal correspondency for index maps. + // The indices must be kept valid when the selection changes. + void initialize_face_indices() const + { + if(face_indices.empty()) + { + face_index_type index = 0; + face_indices.resize(num_faces(_graph)); + for(std::size_t i=selected_faces.find_first(); i + void set_selected_faces(typename boost::property_traits::value_type face_patch_id, + FacePatchIndexMap face_patch_index_map) + { selected_faces.resize(num_faces(_graph)); selected_vertices.resize(num_vertices(_graph)); selected_halfedges.resize(num_halfedges(_graph)); + selected_faces.reset(); selected_vertices.reset(); selected_halfedges.reset(); + for(face_descriptor fd : faces(_graph) ) { if(get(face_patch_index_map, fd) == face_patch_id) @@ -421,6 +468,8 @@ struct Face_filtered_graph } } } + + reset_indices(); } /// change the set of selected faces using a range of patch ids template @@ -433,16 +482,14 @@ struct Face_filtered_graph #endif ) { - face_indices.clear(); - vertex_indices.clear(); - halfedge_indices.clear(); - selected_faces.resize(num_faces(_graph)); selected_vertices.resize(num_vertices(_graph)); selected_halfedges.resize(num_halfedges(_graph)); + selected_faces.reset(); selected_vertices.reset(); selected_halfedges.reset(); + typedef typename boost::property_traits::value_type Patch_index; boost::unordered_set pids(boost::begin(selected_face_patch_indices), boost::end(selected_face_patch_indices)); @@ -460,21 +507,22 @@ struct Face_filtered_graph } } } + + reset_indices(); } + /// change the set of selected faces using a range of face descriptors template void set_selected_faces(const FaceRange& selection) { - face_indices.clear(); - vertex_indices.clear(); - halfedge_indices.clear(); - selected_faces.resize(num_faces(_graph)); selected_vertices.resize(num_vertices(_graph)); selected_halfedges.resize(num_halfedges(_graph)); + selected_faces.reset(); selected_vertices.reset(); selected_halfedges.reset(); + for(face_descriptor fd : selection) { selected_faces.set(get(fimap, fd)); @@ -485,6 +533,8 @@ struct Face_filtered_graph selected_vertices.set(get(vimap, target(hd, _graph))); } } + + reset_indices(); } struct Is_simplex_valid @@ -543,45 +593,27 @@ struct Face_filtered_graph Property_map_binder::value_type>::type> get_face_index_map() const { - if (face_indices.empty()) - { - face_index_type index = 0; - face_indices.resize(num_faces(_graph)); - for (std::size_t i=selected_faces.find_first(); i < selected_faces.npos; i = selected_faces.find_next(i)) - { - face_indices[i] = index++; - } - } - return bind_property_maps(fimap, make_property_map(face_indices) ); + is_imap_in_use.set(0); + initialize_face_indices(); + + return bind_property_maps(fimap, make_property_map(face_indices)); } Property_map_binder::value_type>::type> get_vertex_index_map() const { - if (vertex_indices.empty()) - { - vertex_index_type index = 0; - vertex_indices.resize(num_vertices(_graph)); - for (std::size_t i=selected_vertices.find_first(); i < selected_vertices.npos; i = selected_vertices.find_next(i)) - { - vertex_indices[i] = index++; - } - } + is_imap_in_use.set(1); + initialize_vertex_indices(); + return bind_property_maps(vimap, make_property_map(vertex_indices) ); } Property_map_binder::value_type >::type> get_halfedge_index_map() const { - if (halfedge_indices.empty()) - { - halfedge_index_type index = 0; - halfedge_indices.resize(num_halfedges(_graph)); - for (std::size_t i=selected_halfedges.find_first(); i < selected_halfedges.npos; i = selected_halfedges.find_next(i)) - { - halfedge_indices[i] = index++; - } - } + is_imap_in_use.set(2); + initialize_halfedge_indices(); + return bind_property_maps(himap, make_property_map(halfedge_indices) ); } @@ -649,9 +681,11 @@ private: boost::dynamic_bitset<> selected_faces; boost::dynamic_bitset<> selected_vertices; boost::dynamic_bitset<> selected_halfedges; + mutable std::vector face_indices; mutable std::vector vertex_indices; mutable std::vector halfedge_indices; + mutable std::bitset<3> is_imap_in_use; // one per descriptor type (face, vertex, halfedge) }; } // namespace CGAL @@ -1278,13 +1312,10 @@ struct property_map, boost typedef CGAL::Face_filtered_graph FFG; typedef typename FFG::FIM FIM; - typedef typename boost::property_traits::value_type Index; - typedef typename CGAL::dynamic_face_property_t Index_dtag; - typedef typename boost::property_map::type type; - typedef typename CGAL::Property_map_binder::value_type>::type> const_type; + typename boost::property_traits::value_type>::type> type; + typedef type const_type; }; template @@ -1293,13 +1324,10 @@ struct property_map, boost typedef CGAL::Face_filtered_graph FFG; typedef typename FFG::VIM VIM; - typedef typename boost::property_traits::value_type Index; - typedef typename CGAL::dynamic_vertex_property_t Index_dtag; - typedef typename boost::property_map::type type; - typedef typename CGAL::Property_map_binder::value_type>::type> const_type; + typename boost::property_traits::value_type>::type> type; + typedef type const_type; }; template @@ -1308,13 +1336,10 @@ struct property_map, boost typedef CGAL::Face_filtered_graph FFG; typedef typename FFG::HIM HIM; - typedef typename boost::property_traits::value_type Index; - typedef typename CGAL::dynamic_halfedge_property_t Index_dtag; - typedef typename boost::property_map::type type; - typedef typename CGAL::Property_map_binder::value_type>::type> const_type; + typename boost::property_traits::value_type>::type> type; + typedef type const_type; }; } // namespace boost @@ -1343,41 +1368,26 @@ get(boost::halfedge_index_t, const Face_filtered_graph -typename boost::property_map, boost::face_index_t >::type +typename boost::property_map, boost::face_index_t >::const_type get(boost::face_index_t, Face_filtered_graph& w) { - typedef CGAL::Face_filtered_graph FFG; - typedef typename boost::property_map::type result_type; - typedef typename boost::property_traits::value_type Index; - typedef typename CGAL::dynamic_face_property_t Index_dtag; - - return get(Index_dtag(), w.graph()); + return w.get_face_index_map(); } template -typename boost::property_map, boost::vertex_index_t >::type +typename boost::property_map, boost::vertex_index_t >::const_type get(boost::vertex_index_t, Face_filtered_graph& w) { - typedef CGAL::Face_filtered_graph FFG; - typedef typename boost::property_map::type result_type; - typedef typename boost::property_traits::value_type Index; - typedef typename CGAL::dynamic_vertex_property_t Index_dtag; - - return get(Index_dtag(), w.graph()); + return w.get_vertex_index_map(); } template -typename boost::property_map, boost::halfedge_index_t >::type +typename boost::property_map, boost::halfedge_index_t >::const_type get(boost::halfedge_index_t, Face_filtered_graph& w) { - typedef CGAL::Face_filtered_graph FFG; - typedef typename boost::property_map::type result_type; - typedef typename boost::property_traits::value_type Index; - typedef typename CGAL::dynamic_halfedge_property_t Index_dtag; - - return get(Index_dtag(), w.graph()); + return w.get_halfedge_index_map(); } } // namespace CGAL From 55e71b602a216b61ffbfb8d6a1097d56d68fb6ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 26 Jul 2021 12:27:03 +0200 Subject: [PATCH 313/349] Test binder-based index pmaps on selection -changing FFG --- BGL/test/BGL/test_Face_filtered_graph.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/BGL/test/BGL/test_Face_filtered_graph.cpp b/BGL/test/BGL/test_Face_filtered_graph.cpp index 10e3086476d..100f08eb278 100644 --- a/BGL/test/BGL/test_Face_filtered_graph.cpp +++ b/BGL/test/BGL/test_Face_filtered_graph.cpp @@ -279,7 +279,8 @@ void test_index_property_maps(const Graph& g) typedef typename boost::graph_traits::face_descriptor g_face_descriptor; std::map map; PMP::connected_components(g, boost::make_assoc_property_map(map), CGAL::parameters::all_default()); - Adapter fg(g, 0, boost::make_assoc_property_map(map)); + Adapter fg(g, -1, boost::make_assoc_property_map(map)); + assert(is_empty(fg)); // Non const typedef typename CGAL::GetInitializedVertexIndexMap::type VIMap; @@ -294,6 +295,13 @@ void test_index_property_maps(const Graph& g) FIMap fim = CGAL::get_initialized_face_index_map(fg); assert(CGAL::BGL::internal::is_index_map_valid(fim, num_faces(fg), faces(fg))); + fg.set_selected_faces(0, boost::make_assoc_property_map(map)); + assert(!is_empty(fg)); + + assert(CGAL::BGL::internal::is_index_map_valid(vim, num_vertices(fg), vertices(fg))); + assert(CGAL::BGL::internal::is_index_map_valid(him, num_halfedges(fg), halfedges(fg))); + assert(CGAL::BGL::internal::is_index_map_valid(fim, num_faces(fg), faces(fg))); + // Const const Adapter cfg(g, 0, boost::make_assoc_property_map(map)); typedef typename CGAL::GetInitializedVertexIndexMap::const_type CVIMap; From 09337e4c3b7dc290ea56723bd86a2393fc95e427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 26 Jul 2021 12:31:22 +0200 Subject: [PATCH 314/349] Add some missing STL includes --- BGL/include/CGAL/boost/graph/Face_filtered_graph.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h index 7cdbbfc9747..58eb511d846 100644 --- a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h +++ b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h @@ -28,6 +28,10 @@ #include #include +#include +#include +#include + #ifdef DOXYGEN_RUNNING #define CGAL_BGL_NP_TEMPLATE_PARAMETERS NamedParameters #define CGAL_BGL_NP_CLASS NamedParameters From d8c4d6a3c9283e3ed42c2195588c20b68a66a2b6 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Mon, 26 Jul 2021 13:06:58 +0200 Subject: [PATCH 315/349] Install ITK in Github action tests --- .github/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/install.sh b/.github/install.sh index 047c539ff95..e06328da401 100755 --- a/.github/install.sh +++ b/.github/install.sh @@ -3,7 +3,7 @@ sudo add-apt-repository ppa:mikhailnov/pulseeffects -y sudo apt-get update sudo apt-get install -y libmpfr-dev \ libeigen3-dev qtbase5-dev libqt5sql5-sqlite libqt5opengl5-dev qtscript5-dev \ - libqt5svg5-dev qttools5-dev qttools5-dev-tools libboost1.72-dev zsh + libqt5svg5-dev qttools5-dev qttools5-dev-tools libboost-dev libinsighttoolkit4-dev zsh #update cmake to 3.18.4 sudo apt purge --auto-remove cmake cd /tmp From ec9c77b44d117685b6a591ae4d71469abefc5962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 26 Jul 2021 13:49:27 +0200 Subject: [PATCH 316/349] Use the non-const ::type typedef for consistency Internally, both ::type and ::const_type are the same --- BGL/include/CGAL/boost/graph/Face_filtered_graph.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h index 58eb511d846..88dc8f55b92 100644 --- a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h +++ b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h @@ -1374,21 +1374,21 @@ get(boost::halfedge_index_t, const Face_filtered_graph -typename boost::property_map, boost::face_index_t >::const_type +typename boost::property_map, boost::face_index_t >::type get(boost::face_index_t, Face_filtered_graph& w) { return w.get_face_index_map(); } template -typename boost::property_map, boost::vertex_index_t >::const_type +typename boost::property_map, boost::vertex_index_t >::type get(boost::vertex_index_t, Face_filtered_graph& w) { return w.get_vertex_index_map(); } template -typename boost::property_map, boost::halfedge_index_t >::const_type +typename boost::property_map, boost::halfedge_index_t >::type get(boost::halfedge_index_t, Face_filtered_graph& w) { return w.get_halfedge_index_map(); From 4acf4ca6336491064c61d343f61e48817ee6c0ff Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 26 Jul 2021 14:56:48 +0200 Subject: [PATCH 317/349] test CGAL_VERSION value --- .github/workflows/filter_testsuite.yml | 10 +++------ .../run_testsuite_from_branch_name.sh | 21 +++++++++---------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/.github/workflows/filter_testsuite.yml b/.github/workflows/filter_testsuite.yml index 3c2e6364c05..3104da560ba 100644 --- a/.github/workflows/filter_testsuite.yml +++ b/.github/workflows/filter_testsuite.yml @@ -73,18 +73,14 @@ jobs: LABEL="${{ steps.get_label.outputs.result }}" USER_NAME=$(echo $LABEL | cut -d':' -f 1) BRANCH_NAME=$(echo $LABEL | cut -d':' -f 2) + PR_NUMBER=$(python -c "import json; import os; y = json.load(open(os.environ['GITHUB_EVENT_PATH'])); print(y[\"number\"])") BASE="${{ steps.get_base.outputs.result }}" mapfile -t HOSTS < ~/ssh_host_list; for i in ${!HOSTS[@]}; do HOST=$(echo ${HOSTS[$i]}|cut -d' ' -f 1 ) PATH_TO_SCRIPT=$(echo ${HOSTS[$i]}|cut -d' ' -f 2 ) - if [ "$i" = "0" ] ; then - echo "ssh ${HOST} ${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE y" - ssh ${HOST} "${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE y" - else - echo "ssh ${HOST} ${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE" - ssh ${HOST} "${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE" - fi + echo "ssh ${HOST} ${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE $PR_NUMBER" + ssh ${HOST} "${PATH_TO_SCRIPT}/run_testsuite_from_branch_name.sh $USER_NAME $BRANCH_NAME $BASE $PR_NUMBER" done - name: Post address uses: actions/github-script@v3 diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index 6ed259be166..5f3883a005a 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -3,7 +3,7 @@ #To run: $1 = name of the user # $2 = name of the branch # $3 = base ref name (master, 5.1.x, 5.2.x, etc...) -# $4 = if given, update the VERSION_NUMBER +# $4 = number of the PR if uname | grep -q -i cygwin; then @@ -16,8 +16,9 @@ echo "CGAL_ROOT = $CGAL_ROOT" > log USER_REPO=$1 BRANCH_NAME=$2 BASE_NAME=$3 +PR_NUMBER=$4 + cd ${CGAL_ROOT} -scp ${VERSION_NUMBER_SSH_URL} . cd ${CGAL_GIT_DIR} if [ ! -d cgal ]; then git clone --depth 1 --no-single-branch https://github.com/CGAL/cgal.git @@ -26,6 +27,9 @@ if [ ! -d cgal ]; then cd .. fi cd cgal +CGAL_VERSION="CGAL-$(sed -E 's/#define CGAL_VERSION (.*\..*)-dev/\1/' <(grep "#define CGAL_VERSION " Installation/include/CGAL/version.h))-${PR_NUMBER}" +echo $CGAL_VERSION > log +exit 0 git fetch --depth 1 cgal git remote add $USER_REPO https://github.com/$USER_REPO/cgal.git git fetch --depth 1 $USER_REPO @@ -53,8 +57,10 @@ fi ( #create the release from the branch echo " Create release..." -echo "CGAL_VERSION=0.0-Ic-$(cat ${CGAL_ROOT}/VERSION_NUMBER)"> log -cmake -DGIT_REPO=${CGAL_GIT_DIR}/cgal -DDESTINATION=${CGAL_ROOT}/CGAL-TEST -DPUBLIC=OFF -DTESTSUITE=ON -DCGAL_VERSION=0.0-Ic-$(cat ${CGAL_ROOT}/VERSION_NUMBER) -P ${CGAL_GIT_DIR}/cgal/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake | tee log +CGAL_VERSION="CGAL-$(sed -E 's/#define CGAL_VERSION (.*\..*)-dev/\1/' <(grep "#define CGAL_VERSION " Installation/include/CGAL/version.h))-${PR_NUMBER}" + +echo "CGAL_VERSION = ${CGAL_VERSION}"> log +cmake -DGIT_REPO=${CGAL_GIT_DIR}/cgal -DDESTINATION=${CGAL_ROOT}/CGAL-TEST -DPUBLIC=OFF -DTESTSUITE=ON -DCGAL_VERSION=${CGAL_VERSION} -P ${CGAL_GIT_DIR}/cgal/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake | tee log echo "done." DEST=$(sed -E 's/.*CGAL-TEST\/(.*)/\1/' log); @@ -66,13 +72,6 @@ echo "starting testsuite..." ./autotest_cgal -c -if [ "$4" = "y" ]; then - cd ${CGAL_ROOT} - V=$(cat VERSION_NUMBER) - V=$(($V+1)) - echo $V > VERSION_NUMBER - scp VERSION_NUMBER ${VERSION_NUMBER_SSH_URL} -fi )>${CGAL_ROOT}/autotest.log2 2>&1 & echo "finished." From e050373f885942008bce625e8abf3e5ac19a3480 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 27 Jul 2021 11:42:58 +0200 Subject: [PATCH 318/349] restore tests on GNUC>4 in tests of Periodic_3_triangulation_3, because clang also defines __GNUC__ or something... --- .../CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h | 2 +- .../include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h index a7297b25ee9..c59d2d48472 100644 --- a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h +++ b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_regular_triangulation_traits_3.h @@ -10,7 +10,7 @@ // Author(s) : Aymeric PELLE // Mael Rouxel-Labbé -#if (__GNUC__ > 0) +#if (__GNUC__>4) || (__GNUC__ == 4 && __GNUC_MINOR__ >=6) # pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif diff --git a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h index fef5f500309..37ebb32353b 100644 --- a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h +++ b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_triangulation_traits_3.h @@ -11,7 +11,7 @@ // Author(s) : Mariette Yvinec // Manuel Caroli -#if (__GNUC__ > 0) +#if (__GNUC__>4) || (__GNUC__ == 4 && __GNUC_MINOR__ >=6) # pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif From db8976d4576fac72a51a316157f93f6e4b1bb0dd Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 27 Jul 2021 15:36:32 +0200 Subject: [PATCH 319/349] updated changes.md --- Installation/CHANGES.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 5ae1f610222..81763b0ca26 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -1,6 +1,15 @@ Release History =============== +[Release 5.4](https://github.com/CGAL/cgal/releases/tag/v5.4) +----------- + +Release date: December 2021 + +### [2D and 3D Linear Geometry Kernel](https://doc.cgal.org/5.4/Manual/packages.html#PkgKernel23) + +- Added `construct_centroid_2_object()` and `compute_determinant_2_object()` in `Projection_traits_xy_3`, `Projection_traits_xz_3`, and `Projection_traits_yz_3` classes. + [Release 5.3](https://github.com/CGAL/cgal/releases/tag/v5.3) ----------- From b3ffe456adb4ba77ced8b9b977974135220ee9c1 Mon Sep 17 00:00:00 2001 From: Dmitry Anisimov Date: Tue, 27 Jul 2021 16:21:22 +0200 Subject: [PATCH 320/349] updated tabs --- Installation/CHANGES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 81763b0ca26..f2794328d22 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -8,7 +8,8 @@ Release date: December 2021 ### [2D and 3D Linear Geometry Kernel](https://doc.cgal.org/5.4/Manual/packages.html#PkgKernel23) -- Added `construct_centroid_2_object()` and `compute_determinant_2_object()` in `Projection_traits_xy_3`, `Projection_traits_xz_3`, and `Projection_traits_yz_3` classes. +- Added `construct_centroid_2_object()` and `compute_determinant_2_object()` in `Projection_traits_xy_3`, `Projection_traits_xz_3`, + and`Projection_traits_yz_3` classes. [Release 5.3](https://github.com/CGAL/cgal/releases/tag/v5.3) ----------- From 30a43908a92ff6433346f387317abadc1ce5d522 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 28 Jul 2021 10:47:04 +0200 Subject: [PATCH 321/349] test CGAL_VERSION value --- .github/workflows/filter_testsuite.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/filter_testsuite.yml b/.github/workflows/filter_testsuite.yml index 3104da560ba..2c2bc279eeb 100644 --- a/.github/workflows/filter_testsuite.yml +++ b/.github/workflows/filter_testsuite.yml @@ -45,6 +45,15 @@ jobs: const base = pr_content.data.base.ref console.log(base) return base + - uses: actions/github-script@v3 + if: steps.get_round.outputs.result != 'stop' + id: get_pr_number + with: + result-encoding: string + script: | + //get pullrequest url + const pr_number = context.payload.issue.number + return pr_number - name: Run Testsuite if: steps.check.outputs.result != 'stop' run: | @@ -66,14 +75,14 @@ jobs: #known hosts wget --no-check-certificate https://cgal.geometryfactory.com/CGAL/ssh_known_hosts -O ~/.ssh/known_hosts #config file - wget --no-check-certificate https://cgal.geometryfactory.com/CGAL/ssh_config -O ~/.ssh/config + wget --no-check-certificate https://cgal.geometryfactory.com/CGAL/ssh_config -O ~/.ssh/config #list of hosts wget --no-check-certificate https://cgal.geometryfactory.com/CGAL/ssh_host_list -O ~/ssh_host_list #ssh command LABEL="${{ steps.get_label.outputs.result }}" USER_NAME=$(echo $LABEL | cut -d':' -f 1) BRANCH_NAME=$(echo $LABEL | cut -d':' -f 2) - PR_NUMBER=$(python -c "import json; import os; y = json.load(open(os.environ['GITHUB_EVENT_PATH'])); print(y[\"number\"])") + PR_NUMBER=${{ steps.get_pr_number.outputs.result }} BASE="${{ steps.get_base.outputs.result }}" mapfile -t HOSTS < ~/ssh_host_list; for i in ${!HOSTS[@]}; do From e2e9f7385d89f34d2ba68b2f09cf2a62c4e4c869 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 28 Jul 2021 10:43:54 +0200 Subject: [PATCH 322/349] Use a queue --- .../run_testsuite_from_branch_name.sh | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index 5f3883a005a..80fb4872432 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -12,7 +12,35 @@ if uname | grep -q -i cygwin; then set -o igncr fi source ~/.autofilterrc -echo "CGAL_ROOT = $CGAL_ROOT" > log + + + + +queue_insert (){ +echo "$1 $2 $3 $4">>$CGAL_ROOT/queue_file +if [ ! -f running ];then + execute $1 $2 $3 $4 +fi +} + +queue_pop(){ +mv queue_file tmp + egrep -v "$1 $2 $3 $4" tmp>$CGAL_ROOT/queue_file + if [ "$( log -exit 0 git fetch --depth 1 cgal git remote add $USER_REPO https://github.com/$USER_REPO/cgal.git git fetch --depth 1 $USER_REPO @@ -54,11 +79,9 @@ if [ "$LIST_OF_PKGS" != "" ]; then echo "echo \"${f}_Demo\"" >> ${CGAL_ROOT}/list_test_packages done fi -( #create the release from the branch echo " Create release..." CGAL_VERSION="CGAL-$(sed -E 's/#define CGAL_VERSION (.*\..*)-dev/\1/' <(grep "#define CGAL_VERSION " Installation/include/CGAL/version.h))-${PR_NUMBER}" - echo "CGAL_VERSION = ${CGAL_VERSION}"> log cmake -DGIT_REPO=${CGAL_GIT_DIR}/cgal -DDESTINATION=${CGAL_ROOT}/CGAL-TEST -DPUBLIC=OFF -DTESTSUITE=ON -DCGAL_VERSION=${CGAL_VERSION} -P ${CGAL_GIT_DIR}/cgal/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake | tee log echo "done." @@ -72,8 +95,17 @@ echo "starting testsuite..." ./autotest_cgal -c -)>${CGAL_ROOT}/autotest.log2 2>&1 & echo "finished." +queue_pop $1 $2 $3 $4 +} + + +( +cd $CGAL_ROOT +queue_insert $1 $2 $3 $4 + +)>${CGAL_ROOT}/autotest.log2 2>&1 & + echo "exit." exit 0 From 477f7231b3e329f23f576ff90fbb5aa4ccbf24b1 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 28 Jul 2021 11:11:36 +0200 Subject: [PATCH 323/349] Don't use a queue file after all --- .../run_testsuite_from_branch_name.sh | 40 +------------------ 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index 80fb4872432..d0a79a7d2a4 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -12,35 +12,8 @@ if uname | grep -q -i cygwin; then set -o igncr fi source ~/.autofilterrc - - - - -queue_insert (){ -echo "$1 $2 $3 $4">>$CGAL_ROOT/queue_file -if [ ! -f running ];then - execute $1 $2 $3 $4 -fi -} - -queue_pop(){ -mv queue_file tmp - egrep -v "$1 $2 $3 $4" tmp>$CGAL_ROOT/queue_file - if [ "$(${CGAL_ROOT}/autotest.log2 2>&1 & - echo "exit." exit 0 From 02152abfee06096a82b7f8f51694d2991652bfad Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 28 Jul 2021 11:31:26 +0200 Subject: [PATCH 324/349] Fix CGAL_VERSION --- Scripts/developer_scripts/run_testsuite_from_branch_name.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index d0a79a7d2a4..6c85febdd81 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -54,7 +54,7 @@ if [ "$LIST_OF_PKGS" != "" ]; then fi #create the release from the branch echo " Create release..." -CGAL_VERSION="CGAL-$(sed -E 's/#define CGAL_VERSION (.*\..*)-dev/\1/' <(grep "#define CGAL_VERSION " Installation/include/CGAL/version.h))-${PR_NUMBER}" +CGAL_VERSION="$(sed -E 's/#define CGAL_VERSION (.*\..*)-dev/\1/' <(grep "#define CGAL_VERSION " Installation/include/CGAL/version.h))-Ic-${PR_NUMBER}" echo "CGAL_VERSION = ${CGAL_VERSION}"> log cmake -DGIT_REPO=${CGAL_GIT_DIR}/cgal -DDESTINATION=${CGAL_ROOT}/CGAL-TEST -DPUBLIC=OFF -DTESTSUITE=ON -DCGAL_VERSION=${CGAL_VERSION} -P ${CGAL_GIT_DIR}/cgal/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake | tee log echo "done." From ab0a35be168bf6b73f98443739b145976917a63e Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 28 Jul 2021 12:03:38 +0200 Subject: [PATCH 325/349] debug liste --- Scripts/developer_scripts/run_testsuite_from_branch_name.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index 6c85febdd81..bdd61fc6163 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -11,9 +11,8 @@ if uname | grep -q -i cygwin; then export SHELLOPTS set -o igncr fi -source ~/.autofilterrc ( -cd $CGAL_ROOT +source ~/.autofilterrc USER_REPO=$1 BRANCH_NAME=$2 BASE_NAME=$3 @@ -44,6 +43,7 @@ for PKG in $(ls) ; do fi done if [ -f ${CGAL_ROOT}/list_test_packages ]; then rm ${CGAL_ROOT}/list_test_packages; fi +echo "list of pkgs = $LIST_OF_PKGS">log if [ "$LIST_OF_PKGS" != "" ]; then for f in $LIST_OF_PKGS do From 7ee8667058091434c3d298fcb7172758b62b6e00 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 28 Jul 2021 12:37:50 +0200 Subject: [PATCH 326/349] debuf list --- Scripts/developer_scripts/run_testsuite_from_branch_name.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index bdd61fc6163..39c1ce85104 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -43,7 +43,7 @@ for PKG in $(ls) ; do fi done if [ -f ${CGAL_ROOT}/list_test_packages ]; then rm ${CGAL_ROOT}/list_test_packages; fi -echo "list of pkgs = $LIST_OF_PKGS">log +echo "list of pkgs = $LIST_OF_PKGS">${CGAL_ROOT}/log if [ "$LIST_OF_PKGS" != "" ]; then for f in $LIST_OF_PKGS do From 352cb7b9be89935272f5f61f61900b85c9b904ec Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 28 Jul 2021 12:48:06 +0200 Subject: [PATCH 327/349] plus --- Scripts/developer_scripts/run_testsuite_from_branch_name.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index 39c1ce85104..a4c2edeaccc 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -18,7 +18,7 @@ BRANCH_NAME=$2 BASE_NAME=$3 PR_NUMBER=$4 -cd ${CGAL_ROOT} + cd ${CGAL_GIT_DIR} if [ ! -d cgal ]; then git clone --depth 1 --no-single-branch https://github.com/CGAL/cgal.git @@ -43,7 +43,7 @@ for PKG in $(ls) ; do fi done if [ -f ${CGAL_ROOT}/list_test_packages ]; then rm ${CGAL_ROOT}/list_test_packages; fi -echo "list of pkgs = $LIST_OF_PKGS">${CGAL_ROOT}/log +echo "list of pkgs = ${LIST_OF_PKGS}">${CGAL_ROOT}/log if [ "$LIST_OF_PKGS" != "" ]; then for f in $LIST_OF_PKGS do @@ -55,10 +55,10 @@ fi #create the release from the branch echo " Create release..." CGAL_VERSION="$(sed -E 's/#define CGAL_VERSION (.*\..*)-dev/\1/' <(grep "#define CGAL_VERSION " Installation/include/CGAL/version.h))-Ic-${PR_NUMBER}" -echo "CGAL_VERSION = ${CGAL_VERSION}"> log cmake -DGIT_REPO=${CGAL_GIT_DIR}/cgal -DDESTINATION=${CGAL_ROOT}/CGAL-TEST -DPUBLIC=OFF -DTESTSUITE=ON -DCGAL_VERSION=${CGAL_VERSION} -P ${CGAL_GIT_DIR}/cgal/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake | tee log echo "done." DEST=$(sed -E 's/.*CGAL-TEST\/(.*)/\1/' log); +echo "CGAL_VERSION = ${CGAL_VERSION}"> log cd ${CGAL_ROOT} From dec96f5dd8f48b26d60b091f39551d48533ef8d7 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 28 Jul 2021 12:52:02 +0200 Subject: [PATCH 328/349] fix sourcing --- Scripts/developer_scripts/run_testsuite_from_branch_name.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index a4c2edeaccc..125b2035d31 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -11,8 +11,8 @@ if uname | grep -q -i cygwin; then export SHELLOPTS set -o igncr fi -( source ~/.autofilterrc +( USER_REPO=$1 BRANCH_NAME=$2 BASE_NAME=$3 From 2a861a7fd17caddb5373ca401230fa4890588037 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 28 Jul 2021 12:54:44 +0200 Subject: [PATCH 329/349] Fix list_of_pkgs --- Scripts/developer_scripts/run_testsuite_from_branch_name.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index 125b2035d31..dfd843a4e93 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -34,10 +34,11 @@ git checkout $BRANCH_NAME git reset --hard $USER_REPO/$BRANCH_NAME #setup the list_test_packages TMP_LIST=$(git diff --name-only HEAD cgal/$BASE_NAME |cut -s -d/ -f1 |sort -u | xargs -I {} ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true) + LIST_OF_PKGS="" for PKG in $(ls) ; do if [ -f $PKG/package_info/$PKG/dependencies ]; then - if [ -n "$(comm -12 <(echo "$LIST_OF_PKGS"|sort) <(cat $PKG/package_info/$PKG/dependencies|sort))" ]; then + if [ -n "$(comm -12 <(echo "$TMP_LIST"|sort) <(cat $PKG/package_info/$PKG/dependencies|sort))" ]; then LIST_OF_PKGS="$LIST_OF_PKGS $PKG" fi fi From 22a61aaa00f9cd07e126cbea228fedd84c9b869f Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 28 Jul 2021 13:53:15 +0200 Subject: [PATCH 330/349] remove debug --- Scripts/developer_scripts/run_testsuite_from_branch_name.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index dfd843a4e93..675ea0020d8 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -44,7 +44,6 @@ for PKG in $(ls) ; do fi done if [ -f ${CGAL_ROOT}/list_test_packages ]; then rm ${CGAL_ROOT}/list_test_packages; fi -echo "list of pkgs = ${LIST_OF_PKGS}">${CGAL_ROOT}/log if [ "$LIST_OF_PKGS" != "" ]; then for f in $LIST_OF_PKGS do @@ -59,7 +58,6 @@ CGAL_VERSION="$(sed -E 's/#define CGAL_VERSION (.*\..*)-dev/\1/' <(grep "#define cmake -DGIT_REPO=${CGAL_GIT_DIR}/cgal -DDESTINATION=${CGAL_ROOT}/CGAL-TEST -DPUBLIC=OFF -DTESTSUITE=ON -DCGAL_VERSION=${CGAL_VERSION} -P ${CGAL_GIT_DIR}/cgal/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake | tee log echo "done." DEST=$(sed -E 's/.*CGAL-TEST\/(.*)/\1/' log); -echo "CGAL_VERSION = ${CGAL_VERSION}"> log cd ${CGAL_ROOT} From 8743865c5258e392b30df5e30dcda96a40c5c0d1 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 29 Jul 2021 14:03:04 +0200 Subject: [PATCH 331/349] add error messages for other exit 1 cases --- .github/workflows/build_doc.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index 477c56a2acf..089e8d33c53 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -76,13 +76,14 @@ jobs: #list impacted packages LIST_OF_PKGS=$(git diff --name-only HEAD^1 HEAD |cut -s -d/ -f1 |sort -u | xargs -I {} echo {} && ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true) if [ "$LIST_OF_PKGS" = "" ]; then + echo "::set-output name=DoxygenError::No package affected." exit 1 fi cd build_doc && make -j2 doc make -j2 doc_with_postprocessing 2>tmp.log if [ -s tmp.log ]; then content=`cat ./tmp.log` - echo ::set-output name=DoxygenError::$(cat tmp.log) + echo "::set-output name=DoxygenError::$(cat tmp.log)" exit 1 fi cd .. @@ -101,6 +102,7 @@ jobs: mv tmp.html index.html git add ${PR_NUMBER}/$ROUND index.html && git commit -q --amend -m "base commit" && git push -q -f -u origin master else + echo "::set-output name=DoxygenError::This round already exists." exit 1 fi From 5072518a3d153721e1415d8314958fd1c95367b1 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 29 Jul 2021 14:31:10 +0200 Subject: [PATCH 332/349] add a force-build command to overwrite a round --- .github/workflows/build_doc.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index 089e8d33c53..7f74eee9a6b 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -21,6 +21,9 @@ jobs: const re = /\/build:(\w+)\s*/; if(re.test(body)){ const res = re.exec(body) + if(body.includes("force-")) { + echo "::set-output name=force::yes" + } return res[1]; } } @@ -72,7 +75,8 @@ jobs: PR_NUMBER=${{ steps.get_pr_number.outputs.result }} ROUND=${{ steps.get_round.outputs.result }} wget --no-verbose cgal.github.io -O tmp.html - if ! egrep -q "\/$PR_NUMBER\/$ROUND" tmp.html; then + const force = "${{steps.get_round.outputs.force}}" + if ! egrep -q "\/$PR_NUMBER\/$ROUND" tmp.html || [ "$force" = "yes" ]; then #list impacted packages LIST_OF_PKGS=$(git diff --name-only HEAD^1 HEAD |cut -s -d/ -f1 |sort -u | xargs -I {} echo {} && ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true) if [ "$LIST_OF_PKGS" = "" ]; then From f57715bb28b8f4f0a9e50782b16b1925ab901db8 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 29 Jul 2021 14:56:38 +0200 Subject: [PATCH 333/349] FIx force-build --- .github/workflows/build_doc.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index 7f74eee9a6b..8babc109d02 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -18,13 +18,15 @@ jobs: if(asso == 'OWNER' || asso == 'MEMBER') { const body = context.payload.comment.body if(body.includes("build:")) { - const re = /\/build:(\w+)\s*/; + const re = /\/(force-)?build:(\w+)\s*/; if(re.test(body)){ const res = re.exec(body) if(body.includes("force-")) { - echo "::set-output name=force::yes" + return "res[1]:yes"; + } + else{ + return "res[1]:no"; } - return res[1]; } } } @@ -73,7 +75,9 @@ jobs: run: | set -ex PR_NUMBER=${{ steps.get_pr_number.outputs.result }} - ROUND=${{ steps.get_round.outputs.result }} + TMP_ROUND=${{ steps.get_round.outputs.result }} + ROUND=$(echo $TMP_ROUND | cut -d ":" -f 1) + force=$(echo $TMP_ROUND | cut -d ":" -f 2) wget --no-verbose cgal.github.io -O tmp.html const force = "${{steps.get_round.outputs.force}}" if ! egrep -q "\/$PR_NUMBER\/$ROUND" tmp.html || [ "$force" = "yes" ]; then @@ -106,7 +110,7 @@ jobs: mv tmp.html index.html git add ${PR_NUMBER}/$ROUND index.html && git commit -q --amend -m "base commit" && git push -q -f -u origin master else - echo "::set-output name=DoxygenError::This round already exists." + echo "::set-output name=DoxygenError::This round already exists. Overwrite it with `/build-force`" exit 1 fi From 0eb5ee618d914791f41835e6d7f936b6ddeca060 Mon Sep 17 00:00:00 2001 From: Maxime GIMENO Date: Thu, 29 Jul 2021 15:06:07 +0200 Subject: [PATCH 334/349] Update .github/workflows/build_doc.yml Co-authored-by: Laurent Rineau --- .github/workflows/build_doc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index 8babc109d02..b12a57f92e1 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -110,7 +110,7 @@ jobs: mv tmp.html index.html git add ${PR_NUMBER}/$ROUND index.html && git commit -q --amend -m "base commit" && git push -q -f -u origin master else - echo "::set-output name=DoxygenError::This round already exists. Overwrite it with `/build-force`" + echo "::set-output name=DoxygenError::This round already exists. Overwrite it with `/force-build`" exit 1 fi From 6419ac94707711602353d266854548fef609d2a6 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 29 Jul 2021 15:42:27 +0200 Subject: [PATCH 335/349] Fix typo --- .github/workflows/build_doc.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index b12a57f92e1..903e3cacc44 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -79,7 +79,6 @@ jobs: ROUND=$(echo $TMP_ROUND | cut -d ":" -f 1) force=$(echo $TMP_ROUND | cut -d ":" -f 2) wget --no-verbose cgal.github.io -O tmp.html - const force = "${{steps.get_round.outputs.force}}" if ! egrep -q "\/$PR_NUMBER\/$ROUND" tmp.html || [ "$force" = "yes" ]; then #list impacted packages LIST_OF_PKGS=$(git diff --name-only HEAD^1 HEAD |cut -s -d/ -f1 |sort -u | xargs -I {} echo {} && ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true) From 9e01da635d59cc29d369a047bb4fb68b21946654 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 30 Jul 2021 09:51:37 +0200 Subject: [PATCH 336/349] FIX result of first job --- .github/workflows/build_doc.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index 903e3cacc44..ee65d8f7ef0 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -22,10 +22,10 @@ jobs: if(re.test(body)){ const res = re.exec(body) if(body.includes("force-")) { - return "res[1]:yes"; + return res[2]+":yes" } else{ - return "res[1]:no"; + return res[2]+":no" } } } From a945067ae603df2bdbda88d0bb59b23f77ea2106 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 30 Jul 2021 09:59:04 +0200 Subject: [PATCH 337/349] fix error text --- .github/workflows/build_doc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index ee65d8f7ef0..9d9ca8cb4be 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -109,7 +109,7 @@ jobs: mv tmp.html index.html git add ${PR_NUMBER}/$ROUND index.html && git commit -q --amend -m "base commit" && git push -q -f -u origin master else - echo "::set-output name=DoxygenError::This round already exists. Overwrite it with `/force-build`" + echo "::set-output name=DoxygenError::This round already exists. Overwrite it with /force-build" exit 1 fi From e1e77563f709a3a2488287d1fafc432fbf762516 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 30 Jul 2021 10:17:08 +0200 Subject: [PATCH 338/349] fix address --- .github/workflows/build_doc.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index 9d9ca8cb4be..2e79aaa205a 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -118,6 +118,9 @@ jobs: if: ${{ success() && steps.get_round.outputs.result != 'stop' }} with: script: | + const tmp_round=${{ steps.get_round.outputs.result }} + const id=tmp_round.indexOf(':') + const round = tmp_round.substring(0,id); const address = "The documentation is built. It will be available, after a few minutes, here : https://cgal.github.io/${{ steps.get_pr_number.outputs.result }}/${{ steps.get_round.outputs.result }}/Manual/index.html" github.issues.createComment({ owner: "CGAL", From 3fe1cef92aa45bf46f58551b7231a4c6cb33b253 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 30 Jul 2021 11:04:49 +0200 Subject: [PATCH 339/349] more fix --- .github/workflows/build_doc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index 2e79aaa205a..016ead703d7 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -121,7 +121,7 @@ jobs: const tmp_round=${{ steps.get_round.outputs.result }} const id=tmp_round.indexOf(':') const round = tmp_round.substring(0,id); - const address = "The documentation is built. It will be available, after a few minutes, here : https://cgal.github.io/${{ steps.get_pr_number.outputs.result }}/${{ steps.get_round.outputs.result }}/Manual/index.html" + const address = "The documentation is built. It will be available, after a few minutes, here : https://cgal.github.io/${{ steps.get_pr_number.outputs.result }}/"+round+"/Manual/index.html" github.issues.createComment({ owner: "CGAL", repo: "cgal", From ddf5ff66005cccd760a775850483ada8c6b0e80d Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 30 Jul 2021 11:12:23 +0200 Subject: [PATCH 340/349] more fixes --- .github/workflows/build_doc.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index 016ead703d7..25d9ef050d7 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -118,8 +118,8 @@ jobs: if: ${{ success() && steps.get_round.outputs.result != 'stop' }} with: script: | - const tmp_round=${{ steps.get_round.outputs.result }} - const id=tmp_round.indexOf(':') + const tmp_round=${{ steps.get_round.outputs.result }}; + const id = tmp_round.indexOf(":"); const round = tmp_round.substring(0,id); const address = "The documentation is built. It will be available, after a few minutes, here : https://cgal.github.io/${{ steps.get_pr_number.outputs.result }}/"+round+"/Manual/index.html" github.issues.createComment({ From 30ceb97b8dbfb3fe9e6f7a2c7b8034484f1cb01f Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 30 Jul 2021 11:34:41 +0200 Subject: [PATCH 341/349] Fix the adress --- .github/workflows/build_doc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index 25d9ef050d7..974d8e55f2f 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -118,7 +118,7 @@ jobs: if: ${{ success() && steps.get_round.outputs.result != 'stop' }} with: script: | - const tmp_round=${{ steps.get_round.outputs.result }}; + const tmp_round = "${{ steps.get_round.outputs.result }}"; const id = tmp_round.indexOf(":"); const round = tmp_round.substring(0,id); const address = "The documentation is built. It will be available, after a few minutes, here : https://cgal.github.io/${{ steps.get_pr_number.outputs.result }}/"+round+"/Manual/index.html" From f9e2b630e97ed76b45dfd82164dcc074cb13b4c1 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 30 Jul 2021 13:20:03 +0200 Subject: [PATCH 342/349] CLea-up and simplify --- .github/workflows/filter_testsuite.yml | 47 ++++---------------------- 1 file changed, 7 insertions(+), 40 deletions(-) diff --git a/.github/workflows/filter_testsuite.yml b/.github/workflows/filter_testsuite.yml index 2c2bc279eeb..ba7b4a8792a 100644 --- a/.github/workflows/filter_testsuite.yml +++ b/.github/workflows/filter_testsuite.yml @@ -9,20 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/github-script@v3 - id: check - with: - result-encoding: string - script: | - const userName = context.payload.comment.user.login - if(userName == 'maxGimeno') { - const body = context.payload.comment.body - if(body.includes("/testme")) { - return 'OK' - } - } - return 'stop' - - uses: actions/github-script@v3 - if: steps.check.result != 'stop' + if: github.event.comment.user.login == 'maxGimeno' && contains(github.event.comment.body, '/testme') id: get_label with: result-encoding: string @@ -31,31 +18,11 @@ jobs: const pr_url = context.payload.issue.pull_request.url const pr_content = await github.request(pr_url) const label = pr_content.data.head.label - console.log(label) - return label - - uses: actions/github-script@v3 - if: steps.check.result != 'stop' - id: get_base - with: - result-encoding: string - script: | - //get branch name and username - const pr_url = context.payload.issue.pull_request.url - const pr_content = await github.request(pr_url) const base = pr_content.data.base.ref - console.log(base) - return base - - uses: actions/github-script@v3 - if: steps.get_round.outputs.result != 'stop' - id: get_pr_number - with: - result-encoding: string - script: | - //get pullrequest url - const pr_number = context.payload.issue.number - return pr_number + console.log(label) + return label+":"+base - name: Run Testsuite - if: steps.check.outputs.result != 'stop' + if: github.event.comment.user.login == 'maxGimeno' && contains(github.event.comment.body, '/testme') run: | mkdir -p ~/.ssh #ssh key @@ -82,8 +49,8 @@ jobs: LABEL="${{ steps.get_label.outputs.result }}" USER_NAME=$(echo $LABEL | cut -d':' -f 1) BRANCH_NAME=$(echo $LABEL | cut -d':' -f 2) - PR_NUMBER=${{ steps.get_pr_number.outputs.result }} - BASE="${{ steps.get_base.outputs.result }}" + BASE=$(echo $LABEL | cut -d':' -f 3) + PR_NUMBER=${{ github.event.issue.number }} mapfile -t HOSTS < ~/ssh_host_list; for i in ${!HOSTS[@]}; do HOST=$(echo ${HOSTS[$i]}|cut -d' ' -f 1 ) @@ -93,7 +60,7 @@ jobs: done - name: Post address uses: actions/github-script@v3 - if: steps.check.outputs.result != 'stop' + if: github.event.comment.user.login == 'maxGimeno' && contains(github.event.comment.body, '/testme') with: script: | const address = "The testsuite is lauched. results will be found, after it is done, here : https://cgal.geometryfactory.com/~mgimeno/test_suite/TESTRESULTS/index.shtml " From 618b439d9a0f557a6226e5122e04dfb3409083e2 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 30 Jul 2021 14:25:34 +0200 Subject: [PATCH 343/349] Factorize condition --- .github/workflows/filter_testsuite.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/filter_testsuite.yml b/.github/workflows/filter_testsuite.yml index ba7b4a8792a..3748df82818 100644 --- a/.github/workflows/filter_testsuite.yml +++ b/.github/workflows/filter_testsuite.yml @@ -6,10 +6,10 @@ on: jobs: build: + if: github.event.comment.user.login == 'maxGimeno' && contains(github.event.comment.body, '/testme') runs-on: ubuntu-latest steps: - uses: actions/github-script@v3 - if: github.event.comment.user.login == 'maxGimeno' && contains(github.event.comment.body, '/testme') id: get_label with: result-encoding: string @@ -22,7 +22,6 @@ jobs: console.log(label) return label+":"+base - name: Run Testsuite - if: github.event.comment.user.login == 'maxGimeno' && contains(github.event.comment.body, '/testme') run: | mkdir -p ~/.ssh #ssh key @@ -60,7 +59,6 @@ jobs: done - name: Post address uses: actions/github-script@v3 - if: github.event.comment.user.login == 'maxGimeno' && contains(github.event.comment.body, '/testme') with: script: | const address = "The testsuite is lauched. results will be found, after it is done, here : https://cgal.geometryfactory.com/~mgimeno/test_suite/TESTRESULTS/index.shtml " From 38b075b63a3e7739160e6af5442d0a2b6566b6fa Mon Sep 17 00:00:00 2001 From: Maxime GIMENO Date: Fri, 30 Jul 2021 15:01:44 +0200 Subject: [PATCH 344/349] Update filter_testsuite.yml --- .github/workflows/filter_testsuite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/filter_testsuite.yml b/.github/workflows/filter_testsuite.yml index 3748df82818..2a11fd2cc71 100644 --- a/.github/workflows/filter_testsuite.yml +++ b/.github/workflows/filter_testsuite.yml @@ -63,7 +63,7 @@ jobs: script: | const address = "The testsuite is lauched. results will be found, after it is done, here : https://cgal.geometryfactory.com/~mgimeno/test_suite/TESTRESULTS/index.shtml " github.issues.createComment({ - owner: "maxGimeno", + owner: "CGAL", repo: "cgal", issue_number: ${{ github.event.issue.number }}, body: address From e157a4aac9e2a831af90daec4a36bc1e0dc412aa Mon Sep 17 00:00:00 2001 From: Maxime GIMENO Date: Fri, 30 Jul 2021 15:27:49 +0200 Subject: [PATCH 345/349] Fix diff --- Scripts/developer_scripts/run_testsuite_from_branch_name.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index 675ea0020d8..7daf8b19526 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -33,7 +33,7 @@ git fetch --depth 1 $USER_REPO git checkout $BRANCH_NAME git reset --hard $USER_REPO/$BRANCH_NAME #setup the list_test_packages -TMP_LIST=$(git diff --name-only HEAD cgal/$BASE_NAME |cut -s -d/ -f1 |sort -u | xargs -I {} ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true) +TMP_LIST=$(git diff --name-only cgal/$BASE_NAME...HEAD |cut -s -d/ -f1 |sort -u | xargs -I {} ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true) LIST_OF_PKGS="" for PKG in $(ls) ; do From 62835eb601bccdc22d30c54ac0d9818b2f6a7089 Mon Sep 17 00:00:00 2001 From: Maxime GIMENO Date: Fri, 30 Jul 2021 15:46:28 +0200 Subject: [PATCH 346/349] No shallow clone to keep the history for the diff --- Scripts/developer_scripts/run_testsuite_from_branch_name.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index 7daf8b19526..bc1d32e0ec2 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -21,7 +21,7 @@ PR_NUMBER=$4 cd ${CGAL_GIT_DIR} if [ ! -d cgal ]; then - git clone --depth 1 --no-single-branch https://github.com/CGAL/cgal.git + git clone https://github.com/CGAL/cgal.git cd cgal git remote rename origin cgal cd .. From 314f86756457d947f9565ce6c41abf9604f93430 Mon Sep 17 00:00:00 2001 From: Maxime GIMENO Date: Fri, 30 Jul 2021 15:52:10 +0200 Subject: [PATCH 347/349] No --depth 1 anywhere --- Scripts/developer_scripts/run_testsuite_from_branch_name.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh index bc1d32e0ec2..b5ce2554e68 100644 --- a/Scripts/developer_scripts/run_testsuite_from_branch_name.sh +++ b/Scripts/developer_scripts/run_testsuite_from_branch_name.sh @@ -27,9 +27,9 @@ if [ ! -d cgal ]; then cd .. fi cd cgal -git fetch --depth 1 cgal +git fetch cgal git remote add $USER_REPO https://github.com/$USER_REPO/cgal.git -git fetch --depth 1 $USER_REPO +git fetch $USER_REPO git checkout $BRANCH_NAME git reset --hard $USER_REPO/$BRANCH_NAME #setup the list_test_packages From 753fc4d434f416450a78d01842d09805947680a3 Mon Sep 17 00:00:00 2001 From: Mael Date: Wed, 4 Aug 2021 09:04:48 +0200 Subject: [PATCH 348/349] Minor comment fixes --- .../include/CGAL/Polyhedral_envelope.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polyhedral_envelope.h b/Polygon_mesh_processing/include/CGAL/Polyhedral_envelope.h index abc6f3804e4..c8d8b784513 100644 --- a/Polygon_mesh_processing/include/CGAL/Polyhedral_envelope.h +++ b/Polygon_mesh_processing/include/CGAL/Polyhedral_envelope.h @@ -47,11 +47,11 @@ // } // // The code below uses the version of -// https://github.com/wangbolun300/fast-envelope avaiable on 7th of October 2020 +// https://github.com/wangbolun300/fast-envelope available on 7th of October 2020. // -// The code below only use the high level algorithms of checking that a query -// is covered by a set of prisms, where each prism is an offset for an input triangle. -// That is, we do not use indirect predicates +// The code below only uses the high-level algorithms checking that a query +// is covered by a set of prisms, where each prism is the offset of an input triangle. +// That is, we do not use indirect predicates. #ifndef CGAL_POLYGON_MESH_PROCESSING_POLYHEDRAL_ENVELOPE_H #define CGAL_POLYGON_MESH_PROCESSING_POLYHEDRAL_ENVELOPE_H From 5b6f3abac2464158a8a0c7027bd0f7aa61993a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 4 Aug 2021 20:58:53 +0200 Subject: [PATCH 349/349] fix iteration up to the end --- Documentation/doc/scripts/testsuite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/doc/scripts/testsuite.py b/Documentation/doc/scripts/testsuite.py index 4e9e7393552..f303a6e3c98 100755 --- a/Documentation/doc/scripts/testsuite.py +++ b/Documentation/doc/scripts/testsuite.py @@ -150,7 +150,7 @@ body {color: black; background-color: #C0C0D0; font-family: sans-serif;} for index in range(0, len(results1)): result = [('./build_logs', './build_logs', (0,1))] results_master.extend(result) - for index in range(0, len(results1)-1): + for index in range(0, len(results1)): status='class="package-good"' no_errors = True no_warn = True

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 IjaktD08A?3 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 j0qYkX=<8<~h6{=Cj!^_}XytDIdmyYW?9Jd(`U literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-no_conflict.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-no_conflict.png new file mode 100644 index 0000000000000000000000000000000000000000..4d544baf562c0f0877201f2d1ddbc75c6fe8fd8e GIT binary patch literal 5970 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 Mf+n>7m1V^L0A}S8;Q#;t literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-right_vertex_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-right_vertex_bw.png new file mode 100644 index 0000000000000000000000000000000000000000..908c9e41ad17883386fc53633b098c149d572b61 GIT binary patch literal 3236 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 literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-false.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-false.png new file mode 100644 index 0000000000000000000000000000000000000000..2b67ce1e7fcbb916bb1cfd27ca2095ac4e447e76 GIT binary patch literal 5985 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 literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-false_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-false_bw.png new file mode 100644 index 0000000000000000000000000000000000000000..93a0a00da0a033a76b985da9aa8434d367f0ef8b GIT binary patch literal 2864 zcmd7U`#;l*1IKZf<2Iy7kxLsVg(OpBF1gJuWki>$T!+dSGxuBQ=5FQMi6Ye65JGc3 z#dkirOb(LED4Xjr+uSYAIX`^=hx5bx@pwO8f59`w$T=2PuZ+WjU^-BX~89eX>ROs%ct~V z@dn(RLcM+_{ZAE3wD}V$ae^QO3Py-N0PY`DJg6r8UyIp1btK33$&^jcI5}B(umu@TwIhD>B9BG$P^==ZwC1d^6)f^rzwYtS% zVE{gkna4mxyQq!KDIJn^mj-Qk8uhLR(sW^H~b#&K{AbzhdN=JHq zxLH}Hy<2!sA8l~79bc;V;EUt>PNmfTh5ffn;JSXyn(5G{p*n%pHSx0gIAY(u#usLO zEs!@=m6|M>{j7TH*9jj+tSIv@)$wb%hu>32e+ZO~du-QMFBjaBpM+~4C}|{x9hmu* zu@p{sJcaogtHGQcG58fkdP*kt3x0Kjj!Z$H@_KUY#emSjy2`Hu zgJ-$(u8Skmi*Rsbu7aFvTj>3B1{-Iq_~u z%ECQ2U0IYpOnJ@GeD14vhcy-6L7x+hz5i`c>uTpv3 zlrd)K5#7No5$o5lj?6mm_gM0GE}7F!FW`DjcIoAtJ329n%%aNVtWiJ3=$|O&CO4tG zkbMt@$lSl4V z7E}DeCl=~8SnY*c(o7l8joJfd(;G)(79HS+ah66F^aRN_Nt~AE32lAkRQsrkZaTq% zwvIfLOK_k{1B1KOq3Ux*V)0$AVE^`}heWVJEA7xxxc#pskFNcO-fG5F{*T3gZ73iy zpQzL(pPt|`cN)^z>KP%*%)uMrh~>$bRkxvCOd~uA9|Ac}JJap3ea!!;2CWiEa68%K z2qd?Y;xEL!@1ZU*9;V{TdKN9_)4;le56o$(xtbm-(c|^vsiXdJezG7q-MF&uC!Y@;t1u2&sCXm5siA}%W5ohL< z$1`SW^|15WuX-z+*5tSO)+gezL7&tZ#4KctI}kj>AX$y&t%s&5sbRU1^8{IV20v~( zAiAD+7?@Y;Le>Wm;9=2vnNr(^R?5t=|Jg07`*i@b$9q%C_)*VFemINyh%jlH)u|I} z+5wt4Y}a+03vIif??PCRj+{5#m^0AsVrnV?$e5=PBCsjOaA>e5k`*I;LWT}*RwU75 zWwsN)jF^c4O1{?_gAk+=dRwq#-LoW8$v&OyHZ$|prRRabKl`(POHoj|Bvw*wITb!7QA<_45zY8Y-K& zu9Mx#G8F<*c_tB>q)Np=*}$3BJ3FNIP47rPznU0!9(k`51~eTtjGAUAt5WzY-5rK7 z?(de9Q`4G06X6bR_pCk8*0W(wU(RGje9>GANdomB0WNlr+xy1wRf|c+^1nDm&(%_Q z$1W zBBL`)uTa@NN;HW^OagaoK45@gTzy?WEbL*$UE4R%dTb!z!--^bKAL z40}Pvze_vLrvZQ)!sakr8Rf%4RX}?&RT|Rk?6W+vs8u-yL>4_5R!-%#6pHe7Kmru^>Q37Z8@={J0E4r^{0xb#_y;8b%%pUn$i%qU! z&kKR;r#}vb5f{(t6RK|n6IoZ*jrFG@1Pcn;U?Hi?=+2?o4v6Qywy-051|Jj%%K`Ka zh7{kEmMhx6Jh!!#;`)`z$DH>LzX4GjAED?%S7|z%tweEbR`SCA#?!)hb2LJ7R-mN= zG7o!NB^Q0fLn6}3m8TlHk4DHlt3=%0RN$5sK!2~ zH}J$ngiw}7NuK-*TFij3 zwmPAikIAo;F)Fr*y}gttRySk%-($ZtC!$@1oqVPsucKO&>|nz>@&v) zYI9<&edfAYYsp-WLt_jsjcQI9&qU-ob|ALw#^}gYn=~Xy5R=KE9^GL4i20 W2u%?C+_Q~;DQs`;h^VskO!^y^`CrKZ literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-true.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-true.png new file mode 100644 index 0000000000000000000000000000000000000000..4e2caf6b1ddb3a682f7a9b0ca57c5c0f1bab6024 GIT binary patch literal 6126 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 Q9s+>(vZ|13X|vG(1DQJF$N&HU literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-true_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius-vertex_conflict-true_bw.png new file mode 100644 index 0000000000000000000000000000000000000000..da68029a930de9299201b34fb4f9b121865a4cc3 GIT binary patch literal 3064 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 DI1bOh literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_diagram.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..13d893e7cc822105443644da2107fa24d9fdcc40 GIT binary patch literal 12363 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 literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_diagram_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_diagram_bw.png new file mode 100644 index 0000000000000000000000000000000000000000..76437491b4b6694cb961115fd87297c57d2749cd GIT binary patch literal 5396 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 W|2zCBXomiC07!_)3fBng2mTMg&tMz? literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_graph_bw.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/apollonius_graph_bw.png new file mode 100644 index 0000000000000000000000000000000000000000..fbcca9aa0cd3af6275f501b7f9df7e70b4d9b4da GIT binary patch literal 6515 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 ZZE|6EDGKj2llA}r002ovPDHLkV1h0$0<{1D literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig/insert_degree_2.png b/Apollonius_graph_2/doc/Apollonius_graph_2/fig/insert_degree_2.png new file mode 100644 index 0000000000000000000000000000000000000000..dbf53288ceb90b3633985932fb3d7562bbdb35c5 GIT binary patch literal 5244 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 YN-EMWZ`Ga)bs})i+QEu)#w+pv0R31M;Q#;t literal 0 HcmV?d00001 diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/fig_src/insert_degree_2.fig b/Apollonius_graph_2/doc/Apollonius_graph_2/fig_src/insert_degree_2.fig new file mode 100644 index 0000000000000000000000000000000000000000..acc8413f6f46b2db4ffd5cfe697b4ba01528bc18 GIT binary patch literal 2599 zcmbtW%Wm5+5ImP(L7?XZBt?qixj>5mx%JwMk*cYSR4HsD-`|-fB|5Hb(vQD3*y^UJ8Bvd$Ro zRIl>`wzc;z=xBnO-+Ic}P_~rURvR4*zO1%`CLs3+Q9dzf-$CN-n=uv&lobUCV6`aV zoi#yQ%8FSd3U@tBdkZ&wKkxV&=#i=mblEgv+Fq- z%m@^zE6L%P4aCEfYJhPO!p<)+b?pYk&7EeLzR#`@k+8BB7(TVYc$8dRFG1CHE(L>f zQhSH|#9Yw3k`pO07x;7P!%;>S7$`HbMVUWq$^ptX4>hqhs0FafU1*FX1?t$Lu0uy{ zOG}>VVHZSRtaStAe_WCG(gT9uC*=LtWqCW~84&}44n5C(*Xzh`7cZ@0OQLWbLU}En z9a9;H3jvoQjFIDW!w^PJ&FK(gI^l;*VRor)46Tv5yJ(j53)x@C~p*(V8mk@OY{m@PAkY#E7fw9F80vdo&gxd|FrBXu6^=#wvVTGz=t zD?2UYJ{abSoCSyRU)O`20*xG&(E7(5R@bQmYAc6{+7XAg8e znP82HNMkiA6{wxZYAz~H4Xh&SMNp9;kxzWq2-fKCol~M00vf1-L7<#gJgf5a&9JCk zhu*jbd-f_&W>Ng>0vc_eh%>Z1(_#*&heD>svj*n7Mk2VdRzC1?b;xHFFCA+sM5XBi zic2|<9I;3FgKGnRkUlRg%Zowe&4*Wn{|C)bLUIC+rxQXsxfu1y=$3Ux6^*y9k#ENDE`https://www.gnu.org/software/glpk/`. @@ -309,12 +306,18 @@ The \glpk web site is `https://www. \scip (Solving Constraint Integer Programs) is currently one of the fastest open source solvers for mixed integer programming (MIP) and mixed integer nonlinear programming (MINLP). -In \cgal, \scip provides an optional linear integer program solver -in the \ref PkgPolygonalSurfaceReconstruction package. In order to use -\scip in \cgal programs, the executables should be linked with the -CMake imported target `CGAL::SCIP_support` provided in -`CGAL_SCIP_support.cmake`. +In \cgal, \scip provides an optional linear integer program solver in the \ref PkgPolygonalSurfaceReconstruction package. +In order to use \scip in \cgal programs, the executables should be linked with the CMake imported target `CGAL::SCIP_support` provided in `CGAL_SCIP_support.cmake`. The \scip web site is `http://scip.zib.de/`. +\subsection thirdpartyOSQP OSQP + +\osqp (Operator Splitting Quadratic Program) is currently one of the fastest open source solvers for convex Quadratic Programs (QP). + +In \cgal, \osqp provides an optional solver for the QP problems often arising in various computational geometry algorithms. +In order to use \osqp in \cgal programs, the executables should be linked with the CMake imported target `CGAL::OSQP_support` provided in `CGAL_OSQP_support.cmake`. + +The \osqp web site is `https://osqp.org`. + */ diff --git a/Documentation/doc/resources/1.8.13/BaseDoxyfile.in b/Documentation/doc/resources/1.8.13/BaseDoxyfile.in index 90cb15aabb7..259b0709b4a 100644 --- a/Documentation/doc/resources/1.8.13/BaseDoxyfile.in +++ b/Documentation/doc/resources/1.8.13/BaseDoxyfile.in @@ -266,6 +266,7 @@ ALIASES = "cgal=%CGAL" \ "ceres=Ceres" \ "glpk=GLPK" \ "scip=SCIP" \ + "osqp=OSQP" \ "rs=RS" \ "rs3=RS3" \ "unix=Unix" \ diff --git a/Documentation/doc/resources/1.8.14/BaseDoxyfile.in b/Documentation/doc/resources/1.8.14/BaseDoxyfile.in index 96fd516d1ca..f0586530fc4 100644 --- a/Documentation/doc/resources/1.8.14/BaseDoxyfile.in +++ b/Documentation/doc/resources/1.8.14/BaseDoxyfile.in @@ -267,6 +267,7 @@ ALIASES = "cgal=%CGAL" \ "ceres=Ceres" \ "glpk=GLPK" \ "scip=SCIP" \ + "osqp=OSQP" \ "rs=RS" \ "rs3=RS3" \ "unix=Unix" \ diff --git a/Documentation/doc/resources/1.8.20/BaseDoxyfile.in b/Documentation/doc/resources/1.8.20/BaseDoxyfile.in index afb52c9c5af..7cdd82581dc 100644 --- a/Documentation/doc/resources/1.8.20/BaseDoxyfile.in +++ b/Documentation/doc/resources/1.8.20/BaseDoxyfile.in @@ -289,6 +289,7 @@ ALIASES = "cgal=%CGAL" \ "ceres=Ceres" \ "glpk=GLPK" \ "scip=SCIP" \ + "osqp=OSQP" \ "rs=RS" \ "rs3=RS3" \ "unix=Unix" \ diff --git a/Documentation/doc/resources/1.8.4/BaseDoxyfile.in b/Documentation/doc/resources/1.8.4/BaseDoxyfile.in index 9124909bf7c..fcb7026306b 100644 --- a/Documentation/doc/resources/1.8.4/BaseDoxyfile.in +++ b/Documentation/doc/resources/1.8.4/BaseDoxyfile.in @@ -235,6 +235,7 @@ ALIASES += "zlib=zlib" ALIASES += "ceres=Ceres" ALIASES += "glpk=GLPK" ALIASES += "scip=SCIP" +ALIASES += "osqp=OSQP" ALIASES += "rs=RS" ALIASES += "rs3=RS3" ALIASES += "unix=Unix" diff --git a/Installation/cmake/modules/CGAL_OSQP_support.cmake b/Installation/cmake/modules/CGAL_OSQP_support.cmake new file mode 100644 index 00000000000..6252d3aeeae --- /dev/null +++ b/Installation/cmake/modules/CGAL_OSQP_support.cmake @@ -0,0 +1,7 @@ +if(OSQP_FOUND AND NOT TARGET CGAL::OSQP_support) + add_library(CGAL::OSQP_support INTERFACE IMPORTED) + set_target_properties(CGAL::OSQP_support PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "CGAL_USE_OSQP" + INTERFACE_INCLUDE_DIRECTORIES "${OSQP_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "${OSQP_LIBRARIES}") +endif() diff --git a/Installation/cmake/modules/FindOSQP.cmake b/Installation/cmake/modules/FindOSQP.cmake new file mode 100644 index 00000000000..1fe8e048769 --- /dev/null +++ b/Installation/cmake/modules/FindOSQP.cmake @@ -0,0 +1,23 @@ +# This file sets up OSQP for CMake. Once done this will define +# OSQP_FOUND - system has OSQP lib +# OSQP_INCLUDE_DIR - the OSQP include directory +# OSQP_LIBRARIES - link these to use OSQP + +if(NOT OSQP_FOUND) + find_path(OSQP_INCLUDE_DIR + NAMES osqp.h + PATHS /usr/local/include/osqp/ + ENV OSQP_INC_DIR) + + find_library(OSQP_LIBRARIES + NAMES libosqp osqp + PATHS ENV LD_LIBRARY_PATH + ENV LIBRARY_PATH + /usr/local/lib + ${OSQP_INCLUDE_DIR}/../lib + ENV OSQP_LIB_DIR) + + if(OSQP_LIBRARIES AND OSQP_INCLUDE_DIR) + set(OSQP_FOUND TRUE) + endif() +endif() diff --git a/Solver_interface/doc/Solver_interface/Concepts/LinearProgramTraits.h b/Solver_interface/doc/Solver_interface/Concepts/LinearProgramTraits.h new file mode 100644 index 00000000000..9d44b4a667f --- /dev/null +++ b/Solver_interface/doc/Solver_interface/Concepts/LinearProgramTraits.h @@ -0,0 +1,112 @@ +/*! +\ingroup PkgSolverInterfaceConcepts +\cgalConcept + +A concept that describes the set of methods used to define and solve a +linear programming (LP) problem of the general form: +