diff --git a/.travis/test_package.sh b/.travis/test_package.sh index f91f9982916..7b01d24ceb4 100644 --- a/.travis/test_package.sh +++ b/.travis/test_package.sh @@ -5,11 +5,17 @@ DO_IGNORE=FALSE cd $1 -if [ ! -f "$2/package_info/$2/dependencies" ];then + +if [ ! -d "$2" ]; then + echo "$2 : MISSING PACKAGE. Ignoring." + DO_IGNORE=TRUE + exit 1 +fi + + +if [ ! -f "$2/package_info/$2/dependencies" ];then echo "No dependencies found for $2" - bash Scripts/developer_scripts/cgal_check_dependencies.sh --check_headers /usr/bin/doxygen - - + bash Scripts/developer_scripts/cgal_check_dependencies.sh --check_headers /usr/bin/doxygen exit 1 fi LIST_OF_FILES=$(git diff --name-only origin/master... |cut -d/ -f1 |uniq |sort) 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 index 8f29331cbfb..196fc8451f1 100644 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt @@ -369,9 +369,9 @@ 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 -`Ring_tag` and `Sqrt_field_tag`. When -`Ring_tag` is used, only ring operations are used during the -evaluation of the predicates, whereas if `Sqrt_field_tag` is +`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. @@ -379,32 +379,22 @@ 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 `Ring_tag` as tag will give exact predicates, -whereas `MP_Float` with `Sqrt_field_tag` will give +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. -Since using an exact number type may be too slow, the -`Apollonius_graph_traits_2` class is designed to -support the dynamic filtering of \cgal through the -`Filtered_exact` mechanism. In particular if `CT` -is an inexact number type that supports the operations denoted by the -tag `Method_tag` and `ET` is an exact number type for these -operations, then kernel with number type -`Filtered_exact` will yield exact predicates for the -Apollonius graph traits. To give a concrete example, -`CGAL::Filtered_exact` with -`Ring_tag` will produce exact predicates. - -Another possibility for fast and exact predicate evaluation is to use -the -`Apollonius_graph_filtered_traits_2` -class. This class is the analog of a filtered kernel. It takes a +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). -It evaluates the predicates by first using the filtering kernel, and -if this fails the evaluation is performed using the exact kernel. The -constructions are done using the kernel `CK`, which means that +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. 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 index a1b4a8003d5..c49c4a0bb76 100644 --- 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 @@ -20,8 +20,8 @@ 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::Sqrt_field_tag` and -`CGAL::Ring_tag`. The first one must be used when the number type +`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 @@ -31,7 +31,7 @@ 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::Ring_tag`, +`CM = CGAL::Integral_domain_without_division_tag`, `EK = CGAL::Simple_cartesian`, `EM = CM`, `FK = CGAL::Simple_cartesian >`, @@ -41,8 +41,8 @@ The default values for the template parameters are as follows: \sa `Kernel` \sa `ApolloniusGraphTraits_2` -\sa `CGAL::Ring_tag` -\sa `CGAL::Sqrt_field_tag` +\sa `CGAL::Integral_domain_without_division_tag` +\sa `CGAL::Field_with_sqrt_tag` \sa `CGAL::Apollonius_graph_2` \sa `CGAL::Apollonius_graph_traits_2` 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 index 6f3d11a7517..2b9ebca5625 100644 --- 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 @@ -10,13 +10,13 @@ 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::Sqrt_field_tag` and `CGAL::Ring_tag`. The first one +`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::Ring_tag`. +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}. @@ -24,8 +24,8 @@ The way the predicates are evaluated is discussed in \sa `Kernel` \sa `ApolloniusGraphTraits_2` -\sa `CGAL::Ring_tag` -\sa `CGAL::Sqrt_field_tag` +\sa `CGAL::Integral_domain_without_division_tag` +\sa `CGAL::Field_with_sqrt_tag` \sa `CGAL::Apollonius_graph_2` \sa `CGAL::Apollonius_graph_filtered_traits_2` diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies b/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies index 49ad6034b25..6270b1d0d3b 100644 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies @@ -5,5 +5,6 @@ Algebraic_foundations Circulator Stream_support Voronoi_diagram_2 +Number_types TDS_2 Triangulation_2 diff --git a/Apollonius_graph_2/include/CGAL/Apollonius_graph_2/check_filter.h b/Apollonius_graph_2/include/CGAL/Apollonius_graph_2/check_filter.h deleted file mode 100644 index d2395df4880..00000000000 --- a/Apollonius_graph_2/include/CGAL/Apollonius_graph_2/check_filter.h +++ /dev/null @@ -1,38 +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_CHECK_FILTER_H -#define CGAL_CHECK_FILTER_H - -#include - - -#undef CGAL_IA_NEW_FILTERS - -namespace CGAL { - -template < class T> -void must_be_filtered(const T&) -{} - -#if defined CGAL_ARITHMETIC_FILTER_H -template < class CT, class ET, class Type, bool Protection, class Cache> -void must_be_filtered(const Filtered_exact &) -{ dont_compile(CT(), ET()); } -#endif - -} - -#endif diff --git a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag2.cpp b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag2.cpp index 22c23e75145..9b338b30edb 100644 --- a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag2.cpp +++ b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag2.cpp @@ -3,76 +3,31 @@ #include #include -#define DONT_USE_FILTERED_EXACT // choose number type #include -#ifndef DONT_USE_FILTERED_EXACT -# include -#endif typedef double inexact_type; typedef CGAL::MP_Float exact_type; -#ifndef DONT_USE_FILTERED_EXACT -typedef CGAL::Filtered_exact number_t; -#endif - #include -#ifndef DONT_USE_FILTERED_EXACT -typedef CGAL::Simple_cartesian Kernel; -#endif - typedef CGAL::Integral_domain_without_division_tag Method_tag; #include "./include/test.h" - typedef CGAL::Simple_cartesian CK; typedef CGAL::Simple_cartesian EK; - int main() { -#ifndef DONT_USE_FILTERED_EXACT - { - std::ifstream ifs_algo("./data/algo.dat"); + std::ifstream ifs_algo("./data/algo.dat"); + assert( ifs_algo ); - assert( ifs_algo ); - - std::cout << "testing the Apollonius graph class..." << std::flush; - bool algo_ok = - CGAL::test_algo(ifs_algo); - - assert( algo_ok ); - std::cout << " done!" << std::endl; - - ifs_algo.close(); - - std::cout << std::endl; - } -#endif - //------------------------------------------------------------------------ - - { - std::ifstream ifs_algo("./data/algo.dat"); - - assert( ifs_algo ); - - std::cout << "testing the Apollonius graph class" - << " with filtered traits..." << std::flush; - bool algo_ok = - CGAL::test_filtered_traits_algo(ifs_algo); - - assert( algo_ok ); - std::cout << " done!" << std::endl; - - ifs_algo.close(); - - std::cout << std::endl; - } + std::cout << "testing the Apollonius graph class" << " with filtered traits..." << std::flush; + bool algo_ok = CGAL::test_filtered_traits_algo(ifs_algo); + assert( algo_ok ); + std::cout << " done!" << std::endl; return 0; } diff --git a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_hierarchy_2.cpp b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_hierarchy_2.cpp index 51baa1a0cab..9bb7f335333 100644 --- a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_hierarchy_2.cpp +++ b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_hierarchy_2.cpp @@ -3,79 +3,31 @@ #include #include -#define DNOT_USE_FILTERED_EXACT - // choose number type #include -#ifndef DNOT_USE_FILTERED_EXACT -# include -#endif - typedef double inexact_type; typedef CGAL::MP_Float exact_type; -#ifndef DNOT_USE_FILTERED_EXACT -typedef CGAL::Filtered_exact number_t; -#endif - #include -#ifndef DNOT_USE_FILTERED_EXACT -typedef CGAL::Simple_cartesian K; -#endif - typedef CGAL::Integral_domain_without_division_tag Method_tag; #include "./include/test.h" - typedef CGAL::Simple_cartesian CK; typedef CGAL::Simple_cartesian EK; - int main() { -#ifndef DNOT_USE_FILTERED_EXACT - { - std::ifstream ifs_hierarchy("./data/hierarchy.dat"); + std::ifstream ifs_hierarchy("./data/hierarchy.dat"); + assert( ifs_hierarchy ); - assert( ifs_hierarchy ); + std::cout << "testing the Apollonius graph hierarchy class" << " with filtered traits..." << std::flush; + bool hierarchy_ok = CGAL::test_filtered_traits_hierarchy_algo(ifs_hierarchy); - std::cout << "testing the Apollonius graph hierarchy class..." - << std::flush; - bool hierarchy_ok = - CGAL::test_hierarchy_algo(ifs_hierarchy); - - assert( hierarchy_ok ); - std::cout << " done!" << std::endl; - - ifs_hierarchy.close(); - - std::cout << std::endl; - } -#endif - //------------------------------------------------------------------------ - - { - std::ifstream ifs_hierarchy("./data/hierarchy.dat"); - - assert( ifs_hierarchy ); - - std::cout << "testing the Apollonius graph hierarchy class" - << " with filtered traits..." << std::flush; - bool hierarchy_ok = - CGAL::test_filtered_traits_hierarchy_algo(ifs_hierarchy); - - assert( hierarchy_ok ); - std::cout << " done!" << std::endl; - - ifs_hierarchy.close(); - - std::cout << std::endl; - } + assert( hierarchy_ok ); + std::cout << " done!" << std::endl; return 0; } diff --git a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_traits_2.cpp b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_traits_2.cpp index 3739b77cad4..1a8d4781bd9 100644 --- a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_traits_2.cpp +++ b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_traits_2.cpp @@ -2,79 +2,33 @@ #include #include -#define DONT_USE_FILTERED_EXACT - // choose number type #include -#ifndef DONT_USE_FILTERED_EXACT -# include -#endif typedef double inexact_type; typedef CGAL::MP_Float exact_type; -#ifndef DONT_USE_FILTERED_EXACT -typedef CGAL::Filtered_exact number_t; -#endif - #include -#ifndef DONT_USE_FILTERED_EXACT -typedef CGAL::Simple_cartesian Kernel; -#endif - typedef CGAL::Integral_domain_without_division_tag Method_tag; #include "./include/test.h" - typedef CGAL::Simple_cartesian CK; typedef CGAL::Simple_cartesian EK; - int main() { -#ifndef DONT_USE_FILTERED_EXACT - { - std::ifstream ifs_traits("./data/traits.dat"); + std::ifstream ifs_traits("./data/traits.dat"); + assert( ifs_traits ); - assert( ifs_traits ); + std::cout << "testing the filtered traits class..." << std::flush; - // bool is_ok = - // CGAL::test_traits(ifs_traits); + CGAL::Filtered_traits_tester test_traits; + bool traits_ok = test_traits(); + assert( traits_ok ); - std::cout << "testing the traits class..." << std::flush; - - CGAL::Traits_tester test_traits; - bool traits_ok = test_traits(); - - assert( traits_ok ); - std::cout << " done!" << std::endl; - - ifs_traits.close(); - - std::cout << std::endl; - } -#endif - //------------------------------------------------------------------------ - - { - std::ifstream ifs_traits("./data/traits.dat"); - - assert( ifs_traits ); - - std::cout << "testing the filtered traits class..." << std::flush; - - CGAL::Filtered_traits_tester test_traits; - bool traits_ok = test_traits(); - - assert( traits_ok ); - std::cout << " done!" << std::endl; - - ifs_traits.close(); - - std::cout << std::endl; - } + std::cout << " done!" << std::endl; return 0; } diff --git a/BGL/doc/BGL/CGAL/HalfedgeDS_face_max_base_with_id.h b/BGL/doc/BGL/CGAL/HalfedgeDS_face_max_base_with_id.h index 446481b9fc4..0006a4332e8 100644 --- a/BGL/doc/BGL/CGAL/HalfedgeDS_face_max_base_with_id.h +++ b/BGL/doc/BGL/CGAL/HalfedgeDS_face_max_base_with_id.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `HalfedgeDS_face_max_base_with_id` is a model of the `HalfedgeDSFace` concept. diff --git a/BGL/doc/BGL/CGAL/HalfedgeDS_halfedge_max_base_with_id.h b/BGL/doc/BGL/CGAL/HalfedgeDS_halfedge_max_base_with_id.h index 6e597c7d346..b9d7f4142eb 100644 --- a/BGL/doc/BGL/CGAL/HalfedgeDS_halfedge_max_base_with_id.h +++ b/BGL/doc/BGL/CGAL/HalfedgeDS_halfedge_max_base_with_id.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `HalfedgeDS_halfedge_max_base_with_id` is a model of the `HalfedgeDSHalfedge` concept. diff --git a/BGL/doc/BGL/CGAL/HalfedgeDS_vertex_max_base_with_id.h b/BGL/doc/BGL/CGAL/HalfedgeDS_vertex_max_base_with_id.h index 0839d254c8f..565236d880e 100644 --- a/BGL/doc/BGL/CGAL/HalfedgeDS_vertex_max_base_with_id.h +++ b/BGL/doc/BGL/CGAL/HalfedgeDS_vertex_max_base_with_id.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `HalfedgeDS_vertex_max_base_with_id` is a model of the `HalfedgeDSVertex` concept. It is diff --git a/BGL/doc/BGL/CGAL/Linear_cell_complex_bgl_min_items.h b/BGL/doc/BGL/CGAL/Linear_cell_complex_bgl_min_items.h index 0c9ab30a613..611ff3cd88b 100644 --- a/BGL/doc/BGL/CGAL/Linear_cell_complex_bgl_min_items.h +++ b/BGL/doc/BGL/CGAL/Linear_cell_complex_bgl_min_items.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `Linear_cell_complex_bgl_min_items` defines `void` as the information associated with darts, darts have ids and 0- and 2-attributes are enabled and have ids. diff --git a/BGL/doc/BGL/CGAL/Linear_cell_complex_for_bgl_combinatorial_map_helper.h b/BGL/doc/BGL/CGAL/Linear_cell_complex_for_bgl_combinatorial_map_helper.h index 72ba704077c..8bebd8f9e53 100644 --- a/BGL/doc/BGL/CGAL/Linear_cell_complex_for_bgl_combinatorial_map_helper.h +++ b/BGL/doc/BGL/CGAL/Linear_cell_complex_for_bgl_combinatorial_map_helper.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `Linear_cell_complex_for_bgl_combinatorial_map_helper` defines a `CGAL::Linear_cell_complex_for_combinatorial_map` as inner type, named `type`, having `CGAL::Linear_cell_complex_bgl_min_items` as items class. With this item class, no information are associated with darts, darts have ids and 0- and 2-attributes are enabled and have ids. diff --git a/BGL/doc/BGL/CGAL/Polyhedron_items_with_id_3.h b/BGL/doc/BGL/CGAL/Polyhedron_items_with_id_3.h index fdfee46c400..a64795aaa74 100644 --- a/BGL/doc/BGL/CGAL/Polyhedron_items_with_id_3.h +++ b/BGL/doc/BGL/CGAL/Polyhedron_items_with_id_3.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `Polyhedron_items_with_id_3` is a model of the `PolyhedronItems_3` concept. It provides definitions for vertices with points, halfedges, @@ -63,7 +63,7 @@ public: /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices Given a `CGAL::Polyhedron_3`, for each simplex type (vertex, halfedge, facet) associates an index from diff --git a/BGL/doc/BGL/CGAL/Triangulation_face_base_with_id_2.h b/BGL/doc/BGL/CGAL/Triangulation_face_base_with_id_2.h index 83e14e58af7..15827d6758b 100644 --- a/BGL/doc/BGL/CGAL/Triangulation_face_base_with_id_2.h +++ b/BGL/doc/BGL/CGAL/Triangulation_face_base_with_id_2.h @@ -1,15 +1,16 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `Triangulation_face_base_with_id_2` is a model of the concept `TriangulationFaceBase_2`, the base face of a -2D-triangulation. It provides an integer field that can be used to +2D-triangulation. It provides an integer field that can be used to index faces for \sc{Bgl} algorithms. Note that the user is in charge of setting indices correctly before -running a graph algorithm. +running a graph algorithm, by calling the function +`CGAL::set_triangulation_ids(Triangulation&)`. \tparam TriangulationTraits_2 is the geometric traits class and must be a model of `TriangulationTraits_2`. @@ -42,4 +43,19 @@ int& id(); /// @} }; /* end Triangulation_face_base_with_id_2 */ + +/// \ingroup BGLGraphExternalIndices +/// +/// This function initializes vertex, edge, and face indices of the triangulation `tr` and must +/// be called prior to using `tr` as a BGL graph in an algorithm that requires +/// vertex, halfedge, edge, or face indices. +/// +/// \tparam Triangulation a 2D triangulation of \cgal, whose combinatorial data structure +/// has been initialized with the vertex and face classes `Triangulation_vertex_base_with_id_2` +/// and `Triangulation_face_base_with_id_2`. +/// +/// \sa the \ref PkgTriangulation2 package +template +void set_triangulation_ids(Triangulation& tr); + } /* end namespace CGAL */ diff --git a/BGL/doc/BGL/CGAL/Triangulation_vertex_base_with_id_2.h b/BGL/doc/BGL/CGAL/Triangulation_vertex_base_with_id_2.h index a93691aa0b4..bc156657b30 100644 --- a/BGL/doc/BGL/CGAL/Triangulation_vertex_base_with_id_2.h +++ b/BGL/doc/BGL/CGAL/Triangulation_vertex_base_with_id_2.h @@ -1,7 +1,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `Triangulation_vertex_base_with_id_2` is a model of the concept `TriangulationVertexBase_2`, the base vertex of a @@ -9,7 +9,8 @@ concept `TriangulationVertexBase_2`, the base vertex of a index vertices for \sc{Bgl} algorithms. Note that the user is in charge of setting indices correctly before -running a graph algorithm. +running a graph algorithm, by calling the function +`CGAL::set_triangulation_ids(Triangulation&)`. \tparam TriangulationTraits_2 is the geometric traits class and must be a model of `TriangulationTraits_2`. diff --git a/BGL/doc/BGL/CGAL/boost/graph/properties.h b/BGL/doc/BGL/CGAL/boost/graph/properties.h index cbd4d4f960f..a7416d53eae 100644 --- a/BGL/doc/BGL/CGAL/boost/graph/properties.h +++ b/BGL/doc/BGL/CGAL/boost/graph/properties.h @@ -1,14 +1,9 @@ -/// Boost Namespace -namespace boost { +/// CGAL Namespace +namespace CGAL { /// \ingroup PkgBGLProperties /// @{ -/// The constant `edge_index` is a property tag which identifies the index property of an edge of a \sc{Bgl} -/// Graph. -/// \cgalModels PropertyTag -enum edge_index_t { edge_index}; - /// The constant `vertex_index` is a property tag which identifies the index property of a vertex of a \sc{Bgl} /// Graph. /// \cgalModels PropertyTag @@ -20,13 +15,17 @@ enum vertex_index_t { vertex_index }; /// \cgalModels PropertyTag enum halfedge_index_t { halfedge_index }; +/// The constant `edge_index` is a property tag which identifies the index property of an edge of a \sc{Bgl} +/// Graph. +/// \cgalModels PropertyTag +enum edge_index_t { edge_index }; + /// The constant `face_index` is a property tag which identifies the index property of a face of a `FaceGraph`. /// /// This is a property tag introduced by \cgal. /// \cgalModels PropertyTag enum face_index_t { face_index }; - /// The constant `vertex_point` is a property tag which refers to the geometric embedding property of /// a vertex of a `HalfedgeGraph`. /// @@ -34,12 +33,22 @@ enum face_index_t { face_index }; /// \cgalModels PropertyTag enum vertex_point_t { vertex_point }; - /// @} -} // namespace boost - -namespace CGAL { +/// \ingroup PkgBGLProperties +/// +/// \brief graph_has_property is used to indicate if a model of `HalfedgeGraph` or `FaceGraph` +/// has an internal property associated with the given `PropertyTag`. +/// +/// It inherits from \link Tag_true `CGAL::Tag_true` \endlink if there is a +/// default internal property map for the corresponding property tag and from +/// \link Tag_false `CGAL::Tag_false` \endlink otherwise. +/// +/// \tparam Graph a model of `HalfedgeGraph` or `FaceGraph` +/// \tparam PropertyTag the type of a property tag referring to the property of interest. +/// +template +struct graph_has_property; /// @{ diff --git a/BGL/doc/BGL/NamedParameters.txt b/BGL/doc/BGL/NamedParameters.txt index ce3be60f8f4..47c1d3f866a 100644 --- a/BGL/doc/BGL/NamedParameters.txt +++ b/BGL/doc/BGL/NamedParameters.txt @@ -38,38 +38,51 @@ a \cgal point type as value type. \n \cgalNPEnd \cgalNPBegin{vertex_index_map} \anchor BGL_vertex_index_map -is the property map containing the index of each vertex of the input polygon mesh.\n +is the property map associating a unique index to each vertex of a polygon mesh `g`, +between `0` and `num_vertices(g)-1`. +If this parameter is not passed, internal machinery will create and initialize a vertex 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.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` as key type and the value type \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::vertex_index, pmesh)\endcode +Default: an initialized vertex index property map \cgalNPEnd \cgalNPBegin{halfedge_index_map} \anchor BGL_halfedge_index_map -is the property map containing the index of each halfedge of the input polygon mesh.\n +is the property map associating a unique index to each halfedge of a polygon mesh, +between `0` and `num_halfedges(g)-1`. +If this parameter is not passed, internal machinery will create and initialize a halfedge 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.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%halfedge_descriptor` as key type and the value type: \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::halfedge_index, pmesh)\endcode -If this internal property map exists, its values should be initialized. +Default: an initialized halfedge index property map \cgalNPEnd \cgalNPBegin{edge_index_map} \anchor BGL_edge_index_map -is the property map containing the index of each edge of the input polygon mesh.\n +is the property map associating a unique index to each edge of a polygon mesh, +between `0` and `num_edges(g)-1`. +If this parameter is not passed, internal machinery will create and initialize a edge 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.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%edge_descriptor` as key type and the value type: \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::edge_index, pmesh)\endcode -If this internal property map exists, its values should be initialized. +Default: an initialized edge index property map \cgalNPEnd \cgalNPBegin{face_index_map} \anchor BGL_face_index_map -is the property map containing the index of each face of the input polygon mesh.\n +is the property map associating a unique index to each face of a polygon mesh, +between `0` and `num_faces(g)-1`. +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.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%face_descriptor` as key type and the value type: \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::face_index, pmesh)\endcode -If this internal property map exists, its values should be initialized. +Default: an initialized face index property map \cgalNPEnd \cgalNPBegin{edge_is_constrained_map} \anchor BGL_edge_is_constrained_map diff --git a/BGL/doc/BGL/PackageDescription.txt b/BGL/doc/BGL/PackageDescription.txt index 287b2662399..6f85bafbf06 100644 --- a/BGL/doc/BGL/PackageDescription.txt +++ b/BGL/doc/BGL/PackageDescription.txt @@ -443,7 +443,7 @@ the requirement for traversal of all faces in a graph. /// \defgroup PkgBGLPropertiesDynamic Dynamic Properties /// \ingroup PkgBGLRef -/// \defgroup PkgBGLHelper Helper Classes +/// \defgroup PkgBGLGraphExternalIndices External Indices /// \ingroup PkgBGLRef /// \defgroup PkgBGLHelperFct Helper Functions @@ -473,8 +473,11 @@ The dynamic property tags enable to associate information to simplices of a `Fac */ /*! -\addtogroup PkgBGLHelper -Several classes that enable to store ids in vertices/halfedges/faces of a `CGAL::Polyhedron_3`, as well as adapters such as `CGAL::Dual`. +\addtogroup BGLGraphExternalIndices +A number of BGL and \cgal algorithms require the graph to have (initialized) integer-like indices +for its vertices, edges, or faces. However, not all graphs intrinsically offer a natural way +to attach a unique ID to each element. The following classes and functions paliate this +by attaching and initializing external IDs to the elements of the graph. */ /*! @@ -574,25 +577,25 @@ Methods to read and write graphs. - `MutableFaceGraph` \cgalCRPSection{Properties} -- `boost::vertex_index_t` -- `boost::halfedge_index_t` -- `boost::edge_index_t` -- `boost::face_index_t` -- `boost::vertex_point_t` +- `CGAL::vertex_index_t` +- `CGAL::halfedge_index_t` +- `CGAL::edge_index_t` +- `CGAL::face_index_t` +- `CGAL::vertex_point_t` \cgalCRPSection{%CGAL Classes Adapted for the Graph API} -Different \cgal types have been adapted as graphs for the \sc{Bgl}. All +A number of \cgal structures have been adapted as graphs for the \sc{Bgl}. All adapted types are listed here. The pages document which concepts they model, the properties they support, and any possible caveats that a user might encounter. -- \link BGLSMGT `boost::graph_traits< CGAL::Surface_mesh

>` \endlink -- \link BGLPolyGT `boost::graph_traits< CGAL::Polyhedron_3 >` \endlink -- \link BGLLCCGT `boost::graph_traits< CGAL::Linear_cell_complex_for_combinatorial_map<...> >` \endlink -- \link BGLSeam_meshGT `boost::graph_traits< CGAL::Seam_mesh >` \endlink -- \link BGLT2GT `boost::graph_traits< CGAL::Triangulation_2 >` \endlink -- \link BGLArgtGT `boost::graph_traits< CGAL::Arrangement_2 >` \endlink +- \link BGLSMGT `boost::graph_traits >` \endlink +- \link BGLPolyGT `boost::graph_traits >` \endlink +- \link BGLLCCGT `boost::graph_traits >` \endlink +- \link BGLSeam_meshGT `boost::graph_traits >` \endlink +- \link BGLT2GT `boost::graph_traits >` \endlink and other 2D triangulations +- \link BGLArgtGT `boost::graph_traits >` \endlink - \link BGLOMPAK `boost::graph_traits >` \endlink - \link BGLOMTMAK `boost::graph_traits >` \endlink @@ -642,6 +645,8 @@ user might encounter. - `CGAL::clear()` - `CGAL::copy_face_graph()` +- `CGAL::set_triangulation_ids()` + \cgalCRPSection{Iterators} - `CGAL::Halfedge_around_source_iterator` - `CGAL::Halfedge_around_target_iterator` diff --git a/BGL/include/CGAL/boost/graph/Euler_operations.h b/BGL/include/CGAL/boost/graph/Euler_operations.h index 12e6ed25252..f362aef6e17 100644 --- a/BGL/include/CGAL/boost/graph/Euler_operations.h +++ b/BGL/include/CGAL/boost/graph/Euler_operations.h @@ -702,19 +702,35 @@ add_face(const VertexRange& vr, Graph& g) break; case 3: // both are new - if (halfedge(v, g) == boost::graph_traits::null_halfedge()) { - set_halfedge(v, outer_prev, g); - next_cache.push_back(NextCacheEntry(outer_prev, outer_next)); + // try to pick a border halfedge with v as target + halfedge_descriptor hv = halfedge(v, g); + if (hv != boost::graph_traits::null_halfedge() && !is_border(hv, g)) + { + for(halfedge_descriptor h_around_v : halfedges_around_target(hv, g)) + if (is_border(h_around_v, g)) + { + hv = h_around_v; + break; + } + if (!is_border(hv, g)) + hv = boost::graph_traits::null_halfedge(); + } + + if (hv == boost::graph_traits::null_halfedge()) + { + set_halfedge(v, outer_prev, g); + next_cache.push_back(NextCacheEntry(outer_prev, outer_next)); + } + else + { + border_prev = hv; + border_next = next(border_prev, g); + next_cache.push_back(NextCacheEntry(border_prev, outer_next)); + next_cache.push_back(NextCacheEntry(outer_prev, border_next)); + } + break; } - else - { - border_prev = halfedge(v, g); - border_next = next(border_prev, g); - next_cache.push_back(NextCacheEntry(border_prev, outer_next)); - next_cache.push_back(NextCacheEntry(outer_prev, border_next)); - } - break; } // set inner link @@ -1323,7 +1339,7 @@ flip_edge(typename boost::graph_traits::halfedge_descriptor h, template bool does_satisfy_link_condition(typename boost::graph_traits::edge_descriptor e, - Graph& g) + const Graph& g) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; @@ -1423,7 +1439,7 @@ does_satisfy_link_condition(typename boost::graph_traits::edge_descriptor template bool satisfies_link_condition(typename boost::graph_traits::edge_descriptor e, - Graph& g) + const Graph& g) { return does_satisfy_link_condition(e, g); } diff --git a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h index ffd943fb9c4..875eb7f3e73 100644 --- a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h +++ b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h @@ -16,23 +16,24 @@ #include #include #include +#include #include -#include -#include -#include -#include #include -#include +#include +#include + #include +#include +#include #include +#include #ifdef DOXYGEN_RUNNING #define CGAL_BGL_NP_TEMPLATE_PARAMETERS NamedParameters #define CGAL_BGL_NP_CLASS NamedParameters #endif -namespace CGAL -{ +namespace CGAL { /*! * \ingroup PkgBGLAdaptors @@ -62,18 +63,18 @@ namespace CGAL * missing if the default is fine. * * \tparam Graph must be a model of a `FaceListGraph`, `HalfedgeListGraph`, and \bgllink{VertexListGraph}. - * \tparam FIMap a model of `ReadablePropertyMap` with `face_descriptor` as key and `graph_traits::%faces_size_type` as value - * \tparam VIMap a model of `ReadablePropertyMap` with `vertex_descriptor` as key and `graph_traits::%vertices_size_type` as value - * \tparam HIMap a model of `ReadablePropertyMap` with `halfedge_descriptor` as key and `graph_traits::%halfedges_size_type` as value + * \tparam FIMap a model of `ReadablePropertyMap` with `graph_traits::%face_descriptor` as key and `graph_traits::%faces_size_type` as value + * \tparam VIMap a model of `ReadablePropertyMap` with `graph_traits::%vertex_descriptor` as key and `graph_traits::%vertices_size_type` as value + * \tparam HIMap a model of `ReadablePropertyMap` with `graph_traits::%halfedge_descriptor` as key and `graph_traits::%halfedges_size_type` as value * * \cgalModels `FaceListGraph` * \cgalModels `HalfedgeListGraph` * \cgalModels \bgllink{VertexListGraph} */ template::type, - typename VIMap = typename boost::property_map::type, - typename HIMap = typename boost::property_map::type> + typename FIMap = Default, + typename VIMap = Default, + typename HIMap = Default> struct Face_filtered_graph { typedef boost::graph_traits gt; @@ -93,10 +94,15 @@ struct Face_filtered_graph #endif // non documented types - typedef typename boost::property_traits< FIMap >::value_type face_index_type; - typedef typename boost::property_traits< VIMap >::value_type vertex_index_type; - typedef typename boost::property_traits< HIMap >::value_type halfedge_index_type; - typedef Face_filtered_graph Self; + typedef typename Default::Get::const_type>::type FIM; + typedef typename Default::Get::const_type>::type VIM; + typedef typename Default::Get::const_type>::type HIM; + + typedef typename boost::property_traits::value_type face_index_type; + typedef typename boost::property_traits::value_type vertex_index_type; + typedef typename boost::property_traits::value_type halfedge_index_type; + + typedef Face_filtered_graph Self; /*! * \brief Constructor where the set of selected faces is specified as a range of patch ids. @@ -115,31 +121,31 @@ struct Face_filtered_graph * * \cgalNamedParamsBegin * \cgalParamBegin{face_index_map} - * a property map containing an index for each face initialized from 0 to `num_vertices(graph)` + * a property map containing for each face of `graph` a unique index between `0` and `num_faces(graph)-1` * \cgalParamEnd * \cgalParamBegin{vertex_index_map} - * a property map containing an index for each vertex initialized 0 to `num_vertices(graph)` + * a property map containing for each vertex of `graph` a unique index between `0` and `num_vertices(graph)-1` * \cgalParamEnd * \cgalParamBegin{halfedge_index_map} - * a property map containing an index for each halfedge initialized 0 to `num_halfedges(graph)` + * a property map containing for each halfedge of `graph` a unique index between `0` and `num_halfedges(graph)-1` * \cgalParamEnd * \cgalNamedParamsEnd */ template Face_filtered_graph(const Graph& graph, const FacePatchIndexRange& selected_face_patch_indices, - FacePatchIndexMap face_patch_index_map, - const CGAL_BGL_NP_CLASS& np - #ifndef DOXYGEN_RUNNING - , typename boost::enable_if< - typename boost::has_range_const_iterator::type - >::type* = 0 - #endif - ) - : _graph(const_cast(graph)) - , fimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), get_const_property_map(face_index, graph))) - , vimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_index), get_const_property_map(boost::vertex_index, graph))) - , himap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::halfedge_index), get_const_property_map(halfedge_index, graph))) + FacePatchIndexMap face_patch_index_map, + const CGAL_BGL_NP_CLASS& np +#ifndef DOXYGEN_RUNNING + , typename boost::enable_if< + typename boost::has_range_const_iterator::type + >::type* = 0 +#endif + ) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph, np)), + vimap(CGAL::get_initialized_vertex_index_map(graph, np)), + himap(CGAL::get_initialized_halfedge_index_map(graph, np)) { set_selected_faces(selected_face_patch_indices, face_patch_index_map); } @@ -152,10 +158,10 @@ struct Face_filtered_graph typename boost::has_range_const_iterator::type >::type* = 0 ) - : _graph(const_cast(graph)) - , fimap(get(CGAL::face_index, graph)) - , vimap(get(boost::vertex_index, graph)) - , himap(get(CGAL::halfedge_index, graph)) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph)), + vimap(CGAL::get_initialized_vertex_index_map(graph)), + himap(CGAL::get_initialized_halfedge_index_map(graph)) { set_selected_faces(selected_face_patch_indices, face_patch_index_map); } @@ -175,38 +181,37 @@ struct Face_filtered_graph * * \cgalNamedParamsBegin * \cgalParamBegin{face_index_map} - * a property map containing an index for each face initialized from 0 to `num_vertices(graph)` + * a property map containing for each face of `graph` a unique index between `0` and `num_faces(graph)-1` * \cgalParamEnd * \cgalParamBegin{vertex_index_map} - * a property map containing an index for each vertex initialized 0 to `num_vertices(graph)` + * a property map containing for each vertex of `graph` a unique index between `0` and `num_vertices(graph)-1` * \cgalParamEnd * \cgalParamBegin{halfedge_index_map} - * a property map containing an index for each halfedge initialized 0 to `num_halfedges(graph)` + * a property map containing for each halfedge of `graph` a unique index between `0` and `num_halfedges(graph)-1` * \cgalParamEnd * \cgalNamedParamsEnd */ template Face_filtered_graph(const Graph& graph, - typename boost::property_traits::value_type selected_face_patch_index, - FacePatchIndexMap face_patch_index_map, - const CGAL_BGL_NP_CLASS& np - ) - : _graph(const_cast(graph)) - , fimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), get_const_property_map(face_index, graph))) - , vimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_index), get_const_property_map(boost::vertex_index, graph))) - , himap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::halfedge_index), get_const_property_map(halfedge_index, graph))) + typename boost::property_traits::value_type selected_face_patch_index, + FacePatchIndexMap face_patch_index_map, + const CGAL_BGL_NP_CLASS& np) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph, np)), + vimap(CGAL::get_initialized_vertex_index_map(graph, np)), + himap(CGAL::get_initialized_halfedge_index_map(graph, np)) { set_selected_faces(selected_face_patch_index, face_patch_index_map); } template Face_filtered_graph(const Graph& graph, - typename boost::property_traits::value_type pid, - FacePatchIndexMap face_patch_index_map) - : _graph(const_cast(graph)) - , fimap(get(CGAL::face_index, graph)) - , vimap(get(boost::vertex_index, graph)) - , himap(get(CGAL::halfedge_index, graph)) + typename boost::property_traits::value_type pid, + FacePatchIndexMap face_patch_index_map) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph)), + vimap(CGAL::get_initialized_vertex_index_map(graph)), + himap(CGAL::get_initialized_halfedge_index_map(graph)) { set_selected_faces(pid, face_patch_index_map); } @@ -236,10 +241,10 @@ struct Face_filtered_graph Face_filtered_graph(const Graph& graph, const FaceRange& selected_faces, const CGAL_BGL_NP_CLASS& np) - : _graph(const_cast(graph)) - , fimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), get_const_property_map(face_index, graph))) - , vimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_index), get_const_property_map(boost::vertex_index, graph))) - , himap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::halfedge_index), get_const_property_map(halfedge_index, graph))) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph, np)), + vimap(CGAL::get_initialized_vertex_index_map(graph, np)), + himap(CGAL::get_initialized_halfedge_index_map(graph, np)) { set_selected_faces(selected_faces); } @@ -247,10 +252,10 @@ struct Face_filtered_graph template Face_filtered_graph(const Graph& graph, const FaceRange& selected_faces) - : _graph(const_cast(graph)) - , fimap(get(CGAL::face_index, graph)) - , vimap(get(boost::vertex_index, graph)) - , himap(get(CGAL::halfedge_index, graph)) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph)), + vimap(CGAL::get_initialized_vertex_index_map(graph)), + himap(CGAL::get_initialized_halfedge_index_map(graph)) { set_selected_faces(selected_faces); } @@ -293,12 +298,12 @@ struct Face_filtered_graph template void set_selected_faces(const FacePatchIndexRange& selected_face_patch_indices, FacePatchIndexMap face_patch_index_map - #ifndef DOXYGEN_RUNNING +#ifndef DOXYGEN_RUNNING , typename boost::enable_if< typename boost::has_range_const_iterator::type >::type* = 0 - #endif - ) +#endif + ) { face_indices.clear(); vertex_indices.clear(); @@ -407,7 +412,7 @@ struct Face_filtered_graph return selected_halfedges.count(); } - Property_map_binder< FIMap, typename Pointer_property_map< typename boost::property_traits< FIMap >::value_type >::type > + Property_map_binder::value_type>::type> get_face_index_map() const { if (face_indices.empty()) @@ -422,7 +427,7 @@ struct Face_filtered_graph return bind_property_maps(fimap, make_property_map(face_indices) ); } - Property_map_binder< VIMap, typename Pointer_property_map< typename boost::property_traits< VIMap >::value_type >::type > + Property_map_binder::value_type>::type> get_vertex_index_map() const { if (vertex_indices.empty()) @@ -437,7 +442,7 @@ struct Face_filtered_graph return bind_property_maps(vimap, make_property_map(vertex_indices) ); } - Property_map_binder< HIMap, typename Pointer_property_map< typename boost::property_traits< HIMap >::value_type >::type > + Property_map_binder::value_type >::type> get_halfedge_index_map() const { if (halfedge_indices.empty()) @@ -510,9 +515,9 @@ struct Face_filtered_graph private: Graph& _graph; - FIMap fimap; - VIMap vimap; - HIMap himap; + FIM fimap; + VIM vimap; + HIM himap; boost::dynamic_bitset<> selected_faces; boost::dynamic_bitset<> selected_vertices; boost::dynamic_bitset<> selected_halfedges; @@ -1142,38 +1147,40 @@ CGAL_FILTERED_FACE_GRAPH_DYNAMIC_PMAP_SPECIALIZATION(dynamic_face_property_t) #undef CGAL_FILTERED_FACE_GRAPH_DYNAMIC_PMAP_SPECIALIZATION - - //specializations for indices -template -struct property_map, CGAL::face_index_t>{ - typedef typename CGAL::Property_map_binder< FIMap, - typename CGAL::Pointer_property_map< typename boost::property_traits< FIMap >::value_type >::type > type; - typedef type const_type; +template +struct property_map, CGAL::face_index_t> +{ + typedef typename CGAL::Face_filtered_graph::FIM FIM; + typedef typename CGAL::Property_map_binder::value_type>::type> type; + typedef type const_type; +}; + +template +struct property_map, boost::vertex_index_t> +{ + typedef typename CGAL::Face_filtered_graph::VIM VIM; + typedef typename CGAL::Property_map_binder::value_type>::type> type; + typedef type const_type; }; template -struct property_map, boost::vertex_index_t>{ - typedef typename CGAL::Property_map_binder< VIMap, - typename CGAL::Pointer_property_map< typename boost::property_traits< VIMap >::value_type >::type > type; - typedef type const_type; +struct property_map, CGAL::halfedge_index_t> +{ + typedef typename CGAL::Face_filtered_graph::HIM HIM; + typedef typename CGAL::Property_map_binder::value_type>::type> type; + typedef type const_type; }; -template +} // namespace boost -struct property_map, CGAL::halfedge_index_t>{ - typedef typename CGAL::Property_map_binder< HIMap, - typename CGAL::Pointer_property_map< typename boost::property_traits< HIMap >::value_type >::type > type; - typedef type const_type; -}; -}// namespace boost #endif // CGAL_BOOST_GRAPH_FACE_FILTERED_GRAPH_H diff --git a/BGL/include/CGAL/boost/graph/METIS/partition_dual_graph.h b/BGL/include/CGAL/boost/graph/METIS/partition_dual_graph.h index 50c0bcf7e37..d11a426b5e1 100644 --- a/BGL/include/CGAL/boost/graph/METIS/partition_dual_graph.h +++ b/BGL/include/CGAL/boost/graph/METIS/partition_dual_graph.h @@ -42,17 +42,14 @@ void partition_dual_graph(const TriangleMesh& tm, CGAL_precondition(CGAL::is_triangle_mesh(tm)); CGAL_precondition_msg(nparts > 1, ("Partitioning requires a number of parts > 1")); - using parameters::choose_parameter; using parameters::get_parameter; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_iterator face_iterator; - // vertex index map - typedef typename CGAL::GetVertexIndexMap::type Indices; - Indices indices = choose_parameter(get_parameter(np, internal_np::vertex_index), - get_const_property_map(boost::vertex_index, tm)); + typedef typename CGAL::GetInitializedVertexIndexMap::type Indices; + Indices indices = CGAL::get_initialized_vertex_index_map(tm, np); idx_t nn = static_cast(num_vertices(tm)); idx_t ne = static_cast(num_faces(tm)); @@ -136,9 +133,6 @@ void partition_dual_graph(const TriangleMesh& tm, int nparts, /// based on the mesh's dual graph. The resulting partition is stored in the vertex and/or face /// property maps that are passed as parameters using \ref bgl_namedparameters "Named Parameters". /// -/// Property map for `CGAL::vertex_index_t` should be either available -/// as an internal property map to `tm` or provided as \ref bgl_namedparameters "Named Parameters". -/// /// \param tm a triangle mesh /// \param nparts the number of parts in the final partition /// \param np optional \ref bgl_namedparameters "Named Parameters" described below @@ -148,7 +142,7 @@ void partition_dual_graph(const TriangleMesh& tm, int nparts, /// /// \cgalNamedParamsBegin /// \cgalParamBegin{vertex_index_map} -/// is a property map containing the index of each vertex of `tm` intialized from `0` to `num_vertices(tm)-1`. +/// is a property map containing for each vertex of `tm` a unique index between `0` and `num_vertices(tm)-1`. /// \cgalParamEnd /// \cgalParamBegin{METIS_options} /// is a parameter used in to pass options to the METIS mesh diff --git a/BGL/include/CGAL/boost/graph/METIS/partition_graph.h b/BGL/include/CGAL/boost/graph/METIS/partition_graph.h index ec60ecbc11a..4ef813efcc6 100644 --- a/BGL/include/CGAL/boost/graph/METIS/partition_graph.h +++ b/BGL/include/CGAL/boost/graph/METIS/partition_graph.h @@ -77,17 +77,14 @@ void partition_graph(const TriangleMesh& tm, CGAL_precondition(CGAL::is_triangle_mesh(tm)); CGAL_precondition_msg(nparts > 1, ("Partitioning requires a number of parts > 1")); - using parameters::choose_parameter; using parameters::get_parameter; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_iterator face_iterator; - //Vertex index map - typedef typename CGAL::GetVertexIndexMap::type Indices; - Indices indices = choose_parameter(get_parameter(np, internal_np::vertex_index), - get_const_property_map(boost::vertex_index, tm)); + typedef typename CGAL::GetInitializedVertexIndexMap::type Indices; + Indices indices = CGAL::get_initialized_vertex_index_map(tm, np); idx_t nn = static_cast(num_vertices(tm)); idx_t ne = static_cast(num_faces(tm)); @@ -168,9 +165,6 @@ void partition_graph(const TriangleMesh& tm, int nparts, /// mesh's nodal graph. The resulting partition is stored in the vertex and/or face /// property maps that are passed as parameters using \ref bgl_namedparameters "Named Parameters". /// -/// Property map for `CGAL::vertex_index_t` should be either available -/// as an internal property map to `tm` or provided as \ref bgl_namedparameters "Named Parameters". -/// /// \param tm a triangle mesh /// \param nparts the number of parts in the final partition /// \param np optional \ref bgl_namedparameters "Named Parameters" described below @@ -180,7 +174,7 @@ void partition_graph(const TriangleMesh& tm, int nparts, /// /// \cgalNamedParamsBegin /// \cgalParamBegin{vertex_index_map} -/// is a property map containing the index of each vertex of `tm` intialized from `0` to `num_vertices(tm)-1`. +/// is a property map containing for each vertex of `tm` a unique index between `0` and `num_vertices(tm)-1`. /// \cgalParamEnd /// \cgalParamBegin{METIS_options} /// is a parameter used in to pass options to the METIS mesh diff --git a/BGL/include/CGAL/boost/graph/Seam_mesh.h b/BGL/include/CGAL/boost/graph/Seam_mesh.h index 33a995dba43..07ed312307f 100644 --- a/BGL/include/CGAL/boost/graph/Seam_mesh.h +++ b/BGL/include/CGAL/boost/graph/Seam_mesh.h @@ -124,8 +124,8 @@ public: /// The type for the objects used to identify halfedges in the underlying mesh. typedef typename boost::graph_traits::halfedge_descriptor TM_halfedge_descriptor; - /// The type for the iterators that traverse through the complete halfedge set of the underlying mesh. - typedef typename boost::graph_traits::halfedge_iterator TM_halfedge_iterator; + /// The type for the iterators that traverse through the complete halfedge set of the underlying mesh. + typedef typename boost::graph_traits::halfedge_iterator TM_halfedge_iterator; /// The type for the objects used to identify edges in the underlying mesh. typedef typename boost::graph_traits::edge_descriptor TM_edge_descriptor; @@ -439,6 +439,11 @@ public: { return ! (e1 == e2); } + + friend std::size_t hash_value(const edge_descriptor& ed) + { + return hash_value((std::min)(ed.hd, ed.mesh_->opposite(ed.hd))); + } }; #ifndef DOXYGEN_RUNNING diff --git a/BGL/include/CGAL/boost/graph/copy_face_graph.h b/BGL/include/CGAL/boost/graph/copy_face_graph.h index 5eafa161533..4e0dc04cd93 100644 --- a/BGL/include/CGAL/boost/graph/copy_face_graph.h +++ b/BGL/include/CGAL/boost/graph/copy_face_graph.h @@ -199,13 +199,8 @@ void copy_face_graph(const SourceMesh& sm, TargetMesh& tm, typedef typename boost::graph_traits::halfedge_descriptor tm_halfedge_descriptor; std::vector hedges(num_halfedges(sm)); - // init halfedge index map - /// \TODO shall we keep that? - helpers::init_halfedge_indices(const_cast(sm), - get(boost::halfedge_index, sm)); - copy_face_graph_impl(sm, tm, - bind_property_maps(get(boost::halfedge_index, sm), + bind_property_maps(get_initialized_halfedge_index_map(sm), make_property_map(hedges)), v2v, h2h, f2f, sm_vpm, tm_vpm); diff --git a/BGL/include/CGAL/boost/graph/internal/initialized_index_maps_helpers.h b/BGL/include/CGAL/boost/graph/internal/initialized_index_maps_helpers.h new file mode 100644 index 00000000000..e392ff064a0 --- /dev/null +++ b/BGL/include/CGAL/boost/graph/internal/initialized_index_maps_helpers.h @@ -0,0 +1,307 @@ +// Copyright (c) 2020 GeometryFactory (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) : Mael Rouxel-Labbé +// Maxime Gimeno + +#ifndef CGAL_BOOST_GRAPH_INITIALIZED_INTERNAL_INDEX_MAPS_HELPERS +#define CGAL_BOOST_GRAPH_INITIALIZED_INTERNAL_INDEX_MAPS_HELPERS + +#include +#include +#include +#include +#include + +#include +#include + +namespace CGAL { +namespace BGL { +namespace internal { + +// Check that an index map has been correctly initialized +template +bool is_index_map_valid(IndexMap idmap, + const std::size_t num_simplices, + const DescriptorRange& range) +{ + typedef typename boost::property_traits::value_type Id_type; + + Id_type max_id = static_cast(num_simplices); + std::vector indices(max_id); + for(const auto& d : range) + { + const Id_type id = get(idmap, d); + if(id >= 0 && id < max_id && !indices[id]) + { + indices[id] = true; + } + else + { +#ifdef CGAL_BGL_INDEX_MAP_DEBUG + std::cerr << "Invalid ID: " << id << " num_simplices: " << num_simplices << std::endl; +#endif + return false; + } + } + + return true; +} + +template +bool is_index_map_valid(const CGAL::internal_np::vertex_index_t, VertexIndexPropertyMap vertex_index_map, const Graph& g) +{ + return is_index_map_valid(vertex_index_map, num_vertices(g), vertices(g)); +} + +template +bool is_index_map_valid(const CGAL::internal_np::halfedge_index_t, HalfedgeIndexPropertyMap halfedge_index_map, const Graph& g) +{ + return is_index_map_valid(halfedge_index_map, num_halfedges(g), halfedges(g)); +} + +template +bool is_index_map_valid(const CGAL::internal_np::edge_index_t, EdgeIndexPropertyMap edge_index_map, const Graph& g) +{ + return is_index_map_valid(edge_index_map, num_edges(g), edges(g)); +} + +template +bool is_index_map_valid(const CGAL::internal_np::face_index_t, FaceIndexPropertyMap face_index_map, const Graph& g) +{ + return is_index_map_valid(face_index_map, num_faces(g), faces(g)); +} + +template +void initialize_index_map(const PropertyTag, IndexPropertyMap, const Graph&) +{ + // Unknown parameter; should never be here. + CGAL_assertion(false); +} + +template ::value> +struct Index_map_initializer +{ + void operator()(const CGAL::internal_np::vertex_index_t, IndexPropertyMap vertex_index_map, const Graph& g) + { + typename boost::property_traits::value_type i = 0; + for(typename boost::graph_traits::vertex_descriptor vd : vertices(g)) + put(vertex_index_map, vd, i++); + } + + void operator()(const CGAL::internal_np::halfedge_index_t, IndexPropertyMap halfedge_index_map, const Graph& g) + { + typename boost::property_traits::value_type i = 0; + for(typename boost::graph_traits::halfedge_descriptor hd : halfedges(g)) + put(halfedge_index_map, hd, i++); + } + + void operator()(const CGAL::internal_np::edge_index_t, IndexPropertyMap edge_index_map, const Graph& g) + { + typename boost::property_traits::value_type i = 0; + for(typename boost::graph_traits::edge_descriptor ed : edges(g)) + put(edge_index_map, ed, i++); + } + + void operator()(const CGAL::internal_np::face_index_t, IndexPropertyMap face_index_map, const Graph& g) + { + typename boost::property_traits::value_type i = 0; + for(typename boost::graph_traits::face_descriptor fd : faces(g)) + put(face_index_map, fd, i++); + } + + template + void operator()(const PropertyTag, IndexPropertyMap, const Graph&) + { + // Unknown parameter; should never be here. + CGAL_assertion(false); + } +}; + +template +struct Index_map_initializer +{ + template + void operator()(const PropertyTag, IndexPropertyMap, const Graph&) + { + // The property map is not writable; should never be here. + CGAL_assertion_msg(false, "You are trying to initialize a non-writable property map"); + } +}; + +// Just for convenience, define the following functions: +// +// BGL::internal::initialize_vertex_index_map() +// BGL::internal::initialize_halfedge_index_map() +// BGL::internal::initialize_edge_index_map() +// BGL::internal::initialize_face_index_map() + +#define CGAL_DEF_INITIALIZE_ID_MAP_FUNCTION(TYPE) \ +template \ +void initialize_##TYPE##_index_map(WritableIndexPropertyMap index_map, \ + const Graph& g) \ +{ \ + Index_map_initializer initializer; \ + initializer(CGAL::internal_np::TYPE##_index_t{}, index_map, g); \ +} + +CGAL_DEF_INITIALIZE_ID_MAP_FUNCTION(vertex) +CGAL_DEF_INITIALIZE_ID_MAP_FUNCTION(halfedge) +CGAL_DEF_INITIALIZE_ID_MAP_FUNCTION(edge) +CGAL_DEF_INITIALIZE_ID_MAP_FUNCTION(face) + +#undef CGAL_DEF_INITIALIZE_ID_FUCNTION + +// Using the pmap passed in named parameters ------------------------------------------------------- +template +IndexMap get_initialized_index_map_const(const IndexMap index_map, + const PropertyTag p, Tag, DynamicTag, + const Graph& g) +{ + CGAL_USE(g); + CGAL_USE(p); + + // If you are passing a pmap via NPs, it must be initialized + CGAL_assertion(is_index_map_valid(p, index_map, g)); + + return index_map; +} + +template +IndexMap get_initialized_index_map(const IndexMap index_map, + const PropertyTag p, Tag, DynamicTag, + Graph& g) +{ + CGAL_USE(g); + CGAL_USE(p); + + // If you are passing a pmap via NPs, it must be initialized + CGAL_assertion(is_index_map_valid(p, index_map, g)); + + return index_map; +} + +// Using the internal to the mesh ------------------------------------------------------------------ +template +InternalIndexMap +get_initialized_internal_index_map(InternalIndexMap index_map, + const PropertyTag p, + const Graph& g) +{ + if(CGAL::internal::Is_writable_property_map::value) + { + if(!is_index_map_valid(p, index_map, g)) + Index_map_initializer{}(p, index_map, g); + } + else // not writable + { + CGAL_assertion(is_index_map_valid(p, index_map, g)); + } + + return index_map; +} + +template +typename boost::property_map::const_type +get_initialized_index_map_const(CGAL::internal_np::Param_not_found, + const PropertyTag p, const Tag tag, DynamicTag, + const Graph& g) +{ + return get_initialized_internal_index_map(get(tag, g), p, g); +} + +// same as above, non-const graph overload +template +typename boost::property_map::type +get_initialized_index_map(CGAL::internal_np::Param_not_found, + const PropertyTag p, const Tag tag, DynamicTag, + Graph& g) +{ + // From now on the correct property map has been acquired + // and there is no need to distinguish between const and non-const mesh + return get_initialized_internal_index_map(get(tag, g), p, g); +} + +// Create a dynamic property and initialize it ----------------------------------------------------- +template +DynamicIndexMap +get_initialized_dynamic_index_map(DynamicIndexMap index_map, + const PropertyTag p, + const Graph& g) +{ +#ifdef CGAL_PERFORMANCE_WARNINGS + std::cerr << "Warning: the automatically selected index map is a dynamic property map," + << " which might not have constant-time access complexity." << std::endl; +#endif + + Index_map_initializer{}(p, index_map, g); + return index_map; +} + +template +typename boost::property_map::const_type +get_initialized_index_map_const(CGAL::internal_np::Param_not_found, + const PropertyTag p, const DynamicTag dtag, DynamicTag, + const Graph& g) +{ + return get_initialized_dynamic_index_map(get(dtag, g), p, g); +} + +// same as above, non-const graph overload +template +typename boost::property_map::type +get_initialized_index_map(CGAL::internal_np::Param_not_found, + const PropertyTag p, const DynamicTag dtag, DynamicTag, + Graph& g) +{ + // From now on the correct property map has been acquired + // and there is no need to distinguish between const and non-const mesh + return get_initialized_dynamic_index_map(get(dtag, g), p, g); +} + +template > +class GetInitializedIndexMap +{ +public: + // Check if there is an internal property map; if not, we must a dynamic property map + typedef typename boost::mpl::if_c< + CGAL::graph_has_property::value, Tag, DynamicTag>::type Final_tag; + + typedef typename internal_np::Lookup_named_param_def< + PropertyTag, + NamedParameters, + typename boost::property_map::const_type>::type const_type; + + typedef typename internal_np::Lookup_named_param_def< + PropertyTag, + NamedParameters, + typename boost::property_map::type>::type type; + + static const_type get_const(const PropertyTag p, const Graph& g, const NamedParameters& np) + { + return BGL::internal::get_initialized_index_map_const(parameters::get_parameter(np, p), + p, Final_tag{}, DynamicTag{}, g); + } + + static type get(const PropertyTag p, Graph& g, const NamedParameters& np) + { + return BGL::internal::get_initialized_index_map(parameters::get_parameter(np, p), + p, Final_tag{}, DynamicTag{}, g); + } +}; + +} // namespace internal +} // namespace BGL +} // namespace CGAL + +#endif // CGAL_BOOST_GRAPH_INITIALIZED_INTERNAL_INDEX_MAPS_HELPERS diff --git a/BGL/include/CGAL/boost/graph/io.h b/BGL/include/CGAL/boost/graph/io.h index f8e91ea49c2..dd41b28a65f 100644 --- a/BGL/include/CGAL/boost/graph/io.h +++ b/BGL/include/CGAL/boost/graph/io.h @@ -417,13 +417,9 @@ write_polys(std::ostream& os, { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_iterator face_iterator; - typedef typename CGAL::GetVertexIndexMap::type Vimap; - using parameters::get_parameter; - using parameters::choose_parameter; - - Vimap V = choose_parameter(get_parameter(np, internal_np::vertex_index), - get_const_property_map(boost::vertex_index, mesh)); + typedef typename CGAL::GetInitializedVertexIndexMap::const_type Vimap; + Vimap V = CGAL::get_initialized_vertex_index_map(mesh, np); std::vector connectivity_table; std::vector offsets; @@ -456,13 +452,9 @@ write_polys_tag(std::ostream& os, { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_iterator face_iterator; - typedef typename CGAL::GetVertexIndexMap::type Vimap; - using parameters::get_parameter; - using parameters::choose_parameter; - - Vimap V = choose_parameter(get_parameter(np, internal_np::vertex_index), - get_const_property_map(boost::vertex_index, mesh)); + typedef typename CGAL::GetInitializedVertexIndexMap::const_type Vimap; + Vimap V = CGAL::get_initialized_vertex_index_map(mesh, np); std::string formatattribute = binary ? " format=\"appended\"" : " format=\"ascii\""; @@ -638,8 +630,7 @@ write_polys_points(std::ostream& os, * `CGAL::vertex_point_t` must be available in `TriangleMesh`. * \cgalParamEnd * \cgalParamBegin{vertex_index_map} the property map with the indices associated to - * the vertices of `mesh`. If this parameter is omitted, an internal property map for - * `CGAL::vertex_index_t` must be available in `TriangleMesh`. + * the vertices of `mesh`. * \cgalParamEnd * \cgalNamedParamsEnd */ diff --git a/BGL/include/CGAL/boost/graph/named_params_helper.h b/BGL/include/CGAL/boost/graph/named_params_helper.h index 4c432a311c6..297c93e0f18 100644 --- a/BGL/include/CGAL/boost/graph/named_params_helper.h +++ b/BGL/include/CGAL/boost/graph/named_params_helper.h @@ -19,18 +19,19 @@ #ifndef CGAL_BOOST_GRAPH_NAMED_PARAMETERS_HELPERS_H #define CGAL_BOOST_GRAPH_NAMED_PARAMETERS_HELPERS_H +#include #include - +#include +#include #include #include - #include -#include + #include #include - #include +#include namespace CGAL { @@ -40,8 +41,8 @@ namespace CGAL { class Eigen_svd; class Lapack_svd; // - - + + //helper classes template class property_map_selector @@ -104,7 +105,8 @@ namespace CGAL { property_map_selector pms; return pms.get_const_pmap(p, pmesh); } -// shortcut for accessing the value type of the property map + + // Shortcut for accessing the value type of the property map template class property_map_value { typedef typename boost::property_map::const_type PMap; @@ -175,37 +177,105 @@ namespace CGAL { > ::type type; }; - template - class GetFaceIndexMap - { - typedef typename property_map_selector::type DefaultMap; - typedef typename property_map_selector::const_type DefaultMap_const; - public: - typedef typename internal_np::Lookup_named_param_def < - internal_np::face_index_t, - NamedParameters, - DefaultMap - > ::type type; - typedef typename internal_np::Lookup_named_param_def < - internal_np::face_index_t, - NamedParameters, - DefaultMap_const - > ::type const_type; - typedef typename boost::is_same::type Is_internal_map; - typedef typename boost::is_same::type Is_internal_map_const; - }; +// Define the following structs: +// +// GetInitializedVertexIndexMap +// GetInitializedHalfedgeIndexMap +// GetInitializedEdgeIndexMap +// GetInitializedFaceIndexMap - template - class GetVertexIndexMap - { - typedef typename property_map_selector::type DefaultMap; - public: - typedef typename internal_np::Lookup_named_param_def < - internal_np::vertex_index_t, - NamedParameters, - DefaultMap - > ::type type; - }; +#define CGAL_DEF_GET_INDEX_TYPE(CTYPE, DTYPE, STYPE) \ +template > \ +struct GetInitialized##CTYPE##IndexMap \ + : public BGL::internal::GetInitializedIndexMap, \ + Graph, NamedParameters> \ +{ }; + +CGAL_DEF_GET_INDEX_TYPE(Vertex, vertex, typename boost::graph_traits::vertices_size_type) +CGAL_DEF_GET_INDEX_TYPE(Halfedge, halfedge, typename boost::graph_traits::halfedges_size_type) +CGAL_DEF_GET_INDEX_TYPE(Edge, edge, typename boost::graph_traits::edges_size_type) +CGAL_DEF_GET_INDEX_TYPE(Face, face, typename boost::graph_traits::faces_size_type) + +#undef CGAL_DEF_GET_INDEX_TYPE + +// Define the following functions: +// +// get_initialized_vertex_index_map() +// get_initialized_halfedge_index_map() +// get_initialized_edge_index_map() +// get_initialized_face_index_map() +// +// The function returns: +// - the index property map passed in the NPs, if passed in the NPs; it must be initialized by the user; +// - the internal index property map if it is the graph has one. It is initialized if needed and possible; +// - an initialized dynamic pmap otherwise. + +#define CGAL_DEF_GET_INITIALIZED_INDEX_MAP(DTYPE, STYPE) \ +template \ +typename BGL::internal::GetInitializedIndexMap, \ + Graph, NamedParameters>::const_type \ +get_initialized_##DTYPE##_index_map(const Graph& g, \ + const NamedParameters& np) \ +{ \ + typedef BGL::internal::GetInitializedIndexMap, \ + Graph, NamedParameters> Index_map_getter; \ + return Index_map_getter::get_const(CGAL::internal_np::DTYPE##_index_t{}, g, np); \ +} \ +template \ +typename BGL::internal::GetInitializedIndexMap, \ + Graph>::const_type \ +get_initialized_##DTYPE##_index_map(const Graph& g) \ +{ \ + return get_initialized_##DTYPE##_index_map(g, CGAL::parameters::all_default()); \ +} \ +/* same as above, non-const version*/ \ +template ::type>::value, int> = 0> \ +typename BGL::internal::GetInitializedIndexMap, \ + Graph, NamedParameters>::type \ +get_initialized_##DTYPE##_index_map(Graph& g, \ + const NamedParameters& np) \ +{ \ + typedef BGL::internal::GetInitializedIndexMap, \ + Graph, NamedParameters> Index_map_getter; \ + return Index_map_getter::get(CGAL::internal_np::DTYPE##_index_t{}, g, np); \ +} \ +template ::type>::value, int> = 0> \ +typename BGL::internal::GetInitializedIndexMap, \ + Graph>::type \ +get_initialized_##DTYPE##_index_map(Graph& g) \ +{ \ + return get_initialized_##DTYPE##_index_map(g, CGAL::parameters::all_default()); \ +} + +CGAL_DEF_GET_INITIALIZED_INDEX_MAP(vertex, typename boost::graph_traits::vertices_size_type) +CGAL_DEF_GET_INITIALIZED_INDEX_MAP(halfedge, typename boost::graph_traits::halfedges_size_type) +CGAL_DEF_GET_INITIALIZED_INDEX_MAP(edge, typename boost::graph_traits::edges_size_type) +CGAL_DEF_GET_INITIALIZED_INDEX_MAP(face, typename boost::graph_traits::faces_size_type) + +#undef CGAL_DEF_GET_INITIALIZED_INDEX_MAP template class GetFaceNormalMap @@ -244,7 +314,7 @@ namespace CGAL { typedef std::random_access_iterator_tag iterator_category; }; }; - + namespace parameters { template @@ -258,7 +328,7 @@ namespace CGAL { namespace internal{ BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_nested_type_iterator, iterator, false) } - + template::value> class GetPointMap @@ -380,7 +450,7 @@ namespace CGAL { DefaultPMap > ::type const_type; }; - + template class GetPlaneIndexMap { @@ -428,7 +498,7 @@ namespace CGAL { }; } // namespace Point_set_processing_3 - + template class GetSolver { @@ -461,10 +531,10 @@ namespace CGAL { typedef int Matrix; static FT solve (const Matrix&, Vector&) { return 0.; } }; - + public: typedef DummySvdTraits NoTraits; - + typedef typename internal_np::Lookup_named_param_def < internal_np::svd_traits_t, NamedParameters, @@ -477,6 +547,7 @@ namespace CGAL { #endif > ::type type; }; + } //namespace CGAL diff --git a/BGL/include/CGAL/boost/graph/parameters_interface.h b/BGL/include/CGAL/boost/graph/parameters_interface.h index ebdce042e75..a65e2d99f07 100644 --- a/BGL/include/CGAL/boost/graph/parameters_interface.h +++ b/BGL/include/CGAL/boost/graph/parameters_interface.h @@ -93,7 +93,8 @@ CGAL_add_named_parameter(get_placement_policy_t, get_placement_policy, get_place //to be documented CGAL_add_named_parameter(face_normal_t, face_normal, face_normal_map) CGAL_add_named_parameter(random_seed_t, random_seed, random_seed) -CGAL_add_named_parameter(tolerance_map_t, tolerance_map, tolerance_map) +CGAL_add_named_parameter(do_lock_mesh_t, do_lock_mesh, do_lock_mesh) +CGAL_add_named_parameter(do_simplify_border_t, do_simplify_border, do_simplify_border) //internal CGAL_add_named_parameter(weight_calculator_t, weight_calculator, weight_calculator) diff --git a/BGL/include/CGAL/boost/graph/properties.h b/BGL/include/CGAL/boost/graph/properties.h index 6460f9f88e6..589662ce0dc 100644 --- a/BGL/include/CGAL/boost/graph/properties.h +++ b/BGL/include/CGAL/boost/graph/properties.h @@ -14,72 +14,45 @@ #define CGAL_BOOST_GRAPH_BGL_PROPERTIES_H #include +#include +#include + #include #include -#include -#include -#include -#include #include +#include +#include + +namespace CGAL { -namespace CGAL{ -/// \ingroup PkgBGLProperties -/// \brief graph_has_property is used to indicate if -/// a model of `HalfedgeGraph` or `FaceGraph` -/// has an internal property associated with the -/// given `PropertyTag`. -/// -/// It inherits from `CGAL::Tag_true` if there is a -/// default internal property map for the -/// corresponding property tag and from -/// `CGAL::Tag_false` otherwise. -/// -/// \tparam Graph a model of `HalfedgeGraph` or `FaceGraph` -/// \tparam PropertyTag the type of a property tag -/// referring to the property of interest. -/// template -struct graph_has_property -#ifndef DOXYGEN_RUNNING - : CGAL::Tag_false -#endif -{}; -} -/// Boost Namespace +struct graph_has_property : CGAL::Tag_false { }; + +} // namespace CGAL + namespace boost { -/// \ingroup PkgBGLProperties -/// @{ - -/// A property tag which refers to the geometric embedding property -/// of a vertex of a \ref HalfedgeGraph. enum vertex_point_t { vertex_point }; -enum vertex_external_index_t { vertex_external_index } ; -/// A property tag which refers to the property -/// of a halfedge of being a border halfedge. -enum edge_external_index_t { edge_external_index } ; +// vertex_index_t is defined in boost +enum vertex_external_index_t { vertex_external_index }; -/// A property tag which identifies the *index* property of -/// a halfedge of a \ref HalfedgeGraph. -enum halfedge_index_t { halfedge_index }; -enum halfedge_external_index_t { halfedge_external_index } ; +enum halfedge_index_t { halfedge_index }; +enum halfedge_external_index_t { halfedge_external_index }; + +// edge_index_t is defined in boost +enum edge_external_index_t { edge_external_index }; -/// A property tag which identifies the *index* property of -/// a face of a \ref FaceGraph. enum face_index_t { face_index }; -enum face_external_index_t { face_external_index } ; +enum face_external_index_t { face_external_index }; - struct cgal_no_property { typedef bool type; typedef const bool const_type; }; -/// @} - // Introduce those two tags so we can use BOOST_INSTALL_PROPERTY // macro. This is dangerous because we now rely on implementation // details. @@ -97,12 +70,16 @@ BOOST_INSTALL_PROPERTY(face, external_index); namespace CGAL { using boost::vertex_point_t; using boost::vertex_point; +using boost::vertex_index_t; +using boost::vertex_index; using boost::vertex_external_index_t; using boost::vertex_external_index; using boost::halfedge_index_t; using boost::halfedge_index; using boost::halfedge_external_index_t; using boost::halfedge_external_index; +using boost::edge_index_t; +using boost::edge_index; using boost::edge_external_index_t; using boost::edge_external_index; using boost::face_index_t; @@ -111,128 +88,7 @@ using boost::face_external_index_t; using boost::face_external_index; } // CGAL -namespace CGAL{ -namespace helpers { - -// matches read-write property maps -template -void init_face_indices(PolygonMesh& pm, - FaceIndexMap& fid, - boost::read_write_property_map_tag, - Tag) -{ - typename boost::property_traits::value_type i = 0; - for(typename boost::graph_traits::face_descriptor fd : - faces(pm)) - { - put(fid, fd, i); - ++i; - } -} -template -void init_vertex_indices(PolygonMesh& pm, - VertexIndexMap& vid, - boost::read_write_property_map_tag, - Tag) -{ - typename boost::property_traits::value_type i = 0; - for(typename boost::graph_traits::vertex_descriptor vd : - vertices(pm)) - { - put(vid, vd, i); - ++i; - } -} -template -void init_halfedge_indices(PolygonMesh& pm, - HalfedgeIndexMap& hid, - boost::read_write_property_map_tag, - Tag) -{ - typename boost::property_traits::value_type i = 0; - for(typename boost::graph_traits::halfedge_descriptor hd : - halfedges(pm)) - { - put(hid, hd, i); - ++i; - } -} - -// matches mutable Lvalue property maps -template -void init_face_indices(PolygonMesh& pm, - FaceIndexMap& fid, - boost::lvalue_property_map_tag, - boost::false_type) -{ - init_face_indices(pm, fid, - boost::read_write_property_map_tag(), boost::false_type()); -} -template -void init_vertex_indices(PolygonMesh& pm, - VertexIndexMap& vid, - boost::lvalue_property_map_tag, - boost::false_type) -{ - init_vertex_indices(pm, vid, - boost::read_write_property_map_tag(), boost::false_type()); -} -template -void init_halfedge_indices(PolygonMesh& pm, - HalfedgeIndexMap& hid, - boost::lvalue_property_map_tag, - boost::false_type) -{ - init_halfedge_indices(pm, hid, - boost::read_write_property_map_tag(), boost::false_type()); -} - -// matches all other types of property map -template -void init_face_indices(PolygonMesh&, FaceIndexMap, MapTag, Tag) -{} -template -void init_vertex_indices(PolygonMesh&, VertexIndexMap, MapTag, Tag) -{} -template -void init_halfedge_indices(PolygonMesh&, HalfedgeIndexMap, MapTag, Tag) -{} - -template -void init_face_indices(PolygonMesh& pm, FaceIndexMap fid) -{ - init_face_indices(pm, fid, - typename boost::property_traits::category(), - typename boost::is_const< - typename boost::remove_reference< - typename boost::property_traits::reference - >::type >::type() ); -} - -template -void init_vertex_indices(PolygonMesh& pm, VertexIndexMap vid) -{ - init_vertex_indices(pm, vid, - typename boost::property_traits::category(), - typename boost::is_const< - typename boost::remove_reference< - typename boost::property_traits::reference - >::type >::type() ); -} - -template -void init_halfedge_indices(PolygonMesh& pm, HalfedgeIndexMap hid) -{ - init_halfedge_indices(pm, hid, - typename boost::property_traits::category(), - typename boost::is_const< - typename boost::remove_reference< - typename boost::property_traits::reference - >::type >::type() ); -} - -} //namespace helpers - +namespace CGAL { namespace internal { template @@ -260,8 +116,8 @@ struct Edge_index_accessor }; template::type >::value> + bool is_const = std::is_const< + typename std::remove_reference::type >::value> struct Point_accessor : boost::put_get_helper< Reference, Point_accessor > { @@ -293,6 +149,32 @@ struct Point_accessor reference operator[](Handle h) const { return h->point(); } }; +// this one is basically 'readable_property_map_tag' +template ::category> +struct Is_writable_property_map : CGAL::Tag_false { }; + +template +struct Is_writable_property_map : CGAL::Tag_true { }; + +template +struct Is_writable_property_map : CGAL::Tag_true { }; + +// 'lvalue_pmap_tag' is annoying, because the property map is allowed to be non-mutable, +// but boost::lvalue_property_map_tag is defined as: +// struct lvalue_property_map_tag : public read_write_property_map_tag +// so we can't just check that 'writable_property_map_tag' is a base of the the lvalue tag. +// +// This checks if the reference is non-const, which is not completely correct: map[key] returning +// a non-const reference doesn't mean that 'put(map, key, val)' exists, which is what a writable +// property map must define. +template +struct Is_writable_property_map + : boost::mpl::if_c::reference>::type>::value, + CGAL::Tag_false, CGAL::Tag_true>::type +{ }; + } // namespace internal // Needed by PMP::detec_features and Mesh_3 @@ -303,12 +185,12 @@ enum vertex_time_stamp_t { vertex_time_stamp}; enum halfedge_time_stamp_t { halfedge_time_stamp}; enum face_time_stamp_t { face_time_stamp}; -template +template struct vertex_incident_patches_t { typedef ID type; }; -template +template struct face_patch_id_t { typedef ID type; }; diff --git a/BGL/include/CGAL/boost/graph/properties_Seam_mesh.h b/BGL/include/CGAL/boost/graph/properties_Seam_mesh.h index 96bf18fa8ab..53acfbce101 100644 --- a/BGL/include/CGAL/boost/graph/properties_Seam_mesh.h +++ b/BGL/include/CGAL/boost/graph/properties_Seam_mesh.h @@ -112,6 +112,39 @@ struct property_map, CGAL::vertex_point_t> typedef CGAL::Seam_mesh_point_map type; typedef type const_type; }; + +template +struct property_map, CGAL::dynamic_vertex_property_t > +{ + typedef typename boost::graph_traits >::vertex_descriptor vertex_descriptor; + typedef CGAL::internal::Dynamic_property_map type; + typedef type const_type; +}; + +template +struct property_map, CGAL::dynamic_halfedge_property_t > +{ + typedef typename boost::graph_traits >::halfedge_descriptor halfedge_descriptor; + typedef CGAL::internal::Dynamic_property_map type; + typedef type const_type; +}; + + +template +struct property_map, CGAL::dynamic_edge_property_t > +{ + typedef typename boost::graph_traits >::edge_descriptor edge_descriptor; + typedef CGAL::internal::Dynamic_property_map type; + typedef type const_type; +}; + +template +struct property_map, CGAL::dynamic_face_property_t > +{ + typedef typename boost::graph_traits >::face_descriptor face_descriptor; + typedef CGAL::internal::Dynamic_property_map type; + typedef type const_type; +}; } // namespace boost namespace CGAL { diff --git a/BGL/include/CGAL/boost/graph/selection.h b/BGL/include/CGAL/boost/graph/selection.h index 769561cd705..ae44f79c0fa 100644 --- a/BGL/include/CGAL/boost/graph/selection.h +++ b/BGL/include/CGAL/boost/graph/selection.h @@ -584,26 +584,38 @@ void expand_face_selection_for_removal(const FaceRange& faces_to_be_deleted, { // collect non-selected faces std::vector faces_traversed; + bool non_selected_face_range_has_boundary = false; // handle non-manifold situations when crossing a border do { faces_traversed.push_back(next_around_vertex); next_around_vertex = opposite( next(next_around_vertex, tm), tm); if (is_border(next_around_vertex,tm)) + { next_around_vertex = opposite( next(next_around_vertex, tm), tm); + if (!get(is_selected, face(next_around_vertex, tm) )) + { + non_selected_face_range_has_boundary=true; // always non-manifold after removal of the selection + break; + } + } CGAL_assertion(!is_border(next_around_vertex,tm)); } while( !get(is_selected, face(next_around_vertex, tm) ) ); - // go over the connected components of faces to remove - do{ + if (!non_selected_face_range_has_boundary) + { + // go over the connected components of faces to remove + do{ + if (next_around_vertex==start) + break; + next_around_vertex = opposite( next(next_around_vertex, tm), tm); + } + while(is_border(next_around_vertex,tm) || get(is_selected, face(next_around_vertex, tm) ) ); + if (next_around_vertex==start) break; - next_around_vertex = opposite( next(next_around_vertex, tm), tm); } - while(is_border(next_around_vertex,tm) || get(is_selected, face(next_around_vertex, tm) ) ); - - if (next_around_vertex==start) - break; + // else we simply mark the range of traversed faces and start a new range after the border for(halfedge_descriptor f_hd : faces_traversed) { diff --git a/BGL/test/BGL/data/nm_selection_removal.off b/BGL/test/BGL/data/nm_selection_removal.off new file mode 100644 index 00000000000..d9a07f81dba --- /dev/null +++ b/BGL/test/BGL/data/nm_selection_removal.off @@ -0,0 +1,18 @@ +OFF +9 7 0 +0 0 0 +1 0 0 +2 0 0 +2 1 0 +2 2 0 +1 2 0 +0 2 0 +0 1 0 +1 1 0 +3 0 1 8 +3 1 2 8 +3 2 3 8 +3 3 4 8 +3 5 6 8 +3 6 7 8 +3 7 0 8 diff --git a/BGL/test/BGL/test_Euler_operations.cpp b/BGL/test/BGL/test_Euler_operations.cpp index 7b5439470a8..2edc8060d89 100644 --- a/BGL/test/BGL/test_Euler_operations.cpp +++ b/BGL/test/BGL/test_Euler_operations.cpp @@ -402,6 +402,44 @@ test_swap_edges() } } +template +void +add_face_bug() +{ + typedef boost::graph_traits GT; + typedef typename GT::vertex_descriptor vertex_descriptor; + typedef typename GT::halfedge_descriptor halfedge_descriptor; + + T g; + + std::vector vs; + vs.push_back( add_vertex(g) ); // Kernel::Point_3(0,1,0) + vs.push_back( add_vertex(g) ); // Kernel::Point_3(4,1,0) + vs.push_back( add_vertex(g) ); // Kernel::Point_3(5,2,0) + vs.push_back( add_vertex(g) ); // Kernel::Point_3(4,0,0) + + CGAL::Euler::add_face(CGAL::make_array(vs[0], vs[1], vs[2]), g); + CGAL::Euler::add_face(CGAL::make_array(vs[1], vs[3], vs[2]), g); + + // force vertex halfedge to not be a border halfedge + for(vertex_descriptor v : vertices(g)) + { + halfedge_descriptor h = halfedge(v, g); + if ( CGAL::is_border(h, g) ) + set_halfedge(v, prev(opposite(h, g), g), g); + assert(target(halfedge(v, g), g)==v); + } + + vs.push_back( add_vertex(g) ); // Kernel::Point_3(0,0,0) + vs.push_back( add_vertex(g) ); // Kernel::Point_3(1,0,0) + CGAL::Euler::add_face(CGAL::make_array(vs[4],vs[5],vs[0]), g); + + vs.push_back( add_vertex(g) ); // Kernel::Point_3(2,0,0) + vs.push_back( add_vertex(g) ); // Kernel::Point_3(3,0,0) + CGAL::Euler::add_face(CGAL::make_array(vs[6],vs[7],vs[1]), g); + CGAL::Euler::add_face(CGAL::make_array(vs[7],vs[3],vs[1]), g); +} + template void test_Euler_operations() @@ -421,6 +459,7 @@ test_Euler_operations() join_split_inverse(); does_satisfy_link_condition(); test_swap_edges(); + add_face_bug(); } int main() diff --git a/BGL/test/BGL/test_Face_filtered_graph.cpp b/BGL/test/BGL/test_Face_filtered_graph.cpp index bbf57e5b2c2..0a579fe96cc 100644 --- a/BGL/test/BGL/test_Face_filtered_graph.cpp +++ b/BGL/test/BGL/test_Face_filtered_graph.cpp @@ -491,13 +491,13 @@ int main() typedef boost::graph_traits PolyTraits; - typedef boost::property_map::type VPMap; + typedef boost::property_map::const_type VPMap; typedef PolyTraits::face_descriptor poly_face_descriptor; typedef boost::associative_property_map< std::map > FCMap; - typedef boost::property_map::type FIMap; - typedef boost::property_map::type VIMap; - typedef boost::property_map::type HIMap; + 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( @@ -516,14 +516,14 @@ int main() 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)); + 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, - CGAL::parameters::face_index_map(poly_fimap). - vertex_index_map(poly_vimap). - halfedge_index_map(poly_himap)); + CGAL::parameters::face_index_map(poly_fimap) + .vertex_index_map(poly_vimap) + .halfedge_index_map(poly_himap)); test_mesh(poly_adapter); } diff --git a/BGL/test/BGL/test_Manifold_face_removal.cpp b/BGL/test/BGL/test_Manifold_face_removal.cpp index 97ab16b3026..4e5e75dd0c8 100644 --- a/BGL/test/BGL/test_Manifold_face_removal.cpp +++ b/BGL/test/BGL/test_Manifold_face_removal.cpp @@ -14,6 +14,68 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Surface_mesh SM; typedef boost::graph_traits::face_descriptor face_descriptor; +void border_cases() +{ + SM sm_ref; + std::ifstream input("data/nm_selection_removal.off"); + input >> sm_ref; + + { + SM sm = sm_ref; + std::vector faces_to_remove; + faces_to_remove.push_back(SM::Face_index(5)); + faces_to_remove.push_back(SM::Face_index(6)); + SM::Property_map is_selected = sm.add_property_map("f:is_selected", false).first; + is_selected[SM::Face_index(5)]=true; + is_selected[SM::Face_index(6)]=true; + CGAL::expand_face_selection_for_removal(faces_to_remove, + sm, + is_selected); + int i=0; + for(face_descriptor fh : sm.faces()) + if(!is_selected[fh]) ++i; + assert(i==4); + } + + { + SM sm = sm_ref; + std::vector faces_to_remove; + faces_to_remove.push_back(SM::Face_index(4)); + faces_to_remove.push_back(SM::Face_index(6)); + SM::Property_map is_selected = sm.add_property_map("f:is_selected", false).first; + is_selected[SM::Face_index(4)]=true; + is_selected[SM::Face_index(6)]=true; + CGAL::expand_face_selection_for_removal(faces_to_remove, + sm, + is_selected); + int i=0; + for(face_descriptor fh : sm.faces()) + if(!is_selected[fh]) ++i; + + assert(i==1 || i==4); // depends on the start point + } + + { + SM sm = sm_ref; + std::vector faces_to_remove; + faces_to_remove.push_back(SM::Face_index(4)); + faces_to_remove.push_back(SM::Face_index(5)); + faces_to_remove.push_back(SM::Face_index(6)); + SM::Property_map is_selected = sm.add_property_map("f:is_selected", false).first; + is_selected[SM::Face_index(4)]=true; + is_selected[SM::Face_index(5)]=true; + is_selected[SM::Face_index(6)]=true; + CGAL::expand_face_selection_for_removal(faces_to_remove, + sm, + is_selected); + int i=0; + for(face_descriptor fh : sm.faces()) + if(!is_selected[fh]) ++i; + assert(i==4); // depends on the start point + } + +} + int main() { SM sm; @@ -60,6 +122,8 @@ int main() assert( sm.number_of_faces()+30 < nb_input_faces); assert(is_valid_polygon_mesh(sm)); + border_cases(); + return 0; } diff --git a/BGL/test/BGL/test_Prefix.h b/BGL/test/BGL/test_Prefix.h index e5343a10659..4ca383561f1 100644 --- a/BGL/test/BGL/test_Prefix.h +++ b/BGL/test/BGL/test_Prefix.h @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -57,6 +58,10 @@ typedef CGAL::Linear_cell_complex_for_bgl_combinatorial_map_helper typedef CGAL::Surface_mesh SM; +typedef SM::Property_map Seam_edge_pmap; +typedef SM::Property_map Seam_vertex_pmap; +typedef CGAL::Seam_mesh Seam_mesh; + #if defined(CGAL_USE_OPENMESH) #include @@ -73,6 +78,8 @@ typedef OpenMesh::PolyMesh_ArrayKernelT OMesh; typedef CGAL::Triangulation_vertex_base_with_id_2 Vbb; typedef CGAL::Triangulation_face_base_with_id_2 Fbb; +typedef CGAL::Triangulation_2 Triangulation_no_id_2; + typedef CGAL::Triangulation_2 > Triangulation_2; typedef CGAL::Delaunay_triangulation_2 Tr build_dummy_triangulation() { typedef typename Tr::Point Point; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; Tr t; t.insert(Point(0.1,0)); @@ -199,24 +204,25 @@ Tr build_dummy_triangulation() t.insert(Point(0,1)); t.insert(Point(0,2)); - int id = 0; - for(vertex_descriptor vd : vertices(t)) - vd->id() = id++; - - id = 0; - for(face_descriptor fd : faces(t)) - fd->id() = id++; - return t; } -Triangulation_2 t2_data() { return build_dummy_triangulation(); } -Delaunay_triangulation_2 dt2_data() { return build_dummy_triangulation(); } -Regular_triangulation_2 rt2_data() { return build_dummy_triangulation(); } -Constrained_triangulation_2 ct2_data() { return build_dummy_triangulation(); } -Constrained_Delaunay_triangulation_2 cdt2_data() { return build_dummy_triangulation(); } -CDT_P2 cdtp2_data() { return build_dummy_triangulation(); } -Triangulation_hierarchy_2 t2h_data() { return build_dummy_triangulation(); } +template +Tr build_dummy_triangulation_with_ids() +{ + Tr t = build_dummy_triangulation(); + CGAL::set_triangulation_ids(t); + return t; +} + +Triangulation_no_id_2 t2_no_id_data() { return build_dummy_triangulation(); } +Triangulation_2 t2_data() { return build_dummy_triangulation_with_ids(); } +Delaunay_triangulation_2 dt2_data() { return build_dummy_triangulation_with_ids(); } +Regular_triangulation_2 rt2_data() { return build_dummy_triangulation_with_ids(); } +Constrained_triangulation_2 ct2_data() { return build_dummy_triangulation_with_ids(); } +Constrained_Delaunay_triangulation_2 cdt2_data() { return build_dummy_triangulation_with_ids(); } +CDT_P2 cdtp2_data() { return build_dummy_triangulation_with_ids(); } +Triangulation_hierarchy_2 t2h_data() { return build_dummy_triangulation_with_ids(); } template struct Surface_fixture_1 { diff --git a/BGL/test/BGL/test_Properties.cpp b/BGL/test/BGL/test_Properties.cpp index 3ffd9d1720e..984891b4ca9 100644 --- a/BGL/test/BGL/test_Properties.cpp +++ b/BGL/test/BGL/test_Properties.cpp @@ -1,115 +1,459 @@ #include "test_Prefix.h" +#include + #include -template< typename G, - typename ForwardRange, - typename IndexPropertyMap - > -void index_uniqueness(const G&, - ForwardRange range, - IndexPropertyMap pm) +// #define CGAL_TEST_PROPERTIES_DEBUG + +namespace CGAL { + +template +struct Non_mutable_property_map { + typedef Key key_type; + typedef Value value_type; + typedef value_type reference; + typedef boost::readable_property_map_tag category; + + Non_mutable_property_map(const Container& c) : m_c(c) { } + + friend reference get(const Non_mutable_property_map& pmap, key_type k) + { + return pmap.m_c.at(k); + } + +private: + const Container& m_c; +}; + +template +struct RW_property_map +{ + typedef Key key_type; + typedef Value value_type; + typedef value_type& reference; + typedef boost::read_write_property_map_tag category; + + RW_property_map(Container& c) : m_c(c) { } + + friend void put(RW_property_map& pmap, const key_type& k, const value_type& val) + { + pmap.m_c[k] = val; + } + + friend reference get(RW_property_map& pmap, const key_type& k) + { + return pmap.m_c[k]; + } + +private: + Container& m_c; +}; + +} // namespace CGAL + +template +void test_uniqueness(const Graph&, + const ForwardRange& range, + IndexPropertyMap index_map) +{ +#ifdef CGAL_TEST_PROPERTIES_DEBUG + std::cout << std::endl + << "Checking the uniqueness of the property map of type: " + << typeid(IndexPropertyMap).name() << std::endl; + std::cout << "Element type: " << typeid(typename boost::range_value::type).name() << std::endl; +#endif + typename boost::range_iterator::type - begin = boost::begin(range), + begin = boost::begin(range), begin2 = boost::begin(range), end = boost::end(range); typedef boost::unordered_set id_map; typedef std::pair resultp; - id_map m; - while(begin != end) { - resultp r = m.insert(get(pm, *begin)); + id_map m; + while(begin != end) + { + resultp r = m.insert(get(index_map, *begin)); +#ifdef CGAL_TEST_PROPERTIES_DEBUG + std::cout << "id: " << get(index_map, *begin) << std::endl; +#endif ++begin; - assert(r.second); + assert(r.second); // already seen that id } assert(std::distance(begin2, end) == static_cast(m.size())); } - -void index_uniqueness_poly(const Polyhedron& g) +template +void test_vertex_index_map_uniqueness(const Graph& g, + const NamedParameters& np) { - index_uniqueness(g, edges(g) , get(boost::edge_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); - index_uniqueness(g, faces(g), get(boost::face_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + typedef typename CGAL::GetInitializedVertexIndexMap::type VIM; + typedef typename CGAL::GetInitializedVertexIndexMap::const_type CVIM; - index_uniqueness(g, edges(g) , get(boost::edge_external_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_external_index, g)); - index_uniqueness(g, faces(g), get(boost::face_external_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_external_index, g)); + // in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not + static_assert((std::is_same::value), "VIM, CVIM must be the same type"); + + VIM ivim = CGAL::get_initialized_vertex_index_map(g, np); + + return test_uniqueness(g, vertices(g), ivim); } -void index_uniqueness_lcc(const LCC& g) +template +void test_halfedge_index_map_uniqueness(const Graph& g, + const NamedParameters& np) { - index_uniqueness(g, edges(g) , get(boost::edge_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); - index_uniqueness(g, faces(g), get(boost::face_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + typedef typename CGAL::GetInitializedHalfedgeIndexMap::type HIM; + typedef typename CGAL::GetInitializedHalfedgeIndexMap::const_type CHIM; + + // in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not + static_assert((std::is_same::value), "HIM, CHIM must be the same type"); + + HIM ihim = CGAL::get_initialized_halfedge_index_map(g, np); + + return test_uniqueness(g, halfedges(g), ihim); } -void index_uniqueness_sm(const SM& g) +template +void test_edge_index_map_uniqueness(const Graph& g, + const NamedParameters& np) { - index_uniqueness(g, edges(g) , get(boost::edge_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); - index_uniqueness(g, faces(g), get(boost::face_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + typedef typename CGAL::GetInitializedEdgeIndexMap::type EIM; + typedef typename CGAL::GetInitializedEdgeIndexMap::const_type CEIM; + + // in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not + static_assert((std::is_same::value), "EIM, CEIM must be the same type"); + + EIM ieim = CGAL::get_initialized_edge_index_map(g, np); + + return test_uniqueness(g, edges(g), ieim); } -#if defined(CGAL_USE_OPENMESH) -void index_uniqueness_omesh(const OMesh& g) +template +void test_face_index_map_uniqueness(const Graph& g, + const NamedParameters& np) { - index_uniqueness(g, edges(g) , get(boost::edge_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); - index_uniqueness(g, faces(g), get(boost::face_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + typedef typename CGAL::GetInitializedFaceIndexMap::type FIM; + typedef typename CGAL::GetInitializedFaceIndexMap::const_type CFIM; + + // in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not + static_assert((std::is_same::value), "FIM, CFIM must be the same type"); + + FIM ifim = CGAL::get_initialized_face_index_map(g, np); + + return test_uniqueness(g, faces(g), ifim); } + +////////////////////////////////////////// const /////////////////////////////////////////////////// + +template +void test_internal_index_maps_const(const Graph& g) +{ + test_uniqueness(g, vertices(g), get(boost::vertex_index, g)); + test_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + test_uniqueness(g, edges(g) , get(boost::edge_index, g)); + test_uniqueness(g, faces(g), get(boost::face_index, g)); +} + +template +void test_initialized_index_maps_const(const Graph& g) +{ + typedef typename CGAL::GetInitializedVertexIndexMap::const_type VIM; + VIM ivim = CGAL::get_initialized_vertex_index_map(g); + test_uniqueness(g, vertices(g), ivim); + + typedef typename CGAL::GetInitializedHalfedgeIndexMap::const_type HIM; + HIM ihim = CGAL::get_initialized_halfedge_index_map(g); + test_uniqueness(g, halfedges(g), ihim); + + typedef typename CGAL::GetInitializedEdgeIndexMap::const_type EIM; + EIM ieim = CGAL::get_initialized_edge_index_map(g); + test_uniqueness(g, edges(g), ieim); + + typedef typename CGAL::GetInitializedFaceIndexMap::const_type FIM; + FIM ifim = CGAL::get_initialized_face_index_map(g); + test_uniqueness(g, faces(g), ifim); + + // Passing an index map via NP + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef std::map VertexIndexMap; + typedef boost::associative_property_map VertexIdPropertyMap; // lvalue_pmap + + int vi = static_cast(num_vertices(g)); + VertexIndexMap vim; + VertexIdPropertyMap external_vertex_index_map(vim); + for(vertex_descriptor v : vertices(g)) + put(external_vertex_index_map, v, --vi); + + test_vertex_index_map_uniqueness(g, CGAL::parameters::vertex_index_map(external_vertex_index_map)); + + // Read-only pmap + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef std::map HalfedgeIndexMap; + typedef CGAL::Non_mutable_property_map HalfedgeIdPropertyMap; + + int hi = 0; + HalfedgeIndexMap him; + HalfedgeIdPropertyMap external_halfedge_index_map(him); + + // this should complain that the map is not writable (commented because it does assert) +// CGAL::BGL::internal::initialize_halfedge_index_map(external_halfedge_index_map, g); + + // forced to initialize the underlying map + for(halfedge_descriptor h : halfedges(g)) + him[h] = hi++; + + test_halfedge_index_map_uniqueness(g, CGAL::parameters::halfedge_index_map(external_halfedge_index_map)); + + // Writable pmap + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef boost::unordered_map EdgeIndexMap; + typedef CGAL::RW_property_map EdgeIdPropertyMap; + + EdgeIndexMap eim; + EdgeIdPropertyMap external_edge_index_map(eim); + CGAL::BGL::internal::initialize_edge_index_map(external_edge_index_map, g); + + test_edge_index_map_uniqueness(g, CGAL::parameters::edge_index_map(external_edge_index_map)); + + // Just so face_index_map don't feel excluded + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef std::map FaceIndexMap; + typedef boost::const_associative_property_map FaceIdPropertyMap; + + FaceIndexMap fim; + FaceIdPropertyMap external_face_index_map(fim); + + // 'const_associative_pmap' has category 'lvalue_property_map_tag' but it's not writable + // so below should complain (commented because it does assert) +// CGAL::BGL::internal::initialize_face_index_map(external_face_index_map, g); + + // gotta initialize the underlying map + int fi = 0; + for(face_descriptor f : faces(g)) + fim[f] = fi++; + + test_face_index_map_uniqueness(g, CGAL::parameters::face_index_map(external_face_index_map)); +} + +template +void test_all_index_maps_const(const Graph& g) +{ +#ifdef CGAL_TEST_PROPERTIES_DEBUG + std::cout << " ---------------------------- Const graph tests" << std::endl; #endif -template -void index_uniqueness_tr(const Triangulation& g) -{ - index_uniqueness(g, edges(g) , get(boost::edge_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); - index_uniqueness(g, faces(g), get(boost::face_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + test_internal_index_maps_const(g); + test_initialized_index_maps_const(g); } -int main() +///////////////////////////////////// non-const //////////////////////////////////////////////////// + +template +void test_internal_index_maps(Graph& g) +{ + test_uniqueness(g, vertices(g), get(boost::vertex_index, g)); + test_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + test_uniqueness(g, edges(g) , get(boost::edge_index, g)); + test_uniqueness(g, faces(g), get(boost::face_index, g)); +} + +template +void test_initialized_index_maps(Graph& g) +{ + typedef typename CGAL::GetInitializedVertexIndexMap::type VIM; + VIM ivim = CGAL::get_initialized_vertex_index_map(g); + test_uniqueness(g, vertices(g), ivim); + + typedef typename CGAL::GetInitializedHalfedgeIndexMap::type HIM; + HIM ihim = CGAL::get_initialized_halfedge_index_map(g); + test_uniqueness(g, halfedges(g), ihim); + + typedef typename CGAL::GetInitializedEdgeIndexMap::type EIM; + EIM ieim = CGAL::get_initialized_edge_index_map(g); + test_uniqueness(g, edges(g), ieim); + + typedef typename CGAL::GetInitializedFaceIndexMap::type FIM; + FIM ifim = CGAL::get_initialized_face_index_map(g); + test_uniqueness(g, faces(g), ifim); + + // Passing an index map via NP + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef std::map VertexIndexMap; + typedef boost::associative_property_map VertexIdPropertyMap; // lvalue_pmap + + int vi = static_cast(num_vertices(g)); + VertexIndexMap vim; + VertexIdPropertyMap external_vertex_index_map(vim); + for(vertex_descriptor v : vertices(g)) + put(external_vertex_index_map, v, --vi); + + test_vertex_index_map_uniqueness(g, CGAL::parameters::vertex_index_map(external_vertex_index_map)); + + // Read-only pmap + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef std::map HalfedgeIndexMap; + typedef CGAL::Non_mutable_property_map HalfedgeIdPropertyMap; + + int hi = 0; + HalfedgeIndexMap him; + HalfedgeIdPropertyMap external_halfedge_index_map(him); + + // this should complain that the map is not writable (commented because it does assert) +// CGAL::BGL::internal::initialize_halfedge_index_map(external_halfedge_index_map, g); + + // forced to initialize the underlying map + for(halfedge_descriptor h : halfedges(g)) + him[h] = hi++; + + test_halfedge_index_map_uniqueness(g, CGAL::parameters::halfedge_index_map(external_halfedge_index_map)); + + // Writable pmap + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef boost::unordered_map EdgeIndexMap; + typedef CGAL::RW_property_map EdgeIdPropertyMap; + + EdgeIndexMap eim; + EdgeIdPropertyMap external_edge_index_map(eim); + CGAL::BGL::internal::initialize_edge_index_map(external_edge_index_map, g); + + test_edge_index_map_uniqueness(g, CGAL::parameters::edge_index_map(external_edge_index_map)); + + // Just so face_index_map don't feel excluded + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef std::map FaceIndexMap; + typedef boost::const_associative_property_map FaceIdPropertyMap; + + FaceIndexMap fim; + FaceIdPropertyMap external_face_index_map(fim); + + // 'const_associative_pmap' has category 'lvalue_property_map_tag' but it's not writable + // so below should complain (commented because it does assert) +// CGAL::BGL::internal::initialize_face_index_map(external_face_index_map, g); + + // gotta initialize the underlying map + int fi = 0; + for(face_descriptor f : faces(g)) + fim[f] = fi++; + + test_face_index_map_uniqueness(g, CGAL::parameters::face_index_map(external_face_index_map)); +} + +template +void test_all_index_maps(Graph& g) +{ +#ifdef CGAL_TEST_PROPERTIES_DEBUG + std::cout << " ---------------------------- Non-const graph tests" << std::endl; +#endif + + test_internal_index_maps(g); + test_initialized_index_maps(g); +} + +template +void test_graph(Graph& g) +{ +#ifdef CGAL_TEST_PROPERTIES_DEBUG + std::cout << "Graph has:" << std::endl + << "\t" << num_vertices(g) << " vertices (actual: " << vertices(g).size() << ")" << std::endl + << "\t" << num_halfedges(g) << " halfedges (actual: " << halfedges(g).size() << ")" << std::endl + << "\t" << num_edges(g) << " edges (actual: " << edges(g).size() << ")" << std::endl + << "\t" << num_faces(g) << " faces (actual: " << faces(g).size() << ")" << std::endl; +#endif + + test_all_index_maps(g); + test_all_index_maps_const(g); +} + +void test_poly(Polyhedron& g) +{ + test_graph(g); + + test_uniqueness(g, edges(g) , get(boost::edge_external_index, g)); + test_uniqueness(g, vertices(g), get(boost::vertex_external_index, g)); + test_uniqueness(g, faces(g), get(boost::face_external_index, g)); + test_uniqueness(g, halfedges(g), get(boost::halfedge_external_index, g)); +} + +int main(int, char**) { std::cout << "testing Polyhedron\n"; std::vector polys = poly_data(); - for(Polyhedron p : polys) - index_uniqueness_poly(p); + for(Polyhedron& p : polys) + test_poly(p); std::cout << "testing Linear_cell_complex\n"; std::vector lccs = lcc_data(); - for(LCC p : lccs) - index_uniqueness_lcc(p); + for(LCC& p : lccs) + test_graph(p); std::cout << "testing Surface_mesh\n"; std::vector sms = sm_data(); - for(SM p : sms) - index_uniqueness_sm(p); + for(SM& sm : sms) + { + assert(!CGAL::is_empty(sm)); + + // Add some garbage + CGAL::Euler::join_vertex(*(halfedges(sm).begin()), sm); + + test_graph(sm); + + // Test on a mesh with no internal index maps + Seam_edge_pmap seam_edges = sm.add_property_map("e:on_seam", false).first; + Seam_vertex_pmap seam_vertices = sm.add_property_map("v:on_seam", false).first; + Seam_mesh seam_mesh(sm, seam_edges, seam_vertices); + + test_initialized_index_maps(seam_mesh); + test_initialized_index_maps_const(seam_mesh); + } #if defined(CGAL_USE_OPENMESH) std::cout << "testing OpenMesh\n"; std::vector omeshs = omesh_data(); - for(OMesh p : omeshs) - index_uniqueness_omesh(p); + for(OMesh& p : omeshs) + test_graph(p); #endif std::cout << "testing Triangulations\n"; - index_uniqueness_tr(t2_data()); - index_uniqueness_tr(dt2_data()); - index_uniqueness_tr(rt2_data()); - index_uniqueness_tr(ct2_data()); - index_uniqueness_tr(cdt2_data()); - index_uniqueness_tr(cdtp2_data()); - index_uniqueness_tr(t2h_data()); - std::cerr << "done\n"; - return 0; + Triangulation_2 t2 = t2_data(); + test_graph(t2); + + Delaunay_triangulation_2 dt2 = dt2_data(); + test_graph(dt2); + + Regular_triangulation_2 rt2 = rt2_data(); + test_graph(rt2); + + Constrained_triangulation_2 ct2 = ct2_data(); + test_graph(ct2); + + Constrained_Delaunay_triangulation_2 cdt2 = cdt2_data(); + test_graph(cdt2); + + CDT_P2 cdtp2 = cdtp2_data(); + test_graph(cdtp2); + + Triangulation_hierarchy_2 t2h = t2h_data(); + test_graph(t2h); + + // no dynamic pmaps in triangulations (yet) +// Triangulation_no_id_2 t2_no_id = t2_no_id_data(); +// test_initialized_index_maps(t2_no_id); +// test_initialized_index_maps_const(t2_no_id); + + std::cout << "Done!" << std::endl; + + return EXIT_SUCCESS; } diff --git a/BGL/test/BGL/test_cgal_bgl_named_params.cpp b/BGL/test/BGL/test_cgal_bgl_named_params.cpp index c3a577f20e3..53c6c65adf1 100644 --- a/BGL/test/BGL/test_cgal_bgl_named_params.cpp +++ b/BGL/test/BGL/test_cgal_bgl_named_params.cpp @@ -94,6 +94,8 @@ void test(const NamedParameters& np) assert(get_parameter(np, CGAL::internal_np::area_threshold).v == 57); assert(get_parameter(np, CGAL::internal_np::volume_threshold).v == 58); assert(get_parameter(np, CGAL::internal_np::dry_run).v == 59); + assert(get_parameter(np, CGAL::internal_np::do_lock_mesh).v == 60); + assert(get_parameter(np, CGAL::internal_np::do_simplify_border).v == 61); // Named parameters that we use in the package 'Surface Mesh Simplification' assert(get_parameter(np, CGAL::internal_np::get_cost_policy).v == 34); @@ -181,6 +183,8 @@ void test(const NamedParameters& np) check_same_type<57>(get_parameter(np, CGAL::internal_np::area_threshold)); check_same_type<58>(get_parameter(np, CGAL::internal_np::volume_threshold)); check_same_type<59>(get_parameter(np, CGAL::internal_np::dry_run)); + check_same_type<60>(get_parameter(np, CGAL::internal_np::do_lock_mesh)); + check_same_type<61>(get_parameter(np, CGAL::internal_np::do_simplify_border)); // Named parameters that we use in the package 'Surface Mesh Simplification' check_same_type<34>(get_parameter(np, CGAL::internal_np::get_cost_policy)); @@ -274,6 +278,8 @@ int main() .area_threshold(A<57>(57)) .volume_threshold(A<58>(58)) .dry_run(A<59>(59)) + .do_lock_mesh(A<60>(60)) + .do_simplify_border(A<61>(61)) ); return EXIT_SUCCESS; diff --git a/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt b/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt index 8802463b72d..9e5c6bb914e 100644 --- a/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt +++ b/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt @@ -8,15 +8,16 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() # create a target per cppfile file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) if(NOT (${cppfile} STREQUAL "ellipsoid.cpp") OR EIGEN3_FOUND) create_single_source_cgal_program( "${cppfile}" ) + if (EIGEN3_FOUND) + get_filename_component(target ${cppfile} NAME_WE) + CGAL_target_use_Eigen(${target}) + endif() endif() endforeach() diff --git a/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt b/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt index 403e652475c..dd6813bb97e 100644 --- a/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt +++ b/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt @@ -14,15 +14,16 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() # create a target per cppfile file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) if(NOT (${cppfile} STREQUAL "Approximate_min_ellipsoid_d.cpp") OR EIGEN3_FOUND) create_single_source_cgal_program( "${cppfile}" ) + if (EIGEN3_FOUND) + get_filename_component(target ${cppfile} NAME_WE) + CGAL_target_use_Eigen(${target}) + endif() endif() endforeach() diff --git a/CGAL_ImageIO/include/CGAL/read_vtk_image_data.h b/CGAL_ImageIO/include/CGAL/read_vtk_image_data.h index a0e892fb416..3dee3352a19 100644 --- a/CGAL_ImageIO/include/CGAL/read_vtk_image_data.h +++ b/CGAL_ImageIO/include/CGAL/read_vtk_image_data.h @@ -76,6 +76,10 @@ read_vtk_image_data(vtkImageData* vtk_image, Image_3::Own owning = Image_3::OWN_ image->wdim = imageio_type.wdim; image->wordKind = imageio_type.wordKind; image->sign = imageio_type.sign; + if (!vtk_image->GetPointData() || !vtk_image->GetPointData()->GetScalars()) { + ::_freeImage(image); + return Image_3(); + } CGAL_assertion(vtk_image->GetPointData()->GetScalars()->GetNumberOfTuples() == dims[0]*dims[1]*dims[2]); if(owning == Image_3::OWN_THE_DATA) { image->data = ::ImageIO_alloc(dims[0]*dims[1]*dims[2]*image->wdim); diff --git a/CGAL_ipelets/demo/CGAL_ipelets/CMakeLists.txt b/CGAL_ipelets/demo/CGAL_ipelets/CMakeLists.txt index 64206c30223..a764689a9d9 100644 --- a/CGAL_ipelets/demo/CGAL_ipelets/CMakeLists.txt +++ b/CGAL_ipelets/demo/CGAL_ipelets/CMakeLists.txt @@ -27,9 +27,7 @@ if ( CGAL_FOUND ) include(${CGAL_USE_FILE}) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - else() + if (NOT EIGEN3_FOUND) message(STATUS "NOTICE: This project requires the Eigen library, and will not be compiled.") return() endif() @@ -143,6 +141,7 @@ if ( CGAL_FOUND ) add_library(CGAL_${IPELET} MODULE ${IPELET}.cpp) add_to_cached_list(CGAL_EXECUTABLE_TARGETS CGAL_${IPELET}) target_link_libraries(CGAL_${IPELET} PRIVATE CGAL::CGAL ${IPE_LIBRARIES}) + CGAL_target_use_Eigen(CGAL_${IPELET}) if ( IPELET_INSTALL_DIR ) install(TARGETS CGAL_${IPELET} DESTINATION ${IPELET_INSTALL_DIR}) if (WITH_IPE_7) @@ -153,12 +152,13 @@ if ( CGAL_FOUND ) endforeach(IPELET) if(CGAL_Core_FOUND) target_link_libraries(CGAL_cone_spanners PRIVATE CGAL::CGAL_Core) + CGAL_target_use_Eigen(CGAL_cone_spanners) endif() #example in doc not installed add_library(simple_triangulation MODULE simple_triangulation.cpp) add_to_cached_list(CGAL_EXECUTABLE_TARGETS simple_triangulation) target_link_libraries(simple_triangulation ${IPE_LIBRARIES}) - + CGAL_target_use_Eigen(simple_triangulation) cgal_add_compilation_test(simple_triangulation) else() diff --git a/Cartesian_kernel/include/CGAL/Cartesian/Point_2.h b/Cartesian_kernel/include/CGAL/Cartesian/Point_2.h index 92985777bbb..028c772c102 100644 --- a/Cartesian_kernel/include/CGAL/Cartesian/Point_2.h +++ b/Cartesian_kernel/include/CGAL/Cartesian/Point_2.h @@ -50,6 +50,15 @@ public: PointC2(const FT &hx, const FT &hy, const FT &hw) : base(hx, hy, hw) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.base, b.base); + } + const FT& x() const { return base.x(); diff --git a/Cartesian_kernel/include/CGAL/Cartesian/Point_3.h b/Cartesian_kernel/include/CGAL/Cartesian/Point_3.h index 614ec31fcc5..b46ab99284b 100644 --- a/Cartesian_kernel/include/CGAL/Cartesian/Point_3.h +++ b/Cartesian_kernel/include/CGAL/Cartesian/Point_3.h @@ -24,6 +24,7 @@ namespace CGAL { template < class R_ > class PointC3 { + typedef PointC3 Self; typedef typename R_::Vector_3 Vector_3; typedef typename R_::Point_3 Point_3; typedef typename R_::Aff_transformation_3 Aff_transformation_3; @@ -47,6 +48,15 @@ public: PointC3(const FT &x, const FT &y, const FT &z, const FT &w) : base(x, y, z, w) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.base, b.base); + } + const FT & x() const { return base.x(); diff --git a/Cartesian_kernel/include/CGAL/Cartesian/Vector_2.h b/Cartesian_kernel/include/CGAL/Cartesian/Vector_2.h index 6331471dff7..01986b321a3 100644 --- a/Cartesian_kernel/include/CGAL/Cartesian/Vector_2.h +++ b/Cartesian_kernel/include/CGAL/Cartesian/Vector_2.h @@ -27,6 +27,7 @@ namespace CGAL { template < class R_ > class VectorC2 { + typedef VectorC2 Self; typedef typename R_::FT FT; typedef typename R_::Point_2 Point_2; typedef typename R_::Vector_2 Vector_2; @@ -55,6 +56,15 @@ public: : base( hw != FT(1) ? CGAL::make_array(hx/hw, hy/hw) : CGAL::make_array(hx, hy) ) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.base, b.base); + } + const FT & x() const { return CGAL::get_pointee_or_identity(base)[0]; diff --git a/Cartesian_kernel/include/CGAL/Cartesian/Vector_3.h b/Cartesian_kernel/include/CGAL/Cartesian/Vector_3.h index ccad6ad574c..72954931d0b 100644 --- a/Cartesian_kernel/include/CGAL/Cartesian/Vector_3.h +++ b/Cartesian_kernel/include/CGAL/Cartesian/Vector_3.h @@ -27,6 +27,7 @@ template < class R_ > class VectorC3 { // https://doc.cgal.org/latest/Manual/devman_code_format.html#secprogramming_conventions + typedef VectorC3 Self; typedef typename R_::FT FT_; typedef typename R_::Point_3 Point_3; typedef typename R_::Vector_3 Vector_3; @@ -70,6 +71,15 @@ public: : base( w != FT_(1) ? CGAL::make_array(x/w, y/w, z/w) : CGAL::make_array(x, y, z) ) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.base, b.base); + } + const FT_ & x() const { return get_pointee_or_identity(base)[0]; diff --git a/Classification/examples/Classification/CMakeLists.txt b/Classification/examples/Classification/CMakeLists.txt index 79ad8c5bf03..4cdfe2e2c08 100644 --- a/Classification/examples/Classification/CMakeLists.txt +++ b/Classification/examples/Classification/CMakeLists.txt @@ -5,7 +5,6 @@ cmake_minimum_required(VERSION 3.1...3.15) project( Classification_Examples ) - # CGAL and its components find_package( CGAL QUIET COMPONENTS ) @@ -22,127 +21,73 @@ if ( NOT Boost_FOUND ) return() endif() -find_package( Boost OPTIONAL_COMPONENTS serialization iostreams ) +set(Classification_dependencies_met TRUE) -if( WIN32 ) -# to avoid a warning with old cmake - set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp") - set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp") - find_package( Boost OPTIONAL_COMPONENTS bzip2 zlib) -else() - find_package(ZLIB QUIET) +find_package( Boost OPTIONAL_COMPONENTS serialization iostreams ) +if (NOT Boost_SERIALIZATION_FOUND) + message(STATUS "NOTICE: This project requires Boost Serialization, and will not be compiled.") + set(Classification_dependencies_met FALSE) +endif() +if (NOT Boost_IOSTREAMS_FOUND) + message(STATUS "NOTICE: This project requires Boost IO Streams, and will not be compiled.") + set(Classification_dependencies_met FALSE) +endif() + +find_package(OpenCV QUIET COMPONENTS core ml) # Need core + machine learning +if (NOT OpenCV_FOUND) + message(STATUS "NOTICE: OpenCV was not found. OpenCV random forest predicate for classification won't be available.") +endif() + +find_package(TensorFlow QUIET) +if (NOT TensorFlow_FOUND) + message(STATUS "NOTICE: TensorFlow was not found. TensorFlow neural network predicate for classification won't be available.") +endif() + +find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater) +if (NOT EIGEN3_FOUND) + message(STATUS "This project requires the Eigen library, and will not be compiled.") + set(Classification_dependencies_met FALSE) endif() find_package(TBB QUIET) -find_package(OpenCV QUIET COMPONENTS core ml) # Need core + machine learning - -# Use Eigen -find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater) -if (NOT EIGEN3_FOUND) - message(STATUS "This project requires the Eigen library, and will not be compiled.") - return() -else() - include( ${EIGEN3_USE_FILE} ) -endif() - - -# Creating entries for all C++ files with "main" routine -# ########################################################## - -# Classification examples -set(targets - example_classification - example_ethz_random_forest - example_feature - example_generation_and_training - example_mesh_classification - example_cluster_classification) - -# Classification requires some C++11 features -set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates) - -# Libraries and flags -set(classification_linked_libraries) -set(classification_compile_definitions) - - -if (Boost_SERIALIZATION_FOUND AND Boost_IOSTREAMS_FOUND) - if(TARGET Boost::serialization AND TARGET Boost::iostreams) - set(classification_linked_libraries Boost::serialization Boost::iostreams) - else() - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_SERIALIZATION_LIBRARY} - ${Boost_IOSTREAMS_LIBRARY}) - endif() -else() - if (NOT Boost_SERIALIZATION_FOUND) - message(STATUS "NOTICE: This project requires Boost Serialization, and will not be compiled.") - endif() - if (NOT Boost_IOSTREAMS_FOUND) - message(STATUS "NOTICE: This project requires Boost IO Streams, and will not be compiled.") - endif() +if (NOT Classification_dependencies_met) return() endif() -if( WIN32 ) - if (Boost_ZLIB_FOUND AND Boost_BZIP2_FOUND) - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_ZLIB_LIBRARY} ${Boost_BZIP2_LIBRARY}) - else() - message(STATUS "NOTICE: This project requires Boost ZLIB and Boost BZIP2, and will not be compiled.") - return() - endif() -else() - if(ZLIB_FOUND) - set(classification_linked_libraries ${classification_linked_libraries} ZLIB::ZLIB) - else() - message(STATUS "NOTICE: This project requires ZLIB, and will not be compiled.") - return() - endif() -endif() +create_single_source_cgal_program( "example_classification.cpp" ) +create_single_source_cgal_program( "example_ethz_random_forest.cpp" ) +create_single_source_cgal_program( "example_feature.cpp" ) +create_single_source_cgal_program( "example_generation_and_training.cpp" ) +create_single_source_cgal_program( "example_mesh_classification.cpp" ) +create_single_source_cgal_program( "example_cluster_classification.cpp" ) if (OpenCV_FOUND) - message(STATUS "Found OpenCV ${OpenCV_VERSION}") - include_directories(${OpenCV_INCLUDE_DIRS}) - set(classification_linked_libraries ${classification_linked_libraries} - ${OpenCV_LIBS}) - set(classification_compile_definitions ${classification_compile_definitions} - "-DCGAL_LINKED_WITH_OPENCV") - - set(targets ${targets} example_opencv_random_forest) -else() - message(STATUS "NOTICE: OpenCV was not found. OpenCV random forest predicate for classification won't be available.") + create_single_source_cgal_program( "example_opencv_random_forest.cpp" ) + CGAL_target_use_OpenCV(example_opencv_random_forest) endif() -find_package(TensorFlow QUIET) if (TensorFlow_FOUND) - message(STATUS "Found TensorFlow") - include_directories( ${TensorFlow_INCLUDE_DIR} ) - set(classification_linked_libraries ${classification_linked_libraries} - ${TensorFlow_LIBRARY}) - set(classification_compile_definitions ${classification_compile_definitions} - "-DCGAL_LINKED_WITH_TENSORFLOW") - - set(targets ${targets} example_tensorflow_neural_network) -else() - message(STATUS "NOTICE: TensorFlow not found, Neural Network predicate for classification won't be available.") + create_single_source_cgal_program( "example_tensorflow_neural_network.cpp" ) + CGAL_target_use_TensorFlow(example_tensorflow_neural_network) endif() - -# Creating targets with correct libraries and flags -foreach(target ${targets}) - create_single_source_cgal_program( "${target}.cpp" CXX_FEATURES ${needed_cxx_features} ) +foreach(target + example_classification + example_ethz_random_forest + example_feature + example_generation_and_training + example_mesh_classification + example_cluster_classification + example_opencv_random_forest + example_tensorflow_neural_network) if(TARGET ${target}) - target_link_libraries(${target} PUBLIC ${classification_linked_libraries}) - target_compile_definitions(${target} PUBLIC ${classification_compile_definitions}) + CGAL_target_use_Eigen(${target}) + CGAL_target_use_Boost_IOStreams(${target}) + CGAL_target_use_Boost_Serialization(${target}) if(TBB_FOUND) CGAL_target_use_TBB(${target}) endif() endif() endforeach() - - - - diff --git a/Classification/test/Classification/CMakeLists.txt b/Classification/test/Classification/CMakeLists.txt index ae7699281d1..c108ca45a56 100644 --- a/Classification/test/Classification/CMakeLists.txt +++ b/Classification/test/Classification/CMakeLists.txt @@ -5,7 +5,6 @@ cmake_minimum_required(VERSION 3.1...3.15) project( Classification_Tests ) - # CGAL and its components find_package( CGAL QUIET COMPONENTS ) @@ -22,88 +21,39 @@ if ( NOT Boost_FOUND ) return() endif() +set(Classification_dependencies_met TRUE) + find_package( Boost OPTIONAL_COMPONENTS serialization iostreams ) - -if( WIN32 ) -# to avoid a warning with old cmake - set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp") - set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp") - find_package( Boost OPTIONAL_COMPONENTS bzip2 zlib) -else() - find_package(ZLIB QUIET) +if (NOT Boost_SERIALIZATION_FOUND) + message(STATUS "NOTICE: This project requires Boost Serialization, and will not be compiled.") + set(Classification_dependencies_met FALSE) +endif() +if (NOT Boost_IOSTREAMS_FOUND) + message(STATUS "NOTICE: This project requires Boost IO Streams, and will not be compiled.") + set(Classification_dependencies_met FALSE) endif() -# Use Eigen -find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) +find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater) +if (NOT EIGEN3_FOUND) + message(STATUS "This project requires the Eigen library, and will not be compiled.") + set(Classification_dependencies_met FALSE) endif() -find_package( TBB ) +find_package(TBB QUIET) -# include for local directory -include_directories( BEFORE include ) - -# include for local package - -# Creating entries for all C++ files with "main" routine -# ########################################################## - -#add_definitions("-DCGAL_DO_NOT_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE") - -# Classification requires some C++11 features -set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates) - -# Libraries and flags -set(classification_linked_libraries) - -if (Boost_SERIALIZATION_FOUND AND Boost_IOSTREAMS_FOUND) - if(TARGET Boost::serialization AND TARGET Boost::iostreams) - set(classification_linked_libraries Boost::serialization Boost::iostreams) - else() - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_SERIALIZATION_LIBRARY} - ${Boost_IOSTREAMS_LIBRARY}) - endif() -else() - if (NOT Boost_SERIALIZATION_FOUND) - message(STATUS "NOTICE: This project requires Boost Serialization, and will not be compiled.") - endif() - if (NOT Boost_IOSTREAMS_FOUND) - message(STATUS "NOTICE: This project requires Boost IO Streams, and will not be compiled.") - endif() +if (NOT Classification_dependencies_met) return() endif() -if( WIN32 ) - if (Boost_ZLIB_FOUND AND Boost_BZIP2_FOUND) - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_ZLIB_LIBRARY} ${Boost_BZIP2_LIBRARY}) - else() - message(STATUS "NOTICE: This project requires Boost ZLIB and Boost BZIP2, and will not be compiled.") - return() - endif() -else() - if(ZLIB_FOUND) - set(classification_linked_libraries ${classification_linked_libraries} ZLIB::ZLIB) - else() - message(STATUS "NOTICE: This project requires ZLIB, and will not be compiled.") - return() - endif() -endif() +create_single_source_cgal_program( "test_classification_point_set.cpp" ) +create_single_source_cgal_program( "test_classification_io.cpp" ) -create_single_source_cgal_program( "test_classification_point_set.cpp" CXX_FEATURES ${needed_cxx_features} ) -if(TARGET test_classification_point_set) - target_link_libraries(test_classification_point_set PUBLIC ${classification_linked_libraries}) - if (TBB_FOUND) - CGAL_target_use_TBB( test_classification_point_set ) +foreach(target test_classification_point_set test_classification_io) + CGAL_target_use_Eigen(${target}) + CGAL_target_use_Boost_IOStreams(${target}) + CGAL_target_use_Boost_Serialization(${target}) + if(TBB_FOUND) + CGAL_target_use_TBB(${target}) endif() -endif() +endforeach() -create_single_source_cgal_program( "test_classification_io.cpp" CXX_FEATURES ${needed_cxx_features} ) -if(TARGET test_classification_io) - target_link_libraries(test_classification_io PUBLIC ${classification_linked_libraries}) - if (TBB_FOUND) - CGAL_target_use_TBB( test_classification_io ) - endif() -endif() diff --git a/Convex_hull_3/doc/Convex_hull_3/CGAL/convex_hull_3.h b/Convex_hull_3/doc/Convex_hull_3/CGAL/convex_hull_3.h index bc83e1d13a0..78e5d46a00f 100644 --- a/Convex_hull_3/doc/Convex_hull_3/CGAL/convex_hull_3.h +++ b/Convex_hull_3/doc/Convex_hull_3/CGAL/convex_hull_3.h @@ -21,7 +21,7 @@ is a kernel with exact predicates but inexact constructions (in practice we check `R::Has_filtered_predicates_tag` is `Tag_true` and `R::FT` is a floating point type), then the default traits class of `::convex_hull_3()` is `Convex_hull_traits_3`, and `R` otherwise. -\attention The user must include the header file of the `Polygon_mesh` type. +\attention The user must include the header file of the `PolygonMesh` type. \cgalHeading{Implementation} @@ -34,6 +34,36 @@ Barnard et al. \cgalCite{bdh-qach-96}. template void convex_hull_3(InputIterator first, InputIterator last, PolygonMesh& pm, const Traits& ch_traits = Default_traits); + +/*! +\ingroup PkgConvexHull3Functions + * \brief computes the convex hull of the points associated to the vertices of `g`. + * The polygon mesh `pm` is cleared, then + * the convex hull is stored in `pm`. Note that the convex hull will be triangulated, + * that is `pm` will contain only triangular faces. + * if the convex hull is a point or a segment, endpoints will be added in `pm` as isolated vertices. + * + * \tparam VertexListGraph a model of `VertexListGraph`. + * \tparam PolygonMesh must be a model of `MutableFaceGraph`. + * \tparam NamedParameters a sequence of named parameters + * + * \param g the graph + * \param pm the `PolygonMesh` that will contain the convex hull + * \param np optional sequence of named parameters among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `g`. + * If this parameter is omitted, an internal property map for + * `CGAL::vertex_point_t` must be available in `VertexListGraph` + * \cgalParamEnd +* \cgalNamedParamsEnd + * \attention The user must include the header file of the `PolygonMesh` and `VertexListGraph` types. + */ +template +void convex_hull_3(const VertexListGraph& g, + PolygonMesh& pm, + const NamedParameters& np); + /*! \ingroup PkgConvexHull3Functions @@ -47,7 +77,7 @@ that is the polygon mesh will contain only triangular facets. \tparam Traits must be model of the concept `ConvexHullTraits_3`. For the purposes of checking the postcondition that the convex hull is valid, `Traits` must also be a model of the concept -`IsStronglyConvexTraits_3`. Furthermore, `Traits` must define a type `Polygon_mesh` that is a model of +`IsStronglyConvexTraits_3`. Furthermore, `Traits` must define a type `PolygonMesh` that is a model of `MutableFaceGraph`. If the kernel `R` of the points determined by the value type of `InputIterator` @@ -55,7 +85,7 @@ is a kernel with exact predicates but inexact constructions (in practice we check `R::Has_filtered_predicates_tag` is `Tag_true` and `R::FT` is a floating point type), then the default traits class of `convex_hull_3()` is `Convex_hull_traits_3`, and `R` otherwise. -\attention The user must include the header file of the `Polygon_mesh` type. +\attention The user must include the header file of the `PolygonMesh` type. */ template diff --git a/Convex_hull_3/doc/Convex_hull_3/Doxyfile.in b/Convex_hull_3/doc/Convex_hull_3/Doxyfile.in index a114b807a2b..860593ed992 100644 --- a/Convex_hull_3/doc/Convex_hull_3/Doxyfile.in +++ b/Convex_hull_3/doc/Convex_hull_3/Doxyfile.in @@ -1,3 +1,9 @@ @INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Convex Hulls" + +\# macros to be used inside the code +ALIASES += "cgalNamedParamsBegin=

Named Parameters
" +ALIASES += "cgalNamedParamsEnd=
" +ALIASES += "cgalParamBegin{1}=\ref BGL_\1 \"\1\"" +ALIASES += "cgalParamEnd=" diff --git a/Convex_hull_3/examples/Convex_hull_3/CMakeLists.txt b/Convex_hull_3/examples/Convex_hull_3/CMakeLists.txt index 18d983da969..a5b3583a751 100644 --- a/Convex_hull_3/examples/Convex_hull_3/CMakeLists.txt +++ b/Convex_hull_3/examples/Convex_hull_3/CMakeLists.txt @@ -54,6 +54,9 @@ create_single_source_cgal_program( "lloyd_algorithm.cpp" ) create_single_source_cgal_program( "quickhull_3.cpp" ) +create_single_source_cgal_program( "graph_hull_3.cpp" ) + + create_single_source_cgal_program( "quickhull_any_dim_3.cpp" ) create_single_source_cgal_program( "extreme_points_3_sm.cpp" ) diff --git a/Convex_hull_3/examples/Convex_hull_3/graph_hull_3.cpp b/Convex_hull_3/examples/Convex_hull_3/graph_hull_3.cpp new file mode 100644 index 00000000000..1769315fe5b --- /dev/null +++ b/Convex_hull_3/examples/Convex_hull_3/graph_hull_3.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::Point_3 Point_3; +typedef CGAL::Surface_mesh Surface_mesh; + + +int main(int argc, char* argv[]) +{ + std::ifstream in( (argc>1)? argv[1] : "data/star.off"); + + Surface_mesh poly; + if(!(in >> poly)) + { + std::cerr<<"Could not find input file."< #include #include +#include #include #include #include @@ -49,6 +50,9 @@ #include #include #include +#include +#include +#include #include @@ -1036,7 +1040,10 @@ void convex_hull_3(InputIterator first, InputIterator beyond, template void convex_hull_3(InputIterator first, InputIterator beyond, - Polyhedron_3& polyhedron) + Polyhedron_3& polyhedron, + typename std::enable_if< + CGAL::is_iterator::value + >::type* =0) //workaround to avoid ambiguity with next overload. { typedef typename std::iterator_traits::value_type Point_3; typedef typename internal::Convex_hull_3::Default_traits_for_Chull_3::type Traits; @@ -1044,6 +1051,29 @@ void convex_hull_3(InputIterator first, InputIterator beyond, } +template +void convex_hull_3(const VertexListGraph& g, + PolygonMesh& pm, + const NamedParameters& np) +{ + typedef typename GetVertexPointMap::const_type Vpmap; + typedef CGAL::Property_map_to_unary_function Vpmap_fct; + Vpmap vpm = CGAL::parameters::choose_parameter( + CGAL::parameters::get_parameter(np, internal_np::vertex_point), + get_const_property_map(boost::vertex_point, g)); + + Vpmap_fct v2p(vpm); + convex_hull_3(boost::make_transform_iterator(vertices(g).begin(), v2p), + boost::make_transform_iterator(vertices(g).end(), v2p), pm); +} + +template +void convex_hull_3(const VertexListGraph& g, + PolygonMesh& pm) +{ + convex_hull_3(g,pm,CGAL::parameters::all_default()); +} + template OutputIterator extreme_points_3(const InputRange& range, diff --git a/Convex_hull_3/test/Convex_hull_3/test_ch_3_ambiguity.cpp b/Convex_hull_3/test/Convex_hull_3/test_ch_3_ambiguity.cpp new file mode 100644 index 00000000000..0b67fa73bdc --- /dev/null +++ b/Convex_hull_3/test/Convex_hull_3/test_ch_3_ambiguity.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Polyhedron_3 Polyhedron_3; +typedef K::Point_3 Point_3; +typedef CGAL::Surface_mesh Surface_mesh; + + +int main(int argc, char* argv[]) +{ + std::ifstream in( (argc>1)? argv[1] : "data/cross.off"); + + Surface_mesh poly; + if(!in || !(in >> poly)) + { + std::cerr<<"Could not find a correct input file."<Package Overview page. +In \cgal, \sc{Eigen} is used in many packages such as \ref +PkgPoissonSurfaceReconstruction3 or \ref PkgJetFitting3, providing +sparse linear solvers and singular value decompositions. A package +dependency over \sc{Eigen} is marked on the Package +Overview page. In order to use Eigen in \cgal programs, the +provided CMake function `CGAL_target_use_Eigen()` should be +used. The \sc{Eigen} web site is `http://eigen.tuxfamily.org`. @@ -194,7 +198,9 @@ It can be downloaded from `http://esbtl. \sc{Tbb} (Threading Building Blocks) is a library developed by Intel Corporation for writing software programs that take advantage of multi-core processors. -In \cgal, \sc{Tbb} is used by the packages that offer parallel code. +In \cgal, \sc{Tbb} is used by the packages that offer parallel +code. In order to use \sc{Tbb} in \cgal programs, the provided CMake +function `CGAL_target_use_TBB()` should be used. The \sc{Tbb} web site is `https://www.threadingbuildingblocks.org`. @@ -204,7 +210,9 @@ The \sc{Tbb} web site is `http the LAS format (or the compressed LAZ format). In \cgal, \sc{LASlib} is used to provide input and output functions in -the \ref PkgPointSetProcessing3 package. +the \ref PkgPointSetProcessing3 package. In order to use \sc{LASlib} in +\cgal programs, the provided CMake function +`CGAL_target_use_LASLIB()` should be used. The \sc{LASlib} web site is `https://rapidlasso.com/lastools/`. \sc{LASlib} @@ -217,7 +225,9 @@ CMake based install procedure. \sc{OpenCV} (Open Computer Vision) is a library designed for computer vision, computer graphics and machine learning. -In \cgal, \sc{OpenCV} is used by the \ref PkgClassification package. +In \cgal, \sc{OpenCV} is used by the \ref PkgClassification +package. In order to use \sc{OpenCV} in \cgal programs, the provided +CMake function `CGAL_target_use_OpenCV()` should be used. The \sc{OpenCV} web site is `https://opencv.org/`. @@ -235,6 +245,9 @@ enable and compile the following targets: - `tensorflow_BUILD_PYTHON_BINDINGS` - `tensorflow_BUILD_SHARED_LIB`. +In order to use \sc{TensorFlow} in \cgal programs, the provided CMake +function `CGAL_target_use_TensorFlow()` should be used. + The \sc{TensorFlow} web site is `https://www.tensorflow.org/`. \subsection thirdpartyMETIS METIS @@ -274,7 +287,10 @@ for more information. \sc{GLPK} (GNU Linear Programming Kit) is a library for solving linear programming (LP), mixed integer programming (MIP), and other related problems. -In \cgal, \sc{GLPK} provides an optional linear integer program solver in the \ref PkgPolygonalSurfaceReconstruction package. +In \cgal, \sc{GLPK} provides an optional linear integer program solver +in the \ref PkgPolygonalSurfaceReconstruction package. In order to use +\sc{GLPK} in \cgal programs, the provided CMake function +`CGAL_target_use_GLPK()` should be used. The \sc{GLPK} web site is `https://www.gnu.org/software/glpk/`. @@ -282,7 +298,10 @@ The \sc{GLPK} web site is `https:// \sc{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, \sc{SCIP} provides an optional linear integer program solver in the \ref PkgPolygonalSurfaceReconstruction package. +In \cgal, \sc{SCIP} provides an optional linear integer program solver +in the \ref PkgPolygonalSurfaceReconstruction package. In order to use +\sc{SCIP} in \cgal programs, the provided CMake function +`CGAL_target_use_SCIP()` should be used. The \sc{SCIP} web site is `http://scip.zib.de/`. diff --git a/Documentation/doc/Documentation/Usage.txt b/Documentation/doc/Documentation/Usage.txt index b1a21d4c121..38d2b257697 100644 --- a/Documentation/doc/Documentation/Usage.txt +++ b/Documentation/doc/Documentation/Usage.txt @@ -60,6 +60,12 @@ On most operating systems, package managers offer \cgal and its essential third On macOS, we recommend using of Homebrew in the following way: brew install cgal + brew install cgal-qt5 #(only for GUI) + +You should check that cgal and cgal-qt5 are correctly "linked", especially when upgrading from an old version. If not, run the following command: + + brew link cgal + brew link cgal-qt5 #(if you installed it) On Linux distributions such as `Debian`/`Ubuntu`/`Mint`, use `apt-get` in the following way: @@ -148,10 +154,14 @@ The variable `CGAL_DIR` is also generally found when \cgal has been obtained via In the rare event that it has not, the variable `CGAL_DIR` should be set manually to:
    -
  • something like `/usr/local/Cellar/cgal/CGAL-\cgalReleaseNumber/lib/cmake/CGAL`, for Brew.
  • +
  • something like `/usr/local/opt/cgal/lib/cmake/CGAL`, for Brew.
  • something like `/usr/lib/x86_64-linux-gnu/cmake/CGAL`, for Linux distributions.
+Note that you can also use `CMAKE_PREFIX_PATH` to point to a directory that contains all dependencies, like so: + + cmake -DCMAKE_PREFIX_PATH=/my/custom/brew/installation/dir -DCMAKE_BUILD_TYPE=Release . + If \cgal has been obtained via other means, `CGAL_DIR` must point to the root directory of the \cgal source code (either the root of the unpacked release tarball or the root of the Git working directory). @@ -162,6 +172,13 @@ if no debugging is intended. Users should thus run: cd CGAL-\cgalReleaseNumber/examples/Triangulation_2 cmake -DCGAL_DIR=$HOME/CGAL-\cgalReleaseNumber -DCMAKE_BUILD_TYPE=Release . # we are here using a release tarball +Note that the package Qt on brew is "keg-only", which means it cannot be "linked" with brew. +You will have to specify the Qt5_DIR by hand to cmake, using something like + + -DQt5_DIR=/usr/local/opt/qt/lib/cmake/Qt5 + +where '/usr/local/` is actually your current brew installation directory. + \subsection usage_configuring_cmake_gui Specifying Missing Dependencies The configuration process launched above might fail if CMake fails to find diff --git a/Documentation/doc/Documentation/advanced/Configuration_variables.txt b/Documentation/doc/Documentation/advanced/Configuration_variables.txt index 1bebdc5ddd7..2a880f1e488 100644 --- a/Documentation/doc/Documentation/advanced/Configuration_variables.txt +++ b/Documentation/doc/Documentation/advanced/Configuration_variables.txt @@ -85,6 +85,7 @@ and will serverly limit performances. | Variable | Description | Type | %Default Value | | :- | :- | :- | :- | | `CGAL_DIR` | Full-path to the binary directory where \cgal was configured |Either CMake or Environment | none | +| `Qt5_DIR` | Full-path to the Qt cmake directory |CMake| platform-dependent| \subsection installation_variables_third_party Variables Providing Information About 3rd-Party Libraries @@ -300,6 +301,20 @@ environment variable is sufficient. | `ESBTL_INC_DIR` | Directory containing the `ESBTL/default.h` file | Environment | | `ESBTL_INCLUDE_DIR` | Directory containing the `ESBTL/default.h` file | CMake | +\subsection installation_metis METIS Library + +Some BGL examples require the \sc{Metis} library in order to partition \sc{Metis} meshes. + +If \sc{Metis} is not automatically found, setting the `METIS_INCLUDE_DIR` and `METIS_LIBRARY` +cmake variables is necessary. + + +| Variable | Description | Type | +| :- | :- | :- | +| `METIS_INCLUDE_DIR` | Directory of \sc{Metis} default installation | CMAKE | +| `METIS_LIBRARY` | Directory containing the `libmetis.so or .lib` file | CMAKE | + + \subsection installation_tbb TBB Library If \sc{Tbb} is not automatically found, the user must set the `TBB_ROOT` @@ -324,6 +339,44 @@ Note that the variables in the table below are being used. | `TBB_MALLOCPROXY_DEBUG_LIBRARY` | Full pathname of the compiled TBB debug malloc_proxy library (optional) | CMake | | `TBB_MALLOCPROXY_RELEASE_LIBRARY` | Full pathname of the compiled TBB release malloc_proxy library (optional) | CMake | +\subsection installation_laslib LASlib library + +If LASLIB is not automatically found, the following variables must be set: + +| Variable | Description | Type | +| :- | :- | :- | +| `LASLIB_INCLUDE_DIR` | Directory containing the file `lasreader.hpp` | CMake | +| `LASZIP_INCLUDE_DIR` | Directory containing the file `mydefs.hpp` | CMake | +| `LASLIB_LIBRARIES` | Full pathname of the compiled LASLIB library | CMake | + +\subsection installation_OpenCV OpenCV library + +The environment variable `OPENCV_DIR` should be set to the directory +containing the file `OpenCVConfig.cmake` provided by OpenCV. + +\subsection installation_TensorFlow TensorFlow library + +If TensorFlow is not automatically found, the following variables must be set: + +| Variable | Description | Type | +| :- | :- | :- | +| `TensorFlow_INCLUDE_DIR` | Directory containing the directories `tensorflow/core`, `tensorflow/cc`, etc. | CMake | +| `TensorFlow_LIBRARY` | Full pathname of the compiled TensorFlow C++ library | CMake | + +\subsection installation_SCIP SCIP library + +The environment variable `SCIP_DIR` should be set to the directory +containing the file `scip-config.cmake` provided by SCIP. + +\subsection installation_GLPK GLPK library + +If GLPK is not automatically found, the following variables must be set: + +| Variable | Description | Type | +| :- | :- | :- | +| `GLPK_INCLUDE_DIR` | Directory containing the file `glpk.h` | CMake | +| `GLPK_LIBRARIES` | Full pathname of the compiled GLPK library | CMake | + \section installation_compiler_workarounds Compiler Workarounds A number of boolean flags are used to workaround compiler bugs and diff --git a/Documentation/doc/Documentation/windows.txt b/Documentation/doc/Documentation/windows.txt index ca37e021001..c123b537496 100644 --- a/Documentation/doc/Documentation/windows.txt +++ b/Documentation/doc/Documentation/windows.txt @@ -37,8 +37,8 @@ The first step is to clone or download `vcpkg` from By default `vcpkg` installs for 32 bit binaries and will use the latest version of Visual C++ installed on your machine. If you develop 64 bit software you must -set the Windows environment variable `VCPKG_DEFAULT_TRIPLE` to `x64-windows` -or pass the option `--triplet x64-windows` whenever you install a package. +set the Windows environment variable `VCPKG_DEFAULT_TRIPLET` to `x64-windows` +or add the suffix `:x64-windows` to the package name you want to install (for example `cgal:x64-windows`). We refer to the official documentation of `vcpkg` if you want to compile for an older version of a compiler. diff --git a/Documentation/doc/resources/1.8.13/menu_version.js b/Documentation/doc/resources/1.8.13/menu_version.js index 03ad8f3fbd0..36b298ee045 100644 --- a/Documentation/doc/resources/1.8.13/menu_version.js +++ b/Documentation/doc/resources/1.8.13/menu_version.js @@ -3,12 +3,12 @@ var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(master|latest|(\d\.\d+|\d\.\d+\.\d+))\//; var url_local = /.*\/doc_output\//; - var current_version_local = '5.0.1' + var current_version_local = '5.1-dev' var all_versions = [ 'master', 'latest', - '5.0.1', - '4.14.2', + '5.0.2', + '4.14.3', '4.13.2', '4.12.2', '4.11.3', diff --git a/Documentation/doc/resources/1.8.14/menu_version.js b/Documentation/doc/resources/1.8.14/menu_version.js index 03ad8f3fbd0..36b298ee045 100644 --- a/Documentation/doc/resources/1.8.14/menu_version.js +++ b/Documentation/doc/resources/1.8.14/menu_version.js @@ -3,12 +3,12 @@ var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(master|latest|(\d\.\d+|\d\.\d+\.\d+))\//; var url_local = /.*\/doc_output\//; - var current_version_local = '5.0.1' + var current_version_local = '5.1-dev' var all_versions = [ 'master', 'latest', - '5.0.1', - '4.14.2', + '5.0.2', + '4.14.3', '4.13.2', '4.12.2', '4.11.3', diff --git a/Documentation/doc/resources/1.8.4/menu_version.js b/Documentation/doc/resources/1.8.4/menu_version.js index 03ad8f3fbd0..36b298ee045 100644 --- a/Documentation/doc/resources/1.8.4/menu_version.js +++ b/Documentation/doc/resources/1.8.4/menu_version.js @@ -3,12 +3,12 @@ var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(master|latest|(\d\.\d+|\d\.\d+\.\d+))\//; var url_local = /.*\/doc_output\//; - var current_version_local = '5.0.1' + var current_version_local = '5.1-dev' var all_versions = [ 'master', 'latest', - '5.0.1', - '4.14.2', + '5.0.2', + '4.14.3', '4.13.2', '4.12.2', '4.11.3', diff --git a/Filtered_kernel/include/CGAL/Kernel_profiler.h b/Filtered_kernel/include/CGAL/Kernel_profiler.h index 9a55a12ea13..d592de79fc9 100644 --- a/Filtered_kernel/include/CGAL/Kernel_profiler.h +++ b/Filtered_kernel/include/CGAL/Kernel_profiler.h @@ -34,77 +34,13 @@ struct Primitive_profiler Primitive_profiler(const P& p = P()) : P(p) {} - template + template result_type - operator()(const A1 &a1) const + operator()(A&& ... a) const { CGAL_KERNEL_PROFILER; - return P::operator()(a1); + return P::operator()(std::forward(a)...); } - - template - result_type - operator()(const A1 &a1, const A2 &a2) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3, a4); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3, a4, a5); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3, a4, a5, a6); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6, const A7 &a7) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3, a4, a5, a6, a7); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6, const A7 &a7, const A8 &a8) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3, a4, a5, a6, a7, a8); - } - - // ... }; // We inherit all geometric objects from K, and just replace the primitives. diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 2a887d57b48..dd3616d4a7e 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -731,6 +731,9 @@ public : PTR = new Lazy_rep_0(std::move(e)); } + friend void swap(Lazy& a, Lazy& b) noexcept + { swap(static_cast(a), static_cast(b)); } + const AT& approx() const { return ptr()->approx(); } diff --git a/Generator/examples/Generator/CMakeLists.txt b/Generator/examples/Generator/CMakeLists.txt index 8ef7883800d..0fa1a97db40 100644 --- a/Generator/examples/Generator/CMakeLists.txt +++ b/Generator/examples/Generator/CMakeLists.txt @@ -12,9 +12,6 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() # create a target per cppfile file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) @@ -23,6 +20,10 @@ if ( CGAL_FOUND ) OR NOT (${cppfile} STREQUAL "random_points_on_tetrahedral_mesh_3.cpp") OR EIGEN3_FOUND) create_single_source_cgal_program( "${cppfile}" ) + if (EIGEN3_FOUND) + get_filename_component(target ${cppfile} NAME_WE) + CGAL_target_use_Eigen(${target}) + endif() endif() endforeach() diff --git a/Generator/test/Generator/CMakeLists.txt b/Generator/test/Generator/CMakeLists.txt index 8842178b20b..0eb1657d2a9 100644 --- a/Generator/test/Generator/CMakeLists.txt +++ b/Generator/test/Generator/CMakeLists.txt @@ -12,15 +12,16 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() # create a target per cppfile file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) if(NOT (${cppfile} STREQUAL "generic_random_test.cpp") OR EIGEN3_FOUND) create_single_source_cgal_program( "${cppfile}" ) + if (EIGEN3_FOUND) + get_filename_component(target ${cppfile} NAME_WE) + CGAL_target_use_Eigen(${target}) + endif() endif() endforeach() diff --git a/GraphicsView/demo/Polygon/CMakeLists.txt b/GraphicsView/demo/Polygon/CMakeLists.txt index 8d0df276e19..1a84a55e34a 100644 --- a/GraphicsView/demo/Polygon/CMakeLists.txt +++ b/GraphicsView/demo/Polygon/CMakeLists.txt @@ -16,9 +16,7 @@ endif() find_package(CGAL COMPONENTS Qt5 Core) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -else() +if (NOT EIGEN3_FOUND) message(STATUS "NOTICE: This project requires the Eigen library, and will not be compiled.") return() endif() @@ -48,6 +46,7 @@ if ( CGAL_FOUND AND CGAL_Qt5_FOUND AND Qt5_FOUND ) # The executable itself. add_executable ( Polygon_2 Polygon_2.cpp ${DT_UI_FILES} ${DT_RESOURCE_FILES} ${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES} ) + CGAL_target_use_Eigen(Polygon_2) add_to_cached_list( CGAL_EXECUTABLE_TARGETS Polygon_2 ) diff --git a/GraphicsView/src/CGAL_Qt5/CMakeLists.txt b/GraphicsView/src/CGAL_Qt5/CMakeLists.txt index 224de8bbe4b..c9ab3d99241 100644 --- a/GraphicsView/src/CGAL_Qt5/CMakeLists.txt +++ b/GraphicsView/src/CGAL_Qt5/CMakeLists.txt @@ -31,8 +31,8 @@ if(COMMAND add_config_flag) add_config_flag( CGAL_HAS_QT5 ) endif() +install(DIRECTORY "../../include/CGAL/Qt/" DESTINATION "${CGAL_INSTALL_INC_DIR}/CGAL/Qt" COMPONENT CGAL_Qt5) if (CGAL_HEADER_ONLY) - install(DIRECTORY "../../include/CGAL/Qt/" DESTINATION "${CGAL_INSTALL_INC_DIR}/CGAL/include/CGAL/Qt" COMPONENT CGAL_Qt5) install(DIRECTORY "../../demo/resources/" DESTINATION "${CGAL_INSTALL_CMAKE_DIR}/demo/resources" COMPONENT CGAL_Qt5) install(DIRECTORY "../../demo/icons/" DESTINATION "${CGAL_INSTALL_CMAKE_DIR}/demo/icons" COMPONENT CGAL_Qt5) endif() diff --git a/Heat_method_3/examples/Heat_method_3/CMakeLists.txt b/Heat_method_3/examples/Heat_method_3/CMakeLists.txt index ee40274e08e..f9703071b81 100644 --- a/Heat_method_3/examples/Heat_method_3/CMakeLists.txt +++ b/Heat_method_3/examples/Heat_method_3/CMakeLists.txt @@ -34,11 +34,8 @@ endif() find_package(Eigen3 3.3.0) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -else() +if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library (3.3 or greater), and will not be compiled.") - return() endif() @@ -54,6 +51,10 @@ include_directories( BEFORE include ) include( CGAL_CreateSingleSourceCGALProgram ) create_single_source_cgal_program( "heat_method.cpp" ) +CGAL_target_use_Eigen(heat_method) create_single_source_cgal_program( "heat_method_polyhedron.cpp" ) +CGAL_target_use_Eigen(heat_method_polyhedron) create_single_source_cgal_program( "heat_method_surface_mesh.cpp" ) +CGAL_target_use_Eigen(heat_method_surface_mesh) create_single_source_cgal_program( "heat_method_surface_mesh_direct.cpp" ) +CGAL_target_use_Eigen(heat_method_surface_mesh_direct) diff --git a/Heat_method_3/test/Heat_method_3/CMakeLists.txt b/Heat_method_3/test/Heat_method_3/CMakeLists.txt index adb6cfa80c0..af4fd6eb470 100644 --- a/Heat_method_3/test/Heat_method_3/CMakeLists.txt +++ b/Heat_method_3/test/Heat_method_3/CMakeLists.txt @@ -34,11 +34,8 @@ endif() find_package(Eigen3 3.3.0) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -else() +if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library (3.3 or greater), and will not be compiled.") - return() endif() @@ -52,5 +49,8 @@ include_directories( BEFORE include ) include( CGAL_CreateSingleSourceCGALProgram ) create_single_source_cgal_program( "heat_method_concept.cpp" ) +CGAL_target_use_Eigen(heat_method_concept) create_single_source_cgal_program( "heat_method_surface_mesh_test.cpp" ) +CGAL_target_use_Eigen(heat_method_surface_mesh_test) create_single_source_cgal_program( "heat_method_surface_mesh_direct_test.cpp" ) +CGAL_target_use_Eigen(heat_method_surface_mesh_direct_test) diff --git a/INSTALL.md b/INSTALL.md index c2c9526c05e..50f7a3d3e8c 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -8,7 +8,7 @@ git clone https://github.com/CGAL/cgal.git /path/to/cgal.git cd /path/to/cgal.git/Triangulation_2/examples/Triangulation_2 mkdir -p build/debug cd build/debug -cmake -DCMAKE_BUILD_TYPE=Debug -DCGAL_DIR=/path/to/cgal.git +cmake -DCMAKE_BUILD_TYPE=Debug -DCGAL_DIR=/path/to/cgal.git ../.. make ``` diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 2e87bd47f28..642b1be4140 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -21,6 +21,10 @@ Release date: June 2020 ### Intersecting Sequences of dD Iso-oriented Boxes - Added parallel versions of the functions `CGAL::box_intersection_d()` and `CGAL::box_self_intersection_d()`. +### CGAL and the Boost Graph Library (BGL) + - Introduced the function `set_triangulation_ids(Triangulation& tr)` which must be used to initialize vertex, + edge, and face indices of a triangulation meant to be used with BGL algorithms. + ### Polygon Mesh Processing - Introduced a new function, `CGAL::Polygon_mesh_processing::remove_connected_components_of_negligible_size()`, @@ -91,6 +95,11 @@ Release date: June 2020 ### STL Extensions for CGAL - Added a new concurrency tag: `CGAL::Parallel_if_available_tag`. This tag is a convenience typedef to `CGAL::Parallel_tag` if the third party library TBB has been found and linked with, and to `CGAL::Sequential_tag` otherwise. + + +### Convex_hull_3 +- A new overload for `convex_hull_3()` that takes a model of `VertexListGraph` has been added. + [Release 5.0](https://github.com/CGAL/cgal/releases/tag/releases%2FCGAL-5.0) ----------- diff --git a/Installation/CMakeLists.txt b/Installation/CMakeLists.txt index c96b2b9af03..4b5aaa2f173 100644 --- a/Installation/CMakeLists.txt +++ b/Installation/CMakeLists.txt @@ -882,11 +882,11 @@ endif() foreach (dir ${CGAL_CONFIGURED_PACKAGES}) if (EXISTS ${dir}/include/CGAL) - install(DIRECTORY ${dir}/include/CGAL DESTINATION ${CGAL_INSTALL_INC_DIR} PATTERN ".svn" EXCLUDE) + install(DIRECTORY ${dir}/include/CGAL DESTINATION ${CGAL_INSTALL_INC_DIR} PATTERN ".svn" EXCLUDE PATTERN "Qt" EXCLUDE) endif() endforeach() if(EXISTS ${CMAKE_BINARY_DIR}/include/CGAL) - install(DIRECTORY ${CMAKE_BINARY_DIR}/include/CGAL DESTINATION ${CGAL_INSTALL_INC_DIR} PATTERN ".svn" EXCLUDE) + install(DIRECTORY ${CMAKE_BINARY_DIR}/include/CGAL DESTINATION ${CGAL_INSTALL_INC_DIR} PATTERN ".svn" EXCLUDE PATTERN "Qt" EXCLUDE) endif() file(GLOB scripts "scripts/*") diff --git a/Installation/cmake/modules/CGAL_Common.cmake b/Installation/cmake/modules/CGAL_Common.cmake index 51967d5f6d5..4ba76b468b9 100644 --- a/Installation/cmake/modules/CGAL_Common.cmake +++ b/Installation/cmake/modules/CGAL_Common.cmake @@ -56,10 +56,13 @@ if( NOT CGAL_COMMON_FILE_INCLUDED ) endif() endif() - # set minimal version of some optional libraries: - set( Eigen3_FIND_VERSION "3.1.0") - # set use-file for Eigen3 (needed to have default solvers) - set(EIGEN3_USE_FILE "UseEigen3") - + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_Boost_IOStreams.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_Boost_Serialization.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_Eigen.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_GLPK.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_LASLIB.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_OpenCV.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_SCIP.cmake) include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_TBB.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_TensorFlow.cmake) endif() diff --git a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake index f0a2f7c3ea3..9125a477c93 100644 --- a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake +++ b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake @@ -119,12 +119,23 @@ function(CGAL_setup_CGAL_dependencies target) # Now setup compilation flags if(MSVC) target_compile_options(${target} ${keyword} - "-D_SCL_SECURE_NO_DEPRECATE;-D_SCL_SECURE_NO_WARNINGS" - "/fp:strict" - "/fp:except-" - "/wd4503" # Suppress warnings C4503 about "decorated name length exceeded" - "/bigobj" # Use /bigobj by default - ) + "-D_SCL_SECURE_NO_DEPRECATE;-D_SCL_SECURE_NO_WARNINGS") + if(CMAKE_VERSION VERSION_LESS 3.11) + target_compile_options(${target} ${keyword} + /fp:strict + /fp:except- + /wd4503 # Suppress warnings C4503 about "decorated name length exceeded" + /bigobj # Use /bigobj by default + ) + else() + # The MSVC generator supports `$` since CMake 3.11. + target_compile_options(${target} ${keyword} + $<$:/fp:strict> + $<$:/fp:except-> + $<$:/wd4503> # Suppress warnings C4503 about "decorated name length exceeded" + $<$:/bigobj> # Use /bigobj by default + ) + endif() elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") message( STATUS "Using Intel Compiler. Adding -fp-model strict" ) if(WIN32) diff --git a/Installation/cmake/modules/CGAL_target_use_Boost_IOStreams.cmake b/Installation/cmake/modules/CGAL_target_use_Boost_IOStreams.cmake new file mode 100644 index 00000000000..d57f785d54f --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_Boost_IOStreams.cmake @@ -0,0 +1,39 @@ +if (CGAL_target_use_Boost_IOStreams_included) + return() +endif() +set(CGAL_target_use_Boost_IOStreams_included TRUE) + +function(CGAL_target_use_Boost_IOStreams target) + + if( WIN32 ) + # to avoid a warning with old cmake + set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp") + set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp") + find_package( Boost OPTIONAL_COMPONENTS bzip2 zlib) + else() + find_package(ZLIB QUIET) + endif() + + if(TARGET Boost::iostreams) + target_link_libraries(${target} PUBLIC Boost::iostreams) + else() + target_link_libraries(${target} PUBLIC ${Boost_IOSTREAMS_LIBRARY}) + endif() + + if( WIN32 ) + if (Boost_ZLIB_FOUND AND Boost_BZIP2_FOUND) + target_link_libraries(${target} PUBLIC ${Boost_ZLIB_LIBRARY} ${Boost_BZIP2_LIBRARY}) + else() + message(STATUS "NOTICE: This project requires Boost ZLIB and Boost BZIP2, and will not be compiled.") + return() + endif() + else() + if(ZLIB_FOUND) + target_link_libraries(${target} PUBLIC ZLIB::ZLIB) + else() + message(STATUS "NOTICE: This project requires ZLIB, and will not be compiled.") + return() + endif() + endif() + +endfunction() diff --git a/Installation/cmake/modules/CGAL_target_use_Boost_Serialization.cmake b/Installation/cmake/modules/CGAL_target_use_Boost_Serialization.cmake new file mode 100644 index 00000000000..d6ae805efd8 --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_Boost_Serialization.cmake @@ -0,0 +1,14 @@ +if (CGAL_target_use_Boost_Serialization_included) + return() +endif() +set(CGAL_target_use_Boost_Serialization_included TRUE) + +function(CGAL_target_use_Boost_Serialization target) + + if(TARGET Boost::serialization) + target_link_libraries(${target} PUBLIC Boost::serialization) + else() + target_link_libraries(${target} PUBLIC ${Boost_SERIALIZATION_LIBRARY}) + endif() + +endfunction() diff --git a/Installation/cmake/modules/CGAL_target_use_Eigen.cmake b/Installation/cmake/modules/CGAL_target_use_Eigen.cmake new file mode 100644 index 00000000000..84f9f3be721 --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_Eigen.cmake @@ -0,0 +1,13 @@ +if (CGAL_target_use_Eigen_included) + return() +endif() +set(CGAL_target_use_Eigen_included TRUE) + +set( Eigen3_FIND_VERSION "3.1.0") +set(EIGEN3_USE_FILE "UseEigen3") + +function(CGAL_target_use_Eigen target) + target_include_directories(${target} PUBLIC ${EIGEN3_INCLUDE_DIR}) + target_compile_options( ${target} PUBLIC -DCGAL_EIGEN3_ENABLED) +endfunction() + diff --git a/Installation/cmake/modules/CGAL_target_use_GLPK.cmake b/Installation/cmake/modules/CGAL_target_use_GLPK.cmake new file mode 100644 index 00000000000..f19bd315b16 --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_GLPK.cmake @@ -0,0 +1,11 @@ +if (CGAL_target_use_GLPK_included) + return() +endif() +set(CGAL_target_use_GLPK_included TRUE) + +function(CGAL_target_use_GLPK target) + target_include_directories(${target} PUBLIC ${GLPK_INCLUDE_DIR}) + target_compile_options(${target} PUBLIC -DCGAL_USE_GLPK) + target_link_libraries(${target} PUBLIC ${GLPK_LIBRARIES}) +endfunction() + diff --git a/Installation/cmake/modules/CGAL_target_use_LASLIB.cmake b/Installation/cmake/modules/CGAL_target_use_LASLIB.cmake new file mode 100644 index 00000000000..65ad9084e5a --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_LASLIB.cmake @@ -0,0 +1,11 @@ +if (CGAL_target_use_LASLIB_included) + return() +endif() +set(CGAL_target_use_LASLIB_included TRUE) + +function(CGAL_target_use_LASLIB target) + target_include_directories(${target} PUBLIC ${LASLIB_INCLUDE_DIR}) + target_include_directories(${target} PUBLIC ${LASZIP_INCLUDE_DIR}) + target_compile_options( ${target} PUBLIC -DCGAL_LINKED_WITH_LASLIB) + target_link_libraries(${target} PUBLIC ${LASLIB_LIBRARIES}) +endfunction() diff --git a/Installation/cmake/modules/CGAL_target_use_OpenCV.cmake b/Installation/cmake/modules/CGAL_target_use_OpenCV.cmake new file mode 100644 index 00000000000..d378d50aead --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_OpenCV.cmake @@ -0,0 +1,10 @@ +if (CGAL_target_use_OpenCV_included) + return() +endif() +set(CGAL_target_use_OpenCV_included TRUE) + +function(CGAL_target_use_OpenCV target) + target_include_directories(${target} PUBLIC ${OpenCV_INCLUDE_DIRS}) + target_compile_options( ${target} PUBLIC -DCGAL_LINKED_WITH_OPENCV) + target_link_libraries(${target} PUBLIC ${OpenCV_LIBS}) +endfunction() diff --git a/Installation/cmake/modules/CGAL_target_use_SCIP.cmake b/Installation/cmake/modules/CGAL_target_use_SCIP.cmake new file mode 100644 index 00000000000..354216bb1f7 --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_SCIP.cmake @@ -0,0 +1,11 @@ +if (CGAL_target_use_SCIP_included) + return() +endif() +set(CGAL_target_use_SCIP_included TRUE) + +function(CGAL_target_use_SCIP target) + target_include_directories(${target} PUBLIC ${SCIP_INCLUDE_DIRS}) + target_compile_options(${target} PUBLIC -DCGAL_USE_SCIP) + target_link_libraries(${target} PUBLIC ${SCIP_LIBRARIES}) +endfunction() + diff --git a/Installation/cmake/modules/CGAL_target_use_TensorFlow.cmake b/Installation/cmake/modules/CGAL_target_use_TensorFlow.cmake new file mode 100644 index 00000000000..80bda689dab --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_TensorFlow.cmake @@ -0,0 +1,10 @@ +if (CGAL_target_use_TensorFlow_included) + return() +endif() +set(CGAL_target_use_TensorFlow_included TRUE) + +function(CGAL_target_use_TensorFlow target) + target_include_directories(${target} PUBLIC ${TensorFlow_INCLUDE_DIR}) + target_compile_options( ${target} PUBLIC -DCGAL_LINKED_WITH_TENSORFLOW) + target_link_libraries(${target} PUBLIC ${TensorFlow_LIBRARU}) +endfunction() diff --git a/Installation/cmake/modules/FindLibSSH.cmake b/Installation/cmake/modules/FindLibSSH.cmake new file mode 100644 index 00000000000..e2c49ee2fce --- /dev/null +++ b/Installation/cmake/modules/FindLibSSH.cmake @@ -0,0 +1,39 @@ +# - Try to find the LibSSH libraries +# This module defines: +# LIBSSH_FOUND - system has LibSSH lib +# LIBSSH_INCLUDE_DIR - the LibSSH include directory +# LIBSSH_LIBRARIES_DIR - directory where the LibSSH libraries are located +# LIBSSH_LIBRARIES - Link these to use LibSSH + + +include(FindPackageHandleStandardArgs) +include(${CMAKE_CURRENT_LIST_DIR}/CGAL_GeneratorSpecificSettings.cmake) + +if(LIBSSH_INCLUDE_DIR) + set(LIBSSH_in_cache TRUE) +else() + set(LIBSSH_in_cache FALSE) +endif() +if(NOT LIBSSH_LIBRARIES) + set(LIBSSH_in_cache FALSE) +endif() + +# Is it already configured? +if( NOT LIBSSH_in_cache ) + + find_path(LIBSSH_INCLUDE_DIR + NAMES "libssh/libssh.h" + ) + + find_library(LIBSSH_LIBRARIES NAMES ssh libssh + HINTS "/usr/lib" + "usr/lib/x86_64-linux-gnu" + PATH_SUFFIXES lib + DOC "Path to the LIBSSH library" + ) +endif() + +SET(LIBSSH_FOUND TRUE) +if( NOT LIBSSH_LIBRARIES OR NOT LIBSSH_INCLUDE_DIR) + SET(LIBSSH_FOUND FALSE) +endif() diff --git a/Installation/cmake/modules/UseEigen3.cmake b/Installation/cmake/modules/UseEigen3.cmake index e3ed18be243..850bb638392 100644 --- a/Installation/cmake/modules/UseEigen3.cmake +++ b/Installation/cmake/modules/UseEigen3.cmake @@ -7,3 +7,5 @@ include_directories( SYSTEM ${EIGEN3_INCLUDE_DIR} ) add_definitions(-DCGAL_EIGEN3_ENABLED) set (EIGEN3_SETUP TRUE) + +message(DEPRECATION "This file UseEigen.cmake is deprecated, and the function `CGAL_target_use_Eigen` from CGAL_target_use_Eigen.cmake should be used instead.") diff --git a/Installation/cmake/modules/UseLASLIB.cmake b/Installation/cmake/modules/UseLASLIB.cmake index 9235230eb1f..99f3374a24f 100644 --- a/Installation/cmake/modules/UseLASLIB.cmake +++ b/Installation/cmake/modules/UseLASLIB.cmake @@ -2,3 +2,6 @@ # It assumes that find_package(LASLIB) was already called. add_definitions(-DCGAL_LINKED_WITH_LASLIB) + +message(DEPRECATION "This file UseLASLIB.cmake is deprecated, and the function `CGAL_target_use_LASLIB` from CGAL_target_use_LASLIB.cmake should be used instead.") + diff --git a/Jet_fitting_3/examples/Jet_fitting_3/CMakeLists.txt b/Jet_fitting_3/examples/Jet_fitting_3/CMakeLists.txt index 19a1b9d32bd..d53b00b46a6 100644 --- a/Jet_fitting_3/examples/Jet_fitting_3/CMakeLists.txt +++ b/Jet_fitting_3/examples/Jet_fitting_3/CMakeLists.txt @@ -14,7 +14,6 @@ if ( CGAL_FOUND ) # use Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) # Link with Boost.ProgramOptions (optional) find_package(Boost QUIET COMPONENTS program_options) if(Boost_PROGRAM_OPTIONS_FOUND) @@ -30,9 +29,11 @@ if ( CGAL_FOUND ) list(APPEND CGAL_3RD_PARTY_LIBRARIES ${Boost_PROGRAM_OPTIONS_LIBRARY}) endif() - create_single_source_cgal_program( "Mesh_estimation.cpp" ) - create_single_source_cgal_program( "Single_estimation.cpp" ) - + create_single_source_cgal_program( "Mesh_estimation.cpp" ) + CGAL_target_use_Eigen(Mesh_estimation) + create_single_source_cgal_program( "Single_estimation.cpp" ) + CGAL_target_use_Eigen(Single_estimation) + else() message(STATUS "NOTICE: This program requires Eigen 3.1 (or greater) and will not be compiled.") endif() diff --git a/Jet_fitting_3/test/Jet_fitting_3/CMakeLists.txt b/Jet_fitting_3/test/Jet_fitting_3/CMakeLists.txt index c1cbc58150d..feff5e7bb7a 100644 --- a/Jet_fitting_3/test/Jet_fitting_3/CMakeLists.txt +++ b/Jet_fitting_3/test/Jet_fitting_3/CMakeLists.txt @@ -14,8 +14,8 @@ if ( CGAL_FOUND ) # use Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) create_single_source_cgal_program( "blind_1pt.cpp" ) + CGAL_target_use_Eigen(blind_1pt) else() message(STATUS "NOTICE: This program requires Eigen 3.1 (or greater) and will not be compiled.") endif() diff --git a/Kernel_23/doc/Kernel_23/CGAL/Filtered_predicate.h b/Kernel_23/doc/Kernel_23/CGAL/Filtered_predicate.h index 4d0ba6880ec..b08e4274f56 100644 --- a/Kernel_23/doc/Kernel_23/CGAL/Filtered_predicate.h +++ b/Kernel_23/doc/Kernel_23/CGAL/Filtered_predicate.h @@ -59,19 +59,13 @@ Filtered_predicate(); /// @} /// \name Operations -/// Similar function operators are defined for up to 7 arguments. /// @{ /*! -The unary function operator for unary predicates. +The function operator for predicates. */ -template result_type operator()(A1 a1); +template result_type operator()(A a...); -/*! -The binary function operator for binary predicates. -*/ -template -result_type operator()(A1 a1, A2 a2); /// @} diff --git a/Kernel_23/include/CGAL/Kernel/interface_macros.h b/Kernel_23/include/CGAL/Kernel/interface_macros.h index 18d35b53366..908a6dd277c 100644 --- a/Kernel_23/include/CGAL/Kernel/interface_macros.h +++ b/Kernel_23/include/CGAL/Kernel/interface_macros.h @@ -110,8 +110,8 @@ CGAL_Kernel_pred(Compare_dihedral_angle_3, compare_dihedral_angle_3_object) CGAL_Kernel_pred(Compare_distance_2, compare_distance_2_object) -CGAL_Kernel_pred_RT(Compare_distance_3, - compare_distance_3_object) +CGAL_Kernel_pred(Compare_distance_3, + compare_distance_3_object) CGAL_Kernel_pred_RT(Compare_power_distance_2, compare_power_distance_2_object) CGAL_Kernel_pred_RT(Compare_power_distance_3, diff --git a/Kernel_23/include/CGAL/Kernel_checker.h b/Kernel_23/include/CGAL/Kernel_checker.h index a4ee19def63..483ab5b645d 100644 --- a/Kernel_23/include/CGAL/Kernel_checker.h +++ b/Kernel_23/include/CGAL/Kernel_checker.h @@ -79,164 +79,21 @@ public: : p1(pp1), p2(pp2), cmp(c) { } - template - typename Pairify::type, - typename CGAL::cpp11::result_of::type>::result_type - operator()(const A1 &a1) const + template + typename Pairify::type, + typename CGAL::cpp11::result_of::type>::result_type + operator()(const A&... a) const { - typedef typename CGAL::cpp11::result_of::type result_type_1; - typedef typename CGAL::cpp11::result_of::type result_type_2; - result_type_1 res1 = p1(a1.first); - result_type_2 res2 = p2(a1.second); + typedef typename CGAL::cpp11::result_of::type result_type_1; + typedef typename CGAL::cpp11::result_of::type result_type_2; + result_type_1 res1 = p1(a.first...); + result_type_2 res2 = p2(a.second...); if (! cmp(res1, res2)) { - std::cerr << "Kernel_checker error : " << res1 << " != " << res2 - << " for the inputs : " << std::endl; - std::cerr << a1.first << std::endl; - std::cerr << a1.second << std::endl; - std::cerr << "functor first kernel : " - << typeid(p1).name() << std::endl; - std::cerr << "functor second kernel: " - << typeid(p2).name() << std::endl; - std::cerr << CGAL_PRETTY_FUNCTION << std::endl; CGAL_kernel_assertion(false); } return Pairify()(res1, res2); } - - template - typename Pairify::type, - typename CGAL::cpp11::result_of::type>::result_type - operator()(const A1 &a1, const A2 &a2) const - { - typedef typename CGAL::cpp11::result_of::type result_type_1; - typedef typename CGAL::cpp11::result_of::type result_type_2; - result_type_1 res1 = p1(a1.first, a2.first); - result_type_2 res2 = p2(a1.second, a2.second); - if (! cmp(res1, res2)) - { - std::cerr << "Kernel_checker error : " << res1 << " != " << res2 - << " for the inputs : " << std::endl; - std::cerr << a1.first << std::endl; - std::cerr << a1.second << std::endl; - std::cerr << a2.first << std::endl; - std::cerr << a2.second << std::endl; - std::cerr << "functor first kernel : " - << typeid(p1).name() << std::endl; - std::cerr << "functor second kernel: " - << typeid(p2).name() << std::endl; - std::cerr << CGAL_PRETTY_FUNCTION << std::endl; - CGAL_kernel_assertion(false); - } - return Pairify()(res1, res2); - } - - template - typename Pairify::type, - typename CGAL::cpp11::result_of::type>::result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3) const - { - typedef typename CGAL::cpp11::result_of::type result_type_1; - typedef typename CGAL::cpp11::result_of::type result_type_2; - result_type_1 res1 = p1(a1.first, a2.first, a3.first); - result_type_2 res2 = p2(a1.second, a2.second, a3.second); - if (! cmp(res1, res2)) - { - std::cerr << "Kernel_checker error : " << res1 << " != " << res2 - << " for the inputs : " << std::endl; - std::cerr << a1.first << std::endl; - std::cerr << a1.second << std::endl; - std::cerr << a2.first << std::endl; - std::cerr << a2.second << std::endl; - std::cerr << a3.first << std::endl; - std::cerr << a3.second << std::endl; - std::cerr << "functor first kernel : " - << typeid(p1).name() << std::endl; - std::cerr << "functor second kernel: " - << typeid(p2).name() << std::endl; - std::cerr << CGAL_PRETTY_FUNCTION << std::endl; - CGAL_kernel_assertion(false); - } - return Pairify()(res1, res2); - } - - template - typename Pairify::type, - typename CGAL::cpp11::result_of::type>::result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) const - { - typedef typename CGAL::cpp11::result_of::type result_type_1; - typedef typename CGAL::cpp11::result_of::type result_type_2; - - result_type_1 res1 = p1(a1.first, a2.first, a3.first, a4.first); - result_type_2 res2 = p2(a1.second, a2.second, a3.second, a4.second); - if (! cmp(res1, res2)) - { - std::cerr << "Kernel_checker error : " << res1 << " != " << res2 - << " for the inputs : " << std::endl; - std::cerr << a1.first << std::endl; - std::cerr << a1.second << std::endl; - std::cerr << a2.first << std::endl; - std::cerr << a2.second << std::endl; - std::cerr << a3.first << std::endl; - std::cerr << a3.second << std::endl; - std::cerr << a4.first << std::endl; - std::cerr << a4.second << std::endl; - std::cerr << "functor first kernel : " - << typeid(p1).name() << std::endl; - std::cerr << "functor second kernel: " - << typeid(p2).name() << std::endl; - std::cerr << CGAL_PRETTY_FUNCTION << std::endl; - CGAL_kernel_assertion(false); - } - return Pairify()(res1, res2); - } - - template - typename Pairify::type, - typename CGAL::cpp11::result_of::type>::result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5) const - { - typedef typename CGAL::cpp11::result_of::type result_type_1; - typedef typename CGAL::cpp11::result_of::type result_type_2; - - result_type_1 res1 = p1(a1.first, a2.first, a3.first, a4.first, a5.first); - result_type_2 res2 = p2(a1.second, a2.second, a3.second, a4.second, a5.second); - if (! cmp(res1, res2)) - { - std::cerr << "Kernel_checker error : " << res1 << " != " << res2 - << " for the inputs : " << std::endl; - std::cerr << a1.first << std::endl; - std::cerr << a1.second << std::endl; - std::cerr << a2.first << std::endl; - std::cerr << a2.second << std::endl; - std::cerr << a3.first << std::endl; - std::cerr << a3.second << std::endl; - std::cerr << a4.first << std::endl; - std::cerr << a4.second << std::endl; - std::cerr << a5.first << std::endl; - std::cerr << a5.second << std::endl; - std::cerr << "functor first kernel : " - << typeid(p1).name() << std::endl; - std::cerr << "functor second kernel: " - << typeid(p2).name() << std::endl; - std::cerr << CGAL_PRETTY_FUNCTION << std::endl; - CGAL_kernel_assertion(false); - } - return Pairify()(res1, res2); - } - - // Same thing with more arguments... }; struct dont_check_equal { diff --git a/Kernel_23/include/CGAL/Point_2.h b/Kernel_23/include/CGAL/Point_2.h index a5b00bb1eb9..7358d0dc46b 100644 --- a/Kernel_23/include/CGAL/Point_2.h +++ b/Kernel_23/include/CGAL/Point_2.h @@ -48,12 +48,12 @@ public: typedef RPoint_2 Rep; typedef typename R_::Cartesian_const_iterator_2 Cartesian_const_iterator; - const Rep& rep() const + const Rep& rep() const noexcept { return *this; } - Rep& rep() + Rep& rep() noexcept { return *this; } @@ -84,6 +84,15 @@ public: : RPoint_2(typename R::Construct_point_2()(Return_base_tag(), hx, hy, hw)) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.rep(), b.rep()); + } + typename cpp11::result_of::type x() const { diff --git a/Kernel_23/include/CGAL/Point_3.h b/Kernel_23/include/CGAL/Point_3.h index bf3952fb0dc..01b07bd3e0e 100644 --- a/Kernel_23/include/CGAL/Point_3.h +++ b/Kernel_23/include/CGAL/Point_3.h @@ -46,12 +46,12 @@ public: typedef typename R_::Kernel_base::Point_3 Rep; typedef typename R_::Cartesian_const_iterator_3 Cartesian_const_iterator; - const Rep& rep() const + const Rep& rep() const noexcept { return *this; } - Rep& rep() + Rep& rep() noexcept { return *this; } @@ -81,6 +81,15 @@ public: : Rep(typename R::Construct_point_3()(Return_base_tag(), hx, hy, hz, hw)) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.rep(), b.rep()); + } + typename cpp11::result_of::type x() const { diff --git a/Kernel_23/include/CGAL/Vector_2.h b/Kernel_23/include/CGAL/Vector_2.h index 4f570ed6b02..67f07e5e3e6 100644 --- a/Kernel_23/include/CGAL/Vector_2.h +++ b/Kernel_23/include/CGAL/Vector_2.h @@ -54,12 +54,12 @@ public: typedef RVector_2 Rep; typedef typename R_::Cartesian_const_iterator_2 Cartesian_const_iterator; - const Rep& rep() const + const Rep& rep() const noexcept { return *this; } - Rep& rep() + Rep& rep() noexcept { return *this; } @@ -93,6 +93,15 @@ public: Vector_2(const RT &x, const RT &y, const RT &w) : RVector_2(typename R::Construct_vector_2()(Return_base_tag(), x,y,w)) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.rep(), b.rep()); + } + typename cpp11::result_of::type x() const diff --git a/Kernel_23/include/CGAL/Vector_3.h b/Kernel_23/include/CGAL/Vector_3.h index c3c7c0bc953..077da5d649d 100644 --- a/Kernel_23/include/CGAL/Vector_3.h +++ b/Kernel_23/include/CGAL/Vector_3.h @@ -93,6 +93,15 @@ public: Vector_3(const RT& x, const RT& y, const RT& z, const RT& w) : Rep(typename R::Construct_vector_3()(Return_base_tag(), x, y, z, w)) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.rep(), b.rep()); + } + Direction_3 direction() const { return R().construct_direction_3_object()(*this); diff --git a/Kernel_d/include/CGAL/Kernel_d/function_objects.h b/Kernel_d/include/CGAL/Kernel_d/function_objects.h index 725167722a7..25d8c84628f 100644 --- a/Kernel_d/include/CGAL/Kernel_d/function_objects.h +++ b/Kernel_d/include/CGAL/Kernel_d/function_objects.h @@ -32,81 +32,10 @@ class Construct public: typedef ToBeConstructed result_type; + template ToBeConstructed - operator()() const - { return ToBeConstructed(); } - - template - ToBeConstructed - operator()( const A1& a1) const - { return ToBeConstructed(a1); } - - template - ToBeConstructed - operator()( const A1& a1, const A2& a2) const - { return ToBeConstructed(a1,a2); } - - template - ToBeConstructed - operator()( const A1& a1, const A2& a2, const A3& a3) const - { return ToBeConstructed(a1,a2,a3); } - - template - ToBeConstructed - operator()( const A1& a1, const A2& a2, const A3& a3, const A4& a4) const - { return ToBeConstructed(a1,a2,a3,a4); } - - template - ToBeConstructed - operator()( const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5) const - { return ToBeConstructed(a1,a2,a3,a4,a5); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6 ) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6, - const A& a7 ) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6,a7); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6, - const A& a7, const A& a8, const A& a9) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6,a7,a8,a9); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6, - const A& a7, const A& a8, const A& a9, - const A& a10) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6, - const A& a7, const A& a8, const A& a9, - const A& a10,const A& a11,const A& a12) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6, - const A& a7, const A& a8, const A& a9, - const A& a10,const A& a11,const A& a12, - const A& a13) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13); } - + operator()( A&& ... a) const + { return ToBeConstructed(std::forward(a)...); } }; class Call_has_on_positive_side diff --git a/Linear_cell_complex/include/CGAL/Cell_attribute_with_point.h b/Linear_cell_complex/include/CGAL/Cell_attribute_with_point.h index 6799463d399..5c6c15505e6 100644 --- a/Linear_cell_complex/include/CGAL/Cell_attribute_with_point.h +++ b/Linear_cell_complex/include/CGAL/Cell_attribute_with_point.h @@ -25,11 +25,11 @@ namespace CGAL { class Point_for_cell { public: - /// Contructor without parameter. + /// Constructor without parameter. Point_for_cell() {} - /// Contructor with a point in parameter. + /// Constructor with a point in parameter. Point_for_cell(const Point& apoint) : mpoint(apoint) {} @@ -87,15 +87,15 @@ namespace CGAL { { return !operator==(other); } protected: - /// Default contructor. + /// Default constructor. Cell_attribute_with_point() {} - /// Contructor with a point in parameter. + /// Constructor with a point in parameter. Cell_attribute_with_point(const Point& apoint) : Base2(apoint) {} - /// Contructor with a point and an attribute in parameters. + /// Constructor with a point and an attribute in parameters. Cell_attribute_with_point(const Point& apoint, const Info& ainfo) : Base1(ainfo), Base2(apoint) @@ -144,11 +144,11 @@ namespace CGAL { { return false; } protected: - /// Default contructor. + /// Default constructor. Cell_attribute_with_point() {} - /// Contructor with a point in parameter. + /// Constructor with a point in parameter. Cell_attribute_with_point(const Point& apoint) : Base2(apoint) {} }; diff --git a/Maintenance/infrastructure/cgal.geometryfactory.com/crontab b/Maintenance/infrastructure/cgal.geometryfactory.com/crontab index 6912301cc49..d98d42b770d 100644 --- a/Maintenance/infrastructure/cgal.geometryfactory.com/crontab +++ b/Maintenance/infrastructure/cgal.geometryfactory.com/crontab @@ -25,11 +25,11 @@ LC_CTYPE=en_US.UTF-8 # "master" alone 0 21 * * Sun cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/master.git --do-it || echo ERROR # "integration" -0 21 * * Mon,Tue,Wed,Thu cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/integration.git $HOME/CGAL/branches/empty-dir --do-it --public || echo ERROR +0 21 * * Mon,Tue,Wed,Thu,Fri cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/integration.git $HOME/CGAL/branches/empty-dir --do-it --public || echo ERROR # from branch 5.0 -0 21 * * Fri cd $HOME/CGAL/create_internal_release-5.0-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.0-branch.git --public --do-it || echo ERROR +0 21 * * Sat cd $HOME/CGAL/create_internal_release-5.0-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.0-branch.git --public --do-it || echo ERROR # from branch 4.14 -0 21 * * Sat cd $HOME/CGAL/create_internal_release-4.14-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-4.14-branch.git --public --do-it || echo ERROR +#0 21 * * Sat cd $HOME/CGAL/create_internal_release-4.14-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-4.14-branch.git --public --do-it || echo ERROR ## Older stuff # from branch 4.13 diff --git a/Mesh_2/include/CGAL/Delaunay_mesh_size_criteria_2.h b/Mesh_2/include/CGAL/Delaunay_mesh_size_criteria_2.h index 86b17c1030b..62de1a1e3de 100644 --- a/Mesh_2/include/CGAL/Delaunay_mesh_size_criteria_2.h +++ b/Mesh_2/include/CGAL/Delaunay_mesh_size_criteria_2.h @@ -111,10 +111,8 @@ public: typedef typename Geom_traits::Compute_squared_distance_2 Compute_squared_distance_2; - Geom_traits traits; /** @warning traits with data!! */ - Compute_squared_distance_2 squared_distance = - traits.compute_squared_distance_2_object(); + this->traits.compute_squared_distance_2_object(); const Point_2& pa = fh->vertex(0)->point(); const Point_2& pb = fh->vertex(1)->point(); @@ -165,7 +163,7 @@ public: } } - Compute_area_2 area_2 = traits.compute_area_2_object(); + Compute_area_2 area_2 = this->traits.compute_area_2_object(); double area = 2*CGAL::to_double(area_2(pa, pb, pc)); diff --git a/Mesh_2/test/Mesh_2/test_mesh_projection_traits.cpp b/Mesh_2/test/Mesh_2/test_mesh_projection_traits.cpp new file mode 100644 index 00000000000..030471c0295 --- /dev/null +++ b/Mesh_2/test/Mesh_2/test_mesh_projection_traits.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include + +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K1; +typedef CGAL::Triangulation_2_projection_traits_3 K; +typedef CGAL::Triangulation_vertex_base_2 Vb; +typedef CGAL::Delaunay_mesh_face_base_2 Fb; +typedef CGAL::Triangulation_data_structure_2 Tds; +typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; +typedef CGAL::Delaunay_mesh_size_criteria_2 Criteria; + +typedef CDT::Vertex_handle Vertex_handle; +typedef CDT::Point Point; + +int main() +{ + K gt{ { 0, 0, 1} }; + CDT cdt(gt); + + Vertex_handle va = cdt.insert(Point(-4,0,0)); + Vertex_handle vb = cdt.insert(Point(0,-1,0)); + Vertex_handle vc = cdt.insert(Point(4,0,0)); + Vertex_handle vd = cdt.insert(Point(0,1,0)); + cdt.insert(Point(2, 0.6, 0)); + + cdt.insert_constraint(va, vb); + cdt.insert_constraint(vb, vc); + cdt.insert_constraint(vc, vd); + cdt.insert_constraint(vd, va); + + std::cout << "Number of vertices: " << cdt.number_of_vertices() << std::endl; + + std::cout << "Meshing the triangulation..." << std::endl; + CGAL::refine_Delaunay_mesh_2(cdt, Criteria(0.125, 0.5, gt)); + + std::cout << "Number of vertices: " << cdt.number_of_vertices() << std::endl; +} diff --git a/Mesh_3/examples/Mesh_3/CMakeLists.txt b/Mesh_3/examples/Mesh_3/CMakeLists.txt index dcaedc3629a..a6f7848d200 100644 --- a/Mesh_3/examples/Mesh_3/CMakeLists.txt +++ b/Mesh_3/examples/Mesh_3/CMakeLists.txt @@ -48,8 +48,6 @@ if ( CGAL_FOUND ) if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library, and will not be compiled.") return() - else() - include( ${EIGEN3_USE_FILE} ) endif() find_package(VTK QUIET COMPONENTS vtkImagingGeneral vtkIOImage NO_MODULE) @@ -72,49 +70,99 @@ if ( CGAL_FOUND ) # Compilable examples create_single_source_cgal_program( "mesh_hybrid_mesh_domain.cpp" ) + CGAL_target_use_Eigen(mesh_hybrid_mesh_domain) + create_single_source_cgal_program( "mesh_implicit_sphere.cpp" ) + CGAL_target_use_Eigen(mesh_implicit_sphere) + create_single_source_cgal_program( "mesh_implicit_sphere_variable_size.cpp" ) + CGAL_target_use_Eigen(mesh_implicit_sphere_variable_size) + create_single_source_cgal_program( "mesh_two_implicit_spheres_with_balls.cpp" ) + CGAL_target_use_Eigen(mesh_two_implicit_spheres_with_balls) + create_single_source_cgal_program( "mesh_implicit_domains_2.cpp" "implicit_functions.cpp" ) + CGAL_target_use_Eigen(mesh_implicit_domains_2) + create_single_source_cgal_program( "mesh_cubes_intersection.cpp" ) + CGAL_target_use_Eigen(mesh_cubes_intersection) + create_single_source_cgal_program( "mesh_cubes_intersection_with_features.cpp" ) + CGAL_target_use_Eigen(mesh_cubes_intersection_with_features) + create_single_source_cgal_program( "mesh_implicit_domains.cpp" "implicit_functions.cpp" ) + CGAL_target_use_Eigen(mesh_implicit_domains) + create_single_source_cgal_program( "mesh_polyhedral_domain.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain) + create_single_source_cgal_program( "mesh_polyhedral_domain_sm.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain_sm) + create_single_source_cgal_program( "mesh_polyhedral_domain_with_surface_inside.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain_with_surface_inside) + create_single_source_cgal_program( "remesh_polyhedral_surface.cpp" ) + CGAL_target_use_Eigen(remesh_polyhedral_surface) + create_single_source_cgal_program( "remesh_polyhedral_surface_sm.cpp" ) + CGAL_target_use_Eigen(remesh_polyhedral_surface_sm) + create_single_source_cgal_program( "mesh_polyhedral_domain_with_features.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain_with_features) + create_single_source_cgal_program( "mesh_polyhedral_domain_with_features_sm.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain_with_features_sm) + create_single_source_cgal_program( "mesh_polyhedral_domain_with_lipschitz_sizing.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain_with_lipschitz_sizing) + create_single_source_cgal_program( "mesh_polyhedral_complex.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_complex) + create_single_source_cgal_program( "mesh_polyhedral_complex_sm.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_complex_sm) + if( WITH_CGAL_ImageIO ) if( VTK_FOUND AND ("${VTK_VERSION_MAJOR}" GREATER "5" OR VTK_VERSION VERSION_GREATER 5) ) add_executable ( mesh_3D_gray_vtk_image mesh_3D_gray_vtk_image.cpp ) + CGAL_target_use_Eigen(mesh_3D_gray_vtk_image) target_link_libraries( mesh_3D_gray_vtk_image ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ${VTK_LIBRARIES}) cgal_add_test( mesh_3D_gray_vtk_image ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS mesh_3D_gray_vtk_image ) endif() create_single_source_cgal_program( "mesh_3D_gray_image.cpp" ) + CGAL_target_use_Eigen(mesh_3D_gray_image) + create_single_source_cgal_program( "mesh_3D_gray_image_multiple_values.cpp" ) + CGAL_target_use_Eigen(mesh_3D_gray_image_multiple_values) + create_single_source_cgal_program( "mesh_3D_image_with_features.cpp" ) + CGAL_target_use_Eigen(mesh_3D_image_with_features) + if( CGAL_ImageIO_USE_ZLIB ) create_single_source_cgal_program( "mesh_optimization_example.cpp" ) + CGAL_target_use_Eigen(mesh_optimization_example) create_single_source_cgal_program( "mesh_optimization_lloyd_example.cpp" ) + CGAL_target_use_Eigen(mesh_optimization_lloyd_example) create_single_source_cgal_program( "mesh_3D_image.cpp" ) + CGAL_target_use_Eigen(mesh_3D_image) + create_single_source_cgal_program( "mesh_3D_image_with_custom_initialization.cpp" ) + CGAL_target_use_Eigen(mesh_3D_image_with_custom_initialization) create_single_source_cgal_program( "mesh_3D_image_variable_size.cpp" ) + CGAL_target_use_Eigen(mesh_3D_image_variable_size) else() message( STATUS "NOTICE: The examples mesh_3D_image.cpp, mesh_3D_image_variable_size.cpp, mesh_optimization_example.cpp and mesh_optimization_lloyd_example.cpp need CGAL_ImageIO to be configured with ZLIB support, and will not be compiled." ) endif() else() message( STATUS "NOTICE: Some examples need the CGAL_ImageIO library, and will not be compiled." ) endif() + # create_single_source_cgal_program( "mesh_polyhedral_implicit_function.cpp" ) # create_single_source_cgal_program( "mesh_polyhedral_surface_tolerance_region.cpp" ) # create_single_source_cgal_program( "mesh_polyhedral_edge_tolerance_region.cpp" ) diff --git a/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h b/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h index e00ea7ade01..a35de5e6c50 100644 --- a/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h +++ b/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h @@ -824,7 +824,7 @@ protected: false> Wrapper; return Wrapper(image, transform_fct, - transform_fct(value_outside)); + value_outside) ; } template diff --git a/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h b/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h index ae6413ca009..9421e883a45 100644 --- a/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h +++ b/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h @@ -750,8 +750,7 @@ detect_features(FT angle_in_degree, for(Polyhedron_type& p : poly) { initialize_ts(p); - using Mesh_3::internal::Get_face_index_pmap; - Get_face_index_pmap get_face_index_pmap(p); + #ifdef CGAL_MESH_3_VERBOSE std::size_t poly_id = &p-&poly[0]; std::cerr << "Polyhedron #" << poly_id << " :\n"; @@ -768,9 +767,9 @@ detect_features(FT angle_in_degree, , eif , pid_map , PMP::parameters::first_index(nb_of_patch_plus_one) - .face_index_map(get_face_index_pmap(p)) - .vertex_incident_patches_map(vip_map) - .vertex_feature_degree_map(vertex_feature_degree_map)); + .face_index_map(get_initialized_face_index_map(p)) + .vertex_incident_patches_map(vip_map) + .vertex_feature_degree_map(vertex_feature_degree_map)); Mesh_3::internal::Is_featured_edge is_featured_edge(p); diff --git a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h index f9a7a0d5cf4..42abf9d1256 100644 --- a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h +++ b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h @@ -105,47 +105,6 @@ struct IGT_generator } // end namespace details } // end namespace Mesh_3 -namespace Mesh_3 { -namespace internal { - -template ::value> -class Get_face_index_pmap { -public: - typedef typename boost::property_map::const_type Pmap; - Get_face_index_pmap(const Polyhedron_type&) {} - Pmap operator()(const Polyhedron_type& polyhedron) { - return get(CGAL::face_index, polyhedron); - } -}; - -template -class Get_face_index_pmap { - typedef typename boost::graph_traits::face_descriptor - face_descriptor; - typedef std::map Map; -public: - Get_face_index_pmap(const Polyhedron_type& polyhedron) { - int id = 0; - for(face_descriptor f : faces(polyhedron)) - { - face_ids[f] = id++; - } - } - typedef boost::associative_property_map Pmap; - - Pmap operator()(const Polyhedron_type&) { - return Pmap(face_ids); - } -private: - Map face_ids; -}; - -} // end namespace internal -} // end namespace Mesh_3 - /** * @class Polyhedral_mesh_domain_3 * diff --git a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h index d5f9979bc9b..ea92e1341ea 100644 --- a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h +++ b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h @@ -348,9 +348,6 @@ detect_features(FT angle_in_degree, std::vector& poly) typedef typename boost::property_map >::type VIPMap; typedef typename boost::property_map::type EIFMap; - using Mesh_3::internal::Get_face_index_pmap; - Get_face_index_pmap get_face_index_pmap(p); - PIDMap pid_map = get(face_patch_id_t(), p); VIPMap vip_map = get(vertex_incident_patches_t(), p); EIFMap eif_map = get(CGAL::edge_is_feature, p); @@ -360,8 +357,8 @@ detect_features(FT angle_in_degree, std::vector& poly) , eif_map , pid_map , PMP::parameters::first_index(nb_of_patch_plus_one) - .face_index_map(get_face_index_pmap(p)) - .vertex_incident_patches_map(vip_map)); + .face_index_map(get_initialized_face_index_map(p)) + .vertex_incident_patches_map(vip_map)); Mesh_3::internal::Is_featured_edge is_featured_edge(p); diff --git a/Mesh_3/test/Mesh_3/CMakeLists.txt b/Mesh_3/test/Mesh_3/CMakeLists.txt index 525573cbeb4..bd6221a9aa6 100644 --- a/Mesh_3/test/Mesh_3/CMakeLists.txt +++ b/Mesh_3/test/Mesh_3/CMakeLists.txt @@ -22,8 +22,6 @@ if ( CGAL_FOUND ) if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library, and will not be compiled.") return() - else() - include( ${EIGEN3_USE_FILE} ) endif() create_single_source_cgal_program( "test_boost_has_xxx.cpp" ) @@ -61,6 +59,42 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "test_mesh_polyhedral_domain_with_features_deprecated.cpp" ) create_single_source_cgal_program( "test_meshing_with_one_step.cpp" ) + foreach(target + test_boost_has_xxx + test_c3t3 + test_mesh_capsule_var_distance_bound + test_implicit_multi_domain_to_labeling_function_wrapper + test_c3t3_io + test_c3t3_with_features + test_criteria + test_domain_with_polyline_features + test_labeled_mesh_domain_3 + test_mesh_criteria_creation + test_c3t3_into_facegraph + test_without_detect_features + test_meshing_3D_image + test_meshing_3D_image_deprecated + test_meshing_3D_gray_image + test_meshing_3D_gray_image_deprecated + test_meshing_implicit_function + test_meshing_implicit_function_deprecated + test_meshing_polyhedral_complex + test_meshing_polyhedron + test_meshing_polylines_only + test_meshing_polyhedron_with_features + test_meshing_verbose + test_meshing_unit_tetrahedron + test_meshing_with_default_edge_size + test_meshing_determinism + test_c3t3_extract_subdomains_boundaries + test_mesh_3_issue_1554 + test_mesh_polyhedral_domain_with_features_deprecated + test_meshing_with_one_step.cpp) + if(TARGET ${target}) + CGAL_target_use_Eigen(${target}) + endif() + endforeach() + foreach(target test_meshing_verbose test_meshing_polyhedron_with_features diff --git a/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h b/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h index 5e0e24254fe..7c3c8e01878 100644 --- a/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h +++ b/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h @@ -109,6 +109,12 @@ template, private EC { + // `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. + template + static T default_construct() { return T(); } + // 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; @@ -138,7 +144,7 @@ class Lazy_rep_XXX : // Currently we construct the vectors, then move them into the tuple. It would be nicer to construct them in their final destination, because eventually we will also have arrays instead of vectors. template Lazy_rep_XXX(Lazy_internal::typelist, const AC& ac, const EC& ec, LLL const&lll, LL const&...ll) : - Lazy_rep(ac(CGAL::approx(ll)...)), EC(ec), l(Lazy_internal::do_extract(T{},lll)...) + Lazy_rep(ac(CGAL::approx(ll)...)), EC(ec), l(Lazy_internal::do_extract(default_construct(),lll)...) { //this->set_depth(std::max({ -1, (int)CGAL::depth(ll)...}) + 1); this->set_depth(1); // FIXME: now that we have ranges, we could actually compute the depth if we cared... diff --git a/NewKernel_d/include/CGAL/NewKernel_d/Wrapper/Point_d.h b/NewKernel_d/include/CGAL/NewKernel_d/Wrapper/Point_d.h index 404eca88bf3..5c0dce2db1f 100644 --- a/NewKernel_d/include/CGAL/NewKernel_d/Wrapper/Point_d.h +++ b/NewKernel_d/include/CGAL/NewKernel_d/Wrapper/Point_d.h @@ -51,12 +51,12 @@ public: typedef typename Get_type::type Rep; //typedef typename CGAL::decay::type>::type Cartesian_const_iterator; - const Rep& rep() const + const Rep& rep() const noexcept { return *this; } - Rep& rep() + Rep& rep() noexcept { return *this; } @@ -101,6 +101,14 @@ public: Point_d(Origin&& v) : Rep(CPBase()(std::move(v))) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.rep(), b.rep()); + } decltype(auto) cartesian(int i)const{ return CCBase()(rep(),i); diff --git a/NewKernel_d/test/NewKernel_d/CMakeLists.txt b/NewKernel_d/test/NewKernel_d/CMakeLists.txt index 9cbe76d8204..8f7ee2b990c 100644 --- a/NewKernel_d/test/NewKernel_d/CMakeLists.txt +++ b/NewKernel_d/test/NewKernel_d/CMakeLists.txt @@ -18,10 +18,8 @@ if ( CGAL_FOUND ) find_package(Eigen3) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - create_single_source_cgal_program( "Epick_d.cpp" ) - + CGAL_target_use_Eigen(Epick_d) else() message(STATUS "NOTICE: This program requires the Eigen3 library, and will not be compiled.") diff --git a/Number_types/include/CGAL/FPU.h b/Number_types/include/CGAL/FPU.h index 1ed1d728d34..1d290381603 100644 --- a/Number_types/include/CGAL/FPU.h +++ b/Number_types/include/CGAL/FPU.h @@ -408,7 +408,7 @@ typedef unsigned int FPU_CW_t; #elif defined __mips__ #define CGAL_IA_SETFPCW(CW) asm volatile ("ctc1 %0,$31" : :"r" (CW)) -#define CGAL_IA_GETFPCW(CW) asm volatile ("cfc1 %0,$31" : "=r" (CW)) +#define CGAL_IA_GETFPCW(CW) asm volatile ("cfc1 %0,$31" : "=r" (CW)); CW &= 3 typedef unsigned int FPU_CW_t; #define CGAL_FE_TONEAREST (0x0) #define CGAL_FE_TOWARDZERO (0x1) diff --git a/Number_types/include/CGAL/GMP/Gmpq_type.h b/Number_types/include/CGAL/GMP/Gmpq_type.h index 8fa397492d5..e339590b8d1 100644 --- a/Number_types/include/CGAL/GMP/Gmpq_type.h +++ b/Number_types/include/CGAL/GMP/Gmpq_type.h @@ -222,20 +222,23 @@ public: Gmpq& operator*=(const Gmpq &q); Gmpq& operator/=(const Gmpq &q); - bool operator==(const Gmpq &q) const { return mpq_equal(this->mpq(), q.mpq()) != 0;} - bool operator< (const Gmpq &q) const { return mpq_cmp(this->mpq(), q.mpq()) < 0; } + bool operator==(const Gmpq &q) const noexcept { return mpq_equal(this->mpq(), q.mpq()) != 0;} + bool operator< (const Gmpq &q) const noexcept { return mpq_cmp(this->mpq(), q.mpq()) < 0; } - double to_double() const; - Sign sign() const; + double to_double() const noexcept; + Sign sign() const noexcept; - const mpq_t & mpq() const { return Ptr()->mpQ; } - mpq_t & mpq() { return ptr()->mpQ; } + const mpq_t & mpq() const noexcept { return Ptr()->mpQ; } + mpq_t & mpq() noexcept { return ptr()->mpQ; } + friend void swap(Gmpq &x, Gmpq &y) noexcept { x.Base::swap(y); } +#ifdef CGAL_PROFILE ~Gmpq() { CGAL_HISTOGRAM_PROFILER("[Gmpq sizes in log2 scale]", (unsigned) ( ::log(double(size())) / ::log(double(2)) ) ); } +#endif // Interoperability with int Gmpq& operator+=(int z){return (*this)+= Gmpq(z);} @@ -446,12 +449,12 @@ Gmpq& Gmpq::operator/=(const Gmpz &z){ inline double -Gmpq::to_double() const +Gmpq::to_double() const noexcept { return mpq_get_d(mpq()); } inline Sign -Gmpq::sign() const +Gmpq::sign() const noexcept { return static_cast(mpq_sgn(mpq())); } inline diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index 471096f37ba..41e2c597981 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -383,6 +383,9 @@ public : typename boost::disable_if,int>::type=0) : Base(new Lazy_lazy_exact_Cst(x)){} + friend void swap(Lazy_exact_nt& a, Lazy_exact_nt& b) noexcept + { swap(static_cast(a), static_cast(b)); } + Self operator+ () const { return *this; } diff --git a/Number_types/include/CGAL/Sqrt_extension/Eigen_NumTraits.h b/Number_types/include/CGAL/Sqrt_extension/Eigen_NumTraits.h index b51e888839a..dc934692689 100644 --- a/Number_types/include/CGAL/Sqrt_extension/Eigen_NumTraits.h +++ b/Number_types/include/CGAL/Sqrt_extension/Eigen_NumTraits.h @@ -19,13 +19,6 @@ namespace Eigen { template struct NumTraits > { - typedef CGAL::Sqrt_extension Real; - typedef Real NonInteger; - typedef Real Nested; - typedef Real Literal; - - static inline Real epsilon() { return NumTraits::epsilon(); } - enum { IsInteger = 0, IsSigned = 1, @@ -35,6 +28,19 @@ namespace Eigen { AddCost = 2*NumTraits::AddCost+NumTraits::ReadCost, MulCost = 5*NumTraits::MulCost+2*NumTraits::AddCost }; + + typedef CGAL::Sqrt_extension Real; + typedef Real NonInteger; + typedef Real Nested; + typedef Real Literal; + + static inline Real epsilon() { return NumTraits::epsilon(); } + static inline int digits10() { return NumTraits::digits10(); } + static inline Real dummy_precision() { return NumTraits::dummy_precision(); } + static inline Real highest() { return NumTraits::highest(); } + static inline Real lowest() { return NumTraits::lowest(); } + static inline Real infinity() { return NumTraits::infinity(); } + static inline Real quiet_NaN() { return NumTraits::quiet_NaN(); } }; } diff --git a/Number_types/test/Number_types/CMakeLists.txt b/Number_types/test/Number_types/CMakeLists.txt index 6a74945aea9..0bb60b63e1d 100644 --- a/Number_types/test/Number_types/CMakeLists.txt +++ b/Number_types/test/Number_types/CMakeLists.txt @@ -26,7 +26,6 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "Counted_number.cpp" ) create_single_source_cgal_program( "double.cpp" ) create_single_source_cgal_program( "doubletst.cpp" ) - create_single_source_cgal_program( "eigen.cpp" ) create_single_source_cgal_program( "float.cpp" ) create_single_source_cgal_program( "floattst.cpp" ) create_single_source_cgal_program( "Gmpfr.cpp" ) @@ -80,7 +79,13 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "Gmpfr_bug.cpp" ) create_single_source_cgal_program( "Quotient_new.cpp" ) create_single_source_cgal_program( "test_nt_Coercion_traits.cpp" ) - + + create_single_source_cgal_program( "eigen.cpp" ) + find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) + if (EIGEN3_FOUND) + cgal_target_use_Eigen(eigen) + endif() + else( CGAL_FOUND ) message(STATUS diff --git a/Number_types/test/Number_types/eigen.cpp b/Number_types/test/Number_types/eigen.cpp index 91f620b0b3b..8e0dd9bf194 100644 --- a/Number_types/test/Number_types/eigen.cpp +++ b/Number_types/test/Number_types/eigen.cpp @@ -34,7 +34,7 @@ void check_(){ v << 1, 2, 3; NT t=v.dot(v); v+=d*m*(t*v); - int si=v.size(); + std::ptrdiff_t si=v.size(); CGAL_USE(si); } template @@ -59,7 +59,7 @@ int main(){ //check > >(); check >(); #ifdef CGAL_USE_GMP - check(); +// check(); check(); check(); check >(); @@ -69,7 +69,7 @@ int main(){ check(); #endif #ifdef CGAL_USE_CORE - check(); +// check(); check(); check(); check(); diff --git a/Periodic_3_mesh_3/examples/Periodic_3_mesh_3/CMakeLists.txt b/Periodic_3_mesh_3/examples/Periodic_3_mesh_3/CMakeLists.txt index b18274683b9..8b1fb98c95f 100644 --- a/Periodic_3_mesh_3/examples/Periodic_3_mesh_3/CMakeLists.txt +++ b/Periodic_3_mesh_3/examples/Periodic_3_mesh_3/CMakeLists.txt @@ -26,8 +26,6 @@ find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater) if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library, and will not be compiled.") return() -else() - include( ${EIGEN3_USE_FILE} ) endif() # Boost and its components @@ -46,3 +44,13 @@ create_single_source_cgal_program( "mesh_implicit_multi_domain.cpp" ) create_single_source_cgal_program( "mesh_implicit_shape_with_subdomains.cpp" ) create_single_source_cgal_program( "mesh_implicit_shape_with_optimizers.cpp" ) create_single_source_cgal_program( "mesh_implicit_shape_with_features.cpp" ) + + +foreach(target + mesh_implicit_shape + mesh_implicit_multi_domain + mesh_implicit_shape_with_subdomains + mesh_implicit_shape_with_optimizers + mesh_implicit_shape_with_features) + CGAL_target_use_Eigen(${target}) +endforeach() diff --git a/Periodic_3_mesh_3/test/Periodic_3_mesh_3/CMakeLists.txt b/Periodic_3_mesh_3/test/Periodic_3_mesh_3/CMakeLists.txt index dddf3a8f260..d1929fd2bbb 100644 --- a/Periodic_3_mesh_3/test/Periodic_3_mesh_3/CMakeLists.txt +++ b/Periodic_3_mesh_3/test/Periodic_3_mesh_3/CMakeLists.txt @@ -19,14 +19,15 @@ if ( CGAL_FOUND ) if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library, and will not be compiled.") return() - else() - include( ${EIGEN3_USE_FILE} ) endif() create_single_source_cgal_program( "test_implicit_shapes_bunch.cpp" ) + CGAL_target_use_Eigen(test_implicit_shapes_bunch) create_single_source_cgal_program( "test_implicit_shapes_with_features.cpp" ) + CGAL_target_use_Eigen(test_implicit_shapes_with_features) create_single_source_cgal_program( "test_triply_periodic_minimal_surfaces.cpp" ) - + CGAL_target_use_Eigen(test_triply_periodic_minimal_surfaces) + else() message(STATUS "This program requires the CGAL library, and will not be compiled.") diff --git a/Point_set_3/examples/Point_set_3/CMakeLists.txt b/Point_set_3/examples/Point_set_3/CMakeLists.txt index 45172ef603d..21055796731 100644 --- a/Point_set_3/examples/Point_set_3/CMakeLists.txt +++ b/Point_set_3/examples/Point_set_3/CMakeLists.txt @@ -44,14 +44,9 @@ set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates) create_single_source_cgal_program( "point_set_read_ply.cpp" CXX_FEATURES ${needed_cxx_features} ) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) -if (NOT EIGEN3_FOUND) - find_package(LAPACK) - if(LAPACK_FOUND) - include( ${LAPACK_USE_FILE} ) - endif(LAPACK_FOUND) -else() - include( ${EIGEN3_USE_FILE} ) +if (EIGEN3_FOUND) create_single_source_cgal_program( "point_set_algo.cpp" ) + CGAL_target_use_Eigen(point_set_algo) endif() create_single_source_cgal_program("draw_point_set_3.cpp" ) diff --git a/Point_set_processing_3/examples/Point_set_processing_3/CMakeLists.txt b/Point_set_processing_3/examples/Point_set_processing_3/CMakeLists.txt index c2da826d49b..34cff04d333 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/CMakeLists.txt +++ b/Point_set_processing_3/examples/Point_set_processing_3/CMakeLists.txt @@ -3,8 +3,6 @@ cmake_minimum_required(VERSION 3.1...3.15) project( Point_set_processing_3_Examples ) - - # Find CGAL find_package(CGAL QUIET) @@ -42,30 +40,21 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "bilateral_smooth_point_set_example.cpp" ) create_single_source_cgal_program( "grid_simplification_example.cpp" ) create_single_source_cgal_program( "grid_simplify_indices.cpp" ) - create_single_source_cgal_program( "hierarchy_simplification_example.cpp" ) - create_single_source_cgal_program( "normals_example.cpp" ) create_single_source_cgal_program( "property_map.cpp" ) create_single_source_cgal_program( "random_simplification_example.cpp" ) create_single_source_cgal_program( "read_write_xyz_point_set_example.cpp" ) create_single_source_cgal_program( "remove_outliers_example.cpp" ) - create_single_source_cgal_program( "scale_estimation_example.cpp" ) - create_single_source_cgal_program( "scale_estimation_2d_example.cpp" ) create_single_source_cgal_program( "wlop_simplify_and_regularize_point_set_example.cpp" ) create_single_source_cgal_program( "edge_aware_upsample_point_set_example.cpp" ) create_single_source_cgal_program( "structuring_example.cpp" ) - create_single_source_cgal_program( "callback_example.cpp" ) - set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates) - create_single_source_cgal_program( "read_ply_points_with_colors_example.cpp" CXX_FEATURES ${needed_cxx_features} ) - create_single_source_cgal_program( "write_ply_points_example.cpp" CXX_FEATURES ${needed_cxx_features} ) + create_single_source_cgal_program( "read_ply_points_with_colors_example.cpp" ) + create_single_source_cgal_program( "write_ply_points_example.cpp" ) find_package(LASLIB) if (LASLIB_FOUND) - include(${LASLIB_USE_FILE}) - include_directories(${LASLIB_INCLUDE_DIR}) - include_directories(${LASZIP_INCLUDE_DIR}) - create_single_source_cgal_program( "read_las_example.cpp" CXX_FEATURES ${needed_cxx_features} ) - target_link_libraries(read_las_example PRIVATE ${LASLIB_LIBRARIES}) + create_single_source_cgal_program( "read_las_example.cpp" ) + CGAL_target_use_LASLIB(read_las_example) else() message(STATUS "NOTICE : the LAS reader test requires LASlib and will not be compiled.") endif() @@ -73,30 +62,51 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) # Executables that require Eigen create_single_source_cgal_program( "jet_smoothing_example.cpp" ) + CGAL_target_use_Eigen(jet_smoothing_example) + create_single_source_cgal_program( "normal_estimation.cpp" ) + CGAL_target_use_Eigen(normal_estimation) + create_single_source_cgal_program( "edges_example.cpp" ) - else() + CGAL_target_use_Eigen(edges_example) + + create_single_source_cgal_program( "callback_example.cpp" ) + CGAL_target_use_Eigen(callback_example) + + create_single_source_cgal_program( "scale_estimation_example.cpp" ) + CGAL_target_use_Eigen(scale_estimation_example) + + create_single_source_cgal_program( "scale_estimation_2d_example.cpp" ) + CGAL_target_use_Eigen(scale_estimation_2d_example) + create_single_source_cgal_program( "hierarchy_simplification_example.cpp" ) + CGAL_target_use_Eigen(hierarchy_simplification_example) + + create_single_source_cgal_program( "normals_example.cpp" ) + CGAL_target_use_Eigen(normals_example) + + else() message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.") endif() - foreach(target - scale_estimation_example - wlop_simplify_and_regularize_point_set_example - bilateral_smooth_point_set_example - edge_aware_upsample_point_set_example - average_spacing_example - normals_example - jet_smoothing_example - normal_estimation - callback_example) - if(TBB_FOUND AND TARGET ${target}) - CGAL_target_use_TBB(${target}) - endif() - endforeach() + if (TBB_FOUND) + foreach(target + scale_estimation_example + wlop_simplify_and_regularize_point_set_example + bilateral_smooth_point_set_example + edge_aware_upsample_point_set_example + average_spacing_example + normals_example + jet_smoothing_example + normal_estimation + callback_example) + if(TARGET ${target}) + CGAL_target_use_TBB(${target}) + endif() + endforeach() + endif() else() message(STATUS "NOTICE: This program requires the CGAL library, and will not be compiled.") diff --git a/Point_set_processing_3/test/Point_set_processing_3/CMakeLists.txt b/Point_set_processing_3/test/Point_set_processing_3/CMakeLists.txt index 264c713ef55..1b5e1a80746 100644 --- a/Point_set_processing_3/test/Point_set_processing_3/CMakeLists.txt +++ b/Point_set_processing_3/test/Point_set_processing_3/CMakeLists.txt @@ -41,29 +41,41 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) # Executables that require Eigen create_single_source_cgal_program( "normal_estimation_test.cpp" ) + CGAL_target_use_Eigen(normal_estimation_test) + create_single_source_cgal_program( "hierarchy_simplification_test.cpp" ) + CGAL_target_use_Eigen(hierarchy_simplification_test) + create_single_source_cgal_program( "smoothing_test.cpp" ) + CGAL_target_use_Eigen(smoothing_test) + create_single_source_cgal_program( "vcm_plane_test.cpp" ) + CGAL_target_use_Eigen(vcm_plane_test) + create_single_source_cgal_program( "vcm_all_test.cpp" ) + CGAL_target_use_Eigen(vcm_all_test) + create_single_source_cgal_program( "jet_pointer_as_property_map.cpp" ) + CGAL_target_use_Eigen(jet_pointer_as_property_map) else() message(STATUS "NOTICE: This program requires Eigen 3.1 (or greater) and will not be compiled.") endif() - foreach(target - analysis_test - smoothing_test - bilateral_smoothing_test - wlop_simplify_and_regularize_test - edge_aware_upsample_test - normal_estimation_test) - if(TBB_FOUND AND TARGET ${target}) - CGAL_target_use_TBB(${target}) - endif() - endforeach() + if (TBB_FOUND) + foreach(target + analysis_test + smoothing_test + bilateral_smoothing_test + wlop_simplify_and_regularize_test + edge_aware_upsample_test + normal_estimation_test) + if(TARGET ${target}) + CGAL_target_use_TBB(${target}) + endif() + endforeach() + endif() else() diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt index ae0215158da..0b65cf899cf 100644 --- a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt +++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt @@ -23,15 +23,14 @@ if ( CGAL_FOUND ) # Find Eigen3 (requires 3.1.0 or greater) find_package(Eigen3 3.1.0) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() - if (EIGEN3_FOUND) # Executables that require Eigen 3 create_single_source_cgal_program( "poisson_reconstruction_example.cpp" ) + CGAL_target_use_Eigen(poisson_reconstruction_example) create_single_source_cgal_program( "poisson_reconstruction.cpp" ) + CGAL_target_use_Eigen(poisson_reconstruction) create_single_source_cgal_program( "poisson_reconstruction_function.cpp" ) + CGAL_target_use_Eigen(poisson_reconstruction_function) else() message(STATUS "NOTICE: The examples need Eigen 3.1 (or greater) will not be compiled.") endif() diff --git a/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/CMakeLists.txt b/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/CMakeLists.txt index e1d9326840b..1c518a1267b 100644 --- a/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/CMakeLists.txt +++ b/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/CMakeLists.txt @@ -25,11 +25,9 @@ if ( CGAL_FOUND ) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if(EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - # Executables that require Eigen 3.1 create_single_source_cgal_program( "poisson_reconstruction_test.cpp" ) - + CGAL_target_use_Eigen(poisson_reconstruction_test) else() message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.") diff --git a/Polygon_mesh_processing/benchmark/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/benchmark/Polygon_mesh_processing/CMakeLists.txt index 45799830a42..7db73683150 100644 --- a/Polygon_mesh_processing/benchmark/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/benchmark/Polygon_mesh_processing/CMakeLists.txt @@ -29,10 +29,6 @@ endif() # include for local package find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) -if (EIGEN3_FOUND) - # Executables that require Eigen 3.2 - include( ${EIGEN3_USE_FILE} ) -endif(EIGEN3_FOUND) # Creating entries for all .cpp/.C files with "main" routine # ########################################################## @@ -41,4 +37,8 @@ create_single_source_cgal_program( "polygon_mesh_slicer.cpp" ) create_single_source_cgal_program( "hole_filling.cpp" ) +if (EIGEN3_FOUND) + CGAL_target_use_Eigen(polygon_mesh_slicer) + CGAL_target_use_Eigen(hole_filling) +endif() diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt index 20cea4f136f..b95f8671c34 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt @@ -32,20 +32,27 @@ is the property map with the points associated to the vertices of the polygon me \cgalNPEnd \cgalNPBegin{vertex_index_map} \anchor PMP_vertex_index_map -is the property map containing the index of each vertex of the input polygon mesh.\n +is the property map associating a unique index to each vertex of a polygon mesh, +between `0` and `num_vertices(g)-1`. +If this parameter is not passed, internal machinery will create and initialize a vertex 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.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` as key type and the value type \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::vertex_index, pmesh)\endcode +Default: an initialized vertex index property map \cgalNPEnd \cgalNPBegin{face_index_map} \anchor PMP_face_index_map -is the property map containing the index of each face of the input polygon mesh.\n +is the property map associating a unique index to each face of a polygon mesh, +between `0` and `num_faces(g)-1`. +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.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%face_descriptor` as key type and the value type: \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::face_index, pmesh)\endcode -If this internal property map exists, its values must be initialized. +Default: an initialized face index property map \cgalNPEnd \cgalNPBegin{edge_is_constrained_map} \anchor PMP_edge_is_constrained_map diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index eff0d48d229..ec36a4b70f0 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -46,14 +46,16 @@ find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) create_single_source_cgal_program( "hausdorff_distance_remeshing_example.cpp") if (EIGEN3_FOUND) - # Executables that require Eigen 3.2 - include( ${EIGEN3_USE_FILE} ) - create_single_source_cgal_program( "hole_filling_example.cpp" ) + CGAL_target_use_Eigen(hole_filling_example) create_single_source_cgal_program( "hole_filling_example_SM.cpp" ) + CGAL_target_use_Eigen(hole_filling_example_SM) create_single_source_cgal_program( "refine_fair_example.cpp") + CGAL_target_use_Eigen(refine_fair_example) create_single_source_cgal_program( "shape_smoothing_example.cpp") - + CGAL_target_use_Eigen(shape_smoothing_example) + create_single_source_cgal_program( "hole_filling_example_LCC.cpp" ) + CGAL_target_use_Eigen(hole_filling_example_LCC) endif(EIGEN3_FOUND) create_single_source_cgal_program( "self_intersections_example.cpp" ) @@ -80,19 +82,24 @@ create_single_source_cgal_program( "corefinement_mesh_union_with_attributes.cpp" create_single_source_cgal_program( "corefinement_polyhedron_union.cpp" ) create_single_source_cgal_program( "random_perturbation_SM_example.cpp" ) create_single_source_cgal_program( "corefinement_LCC.cpp") -create_single_source_cgal_program( "hole_filling_example_LCC.cpp" ) create_single_source_cgal_program( "detect_features_example.cpp" ) create_single_source_cgal_program( "manifoldness_repair_example.cpp" ) create_single_source_cgal_program( "repair_polygon_soup_example.cpp" ) create_single_source_cgal_program( "mesh_smoothing_example.cpp") create_single_source_cgal_program( "locate_example.cpp") +#create_single_source_cgal_program( "self_snapping_example.cpp") +#create_single_source_cgal_program( "snapping_example.cpp") if(OpenMesh_FOUND) + create_single_source_cgal_program( "compute_normals_example_OM.cpp" ) target_link_libraries( compute_normals_example_OM PRIVATE ${OPENMESH_LIBRARIES} ) -create_single_source_cgal_program( "hole_filling_example_OM.cpp" ) -target_link_libraries( hole_filling_example_OM PRIVATE ${OPENMESH_LIBRARIES} ) +if (EIGEN3_FOUND) + create_single_source_cgal_program( "hole_filling_example_OM.cpp" ) + target_link_libraries( hole_filling_example_OM PRIVATE ${OPENMESH_LIBRARIES} ) + CGAL_target_use_Eigen( hole_filling_example_OM ) +endif() create_single_source_cgal_program( "point_inside_example_OM.cpp") target_link_libraries( point_inside_example_OM PRIVATE ${OPENMESH_LIBRARIES} ) @@ -109,6 +116,8 @@ endif(OpenMesh_FOUND) find_package( TBB ) if( TBB_FOUND ) +# CGAL_target_use_TBB(self_snapping_example) +# CGAL_target_use_TBB(snapping_example) CGAL_target_use_TBB(self_intersections_example) CGAL_target_use_TBB(hausdorff_distance_remeshing_example) else() diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_snapping_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_snapping_example.cpp new file mode 100644 index 00000000000..c20c59a2172 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_snapping_example.cpp @@ -0,0 +1,75 @@ +#include +#include + +#include +#include + +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; + +typedef Kernel::FT FT; +typedef Kernel::Point_3 Point_3; +typedef Kernel::Vector_3 Vector_3; +typedef CGAL::Surface_mesh Surface_mesh; + +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + +namespace PMP = CGAL::Polygon_mesh_processing; + +int main(int argc, char** argv) +{ + std::cout.precision(17); + + if(argc != 3) + { + std::cerr << "Usage: " << argv[0] << " input_mesh tolerance" << std::endl; + return EXIT_FAILURE; + } + + Surface_mesh sm; + std::ifstream in(argv[1]); + if(!in || in >> sm) + { + std::cerr << "Problem loading the input data" << std::endl; + return EXIT_FAILURE; + } + + Surface_mesh::Property_map tolerance_map; + tolerance_map = sm.add_property_map("v:t").first; + for(vertex_descriptor v : vertices(sm)) + put(tolerance_map, v, std::atof(argv[3])); + + std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); + + // Snap + std::size_t nb_snapped = PMP::experimental::snap_borders(sm, tolerance_map); + std::cout << "#snapped: " << nb_snapped << std::endl; + + std::chrono::steady_clock::time_point snap_time = std::chrono::steady_clock::now(); + std::cout << "Time elapsed (snap): " + << std::chrono::duration_cast(snap_time - start_time).count() + << "ms" << std::endl; + + // Stitch + std::cout << "Stitch, #ne: " << edges(sm).size() << std::endl; + PMP::stitch_borders(sm); + + std::chrono::steady_clock::time_point stitch_time = std::chrono::steady_clock::now(); + std::cout << "Time elapsed (stitch): " + << std::chrono::duration_cast(stitch_time - snap_time).count() + << "ms" << std::endl; + + std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); + std::cout << "Total time elapsed: " + << std::chrono::duration_cast(end_time - start_time).count() + << "ms" << std::endl; + + std::cout << "#border: " << PMP::number_of_borders(sm) << std::endl; + std::cout << "Done!" << std::endl; + + std::ofstream("snapped.off") << std::setprecision(17) << sm; + + return EXIT_SUCCESS; +} diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/snapping_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/snapping_example.cpp new file mode 100644 index 00000000000..b5bb4d913ed --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/snapping_example.cpp @@ -0,0 +1,78 @@ +#include +#include + +#include + +#include +#include + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Surface_mesh Surface_mesh; + +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + +namespace PMP = CGAL::Polygon_mesh_processing; + +int main(int argc, char** argv) +{ + if(argc != 4) + { + std::cerr << "Usage: " << argv[0] << " movable_mesh fixed_mesh tolerance" << std::endl; + return EXIT_FAILURE; + } + + Surface_mesh movable_mesh, fixed_mesh; + + std::ifstream in_m(argv[1]); + if(!in_m || in_m >> movable_mesh) + { + std::cerr << "Problem loading the input data" << std::endl; + return EXIT_FAILURE; + } + + std::ifstream in_f(argv[2]); + if(!in_f || in_f >> fixed_mesh) + { + std::cerr << "Problem loading the input data" << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Movable mesh: " << num_vertices(movable_mesh) << std::endl; + std::cout << "Fixed mesh: " << num_vertices(fixed_mesh) << std::endl; + + const double tolerance = std::atof(argv[3]); + + Surface_mesh::Property_map movable_tolerance_map; + movable_tolerance_map = movable_mesh.add_property_map("v:t").first; + for(vertex_descriptor v : vertices(movable_mesh)) + put(movable_tolerance_map, v, tolerance); + + Surface_mesh::Property_map fixed_tolerance_map; + fixed_tolerance_map = fixed_mesh.add_property_map("v:t").first; + for(vertex_descriptor v : vertices(fixed_mesh)) + put(fixed_tolerance_map, v, tolerance); + + std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); + + // Choice of named parameters indicates that: + // - We want to simplify the boundary of the first mesh + // - The geometry of the second mesh cannot change + std::size_t nb_snapped = PMP::experimental::snap_borders(movable_mesh, movable_tolerance_map, + fixed_mesh, fixed_tolerance_map, + CGAL::parameters::do_simplify_border(true), + CGAL::parameters::do_lock_mesh(true)); + + std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); + + std::cout << "Time elapsed: " + << std::chrono::duration_cast(end_time - start_time).count() + << "ms" << std::endl; + + std::cout << "#Snapped: " << nb_snapped << std::endl; + + std::ofstream("snapped_movable.off") << std::setprecision(17) << movable_mesh; + std::ofstream("snapped_fixed.off") << std::setprecision(17) << fixed_mesh; + + return EXIT_SUCCESS; +} diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h index 54a520908e0..c52695b90cf 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -28,13 +29,31 @@ namespace CGAL{ namespace Polygon_mesh_processing { +namespace internal { - namespace internal +template +std::size_t border_size(typename boost::graph_traits::halfedge_descriptor h, + const PolygonMesh& pmesh) +{ + // if you want to use it on a non-border halfedge, just use `degree(face, mesh)` + CGAL_precondition(is_border(h, pmesh)); + + std::size_t res = 0; + typename boost::graph_traits::halfedge_descriptor done = h; + do { + ++res; + h = next(h, pmesh); + } + while(h != done); + + return res; +} + template - HalfedgeOutputIterator border_halfedges_impl(const FaceRange& faces + HalfedgeOutputIterator border_halfedges_impl(const FaceRange& face_range , HalfedgeOutputIterator out , const PM& pmesh) { @@ -45,7 +64,7 @@ namespace Polygon_mesh_processing { // the bool is true if the halfedge stored is the one of the face, // false if it is its opposite std::map border; - for(face_descriptor f : faces) + for(face_descriptor f : face_range) { for(halfedge_descriptor h : halfedges_around_face(halfedge(f, pmesh), pmesh)) @@ -75,13 +94,13 @@ namespace Polygon_mesh_processing { , typename FaceRange , typename HalfedgeOutputIterator , typename NamedParameters> - HalfedgeOutputIterator border_halfedges_impl(const FaceRange& faces + HalfedgeOutputIterator border_halfedges_impl(const FaceRange& face_range , typename boost::cgal_no_property::type , HalfedgeOutputIterator out , const PM& pmesh , const NamedParameters& /* np */) { - return border_halfedges_impl(faces, out, pmesh); + return border_halfedges_impl(face_range, out, pmesh); } template - HalfedgeOutputIterator border_halfedges_impl(const FaceRange& faces + HalfedgeOutputIterator border_halfedges_impl(const FaceRange& face_range , const FaceIndexMap& fmap , HalfedgeOutputIterator out , const PM& pmesh @@ -98,25 +117,13 @@ namespace Polygon_mesh_processing { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; - //make a minimal check that it's properly initialized : - //if the 2 first faces have the same id, we know the property map is not initialized - if (boost::is_same::Is_internal_map, - boost::true_type>::value) - { - typename boost::range_iterator::type it = boost::const_begin(faces); - if (get(fmap, *it) == get(fmap, *std::next(it))) - { - std::cerr << "WARNING : the internal property map for CGAL::face_index_t" << std::endl - << " is not properly initialized." << std::endl - << " Initialize it before calling border_halfedges()" << std::endl; - } - } + CGAL_assertion(BGL::internal::is_index_map_valid(fmap, num_faces(pmesh), faces(pmesh))); std::vector present(num_faces(pmesh), false); - for(face_descriptor fd : faces) + for(face_descriptor fd : face_range) present[get(fmap, fd)] = true; - for(face_descriptor fd : faces) + for(face_descriptor fd : face_range) for(halfedge_descriptor hd : halfedges_around_face(halfedge(fd, pmesh), pmesh)) { @@ -142,21 +149,16 @@ namespace Polygon_mesh_processing { * For each returned halfedge `h`, `opposite(h, pmesh)` belongs to a face of the patch, * but `face(h, pmesh)` does not belong to the patch. * - * @tparam PolygonMesh model of `HalfedgeGraph`. If `PolygonMesh` - * has an internal property map - * for `CGAL::face_index_t` and no `face_index_map` is given - * as a named parameter, then the internal one must be initialized - * @tparam FaceRange range of - `boost::graph_traits::%face_descriptor`, model of `Range`. - Its iterator type is `InputIterator`. + * @tparam PolygonMesh model of `HalfedgeGraph` + * @tparam FaceRange a model of `Range` with value type `boost::graph_traits::%face_descriptor`. * @tparam HalfedgeOutputIterator model of `OutputIterator` holding `boost::graph_traits::%halfedge_descriptor` for patch border * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * - * @param pmesh the polygon mesh to which `faces` belong - * @param faces the range of faces defining the patch whose border halfedges - * are collected + * @param pmesh the polygon mesh to which the faces in `face_range` belong + * @param face_range the range of faces defining the patch whose border halfedges + * are collected * @param out the output iterator that collects the border halfedges of the patch, * seen from outside. * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below @@ -171,29 +173,18 @@ namespace Polygon_mesh_processing { , typename FaceRange , typename HalfedgeOutputIterator , typename NamedParameters> - HalfedgeOutputIterator border_halfedges(const FaceRange& faces + HalfedgeOutputIterator border_halfedges(const FaceRange& face_range , const PolygonMesh& pmesh , HalfedgeOutputIterator out , const NamedParameters& np) { - if (faces.empty()) return out; + if (face_range.empty()) + return out; - typedef PolygonMesh PM; - typedef typename GetFaceIndexMap::const_type FIMap; - typedef typename boost::property_map::type Unset_FIMap; + typedef typename CGAL::GetInitializedFaceIndexMap::const_type FIMap; + FIMap fim = CGAL::get_initialized_face_index_map(pmesh, np); - if (boost::is_same::value || faces.size() == 1) - { - //face index map is not given in named parameters, nor as an internal property map - return internal::border_halfedges_impl(faces, out, pmesh); - } - - //face index map given as a named parameter, or as an internal property map - FIMap fim = parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_const_property_map(CGAL::face_index, pmesh)); - - return internal::border_halfedges_impl(faces, fim, out, pmesh, np); + return internal::border_halfedges_impl(face_range, fim, out, pmesh, np); } template - HalfedgeOutputIterator border_halfedges(const FaceRange& faces + HalfedgeOutputIterator border_halfedges(const FaceRange& face_range , const PolygonMesh& pmesh , HalfedgeOutputIterator out) { - return border_halfedges(faces, pmesh, out, + return border_halfedges(face_range, pmesh, out, CGAL::Polygon_mesh_processing::parameters::all_default()); } @@ -225,7 +216,7 @@ namespace Polygon_mesh_processing { // // @tparam PolygonMesh model of `HalfedgeGraph`. // - // @param pmesh the polygon mesh to which `faces` belong + // @param pmesh the polygon mesh to which `face_range` belong // template unsigned int number_of_borders(const PolygonMesh& pmesh) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h index a75689c127f..5b31be90cff 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h @@ -416,9 +416,6 @@ void split_along_edges(TriangleMesh& tm, * \pre \link CGAL::Polygon_mesh_processing::does_bound_a_volume() `CGAL::Polygon_mesh_processing::does_bound_a_volume(clipper)` \endlink * * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`. - * If `TriangleMesh` has an internal property map for `CGAL::face_index_t`, - * as a named parameter, then it must be initialized. - * * @tparam NamedParameters1 a sequence of \ref pmp_namedparameters "Named Parameters" * @tparam NamedParameters2 a sequence of \ref pmp_namedparameters "Named Parameters" * @@ -434,8 +431,8 @@ void split_along_edges(TriangleMesh& tm, * `CGAL::vertex_point_t` must be available in `TriangleMesh` * \cgalParamEnd * \cgalParamBegin{face_index_map} a property map containing the index of each face of `tm` (`clipper`). - * Note that if the property map is writable, the indices of the faces - * of `tm` and `clipper` will be set after refining `tm` with the intersection with `clipper`. + * This property map must be either writable, or be automatically updated + * when new faces are added and removed in the mesh. * \cgalParamEnd * \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor` * that is used to track the creation of new faces. @@ -443,14 +440,14 @@ void split_along_edges(TriangleMesh& tm, * \cgalParamBegin{throw_on_self_intersection} if `true`, * the set of triangles closed to the intersection of `tm` and `clipper` will be * checked for self-intersections and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` - * will be thrown if at least one is found. + * will be thrown if at least one is found. Default value is `false`. * \cgalParamEnd * \cgalParamBegin{clip_volume} if `true` and `tm` is closed, the clipping will be done on * the volume \link coref_def_subsec bounded \endlink by `tm` rather than on its surface - * (i.e., `tm` will be kept closed). + * (i.e., `tm` will be kept closed). Default value is `false`. * \cgalParamEnd - * \cgalParamBegin{use_compact_clipper} if `false` and `clip_volume` is `false` and `tm` is open, the parts of `tm` coplanar with `clipper` - * will not be part of the output. + * \cgalParamBegin{use_compact_clipper} if `false`, the parts of `tm` coplanar with `clipper` + * will not be part of the output. Default value is `true`. * \cgalParamEnd * \cgalNamedParamsEnd * @@ -476,26 +473,6 @@ clip( TriangleMesh& tm, np_c); } -namespace internal{ -template -bool dispatch_clip_call(TriangleMesh& tm, TriangleMesh& clipper, - const NamedParameters& np, Tag_false) -{ - return clip(tm, clipper, - np.face_index_map(get(CGAL::dynamic_face_property_t(), tm)), - parameters::face_index_map(get(CGAL::dynamic_face_property_t(), clipper))); -} - -template -bool dispatch_clip_call(TriangleMesh& tm, TriangleMesh& clipper, - const NamedParameters& np, Tag_true) -{ - return clip(tm, clipper, - np.face_index_map(get(face_index, tm)), - parameters::face_index_map(get(face_index, clipper))); -} -} - /** * \ingroup PMP_corefinement_grp * clips `tm` by keeping the part that is on the negative side of `plane` (side opposite to its normal vector). @@ -507,8 +484,6 @@ bool dispatch_clip_call(TriangleMesh& tm, TriangleMesh& clipper, * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm)` \endlink * * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`. - * If `TriangleMesh` has an internal property map for `CGAL::face_index_t`, - * as a named parameter, then it must be initialized. * An internal property map for `CGAL::vertex_point_t` must be available. * * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" @@ -525,14 +500,14 @@ bool dispatch_clip_call(TriangleMesh& tm, TriangleMesh& clipper, * \cgalParamBegin{throw_on_self_intersection} if `true`, * the set of triangles closed to the intersection of `tm` and `plane` will be * checked for self-intersections and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` - * will be thrown if at least one is found. + * will be thrown if at least one is found. Default value is `false`. * \cgalParamEnd * \cgalParamBegin{clip_volume} if `true` and `tm` is closed, the clipping will be done on * the volume \link coref_def_subsec bounded \endlink by `tm` rather than on its surface - * (i.e., `tm` will be kept closed). + * (i.e., `tm` will be kept closed). Default value is `false`. * \cgalParamEnd - * \cgalParamBegin{use_compact_clipper} if `false` and `clip_volume` is `false` and `tm` is open, the parts of `tm` coplanar with `plane` - * will not be part of the output. + * \cgalParamBegin{use_compact_clipper} if `false` the parts of `tm` coplanar with `plane` + * will not be part of the output. Default value is `true`. * \cgalNamedParamsEnd * * @return `true` if the output surface mesh is manifold. @@ -570,9 +545,8 @@ bool clip( TriangleMesh& tm, default: break; } - // dispatch is needed because face index map for tm and clipper have to be of the same time - return internal::dispatch_clip_call(tm, clipper, - np, CGAL::graph_has_property()); + + return clip(tm, clipper, np, parameters::all_default()); } @@ -727,8 +701,6 @@ void split( TriangleMesh& tm, * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm)` \endlink * * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`. - * If `TriangleMesh` has an internal property map for `CGAL::face_index_t`, - * as a named parameter, then it must be initialized. * An internal property map for `CGAL::vertex_point_t` must be available. * * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" @@ -775,9 +747,7 @@ bool clip( TriangleMesh& tm, clipper); triangulate_faces(clipper); - // dispatch is needed because face index map for tm and clipper have to be of the same time - return internal::dispatch_clip_call(tm, clipper, - np, CGAL::graph_has_property()); + return clip(tm, clipper, np, parameters::all_default()); } /// \cond SKIP_IN_MANUAL diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h index 9932d96fdc5..a1b1013ae35 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h @@ -151,7 +151,7 @@ connected_component(typename boost::graph_traits::face_descriptor s if (!already_processed.insert(seed_face).second) continue; *out++=seed_face; for(halfedge_descriptor hd : - CGAL::halfedges_around_face(halfedge(seed_face, pmesh), pmesh) ) + halfedges_around_face(halfedge(seed_face, pmesh), pmesh) ) { if(! get(ecmap, edge(hd, pmesh))){ face_descriptor neighbor = face( opposite(hd, pmesh), pmesh ); @@ -177,9 +177,6 @@ connected_component(typename boost::graph_traits::face_descriptor s * \ingroup keep_connected_components_grp * computes for each face the index of the corresponding connected component. * - * A property map for `CGAL::face_index_t` must be either available as an internal property map - * to `pmesh` or provided as one of the \ref pmp_namedparameters "Named Parameters". - * * \tparam PolygonMesh a model of `FaceListGraph` * \tparam FaceComponentMap a model of `WritablePropertyMap` with `boost::graph_traits::%face_descriptor` as key type and @@ -219,13 +216,13 @@ connected_components(const PolygonMesh& pmesh, NamedParameters, internal::No_constraint//default > ::type EdgeConstraintMap; + EdgeConstraintMap ecmap = choose_parameter(get_parameter(np, internal_np::edge_is_constrained), internal::No_constraint()); - typedef typename GetFaceIndexMap::const_type FaceIndexMap; - FaceIndexMap fimap = choose_parameter(get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, pmesh)); + typedef typename GetInitializedFaceIndexMap::const_type FaceIndexMap; + FaceIndexMap fimap = get_initialized_face_index_map(pmesh, np); typename boost::property_traits::value_type i=0; std::vector handled(num_faces(pmesh), false); @@ -329,10 +326,6 @@ std::size_t number_of_connected_components(const PolygonMesh& pmesh) * By default, the size of a face is `1` (and thus the size of a connected component is the number * of faces it contains), but it is also possible to pass custom sizes, such as the area of the face. * - * Property maps for `CGAL::face_index_t` and `CGAL::vertex_index_t` - * must be either available as internal property maps - * to `pmesh` or provided as \ref pmp_namedparameters "Named Parameters". - * * \tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` * \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * @@ -374,10 +367,8 @@ std::size_t keep_largest_connected_components(PolygonMesh& pmesh, using parameters::choose_parameter; using parameters::get_parameter; - // FaceIndexMap - typedef typename GetFaceIndexMap::type FaceIndexMap; - FaceIndexMap fimap = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(boost::face_index, pmesh)); + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap; + FaceIndexMap fimap = CGAL::get_initialized_face_index_map(pmesh, np); // FaceSizeMap typedef typename internal_np::Lookup_named_param_def::type FaceIndexMap; - FaceIndexMap fim = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(boost::face_index, pmesh)); + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap; + FaceIndexMap fim = CGAL::get_initialized_face_index_map(pmesh, np); typedef typename internal_np::Lookup_named_param_def // default - >::type FaceSizeMap; + NamedParameters, + Constant_property_map // default + >::type FaceSizeMap; typedef typename boost::property_traits::value_type Face_size; CGAL_static_assertion((std::is_convertible::value)); @@ -593,7 +578,6 @@ void keep_or_remove_connected_components(PolygonMesh& pmesh , bool keep , const NamedParameters& np) { - typedef PolygonMesh PM; using parameters::choose_parameter; using parameters::get_parameter; @@ -605,10 +589,8 @@ void keep_or_remove_connected_components(PolygonMesh& pmesh typedef typename boost::graph_traits::edge_descriptor edge_descriptor; typedef typename boost::graph_traits::edge_iterator edge_iterator; - //VertexIndexMap - typedef typename GetVertexIndexMap::type VertexIndexMap; - VertexIndexMap vim = choose_parameter(get_parameter(np, internal_np::vertex_index), - get_const_property_map(boost::vertex_index, pmesh)); + typedef typename GetInitializedVertexIndexMap::type VertexIndexMap; + VertexIndexMap vim = get_initialized_vertex_index_map(pmesh, np); std::set cc_to_keep; for(std::size_t i : components_to_keep) @@ -727,10 +709,6 @@ void keep_or_remove_connected_components(PolygonMesh& pmesh * \note If the removal of the connected components makes `pmesh` a non-manifold surface, * then the behavior of this function is undefined. * -* Property maps for `CGAL::vertex_index_t` -* must be either available as internal property map -* to `pmesh` or provided as \ref pmp_namedparameters "Named Parameters". -* * \tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` * \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * \tparam ComponentRange a range of ids convertible to `std::size` @@ -770,11 +748,6 @@ void keep_connected_components(PolygonMesh& pmesh * \note If the removal of the connected components makes `pmesh` a non-manifold surface, * then the behavior of this function is undefined. * -* Property maps for `CGAL::vertex_index_t` -* must be either available as internal property map -* to `pmesh` or provided as \ref pmp_namedparameters "Named Parameters". -* -* * \tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` * \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * \tparam ComponentRange a range of ids convertible to `std::size` @@ -811,10 +784,6 @@ void remove_connected_components(PolygonMesh& pmesh * keeps the connected components not designated by the faces in `components_to_remove`, * and removes the other connected components and all isolated vertices. * -* Property maps for `CGAL::face_index_t` and `CGAL::vertex_index_t` -* must be either available as internal property maps -* to `pmesh` or provided as \ref pmp_namedparameters "Named Parameters". -* * \note If the removal of the connected components makes `pmesh` a non-manifold surface, * then the behavior of this function is undefined. * @@ -841,20 +810,19 @@ void remove_connected_components(PolygonMesh& pmesh , const FaceRange& components_to_remove , const CGAL_PMP_NP_CLASS& np) { - if (components_to_remove.empty()) return; - typedef PolygonMesh PM; - typedef typename boost::graph_traits::face_descriptor face_descriptor; using parameters::choose_parameter; using parameters::get_parameter; - //FaceIndexMap - typedef typename GetFaceIndexMap::type FaceIndexMap; - FaceIndexMap fim = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(boost::face_index, pmesh)); + if (components_to_remove.empty()) + return; + + typedef PolygonMesh PM; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap; + FaceIndexMap fim = CGAL::get_initialized_face_index_map(pmesh, np); - //vector_property_map boost::vector_property_map face_cc(fim); - connected_components(pmesh, face_cc, np); std::vector cc_to_remove; @@ -869,10 +837,6 @@ void remove_connected_components(PolygonMesh& pmesh * keeps the connected components designated by the faces in `components_to_keep`, * and removes the other connected components and all isolated vertices. * -* Property maps for `CGAL::face_index_t` and `CGAL::vertex_index_t` -* must be either available as internal property maps -* to `pmesh` or provided as \ref pmp_namedparameters "Named Parameters". -* * \note If the removal of the connected components makes `pmesh` a non-manifold surface, * then the behavior of this function is undefined. * @@ -905,14 +869,10 @@ void keep_connected_components(PolygonMesh& pmesh using parameters::choose_parameter; using parameters::get_parameter; - //FaceIndexMap - typedef typename GetFaceIndexMap::type FaceIndexMap; - FaceIndexMap fim = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(boost::face_index, pmesh)); + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap; + FaceIndexMap fim = CGAL::get_initialized_face_index_map(pmesh, np); - //vector_property_map boost::vector_property_map face_cc(fim); - connected_components(pmesh, face_cc, np); std::vector cc_to_keep; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h index a6f2f052434..3c4f77b9bbe 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h @@ -17,11 +17,12 @@ #include +#include +#include #include #include #include #include -#include #include namespace CGAL { @@ -39,16 +40,17 @@ namespace internal { template bool recursive_does_bound_a_volume(const TriangleMesh& tm, Vpm& vpm, - Fid_map& fid_map, + Fid_map fid_map, const std::vector& xtrm_vertices, boost::dynamic_bitset<>& cc_handled, const std::vector& face_cc, std::size_t xtrm_cc_id, bool is_parent_outward_oriented) { - typedef boost::graph_traits GT; - typedef typename GT::face_descriptor face_descriptor; - typedef Side_of_triangle_mesh Side_of_tm; + typedef boost::graph_traits Graph_traits; + typedef typename Graph_traits::face_descriptor face_descriptor; + typedef Side_of_triangle_mesh Side_of_tm; + // first check that the orientation of the current cc is consistant with its // parent cc containing it bool new_is_parent_outward_oriented = internal::is_outward_oriented( @@ -170,25 +172,23 @@ enum Boolean_operation_type {UNION = 0, INTERSECTION=1, * \see `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()` */ template -bool does_bound_a_volume(const TriangleMesh& tm, const NamedParameters& np) +bool does_bound_a_volume(const TriangleMesh& tm, + const NamedParameters& np) { - typedef boost::graph_traits GT; - typedef typename GT::vertex_descriptor vertex_descriptor; - typedef typename GetVertexPointMap::const_type Vpm; - typedef typename GetFaceIndexMap::const_type Fid_map; - typedef typename Kernel_traits< - typename boost::property_traits::value_type >::Kernel Kernel; + typedef boost::graph_traits Graph_traits; + typedef typename Graph_traits::vertex_descriptor vertex_descriptor; + typedef typename GetVertexPointMap::const_type Vpm; + typedef typename boost::property_traits::value_type Point; + typedef typename Kernel_traits::Kernel Kernel; if (!is_closed(tm)) return false; if (!is_triangle_mesh(tm)) return false; Vpm vpm = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), - get_const_property_map(boost::vertex_point, tm)); + get_const_property_map(boost::vertex_point, tm)); - Fid_map fid_map = parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, tm)); + typedef typename GetInitializedFaceIndexMap::const_type Fid_map; + Fid_map fid_map = get_initialized_face_index_map(tm, np); std::vector face_cc(num_faces(tm), std::size_t(-1)); @@ -203,11 +203,11 @@ bool does_bound_a_volume(const TriangleMesh& tm, const NamedParameters& np) boost::dynamic_bitset<> cc_handled(nb_cc, 0); // extract a vertex with max z coordinate for each connected component - std::vector xtrm_vertices(nb_cc, GT::null_vertex()); + std::vector xtrm_vertices(nb_cc, Graph_traits::null_vertex()); for(vertex_descriptor vd : vertices(tm)) { std::size_t cc_id = face_cc[get(fid_map, face(halfedge(vd, tm), tm))]; - if (xtrm_vertices[cc_id]==GT::null_vertex()) + if (xtrm_vertices[cc_id] == Graph_traits::null_vertex()) xtrm_vertices[cc_id]=vd; else if (get(vpm, vd).z()>get(vpm,xtrm_vertices[cc_id]).z()) @@ -514,21 +514,14 @@ corefine_and_compute_boolean_operations( typedef std::tuple Edge_mark_map_tuple; -// Face index point maps - typedef typename GetFaceIndexMap::type Fid_map; - typedef typename GetFaceIndexMap::type Fid_map2; - CGAL_USE_TYPE(Fid_map2); - CGAL_assertion_code( - static const bool same_fidmap = (boost::is_same::value);) - CGAL_static_assertion(same_fidmap); + // Face index point maps + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap1; + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap2; - Fid_map fid_map1 = parameters::choose_parameter(parameters::get_parameter(np1, internal_np::face_index), - get_property_map(boost::face_index, tm1)); - Fid_map fid_map2 = parameters::choose_parameter(parameters::get_parameter(np2, internal_np::face_index), - get_property_map(boost::face_index, tm2)); -// User visitor + FaceIndexMap1 fid_map1 = get_initialized_face_index_map(tm1, np1); + FaceIndexMap2 fid_map2 = get_initialized_face_index_map(tm2, np2); + + // User visitor typedef typename internal_np::Lookup_named_param_def < internal_np::graph_visitor_t, NamedParameters1, @@ -541,7 +534,8 @@ corefine_and_compute_boolean_operations( typedef Corefinement::Face_graph_output_builder Algo_visitor; Ecm_in ecm_in(tm1,tm2,ecm1,ecm2); Edge_mark_map_tuple ecms_out(ecm_out_0, ecm_out_1, ecm_out_2, ecm_out_3); - Ob ob(tm1, tm2, vpm1, vpm2, fid_map1, fid_map2, ecm_in, - vpm_out_tuple, ecms_out, uv, output); + Ob ob(tm1, tm2, vpm1, vpm2, fid_map1, fid_map2, ecm_in, vpm_out_tuple, ecms_out, uv, output); // special case used for clipping open meshes if ( parameters::choose_parameter( parameters::get_parameter(np1, internal_np::use_bool_op_to_clip_surface), @@ -933,8 +926,7 @@ namespace experimental { const NamedParameters& np) { // Vertex point maps - typedef typename GetVertexPointMap::type Vpm; + typedef typename GetVertexPointMap::type Vpm; Vpm vpm = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), get_property_map(boost::vertex_point, tm)); @@ -1014,10 +1006,9 @@ namespace experimental { Vpm vpm = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), get_property_map(boost::vertex_point, tm)); // Face index map - typedef typename GetFaceIndexMap::type Fid_map; - Fid_map fid_map = parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_property_map(boost::face_index, tm)); + typedef typename GetInitializedFaceIndexMap::type Fid_map; + Fid_map fid_map = get_initialized_face_index_map(tm, np); + // Edge is-constrained maps typedef typename internal_np::Lookup_named_param_def < internal_np::edge_is_constrained_t, diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/detect_features.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/detect_features.h index ffbb806305a..55b007d16b3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/detect_features.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/detect_features.h @@ -138,11 +138,6 @@ detect_surface_patches(PolygonMesh& p, EdgeIsFeatureMap eif, const NamedParameters& np) { - //extract types from NPs - typename GetFaceIndexMap::const_type - fimap = parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, p)); - int offset = static_cast( parameters::choose_parameter(parameters::get_parameter(np, internal_np::first_index), 1)); @@ -150,11 +145,12 @@ detect_surface_patches(PolygonMesh& p, internal::PatchIdMapWrapper::value_type> wrapmap(patch_id_map, offset); + return connected_components(p, wrapmap, parameters::edge_is_constrained_map(eif) - .face_index_map(fimap)); - + .face_index_map(CGAL::get_initialized_face_index_map(p, np))); } + template typename boost::graph_traits::faces_size_type detect_surface_patches(PolygonMesh& p, @@ -373,8 +369,6 @@ namespace internal * computing a * surface patch id for each face. * - * A property map for `CGAL::face_index_t` must be either available - * as an internal property map to `pmesh` or provided as one of the Named Parameters. * * \tparam PolygonMesh a model of `FaceGraph` * \tparam FT a number type. It is diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h index 2f93d176784..602ae2a2fde 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h @@ -60,7 +60,8 @@ namespace params=PMP::parameters; template + template static void fill_polylines_to_skip( Intersection_polylines& polylines, @@ -223,8 +226,8 @@ class Face_graph_output_builder const std::vector& tm2_patch_ids, const boost::dynamic_bitset<>& patches_of_tm1_used, const boost::dynamic_bitset<>& patches_of_tm2_used, - const FIM& fids1, - const FIM& fids2, + const FIM1 fids1, + const FIM2 fids2, const TM& tm1, const TM& tm2) { @@ -341,18 +344,17 @@ class Face_graph_output_builder public: - Face_graph_output_builder( TriangleMesh& tm1, - TriangleMesh& tm2, - const VertexPointMap &vpm1, - const VertexPointMap &vpm2, - const FaceIdMap& fids1, - const FaceIdMap& fids2, - EdgeMarkMapBind& marks_on_input_edges, + Face_graph_output_builder(TriangleMesh& tm1, + TriangleMesh& tm2, + const VertexPointMap vpm1, + const VertexPointMap vpm2, + FaceIdMap1 fids1, + FaceIdMap2 fids2, + EdgeMarkMapBind& marks_on_input_edges, const VpmOutTuple& output_vpms, - EdgeMarkMapTuple& out_edge_mark_maps, - UserVisitor& user_visitor, - const std::array< - boost::optional, 4 >& requested_output) + EdgeMarkMapTuple& out_edge_mark_maps, + UserVisitor& user_visitor, + const std::array, 4 >& requested_output) : tm1(tm1), tm2(tm2) , vpm1(vpm1), vpm2(vpm2) , fids1(fids1), fids2(fids2) @@ -460,9 +462,12 @@ public: Intersection_edge_map& intersection_edges1 = mesh_to_intersection_edges[&tm1]; Intersection_edge_map& intersection_edges2 = mesh_to_intersection_edges[&tm2]; - // this will initialize face indices if the face index map is writable. - helpers::init_face_indices(tm1, fids1); - helpers::init_face_indices(tm2, fids2); + // The property map must be either writable or well-initialized + if(!BGL::internal::is_index_map_valid(fids1, num_faces(tm1), faces(tm1))) + BGL::internal::initialize_face_index_map(fids1, tm1); + + if(!BGL::internal::is_index_map_valid(fids2, num_faces(tm2), faces(tm2))) + BGL::internal::initialize_face_index_map(fids2, tm2); // bitset to identify coplanar faces boost::dynamic_bitset<> tm1_coplanar_faces(num_faces(tm1), 0); @@ -620,9 +625,8 @@ public: std::size_t nb_patches_tm1 = PMP::connected_components(tm1, bind_property_maps(fids1,make_property_map(&tm1_patch_ids[0])), - params::edge_is_constrained_map( - is_marked_1) - .face_index_map(fids1)); + params::edge_is_constrained_map(is_marked_1) + .face_index_map(fids1)); std::vector tm1_patch_sizes(nb_patches_tm1, 0); for(std::size_t i : tm1_patch_ids) @@ -634,9 +638,8 @@ public: std::size_t nb_patches_tm2 = PMP::connected_components(tm2, bind_property_maps(fids2,make_property_map(&tm2_patch_ids[0])), - params::edge_is_constrained_map( - is_marked_2) - .face_index_map(fids2)); + params::edge_is_constrained_map(is_marked_2) + .face_index_map(fids2)); std::vector tm2_patch_sizes(nb_patches_tm2, 0); for(Node_id i : tm2_patch_ids) @@ -1245,9 +1248,8 @@ public: polyline_lengths.push_back(polyline_info.second+1); } - typedef Patch_container Patches; + typedef Patch_container Patches1; + typedef Patch_container Patches2; boost::unordered_set border_nm_vertices; // only used if used_to_clip_a_surface == true if (used_to_clip_a_surface) @@ -1279,8 +1281,8 @@ public: } //store the patch description in a container to avoid recomputing it several times - Patches patches_of_tm1( tm1, tm1_patch_ids, fids1, intersection_edges1, nb_patches_tm1), - patches_of_tm2( tm2, tm2_patch_ids, fids2, intersection_edges2, nb_patches_tm2); + Patches1 patches_of_tm1(tm1, tm1_patch_ids, fids1, intersection_edges1, nb_patches_tm1); + Patches2 patches_of_tm2(tm2, tm2_patch_ids, fids2, intersection_edges2, nb_patches_tm2); // for each boolean operation, define two bitsets of patches contributing // to the result @@ -1460,11 +1462,12 @@ public: // operation in tm1 with removal (and optionally inside-out) delayed // First backup the border edges of patches to be used - Patches tmp_patches_of_tm1(tm1, - patches_of_tm1.patch_ids, - patches_of_tm1.fids, - patches_of_tm1.is_intersection_edge, - patches_of_tm1.patches.size()); + Patches1 tmp_patches_of_tm1(tm1, + patches_of_tm1.patch_ids, + patches_of_tm1.fids, + patches_of_tm1.is_intersection_edge, + patches_of_tm1.patches.size()); + boost::dynamic_bitset<> patches_of_tm1_removed = ~patches_of_tm1_used[inplace_operation_tm1]; for (std::size_t i = patches_of_tm1_removed.find_first(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Output_builder_for_autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Output_builder_for_autorefinement.h index 3656f46aea3..031d23a1c36 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Output_builder_for_autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Output_builder_for_autorefinement.h @@ -214,9 +214,6 @@ public: const boost::dynamic_bitset<>& is_node_of_degree_one, const Mesh_to_map_node&) { - // this will initialize face indices if the face index map is writable. - helpers::init_face_indices(tm, fids); - // first build an unordered_map mapping a vertex to its node id + a set // of all intersection edges typedef boost::unordered_set Intersection_edge_map; @@ -239,8 +236,9 @@ public: intersection_edges.insert(edge(p.second.h2, tm)); } - // this will initialize face indices if the face index map is writable. - helpers::init_face_indices(tm, fids); + // The property map must be either writable or well-initialized + if(!BGL::internal::is_index_map_valid(fids, num_faces(tm), faces(tm))) + BGL::internal::initialize_face_index_map(fids, tm); // bitset to identify coplanar faces boost::dynamic_bitset<> tm_coplanar_faces(num_faces(tm), 0); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h index 3e9b5499feb..c188231238c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h @@ -424,7 +424,7 @@ template void extract_patch_simplices( std::size_t patch_id, PolygonMesh& pm, - const FaceIndexMap& fids, + const FaceIndexMap fids, const std::vector& patch_ids, std::vector::face_descriptor>& patch_faces, std::set::vertex_descriptor>& interior_vertices, @@ -480,13 +480,13 @@ struct Patch_container{ // external data members PolygonMesh& pm; const std::vector& patch_ids; - const FaceIndexMap& fids; + const FaceIndexMap fids; const IsIntersectionEdge& is_intersection_edge; // constructor Patch_container( PolygonMesh& pm, const std::vector& patch_ids, - const FaceIndexMap& fids, + const FaceIndexMap fids, const IsIntersectionEdge& is_intersection_edge, std::size_t nb_patches ) : patches(nb_patches) @@ -1010,14 +1010,15 @@ template < class TriangleMesh, class EdgeMarkMap2, class EdgeMarkMapOut, class IntersectionPolylines, - class PatchContainer, + class PatchContainer1, + class PatchContainer2, class UserVisitor> void fill_new_triangle_mesh( TriangleMesh& output, const boost::dynamic_bitset<>& patches_of_tm1_to_import, const boost::dynamic_bitset<>& patches_of_tm2_to_import, - PatchContainer& patches_of_tm1, - PatchContainer& patches_of_tm2, + PatchContainer1& patches_of_tm1, + PatchContainer2& patches_of_tm2, bool reverse_orientation_of_patches_from_tm1, bool reverse_orientation_of_patches_from_tm2, const IntersectionPolylines& polylines, @@ -1256,7 +1257,8 @@ void disconnect_patches( } template & patches_of_tm1_to_keep, const boost::dynamic_bitset<>& patches_of_tm2_to_import, - PatchContainer& patches_of_tm1, - PatchContainer& patches_of_tm2, + PatchContainer1& patches_of_tm1, + PatchContainer2& patches_of_tm2, bool reverse_patch_orientation_tm2, const IntersectionPolylines& polylines, const VertexPointMap& vpm1, @@ -1416,7 +1418,8 @@ remove_patches(TriangleMesh& tm, } template & patches_of_tm1_to_keep, const boost::dynamic_bitset<>& patches_of_tm2_to_import, - PatchContainer& patches_of_tm1, - PatchContainer& patches_of_tm2, + PatchContainer1& patches_of_tm1, + PatchContainer2& patches_of_tm2, bool reverse_patch_orientation_tm1, bool reverse_patch_orientation_tm2, const VertexPointMap& vpm1, @@ -1485,14 +1488,15 @@ void compute_inplace_operation( template void compute_border_edge_map( const TriangleMesh& tm1, const TriangleMesh& tm2, const IntersectionPolylines& polylines, - PatchContainer& patches_of_tm1, - PatchContainer& patches_of_tm2, + PatchContainer1& patches_of_tm1, + PatchContainer2& patches_of_tm2, EdgeMap& tm2_edge_to_tm1_edge) { typedef boost::graph_traits GT; @@ -1520,7 +1524,8 @@ void compute_border_edge_map( template & patches_of_tm1_to_keep, const boost::dynamic_bitset<>& patches_of_tm2_to_import, - PatchContainer& patches_of_tm1, - PatchContainer& patches_of_tm2, + PatchContainer1& patches_of_tm1, + PatchContainer2& patches_of_tm2, bool reverse_patch_orientation_tm1, bool reverse_patch_orientation_tm2, const VertexPointMap& vpm1, @@ -1631,9 +1636,22 @@ void remove_unused_polylines( halfedge_descriptor h = halfedge(v, tm), start=GT::null_halfedge(); do{ + + halfedge_descriptor tmp_start = h; while ( !is_border(h, tm) || is_border(opposite(h, tm), tm) ) + { h = opposite(next(h, tm), tm); + if (tmp_start==h) break; + } + if( !is_border(h, tm) ) + { + // nothing to do: the vertex has already been updated and is now in the middle of a patch kept. + // This function can be called after the stitching of the patches kept, the vertex halfedge + // can have been updated and no border halfedge might be found + break; + } halfedge_descriptor in = h; + if (start==GT::null_halfedge()) start=in; else diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h index e5ddeadf013..f5cdff44e23 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h @@ -1513,7 +1513,9 @@ private: // tag patch border halfedges for(halfedge_descriptor h : halfedges(mesh_)) { - if (status(h)==PATCH && status(opposite(h, mesh_))!=PATCH) + if (status(h) == PATCH + && ( status(opposite(h, mesh_)) != PATCH + || get_patch_id(face(h, mesh_)) != get_patch_id(face(opposite(h, mesh_), mesh_)))) { set_status(h, PATCH_BORDER); has_border_ = true; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/helper.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/helper.h new file mode 100644 index 00000000000..e43e37bebdf --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/helper.h @@ -0,0 +1,136 @@ +// Copyright (c) 2018, 2019 GeometryFactory (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) : Mael Rouxel-Labbé + +#ifndef CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAPPING_HELPER_H +#define CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAPPING_HELPER_H + +#include + +#include +#include +#include +#include + +namespace CGAL { +namespace Polygon_mesh_processing { +namespace internal { + +template +void vertices_as_halfedges(const VertexRange& vertex_range, + const PolygonMesh& pmesh, + HalfedgeOutputIterator out) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + for(vertex_descriptor v : vertex_range) + *out++ = halfedge(v, pmesh); +} + +// Assigns at each vertex the 'tolerance' value as tolerance, but bounded by a percentage of the length of its shortest incident edge +template +void assign_tolerance_with_local_edge_length_bound(const HalfedgeRange& halfedge_range, + ToleranceMap& tolerance_map, + const typename GetGeomTraits::type::FT tolerance, + PolygonMesh& mesh, + const NamedParameters& np) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetVertexPointMap::type VPM; + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + + using parameters::get_parameter; + using parameters::choose_parameter; + + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_property_map(vertex_point, mesh)); + + for(halfedge_descriptor hd : halfedge_range) + { + const vertex_descriptor vd = target(hd, mesh); + CGAL::Halfedge_around_target_iterator hit, hend; + boost::tie(hit, hend) = CGAL::halfedges_around_target(vd, mesh); + CGAL_assertion(hit != hend); + + FT sq_length = gt.compute_squared_distance_3_object()(get(vpm, source(*hit, mesh)), + get(vpm, target(*hit, mesh))); + FT min_sq_dist = sq_length; + ++hit; + + for(; hit!=hend; ++hit) + { + sq_length = gt.compute_squared_distance_3_object()(get(vpm, source(*hit, mesh)), + get(vpm, target(*hit, mesh))); + + if(sq_length < min_sq_dist) + min_sq_dist = sq_length; + } + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "tolerance at vd: " << vd << " [" << get(vpm, vd) << "]: min of " + << 0.9 * CGAL::approximate_sqrt(min_sq_dist) << " AND " << tolerance << std::endl; +#endif + put(tolerance_map, vd, CGAL::min(0.9 * CGAL::approximate_sqrt(min_sq_dist), tolerance)); + } +} + +template +void assign_tolerance_with_local_edge_length_bound(const HalfedgeRange& halfedge_range, + ToleranceMap& tolerance_map, + const typename GetGeomTraits::type::FT tolerance, + PolygonMesh& mesh) +{ + return assign_tolerance_with_local_edge_length_bound(halfedge_range, tolerance_map, tolerance, mesh, CGAL::parameters::all_default()); +} + +template +bool is_collinear_with_tolerance(const typename GeomTraits::Point_3& p, // va == vb + const typename GeomTraits::Point_3& pa, + const typename GeomTraits::Point_3& pb, + const GeomTraits& gt) +{ + typedef typename GeomTraits::FT FT; + typedef typename GeomTraits::Vector_3 Vector_3; + + const Vector_3 va = gt.construct_vector_3_object()(p, pa); + const Vector_3 vb = gt.construct_vector_3_object()(p, pb); + const FT sp = gt.compute_scalar_product_3_object()(va, vb); + + // To avoid junctions like: + // ----va vb----- from being locked since it could be needed in ------------- later + // | | ----va vb--- + // | | + if(sp < FT(0)) + return false; + + const FT sq_va_l = gt.compute_squared_distance_3_object()(p, pa); + const FT sq_vb_l = gt.compute_squared_distance_3_object()(p, pb); + const FT sq_cos = 0.99999228397046306; // CGAL::square(std::cos(1°)); + + return (CGAL::square(sp) >= sq_va_l * sq_vb_l * sq_cos); +} + +} // namespace internal +} // namespace Polygon_mesh_processing +} // namespace CGAL + +#endif // CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAPPING_HELPER_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h index 02a0422d5d6..0a1892d486d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h @@ -8,38 +8,49 @@ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // -// Author(s) : Sebastien Loriot -// Mael Rouxel-Labbé +// Author(s) : Mael Rouxel-Labbé +// Sebastien Loriot -#ifndef CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAP_H -#define CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAP_H +#ifndef CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_H +#define CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_H #include +#ifdef CGAL_PMP_SNAP_DEBUG_PP + #ifndef CGAL_PMP_SNAP_DEBUG + #define CGAL_PMP_SNAP_DEBUG + #endif +#endif + +#include +#include + #include #include #include +#include #include #include #include #include -#include #include #include -#include +#include #include #include #include #include +#include +#include -#include -#include -#include +#ifdef CGAL_EIGEN3_ENABLED +#include +#endif #ifdef CGAL_LINKED_WITH_TBB -# include -# include +#include +#include #endif #include @@ -48,912 +59,635 @@ #include #include #include -#include #include +#include #include +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT +#include +#endif + namespace CGAL { namespace Polygon_mesh_processing { namespace internal { -// Assigns at each vertex the 'tolerance' value as tolerance, but bounded by a percentage of the length of its shortest incident edge -template -void assign_tolerance_with_local_edge_length_bound(const HalfedgeRange& hrange, - ToleranceMap& tol_pmap, - const typename GetGeomTraits::type::FT tolerance, - PolygonMesh& mesh, - const SourceNamedParameters& snp) +template +void simplify_range(HalfedgeRange& halfedge_range, + TriangleMesh& tm, + ToleranceMap tolerance_map, + const NamedParameters& np) { + // @todo the simplification below is too naive and will fail to treat complicated zigzaging + // with long edges. + // A real simplification would create a fuzzy area around the border (say the dilation + // of the border polyline by a sphere of radius that continuously interpolates the tolerance + // at each vertex). The border is then simplified to use the least amount of edges possible + // in that fuzzy zone. Need to look into cartography papers, probably. + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + + typedef typename GetVertexPointMap::type VPM; + typedef typename boost::property_traits::reference Point_ref; + using parameters::get_parameter; using parameters::choose_parameter; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + const GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), get_property_map(vertex_point, tm)); - typedef typename GetVertexPointMap::type SVPM; - typedef typename GetGeomTraits::type GT; - typedef typename GT::FT FT; + typedef CGAL::dynamic_halfedge_property_t Halfedge_bool_tag; + typedef typename boost::property_map::type Range_halfedges; - GT gt = choose_parameter(get_parameter(snp, internal_np::geom_traits), GT()); - SVPM svpm = choose_parameter(get_parameter(snp, internal_np::vertex_point), - get_property_map(vertex_point, mesh)); + Range_halfedges range_halfedges = get(Halfedge_bool_tag(), tm); + for(halfedge_descriptor h : halfedge_range) + put(range_halfedges, h, true); - for(halfedge_descriptor hd : hrange) + CGAL_postcondition_code(const std::size_t initial_n = halfedge_range.size();) + + std::set edges_to_test(halfedge_range.begin(), halfedge_range.end()); + + int collapsed_n = 0; + while(!edges_to_test.empty()) { - const vertex_descriptor vd = target(hd, mesh); - CGAL::Halfedge_around_target_iterator hit, hend; - boost::tie(hit, hend) = CGAL::halfedges_around_target(vd, mesh); - CGAL_assertion(hit != hend); + const halfedge_descriptor h = *(edges_to_test.begin()); + edges_to_test.erase(edges_to_test.begin()); - FT sq_length = gt.compute_squared_distance_3_object()(get(svpm, source(*hit, mesh)), - get(svpm, target(*hit, mesh))); - FT min_sq_dist = sq_length; - ++hit; + const vertex_descriptor vs = source(h, tm); + const vertex_descriptor vt = target(h, tm); + const Point_ref ps = get(vpm, vs); + const Point_ref pt = get(vpm, vt); - for(; hit!=hend; ++hit) + // @fixme what if the source vertex is not to be snapped? Tolerance cannot be obtained... + // and where should the post-collapse vertex be since we can't move the source vertex... + // --> simply don't collapse? + const FT min_tol = (std::min)(get(tolerance_map, vs), get(tolerance_map, vt)); + const FT max_tol = (std::max)(get(tolerance_map, vs), get(tolerance_map, vt)); + + if(gt.compare_squared_distance_3_object()(ps,pt,CGAL::square(max_tol))==SMALLER) { - sq_length = gt.compute_squared_distance_3_object()(get(svpm, source(*hit, mesh)), - get(svpm, target(*hit, mesh))); + const halfedge_descriptor prev_h = prev(h, tm); + const halfedge_descriptor next_h = next(h, tm); - if(sq_length < min_sq_dist) - min_sq_dist = sq_length; + // check that the border has at least 4 edges not to create degenerate volumes + if(border_size(h, tm) >= 4) + { + const FT h_sq_length = gt.compute_squared_distance_3_object()(ps, pt); + vertex_descriptor v = Euler::collapse_edge(edge(h, tm), tm); + + put(vpm, v, gt.construct_midpoint_3_object()(ps, pt)); + put(tolerance_map, v, min_tol + 0.5 * CGAL::approximate_sqrt(h_sq_length)); + + if(get(range_halfedges, prev_h)) + edges_to_test.insert(prev_h); + if(get(range_halfedges, next_h)) + edges_to_test.insert(next_h); + + ++collapsed_n; + } } + } #ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "tolerance at vd: " /*<< vd */ << " [" << get(svpm, vd) << "]: min of " - << 0.9 * CGAL::approximate_sqrt(min_sq_dist) << " AND " << tolerance << std::endl; -#endif - put(tol_pmap, vd, CGAL::min(0.9 * CGAL::approximate_sqrt(min_sq_dist), tolerance)); - } -} - -template -void assign_tolerance_with_local_edge_length_bound(const HalfedgeRange& hrange, - ToleranceMap& tol_pmap, - const typename GetGeomTraits::type::FT tolerance, - PolygonMesh& mesh) -{ - return assign_tolerance_with_local_edge_length_bound(hrange, tol_pmap, tolerance, mesh, CGAL::parameters::all_default()); -} - -template -struct Snapping_pair -{ - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename GeomTraits::FT FT; - - Snapping_pair(const vertex_descriptor vs_, const vertex_descriptor vt_, const FT sq_dist_) - : vs(vs_), vt(vt_), sq_dist(sq_dist_) - { } - - vertex_descriptor vs; - vertex_descriptor vt; - FT sq_dist; -}; - -template -struct Vertex_proximity_report -{ - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - - typedef typename GeomTraits::FT FT; - typedef typename boost::property_traits::value_type Point; - - Vertex_proximity_report(DistanceMultiIndexContainer& snapping_pairs, - const SVPM& svpm, const PolygonMesh& smesh, - const TVPM& tvpm, const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap, - const GeomTraits& gt) - : - m_snapping_pairs(snapping_pairs), - is_same_mesh((&smesh == &tmesh)), - svpm(svpm), tvpm(tvpm), - tol_pmap(tol_pmap), - gt(gt) - { } - - void operator()(const Box& a, const Box& b) - { - vertex_descriptor va = a.info(); - vertex_descriptor vb = b.info(); - - if(is_same_mesh && va == vb) - return; - - const Point sp = get(svpm, va); - const Point tp = get(tvpm, vb); - const FT tol = get(tol_pmap, va); - - // Don't reject a '0' distance, it still needs to lock the points in place - const FT sq_dist = gt.compute_squared_distance_3_object()(sp, tp); - CGAL::Comparison_result res = CGAL::compare(sq_dist, tol * tol); - -#ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "distance between " /*<< va*/ << " [" << sp << "] and " - /*<< vb*/ << " [" << tp << "]: " << sq_dist - << " (bound: " << tol*tol << ") larger? " << (res == CGAL::LARGER) - << std::endl; + std::cout << "collapsed " << collapsed_n << " edges" << std::endl; #endif - if(res == CGAL::LARGER) - return; + std::vector new_range; + new_range.reserve(halfedge_range.size()); - m_snapping_pairs.insert(Snapping_pair(va, vb, sq_dist)); - } + for(halfedge_descriptor h : halfedges(tm)) + if(get(range_halfedges, h)) + new_range.push_back(h); -private: - DistanceMultiIndexContainer& m_snapping_pairs; + halfedge_range = HalfedgeRange(new_range.begin(), new_range.end()); - const bool is_same_mesh; - const SVPM& svpm; - const TVPM& tvpm; - const ToleranceMap& tol_pmap; - const GeomTraits& gt; -}; - -} // namespace internal - -namespace experimental { - -// This is the function if you know what you're doing with the ranges -// -// \ingroup PMP_repairing_grp -// -// Attempts to snap the vertices in `source_hrange` onto the vertices in `target_hrange`. -// A vertex of the source range is only snapped to a vertex of the target mesh -// if its distance to the target mesh vertex is smaller than a user-chosen bound. -// If a source vertex can be snapped onto multiple vertices of the target -// range, the closest target vertex is used. -// If multiple vertices within the source range could be snapped onto the same target vertex, -// the source vertex closest to the target vertex will be snapped. Other source vertices will try to snap -// to free target vertices until they find a valid target, or until there is no more target -// to snap to (within the tolerance). -// -// @warning This function does not give any guarantee on the conformity between the source and target meshes after the snapping. -// @warning This function does not merge vertices together. -// -// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` -// @tparam SourceHalfedgeRange a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` -// @tparam TargetHalfedgeRange a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` -// @tparam ToleranceMap a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` -// and value type `GetGeomTraits::type::FT` -// @tparam SourceNamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" -// @tparam TargetNamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" -// -// @param source_hrange a range of vertices of the source mesh whose positions can be changed. -// the vertices must be border vertices of `smesh`. -// @param smesh the source mesh whose border vertices might be moved -// @param target_hrange a range of vertices of the target mesh which are potential new positions -// for the vertices in the source range -// @param tmesh the target mesh to which the vertices in `target_hrange` belong -// @param tol_pmap a tolerance map associating to each vertex of the source range a tolerance value: -// potential projection targets are sought in a sphere centered at the vertex and -// whose radius is the tolerance value. -// @param snp optional \ref pmp_namedparameters "Named Parameters" related to the source mesh, -// amongst those described below: -// -// \cgalNamedParamsBegin -// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of the source mesh. -// The type of this map is model of `ReadWritePropertyMap`. -// If this parameter is omitted, an internal property map for -// `CGAL::vertex_point_t` must be available in `PolygonMesh` -// \cgalParamEnd -// \cgalParamBegin{geom_traits} a geometric traits class instance. -// The traits class must provide the nested types `Point_3` and `Vector_3`, -// and the nested functors : -// - `Construct_bbox_3` to construct a bounding box of a point, -// - `Compute_squared_distance_3` to compute the distance between two points, -// -// and, for each functor `Foo`, a function `Foo foo_object()` -// \cgalParamEnd -// \cgalNamedParamsEnd -// -// @param tnp optional \ref pmp_namedparameters "Named Parameters" related to the target mesh, -// amongst those described below: -// -// \cgalNamedParamsBegin -// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of the target mesh. -// The type of this map is model of `ReadablePropertyMap`. -// If this parameter is omitted, an internal property map for -// `CGAL::vertex_point_t` must be available in `PolygonMesh` -// \cgalParamEnd -// \cgalNamedParamsEnd -// -// @return the number of snapped vertices -// -// @sa `merge_duplicated_vertices_in_boundary_cycles()` -// -template -std::size_t snap_vertex_range_onto_vertex_range(const SourceHalfedgeRange& source_hrange, - PolygonMesh& smesh, - const TargetHalfedgeRange& target_hrange, - const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap, - const SourceNamedParameters& snp, - const TargetNamedParameters& tnp) -{ - using parameters::get_parameter; - using parameters::choose_parameter; - - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - - typedef CGAL::Box_intersection_d::Box_with_info_d Box; - - typedef typename GetVertexPointMap::type SVPM; - typedef typename GetVertexPointMap::const_type TVPM; - typedef typename boost::property_traits::value_type Point; - - typedef typename GetGeomTraits::type GT; - typedef typename GT::FT FT; - - if(is_empty_range(source_hrange.begin(), source_hrange.end()) || - is_empty_range(target_hrange.begin(), target_hrange.end())) - return 0; - - CGAL_static_assertion((std::is_same::value)); - - GT gt = choose_parameter(get_parameter(snp, internal_np::geom_traits), GT()); - - SVPM svpm = choose_parameter(get_parameter(snp, internal_np::vertex_point), - get_property_map(vertex_point, smesh)); - TVPM tvpm = choose_parameter(get_parameter(tnp, internal_np::vertex_point), - get_const_property_map(vertex_point, tmesh)); - -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "Snapping vertices to vertices. Range sizes: " - << std::distance(source_hrange.begin(), source_hrange.end()) << " and " - << std::distance(target_hrange.begin(), target_hrange.end()) << std::endl; - - if(&smesh == &tmesh) - std::cout << "same mesh!" << std::endl; -#endif - - // Try to snap vertices - std::vector boxes; - std::unordered_set unique_vertices; - for(halfedge_descriptor hd : source_hrange) - { - const vertex_descriptor vd = target(hd, smesh); - if(!unique_vertices.insert(vd).second) - continue; // if 'vd' appears multiple times on the border, move it only once - - // only making the box a little larger, but the final tolerance is not changed - const double eps = 1.01 * CGAL::to_double(get(tol_pmap, vd)); - - const Bbox_3 pb = gt.construct_bbox_3_object()(get(svpm, vd)); - const Bbox_3 b(pb.xmin() - eps, pb.ymin() - eps, pb.zmin() - eps, - pb.xmax() + eps, pb.ymax() + eps, pb.zmax() + eps); - boxes.push_back(Box(b, vd)); - } - - std::vector target_boxes; - for(halfedge_descriptor hd : target_hrange) - { - const vertex_descriptor vd = target(hd, tmesh); - const Point& p = get(tvpm, vd); - target_boxes.push_back(Box(gt.construct_bbox_3_object()(p), vd)); - } - - // Use a multi index to sort easily by sources, targets, AND distance. - // Then, look up the distances in increasing order, and snap whenever the source and the target - // have both not been snapped yet. - typedef internal::Snapping_pair Snapping_pair; - typedef boost::multi_index::multi_index_container< - Snapping_pair, - boost::multi_index::indexed_by< - boost::multi_index::ordered_non_unique< - BOOST_MULTI_INDEX_MEMBER(Snapping_pair, vertex_descriptor, vs)>, - boost::multi_index::ordered_non_unique< - BOOST_MULTI_INDEX_MEMBER(Snapping_pair, vertex_descriptor, vt)>, - boost::multi_index::ordered_non_unique< - BOOST_MULTI_INDEX_MEMBER(Snapping_pair, FT, sq_dist)> - > - > Snapping_pair_container; - - typedef internal::Vertex_proximity_report Reporter; - - Snapping_pair_container snapping_pairs; - Reporter vpr(snapping_pairs, svpm, smesh, tvpm, tmesh, tol_pmap, gt); - - // Shenanigans to pass a reference as callback (which is copied by value by 'box_intersection_d') - std::function callback(std::ref(vpr)); - - CGAL::box_intersection_d(boxes.begin(), boxes.end(), - target_boxes.begin(), target_boxes.end(), - callback); - -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << snapping_pairs.size() << " snappable pair(s)!" << std::endl; -#endif - - if(snapping_pairs.empty()) - return 0; - - // Sorted views of the container - typedef typename Snapping_pair_container::template nth_index<0>::type Container_by_source; - typedef typename Snapping_pair_container::template nth_index<1>::type Container_by_target; - typedef typename Snapping_pair_container::template nth_index<2>::type Container_by_distance; - - Container_by_source& container_by_source = snapping_pairs.template get<0>(); - Container_by_target& container_by_target = snapping_pairs.template get<1>(); - Container_by_distance& container_by_dist = snapping_pairs.template get<2>(); - - std::size_t counter = 0; - - CGAL_assertion_code(FT prev = -1;) - while(!container_by_dist.empty()) - { - const Snapping_pair& sp = *(container_by_dist.begin()); - const vertex_descriptor vs = sp.vs; - const vertex_descriptor vt = sp.vt; - CGAL_assertion(sp.sq_dist >= prev); - CGAL_assertion_code(prev = sp.sq_dist;) - -#ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "Snapping " /*<< vs*/ << " (" << get(svpm, vs) << ") " - << " to " /*<< vt*/ << " (" << get(tvpm, vt) << ") at dist: " << sp.sq_dist << std::endl; -#endif - - // Collect all the source vertices projecting onto that target vertex - ++counter; - put(svpm, vs, get(tvpm, vt)); - - // 'vs' and 'vt' cannot be used anymore, remove them from the container - container_by_source.erase(vs); - container_by_target.erase(vt); - } - - return counter; + CGAL_postcondition(halfedge_range.size() == initial_n - collapsed_n); } -template -std::size_t snap_vertex_range_onto_vertex_range(const SourceHalfedgeRange& source_hrange, - PolygonMesh& smesh, - const TargetHalfedgeRange& target_hrange, - const PolygonMesh& tmesh, - const SourceNamedParameters& snp, - const TargetNamedParameters& tnp) -{ - typedef typename GetGeomTraits::type GT; - typedef typename GT::FT FT; - typedef CGAL::dynamic_vertex_property_t Vertex_property_tag; - typedef typename boost::property_map::type Tolerance_map; - - Tolerance_map tol_pmap = get(Vertex_property_tag(), smesh); - const FT tol_mx(std::numeric_limits::max()); - internal::assign_tolerance_with_local_edge_length_bound(source_hrange, tol_pmap, tol_mx, smesh, snp); - - return snap_vertex_range_onto_vertex_range(source_hrange, smesh, target_hrange, tmesh, tol_pmap, snp, tnp); -} - -template -std::size_t snap_vertex_range_onto_vertex_range(const SourceHalfedgeRange& source_hrange, - PolygonMesh& smesh, - const TargetHalfedgeRange& target_hrange, - const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap) -{ - return snap_vertex_range_onto_vertex_range(source_hrange, smesh, target_hrange, tmesh, tol_pmap, - CGAL::parameters::all_default(), - CGAL::parameters::all_default()); -} - -template -std::size_t snap_vertex_range_onto_vertex_range(const SourceHalfedgeRange& source_hrange, - PolygonMesh& smesh, - const TargetHalfedgeRange& target_hrange, - const PolygonMesh& tmesh) -{ - return snap_vertex_range_onto_vertex_range(source_hrange, smesh, target_hrange, tmesh, - CGAL::parameters::all_default(), - CGAL::parameters::all_default()); -} - -template -std::size_t snap_vertex_range_onto_vertex_range(PolygonMesh& smesh, const PolygonMesh& tmesh) -{ - return snap_vertex_range_onto_vertex_range(halfedges(smesh), smesh, halfedges(tmesh), tmesh); -} - -template -std::size_t snap_border_vertices_onto_vertex_range(PolygonMesh& smesh, - const HalfedgeRange& target_hrange, - const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap) -{ - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - - std::vector border_vertices; - border_halfedges(smesh, std::back_inserter(border_vertices)); - - return snap_vertex_range_onto_vertex_range(border_vertices, smesh, target_hrange, tmesh, tol_pmap); -} - -template -std::size_t snap_border_vertices_onto_vertex_range(PolygonMesh& smesh, - const HalfedgeRange& target_hrange, - const PolygonMesh& tmesh) -{ - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - - std::vector border_vertices; - border_halfedges(smesh, std::back_inserter(border_vertices)); - - return snap_vertex_range_onto_vertex_range(border_vertices, smesh, target_hrange, tmesh); -} - -template -std::size_t snap_border_vertices_onto_border_vertices(PolygonMesh& smesh, - const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap) -{ - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - - std::vector sborder_vertices; - border_halfedges(smesh, std::back_inserter(sborder_vertices)); - - std::vector tborder_vertices; - border_halfedges(tmesh, std::back_inserter(tborder_vertices)); - - return snap_vertex_range_onto_vertex_range(sborder_vertices, smesh, tborder_vertices, tmesh, tol_pmap); -} - -// \ingroup PMP_repairing_grp -// -// Attempts to snap the border vertices of the source mesh onto the vertices of the target mesh. -// -// A vertex of the source range is only snapped to a vertex of the target mesh -// if its distance to the target mesh vertex is smaller than a user-chosen bound. -// If any source vertex can be snapped onto multiple vertices of the target -// range, the closest one is chosen. -// If multiple vertices within the source range could be snapped onto the same target vertex, -// the source vertex closest to the target vertex will be snapped. Other source vertices will try to snap -// to free target vertices until they find a valid target, or until there is no more target -// to snap to (within the tolerance). -// -// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` -// @tparam ToleranceMap a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` -// and value type the number type associated with the traits of the mesh. -// -// @param smesh the source mesh whose border vertices might be moved -// @param tmesh the target mesh whose vertices are potential projection targets -// @param tol_pmap a tolerance map associating to each vertex of the source range a tolerance value: -// potential projection targets are sought in a sphere centered at the vertex and -// whose radius is the tolerance value. -// -// @pre `smesh` and `tmesh` are different meshes -// -// \return the number of snapped vertices -// -template -std::size_t snap_border_vertices_onto_vertex_range(PolygonMesh& smesh, - const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap) -{ - return snap_border_vertices_onto_vertex_range(smesh, halfedges(tmesh), tmesh, tol_pmap); -} - -template -std::size_t snap_border_vertices_onto_vertex_range(PolygonMesh& smesh, const PolygonMesh& tmesh) -{ - return snap_border_vertices_onto_vertex_range(smesh, halfedges(tmesh), tmesh); -} - -} // namespace experimental - -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace internal { - // Adapted from -template +template class Projection_traits { - typedef typename AABBTraits::FT FT; - typedef typename AABBTraits::Point_3 Point; - typedef typename AABBTraits::Primitive Primitive; - typedef typename AABBTraits::Bounding_box Bounding_box; - typedef typename AABBTraits::Primitive::Id Primitive_id; - typedef typename AABBTraits::Point_and_primitive_id Point_and_primitive_id; - typedef typename AABBTraits::Object_and_primitive_id Object_and_primitive_id; + typedef typename AABBTraits::FT FT; + typedef typename AABBTraits::Point_3 Point; + typedef typename AABBTraits::Primitive Primitive; + typedef typename AABBTraits::Bounding_box Bounding_box; + typedef typename AABBTraits::Primitive::Id Primitive_id; + typedef typename AABBTraits::Point_and_primitive_id Point_and_primitive_id; + typedef typename AABBTraits::Object_and_primitive_id Object_and_primitive_id; - typedef CGAL::AABB_node Node; + typedef CGAL::AABB_node Node; + + typedef typename AABBTraits::Geom_traits Geom_traits; + typedef typename Geom_traits::Vector_3 Vector; + typedef typename Geom_traits::Plane_3 Plane; + + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + +#ifdef CGAL_PMP_SNAP_USE_ANISOTROPIC_DISTANCE + void build_metric() + { + Vector hv(get(m_vpm_S, source(m_h, m_tm_S)), get(m_vpm_S, target(m_h, m_tm_S))); + Vector n = CGAL::Polygon_mesh_processing::compute_face_normal(face(opposite(m_h, m_tm_S), m_tm_S), m_tm_S, + CGAL::parameters::geom_traits(m_gt) + .vertex_point_map(m_vpm_S)); + Vector pn = m_gt.construct_cross_product_vector_3_object()(hv, n); + Plane pl(get(m_vpm_S, target(m_h, m_tm_S)), pn); + + Vector b1 = pl.base1(); + Vector b2 = pl.base2(); + + internal::normalize(b1, m_gt); + internal::normalize(b2, m_gt); + internal::normalize(pn, m_gt); + + Eigen::Matrix3d eigen_m; + eigen_m(0,0) = b1.x(); eigen_m(0,1) = b2.x(); eigen_m(0,2) = pn.x(); + eigen_m(1,0) = b1.y(); eigen_m(1,1) = b2.y(); eigen_m(1,2) = pn.y(); + eigen_m(2,0) = b1.z(); eigen_m(2,1) = b2.z(); eigen_m(2,2) = pn.z(); + + Eigen::Matrix3d eigen_diag = Eigen::Matrix3d::Zero(); + eigen_diag(0,0) = 1; + eigen_diag(1,1) = 1; + eigen_diag(2,2) = 100; // we scale by 1/sqrt(lambda_0) in the direction of n + + Eigen::Matrix3d eigen_mtransp = eigen_m.transpose(); + m_metric = eigen_m * eigen_diag * eigen_mtransp; + } +#endif + + FT squared_anisotropic_distance(const Point& p, const Point& q) const + { +#ifdef CGAL_PMP_SNAP_USE_ANISOTROPIC_DISTANCE + Vector pq(p, q); + Eigen::Vector3d ev; + ev(0) = pq.x(); + ev(1) = pq.y(); + ev(2) = pq.z(); + + return ev.transpose() * m_metric * ev; +#else + return CGAL::squared_distance(p, q); +#endif + } + + // The idea behind this function is to give priority to projections that are parallel to the edge 'e0' + // whom the query is the target of. This is done by considering an (anisotropic) distance that + // increases the distance if we are not projecting along the vector orthogonal to both the edge 'e0' + // and to the normal of the face, and also by checking the scalar product between the edges. + // The latter is because the distance to the projection point does not entirely reflect + // the alignment of the edges. + // + // This is WIP and likely to evolve... + bool is_better_than_current_best(const FT sq_dist, + const FT scalar_product) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "is_better_than_current_best()" << std::endl; + std::cout << "sq_dist: " << sq_dist << std::endl; + std::cout << "m_sq_adist: " << m_sq_adist << std::endl; + std::cout << "scalar products: " << scalar_product << " " << m_sp_with_closest_edge << std::endl; +#endif + + // Automatically accept much closer tentative targets; automatically reject much farther tentative targets + const FT lambda = 4; // comparing squared distances + if(lambda * sq_dist < m_sq_adist) + return true; + if(lambda * m_sq_adist < sq_dist) + return false; + + return (scalar_product > m_sp_with_closest_edge); + } public: - explicit Projection_traits(const AABBTraits& traits, - const FT sq_tolerance) - : m_traits(traits), + explicit Projection_traits(const halfedge_descriptor h, + const std::size_t patch_id, + const FT sq_tolerance, + const TriangleMesh& tm_S, + const VPMS vpm_S, + const TriangleMesh& tm_T, + const FacePatchMap face_patch_map_T, + const VPMT vpm_T, + const AABBTraits& aabb_traits) + : + m_h(h), + m_patch_id(patch_id), + m_sq_tol(sq_tolerance), + m_tm_S(tm_S), m_vpm_S(vpm_S), + m_tm_T(tm_T), m_face_patch_map_T(face_patch_map_T), m_vpm_T(vpm_T), + m_is_same_mesh((&tm_S == &tm_T)), + m_continue(true), m_closest_point_initialized(false), - m_sq_dist(sq_tolerance) - {} + m_traits(aabb_traits), + m_gt(Geom_traits()) // blame AABB's traits management + { + // not fully convinced that it is still useful after adding scalar product shenanigans +// #define CGAL_PMP_SNAP_USE_ANISOTROPIC_DISTANCE +#ifdef CGAL_PMP_SNAP_USE_ANISOTROPIC_DISTANCE + build_metric(); +#endif - bool go_further() const { return true; } + Vector hv(get(vpm_S, source(h, tm_S)), get(vpm_S, target(h, tm_S))); + m_direction = hv; + CGAL::Polygon_mesh_processing::internal::normalize(m_direction, m_gt); + } + + bool go_further() const { return m_continue; } void intersection(const Point& query, const Primitive& primitive) { - // skip the primitive if one of its endpoints is the query - const typename Primitive::Datum& s = primitive.datum(m_traits.shared_data()); - if(m_traits.equal_3_object()(s[0], query) || m_traits.equal_3_object()(s[1], query)) +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "~~~~ intersection with primitive: " << primitive.id() << std::endl; + std::cout << get(m_vpm_T, source(primitive.id(), m_tm_T)) << std::endl; + std::cout << get(m_vpm_T, target(primitive.id(), m_tm_T)) << std::endl; +#endif + + halfedge_descriptor h = halfedge(primitive.id(), m_tm_T); + if(is_border(h, m_tm_T)) + h = opposite(h, m_tm_T); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "patches: " << get(m_face_patch_map_T, face(h, m_tm_T)) << " " << m_patch_id << std::endl; +#endif + + if(get(m_face_patch_map_T, face(h, m_tm_T)) != m_patch_id) return; - if(!m_closest_point_initialized) + const typename Primitive::Datum& s = primitive.datum(m_traits.shared_data()); + if(m_traits.equal_3_object()(s[0], query) || m_traits.equal_3_object()(s[1], query)) { - m_closest_point_initialized = true; - m_closest_primitive = primitive.id(); - m_closest_point = primitive.reference_point(m_traits.shared_data()); - m_sq_dist = m_traits.squared_distance_object()(query, m_closest_point); + // If we are NOT using the same mesh and the query is (geometrically) equal to one extremity + // of the target edge, we don't want to move the source point away from the target point + // (because we cannot move the target point). + if(!m_is_same_mesh) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "This vertex is stuck because it is equal to a vertex on the target mesh" << std::endl; +#endif + m_closest_point_initialized = false; + m_continue = false; + } + + // skip the primitive if one of its endpoints is the query + return; } - Point new_closest_point = m_traits.closest_point_object()(query, primitive, m_closest_point); - if(!m_traits.equal_3_object()(new_closest_point, m_closest_point)) + // We are searching for a point on the target border that is close to target(h). + // To try and avoid foldings, we penalize potential matches that are roughly in the direction of 'h' + // by using an anisotropic distance that is the Euclidean on the plane orthogonal to the direction, + // and much larger when traveling in the rough direction of 'h'. + // + // Note that we apply this to points that fall within the tolerance ball, so if there is + // only a single candidate that is in a direction we don't like, we still take it. + // + // @todo should the construct_projected_point_3 be anisotropic too? + const Point new_closest_point = m_gt.construct_projected_point_3_object()( + CGAL::internal::Primitive_helper::get_datum(primitive, m_traits), query); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "closest point to primitive: " << new_closest_point << std::endl; +#endif + + const FT sq_ad_to_tentative_closest_pt = squared_anisotropic_distance(query, new_closest_point); + + Vector tentative_dir(get(m_vpm_T, source(primitive.id(), m_tm_T)), + get(m_vpm_T, target(primitive.id(), m_tm_T))); + CGAL::Polygon_mesh_processing::internal::normalize(tentative_dir, m_gt); + const FT sp_with_tentative = CGAL::abs(tentative_dir * m_direction); + + if(!m_closest_point_initialized || + is_better_than_current_best(sq_ad_to_tentative_closest_pt, sp_with_tentative)) { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "is better!" << std::endl; +#endif + + m_closest_point_initialized = true; + m_closest_primitive = primitive.id(); m_closest_point = new_closest_point; - m_sq_dist = m_traits.squared_distance_object()(query, m_closest_point); + m_sq_adist = sq_ad_to_tentative_closest_pt; + m_sp_with_closest_edge = sp_with_tentative; } } bool do_intersect(const Point& query, const Node& node) const { - return m_traits.compare_distance_object()(query, node.bbox(), m_sq_dist) == CGAL::SMALLER; + // This should NOT be the anisotropic distance, as we want to test all targets within the tolerance + return m_traits.compare_distance_object()(query, node.bbox(), m_sq_tol) == CGAL::SMALLER; } const Point& closest_point() const { return m_closest_point; } typename Primitive::Id closest_primitive_id() const { return m_closest_primitive; } bool closest_point_initialized() const { return m_closest_point_initialized; } + FT scalar_product_with_best() const { return m_sp_with_closest_edge; } private: - const AABBTraits& m_traits; + halfedge_descriptor m_h; + const std::size_t m_patch_id; + const FT m_sq_tol; + Vector m_direction; +#ifdef CGAL_PMP_SNAP_USE_ANISOTROPIC_DISTANCE + Eigen::Matrix3d m_metric; +#endif + + const TriangleMesh& m_tm_S; + VPMS m_vpm_S; + const TriangleMesh& m_tm_T; + FacePatchMap m_face_patch_map_T; + VPMT m_vpm_T; + const bool m_is_same_mesh; + + bool m_continue; bool m_closest_point_initialized; - Point m_closest_point; - FT m_sq_dist; - typename Primitive::Id m_closest_primitive; + Point m_closest_point; + FT m_sq_adist; + FT m_sp_with_closest_edge; // scalar product between m_h and the current best edge candidate + + const AABBTraits& m_traits; + Geom_traits m_gt; }; -template -struct Compare_points_along_edge +template +struct Edges_to_split_map_inserter // Parallel { - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename GeomTraits::Point_3 Point; - - Compare_points_along_edge(halfedge_descriptor support, - const GeomTraits& gt, const VPM& vpm, const PolygonMesh& pm) - : gt(gt), m_src(get(vpm, source(support, pm))) - { } - - bool operator()(const Point& p1, const Point& p2) const { - return gt.less_distance_to_point_3_object()(m_src, p1, p2); +#ifdef CGAL_LINKED_WITH_TBB + template + void operator()(EdgeToSplitMap& edges_to_split, + const HalfedgeDescriptor closest_h, + const HalfedgeDescriptor h, + const Point& closest_p) + { + typename EdgeToSplitMap::accessor acc; + edges_to_split.insert(acc, closest_h); + acc->second.emplace_back(h, closest_p); } - - const GeomTraits& gt; - Point m_src; +#endif }; -template -void find_splittable_edge(const std::pair::value_type, - typename GT::FT>& point_with_tolerance, - EdgeToSplitContainer& edges_to_split, +template <> +struct Edges_to_split_map_inserter +{ + template + void operator()(EdgeToSplitMap& edges_to_split, + const HalfedgeDescriptor closest_h, + const HalfedgeDescriptor h, + const Point& closest_p) + { + edges_to_split[closest_h].emplace_back(h, closest_p); + } +}; + +// The UniqueVertex is a pair of a container of vertex_descriptor and FT, representing +// vertices with the same geometric position and their associated snapping tolerance +// (defined as the minimum of the tolerances of the vertices of the bunch) +template +void find_splittable_edge(const VertexWithTolerance& vertex_with_tolerance, + EdgeToSplitMap& edges_to_split, const AABBTree* aabb_tree_ptr, - const TriangleMesh& /* pms */, - const VPM& /* vpms */, - const TriangleMesh& pmt, - const VPM& vpmt, + const TriangleMesh& tm_S, + VertexPatchMap_S vertex_patch_map_S, + VPMS vpm_S, + const TriangleMesh& tm_T, + FacePatchMap_T face_patch_map_T, + VPMT vpm_T, const GT& gt) { - CGAL_USE(vpmt); - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - typedef typename GT::FT FT; - typedef typename boost::property_traits::value_type Point; + typedef typename GT::FT FT; + typedef typename boost::property_traits::value_type Point; + typedef typename boost::property_traits::reference Point_ref; - typedef typename AABBTree::AABB_traits AABB_traits; + typedef typename AABBTree::AABB_traits AABB_traits; - const Point& query = point_with_tolerance.first; - const FT sq_tolerance = CGAL::square(point_with_tolerance.second); + typedef internal::Projection_traits Projection_traits; - // use the current halfedge as hint - internal::Projection_traits traversal_traits(aabb_tree_ptr->traits(), sq_tolerance); + // by construction the whole range has the same position + const halfedge_descriptor h = vertex_with_tolerance.first; + const vertex_descriptor v = target(h, tm_S); + const Point_ref query = get(vpm_S, v); + const FT sq_tolerance = CGAL::square(vertex_with_tolerance.second); + const std::size_t patch_id = get(vertex_patch_map_S, v); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "--------------------------- Query: " << v << " (" << query << ")" << std::endl; +#endif + + Projection_traits traversal_traits(h, patch_id, sq_tolerance, tm_S, vpm_S, + tm_T, face_patch_map_T, vpm_T, aabb_tree_ptr->traits()); aabb_tree_ptr->traversal(query, traversal_traits); if(!traversal_traits.closest_point_initialized()) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Couldn't find any single projection point" << std::endl; +#endif return; + } const Point& closest_p = traversal_traits.closest_point(); // The filtering in the AABB tree checks the dist query <-> node bbox, which might be smaller than // the actual distance between the query <-> closest point - const FT sq_dist_to_closest = gt.compute_squared_distance_3_object()(query, closest_p); - bool is_close_enough = (sq_dist_to_closest <= sq_tolerance); + edge_descriptor closest_e = traversal_traits.closest_primitive_id(); + bool is_close_enough = + gt.compare_squared_distance_3_object()(query, + gt.construct_segment_3_object()(get(vpm_T, source(closest_e, tm_T)), + get(vpm_T, target(closest_e, tm_T))), + sq_tolerance) != LARGER; #ifdef CGAL_PMP_SNAP_DEBUG_PP std::cout << " Closest point: (" << closest_p << ")" << std::endl - << " at distance " << gt.compute_squared_distance_3_object()(query, closest_p) - << " with a tolerance of " << point_with_tolerance.second << " at vertex (squared tol: " << sq_tolerance - << " && close enough? " << is_close_enough << ")" << std::endl; + << " on edge: " << traversal_traits.closest_primitive_id() + << " at sq distance " << gt.compute_squared_distance_3_object()(query, closest_p) + << " with squared tolerance: " << sq_tolerance + << " && close enough? " << is_close_enough << std::endl; #endif if(!is_close_enough) return; -#ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "\t and is thus beneath tolerance" << std::endl; -#endif - edge_descriptor closest = traversal_traits.closest_primitive_id(); - CGAL_assertion(get(vpmt, source(closest, pmt)) != query && - get(vpmt, target(closest, pmt)) != query); + CGAL_assertion(get(vpm_T, source(closest_e, tm_T)) != query && + get(vpm_T, target(closest_e, tm_T)) != query); - halfedge_descriptor clos_hd = halfedge(closest, pmt); - CGAL_assertion(is_border(edge(clos_hd, pmt), pmt)); + halfedge_descriptor closest_h = halfedge(closest_e, tm_T); + CGAL_assertion(is_border(edge(closest_h, tm_T), tm_T)); - if(!is_border(clos_hd, pmt)) - clos_hd = opposite(clos_hd, pmt); + if(!is_border(closest_h, tm_T)) + closest_h = opposite(closest_h, tm_T); -#ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "splitting position: " << query << std::endl; -#endif - - edges_to_split.push_back(std::make_pair(query, clos_hd)); + // Using a map because we need to know if the same halfedge is split multiple times + Edges_to_split_map_inserter()(edges_to_split, closest_h, vertex_with_tolerance.first, closest_p); } #ifdef CGAL_LINKED_WITH_TBB template + typename TriangleMesh, typename EdgeToSplitMap, typename AABBTree, + typename VertexPatchMap_S, typename FacePatchMap_T, + typename VPMS, typename VPMT, typename GT> struct Find_splittable_edge_for_parallel_for { Find_splittable_edge_for_parallel_for(const PointWithToleranceContainer& points_with_tolerance, - EdgeToSplitContainer& edges_to_split, + EdgeToSplitMap& edges_to_split, const AABBTree* aabb_tree_ptr, - const TriangleMesh& pms, - const VPM& vpms, - const TriangleMesh& pmt, - const VPM& vpmt, + const TriangleMesh& tm_S, + const VertexPatchMap_S vertex_patch_map_S, + const VPMS vpm_S, + const TriangleMesh& tm_T, + const FacePatchMap_T face_patch_map_T, + const VPMT vpm_T, const GT& gt) : m_points_with_tolerance(points_with_tolerance), m_edges_to_split(edges_to_split), m_aabb_tree_ptr(aabb_tree_ptr), - m_pms(pms), m_vpms(vpms), m_pmt(pmt), m_vpmt(vpmt), m_gt(gt) + m_tm_S(tm_S), m_vertex_patch_map_S(vertex_patch_map_S), m_vpm_S(vpm_S), + m_tm_T(tm_T), m_face_patch_map_T(face_patch_map_T), m_vpm_T(vpm_T), + m_gt(gt) { } void operator()(const tbb::blocked_range& r) const { for(std::size_t i=r.begin(); i!=r.end(); ++i) { - find_splittable_edge(m_points_with_tolerance[i], m_edges_to_split, - m_aabb_tree_ptr, - m_pms, m_vpms, m_pmt, m_vpmt, - m_gt); + find_splittable_edge(m_points_with_tolerance[i], m_edges_to_split, m_aabb_tree_ptr, + m_tm_S, m_vertex_patch_map_S, m_vpm_S, + m_tm_T, m_face_patch_map_T, m_vpm_T, m_gt); } } private: const PointWithToleranceContainer& m_points_with_tolerance; - EdgeToSplitContainer& m_edges_to_split; + EdgeToSplitMap& m_edges_to_split; const AABBTree* m_aabb_tree_ptr; - const TriangleMesh& m_pms; - const VPM m_vpms; - const TriangleMesh& m_pmt; - const VPM m_vpmt; + const TriangleMesh& m_tm_S; + const VertexPatchMap_S m_vertex_patch_map_S; + const VPMS m_vpm_S; + const TriangleMesh& m_tm_T; + const FacePatchMap_T m_face_patch_map_T; + const VPMT m_vpm_T; const GT& m_gt; }; #endif -} // namespace internal - -namespace experimental { - -// Try to merge vertices in 'hrange' (vd = target(hd, pm)) onto the edges in the 'erange', -// non-conformingly -template -std::size_t snap_vertex_range_onto_vertex_range_non_conforming(const HalfedgeRange& source_hrange, - TriangleMesh& pms, - const HalfedgeRange& target_hrange, - TriangleMesh& pmt, - const ToleranceMap& tol_pmap, - const NamedParameters& nps, - const NamedParameters& npt) +template +std::size_t split_edges(EdgesToSplitContainer& edges_to_split, + TriangleMesh& tm_S, + VPMS vpm_S, + TriangleMesh& tm_T, + VPMT vpm_T, + const GeomTraits& gt, + const bool is_source_mesh_fixed) // when snapping is B --> A and the mesh B is fixed { - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "split " << edges_to_split.size() << " edges" << std::endl; +#endif - typedef typename GetVertexPointMap::type VPM; - typedef typename boost::property_traits::value_type Point; - typedef typename boost::property_traits::reference Point_ref; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename GetGeomTraits::type GT; - typedef typename GT::FT FT; - typedef typename GT::Vector_3 Vector; + typedef typename boost::property_traits::value_type Point; + typedef typename boost::property_traits::reference Point_ref; + typedef typename GeomTraits::Vector_3 Vector; - typedef internal::Compare_points_along_edge Point_along_edge_comparer; - - typedef CGAL::AABB_halfedge_graph_segment_primitive Primitive; - typedef CGAL::AABB_traits AABB_Traits; - typedef CGAL::AABB_tree AABB_tree; - - using parameters::get_parameter; - using parameters::choose_parameter; - - // Need to have a triangle mesh to ensure that the refinement point of a border edge 'e' has visibility - // of the third p oint of the face 'f' incident to 'e' - CGAL_precondition(is_triangle_mesh(pmt)); + typedef std::pair Vertex_with_new_position; + typedef std::vector Vertices_with_new_position; + typedef std::pair Edge_and_splitters; std::size_t snapped_n = 0; - VPM vpms = choose_parameter(get_parameter(nps, internal_np::vertex_point), get_property_map(vertex_point, pms)); - VPM vpmt = choose_parameter(get_parameter(npt, internal_np::vertex_point), get_property_map(vertex_point, pmt)); + CGAL::Real_timer timer; + timer.start(); - const GT gt = choose_parameter(get_parameter(nps, internal_np::geom_traits), GT()); - - // start by snapping vertices together to simplify things - snapped_n = snap_vertex_range_onto_vertex_range(source_hrange, pms, target_hrange, pmt, tol_pmap, nps, npt); - -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "Snapping vertices to edges. Range sizes: " - << std::distance(source_hrange.begin(), source_hrange.end()) << " and " - << std::distance(target_hrange.begin(), target_hrange.end()) << std::endl; -#endif - - // Collect border points that can be projected onto a border edge - typedef std::map Unique_vertices_with_tolerance; // unordered map is empirically slower - - // If the point appears multiple times on the source border, use it only once to snap target edges - // use the smallest tolerance from all source vertices - -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "gather unique points in source range" << std::endl; -#endif - - Unique_vertices_with_tolerance unique_source_vertices; - for(halfedge_descriptor hd : source_hrange) + for(Edge_and_splitters& es : edges_to_split) { - // Skip the source vertex if its two incident halfedges are geometrically identical (it means that - // the two halfedges are already stitchable and we don't want this common vertex to be used - // to split a halfedge somewhere else) - if(get(vpms, source(hd, pms)) == get(vpms, target(next(hd, pms), pms))) - continue; + halfedge_descriptor h_to_split = es.first; + CGAL_assertion(is_border(h_to_split, tm_T)); - const vertex_descriptor vd = target(hd, pms); - const Point_ref query = get(vpms, vd); - const FT tolerance = get(tol_pmap, vd); + Vertices_with_new_position& splitters = es.second; - std::pair is_insert_successful = - unique_source_vertices.insert(std::make_pair(query, tolerance)); - - // Keep the lowest tolerance out of all the source vertices with the same position - is_insert_successful.first->second = (std::min)(is_insert_successful.first->second, tolerance); - -#ifdef CGAL_PMP_SNAP_DEBUG_PP - if(is_insert_successful.second) - std::cout << "Query: " << vd << " (" << query << ")" << std::endl; -#endif - } - - // Since we're inserting primitives one by one, we can't pass this shared data in the constructor of the tree - AABB_Traits aabb_traits; - aabb_traits.set_shared_data(pmt, vpmt); - AABB_tree aabb_tree(aabb_traits); - - for(halfedge_descriptor hd : target_hrange) - { - CGAL_precondition(is_border(edge(hd, pmt), pmt)); - aabb_tree.insert(Primitive(edge(hd, pmt), pmt, vpmt)); - } - - // Now, check which edges of the target range ought to be split by source vertices -#ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "Collect edges to split w/ " << unique_source_vertices.size() << " unique vertices" << std::endl; -#endif - -#ifdef CGAL_LINKED_WITH_TBB -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "Parallel find splittable edges!" << std::endl; -#endif - - typedef tbb::concurrent_vector > Concurrent_edge_to_split_container; - - // Can't parallel for a map... - std::vector > unique_vertices_with_tolerance_vector(unique_source_vertices.begin(), - unique_source_vertices.end()); - - typedef internal::Find_splittable_edge_for_parallel_for >, - TriangleMesh, - Concurrent_edge_to_split_container, - AABB_tree, VPM, GT> Functor; - - Concurrent_edge_to_split_container edges_to_split; - Functor f(unique_vertices_with_tolerance_vector, edges_to_split, &aabb_tree, pms, vpms, pmt, vpmt, gt); - tbb::parallel_for(tbb::blocked_range(0, unique_vertices_with_tolerance_vector.size()), f); -#else // CGAL_LINKED_WITH_TBB -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "Sequential find splittable edges!" << std::endl; -#endif - typedef std::pair Point_with_tolerance; - - std::vector > edges_to_split; - for(const Point_with_tolerance& point_with_tolerance : unique_source_vertices) - { - internal::find_splittable_edge(point_with_tolerance, edges_to_split, &aabb_tree, - pms, vpms, pmt, vpmt, gt); - } -#endif - - // Sort points falling on the same edge and split the edge - std::map > points_per_edge; - typedef std::pair Pair_type; - for(const Pair_type& p : edges_to_split) - points_per_edge[p.second].push_back(p.first); - -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "split " << points_per_edge.size() << " edges" << std::endl; -#endif - - typedef std::pair > Map_type; - for(Map_type& mt : points_per_edge) - { - const halfedge_descriptor mt_hd = mt.first; - const halfedge_descriptor mt_hd_opp = opposite(mt_hd, pmt); - CGAL_assertion(!is_border(mt_hd_opp, pmt)); - - if(mt.second.size() > 1) + if(splitters.size() > 1) { #ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << " MUST SORT ON BORDER!" << std::endl; + std::cout << " _______ Multiple splitting points on the same halfedge" << std::endl; #endif - /// \todo Sorting the projected positions is too simple (for example, this doesn't work - /// for a zigzaging polyline). Rather, points should be sorted following - /// the order along the matching border. Note that this requires identifying - /// matching polylines because a sequence of zigzaging points might not all project - /// onto the same halfedge. - Point_along_edge_comparer cmp(mt_hd, gt, vpmt, pmt); - std::sort(mt.second.begin(), mt.second.end(), cmp); + + const Point_ref hsp = get(vpm_T, source(h_to_split, tm_T)); + std::sort(splitters.begin(), splitters.end(), + [&](const Vertex_with_new_position& l, const Vertex_with_new_position& r) -> bool + { + return gt.less_distance_to_point_3_object()(hsp, l.second, r.second); + }); } - halfedge_descriptor hd_to_split = mt_hd; - for(const Point& p : mt.second) + // Inserting new points ordered from the source to the target of (the initial) 'h' + bool first_split = true; + Point previous_split_position = get(vpm_S, *(vertices(tm_S).begin())); // dummy value to avoid "used uninitialized" warning + for(const Vertex_with_new_position& vnp : splitters) { + const halfedge_descriptor splitter_h = vnp.first; + const vertex_descriptor splitter_v = target(splitter_h, tm_S); + const Point new_position = is_source_mesh_fixed ? get(vpm_S, splitter_v) : vnp.second; + + bool do_split = true; + + // Some splits can create degenerate faces, avoid that + if((new_position == get(vpm_T, target(h_to_split, tm_T))) || + (new_position == get(vpm_T, source(h_to_split, tm_T)))) + do_split = false; + + if(!first_split && new_position == previous_split_position) + do_split = false; + #ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "SPLIT " << edge(hd_to_split, pmt) << " |||| " - << " vs " << source(hd_to_split, pmt) << " (" << pmt.point(source(hd_to_split, pmt)) << ")" - << " --- vt " << target(hd_to_split, pmt) << " (" << pmt.point(target(hd_to_split, pmt)) << ")" << std::endl; - std::cout << " with pos " << p << std::endl; + std::cout << " -.-.-. Splitting " << edge(h_to_split, tm_T) << " |||| " + << " Vs " << source(h_to_split, tm_T) << " (" << tm_T.point(source(h_to_split, tm_T)) << ")" + << " --- Vt " << target(h_to_split, tm_T) << " (" << tm_T.point(target(h_to_split, tm_T)) << ")" << std::endl; + std::cout << "With point: " << vnp.second << std::endl; + std::cout << "Actually split? " << do_split << std::endl; #endif - halfedge_descriptor res = CGAL::Euler::split_edge(hd_to_split, pmt); - put(vpmt, target(res, pmt), p); + // Split and update positions + vertex_descriptor new_v = boost::graph_traits::null_vertex(); + if(do_split) + { + CGAL::Euler::split_edge(h_to_split, tm_T); + new_v = source(h_to_split, tm_T); + put(vpm_T, new_v, new_position); // position of the new point on the target mesh + } + + if(!is_source_mesh_fixed) + put(vpm_S, splitter_v, new_position); + + first_split = false; + previous_split_position = new_position; ++snapped_n; - // @todo ensuring hd_to_split is safe... but is it necessary? - hd_to_split = next(res, pmt); - halfedge_descriptor hd_to_split_opp = opposite(hd_to_split, pmt); + // Everything below is choosing the diagonal to triangulate the quad formed by the edge split + // So, it's only relevant if splitting has been performed + if(!do_split) + continue; - // Look at the geometry to determine which diagonal is better to use to split this new quad face - - /* p + /* new_p * / \ - * res / \ hd_to_split + * res / \ h_to_split * / \ * / \ * left right @@ -962,22 +696,24 @@ std::size_t snap_vertex_range_onto_vertex_range_non_conforming(const HalfedgeRan * | / * | / * | / - * opp + * | / + * opp */ - const Point_ref left_pt = get(vpmt, source(res, pmt)); - const Point_ref right_pt = get(vpmt, target(hd_to_split, pmt)); - const Point_ref opp = get(vpmt, target(next(opposite(res, pmt), pmt), pmt)); + const halfedge_descriptor res = prev(h_to_split, tm_T); + const Point_ref left_pt = get(vpm_T, source(res, tm_T)); + const Point_ref right_pt = get(vpm_T, target(h_to_split, tm_T)); + const Point_ref opp = get(vpm_T, target(next(opposite(res, tm_T), tm_T), tm_T)); // Check if 'p' is "visible" from 'opp' (i.e. its projection on the plane 'Pl(left, opp, right)' // falls in the cone with apex 'opp' and sides given by 'left' and 'right') const Vector n = gt.construct_orthogonal_vector_3_object()(right_pt, left_pt, opp); - const Point trans_left_pt = gt.construct_translated_point_3_object()(left_pt, n); const Point trans_right_pt = gt.construct_translated_point_3_object()(right_pt, n); - const bool left_of_left = (gt.orientation_3_object()(trans_left_pt, left_pt, opp, p) == CGAL::POSITIVE); - const bool right_of_right = (gt.orientation_3_object()(right_pt, trans_right_pt, opp, p) == CGAL::POSITIVE); + const Point_ref new_p = get(vpm_T, new_v); + const bool left_of_left = (gt.orientation_3_object()(trans_left_pt, left_pt, opp, new_p) == CGAL::POSITIVE); + const bool right_of_right = (gt.orientation_3_object()(right_pt, trans_right_pt, opp, new_p) == CGAL::POSITIVE); const bool is_visible = (!left_of_left && !right_of_right); @@ -986,17 +722,20 @@ std::size_t snap_vertex_range_onto_vertex_range_non_conforming(const HalfedgeRan std::cout << "visible from " << opp << " ? " << is_visible << std::endl; #endif + // h_to_split is equal to 'next(res)' after splitting + const halfedge_descriptor h_to_split_opp = opposite(h_to_split, tm_T); + if(is_visible) { - halfedge_descriptor new_hd = CGAL::Euler::split_face(hd_to_split_opp, - prev(prev(mt_hd_opp, pmt), pmt), pmt); - hd_to_split = opposite(prev(new_hd, pmt), pmt); + halfedge_descriptor new_hd = CGAL::Euler::split_face(h_to_split_opp, + prev(prev(h_to_split_opp, tm_T), tm_T), tm_T); + h_to_split = opposite(prev(new_hd, tm_T), tm_T); } else { - halfedge_descriptor new_hd = CGAL::Euler::split_face(opposite(res, pmt), - prev(hd_to_split_opp, pmt), pmt); - hd_to_split = opposite(next(new_hd, pmt), pmt); + halfedge_descriptor new_hd = CGAL::Euler::split_face(opposite(res, tm_T), + prev(h_to_split_opp, tm_T), tm_T); + h_to_split = opposite(next(new_hd, tm_T), tm_T); } } } @@ -1004,27 +743,465 @@ std::size_t snap_vertex_range_onto_vertex_range_non_conforming(const HalfedgeRan return snapped_n; } -template -std::size_t snap_vertex_range_onto_vertex_range_non_conforming(const HalfedgeRange& source_hrange, - TriangleMesh& pms, - const HalfedgeRange& target_hrange, - TriangleMesh& pmt, - const ToleranceMap& tol_pmap) +// Collect border points that can be projected onto a border edge +// +// If multiple vertices on the source border have the same geometric position, they are moved +// all at once and we use the smallest tolerance from all source vertices with that position. +// This is done to solve situation such as: +// || +// || +// ____||____ +// ---------- +// (vertex-vertex snapping into non-conformal snapping) in one go. +template +std::size_t snap_non_conformal_one_way(const HalfedgeRange& halfedge_range_S, + TriangleMesh& tm_S, + ToleranceMap tolerance_map_S, + VertexPatchMap_S vertex_patch_map_S, + LockedVertexMap locked_vertices_S, + const HalfedgeRange& halfedge_range_T, + TriangleMesh& tm_T, + FacePatchMap_T face_patch_map_T, + LockedHalfedgeMap locked_halfedges_T, + const bool is_source_mesh_fixed, + const SourceNamedParameters& snp, + const TargetNamedParameters& tnp) { - return snap_vertex_range_onto_vertex_range_non_conforming(source_hrange, pms, target_hrange, pmt, - tol_pmap, parameters::all_default(), - parameters::all_default()); + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + + typedef typename GetVertexPointMap::type VPMS; + typedef typename GetVertexPointMap::type VPMT; + + typedef typename boost::property_traits::value_type Point; + + typedef CGAL::AABB_halfedge_graph_segment_primitive Primitive; + typedef CGAL::AABB_traits AABB_Traits; + typedef CGAL::AABB_tree AABB_tree; + + typedef std::pair Vertex_with_new_position; + typedef std::vector Vertices_with_new_position; + + using parameters::get_parameter; + using parameters::choose_parameter; + + VPMS vpm_S = choose_parameter(get_parameter(snp, internal_np::vertex_point), get_property_map(vertex_point, tm_S)); + VPMT vpm_T = choose_parameter(get_parameter(tnp, internal_np::vertex_point), get_property_map(vertex_point, tm_T)); + const GT gt = choose_parameter(get_parameter(snp, internal_np::geom_traits), GT()); + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Gather unique points in source range..." << std::endl; +#endif + + typedef std::pair Vertex_with_tolerance; + typedef std::vector Vertices_with_tolerance; + + Vertices_with_tolerance vertices_to_snap; + vertices_to_snap.reserve(halfedge_range_S.size()); // ensures that iterators stay valid + + // Take the min tolerance for all points that have the same coordinates + std::map point_tolerance_map; + + for(halfedge_descriptor h : halfedge_range_S) + { + if(get(locked_vertices_S, target(h, tm_S))) + continue; + + // Skip the source vertex if its two incident halfedges are geometrically identical (it means that + // the two halfedges are already stitchable and we don't want this common vertex to be used + // to split a halfedge somewhere else) + if(get(vpm_S, source(h, tm_S)) == get(vpm_S, target(next(h, tm_S), tm_S))) + continue; + + const vertex_descriptor v = target(h, tm_S); + const FT tolerance = get(tolerance_map_S, v); + + vertices_to_snap.emplace_back(h, tolerance); + + std::pair entry(get(vpm_S, v), tolerance); + std::pair::iterator, bool> is_insert_successful = + point_tolerance_map.insert(entry); + if(!is_insert_successful.second) + is_insert_successful.first->second = (std::min)(is_insert_successful.first->second, tolerance); + + #ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Non-conformal query: " << v << " (" << get(vpm_S, v) << "), tolerance: " << tolerance << std::endl; +#endif + } + + for(auto& p : vertices_to_snap) + p.second = point_tolerance_map[get(vpm_S, target(p.first, tm_S))]; + + // Since we're inserting primitives one by one, we can't pass this shared data in the constructor of the tree + AABB_Traits aabb_traits; + aabb_traits.set_shared_data(tm_T, vpm_T); + AABB_tree aabb_tree(aabb_traits); + + for(halfedge_descriptor h : halfedge_range_T) + { + CGAL_precondition(is_border(edge(h, tm_T), tm_T)); + if(get(locked_halfedges_T, h)) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << edge(h, tm_T) << " is locked and not a valid target" << std::endl; +#endif + continue; + } + + aabb_tree.insert(Primitive(edge(h, tm_T), tm_T, vpm_T)); + } + + // Now, check which edges of the target range ought to be split by source vertices +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Collect edges to split with " << vertices_to_snap.size() << " vertices" << std::endl; +#endif + +#ifndef CGAL_LINKED_WITH_TBB + CGAL_static_assertion_msg (!(std::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); +#else + if(std::is_convertible::value) + { +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Parallel find splittable edges!" << std::endl; +#endif + + typedef tbb::concurrent_hash_map Concurrent_edge_to_split_container; + typedef internal::Find_splittable_edge_for_parallel_for< + Vertices_with_tolerance, TriangleMesh, + Concurrent_edge_to_split_container, AABB_tree, + VertexPatchMap_S, FacePatchMap_T, VPMS, VPMT, GT> Functor; + + CGAL::Real_timer timer; + timer.start(); + + Concurrent_edge_to_split_container edges_to_split; + Functor f(vertices_to_snap, edges_to_split, &aabb_tree, + tm_S, vertex_patch_map_S, vpm_S, tm_T, face_patch_map_T, vpm_T, gt); + tbb::parallel_for(tbb::blocked_range(0, vertices_to_snap.size()), f); + + std::cout << "Time to gather edges: " << timer.time() << std::endl; + + return split_edges(edges_to_split, tm_S, vpm_S, tm_T, vpm_T, gt, is_source_mesh_fixed); + } + else +#endif // CGAL_LINKED_WITH_TBB + { +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Sequential find splittable edges!" << std::endl; +#endif + + std::map edges_to_split; + for(const Vertex_with_tolerance& vt : vertices_to_snap) + { + internal::find_splittable_edge(vt, edges_to_split, &aabb_tree, + tm_S, vertex_patch_map_S, vpm_S, + tm_T, face_patch_map_T, vpm_T, gt); + } + + return split_edges(edges_to_split, tm_S, vpm_S, tm_T, vpm_T, gt, is_source_mesh_fixed); + } } +// \ingroup PMP_repairing_grp +// +// Attempts to snap the vertices in `halfedge_range_A` onto edges of `halfedge_range_B`, and reciprocally. +// A vertex from the first range is only snapped to an edge of the second range if the distance to +// the edge is smaller than the tolerance prescribed at the vertex. +// +// \warning This function does not give any guarantee on the conformity between the two meshes after the snapping. +// \warning This function does not merge vertices or the meshes, it is purely geometric. +// +// \tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` +// \tparam HalfedgeRange_A a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` +// \tparam HalfedgeRange_B a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` +// \tparam ToleranceMap_A a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` +// and value type `GetGeomTraits::type::FT` +// \tparam ToleranceMap_B a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` +// and value type `GetGeomTraits::type::FT` +// \tparam NamedParameters_A a sequence of \ref pmp_namedparameters "Named Parameters" +// \tparam NamedParameters_B a sequence of \ref pmp_namedparameters "Named Parameters" +// +// \param halfedge_range_A a range of halfedges of the first mesh defining a set of vertices (as targets of the halfeges) +// \param tm_A the first mesh to which the vertices in `halfedge_range_A` belong +// \param tolerance_map_A a tolerance map associating to each vertex of the first range a tolerance value +// \param halfedge_range_B a range of vertices of the second mesh defining a set of vertices (as targets of the halfeges) +// \param tolerance_map_B a tolerance map associating to each vertex of the second range a tolerance value +// \param tm_B the target mesh to which the vertices in `halfedge_range_B` belong +// \param np_A optional \ref pmp_namedparameters "Named Parameters" related to the source mesh, +// amongst those described below: +// +// \cgalNamedParamsBegin +// \cgalParamBegin{vertex_point_map} +// the property map with the points associated to the vertices of the source mesh. +// The type of this map is model of `ReadWritePropertyMap`. If this parameter is omitted, +// an internal property map for `CGAL::vertex_point_t` must be available in `TriangleMesh`. +// \cgalParamEnd +// \cgalParamBegin{geom_traits} +// a geometric traits class instance, must be a model of `Kernel` +// \cgalParamEnd +// \cgalNamedParamsEnd +// +// \param np_B optional \ref pmp_namedparameters "Named Parameters" related to the target mesh, +// amongst those described below: +// +// \cgalNamedParamsBegin +// \cgalParamBegin{vertex_point_map} +// the property map with the points associated to the vertices of the target mesh. +// The type of this map is model of `ReadablePropertyMap`. If this parameter is omitted, +// an internal property map for `CGAL::vertex_point_t` must be available in `TriangleMesh`. +// \cgalParamEnd +// \cgalNamedParamsEnd +// +// \return the number of snapped vertex pairs +// +template +std::size_t snap_non_conformal(HalfedgeRange& halfedge_range_A, + TriangleMesh& tm_A, + ToleranceMap_A tolerance_map_A, + HalfedgeRange& halfedge_range_B, + TriangleMesh& tm_B, + ToleranceMap_B tolerance_map_B, + const bool is_self_snapping, // == true if range and meshes are equal + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) +{ +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout.precision(17); + std::cerr.precision(17); +#endif + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef CGAL::dynamic_vertex_property_t Vertex_bool_tag; + typedef CGAL::dynamic_vertex_property_t Vertex_size_t_tag; + typedef CGAL::dynamic_halfedge_property_t Halfedge_bool_tag; + + typedef typename boost::property_map::type Locked_vertices; + typedef typename boost::property_map::type Locked_halfedges; + typedef typename boost::property_map::type Vertex_patch; + + typedef typename internal_np::Lookup_named_param_def < + internal_np::face_patch_t, NamedParameters_A, + Constant_property_map /*default*/ >::type Face_patch_map_A; + typedef typename internal_np::Lookup_named_param_def < + internal_np::face_patch_t, NamedParameters_B, + Constant_property_map /*default*/ >::type Face_patch_map_B; + + using CGAL::parameters::choose_parameter; + using CGAL::parameters::is_default_parameter; + using CGAL::parameters::get_parameter; + + const bool is_same_mesh = (&tm_A == &tm_B); + const bool simplify_first_mesh = choose_parameter(get_parameter(np_A, internal_np::do_simplify_border), false); + const bool simplify_second_mesh = choose_parameter(get_parameter(np_B, internal_np::do_simplify_border), false); + const bool is_second_mesh_fixed = choose_parameter(get_parameter(np_B, internal_np::do_lock_mesh), false); + + // vertex-vertex and vertex-edge snapping is only considered within compatible patches + Face_patch_map_A face_patch_map_A = choose_parameter(get_parameter(np_A, internal_np::face_patch), + Constant_property_map(-1)); + Face_patch_map_B face_patch_map_B = choose_parameter(get_parameter(np_B, internal_np::face_patch), + Constant_property_map(-1)); + + Vertex_patch vertex_patch_map_A = get(Vertex_size_t_tag(), tm_A); + Vertex_patch vertex_patch_map_B = get(Vertex_size_t_tag(), tm_B); + + for(const halfedge_descriptor h : halfedge_range_A) + { + CGAL_precondition(is_border(h, tm_A)); + halfedge_descriptor h_opp = opposite(h, tm_A); + for(const vertex_descriptor v : vertices_around_face(h_opp, tm_A)) + put(vertex_patch_map_A, v, get(face_patch_map_A, face(h_opp, tm_A))); + } + + // @todo avoid that when 'self_snapping' is true + for(const halfedge_descriptor h : halfedge_range_B) + { + CGAL_precondition(is_border(h, tm_B)); + halfedge_descriptor h_opp = opposite(h, tm_B); + for(const vertex_descriptor v : vertices_around_face(h_opp, tm_B)) + put(vertex_patch_map_B, v, get(face_patch_map_B, face(h_opp, tm_B))); + } + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Non-conformal snapping... Range sizes: " + << std::distance(halfedge_range_A.begin(), halfedge_range_A.end()) << " and " + << std::distance(halfedge_range_B.begin(), halfedge_range_B.end()) << std::endl; +#endif + + CGAL_expensive_precondition(is_valid_polygon_mesh(tm_S) && is_triangle_mesh(tm_S)); + CGAL_expensive_precondition(is_valid_polygon_mesh(tm_T) && is_triangle_mesh(tm_T)); + + // Steps: + // - #1 Simplify the source range + // - #1bis Simplify the target range (if it's not locked) + // - #2 two-way vertex-vertex snapping + // - #3 two-way vertex-edge snapping + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// #1 and #1bis (Simplification of borders) + ////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Simplify ranges (" << simplify_first_mesh << " " << simplify_second_mesh << ")..." << std::endl; +#endif + + if(simplify_first_mesh) + { + internal::simplify_range(halfedge_range_A, tm_A, tolerance_map_A, np_A); + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + std::ofstream("results/simplified_A.off") << std::setprecision(17) << tm_A; +#endif + } + + if(!is_self_snapping && !is_second_mesh_fixed && simplify_second_mesh) + { + internal::simplify_range(halfedge_range_B, tm_B, tolerance_map_B, np_B); + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + std::ofstream("results/simplified_B.off") << std::setprecision(17) << tm_B; +#endif + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// #2 (Two-way vertex-vertex snapping) + ////////////////////////////////////////////////////////////////////////////////////////////////// + + // We keep in memory pairs of source/target edges that are stitchable after vertex-vertex snapping + // --> these halfedges should not be considered as targets in non-conformal snapping + // Similarly, matching vertices whose incident edges have matching directions are also locked + Locked_vertices locked_vertices_A = get(Vertex_bool_tag(), tm_A); + Locked_vertices locked_vertices_B = get(Vertex_bool_tag(), tm_B); + Locked_halfedges locked_halfedges_A = get(Halfedge_bool_tag(), tm_A); + Locked_halfedges locked_halfedges_B = get(Halfedge_bool_tag(), tm_B); + + std::size_t snapped_n = 0; + + std::vector > locked_vertices; + std::vector locked_halfedges_A_vector, locked_halfedges_B_vector; + + snapped_n += internal::snap_vertices_two_way( + halfedge_range_A, tm_A, tolerance_map_A, vertex_patch_map_A, + halfedge_range_B, tm_B, tolerance_map_B, vertex_patch_map_B, + std::back_inserter(locked_vertices), + std::back_inserter(locked_halfedges_A_vector), + std::back_inserter(locked_halfedges_B_vector), + is_second_mesh_fixed, np_A, np_B); + + for(const auto& vpair : locked_vertices) + { + put(locked_vertices_A, vpair.first, true); + put(locked_vertices_B, vpair.second, true); + if(is_same_mesh) + { + put(locked_vertices_B, vpair.first, true); + put(locked_vertices_A, vpair.second, true); + } + } + + for(const halfedge_descriptor h : locked_halfedges_A_vector) + put(locked_halfedges_A, h, true); + for(const halfedge_descriptor h : locked_halfedges_B_vector) + put(locked_halfedges_B, h, true); + + if(is_same_mesh) + { + for(const halfedge_descriptor h : locked_halfedges_A_vector) + put(locked_halfedges_B, h, true); + for(const halfedge_descriptor h : locked_halfedges_B_vector) + put(locked_halfedges_A, h, true); + } + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + std::ofstream("results/vertex_vertex_A.off") << std::setprecision(17) << tm_A; + std::ofstream("results/vertex_vertex_B.off") << std::setprecision(17) << tm_B; +#endif + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// #3 (Two one-way vertex-edge snapping) + ////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << " ///////////// Two one-way vertex-edge snapping (A --> B) " << std::endl; +#endif + + snapped_n += internal::snap_non_conformal_one_way( + halfedge_range_A, tm_A, tolerance_map_A, vertex_patch_map_A, locked_vertices_A, + halfedge_range_B, tm_B, face_patch_map_B, locked_halfedges_B, + false /*source is never fixed*/, np_A, np_B); + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + std::ofstream("results/vertex_edge_A.off") << std::setprecision(17) << tm_A; + std::ofstream("results/vertex_edge_B.off") << std::setprecision(17) << tm_B; +#endif + + if(!is_self_snapping) + { +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << " ///////////// Two one-way vertex-edge snapping (B --> A) " << std::endl; +#endif + + snapped_n += internal::snap_non_conformal_one_way( + halfedge_range_B, tm_B, tolerance_map_B, vertex_patch_map_B, locked_vertices_B, + halfedge_range_A, tm_A, face_patch_map_A, locked_halfedges_A, + is_second_mesh_fixed, np_B, np_A); + } + + return snapped_n; +} + +} // namespace internal + +namespace experimental { + //////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// +/// Convenience overloads //////////////////////////////////////////////////////////////////////////////////////////////////// -// Attempt to snap the vertices of the border of 'pm1' onto border edges of 'pm2'. +template +std::size_t snap_borders(TriangleMesh& tm_A, + ToleranceMap_A tolerance_map_A, + TriangleMesh& tm_B, + ToleranceMap_B tolerance_map_B, + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm1, - TriangleMesh& pm2) + std::vector border_vertices_1; + border_halfedges(tm_A, std::back_inserter(border_vertices_1)); + std::vector border_vertices_2; + border_halfedges(tm_B, std::back_inserter(border_vertices_2)); + + return internal::snap_non_conformal(border_vertices_1, tm_A, tolerance_map_A, + border_vertices_2, tm_B, tolerance_map_B, + false /*not self snapping*/, np_A, np_B); +} + +template +std::size_t snap_borders(TriangleMesh& tm_A, + TriangleMesh& tm_B, + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; @@ -1034,84 +1211,109 @@ std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm1, typedef CGAL::dynamic_vertex_property_t Vertex_property_tag; typedef typename boost::property_map::type Tolerance_map; - std::vector border_vertices1; - border_halfedges(pm1, std::back_inserter(border_vertices1)); + std::vector border_vertices_1; + std::vector border_vertices_2; + border_halfedges(tm_A, std::back_inserter(border_vertices_1)); + border_halfedges(tm_B, std::back_inserter(border_vertices_2)); - std::vector border_vertices2; - if(&pm1 == &pm2) - border_vertices2 = border_vertices1; - else - border_halfedges(pm2, std::back_inserter(border_vertices2)); - - Tolerance_map tol_pmap = get(Vertex_property_tag(), pm1); const FT tol_mx(std::numeric_limits::max()); - internal::assign_tolerance_with_local_edge_length_bound(border_vertices1, tol_pmap, tol_mx, pm1); + Tolerance_map tolerance_map_A = get(Vertex_property_tag(), tm_A); + internal::assign_tolerance_with_local_edge_length_bound(border_vertices_1, tolerance_map_A, tol_mx, tm_A, np_A); + Tolerance_map tolerance_map_B = get(Vertex_property_tag(), tm_A); + internal::assign_tolerance_with_local_edge_length_bound(border_vertices_2, tolerance_map_B, tol_mx, tm_B, np_B); - return snap_vertex_range_onto_vertex_range_non_conforming(border_vertices1, pm1, - border_vertices2, pm2, tol_pmap, - CGAL::parameters::all_default(), - CGAL::parameters::all_default()); + return internal::snap_non_conformal(border_vertices_1, tm_A, tolerance_map_A, + border_vertices_2, tm_B, tolerance_map_B, + false /*no self snapping*/, np_A, np_B); } -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm1, - TriangleMesh& pm2, - const ToleranceMap& tol_pmap, - const NamedParameters& np1, - const NamedParameters& np2) +template +std::size_t snap_borders(TriangleMesh& tm_A, + ToleranceMap_A tolerance_map_A, + TriangleMesh& tm_B, + ToleranceMap_B tolerance_map_B) +{ + return snap_borders(tm_A, tolerance_map_A, tm_B, tolerance_map_B, + CGAL::parameters::all_default(), CGAL::parameters::all_default()); +} + +template +std::size_t snap_borders(TriangleMesh& tm_A, + TriangleMesh& tm_B) +{ + return snap_borders(tm_A, tm_B, CGAL::parameters::all_default(), CGAL::parameters::all_default()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Same as above, but with a single mesh + +template +std::size_t snap_borders(TriangleMesh& tm, + ToleranceMap tolerance_map, + const CGAL_PMP_NP_CLASS& np) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - std::vector border_vertices1; - border_halfedges(pm1, std::back_inserter(border_vertices1)); + std::vector border_vertices; + border_halfedges(tm, std::back_inserter(border_vertices)); - std::vector border_vertices2; - border_halfedges(pm2, std::back_inserter(border_vertices2)); - - return snap_vertex_range_onto_vertex_range_non_conforming(border_vertices1, pm1, - border_vertices2, pm2, - tol_pmap, np1, np2); + return internal::snap_non_conformal(border_vertices, tm, tolerance_map, + border_vertices, tm, tolerance_map, + true /*self snapping*/, np, np); } -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm1, - TriangleMesh& pm2, - const ToleranceMap& tol_pmap) +template +std::size_t snap_borders(TriangleMesh& tm, + ToleranceMap tolerance_map) { - return snap_border_vertices_non_conforming(pm1, pm2, tol_pmap, - CGAL::parameters::all_default(), CGAL::parameters::all_default()); + return snap_borders(tm, tolerance_map, CGAL::parameters::all_default()); } -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm) +template +std::size_t snap_borders(TriangleMesh& tm, + const CGAL_PMP_NP_CLASS& np) { - return snap_border_vertices_non_conforming(pm, pm); + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + + typedef CGAL::dynamic_vertex_property_t Vertex_property_tag; + typedef typename boost::property_map::type Tolerance_map; + + std::vector border_vertices; + border_halfedges(tm, std::back_inserter(border_vertices)); + + const FT tol_mx(std::numeric_limits::max()); + Tolerance_map tolerance_map = get(Vertex_property_tag(), tm); + internal::assign_tolerance_with_local_edge_length_bound(border_vertices, tolerance_map, tol_mx, tm, np); + + return internal::snap_non_conformal(border_vertices, tm, tolerance_map, + border_vertices, tm, tolerance_map, + true /*self snapping*/, np, np); } -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm, - const ToleranceMap& tol_pmap, - const NamedParameters& np) +template +std::size_t snap_borders(TriangleMesh& tm) { - return snap_border_vertices_non_conforming(pm, pm, tol_pmap, np, np); -} - -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm, - const ToleranceMap& tol_pmap) -{ - return snap_border_vertices_non_conforming(pm, pm, tol_pmap, - CGAL::parameters::all_default(), CGAL::parameters::all_default()); + return snap_borders(tm, CGAL::parameters::all_default()); } } // end namespace experimental - } // end namespace Polygon_mesh_processing - } // end namespace CGAL -#endif // CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAP_H +#endif // CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap_vertices.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap_vertices.h new file mode 100644 index 00000000000..bb3a5f5297d --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap_vertices.h @@ -0,0 +1,943 @@ +// Copyright (c) 2018, 2019 GeometryFactory (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) : Mael Rouxel-Labbé + +#ifndef CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_VERTICES_H +#define CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_VERTICES_H + +#include + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + #ifndef CGAL_PMP_SNAP_DEBUG + #define CGAL_PMP_SNAP_DEBUG + #endif +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CGAL_LINKED_WITH_TBB +# include +# include +# include +#endif + +#include +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { +namespace Polygon_mesh_processing { +namespace internal { + +// Data entry of the multi-index container +template +struct Snapping_pair +{ + typedef typename GeomTraits::FT FT; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef std::vector Vertex_container; + typedef std::pair Unique_vertex; + typedef const Unique_vertex* Unique_vertex_ptr; + + Snapping_pair(Unique_vertex_ptr uv_a_, Unique_vertex_ptr uv_b_, const FT sq_dist_) + : uv_a(uv_a_), uv_b(uv_b_), sq_dist(sq_dist_) + { } + + Unique_vertex_ptr uv_a; + Unique_vertex_ptr uv_b; + FT sq_dist; +}; + +// Functor that just forwards the pair of the two intersecting boxes +template +struct Intersecting_boxes_pairs_report +{ + Intersecting_boxes_pairs_report(OutputIterator it) : m_iterator(it) { } + + template + void operator()(const Box* b, const Box* c) const { + *m_iterator++ = std::make_pair(b->info(), c->info()); + } + + mutable OutputIterator m_iterator; +}; + +template +struct Vertex_proximity_report +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + + typedef typename GeomTraits::FT FT; + + typedef std::vector Vertex_container; + typedef std::pair Unique_vertex; + typedef const Unique_vertex* Unique_vertex_ptr; + typedef std::pair Unique_vertex_pair; + + Vertex_proximity_report(SnappingPairContainer& snapping_pairs, + const PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + VertexPatchMap_A vertex_patch_map_A, + const VPM_A& vpm_A, + const PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B, + VertexPatchMap_B vertex_patch_map_B, + const VPM_B& vpm_B, + const GeomTraits& gt +#ifdef CGAL_LINKED_WITH_TBB + , const UniqueVertexPairContainer* uv_pairs = nullptr + , ToKeepContainer* to_keep = nullptr +#endif + ) + : + m_tm_A(tm_A), + m_tolerance_map_A(tolerance_map_A), + m_vertex_patch_map_A(vertex_patch_map_A), + m_vpm_A(vpm_A), + m_tm_B(tm_B), + m_tolerance_map_B(tolerance_map_B), + m_vertex_patch_map_B(vertex_patch_map_B), + m_vpm_B(vpm_B), + m_gt(gt), + m_snapping_pairs(snapping_pairs) +#ifdef CGAL_LINKED_WITH_TBB + , m_uv_pairs(uv_pairs) + , m_to_keep(to_keep) +#endif + { } + + bool are_equal_vertices(Unique_vertex_ptr uv_a, Unique_vertex_ptr uv_b) const + { + if(&m_tm_A != &m_tm_B) // must be the same mesh + return false; + + if(uv_a->first.size() != uv_b->first.size()) + return false; + + CGAL_assertion(!uv_a->first.empty() && !uv_b->first.empty()); + const halfedge_descriptor ha = uv_a->first.front(); + return (std::find(uv_b->first.begin(), uv_b->first.end(), ha) != uv_b->first.end()); + } + + std::pair do_keep(Unique_vertex_ptr uv_a, Unique_vertex_ptr uv_b) const + { + const Vertex_container& vs_a = uv_a->first; + const Vertex_container& vs_b = uv_b->first; + const vertex_descriptor va = target(vs_a.front(), m_tm_A); + const vertex_descriptor vb = target(vs_b.front(), m_tm_B); + + // Check for patch compatibility + if(get(m_vertex_patch_map_A, va) != get(m_vertex_patch_map_B, vb)) + return std::make_pair(-1, false); // ignore + + // Reject if same mesh and already grouped together + if(are_equal_vertices(uv_a, uv_b)) + return std::make_pair(-1, false); + + const FT tol_a = uv_a->second; + const FT tol_b = uv_b->second; + CGAL_assertion(tol_a >= FT(0)); + CGAL_assertion(tol_b >= FT(0)); + + const FT upper_bound_squared = CGAL::square(0.5*(tol_a + tol_b)); + CGAL::Comparison_result res = + m_gt.compare_squared_distance_3_object()(get(m_vpm_A, va), get(m_vpm_B, vb), upper_bound_squared); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "squared distance between " + << va << " [" << get(m_vpm_A, va) << "] and " + << vb << " [" << get(m_vpm_B, vb) << "]: " << sq_dist + << " (tol a/b: " << tol_a << " " << tol_b << ") larger? " << (res == CGAL::LARGER) + << std::endl; +#endif + + if(res == CGAL::LARGER) + return std::make_pair(-1, false); // ignore + else + { + const FT sq_dist = (min)(m_gt.compute_squared_distance_3_object()(get(m_vpm_A, va), get(m_vpm_B, vb)), + upper_bound_squared); + return std::make_pair(sq_dist, true); // keep + } + } + + // that's the sequential version + void operator()(const Box* a, const Box* b) + { + Unique_vertex_ptr uv_a = a->info(), uv_b = b->info(); + const std::pair res = do_keep(uv_a, uv_b); + if(res.second) + m_snapping_pairs.insert(Snapping_pair(uv_a, uv_b, res.first)); + } + +#ifdef CGAL_LINKED_WITH_TBB + // that's the parallel version + void operator()(const tbb::blocked_range& r) const + { + CGAL_assertion(m_uv_pairs != nullptr); + CGAL_assertion(m_to_keep != nullptr); + + for(std::size_t ri = r.begin(); ri != r.end(); ++ri) + { + const Unique_vertex_pair& hp = (*m_uv_pairs)[ri]; + m_to_keep->operator[](ri) = do_keep(hp.first, hp.second); + } + } +#endif + +private: + const PolygonMesh& m_tm_A; + ToleranceMap_A m_tolerance_map_A; + VertexPatchMap_A m_vertex_patch_map_A; + VPM_A m_vpm_A; + const PolygonMesh& m_tm_B; + ToleranceMap_B m_tolerance_map_B; + VertexPatchMap_B m_vertex_patch_map_B; + VPM_B m_vpm_B; + const GeomTraits& m_gt; + + SnappingPairContainer& m_snapping_pairs; // will only be filled here in the sequential setting + +#ifdef CGAL_LINKED_WITH_TBB + const UniqueVertexPairContainer* m_uv_pairs; + ToKeepContainer* m_to_keep; +#endif +}; + +template +std::size_t snap_vertices_two_way(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + VertexPatchMap_A vertex_patch_map_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B, + VertexPatchMap_B vertex_patch_map_B, + LockableVerticesOutputIterator lockable_vps_out, + LockableHalfedgesOutputIterator lockable_ha_out, + LockableHalfedgesOutputIterator lockable_hb_out, + const bool is_second_mesh_fixed, + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetVertexPointMap::type VPM_A; + typedef typename GetVertexPointMap::type VPM_B; + + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + typedef typename boost::property_traits::value_type Point; + + typedef std::vector Vertex_container; + typedef std::pair Unique_vertex; + typedef const Unique_vertex* Unique_vertex_ptr; + typedef std::map, Unique_vertex> Unique_positions; + + typedef Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; + + using parameters::get_parameter; + using parameters::choose_parameter; + + CGAL_static_assertion((std::is_same::value)); + + GT gt = choose_parameter(get_parameter(np_A, internal_np::geom_traits), GT()); + VPM_A vpm_A = choose_parameter(get_parameter(np_A, internal_np::vertex_point), + get_property_map(vertex_point, tm_A)); + VPM_B vpm_B = choose_parameter(get_parameter(np_B, internal_np::vertex_point), + get_property_map(vertex_point, tm_B)); + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Finding snappables vertices. Range sizes: " + << std::distance(halfedge_range_A.begin(), halfedge_range_A.end()) << " and " + << std::distance(halfedge_range_B.begin(), halfedge_range_B.end()) << std::endl; +#endif + + if(is_empty_range(halfedge_range_A.begin(), halfedge_range_A.end()) || + is_empty_range(halfedge_range_B.begin(), halfedge_range_B.end())) + return 0; + + // Vertex-Vertex snapping is performed as follows: + // - Identify points which are already equal and group them together so that they are moved together + // - Create a single box for these points + + std::vector boxes_A; + boxes_A.reserve(halfedge_range_A.size()); + std::vector boxes_B; + boxes_B.reserve(halfedge_range_B.size()); + + Unique_positions unique_positions_A; + for(halfedge_descriptor h : halfedge_range_A) + { + const vertex_descriptor v = target(h, tm_A); + const FT tolerance = get(tolerance_map_A, v); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Pos (A): " << v << " (" << get(vpm_A, v) << ")" << std::endl; +#endif + + Vertex_container nvc {{ h }}; + std::pair is_insert_successful = + unique_positions_A.insert(std::make_pair( + std::make_pair(get(vpm_A, v), get(vertex_patch_map_A, v)), // point and patch id + std::make_pair(nvc, tolerance))); + + if(!is_insert_successful.second) // point was already met + { + Unique_vertex& uv = is_insert_successful.first->second; + Vertex_container& vc = uv.first; // second is the tolerance + CGAL_assertion(std::find(vc.begin(), vc.end(), h) == vc.end()); + vc.push_back(h); + uv.second = (std::min)(uv.second, tolerance); + } + } + + // same for tm_B (@todo avoid all that for self snapping + use self_intersection_d) + Unique_positions unique_positions_B; + for(halfedge_descriptor h : halfedge_range_B) + { + const vertex_descriptor v = target(h, tm_B); + const FT tolerance = get(tolerance_map_B, v); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Pos (B): " << v << " (" << get(vpm_B, v) << ")" << std::endl; +#endif + + Vertex_container nvc {{ h }}; + std::pair is_insert_successful = + unique_positions_B.insert(std::make_pair( + std::make_pair(get(vpm_B, v), get(vertex_patch_map_B, v)), // point and patch id + std::make_pair(nvc, tolerance))); + + if(!is_insert_successful.second) // point was already met + { + Unique_vertex& uv = is_insert_successful.first->second; + Vertex_container& vc = uv.first; // second is the tolerance + CGAL_assertion(std::find(vc.begin(), vc.end(), h) == vc.end()); + vc.push_back(h); + uv.second = (std::min)(uv.second, tolerance); + } + } + + // Actually build the boxes now + for(const auto& p : unique_positions_A) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Unique_vertex (A), pos: " << p.first.first << " vertices:"; + for(const halfedge_descriptor h : p.second.first) + std::cout << " " << target(h, tm_A); + std::cout << std::endl; +#endif + + const Unique_vertex& ev = p.second; + CGAL_assertion(!ev.first.empty()); + + // this only makes the box a little larger to ease intersection computations, + // the final tolerance is not changed + const double eps = 1.01 * CGAL::to_double(ev.second); + const Bbox_3 pb = gt.construct_bbox_3_object()(p.first.first); + const Bbox_3 b(pb.xmin() - eps, pb.ymin() - eps, pb.zmin() - eps, + pb.xmax() + eps, pb.ymax() + eps, pb.zmax() + eps); + boxes_A.push_back(Box(b, &ev)); + } + + for(const auto& p : unique_positions_B) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Unique_vertex (B), pos: " << p.first.first << " vertices:"; + for(const halfedge_descriptor h : p.second.first) + std::cout << " " << target(h, tm_B); + std::cout << std::endl; +#endif + + const Unique_vertex& ev = p.second; + CGAL_assertion(!ev.first.empty()); + + const double eps = 1.01 * CGAL::to_double(ev.second); + const Bbox_3 pb = gt.construct_bbox_3_object()(p.first.first); + const Bbox_3 b(pb.xmin() - eps, pb.ymin() - eps, pb.zmin() - eps, + pb.xmax() + eps, pb.ymax() + eps, pb.zmax() + eps); + boxes_B.push_back(Box(b, &ev)); + } + + // @fixme bench and don't use ptrs if not useful + std::vector boxes_A_ptr; + boxes_A_ptr.reserve(boxes_A.size()); + for(const Box& b : boxes_A) + boxes_A_ptr.push_back(&b); + + std::vector boxes_B_ptr; + boxes_B_ptr.reserve(boxes_B.size()); + for(const Box& b : boxes_B) + boxes_B_ptr.push_back(&b); + + // Use a multi index to sort easily by sources, targets, AND distance. + // Then, look up the distances in increasing order, and snap whenever the source and the target + // have both not been snapped yet. + typedef internal::Snapping_pair Snapping_pair; + typedef boost::multi_index::multi_index_container< + Snapping_pair, + boost::multi_index::indexed_by< + boost::multi_index::ordered_non_unique< + BOOST_MULTI_INDEX_MEMBER(Snapping_pair, Unique_vertex_ptr, uv_a)>, + boost::multi_index::ordered_non_unique< + BOOST_MULTI_INDEX_MEMBER(Snapping_pair, Unique_vertex_ptr, uv_b)>, + boost::multi_index::ordered_non_unique< + BOOST_MULTI_INDEX_MEMBER(Snapping_pair, FT, sq_dist)> + > + > Snapping_pair_container; + + Snapping_pair_container snapping_pairs; + +#if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg (!(std::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); +#else + if(std::is_convertible::value) + { + typedef std::pair Unique_vertex_pair; + typedef tbb::concurrent_vector Unique_vertex_pairs; + typedef std::back_insert_iterator UVP_output_iterator; + + Unique_vertex_pairs uv_pairs; + Intersecting_boxes_pairs_report callback(std::back_inserter(uv_pairs)); + + CGAL::Real_timer timer; + timer.start(); + + // Grab the boxes that are interesecting but don't do any extra filtering (in parallel) + CGAL::box_intersection_d(boxes_A_ptr.begin(), boxes_A_ptr.end(), + boxes_B_ptr.begin(), boxes_B_ptr.end(), + callback); + + std::cout << "time for box_d: " << timer.time() << std::endl; + + // Actually filter the range of intersecting boxes now (in parallel) + typedef std::vector > Filters; + typedef Vertex_proximity_report Reporter; + + Filters to_keep(uv_pairs.size()); + Reporter proximity_filterer(snapping_pairs, tm_A, tolerance_map_A, vertex_patch_map_A, vpm_A, + tm_B, tolerance_map_B, vertex_patch_map_B, vpm_B, + gt, &uv_pairs, &to_keep); + tbb::parallel_for(tbb::blocked_range(0, uv_pairs.size()), proximity_filterer); + + // Now fill the multi index, sequentially + for(std::size_t i=0, uvps = uv_pairs.size(); i Reporter; + + Reporter vpr(snapping_pairs, tm_A, tolerance_map_A, vertex_patch_map_A, vpm_A, + tm_B, tolerance_map_B, vertex_patch_map_B, vpm_B, gt); + + // Shenanigans to pass a reference as callback (which is copied by value by 'box_intersection_d') + std::function callback(std::ref(vpr)); + + CGAL::box_intersection_d(boxes_A_ptr.begin(), boxes_A_ptr.end(), + boxes_B_ptr.begin(), boxes_B_ptr.end(), + callback); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// Done collecting; start matching + ////////////////////////////////////////////////////////////////////////////////////////////////// + + if(snapping_pairs.empty()) + return 0; + + typedef std::pair Unique_vertex_pair; + std::vector snappable_vertices_pairs; + + // Sorted views of the container + typedef typename Snapping_pair_container::template nth_index<0>::type Container_by_source; + typedef typename Snapping_pair_container::template nth_index<1>::type Container_by_target; + typedef typename Snapping_pair_container::template nth_index<2>::type Container_by_distance; + + Container_by_source& container_by_source = snapping_pairs.template get<0>(); + Container_by_target& container_by_target = snapping_pairs.template get<1>(); + Container_by_distance& container_by_dist = snapping_pairs.template get<2>(); + + // @todo this could be a best-match algorithm rather than a greedy algorithm, + // but is the increased complexity -and thus runtime- worth it? + CGAL_assertion_code(FT prev = -1;) + while(!container_by_dist.empty()) + { + const Snapping_pair& sp = *(container_by_dist.begin()); + Unique_vertex_ptr uv_a = sp.uv_a; + Unique_vertex_ptr uv_b = sp.uv_b; + CGAL_assertion(sp.sq_dist >= prev); + CGAL_assertion_code(prev = sp.sq_dist;) + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + const Point& pa = get(vpm_A, target(uv_a->first.front(), tm_A)); + const Point& pb = get(vpm_B, target(uv_b->first.front(), tm_B)); + std::cout << "Snapping (" << pa << ") to (" << pb << ") at dist: " << sp.sq_dist << std::endl; + std::cout << "#verts A: " << uv_a->first.size() << " #verts B: " << uv_b->first.size() << std::endl; +#endif + + snappable_vertices_pairs.emplace_back(uv_a, uv_b); + + // 'va' and 'vb' cannot be used anymore, remove them from the container + container_by_source.erase(uv_a); + container_by_target.erase(uv_b); + + if((&tm_A == &tm_B)) + { + container_by_source.erase(uv_b); + container_by_target.erase(uv_a); + } + } + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << snappable_vertices_pairs.size() << " snappable pair(s)" << std::endl; +#endif + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// Done matching; start snapping + ////////////////////////////////////////////////////////////////////////////////////////////////// + + std::size_t counter = 0; + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + std::ofstream out_edges("results/snappable.polylines.txt"); + out_edges.precision(17); +#endif + + for(const Unique_vertex_pair& uvp : snappable_vertices_pairs) + { + Unique_vertex_ptr uv_a = uvp.first; + Unique_vertex_ptr uv_b = uvp.second; + const Vertex_container& vs_a = uv_a->first; + const Vertex_container& vs_b = uv_b->first; + const vertex_descriptor va = target(vs_a.front(), tm_A); + const vertex_descriptor vb = target(vs_b.front(), tm_B); + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + out_edges << "2 " << tm_A.point(va) << " " << tm_B.point(vb) << std::endl; +#endif + + if(!gt.equal_3_object()(get(vpm_A, va), get(vpm_B, vb))) + { + if(is_second_mesh_fixed) + { + for(const halfedge_descriptor ha : vs_a) + put(vpm_A, target(ha, tm_A), get(vpm_B, vb)); + } + else + { + // Pick a point that is on the segment [va; vb], with a ratio based on the respective tolerances + const FT tol_s = uv_a->second; + const FT tol_t = uv_b->second; + CGAL_assertion(tol_s != FT(0) || tol_t != FT(0)); + + const FT lambda = tol_t / (tol_s + tol_t); + const Point new_p = get(vpm_A, va) + lambda * (get(vpm_B, vb) - get(vpm_A, va)); +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "new position of " << va << " " << vb << " --> " << new_p << std::endl; +#endif + + for(const halfedge_descriptor ha : vs_a) + put(vpm_A, target(ha, tm_A), new_p); + + for(const halfedge_descriptor hb : vs_b) + put(vpm_B, target(hb, tm_B), new_p); + } + + ++counter; + } + } + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + out_edges.close(); +#endif + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Snapped " << counter << " pair(s)!" << std::endl; +#endif + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// Done snapping; start analyzing + ////////////////////////////////////////////////////////////////////////////////////////////////// + + // Below is used in non-conformal snapping + // @todo could avoid doing it if not required + // + // Now that vertex-vertex snapping has been performed, look around to see if we can already + // lock some vertices and halfedges... + // + // #1 : If a pair of edges (1 incident to va, the other to vb) are already fully matching, + // we don't want to project anything more onto any of those 2 edges + // #2 : If pairs on either side of the two matching vertices are compatible (not necessary fully matching), + // then the two vertices should be locked as no better match can be obtained + // #3 : If a pair of incident edges are not fully matching, but still have compatible directions + // (i.e. collinear and opposite directions), then we don't want to project onto the shorter + // of the two + for(const Unique_vertex_pair& uvp : snappable_vertices_pairs) + { + Unique_vertex_ptr uv_a = uvp.first; + Unique_vertex_ptr uv_b = uvp.second; + const Vertex_container& vs_a = uv_a->first; + const Vertex_container& vs_b = uv_b->first; + + // Quadratic, but all halfedges in vs_a and vs_b point to the same point. There shouldn't be many. + // @fixme this assumes compatible orientation... + for(const halfedge_descriptor ha : vs_a) + { + for(const halfedge_descriptor hb : vs_b) + { + if(!is_border(ha, tm_A) || !is_border(hb, tm_B)) + continue; + + const vertex_descriptor va = target(ha, tm_A); + const vertex_descriptor vb = target(hb, tm_B); + + // The two folloing halfedges might not be in the range to snap, but it doesn't matter + const halfedge_descriptor nha = next(ha, tm_A); + const halfedge_descriptor nhb = next(hb, tm_B); + const bool is_stitchable_left = gt.equal_3_object()(get(vpm_A, source(ha, tm_A)), + get(vpm_B, target(nhb, tm_B))); + const bool is_stitchable_right = gt.equal_3_object()(get(vpm_A, target(nha, tm_A)), + get(vpm_B, source(hb, tm_B))); + bool is_collinear_left = false; + bool is_collinear_right = false; + + if(is_stitchable_left) + { + *lockable_ha_out++ = ha; // #1 + *lockable_hb_out++ = nhb; // #1 + is_collinear_left = true; + } + else + { + const vertex_descriptor lva = source(ha, tm_A); + const vertex_descriptor lvb = target(nhb, tm_B); + + is_collinear_left = is_collinear_with_tolerance(get(vpm_A, va), get(vpm_A, lva), get(vpm_B, lvb), gt); + if(is_collinear_left) // but not stitchable + { + if(gt.less_distance_to_point_3_object()(get(vpm_A, va), get(vpm_A, lva), get(vpm_B, lvb))) + *lockable_ha_out++ = ha; // #2 + else + *lockable_hb_out++ = nhb; // #2 + } + } + + if(is_stitchable_right) + { + *lockable_ha_out++ = nha; // #1 + *lockable_hb_out++ = hb; // #1 + is_collinear_right = true; + } + else + { + const vertex_descriptor rva = target(nha, tm_A); + const vertex_descriptor rvb = source(hb, tm_B); + + is_collinear_right = is_collinear_with_tolerance(get(vpm_A, va), get(vpm_A, rva), get(vpm_B, rvb), gt); + if(is_collinear_right) // but not stitchable + { + if(gt.less_distance_to_point_3_object()(get(vpm_A, va), get(vpm_A, rva), get(vpm_B, rvb))) + *lockable_ha_out++ = nha; // #2 + else + *lockable_hb_out++ = hb; // #2 + } + } + + if(is_collinear_left && is_collinear_right) // #3 + { +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << va << " (" << get(vpm_A, va) << ") and " << vb << " (" << get(vpm_B, vb) << ") are locked vertices" << std::endl; +#endif + *lockable_vps_out++ = std::make_pair(va, vb); + } + } + } + } + + return counter; +} + +// Convenience overload for snap_borders +template +std::size_t snap_vertices_two_way(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B, + LockableVerticesOutputIterator lockable_vps_out, + LockableHalfedgesOutputIterator lockable_ha_out, + LockableHalfedgesOutputIterator lockable_hb_out, + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + using CGAL::parameters::choose_parameter; + using CGAL::parameters::get_parameter; + + return snap_vertices_two_way(halfedge_range_A, tm_A, tolerance_map_A, + choose_parameter(get_parameter(np_A, internal_np::vertex_incident_patches), + Constant_property_map(-1)), + halfedge_range_B, tm_B, tolerance_map_B, + choose_parameter(get_parameter(np_B, internal_np::vertex_incident_patches), + Constant_property_map(-1)), + lockable_vps_out, lockable_ha_out, lockable_hb_out, + choose_parameter(get_parameter(np_B, internal_np::do_lock_mesh), false), + np_A, np_B); +} + +} // namespace internal + +namespace experimental { + +// \ingroup PMP_repairing_grp +// +// Attempts to snap the vertices in `halfedge_range_A` and `halfedge_range_B`. +// A vertex from the first range and a vertex from the second range are only snapped +// if the distance between both vertices is smaller than the sum of their user-prescribed tolerance. +// All such pairs are collected and processed in a greedy order: the two vertices are moved +// to a common vertex (more on this below), and both vertices are locked and cannot be used +// in any other matches. +// +// \warning This function does not give any guarantee on the conformity between the two meshes after the snapping. +// \warning This function does not merge vertices or the meshes, it is purely geometric. +// +// \tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` +// \tparam HalfedgeRange_A a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` +// \tparam HalfedgeRange_B a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` +// \tparam ToleranceMap_A a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` +// and value type `GetGeomTraits::type::FT` +// \tparam ToleranceMap_B a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` +// and value type `GetGeomTraits::type::FT` +// \tparam NamedParameters_A a sequence of \ref pmp_namedparameters "Named Parameters" +// \tparam NamedParameters_B a sequence of \ref pmp_namedparameters "Named Parameters" +// +// \param halfedge_range_A a range of halfedges of the first mesh defining a set of vertices (as targets of the halfeges) +// \param tm_A the first mesh to which the vertices in `halfedge_range_A` belong +// \param tolerance_map_A a tolerance map associating to each vertex of the first range a tolerance value +// \param halfedge_range_B a range of vertices of the second mesh defining a set of vertices (as targets of the halfeges) +// \param tolerance_map_B a tolerance map associating to each vertex of the second range a tolerance value +// \param tm_B the target mesh to which the vertices in `halfedge_range_B` belong +// \param np_A optional \ref pmp_namedparameters "Named Parameters" related to the source mesh, +// amongst those described below: +// +// \cgalNamedParamsBegin +// \cgalParamBegin{vertex_point_map} +// the property map with the points associated to the vertices of the source mesh. +// The type of this map is model of `ReadWritePropertyMap`. If this parameter is omitted, +// an internal property map for `CGAL::vertex_point_t` must be available in `PolygonMesh`. +// \cgalParamEnd +// \cgalParamBegin{geom_traits} +// a geometric traits class instance, must be a model of `Kernel` +// \cgalParamEnd +// \cgalNamedParamsEnd +// +// \param np_B optional \ref pmp_namedparameters "Named Parameters" related to the target mesh, +// amongst those described below: +// +// \cgalNamedParamsBegin +// \cgalParamBegin{vertex_point_map} +// the property map with the points associated to the vertices of the target mesh. +// The type of this map is model of `ReadablePropertyMap`. If this parameter is omitted, +// an internal property map for `CGAL::vertex_point_t` must be available in `PolygonMesh`. +// \cgalParamEnd +// \cgalNamedParamsEnd +// +// \return the number of snapped vertex pairs +// +template +std::size_t snap_vertices(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B, + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) +{ + CGAL::Emptyset_iterator unused_output_iterator; + + return internal::snap_vertices_two_way(halfedge_range_A, tm_A, tolerance_map_A, + halfedge_range_B, tm_B, tolerance_map_B, + unused_output_iterator, unused_output_iterator, + unused_output_iterator, np_A, np_B); +} + +template +std::size_t snap_vertices(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B) +{ + return snap_vertices(halfedge_range_A, tm_A, tolerance_map_A, halfedge_range_B, tm_B, tolerance_map_B, + CGAL::parameters::all_default(), CGAL::parameters::all_default()); +} + +template +std::size_t snap_vertices(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B, + const CGAL::Named_function_parameters& np_A, + const CGAL::Named_function_parameters& np_B) +{ + typedef CGAL::Named_function_parameters NamedParameters_A; + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + typedef CGAL::dynamic_vertex_property_t Vertex_property_tag; + typedef typename boost::property_map::type Tolerance_map; + + const FT max_tol(std::numeric_limits::max()); + + Tolerance_map tolerance_map_A = get(Vertex_property_tag(), tm_A); + internal::assign_tolerance_with_local_edge_length_bound(halfedge_range_A, tolerance_map_A, max_tol, tm_A, np_A); + Tolerance_map tolerance_map_B = get(Vertex_property_tag(), tm_B); + internal::assign_tolerance_with_local_edge_length_bound(halfedge_range_B, tolerance_map_B, max_tol, tm_B, np_B); + + return snap_vertices(halfedge_range_A, tm_A, tolerance_map_A, halfedge_range_B, tm_B, tolerance_map_B, np_A, np_B); +} + +template +std::size_t snap_vertices(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B) +{ + return snap_vertices(halfedge_range_A, tm_A, halfedge_range_B, tm_B, + parameters::all_default(), parameters::all_default()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Border convenience overloads +/////////////////////////////////////////////////////////////////////////////////////////////////// + +template +std::size_t snap_border_vertices(PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + std::vector border_A; + border_halfedges(tm_A, std::back_inserter(border_A)); + std::vector border_B; + border_halfedges(tm_B, std::back_inserter(border_B)); + + return snap_vertices(border_A, tm_A, tolerance_map_A, + border_B, tm_B, tolerance_map_B); +} + +template +std::size_t snap_border_vertices(PolygonMesh& tm_A, + PolygonMesh& tm_B) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + std::vector border_vertices_A; + border_halfedges(tm_A, std::back_inserter(border_vertices_A)); + + std::vector border_vertices_B; + border_halfedges(tm_B, std::back_inserter(border_vertices_B)); + + return snap_vertices(border_vertices_A, tm_A, border_vertices_B, tm_B); +} + +template +std::size_t snap_border_vertices(PolygonMesh& tm, ToleranceMap tolerance_map) +{ + return snap_border_vertices(tm, tolerance_map, tm, tolerance_map); +} + +template +std::size_t snap_border_vertices(PolygonMesh& tm) +{ + return snap_border_vertices(tm, tm); +} + +} // namespace experimental +} // namespace Polygon_mesh_processing +} // namespace CGAL + +#endif // CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_VERTICES_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/merge_border_vertices.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/merge_border_vertices.h index 891882f13d0..da6fb04d54e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/merge_border_vertices.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/merge_border_vertices.h @@ -109,7 +109,7 @@ void detect_identical_mergeable_vertices( // check that intervals are disjoint or strictly nested // if there is only one issue we drop the whole cycle. - /// \todo shall we try to be more conservative? + // @todo shall we try to be more conservative? if (hedges_with_identical_point_target.empty()) return; std::set< std::pair >::iterator it1 = intervals.begin(), end2 = intervals.end(), diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h index 182a9a866f7..b70eefd073e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h @@ -438,8 +438,6 @@ void recursive_orient_volume_ccs( TriangleMesh& tm, * inward or outward oriented. * * @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` . -* If `TriangleMesh` has an internal property map for `CGAL::face_index_t`, -* as a named parameter, then it must be initialized. * @tparam NamedParameters a sequence of \ref pmp_namedparameters * * @param tm a closed triangulated surface mesh @@ -461,16 +459,15 @@ void recursive_orient_volume_ccs( TriangleMesh& tm, * \cgalNamedParamsEnd */ template -void orient(TriangleMesh& tm, const NamedParameters& np) +void orient(TriangleMesh& tm, + const NamedParameters& np) { - typedef boost::graph_traits Graph_traits; - typedef typename Graph_traits::vertex_descriptor vertex_descriptor; - typedef typename Graph_traits::face_descriptor face_descriptor; - typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename GetVertexPointMap::const_type Vpm; - typedef typename GetFaceIndexMap::const_type Fid_map; + typedef boost::graph_traits Graph_traits; + typedef typename Graph_traits::vertex_descriptor vertex_descriptor; + typedef typename Graph_traits::face_descriptor face_descriptor; + typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename GetVertexPointMap::const_type Vpm; + typedef typename GetInitializedFaceIndexMap::type FaceIndexMap; CGAL_assertion(is_triangle_mesh(tm)); CGAL_assertion(is_valid_polygon_mesh(tm)); @@ -484,8 +481,7 @@ void orient(TriangleMesh& tm, const NamedParameters& np) Vpm vpm = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::vertex_point), get_const_property_map(boost::vertex_point, tm)); - Fid_map fid_map = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, tm)); + FaceIndexMap fid_map = CGAL::get_initialized_face_index_map(tm, np); std::vector face_cc(num_faces(tm), std::size_t(-1)); @@ -542,8 +538,6 @@ void orient(TriangleMesh& tm) * See \ref coref_def_subsec for a precise definition. * * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`. - * If `TriangleMesh` has an internal property map for `CGAL::face_index_t`, - * as a named parameter, then it must be initialized. * @tparam NamedParameters a sequence of \ref pmp_namedparameters * * @param tm a closed triangulated surface mesh @@ -569,20 +563,20 @@ void orient(TriangleMesh& tm) */ template void orient_to_bound_a_volume(TriangleMesh& tm, - const NamedParameters& np) + const NamedParameters& np) { - typedef boost::graph_traits Graph_traits; - typedef typename Graph_traits::vertex_descriptor vertex_descriptor; - typedef typename GetVertexPointMap::const_type Vpm; - typedef typename GetFaceIndexMap::const_type Fid_map; - typedef typename Kernel_traits< - typename boost::property_traits::value_type >::Kernel Kernel; + typedef boost::graph_traits Graph_traits; + typedef typename Graph_traits::vertex_descriptor vertex_descriptor; + + typedef typename GetVertexPointMap::const_type Vpm; + typedef typename boost::property_traits::value_type Point; + typedef typename Kernel_traits::Kernel Kernel; + + typedef typename GetInitializedFaceIndexMap::type FaceIndexMap; + if (!is_closed(tm)) return; if (!is_triangle_mesh(tm)) return; - using parameters::get_parameter; bool orient_outward = CGAL::parameters::choose_parameter( @@ -591,8 +585,7 @@ void orient_to_bound_a_volume(TriangleMesh& tm, Vpm vpm = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::vertex_point), get_const_property_map(boost::vertex_point, tm)); - Fid_map fid_map = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, tm)); + FaceIndexMap fid_map = CGAL::get_initialized_face_index_map(tm, np); std::vector face_cc(num_faces(tm), std::size_t(-1)); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index c5a1b649f89..5290d6b03fc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -41,9 +41,7 @@ namespace Polygon_mesh_processing { * The descriptor types `boost::graph_traits::%face_descriptor` * and `boost::graph_traits::%halfedge_descriptor` must be * models of `Hashable`. -* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, -* and no `face_index_map` is given -* as a named parameter, then the internal one must be initialized +* * @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, model of `Range`. Its iterator type is `ForwardIterator`. * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" @@ -160,9 +158,8 @@ void isotropic_remeshing(const FaceRange& faces VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), get_property_map(vertex_point, pmesh)); - typedef typename GetFaceIndexMap::type FIMap; - FIMap fimap = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(face_index, pmesh)); + typedef typename GetInitializedFaceIndexMap::type FIMap; + FIMap fimap = CGAL::get_initialized_face_index_map(pmesh, np); typedef typename internal_np::Lookup_named_param_def < internal_np::edge_is_constrained_t, @@ -338,9 +335,8 @@ void split_long_edges(const EdgeRange& edges VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), get_property_map(vertex_point, pmesh)); - typedef typename GetFaceIndexMap::type FIMap; - FIMap fimap = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(face_index, pmesh)); + typedef typename GetInitializedFaceIndexMap::type FIMap; + FIMap fimap = CGAL::get_initialized_face_index_map(pmesh, np); typedef typename internal_np::Lookup_named_param_def < internal_np::edge_is_constrained_t, diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h index f635af7bc95..3f2e8a6c03d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h @@ -111,10 +111,6 @@ std::size_t remove_isolated_vertices(PolygonMesh& pmesh) /// As a consequence of the last sentence, the area or volume criteria can be disabled /// by passing zero (`0`) as threshold value. /// -/// Property maps for `CGAL::face_index_t` and `CGAL::vertex_index_t` -/// must be either available as internal property maps -/// to `tmesh` or provided as \ref pmp_namedparameters "Named Parameters". -/// /// \tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` /// \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" /// @@ -129,8 +125,6 @@ std::size_t remove_isolated_vertices(PolygonMesh& pmesh) /// \cgalParamBegin{edge_is_constrained_map} a property map containing the constrained-or-not status of each edge of `pmesh` \cgalParamEnd /// \cgalParamBegin{face_index_map} a property map containing the index of each face of `tmesh` \cgalParamEnd /// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tmesh`. -/// If this parameter is omitted, an internal property map for -/// `CGAL::vertex_point_t` should be available in `TriangleMesh` \cgalParamEnd /// \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel` \cgalParamEnd /// \cgalParamBegin{dry_run} a Boolean parameter. If set to `true`, the mesh will not be altered, /// but the number of components that would be removed is returned. The default value is `false`.\cgalParamEnd @@ -162,9 +156,8 @@ std::size_t remove_connected_components_of_negligible_size(TriangleMesh& tmesh, const VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), get_const_property_map(CGAL::vertex_point, tmesh)); - typedef typename GetFaceIndexMap::type FaceIndexMap; - FaceIndexMap fim = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(boost::face_index, tmesh)); + typedef typename GetInitializedFaceIndexMap::type FaceIndexMap; + FaceIndexMap fim = CGAL::get_initialized_face_index_map(tmesh, np); FT area_threshold = choose_parameter(get_parameter(np, internal_np::area_threshold), FT(-1)); FT volume_threshold = choose_parameter(get_parameter(np, internal_np::volume_threshold), FT(-1)); @@ -992,7 +985,7 @@ bool remove_degenerate_edges(const EdgeRange& edge_range, vertex_descriptor vd = remove_a_border_edge(ed, tmesh, degenerate_edges_to_remove, face_set); if (vd == GT::null_vertex()) { - // TODO: if some border edges are later removed, the edge might be processable later + // @todo: if some border edges are later removed, the edge might be processable later // for example if it belongs to boundary cycle of edges where the number of non-degenerate // edges is 2. That's what happen with fused_vertices.off in the testsuite where the edges // are not processed the same way with Polyhedron and Surface_mesh. In the case of Polyhedron @@ -1198,7 +1191,7 @@ bool remove_degenerate_edges(const EdgeRange& edge_range, } while(true); - /// \todo use the area criteria? this means maybe continue exploration of larger cc + // @todo use the area criteria? this means maybe continue exploration of larger cc // mark faces of completetly explored cc for (index=0; index< nb_cc; ++index) { @@ -1369,15 +1362,15 @@ bool remove_degenerate_edges(TriangleMesh& tmesh) // - `Compare_distance_3` to compute the distance between 2 points // - `Collinear_3` to check whether 3 points are collinear // - `Less_xyz_3` to compare lexicographically two points -/// - `Equal_3` to check whether 2 points are identical. -/// For each functor Foo, a function `Foo foo_object()` must be provided. +// - `Equal_3` to check whether 2 points are identical. +// For each functor Foo, a function `Foo foo_object()` must be provided. // \cgalParamEnd // \cgalNamedParamsEnd // -// \todo the function might not be able to remove all degenerate faces. +// @todo the function might not be able to remove all degenerate faces. // We should probably do something with the return type. // -/// \return `true` if all degenerate faces were successfully removed, and `false` otherwise. +// \return `true` if all degenerate faces were successfully removed, and `false` otherwise. template bool remove_degenerate_faces(const FaceRange& face_range, TriangleMesh& tmesh, @@ -1478,7 +1471,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, // Then, remove triangles made of 3 collinear points // start by filtering out border faces - // TODO: shall we avoid doing that in case a non-manifold vertex on the boundary or if a whole component disappear? + // @todo: shall we avoid doing that in case a non-manifold vertex on the boundary or if a whole component disappear? std::set border_deg_faces; for(face_descriptor f : degenerate_face_set) { @@ -1685,7 +1678,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, all_removed=false; #ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG std::cout << " WARNING: flip is not possible\n"; - // \todo Let p and q be the vertices opposite to `edge_to_flip`, and let + // @todo Let p and q be the vertices opposite to `edge_to_flip`, and let // r be the vertex of `edge_to_flip` that is the furthest away from // the edge `pq`. In that case I think we should remove all the triangles // so that the triangle pqr is in the mesh. @@ -1786,7 +1779,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, (cc_faces.size()+boundary_hedges.size())/2 != 1) { //cc_faces does not define a topological disk - /// \todo Find to way to handle that case + // @todo Find to way to handle that case #ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG std::cout << " WARNING: Cannot remove the component of degenerate faces: not a topological disk.\n"; #endif @@ -1932,7 +1925,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, CGAL_assertion(get(vpmap,source(side_one.front(), tmesh))==side_points.front()); CGAL_assertion(get(vpmap,target(side_one.back(), tmesh))==side_points.back()); - //\todo the reordering could lead to the apparition of null edges. + // @todo the reordering could lead to the apparition of null edges. std::sort(side_points.begin(), side_points.end()); CGAL_assertion(std::unique(side_points.begin(), side_points.end())==side_points.end()); @@ -1950,7 +1943,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, CGAL_assertion(get(vpmap,source(side_two.front(), tmesh))==side_points.front()); CGAL_assertion(get(vpmap,target(side_two.back(), tmesh))==side_points.back()); - //\todo the reordering could lead to the apparition of null edges. + // @todo the reordering could lead to the apparition of null edges. std::sort(side_points.begin(), side_points.end()); CGAL_assertion(std::unique(side_points.begin(), side_points.end())==side_points.end()); @@ -2993,7 +2986,7 @@ remove_self_intersections_one_step(TriangleMesh& tm, vertex_descriptor v = source(h, tm); hole_points.push_back( get(vpmap, v) ); border_vertices.push_back(v); - third_points.push_back(get(vpmap, target(next(opposite(h, tm), tm), tm))); // TODO fix me for mesh border edges + third_points.push_back(get(vpmap, target(next(opposite(h, tm), tm), tm))); // @todo fix me for mesh border edges } CGAL_assertion(hole_points.size() >= 3); @@ -3195,7 +3188,7 @@ bool remove_self_intersections(TriangleMesh& tm, const NamedParameters& np) { typedef std::pair Face_pair; std::vector self_inter; - // TODO : possible optimization to reduce the range to check with the bbox + // @todo : possible optimization to reduce the range to check with the bbox // of the previous patches or something. self_intersections(tm, std::back_inserter(self_inter)); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h index 096f1f60b08..8e4fc9c6f42 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h @@ -567,7 +567,8 @@ std::size_t merge_duplicate_points_in_polygon_soup(PointRange& points, const std::size_t removed_points_n = ini_points_n - points.size(); #ifdef CGAL_PMP_REPAIR_POLYGON_SOUP_VERBOSE - std::cout << "Removed (merged) " << removed_points_n << " duplicate points" << std::endl; + if(removed_points_n > 0) + std::cout << "Removed (merged) " << removed_points_n << " duplicate points" << std::endl; #endif return removed_points_n; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h index 6a2a519fca4..9e565d205f8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h @@ -185,10 +185,8 @@ collect_duplicated_stitchable_boundary_edges if(per_cc) { cc = get(Face_property_tag(), pmesh); - typedef typename GetFaceIndexMap::const_type FIMap; - FIMap fim = parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_const_property_map(face_index, pmesh)); - num_component = num_component_wrapper(pmesh, cc, fim); + + num_component = num_component_wrapper(pmesh, cc, CGAL::get_initialized_face_index_map(pmesh, np)); border_edges_per_cc.resize(num_component); } @@ -862,16 +860,18 @@ std::size_t stitch_borders(PolygonMesh& pmesh, /// @param np 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 `pmesh`. -/// If this parameter is omitted, an internal property map for -/// `CGAL::vertex_point_t` must be available in `PolygonMesh`.\cgalParamEnd -/// \cgalParamBegin{apply_per_connected_component} -/// specifies if the borders should only be stitched inside their own connected component. -/// In that case, a property map for `CGAL::face_index_t` should be either available as an internal property map -/// to `pmesh` or provided as the \ref pmp_namedparameters "Named Parameter" `face_index_map`. If this is not the case, -/// a default map will be created on the fly. -/// Default value is `false`.\cgalParamEnd -/// \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh` \cgalParamEnd +/// \cgalParamBegin{vertex_point_map} +/// the property map with the points associated to the vertices of `pmesh`. +/// If this parameter is omitted, an internal property map for +/// `CGAL::vertex_point_t` must be available in `PolygonMesh`. +/// \cgalParamEnd +/// \cgalParamBegin{apply_per_connected_component} +/// specifies if the borders should only be stitched inside their own connected component. +/// Default value is `false`. +/// \cgalParamEnd +/// \cgalParamBegin{face_index_map} +/// a property map containing for each face of `pmesh` a unique index between `0` and `num_faces(pmesh)-1` +/// \cgalParamEnd /// \cgalNamedParamsEnd /// /// @return the number of pairs of halfedges that were stitched. @@ -892,7 +892,7 @@ std::size_t stitch_borders(PolygonMesh& pmesh, typedef typename GetVertexPointMap::const_type VPMap; VPMap vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(vertex_point, pmesh)); + get_const_property_map(vertex_point, pmesh)); #ifdef CGAL_PMP_STITCHING_DEBUG std::cout << "------- Stitch cycles..." << std::endl; diff --git a/Polygon_mesh_processing/include/CGAL/Rigid_triangle_mesh_collision_detection.h b/Polygon_mesh_processing/include/CGAL/Rigid_triangle_mesh_collision_detection.h index ec20752cf83..2ce1278e7ae 100644 --- a/Polygon_mesh_processing/include/CGAL/Rigid_triangle_mesh_collision_detection.h +++ b/Polygon_mesh_processing/include/CGAL/Rigid_triangle_mesh_collision_detection.h @@ -537,11 +537,8 @@ public: std::vector cc_ids(num_faces(tm)); // face index map - typedef typename CGAL::GetFaceIndexMap::type Fid_map; - - Fid_map fid_map = - parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, tm)); + typedef typename GetInitializedFaceIndexMap::const_type FaceIndexMap; + FaceIndexMap fid_map = CGAL::get_initialized_face_index_map(tm, np); std::size_t nb_cc = Polygon_mesh_processing::connected_components( diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index b708ac434a8..6e480fbbdd2 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -35,14 +35,16 @@ find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) find_package( TBB ) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - # Creating entries for all .cpp/.C files with "main" routine # ########################################################## create_single_source_cgal_program("fairing_test.cpp") + CGAL_target_use_Eigen(fairing_test) create_single_source_cgal_program("triangulate_hole_Polyhedron_3_no_delaunay_test.cpp" ) + CGAL_target_use_Eigen(triangulate_hole_Polyhedron_3_no_delaunay_test) create_single_source_cgal_program("triangulate_hole_Polyhedron_3_test.cpp") + CGAL_target_use_Eigen(triangulate_hole_Polyhedron_3_test) create_single_source_cgal_program("test_shape_smoothing.cpp") + CGAL_target_use_Eigen(test_shape_smoothing) endif(EIGEN3_FOUND) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_polyhedron.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_polyhedron.cpp index 4a9fcec8ec7..35a7e3a75f0 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_polyhedron.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_polyhedron.cpp @@ -37,8 +37,8 @@ void mesh_with_id(const char* argv1, const bool save_output) std::cerr << cc.size() << " faces in the CC of " << &*fd << std::endl; boost::vector_property_map::type> - fccmap(get(boost::face_index,sm)); + boost::property_map::type> + fccmap(get(CGAL::face_index,sm)); std::size_t num = PMP::connected_components(sm, fccmap); if (strcmp(argv1, "data/blobby_3cc.off") == 0) @@ -84,17 +84,17 @@ void mesh_no_id(const char* argv1, const bool save_output) PMP::connected_component(fd, sm, std::back_inserter(cc)); std::cerr << cc.size() << " faces in the CC of " << &*fd << std::endl; - boost::property_map::type vim + boost::property_map::type vim = get(boost::vertex_external_index,sm); - boost::property_map::type fim + boost::property_map::type fim = get(boost::face_external_index,sm); boost::vector_property_map::type> fccmap(fim); - std::size_t num = PMP::connected_components(sm, fccmap, PMP::parameters::face_index_map(fim)); + std::size_t num = PMP::connected_components(sm, fccmap); if (strcmp(argv1, "data/blobby_3cc.off") == 0) assert(num == 3); @@ -104,8 +104,7 @@ void mesh_no_id(const char* argv1, const bool save_output) // std::cout << &*f << " in connected component " << fccmap[f] << std::endl; //} - PMP::keep_largest_connected_components(sm, 2, PMP::parameters::vertex_index_map(vim) - .face_index_map(fim)); + PMP::keep_largest_connected_components(sm, 2, PMP::parameters::vertex_index_map(vim)); if (save_output) return; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test_P_SM_OM.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test_P_SM_OM.cpp index 1769df9e09c..bed1ad1c583 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test_P_SM_OM.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test_P_SM_OM.cpp @@ -31,15 +31,21 @@ int main() } { - typedef CGAL::Polyhedron_3 P; - std::map::face_descriptor, std::size_t> fim; - P p; - std::ifstream in("data/elephant.off"); - in >> p; - PMP::isotropic_remeshing(faces(p), + typedef CGAL::Polyhedron_3 P; + + std::ifstream in("data/elephant.off"); + P p; + in >> p; + + std::map::face_descriptor, std::size_t> fim; + std::size_t fid = 0; + for(const boost::graph_traits

::face_descriptor f : faces(p)) + fim[f] = fid++; + + PMP::isotropic_remeshing(faces(p), 0.02, - p, - PMP::parameters::face_index_map(boost::make_assoc_property_map(fim))); + p, + PMP::parameters::face_index_map(boost::make_assoc_property_map(fim))); std::ofstream out("p.off"); out << p << std::endl; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_orient_cc.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_orient_cc.cpp index 34a54ecd273..8f846d3c455 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_orient_cc.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_orient_cc.cpp @@ -1,5 +1,7 @@ #include #include + +#include #include #include @@ -12,13 +14,13 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Surface_mesh SMesh; template -bool test_orientation(TriangleMesh& tm, bool is_positive, const NamedParameters& np) +bool test_orientation(const TriangleMesh& tm, bool is_positive, const NamedParameters& np) { typedef boost::graph_traits Graph_traits; typedef typename Graph_traits::vertex_descriptor vertex_descriptor; typedef typename Graph_traits::face_descriptor face_descriptor; typedef typename CGAL::GetVertexPointMap::const_type Vpm; - typedef typename CGAL::GetFaceIndexMap::const_type Fid_map; + typedef typename CGAL::GetInitializedFaceIndexMap::const_type Fid_map; using CGAL::parameters::choose_parameter; using CGAL::parameters::get_parameter; @@ -26,8 +28,7 @@ bool test_orientation(TriangleMesh& tm, bool is_positive, const NamedParameters& Vpm vpm = choose_parameter(get_parameter(np, CGAL::internal_np::vertex_point), CGAL::get_const_property_map(boost::vertex_point, tm)); - Fid_map fid_map = choose_parameter(get_parameter(np, CGAL::internal_np::face_index), - CGAL::get_const_property_map(boost::face_index, tm)); + Fid_map fid_map = CGAL::get_initialized_face_index_map(tm, np); std::vector face_cc(num_faces(tm), std::size_t(-1)); @@ -127,5 +128,6 @@ int main() return 1; } + std::cout << "Done!" << std::endl; return 0; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp index 94572946c5a..0fb9319c9f3 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp @@ -22,325 +22,447 @@ template void test() { // test with a clipper mesh - TriangleMesh tm1, tm2; + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/elephant.off") >> tm1; + std::ifstream("data-coref/sphere.off") >> tm2; - std::ifstream input("data-coref/elephant.off"); - input >> tm1; - input.close(); - input.open("data-coref/sphere.off"); - input >> tm2; - input.close(); + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); - PMP::clip(tm1, tm2, - params::clip_volume(false) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2)) - ); - assert(!CGAL::is_closed(tm1)); - CGAL::clear(tm1); - CGAL::clear(tm2); + PMP::clip(tm1, tm2, + params::clip_volume(false).face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(!CGAL::is_closed(tm1)); + } - input.open("data-coref/elephant.off"); - input >> tm1; - input.close(); - input.open("data-coref/sphere.off"); - input >> tm2; - input.close(); + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/elephant.off") >> tm1; + std::ifstream("data-coref/sphere.off") >> tm2; - PMP::clip(tm1, tm2, params::clip_volume(true) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(CGAL::is_closed(tm1)); - CGAL::clear(tm1); - CGAL::clear(tm2); + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + PMP::clip(tm1, tm2, + params::clip_volume(true).face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(CGAL::is_closed(tm1)); + } // test with a iso-cuboid - input.open("data-coref/elephant.off"); - input >> tm1; - input.close(); - K::Iso_cuboid_3 iso_cuboid(K::Point_3(0,0,0), K::Point_3(0.4, 0.6, 0.4)); + { + TriangleMesh tm1; + std::ifstream("data-coref/elephant.off") >> tm1; + K::Iso_cuboid_3 iso_cuboid(K::Point_3(0,0,0), K::Point_3(0.4, 0.6, 0.4)); - PMP::clip(tm1, iso_cuboid, params::clip_volume(true)); - assert(CGAL::is_closed(tm1)); - CGAL::clear(tm1); + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + + PMP::clip(tm1, iso_cuboid, params::clip_volume(true).face_index_map(custom_face_index_map_1)); + assert(CGAL::is_closed(tm1)); + } // test with a plane - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + K::Plane_3 plane(0, 0, 1, -1); - K::Plane_3 plane(0, 0, 1, -1); + PMP::clip(tm1, plane, params::clip_volume(true)); + assert(CGAL::is_closed(tm1)); + } - PMP::clip(tm1, plane, params::clip_volume(true)); - assert(CGAL::is_closed(tm1)); - CGAL::clear(tm1); + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + K::Plane_3 plane(0, 0, 1, -1); - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, plane, params::clip_volume(false) - .use_compact_clipper(false)); - assert(!CGAL::is_closed(tm1)); - CGAL::clear(tm1); + PMP::clip(tm1, plane, params::clip_volume(false).use_compact_clipper(false)); + assert(!CGAL::is_closed(tm1)); + } - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, plane, params::clip_volume(false) - .use_compact_clipper(true)); - assert(CGAL::is_closed(tm1)); - CGAL::clear(tm1); + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + K::Plane_3 plane(0, 0, 1, -1); - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, K::Plane_3(-0.236474, 0.437732, 0.867451, -0.838791), params::clip_volume(true)); - assert(CGAL::is_closed(tm1)); - assert(!CGAL::is_empty(tm1)); - CGAL::clear(tm1); + PMP::clip(tm1, plane, params::clip_volume(false).use_compact_clipper(true)); + assert(CGAL::is_closed(tm1)); + } - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, K::Plane_3(0, 0, 1, 2)); - assert(CGAL::is_empty(tm1)); - CGAL::clear(tm1); + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, K::Plane_3(0, 0, 1, -2)); - assert(!CGAL::is_empty(tm1)); - CGAL::clear(tm1); + PMP::clip(tm1, K::Plane_3(-0.236474, 0.437732, 0.867451, -0.838791), params::clip_volume(true)); + assert(CGAL::is_closed(tm1)); + assert(!CGAL::is_empty(tm1)); + } + + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + + PMP::clip(tm1, K::Plane_3(0, 0, 1, 2)); + assert(CGAL::is_empty(tm1)); + } + + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + + PMP::clip(tm1, K::Plane_3(0, 0, 1, -2)); + assert(!CGAL::is_empty(tm1)); + } // clipping with identity - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::clip(tm1, tm2,params::clip_volume(true) - .use_compact_clipper(true) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(num_vertices(tm1)==8); - CGAL::clear(tm1); - CGAL::clear(tm2); + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + std::ifstream("data-coref/cube.off") >> tm2; - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::clip(tm1, tm2,params::clip_volume(false) - .use_compact_clipper(false) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(CGAL::is_empty(tm1)); - CGAL::clear(tm1); - CGAL::clear(tm2); + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::clip(tm1, tm2,params::clip_volume(false) - .use_compact_clipper(true) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(num_vertices(tm1)==8); - CGAL::clear(tm1); - CGAL::clear(tm2); + PMP::clip(tm1, tm2, + params::clip_volume(true) + .use_compact_clipper(true) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(num_vertices(tm1) == 8); + } - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::transform(K::Aff_transformation_3(CGAL::TRANSLATION, K::Vector_3(1,0,0)), tm2); - PMP::clip(tm1, tm2,params::clip_volume(false) - .use_compact_clipper(false) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(CGAL::is_empty(tm1)); - CGAL::clear(tm1); - CGAL::clear(tm2); + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + std::ifstream("data-coref/cube.off") >> tm2; - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::transform(K::Aff_transformation_3(CGAL::TRANSLATION, K::Vector_3(1,0,0)), tm2); - PMP::clip(tm1, tm2,params::clip_volume(false) - .use_compact_clipper(true) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(vertices(tm1).size()==4); - CGAL::clear(tm1); - CGAL::clear(tm2); + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::clip_volume(false) + .use_compact_clipper(false) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(CGAL::is_empty(tm1)); + } + + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + std::ifstream("data-coref/cube.off") >> tm2; + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::clip_volume(false) + .use_compact_clipper(true) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(num_vertices(tm1) == 8); + } + + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + std::ifstream("data-coref/cube.off") >> tm2; + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::transform(K::Aff_transformation_3(CGAL::TRANSLATION, K::Vector_3(1,0,0)), tm2); + PMP::clip(tm1, tm2, + params::clip_volume(false) + .use_compact_clipper(false) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(CGAL::is_empty(tm1)); + } + + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + std::ifstream("data-coref/cube.off") >> tm2; + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::transform(K::Aff_transformation_3(CGAL::TRANSLATION, K::Vector_3(1,0,0)), tm2); + PMP::clip(tm1, tm2, + params::clip_volume(false) + .use_compact_clipper(true) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(vertices(tm1).size() == 4); + } // test orientation + patch without input vertex - CGAL::make_tetrahedron( - K::Point_3(0.53, -1.3, 0.2), - K::Point_3(0.53, 1.1, 0.2), - K::Point_3(0.53, -1.3, 0.4), - K::Point_3(0.73, -1.3, 0.2), - tm2); - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, tm2,params::clip_volume(false) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(vertices(tm1).size()==6); - CGAL::clear(tm1); - CGAL::clear(tm2); + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; - CGAL::make_tetrahedron( - K::Point_3(0.53, -1.3, 0.2), - K::Point_3(0.53, 1.1, 0.2), - K::Point_3(0.53, -1.3, 0.4), - K::Point_3(0.73, -1.3, 0.2), - tm2); - PMP::reverse_face_orientations(tm2); - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, tm2,params::clip_volume(false) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(vertices(tm1).size()==6+8); - CGAL::clear(tm1); - CGAL::clear(tm2); + CGAL::make_tetrahedron(K::Point_3(0.53, -1.3, 0.2), + K::Point_3(0.53, 1.1, 0.2), + K::Point_3(0.53, -1.3, 0.4), + K::Point_3(0.73, -1.3, 0.2), + tm2); + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::clip_volume(false) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(vertices(tm1).size() == 6); + } + + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + + CGAL::make_tetrahedron(K::Point_3(0.53, -1.3, 0.2), + K::Point_3(0.53, 1.1, 0.2), + K::Point_3(0.53, -1.3, 0.4), + K::Point_3(0.73, -1.3, 0.2), + tm2); + PMP::reverse_face_orientations(tm2); + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::clip_volume(false) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(vertices(tm1).size() == 6+8); + } // clip meshes with intersection polyline opened - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(1, 0, 0, -2)); - assert(vertices(tm1).size()==4); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(1, 0, 0, -2)); + assert(vertices(tm1).size() == 4); + } - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(-1, 0, 0, 2)); - assert(vertices(tm1).size()==3); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(-1, 0, 0, 2)); + assert(vertices(tm1).size() == 3); + } // test with clipper on border edge - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 1, 0), K::Point_3(1, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(0, 1, 0 , 0)); - assert(vertices(tm1).size()==0); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 1, 0), K::Point_3(1, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(0, 1, 0 , 0)); + assert(vertices(tm1).size() == 0); + } - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 1, 0), K::Point_3(1, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(0, -1, 0 , 0)); - assert(vertices(tm1).size()==4); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 1, 0), K::Point_3(1, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(0, -1, 0 , 0)); + assert(vertices(tm1).size() == 4); + } // test with clipper on border edge: full triangle - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(0, 0, 1, 0), params::use_compact_clipper(true)); - assert(vertices(tm1).size()!=0); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(0, 0, 1, 0), params::use_compact_clipper(true)); + assert(vertices(tm1).size()!=0); + } - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(0, 0, 1, 0), params::use_compact_clipper(false)); - assert(vertices(tm1).size()==0); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(0, 0, 1, 0), params::use_compact_clipper(false)); + assert(vertices(tm1).size() == 0); + } // test tangencies - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 2, 0), K::Point_3(1, 1, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(1, 0, 0, -1)); - assert(vertices(tm1).size()==3); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 2, 0), K::Point_3(1, 1, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(1, 0, 0, -1)); + assert(vertices(tm1).size() == 3); + } - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 2, 0), K::Point_3(1, 1, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(-1, 0, 0, 1)); - assert(vertices(tm1).size()==0); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 2, 0), K::Point_3(1, 1, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(-1, 0, 0, 1)); + assert(vertices(tm1).size() == 0); + } - make_triangle( K::Point_3(0.5, 0, 0.5), K::Point_3(1, 0.5, 0.5), K::Point_3(0.5, 1, 0.5), tm1 ); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::clip(tm1, tm2, params::face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(vertices(tm1).size()==3); - CGAL::clear(tm1); - CGAL::clear(tm2); + { + TriangleMesh tm1, tm2; + make_triangle( K::Point_3(0.5, 0, 0.5), K::Point_3(1, 0.5, 0.5), K::Point_3(0.5, 1, 0.5), tm1 ); + std::ifstream("data-coref/cube.off") >> tm2; - make_triangle( K::Point_3(0.5, 0, 0.5), K::Point_3(1, 0.5, 0.5), K::Point_3(0.5, 1, 0.5), tm1 ); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::reverse_face_orientations(tm2); - PMP::clip(tm1, tm2, params::face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(vertices(tm1).size()==0); - CGAL::clear(tm1); - CGAL::clear(tm2); + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(vertices(tm1).size() == 3); + } + + { + TriangleMesh tm1, tm2; + make_triangle( K::Point_3(0.5, 0, 0.5), K::Point_3(1, 0.5, 0.5), K::Point_3(0.5, 1, 0.5), tm1 ); + std::ifstream("data-coref/cube.off") >> tm2; + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::reverse_face_orientations(tm2); + PMP::clip(tm1, tm2, + params::face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(vertices(tm1).size() == 0); + } + + // test combinaison of use_compact_clipper and clip_volume + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + + // -> closed mesh, true/true + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(true).clip_volume(true)); + assert(faces(tm1).size() == 12); + assert(CGAL::is_closed(tm1)); + + // -> closed mesh, false/true + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(false).clip_volume(true)); + assert(faces(tm1).size() == 12); + assert(CGAL::is_closed(tm1)); + + // -> closed mesh, true/false + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(true).clip_volume(false)); + assert(faces(tm1).size() == 12); + assert(CGAL::is_closed(tm1)); + + // -> closed mesh, false/false + PMP::clip(tm1, K::Plane_3(1,0,0,-1), params::use_compact_clipper(false).clip_volume(false)); + assert(faces(tm1).size() == 10); + assert(!CGAL::is_closed(tm1)); + + // -> open mesh true/true + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(true).clip_volume(true)); + assert(faces(tm1).size() == 10); + + // -> open mesh true/false + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(true).clip_volume(false)); + assert(faces(tm1).size() == 10); + + // -> open mesh false/false + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(false).clip_volume(false)); + assert(faces(tm1).size() == 8); + + // -> open mesh false/true + PMP::clip(tm1, K::Plane_3(0,-1,0,0), params::use_compact_clipper(false).clip_volume(true)); + assert(faces(tm1).size() == 6); + } // test special case - input.open("data-clip/tm_1.off"); - input >> tm1; - input.close(); - input.open("data-clip/clipper_1.off"); - input >> tm2; - input.close(); - PMP::clip(tm1, tm2, params::face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(is_valid_polygon_mesh(tm1)); - CGAL::clear(tm1); - CGAL::clear(tm2); + { + TriangleMesh tm1, tm2; + std::ifstream("data-clip/tm_1.off") >> tm2; + std::ifstream("data-clip/clipper_1.off") >> tm2; + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(is_valid_polygon_mesh(tm1)); + } // non-manifold border vertices - std::stringstream ss; - ss << "OFF\n 5 2 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 0 1 4\n3 1 2 3\n"; - ss >> tm1; - PMP::clip(tm1, K::Plane_3(-1,0,0,2)); - assert(vertices(tm1).size()==3); - CGAL::clear(tm1); + { + TriangleMesh tm1; + std::stringstream ss; + ss << "OFF\n 5 2 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 0 1 4\n3 1 2 3\n"; + ss >> tm1; + PMP::clip(tm1, K::Plane_3(-1,0,0,2)); + assert(vertices(tm1).size() == 3); + } - ss.str(std::string()); - ss << "OFF\n 7 4 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 3 5\n"; - ss >> tm1; - CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); - PMP::clip(tm1, K::Plane_3(-1,0,0,2)); - assert(vertices(tm1).size()==6); - CGAL::clear(tm1); - - ss.str(std::string()); - ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; - ss >> tm1; - for (int i=0;i<3;++i) + { + TriangleMesh tm1; + std::stringstream ss; + ss << "OFF\n 7 4 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 3 5\n"; + ss >> tm1; CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); - PMP::clip(tm1, K::Plane_3(-1,0,0,2)); - assert(vertices(tm1).size()==7); - CGAL::clear(tm1); + PMP::clip(tm1, K::Plane_3(-1,0,0,2)); + assert(vertices(tm1).size() == 6); + } - ss.str(std::string()); - ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; - ss >> tm1; - for (int i=0;i<3;++i) - CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); - PMP::clip(tm1, K::Plane_3(0,1,0,0)); - assert(vertices(tm1).size()==3); - CGAL::clear(tm1); + { + TriangleMesh tm1; + std::stringstream ss; + ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; + ss >> tm1; + for (int i=0;i<3;++i) + CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); + PMP::clip(tm1, K::Plane_3(-1,0,0,2)); + assert(vertices(tm1).size() == 7); + } - ss.str(std::string()); - ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; - ss >> tm1; - for (int i=0;i<3;++i) - CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); - PMP::clip(tm1, K::Plane_3(0,-1,0,0)); - assert(vertices(tm1).size()==7); - CGAL::clear(tm1); + { + TriangleMesh tm1; + std::stringstream ss; + ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; + ss >> tm1; + for (int i=0;i<3;++i) + CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); + PMP::clip(tm1, K::Plane_3(0,1,0,0)); + assert(vertices(tm1).size() == 3); + } + + { + TriangleMesh tm1; + std::stringstream ss; + ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; + ss >> tm1; + for (int i=0;i<3;++i) + CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); + PMP::clip(tm1, K::Plane_3(0,-1,0,0)); + assert(vertices(tm1).size() == 7); + } } template @@ -396,20 +518,27 @@ void test_split() int main() { - std::cout << "running test with Surface_mesh\n"; + std::cout << "Surface Mesh" << std::endl; test(); - std::cout << "running test with Polyhedron\n"; + + std::cout << "Polyhedron" << std::endl; test(); + std::cout << "running test_split with Surface_mesh\n"; test_split(); + std::cout << "running test_split_plane with Surface_mesh\n"; test_split_plane(); + std::cout << "running test_split with Polyhedron\n"; test_split(); + std::cout << "running test_split_plane with Polyhedron\n"; test_split_plane(); - return 0; + std::cout << "Done!" << std::endl; + + return EXIT_SUCCESS; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_non_conforming_snapping.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_non_conforming_snapping.cpp index 7bdf106c1fa..5a5964ae604 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_non_conforming_snapping.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_non_conforming_snapping.cpp @@ -1,3 +1,6 @@ +//#define CGAL_PMP_SNAP_DEBUG_PP +//#define CGAL_PMP_SNAP_DEBUG_OUTPUT + #include #include @@ -68,6 +71,7 @@ void read_mesh(const char* filename, template void test(const char* filename, const double large_tolerance, + const double good_tolerance, const double small_tolerance) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -84,19 +88,19 @@ void test(const char* filename, // zero tolerance, just to test the API CGAL::Constant_property_map tol_pmap_zero(0); - PMP::experimental::snap_border_vertices_non_conforming(sm_cpy, sm_cpy); - PMP::experimental::snap_border_vertices_non_conforming(sm_cpy, sm_cpy, tol_pmap_zero); - PMP::experimental::snap_border_vertices_non_conforming(sm_cpy, sm_cpy, tol_pmap_zero, - CGAL::parameters::geom_traits(Kernel()), - CGAL::parameters::geom_traits(Kernel())); + PMP::experimental::snap_borders(sm_cpy, sm_cpy); + PMP::experimental::snap_borders(sm_cpy, tol_pmap_zero, sm_cpy, tol_pmap_zero); + PMP::experimental::snap_borders(sm_cpy, tol_pmap_zero, sm_cpy, tol_pmap_zero, + CGAL::parameters::geom_traits(Kernel()), + CGAL::parameters::geom_traits(Kernel())); // too big, creates wrong snaps sm_cpy = sm; CGAL::Constant_property_map tol_pmap_large(large_tolerance); - res = PMP::experimental::snap_border_vertices_non_conforming(sm_cpy, tol_pmap_large); + res = PMP::experimental::snap_borders(sm_cpy, tol_pmap_large); std::cout << "snapped: " << res << std::endl; - std::ofstream out1("out1.off"); + std::ofstream out1("too_large.off"); out1.precision(17); out1 << sm_cpy; out1.close(); @@ -104,53 +108,64 @@ void test(const char* filename, // too small sm_cpy = sm; CGAL::Constant_property_map tol_pmap_small(small_tolerance); - res = PMP::experimental::snap_border_vertices_non_conforming(sm_cpy, tol_pmap_small, - CGAL::parameters::geom_traits(Kernel())); + res = PMP::experimental::snap_borders(sm_cpy, tol_pmap_small, + CGAL::parameters::geom_traits(Kernel())); std::cout << "snapped: " << res << std::endl; - std::ofstream out2("out2.off"); + std::ofstream out2("too_small.off"); out2.precision(17); out2 << sm_cpy; out2.close(); - // automatically computed, custom tolerance at each vertex sm_cpy = sm; - res = PMP::experimental::snap_border_vertices_non_conforming(sm_cpy); + CGAL::Constant_property_map tol_pmap_good(good_tolerance); + res = PMP::experimental::snap_borders(sm_cpy, tol_pmap_good); std::cout << "snapped: " << res << std::endl; - std::ofstream out3("out3.off"); + std::ofstream out3("good.off"); out3.precision(17); out3 << sm_cpy; out3.close(); + + // automatically computed, custom tolerance at each vertex + sm_cpy = sm; + res = PMP::experimental::snap_borders(sm_cpy); + std::cout << "snapped: " << res << std::endl; + + std::ofstream out4("custom.off"); + out4.precision(17); + out4 << sm_cpy; + out4.close(); } void test(const char* filename, const double large_tolerance, + const double good_tolerance, const double small_tolerance) { std::cout << "######################## TEST FILE: " << filename << " ################## " << std::endl; std::cout << "~~~~~~~~~~~ TEST EPECK POLYHEDRON ~~~~~~~~~~~" << std::endl; - test(filename, large_tolerance, small_tolerance); + test(filename, large_tolerance, good_tolerance, small_tolerance); std::cout << std::endl << "~~~~~~~~~~~ TEST EPICK POLYHEDRON ~~~~~~~~~~~" << std::endl; - test(filename, large_tolerance, small_tolerance); + test(filename, large_tolerance, good_tolerance, small_tolerance); std::cout << std::endl << "~~~~~~~~~~~ TEST EPICK SURFACE MESH ~~~~~~~~~~~" << std::endl; - test(filename, large_tolerance, small_tolerance); + test(filename, large_tolerance, good_tolerance, small_tolerance); } int main(int, char**) { - test("data_snapping/non_conform_snapping.off", 0.02, 0.001); - test("data_snapping/non-conform_snapping-hole.off", 0.02, 0.001); - test("data_snapping/non_conform_snapping-multiple_ccs.off", 0.02, 0.001); - test("data_snapping/non-conform_snapping-overlap.off", 0.02, 0.001); + test("data_snapping/non_conform_snapping.off", 0.2, 0.01, 0.0001); + test("data_snapping/non-conform_snapping-hole.off", 0.2, 0.01, 0.0001); + test("data_snapping/non_conform_snapping-multiple_ccs.off", 0.02, 0.01, 0.0001); + test("data_snapping/non-conform_snapping-overlap.off", 0.2, 0.01, 0.0001); - test("data_snapping/real_data.off", 1., 0.05); - test("data_snapping/real_data_2.off", 2, 0.1); + test("data_snapping/real_data.off", 1., 0.05, 0.0008); + test("data_snapping/real_data_2.off", 2, 0.05, 0.000001); - test("data_snapping/pig.stl", 20, 0.01); + test("data_snapping/pig.stl", 20, 0.3, 0.001); return EXIT_SUCCESS; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_snapping.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_snapping.cpp index 3ae3d761799..5a9a535275d 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_snapping.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_snapping.cpp @@ -1,3 +1,5 @@ +// #define CGAL_PMP_SNAP_DEBUG_PP + #include #include @@ -6,6 +8,7 @@ #include #include +#include #include #include @@ -37,7 +40,9 @@ void test_1() Mesh fg_source, fg_target; // empty meshes - std::size_t res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source, fg_target); + std::cout << "Empty meshes tests..." << std::endl; + + std::size_t res = PMP::experimental::snap_border_vertices(fg_source, fg_target); assert(res == 0); std::ifstream source_input("data_snapping/border_snapping_source.off"); @@ -47,17 +52,12 @@ void test_1() return; } - std::vector border_vertices; - PMP::border_halfedges(fg_source, std::back_inserter(border_vertices)); - std::cout << border_vertices.size() << " border vertices" << std::endl; - // one empty mesh - std::cout << "Empty meshes tests..." << std::endl; - res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source, fg_target); + res = PMP::experimental::snap_border_vertices(fg_source, fg_target); std::cout << "res: " << res << " (expected 0)" << std::endl; assert(res == 0); - res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_target, halfedges(fg_source), fg_source); + res = PMP::experimental::snap_border_vertices(fg_target, fg_source); std::cout << "res: " << res << " (expected 0)" << std::endl; assert(res == 0); @@ -72,23 +72,35 @@ void test_1() // this epsilon value is too small, nothing happens std::cout << "*********************** EPS = 0.000000001 *************** " << std::endl; + CGAL::Constant_property_map tol_map_small(0.000000001); - res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source_cpy, fg_target, tol_map_small); - res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source_cpy, halfedges(fg_target), fg_target, tol_map_small); + res = PMP::experimental::snap_border_vertices(fg_source_cpy, tol_map_small, fg_target, tol_map_small); + std::cout << "res: " << res << " (expected 0)" << std::endl; + assert(res == 0); + + std::vector source_halfedge_range; + PMP::internal::vertices_as_halfedges(vertices(fg_source_cpy), fg_source_cpy, std::back_inserter(source_halfedge_range)); + std::vector target_halfedge_range; + PMP::internal::vertices_as_halfedges(vertices(fg_target), fg_target, std::back_inserter(target_halfedge_range)); + + res = PMP::experimental::snap_vertices(source_halfedge_range, fg_source_cpy, tol_map_small, + target_halfedge_range, fg_target, tol_map_small); + std::cout << "res: " << res << " (expected 0)" << std::endl; assert(res == 0); // this epsilon value is too big; everything gets snapped! std::cout << "*********************** EPS = 0.1 *************** " << std::endl; - CGAL::Constant_property_map tol_map_big(0.1); - fg_source_cpy = fg_source; - border_vertices.clear(); + fg_source_cpy = fg_source; + std::vector border_vertices; PMP::border_halfedges(fg_source_cpy, std::back_inserter(border_vertices)); - res = PMP::experimental::snap_vertex_range_onto_vertex_range(border_vertices, fg_source_cpy, - halfedges(fg_target), fg_target, tol_map_big, - params::geom_traits(Kernel()), params::all_default()); + CGAL::Constant_property_map tol_map_big(0.1); + res = PMP::experimental::snap_vertices(border_vertices, fg_source_cpy, tol_map_big, + target_halfedge_range, fg_target, tol_map_big, + params::geom_traits(Kernel()), + params::do_lock_mesh(true)); std::cout << "res: " << res << " (expected 154)" << std::endl; assert(res == 154); @@ -96,24 +108,28 @@ void test_1() // this is a good value of 'epsilon', but not all expected vertices are projected // because the sampling of the border of the source mesh is not uniform std::cout << "*********************** EPS = 0.001 *************** " << std::endl; - CGAL::Constant_property_map tol_map_good(0.001); - fg_source_cpy = fg_source; + fg_source_cpy = fg_source; border_vertices.clear(); PMP::border_halfedges(fg_source_cpy, std::back_inserter(border_vertices)); - res = PMP::experimental::snap_vertex_range_onto_vertex_range(border_vertices, fg_source_cpy, - halfedges(fg_target), fg_target, tol_map_good); + CGAL::Constant_property_map tol_map_good(0.001); + res = PMP::experimental::snap_vertices(border_vertices, fg_source_cpy, tol_map_good, + target_halfedge_range, fg_target, tol_map_good, + params::all_default(), params::do_lock_mesh(true)); std::cout << "res: " << res << " vertices" << std::endl; assert(res == 76); - std::ofstream partial_snap_out("partially_snapped_mesh.off"); - partial_snap_out << std::setprecision(17) << fg_source_cpy; - // this one automatically computes an epsilon bound at each vertex std::cout << "*********************** EPS = LOCALLY COMPUTED *************** " << std::endl; + fg_source_cpy = fg_source; - res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source_cpy, fg_target); + border_vertices.clear(); + PMP::border_halfedges(fg_source_cpy, std::back_inserter(border_vertices)); + + res = PMP::experimental::snap_vertices(border_vertices, fg_source_cpy, + target_halfedge_range, fg_target, + params::all_default(), params::do_lock_mesh(true)); std::cout << "res: " << res << " vertices" << std::endl; assert(res == 77); @@ -147,9 +163,11 @@ void test_2() // if a target vertex is already occupied, the source vertex will go to the next one that is // within tolerance and is available CGAL::Constant_property_map tol_map(0.5); - std::size_t res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source, fg_target, tol_map); + std::size_t res = PMP::experimental::snap_border_vertices(fg_source, tol_map, fg_target, tol_map); std::cout << "res: " << res << " vertices" << std::endl; assert(res == 3); + + std::ofstream("out.off") << fg_source; } template diff --git a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/CMakeLists.txt b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/CMakeLists.txt index 5572052eb2e..20d0abef1c2 100644 --- a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/CMakeLists.txt +++ b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/CMakeLists.txt @@ -36,58 +36,35 @@ endif() include( CGAL_CreateSingleSourceCGALProgram ) +find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) +if(NOT EIGEN3_FOUND) + message(STATUS "NOTICE: This project requires Eigen 3.1 (or greater) and will not be compiled.") + return() +endif() + +find_package(SCIP QUIET) +if (NOT SCIP_FOUND ) + find_package( GLPK QUIET) + if ( NOT GLPK_FOUND ) + message( STATUS "NOTICE: This project requires either SCIP or GLPK, and will not be compiled.") + return() + endif() +endif() + create_single_source_cgal_program( "polyfit_example_without_input_planes.cpp" ) create_single_source_cgal_program( "polyfit_example_user_provided_planes.cpp" ) create_single_source_cgal_program( "polyfit_example_model_complexty_control.cpp" ) create_single_source_cgal_program( "polyfit_example_with_region_growing.cpp" ) -find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) -if(EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - - find_package( SCIP QUIET) - - if ( NOT SCIP_FOUND ) - find_package( GLPK QUIET) - - if ( NOT GLPK_FOUND ) - message( STATUS "NOTICE: This project requires either SCIP or GLPK, and will not be compiled. " - "Please provide either 'SCIP_DIR' or 'GLPK_INCLUDE_DIR' and 'GLPK_LIBRARIES'") - else() - - - include_directories( BEFORE ${GLPK_INCLUDE_DIR} ) - - target_link_libraries( polyfit_example_without_input_planes PRIVATE ${GLPK_LIBRARIES} ) - target_compile_definitions(polyfit_example_without_input_planes PRIVATE -DCGAL_USE_GLPK) - target_link_libraries( polyfit_example_user_provided_planes PRIVATE ${GLPK_LIBRARIES} ) - target_compile_definitions(polyfit_example_user_provided_planes PRIVATE -DCGAL_USE_GLPK) - target_link_libraries( polyfit_example_model_complexty_control PRIVATE ${GLPK_LIBRARIES} ) - target_compile_definitions(polyfit_example_model_complexty_control PRIVATE -DCGAL_USE_GLPK) - target_link_libraries( polyfit_example_with_region_growing PRIVATE ${GLPK_LIBRARIES} ) - target_compile_definitions(polyfit_example_with_region_growing PRIVATE -DCGAL_USE_GLPK) - - message("GLPK found and used") - - endif() - +foreach(target + polyfit_example_without_input_planes + polyfit_example_user_provided_planes + polyfit_example_model_complexty_control + polyfit_example_with_region_growing) + CGAL_target_use_Eigen(${target}) + if (SCIP_FOUND) + CGAL_target_use_SCIP(${target}) else() - - include_directories( BEFORE ${SCIP_INCLUDE_DIRS} ) - - target_link_libraries( polyfit_example_without_input_planes PRIVATE ${SCIP_LIBRARIES} ) - target_compile_definitions(polyfit_example_without_input_planes PRIVATE -DCGAL_USE_SCIP) - target_link_libraries( polyfit_example_user_provided_planes PRIVATE ${SCIP_LIBRARIES} ) - target_compile_definitions(polyfit_example_user_provided_planes PRIVATE -DCGAL_USE_SCIP) - target_link_libraries( polyfit_example_model_complexty_control PRIVATE ${SCIP_LIBRARIES} ) - target_compile_definitions(polyfit_example_model_complexty_control PRIVATE -DCGAL_USE_SCIP) - target_link_libraries( polyfit_example_with_region_growing PRIVATE ${SCIP_LIBRARIES} ) - target_compile_definitions(polyfit_example_with_region_growing PRIVATE -DCGAL_USE_SCIP) - - message("SCIP found and used") - + CGAL_target_use_GLPK(${target}) endif() - -else() - message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.") -endif() +endforeach() diff --git a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_model_complexty_control.cpp b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_model_complexty_control.cpp index 53d0a4ad1c3..5e48efa5552 100644 --- a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_model_complexty_control.cpp +++ b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_model_complexty_control.cpp @@ -5,10 +5,10 @@ #include #include -#ifdef CGAL_USE_SCIP +#ifdef CGAL_USE_SCIP // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::SCIP_mixed_integer_program_traits MIP_Solver; -#elif defined(CGAL_USE_GLPK) +#elif defined(CGAL_USE_GLPK) // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::GLPK_mixed_integer_program_traits MIP_Solver; #endif diff --git a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_user_provided_planes.cpp b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_user_provided_planes.cpp index 8b56101a76f..e997b671ade 100644 --- a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_user_provided_planes.cpp +++ b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_user_provided_planes.cpp @@ -5,10 +5,10 @@ #include #include -#ifdef CGAL_USE_SCIP +#ifdef CGAL_USE_SCIP // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::SCIP_mixed_integer_program_traits MIP_Solver; -#elif defined(CGAL_USE_GLPK) +#elif defined(CGAL_USE_GLPK) // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::GLPK_mixed_integer_program_traits MIP_Solver; #endif diff --git a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_with_region_growing.cpp b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_with_region_growing.cpp index 0cfe1cd02ff..4cc561a8ae6 100644 --- a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_with_region_growing.cpp +++ b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_with_region_growing.cpp @@ -7,12 +7,12 @@ #include #include -#ifdef CGAL_USE_SCIP +#ifdef CGAL_USE_SCIP // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::SCIP_mixed_integer_program_traits MIP_Solver; -#elif defined(CGAL_USE_GLPK) +#elif defined(CGAL_USE_GLPK) // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::GLPK_mixed_integer_program_traits MIP_Solver; @@ -196,4 +196,4 @@ int main(int, char**) return EXIT_SUCCESS; } -#endif // defined(CGAL_USE_GLPK) || defined(CGAL_USE_SCIP) \ No newline at end of file +#endif // defined(CGAL_USE_GLPK) || defined(CGAL_USE_SCIP) diff --git a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_without_input_planes.cpp b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_without_input_planes.cpp index 76531b62ed8..cd37cc996f1 100644 --- a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_without_input_planes.cpp +++ b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_without_input_planes.cpp @@ -6,12 +6,12 @@ #include #include -#ifdef CGAL_USE_SCIP +#ifdef CGAL_USE_SCIP // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::SCIP_mixed_integer_program_traits MIP_Solver; -#elif defined(CGAL_USE_GLPK) +#elif defined(CGAL_USE_GLPK) // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::GLPK_mixed_integer_program_traits MIP_Solver; diff --git a/Polygonal_surface_reconstruction/test/Polygonal_surface_reconstruction/CMakeLists.txt b/Polygonal_surface_reconstruction/test/Polygonal_surface_reconstruction/CMakeLists.txt index e5f6f23675a..9a88f8a5dc6 100644 --- a/Polygonal_surface_reconstruction/test/Polygonal_surface_reconstruction/CMakeLists.txt +++ b/Polygonal_surface_reconstruction/test/Polygonal_surface_reconstruction/CMakeLists.txt @@ -11,7 +11,7 @@ find_package( CGAL QUIET COMPONENTS ) if ( NOT CGAL_FOUND ) - message(STATUS "This project requires the CGAL library, and will not be compiled.") + message(STATUS "NOTICE: This project requires the CGAL library, and will not be compiled.") return() endif() @@ -24,8 +24,11 @@ include( ${CGAL_USE_FILE} ) find_package( Boost REQUIRED ) if ( NOT Boost_FOUND ) - message(STATUS "This project requires the Boost library, and will not be compiled.") + + message(STATUS "NOTICE: This project requires the Boost library, and will not be compiled.") + return() + endif() # Creating entries for all C++ files with "main" routine @@ -33,49 +36,26 @@ endif() include( CGAL_CreateSingleSourceCGALProgram ) -create_single_source_cgal_program( "polygonal_surface_reconstruction_test.cpp" ) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) -if(EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - - # Executables that require Eigen 3.1 - find_package( SCIP QUIET) - - if (SCIP_FOUND) - - include_directories( BEFORE ${SCIP_INCLUDE_DIRS} ) - - target_link_libraries( polygonal_surface_reconstruction_test PRIVATE ${SCIP_LIBRARIES} ) - - target_compile_definitions(polygonal_surface_reconstruction_test PRIVATE -DCGAL_USE_SCIP) - - message("SCIP found and used") - - endif() - - - find_package( GLPK QUIET) - - if (GLPK_FOUND) - - include_directories( BEFORE ${GLPK_INCLUDE_DIR} ) - - target_link_libraries( polygonal_surface_reconstruction_test PRIVATE ${GLPK_LIBRARIES} ) - - target_compile_definitions(polygonal_surface_reconstruction_test PRIVATE -DCGAL_USE_GLPK) - - message("GLPK found and used") - - endif() - - - if (NOT SCIP_FOUND AND NOT GLPK_FOUND) - - message(STATUS "NOTICE: This project requires either SCIP or GLPK, some functions will not be tested. " - "Please provide either 'SCIP_DIR' or 'GLPK_INCLUDE_DIR' and 'GLPK_LIBRARIES'") - - endif() -else() - message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.") +if(NOT EIGEN3_FOUND) + message(STATUS "NOTICE: This project requires Eigen 3.1 (or greater) and will not be compiled.") + return() +endif() + +find_package(SCIP QUIET) +if (NOT SCIP_FOUND ) + find_package( GLPK QUIET) + if ( NOT GLPK_FOUND ) + message( STATUS "NOTICE : This project requires either SCIP or GLPK, and will not be compiled.") + return() + endif() +endif() + +create_single_source_cgal_program( "polygonal_surface_reconstruction_test.cpp") +CGAL_target_use_Eigen(polygonal_surface_reconstruction_test) +if (SCIP_FOUND) + CGAL_target_use_SCIP(polygonal_surface_reconstruction_test) +else() + CGAL_target_use_GLPK(polygonal_surface_reconstruction_test) endif() diff --git a/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp b/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp index 07c630b7828..50b969ed1bc 100644 --- a/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp +++ b/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp @@ -1,5 +1,5 @@ #include "CGAL_double_edit.h" - +#include #include class DoubleValidator : public QDoubleValidator @@ -59,7 +59,7 @@ public: void DoubleEdit::setRange(double min, double max) { - this->validator->setRange(min, max); + this->validator->setRange(min, max, this->validator->decimals()); } double DoubleEdit::getValue() diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 1b1cd817152..6d3f9dc346f 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -64,7 +64,7 @@ include(${CGAL_USE_FILE}) find_package(Qt5 QUIET COMPONENTS OpenGL Script - OPTIONAL_COMPONENTS ScriptTools) + OPTIONAL_COMPONENTS ScriptTools WebSockets) if(Qt5_FOUND) @@ -73,9 +73,6 @@ if(Qt5_FOUND) endif(Qt5_FOUND) find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -endif(EIGEN3_FOUND) find_package( METIS ) @@ -95,6 +92,11 @@ if( POLYHEDRON_DEMO_ACTIVATE_CONCURRENCY ) endif() endif() +#find libssh for scene sharing +find_package(LibSSH) +if( NOT LIBSSH_FOUND ) + message("NOTICE : The SSH features will be disabled.") +endif() # Activate concurrency ? (turned OFF by default) option(CGAL_ACTIVATE_CONCURRENT_MESH_3 @@ -131,7 +133,7 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) qt5_wrap_ui( statisticsUI_FILES Statistics_on_item_dialog.ui) qt5_wrap_ui( FileLoaderDialogUI_files FileLoaderDialog.ui ) qt5_wrap_ui( Show_point_dialogUI_FILES Show_point_dialog.ui ) - qt5_wrap_ui( PreferencesUI_FILES Preferences.ui Details.ui) + qt5_wrap_ui( PreferencesUI_FILES Preferences.ui Details.ui SSH_dialog.ui) qt5_wrap_ui( Show_point_dialogUI_FILES Show_point_dialog.ui ) qt5_wrap_ui( ViewerUI_FILES LightingDialog.ui) qt5_generate_moc( "File_loader_dialog.h" "${CMAKE_CURRENT_BINARY_DIR}/File_loader_dialog_moc.cpp" ) @@ -195,6 +197,11 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) target_link_libraries(demo_framework PUBLIC Qt5::OpenGL Qt5::Widgets Qt5::Gui Qt5::Script ) + if(TARGET Qt5::WebSockets) + target_link_libraries(demo_framework PUBLIC Qt5::WebSockets) + message(STATUS "Qt5WebSockets was found. Using WebSockets is therefore possible.") + endif() + cgal_add_compilation_test(demo_framework) # Let's define `three_EXPORT` during the compilation of `demo_framework`, # in addition of `demo_framework_EXPORT` (defined automatically by @@ -276,12 +283,15 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) if(EIGEN3_FOUND ) add_item(scene_textured_item Scene_textured_surface_mesh_item.cpp texture.cpp) + CGAL_target_use_Eigen(scene_textured_item) qt5_wrap_ui( editionUI_FILES Plugins/Surface_mesh_deformation/Deform_mesh.ui ) add_item(scene_edit_item Plugins/Surface_mesh_deformation/Scene_edit_polyhedron_item.cpp ${editionUI_FILES}) + CGAL_target_use_Eigen(scene_edit_item) target_link_libraries(scene_edit_item PUBLIC scene_surface_mesh_item scene_k_ring_selection scene_basic_objects) add_item(scene_mcf_item Plugins/PMP/Scene_mcf_item.cpp) + CGAL_target_use_Eigen(scene_mcf_item) endif() add_item(scene_implicit_function_item Scene_implicit_function_item.cpp ) @@ -293,19 +303,19 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) add_item(scene_nef_polyhedron_item Scene_nef_polyhedron_item.cpp) target_link_libraries(scene_nef_polyhedron_item PUBLIC scene_surface_mesh_item) + add_item(scene_points_with_normal_item Scene_points_with_normal_item.cpp) + if (EIGEN3_FOUND) + CGAL_target_use_Eigen(scene_points_with_normal_item) + endif() + find_package(LASLIB) if (LASLIB_FOUND) - include(${LASLIB_USE_FILE}) - include_directories(${LASLIB_INCLUDE_DIR}) - include_directories(${LASZIP_INCLUDE_DIR}) - add_item(scene_points_with_normal_item Scene_points_with_normal_item.cpp) + CGAL_target_use_LASLIB(scene_points_with_normal_item) if (MSVC) target_compile_definitions( scene_points_with_normal_item PUBLIC "-D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS") endif() - target_link_libraries( scene_points_with_normal_item PUBLIC ${LASLIB_LIBRARIES}) - else() - add_item(scene_points_with_normal_item Scene_points_with_normal_item.cpp) endif() + if(TBB_FOUND) CGAL_target_use_TBB(scene_points_with_normal_item) endif() @@ -329,11 +339,20 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) MainWindow.cpp Polyhedron_demo.cpp File_loader_dialog_moc.cpp + Use_ssh.cpp ${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES} ${FileLoaderDialogUI_files} ${MainWindowUI_files} ${PreferencesUI_FILES} ${statisticsUI_FILES} ${SubViewerUI_files}) target_link_libraries(polyhedron_demo PUBLIC demo_framework point_dialog Qt5::Gui Qt5::OpenGL Qt5::Widgets Qt5::Script) + if(LIBSSH_FOUND) + add_definitions(-DCGAL_USE_SSH) + target_link_libraries(polyhedron_demo PUBLIC ${LIBSSH_LIBRARIES}) + endif() #libssh + if(TARGET Qt5::WebSockets) + add_definitions(-DCGAL_USE_WEBSOCKETS) + target_link_libraries(polyhedron_demo PUBLIC Qt5::WebSockets) + endif() add_executable ( Polyhedron_3 Polyhedron_3.cpp ) target_link_libraries( Polyhedron_3 PRIVATE polyhedron_demo ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS Polyhedron_3 ) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index b91b64069fd..d8872fd851f 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -1,3 +1,6 @@ +#ifdef CGAL_USE_SSH +# include "CGAL/Use_ssh.h" +#endif #include #include "config.h" @@ -7,6 +10,7 @@ #include #include #include +#include #include #include @@ -42,6 +46,7 @@ #include #include #include +#include #ifdef QT_SCRIPT_LIB # include # ifdef QT_SCRIPTTOOLS_LIB @@ -58,6 +63,7 @@ #include "ui_Preferences.h" #include "ui_Details.h" #include "ui_Statistics_on_item_dialog.h" +#include "ui_SSH_dialog.h" #include "Show_point_dialog.h" #include "File_loader_dialog.h" #include "Viewer.h" @@ -69,6 +75,14 @@ # include # include #include "Color_map.h" + + +#ifdef CGAL_USE_WEBSOCKETS +#include +#include +#include +#endif + using namespace CGAL::Three; QScriptValue myScene_itemToScriptValue(QScriptEngine *engine, @@ -150,6 +164,7 @@ MainWindow::MainWindow(const QStringList &keywords, bool verbose, QWidget* paren // remove the Load Script menu entry, when the demo has not been compiled with QT_SCRIPT_LIB #if !defined(QT_SCRIPT_LIB) ui->menuBar->removeAction(ui->actionLoadScript); + ui->menuBar->removeAction(ui->on_actionLoad_a_Scene_from_a_Script_File); #endif // Save some pointers from ui, for latter use. sceneView = ui->sceneView; @@ -158,9 +173,9 @@ MainWindow::MainWindow(const QStringList &keywords, bool verbose, QWidget* paren CGAL::Three::Three::s_mainviewer = viewer; viewer->setObjectName("mainViewer"); viewer_window->showMaximized(); - viewer_window->setWindowFlags( + viewer_window->setWindowFlags( Qt::SubWindow - | Qt::CustomizeWindowHint + | Qt::CustomizeWindowHint | Qt::WindowMaximizeButtonHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint @@ -353,7 +368,7 @@ MainWindow::MainWindow(const QStringList &keywords, bool verbose, QWidget* paren // Load plugins, and re-enable actions that need it. operationSearchBar.setPlaceholderText("Filter..."); - searchAction->setDefaultWidget(&operationSearchBar); + searchAction->setDefaultWidget(&operationSearchBar); connect(&operationSearchBar, &QLineEdit::textChanged, this, [=](){filterOperations(true);}); loadPlugins(); @@ -689,7 +704,7 @@ bool MainWindow::load_plugin(QString fileName, bool blacklisted) else{ //qdebug << "error: " << qPrintable(loader.errorString()); pluginsStatus_map[name] = loader.errorString(); - + } PathNames_map[name].push_back(fileinfo.absoluteDir().absolutePath()); return true; @@ -933,7 +948,7 @@ void MainWindow::viewerShow(float xmin, } void MainWindow::viewerShow(Viewer_interface* vi, float x, float y, float z) { - + CGAL::qglviewer::ManipulatedCameraFrame backup_frame(*vi->camera()->frame()); vi->camera()->fitSphere(CGAL::qglviewer::Vec(x, y, z), vi->camera()->sceneRadius()/100); @@ -1000,20 +1015,25 @@ void MainWindow::computeViewerBBox(CGAL::qglviewer::Vec& min, CGAL::qglviewer::V const double xmax = bbox.xmax(); const double ymax = bbox.ymax(); const double zmax = bbox.zmax(); - - - + + + min = CGAL::qglviewer::Vec(xmin, ymin, zmin); max= CGAL::qglviewer::Vec(xmax, ymax, zmax); - + CGAL::qglviewer::Vec bbox_center((xmin+xmax)/2, (ymin+ymax)/2, (zmin+zmax)/2); - CGAL::qglviewer::Vec offset(0,0,0); + double bbox_diag = CGAL::approximate_sqrt( + CGAL::square(xmax - xmin) + + CGAL::square(ymax - ymin) + + CGAL::square(zmax - zmin)); + CGAL::qglviewer::Vec offset(0,0,0); + double l_dist = (std::max)((std::abs)(bbox_center.x - viewer->offset().x), (std::max)((std::abs)(bbox_center.y - viewer->offset().y), (std::abs)(bbox_center.z - viewer->offset().z))); - if((std::log2)(l_dist) > 13.0 ) + if((std::log2)(l_dist/bbox_diag) > 13.0 ) for(int i=0; i<3; ++i) { offset[i] = -bbox_center[i]; @@ -1235,7 +1255,7 @@ void MainWindow::open(QString filename) settings.setValue("OFF open directory", fileinfo.absoluteDir().absolutePath()); loadItem(fileinfo, findLoader(load_pair.first), ok); - + if(!ok) return; this->addToRecentFiles(fileinfo.absoluteFilePath()); @@ -1422,7 +1442,7 @@ void MainWindow::selectionChanged() { if(vi == NULL) continue; - + if(item != NULL && item->manipulatable()) { vi->setManipulatedFrame(item->manipulatedFrame()); } else { @@ -1493,6 +1513,7 @@ void MainWindow::showSceneContextMenu(int selectedItemIndex, } } menu->addMenu(ui->menuOperations); + if(menu) menu->exec(global_pos); } @@ -1556,7 +1577,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { menu_actions["line width"] = action->menu()->actions().last(); } } - + } Q_FOREACH(Scene::Item_id index, scene->selectionIndices()) { @@ -1589,7 +1610,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1624,7 +1645,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1659,7 +1680,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1702,7 +1723,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1755,6 +1776,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { QAction* saveas = menu.addAction(tr("&Save as...")); connect(saveas, SIGNAL(triggered()), this, SLOT(on_actionSaveAs_triggered())); + menu.addMenu(ui->menuOperations); menu.exec(sender->mapToGlobal(p)); return; } @@ -1825,6 +1847,7 @@ void MainWindow::readSettings() this->default_point_size = settings.value("points_size").toInt(); this->default_normal_length = settings.value("normals_length").toInt(); this->default_lines_width = settings.value("lines_width").toInt(); + setProperty("ws_url", settings.value("ws_server_url").toString()); } void MainWindow::writeSettings() @@ -1899,14 +1922,7 @@ void MainWindow::throw_exception() { void MainWindow::on_actionLoadScript_triggered() { #if defined(QT_SCRIPT_LIB) - QString filename = QFileDialog::getOpenFileName( - this, - tr("Select a script to run..."), - ".", - "QTScripts (*.js);;All Files (*)"); - if(filename.isEmpty()) - return; - loadScript(QFileInfo(filename)); + #endif } @@ -1936,7 +1952,7 @@ void MainWindow::on_actionLoad_triggered() filters << filter; } } - + QString directory = settings.value("OFF open directory", QDir::current().dirName()).toString(); @@ -1964,7 +1980,7 @@ void MainWindow::on_actionLoad_triggered() static_cast(nb_files), std::back_inserter(colors_)); std::size_t nb_item = -1; - + Q_FOREACH(const QString& filename, dialog.selectedFiles()) { CGAL::Three::Scene_item* item = NULL; @@ -2189,7 +2205,7 @@ void MainWindow::on_actionShowHide_triggered() item->redraw(); } scene->setUpdatesEnabled(true); - updateViewersBboxes(false); +// updateViewersBboxes(false); //Not usable :when the scene changes scale, smaller items disappear. } void MainWindow::on_actionSetPolyhedronA_triggered() @@ -2209,7 +2225,6 @@ void MainWindow::on_actionPreferences_triggered() QDialog dialog(this); Ui::PreferencesDialog prefdiag; prefdiag.setupUi(&dialog); - float lineWidth[2]; if(!viewer->isOpenGL_4_3()) viewer->glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidth); @@ -2220,22 +2235,22 @@ void MainWindow::on_actionPreferences_triggered() } prefdiag.linesHorizontalSlider->setMinimum(lineWidth[0]); prefdiag.linesHorizontalSlider->setMaximum(lineWidth[1]); - + prefdiag.offset_updateCheckBox->setChecked( settings.value("offset_update", false).toBool()); connect(prefdiag.offset_updateCheckBox, SIGNAL(toggled(bool)), scene, SLOT(enableVisibilityRecentering(bool))); - + prefdiag.antialiasingCheckBox->setChecked(settings.value("antialiasing", false).toBool()); connect(prefdiag.antialiasingCheckBox, SIGNAL(toggled(bool)), viewer, SLOT(setAntiAliasing(bool))); - + prefdiag.quick_cameraCheckBox->setChecked( settings.value("quick_camera_mode", true).toBool()); connect(prefdiag.quick_cameraCheckBox, SIGNAL(toggled(bool)), viewer, SLOT(setFastDrawing(bool))); prefdiag.max_itemsSpinBox->setValue(viewer->textRenderer()->getMax_textItems()); - + connect(prefdiag.max_itemsSpinBox,static_cast(&QSpinBox::valueChanged), this, [this](int i){ setMaxTextItemsDisplayed(i); @@ -2266,20 +2281,20 @@ void MainWindow::on_actionPreferences_triggered() }); connect(prefdiag.background_colorPushButton, &QPushButton::clicked, this, &MainWindow::setBackgroundColor); - + connect(prefdiag.default_save_asPushButton, &QPushButton::clicked, this, &MainWindow::setDefaultSaveDir); - + connect(prefdiag.lightingPushButton, &QPushButton::clicked, this, &MainWindow::setLighting_triggered); - + prefdiag.surface_meshComboBox->setCurrentText(CGAL::Three::Three::modeName( CGAL::Three::Three::s_defaultSMRM)); connect(prefdiag.surface_meshComboBox, &QComboBox::currentTextChanged, this, [this](const QString& text){ this->s_defaultSMRM = CGAL::Three::Three::modeFromName(text); }); - + prefdiag.point_setComboBox->setCurrentText(CGAL::Three::Three::modeName( CGAL::Three::Three::s_defaultPSRM)); connect(prefdiag.point_setComboBox, &QComboBox::currentTextChanged, @@ -2353,6 +2368,70 @@ void MainWindow::on_actionPreferences_triggered() }); dialog.exec(); }); + connect(prefdiag.sshButton, &QPushButton::clicked, + this, [this](){ + QDialog dialog(this); + Ui::SSHDialog sshdiag; + sshdiag.setupUi(&dialog); + +#ifdef CGAL_USE_SSH + sshdiag.userBox->setEnabled(true); + sshdiag.serverBox->setEnabled(true); + sshdiag.pkBox->setEnabled(true); + sshdiag.privkBox->setEnabled(true); + sshdiag.userEdit->setText(settings.value("ssh_user", QString()).toString()); + sshdiag.serverEdit->setText(settings.value("ssh_server", QString()).toString()); + sshdiag.publicEdit->setText(settings.value("ssh_public_key", QString()).toString()); + sshdiag.privkEdit->setText(settings.value("ssh_priv_key", QString()).toString()); + connect(sshdiag.pubButton, &QPushButton::clicked, + this, [this, sshdiag](){ + QFileDialog diag(this, + "Public Key", + "", + "All Files (*)"); + diag.setFilter(QDir::Hidden|QDir::Files|QDir::Dirs|QDir::NoDotAndDotDot); + if(!diag.exec()) + return; + sshdiag.publicEdit->setText(diag.selectedFiles().front()); + }); + connect(sshdiag.privButton, &QPushButton::clicked, + this, [this, sshdiag](){ + QFileDialog diag(this, + "Private Key", + "", + "All Files (*)"); + diag.setFilter(QDir::Hidden|QDir::Files|QDir::Dirs|QDir::NoDotAndDotDot); + if(!diag.exec()) + return; + sshdiag.privkEdit->setText(diag.selectedFiles().front()); + }); +#else + sshdiag.userBox->setEnabled(false); + sshdiag.serverBox->setEnabled(false); + sshdiag.pkBox->setEnabled(false); + sshdiag.privkBox->setEnabled(false); +#endif + sshdiag.wsEdit->setText(settings.value("ws_server_url", QString()).toString()); + + dialog.exec(); + if ( dialog.result() ) + { +#ifdef CGAL_USE_SSH + settings.setValue("ssh_user", + sshdiag.userEdit->text()); + settings.setValue("ssh_server", + sshdiag.serverEdit->text()); + settings.setValue("ssh_public_key", + sshdiag.publicEdit->text()); + settings.setValue("ssh_priv_key", + sshdiag.privkEdit->text()); +#endif + settings.setValue("ws_server_url", + sshdiag.wsEdit->text()); + setProperty("ws_url", sshdiag.wsEdit->text()); + } + }); + dialog.exec(); if ( dialog.result() ) @@ -2365,7 +2444,7 @@ void MainWindow::on_actionPreferences_triggered() if (item->checkState(0)==Qt::Unchecked) plugin_blacklist.insert(item->text(1)); } - + //write settings settings.setValue("antialiasing", prefdiag.antialiasingCheckBox->isChecked()); @@ -2385,7 +2464,7 @@ void MainWindow::on_actionPreferences_triggered() settings.setValue("points_size", this->default_point_size); settings.setValue("normals_length", this->default_normal_length); settings.setValue("lines_width", this->default_lines_width); - + } else { @@ -2405,7 +2484,7 @@ void MainWindow::setBackgroundColor() v->update(); } } - + } void MainWindow::setLighting_triggered() @@ -2567,7 +2646,7 @@ QString MainWindow::get_item_stats() Q_FOREACH(int id, scene->selectionIndices()) { Scene_item* item = scene->item(id); - QString classname = item->property("classname").toString(); + QString classname = item->property("classname").toString(); if(classname.isEmpty()) classname = item->metaObject()->className(); if(!classnames.contains(classname)) @@ -2794,53 +2873,183 @@ void MainWindow::propagate_action() } } +QString make_fullpath(const QString& filename, bool duplicate = false) +{ + QString fullpath = QString("%1/%2").arg(QDir::tempPath()).arg(filename); + QString tmp_fullpath = fullpath; + if(duplicate) + { + int i=0; + while(QFileInfo(tmp_fullpath).exists()) + { + QString basename = QFileInfo(tmp_fullpath).baseName(); + QString dir = QFileInfo(tmp_fullpath).dir().path(); + QString suffix= QFileInfo(fullpath).completeSuffix(); + tmp_fullpath=QString("%1/%2%3.%4").arg(dir).arg(basename).arg(++i).arg(suffix); + } + } + return tmp_fullpath; +} +/* + The two following functions allow to create files from string and strings from files. + This is used as a workaround of the absence of stream management in our IO system. + The whole to/from Base64 is used to avoid problems with binary formats. Everything is written + as a base64 binary string, and converted back to what it was. +*/ +QByteArray file_to_string(const char* filename) +{ + std::ifstream f(filename, std::ifstream::binary); + // get size of file + f.seekg (0,f.end); + long size = f.tellg(); + f.seekg (0); + std::ostringstream ss; + // allocate memory for file content + char* buffer = new char[size]; + + // read content of infile + f.read(buffer,size); + + // write to outfile + ss.write(buffer,size); + // release dynamically-allocated memory + delete[] buffer; + //ss.write( << f.rdbuf(); // reading data + f.close(); + std::string st = ss.str(); + QByteArray ba(st.c_str(), static_cast(st.size())); + return ba; +} + +QString MainWindow::write_string_to_file(const QString& str, const QString &filename) +{ + QString fullpath = make_fullpath(filename); + std::ofstream f(fullpath.toStdString().c_str(), std::ofstream::binary); + QByteArray compressed_item(str.toStdString().c_str()); + QByteArray item = qUncompress(QByteArray::fromBase64(compressed_item)); + QByteArray bb = item; + f.write(bb.constData(),bb.toStdString().size()); + f.close(); + return fullpath; +} + void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() { - QString filename = - QFileDialog::getSaveFileName(this, - "Save the Scene as a Script File", - last_saved_dir, - "Qt Script files (*.js)"); - std::ofstream os(filename.toUtf8()); + if(scene->numberOfEntries() == 0) + return; + bool do_upload = false; +#ifdef CGAL_USE_SSH + QString user = settings.value("ssh_user", QString()).toString(); + QString pass; + if(!user.isEmpty()) + { + QMessageBox::StandardButton doyou = + QMessageBox::question(this, tr("Upload ?"), tr("Do you wish to upload the scene" + " using the SSH preferences ?")); + bool ok; + do_upload = (doyou == QMessageBox::Yes); + if(do_upload) + { + pass = QInputDialog::getText(this, "SSH Password", + "Enter ssh key password:", + QLineEdit::Password, + tr(""), + &ok); + if(!ok) + return; + pass = pass.trimmed(); + } + } +#endif + + QString filename; + + if(do_upload){ + filename = QString("%1/save_scene.js").arg(QDir::tempPath()); + }else{ + filename = QFileDialog::getSaveFileName(this, + "Save the Scene as a Script File", + last_saved_dir, + "Qt Script files (*.js)"); + } + std::ofstream os(filename.toUtf8(), std::ofstream::binary); if(!os) return; - std::vector names; - std::vector loaders; + CGAL::Three::Three::CursorScopeGuard cs(Qt::WaitCursor); + std::vector > names; + std::vector > loaders; std::vector colors; std::vector rendering_modes; QStringList not_saved; for(int i = 0; i < scene->numberOfEntries(); ++i) { Scene_item* item = scene->item(i); - QString loader = item->property("loader_name").toString(); - QString source = item->property("source filename").toString(); + QString loader;// = item->property("loader_name").toString(); + QString ext; + for(Polyhedron_demo_io_plugin_interface* iop : io_plugins) + { + if(iop->isDefaultLoader(item)) + { + QString sf = iop->saveNameFilters().split(";;").first(); + //OFF Files (*.off) + QRegularExpression re("\\(\\*\\.(.*)\\)"); + QRegularExpressionMatch rem = re.match(sf); + if(!rem.hasMatch()) + continue; + ext = rem.captured(1); + QListto_save; + to_save.append(item); + QString savename(tr("%1.%2").arg(item->name()).arg(ext)); + QString fullpath = make_fullpath(savename, true); + savename = QFileInfo(fullpath).fileName(); + iop->save(QFileInfo(fullpath), to_save); + names.push_back(std::make_pair(savename, item->name())); + loader=iop->name(); + break; + } + } if(loader.isEmpty()) { - not_saved.push_back(item->name()); + QMessageBox::warning(this, "", tr("No plugin found for %1. Not saved.").arg(item->name())); continue; } - names.push_back(source); - loaders.push_back(loader); + loaders.push_back(std::make_pair(loader, ext)); colors.push_back(item->color()); rendering_modes.push_back(item->renderingMode()); } + if(loaders.empty()) + return; //path os << "var camera = \""<dumpCameraCoordinates().toStdString()<<"\";\n"; os << "var items = ["; for(std::size_t i = 0; i< names.size() -1; ++i) { - os << "\'" << names[i].toStdString() << "\', "; + QString fullpath = make_fullpath(names[i].first); + + QByteArray item = file_to_string(fullpath.toStdString().c_str()); + os<<"[\'"; + os<show(); } visibleDockWidgets.clear(); - + } } @@ -2923,7 +3189,7 @@ void MainWindow::setupViewer(Viewer* viewer, SubViewer* subviewer) viewer, SLOT(update())); connect(scene, SIGNAL(updated()), viewer, SLOT(update())); - + QAction* action = subviewer->findChild("actionRecenter"); connect(action, SIGNAL(triggered()), viewer, SLOT(update())); @@ -2985,16 +3251,43 @@ void MainWindow::setupViewer(Viewer* viewer, SubViewer* subviewer) this, SLOT(selectSceneItem(int))); connect(viewer, SIGNAL(selectedPoint(double, double, double)), this, SLOT(showSelectedPoint(double, double, double))); - + connect(viewer, SIGNAL(selectionRay(double, double, double, double, double, double)), scene, SIGNAL(selectionRay(double, double, double, double, double, double))); - + connect(viewer, &Viewer::sendMessage, this, [](QString s){ information(s); }); + +#ifdef CGAL_USE_WEBSOCKETS + action= subviewer->viewer->findChild("actionShareCamera"); + connect(action, &QAction::toggled, + this, [this, viewer](bool b) + { + if(!viewer){ + return; + } + QString session; + if(b){ + bool ok; + session = QInputDialog::getText( + this,"Session", + "Please enter the session name.\n" + "Only the machines that enter the same session name will be connected.\n" + "Several sessions can run simultaneously on a same server. ", + QLineEdit::Normal, QString(), &ok); + if(session.isEmpty() || !ok) + { + viewer->setShareCam(false, session); + return; + } + } + viewer->setShareCam(b, session); + }); +#endif } @@ -3014,7 +3307,7 @@ void MainWindow::on_actionAdd_Viewer_triggered() scene->removeViewer(viewer2); viewerDestroyed(viewer2); }); - + setupViewer(viewer2, subviewer); viewer2->camera()->interpolateToFitScene(); subviewer->show(); @@ -3147,11 +3440,20 @@ SubViewer::SubViewer(QWidget *parent, MainWindow* mw, Viewer* mainviewer) QAction* actionTotalPass = new QAction("Set Transparency Pass &Number...",this); actionTotalPass->setObjectName("actionTotalPass"); viewMenu->addAction(actionTotalPass); +#ifdef CGAL_USE_WEBSOCKETS + QAction* actionShareCamera= new QAction("Join &WS Server",viewer); + actionShareCamera->setObjectName("actionShareCamera"); + actionShareCamera->setCheckable(true); + actionShareCamera->setChecked(false); + viewMenu->addAction(actionShareCamera); +#endif + QAction* actionBackFrontShading = new QAction("Activate Back/Front shading.",this); actionBackFrontShading->setObjectName("actionBackFrontShading"); actionBackFrontShading->setCheckable(true); actionBackFrontShading->setChecked(false); viewMenu->addAction(actionBackFrontShading); + if(mainviewer) setAttribute(Qt::WA_DeleteOnClose); setWindowIcon(QIcon(":/cgal/icons/resources/menu.png")); @@ -3199,7 +3501,7 @@ void SubViewer::color() void SubViewer::closeEvent(QCloseEvent *closeEvent) { - + if(is_main) { QMessageBox::information(mw, "", "This is the main viewer. It cannot be closed."); @@ -3220,9 +3522,9 @@ void SubViewer::changeEvent(QEvent *event) { menu->addAction(action); } - setWindowFlags( + setWindowFlags( Qt::SubWindow - | Qt::CustomizeWindowHint + | Qt::CustomizeWindowHint | Qt::WindowMaximizeButtonHint //| Qt::WindowSystemMenuHint | Qt::WindowTitleHint @@ -3238,9 +3540,9 @@ void SubViewer::changeEvent(QEvent *event) { menu->removeAction(action); } - setWindowFlags( + setWindowFlags( Qt::SubWindow - | Qt::CustomizeWindowHint + | Qt::CustomizeWindowHint | Qt::WindowMaximizeButtonHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint @@ -3262,7 +3564,7 @@ void MainWindow::invalidate_bbox(bool do_recenter) void MainWindow::on_action_Save_triggered() { - if(QMessageBox::question(this, "Save", "Are you sure you want to override these files ?") + if(QMessageBox::question(this, "Save", "Are you sure you want to override these files ?") == QMessageBox::No) return; QList to_save; @@ -3278,3 +3580,187 @@ void MainWindow::on_action_Save_triggered() } } } + +void MainWindow::on_actionLoad_a_Scene_from_a_Script_File_triggered() +{ + bool do_download = false; + QString filename; + +#ifdef CGAL_USE_SSH + QString user = settings.value("ssh_user", QString()).toString(); + QString pass; + if(!user.isEmpty()) + { + QMessageBox::StandardButton doyou = + QMessageBox::question(this, tr("Download ?"), tr("Do you wish to download the scene" + " using the SSH preferences ?")); + bool ok; + do_download= (doyou == QMessageBox::Yes); + if(do_download) + { + pass = QInputDialog::getText(this, "SSH Password", + "Enter ssh key password:", + QLineEdit::Password, + tr(""), + &ok); + if(!ok) + return; + pass = pass.trimmed(); + } + } +#endif + + if(do_download) + { + #ifdef CGAL_USE_SSH + using namespace CGAL::ssh_internal; + QString server = settings.value("ssh_server", QString()).toString(); + QString pk = settings.value("ssh_public_key", QString()).toString(); + QString privK = settings.value("ssh_priv_key", QString()).toString(); + user = user.trimmed(); + server = server.trimmed(); + pk = pk.trimmed(); + privK=privK.trimmed(); + QString path; + path = QInputDialog::getText(this, + "", + tr("Enter the remote path for your file.")); + if(path.isEmpty()) + return; + try{ + ssh_session session; + bool res = establish_ssh_session(session, + user.toStdString().c_str(), + server.toStdString().c_str(), + pk.toStdString().c_str(), + privK.toStdString().c_str(), + pass.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The SSH session could not be started."); + return; + } + filename = QString("%1/load_scene.js").arg(QDir::tempPath()); + path = tr("/tmp/%2").arg(path); + res = pull_file(session,path.toStdString().c_str(), filename.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The file could not be fetched. Check your console for more info."); + close_connection(session); + return; + } + close_connection(session); + } catch( ssh::SshException e ) + { + std::cout << "Error during connection : "; + std::cout << e.getError() << std::endl; + } + #endif + } + else + { + filename = QFileDialog::getOpenFileName( + this, + tr("Select a Whole Scene file..."), + ".", + "Whole Scene files (*.js)"); + if(filename.isEmpty()) + return; + } + loadScript(QFileInfo(filename)); + if(do_download){ + QFile tmp_file(filename); + tmp_file.remove(); + } +} + +#ifdef CGAL_USE_WEBSOCKETS +void MainWindow::on_action_Start_a_Session_triggered() +{ + QAction * action= findChild("action_Start_a_Session"); + static EchoServer *server =nullptr; + if(action->isChecked()){ + server = new EchoServer(1234); + QObject::connect(server, &EchoServer::closed, server,&EchoServer::deleteLater); + } + else + { + server->deleteLater(); + } +} + +EchoServer::EchoServer(quint16 port) : + QObject(CGAL::Three::Three::mainWindow()), + m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Echo Server"), + QWebSocketServer::NonSecureMode, this)) +{ + if (m_pWebSocketServer->listen(QHostAddress::Any, port)) { + connect(m_pWebSocketServer, &QWebSocketServer::newConnection, + this, &EchoServer::onNewConnection); + connect(m_pWebSocketServer, &QWebSocketServer::closed, this, &EchoServer::closed); + } + QHostAddress local_host("0.0.0.0"); + + //to avoid printing 127.0.0.1. Not realy sure it won't ever print the external ipv4 though. + const QHostAddress &localhost = QHostAddress(QHostAddress::LocalHost); + for (const QHostAddress &address: QNetworkInterface::allAddresses()) { + if (address.protocol() == QAbstractSocket::IPv4Protocol && address != localhost) + { + local_host= address; + break; + } + } + QMessageBox mb(QMessageBox::NoIcon, "WS Server", + tr("WebSockets Server started.\nEnter the following address in\nyour Network Preferences to be able to join it :\n" + "ws://%1:%2").arg(local_host.toString()).arg(port), QMessageBox::Ok, CGAL::Three::Three::mainWindow()); + mb.setTextInteractionFlags(Qt::TextSelectableByMouse); + mb.exec(); +} + +EchoServer::~EchoServer() +{ + m_pWebSocketServer->close(); + qDeleteAll(m_clients.begin(), m_clients.end()); +} + +void EchoServer::onNewConnection() +{ + QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection(); + + connect(pSocket, &QWebSocket::textMessageReceived, this, &EchoServer::processTextMessage); + connect(pSocket, &QWebSocket::binaryMessageReceived, this, &EchoServer::processBinaryMessage); + connect(pSocket, &QWebSocket::disconnected, this, &EchoServer::socketDisconnected); + + m_clients << pSocket; +} + +void EchoServer::processTextMessage(QString message) +{ + QWebSocket *pClient = qobject_cast(sender()); + for(auto *client : m_clients) { + if(client != pClient) + client->sendTextMessage(message); + } +} + +void EchoServer::processBinaryMessage(QByteArray message) +{ + QWebSocket *pClient = qobject_cast(sender()); + if (pClient) { + pClient->sendBinaryMessage(message); + } +} + +void EchoServer::socketDisconnected() +{ + QWebSocket *pClient = qobject_cast(sender()); + if (pClient) { + m_clients.removeAll(pClient); + pClient->deleteLater(); + } +} +#endif diff --git a/Polyhedron/demo/Polyhedron/MainWindow.h b/Polyhedron/demo/Polyhedron/MainWindow.h index e4bd6d5b3b1..b7650b52b34 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.h +++ b/Polyhedron/demo/Polyhedron/MainWindow.h @@ -138,6 +138,8 @@ public Q_SLOTS: This slot is for use by scripts.*/ bool open(QString filename, QString loader_name); + QString write_string_to_file(const QString &str, const QString& filename); + /*! Reloads an item. Expects to be called by a QAction with the index of the item to be reloaded as data attached to the action. The index must identify a valid `Scene_item`.*/ @@ -352,6 +354,10 @@ protected Q_SLOTS: void save(QString filename, QList& to_save); //!Calls the function saveSnapShot of the viewer. void on_actionSaveSnapshot_triggered(); +#ifdef CGAL_USE_WEBSOCKETS + //!Starts a new WS server if none is already exist. Else, does nothing. + void on_action_Start_a_Session_triggered(); +#endif //!Opens a Dialog to choose a color and make it the background color. void setBackgroundColor(); //!Opens a Dialog to change the lighting settings @@ -447,6 +453,7 @@ public: #endif public Q_SLOTS: void on_actionSa_ve_Scene_as_Script_triggered(); + void on_actionLoad_a_Scene_from_a_Script_File_triggered(); void toggleFullScreen(); void setDefaultSaveDir(); void invalidate_bbox(bool do_recenter); @@ -494,4 +501,30 @@ protected: private: bool is_main; }; +#ifdef CGAL_USE_WEBSOCKETS +QT_FORWARD_DECLARE_CLASS(QWebSocketServer) +QT_FORWARD_DECLARE_CLASS(QWebSocket) + +class EchoServer : public QObject +{ + Q_OBJECT +public: + explicit EchoServer(quint16 port); + ~EchoServer(); + + +Q_SIGNALS: + void closed(); + +private Q_SLOTS: + void onNewConnection(); + void processTextMessage(QString message); + void processBinaryMessage(QByteArray message); + void socketDisconnected(); + +private: + QWebSocketServer *m_pWebSocketServer; + QList m_clients; +}; +#endif #endif // ifndef MAINWINDOW_H diff --git a/Polyhedron/demo/Polyhedron/MainWindow.ui b/Polyhedron/demo/Polyhedron/MainWindow.ui index a011dedab64..6273a37bd16 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.ui +++ b/Polyhedron/demo/Polyhedron/MainWindow.ui @@ -58,6 +58,7 @@ + @@ -96,6 +97,7 @@ + @@ -463,6 +465,22 @@ &Save + + + Load a Scene &from a Script File... + + + + + true + + + &Start a Session + + + Start a WebSocket Server to Share your Camera with Others on your Network. + + diff --git a/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp index 0cf39f89ccb..d23ff947d9a 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp @@ -860,6 +860,12 @@ public: return ok; } + bool isDefaultLoader(const Scene_item* item) const Q_DECL_OVERRIDE{ + if(qobject_cast(item)) + return true; + return false; + } + using Polyhedron_demo_io_plugin_interface::init; void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface* m) override; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Classification/CMakeLists.txt index c0b3eded9c2..f272d98b4cd 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/CMakeLists.txt @@ -2,73 +2,51 @@ include( polyhedron_demo_macros ) if(EIGEN3_FOUND) - set(classification_linked_libraries) - set(classification_compile_definitions) - - find_package(Boost OPTIONAL_COMPONENTS serialization iostreams) + set(Classification_dependencies_met TRUE) - if( WIN32 ) -# to avoid a warning with old cmake - set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp") - set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp") - find_package( Boost OPTIONAL_COMPONENTS serialization iostreams bzip2 zlib) - if( Boost_ZLIB_FOUND AND Boost_BZIP2_FOUND) - if(TARGET Boost::bzip2 AND TARGET Boost::zlib) - set(classification_linked_libraries ${classification_linked_libraries} - Boost::bzip2 Boost::zlib) - else() - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_ZLIB_LIBRARY} ${Boost_BZIP2_LIBRARY}) - endif() - endif() + find_package( Boost OPTIONAL_COMPONENTS serialization iostreams ) + if (NOT Boost_SERIALIZATION_FOUND) + message(STATUS "NOTICE: Boost Serialization not found. Classification plugin won't be available.") + set(Classification_dependencies_met FALSE) + endif() + + if (NOT Boost_IOSTREAMS_FOUND) + message(STATUS "NOTICE: Boost IOStreams not found. Classification plugin won't be available.") + set(Classification_dependencies_met FALSE) endif() - if (Boost_SERIALIZATION_FOUND AND Boost_IOSTREAMS_FOUND AND (NOT WIN32 OR Boost_ZLIB_FOUND)) + find_package(OpenCV QUIET COMPONENTS core ml) # Need core + machine learning + if (NOT OpenCV_FOUND) + message(STATUS "NOTICE: OpenCV was not found. OpenCV random forest predicate for classification won't be available.") + endif() + + find_package(TensorFlow QUIET) + if (NOT TensorFlow_FOUND) + message(STATUS "NOTICE: TensorFlow not found, Neural Network predicate for classification won't be available.") + endif() + + if (Classification_dependencies_met) qt5_wrap_ui( classificationUI_FILES Classification_widget.ui Classification_advanced_widget.ui ) polyhedron_demo_plugin(classification_plugin Classification_plugin Point_set_item_classification Cluster_classification Surface_mesh_item_classification ${classificationUI_FILES} KEYWORDS Classification) - - if(TARGET Boost::serialization AND TARGET Boost::iostreams) - set(classification_linked_libraries ${classification_linked_libraries} - Boost::serialization Boost::iostreams) - else() - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_SERIALIZATION_LIBRARY} - ${Boost_IOSTREAMS_LIBRARY}) + target_link_libraries(classification_plugin PUBLIC scene_points_with_normal_item + scene_polylines_item scene_polygon_soup_item scene_surface_mesh_item scene_selection_item scene_color_ramp) + + CGAL_target_use_Eigen(classification_plugin) + CGAL_target_use_Boost_IOStreams(classification_plugin) + CGAL_target_use_Boost_Serialization(classification_plugin) + if(OpenCV_FOUND) + CGAL_target_use_OpenCV(classification_plugin) endif() - - find_package(OpenCV QUIET COMPONENTS core ml) # Need core + machine learning - if (OpenCV_FOUND) - message(STATUS "Found OpenCV ${OpenCV_VERSION}") - include_directories(${OpenCV_INCLUDE_DIRS}) - set(classification_linked_libraries ${classification_linked_libraries} - ${OpenCV_LIBS}) - set(classification_compile_definitions ${classification_compile_definitions} - "-DCGAL_LINKED_WITH_OPENCV") - else() - message(STATUS "NOTICE: OpenCV was not found. OpenCV random forest predicate for classification won't be available.") + if(TensorFlow_FOUND) + CGAL_target_use_TensorFlow(classification_plugin) endif() - - find_package(TensorFlow QUIET) - if (TensorFlow_FOUND) - message(STATUS "Found TensorFlow") - set(classification_linked_libraries ${classification_linked_libraries} - ${TensorFlow_LIBRARY}) - set(classification_compile_definitions ${classification_compile_definitions} - "-DCGAL_LINKED_WITH_TENSORFLOW") - include_directories( ${TensorFlow_INCLUDE_DIR} ) - else() - message(STATUS "NOTICE: TensorFlow not found, Neural Network predicate for classification won't be available.") + if(TBB_FOUND) + CGAL_target_use_TBB(classification_plugin) endif() - target_link_libraries(classification_plugin PUBLIC scene_points_with_normal_item - scene_polylines_item scene_polygon_soup_item scene_surface_mesh_item scene_selection_item scene_color_ramp ${classification_linked_libraries}) add_dependencies(classification_plugin point_set_selection_plugin selection_plugin) - target_compile_definitions(classification_plugin PUBLIC ${classification_compile_definitions}) - else() - message(STATUS "NOTICE: Boost Serialization or IO Streams or ZLIB not found. Classification plugin won't be available.") endif() - else(EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Classification plugin will not be available.") endif() diff --git a/Polyhedron/demo/Polyhedron/Plugins/Convex_hull/Convex_hull_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Convex_hull/Convex_hull_plugin.cpp index 3722f916e42..b973eeae32f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Convex_hull/Convex_hull_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Convex_hull/Convex_hull_plugin.cpp @@ -80,28 +80,15 @@ void Polyhedron_demo_convex_hull_plugin::on_actionConvexHull_triggered() // add convex hull as new polyhedron SMesh *pConvex_hull = new SMesh; - typedef boost::property_map::type Vpmap; - typedef CGAL::Property_map_to_unary_function Vpmap_fct; if(selection_item) { SMesh* pMesh = selection_item->polyhedron(); - Vpmap vpm = get(CGAL::vertex_point,*pMesh); - - Vpmap_fct v2p(vpm); CGAL::convex_hull_3( - boost::make_transform_iterator(selection_item->selected_vertices.begin(), v2p), - boost::make_transform_iterator(selection_item->selected_vertices.end(), v2p), - *pConvex_hull); + *pMesh, + *pConvex_hull); } else if ( sm_item ){ SMesh* pMesh = sm_item->polyhedron(); - Vpmap vpm = get(CGAL::vertex_point,*pMesh); - - Vpmap_fct v2p(vpm); - boost::graph_traits::vertex_iterator b,e; - boost::tie(b,e) = vertices(*pMesh); - - CGAL::convex_hull_3(boost::make_transform_iterator(b,v2p), - boost::make_transform_iterator(e,v2p), + CGAL::convex_hull_3(*pMesh, *pConvex_hull); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Display/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Display/CMakeLists.txt index 88145266135..c783cd751ac 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Display/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Display/CMakeLists.txt @@ -3,4 +3,5 @@ if(EIGEN3_FOUND) qt5_wrap_ui( display_propertyUI_FILES Display_property.ui ) polyhedron_demo_plugin(display_property_plugin Display_property_plugin ${display_propertyUI_FILES}) target_link_libraries(display_property_plugin PUBLIC scene_surface_mesh_item scene_points_with_normal_item scene_color_ramp) + CGAL_target_use_Eigen(display_property_plugin) endif(EIGEN3_FOUND) diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp index d2e34e4e00e..90f036e8cea 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp @@ -78,61 +78,6 @@ class Io_3mf_plugin: std::vector names; QList result; std::vector > all_colors; - int nb_polylines = - CGAL::read_polylines_from_3mf(fileinfo.filePath().toUtf8().toStdString(), - all_points, all_colors, names); - if(nb_polylines < 0 ) - { - ok = false; - std::cerr << "Error in reading of meshes."<polylines; - polylines.push_back(all_points[i]); - pol_item->setName(names[i].data()); - pol_item->invalidateOpenGLBuffers(); - CGAL::Color c = all_colors[i].front(); - pol_item->setColor(QColor(c.red(), c.green(), c.blue())); - pol_item->setProperty("already_colord", true); - result << pol_item; - if(add_to_scene) - CGAL::Three::Three::scene()->addItem(pol_item); - } - all_points.clear(); - all_colors.clear(); - names.clear(); - int nb_point_sets = - CGAL::read_point_clouds_from_3mf(fileinfo.filePath().toUtf8().toStdString(), - all_points, all_colors, names); - if(nb_point_sets < 0 ) - { - ok = false; - std::cerr << "Error in reading of meshes."<point_set()->insert(all_points[i][j]); - } - pts_item->setName(names[i].data()); - pts_item->invalidateOpenGLBuffers(); - CGAL::Color c = all_colors[i].front(); - pts_item->setColor(QColor(c.red(), c.green(), c.blue())); - pts_item->setProperty("already_colord", true); - result << pts_item; - if(add_to_scene) - CGAL::Three::Three::scene()->addItem(pts_item); - } - all_points.clear(); - names.clear(); - all_colors.clear(); int nb_meshes = CGAL::read_triangle_soups_from_3mf(fileinfo.filePath().toUtf8().toStdString(), all_points, all_polygons, all_colors, names); diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/IO/CMakeLists.txt index 01a48c330b8..c4487f3b768 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/CMakeLists.txt @@ -71,8 +71,9 @@ else() if (LASLIB_FOUND) polyhedron_demo_plugin(las_plugin LAS_io_plugin KEYWORDS IO PointSetProcessing Classification) - target_link_libraries(las_plugin PUBLIC scene_points_with_normal_item ${LASLIB_LIBRARIES}) + target_link_libraries(las_plugin PUBLIC scene_points_with_normal_item) target_compile_features(las_plugin PRIVATE ${needed_cxx_features}) + CGAL_target_use_LASLIB(las_plugin) else() message(STATUS "NOTICE : the LAS IO plugin needs LAS libraries and will not be compiled.") endif() @@ -85,10 +86,10 @@ find_path(3MF_INCLUDE_DIR ) find_library(3MF_LIBRARIES NAMES 3MF DOC "Path to the lib3MF library") -if(3MF_LIBRARIES AND 3MF_INCLUDE_DIR) +if(3MF_LIBRARIES AND 3MF_INCLUDE_DIR AND EXISTS "${3MF_INCLUDE_DIR}/Model/COM/NMR_DLLInterfaces.h") include_directories(${3MF_INCLUDE_DIR}) polyhedron_demo_plugin(3mf_io_plugin 3mf_io_plugin KEYWORDS IO PMP) target_link_libraries(3mf_io_plugin PRIVATE scene_surface_mesh_item scene_points_with_normal_item scene_polylines_item ${3MF_LIBRARIES}) else() - message(STATUS "NOTICE : The 3mf_io_plugin requires the lib3MF library, and will not be compiled.") + message(STATUS "NOTICE : The 3mf_io_plugin requires the lib3MF library in a version < 2.0, and will not be compiled.") endif() diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp index 4aab33b4e0a..22b2ed695d4 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp @@ -15,13 +15,18 @@ class Polyhedron_demo_io_nef_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0" FILE "nef_io_plugin.json") public: - QString nameFilters() const; - QString name() const { return "io_nef_plugin"; } - bool canLoad(QFileInfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString nameFilters() const override; + QString name() const override { return "io_nef_plugin"; } + bool canLoad(QFileInfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList& items); + bool canSave(const CGAL::Three::Scene_item*) override; + bool save(QFileInfo fileinfo,QList& items) override; + bool isDefaultLoader(const Scene_item* item) const override{ + if(qobject_cast(item)) + return true; + return false; + } }; QString Polyhedron_demo_io_nef_plugin::nameFilters() const { diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp index e62593c9b89..6b195e276c4 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp @@ -29,28 +29,28 @@ class Polyhedron_demo_off_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "off_io_plugin.json") public: - bool isDefaultLoader(const Scene_item *item) const + bool isDefaultLoader(const Scene_item *item) const override { if(qobject_cast(item) || qobject_cast(item)) return true; return false; } - bool isDefaultLoader(const QString& name) const + bool isDefaultLoader(const QString& name) const override { if(name == QString("off")) return true; return false; } - QString name() const { return "off_plugin"; } - QString nameFilters() const { return "OFF files (*.off);;Wavefront OBJ (*.obj)"; } - bool canLoad(QFileInfo fileinfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString name() const override{ return "off_plugin"; } + QString nameFilters() const override { return "OFF files (*.off);;Wavefront OBJ (*.obj)"; } + bool canLoad(QFileInfo fileinfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; CGAL::Three::Scene_item* load_off(QFileInfo fileinfo); CGAL::Three::Scene_item* load_obj(QFileInfo fileinfo); - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList& ); + bool canSave(const CGAL::Three::Scene_item*) override; + bool save(QFileInfo fileinfo,QList& ) override; }; bool Polyhedron_demo_off_plugin::canLoad(QFileInfo) const { @@ -136,7 +136,10 @@ Polyhedron_demo_off_plugin::load_off(QFileInfo fileinfo) { // Try to read .off in a surface_mesh SMesh *surface_mesh = new SMesh(); try{ - in >> *surface_mesh; + if(!(in >> *surface_mesh)) + { + surface_mesh->clear(); + } } catch(...) { surface_mesh->clear(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp index 6ce2fdeb793..75c2e1d9845 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp @@ -23,19 +23,19 @@ class Polyhedron_demo_ply_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "ply_io_plugin.json") public: - bool isDefaultLoader(const CGAL::Three::Scene_item *item) const + bool isDefaultLoader(const CGAL::Three::Scene_item *item) const override { if(qobject_cast(item)) return true; return false; } - QString name() const { return "ply_plugin"; } - QString nameFilters() const { return "PLY files (*.ply)"; } - bool canLoad(QFileInfo fileinfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString name() const override{ return "ply_plugin"; } + QString nameFilters() const override{ return "PLY files (*.ply)"; } + bool canLoad(QFileInfo fileinfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true)override; - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList&); + bool canSave(const CGAL::Three::Scene_item*)override; + bool save(QFileInfo fileinfo,QList&)override; }; diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp index d86309749f8..d9fe0b44e0d 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp @@ -75,6 +75,12 @@ public: return QList()<(item)) + return true; + return false; + } protected Q_SLOTS: //!Splits the selected Scene_polylines_item in multiple items all containing a single polyline. void split(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp index 1c340b8f2ad..362709853c6 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp @@ -290,10 +290,11 @@ public: QString nameFilters() const { - return "VTK PolyData files (*.vtk);; VTK XML PolyData (*.vtp);; VTK XML UnstructuredGrid (*.vtu)"; } + return "VTK XML UnstructuredGrid (*.vtu);;VTK PolyData files (*.vtk);; VTK XML PolyData (*.vtp)"; } QString name() const { return "vtk_plugin"; } bool canSave(const CGAL::Three::Scene_item* item) { + return (qobject_cast(item) || qobject_cast(item)); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp index 71c47452676..55a3a7e1b14 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp @@ -17,24 +17,24 @@ class LCC_io_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "lcc_io_plugin.json") public: - bool isDefaultLoader(const CGAL::Three::Scene_item *item) const + bool isDefaultLoader(const CGAL::Three::Scene_item *item) const override { if(qobject_cast(item)) return true; return false; } - QString name() const { return "lcc_plugin"; } - QString nameFilters() const { return + QString name() const override{ return "lcc_plugin"; } + QString nameFilters() const override{ return "OFF files (*.off);;" "3-map files (*.3map)"; } - QString saveNameFilters() const { + QString saveNameFilters() const override{ return "3-map files (*.3map)"; } - bool canLoad(QFileInfo) const { return true; } - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true){ + bool canLoad(QFileInfo) const override{ return true; } + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override{ // Open file std::ifstream ifs(fileinfo.filePath().toUtf8()); if(!ifs) { @@ -67,8 +67,8 @@ public: } - bool canSave(const CGAL::Three::Scene_item*){return false;} - bool save(QFileInfo, QList& ){ + bool canSave(const CGAL::Three::Scene_item*)override{return false;} + bool save(QFileInfo, QList& )override{ return false; } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp index 4a7c004be2b..21a0d5c6207 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp @@ -18,15 +18,20 @@ class Polyhedron_demo_c3t3_binary_io_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "c3t3_io_plugin.json") public: - QString name() const { return "C3t3_io_plugin"; } - QString nameFilters() const { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma)"; } - QString saveNameFilters() const { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma);;avizo (*.am);;OFF files (*.off)"; } - QString loadNameFilters() const { return "binary files (*.cgal);;ascii (*.mesh)"; } - bool canLoad(QFileInfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString name() const override { return "C3t3_io_plugin"; } + QString nameFilters() const override { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma)"; } + QString saveNameFilters() const override { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma);;avizo (*.am);;OFF files (*.off)"; } + QString loadNameFilters() const override { return "binary files (*.cgal);;ascii (*.mesh)"; } + bool canLoad(QFileInfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList& ); + bool canSave(const CGAL::Three::Scene_item*) override; + bool save(QFileInfo fileinfo,QList& ) override; + bool isDefaultLoader(const Scene_item* item) const override{ + if(qobject_cast(item)) + return true; + return false; + } private: bool try_load_other_binary_format(std::istream& in, C3t3& c3t3); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/CMakeLists.txt index 9db4d61b2e1..7dd9fbd4fce 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/CMakeLists.txt @@ -51,7 +51,14 @@ polyhedron_demo_plugin(mesh_3_optimization_plugin Optimization_plugin ${meshingUI_FILES} KEYWORDS IO Mesh_3) target_link_libraries(mesh_3_optimization_plugin PUBLIC scene_c3t3_item scene_surface_mesh_item scene_image_item scene_implicit_function_item ) - +# Use Eigen + find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater) + + if (EIGEN3_FOUND) + CGAL_target_use_Eigen(mesh_3_optimization_plugin) + else() #eigen + message(STATUS "The Mesh_3_optimization_plugin requires Eigen, which was not found, and will use a deprecated class to replace it. Warnings are to be expected.") + endif()#eigen polyhedron_demo_plugin(c3t3_io_plugin C3t3_io_plugin KEYWORDS IO Mesh_3) target_link_libraries(c3t3_io_plugin PUBLIC scene_c3t3_item) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp index 286642446a0..d9b4fff0ef8 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp @@ -296,6 +296,11 @@ public: items.pop_front(); return ok; } + bool isDefaultLoader(const Scene_item* item) const override{ + if(qobject_cast(item)) + return true; + return false; + } QString name() const override{ return "segmented images"; } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui index a29054048fa..cc9a9b224bd 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui @@ -100,9 +100,23 @@ Sharp features - - - + + + + + 60.00 + + + + + + + + + + true + + @@ -115,15 +129,8 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - Edge &size - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + sharpEdgesAngle @@ -134,6 +141,9 @@ + + + @@ -147,23 +157,6 @@ - - - - - - - true - - - - - - - 60.00 - - - @@ -171,6 +164,19 @@ + + + + Edge &size + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + edgeSizing + + + @@ -201,6 +207,9 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + approx + @@ -224,6 +233,9 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + facetAngle + @@ -315,17 +327,17 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 0.00 + + facetSizing - + + + 0.065 + + @@ -337,6 +349,13 @@ + + + + 0.0017 + + + @@ -390,6 +409,9 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + tetSizing + @@ -532,7 +554,7 @@ DoubleEdit QLineEdit -

CGAL_double_edit.h
+
CGAL_double_edit.h
diff --git a/Polyhedron/demo/Polyhedron/Plugins/PCA/Basic_generator_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PCA/Basic_generator_plugin.cpp index 269eb121ae4..4d92aeb7867 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PCA/Basic_generator_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PCA/Basic_generator_plugin.cpp @@ -766,7 +766,7 @@ struct Point_generator { return Point(bl.x() + i*(ur.x()-bl.x())/(w-1), bl.y() + j*(ur.y()-bl.y())/(h-1), - 0); + bl.z() + j*(ur.z()-bl.z())/(h-1)); } }; template diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt index b97c86f9879..3dc0a808de7 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt @@ -3,24 +3,31 @@ if(EIGEN3_FOUND) polyhedron_demo_plugin(jet_fitting_plugin Jet_fitting_plugin) target_link_libraries(jet_fitting_plugin PUBLIC scene_surface_mesh_item scene_polylines_item) + CGAL_target_use_Eigen(jet_fitting_plugin) else(EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Jet fitting plugin will not be available.") endif(EIGEN3_FOUND) +polyhedron_demo_plugin(extrude_plugin Extrude_plugin KEYWORDS PMP) +target_link_libraries(extrude_plugin PUBLIC scene_surface_mesh_item scene_selection_item) + if(EIGEN3_FOUND) if("${EIGEN3_VERSION}" VERSION_GREATER "3.1.90") qt5_wrap_ui( hole_fillingUI_FILES Hole_filling_widget.ui) polyhedron_demo_plugin(hole_filling_plugin Hole_filling_plugin ${hole_fillingUI_FILES} KEYWORDS PMP) target_link_libraries(hole_filling_plugin PUBLIC scene_surface_mesh_item scene_polylines_item scene_selection_item) + CGAL_target_use_Eigen(hole_filling_plugin) qt5_wrap_ui( fairingUI_FILES Fairing_widget.ui) polyhedron_demo_plugin(fairing_plugin Fairing_plugin ${fairingUI_FILES} KEYWORDS PMP) target_link_libraries(fairing_plugin PUBLIC scene_selection_item) + CGAL_target_use_Eigen(fairing_plugin) polyhedron_demo_plugin(hole_filling_polyline_plugin Hole_filling_polyline_plugin ) target_link_libraries(hole_filling_polyline_plugin PUBLIC scene_surface_mesh_item scene_polylines_item) + CGAL_target_use_Eigen(hole_filling_polyline_plugin) qt5_wrap_ui( Mean_curvature_flow_skeleton_pluginUI_FILES Mean_curvature_flow_skeleton_plugin.ui) polyhedron_demo_plugin(mean_curvature_flow_skeleton_plugin Mean_curvature_flow_skeleton_plugin ${Mean_curvature_flow_skeleton_pluginUI_FILES}) @@ -31,6 +38,19 @@ if(EIGEN3_FOUND) scene_polylines_item scene_mcf_item demo_framework) + CGAL_target_use_Eigen(mean_curvature_flow_skeleton_plugin) + # The smoothing plugin can still do some things, even if Ceres is not found + qt5_wrap_ui( smoothingUI_FILES Smoothing_plugin.ui) + polyhedron_demo_plugin(smoothing_plugin Smoothing_plugin ${smoothingUI_FILES}) + target_link_libraries(smoothing_plugin PUBLIC scene_surface_mesh_item scene_selection_item) + CGAL_target_use_Eigen(smoothing_plugin) + find_package(Ceres QUIET) + if(TARGET ceres) + target_compile_definitions( smoothing_plugin PRIVATE CGAL_PMP_USE_CERES_SOLVER ) + target_link_libraries(smoothing_plugin PUBLIC ceres) + endif() + + CGAL_target_use_Eigen(extrude_plugin) else() message(STATUS "NOTICE: The hole filling and fairing plugins require Eigen 3.2 (or higher) and will not be available.") endif() @@ -111,16 +131,3 @@ qt5_wrap_ui( engravUI_FILES Engrave_dock_widget.ui ) polyhedron_demo_plugin(engrave_text_plugin Engrave_text_plugin ${engravUI_FILES}) target_link_libraries(engrave_text_plugin PUBLIC scene_surface_mesh_item scene_selection_item scene_polylines_item) -polyhedron_demo_plugin(extrude_plugin Extrude_plugin KEYWORDS PMP) -target_link_libraries(extrude_plugin PUBLIC scene_surface_mesh_item scene_selection_item) - -# The smoothing plugin can still do some things, even if Ceres is not found -qt5_wrap_ui( smoothingUI_FILES Smoothing_plugin.ui) -polyhedron_demo_plugin(smoothing_plugin Smoothing_plugin ${smoothingUI_FILES}) -target_link_libraries(smoothing_plugin PUBLIC scene_surface_mesh_item scene_selection_item) - -find_package(Ceres QUIET) -if(TARGET ceres) - target_compile_definitions( smoothing_plugin PRIVATE CGAL_PMP_USE_CERES_SOLVER ) - target_link_libraries(smoothing_plugin PUBLIC ceres) -endif() diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Isotropic_remeshing_plugin.cpp index bfb2bb520a7..2049f788572 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Isotropic_remeshing_plugin.cpp @@ -612,7 +612,6 @@ public Q_SLOTS: } if (fpmap_valid) { - PMP::connected_components(pmesh, fpmap, PMP::parameters::edge_is_constrained_map(eif)); poly_item->setItemIsMulticolor(true); poly_item->show_feature_edges(true); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp index 265507b8a9c..6d2d062e002 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp @@ -223,8 +223,8 @@ void Polyhedron_demo_orient_soup_plugin::apply_shuffle( Item* root_item, item->load(root_item); item->shuffle_orientations(); item->setColor(root_item->color()); - scene->replaceItem(index, item); - delete root_item; + scene->replaceItem(index, item, true); + root_item->deleteLater(); QApplication::restoreOverrideCursor(); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp index b4864357dd3..be80490894e 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp @@ -127,6 +127,12 @@ public: return res; } + bool isDefaultLoader(const Scene_item* item) const override{ + if(qobject_cast(item)) + return true; + return false; + } + bool applicable(QAction* action) const override { if(action == actionSelfIntersection) return qobject_cast(scene->item(scene->mainSelectionIndex())); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt index 12b2e9f9056..1d4bfdeb614 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt @@ -1,20 +1,9 @@ include( polyhedron_demo_macros ) if(EIGEN3_FOUND) - set(polyfit_linked_libraries) - set(polyfit_compile_definitions) - find_package(SCIP QUIET) - if(SCIP_FOUND) - include_directories(BEFORE ${SCIP_INCLUDE_DIRS}) - set(polyfit_linked_libraries ${polyfit_linked_libraries} ${SCIP_LIBRARIES}) - set(polyfit_compile_definitions ${polyfit_compile_definitions} "-DCGAL_USE_SCIP") - endif() - find_package(GLPK QUIET) - if(GLPK_FOUND) - include_directories(BEFORE ${GLPK_INCLUDE_DIR}) - set(polyfit_linked_libraries ${polyfit_linked_libraries} ${GLPK_LIBRARIES}) - set(polyfit_compile_definitions ${polyfit_compile_definitions} "-DCGAL_USE_GLPK") + if(NOT SCIP_FOUND) + find_package(GLPK QUIET) endif() if(NOT SCIP_FOUND AND NOT GLPK_FOUND) @@ -23,26 +12,37 @@ if(EIGEN3_FOUND) qt5_wrap_ui( surface_reconstructionUI_FILES Surface_reconstruction_plugin.ui) polyhedron_demo_plugin(surface_reconstruction_plugin Surface_reconstruction_plugin Surface_reconstruction_poisson_impl Surface_reconstruction_advancing_front_impl Surface_reconstruction_scale_space_impl Surface_reconstruction_polygonal_impl ${surface_reconstructionUI_FILES} KEYWORDS PointSetProcessing) - target_link_libraries(surface_reconstruction_plugin PUBLIC scene_polygon_soup_item scene_surface_mesh_item scene_points_with_normal_item ${polyfit_linked_libraries}) - target_compile_definitions(surface_reconstruction_plugin PRIVATE ${polyfit_compile_definitions}) + target_link_libraries(surface_reconstruction_plugin PUBLIC scene_polygon_soup_item scene_surface_mesh_item scene_points_with_normal_item) + CGAL_target_use_Eigen(surface_reconstruction_plugin) + + if (SCIP_FOUND) + CGAL_target_use_SCIP(surface_reconstruction_plugin) + elseif(GLPK_FOUND) + CGAL_target_use_GLPK(surface_reconstruction_plugin) + endif() qt5_wrap_ui( point_set_normal_estimationUI_FILES Point_set_normal_estimation_plugin.ui) polyhedron_demo_plugin(point_set_normal_estimation_plugin Point_set_normal_estimation_plugin ${point_set_normal_estimationUI_FILES} KEYWORDS PointSetProcessing Classification) target_link_libraries(point_set_normal_estimation_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler) + CGAL_target_use_Eigen(point_set_normal_estimation_plugin) qt5_wrap_ui( features_detection_pluginUI_FILES Features_detection_plugin.ui) polyhedron_demo_plugin(features_detection_plugin Features_detection_plugin ${features_detection_pluginUI_FILES} KEYWORDS PointSetProcessing) target_link_libraries(features_detection_plugin PUBLIC scene_points_with_normal_item) + CGAL_target_use_Eigen(features_detection_plugin) polyhedron_demo_plugin(point_set_smoothing_plugin Point_set_smoothing_plugin KEYWORDS PointSetProcessing) target_link_libraries(point_set_smoothing_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler) + CGAL_target_use_Eigen(point_set_smoothing_plugin) polyhedron_demo_plugin(point_set_average_spacing_plugin Point_set_average_spacing_plugin KEYWORDS PointSetProcessing Classification) target_link_libraries(point_set_average_spacing_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler) + CGAL_target_use_Eigen(point_set_average_spacing_plugin) qt5_wrap_ui(point_set_shape_detectionUI_FILES Point_set_shape_detection_plugin.ui) polyhedron_demo_plugin(point_set_shape_detection_plugin Point_set_shape_detection_plugin ${point_set_shape_detectionUI_FILES} KEYWORDS PointSetProcessing Classification) target_link_libraries(point_set_shape_detection_plugin PUBLIC scene_surface_mesh_item scene_points_with_normal_item scene_polygon_soup_item scene_callback_signaler) + CGAL_target_use_Eigen(point_set_shape_detection_plugin) else(EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Surface reconstruction plugin will not be available.") @@ -50,7 +50,6 @@ else(EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Smoothing plugin will not be available.") message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Average spacing plugin will not be available.") message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Feature detection plugin will not be available.") - endif() qt5_wrap_ui(point_set_bilateral_smoothingUI_FILES Point_set_bilateral_smoothing_plugin.ui) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt index 8ab1462de67..99c7d6e618b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt @@ -12,6 +12,7 @@ if(EIGEN3_FOUND) qt5_wrap_ui(parameterizationUI_FILES Parameterization_widget.ui OTE_dialog.ui) polyhedron_demo_plugin(parameterization_plugin Parameterization_plugin ${parameterizationUI_FILES}) target_link_libraries(parameterization_plugin PUBLIC scene_surface_mesh_item scene_textured_item scene_selection_item) + CGAL_target_use_Eigen(parameterization_plugin) else(EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. The Parameterization plugin will not be available.") endif(EIGEN3_FOUND) @@ -31,7 +32,9 @@ target_link_libraries(mesh_simplification_plugin PUBLIC scene_surface_mesh_item qt5_wrap_ui( remeshingUI_FILES Remeshing_dialog.ui) polyhedron_demo_plugin(offset_meshing_plugin Offset_meshing_plugin ${remeshingUI_FILES}) target_link_libraries(offset_meshing_plugin PUBLIC scene_surface_mesh_item scene_polygon_soup_item) - +if(EIGEN3_FOUND) + CGAL_target_use_Eigen(offset_meshing_plugin) +endif() if(TBB_FOUND) CGAL_target_use_TBB(offset_meshing_plugin) endif() diff --git a/Polyhedron/demo/Polyhedron/Preferences.ui b/Polyhedron/demo/Polyhedron/Preferences.ui index 10a7f773f85..358bf1ffbb8 100644 --- a/Polyhedron/demo/Polyhedron/Preferences.ui +++ b/Polyhedron/demo/Polyhedron/Preferences.ui @@ -7,7 +7,7 @@ 0 0 631 - 526 + 628 @@ -58,9 +58,9 @@ 0 - -96 + 0 275 - 528 + 534 @@ -285,6 +285,16 @@ + + + + true + + + Network Settings + + + diff --git a/Polyhedron/demo/Polyhedron/SSH_dialog.ui b/Polyhedron/demo/Polyhedron/SSH_dialog.ui new file mode 100644 index 00000000000..0f18f927cb8 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/SSH_dialog.ui @@ -0,0 +1,151 @@ + + + SSHDialog + + + + 0 + 0 + 415 + 441 + + + + SSH Settings + + + + + + + + SSH Preferences + + + + + + User + + + + + + + + + + + + Server + + + + + + + + + + + + Public Key + + + + + + + + + Browse... + + + + + + + + + + Private Key + + + + + + + + + Browse... + + + + + + + + + + + + + Camera Synchronization Server + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SSHDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SSHDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Polyhedron/demo/Polyhedron/Scene.cpp b/Polyhedron/demo/Polyhedron/Scene.cpp index 5425285d9ed..4730d595adb 100644 --- a/Polyhedron/demo/Polyhedron/Scene.cpp +++ b/Polyhedron/demo/Polyhedron/Scene.cpp @@ -143,6 +143,7 @@ Scene::replaceItem(Scene::Item_id index, CGAL::Three::Scene_item* item, bool emi if(emit_item_about_to_be_destroyed) { Q_EMIT itemAboutToBeDestroyed(item); + item->aboutToBeDestroyed(); } Q_EMIT updated(); diff --git a/Polyhedron/demo/Polyhedron/Scene_c3t3_item.cpp b/Polyhedron/demo/Polyhedron/Scene_c3t3_item.cpp index 685893acac1..0b98891d35c 100644 --- a/Polyhedron/demo/Polyhedron/Scene_c3t3_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_c3t3_item.cpp @@ -1456,6 +1456,7 @@ void Scene_c3t3_item_priv::computeElements() } positions_poly.clear(); + positions_grid.clear(); normals.clear(); f_colors.clear(); positions_lines.clear(); diff --git a/Polyhedron/demo/Polyhedron/Scene_item_rendering_helper.cpp b/Polyhedron/demo/Polyhedron/Scene_item_rendering_helper.cpp index 5413cd0616f..bffe5e847b5 100644 --- a/Polyhedron/demo/Polyhedron/Scene_item_rendering_helper.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_item_rendering_helper.cpp @@ -78,9 +78,9 @@ void PRIV::compute_diag_bbox() { const Scene_item::Bbox& b_box = item->bbox(); _diag_bbox = CGAL::approximate_sqrt( - (b_box.xmax() - b_box.xmin())*(b_box.xmax() - b_box.xmin()) - + (b_box.ymax() - b_box.ymin())*(b_box.ymax() - b_box.ymin()) - + (b_box.zmax() - b_box.zmin())*(b_box.zmax() - b_box.zmin()) + CGAL::square(b_box.xmax() - b_box.xmin()) + + CGAL::square(b_box.ymax() - b_box.ymin()) + + CGAL::square(b_box.zmax() - b_box.zmin()) ); } diff --git a/Polyhedron/demo/Polyhedron/Scene_spheres_item.cpp b/Polyhedron/demo/Polyhedron/Scene_spheres_item.cpp index dbdb9e4dd9d..c26dfd45bec 100644 --- a/Polyhedron/demo/Polyhedron/Scene_spheres_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_spheres_item.cpp @@ -241,7 +241,7 @@ void Scene_spheres_item::drawEdges(Viewer_interface *viewer) const } void Scene_spheres_item::add_sphere(const Sphere &sphere, std::size_t index, CGAL::Color color) { - if(index > d->spheres.size()-1) + if((int)index > (int)d->spheres.size() - 1) d->spheres.resize(index+1); d->spheres[index].push_back(std::make_pair(sphere, color)); diff --git a/Polyhedron/demo/Polyhedron/Use_ssh.cpp b/Polyhedron/demo/Polyhedron/Use_ssh.cpp new file mode 100644 index 00000000000..a1b342eda69 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Use_ssh.cpp @@ -0,0 +1,286 @@ +// Copyright (c) 2020 GeometryFactory (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) : Maxime Gimeno + +#ifdef CGAL_USE_SSH + +#include + +#include "CGAL/Use_ssh.h" +#include +#include +#include +#include +#include +#include + +#include + +bool test_result(int res) +{ + switch(res){ + + case SSH_AUTH_ERROR: + { + std::cerr<<"Auth failed with error: "< buffer(size); + if (!file.read(buffer.data(), size)) + { + std::cerr<<"error while reading file."< timespan(size); + std::this_thread::sleep_for(timespan); + if (res != SSH_OK) + { + std::cerr<< "Can't write to remote file: %s\n" + << ssh_get_error(session)< buffer; + + ssh_scp scp = ssh_scp_new( + session, SSH_SCP_READ | SSH_SCP_RECURSIVE, from_path); + if (scp == NULL) + { + std::cerr<<"Error allocating scp session: %s\n" + << ssh_get_error(session)< #include #include +#include +#include +#ifdef CGAL_USE_WEBSOCKETS +#include +#endif #include @@ -40,6 +45,7 @@ public: bool inDrawWithNames; bool clipping; bool projection_is_ortho; + bool cam_sharing; GLfloat gl_point_size; QVector4D clipbox[6]; QPainter *painter; @@ -111,6 +117,12 @@ public: { return shader_programs; } +#ifdef CGAL_USE_WEBSOCKETS + QWebSocket m_webSocket; +#endif + bool is_connected; + QString session; + QUrl m_url; }; class LightingDialog : @@ -268,6 +280,7 @@ void Viewer::doBindings() d->spec_power = viewer_settings.value("spec_power", 51.8).toFloat(); d->scene = 0; d->projection_is_ortho = false; + d->cam_sharing = false; d->twosides = false; this->setProperty("draw_two_sides", false); this->setProperty("back_front_shading", false); @@ -278,6 +291,7 @@ void Viewer::doBindings() d->shader_programs.resize(NB_OF_PROGRAMS); d->textRenderer = new TextRenderer(); d->is_2d_selection_mode = false; + d->is_connected = false; connect( d->textRenderer, SIGNAL(sendMessage(QString,int)), this, SLOT(printMessage(QString,int)) ); @@ -623,7 +637,7 @@ void Viewer::mousePressEvent(QMouseEvent* event) d->showDistance(event->pos()); event->accept(); } - else { + else{ makeCurrent(); CGAL::QGLViewer::mousePressEvent(event); } @@ -1931,6 +1945,79 @@ bool Viewer::isClipping() const { return d->clipping; } +#ifdef CGAL_USE_WEBSOCKETS +void Viewer::setShareCam(bool b, QString session) +{ + static bool init = false; + if(b) + { + d->cam_sharing = b; + d->session = session; + QString ws_url + = CGAL::Three::Three::mainWindow()->property("ws_url").toString(); + if(ws_url.isEmpty()) + { + QMessageBox::warning(this, "Error", "No Server configured. Please go to Edit->Preferences->Network Settings and fill the \"Camera Synchronization Server\" Field."); + } + else{ + if(!init) + { + connect(&d->m_webSocket, &QWebSocket::connected, this, &Viewer::onSocketConnected); + connect(&d->m_webSocket, &QWebSocket::disconnected, this,[this]() + { + d->is_connected = false; + Viewer::socketClosed(); + }); + init = true; + } + d->m_webSocket.open(QUrl(ws_url)); + QApplication::setOverrideCursor(Qt::WaitCursor); + QTimer::singleShot(1000, this, [this](){ + QApplication::restoreOverrideCursor(); + if(!d->is_connected){ + QMessageBox::warning(CGAL::Three::Three::mainWindow(), + "Connection failure", + "The requested server was not found."); + setShareCam(false, ""); + } + }); + } + } + else + { + QAction* action = findChild("actionShareCamera"); + action->setChecked(false); + d->m_webSocket.close(); + } +} +void Viewer::onSocketConnected() +{ + connect(&d->m_webSocket, &QWebSocket::textMessageReceived, + this, &Viewer::onTextMessageSocketReceived); + connect(camera()->frame(), &CGAL::qglviewer::ManipulatedCameraFrame::manipulated, + this, [this](){ + if(d->cam_sharing){ + QString cam_state = QString("[%1] %2").arg(d->session).arg(dumpCameraCoordinates()); + //send to server + d->m_webSocket.sendTextMessage(cam_state); + } + }); + d->is_connected = true; +} + +void Viewer::onTextMessageSocketReceived(QString message) +{ + QString session; + QString position; + QRegularExpression re("\\[(.*)\\] (.*)"); + QRegularExpressionMatch match = re.match(message); + session = match.captured(1); + position = match.captured(2); + if(session != d->session){ + return; + } + moveCameraToCoordinates(position, 0.05f); +} +#endif #include "Viewer.moc" - diff --git a/Polyhedron/demo/Polyhedron/Viewer.h b/Polyhedron/demo/Polyhedron/Viewer.h index 600b9a6f041..f4fdf522abe 100644 --- a/Polyhedron/demo/Polyhedron/Viewer.h +++ b/Polyhedron/demo/Polyhedron/Viewer.h @@ -95,6 +95,7 @@ public: Q_SIGNALS: void sendMessage(QString); void doneInitGL(CGAL::Three::Viewer_interface*); + void socketClosed(); public Q_SLOTS: //! Sets the antialiasing to true or false. void setAntiAliasing(bool b) Q_DECL_OVERRIDE; @@ -131,6 +132,11 @@ public Q_SLOTS: void setBackFrontColors(); void messageLogged(QOpenGLDebugMessage); +#ifdef CGAL_USE_WEBSOCKETS + void setShareCam(bool, QString); + void onSocketConnected(); + void onTextMessageSocketReceived(QString message); +#endif protected: void paintEvent(QPaintEvent *)Q_DECL_OVERRIDE; diff --git a/Polyhedron/demo/Polyhedron/include/CGAL/Use_ssh.h b/Polyhedron/demo/Polyhedron/include/CGAL/Use_ssh.h new file mode 100644 index 00000000000..2cdca27452b --- /dev/null +++ b/Polyhedron/demo/Polyhedron/include/CGAL/Use_ssh.h @@ -0,0 +1,25 @@ +#ifndef USE_SSH_H +#define USE_SSH_H +#include +namespace CGAL{ +namespace ssh_internal{ +//should be used inside a try/catch(ssh::SshException e) + +//give an unitialized session. +bool establish_ssh_session(ssh_session& session, + const char *user, + const char *server, + const char *pub_key_path, + const char *priv_key_path, + const char *priv_key_password); +void close_connection(ssh_session& session); + +bool push_file(ssh_session& session, + const char* dest_path, + const char* filepath); +bool pull_file(ssh_session &session, + const char *from_path, + const char *to_path); + +}} +#endif diff --git a/Polyhedron_IO/include/CGAL/IO/OFF_reader.h b/Polyhedron_IO/include/CGAL/IO/OFF_reader.h index c1a79eda546..db5c46781e6 100644 --- a/Polyhedron_IO/include/CGAL/IO/OFF_reader.h +++ b/Polyhedron_IO/include/CGAL/IO/OFF_reader.h @@ -76,19 +76,35 @@ namespace CGAL { polygons.resize(scanner.size_of_facets()); if(scanner.has_colors()) vcolors.resize(scanner.size_of_vertices()); + bool vcolored = false; for (std::size_t i = 0; i < scanner.size_of_vertices(); ++i) { double x, y, z, w; scanner.scan_vertex( x, y, z, w); CGAL_assertion(w!=0); IO::internal::fill_point( x/w, y/w, z/w, points[i] ); - if(scanner.has_colors()) + if(i == 0) { - unsigned char r=0, g=0, b=0; - scanner.scan_color( r, g, b); - vcolors[i] = Color_rgb(r,g,b); + std::string col; + char ci; + std::getline(in, col); + std::istringstream iss(col); + if(iss >> ci){ + std::istringstream iss2(col); + vcolors[i] = scanner.get_color_from_line(iss2); + vcolored = true; + } } else - scanner.skip_to_next_vertex(i); + { + if(vcolored){ + //stores the RGB value + std::string col; + std::getline(in, col); + std::istringstream iss(col); + vcolors[i] = scanner.get_color_from_line(iss); + } + } + if(!in) return false; } diff --git a/Principal_component_analysis/demo/Principal_component_analysis/CMakeLists.txt b/Principal_component_analysis/demo/Principal_component_analysis/CMakeLists.txt index 128b250b8f1..af76de02587 100644 --- a/Principal_component_analysis/demo/Principal_component_analysis/CMakeLists.txt +++ b/Principal_component_analysis/demo/Principal_component_analysis/CMakeLists.txt @@ -19,9 +19,7 @@ include_directories( ./ ) find_package(CGAL COMPONENTS Qt5) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -else() +if (NOT EIGEN3_FOUND) message(STATUS "NOTICE: This project requires the Eigen library, and will not be compiled.") return() endif() @@ -47,6 +45,7 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND ) add_file_dependencies( PCA_demo.cpp "${CMAKE_CURRENT_BINARY_DIR}/MainWindow_moc.cpp" "${CMAKE_CURRENT_BINARY_DIR}/Viewer_moc.cpp" ) add_executable ( PCA_demo PCA_demo.cpp ${UI_FILES} ${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES}) + CGAL_target_use_Eigen(PCA_demo) target_link_libraries( PCA_demo PRIVATE CGAL::CGAL CGAL::CGAL_Qt5 Qt5::Gui) diff --git a/Principal_component_analysis/examples/Principal_component_analysis/CMakeLists.txt b/Principal_component_analysis/examples/Principal_component_analysis/CMakeLists.txt index 0518b6ea3cd..ae1c1e63325 100644 --- a/Principal_component_analysis/examples/Principal_component_analysis/CMakeLists.txt +++ b/Principal_component_analysis/examples/Principal_component_analysis/CMakeLists.txt @@ -12,14 +12,15 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() # 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}" ) + if (EIGEN3_FOUND) + get_filename_component(target ${cppfile} NAME_WE) + CGAL_target_use_Eigen(${target}) + endif() endforeach() else() diff --git a/Principal_component_analysis/include/CGAL/PCA_util.h b/Principal_component_analysis/include/CGAL/PCA_util.h index 0f8c0ab8307..689786cc5df 100644 --- a/Principal_component_analysis/include/CGAL/PCA_util.h +++ b/Principal_component_analysis/include/CGAL/PCA_util.h @@ -648,7 +648,8 @@ assemble_covariance_matrix_3(InputIterator first, t[0].y(), t[1].y(), 0.0, t[0].z(), t[1].z(), 1.0}; Matrix transformation = init_matrix(3,delta); - FT length = std::sqrt(t.squared_length()); + using std::sqrt; + FT length = sqrt(t.squared_length()); // skip zero measure primitives if(length == (FT)0.0) diff --git a/Principal_component_analysis/include/CGAL/PCA_util_Eigen.h b/Principal_component_analysis/include/CGAL/PCA_util_Eigen.h index 81759d878ee..a79526fca11 100644 --- a/Principal_component_analysis/include/CGAL/PCA_util_Eigen.h +++ b/Principal_component_analysis/include/CGAL/PCA_util_Eigen.h @@ -566,7 +566,8 @@ assemble_covariance_matrix_3(InputIterator first, transformation << t[0].x(), t[1].x(), 0.0, t[0].y(), t[1].y(), 0.0, t[0].z(), t[1].z(), 1.0; - FT length = std::sqrt(t.squared_length()); + using std::sqrt; + FT length = sqrt(t.squared_length()); // skip zero measure primitives if(length == (FT)0.0) diff --git a/Principal_component_analysis/include/CGAL/linear_least_squares_fitting_segments_2.h b/Principal_component_analysis/include/CGAL/linear_least_squares_fitting_segments_2.h index bd4b8ebd9c6..8edd3203486 100644 --- a/Principal_component_analysis/include/CGAL/linear_least_squares_fitting_segments_2.h +++ b/Principal_component_analysis/include/CGAL/linear_least_squares_fitting_segments_2.h @@ -82,7 +82,8 @@ linear_least_squares_fitting_2(InputIterator first, FT delta[4] = {t[0].x(), t[1].x(), t[0].y(), t[1].y()}; Matrix transformation = init_matrix(2,delta); - FT length = std::sqrt(t.squared_length()); + using std::sqrt; + FT length = sqrt(t.squared_length()); CGAL_assertion(length != 0.0); // Find the 2nd order moment for the segment wrt to the origin by an affine transformation. diff --git a/Principal_component_analysis/test/Principal_component_analysis/CMakeLists.txt b/Principal_component_analysis/test/Principal_component_analysis/CMakeLists.txt index 93abc4b5e32..994d7529744 100644 --- a/Principal_component_analysis/test/Principal_component_analysis/CMakeLists.txt +++ b/Principal_component_analysis/test/Principal_component_analysis/CMakeLists.txt @@ -12,14 +12,15 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() # 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}" ) + if (EIGEN3_FOUND) + get_filename_component(target ${cppfile} NAME_WE) + CGAL_target_use_Eigen(${target}) + endif() endforeach() else() diff --git a/Principal_component_analysis_LGPL/include/CGAL/centroid.h b/Principal_component_analysis_LGPL/include/CGAL/centroid.h index 0d5061ebd6b..dc3b46266b9 100644 --- a/Principal_component_analysis_LGPL/include/CGAL/centroid.h +++ b/Principal_component_analysis_LGPL/include/CGAL/centroid.h @@ -120,7 +120,9 @@ centroid(InputIterator begin, it++) { const Segment& s = *it; - FT length = std::sqrt(std::abs(s.squared_length())); + using std::abs; + using std::sqrt; + FT length = sqrt(abs(s.squared_length())); Point c = K().construct_midpoint_2_object()(s[0],s[1]); v = v + length * (c - ORIGIN); sum_lengths += length; @@ -440,7 +442,8 @@ centroid(InputIterator begin, it++) { const Segment& s = *it; - FT length = std::sqrt(s.squared_length()); + using std::sqrt; + FT length = sqrt(s.squared_length()); Point c = CGAL::midpoint(s.source(),s.target()); // Point c = K().construct_midpoint_3_object()(s[0],s[1]); //Point c = Point((s[0][0] + s[1][0])/2.0, (s[0][1] + s[1][1])/2.0, (s[0][2] + s[1][2])/2.0); diff --git a/Property_map/include/CGAL/Dynamic_property_map.h b/Property_map/include/CGAL/Dynamic_property_map.h index 35cdcd5f4db..2300b4b5efe 100644 --- a/Property_map/include/CGAL/Dynamic_property_map.h +++ b/Property_map/include/CGAL/Dynamic_property_map.h @@ -13,11 +13,13 @@ #define CGAL_DYNAMIC_PROPERTY_MAP_H #include +#include + #include #include + #include #include - #include #include diff --git a/Ridges_3/examples/Ridges_3/CMakeLists.txt b/Ridges_3/examples/Ridges_3/CMakeLists.txt index c6409270728..09a60dbb011 100644 --- a/Ridges_3/examples/Ridges_3/CMakeLists.txt +++ b/Ridges_3/examples/Ridges_3/CMakeLists.txt @@ -11,7 +11,6 @@ if ( CGAL_FOUND ) # use either Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) # Link with Boost.ProgramOptions (optional) find_package(Boost QUIET COMPONENTS program_options) @@ -29,9 +28,12 @@ if ( CGAL_FOUND ) endif() create_single_source_cgal_program( Compute_Ridges_Umbilics.cpp) + CGAL_target_use_Eigen(Compute_Ridges_Umbilics) create_single_source_cgal_program( Ridges_Umbilics_SM.cpp) + CGAL_target_use_Eigen(Ridges_Umbilics_SM) create_single_source_cgal_program( Ridges_Umbilics_LCC.cpp) - + CGAL_target_use_Eigen(Ridges_Umbilics_LCC) + else() message(STATUS "NOTICE: This program requires Eigen 3.1 (or greater) and will not be compiled.") diff --git a/Ridges_3/test/Ridges_3/CMakeLists.txt b/Ridges_3/test/Ridges_3/CMakeLists.txt index 8ed993f8e6b..122000c9c68 100644 --- a/Ridges_3/test/Ridges_3/CMakeLists.txt +++ b/Ridges_3/test/Ridges_3/CMakeLists.txt @@ -14,9 +14,8 @@ if ( CGAL_FOUND ) # use either Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) create_single_source_cgal_program( "ridge_test.cpp" ) - + CGAL_target_use_Eigen(ridge_test) else() message(STATUS "NOTICE: This program requires Eigen 3.1 (or greater) and will not be compiled.") diff --git a/STL_Extension/include/CGAL/Handle.h b/STL_Extension/include/CGAL/Handle.h index 278232748a5..7e725eb67dc 100644 --- a/STL_Extension/include/CGAL/Handle.h +++ b/STL_Extension/include/CGAL/Handle.h @@ -39,13 +39,15 @@ class Handle typedef std::ptrdiff_t Id_type ; - Handle() + Handle() noexcept : PTR(static_cast(0)) {} - Handle(const Handle& x) + // FIXME: if the precondition throws in a noexcept function, the program terminates + Handle(const Handle& x) noexcept { CGAL_precondition( x.PTR != static_cast(0) ); PTR = x.PTR; + CGAL_assume (PTR->count > 0); PTR->count++; } @@ -56,7 +58,7 @@ class Handle } Handle& - operator=(const Handle& x) + operator=(const Handle& x) noexcept { CGAL_precondition( x.PTR != static_cast(0) ); x.PTR->count++; @@ -66,6 +68,8 @@ class Handle return *this; } + friend void swap(Handle& a, Handle& b) noexcept { std::swap(a.PTR, b.PTR); } + void reset() { if (PTR) @@ -77,11 +81,11 @@ class Handle } int - refs() const { return PTR->count; } + refs() const noexcept { return PTR->count; } - Id_type id() const { return PTR - static_cast(0); } + Id_type id() const noexcept { return PTR - static_cast(0); } - bool identical(const Handle& h) const { return PTR == h.PTR; } + bool identical(const Handle& h) const noexcept { return PTR == h.PTR; } protected: Rep* PTR; @@ -89,7 +93,7 @@ class Handle //inline Handle::Id_type id(const Handle& x) { return x.id() ; } -inline bool identical(const Handle &h1, const Handle &h2) { return h1.identical(h2); } +inline bool identical(const Handle &h1, const Handle &h2) noexcept { return h1.identical(h2); } } //namespace CGAL diff --git a/STL_Extension/include/CGAL/Handle_for.h b/STL_Extension/include/CGAL/Handle_for.h index 8bc097d7c02..b283f469003 100644 --- a/STL_Extension/include/CGAL/Handle_for.h +++ b/STL_Extension/include/CGAL/Handle_for.h @@ -102,7 +102,7 @@ public: ptr_ = p; } - Handle_for(const Handle_for& h) + Handle_for(const Handle_for& h) noexcept : ptr_(h.ptr_) { CGAL_assume (ptr_->count > 0); @@ -110,7 +110,7 @@ public: } Handle_for& - operator=(const Handle_for& h) + operator=(const Handle_for& h) noexcept { Handle_for tmp = h; swap(tmp); @@ -132,7 +132,7 @@ public: // from e.g. using nullptr as a ptr value, but this is drastic. Handle_for& - operator=(Handle_for && h) + operator=(Handle_for && h) noexcept { swap(h); return *this; @@ -164,15 +164,15 @@ public: *this = t; } - Id_type id() const { return Ptr() - static_cast(0); } + Id_type id() const noexcept { return Ptr() - static_cast(0); } - bool identical(const Handle_for& h) const { return Ptr() == h.Ptr(); } + bool identical(const Handle_for& h) const noexcept { return Ptr() == h.Ptr(); } // Ptr() is the "public" access to the pointer to the object. // The non-const version asserts that the instance is not shared. const element_type * - Ptr() const + Ptr() const noexcept { return &(ptr_->t); } @@ -188,25 +188,25 @@ public: */ bool - is_shared() const + is_shared() const noexcept { return ptr_->count > 1; } bool - unique() const + unique() const noexcept { return !is_shared(); } long - use_count() const + use_count() const noexcept { return ptr_->count; } void - swap(Handle_for& h) + swap(Handle_for& h) noexcept { std::swap(ptr_, h.ptr_); } @@ -222,11 +222,11 @@ protected: // ptr() is the protected access to the pointer. Both const and non-const. // Redundant with Ptr(). element_type * - ptr() + ptr() noexcept { return &(ptr_->t); } const element_type * - ptr() const + ptr() const noexcept { return &(ptr_->t); } }; diff --git a/Scale_space_reconstruction_3/examples/Scale_space_reconstruction_3/CMakeLists.txt b/Scale_space_reconstruction_3/examples/Scale_space_reconstruction_3/CMakeLists.txt index bab0af3c5b1..7dd3f858f13 100644 --- a/Scale_space_reconstruction_3/examples/Scale_space_reconstruction_3/CMakeLists.txt +++ b/Scale_space_reconstruction_3/examples/Scale_space_reconstruction_3/CMakeLists.txt @@ -20,11 +20,14 @@ if ( CGAL_FOUND ) find_package( Eigen3 3.1.0 ) if( EIGEN3_FOUND ) - include( ${EIGEN3_USE_FILE} ) create_single_source_cgal_program( "scale_space.cpp" ) + CGAL_target_use_Eigen(scale_space) create_single_source_cgal_program( "scale_space_incremental.cpp" ) + CGAL_target_use_Eigen(scale_space_incremental) create_single_source_cgal_program( "scale_space_manifold.cpp" ) + CGAL_target_use_Eigen(scale_space_manifold) create_single_source_cgal_program( "scale_space_advancing_front.cpp" ) + CGAL_target_use_Eigen(scale_space_advancing_front) if(ACTIVATE_CONCURRENCY AND TBB_FOUND) CGAL_target_use_TBB(scale_space) CGAL_target_use_TBB(scale_space_incremental) diff --git a/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Segment_Delaunay_graph_2.txt b/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Segment_Delaunay_graph_2.txt index 93176e528b4..f10e3b43395 100644 --- a/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Segment_Delaunay_graph_2.txt +++ b/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/Segment_Delaunay_graph_2.txt @@ -404,30 +404,17 @@ classes: As mentioned above, performing computations with exact arithmetic can be very costly. For this reason we have devoted considerable -effort in implementing different kinds of arithmetic filtering -mechanisms. Presently, there two ways of performing arithmetic -filtering for the predicates involved in the computation of -segment Delaunay graphs: -
    -
  1. The user can use a kernel with a filtered number type -as the first template parameter in the `Segment_Delaunay_graph_traits_2`. -
  2. The user can define up to three different kernels `CK`, +effort in implementing arithmetic filtering mechanisms +through special traits classes, `Segment_Delaunay_graph_filtered_traits_2` +and `Segment_Delaunay_graph_filtered_traits_without_intersections_2`. +These two traits class employ the `Filtered_predicate` mechanism, +and the user can define up to three different kernels `CK`, `FK` and `EK` (default values are provided for most -parameters). The first kernel `CK` is used only for +parameters): the first kernel `CK` is used only for constructions. The second kernel `FK` is the filtering kernel: the traits class will attempt to compute the predicates using this kernel. If the filtering kernel fails to successfully compute a -predicate, the exact kernel `EK` will be used. These three -kernels are then used in the -`Segment_Delaunay_graph_filtered_traits_2` and -`Segment_Delaunay_graph_filtered_traits_without_intersections_2` -classes, which have been implemented using the -`Filtered_predicate` mechanism. -
-Our experience so far has shown that for all reasonable and valid -values of the template parameters, the second method for arithmetic -filtering is more efficient among the two. -This approach is also used in the examples. +predicate, the exact kernel `EK` will be used. Let's consider once more the class `Segment_Delaunay_graph_traits_2`. @@ -506,7 +493,7 @@ for inputs consisting of more than about 1,000 sites. \subsection Segment_Delaunay_graph_2FirstExample First Example using the Filtered Traits The following example shows how to use the segment Delaunay graph traits -in conjunction with the `Filtered_exact` mechanism. In +in conjunction with filtered traits mechanisms. In addition it shows how to use a few of the iterators provided by the `Segment_Delaunay_graph_2` class in order to count a few site-related quantities. diff --git a/Shape_detection/benchmark/Shape_detection/CMakeLists.txt b/Shape_detection/benchmark/Shape_detection/CMakeLists.txt index f2c7bf19d77..4bcb6bc9978 100644 --- a/Shape_detection/benchmark/Shape_detection/CMakeLists.txt +++ b/Shape_detection/benchmark/Shape_detection/CMakeLists.txt @@ -15,12 +15,12 @@ if(CGAL_FOUND) # Use Eigen. find_package(Eigen3 3.1.0 QUIET) # (3.1.0 or greater) if(EIGEN3_FOUND) - include(${EIGEN3_USE_FILE}) - create_single_source_cgal_program( "benchmark_region_growing_on_point_set_2.cpp") + CGAL_target_use_Eigen(benchmark_region_growing_on_point_set_2) create_single_source_cgal_program( "benchmark_region_growing_on_point_set_3.cpp") + CGAL_target_use_Eigen(benchmark_region_growing_on_point_set_3) endif() else() diff --git a/Shape_detection/benchmark/Shape_detection/README.md b/Shape_detection/benchmark/Shape_detection/README.md index da9a3b99a68..b7eab3675f9 100644 --- a/Shape_detection/benchmark/Shape_detection/README.md +++ b/Shape_detection/benchmark/Shape_detection/README.md @@ -1,11 +1,5 @@ README: -Data: -To keep the size of this package small, all benchmark data are placed here: -https://github.com/... /data - -You can download them and use to get the results below. - Results (Point Set 2): ``` diff --git a/Shape_detection/benchmark/Shape_detection/benchmark_region_growing_on_point_set_2.cpp b/Shape_detection/benchmark/Shape_detection/benchmark_region_growing_on_point_set_2.cpp index a1fe25bf58a..f45f4745dbb 100644 --- a/Shape_detection/benchmark/Shape_detection/benchmark_region_growing_on_point_set_2.cpp +++ b/Shape_detection/benchmark/Shape_detection/benchmark_region_growing_on_point_set_2.cpp @@ -92,6 +92,15 @@ int main(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/point_set_2.xyz"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file point_set_2.xyz!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + return EXIT_FAILURE; + } + Input_range input_range; FT a, b, c, d, e, f; diff --git a/Shape_detection/benchmark/Shape_detection/benchmark_region_growing_on_point_set_3.cpp b/Shape_detection/benchmark/Shape_detection/benchmark_region_growing_on_point_set_3.cpp index 0137b1f05fc..cb17dd6d858 100644 --- a/Shape_detection/benchmark/Shape_detection/benchmark_region_growing_on_point_set_3.cpp +++ b/Shape_detection/benchmark/Shape_detection/benchmark_region_growing_on_point_set_3.cpp @@ -128,6 +128,15 @@ int main(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/point_set_3.xyz"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file point_set_3.xyz!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + return EXIT_FAILURE; + } + Input_range input; Point_3 p; Vector_3 n; diff --git a/Shape_detection/doc/Shape_detection/Shape_detection.txt b/Shape_detection/doc/Shape_detection/Shape_detection.txt index 835e08ae30b..26ad047e26d 100644 --- a/Shape_detection/doc/Shape_detection/Shape_detection.txt +++ b/Shape_detection/doc/Shape_detection/Shape_detection.txt @@ -306,9 +306,9 @@ The `RegionType` class defines the three necessary functions: - `RegionType::update()` - updates the internal flag from the default `false` to `true`. We also define a `SeedMap`, such that the second object is handled first, while the first object follows. -Moreover, the last object is always skipped. Notice that in this example, the container with objects is `std::list`, -which is not a random access. In general, it is much slower, but illustrates that the -generic region growing algorithm can be applied to any type of a container. +Moreover, the last object is always skipped. Notice that in this example, the container with objects is `std::vector`, +which is random access. However, the generic region growing algorithm can be applied +to any other type of container, e.g. `std::list`. The result of using these classes with the region growing main class is that the first two objects form the first region, the third object forms the second region, and the last object is skipped. diff --git a/Shape_detection/examples/Shape_detection/CMakeLists.txt b/Shape_detection/examples/Shape_detection/CMakeLists.txt index d1c49d4986e..f8869233fbd 100644 --- a/Shape_detection/examples/Shape_detection/CMakeLists.txt +++ b/Shape_detection/examples/Shape_detection/CMakeLists.txt @@ -15,8 +15,6 @@ if(CGAL_FOUND) # Use Eigen. find_package(Eigen3 3.1.0 QUIET) # (3.1.0 or greater) if(EIGEN3_FOUND) - include(${EIGEN3_USE_FILE}) - create_single_source_cgal_program( "efficient_RANSAC_basic.cpp") create_single_source_cgal_program( @@ -35,6 +33,19 @@ if(CGAL_FOUND) create_single_source_cgal_program( "shape_detection_basic_deprecated.cpp") + + foreach(target + efficient_RANSAC_basic + efficient_RANSAC_with_callback + efficient_RANSAC_and_plane_regularization + region_growing_on_point_set_2 + region_growing_on_point_set_3 + region_growing_on_polygon_mesh + region_growing_with_custom_classes + shape_detection_basic_deprecated) + CGAL_target_use_Eigen(${target}) + endforeach() + endif() create_single_source_cgal_program( diff --git a/Shape_detection/examples/Shape_detection/efficient_RANSAC_with_parameters.cpp b/Shape_detection/examples/Shape_detection/efficient_RANSAC_with_parameters.cpp index b2425c2c514..e4d21ac5856 100644 --- a/Shape_detection/examples/Shape_detection/efficient_RANSAC_with_parameters.cpp +++ b/Shape_detection/examples/Shape_detection/efficient_RANSAC_with_parameters.cpp @@ -65,7 +65,7 @@ int main(int argc, char** argv) { // Set probability to miss the largest primitive at each iteration. parameters.probability = 0.05; - // Detect shapes with at least 500 points. + // Detect shapes with at least 200 points. parameters.min_points = 200; // Set maximum Euclidean distance between a point and a shape. diff --git a/Shape_detection/examples/Shape_detection/region_growing_on_point_set_2.cpp b/Shape_detection/examples/Shape_detection/region_growing_on_point_set_2.cpp index b8b350fcf33..ffd34a43e62 100644 --- a/Shape_detection/examples/Shape_detection/region_growing_on_point_set_2.cpp +++ b/Shape_detection/examples/Shape_detection/region_growing_on_point_set_2.cpp @@ -80,6 +80,15 @@ int main(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/point_set_2.xyz"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file point_set_2.xyz!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + return EXIT_FAILURE; + } + Input_range input_range; FT a, b, c, d, e, f; diff --git a/Shape_detection/examples/Shape_detection/region_growing_on_point_set_3.cpp b/Shape_detection/examples/Shape_detection/region_growing_on_point_set_3.cpp index 5a8561d37bb..abb522a20af 100644 --- a/Shape_detection/examples/Shape_detection/region_growing_on_point_set_3.cpp +++ b/Shape_detection/examples/Shape_detection/region_growing_on_point_set_3.cpp @@ -111,6 +111,15 @@ int main(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/point_set_3.xyz"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file point_set_3.xyz!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + return EXIT_FAILURE; + } + const bool with_normal_map = true; Input_range input_range(with_normal_map); diff --git a/Shape_detection/examples/Shape_detection/region_growing_on_polygon_mesh.cpp b/Shape_detection/examples/Shape_detection/region_growing_on_polygon_mesh.cpp index e49cee21325..98d2f794cc2 100644 --- a/Shape_detection/examples/Shape_detection/region_growing_on_polygon_mesh.cpp +++ b/Shape_detection/examples/Shape_detection/region_growing_on_polygon_mesh.cpp @@ -67,6 +67,15 @@ int main(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/polygon_mesh.off"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file polygon_mesh.off!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + return EXIT_FAILURE; + } + Polygon_mesh polygon_mesh; in >> polygon_mesh; diff --git a/Shape_detection/include/CGAL/Shape_detection/Efficient_RANSAC/Efficient_RANSAC.h b/Shape_detection/include/CGAL/Shape_detection/Efficient_RANSAC/Efficient_RANSAC.h index 3708c3cfaab..cbc376969ae 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Efficient_RANSAC/Efficient_RANSAC.h +++ b/Shape_detection/include/CGAL/Shape_detection/Efficient_RANSAC/Efficient_RANSAC.h @@ -161,11 +161,49 @@ namespace CGAL { , cluster_epsilon(-1) {} - FT probability; ///< Probability to control search endurance. %Default value: 5%. - std::size_t min_points; ///< Minimum number of points of a shape. %Default value: 1% of total number of input points. - FT epsilon; ///< Maximum tolerance Euclidean distance from a point and a shape. %Default value: 1% of bounding box diagonal. - FT normal_threshold; ///< Maximum tolerance normal deviation from a point's normal to the normal on a shape at the projected point. %Default value: 0.9 (around 25 degrees). - FT cluster_epsilon; ///< Maximum distance between points to be considered connected. %Default value: 1% of bounding box diagonal. + /*! + Probability to control search endurance. + %Default value is 0.05. + + A lower probability provides a higher reliability and determinism at the cost + of longer running time due to a higher search endurance. + + It must belong to the interval [0, 1]. + */ + FT probability; + + /*! + Minimum number of points in a shape. + %Default value is 1% of total number of input points. + + It must belong to the interval [0, +inf). + */ + std::size_t min_points; + + /*! + Maximum acceptable Euclidean distance between a point and a shape. + %Default value is 1% of the bounding box diagonal. + + It must belong to the interval [0, +inf). + */ + FT epsilon; + + /*! + Maximum threshold on the dot product between the estimated + shape's normal and the point's normal, that is the cosine of the angle (cos(25°) = 0.9). + %Default value is 0.9 (around 25 degrees). + + It must belong to the interval [0, 1]. + */ + FT normal_threshold; + + /*! + Maximum acceptable Euclidean distance between points, which are assumed to be neighbors. + %Default value is 1% of the bounding box diagonal. + + It must belong to the interval [0, +inf). + */ + FT cluster_epsilon; }; /// @} diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_point_set/Least_squares_line_fit_region.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_point_set/Least_squares_line_fit_region.h index 00e1ea9e80d..b71b71800bc 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_point_set/Least_squares_line_fit_region.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_point_set/Least_squares_line_fit_region.h @@ -40,9 +40,10 @@ namespace Point_set { \brief Region type based on the quality of the least squares line fit applied to 2D points. - This class fits a line to chunks of points in a 2D point set and controls - the quality of this fit. If all quality conditions are satisfied, the chunk - is accepted as a valid region, otherwise rejected. + This class fits a line, using \ref PkgPrincipalComponentAnalysisDRef "PCA", + to chunks of points in a 2D point set and controls the quality of this fit. + If all quality conditions are satisfied, the chunk is accepted as a valid region, + otherwise rejected. \tparam GeomTraits must be a model of `Kernel`. diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_point_set/Least_squares_plane_fit_region.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_point_set/Least_squares_plane_fit_region.h index dbd98cb1b3c..842c4420277 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_point_set/Least_squares_plane_fit_region.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_point_set/Least_squares_plane_fit_region.h @@ -40,9 +40,10 @@ namespace Point_set { \brief Region type based on the quality of the least squares plane fit applied to 3D points. - This class fits a plane to chunks of points in a 3D point set and controls - the quality of this fit. If all quality conditions are satisfied, the chunk - is accepted as a valid region, otherwise rejected. + This class fits a plane, using \ref PkgPrincipalComponentAnalysisDRef "PCA", + to chunks of points in a 3D point set and controls the quality of this fit. + If all quality conditions are satisfied, the chunk is accepted as a valid region, + otherwise rejected. \tparam GeomTraits must be a model of `Kernel`. diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_polygon_mesh/Least_squares_plane_fit_region.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_polygon_mesh/Least_squares_plane_fit_region.h index 7b552249f44..499e23c956c 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_polygon_mesh/Least_squares_plane_fit_region.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Region_growing_on_polygon_mesh/Least_squares_plane_fit_region.h @@ -49,9 +49,10 @@ namespace Polygon_mesh { \brief Region type based on the quality of the least squares plane fit applied to faces of a polygon mesh. - This class fits a plane to chunks of faces in a polygon mesh and controls - the quality of this fit. If all quality conditions are satisfied, the chunk - is accepted as a valid region, otherwise rejected. + This class fits a plane, using \ref PkgPrincipalComponentAnalysisDRef "PCA", + to chunks of faces in a polygon mesh and controls the quality of this fit. + If all quality conditions are satisfied, the chunk is accepted as a valid region, + otherwise rejected. \tparam GeomTraits must be a model of `Kernel`. @@ -97,6 +98,7 @@ namespace Polygon_mesh { using Squared_length_3 = typename Traits::Compute_squared_length_3; using Squared_distance_3 = typename Traits::Compute_squared_distance_3; using Scalar_product_3 = typename Traits::Compute_scalar_product_3; + using Cross_product_3 = typename Traits::Construct_cross_product_vector_3; using Get_sqrt = internal::Get_sqrt; using Sqrt = typename Get_sqrt::Sqrt; @@ -160,6 +162,7 @@ namespace Polygon_mesh { m_squared_length_3(traits.compute_squared_length_3_object()), m_squared_distance_3(traits.compute_squared_distance_3_object()), m_scalar_product_3(traits.compute_scalar_product_3_object()), + m_cross_product_3(traits.construct_cross_product_vector_3_object()), m_sqrt(Get_sqrt::sqrt_object(traits)), m_to_local_converter() { @@ -207,9 +210,13 @@ namespace Polygon_mesh { const FT distance_to_fitted_plane = get_max_face_distance(face); + if (distance_to_fitted_plane < FT(0)) + return false; + // The sign of this scalar product is important, as it indicates + // into which side of the plane the face's normal points. const FT cos_value = - CGAL::abs(m_scalar_product_3(face_normal, m_normal_of_best_fit)); + m_scalar_product_3(face_normal, m_normal_of_best_fit); return (( distance_to_fitted_plane <= m_distance_threshold ) && ( cos_value >= m_normal_threshold )); @@ -284,6 +291,13 @@ namespace Polygon_mesh { // The best fit plane will be a plane fitted to all vertices of all // region faces with its normal being perpendicular to the plane. + // Given that the points, and no normals, are used in estimating + // the plane, the estimated normal will point into an arbitray + // one of the two possible directions. + // We flip it into the correct direction (the one that the majority + // of faces agree with) below. + // This fix is proposed by nh2: + // https://github.com/CGAL/cgal/pull/4563 CGAL::linear_least_squares_fitting_3( points.begin(), points.end(), fitted_plane, fitted_centroid, @@ -291,18 +305,49 @@ namespace Polygon_mesh { Local_traits(), CGAL::Eigen_diagonalize_traits()); - m_plane_of_best_fit = + const Plane_3 unoriented_plane_of_best_fit = Plane_3( static_cast(fitted_plane.a()), static_cast(fitted_plane.b()), static_cast(fitted_plane.c()), static_cast(fitted_plane.d())); - const Vector_3 normal = m_plane_of_best_fit.orthogonal_vector(); - const FT normal_length = m_sqrt(m_squared_length_3(normal)); + Vector_3 unoriented_plane_normal = + unoriented_plane_of_best_fit.orthogonal_vector(); - CGAL_precondition(normal_length > FT(0)); - m_normal_of_best_fit = normal / normal_length; + const FT squared_length = m_squared_length_3(unoriented_plane_normal); + if (squared_length != FT(0)) { + const FT normal_length = m_sqrt(squared_length); + CGAL_precondition(normal_length > FT(0)); + unoriented_plane_normal /= normal_length; + } + + // Compute actual direction of plane's normal sign + // based on faces belonging to that region. + // Approach: + // Each face gets one vote to keep or flip the current plane normal. + Vector_3 face_normal; + long votes_to_keep_normal = 0; + + for (const std::size_t face_index : region) { + const auto face = *(m_face_range.begin() + face_index); + + get_face_normal(face, face_normal); + const bool agrees = + m_scalar_product_3(face_normal, unoriented_plane_normal) > FT(0); + votes_to_keep_normal += (agrees ? 1 : -1); + } + const bool flip_normal = (votes_to_keep_normal < 0); + + m_plane_of_best_fit = + flip_normal + ? unoriented_plane_of_best_fit.opposite() + : unoriented_plane_of_best_fit; + + m_normal_of_best_fit = + flip_normal + ? (-1 * unoriented_plane_normal) + : unoriented_plane_normal; } } @@ -359,17 +404,30 @@ namespace Polygon_mesh { const Point_3& point2 = get(m_vertex_to_point_map, *vertex); ++vertex; const Point_3& point3 = get(m_vertex_to_point_map, *vertex); - const Vector_3 tmp_normal = CGAL::normal(point1, point2, point3); - const FT tmp_normal_length = m_sqrt(m_squared_length_3(tmp_normal)); + const Vector_3 u = point2 - point1; + const Vector_3 v = point3 - point1; + face_normal = m_cross_product_3(u, v); + const FT squared_length = m_squared_length_3(face_normal); + if (squared_length == FT(0)) + return; - CGAL_precondition(tmp_normal_length > FT(0)); - face_normal = tmp_normal / tmp_normal_length; + const FT normal_length = m_sqrt(squared_length); + CGAL_precondition(normal_length > FT(0)); + face_normal /= normal_length; } // The maximum distance from the vertices of the face to the best fit plane. template FT get_max_face_distance(const Face& face) const { + const FT a = CGAL::abs(m_plane_of_best_fit.a()); + const FT b = CGAL::abs(m_plane_of_best_fit.b()); + const FT c = CGAL::abs(m_plane_of_best_fit.c()); + const FT d = CGAL::abs(m_plane_of_best_fit.d()); + + if (a == FT(0) && b == FT(0) && c == FT(0) && d == FT(0)) + return -FT(1); + const auto hedge = halfedge(face, m_face_graph); const auto vertices = vertices_around_face(hedge, m_face_graph); @@ -403,6 +461,7 @@ namespace Polygon_mesh { const Squared_length_3 m_squared_length_3; const Squared_distance_3 m_squared_distance_3; const Scalar_product_3 m_scalar_product_3; + const Cross_product_3 m_cross_product_3; const Sqrt m_sqrt; const To_local_converter m_to_local_converter; diff --git a/Shape_detection/package_info/Shape_detection/maintainer b/Shape_detection/package_info/Shape_detection/maintainer index 08648392ab4..15b87b3289e 100644 --- a/Shape_detection/package_info/Shape_detection/maintainer +++ b/Shape_detection/package_info/Shape_detection/maintainer @@ -2,4 +2,4 @@ Clément Jamin Sven Oesau Simon Giraudot Thien Hoang -Dmitry Anisimov +Dmitry Anisimov diff --git a/Shape_detection/test/Shape_detection/CMakeLists.txt b/Shape_detection/test/Shape_detection/CMakeLists.txt index 67551a95348..d8f7c9c9ba0 100644 --- a/Shape_detection/test/Shape_detection/CMakeLists.txt +++ b/Shape_detection/test/Shape_detection/CMakeLists.txt @@ -15,8 +15,6 @@ if(CGAL_FOUND) # Use Eigen. find_package(Eigen3 3.1.0 QUIET) # (3.1.0 or greater) if(EIGEN3_FOUND) - include(${EIGEN3_USE_FILE}) - create_single_source_cgal_program( "test_region_growing_basic.cpp") create_single_source_cgal_program( @@ -33,6 +31,21 @@ if(CGAL_FOUND) "test_region_growing_on_point_set_3_with_sorting.cpp") create_single_source_cgal_program( "test_region_growing_on_polygon_mesh_with_sorting.cpp") + create_single_source_cgal_program( + "test_region_growing_on_degenerated_mesh.cpp") + foreach(target + test_region_growing_basic + test_region_growing_on_cube + test_region_growing_on_point_set_2 + test_region_growing_on_point_set_3 + test_region_growing_on_polygon_mesh + test_region_growing_on_point_set_2_with_sorting + test_region_growing_on_point_set_3_with_sorting + test_region_growing_on_polygon_mesh_with_sorting + test_region_growing_on_degenerated_mesh) + CGAL_target_use_Eigen(${target}) + endforeach() + endif() create_single_source_cgal_program( diff --git a/Shape_detection/test/Shape_detection/data/degenerated.off b/Shape_detection/test/Shape_detection/data/degenerated.off new file mode 100644 index 00000000000..aa7c69eb5e1 --- /dev/null +++ b/Shape_detection/test/Shape_detection/data/degenerated.off @@ -0,0 +1,20547 @@ +OFF +7068 13477 0 +139.527 -202.12 -97.6354 +139.515 -202.12 -97.6504 +139.494 -202.12 -97.6759 +139.186 -202.12 -98.4641 +139.496 -202.12 -98.7756 +139.266 -202.12 -100.644 +139.429 -202.12 -100.736 +139.527 -202.12 -100.784 +139.499 -202.12 -100.77 +139.527 -202.12 -98.7932 +136.979 -202.12 -92.7478 +136.719 -202.12 -92.7852 +136.641 -202.12 -92.7799 +137.342 -202.12 -92.4978 +137.323 -202.12 -92.6762 +138.959 -202.12 -97.7563 +139.042 -202.12 -97.7535 +139.175 -202.12 -97.7734 +139.124 -202.12 -97.77 +138.711 -202.12 -97.765 +138.816 -202.12 -97.7595 +139.074 -202.12 -97.7631 +139.467 -202.12 -97.6922 +139.377 -202.12 -97.7183 +138.56 -202.12 -99.9435 +138.557 -202.12 -99.9406 +138.561 -202.12 -99.9448 +136.934 -202.12 -99.6961 +137.03 -202.12 -99.7083 +135.249 -202.12 -99.5766 +135.451 -202.12 -99.5785 +137.179 -202.12 -99.7199 +137.131 -202.12 -99.7214 +135.569 -202.12 -99.5757 +135.912 -202.12 -99.6287 +136.036 -202.12 -99.6395 +137.226 -202.12 -99.7085 +136.754 -202.12 -99.6868 +136.298 -202.12 -99.6533 +136.654 -202.12 -92.7327 +137.276 -202.12 -92.4854 +136.719 -202.12 -92.711 +136.745 -202.12 -92.7029 +137.078 -202.12 -92.5799 +137.043 -202.12 -92.5982 +136.875 -202.12 -92.6612 +138.786 -202.12 -97.9556 +138.843 -202.12 -98.0312 +139.089 -202.12 -98.3528 +138.71 -202.12 -97.8251 +137.725 -202.12 -99.5038 +137.849 -202.12 -99.4794 +137.505 -202.12 -99.568 +137.596 -202.12 -99.5407 +137.663 -202.12 -99.5167 +137.434 -202.12 -99.6125 +138.114 -202.12 -99.5482 +138.199 -202.12 -99.6137 +138.366 -202.12 -99.7639 +138.031 -202.12 -99.5188 +137.296 -202.12 -99.6782 +137.864 -202.12 -99.4815 +138.012 -202.12 -99.5096 +134.957 -202.12 -99.5376 +135.03 -202.12 -99.5526 +134.723 -202.12 -99.5186 +134.425 -202.12 -99.5199 +134.84 -202.12 -99.5275 +134.924 -202.12 -99.5336 +134.415 -202.12 -99.5204 +138.718 -202.12 -100.147 +138.773 -202.12 -100.215 +138.562 -202.12 -99.9458 +139.212 -202.12 -100.615 +139.017 -202.12 -100.445 +138.917 -202.12 -100.335 +138.998 -202.12 -100.433 +137.28 -202.12 -92.6888 +139.461 -227.36 -101.537 +139.527 -227.36 -101.558 +139.457 -227.36 -101.536 +139.437 -227.36 -101.533 +132.772 -227.36 -101.253 +132.772 -227.36 -101.253 +132.772 -227.36 -101.253 +133.224 -227.36 -101.28 +133.605 -227.36 -101.326 +133.043 -227.36 -101.279 +133.141 -227.36 -101.276 +135.282 -227.36 -101.499 +135.378 -227.36 -101.505 +135.412 -227.36 -101.506 +133.628 -227.36 -101.328 +133.881 -227.36 -101.367 +133.891 -227.36 -101.367 +133.876 -227.36 -101.366 +136.739 -227.36 -101.451 +136.842 -227.36 -101.469 +136.636 -227.36 -101.45 +134.509 -227.36 -101.409 +134.695 -227.36 -101.436 +133.647 -227.36 -101.331 +136.549 -227.36 -101.465 +136.142 -227.36 -101.49 +136.362 -227.36 -101.474 +134.393 -227.36 -101.39 +132.266 -227.36 -101.195 +135.013 -227.36 -101.471 +135.153 -227.36 -101.491 +135.2 -227.36 -101.496 +135.717 -227.36 -101.485 +135.628 -227.36 -101.487 +137.14 -227.36 -101.499 +137.316 -227.36 -101.484 +136.451 -227.36 -101.475 +137.063 -227.36 -101.5 +137.024 -227.36 -101.487 +136.079 -227.36 -101.49 +131.969 -227.36 -101.164 +132.053 -227.36 -101.176 +131.607 -227.36 -101.121 +131.837 -227.36 -101.152 +138.894 -227.36 -101.597 +138.836 -227.36 -101.621 +138.815 -227.36 -101.633 +137.659 -227.36 -101.482 +137.648 -227.36 -101.483 +138.004 -227.36 -101.495 +139.013 -227.36 -101.548 +138.787 -227.36 -101.633 +138.438 -227.36 -101.627 +138.548 -227.36 -101.68 +138.083 -227.36 -101.505 +139.217 -227.36 -101.533 +139.076 -227.36 -101.541 +138.174 -227.36 -101.526 +138.29 -227.36 -101.545 +137.448 -227.36 -101.478 +137.631 -227.36 -101.483 +139.527 -216.548 -93.68 +139.527 -216.538 -93.6757 +139.527 -216.693 -93.7411 +139.527 -217.154 -93.8102 +139.527 -217.044 -93.8535 +139.527 -209.402 -97.7596 +139.527 -209.403 -97.7645 +139.527 -220.952 -98.06 +139.527 -220.917 -98.3986 +139.527 -220.959 -101.143 +139.527 -220.955 -101.342 +139.527 -220.966 -101.394 +139.527 -220.958 -100.752 +139.527 -220.949 -100.62 +139.527 -220.929 -100.513 +139.527 -220.88 -99.9789 +139.527 -220.882 -100.286 +139.527 -217.172 -93.778 +139.527 -223.027 -101.822 +139.527 -223.039 -101.823 +139.527 -221.782 -101.738 +139.527 -221.734 -101.717 +139.527 -221.725 -101.709 +139.527 -221.706 -101.69 +139.527 -221.563 -101.562 +139.527 -221.87 -101.773 +139.527 -221.853 -101.768 +139.527 -223.045 -101.822 +139.527 -221.89 -101.774 +139.527 -221.347 -101.4 +139.527 -221.433 -101.451 +139.527 -221.487 -101.476 +139.527 -225.406 -101.61 +139.527 -225.209 -101.586 +139.527 -225.632 -101.652 +139.527 -225.163 -101.583 +139.527 -221.34 -101.399 +139.527 -221.335 -101.398 +139.527 -221.017 -101.53 +139.527 -220.97 -101.462 +139.527 -221.327 -101.401 +139.527 -225.136 -101.625 +139.527 -224.994 -101.793 +139.527 -225.043 -101.734 +139.527 -226.083 -101.674 +139.527 -226.195 -101.675 +139.527 -225.681 -101.655 +139.527 -225.971 -101.673 +139.527 -226 -101.671 +139.527 -225.64 -101.652 +139.527 -226.217 -101.676 +139.527 -223.078 -101.819 +139.527 -223.334 -101.784 +139.527 -222.789 -101.791 +139.527 -222.639 -101.78 +139.527 -222.472 -101.786 +139.527 -222.372 -101.792 +139.527 -222.248 -101.781 +139.527 -222.099 -101.775 +139.527 -219.387 -100.4 +139.527 -219.322 -100.394 +139.527 -219.059 -100.412 +139.527 -219.268 -100.397 +139.527 -219.46 -100.402 +139.527 -219.564 -100.394 +139.527 -219.743 -100.372 +139.527 -219.774 -100.371 +139.527 -220.11 -100.416 +139.527 -220.17 -100.432 +139.527 -218.979 -100.385 +139.527 -219.041 -100.406 +139.527 -220.037 -100.408 +139.527 -219.845 -100.383 +139.527 -219.679 -100.386 +139.527 -217.017 -93.7383 +139.527 -217.158 -93.7696 +139.527 -216.868 -93.684 +139.527 -216.956 -93.7275 +139.527 -216.836 -93.6648 +139.527 -216.766 -93.6113 +139.527 -216.733 -93.597 +139.527 -202.215 -97.7352 +139.527 -202.275 -97.777 +139.527 -202.287 -97.7811 +139.527 -202.285 -97.7805 +139.527 -204.08 -97.785 +139.527 -204.203 -97.8887 +139.527 -204.391 -98.0784 +139.527 -204.764 -98.293 +139.527 -204.655 -98.2617 +139.527 -204.583 -98.2633 +139.527 -204.549 -98.2355 +139.527 -205.274 -98.4181 +139.527 -205.202 -98.3695 +139.527 -204.858 -98.2888 +139.527 -204.97 -98.291 +139.527 -205.039 -98.2885 +139.527 -205.075 -98.2942 +139.527 -205.099 -98.3045 +139.527 -204.043 -97.767 +139.527 -204.002 -97.7243 +139.527 -203.517 -97.542 +139.527 -203.594 -97.577 +139.527 -203.419 -97.4962 +139.527 -203.247 -97.5096 +139.527 -203.911 -97.6745 +139.527 -204.46 -98.1609 +139.527 -220.795 -98.0606 +139.527 -220.554 -100.532 +139.527 -220.446 -100.498 +139.527 -220.4 -100.49 +139.527 -220.579 -100.536 +139.527 -220.707 -100.52 +139.527 -220.623 -100.532 +139.527 -208.566 -99.9618 +139.527 -208.471 -100.039 +139.527 -209.062 -99.5555 +139.527 -209.254 -99.2902 +139.527 -208.161 -100.654 +139.527 -208.171 -100.787 +139.527 -209.425 -98.8725 +139.527 -209.354 -99.0861 +139.527 -208.402 -100.173 +139.527 -208.169 -100.603 +139.527 -209.412 -98.7662 +139.527 -209.769 -100.769 +139.527 -209.379 -100.795 +139.527 -209.321 -100.8 +139.527 -209.066 -100.832 +139.527 -208.814 -100.851 +139.527 -208.642 -100.873 +139.527 -210.216 -100.732 +139.527 -210.104 -100.742 +139.527 -218.833 -100.055 +139.527 -218.902 -100.297 +139.527 -218.811 -99.9075 +139.527 -218.799 -99.8553 +139.527 -218.759 -99.6883 +139.527 -218.971 -100.363 +139.527 -218.474 -99.6616 +139.527 -218.568 -99.6527 +139.527 -218.421 -99.677 +139.527 -218.65 -99.6329 +139.527 -218.682 -99.6214 +139.527 -220.916 -98.4103 +139.527 -220.884 -99.0003 +139.527 -220.875 -99.4519 +139.527 -220.915 -98.4211 +139.527 -220.887 -98.6372 +139.527 -220.892 -98.6877 +139.527 -220.87 -99.6827 +139.527 -204.952 -100.421 +139.527 -204.922 -100.351 +139.527 -205.248 -99.3085 +139.527 -205.39 -98.8663 +139.527 -204.97 -100.141 +139.527 -205.05 -99.8609 +139.527 -205.402 -98.7637 +139.527 -205.393 -98.6766 +139.527 -205.337 -98.5205 +139.527 -205.003 -100.632 +139.527 -205.313 -98.4599 +139.527 -224.821 -101.716 +139.527 -224.761 -101.647 +139.527 -224.659 -101.63 +139.527 -224.981 -101.793 +139.527 -224.648 -101.632 +139.527 -216.51 -93.4508 +139.527 -216.456 -93.4919 +139.527 -216.609 -93.4608 +139.527 -216.542 -93.4518 +139.527 -220.766 -100.478 +139.527 -220.768 -100.476 +139.527 -203.905 -97.6704 +139.527 -202.543 -100.722 +139.527 -202.561 -100.64 +139.527 -220.744 -100.493 +139.527 -206.372 -100.89 +139.527 -206.353 -100.89 +139.527 -207.261 -100.877 +139.527 -207.169 -100.897 +139.527 -207.081 -100.9 +139.527 -206.796 -100.904 +139.527 -207.379 -100.861 +139.527 -207.327 -100.874 +139.527 -207.519 -100.797 +139.527 -207.207 -97.187 +139.527 -207.195 -97.1944 +139.527 -211.221 -100.658 +139.527 -211.086 -100.668 +139.527 -211.349 -100.66 +139.527 -210.932 -100.677 +139.527 -210.727 -100.699 +139.527 -210.551 -100.713 +139.527 -211.899 -100.643 +139.527 -205.304 -98.4391 +139.527 -216.779 -100.016 +139.527 -216.86 -100.091 +139.527 -216.972 -100.234 +139.527 -216.941 -100.214 +139.527 -217.049 -100.27 +139.527 -209.435 -98.3696 +139.527 -209.431 -98.1659 +139.527 -209.431 -98.1124 +139.527 -209.435 -98.0831 +139.527 -208.05 -97.1448 +139.527 -208.237 -97.1971 +139.527 -207.966 -97.1219 +139.527 -208.515 -97.2419 +139.527 -208.56 -97.2541 +139.527 -208.897 -97.4221 +139.527 -209.151 -97.6041 +139.527 -209.24 -97.6322 +139.527 -207.592 -97.2241 +139.527 -207.604 -97.2206 +139.527 -207.869 -97.081 +139.527 -207.851 -97.0821 +139.527 -207.616 -97.2076 +139.527 -208.826 -97.3913 +139.527 -207.526 -97.2099 +139.527 -207.315 -97.1571 +139.527 -209.402 -97.7595 +139.527 -208.449 -97.2324 +139.527 -208.725 -97.2944 +139.527 -217.808 -100.298 +139.527 -217.572 -100.286 +139.527 -216.535 -100.255 +139.527 -216.507 -100.277 +139.527 -216.719 -100.023 +139.527 -216.707 -100.036 +139.527 -218.133 -99.7165 +139.527 -218.098 -99.9099 +139.527 -218.058 -100.185 +139.527 -218.051 -100.24 +139.527 -217.987 -100.278 +139.527 -217.431 -100.283 +139.527 -215.031 -100.478 +139.527 -215.011 -100.48 +139.527 -215.088 -100.475 +139.527 -217.948 -100.298 +139.527 -215.467 -100.445 +139.527 -215.349 -100.457 +139.527 -217.284 -100.282 +139.527 -215.943 -100.403 +139.527 -215.742 -100.428 +139.527 -216.05 -100.391 +139.527 -216.079 -100.384 +139.527 -216.386 -100.348 +139.527 -216.427 -100.331 +139.527 -217.125 -100.28 +139.527 -218.188 -99.6937 +139.527 -215.601 -100.435 +139.527 -214.814 -100.496 +139.527 -202.542 -99.8196 +139.527 -202.485 -99.9332 +139.527 -202.475 -99.9485 +139.527 -202.547 -99.8164 +139.527 -202.352 -100.788 +139.527 -202.144 -100.788 +139.527 -202.45 -100.781 +139.527 -213.727 -100.575 +139.527 -213.764 -100.573 +139.527 -212.074 -100.64 +139.527 -212.316 -100.632 +139.527 -214.438 -100.525 +139.527 -213.014 -100.609 +139.527 -212.975 -100.609 +139.527 -212.825 -100.614 +139.527 -214.366 -100.531 +139.527 -205.148 -100.83 +139.527 -205.214 -100.845 +139.527 -206.297 -100.889 +139.527 -205.033 -100.659 +139.527 -205.091 -100.762 +139.527 -205.35 -100.865 +139.527 -205.788 -100.887 +139.527 -205.881 -100.889 +139.527 -205.55 -100.877 +139.527 -208.358 -100.857 +139.527 -208.414 -100.881 +139.527 -208.305 -100.848 +139.527 -208.22 -100.79 +139.527 -212.563 -100.623 +139.527 -210.483 -100.716 +139.527 -202.938 -97.5737 +139.527 -203.16 -97.5296 +139.527 -203.711 -97.615 +139.527 -203.896 -97.6668 +139.527 -202.856 -97.5893 +139.527 -202.639 -97.5881 +139.527 -226.817 -101.641 +139.527 -226.824 -101.639 +139.527 -227.329 -101.554 +139.527 -227.187 -101.565 +139.527 -226.794 -101.644 +139.527 -226.701 -101.661 +139.527 -226.575 -101.658 +139.527 -226.811 -101.642 +139.527 -226.974 -101.586 +139.527 -226.842 -101.631 +139.527 -226.385 -101.656 +139.527 -223.89 -101.749 +139.527 -223.913 -101.753 +139.527 -224.633 -101.64 +139.527 -224.601 -101.648 +139.527 -223.96 -101.767 +139.527 -224.056 -101.785 +139.527 -224.18 -101.805 +139.527 -224.373 -101.687 +139.527 -224.288 -101.747 +139.527 -224.184 -101.805 +139.527 -223.864 -101.754 +139.527 -223.682 -101.796 +139.527 -223.524 -101.783 +139.527 -223.449 -101.775 +139.527 -202.197 -98.8862 +139.527 -202.151 -98.8387 +139.527 -202.491 -99.2266 +139.527 -207.178 -97.4224 +139.527 -207.126 -97.7046 +139.527 -207.123 -97.7116 +139.527 -207.178 -97.5334 +139.527 -207.092 -97.7814 +139.527 -206.929 -98.0976 +139.527 -206.888 -98.1416 +139.527 -206.823 -98.2385 +139.527 -206.563 -98.3967 +139.527 -206.57 -98.4145 +139.527 -206.715 -98.3019 +139.527 -206.669 -98.3263 +139.527 -220.791 -98.0621 +139.527 -202.453 -97.7288 +139.527 -202.356 -97.7585 +139.527 -202.292 -97.7794 +139.527 -202.535 -97.6618 +139.527 -202.616 -97.592 +139.527 -202.466 -97.7197 +139.527 -207.12 -100.077 +139.527 -207.211 -100.21 +139.527 -207.52 -100.653 +139.527 -207.319 -100.374 +139.527 -207.088 -99.9313 +139.527 -207.516 -100.75 +139.527 -202.635 -99.7346 +139.527 -202.66 -99.6509 +139.527 -202.567 -99.8159 +139.527 -202.629 -99.5115 +139.527 -220.801 -98.8103 +139.527 -220.791 -98.8671 +139.527 -220.804 -98.6576 +139.527 -220.786 -99.2341 +139.527 -220.783 -99.5815 +139.527 -220.781 -99.8445 +139.527 -220.767 -100.414 +139.527 -202.485 -100.769 +139.527 -202.476 -99.9851 +139.527 -202.491 -100.306 +139.527 -202.582 -100.506 +139.527 -216.479 -93.5739 +139.527 -216.529 -93.6589 +139.527 -220.809 -98.466 +139.527 -220.809 -98.3242 +139.527 -220.808 -98.2997 +139.527 -220.792 -98.0803 +139.527 -206.729 -98.7718 +139.527 -206.87 -99.1632 +139.527 -206.562 -98.4772 +139.527 -206.99 -99.4918 +139.527 -207.052 -99.689 +139.527 -220.768 -100.471 +139.527 -202.595 -99.2584 +137.895 -203.929 -99.5234 +134.399 -213.042 -95.5492 +134.165 -213.22 -95.4836 +134.295 -212.586 -95.2648 +136.207 -213.306 -99.5972 +136.223 -213.496 -99.7661 +136.639 -209.048 -93.3382 +136.216 -209.396 -93.3488 +138.534 -208.962 -95.9251 +138.312 -209.19 -95.7415 +138.639 -208.8 -96.0619 +139.393 -202.996 -97.5329 +139.255 -202.947 -97.6313 +137.758 -202.792 -99.5277 +137.655 -203.047 -99.5443 +138.27 -218.372 -99.6472 +138.25 -218.49 -99.6722 +138.368 -218.464 -99.7459 +134.006 -207.113 -99.9584 +134.028 -207.399 -100.058 +139.048 -215.221 -100.47 +139.061 -218.252 -100.111 +138.773 -218.212 -100.173 +133.361 -211.992 -100.186 +135.579 -216.402 -100.481 +135.607 -216.822 -100.485 +135.258 -224.792 -100.709 +135.597 -224.339 -100.705 +133.961 -207.572 -99.9909 +134.049 -207.52 -100.05 +136.161 -202.368 -99.6735 +136.978 -202.867 -99.6992 +137.369 -202.638 -99.5939 +137.784 -202.606 -99.5205 +137.986 -202.76 -99.4816 +136.435 -203.112 -99.7086 +137.602 -210.089 -98.2633 +137.525 -210.164 -98.557 +138.143 -210.264 -98.3018 +136.409 -212.339 -100.056 +136.267 -212.235 -99.6372 +136.797 -212.078 -100.452 +138.853 -210.391 -100.654 +138.674 -209.937 -100.665 +138.392 -209.166 -100.312 +138.247 -209.204 -100.446 +137.894 -211.413 -100.581 +138.725 -212.013 -100.594 +138.148 -212.14 -100.587 +137.616 -202.229 -99.5303 +135.551 -212.384 -100.296 +135.743 -212.237 -100.243 +135.575 -212.287 -100.421 +134.06 -212.279 -100.474 +133.898 -211.975 -100.448 +134.16 -211.402 -100.344 +133.769 -212.535 -100.441 +134.094 -212.836 -100.381 +133.684 -213.063 -100.362 +133.423 -211.525 -100.187 +134.624 -206.337 -99.6561 +134.346 -206.745 -99.7188 +134.224 -206.444 -99.718 +134.48 -207.635 -99.7719 +135.137 -206.361 -99.6336 +135.204 -205.986 -99.6097 +135.471 -206.219 -99.6235 +134.806 -204.762 -99.5545 +134.618 -204.735 -99.5735 +134.748 -204.938 -99.6896 +135.618 -202.279 -99.6177 +135.866 -202.589 -99.6546 +135.305 -203.989 -99.6005 +134.705 -204.035 -99.5406 +135.086 -204.045 -99.5725 +135.027 -202.784 -99.5486 +136.884 -202.778 -99.7558 +135.009 -226.683 -101.479 +134.569 -226.008 -101.335 +134.248 -226.126 -101.329 +134.673 -225.69 -101.395 +134.39 -225.945 -101.334 +133.626 -226.619 -101.325 +133.117 -227.256 -101.28 +133.273 -226.76 -101.299 +133.518 -224.674 -100.905 +133.566 -224.776 -101.324 +133.751 -224.614 -101.375 +134.011 -225.751 -101.32 +134.659 -221.49 -99.935 +134.727 -221.719 -99.6559 +134.485 -221.697 -99.9358 +132.964 -224.36 -100.167 +133.178 -224.197 -100.028 +133.165 -224.487 -100.433 +134.249 -225.12 -101.388 +135.11 -218.893 -100.289 +135.794 -212.409 -99.6393 +135.654 -212.42 -99.945 +136.65 -211.823 -95.7187 +132.623 -217.098 -100.241 +134.452 -216.91 -100.483 +136.063 -213.836 -100 +136.011 -214.184 -100.393 +135.822 -213.67 -99.516 +132.513 -218.748 -100.044 +133.382 -216.656 -98.1171 +133.253 -216.582 -97.9809 +133.23 -216.434 -97.8905 +132.747 -218.52 -100.101 +134.765 -220.012 -100.465 +134.945 -219.805 -100.471 +134.469 -220.151 -100.472 +135.921 -216.618 -100.481 +134.295 -216.763 -100.116 +134.587 -216.8 -100.319 +135.565 -214.915 -100.477 +136.102 -214.716 -100.468 +136.119 -217.754 -100.441 +135.746 -217.988 -100.466 +134.661 -219.025 -100.51 +134.89 -219.294 -100.496 +136.799 -215.797 -100.473 +136.564 -216.23 -100.458 +134.149 -225.234 -101.39 +133.537 -220.251 -100.542 +132.38 -219.407 -100.647 +132.652 -217.839 -99.9322 +132.613 -217.636 -100.008 +133.295 -218.452 -100.6 +133.451 -217.871 -100.629 +133.589 -218.294 -100.573 +134.672 -216.662 -100.158 +134.364 -217.996 -100.551 +134.173 -218.054 -100.55 +134.662 -216.964 -100.587 +135.207 -216.721 -100.545 +134.948 -216.714 -100.565 +135.159 -216.492 -100.358 +134.744 -216.718 -100.48 +134.924 -222.031 -98.4671 +134.643 -222.758 -98.1241 +134.984 -222.466 -98.2386 +135.466 -224.165 -100.66 +133.741 -224.132 -100.126 +133.947 -224.134 -99.9596 +132.724 -222.521 -98.691 +133.6 -224.131 -99.8417 +134.629 -227.199 -101.441 +135.178 -227.311 -101.493 +131.965 -224.927 -100.715 +132.068 -225.122 -101.144 +134.789 -225.593 -101.444 +132.337 -226.099 -101.2 +131.564 -226.609 -101.128 +133.118 -226.453 -101.282 +133.268 -224.791 -101.147 +132.952 -224.845 -101.266 +135.761 -224.721 -98.2105 +136.012 -224.748 -98.7078 +135.727 -224.603 -98.8839 +134.889 -222.603 -98.7025 +134.86 -221.792 -98.8246 +139.002 -218.812 -99.6828 +139.136 -218.93 -99.704 +135.652 -218.741 -100.421 +135.436 -218.955 -100.453 +136.132 -224.848 -101.343 +136.181 -224.676 -101.275 +135.846 -224.695 -100.846 +138.116 -221.314 -101.629 +138.41 -221.471 -101.722 +138.352 -221.231 -101.611 +137.309 -223.663 -101.615 +138.947 -212.908 -100.586 +138.177 -212.669 -100.571 +137.495 -218.178 -100.321 +137.757 -218.097 -100.279 +136.477 -213.317 -100.358 +136.407 -213.45 -100.198 +136.568 -212.992 -100.48 +136.653 -216.626 -100.451 +136.164 -216.61 -100.47 +135.847 -215.917 -100.469 +136.386 -215.982 -100.448 +136.311 -215.255 -100.487 +139.092 -213.329 -100.588 +138.748 -213.669 -100.574 +138.503 -215.11 -100.489 +138.901 -221.126 -101.532 +138.834 -221.085 -101.451 +137.648 -220.239 -100.583 +138.061 -220.567 -100.563 +137.487 -222.435 -101.295 +137.529 -222.236 -101.527 +137.713 -222.955 -101.555 +135.842 -219.878 -100.403 +136.374 -219.65 -100.365 +135.748 -219.699 -100.417 +135.527 -220.139 -100.374 +135.384 -219.926 -100.467 +136.501 -217.249 -100.459 +135.829 -220.278 -100.081 +135.447 -220.458 -100.221 +135.27 -220.309 -100.391 +137.23 -219.968 -99.908 +137.546 -219.554 -99.7339 +137.476 -219.762 -99.7919 +138.971 -209.728 -97.0913 +138.704 -209.855 -97.0914 +137.872 -218.194 -100.222 +137.888 -218.656 -100.159 +134.458 -226.319 -101.411 +134.71 -226.229 -101.433 +139.37 -217.999 -100.271 +139.08 -218.029 -100.218 +136.906 -217.409 -100.445 +137.109 -217.818 -100.376 +139.333 -221.044 -101.571 +138.773 -218.016 -100.248 +137.957 -213.136 -100.553 +138.637 -213.373 -100.562 +139.397 -216.968 -100.191 +139.471 -216.797 -99.9671 +137.662 -215.839 -100.471 +137.586 -216.386 -100.444 +136.426 -212.732 -100.478 +136.78 -212.977 -100.506 +136.362 -212.574 -100.371 +136.506 -212.493 -100.025 +136.4 -212.582 -99.7852 +136.221 -212.787 -99.2784 +136.268 -213.182 -99.7375 +136.434 -212.635 -99.458 +136.507 -212.508 -99.3297 +135.074 -215.07 -97.1484 +135.244 -215.103 -97.2045 +137.75 -219.593 -99.7534 +137.635 -219.331 -99.8043 +138.575 -218.345 -99.9387 +138.217 -218.086 -100.194 +138.429 -218.165 -100.137 +138.623 -218.116 -100.248 +138.583 -219.133 -99.6946 +138.406 -219.476 -99.8527 +138.659 -219.282 -99.7677 +136.615 -219.997 -99.7891 +137.028 -219.033 -100.305 +136.667 -219.327 -100.341 +136.347 -224.023 -100.471 +136.394 -224.608 -100.607 +136.328 -224.672 -100.306 +136.432 -224.593 -99.8658 +138.214 -225.526 -101.295 +138.33 -225.514 -101.323 +138.154 -225.419 -101.303 +135.742 -224.47 -100.617 +135.734 -224.646 -100.18 +135.724 -224.613 -100.652 +136.38 -224.607 -99.4152 +136.141 -224.711 -99.3431 +134.637 -225.215 -101.417 +138.525 -227.032 -101.49 +136.773 -225.851 -101.29 +136.984 -225.528 -101.298 +136.404 -225.926 -101.418 +136.348 -224.615 -98.8182 +136.378 -224.621 -98.3275 +135.743 -224.757 -100.838 +135.512 -224.923 -101.037 +135.456 -224.932 -100.712 +136.781 -224.436 -101.42 +137.401 -224.901 -101.306 +137.148 -224.928 -101.323 +135.708 -224.906 -101.149 +138.109 -225.116 -101.505 +137.777 -224.82 -101.482 +134.355 -225.717 -101.349 +136.81 -223.843 -101.497 +139.404 -224.156 -101.784 +139.283 -224.236 -101.746 +139.5 -224.656 -101.629 +137.455 -223.233 -100.098 +137.48 -223.236 -100.345 +137.491 -222.717 -100.7 +139.091 -226.018 -101.544 +138.259 -224.64 -101.601 +138.385 -224.7 -101.585 +139.062 -226.549 -101.576 +138.755 -225.573 -101.334 +138.281 -225.163 -101.38 +138.255 -224.875 -101.551 +138.971 -222.144 -101.733 +139.309 -222.111 -101.774 +137.41 -221.734 -101.193 +139.364 -220.988 -101.354 +139.057 -221.021 -100.59 +139.365 -220.986 -100.658 +137.815 -222.301 -101.632 +137.896 -222.509 -101.586 +137.567 -223.205 -100.536 +137.469 -222.677 -100.442 +135.533 -225.16 -101.442 +135.245 -225.026 -101.459 +137.534 -222.856 -101.332 +137.49 -222.567 -101.384 +137.456 -220.113 -100.577 +137.399 -220.261 -100.609 +137.592 -219.984 -100.463 +137.199 -220.253 -100.617 +139.324 -219.106 -100.381 +139.494 -219.342 -100.397 +137.933 -219.795 -100.426 +138.004 -219.953 -100.54 +138.344 -219.694 -100.518 +138.144 -221.186 -100.589 +138.341 -221.177 -101.331 +138.708 -217.014 -100.283 +137.619 -221.551 -101.613 +137.431 -221.544 -101.412 +135.987 -226.73 -101.471 +135.889 -225.995 -101.453 +136.221 -224.724 -98.6867 +134.532 -221.658 -93.0783 +134.5 -221.544 -93.2807 +135.744 -222.806 -93.8144 +135.79 -224.727 -98.9252 +135.798 -224.719 -99.4905 +135.865 -221.711 -92.8804 +135.789 -221.951 -92.7798 +136.008 -222.536 -92.503 +135.777 -222.53 -92.712 +136.667 -223.769 -98.3223 +136.779 -218.643 -93.6188 +136.987 -218.818 -93.8005 +136.899 -221.472 -93.9365 +136.496 -221.467 -93.9975 +137.032 -221.457 -93.4288 +136.871 -221.604 -93.5743 +136.581 -221.885 -93.2038 +136.76 -221.612 -93.595 +137.201 -218.159 -93.6532 +137.289 -218.102 -93.6617 +136.829 -218.564 -93.6023 +137.553 -214.195 -94.7052 +137.438 -214.136 -94.8348 +137.404 -214.002 -94.6301 +138.724 -213.652 -94.8955 +137.507 -213.417 -94.0454 +137.542 -213.628 -94.1037 +137.574 -213.404 -94.1315 +137.342 -213.82 -94.2485 +137.202 -213.695 -93.9566 +137.273 -213.407 -93.9952 +135.927 -214.367 -93.9306 +137.548 -213.015 -93.9393 +137.484 -213.261 -93.9752 +136.458 -214.394 -94.0356 +136.504 -214.227 -94.1227 +136.22 -214.138 -94.3 +136.658 -214.445 -94.3561 +137.071 -213.803 -93.9401 +134.351 -212.669 -95.156 +134.311 -212.393 -94.9324 +136.489 -213.7 -94.308 +136.031 -213.883 -94.5456 +136.174 -213.609 -94.4496 +137.639 -213.017 -94.3409 +137.611 -213.432 -94.5975 +136.685 -214.522 -94.698 +136.541 -214.674 -94.8159 +139.469 -216.521 -93.6838 +138.476 -219.052 -94.0727 +138.62 -218.675 -94.388 +138.75 -218.897 -94.294 +136.399 -212.768 -98.8724 +136.227 -212.789 -99.0949 +136.496 -212.705 -99.0694 +138.542 -213.839 -94.8063 +138.364 -213.982 -94.9051 +138.506 -214.099 -94.8222 +138.245 -214.125 -94.6735 +135.844 -216.068 -97.4437 +135.791 -216.175 -97.4893 +136.163 -216.195 -97.8451 +137.126 -214.499 -94.8394 +137.2 -214.087 -95.1462 +137.213 -213.953 -95.2131 +137.037 -214.274 -94.8543 +136.378 -214.786 -94.7784 +139.287 -218.738 -93.8975 +138.902 -218.424 -94.0347 +139.22 -218.771 -93.8801 +138.918 -218.839 -94.2041 +139.18 -218.674 -93.8658 +139.124 -218.276 -94.4036 +139.188 -218.642 -94.2849 +139.394 -216.514 -93.5976 +137.877 -218.455 -93.7043 +137.634 -218.506 -93.773 +137.875 -218.2 -93.6182 +138.523 -218.119 -94.3581 +138.574 -217.732 -94.1171 +137.959 -217.982 -94.1352 +138.054 -217.71 -93.9378 +139.303 -218.355 -94.2187 +137.526 -221.21 -99.5 +137.296 -221.348 -98.8632 +134.406 -221.15 -92.9235 +134.296 -221.018 -93.0777 +137.438 -219.378 -93.9104 +137.531 -219.501 -93.9392 +137.367 -219.59 -93.9694 +138.241 -219.203 -94.1119 +137.817 -219.373 -94.0412 +137.234 -219.581 -94.09 +138.527 -218.884 -93.9809 +137.397 -218.884 -94.3514 +137.095 -221.77 -93.9221 +136.347 -221.811 -94.2063 +136.148 -221.219 -93.6618 +136.611 -221.321 -93.7204 +137.109 -221.92 -98.1762 +136.606 -222.09 -93.2582 +136.557 -221.794 -93.2462 +136.062 -222.812 -94.1171 +136.497 -222.286 -94.2363 +136.576 -222.113 -94.3148 +137.28 -218.259 -94.3113 +137.003 -218.874 -94.1146 +135.791 -222.895 -94.0161 +135.527 -222.735 -93.9189 +136.262 -222.413 -94.2806 +136.041 -222.405 -94.0048 +136.371 -223.891 -99.0091 +136.869 -223.617 -98.9408 +136.454 -223.846 -98.678 +136.38 -224.345 -99.6456 +139.219 -220.822 -98.7997 +138.161 -221.018 -98.3624 +138.597 -220.949 -99.5663 +137.411 -222.747 -98.1911 +137.418 -222.655 -98.447 +136.35 -224.187 -98.8559 +137.186 -222.576 -98.1188 +135.742 -224.159 -99.2853 +138.162 -218.347 -99.7601 +137.335 -221.261 -98.429 +137.309 -221.976 -98.2114 +137.401 -222.958 -98.1302 +137.472 -223.032 -98.192 +137.486 -223.314 -98.3643 +136.4 -224.447 -98.4332 +136.335 -224.678 -98.242 +136.362 -224.177 -98.195 +137.416 -222.922 -99.8211 +137.305 -221.881 -99.1236 +136.437 -223.024 -98.1471 +136.442 -223.244 -98.0179 +137.318 -221.21 -98.0329 +137.085 -221.27 -98.071 +137.277 -221.756 -98.3551 +135.101 -224.184 -99.1904 +135.309 -224.178 -99.0816 +136.292 -220.844 -100.473 +136.25 -221.087 -100.241 +136.122 -220.83 -100.259 +134.179 -221.362 -100.205 +136.309 -224.669 -99.211 +138.513 -217.478 -99.406 +138.476 -217.557 -98.3823 +138.453 -217.583 -98.7067 +138.694 -218.939 -99.6757 +139.272 -220.932 -98.8767 +139.32 -220.907 -99.6679 +138.626 -220.91 -98.7762 +138.574 -221.054 -99.3531 +136.501 -214.858 -100.486 +137.639 -216.98 -100.356 +137.567 -217.3 -100.325 +137.2 -221.223 -98.0409 +137.52 -221.176 -98.1066 +139.444 -220.969 -98.0766 +138.675 -217.712 -98.4504 +134.786 -216.808 -97.248 +134.79 -217.087 -97.3451 +138.54 -217.539 -98.2908 +138.522 -217.695 -98.3267 +135.594 -213.9 -94.783 +135.53 -214.029 -94.8773 +135.613 -214.387 -95.1628 +131.769 -223.624 -97.0645 +131.85 -223.77 -96.9145 +133.306 -222.961 -96.5392 +132.331 -223.538 -97.4588 +132.645 -223.725 -97.1468 +131.934 -222.319 -97.8248 +133.716 -223.385 -96.7805 +133.632 -223.396 -97.3887 +133.811 -223.347 -97.5104 +134.249 -223.731 -97.8984 +134.104 -223.607 -97.7749 +133.818 -223.755 -97.7686 +132.897 -223.737 -97.5417 +132.544 -223.977 -97.4211 +134.23 -223.557 -96.7602 +133.508 -223.298 -96.6049 +134.88 -222.133 -98.1407 +134.945 -221.886 -98.2959 +136.834 -219.901 -99.7868 +137.228 -219.49 -99.8695 +135.775 -215.94 -97.0105 +135.597 -215.982 -97.0421 +134.708 -216.402 -96.6052 +134.657 -216.699 -96.6003 +133.059 -215.929 -100.199 +135.93 -216.257 -97.6979 +135.501 -216.605 -97.3763 +135.184 -216.541 -97.2754 +134.829 -214.753 -97.5178 +134.721 -214.808 -97.3063 +133.986 -214.526 -98.0344 +134.225 -214.513 -97.7666 +133.872 -214.749 -97.6923 +136.406 -214.765 -97.976 +136.397 -215.017 -98.2297 +134.738 -217.126 -97.7925 +134.616 -217.07 -97.0125 +134.264 -216.98 -97.2515 +134.583 -215.937 -97.2932 +134.592 -215.83 -97.4252 +134.53 -215.927 -97.1034 +134.168 -216.745 -97.6973 +133.913 -216.383 -97.651 +134.124 -216.498 -97.5803 +132.785 -215.439 -100.251 +132.807 -215.739 -100.225 +133.873 -217.034 -98.5256 +133.655 -216.744 -98.7994 +132.486 -218.722 -100.008 +133.446 -216.256 -100.156 +133.375 -216.597 -97.9839 +133.267 -216.514 -97.8864 +133.056 -215.593 -100.209 +134.996 -215.506 -99.718 +135.312 -215.303 -99.3291 +134.96 -215.686 -99.5753 +132.813 -216.047 -100.212 +134.967 -214.024 -97.9925 +134.86 -216.699 -97.3675 +134.834 -217.11 -97.763 +134.639 -217.081 -97.8236 +134.968 -216.25 -100.131 +135.044 -216.444 -100.16 +134.924 -216.473 -100.118 +134.954 -214.993 -97.3125 +134.316 -214.38 -97.9314 +134.366 -214.119 -98.4331 +133.499 -216.638 -98.0849 +136.347 -224.07 -99.8421 +132.165 -224.779 -99.9104 +135.497 -224.102 -99.495 +135.772 -224.142 -98.1725 +135.825 -224.433 -97.9971 +133.771 -223.071 -98.0369 +134.324 -223.081 -97.8304 +134.002 -223.431 -97.4983 +132.944 -224.333 -99.2928 +132.624 -224.434 -99.1034 +132.986 -224.356 -99.0751 +132.747 -222.245 -98.5487 +132.766 -222.082 -98.7072 +134.352 -224.395 -98.8471 +134.114 -224.281 -98.8729 +134.253 -224.277 -99.4142 +132.177 -222.833 -97.6391 +132.073 -222.695 -97.5358 +132.127 -222.448 -97.9098 +131.948 -222.395 -97.705 +132.209 -224.257 -97.1676 +132.226 -224.567 -97.6647 +134.872 -221.835 -98.5577 +134.121 -223.862 -98.5035 +133.778 -223.885 -98.2688 +133.684 -224.011 -98.42 +131.63 -224.604 -97.2702 +131.808 -224.49 -97.0922 +131.849 -224.606 -97.2122 +131.644 -225.671 -97.6968 +131.682 -225.704 -97.4832 +131.649 -225.833 -97.5241 +135.507 -222.697 -94.0464 +134.454 -222.666 -93.3854 +133.948 -223.052 -93.9893 +134.297 -223.778 -93.7492 +134.172 -223.862 -93.929 +134.081 -223.843 -94.099 +135.711 -221.649 -93.743 +135.748 -222.424 -94.0962 +134.192 -223.498 -94.1413 +133.122 -223.713 -93.9986 +134.912 -223.437 -93.1974 +133.442 -223.926 -92.9747 +133.679 -223.806 -93.2986 +133.773 -223.724 -93.3128 +132.755 -223.268 -93.1658 +134.615 -222.309 -92.8135 +134.4 -222.143 -92.713 +134.365 -222.813 -92.9966 +134.236 -222.686 -93.1802 +133.895 -222.846 -93.1794 +133.133 -223.542 -94.0622 +133.215 -222.522 -93.2124 +133.141 -222.483 -92.9329 +135.047 -220.634 -93.1311 +134.954 -221.894 -93.5257 +135.124 -221.976 -93.325 +134.955 -221.975 -93.4047 +135.292 -221.688 -93.6485 +135.103 -221.655 -93.6618 +134.559 -222.876 -93.0311 +135.113 -221.808 -93.5846 +135.57 -222.19 -93.8025 +133.789 -223.826 -94.1074 +133.837 -223.914 -93.8553 +134.685 -223.126 -93.2041 +134.331 -223.053 -93.0608 +133.691 -222.849 -93.0896 +133.798 -222.993 -93.1145 +134.904 -223.578 -92.9513 +134.784 -223.264 -93.1528 +135.574 -222.371 -92.4621 +135.229 -222.133 -92.3093 +135.114 -222.495 -92.4536 +135.239 -222.413 -92.3977 +134.933 -221.827 -93.2297 +134.557 -221.686 -92.5841 +135.007 -221.861 -92.5582 +134.793 -221.967 -92.2014 +134.617 -221.881 -92.2113 +134.067 -221.189 -92.8212 +134.276 -221.384 -92.8423 +132.84 -222.199 -92.3956 +132.833 -222.438 -92.4523 +133.029 -222.924 -92.5 +133.358 -222.919 -92.1545 +133.195 -222.946 -92.2639 +133.343 -222.589 -92.3469 +133.024 -222.401 -92.3436 +133.396 -222.844 -92.5313 +133.432 -222.73 -92.6047 +133.132 -223.108 -92.9462 +133.021 -223.198 -92.9853 +133.094 -222.322 -92.4852 +132.938 -222.495 -92.2908 +133.314 -223.086 -92.8631 +136.702 -218.78 -93.7475 +136.746 -218.566 -93.6492 +134.302 -220.777 -92.9779 +134.604 -220.659 -93.1287 +134.967 -213.436 -93.4901 +134.497 -213.298 -95.3381 +134.461 -213.712 -95.3027 +134.346 -213.424 -95.2785 +134.46 -220.749 -92.9706 +134.215 -221.155 -92.7582 +134.461 -220.976 -92.9979 +135.124 -220.686 -93.0873 +135.562 -213.765 -94.672 +135.285 -213.622 -94.7024 +135.064 -213.613 -94.467 +135.174 -213.411 -94.2979 +134.984 -213.433 -94.2759 +134.621 -212.481 -94.8012 +134.243 -213.517 -95.61 +136.326 -215.557 -96.6796 +136.338 -215.505 -96.7941 +136.457 -215.887 -96.6834 +136.452 -210.404 -98.0695 +136.321 -210.623 -98.1492 +136.404 -210.062 -97.8558 +135.274 -213.501 -94.4425 +134.673 -213.594 -95.3674 +134.343 -213.81 -95.3356 +134.849 -215.046 -97.1603 +134.945 -215.357 -97.1263 +134.747 -215.262 -97.1805 +134.901 -213.43 -95.1075 +134.794 -213.247 -95.1536 +133.975 -215.897 -96.7111 +135.949 -215.805 -96.7015 +135.77 -215.699 -96.7334 +134.661 -214.657 -97.4168 +134.586 -214.415 -97.8178 +135.39 -215.892 -97.0164 +135.484 -216.006 -96.9949 +133.744 -210.474 -97.464 +133.673 -210.49 -97.7375 +133.617 -210.293 -98.0352 +134.236 -212.07 -94.7787 +134.205 -212.176 -94.7381 +134.246 -212.146 -94.684 +134.66 -212.996 -95.2933 +134.751 -213.056 -94.9054 +134.466 -212.8 -95.1948 +134.51 -212.324 -95.2098 +134.286 -212.038 -94.9133 +135.348 -209.297 -93.6235 +135.365 -209.404 -93.4541 +135.568 -209.755 -93.5226 +135.269 -209.8 -93.6562 +134.824 -211.662 -94.7785 +134.932 -211.875 -94.7629 +135.486 -212.095 -93.6051 +135.418 -212.245 -93.5885 +135.27 -211.949 -94.4916 +135.305 -211.956 -93.9684 +135.504 -211.91 -93.5282 +135.136 -209.742 -93.389 +135.028 -209.718 -93.4441 +136.779 -205.921 -95.3951 +136.429 -206.324 -94.7137 +135.259 -204.317 -99.5936 +133.921 -206.419 -99.9251 +134.228 -210.508 -97.5526 +134.039 -210.875 -97.4358 +133.799 -210.872 -97.5575 +133.924 -211.197 -97.6692 +133.904 -211.113 -97.5803 +134.04 -211.625 -97.7568 +134.053 -211.611 -97.5863 +134.072 -210.3 -97.522 +133.788 -210.608 -97.4165 +133.747 -210.74 -97.5944 +134.691 -210.648 -97.4926 +138.788 -203.419 -97.8179 +139.071 -203.463 -97.5535 +139.393 -203.744 -97.6007 +139.417 -204.086 -97.7303 +135.139 -204.78 -99.5139 +138.591 -205.519 -97.2174 +138.557 -205.589 -96.8815 +134.449 -204.655 -99.5614 +134.565 -204.469 -99.5482 +137.887 -204.596 -96.4931 +137.872 -204.432 -96.4143 +137.752 -204.626 -96.4623 +137.505 -203.877 -96.5525 +136.536 -204.349 -96.2309 +136.654 -204.03 -96.2741 +138.868 -203.296 -97.7693 +136.824 -202.733 -97.1602 +136.65 -202.794 -97.0466 +136.359 -202.988 -96.7251 +137.03 -203.815 -96.2487 +136.678 -203.785 -96.3092 +137.432 -203.665 -96.6653 +137.311 -204.588 -96.3899 +137.505 -204.754 -96.4159 +137.45 -204.653 -96.4644 +137.478 -204.076 -96.4216 +137.847 -204.295 -96.4075 +137.68 -204.304 -96.4236 +137.065 -204.095 -96.3184 +137.238 -203.953 -96.3571 +136.778 -203.966 -96.2848 +137.202 -204.311 -96.328 +137.029 -204.18 -96.2717 +136.396 -203.818 -96.3459 +136.877 -203.28 -96.3155 +136.559 -203.56 -96.3176 +137.119 -203.806 -96.28 +137.186 -205.69 -96.1776 +137.586 -205.664 -96.2285 +138.191 -205.925 -96.5208 +137.832 -206.066 -96.4936 +138.636 -207.389 -96.6567 +138.554 -207.467 -96.6544 +138.529 -205.307 -96.8578 +138.442 -205.123 -98.2959 +136.407 -208.918 -97.4762 +137.148 -208.716 -95.6805 +137.052 -208.857 -96.3908 +138.798 -208.139 -96.3862 +138.879 -207.556 -96.43 +139.026 -208.11 -96.8178 +138.84 -208.421 -96.5634 +138.652 -208.45 -95.954 +138.645 -208.523 -96.1561 +137.639 -209.481 -96.3322 +137.266 -209.509 -96.9007 +138.039 -209.466 -96.5375 +138.33 -207.658 -96.2997 +138.299 -207.497 -96.4936 +138.396 -207.651 -95.9906 +138.94 -209.165 -96.7663 +137.98 -209.782 -96.8971 +137.633 -209.357 -96.0966 +137.36 -209.65 -100.548 +137.188 -209.875 -100.582 +137.999 -209.843 -97.0618 +138.087 -210 -97.3921 +138.104 -209.931 -97.1041 +138.228 -205.057 -97.0767 +138.429 -204.962 -97.2833 +139.398 -206.95 -97.3582 +138.693 -205.185 -98.192 +138.612 -205.231 -97.9512 +139.342 -206.492 -97.8836 +139.134 -206.363 -97.8347 +138.893 -206.333 -97.8504 +138.713 -206.316 -97.6473 +138.593 -206.304 -97.2839 +138.418 -204.903 -97.3831 +138.699 -205.53 -97.8125 +138.51 -205.146 -97.6559 +138.879 -204.291 -97.882 +138.894 -203.988 -97.7983 +139.505 -205.308 -98.439 +139.486 -207.29 -97.1007 +139.417 -204.986 -100.245 +139.156 -205.313 -100.781 +139.51 -209.462 -98.0952 +139.408 -209.605 -97.3492 +139.357 -209.54 -97.24 +139.224 -209.981 -98.0261 +139.098 -210.066 -97.8589 +138.464 -210.01 -97.2622 +138.146 -209.224 -96.4019 +137.9 -209.432 -95.9885 +138.865 -209.87 -98.744 +138.209 -210.228 -98.494 +135.464 -210.28 -97.6299 +134.814 -209.936 -97.535 +138.939 -208.655 -100.615 +138.905 -209.083 -100.036 +135.521 -210.061 -97.5677 +136.85 -209.453 -97.4167 +134.141 -211.75 -97.9943 +135.772 -212.558 -99.9398 +136.21 -212.643 -99.6408 +136.359 -212.859 -99.1647 +136.085 -213.204 -99.6117 +138.91 -210.119 -97.9719 +138.955 -210.057 -98.1659 +139.504 -206.537 -98.4691 +139.505 -206.547 -98.4001 +138.811 -205.74 -98.6259 +139.281 -206.47 -98.6893 +138.092 -204.419 -99.4084 +137.936 -204.783 -99.5497 +139.471 -202.701 -99.873 +136.219 -204.666 -99.6592 +136.686 -205.007 -99.667 +136.548 -204.312 -99.7074 +138.532 -205.572 -99.7775 +138.235 -205.633 -99.4629 +137.885 -203.323 -99.4557 +138.197 -204.719 -99.4496 +137.941 -205.046 -99.5598 +138.751 -203.638 -98.1837 +138.723 -203.628 -97.9988 +137.645 -204.47 -97.7815 +137.134 -203.344 -97.5846 +137.13 -204.13 -97.5662 +135.54 -204.937 -99.591 +136.103 -204.845 -99.6524 +135.605 -204.472 -99.7226 +139.225 -202.429 -100.168 +139.12 -202.556 -100.181 +138.148 -203.005 -99.4748 +138.714 -203.999 -98.1721 +138.885 -203.63 -97.6463 +138.825 -203.759 -97.7588 +138.778 -204.074 -97.9848 +139.204 -204.05 -97.7529 +138.454 -204.681 -99.2647 +138.423 -204.439 -99.1416 +139.098 -204.934 -98.7081 +139.156 -204.998 -98.6205 +139.205 -205.134 -98.7676 +138.91 -204.547 -98.0108 +139.033 -204.467 -97.8524 +138.587 -204.628 -98.8571 +138.512 -204.52 -98.9587 +138.596 -205.229 -98.5257 +138.053 -203.154 -99.4271 +139.401 -204.23 -97.7919 +139.421 -205.372 -98.6162 +138.035 -202.595 -99.4932 +138.323 -205.911 -95.046 +138.41 -206.037 -94.8813 +138.389 -206.112 -94.7607 +138.35 -207.534 -96.5463 +139.074 -209.44 -96.8335 +134.19 -210.153 -97.5552 +134.495 -210.102 -97.5196 +137.754 -209.499 -96.1831 +137.861 -209.493 -96.2183 +138.239 -207.238 -96.6975 +138.564 -209.115 -95.4738 +138.25 -208.982 -95.1823 +138.239 -209.057 -95.3341 +138.374 -208.667 -94.8853 +138.505 -208.725 -95.1916 +138.386 -208.519 -94.8537 +138.663 -207.077 -95.1103 +138.705 -207.432 -94.9067 +138.402 -206.417 -94.9746 +138.2 -206.268 -94.0365 +137.936 -206.972 -94.9033 +137.939 -207.565 -95.0662 +138.147 -206.666 -94.8156 +138.345 -206.787 -94.6758 +138.32 -206.455 -94.8673 +138.056 -208.949 -94.034 +138.449 -208.607 -94.8667 +138.579 -207.41 -94.6393 +138.486 -207.234 -94.5441 +138.606 -208.978 -96.623 +138.705 -209.294 -96.4829 +136.827 -213.966 -94.1676 +135.515 -213.554 -94.2614 +135.313 -213.379 -94.1332 +136.217 -213.077 -94.1834 +136.198 -213.303 -94.3678 +136.327 -212.568 -93.7266 +136.277 -213.047 -93.7771 +136.234 -212.765 -93.8451 +135.229 -211.371 -95.0258 +135.469 -211.059 -94.8934 +135.094 -211.238 -96.3391 +137.821 -212.47 -94.2643 +137.344 -212.343 -95.7471 +137.589 -212.85 -95.188 +137.839 -207.649 -95.0015 +137.443 -207.747 -94.6844 +137.894 -207.859 -94.8935 +136.331 -207.359 -98.4052 +136.623 -206.354 -97.0972 +137.249 -208.054 -92.9431 +137.274 -208.117 -92.2235 +136.839 -207.766 -92.0816 +136.752 -207.919 -92.0047 +137.165 -208.041 -94.0036 +137.185 -207.653 -93.2885 +137.267 -208.161 -93.295 +136.187 -210.216 -94.566 +136.037 -210.124 -94.3818 +136.616 -209.785 -94.9557 +135.85 -210.137 -94.2489 +138.342 -206.795 -95.8702 +138.591 -207.51 -95.3697 +138.282 -206.083 -94.2503 +138.401 -206.332 -95.1341 +135.581 -204.402 -96.5005 +135.872 -204.264 -96.2523 +136.802 -207.176 -96.1909 +137.034 -207.719 -92.2812 +135.84 -207.505 -93.013 +136.276 -207.705 -93.051 +136.172 -207.374 -93.0996 +137.095 -207.036 -93.0407 +137.023 -207.107 -92.7982 +137.027 -207.428 -92.9328 +135.855 -207.228 -93.1046 +136.38 -206.47 -93.1114 +136.7 -206.109 -93.3739 +136.544 -206.133 -93.7668 +136.468 -206.11 -94.6915 +137.321 -205.514 -95.1544 +137.822 -205.871 -95.7198 +135.96 -206.804 -93.3483 +135.952 -206.961 -93.337 +136.633 -205.889 -94.5654 +136.308 -207.029 -93.2768 +136.388 -206.89 -93.1701 +136.188 -206.684 -93.2177 +136.395 -207.056 -93.1959 +137.069 -207.561 -94.4938 +137.258 -206.911 -94.2208 +137.146 -207.616 -93.5942 +136.138 -208.495 -92.9448 +135.801 -208.604 -93.0169 +136.133 -209.889 -93.9972 +136.301 -211.47 -94.588 +136.206 -211.35 -94.3301 +136.111 -211.484 -94.0909 +135.441 -211.928 -93.3616 +136.775 -214.141 -94.2078 +136.639 -214.235 -94.1084 +136.049 -212.165 -93.4646 +136.259 -211.869 -93.5335 +136.118 -211.968 -93.4389 +136.311 -212.367 -93.7142 +136.394 -212.59 -93.7216 +136.171 -211.837 -93.4405 +137.895 -212.003 -93.4621 +137.839 -211.775 -93.5395 +137.461 -212.103 -93.5079 +137.702 -212.044 -93.5195 +137.057 -211.016 -94.3491 +137.051 -211.101 -94.3724 +137.094 -209.272 -93.5865 +137.372 -209.066 -93.855 +137.373 -206.203 -94.0033 +137.52 -205.791 -94.0954 +137.281 -208.326 -93.2618 +136.651 -209.219 -93.5179 +136.888 -206.3 -92.5678 +137.065 -206.225 -92.6261 +136.419 -207.714 -92.9547 +136.396 -207.465 -93.0064 +136.953 -206.128 -92.743 +136.698 -206.399 -92.5447 +137.251 -206.044 -92.7786 +136.453 -208.496 -92.6645 +136.439 -208.596 -92.7371 +136.648 -208.683 -92.6067 +135.212 -209.59 -93.4072 +135.223 -209.41 -93.6671 +137.147 -208.256 -92.1922 +136.822 -208.127 -92.0826 +136.827 -208.334 -92.2345 +136.684 -208.296 -92.2545 +132.805 -219.04 -100.615 +136.379 -206.032 -99.1926 +136.034 -206.8 -99.5717 +138.861 -223.053 -101.785 +138.857 -222.65 -101.714 +138.947 -222.941 -101.773 +136.462 -202.173 -92.7701 +136.661 -202.44 -92.71 +137.351 -202.134 -92.496 +137.286 -202.16 -92.4773 +137.367 -202.201 -92.5624 +136.811 -202.306 -92.591 +137.18 -202.413 -92.5219 +136.714 -207.929 -92.0602 +137.496 -205.529 -94.5791 +137.167 -205.339 -94.7868 +136.959 -206.517 -92.4448 +135.909 -206.752 -93.5854 +136.055 -206.553 -93.5889 +135.254 -209.371 -93.5995 +136.181 -206.493 -94.2494 +136.281 -206.328 -94.0583 +135.596 -204.143 -96.5611 +135.911 -206.797 -93.4196 +136.529 -206.289 -93.076 +137.422 -206.082 -92.8144 +137.266 -206.161 -93.8644 +136.148 -206.467 -93.4737 +136.025 -206.613 -93.3147 +136.705 -205.889 -94.3252 +137.106 -205.656 -94.4576 +136.67 -206.034 -94.1285 +137.016 -206.055 -93.688 +137.193 -206.04 -93.387 +137.463 -206.105 -94.0501 +136.113 -206.604 -93.2458 +137.891 -205.916 -93.7714 +138.085 -206.153 -93.812 +137.326 -206.262 -93.8923 +137.293 -206.029 -94.0444 +137.124 -207.44 -94.6409 +137.164 -207.255 -94.698 +137.772 -205.748 -94.1394 +137.353 -205.752 -94.26 +137.558 -206.271 -94.0851 +137.717 -206.198 -93.9792 +137.673 -205.981 -93.9297 +137.384 -206.395 -93.8637 +137.663 -205.695 -94.1432 +137.094 -206.069 -92.8254 +136.957 -206.794 -92.2343 +136.968 -207.034 -92.319 +136.796 -206.624 -92.2245 +137.151 -206.531 -92.634 +137.223 -206.123 -92.711 +137.066 -206.127 -92.6848 +137.481 -206.182 -92.7585 +136.634 -207.012 -92.3473 +137.447 -206.353 -92.7538 +137.526 -206.309 -92.9688 +137.435 -206.418 -93.6215 +137.502 -206.196 -92.9145 +137.337 -206.658 -93.8668 +137.541 -206.361 -92.8459 +138.147 -206.171 -93.8595 +138.064 -206.001 -93.8355 +137.943 -205.893 -93.8668 +137.773 -205.805 -93.8733 +136.901 -205.578 -94.71 +137.696 -206.423 -94.1241 +138.147 -206.407 -94.3883 +137.844 -205.966 -93.7709 +137.892 -206.405 -94.0024 +138.102 -205.884 -94.4135 +138.001 -206.389 -94.0659 +138.168 -206.034 -93.9429 +138.354 -206.263 -94.889 +137.919 -206.629 -94.7909 +138.11 -205.853 -95.3156 +138.407 -206.207 -95.2068 +137.44 -206.45 -94.0121 +138.193 -205.977 -94.2154 +137.834 -208.134 -94.0783 +137.165 -207.841 -94.4016 +137.584 -208.105 -94.0556 +136.894 -205.675 -95.1896 +136.934 -205.758 -95.5419 +138.544 -206.94 -94.5592 +138.496 -207.036 -94.5326 +138.086 -206.579 -94.7916 +137.624 -206.619 -94.4394 +137.005 -204.522 -95.9728 +137.11 -204.662 -96.0759 +137.107 -205.436 -94.687 +137.322 -205.494 -94.5297 +136.319 -205.11 -96.2364 +136.35 -204.464 -96.3022 +136.364 -204.788 -96.2375 +136.87 -205.704 -94.4863 +137.649 -205.599 -95.0676 +136.97 -205.844 -95.9915 +137.836 -206.231 -96.1573 +137.344 -206.848 -94.8944 +137.562 -206.547 -94.2047 +137.513 -206.9 -95.0477 +137.405 -206.861 -95.0087 +137.358 -205.82 -95.9464 +138.067 -205.194 -96.6917 +137.829 -205.036 -96.2583 +137.001 -204.804 -96.0371 +137.185 -205.002 -96.1014 +137.044 -205.596 -96.2088 +136.514 -205.508 -96.203 +137.987 -205.43 -96.3693 +138.419 -206.456 -95.4154 +136.54 -203.203 -96.3038 +138.527 -206.589 -94.9464 +138.452 -207.679 -94.9848 +136.65 -205.063 -96.1357 +136.756 -205.312 -96.1943 +139.46 -203.175 -97.4928 +137.336 -202.146 -92.7007 +137.051 -202.149 -92.5905 +136.816 -202.287 -92.7995 +136.916 -202.445 -92.6215 +137.255 -202.331 -92.4865 +137.057 -202.384 -92.4836 +136.594 -202.282 -92.6715 +138.561 -202.122 -99.9442 +135.348 -203.47 -99.638 +135.767 -203.481 -99.6412 +136.079 -202.887 -99.6899 +137.437 -202.332 -99.5801 +137.341 -203.005 -99.6244 +136.864 -202.997 -99.6823 +135.807 -202.923 -99.6814 +135.543 -202.577 -99.5983 +136.662 -202.602 -99.7205 +137.077 -203.191 -99.7067 +135.71 -203.298 -99.6721 +137.143 -202.49 -99.6797 +136.238 -203.317 -99.6961 +135.867 -204.06 -99.6872 +136.136 -203.99 -99.7151 +136.182 -204.189 -99.7879 +138.123 -202.256 -99.5535 +138.076 -202.76 -99.5052 +138.064 -203.68 -99.3608 +137.81 -203.629 -99.5264 +136.814 -203.124 -99.6912 +138.961 -202.463 -97.7575 +138.853 -202.18 -97.7871 +134.736 -202.18 -99.5244 +134.431 -202.6 -99.5135 +134.42 -202.127 -99.5206 +134.83 -202.517 -99.5574 +135.318 -202.76 -99.565 +135.067 -202.436 -99.5792 +135.237 -203.065 -99.5784 +135.28 -202.27 -99.6124 +134.786 -202.878 -99.5273 +133.84 -205.717 -99.664 +134.149 -206.067 -99.7418 +134.613 -205.627 -99.5807 +134.581 -205.399 -99.6429 +134.327 -205.393 -99.6411 +134.084 -206.26 -99.7874 +134.706 -206.093 -99.628 +133.95 -206.685 -99.8953 +133.998 -205.471 -99.83 +133.831 -206.12 -99.7244 +135.571 -205.146 -99.5969 +135.719 -205.24 -99.6218 +134.923 -206.155 -99.6131 +134.106 -205.684 -99.7077 +134.42 -205.682 -99.5989 +134.766 -205.964 -99.6039 +135.413 -206.893 -99.6735 +135.072 -207.139 -99.6842 +135.141 -205.706 -99.5686 +134.853 -205.192 -99.2768 +134.8 -205.188 -99.3523 +134.933 -205.04 -99.4487 +134.196 -205.513 -99.6673 +134.698 -205.264 -99.6984 +134.82 -205.107 -99.7181 +134.701 -205.455 -99.5468 +134.657 -205.369 -99.604 +135.243 -205.651 -99.5217 +135.416 -204.774 -99.5849 +134.193 -205.413 -99.6549 +134.675 -205.147 -99.771 +136.213 -205.348 -99.6445 +134.904 -204.664 -99.5449 +135.485 -205.697 -99.5568 +134.99 -204.938 -99.5139 +134.472 -203.473 -99.5867 +134.045 -204.844 -99.6429 +134.546 -204.801 -99.5717 +135.076 -204.98 -99.4306 +135.107 -205.101 -99.3891 +135.008 -205.237 -99.3374 +133.941 -204.903 -99.7666 +134.068 -204.959 -99.6337 +135.007 -204.212 -99.5669 +134.326 -204.478 -99.562 +134.425 -204.255 -99.5587 +136.372 -203.8 -97.0015 +136.133 -203.62 -96.6372 +136.386 -203.329 -96.9054 +134.634 -203.594 -99.5606 +136.985 -203.77 -99.7345 +134.809 -203.103 -99.5399 +135.381 -202.897 -99.5816 +134.794 -203.759 -99.5317 +134.15 -202.89 -99.5736 +134.45 -203.041 -99.547 +134.84 -203.528 -99.5417 +135.977 -204.888 -99.6645 +136.961 -206.187 -95.9635 +136.417 -204.404 -99.6956 +137.83 -204.13 -99.5517 +137.947 -204.143 -99.4939 +138.503 -204.245 -99.1725 +137.667 -204.445 -99.6043 +137.617 -203.785 -99.5847 +137.21 -203.692 -99.719 +138.262 -204.18 -99.2809 +138.135 -204.189 -99.349 +136.432 -205.19 -99.6347 +136.297 -204.639 -99.5875 +136.405 -204.073 -99.7388 +136.95 -205.13 -99.6771 +136.719 -205.522 -99.5944 +139.052 -202.408 -100.24 +138.943 -202.214 -100.314 +138.993 -202.467 -100.23 +139.361 -202.954 -100.041 +139.089 -203.139 -100.022 +139.232 -203.246 -100.019 +138.756 -203.804 -99.7733 +138.305 -204.061 -99.4517 +138.588 -204.03 -99.7013 +137.131 -204.157 -99.7351 +138.38 -205.507 -99.6377 +138.283 -205.29 -99.5995 +138.447 -205.081 -99.6682 +136.634 -203.779 -99.75 +136.487 -204.216 -99.7299 +136.82 -204.593 -99.685 +137.378 -203.553 -97.3517 +137.549 -203.355 -97.6657 +136.184 -204.515 -99.9385 +136.11 -204.744 -99.7423 +138.651 -205.322 -100.468 +139.403 -205.157 -99.6671 +135.884 -205.725 -99.5805 +137.617 -205.237 -99.609 +137.458 -205.106 -99.6577 +137.807 -205.382 -99.1885 +137.797 -204.894 -97.8203 +136.18 -205.456 -96.4977 +136.191 -205.434 -96.3212 +136.57 -206.172 -96.7593 +136.693 -205.637 -97.517 +136.345 -205.722 -96.5527 +135.695 -205.919 -99.577 +135.776 -206.601 -99.6569 +136.068 -204.504 -99.9042 +133.713 -206.818 -99.5661 +136.895 -210.108 -99.4505 +136.898 -210.458 -98.3483 +136.986 -210.235 -98.9021 +138.582 -205.621 -100.601 +138.775 -206.265 -100.303 +139.242 -205.561 -100.851 +139.139 -206.438 -100.908 +139.148 -206.83 -100.84 +138.962 -206.607 -100.872 +139.423 -205.879 -100.887 +138.904 -205.515 -100.789 +138.648 -205.501 -100.677 +138.729 -205.732 -100.756 +137.775 -209.956 -100.578 +138.798 -206.373 -100.685 +138.959 -205.861 -100.844 +139.031 -206.062 -100.885 +138.83 -206.225 -100.83 +139.439 -207.094 -100.257 +139.419 -207.03 -100.03 +138.519 -205.385 -100.28 +138.885 -206.46 -100.41 +138.596 -204.758 -99.1161 +138.993 -204.999 -99.5679 +138.785 -204.692 -98.5095 +138.663 -205.992 -99.7805 +138.405 -204.557 -99.1969 +139.363 -202.431 -100.116 +138.449 -203.145 -99.6306 +139.087 -202.792 -100.144 +138.317 -204.814 -99.4444 +138.498 -204.788 -99.3457 +139.395 -203.363 -99.1975 +139.298 -203.718 -99.6145 +139.167 -203.738 -99.7372 +139.292 -202.227 -100.684 +139.294 -202.422 -100.525 +139.144 -202.318 -100.418 +139.279 -203.04 -100.104 +139.213 -202.331 -100.577 +139.346 -202.579 -100.01 +139.177 -202.754 -100.143 +139.45 -202.727 -99.1749 +139.399 -203.462 -99.6262 +138.836 -202.224 -98.1266 +138.643 -202.789 -97.9388 +139.003 -203.984 -99.0921 +137.93 -203.859 -97.0974 +137.79 -203.826 -97.7001 +137.58 -203.725 -96.9516 +138.021 -203.875 -98.2699 +137.943 -203.615 -97.9048 +138.152 -203.337 -99.4101 +138.476 -204.192 -99.2828 +138.494 -203.546 -99.6134 +138.164 -203.943 -99.3456 +138.053 -205.258 -99.4626 +138.182 -205.425 -99.3658 +138.299 -205.175 -98.7597 +139.209 -205.182 -99.3632 +138.235 -205.007 -99.4937 +138.449 -205.245 -99.8402 +138.581 -205.036 -99.8719 +138.601 -205.974 -99.6874 +139.407 -205.399 -98.9075 +138.146 -205.264 -99.298 +138.145 -205.16 -99.5206 +138.443 -205.925 -99.5809 +137.964 -205.227 -99.4567 +138.627 -206.428 -99.4093 +138.787 -206.422 -99.6465 +139.131 -206.618 -99.2086 +138.354 -205.914 -99.4335 +138.859 -206.553 -99.6831 +138.523 -206.232 -99.4968 +139.232 -206.838 -100.149 +139.015 -204.94 -98.9963 +139.313 -204.488 -98.0324 +139.199 -204.763 -98.3027 +139.416 -204.693 -98.2755 +138.84 -204.633 -98.2425 +138.676 -206.49 -97.4616 +138.819 -206.276 -97.8059 +138.794 -205.582 -98.0265 +139.05 -204.8 -98.4649 +138.93 -206.042 -97.9781 +139.29 -206.175 -98.4874 +139.23 -206.021 -98.2127 +139.215 -206.154 -98.0898 +139.354 -205.221 -98.4287 +139.332 -206.271 -98.1616 +139.208 -205.919 -98.2167 +138.811 -204.388 -97.9577 +139.014 -205.719 -98.3601 +139.482 -204.857 -98.3212 +138.903 -205.588 -98.2709 +139.288 -206.073 -98.3411 +139.039 -206.102 -98.0717 +138.926 -206.712 -97.4313 +138.603 -206.13 -97.2548 +138.727 -205.695 -97.6541 +138.272 -206.277 -96.8781 +138.01 -206.26 -96.6119 +138.661 -206.047 -97.3232 +138.722 -205.566 -97.6786 +138.828 -205.753 -97.9547 +138.721 -205.202 -97.3274 +138.56 -205.793 -96.7338 +137.895 -204.436 -97.5953 +138.399 -205.107 -97.9139 +138.745 -205.404 -97.3755 +139.21 -204.319 -97.8149 +139.15 -204.635 -98.0869 +138.629 -202.894 -97.884 +137.915 -203.325 -98.0303 +138.678 -204.319 -98.711 +139.34 -203.266 -97.4477 +138.699 -202.948 -97.8249 +139.276 -203.847 -97.6288 +139.076 -202.72 -97.7916 +138.933 -202.804 -97.7871 +139.227 -203.493 -97.4511 +139.098 -203.617 -97.514 +137.369 -203.534 -96.8502 +137.247 -203.173 -97.2365 +139.407 -202.674 -97.5942 +139.258 -202.347 -97.8998 +138.747 -204.61 -98.3903 +137.947 -204.161 -98.0328 +137.742 -204.135 -97.999 +137.943 -204.007 -97.8069 +138.015 -204.286 -97.292 +137.792 -203.161 -97.9414 +138.627 -202.413 -97.9058 +139.493 -202.203 -97.765 +137.328 -202.604 -97.7831 +139.271 -202.242 -97.8626 +139.017 -202.21 -97.7951 +137.101 -202.538 -97.4288 +137.97 -204.13 -96.9317 +138.02 -204.54 -96.9315 +138.03 -204.689 -96.9473 +138.226 -206.991 -96.3058 +138.298 -204.807 -97.3072 +138.059 -204.514 -97.3519 +138.076 -204.542 -97.1868 +138.602 -205.013 -97.2229 +138.191 -205.32 -96.6563 +138.058 -205.363 -96.5042 +138.579 -205.213 -97.0254 +138.3 -205.446 -96.6355 +139.044 -206.857 -97.1539 +139.238 -206.857 -97.3898 +138.737 -206.589 -97.4927 +138.662 -206.733 -97.3174 +138.625 -206.556 -97.3779 +138.469 -205.714 -96.5839 +138.633 -205.902 -97.1171 +138.326 -206.213 -96.9391 +138.572 -206.007 -97.0537 +138.313 -205.127 -97.1052 +138.469 -205.258 -96.832 +138.042 -204.96 -96.7929 +138.359 -206.523 -97.2005 +138.617 -206.889 -97.2002 +138.081 -206.553 -96.6876 +138.486 -206.701 -97.3013 +137.907 -206.344 -96.5195 +138.215 -205.793 -96.4611 +137.831 -204.801 -96.4311 +138.473 -205.554 -96.7075 +137.795 -205.8 -96.4068 +137.967 -205.641 -96.3321 +138.237 -205.658 -96.4202 +137.235 -205.236 -96.1765 +137.639 -205.223 -96.145 +136.8 -206.362 -95.405 +136.367 -205.723 -96.3383 +136.56 -205.779 -96.2115 +137.293 -205.772 -96.1275 +137.781 -205.581 -96.2314 +137.597 -205.934 -96.2205 +138.136 -206.817 -97.0507 +138.071 -206.807 -96.9254 +138.046 -206.894 -96.7464 +137.608 -205.866 -96.2865 +137.987 -206.517 -96.3744 +136.454 -205.242 -96.2009 +136.207 -205.27 -96.2411 +135.953 -204.781 -96.755 +135.68 -204.645 -96.4931 +136.686 -206.037 -96.3073 +136.487 -204.988 -96.1616 +137.03 -205.439 -96.2089 +137.757 -205.451 -96.1536 +136.349 -205.518 -96.2262 +135.939 -205.039 -96.363 +135.816 -204.816 -96.4351 +136.738 -204.835 -96.0595 +136.583 -204.529 -96.1491 +137.397 -204.857 -96.1248 +135.993 -204.773 -96.362 +136.029 -205.101 -96.2898 +136.236 -204.395 -96.3417 +137.783 -204.945 -96.2173 +137.611 -204.741 -96.4621 +137.568 -204.963 -96.1711 +137.535 -205.528 -96.1601 +137.724 -205.071 -96.1693 +137.443 -204.484 -96.4466 +136.803 -204.157 -96.2268 +137.94 -204.703 -96.5958 +137.93 -204.127 -96.5542 +137.271 -204.23 -96.4178 +137.559 -203.74 -96.6651 +136.895 -204.634 -96.0173 +137.11 -203.588 -96.2633 +137.247 -203.441 -96.3851 +137.237 -203.603 -96.5531 +136.223 -203.466 -96.3882 +137.317 -203.465 -96.6847 +137.468 -203.676 -97.12 +137.062 -203.178 -96.3574 +136.858 -202.876 -97.3586 +137.251 -203.257 -96.7083 +136.449 -203.164 -96.3121 +136.865 -203.487 -96.3099 +136.059 -203.886 -96.3954 +136.244 -203.201 -96.4398 +136.879 -203.019 -96.4263 +136.89 -202.612 -97.298 +136.579 -204.162 -96.2614 +136.312 -204.126 -96.3231 +136.697 -204.199 -96.2094 +136.91 -204.309 -96.1039 +135.584 -204.419 -96.6046 +135.861 -204.918 -96.5426 +135.992 -204.234 -96.246 +135.873 -204.676 -96.3257 +135.936 -203.834 -96.5248 +135.802 -204.512 -96.2958 +136.442 -202.911 -96.5391 +135.71 -204.04 -96.5028 +136.1 -203.653 -96.5071 +136.271 -203.053 -96.4989 +135.658 -204.081 -96.6208 +136.579 -202.893 -96.4674 +136.426 -202.951 -96.3981 +134.877 -207.565 -99.7243 +136.476 -204.44 -97.1414 +137.331 -203.225 -97.3637 +137.331 -202.885 -97.5064 +137.836 -203.867 -96.724 +137.873 -203.818 -96.9136 +137.01 -202.778 -97.2599 +137.88 -203.872 -97.4231 +137.928 -203.863 -97.8465 +139.014 -206.916 -97.0903 +138.855 -207.111 -97.075 +138.172 -206.924 -97.0701 +137.594 -203.058 -97.7258 +137.593 -203.578 -97.602 +137.781 -203.266 -97.8868 +137.66 -203.061 -97.8398 +137.306 -202.574 -97.6106 +137.509 -202.803 -97.7949 +137.262 -202.654 -97.5406 +137.144 -202.943 -97.3167 +137.152 -203.087 -96.5893 +134.996 -207.817 -99.7151 +134.748 -207.925 -99.7347 +135.067 -209.471 -97.8842 +134.093 -209.825 -97.8666 +134.05 -210.128 -97.5692 +133.973 -210.065 -97.6117 +133.874 -210.442 -97.422 +134.311 -209.932 -97.6453 +133.807 -211.133 -97.8491 +133.872 -211.4 -98.1685 +133.959 -209.508 -98.4817 +133.857 -209.904 -97.9105 +134.225 -210.775 -97.5086 +135.142 -211.954 -94.5956 +133.438 -210.383 -98.7979 +133.64 -210.884 -98.2346 +135.178 -214.048 -97.9428 +134.337 -211.027 -97.3851 +134.436 -211.643 -94.7244 +134.343 -211.819 -94.6452 +133.842 -211.258 -98.6405 +133.55 -212.169 -100.425 +133.46 -212.019 -100.247 +135.286 -211.678 -98.4187 +135.332 -211.417 -97.5424 +133.56 -211.486 -100.167 +133.767 -211.382 -100.167 +135.477 -211.316 -98.8493 +135.369 -211.728 -98.1826 +135.122 -211.338 -96.6277 +135.035 -212.952 -95.6466 +135.156 -211.264 -96.5944 +137.431 -212 -96.029 +133.625 -210.777 -99.0498 +138.187 -209.129 -96.2795 +134.44 -211.846 -97.6159 +134.53 -211.758 -97.432 +134.207 -211.777 -97.6146 +134.878 -212.594 -100.373 +134.859 -212.038 -100.456 +134.712 -212.335 -100.418 +134.385 -211.875 -98.1112 +136.357 -212.581 -98.8555 +136.173 -212.699 -99.0785 +136.329 -212.493 -98.9142 +136.211 -212.546 -98.9874 +135.919 -212.953 -100.041 +136.397 -213.183 -100.108 +135.847 -213.336 -99.5142 +135.542 -211.214 -97.8554 +136.446 -212.525 -98.8072 +135.462 -214.486 -100.211 +136.107 -214.263 -100.418 +136.472 -212.693 -98.8258 +138.505 -212.945 -100.57 +136.508 -212.61 -98.8449 +135.383 -214.017 -98.131 +134.125 -210.82 -99.7143 +134.728 -211.581 -98.7577 +136.501 -210.219 -97.9675 +137.086 -210.167 -98.1052 +136.642 -210.621 -98.2963 +136.378 -210.77 -98.4291 +136.732 -210.589 -98.4271 +136.562 -210.475 -98.9632 +137.262 -210.141 -99.0694 +137.835 -210.148 -98.9313 +137.443 -210.028 -99.533 +137.361 -210.07 -98.3034 +136.943 -210.4 -98.2279 +135.785 -211.413 -97.966 +135.819 -211.553 -98.1255 +136.75 -209.831 -97.8027 +136.351 -209.899 -97.7388 +136.945 -209.778 -97.7128 +136.113 -211.395 -98.1452 +136.1 -211.2 -98.227 +136.028 -211.245 -98.1084 +137.205 -210.006 -98.036 +137.537 -209.887 -97.8366 +137.82 -209.941 -97.826 +137.449 -209.91 -97.9816 +136.988 -209.919 -97.8929 +137.27 -210.051 -98.1439 +137.881 -209.928 -97.5325 +137.401 -209.807 -97.1727 +137.145 -209.683 -97.3483 +137.189 -209.834 -97.5203 +138.466 -209.074 -96.6346 +138.287 -209.086 -96.423 +137.59 -209.796 -96.9129 +137.111 -209.865 -97.7632 +133.523 -209.862 -98.6408 +136.242 -209.573 -97.6018 +136.69 -209.637 -97.697 +138.524 -207.309 -96.8053 +138.231 -207.139 -96.8382 +137.774 -209.783 -96.8083 +137.389 -211.704 -95.8898 +137.492 -211.657 -95.7162 +137.573 -209.631 -96.6658 +137.681 -209.744 -96.7086 +138.448 -209.025 -96.5515 +138.378 -209.35 -96.8117 +138.423 -209.959 -96.8211 +137.865 -209.672 -96.5433 +137.75 -209.57 -96.3742 +138.121 -206.463 -95.9203 +138.424 -208.018 -95.9607 +137.477 -209.214 -95.834 +137.076 -209.137 -95.3119 +138.461 -208.036 -96.2718 +138.598 -208.327 -95.9937 +138.769 -208.26 -96.3146 +138.978 -207.207 -97.0129 +138.457 -208.115 -95.7244 +138.686 -208.321 -96.1886 +138.633 -207.841 -96.5207 +138.8 -207.31 -96.7322 +138.486 -207.76 -96.5261 +138.853 -208.153 -96.439 +138.547 -208.088 -96.3445 +139.342 -207.82 -97.0184 +139.389 -207.591 -97.1529 +138.325 -207.351 -96.694 +138.699 -207.186 -96.8951 +138.405 -207.037 -97.0458 +138.178 -207.122 -96.6071 +138.251 -206.797 -97.1709 +139.152 -207.466 -96.9312 +139.229 -207.45 -97.0596 +139.321 -208.405 -96.9709 +139.205 -207.733 -96.912 +138.899 -207.278 -96.9287 +138.921 -207.363 -96.842 +138.891 -207.411 -96.5443 +139.188 -206.974 -97.1227 +139.51 -207.598 -97.2072 +139.501 -207.871 -97.056 +139.286 -207.415 -97.1064 +139.081 -207.495 -96.6595 +139.057 -208.335 -96.8203 +138.953 -208.267 -96.6851 +139.053 -207.792 -96.6988 +139.143 -207.589 -96.8734 +139.163 -207.274 -97.1179 +138.65 -208.722 -96.3427 +139.413 -208.04 -97.0395 +139.302 -207.695 -97.0222 +139.385 -206.969 -97.2068 +138.975 -206.534 -97.6179 +139.518 -207.18 -97.1809 +138.956 -207.509 -96.4643 +139.395 -206.879 -97.5069 +139.357 -208.637 -97.1085 +139.38 -208.22 -97.0587 +139.454 -208.517 -97.1763 +139.492 -206.848 -98.1183 +138.749 -209.24 -96.498 +138.704 -208.977 -96.6478 +139.252 -208.695 -96.8668 +139.293 -208.824 -97.0682 +139.448 -208.969 -97.295 +139.262 -209.15 -97.149 +139.469 -208.777 -97.2536 +139.121 -209.074 -96.7918 +139.184 -209.491 -97.0678 +139.27 -209.758 -97.5342 +138.988 -209.359 -96.7418 +138.846 -209.446 -96.6367 +138.935 -208.854 -96.7879 +139.17 -208.818 -96.7336 +138.16 -209.539 -100.631 +137.524 -209.631 -100.588 +138.9 -208.421 -96.6413 +139.006 -208.667 -96.7259 +139.163 -209.209 -96.8343 +138.452 -208.905 -96.2404 +138.618 -209.549 -96.613 +138.83 -209.732 -96.8453 +138.577 -209.887 -96.791 +138.575 -209.662 -96.6706 +138.695 -209.57 -96.6238 +138.486 -208.887 -95.2787 +138.595 -208.811 -95.2887 +138.429 -209.504 -96.7776 +138.627 -208.857 -96.6267 +138.758 -209.908 -97.5386 +138.108 -209.544 -96.7511 +138.291 -209.727 -96.879 +138.21 -209.592 -96.8269 +138.639 -208.456 -95.6811 +138.576 -208.392 -95.7158 +138.764 -208.899 -95.3781 +137.52 -209.588 -95.6925 +137.728 -209.547 -95.9396 +137.697 -209.682 -95.7345 +137.641 -213.337 -95.1939 +139.492 -209.471 -98.7965 +139.014 -209.948 -97.6463 +139.129 -209.932 -97.6771 +138.736 -210.13 -97.9308 +138.596 -210.098 -97.7609 +138.392 -210.179 -98.0094 +139.453 -209.574 -97.4005 +139.395 -209.678 -97.708 +138.52 -210.235 -98.284 +139.353 -209.765 -97.9379 +138.383 -210.252 -98.2303 +138.866 -209.984 -97.7479 +137.93 -210.221 -98.2469 +139.387 -209.255 -99.4404 +138.45 -210.076 -97.6486 +138.094 -210.059 -97.8396 +138.263 -210.05 -97.6752 +138.964 -209.451 -99.4575 +139.41 -208.395 -100.509 +139.351 -209.337 -97.2626 +139.452 -206.656 -98.311 +138.089 -209.41 -100.113 +139.221 -206.847 -100.402 +139.333 -208.508 -100.872 +139.445 -208.353 -100.833 +139.318 -208.373 -100.686 +138.998 -206.583 -100.891 +138.185 -209.833 -99.3133 +139.02 -211.701 -100.606 +139.05 -212.469 -100.594 +139.439 -212.538 -100.619 +137.438 -213.516 -100.537 +137.121 -213.084 -100.533 +139.134 -211.148 -100.614 +139.147 -213.878 -100.56 +137.652 -212.767 -100.547 +138.359 -212.572 -100.587 +138.697 -211.246 -100.593 +138.243 -211.102 -100.582 +138.745 -212.652 -100.586 +137.321 -213.946 -100.523 +139.024 -211.059 -100.619 +137.209 -211.84 -100.502 +136.852 -212.654 -100.495 +138.472 -210.35 -100.636 +139.379 -210.922 -100.661 +138.143 -210.734 -100.585 +137.858 -211.243 -100.576 +139.277 -210.56 -100.688 +139.126 -210.203 -100.691 +136.609 -213.413 -100.471 +135.927 -213.698 -99.6903 +137.769 -210.922 -100.578 +137.792 -210.449 -100.571 +138.518 -209.081 -100.583 +138.654 -208.936 -100.528 +138.656 -209.006 -100.344 +139.508 -209.319 -100.797 +139.324 -208.768 -100.839 +138.768 -209.477 -100.693 +139.046 -208.999 -100.761 +138.645 -209.11 -100.693 +137.226 -209.683 -100.433 +137.085 -209.863 -100.144 +137.72 -209.439 -100.511 +138.927 -208.853 -100.755 +138.743 -208.908 -100.692 +139.504 -207.272 -100.874 +139.47 -207.144 -100.901 +139.397 -207.229 -100.571 +139.417 -207.184 -100.805 +135.398 -211.53 -100.5 +136.503 -210.933 -100.544 +139.272 -206.799 -100.912 +136.847 -209.887 -100.223 +136.907 -209.999 -100.52 +137.117 -209.811 -100.495 +136.751 -210.08 -99.8059 +134.076 -206.746 -99.8322 +134.002 -209.261 -98.8186 +135.069 -207.955 -99.6005 +135.744 -207.984 -99.058 +135.633 -207.789 -99.4402 +136.186 -207.366 -99.4568 +136.076 -207.368 -99.6956 +135.739 -206.975 -99.6726 +136.196 -207.471 -99.1991 +134.388 -207.984 -99.7078 +136.138 -207.434 -99.6473 +135.478 -207.628 -99.6789 +134.446 -207.123 -99.7365 +134.456 -207.391 -99.754 +133.866 -207.03 -99.8525 +134.107 -208.133 -99.5881 +133.687 -208.303 -99.3077 +134.446 -208.219 -99.6062 +136.42 -210.092 -100.175 +136.56 -210.076 -100.352 +135.391 -207.477 -99.6808 +135.445 -207.261 -99.6707 +135.028 -206.733 -99.6655 +133.693 -207.744 -99.3396 +133.637 -208.014 -99.3058 +134.352 -207.11 -99.7587 +134.098 -207.227 -99.9696 +134.049 -206.875 -99.8603 +133.765 -206.83 -99.821 +133.705 -207.242 -99.3656 +133.861 -207.206 -99.7936 +133.686 -207.015 -99.2861 +133.855 -207.507 -99.8569 +133.879 -208.065 -99.5465 +133.581 -208.85 -99.3304 +133.492 -208.988 -99.3845 +133.832 -208.282 -99.3809 +133.718 -208.683 -99.331 +133.861 -208.962 -99.2598 +134.412 -208.543 -99.3441 +133.477 -209.108 -99.3622 +133.818 -208.135 -99.4009 +133.321 -210.198 -99 +133.888 -210.877 -100.108 +133.592 -209.384 -99.0515 +133.341 -209.863 -99.0152 +133.391 -209.62 -99.071 +133.94 -208.693 -99.3911 +133.671 -207.462 -99.4081 +133.712 -206.857 -99.3558 +135.975 -210.277 -100.352 +136.144 -210.346 -100.512 +133.64 -211.195 -100.157 +133.925 -211.031 -100.148 +133.791 -211.768 -100.381 +133.449 -210.59 -99.0639 +134.445 -210.963 -100.283 +134.392 -210.817 -100.015 +133.808 -210.725 -99.7488 +133.388 -210.645 -99.7461 +133.215 -213.006 -99.9989 +133.184 -212.811 -100.142 +133.352 -212.232 -100.281 +133.187 -211.959 -100.25 +135.201 -211.407 -100.431 +135.473 -211.327 -100.499 +133.534 -212.433 -100.367 +133.614 -212.672 -100.409 +133.315 -212.446 -100.214 +133.686 -212.197 -100.479 +133.227 -212.182 -100.321 +134.625 -212.706 -100.354 +133.325 -212.938 -100.22 +133.533 -212.867 -100.351 +133.517 -213.282 -100.111 +133.615 -213.528 -100.161 +133.964 -213.407 -100.279 +133.051 -212.795 -100.042 +133.436 -215.18 -97.4782 +133.558 -214.991 -97.6329 +134.249 -211.144 -100.316 +133.642 -210.674 -99.4436 +133.613 -210.718 -99.8835 +133.627 -210.901 -100.126 +133.441 -210.821 -100.126 +133.674 -210.783 -100.03 +133.018 -213.292 -99.5691 +133.456 -214.092 -100.089 +133.257 -214.02 -99.9155 +133.081 -213.558 -99.6118 +133.291 -213.47 -99.7107 +133.254 -213.212 -99.7725 +136.325 -212.844 -100.257 +135.781 -210.626 -99.6096 +134.557 -211.546 -100.359 +134.111 -211.855 -100.419 +135.88 -212.548 -99.816 +136.184 -212.319 -99.2939 +135.714 -212.28 -99.9818 +135.926 -212.624 -99.4761 +136.006 -212.458 -100.187 +135.713 -212.636 -100.096 +136.13 -212.741 -100.215 +135.891 -214.399 -98.2492 +135.625 -214.365 -97.8706 +135.48 -214.486 -99.1995 +136.713 -215.455 -100.475 +136.546 -214.238 -100.493 +136.218 -210.234 -100.423 +136.405 -210.283 -100.565 +135.393 -210.536 -100.194 +137.573 -211.559 -100.553 +135.947 -212.224 -100.281 +136.501 -212.41 -100 +136.585 -212.388 -100.42 +136.451 -212.508 -100.263 +136.359 -212.497 -100.061 +136.298 -212.493 -100.267 +136.516 -212.357 -100.322 +136.37 -212.301 -100.324 +136.193 -212.521 -99.908 +135.984 -212.292 -100.116 +136.22 -212.333 -100.091 +135.914 -212.234 -99.9245 +136.292 -213.61 -100.153 +138.055 -213.835 -100.548 +136.936 -212.317 -100.47 +137.819 -211.763 -100.577 +137.444 -212.443 -100.541 +136.779 -211.647 -100.48 +136.605 -212.247 -100.449 +136.438 -213.025 -100.393 +134.985 -210.718 -100.14 +136.456 -211.671 -100.451 +136.285 -212.221 -100.401 +136.687 -212.427 -100.465 +135.798 -211.762 -100.459 +136.097 -212.242 -100.34 +136.024 -212.318 -100.233 +135.412 -212.782 -100.315 +135.9 -211.946 -100.441 +136.243 -212.319 -100.279 +135.103 -212.123 -100.48 +135.065 -217.224 -100.532 +134.067 -212.476 -100.454 +135.237 -212.507 -100.451 +135.513 -214.098 -99.7681 +134.49 -211.997 -100.457 +135.285 -212.103 -100.492 +134.433 -212.193 -100.471 +135.562 -212.084 -100.47 +134.786 -211.688 -100.367 +134.492 -211.216 -100.341 +136.718 -211.356 -100.527 +137.109 -211.507 -100.518 +135.37 -212.532 -100.449 +134.874 -212.179 -100.455 +134.849 -211.172 -100.373 +135.248 -210.992 -100.416 +135.787 -210.737 -100.521 +135.568 -211.007 -100.48 +133.989 -211.22 -100.185 +134.997 -210.765 -100.317 +135.184 -210.69 -100.379 +135.044 -210.888 -100.363 +134.81 -210.875 -100.32 +134.109 -210.944 -100.174 +135.474 -210.527 -100.373 +135.474 -210.584 -100.452 +137.433 -210.072 -100.562 +137.259 -210.477 -100.559 +136.139 -211.092 -100.524 +136.685 -210.751 -100.541 +136.685 -210.108 -100.522 +135.747 -210.545 -100.499 +136.197 -210.574 -100.548 +135.815 -210.409 -100.475 +136.447 -210.397 -100.574 +137.678 -213.774 -100.545 +137.882 -213.614 -100.556 +136.986 -214.167 -100.514 +138.063 -214.31 -100.522 +137.501 -214.764 -100.494 +136.902 -214.63 -100.501 +137.092 -214.956 -100.498 +135.528 -214.143 -97.9997 +135.587 -214.126 -98.2258 +138.262 -214.895 -100.492 +137.791 -214.793 -100.498 +136.488 -213.706 -100.462 +138.706 -214.723 -100.505 +134.353 -214 -98.8437 +137.427 -215.064 -100.494 +137.158 -216.155 -100.454 +136.456 -214.529 -100.474 +135.311 -214.96 -100.334 +134.673 -216.721 -100.223 +135.315 -215.669 -100.425 +135.317 -215.141 -100.407 +134.815 -215.681 -100.278 +135.269 -214.775 -99.9908 +134.98 -216.592 -100.484 +135.197 -216.239 -100.248 +134.97 -216.565 -100.219 +138.395 -216.284 -100.393 +137.227 -216.351 -100.459 +136.863 -216.937 -100.465 +136.086 -217.12 -100.46 +137.4 -216.579 -100.429 +137.145 -215.443 -100.486 +138.002 -215.405 -100.482 +135.684 -216.259 -100.467 +136.366 -216.346 -100.465 +136.079 -216.355 -100.458 +135.291 -217.34 -100.508 +134.712 -217.416 -100.542 +136.79 -217.59 -100.43 +135.771 -216.991 -100.475 +135.279 -215.336 -100.448 +137.17 -217.261 -100.425 +137.715 -216.713 -100.393 +134.929 -215.629 -100.388 +134.686 -216.07 -100.113 +133.506 -215.818 -99.3641 +133.674 -214.532 -99.7841 +133.961 -217.051 -100.148 +133.797 -216.708 -100.142 +135.353 -215.956 -99.0295 +134.137 -216.395 -99.981 +134.196 -217.052 -100.233 +134.229 -217.096 -98.4763 +133.986 -216.428 -99.7456 +134.507 -216.141 -99.714 +134.46 -216.792 -100.154 +133.677 -216.61 -100.16 +133.784 -216.459 -100.033 +133.142 -216.456 -100.203 +133.523 -217.296 -100.174 +133.225 -216.844 -100.214 +133.657 -216.351 -100.012 +132.723 -216.756 -100.246 +133.464 -216.626 -98.6158 +133.579 -216.454 -100.125 +132.936 -216.596 -100.218 +134.359 -216.538 -100.078 +134.338 -216.249 -99.9656 +133.597 -215.091 -99.2294 +133.119 -214.834 -100.21 +135.21 -216.047 -100.312 +133.86 -216.641 -98.3189 +133.547 -216.698 -98.4573 +133.491 -213.655 -100.023 +132.963 -215.021 -100.246 +133.354 -214.36 -100.155 +133.304 -214.236 -100.073 +133.721 -213.983 -100.163 +134.039 -213.693 -100.109 +133.855 -213.777 -100.194 +133.645 -213.823 -100.162 +136 -214.456 -100.434 +136.283 -214.087 -100.453 +138.612 -213.823 -100.571 +134.611 -215.889 -99.9584 +135.505 -216.682 -98.0444 +135.629 -216.566 -97.6964 +135.626 -216.669 -98.4299 +135.096 -217.036 -98.571 +135.093 -216.695 -97.8471 +135.031 -214.758 -97.6403 +135.734 -214.717 -97.5705 +135.864 -214.887 -97.529 +133.874 -216.754 -98.3961 +134.129 -217.007 -98.2858 +134.023 -216.676 -98.1739 +133.321 -215.91 -98.1373 +133.632 -214.802 -98.7131 +135.774 -218.573 -100.42 +133.062 -213.782 -99.6959 +133.333 -215.895 -97.8523 +133.444 -215.112 -97.7823 +136.499 -220.494 -100.412 +136.781 -220.444 -100.57 +133.599 -217.327 -100.256 +133.011 -217.747 -99.9598 +133.994 -217.39 -100.607 +133.559 -217.533 -100.612 +132.667 -218.557 -100.573 +133.029 -217.05 -100.212 +132.561 -217.57 -100.172 +132.767 -218.471 -100.013 +132.863 -219.784 -100.604 +132.876 -220.087 -100.605 +133.504 -217.543 -100.306 +132.713 -218.659 -100.693 +133.132 -220.948 -100.548 +132.891 -220.541 -100.574 +132.545 -220.464 -100.608 +133.266 -220.232 -100.566 +134.505 -216.985 -97.7171 +134.236 -217.086 -97.9645 +132.494 -218.254 -99.9563 +132.909 -219.073 -100.604 +132.413 -218.78 -100.679 +132.549 -218.797 -100.701 +133.2 -219.272 -100.588 +133.51 -219.465 -100.565 +133.301 -217.751 -100.029 +132.98 -218.238 -99.9759 +132.633 -218.502 -99.9665 +132.503 -217.696 -99.9382 +133.141 -217.935 -99.9395 +132.749 -218.322 -99.9709 +134.017 -219.811 -100.527 +133.705 -220.182 -100.551 +134.628 -218.858 -100.51 +136.221 -220.295 -99.8642 +135.974 -220.583 -99.9694 +136.045 -220.305 -99.907 +132.946 -218.371 -100.06 +133.092 -217.555 -100.19 +133.238 -217.897 -99.9528 +132.846 -218.41 -100.674 +133.047 -218.229 -100.027 +133.435 -217.791 -100.604 +135.541 -217.397 -100.485 +134.11 -219.16 -100.539 +133.974 -219.423 -100.548 +134.951 -221.811 -98.4765 +134.904 -221.736 -98.8432 +136.165 -218.255 -100.393 +137.18 -218.302 -100.336 +138.937 -220.881 -98.5599 +136.932 -220.296 -100.469 +137.284 -219.413 -99.9591 +135.347 -219.336 -100.456 +134.726 -219.493 -100.491 +137.262 -219.563 -99.8092 +136.9 -220.435 -100.618 +136.416 -218.869 -100.366 +135.238 -218.958 -100.464 +135.133 -219.13 -100.507 +136.461 -220.101 -99.7853 +136.286 -220.139 -99.8559 +137.497 -219.283 -99.8933 +137.21 -219.142 -100.265 +137.317 -219.177 -100.206 +136.84 -220.128 -99.9573 +136.88 -219.791 -99.825 +138.734 -219.337 -99.9818 +137.993 -219.627 -99.8336 +136.512 -220.245 -99.8966 +135.051 -221.865 -98.3397 +137.026 -221.267 -98.246 +134.254 -222.894 -98.3942 +137.292 -221.334 -99.3343 +136.742 -220.13 -99.8916 +136.717 -221.414 -98.8001 +137.068 -221.229 -98.9748 +136.307 -219.871 -100.235 +135.826 -220.707 -99.9414 +135.527 -220.73 -100.103 +136.432 -222.106 -99.112 +136.342 -222.322 -99.1522 +136.027 -221.344 -99.7229 +137.568 -221.163 -99.6361 +136.656 -221.301 -99.512 +137.012 -221.217 -99.649 +136.794 -219.741 -99.9932 +137.719 -221.285 -101.186 +137.792 -221.226 -100.462 +136.781 -220.285 -100.312 +136.663 -219.675 -100.239 +137.129 -219.343 -100.244 +135.83 -221.63 -99.7905 +136.177 -222.557 -99.1106 +136.209 -219.827 -100.329 +135.157 -220.163 -100.453 +135.388 -220.631 -100.179 +134.951 -221.61 -100.317 +134.899 -220.953 -100.174 +135.68 -220.92 -99.9806 +134.416 -220.518 -100.482 +134.832 -220.613 -100.418 +135.666 -219.448 -100.418 +135.002 -220.342 -100.462 +134.468 -226.176 -101.341 +137.909 -220.715 -100.563 +136.689 -219.578 -100.346 +138.047 -218.029 -100.231 +137.971 -217.906 -100.251 +136.117 -219.345 -100.385 +135.25 -219.081 -100.495 +134.534 -218.264 -100.535 +137.344 -218.925 -100.276 +137.445 -218.678 -100.305 +137.137 -218.713 -100.324 +136.312 -217.718 -100.436 +137.423 -226.012 -101.329 +136.581 -217.535 -100.448 +137.81 -217.266 -100.308 +137.44 -227.271 -101.465 +138.506 -220.104 -100.559 +138.648 -220.448 -100.57 +138.076 -216.592 -100.388 +134.925 -217.569 -100.532 +135.959 -217.392 -100.462 +135.371 -217.985 -100.501 +134.654 -217.722 -100.54 +135.213 -217.833 -100.496 +135.298 -218.691 -100.448 +135.065 -218.781 -100.449 +135.811 -217.696 -100.478 +135.185 -218.512 -100.451 +135.131 -218.787 -100.38 +135.144 -218.703 -100.429 +134.985 -218.194 -100.514 +134.419 -218.588 -100.529 +133.886 -218.354 -100.561 +134.029 -217.596 -100.573 +134.304 -217.714 -100.529 +133.926 -217.963 -100.54 +133.171 -217.213 -100.214 +133.817 -217.612 -100.614 +134.465 -217.244 -100.578 +134.204 -217.154 -100.586 +133.854 -217.242 -100.525 +133.747 -217.117 -100.153 +134.022 -217.161 -100.318 +133.324 -217.885 -100.118 +133.407 -217.76 -100.471 +133.46 -217.412 -100.166 +132.965 -217.631 -100.161 +133.248 -217.985 -100.559 +133.025 -218.212 -100.578 +133.201 -218.136 -100.659 +133.047 -218.34 -100.675 +133.049 -218.736 -100.603 +133.434 -219.116 -100.565 +133.356 -218.661 -100.587 +133.663 -218.753 -100.568 +135.11 -218.94 -100.41 +134.988 -218.941 -100.472 +133.161 -219.827 -100.589 +134.173 -220.348 -100.502 +134.477 -220.726 -100.493 +133.995 -220.462 -100.527 +133.497 -220.749 -100.533 +134.016 -220.026 -100.523 +133.028 -219.556 -100.59 +133.847 -220.243 -100.551 +133.511 -221.25 -100.549 +134.639 -220.482 -100.484 +134.209 -220.768 -100.502 +134.377 -220.85 -100.476 +134.408 -219.741 -100.525 +139.521 -221.339 -101.398 +138.294 -220.356 -100.565 +138.225 -221.641 -101.747 +138.184 -220.46 -100.569 +139.251 -219.053 -100.063 +138.988 -219.082 -99.7065 +138.617 -221.352 -101.696 +138.657 -221.452 -101.756 +138.485 -220.561 -100.606 +139.178 -220.227 -100.468 +138.546 -219.74 -100.516 +138.261 -219.688 -100.497 +139.073 -219.861 -100.437 +139.174 -220.649 -100.515 +138.873 -219.626 -100.448 +139.377 -220.417 -100.497 +138.604 -217.374 -100.149 +138.456 -217.37 -100.29 +138.525 -217.42 -100.131 +138.259 -218 -100.248 +138.774 -217.463 -100.279 +137.977 -216.095 -100.44 +139.426 -215.785 -100.426 +138.826 -215.821 -100.442 +138.93 -216.564 -100.319 +138.98 -216.842 -100.287 +139.23 -216.936 -100.253 +138.523 -215.723 -100.466 +139.282 -215.524 -100.438 +139.055 -214.458 -100.505 +139.016 -216.193 -100.395 +139.494 -215.042 -100.478 +138.355 -214.053 -100.541 +138.751 -214.385 -100.521 +138.296 -216.938 -100.311 +138.671 -216.812 -100.309 +139.338 -216.859 -100.124 +139.086 -217.061 -100.273 +139.132 -216.388 -100.341 +139.396 -216.578 -100.23 +138.613 -217.292 -100.289 +139.342 -217.271 -100.273 +139.42 -217.512 -100.278 +139.07 -217.528 -100.269 +138.767 -217.691 -100.267 +139.007 -218.148 -100.204 +138.686 -217.594 -98.4946 +138.64 -217.474 -100.183 +138.531 -217.506 -99.7243 +138.214 -218.274 -99.81 +138.541 -218.452 -99.8716 +138.235 -218.678 -99.8699 +138.49 -218.671 -99.8521 +135.534 -216.916 -98.274 +138.134 -218.801 -99.9333 +137.876 -219.308 -99.7507 +138.576 -219.517 -100.355 +139.48 -218.859 -99.9353 +138.175 -218.471 -99.721 +138.063 -219.224 -99.7456 +138.561 -220.949 -98.1598 +138.87 -220.931 -98.0836 +139.244 -218.598 -99.6415 +139.497 -218.788 -99.701 +139.273 -218.96 -99.7983 +139.369 -218.238 -99.7515 +139.063 -218.536 -99.7095 +138.589 -217.497 -98.5401 +139.411 -218.127 -100.208 +138.633 -217.568 -100.279 +138.462 -217.495 -100.212 +138.148 -217.589 -100.271 +138.345 -217.478 -100.287 +137.96 -217.492 -100.285 +138.476 -217.623 -100.287 +138.911 -218.72 -99.6757 +138.847 -219.397 -100.341 +139.46 -218.99 -100.301 +138.253 -219.634 -100.372 +137.72 -218.643 -100.224 +137.891 -218.791 -100.065 +138.791 -220.954 -100.497 +138.879 -220.938 -100.109 +138.957 -220.769 -100.548 +139.135 -219.191 -100.4 +139.319 -219.186 -100.41 +139.098 -219.702 -100.403 +138.125 -220.95 -100.538 +138.054 -221.127 -100.215 +139.038 -219.452 -100.407 +139.009 -219.223 -100.184 +139.3 -220.835 -98.2599 +139.384 -220.884 -98.497 +137.701 -219.092 -99.948 +138.186 -219.458 -99.7866 +138.014 -219.383 -99.7611 +139.165 -220.888 -98.6509 +139.223 -220.973 -98.1139 +138.64 -217.651 -98.3275 +138.622 -217.551 -98.3495 +136.308 -215.658 -97.9753 +135.846 -216.015 -97.313 +136.316 -216.031 -97.6556 +137.207 -221.74 -93.6397 +137.099 -221.979 -93.6814 +137.13 -222.064 -93.7934 +134.645 -216.564 -96.4981 +134.579 -216.791 -96.6193 +134.331 -217.07 -96.8189 +133.804 -216.187 -97.6644 +134.253 -216.916 -96.8614 +133.803 -215.904 -96.9036 +134.249 -215.777 -96.9457 +135.603 -215.634 -96.8417 +138.32 -214.399 -94.9831 +136.519 -215.839 -96.8403 +134.796 -216.378 -96.8195 +134.813 -216.306 -96.9437 +136.44 -215.946 -97.2342 +136.469 -215.951 -96.7478 +137.016 -218.399 -93.6649 +134.468 -216.362 -96.8743 +134.333 -216.472 -96.8918 +134.42 -217.01 -96.6968 +134.535 -216.724 -96.6189 +134.394 -216.555 -96.7535 +134.309 -215.872 -97.1095 +135.554 -215.296 -96.8877 +135.673 -215.294 -97.1311 +134.408 -215.344 -96.9325 +135.216 -215.486 -96.6619 +135.165 -215.143 -96.8508 +135.059 -215.167 -96.9453 +134.914 -215.204 -97.1137 +135.476 -214.372 -97.8655 +135.987 -214.772 -97.5125 +135.682 -215.057 -97.559 +135.472 -215.047 -97.6324 +136.088 -215.64 -96.6999 +136.22 -216.018 -97.9773 +134.527 -214.919 -96.9669 +136.288 -215.459 -97.0512 +136.26 -215.501 -97.5801 +134.985 -214.864 -97.5221 +134.87 -214.622 -97.755 +134.413 -214.707 -97.0129 +134.108 -213.724 -95.3945 +134.237 -213.807 -95.5229 +134.402 -215.057 -96.7463 +134.49 -215.142 -96.7709 +134.442 -215.225 -96.7492 +134.281 -214.957 -96.8277 +134.331 -214.87 -96.9092 +133.907 -215.08 -97.1585 +133.545 -215.395 -97.3323 +133.733 -214.976 -97.5646 +133.871 -214.892 -97.5157 +134.057 -215.177 -96.8335 +133.776 -215.58 -96.9027 +134.209 -215.149 -96.8464 +134.621 -215.134 -97.0146 +133.945 -215.326 -96.8436 +134.223 -215.3 -96.95 +135.05 -216.399 -97.0464 +134.668 -216.215 -97.1067 +135.38 -215.433 -96.7192 +135.555 -215.477 -96.822 +134.043 -215.295 -96.8602 +134.546 -215.416 -97.0994 +134.014 -215.924 -97.4083 +134.465 -215.741 -97.1543 +134.764 -215.381 -97.4058 +134.839 -215.355 -97.3382 +134.49 -215.971 -97.1355 +134.591 -216.056 -97.1438 +134.557 -216.146 -97.174 +133.891 -215.668 -96.7507 +133.928 -215.501 -96.725 +134.096 -215.559 -96.8612 +134.349 -215.535 -97.0061 +134.002 -215.686 -96.7685 +134.619 -215.265 -97.079 +135.098 -215.609 -96.8545 +136.148 -215.295 -97.4693 +133.864 -215.857 -96.7427 +134.057 -215.844 -96.7439 +133.391 -215.358 -97.5741 +133.611 -215.708 -97.3317 +133.349 -215.658 -97.7765 +133.758 -215.98 -97.2776 +133.645 -215.389 -97.2145 +134.243 -216.061 -97.5418 +133.431 -215.926 -97.7056 +133.832 -216.106 -97.6565 +134.422 -216.188 -97.3217 +134.148 -215.992 -97.5418 +134.223 -216.329 -97.472 +134.518 -216.226 -97.1532 +134.157 -216.592 -97.4428 +134.248 -216.978 -97.7533 +134.213 -216.775 -96.8997 +135.452 -216.403 -96.9345 +134.836 -216.605 -96.9076 +134.768 -216.788 -96.7396 +135.053 -216.531 -96.9357 +134.816 -216.7 -96.9823 +135.061 -216.534 -97.0072 +135.327 -216.251 -96.8524 +135.131 -216.432 -96.9811 +135.283 -216.15 -96.8775 +134.711 -217.018 -96.9393 +135.345 -216.767 -98.0384 +134.703 -216.174 -97.3846 +135.08 -216.06 -97.2265 +135.113 -215.946 -97.2232 +134.972 -216.582 -97.2407 +135.242 -216.43 -97.0156 +136.278 -215.362 -97.7172 +136.216 -215.147 -97.7292 +135.595 -216.088 -97.1331 +135.362 -216.145 -96.8794 +135.678 -216.416 -97.2534 +135.186 -217.007 -97.9989 +134.908 -217.033 -97.8445 +136.381 -215.988 -97.1382 +135.678 -216.042 -97.2723 +135.547 -216.374 -96.9948 +134.998 -215.679 -97.2461 +134.928 -215.841 -97.5203 +134.835 -215.725 -97.5978 +134.913 -215.434 -97.331 +135.406 -215.561 -96.8001 +135.847 -215.448 -97.0221 +135.787 -215.304 -97.1709 +136.058 -215.146 -97.2749 +135.281 -215.714 -96.8866 +135.091 -215.408 -96.8051 +135.981 -215.061 -97.3951 +135.721 -215.526 -96.7962 +135.813 -215.47 -96.867 +136.263 -215.834 -96.6628 +136.184 -215.998 -96.748 +136.485 -215.677 -96.7997 +136.338 -215.994 -96.7629 +135.958 -215.476 -96.9857 +136.208 -215.45 -96.9245 +136.059 -215.217 -97.1574 +136.49 -215.774 -97.1325 +136.202 -216.082 -97.6029 +135.517 -216.711 -98.1568 +135.793 -216.452 -97.7582 +136.581 -215.398 -98.0798 +136.385 -215.497 -98.053 +135.45 -214.198 -97.8954 +134.909 -215.663 -97.4888 +135.954 -216.434 -98.1528 +135.964 -216.411 -97.9467 +136.795 -215.292 -98.1191 +136.746 -215.347 -98.0895 +136.521 -214.912 -97.8268 +134.798 -215.883 -97.5594 +134.56 -217.182 -98.3179 +134.745 -217.15 -98.1556 +135.217 -217.127 -98.1373 +134.749 -217.197 -98.4941 +133.54 -216.228 -97.8399 +133.797 -216.367 -97.8563 +133.669 -216.263 -97.8736 +133.679 -216.178 -97.7484 +133.307 -216.298 -97.8182 +133.999 -216 -97.6146 +133.242 -216.261 -97.8435 +133.449 -216.042 -97.7117 +134.687 -215.704 -97.5823 +135.597 -214.055 -98.5353 +133.5 -215.206 -98.3573 +134.284 -214.807 -97.0056 +134.718 -214.34 -97.8974 +135.094 -214.462 -97.8617 +134.755 -214.072 -98.0285 +134.799 -213.987 -98.2663 +134.541 -214.124 -98.1493 +134.564 -213.962 -98.5509 +135.25 -214.161 -97.8673 +135.145 -214.625 -97.7921 +135.266 -214.798 -97.6444 +135.49 -214.734 -97.6086 +135.59 -215.135 -97.5394 +136.173 -214.824 -97.5245 +136.071 -215.597 -98.4426 +136.313 -214.791 -97.667 +136.232 -214.969 -97.6948 +138.346 -214.367 -95.137 +137.955 -214.213 -95.0544 +136.249 -214.617 -97.899 +136.394 -215.259 -97.9028 +136.125 -214.558 -97.801 +136.571 -215.107 -97.9204 +135.376 -214.364 -99.7364 +133.691 -216.821 -98.5013 +133.783 -216.919 -98.4765 +133.958 -217.075 -98.3929 +135.659 -216.727 -98.2823 +136.439 -215.37 -98.2337 +135.774 -216.555 -98.1318 +135.257 -217.079 -98.0936 +134.893 -217.124 -97.9625 +137.834 -219.086 -93.9083 +136.832 -218.666 -93.9438 +135.125 -220.765 -93.0799 +137.696 -218.332 -94.3378 +138.066 -218.708 -93.7318 +137.883 -218.835 -93.8335 +137.311 -218.115 -94.0784 +136.97 -218.342 -93.8544 +137.066 -218.217 -93.6556 +137.02 -219.415 -94.012 +137.133 -218.664 -93.6659 +137.295 -218.909 -93.7747 +137.181 -218.132 -93.7098 +137.561 -218.197 -93.6768 +137.349 -218.303 -93.7239 +137.235 -218.547 -93.6267 +137.493 -218.508 -93.7318 +137.43 -218.141 -93.6213 +137.489 -218.016 -93.8528 +137.393 -218.686 -93.6958 +136.908 -219.11 -93.9107 +137.189 -219.034 -94.0428 +137.376 -219.115 -94.0304 +137.866 -217.766 -93.9551 +137.608 -217.965 -94.0748 +137.593 -219.217 -93.8759 +137.391 -219.027 -94.0084 +137.214 -219.609 -93.924 +137.72 -219.03 -93.8182 +137.096 -219.558 -93.9794 +138.098 -218.856 -94.3852 +137.175 -219.547 -93.9185 +136.958 -219.258 -93.9802 +136.863 -219.022 -93.9259 +137.834 -218.955 -93.8661 +137.936 -219.214 -94.0231 +137.99 -219.275 -94.2268 +132.878 -222.133 -92.4245 +135.161 -220.719 -93.2717 +134.113 -221.03 -92.9107 +134.453 -213.278 -93.4968 +134.55 -213.042 -93.6311 +134.559 -213.409 -93.3959 +134.412 -213.345 -93.4133 +134.921 -213.41 -93.3913 +135.078 -213.4 -93.3879 +136.213 -214.323 -94.0507 +136.106 -214.35 -94.1931 +135.506 -212.665 -93.6695 +135.247 -213.22 -93.5093 +135.187 -213.325 -93.4385 +135.235 -212.925 -93.6884 +134.754 -213.416 -93.5358 +134.582 -213.35 -93.4537 +134.474 -213.344 -93.4221 +136.649 -214.502 -94.5863 +136.723 -214.453 -94.0354 +136.498 -214.612 -94.0509 +136.667 -214.547 -94.0324 +136.521 -213.333 -94.3308 +136.427 -213.161 -94.0369 +137.595 -213.432 -94.3424 +136.178 -214.428 -93.9812 +136.186 -214.608 -93.9258 +136.469 -214.505 -93.9942 +136.751 -213.361 -94.1281 +138.126 -211.887 -93.4015 +138.37 -211.727 -93.5685 +136.984 -213.698 -93.9079 +137.626 -213.678 -94.5122 +137.666 -213.741 -94.5934 +136.58 -213.902 -94.2395 +136.753 -213.869 -94.1237 +136.992 -213.95 -94.267 +137.06 -214.546 -94.7804 +136.889 -214.197 -94.4888 +136.151 -214.688 -93.9546 +136.182 -214.642 -94.4125 +136.096 -214.564 -94.2244 +135.367 -213.257 -93.9336 +135.152 -213.349 -93.8438 +136.003 -214.55 -93.9469 +135.663 -213.606 -94.2726 +135.648 -213.551 -94.1064 +135.522 -213.658 -94.4157 +135.595 -213.364 -94.0831 +135.12 -213.567 -94.8738 +134.971 -213.484 -94.9114 +134.197 -213.702 -95.2677 +134.508 -213.261 -93.5126 +135.782 -213.53 -94.1519 +135.775 -213.683 -94.5905 +135.697 -213.92 -94.8424 +135.81 -214.053 -94.9875 +135.913 -213.717 -94.662 +136.033 -213.503 -94.4172 +135.307 -213.705 -94.9247 +135.352 -214.138 -95.1051 +135.211 -213.682 -95.2183 +134.758 -213.494 -95.332 +135.382 -214.216 -95.2572 +135.844 -213.995 -95.3537 +136.362 -214.373 -95.1784 +136.62 -214.701 -94.9977 +136.232 -214.734 -94.888 +135.97 -214.342 -94.9644 +136.329 -214.625 -94.3317 +137.149 -214.342 -95.0287 +137.564 -214.117 -94.6644 +136.867 -214.307 -94.7008 +136.084 -214.399 -94.7025 +136.163 -214.691 -94.6445 +136.903 -214.02 -94.3086 +137.09 -214.049 -94.7359 +136.91 -214.378 -94.7662 +136.114 -213.484 -94.4199 +136.238 -213.957 -94.3458 +136.093 -212.797 -93.9888 +135.819 -213.381 -94.184 +135.998 -213.699 -94.6222 +137.403 -213.348 -95.4184 +137.5 -213.784 -94.3236 +137.155 -213.994 -94.6109 +136.951 -213.389 -94.0306 +137.085 -214.111 -94.8462 +136.813 -214.67 -94.8827 +137.24 -214.016 -94.7717 +137.882 -214.318 -94.6812 +137.849 -213.733 -94.8231 +138.006 -213.951 -95.0255 +137.873 -214.418 -94.7747 +137.713 -214.03 -94.6571 +137.521 -213.856 -94.5277 +137.663 -213.926 -94.6386 +137.833 -213.837 -94.7437 +137.915 -214.026 -94.6632 +137.66 -213.634 -95.1069 +136.524 -214.796 -94.907 +135.512 -214.246 -95.0272 +136.051 -214.527 -94.9481 +137.714 -214.366 -94.746 +136.241 -214.776 -94.694 +137.373 -214.065 -94.9865 +137.582 -213.909 -95.1422 +135.659 -214.413 -95.2521 +134.895 -213.988 -95.4188 +135.048 -213.953 -95.4137 +135.253 -214.012 -95.3627 +135.184 -213.563 -95.1137 +134.874 -213.687 -95.3291 +135.185 -214.01 -95.3111 +135.508 -214.356 -95.1521 +134.628 -213.723 -95.4161 +135.068 -213.934 -95.3614 +135.148 -213.593 -95.2548 +134.842 -213.284 -94.9809 +135.795 -213.407 -95.5185 +134.539 -213.665 -95.5094 +134.038 -213.585 -95.5113 +134.622 -213.128 -95.3992 +134.934 -211.514 -95.0359 +134.704 -212.762 -94.8138 +134.502 -212.593 -94.9927 +134.15 -213.188 -95.3734 +134.222 -212.971 -95.2469 +134.384 -213.1 -95.2404 +134.266 -213.094 -95.2235 +134.259 -212.711 -95.2172 +134.708 -212.055 -94.6551 +134.497 -212.167 -94.6862 +134.327 -213.222 -95.2237 +134.953 -213.549 -94.4981 +134.753 -212.904 -94.6949 +134.729 -212.839 -94.0063 +134.83 -213.236 -94.3478 +134.841 -212.553 -94.2085 +134.451 -212.329 -94.8197 +135.153 -212.06 -95.3131 +135.704 -211.747 -93.5189 +136.004 -211.827 -93.546 +134.591 -212.266 -94.7016 +134.713 -212.311 -94.6469 +134.969 -211.997 -94.6859 +134.751 -212.454 -94.6208 +135.032 -213.372 -94.0988 +136.583 -211.155 -94.2088 +136.553 -211.589 -94.22 +136.512 -211.267 -94.3018 +135.088 -212.072 -94.372 +136.173 -211.16 -94.0126 +135.399 -211.839 -94.5983 +135.799 -211.667 -94.0739 +135.145 -211.813 -94.6524 +135.249 -211.619 -94.6309 +135.253 -211.443 -94.6507 +137.277 -212.346 -93.9166 +136.441 -212.149 -93.9511 +136.364 -212.071 -93.8808 +136.571 -212.073 -94.0683 +136.436 -211.709 -94.5389 +136.168 -211.792 -94.5113 +136.187 -211.656 -94.5401 +136.704 -213.175 -93.8039 +136.542 -211.849 -94.1749 +136.663 -211.741 -93.9864 +135.797 -212.495 -93.7338 +135.879 -212.714 -93.9403 +136.025 -212.974 -94.1117 +135.918 -213.275 -94.2164 +137.065 -212.984 -93.7679 +137.145 -213.189 -93.9216 +137.864 -212.542 -94.0024 +137.544 -211.083 -94.9977 +137.549 -210.978 -94.6571 +137.524 -211.393 -94.8621 +136.794 -210.475 -94.1683 +136.495 -210.65 -94.1128 +136.314 -210.432 -94.4752 +137.471 -212.165 -95.663 +137.498 -211.553 -95.4269 +137.478 -211.415 -95.5299 +137.141 -211.092 -95.4114 +137.426 -211.284 -94.6219 +137.456 -210.876 -94.9641 +137.493 -210.717 -94.725 +137.586 -211.052 -94.7198 +136.256 -211.656 -94.6448 +137.379 -211.116 -94.5721 +136.906 -211.619 -93.6847 +136.809 -211.311 -93.9952 +136.67 -211.531 -94.0029 +137.359 -210.321 -94.5716 +137.196 -209.969 -94.615 +137.395 -209.954 -95.0941 +137.261 -210.414 -94.3746 +137.107 -210.1 -94.2557 +137.483 -211.696 -95.0181 +137.216 -210.713 -94.3807 +137.316 -210.477 -94.4578 +137.416 -210.45 -94.6226 +137.453 -210.727 -94.6234 +137.239 -210.235 -94.99 +137.157 -210.157 -94.4746 +138.205 -209.237 -95.4093 +137.739 -211.331 -93.8428 +137.513 -211.276 -93.6568 +137.064 -210.773 -94.2672 +137.643 -211.65 -94.3533 +137.183 -211.264 -94.0365 +136.842 -210.91 -94.0899 +136.839 -210.977 -94.1084 +137.193 -210.378 -94.1125 +137.982 -209.356 -94.2787 +137.63 -209.636 -94.4299 +137.35 -209.546 -94.1719 +137.549 -209.731 -94.62 +137.012 -210.704 -94.0163 +137.007 -210.463 -93.9815 +136.829 -210.298 -94.1942 +137.417 -209.76 -94.6858 +137.378 -209.864 -94.8525 +137.489 -209.826 -95.1208 +137.141 -209.81 -94.2816 +137.067 -210.096 -94.1754 +136.135 -210.534 -94.6174 +135.768 -210.913 -94.2474 +136.049 -210.673 -94.2515 +137.293 -207.985 -94.2249 +137.282 -208.197 -94.0003 +136.607 -210.239 -94.4871 +136.683 -210.071 -94.4132 +136.794 -210.04 -94.266 +136.53 -210.439 -95.0143 +136.369 -210.26 -94.5131 +136.514 -210.022 -94.4595 +136.301 -210.157 -94.4904 +136.15 -210.156 -94.4764 +136.187 -209.937 -94.2357 +136.755 -211.206 -94.0828 +136.872 -211.178 -94.0679 +136.117 -209.913 -94.137 +136.292 -210.035 -94.3955 +136.387 -209.68 -93.8642 +136.43 -211.453 -94.4533 +136.347 -211.602 -94.6168 +136.384 -211.297 -94.4276 +136.118 -211.636 -93.8917 +136.059 -211.487 -93.9994 +135.584 -211.747 -94.4186 +135.84 -211.056 -94.1004 +135.587 -211.31 -94.3895 +135.434 -211.273 -94.5256 +137.095 -210.46 -93.978 +135.005 -211.237 -96.411 +135.42 -211.172 -94.5993 +135.57 -211.184 -94.383 +135.533 -211.03 -94.5606 +135.713 -209.801 -94.1247 +136.043 -210.025 -94.2949 +135.867 -210.903 -94.0884 +135.674 -209.884 -93.6531 +135.791 -209.998 -93.829 +136.002 -210.784 -94.1078 +134.609 -211.55 -97.0826 +135.656 -209.251 -93.9201 +137.001 -210.024 -94.1645 +136.852 -209.968 -94.2042 +137.661 -209.363 -94.1541 +137.515 -209.221 -94.0614 +137.448 -209.415 -94.0997 +136.654 -209.585 -93.8811 +136.371 -208.474 -94.3144 +136.596 -208.892 -94.7971 +136.031 -209.263 -94.1652 +136.56 -209.793 -94.1003 +137.299 -209.74 -94.4657 +136.95 -209.6 -94.0032 +137.123 -209.717 -94.2445 +136.473 -209.649 -93.9023 +136.596 -209.71 -94.0311 +136.946 -209.757 -94.1631 +136.759 -209.688 -94.0393 +137.224 -209.861 -94.502 +137.719 -209.741 -94.6913 +137.846 -209.339 -94.1815 +137.836 -209.635 -94.4575 +137.906 -209.54 -94.3934 +137.561 -208.789 -93.8811 +137.481 -208.998 -93.9623 +137.63 -209.174 -94.049 +137.768 -208.095 -94.5176 +138.032 -208.879 -94.94 +138.115 -208.857 -94.1872 +138.149 -209.263 -94.6017 +137.858 -208.205 -94.6643 +137.924 -208.435 -94.7798 +137.965 -208.937 -93.914 +137.986 -208.716 -93.8064 +137.818 -209.748 -94.8691 +136.72 -209.112 -93.6553 +136.799 -209.054 -93.7611 +138.14 -209.499 -94.981 +137.962 -209.707 -95.0767 +138.175 -209.069 -95.1265 +137.123 -209.953 -95.2284 +137.641 -209.675 -94.9796 +137.582 -209.731 -95.2088 +137.759 -209.636 -95.5288 +137.928 -209.562 -95.4104 +138.198 -209.74 -94.6277 +138.437 -208.151 -95.6 +138.426 -208.257 -95.3145 +138.356 -207.866 -95.1427 +138.121 -208.359 -94.9284 +137.706 -207.33 -95.0939 +137.957 -208.193 -94.8192 +137.91 -207.625 -95.072 +137.323 -207.064 -95.0135 +137.431 -207.076 -95.0664 +137.636 -207.104 -95.0927 +137.834 -207.333 -95.109 +136.886 -208.133 -95.0377 +136.661 -207.777 -94.7708 +137.32 -206.934 -94.9999 +137.273 -206.973 -94.7991 +137.85 -206.959 -94.973 +138.16 -206.999 -94.7498 +137.487 -206.61 -94.2406 +137.141 -207.719 -94.5423 +138.178 -208.542 -94.9252 +137.917 -208.045 -94.7941 +138.07 -207.71 -95.0035 +136.191 -207.791 -93.9596 +138.079 -208.423 -93.8037 +137.983 -208.233 -93.8817 +138.056 -208.322 -93.8236 +137.087 -207.735 -94.384 +137.347 -206.734 -94.2989 +137.365 -208.252 -94.0244 +137.495 -208.304 -93.9827 +135.822 -207.071 -93.4065 +137.232 -209.401 -93.8361 +137.312 -209.348 -93.8206 +137.753 -208.241 -93.8799 +137.251 -207.114 -94.9155 +135.759 -207.569 -93.0455 +136.294 -208.704 -93.0055 +136.317 -208.914 -93.0361 +136.64 -208.171 -92.2459 +136.202 -207.833 -93.0714 +135.884 -208.01 -92.9725 +135.991 -207.556 -93.0127 +136.904 -208.669 -92.3236 +137.045 -208.654 -92.4028 +135.939 -207.154 -93.1532 +135.779 -207.178 -93.1857 +135.739 -207.719 -93.0918 +135.813 -207.815 -93.3102 +135.699 -208.471 -93.0835 +135.861 -206.996 -93.3352 +136.675 -207.094 -92.2771 +136.863 -207.224 -92.217 +136.944 -207.317 -92.3195 +135.753 -208.042 -93.0646 +136.003 -208.394 -92.9131 +136.251 -207.96 -93.0023 +136.417 -208.07 -92.8532 +135.734 -207.444 -93.0913 +135.783 -208.809 -93.3263 +137.455 -206.575 -92.9327 +136.034 -208.382 -93.7235 +136.296 -207.1 -93.2547 +137.169 -207.641 -93.2214 +137.111 -207.676 -93.007 +136.508 -207.608 -92.7905 +137.118 -207.276 -93.6691 +136.323 -207.495 -93.0402 +136.462 -207.402 -92.9075 +137.69 -208.677 -93.8073 +137.472 -208.551 -93.9429 +137.907 -208.27 -93.8226 +137.132 -207.259 -93.3619 +137.505 -206.478 -92.8585 +137.331 -206.756 -93.2029 +137.284 -206.572 -92.7345 +137.083 -206.93 -92.6508 +137.234 -206.472 -92.7071 +137.189 -206.719 -92.7335 +137.218 -206.826 -92.9423 +137.104 -207.208 -93.1116 +136.989 -207.242 -92.7557 +136.497 -206.901 -92.9179 +136.558 -207.293 -92.4771 +136.486 -207.939 -92.7522 +136.342 -207.861 -93.006 +136.009 -208.895 -93.8267 +136.952 -207.478 -92.3871 +136.577 -206.93 -92.5667 +136.53 -206.568 -92.8103 +137.352 -208.36 -92.4565 +137.282 -208.192 -92.673 +136.689 -207.659 -92.3783 +136.531 -207.443 -92.6998 +136.486 -208.196 -92.6634 +137.193 -208.353 -93.845 +137.288 -208.378 -93.9719 +137.119 -208.992 -93.7618 +137.32 -208.423 -92.9164 +136.412 -208.913 -92.9701 +136.499 -209.035 -93.0218 +137.282 -208.477 -92.7511 +136.993 -208.675 -93.297 +136.747 -208.899 -93.294 +136.69 -208.849 -92.9873 +136.431 -209.231 -93.2101 +136.317 -208.261 -92.8524 +136.875 -208.617 -92.2326 +136.267 -208.491 -92.8726 +136.198 -208.332 -92.865 +136.017 -208.753 -93.1775 +135.717 -209.719 -93.4044 +136.88 -208.783 -93.0859 +135.924 -209.22 -93.2477 +136.365 -209.116 -93.0192 +136.341 -209.233 -93.1389 +136.557 -208.397 -92.4359 +136.332 -208.438 -92.7907 +135.724 -208.586 -93.0766 +136.641 -208.441 -92.356 +137.092 -208.588 -92.2234 +135.711 -209.656 -93.3077 +136.124 -209.574 -93.3943 +136.146 -209.313 -93.2116 +136.106 -209.73 -93.3716 +135.906 -209.035 -93.2572 +136.795 -209.256 -93.626 +136.515 -209.266 -93.398 +137.248 -208.951 -93.8011 +136.919 -208.716 -93.6911 +137.433 -209.173 -93.9753 +136.918 -208.83 -93.8652 +137.37 -208.713 -93.9215 +137.506 -208.848 -93.9187 +138.016 -208.592 -93.7324 +137.154 -208.821 -93.8317 +137.349 -209.229 -93.7569 +137.092 -208.623 -93.8348 +137.359 -208.512 -93.9637 +138.428 -208.865 -95.1365 +138.067 -208.784 -93.8953 +137.92 -209.143 -93.9914 +136.665 -209.388 -93.6473 +136.324 -209.768 -94.0107 +136.379 -209.609 -93.6958 +136.27 -209.724 -93.4598 +136.195 -209.871 -93.4973 +136.789 -208.919 -93.8267 +136.913 -208.759 -93.8353 +135.933 -210.059 -94.0987 +136.069 -209.902 -93.5659 +135.308 -209.71 -93.3133 +135.608 -209.34 -93.2633 +135.715 -209.584 -93.2722 +136.306 -210.781 -94.0294 +135.592 -209.471 -93.2321 +135.655 -210.096 -94.027 +135.561 -209.992 -93.8726 +136.196 -209.851 -93.7096 +135.926 -208.909 -93.2425 +135.831 -209.022 -93.349 +135.3 -209.646 -93.2812 +136.161 -211.732 -93.591 +136.001 -209.468 -93.2975 +135.779 -209.188 -93.312 +135.748 -208.424 -92.9994 +135.97 -211.309 -93.9815 +135.667 -211.815 -93.485 +135.582 -211.841 -93.404 +135.789 -211.723 -93.5269 +135.979 -211.709 -93.6022 +135.51 -211.965 -93.4769 +136.147 -211.049 -93.8874 +135.882 -211.596 -94.0846 +136.803 -211.718 -93.7423 +137.076 -211.777 -93.6075 +136.927 -211.954 -93.7703 +136.052 -211.325 -93.9558 +136.444 -210.826 -94.0483 +137.068 -211.456 -93.6911 +137.193 -211.413 -93.603 +135.951 -212.011 -93.5341 +136.563 -210.963 -94.1497 +136.751 -211.041 -94.0638 +136.754 -210.909 -94.0332 +136.689 -210.782 -94.006 +136.934 -210.664 -93.9818 +137.794 -211.294 -93.3129 +137.162 -210.505 -94.0641 +137.124 -210.336 -94.0667 +137.421 -211.394 -93.3211 +137.367 -211.342 -93.4141 +137.522 -211.26 -93.2865 +137.127 -211.316 -93.801 +137.301 -212.063 -93.616 +137.403 -212.033 -93.4923 +137.383 -211.464 -93.3654 +137.406 -211.662 -93.5375 +137.251 -211.672 -93.6095 +137.943 -211.288 -93.515 +137.617 -211.279 -93.2742 +137.654 -211.229 -93.2959 +137.678 -211.859 -93.5495 +137.864 -211.518 -93.4395 +137.593 -212.357 -93.8071 +135.767 -212.357 -93.666 +136.23 -211.928 -93.4865 +136.832 -212.779 -93.6526 +135.292 -212.442 -93.5666 +136.691 -212.525 -93.6864 +136.666 -212.851 -93.6224 +136.71 -213.12 -93.7169 +137.324 -213.052 -93.8164 +137.225 -212.905 -93.7489 +137.15 -212.524 -93.7736 +137.379 -212.985 -93.8207 +137.707 -212.171 -93.5443 +137.728 -212.275 -93.6391 +137.374 -211.811 -93.5569 +137.083 -211.886 -93.6007 +137.035 -212.1 -93.7945 +138.257 -211.695 -93.5119 +136.235 -212.437 -93.6928 +137.014 -212.381 -93.6669 +137.093 -212.238 -93.7928 +137.239 -212.145 -93.7953 +137.467 -212.676 -93.9783 +136.93 -212.514 -93.6331 +136.539 -212.739 -93.6306 +137.775 -212.645 -93.9844 +137.766 -212.736 -94.0654 +138.27 -211.883 -93.5714 +137.643 -212.533 -93.9267 +137.718 -212.47 -93.8412 +137.442 -212.509 -93.9848 +137.861 -212.481 -93.8675 +136.715 -212.077 -93.9322 +136.583 -212.181 -93.9469 +136.792 -212.195 -93.8463 +137.69 -212.028 -94.4634 +136.893 -213.145 -93.8306 +137.39 -213.326 -93.9864 +137.656 -212.882 -94.0318 +136.984 -213.269 -94.0191 +136.56 -212.393 -93.7831 +136.846 -212.943 -93.7072 +136.144 -212.99 -94.0645 +136.737 -211.842 -93.8725 +136.217 -212.519 -93.7624 +136.352 -212.702 -93.6849 +136.371 -212.216 -93.8041 +136.931 -212.346 -93.6483 +135.477 -213.366 -94.0517 +136.371 -213.045 -93.5844 +136.453 -213.189 -93.6328 +135.863 -213.069 -94.0965 +135.384 -213.136 -93.8679 +135.374 -212.973 -93.8219 +135.215 -212.849 -93.7114 +135.118 -213.141 -93.4478 +135.415 -212.927 -93.8213 +134.92 -212.527 -93.4522 +134.997 -212.42 -93.4364 +135.065 -212.588 -93.5375 +135.774 -211.838 -93.5186 +135.927 -212.304 -93.5849 +135.664 -212.25 -93.7086 +134.934 -212.242 -94.0262 +134.854 -212.246 -93.6898 +134.951 -212.191 -93.4502 +135.615 -211.836 -93.5831 +135.44 -211.991 -93.3639 +135.591 -211.991 -93.6353 +135.514 -211.849 -93.8208 +135.508 -213.156 -93.9594 +134.742 -212.563 -93.6525 +135.04 -212.749 -93.589 +134.797 -212.159 -93.4676 +134.742 -212.442 -93.4938 +135.172 -212.29 -93.3402 +135.113 -212.064 -93.5215 +134.951 -212.134 -93.5107 +134.932 -212.88 -93.5154 +134.779 -212.719 -93.4385 +134.461 -213.157 -93.564 +134.785 -212.794 -93.4347 +134.658 -213.055 -93.6049 +134.642 -212.883 -93.6363 +134.826 -212.978 -93.5455 +134.588 -213.376 -93.3916 +134.568 -213.135 -93.5909 +134.827 -213.438 -93.4135 +135.113 -213.341 -93.3571 +134.848 -213.198 -93.5257 +134.711 -212.701 -93.5243 +135.108 -212.22 -93.3159 +135.33 -212.168 -93.3964 +135.21 -212.071 -93.3152 +136.788 -207.601 -92.3072 +137.288 -208.472 -92.4614 +137.006 -208.311 -92.1728 +137.008 -208.105 -91.9921 +136.885 -207.99 -92.0195 +137.129 -208.484 -92.2024 +137.061 -208.521 -92.1692 +136.744 -208.601 -92.3307 +136.831 -207.48 -92.3435 +136.962 -207.88 -92.0908 +136.923 -207.603 -92.2897 +137.211 -207.997 -92.186 +136.732 -207.483 -92.435 +137.042 -206.801 -92.4095 +136.594 -207.208 -92.3861 +136.669 -206.636 -92.3425 +136.769 -206.979 -92.1729 +136.868 -207.016 -92.1715 +138.106 -209.899 -94.5301 +138.792 -208.834 -95.4951 +137.936 -211.591 -93.9633 +138.169 -211.864 -93.7697 +138.049 -212.051 -93.437 +138.167 -212.021 -93.4549 +138.032 -211.885 -93.4055 +137.928 -211.337 -93.3937 +138.433 -211.559 -93.562 +138.059 -212.165 -93.5631 +138.443 -211.307 -93.6164 +138.076 -211.389 -93.5394 +138.807 -213.665 -94.857 +138.536 -211.578 -93.5781 +138.173 -211.296 -93.5836 +138.006 -209.902 -94.5518 +138.141 -209.799 -94.7005 +138.059 -208.579 -93.7611 +138.088 -209.008 -94.6133 +138.767 -208.686 -95.5882 +138.804 -207.185 -94.8214 +138.534 -207.579 -94.8556 +138.333 -207.861 -95.04 +138.374 -208.357 -94.9415 +138.186 -208.126 -94.9189 +138.481 -207.863 -95.4707 +138.707 -207.426 -95.1694 +138.318 -207.724 -94.989 +138.784 -207.012 -94.7273 +138.439 -207.749 -95.2559 +138.751 -207.281 -94.7611 +138.422 -206.556 -94.8766 +138.096 -207.98 -94.8736 +138.434 -207.493 -94.649 +137.939 -207.251 -94.977 +138.254 -207.229 -94.6661 +138.249 -207.909 -94.985 +138.346 -207.38 -94.616 +138.234 -207.619 -94.8733 +138.318 -208.209 -94.9602 +138.102 -207.562 -94.898 +138.484 -208.526 -95.4116 +138.251 -209.272 -95.552 +138.033 -209.426 -95.5847 +138.214 -209.466 -94.7404 +138.706 -209.007 -95.501 +138.067 -209.548 -94.5395 +138.151 -208.663 -94.9558 +138.192 -208.914 -95.0228 +138.186 -209.302 -94.7487 +138.759 -208.775 -95.4624 +138.618 -208.725 -95.3638 +138.835 -213.72 -94.8579 +139.272 -216.852 -93.7832 +139.46 -217.151 -93.7734 +139.423 -216.956 -93.7331 +138.169 -213.982 -94.7412 +138.386 -213.937 -94.6738 +139.029 -217.852 -94.3642 +138.413 -213.995 -94.6636 +138.058 -214.022 -94.708 +138.235 -214.04 -94.673 +138.386 -214.231 -95.2453 +138.028 -214.454 -94.918 +138.35 -214.227 -94.828 +138.433 -214.286 -95.0163 +138.048 -214.227 -94.7134 +138.65 -213.929 -94.8632 +138.126 -213.966 -94.8845 +138.608 -213.854 -94.9294 +138.699 -213.778 -94.8417 +138.267 -214.18 -95.129 +139.364 -217.693 -94.3638 +138.987 -217.738 -94.1886 +138.88 -217.711 -94.1758 +138.741 -218.53 -94.0496 +138.661 -217.889 -93.966 +138.187 -218.444 -94.4052 +138.53 -218.702 -93.9824 +138.331 -218.719 -93.9356 +138.796 -218.378 -94.053 +139.357 -218.038 -94.3648 +139.295 -218.071 -94.2731 +139.063 -218.393 -93.9867 +138.392 -219.081 -94.0754 +138.446 -221.004 -98.1014 +138.043 -218.827 -93.8928 +138.717 -218.969 -94.1707 +138.109 -219.146 -94.0671 +136.818 -221.293 -93.6855 +137.11 -221.41 -93.4719 +137.087 -221.524 -93.4212 +138.407 -217.854 -93.8778 +138.218 -217.945 -93.8381 +139.122 -218.794 -94.0857 +138.846 -218.571 -94.0816 +138.829 -218.197 -94.0589 +138.917 -218.263 -94.0854 +138.763 -218.872 -94.1271 +139.123 -218.245 -94.1621 +138.427 -218.6 -93.9156 +138.356 -218.544 -93.8805 +138.746 -217.835 -94.0058 +138.028 -217.869 -93.8345 +138.268 -218.176 -93.8616 +138.853 -217.86 -94.0926 +138.289 -217.732 -93.936 +137.97 -218.374 -93.6824 +137.684 -218.055 -93.7128 +137.928 -218.048 -93.6448 +137.016 -221.321 -93.5018 +137.158 -221.406 -93.656 +133.29 -222.626 -92.2444 +133.091 -222.542 -92.3049 +136.767 -222.23 -94.0474 +137.261 -223.078 -98.1084 +136.012 -222.58 -94.3926 +137.11 -222.307 -93.672 +136.264 -222.555 -94.3378 +136.339 -222.339 -94.4639 +136.597 -221.514 -93.5499 +136.418 -221.416 -93.5232 +136.219 -221.405 -93.3835 +135.726 -222.561 -93.6527 +135.757 -222.413 -93.599 +137.193 -221.55 -93.4807 +134.993 -221.712 -93.6073 +135.847 -222.654 -93.7561 +136.14 -222.294 -93.8968 +134.701 -223.093 -93.2566 +137.103 -221.768 -93.4949 +136.737 -221.419 -93.6557 +136.755 -221.909 -93.3701 +136.914 -221.87 -93.4524 +136.754 -221.805 -93.4035 +136.197 -221.776 -93.0632 +136.358 -221.759 -93.1993 +136.908 -222.435 -93.5934 +136.931 -222.125 -93.5937 +136.78 -222.167 -93.4419 +136.669 -222.365 -93.1436 +136.714 -222.248 -93.2696 +136.746 -222.362 -93.3286 +136.874 -222.016 -93.492 +136.894 -222.385 -93.5538 +136.227 -222.468 -92.6634 +136.757 -222.456 -93.4356 +136.464 -222.448 -92.9223 +135.981 -221.553 -93.0495 +135.978 -221.297 -93.2871 +136.238 -222.133 -92.8728 +136.41 -222.007 -93.1094 +135.764 -221.374 -92.9956 +135.636 -221.445 -92.66 +135.609 -221.45 -92.9502 +135.708 -221.508 -92.6882 +135.863 -222.123 -92.8316 +135.914 -221.878 -92.8393 +135.75 -222.122 -92.7114 +135.973 -221.718 -92.9303 +136.106 -221.856 -92.9164 +135.32 -222.539 -92.5543 +135.744 -222.535 -92.5632 +135.747 -222.412 -92.5255 +135.963 -222.463 -92.5103 +135.758 -222.313 -92.5577 +136.189 -222.657 -92.6052 +135.607 -222.487 -92.5145 +136.402 -222.361 -92.8523 +136.312 -222.481 -93.051 +136.368 -222.497 -92.8295 +136.592 -222.336 -92.9503 +136.433 -221.982 -93.1765 +135.981 -222.247 -92.7887 +135.942 -222.137 -92.8471 +135.638 -221.785 -92.6209 +135.669 -222.275 -92.5433 +135.135 -222.209 -93.2624 +135.081 -222.407 -92.9456 +134.799 -222.379 -93.0407 +135.256 -221.837 -93.4435 +135.328 -222.001 -93.5756 +134.839 -221.639 -93.6495 +136.419 -222.19 -92.9788 +135.894 -222.299 -93.5251 +135.817 -222.377 -93.2584 +136.331 -222.387 -93.3436 +135.827 -222.482 -93.726 +135.68 -222.707 -93.708 +135.725 -221.109 -93.5646 +135.747 -221.225 -93.5656 +135.594 -221.444 -93.2541 +135.316 -221.708 -93.2343 +135.816 -221.171 -93.451 +135.753 -221.313 -93.1382 +136.319 -221.505 -93.366 +136.106 -221.237 -93.5259 +135.232 -220.72 -93.1302 +134.619 -221.732 -92.9171 +135.325 -221.987 -92.4012 +135.36 -221.712 -92.6853 +134.227 -221.294 -92.6182 +134.094 -221.255 -92.7148 +134.65 -221.647 -93.483 +134.762 -221.693 -93.4663 +134.427 -222.183 -93.2768 +134.404 -222.246 -92.9964 +134.608 -221.745 -92.7832 +135.576 -222.358 -93.3371 +135.531 -222.528 -92.6205 +135.567 -222.546 -93.7155 +135.585 -222.392 -93.5432 +134.601 -222.866 -93.1135 +134.562 -222.895 -93.3539 +134.732 -222.416 -92.8656 +134.634 -222.451 -93.0526 +134.082 -223.629 -93.4744 +134.023 -223.706 -93.7366 +134.437 -223.255 -93.0727 +134.556 -222.534 -93.0803 +134.391 -222.415 -93.1279 +134.445 -222.514 -93.1027 +134.593 -222.706 -93.191 +134.439 -221.98 -92.5381 +134.65 -222.118 -92.5801 +134.918 -222.479 -92.6413 +134.337 -222.54 -93.1751 +134.397 -222.439 -93.326 +132.976 -222.637 -92.8597 +133.914 -222.645 -93.2414 +134.366 -221.623 -92.3534 +134.701 -222.21 -92.6789 +135.116 -221.809 -93.0928 +135.543 -221.846 -92.5254 +135.394 -221.92 -92.4831 +135.554 -222.149 -92.4193 +134.815 -221.923 -92.1717 +134.956 -221.981 -92.1779 +135.177 -221.995 -92.2574 +135.469 -222.172 -92.3607 +135.13 -222.271 -92.3834 +135.097 -222.014 -92.2429 +134.921 -222.02 -92.2035 +135.054 -222.143 -92.3458 +135.006 -222.253 -92.4385 +134.384 -221.733 -92.3148 +134.494 -221.755 -92.8659 +134.411 -221.907 -92.7818 +133.421 -222.723 -92.1595 +135.062 -221.942 -92.2492 +134.733 -221.785 -92.3263 +134.551 -221.767 -92.2694 +135.715 -221.435 -92.7215 +135.56 -221.545 -92.6147 +134.42 -221.443 -92.7368 +134.454 -221.658 -92.7193 +134.319 -221.681 -92.6218 +134.121 -221.501 -92.4988 +134.324 -221.464 -92.5115 +134.145 -221.516 -92.5947 +134.184 -221.466 -92.4751 +134.391 -221.256 -92.8068 +134.27 -221.003 -92.8953 +133.041 -222.872 -92.2383 +132.837 -222.728 -92.1832 +133.421 -222.834 -92.097 +132.846 -222.451 -92.353 +132.794 -222.741 -92.2225 +133.093 -223.858 -92.8472 +133.223 -223.901 -92.9083 +133.125 -223.995 -92.9942 +133.359 -223.36 -93.0879 +133.571 -223.295 -92.9656 +133.302 -222.967 -92.6716 +133.445 -222.779 -92.7995 +133.173 -222.419 -92.7512 +133.628 -222.735 -93.0246 +133.506 -222.985 -92.9189 +132.8 -222.811 -92.3053 +133.175 -223.182 -92.9964 +132.944 -222.91 -92.7067 +133.02 -222.987 -92.8692 +133.403 -222.634 -92.6639 +133.603 -223.04 -92.9826 +133.417 -222.964 -92.8442 +133.447 -223.108 -92.9316 +133.504 -222.641 -92.8539 +133.438 -222.515 -92.9993 +132.834 -223.116 -93.5558 +134.569 -223.85 -92.8563 +134.671 -223.917 -92.8605 +133.995 -222.593 -93.3406 +133.332 -222.475 -93.1427 +132.859 -222.829 -92.1792 +132.959 -222.369 -92.6674 +133.702 -222.645 -93.1267 +134.149 -222.589 -93.429 +133.37 -222.714 -93.8774 +132.948 -222.913 -93.3709 +134.209 -222.932 -93.1095 +134.176 -223.093 -93.0831 +134.17 -223.248 -93.0502 +134.028 -223.4 -92.9585 +134.276 -223.52 -92.9734 +133.831 -223.289 -93.0066 +133.677 -223.58 -93.1648 +133.59 -223.856 -93.0938 +132.991 -222.781 -93.6611 +132.993 -222.848 -92.9505 +133.969 -222.745 -93.7223 +133.487 -222.789 -94.0334 +132.742 -223.186 -93.8717 +133.448 -223.306 -94.1759 +133.13 -222.989 -94.0451 +133.07 -223.331 -97.6489 +132.885 -223.177 -97.8019 +133.462 -223.365 -97.3353 +134.517 -223.524 -93.6819 +133.919 -223.439 -94.243 +133.926 -223.67 -93.612 +133.054 -223.617 -93.7641 +133.512 -223.744 -93.9656 +133.088 -223.346 -92.9496 +133.467 -223.645 -94.1066 +133.285 -223.711 -93.6326 +134.059 -223.891 -93.912 +134.212 -223.781 -93.7732 +134.962 -223.866 -92.8752 +133.222 -223.372 -93.0358 +132.855 -223.947 -92.9299 +132.89 -223.931 -92.8353 +134.55 -223.723 -93.4536 +134.882 -223.96 -92.8678 +132.762 -223.87 -92.8076 +132.674 -223.713 -92.8932 +132.829 -223.66 -92.8223 +133.286 -223.69 -92.9293 +133.74 -223.38 -93.0083 +134.209 -223.55 -93.0537 +134.308 -223.691 -93.2224 +133.996 -223.582 -93.4212 +133.823 -223.755 -93.7171 +133.622 -223.743 -93.7649 +134.026 -223.55 -93.2322 +133.052 -223.669 -93.5248 +132.974 -223.558 -93.572 +133.573 -223.798 -93.0454 +132.924 -223.874 -92.7579 +134.595 -223.362 -92.9997 +134.309 -223.63 -93.036 +134.372 -223.607 -92.942 +134.633 -223.783 -92.8281 +133.054 -223.588 -92.8304 +132.635 -223.512 -92.9611 +134.487 -223.838 -93.2121 +135.054 -223.644 -92.9959 +134.415 -223.526 -92.9176 +132.882 -222.277 -92.3855 +132.888 -223.327 -92.9408 +132.632 -223.539 -92.8646 +132.776 -223.017 -93.8591 +131.918 -223.255 -97.4466 +131.931 -222.757 -97.4238 +131.999 -224.321 -96.6332 +131.955 -224.047 -96.5749 +133.379 -223.607 -97.3887 +133.4 -223.814 -97.7511 +133.384 -223.543 -97.3019 +133.46 -223.251 -96.473 +133.377 -223.025 -96.4934 +133.836 -223.264 -96.7032 +133.669 -223.189 -96.5359 +133.587 -223.574 -96.4199 +133.762 -223.79 -96.5905 +133.835 -223.397 -96.5036 +133.856 -223.519 -96.4478 +131.818 -223.464 -97.2339 +132.234 -224.549 -97.4715 +132.36 -224.032 -97.2596 +133.402 -223.133 -97.7854 +133.643 -223.167 -97.7866 +133.54 -223.317 -97.398 +132.707 -222.353 -98.5462 +133.64 -223.595 -97.5788 +133.804 -223.436 -97.4581 +133.51 -223.07 -97.9825 +133.109 -223.54 -97.3051 +133.375 -223.318 -97.3881 +133.148 -223.695 -97.7122 +132.984 -223.559 -97.3664 +133.491 -223.042 -98.6763 +134.606 -223.951 -97.7988 +134.088 -224.111 -96.548 +132.722 -223.548 -97.3834 +133.134 -223.107 -97.8582 +131.903 -222.495 -97.5732 +132.024 -223.79 -97.0352 +132.113 -223.601 -97.271 +132.429 -223.494 -97.5035 +131.987 -223.158 -97.4996 +132.1 -223.28 -97.5253 +132.317 -223.086 -97.7615 +132.59 -223.308 -97.6749 +132.616 -222.831 -98.1664 +131.899 -222.39 -98.2577 +131.661 -224.342 -96.8626 +131.496 -225.918 -97.3381 +131.573 -225.819 -97.3496 +131.658 -225.577 -97.4867 +132.085 -223.981 -96.956 +132.298 -223.962 -97.1094 +131.697 -225.275 -97.6863 +131.638 -225.12 -97.7184 +131.825 -224.701 -97.786 +131.708 -224.784 -97.7294 +131.714 -224.738 -97.4508 +131.624 -224.438 -97.0292 +131.852 -224.456 -96.7244 +131.956 -224.452 -97.143 +131.788 -224.457 -96.9623 +133.755 -223.76 -96.4363 +131.732 -225.077 -97.8206 +132.045 -224.658 -97.4578 +132.026 -224.527 -98.7344 +132.31 -224.407 -98.1656 +132.347 -224.359 -98.4983 +131.775 -224.684 -98.3202 +131.91 -224.636 -98.0586 +132.128 -224.575 -97.9768 +132.917 -223.844 -97.8279 +132.705 -224.181 -98.1843 +132.886 -224.013 -98.0001 +132.368 -224.46 -97.6508 +132.538 -224.083 -97.6622 +132.642 -223.79 -97.1675 +132.521 -223.155 -97.8362 +133.266 -223.955 -98.1277 +133.242 -223.827 -97.9115 +133.898 -223.549 -97.6568 +133.693 -223.825 -97.9816 +133.004 -224.035 -98.1267 +133.107 -224.243 -98.6911 +132.951 -224.26 -98.4587 +132.043 -224.381 -97.0495 +132.116 -224.291 -96.8486 +132.139 -224.07 -96.9019 +132.037 -224.19 -96.5843 +134.84 -223.889 -98.3095 +135.158 -223.765 -98.1276 +132.105 -223.893 -96.9768 +131.782 -223.919 -96.6124 +131.717 -224.04 -96.6641 +131.679 -223.902 -96.6643 +131.869 -224.293 -96.6525 +134.272 -223.705 -96.5544 +133.99 -224.049 -96.444 +133.855 -223.893 -96.4494 +134.337 -223.842 -96.5275 +131.755 -224.698 -99.2567 +132.204 -224.503 -98.9345 +133.1 -221.519 -100.568 +132.674 -221.264 -100.584 +132.249 -221.93 -100.511 +132.811 -221.924 -100.45 +132.39 -222.365 -100.353 +131.984 -222.302 -98.0938 +132.485 -222.658 -98.3021 +132.368 -222.883 -97.9352 +132.812 -222.653 -98.3141 +132.615 -222.572 -98.4407 +132.708 -222.47 -98.3947 +134.08 -224.162 -98.8356 +133.472 -224.121 -98.7103 +133.928 -224.397 -99.0235 +132.918 -224.334 -98.872 +132.708 -224.277 -98.6517 +135.566 -223.738 -97.927 +135.814 -223.751 -98.0252 +132.489 -224.295 -97.9112 +131.681 -224.873 -98.1824 +131.802 -224.719 -98.0163 +131.738 -224.862 -97.8545 +134.065 -223.815 -98.1343 +131.796 -224.693 -98.7238 +133.377 -224.252 -99.1214 +133.866 -224.227 -98.9103 +134.861 -223.833 -97.729 +134.548 -222.576 -99.2511 +134.674 -224.312 -99.0932 +131.923 -224.838 -100.416 +132.027 -224.609 -99.6066 +134.42 -223.833 -98.7064 +132.77 -224.606 -100.24 +133.018 -224.454 -100.23 +135.7 -224.047 -100.08 +135.357 -224.031 -98.8273 +135.721 -224.048 -99.1561 +134.894 -224.043 -98.7377 +134.658 -224.193 -99.6393 +135.642 -224.025 -98.7591 +135.423 -224.055 -98.497 +134.551 -224.206 -98.8493 +135.031 -224.193 -98.9951 +134.874 -224.268 -99.1296 +134.4 -224.223 -99.6635 +137.346 -222.122 -98.425 +137.41 -222.939 -99.163 +137.438 -223.27 -99.4223 +137.342 -223.378 -99.3123 +137.456 -223.159 -99.8129 +136.542 -223.814 -99.3572 +136.987 -223.565 -99.8526 +137.432 -223.297 -99.8263 +136.378 -224.566 -99.1439 +135.73 -224.653 -98.5449 +136.027 -224.709 -99.6181 +135.743 -224.067 -98.7299 +135.71 -224.626 -98.2283 +135.75 -224.594 -98.1202 +135.734 -224.129 -98.3495 +137.113 -223.522 -98.4293 +137.432 -223.319 -98.6528 +134.864 -221.747 -99.2905 +134.701 -223.928 -98.6719 +134.34 -223.964 -98.8031 +134.709 -221.49 -100.008 +134.91 -221.728 -100.261 +135.109 -224.014 -98.7403 +134.408 -224.134 -98.8137 +134.869 -223.958 -98.6444 +134.469 -223.912 -98.0839 +135.268 -223.848 -98.3464 +134.292 -223.874 -98.7368 +135.335 -223.731 -98.2201 +135.516 -223.765 -98.2933 +135.731 -224.032 -98.2595 +135.794 -223.904 -98.1835 +135.566 -223.987 -98.3516 +135.34 -223.668 -97.8047 +137.091 -223.588 -98.0981 +137.178 -223.452 -98.0717 +136.7 -223.763 -98.1132 +136.344 -224.011 -98.1768 +136.112 -223.03 -98.2181 +136.356 -224.435 -98.1839 +135.861 -224.039 -98.1839 +136.128 -223.858 -98.0673 +136.451 -223.713 -98.048 +136.45 -223.859 -98.0696 +136.026 -224.584 -98.0315 +136.219 -224.414 -98.0023 +136.059 -224.087 -98.0825 +136.246 -224.247 -98.0203 +136.042 -224.193 -97.9807 +135.911 -224.19 -98.0184 +136.202 -224.029 -98.0704 +136.218 -223.485 -97.9065 +135.743 -223.419 -97.8617 +135.988 -223.643 -97.9368 +134.496 -223.73 -97.4054 +135.132 -223.683 -97.6667 +135.555 -223.538 -97.7461 +135.66 -223.438 -97.7748 +135.952 -222.986 -98.3058 +136.043 -223.197 -98.1141 +135.845 -223.247 -98.0002 +135.492 -223.42 -97.5461 +134.815 -223.805 -97.441 +135.556 -223.226 -97.5654 +135.348 -223.198 -97.3313 +136.557 -222.752 -98.5743 +135.665 -222.895 -98.1015 +135.415 -223.272 -97.362 +136.126 -223.755 -98.0244 +136.222 -223.577 -97.9099 +135.937 -223.792 -98.05 +136.477 -223.336 -97.9563 +137.351 -223.439 -98.0637 +136.942 -223.485 -98.0786 +136.719 -223.159 -98.0766 +136.709 -222.946 -98.1874 +137.223 -223.264 -98.0679 +137.456 -223.289 -98.0354 +136.921 -223.273 -98.1299 +136.939 -222.9 -98.1761 +137.121 -222.82 -98.1536 +136.715 -222.665 -98.5045 +136.612 -222.883 -98.368 +136.709 -223.52 -97.999 +136.771 -223.642 -98.001 +136.005 -223.418 -97.9555 +135.372 -222.607 -98.7452 +136.366 -222.67 -98.8447 +136.074 -222.856 -98.4987 +137.308 -221.707 -98.4825 +136.933 -222.76 -98.2382 +135.152 -222.071 -98.167 +135.092 -222.134 -98.3419 +135.154 -222.639 -97.6771 +134.846 -222.369 -97.9344 +134.748 -223.165 -97.2044 +134.544 -223.209 -97.3437 +136.585 -221.756 -98.9429 +137.093 -222.401 -98.2009 +137.254 -221.494 -99.0315 +137.007 -222.264 -98.3671 +137.074 -221.383 -98.0946 +137.027 -222.6 -98.2447 +137.245 -221.482 -98.1558 +137.136 -221.637 -98.1224 +137.152 -222.006 -98.1285 +135.235 -222.405 -98.1517 +135.312 -222.873 -97.5733 +137.413 -221.287 -98.1458 +137.271 -221.421 -98.4633 +137.898 -221.094 -98.2881 +137.995 -221.054 -99.0321 +137.435 -221.196 -98.6757 +137.278 -221.376 -98.2787 +137.889 -221.085 -98.1441 +135.971 -221.022 -99.9212 +135.916 -220.727 -99.9507 +134.822 -221.705 -99.4729 +134.866 -221.727 -99.1444 +136.235 -220.572 -100.22 +134.742 -221.86 -99.8478 +134.875 -221.82 -99.9209 +137.391 -221.232 -99.6543 +137.384 -221.179 -99.7374 +137.26 -221.397 -99.4894 +137.313 -221.996 -99.8743 +136.467 -221.968 -99.0984 +136.585 -222.332 -98.9447 +136.868 -221.829 -98.5004 +138.417 -221.091 -98.5988 +137.096 -220.488 -100.668 +136.824 -220.709 -100.665 +138.154 -221.113 -99.2438 +137.376 -221.253 -98.7648 +138.01 -221.079 -99.7656 +138.104 -221.133 -98.4218 +138.874 -220.899 -98.2874 +139.06 -220.968 -98.3697 +139.019 -220.928 -98.4894 +139.005 -220.989 -98.5082 +139.522 -220.791 -98.0616 +137.764 -221.184 -98.2903 +137.768 -221.15 -100.022 +138.074 -221.123 -99.6919 +137.801 -220.926 -100.582 +138.826 -220.875 -99.4635 +139.345 -220.801 -99.7721 +139.344 -220.834 -98.6917 +139.522 -220.917 -98.4098 +139.214 -220.839 -98.0968 +138.655 -221.041 -98.1629 +138.154 -221.04 -98.1356 +138.816 -220.993 -98.0788 +138.325 -221.077 -98.1475 +139.221 -220.951 -98.086 +137.576 -221.204 -98.064 +139.491 -225.147 -101.576 +139.413 -224.843 -101.661 +138.448 -223.775 -101.418 +138.924 -223.776 -101.622 +138.865 -224.178 -101.634 +135.258 -223.336 -97.273 +134.689 -223.471 -97.2105 +135.124 -223.281 -97.1966 +135.109 -223.489 -97.3123 +134.386 -223.881 -96.6075 +134.525 -223.537 -97.2487 +134.275 -223.49 -97.4125 +134.605 -223.376 -97.1911 +134.404 -223.224 -97.4647 +134.63 -223.291 -97.1921 +134.872 -223.266 -97.1642 +134.322 -223.98 -96.5 +138.887 -221.337 -101.552 +139.255 -222.762 -101.788 +139.229 -223.503 -101.782 +133.926 -226.869 -101.371 +138.43 -223.462 -101.63 +138.536 -223.489 -101.622 +139.405 -225.423 -101.602 +137.253 -225.954 -101.331 +137.085 -226.431 -101.411 +138.951 -225.219 -101.37 +138.717 -225.173 -101.191 +137.247 -225.739 -101.336 +138.395 -226.291 -101.373 +138.289 -225.7 -101.347 +138.384 -226.101 -101.365 +137.627 -221.381 -101.592 +138.189 -221.214 -101.516 +137.66 -221.302 -101.466 +137.508 -221.358 -101.289 +137.856 -221.492 -101.658 +137.631 -221.966 -101.645 +135.699 -225.198 -101.231 +136.36 -224.679 -101.426 +136.345 -225.347 -101.387 +136.346 -225.06 -101.197 +135.337 -224.954 -101.385 +134.433 -225.045 -100.766 +134.576 -225.076 -101.165 +135.449 -226.331 -101.509 +132.937 -226.977 -101.266 +134.529 -226.734 -101.428 +134.456 -225.515 -101.37 +134.871 -225.965 -101.441 +135.358 -226.143 -101.506 +134.213 -225.049 -101.149 +135.234 -225.912 -101.48 +134.91 -225.178 -101.45 +135.859 -225.236 -101.214 +135.615 -225.34 -101.435 +135.793 -225.648 -101.456 +135.086 -225.005 -101.432 +135.337 -225.618 -101.487 +134.96 -224.842 -100.703 +135.473 -224.641 -100.696 +135.67 -225.763 -101.482 +134.473 -224.565 -100.667 +134.333 -224.61 -100.952 +134.519 -225.024 -100.68 +135.401 -226.909 -101.503 +136.35 -226.107 -101.451 +136.104 -226.426 -101.475 +136.273 -226.648 -101.474 +136.377 -226.427 -101.48 +136.052 -225.581 -101.444 +137.048 -226.739 -101.504 +136.55 -224.935 -101.438 +136.075 -225.144 -101.181 +138.526 -224.305 -101.591 +138.716 -224.392 -101.629 +136.393 -225.396 -101.404 +136.43 -224.838 -101.431 +137.141 -226.959 -101.391 +136.78 -225.653 -101.292 +136.676 -226.484 -101.446 +136.98 -225.916 -101.36 +137.886 -226.511 -101.382 +138.179 -226.266 -101.28 +138.275 -226.124 -101.263 +138.188 -225.728 -101.106 +137.059 -225.185 -101.378 +135.674 -224.132 -100.63 +135.745 -224.172 -100.604 +136.536 -226.073 -101.435 +137.211 -225.312 -101.366 +137.214 -225.547 -101.329 +137.214 -224.362 -101.393 +137.54 -224.324 -101.47 +136.467 -225.287 -101.362 +138.059 -224.793 -101.559 +137.445 -226.172 -101.375 +137.658 -226.027 -101.252 +137.46 -226.313 -101.397 +137.784 -226.785 -101.394 +137.533 -226.671 -101.376 +137.121 -223.94 -101.525 +136.654 -224.024 -101.511 +137.467 -223.465 -101.364 +136.759 -223.797 -100.466 +136.567 -223.923 -101.431 +137.547 -223.401 -100.961 +137.487 -223.351 -100.428 +136.4 -224.581 -101.09 +137.794 -224.533 -101.479 +136.37 -225.129 -101.18 +136.397 -224.458 -101.409 +136.485 -224.435 -101.44 +136.712 -225.149 -101.452 +136.796 -224.818 -101.392 +136.485 -224.567 -101.405 +136.495 -224.688 -101.462 +137.406 -225.205 -101.387 +138.032 -225.262 -101.399 +137.819 -225.514 -101.356 +136.131 -224.968 -101.236 +137.118 -223.618 -100.617 +137.44 -223.549 -101.613 +137.476 -223.83 -101.498 +139.037 -224.435 -101.563 +138.898 -224.86 -101.657 +138.56 -224.893 -101.596 +139.173 -225.207 -101.559 +138.47 -225.191 -101.216 +138.217 -225.241 -101.278 +139.065 -224.63 -101.592 +138.624 -223.48 -101.717 +139.232 -224.556 -101.605 +138.226 -224.018 -101.526 +138.372 -223.798 -101.441 +138.148 -224.518 -101.621 +138.151 -223.82 -101.684 +138.261 -224.379 -101.594 +138.077 -224.064 -101.764 +138.125 -223.542 -101.581 +138.551 -223.425 -101.672 +137.534 -224.19 -101.51 +139.122 -223.821 -101.779 +137.801 -224.421 -101.49 +138.111 -224.396 -101.667 +137.967 -224.067 -101.768 +137.759 -223.77 -101.504 +137.663 -224.097 -101.578 +138.567 -223.304 -101.542 +138.694 -222.953 -101.668 +138.084 -225.489 -101.291 +137.921 -225.68 -101.186 +137.755 -225.79 -101.23 +138.836 -226.105 -101.498 +138.101 -226.49 -101.346 +138.742 -226.505 -101.51 +138.227 -226.696 -101.386 +138.785 -226.886 -101.558 +138.891 -225.547 -101.358 +139.163 -225.328 -101.441 +137.729 -227.006 -101.422 +137.999 -225.9 -101.146 +139.301 -224.903 -101.636 +139.05 -227.291 -101.534 +139.238 -226.779 -101.619 +138.998 -221.498 -101.701 +139.34 -221.28 -101.478 +139.269 -221.28 -101.475 +138.023 -222.708 -101.607 +137.622 -223.599 -101.62 +137.937 -222.661 -101.51 +137.945 -222.799 -101.479 +137.591 -223.154 -101.36 +137.632 -223.39 -101.549 +137.591 -223.329 -101.253 +137.594 -223.011 -101.516 +137.753 -223.059 -101.561 +137.948 -223.04 -101.482 +138.204 -223.198 -101.679 +138.404 -223.097 -101.55 +138.501 -222.693 -101.669 +138.103 -223.224 -101.658 +138.719 -222.428 -101.658 +139.415 -222.366 -101.794 +137.346 -222.4 -100.282 +138.366 -222.489 -101.71 +138.208 -222.917 -101.634 +138.009 -222.203 -101.695 +138.475 -223.389 -101.612 +138.663 -223.216 -101.458 +138.47 -221.859 -101.8 +137.914 -221.99 -101.674 +139.068 -222.604 -101.773 +138.797 -222.297 -101.705 +138.835 -221.692 -101.784 +139.424 -221.57 -101.557 +139.076 -221.824 -101.684 +138.687 -221.974 -101.84 +138.598 -221.125 -100.915 +138.662 -221.157 -101.579 +137.38 -221.507 -101.102 +139.288 -220.702 -100.53 +139.154 -220.858 -100.375 +137.494 -221.311 -100.759 +138.488 -221.066 -100.33 +138.372 -220.838 -100.653 +138.251 -220.932 -100.582 +138.294 -220.804 -100.663 +137.305 -221.308 -99.9778 +137.431 -221.203 -100.279 +137.463 -220.835 -100.596 +137.027 -221.179 -100.381 +137.293 -221.206 -100.13 +138.188 -221.084 -99.7977 +137.617 -221.196 -100.223 +138.983 -220.887 -99.8281 +138.769 -220.998 -100.283 +138.821 -220.955 -99.8881 +137.126 -223.482 -100.331 +137.391 -223.343 -100.184 +137.43 -222.117 -100.545 +137.347 -221.404 -100.612 +138.098 -225.735 -101.105 +138.114 -225.931 -101.149 +137.789 -221.168 -99.8052 +137.314 -221.803 -100.312 +137.311 -222.113 -100.256 +137.349 -221.278 -100.268 +137.277 -221.375 -100.286 +136.987 -221.125 -100.511 +137.35 -221.141 -100.518 +134.865 -222.021 -100.028 +134.379 -222.15 -99.9091 +134.847 -221.776 -99.6682 +134.832 -221.115 -100.108 +134.711 -221.279 -100.082 +135.185 -220.605 -100.275 +135.116 -221.585 -100.312 +135.057 -221.795 -100.299 +137.421 -221.002 -100.587 +133.377 -221.484 -100.526 +133.796 -221.487 -100.35 +135.095 -224.072 -100.444 +134.845 -224.042 -100.343 +133.786 -221.21 -100.52 +134.051 -220.996 -100.503 +135.401 -224.112 -100.541 +135.408 -224.141 -100.108 +134.181 -224.404 -101.059 +134.322 -224.375 -100.948 +135.007 -224.173 -100.723 +134.972 -224.324 -100.71 +133.201 -224.211 -99.6455 +133.783 -224.197 -99.5496 +134.563 -224.315 -100.682 +135.731 -224.349 -100.668 +135.696 -224.702 -100.689 +135.714 -224.083 -100.426 +134.35 -224.095 -100.298 +134.084 -224.088 -100.364 +133.426 -224.176 -100.349 +135.004 -222.44 -99.591 +134.62 -224.198 -100.658 +134.444 -224.244 -100.676 +134.597 -224.784 -100.687 +134.319 -224.993 -100.973 +133.706 -224.4 -100.623 +133.854 -224.373 -100.725 +133.712 -224.167 -100.378 +133.647 -224.501 -100.931 +134.319 -224.208 -100.627 +135.68 -224.512 -100.701 +135.222 -224.975 -100.724 +136.343 -224.111 -101.265 +135.895 -224.904 -101.21 +135.617 -224.898 -100.922 +136.336 -224.657 -100.978 +134.183 -224.814 -101.104 +133.874 -226.031 -101.344 +133.72 -225.579 -101.327 +132.768 -224.641 -100.303 +133.951 -225.113 -101.355 +135.865 -225.078 -101.19 +135.627 -225.016 -101.411 +136.615 -224.57 -101.436 +136.387 -224.008 -100.844 +134.07 -224.568 -101.258 +134.103 -224.919 -101.286 +135.371 -222.087 -100.131 +136.564 -221.191 -100.271 +135.346 -221.271 -100.196 +136.57 -220.872 -100.619 +133.846 -220.998 -100.523 +133.18 -221.616 -100.518 +134.002 -221.143 -100.43 +133.871 -224.682 -101.35 +132.233 -221.048 -100.615 +132.385 -221.48 -100.601 +132.574 -221.757 -100.547 +132.537 -222.795 -99.5687 +132.216 -222.625 -100.207 +132.152 -222.349 -100.408 +132.749 -221.619 -100.577 +132.293 -224.982 -101.198 +133.008 -224.876 -101.29 +132.361 -225.701 -101.201 +133.184 -225.26 -101.287 +132.105 -225.337 -101.176 +132.004 -225.055 -101.035 +133.359 -224.845 -101.321 +132.766 -224.882 -101.254 +132.974 -224.798 -100.896 +133.048 -224.735 -100.58 +132.407 -224.912 -101.093 +132.135 -225.159 -101.173 +132.636 -225.209 -101.233 +132.948 -224.321 -100.109 +131.808 -224.993 -100.758 +131.711 -225.314 -101.135 +132.064 -226.415 -101.181 +133.436 -226.012 -101.311 +132.24 -224.892 -100.859 +132.551 -224.773 -100.661 +132.05 -224.802 -100.313 +132.403 -224.727 -100.46 +133.505 -224.501 -100.519 +133.513 -224.336 -100.471 +132.708 -224.426 -99.8197 +132.856 -224.402 -100.092 +132.063 -224.663 -99.7581 +132.691 -224.639 -100.145 +132.362 -224.776 -99.8916 +132.447 -224.503 -99.6905 +132.398 -224.454 -99.5787 +131.669 -227.176 -101.126 +133.339 -225.061 -101.302 +134.001 -226.248 -101.361 +132.772 -227.36 -101.253 +132.539 -226.635 -101.23 +132.56 -226.988 -101.225 +132.125 -227.111 -101.185 +133.625 -227.343 -101.33 +133.876 -227.355 -101.367 +136.756 -227.258 -101.469 +137.028 -227.273 -101.494 +134.402 -227.134 -101.408 +135.973 -227.126 -101.483 +136.221 -227.101 -101.479 +136.779 -226.866 -101.493 +136.541 -227.18 -101.481 +136.561 -226.821 -101.514 +136.791 -226.702 -101.475 +137.223 -226.584 -101.374 +139.45 -227.34 -101.531 +138.289 -227.133 -101.471 +138.631 -227.251 -101.67 +137.786 -205.107 -99.5886 +135.704 -203.976 -96.5816 +136.084 -210.989 -98.4282 +133.141 -214.366 -100.139 +134.798 -213.894 -98.6263 +133.714 -221.946 -100.193 +136.521 -212.446 -95.8265 +134.952 -213.189 -100.192 +138.691 -217.295 -100.288 +133.2 -223.435 -97.3693 +135.979 -211.24 -95.238 +135.785 -214.307 -97.9936 +134.556 -222.647 -98.8197 +135.53 -211.326 -97.8237 +134.972 -221.827 -98.7374 +135.288 -216.411 -100.377 +134.772 -210.302 -97.4706 +134.612 -211.235 -96.9867 +133.144 -222.758 -99.8959 +135.705 -210.959 -95.0285 +133.535 -223.039 -99.3663 +133.607 -227.063 -101.344 +135.535 -214.247 -100.017 +133.505 -222.887 -99.6085 +133.145 -222.934 -99.3849 +136.427 -225.669 -101.37 +136.577 -225.882 -101.33 +136.357 -225.514 -101.401 +137.233 -224.738 -101.336 +137.051 -224.73 -101.321 +139.46 -224.4 -101.658 +139.495 -226.002 -101.663 +135.003 -215.331 -100.067 +135.879 -210.567 -97.8924 +136.254 -202.6 -99.7016 +136.848 -208.556 -96.3646 +137.025 -209.044 -96.658 +137.041 -208.69 -96.1767 +137.416 -209.061 -96.076 +137.319 -208.908 -95.8994 +139.185 -205.03 -100.313 +139.485 -205.176 -100.833 +139.482 -205.03 -100.613 +135.97 -210.118 -97.7365 +137.543 -212.637 -95.0533 +137.54 -212.542 -95.5789 +137.51 -212.337 -95.4034 +136.512 -207.168 -97.6077 +136.478 -207.652 -97.5976 +136.701 -208.295 -96.6836 +137.105 -207.719 -92.6875 +136.792 -206.886 -96.4118 +137.062 -207.525 -94.1185 +137.151 -207.246 -94.4431 +136.151 -206.673 -99.3077 +136.128 -206.951 -99.3922 +136.349 -206.913 -98.4578 +136.861 -207.87 -95.9052 +136.758 -206.067 -93.9152 +136.424 -206.142 -94.0902 +137.123 -202.188 -99.7245 +134.57 -202.369 -99.5446 +134.878 -206.355 -99.6603 +134.252 -205.948 -99.6825 +134.135 -204.008 -99.6067 +134.05 -204.446 -99.7016 +135.986 -203.789 -99.6545 +135.578 -203.953 -99.6221 +134.52 -203.794 -99.5623 +135.021 -203.546 -99.583 +136.857 -206.561 -96.241 +136.824 -206.191 -96.2841 +135.228 -205.482 -99.4626 +136.503 -204.849 -99.6305 +136.441 -204.54 -99.6303 +137.374 -204.191 -99.6879 +137.657 -204.891 -99.6345 +136.71 -204.147 -99.7376 +135.727 -204.375 -99.7783 +136.606 -205.322 -99.6384 +136.433 -205.664 -99.5622 +137.038 -205.56 -99.4301 +136.508 -203.692 -99.7245 +136.34 -206.751 -94.4648 +136.825 -207.038 -95.403 +136.812 -207.337 -95.1636 +136.917 -205.602 -97.8839 +137.298 -205.616 -98.9616 +136.473 -205.997 -98.0774 +136.104 -205.989 -99.4832 +136.296 -205.812 -99.488 +135.809 -206.242 -99.6192 +135.958 -206.491 -99.5788 +136.168 -205.028 -99.6335 +136.371 -203.536 -99.7001 +136.102 -205.777 -99.5674 +139.231 -205.114 -100.579 +139.104 -205.005 -99.9464 +138.382 -203.008 -99.6492 +138.535 -202.501 -99.9244 +138.709 -202.207 -100.121 +138.275 -202.558 -99.7103 +138.778 -203.513 -99.7819 +138.666 -203.682 -99.7259 +138.921 -204.057 -99.2274 +139.103 -203.897 -99.5596 +138.829 -203.946 -99.6863 +138.634 -204.154 -99.2817 +137.975 -205.107 -98.1973 +138.794 -204.193 -99.0233 +139.174 -203.524 -99.8579 +139.491 -202.719 -99.6823 +139.008 -203.27 -99.9437 +137.869 -205.337 -99.363 +137.635 -205.335 -99.4664 +138.871 -206.525 -99.902 +137.707 -205.245 -98.3026 +138.082 -205.245 -99.2263 +139.051 -203.86 -97.6856 +139.235 -203.702 -97.5379 +139.205 -202.688 -97.7443 +136.833 -205.983 -96.1751 +136.76 -206.247 -96.419 +136.882 -205.804 -96.1267 +137.219 -204.905 -97.661 +134.647 -209.801 -97.6933 +133.606 -210.881 -98.591 +133.628 -210.6 -98.0482 +133.48 -210.248 -98.5865 +135.069 -211.217 -96.3986 +134.194 -211.173 -97.3461 +135.014 -211.501 -96.9679 +135.489 -211.652 -98.0151 +134.836 -211.681 -97.3267 +135.799 -214.439 -100.424 +135.818 -214.187 -100.212 +136.98 -209.324 -97.0518 +136.011 -211.017 -98.0766 +135.836 -211.293 -98.017 +135.013 -210.007 -97.5003 +135.527 -209.616 -97.5834 +135.322 -210.812 -97.7302 +135.649 -210.621 -97.8083 +135.287 -210.177 -97.5391 +134.411 -210.85 -97.4502 +134.677 -211.358 -96.8391 +134.278 -211.715 -97.4604 +134.818 -211.553 -96.9754 +134.941 -211.073 -97.5716 +135.835 -210.817 -97.9473 +136.021 -210.826 -98.0559 +136.341 -210.727 -98.2278 +133.777 -210.001 -97.8668 +133.706 -209.655 -98.5161 +136.341 -209.325 -97.5382 +136.024 -209.386 -97.5556 +135.423 -209.245 -97.9145 +136.596 -209.374 -97.548 +136.598 -209.225 -97.4346 +134.681 -209.349 -98.2002 +137.367 -210.122 -98.4999 +137.197 -210.146 -98.816 +139.38 -208.843 -100.017 +138.731 -211.628 -100.584 +139.339 -208.614 -100.282 +134.946 -208.723 -98.7785 +134.303 -208.975 -98.9388 +135.115 -209.006 -98.3578 +135.855 -208.536 -98.3121 +135.404 -207.821 -99.5451 +136.079 -207.604 -99.4102 +136.081 -207.906 -98.8525 +136.519 -206.423 -97.6734 +136.501 -205.995 -97.4847 +134.725 -208.208 -99.5273 +134.272 -207.833 -99.8083 +136.125 -207.135 -99.5161 +135.884 -206.823 -99.6442 +135.939 -206.998 -99.6539 +136.07 -206.61 -99.4859 +133.839 -207.627 -99.7357 +134.042 -207.787 -99.9198 +133.934 -207.746 -99.8843 +133.956 -207.912 -99.7769 +134.297 -208.209 -99.5795 +133.929 -208.406 -99.3926 +134.059 -208.792 -99.2999 +133.915 -209.1 -99.0948 +133.782 -209.438 -98.8021 +134.265 -209.528 -98.2343 +134.215 -208.409 -99.5107 +134.242 -208.511 -99.4758 +133.869 -211.6 -100.294 +133.585 -211.747 -100.177 +133.521 -213.189 -100.203 +133.699 -213.353 -100.264 +133.439 -211.816 -100.165 +134.025 -211.141 -99.139 +134.143 -211.565 -98.5157 +135.972 -211.339 -98.3527 +135.886 -210.944 -98.8855 +135.445 -211.05 -99.2302 +135.099 -211.282 -99.2021 +137.134 -210.082 -99.4854 +136.064 -210.811 -98.76 +135.898 -210.486 -99.7684 +136.109 -212.911 -100.049 +134.96 -212.997 -100.311 +133.668 -211.982 -100.43 +135.308 -212.903 -100.313 +135.309 -212.775 -100.398 +135.783 -210.397 -100.159 +136.301 -211.336 -100.487 +136.979 -211.107 -100.541 +136.948 -210.303 -100.562 +135.932 -215.208 -100.486 +135.439 -214.672 -100.347 +135.591 -214.628 -100.438 +135.404 -214.305 -99.8864 +135.21 -215.014 -100.139 +137.13 -216.921 -100.445 +135.614 -215.227 -100.473 +133.375 -215.325 -100.099 +133.534 -215.486 -99.8731 +133.513 -215.822 -100.032 +133.314 -215.968 -100.158 +133.594 -216.108 -99.9775 +135.422 -216.195 -100.369 +133.507 -214.377 -100.14 +133.527 -214.145 -100.163 +133.504 -214.599 -100.111 +133.667 -214.36 -100.081 +134.747 -213.228 -100.258 +133.89 -213.924 -100.104 +134.071 -213.886 -99.794 +134.646 -213.365 -100.119 +134.351 -213.351 -100.277 +136.134 -213.959 -100.267 +135.285 -213.165 -100.023 +136.406 -213.6 -100.367 +133.68 -216.267 -99.9096 +133.801 -216.391 -99.8754 +133.786 -216.583 -99.4097 +133.379 -214.961 -100.072 +133.245 -214.477 -100.168 +134.378 -222.976 -98.1095 +136.289 -221.81 -99.3192 +136.129 -221.51 -99.5597 +136.078 -222.078 -99.4519 +135.621 -222.057 -99.8952 +136.06 -222.304 -99.401 +135.076 -221.029 -100.153 +135.036 -221.223 -100.196 +135.214 -221.209 -100.201 +135.508 -220.951 -100.11 +136.449 -219.239 -100.342 +137.37 -217.287 -100.365 +135.155 -218.077 -100.505 +134.816 -220.797 -100.324 +135.128 -220.812 -100.188 +138.663 -219.97 -100.53 +139.418 -219.701 -100.372 +138.186 -219.606 -100.082 +137.596 -219.796 -99.854 +133.338 -216.177 -98.6092 +133.504 -215.526 -99.0444 +133.54 -216.132 -99.5445 +135.695 -213.901 -99.0236 +135.647 -213.665 -99.0637 +136.042 -213.522 -99.6004 +134.225 -213.775 -99.6339 +134.15 -214.088 -99.2087 +135.363 -213.577 -99.1812 +135.284 -213.832 -98.5985 +134.628 -214.544 -97.6426 +134.497 -214.344 -97.8892 +135.541 -214.666 -98.8869 +135.119 -213.504 -99.4402 +137.555 -212.557 -94.8197 +137.604 -212.802 -94.6116 +135.564 -214.118 -99.1608 +134.404 -213.746 -99.4146 +133.93 -214.393 -99.0497 +133.655 -214.721 -99.2811 +135.639 -214.217 -98.6935 +136.238 -215.649 -98.2206 +135.992 -216.251 -98.3074 +137.577 -213.073 -94.8573 +137.095 -212.815 -95.6154 +137.522 -211.818 -94.6351 +137.452 -211.384 -94.3341 +137.246 -211.253 -94.2633 +137.55 -211.39 -94.1088 +135.781 -210.763 -94.8612 +136.018 -210.6 -94.8297 +135.489 -211 -94.7937 +137.471 -209.845 -95.3336 +136.85 -206.71 -95.5946 +137.023 -208.173 -95.2776 +136.246 -206.456 -93.2244 +137.2 -207.009 -93.3058 +136.461 -206.625 -93.0093 +136.421 -207.217 -93.0814 +136.721 -208.775 -92.8043 +136.962 -208.717 -92.8848 +136.978 -211.156 -94.1158 +136.982 -211.232 -94.0183 +137.565 -211.553 -93.4025 +137.66 -213.03 -94.0902 +137.502 -212.08 -95.9587 +137.6 -219 -93.8149 +133.446 -223.038 -99.0792 +133.248 -222.936 -98.1477 +133.6 -223.058 -99.1159 +132.618 -222.423 -100.287 +133.211 -223.012 -97.9699 +132.514 -222.61 -98.6374 +132.842 -222.794 -98.1958 +132.716 -222.647 -98.2864 +132.799 -222.586 -98.4868 +133.58 -223.068 -98.1862 +132.966 -224.162 -98.2988 +132.988 -223.677 -97.5662 +133.108 -223.845 -97.948 +133.976 -222.941 -98.4206 +133.914 -223.126 -97.9814 +134.193 -223.1 -97.926 +133.402 -224.035 -98.4352 +133.146 -224.118 -98.3588 +133.773 -224.198 -98.9345 +132.349 -224.48 -99.1133 +134.672 -222.697 -98.5435 +135.832 -222.671 -98.9804 +135.491 -222.563 -99.1839 +135.849 -222.816 -98.5741 +135.721 -223.199 -97.8569 +135.827 -223.043 -98.1502 +135.774 -222.874 -98.3338 +135.385 -222.604 -98.3165 +135.657 -222.78 -98.5297 +135.065 -222.38 -97.8581 +135.155 -222.385 -97.9107 +135.05 -221.952 -98.2043 +136.556 -221.637 -99.0712 +136.796 -221.511 -98.6868 +135.384 -222.577 -98.062 +134.62 -222.839 -97.6741 +134.689 -222.514 -97.9876 +134.764 -222.436 -98.169 +137.05 -221.612 -98.1968 +136.77 -221.759 -98.6532 +136.624 -222.036 -98.9095 +136.079 -222.69 -98.8814 +136.943 -221.272 -98.8385 +136.407 -221.653 -99.2594 +136.415 -221.505 -99.3488 +136.679 -222.193 -98.8621 +136.846 -222.164 -98.6338 +137.032 -221.887 -98.2951 +138.411 -220.958 -99.2617 +138.663 -223.947 -101.504 +138.813 -224.065 -101.561 +137.447 -223.175 -99.2209 +134.341 -223.18 -97.6007 +134.547 -222.813 -97.898 +134.823 -222.665 -97.6393 +134.346 -223.361 -97.3819 +134.187 -226.412 -101.393 +134.844 -225.048 -101.44 +135.374 -225.221 -101.457 +135.531 -225.39 -101.464 +135.466 -225.863 -101.497 +135.796 -225.341 -101.381 +135.915 -225.728 -101.437 +136.254 -225.253 -101.201 +136.124 -225.715 -101.425 +136.687 -226.069 -101.376 +137.666 -224.538 -101.385 +135.99 -225.431 -101.444 +136.836 -224.957 -101.252 +137.167 -226.296 -101.424 +137.089 -224.183 -101.456 +137.053 -225.074 -101.316 +136.923 -224.877 -101.235 +137.546 -224.704 -101.335 +137.662 -224.693 -101.483 +137.831 -225.195 -101.418 +137.852 -224.937 -101.498 +137.684 -225.099 -101.427 +138.651 -224.806 -101.628 +138.954 -224.693 -101.634 +138.941 -224.337 -101.604 +138.706 -223.818 -101.579 +138.421 -224.158 -101.457 +138.362 -224.328 -101.526 +138.543 -224.152 -101.472 +138.998 -224.198 -101.676 +137.902 -224.72 -101.533 +138.633 -225.1 -101.385 +136.919 -224.006 -101.506 +137.31 -225.125 -101.367 +137.939 -226.343 -101.313 +137.268 -226.471 -101.343 +137.512 -226.506 -101.371 +138.561 -226.387 -101.454 +138.599 -226.792 -101.481 +138.813 -225.784 -101.415 +139.236 -225.528 -101.502 +138.977 -225.349 -101.354 +138.957 -225.052 -101.504 +139.214 -226.222 -101.588 +138.923 -226.826 -101.585 +139.468 -226.691 -101.647 +139.354 -225.686 -101.572 +139.23 -225.153 -101.597 +139.272 -225.363 -101.579 +139.091 -227.038 -101.547 +138.903 -227.1 -101.605 +139.172 -224.033 -101.704 +138.993 -224.018 -101.633 +139.246 -224.418 -101.627 +138.028 -222.504 -101.636 +137.854 -223.5 -101.621 +137.99 -223.574 -101.556 +138.542 -222.292 -101.753 +138.858 -223.312 -101.765 +138.773 -223.292 -101.712 +137.714 -222.407 -101.599 +139.028 -222.247 -101.74 +139.227 -223.064 -101.812 +138.958 -223.588 -101.747 +139.276 -223.765 -101.81 +139.501 -223.907 -101.747 +139.191 -223.256 -101.786 +139.504 -221.736 -101.714 +139.125 -221.651 -101.657 +139.222 -221.848 -101.717 +138.645 -221.738 -101.838 +138.251 -221.798 -101.761 +138.417 -222.205 -101.775 +138.193 -222.025 -101.737 +137.942 -221.721 -101.78 +137.694 -221.766 -101.756 +139.28 -221.685 -101.597 +138.808 -221.983 -101.808 +138.593 -221.603 -101.822 +139.209 -221.535 -101.6 +135.517 -221.28 -100.079 +137.559 -223.21 -100.824 +137.458 -221.195 -99.1319 +137.373 -222.542 -99.4502 +134.595 -221.874 -99.893 +134.557 -222.122 -99.916 +134.937 -221.903 -100.072 +135.075 -222.584 -98.8698 +135.575 -220.283 -100.251 +133.936 -222.947 -98.6404 +134.287 -222.777 -98.6822 +134.631 -221.202 -100.095 +134.665 -221.118 -100.16 +134.763 -222.313 -99.8684 +134.443 -222.452 -99.7392 +136.444 -223.875 -99.9368 +136.527 -223.843 -100.287 +134.777 -222.48 -99.4538 +135.339 -222.227 -100.047 +135.457 -222.429 -99.7144 +134.029 -225.499 -101.348 +137.353 -224.199 -101.474 +137.384 -223.996 -101.413 +137.232 -224.104 -101.479 +134.811 -225.054 -100.831 +135.408 -222.353 -99.8403 +135.554 -222.245 -99.8862 +135.118 -221.744 -100.326 +137.051 -221.199 -100.074 +136.71 -221.227 -100.103 +136.465 -221.372 -99.5001 +136.48 -221.288 -99.8366 +136.287 -221.323 -99.7251 +136.031 -221.228 -99.8084 +137.153 -221.058 -100.583 +136.511 -221.018 -100.533 +136.63 -221.11 -100.529 +133.838 -221.64 -100.236 +134.293 -221.827 -100.012 +133.615 -221.668 -100.345 +132.974 -222.631 -100.074 +133.404 -222.103 -100.212 +132.661 -222.7 -100.071 +132.835 -222.859 -99.7421 +132.934 -222.811 -98.5456 +134.187 -226.262 -101.369 +132.084 -222.54 -100.33 +132.695 -224.842 -100.99 +132.782 -222.794 -99.0612 +133.241 -221.843 -100.393 +133.796 -222.929 -99.25 +134.064 -222.773 -99.5286 +133.619 -222.725 -99.8003 +134.105 -222.276 -99.927 +133.904 -222.75 -99.6986 +132.268 -222.723 -99.9766 +132.16 -222.529 -98.873 +132.315 -222.706 -99.4212 +132.096 -222.365 -98.1965 +132.242 -222.764 -99.7766 +132.168 -222.675 -100.14 +133.613 -224.993 -101.32 +133.964 -224.855 -101.341 +133.783 -225.803 -101.322 +137.299 -227.001 -101.439 +136.928 -226.906 -101.504 +136.958 -227.077 -101.482 +137.188 -227.149 -101.459 +137.747 -226.623 -101.4 +137.986 -227.178 -101.443 +137.971 -227.008 -101.403 +138.297 -227.301 -101.533 +138.008 -226.744 -101.376 +138.725 -227.057 -101.604 +138.747 -227.215 -101.681 +139.222 -227.184 -101.511 +134.719 -221.629 -99.7586 +134.6 -221.749 -99.8446 +133.166 -224.214 -100.34 +133.263 -218.182 -100.64 +134.576 -216.862 -100.56 +134.191 -217.104 -100.532 +135.813 -224.747 -98.5231 +135.756 -224.838 -101.085 +136.51 -213.448 -100.44 +137.117 -219.887 -99.8059 +137.925 -219.888 -100.528 +137.142 -213.81 -94.0052 +134.368 -212.54 -95.0306 +134.269 -212.476 -95.108 +136.278 -213.579 -94.4052 +139.145 -218.717 -93.8763 +136.361 -222.305 -94.1443 +136.349 -224.03 -98.6592 +136.265 -220.97 -100.382 +132.757 -223.824 -97.3825 +135.299 -216.59 -100.544 +134.093 -216.598 -97.8357 +135.197 -216.549 -100.481 +135.034 -216.613 -97.5114 +134.153 -224.376 -98.9239 +133.941 -223.96 -98.5722 +134.438 -222.821 -92.9822 +135.034 -223.599 -92.9887 +134.886 -221.793 -92.9534 +135.421 -213.786 -94.8324 +134.669 -212.895 -95.1246 +133.922 -206.301 -99.8575 +133.923 -211.413 -97.8263 +138.592 -205.162 -98.1413 +138.832 -204.075 -97.8547 +139.059 -204.34 -97.7963 +138.325 -210.024 -97.1393 +138.255 -210.022 -97.4305 +135.778 -212.528 -99.6899 +135.661 -212.52 -99.9803 +138.719 -203.385 -97.9129 +135.941 -204.724 -99.7497 +135.762 -204.725 -99.6839 +138.654 -204.423 -98.5164 +138.262 -206.585 -94.8078 +137.736 -208.005 -94.6833 +138.44 -207.306 -95.8184 +136.208 -207.538 -93.0541 +139.103 -225.023 -101.629 +137.319 -226.745 -101.376 +136.924 -226.442 -101.422 +137.048 -227.016 -101.451 +134.109 -225.046 -101.321 +132.531 -224.95 -101.213 +134.698 -221.804 -99.7261 +136.381 -223.947 -99.3611 +135.029 -221.989 -100.146 +137.389 -222.237 -100.401 +135.927 -220.841 -99.9783 +136.944 -223.611 -100.391 +138.663 -221.185 -101.635 +138.74 -221.531 -101.831 +138.112 -223.714 -101.64 +138.832 -225.269 -101.234 +137.678 -225.562 -101.355 +137.839 -223.996 -101.679 +138.804 -223.63 -101.699 +138.675 -225.053 -101.505 +138.297 -225.012 -101.512 +136.575 -225.202 -101.489 +136.821 -226.185 -101.365 +136.949 -225.678 -101.278 +136.391 -225.229 -101.239 +134.499 -225.231 -101.417 +134.472 -221.975 -99.9301 +132.623 -224.238 -98.3475 +134.212 -223.307 -97.519 +133.94 -223.329 -97.5813 +134.948 -223.008 -97.288 +136.987 -221.433 -98.3061 +136.908 -221.278 -98.7084 +135.786 -222.541 -99.3171 +136.629 -221.348 -99.2472 +134.96 -222.586 -97.6559 +135.617 -222.753 -98.2631 +135.541 -222.76 -98.041 +133.638 -224.217 -99.0057 +135.129 -222.604 -98.4584 +133.455 -223.927 -98.1885 +134.874 -222.637 -98.3984 +133.93 -224.133 -98.8161 +133.686 -223.016 -98.7178 +134.294 -222.689 -99.3178 +132.462 -222.592 -98.4579 +132.765 -222.524 -98.3651 +134.296 -223.372 -92.9673 +138.703 -223.099 -101.627 +139.342 -220.909 -100.264 +137.526 -223.931 -101.418 +137.376 -205.434 -94.7861 +137.16 -206.081 -93.7807 +136.338 -206.594 -93.1346 +137.11 -206.039 -93.9955 +137.467 -205.643 -94.3094 +137.577 -205.87 -93.9882 +136.613 -206.479 -92.6312 +137.442 -206.323 -94.02 +138.033 -206.283 -93.8624 +138.195 -206.406 -94.6811 +137.59 -206.44 -94.1221 +137.506 -208.029 -94.1658 +137.492 -207.973 -94.333 +137.803 -205.682 -94.7278 +137.525 -205.569 -94.3892 +137.766 -205.75 -95.3508 +134.406 -205.543 -99.593 +133.986 -205.598 -99.76 +133.921 -206.102 -99.7744 +133.982 -205.708 -99.7503 +134.844 -205.627 -99.574 +134.332 -205.156 -99.609 +134.959 -204.86 -99.5377 +134.211 -204.93 -99.5994 +134.931 -205.519 -99.4658 +134.984 -205.338 -99.3418 +139.35 -203.206 -100.007 +138.021 -203.778 -99.3866 +136.334 -204.251 -99.7889 +136.247 -204.802 -99.6078 +136.461 -205.88 -96.9477 +136.361 -205.713 -96.8887 +136.14 -204.615 -99.9133 +136.177 -204.645 -99.8726 +139.033 -205.3 -100.679 +138.738 -204.768 -98.9197 +138.523 -204.961 -99.6388 +138.395 -204.909 -99.4914 +139.416 -202.346 -100.764 +139.013 -202.138 -100.441 +138.77 -204.052 -98.6073 +138.136 -203.759 -99.3555 +138.11 -203.952 -99.3313 +138.16 -205.369 -99.5003 +139.335 -203.451 -99.8501 +139.357 -203.622 -99.4391 +138.305 -205.082 -99.5415 +138.379 -205.238 -99.6713 +138.827 -206.537 -99.3747 +139.107 -206.721 -99.5676 +138.528 -206.203 -99.3248 +139.092 -205.064 -99.1969 +138.654 -204.965 -99.7458 +139.388 -206.335 -98.3274 +139.28 -204.962 -98.4352 +138.799 -206.365 -97.7449 +138.765 -205.985 -97.6084 +138.947 -206.202 -97.9798 +137.983 -205.902 -96.5082 +138.649 -205.71 -97.5117 +138.203 -205.034 -97.8697 +139.499 -203.419 -97.4868 +139.351 -203.591 -97.4301 +139.507 -203.91 -97.6671 +138.825 -204.165 -98.8831 +138.564 -204.381 -98.9012 +138.619 -204.487 -98.7391 +137.95 -204.216 -97.7024 +138.63 -202.623 -97.8511 +139.149 -202.226 -98.5373 +139.463 -202.853 -97.5584 +137.945 -204.285 -96.485 +138.655 -205.096 -97.1959 +138.731 -205.246 -97.2624 +138.378 -206.354 -97.1589 +138.225 -206.063 -96.5949 +138.074 -206.091 -96.5939 +138.482 -205.348 -96.7773 +138.543 -205.707 -96.6775 +137.691 -205.958 -96.015 +137.441 -205.84 -96.1448 +137.998 -206.486 -96.5621 +137.758 -206.149 -96.3986 +136.152 -205.353 -96.7394 +136.934 -205.734 -96.1321 +137.106 -205.768 -96.0822 +137.129 -205.778 -95.9139 +136.742 -205.427 -96.1991 +137.775 -204.851 -96.3026 +137.437 -205.052 -96.1184 +136.175 -203.999 -96.3467 +136.347 -203.08 -96.3744 +135.928 -204.126 -96.2858 +136.23 -204.21 -96.3091 +136.314 -204.992 -97.0483 +135.984 -203.792 -96.6621 +137.387 -203.482 -97.4261 +137.828 -203.854 -97.6421 +137.991 -204.038 -98.0555 +138.23 -204.828 -97.4931 +137.469 -203.156 -97.5077 +136.986 -202.643 -97.3026 +136.688 -202.799 -96.8461 +133.683 -210.295 -97.7125 +134.093 -211.028 -97.4201 +134.064 -209.932 -97.6971 +133.835 -210.811 -97.4679 +134.289 -211.818 -94.7059 +134.562 -211.577 -94.8772 +134.037 -211.318 -97.4858 +136.192 -213.016 -99.9026 +136.446 -212.372 -99.2364 +135.533 -211.468 -97.8085 +135.654 -211.566 -97.976 +138.835 -207.846 -96.4669 +138.726 -207.591 -96.507 +138.459 -207.498 -96.6343 +138.661 -207.02 -97.088 +138.808 -206.905 -97.2101 +139.234 -207.961 -96.9884 +139.103 -208.157 -96.9493 +139.014 -207.044 -97.0764 +138.893 -207.91 -96.4777 +138.979 -207.65 -96.4897 +139.103 -209.6 -97.0099 +139.256 -208.471 -96.8745 +138.78 -208.665 -96.5874 +138.757 -209.348 -96.5133 +138.801 -209.642 -96.7166 +138.735 -208.801 -96.7261 +138.91 -209.803 -97.249 +138.316 -209.325 -96.778 +138.104 -209.82 -96.957 +137.931 -209.727 -96.7635 +138.613 -209.162 -96.5439 +138.672 -208.669 -95.9775 +139.238 -209.932 -97.8607 +139.268 -206.616 -97.6038 +138.318 -209.245 -100.612 +138.926 -208.674 -100.697 +138.928 -208.754 -100.773 +139.143 -208.58 -100.823 +139.482 -208.226 -100.767 +139.452 -207.346 -100.761 +138.135 -209.362 -100.612 +137.007 -209.833 -100.339 +134.029 -206.486 -99.8786 +137.225 -210.196 -98.4945 +135.99 -207.511 -99.6413 +134.582 -206.563 -99.6863 +133.922 -206.887 -99.8826 +133.807 -206.734 -99.9102 +133.727 -207.038 -99.3564 +133.937 -207.21 -99.9413 +133.746 -208.891 -99.3524 +134.22 -210.831 -100.111 +133.888 -210.77 -99.9999 +134.827 -211.903 -98.1258 +133.095 -212.635 -100.139 +133.475 -210.628 -99.2629 +134.553 -210.875 -100.219 +133.442 -210.721 -100.034 +133.065 -213.013 -99.7245 +133.134 -213.36 -99.5949 +136.343 -213.031 -100.084 +136.075 -212.397 -99.2644 +135.973 -212.341 -99.4605 +135.941 -212.587 -99.2788 +136.292 -212.351 -99.2167 +135.951 -212.663 -100.18 +135.867 -212.587 -100.111 +135.894 -212.513 -100.011 +136.495 -212.498 -99.7803 +136.458 -212.38 -99.6978 +136.311 -213.281 -99.7199 +136.221 -212.595 -100.309 +136.149 -212.516 -100.275 +136.156 -212.376 -100.264 +136.226 -212.091 -100.432 +135.613 -212.791 -100.202 +135.568 -212.514 -100.179 +135.487 -212.635 -100.311 +136.467 -212.541 -100.463 +135.35 -212.37 -100.476 +135.187 -211.926 -100.475 +135.082 -211.689 -100.401 +134.652 -210.863 -99.9699 +133.901 -210.893 -99.3886 +134.742 -210.802 -100.167 +135.152 -210.632 -100.219 +136.961 -210.029 -100.578 +136.697 -210.207 -100.591 +135.841 -214.331 -98.0859 +135.538 -216.327 -100.425 +134.737 -215.919 -100.201 +133.998 -216.768 -100.147 +133.935 -216.518 -100.048 +133.494 -216.842 -100.202 +134.257 -216.443 -100.032 +134.548 -216.233 -100.018 +133.778 -213.515 -100.212 +134.143 -213.558 -100.235 +134.346 -213.467 -100.207 +134.994 -215.394 -100.284 +134.53 -216.084 -100.023 +134.354 -216.209 -99.8628 +133.286 -213.373 -99.7091 +132.617 -217.513 -100.227 +133.674 -217.335 -100.561 +134.354 -217.03 -97.7781 +134.316 -217.178 -98.0596 +136.14 -220.451 -99.9381 +136.001 -220.451 -99.9008 +137.324 -220.058 -100.321 +136.692 -220.02 -99.7927 +135.771 -220.456 -100.001 +136.909 -219.52 -100.221 +137.543 -218.927 -100.188 +133.933 -217.252 -100.59 +133.407 -217.629 -100.171 +133.585 -219.939 -100.559 +139.141 -216.781 -100.265 +139.166 -216.602 -100.272 +138.428 -218.605 -99.8538 +138.678 -219.51 -100.435 +138.374 -219.056 -99.7291 +139.474 -218.702 -99.6169 +139.423 -218.455 -99.6543 +138.657 -217.404 -100.262 +138.517 -217.559 -100.24 +138.449 -218.33 -99.864 +138.745 -218.461 -99.849 +137.961 -218.204 -100.143 +137.715 -218.388 -100.28 +137.947 -218.397 -100.112 +138.026 -218.736 -100.025 +139.098 -218.387 -99.7916 +138.201 -221.075 -100.407 +138.924 -219.417 -100.409 +139.287 -220.93 -98.7228 +139.329 -220.906 -98.6681 +135.646 -216.553 -97.3747 +134.457 -217.077 -96.7475 +134.366 -217.041 -97.2052 +135.638 -215.765 -96.9465 +135.432 -215.731 -96.8818 +137.08 -218.544 -93.6041 +137.26 -218.659 -93.6696 +134.583 -216.405 -96.6327 +135.435 -215.112 -97.5363 +134.46 -214.426 -97.7152 +134.596 -214.749 -97.1375 +134.681 -214.885 -97.2157 +134.486 -214.693 -97.0262 +134.124 -215.025 -96.8816 +133.689 -215.235 -97.2874 +134.949 -215.104 -97.1324 +134.852 -216.299 -97.1039 +134.898 -216.398 -96.9751 +134.672 -216.314 -96.765 +134.514 -215.648 -97.2036 +134.658 -215.398 -97.339 +134.125 -215.92 -96.9837 +134.529 -215.3 -96.9475 +134.135 -215.88 -96.8685 +133.564 -214.92 -97.9619 +133.708 -214.814 -97.8528 +134.03 -214.398 -98.4616 +134.25 -215.904 -97.1881 +133.651 -215.942 -97.3338 +133.674 -215.826 -97.1958 +135.217 -216.329 -96.9562 +135.221 -216.625 -97.804 +134.308 -216.351 -97.2214 +134.826 -216.697 -97.2209 +134.897 -216.059 -97.4172 +135.345 -216.003 -96.9727 +135.071 -215.826 -97.2217 +135.83 -215.846 -96.903 +135.583 -215.214 -97.2869 +135.255 -215.944 -97.0378 +136.067 -214.941 -97.4264 +136.076 -215.041 -97.4005 +135.815 -215.597 -96.7233 +135.279 -215.185 -96.805 +135.108 -216.296 -97.0259 +135.645 -216.181 -97.2638 +136.06 -215.924 -96.6651 +135.707 -215.996 -97.1245 +136.025 -215.979 -96.8535 +135.692 -216.568 -97.8895 +134.844 -216.978 -97.5668 +134.231 -217.109 -98.3307 +133.749 -216.426 -97.9893 +133.894 -216.507 -98.0845 +133.817 -216.47 -98.0281 +133.544 -216.117 -97.707 +134.122 -216.343 -97.562 +134.91 -214.518 -97.8379 +134.492 -214.536 -97.459 +135.148 -214.523 -97.855 +135.254 -214.969 -97.6486 +136.176 -214.745 -97.5643 +136.305 -215.492 -97.7899 +136.521 -215.366 -97.9962 +136.293 -214.626 -97.8317 +135.881 -214.47 -97.8252 +135.05 -214.229 -97.7825 +135.695 -214.232 -98.3985 +134.49 -214.228 -97.9986 +137.1 -218.871 -93.8612 +136.919 -218.385 -93.6847 +137.557 -218.065 -93.7422 +137.191 -218.362 -93.6943 +137.083 -219.255 -94.0239 +137.6 -219.51 -93.9705 +137.481 -218.97 -93.8295 +138.016 -219.263 -94.1296 +136.675 -214.017 -94.1742 +136.806 -214.282 -94.3424 +136.324 -214.68 -93.9895 +135.266 -213.3 -93.7308 +135.189 -213.553 -94.5049 +135.373 -213.998 -94.9846 +135.908 -213.99 -94.8739 +136.326 -214.757 -94.5879 +136.23 -214.654 -94.2358 +136.125 -214.488 -94.4537 +136.202 -212.899 -93.8861 +137.383 -213.919 -94.536 +137.659 -213.556 -94.6982 +137.899 -213.77 -94.902 +137.651 -213.499 -94.9033 +135.862 -214.308 -95.0979 +136.124 -214.307 -94.3724 +136.109 -214.083 -94.4664 +136.024 -214.381 -95.2266 +135.279 -213.967 -95.1464 +134.968 -213.548 -95.2081 +134.747 -213.736 -95.405 +134.16 -213.559 -95.2571 +134.215 -213.819 -95.3762 +134.195 -213.409 -95.2531 +134.363 -211.927 -94.6419 +134.238 -212.292 -94.9731 +134.676 -212.164 -94.6618 +134.885 -212.222 -94.467 +135.238 -213.315 -93.9393 +134.779 -213.04 -94.143 +134.822 -213.216 -94.0207 +134.774 -212.807 -94.3572 +134.773 -212.587 -94.4927 +134.862 -212.343 -94.3428 +135.929 -213.534 -94.3384 +136.453 -211.98 -94.277 +136.231 -211.82 -94.5617 +136.674 -213.191 -93.9173 +136.429 -211.863 -94.4353 +136.377 -213.17 -94.2734 +136.594 -213.233 -94.2237 +136.682 -213.532 -94.1678 +136.212 -211.889 -94.4212 +137.401 -210.245 -94.8084 +137.408 -210.142 -94.7421 +136.988 -210.676 -95.0934 +137.351 -210.636 -94.8956 +137.238 -211.201 -94.4808 +136.625 -210.33 -94.4326 +136.573 -210.137 -94.505 +136.128 -211.656 -94.0694 +136.369 -211.097 -94.257 +135.421 -211.135 -94.7367 +135.114 -211.426 -94.8806 +134.975 -211.667 -94.7715 +134.826 -211.259 -96.6898 +134.853 -211.341 -96.649 +134.947 -211.517 -94.9235 +136.928 -210.244 -94.1049 +136.735 -209.944 -94.2648 +137.723 -209.664 -94.5008 +137.761 -208.091 -94.3849 +137.613 -207.981 -94.5212 +138.123 -209.313 -95.2558 +138.03 -209.446 -95.37 +137.806 -209.654 -95.345 +138.011 -208.663 -94.9312 +137.892 -206.73 -94.8938 +137.492 -207.882 -94.6147 +137.848 -208.13 -94.728 +137.39 -206.615 -94.089 +136.977 -209.451 -93.7839 +135.741 -207.422 -93.1976 +137.805 -208.166 -93.9357 +137.226 -208.216 -93.857 +137.171 -206.625 -92.6702 +137.251 -208.001 -93.0751 +136.454 -206.931 -93.0774 +137.001 -207.458 -92.6941 +137.134 -207.851 -92.3702 +137.114 -209.136 -93.6616 +137.132 -208.483 -93.74 +136.522 -208.858 -92.8839 +136.405 -208.341 -92.7875 +138.425 -208.814 -95.0391 +136.366 -209.492 -93.6139 +135.724 -209.098 -93.5286 +136.779 -208.895 -93.7694 +135.833 -208.966 -93.5088 +135.829 -210.12 -94.0452 +135.469 -209.484 -93.2398 +135.383 -209.653 -93.2669 +135.725 -211.579 -94.2915 +135.992 -211.63 -93.9107 +136.066 -211.144 -93.8803 +136.324 -210.908 -94.026 +136.278 -211.378 -94.4749 +136.213 -210.633 -94.1977 +136.695 -210.689 -93.9906 +136.525 -210.72 -94.0257 +137.272 -211.957 -93.5186 +137.226 -211.332 -93.6615 +137.295 -211.302 -93.7986 +137.672 -212.693 -93.9945 +136.855 -213.247 -94.0229 +137.148 -213.363 -94.0036 +136.079 -213.113 -94.2287 +136.236 -212.234 -93.5575 +136.448 -212.959 -93.5479 +136.392 -213.148 -93.6502 +135.506 -212.545 -93.6838 +135.048 -212.126 -94.1656 +135.837 -211.987 -93.5727 +135.561 -211.884 -93.6468 +134.925 -213.336 -93.9262 +134.907 -213.317 -94.1713 +134.717 -212.894 -93.5429 +135.083 -212.981 -93.5314 +135.383 -211.915 -93.6677 +137.068 -208.05 -92.0141 +136.881 -206.799 -92.1601 +138.146 -212.136 -93.6168 +138.012 -211.631 -93.4771 +138.125 -209.049 -94.3044 +138.552 -207.572 -95.2714 +138.46 -207.878 -95.7083 +138.718 -206.896 -94.9036 +138.153 -207.449 -94.8266 +138.246 -207.775 -95.0063 +137.954 -208.355 -94.8571 +138.301 -208.338 -94.9281 +137.852 -209.539 -95.7874 +138.141 -209.007 -95.0031 +138.035 -209.453 -94.4847 +138.168 -209.696 -94.564 +139.432 -216.811 -93.6611 +137.999 -213.908 -94.8138 +138.089 -214.278 -94.7622 +138.587 -213.854 -94.7856 +137.794 -218.794 -93.8376 +138.222 -218.87 -94.0238 +138.442 -219.142 -94.2633 +139.178 -218.54 -93.9705 +138.82 -218.739 -94.14 +138.977 -218.774 -94.12 +138.255 -218.669 -93.8519 +137.905 -219.269 -94.2336 +139.303 -218.522 -94.142 +137.741 -217.951 -93.782 +138.089 -217.955 -93.7657 +134.855 -222.128 -98.2482 +133.908 -224.388 -98.9269 +139.076 -221.283 -101.477 +137.324 -212.246 -95.9042 +137.447 -211.429 -94.5737 +137.475 -211.502 -94.7474 +135.697 -215.225 -98.8699 +133.766 -214.714 -98.2987 +135.962 -213.353 -99.5075 +135.434 -213.931 -98.4253 +135.477 -213.772 -98.8097 +135.128 -213.921 -98.263 +135.039 -213.836 -98.5393 +133.902 -214.249 -99.5716 +133.776 -214.572 -99.1149 +133.38 -214.673 -100.167 +134.369 -216.661 -99.2923 +133.989 -216.403 -99.9146 +133.594 -215.008 -99.5808 +133.542 -215.582 -99.6325 +135.237 -213.052 -100.22 +134.941 -213.363 -99.8944 +135.914 -212.147 -100.387 +135.855 -212.825 -100.141 +133.956 -208.759 -99.3755 +133.419 -210.009 -98.8496 +133.563 -209.551 -98.9174 +133.458 -209.751 -98.9042 +133.911 -211.216 -98.9174 +135.278 -211.34 -97.6385 +134.366 -211.418 -97.1942 +134.859 -211.231 -96.8038 +135.151 -211.331 -97.1432 +135.262 -211.471 -97.3397 +136.973 -205.824 -95.7702 +137.132 -205.733 -95.6565 +136.921 -206.083 -96.0936 +138.882 -204.98 -99.8355 +139.003 -203.531 -99.8787 +138.833 -202.796 -100.016 +138.455 -204.135 -99.4984 +139.112 -203.914 -99.3369 +136.832 -207.136 -95.7523 +136.687 -206.947 -95.0616 +135.891 -222.375 -93.7841 +136.398 -222.344 -94.3721 +137.047 -221.689 -93.4638 +135.834 -221.426 -92.9912 +136.126 -222.447 -92.6333 +136.448 -222.381 -93.5527 +135.747 -221.251 -93.4228 +136.421 -221.283 -93.6818 +134.619 -221.671 -93.1018 +134.45 -220.675 -93.0343 +134.464 -221.753 -93.0503 +135.23 -221.787 -93.5794 +135.213 -221.697 -93.628 +135.366 -221.651 -93.5232 +134.91 -221.795 -93.5156 +135.561 -221.473 -93.583 +135.715 -222.367 -93.439 +135.648 -222.506 -93.616 +134.255 -223.746 -93.5685 +134.706 -223.166 -93.215 +134.365 -223.196 -93.0815 +134.456 -222.347 -92.9804 +134.615 -222.498 -93.2294 +134.518 -221.628 -92.4276 +135.198 -221.792 -92.9187 +135.393 -222.299 -93.3229 +135.513 -222.314 -93.5636 +134.385 -221.908 -92.5403 +134.889 -222.427 -92.5955 +135.318 -222.511 -92.4783 +135.165 -221.845 -92.7027 +135.507 -221.716 -92.5566 +135.646 -221.502 -92.6193 +135.352 -221.672 -92.9413 +134.411 -221.468 -92.611 +134.284 -221.673 -92.4173 +133.18 -222.89 -92.2358 +133.18 -222.996 -92.5676 +132.895 -223.057 -93.2069 +133.582 -222.59 -93.4498 +134.156 -222.576 -93.2851 +134.289 -222.491 -93.2611 +132.909 -223.166 -93.011 +132.996 -223.07 -92.9832 +133.102 -222.641 -93.2416 +135.559 -222.455 -93.8286 +132.855 -223.41 -93.6499 +133.331 -223.689 -93.8637 +132.826 -223.865 -92.7404 +132.717 -223.755 -92.7979 +133.887 -223.567 -93.2716 +133.611 -223.75 -93.6209 +133.505 -223.719 -93.0144 +133.731 -223.513 -93.1456 +133.976 -223.461 -92.9498 +133.406 -223.516 -93.1001 +134.862 -223.882 -92.8355 +134.406 -223.783 -93.2784 +132.838 -222.325 -92.5054 +132.706 -223.383 -92.9246 +132.837 -223.396 -93.4719 +132.797 -223.353 -93.8246 +133.493 -223.158 -96.4583 +132.059 -222.543 -97.6278 +132.372 -224.304 -97.4257 +131.721 -225.394 -97.7257 +133.702 -223.448 -96.4244 +132.505 -224.083 -97.4853 +132.718 -223.964 -97.7234 +133.495 -223.479 -97.3096 +133.504 -223.557 -97.3448 +132.212 -224.162 -96.9462 +132.157 -224.215 -96.7123 +134.926 -223.844 -98.1247 +131.711 -224.664 -97.304 +131.99 -223.878 -96.9211 +132.407 -223.815 -97.0679 +134.103 -223.754 -96.4568 +134.08 -224.018 -98.7583 +132.517 -224.25 -98.1431 +132.559 -224.146 -97.92 +134.178 -223.738 -97.9459 +131.751 -224.715 -100.179 +131.912 -224.693 -99.9323 +132.952 -224.524 -100.255 +135.734 -224.094 -99.9462 +135.731 -224.622 -99.5691 +136.337 -224.093 -99.318 +137.357 -223.365 -98.9348 +134.685 -224.13 -98.7525 +134.505 -223.907 -98.2462 +134.73 -223.966 -97.909 +134.697 -223.886 -98.5434 +135.661 -224.027 -98.4981 +136.004 -223.996 -98.1361 +136.182 -224.663 -98.1297 +136.176 -224.182 -97.9953 +135.912 -223.5 -97.9142 +134.178 -223.54 -97.5664 +135.182 -223.567 -97.4372 +135.059 -223.748 -98.0298 +136.899 -223.664 -98.0605 +137.507 -223.315 -98.0586 +135.847 -223.647 -97.9121 +136.381 -224.011 -98.3289 +135.18 -222.151 -98.1859 +137.168 -221.268 -98.0173 +137.343 -222.738 -98.13 +137.213 -222.213 -98.1292 +137.218 -221.71 -98.141 +137.368 -221.245 -98.0443 +137.163 -221.436 -98.1221 +134.795 -221.754 -99.4488 +137.311 -221.875 -99.4635 +136.86 -222.518 -98.4791 +139.133 -220.956 -98.6768 +139.474 -220.815 -98.5624 +137.462 -223.215 -98.7165 +134.368 -223.775 -97.5495 +134.667 -223.936 -97.731 +134.114 -223.478 -96.6413 +138.517 -225.825 -101.411 +137.614 -222.816 -101.554 +135.5 -225.026 -101.452 +134.507 -225.1 -101.32 +134.428 -224.961 -100.736 +134.462 -224.721 -100.682 +136.577 -225.454 -101.396 +138.206 -225.899 -101.222 +137.657 -226.364 -101.385 +137.574 -223.344 -100.648 +137.495 -223.421 -100.547 +136.38 -224.221 -101.445 +136.477 -225.07 -101.28 +136.67 -224.828 -101.425 +137.006 -223.706 -101.51 +137.241 -223.601 -101.54 +138.142 -224.332 -101.676 +138.146 -224.005 -101.654 +137.742 -224.223 -101.577 +138.008 -223.97 -101.763 +138.253 -223.779 -101.612 +137.514 -225.667 -101.334 +136.814 -224.641 -101.4 +137.532 -222.691 -101.486 +138.051 -223.162 -101.616 +138.238 -223.643 -101.682 +137.793 -223.271 -101.591 +137.697 -223.466 -101.623 +138.35 -222.855 -101.624 +138.473 -222.976 -101.587 +137.523 -221.392 -101.552 +139.133 -221.066 -101.542 +137.615 -221.748 -101.726 +137.516 -221.67 -101.575 +137.785 -221.703 -101.784 +139.235 -221.081 -101.58 +138.122 -220.784 -100.545 +137.875 -221.13 -100.245 +137.77 -221.13 -100.435 +137.712 -221.062 -100.546 +138.345 -220.996 -100.534 +138.754 -220.853 -100.566 +138.489 -221.036 -99.6632 +139.177 -220.805 -100.535 +139.498 -220.711 -100.524 +137.454 -221.269 -100.344 +137.254 -221.44 -99.9988 +137.384 -221.311 -100.484 +136.144 -220.706 -100.268 +134.808 -221.689 -99.6981 +135.125 -224.042 -99.8016 +135.78 -224.697 -100.563 +135.695 -224.055 -99.492 +136.365 -224.667 -99.5906 +135.614 -224.07 -100.524 +136.393 -224.396 -100.269 +134.559 -224.071 -100.42 +135.006 -224.048 -100.075 +134.243 -224.129 -100.468 +133.857 -224.303 -100.581 +135.337 -224.206 -100.699 +135.604 -224.781 -100.707 +136.995 -224.62 -101.368 +135.777 -224.986 -101.242 +134.047 -224.439 -101.033 +136.381 -220.673 -100.533 +136.513 -220.656 -100.606 +133.674 -224.593 -101.32 +133.513 -224.754 -101.23 +133.087 -224.621 -100.46 +133.433 -224.647 -100.588 +133.275 -224.24 -100.412 +132.915 -224.322 -99.7639 +132.56 -224.597 -99.8172 +132.645 -224.423 -99.6851 +133.657 -224.25 -99.1753 +135.234 -227.111 -101.503 +138.501 -223.648 -101.493 +136.562 -221.518 -99.097 +133.281 -222.976 -99.492 +132.937 -222.845 -98.9705 +133.21 -222.899 -99.6719 +137.014 -208.559 -95.9606 +136.633 -208.625 -96.9189 +136.724 -209.018 -97.0854 +137.483 -212.172 -95.0238 +136.653 -207.768 -96.8852 +136.499 -208.53 -97.4062 +136.74 -207.591 -96.4881 +136.669 -207.318 -96.8456 +136.352 -207.658 -98.1576 +136.717 -206.578 -96.7204 +136.242 -206.87 -98.9391 +136.238 -206.506 -99.0444 +136.306 -207.171 -98.7047 +136.343 -206.377 -98.6662 +136.217 -206.254 -99.3189 +136.783 -208.162 -96.3654 +136.788 -207.528 -96.1702 +136.936 -208.117 -95.808 +136.85 -207.44 -95.4423 +136.698 -206.391 -96.67 +136.69 -205.845 -99.2348 +136.377 -205.571 -99.6022 +136.668 -205.844 -98.3077 +136.684 -205.759 -97.7728 +137.186 -205.62 -98.6625 +136.771 -205.836 -98.8797 +137.447 -205.532 -98.8253 +135.966 -205.949 -99.5493 +136.172 -206.118 -99.3872 +136.119 -206.309 -99.427 +138.856 -205.026 -100.09 +138.812 -205.096 -100.222 +138.781 -202.471 -100.113 +138.478 -202.331 -99.8767 +138.228 -205.122 -98.2598 +137.286 -205.584 -99.2881 +137.837 -205.303 -98.7742 +138.112 -205.162 -98.5979 +136.907 -205.938 -95.8124 +137.434 -205.249 -98.0021 +137.395 -205.418 -98.1891 +136.57 -205.41 -97.2596 +136.613 -206.219 -96.5674 +133.54 -210.536 -98.4928 +133.5 -210.602 -98.7935 +134.763 -211.223 -97.0789 +134.429 -211.174 -97.213 +135.147 -211.562 -97.3548 +135.08 -211.717 -97.7337 +134.719 -211.883 -97.8914 +134.565 -211.939 -97.9451 +136.732 -209.26 -97.3249 +135.312 -209.58 -97.6852 +135.162 -210.561 -97.6123 +134.872 -210.73 -97.5526 +135.434 -211.533 -97.7216 +135.188 -210.999 -97.6918 +134.837 -210.894 -97.5359 +134.615 -210.846 -97.4711 +134.662 -211.01 -97.4222 +134.618 -211.179 -97.2249 +134.823 -211.182 -97.4095 +136.108 -210.892 -98.1895 +136.199 -210.76 -98.1683 +136.19 -210.842 -98.347 +133.654 -210.098 -98.0218 +136.026 -209.544 -97.5776 +135.785 -209.563 -97.572 +136.309 -209.214 -97.5144 +136.303 -208.998 -97.5537 +136.055 -209.193 -97.578 +135.609 -209.394 -97.6963 +135.777 -209.392 -97.6069 +135.968 -208.979 -97.8043 +136.577 -209.083 -97.3369 +134.944 -209.188 -98.2634 +135.539 -208.485 -98.6015 +135.627 -208.944 -98.0657 +136.039 -208.111 -98.6113 +135.395 -208.244 -99.0233 +136.217 -208.569 -97.9967 +136.135 -207.782 -98.985 +136.219 -207.733 -98.7338 +135.971 -207.777 -99.1901 +136.281 -207.495 -98.6332 +136.283 -208.002 -98.2272 +136.279 -208.314 -98.0446 +136.479 -206.723 -97.8767 +136.411 -206.197 -98.3455 +136.518 -206.14 -97.5139 +136.484 -206.086 -97.8775 +135.038 -208.453 -99.0179 +136.197 -207.167 -99.2836 +134.33 -209.23 -98.5953 +135.08 -213.018 -100.29 +133.482 -215.478 -100.022 +133.487 -215.046 -99.9595 +133.53 -214.661 -99.9954 +133.454 -215.775 -100.091 +133.546 -215.869 -99.8466 +133.504 -216.071 -100.076 +135.191 -215.128 -100.306 +133.813 -214.234 -99.8762 +135.684 -213.018 -100.051 +135.655 -213.298 -99.6234 +133.669 -216.366 -99.6107 +135.941 -221.503 -99.7363 +135.754 -213.661 -99.2124 +135.952 -213.475 -99.5062 +135.755 -213.531 -99.2827 +135.581 -213.827 -98.8002 +135.637 -213.897 -98.8254 +135.234 -215.171 -99.6062 +135.186 -214.956 -99.8655 +135.301 -213.706 -98.8811 +135.537 -213.609 -99.0946 +135.135 -213.675 -98.9828 +135.632 -213.46 -99.3203 +135.344 -213.417 -99.533 +134.806 -213.573 -99.5364 +134.351 -213.726 -99.6606 +137.356 -211.323 -94.0648 +136.26 -210.395 -94.7272 +136.895 -206.699 -95.8772 +136.88 -207.628 -95.4203 +136.945 -207.839 -95.1679 +133.264 -222.971 -98.7448 +135.251 -222.421 -98.0068 +136.574 -221.423 -99.1824 +136.177 -221.391 -99.6372 +136.78 -225.224 -101.415 +137.542 -224.82 -101.413 +137.507 -225.003 -101.436 +139.236 -224.73 -101.612 +139.059 -223.6 -101.762 +139.267 -222.503 -101.803 +135.939 -221.216 -99.8047 +135.867 -220.991 -99.8902 +134.79 -221.937 -99.9633 +134.551 -222.278 -99.8373 +134.575 -222.417 -99.7387 +134.793 -222.13 -99.9653 +134.296 -222.372 -99.8183 +134.541 -222.53 -99.5479 +134.77 -222.406 -99.6819 +134.863 -222.365 -99.805 +135.191 -222.109 -100.138 +135.41 -222.468 -99.6094 +135.652 -222.419 -99.6571 +135.396 -221.732 -100.173 +136.278 -221.246 -100.042 +135.255 -221.696 -100.257 +135.296 -220.918 -100.15 +133.429 -222.595 -99.9259 +132.821 -222.805 -99.8849 +133.666 -222.212 -100.067 +133.782 -222.909 -99.4882 +135.879 -203.262 -99.6774 +136.988 -203.453 -99.7401 +139.279 -209.924 -100.731 +137.25 -207.552 -94.6781 +135.689 -226.301 -101.497 +139.41 -216.617 -93.5831 +135.811 -211.143 -100.509 +135.944 -211.348 -100.498 +136.846 -213.286 -100.506 +138.694 -210.916 -100.62 +137.596 -208.974 -93.9572 +136.113 -208.881 -93.1374 +136.153 -209.181 -93.145 +134.929 -227.047 -101.481 +136.954 -202.492 -99.7228 +133.868 -223.114 -93.0857 +133.948 -223.233 -93.0326 +137.079 -205.881 -94.234 +136.527 -202.891 -99.7307 +135.204 -202.599 -99.5929 +134.492 -203.287 -99.5547 +134.171 -203.109 -99.5768 +135.415 -204.501 -99.6425 +138.949 -205.886 -98.0271 +139.23 -204.161 -97.7672 +139.038 -204.075 -97.8108 +139.051 -203.001 -97.7453 +138.217 -206.554 -96.985 +137.953 -205.744 -96.3972 +136.18 -204.841 -96.3083 +136.774 -204.311 -96.1088 +134.512 -210.446 -97.5091 +139.028 -208.534 -96.7087 +138.52 -209.288 -100.67 +134.694 -207.432 -99.7399 +136.572 -213.844 -100.484 +135.78 -214.622 -100.454 +133.283 -213.665 -99.7805 +132.889 -214.936 -100.25 +136.526 -218.261 -100.372 +136.808 -218.751 -100.337 +137.642 -217.623 -100.309 +135.484 -218.339 -100.461 +135.128 -218.4 -100.479 +133.619 -217.999 -100.595 +134.983 -220.147 -100.458 +135.181 -220.007 -100.479 +134.563 -219.611 -100.518 +138.357 -218.965 -99.769 +138.82 -220.583 -100.541 +134.649 -211.689 -94.7158 +134.645 -211.816 -94.6777 +137.212 -207.299 -94.772 +137.301 -207.362 -94.8132 +136.058 -207.818 -93.055 +136.075 -208.167 -92.9018 +135.441 -211.674 -94.5476 +135.923 -211.455 -94.0505 +137.052 -211.392 -93.746 +136.87 -211.441 -93.8285 +137.158 -213.615 -93.9318 +137.17 -213.288 -93.9809 +137.347 -213.177 -93.9159 +135.657 -212.563 -93.6953 +135.552 -212.954 -93.8914 +135.294 -212.306 -93.5199 +136.592 -207.654 -92.6489 +137.931 -212.186 -93.5335 +138.639 -207.222 -94.6014 +138.564 -218.351 -93.9635 +135.342 -211.706 -100.497 +137.662 -211.702 -93.4987 +136.299 -214.316 -100.454 +137.03 -211.983 -100.471 +134.425 -209.583 -98.0124 +134.456 -210.686 -97.5048 +137.515 -209.362 -96.3415 +139.519 -202.462 -97.7281 +135.51 -205.485 -99.5731 +134.69 -223.58 -92.9215 +132.169 -223.782 -97.0887 +132.339 -223.782 -97.0648 +137.307 -222.908 -98.1219 +136.353 -222.795 -98.5825 +137.597 -225.39 -101.369 +136.097 -210.289 -97.8798 +136.147 -210.668 -98.0726 +136.415 -208.115 -97.7151 +136.381 -208.557 -97.7055 +136.487 -208.831 -97.3347 +136.643 -206.64 -97.0693 +136.74 -208.624 -96.669 +137.345 -203.701 -99.6695 +135.636 -204.238 -99.6664 +137.125 -204.536 -99.7194 +135.73 -206.118 -99.6108 +137.333 -204.588 -99.7034 +138.828 -203.031 -99.9148 +135.679 -209.727 -97.5522 +135.657 -211.036 -97.9063 +134.913 -210.557 -97.5444 +134.988 -210.262 -97.4916 +135.239 -210.058 -97.5194 +136.075 -209.817 -97.6421 +136.085 -208.656 -98.0203 +136.215 -208.287 -98.23 +136.182 -208.112 -98.4392 +134.47 -208.331 -99.5397 +135.567 -215.696 -100.456 +135.489 -216.007 -100.424 +134.717 -213.125 -100.293 +133.23 -215.179 -100.172 +133.213 -215.449 -100.161 +139.327 -219.4 -100.389 +132.992 -222.081 -100.322 +135.32 -222.622 -97.8906 +135.794 -221.457 -99.8436 +134.189 -221.589 -100.109 +132.579 -222.562 -100.201 +134.192 -222.026 -100.005 +135.999 -222.607 -92.5526 +135.892 -222.886 -93.973 +134.287 -221.391 -100.118 +133.088 -214.252 -100.017 +136.711 -221.058 -100.578 +138.538 -222.168 -101.806 +138.205 -206.505 -94.7876 +137.203 -208.977 -95.5429 +137.066 -208.619 -95.4287 +137.623 -212.928 -95.3745 +138.616 -219.19 -99.7055 +138.368 -224.464 -101.568 +135.285 -215.884 -100.397 +135.663 -216.464 -100.488 +133.268 -214.915 -100.176 +136.877 -208.742 -96.5428 +134.105 -222.931 -93.1454 +135.958 -224.714 -101.213 +135.849 -224.484 -97.9998 +132.418 -223.068 -97.8914 +132.355 -223.329 -97.6552 +133.587 -223.624 -93.1155 +133.704 -223.665 -93.1983 +133.583 -222.614 -93.0224 +133.682 -222.588 -93.2336 +133.264 -223.055 -92.7734 +135.438 -222.05 -92.374 +134.843 -221.669 -93.588 +136.536 -221.37 -93.6443 +137.164 -205.998 -94.0698 +138.007 -205.161 -99.528 +134.117 -211.232 -97.3795 +133.963 -211.038 -97.5007 +134.516 -222.916 -97.7303 +137.999 -204.522 -99.5123 +138.656 -202.233 -97.8235 +136.061 -205.228 -96.3171 +136.59 -202.999 -96.3675 +135.88 -204.808 -96.3696 +133.741 -211.139 -98.085 +136.869 -209.825 -97.8083 +138.813 -207.458 -96.4956 +138.448 -209.98 -96.9471 +136.247 -213.393 -99.6682 +135.301 -218.928 -100.487 +134.942 -218.746 -100.476 +133.088 -218.183 -100.66 +132.938 -218.362 -100.693 +134.755 -216.668 -96.6957 +135.153 -215.225 -96.7951 +135.118 -214.817 -97.6187 +136.617 -214.982 -97.9481 +135.76 -216.598 -98.2581 +136.504 -214.582 -93.9918 +137.38 -214.034 -94.7542 +137.314 -209.047 -93.7979 +136.866 -208.924 -93.8381 +137.035 -210.225 -94.0979 +136.788 -211.652 -93.7611 +136.972 -212.182 -93.7846 +138.062 -208.533 -94.9413 +138.398 -219.173 -94.1455 +137.245 -226.16 -101.418 +139.302 -221.481 -101.545 +132.859 -223.644 -97.376 +138.778 -204.912 -99.475 +135.96 -222.406 -99.4284 +134.803 -207.994 -99.6772 +139.51 -203.528 -97.5412 +133.326 -217.648 -100.114 +135.846 -208.801 -93.2125 +135.833 -208.895 -93.2989 +137.755 -205.856 -93.8265 +133.383 -212.353 -100.267 +135.324 -209.685 -97.5745 +134.887 -209.843 -97.6191 +136.64 -208.858 -97.092 +137.701 -221.195 -98.1249 +138.353 -208.142 -95.0443 +136.925 -207.142 -92.2182 +136.779 -206.824 -92.1351 +136.774 -207.843 -92.0032 +135.898 -211.871 -93.5369 +134.816 -212.388 -93.4681 +137.229 -212.21 -93.8676 +136.727 -212.396 -93.7163 +135.827 -212.384 -93.6669 +136.891 -210.582 -94.0325 +135.676 -211.941 -93.6135 +135.984 -211.535 -93.983 +135.536 -209.592 -93.2505 +136.279 -209.8 -93.5209 +137.211 -207.999 -94.1732 +136.253 -211.557 -94.632 +136.549 -210.454 -94.3579 +138.086 -208.82 -94.9855 +134.274 -212.846 -95.1839 +136.022 -209.956 -93.7769 +135.829 -214.392 -95.1876 +135.761 -214.342 -95.1648 +137.143 -214.184 -95.0252 +136.898 -218.956 -93.876 +135.183 -215.012 -97.5771 +133.344 -216.438 -98.7371 +134.056 -214.849 -97.2808 +134.123 -214.69 -97.4482 +134.796 -216.157 -97.3951 +134.343 -216.102 -97.4367 +134.733 -214.158 -97.9544 +134.676 -215.919 -97.4866 +134.734 -215.751 -97.6183 +135.758 -214.807 -97.5633 +135.552 -216.109 -97.0233 +133.664 -216.125 -97.5639 +133.762 -215.823 -96.8352 +135.573 -215.382 -96.8196 +134.24 -215.048 -96.8139 +135.32 -215.33 -96.7279 +138.583 -217.531 -100.161 +138.078 -218.098 -100.157 +139.239 -218.23 -100.156 +138.817 -218.352 -99.9112 +136.337 -216.008 -97.3974 +134.162 -217.014 -100.168 +133.778 -216.586 -98.2439 +133.44 -216.469 -100.176 +136.099 -210.234 -100.286 +135.462 -212.495 -100.394 +136.703 -206.845 -92.196 +136.35 -212.684 -100.43 +136.283 -212.695 -100.34 +133.595 -211.008 -100.14 +138.268 -210.229 -98.077 +138.532 -210.018 -97.4637 +139.404 -207.09 -97.1328 +137.505 -210.025 -98.2208 +137.729 -209.873 -97.4152 +137.079 -210.277 -98.2114 +137.854 -204.201 -96.4428 +137.858 -204.706 -96.5163 +137.758 -204.725 -96.4597 +137.962 -204.454 -96.5147 +136.072 -203.778 -96.4344 +138.516 -208.891 -96.4099 +139.311 -204.843 -98.3693 +139.157 -204.853 -98.4635 +138.443 -204.326 -99.1235 +139.406 -203.234 -99.8855 +139.412 -202.471 -100.72 +138.855 -206.464 -100.833 +138.111 -206.294 -93.9241 +137.973 -206.03 -93.7645 +132.558 -222.685 -98.3037 +136.643 -223.09 -98.0806 +135.716 -225.399 -101.452 +138.59 -222.596 -101.674 +138.645 -222.84 -101.667 +131.842 -225.164 -101.159 +133.233 -212.336 -100.261 +138.906 -203.794 -97.699 +137.754 -212.546 -93.8972 +135.436 -209.851 -93.6843 +135.798 -207.808 -93.0322 +136.297 -213.932 -100.398 +135.141 -204.477 -99.5625 +134.241 -220.888 -92.9309 +133.013 -222.308 -92.417 +132.833 -223.016 -93.684 +138.018 -221.109 -98.1534 +135.696 -224.209 -100.679 +137.717 -219.822 -100.051 +136.59 -222.402 -92.9332 +137.531 -221.893 -101.601 +137.586 -222.319 -101.584 +137.643 -222.118 -101.618 +134.999 -217.083 -97.9689 +135.061 -216.94 -97.9039 +139.313 -221.965 -101.769 +137.379 -205.959 -94.0804 +134.911 -222.179 -92.4796 +134.685 -207.814 -99.7657 +137.022 -212.685 -93.6631 +132.583 -224.676 -99.9579 +139.469 -227.015 -101.562 +137.812 -205.195 -99.5627 +132.262 -223.917 -97.0495 +137.375 -205.737 -96.1663 +134.663 -213.403 -95.3679 +133.896 -216.303 -97.6221 +137.933 -211.658 -93.4955 +134.346 -206.112 -99.6938 +137.254 -205.041 -99.6874 +136.914 -224.737 -101.352 +134.465 -211.678 -94.6835 +139.434 -205.119 -100.728 +134.123 -223.443 -97.4622 +137.228 -214.064 -94.9904 +133.958 -211.617 -100.362 +137.403 -206.099 -92.747 +138.326 -206.092 -94.4199 +135.703 -214.303 -97.9302 +136.01 -209.331 -93.2443 +139.302 -204.748 -98.2898 +139.407 -202.498 -99.9907 +135.933 -213.829 -94.7283 +135.655 -224.858 -100.772 +134.871 -215.286 -97.1842 +138.32 -217.784 -93.8809 +138.174 -217.859 -93.8557 +134.782 -215.197 -97.1251 +134.41 -215.897 -97.1456 +134.297 -215.958 -97.3196 +134.097 -213.504 -95.3433 +134.35 -212.958 -95.2073 +135.964 -214.413 -95.0921 +135.315 -212.087 -93.3264 +136.639 -222.41 -93.2381 +136.867 -221.382 -93.5761 +133.253 -217.974 -100.016 +135.244 -212.608 -93.6303 +137.272 -209.671 -94.2933 +132.912 -217.809 -99.9339 +136.541 -213.158 -100.45 +136.459 -212.626 -100.492 +137.282 -220.158 -100.545 +137.478 -213.602 -94.0288 +136.209 -214.263 -94.2434 +136.763 -214.544 -94.7516 +136.162 -222.34 -94.0638 +134.373 -220.952 -92.9363 +135.306 -213.663 -94.8356 +136.398 -215.632 -96.6803 +134.603 -212.825 -95.1711 +133.827 -206.233 -99.8146 +137.173 -203.848 -96.3604 +138.316 -210.039 -96.9451 +136.728 -208.036 -92.0535 +133.977 -224.565 -101.346 +137.396 -222.929 -100.219 +134.26 -225.575 -101.34 +136.625 -220.687 -100.645 +136.319 -221.165 -100.21 +139.401 -221.43 -101.501 +138.507 -221.258 -101.659 +138.036 -221.5 -101.691 +138.077 -222.85 -101.621 +138.021 -223.656 -101.567 +138.032 -223.368 -101.534 +137.741 -225.91 -101.219 +138.346 -223.958 -101.448 +138.857 -224.964 -101.649 +136.51 -225.326 -101.447 +136.814 -225.352 -101.41 +137.087 -225.947 -101.387 +134.68 -222.012 -99.9434 +134.921 -223.144 -97.194 +134.729 -223.029 -97.3351 +132.505 -224.457 -99.503 +133.759 -224.302 -99.0316 +133.262 -223.156 -97.7634 +133.289 -224.218 -98.9008 +138.796 -223.158 -101.711 +139.38 -223.977 -101.746 +137.495 -205.936 -94.0336 +136.748 -206.407 -92.4884 +136.986 -206.336 -92.5618 +137.721 -206.506 -94.1914 +138.085 -206.513 -94.6418 +134.697 -205.551 -99.5778 +135.881 -205.06 -99.6408 +134.749 -205.347 -99.3901 +134.869 -205.29 -99.3015 +137.094 -202.935 -99.6639 +136.395 -204.332 -99.7653 +136.514 -205.813 -97.3433 +138.586 -205.368 -100.434 +139.055 -202.294 -100.365 +138.775 -206.497 -99.5778 +138.55 -204.901 -99.5646 +138.963 -204.867 -98.7555 +139.396 -205.31 -98.4495 +138.122 -206.325 -96.6961 +139.272 -206.408 -97.8836 +138.857 -206.056 -97.7754 +138.544 -205.173 -97.7905 +138.692 -203.088 -97.8443 +139.344 -203.529 -97.3979 +139.117 -202.262 -97.8533 +138.488 -205.16 -97.0265 +138.526 -206.199 -97.1781 +138.417 -205.841 -96.6171 +138.224 -206.128 -96.6749 +138.122 -206.186 -96.6406 +136.777 -205.679 -96.163 +137.242 -204.85 -96.0713 +137.04 -204.698 -95.9846 +137.072 -203.314 -96.3123 +136.921 -204.075 -96.2786 +137.343 -203.425 -97.2369 +138.29 -206.887 -97.159 +133.799 -210.368 -97.4509 +133.66 -211.574 -100.162 +133.835 -210.578 -97.3902 +134.388 -211.753 -97.4187 +136.659 -210.513 -98.2049 +135.444 -211.384 -97.7423 +135.823 -211.504 -98.0324 +137.263 -209.907 -97.9509 +136.776 -209.478 -97.5266 +137.797 -209.668 -96.5141 +137.896 -209.589 -96.4248 +138.013 -206.603 -96.5949 +138.609 -207.634 -96.5689 +138.825 -207.996 -96.4557 +138.32 -207.132 -96.9389 +138.827 -206.771 -97.3431 +139.197 -208.142 -97.0026 +138.722 -207.314 -96.6983 +138.922 -207.992 -96.516 +139.185 -209.043 -96.8164 +138.899 -208.596 -96.6607 +139.17 -208.678 -96.7413 +138.823 -208.82 -96.7707 +138.972 -209.047 -96.8033 +139.171 -209.33 -96.8781 +138.828 -208.944 -96.7806 +139.07 -209.806 -97.3798 +138.293 -209.612 -96.8407 +138.199 -209.917 -96.9813 +139.487 -209.368 -97.5451 +139.296 -206.781 -97.4712 +139.48 -207.013 -99.6434 +139.153 -208.513 -100.765 +137.762 -209.485 -100.592 +138.048 -209.325 -100.547 +133.777 -207.436 -99.642 +136.155 -207.344 -99.6226 +134.187 -206.737 -99.7447 +133.758 -208.481 -99.3187 +133.926 -208.184 -99.4912 +133.408 -210.432 -98.9489 +136.26 -212.968 -100.066 +136.046 -212.229 -99.6728 +135.612 -212.644 -100.177 +136.555 -212.298 -100.417 +135.226 -216.328 -100.269 +133.726 -216.936 -100.163 +135.45 -215.121 -100.464 +136.463 -220.59 -100.528 +133.766 -217.398 -100.626 +134.553 -217.092 -97.9287 +132.545 -218.66 -100.663 +137.002 -220.182 -100.334 +137.221 -219.695 -99.7689 +136.517 -219.702 -100.314 +136.856 -219.549 -100.295 +137.684 -218.979 -100.086 +133.822 -217.195 -100.191 +139.318 -216.489 -100.304 +139.284 -216.712 -100.176 +139.398 -217.065 -100.253 +138.8 -219.553 -100.448 +139.408 -218.665 -99.6332 +139.414 -218.339 -99.6873 +138.997 -220.899 -100.499 +139.519 -219.066 -100.413 +135.387 -215.825 -96.9753 +133.614 -215.287 -97.3622 +134.699 -215.103 -97.1039 +134.701 -215.609 -97.5665 +134.367 -215.813 -97.1093 +134.44 -215.652 -97.1244 +134.456 -215.457 -97.0045 +134.18 -215.418 -96.9343 +133.613 -215.488 -97.2514 +134.763 -217.137 -97.4322 +135.604 -216.497 -97.1967 +135.178 -215.857 -97.0667 +135.146 -215.647 -96.819 +135.161 -215.515 -96.6985 +134.864 -216.495 -96.9146 +136.311 -215.631 -96.6463 +136.173 -215.965 -96.672 +136.03 -215.558 -96.7738 +135.947 -216.01 -97.0017 +135.372 -216.686 -97.9654 +135.731 -216.472 -97.3804 +133.409 -216.111 -97.7439 +134.512 -214.599 -97.2494 +134.895 -214.408 -97.8415 +135.042 -214.296 -97.7811 +135.298 -214.746 -97.6521 +135.972 -215.175 -97.2375 +136.127 -214.778 -97.4992 +135.246 -214.334 -97.8634 +134.573 -214.299 -97.9268 +134.412 -216.993 -97.605 +137.648 -218.233 -93.6831 +137.276 -219.113 -94.058 +137.089 -219.422 -94.0089 +137.08 -218.988 -93.9716 +137.151 -218.952 -93.966 +137.411 -218.85 -93.7422 +137.063 -213.712 -93.9024 +136.849 -214.088 -94.3307 +136.763 -213.973 -94.1589 +136.715 -214.168 -94.1371 +135.188 -213.602 -94.6994 +136.242 -214.687 -94.4186 +136.118 -212.88 -94.0202 +137.762 -214.363 -94.7015 +137.539 -213.952 -94.5919 +137.741 -213.872 -94.6759 +137.468 -213.981 -94.5851 +135.02 -213.488 -95.0839 +134.897 -213.817 -95.3757 +134.87 -213.5 -95.2135 +134.632 -212.587 -94.8813 +134.556 -213.027 -95.3679 +134.718 -213.169 -95.3182 +134.177 -213.225 -95.2856 +134.379 -212.232 -94.7592 +134.817 -212.101 -94.6242 +134.854 -212.158 -94.5553 +135.921 -213.379 -94.2639 +136.449 -212.084 -94.1266 +136.306 -211.836 -94.5684 +136.306 -211.945 -94.4322 +136.363 -213.307 -94.3831 +137.505 -211.218 -94.6875 +137.415 -209.934 -94.9446 +137.234 -210.544 -94.3518 +136.233 -210.337 -94.5368 +135.225 -211.358 -94.7327 +135.034 -211.542 -94.8147 +134.876 -211.583 -94.8252 +137.589 -209.699 -95.0346 +136.928 -209.876 -94.1836 +137.078 -209.809 -94.2142 +136.965 -209.671 -94.1032 +137.682 -209.487 -94.2762 +137.336 -210.002 -94.7499 +137.395 -206.971 -95.079 +137.715 -206.898 -94.9982 +137.92 -206.808 -94.9169 +137.395 -208.128 -94.0869 +137.183 -209.533 -94.0195 +135.806 -208.025 -93.0066 +136.165 -207.105 -93.2782 +136.4 -208.717 -92.8525 +136.197 -208.652 -93.0365 +136.597 -208.865 -92.9173 +136.596 -208.744 -92.748 +136.582 -208.516 -92.4669 +136.644 -209.296 -93.5305 +137.075 -209.316 -93.6236 +137.445 -208.834 -93.8955 +137.187 -208.525 -93.8665 +137.082 -208.553 -93.794 +137.333 -209.423 -93.9721 +136.807 -209.869 -94.2105 +136.44 -209.825 -94.1189 +136.226 -209.803 -93.4316 +135.864 -209.027 -93.75 +136.815 -209.342 -93.6388 +136.207 -209.528 -93.4893 +136.094 -209.475 -93.3633 +135.805 -209.324 -93.2439 +135.781 -208.494 -92.9816 +136.178 -210.903 -93.9606 +136.062 -211.03 -93.894 +135.938 -210.971 -93.989 +136.675 -211.302 -94.103 +136.744 -211.451 -93.9535 +136.548 -210.775 -94.0399 +136.663 -211.056 -94.098 +136.848 -210.799 -93.9912 +137.312 -211.614 -93.561 +137.055 -212.001 -93.7262 +137.561 -211.978 -93.5284 +137.377 -212.34 -93.9282 +136.901 -212.093 -93.8456 +136.763 -211.957 -93.8956 +136.651 -211.931 -94.0039 +136.144 -212.271 -93.5324 +136.32 -212.467 -93.7399 +136.447 -212.296 -93.8353 +136.695 -212.676 -93.665 +135.981 -212.405 -93.6663 +135.288 -213.107 -93.6167 +135.452 -213.254 -93.9744 +135.973 -212.138 -93.5039 +135.766 -212.153 -93.6783 +135.954 -212.842 -94.0271 +134.866 -213.081 -93.5617 +135.051 -212.849 -93.5828 +134.657 -213.298 -93.4489 +134.842 -213.379 -93.425 +134.97 -213.006 -93.5325 +136.893 -207.469 -92.3335 +136.638 -207.475 -92.5552 +136.743 -206.639 -92.2353 +137.996 -211.523 -93.4908 +138.026 -208.397 -93.7624 +138.391 -206.735 -94.6953 +138.33 -207.485 -94.6929 +138.101 -207.656 -94.9673 +138.401 -207.757 -95.077 +138.104 -209.436 -94.5884 +137.963 -209.625 -94.4887 +137.9 -209.776 -94.5202 +138.539 -217.779 -93.9517 +138.924 -218.605 -94.0399 +138.086 -218.566 -93.7139 +138.977 -218.12 -94.1375 +137.871 -218.003 -93.6827 +137.831 -218.101 -93.6262 +137.035 -222.813 -98.184 +136.535 -208.96 -97.3493 +136.486 -206.413 -93.0039 +137.365 -211.312 -94.5045 +138.212 -219.582 -99.9348 +135.048 -215.381 -100.363 +135.984 -212.073 -100.424 +135.726 -212.116 -100.42 +134.371 -207.775 -99.7971 +135.767 -212.733 -100.152 +133.904 -211.443 -100.24 +133.415 -211.893 -100.151 +133.382 -210.15 -98.9111 +133.606 -209.732 -98.6486 +134.018 -208.044 -99.6646 +136.045 -207.07 -99.6277 +134.218 -208.014 -99.7134 +133.839 -209.751 -98.1925 +134.342 -211.534 -97.2791 +134.312 -211.312 -97.2219 +134.467 -211.312 -97.0659 +134.409 -211.242 -97.1563 +137.613 -205.471 -99.2682 +139.053 -202.666 -100.19 +136.701 -221.49 -93.6365 +136.921 -221.796 -93.4771 +135.874 -221.529 -92.9448 +136.137 -222.205 -92.7678 +136.055 -221.968 -92.8563 +135.743 -222.686 -93.6973 +135.901 -222.325 -93.7008 +135.879 -221.261 -93.2131 +135.918 -221.157 -93.4507 +134.339 -221.112 -92.8652 +134.491 -222.422 -93.0533 +134.621 -222.374 -92.9028 +135.011 -222.405 -92.4767 +135.425 -222.432 -92.4354 +135.278 -221.812 -92.6795 +135.605 -221.676 -92.5954 +134.174 -221.532 -92.436 +133.202 -222.53 -92.3226 +133.162 -222.811 -92.2529 +133.344 -223.184 -92.953 +134.042 -222.637 -93.2665 +134.253 -223.46 -92.9494 +132.923 -223.081 -93.0712 +132.973 -222.977 -93.043 +133.721 -223.178 -92.9935 +133.465 -223.476 -93.1356 +133.639 -223.556 -96.3938 +132.868 -223.581 -97.3345 +133.348 -223.48 -97.2825 +133.515 -223.689 -97.5921 +132.267 -224.075 -97.124 +132.152 -224.583 -99.6841 +135.542 -224.059 -98.9559 +134.602 -224.1 -98.7344 +134.629 -224.315 -98.9876 +134.457 -224.273 -98.8546 +134.77 -224.253 -99.0103 +135.218 -223.96 -98.4657 +135.352 -223.967 -98.4375 +135.535 -223.619 -97.8119 +137.02 -223.589 -98.0726 +136.567 -223.538 -97.9516 +136.594 -223.312 -97.9818 +135.669 -223.526 -97.8247 +136.622 -223.748 -98.0743 +137.144 -222.445 -98.1312 +137.274 -222.067 -98.1525 +136.997 -221.346 -98.1957 +137.003 -221.492 -98.184 +137.291 -221.348 -98.1074 +134.962 -222.119 -98.0847 +136.783 -222.282 -98.716 +138.647 -226.107 -101.449 +134.729 -225.961 -101.381 +137.014 -223.828 -101.545 +136.502 -224.081 -101.509 +136.467 -224.018 -101.492 +136.358 -224.044 -101.371 +137.243 -223.942 -101.509 +138.318 -225.095 -101.452 +138.071 -224.196 -101.724 +138.533 -223.192 -101.467 +138.364 -223.306 -101.626 +138.282 -223.415 -101.697 +139.145 -221.399 -101.536 +138.499 -220.796 -100.651 +138.096 -221.041 -100.492 +135.28 -224.142 -100.649 +135.492 -224.96 -101.421 +134.944 -225.025 -100.709 +135.995 -224.968 -101.218 +135.726 -225.282 -101.274 +136.149 -224.74 -101.353 +135.679 -224.947 -101.308 +134.344 -225.072 -101.018 +134.245 -224.315 -100.901 +134.383 -224.272 -100.784 +133.564 -224.575 -100.622 +133.142 -224.249 -100.368 +133.597 -224.223 -100.418 +133.656 -224.324 -100.52 +131.748 -224.741 -100.37 +139.143 -221.992 -101.727 +135.426 -205.912 -99.584 +136.894 -222.097 -98.5186 +139.433 -225.006 -101.684 +134.06 -223.117 -98.0062 +136.379 -206.138 -98.705 +136.184 -206.414 -99.318 +136.973 -208.405 -95.9092 +137.074 -208.593 -95.8194 +137.017 -208.435 -95.6556 +136.607 -205.793 -99.3257 +136.35 -205.965 -99.282 +136.554 -205.932 -99.1736 +136.62 -205.896 -98.683 +136.536 -205.964 -98.4503 +135.984 -206.137 -99.5299 +135.274 -211.598 -97.6565 +134.54 -211.068 -97.3431 +134.897 -211.268 -97.318 +136.354 -209.083 -97.501 +136.461 -209.121 -97.4356 +136.521 -205.902 -97.7495 +133.616 -214.778 -99.8427 +133.55 -215.029 -99.7961 +135.829 -213.494 -99.3987 +135.861 -213.599 -99.4689 +133.687 -223.033 -99.2859 +132.896 -222.753 -98.3149 +134.955 -222.356 -97.8897 +137.413 -225.085 -101.38 +139.427 -223.439 -101.779 +135.807 -221.104 -99.8884 +134.503 -221.877 -99.9237 +134.615 -221.308 -100.029 +139.341 -202.514 -97.7996 +136.286 -208.686 -97.8399 +3 881 140 139 +3 881 139 141 +3 142 3831 143 +3 3831 3830 143 +3 143 3830 141 +3 3830 881 141 +3 144 2278 145 +3 2278 1332 145 +3 146 992 147 +3 992 4430 147 +3 805 149 148 +3 149 805 150 +3 805 728 150 +3 151 807 148 +3 807 805 148 +3 807 151 152 +3 807 152 153 +3 154 984 155 +3 984 5414 155 +3 155 5414 153 +3 5414 807 153 +3 3831 142 156 +3 157 4456 158 +3 4456 5223 158 +3 5228 159 160 +3 5228 161 162 +3 163 4633 162 +3 4633 5228 162 +3 5228 160 161 +3 164 165 6586 +3 6586 165 5230 +3 159 5228 165 +3 5228 5230 165 +3 166 158 5227 +3 5227 158 5223 +3 164 6586 167 +3 6586 803 167 +3 168 2805 169 +3 2805 6651 169 +3 170 169 4633 +3 4633 169 6651 +3 171 172 4461 +3 4461 172 4438 +3 4461 173 171 +3 4438 172 174 +3 2805 175 176 +3 2805 168 175 +3 728 177 178 +3 4633 163 170 +3 2805 176 179 +3 179 177 2805 +3 2805 177 728 +3 4438 174 180 +3 7035 182 181 +3 180 182 4438 +3 4438 182 7035 +3 183 4825 184 +3 4825 795 184 +3 4825 186 185 +3 4825 187 186 +3 188 5207 185 +3 5207 4825 185 +3 4825 183 187 +3 184 795 189 +3 795 5204 189 +3 188 173 5207 +3 5207 173 4461 +3 166 5227 190 +3 5227 7062 190 +3 7062 191 190 +3 4456 192 193 +3 4456 157 192 +3 194 4621 193 +3 4621 4456 193 +3 4621 194 195 +3 195 196 4621 +3 4621 196 803 +3 803 196 197 +3 803 197 167 +3 821 198 199 +3 200 6774 201 +3 6774 821 201 +3 202 6402 203 +3 6402 5055 203 +3 202 198 6402 +3 6402 198 821 +3 5055 205 204 +3 2814 207 206 +3 208 820 209 +3 820 6774 209 +3 821 199 201 +3 6774 200 209 +3 206 210 2814 +3 2814 210 2817 +3 2817 210 211 +3 5055 204 212 +3 5055 212 203 +3 205 5055 211 +3 5055 2817 211 +3 213 3832 214 +3 3832 3831 214 +3 215 5870 216 +3 5870 3832 216 +3 5870 215 217 +3 3832 213 216 +3 3831 156 214 +3 5870 217 218 +3 219 6294 218 +3 6294 5870 218 +3 220 0 1 +3 2 1939 1 +3 1939 220 1 +3 1939 221 220 +3 222 223 1931 +3 1931 223 1941 +3 221 1939 223 +3 1939 1941 223 +3 1397 225 224 +3 1397 226 225 +3 227 228 1899 +3 1899 228 1884 +3 1884 228 229 +3 230 1882 229 +3 1882 1884 229 +3 1328 231 232 +3 1899 233 227 +3 1899 234 233 +3 235 5470 236 +3 5470 1894 236 +3 236 1894 237 +3 1894 6689 237 +3 232 237 1328 +3 1328 237 6689 +3 235 234 5470 +3 5470 234 1899 +3 224 238 1397 +3 1397 238 1248 +3 1248 238 239 +3 240 6477 241 +3 6477 1247 241 +3 242 5477 240 +3 5477 6477 240 +3 243 1655 242 +3 1655 5477 242 +3 239 244 1248 +3 1248 244 5479 +3 226 1397 245 +3 1397 1882 245 +3 1882 230 245 +3 146 246 992 +3 992 246 4422 +3 2820 247 248 +3 249 2814 248 +3 2814 2820 248 +3 250 247 4639 +3 4639 247 2820 +3 6094 251 252 +3 252 250 6094 +3 6094 250 4639 +3 2814 249 207 +3 253 4956 254 +3 4956 4958 254 +3 255 256 4956 +3 4956 256 2285 +3 4956 253 255 +3 5558 258 257 +3 259 2272 260 +3 2272 1340 260 +3 261 254 2290 +3 2290 254 4958 +3 2290 262 261 +3 2272 259 263 +3 256 260 2285 +3 2285 260 1340 +3 262 2290 257 +3 2290 5558 257 +3 264 265 6291 +3 6291 265 2329 +3 2329 265 266 +3 2330 267 268 +3 269 2295 268 +3 2295 2330 268 +3 267 2330 266 +3 2330 2329 266 +3 270 271 2321 +3 2321 271 6291 +3 6291 271 264 +3 272 2862 273 +3 2862 2882 273 +3 2862 272 274 +3 2862 274 275 +3 276 2868 275 +3 2868 2862 275 +3 2882 277 273 +3 208 277 820 +3 820 277 2882 +3 278 5643 279 +3 5643 6771 279 +3 278 280 5643 +3 5643 280 6772 +3 6771 281 279 +3 282 281 5642 +3 5642 281 6771 +3 282 5642 276 +3 5642 2868 276 +3 4430 283 147 +3 284 983 285 +3 983 984 285 +3 4430 286 283 +3 287 5656 288 +3 5656 983 288 +3 983 284 288 +3 287 286 5656 +3 5656 286 4430 +3 984 289 285 +3 984 154 289 +3 1330 290 291 +3 292 293 1790 +3 1790 293 1869 +3 294 295 1330 +3 1330 295 1790 +3 1869 293 296 +3 296 297 1869 +3 1869 297 1398 +3 1330 291 294 +3 1790 295 292 +3 298 1328 297 +3 1328 1398 297 +3 299 290 4836 +3 4836 290 1330 +3 1328 298 300 +3 728 178 150 +3 4439 301 302 +3 303 791 302 +3 791 4439 302 +3 4439 304 301 +3 791 303 305 +3 304 4439 181 +3 4439 7035 181 +3 907 306 307 +3 6294 308 309 +3 309 306 6294 +3 6294 306 907 +3 6294 219 308 +3 310 6093 311 +3 6093 6773 311 +3 5479 244 312 +3 6557 314 313 +3 6094 315 251 +3 315 6094 310 +3 6094 6093 310 +3 316 317 2345 +3 2345 317 1811 +3 318 319 2339 +3 2339 319 2340 +3 2340 319 320 +3 2345 321 316 +3 2339 322 323 +3 2339 323 318 +3 324 322 5559 +3 5559 322 2339 +3 321 2345 320 +3 2345 2340 320 +3 2225 325 326 +3 327 328 2305 +3 2305 328 2317 +3 327 2305 329 +3 2305 2300 329 +3 2317 328 330 +3 331 2320 330 +3 2320 2317 330 +3 2320 331 332 +3 2300 333 329 +3 1328 300 334 +3 1328 334 231 +3 733 336 335 +3 337 338 6769 +3 6769 338 732 +3 336 733 338 +3 733 732 338 +3 6769 339 337 +3 340 2281 263 +3 2281 2272 263 +3 341 1332 340 +3 1332 2281 340 +3 1332 341 342 +3 1332 342 343 +3 2229 345 344 +3 344 346 2229 +3 2229 346 2221 +3 2230 348 347 +3 2236 350 349 +3 350 2236 351 +3 2236 6738 351 +3 2211 353 352 +3 346 354 2221 +3 2221 354 2212 +3 355 356 2212 +3 2212 356 2211 +3 2211 356 353 +3 349 357 2236 +3 2236 357 2238 +3 2211 352 358 +3 359 1329 358 +3 1329 2211 358 +3 359 325 1329 +3 1329 325 2225 +3 2212 354 355 +3 1332 343 145 +3 6738 360 351 +3 144 360 2278 +3 2278 360 6738 +3 2230 347 361 +3 345 2229 361 +3 2229 2230 361 +3 2238 357 362 +3 348 2230 362 +3 2230 2238 362 +3 2847 363 364 +3 365 366 2844 +3 2844 366 6767 +3 367 368 733 +3 733 368 2844 +3 369 370 2870 +3 2870 370 2873 +3 2873 371 372 +3 2873 370 371 +3 2873 372 373 +3 2847 364 374 +3 2844 368 365 +3 733 335 367 +3 2836 375 376 +3 2836 377 375 +3 378 724 373 +3 724 2873 373 +3 379 380 2833 +3 2833 380 530 +3 381 2846 374 +3 2846 2847 374 +3 2827 382 383 +3 384 2835 385 +3 2835 2843 385 +3 2843 386 385 +3 387 386 6767 +3 6767 386 2843 +3 6767 366 387 +3 339 6769 388 +3 6769 2846 388 +3 6772 280 389 +3 369 2870 389 +3 2870 6772 389 +3 390 2833 383 +3 2833 2827 383 +3 2833 390 379 +3 377 2836 380 +3 2836 530 380 +3 378 363 724 +3 724 363 2847 +3 382 2827 384 +3 2827 2835 384 +3 2846 381 388 +3 2836 376 391 +3 6612 392 393 +3 394 1832 393 +3 1832 6612 393 +3 392 6612 395 +3 6612 1845 395 +3 5454 396 397 +3 5454 398 396 +3 399 696 400 +3 696 2306 400 +3 401 2301 402 +3 2301 2302 402 +3 401 333 2301 +3 2301 333 2300 +3 403 2834 391 +3 2834 2836 391 +3 404 405 696 +3 696 405 684 +3 405 406 684 +3 684 406 2302 +3 407 2306 403 +3 2306 2834 403 +3 696 399 404 +3 4835 409 408 +3 317 410 1811 +3 1811 410 1814 +3 4836 411 299 +3 412 6603 408 +3 6603 4835 408 +3 412 411 6603 +3 6603 411 4836 +3 409 4835 413 +3 4835 1810 413 +3 1814 415 414 +3 1814 410 415 +3 1814 414 416 +3 413 1810 416 +3 1810 1814 416 +3 417 2296 418 +3 2296 2295 418 +3 2296 417 419 +3 5558 420 258 +3 419 420 2296 +3 2296 420 5558 +3 2295 269 418 +3 2302 421 402 +3 2302 406 421 +3 2306 407 400 +3 332 422 2320 +3 2320 422 2321 +3 2321 422 270 +3 423 5486 424 +3 5486 1655 424 +3 1247 425 241 +3 426 425 5479 +3 5479 425 1247 +3 5479 312 426 +3 1655 243 424 +3 5486 423 427 +3 5486 427 428 +3 429 5210 430 +3 5210 5316 430 +3 431 432 4791 +3 4791 432 6592 +3 5206 433 434 +3 5206 434 435 +3 429 436 5210 +3 5210 436 4602 +3 433 5206 436 +3 5206 4602 436 +3 78 79 4791 +3 4791 79 431 +3 6592 437 438 +3 430 5316 438 +3 5316 6592 438 +3 4791 80 78 +3 4791 81 80 +3 5204 439 189 +3 439 5204 435 +3 5204 5206 435 +3 6592 432 437 +3 5226 441 440 +3 791 442 443 +3 791 305 442 +3 444 6671 445 +3 6671 789 445 +3 789 446 445 +3 441 5226 444 +3 5226 6671 444 +3 447 448 4824 +3 4824 448 790 +3 790 448 449 +3 446 789 449 +3 789 790 449 +3 443 447 791 +3 791 447 4824 +3 5226 440 450 +3 451 5225 450 +3 5225 5226 450 +3 7062 452 453 +3 452 7062 451 +3 7062 5225 451 +3 7062 453 191 +3 454 5485 455 +3 3 4 5485 +3 5485 4 455 +3 5485 454 456 +3 1840 6 5 +3 7 8 397 +3 397 8 5454 +3 8 6 5454 +3 5454 6 1840 +3 455 4 9 +3 326 457 2225 +3 2225 457 1315 +3 458 459 1315 +3 1315 459 2227 +3 1315 457 460 +3 2231 461 462 +3 463 464 2231 +3 2231 464 2292 +3 1315 460 458 +3 1356 465 466 +3 461 2231 459 +3 2231 2227 459 +3 2231 462 463 +3 2292 464 467 +3 2292 467 468 +3 465 1356 468 +3 1356 2292 468 +3 4422 246 469 +3 6366 470 471 +3 222 1931 472 +3 1931 7066 472 +3 471 472 6366 +3 6366 472 7066 +3 473 6366 474 +3 6366 1930 474 +3 6366 475 470 +3 6366 473 475 +3 474 1930 428 +3 1930 5486 428 +3 1823 476 477 +3 2341 479 478 +3 477 479 1823 +3 1823 479 2341 +3 480 476 1824 +3 1824 476 1823 +3 5559 481 324 +3 481 5559 478 +3 5559 2341 478 +3 482 1361 483 +3 1361 4905 483 +3 1361 482 484 +3 4905 485 483 +3 395 1845 484 +3 1845 1361 484 +3 486 487 4429 +3 4429 487 948 +3 488 486 6045 +3 6045 486 4429 +3 948 487 489 +3 490 4428 489 +3 4428 948 489 +3 4428 491 492 +3 4428 490 491 +3 6557 313 493 +3 398 5454 493 +3 5454 6557 493 +3 494 1841 394 +3 1841 1832 394 +3 1841 494 495 +3 1841 495 496 +3 496 314 1841 +3 1841 314 6557 +3 497 881 307 +3 881 907 307 +3 881 497 498 +3 881 498 140 +3 499 6045 500 +3 6045 2896 500 +3 501 500 4431 +3 4431 500 2896 +3 501 4431 502 +3 4431 4422 502 +3 4422 469 502 +3 6045 499 488 +3 1876 503 504 +3 505 1355 466 +3 1355 1356 466 +3 6740 506 507 +3 503 1876 505 +3 1876 1355 505 +3 507 480 6740 +3 6740 480 1824 +3 504 506 1876 +3 1876 506 6740 +3 492 508 4428 +3 4428 508 4640 +3 508 311 4640 +3 4640 311 6773 +3 456 509 5485 +3 5485 509 1847 +3 485 4905 509 +3 4905 1847 509 +3 4775 82 83 +3 4775 83 84 +3 85 86 593 +3 593 86 4779 +3 593 87 88 +3 593 88 85 +3 89 90 659 +3 659 90 6126 +3 91 4503 90 +3 4503 6126 90 +3 4779 86 92 +3 4780 93 94 +3 4780 95 93 +3 4781 96 97 +3 98 96 4787 +3 4787 96 4781 +3 658 99 100 +3 95 4780 101 +3 4780 4779 101 +3 4787 102 98 +3 4785 103 104 +3 99 658 105 +3 658 4783 105 +3 106 82 4777 +3 4777 82 4775 +3 84 87 4775 +3 4775 87 593 +3 659 107 108 +3 659 108 109 +3 100 107 658 +3 658 107 659 +3 110 4784 111 +3 4784 4503 111 +3 4503 91 111 +3 112 113 4782 +3 4782 113 5308 +3 4787 114 102 +3 4782 115 112 +3 4782 116 115 +3 103 4785 117 +3 4785 4784 117 +3 659 109 89 +3 105 4783 94 +3 4783 4780 94 +3 4779 92 101 +3 97 116 4781 +3 4781 116 4782 +3 104 114 4785 +3 4785 114 4787 +3 4784 110 117 +3 4778 118 119 +3 120 121 4772 +3 4772 121 4778 +3 4778 121 118 +3 119 106 4778 +3 4778 106 4777 +3 122 4601 123 +3 4601 5211 123 +3 123 5211 124 +3 5211 5315 124 +3 125 5310 126 +3 5310 4598 126 +3 5310 125 127 +3 4601 122 128 +3 124 5315 129 +3 5315 4793 129 +3 130 131 5312 +3 5312 131 4793 +3 132 4792 127 +3 4792 5310 127 +3 81 4791 133 +3 4791 5316 133 +3 134 133 4601 +3 4601 133 5316 +3 5312 135 136 +3 137 2750 113 +3 2750 5308 113 +3 5312 136 130 +3 2750 137 138 +3 4793 131 129 +3 126 4598 138 +3 4598 2750 138 +3 135 5312 132 +3 5312 4792 132 +3 4601 128 134 +3 10 1656 11 +3 1656 1658 11 +3 11 1658 12 +3 1658 1541 12 +3 13 1543 14 +3 1543 1656 14 +3 15 1686 16 +3 1686 1942 16 +3 1941 17 18 +3 19 6444 20 +3 6444 1686 20 +3 1686 15 20 +3 18 21 1941 +3 1941 21 6696 +3 16 1942 21 +3 1942 6696 21 +3 1939 2 22 +3 17 1941 23 +3 1941 1939 23 +3 1939 22 23 +3 1663 24 25 +3 1663 26 24 +3 27 6303 28 +3 6303 4854 28 +3 29 1694 30 +3 1694 580 30 +3 4854 31 32 +3 580 34 33 +3 34 580 35 +3 580 540 35 +3 4854 32 28 +3 31 4854 36 +3 4854 1675 36 +3 37 540 27 +3 540 6303 27 +3 580 33 30 +3 540 37 38 +3 540 38 35 +3 1541 39 12 +3 40 1544 13 +3 1544 1543 13 +3 41 1662 42 +3 1662 1546 42 +3 39 1541 41 +3 1541 1662 41 +3 1657 43 44 +3 40 43 1544 +3 1544 43 1657 +3 1657 44 45 +3 42 1546 45 +3 1546 1657 45 +3 1849 46 47 +3 5485 48 3 +3 47 48 1849 +3 1849 48 5485 +3 6444 19 49 +3 49 46 6444 +3 6444 46 1849 +3 50 559 51 +3 559 544 51 +3 52 1667 53 +3 1667 559 53 +3 559 50 54 +3 1667 52 55 +3 1680 57 56 +3 559 54 53 +3 57 1680 58 +3 1680 6165 58 +3 1680 56 59 +3 1667 55 60 +3 36 1675 60 +3 1675 1667 60 +3 58 6165 25 +3 6165 1663 25 +3 1399 62 61 +3 59 62 1680 +3 1680 62 1399 +3 51 544 61 +3 544 1399 61 +3 63 1692 64 +3 1692 1694 64 +3 1694 29 64 +3 65 66 1687 +3 1687 66 1689 +3 1687 67 65 +3 68 1690 63 +3 1690 1692 63 +3 1689 66 69 +3 67 1687 68 +3 1687 1690 68 +3 4894 71 70 +3 72 1663 70 +3 1663 4894 70 +3 1840 5 73 +3 73 74 1840 +3 1840 74 5455 +3 1663 72 26 +3 71 4894 75 +3 4894 1770 75 +3 75 1770 76 +3 1770 5455 76 +3 5455 74 76 +3 1656 77 14 +3 1656 10 77 +3 511 512 513 +3 1184 512 511 +3 1216 5524 1215 +3 3384 4804 4813 +3 1215 3289 2104 +3 2106 4800 609 +3 4800 3289 609 +3 3215 3214 896 +3 896 3219 3215 +3 3256 3212 3213 +3 896 3214 3232 +3 3268 5082 3213 +3 3214 5752 3232 +3 3213 3212 3259 +3 3268 3258 2104 +3 3259 3268 3213 +3 3268 2104 4800 +3 511 3269 1184 +3 4800 5082 3268 +3 3269 511 2104 +3 512 1184 3270 +3 1184 2952 3270 +3 1184 3269 2952 +3 4804 1439 4813 +3 3269 3258 3257 +3 3269 2104 3258 +3 1215 511 513 +3 1216 5760 1209 +3 3289 3272 609 +3 4804 609 3272 +3 3232 3213 5082 +3 609 2172 2106 +3 2172 609 3333 +3 4804 3333 609 +3 3384 5780 4804 +3 4800 2104 3289 +3 1215 2104 511 +3 2184 6416 2268 +3 3384 3456 3353 +3 2184 2268 1459 +3 1459 3456 3384 +3 2268 3456 1459 +3 2268 2183 2269 +3 2183 1307 2269 +3 5888 1443 4800 +3 5524 3272 3289 +3 3333 4804 5780 +3 5780 3384 3353 +3 1216 1215 513 +3 5752 3256 3213 +3 3213 3232 5752 +3 3289 1215 5524 +3 5888 4800 2106 +3 5082 4800 1443 +3 5760 1216 5330 +3 3232 5082 4839 +3 5523 1216 1209 +3 3258 3268 3259 +3 5524 5523 2092 +3 1216 5523 5524 +3 513 3279 5330 +3 513 5330 1216 +3 2270 3456 2268 +3 1443 4839 5082 +3 2183 2268 6416 +3 883 905 906 +3 913 912 911 +3 3115 927 938 +3 939 938 927 +3 3121 927 925 +3 3136 913 3115 +3 3849 3858 905 +3 3849 905 3835 +3 3835 905 911 +3 3854 3142 3115 +3 3142 3854 883 +3 883 911 905 +3 911 883 3854 +3 927 3115 3142 +3 883 903 884 +3 3148 5881 3142 +3 913 3854 3115 +3 911 912 3835 +3 911 3854 913 +3 913 914 912 +3 913 3135 914 +3 5881 925 927 +3 938 3136 3115 +3 927 3142 5881 +3 5876 3148 3142 +3 5876 3142 883 +3 5876 883 884 +3 1169 919 1168 +3 5938 1169 1168 +3 1373 1934 1374 +3 6171 4918 1795 +3 4918 6173 2054 +3 1742 2054 2050 +3 2040 2050 1994 +3 1795 1372 1913 +3 1372 4918 1374 +3 2054 1374 4918 +3 2054 5510 2050 +3 1372 1374 1934 +3 1742 1374 2054 +3 1933 1372 1934 +3 1373 1855 1934 +3 1933 1934 1855 +3 1994 2050 5510 +3 6173 5510 2054 +3 1795 4902 6171 +3 4918 1372 1795 +3 4918 6171 6173 +3 1457 1458 1459 +3 5142 652 651 +3 652 5406 651 +3 4374 652 650 +3 5142 650 652 +3 652 5404 5406 +3 1102 1103 4086 +3 4073 4004 1102 +3 4086 4073 1102 +3 5951 3982 1127 +3 3982 5951 4004 +3 3980 3959 3982 +3 3959 1127 3982 +3 1102 4004 5951 +3 1109 4095 1103 +3 4089 4090 4087 +3 4088 4137 4090 +3 4089 4087 4095 +3 1121 4090 4089 +3 1121 4100 1110 +3 4100 4095 1133 +3 4100 1121 4089 +3 4095 4100 4089 +3 1106 1133 4095 +3 1106 4095 1109 +3 1121 4088 4090 +3 1109 1103 3990 +3 5944 3967 1107 +3 5944 1107 1128 +3 1101 5974 1108 +3 846 929 930 +3 1107 929 1108 +3 846 845 929 +3 3893 929 3896 +3 1108 929 3893 +3 937 929 845 +3 1132 1128 1107 +3 1108 1132 1107 +3 3967 929 1107 +3 1131 1129 1128 +3 1131 1125 3959 +3 1129 1131 3959 +3 1101 1108 3893 +3 3896 929 937 +3 3958 1131 1128 +3 1132 3958 1128 +3 1658 1542 1541 +3 1919 1855 1940 +3 2472 2491 2470 +3 2470 2446 2472 +3 3080 5059 2629 +3 3062 3108 1035 +3 3094 1035 3108 +3 3063 3056 3062 +3 3154 3155 3152 +3 3201 3166 3152 +3 3201 3152 3153 +3 3152 3745 3153 +3 5764 3201 3153 +3 5764 3153 3285 +3 3745 3152 3155 +3 3166 3165 3154 +3 3164 3154 3165 +3 3215 3249 3216 +3 897 3232 3255 +3 1460 3409 1458 +3 3416 3409 1530 +3 3425 3424 1458 +3 1220 1229 1530 +3 1530 3409 1220 +3 3409 3416 3425 +3 1460 3617 3409 +3 3618 1220 3409 +3 1458 3409 3425 +3 3485 3486 3487 +3 3729 3285 3736 +3 3729 3736 3738 +3 1227 3731 3632 +3 3779 3787 3780 +3 3790 3780 3787 +3 3098 2919 3840 +3 3829 857 3789 +3 3846 857 3829 +3 3839 3097 3848 +3 3255 3248 3098 +3 3241 3848 3098 +3 3097 3098 3848 +3 3241 3098 3248 +3 3255 3098 3254 +3 5289 5110 656 +3 4147 1007 1003 +3 4169 1015 4447 +3 1007 1015 4169 +3 4147 1015 1007 +3 2897 2896 6045 +3 3957 3958 1126 +3 3957 5940 3958 +3 1151 4031 4032 +3 1150 3151 1151 +3 1123 4005 4071 +3 4033 4032 4024 +3 2184 3424 3473 +3 1126 3954 1127 +3 3631 3290 3630 +3 3275 3276 512 +3 5780 5778 5781 +3 4071 5987 1152 +3 1098 4198 5994 +3 3973 3967 3966 +3 6693 1325 1909 +3 1325 1911 1909 +3 1909 1324 6693 +3 1911 1915 1909 +3 2069 2070 1940 +3 1940 2070 1937 +3 1940 1937 1919 +3 2464 2468 2463 +3 2701 6034 4808 +3 4808 4299 4400 +3 4400 2678 4808 +3 2701 4808 2678 +3 1948 1323 5515 +3 1949 1948 5515 +3 1949 1950 1948 +3 1936 1950 1949 +3 5459 1862 1366 +3 5459 1861 1862 +3 1366 1779 5459 +3 1862 1877 1366 +3 1872 1366 1877 +3 6439 1861 5459 +3 1366 1872 1779 +3 6439 1873 1861 +3 1598 1596 1591 +3 1591 1596 1560 +3 1598 1594 1596 +3 1595 1597 1582 +3 1594 1595 1573 +3 1573 1561 1596 +3 1560 1596 1561 +3 1594 1573 1596 +3 1597 1595 3534 +3 1594 3534 1595 +3 1561 1573 1574 +3 1598 3534 1594 +3 6607 1591 1560 +3 1582 5423 1573 +3 1582 1615 5423 +3 1597 1615 1582 +3 1573 1595 1582 +3 1856 2061 5514 +3 1856 5514 1855 +3 1855 1919 1856 +3 2061 1935 5514 +3 2061 1856 1853 +3 5513 2061 1853 +3 1935 2061 5513 +3 1933 5514 1935 +3 3595 3449 3794 +3 3794 6912 3595 +3 5012 2496 3103 +3 2496 5061 3103 +3 2545 2125 5012 +3 5011 6325 4928 +3 5012 3103 2550 +3 6233 2545 5013 +3 2496 614 5061 +3 6325 2609 4928 +3 6325 627 2609 +3 6325 5011 626 +3 4816 4929 2323 +3 2496 4816 614 +3 2323 614 4816 +3 613 4929 2125 +3 4928 613 2125 +3 5011 5010 626 +3 2545 626 5010 +3 2125 4929 4816 +3 2125 2545 5010 +3 2496 5012 4816 +3 2125 4816 5012 +3 2545 5012 2550 +3 5011 2125 5010 +3 5013 2545 2550 +3 4928 2125 5011 +3 2609 613 4928 +3 5061 614 6239 +3 5013 2550 6245 +3 2550 3103 6245 +3 6325 626 627 +3 951 959 960 +3 961 951 960 +3 961 952 951 +3 5495 1986 5496 +3 1643 1648 1953 +3 1636 1986 5495 +3 1972 5498 1636 +3 1986 1636 5498 +3 1976 5474 6317 +3 1283 1976 1985 +3 6317 1985 1976 +3 1974 6548 6549 +3 1648 1978 1953 +3 1974 6549 5504 +3 1972 1285 5498 +3 1907 1285 1972 +3 1283 2012 6595 +3 1990 5498 1285 +3 1986 5498 1990 +3 1643 1953 1642 +3 1977 1978 1648 +3 6595 1282 1984 +3 5496 6595 1984 +3 1976 1283 1285 +3 1990 1285 1283 +3 5474 1976 1285 +3 5474 1285 5492 +3 1990 6595 5496 +3 1986 1990 5496 +3 1283 6595 1990 +3 1974 5504 1643 +3 2012 1282 6595 +3 1985 1977 1999 +3 1643 1999 1977 +3 2012 1283 1999 +3 1985 1999 1283 +3 1974 1643 1642 +3 1642 6548 1974 +3 5492 1285 1907 +3 1907 1972 1970 +3 1977 1648 1643 +3 6317 1977 1985 +3 1140 5344 1111 +3 4132 1111 5344 +3 1111 5948 1140 +3 2896 2865 4431 +3 6608 1463 1419 +3 1463 1599 1419 +3 1402 1401 6608 +3 1463 6608 1616 +3 1419 1402 6608 +3 2149 2150 2151 +3 3121 939 927 +3 1016 1003 1007 +3 6180 6181 4926 +3 2102 4926 6181 +3 7048 4926 6187 +3 6180 6179 4927 +3 4926 5529 6187 +3 4926 7048 6180 +3 2109 6181 4927 +3 6181 6180 4927 +3 3214 3215 3216 +3 5752 3214 3251 +3 3251 3214 3216 +3 3264 2952 3269 +3 940 3893 935 +3 940 1101 3893 +3 1127 3959 1125 +3 935 3893 3895 +3 3895 3893 3896 +3 5036 2580 1047 +3 5077 2596 2625 +3 2591 617 6512 +3 2580 5901 3069 +3 2596 5059 3080 +3 2625 2596 3080 +3 1048 1047 2591 +3 5058 618 2624 +3 5901 2580 5036 +3 5036 2591 6237 +3 2591 5060 6237 +3 5018 5020 6231 +3 6227 5018 5017 +3 2624 2629 5059 +3 618 6512 617 +3 2624 5059 5058 +3 2624 618 3076 +3 2991 2629 2993 +3 5036 2581 5901 +3 1048 2591 5036 +3 1047 1048 5036 +3 2573 5060 6512 +3 5058 5059 2573 +3 5059 2596 5904 +3 5017 5904 2596 +3 2573 5059 5904 +3 5058 2573 6512 +3 5017 6231 5904 +3 2573 5904 6231 +3 5018 6231 5017 +3 5020 5060 6231 +3 5020 5034 6237 +3 5020 6237 5060 +3 6237 5035 5036 +3 2581 5036 5035 +3 5034 5035 6237 +3 6512 5060 2591 +3 6512 618 5058 +3 5018 6227 6230 +3 5020 5018 6230 +3 3098 3840 3254 +3 3954 1126 3958 +3 1127 3954 3956 +3 3958 5954 3954 +3 3955 3956 3954 +3 3954 5954 3955 +3 4032 4033 1151 +3 883 906 903 +3 903 906 3871 +3 906 905 915 +3 905 3858 915 +3 5882 906 915 +3 5882 900 906 +3 2106 5103 5888 +3 1176 918 919 +3 1176 919 1169 +3 1105 1106 4094 +3 3990 3906 4094 +3 1109 4094 1106 +3 4094 1109 3990 +3 4796 4998 6196 +3 4993 2101 4994 +3 2150 2149 4993 +3 4993 4796 2150 +3 2151 2150 4931 +3 4796 4993 4994 +3 4796 4994 4998 +3 4944 4931 6194 +3 4796 6194 2150 +3 4796 6196 6194 +3 2150 6194 4931 +3 2907 894 2944 +3 894 3060 2944 +3 2944 2905 2907 +3 5080 2944 3060 +3 5079 2905 2944 +3 3057 2905 5079 +3 5079 2944 5080 +3 3060 2615 5080 +3 3255 3232 3248 +3 1442 3323 3691 +3 3779 3780 3700 +3 2271 5081 5748 +3 1442 3692 3323 +3 3691 877 1442 +3 1442 3700 3780 +3 5073 1442 877 +3 5856 3323 3692 +3 3248 2271 5748 +3 1442 5073 5072 +3 5083 3700 5072 +3 1442 5072 3700 +3 6418 3232 4839 +3 3173 5073 877 +3 878 5746 5748 +3 1442 3780 3692 +3 6418 2271 3232 +3 5073 3173 5081 +3 2271 3248 3232 +3 5081 5072 5073 +3 5102 877 3691 +3 3173 877 860 +3 5102 860 877 +3 5081 2271 6418 +3 5081 878 5748 +3 5081 3173 878 +3 928 2910 3891 +3 937 928 3891 +3 3894 3891 2910 +3 3249 3215 3237 +3 1102 3990 1103 +3 5951 3999 1102 +3 3990 1102 3999 +3 3094 5080 2577 +3 2615 2577 5080 +3 2582 2577 2615 +3 3094 2577 5891 +3 2577 2582 1056 +3 1055 2577 1056 +3 1055 5891 2577 +3 2582 2612 1056 +3 1056 1054 1055 +3 1054 1056 2612 +3 3359 3779 3700 +3 3359 5083 5889 +3 3359 3700 5083 +3 3345 3353 3456 +3 5778 3353 3345 +3 2471 2472 2446 +3 1407 2269 1307 +3 2270 2268 2269 +3 1656 1545 1547 +3 1656 1547 1658 +3 1151 919 918 +3 918 4031 1151 +3 4094 1104 1105 +3 4104 4109 4132 +3 4109 4108 4132 +3 4108 4094 4132 +3 1104 4094 4108 +3 3846 3844 3839 +3 3829 3844 3846 +3 4388 652 4374 +3 1035 3094 5891 +3 3137 3140 5104 +3 3132 3145 3144 +3 3138 3137 5104 +3 3145 3132 6510 +3 922 921 3139 +3 920 3139 921 +3 922 5731 921 +3 3134 920 3137 +3 3138 3134 3137 +3 5730 6807 3133 +3 920 3134 6807 +3 5730 6808 6807 +3 920 6807 6808 +3 3121 6808 5730 +3 3132 3144 5730 +3 3121 5730 3144 +3 3134 3138 6807 +3 3133 6807 3138 +3 3133 6809 3132 +3 5730 3133 3132 +3 3132 6809 6510 +3 5732 3138 5104 +3 3123 3138 5732 +3 3131 5663 6811 +3 3123 6811 5663 +3 3131 6811 5104 +3 5732 5104 6811 +3 3140 3131 5104 +3 5732 6811 3123 +3 920 921 3137 +3 3140 921 5731 +3 3137 921 3140 +3 6113 4712 784 +3 7023 6113 784 +3 4720 4712 6113 +3 4476 6113 4721 +3 4720 6113 4476 +3 4721 6113 7023 +3 784 7018 7023 +3 3209 3212 3263 +3 3212 3209 3262 +3 5753 3262 3209 +3 5755 3269 3257 +3 3262 5753 3210 +3 3210 3208 3260 +3 3250 3209 3263 +3 5346 5739 999 +3 5346 999 998 +3 3250 3263 1000 +3 1000 998 999 +3 5346 1178 6639 +3 5346 998 1178 +3 3208 3210 5753 +3 5739 3208 5753 +3 3209 3250 5739 +3 999 5739 3250 +3 3250 1000 999 +3 5346 6639 3208 +3 3208 6639 3260 +3 5346 3208 5739 +3 5753 3209 5739 +3 3265 3262 3266 +3 3266 3262 3210 +3 3266 6824 3265 +3 3257 3265 6824 +3 5755 3261 1192 +3 3260 3266 3210 +3 5755 6824 3261 +3 3266 3261 6824 +3 5755 3257 6824 +3 1192 3264 5755 +3 1229 1220 1228 +3 1220 1219 1228 +3 6570 3618 3412 +3 3612 3622 1228 +3 3412 1219 6570 +3 3618 6570 1220 +3 1219 1220 6570 +3 3612 1228 1219 +3 6752 5597 5595 +3 6752 5596 5597 +3 6752 5356 5596 +3 6752 2451 5356 +3 2489 5595 5597 +3 2451 5586 1349 +3 2451 1349 5356 +3 5596 560 6536 +3 6536 5597 5596 +3 2120 5908 5595 +3 6235 5595 2489 +3 2451 6935 5586 +3 6536 560 562 +3 6235 2120 5595 +3 5004 2505 2495 +3 2489 6536 2505 +3 5004 2489 2505 +3 5597 6536 2489 +3 5001 2495 2112 +3 2495 5001 5004 +3 5001 6399 5026 +3 567 2426 5030 +3 5026 6399 5030 +3 567 5030 6399 +3 5595 6935 6752 +3 2451 6752 6935 +3 5908 6935 5595 +3 2421 5001 2112 +3 6399 2421 567 +3 6399 5001 2421 +3 2987 3041 1195 +3 6788 2935 3041 +3 3019 3033 3018 +3 3033 5693 3059 +3 3059 5693 3032 +3 3032 2987 1195 +3 3035 3032 1195 +3 3019 6786 5693 +3 5696 6786 3019 +3 5696 3019 3018 +3 2987 6787 6788 +3 2935 6788 6787 +3 3041 2987 6788 +3 5693 2987 3032 +3 2987 6786 6787 +3 3040 6787 6786 +3 5693 6786 2987 +3 3040 2935 6787 +3 2976 3034 3059 +3 3059 3032 3035 +3 3034 3033 3059 +3 3033 3019 5693 +3 3035 2976 3059 +3 2977 2976 3035 +3 2748 2566 711 +3 711 2566 726 +3 2556 2555 691 +3 692 711 691 +3 2557 711 692 +3 2755 711 2557 +3 2674 2755 2557 +3 2556 711 726 +3 711 2556 691 +3 2564 535 2493 +3 2564 2674 535 +3 2567 623 535 +3 2674 2567 535 +3 2674 2557 2567 +3 623 2567 2557 +3 711 2755 2746 +3 2746 2748 711 +3 2566 2748 2746 +3 623 2557 692 +3 4526 4695 4525 +3 6104 4525 4695 +3 4525 6578 4526 +3 1105 1104 4103 +3 4103 4102 1105 +3 1352 5526 2120 +3 2120 5526 5000 +3 4724 4686 6646 +3 4489 605 7024 +3 4489 5369 605 +3 4489 4725 5369 +3 4725 6646 5303 +3 4725 5303 5369 +3 4501 4715 4703 +3 4715 4489 4703 +3 4703 4489 7024 +3 4686 4501 4687 +3 4715 4501 4686 +3 4715 4686 4724 +3 6055 7026 4501 +3 4501 7026 4687 +3 4725 4715 4724 +3 4725 4489 4715 +3 4725 4724 6646 +3 6006 4231 4152 +3 5991 4145 4149 +3 5991 4146 4145 +3 4145 4146 1003 +3 4152 4231 4151 +3 4150 4233 4197 +3 4151 5991 5995 +3 6006 4197 4233 +3 5995 6976 4152 +3 4197 4152 6976 +3 5995 5991 6976 +3 4149 6976 5991 +3 4151 5995 4152 +3 4149 4197 6976 +3 4150 4197 4149 +3 4152 4197 6006 +3 4066 4131 4067 +3 4128 4127 4066 +3 4128 4066 4067 +3 4126 4066 4127 +3 4127 4080 4126 +3 5986 4066 4126 +3 5986 4131 4066 +3 4126 4080 4115 +3 4080 4133 6971 +3 4126 4116 5986 +3 4127 4128 4133 +3 4116 4126 4115 +3 4080 4127 4133 +3 3944 5958 3938 +3 1143 5957 4002 +3 3991 5957 6961 +3 1116 6961 5957 +3 4001 1116 4008 +3 1148 6588 4020 +3 4019 1148 4020 +3 4001 6588 1148 +3 1116 4001 1117 +3 1142 4017 1144 +3 4017 1143 1144 +3 4021 4017 4020 +3 1142 4020 4017 +3 4020 6588 4021 +3 3983 5950 1117 +3 1116 1117 5950 +3 1116 5950 6961 +3 3992 6961 5950 +3 3992 3991 6961 +3 5957 4008 1116 +3 4017 4021 6962 +3 5957 6962 4008 +3 4021 4008 6962 +3 4021 6588 4008 +3 4001 4008 6588 +3 5958 1143 3938 +3 6963 1144 5958 +3 1143 5958 1144 +3 4017 6962 1143 +3 5957 1143 6962 +3 4018 4019 4020 +3 4018 4020 1142 +3 1144 6963 1142 +3 1121 5990 4088 +3 5990 1121 1110 +3 4169 4150 1007 +3 4150 1016 1007 +3 6014 4695 4526 +3 766 955 6014 +3 6015 670 955 +3 6015 836 670 +3 767 955 766 +3 4273 955 4293 +3 6014 4526 766 +3 4293 955 670 +3 767 6015 955 +3 768 6101 767 +3 6014 955 6102 +3 4273 6102 955 +3 836 6015 837 +3 767 837 6015 +3 6101 837 767 +3 4291 5323 668 +3 4291 670 836 +3 4293 670 4291 +3 4694 6101 768 +3 4693 766 4526 +3 836 5323 4291 +3 4709 768 766 +3 4693 4709 766 +3 768 767 766 +3 4111 4106 4110 +3 4130 4111 4136 +3 5978 4136 4111 +3 4111 4110 5978 +3 1101 3987 5974 +3 5946 5945 3988 +3 3987 5946 3988 +3 3987 1101 941 +3 3987 3988 5974 +3 941 1101 940 +3 5946 3987 3965 +3 941 3965 3987 +3 941 940 835 +3 4232 4150 4169 +3 4232 4233 4150 +3 6006 4233 4232 +3 6006 4232 4454 +3 4169 4454 4232 +3 5245 5371 5318 +3 600 5318 5371 +3 6041 5371 4402 +3 4299 6041 4402 +3 600 5371 6041 +3 600 6041 4400 +3 672 4400 6041 +3 5371 5245 4402 +3 3967 5935 3966 +3 3373 3345 5090 +3 3345 3373 6839 +3 5090 3345 3456 +3 2279 5552 2281 +3 2278 1333 2279 +3 1332 2279 2281 +3 2279 1332 2278 +3 3895 3896 5930 +3 937 5930 3896 +3 2549 2612 5620 +3 4826 1054 2612 +3 2549 5619 2612 +3 4826 2612 5619 +3 5619 2549 6931 +3 5013 4826 6233 +3 6233 5619 6931 +3 4826 5619 6233 +3 3793 3461 3777 +3 6239 7056 6241 +3 2139 1805 4997 +3 2139 4955 1805 +3 2347 2523 5606 +3 1309 1308 2348 +3 5606 1309 2348 +3 2335 5561 2334 +3 2347 5606 2348 +3 2347 5561 2346 +3 2140 4997 2141 +3 2141 2349 2335 +3 4997 2349 2141 +3 2293 2335 2334 +3 2293 2141 2335 +3 2141 2293 2299 +3 2140 2141 2299 +3 2346 2523 2347 +3 2349 2346 2335 +3 2458 2369 6535 +3 2458 2523 2369 +3 2369 2523 2346 +3 2519 5606 5008 +3 5008 5606 5607 +3 2368 6535 2369 +3 2369 2346 2368 +3 2368 5005 6535 +3 2334 5561 2348 +3 2347 2348 5561 +3 2335 2346 5561 +3 2368 2346 2349 +3 2519 1309 5606 +3 2523 5607 5606 +3 1805 4955 1807 +3 4997 1805 2349 +3 2140 2139 4997 +3 2368 2349 5005 +3 2519 2520 2325 +3 2519 5008 2520 +3 2901 5655 5656 +3 2901 6044 5655 +3 5124 6666 1078 +3 4718 6119 6013 +3 602 5319 4754 +3 1077 1079 1078 +3 1077 6122 4690 +3 603 4754 5319 +3 6013 4269 4718 +3 6122 4766 4754 +3 5124 4235 4771 +3 1077 4690 4261 +3 6122 4765 4766 +3 603 6122 4754 +3 4269 4768 4718 +3 4763 604 6119 +3 5124 4771 6666 +3 4261 1079 1077 +3 6109 4704 4705 +3 6119 4718 4750 +3 6119 4270 6013 +3 604 4270 6119 +3 604 7028 4270 +3 602 4270 7028 +3 6121 7028 604 +3 6109 7030 4704 +3 7030 4764 4763 +3 4704 7030 4763 +3 6121 604 4764 +3 4763 4764 604 +3 4690 6122 603 +3 6120 7027 4763 +3 4704 4763 7027 +3 4750 6120 6119 +3 4763 6119 6120 +3 6013 602 4766 +3 4754 4766 602 +3 4270 602 6013 +3 4766 4269 6013 +3 4766 4768 4269 +3 4768 4766 4765 +3 6124 1077 6666 +3 6122 1077 6124 +3 1078 6666 1077 +3 6124 4765 6122 +3 4267 4771 4235 +3 4280 972 4279 +3 4265 6984 1082 +3 4278 6985 6984 +3 1082 6984 6985 +3 4279 6986 4280 +3 6986 6984 4265 +3 4280 6986 4265 +3 4278 6984 6986 +3 4279 4278 6986 +3 4305 6985 4278 +3 6985 4305 1082 +3 3190 864 3159 +3 4414 4411 4417 +3 4432 4434 4435 +3 916 4415 4404 +3 4652 2893 4424 +3 916 2714 4662 +3 4419 2897 2902 +3 4430 2902 2897 +3 2902 4430 992 +3 2714 4424 4662 +3 2714 916 4404 +3 4425 2893 4651 +3 4425 4662 2893 +3 4425 4651 6092 +3 4419 2902 4432 +3 4430 2897 5656 +3 4417 4432 4435 +3 984 986 4655 +3 4424 2893 4662 +3 4655 986 6092 +3 4425 6092 4414 +3 4414 6092 986 +3 986 4411 4414 +3 916 4662 4414 +3 4411 986 4421 +3 916 4417 4415 +3 916 4414 4417 +3 984 983 986 +3 983 4421 986 +3 4411 4421 4432 +3 4432 4421 4419 +3 4411 4432 4417 +3 4662 4425 4414 +3 1127 3956 5951 +3 3996 5951 3992 +3 3992 5951 3956 +3 3992 3956 3991 +3 2952 3264 1193 +3 1193 5757 2952 +3 936 937 3891 +3 3914 3891 3894 +3 937 936 5930 +3 3923 936 3914 +3 3891 3914 936 +3 936 3923 5333 +3 936 5333 5930 +3 4995 2101 4996 +3 4999 2482 5605 +3 2512 5605 2482 +3 2482 4996 5602 +3 4999 2443 2482 +3 2443 4994 4995 +3 4995 4996 2482 +3 2482 2443 4995 +3 4994 2101 4995 +3 4998 4994 2443 +3 2443 4999 4998 +3 5755 3264 3269 +3 1076 6027 6604 +3 4449 6604 6027 +3 2582 2615 2616 +3 2615 2858 2616 +3 3069 5901 2616 +3 2582 2616 5901 +3 2578 2595 5621 +3 5901 2581 2582 +3 5902 2581 5035 +3 3069 2616 3068 +3 5621 5620 2612 +3 2582 5621 2612 +3 2595 5620 5621 +3 2616 2858 3068 +3 5035 2585 5902 +3 2585 5612 5902 +3 2578 5902 5612 +3 2582 2581 5621 +3 2578 5621 5902 +3 5621 2581 5902 +3 5614 2595 2578 +3 5614 2578 5612 +3 993 981 2851 +3 3062 3056 3108 +3 3108 3056 3057 +3 3108 3057 5079 +3 5079 5080 3094 +3 3108 5079 3094 +3 2450 2488 2471 +3 5587 2471 2446 +3 5587 2446 1349 +3 5587 2450 2471 +3 5587 1349 5586 +3 2450 5587 5586 +3 700 4471 4637 +3 4471 2718 4472 +3 4636 826 700 +3 825 4642 2893 +3 4471 700 826 +3 4641 4473 2718 +3 4472 2718 4473 +3 4641 2719 6097 +3 2718 826 4636 +3 4473 6080 4472 +3 2719 825 2893 +3 4636 825 2718 +3 4470 4471 4472 +3 4472 6080 4470 +3 2718 825 4641 +3 6081 700 699 +3 6081 805 700 +3 728 805 6081 +3 700 805 806 +3 807 806 805 +3 826 2718 4471 +3 2887 984 4655 +3 2887 5414 984 +3 699 4637 5377 +3 699 700 4637 +3 806 825 4636 +3 806 4636 700 +3 806 4642 825 +3 4654 4642 806 +3 4641 825 2719 +3 4652 2719 2893 +3 2719 4652 6095 +3 2719 6095 6097 +3 4647 6095 4652 +3 4654 5414 2887 +3 807 5414 806 +3 4654 806 5414 +3 3985 5945 3962 +3 3943 3946 3947 +3 3961 3962 5945 +3 3947 3946 3924 +3 6625 3919 3917 +3 3917 3946 3963 +3 3924 3946 3917 +3 3946 3943 3962 +3 3923 3905 5333 +3 3988 5945 3985 +3 6580 3924 3917 +3 841 3986 3962 +3 3905 3923 5934 +3 841 3943 6409 +3 3924 6580 3945 +3 3943 841 3962 +3 3963 3961 3905 +3 3917 3963 6625 +3 3962 3963 3946 +3 3963 5934 6625 +3 3923 6625 5934 +3 3962 3961 3963 +3 5934 3963 3905 +3 3986 3985 3962 +3 5954 3985 3986 +3 5954 3988 3985 +3 4108 4109 4131 +3 4067 4131 4109 +3 4108 4131 5986 +3 5980 1113 1112 +3 1112 1113 4083 +3 1112 4047 5980 +3 1114 4083 1113 +3 1113 5980 4096 +3 1113 4096 1114 +3 887 1351 743 +3 741 743 1351 +3 887 885 1351 +3 2858 2615 3107 +3 6461 3107 2615 +3 2615 3060 6461 +3 669 668 5323 +3 770 4292 6103 +3 6103 978 770 +3 770 669 4292 +3 978 832 770 +3 761 6101 4714 +3 837 4292 669 +3 6101 761 4292 +3 4694 4714 6101 +3 669 770 832 +3 668 669 963 +3 963 669 832 +3 837 6101 4292 +3 837 669 836 +3 836 669 5323 +3 963 6024 668 +3 6103 4292 761 +3 6795 5657 3055 +3 2614 3055 5657 +3 2614 5657 1027 +3 1028 5340 1027 +3 1027 5340 2614 +3 3006 1027 6785 +3 1028 1027 3006 +3 5657 6795 6785 +3 1027 5657 6785 +3 1407 1307 1299 +3 1407 2180 1408 +3 1299 2180 1407 +3 2174 2180 1299 +3 2180 6718 1408 +3 6535 2400 2458 +3 5005 2400 6535 +3 3314 5772 3701 +3 3314 3701 3672 +3 3715 5772 3314 +3 3314 3672 3715 +3 3254 897 3255 +3 6605 897 3254 +3 2040 1994 2041 +3 3098 3097 2919 +3 2144 5528 6715 +3 5573 2132 2097 +3 1239 1348 2111 +3 2145 2102 2097 +3 5603 2131 4991 +3 4992 4991 2131 +3 2115 6182 2111 +3 2149 2145 4993 +3 6715 5528 5529 +3 2115 2111 1348 +3 2115 1348 4992 +3 2145 2097 4993 +3 2101 4993 2097 +3 4996 2097 2132 +3 2101 2097 4996 +3 2115 2132 5573 +3 5573 6182 2115 +3 2132 5602 4996 +3 4992 5602 2132 +3 2131 5602 4992 +3 2132 2115 4992 +3 2145 4926 2102 +3 2109 2111 6182 +3 5573 2097 2102 +3 2144 6715 2149 +3 2145 2149 6715 +3 4926 2145 5529 +3 2145 6715 5529 +3 2109 6182 6181 +3 2102 6181 5573 +3 6182 5573 6181 +3 4275 4265 4281 +3 972 4275 6100 +3 6106 4681 4275 +3 4275 972 4280 +3 4280 4265 4275 +3 6100 1071 972 +3 4281 6106 4275 +3 6107 4275 4681 +3 6100 4685 1071 +3 6100 4275 6107 +3 4681 6106 4680 +3 6107 4681 4685 +3 4681 4680 4685 +3 6107 4685 6100 +3 3260 3199 6823 +3 2435 2433 2393 +3 2515 2514 2512 +3 2405 2107 6176 +3 2431 2409 2408 +3 2407 5602 2131 +3 5575 2431 2107 +3 2393 5571 5572 +3 4991 2107 5603 +3 2409 5577 2432 +3 6176 2107 4920 +3 2514 2513 2512 +3 2515 5576 2406 +3 5913 2107 4991 +3 2393 5572 2435 +3 2094 1348 2083 +3 2083 4920 2094 +3 2107 2094 4920 +3 2094 4992 1348 +3 5572 5571 2408 +3 2131 2431 2408 +3 2407 2131 2408 +3 2131 5603 2431 +3 2107 2405 5575 +3 5571 5576 2407 +3 2408 2409 2432 +3 2408 2432 5572 +3 2432 2435 5572 +3 2407 5604 5602 +3 2107 2431 5603 +3 2515 2406 2507 +3 2482 5602 5604 +3 2512 2482 5604 +3 2512 2513 5605 +3 5604 5576 2515 +3 2512 5604 2515 +3 2407 5576 5604 +3 2507 2514 2515 +3 2107 5913 2094 +3 4991 4992 5913 +3 2094 5913 4992 +3 5577 2435 2432 +3 2433 2435 2434 +3 2407 2408 5571 +3 6749 2405 6176 +3 2433 6540 2393 +3 2435 5577 2434 +3 2434 6540 2433 +3 5576 2516 2406 +3 2514 2507 2508 +3 2513 2514 2508 +3 743 741 1350 +3 2446 2470 1350 +3 2449 1350 741 +3 2470 740 1350 +3 1350 2449 2446 +3 5583 2449 886 +3 741 886 2449 +3 1351 885 886 +3 886 741 1351 +3 1350 740 743 +3 2116 2118 2119 +3 2116 2119 885 +3 2117 885 2119 +3 2117 886 885 +3 2117 2119 5583 +3 886 2117 5583 +3 3139 3141 925 +3 925 922 3139 +3 5731 922 925 +3 1242 1206 1243 +3 3974 3114 3150 +3 3150 3114 1124 +3 6047 6027 1010 +3 4268 4224 1092 +3 4224 6020 6019 +3 6020 4168 4307 +3 4224 6021 4306 +3 4300 6021 4268 +3 4224 4268 6021 +3 1010 4168 6047 +3 4306 6021 4300 +3 1011 1010 6027 +3 4307 4168 1010 +3 6019 1092 4224 +3 6048 4344 4336 +3 4161 4215 1076 +3 6010 4307 1010 +3 4259 4307 6010 +3 4259 6010 1012 +3 6020 4307 6019 +3 4259 1092 4307 +3 6019 4307 1092 +3 1011 6027 1076 +3 1076 4215 1011 +3 4215 1012 1011 +3 1011 6010 1010 +3 1012 6010 1011 +3 4306 6002 4224 +3 6002 6020 4224 +3 4336 4168 6048 +3 6027 6047 4449 +3 4336 4449 6047 +3 4336 4448 4449 +3 4450 4449 4448 +3 4336 4344 4448 +3 4336 6047 4168 +3 924 5881 3148 +3 1052 618 617 +3 3274 6641 6826 +3 4689 4692 4497 +3 7026 4500 4701 +3 780 6111 4498 +3 7026 6055 4500 +3 4700 6106 4701 +3 4703 7024 4481 +3 6054 6055 4703 +3 653 7017 6110 +3 4500 4692 4701 +3 4694 4709 4498 +3 4694 4498 6111 +3 4501 4703 6055 +3 536 6110 4689 +3 5265 7019 4502 +3 4689 6110 4688 +3 537 6110 4498 +3 6055 4702 4500 +3 4502 4702 6055 +3 4692 4689 4688 +3 653 6578 4525 +3 4693 4526 6578 +3 4693 6578 537 +3 653 537 6578 +3 5265 4495 4710 +3 4689 4497 536 +3 5265 4481 4482 +3 4502 6055 6054 +3 4684 6104 4685 +3 4703 4481 6054 +3 4701 6106 4708 +3 6106 4700 4680 +3 4702 4502 4497 +3 4688 4680 4700 +3 4692 4688 4700 +3 4692 4700 4701 +3 653 4525 6104 +3 4709 537 4498 +3 6110 7017 4688 +3 4693 537 4709 +3 536 7019 4710 +3 4497 7019 536 +3 536 780 4498 +3 536 4710 780 +3 4684 4685 4680 +3 653 6104 4684 +3 653 6110 537 +3 7017 4684 4680 +3 4688 7017 4680 +3 653 4684 7017 +3 4502 7019 4497 +3 4482 4481 7024 +3 4708 7026 4701 +3 5265 4710 7019 +3 4702 4692 4500 +3 536 4498 6110 +3 4692 4702 4497 +3 841 3939 3986 +3 841 6409 3939 +3 840 3939 6409 +3 6409 3943 840 +3 3792 3450 3454 +3 3793 3792 3454 +3 3792 3793 3777 +3 3792 3435 3450 +3 5795 3367 3435 +3 6845 5800 3457 +3 3454 3450 5800 +3 3457 3450 3435 +3 3457 5800 3450 +3 3457 3435 3367 +3 5800 6845 3459 +3 3367 3371 6845 +3 3365 3367 5795 +3 3365 3427 3367 +3 3371 3367 3427 +3 3367 6845 3457 +3 3435 6919 5795 +3 3435 3792 6919 +3 3106 1047 2580 +3 2928 2915 2913 +3 2648 1061 1037 +3 3067 1036 1061 +3 1037 6805 2648 +3 3067 3111 1036 +3 6784 1061 1036 +3 6784 1037 1061 +3 5659 1037 5658 +3 1038 3004 5659 +3 2913 5659 5658 +3 2648 5625 6759 +3 5626 6759 5625 +3 1061 2648 6759 +3 3066 2580 3069 +3 3066 5708 2580 +3 2580 5708 3106 +3 1037 5659 6805 +3 5626 5708 3066 +3 5625 2649 5626 +3 1038 5659 2913 +3 2928 2913 5658 +3 1038 2913 2915 +3 3068 3067 3069 +3 3066 3067 5626 +3 1061 6759 3067 +3 5626 3067 6759 +3 2648 6805 5625 +3 5659 3004 6805 +3 5625 3004 2649 +3 3004 5338 2649 +3 2622 2649 5338 +3 5708 2622 3106 +3 5708 5626 2622 +3 2649 2622 5626 +3 3068 3111 3067 +3 3066 3069 3067 +3 4478 5389 5168 +3 4478 5168 4492 +3 5389 4478 4532 +3 5166 7021 4493 +3 4492 7021 5166 +3 4493 7021 4476 +3 4492 4476 7021 +3 4476 4492 4720 +3 4511 4720 4492 +3 5166 4493 6563 +3 6563 4478 5166 +3 4492 5166 4478 +3 5172 4478 6563 +3 4271 6014 6102 +3 4271 4695 6014 +3 4271 6102 4685 +3 5396 6998 6997 +3 2706 5396 6997 +3 3164 5849 1170 +3 3192 3157 1170 +3 5849 3192 1170 +3 3192 5849 3296 +3 648 2551 5339 +3 649 611 5321 +3 649 625 611 +3 2561 534 6422 +3 5321 611 2774 +3 647 646 5337 +3 5339 4809 648 +3 625 649 2551 +3 2546 625 2551 +3 5609 534 2561 +3 6422 623 2561 +3 535 623 6422 +3 649 5321 647 +3 5321 645 647 +3 647 5337 2551 +3 5339 2551 5337 +3 534 5609 5337 +3 5337 646 6422 +3 535 6422 646 +3 534 5337 6422 +3 5339 5609 4809 +3 5337 5609 5339 +3 648 1063 2553 +3 4809 5609 6754 +3 1063 648 6754 +3 4809 6754 648 +3 642 2546 2553 +3 2551 649 647 +3 2546 2551 2553 +3 648 2553 2551 +3 535 646 2493 +3 646 645 2493 +3 647 645 646 +3 5321 2774 645 +3 1433 3296 1181 +3 1181 1191 1433 +3 1181 1182 1180 +3 1182 3283 1180 +3 5738 6816 1191 +3 5738 1180 6816 +3 1181 5738 1191 +3 1181 1180 5738 +3 3296 1182 1181 +3 1182 3286 3283 +3 1159 1155 4050 +3 1155 5966 4050 +3 1154 5966 1156 +3 4057 4058 5966 +3 5966 4058 6434 +3 5966 1155 1156 +3 1154 1156 4040 +3 4055 4057 1154 +3 4050 4061 4051 +3 1159 4050 4051 +3 4061 4050 6434 +3 4050 5966 6434 +3 4055 1154 4070 +3 1154 4040 4070 +3 4057 5966 1154 +3 4505 4507 831 +3 4490 662 4487 +3 5169 4819 4821 +3 4719 5302 4717 +3 4507 4506 4788 +3 587 6302 4503 +3 4503 6302 6126 +3 4779 4815 593 +3 812 4476 4721 +3 5286 2735 589 +3 4785 4788 4506 +3 4484 4775 593 +3 4487 662 590 +3 830 4483 4503 +3 592 4458 4774 +3 5307 4509 5306 +3 634 5390 605 +3 665 594 592 +3 4780 4783 4485 +3 4508 4514 5172 +3 6302 587 658 +3 4484 4777 4775 +3 2735 591 589 +3 594 4815 4458 +3 787 598 589 +3 4717 4744 4758 +3 588 787 591 +3 4488 4490 4487 +3 4485 5161 4458 +3 4783 658 4485 +3 593 594 4484 +3 4507 4504 831 +3 598 787 6648 +3 4719 4717 5261 +3 658 587 4485 +3 4716 5304 4758 +3 5167 831 5169 +3 5165 4490 4488 +3 4821 4514 5169 +3 4508 5169 4514 +3 4487 587 4488 +3 4483 830 6293 +3 4774 4716 4758 +3 4490 5165 4496 +3 4476 812 4493 +3 4815 594 593 +3 4789 5306 4509 +3 6302 658 659 +3 4491 662 4496 +3 665 592 4758 +3 4490 4496 662 +3 4758 592 4774 +3 4505 4506 4507 +3 4504 5169 831 +3 5286 722 2735 +3 5161 722 5286 +3 830 4506 4505 +3 5165 6293 4499 +3 831 4499 6293 +3 5172 6563 4494 +3 5303 5302 4719 +3 830 4785 4506 +3 587 723 4485 +3 591 2735 588 +3 4504 775 5169 +3 587 4487 723 +3 4485 722 5161 +3 4499 4496 5165 +3 5261 634 4719 +3 4514 4478 5172 +3 771 662 4491 +3 588 2735 723 +3 722 723 2735 +3 4789 4518 4788 +3 4788 4786 4789 +3 5307 4782 5308 +3 4509 5367 4789 +3 4719 5369 5303 +3 634 605 4719 +3 4717 5304 598 +3 4486 5261 6648 +3 598 6648 5261 +3 634 5261 4486 +3 4504 4527 775 +3 5163 813 4491 +3 771 5390 662 +3 4717 598 5261 +3 4458 5161 4774 +3 4504 4507 4518 +3 590 588 7003 +3 4486 588 590 +3 4486 590 662 +3 662 5390 4486 +3 634 4486 5390 +3 5369 4719 605 +3 787 4486 6648 +3 588 4486 787 +3 7003 723 4487 +3 588 723 7003 +3 4487 590 7003 +3 4485 723 722 +3 4788 4518 4507 +3 4481 4502 6054 +3 4716 5286 589 +3 5163 812 6052 +3 813 5163 6052 +3 4721 7023 7018 +3 6052 4721 7018 +3 6052 812 4721 +3 598 5304 4716 +3 598 4716 589 +3 5367 4527 4518 +3 5367 4518 4789 +3 4716 4774 5286 +3 659 6126 6302 +3 4458 592 594 +3 4496 5163 4491 +3 5163 4493 812 +3 5164 4493 5163 +3 4496 5164 5163 +3 5165 4488 6293 +3 4483 6293 4488 +3 4494 5164 4496 +3 4499 4494 4496 +3 5164 6563 4493 +3 4494 6563 5164 +3 4508 5167 5169 +3 4494 5167 4508 +3 5172 4494 4508 +3 831 5167 4494 +3 4499 831 4494 +3 4527 4504 4518 +3 5161 5286 4774 +3 4717 5302 4744 +3 4717 4758 5304 +3 4785 4787 4788 +3 5307 4781 4782 +3 4789 4786 5306 +3 4786 4781 5307 +3 5306 4786 5307 +3 4786 4788 4787 +3 4786 4787 4781 +3 4483 587 4503 +3 6293 4505 831 +3 830 4505 6293 +3 4758 4744 665 +3 4483 4488 587 +3 4485 4458 4780 +3 4784 4785 830 +3 4458 4815 4780 +3 4780 4815 4779 +3 787 589 591 +3 594 665 4484 +3 4777 4484 665 +3 4784 830 4503 +3 2661 2639 2657 +3 5579 2439 2440 +3 2608 5616 2425 +3 4797 2604 6412 +3 2601 6326 2437 +3 2590 2637 2593 +3 5622 2440 2601 +3 5022 5900 5024 +3 5022 5023 2603 +3 2637 2590 610 +3 2440 6326 2601 +3 2650 2657 637 +3 2439 2627 6326 +3 4797 5038 2603 +3 4797 2603 2604 +3 2437 2438 2604 +3 2601 2608 2425 +3 2601 2425 5622 +3 5579 2440 5622 +3 6326 2627 2438 +3 2637 5623 2771 +3 2637 610 5623 +3 2658 2639 2661 +3 2650 2661 2657 +3 2658 2661 2650 +3 3077 6796 5712 +3 5038 2597 5900 +3 5023 2608 2437 +3 2601 2437 2608 +3 2605 2608 5023 +3 5023 2437 2604 +3 2603 5023 2604 +3 2439 6326 2440 +3 6327 2602 2597 +3 6326 2438 2437 +3 2605 5023 5022 +3 2605 5022 5024 +3 5900 2603 5038 +3 5022 2603 5900 +3 1045 2602 6327 +3 4140 4230 4194 +3 4182 4230 4228 +3 4223 4230 4140 +3 4227 4229 4228 +3 4141 4227 4228 +3 4141 4228 4230 +3 4141 4230 4223 +3 4182 4194 4230 +3 6480 3621 3586 +3 3579 6479 1493 +3 6480 3586 3620 +3 3586 3621 3625 +3 3560 6858 3499 +3 3500 1534 6645 +3 6479 3579 3520 +3 6300 3571 3620 +3 3620 6479 6480 +3 3616 5826 6499 +3 3572 3412 3611 +3 3572 1219 3412 +3 6301 3574 6610 +3 3584 6301 6610 +3 3620 3571 6479 +3 5826 3572 3582 +3 1533 6645 1534 +3 3569 3498 6858 +3 3499 6858 3498 +3 3498 3569 6859 +3 1492 6859 3569 +3 6300 6859 3571 +3 3498 6859 6300 +3 3571 6859 1492 +3 5817 3561 6860 +3 3575 3561 5817 +3 3575 5817 3560 +3 1492 3569 3570 +3 3578 3570 3569 +3 3578 3569 1527 +3 3569 6858 1527 +3 3578 1527 1526 +3 3561 3575 3576 +3 3566 3561 3576 +3 1528 1527 6861 +3 6861 1527 6858 +3 5817 6861 6858 +3 3580 3577 6862 +3 1526 6862 3577 +3 6862 1527 1528 +3 3766 6862 1528 +3 1526 1527 6862 +3 3575 3560 3499 +3 3583 3606 6874 +3 5826 3582 6499 +3 3582 3572 3611 +3 3607 3585 3582 +3 3607 3582 3611 +3 3572 3612 1219 +3 6875 3584 6610 +3 3624 6875 6610 +3 517 3584 6875 +3 5826 3622 3612 +3 5826 3612 3572 +3 6301 3584 3575 +3 3576 3575 3584 +3 3583 6874 6875 +3 517 6875 6874 +3 6875 3624 3583 +3 3585 3583 3624 +3 3585 3624 3614 +3 3607 6871 3585 +3 3606 3583 3585 +3 3582 3585 3614 +3 3614 6876 3616 +3 3613 3616 6876 +3 3582 3614 6499 +3 3616 6499 3614 +3 3625 6876 3574 +3 3624 6610 6876 +3 3574 6876 6610 +3 3586 3625 3574 +3 3624 6876 3614 +3 5825 3622 5826 +3 3616 5825 5826 +3 5825 3616 3613 +3 1493 1492 3516 +3 6479 1492 1493 +3 3571 1492 6479 +3 1493 3516 6877 +3 1492 3570 3516 +3 1528 3504 3766 +3 3504 3568 3766 +3 3580 3568 1533 +3 3580 3766 3568 +3 3580 6862 3766 +3 3580 1533 1534 +3 3580 1534 3577 +3 1534 3500 3577 +3 3498 6300 3499 +3 6861 5097 1528 +3 3504 1528 5097 +3 517 3576 3584 +3 6860 5097 6861 +3 5817 6860 6861 +3 3565 5097 6860 +3 3561 3565 6860 +3 3575 3499 6301 +3 6300 3586 3574 +3 6301 6300 3574 +3 6301 3499 6300 +3 6300 3620 3586 +3 6711 1242 5522 +3 1405 6320 1406 +3 1206 1242 6711 +3 6709 6711 2080 +3 1206 6711 6709 +3 4810 1406 6320 +3 6711 5522 1235 +3 1343 4919 2081 +3 6389 4810 1244 +3 1406 4810 4933 +3 2086 6364 1234 +3 4938 6364 2086 +3 1405 1234 6320 +3 1405 1406 2081 +3 5520 1235 6441 +3 2086 1235 5520 +3 1235 5522 6441 +3 2078 2080 1241 +3 2078 6709 2080 +3 1241 2080 1235 +3 1235 2080 6711 +3 1234 1235 2086 +3 1241 1235 1234 +3 1405 1241 1234 +3 2078 1241 1405 +3 1343 2081 1406 +3 6190 1244 6364 +3 6190 6364 4938 +3 1244 6186 6389 +3 1244 6190 6186 +3 2086 5520 4938 +3 1343 1406 4933 +3 6364 1244 6320 +3 1244 4810 6320 +3 1234 6364 6320 +3 4933 4810 6390 +3 6389 6390 4810 +3 6391 6390 4937 +3 4933 6390 6391 +3 6390 6389 4937 +3 1346 6391 4937 +3 4620 4631 5218 +3 4605 4604 6085 +3 4632 5239 5231 +3 4634 5230 5237 +3 4620 1539 5222 +3 6414 4631 802 +3 6414 5218 4631 +3 4626 4459 4460 +3 6586 5230 7032 +3 5222 7032 802 +3 5222 803 7032 +3 4634 802 7032 +3 5230 5228 5237 +3 6267 4621 803 +3 803 5222 6267 +3 4633 5237 5228 +3 4631 4620 5222 +3 5222 802 4631 +3 7032 5230 4634 +3 4604 728 6085 +3 4630 5222 1539 +3 4578 4626 4460 +3 803 6586 7032 +3 6414 4628 5233 +3 802 4634 5238 +3 6472 5237 4633 +3 5222 4630 6267 +3 4594 5198 4467 +3 4623 4606 4624 +3 4623 4618 6564 +3 4620 4623 6564 +3 4618 6565 6564 +3 1539 6564 6565 +3 6565 4618 6079 +3 4587 6565 6079 +3 4522 4661 4521 +3 1539 1540 4630 +3 5200 4596 799 +3 4456 6267 4630 +3 1538 5223 1540 +3 4604 6651 2805 +3 1539 4620 6564 +3 4606 6654 4624 +3 4461 4438 5208 +3 4438 4600 5208 +3 5313 4594 4592 +3 5195 4520 4592 +3 4521 5195 4592 +3 4465 4464 5203 +3 764 4465 4566 +3 6050 4468 7002 +3 4468 4469 7002 +3 4522 4468 6057 +3 4522 4469 4468 +3 4467 4469 4522 +3 5380 5202 4464 +3 4465 5380 4464 +3 764 765 763 +3 5198 7002 4467 +3 4469 4467 7002 +3 4591 6050 7002 +3 6050 799 764 +3 4468 764 763 +3 6050 764 4468 +3 4623 4624 6078 +3 6079 4627 5413 +3 6079 7011 4627 +3 7012 4616 7013 +3 4459 7012 7013 +3 4617 4616 7012 +3 4624 6654 4619 +3 6074 6654 4606 +3 4619 6654 6074 +3 4618 6078 6079 +3 6079 4617 7011 +3 6078 4617 6079 +3 6078 4624 4617 +3 4624 4619 4616 +3 4617 4624 4616 +3 1538 4587 5413 +3 4586 4627 7011 +3 4587 6079 5413 +3 1539 6565 4587 +3 4586 7011 4626 +3 7011 4617 7012 +3 4626 7011 7012 +3 4459 4626 7012 +3 4618 4623 6078 +3 4459 7013 6075 +3 7013 4619 6075 +3 4616 4619 7013 +3 1538 1540 4587 +3 1539 4587 1540 +3 699 5887 4605 +3 6081 699 4605 +3 6081 4605 6085 +3 728 4604 2805 +3 4661 4523 4599 +3 4522 6057 4661 +3 4661 6057 4523 +3 5380 4596 5202 +3 4661 4599 5195 +3 4464 5202 4597 +3 4565 5203 4597 +3 4464 4597 5203 +3 4661 5195 4521 +3 4591 7002 5198 +3 5380 4465 799 +3 764 799 4465 +3 4596 5380 799 +3 4592 4467 4521 +3 4467 4522 4521 +3 5201 5202 4596 +3 5207 5200 795 +3 5203 6659 5384 +3 5207 795 4825 +3 4591 795 5200 +3 799 6050 5200 +3 4591 5200 6050 +3 795 4591 5204 +3 5209 4461 5208 +3 5209 5208 4565 +3 5209 5207 4461 +3 4597 5202 5201 +3 5200 5207 4596 +3 5201 4596 5207 +3 4597 5209 4565 +3 5209 5201 5207 +3 4597 5201 5209 +3 4620 5218 4623 +3 1538 5227 5223 +3 6267 4456 4621 +3 6414 802 5238 +3 4635 6414 5238 +3 5218 6414 5233 +3 5218 5233 4623 +3 6414 4635 4628 +3 4634 4632 5238 +3 5238 4632 5231 +3 5231 4628 4635 +3 5238 5231 4635 +3 6472 6651 4605 +3 4604 4605 6651 +3 4633 6651 6472 +3 4605 5887 6472 +3 4520 5313 4592 +3 4520 4537 5313 +3 5311 5313 4537 +3 5311 4594 5313 +3 4594 4467 4592 +3 4456 1540 5223 +3 1540 4456 4630 +3 764 4566 765 +3 4030 3930 3977 +3 5961 4030 5960 +3 5961 3930 4030 +3 4029 5961 3932 +3 4011 5960 3977 +3 3932 5961 6965 +3 5960 6965 5961 +3 5960 4030 3977 +3 5960 4011 6965 +3 5897 3085 5896 +3 3085 3084 1058 +3 2130 5896 2090 +3 2090 2535 2130 +3 3085 4798 3087 +3 3085 3087 3086 +3 2941 3092 3042 +3 3038 6801 3092 +3 5723 2090 1058 +3 5725 5069 6804 +3 1058 5896 3085 +3 1058 2090 5896 +3 3084 3085 3086 +3 1031 1067 5683 +3 3042 5697 2620 +3 1067 5065 5076 +3 5725 3084 3086 +3 1058 6517 5723 +3 2940 2620 5697 +3 3042 3092 6801 +3 3089 2939 5716 +3 1066 1032 5666 +3 3086 1031 1066 +3 1067 1031 3086 +3 1203 5069 5666 +3 3085 5897 4798 +3 5725 1066 5069 +3 1066 5666 5069 +3 3082 5723 6517 +3 5695 3092 5665 +3 6514 1032 1031 +3 1067 5076 5683 +3 1032 1066 1031 +3 2535 2090 3058 +3 2949 2618 3089 +3 2949 1203 1029 +3 2936 2937 6458 +3 6459 2618 2948 +3 1029 2948 2618 +3 1029 2618 2949 +3 2948 6511 5717 +3 3090 6459 5717 +3 2948 5717 6459 +3 3090 5717 2942 +3 1031 1033 6514 +3 1058 3084 6517 +3 2620 6520 2942 +3 2941 2620 2942 +3 2942 5665 3092 +3 2942 6520 3090 +3 3091 3090 6520 +3 3038 5695 2933 +3 3038 3092 5695 +3 3050 1185 1186 +3 3049 1185 3050 +3 3037 3038 2933 +3 3050 3038 3049 +3 3037 3049 3038 +3 3051 3038 3050 +3 1031 5682 1033 +3 3083 6799 6798 +3 3082 6798 6799 +3 3089 5714 2949 +3 5716 5714 3089 +3 5714 3083 6798 +3 5716 3083 5714 +3 6511 5665 2942 +3 5717 6511 2942 +3 2620 2941 3042 +3 2939 6800 3091 +3 3089 6800 2939 +3 2618 6800 3089 +3 3091 6800 3090 +3 2618 3090 6800 +3 2942 3092 2941 +3 3051 6801 3038 +3 2619 3091 6520 +3 6520 2940 2619 +3 2620 2940 6520 +3 5697 6802 2940 +3 2940 5718 2454 +3 2939 2940 2454 +3 5718 2940 6802 +3 2619 2940 2939 +3 3091 2619 2939 +3 2090 5723 3088 +3 3058 2939 2454 +3 6803 2939 3058 +3 3088 6803 3058 +3 3082 6799 5723 +3 6803 5723 6799 +3 3083 6803 6799 +3 3088 5723 6803 +3 6803 3083 5716 +3 2939 6803 5716 +3 2090 3088 3058 +3 5725 6804 6517 +3 3082 6517 6804 +3 3084 5725 6517 +3 6804 2949 3082 +3 5714 3082 2949 +3 1203 2949 6804 +3 5069 1203 6804 +3 5714 6798 3082 +3 533 2412 2096 +3 2420 533 2413 +3 6937 533 2096 +3 2420 2412 533 +3 4987 2096 2404 +3 2404 2096 5002 +3 2413 533 6937 +3 2095 5002 2096 +3 6937 2096 4987 +3 2096 2412 2095 +3 2095 6482 2416 +3 2412 6482 2095 +3 2099 569 4990 +3 4979 2366 6747 +3 2390 5570 2385 +3 5570 2384 2385 +3 2390 2388 5570 +3 4979 6747 2397 +3 2397 6747 2387 +3 2374 2366 2391 +3 2391 2373 2374 +3 2088 2392 6749 +3 2419 564 5002 +3 2095 2419 5002 +3 6482 2412 6567 +3 2420 6567 2412 +3 4987 6710 4990 +3 2099 4990 6710 +3 4987 4990 6937 +3 2404 5002 564 +3 2088 6938 2392 +3 5570 2397 2384 +3 2387 2384 2397 +3 2419 2416 2417 +3 2095 2416 2419 +3 1124 3114 1177 +3 2782 2784 640 +3 1535 2798 2651 +3 2767 2766 644 +3 1177 3974 1124 +3 2662 2676 2655 +3 2742 644 2766 +3 2689 606 2790 +3 2786 6456 2643 +3 2763 606 2689 +3 1535 2643 2653 +3 5320 640 2784 +3 2645 2646 4734 +3 2684 2741 2690 +3 1177 3114 3974 +3 3979 4037 3978 +3 2791 2790 2760 +3 6456 2785 6455 +3 6455 2784 2782 +3 2787 2655 2676 +3 5636 2655 2792 +3 2654 2792 2655 +3 643 2765 2757 +3 2772 6333 2768 +3 2770 2768 6333 +3 2760 6454 2791 +3 2664 2791 6454 +3 2784 6455 2785 +3 2784 2785 5320 +3 2767 2788 2789 +3 2788 2787 2789 +3 2792 2647 5636 +3 630 2791 2664 +3 2651 2798 2654 +3 2789 2675 2767 +3 643 2769 644 +3 2770 644 2769 +3 2654 2655 2787 +3 2645 2644 2647 +3 2785 6456 2786 +3 2769 2768 2770 +3 641 6333 639 +3 5320 639 6333 +3 2643 6760 2653 +3 1535 2653 636 +3 2640 1535 636 +3 5636 2662 2655 +3 2790 2741 2689 +3 2742 2664 2765 +3 6454 6332 2664 +3 2765 2664 6332 +3 2764 6332 6454 +3 2742 2766 2664 +3 2757 2769 643 +3 640 2772 6758 +3 2772 2634 6758 +3 2770 641 2767 +3 2788 641 639 +3 2767 641 2788 +3 2764 6454 2760 +3 2798 2792 2654 +3 2641 2792 2640 +3 630 631 2690 +3 2675 2685 630 +3 631 630 2685 +3 630 2690 2791 +3 2741 2790 2690 +3 2791 2690 2790 +3 2766 2767 2675 +3 2766 630 2664 +3 2798 2640 2792 +3 2654 2787 2788 +3 2654 2788 2651 +3 639 5320 2786 +3 2785 2786 5320 +3 2651 2788 2786 +3 639 2786 2788 +3 2786 2643 1535 +3 2690 631 2684 +3 2685 2684 631 +3 643 2742 2765 +3 2792 2641 2647 +3 2770 2767 644 +3 630 2766 2675 +3 640 5320 6333 +3 2772 640 6333 +3 2651 2786 1535 +3 2768 2634 2772 +3 643 644 2742 +3 5051 2765 6332 +3 641 2770 6333 +3 2798 1535 2640 +3 2646 2647 2641 +3 2646 2645 2647 +3 2676 2675 2787 +3 2789 2787 2675 +3 2644 2645 4734 +3 6808 3121 3141 +3 2819 5054 2817 +3 2630 2700 4401 +3 6808 3141 3143 +3 3143 3141 3139 +3 820 2889 2890 +3 2814 2752 6338 +3 2705 2700 2720 +3 2630 2720 2700 +3 823 2751 824 +3 5055 2891 2817 +3 2815 2751 5054 +3 2682 2631 2687 +3 5054 2814 2817 +3 2752 2814 5054 +3 5054 2751 2752 +3 823 2808 2806 +3 2806 2751 823 +3 2890 6402 821 +3 5326 2705 715 +3 5327 818 816 +3 5327 816 823 +3 819 816 6633 +3 818 6633 816 +3 817 816 819 +3 4677 4413 5275 +3 4413 4412 6649 +3 2687 6649 4412 +3 702 4645 2808 +3 2630 6757 2682 +3 2631 2682 6757 +3 2720 2630 2682 +3 6761 6633 5629 +3 818 5629 6633 +3 2682 6633 6761 +3 2687 4412 819 +3 2696 715 2705 +3 2700 2665 5627 +3 2665 2692 2667 +3 2665 2691 2692 +3 5326 5630 2705 +3 5326 1019 5630 +3 2667 2692 712 +3 2665 2700 2691 +3 5630 2691 2700 +3 5630 2700 2705 +3 2720 2696 2705 +3 2720 6761 2696 +3 756 2691 5630 +3 756 5630 1019 +3 715 2696 5629 +3 2696 6761 5629 +3 2720 2682 6761 +3 2682 2687 819 +3 817 701 816 +3 2682 819 6633 +3 816 701 823 +3 2816 823 824 +3 702 2808 701 +3 2819 6770 2815 +3 6774 820 2890 +3 821 6774 2890 +3 2891 2894 2819 +3 5654 2894 2889 +3 2890 2889 2894 +3 2816 5327 823 +3 5327 822 818 +3 2816 822 5327 +3 5654 5640 6770 +3 5640 824 6770 +3 2815 6770 824 +3 2816 824 5640 +3 6770 2819 5654 +3 2894 5654 2819 +3 920 6808 3143 +3 920 3143 3139 +3 702 701 2736 +3 6402 2890 2894 +3 2813 2752 2806 +3 2751 2806 2752 +3 2819 2815 5054 +3 824 2751 2815 +3 701 2808 823 +3 4401 2700 5627 +3 4645 7015 2813 +3 2813 6338 2752 +3 2808 2813 2806 +3 4645 2813 2808 +3 2736 6086 702 +3 6086 4645 702 +3 4648 4677 4426 +3 2736 4648 4426 +3 2631 6649 2687 +3 817 4412 4648 +3 701 817 4648 +3 817 819 4412 +3 4677 4648 4413 +3 4413 4648 4412 +3 6116 6757 6115 +3 4729 6116 6115 +3 2630 4401 6757 +3 6115 6757 4401 +3 4729 6649 6116 +3 2631 6757 6116 +3 2631 6116 6649 +3 2736 701 4648 +3 4729 4413 6649 +3 5275 4413 4729 +3 2891 2819 2817 +3 2891 5055 2894 +3 6402 2894 5055 +3 1211 1209 1210 +3 2093 2092 5523 +3 1211 5523 1209 +3 5523 1211 5759 +3 5523 5759 2093 +3 3281 5759 1211 +3 1211 6830 3281 +3 6830 1211 1210 +3 3662 3661 3648 +3 3661 3662 3653 +3 6356 3694 3696 +3 3651 3661 3653 +3 3648 3661 3664 +3 3678 1509 3665 +3 5101 3664 3661 +3 3694 3665 3693 +3 3657 5101 3651 +3 3663 6360 3658 +3 5101 3658 6360 +3 3692 3782 5856 +3 3786 5856 3782 +3 3685 3307 6493 +3 3686 3681 6493 +3 3685 6493 3681 +3 1509 3678 3677 +3 6569 3696 3694 +3 3786 3781 6356 +3 3677 6356 3781 +3 3687 3307 3675 +3 6598 3664 1508 +3 6360 1508 3664 +3 3663 1508 6360 +3 3635 3637 3680 +3 3786 3782 3781 +3 5856 3786 3323 +3 3696 3323 3786 +3 5835 3679 3636 +3 3659 3636 3679 +3 3679 5835 3656 +3 3636 3659 3640 +3 3640 6886 3641 +3 3657 3641 6886 +3 3659 6886 3640 +3 3636 3635 3680 +3 3665 1509 3655 +3 3657 6886 3658 +3 3659 3658 6886 +3 5835 3680 3655 +3 3636 3680 5835 +3 3659 3679 3658 +3 3680 6887 3655 +3 3658 3679 3663 +3 3655 1509 3656 +3 5835 3655 3656 +3 1510 6888 1509 +3 3656 1509 6888 +3 3677 1510 1509 +3 3679 3656 6888 +3 1508 3663 1510 +3 1507 1508 1510 +3 3663 3679 6888 +3 1510 3663 6888 +3 3681 3686 6887 +3 3655 6887 3686 +3 3665 3655 3686 +3 3694 3678 3665 +3 3687 3695 3307 +3 5838 6569 3693 +3 3694 3693 6569 +3 3690 6569 5838 +3 3696 6569 3690 +3 3665 3686 6889 +3 3693 3665 6889 +3 3693 6889 3695 +3 3307 3695 6889 +3 3686 6493 6889 +3 3307 6889 6493 +3 5838 3693 3695 +3 3690 5838 3703 +3 3703 3695 3687 +3 865 3703 3687 +3 5838 3695 3703 +3 3681 3637 6890 +3 3681 6887 3637 +3 3680 3637 6887 +3 6890 6468 3681 +3 3685 3681 6468 +3 3677 1507 1510 +3 3178 3682 5857 +3 5857 3783 3178 +3 1507 3783 1508 +3 5857 6598 3783 +3 1508 3783 6598 +3 3781 3783 1507 +3 3677 3678 6356 +3 3781 3178 3783 +3 3677 3781 1507 +3 3782 3682 3178 +3 3692 3682 3782 +3 3781 3782 3178 +3 3784 6911 3788 +3 3682 3788 6911 +3 3682 6911 5857 +3 6911 3664 6598 +3 5857 6911 6598 +3 3784 3664 6911 +3 3784 3648 3664 +3 3703 865 5102 +3 3657 3658 5101 +3 3696 3786 6356 +3 6356 3678 3694 +3 5101 6360 3664 +3 3651 5101 3661 +3 3834 3833 3838 +3 5873 3847 888 +3 3836 3834 3838 +3 3836 5873 3834 +3 3837 3843 3838 +3 3837 3838 3833 +3 857 3847 3789 +3 857 888 3847 +3 891 3838 3843 +3 890 3836 3841 +3 891 3841 3836 +3 3838 891 3836 +3 3242 5872 3843 +3 2919 5872 3840 +3 3840 5872 3242 +3 5872 2919 3841 +3 5872 3841 891 +3 3843 5872 891 +3 3844 3847 5873 +3 3841 2919 890 +3 3836 890 5873 +3 3844 5873 890 +3 5870 3830 3832 +3 3830 3831 3832 +3 6294 3830 5870 +3 1924 1931 6696 +3 1685 6444 5484 +3 6444 1685 1686 +3 1931 1941 6696 +3 1686 1685 1942 +3 1685 1924 6696 +3 1685 6696 1942 +3 1388 6688 1881 +3 6689 1894 1390 +3 1388 1881 1390 +3 6314 5352 6313 +3 1894 1389 1390 +3 1390 1881 5467 +3 1389 6554 1388 +3 1889 1388 6554 +3 1389 1388 1390 +3 1326 5351 1897 +3 4913 1247 5478 +3 1916 1917 1882 +3 6688 1388 1889 +3 6313 1385 6314 +3 1883 1917 1391 +3 1391 1897 1885 +3 5470 6553 6554 +3 1883 6554 6553 +3 1389 5470 6554 +3 1923 1248 5479 +3 1916 6313 5352 +3 1923 1247 4913 +3 1923 1385 1248 +3 1882 1917 6611 +3 1883 6611 1917 +3 1326 1327 5351 +3 6314 1327 1326 +3 6314 1326 5352 +3 1389 1894 5470 +3 1883 6553 6611 +3 1884 6553 1899 +3 5470 1899 6553 +3 1391 1392 1897 +3 5352 1897 1392 +3 1916 5352 1392 +3 5352 1326 1897 +3 1327 4912 6568 +3 1397 1248 6313 +3 1385 6313 1248 +3 5477 6695 6477 +3 5478 6477 6695 +3 1921 6695 5477 +3 5478 1247 6477 +3 1916 1397 6313 +3 1916 1392 1917 +3 1917 1392 1391 +3 1397 1916 1882 +3 1885 1889 1391 +3 1883 1391 1889 +3 1889 1885 6688 +3 1882 6611 1884 +3 1883 1889 6554 +3 1655 1921 5477 +3 4912 4913 1927 +3 4912 1927 6568 +3 4913 6695 1927 +3 4912 1923 4913 +3 1385 1923 4912 +3 1385 4912 6314 +3 1327 6314 4912 +3 4913 5478 6695 +3 1923 5479 1247 +3 6737 2263 5548 +3 5548 1310 6737 +3 1310 1312 6737 +3 2255 2263 2178 +3 2259 2252 2177 +3 2259 2255 2252 +3 2259 2177 6736 +3 6737 6644 2178 +3 2263 6737 2178 +3 1312 6644 6737 +3 2259 2263 2255 +3 2259 6736 2263 +3 5696 5692 1204 +3 3014 5696 5701 +3 3014 5687 3012 +3 3012 3025 3014 +3 3021 3011 1028 +3 3013 3011 3021 +3 3013 3021 5687 +3 5687 5701 3013 +3 3014 5701 5687 +3 3012 5687 3021 +3 3018 5701 5696 +3 3021 3006 3012 +3 5692 5696 3014 +3 1028 3006 3021 +3 5692 3014 3025 +3 3633 5830 6878 +3 6841 3385 3387 +3 3633 3638 3301 +3 3328 3615 5834 +3 6841 3387 3388 +3 3615 6878 5830 +3 5829 3638 3633 +3 3395 3397 1495 +3 3375 6466 3650 +3 6466 5793 3404 +3 3650 6466 3404 +3 3638 6346 6498 +3 3399 3638 6498 +3 3627 6346 3638 +3 3395 3299 3397 +3 5783 3329 6503 +3 3638 5829 3627 +3 3395 1495 3396 +3 6503 3327 5783 +3 3381 5783 3327 +3 3327 6503 3328 +3 3329 3328 6503 +3 3381 3327 3370 +3 5784 3387 3385 +3 3387 3386 3393 +3 5784 3386 3387 +3 3370 3382 3381 +3 3383 3382 3370 +3 3329 6841 3376 +3 6841 3329 3385 +3 5786 5831 3397 +3 3397 3299 3297 +3 5786 1496 5831 +3 3382 5784 3381 +3 3381 3385 3329 +3 5783 3381 3329 +3 5784 3385 3381 +3 5793 6466 3417 +3 3375 3417 6466 +3 3418 5793 3417 +3 3388 3387 3393 +3 3432 6846 6847 +3 3417 6847 6846 +3 3429 3432 6847 +3 5794 3386 3382 +3 5794 3382 3383 +3 5794 3426 3386 +3 3386 5784 3382 +3 3429 6848 3432 +3 3433 3432 6848 +3 6869 3418 6846 +3 3432 6869 6846 +3 5794 3418 6869 +3 3426 5794 6869 +3 6869 3433 3426 +3 3432 3433 6869 +3 3426 3393 3386 +3 5828 3399 6498 +3 3401 3627 5829 +3 5830 3633 3301 +3 1496 5830 3301 +3 5830 5786 3639 +3 1496 5786 5830 +3 5786 6883 3639 +3 3615 5830 3639 +3 6884 3643 3297 +3 3397 3297 3643 +3 3643 3646 6883 +3 3643 6884 3646 +3 1495 3397 5831 +3 3397 3643 6883 +3 5786 3397 6883 +3 3370 6496 5793 +3 3327 6496 3370 +3 3615 3328 5832 +3 3615 3414 6878 +3 3615 5832 3414 +3 3383 3370 5793 +3 3418 3383 5793 +3 5794 3383 3418 +3 5834 6883 5833 +3 3327 5833 6496 +3 3327 3328 5833 +3 5834 5833 3328 +3 3615 3639 5834 +3 5834 3639 6883 +3 3418 3417 6846 +3 3401 6346 3627 +3 3329 5832 3328 +3 3862 4434 2866 +3 4435 4434 3862 +3 4433 4435 3862 +3 4433 6577 4435 +3 4431 992 4422 +3 4436 992 4431 +3 4436 2866 4434 +3 4431 2866 4436 +3 900 904 902 +3 3863 3116 3117 +3 5332 904 901 +3 3117 3116 5874 +3 5332 902 904 +3 3852 6358 3877 +3 6470 3861 923 +3 882 6470 3864 +3 3861 6470 882 +3 3852 3857 6358 +3 926 3864 3875 +3 882 3864 926 +3 3855 3877 3856 +3 6358 3881 3878 +3 3126 3128 909 +3 3126 909 6806 +3 3128 5874 909 +3 3112 5875 3146 +3 3863 3146 5875 +3 3117 3146 3863 +3 908 909 3116 +3 5874 3116 909 +3 3128 3146 5874 +3 3117 5874 3146 +3 3863 5875 3856 +3 5879 6921 5878 +3 3872 5878 6921 +3 5878 903 5879 +3 5879 902 5332 +3 903 3871 5879 +3 3855 926 3875 +3 5879 5332 6921 +3 901 6921 5332 +3 3855 3875 5878 +3 3872 3852 5878 +3 3855 5878 3852 +3 3864 903 3875 +3 5878 3875 903 +3 3872 6921 901 +3 3855 3856 926 +3 3855 3852 3877 +3 926 3861 882 +3 3861 3856 5875 +3 923 3861 5875 +3 926 3856 3861 +3 3865 5875 3112 +3 923 5875 3865 +3 3147 923 3865 +3 3865 3112 3147 +3 3116 3863 5880 +3 3877 5880 3856 +3 3863 3856 5880 +3 3116 3878 6922 +3 5880 3878 3116 +3 3872 901 3857 +3 3872 3857 3852 +3 3878 5880 3877 +3 3878 3884 6922 +3 908 6922 3884 +3 909 908 6806 +3 3884 3878 3881 +3 908 3116 6922 +3 3877 6358 3878 +3 4112 5978 5977 +3 4110 5977 5978 +3 1161 5972 1162 +3 4113 4129 4045 +3 4124 4045 4129 +3 5971 4135 1162 +3 5972 5971 1162 +3 4056 1162 4099 +3 1161 1162 4056 +3 4056 4099 4105 +3 4112 4129 4136 +3 4135 4136 4129 +3 4129 4112 4124 +3 4099 4129 4105 +3 4113 4105 4129 +3 4099 4135 4129 +3 1162 4135 4099 +3 4112 4136 5978 +3 4124 4112 5977 +3 4135 5988 4136 +3 5971 5988 4135 +3 3744 3739 3755 +3 3709 6894 3683 +3 3156 3157 3753 +3 3748 5851 3755 +3 6352 6353 3318 +3 3317 6352 3318 +3 6353 3160 3721 +3 3755 5851 3746 +3 3746 3744 3755 +3 3747 5851 3748 +3 3746 3749 3743 +3 3666 3727 6352 +3 3739 6492 3738 +3 3730 3738 6492 +3 3666 3317 6495 +3 6353 6352 3160 +3 3716 3318 6353 +3 3735 3716 6353 +3 3735 3721 3718 +3 3722 3723 3730 +3 3160 3669 6628 +3 5845 3669 3160 +3 3735 6353 3721 +3 1503 3667 1506 +3 3291 1506 3631 +3 5842 6893 3683 +3 5842 3667 1503 +3 3709 3683 6897 +3 3160 6628 3721 +3 3719 3721 6628 +3 3718 3721 3719 +3 3723 3722 3724 +3 3740 3723 3724 +3 3642 1503 1506 +3 3666 3726 6900 +3 1501 6900 3726 +3 6897 6893 3726 +3 1501 3726 6893 +3 3683 6893 6897 +3 3709 6897 3318 +3 3317 3318 6897 +3 3666 6352 3317 +3 3666 6900 3642 +3 3229 3709 3318 +3 1503 6900 1501 +3 3642 6900 1503 +3 3666 3642 6901 +3 3669 1224 6354 +3 5845 1224 3669 +3 6897 6495 3317 +3 3726 6495 6897 +3 3727 3666 6901 +3 3716 6902 3318 +3 3229 3318 6902 +3 3747 6903 3749 +3 3746 5851 3749 +3 3163 6904 5852 +3 6904 3719 3737 +3 3163 3719 6904 +3 3724 3722 3737 +3 3746 3737 3722 +3 3719 3724 3737 +3 3719 6628 3724 +3 3669 3724 6628 +3 3749 6907 3743 +3 5852 3743 6907 +3 3737 3743 6904 +3 5852 6904 3743 +3 5852 6907 3720 +3 6906 3156 3754 +3 3720 3754 3156 +3 3753 3720 3156 +3 3720 6903 3754 +3 3747 3754 6903 +3 3749 6903 6907 +3 3720 6907 6903 +3 3737 3746 3743 +3 5851 3747 3749 +3 3722 3730 6492 +3 3746 3722 3744 +3 3739 3744 6492 +3 3722 6492 3744 +3 3740 3756 3723 +3 6624 3758 3756 +3 3740 6624 3756 +3 3756 3730 3723 +3 3756 3758 3730 +3 6893 1503 1501 +3 5842 1503 6893 +3 3642 1506 3291 +3 3720 3753 3161 +3 3163 5852 3161 +3 3720 3161 5852 +3 5845 3160 6352 +3 6352 3727 5845 +3 6354 3740 3724 +3 3669 6354 3724 +3 6463 854 856 +3 5745 6463 856 +3 856 854 6822 +3 3175 864 3193 +3 864 3175 3174 +3 3175 5736 6462 +3 3176 3175 6462 +3 3188 5736 3175 +3 3168 3176 6462 +3 3176 3168 867 +3 1500 867 3168 +3 3174 3158 864 +3 1500 868 867 +3 3176 3174 3175 +3 3158 3174 867 +3 3176 867 3174 +3 3193 3188 3175 +3 867 868 3158 +3 1041 2978 2979 +3 2978 6619 6620 +3 2931 6620 6619 +3 6779 6619 1041 +3 2978 1041 6619 +3 2931 6619 6779 +3 5727 2925 3120 +3 5727 1167 2925 +3 3812 3814 1428 +3 3811 3817 5862 +3 3472 1421 3811 +3 3817 3811 1421 +3 3477 3472 3811 +3 1420 3811 3812 +3 1420 3477 3811 +3 6914 3817 3815 +3 3810 6914 3815 +3 5862 3817 6914 +3 5862 3814 3812 +3 5862 6914 3814 +3 3810 3804 1652 +3 3810 3814 6914 +3 1428 3814 3810 +3 3810 3815 3804 +3 3483 5863 6915 +3 6915 3804 3815 +3 5863 3804 6915 +3 3815 3817 6915 +3 6915 1421 3483 +3 3817 1421 6915 +3 3811 5862 3812 +3 1652 3804 6916 +3 1272 6547 1270 +3 1272 1271 6547 +3 2014 1272 1270 +3 5487 6547 1271 +3 1255 5487 1271 +3 2014 1255 1272 +3 1255 1271 1272 +3 3270 2951 6621 +3 3275 3270 6621 +3 3275 6621 6829 +3 6829 3276 3275 +3 3278 3276 6829 +3 1719 1699 1722 +3 5729 3127 3128 +3 3127 5663 3131 +3 3128 3127 3131 +3 3140 3128 3131 +3 3992 5950 6960 +3 3992 6960 3996 +3 3005 2927 3003 +3 3004 1038 1042 +3 3005 3003 1038 +3 3003 1042 1038 +3 3005 1038 2915 +3 1042 1044 5338 +3 1042 3003 1044 +3 3004 1042 5338 +3 3217 6623 3251 +3 3222 3223 5743 +3 3222 5743 5751 +3 3216 3223 3251 +3 5749 3217 5740 +3 5751 3217 3222 +3 3217 5751 5740 +3 3223 3222 3251 +3 3217 3251 3222 +3 5749 6623 3217 +3 2467 5592 5591 +3 2488 2450 5593 +3 5592 5593 2450 +3 5593 5592 2467 +3 5703 5705 3046 +3 3046 6791 5703 +3 3048 6793 2906 +3 2906 6793 5704 +3 3048 3046 6793 +3 5705 6793 3046 +3 5704 3030 2906 +3 6275 5258 6276 +3 5254 6271 6272 +3 5255 6272 6271 +3 5254 6272 6276 +3 4806 671 5258 +3 6276 6272 6275 +3 5251 4806 4264 +3 5246 6663 5391 +3 5245 5391 6663 +3 5391 4670 5246 +3 5258 4264 4806 +3 6663 5246 6273 +3 5254 6273 6271 +3 5246 6271 6273 +3 6271 5246 6274 +3 4670 6274 5246 +3 6274 5255 6271 +3 6275 6272 5255 +3 5258 6275 4264 +3 4000 5956 1117 +3 1149 1148 4013 +3 4028 4022 1149 +3 5956 4022 5964 +3 4013 4028 1149 +3 4000 1117 4001 +3 1148 1149 4001 +3 4000 4001 1149 +3 4000 1149 4022 +3 4028 4007 4022 +3 5956 4000 4022 +3 6966 5964 4022 +3 4007 6966 4022 +3 4007 4037 6966 +3 1072 4295 1073 +3 668 6427 4295 +3 1072 4294 4295 +3 4295 6427 1073 +3 4326 1073 6427 +3 668 6024 4326 +3 6024 4327 4326 +3 4326 4327 1073 +3 668 4326 6427 +3 656 5110 4246 +3 5965 1155 4042 +3 1153 4055 4043 +3 4043 1164 4134 +3 4044 4055 4070 +3 6968 4040 5965 +3 3889 6968 4042 +3 4134 1153 4043 +3 4134 3149 1152 +3 4041 1164 4043 +3 4070 4041 4044 +3 4041 4043 4044 +3 1155 5965 1156 +3 4040 1156 5965 +3 1153 4134 1152 +3 4134 1164 1158 +3 1158 1164 3890 +3 6968 6967 3890 +3 4040 6968 3890 +3 3889 6967 6968 +3 4042 6968 5965 +3 1158 3890 6967 +3 4041 4070 3890 +3 4040 3890 4070 +3 1164 4041 3890 +3 2818 2814 6338 +3 6338 2888 2818 +3 2818 2820 2814 +3 4639 2820 2818 +3 2813 2888 6338 +3 2813 7015 2888 +3 2888 4639 2818 +3 7064 5245 5318 +3 5318 600 5317 +3 600 4399 5317 +3 7064 5318 601 +3 977 5278 6406 +3 601 6406 5279 +3 5279 6406 5278 +3 601 6411 6406 +3 977 6406 6411 +3 601 5318 599 +3 5317 599 5318 +3 599 6411 601 +3 7065 5252 6411 +3 977 6411 5252 +3 599 7065 6411 +3 601 5279 7064 +3 4003 5970 5969 +3 4003 5969 1119 +3 4003 3997 5970 +3 4003 3998 3997 +3 3997 3998 6960 +3 1119 1118 4003 +3 3998 3996 6960 +3 1118 3996 3998 +3 1118 3998 4003 +3 4076 1118 1119 +3 4076 1119 5969 +3 5972 6972 5971 +3 5971 6972 5988 +3 6966 4037 4034 +3 4034 4037 3979 +3 768 4709 4694 +3 6574 1174 1168 +3 4039 1174 6574 +3 3151 4039 6574 +3 1175 4039 3151 +3 3979 3978 1175 +3 3979 1175 3151 +3 2823 2853 979 +3 671 5125 5406 +3 4293 4296 6022 +3 4296 4312 6022 +3 4296 4293 4291 +3 4312 4296 1072 +3 4291 4294 4296 +3 1072 4296 4294 +3 668 4295 4294 +3 4291 668 4294 +3 3997 6960 5950 +3 4004 3997 3982 +3 3982 3997 3983 +3 834 3982 3983 +3 3997 5950 3983 +3 4088 5990 5975 +3 5125 2703 5039 +3 5125 4806 2703 +3 1100 1098 1099 +3 4256 4203 4257 +3 1099 1098 5994 +3 1098 4256 4198 +3 6041 4299 672 +3 4808 672 4299 +3 672 4808 650 +3 1345 2328 1344 +3 4958 1344 2290 +3 554 2293 555 +3 2299 2289 1340 +3 554 2328 1345 +3 554 555 2326 +3 5558 2290 2297 +3 2297 2290 1344 +3 2299 1345 2289 +3 2336 555 2293 +3 2296 5558 2297 +3 2336 2293 2334 +3 1345 2293 554 +3 1345 2299 2293 +3 4956 2285 1345 +3 1345 2285 2289 +3 4958 1345 1344 +3 1345 4958 4956 +3 2285 1340 2289 +3 4421 4420 4419 +3 4420 6044 2901 +3 4420 4421 6044 +3 6509 895 3219 +3 1658 1547 1659 +3 1542 1658 1659 +3 2947 2988 2946 +3 6801 3039 3042 +3 2923 3052 2920 +3 3052 2923 2905 +3 2923 2907 2905 +3 3047 3052 2946 +3 2988 3039 2946 +3 5698 3039 2988 +3 2920 3052 3047 +3 5720 5719 3057 +3 2947 5719 3022 +3 3051 3039 6801 +3 3047 2946 1186 +3 2947 3052 2905 +3 2946 3052 2947 +3 3057 5719 2905 +3 1186 2946 3050 +3 2988 3022 3023 +3 3039 5698 5697 +3 2946 3039 3051 +3 2946 3051 3050 +3 2947 3022 2988 +3 2905 5719 2947 +3 3022 5719 5720 +3 3100 3022 5720 +3 2988 3023 5698 +3 3022 3100 3023 +3 1352 514 742 +3 2481 2121 688 +3 742 5526 1352 +3 689 2121 5590 +3 5325 6631 688 +3 6631 2481 688 +3 515 689 5590 +3 5590 742 514 +3 2121 689 688 +3 2323 612 515 +3 514 6452 5590 +3 5590 5580 742 +3 5526 742 5580 +3 2121 5580 5590 +3 2481 6538 2442 +3 5033 6572 2539 +3 690 6631 2322 +3 5325 2322 6631 +3 690 6632 736 +3 736 6631 690 +3 2481 6631 736 +3 2481 736 6538 +3 736 6632 6538 +3 2442 5580 2481 +3 2121 2481 5580 +3 515 2474 689 +3 612 2474 515 +3 613 6572 5031 +3 5325 2539 2322 +3 5031 2474 612 +3 5033 2539 5325 +3 5325 688 5033 +3 689 5033 688 +3 2323 4929 612 +3 4929 5031 612 +3 4929 613 5031 +3 2474 5031 5033 +3 2474 5033 689 +3 5033 5031 6572 +3 2486 2343 6359 +3 2486 6359 2500 +3 6375 4944 6194 +3 6195 6194 6196 +3 6375 6194 6195 +3 2447 5581 5584 +3 2555 2543 691 +3 633 691 2543 +3 2543 2555 734 +3 632 633 2543 +3 632 694 633 +3 734 2559 2543 +3 632 2456 694 +3 695 694 2456 +3 2456 632 2559 +3 2543 2559 632 +3 735 734 2555 +3 6280 5267 5266 +3 4726 5259 5267 +3 4726 6278 5259 +3 695 627 5009 +3 2548 6233 6931 +3 2572 5620 5615 +3 2595 5615 5620 +3 2549 5620 5610 +3 626 5009 627 +3 2572 5610 5620 +3 5015 5009 626 +3 2547 6421 6398 +3 2598 6398 6421 +3 5615 1064 1062 +3 5615 1062 2572 +3 5021 5609 2561 +3 2552 5609 5021 +3 2549 5610 2571 +3 1063 2552 1062 +3 1062 1064 1063 +3 1064 5615 5614 +3 5614 5615 2595 +3 626 6756 5015 +3 2545 2548 6756 +3 5015 6756 2568 +3 2548 2568 6756 +3 2552 2598 1062 +3 2572 1062 2598 +3 5021 2598 2552 +3 2571 5610 2598 +3 2572 2598 5610 +3 6931 2549 2571 +3 2547 2571 6421 +3 2598 5021 6398 +3 2571 2598 6421 +3 2547 2568 2571 +3 2547 5015 2568 +3 2548 6931 2568 +3 2571 2568 6931 +3 2545 6756 626 +3 5021 2561 6398 +3 5015 2547 6397 +3 2545 6233 2548 +3 5009 693 694 +3 694 695 5009 +3 693 6398 2561 +3 5009 6397 693 +3 6397 5009 5015 +3 6397 6398 693 +3 2547 6398 6397 +3 4284 5156 6046 +3 6046 4298 4284 +3 4318 842 4316 +3 6017 4285 4284 +3 4297 4316 842 +3 842 4319 6033 +3 4284 4289 4286 +3 4285 4289 4284 +3 5156 4284 4286 +3 4319 842 4318 +3 4284 4298 6017 +3 4354 4316 4297 +3 6017 4297 945 +3 961 4354 4297 +3 952 961 6046 +3 4298 961 4297 +3 4283 6046 5156 +3 4283 952 6046 +3 944 945 946 +3 5334 944 946 +3 965 4283 5156 +3 842 6033 946 +3 5334 946 6033 +3 946 945 842 +3 4297 842 945 +3 4298 6046 961 +3 4297 6017 4298 +3 965 5156 4286 +3 945 4285 6017 +3 2326 2327 554 +3 2326 2338 2327 +3 2328 554 2327 +3 2295 2296 6741 +3 2297 6741 2296 +3 2328 2327 5555 +3 2338 5555 2327 +3 1344 2328 5555 +3 2338 5556 5555 +3 5555 5556 5557 +3 6741 1344 5555 +3 5557 6741 5555 +3 2297 1344 6741 +3 2295 6741 5557 +3 3237 3219 895 +3 3215 3219 3237 +3 3780 3790 3179 +3 3692 3780 3179 +3 520 5551 3778 +3 3778 3822 520 +3 2269 1339 5866 +3 2108 2251 518 +3 1339 2269 1407 +3 518 1410 519 +3 520 3822 518 +3 1339 519 3820 +3 3793 3453 3461 +3 520 1298 5551 +3 1407 1408 1339 +3 1410 518 3822 +3 3822 3778 2267 +3 3821 3461 3453 +3 3459 5866 3460 +3 2251 520 518 +3 519 1339 2108 +3 3355 5798 5799 +3 3453 5799 5798 +3 1410 3819 519 +3 1412 3455 5798 +3 5799 3793 3454 +3 3460 5799 3454 +3 3453 3793 5799 +3 3455 3821 3453 +3 3453 5798 3455 +3 3820 5799 3460 +3 518 519 2108 +3 5800 3460 3454 +3 3819 3820 519 +3 2220 520 2251 +3 3820 3355 5799 +3 3355 1412 5798 +3 5866 1339 3820 +3 1410 3355 3819 +3 1298 520 2220 +3 1410 1412 3355 +3 1339 1408 2108 +3 3459 3460 5800 +3 3355 3820 3819 +3 3460 5866 3820 +3 2267 1410 3822 +3 739 5588 740 +3 5588 743 740 +3 4404 4646 4405 +3 2714 4404 4405 +3 4665 4646 4666 +3 6097 6095 4665 +3 4650 4646 4665 +3 4650 4405 4646 +3 4665 4666 6097 +3 1781 1867 5452 +3 1781 5452 5453 +3 4890 6162 6163 +3 1867 6163 6162 +3 1789 4890 6163 +3 4836 4890 6603 +3 1789 6684 1816 +3 5450 4890 1789 +3 1816 5450 1789 +3 1789 6163 1867 +3 1867 6684 1789 +3 1867 5468 5452 +3 5468 6687 5452 +3 1867 1781 6684 +3 4890 5450 6603 +3 1867 6162 5468 +3 6999 4385 4395 +3 4454 4169 4447 +3 4202 6008 4201 +3 1014 4155 5996 +3 4236 4202 4200 +3 6008 5392 4207 +3 6000 1089 6980 +3 1014 4187 4155 +3 4252 5392 4202 +3 4204 4190 4257 +3 6594 4186 4187 +3 4207 6009 6008 +3 1005 6473 6977 +3 4202 4201 4200 +3 1090 4205 4209 +3 6980 4155 4187 +3 4201 6008 4255 +3 4209 4205 4201 +3 4200 4201 4205 +3 4205 4203 4260 +3 4200 4260 4235 +3 1097 6003 4192 +3 4205 1090 4190 +3 4190 4204 4205 +3 4199 4190 1090 +3 4209 4201 4255 +3 6473 1005 4211 +3 4204 4257 4203 +3 4191 4257 4190 +3 4155 6980 1089 +3 6008 4202 5392 +3 6009 4255 6008 +3 1090 4154 4199 +3 5124 4236 4235 +3 4260 4200 4205 +3 6594 4211 6005 +3 1005 6005 4211 +3 4187 4211 6594 +3 5124 1078 4236 +3 4252 4236 1078 +3 5336 1013 6473 +3 4211 5336 6473 +3 1089 4154 5993 +3 4155 1089 5993 +3 4190 4192 4191 +3 4154 1089 1097 +3 4154 1097 4199 +3 4199 1097 4192 +3 4199 4192 4190 +3 4155 5993 5996 +3 4209 5996 5993 +3 6473 5116 6977 +3 1013 5116 6473 +3 5336 1014 4210 +3 5997 5336 4210 +3 5336 4211 1014 +3 4187 1014 4211 +3 4186 6594 4226 +3 6005 4226 6594 +3 4210 4255 6009 +3 4208 6009 4207 +3 4205 4204 4203 +3 4154 1090 4209 +3 4206 1013 5997 +3 5336 5997 1013 +3 5997 4210 6009 +3 4208 5997 6009 +3 4208 4206 5997 +3 1014 5996 4210 +3 4209 4210 5996 +3 4154 4209 5993 +3 4209 4255 4210 +3 4200 4235 4236 +3 1013 4206 5116 +3 4202 4236 4252 +3 4705 4707 597 +3 4705 4704 4707 +3 597 6117 596 +3 6118 596 6117 +3 595 6118 6117 +3 4748 667 5288 +3 5288 666 4749 +3 667 666 5288 +3 4751 4748 5288 +3 4751 5288 4760 +3 4707 6117 597 +3 666 596 6118 +3 666 667 596 +3 4750 4749 6120 +3 666 6120 4749 +3 4707 4704 7027 +3 6120 595 7027 +3 4707 7027 595 +3 666 595 6120 +3 666 6118 595 +3 595 6117 4707 +3 4760 5288 4749 +3 4749 4750 4760 +3 5655 983 5656 +3 6030 4366 4318 +3 4318 4316 6030 +3 6990 4366 6030 +3 6030 4316 6990 +3 2924 2920 1187 +3 3029 6531 2923 +3 2920 2924 2923 +3 3029 2923 2924 +3 2906 6531 3029 +3 3046 3048 6791 +3 1187 6791 3048 +3 1187 3048 2924 +3 3048 2906 3029 +3 2924 3048 3029 +3 1827 1829 1393 +3 1932 1393 1829 +3 1828 4891 1864 +3 5451 1829 1827 +3 1828 1864 5467 +3 1932 1885 1897 +3 1828 1881 5451 +3 1827 6474 5451 +3 1828 5451 6474 +3 5467 1881 1828 +3 6688 1885 1829 +3 1829 5451 6688 +3 1881 6688 5451 +3 1932 1829 1885 +3 2338 2326 2333 +3 2331 553 6291 +3 555 5554 2326 +3 2333 2337 2338 +3 2325 1818 2519 +3 2333 6322 2332 +3 2321 553 552 +3 2331 2246 553 +3 1818 553 2246 +3 2321 6291 553 +3 2336 6743 555 +3 2333 2326 5554 +3 2332 5557 2337 +3 5556 2337 5557 +3 2330 2332 2329 +3 2337 2333 2332 +3 2338 2337 5556 +3 1308 2336 2334 +3 2332 2331 2329 +3 6743 5554 555 +3 2331 6291 2329 +3 2519 2247 1309 +3 6322 2331 2332 +3 5554 5560 6322 +3 6322 5560 2246 +3 2246 2247 1818 +3 5554 6322 2333 +3 2330 2295 5557 +3 2332 2330 5557 +3 5560 6742 2246 +3 5554 6743 5560 +3 6742 6743 2336 +3 1308 6742 2336 +3 5560 6743 6742 +3 2246 6742 2247 +3 1308 2247 6742 +3 2348 1308 2334 +3 1309 2247 1308 +3 2247 2519 1818 +3 552 2320 2321 +3 2246 2331 6322 +3 2862 2809 2882 +3 2889 820 2809 +3 820 2882 2809 +3 2698 2881 2895 +3 2810 2698 2895 +3 2861 5640 2881 +3 2895 2881 2889 +3 2883 2861 5056 +3 2861 2881 754 +3 2869 2809 2862 +3 2869 2862 2868 +3 2810 755 2698 +3 2883 5056 822 +3 2883 822 2816 +3 674 5642 6771 +3 2867 6771 5643 +3 2861 754 5056 +3 673 2867 2880 +3 2810 2895 2809 +3 2816 2861 2883 +3 2895 2889 2809 +3 673 6771 2867 +3 674 6771 673 +3 2810 2809 2869 +3 674 982 2810 +3 2881 2698 754 +3 754 2698 755 +3 673 982 674 +3 673 2880 982 +3 755 2810 6419 +3 982 6419 2810 +3 2889 2881 5654 +3 5654 2881 5640 +3 2816 5640 2861 +3 2868 5642 2869 +3 674 2869 5642 +3 2810 2869 674 +3 870 3168 3170 +3 3249 3237 880 +3 3253 899 5741 +3 6817 3218 5742 +3 3218 3169 5736 +3 870 3169 3218 +3 880 3237 3186 +3 5741 880 3167 +3 899 880 5741 +3 3186 3237 895 +3 3169 870 3170 +3 3249 899 3216 +3 3169 3170 6462 +3 3168 6462 3170 +3 880 899 3249 +3 3169 6462 5736 +3 3167 3218 5741 +3 5741 3218 6817 +3 870 3218 3167 +3 5741 6817 3253 +3 3964 3900 3904 +3 3900 5946 3965 +3 6956 3901 5929 +3 3964 3901 3900 +3 3964 5929 3901 +3 3901 3961 5945 +3 3901 5946 3900 +3 3901 5945 5946 +3 6956 3961 3901 +3 943 942 6637 +3 6637 5930 5333 +3 942 5930 6637 +3 5929 943 6637 +3 943 935 3895 +3 943 3964 935 +3 3904 935 3964 +3 3895 942 943 +3 3895 5930 942 +3 5929 3964 943 +3 3904 6410 935 +3 3905 6637 5333 +3 6956 6637 3905 +3 3961 6956 3905 +3 5929 6637 6956 +3 3412 3413 3611 +3 1460 3610 5824 +3 3617 1460 5824 +3 3619 3610 1494 +3 3607 3619 6500 +3 3394 6500 3619 +3 3410 1460 1458 +3 1494 3392 3604 +3 3607 6506 3619 +3 3611 6506 3607 +3 1458 3393 3410 +3 3389 3410 3393 +3 3388 3393 1458 +3 3392 3389 3604 +3 3393 3604 3389 +3 3389 3392 3410 +3 1494 3394 3619 +3 1494 3604 3394 +3 3607 6500 6871 +3 6506 5824 3610 +3 3619 6506 3610 +3 3413 5824 6506 +3 3611 3413 6506 +3 3410 3610 1460 +3 3618 3617 3413 +3 5824 3413 3617 +3 3392 1494 3610 +3 3392 3610 3410 +3 3618 3413 3412 +3 4194 4220 4221 +3 4221 4140 4194 +3 4220 4196 1096 +3 4221 6000 6001 +3 4220 4194 4196 +3 1089 6000 4221 +3 6001 4140 4221 +3 1096 4195 4220 +3 4141 4223 6001 +3 4140 6001 4223 +3 4195 1097 1089 +3 4221 4220 1089 +3 4195 1089 4220 +3 1096 1097 4195 +3 4263 6029 4337 +3 4337 4344 4263 +3 4253 4225 4310 +3 4343 4446 6028 +3 4253 4310 4254 +3 4311 4254 4310 +3 4310 4225 4308 +3 4225 6002 4308 +3 4253 6989 4315 +3 4338 4315 6989 +3 4315 6029 4225 +3 4337 6029 4315 +3 6048 6020 4263 +3 4315 4225 4253 +3 4338 4339 4343 +3 6028 4338 4343 +3 4338 6993 4339 +3 4334 4339 6993 +3 4334 6993 6032 +3 4311 4310 4308 +3 4254 6032 4253 +3 6032 6993 6989 +3 4338 6989 6993 +3 4253 6032 6989 +3 6002 6029 4263 +3 4263 6020 6002 +3 4225 6029 6002 +3 6048 4263 4344 +3 4344 4337 6028 +3 4344 6028 4446 +3 6028 4315 4338 +3 4337 4315 6028 +3 2450 5585 5592 +3 5908 5585 6935 +3 6935 5585 5586 +3 5585 2450 5586 +3 5592 5585 5591 +3 5585 5908 5591 +3 5655 6044 983 +3 4421 983 6044 +3 6577 4417 4435 +3 4423 6486 4437 +3 4390 4423 4437 +3 4415 4417 4423 +3 4423 957 4415 +3 4390 957 4423 +3 4423 6577 6486 +3 4417 6577 4423 +3 4542 4723 4543 +3 4559 4541 4544 +3 762 761 760 +3 6016 1069 5372 +3 1069 6016 947 +3 4288 4656 4657 +3 4542 759 4723 +3 1069 5256 5372 +3 1069 759 5256 +3 6103 762 769 +3 978 769 4290 +3 4559 4544 6060 +3 5256 4287 5372 +3 4714 4477 4546 +3 4541 4559 4542 +3 769 947 4290 +3 4544 6059 6060 +3 4553 4546 4477 +3 5376 4559 6060 +3 4546 760 4714 +3 4289 4657 792 +3 5256 759 5257 +3 4543 4541 4542 +3 6060 6059 4545 +3 759 760 4546 +3 4289 4288 4657 +3 4285 4288 4289 +3 5376 4542 4559 +3 5257 4542 5376 +3 760 761 4714 +3 759 4711 4723 +3 4287 944 5372 +3 944 6016 5372 +3 6016 4290 947 +3 4543 7007 7006 +3 947 769 762 +3 769 978 6103 +3 761 762 6103 +3 760 6105 762 +3 947 762 1069 +3 6105 1069 762 +3 759 6105 760 +3 6105 759 1069 +3 4711 759 4546 +3 4723 4711 7007 +3 4543 4723 7007 +3 4656 6060 4545 +3 4657 4656 4545 +3 5376 6060 4656 +3 4288 4285 4287 +3 4285 945 4287 +3 944 4287 945 +3 5256 5257 4288 +3 5257 4656 4288 +3 5256 4288 4287 +3 4542 5257 759 +3 4656 5257 5376 +3 6614 4713 778 +3 6614 778 6111 +3 6614 6111 780 +3 4713 6614 780 +3 1330 4834 4836 +3 4834 1330 4891 +3 6162 4834 5922 +3 4890 4836 4834 +3 4834 6162 4890 +3 4891 5922 4834 +3 1828 5922 4891 +3 5922 1828 6474 +3 5922 6474 6687 +3 1836 6687 6474 +3 5468 5922 6687 +3 1827 1836 6474 +3 6162 5922 5468 +3 6605 896 897 +3 898 6509 3236 +3 896 3236 6509 +3 3236 3225 3221 +3 3225 3236 6605 +3 896 6605 3236 +3 3238 3225 6605 +3 3236 3221 898 +3 4650 4665 4647 +3 4647 4665 6095 +3 6449 2148 2168 +3 2156 2165 2148 +3 2148 6449 2156 +3 2146 2156 6449 +3 2168 2146 6449 +3 4098 1110 4100 +3 1106 1134 1133 +3 1133 4098 4100 +3 4098 1133 1134 +3 3262 3259 3212 +3 3262 3265 3259 +3 3617 3618 3409 +3 3755 3739 3736 +3 3739 3738 3736 +3 3165 3201 3164 +3 5766 3284 5764 +3 5766 5764 3285 +3 5765 5849 3164 +3 5765 3201 5764 +3 5347 1213 3273 +3 1213 3284 3273 +3 3283 3286 1213 +3 3284 1213 3286 +3 5764 3286 5765 +3 3284 3286 5764 +3 5766 5767 3284 +3 3273 3284 5767 +3 3286 5850 5765 +3 5849 5765 5850 +3 5765 3164 3201 +3 5850 3286 1182 +3 4374 650 4808 +3 2573 6231 5060 +3 957 4395 4391 +3 4395 957 4390 +3 1864 4891 1790 +3 1790 1869 1864 +3 1390 5467 1869 +3 5467 1864 1869 +3 1330 1790 4891 +3 1869 1398 1390 +3 6689 1390 1398 +3 1398 1328 6689 +3 1333 2241 2279 +3 5552 2274 1336 +3 2288 2286 5354 +3 2280 1354 1353 +3 2275 2282 2280 +3 1335 5552 1336 +3 2165 2156 6716 +3 1354 1335 1336 +3 2276 6542 2286 +3 5353 1311 5354 +3 1337 5353 5354 +3 1807 4955 5563 +3 4954 2142 5563 +3 1341 2299 1340 +3 2273 1336 2274 +3 2241 2274 5552 +3 1335 1354 1340 +3 6735 2241 1333 +3 2164 2159 6545 +3 2153 6545 2159 +3 2155 2153 2165 +3 2280 1353 2275 +3 1336 1353 1354 +3 1337 5354 2286 +3 1340 2272 1335 +3 2279 2241 5552 +3 2286 2277 2276 +3 6644 1311 5353 +3 2275 2276 2277 +3 2277 2282 2275 +3 2155 6716 2142 +3 6644 5353 6451 +3 6451 5353 1337 +3 6542 1337 2286 +3 2273 5546 2261 +3 1311 2288 5354 +3 4954 5563 4955 +3 2282 1341 2280 +3 1337 719 6451 +3 6735 5546 2273 +3 4954 4955 547 +3 2280 1340 1354 +3 6541 2288 2287 +3 2277 2286 2288 +3 719 2253 6451 +3 2275 2261 2276 +3 547 4955 2139 +3 2288 6541 2277 +3 2288 1311 2158 +3 2273 2261 2283 +3 2288 2158 2154 +3 2287 2284 6541 +3 2287 2154 2284 +3 1340 2280 1341 +3 1337 6542 2261 +3 2276 2261 6542 +3 2154 2155 6544 +3 2142 6544 2155 +3 1310 2164 6545 +3 2282 2277 6541 +3 1311 6644 1312 +3 548 2139 2140 +3 546 547 2284 +3 2284 2154 546 +3 2153 2158 6545 +3 2154 2158 2153 +3 2154 2153 2155 +3 2165 2153 2159 +3 2142 4954 6544 +3 546 6544 4954 +3 2154 6544 546 +3 2165 6716 2155 +3 1310 6545 2158 +3 5540 1333 1334 +3 1333 5540 718 +3 718 5540 2253 +3 719 718 2253 +3 1333 718 6735 +3 5546 6735 718 +3 1337 2261 719 +3 6541 2284 548 +3 2282 6541 548 +3 547 548 2284 +3 548 1341 2282 +3 6735 2274 2241 +3 2273 2274 6735 +3 1334 1333 2278 +3 1336 2273 1353 +3 2283 1353 2273 +3 2283 2261 2275 +3 1353 2283 2275 +3 2158 1311 1312 +3 1310 2158 1312 +3 2288 2154 2287 +3 719 2261 5546 +3 719 5546 718 +3 1341 2140 2299 +3 548 2140 1341 +3 546 4954 547 +3 548 547 2139 +3 900 3871 906 +3 902 3871 900 +3 3871 902 5879 +3 5324 778 4713 +3 784 5324 779 +3 4713 779 5324 +3 5324 784 4712 +3 6426 778 5324 +3 6426 679 778 +3 780 779 4713 +3 4495 4480 779 +3 784 779 4480 +3 4480 4495 813 +3 4710 4495 779 +3 780 4710 779 +3 4495 4491 813 +3 6052 7018 813 +3 4480 813 7018 +3 784 4480 7018 +3 5324 4712 6426 +3 5881 5731 925 +3 3148 923 5733 +3 5881 924 5731 +3 3148 5876 923 +3 6470 923 5876 +3 3864 5876 884 +3 3864 884 903 +3 5876 3864 6470 +3 3148 5733 924 +3 3147 924 5733 +3 3147 3112 924 +3 924 3112 5731 +3 5733 923 3147 +3 4762 4768 4769 +3 4762 4718 4768 +3 4760 4762 4759 +3 4751 4760 4759 +3 6011 1070 6012 +3 661 4741 4746 +3 4746 660 4755 +3 4752 661 6566 +3 4746 4741 4759 +3 4751 4759 4741 +3 4746 4759 660 +3 4761 4266 660 +3 4755 660 4266 +3 4761 660 4762 +3 4759 4762 660 +3 4718 4762 4760 +3 4750 4718 4760 +3 6011 4266 1070 +3 6011 7031 4266 +3 1070 4761 4769 +3 4761 4762 4769 +3 4266 4761 1070 +3 4755 6566 4746 +3 661 4746 6566 +3 4482 4495 5265 +3 6999 4390 6039 +3 4437 6039 4390 +3 3265 3257 3258 +3 3259 3265 3258 +3 3020 3011 5690 +3 3020 1028 3011 +3 5690 1059 3020 +3 5340 3020 1059 +3 3020 5340 1028 +3 6480 3520 5823 +3 3520 6480 6479 +3 6410 940 935 +3 940 6410 835 +3 2553 1063 1064 +3 2553 1064 642 +3 1064 5614 2594 +3 5612 2594 5614 +3 1064 2594 642 +3 1884 6611 6553 +3 4502 4481 5265 +3 4563 6659 5365 +3 4555 4528 4529 +3 5190 5185 4562 +3 5214 4562 4570 +3 763 4660 4523 +3 5182 4555 6373 +3 4547 5191 4581 +3 5381 4557 6373 +3 5180 6373 4557 +3 4824 4570 791 +3 796 4533 801 +3 4547 4581 5171 +3 4533 4573 5191 +3 4581 5191 4573 +3 4513 5183 4563 +3 4556 785 5180 +3 797 4564 5183 +3 4600 5184 4563 +3 4600 4568 5184 +3 5183 4564 6659 +3 5384 6659 4564 +3 5385 4564 801 +3 797 801 4564 +3 4555 5194 4528 +3 4524 4528 5194 +3 5365 4600 4563 +3 4524 4529 4528 +3 800 785 4556 +3 4573 796 6066 +3 785 5385 801 +3 5385 785 7009 +3 800 7009 785 +3 7009 5384 4564 +3 5385 7009 4564 +3 4573 4533 796 +3 4588 763 765 +3 4589 4588 4557 +3 4556 4557 4588 +3 4557 5381 6071 +3 4529 6071 5381 +3 4588 765 4556 +3 4557 4590 4589 +3 4660 6657 4599 +3 4590 6657 4589 +3 4660 4589 6657 +3 4589 4660 4588 +3 4660 763 4588 +3 4590 6071 6657 +3 4557 6071 4590 +3 4523 4660 4599 +3 5208 4600 5365 +3 4547 5171 5179 +3 5181 5182 5180 +3 5182 6264 4555 +3 6264 5182 786 +3 5181 786 5182 +3 785 5181 5180 +3 796 801 797 +3 5184 5185 4513 +3 5184 4562 5185 +3 5181 5191 786 +3 4533 5191 5181 +3 5183 6659 4563 +3 4513 797 5183 +3 5184 4568 4562 +3 4513 4563 5184 +3 5179 5191 4547 +3 5191 5179 786 +3 785 801 4533 +3 785 4533 5181 +3 5194 7061 782 +3 786 5179 6264 +3 6264 7061 4555 +3 5194 4555 7061 +3 5180 5182 6373 +3 4556 5180 4557 +3 4570 4824 5214 +3 5214 790 4562 +3 5190 4562 790 +3 790 5214 4824 +3 4570 4562 4568 +3 6265 791 4570 +3 4439 4600 7035 +3 6265 4570 4568 +3 6265 4568 4600 +3 4439 6265 4600 +3 6265 4439 791 +3 6373 4555 4529 +3 4529 5381 6373 +3 939 3113 938 +3 939 6510 3113 +3 1166 1167 3113 +3 1166 3113 6510 +3 3982 834 3980 +3 4024 4032 4023 +3 4043 4055 4044 +3 1152 3149 4071 +3 5141 5885 5142 +3 671 4806 5125 +3 3145 939 3144 +3 3144 939 3121 +3 6510 939 3145 +3 1151 4036 1150 +3 4034 1150 4036 +3 4033 4036 1151 +3 5964 4036 4033 +3 4034 4036 5964 +3 5964 4033 5956 +3 3113 3119 938 +3 651 5158 5142 +3 651 5039 1075 +3 651 5125 5039 +3 651 1075 5158 +3 1153 5987 4005 +3 4055 4005 4057 +3 4005 4085 4057 +3 4058 4057 4085 +3 4055 1153 4005 +3 1123 1122 5973 +3 6973 5972 4058 +3 6576 4075 4084 +3 4085 4005 5973 +3 1123 5973 4005 +3 4065 4075 6576 +3 5973 4075 6973 +3 6973 4058 4085 +3 5973 1122 4084 +3 6973 4085 5973 +3 5967 6973 4075 +3 4084 4137 6576 +3 4084 4075 5973 +3 4088 4065 6576 +3 650 5142 5885 +3 650 5885 1091 +3 1132 1108 5974 +3 1110 5975 5990 +3 3983 1117 4024 +3 833 834 5939 +3 5956 4033 4024 +3 5956 4024 1117 +3 5939 4023 833 +3 834 3983 5939 +3 4023 5939 4024 +3 3983 4024 5939 +3 980 981 997 +3 993 997 981 +3 996 980 997 +3 4097 5976 4101 +3 4106 4111 4121 +3 4101 4106 4121 +3 4101 4047 4106 +3 4101 5976 5980 +3 4047 4101 5980 +3 4101 4121 4097 +3 1084 4250 4691 +3 5148 5137 5149 +3 3862 2865 4433 +3 4437 4396 991 +3 5243 4394 4393 +3 4730 2796 2644 +3 5728 852 3129 +3 2760 2763 2764 +3 2866 2865 3862 +3 4433 949 4396 +3 4433 2865 949 +3 4238 4735 4237 +3 2795 2663 635 +3 3129 3125 5728 +3 4392 4396 949 +3 4392 949 4393 +3 4740 4237 4735 +3 5048 2730 2710 +3 6282 5274 5273 +3 5728 3130 852 +3 6268 2713 5274 +3 2706 5397 5399 +3 5147 5399 5397 +3 3135 3130 5883 +3 3129 852 851 +3 2801 2734 6334 +3 2663 5636 635 +3 2756 629 2761 +3 2726 6334 2734 +3 2715 2707 2716 +3 714 2732 4674 +3 5049 758 757 +3 5272 5273 5271 +3 5271 2715 5272 +3 4397 5375 6269 +3 5241 2730 5048 +3 2797 622 2662 +3 5153 949 985 +3 991 969 6039 +3 4431 2865 2866 +3 991 6039 4437 +3 4393 4394 4392 +3 4730 2644 2800 +3 2569 726 727 +3 4731 4237 4740 +3 6268 5274 4397 +3 5147 2715 5399 +3 6128 5149 5137 +3 2706 5399 6260 +3 4732 2803 4683 +3 2731 2794 2801 +3 4678 4237 4731 +3 2730 5241 6405 +3 5014 2555 2556 +3 4240 5290 4731 +3 2800 2644 4237 +3 6405 7063 2730 +3 710 621 6335 +3 2706 6260 6128 +3 4238 4237 2644 +3 4736 4239 4240 +3 4437 4433 4396 +3 5280 5290 4799 +3 2746 6328 727 +3 2723 6405 6281 +3 6238 6405 2723 +3 5041 2723 5040 +3 710 708 621 +3 4237 4678 2800 +3 6283 4675 5268 +3 2878 2749 6330 +3 2741 676 6453 +3 2794 2732 2801 +3 622 2793 2731 +3 2796 2802 2795 +3 2800 4682 4730 +3 4683 4730 4682 +3 2569 727 5050 +3 989 2749 988 +3 635 5636 2647 +3 709 5249 2725 +3 4408 4379 5137 +3 2840 2830 2829 +3 5243 4393 2714 +3 2839 2822 2845 +3 2570 2839 2753 +3 2675 6336 2685 +3 2675 2804 6336 +3 2732 2734 2801 +3 2685 6336 621 +3 2626 6331 675 +3 2762 675 6331 +3 629 6331 2626 +3 4732 4682 4679 +3 5041 6238 2723 +3 5241 5048 4728 +3 2570 2826 735 +3 827 2830 2840 +3 620 6336 2804 +3 621 6336 620 +3 621 620 6334 +3 2569 2556 726 +3 5014 2556 2569 +3 6405 5241 6281 +3 5050 988 2558 +3 989 988 5050 +3 2794 2731 2802 +3 2711 5145 4408 +3 675 2759 676 +3 5883 5728 3885 +3 3125 3885 5728 +3 3130 5728 5883 +3 710 706 708 +3 2710 2709 5631 +3 628 6328 2746 +3 2679 629 2626 +3 2684 676 2741 +3 2804 2662 622 +3 620 2804 622 +3 2554 2840 2829 +3 5253 5252 4672 +3 4673 4672 5252 +3 713 5249 714 +3 4674 713 714 +3 713 5631 5249 +3 712 5249 5631 +3 2706 5138 5396 +3 5397 990 5147 +3 2707 5147 990 +3 5138 5144 5396 +3 5253 4672 2729 +3 2663 2662 5636 +3 2741 6453 2689 +3 5631 2667 712 +3 5243 2714 4405 +3 4405 2716 5243 +3 2725 6763 707 +3 708 706 707 +3 2725 707 706 +3 710 709 706 +3 709 2725 706 +3 714 5249 709 +3 676 2684 675 +3 2684 2733 675 +3 707 6763 2737 +3 2566 727 726 +3 628 2755 2761 +3 6453 2764 2763 +3 2689 6453 2763 +3 2759 2764 6453 +3 676 2759 6453 +3 675 2762 2759 +3 2759 2762 2764 +3 2663 2797 2662 +3 2663 2799 2797 +3 709 2726 714 +3 2734 714 2726 +3 6335 2726 709 +3 710 6335 709 +3 2802 2803 2794 +3 2829 2835 2554 +3 2753 2839 2840 +3 827 2840 2839 +3 3126 6806 3125 +3 3126 3125 3129 +3 851 3126 3129 +3 3885 6924 5883 +3 6925 3885 6806 +3 3125 6806 3885 +3 910 6925 6806 +3 3135 5883 3880 +3 5883 6924 3880 +3 910 3886 6925 +3 3885 6925 6924 +3 910 6806 908 +3 910 3884 3886 +3 908 3884 910 +3 2796 2795 635 +3 2749 989 6330 +3 2740 2733 708 +3 2796 635 2647 +3 4678 4731 5290 +3 5280 4678 5290 +3 2729 2803 5253 +3 2684 2685 2733 +3 628 2746 2755 +3 5052 4674 2732 +3 2555 5014 2558 +3 4674 2727 713 +3 2710 2730 2709 +3 5047 5046 2728 +3 5047 4675 4728 +3 735 2558 2570 +3 5047 2728 4675 +3 2753 2840 2554 +3 2826 2753 2554 +3 2801 6334 620 +3 5049 2740 707 +3 991 4394 969 +3 4392 4394 991 +3 2707 990 969 +3 4394 2707 969 +3 2716 2707 5243 +3 2707 4394 5243 +3 5631 2709 2667 +3 4675 2728 5268 +3 2794 5052 2732 +3 2803 5052 2794 +3 4678 4682 2800 +3 2793 2799 2795 +3 2731 2795 2802 +3 2793 2795 2731 +3 4730 4683 2802 +3 2802 4683 2803 +3 4679 4682 4678 +3 4732 4683 4682 +3 2803 4732 5253 +3 977 5253 4732 +3 4732 4679 977 +3 2727 2710 5631 +3 713 2727 5631 +3 4672 4673 5046 +3 4672 5046 5045 +3 2729 4672 5045 +3 2797 2799 2793 +3 4735 4238 4734 +3 977 4679 5278 +3 977 5252 5253 +3 2756 2761 2755 +3 2570 2558 988 +3 2713 6238 5041 +3 5046 4673 2728 +3 5045 5046 5047 +3 2558 5014 5050 +3 2569 5050 5014 +3 5052 5053 4674 +3 4674 5053 2727 +3 5052 2729 5053 +3 5137 5138 6128 +3 2706 6128 5138 +3 5138 4379 5144 +3 5138 5137 4379 +3 4379 4408 5144 +3 5145 5144 4408 +3 5147 2707 2715 +3 5148 5149 5041 +3 6261 5041 5149 +3 2713 5041 6261 +3 4408 5137 5148 +3 6238 6268 7063 +3 6405 6238 7063 +3 2713 6268 6238 +3 6268 6269 7063 +3 4397 6269 6268 +3 4398 2709 6269 +3 5375 4398 6269 +3 2730 7063 2709 +3 5148 5041 5040 +3 4408 5148 5040 +3 6260 5399 5271 +3 2715 5271 5399 +3 6260 5271 5149 +3 6261 5149 5271 +3 5273 5272 6282 +3 5273 6261 5271 +3 2715 2716 5272 +3 2713 6261 5274 +3 5273 5274 6261 +3 5274 975 4397 +3 6282 975 5274 +3 4726 6283 5268 +3 4728 4675 6283 +3 6283 6281 5241 +3 4728 6283 5241 +3 4726 6281 6283 +3 6281 4726 2723 +3 4728 6284 5047 +3 5045 5047 6284 +3 2710 6284 5048 +3 2727 6284 2710 +3 5053 6284 2727 +3 4728 5048 6284 +3 5053 5045 6284 +3 2729 5045 5053 +3 5278 5280 4799 +3 4679 5280 5278 +3 4679 4678 5280 +3 2734 2732 714 +3 686 727 2680 +3 2680 2745 686 +3 2740 675 2733 +3 4740 4736 4731 +3 4240 4731 4736 +3 2740 708 707 +3 4740 4735 4736 +3 2729 5052 2803 +3 2555 2558 735 +3 2680 727 6328 +3 2688 2740 5049 +3 758 5049 707 +3 707 2737 758 +3 6329 2688 5049 +3 5049 757 6329 +3 758 2737 757 +3 2680 6328 6329 +3 2679 6329 6328 +3 6329 2745 2680 +3 757 2745 6329 +3 686 6330 727 +3 2566 2746 727 +3 2761 629 628 +3 2679 628 629 +3 628 2679 6328 +3 2626 2688 2679 +3 6331 6332 2762 +3 5051 6332 6331 +3 2756 5051 6331 +3 2756 6331 629 +3 2797 2793 622 +3 6335 621 6334 +3 6334 2726 6335 +3 2801 620 2731 +3 2676 2662 2804 +3 2675 2676 2804 +3 2753 2826 2570 +3 2845 827 2839 +3 2822 2839 2749 +3 2822 2749 2878 +3 2839 2570 2749 +3 727 6330 5050 +3 6330 989 5050 +3 621 708 2733 +3 2679 2688 6329 +3 988 2749 2570 +3 620 622 2731 +3 2796 4730 2802 +3 2644 2796 2647 +3 4238 2644 4734 +3 2626 675 2688 +3 2688 675 2740 +3 2685 621 2733 +3 1441 5791 4941 +3 4941 3415 2110 +3 6179 2103 4925 +3 5791 1441 3405 +3 6946 5790 4811 +3 5790 3405 4923 +3 4927 4925 4941 +3 3415 4941 5791 +3 1240 2111 4940 +3 4927 2110 2109 +3 6712 2110 3415 +3 5790 4939 5791 +3 3415 5791 4939 +3 3405 5790 5791 +3 6946 4939 5790 +3 6712 3415 4940 +3 4941 4925 1441 +3 2103 1441 4925 +3 6712 2109 2110 +3 4925 4927 6179 +3 2110 4927 4941 +3 4940 3415 4939 +3 4940 6944 1240 +3 2111 6712 4940 +3 2109 6712 2111 +3 5915 6945 5525 +3 1240 6944 5525 +3 5915 5525 6944 +3 6945 6946 6947 +3 4811 6947 6946 +3 4924 6945 6947 +3 5915 6946 6945 +3 4939 6944 4940 +3 5915 6944 4939 +3 4939 6946 5915 +3 5700 2933 746 +3 5666 1032 5715 +3 6524 3044 2932 +3 6797 5667 1202 +3 6797 5715 1032 +3 1203 5068 1029 +3 5666 5068 1203 +3 5068 5666 5715 +3 746 5695 5665 +3 6797 1202 5715 +3 3044 3043 6792 +3 2933 2932 3044 +3 6524 3043 3044 +3 6792 5699 2943 +3 6618 2938 1194 +3 5668 2945 2965 +3 1032 6514 2950 +3 1194 2938 5672 +3 2945 5668 5667 +3 745 1065 5672 +3 746 5665 1065 +3 1065 1194 5672 +3 1065 745 746 +3 6797 1032 2950 +3 2936 746 745 +3 2945 2954 2965 +3 2954 2945 2953 +3 2957 2953 2945 +3 2936 745 2937 +3 5672 2937 745 +3 2938 2937 5672 +3 5699 6792 3043 +3 746 2933 5695 +3 5700 2932 2933 +3 6458 3041 2935 +3 1202 1030 1029 +3 1202 5667 1030 +3 1202 5068 5715 +3 1202 1029 5068 +3 5700 746 2936 +3 3081 2950 6514 +3 2937 2938 3041 +3 2933 3044 3037 +3 3041 6458 2937 +3 3081 6514 6513 +3 2970 6524 6526 +3 2932 6526 6524 +3 2971 6524 2970 +3 2970 6526 2935 +3 1030 2948 1029 +3 1065 2948 1030 +3 6458 6526 5700 +3 2936 6458 5700 +3 2935 6526 6458 +3 2932 5700 6526 +3 6513 6514 1033 +3 2948 1065 6511 +3 5668 1030 5667 +3 3081 2957 2950 +3 2945 5667 5669 +3 5669 2950 2945 +3 2957 2945 2950 +3 1194 1030 5668 +3 1065 1030 1194 +3 2965 6777 5668 +3 1194 5668 6777 +3 1194 6777 6618 +3 2965 6618 6777 +3 2935 3036 2970 +3 2971 2970 3036 +3 3043 2918 5699 +3 3036 5661 2971 +3 2918 2971 5661 +3 2971 3043 6524 +3 2918 3043 2971 +3 3036 3040 5661 +3 3036 2935 3040 +3 1185 2943 6790 +3 3044 6792 3049 +3 2943 1185 6792 +3 3049 6792 1185 +3 2950 5669 6797 +3 1065 5665 6511 +3 3830 6294 907 +3 3887 3867 3888 +3 3868 3867 847 +3 5931 3868 847 +3 6626 847 3887 +3 6626 3887 3866 +3 3867 3887 847 +3 3908 848 6626 +3 6626 5931 847 +3 848 5931 6626 +3 3908 6626 3866 +3 3908 3866 931 +3 6319 2020 1626 +3 1995 2002 6447 +3 2037 5506 5509 +3 5509 2008 2037 +3 2037 1259 1278 +3 5506 2042 5509 +3 6319 2038 1258 +3 2007 2001 6445 +3 5506 2037 1278 +3 1631 2037 2008 +3 2015 2039 1277 +3 2007 6445 1993 +3 2006 6447 2001 +3 2002 2001 6447 +3 1264 1265 1275 +3 2014 2018 1267 +3 1276 1267 2018 +3 1270 2018 2014 +3 5508 1466 2042 +3 1992 1647 1654 +3 2000 1647 1992 +3 1465 2045 1466 +3 2015 2038 6319 +3 2039 2015 6319 +3 1258 2038 2036 +3 1259 1275 1278 +3 2045 2042 1466 +3 5506 6551 2032 +3 1278 6551 5506 +3 1630 1632 6318 +3 2043 2006 2008 +3 2008 2006 6318 +3 1631 2008 6318 +3 2020 2004 2003 +3 1465 1466 1557 +3 6318 1632 1631 +3 1654 1645 1653 +3 1992 1654 1653 +3 1997 1992 1653 +3 1653 1645 1644 +3 1654 1979 1645 +3 2003 1653 1644 +3 2003 1997 1653 +3 2000 1992 1993 +3 2003 1632 1997 +3 1993 1992 1630 +3 1997 1630 1992 +3 6703 1627 6704 +3 1644 6703 6704 +3 2005 1627 6703 +3 1644 1645 6703 +3 1645 1979 5505 +3 5505 2005 6703 +3 1645 5505 6703 +3 2005 1267 1627 +3 1277 1626 1276 +3 1273 1277 1276 +3 1270 1274 2018 +3 1274 1273 2018 +3 2020 1644 6704 +3 2018 1273 1276 +3 1632 2004 1258 +3 1631 1632 1258 +3 1632 1630 1997 +3 1264 1273 1281 +3 1274 1281 1273 +3 1632 2003 2004 +3 1267 1276 1627 +3 1626 1627 1276 +3 1259 2036 2038 +3 1264 1275 6706 +3 2015 6706 1259 +3 1275 1259 6706 +3 1277 1273 6706 +3 1264 6706 1273 +3 2015 1277 6706 +3 2020 2003 1644 +3 2020 6704 1626 +3 1627 1626 6704 +3 2015 1259 2038 +3 5509 2043 2008 +3 2036 1631 1258 +3 5509 2042 2043 +3 2045 2043 2042 +3 5506 5508 2042 +3 5506 2032 5508 +3 1557 1466 5508 +3 1465 1995 2045 +3 1995 2043 2045 +3 2006 2043 6447 +3 1995 6447 2043 +3 1277 2039 1626 +3 2001 2007 2006 +3 6318 2007 1993 +3 1630 6318 1993 +3 2006 2007 6318 +3 1265 1278 1275 +3 2037 2036 1259 +3 1626 2039 6319 +3 2004 2020 6319 +3 6319 1258 2004 +3 2037 1631 2036 +3 1436 1438 3710 +3 3308 6895 3698 +3 1438 3714 3710 +3 3308 3711 6895 +3 3698 6895 3705 +3 1436 3710 1505 +3 3706 5843 3715 +3 3715 3672 3706 +3 3684 3307 3685 +3 3709 1436 6894 +3 3307 3684 3675 +3 3635 6467 3316 +3 3708 3635 3316 +3 3670 1505 3689 +3 6468 3712 3685 +3 3684 3685 3712 +3 3699 3712 6468 +3 3670 3705 1505 +3 3708 3637 3635 +3 3689 1505 3710 +3 3699 6494 3712 +3 3688 6590 3675 +3 3688 3675 3684 +3 3670 6494 3705 +3 3699 3705 6494 +3 1436 3229 1438 +3 3698 3699 3697 +3 3699 6890 3697 +3 6890 3637 6891 +3 3697 6890 6891 +3 3708 6891 3637 +3 3697 6892 3310 +3 3698 3697 3310 +3 3708 3316 6892 +3 3697 6891 6892 +3 3708 6892 6891 +3 3699 3698 3705 +3 6894 6895 1504 +3 3711 1504 6895 +3 1505 6895 6894 +3 3712 3688 3684 +3 3699 6468 6890 +3 1505 3705 6895 +3 3712 6494 3670 +3 6896 3688 3670 +3 3712 3670 3688 +3 3668 3688 6896 +3 3671 3706 3668 +3 3715 5843 3714 +3 3689 3710 5843 +3 3714 5843 3710 +3 6590 3668 3321 +3 3706 3321 3668 +3 3668 6590 3688 +3 3671 3668 6896 +3 3671 5843 3706 +3 3701 3706 3672 +3 3321 3706 3701 +3 3689 5843 3671 +3 3670 3689 6896 +3 3671 6896 3689 +3 3715 3714 5844 +3 1436 3709 3229 +3 4866 1729 6367 +3 572 1701 5562 +3 1709 5433 5435 +3 1698 6677 1699 +3 1709 1718 5433 +3 1721 1699 6677 +3 1704 5433 1718 +3 5432 1698 1699 +3 1736 4866 6367 +3 576 575 1708 +3 1702 4857 6599 +3 1700 1718 5432 +3 1699 1700 5432 +3 5434 5435 1696 +3 1697 5435 5434 +3 1709 4857 1710 +3 1697 4857 1709 +3 1697 1709 5435 +3 5436 1698 1711 +3 1710 1711 1698 +3 1698 5432 1710 +3 5436 6677 1698 +3 1721 6677 5436 +3 1710 1718 1709 +3 5432 1718 1710 +3 1721 1722 1699 +3 5436 5440 6679 +3 1721 5436 6679 +3 1714 5440 5436 +3 5441 1736 6680 +3 1722 1721 6679 +3 4866 5441 1723 +3 5441 4866 1736 +3 6680 5440 5441 +3 1723 5441 5440 +3 570 1702 6599 +3 572 570 6599 +3 2350 572 5562 +3 1723 5440 1714 +3 1702 1710 4857 +3 575 1711 1708 +3 5434 1701 1697 +3 575 576 7033 +3 4857 1697 6599 +3 1697 572 6599 +3 1701 572 1697 +3 1702 1711 1710 +3 1708 1702 570 +3 1711 1702 1708 +3 575 1714 5436 +3 5436 1711 575 +3 7033 1714 575 +3 1729 4866 1723 +3 7033 1729 1723 +3 1714 7033 1723 +3 4247 4159 4246 +3 5111 4180 4092 +3 4178 4244 1085 +3 4246 5112 4247 +3 1087 5992 1085 +3 6561 5112 4246 +3 6561 4246 5410 +3 5112 6561 4180 +3 4243 6561 5410 +3 1087 1085 4244 +3 4178 6428 4244 +3 4177 6429 4178 +3 4092 4180 4212 +3 4180 6561 4243 +3 1086 4172 4139 +3 4177 4178 4176 +3 4243 5410 1087 +3 5410 5299 1087 +3 1088 4172 5992 +3 1086 5992 4172 +3 5992 1087 1088 +3 1085 5992 1086 +3 1085 1086 4139 +3 4177 4176 4138 +3 4139 4176 1085 +3 4138 4153 4177 +3 6428 4178 6429 +3 4212 6428 6429 +3 4178 1085 4176 +3 1087 1006 1088 +3 4244 6428 4243 +3 4180 4243 6428 +3 5299 4242 1006 +3 1087 5299 1006 +3 4180 6428 4212 +3 4243 1087 4244 +3 5112 4180 5111 +3 3933 3942 3950 +3 3941 5933 3942 +3 3950 3942 5933 +3 840 3943 3922 +3 840 3922 5933 +3 840 5933 3941 +3 5933 3922 6953 +3 3927 6953 3922 +3 3951 3950 6953 +3 5933 6953 3950 +3 6953 3937 6954 +3 3951 6953 6954 +3 3927 3937 6953 +3 3934 3933 3951 +3 3933 3950 3951 +3 3934 3951 6954 +3 3937 3934 6954 +3 3368 3404 3647 +3 3404 3369 3647 +3 3369 3404 5793 +3 3369 5793 6496 +3 3647 3369 6496 +3 5833 6885 3647 +3 5833 3647 6496 +3 3647 6885 3368 +3 5833 6883 3646 +3 5833 3646 6885 +3 2659 2633 638 +3 2638 638 2781 +3 2633 2781 638 +3 2638 2781 5623 +3 1168 3151 6574 +3 4643 6091 7015 +3 6091 2886 6773 +3 4643 2886 6091 +3 6091 2888 7015 +3 6093 6091 6773 +3 6093 2888 6091 +3 6093 4639 2888 +3 4778 664 4772 +3 4777 664 4778 +3 1159 1160 4042 +3 1160 4025 4042 +3 4053 4063 4051 +3 4025 3889 4042 +3 4059 4025 1160 +3 1160 4063 4059 +3 6432 4053 4072 +3 6432 4063 4053 +3 4063 4064 4059 +3 4072 6433 6432 +3 1160 1159 4051 +3 4063 6432 4064 +3 1160 4051 4063 +3 2903 2904 996 +3 997 2903 996 +3 2903 993 2851 +3 2903 997 993 +3 6350 6351 3322 +3 6812 6349 3180 +3 3180 6349 5840 +3 3702 6350 863 +3 5840 6349 863 +3 863 6350 5840 +3 858 863 6349 +3 3701 3704 3322 +3 3702 863 858 +3 3701 3322 3321 +3 3235 5840 6350 +3 3704 3235 6350 +3 3704 6350 3322 +3 866 3673 6351 +3 858 6349 6634 +3 860 865 866 +3 858 860 866 +3 3321 6351 3673 +3 3322 6351 3321 +3 3321 3673 3674 +3 3675 6590 3676 +3 3674 3676 6590 +3 3673 3676 3674 +3 865 3687 3676 +3 860 858 6634 +3 858 866 3702 +3 3673 865 3676 +3 866 865 3673 +3 3675 3676 3687 +3 3235 3180 5840 +3 3674 6590 3321 +3 5102 865 860 +3 866 6351 3702 +3 6351 6350 3702 +3 2178 6644 6451 +3 6733 2240 2235 +3 2256 5543 2252 +3 2178 2254 2255 +3 2239 2250 6728 +3 2234 6730 2245 +3 2250 6733 2235 +3 1404 5544 2253 +3 6728 2250 2235 +3 2256 5544 2243 +3 2243 5543 2256 +3 2232 5543 2243 +3 2256 2252 2255 +3 2254 6451 2253 +3 2178 6451 2254 +3 2234 2245 6728 +3 2239 6728 2245 +3 2235 2234 6728 +3 5540 1334 2240 +3 2232 2243 2242 +3 1305 2242 2250 +3 2239 2245 2244 +3 2239 2244 6732 +3 2239 6732 2250 +3 1305 2250 6732 +3 2232 2242 1305 +3 2240 1404 5540 +3 1404 2253 5540 +3 1404 6733 2250 +3 2242 1404 2250 +3 2240 6733 1404 +3 2243 5544 1404 +3 2242 2243 1404 +3 5544 2254 2253 +3 2254 5544 2256 +3 2254 2256 2255 +3 6734 1305 6732 +3 2244 6734 6732 +3 527 525 526 +3 526 5639 527 +3 525 751 750 +3 2855 5646 527 +3 527 5646 525 +3 2855 5639 2857 +3 531 532 6530 +3 749 6530 532 +3 2850 752 532 +3 527 5639 2855 +3 2824 750 752 +3 751 752 750 +3 532 752 751 +3 749 751 5646 +3 751 525 5646 +3 749 532 751 +3 749 5647 6530 +3 2855 5647 749 +3 2855 2857 5647 +3 5639 526 2856 +3 5646 2855 749 +3 532 531 2850 +3 5236 6084 6082 +3 6076 4611 6077 +3 6073 815 814 +3 6582 6051 5221 +3 6051 4613 705 +3 6051 6073 4613 +3 705 4613 4614 +3 5235 6084 5236 +3 6073 704 815 +3 814 4613 6073 +3 4613 4611 4614 +3 809 808 5221 +3 809 5215 808 +3 4625 808 5215 +3 6656 5216 5217 +3 5232 4629 5234 +3 4608 4606 5215 +3 5232 5234 4628 +3 808 4625 4629 +3 5215 4623 4625 +3 2807 5232 4628 +3 4608 5215 809 +3 5234 4625 5233 +3 5215 4606 4623 +3 4629 5232 5235 +3 6581 6582 6583 +3 5221 6583 6582 +3 4475 6581 6583 +3 5232 2807 5235 +3 5216 6656 4615 +3 6051 6582 6073 +3 704 6073 6582 +3 4609 4615 6074 +3 6074 4615 6656 +3 6076 4615 4614 +3 4560 4607 6077 +3 4560 6077 4611 +3 6077 5216 6076 +3 4584 5216 4607 +3 6077 4607 5216 +3 5216 4615 6076 +3 4611 6076 4614 +3 4609 4608 5221 +3 809 5221 4608 +3 705 4609 5221 +3 4608 4609 4606 +3 4609 6074 4606 +3 4609 705 4614 +3 4615 4609 4614 +3 4475 6082 6581 +3 4475 5236 6082 +3 6051 705 5221 +3 808 4629 6583 +3 4475 6583 4629 +3 5221 808 6583 +3 5234 4629 4625 +3 4625 4623 5233 +3 5234 5233 4628 +3 5235 2807 6084 +3 5236 4475 5235 +3 4629 5235 4475 +3 597 6646 4686 +3 4773 4748 4744 +3 596 5302 4733 +3 4742 4773 4747 +3 4733 5303 6646 +3 4742 667 4748 +3 597 596 4733 +3 667 4747 596 +3 4742 4747 667 +3 4747 4773 5302 +3 596 4747 5302 +3 597 4733 6646 +3 4733 5302 5303 +3 4773 4742 4748 +3 4773 4744 5302 +3 2562 693 2563 +3 694 693 2562 +3 633 694 2562 +3 623 2563 2561 +3 2563 623 692 +3 692 691 2562 +3 692 2562 2563 +3 2562 691 633 +3 2563 693 2561 +3 915 3858 3859 +3 3859 3858 3849 +3 3881 6358 3853 +3 3874 3860 3876 +3 3879 6920 3853 +3 3869 3853 6920 +3 3873 3882 3879 +3 3879 3853 3873 +3 901 3860 3874 +3 3857 901 3874 +3 3879 3851 6920 +3 3882 3851 3879 +3 5877 5882 915 +3 5877 915 3876 +3 3876 3859 6923 +3 3860 5877 3876 +3 904 3860 901 +3 5877 904 900 +3 904 5877 3860 +3 5877 900 5882 +3 3874 3876 6923 +3 3857 3874 3873 +3 3874 6923 3873 +3 3882 3850 3851 +3 6923 3850 3882 +3 3873 6923 3882 +3 3859 3850 6923 +3 915 3859 3876 +3 3850 3859 3849 +3 3881 3853 3869 +3 3857 3873 6358 +3 3853 6358 3873 +3 1099 4184 1100 +3 4184 4183 1100 +3 4184 1099 4185 +3 1099 5994 4185 +3 1204 5692 1205 +3 1205 5692 3025 +3 3031 3006 6785 +3 1022 6521 3024 +3 6531 2907 2923 +3 3031 6785 3026 +3 3012 3006 3031 +3 3025 3012 3031 +3 3024 6521 3031 +3 3025 3031 6521 +3 3025 6521 1205 +3 1022 1205 6521 +3 894 892 1026 +3 893 1026 892 +3 1205 1022 1204 +3 3031 3026 5702 +3 3024 3031 5702 +3 5702 893 3030 +3 3024 5702 3030 +3 5704 3024 3030 +3 1022 3024 5704 +3 2906 3053 6531 +3 892 3053 2906 +3 3053 2907 6531 +3 894 2907 3053 +3 5702 3026 893 +3 1026 893 3026 +3 3030 892 2906 +3 892 894 3053 +3 3030 893 892 +3 3056 5720 3057 +3 2858 3110 3068 +3 3068 3110 6584 +3 3027 6584 3110 +3 3068 6584 3111 +3 3027 2858 3107 +3 3110 2858 3027 +3 6957 5932 3926 +3 3940 3944 3939 +3 6435 3976 4015 +3 4010 4011 6435 +3 3976 6435 4011 +3 3898 6437 5936 +3 931 5936 6437 +3 3913 3972 3912 +3 840 3940 3939 +3 3940 1141 3944 +3 3972 3936 3912 +3 3899 3925 3936 +3 3897 3911 850 +3 3949 933 849 +3 850 6950 3897 +3 848 6951 5931 +3 848 850 6951 +3 3911 6951 850 +3 848 6950 850 +3 3908 6950 848 +3 849 933 3909 +3 849 3909 3911 +3 3911 3909 6951 +3 3933 839 3935 +3 3934 839 3933 +3 838 6952 3932 +3 5932 3932 6952 +3 3912 3927 3928 +3 3937 3927 3912 +3 839 3934 838 +3 3936 838 3934 +3 3936 3934 3937 +3 3936 3937 3912 +3 3942 3933 3935 +3 3942 3940 3941 +3 840 3941 3940 +3 3913 3928 3949 +3 3913 3949 849 +3 934 849 3911 +3 3897 934 3911 +3 3925 838 3936 +3 5932 6952 3925 +3 3926 5932 3925 +3 838 3925 6952 +3 3898 5936 3973 +3 3899 3898 3973 +3 934 3972 3913 +3 934 3897 3898 +3 3972 934 3898 +3 934 3913 849 +3 3913 3912 3928 +3 3899 3972 3898 +3 3973 6958 3926 +3 3899 3973 3926 +3 3926 6958 6957 +3 3908 6437 6950 +3 3897 6950 6437 +3 931 6437 3908 +3 3897 6437 3898 +3 838 3932 3952 +3 3953 1141 3942 +3 3940 3942 1141 +3 3953 4012 1141 +3 3942 3935 3953 +3 4016 4012 6435 +3 4010 6435 4012 +3 1141 4012 4016 +3 839 4010 4012 +3 4010 839 3952 +3 839 4012 3935 +3 3953 3935 4012 +3 4015 1142 4016 +3 1141 6963 3944 +3 6963 4016 1142 +3 1141 4016 6963 +3 4015 4016 6435 +3 3952 839 838 +3 6965 4011 4010 +3 3952 6965 4010 +3 3932 6965 3952 +3 3926 3925 3899 +3 3972 3899 3936 +3 6062 4479 4548 +3 5426 6675 1604 +3 5423 1579 1569 +3 1606 1580 1607 +3 1604 1607 1580 +3 1580 1569 1579 +3 1580 1579 1604 +3 1607 5424 1606 +3 1607 1609 5424 +3 1609 1607 6675 +3 1604 6675 1607 +3 5423 1615 5426 +3 1604 1579 5426 +3 5423 5426 1579 +3 3645 3362 3361 +3 3645 3361 6885 +3 3645 6885 3646 +3 4433 4437 6486 +3 4433 6486 6577 +3 6061 4550 7005 +3 4540 7005 4550 +3 4549 4550 6061 +3 7006 7007 6061 +3 4711 6061 7007 +3 4540 7006 7005 +3 6061 7005 7006 +3 4549 6061 4711 +3 4553 4549 4546 +3 4550 4549 4553 +3 4549 4711 4546 +3 896 3232 897 +3 3458 3459 6845 +3 2269 5866 2270 +3 3459 2270 5866 +3 3458 3373 5090 +3 3458 3372 3373 +3 3456 2270 5090 +3 5090 2270 3458 +3 3458 3371 3372 +3 3458 6845 3371 +3 3373 3372 6839 +3 3458 2270 3459 +3 6687 5453 5452 +3 5453 6687 1836 +3 4097 4121 4122 +3 4122 4121 4111 +3 4122 4111 4130 +3 4097 5975 1110 +3 4122 5989 5975 +3 4130 5989 4122 +3 4097 4122 5975 +3 1110 5976 4097 +3 864 3190 3193 +3 899 3253 3216 +3 3253 3223 3216 +3 3189 5743 3223 +3 3190 5743 3189 +3 3159 5750 3190 +3 5743 3190 5750 +3 3253 6817 3223 +3 3189 3223 6817 +3 1152 5987 1153 +3 2670 2656 2633 +3 5635 6478 2656 +3 2672 2778 6627 +3 2657 2672 2660 +3 6478 2780 2669 +3 2656 6478 2669 +3 637 2657 2660 +3 2672 6627 2670 +3 2660 2672 2670 +3 2659 637 6630 +3 2669 2771 5623 +3 2659 6630 2633 +3 6630 2660 2633 +3 637 2660 6630 +3 2656 2669 2781 +3 2633 2660 2670 +3 2656 2781 2633 +3 2771 2669 2780 +3 5635 2780 6478 +3 2669 5623 2781 +3 6627 2778 2656 +3 5635 2656 2778 +3 2670 6627 2656 +3 828 6080 6083 +3 6581 6083 829 +3 828 6083 6082 +3 5377 2811 4455 +3 4637 4471 682 +3 2812 4455 2811 +3 4637 682 5377 +3 5229 4634 5237 +3 829 6083 6080 +3 6082 6084 4474 +3 828 4470 6080 +3 5240 5229 5237 +3 5240 5237 6472 +3 681 2812 2811 +3 5231 5239 4628 +3 2807 4628 5239 +3 682 680 681 +3 4471 680 682 +3 2811 5377 6652 +3 682 6652 5377 +3 5239 5378 2812 +3 681 5239 2812 +3 6653 680 4474 +3 4470 4474 680 +3 4471 4470 680 +3 4470 828 4474 +3 699 4455 5887 +3 699 5377 4455 +3 6083 6581 6082 +3 681 6652 682 +3 4603 7014 4455 +3 5887 4455 7014 +3 4474 828 6082 +3 681 2807 5239 +3 680 2807 681 +3 4603 4455 2812 +3 5378 4603 2812 +3 5378 5229 4603 +3 2807 680 6653 +3 4474 6084 6653 +3 2807 6653 6084 +3 4634 5229 4632 +3 4632 5229 5378 +3 4632 5378 5239 +3 681 2811 6652 +3 7014 4603 5240 +3 5229 5240 4603 +3 5240 6472 7014 +3 2911 1023 5664 +3 2927 2930 5664 +3 5664 2930 2911 +3 2927 3005 2930 +3 2930 3005 2928 +3 6457 2911 1024 +3 1023 2911 6457 +3 2911 2929 2912 +3 2930 2929 2911 +3 2911 2912 1024 +3 1024 3008 6457 +3 2912 2928 5658 +3 2912 2929 2928 +3 2928 2929 2930 +3 2928 3005 2915 +3 5658 3008 2912 +3 1024 2912 3008 +3 4355 4366 6990 +3 4364 967 4357 +3 960 959 4359 +3 4362 6371 954 +3 4320 967 4364 +3 4362 3892 6371 +3 959 6036 6371 +3 4361 3892 4362 +3 6037 954 6036 +3 6371 6036 954 +3 959 6371 3892 +3 4359 959 3892 +3 967 968 6562 +3 4351 4333 4367 +3 6026 4351 4367 +3 6562 4361 4357 +3 967 6562 4357 +3 4356 4361 6562 +3 4360 3892 4361 +3 4361 4362 6926 +3 4367 4341 4342 +3 5130 4342 4341 +3 4358 4359 3892 +3 3892 4360 4358 +3 4360 4355 4358 +3 4366 4365 6991 +3 4353 6991 4365 +3 4356 6992 4365 +3 4353 4365 6992 +3 4356 4365 4360 +3 4365 4355 4360 +3 4355 4317 4358 +3 4355 6990 4317 +3 4316 4317 6990 +3 4353 4351 6991 +3 4333 4351 4353 +3 4334 6032 6026 +3 4367 4353 968 +3 4341 4367 968 +3 4333 4353 4367 +3 6026 4367 4342 +3 4334 6026 4342 +3 4316 4354 4317 +3 4366 4355 4365 +3 968 4353 6992 +3 4356 4360 4361 +3 4357 4372 4364 +3 968 4320 4341 +3 4340 4341 4320 +3 6926 4372 4361 +3 4357 4361 4372 +3 4362 954 6995 +3 4362 6995 6926 +3 954 6037 6995 +3 4359 4317 4354 +3 4358 4317 4359 +3 6562 6992 4356 +3 968 6992 6562 +3 4320 968 967 +3 5130 4341 4340 +3 3112 3146 3140 +3 3112 3140 5731 +3 3140 3146 3128 +3 3843 3837 3247 +3 3220 6822 854 +3 3247 3837 3246 +3 5871 3246 3837 +3 5871 3240 3246 +3 3246 5746 3182 +3 3240 5746 3246 +3 3239 3243 6819 +3 6819 3220 854 +3 3243 3220 6819 +3 3245 3182 6820 +3 3245 6821 3182 +3 3220 3245 6820 +3 3220 6820 6822 +3 6819 3242 3239 +3 3220 3243 3245 +3 3833 5871 3837 +3 3239 3247 3243 +3 3182 6821 3246 +3 6821 3243 3247 +3 3246 6821 3247 +3 3245 3243 6821 +3 3247 3239 3843 +3 3242 3843 3239 +3 3494 3591 3597 +3 3591 1514 3597 +3 1514 6464 3597 +3 1513 3597 6464 +3 3597 1513 3494 +3 3493 3494 1513 +3 3428 6855 5806 +3 3493 5806 6855 +3 3493 1513 6864 +3 1514 6865 6464 +3 3589 6464 6865 +3 3594 6865 1514 +3 6868 6855 3366 +3 3493 6855 6868 +3 3494 3493 6868 +3 3366 6855 3428 +3 3591 3494 6868 +3 5806 3493 6864 +3 6864 1513 6873 +3 5806 6864 6873 +3 3907 3868 5931 +3 3910 5931 6951 +3 3910 3907 5931 +3 3910 3920 3907 +3 3910 6951 3909 +3 3909 3920 3910 +3 4512 6420 797 +3 5188 6420 4512 +3 5188 4512 5189 +3 5187 5188 5189 +3 4442 5185 5190 +3 5188 4575 6420 +3 796 6420 4575 +3 5187 6658 4571 +3 4572 4571 6658 +3 4460 5186 4569 +3 6658 5189 4440 +3 5187 5189 6658 +3 4575 6066 796 +3 4460 4569 4578 +3 6066 4575 4571 +3 5187 4571 5188 +3 4575 5188 4571 +3 4459 6127 4460 +3 4572 6127 4459 +3 4442 5213 5155 +3 5154 5155 5213 +3 4512 4513 4442 +3 4512 797 4513 +3 4513 5185 4442 +3 4460 6127 5186 +3 6127 5154 5186 +3 4512 5155 5189 +3 4512 4442 5155 +3 4440 5189 5154 +3 5154 5189 5155 +3 4572 4440 6127 +3 6127 4440 5154 +3 4572 6658 4440 +3 6420 796 797 +3 5213 4442 5190 +3 3184 6814 1431 +3 1431 6814 1499 +3 1132 5955 3958 +3 3958 5955 5954 +3 5974 3988 5955 +3 1132 5974 5955 +3 3988 5954 5955 +3 4145 1003 1016 +3 4145 1016 4149 +3 4150 4149 1016 +3 2790 606 2760 +3 606 2763 2760 +3 4110 4107 5977 +3 4110 4106 4107 +3 5977 4107 4124 +3 4045 4124 4107 +3 4113 4045 4046 +3 4047 4046 4107 +3 4045 4107 4046 +3 4106 4047 4107 +3 4047 1112 4046 +3 4046 1112 4113 +3 2041 2001 2002 +3 1995 2040 2041 +3 2041 2002 1995 +3 1208 4921 1207 +3 1207 4921 1243 +3 4922 4921 1208 +3 2082 5349 1237 +3 1243 1236 5522 +3 4921 2089 1243 +3 4920 2089 6175 +3 4921 6175 2089 +3 1207 1243 1206 +3 1243 5522 1242 +3 2083 6448 4920 +3 1240 5349 1239 +3 1240 1239 2111 +3 1236 1243 2082 +3 1240 1237 5349 +3 1238 2082 1237 +3 4920 6175 6176 +3 6448 5349 2082 +3 6448 2083 5349 +3 6448 1243 2089 +3 6448 2082 1243 +3 2089 4920 6448 +3 6440 6441 5525 +3 1238 5525 6441 +3 5520 6441 6440 +3 5520 6440 4924 +3 5349 2083 1239 +3 1348 1239 2083 +3 2082 1238 1236 +3 6441 5522 1238 +3 1236 1238 5522 +3 1237 1240 5525 +3 1238 1237 5525 +3 6440 5525 6945 +3 4924 6440 6945 +3 3105 3104 1047 +3 2591 616 617 +3 2600 616 2591 +3 2599 3104 2621 +3 2591 1047 3104 +3 3106 3105 1047 +3 2599 2600 3104 +3 618 3074 3076 +3 2591 3104 2600 +3 1051 617 616 +3 1052 3074 618 +3 3105 2621 3104 +3 1052 617 1051 +3 2621 2623 2599 +3 1068 2600 6533 +3 616 2600 1068 +3 2621 2622 2623 +3 1068 5709 1051 +3 616 1068 1051 +3 5711 6533 5710 +3 2599 5710 6533 +3 5710 2623 5338 +3 2599 2623 5710 +3 3071 5709 5711 +3 5711 5709 1068 +3 5711 1068 6533 +3 1052 3070 3074 +3 5709 3070 1051 +3 1052 1051 3070 +3 2600 2599 6533 +3 2621 3106 2622 +3 2621 3105 3106 +3 2622 5338 2623 +3 1025 1045 1046 +3 611 625 2579 +3 2776 6766 2575 +3 5612 2584 2576 +3 2586 1025 2593 +3 2584 5612 2585 +3 2588 2586 2637 +3 2587 6766 2776 +3 2587 2632 6766 +3 1046 1057 1025 +3 2583 6532 2579 +3 624 2594 5611 +3 1050 1025 6534 +3 2586 6534 1025 +3 2592 1050 6534 +3 2585 2589 2592 +3 642 2583 2546 +3 2585 2592 2584 +3 5322 2774 611 +3 5612 5611 2594 +3 2576 5611 5612 +3 2587 2776 6755 +3 2584 5613 2576 +3 5613 6534 2586 +3 2586 2588 5613 +3 6534 5613 2584 +3 2592 6534 2584 +3 2589 1050 2592 +3 2587 6755 5613 +3 2576 5613 6755 +3 624 2583 642 +3 642 2594 624 +3 2593 1025 1057 +3 2634 5634 6758 +3 5624 6758 5634 +3 5634 5322 2775 +3 5634 2774 5322 +3 2579 2777 5322 +3 2775 5322 2777 +3 611 2579 5322 +3 2579 625 2546 +3 2583 2579 2546 +3 6755 2776 5611 +3 2576 6755 5611 +3 6532 6766 2579 +3 2777 2579 6766 +3 2575 6766 6532 +3 5611 2776 2575 +3 624 5611 2575 +3 2575 6532 624 +3 2583 624 6532 +3 2632 2777 6766 +3 2771 2587 5613 +3 2588 2771 5613 +3 2771 2780 2587 +3 2632 2775 2777 +3 5624 5634 2775 +3 2632 5624 2775 +3 2634 2774 5634 +3 2637 2586 2593 +3 2588 2637 2771 +3 1437 3707 1434 +3 1437 1434 5844 +3 3172 5844 1434 +3 6818 3707 1437 +3 5772 3715 3172 +3 6818 1437 5744 +3 1434 3319 5841 +3 3319 1434 3707 +3 5774 3172 1434 +3 5774 5775 3172 +3 3172 5775 5772 +3 3715 5844 3172 +3 1438 3229 6818 +3 5744 1438 6818 +3 5841 5774 1434 +3 3319 3716 5841 +3 1438 5744 3714 +3 1437 3714 5744 +3 5844 3714 1437 +3 3319 6902 3716 +3 3319 6818 6902 +3 3229 6902 6818 +3 3707 6818 3319 +3 608 560 5596 +3 608 5596 5356 +3 607 5355 5583 +3 5583 5355 2449 +3 5355 2446 2449 +3 608 2448 560 +3 1349 2446 5355 +3 5356 5355 608 +3 607 608 5355 +3 1349 5355 5356 +3 2448 608 607 +3 1210 5760 873 +3 1213 1198 3267 +3 3292 5761 3281 +3 3281 3288 3292 +3 1198 1197 3267 +3 5329 3288 873 +3 3260 6823 3266 +3 3266 6823 5754 +3 6823 3199 1197 +3 1197 3199 3267 +3 3199 3283 3267 +3 1213 3267 3283 +3 1213 5347 1198 +3 1198 5347 6828 +3 1212 6828 5347 +3 5330 5329 873 +3 6505 872 3279 +3 872 5330 3279 +3 1214 872 6505 +3 5347 6641 1212 +3 1192 3211 6596 +3 1197 5754 6823 +3 1197 6825 5754 +3 3261 5754 6825 +3 3261 3211 1192 +3 5754 3261 3266 +3 6827 6641 1214 +3 1212 6641 6827 +3 6828 6825 1198 +3 1197 1198 6825 +3 3211 6825 6828 +3 872 3274 5329 +3 5329 3274 3288 +3 3211 6828 3271 +3 1212 3271 6828 +3 3211 3271 6596 +3 3261 6825 3211 +3 1214 3274 872 +3 1212 6827 3271 +3 5330 872 5329 +3 1214 6641 3274 +3 5330 873 5760 +3 3288 3281 6830 +3 6830 1210 873 +3 3288 6830 873 +3 6527 5645 2874 +3 2874 5645 2879 +3 2853 2875 5645 +3 2877 2879 5645 +3 2877 5645 2875 +3 2824 2879 2876 +3 2876 2879 2877 +3 2853 5645 6527 +3 729 2879 752 +3 2824 752 2879 +3 729 752 2850 +3 2849 729 2850 +3 2849 725 2848 +3 2849 2850 725 +3 2825 2849 2848 +3 2874 2849 2825 +3 2874 2879 2849 +3 729 2849 2879 +3 2824 2876 2738 +3 5972 1161 4058 +3 1165 6434 1161 +3 1161 6434 4058 +3 4061 1165 4062 +3 4061 6434 1165 +3 1161 4056 6969 +3 1165 6969 4062 +3 1165 1161 6969 +3 4193 4196 4194 +3 5752 6507 3256 +3 6507 1000 3256 +3 6040 4383 5143 +3 6998 5143 4383 +3 5151 5144 5145 +3 4410 5144 5151 +3 4382 4380 932 +3 5152 4382 932 +3 6997 6998 4383 +3 970 6997 4383 +3 5143 5152 932 +3 4386 5143 932 +3 6040 5143 4386 +3 4410 5151 7034 +3 5396 5144 4410 +3 5143 5396 4410 +3 5143 6998 5396 +3 5143 4410 5152 +3 5152 7034 4382 +3 5151 4382 7034 +3 4410 7034 5152 +3 855 854 6463 +3 855 6463 3254 +3 3238 3254 6463 +3 3238 6605 3254 +3 5745 3238 6463 +3 2500 2498 5599 +3 563 2419 2494 +3 2419 566 2494 +3 6359 2498 2500 +3 2114 2421 2112 +3 2506 2114 2112 +3 2498 5600 2492 +3 563 2494 2499 +3 568 567 566 +3 2494 566 567 +3 5599 2492 2495 +3 2497 563 2499 +3 564 2419 563 +3 567 568 2426 +3 568 566 2417 +3 2506 2495 2492 +3 2492 2113 2506 +3 2112 2495 2506 +3 2113 2497 2499 +3 2113 2499 2506 +3 2492 5600 2113 +3 2505 5599 2495 +3 2498 6359 5600 +3 2114 2506 2499 +3 2494 2114 2499 +3 566 2419 2417 +3 2114 2494 2421 +3 563 2445 564 +3 5599 2498 2492 +3 2421 2494 567 +3 2497 2445 563 +3 6497 3731 5848 +3 6497 5848 3733 +3 597 6114 4705 +3 4686 6114 597 +3 4686 7025 6114 +3 4705 6114 7025 +3 5756 6621 2951 +3 5440 6680 6679 +3 1204 6775 5696 +3 3133 3138 6810 +3 3123 6810 3138 +3 3133 6810 6809 +3 5726 6809 6810 +3 5726 6810 3123 +3 5817 6858 3560 +3 3726 3666 6495 +3 2516 2511 2430 +3 2507 2406 2502 +3 2403 2511 2516 +3 6606 4986 2404 +3 2445 2501 2444 +3 2516 2393 2403 +3 6540 2402 2393 +3 2403 2393 2402 +3 2444 565 2445 +3 2403 2402 2100 +3 2414 2343 2415 +3 2099 6710 2402 +3 2100 2402 6710 +3 2404 4986 4987 +3 2501 2445 2497 +3 2414 5601 6359 +3 5600 6359 5601 +3 2501 5600 5601 +3 2113 2501 2497 +3 2501 2113 5600 +3 2510 2508 2415 +3 2414 2415 2508 +3 2502 2406 2430 +3 5571 2516 5576 +3 2406 2516 2430 +3 5571 2393 2516 +3 2414 6359 2343 +3 2403 2100 2511 +3 2507 5601 2414 +3 2414 2508 2507 +3 4987 6936 6710 +3 2100 6710 6936 +3 2445 6606 564 +3 2404 564 6606 +3 4987 4986 6936 +3 565 6606 2445 +3 2511 2100 6936 +3 2430 2511 6936 +3 6936 6606 565 +3 2430 6936 565 +3 4986 6606 6936 +3 2502 2430 565 +3 2502 565 2444 +3 2444 2507 2502 +3 2501 5601 2507 +3 2444 2501 2507 +3 4714 678 4477 +3 4694 6111 778 +3 4694 679 4714 +3 679 6426 678 +3 4714 679 678 +3 778 679 4694 +3 678 7022 4477 +3 678 6426 7022 +3 2488 5593 2487 +3 5593 2466 2491 +3 2491 2487 5593 +3 2466 2470 2491 +3 2467 2466 5593 +3 3252 855 3254 +3 3242 3252 3840 +3 3252 3254 3840 +3 854 855 3252 +3 3252 6819 854 +3 3242 6819 3252 +3 3256 3263 3212 +3 1000 3263 3256 +3 2951 3270 2952 +3 3188 3193 3190 +3 3188 5742 5736 +3 3188 3190 5742 +3 5736 5742 3218 +3 6817 5742 3189 +3 3190 3189 5742 +3 4277 6022 4314 +3 4250 6667 6125 +3 1071 973 972 +3 4249 1094 5121 +3 654 4706 4697 +3 4697 4696 655 +3 4696 4697 6108 +3 4279 972 973 +3 4219 5115 4207 +3 4312 4311 4314 +3 4696 6108 6106 +3 4165 4142 4163 +3 4219 5392 4252 +3 4252 4251 4219 +3 1084 5341 4250 +3 4219 4207 5392 +3 4300 4268 4301 +3 4207 5115 4208 +3 5341 1084 1082 +3 602 7028 5319 +3 4281 4265 1084 +3 4272 6982 4276 +3 1084 655 4281 +3 4261 657 6125 +3 5122 4217 5115 +3 4273 973 1071 +3 4251 4218 4219 +3 4314 6022 4312 +3 6667 5403 6125 +3 1008 5998 5999 +3 5999 4161 1008 +3 4277 4276 6022 +3 1071 6102 4273 +3 4271 4685 6104 +3 4265 1082 1084 +3 4691 6125 657 +3 1071 4685 6102 +3 4271 6104 4695 +3 4281 4696 6106 +3 657 655 4691 +3 1084 4691 655 +3 6125 4691 4250 +3 4250 5341 5886 +3 5999 5998 4144 +3 657 4261 4690 +3 4276 6982 4273 +3 5123 1094 4249 +3 5407 5123 4262 +3 4301 4268 4309 +3 4217 4208 5115 +3 4281 655 4696 +3 1094 5405 5121 +3 4293 6022 4276 +3 5121 5122 4249 +3 4249 5122 5115 +3 4218 4249 5115 +3 5407 1094 5123 +3 4161 5999 4160 +3 4251 1078 1079 +3 1092 1093 5342 +3 5342 1093 1094 +3 5403 5123 4249 +3 4262 5123 6667 +3 5403 6667 5123 +3 4213 5121 5405 +3 5117 4214 4165 +3 4143 4165 4214 +3 4213 4214 5117 +3 4261 5403 6669 +3 4249 6669 5403 +3 4250 5886 6667 +3 4262 6667 5886 +3 4163 4142 4144 +3 4165 4163 5116 +3 4166 5116 4163 +3 4166 6977 5116 +3 4143 4216 1012 +3 4143 4214 4216 +3 4143 1012 6979 +3 4160 6979 1012 +3 4144 4142 5999 +3 4143 5999 4142 +3 4160 5999 6979 +3 4143 6979 5999 +3 5117 4217 4213 +3 4216 4259 1012 +3 6007 5342 5407 +3 5407 5342 1094 +3 4248 6007 5407 +3 1092 5342 4309 +3 6007 4309 5342 +3 4214 4213 5405 +3 1094 1093 5405 +3 4214 5405 1093 +3 4214 1093 4216 +3 4161 4160 4215 +3 4165 4143 4142 +3 4160 1012 4215 +3 4261 6669 1079 +3 4251 1079 6669 +3 1078 4251 4252 +3 4218 5115 4219 +3 4262 5886 1083 +3 4262 1083 4248 +3 973 4273 6982 +3 4272 4304 4279 +3 4274 4279 4304 +3 4272 973 6982 +3 4279 973 4272 +3 6018 4300 6983 +3 4279 4274 6018 +3 4277 4272 4276 +3 4277 4304 4272 +3 1092 4309 4268 +3 4300 4301 4305 +3 4305 4301 1083 +3 4301 4248 1083 +3 4279 6018 4278 +3 4262 4248 5407 +3 1083 1082 4305 +3 1082 1083 5341 +3 6018 6983 4278 +3 4305 4278 6983 +3 4300 4305 6983 +3 4276 4273 4293 +3 4306 6987 6002 +3 4308 6002 6987 +3 4304 6987 4306 +3 4301 6007 4248 +3 4301 4309 6007 +3 4216 1093 4259 +3 1092 4259 1093 +3 4308 6987 6988 +3 4277 6988 6987 +3 6988 4277 4314 +3 4311 6988 4314 +3 4277 6987 4304 +3 4274 4304 4306 +3 4308 6988 4311 +3 6018 4274 4300 +3 4300 4274 4306 +3 6020 6048 4168 +3 6108 4708 6106 +3 7026 7025 4687 +3 4686 4687 7025 +3 4708 7025 7026 +3 4705 7025 4708 +3 4706 7029 7030 +3 4764 7030 7029 +3 6109 4706 7030 +3 5319 4698 603 +3 5319 6121 4698 +3 5319 7028 6121 +3 6109 4697 4706 +3 6109 4708 6108 +3 6109 6108 4697 +3 6109 4705 4708 +3 4698 7029 4706 +3 7029 6121 4764 +3 4698 6121 7029 +3 657 654 655 +3 654 4697 655 +3 603 654 657 +3 654 603 4706 +3 4698 4706 603 +3 4690 603 657 +3 6125 5403 4261 +3 4249 4218 6669 +3 4251 6669 4218 +3 5116 4206 4165 +3 5117 4165 4206 +3 5117 4206 4217 +3 4208 4217 4206 +3 4217 5122 4213 +3 4213 5122 5121 +3 3198 3283 3199 +3 3283 3198 1180 +3 1179 6816 3198 +3 3194 3202 3195 +3 3195 1432 3194 +3 1433 1432 3195 +3 1432 1433 1191 +3 1179 6639 1178 +3 3194 1432 3196 +3 3194 3203 3202 +3 1178 3194 3196 +3 1178 3203 3194 +3 1432 1191 3196 +3 1191 1179 3196 +3 1178 3196 1179 +3 6816 1179 1191 +3 3198 6816 1180 +3 3260 6639 3198 +3 1179 3198 6639 +3 3199 3260 3198 +3 5684 2931 5680 +3 5684 2974 3000 +3 5680 5678 5684 +3 5680 1199 5678 +3 2916 5678 1199 +3 2916 2974 5678 +3 5678 2974 5684 +3 5684 3000 6620 +3 2931 5684 6620 +3 3944 3986 3939 +3 3991 4002 5957 +3 3938 3955 3986 +3 4002 3991 3955 +3 3956 3955 3991 +3 3944 3938 3986 +3 5954 3986 3955 +3 3938 4002 3955 +3 3938 1143 4002 +3 1134 1106 4102 +3 4119 4118 5980 +3 4103 1104 5947 +3 4119 5980 5976 +3 4102 3994 1134 +3 1104 4108 5986 +3 1104 5986 5947 +3 1105 4102 1106 +3 4116 3993 5986 +3 5986 3993 5947 +3 4118 1134 3994 +3 4117 4115 4120 +3 4115 5983 4120 +3 5979 4117 4120 +3 4103 3994 4102 +3 5947 3993 4103 +3 3994 4103 3993 +3 4096 3994 3993 +3 4098 5976 1110 +3 4119 5976 4098 +3 1134 4119 4098 +3 4118 3994 4096 +3 1134 4118 4119 +3 4118 4096 5980 +3 4117 1114 4096 +3 5979 1114 4117 +3 4117 4116 4115 +3 5983 4080 6971 +3 4115 4080 5983 +3 4120 5982 5979 +3 4096 3993 4117 +3 4117 3993 4116 +3 4120 5983 5982 +3 6623 5752 3251 +3 5752 6623 6507 +3 1060 995 1036 +3 1025 1053 1045 +3 2602 1045 1053 +3 5034 2589 5035 +3 5019 1050 6232 +3 2589 6232 1050 +3 2585 5035 2589 +3 1053 6400 2602 +3 6401 5016 6400 +3 6230 5016 6401 +3 1050 5019 1025 +3 1025 5019 1053 +3 6232 5020 6230 +3 5020 6232 2589 +3 5034 5020 2589 +3 6230 5019 6232 +3 1053 5019 6401 +3 6230 6401 5019 +3 1053 6401 6400 +3 2088 6176 6175 +3 6749 6176 2088 +3 5850 3296 5849 +3 5850 1182 3296 +3 6269 2709 7063 +3 3156 1170 3157 +3 3156 3752 1170 +3 3154 3164 3752 +3 3164 1170 3752 +3 2465 5598 2464 +3 5598 2465 738 +3 739 740 2466 +3 2464 739 2465 +3 2466 2467 2465 +3 739 2466 2465 +3 740 2470 2466 +3 2467 5591 738 +3 2465 2467 738 +3 2485 2464 5598 +3 7024 605 6053 +3 6053 771 5162 +3 5162 4482 6053 +3 5162 4495 4482 +3 7024 6053 4482 +3 6053 605 5390 +3 771 6053 5390 +3 5162 771 4491 +3 5162 4491 4495 +3 992 4436 2902 +3 2902 4436 4434 +3 2902 4434 4432 +3 4769 4768 6591 +3 4767 6981 4267 +3 6981 4767 4769 +3 1070 4769 4767 +3 4770 6981 4769 +3 4767 6012 1070 +3 4767 4267 6012 +3 4770 4771 6981 +3 4267 6981 4771 +3 4770 4769 6123 +3 4769 6591 6123 +3 6123 6591 4765 +3 4768 4765 6591 +3 4771 6124 6666 +3 6123 4765 6124 +3 4771 4770 6124 +3 6123 6124 4770 +3 3774 6489 6910 +3 1570 1482 1487 +3 1562 1563 5093 +3 1523 1590 1584 +3 1482 1485 1487 +3 1519 1590 1523 +3 3529 3543 5096 +3 5812 5096 3543 +3 1558 1482 1563 +3 1570 1563 1482 +3 3774 6537 6489 +3 1592 3512 6537 +3 5096 1488 3523 +3 1478 4853 1562 +3 3773 3512 1592 +3 1485 1486 1487 +3 1488 1486 1485 +3 1477 1559 1523 +3 1524 1523 1559 +3 1570 1487 5418 +3 1570 5418 1476 +3 6673 1519 1524 +3 5422 1524 1559 +3 1519 1523 1524 +3 1584 1477 1523 +3 1488 1485 3523 +3 1478 1562 5093 +3 1563 1570 5093 +3 1570 1476 5093 +3 1487 1486 5418 +3 5812 1486 1488 +3 3549 3773 1592 +3 3544 3773 3549 +3 3774 6673 1524 +3 3771 3512 3773 +3 6909 3773 3544 +3 3771 3773 6909 +3 3543 3549 3550 +3 3543 3544 3549 +3 3774 1524 5422 +3 3774 6910 6673 +3 1592 6537 3774 +3 3774 3549 1592 +3 3550 3549 3774 +3 5812 1488 5096 +3 5095 5812 3543 +3 3529 3544 3543 +3 1476 5418 5095 +3 3550 6928 5095 +3 1476 5095 6928 +3 5095 1486 5812 +3 5418 1486 5095 +3 1476 6928 1559 +3 1476 1559 5093 +3 1477 5093 1559 +3 1478 5093 1477 +3 3543 3550 5095 +3 5422 1559 6928 +3 3550 5422 6928 +3 5422 3550 3774 +3 1796 2001 2041 +3 1798 6174 1982 +3 1797 1800 1982 +3 1797 1796 1800 +3 1983 1982 1996 +3 1800 1798 1982 +3 5921 1635 4917 +3 6151 4916 6174 +3 1982 6174 1996 +3 4916 1996 6174 +3 6174 1798 6151 +3 4917 1635 5500 +3 1796 1797 6445 +3 6445 2001 1796 +3 1983 1647 2000 +3 1797 1993 6445 +3 1982 1983 2000 +3 1983 6702 1647 +3 1982 2000 1797 +3 1797 2000 1993 +3 4917 5500 6702 +3 1983 4917 6702 +3 1983 4915 4917 +3 4865 6151 4864 +3 4916 6151 4865 +3 1996 4916 4865 +3 4915 1996 4865 +3 1983 1996 4915 +3 5921 4865 4864 +3 5921 4915 4865 +3 5921 4917 4915 +3 6384 7033 576 +3 1791 1729 1801 +3 6384 1802 4885 +3 1727 6678 1707 +3 7042 7043 7044 +3 1536 7044 7043 +3 4884 7043 7042 +3 4884 7042 4874 +3 1801 1729 7033 +3 1729 1791 1707 +3 1727 1707 1791 +3 6159 4883 4889 +3 4884 4889 4883 +3 4883 6160 7043 +3 1536 7043 6160 +3 1791 1801 6159 +3 4886 6160 7047 +3 6160 4883 7047 +3 6384 7047 6159 +3 4883 6159 7047 +3 1801 6384 6159 +3 4885 7047 6384 +3 4885 4886 7047 +3 1802 4886 4885 +3 4889 4874 6153 +3 4884 4874 4889 +3 4884 4883 7043 +3 4889 1727 1791 +3 6159 4889 1791 +3 4889 6153 1727 +3 1801 7033 6384 +3 6384 576 1802 +3 3312 5771 3313 +3 3623 1502 3398 +3 3398 1502 3309 +3 3312 3313 1497 +3 3312 5785 5777 +3 1506 1502 3623 +3 1497 3313 1496 +3 3399 5785 1497 +3 3631 3623 3398 +3 5777 3309 3308 +3 3638 1497 3301 +3 3398 3309 5785 +3 1497 5785 3312 +3 3309 5777 5785 +3 3308 3309 3711 +3 3638 3399 1497 +3 5771 3312 5777 +3 3631 3398 5828 +3 5828 3398 3399 +3 5785 3399 3398 +3 1497 1496 3301 +3 3631 1506 3623 +3 1502 3711 3309 +3 1780 5459 1779 +3 5463 1780 1779 +3 1779 1365 5463 +3 1780 1871 5459 +3 6439 5459 1871 +3 1365 1779 1872 +3 6258 5285 5106 +3 6130 5113 5285 +3 5111 5106 7059 +3 4245 5285 5113 +3 7059 4245 5111 +3 7059 5106 5285 +3 4245 5113 5411 +3 1080 5411 5113 +3 4245 7059 5285 +3 4245 5112 5111 +3 5411 5112 4245 +3 6258 6130 5285 +3 4645 6086 4644 +3 4645 4644 4643 +3 4645 4643 7015 +3 6086 2736 2892 +3 6086 2892 4644 +3 3967 3973 930 +3 3973 5936 930 +3 6166 6169 4902 +3 6958 3973 3966 +3 5067 5897 5896 +3 2536 5894 2130 +3 5896 5894 5067 +3 2130 5894 5896 +3 5078 5724 5070 +3 1035 1034 3062 +3 5070 5724 2453 +3 2453 1035 5070 +3 1034 1035 2453 +3 2453 5724 5608 +3 3099 2453 5608 +3 1034 2453 3099 +3 1034 5721 6460 +3 3062 1034 6460 +3 3099 5721 1034 +3 2173 2172 3332 +3 3336 3324 3335 +3 3337 3324 3336 +3 3335 3333 5781 +3 3332 3333 3335 +3 3326 3324 3337 +3 5890 5889 5083 +3 3332 3331 2173 +3 3332 3324 3331 +3 3326 3331 3324 +3 3335 3324 3332 +3 3326 3348 3331 +3 5103 2173 3330 +3 1443 4840 4839 +3 5083 6135 5890 +3 3351 3335 5781 +3 5083 5072 6135 +3 1443 3330 4840 +3 4839 1444 6418 +3 5072 4838 6135 +3 3348 3330 3331 +3 1444 5081 6418 +3 2173 3331 3330 +3 3326 6838 5890 +3 3334 5890 6838 +3 3348 3326 5890 +3 3335 3351 3336 +3 3352 3336 3351 +3 3334 5889 5890 +3 6135 4840 3330 +3 4838 4840 6135 +3 4839 4840 1444 +3 4838 1444 4840 +3 1444 4838 5081 +3 5072 5081 4838 +3 6135 3348 5890 +3 3330 3348 6135 +3 1877 1879 1872 +3 5466 1879 1877 +3 1879 5466 1874 +3 5466 1357 1874 +3 1877 1357 5466 +3 1877 1870 1357 +3 1879 6686 1875 +3 1879 1874 6686 +3 1879 1868 1872 +3 1868 1879 1875 +3 5133 5132 5401 +3 5248 671 5404 +3 5401 5132 5139 +3 5133 4368 5132 +3 5404 5132 4368 +3 5258 671 5248 +3 5248 5404 4368 +3 4368 5133 5127 +3 5248 4368 5127 +3 4699 5258 5248 +3 4699 5248 5127 +3 4699 6276 5258 +3 6246 6248 5897 +3 4798 5897 6248 +3 3037 3044 3049 +3 792 965 4286 +3 792 4286 4289 +3 5483 1372 1933 +3 1949 1913 1936 +3 5483 1936 1913 +3 5483 1913 1372 +3 5515 1913 1949 +3 5515 1795 1913 +3 1933 1935 5483 +3 5483 1935 1936 +3 5078 5070 2455 +3 1055 5070 5891 +3 4826 5013 6245 +3 5074 3103 5061 +3 4826 6244 1054 +3 2455 5074 5078 +3 5074 2455 3103 +3 5061 5078 5074 +3 6244 4826 6245 +3 6244 6245 2455 +3 1035 5891 5070 +3 1055 1054 6244 +3 1055 6244 2455 +3 5070 1055 2455 +3 2455 6245 3103 +3 2471 2473 2472 +3 671 5406 5404 +3 1868 1830 1365 +3 4909 1830 1875 +3 1868 1875 1830 +3 1830 1808 1825 +3 1830 1809 1808 +3 1809 1830 4909 +3 2106 2173 5103 +3 2124 2118 2116 +3 2468 2469 549 +3 549 2473 550 +3 549 2463 2468 +3 2487 2462 2488 +3 2488 2462 2471 +3 549 2472 2473 +3 2462 561 2471 +3 2473 2471 561 +3 549 550 5589 +3 6751 2448 5582 +3 6753 2469 2468 +3 2469 2472 549 +3 5589 2463 549 +3 2484 2469 6753 +3 6751 2473 2448 +3 2448 607 5582 +3 607 5583 5581 +3 5581 2118 5584 +3 2124 5584 2118 +3 2119 2118 5581 +3 2124 5527 5584 +3 561 2448 2473 +3 550 5527 5589 +3 5583 2119 5581 +3 5582 607 5581 +3 2447 5582 5581 +3 5584 5527 550 +3 550 2447 5584 +3 2473 6751 550 +3 5582 2447 6751 +3 550 6751 2447 +3 4418 4419 4420 +3 2681 985 4418 +3 4420 2681 4418 +3 985 2865 4418 +3 2865 2896 4418 +3 2901 948 2681 +3 4420 2901 2681 +3 2681 948 985 +3 6094 4639 6093 +3 5513 2060 1935 +3 1853 2060 5513 +3 1356 1355 5469 +3 1355 1891 5469 +3 1128 5941 5942 +3 1872 1868 1365 +3 5491 5492 6700 +3 3308 6836 5777 +3 5771 5777 6836 +3 4093 4158 4164 +3 1357 1891 1358 +3 1900 1898 1357 +3 1898 1901 1891 +3 1898 1891 1357 +3 1355 1358 1891 +3 1874 1357 1358 +3 5469 1891 1901 +3 4374 4808 6034 +3 6034 4388 4374 +3 1111 4132 4094 +3 3906 1111 4094 +3 5721 3099 3101 +3 1933 1855 5514 +3 3353 5778 5780 +3 5067 6246 5897 +3 5937 3981 834 +3 3980 834 3981 +3 3975 833 4023 +3 3959 3903 1129 +3 5941 1129 3903 +3 3975 4023 3984 +3 5937 833 3975 +3 3984 5345 3975 +3 1145 5943 3975 +3 3981 6436 3980 +3 833 5937 834 +3 5937 3975 5943 +3 3981 5937 5943 +3 5345 1145 3975 +3 5943 1145 1127 +3 6436 5943 3903 +3 3981 5943 6436 +3 3959 6436 3903 +3 5943 1125 3903 +3 1127 1125 5943 +3 1147 5345 3984 +3 1146 1147 3984 +3 1545 1656 1543 +3 1896 1898 1900 +3 1900 1888 1896 +3 6691 1319 5553 +3 1910 6312 1888 +3 1317 1316 5350 +3 1890 6312 1910 +3 1896 1901 1898 +3 6312 1890 1902 +3 1896 1888 6312 +3 6312 1902 1892 +3 1896 6312 1892 +3 1900 1316 1317 +3 1910 1888 1324 +3 1900 1317 1888 +3 1892 1902 1893 +3 1901 1896 1892 +3 5471 2224 1320 +3 1901 1892 1895 +3 1892 1893 1895 +3 5471 1887 1321 +3 1320 1319 1893 +3 1902 5473 1893 +3 1320 1893 5473 +3 5473 1902 1890 +3 1895 6691 1318 +3 1893 6691 1895 +3 1893 1319 6691 +3 1890 1905 6692 +3 5472 6692 1905 +3 6692 5473 1890 +3 1887 5473 6692 +3 1887 1320 5473 +3 1910 1905 1890 +3 1888 1317 1324 +3 1905 1910 1324 +3 1321 1887 6692 +3 5472 1321 6692 +3 1887 5471 1320 +3 2224 5553 1319 +3 1320 2224 1319 +3 560 2448 561 +3 2345 1811 2298 +3 2298 1813 1812 +3 2298 1812 2345 +3 2340 1812 2342 +3 2345 1812 2340 +3 2342 5559 2339 +3 2342 2339 2340 +3 5192 5203 5384 +3 5192 7009 800 +3 5192 5384 7009 +3 1365 1866 5463 +3 1365 1825 1866 +3 1825 1365 1830 +3 6593 1873 4794 +3 6439 4794 1873 +3 4794 6439 1369 +3 5539 2214 2226 +3 5539 2226 1294 +3 2226 6450 1294 +3 2209 6450 2226 +3 2192 2208 2199 +3 2207 2199 2208 +3 2214 2209 2226 +3 2185 2186 2190 +3 2185 2190 2195 +3 6721 2191 6722 +3 1293 6722 2191 +3 6450 1286 6721 +3 1287 6721 1286 +3 2193 1293 2191 +3 5532 1403 2193 +3 2193 6721 1287 +3 5532 2193 1287 +3 2191 6721 2193 +3 2193 2185 2195 +3 2193 1403 1303 +3 2193 1303 2185 +3 2169 5532 1287 +3 2192 2199 6726 +3 2169 6726 2199 +3 2169 1286 6726 +3 2169 1287 1286 +3 2208 2209 2214 +3 6450 2209 6726 +3 2192 6726 2209 +3 1286 6450 6726 +3 2194 6722 1293 +3 2207 2208 2203 +3 2204 2207 2203 +3 2203 2208 2214 +3 2208 2192 2209 +3 1952 1953 1955 +3 1288 1966 5493 +3 1952 1642 1953 +3 1965 1952 1966 +3 1954 6697 1966 +3 1965 1966 6697 +3 1288 1954 1966 +3 1954 1951 6697 +3 1965 6697 1951 +3 1952 1955 5493 +3 1966 1952 5493 +3 1952 1965 1642 +3 4647 4649 4650 +3 4405 4650 5269 +3 5653 2893 4642 +3 2886 4642 4654 +3 4649 5269 4650 +3 6088 6089 4668 +3 6087 4652 4424 +3 4668 4647 6088 +3 4654 6773 2886 +3 5277 6413 5276 +3 5275 4729 6413 +3 4649 4647 4668 +3 4667 4649 4668 +3 5272 5270 4727 +3 5275 4668 4677 +3 6089 4677 4668 +3 4667 4668 5275 +3 2716 4405 5269 +3 4727 4667 5277 +3 4667 5275 6413 +3 5277 5276 6650 +3 975 6650 5276 +3 4727 5277 6650 +3 4644 6090 4643 +3 2892 2736 4426 +3 7016 6089 6088 +3 2892 6089 7016 +3 6089 4426 4677 +3 2892 4426 6089 +3 4643 6090 2886 +3 7016 5653 6090 +3 4644 7016 6090 +3 5653 2886 6090 +3 4642 2886 5653 +3 6088 6087 5653 +3 6087 4647 4652 +3 6088 4647 6087 +3 5653 6087 2893 +3 6088 5653 7016 +3 4644 2892 7016 +3 2716 5269 5270 +3 4649 4667 4727 +3 5270 4649 4727 +3 5270 5269 4649 +3 2716 5270 5272 +3 6282 6650 975 +3 6282 5272 4727 +3 6282 4727 6650 +3 4667 6413 5277 +3 1131 3958 5940 +3 5941 5940 5942 +3 1131 5941 3903 +3 1131 5940 5941 +3 1125 1131 3903 +3 980 996 2872 +3 3357 3662 3660 +3 3787 3356 3791 +3 3357 3660 3791 +3 3648 3660 3662 +3 3788 3791 3660 +3 3356 3357 3791 +3 3784 3660 3648 +3 3784 3788 3660 +3 3682 3791 3788 +3 3787 3791 3682 +3 3154 3152 3166 +3 5853 1498 1227 +3 3729 3742 3741 +3 3758 1498 3741 +3 5853 3741 1498 +3 6624 1498 3758 +3 3742 3758 3741 +3 3742 3730 3758 +3 6274 5295 5255 +3 5998 1008 4093 +3 5118 5250 1074 +3 1074 4162 4157 +3 5292 5291 5409 +3 4241 5108 4240 +3 5393 5157 1075 +3 5255 5295 5292 +3 4162 4156 4157 +3 6442 1075 5157 +3 6442 5158 1075 +3 5301 4738 5287 +3 5293 5294 6287 +3 4162 1074 5114 +3 5107 5408 5291 +3 4093 4164 4803 +3 4093 4803 6978 +3 4739 5287 4241 +3 6978 5998 4093 +3 4161 1009 1008 +3 4158 4093 1008 +3 5250 5291 5408 +3 4167 5107 5105 +3 5284 5296 5300 +3 4240 4239 4241 +3 4738 6407 5287 +3 4241 5287 6407 +3 5278 4799 6408 +3 5281 5282 6403 +3 4799 5282 6287 +3 4241 4239 4739 +3 4241 6407 5108 +3 5281 6287 5282 +3 5108 6407 5281 +3 6287 5281 6285 +3 4158 1008 1009 +3 6403 4240 5108 +3 5294 4799 6287 +3 5408 5107 4167 +3 5294 6408 4799 +3 5282 5290 6403 +3 5290 5282 4799 +3 5279 5278 6408 +3 5281 6407 5283 +3 5281 4812 6285 +3 4738 5283 6407 +3 5293 6287 6285 +3 4378 5160 4452 +3 4450 4452 5160 +3 5160 4378 4451 +3 1009 4161 1076 +3 5295 6274 5293 +3 4091 4166 4803 +3 6274 5294 5293 +3 5279 6408 5391 +3 4377 4452 4453 +3 5281 6403 5108 +3 5160 6604 4449 +3 4171 4092 4091 +3 5391 6408 4670 +3 6408 5294 4670 +3 5393 4451 5157 +3 5160 4451 5393 +3 5395 6664 4346 +3 5395 4346 4375 +3 4373 2701 5136 +3 5395 4377 6664 +3 5159 6665 4377 +3 5400 5159 4377 +3 5119 1009 5394 +3 5114 5408 4167 +3 5409 5250 5118 +3 5291 5250 5409 +3 1074 5250 5408 +3 5114 1074 5408 +3 4164 6668 4091 +3 4171 4091 6668 +3 4170 4179 4175 +3 1004 4170 4175 +3 4175 4212 6429 +3 4175 6429 1004 +3 4175 4179 4212 +3 4378 4377 6665 +3 5159 5140 4378 +3 4451 4378 5140 +3 5294 6274 4670 +3 5039 5120 1075 +3 5120 5039 2703 +3 4806 5251 2703 +3 4156 4158 4157 +3 4156 4164 4158 +3 4166 4091 6977 +3 4170 6977 4091 +3 4170 1005 6977 +3 1005 4170 1004 +3 4212 4179 4092 +3 4157 4158 1009 +3 1009 1076 5394 +3 1009 5119 4157 +3 1074 4157 5119 +3 4156 6668 4164 +3 4164 4091 4803 +3 4170 4091 4092 +3 4450 5160 4449 +3 4377 4453 6664 +3 4378 4452 4377 +3 4179 4170 4092 +3 5290 4240 6403 +3 5119 5394 7036 +3 5120 7036 5394 +3 1075 5120 5394 +3 4814 4817 6129 +3 4817 6131 6129 +3 4817 4812 6131 +3 5105 6258 4167 +3 5107 7058 4814 +3 5105 5107 4814 +3 4092 4171 5111 +3 5109 5111 4171 +3 4171 6668 5109 +3 4156 5109 6668 +3 5106 4162 5114 +3 4156 4162 5109 +3 5106 5109 4162 +3 4167 6258 5106 +3 5106 5114 4167 +3 5111 5109 5106 +3 5118 2703 5251 +3 5119 2703 5118 +3 5118 1074 5119 +3 5120 2703 7036 +3 5119 7036 2703 +3 4373 5136 5134 +3 4373 5134 5135 +3 4375 5134 5400 +3 5135 5134 4375 +3 4377 5395 5400 +3 4375 5400 5395 +3 5159 4378 6665 +3 1075 5394 5393 +3 4376 5140 5159 +3 4451 5140 6442 +3 5159 5400 7060 +3 5134 7060 5400 +3 4376 5159 7060 +3 1076 6604 5393 +3 5160 5393 6604 +3 4451 6442 5157 +3 5409 5118 4264 +3 5251 4264 5118 +3 5409 6275 5292 +3 5255 5292 6275 +3 5245 7064 5391 +3 5279 5391 7064 +3 5283 6286 4812 +3 5296 6286 5301 +3 5283 5301 6286 +3 5284 6286 5296 +3 4812 5281 5283 +3 5105 4814 6129 +3 6286 5284 6131 +3 6286 6131 4812 +3 6288 7058 5291 +3 4814 7058 6288 +3 6288 5291 5292 +3 5293 6285 4812 +3 5295 5293 4817 +3 5293 4812 4817 +3 5295 6288 5292 +3 4814 6288 4817 +3 5295 4817 6288 +3 4264 6275 5409 +3 4738 5301 5283 +3 3850 3835 3851 +3 5941 1128 1129 +3 3080 2629 5681 +3 1282 5500 5501 +3 1984 1641 5496 +3 1984 5501 1641 +3 5496 1641 5495 +3 1282 5501 1984 +3 1323 1314 1951 +3 1314 1323 1948 +3 1948 1965 1314 +3 1314 1965 1951 +3 1732 1737 1738 +3 3826 3455 5867 +3 5871 3833 3845 +3 3833 3834 888 +3 3846 889 888 +3 888 889 3833 +3 889 3845 3833 +3 5873 888 3834 +3 3957 1126 3969 +3 4069 5968 4074 +3 4052 4069 1122 +3 4069 4074 1122 +3 4084 4074 4090 +3 4090 4137 4084 +3 4084 1122 4074 +3 4069 4052 4064 +3 4074 5968 4087 +3 4087 4068 4086 +3 4073 4086 4068 +3 5968 4068 4087 +3 4064 6433 4069 +3 4064 6432 6433 +3 6433 4068 5968 +3 4069 6433 5968 +3 5110 5297 5299 +3 5410 4246 5110 +3 5110 5289 5297 +3 5299 5410 5110 +3 5107 5291 7058 +3 981 2872 2851 +3 4651 950 6092 +3 4957 2309 2310 +3 6298 2310 2309 +3 2309 2313 6298 +3 2316 2310 6298 +3 2300 2305 4957 +3 2325 2318 2316 +3 2305 2309 4957 +3 2305 2313 2309 +3 6298 552 2316 +3 6298 2313 552 +3 2320 552 2317 +3 2313 2317 552 +3 2317 2313 2305 +3 2325 2316 1818 +3 1818 2316 553 +3 552 553 2316 +3 6552 2176 2260 +3 2171 1310 1306 +3 1429 2260 2162 +3 2162 2260 2176 +3 1429 5545 2260 +3 2162 5550 1429 +3 2264 5548 2263 +3 6321 2216 2248 +3 1296 2194 2187 +3 2179 6718 2175 +3 2171 2179 2175 +3 5545 5542 2260 +3 2161 2165 2159 +3 2148 2165 2161 +3 1298 2187 2190 +3 1293 2187 2194 +3 2251 2108 6552 +3 2260 5542 6552 +3 2160 2148 2161 +3 2171 2175 2164 +3 2220 1296 1298 +3 5547 2176 2163 +3 2245 6321 2249 +3 2163 2108 1338 +3 1310 2171 2164 +3 2174 2160 2159 +3 2160 2161 2159 +3 1430 5543 2232 +3 2262 2163 1301 +3 2176 6552 2163 +3 2108 2163 6552 +3 2163 1338 1301 +3 2174 2159 2164 +3 2148 2160 1347 +3 2175 2180 2174 +3 2175 2174 2164 +3 2175 6718 2180 +3 1408 6718 6719 +3 2179 6719 6718 +3 1298 1296 2187 +3 2248 6729 6321 +3 2249 6321 6729 +3 2245 6730 6321 +3 6729 2248 5542 +3 1296 5542 2248 +3 2245 2249 2244 +3 6731 6729 5545 +3 5542 5545 6729 +3 2249 6729 6731 +3 5543 1430 2252 +3 2252 1430 2177 +3 2244 6731 6734 +3 2177 2162 5547 +3 2176 5547 2162 +3 2163 2262 5547 +3 6736 2177 2264 +3 5547 2264 2177 +3 2263 6736 2264 +3 5547 2262 2264 +3 1306 1310 5548 +3 2264 1306 5548 +3 2262 1301 2179 +3 5549 2262 2179 +3 2264 2262 1306 +3 5549 1306 2262 +3 2171 1306 5549 +3 2171 5549 2179 +3 2249 6731 2244 +3 1301 1408 6719 +3 2177 1430 2162 +3 5550 2162 1430 +3 2251 6552 2220 +3 5542 2220 6552 +3 1296 2220 5542 +3 1296 2248 2216 +3 2194 1296 2216 +3 1338 2108 1408 +3 1338 1408 1301 +3 3062 6460 3064 +3 5721 3095 3064 +3 5697 3093 6802 +3 5718 6802 3093 +3 5718 3095 5721 +3 4805 2535 6609 +3 3064 6460 5721 +3 6609 3058 2454 +3 2535 3058 6609 +3 6609 5722 4805 +3 3101 4805 5722 +3 2454 5722 6609 +3 5697 5698 3093 +3 3095 3093 3096 +3 5718 3093 3095 +3 3023 3100 3096 +3 3023 3096 5698 +3 3093 5698 3096 +3 3095 3096 3102 +3 5720 3063 3100 +3 3102 3100 3063 +3 3056 3063 5720 +3 3096 3100 3102 +3 3095 3102 3064 +3 3064 3102 3063 +3 3062 3064 3063 +3 5722 2454 5718 +3 5721 3101 5718 +3 5722 5718 3101 +3 3192 5737 3157 +3 3191 5763 1433 +3 1433 5763 3296 +3 3192 5763 5737 +3 3191 5737 5763 +3 5763 3192 3296 +3 1433 6899 3191 +3 4561 4607 683 +3 683 7008 4561 +3 7008 5263 4561 +3 4541 4543 6064 +3 4607 4560 683 +3 6064 683 6065 +3 4541 6064 6065 +3 683 4560 6065 +3 4560 4541 6065 +3 5264 5175 5262 +3 5264 5262 5263 +3 5415 5263 5262 +3 4561 5263 5415 +3 4540 5193 788 +3 7004 5193 4539 +3 788 5193 7004 +3 6064 788 7004 +3 683 6064 7004 +3 4543 788 6064 +3 683 4539 7008 +3 4584 4561 5415 +3 4584 4607 4561 +3 4539 683 7004 +3 7006 788 4543 +3 4540 788 7006 +3 7008 4539 5264 +3 5263 7008 5264 +3 4539 5175 5264 +3 5193 4540 5175 +3 4539 5193 5175 +3 6566 4756 4745 +3 4743 4745 663 +3 4744 4753 4743 +3 4745 4752 6566 +3 4745 4753 4752 +3 4741 4752 4753 +3 4757 4776 663 +3 4777 4757 664 +3 4776 4757 4777 +3 4748 4753 4744 +3 665 4744 4743 +3 4753 4745 4743 +3 5370 4751 4741 +3 4752 4741 661 +3 5370 4748 4751 +3 4748 5370 4753 +3 4741 4753 5370 +3 663 4776 665 +3 4743 663 665 +3 4777 665 4776 +3 5328 862 871 +3 870 3221 5735 +3 3168 870 5735 +3 6812 862 6349 +3 3185 3234 861 +3 871 862 6812 +3 3221 870 3167 +3 1431 5328 871 +3 895 6509 898 +3 3185 861 5328 +3 1431 3185 5328 +3 895 898 3226 +3 862 5328 6634 +3 862 6634 6349 +3 880 6636 879 +3 3224 3185 1431 +3 5735 6813 1499 +3 1431 1499 6813 +3 3187 6813 5735 +3 5735 1499 3168 +3 3221 3167 879 +3 3225 3224 6813 +3 1431 6813 3224 +3 895 3226 3186 +3 3221 3187 5735 +3 5328 861 6634 +3 3224 3234 3185 +3 3225 3234 3224 +3 3225 6813 3187 +3 3238 3234 3225 +3 3221 3225 3187 +3 5745 3234 3238 +3 5745 861 3234 +3 880 879 3167 +3 6636 3226 879 +3 3221 879 3226 +3 3226 6636 3186 +3 880 3186 6636 +3 3226 898 3221 +3 733 2841 732 +3 2831 6769 732 +3 2841 2831 732 +3 6039 969 6035 +3 4383 6040 6039 +3 4383 6035 970 +3 6039 6035 4383 +3 2673 2779 2782 +3 2632 2642 5624 +3 2587 2780 2632 +3 2778 2782 2779 +3 5635 2642 2632 +3 2635 5624 2642 +3 2782 640 2673 +3 2635 6758 5624 +3 2632 2780 5635 +3 2779 2642 2778 +3 5635 2778 2642 +3 2635 640 6758 +3 2673 640 2635 +3 2779 2673 2635 +3 2642 2779 2635 +3 5893 1352 2122 +3 514 1352 5893 +3 6240 6452 514 +3 5893 6240 514 +3 7056 5893 2122 +3 6240 5893 7056 +3 3592 3609 3608 +3 3608 3609 5822 +3 3609 3592 3598 +3 1060 1036 3111 +3 3061 3055 5706 +3 3055 2614 5706 +3 2614 2613 5706 +3 3055 3061 1026 +3 894 1026 3061 +3 3060 894 3061 +3 3109 6461 3060 +3 6584 6585 3028 +3 3111 6584 3028 +3 3027 6585 6584 +3 5340 5688 2614 +3 5340 2617 5688 +3 3016 2617 6585 +3 3016 6585 3027 +3 3016 6794 2617 +3 5688 2617 6794 +3 2613 6794 3016 +3 3027 3054 3016 +3 2613 3016 3054 +3 3109 2613 3054 +3 3109 5706 2613 +3 3028 6585 2617 +3 5688 6794 2614 +3 2613 2614 6794 +3 5340 1059 2617 +3 3061 3109 3060 +3 5706 3109 3061 +3 3054 3107 6461 +3 3109 3054 6461 +3 3054 3027 3107 +3 3111 3028 1060 +3 3028 2617 1059 +3 5707 3028 1059 +3 1060 3028 5707 +3 2281 1335 2272 +3 1335 2281 5552 +3 4042 1155 1159 +3 5056 818 822 +3 5057 6579 2699 +3 717 716 5326 +3 717 5326 715 +3 2686 716 748 +3 1019 6762 2686 +3 716 6762 5326 +3 5326 6762 1019 +3 717 747 716 +3 2686 6762 716 +3 2864 2900 6419 +3 2899 6419 2900 +3 717 715 5057 +3 2699 747 5057 +3 717 5057 747 +3 6419 2899 755 +3 754 755 2899 +3 2860 716 747 +3 748 716 2860 +3 748 2860 2864 +3 2864 2860 2900 +3 2900 747 2899 +3 2860 747 2900 +3 2699 754 2899 +3 747 2699 2899 +3 818 6579 5629 +3 715 5629 6579 +3 2699 6930 754 +3 5056 754 6930 +3 6930 6579 5056 +3 2699 6579 6930 +3 5057 715 6579 +3 818 5056 6579 +3 4082 6430 6431 +3 4123 6431 6430 +3 5981 1112 4123 +3 4083 4123 1112 +3 4123 1114 6431 +3 4083 1114 4123 +3 4123 6430 5981 +3 6431 1114 5979 +3 4082 6431 5979 +3 1112 5981 4113 +3 6430 4113 5981 +3 515 5590 6452 +3 5153 950 4416 +3 4655 950 4653 +3 6092 950 4655 +3 4427 950 5153 +3 985 948 4427 +3 4427 5153 985 +3 4428 4427 948 +3 4653 4427 4428 +3 950 4427 4653 +3 6099 4299 4671 +3 4399 6099 5317 +3 599 5317 6099 +3 4299 6099 4399 +3 5747 3845 3241 +3 3240 5747 5748 +3 3248 5748 5747 +3 3241 3248 5747 +3 3845 5747 5871 +3 3240 5871 5747 +3 5748 5746 3240 +3 1568 1525 1560 +3 1568 1561 5417 +3 1560 1561 1568 +3 1561 5419 5417 +3 1561 1574 5419 +3 1567 5417 5419 +3 1567 1477 1568 +3 1584 1568 1477 +3 1584 1525 1568 +3 1567 1568 5417 +3 1567 5419 4852 +3 1567 1478 1477 +3 4852 1478 1567 +3 1911 1325 1323 +3 1911 1951 5488 +3 1323 1951 1911 +3 2845 2821 4802 +3 6929 5889 3334 +3 2237 2240 2291 +3 2237 2291 2236 +3 5541 2234 2205 +3 6730 2215 6321 +3 6730 5541 2215 +3 6321 2215 2216 +3 2234 5541 6730 +3 2228 2205 2234 +3 2235 2237 2238 +3 2215 5541 2205 +3 2216 2215 5536 +3 2206 2218 2217 +3 2206 2196 2222 +3 2197 2204 2222 +3 5536 2215 2205 +3 2214 2218 2203 +3 2197 2213 2204 +3 2197 2222 2196 +3 2237 2236 2238 +3 2234 2235 2228 +3 2291 6738 2236 +3 1295 2217 6727 +3 1329 2225 6543 +3 2223 6543 2225 +3 2211 2196 2212 +3 2230 2228 2238 +3 2228 2235 2238 +3 5535 2206 5536 +3 1295 5536 2206 +3 2205 6725 5536 +3 5535 5536 6725 +3 1295 2206 2217 +3 2211 2197 2196 +3 2218 2204 2203 +3 5538 2194 6727 +3 5538 6722 2194 +3 2196 2206 5535 +3 5535 2212 2196 +3 2221 2212 5535 +3 2218 2206 2222 +3 2218 2222 2204 +3 1329 2213 2197 +3 1329 2197 2211 +3 1329 6543 2213 +3 2218 2214 2217 +3 5539 2217 2214 +3 5539 6727 2217 +3 5538 6727 5539 +3 5539 1294 5538 +3 5535 6725 2221 +3 2229 2221 6725 +3 5536 1295 2216 +3 2216 1295 6727 +3 2194 2216 6727 +3 2205 2229 6725 +3 2230 2229 2205 +3 2205 2228 2230 +3 2235 2240 2237 +3 2278 6738 2291 +3 1334 2278 2291 +3 2240 1334 2291 +3 3696 3690 3323 +3 3691 3323 3690 +3 5102 3691 3703 +3 3690 3703 3691 +3 619 2636 2671 +3 2668 619 2671 +3 2782 2778 2783 +3 2639 615 619 +3 2672 2668 2671 +3 2657 2639 2668 +3 619 615 2652 +3 2639 619 2668 +3 2672 2671 2778 +3 2671 2783 2778 +3 619 2652 2636 +3 2643 2671 2636 +3 6456 2671 2643 +3 6456 6455 2783 +3 6455 2782 2783 +3 2783 2671 6456 +3 1049 615 2658 +3 2639 2658 615 +3 2672 2657 2668 +3 1430 2232 5550 +3 2233 1429 2232 +3 2232 1305 2233 +3 1429 5550 2232 +3 5545 6734 6731 +3 2233 1305 6734 +3 1429 2233 6734 +3 5545 1429 6734 +3 3989 3999 3996 +3 3999 5951 3996 +3 4385 971 4395 +3 4391 4395 971 +3 6999 6039 6040 +3 4385 6040 4386 +3 6999 4395 4390 +3 6999 6040 4385 +3 4385 958 971 +3 6036 959 951 +3 951 4282 958 +3 4282 971 958 +3 971 4282 4371 +3 951 6996 6036 +3 6037 6036 6996 +3 4387 6038 4386 +3 6037 6038 4387 +3 958 6038 6996 +3 6037 6996 6038 +3 951 958 6996 +3 958 4385 6038 +3 4385 4386 6038 +3 4371 4391 971 +3 4391 4371 4381 +3 4282 4381 4371 +3 4282 952 4381 +3 952 4282 951 +3 4514 4821 6660 +3 6660 6062 4532 +3 6660 4510 6062 +3 4479 6062 4510 +3 4548 5389 6062 +3 4532 6062 5389 +3 4532 4514 6660 +3 5168 5389 4548 +3 4548 4511 5168 +3 4479 4515 4558 +3 4558 4511 4479 +3 4548 4479 4511 +3 4532 4478 4514 +3 4553 4477 4554 +3 4554 4515 4510 +3 4479 4510 4515 +3 4477 4515 4554 +3 7020 4720 4511 +3 4558 7020 4511 +3 677 4515 7022 +3 4477 7022 4515 +3 7020 4558 677 +3 4515 677 4558 +3 677 7022 6426 +3 4720 7020 4712 +3 677 4712 7020 +3 677 6426 4712 +3 4511 4492 5168 +3 2152 6716 2156 +3 2157 2142 6716 +3 2134 2156 2146 +3 2134 2152 2156 +3 2142 2157 6546 +3 2152 6546 2157 +3 2152 2134 6546 +3 2157 6716 2152 +3 4447 4231 4234 +3 1015 4231 4447 +3 4447 4234 4454 +3 6006 4454 4234 +3 4231 6006 4234 +3 5178 7061 6263 +3 5178 6263 5171 +3 7061 6264 6263 +3 5171 6263 5179 +3 6263 6264 5179 +3 1417 3803 3797 +3 6357 1427 3807 +3 1652 3803 1417 +3 3798 1652 1417 +3 1427 3798 1417 +3 1652 5859 3803 +3 1462 3803 5859 +3 5859 3802 1462 +3 3807 3797 3805 +3 6357 3807 3805 +3 3797 3807 1417 +3 3807 1427 1417 +3 3798 3810 1652 +3 1428 3810 1427 +3 1427 3810 3798 +3 1652 3806 5859 +3 5859 3806 3802 +3 3802 3806 3464 +3 3806 6916 3464 +3 1652 6916 3806 +3 6357 1428 1427 +3 1502 3667 3711 +3 3683 6894 1504 +3 5842 3711 3667 +3 1502 1506 3667 +3 1504 5842 3683 +3 1504 3711 5842 +3 2795 2799 2663 +3 6509 3219 896 +3 815 704 829 +3 704 6582 6581 +3 704 6581 829 +3 829 703 815 +3 4577 6656 5217 +3 5216 4584 5217 +3 5379 4577 6655 +3 5217 6655 4577 +3 4584 6655 5217 +3 6655 4584 5379 +3 4574 5379 6069 +3 6069 5379 4584 +3 6074 6656 4577 +3 4577 5379 6075 +3 4574 6075 5379 +3 6074 4577 4619 +3 4577 6075 4619 +3 738 6539 6538 +3 2442 6538 6539 +3 5000 5526 6750 +3 5526 5580 6750 +3 6750 2442 6539 +3 5000 6750 6539 +3 5580 2442 6750 +3 738 6538 5598 +3 6500 3606 6871 +3 3606 3585 6871 +3 3949 3928 933 +3 4364 6372 4320 +3 2712 5042 5044 +3 2711 5040 5042 +3 5040 2723 5042 +3 5042 5043 5044 +3 4370 5146 5126 +3 2724 5146 4369 +3 2723 5043 5042 +3 2711 2712 4409 +3 6372 5146 4370 +3 4347 6372 4364 +3 4370 4320 6372 +3 2712 5044 6475 +3 4363 4369 4347 +3 2712 2724 4369 +3 5150 5151 5145 +3 4370 4340 4320 +3 2724 5398 5146 +3 4363 4364 4372 +3 4372 4384 6043 +3 4363 4372 6043 +3 4364 4363 4347 +3 932 4380 6995 +3 4384 4380 4382 +3 6995 4384 6926 +3 4372 6926 4384 +3 4380 4384 6995 +3 2712 4369 4409 +3 4363 6043 4409 +3 6043 4382 7001 +3 5151 7001 4382 +3 4384 4382 6043 +3 4363 4409 4369 +3 2711 5150 5145 +3 5150 4409 7001 +3 5150 7001 5151 +3 6043 7001 4409 +3 5128 5126 5133 +3 5131 5130 4340 +3 5131 4348 5130 +3 5128 5133 5131 +3 5131 5401 4348 +3 5133 5401 5131 +3 5128 5131 4340 +3 5146 5398 5126 +3 2711 4409 5150 +3 5126 5128 4370 +3 4370 5128 4340 +3 2711 4408 5040 +3 5398 2724 6280 +3 5267 6280 6475 +3 2724 6475 6280 +3 5043 4726 5267 +3 5043 5267 5044 +3 5267 6475 5044 +3 2723 4726 5043 +3 6372 4369 5146 +3 4347 4369 6372 +3 2712 6475 2724 +3 2712 2711 5042 +3 3013 5701 2968 +3 3065 3017 6515 +3 3065 6515 5691 +3 3033 3065 5691 +3 3034 3065 3033 +3 5691 5701 3018 +3 5691 2968 5701 +3 5691 6515 2968 +3 3017 2968 6515 +3 3033 5691 3018 +3 3013 2968 5674 +3 1666 545 4828 +3 1672 4828 6307 +3 1693 585 1747 +3 6307 4828 545 +3 586 6303 1672 +3 1695 1688 1751 +3 581 1670 1666 +3 581 1748 1670 +3 1675 6303 586 +3 4854 6303 1675 +3 586 6307 545 +3 1747 1695 1751 +3 1748 1671 1691 +3 580 6308 1671 +3 585 1695 1747 +3 585 1690 1688 +3 1748 581 1671 +3 1670 1674 1666 +3 1672 6307 586 +3 1693 1691 585 +3 1693 1748 1691 +3 1693 1674 1670 +3 1693 1670 1748 +3 585 1688 1695 +3 581 540 580 +3 581 580 1671 +3 4828 1672 540 +3 1672 6303 540 +3 1691 1671 6308 +3 6308 585 1691 +3 540 1666 4828 +3 581 1666 540 +3 525 2854 956 +3 2863 525 956 +3 2863 526 525 +3 956 2854 5648 +3 750 2854 525 +3 2863 956 5650 +3 6528 2854 750 +3 6528 5648 2854 +3 5648 5650 956 +3 750 2738 6528 +3 2824 2738 750 +3 2823 979 2821 +3 2875 2853 2823 +3 2845 2823 2821 +3 2822 2823 2845 +3 2822 2875 2823 +3 2878 2876 2877 +3 2875 2822 2877 +3 2878 2877 2822 +3 6768 2841 733 +3 733 2844 6768 +3 2870 2873 6529 +3 6768 2844 5638 +3 724 725 6529 +3 2850 6529 725 +3 4802 827 2845 +3 5647 2880 2871 +3 2848 2847 2846 +3 2842 827 2848 +3 724 6529 2873 +3 5637 2829 2830 +3 827 2842 2830 +3 2831 5637 2830 +3 2831 2830 2842 +3 2841 5637 2831 +3 5638 6767 2843 +3 2829 2843 2835 +3 5638 2843 2829 +3 5638 2844 6767 +3 5637 5638 2829 +3 5638 5637 6768 +3 2841 6768 5637 +3 827 4802 2848 +3 2825 2848 4802 +3 2825 4802 5644 +3 724 2848 725 +3 5652 2871 6772 +3 5647 2871 5652 +3 531 6530 5652 +3 5647 5652 6530 +3 2871 2880 2867 +3 5652 6772 2870 +3 2871 2867 6772 +3 5643 6772 2867 +3 6529 531 5652 +3 2870 6529 5652 +3 2850 531 6529 +3 724 2847 2848 +3 6769 2842 2846 +3 2831 2842 6769 +3 2842 2848 2846 +3 3124 851 852 +3 851 3124 3120 +3 3731 3290 3734 +3 5808 3495 3532 +3 5808 3486 1617 +3 5808 3532 3486 +3 6912 3487 3532 +3 3532 3487 3486 +3 1617 5427 5808 +3 5808 1619 3495 +3 5808 5427 1619 +3 1619 6854 3491 +3 5427 6854 1619 +3 1619 3491 3495 +3 3491 3530 3495 +3 3530 3532 3495 +3 3532 3530 3595 +3 3487 6912 3485 +3 3532 3595 6912 +3 3652 3651 3653 +3 3657 3651 3652 +3 3657 3652 3641 +3 2678 1091 2677 +3 1018 2677 1091 +3 2678 2677 2701 +3 1017 5885 5141 +3 2701 2677 1018 +3 1018 5885 1017 +3 5885 1018 1091 +3 5140 5141 6442 +3 5158 6442 5141 +3 1018 5136 2701 +3 5141 4376 1017 +3 5136 1018 7000 +3 1017 7000 1018 +3 5134 5136 7060 +3 7060 7000 4376 +3 1017 4376 7000 +3 5136 7000 7060 +3 5141 5140 4376 +3 6001 4222 4141 +3 4187 4222 6980 +3 4186 4226 6004 +3 4222 6001 6000 +3 6000 6980 4222 +3 4187 4186 4222 +3 4141 4222 4186 +3 4186 6004 4141 +3 4141 6004 1002 +3 6005 6370 4226 +3 4174 4173 6369 +3 1005 1004 6370 +3 4226 6369 4173 +3 1004 4174 6369 +3 4141 1002 4227 +3 4174 1001 4173 +3 1005 6370 6005 +3 4153 4174 1004 +3 6370 1004 6369 +3 1004 6429 4177 +3 1004 4177 4153 +3 4174 4153 1001 +3 4173 1002 6004 +3 4226 4173 6004 +3 4173 1001 1002 +3 4226 6370 6369 +3 3151 1150 3979 +3 4034 3979 1150 +3 3634 3400 3303 +3 2092 2093 6602 +3 1221 2092 6339 +3 3280 6340 5759 +3 6339 2092 6602 +3 6339 6602 6340 +3 2093 6340 6602 +3 1222 6339 6340 +3 3280 1222 6340 +3 3281 3280 5759 +3 6340 2093 5759 +3 1221 6339 1222 +3 6906 3752 3156 +3 1174 5938 1168 +3 1682 1396 1367 +3 1682 1857 1396 +3 1682 5457 1857 +3 3375 3650 3347 +3 1606 6481 1581 +3 5421 1581 6481 +3 1516 6672 5421 +3 5421 6481 1516 +3 6672 1580 1581 +3 5421 6672 1581 +3 1569 1580 6672 +3 1580 1606 1581 +3 2764 2762 6332 +3 3718 3719 3163 +3 6957 6958 3970 +3 3970 6958 3966 +3 4673 5252 7065 +3 1621 1480 5920 +3 1621 5920 5919 +3 1832 1842 1378 +3 6685 1378 1842 +3 1832 1378 6612 +3 1845 6612 1378 +3 5455 6685 1842 +3 888 857 3846 +3 4903 5480 4898 +3 5360 1920 5482 +3 1920 5481 5482 +3 4903 5481 5480 +3 1920 5480 5481 +3 4898 4901 4903 +3 776 962 777 +3 4290 776 978 +3 777 832 776 +3 4321 962 964 +3 962 4321 777 +3 963 777 4321 +3 4327 963 4321 +3 963 832 777 +3 962 776 4290 +3 962 4290 953 +3 832 978 776 +3 964 5334 6033 +3 6033 4319 964 +3 963 4327 6024 +3 4321 4329 4327 +3 964 962 953 +3 944 5334 953 +3 944 953 6016 +3 6016 953 4290 +3 964 953 5334 +3 4329 6025 4327 +3 964 4329 4321 +3 964 4319 4329 +3 6025 4329 4319 +3 6025 4319 4332 +3 2300 4957 557 +3 2116 2127 2124 +3 2303 2304 6297 +3 2827 2833 2828 +3 2308 557 558 +3 2539 6324 2322 +3 2127 887 2129 +3 5589 5588 2463 +3 2835 2827 2828 +3 5908 5000 2452 +3 2504 2319 5007 +3 2308 2311 557 +3 2509 6295 2521 +3 2464 2463 739 +3 2529 730 2303 +3 744 2129 887 +3 2324 2325 2520 +3 697 2529 2475 +3 2531 2532 2538 +3 2527 5607 2459 +3 5527 744 5589 +3 6296 6295 2415 +3 2316 2318 2310 +3 2124 2129 5527 +3 744 5527 2129 +3 887 2127 885 +3 744 887 743 +3 744 743 5588 +3 744 5588 5589 +3 739 2463 5588 +3 2304 2303 730 +3 6539 5591 2452 +3 2307 685 558 +3 2308 685 2128 +3 2306 697 2611 +3 2461 556 2319 +3 2478 2304 2307 +3 2306 2838 2834 +3 5000 5908 2120 +3 2479 2483 551 +3 551 2476 6362 +3 2457 6324 2610 +3 2129 2124 2127 +3 5007 2319 2324 +3 5006 2479 2503 +3 2324 2319 2318 +3 2485 2480 2464 +3 5007 2522 2344 +3 2609 6361 2126 +3 556 2310 2319 +3 2318 2319 2310 +3 731 2128 685 +3 5008 2522 2520 +3 6361 2610 2126 +3 5008 5607 2522 +3 2527 2522 5607 +3 5006 2483 2479 +3 2838 2306 2611 +3 2461 2319 2504 +3 2504 2314 2461 +3 6539 738 5591 +3 2483 2480 551 +3 2531 2530 2532 +3 2538 2542 2560 +3 2456 2534 695 +3 2837 2838 2611 +3 2537 2531 2538 +3 2560 2537 2538 +3 2832 2828 2833 +3 2828 2554 2835 +3 2826 2554 2832 +3 2344 2509 2521 +3 2534 2542 2532 +3 2311 2128 731 +3 2509 2401 2524 +3 2525 2401 2509 +3 698 2560 2832 +3 734 2832 2560 +3 684 2311 731 +3 2116 885 2127 +3 987 627 695 +3 2560 698 2537 +3 2833 530 2832 +3 2312 2530 2531 +3 2479 551 6362 +3 2476 2314 6362 +3 690 6297 737 +3 5006 2503 2521 +3 2559 734 2560 +3 5007 2503 2504 +3 734 2826 2832 +3 2528 2475 2529 +3 2544 987 2457 +3 731 730 2529 +3 987 2544 627 +3 557 4957 556 +3 2522 2527 2525 +3 2457 6361 2544 +3 2609 2544 6361 +3 737 2315 6632 +3 690 737 6632 +3 6572 613 2126 +3 2610 6572 2126 +3 737 2304 2315 +3 2307 558 2478 +3 2539 2610 6324 +3 2475 2531 2837 +3 696 731 697 +3 731 696 684 +3 558 557 2477 +3 556 2477 557 +3 690 2322 6297 +3 2480 2485 2476 +3 551 2480 2476 +3 2315 2485 6632 +3 5598 6632 2485 +3 6632 5598 6538 +3 2503 2479 2504 +3 2525 2527 2459 +3 2525 2459 2401 +3 2522 2525 2344 +3 2510 2509 2524 +3 737 6297 2304 +3 2539 6572 2610 +3 2542 2538 2532 +3 2529 697 731 +3 2475 2611 697 +3 2540 2537 698 +3 530 2834 2540 +3 684 2301 2311 +3 2308 2128 2311 +3 2509 2510 6295 +3 627 2544 2609 +3 2344 2525 2509 +3 5908 2452 5591 +3 5000 6539 2452 +3 2540 2838 2537 +3 2542 2456 2559 +3 2315 2476 2485 +3 2530 2457 2533 +3 987 2533 2457 +3 2837 2531 2537 +3 2838 2837 2537 +3 2302 2301 684 +3 2344 2521 2503 +3 2126 613 2609 +3 2475 2837 2611 +3 2324 2318 2325 +3 2520 5007 2324 +3 2522 5007 2520 +3 2834 530 2836 +3 2304 730 2307 +3 2415 2343 6296 +3 2521 6295 6296 +3 6295 2510 2415 +3 2312 2303 6297 +3 685 730 731 +3 2343 2486 6296 +3 2477 2314 2478 +3 2476 2478 2314 +3 734 735 2826 +3 2301 557 2311 +3 2300 557 2301 +3 685 2307 730 +3 5006 2486 2483 +3 6296 2486 5006 +3 5006 2521 6296 +3 2503 5007 2344 +3 2461 2314 2477 +3 2315 2304 2478 +3 2476 2315 2478 +3 2312 2528 2303 +3 2528 2529 2303 +3 2322 6324 6297 +3 6297 6324 2312 +3 2312 6324 2530 +3 2533 2532 2530 +3 2542 2534 2456 +3 2533 987 2534 +3 2530 6324 2457 +3 2560 2542 2559 +3 2533 2534 2532 +3 2832 530 698 +3 2540 698 530 +3 2834 2838 2540 +3 2528 2531 2475 +3 2312 2531 2528 +3 697 2306 696 +3 2457 2610 6361 +3 2534 987 695 +3 6362 2314 2479 +3 2314 2504 2479 +3 2477 2478 558 +3 558 685 2308 +3 556 4957 2310 +3 2461 2477 556 +3 2832 2554 2828 +3 6527 2874 2852 +3 5644 4802 2821 +3 2852 979 2853 +3 5644 979 2852 +3 5644 2821 979 +3 5644 2852 2825 +3 2825 2852 2874 +3 6527 2852 2853 +3 1811 1821 2298 +3 1811 1814 1821 +3 1820 1810 1815 +3 2298 1821 1822 +3 1817 1822 1820 +3 1821 1820 1822 +3 1821 1814 1820 +3 1816 1808 1817 +3 1808 6558 1817 +3 4835 1331 1810 +3 1810 1820 1814 +3 1815 1816 1817 +3 1822 6558 2298 +3 1808 1819 6558 +3 1331 5450 1815 +3 1816 1815 5450 +3 1810 1331 1815 +3 1815 1817 1820 +3 1817 6558 1822 +3 1809 1819 1808 +3 1808 1816 6684 +3 1808 6684 1825 +3 5463 1866 1781 +3 1866 1825 6684 +3 1866 6684 1781 +3 6603 5450 1331 +3 4835 6603 1331 +3 2258 2257 2267 +3 3800 1426 1414 +3 3778 3827 2267 +3 2258 2267 3827 +3 5819 3600 1414 +3 2258 3600 2257 +3 1412 1411 3455 +3 3800 1414 3818 +3 2257 3600 1411 +3 3800 3818 6487 +3 2257 1411 1412 +3 5819 1426 1413 +3 1414 1426 5819 +3 5819 1413 3825 +3 2267 2257 1412 +3 1411 5819 3825 +3 1411 3600 5819 +3 5867 3455 3825 +3 1411 3825 3455 +3 2267 1412 1410 +3 703 794 814 +3 5242 4544 4612 +3 804 4638 4659 +3 4473 829 6080 +3 5242 4612 4610 +3 804 4659 4658 +3 4658 5374 811 +3 794 4658 811 +3 6042 966 5244 +3 6059 4544 5242 +3 4473 4638 829 +3 4610 814 794 +3 4544 4541 4612 +3 4659 4638 4641 +3 4641 4638 4473 +3 4638 804 829 +3 792 6647 965 +3 4381 2704 917 +3 6059 5242 810 +3 4610 794 5242 +3 794 810 5242 +3 792 793 6647 +3 4391 4381 917 +3 917 957 4391 +3 810 794 811 +3 4404 4415 2704 +3 2704 4415 917 +3 4612 4611 4610 +3 4610 4613 814 +3 4612 4541 4611 +3 4610 4611 4613 +3 4545 6059 810 +3 793 4545 810 +3 793 792 4657 +3 793 4657 4545 +3 4622 965 6647 +3 4646 4404 2704 +3 4611 4541 4560 +3 4283 5244 966 +3 5244 4622 4407 +3 4659 4663 4658 +3 4407 6042 5244 +3 4622 4664 4407 +3 952 4283 966 +3 6097 4659 4641 +3 4666 4663 4659 +3 5244 4283 965 +3 703 804 4658 +3 794 703 4658 +3 4381 952 966 +3 5244 965 4622 +3 811 793 810 +3 957 917 4415 +3 793 4622 6647 +3 2704 4381 4406 +3 4381 6042 4406 +3 4381 966 6042 +3 4664 4663 4407 +3 4646 4406 6096 +3 4407 6096 4406 +3 4664 4622 5374 +3 811 5374 793 +3 5374 4622 793 +3 4646 6096 4666 +3 4407 4406 6042 +3 4659 6097 4666 +3 4646 2704 4406 +3 4407 4663 6096 +3 829 804 703 +3 5374 4658 4663 +3 4664 5374 4663 +3 4663 4666 6096 +3 4403 4303 4302 +3 6270 5247 4403 +3 7065 599 4302 +3 4676 4303 5373 +3 4402 4671 4299 +3 4671 4403 6099 +3 4403 5247 4303 +3 5247 5373 4303 +3 7065 4302 4673 +3 599 6099 4302 +3 4403 4302 6099 +3 4302 4303 4673 +3 6663 4669 6270 +3 5247 6270 4669 +3 6663 6270 5245 +3 4402 4403 4671 +3 4402 6270 4403 +3 4402 5245 6270 +3 5373 5247 4669 +3 4673 4303 2728 +3 4676 5268 2728 +3 4303 4676 2728 +3 4669 6663 6273 +3 4669 6273 5373 +3 6278 5373 6273 +3 5259 6278 5254 +3 6273 5254 6278 +3 6278 5268 4676 +3 4726 5268 6278 +3 6278 4676 5373 +3 6031 961 960 +3 6031 4354 961 +3 4359 6031 960 +3 4354 6031 4359 +3 2908 2909 2910 +3 3902 3888 3867 +3 3902 3867 3868 +3 2908 2910 928 +3 3921 3914 3894 +3 3894 2910 2909 +3 3907 3902 3868 +3 3919 3918 3917 +3 928 3888 2908 +3 3902 2908 3888 +3 3914 3919 3923 +3 3917 3918 3948 +3 3922 3943 3947 +3 3921 3919 3914 +3 3922 3947 3945 +3 2908 3902 3907 +3 3917 3948 6580 +3 3919 6625 3923 +3 3916 3918 3919 +3 3916 3919 3921 +3 3916 3921 3915 +3 3921 3894 3915 +3 3920 3916 3915 +3 3915 3894 2909 +3 3909 3916 3920 +3 2909 3907 3920 +3 2908 3907 2909 +3 2909 3920 3915 +3 3909 933 3916 +3 933 3918 3916 +3 3948 3945 6580 +3 3945 3947 3924 +3 3927 3945 3960 +3 3960 3945 3948 +3 3927 3922 3945 +3 3928 3927 3960 +3 933 3928 3960 +3 3948 3918 933 +3 3948 933 3960 +3 3010 3007 3008 +3 3010 3015 994 +3 3010 3011 3009 +3 3015 3010 3008 +3 995 6784 1036 +3 1037 3015 5658 +3 3015 1037 995 +3 995 994 3015 +3 3010 5690 3011 +3 3009 3011 3013 +3 3007 6457 3008 +3 5690 3010 994 +3 1023 6457 2921 +3 3007 2921 6457 +3 6784 995 1037 +3 5658 3015 3008 +3 3009 3007 3010 +3 5674 6789 3009 +3 3013 5674 3009 +3 3009 6789 3007 +3 3007 6789 2921 +3 5707 1059 994 +3 994 1059 5690 +3 5707 994 995 +3 1060 5707 995 +3 3629 3628 3290 +3 3630 3290 3628 +3 3731 3628 3632 +3 1973 1978 1977 +3 6316 1988 1987 +3 6316 1906 1970 +3 1968 6316 1987 +3 1904 1908 1964 +3 6316 1968 5490 +3 1906 6316 5490 +3 1988 6316 1970 +3 1284 6317 5474 +3 6317 1973 1977 +3 1908 1962 1964 +3 1912 1962 1251 +3 1978 1961 1953 +3 1955 1953 1961 +3 1955 1975 5493 +3 6317 1284 1973 +3 1961 1978 1973 +3 1908 5472 5475 +3 5475 5472 1905 +3 5472 1908 1904 +3 5472 1904 1321 +3 1954 1250 1915 +3 1964 1962 1912 +3 1250 1954 1288 +3 1250 1962 5475 +3 1908 5475 1962 +3 5475 1905 1250 +3 1915 1250 1905 +3 1250 1251 1962 +3 5490 1963 1906 +3 5490 1322 6698 +3 1968 1322 5490 +3 6699 1964 1912 +3 1963 1964 6699 +3 1906 6690 1970 +3 1907 1970 6690 +3 1906 1963 6700 +3 1964 1963 6698 +3 5490 6698 1963 +3 1904 1964 6698 +3 1963 5491 6700 +3 1963 6699 5491 +3 5491 1973 1284 +3 6700 5492 6701 +3 1906 6700 6701 +3 1955 1961 1975 +3 1250 1288 1251 +3 5493 1251 1288 +3 5493 1975 1251 +3 1251 5494 1912 +3 1975 5494 1251 +3 1975 1961 5494 +3 1912 1961 6699 +3 5494 1961 1912 +3 5491 6699 1973 +3 1961 1973 6699 +3 1907 6690 6701 +3 1906 6701 6690 +3 5492 1907 6701 +3 5491 1284 5492 +3 5474 5492 1284 +3 2202 1987 2064 +3 1987 2202 1968 +3 1987 1988 2064 +3 4343 4339 4345 +3 4349 4443 4343 +3 4373 6034 2701 +3 4343 4345 4349 +3 4343 4443 4446 +3 6404 4389 5402 +3 6259 4388 6034 +3 6404 6259 5135 +3 5139 6259 6404 +3 4448 4444 4450 +3 6404 4375 4389 +3 4450 4453 4452 +3 4444 4453 4450 +3 4346 6664 4445 +3 4453 4445 6664 +3 5401 5139 5402 +3 5129 5402 4345 +3 4348 5402 5129 +3 5129 4334 4342 +3 4334 5129 4339 +3 4346 4349 4345 +3 4445 4446 4443 +3 4443 4346 4445 +3 4349 4346 4443 +3 4444 4448 4344 +3 4444 4344 4446 +3 4444 4446 4445 +3 4444 4445 4453 +3 4339 5129 4345 +3 5130 5129 4342 +3 5130 4348 5129 +3 5402 4348 5401 +3 5139 6404 5402 +3 6259 4373 5135 +3 6034 4373 6259 +3 4346 4389 4375 +3 5135 4375 6404 +3 5402 4389 4345 +3 4389 4346 4345 +3 1491 1456 1454 +3 3590 5822 3609 +3 3559 1456 3552 +3 1450 3552 1456 +3 3540 3521 3539 +3 1517 1456 3559 +3 1456 3556 5809 +3 5809 1454 1456 +3 1517 3556 1456 +3 3488 4846 1454 +3 1451 3552 5814 +3 3551 3559 3552 +3 3527 5094 3533 +3 3524 3533 3541 +3 3533 1472 3541 +3 3564 3563 3573 +3 1473 3514 3542 +3 1586 3514 1473 +3 3525 1450 3524 +3 3521 3535 3534 +3 1597 3534 3535 +3 3552 4844 5814 +3 1468 5814 4844 +3 1576 3476 4847 +3 4847 4846 1489 +3 3488 1489 4846 +3 1454 4846 1491 +3 1450 3525 4844 +3 5811 1455 3524 +3 3564 3590 3563 +3 1473 1472 3537 +3 1473 3542 3541 +3 1474 3541 3542 +3 1472 1473 3541 +3 1575 4847 1489 +3 1576 4847 1575 +3 3476 1576 3496 +3 3525 3524 1474 +3 3537 1472 3540 +3 3540 3539 3537 +3 5811 1491 1455 +3 1456 1491 5811 +3 3521 3540 3535 +3 3540 1472 5094 +3 3533 5094 1472 +3 3540 5094 3535 +3 3539 3521 3534 +3 3542 5813 1474 +3 3542 3548 5813 +3 1586 1473 3537 +3 3541 1474 3524 +3 5813 4844 3525 +3 5813 3525 1474 +3 1456 5811 1450 +3 5816 3559 3563 +3 3562 3563 3559 +3 3590 5816 3563 +3 5816 6867 3556 +3 5816 1517 3559 +3 3556 1517 5816 +3 3590 6867 5816 +3 3590 3609 6867 +3 5822 3590 3564 +3 3552 1451 3551 +3 3514 6908 3548 +3 3769 3548 6908 +3 1468 4844 5813 +3 3548 1468 5813 +3 3769 1468 3548 +3 3542 3514 3548 +3 3513 6908 3514 +3 3559 3551 3562 +3 1597 3535 5094 +3 1491 3527 3533 +3 1455 1491 3533 +3 4847 1490 4846 +3 5094 3527 1490 +3 4846 1490 3527 +3 1491 4846 3527 +3 4847 3476 1490 +3 1490 1597 5094 +3 3563 3562 3573 +3 3552 1450 4844 +3 1135 3906 3989 +3 3990 3989 3906 +3 3990 3999 3989 +3 3842 3839 3844 +3 3839 3842 3097 +3 890 2919 3842 +3 3844 890 3842 +3 3097 3842 2919 +3 3173 859 3181 +3 3182 5746 3181 +3 3233 3181 859 +3 3181 3233 3244 +3 860 6634 859 +3 859 6634 861 +3 3233 859 861 +3 3182 3244 6820 +3 3244 6822 6820 +3 861 5745 3244 +3 3233 861 3244 +3 5745 856 6822 +3 3244 5745 6822 +3 3182 3181 3244 +3 860 859 3173 +3 3181 5746 878 +3 3173 3181 878 +3 6760 2636 2652 +3 4258 4256 4257 +3 4257 4191 4258 +3 4256 4258 4198 +3 5994 4188 4185 +3 4191 4189 4258 +3 4198 4258 4189 +3 4188 4198 4189 +3 5994 4198 4188 +3 6795 3055 1026 +3 1026 3026 6795 +3 3026 6785 6795 +3 3347 3363 3354 +3 3354 3344 3347 +3 3368 3649 3404 +3 3344 3434 3347 +3 3363 3346 3354 +3 3363 3347 3650 +3 3374 3347 3434 +3 3346 3343 3354 +3 3345 6839 5778 +3 5778 6839 5779 +3 3350 3352 3351 +3 3352 3350 3349 +3 5779 3343 3351 +3 3350 3351 3343 +3 3350 3343 3346 +3 3349 3350 6840 +3 3349 6840 3358 +3 3375 3347 3374 +3 3427 3429 3374 +3 3429 6847 3374 +3 3427 3374 3434 +3 6847 3417 3374 +3 3375 3374 3417 +3 6850 3344 3354 +3 3343 6850 3354 +3 3372 3344 6850 +3 3371 3427 3434 +3 3344 3372 3434 +3 3371 3434 3372 +3 6850 3343 5779 +3 6850 6839 3372 +3 5779 6839 6850 +3 3358 3649 3368 +3 6885 3361 3368 +3 3368 3361 3358 +3 3350 3346 6840 +3 3358 6840 3649 +3 3346 3649 6840 +3 3363 3404 3649 +3 3346 3363 3649 +3 3650 3404 3363 +3 4026 4018 4015 +3 3976 4026 4015 +3 4015 4018 1142 +3 1616 6608 1401 +3 3047 6640 1187 +3 2920 3047 1187 +3 1186 6640 3047 +3 6790 6640 1185 +3 1186 1185 6640 +3 1599 1463 1610 +3 5609 2552 6754 +3 1063 6754 2552 +3 5667 6797 5669 +3 3605 6874 3606 +3 3605 3606 6500 +3 3802 3464 3462 +3 3799 3464 6916 +3 3799 6487 3464 +3 5932 4029 3932 +3 4523 6057 4468 +3 763 4523 4468 +3 1076 5393 5394 +3 7014 6472 5887 +3 1593 1598 1591 +3 6910 6489 1587 +3 3534 1593 3536 +3 1593 3538 3536 +3 3538 1593 1591 +3 5855 1587 6489 +3 1589 3538 1591 +3 1586 6488 3514 +3 3776 5855 6489 +3 3775 6489 6537 +3 3775 6537 3512 +3 1519 1520 1590 +3 1598 1593 3534 +3 1520 3538 1589 +3 1551 1519 1587 +3 1551 6674 1519 +3 1519 6674 1520 +3 1588 6674 1551 +3 1585 1588 1551 +3 1590 1520 1589 +3 3539 3536 5810 +3 3538 5810 3536 +3 1586 3537 3772 +3 3538 1588 5810 +3 1588 1520 6674 +3 3538 1520 1588 +3 1585 5810 1588 +3 3539 5810 3772 +3 1585 3772 5810 +3 3537 3539 3772 +3 3539 3534 3536 +3 3775 3512 3513 +3 3767 3513 3512 +3 3767 6908 3513 +3 3772 1585 1586 +3 1585 3776 6488 +3 3513 6488 3776 +3 1586 1585 6488 +3 5855 1551 1587 +3 1585 1551 5855 +3 3514 6488 3513 +3 3775 3776 6489 +3 3513 3776 3775 +3 3776 1585 5855 +3 1591 6607 1589 +3 5985 4109 4104 +3 1130 1135 3989 +3 1130 3989 3996 +3 3996 1118 5343 +3 1138 6974 6304 +3 4081 6304 6974 +3 3996 5343 1130 +3 4109 5985 4067 +3 4128 4067 5985 +3 1139 5985 5344 +3 5344 5985 4104 +3 3906 1135 5948 +3 4132 5344 4104 +3 1137 4072 4053 +3 4060 4054 4062 +3 4061 4062 4054 +3 3906 5948 1111 +3 4072 1137 1120 +3 4006 4072 1120 +3 1120 4077 6425 +3 4076 6425 4077 +3 1120 6304 6305 +3 1138 6304 1120 +3 1136 5343 1118 +3 1130 5343 1136 +3 1140 4125 1139 +3 5344 1140 1139 +3 4078 4079 5412 +3 4078 6305 4079 +3 4081 4079 6305 +3 1137 4060 1138 +3 4133 6368 4125 +3 5949 1135 1136 +3 4048 4049 6969 +3 4072 4068 6433 +3 4006 1120 6970 +3 1130 1136 1135 +3 6970 6425 5969 +3 4076 5969 6425 +3 1120 6425 6970 +3 3995 5949 4078 +3 4077 4078 5949 +3 4077 5949 1136 +3 1136 4076 4077 +3 1136 1118 4076 +3 4079 6971 5412 +3 4054 1137 4053 +3 1137 1138 1120 +3 4060 1137 4054 +3 4048 6969 4056 +3 4051 4061 4054 +3 4051 4054 4053 +3 4072 4006 4068 +3 4068 4006 6970 +3 3995 5948 5949 +3 5949 5948 1135 +3 1138 4060 6974 +3 4114 4049 4048 +3 4056 4105 4048 +3 4062 4049 6974 +3 4060 4062 6974 +3 4062 6969 4049 +3 5982 4048 6975 +3 4082 5982 6975 +3 4114 4048 5982 +3 4079 5983 6971 +3 4133 4125 5412 +3 5412 6971 4133 +3 4078 5412 3995 +3 4125 3995 5412 +3 4082 5979 5982 +3 6975 4048 5984 +3 4105 5984 4048 +3 4082 6975 5984 +3 4082 5984 6430 +3 5984 4113 6430 +3 4114 5982 5983 +3 4049 4114 4081 +3 4049 4081 6974 +3 4081 4114 5983 +3 4081 5983 4079 +3 4113 5984 4105 +3 3995 1140 5948 +3 3995 4125 1140 +3 6305 6304 4081 +3 6305 4078 4077 +3 1120 6305 4077 +3 5985 6368 4128 +3 6368 5985 1139 +3 4125 6368 1139 +3 4133 4128 6368 +3 5316 4791 6592 +3 4793 5315 5314 +3 4598 5310 5311 +3 5305 2750 4598 +3 798 5206 5204 +3 4793 772 4792 +3 798 4591 4593 +3 798 5204 4591 +3 4593 4591 5198 +3 4595 4593 5199 +3 5199 4593 5198 +3 4594 5199 5198 +3 4595 5205 4593 +3 5205 798 4593 +3 5211 5210 5205 +3 4601 5210 5211 +3 5308 2750 5305 +3 4537 5305 4598 +3 4792 5311 5310 +3 4598 5311 4537 +3 4793 4792 5312 +3 5199 772 4595 +3 5314 4595 772 +3 4793 5314 772 +3 4594 772 5199 +3 772 4594 5311 +3 4792 772 5311 +3 798 4602 5206 +3 4602 5205 5210 +3 5205 4602 798 +3 5316 5210 4601 +3 5211 5205 5315 +3 5314 5315 5205 +3 5314 5205 4595 +3 1701 5348 1233 +3 1701 1233 5562 +3 1705 5434 1696 +3 5348 1701 5434 +3 5434 1705 6642 +3 5348 5434 6642 +3 1703 2350 5562 +3 5569 2380 2382 +3 2378 2364 5566 +3 528 5566 2364 +3 528 2377 5566 +3 5566 1703 5567 +3 2378 5566 5567 +3 1703 2377 2350 +3 5566 2377 1703 +3 5569 2382 538 +3 2364 2380 5569 +3 528 2364 5569 +3 1039 1041 2979 +3 2986 2973 5677 +3 2975 1039 1040 +3 6781 2934 2967 +3 3078 5676 2975 +3 5680 6779 2917 +3 2986 5677 1196 +3 2973 2986 5679 +3 2986 2965 5679 +3 6779 5680 2931 +3 5680 2917 2990 +3 1040 1039 3017 +3 5679 2965 2954 +3 3078 2975 1040 +3 3078 6518 6519 +3 3065 6519 6518 +3 1040 6518 3078 +3 1041 1039 2975 +3 5680 2990 1199 +3 2964 6525 2962 +3 3034 6519 3065 +3 6618 2986 1196 +3 2965 2986 6618 +3 3065 6518 3017 +3 1040 3017 6518 +3 2953 6525 2955 +3 2964 2955 6525 +3 2976 5677 6778 +3 5676 6778 5677 +3 2973 5676 5677 +3 2975 6779 1041 +3 2983 2985 2917 +3 5677 2976 1196 +3 2964 2967 2934 +3 2964 2934 2955 +3 2975 5676 6780 +3 6780 2917 6779 +3 2975 6780 6779 +3 2984 2917 6780 +3 5679 6781 2973 +3 2934 6781 5679 +3 2954 2955 5679 +3 2934 5679 2955 +3 2984 6782 2917 +3 2983 2917 6782 +3 2984 6780 6781 +3 2973 6781 5676 +3 2967 2984 6781 +3 2967 6782 2984 +3 2953 2955 2954 +3 2972 2982 2983 +3 2985 2983 2982 +3 2917 2985 2990 +3 2967 2972 6782 +3 2972 2983 6782 +3 2967 2964 2972 +3 2962 2972 2964 +3 6778 6519 3034 +3 2976 6778 3034 +3 3078 6519 6778 +3 5676 3078 6778 +3 3629 1498 3732 +3 3628 3629 3632 +3 3725 3628 3731 +3 3757 1224 3732 +3 3632 3629 3732 +3 1227 3733 5848 +3 6624 3732 1498 +3 1223 3732 1224 +3 3732 1223 3632 +3 1224 3757 6354 +3 3733 1227 3632 +3 3630 3628 3725 +3 3630 6491 3631 +3 3291 3631 6491 +3 3725 6491 3630 +3 5847 3725 6497 +3 5845 3727 1223 +3 6354 3757 3740 +3 3757 3732 6624 +3 3642 3291 6491 +3 5847 6901 3642 +3 3725 5847 6491 +3 3642 6491 5847 +3 3731 6497 3725 +3 6901 6497 3733 +3 3727 6901 3733 +3 5847 6497 6901 +3 5845 1223 1224 +3 3632 1223 3733 +3 1223 3727 3733 +3 3757 6624 3740 +3 5220 6670 4627 +3 1538 5413 6670 +3 5413 4627 6670 +3 4586 4626 4578 +3 5213 4580 4441 +3 5220 4578 4569 +3 5154 5213 4441 +3 5383 4569 5186 +3 5383 5186 4441 +3 5219 1538 6670 +3 5220 5219 6670 +3 4627 4586 5220 +3 5220 4586 4578 +3 5186 5154 4441 +3 5190 6671 5212 +3 5213 5190 5212 +3 5213 5212 4580 +3 4580 5212 5225 +3 5190 790 789 +3 5190 789 6671 +3 5220 4569 5219 +3 4441 4580 6266 +3 6266 4580 5225 +3 6266 5225 4457 +3 5383 4441 5224 +3 4569 5383 5224 +3 4441 6266 5224 +3 5226 5225 6671 +3 5212 6671 5225 +3 4457 5225 7062 +3 5224 5227 5219 +3 4569 5224 5219 +3 4457 5227 6266 +3 5224 6266 5227 +3 5219 5227 1538 +3 7062 5227 4457 +3 3469 3475 3496 +3 3475 1640 1637 +3 3472 3471 3466 +3 3470 3466 3471 +3 3469 3470 6851 +3 3471 6852 1639 +3 1639 6851 3471 +3 3470 3471 6851 +3 1612 1637 1640 +3 1640 3475 6851 +3 3469 6851 3475 +3 1639 1640 6851 +3 1612 1640 5802 +3 1639 5802 1640 +3 6853 5802 6852 +3 1639 6852 5802 +3 3477 6853 6852 +3 5802 1624 1612 +3 5802 1422 1624 +3 6852 3471 3472 +3 3477 6852 3472 +3 3470 3469 3466 +3 3477 1420 6853 +3 5802 6853 1422 +3 1420 1422 6853 +3 975 5335 4397 +3 5276 974 5335 +3 976 4397 5335 +3 4729 5276 6413 +3 5335 974 976 +3 5628 5627 2665 +3 5628 2666 5627 +3 2665 2667 5628 +3 4398 5375 976 +3 4397 976 5375 +3 4401 5627 2666 +3 6098 4401 2666 +3 4398 976 6098 +3 6098 2666 4398 +3 5628 2667 2709 +3 2666 2709 4398 +3 5628 2709 2666 +3 976 974 6098 +3 974 6115 6098 +3 6115 4401 6098 +3 4729 6115 974 +3 975 5276 5335 +3 5276 4729 974 +3 3601 3794 3449 +3 5869 3777 3461 +3 3587 3451 1518 +3 3380 5809 3556 +3 3557 3380 3556 +3 3448 6299 3441 +3 3605 3394 3430 +3 3394 3605 6500 +3 3448 3441 3602 +3 1548 1453 6490 +3 3768 3769 1452 +3 3588 517 5820 +3 3505 3504 5097 +3 3440 3420 3441 +3 3763 6490 1453 +3 3430 3588 5820 +3 5098 3562 3505 +3 3439 6299 3530 +3 3594 6299 3439 +3 3444 3601 1425 +3 3427 6629 3429 +3 1532 6645 1533 +3 3419 3420 3421 +3 3431 3422 3430 +3 3433 3422 3431 +3 3437 3365 5795 +3 3438 3365 3437 +3 3366 3365 6849 +3 3438 6849 3365 +3 3490 3491 6854 +3 1453 6645 3763 +3 1532 3763 6645 +3 3490 6854 3380 +3 3561 3566 516 +3 3561 3564 3565 +3 3561 516 3564 +3 3581 3504 3505 +3 3566 3588 516 +3 3588 3603 6863 +3 6863 1518 3588 +3 516 3588 1518 +3 3490 3380 3557 +3 3530 3531 3439 +3 6865 3439 3531 +3 3593 6865 3531 +3 3594 3439 6865 +3 3440 3591 3420 +3 3591 3440 1514 +3 3594 1514 3440 +3 3589 6865 3593 +3 3589 3593 3596 +3 6866 3599 3557 +3 3596 3599 6866 +3 3490 3557 3599 +3 3556 6867 6866 +3 3598 6866 6867 +3 3557 3556 6866 +3 3598 3596 6866 +3 3530 3491 3531 +3 3599 3531 3491 +3 3490 3599 3491 +3 3596 3593 3599 +3 3599 3593 3531 +3 3421 6868 3366 +3 3419 3441 3420 +3 3602 3419 3436 +3 3436 6849 3438 +3 3419 6849 3436 +3 3419 3602 3441 +3 3366 6849 3421 +3 3419 3421 6849 +3 6868 3421 3591 +3 3420 3591 3421 +3 3422 5806 3603 +3 3605 3430 5820 +3 3422 3433 3428 +3 3422 3428 5806 +3 3428 3433 6848 +3 3433 3431 3426 +3 3431 6870 3426 +3 6870 3430 3604 +3 3394 3604 3430 +3 3431 3430 6870 +3 3393 6870 3604 +3 3426 6870 3393 +3 3603 5806 6873 +3 3596 3598 3592 +3 3598 6867 3609 +3 3430 3603 3588 +3 3603 3430 3422 +3 3451 5822 1518 +3 1518 5822 516 +3 3587 6863 6873 +3 3603 6873 6863 +3 1518 6863 3587 +3 5820 6874 3605 +3 5820 517 6874 +3 3762 3761 1531 +3 3760 3551 1531 +3 1451 1531 3551 +3 3581 3765 3568 +3 1533 3568 3761 +3 3765 3761 3568 +3 3581 3568 3504 +3 3761 3765 3764 +3 1531 3761 3764 +3 1532 1533 3762 +3 3761 3762 1533 +3 3764 3765 3581 +3 5854 1531 1451 +3 3762 1531 5854 +3 1451 3770 5854 +3 3763 5854 3768 +3 1468 3768 3770 +3 5854 3770 3768 +3 1532 3762 3763 +3 3768 1468 3769 +3 3763 3762 5854 +3 1452 6490 3768 +3 3763 3768 6490 +3 3448 3601 3449 +3 3448 1425 3601 +3 3448 3602 1425 +3 3364 6917 1425 +3 3602 3364 1425 +3 3436 3364 3602 +3 5868 6917 3364 +3 3436 3438 3364 +3 3821 3823 5869 +3 5869 6918 3777 +3 3823 6918 5869 +3 5869 3461 3821 +3 3437 3777 6918 +3 5868 3438 6918 +3 3437 6918 3438 +3 3823 5868 6918 +3 3364 3438 5868 +3 3437 5795 6919 +3 3437 6919 3777 +3 3777 6919 3792 +3 3823 6917 5868 +3 3821 6917 3823 +3 3595 3530 3449 +3 3530 3448 3449 +3 3440 6299 3594 +3 3365 6629 3427 +3 3764 3760 1531 +3 3551 3760 3562 +3 3764 3581 3760 +3 5097 3565 5098 +3 3573 5098 3565 +3 5822 3564 516 +3 6629 3428 6848 +3 3429 6629 6848 +3 3366 3428 6629 +3 3365 3366 6629 +3 3564 3573 3565 +3 3505 5097 5098 +3 5098 3573 3562 +3 3760 3581 3505 +3 3562 3760 3505 +3 3440 3441 6299 +3 6299 3448 3530 +3 3566 3576 517 +3 3566 517 3588 +3 4013 1148 4014 +3 4013 4014 4026 +3 4014 4018 4026 +3 4019 4014 1148 +3 4018 4014 4019 +3 4823 5177 783 +3 4823 6601 5177 +3 4573 6066 4582 +3 4552 5177 6601 +3 4553 4554 4722 +3 4585 6068 4583 +3 7010 4582 6066 +3 4823 6112 6601 +3 4822 6112 4823 +3 4822 4530 6112 +3 4583 5382 4585 +3 4531 5171 4581 +3 781 4550 4722 +3 5386 6262 4551 +3 4510 6660 5386 +3 4552 5173 5177 +3 4551 5173 4552 +3 4524 5194 5176 +3 783 5176 5194 +3 5415 5262 4579 +3 4510 5386 6063 +3 6063 4551 4552 +3 5386 4551 6063 +3 4554 4510 6063 +3 4583 6068 7010 +3 4581 7010 6068 +3 6069 4584 5382 +3 6069 5382 4583 +3 4576 4583 7010 +3 4581 4573 4582 +3 4584 5415 4585 +3 4585 5415 4579 +3 4582 7010 4581 +3 4531 4581 6068 +3 6068 4585 4579 +3 4579 4531 6068 +3 6072 4722 6063 +3 4554 6063 4722 +3 6072 6063 4552 +3 6112 781 6072 +3 6072 4552 6601 +3 6112 6072 6601 +3 4550 4553 4722 +3 781 4722 6072 +3 783 4822 4823 +3 4822 782 5178 +3 4822 783 782 +3 4531 4530 5171 +3 5262 4530 4531 +3 4551 6262 5173 +3 781 4540 4550 +3 5175 4540 781 +3 5177 5176 783 +3 5176 5177 5173 +3 5176 5173 4524 +3 6262 4524 5173 +3 5178 5171 4530 +3 4822 5178 4530 +3 5382 4584 4585 +3 5178 782 7061 +3 783 5194 782 +3 5175 781 4530 +3 6112 4530 781 +3 5262 5175 4530 +3 4579 5262 4531 +3 1433 3195 3713 +3 3717 3161 3191 +3 3191 3161 5737 +3 3161 3162 5737 +3 3162 3157 5737 +3 3753 3157 3162 +3 3197 3195 3202 +3 3202 6833 3230 +3 3197 3202 3230 +3 3202 5769 6833 +3 3207 5769 3203 +3 3202 3203 5769 +3 6833 3207 3227 +3 5769 3207 6833 +3 3227 5841 3320 +3 3320 5841 3716 +3 3163 6898 3717 +3 3161 3717 6898 +3 3713 6899 1433 +3 3718 3163 3717 +3 3197 3716 3735 +3 3230 6833 3320 +3 3227 3320 6833 +3 3197 3230 3320 +3 3197 3320 3716 +3 3197 3735 3713 +3 3197 3713 3195 +3 3717 3191 6899 +3 3717 6899 3735 +3 3713 3735 6899 +3 3718 3717 3735 +3 3163 3161 6898 +3 3162 3161 3753 +3 6959 918 1176 +3 1169 1174 1176 +3 4031 918 4038 +3 5938 1174 1169 +3 4039 6638 1174 +3 1174 6638 1176 +3 918 6959 4038 +3 6959 1175 3978 +3 4038 6959 3978 +3 6638 4039 6959 +3 1175 6959 4039 +3 1176 6638 6959 +3 3829 3789 3847 +3 3844 3829 3847 +3 1662 1541 1542 +3 1661 1547 1660 +3 1660 1545 1543 +3 1661 1546 1659 +3 1546 1542 1659 +3 1546 1661 1657 +3 1661 1544 1657 +3 1660 1544 1661 +3 1660 1543 1544 +3 1545 1660 1547 +3 1547 1661 1659 +3 1546 1662 1542 +3 2258 1414 3600 +3 970 6035 990 +3 969 990 6035 +3 5341 1083 5886 +3 2618 6459 3090 +3 3533 3524 1455 +3 868 5734 869 +3 3183 869 5734 +3 3183 3228 869 +3 1500 5734 868 +3 5734 1500 6815 +3 6815 3168 1499 +3 1500 3168 6815 +3 6815 1499 6814 +3 5734 6815 6814 +3 3184 5734 6814 +3 3184 3183 5734 +3 4387 4386 932 +3 6037 4387 6995 +3 932 6995 4387 +3 5958 3944 6963 +3 728 6081 6085 +3 1940 1855 1373 +3 2028 1373 1744 +3 1742 1373 1374 +3 2035 1943 1940 +3 1373 2028 1940 +3 2035 1940 2028 +3 1263 1262 1744 +3 1744 1743 1263 +3 1744 1262 2028 +3 1742 1744 1373 +3 1744 1742 1743 +3 5511 1743 1742 +3 5511 1742 2050 +3 2050 4795 5511 +3 1994 5499 2041 +3 1796 2041 5499 +3 4910 4902 6168 +3 4910 6171 4902 +3 6172 6171 4910 +3 6168 4902 6169 +3 6171 1799 6173 +3 6168 6172 4910 +3 1794 6168 6169 +3 6171 6172 4880 +3 6158 6172 6168 +3 1794 6158 6168 +3 6171 4880 1799 +3 2033 1743 2048 +3 1743 2049 1263 +3 2049 2052 2046 +3 2049 2046 1263 +3 1743 5511 2048 +3 2049 1743 2033 +3 4795 2047 2044 +3 4795 2044 5511 +3 2044 2048 5511 +3 1262 2046 5518 +3 1263 2046 1262 +3 2052 2051 2046 +3 2051 5518 2046 +3 6551 2044 2032 +3 6551 2048 2044 +3 2048 2024 2033 +3 2044 5508 2032 +3 2047 5508 2044 +3 2048 6551 2024 +3 1557 5508 2047 +3 4795 1557 2047 +3 5507 2049 2033 +3 2052 2049 5507 +3 5507 2033 2024 +3 2024 6551 1278 +3 3416 1530 1217 +3 6480 5823 3621 +3 1554 1217 1530 +3 5821 3621 5823 +3 6872 5821 5823 +3 6872 3416 1217 +3 6872 1217 5821 +3 1529 1229 1228 +3 1529 1228 3622 +3 3613 1217 1218 +3 1554 1218 1217 +3 1529 5825 1218 +3 3613 1218 5825 +3 1554 1529 1218 +3 5825 1529 3622 +3 1554 1530 1229 +3 1529 1554 1229 +3 3613 3625 1217 +3 5821 1217 3625 +3 3621 5821 3625 +3 3625 3613 6876 +3 6290 4876 1782 +3 586 545 1669 +3 4871 1778 1746 +3 1761 6290 1746 +3 1669 545 1684 +3 541 1675 586 +3 1746 1766 4871 +3 4876 6290 1684 +3 1684 6290 1673 +3 1669 1684 1673 +3 1669 541 586 +3 1668 523 542 +3 1669 1673 6681 +3 1782 4876 1766 +3 1766 1783 4871 +3 4871 1783 1364 +3 542 1675 541 +3 1669 6681 541 +3 542 541 6681 +3 542 6681 1668 +3 1668 6681 1673 +3 1668 1673 1761 +3 1746 1782 1766 +3 1761 1673 6290 +3 6290 1782 1746 +3 1746 1778 1761 +3 3508 6856 6571 +3 3515 6856 3508 +3 3515 3626 6856 +3 3579 3626 3510 +3 3515 3510 3626 +3 1290 6927 6378 +3 3141 3121 925 +3 1168 919 3151 +3 3151 919 1151 +3 4071 4005 5987 +3 5125 651 5406 +3 5141 5142 5158 +3 672 1091 2678 +3 672 2678 4400 +3 650 1091 672 +3 1115 5989 4130 +3 1115 4130 5988 +3 1115 4065 5989 +3 4065 1115 5967 +3 4136 5988 4130 +3 5967 6972 6973 +3 5972 6973 6972 +3 6972 5967 5988 +3 1115 5988 5967 +3 5989 4065 5975 +3 4088 5975 4065 +3 4137 4088 6576 +3 4065 5967 4075 +3 4159 1080 1081 +3 1081 656 4159 +3 4246 4159 656 +3 4247 1080 4159 +3 6132 4832 4833 +3 1291 7040 4833 +3 3484 3474 3423 +3 3474 3473 3423 +3 3522 3547 3520 +3 3522 3509 3484 +3 3509 3522 3510 +3 3520 3510 3522 +3 3522 3423 3547 +3 3484 3423 3522 +3 1307 2183 4833 +3 3507 3492 5807 +3 6132 4833 7040 +3 4833 2183 1291 +3 3509 3510 3515 +3 3508 3509 3515 +3 3509 3508 5807 +3 3492 3484 5807 +3 3492 3507 3511 +3 4831 4832 6132 +3 1307 4832 6365 +3 4832 1307 4833 +3 6257 3473 3474 +3 6257 5092 3473 +3 4832 1292 6365 +3 1292 4830 6365 +3 6365 1299 1307 +3 3509 5807 3484 +3 3484 3492 3474 +3 6417 3473 5092 +3 6417 2184 3473 +3 6416 1291 2183 +3 1291 6416 6417 +3 2184 6417 6416 +3 1299 6365 1300 +3 4930 1347 1300 +3 1347 4930 6183 +3 4832 4831 1292 +3 1300 1347 2160 +3 2174 1300 2160 +3 1299 1300 2174 +3 1291 7041 7040 +3 4830 6183 4930 +3 1291 6417 7041 +3 5092 7041 6417 +3 6365 4830 1300 +3 1300 4830 4930 +3 4911 1873 4907 +3 1796 5447 1800 +3 6154 6155 6156 +3 1796 5499 5447 +3 1800 5447 5446 +3 5510 5499 1994 +3 6593 4907 1873 +3 1800 5446 1798 +3 4967 1798 5446 +3 1794 4911 4907 +3 4880 6156 6155 +3 4907 6593 1792 +3 5446 5447 6683 +3 1799 6683 5447 +3 4967 5446 6683 +3 5499 6173 5447 +3 1799 5447 6173 +3 5510 6173 5499 +3 4907 6948 1794 +3 4908 6948 4907 +3 4881 6157 6156 +3 6154 6156 6157 +3 4880 6155 1799 +3 6155 6154 4882 +3 6156 6158 4881 +3 1794 4881 6158 +3 4881 6167 6157 +3 6167 4881 6948 +3 1794 6948 4881 +3 4908 6167 6948 +3 4880 6172 6156 +3 6158 6156 6172 +3 6683 7053 4967 +3 6155 7053 6683 +3 6155 6683 1799 +3 6155 4882 7053 +3 1231 1230 1981 +3 4813 5088 3384 +3 3384 6254 1459 +3 6254 3384 5088 +3 1457 1459 6254 +3 1439 1440 4813 +3 3376 1457 6254 +3 4813 5087 5088 +3 5087 4813 1440 +3 1459 1458 3424 +3 3424 2184 1459 +3 3423 3424 3425 +3 3424 3423 3473 +3 3423 3425 3547 +3 5823 3520 3547 +3 6872 5823 3547 +3 6872 3547 3425 +3 6872 3425 3416 +3 3629 3731 1498 +3 3731 1227 1498 +3 3629 3290 3731 +3 907 881 3830 +3 3272 1439 4804 +3 3734 5848 3731 +3 3734 5853 5848 +3 1227 5848 5853 +3 4907 1792 4908 +3 5925 4901 1777 +3 5925 1858 4901 +3 4898 4899 4901 +3 1777 4901 4899 +3 3201 3155 3166 +3 3165 3166 3750 +3 3155 3750 3166 +3 3750 3155 3154 +3 3750 3154 3752 +3 1484 1633 1603 +3 5420 1516 1583 +3 6438 6306 1564 +3 1566 6438 1564 +3 1578 1565 6306 +3 1564 6306 1565 +3 6587 1578 6306 +3 1574 6587 6306 +3 1516 1578 6587 +3 1574 6306 6438 +3 1569 6672 6587 +3 1516 6587 6672 +3 6587 1574 1569 +3 6438 5419 1574 +3 5420 1578 1516 +3 1578 5420 1629 +3 1565 1578 1629 +3 1629 5420 5430 +3 1583 5430 5420 +3 1577 5430 1583 +3 1628 1629 1550 +3 1549 1550 1629 +3 1603 1628 1550 +3 1628 1565 1629 +3 1633 1628 1603 +3 1628 1633 1565 +3 1565 1633 1564 +3 1577 1549 5430 +3 1549 1629 5430 +3 1566 1478 4852 +3 1478 1566 4853 +3 1633 1484 1564 +3 1566 5419 6438 +3 1566 4852 5419 +3 4853 1564 1484 +3 4853 1566 1564 +3 5961 4029 3930 +3 3405 1441 4923 +3 2105 4923 1441 +3 2065 2068 2070 +3 2022 1281 2023 +3 2072 2073 2029 +3 5517 1261 2059 +3 5517 2035 1261 +3 5518 1261 1262 +3 2029 1929 2072 +3 1937 2070 2068 +3 2029 2025 1928 +3 1786 2068 2065 +3 2022 2023 2025 +3 2022 2025 2029 +3 2073 2059 2034 +3 2072 2059 2073 +3 1265 1280 1278 +3 2030 6446 2052 +3 2051 2052 6446 +3 2034 2051 6446 +3 2065 2070 2071 +3 2069 2071 2070 +3 2034 6446 2027 +3 1650 2027 6446 +3 1650 2030 1280 +3 2031 1265 1264 +3 2030 2052 5507 +3 2071 2056 2065 +3 1280 2024 1278 +3 1279 1650 1280 +3 2022 2027 6705 +3 1279 2027 1650 +3 2021 6705 1279 +3 2027 1279 6705 +3 2031 1280 1265 +3 2021 1279 2031 +3 1279 1280 2031 +3 2022 6705 2021 +3 2021 2031 1264 +3 1264 1281 2021 +3 2022 2021 1281 +3 6707 2055 1929 +3 5512 2055 6707 +3 1928 2025 1266 +3 1266 2025 2023 +3 2066 5512 1785 +3 1937 2068 2067 +3 1786 2067 2068 +3 5512 6707 1785 +3 2066 1786 5512 +3 2066 1785 1853 +3 1919 2067 1856 +3 1919 1937 2067 +3 2066 1856 2067 +3 2066 2067 1786 +3 2066 1853 1856 +3 1786 2065 5516 +3 2056 5516 2065 +3 1786 5516 5512 +3 5512 5516 2055 +3 2055 2072 1929 +3 2072 2055 2056 +3 5516 2056 2055 +3 5517 2056 2071 +3 5517 2071 1943 +3 1943 2071 2069 +3 2072 2056 2059 +3 2059 2056 5517 +3 2035 5517 1943 +3 2029 1928 1929 +3 2034 2059 1261 +3 2073 2022 2029 +3 2034 2027 2073 +3 2022 2073 2027 +3 2030 1650 6446 +3 5507 2024 2030 +3 1261 5518 2034 +3 2034 5518 2051 +3 1280 2030 2024 +3 1804 2399 2364 +3 2373 2391 2383 +3 2398 2373 4974 +3 5568 2399 2381 +3 2399 5568 2364 +3 2380 2364 5568 +3 2380 6744 2382 +3 2379 5568 2381 +3 5568 2379 2380 +3 1804 2364 2378 +3 4974 6744 2398 +3 2379 2398 6744 +3 2379 6744 2380 +3 2373 2383 4974 +3 2382 6744 4974 +3 3465 3801 3467 +3 5804 3467 3482 +3 3467 5864 3465 +3 6487 3816 3800 +3 3442 5797 5796 +3 3472 3468 1421 +3 1575 1489 3480 +3 3801 3809 3482 +3 3488 3480 1489 +3 1454 5809 3380 +3 3801 3482 3467 +3 3468 3466 1445 +3 3488 1618 3480 +3 3488 6501 1618 +3 3379 1618 6501 +3 1454 6501 3488 +3 5865 3801 3465 +3 1446 1445 6342 +3 3469 6342 1445 +3 1575 6292 6342 +3 1575 6341 1576 +3 3472 3466 3468 +3 3813 3483 3809 +3 3483 1447 3482 +3 5362 1447 5803 +3 1446 5803 1447 +3 5427 5428 3379 +3 5427 1617 5428 +3 1618 3379 5428 +3 5796 5797 5428 +3 1618 5428 5797 +3 5428 1617 5796 +3 5362 5803 5797 +3 5803 1618 5797 +3 5797 3442 5362 +3 3480 5803 1446 +3 3466 3469 1445 +3 1446 1447 1445 +3 5804 3482 5362 +3 1447 5362 3482 +3 3442 5804 5362 +3 5803 3480 1618 +3 3379 6854 5427 +3 6341 3496 1576 +3 6854 6501 3380 +3 3379 6501 6854 +3 1454 3380 6501 +3 3800 5865 1415 +3 3481 1415 5865 +3 3799 3804 5863 +3 5863 3483 3813 +3 3799 5863 3813 +3 3483 3482 3809 +3 3483 3468 1447 +3 1445 1447 3468 +3 5804 5864 3467 +3 3799 3813 3816 +3 3801 3813 3809 +3 3801 3816 3813 +3 5865 3816 3801 +3 3800 3816 5865 +3 3468 3483 1421 +3 3481 5865 3465 +3 3799 6916 3804 +3 3799 3816 6487 +3 3480 6292 1575 +3 6292 3480 1446 +3 6292 1446 6342 +3 1575 6342 6341 +3 6341 6342 3496 +3 3469 3496 6342 +3 3478 1423 1420 +3 1422 5361 1624 +3 1422 1420 1423 +3 1420 3812 3478 +3 3805 3808 1622 +3 1423 5361 1422 +3 1423 6913 5361 +3 3808 5361 6913 +3 1651 3808 3805 +3 1623 3812 1428 +3 1423 3812 1623 +3 1622 3808 6913 +3 1622 6913 1423 +3 6357 1623 1428 +3 1622 1623 6357 +3 1622 1423 1623 +3 3478 3812 1423 +3 3805 1622 6357 +3 1957 2223 1315 +3 2225 1315 2223 +3 1958 1960 1959 +3 1886 1960 1958 +3 6739 1957 1315 +3 1886 1322 1960 +3 1321 1904 1322 +3 1968 1960 1322 +3 1322 1886 1321 +3 1957 1903 1956 +3 1322 1904 6698 +3 2200 6708 2064 +3 2202 2064 6708 +3 2062 5534 2063 +3 1959 1960 1971 +3 1969 1971 6708 +3 2200 1969 6708 +3 1971 2202 6708 +3 2169 2200 6723 +3 2200 2064 6723 +3 1971 1968 2202 +3 1971 1960 1968 +3 2063 1969 5533 +3 5533 1969 2200 +3 1959 6724 1958 +3 5534 6724 1959 +3 1959 1971 1969 +3 2063 5534 1969 +3 5534 1959 1969 +3 1956 6724 2062 +3 1903 6724 1956 +3 2062 6724 5534 +3 5533 2200 2169 +3 5533 2169 2199 +3 2207 2188 2063 +3 2199 2063 5533 +3 2207 2063 2199 +3 1956 2062 2210 +3 5537 2210 2062 +3 2062 2063 5537 +3 2188 5537 2063 +3 2188 2207 2219 +3 2204 2219 2207 +3 2204 2213 2219 +3 2223 1956 2210 +3 1903 2224 1958 +3 5471 1958 2224 +3 1903 1958 6724 +3 5471 1321 1958 +3 1886 1958 1321 +3 5537 2219 2210 +3 2213 6543 2219 +3 2210 2219 6543 +3 2219 5537 2188 +3 2223 2210 6543 +3 2224 1903 1957 +3 1957 1956 2223 +3 6739 5553 2224 +3 1957 6739 2224 +3 1780 5462 1871 +3 5462 1780 5463 +3 1865 1871 5462 +3 1368 1360 1865 +3 1369 1871 1865 +3 1369 1865 1360 +3 1368 6443 1360 +3 4565 5208 5365 +3 5203 5365 6659 +3 4565 5365 5203 +3 5099 3360 5085 +3 3337 3336 3325 +3 3336 3352 3325 +3 3337 3325 6838 +3 3326 3337 6838 +3 3339 6838 3325 +3 3358 1511 3349 +3 5782 3339 1511 +3 1512 1511 3362 +3 3361 3362 1511 +3 1511 1512 5782 +3 5782 3334 3339 +3 3334 6838 3339 +3 3339 3349 1511 +3 3339 3325 3349 +3 3325 3352 3349 +3 3361 1511 3358 +3 3362 5099 1512 +3 5085 5782 1512 +3 5099 5085 1512 +3 5085 6929 5782 +3 5782 6929 3334 +3 5423 1569 1515 +3 1515 1574 1573 +3 1515 1569 1574 +3 5423 1515 1573 +3 4567 765 4566 +3 4465 5203 5192 +3 5192 4566 4465 +3 4566 800 4567 +3 800 4566 5192 +3 800 4556 4567 +3 4567 4556 765 +3 2265 1297 2266 +3 2258 3828 1414 +3 3828 2258 3827 +3 2265 3796 1297 +3 2266 3818 2265 +3 1414 3828 3818 +3 3796 3828 3827 +3 3796 2265 3828 +3 3818 3828 2265 +3 1294 6450 5531 +3 5530 6721 6722 +3 5530 1294 5531 +3 5531 6721 5530 +3 5531 6450 6721 +3 5530 5538 1294 +3 5538 5530 6722 +3 3785 3682 3179 +3 3692 3179 3682 +3 3787 3682 3785 +3 3790 3787 3785 +3 3785 3179 3790 +3 5127 5133 5126 +3 5127 5126 6279 +3 5260 5398 6280 +3 5126 5398 6279 +3 5260 6279 5398 +3 5127 6279 4699 +3 5266 5260 6280 +3 6279 5260 5266 +3 5266 4699 6279 +3 562 560 561 +3 2487 2491 2484 +3 6933 561 5907 +3 5907 561 2462 +3 2487 2484 6932 +3 6933 562 561 +3 6932 5907 2487 +3 2500 5599 6933 +3 2480 2484 6753 +3 2484 2491 2469 +3 2472 2469 2491 +3 562 6933 5599 +3 5594 6932 2484 +3 2505 562 5599 +3 6753 2464 2480 +3 2462 2487 5907 +3 6536 562 2505 +3 6753 2468 2464 +3 2486 2500 2490 +3 2490 5594 2483 +3 2483 5594 2480 +3 2480 5594 2484 +3 2490 6932 5594 +3 6932 2490 6933 +3 2500 6933 2490 +3 5907 6932 6933 +3 2483 2486 2490 +3 2227 1318 5553 +3 2231 1318 2227 +3 2292 1318 2231 +3 6739 1315 2227 +3 1318 6691 5553 +3 2292 1356 5469 +3 1895 5469 1901 +3 5469 1895 2292 +3 1318 2292 1895 +3 2227 5553 6739 +3 2872 2904 2851 +3 2903 2851 2904 +3 1945 5487 6550 +3 5487 1945 1944 +3 1928 1266 2026 +3 2058 2017 1944 +3 2060 1853 1854 +3 1852 1936 1935 +3 1944 2017 5487 +3 2026 1266 1854 +3 1935 2060 1852 +3 2026 1785 1928 +3 1254 2016 6550 +3 2019 1854 1266 +3 1945 6550 2016 +3 1854 2019 2058 +3 1255 6550 5487 +3 2058 1944 1852 +3 6547 1257 1270 +3 6548 1254 6549 +3 1255 1254 6550 +3 1254 6548 2016 +3 1274 6643 1281 +3 1313 1965 1948 +3 1950 1945 1946 +3 1313 1950 1946 +3 1946 1967 1313 +3 1946 1945 2016 +3 2023 1281 6643 +3 1274 2023 6643 +3 1257 2017 2019 +3 2057 2019 2017 +3 1257 1266 1274 +3 1270 1257 1274 +3 1946 2016 1967 +3 1967 6548 1642 +3 2016 6548 1967 +3 1785 6707 1928 +3 1929 1928 6707 +3 2058 2019 2057 +3 1257 2019 1266 +3 1274 1266 2023 +3 1852 2060 1854 +3 2058 1852 1854 +3 1257 6547 2017 +3 5487 2017 6547 +3 1944 1936 1852 +3 1950 1936 1944 +3 2017 2058 2057 +3 1313 1948 1950 +3 1950 1944 1945 +3 1313 1642 1965 +3 1967 1642 1313 +3 1785 2026 1853 +3 1854 1853 2026 +3 3974 3150 1124 +3 1915 1911 5489 +3 5489 1911 5488 +3 1954 5489 5488 +3 1954 5488 1951 +3 1915 5489 1954 +3 3826 3821 3455 +3 5864 3446 3447 +3 3443 3795 3445 +3 3485 3446 3486 +3 1617 3486 5796 +3 3486 3446 5796 +3 3442 5796 3446 +3 3485 3794 3601 +3 3601 3444 3485 +3 6917 3445 5858 +3 3442 3446 5804 +3 3446 3485 3447 +3 3795 3447 3444 +3 3444 5858 3795 +3 3445 3795 5858 +3 3444 3447 3485 +3 3794 3485 6912 +3 5804 3446 5864 +3 3443 3447 3795 +3 1425 6917 5858 +3 1425 5858 3444 +3 6917 3821 3826 +3 3445 6917 3826 +3 3826 5867 3445 +3 5867 3443 3445 +3 6720 1989 1988 +3 1991 5497 1972 +3 6720 1988 1970 +3 5497 1970 1972 +3 1989 2201 2170 +3 1409 2170 2201 +3 2064 1989 2170 +3 1970 5497 6720 +3 1989 6720 1991 +3 5497 1991 6720 +3 1409 1403 2198 +3 2170 1409 2198 +3 1409 1303 1403 +3 2169 2198 5532 +3 2198 1403 5532 +3 1409 2201 1303 +3 2064 1988 1989 +3 6723 2064 2170 +3 6723 2198 2169 +3 2170 2198 6723 +3 3351 5781 5778 +3 5778 5779 3351 +3 4031 5963 1146 +3 5952 1146 5963 +3 5963 4031 4038 +3 4027 5952 4007 +3 4013 4027 4028 +3 4026 4027 4013 +3 4026 1147 4027 +3 1146 4027 1147 +3 4035 4007 5952 +3 5963 4035 5952 +3 5952 4027 1146 +3 4027 4007 4028 +3 4035 3978 4037 +3 4035 4037 4007 +3 4038 4035 5963 +3 4038 3978 4035 +3 3770 1451 5814 +3 3770 5814 1468 +3 1369 6439 1871 +3 5811 3524 1450 +3 1610 1463 1616 +3 1914 5476 1325 +3 4438 7035 4600 +3 5259 5254 6277 +3 6277 6276 4699 +3 5254 6276 6277 +3 5259 5266 5267 +3 6277 4699 5266 +3 6277 5266 5259 +3 6224 6745 2355 +3 6224 4970 6745 +3 6224 4849 4970 +3 4973 4886 1537 +3 6941 2356 6745 +3 4970 6941 6745 +3 4972 2356 6941 +3 1537 6941 4970 +3 6143 4848 6142 +3 4848 4849 6142 +3 4850 6143 6142 +3 6144 4850 6142 +3 4849 6144 6142 +3 6145 6146 6143 +3 6145 7037 6146 +3 6143 7038 4848 +3 6146 7038 6143 +3 4850 6145 6143 +3 4886 6161 6160 +3 6161 6146 6160 +3 1536 6160 6146 +3 7037 1536 6146 +3 1448 6144 2355 +3 6224 2355 6144 +3 4849 6224 6144 +3 1537 4970 4849 +3 1537 4972 6941 +3 6161 4973 7038 +3 4848 7038 4973 +3 4973 6161 4886 +3 4973 1537 4849 +3 4848 4973 4849 +3 6161 7038 6146 +3 1448 4841 4850 +3 4841 6219 4850 +3 1448 4850 6144 +3 5500 1282 1646 +3 1647 6702 5503 +3 1646 5503 6702 +3 5503 1998 1654 +3 5503 1646 1998 +3 1647 5503 1654 +3 1998 1979 1654 +3 2012 1998 1282 +3 1979 1998 2012 +3 1998 1646 1282 +3 1646 6702 5500 +3 1495 5831 6502 +3 1496 6502 5831 +3 3338 3313 5771 +3 6502 1496 3313 +3 3313 3338 6502 +3 1495 6502 3396 +3 3338 3396 6502 +3 3452 3451 3587 +3 6465 3592 3608 +3 6465 3608 3452 +3 3451 3452 3608 +3 3452 3558 6465 +3 3452 3587 3558 +3 1513 6464 5815 +3 3589 5815 6464 +3 3587 1513 5815 +3 3558 3587 5815 +3 3589 3596 3558 +3 3589 3558 5815 +3 3592 6465 3596 +3 3558 3596 6465 +3 3451 3608 5822 +3 3587 6873 1513 +3 1415 1426 3800 +3 3481 1413 1415 +3 3825 1413 3824 +3 5864 6469 3465 +3 1426 1415 1413 +3 3824 3481 6469 +3 3465 6469 3481 +3 5801 6504 6469 +3 3824 6469 6504 +3 3443 6504 5801 +3 1413 3481 3824 +3 5801 3447 3443 +3 3824 6504 3825 +3 3443 5867 6504 +3 3825 6504 5867 +3 5801 6469 5864 +3 5864 3447 5801 +3 3476 3496 3475 +3 1402 1611 1401 +3 3476 3475 1637 +3 5425 6415 1424 +3 1611 5425 1424 +3 1611 1424 1418 +3 1609 1419 6559 +3 1402 1419 5425 +3 1611 1402 5425 +3 1419 1599 6559 +3 1609 6559 5424 +3 1625 1609 6675 +3 5425 1419 1605 +3 1612 1605 1609 +3 1609 1605 1419 +3 1624 6676 1612 +3 1612 6676 1605 +3 5425 1605 6676 +3 1625 1612 1609 +3 1625 3479 1637 +3 1611 1464 1614 +3 1401 1611 1614 +3 1611 1418 1464 +3 1637 1612 1625 +3 3479 1638 5805 +3 1615 5805 1638 +3 1597 5805 1615 +3 1625 6675 1638 +3 5426 1638 6675 +3 1615 1638 5426 +3 5805 3489 3479 +3 1638 3479 1625 +3 1418 3808 1651 +3 1418 1651 1464 +3 1424 5361 3808 +3 1418 1424 3808 +3 6415 6676 1624 +3 5425 6676 6415 +3 1424 6415 5361 +3 1624 5361 6415 +3 1490 5805 1597 +3 3476 3489 1490 +3 3479 3489 1637 +3 3476 1637 3489 +3 3489 5805 1490 +3 1386 1836 1827 +3 1301 6719 2179 +3 5676 6781 6780 +3 5903 5017 2596 +3 6234 2574 5898 +3 2411 2427 2410 +3 2429 2629 2428 +3 2429 5681 2629 +3 3276 3279 512 +3 5027 5025 6234 +3 5028 6234 5898 +3 7054 5077 2574 +3 4989 4988 2425 +3 5898 2574 5899 +3 5076 5899 5892 +3 5017 7055 6227 +3 2422 2410 4988 +3 5681 2625 3080 +3 2957 2956 2953 +3 2424 2410 2441 +3 2606 5617 2607 +3 2410 2427 5578 +3 2424 4988 2410 +3 1033 2960 2961 +3 7054 5903 5077 +3 5037 6229 5024 +3 5025 5024 6229 +3 2596 5077 5903 +3 2958 2962 5670 +3 2416 2418 2422 +3 2423 2416 2422 +3 2411 5574 2427 +3 6505 3279 3276 +3 6234 5028 5027 +3 2574 5077 5899 +3 5899 2625 5892 +3 5077 2625 5899 +3 5682 5681 2429 +3 2411 2410 2422 +3 2423 2417 2416 +3 2425 4988 2424 +3 6229 7054 2574 +3 2602 6400 2597 +3 5670 2962 6525 +3 5682 2429 1033 +3 3276 6622 6505 +3 1214 6505 6622 +3 3278 6622 3276 +3 6513 1033 2961 +3 5578 2436 5579 +3 2423 568 2417 +3 4988 568 2422 +3 2423 2422 568 +3 5574 2411 2418 +3 2416 6482 2418 +3 2418 6482 6567 +3 2410 5578 2441 +3 2411 2422 2418 +3 2607 2426 5616 +3 5618 5617 2606 +3 5030 5617 5618 +3 2607 2608 2605 +3 2607 5616 2608 +3 2424 5622 2425 +3 2424 2441 5622 +3 5579 5622 5578 +3 5578 5622 2441 +3 3081 2956 2957 +3 5670 3081 6513 +3 2958 5670 6513 +3 3081 5670 2956 +3 2959 6776 2428 +3 2958 2961 5671 +3 5671 2961 2960 +3 5670 6525 2956 +3 2956 6525 2953 +3 5681 5682 5892 +3 5683 5892 5682 +3 5683 5682 1031 +3 2625 5681 5892 +3 2962 2958 5671 +3 2995 2962 5671 +3 5671 6776 2995 +3 2959 2995 6776 +3 2428 6776 2960 +3 5671 2960 6776 +3 2428 2960 2429 +3 1033 2429 2960 +3 2958 6513 2961 +3 3277 6827 6622 +3 1214 6622 6827 +3 3278 3277 6622 +3 5892 5683 5076 +3 5065 5898 5076 +3 5899 5076 5898 +3 2606 2607 5027 +3 5027 2607 2605 +3 5030 2426 5617 +3 5617 2426 2607 +3 5616 2426 4989 +3 5037 6423 6400 +3 5016 5037 6400 +3 2425 5616 4989 +3 4989 2426 568 +3 4988 4989 568 +3 5903 7054 7055 +3 6228 7055 7054 +3 7054 6229 5037 +3 6228 7054 5037 +3 5017 5903 7055 +3 5016 6230 6227 +3 2574 6234 6229 +3 5025 6229 6234 +3 5024 5025 2605 +3 5027 2605 5025 +3 5026 5030 5618 +3 5037 5024 5900 +3 2597 6423 5900 +3 5037 5900 6423 +3 5016 6228 5037 +3 6227 6228 5016 +3 5028 5898 5065 +3 5027 5028 2606 +3 6400 6423 2597 +3 544 559 543 +3 1396 1380 1681 +3 1380 4895 1681 +3 4895 1399 1681 +3 1396 1681 544 +3 1681 1399 544 +3 1396 1857 1380 +3 523 544 543 +3 1667 542 543 +3 523 543 542 +3 1675 542 1667 +3 559 1667 543 +3 523 1396 544 +3 1680 1399 4895 +3 1680 4895 6165 +3 580 1694 6308 +3 1689 4855 1687 +3 1694 1692 6308 +3 1687 4855 1690 +3 1690 4855 1688 +3 585 6308 1690 +3 1692 1690 6308 +3 1751 1750 6310 +3 2629 2624 2993 +3 5565 2362 1713 +3 1713 2362 6323 +3 2371 2357 1712 +3 529 538 539 +3 573 529 539 +3 5570 2388 4980 +3 5909 5570 4980 +3 6396 6476 2075 +3 2367 6396 2075 +3 4968 6476 6396 +3 2352 2361 2074 +3 4985 4980 2389 +3 1537 4886 4971 +3 571 5565 570 +3 2362 5565 571 +3 570 5565 4856 +3 1713 2372 5565 +3 2074 6589 2075 +3 528 529 2376 +3 571 570 572 +3 6323 2363 573 +3 1713 1712 2372 +3 2359 2075 6589 +3 4972 2357 2356 +3 2357 2371 2356 +3 2361 2356 2370 +3 2371 2370 2356 +3 1708 570 4856 +3 4856 2372 574 +3 2350 6746 572 +3 571 572 6746 +3 2362 2375 2363 +3 573 2363 529 +3 2375 529 2363 +3 2362 571 2375 +3 2375 571 6746 +3 6746 2350 2377 +3 2375 6746 2377 +3 2376 2375 2377 +3 2375 2376 529 +3 529 5569 538 +3 529 528 5569 +3 528 2376 2377 +3 2383 2391 6748 +3 4969 2359 6934 +3 6934 6589 573 +3 2359 6589 6934 +3 4978 2367 2359 +3 2359 2367 2075 +3 4968 2352 6476 +3 6476 2074 2075 +3 2352 2074 6476 +3 4977 2383 6940 +3 2366 2386 2391 +3 2391 2386 6748 +3 2386 2366 4979 +3 2365 6940 6748 +3 2383 6748 6940 +3 2386 2365 6748 +3 5909 2397 5570 +3 5565 2372 4856 +3 2363 6323 2362 +3 574 1708 4856 +3 576 1708 574 +3 1712 1713 2371 +3 2370 2371 1713 +3 4971 4972 1537 +3 576 1712 1802 +3 1712 576 574 +3 1713 2053 2370 +3 4971 4886 1802 +3 1712 574 2372 +3 4969 6942 2359 +3 2365 2359 6942 +3 539 4969 6934 +3 573 539 6934 +3 4969 4975 6942 +3 538 2382 4976 +3 4974 4976 2382 +3 4976 4975 538 +3 539 538 4975 +3 4977 4976 4974 +3 2383 4977 4974 +3 4975 6940 6942 +3 2365 6942 6940 +3 4977 6940 4975 +3 539 4975 4969 +3 4976 4977 4975 +3 2365 2386 4978 +3 4978 2386 4979 +3 4978 4979 4984 +3 4979 2397 4984 +3 2365 4978 2359 +3 2367 4978 4984 +3 4985 4984 2397 +3 2367 4984 4985 +3 4985 5909 4980 +3 4985 2397 5909 +3 2367 4985 6396 +3 4972 4971 2357 +3 4971 1712 2357 +3 4985 2389 6396 +3 4971 1802 1712 +3 6323 6589 2053 +3 2074 2053 6589 +3 573 6589 6323 +3 2053 1713 6323 +3 2361 2053 2074 +3 2053 2361 2370 +3 6223 2352 4968 +3 2389 6223 4968 +3 6396 2389 4968 +3 4959 6223 2389 +3 4959 2389 4980 +3 7066 4914 6366 +3 1827 1393 1386 +3 1386 1393 1394 +3 1762 1858 1776 +3 4914 7066 1924 +3 1776 1777 4897 +3 6315 1925 1260 +3 7066 1931 1924 +3 5360 5482 1932 +3 1926 6695 1921 +3 1927 1246 1382 +3 1327 1383 5351 +3 1758 1858 1762 +3 1762 1776 1860 +3 1384 5351 1383 +3 1897 5360 1932 +3 1393 1932 5482 +3 1393 5482 1394 +3 1835 5453 1836 +3 1930 6366 4914 +3 1383 1371 1384 +3 1897 5351 1384 +3 1831 1386 1394 +3 5481 6555 1387 +3 1922 1260 1925 +3 5925 1776 1858 +3 1859 1857 5457 +3 5481 1758 6555 +3 1394 5482 5481 +3 4897 1859 1776 +3 1922 1925 5484 +3 1245 1382 1260 +3 1246 1260 1382 +3 1762 1387 6555 +3 1394 1387 1831 +3 5481 1387 1394 +3 1383 6568 1382 +3 4914 1924 522 +3 6315 522 1924 +3 1384 1371 1381 +3 1776 5925 1777 +3 1260 1246 6315 +3 1836 1386 1835 +3 1831 1835 1386 +3 4914 522 1930 +3 521 1930 522 +3 6315 1246 1921 +3 6315 1921 522 +3 1384 1381 5360 +3 521 1655 5486 +3 1860 5457 1682 +3 1776 5457 1860 +3 1762 6555 1758 +3 1383 1327 6568 +3 1918 6694 1922 +3 1260 1922 6694 +3 6694 1245 1260 +3 1245 1383 1382 +3 1246 1926 1921 +3 1927 1926 1246 +3 1384 5360 1897 +3 5484 1918 1922 +3 1924 1685 1925 +3 1685 5484 1925 +3 521 5486 1930 +3 521 1921 1655 +3 522 1921 521 +3 1382 6568 1927 +3 1927 6695 1926 +3 5457 1776 1859 +3 1924 1925 6315 +3 3755 3736 3748 +3 3745 3155 3201 +3 3165 3751 3201 +3 3747 3748 3153 +3 3153 3745 3751 +3 3751 3745 3201 +3 6905 3751 3165 +3 3751 3754 3747 +3 3153 3751 3747 +3 3751 6905 3754 +3 6905 3750 6906 +3 3752 6906 3750 +3 3754 6905 6906 +3 3652 3653 5836 +3 6835 3338 5771 +3 5836 3641 3652 +3 3311 3395 3396 +3 6835 3311 3338 +3 3338 3311 3396 +3 6348 3340 3640 +3 3641 5836 3640 +3 6347 6348 3640 +3 3360 5100 3654 +3 5100 3341 6347 +3 3341 6348 6347 +3 3654 5100 6347 +3 3342 3316 6467 +3 5099 5100 3360 +3 3298 3316 3342 +3 5836 6347 3640 +3 3310 5770 6834 +3 5773 6835 6836 +3 5771 6836 6835 +3 5770 5773 6836 +3 3311 6835 5773 +3 3308 6834 6836 +3 5770 6836 6834 +3 5773 5770 3315 +3 3315 5770 3310 +3 3391 3390 3341 +3 5773 3298 3311 +3 3298 3395 3311 +3 3316 3298 3315 +3 5773 3315 3298 +3 3636 3640 3340 +3 6348 6467 3340 +3 3635 3340 6467 +3 3636 3340 3635 +3 3341 6881 6882 +3 3342 6882 6881 +3 3390 6881 3341 +3 3644 3390 3391 +3 3391 5099 3362 +3 3644 3391 3362 +3 3297 3299 6881 +3 3342 6881 3299 +3 3299 3395 3298 +3 3342 3299 3298 +3 3297 6881 3390 +3 3297 3390 6884 +3 3644 6884 3390 +3 3644 3362 3645 +3 5836 3654 6347 +3 3698 3310 6834 +3 3308 3698 6834 +3 3315 3310 6892 +3 3315 6892 3316 +3 3391 3341 5100 +3 6882 6467 6348 +3 3341 6882 6348 +3 3342 6467 6882 +3 3391 5100 5099 +3 1183 3292 3288 +3 3290 3631 5828 +3 1226 3300 5846 +3 3303 3734 3290 +3 3634 5827 3400 +3 5828 3303 3290 +3 2087 3300 1225 +3 6832 5762 3300 +3 6832 3300 2087 +3 3274 6826 1183 +3 3273 3295 6826 +3 6832 3293 5762 +3 3303 5828 3634 +3 3293 5761 3292 +3 3295 5762 3293 +3 3293 1183 3295 +3 1183 6826 3295 +3 3292 1183 3293 +3 3300 5762 5846 +3 1226 5846 3741 +3 3741 5853 1226 +3 1226 5853 3734 +3 3402 5827 6346 +3 6346 5827 3634 +3 6832 5761 3293 +3 3634 6498 6346 +3 3402 3401 3407 +3 3402 3403 6345 +3 3400 5827 6345 +3 1183 3288 3274 +3 6641 5347 6826 +3 3273 6826 5347 +3 3294 3280 6831 +3 5761 6831 3280 +3 3281 5761 3280 +3 3294 6831 6832 +3 5761 6832 6831 +3 2087 3294 6832 +3 3294 1222 3280 +3 2087 1222 3294 +3 3302 3305 3304 +3 2087 3302 3304 +3 2087 1225 3302 +3 1225 3400 3302 +3 3303 3400 1225 +3 3406 3407 3377 +3 3302 6345 3305 +3 3400 6345 3302 +3 3403 3406 6842 +3 3403 6842 3306 +3 3304 5789 2087 +3 5789 3305 3306 +3 3304 3305 5789 +3 2087 5789 1222 +3 3306 6842 6843 +3 6345 3306 3305 +3 1221 1222 5789 +3 5789 6843 6844 +3 5789 6844 1221 +3 5789 3306 6843 +3 1221 6844 2092 +3 3407 3411 3377 +3 3407 3403 3402 +3 3411 3414 3377 +3 5828 6498 3634 +3 6878 6879 3633 +3 5829 3633 6879 +3 3414 6879 6878 +3 6879 6880 5829 +3 3401 5829 6880 +3 3414 6880 6879 +3 3401 6880 3411 +3 3407 3401 3411 +3 3411 6880 3414 +3 1225 1226 3303 +3 3734 3303 1226 +3 3300 1226 1225 +3 3306 6345 3403 +3 3406 3403 3407 +3 5827 3402 6345 +3 6346 3401 3402 +3 5149 6128 6260 +3 4147 4148 6049 +3 6049 4151 4231 +3 4148 4147 1003 +3 4151 6049 4148 +3 4148 1003 4146 +3 4148 4146 5991 +3 4151 4148 5991 +3 4231 1015 6049 +3 1015 4147 6049 +3 3931 3930 3929 +3 3931 3929 3971 +3 3968 5962 3931 +3 4029 5932 3929 +3 3930 3931 5962 +3 3969 5962 3968 +3 5345 5953 4009 +3 5935 5944 3968 +3 3970 5935 3971 +3 5953 3969 4009 +3 3930 4029 3929 +3 5944 5935 3967 +3 3970 3966 5935 +3 3957 5942 5940 +3 3971 3968 3931 +3 3969 3968 5942 +3 3968 5944 5942 +3 3957 3969 5942 +3 1128 5942 5944 +3 3930 5962 3977 +3 3976 1147 4026 +3 3929 5932 6957 +3 3929 6957 3971 +3 3971 6957 3970 +3 3971 5935 3968 +3 1147 5959 5345 +3 5953 5345 5959 +3 3977 5962 5953 +3 3969 5953 5962 +3 4011 6964 3976 +3 5959 3976 6964 +3 3977 6964 4011 +3 3976 5959 1147 +3 6964 5953 5959 +3 3977 5953 6964 +3 2743 2744 2745 +3 2859 2857 2856 +3 2697 1020 2717 +3 2691 756 2692 +3 2683 5632 2717 +3 2856 2857 5639 +3 2722 5632 2683 +3 2683 2717 1020 +3 982 753 6419 +3 686 687 6330 +3 2738 5648 6528 +3 2725 5249 2708 +3 712 2708 5249 +3 5641 982 6337 +3 2739 2878 6330 +3 6330 687 2739 +3 748 2693 2686 +3 1020 2686 2693 +3 2697 2686 1020 +3 1019 2686 2697 +3 2708 712 2692 +3 2708 2692 756 +3 2708 756 2721 +3 2717 2721 756 +3 756 2697 2717 +3 756 1019 2697 +3 2721 2717 5632 +3 2708 6763 2725 +3 6764 5632 2722 +3 2737 6764 2722 +3 2737 2722 2694 +3 2721 6764 2737 +3 2695 2722 2693 +3 2683 2693 2722 +3 1020 2693 2683 +3 2708 2721 6763 +3 2721 2737 6763 +3 2722 2695 2694 +3 2721 5632 6764 +3 6765 5633 2695 +3 2694 2695 5633 +3 2694 5633 2743 +3 687 720 2739 +3 2738 2739 720 +3 2859 748 2864 +3 2739 2876 2878 +3 2738 2876 2739 +3 2880 5647 2857 +3 2738 720 5648 +3 720 687 5649 +3 720 5649 721 +3 687 686 5649 +3 2744 2884 5649 +3 721 5649 2884 +3 2743 2884 2744 +3 720 5650 5648 +3 720 721 5650 +3 753 5641 2864 +3 5641 6337 2864 +3 2859 2864 6337 +3 753 2864 6419 +3 6337 982 2880 +3 2693 748 2898 +3 2885 5651 721 +3 2695 2693 2898 +3 2695 2898 6765 +3 2743 5633 2884 +3 2898 748 2859 +3 5633 6765 2885 +3 2898 2885 6765 +3 2885 721 2884 +3 5633 2885 2884 +3 2898 2859 2885 +3 2859 2856 5651 +3 2859 5651 2885 +3 2744 5649 686 +3 753 982 5641 +3 2745 2744 686 +3 757 2694 2743 +3 2694 757 2737 +3 757 2743 2745 +3 2859 6337 2857 +3 2857 6337 2880 +3 4004 5970 3997 +3 5969 4073 4068 +3 5969 5970 4073 +3 4004 4073 5970 +3 4068 6970 5969 +3 3578 3567 3570 +3 1505 6894 1436 +3 1765 4868 1755 +3 1755 5449 1362 +3 1788 1362 5449 +3 1376 4887 5445 +3 1755 4868 1364 +3 1765 1755 1362 +3 4868 4867 1784 +3 1363 1784 4867 +3 1765 5445 4867 +3 4868 1765 4867 +3 1783 1755 1364 +3 1364 1784 4871 +3 1765 1362 1376 +3 1788 1376 1362 +3 5445 1765 1376 +3 1788 1753 1376 +3 5448 1788 5449 +3 4887 1753 6678 +3 1727 4887 6678 +3 1376 1753 4887 +3 5445 4887 1764 +3 4867 5445 1764 +3 1364 4868 1784 +3 4867 1764 1363 +3 1363 4873 1767 +3 1363 1764 4873 +3 1764 4887 1727 +3 6153 4873 1727 +3 1764 1727 4873 +3 6383 4871 1784 +3 1778 4871 6383 +3 1767 6383 1784 +3 1767 1784 1363 +3 6376 6137 6136 +3 4843 6136 6137 +3 1449 6151 1798 +3 6380 6424 4829 +3 6148 6138 6147 +3 6424 6380 6485 +3 6133 6485 6380 +3 6134 6424 6485 +3 6379 6219 4841 +3 1467 4845 6139 +3 4966 6219 6379 +3 6133 6378 6485 +3 4843 4829 6147 +3 4831 6424 1292 +3 4829 6424 4831 +3 4829 4831 6132 +3 6424 6134 4830 +3 1292 6424 4830 +3 4845 6141 6379 +3 4864 6141 4845 +3 6151 6141 4864 +3 6141 1449 6379 +3 6151 1449 6141 +3 1467 4864 4845 +3 6927 6134 6485 +3 6378 6927 6485 +3 4830 6134 6183 +3 6219 4966 6220 +3 6145 6219 6220 +3 6219 6145 4850 +3 6220 7037 6145 +3 4966 6379 1449 +3 4967 6222 6221 +3 6222 7053 4882 +3 4967 7053 6222 +3 6221 6222 4966 +3 1449 6221 4966 +3 4967 6221 1798 +3 1449 1798 6221 +3 6222 4882 6220 +3 4966 6222 6220 +3 6220 4882 7037 +3 6136 6139 4842 +3 4842 6139 4841 +3 6136 4842 6376 +3 6377 6378 6137 +3 6137 6378 6133 +3 6139 6136 6138 +3 6138 6148 1467 +3 6138 1467 6139 +3 4843 6147 6136 +3 6138 6136 6147 +3 4845 6379 6139 +3 6379 4841 6139 +3 4843 6137 6133 +3 4843 6380 4829 +3 4843 6133 6380 +3 6217 6376 4842 +3 6376 6217 6218 +3 6376 6218 6377 +3 6376 6377 6137 +3 1370 1918 1850 +3 6694 1918 5357 +3 1370 1371 5357 +3 1383 5357 1371 +3 1918 1370 5357 +3 5357 1383 1245 +3 5357 1245 6694 +3 5461 1838 5926 +3 1717 1716 1715 +3 1722 1716 1719 +3 1665 4860 4888 +3 6682 1755 1783 +3 6682 5444 1787 +3 1730 1717 1734 +3 1787 5448 5449 +3 5358 1788 5448 +3 6682 1787 1755 +3 1734 1717 1715 +3 1719 1716 1720 +3 1704 1718 1725 +3 1717 1720 1716 +3 1787 5449 1755 +3 6679 1716 1722 +3 6679 1715 1716 +3 545 1666 1676 +3 1707 1706 6367 +3 1249 1730 1734 +3 1735 6367 1706 +3 1720 1717 1730 +3 4861 1232 6382 +3 1249 5438 1730 +3 1787 5444 1679 +3 1731 1745 6309 +3 6289 1676 1666 +3 1741 583 4858 +3 1375 1735 1706 +3 4876 4888 1678 +3 4876 1684 4888 +3 584 1664 4863 +3 1232 6573 6311 +3 1739 583 1253 +3 1741 1253 583 +3 6309 1747 1751 +3 1375 1734 1735 +3 1752 1693 1747 +3 6382 1677 4861 +3 6382 4872 1677 +3 4888 4860 1678 +3 1740 1741 4859 +3 4858 4859 1741 +3 1253 1740 1252 +3 1674 6289 1666 +3 578 1253 1252 +3 578 579 577 +3 5359 1753 5358 +3 5359 5358 1377 +3 6311 5359 1377 +3 6311 1724 5359 +3 1377 4872 6382 +3 1745 1752 1747 +3 1726 5437 1700 +3 1700 5437 1725 +3 1700 1725 1718 +3 1700 1699 1726 +3 1719 1726 1699 +3 1719 1720 1726 +3 1728 1253 577 +3 578 577 1253 +3 1733 1252 5439 +3 578 1252 1733 +3 5439 1740 1732 +3 1252 1740 5439 +3 1715 1735 1734 +3 1715 1736 1735 +3 1736 1715 6680 +3 578 1733 579 +3 1733 5437 1726 +3 579 1733 1726 +3 1720 579 1726 +3 1730 5438 1720 +3 1720 5438 579 +3 577 579 5438 +3 5437 5439 1725 +3 1738 1725 5439 +3 5437 1733 5439 +3 5439 1732 1738 +3 1738 1737 1725 +3 1249 6573 1728 +3 5438 1249 1728 +3 577 5438 1728 +3 1707 1375 1706 +3 6289 1674 1665 +3 4862 1752 1745 +3 584 582 1664 +3 1253 1728 1739 +3 1715 6679 6680 +3 1664 1674 1693 +3 1665 1664 582 +3 1766 1678 1679 +3 1783 1766 5444 +3 1783 5444 6682 +3 5359 1375 1753 +3 1724 1375 5359 +3 6678 1753 1375 +3 1707 6678 1375 +3 4872 1377 1803 +3 5358 1803 1377 +3 5448 1803 5358 +3 5358 1753 1788 +3 1766 1679 5444 +3 1803 1679 1678 +3 1677 1803 1678 +3 1787 1679 1803 +3 1787 1803 5448 +3 1677 4872 1803 +3 1665 1674 1664 +3 1766 4876 1678 +3 4860 1677 1678 +3 1232 1739 6573 +3 1728 6573 1739 +3 4862 1749 1752 +3 1749 4863 1752 +3 4862 583 1749 +3 1739 584 1749 +3 583 1739 1749 +3 1232 4861 582 +3 1665 582 4861 +3 1676 1665 4888 +3 1684 1676 4888 +3 1732 1740 4859 +3 6311 6573 1249 +3 4861 1677 4860 +3 1731 4862 1745 +3 4863 1664 1693 +3 1752 4863 1693 +3 1749 584 4863 +3 1232 582 584 +3 1232 584 1739 +3 1665 4861 4860 +3 1665 1676 6289 +3 1249 1734 1724 +3 1734 1375 1724 +3 583 4862 4858 +3 1751 6310 6309 +3 6310 1731 6309 +3 6309 1745 1747 +3 1253 1741 1740 +3 6311 1249 1724 +3 545 1676 1684 +3 1736 6367 1735 +3 1377 6382 6311 +3 1232 6311 6382 +3 1729 1707 6367 +3 6393 6201 7067 +3 2147 2167 6392 +3 6214 6395 6217 +3 1346 6387 6391 +3 1290 7067 6201 +3 2352 4963 2361 +3 6216 1448 2358 +3 4965 6210 6395 +3 1346 6392 6387 +3 6198 6387 6392 +3 6199 4934 6387 +3 6209 6202 6205 +3 1343 6483 6484 +3 6184 6484 6483 +3 4933 6391 6387 +3 4842 6140 6217 +3 2355 2360 4964 +3 2358 2355 4964 +3 1448 2355 2358 +3 4965 6395 6214 +3 6392 1346 4837 +3 2354 2353 6215 +3 6207 2076 4950 +3 2355 6745 2360 +3 2356 2360 6745 +3 2356 5564 2360 +3 2361 4963 5564 +3 2356 2361 5564 +3 5564 4963 2354 +3 2354 6215 5564 +3 4964 5564 6215 +3 2360 5564 4964 +3 2147 2168 2167 +3 4965 2353 6210 +3 4837 1190 2147 +3 6374 1190 4837 +3 1343 6484 4919 +3 6483 4933 6387 +3 4934 6483 6387 +3 1343 4933 6483 +3 4934 6184 6483 +3 4948 6198 2167 +3 4949 6198 4948 +3 6199 6387 6198 +3 6199 6198 4949 +3 6200 7051 6202 +3 6201 6202 7051 +3 4949 6200 6202 +3 1290 6201 7051 +3 4949 4948 6200 +3 6204 6203 4934 +3 6204 4949 6202 +3 6209 6204 6202 +3 6203 6204 6209 +3 6205 6202 6201 +3 6184 6203 4950 +3 6184 4950 2076 +3 4934 6203 6184 +3 6203 6209 4950 +3 6204 6199 4949 +3 6204 4934 6199 +3 2167 2168 4948 +3 6200 4948 7052 +3 7052 6927 7051 +3 1290 7051 6927 +3 6200 7052 7051 +3 2358 6213 6214 +3 2358 4964 6213 +3 6213 4965 6214 +3 2353 4965 6215 +3 6213 6215 4965 +3 6213 4964 6215 +3 6140 6216 6214 +3 1448 6216 6140 +3 6216 2358 6214 +3 6140 6214 6217 +3 6198 6392 2167 +3 6484 6184 2076 +3 6484 2076 4919 +3 6140 4842 4841 +3 6140 4841 1448 +3 4837 2147 6392 +3 6207 4919 2076 +3 4959 4961 6208 +3 6208 4961 4962 +3 6209 6205 4962 +3 4962 4961 6209 +3 6208 6210 6211 +3 2353 6211 6210 +3 4959 6208 6223 +3 6208 6211 6223 +3 6210 6208 4962 +3 4961 4950 6209 +3 6393 6205 6201 +3 6212 6393 7067 +3 4962 6205 6393 +3 6395 6394 6217 +3 6218 6217 6394 +3 6210 6394 6395 +3 6210 4962 6394 +3 6377 6218 7067 +3 6377 1290 6378 +3 1290 6377 7067 +3 6393 6212 6394 +3 4962 6393 6394 +3 6218 6212 7067 +3 6212 6218 6394 +3 2354 6211 2353 +3 4963 2352 6211 +3 6223 6211 2352 +3 4963 6211 2354 +3 4961 6207 4950 +3 6645 1548 3500 +3 3526 3529 1522 +3 3553 6490 3759 +3 3771 3759 3767 +3 6908 3767 3769 +3 1452 3769 3759 +3 6645 1453 1548 +3 3579 6877 3626 +3 3579 1493 6877 +3 3526 1522 1521 +3 5096 1522 3529 +3 3501 5364 3503 +3 3528 1522 5096 +3 1470 1521 3528 +3 3497 3519 3508 +3 3506 3511 3507 +3 3759 3769 3767 +3 3555 3500 3553 +3 3555 3553 3545 +3 6343 3501 3503 +3 5818 1526 3555 +3 3511 1483 1558 +3 1482 1558 1483 +3 3528 1521 1522 +3 3577 3555 1526 +3 1521 1470 3546 +3 3553 3759 3771 +3 1548 3553 3500 +3 1452 3759 6490 +3 3553 6355 3545 +3 3546 3545 1521 +3 3518 3545 3546 +3 3517 6344 3567 +3 6571 6343 3503 +3 3502 6343 6571 +3 3516 6344 3502 +3 3570 3567 6344 +3 1485 1482 1483 +3 3526 1521 6355 +3 3545 6355 1521 +3 1469 3503 1475 +3 1471 1475 3503 +3 3502 3517 6343 +3 3519 1469 1475 +3 3519 1475 3507 +3 3506 3507 1475 +3 3497 1469 3519 +3 3497 6571 1469 +3 3503 1469 6571 +3 3508 6571 3497 +3 5364 1471 3503 +3 1471 5364 3528 +3 1470 3528 5364 +3 3502 6571 6856 +3 6857 3523 1485 +3 3506 1471 6857 +3 1483 3506 6857 +3 1475 1471 3506 +3 3511 3506 1483 +3 1485 1483 6857 +3 3523 6857 3528 +3 1471 3528 6857 +3 3517 3501 6343 +3 3555 3545 3518 +3 3554 3544 3529 +3 3526 3554 3529 +3 3502 6344 3517 +3 3546 1470 3501 +3 3546 3501 3517 +3 3518 3546 3517 +3 3501 1470 5364 +3 3518 3517 3567 +3 3578 5818 3567 +3 3555 3518 5818 +3 3518 3567 5818 +3 3578 1526 5818 +3 3502 6856 3626 +3 6877 3516 3502 +3 3626 6877 3502 +3 3553 1548 6490 +3 3500 3555 3577 +3 3767 3512 3771 +3 3771 6909 6355 +3 3526 6355 6909 +3 3553 3771 6355 +3 3554 6909 3544 +3 3526 6909 3554 +3 5096 3523 3528 +3 3570 6344 3516 +3 3510 3520 3579 +3 3376 3378 5832 +3 5832 3329 3376 +3 6254 5088 3376 +3 5087 3376 5088 +3 3378 3376 5087 +3 5089 3377 3378 +3 3377 3414 3378 +3 3378 3414 5832 +3 5089 3378 5087 +3 1440 5089 5087 +3 1587 1519 6673 +3 6910 1587 6673 +3 5066 6247 6249 +3 2535 2536 2130 +3 6242 5895 5894 +3 2536 3079 5894 +3 4805 5608 2536 +3 5062 6241 6247 +3 5066 6248 6246 +3 3079 5724 5078 +3 2535 4805 2536 +3 6241 5062 6239 +3 6241 6249 6247 +3 5724 2536 5608 +3 3079 2536 5724 +3 3101 3099 5608 +3 5895 5067 5894 +3 6242 5894 3079 +3 6239 6242 6243 +3 5061 6239 6243 +3 5062 6242 6239 +3 6246 5895 6247 +3 5062 6247 5895 +3 5066 6246 6247 +3 5067 5895 6246 +3 5062 5895 6242 +3 3079 5061 6243 +3 4805 3101 5608 +3 5061 3079 5078 +3 6241 7056 2122 +3 3079 6243 6242 +3 6241 2122 6249 +3 6248 5066 5071 +3 1870 1862 1861 +3 1877 1862 1870 +3 2342 1812 2294 +3 1813 1826 1812 +3 2342 2294 2341 +3 1826 2294 1812 +3 5559 2342 2341 +3 2294 1824 1823 +3 4909 5465 1880 +3 1819 1826 1813 +3 1824 1880 5465 +3 1823 2341 2294 +3 1880 1824 2294 +3 1826 1809 4909 +3 1813 2298 6558 +3 1813 6558 1819 +3 1819 1809 1826 +3 1878 1875 6686 +3 5465 4909 1878 +3 1826 1880 2294 +3 4909 1880 1826 +3 1878 4909 1875 +3 1462 1416 3803 +3 3797 3803 1416 +3 3796 3827 3778 +3 1636 1649 2181 +3 1636 1614 1649 +3 3796 3778 5551 +3 1991 1636 2181 +3 1298 1297 5551 +3 2186 2266 1297 +3 1416 5363 1461 +3 1304 1462 5860 +3 1416 1462 5363 +3 5551 1297 3796 +3 1304 5363 1462 +3 3802 5860 1462 +3 3802 3462 5860 +3 3464 3463 3462 +3 3797 5861 3805 +3 1649 5861 1416 +3 1947 5363 1304 +3 1636 1991 1972 +3 2181 1649 1461 +3 3797 1416 5861 +3 1947 1461 5363 +3 2186 1297 1298 +3 1991 2181 1461 +3 6487 3463 3464 +3 3462 2189 5860 +3 2185 1303 1302 +3 2182 2185 1302 +3 3818 3463 6487 +3 2189 2186 2185 +3 2266 2186 2189 +3 1298 2190 2186 +3 1651 5861 1464 +3 5861 1649 1464 +3 1464 1649 1614 +3 1416 1461 1649 +3 2189 2185 2182 +3 1302 1303 2201 +3 1989 1947 2201 +3 1991 1947 1989 +3 1302 2201 1947 +3 1302 1947 1304 +3 1304 2189 2182 +3 1651 3805 5861 +3 1461 1947 1991 +3 1304 5860 2189 +3 2182 1302 1304 +3 3462 3463 3818 +3 2266 2189 3462 +3 3462 3818 2266 +3 1080 5113 1081 +3 656 1081 5113 +3 656 5113 6130 +3 1905 1324 1909 +3 1909 1915 1905 +3 2173 2106 2172 +3 1324 1317 6693 +3 2195 2187 1293 +3 2190 2187 2195 +3 2195 1293 2193 +3 1556 1484 1479 +3 1563 1552 1558 +3 6170 1754 1230 +3 5091 1230 1754 +3 1555 1479 1231 +3 1230 1231 1479 +3 1603 1550 1620 +3 6255 5927 5091 +3 5927 4878 5091 +3 6255 1754 4864 +3 3474 4879 6257 +3 4877 3474 3492 +3 1555 1231 4877 +3 1981 1230 5091 +3 1230 1620 1621 +3 1754 6170 1635 +3 1555 3492 1552 +3 1230 1479 1620 +3 1621 1620 1550 +3 3511 1552 3492 +3 4879 5928 4878 +3 1620 1484 1603 +3 3492 1555 4877 +3 5502 5919 5920 +3 1635 5919 5502 +3 5928 1981 4878 +3 1563 1562 1553 +3 1553 1552 1563 +3 1556 1479 1555 +3 3474 5928 4879 +3 1230 5919 6170 +3 1635 6170 5919 +3 1621 5919 1230 +3 1754 6255 5091 +3 5928 3474 4877 +3 4877 1981 5928 +3 5091 4878 1981 +3 1231 1981 4877 +3 1556 1555 1553 +3 1555 1552 1553 +3 1553 1562 1556 +3 1556 1562 4853 +3 1467 6148 5927 +3 6150 5927 6148 +3 1620 1479 1484 +3 3511 1558 1552 +3 6148 6147 4851 +3 6147 6149 4851 +3 6147 7039 6149 +3 7039 7040 7041 +3 6149 7039 7041 +3 6132 7040 7039 +3 7039 4829 6132 +3 6147 4829 7039 +3 6148 4851 6150 +3 1556 4853 1484 +3 6150 4878 5927 +3 4864 1754 5921 +3 1635 5921 1754 +3 6255 1467 5927 +3 4864 1467 6255 +3 6257 4879 6256 +3 5092 6257 6256 +3 4851 5092 6256 +3 4878 6150 4879 +3 6256 4879 6150 +3 4851 6256 6150 +3 6149 7041 5092 +3 4851 6149 5092 +3 1361 1845 1772 +3 4905 1361 6556 +3 1772 6556 1361 +3 1772 5442 6556 +3 6444 1849 1938 +3 1938 5484 6444 +3 1757 510 1756 +3 4870 1793 4794 +3 1792 4794 1793 +3 4869 6385 4870 +3 6381 1756 1760 +3 1757 5443 510 +3 510 5443 1683 +3 1367 1683 5443 +3 6593 4794 1792 +3 6385 6383 6600 +3 1767 6600 6383 +3 1793 6385 6600 +3 524 1683 1367 +3 4870 1759 4869 +3 6381 1760 1668 +3 523 1668 524 +3 524 1760 1683 +3 1668 1760 524 +3 1396 523 524 +3 1396 524 1367 +3 1760 510 1683 +3 1760 1756 510 +3 1360 6443 1756 +3 1757 1756 6443 +3 1756 1759 1360 +3 4794 1369 4870 +3 1360 1759 4870 +3 1793 4870 6385 +3 1767 4873 1793 +3 1768 1793 4873 +3 1793 6600 1767 +3 6152 7042 7044 +3 4875 1768 7042 +3 1768 4874 7042 +3 4873 6153 1768 +3 4874 1768 6153 +3 1369 1360 4870 +3 6154 6157 7045 +3 7045 7044 1536 +3 6157 7044 7045 +3 7045 7046 6154 +3 4882 6154 7046 +3 1536 7046 7045 +3 6152 6167 4875 +3 6157 6167 6152 +3 6157 6152 7044 +3 6152 4875 7042 +3 4908 1792 4875 +3 4875 1792 1768 +3 1768 1792 1793 +3 4875 6167 4908 +3 4882 7046 7037 +3 1536 7037 7046 +3 1668 1761 6381 +3 1778 6385 4869 +3 4869 1761 1778 +3 1759 1756 4869 +3 6381 4869 1756 +3 4869 6381 1761 +3 6383 6385 1778 +3 2136 2138 2137 +3 4945 6196 2136 +3 1189 1188 6375 +3 6713 1188 1189 +3 4945 1189 6195 +3 1189 4945 6713 +3 2136 6196 4998 +3 6375 6195 1189 +3 5005 4999 2460 +3 2458 2526 2401 +3 2401 2459 2458 +3 2517 5605 2513 +3 2518 2517 2513 +3 2460 5605 2517 +3 2460 4999 5605 +3 6375 1188 6374 +3 1805 1807 2138 +3 1807 2137 2138 +3 1807 5563 1806 +3 2508 2518 2513 +3 2517 2400 2460 +3 4945 6195 6196 +3 2460 2400 5005 +3 1806 2137 1807 +3 2526 2458 2400 +3 1806 2135 2137 +3 4998 2138 2136 +3 6374 2133 1190 +3 6374 1188 2133 +3 2137 2135 2136 +3 2517 2526 2400 +3 2526 2518 2524 +3 2517 2518 2526 +3 2526 2524 2401 +3 2510 2524 2518 +3 2510 2518 2508 +3 1806 2142 6546 +3 2133 2134 2146 +3 2134 2143 6546 +3 1806 6546 2143 +3 2136 2135 4945 +3 2146 2147 1190 +3 2458 2459 2523 +3 2135 6713 4945 +3 2135 2143 6713 +3 2135 1806 2143 +3 2143 1188 6713 +3 2133 2143 2134 +3 2133 2146 1190 +3 2147 2146 2168 +3 1806 5563 2142 +3 2523 2459 5607 +3 2143 2133 1188 +3 4999 2138 4998 +3 4999 5005 2349 +3 2349 1805 4999 +3 2138 4999 1805 +3 815 703 814 +3 5103 1443 5888 +3 1443 5103 3330 +3 5063 6452 6240 +3 515 6452 5063 +3 7056 6239 7057 +3 614 7057 6239 +3 6240 7056 7057 +3 2323 5063 6240 +3 2323 6240 7057 +3 2323 7057 614 +3 515 5063 2323 +3 5923 4904 1774 +3 1834 1846 6949 +3 1845 1379 1846 +3 1845 1846 1772 +3 5442 4904 5460 +3 1839 5460 4904 +3 1774 4904 5442 +3 1775 4904 5923 +3 6949 1846 1379 +3 1769 1378 6685 +3 1774 1843 1773 +3 1774 5442 1843 +3 1772 1843 5442 +3 1379 1845 1378 +3 1379 1769 1771 +3 1379 1378 1769 +3 5924 6386 1773 +3 1833 4906 6386 +3 1773 6386 4906 +3 1843 1846 1834 +3 1772 1846 1843 +3 1843 1834 1773 +3 5924 1773 1834 +3 1774 1773 4906 +3 4896 4906 1833 +3 1379 1771 6949 +3 5924 1834 6949 +3 1771 5924 6949 +3 4904 1775 1839 +3 4900 1839 1775 +3 4896 5923 4906 +3 1775 5923 4896 +3 1774 4906 5923 +3 3519 5807 3508 +3 3507 5807 3519 +3 1557 4795 2050 +3 6717 4952 4951 +3 2148 1347 6717 +3 6717 2168 2148 +3 4951 2168 6717 +3 4948 2168 4951 +3 7052 4948 4952 +3 4951 4952 4948 +3 6206 7052 4952 +3 6206 6927 7052 +3 6206 6134 6927 +3 6134 4952 6183 +3 6206 4952 6134 +3 1347 6183 6717 +3 4952 6717 6183 +3 2166 5910 4922 +3 6175 4922 2088 +3 6938 4922 5910 +3 4921 4922 6175 +3 2166 5912 5910 +3 6197 2166 1208 +3 1206 5519 1207 +3 5519 1208 1207 +3 6938 2088 4922 +3 1208 2166 4922 +3 6197 4946 6939 +3 6363 4983 2077 +3 2081 4919 2077 +3 4981 2388 2394 +3 6363 4953 4983 +3 4960 4981 2351 +3 5519 1206 6709 +3 2079 2085 4946 +3 5521 2085 2079 +3 2078 2079 6709 +3 5521 2079 2081 +3 1405 2081 2079 +3 1405 2079 2078 +3 5521 2077 2085 +3 2081 2077 5521 +3 5910 2395 6938 +3 2396 5912 5911 +3 5912 2396 2395 +3 2166 6939 5912 +3 5911 5912 6939 +3 1208 5519 6197 +3 4946 6197 5519 +3 5519 6709 4946 +3 2079 4946 6709 +3 6943 2077 2084 +3 2085 2077 6943 +3 6943 4947 4946 +3 2084 4947 6943 +3 4947 6939 4946 +3 6197 6939 2166 +3 4946 2085 6943 +3 4981 4982 2351 +3 4981 2394 4982 +3 2084 4982 4947 +3 6939 4982 5911 +3 4947 4982 6939 +3 2351 4982 2084 +3 4983 6225 2084 +3 2084 2077 4983 +3 4982 2394 5911 +3 2396 5911 2394 +3 5912 2395 5910 +3 6363 4919 4953 +3 2077 4919 6363 +3 4961 4960 6225 +3 6225 6207 4961 +3 4953 6207 6225 +3 4961 4959 4960 +3 4980 4981 4960 +3 4980 2388 4981 +3 4983 4953 6225 +3 6207 4953 4919 +3 4960 2351 6225 +3 2084 6225 2351 +3 4980 4960 4959 +3 4892 6386 5924 +3 1775 4897 1777 +3 4900 1775 1777 +3 4896 4897 1775 +3 1859 4897 4896 +3 1859 1833 1857 +3 1380 4892 4895 +3 6685 5455 1770 +3 1769 6685 1770 +3 1769 1770 1771 +3 1380 1833 4892 +3 1771 1770 6164 +3 4894 6164 1770 +3 1833 1380 1857 +3 4892 1833 6386 +3 6164 4893 5924 +3 4892 5924 4893 +3 1771 6164 5924 +3 4893 6164 4894 +3 4894 1663 6165 +3 4893 4894 6165 +3 6165 4895 4893 +3 4892 4893 4895 +3 4896 1833 1859 +3 1067 3086 3087 +3 1210 1209 5760 +3 2541 1067 3087 +3 5064 2541 3087 +3 5075 6251 6252 +3 5065 2541 5064 +3 5065 1067 2541 +3 5075 6252 5064 +3 6251 5906 5029 +3 5618 6252 5029 +3 6251 5029 6252 +3 5028 5064 2606 +3 5028 5065 5064 +3 5906 6251 5071 +3 2606 6252 5618 +3 5071 6251 6248 +3 6251 5075 6248 +3 3087 5075 5064 +3 3087 4798 5075 +3 6248 5075 4798 +3 2606 5064 6252 +3 3124 852 3130 +3 3113 1167 3119 +3 3118 3119 3124 +3 3118 938 3119 +3 3130 3135 3136 +3 3118 3124 3130 +3 3120 3124 3119 +3 3119 5727 3120 +3 3136 938 3118 +3 1167 5727 3119 +3 3136 3118 3130 +3 3159 864 3158 +3 869 5751 5750 +3 6635 5750 3159 +3 5750 5751 5743 +3 3159 3158 6635 +3 6635 869 5750 +3 5751 869 3228 +3 875 5751 3228 +3 868 869 6635 +3 3158 868 6635 +3 5751 875 5740 +3 3357 5836 3653 +3 3662 3357 3653 +3 3357 5837 5836 +3 6253 3360 5837 +3 5836 5837 3654 +3 3357 6253 5837 +3 3360 3654 5837 +3 3728 3285 3729 +3 3729 3738 3742 +3 3287 3285 3728 +3 3729 3741 3728 +3 3287 5766 3285 +3 3287 5767 5766 +3 3295 5767 5768 +3 3287 5768 5767 +3 3273 5767 3295 +3 3728 5768 3287 +3 5762 5768 5846 +3 3728 5846 5768 +3 3295 5768 5762 +3 5846 3728 3741 +3 3742 3738 3730 +3 3285 3153 3748 +3 3736 3285 3748 +3 3279 513 512 +3 5725 3086 1066 +3 5792 5788 1439 +3 5524 5792 3272 +3 5787 1440 5788 +3 1440 5787 5089 +3 3408 5089 5787 +3 1439 5788 1440 +3 1439 3272 5792 +3 3406 3377 3408 +3 5787 3406 3408 +3 5787 6842 3406 +3 5788 6842 5787 +3 5788 6843 6842 +3 5792 6844 6843 +3 5788 5792 6843 +3 5524 2092 6844 +3 5792 5524 6844 +3 3408 3377 5089 +3 4923 5916 5790 +3 4937 6185 1342 +3 2151 4931 4932 +3 5528 2098 6187 +3 4923 5917 5916 +3 1342 6185 4936 +3 5917 6177 5916 +3 6177 5917 2098 +3 5529 5528 6187 +3 5916 4811 5790 +3 4827 4837 1342 +3 6374 4837 4827 +3 6388 4943 4935 +3 4944 4943 4931 +3 4837 1346 1342 +3 2123 4932 6388 +3 4931 6388 4932 +3 4807 5528 2144 +3 2098 5528 6714 +3 4807 6714 5528 +3 4807 4932 2123 +3 4807 2144 4932 +3 2144 2149 4932 +3 2151 4932 2149 +3 6714 4807 5914 +3 2098 6714 5914 +3 2091 5520 4924 +3 4937 6389 6185 +3 1342 1346 4937 +3 4811 5916 6177 +3 6178 2091 4924 +3 4811 6178 6947 +3 4924 6947 6178 +3 6185 6389 6186 +3 6185 6186 4935 +3 2123 6388 6188 +3 4935 6188 6388 +3 6188 4942 2123 +3 4807 2123 4942 +3 6189 6186 6190 +3 6189 6191 4942 +3 6188 6189 4942 +3 6189 6188 4935 +3 6186 6189 4935 +3 2091 4938 5520 +3 6191 4938 7049 +3 2091 7049 4938 +3 6190 4938 6191 +3 6178 6192 7049 +3 4811 6192 6178 +3 7049 6193 6191 +3 4942 6191 6193 +3 6192 6193 7049 +3 6178 7049 2091 +3 6189 6190 6191 +3 5914 4942 6193 +3 4807 4942 5914 +3 6192 7050 6193 +3 6177 7050 6192 +3 4811 6177 6192 +3 2098 7050 6177 +3 6193 7050 5914 +3 2098 5914 7050 +3 4944 4827 4943 +3 4943 4827 4936 +3 4935 4936 6185 +3 4943 4936 4935 +3 4944 6375 4827 +3 6375 6374 4827 +3 6388 4931 4943 +3 4936 4827 1342 +3 2702 970 990 +3 6997 970 2702 +3 2702 5397 2706 +3 990 5397 2702 +3 6997 2702 2706 +3 1758 4901 1858 +3 1758 5481 4903 +3 1758 4903 4901 +3 3270 3275 512 +3 5404 4388 5132 +3 5404 652 4388 +3 4388 5139 5132 +3 5139 4388 6259 +3 937 845 928 +3 845 3888 928 +3 6597 2914 3072 +3 2628 2993 2624 +3 2979 2980 2969 +3 2624 3076 2628 +3 2993 2628 2997 +3 2982 2966 2963 +3 2991 2428 2629 +3 1043 3071 5338 +3 2962 2995 2966 +3 2993 2997 2992 +3 2994 2916 5685 +3 2963 2981 2982 +3 2916 5686 5685 +3 2972 2966 2982 +3 5686 6523 2963 +3 2963 2966 2995 +3 5710 5338 3071 +3 3071 5711 5710 +3 1044 5713 1043 +3 1044 1043 5338 +3 6597 3072 1043 +3 3071 1043 3072 +3 6597 1043 5713 +3 5712 3070 3073 +3 1044 3003 3001 +3 6783 2963 2995 +3 2991 2959 2428 +3 2978 2980 2979 +3 2997 2628 3076 +3 3001 2999 6516 +3 2998 6522 3073 +3 5712 3073 6522 +3 2916 2989 6523 +3 1199 2989 2916 +3 2985 2982 2981 +3 6523 2981 2963 +3 2989 2981 6523 +3 2985 2981 1199 +3 2989 1199 2981 +3 2990 2985 1199 +3 2992 2991 2993 +3 2962 2966 2972 +3 2963 2992 5686 +3 5685 5686 2992 +3 5686 2916 6523 +3 2996 6620 3000 +3 2974 2916 2994 +3 2963 6783 2992 +3 2959 2992 6783 +3 2959 6783 2995 +3 2991 2992 2959 +3 2998 2994 6522 +3 5685 6522 2994 +3 2978 6620 2996 +3 6516 2980 2978 +3 2999 2980 6516 +3 2978 2996 6516 +3 3070 5709 3072 +3 5709 3071 3072 +3 2994 2998 3075 +3 2974 2994 3075 +3 6597 3075 2998 +3 2914 6597 2998 +3 3073 2914 2998 +3 3073 3072 2914 +3 3070 3072 3073 +3 3070 6796 3074 +3 6796 2997 3076 +3 3074 6796 3076 +3 3077 2997 6796 +3 3070 5712 6796 +3 3000 2974 3075 +3 3075 2996 3000 +3 3001 6516 2996 +3 2992 2997 5685 +3 3077 5685 2997 +3 5685 5712 6522 +3 3077 5712 5685 +3 1044 3001 5713 +3 3075 6597 5713 +3 3001 2996 5713 +3 3075 5713 2996 +3 645 2773 2565 +3 2769 2773 2768 +3 2768 2773 2634 +3 2757 2765 2754 +3 2493 2754 2564 +3 2674 2564 2758 +3 2756 2674 2758 +3 2757 2565 2769 +3 2565 2773 2769 +3 2757 2754 2565 +3 2493 645 2565 +3 2773 2774 2634 +3 2493 2565 2754 +3 2756 2758 5051 +3 5051 2758 2765 +3 2754 2765 2758 +3 2774 2773 645 +3 2756 2755 2674 +3 2754 2758 2564 +3 2938 1195 3041 +3 6615 1195 2938 +3 1196 6615 6618 +3 2938 6618 6615 +3 3035 6615 2977 +3 1196 2977 6615 +3 1195 6615 3035 +3 1196 2976 2977 +3 1097 1095 6003 +3 2952 5757 2951 +3 2951 5757 3200 +3 1172 3264 1192 +3 1193 3264 1172 +3 1172 1173 5756 +3 1172 6596 1173 +3 1171 1173 6596 +3 5756 2951 3200 +3 1172 1192 6596 +3 3200 1172 5756 +3 1172 3200 1193 +3 5757 1193 3200 +3 3277 1171 6827 +3 3271 6827 1171 +3 5756 1173 5758 +3 5758 6829 6621 +3 5756 5758 6621 +3 3271 1171 6596 +3 3282 1171 3277 +3 3278 3282 3277 +3 5758 3278 6829 +3 5758 3282 3278 +3 1173 3282 5758 +3 1171 3282 1173 +3 4819 775 4820 +3 5307 5368 4509 +3 6660 4821 6056 +3 4516 4509 5368 +3 4819 5169 775 +3 5174 4536 6471 +3 4534 6471 4536 +3 4466 6071 4529 +3 4463 5196 5174 +3 4536 5174 5196 +3 4520 5309 4537 +3 5197 5196 4790 +3 5366 5197 4790 +3 5366 4538 5197 +3 5197 4538 5309 +3 4537 5309 4538 +3 5305 5366 4516 +3 5366 4790 4516 +3 4538 5366 5305 +3 5307 5308 5368 +3 4516 5368 5308 +3 5305 4516 5308 +3 4599 6657 4535 +3 4524 6661 774 +3 5170 5387 773 +3 5388 4519 4529 +3 4466 4529 4519 +3 4466 4519 6662 +3 4509 4463 5367 +3 6661 5386 6056 +3 774 6661 6056 +3 4524 774 4529 +3 4529 774 5388 +3 773 4519 5388 +3 6056 4821 4517 +3 774 6056 4517 +3 4527 5387 5170 +3 5367 4463 5387 +3 4463 773 5387 +3 5367 5387 4527 +3 6056 5386 6660 +3 4534 4536 6058 +3 4534 6058 4535 +3 6071 2747 6657 +3 4535 6657 2747 +3 4466 2747 6071 +3 4462 2747 4466 +3 4535 2747 4534 +3 4599 4535 5195 +3 774 4517 5388 +3 773 5388 4517 +3 4536 5197 6058 +3 5309 6058 5197 +3 4790 5196 4463 +3 4509 4790 4463 +3 4819 4820 4517 +3 773 4517 4820 +3 4819 4517 4821 +3 4466 6662 4462 +3 4463 5174 4519 +3 773 4463 4519 +3 5170 4820 4527 +3 5170 773 4820 +3 4527 4820 775 +3 6262 6661 4524 +3 5386 6661 6262 +3 6471 6662 5174 +3 4519 5174 6662 +3 4462 6662 6471 +3 4462 6471 2747 +3 4534 2747 6471 +3 4536 5196 5197 +3 4537 4538 5305 +3 4509 4516 4790 +3 6058 4520 5195 +3 4535 6058 5195 +3 4520 6058 5309 +3 5112 5411 4247 +3 4247 5411 1080 +3 5026 4801 5001 +3 5905 4801 5032 +3 5905 6235 5003 +3 2489 5003 6235 +3 4801 5906 5032 +3 4801 5029 5906 +3 6226 5001 4801 +3 5029 4801 5026 +3 5905 6226 4801 +3 6226 5004 5001 +3 6226 5003 5004 +3 6226 5905 5003 +3 2489 5004 5003 +3 5026 5618 5029 +3 5905 5032 6235 +3 6235 6236 2120 +3 2120 6236 1352 +3 2122 1352 6236 +3 5066 6250 5071 +3 6249 6236 6250 +3 6249 2122 6236 +3 6250 6235 5032 +3 6236 6235 6250 +3 5066 6249 6250 +3 6250 5032 5906 +3 6250 5906 5071 +3 4328 4331 4330 +3 4332 6023 4328 +3 4322 4328 6023 +3 4328 4330 6025 +3 4312 4313 4311 +3 4332 4328 6025 +3 6994 4318 4366 +3 4325 4318 6994 +3 4335 4350 4351 +3 4322 4312 1072 +3 1073 4331 1072 +3 4322 1072 4331 +3 6026 4335 4351 +3 4331 1073 4330 +3 4312 4322 4313 +3 6023 4313 4322 +3 4327 6025 4330 +3 1073 4327 4330 +3 4322 4331 4328 +3 6023 4332 4323 +3 4352 6023 4323 +3 4352 4313 6023 +3 4352 4323 4350 +3 6026 6032 4335 +3 4254 4335 6032 +3 4351 4324 6991 +3 4324 4351 4350 +3 4323 4324 4350 +3 4352 4335 4254 +3 4311 4352 4254 +3 4352 4350 4335 +3 4323 4332 4325 +3 4325 4319 4318 +3 4332 4319 4325 +3 4323 4325 4324 +3 4313 4352 4311 +3 6991 4324 6994 +3 4325 6994 4324 +3 4366 6991 6994 +3 6978 4144 5998 +3 4163 6978 4803 +3 4803 4166 4163 +3 4163 4144 6978 +3 3900 3965 6955 +3 3900 6955 3904 +3 6410 6955 835 +3 3965 835 6955 +3 3904 6955 6410 +3 941 835 3965 +3 4576 6067 4574 +3 6070 4574 6067 +3 4572 6070 4571 +3 6067 4571 6070 +3 4571 6067 6066 +3 4576 6066 6067 +3 4574 6070 6075 +3 4576 6069 4583 +3 4574 6069 4576 +3 4576 7010 6066 +3 6070 4459 6075 +3 4572 4459 6070 +3 1457 6841 3388 +3 1457 3388 1458 +3 1457 3376 6841 +3 1166 843 1167 +3 843 853 1167 +3 2925 853 5662 +3 2925 851 3120 +3 5729 851 2925 +3 844 1166 6510 +3 5729 3126 851 +3 5662 843 3122 +3 3122 5663 5662 +3 3127 5662 5663 +3 3122 5726 3123 +3 853 843 5662 +3 2925 1167 853 +3 5729 3128 3126 +3 5663 3122 3123 +3 5662 3127 2925 +3 5729 2925 3127 +3 844 843 1166 +3 843 844 3122 +3 3122 844 5726 +3 844 6510 6809 +3 5726 844 6809 +3 1187 3045 6791 +3 5703 6791 3045 +3 6793 5705 1021 +3 2918 5661 5660 +3 5660 6775 1204 +3 5661 6775 5660 +3 5660 1204 1022 +3 5696 6775 6786 +3 3040 6786 6775 +3 1201 5699 2918 +3 3040 6775 5661 +3 5660 1022 1021 +3 5694 5660 1021 +3 2918 5660 5694 +3 1187 6790 3045 +3 5703 3045 1200 +3 1200 3045 2943 +3 3045 6790 2943 +3 1200 2943 5699 +3 5699 1201 1200 +3 1200 1201 5694 +3 2918 5694 1201 +3 1021 5705 5694 +3 5703 5694 5705 +3 5703 1200 5694 +3 1187 6640 6790 +3 1021 5704 6793 +3 1022 5704 1021 +3 5697 3042 3039 +3 2863 5651 526 +3 2856 526 5651 +3 721 5651 5650 +3 5650 5651 2863 +3 6760 2643 2636 +3 7055 6228 6227 +3 5839 5772 5775 +3 3184 3180 874 +3 1000 6507 6508 +3 5749 6508 6507 +3 3231 875 876 +3 3205 5740 6613 +3 875 6613 5740 +3 5749 6507 6623 +3 871 6812 3180 +3 1431 871 3180 +3 1431 3180 3184 +3 1178 3204 3203 +3 3205 3206 3204 +3 1178 998 3204 +3 3203 3204 3206 +3 1000 3204 998 +3 3204 1000 3205 +3 3183 874 3228 +3 5331 876 3228 +3 875 3228 876 +3 874 5331 3228 +3 874 3171 5331 +3 3184 874 3183 +3 3207 3206 3231 +3 875 3231 6613 +3 3206 6613 3231 +3 3207 3203 3206 +3 3205 6613 3206 +3 5749 5740 3205 +3 6508 5749 3205 +3 1000 6508 3205 +3 876 3227 3231 +3 3207 3231 3227 +3 3227 6837 1435 +3 5331 6837 3227 +3 876 5331 3227 +3 3171 5775 5774 +3 3171 5774 6837 +3 5776 3171 874 +3 874 3180 5776 +3 3171 6837 5331 +3 3235 3177 5776 +3 5776 3177 3171 +3 3701 5839 3704 +3 3177 5839 5775 +3 5839 3701 5772 +3 3704 5839 3177 +3 3177 5775 3171 +3 3704 3177 3235 +3 3235 5776 3180 +3 6837 5774 1435 +3 5841 1435 5774 +3 3227 1435 5841 +3 2652 2653 6760 +3 5625 6805 3004 +3 3644 3645 6884 +3 3645 3646 6884 +3 4034 5964 6966 +3 1865 1835 1368 +3 1865 5453 1835 +3 1865 5462 5453 +3 1762 1860 5458 +3 1781 5453 5462 +3 1368 1835 1831 +3 5463 1781 5462 +3 1682 5458 1860 +3 1682 5443 5458 +3 1762 1763 1387 +3 1763 1762 5458 +3 1763 1757 1359 +3 1757 6443 1359 +3 1763 1359 1387 +3 1387 1359 1831 +3 1763 5443 1757 +3 1367 5443 1682 +3 5458 5443 1763 +3 1359 1368 1831 +3 1359 6443 1368 +3 1602 1571 1601 +3 1571 1600 1601 +3 1610 1601 1600 +3 6560 1600 1571 +3 1572 1600 6560 +3 1577 1601 1616 +3 1601 1610 1616 +3 1602 1601 1577 +3 1571 6481 1606 +3 1571 1602 6481 +3 1600 1572 1599 +3 1571 1606 6560 +3 1577 1583 1602 +3 6481 1602 1516 +3 1583 1516 1602 +3 6560 5424 1572 +3 1606 5424 6560 +3 1572 6559 1599 +3 5424 6559 1572 +3 1599 1610 1600 +3 2904 2872 996 +3 980 2872 981 +3 3002 2969 2980 +3 3017 1039 2969 +3 2979 2969 1039 +3 5689 3001 3003 +3 3002 2926 2969 +3 2922 5673 2969 +3 5689 3003 2927 +3 3002 5689 2926 +3 5689 3002 2999 +3 2980 2999 3002 +3 5675 2969 2926 +3 1023 2921 5675 +3 2969 5675 2922 +3 2922 5674 5673 +3 2927 2926 5689 +3 2969 5673 3017 +3 5673 5674 2968 +3 5664 1023 5675 +3 2999 3001 5689 +3 2927 5664 2926 +3 5664 5675 2926 +3 2968 3017 5673 +3 2921 5674 2922 +3 2921 2922 5675 +3 6789 5674 2921 +3 1441 2103 2105 +3 2098 5918 6187 +3 2103 6179 5918 +3 6187 5918 7048 +3 6179 7048 5918 +3 5917 2105 5918 +3 2103 5918 2105 +3 2098 5917 5918 +3 4923 2105 5917 +3 6179 6180 7048 +3 2897 4429 5656 +3 2901 5656 4429 +3 6045 4429 2897 +3 2901 4429 948 +3 1163 4052 3149 +3 4052 4059 4064 +3 4059 4052 1163 +3 3889 4025 1157 +3 1163 3149 6575 +3 4134 6575 3149 +3 4134 1158 6575 +3 3889 1157 6967 +3 6967 1163 6575 +3 1158 6967 6575 +3 1157 1163 6967 +3 4025 4059 1157 +3 1157 4059 1163 +3 3883 912 914 +3 6920 912 3883 +3 6920 3851 912 +3 3870 6616 6617 +3 914 6617 6616 +3 3870 3869 6616 +3 6616 6920 3883 +3 914 6616 3883 +3 3869 6920 6616 +3 3870 3881 3869 +3 3135 6617 914 +3 3880 6617 3135 +3 5884 3870 6617 +3 3880 5884 6617 +3 3886 5884 3880 +3 3886 3880 6924 +3 6924 6925 3886 +3 3884 3881 5884 +3 3886 3884 5884 +3 3870 5884 3881 +3 6905 3165 3750 +3 5504 2010 2011 +3 2009 2013 1643 +3 2005 5505 2011 +3 1999 1643 2013 +3 2011 2010 1268 +3 2013 1980 1999 +3 1269 2014 1267 +3 1256 1254 1255 +3 1256 6549 1254 +3 1268 1269 1267 +3 1256 2010 6549 +3 5504 6549 2010 +3 5504 2009 1643 +3 2011 2013 2009 +3 2011 2009 5504 +3 1979 2012 1980 +3 1980 2012 1999 +3 2011 5505 2013 +3 1980 2013 5505 +3 1979 1980 5505 +3 2005 1268 1267 +3 2011 1268 2005 +3 1256 1269 2010 +3 1269 1256 2014 +3 1268 2010 1269 +3 2014 1256 1255 +3 1589 1525 1590 +3 1584 1590 1525 +3 1560 1525 6607 +3 1589 6607 1525 +3 4655 4653 2887 +3 3959 3980 6436 +3 4653 4428 4640 +3 1840 5455 1844 +3 1842 1844 5455 +3 1844 6557 1840 +3 5454 1840 6557 +3 1873 1870 1861 +3 5476 1795 5515 +3 4902 1795 5476 +3 5476 5515 1323 +3 6166 4902 5476 +3 6166 5476 1914 +3 1323 1325 5476 +3 1847 1837 1850 +3 1370 1850 1837 +3 1381 1371 1370 +3 5456 1381 1370 +3 4905 1837 1847 +3 1848 5460 1838 +3 1851 5456 1837 +3 1837 1848 5461 +3 1920 5360 5456 +3 1837 5456 1370 +3 1920 5456 5480 +3 1851 5480 5456 +3 5360 1381 5456 +3 4905 1848 1837 +3 1851 1837 5461 +3 1851 4898 5480 +3 1839 1838 5460 +3 1851 5461 5926 +3 5461 1848 1838 +3 5460 1848 6556 +3 6556 5442 5460 +3 6556 1848 4905 +3 1851 5926 4898 +3 4899 4898 5926 +3 4899 5926 1838 +3 1838 1839 4899 +3 1777 4899 4900 +3 4900 4899 1839 +3 1943 2069 1940 +3 3333 3332 2172 +3 1870 1395 1357 +3 4911 1870 1873 +3 1289 1316 1863 +3 1863 1395 1870 +3 1395 1316 1900 +3 1395 1863 1316 +3 1289 6169 6166 +3 4911 1863 1870 +3 1289 1863 6169 +3 1914 1289 6166 +3 1289 5350 1316 +3 1357 1395 1900 +3 5350 1914 6693 +3 1317 5350 6693 +3 1289 1914 5350 +3 1914 1325 6693 +3 1863 4911 6169 +3 1794 6169 4911 +3 1146 3984 4032 +3 4023 4032 3984 +3 1146 4032 4031 +3 3333 5780 5781 +3 4400 4399 600 +3 4299 4399 4400 +3 1126 1145 4009 +3 4009 3969 1126 +3 1126 1127 1145 +3 1145 5345 4009 +3 4087 4090 4074 +3 3779 3356 3787 +3 3846 3839 889 +3 889 3848 3845 +3 889 3839 3848 +3 3845 3848 3241 +3 3850 3849 3835 +3 3135 913 3136 +3 1123 4052 1122 +3 4071 4052 1123 +3 3149 4052 4071 +3 1103 4095 4087 +3 4396 4392 991 +3 4419 2896 2897 +3 2896 4419 4418 +3 3851 3835 912 +3 930 929 3967 +3 6929 5084 5889 +3 3359 5086 3779 +3 3359 5084 5086 +3 3356 3779 5086 +3 6929 5085 5084 +3 3359 5889 5084 +3 6253 3356 5086 +3 5086 5084 6253 +3 5085 3360 6253 +3 5084 5085 6253 +3 3356 6253 3357 +3 5298 5297 5289 +3 5299 4181 4242 +3 5289 4818 4737 +3 5284 4737 4818 +3 656 6130 5289 +3 4737 5300 5298 +3 4737 5284 5300 +3 4181 5299 5297 +3 4818 6131 5284 +3 6131 4818 6129 +3 4818 6130 6258 +3 6130 4818 5289 +3 6129 4818 5105 +3 4818 6258 5105 +3 5289 4737 5298 +3 1841 1842 1832 +3 1844 1842 1841 +3 1841 6557 1844 +3 4087 4086 1103 +3 3866 845 931 +3 3866 3888 845 +3 3887 3888 3866 +3 846 931 845 +3 930 5936 846 +3 931 846 5936 +3 1614 1613 1400 +3 1480 1641 5920 +3 1621 1550 1480 +3 5431 1481 1641 +3 5431 1641 1480 +3 1481 5495 1641 +3 1481 5431 1613 +3 1613 1614 1481 +3 1636 5495 1481 +3 1636 1481 1614 +3 1401 1614 1400 +3 1635 5501 5500 +3 5502 1641 5501 +3 1635 5502 5501 +3 1641 5502 5920 +3 1549 5416 1550 +3 1400 1608 1616 +3 1400 1616 1401 +3 1608 1577 1616 +3 1608 1549 1577 +3 5429 1549 1608 +3 5416 5429 1634 +3 5416 1549 5429 +3 1400 1634 5429 +3 1608 1400 5429 +3 1634 5431 1480 +3 1634 1480 5416 +3 1550 5416 1480 +3 1400 1613 5431 +3 5431 1634 1400 +3 1876 5464 1874 +3 1358 1876 1874 +3 1358 1355 1876 +3 1878 5464 5465 +3 1876 5465 5464 +3 1878 6686 5464 +3 1874 5464 6686 +3 1876 6740 5465 +3 1824 5465 6740 +3 949 2865 985 +3 4416 4424 2714 +3 950 4651 4416 +3 4416 4651 2893 +3 2893 6087 4416 +3 4424 4416 6087 +3 4393 5153 4416 +3 4416 2714 4393 +3 949 5153 4393 +3 6773 4654 4640 +3 2887 4640 4654 +3 4640 2887 4653 +3 1938 1849 1850 +3 1918 5484 1850 +3 1849 5485 1847 +3 1850 1849 1847 +3 1850 5484 1938 +3 1261 2035 2028 +3 1262 1261 2028 +3 1465 1557 2040 +3 1465 2040 1995 +3 2040 1557 2050 diff --git a/Shape_detection/test/Shape_detection/test_region_growing_basic.cpp b/Shape_detection/test/Shape_detection/test_region_growing_basic.cpp index 791ac71a32f..14246ea65f4 100644 --- a/Shape_detection/test/Shape_detection/test_region_growing_basic.cpp +++ b/Shape_detection/test/Shape_detection/test_region_growing_basic.cpp @@ -37,6 +37,16 @@ int main(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/point_set_2.xyz"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file point_set_2.xyz!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + assert(false); + return EXIT_FAILURE; + } + Input_range input_range; FT a, b, c, d, e, f; diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_cube.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_cube.cpp index c2ce454ccb7..4b97bd2f01d 100644 --- a/Shape_detection/test/Shape_detection/test_region_growing_on_cube.cpp +++ b/Shape_detection/test/Shape_detection/test_region_growing_on_cube.cpp @@ -42,6 +42,15 @@ bool test_region_growing_on_cube(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/cube.off"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file cube.off!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + return false; + } + Polyhedron polyhedron; in >> polyhedron; diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_degenerated_mesh.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_degenerated_mesh.cpp new file mode 100644 index 00000000000..c674749d4a1 --- /dev/null +++ b/Shape_detection/test/Shape_detection/test_region_growing_on_degenerated_mesh.cpp @@ -0,0 +1,132 @@ +// STL includes. +#include +#include +#include +#include +#include +#include + +// CGAL includes. +#include +#include + +#include +#include +#include + +#include +#include + +namespace SD = CGAL::Shape_detection; + +template +bool test_region_growing_on_degenerated_mesh(int argc, char *argv[]) { + + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + + using Surface_mesh = CGAL::Surface_mesh; + using Face_range = typename Surface_mesh::Face_range; + + using Neighbor_query = SD::Polygon_mesh::One_ring_neighbor_query; + using Region_type = SD::Polygon_mesh::Least_squares_plane_fit_region; + using Region_growing = SD::Region_growing; + + // Default parameter values for the data file degenerated.off. + const FT distance_threshold = FT(1); + const FT angle_threshold = FT(45); + const std::size_t min_region_size = 5; + + // Load data. + std::ifstream in(argc > 1 ? argv[1] : "data/degenerated.off"); + CGAL::set_ascii_mode(in); + + if (!in) { + std::cout << + "Error: cannot read the file degenerated.off!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + return false; + } + + Surface_mesh surface_mesh; + in >> surface_mesh; + + in.close(); + const Face_range face_range = faces(surface_mesh); + + assert(face_range.size() == 13477); + if (face_range.size() != 13477) + return false; + + // Create parameter classes. + Neighbor_query neighbor_query(surface_mesh); + + using Vertex_to_point_map = typename Region_type::Vertex_to_point_map; + const Vertex_to_point_map vertex_to_point_map( + get(CGAL::vertex_point, surface_mesh)); + + Region_type region_type( + surface_mesh, + distance_threshold, angle_threshold, min_region_size, + vertex_to_point_map); + + // Run region growing. + Region_growing region_growing( + face_range, neighbor_query, region_type); + + std::vector< std::vector > regions; + region_growing.detect(std::back_inserter(regions)); + + // Test data. + assert(regions.size() >= 265 && regions.size() <= 269); + if (regions.size() < 265 || regions.size() > 269) + return false; + + for (const auto& region : regions) + if (!region_type.is_valid_region(region)) + return false; + + std::vector unassigned_faces; + region_growing.unassigned_items(std::back_inserter(unassigned_faces)); + + assert(unassigned_faces.size() >= 501 && unassigned_faces.size() <= 521); + if (unassigned_faces.size() < 501 || unassigned_faces.size() > 521) + return false; + + return true; +} + +int main(int argc, char *argv[]) { + + // ------> + + bool cartesian_double_test_success = true; + if (!test_region_growing_on_degenerated_mesh< CGAL::Simple_cartesian >(argc, argv)) + cartesian_double_test_success = false; + + std::cout << "cartesian_double_test_success: " << cartesian_double_test_success << std::endl; + assert(cartesian_double_test_success); + + // ------> + + bool exact_inexact_test_success = true; + if (!test_region_growing_on_degenerated_mesh(argc, argv)) + exact_inexact_test_success = false; + + std::cout << "exact_inexact_test_success: " << exact_inexact_test_success << std::endl; + assert(exact_inexact_test_success); + + // ------> + + bool exact_exact_test_success = true; + if (!test_region_growing_on_degenerated_mesh(argc, argv)) + exact_exact_test_success = false; + + std::cout << "exact_exact_test_success: " << exact_exact_test_success << std::endl; + assert(exact_exact_test_success); + + const bool success = cartesian_double_test_success && exact_inexact_test_success && exact_exact_test_success; + return (success) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_2.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_2.cpp index 5814d7294c6..39efcd97799 100644 --- a/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_2.cpp +++ b/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_2.cpp @@ -46,6 +46,15 @@ bool test_region_growing_on_point_set_2(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/point_set_2.xyz"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file point_set_2.xyz!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + return false; + } + Input_range input_range; FT a, b, c, d, e, f; diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_2_with_sorting.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_2_with_sorting.cpp index 9ab1943d3a5..c3b2c40eebd 100644 --- a/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_2_with_sorting.cpp +++ b/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_2_with_sorting.cpp @@ -41,6 +41,16 @@ int main(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/point_set_2.xyz"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file point_set_2.xyz!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + assert(false); + return EXIT_FAILURE; + } + Input_range input_range; FT a, b, c, d, e, f; diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_3.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_3.cpp index 5667c32c5ad..f758f508ae5 100644 --- a/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_3.cpp +++ b/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_3.cpp @@ -45,6 +45,15 @@ bool test_region_growing_on_point_set_3(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/point_set_3.xyz"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file point_set_3.xyz!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + return false; + } + const bool with_normal_map = true; Input_range input_range(with_normal_map); diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_3_with_sorting.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_3_with_sorting.cpp index 4869de2b0b0..198e7031ff3 100644 --- a/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_3_with_sorting.cpp +++ b/Shape_detection/test/Shape_detection/test_region_growing_on_point_set_3_with_sorting.cpp @@ -41,6 +41,16 @@ int main(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/point_set_3.xyz"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file point_set_3.xyz!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + assert(false); + return EXIT_FAILURE; + } + const bool with_normal_map = true; Input_range input_range(with_normal_map); diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh.cpp index 9b161f1d1b2..80a3a6264d8 100644 --- a/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh.cpp +++ b/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh.cpp @@ -40,6 +40,15 @@ bool test_region_growing_on_polygon_mesh(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/polygon_mesh.off"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file polygon_mesh.off!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + return false; + } + Surface_mesh surface_mesh; in >> surface_mesh; @@ -70,8 +79,8 @@ bool test_region_growing_on_polygon_mesh(int argc, char *argv[]) { region_growing.detect(std::back_inserter(regions)); // Test data. - assert(regions.size() >= 327 && regions.size() <= 331); - if (regions.size() < 327 || regions.size() > 331) + assert(regions.size() >= 324 && regions.size() <= 328); + if (regions.size() < 324 || regions.size() > 328) return false; for (const auto& region : regions) @@ -81,8 +90,8 @@ bool test_region_growing_on_polygon_mesh(int argc, char *argv[]) { std::vector unassigned_faces; region_growing.unassigned_items(std::back_inserter(unassigned_faces)); - assert(unassigned_faces.size() >= 908 && unassigned_faces.size() <= 928); - if (unassigned_faces.size() < 908 || unassigned_faces.size() > 928) + assert(unassigned_faces.size() >= 904 && unassigned_faces.size() <= 924); + if (unassigned_faces.size() < 904 || unassigned_faces.size() > 924) return false; return true; diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh_with_sorting.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh_with_sorting.cpp index 6cfe0900a82..244f73d0e79 100644 --- a/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh_with_sorting.cpp +++ b/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh_with_sorting.cpp @@ -38,6 +38,16 @@ int main(int argc, char *argv[]) { std::ifstream in(argc > 1 ? argv[1] : "data/polygon_mesh.off"); CGAL::set_ascii_mode(in); + if (!in) { + std::cout << + "Error: cannot read the file polygon_mesh.off!" << std::endl; + std::cout << + "You can either create a symlink to the data folder or provide this file by hand." + << std::endl << std::endl; + assert(false); + return EXIT_FAILURE; + } + Polygon_mesh polygon_mesh; in >> polygon_mesh; @@ -79,7 +89,7 @@ int main(int argc, char *argv[]) { region_growing.release_memory(); assert(regions.size() >= 324 && regions.size() <= 328); - const bool exact_exact_test_success = (regions.size() >= 323 && regions.size() <= 327); + const bool exact_exact_test_success = (regions.size() >= 324 && regions.size() <= 328); std::cout << "exact_exact_test_success: " << exact_exact_test_success << std::endl; const bool success = exact_exact_test_success; diff --git a/Solver_interface/examples/Solver_interface/CMakeLists.txt b/Solver_interface/examples/Solver_interface/CMakeLists.txt index e8cc264ec88..13ad3314c8e 100644 --- a/Solver_interface/examples/Solver_interface/CMakeLists.txt +++ b/Solver_interface/examples/Solver_interface/CMakeLists.txt @@ -14,24 +14,21 @@ if ( CGAL_FOUND ) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) create_single_source_cgal_program( "singular_value_decomposition.cpp" ) + CGAL_target_use_Eigen(singular_value_decomposition) create_single_source_cgal_program( "sparse_solvers.cpp" ) + CGAL_target_use_Eigen(sparse_solvers) + create_single_source_cgal_program( "diagonalize_matrix.cpp" ) + CGAL_target_use_Eigen(diagonalize_matrix) endif() - create_single_source_cgal_program( "diagonalize_matrix.cpp" ) create_single_source_cgal_program( "mixed_integer_program.cpp" ) find_package( SCIP QUIET) if (SCIP_FOUND) - include_directories( BEFORE ${SCIP_INCLUDE_DIRS} ) - - target_link_libraries( mixed_integer_program PRIVATE ${SCIP_LIBRARIES} ) - - target_compile_definitions(mixed_integer_program PRIVATE -DCGAL_USE_SCIP) - + CGAL_target_use_SCIP(mixed_integer_program) message("SCIP found and used") else() @@ -39,13 +36,8 @@ if ( CGAL_FOUND ) find_package( GLPK QUIET) if (GLPK_FOUND) - - include_directories( BEFORE ${GLPK_INCLUDE_DIR} ) - - target_link_libraries( mixed_integer_program PRIVATE ${GLPK_LIBRARIES} ) - - target_compile_definitions(mixed_integer_program PRIVATE -DCGAL_USE_GLPK) - + + CGAL_target_use_GLPK(mixed_integer_program) message("GLPK found and used") else() diff --git a/Spatial_searching/benchmark/Spatial_searching/CMakeLists.txt b/Spatial_searching/benchmark/Spatial_searching/CMakeLists.txt index ca8157f8a8e..adb47481272 100644 --- a/Spatial_searching/benchmark/Spatial_searching/CMakeLists.txt +++ b/Spatial_searching/benchmark/Spatial_searching/CMakeLists.txt @@ -13,9 +13,6 @@ if ( CGAL_FOUND ) include(${CGAL_USE_FILE}) find_package(Eigen3 3.1.91) #(requires 3.2.0 or greater) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -endif() include_directories (BEFORE "include") @@ -33,6 +30,23 @@ endif() create_single_source_cgal_program( "nn3nanoflan.cpp" ) create_single_source_cgal_program( "sizeof.cpp" ) create_single_source_cgal_program( "deque.cpp" ) + foreach(target + Compare_ANN_STANN_CGAL + nanoflan + binary + nearest_neighbor_searching_50 + nearest_neighbor_searching_inplace_50 + Nearest_neighbor_searching + Nearest_neighbor_searching_2D + Nearest_neighbor_searching_2D_user_defined + Split_data + nn3cgal + nn4cgal + nn3nanoflan + sizeof + deque) + CGAL_target_use_Eigen(${target}) + endforeach() else() diff --git a/Spatial_searching/examples/Spatial_searching/CMakeLists.txt b/Spatial_searching/examples/Spatial_searching/CMakeLists.txt index c4a335960b5..f60f06a9bc6 100644 --- a/Spatial_searching/examples/Spatial_searching/CMakeLists.txt +++ b/Spatial_searching/examples/Spatial_searching/CMakeLists.txt @@ -18,9 +18,6 @@ if ( NOT CGAL_FOUND ) endif() find_package(Eigen3 3.1.91) #(requires 3.2.0 or greater) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -endif() if (MSVC) # Turn off VC++ warning @@ -68,8 +65,10 @@ create_single_source_cgal_program( "weighted_Minkowski_distance.cpp" ) if (EIGEN3_FOUND) create_single_source_cgal_program( "fuzzy_range_query.cpp" ) + CGAL_target_use_Eigen(fuzzy_range_query) create_single_source_cgal_program( "general_neighbor_searching.cpp" ) + CGAL_target_use_Eigen(general_neighbor_searching) else() diff --git a/Spatial_searching/examples/Spatial_searching/searching_polyhedron_vertices_with_fuzzy_sphere.cpp b/Spatial_searching/examples/Spatial_searching/searching_polyhedron_vertices_with_fuzzy_sphere.cpp index 05481a615dd..70a53e948ec 100644 --- a/Spatial_searching/examples/Spatial_searching/searching_polyhedron_vertices_with_fuzzy_sphere.cpp +++ b/Spatial_searching/examples/Spatial_searching/searching_polyhedron_vertices_with_fuzzy_sphere.cpp @@ -30,19 +30,15 @@ int main(int argc, char* argv[]) in >> mesh; Vertex_point_pmap vppmap = get(CGAL::vertex_point,mesh); + Traits traits(vppmap); + Tree tree(vertices(mesh).begin(), vertices(mesh).end(), Splitter(), traits); - // Insert number_of_data_points in the tree - Tree tree(vertices(mesh).begin(), - vertices(mesh).end(), - Splitter(), - Traits(vppmap) - ); Point_3 query(0.0, 0.0, 0.0); double radius = 0.5; double epsilon = 0.01; // search vertices - CGAL::Fuzzy_sphere fz(query, radius, epsilon); + CGAL::Fuzzy_sphere fz(query, radius, epsilon, traits); //collect vertices that are inside the sphere std::list result; diff --git a/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_traits_2_aux.h b/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_traits_2_aux.h index f96399f697c..e38aa809e1f 100644 --- a/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_traits_2_aux.h +++ b/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_traits_2_aux.h @@ -106,98 +106,23 @@ public: Exceptionless_filtered_construction() {} - template + template result_type - operator()(const A1 &a1) const + operator()(A&& ... a) const { try { Protect_FPU_rounding P; - FC_result_type fr = Filter_construction(To_Filtered(a1)); + FC_result_type fr = Filter_construction(To_Filtered(std::forward
(a))...); if ( fr ) return From_Filtered(fr); } catch (Uncertain_conversion_exception&) {} Protect_FPU_rounding P(CGAL_FE_TONEAREST); - EC_result_type er = Exact_construction(To_Exact(a1)) ; + EC_result_type er = Exact_construction(To_Exact(std::forward(a))...) ; return From_Exact(er); } - - template - result_type - operator()(const A1 &a1, const A2 &a2) const - { - try - { - Protect_FPU_rounding P; - FC_result_type fr = Filter_construction(To_Filtered(a1),To_Filtered(a2)); - if ( fr ) - return From_Filtered(fr); - } - catch (Uncertain_conversion_exception&) {} - - Protect_FPU_rounding P(CGAL_FE_TONEAREST); - EC_result_type er = Exact_construction(To_Exact(a1), To_Exact(a2)) ; - return From_Exact(er); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3) const - { - try - { - Protect_FPU_rounding P; - FC_result_type fr = Filter_construction(To_Filtered(a1),To_Filtered(a2),To_Filtered(a3)); - if ( fr ) - return From_Filtered(fr); - } - catch (Uncertain_conversion_exception&) {} - - Protect_FPU_rounding P(CGAL_FE_TONEAREST); - EC_result_type er = Exact_construction(To_Exact(a1), To_Exact(a2), To_Exact(a3)) ; - return From_Exact(er); - - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) const - { - try - { - Protect_FPU_rounding P; - FC_result_type fr = Filter_construction(To_Filtered(a1),To_Filtered(a2),To_Filtered(a3),To_Filtered(a4)); - if ( fr ) - return From_Filtered(fr); - } - catch (Uncertain_conversion_exception&) {} - - Protect_FPU_rounding P(CGAL_FE_TONEAREST); - EC_result_type er = Exact_construction(To_Exact(a1), To_Exact(a2), To_Exact(a3), To_Exact(a4)) ; - return From_Exact(er); - - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5) const - { - try - { - Protect_FPU_rounding P; - FC_result_type fr = Filter_construction(To_Filtered(a1),To_Filtered(a2),To_Filtered(a3),To_Filtered(a4),To_Filtered(a5)); - if ( fr ) - return From_Filtered(fr); - } - catch (Uncertain_conversion_exception&) {} - - Protect_FPU_rounding P(CGAL_FE_TONEAREST); - EC_result_type er = Exact_construction(To_Exact(a1), To_Exact(a2), To_Exact(a3), To_Exact(a4), To_Exact(a5)) ; - return From_Exact(er); - - } }; diff --git a/Straight_skeleton_2/include/CGAL/Unfiltered_predicate_adaptor.h b/Straight_skeleton_2/include/CGAL/Unfiltered_predicate_adaptor.h index 73311ab7aeb..16f2714a06e 100644 --- a/Straight_skeleton_2/include/CGAL/Unfiltered_predicate_adaptor.h +++ b/Straight_skeleton_2/include/CGAL/Unfiltered_predicate_adaptor.h @@ -45,111 +45,14 @@ public: : Certified_approx_predicate(o1, o2) {} - template + template result_type - operator()(const A1 &a1) const + operator()(A&& ... a) const #ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG ; #else { - return static_cast(Certified_approx_predicate(a1)); - } -#endif - - template - result_type - operator()(const A1 &a1, const A2 &a2) const -#ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG - ; -#else - { - return static_cast(Certified_approx_predicate(a1, a2)); - } -#endif - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3) const -#ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG - ; -#else - { - return static_cast(Certified_approx_predicate(a1, a2, a3)); - } -#endif - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) const -#ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG - ; -#else - { - return static_cast(Certified_approx_predicate(a1, a2, a3,a4)); - } -#endif - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5) const -#ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG - ; -#else - { - return static_cast(Certified_approx_predicate(a1, a2, a3, a4, a5)); - } -#endif - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6) const -#ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG - ; -#else - { - return static_cast(Certified_approx_predicate(a1, a2, a3, a4, a5, a6)); - } -#endif - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6, const A7 &a7) const -#ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG - ; -#else - { - return static_cast(Certified_approx_predicate(a1, a2, a3, a4, a5, a6, a7)); - } -#endif - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6, const A7 &a7, const A8 &a8) const -#ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG - ; -#else - { - return static_cast(Certified_approx_predicate(a1, a2, a3, a4, a5, a6, a7, a8)); - } -#endif - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6, const A7 &a7, const A8 &a8, - const A9 &a9 ) const -#ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG - ; -#else - { - return static_cast(Certified_approx_predicate(a1, a2, a3, a4, a5, a6, a7, a8, a9)); + return static_cast(Certified_approx_predicate(std::forward(a)...)); } #endif @@ -158,90 +61,12 @@ public: #ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG template - template + template typename Unfiltered_predicate_adaptor::result_type Unfiltered_predicate_adaptor:: - operator()(const A1 &a1) const + operator()(A&& ... a) const { - return static_cast(Certified_approx_predicate(a1)); -} - -template - template -typename Unfiltered_predicate_adaptor::result_type -Unfiltered_predicate_adaptor:: - operator()(const A1 &a1, const A2 &a2) const -{ - return static_cast(Certified_approx_predicate(a1, a2)); -} - -template - template -typename Unfiltered_predicate_adaptor::result_type -Unfiltered_predicate_adaptor:: - operator()(const A1 &a1, const A2 &a2, const A3 &a3) const -{ - return static_cast(Certified_approx_predicate(a1, a2, a3)); -} - -template - template -typename Unfiltered_predicate_adaptor::result_type -Unfiltered_predicate_adaptor:: - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) const -{ - return static_cast(Certified_approx_predicate(a1, a2, a3, a4)); -} - -template - template -typename Unfiltered_predicate_adaptor::result_type -Unfiltered_predicate_adaptor:: - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5) const -{ - return static_cast(Certified_approx_predicate(a1, a2, a3, a4, a5)); -} - -template - template -typename Unfiltered_predicate_adaptor::result_type -Unfiltered_predicate_adaptor:: - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6) const -{ - return static_cast(Certified_approx_predicate(a1, a2, a3, a4, a5, a6)); -} - -template - template -typename Unfiltered_predicate_adaptor::result_type -Unfiltered_predicate_adaptor:: - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6, const A7 &a7 ) const -{ - return static_cast(Certified_approx_predicate(a1, a2, a3, a4, a5, a6, a7)); -} - -template - template -typename Unfiltered_predicate_adaptor::result_type -Unfiltered_predicate_adaptor:: - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6, const A7 &a7, const A8 &a8 ) const -{ - return static_cast(Certified_approx_predicate(a1, a2, a3, a4, a5, a6, a7, a8)); -} - -template - template -typename Unfiltered_predicate_adaptor::result_type -Unfiltered_predicate_adaptor:: - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6, const A7 &a7, const A8 &a8, - const A9 &a9 ) const -{ - return static_cast(Certified_approx_predicate(a1, a2, a3, a4, a5, a6, a7, a8, a9)); + return static_cast(Certified_approx_predicate(std::forward(a)...)); } #endif diff --git a/Stream_support/include/CGAL/IO/read_3mf.h b/Stream_support/include/CGAL/IO/read_3mf.h index ac1b48459a8..7a6def1f2fe 100644 --- a/Stream_support/include/CGAL/IO/read_3mf.h +++ b/Stream_support/include/CGAL/IO/read_3mf.h @@ -65,12 +65,6 @@ bool extract_soups (NMR::PLib3MFModelMeshObject *pMeshObject, pBuffer.resize(nNeededChars + 1); hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, &pBuffer[0], nNeededChars + 1, NULL); pBuffer[nNeededChars] = 0; - std::string temp(&pBuffer[0]); - if(temp.find("_cgal_pc") != std::string::npos - || temp.find("_cgal_pl")!= std::string::npos) //ignore point clouds and polylines - { - return false; - } name = std::string(&pBuffer[0]); } else @@ -120,151 +114,6 @@ bool extract_soups (NMR::PLib3MFModelMeshObject *pMeshObject, return true; } -template -bool extract_polylines (NMR::PLib3MFModelMeshObject *pMeshObject, - const NMR::MODELTRANSFORM& , - PointRange& points, - PolygonRange&, - ColorRange& colors, - std::string& name) { - typedef typename PointRange::value_type Point_3; - - HRESULT hResult; - DWORD nNeededChars; - std::vector pBuffer; - // Retrieve Mesh Name Length - hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, NULL, 0, &nNeededChars); - if (hResult != LIB3MF_OK) - { - points.resize(0); - std::cerr<<"Error during name extraction."; - return false; - } - - // Retrieve Mesh Name - if (nNeededChars > 0) { - pBuffer.resize(nNeededChars + 1); - hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, &pBuffer[0], nNeededChars + 1, NULL); - pBuffer[nNeededChars] = 0; - std::string temp(&pBuffer[0]); - if(temp.find("_cgal_pl")== std::string::npos) //ignore not polylines - { - points.resize(0); - return false; - } - name = std::string(&pBuffer[0]); - } - else - { - points.resize(0); - return false; - } - - NMR::PLib3MFPropertyHandler * pPropertyHandler; - hResult = NMR::lib3mf_meshobject_createpropertyhandler(pMeshObject, &pPropertyHandler); - if (hResult != LIB3MF_OK) { - DWORD nErrorMessage; - LPCSTR pszErrorMessage; - std::cerr << "could not create property handler: " << std::hex << hResult << std::endl; - NMR::lib3mf_getlasterror(pMeshObject, &nErrorMessage, &pszErrorMessage); - std::cerr << "error #" << std::hex << nErrorMessage << ": " << pszErrorMessage << std::endl; - NMR::lib3mf_release(pMeshObject); - return false; - } - - points.resize(points.size()-3);//ignore dummy_vertices - for(DWORD vid = 0; vid < points.size(); ++vid) - { - NMR::MODELMESHVERTEX pVertex; - NMR::lib3mf_meshobject_getvertex(pMeshObject, vid+3, &pVertex); - points[vid] = - Point_3(pVertex.m_fPosition[0], - pVertex.m_fPosition[1], - pVertex.m_fPosition[2]); - } - - NMR::MODELMESH_TRIANGLECOLOR_SRGB pColor; - NMR::lib3mf_propertyhandler_getcolor(pPropertyHandler, 0, &pColor);//get color of the dummy triangle - NMR::MODELMESHCOLOR_SRGB mColor = pColor.m_Colors[0]; - colors[0]=CGAL::Color(mColor.m_Red, mColor.m_Green, - mColor.m_Blue, mColor.m_Alpha); - return true; -} - -template -bool extract_point_clouds (NMR::PLib3MFModelMeshObject *pMeshObject, - const NMR::MODELTRANSFORM&, - PointRange& points, - PolygonRange&, - ColorRange& colors, - std::string& name) { - typedef typename PointRange::value_type Point_3; - - HRESULT hResult; - DWORD nNeededChars; - std::vector pBuffer; - // Retrieve Mesh Name Length - hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, NULL, 0, &nNeededChars); - if (hResult != LIB3MF_OK) - { - std::cerr<<"Error during name extraction."; - points.resize(0); - return false; - } - - // Retrieve Mesh Name - if (nNeededChars > 0) { - pBuffer.resize(nNeededChars + 1); - hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, &pBuffer[0], nNeededChars + 1, NULL); - pBuffer[nNeededChars] = 0; - std::string temp(&pBuffer[0]); - if(temp.find("_cgal_pc")== std::string::npos) //ignore not point_cloud - { - points.resize(0); - return false; - } - name = std::string(&pBuffer[0]); - } - else{ - points.resize(0); - return false; - } - - NMR::PLib3MFPropertyHandler * pPropertyHandler; - hResult = NMR::lib3mf_meshobject_createpropertyhandler(pMeshObject, &pPropertyHandler); - if (hResult != LIB3MF_OK) { - DWORD nErrorMessage; - LPCSTR pszErrorMessage; - std::cerr << "could not create property handler: " << std::hex << hResult << std::endl; - NMR::lib3mf_getlasterror(pMeshObject, &nErrorMessage, &pszErrorMessage); - std::cerr << "error #" << std::hex << nErrorMessage << ": " << pszErrorMessage << std::endl; - NMR::lib3mf_release(pMeshObject); - return -1; - } - - points.resize(points.size()-3);//ignore dummy_vertices - for(DWORD vid = 0; vid < points.size(); ++vid) - { - NMR::MODELMESHVERTEX pVertex; - NMR::lib3mf_meshobject_getvertex(pMeshObject, vid+3, &pVertex); - points[vid] = - Point_3(pVertex.m_fPosition[0], - pVertex.m_fPosition[1], - pVertex.m_fPosition[2]); - } - - NMR::MODELMESH_TRIANGLECOLOR_SRGB pColor; - NMR::lib3mf_propertyhandler_getcolor(pPropertyHandler, 0, &pColor);//get color of the dummy triangle - NMR::MODELMESHCOLOR_SRGB mColor = pColor.m_Colors[0]; - colors[0]=CGAL::Color(mColor.m_Red, mColor.m_Green, - mColor.m_Blue, mColor.m_Alpha); - return true; -} - template @@ -589,6 +438,8 @@ int read_from_3mf(const std::string& file_name, PointRanges& all_points, * \param names will contain the name of each mesh in `file_name` if any. * If the i'th mesh has no name, it will be called "Unknown Mesh" in names. * \return the number of soups read. + * + * \attention Only versions inferior to 2.0 of lib3mf are supported. */ template int read_triangle_soups_from_3mf(const std::string& file_name, PointRanges& all_points, @@ -605,43 +456,6 @@ int read_triangle_soups_from_3mf(const std::string& file_name, PointRanges& all_ all_colors, names, extract_soups); } - -template -int read_polylines_from_3mf(const std::string& file_name, - PointRanges& all_points, - ColorRanges& all_colors, - std::vector& names - ) -{ - typedef typename PointRanges::value_type PointRange; - typedef std::vector Polygon; - typedef std::vector PolygonRange; - typedef std::vector ColorRange; - std::vector all_polygons; - return read_from_3mf, - std::vector, PointRange, PolygonRange, ColorRange> - (file_name, all_points, all_polygons, all_colors, names, - extract_polylines); -} - - -template -int read_point_clouds_from_3mf(const std::string& file_name, - PointRanges& all_points, - ColorRanges& all_colors, - std::vector& names - ) -{ - typedef typename PointRanges::value_type PointRange; - typedef std::vector Polygon; - typedef std::vector PolygonRange; - typedef std::vector ColorRange; - std::vector all_polygons; - return read_from_3mf, - std::vector, PointRange, PolygonRange, ColorRange> - (file_name, all_points, all_polygons, all_colors, names, - extract_point_clouds); -} }//end CGAL #endif // CGAL_IO_READ_3MF_H diff --git a/Stream_support/include/CGAL/IO/write_3mf.h b/Stream_support/include/CGAL/IO/write_3mf.h index f6c2a73689e..4aa6ecbf866 100644 --- a/Stream_support/include/CGAL/IO/write_3mf.h +++ b/Stream_support/include/CGAL/IO/write_3mf.h @@ -359,6 +359,8 @@ bool write_polyline_to_model(const PointRange& points, * soups in `file_name`. * \param names will contains the name of each mesh in `file_name`. * \return `true` if the writing is successful, `false` otherwise. + * + * \attention Only versions inferior to 2.0 of lib3mf are supported. */ template bool write_triangle_soups_to_3mf(const std::string& file_name, @@ -406,6 +408,8 @@ bool write_triangle_soups_to_3mf(const std::string& file_name, * must be available for each mesh. * \param names will contains the name of each mesh in `file_name`. * \return `true` if the writing is successful, `false` otherwise. + * + * \attention Only versions inferior to 2.0 of lib3mf are supported. */ template bool write_triangle_meshes_to_3mf(const std::string& file_name, diff --git a/Stream_support/test/Stream_support/CMakeLists.txt b/Stream_support/test/Stream_support/CMakeLists.txt index d97144f1b86..93787ca49f6 100644 --- a/Stream_support/test/Stream_support/CMakeLists.txt +++ b/Stream_support/test/Stream_support/CMakeLists.txt @@ -18,7 +18,7 @@ if ( CGAL_FOUND ) file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) if ( "${cppfile}" STREQUAL "test_3mf_to_sm.cpp" ) - if(3MF_LIBRARIES AND 3MF_INCLUDE_DIR) + if(3MF_LIBRARIES AND 3MF_INCLUDE_DIR AND EXISTS "${3MF_INCLUDE_DIR}/Model/COM/NMR_DLLInterfaces.h") include_directories(${3MF_INCLUDE_DIR}) create_single_source_cgal_program( "${cppfile}" ) target_link_libraries(test_3mf_to_sm PRIVATE ${3MF_LIBRARIES}) diff --git a/Stream_support/test/Stream_support/test_3mf_to_sm.cpp b/Stream_support/test/Stream_support/test_3mf_to_sm.cpp index 654cae33bb0..4f4e94feb7e 100644 --- a/Stream_support/test/Stream_support/test_3mf_to_sm.cpp +++ b/Stream_support/test/Stream_support/test_3mf_to_sm.cpp @@ -51,33 +51,6 @@ int main(int argc, char** argv) ofs << mesh; ofs.close(); } - int nb_polylines = - CGAL::read_polylines_from_3mf(file_name, all_points, all_colors, names); - - if(nb_polylines == 0) - std::cout<<"No polyline found."< reindex; + reindex.resize (sm.num_vertices()); + int n = 0; for(VIndex vi : sm.vertices()) { for (std::size_t i = 0; i < vprinters.size(); ++ i) @@ -2297,22 +2300,23 @@ private: //------------------------------------------------------- private data } if (get_mode (os) == IO::ASCII) os << std::endl; + reindex[std::size_t(vi)] = n ++; } - std::vector polygon; + std::vector polygon; for(FIndex fi : sm.faces()) { // Get list of vertex indices polygon.clear(); - for(HIndex hi : halfedges_around_face(halfedge(fi, sm), sm)) - polygon.push_back (sm.target(hi)); + for(VIndex vi : CGAL::vertices_around_face(sm.halfedge(fi),sm)) + polygon.push_back (reindex[std::size_t(vi)]); if (get_mode (os) == IO::ASCII) { os << polygon.size() << " "; for (std::size_t i = 0; i < polygon.size(); ++ i) - os << int(polygon[i]) << " "; + os << polygon[i] << " "; } else { @@ -2320,7 +2324,7 @@ private: //------------------------------------------------------- private data os.write (reinterpret_cast(&size), sizeof(size)); for (std::size_t i = 0; i < polygon.size(); ++ i) { - int idx = int(polygon[i]); + int idx = polygon[i]; os.write (reinterpret_cast(&idx), sizeof(idx)); } } @@ -2340,12 +2344,12 @@ private: //------------------------------------------------------- private data { for(EIndex ei : sm.edges()) { + int v0 = reindex[std::size_t(sm.vertex(ei,0))]; + int v1 = reindex[std::size_t(sm.vertex(ei,1))]; if (get_mode (os) == IO::ASCII) - os << int(sm.vertex(ei,0)) << " " << int(sm.vertex(ei,1)) << " "; + os << v0 << " " << v1 << " "; else { - int v0 = int(sm.vertex(ei,0)); - int v1 = int(sm.vertex(ei,1)); os.write (reinterpret_cast(&v0), sizeof(v0)); os.write (reinterpret_cast(&v1), sizeof(v1)); } @@ -2366,12 +2370,12 @@ private: //------------------------------------------------------- private data { for(HIndex hi : sm.halfedges()) { + int source = reindex[std::size_t(sm.source(hi))]; + int target = reindex[std::size_t(sm.target(hi))]; if (get_mode (os) == IO::ASCII) - os << int(sm.source(hi)) << " " << int(sm.target(hi)) << " "; + os << source << " " << target << " "; else { - int source = int(sm.source(hi)); - int target = int(sm.target(hi)); os.write (reinterpret_cast(&source), sizeof(source)); os.write (reinterpret_cast(&target), sizeof(target)); } @@ -2457,6 +2461,7 @@ private: //------------------------------------------------------- private data is.setstate(std::ios::failbit); return false; } + is >> sm_skip_comments; is >> n >> f >> e; if(!is){ return false; @@ -2474,12 +2479,14 @@ private: //------------------------------------------------------- private data boost::tie(vnormal, created) = sm.template add_property_map("v:normal",Vector_3(0,0,0)); v_has_normals = true; } + std::string line; char ci; - for(int i=0; i < n; i++){ is >> sm_skip_comments; + std::getline(is, line); + std::istringstream iss(line); double x, y, z; - is >> iformat(x) >> iformat(y) >> iformat(z); + iss >> iformat(x) >> iformat(y) >> iformat(z); Vertex_index vi = sm.add_vertex(); put(vpm, vi, P(x, y, z)); @@ -2487,26 +2494,37 @@ private: //------------------------------------------------------- private data vertexmap[i] = vi; if(v_has_normals){ - is >> v; + if(!(iss >> v)) + { + std::cerr<<"This doesn't seem to be a correct NOFF file. Aborting."<> ci){ + std::getline(iss, col); + std::istringstream iss2(col); + if(iss2 >> ci){ bool created; boost::tie(vcolor, created) = sm.template add_property_map("v:color",CGAL::Color(0,0,0)); - std::istringstream iss2(col); - vcolor[vi] = File_scanner_OFF::get_color_from_line(iss2); + std::istringstream iss3(col); + vcolor[vi] = File_scanner_OFF::get_color_from_line(iss3); vcolored = true; } + else + { + std::cerr<<"This doesn't seem to be a correct COFF file. Aborting."< +#include +#include #include #include #include - #include #include @@ -215,13 +216,9 @@ public: // Index maps #ifndef DOXYGEN_RUNNING typedef typename Default::Get< - VIM, - typename boost::property_map::type - >::type Vertex_index_map; + VIM, typename CGAL::GetInitializedVertexIndexMap::type>::type Vertex_index_map; typedef typename Default::Get< - HIM, - typename boost::property_map::type - >::type Hedge_index_map; + HIM, typename CGAL::GetInitializedHalfedgeIndexMap::type>::type Hedge_index_map; #else /// vertex index map type typedef VIM Vertex_index_map; @@ -356,9 +353,10 @@ public: //vertex_point_map set by default Surface_mesh_deformation(Triangle_mesh& triangle_mesh, Vertex_index_map vertex_index_map, - Hedge_index_map hedge_index_map - ) - : m_triangle_mesh(triangle_mesh), vertex_index_map(vertex_index_map), hedge_index_map(hedge_index_map), + Hedge_index_map hedge_index_map) + : m_triangle_mesh(triangle_mesh), + vertex_index_map(vertex_index_map), + hedge_index_map(hedge_index_map), ros_id_map(std::vector(num_vertices(triangle_mesh), (std::numeric_limits::max)() )), is_roi_map(std::vector(num_vertices(triangle_mesh), false)), is_ctrl_map(std::vector(num_vertices(triangle_mesh), false)), @@ -374,10 +372,10 @@ public: //vertex_point_map and hedge_index_map set by default Surface_mesh_deformation(Triangle_mesh& triangle_mesh, - Vertex_index_map vertex_index_map - ) - : m_triangle_mesh(triangle_mesh), vertex_index_map(vertex_index_map), - hedge_index_map(get(boost::halfedge_index, triangle_mesh)), + Vertex_index_map vertex_index_map) + : m_triangle_mesh(triangle_mesh), + vertex_index_map(vertex_index_map), + hedge_index_map(CGAL::get_initialized_halfedge_index_map(triangle_mesh)), ros_id_map(std::vector(num_vertices(triangle_mesh), (std::numeric_limits::max)() )), is_roi_map(std::vector(num_vertices(triangle_mesh), false)), is_ctrl_map(std::vector(num_vertices(triangle_mesh), false)), @@ -393,8 +391,8 @@ public: //vertex_point_map, hedge_index_map and vertex_index_map set by default Surface_mesh_deformation(Triangle_mesh& triangle_mesh) : m_triangle_mesh(triangle_mesh), - vertex_index_map(get(boost::vertex_index, triangle_mesh)), - hedge_index_map(get(boost::halfedge_index, triangle_mesh)), + vertex_index_map(CGAL::get_initialized_vertex_index_map(triangle_mesh)), + hedge_index_map(CGAL::get_initialized_halfedge_index_map(triangle_mesh)), ros_id_map(std::vector(num_vertices(triangle_mesh), (std::numeric_limits::max)() )), is_roi_map(std::vector(num_vertices(triangle_mesh), false)), is_ctrl_map(std::vector(num_vertices(triangle_mesh), false)), @@ -413,18 +411,19 @@ public: Vertex_index_map vertex_index_map, Hedge_index_map hedge_index_map, Vertex_point_map vertex_point_map, - Weight_calculator weight_calculator = Weight_calculator() - ) - : m_triangle_mesh(triangle_mesh), vertex_index_map(vertex_index_map), hedge_index_map(hedge_index_map), - ros_id_map(std::vector(num_vertices(triangle_mesh), (std::numeric_limits::max)() )), - is_roi_map(std::vector(num_vertices(triangle_mesh), false)), - is_ctrl_map(std::vector(num_vertices(triangle_mesh), false)), - m_iterations(5), m_tolerance(1e-4), - need_preprocess_factorization(true), - need_preprocess_region_of_solution(true), - last_preprocess_successful(false), - weight_calculator(weight_calculator), - vertex_point_map(vertex_point_map) + Weight_calculator weight_calculator = Weight_calculator()) + : m_triangle_mesh(triangle_mesh), + vertex_index_map(vertex_index_map), + hedge_index_map(hedge_index_map), + ros_id_map(std::vector(num_vertices(triangle_mesh), (std::numeric_limits::max)() )), + is_roi_map(std::vector(num_vertices(triangle_mesh), false)), + is_ctrl_map(std::vector(num_vertices(triangle_mesh), false)), + m_iterations(5), m_tolerance(1e-4), + need_preprocess_factorization(true), + need_preprocess_region_of_solution(true), + last_preprocess_successful(false), + weight_calculator(weight_calculator), + vertex_point_map(vertex_point_map) { init(); } @@ -433,21 +432,23 @@ public: /// \name Construction /// @{ /** - * The constructor of a deformation object + * The constructor of a deformation object. * * @pre `triangle_mesh` consists of only triangular facets * @param triangle_mesh triangulated surface mesh to deform - * @param vertex_index_map property map which associates an id to each vertex, from `0` to `num_vertices(triangle_mesh)-1`. - * @param hedge_index_map property map which associates an id to each halfedge, from `0` to `2*num_edges(triangle_mesh)-1`. + * @param vertex_index_map a property map which associates a unique id to each vertex, + * between `0` to `num_vertices(triangle_mesh)-1`. + * @param hedge_index_map property map which associates a unique id to each halfedge, + * between `0` to `2*num_edges(triangle_mesh)-1`. * @param vertex_point_map property map which associates a point to each vertex of the triangle mesh. * @param weight_calculator function object or pointer for weight calculation + * */ Surface_mesh_deformation(Triangle_mesh& triangle_mesh, - Vertex_index_map vertex_index_map=get(boost::vertex_index, triangle_mesh), - Hedge_index_map hedge_index_map=get(boost::halfedge_index, triangle_mesh), - Vertex_point_map vertex_point_map=get(boost::vertex_point, triangle_mesh), - Weight_calculator weight_calculator = Weight_calculator() - ); + Vertex_index_map vertex_index_map = unspecified_internal_vertex_index_map, + Hedge_index_map hedge_index_map = unspecified_internal_halfedge_index_map, + Vertex_point_map vertex_point_map = get(boost::vertex_point, triangle_mesh), + Weight_calculator weight_calculator = Weight_calculator()); /// @} #endif diff --git a/Surface_mesh_deformation/test/Surface_mesh_deformation/CMakeLists.txt b/Surface_mesh_deformation/test/Surface_mesh_deformation/CMakeLists.txt index 54163d64df1..555174ccf92 100644 --- a/Surface_mesh_deformation/test/Surface_mesh_deformation/CMakeLists.txt +++ b/Surface_mesh_deformation/test/Surface_mesh_deformation/CMakeLists.txt @@ -13,15 +13,18 @@ if ( CGAL_FOUND ) find_package(Eigen3 3.1.91) #(requires 3.2.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) create_single_source_cgal_program( "Cactus_deformation_session.cpp" ) + CGAL_target_use_Eigen(Cactus_deformation_session) create_single_source_cgal_program( "Cactus_performance_test.cpp" ) + CGAL_target_use_Eigen(Cactus_performance_test) create_single_source_cgal_program( "Symmetry_test.cpp" ) + CGAL_target_use_Eigen(Symmetry_test) find_package( OpenMesh QUIET ) if ( OpenMesh_FOUND ) include( UseOpenMesh ) create_single_source_cgal_program( "Cactus_deformation_session_OpenMesh.cpp" ) + CGAL_target_use_Eigen(Cactus_deformation_session_OpenMesh) target_link_libraries( Cactus_deformation_session_OpenMesh PRIVATE ${OPENMESH_LIBRARIES} ) else() message(STATUS "Example that use OpenMesh will not be compiled.") diff --git a/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/CMakeLists.txt b/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/CMakeLists.txt index 62640e3b6a9..3519d912b03 100644 --- a/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/CMakeLists.txt +++ b/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/CMakeLists.txt @@ -14,7 +14,6 @@ if ( CGAL_FOUND ) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) # Executables that require Eigen 3.1 - include( ${EIGEN3_USE_FILE} ) # ------------------------------------------------------------------ # Detect SuiteSparse libraries: @@ -52,11 +51,17 @@ if ( CGAL_FOUND ) # ------------------------------------------------------------------ create_single_source_cgal_program( "discrete_authalic.cpp" ) + CGAL_target_use_Eigen(discrete_authalic) create_single_source_cgal_program( "lscm.cpp" ) + CGAL_target_use_Eigen(lscm) create_single_source_cgal_program( "orbifold.cpp" ) + CGAL_target_use_Eigen(orbifold) create_single_source_cgal_program( "seam_Polyhedron_3.cpp" ) + CGAL_target_use_Eigen(seam_Polyhedron_3) create_single_source_cgal_program( "simple_parameterization.cpp" ) + CGAL_target_use_Eigen(simple_parameterization) create_single_source_cgal_program( "square_border_parameterizer.cpp" ) + CGAL_target_use_Eigen(square_border_parameterizer) if(SuiteSparse_FOUND) target_link_libraries(orbifold PRIVATE ${SuiteSparse_LIBRARIES}) diff --git a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h index 3d570311b53..068a882f0e1 100644 --- a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h +++ b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h @@ -25,6 +25,7 @@ #include #include +#include #include #include diff --git a/Surface_mesh_parameterization/test/Surface_mesh_parameterization/CMakeLists.txt b/Surface_mesh_parameterization/test/Surface_mesh_parameterization/CMakeLists.txt index 4021770c494..401f37978b4 100644 --- a/Surface_mesh_parameterization/test/Surface_mesh_parameterization/CMakeLists.txt +++ b/Surface_mesh_parameterization/test/Surface_mesh_parameterization/CMakeLists.txt @@ -14,8 +14,8 @@ if ( CGAL_FOUND ) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if(EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) create_single_source_cgal_program( "extensive_parameterization_test.cpp" ) + CGAL_target_use_Eigen(extensive_parameterization_test) else(EIGEN3_FOUND) message(STATUS "NOTICE: The tests require Eigen 3.1 (or greater) and will not be compiled.") endif(EIGEN3_FOUND) diff --git a/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h b/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h index 70b3dbb32f3..a96c08a1414 100644 --- a/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h +++ b/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h @@ -63,7 +63,7 @@ sdf_values( const TriangleMesh& triangle_mesh, * \ingroup PkgSurfaceMeshSegmentationRef * @brief Function computing the Shape Diameter Function over a surface mesh. * - * This function implements the Shape Diameter Function (SDF) as described in \cgalCite{shapira2008consistent}. + * This function implements the Shape Diameter Function (SDF) as described in \cgalCite{Shapira2008Consistent}. * It is possible to compute raw SDF values (without post-processing). In such a case, * -1 is used to indicate when no SDF value could be computed for a facet. * @@ -151,7 +151,7 @@ sdf_values_postprocessing(const TriangleMesh& triangle_mesh, * A segment is a set of connected facets which are placed under the same cluster (see \cgalFigureRef{Cluster_vs_segment}). * * \note Log-normalization is applied on `sdf_values_map` before segmentation. - * As described in the original paper \cgalCite{shapira2008consistent}, + * As described in the original paper \cgalCite{Shapira2008Consistent}, * this normalization is done to preserve thin parts of the mesh * by increasing the distance between smaller SDF values and reducing * it between larger ones. diff --git a/Surface_mesh_shortest_path/include/CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path.h b/Surface_mesh_shortest_path/include/CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path.h index a54781c1ae1..01057be54ca 100644 --- a/Surface_mesh_shortest_path/include/CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path.h +++ b/Surface_mesh_shortest_path/include/CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path.h @@ -67,7 +67,7 @@ Refer to those respective papers for the details of the implementation. If index property maps are not provided through the constructor of the class, internal property maps must be available and initialized. -\sa \link PkgBGLHelper `CGAL::set_halfedgeds_items_id()`\endlink +\sa \link BGLGraphExternalIndices `CGAL::set_halfedgeds_items_id()`\endlink */ template()), choose_parameter(get_parameter(np, internal_np::get_cost_policy), diff --git a/Surface_mesh_skeletonization/benchmark/Surface_mesh_skeletonization/CMakeLists.txt b/Surface_mesh_skeletonization/benchmark/Surface_mesh_skeletonization/CMakeLists.txt index d73305b0549..4ee6bec3cc0 100644 --- a/Surface_mesh_skeletonization/benchmark/Surface_mesh_skeletonization/CMakeLists.txt +++ b/Surface_mesh_skeletonization/benchmark/Surface_mesh_skeletonization/CMakeLists.txt @@ -38,8 +38,6 @@ find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) if(NOT EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.2 (or greater) is not found.") -else() - include( ${EIGEN3_USE_FILE} ) endif(NOT EIGEN3_FOUND) @@ -47,5 +45,7 @@ endif(NOT EIGEN3_FOUND) # ########################################################## create_single_source_cgal_program( "solver_benchmark.cpp" ) +CGAL_target_use_Eigen(solver_benchmark) create_single_source_cgal_program( "mcf_scale_invariance.cpp" ) +CGAL_target_use_Eigen(mcf_scale_invariance) diff --git a/Surface_mesh_skeletonization/examples/Surface_mesh_skeletonization/CMakeLists.txt b/Surface_mesh_skeletonization/examples/Surface_mesh_skeletonization/CMakeLists.txt index 7327aafc329..d3f29d30dc3 100644 --- a/Surface_mesh_skeletonization/examples/Surface_mesh_skeletonization/CMakeLists.txt +++ b/Surface_mesh_skeletonization/examples/Surface_mesh_skeletonization/CMakeLists.txt @@ -14,8 +14,6 @@ if ( CGAL_FOUND ) find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) if(EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - create_single_source_cgal_program( "simple_mcfskel_example.cpp" ) create_single_source_cgal_program( "simple_mcfskel_sm_example.cpp" ) create_single_source_cgal_program( "simple_mcfskel_LCC_example.cpp" ) @@ -23,6 +21,16 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "MCF_Skeleton_sm_example.cpp" ) create_single_source_cgal_program( "MCF_Skeleton_LCC_example.cpp" ) create_single_source_cgal_program( "segmentation_example.cpp" ) + foreach(target + simple_mcfskel_example + simple_mcfskel_sm_example + simple_mcfskel_LCC_example + MCF_Skeleton_example + MCF_Skeleton_sm_example + MCF_Skeleton_LCC_example + segmentation_example) + CGAL_target_use_Eigen(${target}) + endforeach() else() message(STATUS "These programs require the Eigen library (3.2 or greater), and will not be compiled.") endif() diff --git a/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/CMakeLists.txt b/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/CMakeLists.txt index fdab781a1ca..fd313cbf499 100644 --- a/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/CMakeLists.txt +++ b/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/CMakeLists.txt @@ -14,10 +14,10 @@ if ( CGAL_FOUND ) find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) if(EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - create_single_source_cgal_program( "MCF_Skeleton_test.cpp" ) + CGAL_target_use_Eigen(MCF_Skeleton_test) create_single_source_cgal_program( "skeleton_connectivity_test.cpp" ) + CGAL_target_use_Eigen(skeleton_connectivity_test) else() message(STATUS "These tests require the Eigen library (3.2 or greater), and will not be compiled.") endif() diff --git a/Triangulation/applications/Triangulation/CMakeLists.txt b/Triangulation/applications/Triangulation/CMakeLists.txt index f95f8c19f46..eb9a2aee481 100644 --- a/Triangulation/applications/Triangulation/CMakeLists.txt +++ b/Triangulation/applications/Triangulation/CMakeLists.txt @@ -26,9 +26,6 @@ if ( NOT Boost_FOUND ) endif() find_package(Eigen3 3.1.0) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -endif() # include for local directory include_directories( BEFORE include ) @@ -39,6 +36,8 @@ include_directories( BEFORE include ) # ########################################################## create_single_source_cgal_program( "points_to_RT_to_off.cpp" ) +CGAL_target_use_Eigen(points_to_RT_to_off) create_single_source_cgal_program( "points_to_DT_to_off.cpp" ) +CGAL_target_use_Eigen(points_to_DT_to_off) diff --git a/Triangulation/benchmark/Triangulation/CMakeLists.txt b/Triangulation/benchmark/Triangulation/CMakeLists.txt index f82e906db3d..aa2d0cf578c 100644 --- a/Triangulation/benchmark/Triangulation/CMakeLists.txt +++ b/Triangulation/benchmark/Triangulation/CMakeLists.txt @@ -15,10 +15,11 @@ if ( CGAL_FOUND ) find_package(Eigen3 3.1.0) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) include_directories (BEFORE "include") create_single_source_cgal_program( "delaunay.cpp" ) + CGAL_target_use_Eigen(delaunay) create_single_source_cgal_program( "Td_vs_T2_and_T3.cpp" ) + CGAL_target_use_Eigen(Td_vs_T2_and_T3) else() message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.") diff --git a/Triangulation/examples/Triangulation/CMakeLists.txt b/Triangulation/examples/Triangulation/CMakeLists.txt index 69eacb3a05b..a528bd6a21c 100644 --- a/Triangulation/examples/Triangulation/CMakeLists.txt +++ b/Triangulation/examples/Triangulation/CMakeLists.txt @@ -18,8 +18,6 @@ if ( CGAL_FOUND ) find_package(Eigen3 3.1.0) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - create_single_source_cgal_program( "barycentric_subdivision.cpp" ) create_single_source_cgal_program( "delaunay_triangulation.cpp" ) create_single_source_cgal_program( "convex_hull.cpp" ) @@ -28,6 +26,16 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "triangulation_data_structure_dynamic.cpp" ) create_single_source_cgal_program( "triangulation_data_structure_static.cpp" ) + foreach(target + barycentric_subdivision + delaunay_triangulation + convex_hull + regular_triangulation + triangulation + triangulation_data_structure_dynamic + triangulation_data_structure_static) + CGAL_target_use_Eigen(${target}) + endforeach() else() message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.") endif() diff --git a/Triangulation/test/Triangulation/CMakeLists.txt b/Triangulation/test/Triangulation/CMakeLists.txt index 49054feffce..1a58eb9e81d 100644 --- a/Triangulation/test/Triangulation/CMakeLists.txt +++ b/Triangulation/test/Triangulation/CMakeLists.txt @@ -16,7 +16,6 @@ if ( CGAL_FOUND ) find_package(Eigen3 3.1.0) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) include_directories (BEFORE "include") create_single_source_cgal_program( "test_triangulation.cpp" ) @@ -25,6 +24,15 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "test_tds.cpp" ) create_single_source_cgal_program( "test_torture.cpp" ) create_single_source_cgal_program( "test_insert_if_in_star.cpp" ) + foreach(target + test_triangulation + test_delaunay + test_regular + test_tds + test_torture + test_insert_if_in_star) + CGAL_target_use_Eigen(${target}) + endforeach() else() message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.") diff --git a/Triangulation/test/Triangulation/test_delaunay.cpp b/Triangulation/test/Triangulation/test_delaunay.cpp index bf6b38ff7ab..4c105df3d2f 100644 --- a/Triangulation/test/Triangulation/test_delaunay.cpp +++ b/Triangulation/test/Triangulation/test_delaunay.cpp @@ -10,6 +10,7 @@ int main() #else #include +#include #include #include #include @@ -112,13 +113,21 @@ void test(const int d, const string & type, const int N) template< int D > void go(const int N) { - typedef CGAL::Epick_d > FK; - typedef CGAL::Delaunay_triangulation Triangulation; - test(D, "static", N); + typedef CGAL::Epick_d > KI; + typedef CGAL::Delaunay_triangulation Triangulation; + test(D, "inexact static", N); - typedef CGAL::Epick_d FK_dyn; - typedef CGAL::Delaunay_triangulation Triangulation_dyn; - test(D, "dynamic", N); + typedef CGAL::Epick_d KI_dyn; + typedef CGAL::Delaunay_triangulation Triangulation_dyn; + test(D, "inexact dynamic", N); + + typedef CGAL::Epeck_d > KE; + typedef CGAL::Delaunay_triangulation TriangulationE; + test(D, "exact static", N); + + typedef CGAL::Epeck_d KE_dyn; + typedef CGAL::Delaunay_triangulation TriangulationE_dyn; + test(D, "exact dynamic", N); } int main(int argc, char **argv) diff --git a/Triangulation/test/Triangulation/test_regular.cpp b/Triangulation/test/Triangulation/test_regular.cpp index f124b1ddabf..c044e663f0e 100644 --- a/Triangulation/test/Triangulation/test_regular.cpp +++ b/Triangulation/test/Triangulation/test_regular.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -93,13 +94,21 @@ void test(const int d, const string & type, const int N) template< int D > void go(const int N) { - typedef CGAL::Epick_d > FK; - typedef CGAL::Regular_triangulation Triangulation; - test(D, "static", N); + typedef CGAL::Epick_d > KI; + typedef CGAL::Regular_triangulation Triangulation; + test(D, "inexact static", N); - typedef CGAL::Epick_d FK_dyn; - typedef CGAL::Regular_triangulation Triangulation_dyn; - test(D, "dynamic", N); + typedef CGAL::Epick_d KI_dyn; + typedef CGAL::Regular_triangulation Triangulation_dyn; + test(D, "inexact dynamic", N); + + typedef CGAL::Epeck_d > KE; + typedef CGAL::Regular_triangulation TriangulationE; + test(D, "exact static", N); + + typedef CGAL::Epeck_d KE_dyn; + typedef CGAL::Regular_triangulation TriangulationE_dyn; + test(D, "exact dynamic", N); } void test_inserting_points_at_the_same_position() diff --git a/Triangulation_2/include/CGAL/Constrained_Delaunay_triangulation_2.h b/Triangulation_2/include/CGAL/Constrained_Delaunay_triangulation_2.h index a3d3af22911..6e04239a242 100644 --- a/Triangulation_2/include/CGAL/Constrained_Delaunay_triangulation_2.h +++ b/Triangulation_2/include/CGAL/Constrained_Delaunay_triangulation_2.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -45,10 +46,46 @@ struct Get_iterator_value_type{ } } //namespace CGAL::internal #endif //CGAL_TRIANGULATION_2_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO - - namespace CGAL { +namespace internal { +// Compare geometry to ensure deterministic flips +template +class Cdt_2_less_edge + : public CGAL::cpp98::binary_function +{ + const Tr* tr_ptr; + + typedef typename Tr::Point Point; + typedef typename Tr::Edge Edge; + +public: + Cdt_2_less_edge(const Tr* tr_ptr) : tr_ptr(tr_ptr) { } + + // just a manual lexicographical_compare + bool operator() (const Edge& e1, const Edge& e2) const + { + const Point& e1p1 = tr_ptr->point(e1.first, Tr::ccw(e1.second)); + const Point& e2p1 = tr_ptr->point(e2.first, Tr::ccw(e2.second)); + + CGAL::Comparison_result res1 = tr_ptr->compare_xy(e1p1, e2p1); + if(res1 == CGAL::SMALLER) + return true; + if(res1 == CGAL::LARGER) + return false; + + const Point& e1p2 = tr_ptr->point(e1.first, Tr::cw(e1.second)); + const Point& e2p2 = tr_ptr->point(e2.first, Tr::cw(e2.second)); + + CGAL::Comparison_result res2 = tr_ptr->compare_xy(e1p2, e2p2); + if(res2 == CGAL::SMALLER) + return true; + + return false; + } +}; + +} // namespace internal template Less_edge; + typedef boost::container::flat_set Edge_set; //Tag to distinguish Delaunay from regular triangulations typedef Tag_false Weighted_tag; @@ -530,8 +568,10 @@ public: int i, ii, indf, indn; Face_handle ni, f,ff; Edge ei,eni; - typename Ctr::Edge_set edge_set; - typename Ctr::Less_edge less_edge; + + Less_edge less_edge(this); + Edge_set edge_set(less_edge); + Edge e[4]; typename List_edges::iterator itedge=edges.begin(); diff --git a/Triangulation_2/include/CGAL/Constrained_triangulation_2.h b/Triangulation_2/include/CGAL/Constrained_triangulation_2.h index 4805a68e33e..48ab6cc3111 100644 --- a/Triangulation_2/include/CGAL/Constrained_triangulation_2.h +++ b/Triangulation_2/include/CGAL/Constrained_triangulation_2.h @@ -170,10 +170,6 @@ public: // Tag to distinguish periodic triangulations from others typedef Tag_false Periodic_tag; - class Less_edge; - typedef std::set Edge_set; - - Constrained_triangulation_2(const Gt& gt = Gt()) : Triangulation(gt) { } Constrained_triangulation_2(std::list& lc, const Gt& gt=Gt()) @@ -435,21 +431,6 @@ insert_constraint(Vertex_handle vaa, Vertex_handle vbb, OutputIterator out) // template // OutputItEdges incident_constraints(Vertex_handle v, // OutputItEdges out) const; - - - class Less_edge - : public CGAL::cpp98::binary_function - { - public: - Less_edge() {} - bool operator() (const Edge& e1, const Edge& e2) const - { - int ind1=e1.second, ind2=e2.second; - return( (&(*e1.first) < &(*e2.first)) - || ( (&(*e1.first) == &(*e2.first)) && (ind1 < ind2))); - } - }; - void file_output(std::ostream& os) const; diff --git a/Triangulation_2/include/CGAL/Triangulation_face_base_with_id_2.h b/Triangulation_2/include/CGAL/Triangulation_face_base_with_id_2.h index d47a256a245..8d5a54281e1 100644 --- a/Triangulation_2/include/CGAL/Triangulation_face_base_with_id_2.h +++ b/Triangulation_2/include/CGAL/Triangulation_face_base_with_id_2.h @@ -42,11 +42,15 @@ public: : Fb(v0, v1, v2, n0, n1, n2) { } - int& id() { return _id; } - int id() const { return _id; } + int& id() { return face_id; } + int id() const { return face_id; } + + int& edge_id(const std::size_t i) { return edge_ids[i]; } + int edge_id(const std::size_t i) const { return edge_ids[i]; } private: - int _id; + int face_id; + std::array edge_ids; }; } //namespace CGAL diff --git a/Triangulation_2/include/CGAL/boost/graph/internal/properties_2D_triangulation.h b/Triangulation_2/include/CGAL/boost/graph/internal/properties_2D_triangulation.h index 6bad3c9aa0c..16895ba78a8 100644 --- a/Triangulation_2/include/CGAL/boost/graph/internal/properties_2D_triangulation.h +++ b/Triangulation_2/include/CGAL/boost/graph/internal/properties_2D_triangulation.h @@ -111,7 +111,7 @@ public: T2_halfedge_id_map(const Tr& tr) : tr(tr) { } // Halfedge id is twice the edge id, and +0/+1 depending whether - // h.first is such that h.first < opposite(h).first --> different ids + // h.first is such that h.first < opposite(h).first value_type operator[](key_type h) const { const Face_handle f1 = h.first; @@ -119,13 +119,13 @@ public: CGAL_assertion(!tr.is_infinite(f1) || !tr.is_infinite(f2)); if(tr.is_infinite(f1)) - return 2*(3 * f2->id() + f2->index(f1)); + return 2*(f2->edge_id(f2->index(f1))); else if(tr.is_infinite(f2)) - return 2*(3 * f1->id() + h.second) + 1; + return 2*(f1->edge_id(h.second)) + 1; else if(f1->id() < f2->id()) - return 2*(3 * f1->id() + h.second); + return 2*(f1->edge_id(h.second)); else - return 2*(3 * f2->id() + f2->index(f1)) + 1; + return 2*(f1->edge_id(h.second)) + 1; } private: @@ -152,13 +152,9 @@ public: CGAL_assertion(!tr.is_infinite(f1) || !tr.is_infinite(f2)); if(tr.is_infinite(f1)) - return 3 * f2->id() + f2->index(f1); - else if(tr.is_infinite(f2)) - return 3 * f1->id() + e.second; - else if(f1->id() < f2->id()) - return 3 * f1->id() + e.second; + return f2->edge_id(f2->index(f1)); else - return 3 * f2->id() + f2->index(f1); + return f1->edge_id(e.second); } private: @@ -368,6 +364,39 @@ put(PropertyTag p, CGAL_2D_TRIANGULATION& g, const Key& key, const Value& value) put(pmap, key, value); } +template < CGAL_2D_TRIANGULATION_TEMPLATE_PARAMETERS > +void set_triangulation_ids(CGAL_2D_TRIANGULATION& g) +{ + typedef typename boost::graph_traits< CGAL_2D_TRIANGULATION >::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits< CGAL_2D_TRIANGULATION >::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits< CGAL_2D_TRIANGULATION >::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits< CGAL_2D_TRIANGULATION >::face_descriptor face_descriptor; + + int vid = 0; + for(vertex_descriptor vd : vertices(g)) + vd->id() = vid++; + + int eid = 0; + for(edge_descriptor ed : edges(g)) + { + halfedge_descriptor hd = halfedge(ed, g); + face_descriptor fd = face(hd, g); + if(fd != boost::graph_traits< CGAL_2D_TRIANGULATION >::null_face()) + fd->edge_id(hd.second) = eid; + + halfedge_descriptor opp_hd = opposite(hd, g); + face_descriptor opp_fd = face(opp_hd, g); + if(opp_fd != boost::graph_traits< CGAL_2D_TRIANGULATION >::null_face()) + opp_fd->edge_id(opp_hd.second) = eid; + + ++eid; + } + + int fid = 0; + for(face_descriptor fd : faces(g)) + fd->id() = fid++; +} + } // namespace CGAL #undef CGAL_2D_TRIANGULATION_TEMPLATE_PARAMETERS diff --git a/Triangulation_3/include/CGAL/Triangulation_3_to_lcc.h b/Triangulation_3/include/CGAL/Triangulation_3_to_lcc.h index be15a9e3c72..1bb09346ee9 100644 --- a/Triangulation_3/include/CGAL/Triangulation_3_to_lcc.h +++ b/Triangulation_3/include/CGAL/Triangulation_3_to_lcc.h @@ -15,9 +15,27 @@ #include #include +#include namespace CGAL { + namespace internal + { + template + struct Get_point + { + static const Point& run(const Point& p) + { return p; } + }; + + template + struct Get_point > + { + static const typename Kernel::Point_3& run(const CGAL::Weighted_point_3& p) + { return p.point(); } + }; + } + /** Convert a given Triangulation_3 into a 3D linear cell complex. * @param alcc the used linear cell complex. * @param atr the Triangulation_3. @@ -52,7 +70,7 @@ namespace CGAL { for (TVertex_iterator itv = atr.vertices_begin(); itv != atr.vertices_end(); ++itv) { - TV[itv] = alcc.create_vertex_attribute(itv->point()); + TV[itv] = alcc.create_vertex_attribute(internal::Get_point::run(itv->point())); } // Create the tetrahedron and create a map to link Cell_iterator