diff --git a/.gitignore b/.gitignore index 9a1d742f1fe..9e2bd72d875 100644 --- a/.gitignore +++ b/.gitignore @@ -757,7 +757,6 @@ Ridges_3/examples/Ridges_3/Compute_Ridges_Umbilics Ridges_3/examples/Ridges_3/Makefile Ridges_3/test/Ridges_3/Makefile Ridges_3/test/Ridges_3/ridge_test -STL_Extension/test/STL_Extension/CMakeLists.txt STL_Extension/test/STL_Extension/cgal_test_with_cmake STL_Extension/test/STL_Extension/test_Cache STL_Extension/test/STL_Extension/test_Compact_container @@ -930,7 +929,6 @@ Triangulation_2/test/Triangulation_2/vrml_tds* Triangulation_3/benchmark/Triangulation_3/CMakeLists.txt Triangulation_3/benchmark/Triangulation_3/cgal_test_with_cmake Triangulation_3/benchmark/Triangulation_3/simple -Triangulation_3/examples/Triangulation_3/CMakeLists.txt Triangulation_3/examples/Triangulation_3/adding_handles_3 Triangulation_3/examples/Triangulation_3/cgal_test_with_cmake Triangulation_3/examples/Triangulation_3/color @@ -946,7 +944,6 @@ Triangulation_3/examples/Triangulation_3/regular_3 Triangulation_3/examples/Triangulation_3/simple_triangulation_3 Triangulation_3/examples/Triangulation_3/simplex Triangulation_3/examples/Triangulation_3/tds -Triangulation_3/test/Triangulation_3/CMakeLists.txt Triangulation_3/test/Triangulation_3/Makefile Triangulation_3/test/Triangulation_3/Test1_triangulation_IO_3_binary Triangulation_3/test/Triangulation_3/Test2_triangulation_IO_3_binary diff --git a/Documentation/biblio/cgal_manual.bib b/Documentation/biblio/cgal_manual.bib index 2285b00840a..509cdd3189a 100644 --- a/Documentation/biblio/cgal_manual.bib +++ b/Documentation/biblio/cgal_manual.bib @@ -1811,7 +1811,7 @@ ABSTRACT = {We present the first complete, exact and efficient C++ implementatio } @inproceedings{cgal:tsa-ps3dd-09, -author = {Jane TOURNOIS and Rahul SRINIVASAN and Pierre ALLIEZ}, +author = {Jane Tournois and Rahul Srinivasan and Pierre Alliez}, title = {{Perturbing slivers in 3D Delaunay meshes}}, year = {2009}, month = {october}, diff --git a/Hash_map/include/CGAL/Tools/chained_map.h b/Hash_map/include/CGAL/Tools/chained_map.h index 240b50324c9..63ddd7d4bad 100644 --- a/Hash_map/include/CGAL/Tools/chained_map.h +++ b/Hash_map/include/CGAL/Tools/chained_map.h @@ -24,22 +24,24 @@ #ifndef CGAL_CHAINED_MAP_H #define CGAL_CHAINED_MAP_H +#include + namespace CGAL { namespace internal { -template class chained_map; +template class chained_map; template class chained_map_elem; template class chained_map_elem { - friend class chained_map; + template friend class chained_map; std::size_t k; T i; chained_map_elem* succ; }; -template +template class chained_map { const std::size_t NULLKEY; @@ -50,8 +52,8 @@ class chained_map chained_map_elem* table; chained_map_elem* table_end; chained_map_elem* free; - std::size_t table_size; - std::size_t table_size_1; + std::size_t table_size; + std::size_t table_size_1; chained_map_elem* old_table; chained_map_elem* old_table_end; @@ -61,6 +63,9 @@ class chained_map std::size_t old_index; + typedef typename Allocator::template rebind >::other allocator_type; + allocator_type alloc; + public: T& xdef() { return STOP.i; } const T& cxdef() const { return STOP.i; } @@ -84,14 +89,25 @@ public: std::size_t index(chained_map_item it) const { return it->k; } T& inf(chained_map_item it) const { return it->i; } - chained_map(std::size_t n = 1); - chained_map(const chained_map& D); - chained_map& operator=(const chained_map& D); + chained_map(std::size_t n = 1); + chained_map(const chained_map& D); + chained_map& operator=(const chained_map& D); void clear_entries(); void clear(); - ~chained_map() { if (old_table) delete[] old_table; delete[] table; } + ~chained_map() + { + if (old_table) + { + for (chained_map_item item = old_table ; item != old_table_end ; ++item) + alloc.destroy(item); + alloc.deallocate(old_table, old_table_end - old_table); + } + for (chained_map_item item = table ; item != table_end ; ++item) + alloc.destroy(item); + alloc.deallocate(table, table_end - table); + } T& access(chained_map_item p, std::size_t x); T& access(std::size_t x); @@ -101,8 +117,8 @@ public: void statistics() const; }; -template -inline T& chained_map::access(std::size_t x) +template +inline T& chained_map::access(std::size_t x) { chained_map_item p = HASH(x); if (old_table) del_old_table(); @@ -121,12 +137,12 @@ inline T& chained_map::access(std::size_t x) } } -template -void chained_map::init_table(std::size_t t) +template +void chained_map::init_table(std::size_t t) { table_size = t; table_size_1 = t-1; - table = new chained_map_elem[t + t/2]; + table = alloc.allocate(t + t/2); free = table + t; table_end = table + t + t/2; @@ -138,8 +154,8 @@ void chained_map::init_table(std::size_t t) } -template -inline void chained_map::insert(std::size_t x, T y) +template +inline void chained_map::insert(std::size_t x, T y) { chained_map_item q = HASH(x); if ( q->k == NULLKEY ) { q->k = x; @@ -153,8 +169,8 @@ inline void chained_map::insert(std::size_t x, T y) } -template -void chained_map::rehash() +template +void chained_map::rehash() { old_table = table; old_table_end = table_end; @@ -185,8 +201,8 @@ void chained_map::rehash() } -template -void chained_map::del_old_table() +template +void chained_map::del_old_table() { chained_map_item save_table = table; chained_map_item save_table_end = table_end; @@ -204,7 +220,9 @@ void chained_map::del_old_table() T p = access(old_index); - delete[] table; + for (chained_map_item item = table ; item != table_end ; ++item) + alloc.destroy(item); + alloc.deallocate(table, table_end - table); table = save_table; table_end = save_table_end; @@ -214,8 +232,8 @@ void chained_map::del_old_table() access(old_index) = p; } -template -T& chained_map::access(chained_map_item p, std::size_t x) +template +T& chained_map::access(chained_map_item p, std::size_t x) { STOP.k = x; chained_map_item q = p->succ; @@ -247,8 +265,8 @@ T& chained_map::access(chained_map_item p, std::size_t x) } -template -chained_map::chained_map(std::size_t n) : +template +chained_map::chained_map(std::size_t n) : NULLKEY(0), NONNULLKEY(1), old_table(0) { if (n < 512) @@ -261,8 +279,8 @@ chained_map::chained_map(std::size_t n) : } -template -chained_map::chained_map(const chained_map& D) : +template +chained_map::chained_map(const chained_map& D) : NULLKEY(0), NONNULLKEY(1), old_table(0) { init_table(D.table_size); @@ -276,11 +294,15 @@ chained_map::chained_map(const chained_map& D) : } } -template -chained_map& chained_map::operator=(const chained_map& D) +template +chained_map& chained_map::operator=(const chained_map& D) { clear_entries(); - delete[] table; + + for (chained_map_item item = table ; item != table_end ; ++item) + alloc.destroy(item); + alloc.deallocate(table, table_end - table); + init_table(D.table_size); STOP.i = D.STOP.i; // xdef @@ -293,23 +315,28 @@ chained_map& chained_map::operator=(const chained_map& D) return *this; } -template -void chained_map::clear_entries() +template +void chained_map::clear_entries() { for(chained_map_item p = table + 1; p < free; p++) if (p->k != NULLKEY || p >= table + table_size) p->i = T(); } -template -void chained_map::clear() -{ clear_entries(); - delete[] table; +template +void chained_map::clear() +{ + clear_entries(); + + for (chained_map_item item = table ; item != table_end ; ++item) + alloc.destroy(item); + alloc.deallocate(table, table_end - table); + init_table(512); } -template -typename chained_map::chained_map_item -chained_map::lookup(std::size_t x) const +template +typename chained_map::chained_map_item +chained_map::lookup(std::size_t x) const { chained_map_item p = HASH(x); ((std::size_t &)STOP.k) = x; // cast away const while (p->k != x) @@ -318,21 +345,21 @@ chained_map::lookup(std::size_t x) const } -template -typename chained_map::chained_map_item -chained_map::first_item() const +template +typename chained_map::chained_map_item +chained_map::first_item() const { return next_item(table); } -template -typename chained_map::chained_map_item -chained_map::next_item(chained_map_item it) const +template +typename chained_map::chained_map_item +chained_map::next_item(chained_map_item it) const { if (it == 0) return 0; do it++; while (it < table + table_size && it->k == NULLKEY); return (it < free ? it : 0); } -template -void chained_map::statistics() const +template +void chained_map::statistics() const { std::cout << "table_size: " << table_size <<"\n"; std::size_t n = 0; for (chained_map_item p = table + 1; p < table + table_size; p++) diff --git a/Hash_map/include/CGAL/Unique_hash_map.h b/Hash_map/include/CGAL/Unique_hash_map.h index 50043e9b756..494ef12d64c 100644 --- a/Hash_map/include/CGAL/Unique_hash_map.h +++ b/Hash_map/include/CGAL/Unique_hash_map.h @@ -27,6 +27,7 @@ #define CGAL_UNIQUE_HASH_MAP_H #include +#include #include #include #include @@ -34,22 +35,24 @@ namespace CGAL { template + class UniqueHashFunction = Handle_hash_function, + class Allocator_ = CGAL_ALLOCATOR(Data_) > class Unique_hash_map { public: typedef Key_ Key; typedef Data_ Data; typedef UniqueHashFunction Hash_function; + typedef Allocator_ Allocator; // STL compliance typedef Key_ key_type; typedef Data_ data_type; typedef UniqueHashFunction hasher; - typedef Unique_hash_map Self; + typedef Unique_hash_map Self; private: - typedef internal::chained_map Map; + typedef internal::chained_map Map; typedef typename Map::item Item; private: diff --git a/Installation/changes.html b/Installation/changes.html index ca81aad4774..31271f48168 100644 --- a/Installation/changes.html +++ b/Installation/changes.html @@ -164,14 +164,20 @@ and src/ directories).
  • The meshing functionality in the Qt demos in demo/Polyhedron/ and demo/Mesh_3/ can now use the handling of 1d-features, that exists in CGAL since version 3.8. +
  • Added a parallel version of the 3D mesh refinement and mesh optimization methods. +
  • STL_extension

      -
    • Added Compact_container::operator[], allowing a direct access to the ith element of a compact container. -
    • +
    • Added Compact_container::operator[], allowing a direct access to the ith element of a compact container.
    • +
    • Added Concurrent_compact_container, a compact container which allows concurrent insertion and removal.
    • +
    +

    Triangulation_3

    +
      +
    • Added a parallel version of the Delaunay triangulation and the Regular triangulation algorithms, + which allows parallel insertion and removal of point ranges.
    -

    Triangulated Surface Mesh Simplification

    • Add some optimization in the code making the implementation faster diff --git a/Mesh_2/include/CGAL/Mesher_level.h b/Mesh_2/include/CGAL/Mesher_level.h index 5ba8f158ef2..441e9dc4151 100644 --- a/Mesh_2/include/CGAL/Mesher_level.h +++ b/Mesh_2/include/CGAL/Mesher_level.h @@ -78,7 +78,7 @@ template < /**< Previous level type, defaults to \c Null_mesher_level. */ class Triangulation_traits /** Traits class that defines types for the - triangulation. */ + triangulation. */ > class Mesher_level { @@ -121,7 +121,7 @@ public: Derived, Element, Previous_level, - Triangulation_traits> Self; + Triangulation_traits> Self; /** \name CONSTRUCTORS */ Mesher_level(Previous_level& previous) @@ -193,7 +193,7 @@ public: /** Actions before testing conflicts for point \c p and element \c e */ template void before_conflicts(const Element& e, const Point& p, - Mesh_visitor visitor) + Mesh_visitor visitor) { visitor.before_conflicts(e, p); derived().before_conflicts_impl(e, p); @@ -207,7 +207,7 @@ public: the tested element should be reconsidered latter. */ Mesher_level_conflict_status private_test_point_conflict(const Point& p, - Zone& zone) + Zone& zone) { return derived().private_test_point_conflict_impl(p, zone); } @@ -222,7 +222,7 @@ public: */ Mesher_level_conflict_status test_point_conflict_from_superior(const Point& p, - Zone& zone) + Zone& zone) { return derived().test_point_conflict_from_superior_impl(p, zone); } @@ -254,7 +254,7 @@ public: * if no point is inserted. */ template void after_no_insertion(const Element& e, const Point& p, Zone& zone, - Mesh_visitor visitor) + Mesh_visitor visitor) { derived().after_no_insertion_impl(e, p, zone); visitor.after_no_insertion(e, p, zone); diff --git a/Mesh_3/applications/mesh_polyhedral_domain.cpp b/Mesh_3/applications/mesh_polyhedral_domain.cpp index 34508334f10..dda88171e41 100644 --- a/Mesh_3/applications/mesh_polyhedral_domain.cpp +++ b/Mesh_3/applications/mesh_polyhedral_domain.cpp @@ -80,7 +80,7 @@ int main(int argc, char** argv) ("show_patches", "Show surface patches in medit output"); - po::options_description cmdline_options("Usage",1); + po::options_description cmdline_options("Usage"); cmdline_options.add(generic).add(mesh).add(desc); po::variables_map vm; @@ -150,7 +150,7 @@ int main(int argc, char** argv) // Output std::ofstream medit_file_before("out_before.mesh"); c3t3.output_to_medit(medit_file_before, - !vm.count("no_label_rebind"), vm.count("show_patches")); + vm.count("no_label_rebind") == 0, vm.count("show_patches") > 0); // Odt if ( vm.count("odt") ) @@ -198,7 +198,7 @@ int main(int argc, char** argv) // Output std::ofstream medit_file("out.mesh"); - c3t3.output_to_medit(medit_file,!vm.count("no_label_rebind"), vm.count("show_patches")); + c3t3.output_to_medit(medit_file, vm.count("no_label_rebind") == 0, vm.count("show_patches") > 0); return 0; } diff --git a/Mesh_3/applications/mesher_tester.h b/Mesh_3/applications/mesher_tester.h index 12dd8c36823..fd8682153aa 100644 --- a/Mesh_3/applications/mesher_tester.h +++ b/Mesh_3/applications/mesher_tester.h @@ -1,3 +1,4 @@ +#define BOOST_FILESYSTEM_VERSION 2 #include @@ -14,7 +15,7 @@ #include #include #include -#include +#include #include "thread_queue.h" @@ -408,32 +409,32 @@ void save_histogram(const std::string& filename, const Point_3& p3 = cit->vertex(3)->point(); double a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p0,p1,p2,p3))); - histo[std::floor(a)] += 1; + histo[static_cast(std::floor(a))] += 1; min_value = (std::min)(min_value, a); max_value = (std::max)(max_value, a); a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p0, p2, p1, p3))); - histo[std::floor(a)] += 1; + histo[static_cast(std::floor(a))] += 1; min_value = (std::min)(min_value, a); max_value = (std::max)(max_value, a); a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p0, p3, p1, p2))); - histo[std::floor(a)] += 1; + histo[static_cast(std::floor(a))] += 1; min_value = (std::min)(min_value, a); max_value = (std::max)(max_value, a); a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p1, p2, p0, p3))); - histo[std::floor(a)] += 1; + histo[static_cast(std::floor(a))] += 1; min_value = (std::min)(min_value, a); max_value = (std::max)(max_value, a); a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p1, p3, p0, p2))); - histo[std::floor(a)] += 1; + histo[static_cast(std::floor(a))] += 1; min_value = (std::min)(min_value, a); max_value = (std::max)(max_value, a); a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p2, p3, p0, p1))); - histo[std::floor(a)] += 1; + histo[static_cast(std::floor(a))] += 1; min_value = (std::min)(min_value, a); max_value = (std::max)(max_value, a); diff --git a/Mesh_3/applications/mesher_tester_image.cpp b/Mesh_3/applications/mesher_tester_image.cpp index 7dc35493ae8..b77aa2b8f23 100644 --- a/Mesh_3/applications/mesher_tester_image.cpp +++ b/Mesh_3/applications/mesher_tester_image.cpp @@ -1,4 +1,4 @@ -#include +#include "mesher_tester.h" #include #include diff --git a/Mesh_3/applications/mesher_tester_polyhedron.cpp b/Mesh_3/applications/mesher_tester_polyhedron.cpp index 373caf18baa..ee05e655c5c 100644 --- a/Mesh_3/applications/mesher_tester_polyhedron.cpp +++ b/Mesh_3/applications/mesher_tester_polyhedron.cpp @@ -1,4 +1,4 @@ -#include +#include "mesher_tester.h" #include #include #include diff --git a/Mesh_3/applications/thread_queue.h b/Mesh_3/applications/thread_queue.h index 9610d0ceeba..9fd01f88a37 100644 --- a/Mesh_3/applications/thread_queue.h +++ b/Mesh_3/applications/thread_queue.h @@ -121,7 +121,7 @@ std::string format(std::string input, bool remove_template) std::size_t pos = input.find('\074'); while ( remove_template && pos != std::string::npos ) { - unsigned int init = pos; + size_t init = pos; int nb_open=1; int nb_close=0; @@ -144,7 +144,7 @@ std::string format(std::string input, bool remove_template) input.push_back('\n'); // Add " ! " at the begining of each line - unsigned int prev = 0; + size_t prev = 0; pos = input.find("\n"); while ( pos != std::string::npos ) { diff --git a/Mesh_3/benchmark/Mesh_3/CMakeLists.txt b/Mesh_3/benchmark/Mesh_3/CMakeLists.txt new file mode 100644 index 00000000000..92bd608336f --- /dev/null +++ b/Mesh_3/benchmark/Mesh_3/CMakeLists.txt @@ -0,0 +1,110 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + + +project( Mesh_3_benchmark ) + +cmake_minimum_required(VERSION 2.6.2) +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6) + if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3) + cmake_policy(VERSION 2.8.4) + else() + cmake_policy(VERSION 2.6) + endif() +endif() + +# Creates a new CMake option, turned ON by default +option(ACTIVATE_MSVC_PRECOMPILED_HEADERS + "Activate precompiled headers in MSVC" + ON) + +# Macro to add precompiled headers for MSVC +# This function does two things: +# 1. Enable precompiled headers on each file which is listed in "SourcesVar". +# 2. Add the content of "PrecompiledSource" (e.g. "StdAfx.cpp") to "SourcesVar". +MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar) + IF(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS) + GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE) + SET(Sources ${${SourcesVar}}) + + SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource} + PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\"") + SET_SOURCE_FILES_PROPERTIES(${Sources} + PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeaders}\" /FI\"${PrecompiledHeader}\"") + # Add precompiled header to SourcesVar + LIST(APPEND ${SourcesVar} ${PrecompiledSource}) + ENDIF(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS) +ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER) +# The compiler might need more memory because of precompiled headers +if(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS AND NOT(MSVC_VERSION LESS 1310)) + set(CGAL_C_FLAGS "${CGAL_C_FLAGS} /Zm1000") + set(CGAL_CXX_FLAGS "${CGAL_CXX_FLAGS} /Zm1000") +endif() + +include_directories(../../include) +include_directories(../../../Triangulation_3/include) +include_directories(../../../STL_Extension/include) +include_directories(../../../AABB_tree/include) +add_definitions(-DCGAL_MESH_3_NO_DEPRECATED_SURFACE_INDEX + -DCGAL_MESH_3_NO_DEPRECATED_C3T3_ITERATORS) + +if ( MESH_3_VERBOSE ) + add_definitions(-DCGAL_MESH_3_VERBOSE) +endif() + +find_package(CGAL COMPONENTS ImageIO) + +if ( CGAL_FOUND ) + include( ${CGAL_USE_FILE} ) + + # Activate concurrency ? (turned OFF by default) + option(ACTIVATE_CONCURRENT_MESH_3 + "Activate parallelism in Mesh_3" + OFF) + + # And add -DCGAL_CONCURRENT_MESH_3 if that option is ON + if( ACTIVATE_CONCURRENT_MESH_3 ) + add_definitions( -DCGAL_CONCURRENT_MESH_3 ) + find_package( TBB REQUIRED ) + else() + option( LINK_WITH_TBB + "Link with TBB anyway so we can use TBB timers for profiling" + ON) + if( LINK_WITH_TBB ) + find_package( TBB ) + endif( LINK_WITH_TBB ) + endif() + + if( TBB_FOUND ) + include(${TBB_USE_FILE}) + list(APPEND CGAL_3RD_PARTY_LIBRARIES ${TBB_LIBRARIES}) + endif() + + # Link with Boost.ProgramOptions (optional) + find_package(Boost QUIET COMPONENTS program_options) + if(Boost_PROGRAM_OPTIONS_FOUND) + if( CGAL_AUTO_LINK_ENABLED ) + message( STATUS "Boost.ProgramOptions library: found" ) + else() + message( STATUS "Boost.ProgramOptions library: ${Boost_PROGRAM_OPTIONS_LIBRARY}" ) + endif() + add_definitions( "-DCGAL_USE_BOOST_PROGRAM_OPTIONS" ) + list(APPEND CGAL_3RD_PARTY_LIBRARIES ${Boost_LIBRARIES}) + endif() + + if ( Boost_FOUND AND Boost_VERSION GREATER 103400 ) + include( CGAL_CreateSingleSourceCGALProgram ) + + # Compilable benchmark + set (BENCHMARK_SOURCE_FILES "concurrency.cpp") + ADD_MSVC_PRECOMPILED_HEADER("StdAfx.h" "StdAfx.cpp" BENCHMARK_SOURCE_FILES) + create_single_source_cgal_program( ${BENCHMARK_SOURCE_FILES} ) + + else() + message(STATUS "NOTICE: This program requires Boost >= 1.34.1, and will not be compiled.") + endif() + +else() + message(STATUS "This program requires the CGAL library, and will not be compiled.") +endif() + diff --git a/Mesh_3/benchmark/Mesh_3/StdAfx.cpp b/Mesh_3/benchmark/Mesh_3/StdAfx.cpp new file mode 100644 index 00000000000..15668dcadef --- /dev/null +++ b/Mesh_3/benchmark/Mesh_3/StdAfx.cpp @@ -0,0 +1,2 @@ +// Build the precompiled headers. +#include "StdAfx.h" \ No newline at end of file diff --git a/Mesh_3/benchmark/Mesh_3/StdAfx.h b/Mesh_3/benchmark/Mesh_3/StdAfx.h new file mode 100644 index 00000000000..2c7f3b0abd4 --- /dev/null +++ b/Mesh_3/benchmark/Mesh_3/StdAfx.h @@ -0,0 +1,288 @@ +#ifndef STDAFX_H +#define STDAFX_H + +#include +#include +#include + +// STL +#include +#include +#include +#include +#include +#include +#include + +// Windows +#include + +// Boost +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// CGAL +//#include +//#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +//#include +#include +#include +//#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +//#include +//#include +//#include +//#include +//#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +#include +#include +#include + +// Mesh_3 +/*#include +#include +#include +#include +#include +#include +#include */ + +#endif //STDAFX_H \ No newline at end of file diff --git a/Mesh_3/benchmark/Mesh_3/concurrency.cpp b/Mesh_3/benchmark/Mesh_3/concurrency.cpp new file mode 100644 index 00000000000..765906e03b5 --- /dev/null +++ b/Mesh_3/benchmark/Mesh_3/concurrency.cpp @@ -0,0 +1,1033 @@ +//#define CHECK_MEMORY_LEAKS_ON_MSVC + +#if defined(CHECK_MEMORY_LEAKS_ON_MSVC) && defined(_MSC_VER) + #define _CRTDBG_MAP_ALLOC + #include + #include +#endif + +// Without TBB_USE_THREADING_TOOL Intel Inspector XE will report false positives in Intel TBB +// (http://software.intel.com/en-us/articles/compiler-settings-for-threading-error-analysis-in-intel-inspector-xe/) +#ifdef _DEBUG +# define TBB_USE_THREADING_TOOL +#endif + +#include +#include +#include +#include +#include + +#include +#ifdef CGAL_USE_BOOST_PROGRAM_OPTIONS +# include + namespace po = boost::program_options; +#endif + +#include +#include + +const char * const BENCHMARK_CONFIG_FILENAME = "concurrency_config.cfg"; +const char * const BENCHMARK_SCRIPT_FILENAME = "concurrency_script.txt"; + +// ========================================================================== +// BENCHMARK GENERAL PARAMETERS +// ========================================================================== + +//#define BENCHMARK_WITH_1_TO_MAX_THREADS +//#define CGAL_MESH_3_POLYHEDRON_WITH_FEATURES +//#define CGAL_MESH_3_IMPLICIT_WITH_FEATURES +//#define CGAL_MESH_3_BENCHMARK_EXPORT_TO_MAYA +//#define CGAL_MESH_3_BENCHMARK_EXPORT_TO_MESH +//#define CGAL_MESH_3_BENCHMARK_LLOYD +//#define CGAL_MESH_3_BENCHMARK_PERTURB +//#define CGAL_MESH_3_BENCHMARK_EXUDE + +// ========================================================================== +// MESH_3 GENERAL PARAMETERS +// ========================================================================== + +//#define CGAL_MESH_3_USE_OLD_SURFACE_RESTRICTED_DELAUNAY_UPDATE // WARNING: VERY SLOW +//#define CGAL_MESH_3_VERBOSE +//#define CGAL_MESH_3_PERTURBER_VERBOSE +//#define CGAL_MESH_3_PERTURBER_HIGH_VERBOSITY +//#define CGAL_MESH_3_EXUDER_VERBOSE +//#define CGAL_MESH_3_EXUDER_HIGH_VERBOSITY +//#define CGAL_MESH_3_VERY_VERBOSE +//#define CGAL_MESHES_DEBUG_REFINEMENT_POINTS +//#define CGAL_MESH_3_OPTIMIZER_VERBOSE +#define CGAL_MESH_3_INITIAL_POINTS_NO_RANDOM_SHOOTING + +#define CGAL_MESH_3_PROFILING +//#define CHECK_AND_DISPLAY_THE_NUMBER_OF_BAD_ELEMENTS_IN_THE_END + +const int FACET_ANGLE = 25; +const int TET_SHAPE = 3; + +// ========================================================================== +// CONCURRENCY +// ========================================================================== + +#ifdef CGAL_CONCURRENT_MESH_3 + +# ifndef CGAL_LINKED_WITH_TBB +# pragma message(" : Warning: CGAL_LINKED_WITH_TBB not defined: EVERYTHING WILL BE SEQUENTIAL.") +# endif + +//# define CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE // default behavior +//# define CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE +//# define CGAL_MESH_3_IF_UNSORTED_QUEUE_JUST_SORT_AFTER_SCAN // recommended +//#define CGAL_PARALLEL_MESH_3_DO_NOT_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE // not recommended + + // ========================================================================== + // Verbose + // ========================================================================== + +# define CGAL_CONCURRENT_MESH_3_VERBOSE +//# define CGAL_CONCURRENT_MESH_3_VERY_VERBOSE + + // ========================================================================== + // Concurrency config + // ========================================================================== + + const char * const CONFIG_FILENAME = "concurrent_mesher_config.cfg"; + + // ===================== + // Worksharing strategy + // ===================== + +//# define CGAL_MESH_3_LOAD_BASED_WORKSHARING // Not recommended +//# define CGAL_MESH_3_TASK_SCHEDULER_SORTED_BATCHES_WITH_MULTISET +//# define CGAL_MESH_3_TASK_SCHEDULER_SORTED_BATCHES_WITH_SORT // default + + // ========================================================================== + // Profiling + // ========================================================================== + + // For profiling, etc. +# define CGAL_CONCURRENT_MESH_3_PROFILING +//# define CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT + + // ========================================================================== + // TBB + // ========================================================================== +# if TBB_IMPLEMENT_CPP0X +# include +# else +# include +# endif + +// ========================================================================== +// SEQUENTIAL +// ========================================================================== + +#else // !CGAL_CONCURRENT_MESH_3 + +//# define CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE // default behavior +//# define CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE +//# define CGAL_MESH_3_IF_UNSORTED_QUEUE_JUST_SORT_AFTER_SCAN // recommended + +#endif // CGAL_CONCURRENT_MESH_3 + +// ========================================================================== +// ========================================================================== + +const char * const DEFAULT_INPUT_FILE_NAME = "elephant.off"; + +// ========================================================================== +// ========================================================================== + +#include "../../test/Mesh_3/XML_exporter.h" +#define CGAL_MESH_3_EXPORT_PERFORMANCE_DATA +#define CGAL_MESH_3_SET_PERFORMANCE_DATA(value_name, value) \ + XML_perf_data::set(value_name, value); + +class XML_perf_data +{ +public: + typedef Streaming_XML_exporter XML_exporter; + + XML_perf_data(const std::string &filename) + : m_xml(filename, "ContainerPerformance", "Perf", + construct_subelements_names()) + {} + + virtual ~XML_perf_data() + { + } + + static XML_perf_data &get() + { + static XML_perf_data singleton(build_filename()); + return singleton; + } + + template + static void set(const std::string &name, Value_type value) + { + get().set_data(name, value); + } + + static void commit() + { + get().commit_current_element(); + } + +protected: + static std::string build_filename() + { + std::stringstream sstr; + sstr << "Performance_log_" << time(0) << ".xml"; + return sstr.str(); + } + + static std::vector construct_subelements_names() + { + std::vector subelements; + subelements.push_back("Domain"); + subelements.push_back("Facet_angle"); + subelements.push_back("Facet_size"); + subelements.push_back("Facet_approx"); + subelements.push_back("Cell_size"); + subelements.push_back("Cell_shape"); + subelements.push_back("Technique"); + subelements.push_back("Num_threads"); + subelements.push_back("Lockgrid_size"); + subelements.push_back("Lock_radius"); + subelements.push_back("Statgrid_size"); + subelements.push_back("Num_work_items_per_batch"); + subelements.push_back("V"); + subelements.push_back("F"); + subelements.push_back("T"); + subelements.push_back("Facets_time"); + subelements.push_back("Cells_scan_time"); + subelements.push_back("Cells_refin_time"); + subelements.push_back("Lloyd_optim_time"); + subelements.push_back("Odt_optim_time"); + subelements.push_back("Perturber_optim_time"); + subelements.push_back("Exuder_optim_time"); + subelements.push_back("Mem"); + + return subelements; + } + + void set_data(const std::string &name, const std::string &value) + { + m_current_element[name] = value; + } + + template + void set_data(const std::string &name, Value_type value) + { + std::stringstream sstr; + sstr << value; + set_data(name, sstr.str()); + } + + void commit_current_element() + { + m_xml.add_element(m_current_element); + m_current_element.clear(); + } + + XML_exporter m_xml; + XML_exporter::Element_with_map m_current_element; +}; + + +// ========================================================================== +// ========================================================================== + + + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CGAL_MESH_3_POLYHEDRON_WITH_FEATURES +# include +#endif + +// basic types from kernel +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef Kernel::FT FT; +typedef Kernel::Point_3 Point; +typedef Kernel::Sphere_3 Sphere; +// IO +#include + +// To avoid verbose function and named parameters call +using namespace CGAL::parameters; + +struct Mesh_parameters +{ + double facet_approx; + double facet_sizing; + double facet_angle; + + double tet_shape; + double tet_sizing; + + std::string log() const + { + std::stringstream sstr; + sstr + << " * facet approx error: " << facet_approx << std::endl + << " * facet max size: " << facet_sizing << std::endl + << " * facet min angle: " << facet_angle << std::endl + << " * tet shape (radius-edge): " << tet_shape << std::endl + << " * tet max size: " << tet_sizing << std::endl; + + return sstr.str(); + } +}; + +struct Klein_function +{ + typedef ::FT FT; + typedef ::Point Point; + + FT operator()(const Point& query) const + { + const FT x = query.x(); + const FT y = query.y(); + const FT z = query.z(); + + return (x*x+y*y+z*z+2*y-1) + * ( (x*x+y*y+z*z-2*y-1) *(x*x+y*y+z*z-2*y-1)-8*z*z) + + 16*x*z* (x*x+y*y+z*z-2*y-1); + } +}; + +struct Tanglecube_function +{ + typedef ::FT FT; + typedef ::Point Point; + + FT operator()(const Point& query) const + { + const FT x = query.x(); + const FT y = query.y(); + const FT z = query.z(); + + double x2=x*x, y2=y*y, z2=z*z; + double x4=x2*x2, y4=y2*y2, z4=z2*z2; + return x4 - 5*x2 + y4 - 5*y2 + z4 - 5*z2 + 11.8; + } +}; + +struct Sphere_function +{ + typedef ::FT FT; + typedef ::Point Point; + + Sphere_function(double radius = 1.) + : m_squared_radius(radius*radius) + {} + + FT operator()(const Point& query) const + { + const FT x = query.x(); + const FT y = query.y(); + const FT z = query.z(); + + return (x*x + y*y + z*z - m_squared_radius); + } + +protected: + FT m_squared_radius; +}; + +struct Cylinder_function +{ + typedef ::FT FT; + typedef ::Point Point; + + Cylinder_function(double radius = 0.5, double height = 2.) + : m_radius(radius), m_height(height) + {} + + FT operator()(const Point& query) const + { + const FT x = query.x(); + const FT y = query.y(); + const FT z = query.z(); + + if (z > 0.5*m_height) + return z - 0.5*m_height; + else if (z < -0.5*m_height) + return -z + 0.5*m_height; + else + return (x*x + y*y - m_radius*m_radius); + } + +protected: + FT m_radius; + FT m_height; +}; + + +std::string get_technique() +{ + std::string tech; +#ifdef CGAL_CONCURRENT_MESH_3 + + tech += "Task-scheduler (auto"; +# if defined(CGAL_MESH_3_TASK_SCHEDULER_SORTED_BATCHES_WITH_MULTISET) + tech += ", sorted batches with multiset"; +# elif defined(CGAL_MESH_3_LOAD_BASED_WORKSHARING) + tech += ", load-based worksharing"; +# else // CGAL_MESH_3_TASK_SCHEDULER_SORTED_BATCHES_WITH_SORT + tech += ", sorted batches with std::sort"; +# endif + tech += ")"; + +#else // !CGAL_CONCURRENT_MESH_3 + + tech += "Sequential "; +# if defined(CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE) +# ifdef CGAL_MESH_3_IF_UNSORTED_QUEUE_JUST_SORT_AFTER_SCAN + tech += "(sort after scan only"; +# else + tech += "(unsorted"; +# endif +# elif defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) + tech += "(sorted"; +# else + tech += "(NOT LAZY, sorted"; +# endif + +#ifdef CGAL_SEQUENTIAL_MESH_3_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE + tech += ", points on far sphere)"; +#else + tech += ")"; +#endif + +#endif // CGAL_CONCURRENT_MESH_3 + + return tech; +} + +void xml_perf_set_technique() +{ + CGAL_MESH_3_SET_PERFORMANCE_DATA("Technique", get_technique()); +} + + +void display_info(int num_threads) +{ + std::cerr << get_technique() << std::endl; + +#ifdef CGAL_CONCURRENT_MESH_3 + + if (num_threads != -1) + std::cerr << "Num threads = " << num_threads << std::endl; + else + std::cerr << "Num threads = AUTO" << std::endl; + +#else // !CGAL_CONCURRENT_MESH_3 + +# ifdef CGAL_MESH_3_INITIAL_POINTS_NO_RANDOM_SHOOTING + std::cerr << "NO random shooting)" << std::endl; +# else + std::cerr << "WITH random shooting)" << std::endl; +# endif + +#endif // CGAL_CONCURRENT_MESH_3 +} + +// To add a crease (feature) +typedef std::vector Crease; +typedef std::list Creases; +void add_crease(const Point& a, + const Point& b, + Creases& creases) +{ + Crease crease; + crease.push_back(a); + crease.push_back(b); + creases.push_back(crease); +} + +bool make_mesh_polyhedron(const std::string &input_filename, + double facet_approx, + double facet_sizing, + double cell_sizing) +{ + // Domain + typedef Kernel K; + +#ifdef CGAL_MESH_3_POLYHEDRON_WITH_FEATURES + typedef CGAL::Mesh_polyhedron_3::type Polyhedron; + typedef CGAL::Polyhedral_mesh_domain_with_features_3 Mesh_domain; +#else + typedef CGAL::Polyhedron_3 Polyhedron; + typedef CGAL::Polyhedral_mesh_domain_3 Mesh_domain; +#endif + + // Triangulation +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, + CGAL::Parallel_tag>::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif + // C3t3 + typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; + // Criteria + typedef CGAL::Mesh_criteria_3 Mesh_criteria; + + // Create input polyhedron + Polyhedron polyhedron; + std::ifstream input(input_filename.c_str()); + if (!input.is_open()) + { + std::cerr << "Could not open '" << input_filename << "'" << std::endl; + return false; + } + input >> polyhedron; + + std::cerr << "Building AABB tree... "; + // Create domain + Mesh_domain domain(polyhedron); + std::cerr << "done." << std::endl; + +#ifdef CGAL_MESH_3_POLYHEDRON_WITH_FEATURES + std::cerr << "Detecting features... "; + domain.detect_features(); + std::cerr << "done." << std::endl; +#endif + + Mesh_parameters params; + params.facet_approx = facet_approx; + params.facet_sizing = facet_sizing; + params.facet_angle = FACET_ANGLE; + params.tet_sizing = cell_sizing; + params.tet_shape = TET_SHAPE; + + std::cerr + << "File: " << input_filename << std::endl + << "Parameters: " << std::endl + << params.log() << std::endl; + + // Mesh criteria (no cell_size set) + Mesh_criteria criteria( + edge_size=params.facet_sizing, + facet_angle=params.facet_angle, + facet_size=params.facet_sizing, + facet_distance=params.facet_approx, + cell_size=params.tet_sizing, + cell_radius_edge_ratio=params.tet_shape + ); + + // Mesh generation +#ifdef _DEBUG + double timelimit = 10; + double sliverbound = 2; +#else + double timelimit = 0; + double sliverbound = 2; +#endif + + C3t3 c3t3 = CGAL::make_mesh_3( domain + , criteria +# ifdef CGAL_MESH_3_BENCHMARK_LLOYD + , lloyd(time_limit=timelimit) +# else + , no_lloyd() +# endif + , no_odt() +# ifdef CGAL_MESH_3_BENCHMARK_PERTURB + , perturb(time_limit = timelimit, + sliver_bound = sliverbound) +# else + , no_perturb() +#endif +#ifdef CGAL_MESH_3_BENCHMARK_EXUDE + , exude(time_limit = timelimit, + sliver_bound = sliverbound) +#else + , no_exude() +#endif + ); + + CGAL_MESH_3_SET_PERFORMANCE_DATA("V", c3t3.triangulation().number_of_vertices()); + CGAL_MESH_3_SET_PERFORMANCE_DATA("F", c3t3.number_of_facets_in_complex()); + CGAL_MESH_3_SET_PERFORMANCE_DATA("T", c3t3.number_of_cells_in_complex()); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Mem", CGAL::Memory_sizer().virtual_size() >> 20); + +#ifdef CGAL_MESH_3_BENCHMARK_EXPORT_TO_MAYA + std::cerr << "Exporting to maya file format (*.maya)... "; + c3t3.output_to_maya(std::ofstream(input_filename + ".maya"), true); + std::cerr << "done." << std::endl; +#endif + +#ifdef CGAL_MESH_3_BENCHMARK_EXPORT_TO_MESH + std::cerr << "Exporting to Medit file format (*.mesh)... "; + c3t3.output_to_medit(std::ofstream(input_filename + ".mesh"), true); + std::cerr << "done." << std::endl; +#endif + + return true; +} + + +bool make_mesh_3D_images(const std::string &input_filename, + double facet_approx, + double facet_sizing, + double cell_sizing) +{ + // Domain + typedef Kernel K; + + typedef CGAL::Labeled_image_mesh_domain_3 Mesh_domain; + + // Triangulation +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, + CGAL::Parallel_tag>::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif + // C3t3 + typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; + // Criteria + typedef CGAL::Mesh_criteria_3 Mesh_criteria; + + // Load image + CGAL::Image_3 image; + image.read(input_filename.c_str()); + + // Create domain + Mesh_domain domain(image); + std::cerr << "done." << std::endl; + + Mesh_parameters params; + params.facet_approx = facet_approx; + params.facet_sizing = facet_sizing; + params.facet_angle = FACET_ANGLE; + params.tet_sizing = cell_sizing; + params.tet_shape = TET_SHAPE; + + std::cerr + << "File: " << input_filename << std::endl + << "Parameters: " << std::endl + << params.log() << std::endl; + + // Mesh criteria (no cell_size set) + Mesh_criteria criteria( + edge_size=params.facet_sizing, + facet_angle=params.facet_angle, + facet_size=params.facet_sizing, + facet_distance=params.facet_approx, + cell_size=params.tet_sizing, + cell_radius_edge_ratio=params.tet_shape + ); + + // Mesh generation +#ifdef _DEBUG + double timelimit = 10; + double sliverbound = 2; +#else + double timelimit = 0; + double sliverbound = 2; +#endif + + C3t3 c3t3 = CGAL::make_mesh_3( domain + , criteria +# ifdef CGAL_MESH_3_BENCHMARK_LLOYD + , lloyd(time_limit=timelimit) +# else + , no_lloyd() +# endif + , no_odt() +# ifdef CGAL_MESH_3_BENCHMARK_PERTURB + , perturb(time_limit = timelimit, + sliver_bound = sliverbound) +# else + , no_perturb() +#endif +#ifdef CGAL_MESH_3_BENCHMARK_EXUDE + , exude(time_limit = timelimit, + sliver_bound = sliverbound) +#else + , no_exude() +#endif + ); + + CGAL_MESH_3_SET_PERFORMANCE_DATA("V", c3t3.triangulation().number_of_vertices()); + CGAL_MESH_3_SET_PERFORMANCE_DATA("F", c3t3.number_of_facets_in_complex()); + CGAL_MESH_3_SET_PERFORMANCE_DATA("T", c3t3.number_of_cells_in_complex()); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Mem", CGAL::Memory_sizer().virtual_size() >> 20); + +#ifdef CGAL_MESH_3_BENCHMARK_EXPORT_TO_MAYA + std::cerr << "Exporting to maya file format (*.maya)... "; + c3t3.output_to_maya(std::ofstream(input_filename + ".maya"), true); + std::cerr << "done." << std::endl; +#endif + +#ifdef CGAL_MESH_3_BENCHMARK_EXPORT_TO_MESH + std::cerr << "Exporting to Medit file format (*.mesh)... "; + c3t3.output_to_medit(std::ofstream(input_filename + ".mesh"), true); + std::cerr << "done." << std::endl; +#endif + + return true; +} + + +template +bool make_mesh_implicit(double facet_approx, + double facet_sizing, + double cell_sizing, + ImplicitFunction func, + const std::string &function_name) +{ + // Domain +#ifdef CGAL_MESH_3_IMPLICIT_WITH_FEATURES + typedef CGAL::Implicit_mesh_domain_3 Implicit_domain; + typedef CGAL::Mesh_domain_with_polyline_features_3 Mesh_domain; +#else + typedef CGAL::Implicit_mesh_domain_3 Mesh_domain; +#endif + + // Triangulation +#ifdef CGAL_CONCURRENT_MESH_3 + typedef typename CGAL::Mesh_triangulation_3< + Mesh_domain, + typename CGAL::Kernel_traits::Kernel, + CGAL::Parallel_tag>::type Tr; +#else + typedef typename CGAL::Mesh_triangulation_3::type Tr; +#endif + // C3t3 + typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; + // Criteria + typedef CGAL::Mesh_criteria_3 Mesh_criteria; + + // Create domain + Sphere bounding_sphere(CGAL::ORIGIN, 10.0 * 10.0); + Mesh_domain domain(func, bounding_sphere/*, 1e-7*/); + +#ifdef CGAL_MESH_3_IMPLICIT_WITH_FEATURES + // Add 12 feature creases + Creases creases; + Point p1(-1.0, -1.0, -1.0); + Point p2(-1.0, -1.0, 1.0); + Point p3(-1.0, 1.0, 1.0); + Point p4(-1.0, 1.0, -1.0); + Point p5( 1.0, -1.0, -1.0); + Point p6( 1.0, -1.0, 1.0); + Point p7( 1.0, 1.0, 1.0); + Point p8( 1.0, 1.0, -1.0); + + add_crease(p1, p2, creases); + add_crease(p2, p3, creases); + add_crease(p3, p4, creases); + add_crease(p4, p1, creases); + + add_crease(p5, p6, creases); + add_crease(p6, p7, creases); + add_crease(p7, p8, creases); + add_crease(p8, p5, creases); + + add_crease(p5, p1, creases); + add_crease(p6, p2, creases); + add_crease(p7, p3, creases); + add_crease(p8, p4, creases); + + domain.add_features(creases.begin(), creases.end()); +#endif + + Mesh_parameters params; + params.facet_angle = FACET_ANGLE; + params.facet_sizing = facet_sizing; + params.facet_approx = facet_approx; + params.tet_sizing = cell_sizing; + params.tet_shape = TET_SHAPE; + + std::cerr + << "Implicit function" << std::endl + << "Parameters: " << std::endl + << params.log() << std::endl; + + // Mesh criteria (no cell_size set) + Mesh_criteria criteria( + edge_size=params.facet_sizing, + facet_angle=params.facet_angle, + facet_size=params.facet_sizing, + facet_distance=params.facet_approx, + cell_size=params.tet_sizing, + cell_radius_edge_ratio=params.tet_shape + ); + + // Mesh generation +#ifdef _DEBUG + double timelimit = 10; + double sliverbound = 2; +#else + double timelimit = 0; + double sliverbound = 2; +#endif + + C3t3 c3t3 = CGAL::make_mesh_3( domain + , criteria +# ifdef CGAL_MESH_3_BENCHMARK_LLOYD + , lloyd(time_limit=timelimit) +# else + , no_lloyd() +# endif + , no_odt() +# ifdef CGAL_MESH_3_BENCHMARK_PERTURB + , perturb(time_limit = timelimit, + sliver_bound = sliverbound) +# else + , no_perturb() +#endif +#ifdef CGAL_MESH_3_BENCHMARK_EXUDE + , exude(time_limit = timelimit, + sliver_bound = sliverbound) +#else + , no_exude() +#endif + ); + + CGAL_MESH_3_SET_PERFORMANCE_DATA("V", c3t3.triangulation().number_of_vertices()); + CGAL_MESH_3_SET_PERFORMANCE_DATA("F", c3t3.number_of_facets_in_complex()); + CGAL_MESH_3_SET_PERFORMANCE_DATA("T", c3t3.number_of_cells_in_complex()); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Mem", CGAL::Memory_sizer().virtual_size() >> 20); + +#ifdef CGAL_MESH_3_BENCHMARK_EXPORT_TO_MAYA + std::cerr << "Exporting to maya file format (*.maya)... "; + c3t3.output_to_maya(std::ofstream(function_name + ".maya"), true); + std::cerr << "done." << std::endl; +#endif + +#ifdef CGAL_MESH_3_BENCHMARK_EXPORT_TO_MESH + std::cerr << "Exporting to Medit file format (*.mesh)... "; + c3t3.output_to_medit(std::ofstream(function_name + ".mesh"), true); + std::cerr << "done." << std::endl; +#endif + + return true; +} + +int main() +{ +#if defined(CHECK_MEMORY_LEAKS_ON_MSVC) && defined(_MSC_VER) + _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); +#endif + +#ifdef CGAL_USE_BOOST_PROGRAM_OPTIONS + // Program options + po::variables_map vm; + try + { + // Declare the supported options. + po::options_description desc("Allowed options"); + desc.add_options() + ("filename", po::value()->default_value(DEFAULT_INPUT_FILE_NAME), "") + ("facet_approx", po::value()->default_value(0.0068), "") + ("facet_sizing", po::value()->default_value(0.005), "") + ("cell_sizing", po::value()->default_value(0.005), "") + ("numthreads", po::value()->default_value(-1), ""); + + std::ifstream in(BENCHMARK_CONFIG_FILENAME); + po::store(po::parse_config_file(in, desc), vm); + po::notify(vm); + } + catch (std::exception &e) + { + std::cerr << "Config file error: " << e.what() << std::endl; + return false; + } + int num_threads = vm["numthreads"].as(); + double facet_approx = vm["facet_approx"].as(); + double facet_sizing = vm["facet_sizing"].as(); + double cell_sizing = vm["cell_sizing"].as(); + std::string filename = vm["filename"].as(); + +#else // no CGAL_USE_BOOST_PROGRAM_OPTIONS + int num_threads = -1; + double facet_approx = 0.0068; + double facet_sizing = 0.005; + double cell_sizing = 0.005; + std::string filename = DEFAULT_INPUT_FILE_NAME; + +#endif + +#ifdef CGAL_CONCURRENT_MESH_3 + Concurrent_mesher_config::load_config_file(CONFIG_FILENAME, true); +#endif + + std::ifstream script_file; + script_file.open(BENCHMARK_SCRIPT_FILENAME); + // Script? + // Script file format: each line gives + // - Filename (polyhedron) or "XXX_function" (implicit) + // - Facet sizing + // - Cell sizing + // - Number of iterations with these parameters + if (script_file.is_open()) + { + int i = 1; +#ifdef CGAL_CONCURRENT_MESH_3 +# ifdef BENCHMARK_WITH_1_TO_MAX_THREADS + for(num_threads = 1 ; + num_threads <= tbb::task_scheduler_init::default_num_threads() ; + ++num_threads) +# endif + /*for (Concurrent_mesher_config::get().num_work_items_per_batch = 5 ; + Concurrent_mesher_config::get().num_work_items_per_batch < 100 ; + Concurrent_mesher_config::get().num_work_items_per_batch += 5)*/ +#endif + { +#ifdef CGAL_CONCURRENT_MESH_3 + tbb::task_scheduler_init init( + num_threads > 0 ? num_threads : tbb::task_scheduler_init::automatic); +#endif + + std::cerr << "Script file '" << BENCHMARK_SCRIPT_FILENAME << "' found." << std::endl; + script_file.seekg(0); + while (script_file.good()) + { + std::string line; + std::getline(script_file, line); + if (line.size() > 1 && line[0] != '#') + { + std::cerr << std::endl << std::endl; + std::cerr << "*****************************************" << std::endl; + std::cerr << "******* " << line << std::endl; + std::cerr << "*****************************************" << std::endl; + std::stringstream sstr(line); + + std::string input; + double facet_approx; + double facet_sizing; + double cell_sizing; + int num_iteration; + sstr >> input; + sstr >> facet_approx; + sstr >> facet_sizing; + sstr >> cell_sizing; + sstr >> num_iteration; + + for (int j = 0 ; j < num_iteration ; ++j) + { + std::string domain = input; + size_t slash_index = domain.find_last_of('/'); + if (slash_index == std::string::npos) + slash_index = domain.find_last_of('\\'); + if (slash_index == std::string::npos) + slash_index = 0; + else + ++slash_index; + domain = domain.substr( + slash_index, domain.find_last_of('.') - slash_index); + + CGAL_MESH_3_SET_PERFORMANCE_DATA("Domain", domain); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Facet_approx", facet_approx); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Facet_size", facet_sizing); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Facet_angle", FACET_ANGLE); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Cell_size", cell_sizing); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Cell_shape", TET_SHAPE); + xml_perf_set_technique(); +#ifdef CGAL_CONCURRENT_MESH_3 + CGAL_MESH_3_SET_PERFORMANCE_DATA( + "Num_threads", + (num_threads == -1 ? boost::thread::hardware_concurrency() : num_threads)); + CGAL_MESH_3_SET_PERFORMANCE_DATA( + "Lockgrid_size", + Concurrent_mesher_config::get().locking_grid_num_cells_per_axis); + CGAL_MESH_3_SET_PERFORMANCE_DATA( + "Lock_radius", + Concurrent_mesher_config::get().first_grid_lock_radius); + CGAL_MESH_3_SET_PERFORMANCE_DATA( + "Statgrid_size", + Concurrent_mesher_config::get().work_stats_grid_num_cells_per_axis); + CGAL_MESH_3_SET_PERFORMANCE_DATA( + "Num_work_items_per_batch", + Concurrent_mesher_config::get().num_work_items_per_batch); +#else + CGAL_MESH_3_SET_PERFORMANCE_DATA("Num_threads", "N/A"); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Lockgrid_size", "N/A"); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Lock_radius", "N/A"); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Statgrid_size", "N/A"); + CGAL_MESH_3_SET_PERFORMANCE_DATA("Num_work_items_per_batch", "N/A"); +#endif + + std::cerr << std::endl << "Refinement #" << i << "..." << std::endl; + + display_info(num_threads); + + if (input == "Klein_function") + make_mesh_implicit(facet_approx, facet_sizing, cell_sizing, Klein_function(), input); + /*else if (input == "Tanglecube_function") + make_mesh_implicit(facet_approx, facet_sizing, cell_sizing, Tanglecube_function(), input); + else if (input == "Sphere_function") + make_mesh_implicit(facet_approx, facet_sizing, cell_sizing, Sphere_function(1.), input); + else if (input == "Thin_cylinder_function") + { + Cylinder_function f(0.05, 3.); + make_mesh_implicit(facet_approx, facet_sizing, cell_sizing, f, input); + } + else if (input == "Pancake_function") + { + Cylinder_function f(3., 0.1); + make_mesh_implicit(facet_approx, facet_sizing, cell_sizing, f, input); + }*/ + else + { + size_t dot_position = input.find_last_of('.'); + std::string extension = input.substr(dot_position + 1); + if (extension == "off") + make_mesh_polyhedron(input, facet_approx, facet_sizing, cell_sizing); + else if (extension == "inr") + make_mesh_3D_images(input, facet_approx, facet_sizing, cell_sizing); + } + + std::cerr << "Refinement #" << i++ << " done." << std::endl; + std::cerr << std::endl << "---------------------------------" << std::endl << std::endl; + + XML_perf_data::commit(); + } + } + } + script_file.seekg(0); + script_file.clear(); + } + + script_file.close(); + } + // Or not script? + else + { + std::cerr << "Script file '" << BENCHMARK_SCRIPT_FILENAME << "' NOT found." << std::endl; + for(int i = 1 ; ; ++i) + { + std::cerr << "Refinement #" << i << "..." << std::endl; + display_info(num_threads); + make_mesh_polyhedron(filename, facet_approx, facet_sizing, cell_sizing); + //make_mesh_implicit(facet_approx, facet_sizing, cell_sizing, Klein_function(), "Klein_function"); + std::cerr << "Refinement #" << i << " done." << std::endl; + std::cerr << std::endl << "---------------------------------" << std::endl << std::endl; + } + } + + return 0; +} diff --git a/Mesh_3/benchmark/Mesh_3/concurrency_config.cfg b/Mesh_3/benchmark/Mesh_3/concurrency_config.cfg new file mode 100644 index 00000000000..57d6a2329ad --- /dev/null +++ b/Mesh_3/benchmark/Mesh_3/concurrency_config.cfg @@ -0,0 +1,6 @@ +#filename=D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off +filename=D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off +facet_sizing=0.01 +cell_sizing=0.03 +numthreads=11 # default = -1 (auto) + \ No newline at end of file diff --git a/Mesh_3/benchmark/Mesh_3/concurrency_script.txt b/Mesh_3/benchmark/Mesh_3/concurrency_script.txt new file mode 100644 index 00000000000..8c8eec7eb30 --- /dev/null +++ b/Mesh_3/benchmark/Mesh_3/concurrency_script.txt @@ -0,0 +1,266 @@ +######################################################### +##### Benchmark MAX (warning: requires a lot of RAM!) +######################################################### +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.002 0.002 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.003 0.003 1 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.0015 0.0015 1 +#D:/INRIA/Data/_Models/BigOFF/bimba_400kf.off 0.0068 0.002 0.003 1 +#Klein_function 0.0068 0.01 0.03 1 +#Tanglecube_function 0.0068 0.005 0.025 1 +#Sphere_function 0.0068 0.003 0.01 1 +#Thin_cylinder_function 0.0068 0.001 0.002 1 +#Pancake_function 0.0068 0.007 0.01 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.002 0.002 2 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.003 0.003 2 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.0015 0.0015 2 +#D:/INRIA/Data/_Models/BigOFF/bimba_400kf.off 0.0068 0.002 0.003 2 +#Klein_function 0.0068 0.01 0.03 2 +#Tanglecube_function 0.0068 0.005 0.025 2 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/cheese.off 0.0068 0.002 0.002 1 + +######################################################### +##### Benchmark for refinement+optim +######################################################### +#../../examples/Mesh_3/data/elephant.off 0.05 0.04 0.04 10000 +#../../examples/Mesh_3/data/elephant.off 0.01 0.004 0.004 10000 +../../examples/Mesh_3/data/elephant.off 0.0068 0.002 0.0025 10000 # typical timing (11 thr): 4.4 2.3 9.9 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.002 0.0025 10000 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.003 0.006 1 # typical timing (11 thr): 2.4 1.0 2.9 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.0015 0.003 1 +#D:/INRIA/Data/_Models/BigOFF/bimba_400kf.off 0.0068 0.003 0.006 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/cheese.off 0.0068 0.002 0.002 1 +#Klein_function 0.0068 0.01 0.06 1 +#Pancake_function 0.0068 0.02 0.02 1 +#Tanglecube_function 0.0068 0.007 0.035 1 +#Sphere_function 0.0068 0.006 0.02 1 +#Thin_cylinder_function 0.0068 0.002 0.004 1 + +######################################################### +##### Benchmark according to number of elements +######################################################### +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.006 0.006 10 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.005 0.005 10 + +######################################################### +##### Middle class +######################################################### +#Klein_function 0.0068 0.005 2.02 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.005 0.005 1 + +######################################################### +##### A few seconds +######################################################### +#Klein_function 0.0068 0.02 0.05 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.003 0.003 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.008 0.008 2 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/cheese.off 0.0068 0.005 0.005 1 + +######################################################### +##### Instant +######################################################### +#Klein_function 0.0068 0.2 0.5 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.03 0.03 5 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.05 0.05 5 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.068 0.068 1500 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 2.68 2.68 150 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 1.68 1.68 150 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 2.68 2.68 150 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 1.68 1.68 150 +#D:/INRIA/CGAL/svn/cgal/trunk/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.05 0.05 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0200 0.05 0.25 2 + +######################################################### +##### Benchmark for TOMS article +######################################################### +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.002 0.002 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.003 0.003 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.004 0.004 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.005 0.005 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.006 0.006 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.007 0.007 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.008 0.008 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.010 0.010 1 + +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.003 0.003 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.0035 0.0035 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.004 0.004 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.005 0.005 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.006 0.006 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.007 0.007 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.008 0.008 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.010 0.010 1 + +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.0015 0.0015 1 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.002 0.002 1 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.003 0.003 1 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.004 0.004 1 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.005 0.005 1 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.006 0.006 1 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.007 0.007 1 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.008 0.008 1 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.010 0.010 1 + +#D:/INRIA/Data/_Models/BigOFF/bimba_400kf.off 0.0068 0.003 0.003 1 +#D:/INRIA/Data/_Models/BigOFF/bimba_400kf.off 0.0068 0.004 0.004 1 +#D:/INRIA/Data/_Models/BigOFF/bimba_400kf.off 0.0068 0.005 0.005 1 +#D:/INRIA/Data/_Models/BigOFF/bimba_400kf.off 0.0068 0.006 0.006 1 +#D:/INRIA/Data/_Models/BigOFF/bimba_400kf.off 0.0068 0.007 0.007 1 +#D:/INRIA/Data/_Models/BigOFF/bimba_400kf.off 0.0068 0.008 0.008 1 +#D:/INRIA/Data/_Models/BigOFF/bimba_400kf.off 0.0068 0.010 0.010 1 + +#D:/INRIA/Data/_Models/BigOFF/david_200kv.off 0.0068 0.0015 0.0015 1 +#D:/INRIA/Data/_Models/BigOFF/david_200kv.off 0.0068 0.0017 0.0017 1 +#D:/INRIA/Data/_Models/BigOFF/david_200kv.off 0.0068 0.002 0.002 1 +#D:/INRIA/Data/_Models/BigOFF/david_200kv.off 0.0068 0.0025 0.0025 1 +#D:/INRIA/Data/_Models/BigOFF/david_200kv.off 0.0068 0.003 0.003 1 +#D:/INRIA/Data/_Models/BigOFF/david_200kv.off 0.0068 0.004 0.004 1 +#D:/INRIA/Data/_Models/BigOFF/david_200kv.off 0.0068 0.005 0.005 1 +#D:/INRIA/Data/_Models/BigOFF/david_200kv.off 0.0068 0.006 0.006 1 +#D:/INRIA/Data/_Models/BigOFF/david_200kv.off 0.0068 0.007 0.007 1 +#D:/INRIA/Data/_Models/BigOFF/david_200kv.off 0.0068 0.008 0.008 1 +#D:/INRIA/Data/_Models/BigOFF/david_200kv.off 0.0068 0.010 0.010 1 + +#D:/INRIA/Data/_Models/CAD/ecrou-larousse.off 0.0068 0.003 0.003 1 +#D:/INRIA/Data/_Models/CAD/ecrou-larousse.off 0.0068 0.004 0.004 1 +#D:/INRIA/Data/_Models/CAD/ecrou-larousse.off 0.0068 0.005 0.005 1 +#D:/INRIA/Data/_Models/CAD/ecrou-larousse.off 0.0068 0.006 0.006 1 +#D:/INRIA/Data/_Models/CAD/ecrou-larousse.off 0.0068 0.007 0.007 1 +#D:/INRIA/Data/_Models/CAD/ecrou-larousse.off 0.0068 0.008 0.008 1 +#D:/INRIA/Data/_Models/CAD/ecrou-larousse.off 0.0068 0.010 0.010 1 + +#D:/INRIA/Data/_Models/CAD/turbine.off 0.0068 0.002 0.002 1 +#D:/INRIA/Data/_Models/CAD/turbine.off 0.0068 0.003 0.003 1 +#D:/INRIA/Data/_Models/CAD/turbine.off 0.0068 0.004 0.004 1 +#D:/INRIA/Data/_Models/CAD/turbine.off 0.0068 0.005 0.005 1 +#D:/INRIA/Data/_Models/CAD/turbine.off 0.0068 0.006 0.006 1 +#D:/INRIA/Data/_Models/CAD/turbine.off 0.0068 0.007 0.007 1 +#D:/INRIA/Data/_Models/CAD/turbine.off 0.0068 0.008 0.008 1 +#D:/INRIA/Data/_Models/CAD/turbine.off 0.0068 0.010 0.010 1 + +#D:/INRIA/Data/_Models/CAD/cheese.off 0.0068 0.0004 0.0004 1 +#D:/INRIA/Data/_Models/CAD/cheese.off 0.0068 0.0005 0.0005 1 +#D:/INRIA/Data/_Models/CAD/cheese.off 0.0068 0.0007 0.0007 1 +#D:/INRIA/Data/_Models/CAD/cheese.off 0.0068 0.001 0.001 1 +#D:/INRIA/Data/_Models/CAD/cheese.off 0.0068 0.002 0.002 1 +#D:/INRIA/Data/_Models/CAD/cheese.off 0.0068 0.004 0.004 1 +#D:/INRIA/Data/_Models/CAD/cheese.off 0.0068 0.005 0.005 1 +#D:/INRIA/Data/_Models/CAD/cheese.off 0.0068 0.007 0.007 1 +#D:/INRIA/Data/_Models/CAD/cheese.off 0.0068 0.010 0.010 1 + +#D:/INRIA/Data/_Models/CAD/pump_carter.off 0.0068 0.002 0.002 1 +#D:/INRIA/Data/_Models/CAD/pump_carter.off 0.0068 0.003 0.003 1 +#D:/INRIA/Data/_Models/CAD/pump_carter.off 0.0068 0.004 0.004 1 +#D:/INRIA/Data/_Models/CAD/pump_carter.off 0.0068 0.005 0.005 1 +#D:/INRIA/Data/_Models/CAD/pump_carter.off 0.0068 0.006 0.006 1 +#D:/INRIA/Data/_Models/CAD/pump_carter.off 0.0068 0.007 0.007 1 +#D:/INRIA/Data/_Models/CAD/pump_carter.off 0.0068 0.008 0.008 1 +#D:/INRIA/Data/_Models/CAD/pump_carter.off 0.0068 0.010 0.010 1 + +#Thin_cylinder_function 0.0068 0.001 0.003 1 +#Thin_cylinder_function 0.0068 0.002 0.006 1 +#Thin_cylinder_function 0.0068 0.003 0.01 1 +#Thin_cylinder_function 0.0068 0.006 0.02 1 +#Thin_cylinder_function 0.0068 0.01 0.03 1 +#Thin_cylinder_function 0.0068 0.012 0.035 1 +#Thin_cylinder_function 0.0068 0.013 0.04 1 +#Thin_cylinder_function 0.0068 0.017 0.05 1 +#Thin_cylinder_function 0.0068 0.02 0.06 1 +#Thin_cylinder_function 0.0068 0.023 0.07 1 +#Thin_cylinder_function 0.0068 0.027 0.08 1 +#Thin_cylinder_function 0.0068 0.033 0.10 1 + +#Pancake_function 0.0068 0.004 0.013 1 +#Pancake_function 0.0068 0.006 0.02 1 +#Pancake_function 0.0068 0.01 0.03 1 +#Pancake_function 0.0068 0.012 0.035 1 +#Pancake_function 0.0068 0.013 0.04 1 +#Pancake_function 0.0068 0.017 0.05 1 +#Pancake_function 0.0068 0.02 0.06 1 +#Pancake_function 0.0068 0.023 0.07 1 +#Pancake_function 0.0068 0.027 0.08 1 +#Pancake_function 0.0068 0.033 0.10 1 + +#Klein_function 0.0068 0.01 0.03 1 +#Klein_function 0.0068 0.012 0.035 1 +#Klein_function 0.0068 0.013 0.04 1 +#Klein_function 0.0068 0.017 0.05 1 +#Klein_function 0.0068 0.02 0.06 1 +#Klein_function 0.0068 0.023 0.07 1 +#Klein_function 0.0068 0.027 0.08 1 +#Klein_function 0.0068 0.033 0.10 1 + +#Tanglecube_function 0.0068 0.01 0.03 1 +#Tanglecube_function 0.0068 0.012 0.035 1 +#Tanglecube_function 0.0068 0.013 0.04 1 +#Tanglecube_function 0.0068 0.017 0.05 1 +#Tanglecube_function 0.0068 0.02 0.06 1 +#Tanglecube_function 0.0068 0.023 0.07 1 +#Tanglecube_function 0.0068 0.027 0.08 1 +#Tanglecube_function 0.0068 0.033 0.10 1 + +#Sphere_function 0.0068 0.003 0.01 1 +#Sphere_function 0.0068 0.006 0.02 1 +#Sphere_function 0.0068 0.01 0.03 1 +#Sphere_function 0.0068 0.012 0.035 1 +#Sphere_function 0.0068 0.013 0.04 1 +#Sphere_function 0.0068 0.017 0.05 1 +#Sphere_function 0.0068 0.02 0.06 1 +#Sphere_function 0.0068 0.023 0.07 1 +#Sphere_function 0.0068 0.027 0.08 1 +#Sphere_function 0.0068 0.033 0.10 1 + +#D:/INRIA/Data/_Models/3D_images/liver_kidney_gallbladder.inr 0.5 5 5 1 +#D:/INRIA/Data/_Models/3D_images/liver_kidney_gallbladder.inr 0.5 2 2 1 +#D:/INRIA/Data/_Models/3D_images/liver_kidney_gallbladder.inr 0.5 1.5 1.5 1 +#D:/INRIA/Data/_Models/3D_images/liver_kidney_gallbladder.inr 0.5 1 1 1 +#D:/INRIA/Data/_Models/3D_images/liver_kidney_gallbladder.inr 0.5 0.8 0.8 1 +#D:/INRIA/Data/_Models/3D_images/liver_kidney_gallbladder.inr 0.5 0.65 0.65 1 + +#D:/INRIA/Data/_Models/3D_images/VisibleHuman1mm.inr 0.3 1.5 1.5 1 +#D:/INRIA/Data/_Models/3D_images/VisibleHuman1mm.inr 0.3 1 1 1 +#D:/INRIA/Data/_Models/3D_images/VisibleHuman1mm.inr 0.3 0.8 0.8 1 +#D:/INRIA/Data/_Models/3D_images/VisibleHuman1mm.inr 0.3 0.65 0.65 1 +#D:/INRIA/Data/_Models/3D_images/VisibleHuman1mm.inr 0.3 0.40 0.40 1 +#D:/INRIA/Data/_Models/3D_images/VisibleHuman1mm.inr 0.3 0.30 0.30 1 + + +########### Bug maya ########## +#Klein_function 0.0068 0.2 0.5 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.5 0.5 1 + +####### Divers ####### +#Klein_function 0.0068 1.1 1.1 10 +#Klein_function 0.0068 0.4 0.8 1 +#Klein_function 0.0068 0.04 0.1 1 +#Klein_function 0.0068 0.01 0.03 1 +#Klein_function 0.0068 0.01 0.03 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.2 0.002 1000 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.007 0.007 150 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.02 0.02 15 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.2 0.2 2 +#Tanglecube_function 0.0068 0.01 0.03 1000 + +####### Crash compact cell: SOLVED! ######## +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.005 0.005 100000 + +####### Test crash "A facet is not in conflict with its refinement point!" - SOLVED ######## +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.002 10 100000 + +####### Parallel optimizers ######## +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.005 0.005 1000 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.002 0.003 100 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0010 0.068 0.068 10000 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0020 0.068 0.068 10000 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/elephant.off 0.0068 0.068 0.068 10000 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/fandisk.off 0.0068 0.006 0.006 10 +#D:/INRIA/Data/_Models/BigOFF/lucy-100kt.off 0.0068 0.003 0.003 10 +#D:/INRIA/Data/_Models/BigOFF/bimba_400kf.off 0.0068 0.005 0.006 10 +#Klein_function 0.0068 0.02 0.06 10 +#Tanglecube_function 0.0068 0.01 0.05 10 +#Sphere_function 0.0068 0.006 0.02 10 +#Thin_cylinder_function 0.0068 0.002 0.004 10 +#Pancake_function 0.0068 0.02 0.02 10 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/cheese.off 0.0068 0.002 0.002 10 +#Klein_function 0.068 0.04 0.15 1 +#D:/INRIA/CGAL/workingcopy/Mesh_3/examples/Mesh_3/data/cheese.off 0.0001 0.004 0.0086 100 +#D:/INRIA/Data/_Models/CAD/pump_carter.off 0.0061 0.061 0.061 10 diff --git a/Mesh_3/benchmark/Mesh_3/concurrent_mesher_config.cfg b/Mesh_3/benchmark/Mesh_3/concurrent_mesher_config.cfg new file mode 100644 index 00000000000..2ac949502da --- /dev/null +++ b/Mesh_3/benchmark/Mesh_3/concurrent_mesher_config.cfg @@ -0,0 +1,27 @@ +#========================================== +#======== Worksharing strategy =========== +#========================================== + +locking_grid_num_cells_per_axis = 50 +first_grid_lock_radius = 0 + + +#========================================== +#============= Brute-force ================ +#========================================== + +#locking_grid_num_cells_per_axis = 30 +#first_grid_lock_radius = 2 + + +#========================================== +#=============== Other ==================== +#========================================== + +refinement_grainsize = 10 # for parallel_for techniques +refinement_batch_size = 10000 # for parallel_for technique +work_stats_grid_num_cells_per_axis = 5 # for "task" technique +num_work_items_per_batch = 50 # for "task" technique +min_num_vertices_of_coarse_mesh = 100 +num_vertices_of_coarse_mesh_per_core = 3.5 +num_pseudo_infinite_vertices_per_core = 5.0 \ No newline at end of file diff --git a/Mesh_3/demo/Mesh_3/C3t3_rib_exporter_plugin.cpp b/Mesh_3/demo/Mesh_3/C3t3_rib_exporter_plugin.cpp index b5643e5fd89..35bbc7147b3 100644 --- a/Mesh_3/demo/Mesh_3/C3t3_rib_exporter_plugin.cpp +++ b/Mesh_3/demo/Mesh_3/C3t3_rib_exporter_plugin.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include #if defined(BOOST_MSVC) # pragma warning( disable : 4503) @@ -102,10 +104,14 @@ private: void write_facets(const C3t3& c3t3, std::ofstream& out); void write_facets(const C3t3& c3t3, const Plane& plane, std::ofstream& out); - void write_cells(const C3t3& c3t3, const Plane& plane, std::ofstream& out); + void write_surface_cells(const C3t3& c3t3, const Plane& plane, std::ofstream& out); + void write_cells_intersecting_a_plane(const C3t3& c3t3, const Plane& plane, std::ofstream& out); + void write_cells_on_the_positive_side_of_a_plane(const C3t3& c3t3, const Plane& plane, std::ofstream& out); void write_triangle(const Point_3& p, const Point_3& q, const Point_3& r, const QColor& color, const QColor& edge_color, std::ofstream& out); + void write_tetrahedron (const Point_3& p, const Point_3& q, const Point_3& r, const Point_3& s, + const QColor& color, const QColor& edge_color, std::ofstream& out); void write_point(const Point_3& p, std::ofstream& out); void write_point_sphere(const Point_3& p, std::ofstream& out); @@ -211,8 +217,9 @@ C3t3_rib_exporter_plugin::create_rib() } // Init data - if ( c3t3_item != prev_c3t3_ ) - { + //if ( c3t3_item != prev_c3t3_ ) // Commented because it was causing problems + // when changing the color of the c3t3 + { init_maps(c3t3_item->c3t3(), c3t3_item->color()); init_point_radius(c3t3_item->c3t3()); init_parameters(); @@ -383,12 +390,14 @@ save(const Scene_c3t3_item& c3t3_item, const QFileInfo& fileInfo) write_facets(c3t3_item.c3t3(), c3t3_item.plane(), rib_file); rib_file << "Surface \"plastic\" \"Ka\" 0.65 \"Kd\" 0.65 \"Ks\" 0.35 \"roughness\" 0.2" << std::endl; - write_cells(c3t3_item.c3t3(), c3t3_item.plane(), rib_file); + //write_cells_intersecting_a_plane(c3t3_item.c3t3(), c3t3_item.plane(), rib_file); + write_cells_on_the_positive_side_of_a_plane(c3t3_item.c3t3(), c3t3_item.plane(), rib_file); break; case MESH: rib_file << "Surface \"plastic\" \"Ka\" 0.65 \"Kd\" 0.85 \"Ks\" 0.25 \"roughness\" 0.1" << std::endl; - write_facets(c3t3_item.c3t3(), rib_file); + //write_facets(c3t3_item.c3t3(), rib_file); + write_surface_cells(c3t3_item.c3t3(), c3t3_item.plane(), rib_file); break; case TRIANGULATION: @@ -436,7 +445,7 @@ C3t3_rib_exporter_plugin::init_maps(const C3t3& c3t3, const QColor& color) } // Fill value of maps - int nb_colors = static_cast(subdomain_map_.size()); // + surface_map_.size(); + size_t nb_colors = subdomain_map_.size(); // + surface_map_.size(); // Starting hue double c = color.hueF(); @@ -701,10 +710,137 @@ write_facets(const C3t3& c3t3, const Plane& plane, std::ofstream& out) } } +void +C3t3_rib_exporter_plugin:: +write_surface_cells(const C3t3& c3t3, const Plane& plane, std::ofstream& out) +{ + typedef Kernel::Oriented_side Side; + + for ( C3t3::Cells_in_complex_iterator it_cell = c3t3.cells_in_complex_begin(), + end = c3t3.cells_in_complex_end() ; it_cell != end ; ++it_cell ) + { + C3t3::Cell_handle c = it_cell; + + // Compute the number of surface vertices in c + // Keep one of them in memory + int num_2D_vertices = 0; + int last_2D_vertex_index = -1; + for (int i = 0 ; i < 4 ; ++i) + { + if (c3t3.in_dimension(c->vertex(i)) == 2) + { + ++num_2D_vertices; + last_2D_vertex_index = i; + } + } + + //const int TRANSPARENCY_ALPHA_VALUE = 100; + CGAL::Bbox_3 bbox = c3t3.bbox(); + float relPos = (c->weighted_circumcenter().x() - bbox.xmin()) + / (bbox.xmax() - bbox.xmin()); + float TRANSPARENCY_ALPHA_VALUE = + 1.f - + (relPos < 0.25f ? + 0.0f : + (relPos > 0.75f ? + 1.0f : + (relPos - 0.25f)*1.0f/0.5f + ) + ); + + + /* + // ONLY SURFACE FACETS ARE TRANSPARENT + if (num_2D_vertices >= 3) + { + QColor basecolor = subdomain_map_[c3t3.subdomain_index(c)]; + QColor facecolor = basecolor.darker(150); + QColor edgecolor = facecolor.darker(150); + + for (int i = 0 ; i < 4 ; ++i) + { + if (c3t3.in_dimension(c->vertex((i+1)%4)) == 2 + && c3t3.in_dimension(c->vertex((i+2)%4)) == 2 + && c3t3.in_dimension(c->vertex((i+3)%4)) == 2) + { + edgecolor.setAlpha(TRANSPARENCY_ALPHA_VALUE); + } + else + { + edgecolor.setAlpha(255); + } + + write_triangle(c->vertex((i+1)%4)->point(), + c->vertex((i+2)%4)->point(), + c->vertex((i+3)%4)->point(), + facecolor, edgecolor, out ); + } + }*/ + + + // SURFACE CELLS ARE TRANSPARENT + if (num_2D_vertices >= 2) + { + QColor basecolor = subdomain_map_[c3t3.subdomain_index(c)]; + QColor facecolor = basecolor.darker(150); + QColor edgecolor = facecolor.darker(150); + + /* + // Transparency on the negative side of the plane + const Side s0 = plane.oriented_side(c->vertex(0)->point()); + const Side s1 = plane.oriented_side(c->vertex(1)->point()); + const Side s2 = plane.oriented_side(c->vertex(2)->point()); + const Side s3 = plane.oriented_side(c->vertex(3)->point()); + if( s0 == CGAL::ON_NEGATIVE_SIDE && s1 == CGAL::ON_NEGATIVE_SIDE + && s2 == CGAL::ON_NEGATIVE_SIDE && s3 == CGAL::ON_NEGATIVE_SIDE ) + { + edgecolor.setAlpha(TRANSPARENCY_ALPHA_VALUE); + } + else + { + edgecolor.setAlpha(255); + }*/ + + edgecolor.setAlphaF(TRANSPARENCY_ALPHA_VALUE); + + for (int i = 0 ; i < 4 ; ++i) + { + write_triangle(c->vertex((i+1)%4)->point(), + c->vertex((i+2)%4)->point(), + c->vertex((i+3)%4)->point(), + facecolor, edgecolor, out ); + } + } + else if (num_2D_vertices == 1) + { + QColor basecolor = subdomain_map_[c3t3.subdomain_index(c)]; + QColor facecolor = basecolor.darker(150); + QColor edgecolor = facecolor.darker(150); + + for (int i = 0 ; i < 4 ; ++i) + { + if (i == last_2D_vertex_index) + { + edgecolor.setAlpha(TRANSPARENCY_ALPHA_VALUE); + } + else + { + edgecolor.setAlphaF(TRANSPARENCY_ALPHA_VALUE); + } + + write_triangle(c->vertex((i+1)%4)->point(), + c->vertex((i+2)%4)->point(), + c->vertex((i+3)%4)->point(), + facecolor, edgecolor, out ); + } + } + } +} + void C3t3_rib_exporter_plugin:: -write_cells(const C3t3& c3t3, const Plane& plane, std::ofstream& out) +write_cells_intersecting_a_plane(const C3t3& c3t3, const Plane& plane, std::ofstream& out) { typedef Kernel::Oriented_side Side; @@ -728,6 +864,58 @@ write_cells(const C3t3& c3t3, const Plane& plane, std::ofstream& out) QColor basecolor = subdomain_map_[c3t3.subdomain_index(it)]; QColor facecolor = basecolor.darker(150); QColor edgecolor = facecolor.darker(150); + + edgecolor.setAlpha(20); + + // Don't write facet twice + if ( s1 != CGAL::ON_NEGATIVE_SIDE || s2 != CGAL::ON_NEGATIVE_SIDE || s3 != CGAL::ON_NEGATIVE_SIDE ) + write_triangle(p1, p2, p3, facecolor, edgecolor, out ); + + if ( s1 != CGAL::ON_NEGATIVE_SIDE || s2 != CGAL::ON_NEGATIVE_SIDE || s4 != CGAL::ON_NEGATIVE_SIDE ) + write_triangle(p1, p2, p4, facecolor, edgecolor, out ); + + if ( s1 != CGAL::ON_NEGATIVE_SIDE || s3 != CGAL::ON_NEGATIVE_SIDE || s4 != CGAL::ON_NEGATIVE_SIDE ) + write_triangle(p1, p3, p4, facecolor, edgecolor, out ); + + if ( s2 != CGAL::ON_NEGATIVE_SIDE || s3 != CGAL::ON_NEGATIVE_SIDE || s4 != CGAL::ON_NEGATIVE_SIDE ) + write_triangle(p2, p3, p4, facecolor, edgecolor, out ); + } + } +} + +void +C3t3_rib_exporter_plugin:: +write_cells_on_the_positive_side_of_a_plane(const C3t3& c3t3, const Plane& plane, std::ofstream& out) +{ + typedef Kernel::Oriented_side Side; + + for ( C3t3::Cells_in_complex_iterator it = c3t3.cells_in_complex_begin(), + end = c3t3.cells_in_complex_end() ; it != end ; ++it ) + { + const Point_3& p1 = it->vertex(0)->point(); + const Point_3& p2 = it->vertex(1)->point(); + const Point_3& p3 = it->vertex(2)->point(); + const Point_3& p4 = it->vertex(3)->point(); + + const Side s1 = plane.oriented_side(p1); + const Side s2 = plane.oriented_side(p2); + const Side s3 = plane.oriented_side(p3); + const Side s4 = plane.oriented_side(p4); + + if( ( s1 == CGAL::ON_POSITIVE_SIDE || s2 == CGAL::ON_POSITIVE_SIDE + || s3 == CGAL::ON_POSITIVE_SIDE || s4 == CGAL::ON_POSITIVE_SIDE ) + /*&& + ( c3t3.surface_patch_index(it, 0) != C3t3::Surface_patch_index() + || c3t3.surface_patch_index(it, 1) != C3t3::Surface_patch_index() + || c3t3.surface_patch_index(it, 2) != C3t3::Surface_patch_index() + || c3t3.surface_patch_index(it, 3) != C3t3::Surface_patch_index() )*/ + ) + { + QColor basecolor = subdomain_map_[c3t3.subdomain_index(it)]; + QColor facecolor = basecolor.darker(150); + QColor edgecolor = facecolor.darker(150); + + edgecolor.setAlpha(10); // Don't write facet twice if ( s1 != CGAL::ON_NEGATIVE_SIDE || s2 != CGAL::ON_NEGATIVE_SIDE || s3 != CGAL::ON_NEGATIVE_SIDE ) @@ -772,6 +960,36 @@ write_triangle (const Point_3& p, const Point_3& q, const Point_3& r, add_vertex(r,edge_color); } +void +C3t3_rib_exporter_plugin:: +write_tetrahedron (const Point_3& p, const Point_3& q, const Point_3& r, const Point_3& s, + const QColor& color, const QColor& edge_color, std::ofstream& out) +{ + // Color + write_color(color, true, out); + + // Triangle + out << "Polygon \"P\" ["; + write_point(p,out); + write_point(q,out); + write_point(r,out); + write_point(s,out); + out << "]" << std::endl; + + // Edges (will be drawn later on) + add_edge(p,q,edge_color); + add_edge(p,r,edge_color); + add_edge(q,r,edge_color); + add_edge(s,p,edge_color); + add_edge(s,q,edge_color); + add_edge(s,r,edge_color); + + // Vertices (will be drawn later on) + add_vertex(p,edge_color); + add_vertex(q,edge_color); + add_vertex(r,edge_color); + add_vertex(s,edge_color); +} void C3t3_rib_exporter_plugin:: @@ -852,7 +1070,7 @@ write_edges_flat(std::ofstream& out) it != end ; ++it ) { // Color - write_color(it->second, false, out); + write_color(it->second, true, out); // Edge out << "Curves \"linear\" [2] \"nonperiodic\" \"P\" ["; @@ -874,7 +1092,7 @@ write_edges_volumic(std::ofstream& out) it != end ; ++it ) { // Color - write_color(it->second, false, out); + write_color(it->second, true, out); // Edge write_edge_cylinder(it->first.first, it->first.second, out); } diff --git a/Mesh_3/demo/Mesh_3/C3t3_type.h b/Mesh_3/demo/Mesh_3/C3t3_type.h index f17042b778f..ba952fb824b 100644 --- a/Mesh_3/demo/Mesh_3/C3t3_type.h +++ b/Mesh_3/demo/Mesh_3/C3t3_type.h @@ -12,6 +12,7 @@ #include #include #include +#include template struct Wrapper @@ -42,12 +43,18 @@ typedef CGAL::Polyhedral_mesh_domain_with_features_3 Image_mesh_domain; typedef Wrapper Function_wrapper; -typedef CGAL::Labeled_mesh_domain_3 Function_mesh_domain; +typedef CGAL::Labeled_mesh_domain_3 Function_mesh_domain; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; - -// 3D complex +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3::Kernel, + CGAL::Parallel_tag>::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; +// 3D complex + #endif // CGAL_DEMO_MESH_3_C3T3_TYPE_H diff --git a/Mesh_3/demo/Mesh_3/CMakeLists.txt b/Mesh_3/demo/Mesh_3/CMakeLists.txt index a378373d890..56ecbb80c40 100644 --- a/Mesh_3/demo/Mesh_3/CMakeLists.txt +++ b/Mesh_3/demo/Mesh_3/CMakeLists.txt @@ -9,6 +9,34 @@ else() cmake_policy(VERSION 2.6) endif() +# Creates a new CMake option, turned ON by default +option(ACTIVATE_MSVC_PRECOMPILED_HEADERS + "Activate precompiled headers in MSVC" + ON) + +# Macro to add precompiled headers for MSVC +# This function does two things: +# 1. Enable precompiled headers on each file which is listed in "SourcesVar". +# 2. Add the content of "PrecompiledSource" (e.g. "StdAfx.cpp") to "SourcesVar". +MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar) + IF(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS) + GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE) + SET(Sources ${${SourcesVar}}) + + SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource} + PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\"") + SET_SOURCE_FILES_PROPERTIES(${Sources} + PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeaders}\" /FI\"${PrecompiledHeader}\"") + # Add precompiled header to SourcesVar + LIST(APPEND ${SourcesVar} ${PrecompiledSource}) + ENDIF(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS) +ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER) +# The compiler might need more memory because of precompiled headers +if(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS AND NOT(MSVC_VERSION LESS 1310)) + set(CGAL_C_FLAGS "${CGAL_C_FLAGS} /Zm1000") + set(CGAL_CXX_FLAGS "${CGAL_CXX_FLAGS} /Zm1000") +endif() + # Let plugins be compiled in the same directory as the executable. set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") @@ -22,9 +50,37 @@ include_directories( BEFORE ./ ./include ../../include ) add_definitions(-DCGAL_MESH_3_NO_DEPRECATED_SURFACE_INDEX -DCGAL_MESH_3_NO_DEPRECATED_C3T3_ITERATORS) - # Add specific Find.cmake modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ) +set(CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules + ${CMAKE_CURRENT_SOURCE_DIR}/../../../Installation/cmake/modules/) + +# Activate concurrency ? (turned OFF by default) +option(ACTIVATE_CONCURRENT_MESH_3 + "Activate parallelism in Mesh_3" + OFF) + +# And add -DCGAL_CONCURRENT_MESH_3 if that option is ON +if( ACTIVATE_CONCURRENT_MESH_3 ) + add_definitions( -DCGAL_CONCURRENT_MESH_3 ) + find_package( TBB REQUIRED ) +else( ACTIVATE_CONCURRENT_MESH_3 ) + option( LINK_WITH_TBB + "Link with TBB anyway so we can use TBB timers for profiling" + ON) + if( LINK_WITH_TBB ) + find_package( TBB ) + endif( LINK_WITH_TBB ) +endif() + +if( TBB_FOUND ) + include(${TBB_USE_FILE}) +endif() + +# Creates a new CMake option, turned ON by default +option(ACTIVATE_MSVC_PRECOMPILED_HEADERS + "Activate precompiled headers in MSVC" + ON) # Find CGAL and CGAL Qt4 find_package(CGAL COMPONENTS Qt4 ImageIO) @@ -133,7 +189,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND AND Boost_F set(SCENE_SEGMENTED_IMAGE_ITEM_LIB "${MESH_3_LIB_PREFIX}scene_segmented_image_item") add_library(${SCENE_SEGMENTED_IMAGE_ITEM_LIB} SHARED Scene_segmented_image_item.cpp Scene_segmented_image_item.moc) - target_link_libraries(${SCENE_SEGMENTED_IMAGE_ITEM_LIB} ${SCENE_ITEM_LIB} ${CGAL_LIBRARIES}) + target_link_libraries(${SCENE_SEGMENTED_IMAGE_ITEM_LIB} ${SCENE_ITEM_LIB} ${CGAL_LIBRARIES} ${TBB_LIBRARIES}) set_target_properties(${SCENE_SEGMENTED_IMAGE_ITEM_LIB} PROPERTIES DEFINE_SYMBOL scene_segmented_image_item_EXPORTS) if(GLEW_FOUND) @@ -143,43 +199,49 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND AND Boost_F set(SCENE_POLYHEDRON_ITEM_LIB "${MESH_3_LIB_PREFIX}scene_polyhedron_item") add_library(${SCENE_POLYHEDRON_ITEM_LIB} SHARED Scene_polyhedron_item.cpp Scene_polyhedron_item.moc) - target_link_libraries(${SCENE_POLYHEDRON_ITEM_LIB} ${SCENE_ITEM_LIB} ${CGAL_LIBRARIES}) + target_link_libraries(${SCENE_POLYHEDRON_ITEM_LIB} ${SCENE_ITEM_LIB} ${CGAL_LIBRARIES} ${TBB_LIBRARIES}) set_target_properties(${SCENE_POLYHEDRON_ITEM_LIB} PROPERTIES DEFINE_SYMBOL scene_polyhedron_item_EXPORTS) set(POLYGON_SOUP_LIB "${MESH_3_LIB_PREFIX}polygon_soup") add_library(${POLYGON_SOUP_LIB} SHARED Scene_polygon_soup.cpp Scene_polygon_soup.moc) - target_link_libraries(${POLYGON_SOUP_LIB} ${SCENE_ITEM_LIB} ${CGAL_LIBRARIES}) + target_link_libraries(${POLYGON_SOUP_LIB} ${SCENE_ITEM_LIB} ${CGAL_LIBRARIES} ${TBB_LIBRARIES}) set_target_properties(${POLYGON_SOUP_LIB} PROPERTIES DEFINE_SYMBOL polygon_soup_EXPORTS) set(SCENE_C3T3_ITEM_LIB "${MESH_3_LIB_PREFIX}scene_c3t3_item") + set (SCENE_C3T3_ITEM_LIB_SOURCE_FILES Scene_c3t3_item.cpp) + ADD_MSVC_PRECOMPILED_HEADER("StdAfx.h" "StdAfx.cpp" SCENE_C3T3_ITEM_LIB_SOURCE_FILES) + LIST(APPEND SCENE_C3T3_ITEM_LIB_SOURCE_FILES Scene_c3t3_item.moc) add_library(${SCENE_C3T3_ITEM_LIB} SHARED - Scene_c3t3_item.cpp Scene_c3t3_item.moc) - target_link_libraries(${SCENE_C3T3_ITEM_LIB} ${SCENE_ITEM_LIB} ${QGLVIEWER_LIBRARIES} ${QT_LIBRARIES} ${CGAL_LIBRARIES} ${Boost_LIBRARIES}) + ${SCENE_C3T3_ITEM_LIB_SOURCE_FILES}) + target_link_libraries(${SCENE_C3T3_ITEM_LIB} ${SCENE_ITEM_LIB} ${QGLVIEWER_LIBRARIES} ${QT_LIBRARIES} ${CGAL_LIBRARIES} ${Boost_LIBRARIES} ${TBB_LIBRARIES}) set_target_properties(${SCENE_C3T3_ITEM_LIB} PROPERTIES DEFINE_SYMBOL scene_c3t3_item_EXPORTS) set(SCENE_IMPLICIT_FUNCTION_ITEM_LIB "${MESH_3_LIB_PREFIX}scene_implicit_function_item") add_library(${SCENE_IMPLICIT_FUNCTION_ITEM_LIB} SHARED Scene_implicit_function_item.cpp Scene_implicit_function_item.moc Color_ramp.cpp) - target_link_libraries(${SCENE_IMPLICIT_FUNCTION_ITEM_LIB} ${SCENE_ITEM_LIB} ${QGLVIEWER_LIBRARIES} ${QT_LIBRARIES}) + target_link_libraries(${SCENE_IMPLICIT_FUNCTION_ITEM_LIB} ${SCENE_ITEM_LIB} ${QGLVIEWER_LIBRARIES} ${QT_LIBRARIES} ${TBB_LIBRARIES}) set_target_properties(${SCENE_IMPLICIT_FUNCTION_ITEM_LIB} PROPERTIES DEFINE_SYMBOL scene_implicit_function_item_EXPORTS) - + add_definitions(-DUSE_FORWARD_DECL) add_definitions(-DQT_STATICPLUGIN) - add_executable ( Mesh_3 MainWindow.cpp + set (MESH_3_SOURCE_FILES + MainWindow.cpp Mesh_3.cpp ${DEMO_SRC_DIR}/Scene.cpp MainWindow_moc.cpp - Scene_moc.cpp - ${UI_FILES} ${RESOURCE_FILES} ) + Scene_moc.cpp) + #ADD_MSVC_PRECOMPILED_HEADER("StdAfx.h" "StdAfx.cpp" MESH_3_SOURCE_FILES) + LIST(APPEND MESH_3_SOURCE_FILES ${UI_FILES} ${RESOURCE_FILES}) + add_executable( Mesh_3 ${MESH_3_SOURCE_FILES} ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS Mesh_3 ) # Link with Qt libraries target_link_libraries( Mesh_3 ${QT_LIBRARIES} ) # Link with CGAL - target_link_libraries( Mesh_3 ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ) + target_link_libraries( Mesh_3 ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ${TBB_LIBRARIES}) # Link with libQGLViewer, OpenGL target_link_libraries( Mesh_3 ${QGLVIEWER_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ) @@ -217,7 +279,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND AND Boost_F # Link with scene_item target_link_libraries( ${plugin_name} ${SCENE_ITEM_LIB}) # Link with CGAL - target_link_libraries( ${plugin_name} ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ) + target_link_libraries( ${plugin_name} ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ${TBB_LIBRARIES}) endmacro(polyhedron_demo_plugin) set(IO_IMAGE_PLUGIN_LIB "${MESH_3_LIB_PREFIX}io_image_plugin") @@ -235,7 +297,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND AND Boost_F if(GLEW_FOUND) set(VOLUME_PLANES_PLUGIN_LIB "${MESH_3_LIB_PREFIX}volume_planes_plugin") polyhedron_demo_plugin(${VOLUME_PLANES_PLUGIN_LIB} Volume_planes_plugin - ${VOLUME_MOC_OUTFILES} + ${VOLUME_MOC_OUTFILES} Volume_plane_intersection.cpp) target_link_libraries(${VOLUME_PLANES_PLUGIN_LIB} ${SCENE_SEGMENTED_IMAGE_ITEM_LIB} ${VIEWER_LIB}) else() @@ -257,13 +319,25 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND AND Boost_F target_link_libraries(${IO_IMPLICIT_FUNCTION_PLUGIN_LIB} ${SCENE_IMPLICIT_FUNCTION_ITEM_LIB}) set(MESH_3_PLUGIN_LIB "${MESH_3_LIB_PREFIX}mesh_3_plugin") - polyhedron_demo_plugin(${MESH_3_PLUGIN_LIB} Mesh_3_plugin - Mesh_3_plugin_polyhedron_cgal_code.cpp - Mesh_3_plugin_image_cgal_code.cpp - Mesh_3_plugin_implicit_function_cgal_code.cpp - Meshing_thread.cpp - Scene_c3t3_item.moc - ${meshingUI_FILES}) + set(MESH_3_PLUGIN_SOURCE_FILES + Mesh_3_plugin.cpp + Mesh_3_plugin_polyhedron_cgal_code.cpp + Mesh_3_plugin_image_cgal_code.cpp + Mesh_3_plugin_implicit_function_cgal_code.cpp + Meshing_thread.cpp) + ADD_MSVC_PRECOMPILED_HEADER("StdAfx.h" "StdAfx.cpp" MESH_3_PLUGIN_SOURCE_FILES) + LIST(REMOVE_AT MESH_3_PLUGIN_SOURCE_FILES 0) # Remove Mesh_3_plugin.cpp since it's added by polyhedron_demo_plugin + LIST(APPEND MESH_3_PLUGIN_SOURCE_FILES "Scene_c3t3_item.moc" ${meshingUI_FILES}) + polyhedron_demo_plugin(${MESH_3_PLUGIN_LIB} Mesh_3_plugin ${MESH_3_PLUGIN_SOURCE_FILES}) + +# set(MESH_3_PLUGIN_LIB "${MESH_3_LIB_PREFIX}mesh_3_plugin") +# polyhedron_demo_plugin(${MESH_3_PLUGIN_LIB} Mesh_3_plugin +# Mesh_3_plugin_polyhedron_cgal_code.cpp +# Mesh_3_plugin_image_cgal_code.cpp +# Mesh_3_plugin_implicit_function_cgal_code.cpp +# Meshing_thread.cpp +# Scene_c3t3_item.moc +# ${meshingUI_FILES}) target_link_libraries(${MESH_3_PLUGIN_LIB} ${SCENE_C3T3_ITEM_LIB} @@ -272,14 +346,18 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND AND Boost_F ${SCENE_IMPLICIT_FUNCTION_ITEM_LIB} ${QGLVIEWER_LIBRARIES} ${OPENGL_gl_LIBRARY} - ${OPENGL_glu_LIBRARY}) + ${OPENGL_glu_LIBRARY} + ${TBB_LIBRARIES}) - set(MESH_3_OPTIMIZATION_PLUGIN_LIB "${MESH_3_LIB_PREFIX}mesh_3_optimization_plugin") - polyhedron_demo_plugin(${MESH_3_OPTIMIZATION_PLUGIN_LIB} Mesh_3_optimization_plugin - Mesh_3_optimization_plugin_cgal_code.cpp - Optimizer_thread.cpp - Scene_c3t3_item.moc - ${optimUI_FILES}) + set(MESH_3_OPTIMIZATION_PLUGIN_LIB "${MESH_3_LIB_PREFIX}mesh_3_optimization_plugin") + set(MESH_3_OPTIMIZATION_PLUGIN_SOURCE_FILES + Mesh_3_optimization_plugin.cpp + Mesh_3_optimization_plugin_cgal_code.cpp + Optimizer_thread.cpp) + ADD_MSVC_PRECOMPILED_HEADER("StdAfx.h" "StdAfx.cpp" MESH_3_OPTIMIZATION_PLUGIN_SOURCE_FILES) + LIST(REMOVE_AT MESH_3_OPTIMIZATION_PLUGIN_SOURCE_FILES 0) # Remove Mesh_3_optimization_plugin.cpp since it's added by polyhedron_demo_plugin + LIST(APPEND MESH_3_OPTIMIZATION_PLUGIN_SOURCE_FILES "Scene_c3t3_item.moc" ${optimUI_FILES}) + polyhedron_demo_plugin(${MESH_3_OPTIMIZATION_PLUGIN_LIB} Mesh_3_optimization_plugin ${MESH_3_OPTIMIZATION_PLUGIN_SOURCE_FILES}) target_link_libraries(${MESH_3_OPTIMIZATION_PLUGIN_LIB} ${SCENE_C3T3_ITEM_LIB} @@ -288,7 +366,8 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND AND Boost_F ${SCENE_IMPLICIT_FUNCTION_ITEM_LIB} ${QGLVIEWER_LIBRARIES} ${OPENGL_gl_LIBRARY} - ${OPENGL_glu_LIBRARY}) + ${OPENGL_glu_LIBRARY} + ${TBB_LIBRARIES}) else (CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND AND Boost_FOUND) diff --git a/Mesh_3/demo/Mesh_3/Color_ramp.cpp b/Mesh_3/demo/Mesh_3/Color_ramp.cpp index c8d74b8f0fd..89898cedce8 100644 --- a/Mesh_3/demo/Mesh_3/Color_ramp.cpp +++ b/Mesh_3/demo/Mesh_3/Color_ramp.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include "Color_ramp.h" #include diff --git a/Mesh_3/demo/Mesh_3/Io_c3t3_plugin.cpp b/Mesh_3/demo/Mesh_3/Io_c3t3_plugin.cpp index 3025ac10af1..9039a0b68f8 100644 --- a/Mesh_3/demo/Mesh_3/Io_c3t3_plugin.cpp +++ b/Mesh_3/demo/Mesh_3/Io_c3t3_plugin.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include "Scene_c3t3_item.h" #include @@ -17,14 +19,15 @@ public: virtual Scene_item* load(QFileInfo) { return NULL; } virtual bool canSave(const Scene_item*); - virtual bool save(const Scene_item*, QFileInfo fileinfo); + virtual bool save(const Scene_item*, QFileInfo, QString); }; QStringList Io_c3t3_plugin::nameFilters() const { - return QStringList() << "Mesh (*.mesh)"; + return QStringList() << "Mesh (*.mesh)" + << "Maya - surface only (*.ma)" << "Maya - cells (*.ma)"; } @@ -36,7 +39,7 @@ Io_c3t3_plugin::canSave(const Scene_item* item) } bool -Io_c3t3_plugin::save(const Scene_item* item, QFileInfo fileInfo) +Io_c3t3_plugin::save(const Scene_item* item, QFileInfo fileInfo, QString selectedFilter) { const Scene_c3t3_item* c3t3_item = qobject_cast(item); if ( NULL == c3t3_item ) @@ -45,8 +48,17 @@ Io_c3t3_plugin::save(const Scene_item* item, QFileInfo fileInfo) } QString path = fileInfo.absoluteFilePath(); - std::ofstream medit_file (qPrintable(path)); - c3t3_item->c3t3().output_to_medit(medit_file,true,true); + if (fileInfo.suffix() == "mesh") + { + std::ofstream medit_file (qPrintable(path)); + c3t3_item->c3t3().output_to_medit(medit_file,true,true); + } + else if (fileInfo.suffix() == "ma") + { + std::ofstream maya_file (qPrintable(path)); + c3t3_item->c3t3().output_to_maya( + maya_file, selectedFilter == "Maya - surface only (*.ma)"); + } return true; } diff --git a/Mesh_3/demo/Mesh_3/Io_image_plugin.cpp b/Mesh_3/demo/Mesh_3/Io_image_plugin.cpp index f8a78b5b613..13b1b7495bf 100644 --- a/Mesh_3/demo/Mesh_3/Io_image_plugin.cpp +++ b/Mesh_3/demo/Mesh_3/Io_image_plugin.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #ifdef SCENE_SEGMENTED_IMAGE_GL_BUFFERS_AVAILABLE # include #endif @@ -27,7 +29,7 @@ public: Scene_item* load(QFileInfo fileinfo); bool canSave(const Scene_item*); - bool save(const Scene_item*, QFileInfo) { return false; } + bool save(const Scene_item*, QFileInfo, QString) { return false; } }; QStringList Io_image_plugin::nameFilters() const { diff --git a/Mesh_3/demo/Mesh_3/Io_implicit_function_plugin.cpp b/Mesh_3/demo/Mesh_3/Io_implicit_function_plugin.cpp index fbcd9e371d7..57ebd40a9bd 100644 --- a/Mesh_3/demo/Mesh_3/Io_implicit_function_plugin.cpp +++ b/Mesh_3/demo/Mesh_3/Io_implicit_function_plugin.cpp @@ -21,6 +21,7 @@ //****************************************************************************** // File Description : //****************************************************************************** +#include "config.h" #include #include diff --git a/Mesh_3/demo/Mesh_3/Io_off_plugin.cpp b/Mesh_3/demo/Mesh_3/Io_off_plugin.cpp index 87aa44f1659..135c193db44 100644 --- a/Mesh_3/demo/Mesh_3/Io_off_plugin.cpp +++ b/Mesh_3/demo/Mesh_3/Io_off_plugin.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include "Scene_polyhedron_item.h" #include "Scene_polygon_soup.h" #include "Polyhedron_type.h" @@ -18,7 +20,7 @@ public: Scene_item* load(QFileInfo fileinfo); bool canSave(const Scene_item*); - bool save(const Scene_item*, QFileInfo fileinfo); + bool save(const Scene_item*, QFileInfo, QString); }; QStringList Io_off_plugin::nameFilters() const { @@ -69,7 +71,7 @@ bool Io_off_plugin::canSave(const Scene_item* item) qobject_cast(item); } -bool Io_off_plugin::save(const Scene_item* item, QFileInfo fileinfo) +bool Io_off_plugin::save(const Scene_item* item, QFileInfo fileinfo, QString selectedFilter) { // This plugin supports polyhedrons and polygon soups const Scene_polyhedron_item* poly_item = diff --git a/Mesh_3/demo/Mesh_3/MainWindow.cpp b/Mesh_3/demo/Mesh_3/MainWindow.cpp index 4454f247871..c2770ce15da 100644 --- a/Mesh_3/demo/Mesh_3/MainWindow.cpp +++ b/Mesh_3/demo/Mesh_3/MainWindow.cpp @@ -146,6 +146,26 @@ MainWindow::MainWindow(QWidget* parent) readSettings(); // Among other things, the column widths are stored. + const char *windowTitle = "CGAL 3D mesh generator demo [" +#ifdef CGAL_CONCURRENT_MESH_3 + "Parallel" +#else + "Sequential" +# ifdef CGAL_LINKED_WITH_TBB + " - With TBB" +# else + " - Without TBB" +# endif +#endif +#ifdef _DEBUG + " - Debug]"; +#else + "]"; +#endif + + setWindowTitle(QApplication::translate( + "MainWindow", windowTitle, 0, QApplication::UnicodeUTF8)); + this->dumpObjectTree(); } @@ -482,11 +502,13 @@ void MainWindow::on_actionSaveAs_triggered() return; } + QString selectedFilter; QString filename = QFileDialog::getSaveFileName(this, tr("Save to File..."), QString(), - filters.join(";;")); + filters.join(";;"), + &selectedFilter); QFileInfo fileinfo(filename); if(!fileinfo.isFile() || @@ -499,7 +521,7 @@ void MainWindow::on_actionSaveAs_triggered() { Q_FOREACH(Io_plugin_interface* plugin, canSavePlugins) { - if(plugin->save(item, fileinfo)) + if(plugin->save(item, fileinfo, selectedFilter)) break; } } diff --git a/Mesh_3/demo/Mesh_3/Mesh_3.cpp b/Mesh_3/demo/Mesh_3/Mesh_3.cpp index 89590e43ac0..a8369b91fc8 100644 --- a/Mesh_3/demo/Mesh_3/Mesh_3.cpp +++ b/Mesh_3/demo/Mesh_3/Mesh_3.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include "MainWindow.h" #include #include diff --git a/Mesh_3/demo/Mesh_3/Mesh_3_optimization_plugin.cpp b/Mesh_3/demo/Mesh_3/Mesh_3_optimization_plugin.cpp index 2ed1a48e647..98f0442f06a 100644 --- a/Mesh_3/demo/Mesh_3/Mesh_3_optimization_plugin.cpp +++ b/Mesh_3/demo/Mesh_3/Mesh_3_optimization_plugin.cpp @@ -34,29 +34,37 @@ // declare the CGAL function +#ifndef CGAL_MESH_3_DEMO_DISABLE_ODT Optimizer_thread* cgal_code_odt_mesh_3(Scene_c3t3_item& c3t3_item, const double time_limit, const double convergence_ratio, const double freeze_ratio, const int max_iteration_number, const bool create_new_item); +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_LLOYD Optimizer_thread* cgal_code_lloyd_mesh_3(Scene_c3t3_item& c3t3_item, const double time_limit, const double convergence_ratio, const double freeze_ratio, const int max_iteration_number, const bool create_new_item); +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_PERTURBER Optimizer_thread* cgal_code_perturb_mesh_3(Scene_c3t3_item& c3t3_item, const double time_limit, const double sliver_bound, const bool create_new_item); +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_EXUDER Optimizer_thread* cgal_code_exude_mesh_3(Scene_c3t3_item& c3t3_item, const double time_limit, const double sliver_bound, const bool create_new_item); +#endif QString translate(CGAL::Mesh_optimization_return_code rc); @@ -77,10 +85,18 @@ public: inline virtual QList actions() const; public slots: +#ifndef CGAL_MESH_3_DEMO_DISABLE_ODT void odt(); +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_LLOYD void lloyd(); +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_PERTURBER void perturb(); +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_EXUDER void exude(); +#endif void optimization_done(Optimizer_thread* t); void status_report(QString s); @@ -127,29 +143,37 @@ init(QMainWindow* mainWindow, this->mw = mainWindow; // Create menu items +#ifndef CGAL_MESH_3_DEMO_DISABLE_ODT actionOdt = this->getActionFromMainWindow(mw, "actionOdt"); if( NULL != actionOdt ) { connect(actionOdt, SIGNAL(triggered()), this, SLOT(odt())); } +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_LLOYD actionLloyd = this->getActionFromMainWindow(mw, "actionLloyd"); if( NULL != actionLloyd ) { connect(actionLloyd, SIGNAL(triggered()), this, SLOT(lloyd())); } +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_PERTURBER actionPerturb = this->getActionFromMainWindow(mw, "actionPerturb"); if( NULL != actionPerturb ) { connect(actionPerturb, SIGNAL(triggered()), this, SLOT(perturb())); } +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_EXUDER actionExude = this->getActionFromMainWindow(mw, "actionExude"); if( NULL != actionExude ) { connect(actionExude, SIGNAL(triggered()), this, SLOT(exude())); } +#endif msg = msg_interface; } @@ -164,6 +188,7 @@ Mesh_3_optimization_plugin::actions() const } +#ifndef CGAL_MESH_3_DEMO_DISABLE_ODT void Mesh_3_optimization_plugin::odt() { @@ -228,8 +253,10 @@ Mesh_3_optimization_plugin::odt() launch_thread(opt_thread, "Odt iterations are running..."); QApplication::restoreOverrideCursor(); } +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_LLOYD void Mesh_3_optimization_plugin::lloyd() { @@ -294,8 +321,10 @@ Mesh_3_optimization_plugin::lloyd() launch_thread(opt_thread, "Lloyd iterations are running..."); QApplication::restoreOverrideCursor(); } +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_PERTURBER void Mesh_3_optimization_plugin::perturb() { @@ -356,8 +385,10 @@ Mesh_3_optimization_plugin::perturb() launch_thread(opt_thread, "Sliver perturbation is running..."); QApplication::restoreOverrideCursor(); } +#endif +#ifndef CGAL_MESH_3_DEMO_DISABLE_EXUDER void Mesh_3_optimization_plugin::exude() { @@ -418,6 +449,7 @@ Mesh_3_optimization_plugin::exude() launch_thread(opt_thread, "Sliver exudation is running..."); QApplication::restoreOverrideCursor(); } +#endif Scene_c3t3_item* diff --git a/Mesh_3/demo/Mesh_3/Mesh_3_optimization_plugin_cgal_code.cpp b/Mesh_3/demo/Mesh_3/Mesh_3_optimization_plugin_cgal_code.cpp index 60d088e7e98..16260496cbd 100644 --- a/Mesh_3/demo/Mesh_3/Mesh_3_optimization_plugin_cgal_code.cpp +++ b/Mesh_3/demo/Mesh_3/Mesh_3_optimization_plugin_cgal_code.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include "C3t3_type.h" #include "Scene_c3t3_item.h" #include "Scene_polyhedron_item.h" @@ -88,7 +90,8 @@ Optimizer_thread* cgal_code_optimization(Scene_c3t3_item& c3t3_item, // Create domain using real type of c3t3_item.data_item() // ------------------ - + +#ifdef CGAL_MESH_3_DEMO_ACTIVATE_SEGMENTED_IMAGES // Image const Scene_segmented_image_item* image_item = qobject_cast(c3t3_item.data_item()); @@ -110,7 +113,7 @@ Optimizer_thread* cgal_code_optimization(Scene_c3t3_item& c3t3_item, return new Optimizer_thread(p_opt_function, p_result_item); } - +#endif // Polyhedron const Scene_polyhedron_item* poly_item = @@ -134,6 +137,7 @@ Optimizer_thread* cgal_code_optimization(Scene_c3t3_item& c3t3_item, return new Optimizer_thread(p_opt_function, p_result_item); } +#ifdef CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS // Function const Scene_implicit_function_item* function_item = qobject_cast(c3t3_item.data_item()); @@ -160,6 +164,7 @@ Optimizer_thread* cgal_code_optimization(Scene_c3t3_item& c3t3_item, return new Optimizer_thread(p_opt_function, p_result_item); } +#endif return NULL; } @@ -252,6 +257,9 @@ protected: // ----------------------------------- // Odt // ----------------------------------- + +#ifndef CGAL_MESH_3_DEMO_DISABLE_ODT + struct Odt_parameters { double time_limit; @@ -356,12 +364,16 @@ cgal_code_odt_mesh_3(Scene_c3t3_item& c3t3_item, return cgal_code_optimization(c3t3_item, p, create_new_item); } +#endif // ----------------------------------- // Lloyd // ----------------------------------- + +#ifndef CGAL_MESH_3_DEMO_DISABLE_LLOYD + struct Lloyd_parameters { double time_limit; @@ -466,12 +478,16 @@ cgal_code_lloyd_mesh_3(Scene_c3t3_item& c3t3_item, return cgal_code_optimization(c3t3_item, p, create_new_item); } +#endif // ----------------------------------- // Perturbation // ----------------------------------- + +#ifndef CGAL_MESH_3_DEMO_DISABLE_PERTURBER + struct Perturb_parameters { double time_limit; @@ -606,11 +622,14 @@ cgal_code_perturb_mesh_3(Scene_c3t3_item& c3t3_item, return cgal_code_optimization(c3t3_item, p, create_new_item); } - +#endif // ----------------------------------- // Exudation // ----------------------------------- + +#ifndef CGAL_MESH_3_DEMO_DISABLE_EXUDER + struct Exude_parameters { double time_limit; @@ -658,7 +677,8 @@ class Optimization_function < Domain, Exude_parameters > typedef C3t3::Triangulation Tr; typedef CGAL::Mesh_3::Min_dihedral_angle_criterion Sc; typedef Exude_visitor Visitor; - typedef CGAL::Mesh_3::Slivers_exuder Exuder; + typedef CGAL::Mesh_3::Slivers_exuder< + C3t3,Domain,Sc,Visitor> Exuder; typedef Optimization_function_base< Domain > Base; @@ -691,12 +711,12 @@ protected: /// Launch sliver exudation /// The content of this method is taken from CGAL::exude_mesh_3() virtual CGAL::Mesh_optimization_return_code - operator()(C3t3& c3t3, const Domain&) + operator()(C3t3& c3t3, const Domain& domain) { if ( NULL != exude_ ) { return CGAL::MESH_OPTIMIZATION_UNKNOWN_ERROR; } // Create exuder - exude_ = new Exuder(c3t3,criterion_); + exude_ = new Exuder(c3t3, domain, criterion_); if ( NULL == exude_ ) { return CGAL::MESH_OPTIMIZATION_UNKNOWN_ERROR; } // Set time_limit @@ -743,3 +763,4 @@ cgal_code_exude_mesh_3(Scene_c3t3_item& c3t3_item, return new Optimizer_thread(p_opt_function, p_result_item); } +#endif \ No newline at end of file diff --git a/Mesh_3/demo/Mesh_3/Mesh_3_plugin.cpp b/Mesh_3/demo/Mesh_3/Mesh_3_plugin.cpp index 678467d84ad..82e394f53e1 100644 --- a/Mesh_3/demo/Mesh_3/Mesh_3_plugin.cpp +++ b/Mesh_3/demo/Mesh_3/Mesh_3_plugin.cpp @@ -46,19 +46,23 @@ Meshing_thread* cgal_code_mesh_3(const Polyhedron*, const double tet_shape, const bool protect_features); +#ifdef CGAL_MESH_3_DEMO_ACTIVATE_SEGMENTED_IMAGES Meshing_thread* cgal_code_mesh_3(const Image*, const double angle, const double sizing, const double approx, const double tets_sizing, const double tet_shape); +#endif +#ifdef CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS Meshing_thread* cgal_code_mesh_3(const Implicit_function_interface*, const double angle, const double sizing, const double approx, const double tets_sizing, const double tet_shape); +#endif double get_approximate(double d, int precision, int& decimals); @@ -244,7 +248,8 @@ void Mesh_3_plugin::mesh_3() tet_sizing, radius_edge, protect_features); } - // Image + // Image +#ifdef CGAL_MESH_3_DEMO_ACTIVATE_SEGMENTED_IMAGES else if( NULL != image_item ) { const Image* pImage = image_item->image(); @@ -258,7 +263,10 @@ void Mesh_3_plugin::mesh_3() angle, facet_sizing, approx, tet_sizing, radius_edge); } +#endif + // Function +#ifdef CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS else if( NULL != function_item ) { const Implicit_function_interface* pFunction = function_item->function(); @@ -273,6 +281,7 @@ void Mesh_3_plugin::mesh_3() tet_sizing, radius_edge); } +#endif if ( NULL == thread ) { @@ -349,10 +358,19 @@ meshing_done(Meshing_thread* thread) str.append(QString("( %1 )
      ").arg(param)); } + Scene_c3t3_item* result_item = thread->item(); + const Scene_item::Bbox& bbox = result_item->bbox(); + str.append(QString("BBox (x,y,z): [ %1, %2 ], [ %3, %4 ], [ %5, %6 ],
      ") + .arg(bbox.xmin) + .arg(bbox.xmax) + .arg(bbox.ymin) + .arg(bbox.ymax) + .arg(bbox.zmin) + .arg(bbox.zmax)); + msg->information(qPrintable(str)); // Treat new c3t3 item - Scene_c3t3_item* result_item = thread->item(); treat_result(*source_item_, *result_item); // close message box diff --git a/Mesh_3/demo/Mesh_3/Mesh_3_plugin_image_cgal_code.cpp b/Mesh_3/demo/Mesh_3/Mesh_3_plugin_image_cgal_code.cpp index 4bc3c492ed8..9a6b9d7b217 100644 --- a/Mesh_3/demo/Mesh_3/Mesh_3_plugin_image_cgal_code.cpp +++ b/Mesh_3/demo/Mesh_3/Mesh_3_plugin_image_cgal_code.cpp @@ -1,3 +1,7 @@ +#include "config.h" + +#ifdef CGAL_MESH_3_DEMO_ACTIVATE_SEGMENTED_IMAGES + #include "C3t3_type.h" #include "Scene_c3t3_item.h" #include "Image_type.h" @@ -33,3 +37,5 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage, Mesh_function* p_mesh_function = new Mesh_function(p_new_item->c3t3(), p_domain, param); return new Meshing_thread(p_mesh_function, p_new_item); } + +#endif diff --git a/Mesh_3/demo/Mesh_3/Mesh_3_plugin_implicit_function_cgal_code.cpp b/Mesh_3/demo/Mesh_3/Mesh_3_plugin_implicit_function_cgal_code.cpp index 4986820ddf5..34a094b599c 100644 --- a/Mesh_3/demo/Mesh_3/Mesh_3_plugin_implicit_function_cgal_code.cpp +++ b/Mesh_3/demo/Mesh_3/Mesh_3_plugin_implicit_function_cgal_code.cpp @@ -1,3 +1,7 @@ +#include "config.h" + +#ifdef CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS + #include "C3t3_type.h" #include "Scene_c3t3_item.h" #include "implicit_functions/Implicit_function_interface.h" @@ -41,3 +45,5 @@ Meshing_thread* cgal_code_mesh_3(const Implicit_function_interface* pfunction, Mesh_function* p_mesh_function = new Mesh_function(p_new_item->c3t3(), p_domain, param); return new Meshing_thread(p_mesh_function, p_new_item); } + +#endif // CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS diff --git a/Mesh_3/demo/Mesh_3/Mesh_3_plugin_polyhedron_cgal_code.cpp b/Mesh_3/demo/Mesh_3/Mesh_3_plugin_polyhedron_cgal_code.cpp index d71787bcb91..5fe987a4180 100644 --- a/Mesh_3/demo/Mesh_3/Mesh_3_plugin_polyhedron_cgal_code.cpp +++ b/Mesh_3/demo/Mesh_3/Mesh_3_plugin_polyhedron_cgal_code.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include "C3t3_type.h" #include "Scene_c3t3_item.h" #include "Polyhedron_type.h" diff --git a/Mesh_3/demo/Mesh_3/Mesh_function.h b/Mesh_3/demo/Mesh_3/Mesh_function.h index 139513c3814..b39ee4892f8 100644 --- a/Mesh_3/demo/Mesh_3/Mesh_function.h +++ b/Mesh_3/demo/Mesh_3/Mesh_function.h @@ -25,7 +25,9 @@ #ifndef CGAL_DEMO_MESH_3_MESH_FUNCTION_H #define CGAL_DEMO_MESH_3_MESH_FUNCTION_H -#define CGAL_MESH_3_MESHER_STATUS_ACTIVATED 1 +//#define CGAL_MESH_3_MESHER_STATUS_ACTIVATED 1 + +#include #include #include @@ -38,7 +40,6 @@ #include "Meshing_thread.h" #include // for C3t3_initializer - struct Mesh_parameters { double facet_angle; @@ -112,7 +113,9 @@ private: Mesh_parameters p_; bool continue_; Mesher* mesher_; +#ifdef CGAL_MESH_3_MESHER_STATUS_ACTIVATED mutable typename Mesher::Mesher_status last_report_; +#endif }; @@ -146,8 +149,13 @@ Mesh_function(C3t3& c3t3, Domain* domain, const Mesh_parameters& p) , p_(p) , continue_(true) , mesher_(NULL) +#ifdef CGAL_MESH_3_MESHER_STATUS_ACTIVATED , last_report_(0,0,0) +#endif { +#ifdef CGAL_CONCURRENT_MESH_3 + Concurrent_mesher_config::load_config_file(CONFIG_FILENAME, false); +#endif } @@ -191,12 +199,22 @@ launch() // Build mesher and launch refinement process mesher_ = new Mesher(c3t3_, *domain_, criteria); - mesher_->initialize(); + mesher_->refine_mesh(); + /*mesher_->initialize(); +#ifdef CGAL_MESH_3_PROFILING + WallClockTimer t; +#endif + while ( ! mesher_->is_algorithm_done() && continue_ ) { mesher_->one_step(); } + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "Full refinement time (without fix_c3t3): " << t.elapsed() << " seconds." << std::endl; +#endif + */ // Ensure c3t3 is ok (usefull if process has been stop by the user) mesher_->fix_c3t3(); @@ -226,6 +244,9 @@ QString Mesh_function:: status(double time_period) const { + QString result; + +#ifdef CGAL_MESH_3_MESHER_STATUS_ACTIVATED // If mesher_ is not yet created, it means that either launch() has not // been called or that initial points have not been founded if ( NULL == mesher_ ) @@ -236,7 +257,7 @@ status(double time_period) const // Get status and return a string corresponding to it typename Mesher::Mesher_status s = mesher_->status(); - QString result = QString("Vertices: %1 \n" + result = QString("Vertices: %1 \n" "Vertices inserted last %2s: %3 \n\n" "Bad facets: %4 \n" "Bad cells: %5") @@ -247,7 +268,7 @@ status(double time_period) const .arg(s.cells_queue); last_report_ = s; - +#endif return result; } diff --git a/Mesh_3/demo/Mesh_3/Meshing_thread.cpp b/Mesh_3/demo/Mesh_3/Meshing_thread.cpp index 1f64b858935..e21b5a5222b 100644 --- a/Mesh_3/demo/Mesh_3/Meshing_thread.cpp +++ b/Mesh_3/demo/Mesh_3/Meshing_thread.cpp @@ -22,6 +22,7 @@ // File Description : //****************************************************************************** +#include "config.h" #include #include diff --git a/Mesh_3/demo/Mesh_3/Optimizer_thread.cpp b/Mesh_3/demo/Mesh_3/Optimizer_thread.cpp index 4bd03fdfa7b..01ac43a56d8 100644 --- a/Mesh_3/demo/Mesh_3/Optimizer_thread.cpp +++ b/Mesh_3/demo/Mesh_3/Optimizer_thread.cpp @@ -22,6 +22,8 @@ // File Description : //****************************************************************************** +#include "config.h" + #include #include #include "Optimizer_thread.h" diff --git a/Mesh_3/demo/Mesh_3/Scene_c3t3_item.cpp b/Mesh_3/demo/Mesh_3/Scene_c3t3_item.cpp index 5962341d5cf..98207c299b7 100644 --- a/Mesh_3/demo/Mesh_3/Scene_c3t3_item.cpp +++ b/Mesh_3/demo/Mesh_3/Scene_c3t3_item.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include "Scene_c3t3_item.h" #include @@ -219,6 +221,108 @@ Scene_c3t3_item::direct_draw(int mode) const { sb == ON_NEGATIVE_SIDE && sc == ON_NEGATIVE_SIDE) { +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + if(mode != DRAW_EDGES) + { + Tr::Facet mirror_facet = c3t3().triangulation().mirror_facet(*fit); + //int mirror_index = c3t3().triangulation().mirror_index(cell, index); + bool blueOrRed = false; + if(cell->mark == index || mirror_facet.first->mark == mirror_facet.second) + { + std::cerr << "================== BAD TRIANGLE =================" << std::endl; + blueOrRed = true; + + if(cell->mark2 != -1) + { + const Kernel::Point_3& pa2 = cell->vertex((cell->mark2+1)&3)->point(); + const Kernel::Point_3& pb2 = cell->vertex((cell->mark2+2)&3)->point(); + const Kernel::Point_3& pc2 = cell->vertex((cell->mark2+3)&3)->point(); + + CGALglcolor(QColor("blue")); + std::cerr << "================== BLUE =================" << std::endl; + draw_triangle(pa2, pb2, pc2); + + const Tr::Facet f_blue(cell, cell->mark2); + Tr::Facet mirror_f_blue = c3t3().triangulation().mirror_facet(f_blue); + const Kernel::Point_3& dual_edge_pa = c3t3().triangulation().dual(f_blue.first); + const Kernel::Point_3& dual_edge_pb = c3t3().triangulation().dual(mirror_f_blue.first); + const Kernel::Point_3& dual_edge_pc = dual_edge_pa + Kernel::Vector_3(0.001, 0., 0.); + CGALglcolor(QColor("yellow")); + draw_triangle(dual_edge_pa, dual_edge_pb, dual_edge_pc); + } + else if(mirror_facet.first->mark2 != -1) + { + const Kernel::Point_3& pa2 = mirror_facet.first->vertex((mirror_facet.first->mark2+1)&3)->point(); + const Kernel::Point_3& pb2 = mirror_facet.first->vertex((mirror_facet.first->mark2+2)&3)->point(); + const Kernel::Point_3& pc2 = mirror_facet.first->vertex((mirror_facet.first->mark2+3)&3)->point(); + + CGALglcolor(QColor("blue")); + std::cerr << "================== BLUE =================" << std::endl; + draw_triangle(pa2, pb2, pc2); + + const Tr::Facet f_blue(mirror_facet.first, mirror_facet.first->mark2); + Tr::Facet mirror_f_blue = c3t3().triangulation().mirror_facet(f_blue); + const Kernel::Point_3& dual_edge_pa = c3t3().triangulation().dual(f_blue.first); + const Kernel::Point_3& dual_edge_pb = c3t3().triangulation().dual(mirror_f_blue.first); + const Kernel::Point_3& dual_edge_pc = dual_edge_pa + Kernel::Vector_3(0.001, 0., 0.); + CGALglcolor(QColor("yellow")); + draw_triangle(dual_edge_pa, dual_edge_pb, dual_edge_pc); + } + + /* + //const Kernel::Point_3& dual_edge_pa = cell->circumcenter(); + //const Kernel::Point_3& dual_edge_pb = mirror_facet.first->circumcenter(); + const Kernel::Point_3& dual_edge_pa = c3t3().triangulation().dual(cell); + const Kernel::Point_3& dual_edge_pb = c3t3().triangulation().dual(mirror_facet.first); + const Kernel::Point_3& dual_edge_pc = dual_edge_pa + Kernel::Vector_3(0.001, 0., 0.); + CGALglcolor(QColor("yellow")); + draw_triangle(dual_edge_pa, dual_edge_pb, dual_edge_pc); + */ + } + else + { + if(cell->subdomain_index() == 0) { + CGALglcolor(d->colors[cell->neighbor(index)->subdomain_index()]); + } + else { + CGALglcolor(d->colors[cell->subdomain_index()]); + } + draw_triangle(pa, pb, pc); + } + } + + /*if(mode != DRAW_EDGES) { + + Tr::Facet mirror_facet = c3t3().triangulation().mirror_facet(*fit); + //int mirror_index = c3t3().triangulation().mirror_index(cell, index); + bool blueOrRed = false; + if(cell->mark == index || mirror_facet.first->mark == mirror_facet.second) { + //if (cell->mark != -1 || cell->neighbor(index)->mark != -1) { + CGALglcolor(QColor("red")); + std::cerr << "================== RED =================" << std::endl; + blueOrRed = true; + } + + if(cell->mark2 == index || mirror_facet.first->mark2 == mirror_facet.second) { + //if(cell->mark2 != -1 || mirror_facet.first->mark2 != -1) { + CGALglcolor(QColor("blue")); + std::cerr << "================== BLUE =================" << std::endl; + blueOrRed = true; + } + + if (!blueOrRed) + { + if(cell->subdomain_index() == 0) { + CGALglcolor(d->colors[cell->neighbor(index)->subdomain_index()]); + } + else { + CGALglcolor(d->colors[cell->subdomain_index()]); + } + } + } + draw_triangle(pa, pb, pc);*/ + +#else if(mode != DRAW_EDGES) { if(cell->subdomain_index() == 0) { CGALglcolor(d->colors[cell->neighbor(index)->subdomain_index()]); @@ -228,6 +332,7 @@ Scene_c3t3_item::direct_draw(int mode) const { } } draw_triangle(pa, pb, pc); +#endif } } ::glEnd(); @@ -299,6 +404,20 @@ Scene_c3t3_item::graphicalToolTip() const void Scene_c3t3_item::build_histogram() { +#ifdef CGAL_MESH_3_DEMO_BIGGER_HISTOGRAM_WITH_WHITE_BACKGROUNG + // Create an histogram_ and display it + const int height = 280; + const int top_margin = 5; + const int left_margin = 20; + const int drawing_height = height-top_margin*2; + const int width = 804; + const int cell_width = 4; + const int text_margin = 3; + const int text_height = 34; + + histogram_ = QPixmap(width,height+text_height); + histogram_.fill(QColor(255,255,255)); +#else // Create an histogram_ and display it const int height = 140; const int top_margin = 5; @@ -311,7 +430,8 @@ Scene_c3t3_item::build_histogram() histogram_ = QPixmap(width,height+text_height); histogram_.fill(QColor(192,192,192)); - +#endif + QPainter painter(&histogram_); painter.setPen(Qt::black); painter.setBrush(QColor(128,128,128)); @@ -389,6 +509,14 @@ create_histogram(const C3t3& c3t3, double& min_value, double& max_value) if( !c3t3.is_in_complex(cit)) continue; +#ifdef CGAL_MESH_3_DEMO_DONT_COUNT_TETS_ADJACENT_TO_SHARP_FEATURES_FOR_HISTOGRAM + if (c3t3.in_dimension(cit->vertex(0)) <= 1 + || c3t3.in_dimension(cit->vertex(1)) <= 1 + || c3t3.in_dimension(cit->vertex(2)) <= 1 + || c3t3.in_dimension(cit->vertex(3)) <= 1) + continue; +#endif //CGAL_MESH_3_DEMO_DONT_COUNT_TETS_ADJACENT_TO_SHARP_FEATURES_FOR_HISTOGRAM + const Point_3& p0 = cit->vertex(0)->point(); const Point_3& p1 = cit->vertex(1)->point(); const Point_3& p2 = cit->vertex(2)->point(); @@ -436,7 +564,7 @@ Scene_c3t3_item::get_histogram_color(const double v) const if ( v < 5 ) { return Qt::red; } else if ( v < 10 ) { return QColor(215,108,0); } else if ( v < 15 ) { return QColor(138,139,0); } - else if ( v < 165 ) { return Qt::darkGreen; } + else if ( v < 165 ) { return QColor(60,136,64); } else if ( v < 170 ) { return QColor(138,139,1); } else if ( v < 175 ) { return QColor(215,108,0); } else /* 175 #include diff --git a/Mesh_3/demo/Mesh_3/Scene_polygon_soup.cpp b/Mesh_3/demo/Mesh_3/Scene_polygon_soup.cpp index 2e60e048b74..5eb9defce07 100644 --- a/Mesh_3/demo/Mesh_3/Scene_polygon_soup.cpp +++ b/Mesh_3/demo/Mesh_3/Scene_polygon_soup.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include "Scene_polygon_soup.h" #include diff --git a/Mesh_3/demo/Mesh_3/Scene_polyhedron_item.cpp b/Mesh_3/demo/Mesh_3/Scene_polyhedron_item.cpp index ed05550979f..2ed00f46906 100644 --- a/Mesh_3/demo/Mesh_3/Scene_polyhedron_item.cpp +++ b/Mesh_3/demo/Mesh_3/Scene_polyhedron_item.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include "Scene_polyhedron_item.h" #include "Polyhedron_type.h" #include diff --git a/Mesh_3/demo/Mesh_3/Scene_segmented_image_item.cpp b/Mesh_3/demo/Mesh_3/Scene_segmented_image_item.cpp index 2be68c94036..5f8afd1173b 100644 --- a/Mesh_3/demo/Mesh_3/Scene_segmented_image_item.cpp +++ b/Mesh_3/demo/Mesh_3/Scene_segmented_image_item.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #ifdef SCENE_SEGMENTED_IMAGE_GL_BUFFERS_AVAILABLE # include #endif diff --git a/Mesh_3/demo/Mesh_3/StdAfx.cpp b/Mesh_3/demo/Mesh_3/StdAfx.cpp new file mode 100644 index 00000000000..15668dcadef --- /dev/null +++ b/Mesh_3/demo/Mesh_3/StdAfx.cpp @@ -0,0 +1,2 @@ +// Build the precompiled headers. +#include "StdAfx.h" \ No newline at end of file diff --git a/Mesh_3/demo/Mesh_3/StdAfx.h b/Mesh_3/demo/Mesh_3/StdAfx.h new file mode 100644 index 00000000000..490736e828e --- /dev/null +++ b/Mesh_3/demo/Mesh_3/StdAfx.h @@ -0,0 +1,346 @@ +#ifndef STDAFX_H +#define STDAFX_H + +#ifdef CGAL_CONCURRENT_MESH_3 + // In case some code uses CGAL_PROFILE, it needs to be concurrent + #define CGAL_CONCURRENT_PROFILE +#endif + +#include +#include +#include + +// STL +#include +#include +#include +#include +#include +#include +#include + +// Windows +#include + +// Boost +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Qt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// QGLViewer +#include +#include +#include +#include +#include +#include +#include + +// CGAL +//#include +//#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +//#include +#include +#include +//#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +//#include +//#include +//#include +//#include +//#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +#include +#include +#include + +// Mesh_3 +/*#include +#include +#include +#include +#include +#include +#include */ + +#endif //STDAFX_H \ No newline at end of file diff --git a/Mesh_3/demo/Mesh_3/Volume_plane_intersection.cpp b/Mesh_3/demo/Mesh_3/Volume_plane_intersection.cpp index 896031803ab..f691a7d38ee 100644 --- a/Mesh_3/demo/Mesh_3/Volume_plane_intersection.cpp +++ b/Mesh_3/demo/Mesh_3/Volume_plane_intersection.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include "Volume_plane_intersection.h" #include "Volume_plane_interface.h" diff --git a/Mesh_3/demo/Mesh_3/Volume_planes_plugin.cpp b/Mesh_3/demo/Mesh_3/Volume_planes_plugin.cpp index 8c9a72d589d..93e0a442727 100644 --- a/Mesh_3/demo/Mesh_3/Volume_planes_plugin.cpp +++ b/Mesh_3/demo/Mesh_3/Volume_planes_plugin.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include #include "Volume_plane.h" diff --git a/Mesh_3/demo/Mesh_3/concurrent_mesher_config.cfg b/Mesh_3/demo/Mesh_3/concurrent_mesher_config.cfg new file mode 100644 index 00000000000..2ac949502da --- /dev/null +++ b/Mesh_3/demo/Mesh_3/concurrent_mesher_config.cfg @@ -0,0 +1,27 @@ +#========================================== +#======== Worksharing strategy =========== +#========================================== + +locking_grid_num_cells_per_axis = 50 +first_grid_lock_radius = 0 + + +#========================================== +#============= Brute-force ================ +#========================================== + +#locking_grid_num_cells_per_axis = 30 +#first_grid_lock_radius = 2 + + +#========================================== +#=============== Other ==================== +#========================================== + +refinement_grainsize = 10 # for parallel_for techniques +refinement_batch_size = 10000 # for parallel_for technique +work_stats_grid_num_cells_per_axis = 5 # for "task" technique +num_work_items_per_batch = 50 # for "task" technique +min_num_vertices_of_coarse_mesh = 100 +num_vertices_of_coarse_mesh_per_core = 3.5 +num_pseudo_infinite_vertices_per_core = 5.0 \ No newline at end of file diff --git a/Mesh_3/demo/Mesh_3/config.h b/Mesh_3/demo/Mesh_3/config.h index b542ef8a0e5..32a3afee04d 100644 --- a/Mesh_3/demo/Mesh_3/config.h +++ b/Mesh_3/demo/Mesh_3/config.h @@ -1,9 +1,20 @@ +#ifndef CGAL_DEMO_MESH_3_CONFIG_H +#define CGAL_DEMO_MESH_3_CONFIG_H + +#define CGAL_PROFILE + // #define CGAL_POLYHEDRON_DEMO_NO_NEF // #define CGAL_POLYHEDRON_DEMO_NO_SURFACE_MESHER // #define CGAL_POLYHEDRON_DEMO_NO_PARAMETRIZATION -#ifndef CGAL_POLYHEDRON_DEMO_CONFIG_H -#define CGAL_POLYHEDRON_DEMO_CONFIG_H +//#define CGAL_MESH_3_VERBOSE +//#define CGAL_MESH_3_PERTURBER_HIGH_VERBOSITY +//#define CGAL_MESH_3_EXUDER_VERBOSE +//#define CGAL_MESH_3_EXUDER_HIGH_VERBOSITY +//#define CGAL_MESH_3_VERY_VERBOSE +#define CGAL_MESH_3_IO_VERBOSE + +//#define SHOW_REMAINING_BAD_ELEMENT_IN_RED #ifndef CGAL_POLYHEDRON_DEMO_NO_PARAMETRIZATION # define CGAL_POLYHEDRON_DEMO_USE_PARAMETRIZATION @@ -17,4 +28,94 @@ # define CGAL_POLYHEDRON_DEMO_USE_SURFACE_MESHER #endif -#endif // CGAL_POLYHEDRON_DEMO_CONFIG_H +#define CGAL_MESH_3_DEMO_BIGGER_HISTOGRAM_WITH_WHITE_BACKGROUNG + +// If you define this, implicit function and segmented images won't be available +//#define CGAL_MESH_3_DEMO_ACTIVATE_SHARP_FEATURES_IN_POLYHEDRAL_DOMAIN +#ifndef CGAL_MESH_3_DEMO_ACTIVATE_SHARP_FEATURES_IN_POLYHEDRAL_DOMAIN +# define CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS +# define CGAL_MESH_3_DEMO_ACTIVATE_SEGMENTED_IMAGES +#endif + +//#define CGAL_MESH_3_DEMO_DONT_COUNT_TETS_ADJACENT_TO_SHARP_FEATURES_FOR_HISTOGRAM + +// Optimizers +//#define CGAL_MESH_3_DEMO_DISABLE_ODT +//#define CGAL_MESH_3_DEMO_DISABLE_LLOYD +//#define CGAL_MESH_3_DEMO_DISABLE_PERTURBER +//#define CGAL_MESH_3_DEMO_DISABLE_EXUDER + +// ========================================================================== +// MESH_3 GENERAL PARAMETERS +// ========================================================================== + +//#define CGAL_MESH_3_USE_OLD_SURFACE_RESTRICTED_DELAUNAY_UPDATE // WARNING: VERY SLOW +#define CGAL_MESH_3_INITIAL_POINTS_NO_RANDOM_SHOOTING +//#define CGAL_MESHES_DEBUG_REFINEMENT_POINTS +//#define CHECK_AND_DISPLAY_THE_NUMBER_OF_BAD_ELEMENTS_IN_THE_END + +// ========================================================================== +// ========================================================================== +// CONCURRENT MESH_3? +// ========================================================================== +// ========================================================================== + +#ifdef CGAL_CONCURRENT_MESH_3 + +# ifndef CGAL_LINKED_WITH_TBB +# pragma message(" : Warning: CGAL_LINKED_WITH_TBB not defined: EVERYTHING WILL BE SEQUENTIAL.") +# endif + +# define CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE // default behavior +//# define CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE +# define CGAL_MESH_3_IF_UNSORTED_QUEUE_JUST_SORT_AFTER_SCAN +# include + + // ========================================================================== + // Verbose + // ========================================================================== + +# define CGAL_CONCURRENT_MESH_3_VERBOSE +//#define CGAL_CONCURRENT_MESH_3_VERY_VERBOSE + + // ========================================================================== + // Concurrency config + // ========================================================================== + + const char * const CONFIG_FILENAME = "concurrent_mesher_config.cfg"; + + // ===================== + // Worksharing strategy + // ===================== + +//# define CGAL_MESH_3_LOAD_BASED_WORKSHARING // Not recommended +//# define CGAL_MESH_3_TASK_SCHEDULER_SORTED_BATCHES_WITH_MULTISET +//# define CGAL_MESH_3_TASK_SCHEDULER_SORTED_BATCHES_WITH_SORT // default + + // ========================================================================== + // Profiling + // ========================================================================== + + // For abortion profiling, etc. +# define CGAL_CONCURRENT_MESH_3_PROFILING + // Debugging +//# define CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT + + +// ========================================================================== +// ========================================================================== +// SEQUENTIAL MESH_3? +// ========================================================================== +// ========================================================================== + +#else // !CGAL_CONCURRENT_MESH_3 + +//# define CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE +//# define CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE +# define CGAL_MESH_3_IF_UNSORTED_QUEUE_JUST_SORT_AFTER_SCAN + +#endif // CGAL_CONCURRENT_MESH_3 + +#define CGAL_MESH_3_PROFILING + +#endif // CGAL_DEMO_MESH_3_CONFIG_H diff --git a/Mesh_3/demo/Mesh_3/include/CGAL_demo/Io_plugin_interface.h b/Mesh_3/demo/Mesh_3/include/CGAL_demo/Io_plugin_interface.h index 625cb969e13..0cdeeb20732 100644 --- a/Mesh_3/demo/Mesh_3/include/CGAL_demo/Io_plugin_interface.h +++ b/Mesh_3/demo/Mesh_3/include/CGAL_demo/Io_plugin_interface.h @@ -17,7 +17,7 @@ public: virtual Scene_item* load(QFileInfo fileinfo) = 0; virtual bool canSave(const Scene_item*) = 0; - virtual bool save(const Scene_item*, QFileInfo fileinfo) = 0; + virtual bool save(const Scene_item*, QFileInfo fileinfo, QString selectedFilter) = 0; }; Q_DECLARE_INTERFACE(Io_plugin_interface, diff --git a/Mesh_3/demo/Mesh_3/ui_files/MainWindow.ui b/Mesh_3/demo/Mesh_3/ui_files/MainWindow.ui index b6d6dcc1aed..50bbe549e54 100644 --- a/Mesh_3/demo/Mesh_3/ui_files/MainWindow.ui +++ b/Mesh_3/demo/Mesh_3/ui_files/MainWindow.ui @@ -14,7 +14,7 @@ CGAL 3D mesh generator demo - + :/cgal/icons/resources/cgal_logo.xpm:/cgal/icons/resources/cgal_logo.xpm @@ -128,7 +128,7 @@ + - + :/cgal/icons/plus:/cgal/icons/plus @@ -139,7 +139,7 @@ - - + :/cgal/icons/minus:/cgal/icons/minus @@ -150,7 +150,7 @@ ... - + :/cgal/icons/duplicate:/cgal/icons/duplicate @@ -315,7 +315,7 @@ - + :/cgal/icons/plus:/cgal/icons/plus @@ -327,7 +327,7 @@ - + :/cgal/icons/minus:/cgal/icons/minus @@ -339,7 +339,7 @@ - + :/cgal/icons/duplicate:/cgal/icons/duplicate @@ -465,6 +465,9 @@ Create a tetrahedral mesh + + Ctrl+M + @@ -503,21 +506,33 @@ ODT-smoothing + + Ctrl+O + Lloyd-smoothing + + Ctrl+Y + Sliver perturbation + + Ctrl+P + Sliver exudation + + Ctrl+E + @@ -539,11 +554,11 @@ Viewer QWidget -
      CGAL_demo/Viewer.h
      +
      CGAL_demo/Viewer.h
      - + diff --git a/Mesh_3/doc/Mesh_3/CGAL/Mesh_triangulation_3.h b/Mesh_3/doc/Mesh_3/CGAL/Mesh_triangulation_3.h index 49c66b7c58d..7ae7c522974 100644 --- a/Mesh_3/doc/Mesh_3/CGAL/Mesh_triangulation_3.h +++ b/Mesh_3/doc/Mesh_3/CGAL/Mesh_triangulation_3.h @@ -3,16 +3,17 @@ namespace CGAL { /*! \ingroup PkgMesh_3MeshClasses -The class `Mesh_triangulation_3` is a metafunctor which provides the triangulation type to be used - for the 3D triangulation embedding the mesh. +The class `Mesh_triangulation_3` is a metafunctor which provides the triangulation type to be used +for the 3D triangulation embedding the mesh. \tparam MD stands for a model of `MeshDomain_3`. \tparam Gt stands for a model of `RegularTriangulationTraits_3` and defaults to `Kernel_traits::%Kernel`. -\tparam Concurrency_tag is a place-holder. It is not used yet -and defaults to `Default`. +\tparam Concurrency_tag enables sequential versus parallel meshing and optimization algorithms. + Possible values are `Sequential_tag` (the default) and + `Parallel_tag`. \tparam Vertex_base stands for a model of `MeshVertexBase_3` and defaults to `Mesh_vertex_base_3`. diff --git a/Mesh_3/doc/Mesh_3/Concepts/MeshCellBase_3.h b/Mesh_3/doc/Mesh_3/Concepts/MeshCellBase_3.h index 2e42580effd..7467e27e599 100644 --- a/Mesh_3/doc/Mesh_3/Concepts/MeshCellBase_3.h +++ b/Mesh_3/doc/Mesh_3/Concepts/MeshCellBase_3.h @@ -4,7 +4,8 @@ The concept `MeshCellBase_3` describes the requirements for the `Cell` type of the triangulation -used in the 3D mesh generation process. The type `MeshCellBase_3` refines the concept `RegularTriangulationCellBase_3`. +used in the 3D mesh generation process. The type `MeshCellBase_3` refines the concept `RegularTriangulationCellBase_3` +and must be copy constructible. The concept `MeshCellBase_3` includes a way to store and retrieve if a given cell of the triangulation @@ -29,8 +30,17 @@ of a surface facet, the center of its biggest Delaunay surface ball. The optimizers also need this concept to provide read-write access to two `Cell_handle` called 'intrusive'. +For parallel algorithms, the functions related to facet +access/modification must be concurrency-safe when several calls are +made in parallel on different facets of the cell (e.g. calling +set_facet_visited(0, true), set_facet_visited(2, true) +and is_facet_visited(1) in parallel must be safe) -\cgalRefines `RegularTriangulationCellBase_3` +Moreover, the parallel algorithms require an erase counter in +each cell (see below). + +\cgalRefines `RegularTriangulationCellBase_3` +\cgalRefines `CopyConstructible` \cgalHasModel `CGAL::Compact_mesh_cell_base_3` \cgalHasModel `CGAL::Mesh_cell_base_3` @@ -104,7 +114,7 @@ sets `Surface_patch_index` of facet `i` to `index`. void set_surface_patch_index(int i, Surface_patch_index index); /*! -Returns `true` iff `facet(i)` has been visited. +Returns `true` iff `facet(i)` has been visited. */ bool is_facet_visited (int i); @@ -124,7 +134,7 @@ Returns a const reference to the surface center of `facet(i)`. const Point& get_facet_surface_center(int i); /*! -Sets point `p` as the surface center of `facet(i)`. +Sets point `p` as the surface center of `facet(i)`. */ void set_facet_surface_center (int i, Point p); @@ -145,6 +155,20 @@ invalidate this cache value. */ void invalidate_circumcenter(); +/// Get the erase counter. +/// Only required by the parallel algorithms. +/// See `CGAL::Compact_container` for more details. +unsigned int erase_counter() const; + +/// Sets the erase counter. +/// Only required by the parallel algorithms. +/// See `CGAL::Compact_container` for more details. +void set_erase_counter(unsigned int c); + +/// Increments the erase counter. +/// Only required by the parallel algorithms. +/// See `CGAL::Compact_container` for more details. +void increment_erase_counter(); /// @} /*! \name Internal diff --git a/Mesh_3/doc/Mesh_3/Concepts/MeshVertexBase_3.h b/Mesh_3/doc/Mesh_3/Concepts/MeshVertexBase_3.h index a6540782b13..72352f6a228 100644 --- a/Mesh_3/doc/Mesh_3/Concepts/MeshVertexBase_3.h +++ b/Mesh_3/doc/Mesh_3/Concepts/MeshVertexBase_3.h @@ -17,6 +17,9 @@ and to an index characteristic of this face. The concept `MeshVertexBase_3` provides storage and read-write access to a boolean, a `FT` value, and two `Vertex_handle` called 'intrusive'. +The parallel algorithms require an erase counter in +each cell (see below). + \cgalRefines `TriangulationVertexBase_3` \cgalRefines `SurfaceMeshVertexBase_3` @@ -117,7 +120,20 @@ Vertex_handle previous_intrusive() const; */ void set_previous_intrusive(Vertex_handle); +/// Get the erase counter. +/// Only required by the parallel algorithms. +/// See `CGAL::Compact_container` for more details. +unsigned int erase_counter() const; +/// Sets the erase counter. +/// Only required by the parallel algorithms. +/// See `CGAL::Compact_container` for more details. +void set_erase_counter(unsigned int c); + +/// Increments the erase counter. +/// Only required by the parallel algorithms. +/// See `CGAL::Compact_container` for more details. +void increment_erase_counter(); /// @} }; /* end MeshVertexBase_3 */ diff --git a/Mesh_3/doc/Mesh_3/Mesh_3.txt b/Mesh_3/doc/Mesh_3/Mesh_3.txt index 280a290b38b..4e123007fb9 100644 --- a/Mesh_3/doc/Mesh_3/Mesh_3.txt +++ b/Mesh_3/doc/Mesh_3/Mesh_3.txt @@ -4,7 +4,7 @@ namespace CGAL { \mainpage User Manual \anchor Chapter_3D_Mesh_Generation \anchor userchaptermesh3 -\authors Pierre Alliez, Laurent Rineau, Stéphane Tayeb, Jane Tournois, Mariette Yvinec +\authors Pierre Alliez, Clément Jamin, Laurent Rineau, Stéphane Tayeb, Jane Tournois, Mariette Yvinec \cgalAutoToc \cgalFigureBegin{figuremultilabel_mesher,multilabel_mesher.jpg} @@ -15,7 +15,7 @@ Cut-view of a multi-domain 3D mesh generated from a segmented image. This package is devoted to the generation of isotropic simplicial meshes discretizing 3D domains. -The domain to be meshed is a region of 3D space that has to be bounded. +The domain to be meshed is a region of 3D space, required to be bounded. The region may be connected or composed of multiple components and/or subdivided in several subdomains. @@ -55,6 +55,9 @@ the boundary and subdivision surface patches may form \cgalCite{cgal:cdl-pdma-07 The Delaunay refinement is followed by a mesh optimization phase to remove slivers and provide a good quality mesh. +Optionally, the meshing and optimization algorithms support multi-core shared-memory +architectures to take advantage of available parallelism. + \subsection Mesh_3InputDomain Input Domain The domain to be meshed is assumed to be bounded @@ -543,6 +546,21 @@ Mesh_optimization_return_code exude_mesh_3(C3T3& c3t3); Note that the global functions activating the optimization processes or launching those processes have themselves parameters (see details in reference pages) to tune the optimization process. +\subsection Mesh_3ParallelAlgorithms Parallel Algorithms + +Enabling parallel meshing and optimization algorithms is achieved through +setting the third template parameter of the `Mesh_triangulation_3` class +to `Parallel_tag`, when defining the triangulation type. +Note that when the user provides his/her own vertex and +cell base classes, the `MeshVertexBase_3` and +`MeshCellBase_3` concepts impose additionnal requirements. + +Parallel algorithms require the executable to be linked against the +Intel TBB library. +To control the number of threads used, the user may use the tbb::task_scheduler_init class. +See the TBB documentation +for more details. + \section Mesh_3_section_examples Examples \subsection Mesh_33DDomainsBoundedbyIsosurfaces 3D Domains Bounded by Isosurfaces @@ -684,18 +702,19 @@ We set a time bound of 10s and a sliver bound of 10 degrees for the exuder. \cgalExample{Mesh_3/mesh_optimization_lloyd_example.cpp} -\section Mesh_3Performances Performances +\section Mesh_3Performances Performance -We provide here some benchmarks of the performances of the mesh generation engine. The machine -used is a PC running Linux64 with two Intel Xeon CPU X5450 clocked at 3.00 GHz -with 32GB of RAM. The program has been compiled with g++ v4.3.2 with the -O3 option. -Note that our implementation does not take advantage of multi-core -architectures. - -Those benchmarks have been done using \cgal v3.8. +We provide here some benchmarks of the performance of the mesh generation algorithms. \subsection Mesh_3DelaunayRefinement_1 Delaunay Refinement +The computer used for benchmarking is a PC running Linux64 with two Intel Xeon CPU X5450 clocked at 3.00 GHz +with 32GB of RAM. The program has been compiled with g++ v4.3.2 with the -O3 option. +These benchmarks have been done using \cgal v3.8. +Note that these benchmarks were obtained with the sequential version of the algorithm, +which does not take advantage of multi-core architectures. See the next +section for performance of parallel algorithms. + We study the refinement part of the mesh generation engine in this section. We give the CPU time (measured by `Timer`) using the 3 provided oracles. In all experiments, we produce well shaped elements: we set the facet angle bound and the radius edge bound to their @@ -975,6 +994,23 @@ vertices/second +\subsection Mesh_3Parallel_performance_1 Parallel Performance + +We provide below speed-up charts generated using the parallel version of the meshing algorithms of \cgal 4.5. +The machine used is a PC running Windows 7 64-bits with two 6-core Intel Xeon CPU X5660 clocked at 2.80 GHz +with 32GB of RAM. The program has been compiled with Microsoft Visual C++ 2012 in Release mode. + +Figure \cgalFigureRef{figure_refinement_speedup} shows mesh refinement speed-up, and figure \cgalFigureRef{figure_lloyd_speedup} +shows Lloyd optimization speed-up. ODT optimization exhibits similar speed-up. + +\cgalFigureBegin{figure_refinement_speedup,refinement_speedup.png} +Facet refinement speed-up (left) and cell refinement speed-up (right), compared to the sequential version of the algorithm. +\cgalFigureEnd + +\cgalFigureBegin{figure_lloyd_speedup,lloyd_speedup.png} +Lloyd optimization speed-up, compared to the sequential version of the algorithm. Parallel ODT exhibits similar performance. +\cgalFigureEnd + \section Mesh_3DesignAndImpl Design and Implementation History \subsection Mesh_3TheoreticalFoundations Theoretical Foundations @@ -1026,5 +1062,8 @@ Dobrina Boltcheva et al. \cgalCite{cgal:byb-mgmmi-09}, \cgalCite{cgal:-byb-fpdmg of 1-dimensional features was worked out by Laurent Rineau, Stéphane Tayeb and Mariette Yvinec. It appeared first in the release 3.8 of \cgal. +In 2013, Clément Jamin made the meshing and optimization algorithms parallel +on multi-core shared-memory architectures. +\todo Add reference to paper or research report when it is available. */ } /* namespace CGAL */ diff --git a/Mesh_3/doc/Mesh_3/PackageDescription.txt b/Mesh_3/doc/Mesh_3/PackageDescription.txt index 917a34d4566..e4435786cec 100644 --- a/Mesh_3/doc/Mesh_3/PackageDescription.txt +++ b/Mesh_3/doc/Mesh_3/PackageDescription.txt @@ -36,8 +36,8 @@ \cgalPkgDescriptionBegin{3D Mesh Generation,PkgMesh_3Summary} \cgalPkgPicture{Mesh_3/fig/multilabel_mesher_small.jpg} \cgalPkgSummaryBegin -\cgalPkgAuthors{Pierre Alliez, Laurent Rineau, Stéphane Tayeb, Jane Tournois, Mariette Yvinec} -\cgalPkgDesc{This package is devoted to the generation of isotropic simplicial meshes discretizing 3D domains. The domain to be meshed is a region of 3D space that has to be bounded. The region may be connected or composed of multiple components and/or subdivided in several subdomains. The domain is input as an oracle able to answer queries, of a few different types, on the domain. Boundary and subdivision surfaces are either smooth or piecewise smooth surfaces, formed with planar or curved surface patches. Surfaces may exhibit 1-dimensional features (e.g. crease edges) and 0-dimensional features (e.g. singular points as corners tips, cusps or darts), that have to be fairly approximated in the mesh. } +\cgalPkgAuthors{Pierre Alliez, Clément Jamin, Laurent Rineau, Stéphane Tayeb, Jane Tournois, Mariette Yvinec} +\cgalPkgDesc{This package is devoted to the generation of isotropic simplicial meshes discretizing 3D domains. The domain to be meshed is a region of 3D space that has to be bounded. The region may be connected or composed of multiple components and/or subdivided in several subdomains. The domain is input as an oracle able to answer queries, of a few different types, on the domain. Boundary and subdivision surfaces are either smooth or piecewise smooth surfaces, formed with planar or curved surface patches. Surfaces may exhibit 1-dimensional features (e.g. crease edges) and 0-dimensional features (e.g. singular points as corners tips, cusps or darts), that have to be fairly approximated in the mesh. Optionally, the algorithms support multi-core shared-memory architectures to take advantage of available parallelism.} \cgalPkgManuals{Chapter_3D_Mesh_Generation,PkgMesh_3} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin @@ -81,9 +81,9 @@ related to the template parameters of some models of the main concepts: - `CGAL::Mesh_complex_3_in_triangulation_3` - `CGAL::Mesh_triangulation_3` -- `CGAL::Mesh_vertex_base_3` +- `CGAL::Mesh_vertex_base_3` - `CGAL::Compact_mesh_cell_base_3` -- `CGAL::Mesh_cell_base_3` +- `CGAL::Mesh_cell_base_3` - `CGAL::Mesh_criteria_3` - `CGAL::Mesh_cell_criteria_3` - `CGAL::Mesh_facet_criteria_3` diff --git a/Mesh_3/doc/Mesh_3/fig/lloyd_speedup.png b/Mesh_3/doc/Mesh_3/fig/lloyd_speedup.png new file mode 100644 index 00000000000..ee55cacee6b Binary files /dev/null and b/Mesh_3/doc/Mesh_3/fig/lloyd_speedup.png differ diff --git a/Mesh_3/doc/Mesh_3/fig/refinement_speedup.png b/Mesh_3/doc/Mesh_3/fig/refinement_speedup.png new file mode 100644 index 00000000000..b1b8a970b33 Binary files /dev/null and b/Mesh_3/doc/Mesh_3/fig/refinement_speedup.png differ diff --git a/Mesh_3/dont_submit b/Mesh_3/dont_submit index 8b4facfc022..a1a98d4a535 100644 --- a/Mesh_3/dont_submit +++ b/Mesh_3/dont_submit @@ -13,3 +13,4 @@ demo/Mesh_3/C3t3_rib_exporter_plugin.cpp examples/Mesh_3/mesh_polyhedral_edge_tolerance_region.cpp examples/Mesh_3/mesh_polyhedral_implicit_function.cpp examples/Mesh_3/mesh_polyhedral_surface_tolerance_region.cpp +benchmark diff --git a/Mesh_3/examples/Mesh_3/CMakeLists.txt b/Mesh_3/examples/Mesh_3/CMakeLists.txt index e973b4f6bb4..77907617403 100644 --- a/Mesh_3/examples/Mesh_3/CMakeLists.txt +++ b/Mesh_3/examples/Mesh_3/CMakeLists.txt @@ -28,6 +28,30 @@ if ( CGAL_FOUND ) include( ${CGAL_USE_FILE} ) find_package(Boost) + # Activate concurrency ? (turned OFF by default) + option(ACTIVATE_CONCURRENT_MESH_3 + "Activate parallelism in Mesh_3" + OFF) + + # And add -DCGAL_CONCURRENT_MESH_3 if that option is ON + if( ACTIVATE_CONCURRENT_MESH_3 ) + add_definitions( -DCGAL_CONCURRENT_MESH_3 ) + find_package( TBB REQUIRED ) + else( ACTIVATE_CONCURRENT_MESH_3 ) + option( LINK_WITH_TBB + "Link with TBB anyway so we can use TBB timers for profiling" + ON) + if( LINK_WITH_TBB ) + find_package( TBB ) + endif( LINK_WITH_TBB ) + endif() + + if( TBB_FOUND ) + include(${TBB_USE_FILE}) + list(APPEND CGAL_3RD_PARTY_LIBRARIES ${TBB_LIBRARIES}) + endif() + + if ( Boost_FOUND AND Boost_VERSION GREATER 103400 ) include( CGAL_CreateSingleSourceCGALProgram ) diff --git a/Mesh_3/examples/Mesh_3/data/cheese.off b/Mesh_3/examples/Mesh_3/data/cheese.off new file mode 100644 index 00000000000..c484af92c1f --- /dev/null +++ b/Mesh_3/examples/Mesh_3/data/cheese.off @@ -0,0 +1,26417 @@ +OFF +8629 17786 0 +0.0313356780 0.0187550001 0.0386509448 +0.0500000007 0.0500000007 0.0500000007 +0.0500000007 0.0500000007 -0.0500000007 +0.0500000007 0.0437499993 0.0125000002 +0.0500000007 0.0437499993 -0.0125000002 +0.0500000007 0.0437499993 -0.0375000015 +0.0500000007 0.0437420011 0.0378109999 +0.0500000007 0.0436200015 0.0362300016 +0.0500000007 0.0435619988 0.0140230004 +0.0500000007 0.0435619988 0.0109770000 +0.0500000007 0.0435619988 -0.0109770000 +0.0500000007 0.0435619988 -0.0140230004 +0.0500000007 0.0435369983 -0.0358819999 +0.0500000007 0.0435369983 -0.0391179994 +0.0500000007 0.0434629992 0.0393720008 +0.0500000007 0.0431029983 0.0347299986 +0.0500000007 0.0430079997 0.0154539999 +0.0500000007 0.0430079997 0.0095459996 +0.0500000007 0.0430079997 -0.0095459996 +0.0500000007 0.0430079997 -0.0154539999 +0.0500000007 0.0429130010 -0.0343750007 +0.0500000007 0.0429130010 -0.0406249985 +0.0500000007 0.0428000018 0.0408129990 +0.0500000007 0.0422249995 0.0334089994 +0.0500000007 0.0421219990 0.0167069994 +0.0500000007 0.0421219990 0.0082930000 +0.0500000007 0.0421219990 -0.0082930000 +0.0500000007 0.0421219990 -0.0167069994 +0.0500000007 0.0419190004 -0.0330809988 +0.0500000007 0.0419190004 -0.0419190004 +0.0500000007 0.0417950004 0.0420400016 +0.0500000007 0.0410429984 0.0323509984 +0.0500000007 0.0409570001 0.0177069996 +0.0500000007 0.0409570001 0.0072929999 +0.0500000007 0.0409570001 -0.0072929999 +0.0500000007 0.0409570001 -0.0177069996 +0.0500000007 0.0406249985 -0.0320869982 +0.0500000007 0.0406249985 -0.0429130010 +0.0500000007 0.0405139998 0.0429750010 +0.0500000007 0.0396329984 0.0316249989 +0.0500000007 0.0395850018 0.0183920003 +0.0500000007 0.0395850018 0.0066080000 +0.0500000007 0.0395850018 -0.0066080000 +0.0500000007 0.0395850018 -0.0183920003 +0.0500000007 0.0391179994 -0.0314630009 +0.0500000007 0.0391179994 -0.0435369983 +0.0500000007 0.0390390009 0.0435580015 +0.0500000007 0.0380860008 0.0312779993 +0.0500000007 0.0380860008 0.0187219996 +0.0500000007 0.0380860008 0.0062779998 +0.0500000007 0.0380860008 -0.0062779998 +0.0500000007 0.0380860008 -0.0187219996 +0.0500000007 0.0380860008 -0.0255469996 +0.0500000007 0.0378339998 -0.0274580009 +0.0500000007 0.0375000015 -0.0312500000 +0.0500000007 0.0375000015 -0.0437499993 +0.0500000007 0.0374649987 0.0437499993 +0.0500000007 0.0370969996 -0.0292380005 +0.0500000007 0.0359239988 -0.0307669993 +0.0500000007 0.0358930007 0.0435400009 +0.0500000007 0.0358819999 -0.0314630009 +0.0500000007 0.0358819999 -0.0435369983 +0.0500000007 0.0344239995 0.0429410003 +0.0500000007 0.0343950018 -0.0319410004 +0.0500000007 0.0343750007 -0.0320869982 +0.0500000007 0.0343750007 -0.0429130010 +0.0500000007 0.0331539996 0.0419909991 +0.0500000007 0.0330809988 -0.0330809988 +0.0500000007 0.0330809988 -0.0419190004 +0.0500000007 0.0326140001 -0.0326780006 +0.0500000007 0.0321630016 0.0407529995 +0.0500000007 0.0320869982 -0.0343750007 +0.0500000007 0.0320869982 -0.0406249985 +0.0500000007 0.0314630009 -0.0358819999 +0.0500000007 0.0314630009 -0.0391179994 +0.0500000007 0.0312500000 -0.0375000015 +0.0500000007 0.0307030007 0.0408979990 +0.0500000007 0.0307030007 -0.0329300016 +0.0500000007 0.0243749991 0.0408979990 +0.0500000007 0.0227719992 0.0407220013 +0.0500000007 0.0212450009 0.0402019992 +0.0500000007 0.0198679995 0.0393630005 +0.0500000007 0.0187170003 -0.0368579999 +0.0500000007 0.0187049992 0.0382449999 +0.0500000007 0.0186919998 -0.0383489989 +0.0500000007 0.0183879994 -0.0354040004 +0.0500000007 0.0183169991 0.0397869982 +0.0500000007 0.0183150005 -0.0397909991 +0.0500000007 0.0177239999 -0.0340690017 +0.0500000007 0.0176069997 -0.0411030017 +0.0500000007 0.0175509993 0.0411810018 +0.0500000007 0.0169920009 0.0331550017 +0.0500000007 0.0169920009 0.0168450009 +0.0500000007 0.0169920009 0.0081550004 +0.0500000007 0.0169920009 -0.0081550004 +0.0500000007 0.0167629998 -0.0329300016 +0.0500000007 0.0166079998 -0.0422100015 +0.0500000007 0.0164589994 0.0423370004 +0.0500000007 0.0160370003 0.0323470011 +0.0500000007 0.0160370003 0.0073469998 +0.0500000007 0.0157960001 0.0178100001 +0.0500000007 0.0157680009 -0.0071720001 +0.0500000007 0.0153759997 -0.0430490002 +0.0500000007 0.0151100000 0.0431790017 +0.0500000007 0.0149400001 0.0317460001 +0.0500000007 0.0149400001 0.0067460001 +0.0500000007 0.0144010000 0.0184540004 +0.0500000007 0.0143370004 -0.0065259999 +0.0500000007 0.0139800003 -0.0435720012 +0.0500000007 0.0137449997 0.0313749984 +0.0500000007 0.0137449997 0.0063749999 +0.0500000007 0.0135920001 0.0436539985 +0.0500000007 0.0128910001 0.0187379997 +0.0500000007 0.0127910003 -0.0062569999 +0.0500000007 0.0125000002 0.0312500000 +0.0500000007 0.0125000002 0.0062500001 +0.0500000007 0.0125000002 -0.0437499993 +0.0500000007 0.0120029999 0.0437299982 +0.0500000007 0.0113570001 0.0186449997 +0.0500000007 0.0112260003 -0.0063809999 +0.0500000007 0.0110200001 -0.0435720012 +0.0500000007 0.0109750004 0.0064389999 +0.0500000007 0.0109219998 0.0314520001 +0.0500000007 0.0104470002 0.0434029996 +0.0500000007 0.0098919999 0.0181799997 +0.0500000007 0.0097420001 -0.0068919999 +0.0500000007 0.0096239997 -0.0430490002 +0.0500000007 0.0095419995 0.0069940002 +0.0500000007 0.0094470000 0.0320460014 +0.0500000007 0.0090229996 0.0426939987 +0.0500000007 0.0085850004 0.0173719991 +0.0500000007 0.0084309997 -0.0077559999 +0.0500000007 0.0083919996 -0.0422100015 +0.0500000007 0.0082879998 0.0078819999 +0.0500000007 0.0082369996 -0.0329300016 +0.0500000007 0.0081690000 0.0329939984 +0.0500000007 0.0078250002 0.0416480005 +0.0500000007 0.0075150002 0.0162700005 +0.0500000007 0.0073930002 -0.0411030017 +0.0500000007 0.0073779998 -0.0089189997 +0.0500000007 0.0072889999 0.0090490002 +0.0500000007 0.0072760000 -0.0340690017 +0.0500000007 0.0071720001 0.0342320018 +0.0500000007 0.0069289999 0.0403329991 +0.0500000007 0.0067460001 0.0149400001 +0.0500000007 0.0066849999 -0.0397909991 +0.0500000007 0.0066470001 -0.0103080003 +0.0500000007 0.0066120001 -0.0354040004 +0.0500000007 0.0066049998 0.0104250005 +0.0500000007 0.0065199998 0.0356829986 +0.0500000007 0.0063939998 0.0388359986 +0.0500000007 0.0063240002 0.0134619996 +0.0500000007 0.0063080001 -0.0383489989 +0.0500000007 0.0062850001 -0.0118359998 +0.0500000007 0.0062830001 -0.0368579999 +0.0500000007 0.0062759998 0.0119260000 +0.0500000007 0.0062549999 0.0372509994 +0.0500000007 -0.0062500001 0.0375000015 +0.0500000007 -0.0062500001 0.0125000002 +0.0500000007 -0.0062830001 -0.0368579999 +0.0500000007 -0.0062850001 -0.0118359998 +0.0500000007 -0.0063080001 -0.0383489989 +0.0500000007 -0.0064630001 0.0391179994 +0.0500000007 -0.0064630001 0.0358819999 +0.0500000007 -0.0064630001 0.0141179999 +0.0500000007 -0.0064630001 0.0108820004 +0.0500000007 -0.0066120001 -0.0354040004 +0.0500000007 -0.0066320002 -0.0103489999 +0.0500000007 -0.0066849999 -0.0397909991 +0.0500000007 -0.0070870002 0.0406249985 +0.0500000007 -0.0070870002 0.0343750007 +0.0500000007 -0.0070870002 0.0156250000 +0.0500000007 -0.0070870002 0.0093750004 +0.0500000007 -0.0072760000 -0.0340690017 +0.0500000007 -0.0073279999 -0.0089910002 +0.0500000007 -0.0073930002 -0.0411030017 +0.0500000007 -0.0080810003 0.0419190004 +0.0500000007 -0.0080810003 0.0330809988 +0.0500000007 -0.0080810003 0.0169190001 +0.0500000007 -0.0080810003 0.0080810003 +0.0500000007 -0.0082369996 -0.0329300016 +0.0500000007 -0.0083320001 -0.0078419996 +0.0500000007 -0.0083919996 -0.0422100015 +0.0500000007 -0.0093750004 0.0429130010 +0.0500000007 -0.0093750004 0.0320869982 +0.0500000007 -0.0093750004 0.0179130007 +0.0500000007 -0.0093750004 0.0070870002 +0.0500000007 -0.0095859999 -0.0069710002 +0.0500000007 -0.0096239997 -0.0430490002 +0.0500000007 -0.0108820004 0.0435369983 +0.0500000007 -0.0108820004 0.0314630009 +0.0500000007 -0.0108820004 0.0185369998 +0.0500000007 -0.0108820004 0.0064630001 +0.0500000007 -0.0110130003 -0.0064300001 +0.0500000007 -0.0110200001 -0.0435720012 +0.0500000007 -0.0125000002 0.0437499993 +0.0500000007 -0.0125000002 0.0312500000 +0.0500000007 -0.0125000002 0.0187500007 +0.0500000007 -0.0125000002 0.0062500001 +0.0500000007 -0.0125000002 -0.0437499993 +0.0500000007 -0.0125280004 -0.0062500001 +0.0500000007 -0.0139800003 -0.0435720012 +0.0500000007 -0.0140420003 -0.0064429999 +0.0500000007 -0.0141179999 0.0435369983 +0.0500000007 -0.0141179999 0.0314630009 +0.0500000007 -0.0141179999 0.0185369998 +0.0500000007 -0.0141179999 0.0064630001 +0.0500000007 -0.0153759997 -0.0430490002 +0.0500000007 -0.0154640004 -0.0069980002 +0.0500000007 -0.0156250000 0.0429130010 +0.0500000007 -0.0156250000 0.0320869982 +0.0500000007 -0.0156250000 0.0179130007 +0.0500000007 -0.0156250000 0.0070870002 +0.0500000007 -0.0166079998 -0.0422100015 +0.0500000007 -0.0167089999 -0.0078800004 +0.0500000007 -0.0167629998 -0.0329300016 +0.0500000007 -0.0169190001 0.0419190004 +0.0500000007 -0.0169190001 0.0330809988 +0.0500000007 -0.0169190001 0.0169190001 +0.0500000007 -0.0169190001 0.0080810003 +0.0500000007 -0.0176069997 -0.0411030017 +0.0500000007 -0.0177040007 -0.0090380004 +0.0500000007 -0.0177239999 -0.0340690017 +0.0500000007 -0.0178120006 -0.0329300016 +0.0500000007 -0.0179130007 0.0406249985 +0.0500000007 -0.0179130007 0.0343750007 +0.0500000007 -0.0179130007 0.0156250000 +0.0500000007 -0.0179130007 0.0093750004 +0.0500000007 -0.0183150005 -0.0397909991 +0.0500000007 -0.0183879994 -0.0104019996 +0.0500000007 -0.0183879994 -0.0354040004 +0.0500000007 -0.0185369998 0.0391179994 +0.0500000007 -0.0185369998 0.0358819999 +0.0500000007 -0.0185369998 0.0141179999 +0.0500000007 -0.0185369998 0.0108820004 +0.0500000007 -0.0186919998 -0.0383489989 +0.0500000007 -0.0187170003 -0.0368579999 +0.0500000007 -0.0187199991 -0.0118920002 +0.0500000007 -0.0187500007 0.0375000015 +0.0500000007 -0.0187500007 0.0125000002 +0.0500000007 -0.0197230000 -0.0326780006 +0.0500000007 -0.0204450004 -0.0123210000 +0.0500000007 -0.0215039998 -0.0319410004 +0.0500000007 -0.0220160000 -0.0131500000 +0.0500000007 -0.0230330005 -0.0307669993 +0.0500000007 -0.0233449992 -0.0143299997 +0.0500000007 -0.0242059994 -0.0292380005 +0.0500000007 -0.0243519992 -0.0157929994 +0.0500000007 -0.0249439999 -0.0274580009 +0.0500000007 -0.0249819998 -0.0174550004 +0.0500000007 -0.0251950007 -0.0192189999 +0.0500000007 -0.0251950007 -0.0255469996 +0.0500000007 -0.0312500000 0.0375000015 +0.0500000007 -0.0312500000 0.0125000002 +0.0500000007 -0.0312500000 -0.0125000002 +0.0500000007 -0.0312500000 -0.0375000015 +0.0500000007 -0.0314630009 0.0391179994 +0.0500000007 -0.0314630009 0.0358819999 +0.0500000007 -0.0314630009 0.0141179999 +0.0500000007 -0.0314630009 0.0108820004 +0.0500000007 -0.0314630009 -0.0108820004 +0.0500000007 -0.0314630009 -0.0141179999 +0.0500000007 -0.0314630009 -0.0358819999 +0.0500000007 -0.0314630009 -0.0391179994 +0.0500000007 -0.0320869982 0.0406249985 +0.0500000007 -0.0320869982 0.0343750007 +0.0500000007 -0.0320869982 0.0156250000 +0.0500000007 -0.0320869982 0.0093750004 +0.0500000007 -0.0320869982 -0.0093750004 +0.0500000007 -0.0320869982 -0.0156250000 +0.0500000007 -0.0320869982 -0.0343750007 +0.0500000007 -0.0320869982 -0.0406249985 +0.0500000007 -0.0330809988 0.0419190004 +0.0500000007 -0.0330809988 0.0330809988 +0.0500000007 -0.0330809988 0.0169190001 +0.0500000007 -0.0330809988 0.0080810003 +0.0500000007 -0.0330809988 -0.0080810003 +0.0500000007 -0.0330809988 -0.0169190001 +0.0500000007 -0.0330809988 -0.0330809988 +0.0500000007 -0.0330809988 -0.0419190004 +0.0500000007 -0.0343750007 0.0429130010 +0.0500000007 -0.0343750007 0.0320869982 +0.0500000007 -0.0343750007 0.0179130007 +0.0500000007 -0.0343750007 0.0070870002 +0.0500000007 -0.0343750007 -0.0070870002 +0.0500000007 -0.0343750007 -0.0179130007 +0.0500000007 -0.0343750007 -0.0320869982 +0.0500000007 -0.0343750007 -0.0429130010 +0.0500000007 -0.0358819999 0.0435369983 +0.0500000007 -0.0358819999 0.0314630009 +0.0500000007 -0.0358819999 0.0185369998 +0.0500000007 -0.0358819999 0.0064630001 +0.0500000007 -0.0358819999 -0.0064630001 +0.0500000007 -0.0358819999 -0.0185369998 +0.0500000007 -0.0358819999 -0.0314630009 +0.0500000007 -0.0358819999 -0.0435369983 +0.0500000007 -0.0375000015 0.0437499993 +0.0500000007 -0.0375000015 0.0312500000 +0.0500000007 -0.0375000015 0.0187500007 +0.0500000007 -0.0375000015 0.0062500001 +0.0500000007 -0.0375000015 0.0050889999 +0.0500000007 -0.0375000015 -0.0062500001 +0.0500000007 -0.0375000015 -0.0187500007 +0.0500000007 -0.0375000015 -0.0312500000 +0.0500000007 -0.0375000015 -0.0437499993 +0.0500000007 -0.0391030014 -0.0185410008 +0.0500000007 -0.0391179994 0.0435369983 +0.0500000007 -0.0391179994 0.0314630009 +0.0500000007 -0.0391179994 0.0185369998 +0.0500000007 -0.0391179994 0.0064630001 +0.0500000007 -0.0391179994 -0.0314630009 +0.0500000007 -0.0391179994 -0.0435369983 +0.0500000007 -0.0405989997 -0.0179270003 +0.0500000007 -0.0406249985 0.0429130010 +0.0500000007 -0.0406249985 0.0320869982 +0.0500000007 -0.0406249985 0.0179130007 +0.0500000007 -0.0406249985 0.0070870002 +0.0500000007 -0.0406249985 -0.0320869982 +0.0500000007 -0.0406249985 -0.0429130010 +0.0500000007 -0.0418879986 -0.0169510003 +0.0500000007 -0.0419190004 0.0419190004 +0.0500000007 -0.0419190004 0.0330809988 +0.0500000007 -0.0419190004 0.0169190001 +0.0500000007 -0.0419190004 0.0080810003 +0.0500000007 -0.0419190004 -0.0330809988 +0.0500000007 -0.0419190004 -0.0419190004 +0.0500000007 -0.0428830013 -0.0156759992 +0.0500000007 -0.0429130010 0.0406249985 +0.0500000007 -0.0429130010 0.0343750007 +0.0500000007 -0.0429130010 0.0156250000 +0.0500000007 -0.0429130010 0.0093750004 +0.0500000007 -0.0429130010 -0.0343750007 +0.0500000007 -0.0429130010 -0.0406249985 +0.0500000007 -0.0435170010 -0.0141890002 +0.0500000007 -0.0435369983 0.0391179994 +0.0500000007 -0.0435369983 0.0358819999 +0.0500000007 -0.0435369983 0.0141179999 +0.0500000007 -0.0435369983 0.0108820004 +0.0500000007 -0.0435369983 -0.0358819999 +0.0500000007 -0.0435369983 -0.0391179994 +0.0500000007 -0.0437490009 -0.0125890002 +0.0500000007 -0.0437499993 0.0375000015 +0.0500000007 -0.0437499993 0.0125000002 +0.0500000007 -0.0437499993 -0.0375000015 +0.0500000007 -0.0500000007 0.0500000007 +0.0500000007 -0.0500000007 0.0050889999 +0.0500000007 -0.0500000007 -0.0125890002 +0.0500000007 -0.0500000007 -0.0500000007 +0.0487929992 -0.0436140001 -0.0137949996 +0.0476359986 -0.0432480015 -0.0149529995 +0.0465699993 -0.0426659994 -0.0160179995 +0.0456379987 -0.0418879986 -0.0169510003 +0.0448740013 -0.0409450009 -0.0177149996 +0.0443059988 -0.0398709998 -0.0182830002 +0.0439569987 -0.0387080014 -0.0186320003 +0.0438680016 -0.0381070003 -0.0187199991 +0.0438390002 -0.0375000015 -0.0187500007 +0.0437499993 0.0500000007 0.0375000015 +0.0437499993 0.0500000007 0.0125000002 +0.0437499993 0.0500000007 -0.0125000002 +0.0437499993 0.0500000007 -0.0375000015 +0.0437499993 0.0437499993 0.0375000015 +0.0437499993 0.0437499993 0.0125000002 +0.0437499993 0.0437499993 -0.0125000002 +0.0437499993 0.0437499993 -0.0375000015 +0.0437499993 0.0375000015 0.0500000007 +0.0437499993 0.0375000015 0.0437499993 +0.0437499993 0.0375000015 -0.0312500000 +0.0437499993 0.0375000015 -0.0437499993 +0.0437499993 0.0375000015 -0.0500000007 +0.0437499993 0.0312500000 -0.0375000015 +0.0437499993 0.0187500007 -0.0375000015 +0.0437499993 0.0125000002 0.0500000007 +0.0437499993 0.0125000002 0.0437499993 +0.0437499993 0.0125000002 0.0312500000 +0.0437499993 0.0125000002 0.0187500007 +0.0437499993 0.0125000002 0.0062500001 +0.0437499993 0.0125000002 -0.0062500001 +0.0437499993 0.0125000002 -0.0437499993 +0.0437499993 0.0125000002 -0.0500000007 +0.0437499993 0.0062500001 0.0375000015 +0.0437499993 0.0062500001 0.0125000002 +0.0437499993 0.0062500001 -0.0375000015 +0.0437499993 -0.0062500001 0.0375000015 +0.0437499993 -0.0062500001 0.0125000002 +0.0437499993 -0.0062500001 -0.0375000015 +0.0437499993 -0.0125000002 0.0500000007 +0.0437499993 -0.0125000002 0.0437499993 +0.0437499993 -0.0125000002 0.0312500000 +0.0437499993 -0.0125000002 0.0187500007 +0.0437499993 -0.0125000002 0.0062500001 +0.0437499993 -0.0125000002 -0.0062500001 +0.0437499993 -0.0125000002 -0.0437499993 +0.0437499993 -0.0125000002 -0.0500000007 +0.0437499993 -0.0187500007 0.0375000015 +0.0437499993 -0.0187500007 0.0125000002 +0.0437499993 -0.0187500007 -0.0375000015 +0.0437499993 -0.0312500000 0.0375000015 +0.0437499993 -0.0312500000 0.0125000002 +0.0437499993 -0.0312500000 -0.0125000002 +0.0437499993 -0.0312500000 -0.0375000015 +0.0437499993 -0.0375000015 0.0500000007 +0.0437499993 -0.0375000015 0.0437499993 +0.0437499993 -0.0375000015 0.0312500000 +0.0437499993 -0.0375000015 0.0187500007 +0.0437499993 -0.0375000015 0.0062500001 +0.0437499993 -0.0375000015 -0.0011610000 +0.0437499993 -0.0375000015 -0.0062500001 +0.0437499993 -0.0375000015 -0.0188389998 +0.0437499993 -0.0375000015 -0.0312500000 +0.0437499993 -0.0375000015 -0.0437499993 +0.0437499993 -0.0375000015 -0.0500000007 +0.0437499993 -0.0437499993 0.0375000015 +0.0437499993 -0.0437499993 0.0125000002 +0.0437499993 -0.0437499993 -0.0375000015 +0.0437499993 -0.0500000007 0.0375000015 +0.0437499993 -0.0500000007 0.0125000002 +0.0437499993 -0.0500000007 -0.0375000015 +0.0437479988 0.0376459993 -0.0280569997 +0.0437470004 -0.0204029996 -0.0123060001 +0.0437370017 0.0370990001 -0.0292349998 +0.0437319987 0.0379780009 -0.0268029999 +0.0437220000 0.0380860008 0.0312779993 +0.0437220000 0.0380860008 0.0187219996 +0.0437220000 0.0380860008 0.0062779998 +0.0437220000 0.0380860008 -0.0062779998 +0.0437220000 0.0380860008 -0.0187219996 +0.0437220000 0.0380860008 -0.0255469996 +0.0437220000 -0.0380889997 -0.0188669991 +0.0437210016 -0.0219470002 -0.0131019996 +0.0437199995 0.0437199995 0.0381130017 +0.0437199995 0.0437199995 0.0368870012 +0.0437199995 0.0437199995 0.0131130004 +0.0437199995 0.0437199995 0.0118869999 +0.0437199995 0.0437199995 -0.0118869999 +0.0437199995 0.0437199995 -0.0131130004 +0.0437199995 0.0437199995 -0.0368870012 +0.0437199995 0.0437199995 -0.0381130017 +0.0437199995 0.0381130017 0.0437199995 +0.0437199995 0.0381130017 -0.0312799998 +0.0437199995 0.0381130017 -0.0437199995 +0.0437199995 0.0368870012 0.0437199995 +0.0437199995 0.0368870012 -0.0312799998 +0.0437199995 0.0368870012 -0.0437199995 +0.0437199995 0.0312799998 -0.0368870012 +0.0437199995 0.0312799998 -0.0381130017 +0.0437199995 0.0187199991 -0.0368870012 +0.0437199995 0.0187199991 -0.0381130017 +0.0437199995 0.0131130004 0.0437199995 +0.0437199995 0.0131130004 0.0312799998 +0.0437199995 0.0131130004 0.0187199991 +0.0437199995 0.0131130004 0.0062799999 +0.0437199995 0.0131130004 -0.0062799999 +0.0437199995 0.0131130004 -0.0437199995 +0.0437199995 0.0118869999 0.0437199995 +0.0437199995 0.0118869999 0.0312799998 +0.0437199995 0.0118869999 0.0187199991 +0.0437199995 0.0118869999 0.0062799999 +0.0437199995 0.0118869999 -0.0062799999 +0.0437199995 0.0118869999 -0.0437199995 +0.0437199995 0.0062799999 0.0381130017 +0.0437199995 0.0062799999 0.0368870012 +0.0437199995 0.0062799999 0.0131130004 +0.0437199995 0.0062799999 0.0118869999 +0.0437199995 0.0062799999 -0.0368870012 +0.0437199995 0.0062799999 -0.0381130017 +0.0437199995 -0.0062799999 0.0381130017 +0.0437199995 -0.0062799999 0.0368870012 +0.0437199995 -0.0062799999 0.0131130004 +0.0437199995 -0.0062799999 0.0118869999 +0.0437199995 -0.0062799999 -0.0368870012 +0.0437199995 -0.0062799999 -0.0381130017 +0.0437199995 -0.0118869999 0.0437199995 +0.0437199995 -0.0118869999 0.0312799998 +0.0437199995 -0.0118869999 0.0187199991 +0.0437199995 -0.0118869999 0.0062799999 +0.0437199995 -0.0118869999 -0.0062799999 +0.0437199995 -0.0118869999 -0.0437199995 +0.0437199995 -0.0131130004 0.0437199995 +0.0437199995 -0.0131130004 0.0312799998 +0.0437199995 -0.0131130004 0.0187199991 +0.0437199995 -0.0131130004 0.0062799999 +0.0437199995 -0.0131130004 -0.0062799999 +0.0437199995 -0.0131130004 -0.0437199995 +0.0437199995 -0.0187199991 0.0381130017 +0.0437199995 -0.0187199991 0.0368870012 +0.0437199995 -0.0187199991 0.0131130004 +0.0437199995 -0.0187199991 0.0118869999 +0.0437199995 -0.0187199991 -0.0118920002 +0.0437199995 -0.0187199991 -0.0368870012 +0.0437199995 -0.0187199991 -0.0381130017 +0.0437199995 -0.0312799998 0.0381130017 +0.0437199995 -0.0312799998 0.0368870012 +0.0437199995 -0.0312799998 0.0131130004 +0.0437199995 -0.0312799998 0.0118869999 +0.0437199995 -0.0312799998 -0.0118869999 +0.0437199995 -0.0312799998 -0.0131130004 +0.0437199995 -0.0312799998 -0.0368870012 +0.0437199995 -0.0312799998 -0.0381130017 +0.0437199995 -0.0368870012 0.0437199995 +0.0437199995 -0.0368870012 0.0312799998 +0.0437199995 -0.0368870012 0.0187199991 +0.0437199995 -0.0368870012 0.0062799999 +0.0437199995 -0.0368870012 -0.0062799999 +0.0437199995 -0.0368870012 -0.0187199991 +0.0437199995 -0.0368870012 -0.0312799998 +0.0437199995 -0.0368870012 -0.0437199995 +0.0437199995 -0.0381130017 0.0437199995 +0.0437199995 -0.0381130017 0.0312799998 +0.0437199995 -0.0381130017 0.0187199991 +0.0437199995 -0.0381130017 0.0062799999 +0.0437199995 -0.0381130017 -0.0312799998 +0.0437199995 -0.0381130017 -0.0437199995 +0.0437199995 -0.0437199995 0.0381130017 +0.0437199995 -0.0437199995 0.0368870012 +0.0437199995 -0.0437199995 0.0131130004 +0.0437199995 -0.0437199995 0.0118869999 +0.0437199995 -0.0437199995 -0.0368870012 +0.0437199995 -0.0437199995 -0.0381130017 +0.0437150002 0.0062850001 -0.0118359998 +0.0437150002 -0.0062850001 -0.0118359998 +0.0437050015 0.0187049992 0.0382449999 +0.0436550006 -0.0385870002 -0.0012560000 +0.0436489992 -0.0226210002 -0.0136160003 +0.0436469987 0.0363700017 -0.0302779991 +0.0436390005 -0.0386740007 -0.0189500004 +0.0436300002 0.0436300002 0.0387189984 +0.0436300002 0.0436300002 0.0362810008 +0.0436300002 0.0436300002 0.0137189999 +0.0436300002 0.0436300002 0.0112810005 +0.0436300002 0.0436300002 -0.0112810005 +0.0436300002 0.0436300002 -0.0137189999 +0.0436300002 0.0436300002 -0.0362810008 +0.0436300002 0.0436300002 -0.0387189984 +0.0436300002 0.0387189984 0.0436300002 +0.0436300002 0.0387189984 -0.0313699991 +0.0436300002 0.0387189984 -0.0436300002 +0.0436300002 0.0362810008 0.0436300002 +0.0436300002 0.0362810008 -0.0313699991 +0.0436300002 0.0362810008 -0.0436300002 +0.0436300002 0.0313699991 -0.0362810008 +0.0436300002 0.0313699991 -0.0387189984 +0.0436300002 0.0186299998 -0.0362810008 +0.0436300002 0.0186299998 -0.0387189984 +0.0436300002 0.0137189999 0.0436300002 +0.0436300002 0.0137189999 0.0313699991 +0.0436300002 0.0137189999 0.0186299998 +0.0436300002 0.0137189999 0.0063700001 +0.0436300002 0.0137189999 -0.0063700001 +0.0436300002 0.0137189999 -0.0436300002 +0.0436300002 0.0112810005 0.0436300002 +0.0436300002 0.0112810005 0.0313699991 +0.0436300002 0.0112810005 0.0186299998 +0.0436300002 0.0112810005 0.0063700001 +0.0436300002 0.0112810005 -0.0063700001 +0.0436300002 0.0112810005 -0.0436300002 +0.0436300002 0.0063700001 0.0387189984 +0.0436300002 0.0063700001 0.0362810008 +0.0436300002 0.0063700001 0.0137189999 +0.0436300002 0.0063700001 0.0112810005 +0.0436300002 0.0063700001 -0.0362810008 +0.0436300002 0.0063700001 -0.0387189984 +0.0436300002 -0.0063700001 0.0387189984 +0.0436300002 -0.0063700001 0.0362810008 +0.0436300002 -0.0063700001 0.0137189999 +0.0436300002 -0.0063700001 0.0112810005 +0.0436300002 -0.0063700001 -0.0362810008 +0.0436300002 -0.0063700001 -0.0387189984 +0.0436300002 -0.0112810005 0.0436300002 +0.0436300002 -0.0112810005 0.0313699991 +0.0436300002 -0.0112810005 0.0186299998 +0.0436300002 -0.0112810005 0.0063700001 +0.0436300002 -0.0112810005 -0.0063700001 +0.0436300002 -0.0112810005 -0.0436300002 +0.0436300002 -0.0137189999 0.0436300002 +0.0436300002 -0.0137189999 0.0313699991 +0.0436300002 -0.0137189999 0.0186299998 +0.0436300002 -0.0137189999 0.0063700001 +0.0436300002 -0.0137189999 -0.0063700001 +0.0436300002 -0.0137189999 -0.0436300002 +0.0436300002 -0.0186299998 0.0387189984 +0.0436300002 -0.0186299998 0.0362810008 +0.0436300002 -0.0186299998 0.0137189999 +0.0436300002 -0.0186299998 0.0112810005 +0.0436300002 -0.0186299998 -0.0362810008 +0.0436300002 -0.0186299998 -0.0387189984 +0.0436300002 -0.0313699991 0.0387189984 +0.0436300002 -0.0313699991 0.0362810008 +0.0436300002 -0.0313699991 0.0137189999 +0.0436300002 -0.0313699991 0.0112810005 +0.0436300002 -0.0313699991 -0.0112810005 +0.0436300002 -0.0313699991 -0.0137189999 +0.0436300002 -0.0313699991 -0.0362810008 +0.0436300002 -0.0313699991 -0.0387189984 +0.0436300002 -0.0362810008 0.0436300002 +0.0436300002 -0.0362810008 0.0313699991 +0.0436300002 -0.0362810008 0.0186299998 +0.0436300002 -0.0362810008 0.0063700001 +0.0436300002 -0.0362810008 -0.0063700001 +0.0436300002 -0.0362810008 -0.0186299998 +0.0436300002 -0.0362810008 -0.0313699991 +0.0436300002 -0.0362810008 -0.0436300002 +0.0436300002 -0.0387189984 0.0436300002 +0.0436300002 -0.0387189984 0.0313699991 +0.0436300002 -0.0387189984 0.0186299998 +0.0436300002 -0.0387189984 0.0063700001 +0.0436300002 -0.0387189984 -0.0313699991 +0.0436300002 -0.0387189984 -0.0436300002 +0.0436300002 -0.0436300002 0.0387189984 +0.0436300002 -0.0436300002 0.0362810008 +0.0436300002 -0.0436300002 0.0137189999 +0.0436300002 -0.0436300002 0.0112810005 +0.0436300002 -0.0436300002 -0.0362810008 +0.0436300002 -0.0436300002 -0.0387189984 +0.0435400009 0.0358939990 0.0500000007 +0.0435389988 0.0391100012 0.0500000007 +0.0435369983 0.0500000007 0.0391179994 +0.0435369983 0.0500000007 0.0358819999 +0.0435369983 0.0500000007 0.0141179999 +0.0435369983 0.0500000007 0.0108820004 +0.0435369983 0.0500000007 -0.0108820004 +0.0435369983 0.0500000007 -0.0141179999 +0.0435369983 0.0500000007 -0.0358819999 +0.0435369983 0.0500000007 -0.0391179994 +0.0435369983 0.0391179994 -0.0500000007 +0.0435369983 0.0358819999 -0.0500000007 +0.0435369983 0.0141179999 0.0500000007 +0.0435369983 0.0141179999 -0.0500000007 +0.0435369983 0.0108820004 0.0500000007 +0.0435369983 0.0108820004 -0.0500000007 +0.0435369983 -0.0108820004 0.0500000007 +0.0435369983 -0.0108820004 -0.0500000007 +0.0435369983 -0.0141179999 0.0500000007 +0.0435369983 -0.0141179999 -0.0500000007 +0.0435369983 -0.0358819999 0.0500000007 +0.0435369983 -0.0358819999 -0.0500000007 +0.0435369983 -0.0391179994 0.0500000007 +0.0435369983 -0.0391179994 -0.0500000007 +0.0435369983 -0.0500000007 0.0391179994 +0.0435369983 -0.0500000007 0.0358819999 +0.0435369983 -0.0500000007 0.0141179999 +0.0435369983 -0.0500000007 0.0108820004 +0.0435369983 -0.0500000007 -0.0358819999 +0.0435369983 -0.0500000007 -0.0391179994 +0.0435290001 0.0391479991 0.0314709991 +0.0435290001 0.0391479991 0.0185289998 +0.0435290001 0.0391479991 0.0064710001 +0.0435290001 0.0391479991 -0.0064710001 +0.0435290001 0.0391479991 -0.0185289998 +0.0435249992 -0.0185250007 -0.0108359996 +0.0435170010 -0.0232170001 -0.0141890002 +0.0435130000 0.0064869998 -0.0107960002 +0.0435130000 -0.0064869998 -0.0107960002 +0.0434960015 0.0184959993 0.0392629988 +0.0434670001 0.0198640004 0.0393600017 +0.0434210002 0.0354989991 -0.0311600007 +0.0433720015 -0.0396410003 -0.0015390000 +0.0433089994 -0.0398049988 -0.0192799997 +0.0432940014 -0.0237590000 -0.0148440003 +0.0432740003 0.0432740003 0.0398919992 +0.0432740003 0.0432740003 0.0351080000 +0.0432740003 0.0432740003 0.0148919998 +0.0432740003 0.0432740003 0.0101079997 +0.0432740003 0.0432740003 -0.0101079997 +0.0432740003 0.0432740003 -0.0148919998 +0.0432740003 0.0432740003 -0.0351080000 +0.0432740003 0.0432740003 -0.0398919992 +0.0432740003 0.0398919992 0.0432740003 +0.0432740003 0.0398919992 -0.0317259990 +0.0432740003 0.0398919992 -0.0432740003 +0.0432740003 0.0351080000 0.0432740003 +0.0432740003 0.0351080000 -0.0317259990 +0.0432740003 0.0351080000 -0.0432740003 +0.0432740003 0.0317259990 -0.0351080000 +0.0432740003 0.0317259990 -0.0398919992 +0.0432740003 0.0182739999 -0.0351080000 +0.0432740003 0.0182739999 -0.0398919992 +0.0432740003 0.0148919998 0.0432740003 +0.0432740003 0.0148919998 0.0317259990 +0.0432740003 0.0148919998 0.0182739999 +0.0432740003 0.0148919998 0.0067260000 +0.0432740003 0.0148919998 -0.0067260000 +0.0432740003 0.0148919998 -0.0432740003 +0.0432740003 0.0101079997 0.0432740003 +0.0432740003 0.0101079997 0.0317259990 +0.0432740003 0.0101079997 0.0182739999 +0.0432740003 0.0101079997 0.0067260000 +0.0432740003 0.0101079997 -0.0067260000 +0.0432740003 0.0101079997 -0.0432740003 +0.0432740003 0.0067260000 0.0398919992 +0.0432740003 0.0067260000 0.0351080000 +0.0432740003 0.0067260000 0.0148919998 +0.0432740003 0.0067260000 0.0101079997 +0.0432740003 0.0067260000 -0.0351080000 +0.0432740003 0.0067260000 -0.0398919992 +0.0432740003 -0.0067260000 0.0398919992 +0.0432740003 -0.0067260000 0.0351080000 +0.0432740003 -0.0067260000 0.0148919998 +0.0432740003 -0.0067260000 0.0101079997 +0.0432740003 -0.0067260000 -0.0351080000 +0.0432740003 -0.0067260000 -0.0398919992 +0.0432740003 -0.0101079997 0.0432740003 +0.0432740003 -0.0101079997 0.0317259990 +0.0432740003 -0.0101079997 0.0182739999 +0.0432740003 -0.0101079997 0.0067260000 +0.0432740003 -0.0101079997 -0.0067260000 +0.0432740003 -0.0101079997 -0.0432740003 +0.0432740003 -0.0148919998 0.0432740003 +0.0432740003 -0.0148919998 0.0317259990 +0.0432740003 -0.0148919998 0.0182739999 +0.0432740003 -0.0148919998 0.0067260000 +0.0432740003 -0.0148919998 -0.0067260000 +0.0432740003 -0.0148919998 -0.0432740003 +0.0432740003 -0.0182739999 0.0398919992 +0.0432740003 -0.0182739999 0.0351080000 +0.0432740003 -0.0182739999 0.0148919998 +0.0432740003 -0.0182739999 0.0101079997 +0.0432740003 -0.0182739999 -0.0351080000 +0.0432740003 -0.0182739999 -0.0398919992 +0.0432740003 -0.0317259990 0.0398919992 +0.0432740003 -0.0317259990 0.0351080000 +0.0432740003 -0.0317259990 0.0148919998 +0.0432740003 -0.0317259990 0.0101079997 +0.0432740003 -0.0317259990 -0.0101079997 +0.0432740003 -0.0317259990 -0.0148919998 +0.0432740003 -0.0317259990 -0.0351080000 +0.0432740003 -0.0317259990 -0.0398919992 +0.0432740003 -0.0351080000 0.0432740003 +0.0432740003 -0.0351080000 0.0317259990 +0.0432740003 -0.0351080000 0.0182739999 +0.0432740003 -0.0351080000 0.0067260000 +0.0432740003 -0.0351080000 -0.0067260000 +0.0432740003 -0.0351080000 -0.0182739999 +0.0432740003 -0.0351080000 -0.0317259990 +0.0432740003 -0.0351080000 -0.0432740003 +0.0432740003 -0.0398919992 0.0432740003 +0.0432740003 -0.0398919992 0.0317259990 +0.0432740003 -0.0398919992 0.0182739999 +0.0432740003 -0.0398919992 0.0067260000 +0.0432740003 -0.0398919992 -0.0317259990 +0.0432740003 -0.0398919992 -0.0432740003 +0.0432740003 -0.0432740003 0.0398919992 +0.0432740003 -0.0432740003 0.0351080000 +0.0432740003 -0.0432740003 0.0148919998 +0.0432740003 -0.0432740003 0.0101079997 +0.0432740003 -0.0432740003 -0.0351080000 +0.0432740003 -0.0432740003 -0.0398919992 +0.0431560017 0.0401600003 0.0318440013 +0.0431560017 0.0401600003 0.0181559995 +0.0431560017 0.0401600003 0.0068440000 +0.0431560017 0.0401600003 -0.0068440000 +0.0431560017 0.0401600003 -0.0181559995 +0.0431509987 -0.0181510001 -0.0098299999 +0.0431389995 0.0068609999 -0.0098040001 +0.0431389995 -0.0068609999 -0.0098040001 +0.0431360006 0.0212440006 0.0402019992 +0.0431209989 0.0181210004 0.0402319990 +0.0429750010 0.0344859995 -0.0318869986 +0.0429629982 -0.0242110007 -0.0155360000 +0.0429240018 0.0343950018 0.0500000007 +0.0429200009 0.0406120010 0.0500000007 +0.0429130010 0.0500000007 0.0406249985 +0.0429130010 0.0500000007 0.0343750007 +0.0429130010 0.0500000007 0.0156250000 +0.0429130010 0.0500000007 0.0093750004 +0.0429130010 0.0500000007 -0.0093750004 +0.0429130010 0.0500000007 -0.0156250000 +0.0429130010 0.0500000007 -0.0343750007 +0.0429130010 0.0500000007 -0.0406249985 +0.0429130010 0.0406249985 -0.0500000007 +0.0429130010 0.0343750007 -0.0500000007 +0.0429130010 0.0156250000 0.0500000007 +0.0429130010 0.0156250000 -0.0500000007 +0.0429130010 0.0093750004 0.0500000007 +0.0429130010 0.0093750004 -0.0500000007 +0.0429130010 -0.0093750004 0.0500000007 +0.0429130010 -0.0093750004 -0.0500000007 +0.0429130010 -0.0156250000 0.0500000007 +0.0429130010 -0.0156250000 -0.0500000007 +0.0429130010 -0.0343750007 0.0500000007 +0.0429130010 -0.0343750007 -0.0500000007 +0.0429130010 -0.0406249985 0.0500000007 +0.0429130010 -0.0406249985 -0.0500000007 +0.0429130010 -0.0500000007 0.0406249985 +0.0429130010 -0.0500000007 0.0343750007 +0.0429130010 -0.0500000007 0.0156250000 +0.0429130010 -0.0500000007 0.0093750004 +0.0429130010 -0.0500000007 -0.0343750007 +0.0429130010 -0.0500000007 -0.0406249985 +0.0429099984 -0.0406300016 -0.0020020001 +0.0428549983 0.0227760002 0.0407229997 +0.0428370014 0.0321630016 0.0407529995 +0.0427730009 -0.0408550017 -0.0198160000 +0.0427450016 0.0307030007 0.0408979990 +0.0427450016 0.0243749991 0.0408979990 +0.0426970012 0.0426970012 0.0409720019 +0.0426970012 0.0426970012 0.0340280011 +0.0426970012 0.0426970012 0.0159719996 +0.0426970012 0.0426970012 0.0090279998 +0.0426970012 0.0426970012 -0.0090279998 +0.0426970012 0.0426970012 -0.0159719996 +0.0426970012 0.0426970012 -0.0340280011 +0.0426970012 0.0426970012 -0.0409720019 +0.0426970012 0.0409720019 0.0426970012 +0.0426970012 0.0409720019 -0.0323030017 +0.0426970012 0.0409720019 -0.0426970012 +0.0426970012 0.0340280011 0.0426970012 +0.0426970012 0.0340280011 -0.0323030017 +0.0426970012 0.0340280011 -0.0426970012 +0.0426970012 0.0323030017 -0.0340280011 +0.0426970012 0.0323030017 -0.0409720019 +0.0426970012 0.0176970009 -0.0340280011 +0.0426970012 0.0176970009 -0.0409720019 +0.0426970012 0.0159719996 0.0426970012 +0.0426970012 0.0159719996 0.0323030017 +0.0426970012 0.0159719996 0.0176970009 +0.0426970012 0.0159719996 0.0073030000 +0.0426970012 0.0159719996 -0.0073030000 +0.0426970012 0.0159719996 -0.0426970012 +0.0426970012 0.0090279998 0.0426970012 +0.0426970012 0.0090279998 0.0323030017 +0.0426970012 0.0090279998 0.0176970009 +0.0426970012 0.0090279998 0.0073030000 +0.0426970012 0.0090279998 -0.0073030000 +0.0426970012 0.0090279998 -0.0426970012 +0.0426970012 0.0073030000 0.0409720019 +0.0426970012 0.0073030000 0.0340280011 +0.0426970012 0.0073030000 0.0159719996 +0.0426970012 0.0073030000 0.0090279998 +0.0426970012 0.0073030000 -0.0340280011 +0.0426970012 0.0073030000 -0.0409720019 +0.0426970012 -0.0073030000 0.0409720019 +0.0426970012 -0.0073030000 0.0340280011 +0.0426970012 -0.0073030000 0.0159719996 +0.0426970012 -0.0073030000 0.0090279998 +0.0426970012 -0.0073030000 -0.0340280011 +0.0426970012 -0.0073030000 -0.0409720019 +0.0426970012 -0.0090279998 0.0426970012 +0.0426970012 -0.0090279998 0.0323030017 +0.0426970012 -0.0090279998 0.0176970009 +0.0426970012 -0.0090279998 0.0073030000 +0.0426970012 -0.0090279998 -0.0073030000 +0.0426970012 -0.0090279998 -0.0426970012 +0.0426970012 -0.0159719996 0.0426970012 +0.0426970012 -0.0159719996 0.0323030017 +0.0426970012 -0.0159719996 0.0176970009 +0.0426970012 -0.0159719996 0.0073030000 +0.0426970012 -0.0159719996 -0.0073030000 +0.0426970012 -0.0159719996 -0.0426970012 +0.0426970012 -0.0176970009 0.0409720019 +0.0426970012 -0.0176970009 0.0340280011 +0.0426970012 -0.0176970009 0.0159719996 +0.0426970012 -0.0176970009 0.0090279998 +0.0426970012 -0.0176970009 -0.0340280011 +0.0426970012 -0.0176970009 -0.0409720019 +0.0426970012 -0.0323030017 0.0409720019 +0.0426970012 -0.0323030017 0.0340280011 +0.0426970012 -0.0323030017 0.0159719996 +0.0426970012 -0.0323030017 0.0090279998 +0.0426970012 -0.0323030017 -0.0090279998 +0.0426970012 -0.0323030017 -0.0159719996 +0.0426970012 -0.0323030017 -0.0340280011 +0.0426970012 -0.0323030017 -0.0409720019 +0.0426970012 -0.0340280011 0.0426970012 +0.0426970012 -0.0340280011 0.0323030017 +0.0426970012 -0.0340280011 0.0176970009 +0.0426970012 -0.0340280011 0.0073030000 +0.0426970012 -0.0340280011 -0.0073030000 +0.0426970012 -0.0340280011 -0.0176970009 +0.0426970012 -0.0340280011 -0.0323030017 +0.0426970012 -0.0340280011 -0.0426970012 +0.0426970012 -0.0409720019 0.0426970012 +0.0426970012 -0.0409720019 0.0323030017 +0.0426970012 -0.0409720019 0.0176970009 +0.0426970012 -0.0409720019 0.0073030000 +0.0426970012 -0.0409720019 -0.0323030017 +0.0426970012 -0.0409720019 -0.0426970012 +0.0426970012 -0.0426970012 0.0409720019 +0.0426970012 -0.0426970012 0.0340280011 +0.0426970012 -0.0426970012 0.0159719996 +0.0426970012 -0.0426970012 0.0090279998 +0.0426970012 -0.0426970012 -0.0340280011 +0.0426970012 -0.0426970012 -0.0409720019 +0.0426140018 0.0410929993 0.0323860012 +0.0426140018 0.0410929993 0.0176139995 +0.0426140018 0.0410929993 0.0073859999 +0.0426140018 0.0410929993 -0.0073859999 +0.0426140018 0.0410929993 -0.0176139995 +0.0426109992 -0.0176110007 -0.0089020003 +0.0426019989 0.0073980000 -0.0088910004 +0.0426019989 -0.0073980000 -0.0088910004 +0.0425910018 0.0175909996 0.0411260016 +0.0425399989 -0.0245479997 -0.0161969997 +0.0423199981 0.0335219987 -0.0323700011 +0.0422820002 -0.0415240005 -0.0026290000 +0.0420700014 0.0167629998 -0.0329300016 +0.0420700014 0.0082369996 -0.0329300016 +0.0420700014 -0.0082369996 -0.0329300016 +0.0420700014 -0.0167629998 -0.0329300016 +0.0420489982 -0.0417860001 -0.0205400009 +0.0420279987 -0.0247910004 -0.0168079995 +0.0419920012 0.0169920009 0.0331550017 +0.0419920012 0.0169920009 0.0168450009 +0.0419920012 0.0169920009 0.0081550004 +0.0419920012 0.0169920009 -0.0081550004 +0.0419440009 0.0331050009 0.0500000007 +0.0419359989 0.0419030003 0.0500000007 +0.0419190004 0.0500000007 0.0419190004 +0.0419190004 0.0500000007 0.0330809988 +0.0419190004 0.0500000007 0.0169190001 +0.0419190004 0.0500000007 0.0080810003 +0.0419190004 0.0500000007 -0.0080810003 +0.0419190004 0.0500000007 -0.0169190001 +0.0419190004 0.0500000007 -0.0330809988 +0.0419190004 0.0500000007 -0.0419190004 +0.0419190004 0.0419190004 0.0419190004 +0.0419190004 0.0419190004 0.0330809988 +0.0419190004 0.0419190004 0.0169190001 +0.0419190004 0.0419190004 0.0080810003 +0.0419190004 0.0419190004 -0.0080810003 +0.0419190004 0.0419190004 -0.0169190001 +0.0419190004 0.0419190004 -0.0330809988 +0.0419190004 0.0419190004 -0.0419190004 +0.0419190004 0.0419190004 -0.0500000007 +0.0419190004 0.0330809988 0.0419190004 +0.0419190004 0.0330809988 -0.0330809988 +0.0419190004 0.0330809988 -0.0419190004 +0.0419190004 0.0330809988 -0.0500000007 +0.0419190004 0.0169190001 0.0500000007 +0.0419190004 0.0169190001 0.0419190004 +0.0419190004 0.0169190001 0.0330809988 +0.0419190004 0.0169190001 0.0169190001 +0.0419190004 0.0169190001 0.0080810003 +0.0419190004 0.0169190001 -0.0080810003 +0.0419190004 0.0169190001 -0.0330809988 +0.0419190004 0.0169190001 -0.0419190004 +0.0419190004 0.0169190001 -0.0500000007 +0.0419190004 0.0080810003 0.0500000007 +0.0419190004 0.0080810003 0.0419190004 +0.0419190004 0.0080810003 0.0330809988 +0.0419190004 0.0080810003 0.0169190001 +0.0419190004 0.0080810003 0.0080810003 +0.0419190004 0.0080810003 -0.0080810003 +0.0419190004 0.0080810003 -0.0330809988 +0.0419190004 0.0080810003 -0.0419190004 +0.0419190004 0.0080810003 -0.0500000007 +0.0419190004 -0.0080810003 0.0500000007 +0.0419190004 -0.0080810003 0.0419190004 +0.0419190004 -0.0080810003 0.0330809988 +0.0419190004 -0.0080810003 0.0169190001 +0.0419190004 -0.0080810003 0.0080810003 +0.0419190004 -0.0080810003 -0.0080810003 +0.0419190004 -0.0080810003 -0.0330809988 +0.0419190004 -0.0080810003 -0.0419190004 +0.0419190004 -0.0080810003 -0.0500000007 +0.0419190004 -0.0169190001 0.0500000007 +0.0419190004 -0.0169190001 0.0419190004 +0.0419190004 -0.0169190001 0.0330809988 +0.0419190004 -0.0169190001 0.0169190001 +0.0419190004 -0.0169190001 0.0080810003 +0.0419190004 -0.0169190001 -0.0080810003 +0.0419190004 -0.0169190001 -0.0330809988 +0.0419190004 -0.0169190001 -0.0419190004 +0.0419190004 -0.0169190001 -0.0500000007 +0.0419190004 -0.0330809988 0.0500000007 +0.0419190004 -0.0330809988 0.0419190004 +0.0419190004 -0.0330809988 0.0330809988 +0.0419190004 -0.0330809988 0.0169190001 +0.0419190004 -0.0330809988 0.0080810003 +0.0419190004 -0.0330809988 -0.0080810003 +0.0419190004 -0.0330809988 -0.0169190001 +0.0419190004 -0.0330809988 -0.0330809988 +0.0419190004 -0.0330809988 -0.0419190004 +0.0419190004 -0.0330809988 -0.0500000007 +0.0419190004 -0.0419190004 0.0500000007 +0.0419190004 -0.0419190004 0.0419190004 +0.0419190004 -0.0419190004 0.0330809988 +0.0419190004 -0.0419190004 0.0169190001 +0.0419190004 -0.0419190004 0.0080810003 +0.0419190004 -0.0419190004 -0.0330809988 +0.0419190004 -0.0419190004 -0.0419190004 +0.0419190004 -0.0419190004 -0.0500000007 +0.0419190004 -0.0500000007 0.0419190004 +0.0419190004 -0.0500000007 0.0330809988 +0.0419190004 -0.0500000007 0.0169190001 +0.0419190004 -0.0500000007 0.0080810003 +0.0419190004 -0.0500000007 -0.0330809988 +0.0419190004 -0.0500000007 -0.0419190004 +0.0418450013 0.0169920009 0.0330080017 +0.0418450013 0.0169920009 0.0169920009 +0.0418450013 0.0169920009 0.0080080004 +0.0418450013 0.0169920009 -0.0080080004 +0.0417630002 0.0307030007 -0.0329300016 +0.0417630002 0.0170699991 -0.0329300016 +0.0417630002 0.0079300003 -0.0329300016 +0.0417630002 -0.0079300003 -0.0329300016 +0.0417630002 -0.0170699991 -0.0329300016 +0.0417630002 -0.0178120006 -0.0329300016 +0.0417010002 -0.0187279992 -0.0328730009 +0.0416910015 0.0316909999 -0.0328629985 +0.0415100008 -0.0422939993 -0.0034020001 +0.0415030010 -0.0196390003 -0.0326999985 +0.0414600000 0.0326640010 -0.0326640010 +0.0414209999 -0.0249589998 -0.0173669998 +0.0411720015 -0.0204489995 -0.0324429981 +0.0411639996 -0.0425640009 -0.0214249995 +0.0411499999 0.0324259996 0.0425739996 +0.0409720019 0.0426970012 0.0426970012 +0.0409720019 0.0426970012 0.0323030017 +0.0409720019 0.0426970012 0.0176970009 +0.0409720019 0.0426970012 0.0073030000 +0.0409720019 0.0426970012 -0.0073030000 +0.0409720019 0.0426970012 -0.0176970009 +0.0409720019 0.0426970012 -0.0323030017 +0.0409720019 0.0426970012 -0.0426970012 +0.0409720019 0.0323030017 -0.0426970012 +0.0409720019 0.0176970009 0.0426970012 +0.0409720019 0.0176970009 -0.0426970012 +0.0409720019 0.0073030000 0.0426970012 +0.0409720019 0.0073030000 0.0323030017 +0.0409720019 0.0073030000 0.0176970009 +0.0409720019 0.0073030000 0.0073030000 +0.0409720019 0.0073030000 -0.0073030000 +0.0409720019 0.0073030000 -0.0426970012 +0.0409720019 -0.0073030000 0.0426970012 +0.0409720019 -0.0073030000 0.0323030017 +0.0409720019 -0.0073030000 0.0176970009 +0.0409720019 -0.0073030000 0.0073030000 +0.0409720019 -0.0073030000 -0.0073030000 +0.0409720019 -0.0073030000 -0.0426970012 +0.0409720019 -0.0176970009 0.0426970012 +0.0409720019 -0.0176970009 0.0323030017 +0.0409720019 -0.0176970009 0.0176970009 +0.0409720019 -0.0176970009 0.0073030000 +0.0409720019 -0.0176970009 -0.0073030000 +0.0409720019 -0.0176970009 -0.0426970012 +0.0409720019 -0.0323030017 0.0426970012 +0.0409720019 -0.0323030017 0.0323030017 +0.0409720019 -0.0323030017 0.0176970009 +0.0409720019 -0.0323030017 0.0073030000 +0.0409720019 -0.0323030017 -0.0073030000 +0.0409720019 -0.0323030017 -0.0176970009 +0.0409720019 -0.0323030017 -0.0323030017 +0.0409720019 -0.0323030017 -0.0426970012 +0.0409720019 -0.0426970012 0.0426970012 +0.0409720019 -0.0426970012 0.0323030017 +0.0409720019 -0.0426970012 0.0176970009 +0.0409720019 -0.0426970012 0.0073030000 +0.0409720019 -0.0426970012 -0.0323030017 +0.0409720019 -0.0426970012 -0.0426970012 +0.0407299995 -0.0250669997 -0.0178510007 +0.0406729989 -0.0211830009 -0.0321150012 +0.0406650007 0.0321110003 0.0500000007 +0.0406519994 0.0428970009 0.0500000007 +0.0406249985 0.0500000007 0.0429130010 +0.0406249985 0.0500000007 0.0320869982 +0.0406249985 0.0500000007 0.0179130007 +0.0406249985 0.0500000007 0.0070870002 +0.0406249985 0.0500000007 -0.0070870002 +0.0406249985 0.0500000007 -0.0179130007 +0.0406249985 0.0500000007 -0.0320869982 +0.0406249985 0.0500000007 -0.0429130010 +0.0406249985 0.0429130010 -0.0500000007 +0.0406249985 0.0320869982 -0.0500000007 +0.0406249985 0.0179130007 0.0500000007 +0.0406249985 0.0179130007 -0.0500000007 +0.0406249985 0.0070870002 0.0500000007 +0.0406249985 0.0070870002 -0.0500000007 +0.0406249985 -0.0070870002 0.0500000007 +0.0406249985 -0.0070870002 -0.0500000007 +0.0406249985 -0.0179130007 0.0500000007 +0.0406249985 -0.0179130007 -0.0500000007 +0.0406249985 -0.0320869982 0.0500000007 +0.0406249985 -0.0320869982 -0.0500000007 +0.0406249985 -0.0429130010 0.0500000007 +0.0406249985 -0.0429130010 -0.0500000007 +0.0406249985 -0.0500000007 0.0429130010 +0.0406249985 -0.0500000007 0.0320869982 +0.0406249985 -0.0500000007 0.0179130007 +0.0406249985 -0.0500000007 0.0070870002 +0.0406249985 -0.0500000007 -0.0320869982 +0.0406249985 -0.0500000007 -0.0429130010 +0.0406140015 -0.0429189987 -0.0042969999 +0.0402849987 0.0319049992 0.0430950001 +0.0401480012 -0.0431619994 -0.0224409997 +0.0400439985 -0.0217509996 -0.0317910016 +0.0399719998 -0.0251300000 -0.0182399992 +0.0398919992 0.0432740003 0.0432740003 +0.0398919992 0.0432740003 0.0317259990 +0.0398919992 0.0432740003 0.0182739999 +0.0398919992 0.0432740003 0.0067260000 +0.0398919992 0.0432740003 -0.0067260000 +0.0398919992 0.0432740003 -0.0182739999 +0.0398919992 0.0432740003 -0.0317259990 +0.0398919992 0.0432740003 -0.0432740003 +0.0398919992 0.0317259990 -0.0432740003 +0.0398919992 0.0182739999 0.0432740003 +0.0398919992 0.0182739999 -0.0432740003 +0.0398919992 0.0067260000 0.0432740003 +0.0398919992 0.0067260000 0.0317259990 +0.0398919992 0.0067260000 0.0182739999 +0.0398919992 0.0067260000 0.0067260000 +0.0398919992 0.0067260000 -0.0067260000 +0.0398919992 0.0067260000 -0.0432740003 +0.0398919992 -0.0067260000 0.0432740003 +0.0398919992 -0.0067260000 0.0317259990 +0.0398919992 -0.0067260000 0.0182739999 +0.0398919992 -0.0067260000 0.0067260000 +0.0398919992 -0.0067260000 -0.0067260000 +0.0398919992 -0.0067260000 -0.0432740003 +0.0398919992 -0.0182739999 0.0432740003 +0.0398919992 -0.0182739999 0.0317259990 +0.0398919992 -0.0182739999 0.0182739999 +0.0398919992 -0.0182739999 0.0067260000 +0.0398919992 -0.0182739999 -0.0067260000 +0.0398919992 -0.0182739999 -0.0432740003 +0.0398919992 -0.0317259990 0.0432740003 +0.0398919992 -0.0317259990 0.0317259990 +0.0398919992 -0.0317259990 0.0182739999 +0.0398919992 -0.0317259990 0.0067260000 +0.0398919992 -0.0317259990 -0.0067260000 +0.0398919992 -0.0317259990 -0.0182739999 +0.0398919992 -0.0317259990 -0.0317259990 +0.0398919992 -0.0317259990 -0.0432740003 +0.0398919992 -0.0432740003 0.0432740003 +0.0398919992 -0.0432740003 0.0317259990 +0.0398919992 -0.0432740003 0.0182739999 +0.0398919992 -0.0432740003 0.0067260000 +0.0398919992 -0.0432740003 -0.0317259990 +0.0398919992 -0.0432740003 -0.0432740003 +0.0396240018 -0.0433779992 -0.0052870000 +0.0393470004 0.0315289982 0.0434710011 +0.0392730013 -0.0221699998 -0.0315070003 +0.0391729996 0.0314779989 0.0500000007 +0.0391659997 -0.0251630004 -0.0185240004 +0.0391549990 0.0435269997 0.0500000007 +0.0391179994 0.0500000007 0.0435369983 +0.0391179994 0.0500000007 0.0314630009 +0.0391179994 0.0500000007 0.0185369998 +0.0391179994 0.0500000007 0.0064630001 +0.0391179994 0.0500000007 -0.0064630001 +0.0391179994 0.0500000007 -0.0185369998 +0.0391179994 0.0500000007 -0.0314630009 +0.0391179994 0.0500000007 -0.0435369983 +0.0391179994 0.0435369983 -0.0500000007 +0.0391179994 0.0314630009 -0.0500000007 +0.0391179994 0.0185369998 0.0500000007 +0.0391179994 0.0185369998 -0.0500000007 +0.0391179994 0.0064630001 0.0500000007 +0.0391179994 0.0064630001 -0.0500000007 +0.0391179994 -0.0064630001 0.0500000007 +0.0391179994 -0.0064630001 -0.0500000007 +0.0391179994 -0.0185369998 0.0500000007 +0.0391179994 -0.0185369998 -0.0500000007 +0.0391179994 -0.0314630009 0.0500000007 +0.0391179994 -0.0314630009 -0.0500000007 +0.0391179994 -0.0435369983 0.0500000007 +0.0391179994 -0.0435369983 -0.0500000007 +0.0391179994 -0.0500000007 0.0435369983 +0.0391179994 -0.0500000007 0.0314630009 +0.0391179994 -0.0500000007 0.0185369998 +0.0391179994 -0.0500000007 0.0064630001 +0.0391179994 -0.0500000007 -0.0314630009 +0.0391179994 -0.0500000007 -0.0435369983 +0.0390370004 -0.0435580015 -0.0235510003 +0.0387189984 0.0436300002 0.0436300002 +0.0387189984 0.0436300002 0.0313699991 +0.0387189984 0.0436300002 0.0186299998 +0.0387189984 0.0436300002 0.0063700001 +0.0387189984 0.0436300002 -0.0063700001 +0.0387189984 0.0436300002 -0.0186299998 +0.0387189984 0.0436300002 -0.0313699991 +0.0387189984 0.0436300002 -0.0436300002 +0.0387189984 0.0313699991 -0.0436300002 +0.0387189984 0.0186299998 0.0436300002 +0.0387189984 0.0186299998 -0.0436300002 +0.0387189984 0.0063700001 0.0436300002 +0.0387189984 0.0063700001 0.0313699991 +0.0387189984 0.0063700001 0.0186299998 +0.0387189984 0.0063700001 0.0063700001 +0.0387189984 0.0063700001 -0.0063700001 +0.0387189984 0.0063700001 -0.0436300002 +0.0387189984 -0.0063700001 0.0436300002 +0.0387189984 -0.0063700001 0.0313699991 +0.0387189984 -0.0063700001 0.0186299998 +0.0387189984 -0.0063700001 0.0063700001 +0.0387189984 -0.0063700001 -0.0063700001 +0.0387189984 -0.0063700001 -0.0436300002 +0.0387189984 -0.0186299998 0.0436300002 +0.0387189984 -0.0186299998 0.0313699991 +0.0387189984 -0.0186299998 0.0186299998 +0.0387189984 -0.0186299998 0.0063700001 +0.0387189984 -0.0186299998 -0.0063700001 +0.0387189984 -0.0186299998 -0.0436300002 +0.0387189984 -0.0313699991 0.0436300002 +0.0387189984 -0.0313699991 0.0313699991 +0.0387189984 -0.0313699991 0.0186299998 +0.0387189984 -0.0313699991 0.0063700001 +0.0387189984 -0.0313699991 -0.0063700001 +0.0387189984 -0.0313699991 -0.0186299998 +0.0387189984 -0.0313699991 -0.0313699991 +0.0387189984 -0.0313699991 -0.0436300002 +0.0387189984 -0.0436300002 0.0436300002 +0.0387189984 -0.0436300002 0.0313699991 +0.0387189984 -0.0436300002 0.0186299998 +0.0387189984 -0.0436300002 0.0063700001 +0.0387189984 -0.0436300002 -0.0313699991 +0.0387189984 -0.0436300002 -0.0436300002 +0.0385689996 -0.0436579995 -0.0063419999 +0.0385689996 -0.0500000007 -0.0063419999 +0.0383989997 -0.0224210005 -0.0313149989 +0.0383620001 0.0313099995 0.0436899997 +0.0383340009 -0.0251770001 -0.0186940003 +0.0381130017 0.0437199995 0.0437199995 +0.0381130017 0.0437199995 0.0312799998 +0.0381130017 0.0437199995 0.0187199991 +0.0381130017 0.0437199995 0.0062799999 +0.0381130017 0.0437199995 -0.0062799999 +0.0381130017 0.0437199995 -0.0187199991 +0.0381130017 0.0437199995 -0.0312799998 +0.0381130017 0.0437199995 -0.0437199995 +0.0381130017 0.0312799998 -0.0437199995 +0.0381130017 0.0187199991 0.0437199995 +0.0381130017 0.0187199991 -0.0437199995 +0.0381130017 0.0062799999 0.0437199995 +0.0381130017 0.0062799999 0.0312799998 +0.0381130017 0.0062799999 0.0187199991 +0.0381130017 0.0062799999 0.0062799999 +0.0381130017 0.0062799999 -0.0062799999 +0.0381130017 0.0062799999 -0.0437199995 +0.0381130017 -0.0062799999 0.0437199995 +0.0381130017 -0.0062799999 0.0312799998 +0.0381130017 -0.0062799999 0.0187199991 +0.0381130017 -0.0062799999 0.0062799999 +0.0381130017 -0.0062799999 -0.0062799999 +0.0381130017 -0.0062799999 -0.0437199995 +0.0381130017 -0.0187199991 0.0437199995 +0.0381130017 -0.0187199991 0.0312799998 +0.0381130017 -0.0187199991 0.0187199991 +0.0381130017 -0.0187199991 0.0062799999 +0.0381130017 -0.0187199991 -0.0062799999 +0.0381130017 -0.0187199991 -0.0437199995 +0.0381130017 -0.0312799998 0.0437199995 +0.0381130017 -0.0312799998 0.0312799998 +0.0381130017 -0.0312799998 0.0187199991 +0.0381130017 -0.0312799998 0.0062799999 +0.0381130017 -0.0312799998 -0.0062799999 +0.0381130017 -0.0312799998 -0.0187199991 +0.0381130017 -0.0312799998 -0.0312799998 +0.0381130017 -0.0312799998 -0.0437199995 +0.0381130017 -0.0437199995 0.0437199995 +0.0381130017 -0.0437199995 0.0312799998 +0.0381130017 -0.0437199995 0.0187199991 +0.0381130017 -0.0437199995 0.0062799999 +0.0381130017 -0.0437199995 -0.0312799998 +0.0381130017 -0.0437199995 -0.0437199995 +0.0378729999 -0.0437389985 -0.0247159991 +0.0378260016 -0.0437409990 -0.0062589999 +0.0375690013 0.0312500000 0.0500000007 +0.0375460014 0.0437499993 0.0500000007 +0.0375000015 0.0500000007 0.0437499993 +0.0375000015 0.0500000007 0.0312500000 +0.0375000015 0.0500000007 0.0187500007 +0.0375000015 0.0500000007 0.0062500001 +0.0375000015 0.0500000007 -0.0062500001 +0.0375000015 0.0500000007 -0.0187500007 +0.0375000015 0.0500000007 -0.0312500000 +0.0375000015 0.0500000007 -0.0437499993 +0.0375000015 0.0437499993 0.0437499993 +0.0375000015 0.0437499993 0.0312500000 +0.0375000015 0.0437499993 0.0187500007 +0.0375000015 0.0437499993 0.0062500001 +0.0375000015 0.0437499993 -0.0062500001 +0.0375000015 0.0437499993 -0.0187500007 +0.0375000015 0.0437499993 -0.0312500000 +0.0375000015 0.0437499993 -0.0437499993 +0.0375000015 0.0437499993 -0.0500000007 +0.0375000015 0.0312500000 -0.0437499993 +0.0375000015 0.0312500000 -0.0500000007 +0.0375000015 0.0187500007 0.0500000007 +0.0375000015 0.0187500007 0.0437499993 +0.0375000015 0.0187500007 -0.0437499993 +0.0375000015 0.0187500007 -0.0500000007 +0.0375000015 0.0062500001 0.0500000007 +0.0375000015 0.0062500001 0.0437499993 +0.0375000015 0.0062500001 0.0312500000 +0.0375000015 0.0062500001 0.0187500007 +0.0375000015 0.0062500001 0.0062500001 +0.0375000015 0.0062500001 -0.0062500001 +0.0375000015 0.0062500001 -0.0437499993 +0.0375000015 0.0062500001 -0.0500000007 +0.0375000015 -0.0062500001 0.0500000007 +0.0375000015 -0.0062500001 0.0437499993 +0.0375000015 -0.0062500001 0.0312500000 +0.0375000015 -0.0062500001 0.0187500007 +0.0375000015 -0.0062500001 0.0062500001 +0.0375000015 -0.0062500001 -0.0062500001 +0.0375000015 -0.0062500001 -0.0437499993 +0.0375000015 -0.0062500001 -0.0500000007 +0.0375000015 -0.0187500007 0.0500000007 +0.0375000015 -0.0187500007 0.0437499993 +0.0375000015 -0.0187500007 0.0312500000 +0.0375000015 -0.0187500007 0.0187500007 +0.0375000015 -0.0187500007 0.0062500001 +0.0375000015 -0.0187500007 -0.0062500001 +0.0375000015 -0.0187500007 -0.0437499993 +0.0375000015 -0.0187500007 -0.0500000007 +0.0375000015 -0.0225009993 -0.0312500000 +0.0375000015 -0.0251800008 -0.0187500007 +0.0375000015 -0.0312500000 0.0500000007 +0.0375000015 -0.0312500000 0.0437499993 +0.0375000015 -0.0312500000 0.0312500000 +0.0375000015 -0.0312500000 0.0187500007 +0.0375000015 -0.0312500000 0.0062500001 +0.0375000015 -0.0312500000 -0.0062500001 +0.0375000015 -0.0312500000 -0.0187500007 +0.0375000015 -0.0312500000 -0.0312500000 +0.0375000015 -0.0312500000 -0.0437499993 +0.0375000015 -0.0312500000 -0.0500000007 +0.0375000015 -0.0437499993 0.0500000007 +0.0375000015 -0.0437499993 0.0437499993 +0.0375000015 -0.0437499993 0.0312500000 +0.0375000015 -0.0437499993 0.0187500007 +0.0375000015 -0.0437499993 0.0062500001 +0.0375000015 -0.0437499993 -0.0312500000 +0.0375000015 -0.0437499993 -0.0437499993 +0.0375000015 -0.0437499993 -0.0500000007 +0.0375000015 -0.0500000007 0.0437499993 +0.0375000015 -0.0500000007 0.0312500000 +0.0375000015 -0.0500000007 0.0187500007 +0.0375000015 -0.0500000007 0.0062500001 +0.0375000015 -0.0500000007 -0.0312500000 +0.0375000015 -0.0500000007 -0.0437499993 +0.0373530015 0.0312520005 0.0437479988 +0.0372780003 0.0255820006 0.0500000007 +0.0372640006 0.0251700003 0.0437459983 +0.0372340009 0.0263030007 0.0437440015 +0.0370789990 0.0270990003 0.0500000007 +0.0370789990 0.0240659993 0.0500000007 +0.0370789990 -0.0437359996 -0.0062640002 +0.0370789990 -0.0500000007 -0.0062640002 +0.0370679982 0.0240279995 0.0437350012 +0.0369759984 0.0274410006 0.0437280014 +0.0368870012 0.0437199995 0.0437199995 +0.0368870012 0.0437199995 0.0312799998 +0.0368870012 0.0437199995 0.0187199991 +0.0368870012 0.0437199995 0.0062799999 +0.0368870012 0.0437199995 -0.0062799999 +0.0368870012 0.0437199995 -0.0187199991 +0.0368870012 0.0437199995 -0.0312799998 +0.0368870012 0.0437199995 -0.0437199995 +0.0368870012 0.0312799998 -0.0437199995 +0.0368870012 0.0187199991 0.0437199995 +0.0368870012 0.0187199991 -0.0437199995 +0.0368870012 0.0062799999 0.0437199995 +0.0368870012 0.0062799999 0.0312799998 +0.0368870012 0.0062799999 0.0187199991 +0.0368870012 0.0062799999 0.0062799999 +0.0368870012 0.0062799999 -0.0062799999 +0.0368870012 0.0062799999 -0.0437199995 +0.0368870012 -0.0062799999 0.0437199995 +0.0368870012 -0.0062799999 0.0312799998 +0.0368870012 -0.0062799999 0.0187199991 +0.0368870012 -0.0062799999 0.0062799999 +0.0368870012 -0.0062799999 -0.0062799999 +0.0368870012 -0.0062799999 -0.0437199995 +0.0368870012 -0.0187199991 0.0437199995 +0.0368870012 -0.0187199991 0.0312799998 +0.0368870012 -0.0187199991 0.0187199991 +0.0368870012 -0.0187199991 0.0062799999 +0.0368870012 -0.0187199991 -0.0062799999 +0.0368870012 -0.0187199991 -0.0437199995 +0.0368870012 -0.0312799998 0.0437199995 +0.0368870012 -0.0312799998 0.0312799998 +0.0368870012 -0.0312799998 0.0187199991 +0.0368870012 -0.0312799998 0.0062799999 +0.0368870012 -0.0312799998 -0.0062799999 +0.0368870012 -0.0312799998 -0.0187199991 +0.0368870012 -0.0312799998 -0.0312799998 +0.0368870012 -0.0312799998 -0.0437199995 +0.0368870012 -0.0437199995 0.0437199995 +0.0368870012 -0.0437199995 0.0312799998 +0.0368870012 -0.0437199995 0.0187199991 +0.0368870012 -0.0437199995 0.0062799999 +0.0368870012 -0.0437199995 -0.0312799998 +0.0368870012 -0.0437199995 -0.0437199995 +0.0366940014 -0.0436980017 -0.0258939993 +0.0366659984 -0.0251770001 -0.0186940003 +0.0366440006 0.0229310002 0.0436910018 +0.0366009995 -0.0224210005 -0.0313149989 +0.0364929996 0.0285119992 0.0500000007 +0.0364929996 0.0285119992 0.0436679982 +0.0364929996 0.0226520002 0.0500000007 +0.0363489985 0.0313570015 0.0436430015 +0.0363369994 -0.0436410010 -0.0063590002 +0.0362810008 0.0436300002 0.0436300002 +0.0362810008 0.0436300002 0.0313699991 +0.0362810008 0.0436300002 0.0186299998 +0.0362810008 0.0436300002 0.0063700001 +0.0362810008 0.0436300002 -0.0063700001 +0.0362810008 0.0436300002 -0.0186299998 +0.0362810008 0.0436300002 -0.0313699991 +0.0362810008 0.0436300002 -0.0436300002 +0.0362810008 0.0313699991 -0.0436300002 +0.0362810008 0.0186299998 0.0436300002 +0.0362810008 0.0186299998 -0.0436300002 +0.0362810008 0.0063700001 0.0436300002 +0.0362810008 0.0063700001 0.0313699991 +0.0362810008 0.0063700001 0.0186299998 +0.0362810008 0.0063700001 0.0063700001 +0.0362810008 0.0063700001 -0.0063700001 +0.0362810008 0.0063700001 -0.0436300002 +0.0362810008 -0.0063700001 0.0436300002 +0.0362810008 -0.0063700001 0.0313699991 +0.0362810008 -0.0063700001 0.0186299998 +0.0362810008 -0.0063700001 0.0063700001 +0.0362810008 -0.0063700001 -0.0063700001 +0.0362810008 -0.0063700001 -0.0436300002 +0.0362810008 -0.0186299998 0.0436300002 +0.0362810008 -0.0186299998 0.0313699991 +0.0362810008 -0.0186299998 0.0186299998 +0.0362810008 -0.0186299998 0.0063700001 +0.0362810008 -0.0186299998 -0.0063700001 +0.0362810008 -0.0186299998 -0.0436300002 +0.0362810008 -0.0313699991 0.0436300002 +0.0362810008 -0.0313699991 0.0313699991 +0.0362810008 -0.0313699991 0.0186299998 +0.0362810008 -0.0313699991 0.0063700001 +0.0362810008 -0.0313699991 -0.0063700001 +0.0362810008 -0.0313699991 -0.0186299998 +0.0362810008 -0.0313699991 -0.0313699991 +0.0362810008 -0.0313699991 -0.0436300002 +0.0362810008 -0.0436300002 0.0436300002 +0.0362810008 -0.0436300002 0.0313699991 +0.0362810008 -0.0436300002 0.0186299998 +0.0362810008 -0.0436300002 0.0063700001 +0.0362810008 -0.0436300002 -0.0313699991 +0.0362810008 -0.0436300002 -0.0436300002 +0.0360210016 0.0219550002 0.0435720012 +0.0359609984 0.0314429998 0.0500000007 +0.0359349996 0.0435510017 0.0500000007 +0.0358819999 0.0500000007 0.0435369983 +0.0358819999 0.0500000007 0.0314630009 +0.0358819999 0.0500000007 0.0185369998 +0.0358819999 0.0500000007 0.0064630001 +0.0358819999 0.0500000007 -0.0064630001 +0.0358819999 0.0500000007 -0.0185369998 +0.0358819999 0.0500000007 -0.0314630009 +0.0358819999 0.0500000007 -0.0435369983 +0.0358819999 0.0435369983 -0.0500000007 +0.0358819999 0.0314630009 -0.0500000007 +0.0358819999 0.0185369998 0.0500000007 +0.0358819999 0.0185369998 -0.0500000007 +0.0358819999 0.0064630001 0.0500000007 +0.0358819999 0.0064630001 -0.0500000007 +0.0358819999 -0.0064630001 0.0500000007 +0.0358819999 -0.0064630001 -0.0500000007 +0.0358819999 -0.0185369998 0.0500000007 +0.0358819999 -0.0185369998 -0.0500000007 +0.0358819999 -0.0314630009 0.0500000007 +0.0358819999 -0.0314630009 -0.0500000007 +0.0358819999 -0.0435369983 0.0500000007 +0.0358819999 -0.0435369983 -0.0500000007 +0.0358819999 -0.0500000007 0.0435369983 +0.0358819999 -0.0500000007 0.0314630009 +0.0358819999 -0.0500000007 0.0185369998 +0.0358819999 -0.0500000007 0.0064630001 +0.0358819999 -0.0500000007 -0.0314630009 +0.0358819999 -0.0500000007 -0.0435369983 +0.0358339995 -0.0251630004 -0.0185240004 +0.0357270017 -0.0221699998 -0.0315070003 +0.0356130004 -0.0434579998 -0.0065420000 +0.0356130004 -0.0500000007 -0.0065420000 +0.0355620012 0.0214389991 0.0500000007 +0.0355449989 -0.0434359983 -0.0270440001 +0.0353740007 0.0316229984 0.0433770008 +0.0352550000 0.0211529993 0.0433330014 +0.0351080000 0.0432740003 0.0432740003 +0.0351080000 0.0432740003 0.0317259990 +0.0351080000 0.0432740003 0.0182739999 +0.0351080000 0.0432740003 0.0067260000 +0.0351080000 0.0432740003 -0.0067260000 +0.0351080000 0.0432740003 -0.0182739999 +0.0351080000 0.0432740003 -0.0317259990 +0.0351080000 0.0432740003 -0.0432740003 +0.0351080000 0.0317259990 -0.0432740003 +0.0351080000 0.0182739999 0.0432740003 +0.0351080000 0.0182739999 -0.0432740003 +0.0351080000 0.0067260000 0.0432740003 +0.0351080000 0.0067260000 0.0317259990 +0.0351080000 0.0067260000 0.0182739999 +0.0351080000 0.0067260000 0.0067260000 +0.0351080000 0.0067260000 -0.0067260000 +0.0351080000 0.0067260000 -0.0432740003 +0.0351080000 -0.0067260000 0.0432740003 +0.0351080000 -0.0067260000 0.0317259990 +0.0351080000 -0.0067260000 0.0182739999 +0.0351080000 -0.0067260000 0.0067260000 +0.0351080000 -0.0067260000 -0.0067260000 +0.0351080000 -0.0067260000 -0.0432740003 +0.0351080000 -0.0182739999 0.0432740003 +0.0351080000 -0.0182739999 0.0317259990 +0.0351080000 -0.0182739999 0.0182739999 +0.0351080000 -0.0182739999 0.0067260000 +0.0351080000 -0.0182739999 -0.0067260000 +0.0351080000 -0.0182739999 -0.0432740003 +0.0351080000 -0.0317259990 0.0432740003 +0.0351080000 -0.0317259990 0.0317259990 +0.0351080000 -0.0317259990 0.0182739999 +0.0351080000 -0.0317259990 0.0067260000 +0.0351080000 -0.0317259990 -0.0067260000 +0.0351080000 -0.0317259990 -0.0182739999 +0.0351080000 -0.0317259990 -0.0317259990 +0.0351080000 -0.0317259990 -0.0432740003 +0.0351080000 -0.0432740003 0.0432740003 +0.0351080000 -0.0432740003 0.0317259990 +0.0351080000 -0.0432740003 0.0182739999 +0.0351080000 -0.0432740003 0.0067260000 +0.0351080000 -0.0432740003 -0.0317259990 +0.0351080000 -0.0432740003 -0.0432740003 +0.0350279994 -0.0251300000 -0.0182399992 +0.0349560007 -0.0217509996 -0.0317910016 +0.0349150002 -0.0431899987 -0.0068100002 +0.0344650000 -0.0429640003 -0.0281240009 +0.0344550014 0.0320420004 0.0500000007 +0.0344550014 0.0320420004 0.0429579988 +0.0344289988 0.0429430008 0.0500000007 +0.0343750007 0.0500000007 0.0429130010 +0.0343750007 0.0500000007 0.0320869982 +0.0343750007 0.0500000007 0.0179130007 +0.0343750007 0.0500000007 0.0070870002 +0.0343750007 0.0500000007 -0.0070870002 +0.0343750007 0.0500000007 -0.0179130007 +0.0343750007 0.0500000007 -0.0320869982 +0.0343750007 0.0500000007 -0.0429130010 +0.0343750007 0.0429130010 -0.0500000007 +0.0343750007 0.0320869982 -0.0500000007 +0.0343750007 0.0179130007 0.0500000007 +0.0343750007 0.0179130007 -0.0500000007 +0.0343750007 0.0070870002 0.0500000007 +0.0343750007 0.0070870002 -0.0500000007 +0.0343750007 -0.0070870002 0.0500000007 +0.0343750007 -0.0070870002 -0.0500000007 +0.0343750007 -0.0179130007 0.0500000007 +0.0343750007 -0.0179130007 -0.0500000007 +0.0343750007 -0.0320869982 0.0500000007 +0.0343750007 -0.0320869982 -0.0500000007 +0.0343750007 -0.0429130010 0.0500000007 +0.0343750007 -0.0429130010 -0.0500000007 +0.0343750007 -0.0500000007 0.0429130010 +0.0343750007 -0.0500000007 0.0320869982 +0.0343750007 -0.0500000007 0.0179130007 +0.0343750007 -0.0500000007 0.0070870002 +0.0343750007 -0.0500000007 -0.0320869982 +0.0343750007 -0.0500000007 -0.0429130010 +0.0343489982 0.0205080006 0.0500000007 +0.0343489982 0.0205080006 0.0428970009 +0.0343270004 -0.0211830009 -0.0321150012 +0.0342699997 -0.0250669997 -0.0178510007 +0.0342539996 -0.0428409986 -0.0071589998 +0.0342539996 -0.0500000007 -0.0071589998 +0.0340280011 0.0426970012 0.0426970012 +0.0340280011 0.0426970012 0.0323030017 +0.0340280011 0.0426970012 0.0176970009 +0.0340280011 0.0426970012 0.0073030000 +0.0340280011 0.0426970012 -0.0073030000 +0.0340280011 0.0426970012 -0.0176970009 +0.0340280011 0.0426970012 -0.0323030017 +0.0340280011 0.0426970012 -0.0426970012 +0.0340280011 0.0323030017 -0.0426970012 +0.0340280011 0.0176970009 0.0426970012 +0.0340280011 0.0176970009 -0.0426970012 +0.0340280011 0.0073030000 0.0426970012 +0.0340280011 0.0073030000 0.0323030017 +0.0340280011 0.0073030000 0.0176970009 +0.0340280011 0.0073030000 0.0073030000 +0.0340280011 0.0073030000 -0.0073030000 +0.0340280011 0.0073030000 -0.0426970012 +0.0340280011 -0.0073030000 0.0426970012 +0.0340280011 -0.0073030000 0.0323030017 +0.0340280011 -0.0073030000 0.0176970009 +0.0340280011 -0.0073030000 0.0073030000 +0.0340280011 -0.0073030000 -0.0073030000 +0.0340280011 -0.0073030000 -0.0426970012 +0.0340280011 -0.0176970009 0.0426970012 +0.0340280011 -0.0176970009 0.0323030017 +0.0340280011 -0.0176970009 0.0176970009 +0.0340280011 -0.0176970009 0.0073030000 +0.0340280011 -0.0176970009 -0.0073030000 +0.0340280011 -0.0176970009 -0.0426970012 +0.0340280011 -0.0323030017 0.0426970012 +0.0340280011 -0.0323030017 0.0323030017 +0.0340280011 -0.0323030017 0.0176970009 +0.0340280011 -0.0323030017 0.0073030000 +0.0340280011 -0.0323030017 -0.0073030000 +0.0340280011 -0.0323030017 -0.0176970009 +0.0340280011 -0.0323030017 -0.0323030017 +0.0340280011 -0.0323030017 -0.0426970012 +0.0340280011 -0.0426970012 0.0426970012 +0.0340280011 -0.0426970012 0.0323030017 +0.0340280011 -0.0426970012 0.0176970009 +0.0340280011 -0.0426970012 0.0073030000 +0.0340280011 -0.0426970012 -0.0323030017 +0.0340280011 -0.0426970012 -0.0426970012 +0.0338280015 -0.0204489995 -0.0324429981 +0.0335789993 -0.0249589998 -0.0173669998 +0.0335399993 0.0326640010 -0.0326640010 +0.0334969983 -0.0196390003 -0.0326999985 +0.0334930010 -0.0422969982 -0.0290959999 +0.0333090015 0.0316909999 -0.0328629985 +0.0332989991 -0.0187279992 -0.0328730009 +0.0332369991 0.0307030007 -0.0329300016 +0.0332369991 0.0170699991 -0.0329300016 +0.0332369991 0.0079300003 -0.0329300016 +0.0332369991 -0.0079300003 -0.0329300016 +0.0332369991 -0.0170699991 -0.0329300016 +0.0332369991 -0.0178120006 -0.0329300016 +0.0332069993 0.0198490005 0.0420419984 +0.0331550017 0.0169920009 0.0330080017 +0.0331550017 0.0169920009 0.0169920009 +0.0331550017 0.0169920009 0.0080080004 +0.0331550017 0.0169920009 -0.0080080004 +0.0331300013 0.0419679992 0.0500000007 +0.0330809988 0.0500000007 0.0419190004 +0.0330809988 0.0500000007 0.0330809988 +0.0330809988 0.0500000007 0.0169190001 +0.0330809988 0.0500000007 0.0080810003 +0.0330809988 0.0500000007 -0.0080810003 +0.0330809988 0.0500000007 -0.0169190001 +0.0330809988 0.0500000007 -0.0330809988 +0.0330809988 0.0500000007 -0.0419190004 +0.0330809988 0.0419190004 0.0419190004 +0.0330809988 0.0419190004 0.0330809988 +0.0330809988 0.0419190004 0.0169190001 +0.0330809988 0.0419190004 0.0080810003 +0.0330809988 0.0419190004 -0.0080810003 +0.0330809988 0.0419190004 -0.0169190001 +0.0330809988 0.0419190004 -0.0330809988 +0.0330809988 0.0419190004 -0.0419190004 +0.0330809988 0.0419190004 -0.0500000007 +0.0330809988 0.0330809988 -0.0330809988 +0.0330809988 0.0330809988 -0.0419190004 +0.0330809988 0.0330809988 -0.0500000007 +0.0330809988 0.0169190001 0.0500000007 +0.0330809988 0.0169190001 0.0419190004 +0.0330809988 0.0169190001 0.0330809988 +0.0330809988 0.0169190001 0.0169190001 +0.0330809988 0.0169190001 0.0080810003 +0.0330809988 0.0169190001 -0.0080810003 +0.0330809988 0.0169190001 -0.0330809988 +0.0330809988 0.0169190001 -0.0419190004 +0.0330809988 0.0169190001 -0.0500000007 +0.0330809988 0.0080810003 0.0500000007 +0.0330809988 0.0080810003 0.0419190004 +0.0330809988 0.0080810003 0.0330809988 +0.0330809988 0.0080810003 0.0169190001 +0.0330809988 0.0080810003 0.0080810003 +0.0330809988 0.0080810003 -0.0080810003 +0.0330809988 0.0080810003 -0.0330809988 +0.0330809988 0.0080810003 -0.0419190004 +0.0330809988 0.0080810003 -0.0500000007 +0.0330809988 -0.0080810003 0.0500000007 +0.0330809988 -0.0080810003 0.0419190004 +0.0330809988 -0.0080810003 0.0330809988 +0.0330809988 -0.0080810003 0.0169190001 +0.0330809988 -0.0080810003 0.0080810003 +0.0330809988 -0.0080810003 -0.0080810003 +0.0330809988 -0.0080810003 -0.0330809988 +0.0330809988 -0.0080810003 -0.0419190004 +0.0330809988 -0.0080810003 -0.0500000007 +0.0330809988 -0.0169190001 0.0500000007 +0.0330809988 -0.0169190001 0.0419190004 +0.0330809988 -0.0169190001 0.0330809988 +0.0330809988 -0.0169190001 0.0169190001 +0.0330809988 -0.0169190001 0.0080810003 +0.0330809988 -0.0169190001 -0.0080810003 +0.0330809988 -0.0169190001 -0.0330809988 +0.0330809988 -0.0169190001 -0.0419190004 +0.0330809988 -0.0169190001 -0.0500000007 +0.0330809988 -0.0330809988 0.0500000007 +0.0330809988 -0.0330809988 0.0419190004 +0.0330809988 -0.0330809988 0.0330809988 +0.0330809988 -0.0330809988 0.0169190001 +0.0330809988 -0.0330809988 0.0080810003 +0.0330809988 -0.0330809988 -0.0080810003 +0.0330809988 -0.0330809988 -0.0169190001 +0.0330809988 -0.0330809988 -0.0330809988 +0.0330809988 -0.0330809988 -0.0419190004 +0.0330809988 -0.0330809988 -0.0500000007 +0.0330809988 -0.0419190004 0.0500000007 +0.0330809988 -0.0419190004 0.0419190004 +0.0330809988 -0.0419190004 0.0330809988 +0.0330809988 -0.0419190004 0.0169190001 +0.0330809988 -0.0419190004 0.0080810003 +0.0330809988 -0.0419190004 -0.0080810003 +0.0330809988 -0.0419190004 -0.0330809988 +0.0330809988 -0.0419190004 -0.0419190004 +0.0330809988 -0.0419190004 -0.0500000007 +0.0330809988 -0.0500000007 0.0419190004 +0.0330809988 -0.0500000007 0.0330809988 +0.0330809988 -0.0500000007 0.0169190001 +0.0330809988 -0.0500000007 0.0080810003 +0.0330809988 -0.0500000007 -0.0080810003 +0.0330809988 -0.0500000007 -0.0330809988 +0.0330809988 -0.0500000007 -0.0419190004 +0.0330080017 0.0169920009 0.0331550017 +0.0330080017 0.0169920009 0.0168450009 +0.0330080017 0.0169920009 0.0081550004 +0.0330080017 0.0169920009 -0.0081550004 +0.0329720005 -0.0247910004 -0.0168079995 +0.0329300016 0.0167629998 -0.0329300016 +0.0329300016 0.0082369996 -0.0329300016 +0.0329300016 -0.0082369996 -0.0329300016 +0.0329300016 -0.0167629998 -0.0329300016 +0.0326800011 0.0335219987 -0.0323700011 +0.0326640010 -0.0414590016 -0.0299249999 +0.0324600004 -0.0245479997 -0.0161969997 +0.0324090011 0.0175909996 0.0411260016 +0.0324090011 -0.0411260016 -0.0324090011 +0.0323980004 0.0073980000 -0.0088910004 +0.0323980004 -0.0073980000 -0.0088910004 +0.0323890001 -0.0176110007 -0.0089020003 +0.0323860012 0.0410929993 0.0323860012 +0.0323860012 0.0410929993 0.0176139995 +0.0323860012 0.0410929993 0.0073859999 +0.0323860012 0.0410929993 -0.0073859999 +0.0323860012 0.0410929993 -0.0176139995 +0.0323159993 0.0409919992 0.0426840000 +0.0323030017 0.0426970012 0.0409720019 +0.0323030017 0.0426970012 0.0340280011 +0.0323030017 0.0426970012 0.0159719996 +0.0323030017 0.0426970012 0.0090279998 +0.0323030017 0.0426970012 -0.0090279998 +0.0323030017 0.0426970012 -0.0159719996 +0.0323030017 0.0426970012 -0.0340280011 +0.0323030017 0.0426970012 -0.0409720019 +0.0323030017 0.0409720019 -0.0323030017 +0.0323030017 0.0409720019 -0.0426970012 +0.0323030017 0.0340280011 -0.0323030017 +0.0323030017 0.0340280011 -0.0426970012 +0.0323030017 0.0323030017 -0.0340280011 +0.0323030017 0.0323030017 -0.0409720019 +0.0323030017 0.0176970009 -0.0340280011 +0.0323030017 0.0176970009 -0.0409720019 +0.0323030017 0.0159719996 0.0426970012 +0.0323030017 0.0159719996 0.0323030017 +0.0323030017 0.0159719996 0.0176970009 +0.0323030017 0.0159719996 0.0073030000 +0.0323030017 0.0159719996 -0.0073030000 +0.0323030017 0.0159719996 -0.0426970012 +0.0323030017 0.0090279998 0.0426970012 +0.0323030017 0.0090279998 0.0323030017 +0.0323030017 0.0090279998 0.0176970009 +0.0323030017 0.0090279998 0.0073030000 +0.0323030017 0.0090279998 -0.0073030000 +0.0323030017 0.0090279998 -0.0426970012 +0.0323030017 0.0073030000 0.0409720019 +0.0323030017 0.0073030000 0.0340280011 +0.0323030017 0.0073030000 0.0159719996 +0.0323030017 0.0073030000 0.0090279998 +0.0323030017 0.0073030000 -0.0340280011 +0.0323030017 0.0073030000 -0.0409720019 +0.0323030017 -0.0073030000 0.0409720019 +0.0323030017 -0.0073030000 0.0340280011 +0.0323030017 -0.0073030000 0.0159719996 +0.0323030017 -0.0073030000 0.0090279998 +0.0323030017 -0.0073030000 -0.0340280011 +0.0323030017 -0.0073030000 -0.0409720019 +0.0323030017 -0.0090279998 0.0426970012 +0.0323030017 -0.0090279998 0.0323030017 +0.0323030017 -0.0090279998 0.0176970009 +0.0323030017 -0.0090279998 0.0073030000 +0.0323030017 -0.0090279998 -0.0073030000 +0.0323030017 -0.0090279998 -0.0426970012 +0.0323030017 -0.0159719996 0.0426970012 +0.0323030017 -0.0159719996 0.0323030017 +0.0323030017 -0.0159719996 0.0176970009 +0.0323030017 -0.0159719996 0.0073030000 +0.0323030017 -0.0159719996 -0.0073030000 +0.0323030017 -0.0159719996 -0.0426970012 +0.0323030017 -0.0176970009 0.0409720019 +0.0323030017 -0.0176970009 0.0340280011 +0.0323030017 -0.0176970009 0.0159719996 +0.0323030017 -0.0176970009 0.0090279998 +0.0323030017 -0.0176970009 -0.0340280011 +0.0323030017 -0.0176970009 -0.0409720019 +0.0323030017 -0.0323030017 0.0409720019 +0.0323030017 -0.0323030017 0.0340280011 +0.0323030017 -0.0323030017 0.0159719996 +0.0323030017 -0.0323030017 0.0090279998 +0.0323030017 -0.0323030017 -0.0090279998 +0.0323030017 -0.0323030017 -0.0159719996 +0.0323030017 -0.0323030017 -0.0340280011 +0.0323030017 -0.0323030017 -0.0409720019 +0.0323030017 -0.0340280011 0.0426970012 +0.0323030017 -0.0340280011 0.0323030017 +0.0323030017 -0.0340280011 0.0176970009 +0.0323030017 -0.0340280011 0.0073030000 +0.0323030017 -0.0340280011 -0.0073030000 +0.0323030017 -0.0340280011 -0.0176970009 +0.0323030017 -0.0340280011 -0.0323030017 +0.0323030017 -0.0340280011 -0.0426970012 +0.0323030017 -0.0409720019 0.0426970012 +0.0323030017 -0.0409720019 0.0323030017 +0.0323030017 -0.0409720019 0.0176970009 +0.0323030017 -0.0409720019 0.0073030000 +0.0323030017 -0.0409720019 -0.0073030000 +0.0323030017 -0.0409720019 -0.0426970012 +0.0323030017 -0.0426970012 0.0409720019 +0.0323030017 -0.0426970012 0.0340280011 +0.0323030017 -0.0426970012 0.0159719996 +0.0323030017 -0.0426970012 0.0090279998 +0.0323030017 -0.0426970012 -0.0340280011 +0.0323030017 -0.0426970012 -0.0409720019 +0.0322889984 0.0193189997 0.0409509987 +0.0321590006 -0.0428409986 -0.0092540001 +0.0321590006 -0.0500000007 -0.0092540001 +0.0321259983 0.0406920016 0.0500000007 +0.0320869982 0.0500000007 0.0406249985 +0.0320869982 0.0500000007 0.0343750007 +0.0320869982 0.0500000007 0.0156250000 +0.0320869982 0.0500000007 0.0093750004 +0.0320869982 0.0500000007 -0.0093750004 +0.0320869982 0.0500000007 -0.0156250000 +0.0320869982 0.0500000007 -0.0343750007 +0.0320869982 0.0500000007 -0.0406249985 +0.0320869982 0.0406249985 -0.0500000007 +0.0320869982 0.0343750007 -0.0500000007 +0.0320869982 0.0156250000 0.0500000007 +0.0320869982 0.0156250000 -0.0500000007 +0.0320869982 0.0093750004 0.0500000007 +0.0320869982 0.0093750004 -0.0500000007 +0.0320869982 -0.0093750004 0.0500000007 +0.0320869982 -0.0093750004 -0.0500000007 +0.0320869982 -0.0156250000 0.0500000007 +0.0320869982 -0.0156250000 -0.0500000007 +0.0320869982 -0.0343750007 0.0500000007 +0.0320869982 -0.0343750007 -0.0500000007 +0.0320869982 -0.0406249985 0.0500000007 +0.0320869982 -0.0406249985 -0.0500000007 +0.0320869982 -0.0500000007 0.0406249985 +0.0320869982 -0.0500000007 0.0343750007 +0.0320869982 -0.0500000007 0.0156250000 +0.0320869982 -0.0500000007 0.0093750004 +0.0320869982 -0.0500000007 -0.0343750007 +0.0320869982 -0.0500000007 -0.0406249985 +0.0320370011 -0.0242110007 -0.0155360000 +0.0320249982 0.0344859995 -0.0318869986 +0.0320059992 -0.0404799990 -0.0305819996 +0.0318790004 0.0181210004 0.0402319990 +0.0318790004 -0.0402319990 -0.0318790004 +0.0318609998 0.0068609999 -0.0098040001 +0.0318609998 -0.0068609999 -0.0098040001 +0.0318490006 -0.0181510001 -0.0098299999 +0.0318440013 0.0401600003 0.0318440013 +0.0318440013 0.0401600003 0.0181559995 +0.0318440013 0.0401600003 0.0068440000 +0.0318440013 0.0401600003 -0.0068440000 +0.0318440013 0.0401600003 -0.0181559995 +0.0318100005 -0.0431899987 -0.0099149998 +0.0317439996 0.0399339981 0.0432559997 +0.0317259990 0.0432740003 0.0398919992 +0.0317259990 0.0432740003 0.0351080000 +0.0317259990 0.0432740003 0.0148919998 +0.0317259990 0.0432740003 0.0101079997 +0.0317259990 0.0432740003 -0.0101079997 +0.0317259990 0.0432740003 -0.0148919998 +0.0317259990 0.0432740003 -0.0351080000 +0.0317259990 0.0432740003 -0.0398919992 +0.0317259990 0.0398919992 -0.0317259990 +0.0317259990 0.0398919992 -0.0432740003 +0.0317259990 0.0351080000 -0.0317259990 +0.0317259990 0.0351080000 -0.0432740003 +0.0317259990 0.0317259990 -0.0351080000 +0.0317259990 0.0317259990 -0.0398919992 +0.0317259990 0.0182739999 -0.0351080000 +0.0317259990 0.0182739999 -0.0398919992 +0.0317259990 0.0148919998 0.0432740003 +0.0317259990 0.0148919998 0.0317259990 +0.0317259990 0.0148919998 0.0182739999 +0.0317259990 0.0148919998 0.0067260000 +0.0317259990 0.0148919998 -0.0067260000 +0.0317259990 0.0148919998 -0.0432740003 +0.0317259990 0.0101079997 0.0432740003 +0.0317259990 0.0101079997 0.0317259990 +0.0317259990 0.0101079997 0.0182739999 +0.0317259990 0.0101079997 0.0067260000 +0.0317259990 0.0101079997 -0.0067260000 +0.0317259990 0.0101079997 -0.0432740003 +0.0317259990 0.0067260000 0.0398919992 +0.0317259990 0.0067260000 0.0351080000 +0.0317259990 0.0067260000 0.0148919998 +0.0317259990 0.0067260000 0.0101079997 +0.0317259990 0.0067260000 -0.0351080000 +0.0317259990 0.0067260000 -0.0398919992 +0.0317259990 -0.0067260000 0.0398919992 +0.0317259990 -0.0067260000 0.0351080000 +0.0317259990 -0.0067260000 0.0148919998 +0.0317259990 -0.0067260000 0.0101079997 +0.0317259990 -0.0067260000 -0.0351080000 +0.0317259990 -0.0067260000 -0.0398919992 +0.0317259990 -0.0101079997 0.0432740003 +0.0317259990 -0.0101079997 0.0317259990 +0.0317259990 -0.0101079997 0.0182739999 +0.0317259990 -0.0101079997 0.0067260000 +0.0317259990 -0.0101079997 -0.0067260000 +0.0317259990 -0.0101079997 -0.0432740003 +0.0317259990 -0.0148919998 0.0432740003 +0.0317259990 -0.0148919998 0.0317259990 +0.0317259990 -0.0148919998 0.0182739999 +0.0317259990 -0.0148919998 0.0067260000 +0.0317259990 -0.0148919998 -0.0067260000 +0.0317259990 -0.0148919998 -0.0432740003 +0.0317259990 -0.0182739999 0.0398919992 +0.0317259990 -0.0182739999 0.0351080000 +0.0317259990 -0.0182739999 0.0148919998 +0.0317259990 -0.0182739999 0.0101079997 +0.0317259990 -0.0182739999 -0.0351080000 +0.0317259990 -0.0182739999 -0.0398919992 +0.0317259990 -0.0317259990 0.0398919992 +0.0317259990 -0.0317259990 0.0351080000 +0.0317259990 -0.0317259990 0.0148919998 +0.0317259990 -0.0317259990 0.0101079997 +0.0317259990 -0.0317259990 -0.0101079997 +0.0317259990 -0.0317259990 -0.0148919998 +0.0317259990 -0.0317259990 -0.0351080000 +0.0317259990 -0.0317259990 -0.0398919992 +0.0317259990 -0.0351080000 0.0432740003 +0.0317259990 -0.0351080000 0.0317259990 +0.0317259990 -0.0351080000 0.0182739999 +0.0317259990 -0.0351080000 0.0067260000 +0.0317259990 -0.0351080000 -0.0067260000 +0.0317259990 -0.0351080000 -0.0182739999 +0.0317259990 -0.0351080000 -0.0317259990 +0.0317259990 -0.0351080000 -0.0432740003 +0.0317259990 -0.0398919992 0.0432740003 +0.0317259990 -0.0398919992 0.0317259990 +0.0317259990 -0.0398919992 0.0182739999 +0.0317259990 -0.0398919992 0.0067260000 +0.0317259990 -0.0398919992 -0.0067260000 +0.0317259990 -0.0398919992 -0.0432740003 +0.0317259990 -0.0432740003 0.0398919992 +0.0317259990 -0.0432740003 0.0351080000 +0.0317259990 -0.0432740003 0.0148919998 +0.0317259990 -0.0432740003 0.0101079997 +0.0317259990 -0.0432740003 -0.0351080000 +0.0317259990 -0.0432740003 -0.0398919992 +0.0317060016 -0.0237590000 -0.0148440003 +0.0316420011 0.0189449992 0.0396800004 +0.0315789990 0.0354989991 -0.0311600007 +0.0315439999 -0.0393959992 -0.0310440008 +0.0315419994 -0.0434579998 -0.0106130000 +0.0315419994 -0.0500000007 -0.0106130000 +0.0315040015 0.0184959993 0.0392629988 +0.0315040015 -0.0392620005 -0.0315040015 +0.0314869992 0.0064869998 -0.0107960002 +0.0314869992 -0.0064869998 -0.0107960002 +0.0314849988 0.0391989984 0.0500000007 +0.0314829983 -0.0232170001 -0.0141890002 +0.0314750001 -0.0185250007 -0.0108359996 +0.0314709991 0.0391479991 0.0314709991 +0.0314709991 0.0391479991 0.0185289998 +0.0314709991 0.0391479991 0.0064710001 +0.0314709991 0.0391479991 -0.0064710001 +0.0314709991 0.0391479991 -0.0185289998 +0.0314630009 0.0500000007 0.0391179994 +0.0314630009 0.0500000007 0.0358819999 +0.0314630009 0.0500000007 0.0141179999 +0.0314630009 0.0500000007 0.0108820004 +0.0314630009 0.0500000007 -0.0108820004 +0.0314630009 0.0500000007 -0.0141179999 +0.0314630009 0.0500000007 -0.0358819999 +0.0314630009 0.0500000007 -0.0391179994 +0.0314630009 0.0391179994 -0.0500000007 +0.0314630009 0.0358819999 -0.0500000007 +0.0314630009 0.0141179999 0.0500000007 +0.0314630009 0.0141179999 -0.0500000007 +0.0314630009 0.0108820004 0.0500000007 +0.0314630009 0.0108820004 -0.0500000007 +0.0314630009 -0.0108820004 0.0500000007 +0.0314630009 -0.0108820004 -0.0500000007 +0.0314630009 -0.0141179999 0.0500000007 +0.0314630009 -0.0141179999 -0.0500000007 +0.0314630009 -0.0358819999 0.0500000007 +0.0314630009 -0.0358819999 -0.0500000007 +0.0314630009 -0.0391179994 0.0500000007 +0.0314630009 -0.0391179994 -0.0500000007 +0.0314630009 -0.0500000007 0.0391179994 +0.0314630009 -0.0500000007 0.0358819999 +0.0314630009 -0.0500000007 0.0141179999 +0.0314630009 -0.0500000007 0.0108820004 +0.0314630009 -0.0500000007 -0.0358819999 +0.0314630009 -0.0500000007 -0.0391179994 +0.0313839987 0.0387869999 0.0436160006 +0.0313699991 0.0436300002 0.0387189984 +0.0313699991 0.0436300002 0.0362810008 +0.0313699991 0.0436300002 0.0137189999 +0.0313699991 0.0436300002 0.0112810005 +0.0313699991 0.0436300002 -0.0112810005 +0.0313699991 0.0436300002 -0.0137189999 +0.0313699991 0.0436300002 -0.0362810008 +0.0313699991 0.0436300002 -0.0387189984 +0.0313699991 0.0387189984 -0.0313699991 +0.0313699991 0.0387189984 -0.0436300002 +0.0313699991 0.0362810008 -0.0313699991 +0.0313699991 0.0362810008 -0.0436300002 +0.0313699991 0.0313699991 -0.0362810008 +0.0313699991 0.0313699991 -0.0387189984 +0.0313699991 0.0186299998 -0.0362810008 +0.0313699991 0.0186299998 -0.0387189984 +0.0313699991 0.0137189999 0.0436300002 +0.0313699991 0.0137189999 0.0313699991 +0.0313699991 0.0137189999 0.0186299998 +0.0313699991 0.0137189999 0.0063700001 +0.0313699991 0.0137189999 -0.0063700001 +0.0313699991 0.0137189999 -0.0436300002 +0.0313699991 0.0112810005 0.0436300002 +0.0313699991 0.0112810005 0.0313699991 +0.0313699991 0.0112810005 0.0186299998 +0.0313699991 0.0112810005 0.0063700001 +0.0313699991 0.0112810005 -0.0063700001 +0.0313699991 0.0112810005 -0.0436300002 +0.0313699991 0.0063700001 0.0387189984 +0.0313699991 0.0063700001 0.0362810008 +0.0313699991 0.0063700001 0.0137189999 +0.0313699991 0.0063700001 0.0112810005 +0.0313699991 0.0063700001 -0.0362810008 +0.0313699991 0.0063700001 -0.0387189984 +0.0313699991 -0.0063700001 0.0387189984 +0.0313699991 -0.0063700001 0.0362810008 +0.0313699991 -0.0063700001 0.0137189999 +0.0313699991 -0.0063700001 0.0112810005 +0.0313699991 -0.0063700001 -0.0362810008 +0.0313699991 -0.0063700001 -0.0387189984 +0.0313699991 -0.0112810005 0.0436300002 +0.0313699991 -0.0112810005 0.0313699991 +0.0313699991 -0.0112810005 0.0186299998 +0.0313699991 -0.0112810005 0.0063700001 +0.0313699991 -0.0112810005 -0.0063700001 +0.0313699991 -0.0112810005 -0.0436300002 +0.0313699991 -0.0137189999 0.0436300002 +0.0313699991 -0.0137189999 0.0313699991 +0.0313699991 -0.0137189999 0.0186299998 +0.0313699991 -0.0137189999 0.0063700001 +0.0313699991 -0.0137189999 -0.0063700001 +0.0313699991 -0.0137189999 -0.0436300002 +0.0313699991 -0.0186299998 0.0387189984 +0.0313699991 -0.0186299998 0.0362810008 +0.0313699991 -0.0186299998 0.0137189999 +0.0313699991 -0.0186299998 0.0112810005 +0.0313699991 -0.0186299998 -0.0362810008 +0.0313699991 -0.0186299998 -0.0387189984 +0.0313699991 -0.0313699991 0.0387189984 +0.0313699991 -0.0313699991 0.0362810008 +0.0313699991 -0.0313699991 0.0137189999 +0.0313699991 -0.0313699991 0.0112810005 +0.0313699991 -0.0313699991 -0.0112810005 +0.0313699991 -0.0313699991 -0.0137189999 +0.0313699991 -0.0313699991 -0.0362810008 +0.0313699991 -0.0313699991 -0.0387189984 +0.0313699991 -0.0362810008 0.0436300002 +0.0313699991 -0.0362810008 0.0313699991 +0.0313699991 -0.0362810008 0.0186299998 +0.0313699991 -0.0362810008 0.0063700001 +0.0313699991 -0.0362810008 -0.0063700001 +0.0313699991 -0.0362810008 -0.0186299998 +0.0313699991 -0.0362810008 -0.0313699991 +0.0313699991 -0.0362810008 -0.0436300002 +0.0313699991 -0.0387189984 0.0436300002 +0.0313699991 -0.0387189984 0.0313699991 +0.0313699991 -0.0387189984 0.0186299998 +0.0313699991 -0.0387189984 0.0063700001 +0.0313699991 -0.0387189984 -0.0063700001 +0.0313699991 -0.0387189984 -0.0436300002 +0.0313699991 -0.0436300002 0.0387189984 +0.0313699991 -0.0436300002 0.0362810008 +0.0313699991 -0.0436300002 0.0137189999 +0.0313699991 -0.0436300002 0.0112810005 +0.0313699991 -0.0436300002 -0.0362810008 +0.0313699991 -0.0436300002 -0.0387189984 +0.0313589983 -0.0436410010 -0.0113369999 +0.0313530006 0.0363700017 -0.0302779991 +0.0313510001 -0.0226210002 -0.0136160003 +0.0313419998 -0.0436579995 -0.0135690002 +0.0313419998 -0.0500000007 -0.0135690002 +0.0312950015 0.0187049992 0.0382449999 +0.0312939994 -0.0382440016 -0.0312939994 +0.0312890001 0.0381929986 0.0437109992 +0.0312849991 0.0062850001 -0.0118359998 +0.0312849991 -0.0062850001 -0.0118359998 +0.0312799998 0.0437199995 0.0381130017 +0.0312799998 0.0437199995 0.0368870012 +0.0312799998 0.0437199995 0.0131130004 +0.0312799998 0.0437199995 0.0118869999 +0.0312799998 0.0437199995 -0.0118869999 +0.0312799998 0.0437199995 -0.0131130004 +0.0312799998 0.0437199995 -0.0368870012 +0.0312799998 0.0437199995 -0.0381130017 +0.0312799998 0.0381130017 -0.0312799998 +0.0312799998 0.0381130017 -0.0437199995 +0.0312799998 0.0368870012 -0.0312799998 +0.0312799998 0.0368870012 -0.0437199995 +0.0312799998 0.0312799998 -0.0368870012 +0.0312799998 0.0312799998 -0.0381130017 +0.0312799998 0.0187199991 -0.0368870012 +0.0312799998 0.0187199991 -0.0381130017 +0.0312799998 0.0131130004 0.0437199995 +0.0312799998 0.0131130004 0.0312799998 +0.0312799998 0.0131130004 0.0187199991 +0.0312799998 0.0131130004 0.0062799999 +0.0312799998 0.0131130004 -0.0062799999 +0.0312799998 0.0131130004 -0.0437199995 +0.0312799998 0.0118869999 0.0437199995 +0.0312799998 0.0118869999 0.0312799998 +0.0312799998 0.0118869999 0.0187199991 +0.0312799998 0.0118869999 0.0062799999 +0.0312799998 0.0118869999 -0.0062799999 +0.0312799998 0.0118869999 -0.0437199995 +0.0312799998 0.0062799999 0.0381130017 +0.0312799998 0.0062799999 0.0368870012 +0.0312799998 0.0062799999 0.0131130004 +0.0312799998 0.0062799999 0.0118869999 +0.0312799998 0.0062799999 -0.0368870012 +0.0312799998 0.0062799999 -0.0381130017 +0.0312799998 -0.0062799999 0.0381130017 +0.0312799998 -0.0062799999 0.0368870012 +0.0312799998 -0.0062799999 0.0131130004 +0.0312799998 -0.0062799999 0.0118869999 +0.0312799998 -0.0062799999 -0.0368870012 +0.0312799998 -0.0062799999 -0.0381130017 +0.0312799998 -0.0118869999 0.0437199995 +0.0312799998 -0.0118869999 0.0312799998 +0.0312799998 -0.0118869999 0.0187199991 +0.0312799998 -0.0118869999 0.0062799999 +0.0312799998 -0.0118869999 -0.0062799999 +0.0312799998 -0.0118869999 -0.0437199995 +0.0312799998 -0.0131130004 0.0437199995 +0.0312799998 -0.0131130004 0.0312799998 +0.0312799998 -0.0131130004 0.0187199991 +0.0312799998 -0.0131130004 0.0062799999 +0.0312799998 -0.0131130004 -0.0062799999 +0.0312799998 -0.0131130004 -0.0437199995 +0.0312799998 -0.0187199991 0.0381130017 +0.0312799998 -0.0187199991 0.0368870012 +0.0312799998 -0.0187199991 0.0131130004 +0.0312799998 -0.0187199991 0.0118869999 +0.0312799998 -0.0187199991 -0.0118920002 +0.0312799998 -0.0187199991 -0.0368870012 +0.0312799998 -0.0187199991 -0.0381130017 +0.0312799998 -0.0312799998 0.0381130017 +0.0312799998 -0.0312799998 0.0368870012 +0.0312799998 -0.0312799998 0.0131130004 +0.0312799998 -0.0312799998 0.0118869999 +0.0312799998 -0.0312799998 -0.0118869999 +0.0312799998 -0.0312799998 -0.0131130004 +0.0312799998 -0.0312799998 -0.0368870012 +0.0312799998 -0.0312799998 -0.0381130017 +0.0312799998 -0.0368870012 0.0437199995 +0.0312799998 -0.0368870012 0.0312799998 +0.0312799998 -0.0368870012 0.0187199991 +0.0312799998 -0.0368870012 0.0062799999 +0.0312799998 -0.0368870012 -0.0062799999 +0.0312799998 -0.0368870012 -0.0187199991 +0.0312799998 -0.0368870012 -0.0312799998 +0.0312799998 -0.0368870012 -0.0437199995 +0.0312799998 -0.0381130017 0.0437199995 +0.0312799998 -0.0381130017 0.0312799998 +0.0312799998 -0.0381130017 0.0187199991 +0.0312799998 -0.0381130017 0.0062799999 +0.0312799998 -0.0381130017 -0.0062799999 +0.0312799998 -0.0381130017 -0.0437199995 +0.0312799998 -0.0437199995 0.0381130017 +0.0312799998 -0.0437199995 0.0368870012 +0.0312799998 -0.0437199995 0.0131130004 +0.0312799998 -0.0437199995 0.0118869999 +0.0312799998 -0.0437199995 -0.0368870012 +0.0312799998 -0.0437199995 -0.0381130017 +0.0312790014 -0.0219470002 -0.0131019996 +0.0312779993 0.0380860008 0.0312779993 +0.0312779993 0.0380860008 0.0187219996 +0.0312779993 0.0380860008 0.0062779998 +0.0312779993 0.0380860008 -0.0062779998 +0.0312779993 0.0380860008 -0.0187219996 +0.0312779993 0.0380860008 -0.0255469996 +0.0312680006 0.0379780009 -0.0268029999 +0.0312639996 -0.0437359996 -0.0120789995 +0.0312639996 -0.0500000007 -0.0120789995 +0.0312630013 0.0370990001 -0.0292349998 +0.0312590003 -0.0437409990 -0.0128260003 +0.0312529989 -0.0204029996 -0.0123060001 +0.0312520005 0.0376459993 -0.0280569997 +0.0312509984 0.0375920013 0.0500000007 +0.0312509984 0.0375920013 0.0437490009 +0.0312500000 0.0500000007 0.0375000015 +0.0312500000 0.0500000007 0.0125000002 +0.0312500000 0.0500000007 -0.0125000002 +0.0312500000 0.0500000007 -0.0375000015 +0.0312500000 0.0437499993 0.0375000015 +0.0312500000 0.0437499993 0.0125000002 +0.0312500000 0.0437499993 -0.0125000002 +0.0312500000 0.0437499993 -0.0375000015 +0.0312500000 0.0375000015 -0.0312500000 +0.0312500000 0.0375000015 -0.0437499993 +0.0312500000 0.0375000015 -0.0500000007 +0.0312500000 0.0312500000 -0.0375000015 +0.0312500000 0.0187500007 -0.0375000015 +0.0312500000 0.0125000002 0.0500000007 +0.0312500000 0.0125000002 0.0437499993 +0.0312500000 0.0125000002 0.0312500000 +0.0312500000 0.0125000002 0.0187500007 +0.0312500000 0.0125000002 0.0062500001 +0.0312500000 0.0125000002 -0.0062500001 +0.0312500000 0.0125000002 -0.0437499993 +0.0312500000 0.0125000002 -0.0500000007 +0.0312500000 0.0062500001 0.0375000015 +0.0312500000 0.0062500001 0.0125000002 +0.0312500000 0.0062500001 -0.0375000015 +0.0312500000 -0.0062500001 0.0375000015 +0.0312500000 -0.0062500001 0.0125000002 +0.0312500000 -0.0062500001 -0.0375000015 +0.0312500000 -0.0125000002 0.0500000007 +0.0312500000 -0.0125000002 0.0437499993 +0.0312500000 -0.0125000002 0.0312500000 +0.0312500000 -0.0125000002 0.0187500007 +0.0312500000 -0.0125000002 0.0062500001 +0.0312500000 -0.0125000002 -0.0062500001 +0.0312500000 -0.0125000002 -0.0437499993 +0.0312500000 -0.0125000002 -0.0500000007 +0.0312500000 -0.0187500007 0.0375000015 +0.0312500000 -0.0187500007 0.0125000002 +0.0312500000 -0.0187500007 -0.0375000015 +0.0312500000 -0.0312500000 0.0375000015 +0.0312500000 -0.0312500000 0.0125000002 +0.0312500000 -0.0312500000 -0.0125000002 +0.0312500000 -0.0312500000 -0.0375000015 +0.0312500000 -0.0375000015 0.0500000007 +0.0312500000 -0.0375000015 0.0437499993 +0.0312500000 -0.0375000015 0.0312500000 +0.0312500000 -0.0375000015 0.0187500007 +0.0312500000 -0.0375000015 0.0062500001 +0.0312500000 -0.0375000015 -0.0062500001 +0.0312500000 -0.0375000015 -0.0187500007 +0.0312500000 -0.0375000015 -0.0312500000 +0.0312500000 -0.0375000015 -0.0437499993 +0.0312500000 -0.0375000015 -0.0500000007 +0.0312500000 -0.0437499993 0.0375000015 +0.0312500000 -0.0437499993 0.0125000002 +0.0312500000 -0.0437499993 -0.0375000015 +0.0312500000 -0.0500000007 0.0375000015 +0.0312500000 -0.0500000007 0.0125000002 +0.0312500000 -0.0500000007 -0.0375000015 +0.0310600009 0.0186090004 0.0388190001 +0.0310440008 -0.0393959992 -0.0315439999 +0.0309660006 0.0380860008 0.0312779993 +0.0309660006 0.0380860008 0.0187219996 +0.0309660006 0.0380860008 0.0062779998 +0.0309660006 0.0380860008 -0.0003910000 +0.0308020003 0.0184599999 0.0393819995 +0.0306340009 0.0386609994 0.0500000007 +0.0306340009 0.0386609994 0.0436410010 +0.0306340009 0.0386609994 0.0313589983 +0.0306340009 0.0386609994 0.0186410006 +0.0306340009 0.0386609994 0.0063590002 +0.0306340009 0.0386609994 -0.0003910000 +0.0305819996 -0.0404799990 -0.0320059992 +0.0302869994 -0.0433779992 -0.0146239996 +0.0300190002 0.0180079993 0.0404540002 +0.0300179999 0.0395330004 0.0434099995 +0.0299510006 0.0396099985 0.0316170007 +0.0299510006 0.0396099985 0.0183830000 +0.0299510006 0.0396099985 0.0066169999 +0.0299249999 -0.0414590016 -0.0326640010 +0.0298059992 0.0397679992 0.0500000007 +0.0297030006 0.0398739986 -0.0003910000 +0.0292969998 -0.0429189987 -0.0156140001 +0.0292739999 0.0402619988 0.0431060009 +0.0291220006 0.0403829999 0.0319550000 +0.0291220006 0.0403829999 0.0180450007 +0.0291220006 0.0403829999 0.0069550001 +0.0290959999 -0.0422969982 -0.0334930010 +0.0289050005 0.0173649993 0.0414230004 +0.0287420005 0.0406510010 0.0500000007 +0.0284889992 0.0408050008 -0.0003910000 +0.0284519996 0.0408269987 0.0427910015 +0.0284020007 -0.0422939993 -0.0165100005 +0.0282589998 0.0169920009 0.0331550017 +0.0282589998 0.0169920009 0.0168450009 +0.0282589998 0.0169920009 0.0081550004 +0.0282589998 0.0169920009 -0.0003910000 +0.0281889997 0.0409669988 0.0322999991 +0.0281889997 0.0409669988 0.0176999997 +0.0281889997 0.0409669988 0.0073000002 +0.0281240009 -0.0429640003 -0.0344650000 +0.0276289992 -0.0415240005 -0.0172819998 +0.0274999999 0.0500000007 0.0500000007 +0.0274999999 0.0500000007 0.0375000015 +0.0274999999 0.0437499993 0.0375000015 +0.0274999999 0.0435840003 0.0389330015 +0.0274999999 0.0430929996 0.0402900018 +0.0274999999 0.0423040017 0.0414980017 +0.0274999999 0.0412600003 0.0500000007 +0.0274999999 0.0412600003 0.0424930006 +0.0274999999 0.0165539999 0.0500000007 +0.0274999999 0.0165539999 0.0422569998 +0.0274999999 0.0152340000 0.0431200005 +0.0274999999 0.0137409996 0.0436259992 +0.0274999999 0.0121680005 0.0437409990 +0.0274999999 0.0106170001 0.0434600003 +0.0274999999 0.0091850003 0.0427989997 +0.0274999999 0.0079650003 0.0418009982 +0.0274999999 0.0070329998 0.0405290015 +0.0274999999 0.0064490000 0.0390640013 +0.0274999999 0.0062500001 0.0375000015 +0.0274999999 -0.0062500001 0.0375000015 +0.0274999999 -0.0064630001 0.0391179994 +0.0274999999 -0.0070870002 0.0406249985 +0.0274999999 -0.0080810003 0.0419190004 +0.0274999999 -0.0093750004 0.0429130010 +0.0274999999 -0.0108820004 0.0435369983 +0.0274999999 -0.0125000002 0.0437499993 +0.0274999999 -0.0141179999 0.0435369983 +0.0274999999 -0.0156250000 0.0429130010 +0.0274999999 -0.0169190001 0.0419190004 +0.0274999999 -0.0179130007 0.0406249985 +0.0274999999 -0.0185369998 0.0391179994 +0.0274999999 -0.0187500007 0.0375000015 +0.0274999999 -0.0312500000 0.0375000015 +0.0274999999 -0.0314630009 0.0391179994 +0.0274999999 -0.0320869982 0.0406249985 +0.0274999999 -0.0330809988 0.0419190004 +0.0274999999 -0.0343750007 0.0429130010 +0.0274999999 -0.0358819999 0.0435369983 +0.0274999999 -0.0375000015 0.0437499993 +0.0274999999 -0.0391179994 0.0435369983 +0.0274999999 -0.0406249985 0.0429130010 +0.0274999999 -0.0419190004 0.0419190004 +0.0274999999 -0.0429130010 0.0406249985 +0.0274999999 -0.0435369983 0.0391179994 +0.0274999999 -0.0437499993 0.0375000015 +0.0274999999 -0.0500000007 0.0500000007 +0.0274999999 -0.0500000007 0.0375000015 +0.0271070004 0.0413819999 0.0326020010 +0.0271070004 0.0413819999 0.0173979998 +0.0271070004 0.0413819999 0.0076020001 +0.0270760003 0.0413910002 -0.0003910000 +0.0270440001 -0.0434359983 -0.0355449989 +0.0270019993 -0.0406300016 -0.0179099999 +0.0265389998 -0.0396410003 -0.0183719993 +0.0262560006 -0.0385870002 -0.0186550003 +0.0262230001 0.0158159994 0.0322020017 +0.0262230001 0.0158159994 0.0177979991 +0.0262230001 0.0158159994 0.0072019999 +0.0261610001 -0.0375000015 -0.0187500007 +0.0259559993 0.0415770002 0.0327630006 +0.0259559993 0.0415770002 0.0172370002 +0.0259559993 0.0415770002 0.0077630002 +0.0258939993 -0.0436980017 -0.0366940014 +0.0255600009 0.0415900014 -0.0003910000 +0.0248140004 0.0415429994 0.0327339992 +0.0248140004 0.0415429994 0.0172659997 +0.0248140004 0.0415429994 0.0077340002 +0.0247159991 -0.0437389985 -0.0378729999 +0.0240429994 0.0413910002 -0.0003910000 +0.0238499995 0.0144459996 0.0315609984 +0.0238499995 0.0144459996 0.0184390005 +0.0238499995 0.0144459996 0.0065609999 +0.0236740001 0.0412780009 0.0325209983 +0.0236740001 0.0412780009 0.0174790006 +0.0236740001 0.0412780009 0.0075210002 +0.0235510003 -0.0435580015 -0.0390370004 +0.0226300005 0.0408050008 0.0321960002 +0.0226300005 0.0408050008 0.0178040005 +0.0226300005 0.0408050008 0.0071959998 +0.0226300005 0.0408050008 -0.0003910000 +0.0224409997 -0.0431619994 -0.0401480012 +0.0214249995 -0.0425640009 -0.0411639996 +0.0205400009 -0.0417860001 -0.0420489982 +0.0198160000 -0.0408550017 -0.0427730009 +0.0192799997 -0.0398049988 -0.0433089994 +0.0189500004 -0.0386740007 -0.0436390005 +0.0188669991 -0.0380889997 -0.0437220000 +0.0188389998 -0.0375000015 -0.0437499993 +0.0187500007 0.0500000007 0.0375000015 +0.0187500007 0.0500000007 0.0125000002 +0.0187500007 0.0500000007 -0.0125000002 +0.0187500007 0.0500000007 -0.0375000015 +0.0187500007 0.0437499993 0.0375000015 +0.0187500007 0.0437499993 0.0125000002 +0.0187500007 0.0437499993 -0.0125000002 +0.0187500007 0.0437499993 -0.0375000015 +0.0187500007 0.0375000015 -0.0312500000 +0.0187500007 0.0375000015 -0.0437499993 +0.0187500007 0.0375000015 -0.0500000007 +0.0187500007 0.0312500000 -0.0375000015 +0.0187500007 0.0187500007 -0.0375000015 +0.0187500007 0.0125000002 -0.0062500001 +0.0187500007 0.0125000002 -0.0437499993 +0.0187500007 0.0125000002 -0.0500000007 +0.0187500007 0.0062500001 0.0375000015 +0.0187500007 0.0062500001 0.0125000002 +0.0187500007 0.0062500001 -0.0375000015 +0.0187500007 -0.0062500001 0.0375000015 +0.0187500007 -0.0062500001 0.0125000002 +0.0187500007 -0.0062500001 -0.0375000015 +0.0187500007 -0.0125000002 0.0312500000 +0.0187500007 -0.0125000002 0.0187500007 +0.0187500007 -0.0125000002 0.0062500001 +0.0187500007 -0.0125000002 -0.0062500001 +0.0187500007 -0.0125000002 -0.0437499993 +0.0187500007 -0.0125000002 -0.0500000007 +0.0187500007 -0.0187500007 0.0375000015 +0.0187500007 -0.0187500007 0.0125000002 +0.0187500007 -0.0187500007 -0.0375000015 +0.0187500007 -0.0208839998 -0.0125050005 +0.0187500007 -0.0312500000 0.0375000015 +0.0187500007 -0.0312500000 0.0125000002 +0.0187500007 -0.0312500000 -0.0125000002 +0.0187500007 -0.0312500000 -0.0375000015 +0.0187500007 -0.0375000015 0.0312500000 +0.0187500007 -0.0375000015 0.0187500007 +0.0187500007 -0.0375000015 0.0062500001 +0.0187500007 -0.0375000015 -0.0062500001 +0.0187500007 -0.0375000015 -0.0187500007 +0.0187500007 -0.0375000015 -0.0261610001 +0.0187500007 -0.0375000015 -0.0312500000 +0.0187500007 -0.0375000015 -0.0438390002 +0.0187500007 -0.0375000015 -0.0500000007 +0.0187500007 -0.0437499993 0.0375000015 +0.0187500007 -0.0437499993 0.0125000002 +0.0187500007 -0.0437499993 -0.0125000002 +0.0187500007 -0.0500000007 0.0375000015 +0.0187500007 -0.0500000007 0.0125000002 +0.0187500007 -0.0500000007 -0.0125000002 +0.0187470000 0.0376869999 -0.0279399995 +0.0187420007 0.0371880010 -0.0290750004 +0.0187379997 -0.0198199991 -0.0121139996 +0.0187330004 0.0129620004 -0.0003910000 +0.0187309999 0.0379879996 -0.0267430004 +0.0187260006 -0.0218690000 -0.0130500002 +0.0187219996 0.0380860008 -0.0003910000 +0.0187219996 0.0380860008 -0.0062779998 +0.0187219996 0.0380860008 -0.0187219996 +0.0187219996 0.0380860008 -0.0255469996 +0.0187199991 0.0437199995 0.0368870012 +0.0187199991 0.0437199995 0.0131130004 +0.0187199991 0.0437199995 0.0118869999 +0.0187199991 0.0437199995 -0.0118869999 +0.0187199991 0.0437199995 -0.0131130004 +0.0187199991 0.0437199995 -0.0368870012 +0.0187199991 0.0437199995 -0.0381130017 +0.0187199991 0.0381130017 -0.0312799998 +0.0187199991 0.0381130017 -0.0437199995 +0.0187199991 0.0368870012 -0.0312799998 +0.0187199991 0.0368870012 -0.0437199995 +0.0187199991 0.0312799998 -0.0368870012 +0.0187199991 0.0312799998 -0.0381130017 +0.0187199991 0.0187199991 -0.0368870012 +0.0187199991 0.0187199991 -0.0381130017 +0.0187199991 0.0131130004 -0.0062799999 +0.0187199991 0.0131130004 -0.0437199995 +0.0187199991 0.0118869999 -0.0062799999 +0.0187199991 0.0118869999 -0.0437199995 +0.0187199991 0.0062799999 0.0368870012 +0.0187199991 0.0062799999 0.0131130004 +0.0187199991 0.0062799999 0.0118869999 +0.0187199991 0.0062799999 -0.0368870012 +0.0187199991 0.0062799999 -0.0381130017 +0.0187199991 -0.0062799999 0.0368870012 +0.0187199991 -0.0062799999 0.0131130004 +0.0187199991 -0.0062799999 0.0118869999 +0.0187199991 -0.0062799999 -0.0368870012 +0.0187199991 -0.0062799999 -0.0381130017 +0.0187199991 -0.0118869999 0.0312799998 +0.0187199991 -0.0118869999 0.0187199991 +0.0187199991 -0.0118869999 0.0062799999 +0.0187199991 -0.0118869999 -0.0062799999 +0.0187199991 -0.0118869999 -0.0437199995 +0.0187199991 -0.0131130004 0.0312799998 +0.0187199991 -0.0131130004 0.0187199991 +0.0187199991 -0.0131130004 0.0062799999 +0.0187199991 -0.0131130004 -0.0062799999 +0.0187199991 -0.0131130004 -0.0437199995 +0.0187199991 -0.0187199991 0.0368870012 +0.0187199991 -0.0187199991 0.0131130004 +0.0187199991 -0.0187199991 0.0118869999 +0.0187199991 -0.0187199991 -0.0118920002 +0.0187199991 -0.0187199991 -0.0368870012 +0.0187199991 -0.0187199991 -0.0381130017 +0.0187199991 -0.0312799998 0.0368870012 +0.0187199991 -0.0312799998 0.0131130004 +0.0187199991 -0.0312799998 0.0118869999 +0.0187199991 -0.0312799998 -0.0118869999 +0.0187199991 -0.0312799998 -0.0131130004 +0.0187199991 -0.0312799998 -0.0368870012 +0.0187199991 -0.0312799998 -0.0381130017 +0.0187199991 -0.0368870012 0.0312799998 +0.0187199991 -0.0368870012 0.0187199991 +0.0187199991 -0.0368870012 0.0062799999 +0.0187199991 -0.0368870012 -0.0062799999 +0.0187199991 -0.0368870012 -0.0187199991 +0.0187199991 -0.0368870012 -0.0312799998 +0.0187199991 -0.0368870012 -0.0437199995 +0.0187199991 -0.0381070003 -0.0438680016 +0.0187199991 -0.0381130017 0.0312799998 +0.0187199991 -0.0381130017 0.0187199991 +0.0187199991 -0.0381130017 0.0062799999 +0.0187199991 -0.0381130017 -0.0062799999 +0.0187199991 -0.0381130017 -0.0187199991 +0.0187199991 -0.0437199995 0.0368870012 +0.0187199991 -0.0437199995 0.0131130004 +0.0187199991 -0.0437199995 0.0118869999 +0.0187199991 -0.0437199995 -0.0118869999 +0.0187199991 -0.0437199995 -0.0131130004 +0.0187149998 0.0062850001 -0.0118359998 +0.0187149998 -0.0062850001 -0.0118359998 +0.0186730009 0.0365209989 -0.0300929993 +0.0186669994 0.0385169983 0.0313329995 +0.0186669994 0.0385169983 0.0186669994 +0.0186669994 0.0385169983 0.0063330000 +0.0186669994 0.0385169983 -0.0003910000 +0.0186609998 0.0114510003 0.0313390009 +0.0186609998 0.0114510003 0.0186609998 +0.0186609998 0.0114510003 0.0063390001 +0.0186609998 0.0114510003 -0.0003910000 +0.0186550003 -0.0385870002 -0.0262560006 +0.0186320003 -0.0387080014 -0.0439569987 +0.0186299998 0.0436300002 0.0362810008 +0.0186299998 0.0436300002 0.0137189999 +0.0186299998 0.0436300002 0.0112810005 +0.0186299998 0.0436300002 -0.0112810005 +0.0186299998 0.0436300002 -0.0137189999 +0.0186299998 0.0436300002 -0.0362810008 +0.0186299998 0.0436300002 -0.0387189984 +0.0186299998 0.0387189984 -0.0313699991 +0.0186299998 0.0387189984 -0.0436300002 +0.0186299998 0.0362810008 -0.0313699991 +0.0186299998 0.0362810008 -0.0436300002 +0.0186299998 0.0313699991 -0.0362810008 +0.0186299998 0.0313699991 -0.0387189984 +0.0186299998 0.0186299998 -0.0362810008 +0.0186299998 0.0186299998 -0.0387189984 +0.0186299998 0.0137189999 -0.0063700001 +0.0186299998 0.0137189999 -0.0436300002 +0.0186299998 0.0112810005 -0.0063700001 +0.0186299998 0.0112810005 -0.0436300002 +0.0186299998 0.0063700001 0.0362810008 +0.0186299998 0.0063700001 0.0137189999 +0.0186299998 0.0063700001 0.0112810005 +0.0186299998 0.0063700001 -0.0362810008 +0.0186299998 0.0063700001 -0.0387189984 +0.0186299998 -0.0063700001 0.0362810008 +0.0186299998 -0.0063700001 0.0137189999 +0.0186299998 -0.0063700001 0.0112810005 +0.0186299998 -0.0063700001 -0.0362810008 +0.0186299998 -0.0063700001 -0.0387189984 +0.0186299998 -0.0112810005 0.0313699991 +0.0186299998 -0.0112810005 0.0186299998 +0.0186299998 -0.0112810005 0.0063700001 +0.0186299998 -0.0112810005 -0.0063700001 +0.0186299998 -0.0112810005 -0.0436300002 +0.0186299998 -0.0137189999 0.0313699991 +0.0186299998 -0.0137189999 0.0186299998 +0.0186299998 -0.0137189999 0.0063700001 +0.0186299998 -0.0137189999 -0.0063700001 +0.0186299998 -0.0137189999 -0.0436300002 +0.0186299998 -0.0186299998 0.0362810008 +0.0186299998 -0.0186299998 0.0137189999 +0.0186299998 -0.0186299998 0.0112810005 +0.0186299998 -0.0186299998 -0.0362810008 +0.0186299998 -0.0186299998 -0.0387189984 +0.0186299998 -0.0227359999 -0.0137179997 +0.0186299998 -0.0313699991 0.0362810008 +0.0186299998 -0.0313699991 0.0137189999 +0.0186299998 -0.0313699991 0.0112810005 +0.0186299998 -0.0313699991 -0.0112810005 +0.0186299998 -0.0313699991 -0.0137189999 +0.0186299998 -0.0313699991 -0.0362810008 +0.0186299998 -0.0313699991 -0.0387189984 +0.0186299998 -0.0362810008 0.0313699991 +0.0186299998 -0.0362810008 0.0186299998 +0.0186299998 -0.0362810008 0.0063700001 +0.0186299998 -0.0362810008 -0.0063700001 +0.0186299998 -0.0362810008 -0.0186299998 +0.0186299998 -0.0362810008 -0.0313699991 +0.0186299998 -0.0362810008 -0.0436300002 +0.0186299998 -0.0387189984 0.0313699991 +0.0186299998 -0.0387189984 0.0186299998 +0.0186299998 -0.0387189984 0.0063700001 +0.0186299998 -0.0387189984 -0.0063700001 +0.0186299998 -0.0387189984 -0.0186299998 +0.0186299998 -0.0436300002 0.0362810008 +0.0186299998 -0.0436300002 0.0137189999 +0.0186299998 -0.0436300002 0.0112810005 +0.0186299998 -0.0436300002 -0.0112810005 +0.0186299998 -0.0436300002 -0.0137189999 +0.0185410008 -0.0391030014 -0.0500000007 +0.0185369998 0.0500000007 0.0358819999 +0.0185369998 0.0500000007 0.0141179999 +0.0185369998 0.0500000007 0.0108820004 +0.0185369998 0.0500000007 -0.0108820004 +0.0185369998 0.0500000007 -0.0141179999 +0.0185369998 0.0500000007 -0.0358819999 +0.0185369998 0.0500000007 -0.0391179994 +0.0185369998 0.0391179994 -0.0500000007 +0.0185369998 0.0358819999 -0.0500000007 +0.0185369998 0.0141179999 -0.0500000007 +0.0185369998 0.0108820004 -0.0500000007 +0.0185369998 -0.0108820004 -0.0500000007 +0.0185369998 -0.0141179999 -0.0500000007 +0.0185369998 -0.0358819999 -0.0500000007 +0.0185369998 -0.0500000007 0.0358819999 +0.0185369998 -0.0500000007 0.0141179999 +0.0185369998 -0.0500000007 0.0108820004 +0.0185369998 -0.0500000007 -0.0108820004 +0.0185369998 -0.0500000007 -0.0141179999 +0.0185289998 0.0391479991 -0.0064710001 +0.0185289998 0.0391479991 -0.0185289998 +0.0185250007 -0.0185250007 -0.0108359996 +0.0185129996 0.0064869998 -0.0107960002 +0.0185129996 -0.0064869998 -0.0107960002 +0.0184920002 0.0357219987 -0.0309609994 +0.0184390005 0.0144459996 -0.0003910000 +0.0184349995 0.0394599997 0.0315649994 +0.0184349995 0.0394599997 0.0184349995 +0.0184349995 0.0394599997 0.0065649999 +0.0184269994 0.0105170002 0.0315730013 +0.0184269994 0.0105170002 0.0184269994 +0.0184269994 0.0105170002 0.0065730000 +0.0184209999 -0.0234910008 -0.0145009998 +0.0183719993 -0.0396410003 -0.0265389998 +0.0182830002 -0.0398709998 -0.0443059988 +0.0182739999 0.0432740003 0.0351080000 +0.0182739999 0.0432740003 0.0148919998 +0.0182739999 0.0432740003 0.0101079997 +0.0182739999 0.0432740003 -0.0101079997 +0.0182739999 0.0432740003 -0.0148919998 +0.0182739999 0.0432740003 -0.0351080000 +0.0182739999 0.0432740003 -0.0398919992 +0.0182739999 0.0398919992 -0.0317259990 +0.0182739999 0.0398919992 -0.0432740003 +0.0182739999 0.0351080000 -0.0317259990 +0.0182739999 0.0351080000 -0.0432740003 +0.0182739999 0.0317259990 -0.0351080000 +0.0182739999 0.0317259990 -0.0398919992 +0.0182739999 0.0182739999 -0.0351080000 +0.0182739999 0.0182739999 -0.0398919992 +0.0182739999 0.0148919998 -0.0067260000 +0.0182739999 0.0148919998 -0.0432740003 +0.0182739999 0.0101079997 -0.0067260000 +0.0182739999 0.0101079997 -0.0432740003 +0.0182739999 0.0067260000 0.0351080000 +0.0182739999 0.0067260000 0.0148919998 +0.0182739999 0.0067260000 0.0101079997 +0.0182739999 0.0067260000 -0.0351080000 +0.0182739999 0.0067260000 -0.0398919992 +0.0182739999 -0.0067260000 0.0351080000 +0.0182739999 -0.0067260000 0.0148919998 +0.0182739999 -0.0067260000 0.0101079997 +0.0182739999 -0.0067260000 -0.0351080000 +0.0182739999 -0.0067260000 -0.0398919992 +0.0182739999 -0.0101079997 0.0317259990 +0.0182739999 -0.0101079997 0.0182739999 +0.0182739999 -0.0101079997 0.0067260000 +0.0182739999 -0.0101079997 -0.0067260000 +0.0182739999 -0.0101079997 -0.0432740003 +0.0182739999 -0.0148919998 0.0317259990 +0.0182739999 -0.0148919998 0.0182739999 +0.0182739999 -0.0148919998 0.0067260000 +0.0182739999 -0.0148919998 -0.0067260000 +0.0182739999 -0.0148919998 -0.0432740003 +0.0182739999 -0.0182739999 0.0351080000 +0.0182739999 -0.0182739999 0.0148919998 +0.0182739999 -0.0182739999 0.0101079997 +0.0182739999 -0.0182739999 -0.0351080000 +0.0182739999 -0.0182739999 -0.0398919992 +0.0182739999 -0.0317259990 0.0351080000 +0.0182739999 -0.0317259990 0.0148919998 +0.0182739999 -0.0317259990 0.0101079997 +0.0182739999 -0.0317259990 -0.0101079997 +0.0182739999 -0.0317259990 -0.0148919998 +0.0182739999 -0.0317259990 -0.0351080000 +0.0182739999 -0.0317259990 -0.0398919992 +0.0182739999 -0.0351080000 0.0317259990 +0.0182739999 -0.0351080000 0.0182739999 +0.0182739999 -0.0351080000 0.0067260000 +0.0182739999 -0.0351080000 -0.0067260000 +0.0182739999 -0.0351080000 -0.0182739999 +0.0182739999 -0.0351080000 -0.0317259990 +0.0182739999 -0.0351080000 -0.0432740003 +0.0182739999 -0.0398919992 0.0317259990 +0.0182739999 -0.0398919992 0.0182739999 +0.0182739999 -0.0398919992 0.0067260000 +0.0182739999 -0.0398919992 -0.0067260000 +0.0182739999 -0.0398919992 -0.0182739999 +0.0182739999 -0.0432740003 0.0351080000 +0.0182739999 -0.0432740003 0.0148919998 +0.0182739999 -0.0432740003 0.0101079997 +0.0182739999 -0.0432740003 -0.0101079997 +0.0182739999 -0.0432740003 -0.0148919998 +0.0181559995 0.0401600003 -0.0068440000 +0.0181559995 0.0401600003 -0.0181559995 +0.0181510001 -0.0181510001 -0.0098299999 +0.0181389991 0.0068609999 -0.0098040001 +0.0181389991 -0.0068609999 -0.0098040001 +0.0181239992 0.0347750001 -0.0317060016 +0.0180600006 0.0403550006 0.0319399983 +0.0180600006 0.0403550006 0.0180600006 +0.0180600006 0.0403550006 0.0069400002 +0.0180520006 0.0096300002 0.0319480002 +0.0180520006 0.0096300002 0.0180520006 +0.0180520006 0.0096300002 0.0069479998 +0.0180430003 -0.0241240002 -0.0153879998 +0.0179270003 -0.0405989997 -0.0500000007 +0.0179130007 0.0500000007 0.0343750007 +0.0179130007 0.0500000007 0.0156250000 +0.0179130007 0.0500000007 0.0093750004 +0.0179130007 0.0500000007 -0.0093750004 +0.0179130007 0.0500000007 -0.0156250000 +0.0179130007 0.0500000007 -0.0343750007 +0.0179130007 0.0500000007 -0.0406249985 +0.0179130007 0.0406249985 -0.0500000007 +0.0179130007 0.0343750007 -0.0500000007 +0.0179130007 0.0156250000 -0.0500000007 +0.0179130007 0.0093750004 -0.0500000007 +0.0179130007 -0.0093750004 -0.0500000007 +0.0179130007 -0.0156250000 -0.0500000007 +0.0179130007 -0.0343750007 -0.0500000007 +0.0179130007 -0.0500000007 0.0343750007 +0.0179130007 -0.0500000007 0.0156250000 +0.0179130007 -0.0500000007 0.0093750004 +0.0179130007 -0.0500000007 -0.0093750004 +0.0179130007 -0.0500000007 -0.0156250000 +0.0179099999 -0.0406300016 -0.0270019993 +0.0177979991 0.0158159994 -0.0003910000 +0.0177149996 -0.0409450009 -0.0448740013 +0.0176970009 0.0426970012 0.0340280011 +0.0176970009 0.0426970012 0.0159719996 +0.0176970009 0.0426970012 0.0090279998 +0.0176970009 0.0426970012 -0.0090279998 +0.0176970009 0.0426970012 -0.0159719996 +0.0176970009 0.0426970012 -0.0340280011 +0.0176970009 0.0426970012 -0.0409720019 +0.0176970009 0.0409720019 -0.0323030017 +0.0176970009 0.0409720019 -0.0426970012 +0.0176970009 0.0340280011 -0.0323030017 +0.0176970009 0.0340280011 -0.0426970012 +0.0176970009 0.0323030017 -0.0340280011 +0.0176970009 0.0323030017 -0.0409720019 +0.0176970009 0.0176970009 -0.0340280011 +0.0176970009 0.0176970009 -0.0409720019 +0.0176970009 0.0159719996 -0.0073030000 +0.0176970009 0.0159719996 -0.0426970012 +0.0176970009 0.0090279998 -0.0073030000 +0.0176970009 0.0090279998 -0.0426970012 +0.0176970009 0.0073030000 0.0340280011 +0.0176970009 0.0073030000 0.0159719996 +0.0176970009 0.0073030000 0.0090279998 +0.0176970009 0.0073030000 -0.0340280011 +0.0176970009 0.0073030000 -0.0409720019 +0.0176970009 -0.0073030000 0.0340280011 +0.0176970009 -0.0073030000 0.0159719996 +0.0176970009 -0.0073030000 0.0090279998 +0.0176970009 -0.0073030000 -0.0340280011 +0.0176970009 -0.0073030000 -0.0409720019 +0.0176970009 -0.0090279998 0.0323030017 +0.0176970009 -0.0090279998 0.0176970009 +0.0176970009 -0.0090279998 0.0073030000 +0.0176970009 -0.0090279998 -0.0073030000 +0.0176970009 -0.0090279998 -0.0426970012 +0.0176970009 -0.0159719996 0.0323030017 +0.0176970009 -0.0159719996 0.0176970009 +0.0176970009 -0.0159719996 0.0073030000 +0.0176970009 -0.0159719996 -0.0073030000 +0.0176970009 -0.0159719996 -0.0426970012 +0.0176970009 -0.0176970009 0.0340280011 +0.0176970009 -0.0176970009 0.0159719996 +0.0176970009 -0.0176970009 0.0090279998 +0.0176970009 -0.0176970009 -0.0340280011 +0.0176970009 -0.0176970009 -0.0409720019 +0.0176970009 -0.0323030017 0.0340280011 +0.0176970009 -0.0323030017 0.0159719996 +0.0176970009 -0.0323030017 0.0090279998 +0.0176970009 -0.0323030017 -0.0090279998 +0.0176970009 -0.0323030017 -0.0159719996 +0.0176970009 -0.0323030017 -0.0340280011 +0.0176970009 -0.0323030017 -0.0409720019 +0.0176970009 -0.0340280011 0.0323030017 +0.0176970009 -0.0340280011 0.0176970009 +0.0176970009 -0.0340280011 0.0073030000 +0.0176970009 -0.0340280011 -0.0073030000 +0.0176970009 -0.0340280011 -0.0176970009 +0.0176970009 -0.0340280011 -0.0323030017 +0.0176970009 -0.0340280011 -0.0426970012 +0.0176970009 -0.0409720019 0.0323030017 +0.0176970009 -0.0409720019 0.0176970009 +0.0176970009 -0.0409720019 0.0073030000 +0.0176970009 -0.0409720019 -0.0073030000 +0.0176970009 -0.0409720019 -0.0176970009 +0.0176970009 -0.0426970012 0.0340280011 +0.0176970009 -0.0426970012 0.0159719996 +0.0176970009 -0.0426970012 0.0090279998 +0.0176970009 -0.0426970012 -0.0090279998 +0.0176970009 -0.0426970012 -0.0159719996 +0.0176139995 0.0410929993 -0.0073859999 +0.0176139995 0.0410929993 -0.0176139995 +0.0176110007 -0.0176110007 -0.0089020003 +0.0176020004 0.0073980000 -0.0088910004 +0.0176020004 -0.0073980000 -0.0088910004 +0.0175630003 0.0338359997 -0.0322320014 +0.0175500009 0.0411820002 0.0324500017 +0.0175500009 0.0411820002 0.0175500009 +0.0175500009 0.0411820002 0.0074499999 +0.0175460000 0.0088120000 0.0324539989 +0.0175460000 0.0088120000 0.0175460000 +0.0175460000 0.0088120000 0.0074539999 +0.0175080001 -0.0245670006 -0.0162390005 +0.0172819998 -0.0415240005 -0.0276289992 +0.0170699991 0.0167629998 -0.0329300016 +0.0170699991 0.0082369996 -0.0329300016 +0.0170699991 -0.0082369996 -0.0329300016 +0.0170699991 -0.0167629998 -0.0329300016 +0.0169920009 0.0169920009 -0.0081550004 +0.0169510003 -0.0418879986 -0.0456379987 +0.0169510003 -0.0418879986 -0.0500000007 +0.0169190001 0.0500000007 0.0330809988 +0.0169190001 0.0500000007 0.0169190001 +0.0169190001 0.0500000007 0.0080810003 +0.0169190001 0.0500000007 -0.0080810003 +0.0169190001 0.0500000007 -0.0169190001 +0.0169190001 0.0500000007 -0.0330809988 +0.0169190001 0.0500000007 -0.0419190004 +0.0169190001 0.0419190004 0.0330809988 +0.0169190001 0.0419190004 0.0169190001 +0.0169190001 0.0419190004 0.0080810003 +0.0169190001 0.0419190004 -0.0080810003 +0.0169190001 0.0419190004 -0.0169190001 +0.0169190001 0.0419190004 -0.0330809988 +0.0169190001 0.0419190004 -0.0419190004 +0.0169190001 0.0419190004 -0.0500000007 +0.0169190001 0.0330809988 -0.0330809988 +0.0169190001 0.0330809988 -0.0419190004 +0.0169190001 0.0330809988 -0.0500000007 +0.0169190001 0.0169190001 -0.0080810003 +0.0169190001 0.0169190001 -0.0330809988 +0.0169190001 0.0169190001 -0.0419190004 +0.0169190001 0.0169190001 -0.0500000007 +0.0169190001 0.0080810003 0.0330809988 +0.0169190001 0.0080810003 0.0169190001 +0.0169190001 0.0080810003 0.0080810003 +0.0169190001 0.0080810003 -0.0080810003 +0.0169190001 0.0080810003 -0.0330809988 +0.0169190001 0.0080810003 -0.0419190004 +0.0169190001 0.0080810003 -0.0500000007 +0.0169190001 -0.0080810003 0.0330809988 +0.0169190001 -0.0080810003 0.0169190001 +0.0169190001 -0.0080810003 0.0080810003 +0.0169190001 -0.0080810003 -0.0080810003 +0.0169190001 -0.0080810003 -0.0330809988 +0.0169190001 -0.0080810003 -0.0419190004 +0.0169190001 -0.0080810003 -0.0500000007 +0.0169190001 -0.0169190001 0.0330809988 +0.0169190001 -0.0169190001 0.0169190001 +0.0169190001 -0.0169190001 0.0080810003 +0.0169190001 -0.0169190001 -0.0080810003 +0.0169190001 -0.0169190001 -0.0330809988 +0.0169190001 -0.0169190001 -0.0419190004 +0.0169190001 -0.0169190001 -0.0500000007 +0.0169190001 -0.0330809988 0.0330809988 +0.0169190001 -0.0330809988 0.0169190001 +0.0169190001 -0.0330809988 0.0080810003 +0.0169190001 -0.0330809988 -0.0080810003 +0.0169190001 -0.0330809988 -0.0169190001 +0.0169190001 -0.0330809988 -0.0330809988 +0.0169190001 -0.0330809988 -0.0419190004 +0.0169190001 -0.0330809988 -0.0500000007 +0.0169190001 -0.0419190004 0.0330809988 +0.0169190001 -0.0419190004 0.0169190001 +0.0169190001 -0.0419190004 0.0080810003 +0.0169190001 -0.0419190004 -0.0080810003 +0.0169190001 -0.0419190004 -0.0169190001 +0.0169190001 -0.0500000007 0.0330809988 +0.0169190001 -0.0500000007 0.0169190001 +0.0169190001 -0.0500000007 0.0080810003 +0.0169190001 -0.0500000007 -0.0080810003 +0.0169190001 -0.0500000007 -0.0169190001 +0.0168450009 0.0169920009 -0.0003910000 +0.0168450009 0.0169920009 -0.0080080004 +0.0167970005 0.0329609998 -0.0003910000 +0.0167970005 0.0329609998 -0.0079610003 +0.0167970005 0.0329609998 -0.0170389991 +0.0167970005 0.0329609998 -0.0325759985 +0.0167970005 0.0318460017 -0.0328410007 +0.0167970005 0.0307030007 -0.0329300016 +0.0167970005 0.0170389991 -0.0003910000 +0.0167970005 0.0170389991 -0.0079610003 +0.0167970005 0.0170389991 -0.0170389991 +0.0167970005 0.0170389991 -0.0329300016 +0.0167970005 0.0079610003 -0.0170389991 +0.0167970005 0.0079610003 -0.0329300016 +0.0167970005 -0.0079610003 -0.0170389991 +0.0167970005 -0.0079610003 -0.0329300016 +0.0167970005 -0.0170389991 -0.0170389991 +0.0167970005 -0.0170389991 -0.0329300016 +0.0167970005 -0.0178120006 -0.0329300016 +0.0167970005 -0.0197230000 -0.0326780006 +0.0167970005 -0.0215039998 -0.0319410004 +0.0167970005 -0.0230330005 -0.0307669993 +0.0167970005 -0.0242059994 -0.0292380005 +0.0167970005 -0.0248659998 -0.0170389991 +0.0167970005 -0.0249439999 -0.0274580009 +0.0167970005 -0.0251129996 -0.0181159992 +0.0167970005 -0.0251950007 -0.0192189999 +0.0167970005 -0.0251950007 -0.0255469996 +0.0165100005 -0.0422939993 -0.0284020007 +0.0162470005 0.0074979998 0.0324979983 +0.0162470005 0.0074979998 0.0175020006 +0.0162470005 0.0074979998 0.0074979998 +0.0160179995 -0.0426659994 -0.0465699993 +0.0159719996 0.0426970012 0.0323030017 +0.0159719996 0.0426970012 0.0176970009 +0.0159719996 0.0426970012 0.0073030000 +0.0159719996 0.0426970012 -0.0073030000 +0.0159719996 0.0426970012 -0.0176970009 +0.0159719996 0.0426970012 -0.0323030017 +0.0159719996 0.0426970012 -0.0426970012 +0.0159719996 0.0323030017 -0.0323030017 +0.0159719996 0.0323030017 -0.0426970012 +0.0159719996 0.0176970009 -0.0323030017 +0.0159719996 0.0176970009 -0.0426970012 +0.0159719996 0.0073030000 -0.0073030000 +0.0159719996 0.0073030000 -0.0323030017 +0.0159719996 0.0073030000 -0.0426970012 +0.0159719996 -0.0073030000 0.0323030017 +0.0159719996 -0.0073030000 0.0176970009 +0.0159719996 -0.0073030000 0.0073030000 +0.0159719996 -0.0073030000 -0.0073030000 +0.0159719996 -0.0073030000 -0.0323030017 +0.0159719996 -0.0073030000 -0.0426970012 +0.0159719996 -0.0176970009 0.0323030017 +0.0159719996 -0.0176970009 0.0176970009 +0.0159719996 -0.0176970009 0.0073030000 +0.0159719996 -0.0176970009 -0.0073030000 +0.0159719996 -0.0176970009 -0.0323030017 +0.0159719996 -0.0176970009 -0.0426970012 +0.0159719996 -0.0323030017 0.0323030017 +0.0159719996 -0.0323030017 0.0176970009 +0.0159719996 -0.0323030017 0.0073030000 +0.0159719996 -0.0323030017 -0.0073030000 +0.0159719996 -0.0323030017 -0.0176970009 +0.0159719996 -0.0323030017 -0.0323030017 +0.0159719996 -0.0323030017 -0.0426970012 +0.0159719996 -0.0426970012 0.0323030017 +0.0159719996 -0.0426970012 0.0176970009 +0.0159719996 -0.0426970012 0.0073030000 +0.0159719996 -0.0426970012 -0.0073030000 +0.0159719996 -0.0426970012 -0.0176970009 +0.0158469994 0.0322219990 -0.0072220000 +0.0158469994 0.0322219990 -0.0177779999 +0.0158469994 0.0177779999 -0.0072220000 +0.0158469994 0.0177779999 -0.0177779999 +0.0158469994 0.0072220000 -0.0177779999 +0.0158469994 -0.0072220000 -0.0177779999 +0.0158469994 -0.0177779999 -0.0177779999 +0.0156759992 -0.0428830013 -0.0500000007 +0.0156250000 0.0500000007 0.0320869982 +0.0156250000 0.0500000007 0.0179130007 +0.0156250000 0.0500000007 0.0070870002 +0.0156250000 0.0500000007 -0.0070870002 +0.0156250000 0.0500000007 -0.0179130007 +0.0156250000 0.0500000007 -0.0320869982 +0.0156250000 0.0500000007 -0.0429130010 +0.0156250000 0.0429130010 -0.0500000007 +0.0156250000 0.0320869982 -0.0500000007 +0.0156250000 0.0179130007 -0.0500000007 +0.0156250000 0.0070870002 -0.0500000007 +0.0156250000 -0.0070870002 -0.0500000007 +0.0156250000 -0.0179130007 -0.0500000007 +0.0156250000 -0.0320869982 -0.0500000007 +0.0156250000 -0.0500000007 0.0320869982 +0.0156250000 -0.0500000007 0.0179130007 +0.0156250000 -0.0500000007 0.0070870002 +0.0156250000 -0.0500000007 -0.0070870002 +0.0156250000 -0.0500000007 -0.0179130007 +0.0156140001 -0.0429189987 -0.0292969998 +0.0155900000 0.0320670009 -0.0003910000 +0.0155229997 0.0179699995 -0.0003910000 +0.0154980002 0.0070159999 0.0320160016 +0.0154980002 0.0070159999 0.0179839991 +0.0154980002 0.0070159999 0.0070159999 +0.0149529995 -0.0432480015 -0.0476359986 +0.0148919998 0.0432740003 0.0317259990 +0.0148919998 0.0432740003 0.0182739999 +0.0148919998 0.0432740003 0.0067260000 +0.0148919998 0.0432740003 -0.0067260000 +0.0148919998 0.0432740003 -0.0182739999 +0.0148919998 0.0432740003 -0.0317259990 +0.0148919998 0.0432740003 -0.0432740003 +0.0148919998 0.0317259990 -0.0317259990 +0.0148919998 0.0317259990 -0.0432740003 +0.0148919998 0.0182739999 -0.0317259990 +0.0148919998 0.0182739999 -0.0432740003 +0.0148919998 0.0067260000 -0.0067260000 +0.0148919998 0.0067260000 -0.0317259990 +0.0148919998 0.0067260000 -0.0432740003 +0.0148919998 -0.0067260000 0.0317259990 +0.0148919998 -0.0067260000 0.0182739999 +0.0148919998 -0.0067260000 0.0067260000 +0.0148919998 -0.0067260000 -0.0067260000 +0.0148919998 -0.0067260000 -0.0317259990 +0.0148919998 -0.0067260000 -0.0432740003 +0.0148919998 -0.0182739999 0.0317259990 +0.0148919998 -0.0182739999 0.0182739999 +0.0148919998 -0.0182739999 0.0067260000 +0.0148919998 -0.0182739999 -0.0067260000 +0.0148919998 -0.0182739999 -0.0317259990 +0.0148919998 -0.0182739999 -0.0432740003 +0.0148919998 -0.0317259990 0.0317259990 +0.0148919998 -0.0317259990 0.0182739999 +0.0148919998 -0.0317259990 0.0067260000 +0.0148919998 -0.0317259990 -0.0067260000 +0.0148919998 -0.0317259990 -0.0182739999 +0.0148919998 -0.0317259990 -0.0317259990 +0.0148919998 -0.0317259990 -0.0432740003 +0.0148919998 -0.0432740003 0.0317259990 +0.0148919998 -0.0432740003 0.0182739999 +0.0148919998 -0.0432740003 0.0067260000 +0.0148919998 -0.0432740003 -0.0067260000 +0.0148919998 -0.0432740003 -0.0182739999 +0.0147730000 0.0316779986 -0.0066780001 +0.0147730000 0.0316779986 -0.0183220003 +0.0147730000 0.0183220003 -0.0066780001 +0.0147730000 0.0183220003 -0.0183220003 +0.0147730000 0.0066780001 -0.0183220003 +0.0147730000 -0.0066780001 -0.0183220003 +0.0147730000 -0.0183220003 -0.0183220003 +0.0146890003 0.0066459998 0.0316459984 +0.0146890003 0.0066459998 0.0183540005 +0.0146890003 0.0066459998 0.0066459998 +0.0146239996 -0.0433779992 -0.0302869994 +0.0142050004 0.0314869992 -0.0003910000 +0.0141890002 -0.0435170010 -0.0500000007 +0.0141179999 0.0500000007 0.0314630009 +0.0141179999 0.0500000007 0.0185369998 +0.0141179999 0.0500000007 0.0064630001 +0.0141179999 0.0500000007 -0.0064630001 +0.0141179999 0.0500000007 -0.0185369998 +0.0141179999 0.0500000007 -0.0314630009 +0.0141179999 0.0500000007 -0.0435369983 +0.0141179999 0.0435369983 -0.0500000007 +0.0141179999 0.0314630009 -0.0500000007 +0.0141179999 0.0185369998 -0.0500000007 +0.0141179999 0.0064630001 -0.0500000007 +0.0141179999 -0.0064630001 -0.0500000007 +0.0141179999 -0.0185369998 -0.0500000007 +0.0141179999 -0.0314630009 -0.0500000007 +0.0141179999 -0.0500000007 0.0314630009 +0.0141179999 -0.0500000007 0.0185369998 +0.0141179999 -0.0500000007 0.0064630001 +0.0141179999 -0.0500000007 -0.0064630001 +0.0141179999 -0.0500000007 -0.0185369998 +0.0140559999 0.0185529999 -0.0003910000 +0.0138349999 0.0063939998 0.0313940011 +0.0138349999 0.0063939998 0.0186059996 +0.0138349999 0.0063939998 0.0063939998 +0.0137949996 -0.0436140001 -0.0487929992 +0.0137189999 0.0436300002 0.0313699991 +0.0137189999 0.0436300002 0.0186299998 +0.0137189999 0.0436300002 0.0063700001 +0.0137189999 0.0436300002 -0.0063700001 +0.0137189999 0.0436300002 -0.0186299998 +0.0137189999 0.0436300002 -0.0313699991 +0.0137189999 0.0436300002 -0.0436300002 +0.0137189999 0.0313699991 -0.0313699991 +0.0137189999 0.0313699991 -0.0436300002 +0.0137189999 0.0186299998 -0.0313699991 +0.0137189999 0.0186299998 -0.0436300002 +0.0137189999 0.0063700001 -0.0063700001 +0.0137189999 0.0063700001 -0.0313699991 +0.0137189999 0.0063700001 -0.0436300002 +0.0137189999 -0.0063700001 0.0313699991 +0.0137189999 -0.0063700001 0.0186299998 +0.0137189999 -0.0063700001 0.0063700001 +0.0137189999 -0.0063700001 -0.0063700001 +0.0137189999 -0.0063700001 -0.0313699991 +0.0137189999 -0.0063700001 -0.0436300002 +0.0137189999 -0.0186299998 0.0313699991 +0.0137189999 -0.0186299998 0.0186299998 +0.0137189999 -0.0186299998 0.0063700001 +0.0137189999 -0.0186299998 -0.0063700001 +0.0137189999 -0.0186299998 -0.0313699991 +0.0137189999 -0.0186299998 -0.0436300002 +0.0137189999 -0.0313699991 0.0313699991 +0.0137189999 -0.0313699991 0.0186299998 +0.0137189999 -0.0313699991 0.0063700001 +0.0137189999 -0.0313699991 -0.0063700001 +0.0137189999 -0.0313699991 -0.0186299998 +0.0137189999 -0.0313699991 -0.0313699991 +0.0137189999 -0.0313699991 -0.0436300002 +0.0137189999 -0.0436300002 0.0313699991 +0.0137189999 -0.0436300002 0.0186299998 +0.0137189999 -0.0436300002 0.0063700001 +0.0137189999 -0.0436300002 -0.0063700001 +0.0137189999 -0.0436300002 -0.0186299998 +0.0136139998 0.0313500017 -0.0063499999 +0.0136139998 0.0313500017 -0.0186500009 +0.0136139998 0.0186500009 -0.0063499999 +0.0136139998 0.0186500009 -0.0186500009 +0.0136139998 0.0063499999 -0.0186500009 +0.0136139998 -0.0063499999 -0.0186500009 +0.0136139998 -0.0186500009 -0.0186500009 +0.0135690002 -0.0436579995 -0.0313419998 +0.0135690002 -0.0500000007 -0.0313419998 +0.0131130004 0.0437199995 0.0312799998 +0.0131130004 0.0437199995 0.0187199991 +0.0131130004 0.0437199995 0.0062799999 +0.0131130004 0.0437199995 -0.0062799999 +0.0131130004 0.0437199995 -0.0187199991 +0.0131130004 0.0437199995 -0.0312799998 +0.0131130004 0.0437199995 -0.0437199995 +0.0131130004 0.0312799998 -0.0312799998 +0.0131130004 0.0312799998 -0.0437199995 +0.0131130004 0.0187199991 -0.0312799998 +0.0131130004 0.0187199991 -0.0437199995 +0.0131130004 0.0062799999 -0.0062799999 +0.0131130004 0.0062799999 -0.0312799998 +0.0131130004 0.0062799999 -0.0437199995 +0.0131130004 -0.0062799999 0.0312799998 +0.0131130004 -0.0062799999 0.0187199991 +0.0131130004 -0.0062799999 0.0062799999 +0.0131130004 -0.0062799999 -0.0062799999 +0.0131130004 -0.0062799999 -0.0312799998 +0.0131130004 -0.0062799999 -0.0437199995 +0.0131130004 -0.0187199991 0.0312799998 +0.0131130004 -0.0187199991 0.0187199991 +0.0131130004 -0.0187199991 0.0062799999 +0.0131130004 -0.0187199991 -0.0062799999 +0.0131130004 -0.0187199991 -0.0312799998 +0.0131130004 -0.0187199991 -0.0437199995 +0.0131130004 -0.0312799998 0.0312799998 +0.0131130004 -0.0312799998 0.0187199991 +0.0131130004 -0.0312799998 0.0062799999 +0.0131130004 -0.0312799998 -0.0062799999 +0.0131130004 -0.0312799998 -0.0187199991 +0.0131130004 -0.0312799998 -0.0312799998 +0.0131130004 -0.0312799998 -0.0437199995 +0.0131130004 -0.0437199995 0.0312799998 +0.0131130004 -0.0437199995 0.0187199991 +0.0131130004 -0.0437199995 0.0062799999 +0.0131130004 -0.0437199995 -0.0062799999 +0.0131130004 -0.0437199995 -0.0187199991 +0.0130169997 0.0312709995 -0.0062710000 +0.0130169997 0.0312709995 -0.0187289994 +0.0130169997 0.0187289994 -0.0062710000 +0.0130169997 0.0187289994 -0.0187289994 +0.0130169997 0.0062710000 -0.0187289994 +0.0130169997 -0.0062710000 -0.0187289994 +0.0130169997 -0.0187289994 -0.0187289994 +0.0129540004 0.0062670000 0.0312669985 +0.0129540004 0.0062670000 0.0187330004 +0.0129540004 0.0062670000 0.0062670000 +0.0128260003 -0.0437409990 -0.0312590003 +0.0127219995 0.0312540010 -0.0003910000 +0.0125890002 -0.0437490009 -0.0500000007 +0.0125890002 -0.0500000007 -0.0500000007 +0.0125000002 0.0500000007 0.0312500000 +0.0125000002 0.0500000007 0.0187500007 +0.0125000002 0.0500000007 0.0062500001 +0.0125000002 0.0500000007 -0.0062500001 +0.0125000002 0.0500000007 -0.0187500007 +0.0125000002 0.0500000007 -0.0312500000 +0.0125000002 0.0500000007 -0.0437499993 +0.0125000002 0.0437499993 0.0312500000 +0.0125000002 0.0437499993 0.0187500007 +0.0125000002 0.0437499993 0.0062500001 +0.0125000002 0.0437499993 -0.0062500001 +0.0125000002 0.0437499993 -0.0187500007 +0.0125000002 0.0437499993 -0.0312500000 +0.0125000002 0.0437499993 -0.0437499993 +0.0125000002 0.0437499993 -0.0500000007 +0.0125000002 0.0312500000 -0.0312500000 +0.0125000002 0.0312500000 -0.0437499993 +0.0125000002 0.0312500000 -0.0500000007 +0.0125000002 0.0187500007 -0.0312500000 +0.0125000002 0.0187500007 -0.0437499993 +0.0125000002 0.0187500007 -0.0500000007 +0.0125000002 0.0062500001 -0.0062500001 +0.0125000002 0.0062500001 -0.0312500000 +0.0125000002 0.0062500001 -0.0437499993 +0.0125000002 0.0062500001 -0.0500000007 +0.0125000002 -0.0062500001 0.0312500000 +0.0125000002 -0.0062500001 0.0187500007 +0.0125000002 -0.0062500001 0.0062500001 +0.0125000002 -0.0062500001 -0.0062500001 +0.0125000002 -0.0062500001 -0.0312500000 +0.0125000002 -0.0062500001 -0.0437499993 +0.0125000002 -0.0062500001 -0.0500000007 +0.0125000002 -0.0187500007 0.0312500000 +0.0125000002 -0.0187500007 0.0187500007 +0.0125000002 -0.0187500007 0.0062500001 +0.0125000002 -0.0187500007 -0.0062500001 +0.0125000002 -0.0187500007 -0.0312500000 +0.0125000002 -0.0187500007 -0.0437499993 +0.0125000002 -0.0187500007 -0.0500000007 +0.0125000002 -0.0312500000 0.0312500000 +0.0125000002 -0.0312500000 0.0187500007 +0.0125000002 -0.0312500000 0.0062500001 +0.0125000002 -0.0312500000 -0.0062500001 +0.0125000002 -0.0312500000 -0.0187500007 +0.0125000002 -0.0312500000 -0.0312500000 +0.0125000002 -0.0312500000 -0.0437499993 +0.0125000002 -0.0312500000 -0.0500000007 +0.0125000002 -0.0437499993 0.0312500000 +0.0125000002 -0.0437499993 0.0187500007 +0.0125000002 -0.0437499993 0.0062500001 +0.0125000002 -0.0437499993 -0.0062500001 +0.0125000002 -0.0437499993 -0.0187500007 +0.0125000002 -0.0500000007 0.0312500000 +0.0125000002 -0.0500000007 0.0187500007 +0.0125000002 -0.0500000007 0.0062500001 +0.0125000002 -0.0500000007 -0.0062500001 +0.0125000002 -0.0500000007 -0.0187500007 +0.0124899996 0.0187500007 -0.0003910000 +0.0124150002 0.0312509984 -0.0062509999 +0.0124150002 0.0312509984 -0.0187490005 +0.0124150002 0.0187490005 -0.0062509999 +0.0124150002 0.0187490005 -0.0187490005 +0.0124150002 0.0062509999 -0.0187490005 +0.0124150002 -0.0062509999 -0.0187490005 +0.0124150002 -0.0187490005 -0.0187490005 +0.0120789995 -0.0437359996 -0.0312639996 +0.0120789995 -0.0500000007 -0.0312639996 +0.0120639997 0.0062650000 0.0312650017 +0.0120639997 0.0062650000 0.0187350009 +0.0120639997 0.0062650000 0.0062650000 +0.0118869999 0.0437199995 0.0312799998 +0.0118869999 0.0437199995 0.0187199991 +0.0118869999 0.0437199995 0.0062799999 +0.0118869999 0.0437199995 -0.0062799999 +0.0118869999 0.0437199995 -0.0187199991 +0.0118869999 0.0437199995 -0.0312799998 +0.0118869999 0.0437199995 -0.0437199995 +0.0118869999 0.0312799998 -0.0312799998 +0.0118869999 0.0312799998 -0.0437199995 +0.0118869999 0.0187199991 -0.0312799998 +0.0118869999 0.0187199991 -0.0437199995 +0.0118869999 0.0062799999 -0.0062799999 +0.0118869999 0.0062799999 -0.0312799998 +0.0118869999 0.0062799999 -0.0437199995 +0.0118869999 -0.0062799999 0.0312799998 +0.0118869999 -0.0062799999 0.0187199991 +0.0118869999 -0.0062799999 0.0062799999 +0.0118869999 -0.0062799999 -0.0062799999 +0.0118869999 -0.0062799999 -0.0312799998 +0.0118869999 -0.0062799999 -0.0437199995 +0.0118869999 -0.0187199991 0.0312799998 +0.0118869999 -0.0187199991 0.0187199991 +0.0118869999 -0.0187199991 0.0062799999 +0.0118869999 -0.0187199991 -0.0062799999 +0.0118869999 -0.0187199991 -0.0312799998 +0.0118869999 -0.0187199991 -0.0437199995 +0.0118869999 -0.0312799998 0.0312799998 +0.0118869999 -0.0312799998 0.0187199991 +0.0118869999 -0.0312799998 0.0062799999 +0.0118869999 -0.0312799998 -0.0062799999 +0.0118869999 -0.0312799998 -0.0187199991 +0.0118869999 -0.0312799998 -0.0312799998 +0.0118869999 -0.0312799998 -0.0437199995 +0.0118869999 -0.0437199995 0.0312799998 +0.0118869999 -0.0437199995 0.0187199991 +0.0118869999 -0.0437199995 0.0062799999 +0.0118869999 -0.0437199995 -0.0062799999 +0.0118869999 -0.0437199995 -0.0187199991 +0.0118129998 0.0312880017 -0.0062879999 +0.0118129998 0.0312880017 -0.0187120009 +0.0118129998 0.0187120009 -0.0062879999 +0.0118129998 0.0187120009 -0.0187120009 +0.0118129998 0.0062879999 -0.0187120009 +0.0118129998 -0.0062879999 -0.0187120009 +0.0118129998 -0.0187120009 -0.0187120009 +0.0113369999 -0.0436410010 -0.0313589983 +0.0112810005 0.0436300002 0.0313699991 +0.0112810005 0.0436300002 0.0186299998 +0.0112810005 0.0436300002 0.0063700001 +0.0112810005 0.0436300002 -0.0063700001 +0.0112810005 0.0436300002 -0.0186299998 +0.0112810005 0.0436300002 -0.0313699991 +0.0112810005 0.0436300002 -0.0436300002 +0.0112810005 0.0313699991 -0.0313699991 +0.0112810005 0.0313699991 -0.0436300002 +0.0112810005 0.0186299998 -0.0313699991 +0.0112810005 0.0186299998 -0.0436300002 +0.0112810005 0.0063700001 -0.0063700001 +0.0112810005 0.0063700001 -0.0313699991 +0.0112810005 0.0063700001 -0.0436300002 +0.0112810005 -0.0063700001 0.0313699991 +0.0112810005 -0.0063700001 0.0186299998 +0.0112810005 -0.0063700001 0.0063700001 +0.0112810005 -0.0063700001 -0.0063700001 +0.0112810005 -0.0063700001 -0.0313699991 +0.0112810005 -0.0063700001 -0.0436300002 +0.0112810005 -0.0186299998 0.0313699991 +0.0112810005 -0.0186299998 0.0186299998 +0.0112810005 -0.0186299998 0.0063700001 +0.0112810005 -0.0186299998 -0.0063700001 +0.0112810005 -0.0186299998 -0.0313699991 +0.0112810005 -0.0186299998 -0.0436300002 +0.0112810005 -0.0313699991 0.0313699991 +0.0112810005 -0.0313699991 0.0186299998 +0.0112810005 -0.0313699991 0.0063700001 +0.0112810005 -0.0313699991 -0.0063700001 +0.0112810005 -0.0313699991 -0.0186299998 +0.0112810005 -0.0313699991 -0.0313699991 +0.0112810005 -0.0313699991 -0.0436300002 +0.0112810005 -0.0436300002 0.0313699991 +0.0112810005 -0.0436300002 0.0186299998 +0.0112810005 -0.0436300002 0.0063700001 +0.0112810005 -0.0436300002 -0.0063700001 +0.0112810005 -0.0436300002 -0.0186299998 +0.0112260003 0.0313809998 -0.0003910000 +0.0112180002 0.0313830003 -0.0063829999 +0.0112180002 0.0313830003 -0.0186170004 +0.0112180002 0.0186170004 -0.0063829999 +0.0112180002 0.0186170004 -0.0186170004 +0.0112180002 0.0063829999 -0.0186170004 +0.0112180002 -0.0063829999 -0.0186170004 +0.0112180002 -0.0186170004 -0.0186170004 +0.0111830002 0.0063900002 0.0313900001 +0.0111830002 0.0063900002 0.0186100006 +0.0111830002 0.0063900002 0.0063900002 +0.0109249996 0.0185480006 -0.0003910000 +0.0108820004 0.0500000007 0.0314630009 +0.0108820004 0.0500000007 0.0185369998 +0.0108820004 0.0500000007 0.0064630001 +0.0108820004 0.0500000007 -0.0064630001 +0.0108820004 0.0500000007 -0.0185369998 +0.0108820004 0.0500000007 -0.0314630009 +0.0108820004 0.0500000007 -0.0435369983 +0.0108820004 0.0435369983 -0.0500000007 +0.0108820004 0.0314630009 -0.0500000007 +0.0108820004 0.0185369998 -0.0500000007 +0.0108820004 0.0064630001 -0.0500000007 +0.0108820004 -0.0064630001 -0.0500000007 +0.0108820004 -0.0185369998 -0.0500000007 +0.0108820004 -0.0314630009 -0.0500000007 +0.0108820004 -0.0500000007 0.0314630009 +0.0108820004 -0.0500000007 0.0185369998 +0.0108820004 -0.0500000007 0.0064630001 +0.0108820004 -0.0500000007 -0.0064630001 +0.0108820004 -0.0500000007 -0.0185369998 +0.0106130000 -0.0434579998 -0.0315419994 +0.0106130000 -0.0500000007 -0.0315419994 +0.0103280004 0.0066399998 0.0316400006 +0.0103280004 0.0066399998 0.0183600001 +0.0103280004 0.0066399998 0.0066399998 +0.0103280004 0.0066399998 -0.0003910000 +0.0101079997 0.0432740003 0.0317259990 +0.0101079997 0.0432740003 0.0182739999 +0.0101079997 0.0432740003 0.0067260000 +0.0101079997 0.0432740003 -0.0067260000 +0.0101079997 0.0432740003 -0.0182739999 +0.0101079997 0.0432740003 -0.0317259990 +0.0101079997 0.0432740003 -0.0432740003 +0.0101079997 0.0317259990 -0.0317259990 +0.0101079997 0.0317259990 -0.0432740003 +0.0101079997 0.0182739999 -0.0317259990 +0.0101079997 0.0182739999 -0.0432740003 +0.0101079997 0.0067260000 -0.0067260000 +0.0101079997 0.0067260000 -0.0317259990 +0.0101079997 0.0067260000 -0.0432740003 +0.0101079997 -0.0067260000 0.0317259990 +0.0101079997 -0.0067260000 0.0182739999 +0.0101079997 -0.0067260000 0.0067260000 +0.0101079997 -0.0067260000 -0.0067260000 +0.0101079997 -0.0067260000 -0.0317259990 +0.0101079997 -0.0067260000 -0.0432740003 +0.0101079997 -0.0182739999 0.0317259990 +0.0101079997 -0.0182739999 0.0182739999 +0.0101079997 -0.0182739999 0.0067260000 +0.0101079997 -0.0182739999 -0.0067260000 +0.0101079997 -0.0182739999 -0.0317259990 +0.0101079997 -0.0182739999 -0.0432740003 +0.0101079997 -0.0317259990 0.0317259990 +0.0101079997 -0.0317259990 0.0182739999 +0.0101079997 -0.0317259990 0.0067260000 +0.0101079997 -0.0317259990 -0.0067260000 +0.0101079997 -0.0317259990 -0.0182739999 +0.0101079997 -0.0317259990 -0.0317259990 +0.0101079997 -0.0317259990 -0.0432740003 +0.0101079997 -0.0432740003 0.0317259990 +0.0101079997 -0.0432740003 0.0182739999 +0.0101079997 -0.0432740003 0.0067260000 +0.0101079997 -0.0432740003 -0.0067260000 +0.0101079997 -0.0432740003 -0.0182739999 +0.0100689996 0.0317419991 -0.0067420001 +0.0100689996 0.0317419991 -0.0182579998 +0.0100689996 0.0182579998 -0.0067420001 +0.0100689996 0.0182579998 -0.0182579998 +0.0100689996 0.0067420001 -0.0182579998 +0.0100689996 -0.0067420001 -0.0182579998 +0.0100689996 -0.0182579998 -0.0182579998 +0.0099149998 -0.0431899987 -0.0318100005 +0.0098029999 0.0318619981 -0.0003910000 +0.0094659999 0.0061420002 0.0320359990 +0.0094659999 0.0061420002 0.0179639999 +0.0094659999 0.0061420002 0.0070360000 +0.0094600003 0.0179609992 -0.0003910000 +0.0093750004 0.0500000007 0.0320869982 +0.0093750004 0.0500000007 0.0179130007 +0.0093750004 0.0500000007 0.0070870002 +0.0093750004 0.0500000007 -0.0070870002 +0.0093750004 0.0500000007 -0.0179130007 +0.0093750004 0.0500000007 -0.0320869982 +0.0093750004 0.0500000007 -0.0429130010 +0.0093750004 0.0429130010 -0.0500000007 +0.0093750004 0.0320869982 -0.0500000007 +0.0093750004 0.0179130007 -0.0500000007 +0.0093750004 0.0070870002 -0.0500000007 +0.0093750004 -0.0070870002 -0.0500000007 +0.0093750004 -0.0179130007 -0.0500000007 +0.0093750004 -0.0320869982 -0.0500000007 +0.0093750004 -0.0500000007 0.0320869982 +0.0093750004 -0.0500000007 0.0179130007 +0.0093750004 -0.0500000007 0.0070870002 +0.0093750004 -0.0500000007 -0.0070870002 +0.0093750004 -0.0500000007 -0.0179130007 +0.0092540001 -0.0428409986 -0.0321590006 +0.0092540001 -0.0500000007 -0.0321590006 +0.0090279998 0.0426970012 0.0323030017 +0.0090279998 0.0426970012 0.0176970009 +0.0090279998 0.0426970012 0.0073030000 +0.0090279998 0.0426970012 -0.0073030000 +0.0090279998 0.0426970012 -0.0176970009 +0.0090279998 0.0426970012 -0.0323030017 +0.0090279998 0.0426970012 -0.0426970012 +0.0090279998 0.0323030017 -0.0323030017 +0.0090279998 0.0323030017 -0.0426970012 +0.0090279998 0.0176970009 -0.0323030017 +0.0090279998 0.0176970009 -0.0426970012 +0.0090279998 0.0073030000 -0.0073030000 +0.0090279998 0.0073030000 -0.0323030017 +0.0090279998 0.0073030000 -0.0426970012 +0.0090279998 -0.0073030000 0.0323030017 +0.0090279998 -0.0073030000 0.0176970009 +0.0090279998 -0.0073030000 0.0073030000 +0.0090279998 -0.0073030000 -0.0073030000 +0.0090279998 -0.0073030000 -0.0323030017 +0.0090279998 -0.0073030000 -0.0426970012 +0.0090279998 -0.0176970009 0.0323030017 +0.0090279998 -0.0176970009 0.0176970009 +0.0090279998 -0.0176970009 0.0073030000 +0.0090279998 -0.0176970009 -0.0073030000 +0.0090279998 -0.0176970009 -0.0323030017 +0.0090279998 -0.0176970009 -0.0426970012 +0.0090279998 -0.0323030017 0.0323030017 +0.0090279998 -0.0323030017 0.0176970009 +0.0090279998 -0.0323030017 0.0073030000 +0.0090279998 -0.0323030017 -0.0073030000 +0.0090279998 -0.0323030017 -0.0176970009 +0.0090279998 -0.0323030017 -0.0323030017 +0.0090279998 -0.0323030017 -0.0426970012 +0.0090279998 -0.0426970012 0.0323030017 +0.0090279998 -0.0426970012 0.0176970009 +0.0090279998 -0.0426970012 0.0073030000 +0.0090279998 -0.0426970012 -0.0073030000 +0.0090279998 -0.0426970012 -0.0176970009 +0.0090100002 0.0323150009 -0.0073150001 +0.0090100002 0.0323150009 -0.0176849999 +0.0090100002 0.0176849999 -0.0073150001 +0.0090100002 0.0176849999 -0.0176849999 +0.0090100002 0.0073150001 -0.0176849999 +0.0090100002 -0.0073150001 -0.0176849999 +0.0090100002 -0.0176849999 -0.0176849999 +0.0089290002 0.0073699998 -0.0003910000 +0.0086740004 0.0056840000 0.0325580016 +0.0086740004 0.0056840000 0.0174419992 +0.0086740004 0.0056840000 0.0075579998 +0.0085359998 0.0326679982 0.0326679982 +0.0085359998 0.0326679982 0.0173320007 +0.0085359998 0.0326679982 0.0076680002 +0.0085359998 0.0326679982 -0.0003910000 +0.0081890002 0.0170249995 -0.0003910000 +0.0080810003 0.0500000007 0.0330809988 +0.0080810003 0.0500000007 0.0169190001 +0.0080810003 0.0500000007 0.0080810003 +0.0080810003 0.0500000007 -0.0080810003 +0.0080810003 0.0500000007 -0.0169190001 +0.0080810003 0.0500000007 -0.0330809988 +0.0080810003 0.0500000007 -0.0419190004 +0.0080810003 0.0419190004 0.0330809988 +0.0080810003 0.0419190004 0.0169190001 +0.0080810003 0.0419190004 0.0080810003 +0.0080810003 0.0419190004 -0.0080810003 +0.0080810003 0.0419190004 -0.0169190001 +0.0080810003 0.0419190004 -0.0330809988 +0.0080810003 0.0419190004 -0.0419190004 +0.0080810003 0.0419190004 -0.0500000007 +0.0080810003 0.0330809988 0.0330809988 +0.0080810003 0.0330809988 0.0169190001 +0.0080810003 0.0330809988 0.0080810003 +0.0080810003 0.0330809988 -0.0080810003 +0.0080810003 0.0330809988 -0.0169190001 +0.0080810003 0.0330809988 -0.0330809988 +0.0080810003 0.0330809988 -0.0419190004 +0.0080810003 0.0330809988 -0.0500000007 +0.0080810003 0.0169190001 -0.0080810003 +0.0080810003 0.0169190001 -0.0169190001 +0.0080810003 0.0169190001 -0.0330809988 +0.0080810003 0.0169190001 -0.0419190004 +0.0080810003 0.0169190001 -0.0500000007 +0.0080810003 0.0080810003 -0.0080810003 +0.0080810003 0.0080810003 -0.0169190001 +0.0080810003 0.0080810003 -0.0330809988 +0.0080810003 0.0080810003 -0.0419190004 +0.0080810003 0.0080810003 -0.0500000007 +0.0080810003 -0.0080810003 0.0330809988 +0.0080810003 -0.0080810003 0.0169190001 +0.0080810003 -0.0080810003 0.0080810003 +0.0080810003 -0.0080810003 -0.0080810003 +0.0080810003 -0.0080810003 -0.0169190001 +0.0080810003 -0.0080810003 -0.0330809988 +0.0080810003 -0.0080810003 -0.0419190004 +0.0080810003 -0.0080810003 -0.0500000007 +0.0080810003 -0.0169190001 0.0330809988 +0.0080810003 -0.0169190001 0.0169190001 +0.0080810003 -0.0169190001 0.0080810003 +0.0080810003 -0.0169190001 -0.0080810003 +0.0080810003 -0.0169190001 -0.0169190001 +0.0080810003 -0.0169190001 -0.0330809988 +0.0080810003 -0.0169190001 -0.0419190004 +0.0080810003 -0.0169190001 -0.0500000007 +0.0080810003 -0.0330809988 0.0330809988 +0.0080810003 -0.0330809988 0.0169190001 +0.0080810003 -0.0330809988 0.0080810003 +0.0080810003 -0.0330809988 -0.0080810003 +0.0080810003 -0.0330809988 -0.0169190001 +0.0080810003 -0.0330809988 -0.0330809988 +0.0080810003 -0.0330809988 -0.0419190004 +0.0080810003 -0.0330809988 -0.0500000007 +0.0080810003 -0.0419190004 0.0330809988 +0.0080810003 -0.0419190004 0.0169190001 +0.0080810003 -0.0419190004 0.0080810003 +0.0080810003 -0.0419190004 -0.0080810003 +0.0080810003 -0.0419190004 -0.0169190001 +0.0080810003 -0.0419190004 -0.0330809988 +0.0080810003 -0.0500000007 0.0330809988 +0.0080810003 -0.0500000007 0.0169190001 +0.0080810003 -0.0500000007 0.0080810003 +0.0080810003 -0.0500000007 -0.0080810003 +0.0080810003 -0.0500000007 -0.0169190001 +0.0080810003 -0.0500000007 -0.0330809988 +0.0079690004 0.0052780001 0.0331950001 +0.0079690004 0.0052780001 0.0168050006 +0.0079690004 0.0052780001 0.0081949998 +0.0078480002 0.0322710015 0.0333260000 +0.0078480002 0.0322710015 0.0166740008 +0.0078480002 0.0322710015 0.0083259996 +0.0077579999 0.0084279999 -0.0003910000 +0.0075530000 0.0325529985 0.0336810015 +0.0075530000 0.0325529985 0.0163189992 +0.0075530000 0.0325529985 0.0086810002 +0.0073699998 0.0049319998 0.0339299999 +0.0073699998 0.0049319998 0.0160700008 +0.0073699998 0.0049319998 0.0089299995 +0.0073030000 0.0426970012 0.0340280011 +0.0073030000 0.0426970012 0.0159719996 +0.0073030000 0.0426970012 0.0090279998 +0.0073030000 0.0426970012 -0.0090279998 +0.0073030000 0.0426970012 -0.0159719996 +0.0073030000 0.0426970012 -0.0340280011 +0.0073030000 0.0426970012 -0.0409720019 +0.0073030000 0.0409720019 0.0323030017 +0.0073030000 0.0409720019 0.0176970009 +0.0073030000 0.0409720019 0.0073030000 +0.0073030000 0.0409720019 -0.0073030000 +0.0073030000 0.0409720019 -0.0176970009 +0.0073030000 0.0409720019 -0.0323030017 +0.0073030000 0.0409720019 -0.0426970012 +0.0073030000 0.0340280011 0.0323030017 +0.0073030000 0.0340280011 0.0176970009 +0.0073030000 0.0340280011 0.0073030000 +0.0073030000 0.0340280011 -0.0073030000 +0.0073030000 0.0340280011 -0.0176970009 +0.0073030000 0.0340280011 -0.0323030017 +0.0073030000 0.0340280011 -0.0426970012 +0.0073030000 0.0323030017 -0.0090279998 +0.0073030000 0.0323030017 -0.0159719996 +0.0073030000 0.0323030017 -0.0340280011 +0.0073030000 0.0323030017 -0.0409720019 +0.0073030000 0.0176970009 -0.0090279998 +0.0073030000 0.0176970009 -0.0159719996 +0.0073030000 0.0176970009 -0.0340280011 +0.0073030000 0.0176970009 -0.0409720019 +0.0073030000 0.0159719996 -0.0073030000 +0.0073030000 0.0159719996 -0.0176970009 +0.0073030000 0.0159719996 -0.0323030017 +0.0073030000 0.0159719996 -0.0426970012 +0.0073030000 0.0090279998 -0.0073030000 +0.0073030000 0.0090279998 -0.0176970009 +0.0073030000 0.0090279998 -0.0323030017 +0.0073030000 0.0090279998 -0.0426970012 +0.0073030000 0.0073030000 -0.0090279998 +0.0073030000 0.0073030000 -0.0159719996 +0.0073030000 0.0073030000 -0.0340280011 +0.0073030000 0.0073030000 -0.0409720019 +0.0073030000 -0.0073030000 0.0340280011 +0.0073030000 -0.0073030000 0.0159719996 +0.0073030000 -0.0073030000 0.0090279998 +0.0073030000 -0.0073030000 -0.0090279998 +0.0073030000 -0.0073030000 -0.0159719996 +0.0073030000 -0.0073030000 -0.0340280011 +0.0073030000 -0.0073030000 -0.0409720019 +0.0073030000 -0.0090279998 0.0323030017 +0.0073030000 -0.0090279998 0.0176970009 +0.0073030000 -0.0090279998 0.0073030000 +0.0073030000 -0.0090279998 -0.0073030000 +0.0073030000 -0.0090279998 -0.0176970009 +0.0073030000 -0.0090279998 -0.0323030017 +0.0073030000 -0.0090279998 -0.0426970012 +0.0073030000 -0.0159719996 0.0323030017 +0.0073030000 -0.0159719996 0.0176970009 +0.0073030000 -0.0159719996 0.0073030000 +0.0073030000 -0.0159719996 -0.0073030000 +0.0073030000 -0.0159719996 -0.0176970009 +0.0073030000 -0.0159719996 -0.0323030017 +0.0073030000 -0.0159719996 -0.0426970012 +0.0073030000 -0.0176970009 0.0340280011 +0.0073030000 -0.0176970009 0.0159719996 +0.0073030000 -0.0176970009 0.0090279998 +0.0073030000 -0.0176970009 -0.0090279998 +0.0073030000 -0.0176970009 -0.0159719996 +0.0073030000 -0.0176970009 -0.0340280011 +0.0073030000 -0.0176970009 -0.0409720019 +0.0073030000 -0.0323030017 0.0340280011 +0.0073030000 -0.0323030017 0.0159719996 +0.0073030000 -0.0323030017 0.0090279998 +0.0073030000 -0.0323030017 -0.0090279998 +0.0073030000 -0.0323030017 -0.0159719996 +0.0073030000 -0.0323030017 -0.0340280011 +0.0073030000 -0.0323030017 -0.0409720019 +0.0073030000 -0.0340280011 0.0323030017 +0.0073030000 -0.0340280011 0.0176970009 +0.0073030000 -0.0340280011 0.0073030000 +0.0073030000 -0.0340280011 -0.0073030000 +0.0073030000 -0.0340280011 -0.0176970009 +0.0073030000 -0.0340280011 -0.0323030017 +0.0073030000 -0.0340280011 -0.0426970012 +0.0073030000 -0.0409720019 0.0323030017 +0.0073030000 -0.0409720019 0.0176970009 +0.0073030000 -0.0409720019 0.0073030000 +0.0073030000 -0.0409720019 -0.0073030000 +0.0073030000 -0.0409720019 -0.0176970009 +0.0073030000 -0.0409720019 -0.0323030017 +0.0073030000 -0.0426970012 0.0340280011 +0.0073030000 -0.0426970012 0.0159719996 +0.0073030000 -0.0426970012 0.0090279998 +0.0073030000 -0.0426970012 -0.0090279998 +0.0073030000 -0.0426970012 -0.0159719996 +0.0072679999 0.0319360010 0.0340819992 +0.0072679999 0.0319360010 0.0159179997 +0.0072679999 0.0319360010 0.0090819998 +0.0071930001 0.0158009995 -0.0003910000 +0.0071589998 -0.0428409986 -0.0342539996 +0.0071589998 -0.0500000007 -0.0342539996 +0.0071060001 0.0321060009 0.0343430005 +0.0071060001 0.0321060009 0.0156570002 +0.0071060001 0.0321060009 0.0093430001 +0.0070870002 0.0500000007 0.0343750007 +0.0070870002 0.0500000007 0.0156250000 +0.0070870002 0.0500000007 0.0093750004 +0.0070870002 0.0500000007 -0.0093750004 +0.0070870002 0.0500000007 -0.0156250000 +0.0070870002 0.0500000007 -0.0343750007 +0.0070870002 0.0500000007 -0.0406249985 +0.0070870002 0.0406249985 -0.0500000007 +0.0070870002 0.0343750007 -0.0500000007 +0.0070870002 0.0156250000 -0.0500000007 +0.0070870002 0.0093750004 -0.0500000007 +0.0070870002 -0.0093750004 -0.0500000007 +0.0070870002 -0.0156250000 -0.0500000007 +0.0070870002 -0.0343750007 -0.0500000007 +0.0070870002 -0.0500000007 0.0343750007 +0.0070870002 -0.0500000007 0.0156250000 +0.0070870002 -0.0500000007 0.0093750004 +0.0070870002 -0.0500000007 -0.0093750004 +0.0070870002 -0.0500000007 -0.0156250000 +0.0068890001 0.0097460002 -0.0003910000 +0.0068890001 0.0046540000 0.0347479992 +0.0068890001 0.0046540000 0.0152519997 +0.0068890001 0.0046540000 0.0097479997 +0.0068100002 -0.0431899987 -0.0349150002 +0.0068089999 0.0316709988 0.0349159986 +0.0068089999 0.0316709988 0.0150840003 +0.0068089999 0.0316709988 0.0099160001 +0.0067469999 0.0317469984 0.0350570008 +0.0067469999 0.0317469984 0.0149429999 +0.0067469999 0.0317469984 0.0100570004 +0.0067260000 0.0432740003 0.0351080000 +0.0067260000 0.0432740003 0.0148919998 +0.0067260000 0.0432740003 0.0101079997 +0.0067260000 0.0432740003 -0.0101079997 +0.0067260000 0.0432740003 -0.0148919998 +0.0067260000 0.0432740003 -0.0351080000 +0.0067260000 0.0432740003 -0.0398919992 +0.0067260000 0.0398919992 0.0317259990 +0.0067260000 0.0398919992 0.0182739999 +0.0067260000 0.0398919992 0.0067260000 +0.0067260000 0.0398919992 -0.0067260000 +0.0067260000 0.0398919992 -0.0182739999 +0.0067260000 0.0398919992 -0.0317259990 +0.0067260000 0.0398919992 -0.0432740003 +0.0067260000 0.0351080000 0.0317259990 +0.0067260000 0.0351080000 0.0182739999 +0.0067260000 0.0351080000 0.0067260000 +0.0067260000 0.0351080000 -0.0067260000 +0.0067260000 0.0351080000 -0.0182739999 +0.0067260000 0.0351080000 -0.0317259990 +0.0067260000 0.0351080000 -0.0432740003 +0.0067260000 0.0317259990 -0.0101079997 +0.0067260000 0.0317259990 -0.0148919998 +0.0067260000 0.0317259990 -0.0351080000 +0.0067260000 0.0317259990 -0.0398919992 +0.0067260000 0.0182739999 -0.0101079997 +0.0067260000 0.0182739999 -0.0148919998 +0.0067260000 0.0182739999 -0.0351080000 +0.0067260000 0.0182739999 -0.0398919992 +0.0067260000 0.0148919998 -0.0067260000 +0.0067260000 0.0148919998 -0.0182739999 +0.0067260000 0.0148919998 -0.0317259990 +0.0067260000 0.0148919998 -0.0432740003 +0.0067260000 0.0101079997 -0.0067260000 +0.0067260000 0.0101079997 -0.0182739999 +0.0067260000 0.0101079997 -0.0317259990 +0.0067260000 0.0101079997 -0.0432740003 +0.0067260000 0.0067260000 -0.0101079997 +0.0067260000 0.0067260000 -0.0148919998 +0.0067260000 0.0067260000 -0.0351080000 +0.0067260000 0.0067260000 -0.0398919992 +0.0067260000 -0.0067260000 0.0351080000 +0.0067260000 -0.0067260000 0.0148919998 +0.0067260000 -0.0067260000 0.0101079997 +0.0067260000 -0.0067260000 -0.0101079997 +0.0067260000 -0.0067260000 -0.0148919998 +0.0067260000 -0.0067260000 -0.0351080000 +0.0067260000 -0.0067260000 -0.0398919992 +0.0067260000 -0.0101079997 0.0317259990 +0.0067260000 -0.0101079997 0.0182739999 +0.0067260000 -0.0101079997 0.0067260000 +0.0067260000 -0.0101079997 -0.0067260000 +0.0067260000 -0.0101079997 -0.0182739999 +0.0067260000 -0.0101079997 -0.0317259990 +0.0067260000 -0.0101079997 -0.0432740003 +0.0067260000 -0.0148919998 0.0317259990 +0.0067260000 -0.0148919998 0.0182739999 +0.0067260000 -0.0148919998 0.0067260000 +0.0067260000 -0.0148919998 -0.0067260000 +0.0067260000 -0.0148919998 -0.0182739999 +0.0067260000 -0.0148919998 -0.0317259990 +0.0067260000 -0.0148919998 -0.0432740003 +0.0067260000 -0.0182739999 0.0351080000 +0.0067260000 -0.0182739999 0.0148919998 +0.0067260000 -0.0182739999 0.0101079997 +0.0067260000 -0.0182739999 -0.0101079997 +0.0067260000 -0.0182739999 -0.0148919998 +0.0067260000 -0.0182739999 -0.0351080000 +0.0067260000 -0.0182739999 -0.0398919992 +0.0067260000 -0.0317259990 0.0351080000 +0.0067260000 -0.0317259990 0.0148919998 +0.0067260000 -0.0317259990 0.0101079997 +0.0067260000 -0.0317259990 -0.0101079997 +0.0067260000 -0.0317259990 -0.0148919998 +0.0067260000 -0.0317259990 -0.0351080000 +0.0067260000 -0.0317259990 -0.0398919992 +0.0067260000 -0.0351080000 0.0317259990 +0.0067260000 -0.0351080000 0.0182739999 +0.0067260000 -0.0351080000 0.0067260000 +0.0067260000 -0.0351080000 -0.0067260000 +0.0067260000 -0.0351080000 -0.0182739999 +0.0067260000 -0.0351080000 -0.0317259990 +0.0067260000 -0.0351080000 -0.0432740003 +0.0067260000 -0.0398919992 0.0317259990 +0.0067260000 -0.0398919992 0.0182739999 +0.0067260000 -0.0398919992 0.0067260000 +0.0067260000 -0.0398919992 -0.0067260000 +0.0067260000 -0.0398919992 -0.0182739999 +0.0067260000 -0.0398919992 -0.0317259990 +0.0067260000 -0.0432740003 0.0351080000 +0.0067260000 -0.0432740003 0.0148919998 +0.0067260000 -0.0432740003 0.0101079997 +0.0067260000 -0.0432740003 -0.0101079997 +0.0067260000 -0.0432740003 -0.0148919998 +0.0065420000 -0.0434579998 -0.0356130004 +0.0065420000 -0.0500000007 -0.0356130004 +0.0065370002 0.0044499999 0.0356290005 +0.0065370002 0.0044499999 0.0143710002 +0.0065370002 0.0044499999 0.0106290001 +0.0065350002 0.0143670002 -0.0003910000 +0.0064829998 0.0314829983 0.0358109996 +0.0064829998 0.0314829983 0.0141890002 +0.0064829998 0.0314829983 0.0108110001 +0.0064630001 0.0500000007 0.0358819999 +0.0064630001 0.0500000007 0.0141179999 +0.0064630001 0.0500000007 0.0108820004 +0.0064630001 0.0500000007 -0.0108820004 +0.0064630001 0.0500000007 -0.0141179999 +0.0064630001 0.0500000007 -0.0358819999 +0.0064630001 0.0500000007 -0.0391179994 +0.0064630001 0.0391179994 -0.0500000007 +0.0064630001 0.0358819999 -0.0500000007 +0.0064630001 0.0141179999 -0.0500000007 +0.0064630001 0.0108820004 -0.0500000007 +0.0064630001 -0.0108820004 -0.0500000007 +0.0064630001 -0.0141179999 -0.0500000007 +0.0064630001 -0.0358819999 -0.0500000007 +0.0064630001 -0.0500000007 0.0358819999 +0.0064630001 -0.0500000007 0.0141179999 +0.0064630001 -0.0500000007 0.0108820004 +0.0064630001 -0.0500000007 -0.0108820004 +0.0064630001 -0.0500000007 -0.0141179999 +0.0063780001 0.0112389997 -0.0003910000 +0.0063700001 0.0436300002 0.0362810008 +0.0063700001 0.0436300002 0.0137189999 +0.0063700001 0.0436300002 0.0112810005 +0.0063700001 0.0436300002 -0.0112810005 +0.0063700001 0.0436300002 -0.0137189999 +0.0063700001 0.0436300002 -0.0362810008 +0.0063700001 0.0436300002 -0.0387189984 +0.0063700001 0.0387189984 0.0313699991 +0.0063700001 0.0387189984 0.0186299998 +0.0063700001 0.0387189984 0.0063700001 +0.0063700001 0.0387189984 -0.0063700001 +0.0063700001 0.0387189984 -0.0186299998 +0.0063700001 0.0387189984 -0.0313699991 +0.0063700001 0.0387189984 -0.0436300002 +0.0063700001 0.0362810008 0.0313699991 +0.0063700001 0.0362810008 0.0186299998 +0.0063700001 0.0362810008 0.0063700001 +0.0063700001 0.0362810008 -0.0063700001 +0.0063700001 0.0362810008 -0.0186299998 +0.0063700001 0.0362810008 -0.0313699991 +0.0063700001 0.0362810008 -0.0436300002 +0.0063700001 0.0313699991 -0.0112810005 +0.0063700001 0.0313699991 -0.0137189999 +0.0063700001 0.0313699991 -0.0362810008 +0.0063700001 0.0313699991 -0.0387189984 +0.0063700001 0.0186299998 -0.0112810005 +0.0063700001 0.0186299998 -0.0137189999 +0.0063700001 0.0186299998 -0.0362810008 +0.0063700001 0.0186299998 -0.0387189984 +0.0063700001 0.0137189999 -0.0063700001 +0.0063700001 0.0137189999 -0.0186299998 +0.0063700001 0.0137189999 -0.0313699991 +0.0063700001 0.0137189999 -0.0436300002 +0.0063700001 0.0112810005 -0.0063700001 +0.0063700001 0.0112810005 -0.0186299998 +0.0063700001 0.0112810005 -0.0313699991 +0.0063700001 0.0112810005 -0.0436300002 +0.0063700001 0.0063700001 -0.0112810005 +0.0063700001 0.0063700001 -0.0137189999 +0.0063700001 0.0063700001 -0.0362810008 +0.0063700001 0.0063700001 -0.0387189984 +0.0063700001 -0.0063700001 0.0362810008 +0.0063700001 -0.0063700001 0.0137189999 +0.0063700001 -0.0063700001 0.0112810005 +0.0063700001 -0.0063700001 -0.0112810005 +0.0063700001 -0.0063700001 -0.0137189999 +0.0063700001 -0.0063700001 -0.0362810008 +0.0063700001 -0.0063700001 -0.0387189984 +0.0063700001 -0.0112810005 0.0313699991 +0.0063700001 -0.0112810005 0.0186299998 +0.0063700001 -0.0112810005 0.0063700001 +0.0063700001 -0.0112810005 -0.0063700001 +0.0063700001 -0.0112810005 -0.0186299998 +0.0063700001 -0.0112810005 -0.0313699991 +0.0063700001 -0.0112810005 -0.0436300002 +0.0063700001 -0.0137189999 0.0313699991 +0.0063700001 -0.0137189999 0.0186299998 +0.0063700001 -0.0137189999 0.0063700001 +0.0063700001 -0.0137189999 -0.0063700001 +0.0063700001 -0.0137189999 -0.0186299998 +0.0063700001 -0.0137189999 -0.0313699991 +0.0063700001 -0.0137189999 -0.0436300002 +0.0063700001 -0.0186299998 0.0362810008 +0.0063700001 -0.0186299998 0.0137189999 +0.0063700001 -0.0186299998 0.0112810005 +0.0063700001 -0.0186299998 -0.0112810005 +0.0063700001 -0.0186299998 -0.0137189999 +0.0063700001 -0.0186299998 -0.0362810008 +0.0063700001 -0.0186299998 -0.0387189984 +0.0063700001 -0.0313699991 0.0362810008 +0.0063700001 -0.0313699991 0.0137189999 +0.0063700001 -0.0313699991 0.0112810005 +0.0063700001 -0.0313699991 -0.0112810005 +0.0063700001 -0.0313699991 -0.0137189999 +0.0063700001 -0.0313699991 -0.0362810008 +0.0063700001 -0.0313699991 -0.0387189984 +0.0063700001 -0.0362810008 0.0313699991 +0.0063700001 -0.0362810008 0.0186299998 +0.0063700001 -0.0362810008 0.0063700001 +0.0063700001 -0.0362810008 -0.0063700001 +0.0063700001 -0.0362810008 -0.0186299998 +0.0063700001 -0.0362810008 -0.0313699991 +0.0063700001 -0.0362810008 -0.0436300002 +0.0063700001 -0.0387189984 0.0313699991 +0.0063700001 -0.0387189984 0.0186299998 +0.0063700001 -0.0387189984 0.0063700001 +0.0063700001 -0.0387189984 -0.0063700001 +0.0063700001 -0.0387189984 -0.0186299998 +0.0063700001 -0.0387189984 -0.0313699991 +0.0063700001 -0.0436300002 0.0362810008 +0.0063700001 -0.0436300002 0.0137189999 +0.0063700001 -0.0436300002 0.0112810005 +0.0063700001 -0.0436300002 -0.0112810005 +0.0063700001 -0.0436300002 -0.0137189999 +0.0063590002 -0.0436410010 -0.0363369994 +0.0063419999 -0.0436579995 -0.0385689996 +0.0063419999 -0.0500000007 -0.0385689996 +0.0063220002 0.0043270001 0.0365540013 +0.0063220002 0.0043270001 0.0134460004 +0.0063220002 0.0043270001 0.0115540000 +0.0062799999 0.0437199995 0.0368870012 +0.0062799999 0.0437199995 0.0131130004 +0.0062799999 0.0437199995 0.0118869999 +0.0062799999 0.0437199995 -0.0118869999 +0.0062799999 0.0437199995 -0.0131130004 +0.0062799999 0.0437199995 -0.0368870012 +0.0062799999 0.0437199995 -0.0381130017 +0.0062799999 0.0381130017 0.0312799998 +0.0062799999 0.0381130017 0.0187199991 +0.0062799999 0.0381130017 0.0062799999 +0.0062799999 0.0381130017 -0.0062799999 +0.0062799999 0.0381130017 -0.0187199991 +0.0062799999 0.0381130017 -0.0312799998 +0.0062799999 0.0381130017 -0.0437199995 +0.0062799999 0.0368870012 0.0312799998 +0.0062799999 0.0368870012 0.0187199991 +0.0062799999 0.0368870012 0.0062799999 +0.0062799999 0.0368870012 -0.0062799999 +0.0062799999 0.0368870012 -0.0187199991 +0.0062799999 0.0368870012 -0.0312799998 +0.0062799999 0.0368870012 -0.0437199995 +0.0062799999 0.0312799998 -0.0118869999 +0.0062799999 0.0312799998 -0.0131130004 +0.0062799999 0.0312799998 -0.0368870012 +0.0062799999 0.0312799998 -0.0381130017 +0.0062799999 0.0187199991 -0.0118869999 +0.0062799999 0.0187199991 -0.0131130004 +0.0062799999 0.0187199991 -0.0368870012 +0.0062799999 0.0187199991 -0.0381130017 +0.0062799999 0.0131130004 -0.0062799999 +0.0062799999 0.0131130004 -0.0187199991 +0.0062799999 0.0131130004 -0.0312799998 +0.0062799999 0.0131130004 -0.0437199995 +0.0062799999 0.0118869999 -0.0062799999 +0.0062799999 0.0118869999 -0.0187199991 +0.0062799999 0.0118869999 -0.0312799998 +0.0062799999 0.0118869999 -0.0437199995 +0.0062799999 0.0062799999 -0.0118869999 +0.0062799999 0.0062799999 -0.0131130004 +0.0062799999 0.0062799999 -0.0368870012 +0.0062799999 0.0062799999 -0.0381130017 +0.0062799999 -0.0062799999 0.0368870012 +0.0062799999 -0.0062799999 0.0131130004 +0.0062799999 -0.0062799999 0.0118869999 +0.0062799999 -0.0062799999 -0.0118869999 +0.0062799999 -0.0062799999 -0.0131130004 +0.0062799999 -0.0062799999 -0.0368870012 +0.0062799999 -0.0062799999 -0.0381130017 +0.0062799999 -0.0118869999 0.0312799998 +0.0062799999 -0.0118869999 0.0187199991 +0.0062799999 -0.0118869999 0.0062799999 +0.0062799999 -0.0118869999 -0.0062799999 +0.0062799999 -0.0118869999 -0.0187199991 +0.0062799999 -0.0118869999 -0.0312799998 +0.0062799999 -0.0118869999 -0.0437199995 +0.0062799999 -0.0131130004 0.0312799998 +0.0062799999 -0.0131130004 0.0187199991 +0.0062799999 -0.0131130004 0.0062799999 +0.0062799999 -0.0131130004 -0.0062799999 +0.0062799999 -0.0131130004 -0.0187199991 +0.0062799999 -0.0131130004 -0.0312799998 +0.0062799999 -0.0131130004 -0.0437199995 +0.0062799999 -0.0187199991 0.0368870012 +0.0062799999 -0.0187199991 0.0131130004 +0.0062799999 -0.0187199991 0.0118869999 +0.0062799999 -0.0187199991 -0.0118869999 +0.0062799999 -0.0187199991 -0.0131130004 +0.0062799999 -0.0187199991 -0.0368870012 +0.0062799999 -0.0187199991 -0.0381130017 +0.0062799999 -0.0312799998 0.0368870012 +0.0062799999 -0.0312799998 0.0131130004 +0.0062799999 -0.0312799998 0.0118869999 +0.0062799999 -0.0312799998 -0.0118869999 +0.0062799999 -0.0312799998 -0.0131130004 +0.0062799999 -0.0312799998 -0.0368870012 +0.0062799999 -0.0312799998 -0.0381130017 +0.0062799999 -0.0368870012 0.0312799998 +0.0062799999 -0.0368870012 0.0187199991 +0.0062799999 -0.0368870012 0.0062799999 +0.0062799999 -0.0368870012 -0.0062799999 +0.0062799999 -0.0368870012 -0.0187199991 +0.0062799999 -0.0368870012 -0.0312799998 +0.0062799999 -0.0368870012 -0.0437199995 +0.0062799999 -0.0381130017 0.0312799998 +0.0062799999 -0.0381130017 0.0187199991 +0.0062799999 -0.0381130017 0.0062799999 +0.0062799999 -0.0381130017 -0.0062799999 +0.0062799999 -0.0381130017 -0.0187199991 +0.0062799999 -0.0381130017 -0.0312799998 +0.0062799999 -0.0437199995 0.0368870012 +0.0062799999 -0.0437199995 0.0131130004 +0.0062799999 -0.0437199995 0.0118869999 +0.0062799999 -0.0437199995 -0.0118869999 +0.0062799999 -0.0437199995 -0.0131130004 +0.0062640002 -0.0437359996 -0.0370789990 +0.0062640002 -0.0500000007 -0.0370789990 +0.0062589999 -0.0437409990 -0.0378260016 +0.0062580002 0.0128130000 -0.0003910000 +0.0062500001 0.0500000007 0.0375000015 +0.0062500001 0.0500000007 0.0125000002 +0.0062500001 0.0500000007 -0.0125000002 +0.0062500001 0.0500000007 -0.0375000015 +0.0062500001 0.0437499993 0.0375000015 +0.0062500001 0.0437499993 0.0125000002 +0.0062500001 0.0437499993 -0.0125000002 +0.0062500001 0.0437499993 -0.0375000015 +0.0062500001 0.0375000015 0.0312500000 +0.0062500001 0.0375000015 0.0187500007 +0.0062500001 0.0375000015 0.0062500001 +0.0062500001 0.0375000015 -0.0062500001 +0.0062500001 0.0375000015 -0.0187500007 +0.0062500001 0.0375000015 -0.0312500000 +0.0062500001 0.0375000015 -0.0437499993 +0.0062500001 0.0375000015 -0.0500000007 +0.0062500001 0.0312500000 -0.0125000002 +0.0062500001 0.0312500000 -0.0375000015 +0.0062500001 0.0187500007 -0.0125000002 +0.0062500001 0.0187500007 -0.0375000015 +0.0062500001 0.0125000002 -0.0062500001 +0.0062500001 0.0125000002 -0.0187500007 +0.0062500001 0.0125000002 -0.0312500000 +0.0062500001 0.0125000002 -0.0437499993 +0.0062500001 0.0125000002 -0.0500000007 +0.0062500001 0.0062500001 -0.0125000002 +0.0062500001 0.0062500001 -0.0375000015 +0.0062500001 0.0042849998 0.0375000015 +0.0062500001 0.0042849998 0.0125000002 +0.0062500001 -0.0062500001 0.0375000015 +0.0062500001 -0.0062500001 0.0125000002 +0.0062500001 -0.0062500001 -0.0125000002 +0.0062500001 -0.0062500001 -0.0375000015 +0.0062500001 -0.0125000002 0.0312500000 +0.0062500001 -0.0125000002 0.0187500007 +0.0062500001 -0.0125000002 0.0062500001 +0.0062500001 -0.0125000002 -0.0062500001 +0.0062500001 -0.0125000002 -0.0187500007 +0.0062500001 -0.0125000002 -0.0312500000 +0.0062500001 -0.0125000002 -0.0437499993 +0.0062500001 -0.0125000002 -0.0500000007 +0.0062500001 -0.0187500007 0.0375000015 +0.0062500001 -0.0187500007 0.0125000002 +0.0062500001 -0.0187500007 -0.0125000002 +0.0062500001 -0.0187500007 -0.0375000015 +0.0062500001 -0.0312500000 0.0375000015 +0.0062500001 -0.0312500000 0.0125000002 +0.0062500001 -0.0312500000 -0.0125000002 +0.0062500001 -0.0312500000 -0.0375000015 +0.0062500001 -0.0375000015 0.0312500000 +0.0062500001 -0.0375000015 0.0187500007 +0.0062500001 -0.0375000015 0.0062500001 +0.0062500001 -0.0375000015 -0.0062500001 +0.0062500001 -0.0375000015 -0.0187500007 +0.0062500001 -0.0375000015 -0.0312500000 +0.0062500001 -0.0375000015 -0.0437499993 +0.0062500001 -0.0375000015 -0.0500000007 +0.0062500001 -0.0437499993 0.0375000015 +0.0062500001 -0.0437499993 0.0125000002 +0.0062500001 -0.0437499993 -0.0125000002 +0.0062500001 -0.0500000007 0.0375000015 +0.0062500001 -0.0500000007 0.0125000002 +0.0062500001 -0.0500000007 -0.0125000002 +0.0061809998 0.0313079990 0.0366469994 +0.0061809998 0.0313079990 0.0133530004 +0.0061809998 0.0313079990 0.0116470000 +0.0061050002 0.0312650017 0.0370730013 +0.0061050002 0.0312650017 0.0129270004 +0.0061050002 0.0312650017 0.0120730000 +0.0060800002 0.0312500000 0.0375000015 +0.0060800002 0.0312500000 0.0125000002 +0.0052870000 -0.0433779992 -0.0396240018 +0.0042969999 -0.0429189987 -0.0406140015 +0.0034020001 -0.0422939993 -0.0415100008 +0.0026290000 -0.0415240005 -0.0422820002 +0.0024999999 0.0500000007 0.0500000007 +0.0024999999 0.0500000007 0.0375000015 +0.0024999999 0.0437499993 0.0375000015 +0.0024999999 0.0435369983 0.0391179994 +0.0024999999 0.0429130010 0.0406249985 +0.0024999999 0.0419190004 0.0419190004 +0.0024999999 0.0406249985 0.0429130010 +0.0024999999 0.0391179994 0.0435369983 +0.0024999999 0.0375000015 0.0437499993 +0.0024999999 0.0358819999 0.0435369983 +0.0024999999 0.0343750007 0.0429130010 +0.0024999999 0.0330809988 0.0419190004 +0.0024999999 0.0320869982 0.0406249985 +0.0024999999 0.0314630009 0.0391179994 +0.0024999999 0.0312500000 0.0375000015 +0.0024999999 0.0291830003 0.0500000007 +0.0024999999 0.0291830003 0.0375000015 +0.0024999999 0.0021200001 0.0500000007 +0.0024999999 0.0021200001 0.0375000015 +0.0024999999 -0.0062500001 0.0375000015 +0.0024999999 -0.0064630001 0.0391179994 +0.0024999999 -0.0070870002 0.0406249985 +0.0024999999 -0.0080810003 0.0419190004 +0.0024999999 -0.0093750004 0.0429130010 +0.0024999999 -0.0108820004 0.0435369983 +0.0024999999 -0.0125000002 0.0437499993 +0.0024999999 -0.0141179999 0.0435369983 +0.0024999999 -0.0156250000 0.0429130010 +0.0024999999 -0.0169190001 0.0419190004 +0.0024999999 -0.0179130007 0.0406249985 +0.0024999999 -0.0185369998 0.0391179994 +0.0024999999 -0.0187500007 0.0375000015 +0.0024999999 -0.0312500000 0.0375000015 +0.0024999999 -0.0314630009 0.0391179994 +0.0024999999 -0.0320869982 0.0406249985 +0.0024999999 -0.0330809988 0.0419190004 +0.0024999999 -0.0343750007 0.0429130010 +0.0024999999 -0.0358819999 0.0435369983 +0.0024999999 -0.0375000015 0.0437499993 +0.0024999999 -0.0391179994 0.0435369983 +0.0024999999 -0.0406249985 0.0429130010 +0.0024999999 -0.0419190004 0.0419190004 +0.0024999999 -0.0429130010 0.0406249985 +0.0024999999 -0.0435369983 0.0391179994 +0.0024999999 -0.0437499993 0.0375000015 +0.0024999999 -0.0500000007 0.0500000007 +0.0024999999 -0.0500000007 0.0375000015 +0.0020020001 -0.0406300016 -0.0429099984 +0.0015390000 -0.0396410003 -0.0433720015 +0.0012560000 -0.0385870002 -0.0436550006 +0.0011610000 -0.0375000015 -0.0437499993 +0.0001880000 0.0007850000 0.0500000007 +0.0001880000 0.0007850000 -0.0003910000 +0.0000000000 -0.0287500005 0.0500000007 +0.0000000000 -0.0287500005 0.0250000004 +0.0000000000 -0.0312500000 0.0375000015 +0.0000000000 -0.0314630009 0.0391179994 +0.0000000000 -0.0314630009 0.0358819999 +0.0000000000 -0.0320869982 0.0406249985 +0.0000000000 -0.0320869982 0.0343750007 +0.0000000000 -0.0330809988 0.0419190004 +0.0000000000 -0.0330809988 0.0330809988 +0.0000000000 -0.0343750007 0.0429130010 +0.0000000000 -0.0343750007 0.0320869982 +0.0000000000 -0.0358819999 0.0435369983 +0.0000000000 -0.0358819999 0.0314630009 +0.0000000000 -0.0375000015 0.0437499993 +0.0000000000 -0.0375000015 0.0312500000 +0.0000000000 -0.0391179994 0.0435369983 +0.0000000000 -0.0391179994 0.0314630009 +0.0000000000 -0.0406249985 0.0429130010 +0.0000000000 -0.0406249985 0.0320869982 +0.0000000000 -0.0419190004 0.0419190004 +0.0000000000 -0.0419190004 0.0330809988 +0.0000000000 -0.0429130010 0.0406249985 +0.0000000000 -0.0429130010 0.0343750007 +0.0000000000 -0.0435369983 0.0391179994 +0.0000000000 -0.0435369983 0.0358819999 +0.0000000000 -0.0437499993 0.0375000015 +0.0000000000 -0.0500000007 0.0500000007 +0.0000000000 -0.0500000007 0.0250000004 +-0.0001280000 -0.0277789999 0.0500000007 +-0.0001280000 -0.0277789999 0.0250000004 +-0.0001280000 -0.0287500005 0.0240289997 +-0.0001280000 -0.0500000007 0.0240289997 +-0.0003470000 -0.0276640002 0.0238589998 +-0.0005020000 -0.0268750004 0.0500000007 +-0.0005020000 -0.0268750004 0.0250000004 +-0.0005020000 -0.0287500005 0.0231250003 +-0.0005020000 -0.0500000007 0.0231250003 +-0.0008140000 -0.0266350005 0.0240150001 +-0.0008150000 -0.0279510003 0.0228070002 +-0.0009370000 -0.0271259993 0.0231250003 +-0.0010980000 -0.0260979999 0.0500000007 +-0.0010980000 -0.0260979999 0.0250000004 +-0.0010980000 -0.0287500005 0.0223479997 +-0.0010980000 -0.0500000007 0.0223479997 +-0.0012250000 0.0002000000 0.0500000007 +-0.0012250000 0.0002000000 -0.0003910000 +-0.0014540000 -0.0264539998 0.0231250003 +-0.0014540000 -0.0274240002 0.0223479997 +-0.0014780000 -0.0259300005 0.0240269993 +-0.0014820000 -0.0281390008 0.0220769998 +-0.0018750000 -0.0255020000 0.0500000007 +-0.0018750000 -0.0255020000 0.0250000004 +-0.0018750000 -0.0268750004 0.0223479997 +-0.0018750000 -0.0287500005 0.0217519999 +-0.0018750000 -0.0500000007 0.0217519999 +-0.0021259999 -0.0259370003 0.0231250003 +-0.0021259999 -0.0278120004 0.0217519999 +-0.0021850001 -0.0254929997 0.0239979997 +-0.0022090001 -0.0282830000 0.0216130000 +-0.0024240001 -0.0264539998 0.0223479997 +-0.0024240001 -0.0274240002 0.0217519999 +-0.0027419999 -0.0000000000 0.0500000007 +-0.0027419999 -0.0000000000 -0.0003910000 +-0.0027790000 -0.0251279995 0.0500000007 +-0.0027790000 -0.0251279995 0.0250000004 +-0.0027790000 -0.0287500005 0.0213779993 +-0.0027790000 -0.0500000007 0.0213779993 +-0.0028120000 -0.0271259993 0.0217519999 +-0.0028619999 -0.0285710003 0.0213610008 +-0.0028639999 -0.0251599997 0.0243759993 +-0.0029090000 -0.0282649994 0.0213779993 +-0.0029190001 -0.0254170001 0.0234960001 +-0.0029879999 -0.0258970000 0.0226889998 +-0.0030640000 -0.0280639995 0.0213779993 +-0.0031699999 -0.0265859999 0.0219930001 +-0.0032649999 -0.0279089995 0.0213779993 +-0.0034159999 -0.0275030006 0.0214789994 +-0.0037499999 -0.0250000004 0.0500000007 +-0.0037499999 -0.0250000004 0.0250000004 +-0.0037499999 -0.0251279995 0.0240289997 +-0.0037499999 -0.0255020000 0.0231250003 +-0.0037499999 -0.0260979999 0.0223479997 +-0.0037499999 -0.0268750004 0.0217519999 +-0.0037499999 -0.0277789999 0.0213779993 +-0.0037499999 -0.0287500005 0.0212500002 +-0.0037499999 -0.0500000007 0.0212500002 +-0.0050889999 -0.0375000015 -0.0500000007 +-0.0050889999 -0.0500000007 -0.0500000007 +-0.0062500001 0.0500000007 0.0375000015 +-0.0062500001 0.0500000007 0.0125000002 +-0.0062500001 0.0500000007 -0.0125000002 +-0.0062500001 0.0500000007 -0.0375000015 +-0.0062500001 0.0437499993 0.0375000015 +-0.0062500001 0.0437499993 0.0125000002 +-0.0062500001 0.0437499993 -0.0125000002 +-0.0062500001 0.0437499993 -0.0375000015 +-0.0062500001 0.0375000015 0.0500000007 +-0.0062500001 0.0375000015 0.0437499993 +-0.0062500001 0.0375000015 0.0312500000 +-0.0062500001 0.0375000015 0.0187500007 +-0.0062500001 0.0375000015 0.0062500001 +-0.0062500001 0.0375000015 -0.0062500001 +-0.0062500001 0.0375000015 -0.0187500007 +-0.0062500001 0.0375000015 -0.0312500000 +-0.0062500001 0.0375000015 -0.0437499993 +-0.0062500001 0.0375000015 -0.0500000007 +-0.0062500001 0.0312500000 0.0375000015 +-0.0062500001 0.0312500000 0.0125000002 +-0.0062500001 0.0312500000 -0.0125000002 +-0.0062500001 0.0312500000 -0.0375000015 +-0.0062500001 0.0241310000 0.0375000015 +-0.0062500001 0.0241310000 0.0125000002 +-0.0062500001 0.0187500007 -0.0125000002 +-0.0062500001 0.0187500007 -0.0375000015 +-0.0062500001 0.0125000002 -0.0003910000 +-0.0062500001 0.0125000002 -0.0062500001 +-0.0062500001 0.0125000002 -0.0187500007 +-0.0062500001 0.0125000002 -0.0312500000 +-0.0062500001 0.0125000002 -0.0437499993 +-0.0062500001 0.0125000002 -0.0500000007 +-0.0062500001 0.0062500001 -0.0125000002 +-0.0062500001 0.0062500001 -0.0375000015 +-0.0062500001 -0.0000000000 0.0375000015 +-0.0062500001 -0.0000000000 0.0125000002 +-0.0062500001 -0.0062500001 0.0375000015 +-0.0062500001 -0.0062500001 0.0125000002 +-0.0062500001 -0.0062500001 -0.0125000002 +-0.0062500001 -0.0062500001 -0.0375000015 +-0.0062500001 -0.0125000002 0.0500000007 +-0.0062500001 -0.0125000002 0.0437499993 +-0.0062500001 -0.0125000002 0.0312500000 +-0.0062500001 -0.0125000002 0.0187500007 +-0.0062500001 -0.0125000002 0.0062500001 +-0.0062500001 -0.0125000002 -0.0062500001 +-0.0062500001 -0.0125000002 -0.0187500007 +-0.0062500001 -0.0125000002 -0.0312500000 +-0.0062500001 -0.0125000002 -0.0437499993 +-0.0062500001 -0.0125000002 -0.0500000007 +-0.0062500001 -0.0187500007 0.0375000015 +-0.0062500001 -0.0187500007 0.0125000002 +-0.0062500001 -0.0187500007 -0.0125000002 +-0.0062500001 -0.0187500007 -0.0375000015 +-0.0062500001 -0.0250000004 0.0375000015 +-0.0062500001 -0.0312500000 0.0125000002 +-0.0062500001 -0.0312500000 -0.0125000002 +-0.0062500001 -0.0312500000 -0.0375000015 +-0.0062500001 -0.0375000015 0.0212500002 +-0.0062500001 -0.0375000015 0.0187500007 +-0.0062500001 -0.0375000015 0.0062500001 +-0.0062500001 -0.0375000015 -0.0062500001 +-0.0062500001 -0.0375000015 -0.0187500007 +-0.0062500001 -0.0375000015 -0.0312500000 +-0.0062500001 -0.0375000015 -0.0437499993 +-0.0062500001 -0.0375000015 -0.0500000007 +-0.0062500001 -0.0437499993 0.0125000002 +-0.0062500001 -0.0437499993 -0.0125000002 +-0.0062500001 -0.0437499993 -0.0375000015 +-0.0062500001 -0.0500000007 0.0125000002 +-0.0062500001 -0.0500000007 -0.0125000002 +-0.0062500001 -0.0500000007 -0.0375000015 +-0.0062799999 0.0437199995 0.0381130017 +-0.0062799999 0.0437199995 0.0368870012 +-0.0062799999 0.0437199995 0.0131130004 +-0.0062799999 0.0437199995 0.0118869999 +-0.0062799999 0.0437199995 -0.0118869999 +-0.0062799999 0.0437199995 -0.0131130004 +-0.0062799999 0.0437199995 -0.0368870012 +-0.0062799999 0.0437199995 -0.0381130017 +-0.0062799999 0.0381130017 0.0437199995 +-0.0062799999 0.0381130017 0.0312799998 +-0.0062799999 0.0381130017 0.0187199991 +-0.0062799999 0.0381130017 0.0062799999 +-0.0062799999 0.0381130017 -0.0062799999 +-0.0062799999 0.0381130017 -0.0187199991 +-0.0062799999 0.0381130017 -0.0312799998 +-0.0062799999 0.0381130017 -0.0437199995 +-0.0062799999 0.0368870012 0.0437199995 +-0.0062799999 0.0368870012 0.0312799998 +-0.0062799999 0.0368870012 0.0187199991 +-0.0062799999 0.0368870012 0.0062799999 +-0.0062799999 0.0368870012 -0.0062799999 +-0.0062799999 0.0368870012 -0.0187199991 +-0.0062799999 0.0368870012 -0.0312799998 +-0.0062799999 0.0368870012 -0.0437199995 +-0.0062799999 0.0312799998 0.0381130017 +-0.0062799999 0.0312799998 0.0368870012 +-0.0062799999 0.0312799998 0.0131130004 +-0.0062799999 0.0312799998 0.0118869999 +-0.0062799999 0.0312799998 -0.0118869999 +-0.0062799999 0.0312799998 -0.0131130004 +-0.0062799999 0.0312799998 -0.0368870012 +-0.0062799999 0.0312799998 -0.0381130017 +-0.0062799999 0.0187199991 -0.0118869999 +-0.0062799999 0.0187199991 -0.0131130004 +-0.0062799999 0.0187199991 -0.0368870012 +-0.0062799999 0.0187199991 -0.0381130017 +-0.0062799999 0.0131130004 -0.0062799999 +-0.0062799999 0.0131130004 -0.0187199991 +-0.0062799999 0.0131130004 -0.0312799998 +-0.0062799999 0.0131130004 -0.0437199995 +-0.0062799999 0.0118869999 -0.0062799999 +-0.0062799999 0.0118869999 -0.0187199991 +-0.0062799999 0.0118869999 -0.0312799998 +-0.0062799999 0.0118869999 -0.0437199995 +-0.0062799999 0.0062799999 -0.0118869999 +-0.0062799999 0.0062799999 -0.0131130004 +-0.0062799999 0.0062799999 -0.0368870012 +-0.0062799999 0.0062799999 -0.0381130017 +-0.0062799999 -0.0062799999 0.0381130017 +-0.0062799999 -0.0062799999 0.0368870012 +-0.0062799999 -0.0062799999 0.0131130004 +-0.0062799999 -0.0062799999 0.0118869999 +-0.0062799999 -0.0062799999 -0.0118869999 +-0.0062799999 -0.0062799999 -0.0131130004 +-0.0062799999 -0.0062799999 -0.0368870012 +-0.0062799999 -0.0062799999 -0.0381130017 +-0.0062799999 -0.0118869999 0.0437199995 +-0.0062799999 -0.0118869999 0.0312799998 +-0.0062799999 -0.0118869999 0.0187199991 +-0.0062799999 -0.0118869999 0.0062799999 +-0.0062799999 -0.0118869999 -0.0062799999 +-0.0062799999 -0.0118869999 -0.0187199991 +-0.0062799999 -0.0118869999 -0.0312799998 +-0.0062799999 -0.0118869999 -0.0437199995 +-0.0062799999 -0.0131130004 0.0437199995 +-0.0062799999 -0.0131130004 0.0312799998 +-0.0062799999 -0.0131130004 0.0187199991 +-0.0062799999 -0.0131130004 0.0062799999 +-0.0062799999 -0.0131130004 -0.0062799999 +-0.0062799999 -0.0131130004 -0.0187199991 +-0.0062799999 -0.0131130004 -0.0312799998 +-0.0062799999 -0.0131130004 -0.0437199995 +-0.0062799999 -0.0187199991 0.0381130017 +-0.0062799999 -0.0187199991 0.0368870012 +-0.0062799999 -0.0187199991 0.0131130004 +-0.0062799999 -0.0187199991 0.0118869999 +-0.0062799999 -0.0187199991 -0.0118869999 +-0.0062799999 -0.0187199991 -0.0131130004 +-0.0062799999 -0.0187199991 -0.0368870012 +-0.0062799999 -0.0187199991 -0.0381130017 +-0.0062799999 -0.0312799998 0.0131130004 +-0.0062799999 -0.0312799998 0.0118869999 +-0.0062799999 -0.0312799998 -0.0118869999 +-0.0062799999 -0.0312799998 -0.0131130004 +-0.0062799999 -0.0312799998 -0.0368870012 +-0.0062799999 -0.0312799998 -0.0381130017 +-0.0062799999 -0.0368870012 0.0187199991 +-0.0062799999 -0.0368870012 0.0062799999 +-0.0062799999 -0.0368870012 -0.0062799999 +-0.0062799999 -0.0368870012 -0.0187199991 +-0.0062799999 -0.0368870012 -0.0312799998 +-0.0062799999 -0.0368870012 -0.0437199995 +-0.0062799999 -0.0381130017 0.0187199991 +-0.0062799999 -0.0381130017 0.0062799999 +-0.0062799999 -0.0381130017 -0.0062799999 +-0.0062799999 -0.0381130017 -0.0187199991 +-0.0062799999 -0.0381130017 -0.0312799998 +-0.0062799999 -0.0381130017 -0.0437199995 +-0.0062799999 -0.0437199995 0.0131130004 +-0.0062799999 -0.0437199995 0.0118869999 +-0.0062799999 -0.0437199995 -0.0118869999 +-0.0062799999 -0.0437199995 -0.0131130004 +-0.0062799999 -0.0437199995 -0.0368870012 +-0.0062799999 -0.0437199995 -0.0381130017 +-0.0063270000 0.0240870006 0.0384810008 +-0.0063270000 0.0240870006 0.0365189984 +-0.0063270000 0.0240870006 0.0134810004 +-0.0063270000 0.0240870006 0.0115189999 +-0.0063700001 0.0436300002 0.0387189984 +-0.0063700001 0.0436300002 0.0362810008 +-0.0063700001 0.0436300002 0.0137189999 +-0.0063700001 0.0436300002 0.0112810005 +-0.0063700001 0.0436300002 -0.0112810005 +-0.0063700001 0.0436300002 -0.0137189999 +-0.0063700001 0.0436300002 -0.0362810008 +-0.0063700001 0.0436300002 -0.0387189984 +-0.0063700001 0.0387189984 0.0436300002 +-0.0063700001 0.0387189984 0.0313699991 +-0.0063700001 0.0387189984 0.0186299998 +-0.0063700001 0.0387189984 0.0063700001 +-0.0063700001 0.0387189984 -0.0063700001 +-0.0063700001 0.0387189984 -0.0186299998 +-0.0063700001 0.0387189984 -0.0313699991 +-0.0063700001 0.0387189984 -0.0436300002 +-0.0063700001 0.0362810008 0.0436300002 +-0.0063700001 0.0362810008 0.0313699991 +-0.0063700001 0.0362810008 0.0186299998 +-0.0063700001 0.0362810008 0.0063700001 +-0.0063700001 0.0362810008 -0.0063700001 +-0.0063700001 0.0362810008 -0.0186299998 +-0.0063700001 0.0362810008 -0.0313699991 +-0.0063700001 0.0362810008 -0.0436300002 +-0.0063700001 0.0313699991 0.0387189984 +-0.0063700001 0.0313699991 0.0362810008 +-0.0063700001 0.0313699991 0.0137189999 +-0.0063700001 0.0313699991 0.0112810005 +-0.0063700001 0.0313699991 -0.0112810005 +-0.0063700001 0.0313699991 -0.0137189999 +-0.0063700001 0.0313699991 -0.0362810008 +-0.0063700001 0.0313699991 -0.0387189984 +-0.0063700001 0.0186299998 -0.0112810005 +-0.0063700001 0.0186299998 -0.0137189999 +-0.0063700001 0.0186299998 -0.0362810008 +-0.0063700001 0.0186299998 -0.0387189984 +-0.0063700001 0.0137189999 -0.0063700001 +-0.0063700001 0.0137189999 -0.0186299998 +-0.0063700001 0.0137189999 -0.0313699991 +-0.0063700001 0.0137189999 -0.0436300002 +-0.0063700001 0.0112810005 -0.0063700001 +-0.0063700001 0.0112810005 -0.0186299998 +-0.0063700001 0.0112810005 -0.0313699991 +-0.0063700001 0.0112810005 -0.0436300002 +-0.0063700001 0.0063700001 -0.0112810005 +-0.0063700001 0.0063700001 -0.0137189999 +-0.0063700001 0.0063700001 -0.0362810008 +-0.0063700001 0.0063700001 -0.0387189984 +-0.0063700001 -0.0063700001 0.0387189984 +-0.0063700001 -0.0063700001 0.0362810008 +-0.0063700001 -0.0063700001 0.0137189999 +-0.0063700001 -0.0063700001 0.0112810005 +-0.0063700001 -0.0063700001 -0.0112810005 +-0.0063700001 -0.0063700001 -0.0137189999 +-0.0063700001 -0.0063700001 -0.0362810008 +-0.0063700001 -0.0063700001 -0.0387189984 +-0.0063700001 -0.0112810005 0.0436300002 +-0.0063700001 -0.0112810005 0.0313699991 +-0.0063700001 -0.0112810005 0.0186299998 +-0.0063700001 -0.0112810005 0.0063700001 +-0.0063700001 -0.0112810005 -0.0063700001 +-0.0063700001 -0.0112810005 -0.0186299998 +-0.0063700001 -0.0112810005 -0.0313699991 +-0.0063700001 -0.0112810005 -0.0436300002 +-0.0063700001 -0.0137189999 0.0436300002 +-0.0063700001 -0.0137189999 0.0313699991 +-0.0063700001 -0.0137189999 0.0186299998 +-0.0063700001 -0.0137189999 0.0063700001 +-0.0063700001 -0.0137189999 -0.0063700001 +-0.0063700001 -0.0137189999 -0.0186299998 +-0.0063700001 -0.0137189999 -0.0313699991 +-0.0063700001 -0.0137189999 -0.0436300002 +-0.0063700001 -0.0186299998 0.0387189984 +-0.0063700001 -0.0186299998 0.0362810008 +-0.0063700001 -0.0186299998 0.0137189999 +-0.0063700001 -0.0186299998 0.0112810005 +-0.0063700001 -0.0186299998 -0.0112810005 +-0.0063700001 -0.0186299998 -0.0137189999 +-0.0063700001 -0.0186299998 -0.0362810008 +-0.0063700001 -0.0186299998 -0.0387189984 +-0.0063700001 -0.0313699991 0.0137189999 +-0.0063700001 -0.0313699991 0.0112810005 +-0.0063700001 -0.0313699991 -0.0112810005 +-0.0063700001 -0.0313699991 -0.0137189999 +-0.0063700001 -0.0313699991 -0.0362810008 +-0.0063700001 -0.0313699991 -0.0387189984 +-0.0063700001 -0.0362810008 0.0186299998 +-0.0063700001 -0.0362810008 0.0063700001 +-0.0063700001 -0.0362810008 -0.0063700001 +-0.0063700001 -0.0362810008 -0.0186299998 +-0.0063700001 -0.0362810008 -0.0313699991 +-0.0063700001 -0.0362810008 -0.0436300002 +-0.0063700001 -0.0387189984 0.0186299998 +-0.0063700001 -0.0387189984 0.0063700001 +-0.0063700001 -0.0387189984 -0.0063700001 +-0.0063700001 -0.0387189984 -0.0186299998 +-0.0063700001 -0.0387189984 -0.0313699991 +-0.0063700001 -0.0387189984 -0.0436300002 +-0.0063700001 -0.0436300002 0.0137189999 +-0.0063700001 -0.0436300002 0.0112810005 +-0.0063700001 -0.0436300002 -0.0112810005 +-0.0063700001 -0.0436300002 -0.0137189999 +-0.0063700001 -0.0436300002 -0.0362810008 +-0.0063700001 -0.0436300002 -0.0387189984 +-0.0064630001 0.0500000007 0.0391179994 +-0.0064630001 0.0500000007 0.0358819999 +-0.0064630001 0.0500000007 0.0141179999 +-0.0064630001 0.0500000007 0.0108820004 +-0.0064630001 0.0500000007 -0.0108820004 +-0.0064630001 0.0500000007 -0.0141179999 +-0.0064630001 0.0500000007 -0.0358819999 +-0.0064630001 0.0500000007 -0.0391179994 +-0.0064630001 0.0391179994 0.0500000007 +-0.0064630001 0.0391179994 -0.0500000007 +-0.0064630001 0.0358819999 0.0500000007 +-0.0064630001 0.0358819999 -0.0500000007 +-0.0064630001 0.0141179999 -0.0003910000 +-0.0064630001 0.0141179999 -0.0500000007 +-0.0064630001 0.0108820004 -0.0003910000 +-0.0064630001 0.0108820004 -0.0500000007 +-0.0064630001 -0.0000000000 0.0391179994 +-0.0064630001 -0.0000000000 0.0358819999 +-0.0064630001 -0.0000000000 0.0141179999 +-0.0064630001 -0.0000000000 0.0108820004 +-0.0064630001 -0.0108820004 0.0500000007 +-0.0064630001 -0.0108820004 -0.0500000007 +-0.0064630001 -0.0141179999 0.0500000007 +-0.0064630001 -0.0141179999 -0.0500000007 +-0.0064630001 -0.0250000004 0.0391179994 +-0.0064630001 -0.0250000004 0.0358819999 +-0.0064630001 -0.0358819999 0.0212500002 +-0.0064630001 -0.0358819999 -0.0500000007 +-0.0064630001 -0.0391179994 0.0212500002 +-0.0064630001 -0.0391179994 -0.0500000007 +-0.0064630001 -0.0500000007 0.0141179999 +-0.0064630001 -0.0500000007 0.0108820004 +-0.0064630001 -0.0500000007 -0.0108820004 +-0.0064630001 -0.0500000007 -0.0141179999 +-0.0064630001 -0.0500000007 -0.0358819999 +-0.0064630001 -0.0500000007 -0.0391179994 +-0.0065580001 0.0239540003 0.0394380018 +-0.0065580001 0.0239540003 0.0355620012 +-0.0065580001 0.0239540003 0.0144379996 +-0.0065580001 0.0239540003 0.0105619999 +-0.0067260000 0.0432740003 0.0398919992 +-0.0067260000 0.0432740003 0.0351080000 +-0.0067260000 0.0432740003 0.0148919998 +-0.0067260000 0.0432740003 0.0101079997 +-0.0067260000 0.0432740003 -0.0101079997 +-0.0067260000 0.0432740003 -0.0148919998 +-0.0067260000 0.0432740003 -0.0351080000 +-0.0067260000 0.0432740003 -0.0398919992 +-0.0067260000 0.0398919992 0.0432740003 +-0.0067260000 0.0398919992 0.0317259990 +-0.0067260000 0.0398919992 0.0182739999 +-0.0067260000 0.0398919992 0.0067260000 +-0.0067260000 0.0398919992 -0.0067260000 +-0.0067260000 0.0398919992 -0.0182739999 +-0.0067260000 0.0398919992 -0.0317259990 +-0.0067260000 0.0398919992 -0.0432740003 +-0.0067260000 0.0351080000 0.0432740003 +-0.0067260000 0.0351080000 0.0317259990 +-0.0067260000 0.0351080000 0.0182739999 +-0.0067260000 0.0351080000 0.0067260000 +-0.0067260000 0.0351080000 -0.0067260000 +-0.0067260000 0.0351080000 -0.0182739999 +-0.0067260000 0.0351080000 -0.0317259990 +-0.0067260000 0.0351080000 -0.0432740003 +-0.0067260000 0.0317259990 0.0398919992 +-0.0067260000 0.0317259990 0.0351080000 +-0.0067260000 0.0317259990 0.0148919998 +-0.0067260000 0.0317259990 0.0101079997 +-0.0067260000 0.0317259990 -0.0101079997 +-0.0067260000 0.0317259990 -0.0148919998 +-0.0067260000 0.0317259990 -0.0351080000 +-0.0067260000 0.0317259990 -0.0398919992 +-0.0067260000 0.0182739999 -0.0101079997 +-0.0067260000 0.0182739999 -0.0148919998 +-0.0067260000 0.0182739999 -0.0351080000 +-0.0067260000 0.0182739999 -0.0398919992 +-0.0067260000 0.0148919998 -0.0067260000 +-0.0067260000 0.0148919998 -0.0182739999 +-0.0067260000 0.0148919998 -0.0317259990 +-0.0067260000 0.0148919998 -0.0432740003 +-0.0067260000 0.0101079997 -0.0067260000 +-0.0067260000 0.0101079997 -0.0182739999 +-0.0067260000 0.0101079997 -0.0317259990 +-0.0067260000 0.0101079997 -0.0432740003 +-0.0067260000 0.0067260000 -0.0101079997 +-0.0067260000 0.0067260000 -0.0148919998 +-0.0067260000 0.0067260000 -0.0351080000 +-0.0067260000 0.0067260000 -0.0398919992 +-0.0067260000 -0.0067260000 0.0398919992 +-0.0067260000 -0.0067260000 0.0351080000 +-0.0067260000 -0.0067260000 0.0148919998 +-0.0067260000 -0.0067260000 0.0101079997 +-0.0067260000 -0.0067260000 -0.0101079997 +-0.0067260000 -0.0067260000 -0.0148919998 +-0.0067260000 -0.0067260000 -0.0351080000 +-0.0067260000 -0.0067260000 -0.0398919992 +-0.0067260000 -0.0101079997 0.0432740003 +-0.0067260000 -0.0101079997 0.0317259990 +-0.0067260000 -0.0101079997 0.0182739999 +-0.0067260000 -0.0101079997 0.0067260000 +-0.0067260000 -0.0101079997 -0.0067260000 +-0.0067260000 -0.0101079997 -0.0182739999 +-0.0067260000 -0.0101079997 -0.0317259990 +-0.0067260000 -0.0101079997 -0.0432740003 +-0.0067260000 -0.0148919998 0.0432740003 +-0.0067260000 -0.0148919998 0.0317259990 +-0.0067260000 -0.0148919998 0.0182739999 +-0.0067260000 -0.0148919998 0.0067260000 +-0.0067260000 -0.0148919998 -0.0067260000 +-0.0067260000 -0.0148919998 -0.0182739999 +-0.0067260000 -0.0148919998 -0.0317259990 +-0.0067260000 -0.0148919998 -0.0432740003 +-0.0067260000 -0.0182739999 0.0398919992 +-0.0067260000 -0.0182739999 0.0351080000 +-0.0067260000 -0.0182739999 0.0148919998 +-0.0067260000 -0.0182739999 0.0101079997 +-0.0067260000 -0.0182739999 -0.0101079997 +-0.0067260000 -0.0182739999 -0.0148919998 +-0.0067260000 -0.0182739999 -0.0351080000 +-0.0067260000 -0.0182739999 -0.0398919992 +-0.0067260000 -0.0317259990 0.0148919998 +-0.0067260000 -0.0317259990 0.0101079997 +-0.0067260000 -0.0317259990 -0.0101079997 +-0.0067260000 -0.0317259990 -0.0148919998 +-0.0067260000 -0.0317259990 -0.0351080000 +-0.0067260000 -0.0317259990 -0.0398919992 +-0.0067260000 -0.0351080000 0.0182739999 +-0.0067260000 -0.0351080000 0.0067260000 +-0.0067260000 -0.0351080000 -0.0067260000 +-0.0067260000 -0.0351080000 -0.0182739999 +-0.0067260000 -0.0351080000 -0.0317259990 +-0.0067260000 -0.0351080000 -0.0432740003 +-0.0067260000 -0.0398919992 0.0182739999 +-0.0067260000 -0.0398919992 0.0067260000 +-0.0067260000 -0.0398919992 -0.0067260000 +-0.0067260000 -0.0398919992 -0.0182739999 +-0.0067260000 -0.0398919992 -0.0317259990 +-0.0067260000 -0.0398919992 -0.0432740003 +-0.0067260000 -0.0432740003 0.0148919998 +-0.0067260000 -0.0432740003 0.0101079997 +-0.0067260000 -0.0432740003 -0.0101079997 +-0.0067260000 -0.0432740003 -0.0148919998 +-0.0067260000 -0.0432740003 -0.0351080000 +-0.0067260000 -0.0432740003 -0.0398919992 +-0.0069360002 0.0237349998 0.0403469987 +-0.0069360002 0.0237349998 0.0346530005 +-0.0069360002 0.0237349998 0.0153470002 +-0.0069360002 0.0237349998 0.0096530002 +-0.0070870002 0.0500000007 0.0406249985 +-0.0070870002 0.0500000007 0.0343750007 +-0.0070870002 0.0500000007 0.0156250000 +-0.0070870002 0.0500000007 0.0093750004 +-0.0070870002 0.0500000007 -0.0093750004 +-0.0070870002 0.0500000007 -0.0156250000 +-0.0070870002 0.0500000007 -0.0343750007 +-0.0070870002 0.0500000007 -0.0406249985 +-0.0070870002 0.0406249985 0.0500000007 +-0.0070870002 0.0406249985 -0.0500000007 +-0.0070870002 0.0343750007 0.0500000007 +-0.0070870002 0.0343750007 -0.0500000007 +-0.0070870002 0.0156250000 -0.0003910000 +-0.0070870002 0.0156250000 -0.0500000007 +-0.0070870002 0.0093750004 -0.0003910000 +-0.0070870002 0.0093750004 -0.0500000007 +-0.0070870002 -0.0000000000 0.0406249985 +-0.0070870002 -0.0000000000 0.0343750007 +-0.0070870002 -0.0000000000 0.0156250000 +-0.0070870002 -0.0000000000 0.0093750004 +-0.0070870002 -0.0093750004 0.0500000007 +-0.0070870002 -0.0093750004 -0.0500000007 +-0.0070870002 -0.0156250000 0.0500000007 +-0.0070870002 -0.0156250000 -0.0500000007 +-0.0070870002 -0.0250000004 0.0406249985 +-0.0070870002 -0.0250000004 0.0343750007 +-0.0070870002 -0.0343750007 0.0212500002 +-0.0070870002 -0.0343750007 -0.0500000007 +-0.0070870002 -0.0406249985 0.0212500002 +-0.0070870002 -0.0406249985 -0.0500000007 +-0.0070870002 -0.0500000007 0.0156250000 +-0.0070870002 -0.0500000007 0.0093750004 +-0.0070870002 -0.0500000007 -0.0093750004 +-0.0070870002 -0.0500000007 -0.0156250000 +-0.0070870002 -0.0500000007 -0.0343750007 +-0.0070870002 -0.0500000007 -0.0406249985 +-0.0073030000 0.0426970012 0.0409720019 +-0.0073030000 0.0426970012 0.0340280011 +-0.0073030000 0.0426970012 0.0159719996 +-0.0073030000 0.0426970012 0.0090279998 +-0.0073030000 0.0426970012 -0.0090279998 +-0.0073030000 0.0426970012 -0.0159719996 +-0.0073030000 0.0426970012 -0.0340280011 +-0.0073030000 0.0426970012 -0.0409720019 +-0.0073030000 0.0409720019 0.0426970012 +-0.0073030000 0.0409720019 0.0323030017 +-0.0073030000 0.0409720019 0.0176970009 +-0.0073030000 0.0409720019 0.0073030000 +-0.0073030000 0.0409720019 -0.0073030000 +-0.0073030000 0.0409720019 -0.0176970009 +-0.0073030000 0.0409720019 -0.0323030017 +-0.0073030000 0.0409720019 -0.0426970012 +-0.0073030000 0.0340280011 0.0426970012 +-0.0073030000 0.0340280011 0.0323030017 +-0.0073030000 0.0340280011 0.0176970009 +-0.0073030000 0.0340280011 0.0073030000 +-0.0073030000 0.0340280011 -0.0073030000 +-0.0073030000 0.0340280011 -0.0176970009 +-0.0073030000 0.0340280011 -0.0323030017 +-0.0073030000 0.0340280011 -0.0426970012 +-0.0073030000 0.0323030017 0.0409720019 +-0.0073030000 0.0323030017 0.0340280011 +-0.0073030000 0.0323030017 0.0159719996 +-0.0073030000 0.0323030017 0.0090279998 +-0.0073030000 0.0323030017 -0.0090279998 +-0.0073030000 0.0323030017 -0.0159719996 +-0.0073030000 0.0323030017 -0.0340280011 +-0.0073030000 0.0323030017 -0.0409720019 +-0.0073030000 0.0176970009 -0.0090279998 +-0.0073030000 0.0176970009 -0.0159719996 +-0.0073030000 0.0176970009 -0.0340280011 +-0.0073030000 0.0176970009 -0.0409720019 +-0.0073030000 0.0159719996 -0.0073030000 +-0.0073030000 0.0159719996 -0.0176970009 +-0.0073030000 0.0159719996 -0.0323030017 +-0.0073030000 0.0159719996 -0.0426970012 +-0.0073030000 0.0090279998 -0.0073030000 +-0.0073030000 0.0090279998 -0.0176970009 +-0.0073030000 0.0090279998 -0.0323030017 +-0.0073030000 0.0090279998 -0.0426970012 +-0.0073030000 0.0073030000 -0.0090279998 +-0.0073030000 0.0073030000 -0.0159719996 +-0.0073030000 0.0073030000 -0.0340280011 +-0.0073030000 0.0073030000 -0.0409720019 +-0.0073030000 -0.0073030000 0.0409720019 +-0.0073030000 -0.0073030000 0.0340280011 +-0.0073030000 -0.0073030000 0.0159719996 +-0.0073030000 -0.0073030000 0.0090279998 +-0.0073030000 -0.0073030000 -0.0090279998 +-0.0073030000 -0.0073030000 -0.0159719996 +-0.0073030000 -0.0073030000 -0.0340280011 +-0.0073030000 -0.0073030000 -0.0409720019 +-0.0073030000 -0.0090279998 0.0426970012 +-0.0073030000 -0.0090279998 0.0323030017 +-0.0073030000 -0.0090279998 0.0176970009 +-0.0073030000 -0.0090279998 0.0073030000 +-0.0073030000 -0.0090279998 -0.0073030000 +-0.0073030000 -0.0090279998 -0.0176970009 +-0.0073030000 -0.0090279998 -0.0323030017 +-0.0073030000 -0.0090279998 -0.0426970012 +-0.0073030000 -0.0159719996 0.0426970012 +-0.0073030000 -0.0159719996 0.0323030017 +-0.0073030000 -0.0159719996 0.0176970009 +-0.0073030000 -0.0159719996 0.0073030000 +-0.0073030000 -0.0159719996 -0.0073030000 +-0.0073030000 -0.0159719996 -0.0176970009 +-0.0073030000 -0.0159719996 -0.0323030017 +-0.0073030000 -0.0159719996 -0.0426970012 +-0.0073030000 -0.0176970009 0.0409720019 +-0.0073030000 -0.0176970009 0.0340280011 +-0.0073030000 -0.0176970009 0.0159719996 +-0.0073030000 -0.0176970009 0.0090279998 +-0.0073030000 -0.0176970009 -0.0090279998 +-0.0073030000 -0.0176970009 -0.0159719996 +-0.0073030000 -0.0176970009 -0.0340280011 +-0.0073030000 -0.0176970009 -0.0409720019 +-0.0073030000 -0.0323030017 0.0159719996 +-0.0073030000 -0.0323030017 0.0090279998 +-0.0073030000 -0.0323030017 -0.0090279998 +-0.0073030000 -0.0323030017 -0.0159719996 +-0.0073030000 -0.0323030017 -0.0340280011 +-0.0073030000 -0.0323030017 -0.0409720019 +-0.0073030000 -0.0340280011 0.0176970009 +-0.0073030000 -0.0340280011 0.0073030000 +-0.0073030000 -0.0340280011 -0.0073030000 +-0.0073030000 -0.0340280011 -0.0176970009 +-0.0073030000 -0.0340280011 -0.0323030017 +-0.0073030000 -0.0340280011 -0.0426970012 +-0.0073030000 -0.0409720019 0.0176970009 +-0.0073030000 -0.0409720019 0.0073030000 +-0.0073030000 -0.0409720019 -0.0073030000 +-0.0073030000 -0.0409720019 -0.0176970009 +-0.0073030000 -0.0409720019 -0.0323030017 +-0.0073030000 -0.0409720019 -0.0426970012 +-0.0073030000 -0.0426970012 0.0159719996 +-0.0073030000 -0.0426970012 0.0090279998 +-0.0073030000 -0.0426970012 -0.0090279998 +-0.0073030000 -0.0426970012 -0.0159719996 +-0.0073030000 -0.0426970012 -0.0340280011 +-0.0073030000 -0.0426970012 -0.0409720019 +-0.0074519999 0.0234379992 0.0500000007 +-0.0074519999 0.0234379992 0.0411849990 +-0.0074519999 0.0234379992 0.0338150002 +-0.0074519999 0.0234379992 0.0161850005 +-0.0074519999 0.0234379992 0.0088149998 +-0.0074519999 0.0234379992 -0.0003910000 +-0.0080810003 0.0500000007 0.0419190004 +-0.0080810003 0.0500000007 0.0330809988 +-0.0080810003 0.0500000007 0.0169190001 +-0.0080810003 0.0500000007 0.0080810003 +-0.0080810003 0.0500000007 -0.0080810003 +-0.0080810003 0.0500000007 -0.0169190001 +-0.0080810003 0.0500000007 -0.0330809988 +-0.0080810003 0.0500000007 -0.0419190004 +-0.0080810003 0.0419190004 0.0500000007 +-0.0080810003 0.0419190004 0.0419190004 +-0.0080810003 0.0419190004 0.0330809988 +-0.0080810003 0.0419190004 0.0169190001 +-0.0080810003 0.0419190004 0.0080810003 +-0.0080810003 0.0419190004 -0.0080810003 +-0.0080810003 0.0419190004 -0.0169190001 +-0.0080810003 0.0419190004 -0.0330809988 +-0.0080810003 0.0419190004 -0.0419190004 +-0.0080810003 0.0419190004 -0.0500000007 +-0.0080810003 0.0330809988 0.0500000007 +-0.0080810003 0.0330809988 0.0419190004 +-0.0080810003 0.0330809988 0.0330809988 +-0.0080810003 0.0330809988 0.0169190001 +-0.0080810003 0.0330809988 0.0080810003 +-0.0080810003 0.0330809988 -0.0080810003 +-0.0080810003 0.0330809988 -0.0169190001 +-0.0080810003 0.0330809988 -0.0330809988 +-0.0080810003 0.0330809988 -0.0419190004 +-0.0080810003 0.0330809988 -0.0500000007 +-0.0080810003 0.0169190001 -0.0003910000 +-0.0080810003 0.0169190001 -0.0080810003 +-0.0080810003 0.0169190001 -0.0169190001 +-0.0080810003 0.0169190001 -0.0330809988 +-0.0080810003 0.0169190001 -0.0419190004 +-0.0080810003 0.0169190001 -0.0500000007 +-0.0080810003 0.0080810003 -0.0003910000 +-0.0080810003 0.0080810003 -0.0080810003 +-0.0080810003 0.0080810003 -0.0169190001 +-0.0080810003 0.0080810003 -0.0330809988 +-0.0080810003 0.0080810003 -0.0419190004 +-0.0080810003 0.0080810003 -0.0500000007 +-0.0080810003 -0.0000000000 0.0419190004 +-0.0080810003 -0.0000000000 0.0330809988 +-0.0080810003 -0.0000000000 0.0169190001 +-0.0080810003 -0.0000000000 0.0080810003 +-0.0080810003 -0.0080810003 0.0500000007 +-0.0080810003 -0.0080810003 0.0419190004 +-0.0080810003 -0.0080810003 0.0330809988 +-0.0080810003 -0.0080810003 0.0169190001 +-0.0080810003 -0.0080810003 0.0080810003 +-0.0080810003 -0.0080810003 -0.0080810003 +-0.0080810003 -0.0080810003 -0.0169190001 +-0.0080810003 -0.0080810003 -0.0330809988 +-0.0080810003 -0.0080810003 -0.0419190004 +-0.0080810003 -0.0080810003 -0.0500000007 +-0.0080810003 -0.0169190001 0.0500000007 +-0.0080810003 -0.0169190001 0.0419190004 +-0.0080810003 -0.0169190001 0.0330809988 +-0.0080810003 -0.0169190001 0.0169190001 +-0.0080810003 -0.0169190001 0.0080810003 +-0.0080810003 -0.0169190001 -0.0080810003 +-0.0080810003 -0.0169190001 -0.0169190001 +-0.0080810003 -0.0169190001 -0.0330809988 +-0.0080810003 -0.0169190001 -0.0419190004 +-0.0080810003 -0.0169190001 -0.0500000007 +-0.0080810003 -0.0250000004 0.0419190004 +-0.0080810003 -0.0250000004 0.0330809988 +-0.0080810003 -0.0330809988 0.0212500002 +-0.0080810003 -0.0330809988 0.0169190001 +-0.0080810003 -0.0330809988 0.0080810003 +-0.0080810003 -0.0330809988 -0.0080810003 +-0.0080810003 -0.0330809988 -0.0169190001 +-0.0080810003 -0.0330809988 -0.0330809988 +-0.0080810003 -0.0330809988 -0.0419190004 +-0.0080810003 -0.0330809988 -0.0500000007 +-0.0080810003 -0.0419190004 0.0212500002 +-0.0080810003 -0.0419190004 0.0169190001 +-0.0080810003 -0.0419190004 0.0080810003 +-0.0080810003 -0.0419190004 -0.0080810003 +-0.0080810003 -0.0419190004 -0.0169190001 +-0.0080810003 -0.0419190004 -0.0330809988 +-0.0080810003 -0.0419190004 -0.0419190004 +-0.0080810003 -0.0419190004 -0.0500000007 +-0.0080810003 -0.0500000007 0.0169190001 +-0.0080810003 -0.0500000007 0.0080810003 +-0.0080810003 -0.0500000007 -0.0080810003 +-0.0080810003 -0.0500000007 -0.0169190001 +-0.0080810003 -0.0500000007 -0.0330809988 +-0.0080810003 -0.0500000007 -0.0419190004 +-0.0085260002 0.0234379992 0.0423239991 +-0.0085260002 0.0234379992 0.0326760001 +-0.0085260002 0.0234379992 0.0173240006 +-0.0085260002 0.0234379992 0.0076759998 +-0.0090279998 0.0426970012 0.0426970012 +-0.0090279998 0.0426970012 0.0323030017 +-0.0090279998 0.0426970012 0.0176970009 +-0.0090279998 0.0426970012 0.0073030000 +-0.0090279998 0.0426970012 -0.0073030000 +-0.0090279998 0.0426970012 -0.0176970009 +-0.0090279998 0.0426970012 -0.0323030017 +-0.0090279998 0.0426970012 -0.0426970012 +-0.0090279998 0.0323030017 0.0426970012 +-0.0090279998 0.0323030017 0.0323030017 +-0.0090279998 0.0323030017 0.0176970009 +-0.0090279998 0.0323030017 0.0073030000 +-0.0090279998 0.0323030017 -0.0073030000 +-0.0090279998 0.0323030017 -0.0176970009 +-0.0090279998 0.0323030017 -0.0323030017 +-0.0090279998 0.0323030017 -0.0426970012 +-0.0090279998 0.0176970009 -0.0073030000 +-0.0090279998 0.0176970009 -0.0176970009 +-0.0090279998 0.0176970009 -0.0323030017 +-0.0090279998 0.0176970009 -0.0426970012 +-0.0090279998 0.0073030000 -0.0073030000 +-0.0090279998 0.0073030000 -0.0176970009 +-0.0090279998 0.0073030000 -0.0323030017 +-0.0090279998 0.0073030000 -0.0426970012 +-0.0090279998 -0.0073030000 0.0426970012 +-0.0090279998 -0.0073030000 0.0323030017 +-0.0090279998 -0.0073030000 0.0176970009 +-0.0090279998 -0.0073030000 0.0073030000 +-0.0090279998 -0.0073030000 -0.0073030000 +-0.0090279998 -0.0073030000 -0.0176970009 +-0.0090279998 -0.0073030000 -0.0323030017 +-0.0090279998 -0.0073030000 -0.0426970012 +-0.0090279998 -0.0176970009 0.0426970012 +-0.0090279998 -0.0176970009 0.0323030017 +-0.0090279998 -0.0176970009 0.0176970009 +-0.0090279998 -0.0176970009 0.0073030000 +-0.0090279998 -0.0176970009 -0.0073030000 +-0.0090279998 -0.0176970009 -0.0176970009 +-0.0090279998 -0.0176970009 -0.0323030017 +-0.0090279998 -0.0176970009 -0.0426970012 +-0.0090279998 -0.0323030017 0.0176970009 +-0.0090279998 -0.0323030017 0.0073030000 +-0.0090279998 -0.0323030017 -0.0073030000 +-0.0090279998 -0.0323030017 -0.0176970009 +-0.0090279998 -0.0323030017 -0.0323030017 +-0.0090279998 -0.0323030017 -0.0426970012 +-0.0090279998 -0.0426970012 0.0176970009 +-0.0090279998 -0.0426970012 0.0073030000 +-0.0090279998 -0.0426970012 -0.0073030000 +-0.0090279998 -0.0426970012 -0.0176970009 +-0.0090279998 -0.0426970012 -0.0323030017 +-0.0090279998 -0.0426970012 -0.0426970012 +-0.0093750004 0.0500000007 0.0429130010 +-0.0093750004 0.0500000007 0.0320869982 +-0.0093750004 0.0500000007 0.0179130007 +-0.0093750004 0.0500000007 0.0070870002 +-0.0093750004 0.0500000007 -0.0070870002 +-0.0093750004 0.0500000007 -0.0179130007 +-0.0093750004 0.0500000007 -0.0320869982 +-0.0093750004 0.0500000007 -0.0429130010 +-0.0093750004 0.0429130010 0.0500000007 +-0.0093750004 0.0429130010 -0.0500000007 +-0.0093750004 0.0320869982 0.0500000007 +-0.0093750004 0.0320869982 -0.0500000007 +-0.0093750004 0.0179130007 -0.0003910000 +-0.0093750004 0.0179130007 -0.0500000007 +-0.0093750004 0.0070870002 -0.0003910000 +-0.0093750004 0.0070870002 -0.0500000007 +-0.0093750004 -0.0000000000 0.0429130010 +-0.0093750004 -0.0000000000 0.0320869982 +-0.0093750004 -0.0000000000 0.0179130007 +-0.0093750004 -0.0000000000 0.0070870002 +-0.0093750004 -0.0070870002 0.0500000007 +-0.0093750004 -0.0070870002 -0.0500000007 +-0.0093750004 -0.0179130007 0.0500000007 +-0.0093750004 -0.0179130007 -0.0500000007 +-0.0093750004 -0.0250000004 0.0429130010 +-0.0093750004 -0.0250000004 0.0320869982 +-0.0093750004 -0.0320869982 0.0212500002 +-0.0093750004 -0.0320869982 -0.0500000007 +-0.0093750004 -0.0429130010 0.0212500002 +-0.0093750004 -0.0429130010 -0.0500000007 +-0.0093750004 -0.0500000007 0.0179130007 +-0.0093750004 -0.0500000007 0.0070870002 +-0.0093750004 -0.0500000007 -0.0070870002 +-0.0093750004 -0.0500000007 -0.0179130007 +-0.0093750004 -0.0500000007 -0.0320869982 +-0.0093750004 -0.0500000007 -0.0429130010 +-0.0098489998 0.0234379992 0.0431599990 +-0.0098489998 0.0234379992 0.0318400003 +-0.0098489998 0.0234379992 0.0181600004 +-0.0098489998 0.0234379992 0.0068399999 +-0.0101079997 0.0432740003 0.0432740003 +-0.0101079997 0.0432740003 0.0317259990 +-0.0101079997 0.0432740003 0.0182739999 +-0.0101079997 0.0432740003 0.0067260000 +-0.0101079997 0.0432740003 -0.0067260000 +-0.0101079997 0.0432740003 -0.0182739999 +-0.0101079997 0.0432740003 -0.0317259990 +-0.0101079997 0.0432740003 -0.0432740003 +-0.0101079997 0.0317259990 0.0432740003 +-0.0101079997 0.0317259990 0.0317259990 +-0.0101079997 0.0317259990 0.0182739999 +-0.0101079997 0.0317259990 0.0067260000 +-0.0101079997 0.0317259990 -0.0067260000 +-0.0101079997 0.0317259990 -0.0182739999 +-0.0101079997 0.0317259990 -0.0317259990 +-0.0101079997 0.0317259990 -0.0432740003 +-0.0101079997 0.0182739999 -0.0067260000 +-0.0101079997 0.0182739999 -0.0182739999 +-0.0101079997 0.0182739999 -0.0317259990 +-0.0101079997 0.0182739999 -0.0432740003 +-0.0101079997 0.0067260000 -0.0067260000 +-0.0101079997 0.0067260000 -0.0182739999 +-0.0101079997 0.0067260000 -0.0317259990 +-0.0101079997 0.0067260000 -0.0432740003 +-0.0101079997 -0.0067260000 0.0432740003 +-0.0101079997 -0.0067260000 0.0317259990 +-0.0101079997 -0.0067260000 0.0182739999 +-0.0101079997 -0.0067260000 0.0067260000 +-0.0101079997 -0.0067260000 -0.0067260000 +-0.0101079997 -0.0067260000 -0.0182739999 +-0.0101079997 -0.0067260000 -0.0317259990 +-0.0101079997 -0.0067260000 -0.0432740003 +-0.0101079997 -0.0182739999 0.0432740003 +-0.0101079997 -0.0182739999 0.0317259990 +-0.0101079997 -0.0182739999 0.0182739999 +-0.0101079997 -0.0182739999 0.0067260000 +-0.0101079997 -0.0182739999 -0.0067260000 +-0.0101079997 -0.0182739999 -0.0182739999 +-0.0101079997 -0.0182739999 -0.0317259990 +-0.0101079997 -0.0182739999 -0.0432740003 +-0.0101079997 -0.0317259990 0.0182739999 +-0.0101079997 -0.0317259990 0.0067260000 +-0.0101079997 -0.0317259990 -0.0067260000 +-0.0101079997 -0.0317259990 -0.0182739999 +-0.0101079997 -0.0317259990 -0.0317259990 +-0.0101079997 -0.0317259990 -0.0432740003 +-0.0101079997 -0.0432740003 0.0182739999 +-0.0101079997 -0.0432740003 0.0067260000 +-0.0101079997 -0.0432740003 -0.0067260000 +-0.0101079997 -0.0432740003 -0.0182739999 +-0.0101079997 -0.0432740003 -0.0317259990 +-0.0101079997 -0.0432740003 -0.0432740003 +-0.0108820004 0.0500000007 0.0435369983 +-0.0108820004 0.0500000007 0.0314630009 +-0.0108820004 0.0500000007 0.0185369998 +-0.0108820004 0.0500000007 0.0064630001 +-0.0108820004 0.0500000007 -0.0064630001 +-0.0108820004 0.0500000007 -0.0185369998 +-0.0108820004 0.0500000007 -0.0314630009 +-0.0108820004 0.0500000007 -0.0435369983 +-0.0108820004 0.0435369983 0.0500000007 +-0.0108820004 0.0435369983 -0.0500000007 +-0.0108820004 0.0314630009 0.0500000007 +-0.0108820004 0.0314630009 -0.0500000007 +-0.0108820004 0.0185369998 -0.0003910000 +-0.0108820004 0.0185369998 -0.0500000007 +-0.0108820004 0.0064630001 -0.0003910000 +-0.0108820004 0.0064630001 -0.0500000007 +-0.0108820004 -0.0000000000 0.0435369983 +-0.0108820004 -0.0000000000 0.0314630009 +-0.0108820004 -0.0000000000 0.0185369998 +-0.0108820004 -0.0000000000 0.0064630001 +-0.0108820004 -0.0064630001 0.0500000007 +-0.0108820004 -0.0064630001 -0.0500000007 +-0.0108820004 -0.0185369998 0.0500000007 +-0.0108820004 -0.0185369998 -0.0500000007 +-0.0108820004 -0.0250000004 0.0435369983 +-0.0108820004 -0.0250000004 0.0314630009 +-0.0108820004 -0.0314630009 0.0212500002 +-0.0108820004 -0.0314630009 -0.0500000007 +-0.0108820004 -0.0435369983 0.0212500002 +-0.0108820004 -0.0435369983 -0.0500000007 +-0.0108820004 -0.0500000007 0.0185369998 +-0.0108820004 -0.0500000007 0.0064630001 +-0.0108820004 -0.0500000007 -0.0064630001 +-0.0108820004 -0.0500000007 -0.0185369998 +-0.0108820004 -0.0500000007 -0.0314630009 +-0.0108820004 -0.0500000007 -0.0435369983 +-0.0112810005 0.0436300002 0.0436300002 +-0.0112810005 0.0436300002 0.0313699991 +-0.0112810005 0.0436300002 0.0186299998 +-0.0112810005 0.0436300002 0.0063700001 +-0.0112810005 0.0436300002 -0.0063700001 +-0.0112810005 0.0436300002 -0.0186299998 +-0.0112810005 0.0436300002 -0.0313699991 +-0.0112810005 0.0436300002 -0.0436300002 +-0.0112810005 0.0313699991 0.0436300002 +-0.0112810005 0.0313699991 0.0313699991 +-0.0112810005 0.0313699991 0.0186299998 +-0.0112810005 0.0313699991 0.0063700001 +-0.0112810005 0.0313699991 -0.0063700001 +-0.0112810005 0.0313699991 -0.0186299998 +-0.0112810005 0.0313699991 -0.0313699991 +-0.0112810005 0.0313699991 -0.0436300002 +-0.0112810005 0.0186299998 -0.0063700001 +-0.0112810005 0.0186299998 -0.0186299998 +-0.0112810005 0.0186299998 -0.0313699991 +-0.0112810005 0.0186299998 -0.0436300002 +-0.0112810005 0.0063700001 -0.0063700001 +-0.0112810005 0.0063700001 -0.0186299998 +-0.0112810005 0.0063700001 -0.0313699991 +-0.0112810005 0.0063700001 -0.0436300002 +-0.0112810005 -0.0063700001 0.0436300002 +-0.0112810005 -0.0063700001 0.0313699991 +-0.0112810005 -0.0063700001 0.0186299998 +-0.0112810005 -0.0063700001 0.0063700001 +-0.0112810005 -0.0063700001 -0.0063700001 +-0.0112810005 -0.0063700001 -0.0186299998 +-0.0112810005 -0.0063700001 -0.0313699991 +-0.0112810005 -0.0063700001 -0.0436300002 +-0.0112810005 -0.0186299998 0.0436300002 +-0.0112810005 -0.0186299998 0.0313699991 +-0.0112810005 -0.0186299998 0.0186299998 +-0.0112810005 -0.0186299998 0.0063700001 +-0.0112810005 -0.0186299998 -0.0063700001 +-0.0112810005 -0.0186299998 -0.0186299998 +-0.0112810005 -0.0186299998 -0.0313699991 +-0.0112810005 -0.0186299998 -0.0436300002 +-0.0112810005 -0.0313699991 0.0186299998 +-0.0112810005 -0.0313699991 0.0063700001 +-0.0112810005 -0.0313699991 -0.0063700001 +-0.0112810005 -0.0313699991 -0.0186299998 +-0.0112810005 -0.0313699991 -0.0313699991 +-0.0112810005 -0.0313699991 -0.0436300002 +-0.0112810005 -0.0436300002 0.0186299998 +-0.0112810005 -0.0436300002 0.0063700001 +-0.0112810005 -0.0436300002 -0.0063700001 +-0.0112810005 -0.0436300002 -0.0186299998 +-0.0112810005 -0.0436300002 -0.0313699991 +-0.0112810005 -0.0436300002 -0.0436300002 +-0.0113390004 0.0234379992 0.0436410010 +-0.0113390004 0.0234379992 0.0313589983 +-0.0113390004 0.0234379992 0.0186410006 +-0.0113390004 0.0234379992 0.0063590002 +-0.0118869999 0.0437199995 0.0437199995 +-0.0118869999 0.0437199995 0.0312799998 +-0.0118869999 0.0437199995 0.0187199991 +-0.0118869999 0.0437199995 0.0062799999 +-0.0118869999 0.0437199995 -0.0062799999 +-0.0118869999 0.0437199995 -0.0187199991 +-0.0118869999 0.0437199995 -0.0312799998 +-0.0118869999 0.0437199995 -0.0437199995 +-0.0118869999 0.0312799998 0.0437199995 +-0.0118869999 0.0312799998 0.0312799998 +-0.0118869999 0.0312799998 0.0187199991 +-0.0118869999 0.0312799998 0.0062799999 +-0.0118869999 0.0312799998 -0.0062799999 +-0.0118869999 0.0312799998 -0.0187199991 +-0.0118869999 0.0312799998 -0.0312799998 +-0.0118869999 0.0312799998 -0.0437199995 +-0.0118869999 0.0187199991 -0.0062799999 +-0.0118869999 0.0187199991 -0.0187199991 +-0.0118869999 0.0187199991 -0.0312799998 +-0.0118869999 0.0187199991 -0.0437199995 +-0.0118869999 0.0062799999 -0.0062799999 +-0.0118869999 0.0062799999 -0.0187199991 +-0.0118869999 0.0062799999 -0.0312799998 +-0.0118869999 0.0062799999 -0.0437199995 +-0.0118869999 -0.0062799999 0.0437199995 +-0.0118869999 -0.0062799999 0.0312799998 +-0.0118869999 -0.0062799999 0.0187199991 +-0.0118869999 -0.0062799999 0.0062799999 +-0.0118869999 -0.0062799999 -0.0062799999 +-0.0118869999 -0.0062799999 -0.0187199991 +-0.0118869999 -0.0062799999 -0.0312799998 +-0.0118869999 -0.0062799999 -0.0437199995 +-0.0118869999 -0.0187199991 0.0437199995 +-0.0118869999 -0.0187199991 0.0312799998 +-0.0118869999 -0.0187199991 0.0187199991 +-0.0118869999 -0.0187199991 0.0062799999 +-0.0118869999 -0.0187199991 -0.0062799999 +-0.0118869999 -0.0187199991 -0.0187199991 +-0.0118869999 -0.0187199991 -0.0312799998 +-0.0118869999 -0.0187199991 -0.0437199995 +-0.0118869999 -0.0312799998 0.0187199991 +-0.0118869999 -0.0312799998 0.0062799999 +-0.0118869999 -0.0312799998 -0.0062799999 +-0.0118869999 -0.0312799998 -0.0187199991 +-0.0118869999 -0.0312799998 -0.0312799998 +-0.0118869999 -0.0312799998 -0.0437199995 +-0.0118869999 -0.0437199995 0.0187199991 +-0.0118869999 -0.0437199995 0.0062799999 +-0.0118869999 -0.0437199995 -0.0062799999 +-0.0118869999 -0.0437199995 -0.0187199991 +-0.0118869999 -0.0437199995 -0.0312799998 +-0.0118869999 -0.0437199995 -0.0437199995 +-0.0125000002 0.0500000007 0.0437499993 +-0.0125000002 0.0500000007 0.0312500000 +-0.0125000002 0.0500000007 0.0187500007 +-0.0125000002 0.0500000007 0.0062500001 +-0.0125000002 0.0500000007 -0.0062500001 +-0.0125000002 0.0500000007 -0.0187500007 +-0.0125000002 0.0500000007 -0.0312500000 +-0.0125000002 0.0500000007 -0.0437499993 +-0.0125000002 0.0437499993 0.0500000007 +-0.0125000002 0.0437499993 0.0437499993 +-0.0125000002 0.0437499993 0.0312500000 +-0.0125000002 0.0437499993 0.0187500007 +-0.0125000002 0.0437499993 0.0062500001 +-0.0125000002 0.0437499993 -0.0062500001 +-0.0125000002 0.0437499993 -0.0187500007 +-0.0125000002 0.0437499993 -0.0312500000 +-0.0125000002 0.0437499993 -0.0437499993 +-0.0125000002 0.0437499993 -0.0500000007 +-0.0125000002 0.0312500000 0.0500000007 +-0.0125000002 0.0312500000 0.0437499993 +-0.0125000002 0.0312500000 0.0312500000 +-0.0125000002 0.0312500000 0.0187500007 +-0.0125000002 0.0312500000 0.0062500001 +-0.0125000002 0.0312500000 -0.0062500001 +-0.0125000002 0.0312500000 -0.0187500007 +-0.0125000002 0.0312500000 -0.0312500000 +-0.0125000002 0.0312500000 -0.0437499993 +-0.0125000002 0.0312500000 -0.0500000007 +-0.0125000002 0.0187500007 -0.0003910000 +-0.0125000002 0.0187500007 -0.0062500001 +-0.0125000002 0.0187500007 -0.0187500007 +-0.0125000002 0.0187500007 -0.0312500000 +-0.0125000002 0.0187500007 -0.0437499993 +-0.0125000002 0.0187500007 -0.0500000007 +-0.0125000002 0.0062500001 -0.0003910000 +-0.0125000002 0.0062500001 -0.0062500001 +-0.0125000002 0.0062500001 -0.0187500007 +-0.0125000002 0.0062500001 -0.0312500000 +-0.0125000002 0.0062500001 -0.0437499993 +-0.0125000002 0.0062500001 -0.0500000007 +-0.0125000002 -0.0000000000 0.0437499993 +-0.0125000002 -0.0000000000 0.0312500000 +-0.0125000002 -0.0000000000 0.0187500007 +-0.0125000002 -0.0000000000 0.0062500001 +-0.0125000002 -0.0062500001 0.0500000007 +-0.0125000002 -0.0062500001 0.0437499993 +-0.0125000002 -0.0062500001 0.0312500000 +-0.0125000002 -0.0062500001 0.0187500007 +-0.0125000002 -0.0062500001 0.0062500001 +-0.0125000002 -0.0062500001 -0.0062500001 +-0.0125000002 -0.0062500001 -0.0187500007 +-0.0125000002 -0.0062500001 -0.0312500000 +-0.0125000002 -0.0062500001 -0.0437499993 +-0.0125000002 -0.0062500001 -0.0500000007 +-0.0125000002 -0.0187500007 0.0500000007 +-0.0125000002 -0.0187500007 0.0437499993 +-0.0125000002 -0.0187500007 0.0312500000 +-0.0125000002 -0.0187500007 0.0187500007 +-0.0125000002 -0.0187500007 0.0062500001 +-0.0125000002 -0.0187500007 -0.0062500001 +-0.0125000002 -0.0187500007 -0.0187500007 +-0.0125000002 -0.0187500007 -0.0312500000 +-0.0125000002 -0.0187500007 -0.0437499993 +-0.0125000002 -0.0187500007 -0.0500000007 +-0.0125000002 -0.0250000004 0.0437499993 +-0.0125000002 -0.0250000004 0.0312500000 +-0.0125000002 -0.0312500000 0.0212500002 +-0.0125000002 -0.0312500000 0.0187500007 +-0.0125000002 -0.0312500000 0.0062500001 +-0.0125000002 -0.0312500000 -0.0062500001 +-0.0125000002 -0.0312500000 -0.0187500007 +-0.0125000002 -0.0312500000 -0.0312500000 +-0.0125000002 -0.0312500000 -0.0437499993 +-0.0125000002 -0.0312500000 -0.0500000007 +-0.0125000002 -0.0437499993 0.0212500002 +-0.0125000002 -0.0437499993 0.0187500007 +-0.0125000002 -0.0437499993 0.0062500001 +-0.0125000002 -0.0437499993 -0.0062500001 +-0.0125000002 -0.0437499993 -0.0187500007 +-0.0125000002 -0.0437499993 -0.0312500000 +-0.0125000002 -0.0437499993 -0.0437499993 +-0.0125000002 -0.0437499993 -0.0500000007 +-0.0125000002 -0.0500000007 0.0187500007 +-0.0125000002 -0.0500000007 0.0062500001 +-0.0125000002 -0.0500000007 -0.0062500001 +-0.0125000002 -0.0500000007 -0.0187500007 +-0.0125000002 -0.0500000007 -0.0312500000 +-0.0125000002 -0.0500000007 -0.0437499993 +-0.0129009997 0.0234379992 0.0437370017 +-0.0129009997 0.0234379992 0.0312630013 +-0.0129009997 0.0234379992 0.0187369995 +-0.0129009997 0.0234379992 0.0062630000 +-0.0131130004 0.0437199995 0.0437199995 +-0.0131130004 0.0437199995 0.0312799998 +-0.0131130004 0.0437199995 0.0187199991 +-0.0131130004 0.0437199995 0.0062799999 +-0.0131130004 0.0437199995 -0.0062799999 +-0.0131130004 0.0437199995 -0.0187199991 +-0.0131130004 0.0437199995 -0.0312799998 +-0.0131130004 0.0437199995 -0.0437199995 +-0.0131130004 0.0312799998 0.0437199995 +-0.0131130004 0.0312799998 0.0312799998 +-0.0131130004 0.0312799998 0.0187199991 +-0.0131130004 0.0312799998 0.0062799999 +-0.0131130004 0.0312799998 -0.0062799999 +-0.0131130004 0.0312799998 -0.0187199991 +-0.0131130004 0.0312799998 -0.0312799998 +-0.0131130004 0.0312799998 -0.0437199995 +-0.0131130004 0.0187199991 -0.0062799999 +-0.0131130004 0.0187199991 -0.0187199991 +-0.0131130004 0.0187199991 -0.0312799998 +-0.0131130004 0.0187199991 -0.0437199995 +-0.0131130004 0.0062799999 -0.0062799999 +-0.0131130004 0.0062799999 -0.0187199991 +-0.0131130004 0.0062799999 -0.0312799998 +-0.0131130004 0.0062799999 -0.0437199995 +-0.0131130004 -0.0062799999 0.0437199995 +-0.0131130004 -0.0062799999 0.0312799998 +-0.0131130004 -0.0062799999 0.0187199991 +-0.0131130004 -0.0062799999 0.0062799999 +-0.0131130004 -0.0062799999 -0.0062799999 +-0.0131130004 -0.0062799999 -0.0187199991 +-0.0131130004 -0.0062799999 -0.0312799998 +-0.0131130004 -0.0062799999 -0.0437199995 +-0.0131130004 -0.0187199991 0.0437199995 +-0.0131130004 -0.0187199991 0.0312799998 +-0.0131130004 -0.0187199991 0.0187199991 +-0.0131130004 -0.0187199991 0.0062799999 +-0.0131130004 -0.0187199991 -0.0062799999 +-0.0131130004 -0.0187199991 -0.0187199991 +-0.0131130004 -0.0187199991 -0.0312799998 +-0.0131130004 -0.0187199991 -0.0437199995 +-0.0131130004 -0.0312799998 0.0187199991 +-0.0131130004 -0.0312799998 0.0062799999 +-0.0131130004 -0.0312799998 -0.0062799999 +-0.0131130004 -0.0312799998 -0.0187199991 +-0.0131130004 -0.0312799998 -0.0312799998 +-0.0131130004 -0.0312799998 -0.0437199995 +-0.0131130004 -0.0437199995 0.0187199991 +-0.0131130004 -0.0437199995 0.0062799999 +-0.0131130004 -0.0437199995 -0.0062799999 +-0.0131130004 -0.0437199995 -0.0187199991 +-0.0131130004 -0.0437199995 -0.0312799998 +-0.0131130004 -0.0437199995 -0.0437199995 +-0.0137189999 0.0436300002 0.0436300002 +-0.0137189999 0.0436300002 0.0313699991 +-0.0137189999 0.0436300002 0.0186299998 +-0.0137189999 0.0436300002 0.0063700001 +-0.0137189999 0.0436300002 -0.0063700001 +-0.0137189999 0.0436300002 -0.0186299998 +-0.0137189999 0.0436300002 -0.0313699991 +-0.0137189999 0.0436300002 -0.0436300002 +-0.0137189999 0.0313699991 0.0436300002 +-0.0137189999 0.0313699991 0.0313699991 +-0.0137189999 0.0313699991 0.0186299998 +-0.0137189999 0.0313699991 0.0063700001 +-0.0137189999 0.0313699991 -0.0063700001 +-0.0137189999 0.0313699991 -0.0186299998 +-0.0137189999 0.0313699991 -0.0313699991 +-0.0137189999 0.0313699991 -0.0436300002 +-0.0137189999 0.0186299998 -0.0063700001 +-0.0137189999 0.0186299998 -0.0186299998 +-0.0137189999 0.0186299998 -0.0313699991 +-0.0137189999 0.0186299998 -0.0436300002 +-0.0137189999 0.0063700001 -0.0063700001 +-0.0137189999 0.0063700001 -0.0186299998 +-0.0137189999 0.0063700001 -0.0313699991 +-0.0137189999 0.0063700001 -0.0436300002 +-0.0137189999 -0.0063700001 0.0436300002 +-0.0137189999 -0.0063700001 0.0313699991 +-0.0137189999 -0.0063700001 0.0186299998 +-0.0137189999 -0.0063700001 0.0063700001 +-0.0137189999 -0.0063700001 -0.0063700001 +-0.0137189999 -0.0063700001 -0.0186299998 +-0.0137189999 -0.0063700001 -0.0313699991 +-0.0137189999 -0.0063700001 -0.0436300002 +-0.0137189999 -0.0186299998 0.0436300002 +-0.0137189999 -0.0186299998 0.0313699991 +-0.0137189999 -0.0186299998 0.0186299998 +-0.0137189999 -0.0186299998 0.0063700001 +-0.0137189999 -0.0186299998 -0.0063700001 +-0.0137189999 -0.0186299998 -0.0186299998 +-0.0137189999 -0.0186299998 -0.0313699991 +-0.0137189999 -0.0186299998 -0.0436300002 +-0.0137189999 -0.0313699991 0.0186299998 +-0.0137189999 -0.0313699991 0.0063700001 +-0.0137189999 -0.0313699991 -0.0063700001 +-0.0137189999 -0.0313699991 -0.0186299998 +-0.0137189999 -0.0313699991 -0.0313699991 +-0.0137189999 -0.0313699991 -0.0436300002 +-0.0137189999 -0.0436300002 0.0186299998 +-0.0137189999 -0.0436300002 0.0063700001 +-0.0137189999 -0.0436300002 -0.0063700001 +-0.0137189999 -0.0436300002 -0.0186299998 +-0.0137189999 -0.0436300002 -0.0313699991 +-0.0137189999 -0.0436300002 -0.0436300002 +-0.0141179999 0.0500000007 0.0435369983 +-0.0141179999 0.0500000007 0.0314630009 +-0.0141179999 0.0500000007 0.0185369998 +-0.0141179999 0.0500000007 0.0064630001 +-0.0141179999 0.0500000007 -0.0064630001 +-0.0141179999 0.0500000007 -0.0185369998 +-0.0141179999 0.0500000007 -0.0314630009 +-0.0141179999 0.0500000007 -0.0435369983 +-0.0141179999 0.0435369983 0.0500000007 +-0.0141179999 0.0435369983 -0.0500000007 +-0.0141179999 0.0314630009 0.0500000007 +-0.0141179999 0.0314630009 -0.0500000007 +-0.0141179999 0.0185369998 -0.0003910000 +-0.0141179999 0.0185369998 -0.0500000007 +-0.0141179999 0.0064630001 -0.0003910000 +-0.0141179999 0.0064630001 -0.0500000007 +-0.0141179999 -0.0000000000 0.0435369983 +-0.0141179999 -0.0000000000 0.0314630009 +-0.0141179999 -0.0000000000 0.0185369998 +-0.0141179999 -0.0000000000 0.0064630001 +-0.0141179999 -0.0064630001 0.0500000007 +-0.0141179999 -0.0064630001 -0.0500000007 +-0.0141179999 -0.0185369998 0.0500000007 +-0.0141179999 -0.0185369998 -0.0500000007 +-0.0141179999 -0.0250000004 0.0435369983 +-0.0141179999 -0.0250000004 0.0314630009 +-0.0141179999 -0.0314630009 0.0212500002 +-0.0141179999 -0.0314630009 -0.0500000007 +-0.0141179999 -0.0435369983 0.0212500002 +-0.0141179999 -0.0435369983 -0.0500000007 +-0.0141179999 -0.0500000007 0.0185369998 +-0.0141179999 -0.0500000007 0.0064630001 +-0.0141179999 -0.0500000007 -0.0064630001 +-0.0141179999 -0.0500000007 -0.0185369998 +-0.0141179999 -0.0500000007 -0.0314630009 +-0.0141179999 -0.0500000007 -0.0435369983 +-0.0144379996 0.0234379992 0.0434419997 +-0.0144379996 0.0234379992 0.0315579996 +-0.0144379996 0.0234379992 0.0184419993 +-0.0144379996 0.0234379992 0.0065580001 +-0.0148919998 0.0432740003 0.0432740003 +-0.0148919998 0.0432740003 0.0317259990 +-0.0148919998 0.0432740003 0.0182739999 +-0.0148919998 0.0432740003 0.0067260000 +-0.0148919998 0.0432740003 -0.0067260000 +-0.0148919998 0.0432740003 -0.0182739999 +-0.0148919998 0.0432740003 -0.0317259990 +-0.0148919998 0.0432740003 -0.0432740003 +-0.0148919998 0.0317259990 0.0432740003 +-0.0148919998 0.0317259990 0.0317259990 +-0.0148919998 0.0317259990 0.0182739999 +-0.0148919998 0.0317259990 0.0067260000 +-0.0148919998 0.0317259990 -0.0067260000 +-0.0148919998 0.0317259990 -0.0182739999 +-0.0148919998 0.0317259990 -0.0317259990 +-0.0148919998 0.0317259990 -0.0432740003 +-0.0148919998 0.0182739999 -0.0067260000 +-0.0148919998 0.0182739999 -0.0182739999 +-0.0148919998 0.0182739999 -0.0317259990 +-0.0148919998 0.0182739999 -0.0432740003 +-0.0148919998 0.0067260000 -0.0067260000 +-0.0148919998 0.0067260000 -0.0182739999 +-0.0148919998 0.0067260000 -0.0317259990 +-0.0148919998 0.0067260000 -0.0432740003 +-0.0148919998 -0.0067260000 0.0432740003 +-0.0148919998 -0.0067260000 0.0317259990 +-0.0148919998 -0.0067260000 0.0182739999 +-0.0148919998 -0.0067260000 0.0067260000 +-0.0148919998 -0.0067260000 -0.0067260000 +-0.0148919998 -0.0067260000 -0.0182739999 +-0.0148919998 -0.0067260000 -0.0317259990 +-0.0148919998 -0.0067260000 -0.0432740003 +-0.0148919998 -0.0182739999 0.0432740003 +-0.0148919998 -0.0182739999 0.0317259990 +-0.0148919998 -0.0182739999 0.0182739999 +-0.0148919998 -0.0182739999 0.0067260000 +-0.0148919998 -0.0182739999 -0.0067260000 +-0.0148919998 -0.0182739999 -0.0182739999 +-0.0148919998 -0.0182739999 -0.0317259990 +-0.0148919998 -0.0182739999 -0.0432740003 +-0.0148919998 -0.0317259990 0.0182739999 +-0.0148919998 -0.0317259990 0.0067260000 +-0.0148919998 -0.0317259990 -0.0067260000 +-0.0148919998 -0.0317259990 -0.0182739999 +-0.0148919998 -0.0317259990 -0.0317259990 +-0.0148919998 -0.0317259990 -0.0432740003 +-0.0148919998 -0.0432740003 0.0182739999 +-0.0148919998 -0.0432740003 0.0067260000 +-0.0148919998 -0.0432740003 -0.0067260000 +-0.0148919998 -0.0432740003 -0.0182739999 +-0.0148919998 -0.0432740003 -0.0317259990 +-0.0148919998 -0.0432740003 -0.0432740003 +-0.0156250000 0.0500000007 0.0429130010 +-0.0156250000 0.0500000007 0.0320869982 +-0.0156250000 0.0500000007 0.0179130007 +-0.0156250000 0.0500000007 0.0070870002 +-0.0156250000 0.0500000007 -0.0070870002 +-0.0156250000 0.0500000007 -0.0179130007 +-0.0156250000 0.0500000007 -0.0320869982 +-0.0156250000 0.0500000007 -0.0429130010 +-0.0156250000 0.0429130010 0.0500000007 +-0.0156250000 0.0429130010 -0.0500000007 +-0.0156250000 0.0320869982 0.0500000007 +-0.0156250000 0.0320869982 -0.0500000007 +-0.0156250000 0.0179130007 -0.0003910000 +-0.0156250000 0.0179130007 -0.0500000007 +-0.0156250000 0.0070870002 -0.0003910000 +-0.0156250000 0.0070870002 -0.0500000007 +-0.0156250000 -0.0000000000 0.0429130010 +-0.0156250000 -0.0000000000 0.0320869982 +-0.0156250000 -0.0000000000 0.0179130007 +-0.0156250000 -0.0000000000 0.0070870002 +-0.0156250000 -0.0070870002 0.0500000007 +-0.0156250000 -0.0070870002 -0.0500000007 +-0.0156250000 -0.0179130007 0.0500000007 +-0.0156250000 -0.0179130007 -0.0500000007 +-0.0156250000 -0.0250000004 0.0429130010 +-0.0156250000 -0.0250000004 0.0320869982 +-0.0156250000 -0.0320869982 0.0212500002 +-0.0156250000 -0.0320869982 -0.0500000007 +-0.0156250000 -0.0429130010 0.0212500002 +-0.0156250000 -0.0429130010 -0.0500000007 +-0.0156250000 -0.0500000007 0.0179130007 +-0.0156250000 -0.0500000007 0.0070870002 +-0.0156250000 -0.0500000007 -0.0070870002 +-0.0156250000 -0.0500000007 -0.0179130007 +-0.0156250000 -0.0500000007 -0.0320869982 +-0.0156250000 -0.0500000007 -0.0429130010 +-0.0158539992 0.0234379992 0.0427739993 +-0.0158539992 0.0234379992 0.0322260000 +-0.0158539992 0.0234379992 0.0177740008 +-0.0158539992 0.0234379992 0.0072260001 +-0.0159719996 0.0426970012 0.0426970012 +-0.0159719996 0.0426970012 0.0323030017 +-0.0159719996 0.0426970012 0.0176970009 +-0.0159719996 0.0426970012 0.0073030000 +-0.0159719996 0.0426970012 -0.0073030000 +-0.0159719996 0.0426970012 -0.0176970009 +-0.0159719996 0.0426970012 -0.0323030017 +-0.0159719996 0.0426970012 -0.0426970012 +-0.0159719996 0.0323030017 0.0426970012 +-0.0159719996 0.0323030017 0.0323030017 +-0.0159719996 0.0323030017 0.0176970009 +-0.0159719996 0.0323030017 0.0073030000 +-0.0159719996 0.0323030017 -0.0073030000 +-0.0159719996 0.0323030017 -0.0176970009 +-0.0159719996 0.0323030017 -0.0323030017 +-0.0159719996 0.0323030017 -0.0426970012 +-0.0159719996 0.0176970009 -0.0073030000 +-0.0159719996 0.0176970009 -0.0176970009 +-0.0159719996 0.0176970009 -0.0323030017 +-0.0159719996 0.0176970009 -0.0426970012 +-0.0159719996 0.0073030000 -0.0073030000 +-0.0159719996 0.0073030000 -0.0176970009 +-0.0159719996 0.0073030000 -0.0323030017 +-0.0159719996 0.0073030000 -0.0426970012 +-0.0159719996 -0.0073030000 0.0426970012 +-0.0159719996 -0.0073030000 0.0323030017 +-0.0159719996 -0.0073030000 0.0176970009 +-0.0159719996 -0.0073030000 0.0073030000 +-0.0159719996 -0.0073030000 -0.0073030000 +-0.0159719996 -0.0073030000 -0.0176970009 +-0.0159719996 -0.0073030000 -0.0323030017 +-0.0159719996 -0.0073030000 -0.0426970012 +-0.0159719996 -0.0176970009 0.0426970012 +-0.0159719996 -0.0176970009 0.0323030017 +-0.0159719996 -0.0176970009 0.0176970009 +-0.0159719996 -0.0176970009 0.0073030000 +-0.0159719996 -0.0176970009 -0.0073030000 +-0.0159719996 -0.0176970009 -0.0176970009 +-0.0159719996 -0.0176970009 -0.0323030017 +-0.0159719996 -0.0176970009 -0.0426970012 +-0.0159719996 -0.0323030017 0.0176970009 +-0.0159719996 -0.0323030017 0.0073030000 +-0.0159719996 -0.0323030017 -0.0073030000 +-0.0159719996 -0.0323030017 -0.0176970009 +-0.0159719996 -0.0323030017 -0.0323030017 +-0.0159719996 -0.0323030017 -0.0426970012 +-0.0159719996 -0.0426970012 0.0176970009 +-0.0159719996 -0.0426970012 0.0073030000 +-0.0159719996 -0.0426970012 -0.0073030000 +-0.0159719996 -0.0426970012 -0.0176970009 +-0.0159719996 -0.0426970012 -0.0323030017 +-0.0159719996 -0.0426970012 -0.0426970012 +-0.0169190001 0.0500000007 0.0419190004 +-0.0169190001 0.0500000007 0.0330809988 +-0.0169190001 0.0500000007 0.0169190001 +-0.0169190001 0.0500000007 0.0080810003 +-0.0169190001 0.0500000007 -0.0080810003 +-0.0169190001 0.0500000007 -0.0169190001 +-0.0169190001 0.0500000007 -0.0330809988 +-0.0169190001 0.0500000007 -0.0419190004 +-0.0169190001 0.0419190004 0.0500000007 +-0.0169190001 0.0419190004 0.0419190004 +-0.0169190001 0.0419190004 0.0330809988 +-0.0169190001 0.0419190004 0.0169190001 +-0.0169190001 0.0419190004 0.0080810003 +-0.0169190001 0.0419190004 -0.0080810003 +-0.0169190001 0.0419190004 -0.0169190001 +-0.0169190001 0.0419190004 -0.0330809988 +-0.0169190001 0.0419190004 -0.0419190004 +-0.0169190001 0.0419190004 -0.0500000007 +-0.0169190001 0.0330809988 0.0500000007 +-0.0169190001 0.0330809988 0.0419190004 +-0.0169190001 0.0330809988 0.0330809988 +-0.0169190001 0.0330809988 0.0169190001 +-0.0169190001 0.0330809988 0.0080810003 +-0.0169190001 0.0330809988 -0.0080810003 +-0.0169190001 0.0330809988 -0.0169190001 +-0.0169190001 0.0330809988 -0.0330809988 +-0.0169190001 0.0330809988 -0.0419190004 +-0.0169190001 0.0330809988 -0.0500000007 +-0.0169190001 0.0169190001 -0.0003910000 +-0.0169190001 0.0169190001 -0.0080810003 +-0.0169190001 0.0169190001 -0.0169190001 +-0.0169190001 0.0169190001 -0.0330809988 +-0.0169190001 0.0169190001 -0.0419190004 +-0.0169190001 0.0169190001 -0.0500000007 +-0.0169190001 0.0080810003 -0.0003910000 +-0.0169190001 0.0080810003 -0.0080810003 +-0.0169190001 0.0080810003 -0.0169190001 +-0.0169190001 0.0080810003 -0.0330809988 +-0.0169190001 0.0080810003 -0.0419190004 +-0.0169190001 0.0080810003 -0.0500000007 +-0.0169190001 -0.0000000000 0.0419190004 +-0.0169190001 -0.0000000000 0.0330809988 +-0.0169190001 -0.0000000000 0.0169190001 +-0.0169190001 -0.0000000000 0.0080810003 +-0.0169190001 -0.0080810003 0.0500000007 +-0.0169190001 -0.0080810003 0.0419190004 +-0.0169190001 -0.0080810003 0.0330809988 +-0.0169190001 -0.0080810003 0.0169190001 +-0.0169190001 -0.0080810003 0.0080810003 +-0.0169190001 -0.0080810003 -0.0080810003 +-0.0169190001 -0.0080810003 -0.0169190001 +-0.0169190001 -0.0080810003 -0.0330809988 +-0.0169190001 -0.0080810003 -0.0419190004 +-0.0169190001 -0.0080810003 -0.0500000007 +-0.0169190001 -0.0169190001 0.0500000007 +-0.0169190001 -0.0169190001 0.0419190004 +-0.0169190001 -0.0169190001 0.0330809988 +-0.0169190001 -0.0169190001 0.0169190001 +-0.0169190001 -0.0169190001 0.0080810003 +-0.0169190001 -0.0169190001 -0.0080810003 +-0.0169190001 -0.0169190001 -0.0169190001 +-0.0169190001 -0.0169190001 -0.0330809988 +-0.0169190001 -0.0169190001 -0.0419190004 +-0.0169190001 -0.0169190001 -0.0500000007 +-0.0169190001 -0.0250000004 0.0419190004 +-0.0169190001 -0.0250000004 0.0330809988 +-0.0169190001 -0.0330809988 0.0212500002 +-0.0169190001 -0.0330809988 0.0169190001 +-0.0169190001 -0.0330809988 0.0080810003 +-0.0169190001 -0.0330809988 -0.0080810003 +-0.0169190001 -0.0330809988 -0.0169190001 +-0.0169190001 -0.0330809988 -0.0330809988 +-0.0169190001 -0.0330809988 -0.0419190004 +-0.0169190001 -0.0330809988 -0.0500000007 +-0.0169190001 -0.0419190004 0.0212500002 +-0.0169190001 -0.0419190004 0.0169190001 +-0.0169190001 -0.0419190004 0.0080810003 +-0.0169190001 -0.0419190004 -0.0080810003 +-0.0169190001 -0.0419190004 -0.0169190001 +-0.0169190001 -0.0419190004 -0.0330809988 +-0.0169190001 -0.0419190004 -0.0419190004 +-0.0169190001 -0.0419190004 -0.0500000007 +-0.0169190001 -0.0500000007 0.0169190001 +-0.0169190001 -0.0500000007 0.0080810003 +-0.0169190001 -0.0500000007 -0.0080810003 +-0.0169190001 -0.0500000007 -0.0169190001 +-0.0169190001 -0.0500000007 -0.0330809988 +-0.0169190001 -0.0500000007 -0.0419190004 +-0.0170590002 0.0234379992 0.0417749994 +-0.0170590002 0.0234379992 0.0332249999 +-0.0170590002 0.0234379992 0.0167750008 +-0.0170590002 0.0234379992 0.0082250005 +-0.0176970009 0.0426970012 0.0409720019 +-0.0176970009 0.0426970012 0.0340280011 +-0.0176970009 0.0426970012 0.0159719996 +-0.0176970009 0.0426970012 0.0090279998 +-0.0176970009 0.0426970012 -0.0090279998 +-0.0176970009 0.0426970012 -0.0159719996 +-0.0176970009 0.0426970012 -0.0340280011 +-0.0176970009 0.0426970012 -0.0409720019 +-0.0176970009 0.0409720019 0.0426970012 +-0.0176970009 0.0409720019 0.0323030017 +-0.0176970009 0.0409720019 0.0176970009 +-0.0176970009 0.0409720019 0.0073030000 +-0.0176970009 0.0409720019 -0.0073030000 +-0.0176970009 0.0409720019 -0.0176970009 +-0.0176970009 0.0409720019 -0.0323030017 +-0.0176970009 0.0409720019 -0.0426970012 +-0.0176970009 0.0340280011 0.0426970012 +-0.0176970009 0.0340280011 0.0323030017 +-0.0176970009 0.0340280011 0.0176970009 +-0.0176970009 0.0340280011 0.0073030000 +-0.0176970009 0.0340280011 -0.0073030000 +-0.0176970009 0.0340280011 -0.0176970009 +-0.0176970009 0.0340280011 -0.0323030017 +-0.0176970009 0.0340280011 -0.0426970012 +-0.0176970009 0.0323030017 0.0409720019 +-0.0176970009 0.0323030017 0.0340280011 +-0.0176970009 0.0323030017 0.0159719996 +-0.0176970009 0.0323030017 0.0090279998 +-0.0176970009 0.0323030017 -0.0090279998 +-0.0176970009 0.0323030017 -0.0159719996 +-0.0176970009 0.0323030017 -0.0340280011 +-0.0176970009 0.0323030017 -0.0409720019 +-0.0176970009 0.0176970009 -0.0090279998 +-0.0176970009 0.0176970009 -0.0159719996 +-0.0176970009 0.0176970009 -0.0340280011 +-0.0176970009 0.0176970009 -0.0409720019 +-0.0176970009 0.0159719996 -0.0073030000 +-0.0176970009 0.0159719996 -0.0176970009 +-0.0176970009 0.0159719996 -0.0323030017 +-0.0176970009 0.0159719996 -0.0426970012 +-0.0176970009 0.0090279998 -0.0073030000 +-0.0176970009 0.0090279998 -0.0176970009 +-0.0176970009 0.0090279998 -0.0323030017 +-0.0176970009 0.0090279998 -0.0426970012 +-0.0176970009 0.0073030000 -0.0090279998 +-0.0176970009 0.0073030000 -0.0159719996 +-0.0176970009 0.0073030000 -0.0340280011 +-0.0176970009 0.0073030000 -0.0409720019 +-0.0176970009 -0.0073030000 0.0409720019 +-0.0176970009 -0.0073030000 0.0340280011 +-0.0176970009 -0.0073030000 0.0159719996 +-0.0176970009 -0.0073030000 0.0090279998 +-0.0176970009 -0.0073030000 -0.0090279998 +-0.0176970009 -0.0073030000 -0.0159719996 +-0.0176970009 -0.0073030000 -0.0340280011 +-0.0176970009 -0.0073030000 -0.0409720019 +-0.0176970009 -0.0090279998 0.0426970012 +-0.0176970009 -0.0090279998 0.0323030017 +-0.0176970009 -0.0090279998 0.0176970009 +-0.0176970009 -0.0090279998 0.0073030000 +-0.0176970009 -0.0090279998 -0.0073030000 +-0.0176970009 -0.0090279998 -0.0176970009 +-0.0176970009 -0.0090279998 -0.0323030017 +-0.0176970009 -0.0090279998 -0.0426970012 +-0.0176970009 -0.0159719996 0.0426970012 +-0.0176970009 -0.0159719996 0.0323030017 +-0.0176970009 -0.0159719996 0.0176970009 +-0.0176970009 -0.0159719996 0.0073030000 +-0.0176970009 -0.0159719996 -0.0073030000 +-0.0176970009 -0.0159719996 -0.0176970009 +-0.0176970009 -0.0159719996 -0.0323030017 +-0.0176970009 -0.0159719996 -0.0426970012 +-0.0176970009 -0.0176970009 0.0409720019 +-0.0176970009 -0.0176970009 0.0340280011 +-0.0176970009 -0.0176970009 0.0159719996 +-0.0176970009 -0.0176970009 0.0090279998 +-0.0176970009 -0.0176970009 -0.0090279998 +-0.0176970009 -0.0176970009 -0.0159719996 +-0.0176970009 -0.0176970009 -0.0340280011 +-0.0176970009 -0.0176970009 -0.0409720019 +-0.0176970009 -0.0323030017 0.0159719996 +-0.0176970009 -0.0323030017 0.0090279998 +-0.0176970009 -0.0323030017 -0.0090279998 +-0.0176970009 -0.0323030017 -0.0159719996 +-0.0176970009 -0.0323030017 -0.0340280011 +-0.0176970009 -0.0323030017 -0.0409720019 +-0.0176970009 -0.0340280011 0.0176970009 +-0.0176970009 -0.0340280011 0.0073030000 +-0.0176970009 -0.0340280011 -0.0073030000 +-0.0176970009 -0.0340280011 -0.0176970009 +-0.0176970009 -0.0340280011 -0.0323030017 +-0.0176970009 -0.0340280011 -0.0426970012 +-0.0176970009 -0.0409720019 0.0176970009 +-0.0176970009 -0.0409720019 0.0073030000 +-0.0176970009 -0.0409720019 -0.0073030000 +-0.0176970009 -0.0409720019 -0.0176970009 +-0.0176970009 -0.0409720019 -0.0323030017 +-0.0176970009 -0.0409720019 -0.0426970012 +-0.0176970009 -0.0426970012 0.0159719996 +-0.0176970009 -0.0426970012 0.0090279998 +-0.0176970009 -0.0426970012 -0.0090279998 +-0.0176970009 -0.0426970012 -0.0159719996 +-0.0176970009 -0.0426970012 -0.0340280011 +-0.0176970009 -0.0426970012 -0.0409720019 +-0.0179130007 0.0500000007 0.0406249985 +-0.0179130007 0.0500000007 0.0343750007 +-0.0179130007 0.0500000007 0.0156250000 +-0.0179130007 0.0500000007 0.0093750004 +-0.0179130007 0.0500000007 -0.0093750004 +-0.0179130007 0.0500000007 -0.0156250000 +-0.0179130007 0.0500000007 -0.0343750007 +-0.0179130007 0.0500000007 -0.0406249985 +-0.0179130007 0.0406249985 0.0500000007 +-0.0179130007 0.0406249985 -0.0500000007 +-0.0179130007 0.0343750007 0.0500000007 +-0.0179130007 0.0343750007 -0.0500000007 +-0.0179130007 0.0156250000 -0.0003910000 +-0.0179130007 0.0156250000 -0.0500000007 +-0.0179130007 0.0093750004 -0.0003910000 +-0.0179130007 0.0093750004 -0.0500000007 +-0.0179130007 -0.0000000000 0.0406249985 +-0.0179130007 -0.0000000000 0.0343750007 +-0.0179130007 -0.0000000000 0.0156250000 +-0.0179130007 -0.0000000000 0.0093750004 +-0.0179130007 -0.0093750004 0.0500000007 +-0.0179130007 -0.0093750004 -0.0500000007 +-0.0179130007 -0.0156250000 0.0500000007 +-0.0179130007 -0.0156250000 -0.0500000007 +-0.0179130007 -0.0250000004 0.0406249985 +-0.0179130007 -0.0250000004 0.0343750007 +-0.0179130007 -0.0343750007 0.0212500002 +-0.0179130007 -0.0343750007 -0.0500000007 +-0.0179130007 -0.0406249985 0.0212500002 +-0.0179130007 -0.0406249985 -0.0500000007 +-0.0179130007 -0.0500000007 0.0156250000 +-0.0179130007 -0.0500000007 0.0093750004 +-0.0179130007 -0.0500000007 -0.0093750004 +-0.0179130007 -0.0500000007 -0.0156250000 +-0.0179130007 -0.0500000007 -0.0343750007 +-0.0179130007 -0.0500000007 -0.0406249985 +-0.0179779995 0.0234379992 0.0405079983 +-0.0179779995 0.0234379992 0.0344920009 +-0.0179779995 0.0234379992 0.0155079998 +-0.0179779995 0.0234379992 0.0094919996 +-0.0182739999 0.0432740003 0.0398919992 +-0.0182739999 0.0432740003 0.0351080000 +-0.0182739999 0.0432740003 0.0148919998 +-0.0182739999 0.0432740003 0.0101079997 +-0.0182739999 0.0432740003 -0.0101079997 +-0.0182739999 0.0432740003 -0.0148919998 +-0.0182739999 0.0432740003 -0.0351080000 +-0.0182739999 0.0432740003 -0.0398919992 +-0.0182739999 0.0398919992 0.0432740003 +-0.0182739999 0.0398919992 0.0317259990 +-0.0182739999 0.0398919992 0.0182739999 +-0.0182739999 0.0398919992 0.0067260000 +-0.0182739999 0.0398919992 -0.0067260000 +-0.0182739999 0.0398919992 -0.0182739999 +-0.0182739999 0.0398919992 -0.0317259990 +-0.0182739999 0.0398919992 -0.0432740003 +-0.0182739999 0.0351080000 0.0432740003 +-0.0182739999 0.0351080000 0.0317259990 +-0.0182739999 0.0351080000 0.0182739999 +-0.0182739999 0.0351080000 0.0067260000 +-0.0182739999 0.0351080000 -0.0067260000 +-0.0182739999 0.0351080000 -0.0182739999 +-0.0182739999 0.0351080000 -0.0317259990 +-0.0182739999 0.0351080000 -0.0432740003 +-0.0182739999 0.0317259990 0.0398919992 +-0.0182739999 0.0317259990 0.0351080000 +-0.0182739999 0.0317259990 0.0148919998 +-0.0182739999 0.0317259990 0.0101079997 +-0.0182739999 0.0317259990 -0.0101079997 +-0.0182739999 0.0317259990 -0.0148919998 +-0.0182739999 0.0317259990 -0.0351080000 +-0.0182739999 0.0317259990 -0.0398919992 +-0.0182739999 0.0182739999 -0.0101079997 +-0.0182739999 0.0182739999 -0.0148919998 +-0.0182739999 0.0182739999 -0.0351080000 +-0.0182739999 0.0182739999 -0.0398919992 +-0.0182739999 0.0148919998 -0.0067260000 +-0.0182739999 0.0148919998 -0.0182739999 +-0.0182739999 0.0148919998 -0.0317259990 +-0.0182739999 0.0148919998 -0.0432740003 +-0.0182739999 0.0101079997 -0.0067260000 +-0.0182739999 0.0101079997 -0.0182739999 +-0.0182739999 0.0101079997 -0.0317259990 +-0.0182739999 0.0101079997 -0.0432740003 +-0.0182739999 0.0067260000 -0.0101079997 +-0.0182739999 0.0067260000 -0.0148919998 +-0.0182739999 0.0067260000 -0.0351080000 +-0.0182739999 0.0067260000 -0.0398919992 +-0.0182739999 -0.0067260000 0.0398919992 +-0.0182739999 -0.0067260000 0.0351080000 +-0.0182739999 -0.0067260000 0.0148919998 +-0.0182739999 -0.0067260000 0.0101079997 +-0.0182739999 -0.0067260000 -0.0101079997 +-0.0182739999 -0.0067260000 -0.0148919998 +-0.0182739999 -0.0067260000 -0.0351080000 +-0.0182739999 -0.0067260000 -0.0398919992 +-0.0182739999 -0.0101079997 0.0432740003 +-0.0182739999 -0.0101079997 0.0317259990 +-0.0182739999 -0.0101079997 0.0182739999 +-0.0182739999 -0.0101079997 0.0067260000 +-0.0182739999 -0.0101079997 -0.0067260000 +-0.0182739999 -0.0101079997 -0.0182739999 +-0.0182739999 -0.0101079997 -0.0317259990 +-0.0182739999 -0.0101079997 -0.0432740003 +-0.0182739999 -0.0148919998 0.0432740003 +-0.0182739999 -0.0148919998 0.0317259990 +-0.0182739999 -0.0148919998 0.0182739999 +-0.0182739999 -0.0148919998 0.0067260000 +-0.0182739999 -0.0148919998 -0.0067260000 +-0.0182739999 -0.0148919998 -0.0182739999 +-0.0182739999 -0.0148919998 -0.0317259990 +-0.0182739999 -0.0148919998 -0.0432740003 +-0.0182739999 -0.0182739999 0.0398919992 +-0.0182739999 -0.0182739999 0.0351080000 +-0.0182739999 -0.0182739999 0.0148919998 +-0.0182739999 -0.0182739999 0.0101079997 +-0.0182739999 -0.0182739999 -0.0101079997 +-0.0182739999 -0.0182739999 -0.0148919998 +-0.0182739999 -0.0182739999 -0.0351080000 +-0.0182739999 -0.0182739999 -0.0398919992 +-0.0182739999 -0.0317259990 0.0148919998 +-0.0182739999 -0.0317259990 0.0101079997 +-0.0182739999 -0.0317259990 -0.0101079997 +-0.0182739999 -0.0317259990 -0.0148919998 +-0.0182739999 -0.0317259990 -0.0351080000 +-0.0182739999 -0.0317259990 -0.0398919992 +-0.0182739999 -0.0351080000 0.0182739999 +-0.0182739999 -0.0351080000 0.0067260000 +-0.0182739999 -0.0351080000 -0.0067260000 +-0.0182739999 -0.0351080000 -0.0182739999 +-0.0182739999 -0.0351080000 -0.0317259990 +-0.0182739999 -0.0351080000 -0.0432740003 +-0.0182739999 -0.0398919992 0.0182739999 +-0.0182739999 -0.0398919992 0.0067260000 +-0.0182739999 -0.0398919992 -0.0067260000 +-0.0182739999 -0.0398919992 -0.0182739999 +-0.0182739999 -0.0398919992 -0.0317259990 +-0.0182739999 -0.0398919992 -0.0432740003 +-0.0182739999 -0.0432740003 0.0148919998 +-0.0182739999 -0.0432740003 0.0101079997 +-0.0182739999 -0.0432740003 -0.0101079997 +-0.0182739999 -0.0432740003 -0.0148919998 +-0.0182739999 -0.0432740003 -0.0351080000 +-0.0182739999 -0.0432740003 -0.0398919992 +-0.0185369998 0.0500000007 0.0391179994 +-0.0185369998 0.0500000007 0.0358819999 +-0.0185369998 0.0500000007 0.0141179999 +-0.0185369998 0.0500000007 0.0108820004 +-0.0185369998 0.0500000007 -0.0108820004 +-0.0185369998 0.0500000007 -0.0141179999 +-0.0185369998 0.0500000007 -0.0358819999 +-0.0185369998 0.0500000007 -0.0391179994 +-0.0185369998 0.0391179994 0.0500000007 +-0.0185369998 0.0391179994 -0.0500000007 +-0.0185369998 0.0358819999 0.0500000007 +-0.0185369998 0.0358819999 -0.0500000007 +-0.0185369998 0.0141179999 -0.0003910000 +-0.0185369998 0.0141179999 -0.0500000007 +-0.0185369998 0.0108820004 -0.0003910000 +-0.0185369998 0.0108820004 -0.0500000007 +-0.0185369998 -0.0000000000 0.0391179994 +-0.0185369998 -0.0000000000 0.0358819999 +-0.0185369998 -0.0000000000 0.0141179999 +-0.0185369998 -0.0000000000 0.0108820004 +-0.0185369998 -0.0108820004 0.0500000007 +-0.0185369998 -0.0108820004 -0.0500000007 +-0.0185369998 -0.0141179999 0.0500000007 +-0.0185369998 -0.0141179999 -0.0500000007 +-0.0185369998 -0.0250000004 0.0391179994 +-0.0185369998 -0.0250000004 0.0358819999 +-0.0185369998 -0.0358819999 0.0212500002 +-0.0185369998 -0.0358819999 -0.0500000007 +-0.0185369998 -0.0391179994 0.0212500002 +-0.0185369998 -0.0391179994 -0.0500000007 +-0.0185369998 -0.0500000007 0.0141179999 +-0.0185369998 -0.0500000007 0.0108820004 +-0.0185369998 -0.0500000007 -0.0108820004 +-0.0185369998 -0.0500000007 -0.0141179999 +-0.0185369998 -0.0500000007 -0.0358819999 +-0.0185369998 -0.0500000007 -0.0391179994 +-0.0185540002 0.0234379992 0.0390530005 +-0.0185540002 0.0234379992 0.0359469987 +-0.0185540002 0.0234379992 0.0140530001 +-0.0185540002 0.0234379992 0.0109470002 +-0.0186299998 0.0436300002 0.0387189984 +-0.0186299998 0.0436300002 0.0362810008 +-0.0186299998 0.0436300002 0.0137189999 +-0.0186299998 0.0436300002 0.0112810005 +-0.0186299998 0.0436300002 -0.0112810005 +-0.0186299998 0.0436300002 -0.0137189999 +-0.0186299998 0.0436300002 -0.0362810008 +-0.0186299998 0.0436300002 -0.0387189984 +-0.0186299998 0.0387189984 0.0436300002 +-0.0186299998 0.0387189984 0.0313699991 +-0.0186299998 0.0387189984 0.0186299998 +-0.0186299998 0.0387189984 0.0063700001 +-0.0186299998 0.0387189984 -0.0063700001 +-0.0186299998 0.0387189984 -0.0186299998 +-0.0186299998 0.0387189984 -0.0313699991 +-0.0186299998 0.0387189984 -0.0436300002 +-0.0186299998 0.0362810008 0.0436300002 +-0.0186299998 0.0362810008 0.0313699991 +-0.0186299998 0.0362810008 0.0186299998 +-0.0186299998 0.0362810008 0.0063700001 +-0.0186299998 0.0362810008 -0.0063700001 +-0.0186299998 0.0362810008 -0.0186299998 +-0.0186299998 0.0362810008 -0.0313699991 +-0.0186299998 0.0362810008 -0.0436300002 +-0.0186299998 0.0313699991 0.0387189984 +-0.0186299998 0.0313699991 0.0362810008 +-0.0186299998 0.0313699991 0.0137189999 +-0.0186299998 0.0313699991 0.0112810005 +-0.0186299998 0.0313699991 -0.0112810005 +-0.0186299998 0.0313699991 -0.0137189999 +-0.0186299998 0.0313699991 -0.0362810008 +-0.0186299998 0.0313699991 -0.0387189984 +-0.0186299998 0.0186299998 -0.0112810005 +-0.0186299998 0.0186299998 -0.0137189999 +-0.0186299998 0.0186299998 -0.0362810008 +-0.0186299998 0.0186299998 -0.0387189984 +-0.0186299998 0.0137189999 -0.0063700001 +-0.0186299998 0.0137189999 -0.0186299998 +-0.0186299998 0.0137189999 -0.0313699991 +-0.0186299998 0.0137189999 -0.0436300002 +-0.0186299998 0.0112810005 -0.0063700001 +-0.0186299998 0.0112810005 -0.0186299998 +-0.0186299998 0.0112810005 -0.0313699991 +-0.0186299998 0.0112810005 -0.0436300002 +-0.0186299998 0.0063700001 -0.0112810005 +-0.0186299998 0.0063700001 -0.0137189999 +-0.0186299998 0.0063700001 -0.0362810008 +-0.0186299998 0.0063700001 -0.0387189984 +-0.0186299998 -0.0063700001 0.0387189984 +-0.0186299998 -0.0063700001 0.0362810008 +-0.0186299998 -0.0063700001 0.0137189999 +-0.0186299998 -0.0063700001 0.0112810005 +-0.0186299998 -0.0063700001 -0.0112810005 +-0.0186299998 -0.0063700001 -0.0137189999 +-0.0186299998 -0.0063700001 -0.0362810008 +-0.0186299998 -0.0063700001 -0.0387189984 +-0.0186299998 -0.0112810005 0.0436300002 +-0.0186299998 -0.0112810005 0.0313699991 +-0.0186299998 -0.0112810005 0.0186299998 +-0.0186299998 -0.0112810005 0.0063700001 +-0.0186299998 -0.0112810005 -0.0063700001 +-0.0186299998 -0.0112810005 -0.0186299998 +-0.0186299998 -0.0112810005 -0.0313699991 +-0.0186299998 -0.0112810005 -0.0436300002 +-0.0186299998 -0.0137189999 0.0436300002 +-0.0186299998 -0.0137189999 0.0313699991 +-0.0186299998 -0.0137189999 0.0186299998 +-0.0186299998 -0.0137189999 0.0063700001 +-0.0186299998 -0.0137189999 -0.0063700001 +-0.0186299998 -0.0137189999 -0.0186299998 +-0.0186299998 -0.0137189999 -0.0313699991 +-0.0186299998 -0.0137189999 -0.0436300002 +-0.0186299998 -0.0186299998 0.0387189984 +-0.0186299998 -0.0186299998 0.0362810008 +-0.0186299998 -0.0186299998 0.0137189999 +-0.0186299998 -0.0186299998 0.0112810005 +-0.0186299998 -0.0186299998 -0.0112810005 +-0.0186299998 -0.0186299998 -0.0137189999 +-0.0186299998 -0.0186299998 -0.0362810008 +-0.0186299998 -0.0186299998 -0.0387189984 +-0.0186299998 -0.0313699991 0.0137189999 +-0.0186299998 -0.0313699991 0.0112810005 +-0.0186299998 -0.0313699991 -0.0112810005 +-0.0186299998 -0.0313699991 -0.0137189999 +-0.0186299998 -0.0313699991 -0.0362810008 +-0.0186299998 -0.0313699991 -0.0387189984 +-0.0186299998 -0.0362810008 0.0186299998 +-0.0186299998 -0.0362810008 0.0063700001 +-0.0186299998 -0.0362810008 -0.0063700001 +-0.0186299998 -0.0362810008 -0.0186299998 +-0.0186299998 -0.0362810008 -0.0313699991 +-0.0186299998 -0.0362810008 -0.0436300002 +-0.0186299998 -0.0387189984 0.0186299998 +-0.0186299998 -0.0387189984 0.0063700001 +-0.0186299998 -0.0387189984 -0.0063700001 +-0.0186299998 -0.0387189984 -0.0186299998 +-0.0186299998 -0.0387189984 -0.0313699991 +-0.0186299998 -0.0387189984 -0.0436300002 +-0.0186299998 -0.0436300002 0.0137189999 +-0.0186299998 -0.0436300002 0.0112810005 +-0.0186299998 -0.0436300002 -0.0112810005 +-0.0186299998 -0.0436300002 -0.0137189999 +-0.0186299998 -0.0436300002 -0.0362810008 +-0.0186299998 -0.0436300002 -0.0387189984 +-0.0187199991 0.0437199995 0.0381130017 +-0.0187199991 0.0437199995 0.0368870012 +-0.0187199991 0.0437199995 0.0131130004 +-0.0187199991 0.0437199995 0.0118869999 +-0.0187199991 0.0437199995 -0.0118869999 +-0.0187199991 0.0437199995 -0.0131130004 +-0.0187199991 0.0437199995 -0.0368870012 +-0.0187199991 0.0437199995 -0.0381130017 +-0.0187199991 0.0381130017 0.0437199995 +-0.0187199991 0.0381130017 0.0312799998 +-0.0187199991 0.0381130017 0.0187199991 +-0.0187199991 0.0381130017 0.0062799999 +-0.0187199991 0.0381130017 -0.0062799999 +-0.0187199991 0.0381130017 -0.0187199991 +-0.0187199991 0.0381130017 -0.0312799998 +-0.0187199991 0.0381130017 -0.0437199995 +-0.0187199991 0.0368870012 0.0437199995 +-0.0187199991 0.0368870012 0.0312799998 +-0.0187199991 0.0368870012 0.0187199991 +-0.0187199991 0.0368870012 0.0062799999 +-0.0187199991 0.0368870012 -0.0062799999 +-0.0187199991 0.0368870012 -0.0187199991 +-0.0187199991 0.0368870012 -0.0312799998 +-0.0187199991 0.0368870012 -0.0437199995 +-0.0187199991 0.0312799998 0.0381130017 +-0.0187199991 0.0312799998 0.0368870012 +-0.0187199991 0.0312799998 0.0131130004 +-0.0187199991 0.0312799998 0.0118869999 +-0.0187199991 0.0312799998 -0.0118869999 +-0.0187199991 0.0312799998 -0.0131130004 +-0.0187199991 0.0312799998 -0.0368870012 +-0.0187199991 0.0312799998 -0.0381130017 +-0.0187199991 0.0187199991 -0.0118869999 +-0.0187199991 0.0187199991 -0.0131130004 +-0.0187199991 0.0187199991 -0.0368870012 +-0.0187199991 0.0187199991 -0.0381130017 +-0.0187199991 0.0131130004 -0.0062799999 +-0.0187199991 0.0131130004 -0.0187199991 +-0.0187199991 0.0131130004 -0.0312799998 +-0.0187199991 0.0131130004 -0.0437199995 +-0.0187199991 0.0118869999 -0.0062799999 +-0.0187199991 0.0118869999 -0.0187199991 +-0.0187199991 0.0118869999 -0.0312799998 +-0.0187199991 0.0118869999 -0.0437199995 +-0.0187199991 0.0062799999 -0.0118869999 +-0.0187199991 0.0062799999 -0.0131130004 +-0.0187199991 0.0062799999 -0.0368870012 +-0.0187199991 0.0062799999 -0.0381130017 +-0.0187199991 -0.0062799999 0.0381130017 +-0.0187199991 -0.0062799999 0.0368870012 +-0.0187199991 -0.0062799999 0.0131130004 +-0.0187199991 -0.0062799999 0.0118869999 +-0.0187199991 -0.0062799999 -0.0118869999 +-0.0187199991 -0.0062799999 -0.0131130004 +-0.0187199991 -0.0062799999 -0.0368870012 +-0.0187199991 -0.0062799999 -0.0381130017 +-0.0187199991 -0.0118869999 0.0437199995 +-0.0187199991 -0.0118869999 0.0312799998 +-0.0187199991 -0.0118869999 0.0187199991 +-0.0187199991 -0.0118869999 0.0062799999 +-0.0187199991 -0.0118869999 -0.0062799999 +-0.0187199991 -0.0118869999 -0.0187199991 +-0.0187199991 -0.0118869999 -0.0312799998 +-0.0187199991 -0.0118869999 -0.0437199995 +-0.0187199991 -0.0131130004 0.0437199995 +-0.0187199991 -0.0131130004 0.0312799998 +-0.0187199991 -0.0131130004 0.0187199991 +-0.0187199991 -0.0131130004 0.0062799999 +-0.0187199991 -0.0131130004 -0.0062799999 +-0.0187199991 -0.0131130004 -0.0187199991 +-0.0187199991 -0.0131130004 -0.0312799998 +-0.0187199991 -0.0131130004 -0.0437199995 +-0.0187199991 -0.0187199991 0.0381130017 +-0.0187199991 -0.0187199991 0.0368870012 +-0.0187199991 -0.0187199991 0.0131130004 +-0.0187199991 -0.0187199991 0.0118869999 +-0.0187199991 -0.0187199991 -0.0118869999 +-0.0187199991 -0.0187199991 -0.0131130004 +-0.0187199991 -0.0187199991 -0.0368870012 +-0.0187199991 -0.0187199991 -0.0381130017 +-0.0187199991 -0.0312799998 0.0131130004 +-0.0187199991 -0.0312799998 0.0118869999 +-0.0187199991 -0.0312799998 -0.0118869999 +-0.0187199991 -0.0312799998 -0.0131130004 +-0.0187199991 -0.0312799998 -0.0368870012 +-0.0187199991 -0.0312799998 -0.0381130017 +-0.0187199991 -0.0368870012 0.0187199991 +-0.0187199991 -0.0368870012 0.0062799999 +-0.0187199991 -0.0368870012 -0.0062799999 +-0.0187199991 -0.0368870012 -0.0187199991 +-0.0187199991 -0.0368870012 -0.0312799998 +-0.0187199991 -0.0368870012 -0.0437199995 +-0.0187199991 -0.0381130017 0.0187199991 +-0.0187199991 -0.0381130017 0.0062799999 +-0.0187199991 -0.0381130017 -0.0062799999 +-0.0187199991 -0.0381130017 -0.0187199991 +-0.0187199991 -0.0381130017 -0.0312799998 +-0.0187199991 -0.0381130017 -0.0437199995 +-0.0187199991 -0.0437199995 0.0131130004 +-0.0187199991 -0.0437199995 0.0118869999 +-0.0187199991 -0.0437199995 -0.0118869999 +-0.0187199991 -0.0437199995 -0.0131130004 +-0.0187199991 -0.0437199995 -0.0368870012 +-0.0187199991 -0.0437199995 -0.0381130017 +-0.0187500007 0.0500000007 0.0375000015 +-0.0187500007 0.0500000007 0.0125000002 +-0.0187500007 0.0500000007 -0.0125000002 +-0.0187500007 0.0500000007 -0.0375000015 +-0.0187500007 0.0437499993 0.0375000015 +-0.0187500007 0.0437499993 0.0125000002 +-0.0187500007 0.0437499993 -0.0125000002 +-0.0187500007 0.0437499993 -0.0375000015 +-0.0187500007 0.0375000015 0.0500000007 +-0.0187500007 0.0375000015 0.0437499993 +-0.0187500007 0.0375000015 0.0312500000 +-0.0187500007 0.0375000015 0.0187500007 +-0.0187500007 0.0375000015 0.0062500001 +-0.0187500007 0.0375000015 -0.0062500001 +-0.0187500007 0.0375000015 -0.0187500007 +-0.0187500007 0.0375000015 -0.0312500000 +-0.0187500007 0.0375000015 -0.0437499993 +-0.0187500007 0.0375000015 -0.0500000007 +-0.0187500007 0.0312500000 0.0375000015 +-0.0187500007 0.0312500000 0.0125000002 +-0.0187500007 0.0312500000 -0.0125000002 +-0.0187500007 0.0312500000 -0.0375000015 +-0.0187500007 0.0234379992 0.0375000015 +-0.0187500007 0.0234379992 0.0125000002 +-0.0187500007 0.0187500007 -0.0125000002 +-0.0187500007 0.0187500007 -0.0375000015 +-0.0187500007 0.0125000002 -0.0003910000 +-0.0187500007 0.0125000002 -0.0062500001 +-0.0187500007 0.0125000002 -0.0187500007 +-0.0187500007 0.0125000002 -0.0312500000 +-0.0187500007 0.0125000002 -0.0437499993 +-0.0187500007 0.0125000002 -0.0500000007 +-0.0187500007 0.0062500001 -0.0125000002 +-0.0187500007 0.0062500001 -0.0375000015 +-0.0187500007 -0.0000000000 0.0375000015 +-0.0187500007 -0.0000000000 0.0125000002 +-0.0187500007 -0.0062500001 0.0375000015 +-0.0187500007 -0.0062500001 0.0125000002 +-0.0187500007 -0.0062500001 -0.0125000002 +-0.0187500007 -0.0062500001 -0.0375000015 +-0.0187500007 -0.0125000002 0.0500000007 +-0.0187500007 -0.0125000002 0.0437499993 +-0.0187500007 -0.0125000002 0.0312500000 +-0.0187500007 -0.0125000002 0.0187500007 +-0.0187500007 -0.0125000002 0.0062500001 +-0.0187500007 -0.0125000002 -0.0062500001 +-0.0187500007 -0.0125000002 -0.0187500007 +-0.0187500007 -0.0125000002 -0.0312500000 +-0.0187500007 -0.0125000002 -0.0437499993 +-0.0187500007 -0.0125000002 -0.0500000007 +-0.0187500007 -0.0187500007 0.0375000015 +-0.0187500007 -0.0187500007 0.0125000002 +-0.0187500007 -0.0187500007 -0.0125000002 +-0.0187500007 -0.0187500007 -0.0375000015 +-0.0187500007 -0.0250000004 0.0375000015 +-0.0187500007 -0.0312500000 0.0125000002 +-0.0187500007 -0.0312500000 -0.0125000002 +-0.0187500007 -0.0312500000 -0.0375000015 +-0.0187500007 -0.0375000015 0.0212500002 +-0.0187500007 -0.0375000015 0.0187500007 +-0.0187500007 -0.0375000015 0.0062500001 +-0.0187500007 -0.0375000015 -0.0062500001 +-0.0187500007 -0.0375000015 -0.0187500007 +-0.0187500007 -0.0375000015 -0.0312500000 +-0.0187500007 -0.0375000015 -0.0437499993 +-0.0187500007 -0.0375000015 -0.0500000007 +-0.0187500007 -0.0437499993 0.0125000002 +-0.0187500007 -0.0437499993 -0.0125000002 +-0.0187500007 -0.0437499993 -0.0375000015 +-0.0187500007 -0.0500000007 0.0125000002 +-0.0187500007 -0.0500000007 -0.0125000002 +-0.0187500007 -0.0500000007 -0.0375000015 +-0.0300479997 0.0234379992 0.0500000007 +-0.0300479997 0.0234379992 -0.0003910000 +-0.0312500000 0.0500000007 0.0375000015 +-0.0312500000 0.0500000007 0.0125000002 +-0.0312500000 0.0500000007 -0.0125000002 +-0.0312500000 0.0500000007 -0.0375000015 +-0.0312500000 0.0437499993 0.0375000015 +-0.0312500000 0.0437499993 0.0125000002 +-0.0312500000 0.0437499993 -0.0125000002 +-0.0312500000 0.0437499993 -0.0375000015 +-0.0312500000 0.0375000015 0.0500000007 +-0.0312500000 0.0375000015 0.0437499993 +-0.0312500000 0.0375000015 0.0312500000 +-0.0312500000 0.0375000015 0.0187500007 +-0.0312500000 0.0375000015 0.0062500001 +-0.0312500000 0.0375000015 -0.0062500001 +-0.0312500000 0.0375000015 -0.0187500007 +-0.0312500000 0.0375000015 -0.0312500000 +-0.0312500000 0.0375000015 -0.0437499993 +-0.0312500000 0.0375000015 -0.0500000007 +-0.0312500000 0.0312500000 0.0375000015 +-0.0312500000 0.0312500000 0.0125000002 +-0.0312500000 0.0312500000 -0.0125000002 +-0.0312500000 0.0312500000 -0.0375000015 +-0.0312500000 0.0241310000 0.0375000015 +-0.0312500000 0.0241310000 0.0125000002 +-0.0312500000 0.0187500007 -0.0125000002 +-0.0312500000 0.0187500007 -0.0375000015 +-0.0312500000 0.0125000002 -0.0003910000 +-0.0312500000 0.0125000002 -0.0062500001 +-0.0312500000 0.0125000002 -0.0187500007 +-0.0312500000 0.0125000002 -0.0312500000 +-0.0312500000 0.0125000002 -0.0437499993 +-0.0312500000 0.0125000002 -0.0500000007 +-0.0312500000 0.0062500001 -0.0125000002 +-0.0312500000 0.0062500001 -0.0375000015 +-0.0312500000 -0.0062500001 0.0375000015 +-0.0312500000 -0.0062500001 0.0125000002 +-0.0312500000 -0.0062500001 -0.0125000002 +-0.0312500000 -0.0062500001 -0.0375000015 +-0.0312500000 -0.0125000002 0.0500000007 +-0.0312500000 -0.0125000002 0.0437499993 +-0.0312500000 -0.0125000002 0.0312500000 +-0.0312500000 -0.0125000002 0.0187500007 +-0.0312500000 -0.0125000002 0.0062500001 +-0.0312500000 -0.0125000002 -0.0062500001 +-0.0312500000 -0.0125000002 -0.0187500007 +-0.0312500000 -0.0125000002 -0.0312500000 +-0.0312500000 -0.0125000002 -0.0437499993 +-0.0312500000 -0.0125000002 -0.0500000007 +-0.0312500000 -0.0187500007 0.0375000015 +-0.0312500000 -0.0187500007 0.0125000002 +-0.0312500000 -0.0187500007 -0.0125000002 +-0.0312500000 -0.0187500007 -0.0375000015 +-0.0312500000 -0.0250000004 0.0375000015 +-0.0312500000 -0.0312500000 0.0125000002 +-0.0312500000 -0.0312500000 -0.0125000002 +-0.0312500000 -0.0312500000 -0.0375000015 +-0.0312500000 -0.0375000015 0.0212500002 +-0.0312500000 -0.0375000015 0.0187500007 +-0.0312500000 -0.0375000015 0.0062500001 +-0.0312500000 -0.0375000015 -0.0062500001 +-0.0312500000 -0.0375000015 -0.0187500007 +-0.0312500000 -0.0375000015 -0.0312500000 +-0.0312500000 -0.0375000015 -0.0437499993 +-0.0312500000 -0.0375000015 -0.0500000007 +-0.0312500000 -0.0437499993 0.0125000002 +-0.0312500000 -0.0437499993 -0.0125000002 +-0.0312500000 -0.0437499993 -0.0375000015 +-0.0312500000 -0.0500000007 0.0125000002 +-0.0312500000 -0.0500000007 -0.0125000002 +-0.0312500000 -0.0500000007 -0.0375000015 +-0.0312799998 0.0437199995 0.0381130017 +-0.0312799998 0.0437199995 0.0368870012 +-0.0312799998 0.0437199995 0.0131130004 +-0.0312799998 0.0437199995 0.0118869999 +-0.0312799998 0.0437199995 -0.0118869999 +-0.0312799998 0.0437199995 -0.0131130004 +-0.0312799998 0.0437199995 -0.0368870012 +-0.0312799998 0.0437199995 -0.0381130017 +-0.0312799998 0.0381130017 0.0437199995 +-0.0312799998 0.0381130017 0.0312799998 +-0.0312799998 0.0381130017 0.0187199991 +-0.0312799998 0.0381130017 0.0062799999 +-0.0312799998 0.0381130017 -0.0062799999 +-0.0312799998 0.0381130017 -0.0187199991 +-0.0312799998 0.0381130017 -0.0312799998 +-0.0312799998 0.0381130017 -0.0437199995 +-0.0312799998 0.0368870012 0.0437199995 +-0.0312799998 0.0368870012 0.0312799998 +-0.0312799998 0.0368870012 0.0187199991 +-0.0312799998 0.0368870012 0.0062799999 +-0.0312799998 0.0368870012 -0.0062799999 +-0.0312799998 0.0368870012 -0.0187199991 +-0.0312799998 0.0368870012 -0.0312799998 +-0.0312799998 0.0368870012 -0.0437199995 +-0.0312799998 0.0312799998 0.0381130017 +-0.0312799998 0.0312799998 0.0368870012 +-0.0312799998 0.0312799998 0.0131130004 +-0.0312799998 0.0312799998 0.0118869999 +-0.0312799998 0.0312799998 -0.0118869999 +-0.0312799998 0.0312799998 -0.0131130004 +-0.0312799998 0.0312799998 -0.0368870012 +-0.0312799998 0.0312799998 -0.0381130017 +-0.0312799998 0.0187199991 -0.0118869999 +-0.0312799998 0.0187199991 -0.0131130004 +-0.0312799998 0.0187199991 -0.0368870012 +-0.0312799998 0.0187199991 -0.0381130017 +-0.0312799998 0.0131130004 -0.0062799999 +-0.0312799998 0.0131130004 -0.0187199991 +-0.0312799998 0.0131130004 -0.0312799998 +-0.0312799998 0.0131130004 -0.0437199995 +-0.0312799998 0.0118869999 -0.0062799999 +-0.0312799998 0.0118869999 -0.0187199991 +-0.0312799998 0.0118869999 -0.0312799998 +-0.0312799998 0.0118869999 -0.0437199995 +-0.0312799998 0.0062799999 -0.0118869999 +-0.0312799998 0.0062799999 -0.0131130004 +-0.0312799998 0.0062799999 -0.0368870012 +-0.0312799998 0.0062799999 -0.0381130017 +-0.0312799998 -0.0062799999 0.0381130017 +-0.0312799998 -0.0062799999 0.0368870012 +-0.0312799998 -0.0062799999 0.0131130004 +-0.0312799998 -0.0062799999 0.0118869999 +-0.0312799998 -0.0062799999 -0.0118869999 +-0.0312799998 -0.0062799999 -0.0131130004 +-0.0312799998 -0.0062799999 -0.0368870012 +-0.0312799998 -0.0062799999 -0.0381130017 +-0.0312799998 -0.0118869999 0.0437199995 +-0.0312799998 -0.0118869999 0.0312799998 +-0.0312799998 -0.0118869999 0.0187199991 +-0.0312799998 -0.0118869999 0.0062799999 +-0.0312799998 -0.0118869999 -0.0062799999 +-0.0312799998 -0.0118869999 -0.0187199991 +-0.0312799998 -0.0118869999 -0.0312799998 +-0.0312799998 -0.0118869999 -0.0437199995 +-0.0312799998 -0.0131130004 0.0437199995 +-0.0312799998 -0.0131130004 0.0312799998 +-0.0312799998 -0.0131130004 0.0187199991 +-0.0312799998 -0.0131130004 0.0062799999 +-0.0312799998 -0.0131130004 -0.0062799999 +-0.0312799998 -0.0131130004 -0.0187199991 +-0.0312799998 -0.0131130004 -0.0312799998 +-0.0312799998 -0.0131130004 -0.0437199995 +-0.0312799998 -0.0187199991 0.0381130017 +-0.0312799998 -0.0187199991 0.0368870012 +-0.0312799998 -0.0187199991 0.0131130004 +-0.0312799998 -0.0187199991 0.0118869999 +-0.0312799998 -0.0187199991 -0.0118869999 +-0.0312799998 -0.0187199991 -0.0131130004 +-0.0312799998 -0.0187199991 -0.0368870012 +-0.0312799998 -0.0187199991 -0.0381130017 +-0.0312799998 -0.0312799998 0.0131130004 +-0.0312799998 -0.0312799998 0.0118869999 +-0.0312799998 -0.0312799998 -0.0118869999 +-0.0312799998 -0.0312799998 -0.0131130004 +-0.0312799998 -0.0312799998 -0.0368870012 +-0.0312799998 -0.0312799998 -0.0381130017 +-0.0312799998 -0.0368870012 0.0187199991 +-0.0312799998 -0.0368870012 0.0062799999 +-0.0312799998 -0.0368870012 -0.0062799999 +-0.0312799998 -0.0368870012 -0.0187199991 +-0.0312799998 -0.0368870012 -0.0312799998 +-0.0312799998 -0.0368870012 -0.0437199995 +-0.0312799998 -0.0381130017 0.0187199991 +-0.0312799998 -0.0381130017 0.0062799999 +-0.0312799998 -0.0381130017 -0.0062799999 +-0.0312799998 -0.0381130017 -0.0187199991 +-0.0312799998 -0.0381130017 -0.0312799998 +-0.0312799998 -0.0381130017 -0.0437199995 +-0.0312799998 -0.0437199995 0.0131130004 +-0.0312799998 -0.0437199995 0.0118869999 +-0.0312799998 -0.0437199995 -0.0118869999 +-0.0312799998 -0.0437199995 -0.0131130004 +-0.0312799998 -0.0437199995 -0.0368870012 +-0.0312799998 -0.0437199995 -0.0381130017 +-0.0312980004 -0.0000000000 0.0382729992 +-0.0312980004 -0.0000000000 0.0367270000 +-0.0312980004 -0.0000000000 0.0132729998 +-0.0312980004 -0.0000000000 0.0117269997 +-0.0313600004 0.0241950005 0.0386650003 +-0.0313600004 0.0241950005 0.0363349989 +-0.0313600004 0.0241950005 0.0136650000 +-0.0313600004 0.0241950005 0.0113350004 +-0.0313699991 0.0436300002 0.0387189984 +-0.0313699991 0.0436300002 0.0362810008 +-0.0313699991 0.0436300002 0.0137189999 +-0.0313699991 0.0436300002 0.0112810005 +-0.0313699991 0.0436300002 -0.0112810005 +-0.0313699991 0.0436300002 -0.0137189999 +-0.0313699991 0.0436300002 -0.0362810008 +-0.0313699991 0.0436300002 -0.0387189984 +-0.0313699991 0.0387189984 0.0436300002 +-0.0313699991 0.0387189984 0.0313699991 +-0.0313699991 0.0387189984 0.0186299998 +-0.0313699991 0.0387189984 0.0063700001 +-0.0313699991 0.0387189984 -0.0063700001 +-0.0313699991 0.0387189984 -0.0186299998 +-0.0313699991 0.0387189984 -0.0313699991 +-0.0313699991 0.0387189984 -0.0436300002 +-0.0313699991 0.0362810008 0.0436300002 +-0.0313699991 0.0362810008 0.0313699991 +-0.0313699991 0.0362810008 0.0186299998 +-0.0313699991 0.0362810008 0.0063700001 +-0.0313699991 0.0362810008 -0.0063700001 +-0.0313699991 0.0362810008 -0.0186299998 +-0.0313699991 0.0362810008 -0.0313699991 +-0.0313699991 0.0362810008 -0.0436300002 +-0.0313699991 0.0313699991 0.0387189984 +-0.0313699991 0.0313699991 0.0362810008 +-0.0313699991 0.0313699991 0.0137189999 +-0.0313699991 0.0313699991 0.0112810005 +-0.0313699991 0.0313699991 -0.0112810005 +-0.0313699991 0.0313699991 -0.0137189999 +-0.0313699991 0.0313699991 -0.0362810008 +-0.0313699991 0.0313699991 -0.0387189984 +-0.0313699991 0.0186299998 -0.0112810005 +-0.0313699991 0.0186299998 -0.0137189999 +-0.0313699991 0.0186299998 -0.0362810008 +-0.0313699991 0.0186299998 -0.0387189984 +-0.0313699991 0.0137189999 -0.0063700001 +-0.0313699991 0.0137189999 -0.0186299998 +-0.0313699991 0.0137189999 -0.0313699991 +-0.0313699991 0.0137189999 -0.0436300002 +-0.0313699991 0.0112810005 -0.0063700001 +-0.0313699991 0.0112810005 -0.0186299998 +-0.0313699991 0.0112810005 -0.0313699991 +-0.0313699991 0.0112810005 -0.0436300002 +-0.0313699991 0.0063700001 -0.0112810005 +-0.0313699991 0.0063700001 -0.0137189999 +-0.0313699991 0.0063700001 -0.0362810008 +-0.0313699991 0.0063700001 -0.0387189984 +-0.0313699991 -0.0063700001 0.0387189984 +-0.0313699991 -0.0063700001 0.0362810008 +-0.0313699991 -0.0063700001 0.0137189999 +-0.0313699991 -0.0063700001 0.0112810005 +-0.0313699991 -0.0063700001 -0.0112810005 +-0.0313699991 -0.0063700001 -0.0137189999 +-0.0313699991 -0.0063700001 -0.0362810008 +-0.0313699991 -0.0063700001 -0.0387189984 +-0.0313699991 -0.0112810005 0.0436300002 +-0.0313699991 -0.0112810005 0.0313699991 +-0.0313699991 -0.0112810005 0.0186299998 +-0.0313699991 -0.0112810005 0.0063700001 +-0.0313699991 -0.0112810005 -0.0063700001 +-0.0313699991 -0.0112810005 -0.0186299998 +-0.0313699991 -0.0112810005 -0.0313699991 +-0.0313699991 -0.0112810005 -0.0436300002 +-0.0313699991 -0.0137189999 0.0436300002 +-0.0313699991 -0.0137189999 0.0313699991 +-0.0313699991 -0.0137189999 0.0186299998 +-0.0313699991 -0.0137189999 0.0063700001 +-0.0313699991 -0.0137189999 -0.0063700001 +-0.0313699991 -0.0137189999 -0.0186299998 +-0.0313699991 -0.0137189999 -0.0313699991 +-0.0313699991 -0.0137189999 -0.0436300002 +-0.0313699991 -0.0186299998 0.0387189984 +-0.0313699991 -0.0186299998 0.0362810008 +-0.0313699991 -0.0186299998 0.0137189999 +-0.0313699991 -0.0186299998 0.0112810005 +-0.0313699991 -0.0186299998 -0.0112810005 +-0.0313699991 -0.0186299998 -0.0137189999 +-0.0313699991 -0.0186299998 -0.0362810008 +-0.0313699991 -0.0186299998 -0.0387189984 +-0.0313699991 -0.0313699991 0.0137189999 +-0.0313699991 -0.0313699991 0.0112810005 +-0.0313699991 -0.0313699991 -0.0112810005 +-0.0313699991 -0.0313699991 -0.0137189999 +-0.0313699991 -0.0313699991 -0.0362810008 +-0.0313699991 -0.0313699991 -0.0387189984 +-0.0313699991 -0.0362810008 0.0186299998 +-0.0313699991 -0.0362810008 0.0063700001 +-0.0313699991 -0.0362810008 -0.0063700001 +-0.0313699991 -0.0362810008 -0.0186299998 +-0.0313699991 -0.0362810008 -0.0313699991 +-0.0313699991 -0.0362810008 -0.0436300002 +-0.0313699991 -0.0387189984 0.0186299998 +-0.0313699991 -0.0387189984 0.0063700001 +-0.0313699991 -0.0387189984 -0.0063700001 +-0.0313699991 -0.0387189984 -0.0186299998 +-0.0313699991 -0.0387189984 -0.0313699991 +-0.0313699991 -0.0387189984 -0.0436300002 +-0.0313699991 -0.0436300002 0.0137189999 +-0.0313699991 -0.0436300002 0.0112810005 +-0.0313699991 -0.0436300002 -0.0112810005 +-0.0313699991 -0.0436300002 -0.0137189999 +-0.0313699991 -0.0436300002 -0.0362810008 +-0.0313699991 -0.0436300002 -0.0387189984 +-0.0314630009 0.0500000007 0.0391179994 +-0.0314630009 0.0500000007 0.0358819999 +-0.0314630009 0.0500000007 0.0141179999 +-0.0314630009 0.0500000007 0.0108820004 +-0.0314630009 0.0500000007 -0.0108820004 +-0.0314630009 0.0500000007 -0.0141179999 +-0.0314630009 0.0500000007 -0.0358819999 +-0.0314630009 0.0500000007 -0.0391179994 +-0.0314630009 0.0391179994 0.0500000007 +-0.0314630009 0.0391179994 -0.0500000007 +-0.0314630009 0.0358819999 0.0500000007 +-0.0314630009 0.0358819999 -0.0500000007 +-0.0314630009 0.0141179999 -0.0003910000 +-0.0314630009 0.0141179999 -0.0500000007 +-0.0314630009 0.0108820004 -0.0003910000 +-0.0314630009 0.0108820004 -0.0500000007 +-0.0314630009 -0.0108820004 0.0500000007 +-0.0314630009 -0.0108820004 -0.0500000007 +-0.0314630009 -0.0141179999 0.0500000007 +-0.0314630009 -0.0141179999 -0.0500000007 +-0.0314630009 -0.0250000004 0.0391179994 +-0.0314630009 -0.0250000004 0.0358819999 +-0.0314630009 -0.0358819999 0.0212500002 +-0.0314630009 -0.0358819999 -0.0500000007 +-0.0314630009 -0.0391179994 0.0212500002 +-0.0314630009 -0.0391179994 -0.0500000007 +-0.0314630009 -0.0500000007 0.0141179999 +-0.0314630009 -0.0500000007 0.0108820004 +-0.0314630009 -0.0500000007 -0.0108820004 +-0.0314630009 -0.0500000007 -0.0141179999 +-0.0314630009 -0.0500000007 -0.0358819999 +-0.0314630009 -0.0500000007 -0.0391179994 +-0.0316779986 -0.0000000000 0.0397729985 +-0.0316779986 -0.0000000000 0.0352270007 +-0.0316779986 -0.0000000000 0.0147730000 +-0.0316779986 -0.0000000000 0.0102270003 +-0.0316840000 0.0243820008 0.0397889987 +-0.0316840000 0.0243820008 0.0352110006 +-0.0316840000 0.0243820008 0.0147890002 +-0.0316840000 0.0243820008 0.0102110002 +-0.0317259990 0.0432740003 0.0398919992 +-0.0317259990 0.0432740003 0.0351080000 +-0.0317259990 0.0432740003 0.0148919998 +-0.0317259990 0.0432740003 0.0101079997 +-0.0317259990 0.0432740003 -0.0101079997 +-0.0317259990 0.0432740003 -0.0148919998 +-0.0317259990 0.0432740003 -0.0351080000 +-0.0317259990 0.0432740003 -0.0398919992 +-0.0317259990 0.0398919992 0.0432740003 +-0.0317259990 0.0398919992 0.0317259990 +-0.0317259990 0.0398919992 0.0182739999 +-0.0317259990 0.0398919992 0.0067260000 +-0.0317259990 0.0398919992 -0.0067260000 +-0.0317259990 0.0398919992 -0.0182739999 +-0.0317259990 0.0398919992 -0.0317259990 +-0.0317259990 0.0398919992 -0.0432740003 +-0.0317259990 0.0351080000 0.0432740003 +-0.0317259990 0.0351080000 0.0317259990 +-0.0317259990 0.0351080000 0.0182739999 +-0.0317259990 0.0351080000 0.0067260000 +-0.0317259990 0.0351080000 -0.0067260000 +-0.0317259990 0.0351080000 -0.0182739999 +-0.0317259990 0.0351080000 -0.0317259990 +-0.0317259990 0.0351080000 -0.0432740003 +-0.0317259990 0.0317259990 0.0398919992 +-0.0317259990 0.0317259990 0.0351080000 +-0.0317259990 0.0317259990 0.0148919998 +-0.0317259990 0.0317259990 0.0101079997 +-0.0317259990 0.0317259990 -0.0101079997 +-0.0317259990 0.0317259990 -0.0148919998 +-0.0317259990 0.0317259990 -0.0351080000 +-0.0317259990 0.0317259990 -0.0398919992 +-0.0317259990 0.0182739999 -0.0101079997 +-0.0317259990 0.0182739999 -0.0148919998 +-0.0317259990 0.0182739999 -0.0351080000 +-0.0317259990 0.0182739999 -0.0398919992 +-0.0317259990 0.0148919998 -0.0067260000 +-0.0317259990 0.0148919998 -0.0182739999 +-0.0317259990 0.0148919998 -0.0317259990 +-0.0317259990 0.0148919998 -0.0432740003 +-0.0317259990 0.0101079997 -0.0067260000 +-0.0317259990 0.0101079997 -0.0182739999 +-0.0317259990 0.0101079997 -0.0317259990 +-0.0317259990 0.0101079997 -0.0432740003 +-0.0317259990 0.0067260000 -0.0101079997 +-0.0317259990 0.0067260000 -0.0148919998 +-0.0317259990 0.0067260000 -0.0351080000 +-0.0317259990 0.0067260000 -0.0398919992 +-0.0317259990 -0.0067260000 0.0398919992 +-0.0317259990 -0.0067260000 0.0351080000 +-0.0317259990 -0.0067260000 0.0148919998 +-0.0317259990 -0.0067260000 0.0101079997 +-0.0317259990 -0.0067260000 -0.0101079997 +-0.0317259990 -0.0067260000 -0.0148919998 +-0.0317259990 -0.0067260000 -0.0351080000 +-0.0317259990 -0.0067260000 -0.0398919992 +-0.0317259990 -0.0101079997 0.0432740003 +-0.0317259990 -0.0101079997 0.0317259990 +-0.0317259990 -0.0101079997 0.0182739999 +-0.0317259990 -0.0101079997 0.0067260000 +-0.0317259990 -0.0101079997 -0.0067260000 +-0.0317259990 -0.0101079997 -0.0182739999 +-0.0317259990 -0.0101079997 -0.0317259990 +-0.0317259990 -0.0101079997 -0.0432740003 +-0.0317259990 -0.0148919998 0.0432740003 +-0.0317259990 -0.0148919998 0.0317259990 +-0.0317259990 -0.0148919998 0.0182739999 +-0.0317259990 -0.0148919998 0.0067260000 +-0.0317259990 -0.0148919998 -0.0067260000 +-0.0317259990 -0.0148919998 -0.0182739999 +-0.0317259990 -0.0148919998 -0.0317259990 +-0.0317259990 -0.0148919998 -0.0432740003 +-0.0317259990 -0.0182739999 0.0398919992 +-0.0317259990 -0.0182739999 0.0351080000 +-0.0317259990 -0.0182739999 0.0148919998 +-0.0317259990 -0.0182739999 0.0101079997 +-0.0317259990 -0.0182739999 -0.0101079997 +-0.0317259990 -0.0182739999 -0.0148919998 +-0.0317259990 -0.0182739999 -0.0351080000 +-0.0317259990 -0.0182739999 -0.0398919992 +-0.0317259990 -0.0317259990 0.0148919998 +-0.0317259990 -0.0317259990 0.0101079997 +-0.0317259990 -0.0317259990 -0.0101079997 +-0.0317259990 -0.0317259990 -0.0148919998 +-0.0317259990 -0.0317259990 -0.0351080000 +-0.0317259990 -0.0317259990 -0.0398919992 +-0.0317259990 -0.0351080000 0.0182739999 +-0.0317259990 -0.0351080000 0.0067260000 +-0.0317259990 -0.0351080000 -0.0067260000 +-0.0317259990 -0.0351080000 -0.0182739999 +-0.0317259990 -0.0351080000 -0.0317259990 +-0.0317259990 -0.0351080000 -0.0432740003 +-0.0317259990 -0.0398919992 0.0182739999 +-0.0317259990 -0.0398919992 0.0067260000 +-0.0317259990 -0.0398919992 -0.0067260000 +-0.0317259990 -0.0398919992 -0.0182739999 +-0.0317259990 -0.0398919992 -0.0317259990 +-0.0317259990 -0.0398919992 -0.0432740003 +-0.0317259990 -0.0432740003 0.0148919998 +-0.0317259990 -0.0432740003 0.0101079997 +-0.0317259990 -0.0432740003 -0.0101079997 +-0.0317259990 -0.0432740003 -0.0148919998 +-0.0317259990 -0.0432740003 -0.0351080000 +-0.0317259990 -0.0432740003 -0.0398919992 +-0.0320869982 0.0500000007 0.0406249985 +-0.0320869982 0.0500000007 0.0343750007 +-0.0320869982 0.0500000007 0.0156250000 +-0.0320869982 0.0500000007 0.0093750004 +-0.0320869982 0.0500000007 -0.0093750004 +-0.0320869982 0.0500000007 -0.0156250000 +-0.0320869982 0.0500000007 -0.0343750007 +-0.0320869982 0.0500000007 -0.0406249985 +-0.0320869982 0.0406249985 0.0500000007 +-0.0320869982 0.0406249985 -0.0500000007 +-0.0320869982 0.0343750007 0.0500000007 +-0.0320869982 0.0343750007 -0.0500000007 +-0.0320869982 0.0156250000 -0.0003910000 +-0.0320869982 0.0156250000 -0.0500000007 +-0.0320869982 0.0093750004 -0.0003910000 +-0.0320869982 0.0093750004 -0.0500000007 +-0.0320869982 -0.0093750004 0.0500000007 +-0.0320869982 -0.0093750004 -0.0500000007 +-0.0320869982 -0.0156250000 0.0500000007 +-0.0320869982 -0.0156250000 -0.0500000007 +-0.0320869982 -0.0250000004 0.0406249985 +-0.0320869982 -0.0250000004 0.0343750007 +-0.0320869982 -0.0343750007 0.0212500002 +-0.0320869982 -0.0343750007 -0.0500000007 +-0.0320869982 -0.0406249985 0.0212500002 +-0.0320869982 -0.0406249985 -0.0500000007 +-0.0320869982 -0.0500000007 0.0156250000 +-0.0320869982 -0.0500000007 0.0093750004 +-0.0320869982 -0.0500000007 -0.0093750004 +-0.0320869982 -0.0500000007 -0.0156250000 +-0.0320869982 -0.0500000007 -0.0343750007 +-0.0320869982 -0.0500000007 -0.0406249985 +-0.0322129987 0.0246869996 0.0408330001 +-0.0322129987 0.0246869996 0.0341669992 +-0.0322129987 0.0246869996 0.0158329997 +-0.0322129987 0.0246869996 0.0091669997 +-0.0323030017 0.0426970012 0.0409720019 +-0.0323030017 0.0426970012 0.0340280011 +-0.0323030017 0.0426970012 0.0159719996 +-0.0323030017 0.0426970012 0.0090279998 +-0.0323030017 0.0426970012 -0.0090279998 +-0.0323030017 0.0426970012 -0.0159719996 +-0.0323030017 0.0426970012 -0.0340280011 +-0.0323030017 0.0426970012 -0.0409720019 +-0.0323030017 0.0409720019 0.0426970012 +-0.0323030017 0.0409720019 0.0323030017 +-0.0323030017 0.0409720019 0.0176970009 +-0.0323030017 0.0409720019 0.0073030000 +-0.0323030017 0.0409720019 -0.0073030000 +-0.0323030017 0.0409720019 -0.0176970009 +-0.0323030017 0.0409720019 -0.0323030017 +-0.0323030017 0.0409720019 -0.0426970012 +-0.0323030017 0.0340280011 0.0426970012 +-0.0323030017 0.0340280011 0.0323030017 +-0.0323030017 0.0340280011 0.0176970009 +-0.0323030017 0.0340280011 0.0073030000 +-0.0323030017 0.0340280011 -0.0073030000 +-0.0323030017 0.0340280011 -0.0176970009 +-0.0323030017 0.0340280011 -0.0323030017 +-0.0323030017 0.0340280011 -0.0426970012 +-0.0323030017 0.0323030017 0.0409720019 +-0.0323030017 0.0323030017 0.0340280011 +-0.0323030017 0.0323030017 0.0159719996 +-0.0323030017 0.0323030017 0.0090279998 +-0.0323030017 0.0323030017 -0.0090279998 +-0.0323030017 0.0323030017 -0.0159719996 +-0.0323030017 0.0323030017 -0.0340280011 +-0.0323030017 0.0323030017 -0.0409720019 +-0.0323030017 0.0176970009 -0.0090279998 +-0.0323030017 0.0176970009 -0.0159719996 +-0.0323030017 0.0176970009 -0.0340280011 +-0.0323030017 0.0176970009 -0.0409720019 +-0.0323030017 0.0159719996 -0.0073030000 +-0.0323030017 0.0159719996 -0.0176970009 +-0.0323030017 0.0159719996 -0.0323030017 +-0.0323030017 0.0159719996 -0.0426970012 +-0.0323030017 0.0090279998 -0.0073030000 +-0.0323030017 0.0090279998 -0.0176970009 +-0.0323030017 0.0090279998 -0.0323030017 +-0.0323030017 0.0090279998 -0.0426970012 +-0.0323030017 0.0073030000 -0.0090279998 +-0.0323030017 0.0073030000 -0.0159719996 +-0.0323030017 0.0073030000 -0.0340280011 +-0.0323030017 0.0073030000 -0.0409720019 +-0.0323030017 -0.0073030000 0.0409720019 +-0.0323030017 -0.0073030000 0.0340280011 +-0.0323030017 -0.0073030000 0.0159719996 +-0.0323030017 -0.0073030000 0.0090279998 +-0.0323030017 -0.0073030000 -0.0090279998 +-0.0323030017 -0.0073030000 -0.0159719996 +-0.0323030017 -0.0073030000 -0.0340280011 +-0.0323030017 -0.0073030000 -0.0409720019 +-0.0323030017 -0.0090279998 0.0426970012 +-0.0323030017 -0.0090279998 0.0323030017 +-0.0323030017 -0.0090279998 0.0176970009 +-0.0323030017 -0.0090279998 0.0073030000 +-0.0323030017 -0.0090279998 -0.0073030000 +-0.0323030017 -0.0090279998 -0.0176970009 +-0.0323030017 -0.0090279998 -0.0323030017 +-0.0323030017 -0.0090279998 -0.0426970012 +-0.0323030017 -0.0159719996 0.0426970012 +-0.0323030017 -0.0159719996 0.0323030017 +-0.0323030017 -0.0159719996 0.0176970009 +-0.0323030017 -0.0159719996 0.0073030000 +-0.0323030017 -0.0159719996 -0.0073030000 +-0.0323030017 -0.0159719996 -0.0176970009 +-0.0323030017 -0.0159719996 -0.0323030017 +-0.0323030017 -0.0159719996 -0.0426970012 +-0.0323030017 -0.0176970009 0.0409720019 +-0.0323030017 -0.0176970009 0.0340280011 +-0.0323030017 -0.0176970009 0.0159719996 +-0.0323030017 -0.0176970009 0.0090279998 +-0.0323030017 -0.0176970009 -0.0090279998 +-0.0323030017 -0.0176970009 -0.0159719996 +-0.0323030017 -0.0176970009 -0.0340280011 +-0.0323030017 -0.0176970009 -0.0409720019 +-0.0323030017 -0.0323030017 0.0159719996 +-0.0323030017 -0.0323030017 0.0090279998 +-0.0323030017 -0.0323030017 -0.0090279998 +-0.0323030017 -0.0323030017 -0.0159719996 +-0.0323030017 -0.0323030017 -0.0340280011 +-0.0323030017 -0.0323030017 -0.0409720019 +-0.0323030017 -0.0340280011 0.0176970009 +-0.0323030017 -0.0340280011 0.0073030000 +-0.0323030017 -0.0340280011 -0.0073030000 +-0.0323030017 -0.0340280011 -0.0176970009 +-0.0323030017 -0.0340280011 -0.0323030017 +-0.0323030017 -0.0340280011 -0.0426970012 +-0.0323030017 -0.0409720019 0.0176970009 +-0.0323030017 -0.0409720019 0.0073030000 +-0.0323030017 -0.0409720019 -0.0073030000 +-0.0323030017 -0.0409720019 -0.0176970009 +-0.0323030017 -0.0409720019 -0.0323030017 +-0.0323030017 -0.0409720019 -0.0426970012 +-0.0323030017 -0.0426970012 0.0159719996 +-0.0323030017 -0.0426970012 0.0090279998 +-0.0323030017 -0.0426970012 -0.0090279998 +-0.0323030017 -0.0426970012 -0.0159719996 +-0.0323030017 -0.0426970012 -0.0340280011 +-0.0323030017 -0.0426970012 -0.0409720019 +-0.0324149989 -0.0000000000 0.0411330014 +-0.0324149989 -0.0000000000 0.0338670015 +-0.0324149989 -0.0000000000 0.0161329992 +-0.0324149989 -0.0000000000 0.0088670002 +-0.0329269990 0.0251000002 0.0417609997 +-0.0329269990 0.0251000002 0.0332389995 +-0.0329269990 0.0251000002 0.0167609993 +-0.0329269990 0.0251000002 0.0082390001 +-0.0330809988 0.0500000007 0.0419190004 +-0.0330809988 0.0500000007 0.0330809988 +-0.0330809988 0.0500000007 0.0169190001 +-0.0330809988 0.0500000007 0.0080810003 +-0.0330809988 0.0500000007 -0.0080810003 +-0.0330809988 0.0500000007 -0.0169190001 +-0.0330809988 0.0500000007 -0.0330809988 +-0.0330809988 0.0500000007 -0.0419190004 +-0.0330809988 0.0419190004 0.0500000007 +-0.0330809988 0.0419190004 0.0419190004 +-0.0330809988 0.0419190004 0.0330809988 +-0.0330809988 0.0419190004 0.0169190001 +-0.0330809988 0.0419190004 0.0080810003 +-0.0330809988 0.0419190004 -0.0080810003 +-0.0330809988 0.0419190004 -0.0169190001 +-0.0330809988 0.0419190004 -0.0330809988 +-0.0330809988 0.0419190004 -0.0419190004 +-0.0330809988 0.0419190004 -0.0500000007 +-0.0330809988 0.0330809988 0.0500000007 +-0.0330809988 0.0330809988 0.0419190004 +-0.0330809988 0.0330809988 0.0330809988 +-0.0330809988 0.0330809988 0.0169190001 +-0.0330809988 0.0330809988 0.0080810003 +-0.0330809988 0.0330809988 -0.0080810003 +-0.0330809988 0.0330809988 -0.0169190001 +-0.0330809988 0.0330809988 -0.0330809988 +-0.0330809988 0.0330809988 -0.0419190004 +-0.0330809988 0.0330809988 -0.0500000007 +-0.0330809988 0.0169190001 -0.0003910000 +-0.0330809988 0.0169190001 -0.0080810003 +-0.0330809988 0.0169190001 -0.0169190001 +-0.0330809988 0.0169190001 -0.0330809988 +-0.0330809988 0.0169190001 -0.0419190004 +-0.0330809988 0.0169190001 -0.0500000007 +-0.0330809988 0.0080810003 -0.0003910000 +-0.0330809988 0.0080810003 -0.0080810003 +-0.0330809988 0.0080810003 -0.0169190001 +-0.0330809988 0.0080810003 -0.0330809988 +-0.0330809988 0.0080810003 -0.0419190004 +-0.0330809988 0.0080810003 -0.0500000007 +-0.0330809988 -0.0080810003 0.0500000007 +-0.0330809988 -0.0080810003 0.0419190004 +-0.0330809988 -0.0080810003 0.0330809988 +-0.0330809988 -0.0080810003 0.0169190001 +-0.0330809988 -0.0080810003 0.0080810003 +-0.0330809988 -0.0080810003 -0.0080810003 +-0.0330809988 -0.0080810003 -0.0169190001 +-0.0330809988 -0.0080810003 -0.0330809988 +-0.0330809988 -0.0080810003 -0.0419190004 +-0.0330809988 -0.0080810003 -0.0500000007 +-0.0330809988 -0.0169190001 0.0500000007 +-0.0330809988 -0.0169190001 0.0419190004 +-0.0330809988 -0.0169190001 0.0330809988 +-0.0330809988 -0.0169190001 0.0169190001 +-0.0330809988 -0.0169190001 0.0080810003 +-0.0330809988 -0.0169190001 -0.0080810003 +-0.0330809988 -0.0169190001 -0.0169190001 +-0.0330809988 -0.0169190001 -0.0330809988 +-0.0330809988 -0.0169190001 -0.0419190004 +-0.0330809988 -0.0169190001 -0.0500000007 +-0.0330809988 -0.0250000004 0.0419190004 +-0.0330809988 -0.0250000004 0.0330809988 +-0.0330809988 -0.0330809988 0.0212500002 +-0.0330809988 -0.0330809988 0.0169190001 +-0.0330809988 -0.0330809988 0.0080810003 +-0.0330809988 -0.0330809988 -0.0080810003 +-0.0330809988 -0.0330809988 -0.0169190001 +-0.0330809988 -0.0330809988 -0.0330809988 +-0.0330809988 -0.0330809988 -0.0419190004 +-0.0330809988 -0.0330809988 -0.0500000007 +-0.0330809988 -0.0419190004 0.0212500002 +-0.0330809988 -0.0419190004 0.0169190001 +-0.0330809988 -0.0419190004 0.0080810003 +-0.0330809988 -0.0419190004 -0.0080810003 +-0.0330809988 -0.0419190004 -0.0169190001 +-0.0330809988 -0.0419190004 -0.0330809988 +-0.0330809988 -0.0419190004 -0.0419190004 +-0.0330809988 -0.0419190004 -0.0500000007 +-0.0330809988 -0.0500000007 0.0169190001 +-0.0330809988 -0.0500000007 0.0080810003 +-0.0330809988 -0.0500000007 -0.0080810003 +-0.0330809988 -0.0500000007 -0.0169190001 +-0.0330809988 -0.0500000007 -0.0330809988 +-0.0330809988 -0.0500000007 -0.0419190004 +-0.0334630013 -0.0000000000 0.0422709994 +-0.0334630013 -0.0000000000 0.0327289999 +-0.0334630013 -0.0000000000 0.0172710009 +-0.0334630013 -0.0000000000 0.0077289999 +-0.0338019989 0.0256050006 0.0425379984 +-0.0338019989 0.0256050006 0.0324620008 +-0.0338019989 0.0256050006 0.0175379999 +-0.0338019989 0.0256050006 0.0074620000 +-0.0340280011 0.0426970012 0.0426970012 +-0.0340280011 0.0426970012 0.0323030017 +-0.0340280011 0.0426970012 0.0176970009 +-0.0340280011 0.0426970012 0.0073030000 +-0.0340280011 0.0426970012 -0.0073030000 +-0.0340280011 0.0426970012 -0.0176970009 +-0.0340280011 0.0426970012 -0.0323030017 +-0.0340280011 0.0426970012 -0.0426970012 +-0.0340280011 0.0323030017 0.0426970012 +-0.0340280011 0.0323030017 0.0323030017 +-0.0340280011 0.0323030017 0.0176970009 +-0.0340280011 0.0323030017 0.0073030000 +-0.0340280011 0.0323030017 -0.0073030000 +-0.0340280011 0.0323030017 -0.0176970009 +-0.0340280011 0.0323030017 -0.0323030017 +-0.0340280011 0.0323030017 -0.0426970012 +-0.0340280011 0.0176970009 -0.0073030000 +-0.0340280011 0.0176970009 -0.0176970009 +-0.0340280011 0.0176970009 -0.0323030017 +-0.0340280011 0.0176970009 -0.0426970012 +-0.0340280011 0.0073030000 -0.0073030000 +-0.0340280011 0.0073030000 -0.0176970009 +-0.0340280011 0.0073030000 -0.0323030017 +-0.0340280011 0.0073030000 -0.0426970012 +-0.0340280011 -0.0073030000 0.0426970012 +-0.0340280011 -0.0073030000 0.0323030017 +-0.0340280011 -0.0073030000 0.0176970009 +-0.0340280011 -0.0073030000 0.0073030000 +-0.0340280011 -0.0073030000 -0.0073030000 +-0.0340280011 -0.0073030000 -0.0176970009 +-0.0340280011 -0.0073030000 -0.0323030017 +-0.0340280011 -0.0073030000 -0.0426970012 +-0.0340280011 -0.0176970009 0.0426970012 +-0.0340280011 -0.0176970009 0.0323030017 +-0.0340280011 -0.0176970009 0.0176970009 +-0.0340280011 -0.0176970009 0.0073030000 +-0.0340280011 -0.0176970009 -0.0073030000 +-0.0340280011 -0.0176970009 -0.0176970009 +-0.0340280011 -0.0176970009 -0.0323030017 +-0.0340280011 -0.0176970009 -0.0426970012 +-0.0340280011 -0.0323030017 0.0176970009 +-0.0340280011 -0.0323030017 0.0073030000 +-0.0340280011 -0.0323030017 -0.0073030000 +-0.0340280011 -0.0323030017 -0.0176970009 +-0.0340280011 -0.0323030017 -0.0323030017 +-0.0340280011 -0.0323030017 -0.0426970012 +-0.0340280011 -0.0426970012 0.0176970009 +-0.0340280011 -0.0426970012 0.0073030000 +-0.0340280011 -0.0426970012 -0.0073030000 +-0.0340280011 -0.0426970012 -0.0176970009 +-0.0340280011 -0.0426970012 -0.0323030017 +-0.0340280011 -0.0426970012 -0.0426970012 +-0.0343750007 0.0500000007 0.0429130010 +-0.0343750007 0.0500000007 0.0320869982 +-0.0343750007 0.0500000007 0.0179130007 +-0.0343750007 0.0500000007 0.0070870002 +-0.0343750007 0.0500000007 -0.0070870002 +-0.0343750007 0.0500000007 -0.0179130007 +-0.0343750007 0.0500000007 -0.0320869982 +-0.0343750007 0.0500000007 -0.0429130010 +-0.0343750007 0.0429130010 0.0500000007 +-0.0343750007 0.0429130010 -0.0500000007 +-0.0343750007 0.0320869982 0.0500000007 +-0.0343750007 0.0320869982 -0.0500000007 +-0.0343750007 0.0179130007 -0.0003910000 +-0.0343750007 0.0179130007 -0.0500000007 +-0.0343750007 0.0070870002 -0.0003910000 +-0.0343750007 0.0070870002 -0.0500000007 +-0.0343750007 -0.0070870002 0.0500000007 +-0.0343750007 -0.0070870002 -0.0500000007 +-0.0343750007 -0.0179130007 0.0500000007 +-0.0343750007 -0.0179130007 -0.0500000007 +-0.0343750007 -0.0250000004 0.0429130010 +-0.0343750007 -0.0250000004 0.0320869982 +-0.0343750007 -0.0320869982 0.0212500002 +-0.0343750007 -0.0320869982 -0.0500000007 +-0.0343750007 -0.0429130010 0.0212500002 +-0.0343750007 -0.0429130010 -0.0500000007 +-0.0343750007 -0.0500000007 0.0179130007 +-0.0343750007 -0.0500000007 0.0070870002 +-0.0343750007 -0.0500000007 -0.0070870002 +-0.0343750007 -0.0500000007 -0.0179130007 +-0.0343750007 -0.0500000007 -0.0320869982 +-0.0343750007 -0.0500000007 -0.0429130010 +-0.0347580016 -0.0000000000 0.0500000007 +-0.0347580016 -0.0000000000 0.0431159995 +-0.0347580016 -0.0000000000 0.0318839997 +-0.0347580016 -0.0000000000 0.0181159992 +-0.0347580016 -0.0000000000 0.0068839998 +-0.0347580016 -0.0000000000 -0.0003910000 +-0.0348059982 0.0261840001 0.0431389995 +-0.0348059982 0.0261840001 0.0318609998 +-0.0348059982 0.0261840001 0.0181389991 +-0.0348059982 0.0261840001 0.0068609999 +-0.0351080000 0.0432740003 0.0432740003 +-0.0351080000 0.0432740003 0.0317259990 +-0.0351080000 0.0432740003 0.0182739999 +-0.0351080000 0.0432740003 0.0067260000 +-0.0351080000 0.0432740003 -0.0067260000 +-0.0351080000 0.0432740003 -0.0182739999 +-0.0351080000 0.0432740003 -0.0317259990 +-0.0351080000 0.0432740003 -0.0432740003 +-0.0351080000 0.0317259990 0.0432740003 +-0.0351080000 0.0317259990 0.0317259990 +-0.0351080000 0.0317259990 0.0182739999 +-0.0351080000 0.0317259990 0.0067260000 +-0.0351080000 0.0317259990 -0.0067260000 +-0.0351080000 0.0317259990 -0.0182739999 +-0.0351080000 0.0317259990 -0.0317259990 +-0.0351080000 0.0317259990 -0.0432740003 +-0.0351080000 0.0182739999 -0.0067260000 +-0.0351080000 0.0182739999 -0.0182739999 +-0.0351080000 0.0182739999 -0.0317259990 +-0.0351080000 0.0182739999 -0.0432740003 +-0.0351080000 0.0067260000 -0.0067260000 +-0.0351080000 0.0067260000 -0.0182739999 +-0.0351080000 0.0067260000 -0.0317259990 +-0.0351080000 0.0067260000 -0.0432740003 +-0.0351080000 -0.0067260000 0.0432740003 +-0.0351080000 -0.0067260000 0.0317259990 +-0.0351080000 -0.0067260000 0.0182739999 +-0.0351080000 -0.0067260000 0.0067260000 +-0.0351080000 -0.0067260000 -0.0067260000 +-0.0351080000 -0.0067260000 -0.0182739999 +-0.0351080000 -0.0067260000 -0.0317259990 +-0.0351080000 -0.0067260000 -0.0432740003 +-0.0351080000 -0.0182739999 0.0432740003 +-0.0351080000 -0.0182739999 0.0317259990 +-0.0351080000 -0.0182739999 0.0182739999 +-0.0351080000 -0.0182739999 0.0067260000 +-0.0351080000 -0.0182739999 -0.0067260000 +-0.0351080000 -0.0182739999 -0.0182739999 +-0.0351080000 -0.0182739999 -0.0317259990 +-0.0351080000 -0.0182739999 -0.0432740003 +-0.0351080000 -0.0317259990 0.0182739999 +-0.0351080000 -0.0317259990 0.0067260000 +-0.0351080000 -0.0317259990 -0.0067260000 +-0.0351080000 -0.0317259990 -0.0182739999 +-0.0351080000 -0.0317259990 -0.0317259990 +-0.0351080000 -0.0317259990 -0.0432740003 +-0.0351080000 -0.0432740003 0.0182739999 +-0.0351080000 -0.0432740003 0.0067260000 +-0.0351080000 -0.0432740003 -0.0067260000 +-0.0351080000 -0.0432740003 -0.0182739999 +-0.0351080000 -0.0432740003 -0.0317259990 +-0.0351080000 -0.0432740003 -0.0432740003 +-0.0354919992 0.0000460000 0.0434189998 +-0.0354919992 0.0000460000 0.0315809995 +-0.0354919992 0.0000460000 0.0184189994 +-0.0354919992 0.0000460000 0.0065810001 +-0.0358819999 0.0500000007 0.0435369983 +-0.0358819999 0.0500000007 0.0314630009 +-0.0358819999 0.0500000007 0.0185369998 +-0.0358819999 0.0500000007 0.0064630001 +-0.0358819999 0.0500000007 -0.0064630001 +-0.0358819999 0.0500000007 -0.0185369998 +-0.0358819999 0.0500000007 -0.0314630009 +-0.0358819999 0.0500000007 -0.0435369983 +-0.0358819999 0.0435369983 0.0500000007 +-0.0358819999 0.0435369983 -0.0500000007 +-0.0358819999 0.0314630009 0.0500000007 +-0.0358819999 0.0314630009 -0.0500000007 +-0.0358819999 0.0185369998 -0.0003910000 +-0.0358819999 0.0185369998 -0.0500000007 +-0.0358819999 0.0064630001 -0.0003910000 +-0.0358819999 0.0064630001 -0.0500000007 +-0.0358819999 -0.0064630001 0.0500000007 +-0.0358819999 -0.0064630001 -0.0500000007 +-0.0358819999 -0.0185369998 0.0500000007 +-0.0358819999 -0.0185369998 -0.0500000007 +-0.0358819999 -0.0250000004 0.0435369983 +-0.0358819999 -0.0250000004 0.0314630009 +-0.0358819999 -0.0314630009 0.0212500002 +-0.0358819999 -0.0314630009 -0.0500000007 +-0.0358819999 -0.0435369983 0.0212500002 +-0.0358819999 -0.0435369983 -0.0500000007 +-0.0358819999 -0.0500000007 0.0185369998 +-0.0358819999 -0.0500000007 0.0064630001 +-0.0358819999 -0.0500000007 -0.0064630001 +-0.0358819999 -0.0500000007 -0.0185369998 +-0.0358819999 -0.0500000007 -0.0314630009 +-0.0358819999 -0.0500000007 -0.0435369983 +-0.0359040014 0.0268190000 0.0435429998 +-0.0359040014 0.0268190000 0.0314569995 +-0.0359040014 0.0268190000 0.0185429994 +-0.0359040014 0.0268190000 0.0064570000 +-0.0362549983 0.0001950000 0.0436250009 +-0.0362549983 0.0001950000 0.0313749984 +-0.0362549983 0.0001950000 0.0186250005 +-0.0362549983 0.0001950000 0.0063749999 +-0.0362749994 0.0002000000 0.0500000007 +-0.0362749994 0.0002000000 -0.0003910000 +-0.0362810008 0.0436300002 0.0436300002 +-0.0362810008 0.0436300002 0.0313699991 +-0.0362810008 0.0436300002 0.0186299998 +-0.0362810008 0.0436300002 0.0063700001 +-0.0362810008 0.0436300002 -0.0063700001 +-0.0362810008 0.0436300002 -0.0186299998 +-0.0362810008 0.0436300002 -0.0313699991 +-0.0362810008 0.0436300002 -0.0436300002 +-0.0362810008 0.0313699991 0.0436300002 +-0.0362810008 0.0313699991 0.0313699991 +-0.0362810008 0.0313699991 0.0186299998 +-0.0362810008 0.0313699991 0.0063700001 +-0.0362810008 0.0313699991 -0.0063700001 +-0.0362810008 0.0313699991 -0.0186299998 +-0.0362810008 0.0313699991 -0.0313699991 +-0.0362810008 0.0313699991 -0.0436300002 +-0.0362810008 0.0186299998 -0.0063700001 +-0.0362810008 0.0186299998 -0.0186299998 +-0.0362810008 0.0186299998 -0.0313699991 +-0.0362810008 0.0186299998 -0.0436300002 +-0.0362810008 0.0063700001 -0.0063700001 +-0.0362810008 0.0063700001 -0.0186299998 +-0.0362810008 0.0063700001 -0.0313699991 +-0.0362810008 0.0063700001 -0.0436300002 +-0.0362810008 -0.0063700001 0.0436300002 +-0.0362810008 -0.0063700001 0.0313699991 +-0.0362810008 -0.0063700001 0.0186299998 +-0.0362810008 -0.0063700001 0.0063700001 +-0.0362810008 -0.0063700001 -0.0063700001 +-0.0362810008 -0.0063700001 -0.0186299998 +-0.0362810008 -0.0063700001 -0.0313699991 +-0.0362810008 -0.0063700001 -0.0436300002 +-0.0362810008 -0.0186299998 0.0436300002 +-0.0362810008 -0.0186299998 0.0313699991 +-0.0362810008 -0.0186299998 0.0186299998 +-0.0362810008 -0.0186299998 0.0063700001 +-0.0362810008 -0.0186299998 -0.0063700001 +-0.0362810008 -0.0186299998 -0.0186299998 +-0.0362810008 -0.0186299998 -0.0313699991 +-0.0362810008 -0.0186299998 -0.0436300002 +-0.0362810008 -0.0313699991 0.0186299998 +-0.0362810008 -0.0313699991 0.0063700001 +-0.0362810008 -0.0313699991 -0.0063700001 +-0.0362810008 -0.0313699991 -0.0186299998 +-0.0362810008 -0.0313699991 -0.0313699991 +-0.0362810008 -0.0313699991 -0.0436300002 +-0.0362810008 -0.0436300002 0.0186299998 +-0.0362810008 -0.0436300002 0.0063700001 +-0.0362810008 -0.0436300002 -0.0063700001 +-0.0362810008 -0.0436300002 -0.0186299998 +-0.0362810008 -0.0436300002 -0.0313699991 +-0.0362810008 -0.0436300002 -0.0436300002 +-0.0368870012 0.0437199995 0.0437199995 +-0.0368870012 0.0437199995 0.0312799998 +-0.0368870012 0.0437199995 0.0187199991 +-0.0368870012 0.0437199995 0.0062799999 +-0.0368870012 0.0437199995 -0.0062799999 +-0.0368870012 0.0437199995 -0.0187199991 +-0.0368870012 0.0437199995 -0.0312799998 +-0.0368870012 0.0437199995 -0.0437199995 +-0.0368870012 0.0312799998 0.0437199995 +-0.0368870012 0.0312799998 0.0312799998 +-0.0368870012 0.0312799998 0.0187199991 +-0.0368870012 0.0312799998 0.0062799999 +-0.0368870012 0.0312799998 -0.0062799999 +-0.0368870012 0.0312799998 -0.0187199991 +-0.0368870012 0.0312799998 -0.0312799998 +-0.0368870012 0.0312799998 -0.0437199995 +-0.0368870012 0.0187199991 -0.0062799999 +-0.0368870012 0.0187199991 -0.0187199991 +-0.0368870012 0.0187199991 -0.0312799998 +-0.0368870012 0.0187199991 -0.0437199995 +-0.0368870012 0.0062799999 -0.0062799999 +-0.0368870012 0.0062799999 -0.0187199991 +-0.0368870012 0.0062799999 -0.0312799998 +-0.0368870012 0.0062799999 -0.0437199995 +-0.0368870012 -0.0062799999 0.0437199995 +-0.0368870012 -0.0062799999 0.0312799998 +-0.0368870012 -0.0062799999 0.0187199991 +-0.0368870012 -0.0062799999 0.0062799999 +-0.0368870012 -0.0062799999 -0.0062799999 +-0.0368870012 -0.0062799999 -0.0187199991 +-0.0368870012 -0.0062799999 -0.0312799998 +-0.0368870012 -0.0062799999 -0.0437199995 +-0.0368870012 -0.0187199991 0.0437199995 +-0.0368870012 -0.0187199991 0.0312799998 +-0.0368870012 -0.0187199991 0.0187199991 +-0.0368870012 -0.0187199991 0.0062799999 +-0.0368870012 -0.0187199991 -0.0062799999 +-0.0368870012 -0.0187199991 -0.0187199991 +-0.0368870012 -0.0187199991 -0.0312799998 +-0.0368870012 -0.0187199991 -0.0437199995 +-0.0368870012 -0.0312799998 0.0187199991 +-0.0368870012 -0.0312799998 0.0062799999 +-0.0368870012 -0.0312799998 -0.0062799999 +-0.0368870012 -0.0312799998 -0.0187199991 +-0.0368870012 -0.0312799998 -0.0312799998 +-0.0368870012 -0.0312799998 -0.0437199995 +-0.0368870012 -0.0437199995 0.0187199991 +-0.0368870012 -0.0437199995 0.0062799999 +-0.0368870012 -0.0437199995 -0.0062799999 +-0.0368870012 -0.0437199995 -0.0187199991 +-0.0368870012 -0.0437199995 -0.0312799998 +-0.0368870012 -0.0437199995 -0.0437199995 +-0.0370000005 0.0004460000 0.0437299982 +-0.0370000005 0.0004460000 0.0312700011 +-0.0370000005 0.0004460000 0.0187299997 +-0.0370000005 0.0004460000 0.0062699998 +-0.0370590016 0.0274850000 0.0437339991 +-0.0370590016 0.0274850000 0.0312660001 +-0.0370590016 0.0274850000 0.0187340006 +-0.0370590016 0.0274850000 0.0062660002 +-0.0375000015 0.0500000007 0.0437499993 +-0.0375000015 0.0500000007 0.0312500000 +-0.0375000015 0.0500000007 0.0187500007 +-0.0375000015 0.0500000007 0.0062500001 +-0.0375000015 0.0500000007 -0.0062500001 +-0.0375000015 0.0500000007 -0.0187500007 +-0.0375000015 0.0500000007 -0.0312500000 +-0.0375000015 0.0500000007 -0.0437499993 +-0.0375000015 0.0437499993 0.0500000007 +-0.0375000015 0.0437499993 0.0437499993 +-0.0375000015 0.0437499993 0.0312500000 +-0.0375000015 0.0437499993 0.0187500007 +-0.0375000015 0.0437499993 0.0062500001 +-0.0375000015 0.0437499993 -0.0062500001 +-0.0375000015 0.0437499993 -0.0187500007 +-0.0375000015 0.0437499993 -0.0312500000 +-0.0375000015 0.0437499993 -0.0437499993 +-0.0375000015 0.0437499993 -0.0500000007 +-0.0375000015 0.0312500000 0.0500000007 +-0.0375000015 0.0312500000 0.0437499993 +-0.0375000015 0.0312500000 0.0312500000 +-0.0375000015 0.0312500000 0.0187500007 +-0.0375000015 0.0312500000 0.0062500001 +-0.0375000015 0.0312500000 -0.0062500001 +-0.0375000015 0.0312500000 -0.0187500007 +-0.0375000015 0.0312500000 -0.0312500000 +-0.0375000015 0.0312500000 -0.0437499993 +-0.0375000015 0.0312500000 -0.0500000007 +-0.0375000015 0.0187500007 -0.0003910000 +-0.0375000015 0.0187500007 -0.0062500001 +-0.0375000015 0.0187500007 -0.0187500007 +-0.0375000015 0.0187500007 -0.0312500000 +-0.0375000015 0.0187500007 -0.0437499993 +-0.0375000015 0.0187500007 -0.0500000007 +-0.0375000015 0.0062500001 -0.0003910000 +-0.0375000015 0.0062500001 -0.0062500001 +-0.0375000015 0.0062500001 -0.0187500007 +-0.0375000015 0.0062500001 -0.0312500000 +-0.0375000015 0.0062500001 -0.0437499993 +-0.0375000015 0.0062500001 -0.0500000007 +-0.0375000015 -0.0062500001 0.0500000007 +-0.0375000015 -0.0062500001 0.0437499993 +-0.0375000015 -0.0062500001 0.0312500000 +-0.0375000015 -0.0062500001 0.0187500007 +-0.0375000015 -0.0062500001 0.0062500001 +-0.0375000015 -0.0062500001 -0.0062500001 +-0.0375000015 -0.0062500001 -0.0187500007 +-0.0375000015 -0.0062500001 -0.0312500000 +-0.0375000015 -0.0062500001 -0.0437499993 +-0.0375000015 -0.0062500001 -0.0500000007 +-0.0375000015 -0.0187500007 0.0500000007 +-0.0375000015 -0.0187500007 0.0437499993 +-0.0375000015 -0.0187500007 0.0312500000 +-0.0375000015 -0.0187500007 0.0187500007 +-0.0375000015 -0.0187500007 0.0062500001 +-0.0375000015 -0.0187500007 -0.0062500001 +-0.0375000015 -0.0187500007 -0.0187500007 +-0.0375000015 -0.0187500007 -0.0312500000 +-0.0375000015 -0.0187500007 -0.0437499993 +-0.0375000015 -0.0187500007 -0.0500000007 +-0.0375000015 -0.0250000004 0.0437499993 +-0.0375000015 -0.0250000004 0.0312500000 +-0.0375000015 -0.0312500000 0.0212500002 +-0.0375000015 -0.0312500000 0.0187500007 +-0.0375000015 -0.0312500000 0.0062500001 +-0.0375000015 -0.0312500000 -0.0062500001 +-0.0375000015 -0.0312500000 -0.0187500007 +-0.0375000015 -0.0312500000 -0.0312500000 +-0.0375000015 -0.0312500000 -0.0437499993 +-0.0375000015 -0.0312500000 -0.0500000007 +-0.0375000015 -0.0437499993 0.0212500002 +-0.0375000015 -0.0437499993 0.0187500007 +-0.0375000015 -0.0437499993 0.0062500001 +-0.0375000015 -0.0437499993 -0.0062500001 +-0.0375000015 -0.0437499993 -0.0187500007 +-0.0375000015 -0.0437499993 -0.0312500000 +-0.0375000015 -0.0437499993 -0.0437499993 +-0.0375000015 -0.0437499993 -0.0500000007 +-0.0375000015 -0.0500000007 0.0187500007 +-0.0375000015 -0.0500000007 0.0062500001 +-0.0375000015 -0.0500000007 -0.0062500001 +-0.0375000015 -0.0500000007 -0.0187500007 +-0.0375000015 -0.0500000007 -0.0312500000 +-0.0375000015 -0.0500000007 -0.0437499993 +-0.0376879983 0.0007850000 0.0500000007 +-0.0376879983 0.0007850000 0.0437470004 +-0.0376879983 0.0007850000 0.0312529989 +-0.0376879983 0.0007850000 0.0187470000 +-0.0376879983 0.0007850000 0.0062529999 +-0.0376879983 0.0007850000 -0.0003910000 +-0.0381130017 0.0437199995 0.0437199995 +-0.0381130017 0.0437199995 0.0312799998 +-0.0381130017 0.0437199995 0.0187199991 +-0.0381130017 0.0437199995 0.0062799999 +-0.0381130017 0.0437199995 -0.0062799999 +-0.0381130017 0.0437199995 -0.0187199991 +-0.0381130017 0.0437199995 -0.0312799998 +-0.0381130017 0.0437199995 -0.0437199995 +-0.0381130017 0.0312799998 0.0437199995 +-0.0381130017 0.0312799998 0.0312799998 +-0.0381130017 0.0312799998 0.0187199991 +-0.0381130017 0.0312799998 0.0062799999 +-0.0381130017 0.0312799998 -0.0062799999 +-0.0381130017 0.0312799998 -0.0187199991 +-0.0381130017 0.0312799998 -0.0312799998 +-0.0381130017 0.0312799998 -0.0437199995 +-0.0381130017 0.0187199991 -0.0062799999 +-0.0381130017 0.0187199991 -0.0187199991 +-0.0381130017 0.0187199991 -0.0312799998 +-0.0381130017 0.0187199991 -0.0437199995 +-0.0381130017 0.0062799999 -0.0062799999 +-0.0381130017 0.0062799999 -0.0187199991 +-0.0381130017 0.0062799999 -0.0312799998 +-0.0381130017 0.0062799999 -0.0437199995 +-0.0381130017 -0.0062799999 0.0437199995 +-0.0381130017 -0.0062799999 0.0312799998 +-0.0381130017 -0.0062799999 0.0187199991 +-0.0381130017 -0.0062799999 0.0062799999 +-0.0381130017 -0.0062799999 -0.0062799999 +-0.0381130017 -0.0062799999 -0.0187199991 +-0.0381130017 -0.0062799999 -0.0312799998 +-0.0381130017 -0.0062799999 -0.0437199995 +-0.0381130017 -0.0187199991 0.0437199995 +-0.0381130017 -0.0187199991 0.0312799998 +-0.0381130017 -0.0187199991 0.0187199991 +-0.0381130017 -0.0187199991 0.0062799999 +-0.0381130017 -0.0187199991 -0.0062799999 +-0.0381130017 -0.0187199991 -0.0187199991 +-0.0381130017 -0.0187199991 -0.0312799998 +-0.0381130017 -0.0187199991 -0.0437199995 +-0.0381130017 -0.0312799998 0.0187199991 +-0.0381130017 -0.0312799998 0.0062799999 +-0.0381130017 -0.0312799998 -0.0062799999 +-0.0381130017 -0.0312799998 -0.0187199991 +-0.0381130017 -0.0312799998 -0.0312799998 +-0.0381130017 -0.0312799998 -0.0437199995 +-0.0381130017 -0.0437199995 0.0187199991 +-0.0381130017 -0.0437199995 0.0062799999 +-0.0381130017 -0.0437199995 -0.0062799999 +-0.0381130017 -0.0437199995 -0.0187199991 +-0.0381130017 -0.0437199995 -0.0312799998 +-0.0381130017 -0.0437199995 -0.0437199995 +-0.0382289998 0.0281610005 0.0437069982 +-0.0382289998 0.0281610005 0.0312930010 +-0.0382289998 0.0281610005 0.0187069997 +-0.0382289998 0.0281610005 0.0062930002 +-0.0387189984 0.0436300002 0.0436300002 +-0.0387189984 0.0436300002 0.0313699991 +-0.0387189984 0.0436300002 0.0186299998 +-0.0387189984 0.0436300002 0.0063700001 +-0.0387189984 0.0436300002 -0.0063700001 +-0.0387189984 0.0436300002 -0.0186299998 +-0.0387189984 0.0436300002 -0.0313699991 +-0.0387189984 0.0436300002 -0.0436300002 +-0.0387189984 0.0313699991 0.0436300002 +-0.0387189984 0.0313699991 0.0313699991 +-0.0387189984 0.0313699991 0.0186299998 +-0.0387189984 0.0313699991 0.0063700001 +-0.0387189984 0.0313699991 -0.0063700001 +-0.0387189984 0.0313699991 -0.0186299998 +-0.0387189984 0.0313699991 -0.0313699991 +-0.0387189984 0.0313699991 -0.0436300002 +-0.0387189984 0.0186299998 -0.0063700001 +-0.0387189984 0.0186299998 -0.0186299998 +-0.0387189984 0.0186299998 -0.0313699991 +-0.0387189984 0.0186299998 -0.0436300002 +-0.0387189984 0.0063700001 -0.0063700001 +-0.0387189984 0.0063700001 -0.0186299998 +-0.0387189984 0.0063700001 -0.0313699991 +-0.0387189984 0.0063700001 -0.0436300002 +-0.0387189984 -0.0063700001 0.0436300002 +-0.0387189984 -0.0063700001 0.0313699991 +-0.0387189984 -0.0063700001 0.0186299998 +-0.0387189984 -0.0063700001 0.0063700001 +-0.0387189984 -0.0063700001 -0.0063700001 +-0.0387189984 -0.0063700001 -0.0186299998 +-0.0387189984 -0.0063700001 -0.0313699991 +-0.0387189984 -0.0063700001 -0.0436300002 +-0.0387189984 -0.0186299998 0.0436300002 +-0.0387189984 -0.0186299998 0.0313699991 +-0.0387189984 -0.0186299998 0.0186299998 +-0.0387189984 -0.0186299998 0.0063700001 +-0.0387189984 -0.0186299998 -0.0063700001 +-0.0387189984 -0.0186299998 -0.0186299998 +-0.0387189984 -0.0186299998 -0.0313699991 +-0.0387189984 -0.0186299998 -0.0436300002 +-0.0387189984 -0.0313699991 0.0186299998 +-0.0387189984 -0.0313699991 0.0063700001 +-0.0387189984 -0.0313699991 -0.0063700001 +-0.0387189984 -0.0313699991 -0.0186299998 +-0.0387189984 -0.0313699991 -0.0313699991 +-0.0387189984 -0.0313699991 -0.0436300002 +-0.0387189984 -0.0436300002 0.0186299998 +-0.0387189984 -0.0436300002 0.0063700001 +-0.0387189984 -0.0436300002 -0.0063700001 +-0.0387189984 -0.0436300002 -0.0186299998 +-0.0387189984 -0.0436300002 -0.0313699991 +-0.0387189984 -0.0436300002 -0.0436300002 +-0.0388800018 0.0014730000 0.0435959995 +-0.0388800018 0.0014730000 0.0314039998 +-0.0388800018 0.0014730000 0.0185959991 +-0.0388800018 0.0014730000 0.0064039999 +-0.0391179994 0.0500000007 0.0435369983 +-0.0391179994 0.0500000007 0.0314630009 +-0.0391179994 0.0500000007 0.0185369998 +-0.0391179994 0.0500000007 0.0064630001 +-0.0391179994 0.0500000007 -0.0064630001 +-0.0391179994 0.0500000007 -0.0185369998 +-0.0391179994 0.0500000007 -0.0314630009 +-0.0391179994 0.0500000007 -0.0435369983 +-0.0391179994 0.0435369983 0.0500000007 +-0.0391179994 0.0435369983 -0.0500000007 +-0.0391179994 0.0314630009 0.0500000007 +-0.0391179994 0.0314630009 -0.0500000007 +-0.0391179994 0.0185369998 -0.0003910000 +-0.0391179994 0.0185369998 -0.0500000007 +-0.0391179994 0.0064630001 -0.0003910000 +-0.0391179994 0.0064630001 -0.0500000007 +-0.0391179994 -0.0064630001 0.0500000007 +-0.0391179994 -0.0064630001 -0.0500000007 +-0.0391179994 -0.0185369998 0.0500000007 +-0.0391179994 -0.0185369998 -0.0500000007 +-0.0391179994 -0.0250000004 0.0435369983 +-0.0391179994 -0.0250000004 0.0314630009 +-0.0391179994 -0.0314630009 0.0212500002 +-0.0391179994 -0.0314630009 -0.0500000007 +-0.0391179994 -0.0435369983 0.0212500002 +-0.0391179994 -0.0435369983 -0.0500000007 +-0.0391179994 -0.0500000007 0.0185369998 +-0.0391179994 -0.0500000007 0.0064630001 +-0.0391179994 -0.0500000007 -0.0064630001 +-0.0391179994 -0.0500000007 -0.0185369998 +-0.0391179994 -0.0500000007 -0.0314630009 +-0.0391179994 -0.0500000007 -0.0435369983 +-0.0393729992 0.0288210008 0.0434629992 +-0.0393729992 0.0288210008 0.0315370001 +-0.0393729992 0.0288210008 0.0184630007 +-0.0393729992 0.0288210008 0.0065370002 +-0.0398919992 0.0432740003 0.0432740003 +-0.0398919992 0.0432740003 0.0317259990 +-0.0398919992 0.0432740003 0.0182739999 +-0.0398919992 0.0432740003 0.0067260000 +-0.0398919992 0.0432740003 -0.0067260000 +-0.0398919992 0.0432740003 -0.0182739999 +-0.0398919992 0.0432740003 -0.0317259990 +-0.0398919992 0.0432740003 -0.0432740003 +-0.0398919992 0.0317259990 0.0432740003 +-0.0398919992 0.0317259990 0.0317259990 +-0.0398919992 0.0317259990 0.0182739999 +-0.0398919992 0.0317259990 0.0067260000 +-0.0398919992 0.0317259990 -0.0067260000 +-0.0398919992 0.0317259990 -0.0182739999 +-0.0398919992 0.0317259990 -0.0317259990 +-0.0398919992 0.0317259990 -0.0432740003 +-0.0398919992 0.0182739999 -0.0067260000 +-0.0398919992 0.0182739999 -0.0182739999 +-0.0398919992 0.0182739999 -0.0317259990 +-0.0398919992 0.0182739999 -0.0432740003 +-0.0398919992 0.0067260000 -0.0067260000 +-0.0398919992 0.0067260000 -0.0182739999 +-0.0398919992 0.0067260000 -0.0317259990 +-0.0398919992 0.0067260000 -0.0432740003 +-0.0398919992 -0.0067260000 0.0432740003 +-0.0398919992 -0.0067260000 0.0317259990 +-0.0398919992 -0.0067260000 0.0182739999 +-0.0398919992 -0.0067260000 0.0067260000 +-0.0398919992 -0.0067260000 -0.0067260000 +-0.0398919992 -0.0067260000 -0.0182739999 +-0.0398919992 -0.0067260000 -0.0317259990 +-0.0398919992 -0.0067260000 -0.0432740003 +-0.0398919992 -0.0182739999 0.0432740003 +-0.0398919992 -0.0182739999 0.0317259990 +-0.0398919992 -0.0182739999 0.0182739999 +-0.0398919992 -0.0182739999 0.0067260000 +-0.0398919992 -0.0182739999 -0.0067260000 +-0.0398919992 -0.0182739999 -0.0182739999 +-0.0398919992 -0.0182739999 -0.0317259990 +-0.0398919992 -0.0182739999 -0.0432740003 +-0.0398919992 -0.0317259990 0.0182739999 +-0.0398919992 -0.0317259990 0.0067260000 +-0.0398919992 -0.0317259990 -0.0067260000 +-0.0398919992 -0.0317259990 -0.0182739999 +-0.0398919992 -0.0317259990 -0.0317259990 +-0.0398919992 -0.0317259990 -0.0432740003 +-0.0398919992 -0.0432740003 0.0182739999 +-0.0398919992 -0.0432740003 0.0067260000 +-0.0398919992 -0.0432740003 -0.0067260000 +-0.0398919992 -0.0432740003 -0.0182739999 +-0.0398919992 -0.0432740003 -0.0317259990 +-0.0398919992 -0.0432740003 -0.0432740003 +-0.0400209986 0.0021319999 0.0432190001 +-0.0400209986 0.0021319999 0.0317809992 +-0.0400209986 0.0021319999 0.0182189997 +-0.0400209986 0.0021319999 0.0067810002 +-0.0404519998 0.0294439998 0.0430090018 +-0.0404519998 0.0294439998 0.0319910012 +-0.0404519998 0.0294439998 0.0180089995 +-0.0404519998 0.0294439998 0.0069909999 +-0.0406249985 0.0500000007 0.0429130010 +-0.0406249985 0.0500000007 0.0320869982 +-0.0406249985 0.0500000007 0.0179130007 +-0.0406249985 0.0500000007 0.0070870002 +-0.0406249985 0.0500000007 -0.0070870002 +-0.0406249985 0.0500000007 -0.0179130007 +-0.0406249985 0.0500000007 -0.0320869982 +-0.0406249985 0.0500000007 -0.0429130010 +-0.0406249985 0.0429130010 0.0500000007 +-0.0406249985 0.0429130010 -0.0500000007 +-0.0406249985 0.0320869982 0.0500000007 +-0.0406249985 0.0320869982 -0.0500000007 +-0.0406249985 0.0179130007 -0.0003910000 +-0.0406249985 0.0179130007 -0.0500000007 +-0.0406249985 0.0070870002 -0.0003910000 +-0.0406249985 0.0070870002 -0.0500000007 +-0.0406249985 -0.0070870002 0.0500000007 +-0.0406249985 -0.0070870002 -0.0500000007 +-0.0406249985 -0.0179130007 0.0500000007 +-0.0406249985 -0.0179130007 -0.0500000007 +-0.0406249985 -0.0250000004 0.0429130010 +-0.0406249985 -0.0250000004 0.0320869982 +-0.0406249985 -0.0320869982 0.0212500002 +-0.0406249985 -0.0320869982 -0.0500000007 +-0.0406249985 -0.0429130010 0.0212500002 +-0.0406249985 -0.0429130010 -0.0500000007 +-0.0406249985 -0.0500000007 0.0179130007 +-0.0406249985 -0.0500000007 0.0070870002 +-0.0406249985 -0.0500000007 -0.0070870002 +-0.0406249985 -0.0500000007 -0.0179130007 +-0.0406249985 -0.0500000007 -0.0320869982 +-0.0406249985 -0.0500000007 -0.0429130010 +-0.0409720019 0.0426970012 0.0426970012 +-0.0409720019 0.0426970012 0.0323030017 +-0.0409720019 0.0426970012 0.0176970009 +-0.0409720019 0.0426970012 0.0073030000 +-0.0409720019 0.0426970012 -0.0073030000 +-0.0409720019 0.0426970012 -0.0176970009 +-0.0409720019 0.0426970012 -0.0323030017 +-0.0409720019 0.0426970012 -0.0426970012 +-0.0409720019 0.0323030017 0.0426970012 +-0.0409720019 0.0323030017 0.0323030017 +-0.0409720019 0.0323030017 0.0176970009 +-0.0409720019 0.0323030017 0.0073030000 +-0.0409720019 0.0323030017 -0.0073030000 +-0.0409720019 0.0323030017 -0.0176970009 +-0.0409720019 0.0323030017 -0.0323030017 +-0.0409720019 0.0323030017 -0.0426970012 +-0.0409720019 0.0176970009 -0.0073030000 +-0.0409720019 0.0176970009 -0.0176970009 +-0.0409720019 0.0176970009 -0.0323030017 +-0.0409720019 0.0176970009 -0.0426970012 +-0.0409720019 0.0073030000 -0.0073030000 +-0.0409720019 0.0073030000 -0.0176970009 +-0.0409720019 0.0073030000 -0.0323030017 +-0.0409720019 0.0073030000 -0.0426970012 +-0.0409720019 -0.0073030000 0.0426970012 +-0.0409720019 -0.0073030000 0.0323030017 +-0.0409720019 -0.0073030000 0.0176970009 +-0.0409720019 -0.0073030000 0.0073030000 +-0.0409720019 -0.0073030000 -0.0073030000 +-0.0409720019 -0.0073030000 -0.0176970009 +-0.0409720019 -0.0073030000 -0.0323030017 +-0.0409720019 -0.0073030000 -0.0426970012 +-0.0409720019 -0.0176970009 0.0426970012 +-0.0409720019 -0.0176970009 0.0323030017 +-0.0409720019 -0.0176970009 0.0176970009 +-0.0409720019 -0.0176970009 0.0073030000 +-0.0409720019 -0.0176970009 -0.0073030000 +-0.0409720019 -0.0176970009 -0.0176970009 +-0.0409720019 -0.0176970009 -0.0323030017 +-0.0409720019 -0.0176970009 -0.0426970012 +-0.0409720019 -0.0323030017 0.0176970009 +-0.0409720019 -0.0323030017 0.0073030000 +-0.0409720019 -0.0323030017 -0.0073030000 +-0.0409720019 -0.0323030017 -0.0176970009 +-0.0409720019 -0.0323030017 -0.0323030017 +-0.0409720019 -0.0323030017 -0.0426970012 +-0.0409720019 -0.0426970012 0.0176970009 +-0.0409720019 -0.0426970012 0.0073030000 +-0.0409720019 -0.0426970012 -0.0073030000 +-0.0409720019 -0.0426970012 -0.0176970009 +-0.0409720019 -0.0426970012 -0.0323030017 +-0.0409720019 -0.0426970012 -0.0426970012 +-0.0410690010 0.0027369999 0.0426310003 +-0.0410690010 0.0027369999 0.0323689990 +-0.0410690010 0.0027369999 0.0176309999 +-0.0410690010 0.0027369999 0.0073690000 +-0.0414270014 0.0300069991 0.0423620008 +-0.0414270014 0.0300069991 0.0326379985 +-0.0414270014 0.0300069991 0.0173620004 +-0.0414270014 0.0300069991 0.0076380000 +-0.0419190004 0.0500000007 0.0419190004 +-0.0419190004 0.0500000007 0.0330809988 +-0.0419190004 0.0500000007 0.0169190001 +-0.0419190004 0.0500000007 0.0080810003 +-0.0419190004 0.0500000007 -0.0080810003 +-0.0419190004 0.0500000007 -0.0169190001 +-0.0419190004 0.0500000007 -0.0330809988 +-0.0419190004 0.0500000007 -0.0419190004 +-0.0419190004 0.0419190004 0.0500000007 +-0.0419190004 0.0419190004 0.0419190004 +-0.0419190004 0.0419190004 0.0330809988 +-0.0419190004 0.0419190004 0.0169190001 +-0.0419190004 0.0419190004 0.0080810003 +-0.0419190004 0.0419190004 -0.0080810003 +-0.0419190004 0.0419190004 -0.0169190001 +-0.0419190004 0.0419190004 -0.0330809988 +-0.0419190004 0.0419190004 -0.0419190004 +-0.0419190004 0.0419190004 -0.0500000007 +-0.0419190004 0.0330809988 0.0500000007 +-0.0419190004 0.0330809988 0.0419190004 +-0.0419190004 0.0330809988 0.0330809988 +-0.0419190004 0.0330809988 0.0169190001 +-0.0419190004 0.0330809988 0.0080810003 +-0.0419190004 0.0330809988 -0.0080810003 +-0.0419190004 0.0330809988 -0.0169190001 +-0.0419190004 0.0330809988 -0.0330809988 +-0.0419190004 0.0330809988 -0.0419190004 +-0.0419190004 0.0330809988 -0.0500000007 +-0.0419190004 0.0169190001 -0.0003910000 +-0.0419190004 0.0169190001 -0.0080810003 +-0.0419190004 0.0169190001 -0.0169190001 +-0.0419190004 0.0169190001 -0.0330809988 +-0.0419190004 0.0169190001 -0.0419190004 +-0.0419190004 0.0169190001 -0.0500000007 +-0.0419190004 0.0080810003 -0.0003910000 +-0.0419190004 0.0080810003 -0.0080810003 +-0.0419190004 0.0080810003 -0.0169190001 +-0.0419190004 0.0080810003 -0.0330809988 +-0.0419190004 0.0080810003 -0.0419190004 +-0.0419190004 0.0080810003 -0.0500000007 +-0.0419190004 -0.0080810003 0.0500000007 +-0.0419190004 -0.0080810003 0.0419190004 +-0.0419190004 -0.0080810003 0.0330809988 +-0.0419190004 -0.0080810003 0.0169190001 +-0.0419190004 -0.0080810003 0.0080810003 +-0.0419190004 -0.0080810003 -0.0080810003 +-0.0419190004 -0.0080810003 -0.0169190001 +-0.0419190004 -0.0080810003 -0.0330809988 +-0.0419190004 -0.0080810003 -0.0419190004 +-0.0419190004 -0.0080810003 -0.0500000007 +-0.0419190004 -0.0169190001 0.0500000007 +-0.0419190004 -0.0169190001 0.0419190004 +-0.0419190004 -0.0169190001 0.0330809988 +-0.0419190004 -0.0169190001 0.0169190001 +-0.0419190004 -0.0169190001 0.0080810003 +-0.0419190004 -0.0169190001 -0.0080810003 +-0.0419190004 -0.0169190001 -0.0169190001 +-0.0419190004 -0.0169190001 -0.0330809988 +-0.0419190004 -0.0169190001 -0.0419190004 +-0.0419190004 -0.0169190001 -0.0500000007 +-0.0419190004 -0.0250000004 0.0419190004 +-0.0419190004 -0.0250000004 0.0330809988 +-0.0419190004 -0.0330809988 0.0212500002 +-0.0419190004 -0.0330809988 0.0169190001 +-0.0419190004 -0.0330809988 0.0080810003 +-0.0419190004 -0.0330809988 -0.0080810003 +-0.0419190004 -0.0330809988 -0.0169190001 +-0.0419190004 -0.0330809988 -0.0330809988 +-0.0419190004 -0.0330809988 -0.0419190004 +-0.0419190004 -0.0330809988 -0.0500000007 +-0.0419190004 -0.0419190004 0.0212500002 +-0.0419190004 -0.0419190004 0.0169190001 +-0.0419190004 -0.0419190004 0.0080810003 +-0.0419190004 -0.0419190004 -0.0080810003 +-0.0419190004 -0.0419190004 -0.0169190001 +-0.0419190004 -0.0419190004 -0.0330809988 +-0.0419190004 -0.0419190004 -0.0419190004 +-0.0419190004 -0.0419190004 -0.0500000007 +-0.0419190004 -0.0500000007 0.0169190001 +-0.0419190004 -0.0500000007 0.0080810003 +-0.0419190004 -0.0500000007 -0.0080810003 +-0.0419190004 -0.0500000007 -0.0169190001 +-0.0419190004 -0.0500000007 -0.0330809988 +-0.0419190004 -0.0500000007 -0.0419190004 +-0.0419850014 0.0032660000 0.0418529995 +-0.0419850014 0.0032660000 0.0331469998 +-0.0419850014 0.0032660000 0.0168529991 +-0.0419850014 0.0032660000 0.0081470003 +-0.0422650017 0.0304910000 0.0415449999 +-0.0422650017 0.0304910000 0.0334549993 +-0.0422650017 0.0304910000 0.0165449996 +-0.0422650017 0.0304910000 0.0084549999 +-0.0425710008 0.0324289985 0.0411540009 +-0.0425710008 0.0324289985 0.0338459983 +-0.0425710008 0.0324289985 0.0161540005 +-0.0425710008 0.0324289985 0.0088459998 +-0.0426970012 0.0426970012 0.0409720019 +-0.0426970012 0.0426970012 0.0340280011 +-0.0426970012 0.0426970012 0.0159719996 +-0.0426970012 0.0426970012 0.0090279998 +-0.0426970012 0.0426970012 -0.0090279998 +-0.0426970012 0.0426970012 -0.0159719996 +-0.0426970012 0.0426970012 -0.0340280011 +-0.0426970012 0.0426970012 -0.0409720019 +-0.0426970012 0.0409720019 0.0426970012 +-0.0426970012 0.0409720019 0.0323030017 +-0.0426970012 0.0409720019 0.0176970009 +-0.0426970012 0.0409720019 0.0073030000 +-0.0426970012 0.0409720019 -0.0073030000 +-0.0426970012 0.0409720019 -0.0176970009 +-0.0426970012 0.0409720019 -0.0323030017 +-0.0426970012 0.0409720019 -0.0426970012 +-0.0426970012 0.0340280011 0.0426970012 +-0.0426970012 0.0340280011 0.0323030017 +-0.0426970012 0.0340280011 0.0176970009 +-0.0426970012 0.0340280011 0.0073030000 +-0.0426970012 0.0340280011 -0.0073030000 +-0.0426970012 0.0340280011 -0.0176970009 +-0.0426970012 0.0340280011 -0.0323030017 +-0.0426970012 0.0340280011 -0.0426970012 +-0.0426970012 0.0323030017 -0.0090279998 +-0.0426970012 0.0323030017 -0.0159719996 +-0.0426970012 0.0323030017 -0.0340280011 +-0.0426970012 0.0323030017 -0.0409720019 +-0.0426970012 0.0176970009 -0.0090279998 +-0.0426970012 0.0176970009 -0.0159719996 +-0.0426970012 0.0176970009 -0.0340280011 +-0.0426970012 0.0176970009 -0.0409720019 +-0.0426970012 0.0159719996 -0.0073030000 +-0.0426970012 0.0159719996 -0.0176970009 +-0.0426970012 0.0159719996 -0.0323030017 +-0.0426970012 0.0159719996 -0.0426970012 +-0.0426970012 0.0090279998 -0.0073030000 +-0.0426970012 0.0090279998 -0.0176970009 +-0.0426970012 0.0090279998 -0.0323030017 +-0.0426970012 0.0090279998 -0.0426970012 +-0.0426970012 0.0073030000 -0.0090279998 +-0.0426970012 0.0073030000 -0.0159719996 +-0.0426970012 0.0073030000 -0.0340280011 +-0.0426970012 0.0073030000 -0.0409720019 +-0.0426970012 -0.0073030000 0.0409720019 +-0.0426970012 -0.0073030000 0.0340280011 +-0.0426970012 -0.0073030000 0.0159719996 +-0.0426970012 -0.0073030000 0.0090279998 +-0.0426970012 -0.0073030000 -0.0090279998 +-0.0426970012 -0.0073030000 -0.0159719996 +-0.0426970012 -0.0073030000 -0.0340280011 +-0.0426970012 -0.0073030000 -0.0409720019 +-0.0426970012 -0.0090279998 0.0426970012 +-0.0426970012 -0.0090279998 0.0323030017 +-0.0426970012 -0.0090279998 0.0176970009 +-0.0426970012 -0.0090279998 0.0073030000 +-0.0426970012 -0.0090279998 -0.0073030000 +-0.0426970012 -0.0090279998 -0.0176970009 +-0.0426970012 -0.0090279998 -0.0323030017 +-0.0426970012 -0.0090279998 -0.0426970012 +-0.0426970012 -0.0159719996 0.0426970012 +-0.0426970012 -0.0159719996 0.0323030017 +-0.0426970012 -0.0159719996 0.0176970009 +-0.0426970012 -0.0159719996 0.0073030000 +-0.0426970012 -0.0159719996 -0.0073030000 +-0.0426970012 -0.0159719996 -0.0176970009 +-0.0426970012 -0.0159719996 -0.0323030017 +-0.0426970012 -0.0159719996 -0.0426970012 +-0.0426970012 -0.0176970009 0.0409720019 +-0.0426970012 -0.0176970009 0.0340280011 +-0.0426970012 -0.0176970009 0.0159719996 +-0.0426970012 -0.0176970009 0.0090279998 +-0.0426970012 -0.0176970009 -0.0090279998 +-0.0426970012 -0.0176970009 -0.0159719996 +-0.0426970012 -0.0176970009 -0.0340280011 +-0.0426970012 -0.0176970009 -0.0409720019 +-0.0426970012 -0.0323030017 0.0159719996 +-0.0426970012 -0.0323030017 0.0090279998 +-0.0426970012 -0.0323030017 -0.0090279998 +-0.0426970012 -0.0323030017 -0.0159719996 +-0.0426970012 -0.0323030017 -0.0340280011 +-0.0426970012 -0.0323030017 -0.0409720019 +-0.0426970012 -0.0340280011 0.0176970009 +-0.0426970012 -0.0340280011 0.0073030000 +-0.0426970012 -0.0340280011 -0.0073030000 +-0.0426970012 -0.0340280011 -0.0176970009 +-0.0426970012 -0.0340280011 -0.0323030017 +-0.0426970012 -0.0340280011 -0.0426970012 +-0.0426970012 -0.0409720019 0.0176970009 +-0.0426970012 -0.0409720019 0.0073030000 +-0.0426970012 -0.0409720019 -0.0073030000 +-0.0426970012 -0.0409720019 -0.0176970009 +-0.0426970012 -0.0409720019 -0.0323030017 +-0.0426970012 -0.0409720019 -0.0426970012 +-0.0426970012 -0.0426970012 0.0159719996 +-0.0426970012 -0.0426970012 0.0090279998 +-0.0426970012 -0.0426970012 -0.0090279998 +-0.0426970012 -0.0426970012 -0.0159719996 +-0.0426970012 -0.0426970012 -0.0340280011 +-0.0426970012 -0.0426970012 -0.0409720019 +-0.0427349992 0.0036990000 0.0409139991 +-0.0427349992 0.0036990000 0.0340860002 +-0.0427349992 0.0036990000 0.0159140006 +-0.0427349992 0.0036990000 0.0090859998 +-0.0429130010 0.0500000007 0.0406249985 +-0.0429130010 0.0500000007 0.0343750007 +-0.0429130010 0.0500000007 0.0156250000 +-0.0429130010 0.0500000007 0.0093750004 +-0.0429130010 0.0500000007 -0.0093750004 +-0.0429130010 0.0500000007 -0.0156250000 +-0.0429130010 0.0500000007 -0.0343750007 +-0.0429130010 0.0500000007 -0.0406249985 +-0.0429130010 0.0406249985 0.0500000007 +-0.0429130010 0.0406249985 -0.0500000007 +-0.0429130010 0.0343750007 0.0500000007 +-0.0429130010 0.0343750007 -0.0500000007 +-0.0429130010 0.0156250000 -0.0003910000 +-0.0429130010 0.0156250000 -0.0500000007 +-0.0429130010 0.0093750004 -0.0003910000 +-0.0429130010 0.0093750004 -0.0500000007 +-0.0429130010 -0.0093750004 0.0500000007 +-0.0429130010 -0.0093750004 -0.0500000007 +-0.0429130010 -0.0156250000 0.0500000007 +-0.0429130010 -0.0156250000 -0.0500000007 +-0.0429130010 -0.0250000004 0.0406249985 +-0.0429130010 -0.0250000004 0.0343750007 +-0.0429130010 -0.0343750007 0.0212500002 +-0.0429130010 -0.0343750007 -0.0500000007 +-0.0429130010 -0.0406249985 0.0212500002 +-0.0429130010 -0.0406249985 -0.0500000007 +-0.0429130010 -0.0500000007 0.0156250000 +-0.0429130010 -0.0500000007 0.0093750004 +-0.0429130010 -0.0500000007 -0.0093750004 +-0.0429130010 -0.0500000007 -0.0156250000 +-0.0429130010 -0.0500000007 -0.0343750007 +-0.0429130010 -0.0500000007 -0.0406249985 +-0.0429349989 0.0308780000 0.0405859984 +-0.0429349989 0.0308780000 0.0344140008 +-0.0429349989 0.0308780000 0.0155859999 +-0.0429349989 0.0308780000 0.0094140004 +-0.0430909991 0.0319090001 0.0402939990 +-0.0430909991 0.0319090001 0.0347060002 +-0.0430909991 0.0319090001 0.0152939996 +-0.0430909991 0.0319090001 0.0097059999 +-0.0432740003 0.0432740003 0.0398919992 +-0.0432740003 0.0432740003 0.0351080000 +-0.0432740003 0.0432740003 0.0148919998 +-0.0432740003 0.0432740003 0.0101079997 +-0.0432740003 0.0432740003 -0.0101079997 +-0.0432740003 0.0432740003 -0.0148919998 +-0.0432740003 0.0432740003 -0.0351080000 +-0.0432740003 0.0432740003 -0.0398919992 +-0.0432740003 0.0398919992 0.0432740003 +-0.0432740003 0.0398919992 0.0317259990 +-0.0432740003 0.0398919992 0.0182739999 +-0.0432740003 0.0398919992 0.0067260000 +-0.0432740003 0.0398919992 -0.0067260000 +-0.0432740003 0.0398919992 -0.0182739999 +-0.0432740003 0.0398919992 -0.0317259990 +-0.0432740003 0.0398919992 -0.0432740003 +-0.0432740003 0.0351080000 0.0432740003 +-0.0432740003 0.0351080000 0.0317259990 +-0.0432740003 0.0351080000 0.0182739999 +-0.0432740003 0.0351080000 0.0067260000 +-0.0432740003 0.0351080000 -0.0067260000 +-0.0432740003 0.0351080000 -0.0182739999 +-0.0432740003 0.0351080000 -0.0317259990 +-0.0432740003 0.0351080000 -0.0432740003 +-0.0432740003 0.0317259990 -0.0101079997 +-0.0432740003 0.0317259990 -0.0148919998 +-0.0432740003 0.0317259990 -0.0351080000 +-0.0432740003 0.0317259990 -0.0398919992 +-0.0432740003 0.0182739999 -0.0101079997 +-0.0432740003 0.0182739999 -0.0148919998 +-0.0432740003 0.0182739999 -0.0351080000 +-0.0432740003 0.0182739999 -0.0398919992 +-0.0432740003 0.0148919998 -0.0067260000 +-0.0432740003 0.0148919998 -0.0182739999 +-0.0432740003 0.0148919998 -0.0317259990 +-0.0432740003 0.0148919998 -0.0432740003 +-0.0432740003 0.0101079997 -0.0067260000 +-0.0432740003 0.0101079997 -0.0182739999 +-0.0432740003 0.0101079997 -0.0317259990 +-0.0432740003 0.0101079997 -0.0432740003 +-0.0432740003 0.0067260000 -0.0101079997 +-0.0432740003 0.0067260000 -0.0148919998 +-0.0432740003 0.0067260000 -0.0351080000 +-0.0432740003 0.0067260000 -0.0398919992 +-0.0432740003 -0.0067260000 0.0398919992 +-0.0432740003 -0.0067260000 0.0351080000 +-0.0432740003 -0.0067260000 0.0148919998 +-0.0432740003 -0.0067260000 0.0101079997 +-0.0432740003 -0.0067260000 -0.0101079997 +-0.0432740003 -0.0067260000 -0.0148919998 +-0.0432740003 -0.0067260000 -0.0351080000 +-0.0432740003 -0.0067260000 -0.0398919992 +-0.0432740003 -0.0101079997 0.0432740003 +-0.0432740003 -0.0101079997 0.0317259990 +-0.0432740003 -0.0101079997 0.0182739999 +-0.0432740003 -0.0101079997 0.0067260000 +-0.0432740003 -0.0101079997 -0.0067260000 +-0.0432740003 -0.0101079997 -0.0182739999 +-0.0432740003 -0.0101079997 -0.0317259990 +-0.0432740003 -0.0101079997 -0.0432740003 +-0.0432740003 -0.0148919998 0.0432740003 +-0.0432740003 -0.0148919998 0.0317259990 +-0.0432740003 -0.0148919998 0.0182739999 +-0.0432740003 -0.0148919998 0.0067260000 +-0.0432740003 -0.0148919998 -0.0067260000 +-0.0432740003 -0.0148919998 -0.0182739999 +-0.0432740003 -0.0148919998 -0.0317259990 +-0.0432740003 -0.0148919998 -0.0432740003 +-0.0432740003 -0.0182739999 0.0398919992 +-0.0432740003 -0.0182739999 0.0351080000 +-0.0432740003 -0.0182739999 0.0148919998 +-0.0432740003 -0.0182739999 0.0101079997 +-0.0432740003 -0.0182739999 -0.0101079997 +-0.0432740003 -0.0182739999 -0.0148919998 +-0.0432740003 -0.0182739999 -0.0351080000 +-0.0432740003 -0.0182739999 -0.0398919992 +-0.0432740003 -0.0317259990 0.0148919998 +-0.0432740003 -0.0317259990 0.0101079997 +-0.0432740003 -0.0317259990 -0.0101079997 +-0.0432740003 -0.0317259990 -0.0148919998 +-0.0432740003 -0.0317259990 -0.0351080000 +-0.0432740003 -0.0317259990 -0.0398919992 +-0.0432740003 -0.0351080000 0.0182739999 +-0.0432740003 -0.0351080000 0.0067260000 +-0.0432740003 -0.0351080000 -0.0067260000 +-0.0432740003 -0.0351080000 -0.0182739999 +-0.0432740003 -0.0351080000 -0.0317259990 +-0.0432740003 -0.0351080000 -0.0432740003 +-0.0432740003 -0.0398919992 0.0182739999 +-0.0432740003 -0.0398919992 0.0067260000 +-0.0432740003 -0.0398919992 -0.0067260000 +-0.0432740003 -0.0398919992 -0.0182739999 +-0.0432740003 -0.0398919992 -0.0317259990 +-0.0432740003 -0.0398919992 -0.0432740003 +-0.0432740003 -0.0432740003 0.0148919998 +-0.0432740003 -0.0432740003 0.0101079997 +-0.0432740003 -0.0432740003 -0.0101079997 +-0.0432740003 -0.0432740003 -0.0148919998 +-0.0432740003 -0.0432740003 -0.0351080000 +-0.0432740003 -0.0432740003 -0.0398919992 +-0.0432920009 0.0040210001 0.0398479998 +-0.0432920009 0.0040210001 0.0351519994 +-0.0432920009 0.0040210001 0.0148480004 +-0.0432920009 0.0040210001 0.0101520000 +-0.0434149988 0.0311549995 0.0395190008 +-0.0434149988 0.0311549995 0.0354809985 +-0.0434149988 0.0311549995 0.0145190004 +-0.0434149988 0.0311549995 0.0104809999 +-0.0434660017 0.0315340012 0.0393610001 +-0.0434660017 0.0315340012 0.0356389992 +-0.0434660017 0.0315340012 0.0143609997 +-0.0434660017 0.0315340012 0.0106389998 +-0.0435369983 0.0500000007 0.0391179994 +-0.0435369983 0.0500000007 0.0358819999 +-0.0435369983 0.0500000007 0.0141179999 +-0.0435369983 0.0500000007 0.0108820004 +-0.0435369983 0.0500000007 -0.0108820004 +-0.0435369983 0.0500000007 -0.0141179999 +-0.0435369983 0.0500000007 -0.0358819999 +-0.0435369983 0.0500000007 -0.0391179994 +-0.0435369983 0.0391179994 0.0500000007 +-0.0435369983 0.0391179994 -0.0500000007 +-0.0435369983 0.0358819999 0.0500000007 +-0.0435369983 0.0358819999 -0.0500000007 +-0.0435369983 0.0141179999 -0.0003910000 +-0.0435369983 0.0141179999 -0.0500000007 +-0.0435369983 0.0108820004 -0.0003910000 +-0.0435369983 0.0108820004 -0.0500000007 +-0.0435369983 -0.0108820004 0.0500000007 +-0.0435369983 -0.0108820004 -0.0500000007 +-0.0435369983 -0.0141179999 0.0500000007 +-0.0435369983 -0.0141179999 -0.0500000007 +-0.0435369983 -0.0250000004 0.0391179994 +-0.0435369983 -0.0250000004 0.0358819999 +-0.0435369983 -0.0358819999 0.0212500002 +-0.0435369983 -0.0358819999 -0.0500000007 +-0.0435369983 -0.0391179994 0.0212500002 +-0.0435369983 -0.0391179994 -0.0500000007 +-0.0435369983 -0.0500000007 0.0141179999 +-0.0435369983 -0.0500000007 0.0108820004 +-0.0435369983 -0.0500000007 -0.0108820004 +-0.0435369983 -0.0500000007 -0.0141179999 +-0.0435369983 -0.0500000007 -0.0358819999 +-0.0435369983 -0.0500000007 -0.0391179994 +-0.0436300002 0.0436300002 0.0387189984 +-0.0436300002 0.0436300002 0.0362810008 +-0.0436300002 0.0436300002 0.0137189999 +-0.0436300002 0.0436300002 0.0112810005 +-0.0436300002 0.0436300002 -0.0112810005 +-0.0436300002 0.0436300002 -0.0137189999 +-0.0436300002 0.0436300002 -0.0362810008 +-0.0436300002 0.0436300002 -0.0387189984 +-0.0436300002 0.0387189984 0.0436300002 +-0.0436300002 0.0387189984 0.0313699991 +-0.0436300002 0.0387189984 0.0186299998 +-0.0436300002 0.0387189984 0.0063700001 +-0.0436300002 0.0387189984 -0.0063700001 +-0.0436300002 0.0387189984 -0.0186299998 +-0.0436300002 0.0387189984 -0.0313699991 +-0.0436300002 0.0387189984 -0.0436300002 +-0.0436300002 0.0362810008 0.0436300002 +-0.0436300002 0.0362810008 0.0313699991 +-0.0436300002 0.0362810008 0.0186299998 +-0.0436300002 0.0362810008 0.0063700001 +-0.0436300002 0.0362810008 -0.0063700001 +-0.0436300002 0.0362810008 -0.0186299998 +-0.0436300002 0.0362810008 -0.0313699991 +-0.0436300002 0.0362810008 -0.0436300002 +-0.0436300002 0.0313699991 -0.0112810005 +-0.0436300002 0.0313699991 -0.0137189999 +-0.0436300002 0.0313699991 -0.0362810008 +-0.0436300002 0.0313699991 -0.0387189984 +-0.0436300002 0.0186299998 -0.0112810005 +-0.0436300002 0.0186299998 -0.0137189999 +-0.0436300002 0.0186299998 -0.0362810008 +-0.0436300002 0.0186299998 -0.0387189984 +-0.0436300002 0.0137189999 -0.0063700001 +-0.0436300002 0.0137189999 -0.0186299998 +-0.0436300002 0.0137189999 -0.0313699991 +-0.0436300002 0.0137189999 -0.0436300002 +-0.0436300002 0.0112810005 -0.0063700001 +-0.0436300002 0.0112810005 -0.0186299998 +-0.0436300002 0.0112810005 -0.0313699991 +-0.0436300002 0.0112810005 -0.0436300002 +-0.0436300002 0.0063700001 -0.0112810005 +-0.0436300002 0.0063700001 -0.0137189999 +-0.0436300002 0.0063700001 -0.0362810008 +-0.0436300002 0.0063700001 -0.0387189984 +-0.0436300002 -0.0063700001 0.0387189984 +-0.0436300002 -0.0063700001 0.0362810008 +-0.0436300002 -0.0063700001 0.0137189999 +-0.0436300002 -0.0063700001 0.0112810005 +-0.0436300002 -0.0063700001 -0.0112810005 +-0.0436300002 -0.0063700001 -0.0137189999 +-0.0436300002 -0.0063700001 -0.0362810008 +-0.0436300002 -0.0063700001 -0.0387189984 +-0.0436300002 -0.0112810005 0.0436300002 +-0.0436300002 -0.0112810005 0.0313699991 +-0.0436300002 -0.0112810005 0.0186299998 +-0.0436300002 -0.0112810005 0.0063700001 +-0.0436300002 -0.0112810005 -0.0063700001 +-0.0436300002 -0.0112810005 -0.0186299998 +-0.0436300002 -0.0112810005 -0.0313699991 +-0.0436300002 -0.0112810005 -0.0436300002 +-0.0436300002 -0.0137189999 0.0436300002 +-0.0436300002 -0.0137189999 0.0313699991 +-0.0436300002 -0.0137189999 0.0186299998 +-0.0436300002 -0.0137189999 0.0063700001 +-0.0436300002 -0.0137189999 -0.0063700001 +-0.0436300002 -0.0137189999 -0.0186299998 +-0.0436300002 -0.0137189999 -0.0313699991 +-0.0436300002 -0.0137189999 -0.0436300002 +-0.0436300002 -0.0186299998 0.0387189984 +-0.0436300002 -0.0186299998 0.0362810008 +-0.0436300002 -0.0186299998 0.0137189999 +-0.0436300002 -0.0186299998 0.0112810005 +-0.0436300002 -0.0186299998 -0.0112810005 +-0.0436300002 -0.0186299998 -0.0137189999 +-0.0436300002 -0.0186299998 -0.0362810008 +-0.0436300002 -0.0186299998 -0.0387189984 +-0.0436300002 -0.0313699991 0.0137189999 +-0.0436300002 -0.0313699991 0.0112810005 +-0.0436300002 -0.0313699991 -0.0112810005 +-0.0436300002 -0.0313699991 -0.0137189999 +-0.0436300002 -0.0313699991 -0.0362810008 +-0.0436300002 -0.0313699991 -0.0387189984 +-0.0436300002 -0.0362810008 0.0186299998 +-0.0436300002 -0.0362810008 0.0063700001 +-0.0436300002 -0.0362810008 -0.0063700001 +-0.0436300002 -0.0362810008 -0.0186299998 +-0.0436300002 -0.0362810008 -0.0313699991 +-0.0436300002 -0.0362810008 -0.0436300002 +-0.0436300002 -0.0387189984 0.0186299998 +-0.0436300002 -0.0387189984 0.0063700001 +-0.0436300002 -0.0387189984 -0.0063700001 +-0.0436300002 -0.0387189984 -0.0186299998 +-0.0436300002 -0.0387189984 -0.0313699991 +-0.0436300002 -0.0387189984 -0.0436300002 +-0.0436300002 -0.0436300002 0.0137189999 +-0.0436300002 -0.0436300002 0.0112810005 +-0.0436300002 -0.0436300002 -0.0112810005 +-0.0436300002 -0.0436300002 -0.0137189999 +-0.0436300002 -0.0436300002 -0.0362810008 +-0.0436300002 -0.0436300002 -0.0387189984 +-0.0436340012 0.0042180000 0.0386959985 +-0.0436340012 0.0042180000 0.0363040008 +-0.0436340012 0.0042180000 0.0136960000 +-0.0436340012 0.0042180000 0.0113040004 +-0.0436879992 0.0313120000 0.0383800007 +-0.0436879992 0.0313120000 0.0366199985 +-0.0436879992 0.0313120000 0.0133800004 +-0.0436879992 0.0313120000 0.0116200000 +-0.0437199995 0.0437199995 0.0381130017 +-0.0437199995 0.0437199995 0.0368870012 +-0.0437199995 0.0437199995 0.0131130004 +-0.0437199995 0.0437199995 0.0118869999 +-0.0437199995 0.0437199995 -0.0118869999 +-0.0437199995 0.0437199995 -0.0131130004 +-0.0437199995 0.0437199995 -0.0368870012 +-0.0437199995 0.0437199995 -0.0381130017 +-0.0437199995 0.0381130017 0.0437199995 +-0.0437199995 0.0381130017 0.0312799998 +-0.0437199995 0.0381130017 0.0187199991 +-0.0437199995 0.0381130017 0.0062799999 +-0.0437199995 0.0381130017 -0.0062799999 +-0.0437199995 0.0381130017 -0.0187199991 +-0.0437199995 0.0381130017 -0.0312799998 +-0.0437199995 0.0381130017 -0.0437199995 +-0.0437199995 0.0368870012 0.0437199995 +-0.0437199995 0.0368870012 0.0312799998 +-0.0437199995 0.0368870012 0.0187199991 +-0.0437199995 0.0368870012 0.0062799999 +-0.0437199995 0.0368870012 -0.0062799999 +-0.0437199995 0.0368870012 -0.0187199991 +-0.0437199995 0.0368870012 -0.0312799998 +-0.0437199995 0.0368870012 -0.0437199995 +-0.0437199995 0.0312799998 -0.0118869999 +-0.0437199995 0.0312799998 -0.0131130004 +-0.0437199995 0.0312799998 -0.0368870012 +-0.0437199995 0.0312799998 -0.0381130017 +-0.0437199995 0.0187199991 -0.0118869999 +-0.0437199995 0.0187199991 -0.0131130004 +-0.0437199995 0.0187199991 -0.0368870012 +-0.0437199995 0.0187199991 -0.0381130017 +-0.0437199995 0.0131130004 -0.0062799999 +-0.0437199995 0.0131130004 -0.0187199991 +-0.0437199995 0.0131130004 -0.0312799998 +-0.0437199995 0.0131130004 -0.0437199995 +-0.0437199995 0.0118869999 -0.0062799999 +-0.0437199995 0.0118869999 -0.0187199991 +-0.0437199995 0.0118869999 -0.0312799998 +-0.0437199995 0.0118869999 -0.0437199995 +-0.0437199995 0.0062799999 -0.0118869999 +-0.0437199995 0.0062799999 -0.0131130004 +-0.0437199995 0.0062799999 -0.0368870012 +-0.0437199995 0.0062799999 -0.0381130017 +-0.0437199995 -0.0062799999 0.0381130017 +-0.0437199995 -0.0062799999 0.0368870012 +-0.0437199995 -0.0062799999 0.0131130004 +-0.0437199995 -0.0062799999 0.0118869999 +-0.0437199995 -0.0062799999 -0.0118869999 +-0.0437199995 -0.0062799999 -0.0131130004 +-0.0437199995 -0.0062799999 -0.0368870012 +-0.0437199995 -0.0062799999 -0.0381130017 +-0.0437199995 -0.0118869999 0.0437199995 +-0.0437199995 -0.0118869999 0.0312799998 +-0.0437199995 -0.0118869999 0.0187199991 +-0.0437199995 -0.0118869999 0.0062799999 +-0.0437199995 -0.0118869999 -0.0062799999 +-0.0437199995 -0.0118869999 -0.0187199991 +-0.0437199995 -0.0118869999 -0.0312799998 +-0.0437199995 -0.0118869999 -0.0437199995 +-0.0437199995 -0.0131130004 0.0437199995 +-0.0437199995 -0.0131130004 0.0312799998 +-0.0437199995 -0.0131130004 0.0187199991 +-0.0437199995 -0.0131130004 0.0062799999 +-0.0437199995 -0.0131130004 -0.0062799999 +-0.0437199995 -0.0131130004 -0.0187199991 +-0.0437199995 -0.0131130004 -0.0312799998 +-0.0437199995 -0.0131130004 -0.0437199995 +-0.0437199995 -0.0187199991 0.0381130017 +-0.0437199995 -0.0187199991 0.0368870012 +-0.0437199995 -0.0187199991 0.0131130004 +-0.0437199995 -0.0187199991 0.0118869999 +-0.0437199995 -0.0187199991 -0.0118869999 +-0.0437199995 -0.0187199991 -0.0131130004 +-0.0437199995 -0.0187199991 -0.0368870012 +-0.0437199995 -0.0187199991 -0.0381130017 +-0.0437199995 -0.0312799998 0.0131130004 +-0.0437199995 -0.0312799998 0.0118869999 +-0.0437199995 -0.0312799998 -0.0118869999 +-0.0437199995 -0.0312799998 -0.0131130004 +-0.0437199995 -0.0312799998 -0.0368870012 +-0.0437199995 -0.0312799998 -0.0381130017 +-0.0437199995 -0.0368870012 0.0187199991 +-0.0437199995 -0.0368870012 0.0062799999 +-0.0437199995 -0.0368870012 -0.0062799999 +-0.0437199995 -0.0368870012 -0.0187199991 +-0.0437199995 -0.0368870012 -0.0312799998 +-0.0437199995 -0.0368870012 -0.0437199995 +-0.0437199995 -0.0381130017 0.0187199991 +-0.0437199995 -0.0381130017 0.0062799999 +-0.0437199995 -0.0381130017 -0.0062799999 +-0.0437199995 -0.0381130017 -0.0187199991 +-0.0437199995 -0.0381130017 -0.0312799998 +-0.0437199995 -0.0381130017 -0.0437199995 +-0.0437199995 -0.0437199995 0.0131130004 +-0.0437199995 -0.0437199995 0.0118869999 +-0.0437199995 -0.0437199995 -0.0118869999 +-0.0437199995 -0.0437199995 -0.0131130004 +-0.0437199995 -0.0437199995 -0.0368870012 +-0.0437199995 -0.0437199995 -0.0381130017 +-0.0437499993 0.0500000007 0.0375000015 +-0.0437499993 0.0500000007 0.0125000002 +-0.0437499993 0.0500000007 -0.0125000002 +-0.0437499993 0.0500000007 -0.0375000015 +-0.0437499993 0.0437499993 0.0375000015 +-0.0437499993 0.0437499993 0.0125000002 +-0.0437499993 0.0437499993 -0.0125000002 +-0.0437499993 0.0437499993 -0.0375000015 +-0.0437499993 0.0375000015 0.0500000007 +-0.0437499993 0.0375000015 0.0437499993 +-0.0437499993 0.0375000015 0.0312500000 +-0.0437499993 0.0375000015 0.0187500007 +-0.0437499993 0.0375000015 0.0062500001 +-0.0437499993 0.0375000015 -0.0062500001 +-0.0437499993 0.0375000015 -0.0187500007 +-0.0437499993 0.0375000015 -0.0312500000 +-0.0437499993 0.0375000015 -0.0437499993 +-0.0437499993 0.0375000015 -0.0500000007 +-0.0437499993 0.0312500000 -0.0125000002 +-0.0437499993 0.0312500000 -0.0375000015 +-0.0437499993 0.0187500007 -0.0125000002 +-0.0437499993 0.0187500007 -0.0375000015 +-0.0437499993 0.0125000002 -0.0003910000 +-0.0437499993 0.0125000002 -0.0062500001 +-0.0437499993 0.0125000002 -0.0187500007 +-0.0437499993 0.0125000002 -0.0312500000 +-0.0437499993 0.0125000002 -0.0437499993 +-0.0437499993 0.0125000002 -0.0500000007 +-0.0437499993 0.0062500001 -0.0125000002 +-0.0437499993 0.0062500001 -0.0375000015 +-0.0437499993 0.0042849998 0.0375000015 +-0.0437499993 0.0042849998 0.0125000002 +-0.0437499993 -0.0062500001 0.0375000015 +-0.0437499993 -0.0062500001 0.0125000002 +-0.0437499993 -0.0062500001 -0.0125000002 +-0.0437499993 -0.0062500001 -0.0375000015 +-0.0437499993 -0.0125000002 0.0500000007 +-0.0437499993 -0.0125000002 0.0437499993 +-0.0437499993 -0.0125000002 0.0312500000 +-0.0437499993 -0.0125000002 0.0187500007 +-0.0437499993 -0.0125000002 0.0062500001 +-0.0437499993 -0.0125000002 -0.0062500001 +-0.0437499993 -0.0125000002 -0.0187500007 +-0.0437499993 -0.0125000002 -0.0312500000 +-0.0437499993 -0.0125000002 -0.0437499993 +-0.0437499993 -0.0125000002 -0.0500000007 +-0.0437499993 -0.0187500007 0.0375000015 +-0.0437499993 -0.0187500007 0.0125000002 +-0.0437499993 -0.0187500007 -0.0125000002 +-0.0437499993 -0.0187500007 -0.0375000015 +-0.0437499993 -0.0250000004 0.0375000015 +-0.0437499993 -0.0312500000 0.0125000002 +-0.0437499993 -0.0312500000 -0.0125000002 +-0.0437499993 -0.0312500000 -0.0375000015 +-0.0437499993 -0.0375000015 0.0212500002 +-0.0437499993 -0.0375000015 0.0187500007 +-0.0437499993 -0.0375000015 0.0062500001 +-0.0437499993 -0.0375000015 -0.0062500001 +-0.0437499993 -0.0375000015 -0.0187500007 +-0.0437499993 -0.0375000015 -0.0312500000 +-0.0437499993 -0.0375000015 -0.0437499993 +-0.0437499993 -0.0375000015 -0.0500000007 +-0.0437499993 -0.0437499993 0.0125000002 +-0.0437499993 -0.0437499993 -0.0125000002 +-0.0437499993 -0.0437499993 -0.0375000015 +-0.0437499993 -0.0500000007 0.0125000002 +-0.0437499993 -0.0500000007 -0.0125000002 +-0.0437499993 -0.0500000007 -0.0375000015 +-0.0439650007 0.0314729996 0.0391529985 +-0.0439650007 0.0314729996 0.0358470008 +-0.0439650007 0.0314729996 0.0141530000 +-0.0439650007 0.0314729996 0.0108470004 +-0.0444089994 0.0317290016 0.0398989990 +-0.0444089994 0.0317290016 0.0351010002 +-0.0444089994 0.0317290016 0.0148989996 +-0.0444089994 0.0317290016 0.0101009998 +-0.0450120009 0.0320769995 0.0406070016 +-0.0450120009 0.0320769995 0.0343930013 +-0.0450120009 0.0320769995 0.0156070003 +-0.0450120009 0.0320769995 0.0093930000 +-0.0457639992 0.0325109996 0.0412649997 +-0.0457639992 0.0325109996 0.0337349996 +-0.0457639992 0.0325109996 0.0162649993 +-0.0457639992 0.0325109996 0.0087350002 +-0.0471529998 0.0062500001 0.0375000015 +-0.0471529998 0.0062500001 0.0125000002 +-0.0472000018 0.0062770001 0.0380790010 +-0.0472000018 0.0062770001 0.0369209982 +-0.0472000018 0.0062770001 0.0130789997 +-0.0472000018 0.0062770001 0.0119209997 +-0.0473389998 0.0063570002 0.0386530012 +-0.0473389998 0.0063570002 0.0363470018 +-0.0473389998 0.0063570002 0.0136529999 +-0.0473389998 0.0063570002 0.0113469996 +-0.0475700013 0.0064900001 0.0392169990 +-0.0475700013 0.0064900001 0.0357830003 +-0.0475700013 0.0064900001 0.0142170005 +-0.0475700013 0.0064900001 0.0107829999 +-0.0476679988 0.0336109996 0.0423920006 +-0.0476679988 0.0336109996 0.0326079987 +-0.0476679988 0.0336109996 0.0173920002 +-0.0476679988 0.0336109996 0.0076080002 +-0.0478900000 0.0066749998 0.0397659987 +-0.0478900000 0.0066749998 0.0352340005 +-0.0478900000 0.0066749998 0.0147660002 +-0.0478900000 0.0066749998 0.0102340002 +-0.0487870015 0.0071930001 0.0408019982 +-0.0487870015 0.0071930001 0.0341980010 +-0.0487870015 0.0071930001 0.0158019997 +-0.0487870015 0.0071930001 0.0091979997 +-0.0500000007 0.0500000007 0.0500000007 +-0.0500000007 0.0500000007 -0.0500000007 +-0.0500000007 0.0437499993 -0.0125000002 +-0.0500000007 0.0437499993 -0.0375000015 +-0.0500000007 0.0437440015 0.0372200012 +-0.0500000007 0.0437440015 0.0122199999 +-0.0500000007 0.0436130017 0.0388000011 +-0.0500000007 0.0436130017 0.0137999998 +-0.0500000007 0.0435369983 -0.0108820004 +-0.0500000007 0.0435369983 -0.0141179999 +-0.0500000007 0.0435369983 -0.0358819999 +-0.0500000007 0.0435369983 -0.0391179994 +-0.0500000007 0.0434719995 0.0356579982 +-0.0500000007 0.0434719995 0.0106579997 +-0.0500000007 0.0430900007 0.0402959995 +-0.0500000007 0.0430900007 0.0152960001 +-0.0500000007 0.0429130010 -0.0093750004 +-0.0500000007 0.0429130010 -0.0156250000 +-0.0500000007 0.0429130010 -0.0343750007 +-0.0500000007 0.0429130010 -0.0406249985 +-0.0500000007 0.0428170003 0.0342149995 +-0.0500000007 0.0428170003 0.0092150001 +-0.0500000007 0.0422060005 0.0416130014 +-0.0500000007 0.0422060005 0.0166129991 +-0.0500000007 0.0419190004 -0.0080810003 +-0.0500000007 0.0419190004 -0.0169190001 +-0.0500000007 0.0419190004 -0.0330809988 +-0.0500000007 0.0419190004 -0.0419190004 +-0.0500000007 0.0418189988 0.0329830013 +-0.0500000007 0.0418189988 0.0079830000 +-0.0500000007 0.0410199985 0.0426639989 +-0.0500000007 0.0410199985 0.0176640004 +-0.0500000007 0.0406249985 -0.0070870002 +-0.0500000007 0.0406249985 -0.0179130007 +-0.0500000007 0.0406249985 -0.0320869982 +-0.0500000007 0.0406249985 -0.0429130010 +-0.0500000007 0.0405439995 0.0320409983 +-0.0500000007 0.0405439995 0.0070409998 +-0.0500000007 0.0396069996 0.0433840007 +-0.0500000007 0.0396069996 0.0183840003 +-0.0500000007 0.0391179994 -0.0064630001 +-0.0500000007 0.0391179994 -0.0185369998 +-0.0500000007 0.0391179994 -0.0314630009 +-0.0500000007 0.0391179994 -0.0435369983 +-0.0500000007 0.0390730016 0.0314510018 +-0.0500000007 0.0390730016 0.0064510000 +-0.0500000007 0.0380589999 0.0437249988 +-0.0500000007 0.0380589999 0.0187250003 +-0.0500000007 0.0375000015 0.0312500000 +-0.0500000007 0.0375000015 0.0062500001 +-0.0500000007 0.0375000015 -0.0062500001 +-0.0500000007 0.0375000015 -0.0187500007 +-0.0500000007 0.0375000015 -0.0312500000 +-0.0500000007 0.0375000015 -0.0437499993 +-0.0500000007 0.0364749990 0.0436649993 +-0.0500000007 0.0364749990 0.0186650008 +-0.0500000007 0.0362000018 0.0313870013 +-0.0500000007 0.0362000018 0.0063870000 +-0.0500000007 0.0358819999 -0.0064630001 +-0.0500000007 0.0358819999 -0.0185369998 +-0.0500000007 0.0358819999 -0.0314630009 +-0.0500000007 0.0358819999 -0.0435369983 +-0.0500000007 0.0349569991 0.0500000007 +-0.0500000007 0.0349569991 0.0432090014 +-0.0500000007 0.0349569991 0.0317910016 +-0.0500000007 0.0349569991 0.0182089992 +-0.0500000007 0.0349569991 0.0067909998 +-0.0500000007 0.0349569991 -0.0003910000 +-0.0500000007 0.0343750007 -0.0070870002 +-0.0500000007 0.0343750007 -0.0179130007 +-0.0500000007 0.0343750007 -0.0320869982 +-0.0500000007 0.0343750007 -0.0429130010 +-0.0500000007 0.0330809988 -0.0080810003 +-0.0500000007 0.0330809988 -0.0169190001 +-0.0500000007 0.0330809988 -0.0330809988 +-0.0500000007 0.0330809988 -0.0419190004 +-0.0500000007 0.0320869982 -0.0093750004 +-0.0500000007 0.0320869982 -0.0156250000 +-0.0500000007 0.0320869982 -0.0343750007 +-0.0500000007 0.0320869982 -0.0406249985 +-0.0500000007 0.0314630009 -0.0108820004 +-0.0500000007 0.0314630009 -0.0141179999 +-0.0500000007 0.0314630009 -0.0358819999 +-0.0500000007 0.0314630009 -0.0391179994 +-0.0500000007 0.0312500000 -0.0125000002 +-0.0500000007 0.0312500000 -0.0375000015 +-0.0500000007 0.0187500007 -0.0125000002 +-0.0500000007 0.0187500007 -0.0375000015 +-0.0500000007 0.0185369998 -0.0108820004 +-0.0500000007 0.0185369998 -0.0141179999 +-0.0500000007 0.0185369998 -0.0358819999 +-0.0500000007 0.0185369998 -0.0391179994 +-0.0500000007 0.0179130007 -0.0093750004 +-0.0500000007 0.0179130007 -0.0156250000 +-0.0500000007 0.0179130007 -0.0343750007 +-0.0500000007 0.0179130007 -0.0406249985 +-0.0500000007 0.0169190001 -0.0080810003 +-0.0500000007 0.0169190001 -0.0169190001 +-0.0500000007 0.0169190001 -0.0330809988 +-0.0500000007 0.0169190001 -0.0419190004 +-0.0500000007 0.0156250000 -0.0070870002 +-0.0500000007 0.0156250000 -0.0179130007 +-0.0500000007 0.0156250000 -0.0320869982 +-0.0500000007 0.0156250000 -0.0429130010 +-0.0500000007 0.0141179999 -0.0064630001 +-0.0500000007 0.0141179999 -0.0185369998 +-0.0500000007 0.0141179999 -0.0314630009 +-0.0500000007 0.0141179999 -0.0435369983 +-0.0500000007 0.0125000002 -0.0062500001 +-0.0500000007 0.0125000002 -0.0187500007 +-0.0500000007 0.0125000002 -0.0312500000 +-0.0500000007 0.0125000002 -0.0437499993 +-0.0500000007 0.0108820004 -0.0064630001 +-0.0500000007 0.0108820004 -0.0185369998 +-0.0500000007 0.0108820004 -0.0314630009 +-0.0500000007 0.0108820004 -0.0435369983 +-0.0500000007 0.0093750004 -0.0070870002 +-0.0500000007 0.0093750004 -0.0179130007 +-0.0500000007 0.0093750004 -0.0320869982 +-0.0500000007 0.0093750004 -0.0429130010 +-0.0500000007 0.0080810003 -0.0080810003 +-0.0500000007 0.0080810003 -0.0169190001 +-0.0500000007 0.0080810003 -0.0330809988 +-0.0500000007 0.0080810003 -0.0419190004 +-0.0500000007 0.0078929998 0.0500000007 +-0.0500000007 0.0078929998 0.0417240001 +-0.0500000007 0.0078929998 0.0332759991 +-0.0500000007 0.0078929998 0.0167239998 +-0.0500000007 0.0078929998 0.0082759997 +-0.0500000007 0.0078929998 -0.0003910000 +-0.0500000007 0.0070870002 -0.0093750004 +-0.0500000007 0.0070870002 -0.0156250000 +-0.0500000007 0.0070870002 -0.0343750007 +-0.0500000007 0.0070870002 -0.0406249985 +-0.0500000007 0.0069990000 0.0404679999 +-0.0500000007 0.0069990000 0.0345319994 +-0.0500000007 0.0069990000 0.0154680004 +-0.0500000007 0.0069990000 0.0095319999 +-0.0500000007 0.0064630001 -0.0108820004 +-0.0500000007 0.0064630001 -0.0141179999 +-0.0500000007 0.0064630001 -0.0358819999 +-0.0500000007 0.0064630001 -0.0391179994 +-0.0500000007 0.0064400001 0.0390300006 +-0.0500000007 0.0064400001 0.0359699987 +-0.0500000007 0.0064400001 0.0140300002 +-0.0500000007 0.0064400001 0.0109700002 +-0.0500000007 0.0062500001 0.0375000015 +-0.0500000007 0.0062500001 0.0125000002 +-0.0500000007 0.0062500001 -0.0125000002 +-0.0500000007 0.0062500001 -0.0375000015 +-0.0500000007 -0.0062500001 0.0375000015 +-0.0500000007 -0.0062500001 0.0125000002 +-0.0500000007 -0.0062500001 -0.0125000002 +-0.0500000007 -0.0062500001 -0.0375000015 +-0.0500000007 -0.0064630001 0.0391179994 +-0.0500000007 -0.0064630001 0.0358819999 +-0.0500000007 -0.0064630001 0.0141179999 +-0.0500000007 -0.0064630001 0.0108820004 +-0.0500000007 -0.0064630001 -0.0108820004 +-0.0500000007 -0.0064630001 -0.0141179999 +-0.0500000007 -0.0064630001 -0.0358819999 +-0.0500000007 -0.0064630001 -0.0391179994 +-0.0500000007 -0.0070870002 0.0406249985 +-0.0500000007 -0.0070870002 0.0343750007 +-0.0500000007 -0.0070870002 0.0156250000 +-0.0500000007 -0.0070870002 0.0093750004 +-0.0500000007 -0.0070870002 -0.0093750004 +-0.0500000007 -0.0070870002 -0.0156250000 +-0.0500000007 -0.0070870002 -0.0343750007 +-0.0500000007 -0.0070870002 -0.0406249985 +-0.0500000007 -0.0080810003 0.0419190004 +-0.0500000007 -0.0080810003 0.0330809988 +-0.0500000007 -0.0080810003 0.0169190001 +-0.0500000007 -0.0080810003 0.0080810003 +-0.0500000007 -0.0080810003 -0.0080810003 +-0.0500000007 -0.0080810003 -0.0169190001 +-0.0500000007 -0.0080810003 -0.0330809988 +-0.0500000007 -0.0080810003 -0.0419190004 +-0.0500000007 -0.0093750004 0.0429130010 +-0.0500000007 -0.0093750004 0.0320869982 +-0.0500000007 -0.0093750004 0.0179130007 +-0.0500000007 -0.0093750004 0.0070870002 +-0.0500000007 -0.0093750004 -0.0070870002 +-0.0500000007 -0.0093750004 -0.0179130007 +-0.0500000007 -0.0093750004 -0.0320869982 +-0.0500000007 -0.0093750004 -0.0429130010 +-0.0500000007 -0.0108820004 0.0435369983 +-0.0500000007 -0.0108820004 0.0314630009 +-0.0500000007 -0.0108820004 0.0185369998 +-0.0500000007 -0.0108820004 0.0064630001 +-0.0500000007 -0.0108820004 -0.0064630001 +-0.0500000007 -0.0108820004 -0.0185369998 +-0.0500000007 -0.0108820004 -0.0314630009 +-0.0500000007 -0.0108820004 -0.0435369983 +-0.0500000007 -0.0125000002 0.0437499993 +-0.0500000007 -0.0125000002 0.0312500000 +-0.0500000007 -0.0125000002 0.0187500007 +-0.0500000007 -0.0125000002 0.0062500001 +-0.0500000007 -0.0125000002 -0.0062500001 +-0.0500000007 -0.0125000002 -0.0187500007 +-0.0500000007 -0.0125000002 -0.0312500000 +-0.0500000007 -0.0125000002 -0.0437499993 +-0.0500000007 -0.0141179999 0.0435369983 +-0.0500000007 -0.0141179999 0.0314630009 +-0.0500000007 -0.0141179999 0.0185369998 +-0.0500000007 -0.0141179999 0.0064630001 +-0.0500000007 -0.0141179999 -0.0064630001 +-0.0500000007 -0.0141179999 -0.0185369998 +-0.0500000007 -0.0141179999 -0.0314630009 +-0.0500000007 -0.0141179999 -0.0435369983 +-0.0500000007 -0.0156250000 0.0429130010 +-0.0500000007 -0.0156250000 0.0320869982 +-0.0500000007 -0.0156250000 0.0179130007 +-0.0500000007 -0.0156250000 0.0070870002 +-0.0500000007 -0.0156250000 -0.0070870002 +-0.0500000007 -0.0156250000 -0.0179130007 +-0.0500000007 -0.0156250000 -0.0320869982 +-0.0500000007 -0.0156250000 -0.0429130010 +-0.0500000007 -0.0169190001 0.0419190004 +-0.0500000007 -0.0169190001 0.0330809988 +-0.0500000007 -0.0169190001 0.0169190001 +-0.0500000007 -0.0169190001 0.0080810003 +-0.0500000007 -0.0169190001 -0.0080810003 +-0.0500000007 -0.0169190001 -0.0169190001 +-0.0500000007 -0.0169190001 -0.0330809988 +-0.0500000007 -0.0169190001 -0.0419190004 +-0.0500000007 -0.0179130007 0.0406249985 +-0.0500000007 -0.0179130007 0.0343750007 +-0.0500000007 -0.0179130007 0.0156250000 +-0.0500000007 -0.0179130007 0.0093750004 +-0.0500000007 -0.0179130007 -0.0093750004 +-0.0500000007 -0.0179130007 -0.0156250000 +-0.0500000007 -0.0179130007 -0.0343750007 +-0.0500000007 -0.0179130007 -0.0406249985 +-0.0500000007 -0.0185369998 0.0391179994 +-0.0500000007 -0.0185369998 0.0358819999 +-0.0500000007 -0.0185369998 0.0141179999 +-0.0500000007 -0.0185369998 0.0108820004 +-0.0500000007 -0.0185369998 -0.0108820004 +-0.0500000007 -0.0185369998 -0.0141179999 +-0.0500000007 -0.0185369998 -0.0358819999 +-0.0500000007 -0.0185369998 -0.0391179994 +-0.0500000007 -0.0187500007 0.0375000015 +-0.0500000007 -0.0187500007 0.0125000002 +-0.0500000007 -0.0187500007 -0.0125000002 +-0.0500000007 -0.0187500007 -0.0375000015 +-0.0500000007 -0.0250000004 0.0500000007 +-0.0500000007 -0.0250000004 0.0250000004 +-0.0500000007 -0.0251279995 0.0240289997 +-0.0500000007 -0.0255020000 0.0231250003 +-0.0500000007 -0.0260979999 0.0223479997 +-0.0500000007 -0.0268750004 0.0217519999 +-0.0500000007 -0.0277789999 0.0213779993 +-0.0500000007 -0.0287500005 0.0212500002 +-0.0500000007 -0.0312500000 0.0125000002 +-0.0500000007 -0.0312500000 -0.0125000002 +-0.0500000007 -0.0312500000 -0.0375000015 +-0.0500000007 -0.0314630009 0.0141179999 +-0.0500000007 -0.0314630009 0.0108820004 +-0.0500000007 -0.0314630009 -0.0108820004 +-0.0500000007 -0.0314630009 -0.0141179999 +-0.0500000007 -0.0314630009 -0.0358819999 +-0.0500000007 -0.0314630009 -0.0391179994 +-0.0500000007 -0.0320869982 0.0156250000 +-0.0500000007 -0.0320869982 0.0093750004 +-0.0500000007 -0.0320869982 -0.0093750004 +-0.0500000007 -0.0320869982 -0.0156250000 +-0.0500000007 -0.0320869982 -0.0343750007 +-0.0500000007 -0.0320869982 -0.0406249985 +-0.0500000007 -0.0330809988 0.0169190001 +-0.0500000007 -0.0330809988 0.0080810003 +-0.0500000007 -0.0330809988 -0.0080810003 +-0.0500000007 -0.0330809988 -0.0169190001 +-0.0500000007 -0.0330809988 -0.0330809988 +-0.0500000007 -0.0330809988 -0.0419190004 +-0.0500000007 -0.0343750007 0.0179130007 +-0.0500000007 -0.0343750007 0.0070870002 +-0.0500000007 -0.0343750007 -0.0070870002 +-0.0500000007 -0.0343750007 -0.0179130007 +-0.0500000007 -0.0343750007 -0.0320869982 +-0.0500000007 -0.0343750007 -0.0429130010 +-0.0500000007 -0.0358819999 0.0185369998 +-0.0500000007 -0.0358819999 0.0064630001 +-0.0500000007 -0.0358819999 -0.0064630001 +-0.0500000007 -0.0358819999 -0.0185369998 +-0.0500000007 -0.0358819999 -0.0314630009 +-0.0500000007 -0.0358819999 -0.0435369983 +-0.0500000007 -0.0375000015 0.0187500007 +-0.0500000007 -0.0375000015 0.0062500001 +-0.0500000007 -0.0375000015 -0.0062500001 +-0.0500000007 -0.0375000015 -0.0187500007 +-0.0500000007 -0.0375000015 -0.0312500000 +-0.0500000007 -0.0375000015 -0.0437499993 +-0.0500000007 -0.0391179994 0.0185369998 +-0.0500000007 -0.0391179994 0.0064630001 +-0.0500000007 -0.0391179994 -0.0064630001 +-0.0500000007 -0.0391179994 -0.0185369998 +-0.0500000007 -0.0391179994 -0.0314630009 +-0.0500000007 -0.0391179994 -0.0435369983 +-0.0500000007 -0.0406249985 0.0179130007 +-0.0500000007 -0.0406249985 0.0070870002 +-0.0500000007 -0.0406249985 -0.0070870002 +-0.0500000007 -0.0406249985 -0.0179130007 +-0.0500000007 -0.0406249985 -0.0320869982 +-0.0500000007 -0.0406249985 -0.0429130010 +-0.0500000007 -0.0419190004 0.0169190001 +-0.0500000007 -0.0419190004 0.0080810003 +-0.0500000007 -0.0419190004 -0.0080810003 +-0.0500000007 -0.0419190004 -0.0169190001 +-0.0500000007 -0.0419190004 -0.0330809988 +-0.0500000007 -0.0419190004 -0.0419190004 +-0.0500000007 -0.0429130010 0.0156250000 +-0.0500000007 -0.0429130010 0.0093750004 +-0.0500000007 -0.0429130010 -0.0093750004 +-0.0500000007 -0.0429130010 -0.0156250000 +-0.0500000007 -0.0429130010 -0.0343750007 +-0.0500000007 -0.0429130010 -0.0406249985 +-0.0500000007 -0.0435369983 0.0141179999 +-0.0500000007 -0.0435369983 0.0108820004 +-0.0500000007 -0.0435369983 -0.0108820004 +-0.0500000007 -0.0435369983 -0.0141179999 +-0.0500000007 -0.0435369983 -0.0358819999 +-0.0500000007 -0.0435369983 -0.0391179994 +-0.0500000007 -0.0437499993 0.0125000002 +-0.0500000007 -0.0437499993 -0.0125000002 +-0.0500000007 -0.0437499993 -0.0375000015 +-0.0500000007 -0.0500000007 0.0212500002 +-0.0500000007 -0.0500000007 -0.0500000007 +0.0314685032 0.0188249983 0.0389624983 +0.0313510001 0.0187769998 0.0392495021 +3 8523 8572 8522 +3 8572 8571 8522 +3 8475 8474 8421 +3 8373 8397 8396 +3 8425 8470 8462 +3 8487 8494 8486 +3 8496 8497 8504 +3 8520 8570 8569 +3 8520 8569 8563 +3 8520 8563 8528 +3 8563 8557 8528 +3 8557 8536 8528 +3 8542 8557 8553 +3 8536 8557 8542 +3 8535 8553 8556 +3 8542 8553 8535 +3 8455 8443 8450 +3 8428 8472 8464 +3 8625 8617 8618 +3 8625 8618 8623 +3 8611 8612 8618 +3 8612 8605 8606 +3 8599 8600 8606 +3 8587 8588 8593 +3 8582 8588 8587 +3 8582 8587 8581 +3 8582 8581 8576 +3 8506 8507 8514 +3 8515 8522 8514 +3 8522 8565 8530 +3 8543 8559 8554 +3 8543 8554 8537 +3 8564 8537 8558 +3 8537 8554 8558 +3 8529 8537 8564 +3 8521 8564 8570 +3 8529 8564 8521 +3 8474 8483 8482 +3 8408 8409 8412 +3 8447 8451 8437 +3 8429 8428 8419 +3 8428 8415 8419 +3 8411 8415 8428 +3 8411 8428 8407 +3 8428 8403 8407 +3 8399 8403 8428 +3 8358 8369 8368 +3 8368 8373 8372 +3 8383 8385 8379 +3 8323 8320 8315 +3 8315 8312 8307 +3 8307 8304 8301 +3 8300 8308 8301 +3 8614 8607 8608 +3 8601 8602 8608 +3 8595 8589 8590 +3 8589 8583 8590 +3 8583 8584 8590 +3 8571 8578 8577 +3 8578 8583 8577 +3 8584 8583 8578 +3 8530 8559 8538 +3 8559 8543 8538 +3 8565 8559 8530 +3 8571 8565 8522 +3 8578 8571 8572 +3 8626 8620 8624 +3 8626 8624 8621 +3 8626 8621 8615 +3 8626 8615 8609 +3 8626 8609 8603 +3 8626 8603 8597 +3 8626 8597 8591 +3 8626 8591 8585 +3 8626 8508 8500 +3 8572 8531 8566 +3 8531 8560 8566 +3 8523 8531 8572 +3 8515 8523 8522 +3 8507 8515 8514 +3 8499 8507 8506 +3 8499 8506 8498 +3 8499 8498 8491 +3 8544 8560 8539 +3 8560 8531 8539 +3 8555 8560 8544 +3 8555 8544 8561 +3 8544 8540 8561 +3 8540 8532 8561 +3 8532 8567 8561 +3 8573 8567 8532 +3 8573 8532 8524 +3 8573 8524 8579 +3 8524 8516 8579 +3 8516 8508 8579 +3 8508 8585 8579 +3 8626 8585 8508 +3 8410 8626 8500 +3 8410 8500 8414 +3 8500 8492 8414 +3 8492 8484 8414 +3 8484 8418 8414 +3 8422 8418 8484 +3 8422 8484 8476 +3 8422 8476 8432 +3 8476 8468 8432 +3 8468 8460 8432 +3 8460 8440 8432 +3 8448 8440 8460 +3 8448 8460 8452 +3 8448 8452 8459 +3 8448 8459 8439 +3 8475 8431 8467 +3 8431 8459 8467 +3 8439 8459 8431 +3 8482 8491 8490 +3 8491 8498 8490 +3 8483 8491 8482 +3 8475 8483 8474 +3 8431 8475 8421 +3 8473 8428 8465 +3 8428 8429 8465 +3 8429 8437 8465 +3 8437 8457 8465 +3 8451 8457 8437 +3 8458 8451 8447 +3 8458 8447 8438 +3 8458 8438 8430 +3 8458 8430 8466 +3 8430 8420 8466 +3 8420 8474 8466 +3 8421 8474 8420 +3 8421 8420 8416 +3 8421 8416 8417 +3 8416 8412 8417 +3 8412 8413 8417 +3 8409 8413 8412 +3 8405 8409 8408 +3 8405 8408 8404 +3 8405 8404 8401 +3 8300 8360 8352 +3 8370 8398 8374 +3 8374 8394 8378 +3 8384 8390 8386 +3 8384 8386 8389 +3 8384 8389 8381 +3 8397 8377 8393 +3 8377 8389 8393 +3 8381 8389 8377 +3 8396 8401 8400 +3 8401 8404 8400 +3 8397 8401 8396 +3 8377 8397 8373 +3 8395 8371 8391 +3 8371 8375 8391 +3 8375 8379 8391 +3 8379 8387 8391 +3 8385 8387 8379 +3 8388 8385 8383 +3 8388 8383 8380 +3 8388 8380 8376 +3 8388 8376 8392 +3 8376 8372 8392 +3 8372 8396 8392 +3 8373 8396 8372 +3 8369 8373 8368 +3 8359 8369 8358 +3 8359 8358 8351 +3 8340 8351 8350 +3 8351 8358 8350 +3 8341 8351 8340 +3 8341 8340 8333 +3 8302 8309 8300 +3 8302 8300 8310 +3 8300 8318 8310 +3 8326 8318 8300 +3 8326 8300 8334 +3 8300 8342 8334 +3 8352 8342 8300 +3 8527 8550 8549 +3 8550 8535 8551 +3 8602 8595 8596 +3 8595 8590 8596 +3 8601 8595 8602 +3 8607 8601 8608 +3 8613 8607 8614 +3 8613 8614 8619 +3 8614 8620 8619 +3 8620 8626 8619 +3 8626 8623 8619 +3 8625 8623 8626 +3 8378 8390 8382 +3 8390 8384 8382 +3 8394 8390 8378 +3 8398 8394 8374 +3 8402 8398 8370 +3 8402 8370 8360 +3 8402 8360 8406 +3 8360 8300 8406 +3 8300 8410 8406 +3 8626 8410 8300 +3 8300 8304 8299 +3 8361 8353 8362 +3 8345 8353 8361 +3 8345 8361 8337 +3 8361 8299 8337 +3 8299 8329 8337 +3 8321 8329 8299 +3 8321 8299 8313 +3 8299 8305 8313 +3 8303 8305 8299 +3 8303 8299 8311 +3 8319 8322 8327 +3 8327 8330 8335 +3 8335 8338 8343 +3 8343 8346 8347 +3 8347 8354 8355 +3 8355 8364 8363 +3 8354 8364 8355 +3 8346 8354 8347 +3 8338 8346 8343 +3 8330 8338 8335 +3 8322 8330 8327 +3 8314 8322 8319 +3 8314 8319 8311 +3 8314 8311 8306 +3 8311 8299 8306 +3 8299 8304 8306 +3 8324 8333 8332 +3 8333 8340 8332 +3 8325 8333 8324 +3 8325 8324 8316 +3 8325 8316 8317 +3 8316 8308 8317 +3 8308 8309 8317 +3 8300 8309 8308 +3 8304 8300 8301 +3 8312 8304 8307 +3 8320 8312 8315 +3 8328 8320 8323 +3 8328 8323 8331 +3 8328 8331 8336 +3 8331 8339 8336 +3 8339 8344 8336 +3 8365 8356 8366 +3 8356 8348 8366 +3 8348 8344 8366 +3 8344 8339 8366 +3 8339 8349 8366 +3 8349 8357 8366 +3 8357 8367 8366 +3 8367 8371 8366 +3 8371 8395 8366 +3 8395 8399 8366 +3 8399 8428 8366 +3 8427 8428 8436 +3 8569 8576 8575 +3 8576 8581 8575 +3 8570 8576 8569 +3 8521 8570 8520 +3 8521 8520 8513 +3 8520 8512 8513 +3 8512 8504 8513 +3 8504 8505 8513 +3 8497 8505 8504 +3 8489 8497 8496 +3 8489 8496 8488 +3 8489 8488 8480 +3 8489 8480 8481 +3 8480 8472 8481 +3 8472 8473 8481 +3 8428 8473 8472 +3 8436 8428 8464 +3 8436 8464 8456 +3 8436 8456 8444 +3 8456 8450 8444 +3 8450 8446 8444 +3 8443 8446 8450 +3 8435 8443 8455 +3 8435 8455 8463 +3 8435 8463 8426 +3 8494 8495 8502 +3 8495 8503 8502 +3 8487 8495 8494 +3 8479 8487 8486 +3 8479 8486 8478 +3 8479 8478 8470 +3 8479 8470 8471 +3 8470 8426 8471 +3 8426 8463 8471 +3 8425 8426 8470 +3 8434 8425 8462 +3 8434 8462 8454 +3 8434 8454 8442 +3 8454 8449 8442 +3 8449 8445 8442 +3 8441 8445 8449 +3 8441 8449 8453 +3 8441 8453 8433 +3 8493 8423 8485 +3 8423 8477 8485 +3 8469 8477 8423 +3 8469 8423 8461 +3 8423 8433 8461 +3 8433 8453 8461 +3 8424 8433 8423 +3 8533 8541 8545 +3 8533 8545 8525 +3 8545 8517 8525 +3 8509 8517 8545 +3 8509 8545 8501 +3 8545 8493 8501 +3 8423 8493 8545 +3 8600 8593 8594 +3 8593 8588 8594 +3 8599 8593 8600 +3 8605 8599 8606 +3 8611 8605 8612 +3 8617 8611 8618 +3 8622 8617 8625 +3 8622 8625 8616 +3 8625 8610 8616 +3 8604 8610 8625 +3 8604 8625 8598 +3 8625 8592 8598 +3 8586 8592 8625 +3 8586 8625 8552 +3 8586 8552 8580 +3 8552 8574 8580 +3 8568 8574 8552 +3 8568 8552 8562 +3 8552 8551 8562 +3 8551 8556 8562 +3 8535 8556 8551 +3 8527 8535 8550 +3 8519 8527 8549 +3 8519 8549 8548 +3 8519 8548 8547 +3 8519 8547 8511 +3 8547 8546 8511 +3 8546 8503 8511 +3 8502 8503 8546 +3 8502 8546 8510 +3 8546 8518 8510 +3 8526 8518 8546 +3 8526 8546 8534 +3 8546 8541 8534 +3 8545 8541 8546 +3 779 955 964 +3 964 1070 1072 +3 773 775 630 +3 2220 2339 1981 +3 1072 1152 1154 +3 1152 1309 1154 +3 1070 1152 1072 +3 955 1070 964 +3 777 955 779 +3 777 779 634 +3 777 634 632 +3 344 1156 1319 +3 1074 1156 344 +3 1074 344 974 +3 344 781 974 +3 636 781 344 +3 636 344 401 +3 344 634 401 +3 632 634 344 +3 632 344 386 +3 771 905 928 +3 928 1052 1064 +3 2206 1975 2302 +3 2206 2302 1977 +3 1830 1661 1652 +3 1455 1453 1541 +3 1283 1453 1455 +3 1283 1455 1291 +3 1283 1291 1148 +3 1068 1148 1150 +3 1148 1291 1150 +3 1066 1148 1068 +3 1066 1068 937 +3 1457 1309 1299 +3 1309 1152 1299 +3 1459 1309 1457 +3 1459 1457 1545 +3 1457 1543 1545 +3 1543 1670 1545 +3 1670 1679 1545 +3 1836 1679 1670 +3 1836 1670 1834 +3 1836 1834 1983 +3 1834 1981 1983 +3 1981 2339 1983 +3 2339 2235 1983 +3 1985 2235 2339 +3 1985 2339 1838 +3 2339 1689 1838 +3 1547 1689 2339 +3 1547 2339 1461 +3 2339 1319 1461 +3 344 1319 2339 +3 1652 1541 1539 +3 1541 1453 1539 +3 1661 1541 1652 +3 1832 1661 1830 +3 1832 1830 1979 +3 1830 1977 1979 +3 1977 2302 1979 +3 2302 2220 1979 +3 2339 2220 2302 +3 1390 1439 1524 +3 1258 1439 1390 +3 1258 1390 1337 +3 1258 1337 1133 +3 1643 2302 1828 +3 2302 1975 1828 +3 1555 2302 1643 +3 1555 1643 1537 +3 1555 1537 1451 +3 1555 1451 1473 +3 1451 1279 1473 +3 1279 1392 1473 +3 1338 1392 1279 +3 1338 1279 1146 +3 1338 1146 1334 +3 1146 1064 1334 +3 1064 1133 1334 +3 1133 1337 1334 +3 1052 1133 1064 +3 905 1052 928 +3 759 905 771 +3 759 771 626 +3 759 626 614 +3 2272 1957 1817 +3 1957 2258 2191 +3 2272 2258 1957 +3 2281 2272 1817 +3 775 937 946 +3 937 1068 946 +3 773 937 775 +3 628 773 630 +3 628 630 372 +3 630 386 372 +3 386 344 372 +3 344 1 372 +3 1 626 372 +3 614 626 1 +3 614 1 365 +3 1 615 365 +3 760 615 1 +3 760 1 906 +3 1 1053 906 +3 1135 1053 1 +3 1135 1 1259 +3 1 2294 1259 +3 2294 1440 1259 +3 1526 1440 2294 +3 1526 2294 1622 +3 2294 1817 1622 +3 2281 1817 2294 +3 2281 2294 2300 +3 6296 6394 6542 +3 7276 7342 7432 +3 8250 8182 7974 +3 7198 7078 7284 +3 7582 7665 7666 +3 7582 7666 7528 +3 7582 7528 7490 +3 7528 7432 7490 +3 7432 7398 7490 +3 7342 7398 7432 +3 7275 7342 7276 +3 7275 7276 7192 +3 7276 7076 7192 +3 7076 7140 7192 +3 7042 7140 7076 +3 7042 7076 6978 +3 7042 6978 6948 +3 6978 6880 6948 +3 6880 6879 6948 +3 6790 6879 6880 +3 6790 6880 6686 +3 6790 6686 6650 +3 6686 6542 6650 +3 6542 6506 6650 +3 6394 6506 6542 +3 6295 6394 6296 +3 6295 6296 6400 +3 6296 6544 6400 +3 6544 6512 6400 +3 6656 6512 6544 +3 6656 6544 6688 +3 6656 6688 6796 +3 6688 6888 6796 +3 6888 6887 6796 +3 6954 6887 6888 +3 6954 6888 6980 +3 6954 6980 7048 +3 6980 7078 7048 +3 7078 7146 7048 +3 7198 7146 7078 +3 7283 7198 7284 +3 7283 7284 7348 +3 7284 7434 7348 +3 7434 7404 7348 +3 7496 7404 7434 +3 7496 7434 7530 +3 7496 7530 7588 +3 7530 7674 7588 +3 7674 7673 7588 +3 7786 7673 7674 +3 7786 7674 7822 +3 7786 7822 7930 +3 7822 7974 7930 +3 7974 8074 7930 +3 8182 8074 7974 +3 8249 8182 8250 +3 8249 8250 8176 +3 8250 7972 8176 +3 7972 8068 8176 +3 7924 8068 7972 +3 7924 7972 7820 +3 7924 7820 7780 +3 7820 7666 7780 +3 7666 7665 7780 +3 6280 6366 6536 +3 7256 7328 7426 +3 7646 7752 7814 +3 7814 7896 7966 +3 8234 8156 7968 +3 7266 7186 7072 +3 7568 7645 7646 +3 7568 7646 7522 +3 7568 7522 7476 +3 7522 7426 7476 +3 7426 7384 7476 +3 7328 7384 7426 +3 7255 7328 7256 +3 7255 7256 7178 +3 7256 7070 7178 +3 7070 7126 7178 +3 7028 7126 7070 +3 7028 7070 6972 +3 7028 6972 6934 +3 6972 6860 6934 +3 6860 6859 6934 +3 6762 6859 6860 +3 6762 6860 6680 +3 6762 6680 6622 +3 6680 6536 6622 +3 6536 6478 6622 +3 6366 6478 6536 +3 6279 6366 6280 +3 6279 6280 6374 +3 6280 6538 6374 +3 6538 6486 6374 +3 6630 6486 6538 +3 6630 6538 6682 +3 6630 6682 6770 +3 6682 6870 6770 +3 6870 6869 6770 +3 6942 6869 6870 +3 6942 6870 6974 +3 6942 6974 7036 +3 6974 7072 7036 +3 7072 7134 7036 +3 7186 7134 7072 +3 7265 7186 7266 +3 7265 7266 7336 +3 7266 7428 7336 +3 7428 7392 7336 +3 7484 7392 7428 +3 7484 7428 7524 +3 7484 7524 7576 +3 7524 7656 7576 +3 7656 7655 7576 +3 7760 7655 7656 +3 7760 7656 7816 +3 7760 7816 7904 +3 7816 7968 7904 +3 7968 8048 7904 +3 8156 8048 7968 +3 8233 8156 8234 +3 8233 8234 8148 +3 8234 7966 8148 +3 7966 8040 8148 +3 7896 8040 7966 +3 7752 7896 7814 +3 7645 7752 7646 +3 6264 6342 6532 +3 8216 8128 7964 +3 7246 7170 7068 +3 7629 7630 7556 +3 7556 7518 7464 +3 7240 7316 7422 +3 7239 7316 7240 +3 7239 7240 7166 +3 7240 7066 7166 +3 7066 7114 7166 +3 7016 7114 7066 +3 7016 7066 6968 +3 7016 6968 6922 +3 6968 6844 6922 +3 6844 6843 6922 +3 6738 6843 6844 +3 6738 6844 6676 +3 6738 6676 6598 +3 6676 6532 6598 +3 6532 6454 6598 +3 6342 6454 6532 +3 6263 6342 6264 +3 6263 6264 6346 +3 6264 6534 6346 +3 6534 6458 6346 +3 6602 6458 6534 +3 6602 6534 6678 +3 6602 6678 6742 +3 6678 6850 6742 +3 6850 6849 6742 +3 6926 6849 6850 +3 6926 6850 6970 +3 6926 6970 7020 +3 6970 7068 7020 +3 7068 7118 7020 +3 7170 7118 7068 +3 7245 7170 7246 +3 7245 7246 7320 +3 7246 7424 7320 +3 7424 7376 7320 +3 7468 7376 7424 +3 7468 7424 7520 +3 7468 7520 7560 +3 7520 7636 7560 +3 7636 7635 7560 +3 7732 7635 7636 +3 7732 7636 7812 +3 7732 7812 7876 +3 7812 7964 7876 +3 7964 8020 7876 +3 8128 8020 7964 +3 8215 8128 8216 +3 8215 8216 8124 +3 8216 7962 8124 +3 7962 8016 8124 +3 7872 7962 7810 +3 8016 7962 7872 +3 7728 7810 7630 +3 7872 7810 7728 +3 7464 7422 7372 +3 7422 7316 7372 +3 7518 7422 7464 +3 7630 7518 7556 +3 7728 7630 7629 +3 6250 6318 6528 +3 7960 7860 7808 +3 7808 7716 7624 +3 7234 7162 7064 +3 7614 7544 7613 +3 7544 7514 7452 +3 7224 7304 7418 +3 7223 7304 7224 +3 7223 7224 7154 +3 7224 7062 7154 +3 7062 7102 7154 +3 7004 7102 7062 +3 7004 7062 6964 +3 7004 6964 6910 +3 6964 6828 6910 +3 6828 6827 6910 +3 6714 6827 6828 +3 6714 6828 6672 +3 6714 6672 6574 +3 6672 6528 6574 +3 6528 6430 6574 +3 6318 6430 6528 +3 6249 6318 6250 +3 6249 6250 6326 +3 6250 6530 6326 +3 6530 6438 6326 +3 6582 6438 6530 +3 6582 6530 6674 +3 6582 6674 6722 +3 6674 6838 6722 +3 6838 6837 6722 +3 6918 6837 6838 +3 6918 6838 6966 +3 6918 6966 7012 +3 6966 7064 7012 +3 7064 7110 7012 +3 7162 7110 7064 +3 7233 7162 7234 +3 7233 7234 7312 +3 7234 7420 7312 +3 7420 7368 7312 +3 7460 7368 7420 +3 7460 7420 7516 +3 7460 7516 7552 +3 7516 7624 7552 +3 7624 7623 7552 +3 7716 7623 7624 +3 7860 7716 7808 +3 8004 7860 7960 +3 8004 7960 8112 +3 7960 8206 8112 +3 8206 8205 8112 +3 8104 8205 8206 +3 8104 8206 7958 +3 8104 7958 7996 +3 7852 7958 7806 +3 7996 7958 7852 +3 7708 7806 7614 +3 7852 7806 7708 +3 7452 7418 7360 +3 7418 7304 7360 +3 7514 7418 7452 +3 7614 7514 7544 +3 7708 7614 7613 +3 4298 4396 4544 +3 5898 5938 5794 +3 5940 5904 5796 +3 5796 5760 5652 +3 5272 5190 5076 +3 5643 5644 5564 +3 5564 5506 5472 +3 5264 5328 5414 +3 5263 5328 5264 +3 5263 5264 5184 +3 5264 5074 5184 +3 5074 5128 5184 +3 5040 5128 5074 +3 5040 5074 4982 +3 5040 4982 4948 +3 4982 4884 4948 +3 4884 4883 4948 +3 4792 4883 4884 +3 4792 4884 4692 +3 4792 4692 4648 +3 4692 4544 4648 +3 4544 4504 4648 +3 4396 4504 4544 +3 4297 4396 4298 +3 4297 4298 4402 +3 4298 4546 4402 +3 4546 4510 4402 +3 4654 4510 4546 +3 4654 4546 4694 +3 4654 4694 4798 +3 4694 4892 4798 +3 4892 4891 4798 +3 4954 4891 4892 +3 4954 4892 4984 +3 4954 4984 5046 +3 4984 5076 5046 +3 5076 5134 5046 +3 5190 5134 5076 +3 5271 5190 5272 +3 5271 5272 5334 +3 5272 5416 5334 +3 5416 5386 5334 +3 5478 5386 5416 +3 5478 5416 5508 +3 5478 5508 5570 +3 5508 5652 5570 +3 5652 5651 5570 +3 5760 5651 5652 +3 5904 5760 5796 +3 6048 5904 5940 +3 6048 5940 6152 +3 5940 6224 6152 +3 6224 6223 6152 +3 6146 6223 6224 +3 6146 6224 5938 +3 6146 5938 6042 +3 5938 5898 6042 +3 5754 5794 5644 +3 5898 5794 5754 +3 5472 5414 5380 +3 5414 5328 5380 +3 5506 5414 5472 +3 5644 5506 5564 +3 5754 5644 5643 +3 4282 4368 4538 +3 5244 5314 5408 +3 6208 6126 5934 +3 5254 5178 5070 +3 5550 5623 5624 +3 5550 5624 5500 +3 5550 5500 5458 +3 5500 5408 5458 +3 5408 5366 5458 +3 5314 5366 5408 +3 5243 5314 5244 +3 5243 5244 5170 +3 5244 5068 5170 +3 5068 5114 5170 +3 5026 5114 5068 +3 5026 5068 4976 +3 5026 4976 4934 +3 4976 4864 4934 +3 4864 4863 4934 +3 4764 4863 4864 +3 4764 4864 4686 +3 4764 4686 4620 +3 4686 4538 4620 +3 4538 4476 4620 +3 4368 4476 4538 +3 4281 4368 4282 +3 4281 4282 4376 +3 4282 4540 4376 +3 4540 4484 4376 +3 4628 4484 4540 +3 4628 4540 4688 +3 4628 4688 4772 +3 4688 4874 4772 +3 4874 4873 4772 +3 4942 4873 4874 +3 4942 4874 4978 +3 4942 4978 5034 +3 4978 5070 5034 +3 5070 5122 5034 +3 5178 5122 5070 +3 5253 5178 5254 +3 5253 5254 5322 +3 5254 5410 5322 +3 5410 5374 5322 +3 5466 5374 5410 +3 5466 5410 5502 +3 5466 5502 5558 +3 5502 5634 5558 +3 5634 5633 5558 +3 5734 5633 5634 +3 5734 5634 5790 +3 5734 5790 5878 +3 5790 5934 5878 +3 5934 6022 5878 +3 6126 6022 5934 +3 6207 6126 6208 +3 6207 6208 6118 +3 6208 5932 6118 +3 5932 6014 6118 +3 5870 6014 5932 +3 5870 5932 5788 +3 5870 5788 5726 +3 5788 5624 5726 +3 5624 5623 5726 +3 4264 4344 4530 +3 5224 5302 5400 +3 6190 6098 5926 +3 5230 5162 5062 +3 5538 5603 5604 +3 5538 5604 5492 +3 5538 5492 5446 +3 5492 5400 5446 +3 5400 5354 5446 +3 5302 5354 5400 +3 5223 5302 5224 +3 5223 5224 5158 +3 5224 5060 5158 +3 5060 5102 5158 +3 5014 5102 5060 +3 5014 5060 4968 +3 5014 4968 4922 +3 4968 4844 4922 +3 4844 4843 4922 +3 4740 4843 4844 +3 4740 4844 4678 +3 4740 4678 4596 +3 4678 4530 4596 +3 4530 4452 4596 +3 4344 4452 4530 +3 4263 4344 4264 +3 4263 4264 4348 +3 4264 4532 4348 +3 4532 4456 4348 +3 4600 4456 4532 +3 4600 4532 4680 +3 4600 4680 4744 +3 4680 4850 4744 +3 4850 4849 4744 +3 4926 4849 4850 +3 4926 4850 4970 +3 4926 4970 5018 +3 4970 5062 5018 +3 5062 5106 5018 +3 5162 5106 5062 +3 5229 5162 5230 +3 5229 5230 5306 +3 5230 5402 5306 +3 5402 5358 5306 +3 5450 5358 5402 +3 5450 5402 5494 +3 5450 5494 5542 +3 5494 5610 5542 +3 5610 5609 5542 +3 5706 5609 5610 +3 5706 5610 5782 +3 5706 5782 5850 +3 5782 5926 5850 +3 5926 5994 5850 +3 6098 5994 5926 +3 6189 6098 6190 +3 6189 6190 6094 +3 6190 5924 6094 +3 5924 5990 6094 +3 5846 5990 5924 +3 5846 5924 5780 +3 5846 5780 5702 +3 5780 5604 5702 +3 5604 5603 5702 +3 4250 4320 4526 +3 5588 5678 5776 +3 5776 5822 5920 +3 6176 6078 5922 +3 5218 5154 5058 +3 5587 5588 5526 +3 5526 5488 5434 +3 5208 5290 5396 +3 5207 5290 5208 +3 5207 5208 5146 +3 5208 5056 5146 +3 5056 5090 5146 +3 5002 5090 5056 +3 5002 5056 4964 +3 5002 4964 4910 +3 4964 4828 4910 +3 4828 4827 4910 +3 4716 4827 4828 +3 4716 4828 4674 +3 4716 4674 4572 +3 4674 4526 4572 +3 4526 4428 4572 +3 4320 4428 4526 +3 4249 4320 4250 +3 4249 4250 4328 +3 4250 4528 4328 +3 4528 4436 4328 +3 4580 4436 4528 +3 4580 4528 4676 +3 4580 4676 4724 +3 4676 4838 4724 +3 4838 4837 4724 +3 4918 4837 4838 +3 4918 4838 4966 +3 4918 4966 5010 +3 4966 5058 5010 +3 5058 5098 5010 +3 5154 5098 5058 +3 5217 5154 5218 +3 5217 5218 5298 +3 5218 5398 5298 +3 5398 5350 5298 +3 5442 5350 5398 +3 5442 5398 5490 +3 5442 5490 5534 +3 5490 5598 5534 +3 5598 5597 5534 +3 5686 5597 5598 +3 5686 5598 5778 +3 5686 5778 5830 +3 5778 5922 5830 +3 5922 5974 5830 +3 6078 5974 5922 +3 6175 6078 6176 +3 6175 6176 6070 +3 6176 5920 6070 +3 5920 5966 6070 +3 5822 5966 5920 +3 5678 5822 5776 +3 5434 5396 5342 +3 5396 5290 5342 +3 5488 5396 5434 +3 5588 5488 5526 +3 5678 5588 5587 +3 2425 2426 2502 +3 3040 3162 3064 +3 3040 3064 2989 +3 3040 2989 2963 +3 2989 2917 2963 +3 2917 2823 2963 +3 2734 2823 2822 +3 2823 2917 2822 +3 2712 2823 2734 +3 2712 2734 2630 +3 2712 2630 2595 +3 2426 2501 2609 +3 2726 2792 2874 +3 3210 3266 3343 +3 4072 4073 4001 +3 4073 3812 4001 +3 3812 3901 4001 +3 3778 3901 3812 +3 3778 3812 3679 +3 3778 3679 3645 +3 3679 3537 3645 +3 3537 3536 3645 +3 3459 3536 3537 +3 3459 3537 3419 +3 3459 3419 3387 +3 3419 3343 3387 +3 3343 3312 3387 +3 3266 3312 3343 +3 3209 3266 3210 +3 3209 3210 3144 +3 3210 3054 3144 +3 3054 3097 3144 +3 3022 3097 3054 +3 3022 3054 2977 +3 3022 2977 2950 +3 2977 2874 2950 +3 2874 2873 2950 +3 2792 2873 2874 +3 2688 2792 2726 +3 2688 2726 2609 +3 2688 2609 2584 +3 2609 2501 2584 +3 2502 2595 2525 +3 2595 2630 2525 +3 2426 2595 2502 +3 2501 2426 2425 +3 2409 2476 2607 +3 3677 3750 3810 +3 3811 3757 3678 +3 3678 3624 3529 +3 3202 3137 3053 +3 3520 3521 3446 +3 3417 3374 3446 +3 3195 3253 3341 +3 3194 3253 3195 +3 3194 3195 3131 +3 3195 3052 3131 +3 3052 3084 3131 +3 3009 3084 3052 +3 3009 3052 2975 +3 3009 2975 2937 +3 2975 2859 2937 +3 2859 2858 2937 +3 2768 2858 2859 +3 2768 2859 2724 +3 2768 2724 2664 +3 2724 2607 2664 +3 2607 2559 2664 +3 2476 2559 2607 +3 2408 2476 2409 +3 2408 2409 2481 +3 2409 2608 2481 +3 2608 2564 2481 +3 2669 2564 2608 +3 2669 2608 2725 +3 2669 2725 2773 +3 2725 2866 2773 +3 2866 2865 2773 +3 2943 2865 2866 +3 2943 2866 2976 +3 2943 2976 3015 +3 2976 3053 3015 +3 3053 3090 3015 +3 3137 3090 3053 +3 3201 3137 3202 +3 3201 3202 3259 +3 3202 3342 3259 +3 3342 3305 3259 +3 3380 3305 3342 +3 3380 3342 3418 +3 3380 3418 3452 +3 3418 3529 3452 +3 3529 3528 3452 +3 3624 3528 3529 +3 3757 3624 3678 +3 3880 3757 3811 +3 3880 3811 3980 +3 3811 4057 3980 +3 4057 4056 3980 +3 3973 4056 4057 +3 3973 4057 3810 +3 3973 3810 3873 +3 3810 3750 3873 +3 3617 3677 3521 +3 3750 3677 3617 +3 3374 3341 3299 +3 3341 3253 3299 +3 3417 3341 3374 +3 3521 3417 3446 +3 3617 3521 3520 +3 2397 2459 2605 +3 3508 3595 3675 +3 3808 3951 4041 +3 3809 3732 3676 +3 3676 3599 3513 +3 3188 3125 3051 +3 3507 3508 3437 +3 3437 3415 3365 +3 3184 3244 3339 +3 3183 3244 3184 +3 3183 3184 3122 +3 3184 3050 3122 +3 3050 3075 3122 +3 3000 3075 3050 +3 3000 3050 2973 +3 3000 2973 2928 +3 2973 2845 2928 +3 2845 2844 2928 +3 2751 2844 2845 +3 2751 2845 2722 +3 2751 2722 2647 +3 2722 2605 2647 +3 2605 2542 2647 +3 2459 2542 2605 +3 2396 2459 2397 +3 2396 2397 2461 +3 2397 2606 2461 +3 2606 2544 2461 +3 2649 2544 2606 +3 2649 2606 2723 +3 2649 2723 2753 +3 2723 2852 2753 +3 2852 2851 2753 +3 2931 2851 2852 +3 2931 2852 2974 +3 2931 2974 3003 +3 2974 3051 3003 +3 3051 3078 3003 +3 3125 3078 3051 +3 3187 3125 3188 +3 3187 3188 3247 +3 3188 3340 3247 +3 3340 3293 3247 +3 3368 3293 3340 +3 3368 3340 3416 +3 3368 3416 3440 +3 3416 3513 3440 +3 3513 3512 3440 +3 3599 3512 3513 +3 3732 3599 3676 +3 3855 3732 3809 +3 3855 3809 3955 +3 3809 4041 3955 +3 4041 4040 3955 +3 3951 4040 4041 +3 3851 3951 3808 +3 3851 3808 3728 +3 3808 3675 3728 +3 3675 3595 3728 +3 3365 3339 3290 +3 3339 3244 3290 +3 3415 3339 3365 +3 3508 3415 3437 +3 3595 3508 3507 +3 2392 2451 2603 +3 3495 3576 3673 +3 3806 3932 4032 +3 3807 3716 3674 +3 3674 3583 3503 +3 3181 3120 3049 +3 3494 3495 3433 +3 3433 3413 3361 +3 3178 3240 3337 +3 3177 3240 3178 +3 3177 3178 3118 +3 3178 3048 3118 +3 3048 3071 3118 +3 2996 3071 3048 +3 2996 3048 2971 +3 2996 2971 2924 +3 2971 2838 2924 +3 2838 2837 2924 +3 2743 2837 2838 +3 2743 2838 2720 +3 2743 2720 2639 +3 2720 2603 2639 +3 2603 2534 2639 +3 2451 2534 2603 +3 2391 2451 2392 +3 2391 2392 2453 +3 2392 2604 2453 +3 2604 2536 2453 +3 2641 2536 2604 +3 2641 2604 2721 +3 2641 2721 2745 +3 2721 2841 2745 +3 2841 2840 2745 +3 2926 2840 2841 +3 2926 2841 2972 +3 2926 2972 2998 +3 2972 3049 2998 +3 3049 3073 2998 +3 3120 3073 3049 +3 3180 3120 3181 +3 3180 3181 3242 +3 3181 3338 3242 +3 3338 3288 3242 +3 3363 3288 3338 +3 3363 3338 3414 +3 3363 3414 3435 +3 3414 3503 3435 +3 3503 3502 3435 +3 3583 3502 3503 +3 3716 3583 3674 +3 3839 3716 3807 +3 3839 3807 3939 +3 3807 4032 3939 +3 4032 4031 3939 +3 3932 4031 4032 +3 3832 3932 3806 +3 3832 3806 3709 +3 3806 3673 3709 +3 3673 3576 3709 +3 3361 3337 3286 +3 3337 3240 3286 +3 3413 3337 3361 +3 3495 3413 3433 +3 3576 3495 3494 +3 411 506 635 +3 1986 1940 1839 +3 1839 1807 1697 +3 1326 1255 1157 +3 1687 1688 1597 +3 1597 1546 1513 +3 1318 1379 1460 +3 1317 1379 1318 +3 1317 1318 1249 +3 1318 1155 1249 +3 1155 1201 1249 +3 1123 1201 1155 +3 1123 1155 1073 +3 1123 1073 1043 +3 1073 973 1043 +3 973 972 1043 +3 870 972 973 +3 870 973 780 +3 870 780 734 +3 780 635 734 +3 635 601 734 +3 506 601 635 +3 410 506 411 +3 410 411 512 +3 411 637 512 +3 637 607 512 +3 740 607 637 +3 740 637 782 +3 740 782 876 +3 782 981 876 +3 981 980 876 +3 1049 980 981 +3 1049 981 1075 +3 1049 1075 1129 +3 1075 1157 1129 +3 1157 1207 1129 +3 1255 1207 1157 +3 1325 1255 1326 +3 1325 1326 1385 +3 1326 1462 1385 +3 1462 1437 1385 +3 1519 1437 1462 +3 1519 1462 1548 +3 1519 1548 1603 +3 1548 1697 1603 +3 1697 1696 1603 +3 1807 1696 1697 +3 1940 1807 1839 +3 2073 1940 1986 +3 2073 1986 2170 +3 1986 2244 2170 +3 2244 2243 2170 +3 2164 2243 2244 +3 2164 2244 1984 +3 2164 1984 2067 +3 1934 1984 1837 +3 2067 1984 1934 +3 1801 1837 1688 +3 1934 1837 1801 +3 1513 1460 1431 +3 1460 1379 1431 +3 1546 1460 1513 +3 1688 1546 1597 +3 1801 1688 1687 +3 393 477 631 +3 1669 1773 1833 +3 1980 2135 2227 +3 1982 1912 1835 +3 1835 1779 1678 +3 1306 1241 1153 +3 1668 1669 1583 +3 1583 1542 1499 +3 1298 1365 1456 +3 1297 1365 1298 +3 1297 1298 1235 +3 1298 1151 1235 +3 1151 1187 1235 +3 1109 1187 1151 +3 1109 1151 1069 +3 1109 1069 1029 +3 1069 954 1029 +3 954 953 1029 +3 842 953 954 +3 842 954 776 +3 842 776 706 +3 776 631 706 +3 631 573 706 +3 477 573 631 +3 392 477 393 +3 392 393 483 +3 393 633 483 +3 633 579 483 +3 712 579 633 +3 712 633 778 +3 712 778 848 +3 778 963 848 +3 963 962 848 +3 1035 962 963 +3 1035 963 1071 +3 1035 1071 1115 +3 1071 1153 1115 +3 1153 1193 1115 +3 1241 1193 1153 +3 1305 1241 1306 +3 1305 1306 1371 +3 1306 1458 1371 +3 1458 1423 1371 +3 1505 1423 1458 +3 1505 1458 1544 +3 1505 1544 1589 +3 1544 1678 1589 +3 1678 1677 1589 +3 1779 1677 1678 +3 1912 1779 1835 +3 2045 1912 1982 +3 2045 1982 2141 +3 1982 2227 2141 +3 2227 2226 2141 +3 2135 2226 2227 +3 2039 2135 1980 +3 2039 1980 1906 +3 1980 1833 1906 +3 1833 1773 1906 +3 1499 1456 1417 +3 1456 1365 1417 +3 1542 1456 1499 +3 1669 1542 1583 +3 1773 1669 1668 +3 453 627 379 +3 1651 1749 1829 +3 1829 1882 1976 +3 2213 2117 1978 +3 1290 1229 1149 +3 1650 1651 1571 +3 1571 1538 1487 +3 1282 1353 1452 +3 1281 1353 1282 +3 1281 1282 1223 +3 1282 1147 1223 +3 1147 1175 1223 +3 1097 1175 1147 +3 1097 1147 1065 +3 1097 1065 1017 +3 1065 936 1017 +3 936 935 1017 +3 818 935 936 +3 818 936 772 +3 818 772 682 +3 772 627 682 +3 627 549 682 +3 453 549 627 +3 378 453 379 +3 378 379 459 +3 379 629 459 +3 629 555 459 +3 688 555 629 +3 688 629 774 +3 688 774 824 +3 774 945 824 +3 945 944 824 +3 1023 944 945 +3 1023 945 1067 +3 1023 1067 1103 +3 1067 1149 1103 +3 1149 1181 1103 +3 1229 1181 1149 +3 1289 1229 1290 +3 1289 1290 1359 +3 1290 1454 1359 +3 1454 1411 1359 +3 1493 1411 1454 +3 1493 1454 1540 +3 1493 1540 1577 +3 1540 1660 1577 +3 1660 1659 1577 +3 1755 1659 1660 +3 1755 1660 1831 +3 1755 1831 1888 +3 1831 1978 1888 +3 1978 2021 1888 +3 2117 2021 1978 +3 2212 2117 2213 +3 2212 2213 2111 +3 2213 1976 2111 +3 1976 2015 2111 +3 1882 2015 1976 +3 1749 1882 1829 +3 1487 1452 1405 +3 1452 1353 1405 +3 1538 1452 1487 +3 1651 1538 1571 +3 1749 1651 1650 +3 440 624 369 +3 1276 1350 1449 +3 2203 2101 1974 +3 1278 1221 1145 +3 1568 1638 1639 +3 1568 1639 1535 +3 1568 1535 1484 +3 1535 1449 1484 +3 1449 1402 1484 +3 1350 1402 1449 +3 1275 1350 1276 +3 1275 1276 1220 +3 1276 1144 1220 +3 1144 1172 1220 +3 1094 1172 1144 +3 1094 1144 1062 +3 1094 1062 1014 +3 1062 923 1014 +3 923 922 1014 +3 805 922 923 +3 805 923 769 +3 805 769 669 +3 769 624 669 +3 624 536 669 +3 440 536 624 +3 368 440 369 +3 368 369 443 +3 369 625 443 +3 625 539 443 +3 672 539 625 +3 672 625 770 +3 672 770 808 +3 770 927 808 +3 927 926 808 +3 1015 926 927 +3 1015 927 1063 +3 1015 1063 1095 +3 1063 1145 1095 +3 1145 1173 1095 +3 1221 1173 1145 +3 1277 1221 1278 +3 1277 1278 1351 +3 1278 1450 1351 +3 1450 1403 1351 +3 1485 1403 1450 +3 1485 1450 1536 +3 1485 1536 1569 +3 1536 1642 1569 +3 1642 1641 1569 +3 1739 1641 1642 +3 1739 1642 1827 +3 1739 1827 1872 +3 1827 1974 1872 +3 1974 2005 1872 +3 2101 2005 1974 +3 2202 2101 2203 +3 2202 2203 2099 +3 2203 1973 2099 +3 1973 2003 2099 +3 1870 2003 1973 +3 1870 1973 1826 +3 1870 1826 1737 +3 1826 1639 1737 +3 1639 1638 1737 +3 6236 6309 6525 +3 7213 7303 7415 +3 7603 7699 7803 +3 7803 7843 7955 +3 8192 8096 7956 +3 7214 7154 7060 +3 7543 7612 7603 +3 7543 7603 7511 +3 7543 7511 7451 +3 7511 7415 7451 +3 7415 7359 7451 +3 7303 7359 7415 +3 7222 7303 7213 +3 7222 7213 7153 +3 7213 7059 7153 +3 7059 7101 7153 +3 7003 7101 7059 +3 7003 7059 6961 +3 7003 6961 6909 +3 6961 6817 6909 +3 6817 6826 6909 +3 6705 6826 6817 +3 6705 6817 6669 +3 6705 6669 6565 +3 6669 6525 6565 +3 6525 6421 6565 +3 6309 6421 6525 +3 6240 6309 6236 +3 6240 6236 6310 +3 6236 6526 6310 +3 6526 6422 6310 +3 6566 6422 6526 +3 6566 6526 6670 +3 6566 6670 6706 +3 6670 6818 6706 +3 6818 6827 6706 +3 6910 6827 6818 +3 6910 6818 6962 +3 6910 6962 7004 +3 6962 7060 7004 +3 7060 7102 7004 +3 7154 7102 7060 +3 7223 7154 7214 +3 7223 7214 7304 +3 7214 7416 7304 +3 7416 7360 7304 +3 7452 7360 7416 +3 7452 7416 7512 +3 7452 7512 7544 +3 7512 7604 7544 +3 7604 7613 7544 +3 7700 7613 7604 +3 7700 7604 7804 +3 7700 7804 7844 +3 7804 7956 7844 +3 7956 7988 7844 +3 8096 7988 7956 +3 8196 8096 8192 +3 8196 8192 8095 +3 8192 7955 8095 +3 7955 7987 8095 +3 7843 7987 7955 +3 7699 7843 7803 +3 7612 7699 7603 +3 6307 6523 6235 +3 7211 7301 7413 +3 7601 7697 7801 +3 7801 7841 7953 +3 7954 8191 8094 +3 7212 7152 7058 +3 7541 7610 7601 +3 7541 7601 7509 +3 7541 7509 7449 +3 7509 7413 7449 +3 7413 7357 7449 +3 7301 7357 7413 +3 7220 7301 7211 +3 7220 7211 7151 +3 7211 7057 7151 +3 7057 7099 7151 +3 7001 7099 7057 +3 7001 7057 6959 +3 7001 6959 6907 +3 6959 6815 6907 +3 6815 6824 6907 +3 6703 6824 6815 +3 6703 6815 6667 +3 6703 6667 6563 +3 6667 6523 6563 +3 6523 6419 6563 +3 6307 6419 6523 +3 6239 6307 6235 +3 6239 6235 6308 +3 6235 6524 6308 +3 6524 6420 6308 +3 6564 6420 6524 +3 6564 6524 6668 +3 6564 6668 6704 +3 6668 6816 6704 +3 6816 6825 6704 +3 6908 6825 6816 +3 6908 6816 6960 +3 6908 6960 7002 +3 6960 7058 7002 +3 7058 7100 7002 +3 7152 7100 7058 +3 7221 7152 7212 +3 7221 7212 7302 +3 7212 7414 7302 +3 7414 7358 7302 +3 7450 7358 7414 +3 7450 7414 7510 +3 7450 7510 7542 +3 7510 7602 7542 +3 7602 7611 7542 +3 7698 7611 7602 +3 7698 7602 7802 +3 7698 7802 7842 +3 7802 7954 7842 +3 7954 7986 7842 +3 8094 7986 7954 +3 8195 8094 8191 +3 8195 8191 8093 +3 8191 7953 8093 +3 7953 7985 8093 +3 7841 7985 7953 +3 7697 7841 7801 +3 7610 7697 7601 +3 6234 6305 6521 +3 7695 7799 7599 +3 7951 8091 8190 +3 7952 7840 7800 +3 7800 7696 7600 +3 7150 7056 7210 +3 7599 7539 7608 +3 7507 7447 7539 +3 7209 7299 7411 +3 7218 7299 7209 +3 7218 7209 7149 +3 7209 7055 7149 +3 7055 7097 7149 +3 6999 7097 7055 +3 6999 7055 6957 +3 6999 6957 6905 +3 6957 6813 6905 +3 6813 6822 6905 +3 6701 6822 6813 +3 6701 6813 6665 +3 6701 6665 6561 +3 6665 6521 6561 +3 6521 6417 6561 +3 6305 6417 6521 +3 6238 6305 6234 +3 6238 6234 6306 +3 6234 6522 6306 +3 6522 6418 6306 +3 6562 6418 6522 +3 6562 6522 6666 +3 6562 6666 6702 +3 6666 6814 6702 +3 6814 6823 6702 +3 6906 6823 6814 +3 6906 6814 6958 +3 6906 6958 7000 +3 6958 7056 7000 +3 7056 7098 7000 +3 7150 7098 7056 +3 7219 7150 7210 +3 7219 7210 7300 +3 7210 7412 7300 +3 7412 7356 7300 +3 7448 7356 7412 +3 7448 7412 7508 +3 7448 7508 7540 +3 7508 7600 7540 +3 7600 7609 7540 +3 7696 7609 7600 +3 7840 7696 7800 +3 7984 7840 7952 +3 7984 7952 8092 +3 7952 8190 8092 +3 8190 8194 8092 +3 8091 8194 8190 +3 7983 8091 7951 +3 7983 7951 7839 +3 7951 7799 7839 +3 7799 7695 7839 +3 7447 7411 7355 +3 7411 7299 7355 +3 7507 7411 7447 +3 7599 7507 7539 +3 7695 7599 7608 +3 6233 6303 6519 +3 7797 7837 7949 +3 7950 7838 7798 +3 7798 7694 7598 +3 7208 7148 7054 +3 7606 7597 7537 +3 7537 7505 7445 +3 7207 7297 7409 +3 7216 7297 7207 +3 7216 7207 7147 +3 7207 7053 7147 +3 7053 7095 7147 +3 6997 7095 7053 +3 6997 7053 6955 +3 6997 6955 6903 +3 6955 6811 6903 +3 6811 6820 6903 +3 6699 6820 6811 +3 6699 6811 6663 +3 6699 6663 6559 +3 6663 6519 6559 +3 6519 6415 6559 +3 6303 6415 6519 +3 6237 6303 6233 +3 6237 6233 6304 +3 6233 6520 6304 +3 6520 6416 6304 +3 6560 6416 6520 +3 6560 6520 6664 +3 6560 6664 6700 +3 6664 6812 6700 +3 6812 6821 6700 +3 6904 6821 6812 +3 6904 6812 6956 +3 6904 6956 6998 +3 6956 7054 6998 +3 7054 7096 6998 +3 7148 7096 7054 +3 7217 7148 7208 +3 7217 7208 7298 +3 7208 7410 7298 +3 7410 7354 7298 +3 7446 7354 7410 +3 7446 7410 7506 +3 7446 7506 7538 +3 7506 7598 7538 +3 7598 7607 7538 +3 7694 7607 7598 +3 7838 7694 7798 +3 7982 7838 7950 +3 7982 7950 8090 +3 7950 8189 8090 +3 8189 8193 8090 +3 8089 8193 8189 +3 8089 8189 7949 +3 8089 7949 7981 +3 7949 7837 7981 +3 7693 7797 7597 +3 7837 7797 7693 +3 7445 7409 7353 +3 7409 7297 7353 +3 7505 7409 7445 +3 7597 7505 7537 +3 7693 7597 7606 +3 4236 4311 4523 +3 5197 5289 5393 +3 5577 5669 5773 +3 5773 5813 5917 +3 6162 6062 5918 +3 5198 5146 5054 +3 5525 5586 5577 +3 5525 5577 5485 +3 5525 5485 5433 +3 5485 5393 5433 +3 5393 5341 5433 +3 5289 5341 5393 +3 5206 5289 5197 +3 5206 5197 5145 +3 5197 5053 5145 +3 5053 5089 5145 +3 5001 5089 5053 +3 5001 5053 4961 +3 5001 4961 4909 +3 4961 4817 4909 +3 4817 4826 4909 +3 4707 4826 4817 +3 4707 4817 4671 +3 4707 4671 4563 +3 4671 4523 4563 +3 4523 4419 4563 +3 4311 4419 4523 +3 4240 4311 4236 +3 4240 4236 4312 +3 4236 4524 4312 +3 4524 4420 4312 +3 4564 4420 4524 +3 4564 4524 4672 +3 4564 4672 4708 +3 4672 4818 4708 +3 4818 4827 4708 +3 4910 4827 4818 +3 4910 4818 4962 +3 4910 4962 5002 +3 4962 5054 5002 +3 5054 5090 5002 +3 5146 5090 5054 +3 5207 5146 5198 +3 5207 5198 5290 +3 5198 5394 5290 +3 5394 5342 5290 +3 5434 5342 5394 +3 5434 5394 5486 +3 5434 5486 5526 +3 5486 5578 5526 +3 5578 5587 5526 +3 5670 5587 5578 +3 5670 5578 5774 +3 5670 5774 5814 +3 5774 5918 5814 +3 5918 5958 5814 +3 6062 5958 5918 +3 6166 6062 6162 +3 6166 6162 6061 +3 6162 5917 6061 +3 5917 5957 6061 +3 5813 5957 5917 +3 5669 5813 5773 +3 5586 5669 5577 +3 4235 4309 4521 +3 5575 5667 5771 +3 5771 5811 5915 +3 5916 6161 6060 +3 5196 5144 5052 +3 5575 5523 5584 +3 5523 5483 5431 +3 5195 5287 5391 +3 5204 5287 5195 +3 5204 5195 5143 +3 5195 5051 5143 +3 5051 5087 5143 +3 4999 5087 5051 +3 4999 5051 4959 +3 4999 4959 4907 +3 4959 4815 4907 +3 4815 4824 4907 +3 4705 4824 4815 +3 4705 4815 4669 +3 4705 4669 4561 +3 4669 4521 4561 +3 4521 4417 4561 +3 4309 4417 4521 +3 4239 4309 4235 +3 4239 4235 4310 +3 4235 4522 4310 +3 4522 4418 4310 +3 4562 4418 4522 +3 4562 4522 4670 +3 4562 4670 4706 +3 4670 4816 4706 +3 4816 4825 4706 +3 4908 4825 4816 +3 4908 4816 4960 +3 4908 4960 5000 +3 4960 5052 5000 +3 5052 5088 5000 +3 5144 5088 5052 +3 5205 5144 5196 +3 5205 5196 5288 +3 5196 5392 5288 +3 5392 5340 5288 +3 5432 5340 5392 +3 5432 5392 5484 +3 5432 5484 5524 +3 5484 5576 5524 +3 5576 5585 5524 +3 5668 5585 5576 +3 5668 5576 5772 +3 5668 5772 5812 +3 5772 5916 5812 +3 5916 5956 5812 +3 6060 5956 5916 +3 6165 6060 6161 +3 6165 6161 6059 +3 6161 5915 6059 +3 5915 5955 6059 +3 5811 5955 5915 +3 5667 5811 5771 +3 5431 5391 5339 +3 5391 5287 5339 +3 5483 5391 5431 +3 5575 5483 5523 +3 5667 5575 5584 +3 4307 4519 4234 +3 5914 5810 5770 +3 5770 5666 5574 +3 5194 5142 5050 +3 5582 5573 5521 +3 5521 5481 5429 +3 5193 5285 5389 +3 5202 5285 5193 +3 5202 5193 5141 +3 5193 5049 5141 +3 5049 5085 5141 +3 4997 5085 5049 +3 4997 5049 4957 +3 4997 4957 4905 +3 4957 4813 4905 +3 4813 4822 4905 +3 4703 4822 4813 +3 4703 4813 4667 +3 4703 4667 4559 +3 4667 4519 4559 +3 4519 4415 4559 +3 4307 4415 4519 +3 4238 4307 4234 +3 4238 4234 4308 +3 4234 4520 4308 +3 4520 4416 4308 +3 4560 4416 4520 +3 4560 4520 4668 +3 4560 4668 4704 +3 4668 4814 4704 +3 4814 4823 4704 +3 4906 4823 4814 +3 4906 4814 4958 +3 4906 4958 4998 +3 4958 5050 4998 +3 5050 5086 4998 +3 5142 5086 5050 +3 5203 5142 5194 +3 5203 5194 5286 +3 5194 5390 5286 +3 5390 5338 5286 +3 5430 5338 5390 +3 5430 5390 5482 +3 5430 5482 5522 +3 5482 5574 5522 +3 5574 5583 5522 +3 5666 5583 5574 +3 5810 5666 5770 +3 5954 5810 5914 +3 5954 5914 6058 +3 5914 6160 6058 +3 6160 6164 6058 +3 6057 6164 6160 +3 6057 6160 5913 +3 6057 5913 5953 +3 5809 5913 5769 +3 5953 5913 5809 +3 5665 5769 5573 +3 5809 5769 5665 +3 5429 5389 5337 +3 5389 5285 5337 +3 5481 5389 5429 +3 5573 5481 5521 +3 5665 5573 5582 +3 4233 4305 4517 +3 5571 5663 5767 +3 5767 5807 5911 +3 6159 6056 5912 +3 5192 5140 5048 +3 5580 5571 5519 +3 5519 5479 5427 +3 5191 5283 5387 +3 5200 5283 5191 +3 5200 5191 5139 +3 5191 5047 5139 +3 5047 5083 5139 +3 4995 5083 5047 +3 4995 5047 4955 +3 4995 4955 4903 +3 4955 4811 4903 +3 4811 4820 4903 +3 4701 4820 4811 +3 4701 4811 4665 +3 4701 4665 4557 +3 4665 4517 4557 +3 4517 4413 4557 +3 4305 4413 4517 +3 4237 4305 4233 +3 4237 4233 4306 +3 4233 4518 4306 +3 4518 4414 4306 +3 4558 4414 4518 +3 4558 4518 4666 +3 4558 4666 4702 +3 4666 4812 4702 +3 4812 4821 4702 +3 4904 4821 4812 +3 4904 4812 4956 +3 4904 4956 4996 +3 4956 5048 4996 +3 5048 5084 4996 +3 5140 5084 5048 +3 5201 5140 5192 +3 5201 5192 5284 +3 5192 5388 5284 +3 5388 5336 5284 +3 5428 5336 5388 +3 5428 5388 5480 +3 5428 5480 5520 +3 5480 5572 5520 +3 5572 5581 5520 +3 5664 5581 5572 +3 5664 5572 5768 +3 5664 5768 5808 +3 5768 5912 5808 +3 5912 5952 5808 +3 6056 5952 5912 +3 6163 6056 6159 +3 6163 6159 6055 +3 6159 5911 6055 +3 5911 5951 6055 +3 5807 5951 5911 +3 5663 5807 5767 +3 5427 5387 5335 +3 5387 5283 5335 +3 5479 5387 5427 +3 5571 5479 5519 +3 5663 5571 5580 +3 2448 2601 2385 +3 3169 3239 3335 +3 4020 3925 3805 +3 3170 3118 3047 +3 3432 3493 3486 +3 3432 3486 3411 +3 3432 3411 3360 +3 3411 3335 3360 +3 3335 3285 3360 +3 3239 3285 3335 +3 3176 3239 3169 +3 3176 3169 3117 +3 3169 3046 3117 +3 3046 3070 3117 +3 2995 3070 3046 +3 2995 3046 2969 +3 2995 2969 2923 +3 2969 2829 2923 +3 2829 2836 2923 +3 2740 2836 2829 +3 2740 2829 2718 +3 2740 2718 2636 +3 2718 2601 2636 +3 2601 2531 2636 +3 2448 2531 2601 +3 2389 2448 2385 +3 2389 2385 2449 +3 2385 2602 2449 +3 2602 2532 2449 +3 2637 2532 2602 +3 2637 2602 2719 +3 2637 2719 2741 +3 2719 2830 2741 +3 2830 2837 2741 +3 2924 2837 2830 +3 2924 2830 2970 +3 2924 2970 2996 +3 2970 3047 2996 +3 3047 3071 2996 +3 3118 3071 3047 +3 3177 3118 3170 +3 3177 3170 3240 +3 3170 3336 3240 +3 3336 3286 3240 +3 3361 3286 3336 +3 3361 3336 3412 +3 3361 3412 3433 +3 3412 3487 3433 +3 3487 3494 3433 +3 3569 3494 3487 +3 3569 3487 3672 +3 3569 3672 3702 +3 3672 3805 3702 +3 3805 3825 3702 +3 3925 3825 3805 +3 4024 3925 4020 +3 4024 4020 3924 +3 4020 3804 3924 +3 3804 3824 3924 +3 3701 3824 3804 +3 3701 3804 3671 +3 3701 3671 3568 +3 3671 3486 3568 +3 3486 3493 3568 +3 2384 2446 2599 +3 3484 3566 3669 +3 3802 3922 4019 +3 3803 3700 3670 +3 3670 3567 3485 +3 3168 3116 3045 +3 3491 3484 3430 +3 3430 3409 3358 +3 3167 3237 3333 +3 3174 3237 3167 +3 3174 3167 3115 +3 3167 3044 3115 +3 3044 3068 3115 +3 2993 3068 3044 +3 2993 3044 2967 +3 2993 2967 2921 +3 2967 2827 2921 +3 2827 2834 2921 +3 2738 2834 2827 +3 2738 2827 2716 +3 2738 2716 2634 +3 2716 2599 2634 +3 2599 2529 2634 +3 2446 2529 2599 +3 2388 2446 2384 +3 2388 2384 2447 +3 2384 2600 2447 +3 2600 2530 2447 +3 2635 2530 2600 +3 2635 2600 2717 +3 2635 2717 2739 +3 2717 2828 2739 +3 2828 2835 2739 +3 2922 2835 2828 +3 2922 2828 2968 +3 2922 2968 2994 +3 2968 3045 2994 +3 3045 3069 2994 +3 3116 3069 3045 +3 3175 3116 3168 +3 3175 3168 3238 +3 3168 3334 3238 +3 3334 3284 3238 +3 3359 3284 3334 +3 3359 3334 3410 +3 3359 3410 3431 +3 3410 3485 3431 +3 3485 3492 3431 +3 3567 3492 3485 +3 3700 3567 3670 +3 3823 3700 3803 +3 3823 3803 3923 +3 3803 4019 3923 +3 4019 4023 3923 +3 3922 4023 4019 +3 3822 3922 3802 +3 3822 3802 3699 +3 3802 3669 3699 +3 3669 3566 3699 +3 3358 3333 3283 +3 3333 3237 3283 +3 3409 3333 3358 +3 3484 3409 3430 +3 3566 3484 3491 +3 2383 2444 2597 +3 3482 3564 3667 +3 3800 3920 4018 +3 3801 3698 3668 +3 3668 3565 3483 +3 3166 3114 3043 +3 3489 3482 3428 +3 3428 3407 3356 +3 3165 3235 3331 +3 3172 3235 3165 +3 3172 3165 3113 +3 3165 3042 3113 +3 3042 3066 3113 +3 2991 3066 3042 +3 2991 3042 2965 +3 2991 2965 2919 +3 2965 2825 2919 +3 2825 2832 2919 +3 2736 2832 2825 +3 2736 2825 2714 +3 2736 2714 2632 +3 2714 2597 2632 +3 2597 2527 2632 +3 2444 2527 2597 +3 2387 2444 2383 +3 2387 2383 2445 +3 2383 2598 2445 +3 2598 2528 2445 +3 2633 2528 2598 +3 2633 2598 2715 +3 2633 2715 2737 +3 2715 2826 2737 +3 2826 2833 2737 +3 2920 2833 2826 +3 2920 2826 2966 +3 2920 2966 2992 +3 2966 3043 2992 +3 3043 3067 2992 +3 3114 3067 3043 +3 3173 3114 3166 +3 3173 3166 3236 +3 3166 3332 3236 +3 3332 3282 3236 +3 3357 3282 3332 +3 3357 3332 3408 +3 3357 3408 3429 +3 3408 3483 3429 +3 3483 3490 3429 +3 3565 3490 3483 +3 3698 3565 3668 +3 3821 3698 3801 +3 3821 3801 3921 +3 3801 4018 3921 +3 4018 4022 3921 +3 3920 4022 4018 +3 3820 3920 3800 +3 3820 3800 3697 +3 3800 3667 3697 +3 3667 3564 3697 +3 3356 3331 3281 +3 3331 3235 3281 +3 3407 3331 3356 +3 3482 3407 3428 +3 3564 3482 3489 +3 360 436 622 +3 2196 2097 1972 +3 1267 1220 1143 +3 1637 1629 1567 +3 1567 1533 1483 +3 1266 1349 1447 +3 1274 1349 1266 +3 1274 1266 1219 +3 1266 1142 1219 +3 1142 1171 1219 +3 1093 1171 1142 +3 1093 1142 1060 +3 1093 1060 1013 +3 1060 913 1013 +3 913 921 1013 +3 801 921 913 +3 801 913 767 +3 801 767 665 +3 767 622 665 +3 622 532 665 +3 436 532 622 +3 364 436 360 +3 364 360 437 +3 360 623 437 +3 623 533 437 +3 666 533 623 +3 666 623 768 +3 666 768 802 +3 768 914 802 +3 914 922 802 +3 1014 922 914 +3 1014 914 1061 +3 1014 1061 1094 +3 1061 1143 1094 +3 1143 1172 1094 +3 1220 1172 1143 +3 1275 1220 1267 +3 1275 1267 1350 +3 1267 1448 1350 +3 1448 1402 1350 +3 1484 1402 1448 +3 1484 1448 1534 +3 1484 1534 1568 +3 1534 1630 1568 +3 1630 1638 1568 +3 1735 1638 1630 +3 1735 1630 1825 +3 1735 1825 1868 +3 1825 1972 1868 +3 1972 2001 1868 +3 2097 2001 1972 +3 2200 2097 2196 +3 2200 2196 2096 +3 2196 1971 2096 +3 1971 2000 2096 +3 1867 1971 1824 +3 2000 1971 1867 +3 1734 1824 1629 +3 1867 1824 1734 +3 1483 1447 1401 +3 1447 1349 1401 +3 1533 1447 1483 +3 1629 1533 1567 +3 1734 1629 1637 +3 359 434 620 +3 1627 1732 1822 +3 1822 1865 1969 +3 1970 2195 2095 +3 1265 1218 1141 +3 1627 1565 1635 +3 1481 1565 1531 +3 1264 1347 1445 +3 1272 1347 1264 +3 1272 1264 1217 +3 1264 1140 1217 +3 1140 1169 1217 +3 1091 1169 1140 +3 1091 1140 1058 +3 1091 1058 1011 +3 1058 911 1011 +3 911 919 1011 +3 799 919 911 +3 799 911 765 +3 799 765 663 +3 765 620 663 +3 620 530 663 +3 434 530 620 +3 363 434 359 +3 363 359 435 +3 359 621 435 +3 621 531 435 +3 664 531 621 +3 664 621 766 +3 664 766 800 +3 766 912 800 +3 912 920 800 +3 1012 920 912 +3 1012 912 1059 +3 1012 1059 1092 +3 1059 1141 1092 +3 1141 1170 1092 +3 1218 1170 1141 +3 1273 1218 1265 +3 1273 1265 1348 +3 1265 1446 1348 +3 1446 1400 1348 +3 1482 1400 1446 +3 1482 1446 1532 +3 1482 1532 1566 +3 1532 1628 1566 +3 1628 1636 1566 +3 1733 1636 1628 +3 1733 1628 1823 +3 1733 1823 1866 +3 1823 1970 1866 +3 1970 1999 1866 +3 2095 1999 1970 +3 2199 2095 2195 +3 2199 2195 2094 +3 2195 1969 2094 +3 1969 1998 2094 +3 1865 1998 1969 +3 1732 1865 1822 +3 1481 1445 1399 +3 1445 1347 1399 +3 1531 1445 1481 +3 1627 1531 1565 +3 1732 1627 1635 +3 358 432 618 +3 1820 1863 1967 +3 1968 1864 1821 +3 1821 1731 1626 +3 1263 1216 1139 +3 1633 1625 1563 +3 1479 1563 1529 +3 1262 1345 1443 +3 1270 1345 1262 +3 1270 1262 1215 +3 1262 1138 1215 +3 1138 1167 1215 +3 1089 1167 1138 +3 1089 1138 1056 +3 1089 1056 1009 +3 1056 909 1009 +3 909 917 1009 +3 797 917 909 +3 797 909 763 +3 797 763 661 +3 763 618 661 +3 618 528 661 +3 432 528 618 +3 362 432 358 +3 362 358 433 +3 358 619 433 +3 619 529 433 +3 662 529 619 +3 662 619 764 +3 662 764 798 +3 764 910 798 +3 910 918 798 +3 1010 918 910 +3 1010 910 1057 +3 1010 1057 1090 +3 1057 1139 1090 +3 1139 1168 1090 +3 1216 1168 1139 +3 1271 1216 1263 +3 1271 1263 1346 +3 1263 1444 1346 +3 1444 1398 1346 +3 1480 1398 1444 +3 1480 1444 1530 +3 1480 1530 1564 +3 1530 1626 1564 +3 1626 1634 1564 +3 1731 1634 1626 +3 1864 1731 1821 +3 1997 1864 1968 +3 1997 1968 2093 +3 1968 2194 2093 +3 2194 2198 2093 +3 2092 2198 2194 +3 2092 2194 1967 +3 2092 1967 1996 +3 1967 1863 1996 +3 1730 1820 1625 +3 1863 1820 1730 +3 1479 1443 1397 +3 1443 1345 1397 +3 1529 1443 1479 +3 1625 1529 1563 +3 1730 1625 1633 +3 357 430 616 +3 1966 1862 1819 +3 1729 1624 1819 +3 1261 1214 1137 +3 1623 1561 1631 +3 1561 1527 1477 +3 1260 1343 1441 +3 1268 1343 1260 +3 1268 1260 1213 +3 1260 1136 1213 +3 1136 1165 1213 +3 1087 1165 1136 +3 1087 1136 1054 +3 1087 1054 1007 +3 1054 907 1007 +3 907 915 1007 +3 795 915 907 +3 795 907 761 +3 795 761 659 +3 761 616 659 +3 616 526 659 +3 430 526 616 +3 361 430 357 +3 361 357 431 +3 357 617 431 +3 617 527 431 +3 660 527 617 +3 660 617 762 +3 660 762 796 +3 762 908 796 +3 908 916 796 +3 1008 916 908 +3 1008 908 1055 +3 1008 1055 1088 +3 1055 1137 1088 +3 1137 1166 1088 +3 1214 1166 1137 +3 1269 1214 1261 +3 1269 1261 1344 +3 1261 1442 1344 +3 1442 1396 1344 +3 1478 1396 1442 +3 1478 1442 1528 +3 1478 1528 1562 +3 1528 1624 1562 +3 1624 1632 1562 +3 1729 1632 1624 +3 1862 1729 1819 +3 1995 1862 1966 +3 1995 1966 2091 +3 1966 2193 2091 +3 2193 2197 2091 +3 2090 2197 2193 +3 2090 2193 1965 +3 2090 1965 1994 +3 1861 1965 1818 +3 1994 1965 1861 +3 1728 1818 1623 +3 1861 1818 1728 +3 1477 1441 1395 +3 1441 1343 1395 +3 1527 1441 1477 +3 1623 1527 1561 +3 1728 1623 1631 +3 415 513 412 +3 415 412 514 +3 415 514 639 +3 742 639 609 +3 639 514 609 +3 784 639 742 +3 784 742 878 +3 784 878 983 +3 1045 983 976 +3 983 878 976 +3 1077 983 1045 +3 1077 1045 1125 +3 1077 1125 1159 +3 1251 1159 1203 +3 1159 1125 1203 +3 1328 1159 1251 +3 1328 1251 1321 +3 1328 1321 1381 +3 1328 1381 1464 +3 1515 1464 1433 +3 1464 1381 1433 +3 1550 1464 1515 +3 1550 1515 1599 +3 1550 1599 1699 +3 1809 1699 1691 +3 1699 1599 1691 +3 1841 1699 1809 +3 1841 1809 1942 +3 1841 1942 1988 +3 2172 1988 2075 +3 1988 1942 2075 +3 2248 1988 2172 +3 2248 2172 2245 +3 2248 2245 2171 +3 2248 2171 1987 +3 1941 1987 2074 +3 1987 2171 2074 +3 1840 1987 1941 +3 1840 1941 1808 +3 1840 1808 1698 +3 1598 1698 1690 +3 1698 1808 1690 +3 1549 1698 1598 +3 1549 1598 1514 +3 1549 1514 1463 +3 1380 1463 1432 +3 1463 1514 1432 +3 1327 1463 1380 +3 1327 1380 1320 +3 1327 1320 1250 +3 1327 1250 1158 +3 1124 1158 1202 +3 1158 1250 1202 +3 1076 1158 1124 +3 1076 1124 1044 +3 1076 1044 982 +3 877 982 975 +3 982 1044 975 +3 783 982 877 +3 783 877 741 +3 783 741 638 +3 741 608 638 +3 608 513 638 +3 513 415 638 +3 1319 1380 1461 +3 2235 2157 1983 +3 1309 1242 1154 +3 634 594 499 +3 727 594 634 +3 727 634 779 +3 727 779 863 +3 779 964 863 +3 964 965 863 +3 1036 965 964 +3 1036 964 1072 +3 1036 1072 1116 +3 1072 1154 1116 +3 1154 1194 1116 +3 1242 1194 1154 +3 1310 1242 1309 +3 1310 1309 1372 +3 1309 1459 1372 +3 1459 1424 1372 +3 1506 1424 1459 +3 1506 1459 1545 +3 1506 1545 1590 +3 1545 1679 1590 +3 1679 1680 1590 +3 1794 1680 1679 +3 1794 1679 1836 +3 1794 1836 1927 +3 1836 1983 1927 +3 1983 2060 1927 +3 2157 2060 1983 +3 2236 2157 2235 +3 2236 2235 2165 +3 2235 1985 2165 +3 1985 2068 2165 +3 1935 2068 1985 +3 1935 1985 1838 +3 1935 1838 1802 +3 1838 1689 1802 +3 1689 1690 1802 +3 1598 1690 1689 +3 1598 1689 1547 +3 1598 1547 1514 +3 1547 1461 1514 +3 1461 1432 1514 +3 1380 1432 1461 +3 1320 1380 1319 +3 1320 1319 1250 +3 1319 1156 1250 +3 1156 1202 1250 +3 1124 1202 1156 +3 1124 1156 1074 +3 1124 1074 1044 +3 1074 974 1044 +3 974 975 1044 +3 871 975 974 +3 871 974 781 +3 871 781 735 +3 781 636 735 +3 636 602 735 +3 507 602 636 +3 507 636 401 +3 507 401 402 +3 401 499 402 +3 634 499 401 +3 341 513 334 +3 296 499 288 +3 252 492 257 +3 289 595 500 +3 728 595 289 +3 728 289 281 +3 728 281 864 +3 281 273 864 +3 273 966 864 +3 856 966 273 +3 856 273 265 +3 856 265 720 +3 265 257 720 +3 257 587 720 +3 492 587 257 +3 397 492 252 +3 397 252 491 +3 252 256 491 +3 256 586 491 +3 719 586 256 +3 719 256 264 +3 719 264 855 +3 264 272 855 +3 272 965 855 +3 863 965 272 +3 863 272 280 +3 863 280 727 +3 280 288 727 +3 288 594 727 +3 499 594 288 +3 402 499 296 +3 402 296 507 +3 296 306 507 +3 306 602 507 +3 735 602 306 +3 735 306 313 +3 735 313 871 +3 313 320 871 +3 320 975 871 +3 877 975 320 +3 877 320 327 +3 877 327 741 +3 327 334 741 +3 334 608 741 +3 513 608 334 +3 412 513 341 +3 412 341 514 +3 341 335 514 +3 335 609 514 +3 742 609 335 +3 742 335 328 +3 742 328 878 +3 328 321 878 +3 321 976 878 +3 872 976 321 +3 872 321 314 +3 872 314 736 +3 314 307 736 +3 307 603 736 +3 508 603 307 +3 508 307 297 +3 508 297 403 +3 297 500 403 +3 289 500 297 +3 1681 2786 1795 +3 1795 2682 1928 +3 1928 2578 2061 +3 1936 2689 1803 +3 1803 2793 1691 +3 1691 2875 1809 +3 2798 1942 1809 +3 1942 2694 2075 +3 2150 2571 2053 +3 2053 2675 1920 +3 2332 2165 2333 +3 2075 2590 2172 +3 2694 2590 2075 +3 2798 2694 1942 +3 2875 2798 1809 +3 2793 2875 1691 +3 2689 2793 1803 +3 2585 2689 1936 +3 2585 1936 2069 +3 2585 2069 2503 +3 2237 2503 2166 +3 2503 2069 2166 +3 2418 2503 2237 +3 2418 2237 2495 +3 2061 2495 2158 +3 2495 2237 2158 +3 2578 2495 2061 +3 2682 2578 1928 +3 2786 2682 1795 +3 2867 2786 1681 +3 2867 1681 2779 +3 1920 2779 1787 +3 2779 1681 1787 +3 2675 2779 1920 +3 2571 2675 2053 +3 2488 2571 2150 +3 2427 2338 2508 +3 2338 2172 2508 +3 2172 2590 2508 +3 2245 2172 2338 +3 2245 2338 2171 +3 2338 2337 2171 +3 2337 2074 2171 +3 1941 2074 2337 +3 1941 2337 2336 +3 1941 2336 1808 +3 2336 2335 1808 +3 2335 1690 1808 +3 1802 1690 2335 +3 1802 2335 2334 +3 1802 2334 1935 +3 2334 2333 1935 +3 2333 2068 1935 +3 2165 2068 2333 +3 2236 2165 2332 +3 2236 2332 2157 +3 2332 2331 2157 +3 2331 2060 2157 +3 1927 2060 2331 +3 1927 2331 2330 +3 1927 2330 1794 +3 2330 2329 1794 +3 2329 1680 1794 +3 1786 1680 2329 +3 1786 2329 2328 +3 1786 2328 1919 +3 2328 2327 1919 +3 2327 2052 1919 +3 2149 2052 2327 +3 2149 2327 2326 +3 2149 2326 2231 +3 2326 2150 2231 +3 2488 2150 2326 +3 2488 2326 2414 +3 7267 7179 7073 +3 6285 6376 6540 +3 7268 7330 7430 +3 7970 8050 8158 +3 7906 8050 7970 +3 7906 7970 7818 +3 7906 7818 7762 +3 7818 7658 7762 +3 7658 7649 7762 +3 7570 7649 7658 +3 7570 7658 7526 +3 7570 7526 7478 +3 7526 7430 7478 +3 7430 7386 7478 +3 7330 7386 7430 +3 7259 7330 7268 +3 7259 7268 7180 +3 7268 7074 7180 +3 7074 7128 7180 +3 7030 7128 7074 +3 7030 7074 6976 +3 7030 6976 6936 +3 6976 6872 6936 +3 6872 6863 6936 +3 6772 6863 6872 +3 6772 6872 6684 +3 6772 6684 6632 +3 6684 6540 6632 +3 6540 6488 6632 +3 6376 6488 6540 +3 6281 6376 6285 +3 6281 6285 6375 +3 6285 6539 6375 +3 6539 6487 6375 +3 6631 6487 6539 +3 6631 6539 6683 +3 6631 6683 6771 +3 6683 6871 6771 +3 6871 6862 6771 +3 6935 6862 6871 +3 6935 6871 6975 +3 6935 6975 7029 +3 6975 7073 7029 +3 7073 7127 7029 +3 7179 7127 7073 +3 7258 7179 7267 +3 7258 7267 7329 +3 7267 7429 7329 +3 7429 7385 7329 +3 7477 7385 7429 +3 7477 7429 7525 +3 7477 7525 7569 +3 7525 7657 7569 +3 7657 7648 7569 +3 7761 7648 7657 +3 7761 7657 7817 +3 7761 7817 7905 +3 7817 7969 7905 +3 7969 8049 7905 +3 8157 8049 7969 +3 8157 7969 8239 +3 8157 8239 8235 +3 8239 8158 8235 +3 7970 8158 8239 +3 7257 7329 7427 +3 8225 8141 7965 +3 7247 7171 7069 +3 6535 6471 6359 +3 6615 6471 6535 +3 6615 6535 6679 +3 6615 6679 6755 +3 6679 6851 6755 +3 6851 6852 6755 +3 6927 6852 6851 +3 6927 6851 6971 +3 6927 6971 7021 +3 6971 7069 7021 +3 7069 7119 7021 +3 7171 7119 7069 +3 7248 7171 7247 +3 7248 7247 7321 +3 7247 7425 7321 +3 7425 7377 7321 +3 7469 7377 7425 +3 7469 7425 7521 +3 7469 7521 7561 +3 7521 7637 7561 +3 7637 7638 7561 +3 7745 7638 7637 +3 7745 7637 7813 +3 7745 7813 7889 +3 7813 7965 7889 +3 7965 8033 7889 +3 8141 8033 7965 +3 8226 8141 8225 +3 8226 8225 8149 +3 8225 7967 8149 +3 7967 8041 8149 +3 7897 8041 7967 +3 7897 7967 7815 +3 7897 7815 7753 +3 7815 7647 7753 +3 7647 7648 7753 +3 7569 7648 7647 +3 7569 7647 7523 +3 7569 7523 7477 +3 7523 7427 7477 +3 7427 7385 7477 +3 7329 7385 7427 +3 7258 7329 7257 +3 7258 7257 7179 +3 7257 7071 7179 +3 7071 7127 7179 +3 7029 7127 7071 +3 7029 7071 6973 +3 7029 6973 6935 +3 6973 6861 6935 +3 6861 6862 6935 +3 6763 6862 6861 +3 6763 6861 6681 +3 6763 6681 6623 +3 6681 6537 6623 +3 6537 6479 6623 +3 6367 6479 6537 +3 6367 6537 6271 +3 6367 6271 6272 +3 6271 6359 6272 +3 6535 6359 6271 +3 5255 5171 5071 +3 4287 4378 4542 +3 5256 5316 5412 +3 5936 6024 6128 +3 5880 6024 5936 +3 5880 5936 5792 +3 5880 5792 5736 +3 5792 5636 5736 +3 5636 5627 5736 +3 5552 5627 5636 +3 5552 5636 5504 +3 5552 5504 5460 +3 5504 5412 5460 +3 5412 5368 5460 +3 5316 5368 5412 +3 5247 5316 5256 +3 5247 5256 5172 +3 5256 5072 5172 +3 5072 5116 5172 +3 5028 5116 5072 +3 5028 5072 4980 +3 5028 4980 4936 +3 4980 4876 4936 +3 4876 4867 4936 +3 4774 4867 4876 +3 4774 4876 4690 +3 4774 4690 4630 +3 4690 4542 4630 +3 4542 4486 4630 +3 4378 4486 4542 +3 4283 4378 4287 +3 4283 4287 4377 +3 4287 4541 4377 +3 4541 4485 4377 +3 4629 4485 4541 +3 4629 4541 4689 +3 4629 4689 4773 +3 4689 4875 4773 +3 4875 4866 4773 +3 4935 4866 4875 +3 4935 4875 4979 +3 4935 4979 5027 +3 4979 5071 5027 +3 5071 5115 5027 +3 5171 5115 5071 +3 5246 5171 5255 +3 5246 5255 5315 +3 5255 5411 5315 +3 5411 5367 5315 +3 5459 5367 5411 +3 5459 5411 5503 +3 5459 5503 5551 +3 5503 5635 5551 +3 5635 5626 5551 +3 5735 5626 5635 +3 5735 5635 5791 +3 5735 5791 5879 +3 5791 5935 5879 +3 5935 6023 5879 +3 6127 6023 5935 +3 6127 5935 6213 +3 6127 6213 6209 +3 6213 6128 6209 +3 5936 6128 6213 +3 5245 5315 5409 +3 6199 6111 5931 +3 5235 5163 5067 +3 4537 4469 4361 +3 4613 4469 4537 +3 4613 4537 4685 +3 4613 4685 4757 +3 4685 4855 4757 +3 4855 4856 4757 +3 4927 4856 4855 +3 4927 4855 4975 +3 4927 4975 5019 +3 4975 5067 5019 +3 5067 5107 5019 +3 5163 5107 5067 +3 5236 5163 5235 +3 5236 5235 5307 +3 5235 5407 5307 +3 5407 5359 5307 +3 5451 5359 5407 +3 5451 5407 5499 +3 5451 5499 5543 +3 5499 5615 5543 +3 5615 5616 5543 +3 5719 5616 5615 +3 5719 5615 5787 +3 5719 5787 5863 +3 5787 5931 5863 +3 5931 6007 5863 +3 6111 6007 5931 +3 6200 6111 6199 +3 6200 6199 6119 +3 6199 5933 6119 +3 5933 6015 6119 +3 5871 6015 5933 +3 5871 5933 5789 +3 5871 5789 5727 +3 5789 5625 5727 +3 5625 5626 5727 +3 5551 5626 5625 +3 5551 5625 5501 +3 5551 5501 5459 +3 5501 5409 5459 +3 5409 5367 5459 +3 5315 5367 5409 +3 5246 5315 5245 +3 5246 5245 5171 +3 5245 5069 5171 +3 5069 5115 5171 +3 5027 5115 5069 +3 5027 5069 4977 +3 5027 4977 4935 +3 4977 4865 4935 +3 4865 4866 4935 +3 4765 4866 4865 +3 4765 4865 4687 +3 4765 4687 4621 +3 4687 4539 4621 +3 4539 4477 4621 +3 4369 4477 4539 +3 4369 4539 4273 +3 4369 4273 4274 +3 4273 4361 4274 +3 4537 4361 4273 +3 1424 1418 1372 +3 1372 1366 1310 +3 1310 1300 1242 +3 1236 1194 1242 +3 1036 956 965 +3 586 580 491 +3 491 484 397 +3 397 394 492 +3 492 485 587 +3 587 581 720 +3 720 714 856 +3 1787 1914 1920 +3 2231 2228 2149 +3 1919 1780 1786 +3 1672 1681 1585 +3 1585 1591 1501 +3 1501 1507 1419 +3 1419 1425 1367 +3 1367 1373 1301 +3 1301 1311 1237 +3 1111 1037 1031 +3 856 850 966 +3 714 850 856 +3 581 714 720 +3 485 581 587 +3 394 485 492 +3 484 394 397 +3 580 484 491 +3 713 580 586 +3 713 586 719 +3 713 719 849 +3 965 849 855 +3 849 719 855 +3 956 849 965 +3 1030 956 1036 +3 1030 1036 1110 +3 1036 1116 1110 +3 1116 1194 1110 +3 1194 1188 1110 +3 1236 1188 1194 +3 1300 1236 1242 +3 1366 1300 1310 +3 1418 1366 1372 +3 1500 1418 1424 +3 1500 1424 1506 +3 1500 1506 1584 +3 1506 1590 1584 +3 1590 1671 1584 +3 1786 1671 1680 +3 1671 1590 1680 +3 1780 1671 1786 +3 1913 1780 1919 +3 1913 1919 2052 +3 1913 2052 2046 +3 2052 2149 2046 +3 2149 2142 2046 +3 2228 2142 2149 +3 2143 2228 2231 +3 2143 2231 2150 +3 2143 2150 2053 +3 2143 2053 2047 +3 2053 1920 2047 +3 1920 1914 2047 +3 1781 1787 1681 +3 1914 1787 1781 +3 1031 966 957 +3 966 850 957 +3 1037 966 1031 +3 1117 1037 1111 +3 1117 1111 1189 +3 1117 1189 1195 +3 1189 1237 1195 +3 1237 1243 1195 +3 1311 1243 1237 +3 1373 1311 1301 +3 1425 1373 1367 +3 1507 1425 1419 +3 1591 1507 1501 +3 1681 1591 1585 +3 1781 1681 1672 +3 1299 1366 1457 +3 2220 2130 1979 +3 1291 1230 1150 +3 630 568 472 +3 701 568 630 +3 701 630 775 +3 701 775 837 +3 775 946 837 +3 946 947 837 +3 1024 947 946 +3 1024 946 1068 +3 1024 1068 1104 +3 1068 1150 1104 +3 1150 1182 1104 +3 1230 1182 1150 +3 1292 1230 1291 +3 1292 1291 1360 +3 1291 1455 1360 +3 1455 1412 1360 +3 1494 1412 1455 +3 1494 1455 1541 +3 1494 1541 1578 +3 1541 1661 1578 +3 1661 1662 1578 +3 1768 1662 1661 +3 1768 1661 1832 +3 1768 1832 1901 +3 1832 1979 1901 +3 1979 2034 1901 +3 2130 2034 1979 +3 2221 2130 2220 +3 2221 2220 2136 +3 2220 1981 2136 +3 1981 2040 2136 +3 1907 2040 1981 +3 1907 1981 1834 +3 1907 1834 1774 +3 1834 1670 1774 +3 1670 1671 1774 +3 1584 1671 1670 +3 1584 1670 1543 +3 1584 1543 1500 +3 1543 1457 1500 +3 1457 1418 1500 +3 1366 1418 1457 +3 1300 1366 1299 +3 1300 1299 1236 +3 1299 1152 1236 +3 1152 1188 1236 +3 1110 1188 1152 +3 1110 1152 1070 +3 1110 1070 1030 +3 1070 955 1030 +3 955 956 1030 +3 843 956 955 +3 843 955 777 +3 843 777 707 +3 777 632 707 +3 632 574 707 +3 478 574 632 +3 478 632 386 +3 478 386 387 +3 386 472 387 +3 630 472 386 +3 8494 8142 8486 +3 8449 8133 8453 +3 8493 8149 8501 +3 8541 8158 8534 +3 7746 7639 8470 +3 7746 8470 8478 +3 7746 8478 7890 +3 8478 8486 7890 +3 8486 8034 7890 +3 8142 8034 8486 +3 8227 8142 8494 +3 8227 8494 8150 +3 8494 8502 8150 +3 8502 8042 8150 +3 7898 8042 8502 +3 7898 8502 8510 +3 7898 8510 7754 +3 8510 8518 7754 +3 8518 7649 7754 +3 7762 7649 8518 +3 7762 8518 8526 +3 7762 8526 7906 +3 8526 8534 7906 +3 8534 8050 7906 +3 8158 8050 8534 +3 8235 8158 8541 +3 8235 8541 8157 +3 8541 8533 8157 +3 8533 8049 8157 +3 7905 8049 8533 +3 7905 8533 8525 +3 7905 8525 7761 +3 8525 8517 7761 +3 8517 7648 7761 +3 7753 7648 8517 +3 7753 8517 8509 +3 7753 8509 7897 +3 8509 8501 7897 +3 8501 8041 7897 +3 8149 8041 8501 +3 8226 8149 8493 +3 8226 8493 8141 +3 8493 8485 8141 +3 8485 8033 8141 +3 7889 8033 8485 +3 7889 8485 8477 +3 7889 8477 7745 +3 8477 8469 7745 +3 8469 7638 7745 +3 7737 7638 8469 +3 7737 8469 8461 +3 7737 8461 7881 +3 8461 8453 7881 +3 8453 8025 7881 +3 8133 8025 8453 +3 8221 8133 8449 +3 8221 8449 8134 +3 8449 8454 8134 +3 8454 8026 8134 +3 7882 8026 8454 +3 7882 8454 8462 +3 7882 8462 7738 +3 8462 8470 7738 +3 8470 7639 7738 +3 238 484 231 +3 195 472 189 +3 157 467 163 +3 190 569 473 +3 702 569 190 +3 702 190 184 +3 702 184 838 +3 184 177 838 +3 177 948 838 +3 832 948 177 +3 832 177 170 +3 832 170 696 +3 170 163 696 +3 163 563 696 +3 467 563 163 +3 383 467 157 +3 383 157 466 +3 157 162 466 +3 162 562 466 +3 695 562 162 +3 695 162 169 +3 695 169 831 +3 169 176 831 +3 176 947 831 +3 837 947 176 +3 837 176 183 +3 837 183 701 +3 183 189 701 +3 189 568 701 +3 472 568 189 +3 387 472 195 +3 387 195 478 +3 195 203 478 +3 203 574 478 +3 707 574 203 +3 707 203 209 +3 707 209 843 +3 209 216 843 +3 216 956 843 +3 849 956 216 +3 849 216 224 +3 849 224 713 +3 224 231 713 +3 231 580 713 +3 484 580 231 +3 394 484 238 +3 394 238 485 +3 238 232 485 +3 232 581 485 +3 714 581 232 +3 714 232 225 +3 714 225 850 +3 225 217 850 +3 217 957 850 +3 844 957 217 +3 844 217 210 +3 844 210 708 +3 210 204 708 +3 204 575 708 +3 479 575 204 +3 479 204 196 +3 479 196 388 +3 196 473 388 +3 190 473 196 +3 1902 2660 2035 +3 2035 2555 2131 +3 2131 2472 2222 +3 2222 2404 2137 +3 2477 2041 2137 +3 2041 2560 1908 +3 1908 2665 1775 +3 1672 1775 2769 +3 2565 2143 2047 +3 1913 2323 1780 +3 2550 2029 2125 +3 2029 2655 1896 +3 2759 1763 1896 +3 2313 2467 2125 +3 2313 2125 2217 +3 2313 2217 2124 +3 2313 2124 2314 +3 1895 2314 2028 +3 2314 2124 2028 +3 2315 2314 1895 +3 2315 1895 1762 +3 2315 1762 2316 +3 1768 2316 1662 +3 2316 1762 1662 +3 2317 2316 1768 +3 2317 1768 1901 +3 2317 1901 2318 +3 2130 2318 2034 +3 2318 1901 2034 +3 2319 2318 2130 +3 2319 2130 2221 +3 2319 2221 2136 +3 2319 2136 2320 +3 1907 2320 2040 +3 2320 2136 2040 +3 2321 2320 1907 +3 2321 1907 1774 +3 2321 1774 2322 +3 1780 2322 1671 +3 2322 1774 1671 +3 2323 2322 1780 +3 2324 2323 1913 +3 2324 1913 2046 +3 2324 2046 2142 +3 2324 2142 2325 +3 2142 2228 2325 +3 2228 2143 2325 +3 2143 2482 2325 +3 2482 2410 2325 +3 2565 2482 2143 +3 2670 2565 2047 +3 2670 2047 1914 +3 2670 1914 2774 +3 1914 1781 2774 +3 1781 1672 2774 +3 1672 2860 2774 +3 2769 2860 1672 +3 2665 2769 1775 +3 2560 2665 1908 +3 2477 2560 2041 +3 2404 2477 2137 +3 2472 2404 2222 +3 2555 2472 2131 +3 2660 2555 2035 +3 2764 2660 1902 +3 2764 1902 1769 +3 2764 1769 2853 +3 1763 2853 1663 +3 2853 1769 1663 +3 2759 2853 1763 +3 2655 2759 1896 +3 2550 2655 2029 +3 2467 2550 2125 +3 2401 2467 2313 +3 4757 4115 4613 +3 4119 4765 4621 +3 4773 4121 4629 +3 4378 3881 4486 +3 4486 3758 4630 +3 3625 4774 4630 +3 4774 3522 4867 +3 4766 4867 3618 +3 4766 3751 4622 +3 4614 3744 4758 +3 4758 3611 4857 +3 3514 4750 4857 +3 4750 3604 4606 +3 4606 3737 4462 +3 4462 3860 4354 +3 4605 4113 4749 +3 3981 4378 4123 +3 4378 4283 4123 +3 4283 4377 4123 +3 4377 4122 4123 +3 4629 4122 4485 +3 4122 4377 4485 +3 4121 4122 4629 +3 4120 4121 4773 +3 4765 4120 4866 +3 4120 4773 4866 +3 4119 4120 4765 +3 4118 4119 4621 +3 4118 4621 4477 +3 4118 4477 4369 +3 4118 4369 4117 +3 4369 4274 4117 +3 4274 4361 4117 +3 4361 4116 4117 +3 4613 4116 4469 +3 4116 4361 4469 +3 4115 4116 4613 +3 4114 4115 4757 +3 4749 4114 4856 +3 4114 4757 4856 +3 4113 4114 4749 +3 4112 4113 4605 +3 4112 4605 4461 +3 4112 4461 4353 +3 4112 4353 4111 +3 4353 4269 4111 +3 4269 4354 4111 +3 4354 3960 4111 +3 3960 4046 4111 +3 3860 3960 4354 +3 3737 3860 4462 +3 3604 3737 4606 +3 3514 3604 4750 +3 3611 3514 4857 +3 3744 3611 4758 +3 3867 3744 4614 +3 3867 4614 4470 +3 3867 4470 4362 +3 3867 4362 3967 +3 4362 4275 3967 +3 4275 4050 3967 +3 3974 4050 4275 +3 3974 4275 4370 +3 3974 4370 3874 +3 4622 3874 4478 +3 3874 4370 4478 +3 3751 3874 4622 +3 3618 3751 4766 +3 3522 3618 4867 +3 3625 3522 4774 +3 3758 3625 4630 +3 3881 3758 4486 +3 3981 3881 4378 +3 4058 3981 4123 +3 5720 6616 5864 +3 5864 6472 6008 +3 6008 6360 6112 +3 6112 6273 6201 +3 6764 5627 5728 +3 6024 6488 6128 +3 6128 6376 6209 +3 6127 6209 6281 +3 6023 6127 6375 +3 6487 5879 6023 +3 5616 6747 5711 +3 5999 6351 6103 +3 6103 6267 6195 +3 6195 6352 6104 +3 6104 6464 6000 +3 6000 6608 5856 +3 6471 6007 6359 +3 6359 6111 6272 +3 6272 6200 6367 +3 6479 6367 6119 +3 6479 6015 6623 +3 5879 6631 5735 +3 6487 6631 5879 +3 6375 6487 6023 +3 6281 6375 6127 +3 6376 6281 6209 +3 6488 6376 6128 +3 6632 6488 6024 +3 6632 6024 5880 +3 6632 5880 6772 +3 5880 5736 6772 +3 5736 5627 6772 +3 5627 6863 6772 +3 6764 6863 5627 +3 6624 6764 5728 +3 6624 5728 5872 +3 6624 5872 6480 +3 5872 6016 6480 +3 6016 6368 6480 +3 6201 6368 6120 +3 6368 6016 6120 +3 6273 6368 6201 +3 6360 6273 6112 +3 6472 6360 6008 +3 6616 6472 5864 +3 6756 6616 5720 +3 6756 5720 5617 +3 6756 5617 6853 +3 5617 6748 6853 +3 5856 6748 5712 +3 6748 5617 5712 +3 6608 6748 5856 +3 6464 6608 6000 +3 6352 6464 6104 +3 6267 6352 6195 +3 6351 6267 6103 +3 6463 6351 5999 +3 6463 5999 5855 +3 6463 5855 6607 +3 5855 5711 6607 +3 5711 6747 6607 +3 6862 5735 6771 +3 5735 6631 6771 +3 5626 5735 6862 +3 5626 6862 6763 +3 5626 6763 5727 +3 6763 6623 5727 +3 6623 5871 5727 +3 6015 5871 6623 +3 6119 6015 6479 +3 6200 6119 6367 +3 6111 6200 6272 +3 6007 6111 6359 +3 5863 6007 6471 +3 5863 6471 6615 +3 5863 6615 5719 +3 6615 6755 5719 +3 6755 6852 5719 +3 6852 5616 5719 +3 6747 5616 6852 +3 6407 6463 6551 +3 6551 6607 6803 +3 7021 7049 6988 +3 7119 7089 7049 +3 7089 7171 7199 +3 7248 7292 7199 +3 7292 7321 7405 +3 7589 7638 7681 +3 7681 7737 7793 +3 7793 7881 7937 +3 7937 8025 8081 +3 8081 8133 8219 +3 7938 7882 7794 +3 7794 7738 7682 +3 7590 7682 7639 +3 7498 7590 7562 +3 7498 7470 7406 +3 7200 7172 7090 +3 7090 7120 7050 +3 7120 7022 7050 +3 7172 7120 7090 +3 7249 7172 7200 +3 7249 7200 7293 +3 7249 7293 7322 +3 7293 7406 7322 +3 7406 7378 7322 +3 7470 7378 7406 +3 7562 7470 7498 +3 7639 7562 7590 +3 7738 7639 7682 +3 7882 7738 7794 +3 8026 7882 7938 +3 8026 7938 8082 +3 8026 8082 8134 +3 8082 8219 8134 +3 8219 8221 8134 +3 8133 8221 8219 +3 8025 8133 8081 +3 7881 8025 7937 +3 7737 7881 7793 +3 7638 7737 7681 +3 7561 7638 7589 +3 7561 7589 7497 +3 7561 7497 7469 +3 7497 7405 7469 +3 7405 7377 7469 +3 7321 7377 7405 +3 7248 7321 7292 +3 7171 7248 7199 +3 7119 7171 7089 +3 7021 7119 7049 +3 6927 7021 6988 +3 6927 6988 6895 +3 6927 6895 6852 +3 6895 6803 6852 +3 6803 6747 6852 +3 6607 6747 6803 +3 6463 6607 6551 +3 6351 6463 6407 +3 6351 6407 6267 +3 6407 6408 6267 +3 6408 6352 6267 +3 6464 6352 6408 +3 6464 6408 6552 +3 6464 6552 6608 +3 6552 6804 6608 +3 6804 6748 6608 +3 6853 6748 6804 +3 6853 6804 6896 +3 6853 6896 6928 +3 6896 6989 6928 +3 6989 7022 6928 +3 7050 7022 6989 +3 5232 5164 5064 +3 4267 4353 4533 +3 5231 5307 5403 +3 5927 5999 6103 +3 5855 5999 5927 +3 5855 5927 5783 +3 5855 5783 5711 +3 5783 5611 5711 +3 5611 5616 5711 +3 5543 5616 5611 +3 5543 5611 5495 +3 5543 5495 5451 +3 5495 5403 5451 +3 5403 5359 5451 +3 5307 5359 5403 +3 5236 5307 5231 +3 5236 5231 5163 +3 5231 5063 5163 +3 5063 5107 5163 +3 5019 5107 5063 +3 5019 5063 4971 +3 5019 4971 4927 +3 4971 4851 4927 +3 4851 4856 4927 +3 4749 4856 4851 +3 4749 4851 4681 +3 4749 4681 4605 +3 4681 4533 4605 +3 4533 4461 4605 +3 4353 4461 4533 +3 4269 4353 4267 +3 4269 4267 4354 +3 4267 4534 4354 +3 4534 4462 4354 +3 4606 4462 4534 +3 4606 4534 4682 +3 4606 4682 4750 +3 4682 4852 4750 +3 4852 4857 4750 +3 4928 4857 4852 +3 4928 4852 4972 +3 4928 4972 5020 +3 4972 5064 5020 +3 5064 5108 5020 +3 5164 5108 5064 +3 5237 5164 5232 +3 5237 5232 5308 +3 5232 5404 5308 +3 5404 5360 5308 +3 5452 5360 5404 +3 5452 5404 5496 +3 5452 5496 5544 +3 5496 5612 5544 +3 5612 5617 5544 +3 5712 5617 5612 +3 5712 5612 5784 +3 5712 5784 5856 +3 5784 5928 5856 +3 5928 6000 5856 +3 6104 6000 5928 +3 6104 5928 6193 +3 6104 6193 6195 +3 6193 6103 6195 +3 5927 6103 6193 +3 3960 3916 4044 +3 3860 3792 3916 +3 3792 3737 3686 +3 3686 3604 3560 +3 3369 3351 3402 +3 3351 3294 3326 +3 3248 3231 3326 +3 3231 3189 3157 +3 3157 3126 3061 +3 3061 3079 3035 +3 3035 3004 2986 +3 2986 2932 2914 +3 2550 2462 2545 +3 2398 2462 2401 +3 2462 2467 2401 +3 2550 2467 2462 +3 2655 2550 2545 +3 2655 2545 2650 +3 2655 2650 2759 +3 2650 2754 2759 +3 2754 2853 2759 +3 2914 2853 2846 +3 2853 2754 2846 +3 2932 2853 2914 +3 3004 2932 2986 +3 3079 3004 3035 +3 3126 3079 3061 +3 3189 3126 3157 +3 3248 3189 3231 +3 3294 3248 3326 +3 3369 3294 3351 +3 3441 3369 3402 +3 3441 3402 3473 +3 3441 3473 3514 +3 3560 3514 3550 +3 3514 3473 3550 +3 3604 3514 3560 +3 3737 3604 3686 +3 3860 3737 3792 +3 3960 3860 3916 +3 4046 3960 4044 +3 1578 1662 1653 +3 1572 1494 1578 +3 1494 1488 1412 +3 1412 1406 1360 +3 1360 1354 1292 +3 1230 1292 1284 +3 1182 1230 1224 +3 1182 1176 1104 +3 1104 1098 1024 +3 1024 1018 947 +3 831 947 938 +3 831 825 695 +3 562 695 689 +3 562 556 466 +3 466 460 383 +3 383 380 467 +3 563 467 461 +3 696 563 557 +3 832 696 690 +3 832 826 948 +3 939 1025 948 +3 1025 1019 1105 +3 1099 1183 1105 +3 1177 1231 1183 +3 2125 2029 2023 +3 2028 2022 1895 +3 1889 1762 1895 +3 1762 1756 1662 +3 1355 1413 1361 +3 1355 1361 1285 +3 1361 1293 1285 +3 1293 1231 1285 +3 1231 1225 1285 +3 1177 1225 1231 +3 1099 1177 1183 +3 1019 1099 1105 +3 939 1019 1025 +3 826 939 948 +3 690 826 832 +3 557 690 696 +3 461 557 563 +3 380 461 467 +3 460 380 383 +3 556 460 466 +3 689 556 562 +3 825 689 695 +3 938 825 831 +3 1018 938 947 +3 1098 1018 1024 +3 1176 1098 1104 +3 1224 1176 1182 +3 1284 1224 1230 +3 1354 1284 1292 +3 1406 1354 1360 +3 1488 1406 1412 +3 1572 1488 1494 +3 1653 1572 1578 +3 1756 1653 1662 +3 1889 1756 1762 +3 2022 1889 1895 +3 2118 2022 2028 +3 2118 2028 2124 +3 2118 2124 2217 +3 2118 2217 2214 +3 2217 2125 2214 +3 2125 2119 2214 +3 2023 2119 2125 +3 1890 2029 1896 +3 2023 2029 1890 +3 1663 1757 1763 +3 1757 1896 1763 +3 1890 1896 1757 +3 1489 1413 1407 +3 1413 1355 1407 +3 1495 1413 1489 +3 1495 1489 1573 +3 1495 1573 1579 +3 1573 1654 1579 +3 1654 1663 1579 +3 1757 1663 1654 +3 1354 1453 1283 +3 2206 2106 1975 +3 1279 1222 1146 +3 626 544 448 +3 677 544 626 +3 677 626 771 +3 677 771 813 +3 771 928 813 +3 928 929 813 +3 1016 929 928 +3 1016 928 1064 +3 1016 1064 1096 +3 1064 1146 1096 +3 1146 1174 1096 +3 1222 1174 1146 +3 1280 1222 1279 +3 1280 1279 1352 +3 1279 1451 1352 +3 1451 1404 1352 +3 1486 1404 1451 +3 1486 1451 1537 +3 1486 1537 1570 +3 1537 1643 1570 +3 1643 1644 1570 +3 1744 1644 1643 +3 1744 1643 1828 +3 1744 1828 1877 +3 1828 1975 1877 +3 1975 2010 1877 +3 2106 2010 1975 +3 2207 2106 2206 +3 2207 2206 2112 +3 2206 1977 2112 +3 1977 2016 2112 +3 1883 2016 1977 +3 1883 1977 1830 +3 1883 1830 1750 +3 1830 1652 1750 +3 1652 1653 1750 +3 1572 1653 1652 +3 1572 1652 1539 +3 1572 1539 1488 +3 1539 1453 1488 +3 1453 1406 1488 +3 1354 1406 1453 +3 1284 1354 1283 +3 1284 1283 1224 +3 1283 1148 1224 +3 1148 1176 1224 +3 1098 1176 1148 +3 1098 1148 1066 +3 1098 1066 1018 +3 1066 937 1018 +3 937 938 1018 +3 819 938 937 +3 819 937 773 +3 819 773 683 +3 773 628 683 +3 628 550 683 +3 454 550 628 +3 454 628 372 +3 454 372 373 +3 372 448 373 +3 626 448 372 +3 756 653 86 +3 550 123 683 +3 825 143 689 +3 690 557 149 +3 690 142 826 +3 814 98 930 +3 930 91 901 +3 98 91 930 +3 104 98 814 +3 104 814 678 +3 104 678 109 +3 449 109 545 +3 109 678 545 +3 114 109 449 +3 114 449 374 +3 114 374 455 +3 114 455 122 +3 684 122 551 +3 122 455 551 +3 128 122 684 +3 128 684 820 +3 128 820 135 +3 826 135 939 +3 135 820 939 +3 142 135 826 +3 149 142 690 +3 156 149 557 +3 156 557 461 +3 156 461 380 +3 156 380 460 +3 156 460 150 +3 689 150 556 +3 150 460 556 +3 143 150 689 +3 136 143 825 +3 136 825 938 +3 136 938 129 +3 938 819 129 +3 819 683 129 +3 683 123 129 +3 373 117 454 +3 117 550 454 +3 123 550 117 +3 111 373 448 +3 117 373 111 +3 677 111 544 +3 111 448 544 +3 103 111 677 +3 103 677 813 +3 103 813 97 +3 813 929 97 +3 929 90 97 +3 756 90 891 +3 90 929 891 +3 86 90 756 +3 83 86 653 +3 83 653 521 +3 7225 7305 7419 +3 8197 8097 7957 +3 7215 7147 7061 +3 6527 6423 6311 +3 6567 6423 6527 +3 6567 6527 6671 +3 6567 6671 6707 +3 6671 6819 6707 +3 6819 6820 6707 +3 6903 6820 6819 +3 6903 6819 6963 +3 6903 6963 6997 +3 6963 7061 6997 +3 7061 7095 6997 +3 7147 7095 7061 +3 7216 7147 7215 +3 7216 7215 7297 +3 7215 7417 7297 +3 7417 7353 7297 +3 7445 7353 7417 +3 7445 7417 7513 +3 7445 7513 7537 +3 7513 7605 7537 +3 7605 7606 7537 +3 7701 7606 7605 +3 7701 7605 7805 +3 7701 7805 7845 +3 7805 7957 7845 +3 7957 7989 7845 +3 8097 7989 7957 +3 8198 8097 8197 +3 8198 8197 8105 +3 8197 7959 8105 +3 7959 7997 8105 +3 7853 7997 7959 +3 7853 7959 7807 +3 7853 7807 7709 +3 7807 7615 7709 +3 7615 7616 7709 +3 7545 7616 7615 +3 7545 7615 7515 +3 7545 7515 7453 +3 7515 7419 7453 +3 7419 7361 7453 +3 7305 7361 7419 +3 7226 7305 7225 +3 7226 7225 7155 +3 7225 7063 7155 +3 7063 7103 7155 +3 7005 7103 7063 +3 7005 7063 6965 +3 7005 6965 6911 +3 6965 6829 6911 +3 6829 6830 6911 +3 6715 6830 6829 +3 6715 6829 6673 +3 6715 6673 6575 +3 6673 6529 6575 +3 6529 6431 6575 +3 6319 6431 6529 +3 6319 6529 6241 +3 6319 6241 6242 +3 6241 6311 6242 +3 6527 6311 6241 +3 4553 4437 4409 +3 4409 4329 4255 +3 4554 4582 4662 +3 4662 4726 4807 +3 4807 4831 4900 +3 4900 4912 4992 +3 4992 5004 5136 +3 5804 5832 5948 +3 6079 5947 6181 +3 5659 5590 5515 +3 4911 4830 4899 +3 4911 4899 4991 +3 4911 4991 5003 +3 4991 5135 5003 +3 5135 5091 5003 +3 5147 5091 5135 +3 5147 5135 5279 +3 5147 5279 5210 +3 5279 5291 5210 +3 5343 5291 5279 +3 5343 5279 5423 +3 5343 5423 5435 +3 5423 5515 5435 +3 5515 5527 5435 +3 5590 5527 5515 +3 5687 5590 5659 +3 5687 5659 5803 +3 5687 5803 5831 +3 5803 5947 5831 +3 5947 5975 5831 +3 6079 5975 5947 +3 6177 6079 6181 +3 6177 6181 6080 +3 6181 5948 6080 +3 5948 5976 6080 +3 5832 5976 5948 +3 5688 5832 5804 +3 5688 5804 5660 +3 5688 5660 5591 +3 5660 5516 5591 +3 5516 5528 5591 +3 5436 5528 5516 +3 5436 5516 5424 +3 5436 5424 5344 +3 5424 5280 5344 +3 5280 5292 5344 +3 5211 5292 5280 +3 5211 5280 5148 +3 5280 5136 5148 +3 5136 5092 5148 +3 5004 5092 5136 +3 4912 5004 4992 +3 4831 4912 4900 +3 4726 4831 4807 +3 4582 4726 4662 +3 4438 4582 4554 +3 4438 4554 4410 +3 4438 4410 4330 +3 4410 4255 4330 +3 4255 4251 4330 +3 4329 4251 4255 +3 4437 4329 4409 +3 4581 4437 4553 +3 4581 4553 4661 +3 4581 4661 4725 +3 4661 4806 4725 +3 4806 4830 4725 +3 4899 4830 4806 +3 5209 5291 5397 +3 6167 6063 5919 +3 5199 5139 5055 +3 4525 4421 4313 +3 4565 4421 4525 +3 4565 4525 4673 +3 4565 4673 4709 +3 4673 4819 4709 +3 4819 4820 4709 +3 4903 4820 4819 +3 4903 4819 4963 +3 4903 4963 4995 +3 4963 5055 4995 +3 5055 5083 4995 +3 5139 5083 5055 +3 5200 5139 5199 +3 5200 5199 5283 +3 5199 5395 5283 +3 5395 5335 5283 +3 5427 5335 5395 +3 5427 5395 5487 +3 5427 5487 5519 +3 5487 5579 5519 +3 5579 5580 5519 +3 5671 5580 5579 +3 5671 5579 5775 +3 5671 5775 5815 +3 5775 5919 5815 +3 5919 5959 5815 +3 6063 5959 5919 +3 6168 6063 6167 +3 6168 6167 6071 +3 6167 5921 6071 +3 5921 5967 6071 +3 5823 5967 5921 +3 5823 5921 5777 +3 5823 5777 5679 +3 5777 5589 5679 +3 5589 5590 5679 +3 5527 5590 5589 +3 5527 5589 5489 +3 5527 5489 5435 +3 5489 5397 5435 +3 5397 5343 5435 +3 5291 5343 5397 +3 5210 5291 5209 +3 5210 5209 5147 +3 5209 5057 5147 +3 5057 5091 5147 +3 5003 5091 5057 +3 5003 5057 4965 +3 5003 4965 4911 +3 4965 4829 4911 +3 4829 4830 4911 +3 4717 4830 4829 +3 4717 4829 4675 +3 4717 4675 4573 +3 4675 4527 4573 +3 4527 4429 4573 +3 4321 4429 4527 +3 4321 4527 4241 +3 4321 4241 4242 +3 4241 4313 4242 +3 4525 4313 4241 +3 2191 2087 1957 +3 1259 1213 1135 +3 441 614 365 +3 1258 1393 1439 +3 1439 1475 1524 +3 1475 1525 1524 +3 1393 1475 1439 +3 1333 1393 1258 +3 1333 1258 1211 +3 1258 1133 1211 +3 1133 1131 1211 +3 1083 1131 1133 +3 1083 1133 1052 +3 1083 1052 1006 +3 1052 905 1006 +3 905 924 1006 +3 806 924 905 +3 806 905 759 +3 806 759 670 +3 759 614 670 +3 614 537 670 +3 441 537 614 +3 366 441 365 +3 366 365 438 +3 365 615 438 +3 615 534 438 +3 667 534 615 +3 667 615 760 +3 667 760 803 +3 760 906 803 +3 906 915 803 +3 1007 915 906 +3 1007 906 1053 +3 1007 1053 1087 +3 1053 1135 1087 +3 1135 1165 1087 +3 1213 1165 1135 +3 1268 1213 1259 +3 1268 1259 1343 +3 1259 1440 1343 +3 1440 1395 1343 +3 1477 1395 1440 +3 1477 1440 1526 +3 1477 1526 1561 +3 1526 1622 1561 +3 1622 1631 1561 +3 1727 1631 1622 +3 1727 1622 1817 +3 1727 1817 1860 +3 1817 1957 1860 +3 1957 1993 1860 +3 2087 1993 1957 +3 2192 2087 2191 +3 6072 6169 6243 +3 6072 6320 5968 +3 5968 6432 5824 +3 5824 6576 5680 +3 5680 6716 5591 +3 6831 5688 5591 +3 5688 6724 5832 +3 5832 6584 5976 +3 5976 6440 6080 +3 6080 6328 6177 +3 6079 6177 6251 +3 6079 6327 5975 +3 5975 6439 5831 +3 5823 5679 6715 +3 5823 6575 5967 +3 6071 5967 6431 +3 6055 6237 6163 +3 6163 6304 6056 +3 6056 6416 5952 +3 5952 6560 5808 +3 5808 6700 5664 +3 6707 5815 6567 +3 6567 5959 6423 +3 6423 6063 6311 +3 6071 6319 6168 +3 6431 6319 6071 +3 6575 6431 5967 +3 6715 6575 5823 +3 6830 6715 5679 +3 6830 5679 5590 +3 6830 5590 6723 +3 5590 5687 6723 +3 5687 5831 6723 +3 5831 6583 6723 +3 6439 6583 5831 +3 6327 6439 5975 +3 6251 6327 6079 +3 6328 6251 6177 +3 6440 6328 6080 +3 6584 6440 5976 +3 6724 6584 5832 +3 6831 6724 5688 +3 6716 6831 5591 +3 6576 6716 5680 +3 6432 6576 5824 +3 6320 6432 5968 +3 6243 6320 6072 +3 6312 6243 6169 +3 6312 6169 6064 +3 6312 6064 6424 +3 5816 6424 5960 +3 6424 6064 5960 +3 6568 6424 5816 +3 6568 5816 6708 +3 5816 5672 6708 +3 5672 6821 6708 +3 5664 6821 5581 +3 6821 5672 5581 +3 6700 6821 5664 +3 6560 6700 5808 +3 6416 6560 5952 +3 6304 6416 6056 +3 6237 6304 6163 +3 6303 6237 6055 +3 6303 6055 5951 +3 6303 5951 6415 +3 5951 5807 6415 +3 5807 6559 6415 +3 6699 5807 5663 +3 6559 5807 6699 +3 6311 6168 6242 +3 6168 6319 6242 +3 6063 6168 6311 +3 5959 6063 6423 +3 5815 5959 6567 +3 5671 5815 6707 +3 5671 6707 6820 +3 5671 6820 5580 +3 6820 5663 5580 +3 6699 5663 6820 +3 7286 7344 7436 +3 7975 8254 8183 +3 7285 7193 7079 +3 6545 6513 6401 +3 6657 6513 6545 +3 6657 6545 6689 +3 6657 6689 6797 +3 6689 6889 6797 +3 6889 6882 6797 +3 6949 6882 6889 +3 6949 6889 6981 +3 6949 6981 7043 +3 6981 7079 7043 +3 7079 7141 7043 +3 7193 7141 7079 +3 7278 7193 7285 +3 7278 7285 7343 +3 7285 7435 7343 +3 7435 7399 7343 +3 7491 7399 7435 +3 7491 7435 7531 +3 7491 7531 7583 +3 7531 7675 7583 +3 7675 7668 7583 +3 7787 7668 7675 +3 7787 7675 7823 +3 7787 7823 7931 +3 7823 7975 7931 +3 7975 8075 7931 +3 8183 8075 7975 +3 8251 8183 8254 +3 8251 8254 8184 +3 8254 7976 8184 +3 7976 8076 8184 +3 7932 8076 7976 +3 7932 7976 7824 +3 7932 7824 7788 +3 7824 7676 7788 +3 7676 7669 7788 +3 7584 7669 7676 +3 7584 7676 7532 +3 7584 7532 7492 +3 7532 7436 7492 +3 7436 7400 7492 +3 7344 7400 7436 +3 7279 7344 7286 +3 7279 7286 7194 +3 7286 7080 7194 +3 7080 7142 7194 +3 7044 7142 7080 +3 7044 7080 6982 +3 7044 6982 6950 +3 6982 6890 6950 +3 6890 6883 6950 +3 6798 6883 6890 +3 6798 6890 6690 +3 6798 6690 6658 +3 6690 6546 6658 +3 6546 6514 6658 +3 6402 6514 6546 +3 6402 6546 6300 +3 6402 6300 6297 +3 6300 6401 6297 +3 6545 6401 6300 +3 7269 7187 7075 +3 6289 6395 6543 +3 7277 7343 7433 +3 7973 8069 8177 +3 7925 8069 7973 +3 7925 7973 7821 +3 7925 7821 7781 +3 7821 7667 7781 +3 7667 7668 7781 +3 7583 7668 7667 +3 7583 7667 7529 +3 7583 7529 7491 +3 7529 7433 7491 +3 7433 7399 7491 +3 7343 7399 7433 +3 7278 7343 7277 +3 7278 7277 7193 +3 7277 7077 7193 +3 7077 7141 7193 +3 7043 7141 7077 +3 7043 7077 6979 +3 7043 6979 6949 +3 6979 6881 6949 +3 6881 6882 6949 +3 6791 6882 6881 +3 6791 6881 6687 +3 6791 6687 6651 +3 6687 6543 6651 +3 6543 6507 6651 +3 6395 6507 6543 +3 6290 6395 6289 +3 6290 6289 6389 +3 6289 6541 6389 +3 6541 6501 6389 +3 6645 6501 6541 +3 6645 6541 6685 +3 6645 6685 6785 +3 6685 6873 6785 +3 6873 6874 6785 +3 6943 6874 6873 +3 6943 6873 6977 +3 6943 6977 7037 +3 6977 7075 7037 +3 7075 7135 7037 +3 7187 7135 7075 +3 7270 7187 7269 +3 7270 7269 7337 +3 7269 7431 7337 +3 7431 7393 7337 +3 7485 7393 7431 +3 7485 7431 7527 +3 7485 7527 7577 +3 7527 7659 7577 +3 7659 7660 7577 +3 7775 7660 7659 +3 7775 7659 7819 +3 7775 7819 7919 +3 7819 7971 7919 +3 7971 8063 7919 +3 8171 8063 7971 +3 8171 7971 8243 +3 8171 8243 8244 +3 8243 8177 8244 +3 7973 8177 8243 +3 5274 5330 5418 +3 5941 6228 6153 +3 5273 5185 5077 +3 4547 4511 4403 +3 4655 4511 4547 +3 4655 4547 4695 +3 4655 4695 4799 +3 4695 4893 4799 +3 4893 4886 4799 +3 4949 4886 4893 +3 4949 4893 4985 +3 4949 4985 5041 +3 4985 5077 5041 +3 5077 5129 5041 +3 5185 5129 5077 +3 5266 5185 5273 +3 5266 5273 5329 +3 5273 5417 5329 +3 5417 5381 5329 +3 5473 5381 5417 +3 5473 5417 5509 +3 5473 5509 5565 +3 5509 5653 5565 +3 5653 5646 5565 +3 5761 5646 5653 +3 5761 5653 5797 +3 5761 5797 5905 +3 5797 5941 5905 +3 5941 6049 5905 +3 6153 6049 5941 +3 6225 6153 6228 +3 6225 6228 6154 +3 6228 5942 6154 +3 5942 6050 6154 +3 5906 6050 5942 +3 5906 5942 5798 +3 5906 5798 5762 +3 5798 5654 5762 +3 5654 5647 5762 +3 5566 5647 5654 +3 5566 5654 5510 +3 5566 5510 5474 +3 5510 5418 5474 +3 5418 5382 5474 +3 5330 5382 5418 +3 5267 5330 5274 +3 5267 5274 5186 +3 5274 5078 5186 +3 5078 5130 5186 +3 5042 5130 5078 +3 5042 5078 4986 +3 5042 4986 4950 +3 4986 4894 4950 +3 4894 4887 4950 +3 4800 4887 4894 +3 4800 4894 4696 +3 4800 4696 4656 +3 4696 4548 4656 +3 4548 4512 4656 +3 4404 4512 4548 +3 4404 4548 4302 +3 4404 4302 4299 +3 4302 4403 4299 +3 4547 4403 4302 +3 5257 5179 5073 +3 4291 4397 4545 +3 5265 5329 5415 +3 5939 6043 6147 +3 5899 6043 5939 +3 5899 5939 5795 +3 5899 5795 5755 +3 5795 5645 5755 +3 5645 5646 5755 +3 5565 5646 5645 +3 5565 5645 5507 +3 5565 5507 5473 +3 5507 5415 5473 +3 5415 5381 5473 +3 5329 5381 5415 +3 5266 5329 5265 +3 5266 5265 5185 +3 5265 5075 5185 +3 5075 5129 5185 +3 5041 5129 5075 +3 5041 5075 4983 +3 5041 4983 4949 +3 4983 4885 4949 +3 4885 4886 4949 +3 4793 4886 4885 +3 4793 4885 4693 +3 4793 4693 4649 +3 4693 4545 4649 +3 4545 4505 4649 +3 4397 4505 4545 +3 4292 4397 4291 +3 4292 4291 4391 +3 4291 4543 4391 +3 4543 4499 4391 +3 4643 4499 4543 +3 4643 4543 4691 +3 4643 4691 4787 +3 4691 4877 4787 +3 4877 4878 4787 +3 4943 4878 4877 +3 4943 4877 4981 +3 4943 4981 5035 +3 4981 5073 5035 +3 5073 5123 5035 +3 5179 5123 5073 +3 5258 5179 5257 +3 5258 5257 5323 +3 5257 5413 5323 +3 5413 5375 5323 +3 5467 5375 5413 +3 5467 5413 5505 +3 5467 5505 5559 +3 5505 5637 5559 +3 5637 5638 5559 +3 5749 5638 5637 +3 5749 5637 5793 +3 5749 5793 5893 +3 5793 5937 5893 +3 5937 6037 5893 +3 6141 6037 5937 +3 6141 5937 6217 +3 6141 6217 6218 +3 6217 6147 6218 +3 5939 6147 6217 +3 3218 3269 3346 +3 4009 3814 4078 +3 3217 3146 3056 +3 2611 2591 2509 +3 2695 2591 2611 +3 2695 2611 2728 +3 2695 2728 2799 +3 2728 2881 2799 +3 2881 2876 2799 +3 2952 2876 2881 +3 2952 2881 2979 +3 2952 2979 3024 +3 2979 3056 3024 +3 3056 3099 3024 +3 3146 3099 3056 +3 3212 3146 3217 +3 3212 3217 3268 +3 3217 3345 3268 +3 3345 3314 3268 +3 3389 3314 3345 +3 3389 3345 3421 +3 3389 3421 3461 +3 3421 3545 3461 +3 3545 3539 3461 +3 3653 3539 3545 +3 3653 3545 3681 +3 3653 3681 3786 +3 3681 3814 3786 +3 3814 3909 3786 +3 4009 3909 3814 +3 4075 4009 4078 +3 4075 4078 4010 +3 4078 3815 4010 +3 3815 3910 4010 +3 3787 3910 3815 +3 3787 3815 3682 +3 3787 3682 3654 +3 3682 3546 3654 +3 3546 3540 3654 +3 3462 3540 3546 +3 3462 3546 3422 +3 3462 3422 3390 +3 3422 3346 3390 +3 3346 3315 3390 +3 3269 3315 3346 +3 3213 3269 3218 +3 3213 3218 3147 +3 3218 3057 3147 +3 3057 3100 3147 +3 3025 3100 3057 +3 3025 3057 2980 +3 3025 2980 2953 +3 2980 2882 2953 +3 2882 2877 2953 +3 2800 2877 2882 +3 2800 2882 2729 +3 2800 2729 2696 +3 2729 2612 2696 +3 2612 2592 2696 +3 2510 2592 2612 +3 2510 2612 2431 +3 2510 2431 2428 +3 2431 2509 2428 +3 2611 2509 2431 +3 3539 3460 3461 +3 3388 3389 3461 +3 3389 3313 3314 +3 3314 3267 3268 +3 3211 3212 3268 +3 3212 3145 3146 +3 2951 2876 2952 +3 2876 2875 2794 +3 2794 2793 2690 +3 2586 2690 2689 +3 2586 2585 2504 +3 2504 2503 2419 +3 2419 2418 2496 +3 3646 3647 3780 +3 3647 3538 3539 +3 3382 3306 3381 +3 3306 3307 3260 +3 3203 3260 3261 +3 3203 3204 3138 +3 3138 3139 3091 +3 2944 2868 2867 +3 2867 2787 2786 +3 2786 2683 2682 +3 2496 2495 2579 +3 2418 2495 2496 +3 2503 2418 2419 +3 2585 2503 2504 +3 2689 2585 2586 +3 2793 2689 2690 +3 2875 2793 2794 +3 2951 2875 2876 +3 3023 2951 2952 +3 3023 2952 3024 +3 3023 3024 3098 +3 3146 3098 3099 +3 3098 3024 3099 +3 3145 3098 3146 +3 3211 3145 3212 +3 3267 3211 3268 +3 3313 3267 3314 +3 3388 3313 3389 +3 3460 3388 3461 +3 3538 3460 3539 +3 3646 3538 3647 +3 3779 3646 3780 +3 3779 3780 3903 +3 3779 3903 3902 +3 3903 4003 3902 +3 4003 4002 3902 +3 4066 4002 4003 +3 4066 4003 4067 +3 4066 4067 3995 +3 3896 3995 3996 +3 3995 4067 3996 +3 3895 3995 3896 +3 3895 3896 3773 +3 3895 3773 3772 +3 3639 3773 3640 +3 3772 3773 3639 +3 2682 2579 2578 +3 2579 2495 2578 +3 2683 2579 2682 +3 2787 2683 2786 +3 2868 2787 2867 +3 2945 2868 2944 +3 2945 2944 3016 +3 2945 3016 3017 +3 3016 3091 3017 +3 3091 3092 3017 +3 3139 3092 3091 +3 3204 3139 3138 +3 3261 3204 3203 +3 3307 3261 3260 +3 3382 3307 3306 +3 3454 3382 3381 +3 3454 3381 3453 +3 3454 3453 3531 +3 3453 3530 3531 +3 3530 3640 3531 +3 3639 3640 3530 +3 1330 1383 1466 +3 2173 1989 2249 +3 1329 1252 1160 +3 640 610 515 +3 743 610 640 +3 743 640 785 +3 743 785 879 +3 785 984 879 +3 984 977 879 +3 1046 977 984 +3 1046 984 1078 +3 1046 1078 1126 +3 1078 1160 1126 +3 1160 1204 1126 +3 1252 1204 1160 +3 1322 1252 1329 +3 1322 1329 1382 +3 1329 1465 1382 +3 1465 1434 1382 +3 1516 1434 1465 +3 1516 1465 1551 +3 1516 1551 1600 +3 1551 1700 1600 +3 1700 1692 1600 +3 1810 1692 1700 +3 1810 1700 1842 +3 1810 1842 1943 +3 1842 1989 1943 +3 1989 2076 1943 +3 2173 2076 1989 +3 2246 2173 2249 +3 2246 2249 2174 +3 2249 1990 2174 +3 1990 2077 2174 +3 1944 2077 1990 +3 1944 1990 1843 +3 1944 1843 1811 +3 1843 1701 1811 +3 1701 1693 1811 +3 1601 1693 1701 +3 1601 1701 1552 +3 1601 1552 1517 +3 1552 1466 1517 +3 1466 1435 1517 +3 1383 1435 1466 +3 1323 1383 1330 +3 1323 1330 1253 +3 1330 1161 1253 +3 1161 1205 1253 +3 1127 1205 1161 +3 1127 1161 1079 +3 1127 1079 1047 +3 1079 985 1047 +3 985 978 1047 +3 880 978 985 +3 880 985 786 +3 880 786 744 +3 786 641 744 +3 641 611 744 +3 516 611 641 +3 516 641 416 +3 516 416 413 +3 416 515 413 +3 640 515 416 +3 1515 1516 1600 +3 1516 1433 1434 +3 873 736 737 +3 737 603 604 +3 501 500 596 +3 595 729 596 +3 729 728 865 +3 1796 1928 1929 +3 1929 2061 2062 +3 2238 2166 2167 +3 1425 1426 1373 +3 1196 1195 1243 +3 1195 1118 1117 +3 1117 1038 1037 +3 865 864 967 +3 728 864 865 +3 595 728 729 +3 500 595 596 +3 403 500 501 +3 403 501 404 +3 403 404 508 +3 604 508 509 +3 508 404 509 +3 603 508 604 +3 736 603 737 +3 872 736 873 +3 872 873 977 +3 872 977 976 +3 977 1046 976 +3 1046 1045 976 +3 1125 1045 1046 +3 1125 1046 1126 +3 1125 1126 1203 +3 1126 1204 1203 +3 1204 1251 1203 +3 1322 1251 1252 +3 1251 1204 1252 +3 1321 1251 1322 +3 1321 1322 1381 +3 1434 1381 1382 +3 1381 1322 1382 +3 1433 1381 1434 +3 1515 1433 1516 +3 1599 1515 1600 +3 1599 1600 1692 +3 1599 1692 1691 +3 1692 1804 1691 +3 1804 1803 1691 +3 1936 1803 1804 +3 1936 1804 1937 +3 1936 1937 2069 +3 2167 2069 2070 +3 2069 1937 2070 +3 2166 2069 2167 +3 2237 2166 2238 +3 2237 2238 2158 +3 2062 2158 2159 +3 2158 2238 2159 +3 2061 2158 2062 +3 1928 2061 1929 +3 1795 1796 1682 +3 1928 1796 1795 +3 1037 967 966 +3 967 864 966 +3 1038 967 1037 +3 1118 1038 1117 +3 1196 1118 1195 +3 1244 1196 1243 +3 1244 1243 1311 +3 1244 1311 1312 +3 1311 1373 1312 +3 1373 1374 1312 +3 1426 1374 1373 +3 1508 1426 1425 +3 1508 1425 1507 +3 1508 1507 1592 +3 1507 1591 1592 +3 1591 1681 1592 +3 1681 1682 1592 +3 1795 1682 1681 +3 8557 8166 8553 +3 8556 7913 8562 +3 8562 7769 8568 +3 8586 8177 8592 +3 8622 8184 8617 +3 7661 8569 7776 +3 7776 8575 7920 +3 8587 8172 8581 +3 8245 8172 8587 +3 8245 8587 8178 +3 8587 8593 8178 +3 8593 8070 8178 +3 7926 8070 8593 +3 7926 8593 8599 +3 7926 8599 7782 +3 8599 8605 7782 +3 8605 7669 7782 +3 7788 7669 8605 +3 7788 8605 8611 +3 7788 8611 7932 +3 8611 8617 7932 +3 8617 8076 7932 +3 8184 8076 8617 +3 8251 8184 8622 +3 8251 8622 8183 +3 8622 8616 8183 +3 8616 8075 8183 +3 7931 8075 8616 +3 7931 8616 8610 +3 7931 8610 7787 +3 8610 8604 7787 +3 8604 7668 7787 +3 7781 7668 8604 +3 7781 8604 8598 +3 7781 8598 7925 +3 8598 8592 7925 +3 8592 8069 7925 +3 8177 8069 8592 +3 8244 8177 8586 +3 8244 8586 8171 +3 8586 8580 8171 +3 8580 8063 8171 +3 7919 8063 8580 +3 7919 8580 8574 +3 7919 8574 7775 +3 8574 8568 7775 +3 8568 7660 7775 +3 7769 7660 8568 +3 7913 7769 8562 +3 8057 7913 8556 +3 8057 8556 8165 +3 8556 8553 8165 +3 8553 8240 8165 +3 8166 8240 8553 +3 8058 8166 8557 +3 7914 8557 8563 +3 8058 8557 7914 +3 7770 8563 8569 +3 7914 8563 7770 +3 7920 8581 8064 +3 8581 8172 8064 +3 8575 8581 7920 +3 8569 8575 7776 +3 7770 8569 7661 +3 342 515 336 +3 298 501 290 +3 253 494 259 +3 291 597 502 +3 730 597 291 +3 730 291 283 +3 730 283 866 +3 283 275 866 +3 275 968 866 +3 858 968 275 +3 858 275 267 +3 858 267 722 +3 267 259 722 +3 259 589 722 +3 494 589 259 +3 398 494 253 +3 398 253 493 +3 253 258 493 +3 258 588 493 +3 721 588 258 +3 721 258 266 +3 721 266 857 +3 266 274 857 +3 274 967 857 +3 865 967 274 +3 865 274 282 +3 865 282 729 +3 282 290 729 +3 290 596 729 +3 501 596 290 +3 404 501 298 +3 404 298 509 +3 298 308 509 +3 308 604 509 +3 737 604 308 +3 737 308 315 +3 737 315 873 +3 315 322 873 +3 322 977 873 +3 879 977 322 +3 879 322 329 +3 879 329 743 +3 329 336 743 +3 336 610 743 +3 515 610 336 +3 413 515 342 +3 413 342 516 +3 342 337 516 +3 337 611 516 +3 744 611 337 +3 744 337 330 +3 744 330 880 +3 330 323 880 +3 323 978 880 +3 874 978 323 +3 874 323 316 +3 874 316 738 +3 316 309 738 +3 309 605 738 +3 510 605 309 +3 510 309 299 +3 510 299 405 +3 299 502 405 +3 291 502 299 +3 1930 2580 2063 +3 2063 2497 2160 +3 2160 2420 2239 +3 2239 2505 2168 +3 2071 2168 2587 +3 2071 2691 1938 +3 1938 2795 1805 +3 1805 2877 1693 +3 1693 2800 1811 +3 1811 2696 1944 +3 2246 2428 2173 +3 2173 2509 2076 +3 2076 2591 1943 +3 1943 2695 1810 +3 2572 2054 1921 +3 1922 2677 1789 +3 2781 1683 1789 +3 2868 1682 2787 +3 2787 1796 2683 +3 2683 1929 2579 +3 2579 2062 2496 +3 2586 2504 2070 +3 1937 2690 2586 +3 2690 1804 2794 +3 1810 2799 1692 +3 2695 2799 1810 +3 2591 2695 1943 +3 2509 2591 2076 +3 2428 2509 2173 +3 2510 2428 2246 +3 2510 2246 2174 +3 2510 2174 2592 +3 1944 2592 2077 +3 2592 2174 2077 +3 2696 2592 1944 +3 2800 2696 1811 +3 2877 2800 1693 +3 2795 2877 1805 +3 2691 2795 1938 +3 2587 2691 2071 +3 2505 2587 2168 +3 2420 2505 2239 +3 2497 2420 2160 +3 2580 2497 2063 +3 2684 2580 1930 +3 2684 1930 1797 +3 2684 1797 2788 +3 1797 1683 2788 +3 1683 2869 2788 +3 2781 2869 1683 +3 2677 2781 1789 +3 2573 2677 1922 +3 2573 1922 2055 +3 2573 2055 2490 +3 2232 2490 2152 +3 2490 2055 2152 +3 2415 2490 2232 +3 2415 2232 2151 +3 2415 2151 2489 +3 2151 2054 2489 +3 2054 2572 2489 +3 2676 1921 1788 +3 2572 1921 2676 +3 2780 1788 1682 +3 2676 1788 2780 +3 2794 1692 2876 +3 1692 2799 2876 +3 1804 1692 2794 +3 1937 1804 2690 +3 2070 1937 2586 +3 2167 2070 2504 +3 2167 2504 2238 +3 2504 2419 2238 +3 2419 2496 2238 +3 2496 2159 2238 +3 2062 2159 2496 +3 1929 2062 2579 +3 1796 1929 2683 +3 1682 1796 2787 +3 2780 1682 2868 +3 3997 4293 4068 +3 3648 4887 3540 +3 4655 3786 3909 +3 3633 4781 3766 +3 3990 4494 3890 +3 4292 4067 4397 +3 4505 4397 4003 +3 3786 4799 3653 +3 4799 3539 3653 +3 4655 4799 3786 +3 4511 4655 3909 +3 4511 3909 4403 +3 4075 4403 4009 +3 4403 3909 4009 +3 4299 4403 4075 +3 4299 4075 4010 +3 4299 4010 4404 +3 4010 3910 4404 +3 3910 4512 4404 +3 4656 4512 3910 +3 4656 3910 3787 +3 4656 3787 4800 +3 3540 4800 3654 +3 4800 3787 3654 +3 4887 4800 3540 +3 4794 4887 3648 +3 4794 3648 3781 +3 4794 3781 4650 +3 3781 3904 4650 +3 3904 4506 4650 +3 4398 4506 3904 +3 4068 4398 4004 +3 4398 3904 4004 +3 4293 4398 4068 +3 4392 4293 3997 +3 4392 3997 4500 +3 3997 3897 4500 +3 3897 3774 4500 +3 3774 4644 4500 +3 4788 4644 3774 +3 4788 3774 3641 +3 4788 3641 4879 +3 3641 3532 4879 +3 3532 3634 4879 +3 3634 4782 4879 +3 4638 4782 3634 +3 3890 4638 3767 +3 4638 3634 3767 +3 4494 4638 3890 +3 4386 4494 3990 +3 4386 3990 4288 +3 3990 4063 4288 +3 4063 3989 4288 +3 3989 4385 4288 +3 4493 4385 3989 +3 4493 3989 3889 +3 4493 3889 3766 +3 4493 3766 4637 +3 3766 4781 4637 +3 4793 3539 4886 +3 3539 4799 4886 +3 3647 3539 4793 +3 3647 4793 4649 +3 3647 4649 3780 +3 4649 4505 3780 +3 4505 3903 3780 +3 4003 3903 4505 +3 4067 4003 4397 +3 3996 4067 4292 +3 3996 4292 4391 +3 3996 4391 3896 +3 4391 4499 3896 +3 4499 4643 3896 +3 4643 3773 3896 +3 3640 3773 4643 +3 3640 4643 4787 +3 3640 4787 3531 +3 4787 4878 3531 +3 4878 3633 3531 +3 4781 3633 4878 +3 6875 5750 5639 +3 5750 6786 5894 +3 5894 6646 6038 +3 6038 6502 6142 +3 6219 6142 6390 +3 6219 6291 6148 +3 6396 6044 6148 +3 5647 6883 5762 +3 6050 6402 6154 +3 6154 6297 6225 +3 6225 6401 6153 +3 6153 6513 6049 +3 6496 5888 6032 +3 6874 5638 6785 +3 6785 5749 6645 +3 5893 6501 6645 +3 6501 6037 6389 +3 6389 6141 6290 +3 6507 5899 6651 +3 5755 6791 6651 +3 6882 6791 5646 +3 6049 6657 5905 +3 6657 5761 5905 +3 6513 6657 6049 +3 6401 6513 6153 +3 6297 6401 6225 +3 6402 6297 6154 +3 6514 6402 6050 +3 6514 6050 5906 +3 6514 5906 6658 +3 5906 5762 6658 +3 5762 6798 6658 +3 6883 6798 5762 +3 6792 6883 5647 +3 6792 5647 5756 +3 6792 5756 5900 +3 6792 5900 6652 +3 5900 6044 6652 +3 6044 6508 6652 +3 6396 6508 6044 +3 6291 6396 6148 +3 6390 6291 6219 +3 6502 6390 6142 +3 6646 6502 6038 +3 6786 6646 5894 +3 6875 6786 5750 +3 6780 6875 5639 +3 6780 5639 5744 +3 6780 5744 6640 +3 5744 5888 6640 +3 5888 6496 6640 +3 6384 6032 6136 +3 6496 6032 6384 +3 6135 6286 6214 +3 6286 6136 6214 +3 6384 6136 6286 +3 6383 6135 6031 +3 6286 6135 6383 +3 6495 6031 5887 +3 6383 6031 6495 +3 6639 5887 5743 +3 6495 5887 6639 +3 6779 5743 5638 +3 6639 5743 6779 +3 6882 5761 6797 +3 5761 6657 6797 +3 5646 5761 6882 +3 5755 5646 6791 +3 5899 5755 6651 +3 6043 5899 6507 +3 6043 6507 6395 +3 6043 6395 6147 +3 6395 6290 6147 +3 6290 6218 6147 +3 6141 6218 6290 +3 6037 6141 6389 +3 5893 6037 6501 +3 5749 5893 6645 +3 5638 5749 6785 +3 6779 5638 6874 +3 7577 7571 7485 +3 7485 7479 7393 +3 7393 7387 7337 +3 7337 7331 7270 +3 7187 7270 7260 +3 7135 7187 7181 +3 7135 7129 7037 +3 7037 7031 6943 +3 6943 6937 6874 +3 6874 6864 6779 +3 6779 6773 6639 +3 6633 6495 6639 +3 6495 6489 6383 +3 6383 6377 6286 +3 6282 6384 6286 +3 6384 6378 6496 +3 6496 6490 6640 +3 6944 6938 7038 +3 7038 7032 7136 +3 7136 7130 7188 +3 7188 7182 7271 +3 7271 7261 7338 +3 7486 7572 7578 +3 7578 7651 7661 +3 7572 7651 7578 +3 7480 7572 7486 +3 7480 7486 7394 +3 7480 7394 7388 +3 7394 7338 7388 +3 7338 7332 7388 +3 7261 7332 7338 +3 7182 7261 7271 +3 7130 7182 7188 +3 7032 7130 7136 +3 6938 7032 7038 +3 6865 6938 6944 +3 6865 6944 6875 +3 6865 6875 6780 +3 6865 6780 6774 +3 6780 6640 6774 +3 6640 6634 6774 +3 6490 6634 6640 +3 6378 6490 6496 +3 6282 6378 6384 +3 6377 6282 6286 +3 6489 6377 6383 +3 6633 6489 6495 +3 6773 6633 6639 +3 6864 6773 6779 +3 6937 6864 6874 +3 7031 6937 6943 +3 7129 7031 7037 +3 7181 7129 7135 +3 7260 7181 7187 +3 7331 7260 7270 +3 7387 7331 7337 +3 7479 7387 7393 +3 7571 7479 7485 +3 7650 7571 7577 +3 7650 7577 7660 +3 7650 7660 7763 +3 7913 7763 7769 +3 7763 7660 7769 +3 7907 7763 7913 +3 7907 7913 8057 +3 7907 8057 8051 +3 8057 8165 8051 +3 8165 8159 8051 +3 8236 8159 8165 +3 8236 8165 8240 +3 8236 8240 8160 +3 8240 8166 8160 +3 8166 8058 8160 +3 8058 8052 8160 +3 7908 8052 8058 +3 7908 8058 7914 +3 7908 7914 7764 +3 7914 7770 7764 +3 7770 7661 7764 +3 7661 7651 7764 +3 7570 7571 7650 +3 7571 7478 7479 +3 7387 7479 7386 +3 7330 7331 7387 +3 7331 7259 7260 +3 7031 7030 6937 +3 6937 6936 6864 +3 6864 6863 6765 +3 6765 6764 6625 +3 6625 6624 6481 +3 6481 6480 6369 +3 6369 6368 6274 +3 8228 8227 8151 +3 7899 7754 7755 +3 7755 7649 7650 +3 7470 7471 7378 +3 7378 7379 7322 +3 7322 7323 7249 +3 7249 7250 7172 +3 7120 7172 7173 +3 6928 6854 6853 +3 6853 6757 6756 +3 6756 6617 6616 +3 6616 6473 6472 +3 6274 6273 6361 +3 6368 6273 6274 +3 6480 6368 6369 +3 6624 6480 6481 +3 6764 6624 6625 +3 6863 6764 6765 +3 6936 6863 6864 +3 7030 6936 6937 +3 7128 7030 7031 +3 7128 7031 7129 +3 7128 7129 7180 +3 7260 7180 7181 +3 7180 7129 7181 +3 7259 7180 7260 +3 7330 7259 7331 +3 7386 7330 7387 +3 7478 7386 7479 +3 7570 7478 7571 +3 7649 7570 7650 +3 7754 7649 7755 +3 7898 7754 7899 +3 7898 7899 8043 +3 7898 8043 8042 +3 8043 8151 8042 +3 8151 8150 8042 +3 8227 8150 8151 +3 8142 8227 8228 +3 8142 8228 8143 +3 8142 8143 8035 +3 8142 8035 8034 +3 7890 8035 7891 +3 8034 8035 7890 +3 7746 7891 7747 +3 7890 7891 7746 +3 6472 6361 6360 +3 6361 6273 6360 +3 6473 6361 6472 +3 6617 6473 6616 +3 6757 6617 6756 +3 6854 6757 6853 +3 6929 6854 6928 +3 6929 6928 7022 +3 6929 7022 7023 +3 7022 7120 7023 +3 7120 7121 7023 +3 7173 7121 7120 +3 7250 7173 7172 +3 7323 7250 7249 +3 7379 7323 7322 +3 7471 7379 7378 +3 7563 7471 7470 +3 7563 7470 7562 +3 7563 7562 7640 +3 7562 7639 7640 +3 7639 7747 7640 +3 7746 7747 7639 +3 5638 5553 5559 +3 5559 5461 5467 +3 5467 5369 5375 +3 5317 5323 5375 +3 5323 5248 5258 +3 4943 4937 4878 +3 4878 4868 4781 +3 4781 4775 4637 +3 4637 4631 4493 +3 4385 4493 4487 +3 4385 4379 4288 +3 4386 4288 4284 +3 4386 4380 4494 +3 4494 4488 4638 +3 5036 4944 4938 +3 5036 5030 5124 +3 5124 5118 5180 +3 5174 5259 5180 +3 5744 5882 5888 +3 6214 6210 6135 +3 5737 5743 5887 +3 5743 5628 5638 +3 5462 5376 5370 +3 5259 5249 5324 +3 5174 5249 5259 +3 5118 5174 5180 +3 5030 5118 5124 +3 4938 5030 5036 +3 4869 4938 4944 +3 4869 4944 4879 +3 4869 4879 4782 +3 4869 4782 4776 +3 4782 4638 4776 +3 4638 4632 4776 +3 4488 4632 4638 +3 4380 4488 4494 +3 4284 4380 4386 +3 4379 4284 4288 +3 4487 4379 4385 +3 4631 4487 4493 +3 4775 4631 4637 +3 4868 4775 4781 +3 4937 4868 4878 +3 5029 4937 4943 +3 5029 4943 5035 +3 5029 5035 5117 +3 5035 5123 5117 +3 5123 5173 5117 +3 5258 5173 5179 +3 5173 5123 5179 +3 5248 5173 5258 +3 5317 5248 5323 +3 5369 5317 5375 +3 5461 5369 5467 +3 5553 5461 5559 +3 5628 5553 5638 +3 5737 5628 5743 +3 5881 5737 5887 +3 5881 5887 6031 +3 5881 6031 6025 +3 6031 6135 6025 +3 6135 6129 6025 +3 6210 6129 6135 +3 6130 6210 6214 +3 6130 6214 6136 +3 6130 6136 6032 +3 6130 6032 6026 +3 6032 5888 6026 +3 5888 5882 6026 +3 5738 5744 5639 +3 5882 5744 5738 +3 5370 5324 5318 +3 5324 5249 5318 +3 5376 5324 5370 +3 5468 5376 5462 +3 5468 5462 5554 +3 5468 5554 5560 +3 5554 5629 5560 +3 5629 5639 5560 +3 5738 5639 5629 +3 5552 5553 5628 +3 5461 5553 5460 +3 5461 5368 5369 +3 5369 5316 5317 +3 5317 5247 5248 +3 5029 5028 4937 +3 4937 4936 4868 +3 4868 4867 4767 +3 4767 4766 4623 +3 4623 4622 4479 +3 4479 4478 4371 +3 4371 4370 4276 +3 4276 4275 4363 +3 6009 6008 6113 +3 5873 5728 5729 +3 5729 5627 5628 +3 5452 5453 5360 +3 5360 5361 5308 +3 5308 5309 5237 +3 5237 5238 5164 +3 5165 5108 5164 +3 5108 5109 5020 +3 4758 4857 4759 +3 4614 4758 4615 +3 4363 4362 4471 +3 4275 4362 4363 +3 4370 4275 4276 +3 4478 4370 4371 +3 4622 4478 4479 +3 4766 4622 4623 +3 4867 4766 4767 +3 4936 4867 4868 +3 5028 4936 4937 +3 5116 5028 5029 +3 5116 5029 5117 +3 5116 5117 5172 +3 5248 5172 5173 +3 5172 5117 5173 +3 5247 5172 5248 +3 5316 5247 5317 +3 5368 5316 5369 +3 5460 5368 5461 +3 5552 5460 5553 +3 5627 5552 5628 +3 5728 5627 5729 +3 5872 5728 5873 +3 5872 5873 6017 +3 5872 6017 6016 +3 6017 6121 6016 +3 6121 6120 6016 +3 6201 6120 6121 +3 6201 6121 6202 +3 6201 6202 6112 +3 6202 6113 6112 +3 6113 6008 6112 +3 5864 6009 5865 +3 6008 6009 5864 +3 5720 5865 5721 +3 5864 5865 5720 +3 4614 4471 4470 +3 4471 4362 4470 +3 4615 4471 4614 +3 4759 4615 4758 +3 4858 4759 4857 +3 4858 4857 4928 +3 4858 4928 4929 +3 4928 5020 4929 +3 5020 5021 4929 +3 5109 5021 5020 +3 5165 5109 5108 +3 5238 5165 5164 +3 5309 5238 5237 +3 5361 5309 5308 +3 5453 5361 5360 +3 5545 5453 5452 +3 5545 5452 5544 +3 5545 5544 5618 +3 5544 5617 5618 +3 5617 5721 5618 +3 5720 5721 5617 +3 3448 3454 3531 +3 3454 3376 3382 +3 3382 3301 3307 +3 3139 3133 3092 +3 3092 3086 3017 +3 3017 3011 2945 +3 2945 2939 2868 +3 2868 2861 2780 +3 2775 2676 2780 +3 2671 2572 2676 +3 2572 2566 2489 +3 2489 2483 2415 +3 2490 2415 2411 +3 2490 2484 2573 +3 2573 2567 2677 +3 2677 2672 2781 +3 2781 2776 2869 +3 2869 2862 2946 +3 3093 3134 3140 +3 3140 3198 3205 +3 3262 3205 3256 +3 3262 3302 3308 +3 3308 3377 3383 +3 3383 3449 3455 +3 3766 3626 3633 +3 3523 3531 3633 +3 3455 3524 3532 +3 3449 3524 3455 +3 3377 3449 3383 +3 3302 3377 3308 +3 3256 3302 3262 +3 3198 3256 3205 +3 3134 3198 3140 +3 3087 3134 3093 +3 3087 3093 3018 +3 3087 3018 3012 +3 3018 2946 3012 +3 2946 2940 3012 +3 2862 2940 2946 +3 2776 2862 2869 +3 2672 2776 2781 +3 2567 2672 2677 +3 2484 2567 2573 +3 2411 2484 2490 +3 2483 2411 2415 +3 2566 2483 2489 +3 2671 2566 2572 +3 2775 2671 2676 +3 2861 2775 2780 +3 2939 2861 2868 +3 3011 2939 2945 +3 3086 3011 3017 +3 3133 3086 3092 +3 3197 3133 3139 +3 3197 3139 3204 +3 3197 3204 3255 +3 3307 3255 3261 +3 3255 3204 3261 +3 3301 3255 3307 +3 3376 3301 3382 +3 3448 3376 3454 +3 3523 3448 3531 +3 3626 3523 3633 +3 3759 3626 3766 +3 3759 3766 3889 +3 3759 3889 3882 +3 3889 3989 3882 +3 3989 3982 3882 +3 4059 3982 3989 +3 4059 3989 4063 +3 4059 4063 3983 +3 3890 3983 3990 +3 3983 4063 3990 +3 3883 3983 3890 +3 3883 3890 3767 +3 3883 3767 3760 +3 3767 3627 3760 +3 3532 3627 3634 +3 3627 3767 3634 +3 3524 3627 3532 +3 3523 3447 3448 +3 3375 3376 3448 +3 3376 3300 3301 +3 3301 3254 3255 +3 3196 3197 3255 +3 3197 3132 3133 +3 3133 3085 3086 +3 3086 3010 3011 +3 2938 2939 3011 +3 2666 2665 2561 +3 2560 2478 2561 +3 2477 2405 2478 +3 2405 2404 2473 +3 2473 2472 2556 +3 2556 2555 2661 +3 2661 2660 2765 +3 2765 2764 2854 +3 2854 2853 2933 +3 2933 2932 3005 +3 3005 3004 3080 +3 3080 3079 3127 +3 3126 3190 3127 +3 3190 3189 3249 +3 3249 3248 3295 +3 3752 3618 3619 +3 3619 3522 3523 +3 3295 3294 3370 +3 3248 3294 3295 +3 3189 3248 3249 +3 3126 3189 3190 +3 3079 3126 3127 +3 3004 3079 3080 +3 2932 3004 3005 +3 2853 2932 2933 +3 2764 2853 2854 +3 2660 2764 2765 +3 2555 2660 2661 +3 2472 2555 2556 +3 2404 2472 2473 +3 2477 2404 2405 +3 2560 2477 2478 +3 2665 2560 2561 +3 2769 2665 2666 +3 2769 2666 2770 +3 2769 2770 2860 +3 2939 2860 2861 +3 2860 2770 2861 +3 2938 2860 2939 +3 3010 2938 3011 +3 3085 3010 3086 +3 3132 3085 3133 +3 3196 3132 3197 +3 3254 3196 3255 +3 3300 3254 3301 +3 3375 3300 3376 +3 3447 3375 3448 +3 3522 3447 3523 +3 3618 3522 3619 +3 3751 3618 3752 +3 3751 3752 3875 +3 3751 3875 3874 +3 3875 3975 3874 +3 3975 3974 3874 +3 4050 3974 3975 +3 4050 3975 4051 +3 4050 4051 3967 +3 3868 3967 3968 +3 3967 4051 3968 +3 3867 3967 3868 +3 3867 3868 3745 +3 3867 3745 3744 +3 3611 3745 3612 +3 3744 3745 3611 +3 3441 3370 3369 +3 3370 3294 3369 +3 3442 3370 3441 +3 3442 3441 3514 +3 3442 3514 3515 +3 3514 3612 3515 +3 3611 3612 3514 +3 1238 1196 1244 +3 1196 1190 1118 +3 1118 1112 1038 +3 1789 1916 1922 +3 1921 1915 1788 +3 1788 1782 1682 +3 1674 1683 1587 +3 1587 1593 1503 +3 1421 1503 1509 +3 1421 1427 1369 +3 1369 1375 1303 +3 1239 1303 1313 +3 1239 1245 1191 +3 1191 1197 1113 +3 1119 1033 1113 +3 1039 959 1033 +3 959 968 852 +3 852 858 716 +3 716 722 583 +3 583 589 487 +3 487 494 395 +3 395 398 486 +3 493 582 486 +3 1038 1032 967 +3 1112 1032 1038 +3 1190 1112 1118 +3 1238 1190 1196 +3 1302 1238 1244 +3 1302 1244 1312 +3 1302 1312 1368 +3 1312 1374 1368 +3 1374 1420 1368 +3 1508 1420 1426 +3 1420 1374 1426 +3 1502 1420 1508 +3 1502 1508 1592 +3 1502 1592 1586 +3 1592 1682 1586 +3 1682 1673 1586 +3 1782 1673 1682 +3 1915 1782 1788 +3 2048 1915 1921 +3 2048 1921 2054 +3 2048 2054 2144 +3 2054 2151 2144 +3 2151 2232 2144 +3 2232 2229 2144 +3 2145 2229 2232 +3 2145 2232 2152 +3 2145 2152 2055 +3 2145 2055 2049 +3 2055 1922 2049 +3 1922 1916 2049 +3 1783 1789 1683 +3 1916 1789 1783 +3 851 967 958 +3 967 1032 958 +3 857 967 851 +3 857 851 715 +3 857 715 721 +3 715 582 721 +3 582 588 721 +3 493 588 582 +3 398 493 486 +3 494 398 395 +3 589 494 487 +3 722 589 583 +3 858 722 716 +3 968 858 852 +3 1039 968 959 +3 1119 1039 1033 +3 1197 1119 1113 +3 1245 1197 1191 +3 1313 1245 1239 +3 1375 1313 1303 +3 1427 1375 1369 +3 1509 1427 1421 +3 1593 1509 1503 +3 1683 1593 1587 +3 1783 1683 1674 +3 1673 1672 1586 +3 1585 1502 1586 +3 1502 1501 1420 +3 1302 1237 1238 +3 1238 1189 1190 +3 1190 1111 1112 +3 1112 1031 1032 +3 1032 957 958 +3 958 844 845 +3 845 708 709 +3 389 388 474 +3 474 473 570 +3 570 569 703 +3 703 702 839 +3 839 838 949 +3 949 948 1026 +3 1026 1025 1106 +3 1184 1106 1105 +3 1183 1232 1184 +3 1232 1231 1294 +3 1903 1770 1902 +3 2138 2223 2222 +3 1776 1775 1673 +3 1495 1414 1413 +3 1294 1293 1362 +3 1231 1293 1294 +3 1183 1231 1232 +3 1105 1183 1184 +3 1025 1105 1106 +3 948 1025 1026 +3 838 948 949 +3 702 838 839 +3 569 702 703 +3 473 569 570 +3 388 473 474 +3 479 388 389 +3 479 389 480 +3 479 480 575 +3 709 575 576 +3 575 480 576 +3 708 575 709 +3 844 708 845 +3 957 844 958 +3 1031 957 1032 +3 1111 1031 1112 +3 1189 1111 1190 +3 1237 1189 1238 +3 1301 1237 1302 +3 1301 1302 1368 +3 1301 1368 1367 +3 1368 1420 1367 +3 1420 1419 1367 +3 1501 1419 1420 +3 1585 1501 1502 +3 1672 1585 1586 +3 1775 1672 1673 +3 1908 1775 1776 +3 1908 1776 1909 +3 1908 1909 2042 +3 1908 2042 2041 +3 2042 2138 2041 +3 2138 2137 2041 +3 2222 2137 2138 +3 2131 2222 2223 +3 2131 2223 2132 +3 2131 2132 2036 +3 2131 2036 2035 +3 2036 1903 2035 +3 1903 1902 2035 +3 1769 1770 1664 +3 1902 1770 1769 +3 1413 1362 1361 +3 1362 1293 1361 +3 1414 1362 1413 +3 1496 1414 1495 +3 1496 1495 1579 +3 1496 1579 1580 +3 1579 1663 1580 +3 1663 1664 1580 +3 1769 1664 1663 +3 8450 8135 8455 +3 8495 8151 8503 +3 8542 8160 8536 +3 7641 8472 7748 +3 7748 8480 7892 +3 8496 8144 8488 +3 8229 8144 8496 +3 8229 8496 8152 +3 8496 8504 8152 +3 8504 8044 8152 +3 7900 8044 8504 +3 7900 8504 8512 +3 7900 8512 7756 +3 8512 8520 7756 +3 8520 7651 7756 +3 7764 7651 8520 +3 7764 8520 8528 +3 7764 8528 7908 +3 8528 8536 7908 +3 8536 8052 7908 +3 8160 8052 8536 +3 8236 8160 8542 +3 8236 8542 8159 +3 8542 8535 8159 +3 8535 8051 8159 +3 7907 8051 8535 +3 7907 8535 8527 +3 7907 8527 7763 +3 8527 8519 7763 +3 8519 7650 7763 +3 7755 7650 8519 +3 7755 8519 8511 +3 7755 8511 7899 +3 8511 8503 7899 +3 8503 8043 7899 +3 8151 8043 8503 +3 8228 8151 8495 +3 8228 8495 8143 +3 8495 8487 8143 +3 8487 8035 8143 +3 7891 8035 8487 +3 7891 8487 8479 +3 7891 8479 7747 +3 8479 8471 7747 +3 8471 7640 7747 +3 7739 7640 8471 +3 7739 8471 8463 +3 7739 8463 7883 +3 8463 8455 7883 +3 8455 8027 7883 +3 8135 8027 8455 +3 8222 8135 8450 +3 8222 8450 8136 +3 8450 8456 8136 +3 8456 8028 8136 +3 7884 8456 8464 +3 8028 8456 7884 +3 7740 8464 8472 +3 7884 8464 7740 +3 7892 8488 8036 +3 8488 8144 8036 +3 8480 8488 7892 +3 8472 8480 7748 +3 7740 8472 7641 +3 239 486 233 +3 197 474 191 +3 158 469 165 +3 192 571 475 +3 704 571 192 +3 704 192 186 +3 704 186 840 +3 186 179 840 +3 179 950 840 +3 834 950 179 +3 834 179 172 +3 834 172 698 +3 172 165 698 +3 165 565 698 +3 469 565 165 +3 384 469 158 +3 384 158 468 +3 158 164 468 +3 164 564 468 +3 697 564 164 +3 697 164 171 +3 697 171 833 +3 171 178 833 +3 178 949 833 +3 839 949 178 +3 839 178 185 +3 839 185 703 +3 185 191 703 +3 191 570 703 +3 474 570 191 +3 389 474 197 +3 389 197 480 +3 197 205 480 +3 205 576 480 +3 709 576 205 +3 709 205 211 +3 709 211 845 +3 211 218 845 +3 218 958 845 +3 851 958 218 +3 851 218 226 +3 851 226 715 +3 226 233 715 +3 233 582 715 +3 486 582 233 +3 395 486 239 +3 395 239 487 +3 239 234 487 +3 234 583 487 +3 716 583 234 +3 716 234 227 +3 716 227 852 +3 227 219 852 +3 219 959 852 +3 846 959 219 +3 846 219 212 +3 846 212 710 +3 212 206 710 +3 206 577 710 +3 481 577 206 +3 481 206 198 +3 481 198 390 +3 198 475 390 +3 192 475 198 +3 2855 1771 1665 +3 2766 1904 1771 +3 2662 2037 1904 +3 2557 2133 2037 +3 2133 2474 2224 +3 2139 2224 2406 +3 1764 2760 1897 +3 2126 2468 2218 +3 2127 2218 2402 +3 2469 2031 2127 +3 2552 1898 2031 +3 2657 1765 1898 +3 1765 2761 1665 +3 2661 1903 2556 +3 2036 2473 2556 +3 2561 2478 2042 +3 2561 1909 2666 +3 2666 1776 2770 +3 2770 1673 2861 +3 2861 1782 2775 +3 2775 1915 2671 +3 2671 2048 2566 +3 2566 2144 2483 +3 2483 2229 2411 +3 2411 2145 2484 +3 2567 2484 2049 +3 2567 1916 2672 +3 2672 1783 2776 +3 2862 2776 1674 +3 1777 2771 2862 +3 2771 1910 2667 +3 2139 2479 2043 +3 2406 2479 2139 +3 2474 2406 2224 +3 2557 2474 2133 +3 2662 2557 2037 +3 2766 2662 1904 +3 2855 2766 1771 +3 2761 2855 1665 +3 2657 2761 1765 +3 2552 2657 1898 +3 2469 2552 2031 +3 2402 2469 2127 +3 2468 2402 2218 +3 2551 2468 2126 +3 2551 2126 2030 +3 2551 2030 2656 +3 2030 1897 2656 +3 1897 2760 2656 +3 2667 2043 2562 +3 2043 2479 2562 +3 1910 2043 2667 +3 1777 1910 2771 +3 1674 1777 2862 +3 1783 1674 2776 +3 1916 1783 2672 +3 2049 1916 2567 +3 2145 2049 2484 +3 2229 2145 2411 +3 2144 2229 2483 +3 2048 2144 2566 +3 1915 2048 2671 +3 1782 1915 2775 +3 1673 1782 2861 +3 1776 1673 2770 +3 1909 1776 2666 +3 2042 1909 2561 +3 2138 2042 2478 +3 2138 2478 2223 +3 2478 2405 2223 +3 2405 2473 2223 +3 2473 2132 2223 +3 2036 2132 2473 +3 1903 2036 2556 +3 1770 1903 2661 +3 1770 2661 2765 +3 1770 2765 1664 +3 2765 2854 1664 +3 2854 1764 1664 +3 2760 1764 2854 +3 3746 4616 3869 +3 3753 4768 3620 +3 4380 3983 3883 +3 3983 4284 4059 +3 3982 4059 4379 +3 4767 3619 3523 +3 3619 4623 3752 +3 4371 4051 3975 +3 4051 4276 3968 +3 3612 4759 3515 +3 3861 4463 3961 +3 3961 4355 4047 +3 4047 4270 3962 +3 3962 4356 3862 +3 3739 3862 4464 +3 3606 3739 4608 +3 3515 4858 3605 +3 4759 4858 3515 +3 4615 4759 3612 +3 4615 3612 3745 +3 4615 3745 4471 +3 3745 3868 4471 +3 3868 3968 4471 +3 3968 4363 4471 +3 4276 4363 3968 +3 4371 4276 4051 +3 4479 4371 3975 +3 3752 4479 3875 +3 4479 3975 3875 +3 4623 4479 3752 +3 4767 4623 3619 +3 4868 4767 3523 +3 4868 3523 4775 +3 3523 3626 4775 +3 3626 3759 4775 +3 3759 4631 4775 +3 4487 4631 3759 +3 3982 4487 3882 +3 4487 3759 3882 +3 4379 4487 3982 +3 4284 4379 4059 +3 4380 4284 3983 +3 4488 4380 3883 +3 4488 3883 4632 +3 3627 4632 3760 +3 4632 3883 3760 +3 4776 4632 3627 +3 4776 3627 4869 +3 3620 4869 3524 +3 4869 3627 3524 +3 4768 4869 3620 +3 4624 4768 3753 +3 4624 3753 3876 +3 4624 3876 4480 +3 3876 3976 4480 +3 3976 4372 4480 +3 4277 4372 3976 +3 4277 3976 4052 +3 4277 4052 3969 +3 4277 3969 4364 +3 3969 3869 4364 +3 3869 4472 4364 +3 4616 4472 3869 +3 4760 4616 3746 +3 4760 3746 3613 +3 4760 3613 4859 +3 3613 3516 4859 +3 3516 3606 4859 +3 3606 4752 4859 +3 4608 4752 3606 +3 4464 4608 3739 +3 4356 4464 3862 +3 4270 4356 3962 +3 4355 4270 4047 +3 4463 4355 3961 +3 4607 4463 3861 +3 4607 3861 3738 +3 4607 3738 4751 +3 3738 3605 4751 +3 3605 4858 4751 +3 5619 6855 5722 +3 5722 6758 5866 +3 5866 6618 6010 +3 6010 6474 6114 +3 6114 6362 6203 +3 6018 6626 5874 +3 5874 6766 5730 +3 6130 6282 6210 +3 6489 5881 6025 +3 5881 6633 5737 +3 5729 6625 5873 +3 5873 6481 6017 +3 6017 6369 6121 +3 5865 6009 6473 +3 5865 6617 5721 +3 5857 6465 6001 +3 6001 6353 6105 +3 6002 6466 5858 +3 5858 6610 5714 +3 5714 6750 5619 +3 5721 6757 5618 +3 6757 6854 5618 +3 6617 6757 5721 +3 6473 6617 5865 +3 6361 6473 6009 +3 6361 6009 6113 +3 6361 6113 6274 +3 6121 6274 6202 +3 6274 6113 6202 +3 6369 6274 6121 +3 6481 6369 6017 +3 6625 6481 5873 +3 6765 6625 5729 +3 6765 5729 5628 +3 6765 5628 6864 +3 5628 5737 6864 +3 5737 6773 6864 +3 6633 6773 5737 +3 6489 6633 5881 +3 6377 6489 6025 +3 6210 6377 6129 +3 6377 6025 6129 +3 6282 6377 6210 +3 6378 6282 6130 +3 6378 6130 6490 +3 5882 6490 6026 +3 6490 6130 6026 +3 6634 6490 5882 +3 6634 5882 5738 +3 6634 5738 6774 +3 5738 6865 6774 +3 5730 6865 5629 +3 6865 5738 5629 +3 6766 6865 5730 +3 6626 6766 5874 +3 6482 6626 6018 +3 6482 6018 6122 +3 6482 6122 6370 +3 6122 6203 6370 +3 6203 6275 6370 +3 6362 6275 6203 +3 6474 6362 6114 +3 6618 6474 6010 +3 6758 6618 5866 +3 6855 6758 5722 +3 6750 6855 5619 +3 6610 6750 5714 +3 6466 6610 5858 +3 6354 6466 6002 +3 6354 6002 6106 +3 6354 6106 6268 +3 6105 6268 6196 +3 6268 6106 6196 +3 6353 6268 6105 +3 6465 6353 6001 +3 6609 6465 5857 +3 6609 5857 5713 +3 6609 5713 6749 +3 5713 5618 6749 +3 5618 6854 6749 +3 6409 6465 6553 +3 6553 6609 6805 +3 6990 7023 7051 +3 7051 7121 7091 +3 7173 7201 7091 +3 7250 7294 7201 +3 7323 7407 7294 +3 7591 7640 7683 +3 7683 7739 7795 +3 7939 7795 7883 +3 7939 8027 8083 +3 8083 8135 8220 +3 7940 7884 7796 +3 7796 7740 7684 +3 7592 7684 7641 +3 7592 7564 7500 +3 7500 7472 7408 +3 7202 7174 7092 +3 7092 7122 7052 +3 7122 7024 7052 +3 7174 7122 7092 +3 7251 7174 7202 +3 7251 7202 7295 +3 7251 7295 7324 +3 7295 7408 7324 +3 7408 7380 7324 +3 7472 7380 7408 +3 7564 7472 7500 +3 7641 7564 7592 +3 7740 7641 7684 +3 7884 7740 7796 +3 8028 7884 7940 +3 8028 7940 8084 +3 8028 8084 8136 +3 8084 8220 8136 +3 8220 8222 8136 +3 8135 8222 8220 +3 8027 8135 8083 +3 7883 8027 7939 +3 7739 7883 7795 +3 7640 7739 7683 +3 7563 7640 7591 +3 7563 7591 7499 +3 7563 7499 7471 +3 7499 7407 7471 +3 7407 7379 7471 +3 7323 7379 7407 +3 7250 7323 7294 +3 7173 7250 7201 +3 7121 7173 7091 +3 7023 7121 7051 +3 6929 7023 6990 +3 6929 6990 6897 +3 6929 6897 6854 +3 6897 6805 6854 +3 6805 6749 6854 +3 6609 6749 6805 +3 6465 6609 6553 +3 6353 6465 6409 +3 6353 6409 6268 +3 6409 6410 6268 +3 6410 6354 6268 +3 6466 6354 6410 +3 6466 6410 6554 +3 6466 6554 6610 +3 6554 6806 6610 +3 6806 6750 6610 +3 6855 6750 6806 +3 6855 6806 6898 +3 6855 6898 6930 +3 6898 6991 6930 +3 6991 7024 6930 +3 7052 7024 6991 +3 5234 5166 5066 +3 4268 4355 4535 +3 5233 5309 5405 +3 5929 6001 6105 +3 5857 6001 5929 +3 5857 5929 5785 +3 5857 5785 5713 +3 5785 5613 5713 +3 5613 5618 5713 +3 5545 5618 5613 +3 5545 5613 5497 +3 5545 5497 5453 +3 5497 5405 5453 +3 5405 5361 5453 +3 5309 5361 5405 +3 5238 5309 5233 +3 5238 5233 5165 +3 5233 5065 5165 +3 5065 5109 5165 +3 5021 5109 5065 +3 5021 5065 4973 +3 5021 4973 4929 +3 4973 4853 4929 +3 4853 4858 4929 +3 4751 4858 4853 +3 4751 4853 4683 +3 4751 4683 4607 +3 4683 4535 4607 +3 4535 4463 4607 +3 4355 4463 4535 +3 4270 4355 4268 +3 4270 4268 4356 +3 4268 4536 4356 +3 4536 4464 4356 +3 4608 4464 4536 +3 4608 4536 4684 +3 4608 4684 4752 +3 4684 4854 4752 +3 4854 4859 4752 +3 4930 4859 4854 +3 4930 4854 4974 +3 4930 4974 5022 +3 4974 5066 5022 +3 5066 5110 5022 +3 5166 5110 5066 +3 5239 5166 5234 +3 5239 5234 5310 +3 5234 5406 5310 +3 5406 5362 5310 +3 5454 5362 5406 +3 5454 5406 5498 +3 5454 5498 5546 +3 5498 5614 5546 +3 5614 5619 5546 +3 5714 5619 5614 +3 5714 5614 5786 +3 5714 5786 5858 +3 5786 5930 5858 +3 5930 6002 5858 +3 6106 6002 5930 +3 6106 5930 6194 +3 6106 6194 6196 +3 6194 6105 6196 +3 5929 6105 6194 +3 3370 3352 3295 +3 3295 3327 3249 +3 3249 3232 3190 +3 3190 3158 3127 +3 3127 3062 3080 +3 3080 3036 3005 +3 3005 2987 2933 +3 2933 2915 2854 +3 2854 2847 2760 +3 2656 2760 2755 +3 2656 2651 2551 +3 2551 2546 2468 +3 2468 2463 2402 +3 2402 2399 2469 +3 2469 2464 2552 +3 3739 3794 3862 +3 3862 3918 3962 +3 3861 3793 3738 +3 3738 3687 3605 +3 3605 3561 3515 +3 3233 3191 3159 +3 3159 3128 3063 +3 3063 3081 3037 +3 3037 3006 2988 +3 2934 2916 2988 +3 2855 2848 2916 +3 2848 2761 2756 +3 2552 2547 2657 +3 2464 2547 2552 +3 2399 2464 2469 +3 2463 2399 2402 +3 2546 2463 2468 +3 2651 2546 2551 +3 2755 2651 2656 +3 2847 2755 2760 +3 2915 2847 2854 +3 2987 2915 2933 +3 3036 2987 3005 +3 3062 3036 3080 +3 3158 3062 3127 +3 3232 3158 3190 +3 3327 3232 3249 +3 3352 3327 3295 +3 3403 3352 3370 +3 3403 3370 3442 +3 3403 3442 3474 +3 3442 3515 3474 +3 3515 3551 3474 +3 3561 3551 3515 +3 3687 3561 3605 +3 3793 3687 3738 +3 3917 3793 3861 +3 3917 3861 3961 +3 3917 3961 4045 +3 3962 4045 4047 +3 4045 3961 4047 +3 3918 4045 3962 +3 3794 3918 3862 +3 3688 3794 3739 +3 3688 3739 3606 +3 3688 3606 3562 +3 3606 3516 3562 +3 3516 3552 3562 +3 3475 3516 3443 +3 3552 3516 3475 +3 3404 3443 3371 +3 3475 3443 3404 +3 2756 2657 2652 +3 2657 2547 2652 +3 2761 2657 2756 +3 2855 2761 2848 +3 2934 2855 2916 +3 3006 2934 2988 +3 3081 3006 3037 +3 3128 3081 3063 +3 3191 3128 3159 +3 3250 3191 3233 +3 3250 3233 3328 +3 3250 3328 3296 +3 3328 3353 3296 +3 3353 3371 3296 +3 3404 3371 3353 +3 1664 1574 1580 +3 1580 1490 1496 +3 1496 1408 1414 +3 1100 1026 1106 +3 1026 1020 949 +3 468 462 384 +3 384 381 469 +3 565 469 463 +3 565 559 698 +3 2030 1891 1897 +3 1758 1764 1897 +3 1655 1664 1764 +3 1409 1491 1415 +3 1409 1363 1357 +3 1357 1295 1287 +3 1287 1233 1227 +3 1185 1179 1227 +3 1179 1107 1101 +3 1027 1021 1101 +3 1021 950 941 +3 698 692 834 +3 559 692 698 +3 463 559 565 +3 381 463 469 +3 462 381 384 +3 558 462 468 +3 697 558 564 +3 558 468 564 +3 691 558 697 +3 691 697 833 +3 691 833 827 +3 833 949 827 +3 949 940 827 +3 1020 940 949 +3 1100 1020 1026 +3 1178 1100 1106 +3 1178 1106 1184 +3 1178 1184 1226 +3 1294 1226 1232 +3 1226 1184 1232 +3 1286 1226 1294 +3 1286 1294 1356 +3 1414 1356 1362 +3 1356 1294 1362 +3 1408 1356 1414 +3 1490 1408 1496 +3 1574 1490 1580 +3 1655 1574 1664 +3 1758 1655 1764 +3 1891 1758 1897 +3 2024 1891 2030 +3 2024 2030 2126 +3 2024 2126 2120 +3 2215 2126 2218 +3 2120 2126 2215 +3 2031 2121 2127 +3 2121 2218 2127 +3 2215 2218 2121 +3 2025 2031 1898 +3 2121 2031 2025 +3 1892 1898 1765 +3 2025 1898 1892 +3 1759 1765 1665 +3 1892 1765 1759 +3 941 834 828 +3 834 692 828 +3 950 834 941 +3 1027 950 1021 +3 1107 1027 1101 +3 1185 1107 1179 +3 1233 1185 1227 +3 1295 1233 1287 +3 1363 1295 1357 +3 1415 1363 1409 +3 1497 1415 1491 +3 1497 1491 1575 +3 1497 1575 1581 +3 1575 1656 1581 +3 1656 1665 1581 +3 1759 1665 1656 +3 7157 7104 7105 +3 7105 7006 7007 +3 7007 6912 6913 +3 6913 6831 6832 +3 6569 6425 6568 +3 6708 6709 6569 +3 6999 6998 7097 +3 7097 7096 7149 +3 7149 7148 7218 +3 8200 8106 8107 +3 8107 7998 7999 +3 7999 7854 7855 +3 7710 7711 7855 +3 7711 7617 7618 +3 7538 7447 7446 +3 7355 7299 7298 +3 7299 7218 7298 +3 7218 7217 7298 +3 7148 7217 7218 +3 7096 7148 7149 +3 6998 7096 7097 +3 6904 6998 6999 +3 6904 6999 6905 +3 6904 6905 6821 +3 6709 6821 6822 +3 6821 6905 6822 +3 6708 6821 6709 +3 6568 6708 6569 +3 6424 6568 6425 +3 6424 6425 6312 +3 6244 6312 6313 +3 6312 6425 6313 +3 6243 6312 6244 +3 6243 6244 6321 +3 6243 6321 6320 +3 6321 6433 6320 +3 6433 6432 6320 +3 6576 6432 6433 +3 6576 6433 6577 +3 6576 6577 6716 +3 6832 6716 6717 +3 6716 6577 6717 +3 6831 6716 6832 +3 6912 6831 6913 +3 7006 6912 7007 +3 7104 7006 7105 +3 7156 7104 7157 +3 7156 7157 7228 +3 7156 7228 7227 +3 7228 7307 7227 +3 7307 7306 7227 +3 7362 7306 7307 +3 7362 7307 7363 +3 7362 7363 7454 +3 7363 7455 7454 +3 7455 7546 7454 +3 7618 7546 7547 +3 7546 7455 7547 +3 7617 7546 7618 +3 7710 7617 7711 +3 7854 7710 7855 +3 7998 7854 7999 +3 8106 7998 8107 +3 8199 8106 8200 +3 8199 8200 8098 +3 7991 8098 8099 +3 8098 8200 8099 +3 7990 8098 7991 +3 7846 7991 7847 +3 7990 7991 7846 +3 7702 7847 7703 +3 7846 7847 7702 +3 7446 7355 7354 +3 7355 7298 7354 +3 7447 7355 7446 +3 7539 7447 7538 +3 7539 7538 7607 +3 7539 7607 7608 +3 7607 7703 7608 +3 7702 7703 7607 +3 4833 4809 4728 +3 4728 4664 4584 +3 4584 4556 4440 +3 4440 4412 4332 +3 4439 4555 4583 +3 4583 4663 4727 +3 5690 5662 5593 +3 4727 4808 4832 +3 4663 4808 4727 +3 4555 4663 4583 +3 4411 4555 4439 +3 4411 4439 4331 +3 4411 4331 4256 +3 4332 4256 4252 +3 4256 4331 4252 +3 4412 4256 4332 +3 4556 4412 4440 +3 4664 4556 4584 +3 4809 4664 4728 +3 4902 4833 4914 +3 4809 4833 4902 +3 4994 4914 5006 +3 4902 4914 4994 +3 5150 5138 5094 +3 5138 5006 5094 +3 4994 5006 5138 +3 5282 5150 5213 +3 5138 5150 5282 +3 5346 5282 5294 +3 5282 5213 5294 +3 5426 5282 5346 +3 5426 5346 5438 +3 5426 5438 5518 +3 5593 5518 5530 +3 5518 5438 5530 +3 5662 5518 5593 +3 5806 5662 5690 +3 5806 5690 5834 +3 5806 5834 5950 +3 6082 5950 5978 +3 5950 5834 5978 +3 6182 5950 6082 +3 6182 6082 6178 +3 6182 6178 6081 +3 6182 6081 5949 +3 5833 5949 5977 +3 5949 6081 5977 +3 5805 5949 5833 +3 5805 5833 5689 +3 5805 5689 5661 +3 5689 5592 5661 +3 5592 5517 5661 +3 5437 5517 5529 +3 5517 5592 5529 +3 5425 5517 5437 +3 5425 5437 5345 +3 5425 5345 5281 +3 5345 5293 5281 +3 5293 5212 5281 +3 5212 5149 5281 +3 5149 5137 5281 +3 5005 5137 5093 +3 5137 5149 5093 +3 4993 5137 5005 +3 4993 5005 4913 +3 4993 4913 4901 +3 4913 4832 4901 +3 4832 4808 4901 +3 5592 5591 5529 +3 5529 5528 5437 +3 5211 5212 5293 +3 5212 5148 5149 +3 5149 5092 5093 +3 5005 5093 5004 +3 4913 5005 4912 +3 4832 4913 4831 +3 4832 4718 4719 +3 4574 4575 4719 +3 4431 4575 4430 +3 4431 4322 4323 +3 4243 4244 4323 +3 4567 4566 4711 +3 4711 4710 4822 +3 4822 4821 4905 +3 4905 4904 4997 +3 4997 4996 5085 +3 5085 5084 5141 +3 5141 5140 5202 +3 5202 5201 5285 +3 6170 6169 6073 +3 5680 5592 5681 +3 5285 5284 5337 +3 5201 5284 5285 +3 5140 5201 5202 +3 5084 5140 5141 +3 4996 5084 5085 +3 4904 4996 4997 +3 4821 4904 4905 +3 4710 4821 4822 +3 4566 4710 4711 +3 4422 4566 4567 +3 4422 4567 4423 +3 4422 4423 4314 +3 4244 4314 4315 +3 4314 4423 4315 +3 4243 4314 4244 +3 4322 4243 4323 +3 4430 4322 4431 +3 4574 4430 4575 +3 4718 4574 4719 +3 4831 4718 4832 +3 4912 4831 4913 +3 5004 4912 5005 +3 5092 5004 5093 +3 5148 5092 5149 +3 5211 5148 5212 +3 5292 5211 5293 +3 5292 5293 5345 +3 5292 5345 5344 +3 5345 5437 5344 +3 5437 5436 5344 +3 5528 5436 5437 +3 5591 5528 5529 +3 5680 5591 5592 +3 5824 5680 5681 +3 5824 5681 5825 +3 5824 5825 5968 +3 5825 5969 5968 +3 5969 6073 5968 +3 6073 6072 5968 +3 6169 6072 6073 +3 5961 6064 6065 +3 6064 6170 6065 +3 6169 6170 6064 +3 5960 5961 5817 +3 6064 5961 5960 +3 5816 5817 5673 +3 5960 5817 5816 +3 5672 5673 5582 +3 5816 5673 5672 +3 5428 5337 5336 +3 5337 5284 5336 +3 5429 5337 5428 +3 5429 5428 5520 +3 5429 5520 5521 +3 5520 5581 5521 +3 5581 5582 5521 +3 5672 5582 5581 +3 4423 4567 3704 +3 4085 4332 4252 +3 4332 4082 4440 +3 4440 3798 4584 +3 3835 4432 4576 +3 4424 3828 4568 +3 4712 4568 3705 +3 4712 3572 4823 +3 4823 3490 4704 +3 4704 3565 4560 +3 4238 4022 4307 +3 4307 3920 4415 +3 3558 4832 3497 +3 4719 3578 3497 +3 4575 3711 3578 +3 4323 3934 4431 +3 4026 3934 4323 +3 4026 4323 4244 +3 4026 4244 3927 +3 4244 4315 3927 +3 4315 4423 3927 +3 4423 3827 3927 +3 3704 3827 4423 +3 3571 3704 4567 +3 3571 4567 4711 +3 3571 4711 3489 +3 4703 3489 4822 +3 3489 4711 4822 +3 3564 3489 4703 +3 3564 4703 4559 +3 3564 4559 3697 +3 4559 4415 3697 +3 4415 3820 3697 +3 3920 3820 4415 +3 4022 3920 4307 +3 3921 4022 4238 +3 3921 4238 4308 +3 3921 4308 3821 +3 4308 4416 3821 +3 4416 4560 3821 +3 4560 3698 3821 +3 3565 3698 4560 +3 3490 3565 4704 +3 3572 3490 4823 +3 3705 3572 4712 +3 3828 3705 4568 +3 3928 3828 4424 +3 4245 3928 4316 +3 3928 4424 4316 +3 4027 3928 4245 +3 4027 4245 3935 +3 4432 3935 4324 +3 3935 4245 4324 +3 3835 3935 4432 +3 3712 3835 4576 +3 3712 4576 4720 +3 3712 4720 3579 +3 4720 4833 3579 +3 4833 3498 3579 +3 3559 3498 4833 +3 3559 4833 4728 +3 3559 4728 3665 +3 4728 4584 3665 +3 4584 3695 3665 +3 3798 3695 4584 +3 4082 3798 4440 +3 4085 4082 4332 +3 4087 4085 4252 +3 4084 4252 4331 +3 4087 4252 4084 +3 4081 4331 4439 +3 4084 4331 4081 +3 3711 4431 3834 +3 4431 3934 3834 +3 4575 4431 3711 +3 4719 4575 3578 +3 4832 4719 3497 +3 4727 4832 3558 +3 4727 3558 3664 +3 4727 3664 4583 +3 3664 3694 4583 +3 3694 3797 4583 +3 3797 4439 4583 +3 4081 4439 3797 +3 5818 6570 5962 +3 5962 6426 6066 +3 6066 6314 6171 +3 6074 6171 6245 +3 5826 6718 5682 +3 5834 6586 5978 +3 5978 6442 6082 +3 6082 6330 6178 +3 6178 6252 6081 +3 6058 6418 5954 +3 5954 6562 5810 +3 5810 6702 5666 +3 6569 5817 6425 +3 5961 6313 6425 +3 6313 6065 6244 +3 6321 6244 6170 +3 6073 6433 6321 +3 6577 6433 5969 +3 6577 5825 6717 +3 6717 5681 6832 +3 6081 6329 5977 +3 6252 6329 6081 +3 6330 6252 6178 +3 6442 6330 6082 +3 6586 6442 5978 +3 6726 6586 5834 +3 6726 5834 5690 +3 6726 5690 6833 +3 5682 6833 5593 +3 6833 5690 5593 +3 6718 6833 5682 +3 6578 6718 5826 +3 6578 5826 5970 +3 6578 5970 6434 +3 5970 6074 6434 +3 6074 6322 6434 +3 6245 6322 6074 +3 6314 6245 6171 +3 6426 6314 6066 +3 6570 6426 5962 +3 6710 6570 5818 +3 6710 5818 5674 +3 6710 5674 6823 +3 5666 6823 5583 +3 6823 5674 5583 +3 6702 6823 5666 +3 6562 6702 5810 +3 6418 6562 5954 +3 6306 6418 6058 +3 6306 6058 6164 +3 6306 6164 6238 +3 6305 6164 6057 +3 6238 6164 6305 +3 6417 6057 5953 +3 6305 6057 6417 +3 6561 5953 5809 +3 6417 5953 6561 +3 6701 5809 5665 +3 6561 5809 6701 +3 6585 5977 6441 +3 5977 6329 6441 +3 5833 5977 6585 +3 5833 6585 6725 +3 5833 6725 5689 +3 6725 6832 5689 +3 6832 5592 5689 +3 5681 5592 6832 +3 5825 5681 6717 +3 5969 5825 6577 +3 6073 5969 6433 +3 6170 6073 6321 +3 6065 6170 6244 +3 5961 6065 6313 +3 5817 5961 6425 +3 5673 5817 6569 +3 5673 6569 6709 +3 5673 6709 5582 +3 6709 6822 5582 +3 6822 5665 5582 +3 6701 5665 6822 +3 6403 6298 6301 +3 6298 6404 6301 +3 6404 6548 6301 +3 6660 6548 6516 +3 6548 6404 6516 +3 6692 6548 6660 +3 6692 6660 6800 +3 6692 6800 6892 +3 6952 6892 6885 +3 6892 6800 6885 +3 6984 6892 6952 +3 6984 6952 7046 +3 6984 7046 7082 +3 7196 7082 7144 +3 7082 7046 7144 +3 7288 7082 7196 +3 7288 7196 7281 +3 7288 7281 7346 +3 7288 7346 7438 +3 7494 7438 7402 +3 7438 7346 7402 +3 7534 7438 7494 +3 7534 7494 7586 +3 7534 7586 7678 +3 7790 7678 7671 +3 7678 7586 7671 +3 7826 7678 7790 +3 7826 7790 7934 +3 7826 7934 7978 +3 8186 7978 8078 +3 7978 7934 8078 +3 8255 7978 8186 +3 8255 8186 8252 +3 8255 8252 8185 +3 8255 8185 7977 +3 7933 7977 8077 +3 7977 8185 8077 +3 7825 7977 7933 +3 7825 7933 7789 +3 7825 7789 7677 +3 7585 7677 7670 +3 7677 7789 7670 +3 7533 7677 7585 +3 7533 7585 7493 +3 7533 7493 7437 +3 7345 7437 7401 +3 7437 7493 7401 +3 7287 7437 7345 +3 7287 7345 7280 +3 7287 7280 7195 +3 7287 7195 7081 +3 7045 7081 7143 +3 7081 7195 7143 +3 6983 7081 7045 +3 6983 7045 6951 +3 6983 6951 6891 +3 6799 6891 6884 +3 6891 6951 6884 +3 6691 6891 6799 +3 6691 6799 6659 +3 6691 6659 6547 +3 6659 6515 6547 +3 6515 6403 6547 +3 6403 6301 6547 +3 7670 7584 7585 +3 7585 7492 7493 +3 6951 7045 7044 +3 6951 6950 6884 +3 6884 6883 6793 +3 6653 6793 6792 +3 6653 6652 6509 +3 8179 8178 8071 +3 7783 7669 7670 +3 7487 7394 7486 +3 7136 7188 7189 +3 6875 6944 6876 +3 6875 6787 6786 +3 6786 6647 6646 +3 6391 6390 6503 +3 6291 6390 6391 +3 6291 6391 6292 +3 6291 6292 6397 +3 6291 6397 6396 +3 6397 6509 6396 +3 6509 6508 6396 +3 6652 6508 6509 +3 6792 6652 6653 +3 6883 6792 6793 +3 6950 6883 6884 +3 7044 6950 6951 +3 7142 7044 7045 +3 7142 7045 7143 +3 7142 7143 7195 +3 7142 7195 7194 +3 7195 7280 7194 +3 7280 7279 7194 +3 7344 7279 7280 +3 7344 7280 7345 +3 7344 7345 7400 +3 7493 7400 7401 +3 7400 7345 7401 +3 7492 7400 7493 +3 7584 7492 7585 +3 7669 7584 7670 +3 7782 7669 7783 +3 7782 7783 7927 +3 7782 7927 7926 +3 7927 8071 7926 +3 8071 8070 7926 +3 8178 8070 8071 +3 8245 8178 8179 +3 8173 8245 8246 +3 8245 8179 8246 +3 8172 8245 8173 +3 8172 8173 8065 +3 8172 8065 8064 +3 7920 8065 7921 +3 8064 8065 7920 +3 7776 7921 7777 +3 7920 7921 7776 +3 6646 6503 6502 +3 6503 6390 6502 +3 6647 6503 6646 +3 6787 6647 6786 +3 6876 6787 6875 +3 6945 6876 6944 +3 6945 6944 7038 +3 6945 7038 7039 +3 7038 7136 7039 +3 7136 7137 7039 +3 7189 7137 7136 +3 7272 7189 7188 +3 7272 7188 7271 +3 7272 7271 7338 +3 7272 7338 7339 +3 7338 7394 7339 +3 7394 7395 7339 +3 7487 7395 7394 +3 7579 7487 7486 +3 7579 7486 7578 +3 7579 7578 7662 +3 7578 7661 7662 +3 7661 7777 7662 +3 7776 7777 7661 +3 5276 5332 5420 +3 6229 6155 5943 +3 5275 5187 5079 +3 4549 4513 4405 +3 4657 4513 4549 +3 4657 4549 4697 +3 4657 4697 4801 +3 4697 4895 4801 +3 4895 4888 4801 +3 4951 4888 4895 +3 4951 4895 4987 +3 4951 4987 5043 +3 4987 5079 5043 +3 5079 5131 5043 +3 5187 5131 5079 +3 5268 5187 5275 +3 5268 5275 5331 +3 5275 5419 5331 +3 5419 5383 5331 +3 5475 5383 5419 +3 5475 5419 5511 +3 5475 5511 5567 +3 5511 5655 5567 +3 5655 5648 5567 +3 5763 5648 5655 +3 5763 5655 5799 +3 5763 5799 5907 +3 5799 5943 5907 +3 5943 6051 5907 +3 6155 6051 5943 +3 6226 6155 6229 +3 6226 6229 6156 +3 6229 5944 6156 +3 5944 6052 6156 +3 5908 6052 5944 +3 5908 5944 5800 +3 5908 5800 5764 +3 5800 5656 5764 +3 5656 5649 5764 +3 5568 5649 5656 +3 5568 5656 5512 +3 5568 5512 5476 +3 5512 5420 5476 +3 5420 5384 5476 +3 5332 5384 5420 +3 5269 5332 5276 +3 5269 5276 5188 +3 5276 5080 5188 +3 5080 5132 5188 +3 5044 5132 5080 +3 5044 5080 4988 +3 5044 4988 4952 +3 4988 4896 4952 +3 4896 4889 4952 +3 4802 4889 4896 +3 4802 4896 4698 +3 4802 4698 4658 +3 4698 4550 4658 +3 4550 4514 4658 +3 4406 4514 4550 +3 4406 4550 4303 +3 4406 4303 4300 +3 4303 4405 4300 +3 4549 4405 4303 +3 5648 5566 5567 +3 5567 5474 5475 +3 5475 5382 5383 +3 5043 5042 4951 +3 4888 4951 4950 +3 4887 4795 4888 +3 4795 4794 4651 +3 4651 4650 4507 +3 5750 5895 5751 +3 6039 5895 5894 +3 6149 6148 6045 +3 5757 5647 5648 +3 5468 5469 5376 +3 5180 5181 5124 +3 4944 4880 4879 +3 4879 4789 4788 +3 4788 4645 4644 +3 4393 4392 4501 +3 4293 4392 4393 +3 4293 4393 4294 +3 4293 4294 4399 +3 4293 4399 4398 +3 4399 4507 4398 +3 4507 4506 4398 +3 4650 4506 4507 +3 4794 4650 4651 +3 4887 4794 4795 +3 4950 4887 4888 +3 5042 4950 4951 +3 5130 5042 5043 +3 5130 5043 5131 +3 5130 5131 5187 +3 5130 5187 5186 +3 5187 5268 5186 +3 5268 5267 5186 +3 5330 5267 5268 +3 5383 5330 5331 +3 5330 5268 5331 +3 5382 5330 5383 +3 5474 5382 5475 +3 5566 5474 5567 +3 5647 5566 5648 +3 5756 5647 5757 +3 5756 5757 5901 +3 5756 5901 5900 +3 5901 6045 5900 +3 6045 6044 5900 +3 6148 6044 6045 +3 6219 6148 6149 +3 6219 6149 6220 +3 6219 6220 6143 +3 6219 6143 6142 +3 6143 6039 6142 +3 6039 6038 6142 +3 5894 6038 6039 +3 5750 5894 5895 +3 4644 4501 4500 +3 4501 4392 4500 +3 4645 4501 4644 +3 4789 4645 4788 +3 4880 4789 4879 +3 4945 4880 4944 +3 4945 4944 5036 +3 4945 5036 5037 +3 5036 5124 5037 +3 5124 5125 5037 +3 5181 5125 5124 +3 5260 5181 5180 +3 5260 5180 5259 +3 5260 5259 5324 +3 5260 5324 5325 +3 5324 5376 5325 +3 5376 5377 5325 +3 5469 5377 5376 +3 5561 5469 5468 +3 5561 5468 5560 +3 5561 5560 5640 +3 5560 5639 5640 +3 5639 5751 5640 +3 5750 5751 5639 +3 2432 2511 2429 +3 2432 2429 2512 +3 2432 2512 2614 +3 2698 2614 2594 +3 2614 2512 2594 +3 2731 2614 2698 +3 2731 2698 2802 +3 2731 2802 2884 +3 2955 2884 2879 +3 2884 2802 2879 +3 2982 2884 2955 +3 2982 2955 3027 +3 2982 3027 3059 +3 3149 3059 3102 +3 3059 3027 3102 +3 3220 3059 3149 +3 3220 3149 3215 +3 3220 3215 3271 +3 3220 3271 3348 +3 3392 3348 3317 +3 3348 3271 3317 +3 3424 3348 3392 +3 3424 3392 3464 +3 3424 3464 3548 +3 3656 3548 3542 +3 3548 3464 3542 +3 3684 3548 3656 +3 3684 3656 3789 +3 3684 3789 3817 +3 4012 3817 3912 +3 3817 3789 3912 +3 4079 3817 4012 +3 4079 4012 4076 +3 4079 4076 4011 +3 4079 4011 3816 +3 3788 3816 3911 +3 3816 4011 3911 +3 3683 3816 3788 +3 3683 3788 3655 +3 3683 3655 3547 +3 3463 3547 3541 +3 3547 3655 3541 +3 3423 3547 3463 +3 3423 3463 3391 +3 3423 3391 3347 +3 3270 3347 3316 +3 3347 3391 3316 +3 3219 3347 3270 +3 3219 3270 3214 +3 3219 3214 3148 +3 3219 3148 3058 +3 3026 3058 3101 +3 3058 3148 3101 +3 2981 3058 3026 +3 2981 3026 2954 +3 2981 2954 2883 +3 2801 2883 2878 +3 2883 2954 2878 +3 2730 2883 2801 +3 2730 2801 2697 +3 2730 2697 2613 +3 2697 2593 2613 +3 2593 2511 2613 +3 2511 2432 2613 +3 3774 3898 3775 +3 3383 3384 3308 +3 3262 3308 3309 +3 3205 3262 3263 +3 3205 3206 3140 +3 3140 3141 3093 +3 3093 3094 3018 +3 3018 3019 2946 +3 2946 2947 2869 +3 2497 2580 2581 +3 2497 2498 2420 +3 2420 2421 2505 +3 2505 2506 2587 +3 2587 2588 2691 +3 2692 2795 2691 +3 2795 2796 2877 +3 2877 2878 2953 +3 2953 2954 3025 +3 3147 3214 3213 +3 3213 3270 3269 +3 3269 3316 3315 +3 3390 3315 3391 +3 3462 3390 3463 +3 3462 3541 3540 +3 3540 3649 3648 +3 3648 3782 3781 +3 4004 3905 4005 +3 4004 4005 4068 +3 3998 4068 4069 +3 4068 4005 4069 +3 3997 4068 3998 +3 3997 3998 3898 +3 3997 3898 3897 +3 3898 3774 3897 +3 3641 3775 3642 +3 3774 3775 3641 +3 3781 3905 3904 +3 3905 4004 3904 +3 3782 3905 3781 +3 3649 3782 3648 +3 3541 3649 3540 +3 3463 3541 3462 +3 3391 3463 3390 +3 3316 3391 3315 +3 3270 3316 3269 +3 3214 3270 3213 +3 3148 3214 3147 +3 3148 3147 3100 +3 3148 3100 3101 +3 3100 3025 3101 +3 3025 3026 3101 +3 2954 3026 3025 +3 2878 2954 2953 +3 2796 2878 2877 +3 2692 2796 2795 +3 2588 2692 2691 +3 2506 2588 2587 +3 2421 2506 2505 +3 2498 2421 2420 +3 2581 2498 2497 +3 2685 2581 2580 +3 2685 2580 2684 +3 2685 2684 2788 +3 2685 2788 2789 +3 2788 2869 2789 +3 2869 2870 2789 +3 2947 2870 2869 +3 3019 2947 2946 +3 3094 3019 3018 +3 3141 3094 3093 +3 3206 3141 3140 +3 3263 3206 3205 +3 3309 3263 3262 +3 3384 3309 3308 +3 3456 3384 3383 +3 3456 3383 3455 +3 3456 3455 3533 +3 3455 3532 3533 +3 3532 3642 3533 +3 3641 3642 3532 +3 2084 2083 2188 +3 2084 2188 2186 +3 2080 2186 2185 +3 2186 2188 2185 +3 1952 2186 2080 +3 1859 1952 1951 +3 1952 2080 1951 +3 1816 1952 1859 +3 1816 1859 1815 +3 1816 1815 1702 +3 1559 1702 1694 +3 1702 1815 1694 +3 1560 1702 1559 +3 1560 1559 1522 +3 1560 1522 1472 +3 1394 1472 1471 +3 1472 1522 1471 +3 1340 1472 1394 +3 1340 1394 1339 +3 1340 1339 1257 +3 1340 1257 1209 +3 1257 1208 1209 +3 8554 8167 8558 +3 8588 8179 8594 +3 8623 8186 8619 +3 7663 8571 7778 +3 7778 8577 7922 +3 8589 8174 8583 +3 8247 8174 8589 +3 8247 8589 8180 +3 8589 8595 8180 +3 8595 8072 8180 +3 7928 8072 8595 +3 7928 8595 8601 +3 7928 8601 7784 +3 8601 8607 7784 +3 8607 7671 7784 +3 7790 7671 8607 +3 7790 8607 8613 +3 7790 8613 7934 +3 8613 8619 7934 +3 8619 8078 7934 +3 8186 8078 8619 +3 8252 8186 8623 +3 8252 8623 8185 +3 8623 8618 8185 +3 8618 8077 8185 +3 7933 8077 8618 +3 7933 8618 8612 +3 7933 8612 7789 +3 8612 8606 7789 +3 8606 7670 7789 +3 7783 7670 8606 +3 7783 8606 8600 +3 7783 8600 7927 +3 8600 8594 7927 +3 8594 8071 7927 +3 8179 8071 8594 +3 8246 8179 8588 +3 8246 8588 8173 +3 8588 8582 8173 +3 8582 8065 8173 +3 7921 8065 8582 +3 7921 8582 8576 +3 7921 8576 7777 +3 8576 8570 7777 +3 8570 7662 7777 +3 7771 7662 8570 +3 7771 8570 8564 +3 7771 8564 7915 +3 8564 8558 7915 +3 8558 8059 7915 +3 8167 8059 8558 +3 8241 8167 8554 +3 8241 8554 8168 +3 8554 8559 8168 +3 8559 8060 8168 +3 7916 8559 8565 +3 8060 8559 7916 +3 7772 8565 8571 +3 7916 8565 7772 +3 7922 8583 8066 +3 8583 8174 8066 +3 8577 8583 7922 +3 8571 8577 7778 +3 7772 8571 7663 +3 3906 4652 3783 +3 3783 4796 3650 +3 3650 4889 3542 +3 3788 3911 4657 +3 3541 4795 3649 +3 3649 4651 3782 +3 4069 4005 4399 +3 3998 4069 4294 +3 3998 4393 3898 +3 3891 4495 3991 +3 3892 4496 3769 +3 3769 4640 3636 +3 3533 4880 3635 +3 4789 4880 3533 +3 4789 3533 3642 +3 4789 3642 4645 +3 3642 3775 4645 +3 3775 3898 4645 +3 3898 4501 4645 +3 4393 4501 3898 +3 4294 4393 3998 +3 4399 4294 4069 +3 4507 4399 4005 +3 3782 4507 3905 +3 4507 4005 3905 +3 4651 4507 3782 +3 4795 4651 3649 +3 4888 4795 3541 +3 4888 3541 4801 +3 3788 4801 3655 +3 4801 3541 3655 +3 4657 4801 3788 +3 4513 4657 3911 +3 4513 3911 4405 +3 4076 4405 4011 +3 4405 3911 4011 +3 4300 4405 4076 +3 4300 4076 4012 +3 4300 4012 4406 +3 4012 3912 4406 +3 3912 4514 4406 +3 4658 4514 3912 +3 4658 3912 3789 +3 4658 3789 4802 +3 3542 4802 3656 +3 4802 3789 3656 +3 4889 4802 3542 +3 4796 4889 3650 +3 4652 4796 3783 +3 4508 4652 3906 +3 4508 3906 4400 +3 3906 4006 4400 +3 4006 4070 4400 +3 4070 4295 4400 +3 4394 4295 4070 +3 4394 4070 3999 +3 4394 3999 4502 +3 3999 3899 4502 +3 3899 3776 4502 +3 3776 4646 4502 +3 4790 4646 3776 +3 4790 3776 3643 +3 4790 3643 4881 +3 3643 3534 4881 +3 3534 3636 4881 +3 3636 4784 4881 +3 4640 4784 3636 +3 4496 4640 3769 +3 4388 4496 3892 +3 4388 3892 3992 +3 4388 3992 4064 +3 4388 4064 4289 +3 4064 3991 4289 +3 3991 4387 4289 +3 4495 4387 3991 +3 4639 4495 3891 +3 4639 3891 3768 +3 4639 3768 4783 +3 3768 3635 4783 +3 3635 4880 4783 +3 5641 6877 5752 +3 5752 6788 5896 +3 5896 6648 6040 +3 6040 6504 6144 +3 6144 6392 6221 +3 6221 6293 6150 +3 6398 6046 6150 +3 6046 6510 5902 +3 5902 6654 5758 +3 5758 6794 5649 +3 5764 5649 6885 +3 6052 6404 6156 +3 6156 6298 6226 +3 6137 6033 6385 +3 6137 6385 6215 +3 6138 6215 6287 +3 6138 6386 6034 +3 6498 5890 6034 +3 5890 6642 5746 +3 6782 5641 5746 +3 6503 6039 6391 +3 6391 6143 6292 +3 6509 5901 6653 +3 6653 5757 6793 +3 6793 5648 6884 +3 5907 6659 5763 +3 6515 6659 5907 +3 6515 5907 6051 +3 6515 6051 6403 +3 6226 6403 6155 +3 6403 6051 6155 +3 6298 6403 6226 +3 6404 6298 6156 +3 6516 6404 6052 +3 6516 6052 6660 +3 6052 5908 6660 +3 5908 5764 6660 +3 5764 6800 6660 +3 6885 6800 5764 +3 6794 6885 5649 +3 6654 6794 5758 +3 6510 6654 5902 +3 6398 6510 6046 +3 6293 6398 6150 +3 6392 6293 6221 +3 6504 6392 6144 +3 6648 6504 6040 +3 6788 6648 5896 +3 6877 6788 5752 +3 6782 6877 5641 +3 6642 6782 5746 +3 6498 6642 5890 +3 6386 6498 6034 +3 6287 6386 6138 +3 6385 6287 6215 +3 6497 6033 5889 +3 6385 6033 6497 +3 6641 5889 5745 +3 6497 5889 6641 +3 6781 5745 5640 +3 6641 5745 6781 +3 6884 5763 6799 +3 5763 6659 6799 +3 5648 5763 6884 +3 5757 5648 6793 +3 5901 5757 6653 +3 6045 5901 6509 +3 6045 6509 6397 +3 6045 6397 6149 +3 6397 6292 6149 +3 6292 6220 6149 +3 6143 6220 6292 +3 6039 6143 6391 +3 5895 6039 6503 +3 5895 6503 6647 +3 5895 6647 5751 +3 6647 6787 5751 +3 6787 6876 5751 +3 6876 5640 5751 +3 6781 5640 6876 +3 7579 7481 7487 +3 7189 7183 7137 +3 7137 7131 7039 +3 7039 7033 6945 +3 6945 6939 6876 +3 6876 6866 6781 +3 6781 6775 6641 +3 6641 6635 6497 +3 6497 6491 6385 +3 6385 6379 6287 +3 6283 6386 6287 +3 6386 6380 6498 +3 6498 6492 6642 +3 6946 6940 7040 +3 7040 7034 7138 +3 7132 7190 7138 +3 7772 7910 7916 +3 8241 8237 8167 +3 7915 7765 7771 +3 7396 7390 7482 +3 7340 7273 7263 +3 7273 7190 7263 +3 7190 7184 7263 +3 7132 7184 7190 +3 7034 7132 7138 +3 6940 7034 7040 +3 6867 6940 6946 +3 6867 6946 6877 +3 6867 6877 6782 +3 6867 6782 6776 +3 6782 6642 6776 +3 6642 6636 6776 +3 6492 6636 6642 +3 6380 6492 6498 +3 6283 6380 6386 +3 6379 6283 6287 +3 6491 6379 6385 +3 6635 6491 6497 +3 6775 6635 6641 +3 6866 6775 6781 +3 6939 6866 6876 +3 7033 6939 6945 +3 7131 7033 7039 +3 7183 7131 7137 +3 7262 7183 7189 +3 7262 7189 7272 +3 7262 7272 7333 +3 7272 7339 7333 +3 7339 7389 7333 +3 7487 7389 7395 +3 7389 7339 7395 +3 7481 7389 7487 +3 7573 7481 7579 +3 7573 7579 7652 +3 7771 7652 7662 +3 7652 7579 7662 +3 7765 7652 7771 +3 7909 7765 7915 +3 7909 7915 8059 +3 7909 8059 8053 +3 8059 8167 8053 +3 8167 8161 8053 +3 8237 8161 8167 +3 8162 8237 8241 +3 8162 8241 8168 +3 8162 8168 8060 +3 8162 8060 8054 +3 8060 7916 8054 +3 7916 7910 8054 +3 7766 7772 7663 +3 7910 7772 7766 +3 7390 7340 7334 +3 7340 7263 7334 +3 7396 7340 7390 +3 7488 7396 7482 +3 7488 7482 7574 +3 7488 7574 7580 +3 7574 7653 7580 +3 7653 7663 7580 +3 7766 7663 7653 +3 7572 7573 7652 +3 7573 7480 7481 +3 7033 7032 6939 +3 6939 6938 6866 +3 6866 6865 6767 +3 6767 6766 6627 +3 6627 6626 6483 +3 7893 7749 7748 +3 7893 7892 8037 +3 8153 8152 8045 +3 7651 7652 7757 +3 7473 7380 7472 +3 7122 7174 7175 +3 6856 6855 6930 +3 6855 6759 6758 +3 6758 6619 6618 +3 6363 6362 6475 +3 6275 6362 6363 +3 6275 6363 6276 +3 6275 6276 6371 +3 6275 6371 6370 +3 6371 6483 6370 +3 6483 6482 6370 +3 6626 6482 6483 +3 6766 6626 6627 +3 6865 6766 6767 +3 6938 6865 6866 +3 7032 6938 6939 +3 7130 7032 7033 +3 7130 7033 7131 +3 7130 7131 7183 +3 7130 7183 7182 +3 7183 7262 7182 +3 7262 7261 7182 +3 7332 7261 7262 +3 7332 7262 7333 +3 7332 7333 7388 +3 7481 7388 7389 +3 7388 7333 7389 +3 7480 7388 7481 +3 7572 7480 7573 +3 7651 7572 7652 +3 7756 7651 7757 +3 7756 7757 7901 +3 7756 7901 7900 +3 7901 8045 7900 +3 8045 8044 7900 +3 8152 8044 8045 +3 8229 8152 8153 +3 8229 8153 8230 +3 8229 8230 8145 +3 8229 8145 8144 +3 8145 8037 8144 +3 8037 8036 8144 +3 7892 8036 8037 +3 7748 7892 7893 +3 6618 6475 6474 +3 6475 6362 6474 +3 6619 6475 6618 +3 6759 6619 6758 +3 6856 6759 6855 +3 6931 6856 6930 +3 6931 6930 7024 +3 6931 7024 7025 +3 7024 7122 7025 +3 7122 7123 7025 +3 7175 7123 7122 +3 7252 7175 7174 +3 7252 7174 7251 +3 7252 7251 7324 +3 7252 7324 7325 +3 7324 7380 7325 +3 7380 7381 7325 +3 7473 7381 7380 +3 7565 7473 7472 +3 7565 7472 7564 +3 7565 7564 7642 +3 7564 7641 7642 +3 7641 7749 7642 +3 7748 7749 7641 +3 5640 5555 5561 +3 5463 5469 5561 +3 5469 5371 5377 +3 5037 5031 4945 +3 4945 4939 4880 +3 4880 4870 4783 +3 4783 4777 4639 +3 4639 4633 4495 +3 4495 4489 4387 +3 4387 4381 4289 +3 4388 4289 4285 +3 4388 4382 4496 +3 4490 4640 4496 +3 4946 4940 5038 +3 5038 5032 5126 +3 5120 5182 5126 +3 5182 5176 5261 +3 5641 5740 5746 +3 5740 5890 5746 +3 5890 5884 6034 +3 5889 5739 5745 +3 5745 5630 5640 +3 5464 5378 5372 +3 5261 5251 5326 +3 5176 5251 5261 +3 5120 5176 5182 +3 5032 5120 5126 +3 4940 5032 5038 +3 4871 4940 4946 +3 4871 4946 4881 +3 4871 4881 4784 +3 4871 4784 4778 +3 4784 4640 4778 +3 4640 4634 4778 +3 4490 4634 4640 +3 4382 4490 4496 +3 4285 4382 4388 +3 4381 4285 4289 +3 4489 4381 4387 +3 4633 4489 4495 +3 4777 4633 4639 +3 4870 4777 4783 +3 4939 4870 4880 +3 5031 4939 4945 +3 5119 5031 5037 +3 5119 5037 5125 +3 5119 5125 5175 +3 5260 5175 5181 +3 5175 5125 5181 +3 5250 5175 5260 +3 5250 5260 5319 +3 5377 5319 5325 +3 5319 5260 5325 +3 5371 5319 5377 +3 5463 5371 5469 +3 5555 5463 5561 +3 5630 5555 5640 +3 5739 5630 5745 +3 5883 5739 5889 +3 5883 5889 6033 +3 5883 6033 6027 +3 6033 6137 6027 +3 6137 6131 6027 +3 6211 6131 6137 +3 6211 6137 6215 +3 6211 6215 6132 +3 6215 6138 6132 +3 6138 6034 6132 +3 6034 6028 6132 +3 5884 6028 6034 +3 5740 5884 5890 +3 5372 5326 5320 +3 5326 5251 5320 +3 5378 5326 5372 +3 5470 5378 5464 +3 5470 5464 5556 +3 5470 5556 5562 +3 5556 5631 5562 +3 5631 5641 5562 +3 5740 5641 5631 +3 5554 5555 5630 +3 5555 5462 5463 +3 5370 5371 5463 +3 5031 5030 4939 +3 4870 4939 4938 +3 4870 4869 4769 +3 4769 4768 4625 +3 4625 4624 4481 +3 4481 4480 4373 +3 4278 4373 4372 +3 4278 4277 4365 +3 4365 4364 4473 +3 4472 4617 4473 +3 4860 4930 4931 +3 5111 5110 5167 +3 5166 5240 5167 +3 5311 5240 5239 +3 5311 5310 5363 +3 5362 5455 5363 +3 5455 5454 5547 +3 5547 5546 5620 +3 5867 5723 5722 +3 6011 5867 5866 +3 5731 5875 5730 +3 5629 5630 5731 +3 5620 5619 5723 +3 5546 5619 5620 +3 5454 5546 5547 +3 5362 5454 5455 +3 5310 5362 5363 +3 5239 5310 5311 +3 5166 5239 5240 +3 5110 5166 5167 +3 5022 5110 5111 +3 4931 5022 5023 +3 5022 5111 5023 +3 4930 5022 4931 +3 4859 4930 4860 +3 4859 4860 4761 +3 4859 4761 4760 +3 4761 4617 4760 +3 4617 4616 4760 +3 4472 4616 4617 +3 4364 4472 4473 +3 4277 4364 4365 +3 4372 4277 4278 +3 4480 4372 4373 +3 4624 4480 4481 +3 4768 4624 4625 +3 4869 4768 4769 +3 4938 4869 4870 +3 5030 4938 4939 +3 5118 5030 5031 +3 5118 5031 5119 +3 5118 5119 5175 +3 5118 5175 5174 +3 5175 5250 5174 +3 5250 5249 5174 +3 5318 5249 5250 +3 5371 5318 5319 +3 5318 5250 5319 +3 5370 5318 5371 +3 5462 5370 5463 +3 5554 5462 5555 +3 5629 5554 5630 +3 5730 5629 5731 +3 5874 5730 5875 +3 5874 5875 6019 +3 5874 6019 6018 +3 6019 6123 6018 +3 6123 6122 6018 +3 6203 6122 6123 +3 6203 6123 6204 +3 6203 6204 6114 +3 6204 6115 6114 +3 6115 6011 6114 +3 6011 6010 6114 +3 5866 6010 6011 +3 5722 5866 5867 +3 5619 5722 5723 +3 3450 3456 3533 +3 3456 3378 3384 +3 3384 3303 3309 +3 3141 3135 3094 +3 3094 3088 3019 +3 3019 3013 2947 +3 2947 2941 2870 +3 2678 2617 2574 +3 2574 2485 2491 +3 3095 3109 3142 +3 3156 3207 3142 +3 3207 3228 3264 +3 3264 3278 3310 +3 3310 3325 3385 +3 3385 3399 3457 +3 3471 3534 3457 +3 3892 3885 3992 +3 3992 3985 4064 +3 4064 4060 3991 +3 3768 3628 3635 +3 3635 3525 3533 +3 2815 2783 2711 +3 2711 2679 2628 +3 2575 2570 2628 +3 2570 2492 2438 +3 2491 2435 2416 +3 2485 2435 2491 +3 2617 2485 2574 +3 2701 2617 2678 +3 2701 2678 2782 +3 2701 2782 2805 +3 2782 2870 2805 +3 2870 2863 2805 +3 2941 2863 2870 +3 3013 2941 2947 +3 3088 3013 3019 +3 3135 3088 3094 +3 3199 3135 3141 +3 3199 3141 3206 +3 3199 3206 3257 +3 3309 3257 3263 +3 3257 3206 3263 +3 3303 3257 3309 +3 3378 3303 3384 +3 3450 3378 3456 +3 3525 3450 3533 +3 3628 3525 3635 +3 3761 3628 3768 +3 3761 3768 3891 +3 3761 3891 3884 +3 3891 3991 3884 +3 3991 3984 3884 +3 4060 3984 3991 +3 3985 4060 4064 +3 3885 3985 3992 +3 3762 3885 3892 +3 3762 3892 3769 +3 3762 3769 3629 +3 3769 3636 3629 +3 3636 3534 3629 +3 3534 3526 3629 +3 3471 3526 3534 +3 3399 3471 3457 +3 3325 3399 3385 +3 3278 3325 3310 +3 3228 3278 3264 +3 3156 3228 3207 +3 3109 3156 3142 +3 3034 3109 3095 +3 3034 3095 3020 +3 3034 3020 2962 +3 2438 2416 2413 +3 2416 2435 2413 +3 2492 2416 2438 +3 2575 2492 2570 +3 2679 2575 2628 +3 2783 2679 2711 +3 2871 2783 2815 +3 2871 2815 2908 +3 2871 2908 2948 +3 2908 2962 2948 +3 2962 3020 2948 +3 2901 2962 2908 +3 3614 3746 3747 +3 3516 3517 3443 +3 3443 3444 3371 +3 3371 3372 3296 +3 3296 3297 3250 +3 3250 3251 3191 +3 3191 3192 3128 +3 3129 3081 3128 +3 3081 3082 3006 +3 3006 3007 2934 +3 2934 2935 2855 +3 2855 2856 2766 +3 2767 2662 2766 +3 2662 2663 2557 +3 2474 2557 2558 +3 2475 2406 2474 +3 2406 2407 2479 +3 2479 2480 2562 +3 2667 2562 2563 +3 2667 2668 2771 +3 2862 2771 2772 +3 3012 3088 3087 +3 3134 3087 3135 +3 3134 3199 3198 +3 3257 3256 3198 +3 3256 3303 3302 +3 3302 3378 3377 +3 3377 3450 3449 +3 3449 3525 3524 +3 3524 3621 3620 +3 3620 3754 3753 +3 3753 3877 3876 +3 4053 4052 3977 +3 3969 4052 4053 +3 3969 4053 3970 +3 3969 3970 3870 +3 3969 3870 3869 +3 3870 3747 3869 +3 3747 3746 3869 +3 3613 3614 3517 +3 3746 3614 3613 +3 3876 3977 3976 +3 3977 4052 3976 +3 3877 3977 3876 +3 3754 3877 3753 +3 3621 3754 3620 +3 3525 3621 3524 +3 3450 3525 3449 +3 3378 3450 3377 +3 3303 3378 3302 +3 3257 3303 3256 +3 3199 3257 3198 +3 3135 3199 3134 +3 3088 3135 3087 +3 3013 3088 3012 +3 3013 3012 2940 +3 3013 2940 2941 +3 2940 2862 2941 +3 2862 2863 2941 +3 2772 2863 2862 +3 2668 2772 2771 +3 2563 2668 2667 +3 2480 2563 2562 +3 2407 2480 2479 +3 2475 2407 2406 +3 2558 2475 2474 +3 2663 2558 2557 +3 2767 2663 2662 +3 2856 2767 2766 +3 2935 2856 2855 +3 3007 2935 2934 +3 3082 3007 3006 +3 3129 3082 3081 +3 3192 3129 3128 +3 3251 3192 3191 +3 3297 3251 3250 +3 3372 3297 3296 +3 3444 3372 3371 +3 3517 3444 3443 +3 3613 3517 3516 +3 1428 1510 1422 +3 1314 1304 1246 +3 1246 1240 1198 +3 1198 1192 1120 +3 1120 1114 1040 +3 1040 1034 969 +3 723 649 590 +3 419 399 495 +3 399 429 496 +3 496 523 591 +3 591 650 724 +3 1429 1469 1511 +3 2177 2233 2154 +3 2233 2189 2153 +3 2153 2146 2056 +3 2056 1959 1923 +3 1923 1853 1790 +3 1790 1721 1684 +3 590 488 495 +3 649 488 590 +3 752 649 723 +3 752 723 859 +3 752 859 888 +3 859 969 888 +3 969 960 888 +3 1034 960 969 +3 1114 1034 1040 +3 1192 1114 1120 +3 1240 1192 1198 +3 1304 1240 1246 +3 1370 1304 1314 +3 1428 1370 1376 +3 1370 1314 1376 +3 1422 1370 1428 +3 1504 1422 1510 +3 1504 1510 1594 +3 1504 1594 1588 +3 1594 1684 1588 +3 1684 1675 1588 +3 1721 1675 1684 +3 1853 1721 1790 +3 1959 1853 1923 +3 2146 1959 2056 +3 2189 2146 2153 +3 2177 2189 2233 +3 2082 2177 2154 +3 2082 2154 2057 +3 2082 2057 1958 +3 2057 1924 1958 +3 1924 1947 1958 +3 1846 1947 1924 +3 1846 1924 1791 +3 1846 1791 1716 +3 1791 1685 1716 +3 1685 1709 1716 +3 1605 1709 1685 +3 1605 1685 1595 +3 1605 1595 1558 +3 1595 1511 1558 +3 1511 1520 1558 +3 1469 1520 1511 +3 1387 1469 1429 +3 1387 1429 1377 +3 1387 1377 1308 +3 1247 1308 1315 +3 1308 1377 1315 +3 1212 1308 1247 +3 1212 1247 1199 +3 1212 1199 1134 +3 1199 1121 1134 +3 1121 1086 1134 +3 1050 1086 1121 +3 1050 1121 1041 +3 1050 1041 1003 +3 1041 970 1003 +3 970 900 1003 +3 892 900 970 +3 892 970 860 +3 892 860 758 +3 860 724 758 +3 724 658 758 +3 650 658 724 +3 523 650 591 +3 429 523 496 +3 419 429 399 +3 488 419 495 +3 1588 1675 1674 +3 2225 2224 2140 +3 1415 1416 1363 +3 1295 1363 1364 +3 1233 1295 1296 +3 1185 1233 1234 +3 1107 1185 1186 +3 1027 1107 1108 +3 950 1027 1028 +3 950 951 840 +3 840 841 704 +3 704 705 571 +3 572 475 571 +3 475 476 390 +3 481 390 391 +3 481 482 577 +3 710 577 578 +3 959 1034 1033 +3 1033 1114 1113 +3 1192 1191 1113 +3 1191 1240 1239 +3 1239 1304 1303 +3 1369 1303 1370 +3 1369 1422 1421 +3 1588 1587 1504 +3 1674 1587 1588 +3 1777 1674 1675 +3 1777 1675 1778 +3 1777 1778 1910 +3 2044 1910 1911 +3 1910 1778 1911 +3 2043 1910 2044 +3 2043 2044 2140 +3 2043 2140 2139 +3 2140 2224 2139 +3 2038 2133 2134 +3 2133 2225 2134 +3 2224 2225 2133 +3 2037 2038 1905 +3 2133 2038 2037 +3 1904 1905 1772 +3 2037 1905 1904 +3 1771 1772 1666 +3 1904 1772 1771 +3 1421 1504 1503 +3 1504 1587 1503 +3 1422 1504 1421 +3 1370 1422 1369 +3 1304 1370 1303 +3 1240 1304 1239 +3 1192 1240 1191 +3 1114 1192 1113 +3 1034 1114 1033 +3 960 1034 959 +3 960 959 846 +3 960 846 847 +3 846 710 847 +3 710 711 847 +3 578 711 710 +3 482 578 577 +3 391 482 481 +3 476 391 390 +3 572 476 475 +3 705 572 571 +3 841 705 704 +3 951 841 840 +3 1028 951 950 +3 1108 1028 1027 +3 1186 1108 1107 +3 1234 1186 1185 +3 1296 1234 1233 +3 1364 1296 1295 +3 1416 1364 1363 +3 1498 1416 1415 +3 1498 1415 1497 +3 1498 1497 1582 +3 1497 1581 1582 +3 1581 1665 1582 +3 1665 1666 1582 +3 1771 1666 1665 +3 8474 7742 8466 +3 8458 8138 8451 +3 8457 7885 8465 +3 8465 7741 8473 +3 8497 8153 8505 +3 8543 8162 8538 +3 7643 8474 7750 +3 7750 8482 7894 +3 8498 8146 8490 +3 8231 8146 8498 +3 8231 8498 8154 +3 8498 8506 8154 +3 8506 8046 8154 +3 7902 8046 8506 +3 7902 8506 8514 +3 7902 8514 7758 +3 8514 8522 7758 +3 8522 7653 7758 +3 7766 7653 8522 +3 7766 8522 8530 +3 7766 8530 7910 +3 8530 8538 7910 +3 8538 8054 7910 +3 8162 8054 8538 +3 8237 8162 8543 +3 8237 8543 8161 +3 8543 8537 8161 +3 8537 8053 8161 +3 7909 8053 8537 +3 7909 8537 8529 +3 7909 8529 7765 +3 8529 8521 7765 +3 8521 7652 7765 +3 7757 7652 8521 +3 7757 8521 8513 +3 7757 8513 7901 +3 8513 8505 7901 +3 8505 8045 7901 +3 8153 8045 8505 +3 8230 8153 8497 +3 8230 8497 8145 +3 8497 8489 8145 +3 8489 8037 8145 +3 7893 8037 8489 +3 7893 8489 8481 +3 7893 8481 7749 +3 8481 8473 7749 +3 8473 7642 7749 +3 7741 7642 8473 +3 7885 7741 8465 +3 8029 7885 8457 +3 8029 8457 8137 +3 8457 8451 8137 +3 8451 8223 8137 +3 8138 8223 8451 +3 8030 8138 8458 +3 8030 8458 7886 +3 8458 8466 7886 +3 8466 7742 7886 +3 7894 8490 8038 +3 8490 8146 8038 +3 8482 8490 7894 +3 8474 8482 7750 +3 7742 8474 7643 +3 237 649 229 +3 752 221 229 +3 208 711 202 +3 200 476 193 +3 181 951 174 +3 652 520 160 +3 652 160 167 +3 652 167 754 +3 167 174 754 +3 174 890 754 +3 951 890 174 +3 841 951 181 +3 841 181 187 +3 841 187 705 +3 187 193 705 +3 193 572 705 +3 476 572 193 +3 391 476 200 +3 391 200 482 +3 200 202 482 +3 202 578 482 +3 711 578 202 +3 847 711 208 +3 847 208 214 +3 847 214 960 +3 214 221 960 +3 221 888 960 +3 752 888 221 +3 649 752 229 +3 488 649 237 +3 1959 2617 1853 +3 1853 2701 1721 +3 1721 2805 1675 +3 1911 2563 2044 +3 2134 2475 2038 +3 2038 2558 1905 +3 1905 2663 1772 +3 1772 2767 1666 +3 1666 2856 1720 +3 1720 2807 1852 +3 1852 2703 1956 +3 1956 2619 2089 +3 2619 2514 2089 +3 2703 2619 1956 +3 2807 2703 1852 +3 2856 2807 1720 +3 2767 2856 1666 +3 2663 2767 1772 +3 2558 2663 1905 +3 2475 2558 2038 +3 2407 2475 2134 +3 2407 2134 2225 +3 2407 2225 2480 +3 2044 2480 2140 +3 2480 2225 2140 +3 2563 2480 2044 +3 2668 2563 1911 +3 2668 1911 1778 +3 2668 1778 2772 +3 1778 1675 2772 +3 1675 2863 2772 +3 2805 2863 1675 +3 2701 2805 1721 +3 2617 2701 1853 +3 2485 2617 1959 +3 2485 1959 2146 +3 3748 4618 3871 +3 3755 4770 3622 +3 3622 4871 3526 +3 3526 4778 3629 +3 3629 4634 3762 +3 3762 4490 3885 +3 3885 4382 3985 +3 3985 4285 4060 +3 4060 4381 3984 +3 4489 3884 3984 +3 3884 4633 3761 +3 3977 4373 4053 +3 4617 3614 3747 +3 3614 4761 3517 +3 3963 3863 4465 +3 3963 4357 4048 +3 4048 4271 3964 +3 3964 4358 3864 +3 3864 4466 3741 +3 3741 4610 3608 +3 3517 4860 3607 +3 4761 4860 3517 +3 4617 4761 3614 +3 4473 4617 3747 +3 4473 3747 3870 +3 4473 3870 3970 +3 4473 3970 4365 +3 3970 4053 4365 +3 4053 4278 4365 +3 4373 4278 4053 +3 4481 4373 3977 +3 3754 4481 3877 +3 4481 3977 3877 +3 4625 4481 3754 +3 4625 3754 3621 +3 4625 3621 4769 +3 3621 3525 4769 +3 3525 4870 4769 +3 4777 4870 3525 +3 3761 4777 3628 +3 4777 3525 3628 +3 4633 4777 3761 +3 4489 4633 3884 +3 4381 4489 3984 +3 4285 4381 4060 +3 4382 4285 3985 +3 4490 4382 3885 +3 4634 4490 3762 +3 4778 4634 3629 +3 4871 4778 3526 +3 4770 4871 3622 +3 4626 4770 3755 +3 4626 3755 3878 +3 4626 3878 4482 +3 3878 3978 4482 +3 3978 4374 4482 +3 4279 4374 3978 +3 4279 3978 4054 +3 4279 4054 3971 +3 4279 3971 4366 +3 3971 3871 4366 +3 3871 4474 4366 +3 4618 4474 3871 +3 4762 4618 3748 +3 4762 3748 3615 +3 4762 3615 4861 +3 3615 3518 4861 +3 3518 3608 4861 +3 3608 4754 4861 +3 4610 4754 3608 +3 4466 4610 3741 +3 4358 4466 3864 +3 4271 4358 3964 +3 4357 4271 4048 +3 4465 4357 3963 +3 4609 4465 3863 +3 4609 3863 3740 +3 4609 3740 4753 +3 3740 3607 4753 +3 3607 4860 4753 +3 6857 5724 5621 +3 5724 6760 5868 +3 6620 6012 5868 +3 6205 6372 6124 +3 6124 6484 6020 +3 6020 6628 5876 +3 5876 6768 5732 +3 5732 6867 5631 +3 5631 6776 5740 +3 5884 5740 6636 +3 5884 6492 6028 +3 6132 6028 6380 +3 6132 6283 6211 +3 6211 6379 6131 +3 6131 6491 6027 +3 5620 6751 5715 +3 6108 6356 6004 +3 6004 6468 5860 +3 5860 6612 5716 +3 5716 6752 5621 +3 5620 6759 6856 +3 6759 5723 6619 +3 6619 5867 6475 +3 6475 6011 6363 +3 6363 6115 6276 +3 6627 6483 5875 +3 6627 5731 6767 +3 6866 6767 5630 +3 6027 6635 5883 +3 6635 5739 5883 +3 6491 6635 6027 +3 6379 6491 6131 +3 6283 6379 6211 +3 6380 6283 6132 +3 6492 6380 6028 +3 6636 6492 5884 +3 6776 6636 5740 +3 6867 6776 5631 +3 6768 6867 5732 +3 6628 6768 5876 +3 6484 6628 6020 +3 6372 6484 6124 +3 6277 6372 6205 +3 6277 6205 6116 +3 6277 6116 6364 +3 6116 6012 6364 +3 6012 6476 6364 +3 6620 6476 6012 +3 6760 6620 5868 +3 6857 6760 5724 +3 6752 6857 5621 +3 6612 6752 5716 +3 6468 6612 5860 +3 6356 6468 6004 +3 6269 6356 6108 +3 6269 6108 6197 +3 6269 6197 6355 +3 6003 6355 6107 +3 6355 6197 6107 +3 6467 6355 6003 +3 6467 6003 5859 +3 6467 5859 6611 +3 5859 5715 6611 +3 5715 6751 6611 +3 6866 5739 6775 +3 5739 6635 6775 +3 5630 5739 6866 +3 5731 5630 6767 +3 5875 5731 6627 +3 6019 5875 6483 +3 6019 6483 6371 +3 6019 6371 6123 +3 6371 6276 6123 +3 6276 6204 6123 +3 6115 6204 6276 +3 6011 6115 6363 +3 5867 6011 6475 +3 5723 5867 6619 +3 5620 5723 6759 +3 6751 5620 6856 +3 7473 7465 7381 +3 7381 7373 7325 +3 7252 7325 7317 +3 7175 7252 7242 +3 7175 7167 7123 +3 7123 7115 7025 +3 7017 6931 7025 +3 6931 6923 6856 +3 6856 6846 6751 +3 6743 6611 6751 +3 6603 6467 6611 +3 6355 6467 6459 +3 6355 6347 6269 +3 6269 6265 6356 +3 6468 6356 6348 +3 6460 6612 6468 +3 6752 6612 6604 +3 6752 6744 6857 +3 6857 6847 6932 +3 6924 7026 6932 +3 7124 7026 7018 +3 7382 7326 7318 +3 7886 7742 7734 +3 8223 8217 8137 +3 7885 7733 7741 +3 7382 7374 7474 +3 7318 7374 7382 +3 7243 7318 7326 +3 7243 7326 7253 +3 7243 7253 7168 +3 7253 7176 7168 +3 7176 7124 7168 +3 7124 7116 7168 +3 7018 7116 7124 +3 6924 7018 7026 +3 6847 6924 6932 +3 6744 6847 6857 +3 6604 6744 6752 +3 6460 6604 6612 +3 6348 6460 6468 +3 6265 6348 6356 +3 6347 6265 6269 +3 6459 6347 6355 +3 6603 6459 6467 +3 6743 6603 6611 +3 6846 6743 6751 +3 6923 6846 6856 +3 7017 6923 6931 +3 7115 7017 7025 +3 7167 7115 7123 +3 7242 7167 7175 +3 7317 7242 7252 +3 7373 7317 7325 +3 7465 7373 7381 +3 7557 7465 7473 +3 7557 7473 7565 +3 7557 7565 7632 +3 7741 7632 7642 +3 7632 7565 7642 +3 7733 7632 7741 +3 7877 7733 7885 +3 7877 7885 8029 +3 7877 8029 8021 +3 8029 8137 8021 +3 8137 8129 8021 +3 8217 8129 8137 +3 8130 8217 8223 +3 8130 8223 8138 +3 8130 8138 8030 +3 8130 8030 8022 +3 8030 7886 8022 +3 7886 7878 8022 +3 7734 7878 7886 +3 7558 7474 7466 +3 7474 7374 7466 +3 7566 7474 7558 +3 7566 7558 7643 +3 7558 7633 7643 +3 7633 7742 7643 +3 7734 7742 7633 +3 7235 7163 7065 +3 6259 6343 6533 +3 7317 7423 7241 +3 7963 8017 8125 +3 7873 8017 7963 +3 7873 7963 7811 +3 7873 7811 7729 +3 7811 7631 7729 +3 7631 7632 7729 +3 7557 7632 7631 +3 7557 7631 7519 +3 7557 7519 7465 +3 7519 7423 7465 +3 7423 7373 7465 +3 7317 7373 7423 +3 7242 7317 7241 +3 7242 7241 7167 +3 7241 7067 7167 +3 7067 7115 7167 +3 7017 7115 7067 +3 7017 7067 6969 +3 7017 6969 6923 +3 6969 6845 6923 +3 6845 6846 6923 +3 6739 6846 6845 +3 6739 6845 6677 +3 6739 6677 6599 +3 6677 6533 6599 +3 6533 6455 6599 +3 6343 6455 6533 +3 6260 6343 6259 +3 6260 6259 6339 +3 6259 6531 6339 +3 6531 6451 6339 +3 6595 6451 6531 +3 6595 6531 6675 +3 6595 6675 6735 +3 6675 6839 6735 +3 6839 6840 6735 +3 6919 6840 6839 +3 6919 6839 6967 +3 6919 6967 7013 +3 6967 7065 7013 +3 7065 7111 7013 +3 7163 7111 7065 +3 7236 7163 7235 +3 7236 7235 7313 +3 7235 7421 7313 +3 7421 7369 7313 +3 7461 7369 7421 +3 7461 7421 7517 +3 7461 7517 7553 +3 7517 7625 7553 +3 7625 7626 7553 +3 7725 7626 7625 +3 7725 7625 7809 +3 7725 7809 7869 +3 7809 7961 7869 +3 7961 8013 7869 +3 8121 8013 7961 +3 8121 7961 8211 +3 8121 8211 8212 +3 8211 8125 8212 +3 7963 8125 8211 +3 5620 5539 5547 +3 5447 5455 5547 +3 5111 5103 5023 +3 5023 5015 4931 +3 4931 4923 4860 +3 4860 4846 4753 +3 4609 4753 4745 +3 4465 4609 4601 +3 4465 4457 4357 +3 4357 4349 4271 +3 4271 4265 4358 +3 4358 4350 4466 +3 4466 4458 4610 +3 4610 4602 4754 +3 4754 4746 4861 +3 4847 4932 4861 +3 4932 4924 5024 +3 5112 5024 5016 +3 5364 5312 5304 +3 5860 5996 6004 +3 5707 5715 5859 +3 5606 5620 5715 +3 5548 5607 5621 +3 5540 5607 5548 +3 5540 5548 5456 +3 5540 5456 5448 +3 5456 5364 5448 +3 5364 5356 5448 +3 5304 5356 5364 +3 5227 5304 5312 +3 5227 5312 5241 +3 5227 5241 5168 +3 5227 5168 5160 +3 5168 5112 5160 +3 5112 5104 5160 +3 5016 5104 5112 +3 4924 5016 5024 +3 4847 4924 4932 +3 4746 4847 4861 +3 4602 4746 4754 +3 4458 4602 4610 +3 4350 4458 4466 +3 4265 4350 4358 +3 4349 4265 4271 +3 4457 4349 4357 +3 4601 4457 4465 +3 4745 4601 4609 +3 4846 4745 4753 +3 4923 4846 4860 +3 5015 4923 4931 +3 5103 5015 5023 +3 5159 5103 5111 +3 5240 5159 5167 +3 5159 5111 5167 +3 5226 5159 5240 +3 5226 5240 5303 +3 5240 5311 5303 +3 5311 5355 5303 +3 5455 5355 5363 +3 5355 5311 5363 +3 5447 5355 5455 +3 5539 5447 5547 +3 5606 5539 5620 +3 5707 5606 5715 +3 5851 5707 5859 +3 5851 5859 6003 +3 5851 6003 5995 +3 6003 6107 5995 +3 6107 6099 5995 +3 6191 6099 6107 +3 6191 6107 6197 +3 6191 6197 6100 +3 6004 6100 6108 +3 6100 6197 6108 +3 5996 6100 6004 +3 5852 5996 5860 +3 5852 5860 5716 +3 5852 5716 5708 +3 5716 5621 5708 +3 5621 5607 5708 +3 5015 4969 4923 +3 4737 4593 4677 +3 6091 6185 6186 +3 6185 6095 6186 +3 5923 6185 6091 +3 5843 5923 5987 +3 5923 6091 5987 +3 5779 5923 5843 +3 5779 5843 5699 +3 5779 5699 5599 +3 5535 5599 5600 +3 5599 5699 5600 +3 5491 5599 5535 +3 5491 5535 5443 +3 5491 5443 5399 +3 5299 5399 5351 +3 5399 5443 5351 +3 5219 5399 5299 +3 5219 5299 5220 +3 5219 5220 5155 +3 5219 5155 5059 +3 5011 5059 5099 +3 5059 5155 5099 +3 4967 5059 5011 +3 4967 5011 4919 +3 4967 4919 4839 +3 4737 4839 4840 +3 4839 4919 4840 +3 4677 4839 4737 +3 4529 4677 4593 +3 4529 4593 4449 +3 4529 4449 4341 +3 4529 4341 4259 +3 4345 4259 4260 +3 4259 4341 4260 +3 4531 4259 4345 +3 4531 4345 4453 +3 4531 4453 4597 +3 4531 4597 4679 +3 4597 4741 4679 +3 4741 4845 4679 +3 4923 4845 4846 +3 4845 4741 4846 +3 4969 4845 4923 +3 5061 4969 5015 +3 5061 5015 5103 +3 5061 5103 5159 +3 5061 5159 5225 +3 5159 5226 5225 +3 5226 5303 5225 +3 5303 5401 5225 +3 5447 5401 5355 +3 5401 5303 5355 +3 5493 5401 5447 +3 5493 5447 5539 +3 5493 5539 5605 +3 5703 5605 5606 +3 5605 5539 5606 +3 5781 5605 5703 +3 5781 5703 5847 +3 5781 5847 5925 +3 6095 5925 5991 +3 5925 5847 5991 +3 6185 5925 6095 +3 3032 3033 2961 +3 3033 3107 3108 +3 3108 3154 3155 +3 3226 3227 3155 +3 3227 3276 3277 +3 3323 3324 3277 +3 3398 3324 3397 +3 3398 3469 3470 +3 3470 3510 3518 +3 3518 3601 3608 +3 3608 3734 3741 +3 3741 3857 3864 +3 3600 3607 3740 +3 3607 3509 3517 +3 3444 3517 3438 +3 3444 3366 3372 +3 3007 3001 2935 +3 2856 2935 2929 +3 2856 2849 2807 +3 2807 2806 2703 +3 2703 2702 2619 +3 2619 2618 2514 +3 2618 2513 2514 +3 2702 2618 2619 +3 2806 2702 2703 +3 2849 2806 2807 +3 2929 2849 2856 +3 3001 2929 2935 +3 3076 3001 3007 +3 3076 3007 3082 +3 3076 3082 3129 +3 3076 3129 3123 +3 3129 3192 3123 +3 3192 3185 3123 +3 3245 3185 3192 +3 3245 3192 3251 +3 3245 3251 3291 +3 3372 3291 3297 +3 3291 3251 3297 +3 3366 3291 3372 +3 3438 3366 3444 +3 3509 3438 3517 +3 3600 3509 3607 +3 3733 3600 3740 +3 3733 3740 3863 +3 3733 3863 3856 +3 3863 3963 3856 +3 3963 3956 3856 +3 4042 3956 3963 +3 4042 3963 4048 +3 4042 4048 3957 +3 3864 3957 3964 +3 3957 4048 3964 +3 3857 3957 3864 +3 3734 3857 3741 +3 3601 3734 3608 +3 3510 3601 3518 +3 3469 3510 3470 +3 3397 3469 3398 +3 3323 3397 3324 +3 3276 3323 3277 +3 3226 3276 3227 +3 3154 3226 3155 +3 3107 3154 3108 +3 3032 3107 3033 +3 2960 3032 2961 +3 2960 2961 2897 +3 2961 2899 2897 +3 8408 8122 8404 +3 8385 8117 8387 +3 8407 8125 8411 +3 8447 8130 8438 +3 7726 7627 8396 +3 7726 8396 8400 +3 7726 8400 7870 +3 8400 8404 7870 +3 8404 8014 7870 +3 8122 8014 8404 +3 8213 8122 8408 +3 8213 8408 8126 +3 8408 8412 8126 +3 8412 8018 8126 +3 7874 8018 8412 +3 7874 8412 8416 +3 7874 8416 7730 +3 8416 8420 7730 +3 8420 7633 7730 +3 7734 7633 8420 +3 7734 8420 8430 +3 7734 8430 7878 +3 8430 8438 7878 +3 8438 8022 7878 +3 8130 8022 8438 +3 8217 8130 8447 +3 8217 8447 8129 +3 8447 8437 8129 +3 8437 8021 8129 +3 7877 8021 8437 +3 7877 8437 8429 +3 7877 8429 7733 +3 8429 8419 7733 +3 8419 7632 7733 +3 7729 7632 8419 +3 7729 8419 8415 +3 7729 8415 7873 +3 8415 8411 7873 +3 8411 8017 7873 +3 8125 8017 8411 +3 8212 8125 8407 +3 8212 8407 8121 +3 8407 8403 8121 +3 8403 8013 8121 +3 7869 8013 8403 +3 7869 8403 8399 +3 7869 8399 7725 +3 8399 8395 7725 +3 8395 7626 7725 +3 7721 7626 8395 +3 7721 8395 8391 +3 7721 8391 7865 +3 8391 8387 7865 +3 8387 8009 7865 +3 8117 8009 8387 +3 8209 8117 8385 +3 8209 8385 8118 +3 8385 8388 8118 +3 8388 8010 8118 +3 7866 8010 8388 +3 7866 8388 8392 +3 7866 8392 7722 +3 8392 8396 7722 +3 8396 7627 7722 +3 817 101 681 +3 107 548 681 +3 519 651 153 +3 146 651 753 +3 153 651 146 +3 942 139 889 +3 139 753 889 +3 146 753 139 +3 131 942 823 +3 139 942 131 +3 125 823 687 +3 131 823 125 +3 458 119 554 +3 119 687 554 +3 125 687 119 +3 113 458 377 +3 119 458 113 +3 548 113 452 +3 113 377 452 +3 107 113 548 +3 101 107 681 +3 94 101 817 +3 94 817 933 +3 94 933 904 +3 2750 1748 2646 +3 2646 1881 2541 +3 2541 2014 2458 +3 2460 2020 2543 +3 2543 1887 2648 +3 1754 2752 2648 +3 2752 1657 2849 +3 2849 1719 2806 +3 2806 1851 2702 +3 1955 2618 2702 +3 2618 2088 2513 +3 1955 2088 2618 +3 1851 1955 2702 +3 1719 1851 2806 +3 1657 1719 2849 +3 1754 1657 2752 +3 1887 1754 2648 +3 2020 1887 2543 +3 2116 2020 2460 +3 2116 2460 2211 +3 2460 2395 2211 +3 2395 2458 2211 +3 2458 2110 2211 +3 2014 2110 2458 +3 1881 2014 2541 +3 1748 1881 2646 +3 1648 1748 2750 +3 1648 2750 2842 +3 1648 2842 2821 +3 1648 2821 1708 +3 3505 4841 3593 +3 4738 3726 3593 +3 3726 4594 3849 +3 3853 3953 4346 +3 4602 3734 3601 +3 4458 3857 3734 +3 4350 3957 3857 +3 3957 4265 4042 +3 3956 4042 4349 +3 3956 4457 3856 +3 3856 4601 3733 +3 3733 4745 3600 +3 4846 3509 3600 +3 4741 3596 3509 +3 3596 4597 3729 +3 3592 3725 4593 +3 3844 4445 3944 +3 3944 4337 4035 +3 4035 4257 3945 +3 3945 4338 3845 +3 3845 4446 3722 +3 3722 4590 3589 +3 3589 4734 3505 +3 3592 4737 3504 +3 4737 4840 3504 +3 4593 4737 3592 +3 4449 4593 3725 +3 4449 3725 3848 +3 4449 3848 4341 +3 3848 3948 4341 +3 3948 4037 4341 +3 4037 4260 4341 +3 4345 4260 4037 +3 4345 4037 3952 +3 4345 3952 4453 +3 3729 4453 3852 +3 4453 3952 3852 +3 4597 4453 3729 +3 4741 4597 3596 +3 4846 4741 3509 +3 4745 4846 3600 +3 4601 4745 3733 +3 4457 4601 3856 +3 4349 4457 3956 +3 4265 4349 4042 +3 4350 4265 3957 +3 4458 4350 3857 +3 4602 4458 3734 +3 4746 4602 3601 +3 4746 3601 4847 +3 3597 4847 3510 +3 4847 3601 3510 +3 4742 4847 3597 +3 4742 3597 3730 +3 4742 3730 4598 +3 3730 3853 4598 +3 3853 4454 4598 +3 4346 4454 3853 +3 4261 4346 3953 +3 4261 3953 4038 +3 4261 4038 3949 +3 4261 3949 4342 +3 3949 3849 4342 +3 3849 4450 4342 +3 4594 4450 3849 +3 4738 4594 3726 +3 4841 4738 3593 +3 4734 4841 3505 +3 4590 4734 3589 +3 4446 4590 3722 +3 4338 4446 3845 +3 4257 4338 3945 +3 4337 4257 4035 +3 4445 4337 3944 +3 4589 4445 3844 +3 4589 3844 3721 +3 4589 3721 4733 +3 3721 3588 4733 +3 3588 3504 4733 +3 3504 4840 4733 +3 5601 6841 5700 +3 5700 6736 5844 +3 5844 6596 5988 +3 5988 6452 6092 +3 5984 6448 5840 +3 6595 5843 6451 +3 6451 5987 6339 +3 6339 6091 6260 +3 6260 6186 6343 +3 6343 6095 6455 +3 6455 5991 6599 +3 6599 5847 6739 +3 6743 5851 6603 +3 5995 6459 6603 +3 6459 6099 6347 +3 6347 6191 6265 +3 6265 6100 6348 +3 6460 6348 5996 +3 6604 6460 5852 +3 5708 6744 6604 +3 6744 5607 6847 +3 6847 5704 6740 +3 6740 5848 6600 +3 6600 5992 6456 +3 6456 6096 6344 +3 6092 6340 6187 +3 6452 6340 6092 +3 6596 6452 5988 +3 6736 6596 5844 +3 6841 6736 5700 +3 6732 6841 5601 +3 6732 5601 5696 +3 6732 5696 6592 +3 5696 5840 6592 +3 5840 6448 6592 +3 6336 5984 6088 +3 6448 5984 6336 +3 6257 6088 6183 +3 6336 6088 6257 +3 6335 6183 6087 +3 6257 6183 6335 +3 6447 6087 5983 +3 6335 6087 6447 +3 6591 5983 5839 +3 6447 5983 6591 +3 6731 5839 5695 +3 6591 5839 6731 +3 6344 6187 6261 +3 6187 6340 6261 +3 6096 6187 6344 +3 5992 6096 6456 +3 5848 5992 6600 +3 5704 5848 6740 +3 5607 5704 6847 +3 5708 5607 6744 +3 5852 5708 6604 +3 5996 5852 6460 +3 6100 5996 6348 +3 6191 6100 6265 +3 6099 6191 6347 +3 5995 6099 6459 +3 5851 5995 6603 +3 5707 5851 6743 +3 5707 6743 6846 +3 5707 6846 5606 +3 6846 6739 5606 +3 6739 5703 5606 +3 5847 5703 6739 +3 5991 5847 6599 +3 6095 5991 6455 +3 6186 6095 6343 +3 6091 6186 6260 +3 5987 6091 6339 +3 5843 5987 6451 +3 5699 5843 6595 +3 5699 6595 6735 +3 5699 6735 5600 +3 6735 6840 5600 +3 6840 5695 5600 +3 6731 5695 6840 +3 7549 7553 7626 +3 7553 7457 7461 +3 7461 7365 7369 +3 7369 7309 7313 +3 7313 7230 7236 +3 7236 7159 7163 +3 7163 7107 7111 +3 7111 7009 7013 +3 7013 6915 6919 +3 6591 6587 6447 +3 6447 6443 6335 +3 6335 6331 6257 +3 6336 6257 6253 +3 6336 6332 6448 +3 7014 7010 7112 +3 7722 7718 7866 +3 8114 8118 8010 +3 8118 8207 8209 +3 8209 8113 8117 +3 8005 8009 8117 +3 8009 7861 7865 +3 7865 7717 7721 +3 7721 7620 7626 +3 7550 7462 7458 +3 7458 7370 7366 +3 7366 7314 7310 +3 7310 7237 7231 +3 7112 7108 7164 +3 7010 7108 7112 +3 6916 7010 7014 +3 6916 7014 6920 +3 6916 6920 6835 +3 6732 6835 6841 +3 6835 6920 6841 +3 6728 6835 6732 +3 6728 6732 6592 +3 6728 6592 6588 +3 6592 6448 6588 +3 6448 6444 6588 +3 6332 6444 6448 +3 6253 6332 6336 +3 6331 6253 6257 +3 6443 6331 6335 +3 6587 6443 6447 +3 6727 6587 6591 +3 6727 6591 6731 +3 6727 6731 6834 +3 6919 6834 6840 +3 6834 6731 6840 +3 6915 6834 6919 +3 7009 6915 7013 +3 7107 7009 7111 +3 7159 7107 7163 +3 7230 7159 7236 +3 7309 7230 7313 +3 7365 7309 7369 +3 7457 7365 7461 +3 7549 7457 7553 +3 7620 7549 7626 +3 7717 7620 7721 +3 7861 7717 7865 +3 8005 7861 8009 +3 8113 8005 8117 +3 8207 8113 8209 +3 8114 8207 8118 +3 8006 8114 8010 +3 8006 8010 7862 +3 8010 7866 7862 +3 7866 7718 7862 +3 7231 7164 7160 +3 7164 7108 7160 +3 7237 7164 7231 +3 7314 7237 7310 +3 7370 7314 7366 +3 7462 7370 7458 +3 7554 7462 7550 +3 7554 7550 7621 +3 7554 7621 7627 +3 7621 7722 7627 +3 7718 7722 7621 +3 7364 7365 7457 +3 7309 7365 7308 +3 7309 7229 7230 +3 7230 7158 7159 +3 7705 7848 7849 +3 7992 7993 7849 +3 7356 7448 7449 +3 7300 7356 7357 +3 7300 7301 7219 +3 7219 7220 7150 +3 7151 7098 7150 +3 7099 7000 7098 +3 7001 6906 7000 +3 6907 6823 6906 +3 6710 6823 6824 +3 6710 6711 6570 +3 6570 6571 6426 +3 6427 6314 6426 +3 6578 6435 6579 +3 6578 6579 6719 +3 6578 6719 6718 +3 6719 6834 6718 +3 6834 6833 6718 +3 6914 6833 6834 +3 6914 6834 6915 +3 6914 6915 7008 +3 6915 7009 7008 +3 7009 7106 7008 +3 7159 7106 7107 +3 7106 7009 7107 +3 7158 7106 7159 +3 7229 7158 7230 +3 7308 7229 7309 +3 7364 7308 7365 +3 7456 7364 7457 +3 7456 7457 7549 +3 7456 7549 7548 +3 7549 7620 7548 +3 7620 7619 7548 +3 7712 7619 7620 +3 7857 7712 7713 +3 7712 7620 7713 +3 7856 7712 7857 +3 7856 7857 8001 +3 7856 8001 8000 +3 8001 8109 8000 +3 8109 8108 8000 +3 8201 8108 8109 +3 8201 8109 8202 +3 8201 8202 8100 +3 7993 8100 8101 +3 8100 8202 8101 +3 7992 8100 7993 +3 7848 7992 7849 +3 7704 7848 7705 +3 6322 6435 6434 +3 6435 6578 6434 +3 6323 6435 6322 +3 6323 6322 6246 +3 6322 6245 6246 +3 6245 6314 6246 +3 6314 6315 6246 +3 6427 6315 6314 +3 6571 6427 6426 +3 6711 6571 6570 +3 6824 6711 6710 +3 6907 6824 6823 +3 7001 6907 6906 +3 7099 7001 7000 +3 7151 7099 7098 +3 7220 7151 7150 +3 7301 7220 7219 +3 7357 7301 7300 +3 7449 7357 7356 +3 7541 7449 7448 +3 7541 7448 7540 +3 7541 7540 7610 +3 7540 7609 7610 +3 7609 7705 7610 +3 7704 7705 7609 +3 5351 5347 5299 +3 5299 5295 5220 +3 5220 5214 5155 +3 5155 5151 5099 +3 5099 5095 5011 +3 5007 4919 5011 +3 4919 4915 4840 +3 4589 4441 4445 +3 4337 4445 4333 +3 4337 4253 4257 +3 4257 4334 4338 +3 4734 4730 4841 +3 4841 4835 4920 +3 4920 4916 5012 +3 5012 5008 5100 +3 5100 5096 5156 +3 5352 5300 5348 +3 5352 5440 5444 +3 5536 5444 5532 +3 5980 5984 5840 +3 5984 6084 6088 +3 6088 6179 6183 +3 6183 6083 6087 +3 6087 5979 5983 +3 5839 5983 5835 +3 5839 5691 5695 +3 5695 5594 5600 +3 5536 5595 5601 +3 5532 5595 5536 +3 5440 5532 5444 +3 5348 5440 5352 +3 5296 5348 5300 +3 5296 5300 5221 +3 5296 5221 5215 +3 5221 5156 5215 +3 5156 5152 5215 +3 5096 5152 5156 +3 5008 5096 5100 +3 4916 5008 5012 +3 4835 4916 4920 +3 4730 4835 4841 +3 4586 4730 4734 +3 4586 4734 4590 +3 4586 4590 4442 +3 4338 4442 4446 +3 4442 4590 4446 +3 4334 4442 4338 +3 4253 4334 4257 +3 4333 4253 4337 +3 4441 4333 4445 +3 4585 4441 4589 +3 4585 4589 4733 +3 4585 4733 4729 +3 4733 4840 4729 +3 4840 4834 4729 +3 4915 4834 4840 +3 5007 4915 4919 +3 5095 5007 5011 +3 5151 5095 5099 +3 5214 5151 5155 +3 5295 5214 5220 +3 5347 5295 5299 +3 5439 5347 5351 +3 5439 5351 5443 +3 5439 5443 5531 +3 5600 5531 5535 +3 5531 5443 5535 +3 5594 5531 5600 +3 5691 5594 5695 +3 5835 5691 5839 +3 5979 5835 5983 +3 6083 5979 6087 +3 6179 6083 6183 +3 6084 6179 6088 +3 5980 6084 5984 +3 5836 5980 5840 +3 5836 5840 5696 +3 5836 5696 5692 +3 5696 5601 5692 +3 5601 5595 5692 +3 5531 5594 5593 +3 5347 5294 5295 +3 5295 5213 5214 +3 5151 5214 5150 +3 5151 5094 5095 +3 5095 5006 5007 +3 5007 4914 4915 +3 4833 4834 4915 +3 4834 4720 4721 +3 4721 4576 4577 +3 4569 4568 4713 +3 4713 4712 4824 +3 4907 4824 4823 +3 4999 4907 4906 +3 4999 4998 5087 +3 5087 5086 5143 +3 5204 5143 5142 +3 5287 5204 5203 +3 5287 5286 5339 +3 5431 5339 5338 +3 5675 5584 5674 +3 5818 5819 5675 +3 5962 5963 5819 +3 6172 6171 6075 +3 5683 5682 5594 +3 5583 5584 5523 +3 5583 5523 5522 +3 5523 5431 5522 +3 5431 5430 5522 +3 5338 5430 5431 +3 5286 5338 5339 +3 5203 5286 5287 +3 5142 5203 5204 +3 5086 5142 5143 +3 4998 5086 5087 +3 4906 4998 4999 +3 4823 4906 4907 +3 4712 4823 4824 +3 4568 4712 4713 +3 4424 4568 4569 +3 4424 4569 4425 +3 4424 4425 4317 +3 4424 4317 4316 +3 4317 4246 4316 +3 4246 4245 4316 +3 4324 4245 4246 +3 4324 4246 4325 +3 4324 4325 4432 +3 4577 4432 4433 +3 4432 4325 4433 +3 4576 4432 4577 +3 4720 4576 4721 +3 4833 4720 4834 +3 4914 4833 4915 +3 5006 4914 5007 +3 5094 5006 5095 +3 5150 5094 5151 +3 5213 5150 5214 +3 5294 5213 5295 +3 5346 5294 5347 +3 5346 5347 5439 +3 5346 5439 5438 +3 5439 5531 5438 +3 5531 5530 5438 +3 5593 5530 5531 +3 5682 5593 5594 +3 5826 5682 5683 +3 5826 5683 5827 +3 5826 5827 5971 +3 5826 5971 5970 +3 5971 6075 5970 +3 6075 6074 5970 +3 6171 6074 6075 +3 6066 6171 6172 +3 5963 6066 6067 +3 6066 6172 6067 +3 5962 6066 5963 +3 5818 5962 5819 +3 5674 5818 5675 +3 5583 5674 5584 +3 2821 2842 2886 +3 2811 2834 2803 +3 2834 2833 2921 +3 2921 2920 2993 +3 2993 2992 3068 +3 3068 3067 3115 +3 3430 3490 3491 +3 3572 3573 3491 +3 3573 3705 3706 +3 3713 3712 3580 +3 3580 3579 3499 +3 2956 2887 2888 +3 2984 2956 3028 +3 2887 2956 2984 +3 3039 3028 3103 +3 2984 3028 3039 +3 3161 3103 3150 +3 3039 3103 3161 +3 3272 3161 3222 +3 3161 3150 3222 +3 3318 3161 3272 +3 3393 3318 3319 +3 3318 3272 3319 +3 3401 3318 3393 +3 3401 3393 3465 +3 3401 3465 3479 +3 3465 3499 3479 +3 3499 3498 3479 +3 3498 3478 3479 +3 3579 3498 3499 +3 3712 3579 3580 +3 3835 3712 3713 +3 3835 3713 3836 +3 3835 3836 3936 +3 3835 3936 3935 +3 3936 4028 3935 +3 4028 4027 3935 +3 3928 4027 4028 +3 3928 4028 3929 +3 3928 3929 3828 +3 3706 3828 3829 +3 3828 3929 3829 +3 3705 3828 3706 +3 3572 3705 3573 +3 3490 3572 3491 +3 3429 3490 3430 +3 3429 3430 3358 +3 3429 3358 3357 +3 3358 3283 3357 +3 3283 3282 3357 +3 3236 3282 3283 +3 3236 3283 3237 +3 3236 3237 3173 +3 3237 3174 3173 +3 3174 3115 3173 +3 3115 3114 3173 +3 3067 3114 3115 +3 2992 3067 3068 +3 2920 2992 2993 +3 2833 2920 2921 +3 2811 2833 2834 +3 2707 2811 2803 +3 2707 2803 2699 +3 2707 2699 2624 +3 2440 2439 2519 +3 2440 2519 2615 +3 2519 2624 2615 +3 2624 2699 2615 +3 2518 2624 2519 +3 904 933 991 +3 8308 8094 8301 +3 8307 7841 8315 +3 8315 7697 8323 +3 8349 8109 8357 +3 8383 8114 8380 +3 8324 7706 7611 +3 7706 8332 7850 +3 8350 8102 8340 +3 8203 8102 8350 +3 8203 8350 8110 +3 8350 8358 8110 +3 8358 8002 8110 +3 7858 8002 8358 +3 7858 8358 8368 +3 7858 8368 7714 +3 8368 8372 7714 +3 8372 7621 7714 +3 7718 7621 8372 +3 7718 8372 8376 +3 7718 8376 7862 +3 8376 8380 7862 +3 8380 8006 7862 +3 8114 8006 8380 +3 8207 8114 8383 +3 8207 8383 8113 +3 8383 8379 8113 +3 8379 8005 8113 +3 7861 8005 8379 +3 7861 8379 8375 +3 7861 8375 7717 +3 8375 8371 7717 +3 8371 7620 7717 +3 7713 7620 8371 +3 7713 8371 8367 +3 7713 8367 7857 +3 8367 8357 7857 +3 8357 8001 7857 +3 8109 8001 8357 +3 8202 8109 8349 +3 8202 8349 8101 +3 8349 8339 8101 +3 8339 7993 8101 +3 7849 7993 8339 +3 7849 8339 8331 +3 7849 8331 7705 +3 8331 8323 7705 +3 8323 7610 7705 +3 7697 7610 8323 +3 7841 7697 8315 +3 7985 7841 8307 +3 7985 8307 8093 +3 8307 8301 8093 +3 8301 8195 8093 +3 8094 8195 8301 +3 7986 8094 8308 +3 7842 8308 8316 +3 7986 8308 7842 +3 7698 8316 8324 +3 7842 8316 7698 +3 7850 8340 7994 +3 8340 8102 7994 +3 8332 8340 7850 +3 8324 8332 7706 +3 7698 8324 7611 +3 50 647 42 +3 42 750 34 +3 18 663 10 +3 4 435 11 +3 27 920 35 +3 648 426 51 +3 648 51 43 +3 648 43 751 +3 43 35 751 +3 35 887 751 +3 920 887 35 +3 800 920 27 +3 800 27 19 +3 800 19 664 +3 19 11 664 +3 11 531 664 +3 435 531 11 +3 363 435 4 +3 363 4 434 +3 4 10 434 +3 10 530 434 +3 663 530 10 +3 799 663 18 +3 799 18 26 +3 799 26 919 +3 26 34 919 +3 34 886 919 +3 750 886 34 +3 647 750 42 +3 425 647 50 +3 1963 2615 1857 +3 1857 2699 1725 +3 1725 2803 1635 +3 1635 2834 1732 +3 1732 2738 1865 +3 1998 1865 2634 +3 2094 1998 2529 +3 2094 2446 2199 +3 2199 2388 2095 +3 2447 1999 2095 +3 2182 1964 2441 +3 1964 2616 2441 +3 2700 2616 1964 +3 2700 1964 1858 +3 2700 1858 2804 +3 1858 1726 2804 +3 1726 2835 2804 +3 1733 2835 1636 +3 2835 1726 1636 +3 2739 2835 1733 +3 2739 1733 1866 +3 2739 1866 2635 +3 1866 1999 2635 +3 1999 2530 2635 +3 2447 2530 1999 +3 2388 2447 2095 +3 2446 2388 2199 +3 2529 2446 2094 +3 2634 2529 1998 +3 2738 2634 1865 +3 2834 2738 1732 +3 2803 2834 1635 +3 2699 2803 1725 +3 2615 2699 1857 +3 2440 2615 1963 +3 2440 1963 2181 +3 3492 4825 3574 +3 3574 4714 3707 +3 3707 4570 3830 +3 3930 3830 4426 +3 3937 4434 3837 +3 3837 4578 3714 +3 3714 4722 3581 +3 4834 3499 3584 +3 3499 4721 3580 +3 3580 4577 3713 +3 4561 3699 3566 +3 3567 3700 4562 +3 3567 4706 3492 +3 4713 4824 3491 +3 4569 4713 3573 +3 4569 3706 4425 +3 3713 4433 3836 +3 4433 3936 3836 +3 4577 4433 3713 +3 4721 4577 3580 +3 4834 4721 3499 +3 4729 4834 3584 +3 4729 3584 3717 +3 4729 3717 4585 +3 3717 4441 4585 +3 3940 4441 3840 +3 4441 3717 3840 +3 4333 4441 3940 +3 4333 3940 4253 +3 3941 4253 4033 +3 4253 3940 4033 +3 4334 4253 3941 +3 4334 3941 4442 +3 3941 3841 4442 +3 3841 4586 4442 +3 3585 4586 3718 +3 4586 3841 3718 +3 4730 4586 3585 +3 4730 3585 4835 +3 3581 4835 3500 +3 4835 3585 3500 +3 4722 4835 3581 +3 4578 4722 3714 +3 4434 4578 3837 +3 4326 4434 3937 +3 4326 3937 4247 +3 3937 4029 4247 +3 4029 3930 4247 +3 3930 4318 4247 +3 4426 4318 3930 +3 4570 4426 3830 +3 4714 4570 3707 +3 4825 4714 3574 +3 4706 4825 3492 +3 4562 4706 3567 +3 4418 4562 3700 +3 4418 3700 3823 +3 4418 3823 4310 +3 3823 3923 4310 +3 3923 4023 4310 +3 4023 4239 4310 +3 4309 4239 4023 +3 4309 4023 3922 +3 4309 3922 4417 +3 3922 3822 4417 +3 3822 3699 4417 +3 3699 4561 4417 +3 4705 3566 3491 +3 4561 3566 4705 +3 4246 3936 4325 +3 3936 4433 4325 +3 4028 3936 4246 +3 4028 4246 4317 +3 4028 4317 3929 +3 4317 4425 3929 +3 4425 3829 3929 +3 3706 3829 4425 +3 3573 3706 4569 +3 3491 3573 4713 +3 4705 3491 4824 +3 5820 6572 5964 +3 5964 6428 6068 +3 5811 6563 5955 +3 6059 6239 6165 +3 6165 6308 6060 +3 6060 6420 5956 +3 5956 6564 5812 +3 5668 5812 6704 +3 6571 5819 6427 +3 5963 6315 6427 +3 6315 6067 6246 +3 6246 6172 6323 +3 6323 6075 6435 +3 5971 6579 6435 +3 6579 5827 6719 +3 6719 5683 6834 +3 6834 5594 6727 +3 6331 6083 6253 +3 6332 6253 6179 +3 6332 6084 6444 +3 6588 6444 5980 +3 5836 6728 6588 +3 6835 6728 5692 +3 6436 6580 5972 +3 6436 6076 6324 +3 6068 6316 6173 +3 6428 6316 6068 +3 6572 6428 5964 +3 6712 6572 5820 +3 6712 5820 5676 +3 6712 5676 6825 +3 5668 6825 5585 +3 6825 5676 5585 +3 6704 6825 5668 +3 6564 6704 5812 +3 6420 6564 5956 +3 6308 6420 6060 +3 6239 6308 6165 +3 6307 6239 6059 +3 6307 6059 5955 +3 6307 5955 6419 +3 5955 6563 6419 +3 6703 5811 5667 +3 6563 5811 6703 +3 6324 6173 6247 +3 6173 6316 6247 +3 6076 6173 6324 +3 5972 6076 6436 +3 5828 5972 6580 +3 5828 6580 6720 +3 5828 6720 5684 +3 6720 6835 5684 +3 6835 5595 5684 +3 5692 5595 6835 +3 5836 5692 6728 +3 5980 5836 6588 +3 6084 5980 6444 +3 6179 6084 6332 +3 6083 6179 6253 +3 5979 6083 6331 +3 5979 6331 6443 +3 5979 6443 6587 +3 5979 6587 5835 +3 6587 6727 5835 +3 6727 5691 5835 +3 5594 5691 6727 +3 5683 5594 6834 +3 5827 5683 6719 +3 5971 5827 6579 +3 6075 5971 6435 +3 6172 6075 6323 +3 6067 6172 6246 +3 5963 6067 6315 +3 5819 5963 6427 +3 5675 5819 6571 +3 5675 6571 6711 +3 5675 6711 5584 +3 6711 6824 5584 +3 6824 5667 5584 +3 6703 5667 6824 +3 6801 6661 6693 +3 7935 7791 7827 +3 6302 6405 6299 +3 6302 6299 6406 +3 6302 6406 6550 +3 6662 6550 6518 +3 6550 6406 6518 +3 6694 6550 6662 +3 6694 6662 6802 +3 6694 6802 6894 +3 6954 6894 6887 +3 6894 6802 6887 +3 6986 6894 6954 +3 6986 6954 7048 +3 6986 7048 7084 +3 7198 7084 7146 +3 7084 7048 7146 +3 7290 7084 7198 +3 7290 7198 7283 +3 7290 7283 7348 +3 7290 7348 7440 +3 7496 7440 7404 +3 7440 7348 7404 +3 7536 7440 7496 +3 7536 7496 7588 +3 7536 7588 7680 +3 7792 7680 7673 +3 7680 7588 7673 +3 7828 7680 7792 +3 7828 7792 7936 +3 7828 7936 7980 +3 8188 7980 8080 +3 7980 7936 8080 +3 8256 7980 8188 +3 8256 8188 8253 +3 8256 8253 8187 +3 8256 8187 7979 +3 7935 7979 8079 +3 7979 8187 8079 +3 7827 7979 7935 +3 7679 7827 7791 +3 7679 7791 7672 +3 7679 7672 7587 +3 7679 7587 7535 +3 7587 7495 7535 +3 7495 7439 7535 +3 7347 7439 7403 +3 7439 7495 7403 +3 7289 7439 7347 +3 7289 7347 7282 +3 7289 7282 7197 +3 7289 7197 7083 +3 7047 7083 7145 +3 7083 7197 7145 +3 6985 7083 7047 +3 6985 7047 6953 +3 6985 6953 6893 +3 6801 6893 6886 +3 6893 6953 6886 +3 6693 6893 6801 +3 6549 6693 6661 +3 6405 6549 6517 +3 6549 6661 6517 +3 6302 6549 6405 +3 7672 7586 7587 +3 7494 7495 7587 +3 7403 7495 7402 +3 7403 7346 7347 +3 7046 6953 7047 +3 6953 6952 6886 +3 6886 6885 6795 +3 6655 6795 6794 +3 6655 6654 6511 +3 6399 6511 6510 +3 6399 6398 6294 +3 6505 6648 6649 +3 6788 6789 6649 +3 6789 6877 6878 +3 6878 6946 6947 +3 6947 7040 7041 +3 7041 7138 7139 +3 7341 7274 7273 +3 7341 7340 7397 +3 7489 7397 7396 +3 7488 7581 7489 +3 7580 7664 7581 +3 8067 8066 8175 +3 8175 8174 8248 +3 8073 7928 7929 +3 7785 7929 7784 +3 7785 7671 7672 +3 7664 7663 7779 +3 7580 7663 7664 +3 7488 7580 7581 +3 7396 7488 7489 +3 7340 7396 7397 +3 7273 7340 7341 +3 7190 7273 7274 +3 7139 7190 7191 +3 7190 7274 7191 +3 7138 7190 7139 +3 7040 7138 7041 +3 6946 7040 6947 +3 6877 6946 6878 +3 6788 6877 6789 +3 6648 6788 6649 +3 6504 6648 6505 +3 6504 6505 6393 +3 6504 6393 6392 +3 6393 6294 6392 +3 6294 6293 6392 +3 6398 6293 6294 +3 6510 6398 6399 +3 6654 6510 6511 +3 6794 6654 6655 +3 6885 6794 6795 +3 6952 6885 6886 +3 7046 6952 6953 +3 7144 7046 7047 +3 7144 7047 7145 +3 7144 7145 7196 +3 7145 7197 7196 +3 7197 7281 7196 +3 7347 7281 7282 +3 7281 7197 7282 +3 7346 7281 7347 +3 7402 7346 7403 +3 7494 7402 7495 +3 7586 7494 7587 +3 7671 7586 7672 +3 7784 7671 7785 +3 7928 7784 7929 +3 8072 7928 8073 +3 8072 8073 8181 +3 8072 8181 8180 +3 8181 8248 8180 +3 8248 8247 8180 +3 8174 8247 8248 +3 8066 8174 8175 +3 7922 8066 8067 +3 7922 8067 7923 +3 7922 7923 7778 +3 7923 7779 7778 +3 7779 7663 7778 +3 5278 5334 5422 +3 6230 6157 5945 +3 5277 5189 5081 +3 4551 4515 4407 +3 4659 4515 4551 +3 4659 4551 4699 +3 4659 4699 4803 +3 4699 4897 4803 +3 4897 4890 4803 +3 4953 4890 4897 +3 4953 4897 4989 +3 4953 4989 5045 +3 4989 5081 5045 +3 5081 5133 5045 +3 5189 5133 5081 +3 5270 5189 5277 +3 5270 5277 5333 +3 5277 5421 5333 +3 5421 5385 5333 +3 5477 5385 5421 +3 5477 5421 5513 +3 5477 5513 5569 +3 5513 5657 5569 +3 5657 5650 5569 +3 5765 5650 5657 +3 5765 5657 5801 +3 5765 5801 5909 +3 5801 5945 5909 +3 5945 6053 5909 +3 6157 6053 5945 +3 6227 6157 6230 +3 6227 6230 6158 +3 6230 5946 6158 +3 5946 6054 6158 +3 5910 6054 5946 +3 5910 5946 5802 +3 5910 5802 5766 +3 5802 5658 5766 +3 5658 5651 5766 +3 5570 5651 5658 +3 5570 5658 5514 +3 5570 5514 5478 +3 5514 5422 5478 +3 5422 5386 5478 +3 5334 5386 5422 +3 5271 5334 5278 +3 5271 5278 5190 +3 5278 5082 5190 +3 5082 5134 5190 +3 5046 5134 5082 +3 5046 5082 4990 +3 5046 4990 4954 +3 4990 4898 4954 +3 4898 4891 4954 +3 4804 4891 4898 +3 4804 4898 4700 +3 4804 4700 4660 +3 4700 4552 4660 +3 4552 4516 4660 +3 4408 4516 4552 +3 4408 4552 4304 +3 4408 4304 4301 +3 4304 4407 4301 +3 4551 4407 4304 +3 5650 5568 5569 +3 5569 5476 5477 +3 5385 5477 5384 +3 5333 5385 5332 +3 5269 5270 5333 +3 5189 5270 5188 +3 4953 4952 4890 +3 4797 4890 4889 +3 4796 4653 4797 +3 4652 4509 4653 +3 4509 4508 4401 +3 4401 4400 4296 +3 4296 4295 4395 +3 6046 6047 6151 +3 6047 5902 5903 +3 5758 5759 5903 +3 5759 5649 5650 +3 5471 5378 5470 +3 5378 5379 5326 +3 5326 5327 5261 +3 5126 5039 5038 +3 5038 4947 4946 +3 4946 4882 4881 +3 4881 4791 4790 +3 4790 4647 4646 +3 4395 4394 4503 +3 4295 4394 4395 +3 4400 4295 4296 +3 4508 4400 4401 +3 4652 4508 4509 +3 4796 4652 4653 +3 4889 4796 4797 +3 4952 4889 4890 +3 5044 4952 4953 +3 5044 4953 5045 +3 5044 5045 5132 +3 5189 5132 5133 +3 5132 5045 5133 +3 5188 5132 5189 +3 5269 5188 5270 +3 5332 5269 5333 +3 5384 5332 5385 +3 5476 5384 5477 +3 5568 5476 5569 +3 5649 5568 5650 +3 5758 5649 5759 +3 5902 5758 5903 +3 6046 5902 6047 +3 6150 6046 6151 +3 6150 6151 6222 +3 6150 6222 6221 +3 6144 6222 6145 +3 6221 6222 6144 +3 6040 6145 6041 +3 6144 6145 6040 +3 5896 6041 5897 +3 6040 6041 5896 +3 5752 5897 5753 +3 5896 5897 5752 +3 4646 4503 4502 +3 4503 4394 4502 +3 4647 4503 4646 +3 4791 4647 4790 +3 4882 4791 4881 +3 4947 4882 4946 +3 5039 4947 5038 +3 5127 5039 5126 +3 5127 5126 5182 +3 5127 5182 5183 +3 5182 5261 5183 +3 5261 5262 5183 +3 5327 5262 5261 +3 5379 5327 5326 +3 5471 5379 5378 +3 5563 5471 5470 +3 5563 5470 5562 +3 5563 5562 5642 +3 5562 5641 5642 +3 5641 5753 5642 +3 5752 5753 5641 +3 3534 3535 3457 +3 3457 3458 3385 +3 3386 3310 3385 +3 3310 3311 3264 +3 3264 3265 3207 +3 3207 3208 3142 +3 3142 3143 3095 +3 3095 3096 3020 +3 2871 2791 2790 +3 2790 2687 2686 +3 2686 2583 2582 +3 2816 2879 2797 +3 3027 3038 3102 +3 3102 3110 3149 +3 3160 3215 3149 +3 3271 3215 3229 +3 3271 3279 3317 +3 3317 3349 3392 +3 3542 3651 3650 +3 3650 3784 3783 +3 3906 3783 3907 +3 3906 4007 4006 +3 3899 3900 3776 +3 3776 3777 3643 +3 3643 3644 3534 +3 2582 2500 2499 +3 2583 2500 2582 +3 2687 2583 2686 +3 2791 2687 2790 +3 2872 2791 2871 +3 2872 2871 2948 +3 2872 2948 2949 +3 2948 3020 2949 +3 3020 3021 2949 +3 3096 3021 3020 +3 3143 3096 3095 +3 3208 3143 3142 +3 3265 3208 3207 +3 3311 3265 3264 +3 3386 3311 3310 +3 3458 3386 3385 +3 3535 3458 3457 +3 3644 3535 3534 +3 3777 3644 3643 +3 3900 3777 3776 +3 4000 3900 3899 +3 4000 3899 3999 +3 4000 3999 4071 +3 4006 4071 4070 +3 4071 3999 4070 +3 4007 4071 4006 +3 3907 4007 3906 +3 3784 3907 3783 +3 3651 3784 3650 +3 3543 3651 3542 +3 3543 3542 3464 +3 3543 3464 3425 +3 3464 3392 3425 +3 3392 3400 3425 +3 3349 3400 3392 +3 3279 3349 3317 +3 3229 3279 3271 +3 3160 3229 3215 +3 3110 3160 3149 +3 3038 3110 3102 +3 2983 3038 3027 +3 2983 3027 2955 +3 2983 2955 2913 +3 2955 2879 2913 +3 2879 2816 2913 +3 2732 2797 2693 +3 2816 2797 2732 +3 2629 2693 2589 +3 2732 2693 2629 +3 2524 2589 2507 +3 2629 2589 2524 +3 2423 2500 2424 +3 2499 2500 2423 +3 2499 2423 2422 +3 2423 2507 2422 +3 2524 2507 2423 +3 1332 1385 1468 +3 2250 2175 1991 +3 1331 1254 1162 +3 642 612 517 +3 745 612 642 +3 745 642 787 +3 745 787 881 +3 787 986 881 +3 986 979 881 +3 1048 979 986 +3 1048 986 1080 +3 1048 1080 1128 +3 1080 1162 1128 +3 1162 1206 1128 +3 1254 1206 1162 +3 1324 1254 1331 +3 1324 1331 1384 +3 1331 1467 1384 +3 1467 1436 1384 +3 1518 1436 1467 +3 1518 1467 1553 +3 1518 1553 1602 +3 1553 1703 1602 +3 1703 1695 1602 +3 1812 1695 1703 +3 1812 1703 1844 +3 1812 1844 1945 +3 1844 1991 1945 +3 1991 2078 1945 +3 2175 2078 1991 +3 2247 2175 2250 +3 2247 2250 2176 +3 2250 1992 2176 +3 1992 2079 2176 +3 1946 2079 1992 +3 1946 1992 1845 +3 1946 1845 1813 +3 1845 1704 1813 +3 1704 1696 1813 +3 1603 1696 1704 +3 1603 1704 1554 +3 1603 1554 1519 +3 1554 1468 1519 +3 1468 1437 1519 +3 1385 1437 1468 +3 1325 1385 1332 +3 1325 1332 1255 +3 1332 1163 1255 +3 1163 1207 1255 +3 1129 1207 1163 +3 1129 1163 1081 +3 1129 1081 1049 +3 1081 987 1049 +3 987 980 1049 +3 882 980 987 +3 882 987 788 +3 882 788 746 +3 788 643 746 +3 643 613 746 +3 518 613 643 +3 518 643 417 +3 518 417 414 +3 417 517 414 +3 642 517 417 +3 511 525 428 +3 525 606 657 +3 657 739 792 +3 792 875 899 +3 899 979 1005 +3 1005 1048 1084 +3 1084 1128 1164 +3 1523 1602 1608 +3 1608 1695 1715 +3 1715 1718 1848 +3 1848 1850 1950 +3 733 732 869 +3 868 971 869 +3 1800 1932 1933 +3 1933 2065 2066 +3 2241 2242 2162 +3 2066 2162 2163 +3 2162 2242 2163 +3 2065 2162 2066 +3 1932 2065 1933 +3 1799 1932 1800 +3 1799 1800 1686 +3 1799 1686 1685 +3 1686 1596 1685 +3 1596 1595 1685 +3 1511 1595 1596 +3 1511 1596 1512 +3 1511 1512 1429 +3 1378 1429 1430 +3 1429 1512 1430 +3 1377 1429 1378 +3 1377 1378 1316 +3 1377 1316 1315 +3 1316 1248 1315 +3 1248 1247 1315 +3 1199 1247 1248 +3 1122 1199 1200 +3 1199 1248 1200 +3 1121 1199 1122 +3 1121 1122 1042 +3 1121 1042 1041 +3 1042 971 1041 +3 971 970 1041 +3 868 970 971 +3 732 868 869 +3 599 732 733 +3 599 733 600 +3 599 600 504 +3 1950 1954 2086 +3 1850 1954 1950 +3 1718 1850 1848 +3 1695 1718 1715 +3 1602 1695 1608 +3 1518 1602 1523 +3 1518 1523 1474 +3 1518 1474 1436 +3 1474 1386 1436 +3 1386 1384 1436 +3 1324 1384 1386 +3 1324 1386 1256 +3 1324 1256 1254 +3 1256 1164 1254 +3 1164 1206 1254 +3 1128 1206 1164 +3 1048 1128 1084 +3 979 1048 1005 +3 875 979 899 +3 739 875 792 +3 606 739 657 +3 511 606 525 +3 409 511 428 +3 409 428 408 +3 409 408 505 +3 408 504 505 +3 504 600 505 +3 8560 7917 8566 +3 8566 7773 8572 +3 8590 8181 8596 +3 8624 8188 8621 +3 7665 8573 7780 +3 8579 7924 7780 +3 8591 8176 8585 +3 8249 8176 8591 +3 8249 8591 8182 +3 8591 8597 8182 +3 8597 8074 8182 +3 7930 8074 8597 +3 7930 8597 8603 +3 7930 8603 7786 +3 8603 8609 7786 +3 8609 7673 7786 +3 7792 7673 8609 +3 7792 8609 8615 +3 7792 8615 7936 +3 8615 8621 7936 +3 8621 8080 7936 +3 8188 8080 8621 +3 8253 8188 8624 +3 8253 8624 8187 +3 8624 8620 8187 +3 8620 8079 8187 +3 7935 8079 8620 +3 7935 8620 8614 +3 7935 8614 7791 +3 8614 8608 7791 +3 8608 7672 7791 +3 7785 7672 8608 +3 7785 8608 8602 +3 7785 8602 7929 +3 8602 8596 7929 +3 8596 8073 7929 +3 8181 8073 8596 +3 8248 8181 8590 +3 8248 8590 8175 +3 8590 8584 8175 +3 8584 8067 8175 +3 7923 8067 8584 +3 7923 8584 8578 +3 7923 8578 7779 +3 8578 8572 7779 +3 8572 7664 7779 +3 7773 7664 8572 +3 7917 7773 8566 +3 8061 7917 8560 +3 8061 8560 8169 +3 8560 8555 8169 +3 8555 8242 8169 +3 8170 8242 8555 +3 8170 8555 8561 +3 8170 8561 8062 +3 7918 8561 8567 +3 8062 8561 7918 +3 7774 8567 8573 +3 7918 8567 7774 +3 7924 8585 8068 +3 8585 8176 8068 +3 8579 8585 7924 +3 8573 8579 7780 +3 7774 8573 7665 +3 343 517 338 +3 303 505 294 +3 255 498 263 +3 295 601 506 +3 734 601 295 +3 734 295 287 +3 734 287 870 +3 287 279 870 +3 279 972 870 +3 862 972 279 +3 862 279 271 +3 862 271 726 +3 271 263 726 +3 263 593 726 +3 498 593 263 +3 400 498 255 +3 400 255 497 +3 255 262 497 +3 262 592 497 +3 725 592 262 +3 725 262 270 +3 725 270 861 +3 270 278 861 +3 278 971 861 +3 869 971 278 +3 869 278 286 +3 869 286 733 +3 286 294 733 +3 294 600 733 +3 505 600 294 +3 409 505 303 +3 409 303 511 +3 303 310 511 +3 310 606 511 +3 739 606 310 +3 739 310 317 +3 739 317 875 +3 317 324 875 +3 324 979 875 +3 881 979 324 +3 881 324 331 +3 881 331 745 +3 331 338 745 +3 338 612 745 +3 517 612 338 +3 414 517 343 +3 414 343 518 +3 343 339 518 +3 339 613 518 +3 746 613 339 +3 746 339 332 +3 746 332 882 +3 332 325 882 +3 325 980 882 +3 876 980 325 +3 876 325 318 +3 876 318 740 +3 318 311 740 +3 311 607 740 +3 512 607 311 +3 512 311 304 +3 512 304 410 +3 304 506 410 +3 295 506 304 +3 2425 2381 2501 +3 2584 1934 2688 +3 2688 1801 2792 +3 2494 2234 2417 +3 2417 2155 2493 +3 2058 2576 2493 +3 2576 1925 2680 +3 2680 1792 2784 +3 2872 2784 1686 +3 2872 1800 2791 +3 2791 1933 2687 +3 2500 2163 2424 +3 2163 2242 2424 +3 2066 2163 2500 +3 2687 2066 2583 +3 2066 2500 2583 +3 1933 2066 2687 +3 1800 1933 2791 +3 1686 1800 2872 +3 1792 1686 2784 +3 1925 1792 2680 +3 2058 1925 2576 +3 2155 2058 2493 +3 2234 2155 2417 +3 2156 2234 2494 +3 2156 2494 2577 +3 2156 2577 2059 +3 2577 2681 2059 +3 2681 1926 2059 +3 1793 1926 2681 +3 1793 2681 2785 +3 1793 2785 1687 +3 1696 2375 1813 +3 1812 1945 2292 +3 1695 1812 2279 +3 1695 2271 1718 +3 1718 2264 1850 +3 1850 2252 1954 +3 2252 2086 1954 +3 2264 2252 1850 +3 2271 2264 1718 +3 2279 2271 1695 +3 2292 2279 1812 +3 2345 2292 1945 +3 2345 1945 2078 +3 2345 2078 2356 +3 2247 2356 2175 +3 2356 2078 2175 +3 2361 2356 2247 +3 2079 2361 2176 +3 2361 2247 2176 +3 2369 2361 2079 +3 2369 2079 1946 +3 2369 1946 2374 +3 1946 1813 2374 +3 1813 2375 2374 +3 2376 1696 1807 +3 2375 1696 2376 +3 2377 1807 1940 +3 2376 1807 2377 +3 2378 1940 2073 +3 2377 1940 2378 +3 2379 2073 2170 +3 2378 2073 2379 +3 2380 2170 2243 +3 2379 2170 2380 +3 2792 1687 2873 +3 1687 2785 2873 +3 1801 1687 2792 +3 1934 1801 2688 +3 2067 1934 2584 +3 2067 2584 2501 +3 2067 2501 2164 +3 2501 2381 2164 +3 2381 2243 2164 +3 2380 2243 2381 +3 4142 4001 4396 +3 4882 3644 4791 +3 4791 3777 4647 +3 4647 3900 4503 +3 4653 3651 4797 +3 4407 4013 4301 +3 4015 4408 4301 +3 3914 4516 4408 +3 4516 4088 4660 +3 4660 4089 4804 +3 4804 4090 4891 +3 4891 4091 4798 +3 4798 4139 4654 +3 4140 4510 4654 +3 4510 4141 4402 +3 4883 4792 3645 +3 4883 3536 4786 +3 3638 4642 4786 +3 4642 3771 4498 +3 4498 3894 4390 +3 4785 3535 4882 +3 4402 4142 4297 +3 4142 4396 4297 +3 4141 4142 4402 +3 4140 4141 4510 +3 4139 4140 4654 +3 4091 4139 4798 +3 4090 4091 4891 +3 4089 4090 4804 +3 4088 4089 4660 +3 3914 4088 4516 +3 4015 3914 4408 +3 4013 4015 4301 +3 3913 4013 4407 +3 3913 4407 4515 +3 3913 4515 3790 +3 4515 4659 3790 +3 4659 3689 3790 +3 3661 3689 4659 +3 3661 4659 4803 +3 3661 4803 3543 +3 4797 3543 4890 +3 3543 4803 4890 +3 3651 3543 4797 +3 3784 3651 4653 +3 3784 4653 4509 +3 3784 4509 3907 +3 4509 4401 3907 +3 4401 4007 3907 +3 4071 4007 4401 +3 4071 4401 4296 +3 4071 4296 4000 +3 4503 4000 4395 +3 4000 4296 4395 +3 3900 4000 4503 +3 3777 3900 4647 +3 3644 3777 4791 +3 3535 3644 4882 +3 3637 3535 4785 +3 3637 4785 4641 +3 3637 4641 3770 +3 4641 4497 3770 +3 4497 3893 3770 +3 3993 3893 4497 +3 3993 4497 4389 +3 3993 4389 4065 +3 4389 4290 4065 +3 4290 4390 4065 +3 4390 3994 4065 +3 3894 3994 4390 +3 3771 3894 4498 +3 3638 3771 4642 +3 3536 3638 4786 +3 3645 3536 4883 +3 3778 3645 4792 +3 3778 4792 4648 +3 3778 4648 3901 +3 4396 3901 4504 +3 3901 4648 4504 +3 4001 3901 4396 +3 4072 4001 4142 +3 5643 6790 5754 +3 6650 5898 5754 +3 5898 6506 6042 +3 6042 6394 6146 +3 6048 6512 5904 +3 6656 5760 5904 +3 5760 6796 5651 +3 5651 6887 5766 +3 6158 6406 6227 +3 6227 6299 6157 +3 6157 6405 6053 +3 6053 6517 5909 +3 6661 5765 5909 +3 5903 6655 6047 +3 6047 6511 6151 +3 6151 6399 6222 +3 6222 6294 6145 +3 5891 6499 6035 +3 6216 6388 6140 +3 6140 6500 6036 +3 6036 6644 5892 +3 6145 6393 6041 +3 6294 6393 6145 +3 6399 6294 6222 +3 6511 6399 6151 +3 6655 6511 6047 +3 6795 6655 5903 +3 6795 5903 5759 +3 6795 5759 5650 +3 6795 5650 6886 +3 5650 5765 6886 +3 5765 6801 6886 +3 6661 6801 5765 +3 6517 6661 5909 +3 6405 6517 6053 +3 6299 6405 6157 +3 6406 6299 6227 +3 6518 6406 6158 +3 6518 6158 6054 +3 6518 6054 6662 +3 6054 5910 6662 +3 5910 5766 6662 +3 5766 6802 6662 +3 6887 6802 5766 +3 6796 6887 5651 +3 6656 6796 5760 +3 6512 6656 5904 +3 6400 6512 6048 +3 6400 6048 6152 +3 6400 6152 6295 +3 6146 6295 6223 +3 6295 6152 6223 +3 6394 6295 6146 +3 6506 6394 6042 +3 6650 6506 5898 +3 6790 6650 5754 +3 6879 6790 5643 +3 6879 5643 6784 +3 5892 6784 5748 +3 6784 5643 5748 +3 6644 6784 5892 +3 6500 6644 6036 +3 6388 6500 6140 +3 6288 6388 6216 +3 6288 6216 6139 +3 6288 6139 6387 +3 6139 6035 6387 +3 6035 6499 6387 +3 6643 5891 5747 +3 6499 5891 6643 +3 6783 5747 5642 +3 6643 5747 6783 +3 6649 6041 6505 +3 6041 6393 6505 +3 5897 6041 6649 +3 5897 6649 5753 +3 6649 6789 5753 +3 6789 6878 5753 +3 6878 5642 5753 +3 6783 5642 6878 +3 7581 7575 7489 +3 7483 7397 7489 +3 7397 7391 7341 +3 7191 7133 7139 +3 7139 7035 7041 +3 7041 6941 6947 +3 6637 6499 6643 +3 6499 6493 6387 +3 6387 6381 6288 +3 6388 6288 6284 +3 6388 6382 6500 +3 6494 6644 6500 +3 7768 7774 7665 +3 7917 7767 7773 +3 7036 6948 6942 +3 6942 6879 6869 +3 6644 6638 6784 +3 6494 6638 6644 +3 6382 6494 6500 +3 6284 6382 6388 +3 6381 6284 6288 +3 6493 6381 6387 +3 6637 6493 6499 +3 6777 6637 6643 +3 6777 6643 6783 +3 6777 6783 6868 +3 6947 6868 6878 +3 6868 6783 6878 +3 6941 6868 6947 +3 7035 6941 7041 +3 7133 7035 7139 +3 7185 7133 7191 +3 7185 7191 7264 +3 7191 7274 7264 +3 7274 7341 7264 +3 7341 7335 7264 +3 7391 7335 7341 +3 7483 7391 7397 +3 7575 7483 7489 +3 7654 7575 7581 +3 7773 7654 7664 +3 7654 7581 7664 +3 7767 7654 7773 +3 7911 7767 7917 +3 7911 7917 8061 +3 7911 8061 8055 +3 8061 8169 8055 +3 8169 8163 8055 +3 8238 8163 8169 +3 8238 8169 8242 +3 8238 8242 8164 +3 8062 8164 8170 +3 8164 8242 8170 +3 8056 8164 8062 +3 8056 8062 7918 +3 8056 7918 7912 +3 7918 7774 7912 +3 7774 7768 7912 +3 6869 6784 6778 +3 6784 6638 6778 +3 6879 6784 6869 +3 6948 6879 6942 +3 7042 6948 7036 +3 7042 7036 7134 +3 7042 7134 7140 +3 7134 7186 7140 +3 7186 7192 7140 +3 7275 7192 7186 +3 7275 7186 7265 +3 7275 7265 7336 +3 7275 7336 7342 +3 7336 7392 7342 +3 7392 7398 7342 +3 7490 7398 7392 +3 7490 7392 7484 +3 7490 7484 7582 +3 7484 7576 7582 +3 7576 7655 7582 +3 7655 7665 7582 +3 7768 7665 7655 +3 7574 7575 7654 +3 7575 7482 7483 +3 7391 7483 7390 +3 7334 7335 7391 +3 7263 7264 7335 +3 7035 7034 6941 +3 6941 6940 6868 +3 6868 6867 6769 +3 6769 6768 6629 +3 6628 6485 6629 +3 6485 6484 6373 +3 6373 6372 6278 +3 8038 8147 8039 +3 8232 8154 8155 +3 8046 8047 8155 +3 8047 7902 7903 +3 7759 7903 7758 +3 7759 7653 7654 +3 7475 7382 7474 +3 7382 7383 7326 +3 7326 7327 7253 +3 7253 7254 7176 +3 7026 6933 6932 +3 6932 6858 6857 +3 6760 6857 6761 +3 6760 6621 6620 +3 6476 6620 6477 +3 6278 6277 6365 +3 6372 6277 6278 +3 6484 6372 6373 +3 6628 6484 6485 +3 6768 6628 6629 +3 6867 6768 6769 +3 6940 6867 6868 +3 7034 6940 6941 +3 7132 7034 7035 +3 7132 7035 7133 +3 7132 7133 7184 +3 7264 7184 7185 +3 7184 7133 7185 +3 7263 7184 7264 +3 7334 7263 7335 +3 7390 7334 7391 +3 7482 7390 7483 +3 7574 7482 7575 +3 7653 7574 7654 +3 7758 7653 7759 +3 7902 7758 7903 +3 8046 7902 8047 +3 8154 8046 8155 +3 8231 8154 8232 +3 8231 8232 8146 +3 8232 8147 8146 +3 8147 8038 8146 +3 7894 8039 7895 +3 8038 8039 7894 +3 7750 7895 7751 +3 7894 7895 7750 +3 6476 6365 6364 +3 6365 6277 6364 +3 6477 6365 6476 +3 6621 6477 6620 +3 6761 6621 6760 +3 6858 6761 6857 +3 6933 6858 6932 +3 7027 6933 7026 +3 7027 7026 7124 +3 7027 7124 7125 +3 7124 7176 7125 +3 7176 7177 7125 +3 7254 7177 7176 +3 7327 7254 7253 +3 7383 7327 7326 +3 7475 7383 7382 +3 7567 7475 7474 +3 7567 7474 7566 +3 7567 7566 7644 +3 7566 7643 7644 +3 7643 7751 7644 +3 7750 7751 7643 +3 5471 5465 5379 +3 5379 5373 5327 +3 5327 5321 5262 +3 5262 5252 5183 +3 5183 5177 5127 +3 4641 4635 4497 +3 4497 4491 4389 +3 4389 4383 4290 +3 4290 4286 4390 +3 4390 4384 4498 +3 4498 4492 4642 +3 4642 4636 4786 +3 5128 5040 5034 +3 5128 5122 5184 +3 5891 5741 5747 +3 5322 5380 5328 +3 5322 5328 5253 +3 5328 5263 5253 +3 5263 5184 5253 +3 5184 5178 5253 +3 5122 5178 5184 +3 5034 5122 5128 +3 4942 5034 5040 +3 4942 5040 4948 +3 4942 4948 4883 +3 4942 4883 4873 +3 4883 4786 4873 +3 4786 4780 4873 +3 4636 4780 4786 +3 4492 4636 4642 +3 4384 4492 4498 +3 4286 4384 4390 +3 4383 4286 4290 +3 4491 4383 4389 +3 4635 4491 4497 +3 4779 4635 4641 +3 4779 4641 4785 +3 4779 4785 4872 +3 4947 4872 4882 +3 4872 4785 4882 +3 4941 4872 4947 +3 4941 4947 5039 +3 4941 5039 5033 +3 5039 5127 5033 +3 5127 5121 5033 +3 5177 5121 5127 +3 5252 5177 5183 +3 5321 5252 5262 +3 5373 5321 5327 +3 5465 5373 5379 +3 5557 5465 5471 +3 5557 5471 5563 +3 5557 5563 5632 +3 5747 5632 5642 +3 5632 5563 5642 +3 5741 5632 5747 +3 5885 5741 5891 +3 5885 5891 6035 +3 5885 6035 6029 +3 6035 6139 6029 +3 6139 6133 6029 +3 6212 6139 6216 +3 6133 6139 6212 +3 6036 6134 6140 +3 6134 6216 6140 +3 6212 6216 6134 +3 6030 6036 5892 +3 6134 6036 6030 +3 5886 5892 5748 +3 6030 5892 5886 +3 5742 5748 5643 +3 5886 5748 5742 +3 5466 5380 5374 +3 5380 5322 5374 +3 5472 5380 5466 +3 5472 5466 5558 +3 5472 5558 5564 +3 5558 5633 5564 +3 5633 5643 5564 +3 5742 5643 5633 +3 5632 5556 5557 +3 5557 5464 5465 +3 5372 5373 5465 +3 5320 5321 5373 +3 5321 5251 5252 +3 5033 5032 4941 +3 4941 4940 4872 +3 4771 4872 4871 +3 4771 4770 4627 +3 4627 4626 4483 +3 4375 4483 4482 +3 4375 4374 4280 +3 4280 4279 4367 +3 4367 4366 4475 +3 5868 6013 5869 +3 6021 5876 5877 +3 5732 5733 5877 +3 5733 5631 5632 +3 5457 5364 5456 +3 5364 5365 5312 +3 5312 5313 5241 +3 5241 5242 5168 +3 5168 5169 5112 +3 4932 4862 4861 +3 4861 4763 4762 +3 4475 4474 4619 +3 4366 4474 4475 +3 4279 4366 4367 +3 4374 4279 4280 +3 4482 4374 4375 +3 4626 4482 4483 +3 4770 4626 4627 +3 4871 4770 4771 +3 4940 4871 4872 +3 5032 4940 4941 +3 5120 5032 5033 +3 5120 5033 5121 +3 5120 5121 5176 +3 5252 5176 5177 +3 5176 5121 5177 +3 5251 5176 5252 +3 5320 5251 5321 +3 5372 5320 5373 +3 5464 5372 5465 +3 5556 5464 5557 +3 5631 5556 5632 +3 5732 5631 5733 +3 5876 5732 5877 +3 6020 5876 6021 +3 6020 6021 6125 +3 6020 6125 6124 +3 6125 6206 6124 +3 6206 6205 6124 +3 6116 6205 6206 +3 6116 6206 6117 +3 6116 6117 6012 +3 6117 6013 6012 +3 6013 5868 6012 +3 5724 5869 5725 +3 5868 5869 5724 +3 4762 4619 4618 +3 4619 4474 4618 +3 4763 4619 4762 +3 4862 4763 4861 +3 4933 4862 4932 +3 4933 4932 5024 +3 4933 5024 5025 +3 5024 5112 5025 +3 5112 5113 5025 +3 5169 5113 5112 +3 5242 5169 5168 +3 5313 5242 5241 +3 5365 5313 5312 +3 5457 5365 5364 +3 5549 5457 5456 +3 5549 5456 5548 +3 5549 5548 5622 +3 5548 5621 5622 +3 5621 5725 5622 +3 5724 5725 5621 +3 3535 3527 3458 +3 3458 3451 3386 +3 3386 3379 3311 +3 3311 3304 3265 +3 3258 3208 3265 +3 3208 3200 3143 +3 3136 3096 3143 +3 3089 3021 3096 +3 3014 2949 3021 +3 2949 2942 2872 +3 2864 2784 2872 +3 2784 2777 2680 +3 2680 2673 2576 +3 2568 2493 2576 +3 2493 2486 2417 +3 2412 2494 2417 +3 2494 2487 2577 +3 2577 2569 2681 +3 2681 2674 2785 +3 3993 3986 3893 +3 3637 3630 3535 +3 3528 3536 3452 +3 3452 3459 3380 +3 3387 3305 3380 +3 3305 3312 3259 +3 3259 3266 3201 +3 3137 3201 3209 +3 3015 2950 2943 +3 2785 2778 2873 +3 2674 2778 2785 +3 2569 2674 2681 +3 2487 2569 2577 +3 2412 2487 2494 +3 2486 2412 2417 +3 2568 2486 2493 +3 2673 2568 2576 +3 2777 2673 2680 +3 2864 2777 2784 +3 2942 2864 2872 +3 3014 2942 2949 +3 3089 3014 3021 +3 3136 3089 3096 +3 3200 3136 3143 +3 3258 3200 3208 +3 3304 3258 3265 +3 3379 3304 3311 +3 3451 3379 3386 +3 3527 3451 3458 +3 3630 3527 3535 +3 3763 3630 3637 +3 3763 3637 3770 +3 3763 3770 3886 +3 3770 3893 3886 +3 3893 3986 3886 +3 4061 3993 4065 +3 3986 3993 4061 +3 3987 4065 3994 +3 4061 4065 3987 +3 3771 3887 3894 +3 3887 3994 3894 +3 3987 3994 3887 +3 3764 3771 3638 +3 3887 3771 3764 +3 3631 3638 3536 +3 3764 3638 3631 +3 2943 2873 2865 +3 2873 2778 2865 +3 2950 2873 2943 +3 3022 2950 3015 +3 3022 3015 3090 +3 3022 3090 3097 +3 3090 3137 3097 +3 3137 3144 3097 +3 3209 3144 3137 +3 3266 3209 3201 +3 3312 3266 3259 +3 3387 3312 3305 +3 3459 3387 3380 +3 3536 3459 3452 +3 3631 3536 3528 +3 3008 3033 3083 +3 3083 3108 3130 +3 3130 3155 3193 +3 3227 3252 3193 +3 3252 3277 3298 +3 3298 3324 3373 +3 3373 3398 3445 +3 3445 3470 3519 +3 3749 3871 3872 +3 3872 3971 3972 +3 3972 4054 4055 +3 4055 3978 3979 +3 3878 3879 3979 +3 3879 3755 3756 +3 3756 3622 3623 +3 3623 3526 3527 +3 3527 3471 3451 +3 3451 3399 3379 +3 3379 3325 3304 +3 3304 3278 3258 +3 3228 3200 3258 +3 3200 3156 3136 +3 3109 3089 3136 +3 3089 3034 3014 +3 3014 2962 2942 +3 2820 2864 2902 +3 2864 2942 2902 +3 2942 2901 2902 +3 2962 2901 2942 +3 3034 2962 3014 +3 3109 3034 3089 +3 3156 3109 3136 +3 3228 3156 3200 +3 3278 3228 3258 +3 3325 3278 3304 +3 3399 3325 3379 +3 3471 3399 3451 +3 3526 3471 3527 +3 3622 3526 3623 +3 3755 3622 3756 +3 3878 3755 3879 +3 3978 3878 3979 +3 4054 3978 4055 +3 3971 4054 3972 +3 3871 3971 3872 +3 3748 3871 3749 +3 3748 3749 3616 +3 3748 3616 3615 +3 3616 3519 3615 +3 3519 3518 3615 +3 3470 3518 3519 +3 3398 3470 3445 +3 3324 3398 3373 +3 3277 3324 3298 +3 3227 3277 3252 +3 3155 3227 3193 +3 3108 3155 3130 +3 3033 3108 3083 +3 2961 3033 3008 +3 2961 3008 2936 +3 2961 2936 2899 +3 2819 2900 2857 +3 2900 2936 2857 +3 2899 2936 2900 +3 8476 7744 8468 +3 8460 8140 8452 +3 7887 8467 8459 +3 8467 7743 8475 +3 8499 8155 8507 +3 8544 8164 8540 +3 7645 8476 7752 +3 8484 7896 7752 +3 8500 8148 8492 +3 8233 8148 8500 +3 8233 8500 8156 +3 8500 8508 8156 +3 8508 8048 8156 +3 7904 8048 8508 +3 7904 8508 8516 +3 7904 8516 7760 +3 8516 8524 7760 +3 8524 7655 7760 +3 7768 7655 8524 +3 7768 8524 8532 +3 7768 8532 7912 +3 8532 8540 7912 +3 8540 8056 7912 +3 8164 8056 8540 +3 8238 8164 8544 +3 8238 8544 8163 +3 8544 8539 8163 +3 8539 8055 8163 +3 7911 8055 8539 +3 7911 8539 8531 +3 7911 8531 7767 +3 8531 8523 7767 +3 8523 7654 7767 +3 7759 7654 8523 +3 7759 8523 8515 +3 7759 8515 7903 +3 8515 8507 7903 +3 8507 8047 7903 +3 8155 8047 8507 +3 8232 8155 8499 +3 8232 8499 8147 +3 8499 8491 8147 +3 8491 8039 8147 +3 7895 8039 8491 +3 7895 8491 8483 +3 7895 8483 7751 +3 8483 8475 7751 +3 8475 7644 7751 +3 7743 7644 8475 +3 7887 7743 8467 +3 8031 7887 8459 +3 8031 8459 8139 +3 8459 8452 8139 +3 8452 8224 8139 +3 8140 8224 8452 +3 8032 8140 8460 +3 8032 8460 7888 +3 8460 8468 7888 +3 8468 7744 7888 +3 7896 8492 8040 +3 8492 8148 8040 +3 8484 8492 7896 +3 8476 8484 7752 +3 7744 8476 7645 +3 180 952 173 +3 567 168 161 +3 182 842 188 +3 188 706 194 +3 199 483 201 +3 962 220 213 +3 220 854 228 +3 235 396 236 +3 898 215 961 +3 215 222 961 +3 222 853 961 +3 717 853 222 +3 717 222 230 +3 717 230 584 +3 230 236 584 +3 236 489 584 +3 396 489 236 +3 490 396 235 +3 490 235 585 +3 235 228 585 +3 228 718 585 +3 854 718 228 +3 962 854 220 +3 848 962 213 +3 848 213 207 +3 848 207 712 +3 207 201 712 +3 201 579 712 +3 483 579 201 +3 392 483 199 +3 392 199 477 +3 199 194 477 +3 194 573 477 +3 706 573 194 +3 842 706 188 +3 953 842 182 +3 953 182 175 +3 953 175 836 +3 175 168 836 +3 168 700 836 +3 567 700 168 +3 471 567 161 +3 471 161 385 +3 161 159 385 +3 159 470 385 +3 566 470 159 +3 566 159 166 +3 566 166 699 +3 166 173 699 +3 173 835 699 +3 952 835 173 +3 897 952 180 +3 1899 2553 2032 +3 2032 2470 2128 +3 2128 2403 2219 +3 2219 2471 2129 +3 2129 2554 2033 +3 1906 2559 2039 +3 2141 2226 2408 +3 2141 2481 2045 +3 2045 2564 1912 +3 1912 2669 1779 +3 2773 1677 1779 +3 2147 2486 2050 +3 2050 2568 1917 +3 1917 2673 1784 +3 1784 2777 1676 +3 1713 1676 2820 +3 1676 2864 2820 +3 2777 2864 1676 +3 2673 2777 1784 +3 2568 2673 1917 +3 2486 2568 2050 +3 2412 2486 2147 +3 2412 2147 2230 +3 2412 2230 2487 +3 2230 2148 2487 +3 2148 2569 2487 +3 1918 2569 2051 +3 2569 2148 2051 +3 2674 2569 1918 +3 2674 1918 1785 +3 2674 1785 2778 +3 1785 1677 2778 +3 1677 2865 2778 +3 2773 2865 1677 +3 2669 2773 1779 +3 2564 2669 1912 +3 2481 2564 2045 +3 2408 2481 2141 +3 2476 2408 2226 +3 2039 2476 2135 +3 2476 2226 2135 +3 2559 2476 2039 +3 2664 2559 1906 +3 2664 1906 1773 +3 2664 1773 2768 +3 1773 1668 2768 +3 1668 2858 2768 +3 2763 2858 1668 +3 2763 1668 1767 +3 2763 1767 2659 +3 2033 2659 1900 +3 2659 1767 1900 +3 2554 2659 2033 +3 2471 2554 2129 +3 2403 2471 2219 +3 2470 2403 2128 +3 2553 2470 2032 +3 2658 2553 1899 +3 2658 1899 1766 +3 2658 1766 2762 +3 1766 1667 2762 +3 1667 2857 2762 +3 2819 2857 1667 +3 2819 1667 1712 +3 4863 3617 3520 +3 4764 3750 3617 +3 3750 4620 3873 +3 3865 3742 4611 +3 3965 3865 4467 +3 3965 4359 4049 +3 4049 4272 3966 +3 3966 4360 3866 +3 3866 4468 3743 +3 3610 3743 4612 +3 3610 4756 3520 +3 4475 4619 3749 +3 4375 3979 4483 +3 4771 3527 4872 +3 4872 3630 4779 +3 4779 3763 4635 +3 3886 4491 4635 +3 4491 3986 4383 +3 4383 4061 4286 +3 4286 3987 4384 +3 4384 3887 4492 +3 3764 4636 4492 +3 4636 3631 4780 +3 4780 3528 4873 +3 4873 3624 4772 +3 4772 3757 4628 +3 3980 4376 3880 +3 4281 4376 3980 +3 4281 3980 4056 +3 4281 4056 3973 +3 4281 3973 4368 +3 3973 3873 4368 +3 3873 4476 4368 +3 4620 4476 3873 +3 4764 4620 3750 +3 4863 4764 3617 +3 4756 4863 3520 +3 4612 4756 3610 +3 4468 4612 3743 +3 4360 4468 3866 +3 4272 4360 3966 +3 4359 4272 4049 +3 4467 4359 3965 +3 4611 4467 3865 +3 4755 3742 3609 +3 4611 3742 4755 +3 4628 3880 4484 +3 3880 4376 4484 +3 3757 3880 4628 +3 3624 3757 4772 +3 3528 3624 4873 +3 3631 3528 4780 +3 3764 3631 4636 +3 3887 3764 4492 +3 3987 3887 4384 +3 4061 3987 4286 +3 3986 4061 4383 +3 3886 3986 4491 +3 3763 3886 4635 +3 3630 3763 4779 +3 3527 3630 4872 +3 3623 3527 4771 +3 3623 4771 4627 +3 3623 4627 3756 +3 4627 4483 3756 +3 4483 3879 3756 +3 3979 3879 4483 +3 4055 3979 4375 +3 4055 4375 4280 +3 4055 4280 4367 +3 4055 4367 3972 +3 4367 4475 3972 +3 4475 3872 3972 +3 3749 3872 4475 +3 3616 3749 4619 +3 3616 4619 4763 +3 3616 4763 3519 +3 4763 4862 3519 +3 4862 3609 3519 +3 4755 3609 4862 +3 5623 6762 5726 +3 6622 5870 5726 +3 6014 5870 6478 +3 6366 6118 6014 +3 6118 6279 6207 +3 6207 6374 6126 +3 6126 6486 6022 +3 6022 6630 5878 +3 5878 6770 5734 +3 5734 6869 5633 +3 5633 6778 5742 +3 6134 6382 6212 +3 6212 6284 6133 +3 6133 6381 6029 +3 6029 6493 5885 +3 5717 6613 5861 +3 6005 5861 6469 +3 6005 6357 6109 +3 6109 6270 6198 +3 6198 6358 6110 +3 6110 6470 6006 +3 6614 5862 6006 +3 6013 6365 6477 +3 6365 6117 6278 +3 6278 6206 6373 +3 6373 6125 6485 +3 6021 6629 6485 +3 5885 6637 5741 +3 6493 6637 5885 +3 6381 6493 6029 +3 6284 6381 6133 +3 6382 6284 6212 +3 6494 6382 6134 +3 6494 6134 6030 +3 6494 6030 6638 +3 5742 6638 5886 +3 6638 6030 5886 +3 6778 6638 5742 +3 6869 6778 5633 +3 6770 6869 5734 +3 6630 6770 5878 +3 6486 6630 6022 +3 6374 6486 6126 +3 6279 6374 6207 +3 6366 6279 6118 +3 6478 6366 6014 +3 6622 6478 5870 +3 6762 6622 5726 +3 6859 6762 5623 +3 6859 5623 6754 +3 5862 6754 5718 +3 6754 5623 5718 +3 6614 6754 5862 +3 6470 6614 6006 +3 6358 6470 6110 +3 6270 6358 6198 +3 6357 6270 6109 +3 6469 6357 6005 +3 6613 6469 5861 +3 6753 5717 5622 +3 6613 5717 6753 +3 6868 5741 6777 +3 5741 6637 6777 +3 5632 5741 6868 +3 5632 6868 6769 +3 5632 6769 5733 +3 6769 6629 5733 +3 6629 5877 5733 +3 6021 5877 6629 +3 6125 6021 6485 +3 6206 6125 6373 +3 6117 6206 6278 +3 6013 6117 6365 +3 5869 6013 6477 +3 5869 6477 6621 +3 5869 6621 5725 +3 6621 6761 5725 +3 6761 6858 5725 +3 6858 5622 5725 +3 6753 5622 6858 +3 7383 7375 7327 +3 7327 7319 7254 +3 7177 7254 7244 +3 7177 7169 7125 +3 7027 7125 7117 +3 7019 6933 7027 +3 6925 6858 6933 +3 6858 6848 6753 +3 6613 6753 6745 +3 6613 6605 6469 +3 6614 6746 6754 +3 7887 8031 7879 +3 7735 7743 7887 +3 7743 7634 7644 +3 7384 7376 7468 +3 7376 7328 7320 +3 7320 7255 7245 +3 7170 7245 7178 +3 7170 7126 7118 +3 7118 7028 7020 +3 6754 6849 6859 +3 6849 6934 6859 +3 6746 6849 6754 +3 6606 6746 6614 +3 6606 6614 6470 +3 6606 6470 6462 +3 6470 6358 6462 +3 6358 6350 6462 +3 6266 6350 6358 +3 6266 6358 6270 +3 6266 6270 6357 +3 6266 6357 6349 +3 6357 6469 6349 +3 6469 6461 6349 +3 6605 6461 6469 +3 6745 6605 6613 +3 6848 6745 6753 +3 6925 6848 6858 +3 7019 6925 6933 +3 7117 7019 7027 +3 7169 7117 7125 +3 7244 7169 7177 +3 7319 7244 7254 +3 7375 7319 7327 +3 7467 7375 7383 +3 7467 7383 7475 +3 7467 7475 7559 +3 7644 7559 7567 +3 7559 7475 7567 +3 7634 7559 7644 +3 7735 7634 7743 +3 7879 7735 7887 +3 8023 7879 8031 +3 8023 8031 8139 +3 8023 8139 8131 +3 8218 8139 8224 +3 8131 8139 8218 +3 8032 8132 8140 +3 8132 8224 8140 +3 8218 8224 8132 +3 8024 8032 7888 +3 8132 8032 8024 +3 7880 7888 7744 +3 8024 7888 7880 +3 7736 7744 7645 +3 7880 7744 7736 +3 7020 6934 6926 +3 6934 6849 6926 +3 7028 6934 7020 +3 7126 7028 7118 +3 7178 7126 7170 +3 7255 7178 7245 +3 7328 7255 7320 +3 7384 7328 7376 +3 7476 7384 7468 +3 7476 7468 7560 +3 7476 7560 7568 +3 7560 7635 7568 +3 7635 7645 7568 +3 7736 7645 7635 +3 7634 7558 7559 +3 7559 7466 7467 +3 7374 7375 7467 +3 7318 7319 7375 +3 7319 7243 7244 +3 7168 7169 7244 +3 7169 7116 7117 +3 6925 6924 6848 +3 6847 6741 6848 +3 6741 6740 6601 +3 6601 6600 6457 +3 6456 6345 6457 +3 6262 6345 6344 +3 6262 6261 6341 +3 8123 8213 8214 +3 8214 8126 8127 +3 8018 8019 8127 +3 8019 7874 7875 +3 7730 7731 7875 +3 7731 7633 7634 +3 7462 7463 7370 +3 7370 7371 7314 +3 7314 7315 7237 +3 7237 7238 7164 +3 7014 6921 6920 +3 6920 6842 6841 +3 6841 6737 6736 +3 6736 6597 6596 +3 6341 6340 6453 +3 6261 6340 6341 +3 6344 6261 6262 +3 6456 6344 6345 +3 6600 6456 6457 +3 6740 6600 6601 +3 6847 6740 6741 +3 6924 6847 6848 +3 7018 6924 6925 +3 7117 7018 7019 +3 7018 6925 7019 +3 7116 7018 7117 +3 7168 7116 7169 +3 7243 7168 7244 +3 7318 7243 7319 +3 7374 7318 7375 +3 7466 7374 7467 +3 7558 7466 7559 +3 7633 7558 7634 +3 7730 7633 7731 +3 7874 7730 7875 +3 8018 7874 8019 +3 8126 8018 8127 +3 8213 8126 8214 +3 8122 8213 8123 +3 8122 8123 8015 +3 8122 8015 8014 +3 7870 8015 7871 +3 8014 8015 7870 +3 7726 7871 7727 +3 7870 7871 7726 +3 6596 6453 6452 +3 6453 6340 6452 +3 6597 6453 6596 +3 6737 6597 6736 +3 6842 6737 6841 +3 6921 6842 6920 +3 7015 6921 7014 +3 7015 7014 7112 +3 7015 7112 7113 +3 7112 7164 7113 +3 7164 7165 7113 +3 7238 7165 7164 +3 7315 7238 7237 +3 7371 7315 7314 +3 7463 7371 7370 +3 7555 7463 7462 +3 7555 7462 7554 +3 7555 7554 7628 +3 7554 7627 7628 +3 7627 7727 7628 +3 7726 7727 7627 +3 5541 5549 5622 +3 5549 5449 5457 +3 5025 5017 4933 +3 4933 4925 4862 +3 4848 4755 4862 +3 4611 4755 4747 +3 4467 4611 4603 +3 4459 4359 4467 +3 4272 4359 4351 +3 4272 4266 4360 +3 4360 4352 4468 +3 4468 4460 4612 +3 4612 4604 4756 +3 4756 4748 4863 +3 4863 4849 4934 +3 4934 4926 5026 +3 5026 5018 5114 +3 5854 5862 5718 +3 6198 6192 6109 +3 5709 5717 5861 +3 5717 5608 5622 +3 5314 5306 5366 +3 5229 5306 5314 +3 5229 5314 5243 +3 5229 5243 5170 +3 5229 5170 5162 +3 5170 5114 5162 +3 5114 5106 5162 +3 5018 5106 5114 +3 4926 5018 5026 +3 4849 4926 4934 +3 4748 4849 4863 +3 4604 4748 4756 +3 4460 4604 4612 +3 4352 4460 4468 +3 4266 4352 4360 +3 4351 4266 4272 +3 4459 4351 4359 +3 4603 4459 4467 +3 4747 4603 4611 +3 4848 4747 4755 +3 4925 4848 4862 +3 5017 4925 4933 +3 5105 5017 5025 +3 5105 5025 5113 +3 5105 5113 5169 +3 5105 5169 5161 +3 5169 5242 5161 +3 5242 5228 5161 +3 5305 5228 5242 +3 5305 5242 5313 +3 5305 5313 5357 +3 5457 5357 5365 +3 5357 5313 5365 +3 5449 5357 5457 +3 5541 5449 5549 +3 5608 5541 5622 +3 5709 5608 5717 +3 5853 5709 5861 +3 5853 5861 6005 +3 5853 6005 5997 +3 6005 6109 5997 +3 6109 6101 5997 +3 6192 6101 6109 +3 6102 6192 6198 +3 6102 6198 6110 +3 6102 6110 6006 +3 6102 6006 5998 +3 6006 5862 5998 +3 5862 5854 5998 +3 5710 5718 5623 +3 5854 5718 5710 +3 5450 5366 5358 +3 5366 5306 5358 +3 5458 5366 5450 +3 5458 5450 5542 +3 5458 5542 5550 +3 5542 5609 5550 +3 5609 5623 5550 +3 5710 5623 5609 +3 5608 5540 5541 +3 5541 5448 5449 +3 5449 5356 5357 +3 5305 5357 5304 +3 5227 5228 5305 +3 5228 5160 5161 +3 5104 5105 5161 +3 4848 4847 4743 +3 4346 4262 4347 +3 4262 4261 4343 +3 4343 4342 4451 +3 4450 4595 4451 +3 4595 4594 4739 +3 4842 4739 4738 +3 4842 4841 4921 +3 4921 4920 5013 +3 5012 5101 5013 +3 5101 5100 5157 +3 5156 5222 5157 +3 5222 5221 5301 +3 5301 5300 5353 +3 5353 5352 5445 +3 5445 5444 5537 +3 5845 5988 5989 +3 5989 6092 6093 +3 6093 6187 6188 +3 6188 6096 6097 +3 5992 5993 6097 +3 5848 5849 5993 +3 5849 5704 5705 +3 5607 5608 5705 +3 5537 5536 5602 +3 5536 5601 5602 +3 5444 5536 5537 +3 5352 5444 5445 +3 5300 5352 5353 +3 5221 5300 5301 +3 5156 5221 5222 +3 5100 5156 5157 +3 5012 5100 5101 +3 4920 5012 5013 +3 4841 4920 4921 +3 4738 4841 4842 +3 4594 4738 4739 +3 4450 4594 4595 +3 4342 4450 4451 +3 4261 4342 4343 +3 4346 4261 4262 +3 4454 4346 4347 +3 4454 4347 4455 +3 4454 4455 4598 +3 4455 4599 4598 +3 4599 4743 4598 +3 4743 4742 4598 +3 4847 4742 4743 +3 4924 4847 4848 +3 4924 4848 4925 +3 4924 4925 5016 +3 5105 5016 5017 +3 5016 4925 5017 +3 5104 5016 5105 +3 5160 5104 5161 +3 5227 5160 5228 +3 5304 5227 5305 +3 5356 5304 5357 +3 5448 5356 5449 +3 5540 5448 5541 +3 5607 5540 5608 +3 5704 5607 5705 +3 5848 5704 5849 +3 5992 5848 5993 +3 6096 5992 6097 +3 6187 6096 6188 +3 6092 6187 6093 +3 5988 6092 5989 +3 5844 5988 5845 +3 5844 5845 5701 +3 5844 5701 5700 +3 5701 5602 5700 +3 5602 5601 5700 +3 3519 3439 3445 +3 3445 3367 3373 +3 2936 3008 3002 +3 2936 2930 2857 +3 2857 2850 2762 +3 2762 2757 2658 +3 2658 2653 2553 +3 2470 2553 2548 +3 2403 2470 2465 +3 2403 2400 2471 +3 2554 2471 2466 +3 2554 2549 2659 +3 2763 2659 2654 +3 2858 2763 2758 +3 2858 2851 2937 +3 2937 2931 3009 +3 3084 3009 3003 +3 3084 3078 3131 +3 3736 3743 3610 +3 4049 4043 3965 +3 3742 3602 3609 +3 3511 3519 3609 +3 3247 3299 3253 +3 3247 3253 3187 +3 3253 3194 3187 +3 3194 3131 3187 +3 3131 3125 3187 +3 3078 3125 3131 +3 3003 3078 3084 +3 2931 3003 3009 +3 2851 2931 2937 +3 2758 2851 2858 +3 2654 2758 2763 +3 2549 2654 2659 +3 2466 2549 2554 +3 2400 2466 2471 +3 2465 2400 2403 +3 2548 2465 2470 +3 2653 2548 2553 +3 2757 2653 2658 +3 2850 2757 2762 +3 2930 2850 2857 +3 3002 2930 2936 +3 3077 3002 3008 +3 3077 3008 3083 +3 3077 3083 3130 +3 3077 3130 3124 +3 3130 3193 3124 +3 3193 3186 3124 +3 3246 3186 3193 +3 3246 3193 3252 +3 3246 3252 3292 +3 3373 3292 3298 +3 3292 3252 3298 +3 3367 3292 3373 +3 3439 3367 3445 +3 3511 3439 3519 +3 3602 3511 3609 +3 3735 3602 3742 +3 3735 3742 3865 +3 3735 3865 3858 +3 3865 3965 3858 +3 3965 3958 3858 +3 4043 3958 3965 +3 3959 4043 4049 +3 3959 4049 3966 +3 3959 3966 3866 +3 3959 3866 3859 +3 3866 3743 3859 +3 3743 3736 3859 +3 3603 3610 3520 +3 3736 3610 3603 +3 3368 3299 3293 +3 3299 3247 3293 +3 3374 3299 3368 +3 3374 3368 3440 +3 3374 3440 3446 +3 3440 3512 3446 +3 3512 3520 3446 +3 3603 3520 3512 +3 3074 2999 3031 +3 3106 3121 3074 +3 3121 3153 3182 +3 3182 3225 3243 +3 3243 3275 3289 +3 3289 3322 3364 +3 3364 3396 3436 +3 3468 3506 3436 +3 3727 3849 3850 +3 3850 3949 3950 +3 4038 4039 3950 +3 3953 3954 4039 +3 3367 3323 3292 +3 3292 3276 3246 +3 3246 3226 3186 +3 3186 3154 3124 +3 3124 3107 3077 +3 3077 3032 3002 +3 3002 2960 2930 +3 2818 2850 2898 +3 2850 2930 2898 +3 2930 2897 2898 +3 2960 2897 2930 +3 3032 2960 3002 +3 3107 3032 3077 +3 3154 3107 3124 +3 3226 3154 3186 +3 3276 3226 3246 +3 3323 3276 3292 +3 3397 3323 3367 +3 3397 3367 3439 +3 3397 3439 3469 +3 3439 3511 3469 +3 3511 3510 3469 +3 3597 3510 3511 +3 3597 3511 3598 +3 3597 3598 3730 +3 3598 3731 3730 +3 3731 3853 3730 +3 3954 3853 3854 +3 3853 3731 3854 +3 3953 3853 3954 +3 4038 3953 4039 +3 3949 4038 3950 +3 3849 3949 3850 +3 3726 3849 3727 +3 3726 3727 3594 +3 3726 3594 3593 +3 3594 3506 3593 +3 3506 3505 3593 +3 3468 3505 3506 +3 3396 3468 3436 +3 3322 3396 3364 +3 3275 3322 3289 +3 3225 3275 3243 +3 3153 3225 3182 +3 3106 3153 3121 +3 3031 3106 3074 +3 2959 3031 2999 +3 2959 2999 2927 +3 2959 2927 2895 +3 2817 2896 2843 +3 2896 2927 2843 +3 2895 2927 2896 +3 8389 7867 8393 +3 8393 7723 8397 +3 8409 8127 8413 +3 8132 8440 8448 +3 7629 8398 7728 +3 7728 8402 7872 +3 8410 8124 8406 +3 8215 8124 8410 +3 8215 8410 8128 +3 8410 8414 8128 +3 8414 8020 8128 +3 7876 8020 8414 +3 7876 8414 8418 +3 7876 8418 7732 +3 8418 8422 7732 +3 8422 7635 7732 +3 7736 7635 8422 +3 7736 8422 8432 +3 7736 8432 7880 +3 8432 8440 7880 +3 8440 8024 7880 +3 8132 8024 8440 +3 8218 8132 8448 +3 8218 8448 8131 +3 8448 8439 8131 +3 8439 8023 8131 +3 7879 8023 8439 +3 7879 8439 8431 +3 7879 8431 7735 +3 8431 8421 7735 +3 8421 7634 7735 +3 7731 7634 8421 +3 7731 8421 8417 +3 7731 8417 7875 +3 8417 8413 7875 +3 8413 8019 7875 +3 8127 8019 8413 +3 8214 8127 8409 +3 8214 8409 8123 +3 8409 8405 8123 +3 8405 8015 8123 +3 7871 8015 8405 +3 7871 8405 8401 +3 7871 8401 7727 +3 8401 8397 7727 +3 8397 7628 7727 +3 7723 7628 8397 +3 7867 7723 8393 +3 8011 7867 8389 +3 8011 8389 8119 +3 8389 8386 8119 +3 8386 8210 8119 +3 8120 8210 8386 +3 8120 8386 8390 +3 8120 8390 8012 +3 7868 8390 8394 +3 8012 8390 7868 +3 7724 8394 8398 +3 7868 8394 7724 +3 7872 8406 8016 +3 8406 8124 8016 +3 8402 8406 7872 +3 8398 8402 7728 +3 7724 8398 7629 +3 95 934 88 +3 84 543 87 +3 96 818 102 +3 102 682 108 +3 116 459 120 +3 132 944 138 +3 138 830 145 +3 152 382 154 +3 896 134 943 +3 134 141 943 +3 141 829 943 +3 693 829 141 +3 693 141 147 +3 693 147 560 +3 147 154 560 +3 154 464 560 +3 382 464 154 +3 465 382 152 +3 465 152 561 +3 152 145 561 +3 145 694 561 +3 830 694 145 +3 944 830 138 +3 824 944 132 +3 824 132 126 +3 824 126 688 +3 126 120 688 +3 120 555 688 +3 459 555 120 +3 378 459 116 +3 378 116 453 +3 116 108 453 +3 108 549 453 +3 682 549 108 +3 818 682 102 +3 935 818 96 +3 935 96 89 +3 935 89 812 +3 89 87 812 +3 87 676 812 +3 543 676 87 +3 447 543 84 +3 447 84 371 +3 84 82 371 +3 82 446 371 +3 542 446 82 +3 542 82 85 +3 542 85 675 +3 85 88 675 +3 88 811 675 +3 934 811 88 +3 895 934 95 +3 1742 2644 1875 +3 1875 2539 2008 +3 2104 2008 2456 +3 2104 2394 2205 +3 2205 2457 2105 +3 2540 2009 2105 +3 2009 2645 1876 +3 1876 2749 1743 +3 1743 2844 1650 +3 2015 2542 2111 +3 2111 2459 2212 +3 2021 2649 1888 +3 1888 2753 1755 +3 1755 2851 1659 +3 2027 2549 2123 +3 2123 2466 2216 +3 2216 2400 2122 +3 2122 2465 2026 +3 2548 1893 2026 +3 1893 2653 1760 +3 2818 1711 1658 +3 2818 1658 2850 +3 1658 1760 2850 +3 1760 2757 2850 +3 2653 2757 1760 +3 2548 2653 1893 +3 2465 2548 2026 +3 2400 2465 2122 +3 2466 2400 2216 +3 2549 2466 2123 +3 2654 2549 2027 +3 2654 2027 1894 +3 2654 1894 2758 +3 1659 2758 1761 +3 2758 1894 1761 +3 2851 2758 1659 +3 2753 2851 1755 +3 2649 2753 1888 +3 2544 2649 2021 +3 2544 2021 2117 +3 2544 2117 2461 +3 2117 2212 2461 +3 2212 2396 2461 +3 2459 2396 2212 +3 2542 2459 2111 +3 2647 2542 2015 +3 2647 2015 1882 +3 2647 1882 2751 +3 1650 2751 1749 +3 2751 1882 1749 +3 2844 2751 1650 +3 2749 2844 1743 +3 2645 2749 1876 +3 2540 2645 2009 +3 2457 2540 2105 +3 2394 2457 2205 +3 2456 2394 2104 +3 2539 2456 2008 +3 2644 2539 1875 +3 2748 2644 1742 +3 2748 1742 2843 +3 1710 2843 1649 +3 2843 1742 1649 +3 2817 2843 1710 +3 3507 4843 3595 +3 3595 4740 3728 +3 3851 3728 4596 +3 3946 3846 4447 +3 3946 4339 4036 +3 4036 4258 3947 +3 3947 4340 3847 +3 3847 4448 3724 +3 3591 3724 4592 +3 3507 3591 4736 +3 3727 4451 4595 +3 4451 3850 4343 +3 4743 3511 4848 +3 3602 4747 4848 +3 4747 3735 4603 +3 3858 4459 4603 +3 4459 3958 4351 +3 4351 4043 4266 +3 4266 3959 4352 +3 4352 3859 4460 +3 4604 4460 3736 +3 4604 3603 4748 +3 4748 3512 4849 +3 4849 3599 4744 +3 3732 4600 4744 +3 3955 4348 3855 +3 4263 4348 3955 +3 4263 3955 4040 +3 4263 4040 3951 +3 4263 3951 4344 +3 3951 3851 4344 +3 3851 4452 4344 +3 4596 4452 3851 +3 4740 4596 3728 +3 4843 4740 3595 +3 4736 4843 3507 +3 4592 4736 3591 +3 4448 4592 3724 +3 4340 4448 3847 +3 4258 4340 3947 +3 4339 4258 4036 +3 4447 4339 3946 +3 4591 3846 3723 +3 4447 3846 4591 +3 4735 3723 3590 +3 4591 3723 4735 +3 4600 3855 4456 +3 3855 4348 4456 +3 3732 3855 4600 +3 3599 3732 4744 +3 3512 3599 4849 +3 3603 3512 4748 +3 3736 3603 4604 +3 3859 3736 4460 +3 3959 3859 4352 +3 4043 3959 4266 +3 3958 4043 4351 +3 3858 3958 4459 +3 3735 3858 4603 +3 3602 3735 4747 +3 3511 3602 4848 +3 3598 3511 4743 +3 3598 4743 4599 +3 3598 4599 3731 +3 4599 4455 3731 +3 4455 3854 3731 +3 3954 3854 4455 +3 3954 4455 4347 +3 3954 4347 4039 +3 4347 4262 4039 +3 4262 4343 4039 +3 4343 3950 4039 +3 3850 3950 4343 +3 3727 3850 4451 +3 3594 3727 4595 +3 3594 4595 4739 +3 3594 4739 3506 +3 4739 4842 3506 +3 4842 3590 3506 +3 4735 3590 4842 +3 5846 5702 6738 +3 5990 5846 6598 +3 5990 6454 6094 +3 6094 6342 6189 +3 6189 6263 6098 +3 6098 6346 5994 +3 5994 6458 5850 +3 6602 5706 5850 +3 5706 6742 5609 +3 5609 6849 5710 +3 5710 6746 5854 +3 5854 6606 5998 +3 5998 6462 6102 +3 6102 6350 6192 +3 6192 6266 6101 +3 6101 6349 5997 +3 5997 6461 5853 +3 5853 6605 5709 +3 5849 6601 5993 +3 6457 6097 5993 +3 5697 6733 5841 +3 5985 6337 6089 +3 6089 6258 6184 +3 6090 6184 6338 +3 6450 5986 6090 +3 5986 6594 5842 +3 6737 5845 6597 +3 6597 5989 6453 +3 6453 6093 6341 +3 6097 6345 6188 +3 6457 6345 6097 +3 6601 6457 5993 +3 6741 6601 5849 +3 6741 5849 5705 +3 6741 5705 6848 +3 5705 5608 6848 +3 5608 5709 6848 +3 5709 6745 6848 +3 6605 6745 5709 +3 6461 6605 5853 +3 6349 6461 5997 +3 6266 6349 6101 +3 6350 6266 6192 +3 6462 6350 6102 +3 6606 6462 5998 +3 6746 6606 5854 +3 6849 6746 5710 +3 6742 6849 5609 +3 6602 6742 5706 +3 6458 6602 5850 +3 6346 6458 5994 +3 6263 6346 6098 +3 6342 6263 6189 +3 6454 6342 6094 +3 6598 6454 5990 +3 6738 6598 5846 +3 6843 6738 5702 +3 6843 5702 5603 +3 6843 5603 6734 +3 5842 6734 5698 +3 6734 5603 5698 +3 6594 6734 5842 +3 6450 6594 5986 +3 6338 6450 6090 +3 6258 6338 6184 +3 6337 6258 6089 +3 6449 6337 5985 +3 6449 5985 6593 +3 5985 5841 6593 +3 5841 6733 6593 +3 6341 6188 6262 +3 6188 6345 6262 +3 6093 6188 6341 +3 5989 6093 6453 +3 5845 5989 6597 +3 5701 5845 6737 +3 5701 6737 6842 +3 5701 6842 5602 +3 6842 5697 5602 +3 6733 5697 6842 +3 7463 7459 7371 +3 7371 7367 7315 +3 7315 7311 7238 +3 7011 7015 7113 +3 7015 6917 6921 +3 6593 6589 6449 +3 6445 6337 6449 +3 6337 6333 6258 +3 6258 6254 6338 +3 6338 6334 6450 +3 6450 6446 6594 +3 6594 6590 6734 +3 6730 6843 6734 +3 7016 7110 7114 +3 7114 7162 7166 +3 7166 7233 7239 +3 8008 8012 7868 +3 8012 8116 8120 +3 8120 8208 8210 +3 8210 8115 8119 +3 8119 8007 8011 +3 8011 7863 7867 +3 7867 7719 7723 +3 7464 7460 7552 +3 7239 7312 7316 +3 7312 7372 7316 +3 7233 7312 7239 +3 7162 7233 7166 +3 7110 7162 7114 +3 7012 7110 7016 +3 7012 7016 6922 +3 7012 6922 6918 +3 6922 6843 6918 +3 6843 6837 6918 +3 6730 6837 6843 +3 6590 6730 6734 +3 6446 6590 6594 +3 6334 6446 6450 +3 6254 6334 6338 +3 6333 6254 6258 +3 6445 6333 6337 +3 6589 6445 6449 +3 6729 6589 6593 +3 6729 6593 6733 +3 6729 6733 6836 +3 6921 6836 6842 +3 6836 6733 6842 +3 6917 6836 6921 +3 7011 6917 7015 +3 7109 7011 7113 +3 7109 7113 7165 +3 7109 7165 7161 +3 7165 7238 7161 +3 7238 7232 7161 +3 7311 7232 7238 +3 7367 7311 7315 +3 7459 7367 7371 +3 7551 7459 7463 +3 7551 7463 7555 +3 7551 7555 7622 +3 7723 7622 7628 +3 7622 7555 7628 +3 7719 7622 7723 +3 7863 7719 7867 +3 8007 7863 8011 +3 8115 8007 8119 +3 8208 8115 8210 +3 8116 8208 8120 +3 8008 8116 8012 +3 7864 8008 7868 +3 7864 7868 7724 +3 7864 7724 7720 +3 7460 7372 7368 +3 7372 7312 7368 +3 7464 7372 7460 +3 7556 7464 7552 +3 7556 7552 7623 +3 7556 7623 7629 +3 7623 7724 7629 +3 7720 7724 7623 +3 7367 7366 7311 +3 7311 7310 7232 +3 7109 7010 7011 +3 7011 6916 6917 +3 6835 6836 6917 +3 6437 6436 6325 +3 6325 6324 6248 +3 6429 6572 6573 +3 6573 6712 6713 +3 6825 6826 6713 +3 7101 7100 7153 +3 7707 7612 7706 +3 7707 7706 7851 +3 8103 8102 8204 +3 7858 7859 8003 +3 7859 7714 7715 +3 7715 7621 7622 +3 7450 7359 7358 +3 7358 7303 7302 +3 7153 7152 7222 +3 7100 7152 7153 +3 7002 7100 7101 +3 7002 7101 7003 +3 7002 7003 6908 +3 6826 6908 6909 +3 6908 7003 6909 +3 6825 6908 6826 +3 6712 6825 6713 +3 6572 6712 6573 +3 6428 6572 6429 +3 6428 6429 6317 +3 6428 6317 6316 +3 6317 6248 6316 +3 6248 6247 6316 +3 6324 6247 6248 +3 6436 6324 6325 +3 6580 6436 6437 +3 6580 6437 6581 +3 6580 6581 6720 +3 6836 6720 6721 +3 6720 6581 6721 +3 6835 6720 6836 +3 6916 6835 6917 +3 7010 6916 7011 +3 7108 7010 7109 +3 7108 7109 7161 +3 7108 7161 7160 +3 7161 7232 7160 +3 7232 7231 7160 +3 7310 7231 7232 +3 7366 7310 7311 +3 7458 7366 7367 +3 7458 7367 7459 +3 7458 7459 7550 +3 7622 7550 7551 +3 7550 7459 7551 +3 7621 7550 7622 +3 7714 7621 7715 +3 7858 7714 7859 +3 8002 7858 8003 +3 8002 8003 8111 +3 8002 8111 8110 +3 8111 8204 8110 +3 8204 8203 8110 +3 8102 8203 8204 +3 7994 8102 8103 +3 7994 8103 7995 +3 7994 7995 7850 +3 7995 7851 7850 +3 7851 7706 7850 +3 7302 7222 7221 +3 7222 7152 7221 +3 7303 7222 7302 +3 7359 7303 7358 +3 7451 7359 7450 +3 7451 7450 7542 +3 7451 7542 7543 +3 7542 7611 7543 +3 7611 7612 7543 +3 7706 7612 7611 +3 5537 5533 5445 +3 5445 5441 5353 +3 5301 5353 5349 +3 5157 5097 5101 +3 5009 5013 5101 +3 4917 4921 5013 +3 4591 4587 4447 +3 4258 4336 4340 +3 4340 4444 4448 +3 4588 4592 4448 +3 4592 4732 4736 +3 4837 4843 4736 +3 4918 4922 4843 +3 5010 5014 4922 +3 5014 5098 5102 +3 5154 5158 5102 +3 5158 5217 5223 +3 5223 5298 5302 +3 5302 5350 5354 +3 5354 5442 5446 +3 5986 6086 6090 +3 6090 6180 6184 +3 6184 6085 6089 +3 6089 5981 5985 +3 5985 5837 5841 +3 5693 5697 5841 +3 5597 5698 5603 +3 5597 5603 5534 +3 5446 5534 5538 +3 5534 5603 5538 +3 5442 5534 5446 +3 5350 5442 5354 +3 5298 5350 5302 +3 5217 5298 5223 +3 5154 5217 5158 +3 5098 5154 5102 +3 5010 5098 5014 +3 4918 5010 4922 +3 4837 4918 4843 +3 4732 4837 4736 +3 4588 4732 4592 +3 4444 4588 4448 +3 4336 4444 4340 +3 4254 4336 4258 +3 4254 4258 4339 +3 4254 4339 4335 +3 4339 4447 4335 +3 4447 4443 4335 +3 4587 4443 4447 +3 4731 4587 4591 +3 4731 4591 4735 +3 4731 4735 4836 +3 4921 4836 4842 +3 4836 4735 4842 +3 4917 4836 4921 +3 5009 4917 5013 +3 5097 5009 5101 +3 5153 5097 5157 +3 5153 5157 5222 +3 5153 5222 5216 +3 5222 5301 5216 +3 5301 5297 5216 +3 5349 5297 5301 +3 5441 5349 5353 +3 5533 5441 5445 +3 5596 5533 5537 +3 5697 5596 5602 +3 5596 5537 5602 +3 5693 5596 5697 +3 5837 5693 5841 +3 5981 5837 5985 +3 6085 5981 6089 +3 6180 6085 6184 +3 6086 6180 6090 +3 5982 6086 5986 +3 5982 5986 5842 +3 5982 5842 5838 +3 5842 5698 5838 +3 5698 5694 5838 +3 5597 5694 5698 +3 5596 5595 5533 +3 5533 5532 5441 +3 5441 5440 5349 +3 5349 5348 5297 +3 5153 5096 5097 +3 5097 5008 5009 +3 4916 4917 5009 +3 4917 4835 4836 +3 4836 4722 4723 +3 4327 4326 4248 +3 4248 4247 4319 +3 4319 4318 4427 +3 4571 4427 4426 +3 4571 4570 4715 +3 4715 4714 4826 +3 4826 4825 4909 +3 4909 4908 5001 +3 5001 5000 5089 +3 5089 5088 5145 +3 5145 5144 5206 +3 5206 5205 5289 +3 6174 6069 6173 +3 6174 6173 6077 +3 6077 6076 5973 +3 5973 5972 5829 +3 5828 5685 5829 +3 5685 5684 5596 +3 5289 5288 5341 +3 5205 5288 5289 +3 5144 5205 5206 +3 5088 5144 5145 +3 5000 5088 5089 +3 4908 5000 5001 +3 4825 4908 4909 +3 4714 4825 4826 +3 4570 4714 4715 +3 4426 4570 4571 +3 4318 4426 4427 +3 4247 4318 4319 +3 4326 4247 4248 +3 4434 4326 4327 +3 4434 4327 4435 +3 4434 4435 4578 +3 4723 4578 4579 +3 4578 4435 4579 +3 4722 4578 4723 +3 4835 4722 4836 +3 4916 4835 4917 +3 5008 4916 5009 +3 5096 5008 5097 +3 5152 5096 5153 +3 5152 5153 5216 +3 5152 5216 5215 +3 5216 5297 5215 +3 5297 5296 5215 +3 5348 5296 5297 +3 5440 5348 5349 +3 5532 5440 5441 +3 5595 5532 5533 +3 5684 5595 5596 +3 5828 5684 5685 +3 5972 5828 5829 +3 6076 5972 5973 +3 6173 6076 6077 +3 6068 6069 5965 +3 6173 6069 6068 +3 5964 5965 5821 +3 6068 5965 5964 +3 5820 5821 5677 +3 5964 5821 5820 +3 5676 5677 5586 +3 5820 5677 5676 +3 5432 5341 5340 +3 5341 5288 5340 +3 5433 5341 5432 +3 5433 5432 5524 +3 5433 5524 5525 +3 5524 5585 5525 +3 5585 5586 5525 +3 5676 5586 5585 +3 3506 3434 3436 +3 3436 3362 3364 +3 3364 3287 3289 +3 3241 3243 3289 +3 3243 3179 3182 +3 3182 3119 3121 +3 3121 3072 3074 +3 2839 2843 2927 +3 2539 2537 2456 +3 2456 2454 2394 +3 2394 2393 2457 +3 2457 2455 2540 +3 2540 2538 2645 +3 2643 2749 2645 +3 2749 2747 2844 +3 3000 3073 3075 +3 3075 3120 3122 +3 3288 3365 3290 +3 3365 3363 3437 +3 3507 3587 3591 +3 3591 3720 3724 +3 3843 3847 3724 +3 3943 3947 3847 +3 3947 4034 4036 +3 3942 3946 4036 +3 3946 3842 3846 +3 3719 3723 3846 +3 3723 3586 3590 +3 3590 3501 3506 +3 3437 3435 3507 +3 3435 3502 3507 +3 3363 3435 3437 +3 3288 3363 3365 +3 3242 3288 3290 +3 3242 3290 3244 +3 3242 3244 3180 +3 3122 3180 3183 +3 3180 3244 3183 +3 3120 3180 3122 +3 3073 3120 3075 +3 2998 3073 3000 +3 2998 3000 2928 +3 2998 2928 2926 +3 2928 2844 2926 +3 2844 2840 2926 +3 2747 2840 2844 +3 2643 2747 2749 +3 2538 2643 2645 +3 2455 2538 2540 +3 2393 2455 2457 +3 2454 2393 2394 +3 2537 2454 2456 +3 2642 2537 2539 +3 2642 2539 2644 +3 2642 2644 2746 +3 2843 2746 2748 +3 2746 2644 2748 +3 2839 2746 2843 +3 2925 2839 2927 +3 2925 2927 2997 +3 3074 2997 2999 +3 2997 2927 2999 +3 3072 2997 3074 +3 3119 3072 3121 +3 3179 3119 3182 +3 3241 3179 3243 +3 3287 3241 3289 +3 3362 3287 3364 +3 3434 3362 3436 +3 3501 3434 3506 +3 3586 3501 3590 +3 3719 3586 3723 +3 3842 3719 3846 +3 3942 3842 3946 +3 4034 3942 4036 +3 3943 4034 3947 +3 3843 3943 3847 +3 3720 3843 3724 +3 3587 3720 3591 +3 3502 3587 3507 +3 3320 3287 3362 +3 3241 3287 3273 +3 3241 3223 3179 +3 3179 3151 3119 +3 3119 3104 3072 +3 3029 2997 3072 +3 2638 2533 2616 +3 2638 2700 2742 +3 2804 2836 2742 +3 2836 2835 2923 +3 2923 2922 2995 +3 2994 3070 2995 +3 3070 3069 3117 +3 3117 3116 3176 +3 3176 3175 3239 +3 3360 3431 3432 +3 3432 3492 3493 +3 3493 3574 3575 +3 3707 3708 3575 +3 3708 3830 3831 +3 3831 3930 3931 +3 3837 3715 3838 +3 3715 3714 3582 +3 3582 3581 3501 +3 2434 2452 2515 +3 2535 2620 2515 +3 2704 2620 2640 +3 2744 2808 2704 +3 2808 2839 2890 +3 2997 2957 2925 +3 3029 2957 2997 +3 3104 3029 3072 +3 3151 3104 3119 +3 3223 3151 3179 +3 3273 3223 3241 +3 3320 3273 3287 +3 3394 3320 3362 +3 3394 3362 3434 +3 3394 3434 3466 +3 3434 3501 3466 +3 3501 3500 3466 +3 3581 3500 3501 +3 3714 3581 3582 +3 3837 3714 3715 +3 3937 3837 3838 +3 3937 3838 3938 +3 3937 3938 4029 +3 3931 4029 4030 +3 4029 3938 4030 +3 3930 4029 3931 +3 3830 3930 3831 +3 3707 3830 3708 +3 3574 3707 3575 +3 3492 3574 3493 +3 3431 3492 3432 +3 3359 3431 3360 +3 3359 3360 3285 +3 3359 3285 3284 +3 3285 3239 3284 +3 3239 3238 3284 +3 3175 3238 3239 +3 3116 3175 3176 +3 3069 3116 3117 +3 2994 3069 3070 +3 2922 2994 2995 +3 2835 2922 2923 +3 2804 2835 2836 +3 2700 2804 2742 +3 2616 2700 2638 +3 2441 2616 2533 +3 2890 2925 2889 +3 2925 2957 2889 +3 2839 2925 2890 +3 2744 2839 2808 +3 2640 2744 2704 +3 2535 2640 2620 +3 2452 2535 2515 +3 2390 2452 2434 +3 2390 2434 2433 +3 2390 2433 2450 +3 2433 2437 2450 +3 2437 2442 2450 +3 2442 2533 2450 +3 2441 2533 2442 +3 8352 8104 8342 +3 8302 8095 8309 +3 8351 8111 8359 +3 8384 8116 8382 +3 7708 7613 8326 +3 7708 8326 8334 +3 7708 8334 7852 +3 8334 8342 7852 +3 8342 7996 7852 +3 8104 7996 8342 +3 8205 8104 8352 +3 8205 8352 8112 +3 8352 8360 8112 +3 8360 8004 8112 +3 7860 8004 8360 +3 7860 8360 8370 +3 7860 8370 7716 +3 8370 8374 7716 +3 8374 7623 7716 +3 7720 7623 8374 +3 7720 8374 8378 +3 7720 8378 7864 +3 8378 8382 7864 +3 8382 8008 7864 +3 8116 8008 8382 +3 8208 8116 8384 +3 8208 8384 8115 +3 8384 8381 8115 +3 8381 8007 8115 +3 7863 8007 8381 +3 7863 8381 8377 +3 7863 8377 7719 +3 8377 8373 7719 +3 8373 7622 7719 +3 7715 7622 8373 +3 7715 8373 8369 +3 7715 8369 7859 +3 8369 8359 7859 +3 8359 8003 7859 +3 8111 8003 8359 +3 8204 8111 8351 +3 8204 8351 8103 +3 8351 8341 8103 +3 8341 7995 8103 +3 7851 7995 8341 +3 7851 8341 8333 +3 7851 8333 7707 +3 8333 8325 7707 +3 8325 7612 7707 +3 7699 7612 8325 +3 7699 8325 8317 +3 7699 8317 7843 +3 8317 8309 7843 +3 8309 7987 7843 +3 8095 7987 8309 +3 8196 8095 8302 +3 8196 8302 8096 +3 8302 8310 8096 +3 8310 7988 8096 +3 7844 7988 8310 +3 7844 8310 8318 +3 7844 8318 7700 +3 8318 8326 7700 +3 8326 7613 7700 +3 75 444 73 +3 54 439 44 +3 5 437 13 +3 45 536 440 +3 669 536 45 +3 669 45 37 +3 669 37 805 +3 37 29 805 +3 29 922 805 +3 802 922 29 +3 802 29 21 +3 802 21 666 +3 21 13 666 +3 13 533 666 +3 437 533 13 +3 364 437 5 +3 364 5 436 +3 5 12 436 +3 12 532 436 +3 665 532 12 +3 665 12 20 +3 665 20 801 +3 20 28 801 +3 28 921 801 +3 804 921 28 +3 804 28 36 +3 804 36 668 +3 36 44 668 +3 44 535 668 +3 439 535 44 +3 367 439 54 +3 367 54 442 +3 54 60 442 +3 60 538 442 +3 671 538 60 +3 671 60 64 +3 671 64 807 +3 64 67 807 +3 67 925 807 +3 809 925 67 +3 809 67 71 +3 809 71 673 +3 71 73 673 +3 73 540 673 +3 444 540 73 +3 370 444 75 +3 370 75 445 +3 75 74 445 +3 74 541 445 +3 674 541 74 +3 674 74 72 +3 674 72 810 +3 72 68 810 +3 68 926 810 +3 808 926 68 +3 808 68 65 +3 808 65 672 +3 65 61 672 +3 61 539 672 +3 443 539 61 +3 443 61 55 +3 443 55 368 +3 55 440 368 +3 45 440 55 +3 2743 1737 1638 +3 1737 2639 1870 +3 2003 1870 2534 +3 2003 2451 2099 +3 2099 2391 2202 +3 1739 2840 1641 +3 2103 2455 2204 +3 2204 2393 2102 +3 2102 2454 2006 +3 2537 1873 2006 +3 1873 2642 1740 +3 1740 2746 1640 +3 1640 2839 1738 +3 1738 2744 1871 +3 2640 2004 1871 +3 2004 2535 2100 +3 2000 2448 2096 +3 2096 2389 2200 +3 2200 2449 2097 +3 2532 2001 2097 +3 1868 2001 2637 +3 1735 1868 2741 +3 1735 2837 1638 +3 2742 1869 2638 +3 2638 2002 2533 +3 2098 2201 2390 +3 2201 2100 2390 +3 2100 2452 2390 +3 2535 2452 2100 +3 2640 2535 2004 +3 2744 2640 1871 +3 2839 2744 1738 +3 2746 2839 1640 +3 2642 2746 1740 +3 2537 2642 1873 +3 2454 2537 2006 +3 2393 2454 2102 +3 2455 2393 2204 +3 2538 2455 2103 +3 2538 2103 2007 +3 2538 2007 2643 +3 2007 1874 2643 +3 1874 2747 2643 +3 1641 2747 1741 +3 2747 1874 1741 +3 2840 2747 1641 +3 2745 2840 1739 +3 2745 1739 2641 +3 2005 2641 1872 +3 2641 1739 1872 +3 2536 2641 2005 +3 2536 2005 2453 +3 2202 2453 2101 +3 2453 2005 2101 +3 2391 2453 2202 +3 2451 2391 2099 +3 2534 2451 2003 +3 2639 2534 1870 +3 2743 2639 1737 +3 2837 2743 1638 +3 2741 2837 1735 +3 2637 2741 1868 +3 2532 2637 2001 +3 2449 2532 2097 +3 2389 2449 2200 +3 2448 2389 2096 +3 2531 2448 2000 +3 2531 2000 1867 +3 2531 1867 2636 +3 2740 1867 1734 +3 2636 1867 2740 +3 2533 2098 2450 +3 2098 2390 2450 +3 2002 2098 2533 +3 1869 2002 2638 +3 1736 1869 2742 +3 1736 2742 2836 +3 1736 2836 1637 +3 2836 1734 1637 +3 2740 1734 2836 +3 3494 4827 3576 +3 3576 4716 3709 +3 4572 3832 3709 +3 3832 4428 3932 +3 4031 3932 4320 +3 4031 4249 3939 +3 3839 3939 4328 +3 4436 3716 3839 +3 3583 3716 4580 +3 3502 3583 4724 +3 3502 4837 3587 +3 4732 3720 3587 +3 3843 3720 4588 +3 3843 4444 3943 +3 4443 3842 3942 +3 3719 3842 4587 +3 3719 4731 3586 +3 3586 4836 3501 +3 4723 3582 3501 +3 3582 4579 3715 +3 4435 3838 3715 +3 4030 4248 3931 +3 3568 4707 3701 +3 3701 4563 3824 +3 4419 3924 3824 +3 3924 4311 4024 +3 4024 4240 3925 +3 3825 3925 4312 +3 3702 3825 4420 +3 3569 3702 4564 +3 3494 3569 4708 +3 4826 3568 3493 +3 4826 3493 4715 +3 3708 4715 3575 +3 4715 3493 3575 +3 4571 4715 3708 +3 4571 3708 3831 +3 4571 3831 4427 +3 3831 3931 4427 +3 3931 4319 4427 +3 4248 4319 3931 +3 4327 4248 4030 +3 3838 4327 3938 +3 4327 4030 3938 +3 4435 4327 3838 +3 4579 4435 3715 +3 4723 4579 3582 +3 4836 4723 3501 +3 4731 4836 3586 +3 4587 4731 3719 +3 4443 4587 3842 +3 4335 4443 3942 +3 4335 3942 4254 +3 3942 4034 4254 +3 4034 3943 4254 +3 3943 4336 4254 +3 4444 4336 3943 +3 4588 4444 3843 +3 4732 4588 3720 +3 4837 4732 3587 +3 4724 4837 3502 +3 4580 4724 3583 +3 4436 4580 3716 +3 4328 4436 3839 +3 4249 4328 3939 +3 4320 4249 4031 +3 4428 4320 3932 +3 4572 4428 3832 +3 4716 4572 3709 +3 4827 4716 3576 +3 4708 4827 3494 +3 4564 4708 3569 +3 4420 4564 3702 +3 4312 4420 3825 +3 4240 4312 3925 +3 4311 4240 4024 +3 4419 4311 3924 +3 4563 4419 3824 +3 4707 4563 3701 +3 4826 4707 3568 +3 6078 6175 6249 +3 6078 6326 5974 +3 5830 5974 6438 +3 5830 6582 5686 +3 6722 5597 5686 +3 5597 6837 5694 +3 5694 6730 5838 +3 5838 6590 5982 +3 6446 6086 5982 +3 6086 6334 6180 +3 6180 6254 6085 +3 6085 6333 5981 +3 6445 5837 5981 +3 5685 6721 5829 +3 5829 6581 5973 +3 5973 6437 6077 +3 5669 6705 5813 +3 6061 6240 6166 +3 6166 6310 6062 +3 6422 5958 6062 +3 5958 6566 5814 +3 6706 5670 5814 +3 5670 6827 5587 +3 6713 5821 6573 +3 6573 5965 6429 +3 6317 6429 6069 +3 6077 6325 6174 +3 6437 6325 6077 +3 6581 6437 5973 +3 6721 6581 5829 +3 6836 6721 5685 +3 6836 5685 5596 +3 6836 5596 6729 +3 5596 5693 6729 +3 5693 5837 6729 +3 5837 6589 6729 +3 6445 6589 5837 +3 6333 6445 5981 +3 6254 6333 6085 +3 6334 6254 6180 +3 6446 6334 6086 +3 6590 6446 5982 +3 6730 6590 5838 +3 6837 6730 5694 +3 6722 6837 5597 +3 6582 6722 5686 +3 6438 6582 5830 +3 6326 6438 5974 +3 6249 6326 6078 +3 6318 6249 6175 +3 6318 6175 6070 +3 6318 6070 6430 +3 5822 6430 5966 +3 6430 6070 5966 +3 6574 6430 5822 +3 6574 5822 6714 +3 5587 6714 5678 +3 6714 5822 5678 +3 6827 6714 5587 +3 6706 6827 5670 +3 6566 6706 5814 +3 6422 6566 5958 +3 6310 6422 6062 +3 6240 6310 6166 +3 6309 6240 6061 +3 6309 6061 5957 +3 6309 5957 6421 +3 5957 5813 6421 +3 5813 6565 6421 +3 6705 6565 5813 +3 6317 6174 6248 +3 6174 6325 6248 +3 6069 6174 6317 +3 5965 6069 6429 +3 5821 5965 6573 +3 5677 5821 6713 +3 5677 6713 6826 +3 5677 6826 5586 +3 6826 5669 5586 +3 6705 5669 6826 +3 1296 1288 1234 +3 1022 951 1028 +3 951 942 890 +3 754 890 889 +3 753 652 754 +3 652 651 520 +3 651 519 520 +3 753 651 652 +3 889 753 754 +3 942 889 890 +3 1022 942 951 +3 1102 1022 1028 +3 1102 1028 1108 +3 1102 1108 1180 +3 1108 1186 1180 +3 1186 1234 1180 +3 1234 1228 1180 +3 1288 1228 1234 +3 1358 1288 1296 +3 1358 1296 1364 +3 1358 1364 1410 +3 1498 1410 1416 +3 1410 1364 1416 +3 1492 1410 1498 +3 1492 1498 1582 +3 1492 1582 1576 +3 1582 1666 1576 +3 1666 1657 1576 +3 1719 1657 1666 +3 1719 1666 1720 +3 1719 1720 1852 +3 1719 1852 1851 +3 1852 1956 1851 +3 1956 1955 1851 +3 2088 1955 1956 +3 2088 1956 2089 +3 1667 1614 1712 +3 897 995 952 +3 996 898 961 +3 1615 1676 1713 +3 1926 1918 2051 +3 1918 1793 1785 +3 1505 1513 1423 +3 1423 1431 1371 +3 1371 1379 1305 +3 1241 1305 1317 +3 1115 1043 1035 +3 585 593 490 +3 490 498 396 +3 396 400 489 +3 489 497 584 +3 592 717 584 +3 717 725 853 +3 853 861 961 +3 1210 1248 1307 +3 1596 1686 1607 +3 1512 1470 1430 +3 1430 1389 1378 +3 1200 1210 1132 +3 1248 1210 1200 +3 1051 1122 1085 +3 1122 1132 1085 +3 1200 1132 1122 +3 1001 1042 1004 +3 1042 1051 1004 +3 1122 1051 1042 +3 971 1001 998 +3 1042 1001 971 +3 996 961 997 +3 961 971 997 +3 971 998 997 +3 861 971 961 +3 725 861 853 +3 592 725 717 +3 497 592 584 +3 400 497 489 +3 498 400 396 +3 593 498 490 +3 726 593 585 +3 726 585 718 +3 726 718 862 +3 718 854 862 +3 854 972 862 +3 1035 972 962 +3 972 854 962 +3 1043 972 1035 +3 1123 1043 1115 +3 1123 1115 1193 +3 1123 1193 1201 +3 1193 1241 1201 +3 1241 1249 1201 +3 1317 1249 1241 +3 1379 1317 1305 +3 1431 1379 1371 +3 1513 1431 1423 +3 1597 1513 1505 +3 1597 1505 1589 +3 1597 1589 1687 +3 1785 1687 1677 +3 1687 1589 1677 +3 1793 1687 1785 +3 1926 1793 1918 +3 2059 1926 2051 +3 2059 2051 2148 +3 2059 2148 2156 +3 2234 2148 2230 +3 2156 2148 2234 +3 2050 2155 2147 +3 2155 2230 2147 +3 2234 2230 2155 +3 2058 2050 1917 +3 2155 2050 2058 +3 1925 1917 1784 +3 2058 1917 1925 +3 1792 1784 1676 +3 1925 1784 1792 +3 1378 1307 1316 +3 1307 1248 1316 +3 1389 1307 1378 +3 1470 1389 1430 +3 1521 1470 1512 +3 1521 1512 1557 +3 1512 1596 1557 +3 1596 1604 1557 +3 1607 1604 1596 +3 1610 1607 1686 +3 1610 1686 1616 +3 1686 1676 1616 +3 1676 1615 1616 +3 1792 1676 1686 +3 1649 1612 1710 +3 934 895 993 +3 994 896 943 +3 1613 1658 1711 +3 1893 1899 2026 +3 2123 2129 2027 +3 1761 1668 1659 +3 1659 1583 1577 +3 1499 1493 1577 +3 1493 1417 1411 +3 1411 1365 1359 +3 1359 1297 1289 +3 1289 1235 1229 +3 1229 1187 1181 +3 1181 1109 1103 +3 830 944 953 +3 694 830 836 +3 694 700 561 +3 465 561 567 +3 471 382 465 +3 382 385 464 +3 560 464 470 +3 560 566 693 +3 693 699 829 +3 829 835 943 +3 943 952 994 +3 952 995 994 +3 835 952 943 +3 699 835 829 +3 566 699 693 +3 470 566 560 +3 385 470 464 +3 471 385 382 +3 567 471 465 +3 700 567 561 +3 836 700 694 +3 953 836 830 +3 1029 953 944 +3 1103 1029 1023 +3 1029 944 1023 +3 1109 1029 1103 +3 1187 1109 1181 +3 1235 1187 1229 +3 1297 1235 1289 +3 1365 1297 1359 +3 1417 1365 1411 +3 1499 1417 1493 +3 1583 1499 1577 +3 1668 1583 1659 +3 1767 1668 1761 +3 1767 1761 1894 +3 1767 1894 1900 +3 1894 2027 1900 +3 2027 2033 1900 +3 2129 2033 2027 +3 2219 2129 2123 +3 2219 2123 2216 +3 2219 2216 2122 +3 2219 2122 2128 +3 2122 2026 2128 +3 2026 2032 2128 +3 1899 2032 2026 +3 1766 1899 1893 +3 1766 1893 1760 +3 1766 1760 1667 +3 1760 1658 1667 +3 1658 1613 1667 +3 1613 1614 1667 +3 1740 1875 1873 +3 2006 1873 2008 +3 2102 2006 2104 +3 2102 2205 2204 +3 2105 2103 2204 +3 2103 2009 2007 +3 2007 1876 1874 +3 1874 1743 1741 +3 1487 1403 1485 +3 1403 1405 1351 +3 1351 1353 1277 +3 1095 1173 1097 +3 1095 1017 1015 +3 674 676 541 +3 543 445 541 +3 445 447 370 +3 370 371 444 +3 444 446 540 +3 540 542 673 +3 809 673 675 +3 999 1002 925 +3 999 925 992 +3 993 992 934 +3 992 925 934 +3 925 809 934 +3 809 811 934 +3 675 811 809 +3 542 675 673 +3 446 542 540 +3 371 446 444 +3 447 371 370 +3 543 447 445 +3 676 543 541 +3 812 676 674 +3 812 674 810 +3 812 810 935 +3 1015 935 926 +3 935 810 926 +3 1017 935 1015 +3 1097 1017 1095 +3 1175 1097 1173 +3 1175 1173 1221 +3 1175 1221 1223 +3 1221 1277 1223 +3 1277 1281 1223 +3 1353 1281 1277 +3 1405 1353 1351 +3 1487 1405 1403 +3 1571 1487 1485 +3 1571 1485 1569 +3 1571 1569 1650 +3 1741 1650 1641 +3 1650 1569 1641 +3 1743 1650 1741 +3 1876 1743 1874 +3 2009 1876 2007 +3 2105 2009 2103 +3 2205 2105 2204 +3 2104 2205 2102 +3 2008 2104 2006 +3 1875 2008 1873 +3 1742 1875 1740 +3 1742 1740 1640 +3 1742 1640 1649 +3 1640 1611 1649 +3 1611 1612 1649 +3 1609 1611 1640 +3 1609 1640 1606 +3 1636 1567 1566 +3 1400 1349 1348 +3 1092 1170 1171 +3 1012 1092 1093 +3 1012 1013 920 +3 920 921 887 +3 751 887 804 +3 751 668 648 +3 420 442 524 +3 524 538 655 +3 757 655 671 +3 757 807 893 +3 893 925 1002 +3 807 925 893 +3 671 807 757 +3 538 671 655 +3 442 538 524 +3 367 442 420 +3 367 420 418 +3 367 418 439 +3 418 421 439 +3 421 427 439 +3 427 535 439 +3 648 535 426 +3 535 427 426 +3 668 535 648 +3 804 668 751 +3 921 804 887 +3 1013 921 920 +3 1093 1013 1012 +3 1171 1093 1092 +3 1219 1171 1170 +3 1219 1170 1218 +3 1219 1218 1274 +3 1348 1274 1273 +3 1274 1218 1273 +3 1349 1274 1348 +3 1401 1349 1400 +3 1401 1400 1482 +3 1401 1482 1483 +3 1482 1566 1483 +3 1566 1567 1483 +3 1637 1636 1726 +3 1567 1636 1637 +3 1736 1726 1858 +3 1637 1726 1736 +3 1869 1858 1964 +3 1736 1858 1869 +3 2002 1964 2182 +3 1869 1964 2002 +3 2098 2190 2201 +3 2201 2187 2100 +3 2100 2081 2004 +3 2004 1949 1871 +3 1871 1847 1738 +3 1738 1714 1640 +3 1714 1606 1640 +3 1847 1714 1738 +3 1949 1847 1871 +3 2081 1949 2004 +3 2187 2081 2100 +3 2190 2187 2201 +3 2184 2190 2098 +3 2184 2098 2183 +3 2098 2002 2183 +3 2002 2182 2183 +3 2956 2958 3028 +3 3028 3030 3103 +3 3222 3274 3272 +3 3272 3321 3319 +3 3319 3395 3393 +3 3467 3465 3393 +3 3465 3504 3499 +3 3941 4033 3945 +3 3941 3845 3841 +3 3841 3722 3718 +3 3500 3468 3466 +3 3466 3396 3394 +3 3394 3322 3320 +3 3320 3275 3273 +3 3273 3225 3223 +3 3223 3153 3151 +3 3151 3106 3104 +3 3104 3031 3029 +3 3029 2959 2957 +3 2957 2895 2889 +3 2959 2895 2957 +3 3031 2959 3029 +3 3106 3031 3104 +3 3153 3106 3151 +3 3225 3153 3223 +3 3275 3225 3273 +3 3322 3275 3320 +3 3396 3322 3394 +3 3468 3396 3466 +3 3505 3468 3500 +3 3505 3500 3589 +3 3718 3589 3585 +3 3589 3500 3585 +3 3722 3589 3718 +3 3845 3722 3841 +3 3945 3845 3941 +3 4035 3945 4033 +3 4035 4033 3940 +3 4035 3940 3944 +3 3940 3840 3944 +3 3840 3844 3944 +3 3721 3844 3840 +3 3721 3840 3717 +3 3721 3717 3588 +3 3499 3588 3584 +3 3588 3717 3584 +3 3504 3588 3499 +3 3467 3504 3465 +3 3395 3467 3393 +3 3321 3395 3319 +3 3274 3321 3272 +3 3224 3274 3222 +3 3224 3222 3150 +3 3224 3150 3152 +3 3150 3103 3152 +3 3103 3105 3152 +3 3030 3105 3103 +3 2958 3030 3028 +3 2894 2958 2956 +3 2894 2956 2888 +3 3695 3692 3665 +3 3559 3665 3659 +3 3559 3555 3498 +3 3555 3478 3498 +3 3659 3555 3559 +3 3692 3659 3665 +3 3798 3692 3695 +3 2351 1880 1747 +3 1886 2710 1753 +3 1656 1753 2814 +3 1759 1656 2848 +3 1759 2756 1892 +3 1892 2652 2025 +3 2025 2547 2121 +3 2121 2464 2215 +3 2120 2215 2399 +3 2120 2463 2024 +3 2546 1891 2024 +3 1655 2813 1752 +3 1885 1752 2709 +3 2626 2018 1885 +3 2286 1646 1746 +3 1706 1646 2286 +3 2350 1746 1879 +3 2286 1746 2350 +3 2108 2364 2012 +3 2364 1879 2012 +3 2350 1879 2364 +3 2521 2108 2209 +3 2364 2108 2521 +3 2018 2521 2114 +3 2521 2209 2114 +3 2626 2521 2018 +3 2709 2626 1885 +3 2813 2709 1752 +3 2847 2813 1655 +3 2847 1655 2755 +3 1655 1758 2755 +3 1758 1891 2755 +3 1891 2651 2755 +3 2546 2651 1891 +3 2463 2546 2024 +3 2399 2463 2120 +3 2464 2399 2215 +3 2547 2464 2121 +3 2652 2547 2025 +3 2756 2652 1892 +3 2848 2756 1759 +3 2814 2848 1656 +3 2710 2814 1753 +3 2627 2710 1886 +3 2627 1886 2019 +3 2627 2019 2522 +3 2019 2115 2522 +3 2115 2210 2522 +3 2210 2109 2522 +3 2109 2365 2522 +3 1880 2365 2013 +3 2365 2109 2013 +3 2351 2365 1880 +3 1707 2287 1647 +3 2287 1747 1647 +3 2351 1747 2287 +3 990 932 903 +3 902 931 989 +3 1646 1706 1619 +3 1647 1620 1707 +3 678 679 545 +3 545 546 449 +3 449 450 374 +3 374 375 455 +3 684 821 820 +3 820 940 939 +3 1020 1019 939 +3 1019 1100 1099 +3 1177 1099 1178 +3 1226 1225 1177 +3 1225 1286 1285 +3 1489 1490 1573 +3 1573 1574 1654 +3 1654 1655 1751 +3 1751 1752 1884 +3 1884 1885 2017 +3 2017 2018 2113 +3 2012 2011 2107 +3 1879 1878 2011 +3 1878 1746 1745 +3 1646 1619 1618 +3 1745 1646 1645 +3 1646 1618 1645 +3 1746 1646 1745 +3 1879 1746 1878 +3 2012 1879 2011 +3 2108 2012 2107 +3 2108 2107 2209 +3 2107 2208 2209 +3 2208 2113 2209 +3 2113 2114 2209 +3 2018 2114 2113 +3 1885 2018 2017 +3 1752 1885 1884 +3 1655 1752 1751 +3 1574 1655 1654 +3 1490 1574 1573 +3 1408 1490 1489 +3 1408 1489 1407 +3 1408 1407 1356 +3 1285 1356 1355 +3 1356 1407 1355 +3 1286 1356 1285 +3 1226 1286 1225 +3 1178 1226 1177 +3 1100 1178 1099 +3 1020 1100 1019 +3 940 1020 939 +3 821 940 820 +3 685 821 684 +3 685 684 551 +3 685 551 552 +3 551 455 552 +3 455 456 552 +3 375 456 455 +3 450 375 374 +3 546 450 449 +3 679 546 545 +3 815 679 678 +3 815 678 814 +3 815 814 931 +3 988 931 930 +3 931 814 930 +3 989 931 988 +3 1335 1280 1341 +3 1341 1352 1388 +3 1388 1404 1438 +3 1948 1953 8627 +3 1849 1953 1948 +3 1849 1948 1814 +3 1849 1814 1717 +3 1814 1617 1717 +3 1617 1644 1717 +3 1570 1644 1617 +3 1570 1617 1556 +3 1570 1556 1486 +3 1174 1131 1096 +3 929 924 891 +3 791 793 924 +3 521 653 654 +3 653 756 654 +3 756 755 654 +3 790 755 756 +3 790 756 891 +3 790 891 794 +3 891 793 794 +3 924 793 891 +3 1006 924 929 +3 1006 929 1016 +3 1006 1016 1083 +3 1016 1096 1083 +3 1096 1131 1083 +3 1211 1174 1222 +3 1131 1174 1211 +3 1333 1222 1280 +3 1211 1222 1333 +3 1438 1486 1476 +3 1486 1556 1476 +3 1404 1486 1438 +3 1352 1404 1388 +3 1280 1352 1341 +3 1333 1280 1335 +3 1333 1335 1336 +3 1333 1336 1342 +3 1333 1342 1393 +3 1342 1391 1393 +3 1391 1475 1393 +3 1525 1475 1391 +3 1705 1645 1618 +3 988 930 901 +3 93 932 99 +3 99 816 105 +3 680 110 105 +3 115 457 121 +3 133 941 140 +3 151 558 144 +3 130 821 124 +3 124 685 118 +3 100 815 92 +3 92 931 902 +3 815 931 92 +3 679 815 100 +3 679 100 106 +3 679 106 546 +3 106 112 546 +3 112 450 546 +3 375 450 112 +3 375 112 456 +3 112 118 456 +3 118 552 456 +3 685 552 118 +3 821 685 124 +3 940 821 130 +3 940 130 137 +3 940 137 827 +3 137 144 827 +3 144 691 827 +3 558 691 144 +3 462 558 151 +3 462 151 381 +3 151 155 381 +3 155 463 381 +3 559 463 155 +3 559 155 148 +3 559 148 692 +3 148 140 692 +3 140 828 692 +3 941 828 140 +3 822 941 133 +3 822 133 127 +3 822 127 686 +3 127 121 686 +3 121 553 686 +3 457 553 121 +3 376 457 115 +3 376 115 451 +3 115 110 451 +3 110 547 451 +3 680 547 110 +3 816 680 105 +3 932 816 99 +3 903 932 93 +3 1621 1648 1708 +3 547 680 681 +3 457 458 553 +3 822 942 941 +3 941 1022 1021 +3 1021 1102 1101 +3 1491 1492 1575 +3 1575 1576 1656 +3 1753 1656 1657 +3 1886 1753 1754 +3 1886 1887 2019 +3 1880 1748 1747 +3 1621 1620 1648 +3 1747 1648 1647 +3 1648 1620 1647 +3 1748 1648 1747 +3 1881 1748 1880 +3 1881 1880 2013 +3 1881 2013 2014 +3 2013 2109 2014 +3 2109 2110 2014 +3 2211 2110 2109 +3 2211 2109 2210 +3 2211 2210 2115 +3 2211 2115 2116 +3 2115 2019 2116 +3 2019 2020 2116 +3 1887 2020 2019 +3 1754 1887 1886 +3 1657 1754 1753 +3 1576 1657 1656 +3 1492 1576 1575 +3 1410 1492 1491 +3 1410 1491 1409 +3 1410 1409 1357 +3 1410 1357 1358 +3 1357 1287 1358 +3 1287 1288 1358 +3 1228 1288 1287 +3 1228 1287 1227 +3 1228 1227 1180 +3 1101 1180 1179 +3 1180 1227 1179 +3 1102 1180 1101 +3 1022 1102 1021 +3 942 1022 941 +3 823 942 822 +3 823 822 686 +3 823 686 687 +3 686 553 687 +3 553 554 687 +3 458 554 553 +3 377 458 457 +3 377 457 376 +3 377 376 451 +3 377 451 452 +3 451 547 452 +3 547 548 452 +3 681 548 547 +3 817 681 680 +3 817 680 816 +3 817 816 933 +3 990 933 932 +3 933 816 932 +3 991 933 990 +3 796 15 660 +3 526 14 659 +3 659 22 795 +3 62 806 670 +3 806 66 924 +3 924 70 791 +3 66 70 924 +3 62 66 806 +3 59 62 670 +3 59 670 537 +3 59 537 441 +3 59 441 56 +3 441 366 56 +3 366 438 56 +3 438 46 56 +3 667 46 534 +3 46 438 534 +3 38 46 667 +3 38 667 803 +3 38 803 30 +3 795 30 915 +3 30 803 915 +3 22 30 795 +3 14 22 659 +3 6 14 526 +3 6 526 430 +3 6 430 361 +3 6 361 431 +3 6 431 7 +3 660 7 527 +3 7 431 527 +3 15 7 660 +3 23 15 796 +3 23 796 916 +3 23 916 31 +3 747 31 883 +3 31 916 883 +3 39 31 747 +3 39 747 644 +3 39 644 47 +3 644 422 47 +3 749 646 41 +3 798 17 662 +3 24 917 797 +3 645 48 423 +3 40 48 645 +3 40 645 748 +3 40 748 32 +3 917 32 884 +3 32 748 884 +3 24 32 917 +3 16 24 797 +3 16 797 661 +3 16 661 8 +3 432 8 528 +3 8 661 528 +3 3 8 432 +3 3 432 362 +3 3 362 433 +3 3 433 9 +3 662 9 529 +3 9 433 529 +3 17 9 662 +3 25 17 798 +3 25 798 918 +3 25 918 33 +3 749 33 885 +3 33 918 885 +3 41 33 749 +3 49 41 646 +3 49 646 424 +3 1961 1960 2178 +3 1960 1855 1854 +3 1854 1723 1722 +3 1722 1633 1632 +3 1632 1563 1562 +3 1562 1479 1478 +3 1478 1397 1396 +3 1396 1345 1344 +3 1344 1270 1269 +3 1088 1089 1008 +3 1009 916 1008 +3 916 917 883 +3 883 884 747 +3 747 748 644 +3 644 645 422 +3 645 423 422 +3 748 645 644 +3 884 748 747 +3 917 884 883 +3 1009 917 916 +3 1089 1009 1008 +3 1167 1089 1088 +3 1167 1088 1166 +3 1167 1166 1215 +3 1269 1215 1214 +3 1215 1166 1214 +3 1270 1215 1269 +3 1345 1270 1344 +3 1397 1345 1396 +3 1479 1397 1478 +3 1563 1479 1562 +3 1633 1563 1632 +3 1723 1633 1722 +3 1855 1723 1854 +3 1961 1855 1960 +3 2179 1961 2178 +3 1857 1856 1962 +3 1856 1725 1724 +3 1724 1635 1634 +3 1565 1564 1634 +3 1481 1480 1564 +3 1271 1346 1347 +3 1090 1091 1010 +3 918 1010 1011 +3 918 919 885 +3 749 885 886 +3 750 646 749 +3 424 646 425 +3 646 647 425 +3 750 647 646 +3 886 750 749 +3 919 886 885 +3 1011 919 918 +3 1091 1011 1010 +3 1169 1091 1090 +3 1169 1090 1168 +3 1169 1168 1216 +3 1169 1216 1217 +3 1216 1271 1217 +3 1271 1272 1217 +3 1347 1272 1271 +3 1399 1347 1346 +3 1480 1399 1398 +3 1399 1346 1398 +3 1481 1399 1480 +3 1565 1481 1564 +3 1635 1565 1634 +3 1725 1635 1724 +3 1857 1725 1856 +3 1963 1857 1962 +3 1963 1962 2181 +3 1962 2180 2181 +3 76 794 793 +3 78 794 76 +3 2088 2089 2514 +3 2088 2514 2513 +3 2911 1308 250 +3 1716 1709 2815 +3 1716 2815 1846 +3 1846 2711 1947 +3 1958 1947 2628 +3 1958 2570 2082 +3 2082 2438 2177 +3 2189 2177 2413 +3 2189 2435 2146 +3 2435 2485 2146 +3 2413 2435 2189 +3 2438 2413 2177 +3 2570 2438 2082 +3 2628 2570 1958 +3 2711 2628 1947 +3 2815 2711 1846 +3 241 419 237 +3 419 488 237 +3 429 419 241 +3 429 241 243 +3 429 243 523 +3 243 245 523 +3 245 650 523 +3 658 650 245 +3 658 245 247 +3 658 247 758 +3 247 892 758 +3 900 892 247 +3 900 247 249 +3 900 249 1003 +3 249 1050 1003 +3 1086 1050 249 +3 1086 249 250 +3 1086 250 1134 +3 250 1212 1134 +3 1308 1212 250 +3 1387 1308 2911 +3 1387 2911 1469 +3 2911 2910 1469 +3 2910 1520 1469 +3 1558 1520 2910 +3 1558 2910 1605 +3 2910 2908 1605 +3 2908 1709 1605 +3 2815 1709 2908 +3 994 134 896 +3 180 134 994 +3 180 994 995 +3 180 995 897 +3 2184 2433 2190 +3 2190 2434 2187 +3 2515 2081 2187 +3 2081 2620 1949 +3 1949 2704 1847 +3 1847 2808 1714 +3 2890 1606 1714 +3 1606 2891 1609 +3 1609 2892 1611 +3 2891 2892 1609 +3 2890 2891 1606 +3 2808 2890 1714 +3 2704 2808 1847 +3 2620 2704 1949 +3 2515 2620 2081 +3 2434 2515 2187 +3 2433 2434 2190 +3 2437 2433 2184 +3 2437 2184 2183 +3 2437 2183 2442 +3 2892 2895 2896 +3 2889 2895 2892 +3 2889 2892 2891 +3 2889 2891 2890 +3 94 904 93 +3 904 903 93 +3 990 903 904 +3 990 904 991 +3 755 80 654 +3 83 521 81 +3 521 654 81 +3 654 80 81 +3 79 755 790 +3 80 755 79 +3 78 790 794 +3 79 790 78 +3 153 160 520 +3 153 520 519 +3 1710 2892 2817 +3 2892 2896 2817 +3 1611 2892 1710 +3 1611 1710 1612 +3 95 77 895 +3 77 992 895 +3 992 993 895 +3 215 898 223 +3 898 997 223 +3 996 997 898 +3 2903 2820 2902 +3 1713 2820 2903 +3 1713 2903 1616 +3 1713 1616 1615 +3 2900 2819 1712 +3 2900 1712 1614 +3 2900 1614 2898 +3 1614 1613 2898 +3 1613 1711 2898 +3 1711 2818 2898 +3 2887 2894 2888 +3 2893 2894 2887 +3 2897 2899 2900 +3 2897 2900 2898 +3 2902 2906 2903 +3 2901 2911 2912 +3 2910 2911 2901 +3 2910 2901 2908 +3 2903 2905 2904 +3 2906 2905 2903 +3 2907 2906 2902 +3 2907 2902 2909 +3 2902 2912 2909 +3 2901 2912 2902 +3 2886 2885 2288 +3 2886 2288 2821 +3 2288 1708 2821 +3 1621 1708 2288 +3 1621 2288 1620 +3 1707 1620 2287 +3 1620 2288 2287 +3 91 92 902 +3 91 902 901 +3 902 988 901 +3 989 988 902 +3 1619 1706 1618 +3 1706 1705 1618 +3 2285 1705 1706 +3 2285 1706 2286 +3 2442 2183 2182 +3 2442 2182 2441 +3 427 52 51 +3 427 51 426 +3 49 424 425 +3 49 425 50 +3 2254 2179 2178 +3 2254 2178 2253 +3 48 47 422 +3 48 422 423 +3 2912 2911 251 +3 2911 250 251 +3 2909 251 248 +3 2912 251 2909 +3 2907 248 246 +3 2909 248 2907 +3 1307 2906 244 +3 2906 246 244 +3 2907 246 2906 +3 2904 1610 2903 +3 1610 1616 2903 +3 1607 1610 2904 +3 1607 2904 1604 +3 2904 2905 1604 +3 2905 1557 1604 +3 1521 1557 2905 +3 1521 2905 1470 +3 2905 2906 1470 +3 2906 1389 1470 +3 1307 1389 2906 +3 1210 1307 244 +3 1210 244 1132 +3 244 242 1132 +3 242 1085 1132 +3 1051 1085 242 +3 1051 242 1004 +3 242 240 1004 +3 240 1001 1004 +3 998 1001 240 +3 998 240 223 +3 998 223 997 +3 418 57 53 +3 69 999 77 +3 999 992 77 +3 1002 999 69 +3 1002 69 893 +3 69 63 893 +3 63 757 893 +3 655 757 63 +3 655 63 58 +3 655 58 524 +3 58 57 524 +3 57 420 524 +3 418 420 57 +3 421 418 53 +3 421 53 52 +3 421 52 427 +3 76 793 791 +3 76 791 70 +3 3557 3663 3657 +3 3557 3553 3496 +3 3553 3476 3496 +3 3657 3553 3557 +3 3690 3657 3663 +3 3690 3663 3693 +3 3690 3693 3796 +3 4102 4717 4573 +3 4330 4080 4438 +3 4438 3796 4582 +3 3496 4718 4831 +3 4718 3577 4574 +3 4574 3710 4430 +3 4322 4430 3833 +3 4322 3933 4243 +3 4243 4025 4314 +3 4422 4314 3926 +3 4422 3826 4566 +3 4710 4566 3703 +3 3570 4821 4710 +3 4702 4821 3488 +3 4306 4414 3919 +3 4557 4096 4701 +3 4106 4083 4330 +3 4106 4330 4251 +3 4106 4251 4329 +3 4106 4329 4105 +3 4581 4105 4437 +3 4105 4329 4437 +3 4104 4105 4581 +3 4104 4581 4725 +3 4104 4725 4103 +3 4717 4103 4830 +3 4103 4725 4830 +3 4102 4103 4717 +3 4101 4102 4573 +3 4321 4101 4429 +3 4101 4573 4429 +3 4100 4101 4321 +3 4313 4100 4242 +3 4100 4321 4242 +3 4099 4100 4313 +3 4099 4313 4421 +3 4099 4421 4565 +3 4099 4565 4098 +3 4565 4709 4098 +3 4709 4097 4098 +3 4701 4097 4820 +3 4097 4709 4820 +3 4096 4097 4701 +3 4095 4096 4557 +3 4095 4557 4413 +3 4095 4413 4305 +3 4095 4305 4094 +3 3919 4021 4094 +3 4306 4094 4237 +3 4094 4305 4237 +3 3919 4094 4306 +3 3819 3919 4414 +3 3819 4414 4558 +3 3819 4558 3696 +3 4558 4702 3696 +3 4702 3563 3696 +3 3488 3563 4702 +3 3570 3488 4821 +3 3703 3570 4710 +3 3826 3703 4566 +3 3926 3826 4422 +3 4025 3926 4314 +3 3933 4025 4243 +3 3833 3933 4322 +3 3710 3833 4430 +3 3577 3710 4574 +3 3496 3577 4718 +3 3557 3496 4831 +3 3557 4831 4726 +3 3557 4726 3663 +3 4726 4582 3663 +3 4582 3693 3663 +3 3796 3693 4582 +3 4080 3796 4438 +3 4083 4080 4330 +3 4086 4083 4106 +3 2622 2623 2517 +3 2919 2918 2991 +3 2990 3066 2991 +3 3066 3065 3113 +3 3112 3172 3113 +3 3172 3171 3235 +3 3234 3281 3235 +3 3428 3488 3489 +3 3489 3570 3571 +3 3571 3703 3704 +3 3827 3704 3826 +3 3578 3577 3497 +3 3477 3497 3476 +3 3497 3496 3476 +3 3577 3496 3497 +3 3710 3577 3578 +3 3710 3578 3711 +3 3710 3711 3833 +3 3711 3834 3833 +3 3834 3934 3833 +3 3934 3933 3833 +3 4025 3933 3934 +3 4025 3934 4026 +3 4025 4026 3926 +3 3827 3926 3927 +3 3926 4026 3927 +3 3826 3926 3827 +3 3703 3826 3704 +3 3570 3703 3571 +3 3488 3570 3489 +3 3427 3488 3428 +3 3427 3428 3356 +3 3427 3356 3355 +3 3356 3281 3355 +3 3281 3280 3355 +3 3234 3280 3281 +3 3171 3234 3235 +3 3112 3171 3172 +3 3065 3112 3113 +3 2990 3065 3066 +3 2918 2990 2991 +3 2831 2918 2919 +3 2831 2919 2832 +3 2831 2832 2809 +3 2832 2810 2809 +3 2810 2705 2809 +3 2623 2705 2706 +3 2705 2810 2706 +3 2622 2705 2623 +3 2516 2622 2517 +3 3558 3658 3664 +3 3664 3691 3694 +3 3691 3797 3694 +3 3658 3691 3664 +3 3554 3658 3558 +3 3554 3558 3497 +3 3554 3497 3477 +3 8098 8343 8347 +3 8311 7982 8303 +3 8321 7606 8329 +3 8353 7997 8362 +3 8269 7689 8265 +3 8265 7833 8261 +3 8261 7945 8257 +3 7945 8085 8257 +3 7833 7945 8261 +3 7689 7833 8265 +3 7616 7689 8269 +3 7616 8269 8287 +3 7616 8287 7709 +3 8287 8362 7709 +3 8362 7853 7709 +3 7997 7853 8362 +3 8105 7997 8353 +3 8105 8353 8198 +3 8353 8345 8198 +3 8345 8097 8198 +3 7989 8097 8345 +3 7989 8345 8337 +3 7989 8337 7845 +3 8337 8329 7845 +3 8329 7701 7845 +3 7606 7701 8329 +3 7693 7606 8321 +3 7693 8321 8313 +3 7693 8313 7837 +3 8313 8305 7837 +3 8305 7981 7837 +3 8089 7981 8305 +3 8089 8305 8303 +3 8089 8303 8193 +3 8303 8090 8193 +3 7982 8090 8303 +3 7838 7982 8311 +3 7838 8311 8319 +3 7838 8319 7694 +3 8319 8327 7694 +3 8327 7607 7694 +3 7702 7607 8327 +3 7702 8327 8335 +3 7702 8335 7846 +3 8335 8343 7846 +3 8343 7990 7846 +3 8098 7990 8343 +3 8199 8098 8347 +3 8199 8347 8106 +3 8347 8355 8106 +3 8355 7998 8106 +3 7854 7998 8355 +3 7854 8355 8363 +3 7854 8363 7710 +3 7690 8266 7834 +3 7834 8262 7946 +3 7946 8258 8086 +3 8262 8258 7946 +3 8266 8262 7834 +3 8270 8266 7690 +3 8270 7690 7617 +3 8270 7617 8288 +3 7617 7710 8288 +3 7710 8363 8288 +3 7617 7690 7686 +3 7617 7594 7546 +3 7502 7454 7546 +3 7454 7442 7362 +3 7104 7086 7006 +3 7006 6994 6912 +3 6912 6900 6831 +3 6831 6808 6724 +3 6724 6696 6584 +3 6584 6556 6440 +3 6440 6412 6328 +3 6327 6411 6439 +3 6439 6555 6583 +3 6583 6695 6723 +3 6723 6807 6830 +3 6830 6899 6911 +3 6911 6993 7005 +3 7005 7085 7103 +3 7361 7441 7453 +3 7501 7545 7453 +3 7616 7545 7593 +3 7685 7689 7616 +3 7833 7689 7829 +3 7833 7941 7945 +3 7941 8085 7945 +3 7829 7941 7833 +3 7685 7829 7689 +3 7593 7685 7616 +3 7501 7593 7545 +3 7441 7501 7453 +3 7349 7441 7361 +3 7349 7361 7305 +3 7349 7305 7226 +3 7349 7226 7203 +3 7103 7203 7155 +3 7203 7226 7155 +3 7085 7203 7103 +3 6993 7085 7005 +3 6899 6993 6911 +3 6807 6899 6830 +3 6695 6807 6723 +3 6555 6695 6583 +3 6411 6555 6439 +3 6255 6411 6327 +3 6328 6255 6251 +3 6255 6327 6251 +3 6412 6255 6328 +3 6556 6412 6440 +3 6696 6556 6584 +3 6808 6696 6724 +3 6900 6808 6831 +3 6994 6900 6912 +3 7086 6994 7006 +3 7204 7086 7104 +3 7204 7104 7156 +3 7204 7156 7227 +3 7204 7227 7350 +3 7362 7350 7306 +3 7350 7227 7306 +3 7442 7350 7362 +3 7502 7442 7454 +3 7594 7502 7546 +3 7686 7594 7617 +3 7830 7686 7690 +3 7830 7690 7834 +3 7830 7834 7942 +3 7834 7946 7942 +3 7946 8086 7942 +3 2627 2648 2710 +3 2710 2752 2814 +3 2916 2929 2988 +3 3001 3037 2988 +3 3037 3076 3063 +3 3063 3123 3159 +3 3159 3185 3233 +3 3328 3233 3245 +3 3354 3328 3291 +3 3353 3328 3354 +3 3366 3472 3354 +3 3685 3729 3818 +3 3660 3592 3480 +3 3221 3152 3060 +3 2958 2894 2893 +3 2958 2893 2985 +3 2958 2985 3030 +3 2985 3060 3030 +3 3060 3105 3030 +3 3152 3105 3060 +3 3224 3152 3221 +3 3224 3221 3274 +3 3221 3329 3274 +3 3329 3321 3274 +3 3395 3321 3329 +3 3395 3329 3405 +3 3395 3405 3467 +3 3405 3480 3467 +3 3480 3504 3467 +3 3592 3504 3480 +3 3725 3592 3660 +3 3725 3660 3795 +3 3725 3795 3848 +3 3795 4016 3848 +3 4016 3948 3848 +3 4037 3948 4016 +3 4037 4016 3952 +3 4016 3818 3952 +3 3818 3852 3952 +3 3729 3852 3818 +3 3596 3729 3685 +3 3596 3685 3556 +3 3596 3556 3509 +3 3556 3472 3509 +3 3472 3438 3509 +3 3366 3438 3472 +3 3291 3366 3354 +3 3245 3291 3328 +3 3185 3245 3233 +3 3123 3185 3159 +3 3076 3123 3063 +3 3001 3076 3037 +3 2929 3001 2988 +3 2849 2929 2916 +3 2458 2395 2436 +3 2458 2436 2541 +3 2541 2621 2646 +3 2733 2750 2646 +3 2750 2885 2842 +3 2885 2886 2842 +3 2733 2885 2750 +3 2621 2733 2646 +3 2436 2621 2541 +3 2543 2648 2523 +3 2543 2523 2460 +3 2523 2395 2460 +3 2436 2395 2523 +3 2814 2849 2848 +3 2849 2916 2848 +3 2752 2849 2814 +3 2648 2752 2710 +3 2523 2648 2627 +3 2523 2627 2522 +3 2847 2846 2812 +3 2846 2915 2914 +3 2986 2914 2987 +3 3036 3035 2986 +3 3035 3062 3061 +3 3326 3327 3351 +3 3327 3352 3351 +3 3232 3327 3326 +3 3232 3326 3231 +3 3232 3231 3158 +3 3061 3158 3157 +3 3158 3231 3157 +3 3062 3158 3061 +3 3036 3062 3035 +3 2987 3036 2986 +3 2915 2987 2914 +3 2847 2915 2846 +3 2813 2847 2812 +3 2813 2812 2708 +3 2813 2708 2709 +3 2708 2625 2709 +3 2625 2626 2709 +3 2521 2626 2625 +3 2521 2625 2520 +3 8108 8348 8356 +3 8344 7848 8336 +3 8336 7704 8328 +3 8312 7984 8304 +3 8322 7608 8330 +3 8354 7999 8364 +3 8271 7691 8267 +3 8267 7835 8263 +3 8260 8088 7948 +3 8264 7948 7836 +3 8260 7948 8264 +3 8268 7836 7692 +3 8264 7836 8268 +3 8272 7692 7619 +3 8268 7692 8272 +3 8290 7619 7712 +3 8272 7619 8290 +3 8263 7947 8259 +3 7947 8087 8259 +3 7835 7947 8263 +3 7691 7835 8267 +3 7618 7691 8271 +3 7618 8271 8289 +3 7618 8289 7711 +3 8289 8364 7711 +3 8364 7855 7711 +3 7999 7855 8364 +3 8107 7999 8354 +3 8107 8354 8200 +3 8354 8346 8200 +3 8346 8099 8200 +3 7991 8099 8346 +3 7991 8346 8338 +3 7991 8338 7847 +3 8338 8330 7847 +3 8330 7703 7847 +3 7608 7703 8330 +3 7695 7608 8322 +3 7695 8322 8314 +3 7695 8314 7839 +3 8314 8306 7839 +3 8306 7983 7839 +3 8091 7983 8306 +3 8091 8306 8304 +3 8091 8304 8194 +3 8304 8092 8194 +3 7984 8092 8304 +3 7840 7984 8312 +3 7840 8312 8320 +3 7840 8320 7696 +3 8320 8328 7696 +3 8328 7609 7696 +3 7704 7609 8328 +3 7848 7704 8336 +3 7992 7848 8344 +3 7992 8344 8100 +3 8344 8348 8100 +3 8348 8201 8100 +3 8108 8201 8348 +3 8000 8108 8356 +3 8000 8356 7856 +3 8356 8365 7856 +3 8365 7712 7856 +3 8290 7712 8365 +3 7836 7832 7692 +3 7692 7688 7619 +3 7619 7596 7548 +3 7548 7504 7456 +3 7456 7444 7364 +3 7106 7088 7008 +3 7008 6996 6914 +3 6833 6914 6902 +3 6833 6810 6726 +3 6726 6698 6586 +3 6586 6558 6442 +3 6414 6330 6442 +3 6329 6413 6441 +3 6585 6441 6557 +3 6697 6725 6585 +3 6725 6809 6832 +3 6832 6901 6913 +3 6913 6995 7007 +3 7007 7087 7105 +3 7455 7503 7547 +3 7547 7595 7618 +3 7618 7687 7691 +3 7691 7831 7835 +3 7835 7943 7947 +3 7943 8087 7947 +3 7831 7943 7835 +3 7687 7831 7691 +3 7595 7687 7618 +3 7503 7595 7547 +3 7443 7503 7455 +3 7443 7455 7363 +3 7443 7363 7351 +3 7363 7307 7351 +3 7307 7228 7351 +3 7228 7205 7351 +3 7105 7205 7157 +3 7205 7228 7157 +3 7087 7205 7105 +3 6995 7087 7007 +3 6901 6995 6913 +3 6809 6901 6832 +3 6697 6809 6725 +3 6557 6697 6585 +3 6413 6557 6441 +3 6256 6413 6329 +3 6330 6256 6252 +3 6256 6329 6252 +3 6414 6256 6330 +3 6558 6414 6442 +3 6698 6558 6586 +3 6810 6698 6726 +3 6902 6810 6833 +3 6996 6902 6914 +3 7088 6996 7008 +3 7206 7088 7106 +3 7206 7106 7158 +3 7206 7158 7229 +3 7206 7229 7352 +3 7364 7352 7308 +3 7352 7229 7308 +3 7444 7352 7364 +3 7504 7444 7456 +3 7596 7504 7548 +3 7688 7596 7619 +3 7832 7688 7692 +3 7944 7832 7836 +3 7944 7836 7948 +3 7944 7948 8088 +3 8435 8293 8443 +3 8298 8427 8436 +3 8298 8436 8294 +3 8436 8444 8294 +3 8444 8286 8294 +3 8282 8286 8444 +3 8282 8444 8278 +3 8444 8446 8278 +3 8446 8274 8278 +3 8277 8274 8446 +3 8277 8446 8443 +3 8277 8443 8281 +3 8443 8285 8281 +3 8293 8285 8443 +3 8297 8293 8435 +3 8297 8435 8426 +3 8433 8291 8441 +3 8296 8425 8434 +3 8296 8434 8292 +3 8434 8442 8292 +3 8442 8284 8292 +3 8280 8284 8442 +3 8280 8442 8276 +3 8442 8445 8276 +3 8445 8273 8276 +3 8275 8273 8445 +3 8275 8445 8441 +3 8275 8441 8279 +3 8441 8283 8279 +3 8291 8283 8441 +3 8295 8291 8433 +3 8295 8433 8424 +3 1631 2301 2299 +3 2259 2087 2192 +3 1993 2087 2259 +3 1993 2259 2267 +3 1993 2267 1860 +3 2267 2275 1860 +3 2275 1727 1860 +3 2301 1727 2283 +3 1727 2275 2283 +3 1631 1727 2301 +3 1728 1631 2299 +3 1728 2299 2298 +3 1728 2298 1861 +3 2298 2297 1861 +3 2297 1994 1861 +3 2090 1994 2297 +3 2090 2297 2296 +3 2090 2296 2197 +3 2091 2296 2443 +3 2197 2296 2091 +3 2091 2526 1995 +3 1995 2631 1862 +3 2735 1729 1862 +3 1729 2831 1632 +3 1722 2276 1854 +3 1854 2268 1960 +3 2366 2358 2809 +3 2366 2809 2370 +3 2622 2516 2370 +3 2622 2370 2705 +3 2370 2809 2705 +3 2831 2358 2353 +3 2809 2358 2831 +3 1960 2260 2178 +3 2260 2253 2178 +3 2268 2260 1960 +3 2276 2268 1854 +3 2289 2276 1722 +3 2289 1722 2341 +3 1722 1632 2341 +3 1632 2353 2341 +3 2831 2353 1632 +3 2735 2831 1729 +3 2631 2735 1862 +3 2526 2631 1995 +3 2443 2526 2091 +3 2386 2443 2296 +3 2811 2360 2833 +3 1864 2633 2737 +3 2445 2198 2387 +3 1863 2736 2632 +3 2736 1730 2832 +3 1855 2269 2277 +3 2269 1961 2261 +3 2261 2179 2254 +3 1961 2179 2261 +3 1855 1961 2269 +3 1723 1855 2277 +3 1723 2277 2290 +3 1723 2290 2342 +3 1723 2342 1633 +3 2517 2623 2371 +3 2623 2706 2371 +3 2706 2810 2371 +3 2810 2367 2371 +3 2359 2367 2810 +3 2359 2810 2832 +3 2359 2832 2354 +3 2832 1633 2354 +3 1633 2342 2354 +3 1730 1633 2832 +3 1863 1730 2736 +3 1996 1863 2632 +3 1996 2632 2527 +3 1996 2527 2092 +3 2387 2092 2444 +3 2092 2527 2444 +3 2198 2092 2387 +3 2093 2198 2445 +3 2093 2445 2528 +3 2093 2528 1997 +3 2528 2633 1997 +3 2633 1864 1997 +3 1731 2737 2833 +3 1864 2737 1731 +3 1634 2833 2355 +3 1731 2833 1634 +3 1634 2343 1724 +3 1962 2262 2180 +3 2262 2255 2180 +3 2270 2262 1962 +3 2270 1962 1856 +3 2270 1856 2278 +3 1856 1724 2278 +3 1724 2291 2278 +3 2343 2291 1724 +3 2355 2343 1634 +3 2360 2355 2833 +3 2368 2360 2811 +3 2368 2811 2372 +3 2811 2707 2372 +3 2707 2624 2372 +3 2624 2518 2372 +3 2256 2439 2440 +3 2256 2440 2181 +3 2256 2181 2180 +3 2256 2180 2255 +3 4810 5426 6232 +3 4805 4899 4806 +3 4991 4899 4805 +3 4991 4805 5135 +3 4805 5279 5135 +3 5423 5279 4805 +3 5423 4805 6231 +3 5423 6231 5515 +3 6231 5659 5515 +3 5803 5659 6231 +3 5803 6231 5947 +3 6231 6181 5947 +3 5804 5805 5660 +3 5660 5661 5516 +3 5517 5424 5516 +3 5425 5280 5424 +3 5280 5281 5136 +3 5136 5137 4992 +3 4992 4993 4900 +3 4900 4901 4807 +3 4901 4808 4807 +3 4993 4901 4900 +3 5137 4993 4992 +3 5281 5137 5136 +3 5425 5281 5280 +3 5517 5425 5424 +3 5661 5517 5516 +3 5805 5661 5660 +3 5949 5805 5804 +3 5949 5804 5948 +3 5949 5948 6182 +3 5948 6181 6182 +3 6181 6231 6182 +3 6231 6232 6182 +3 6232 5950 6182 +3 5806 5950 6232 +3 5806 6232 5662 +3 6232 5518 5662 +3 5426 5518 6232 +3 5282 5426 4810 +3 5282 4810 5138 +3 4810 4994 5138 +3 4902 4994 4810 +3 4902 4810 4809 +3 7590 7591 7682 +3 7682 7683 7794 +3 8219 8275 8081 +3 8279 7937 8081 +3 7589 7681 7291 +3 7589 7291 7497 +3 7291 7405 7497 +3 7292 7405 7291 +3 7937 8283 8423 +3 7937 8423 7793 +3 8423 7681 7793 +3 7291 7681 8423 +3 8296 8292 8293 +3 8428 8298 8294 +3 8427 8298 8428 +3 7408 7295 7296 +3 7408 7296 7500 +3 7296 7592 7500 +3 7684 7592 7296 +3 7684 7296 8428 +3 7684 8428 7796 +3 8282 7940 8286 +3 7940 8428 8286 +3 8428 8294 8286 +3 7796 8428 7940 +3 8084 8282 8278 +3 7940 8282 8084 +3 8277 8220 8274 +3 8220 8278 8274 +3 8084 8278 8220 +3 8296 8297 8425 +3 8297 8426 8425 +3 8293 8297 8296 +3 8285 8293 8292 +3 8285 8292 8284 +3 8285 8284 8281 +3 8284 8280 8281 +3 8280 8083 8281 +3 8083 8277 8281 +3 8220 8277 8083 +3 8424 8423 8295 +3 8423 8291 8295 +3 8283 8291 8423 +3 8279 8283 7937 +3 8275 8279 8081 +3 8273 8275 8219 +3 8273 8219 8276 +3 8219 8082 8276 +3 8082 8280 8276 +3 8083 8280 8082 +3 8083 8082 7939 +3 8082 7938 7939 +3 7938 7794 7939 +3 7794 7795 7939 +3 7683 7795 7794 +3 7591 7683 7682 +3 7499 7591 7590 +3 7499 7590 7498 +3 7499 7498 7406 +3 7499 7406 7407 +3 7294 7406 7293 +3 7407 7406 7294 +3 2288 2351 2287 +3 2365 2351 2288 +3 2365 2288 2523 +3 2365 2523 2522 +3 4189 4144 4190 +3 4143 4144 4189 +3 4206 4190 4207 +3 4189 4190 4206 +3 2192 2191 2258 +3 2192 2258 2259 +3 2349 2350 2363 +3 2363 2364 2520 +3 2364 2521 2520 +3 2350 2364 2363 +3 2286 2350 2349 +3 2286 2349 2285 +3 4109 4110 4143 +3 4144 4110 4045 +3 4143 4110 4144 +3 4144 3562 3354 +3 3404 3353 3354 +3 3404 3354 3475 +3 3354 3552 3475 +3 3562 3552 3354 +3 3688 3562 4144 +3 3688 4144 3794 +3 4144 3918 3794 +3 4045 3918 4144 +3 3917 4045 4110 +3 3917 4110 3793 +3 3551 3561 3560 +3 3551 3550 3474 +3 3473 3403 3474 +3 3352 3403 3351 +3 3403 3402 3351 +3 3473 3402 3403 +3 3550 3473 3474 +3 3560 3550 3551 +3 3686 3560 3561 +3 3686 3561 3687 +3 3686 3687 3792 +3 3687 3793 3792 +3 3793 4110 3792 +3 4110 3916 3792 +3 4044 3916 4110 +3 6987 6895 6988 +3 6803 6895 6987 +3 6803 6987 6551 +3 6804 6805 6896 +3 6896 6897 6989 +3 6897 6990 6989 +3 6805 6897 6896 +3 6553 6805 6804 +3 6553 6804 6552 +3 6553 6552 6408 +3 6553 6408 6409 +3 6410 5930 6554 +3 5786 6992 6554 +3 6992 6806 6554 +3 6898 6806 6992 +3 6898 6992 6991 +3 5403 5495 6987 +3 5403 6987 4206 +3 5403 4206 5231 +3 4206 5063 5231 +3 4971 5063 4206 +3 4971 4206 4851 +3 4206 4681 4851 +3 4533 4681 4206 +3 4533 4206 4267 +3 4206 4534 4267 +3 4852 4853 4972 +3 4972 4973 5064 +3 5065 5232 5064 +3 5404 5232 5233 +3 5404 5405 5496 +3 5612 5496 5497 +3 5612 5613 5784 +3 5613 5785 5784 +3 5497 5613 5612 +3 5405 5497 5496 +3 5233 5405 5404 +3 5065 5233 5232 +3 4973 5065 5064 +3 4853 4973 4972 +3 4683 4853 4852 +3 4683 4852 4682 +3 4683 4682 4535 +3 4682 4534 4535 +3 4534 4206 4535 +3 4206 4207 4535 +3 4207 4268 4535 +3 4536 4268 4207 +3 4536 4207 4684 +3 4207 4854 4684 +3 4974 4854 4207 +3 4974 4207 5066 +3 4207 5234 5066 +3 5406 5234 4207 +3 5406 4207 6992 +3 5406 6992 5498 +3 6992 5614 5498 +3 5786 5614 6992 +3 5930 5786 6554 +3 6194 5930 6410 +3 6194 6410 6409 +3 6194 6409 5929 +3 6409 6408 5929 +3 6408 5928 5929 +3 5928 5785 5929 +3 5784 5785 5928 +3 5783 6987 5611 +3 6987 5495 5611 +3 6551 6987 5783 +3 6551 5783 5927 +3 6551 5927 6407 +3 5927 6193 6407 +3 6193 6408 6407 +3 5928 6408 6193 +3 2523 2288 2436 +3 2288 2621 2436 +3 2733 2621 2288 +3 2733 2288 2885 +3 7067 6992 6969 +3 6969 5493 6845 +3 6845 5605 6677 +3 6677 5781 6533 +3 6533 5925 6259 +3 6259 6185 6531 +3 6531 5923 6675 +3 5779 6839 6675 +3 5599 6232 6839 +3 6232 6967 6839 +3 7065 6967 6232 +3 7065 6232 7235 +3 6232 7421 7235 +3 4207 5225 5401 +3 5061 5225 4207 +3 5061 4207 4969 +3 4845 3556 4679 +3 4016 4529 4259 +3 4677 4529 3795 +3 7809 7625 8366 +3 7625 7517 8366 +3 7517 7421 8366 +3 7421 6232 8366 +3 3039 2985 2984 +3 2984 2893 2887 +3 2985 2893 2984 +3 3060 2985 3039 +3 3060 3039 3161 +3 3060 3161 3221 +3 3161 3318 3221 +3 3318 3329 3221 +3 4677 3660 4839 +3 3660 3480 4839 +3 3795 3660 4677 +3 4016 3795 4529 +3 3818 4016 4259 +3 3818 4259 4531 +3 3818 4531 3685 +3 4531 4679 3685 +3 4679 3556 3685 +3 3354 3472 4144 +3 3472 3556 4144 +3 3556 4845 4144 +3 4845 4969 4144 +3 4969 4207 4144 +3 4207 4190 4144 +3 6992 5401 5493 +3 4207 5401 6992 +3 6992 7296 7094 +3 3479 4810 3401 +3 4810 3318 3401 +3 3329 3318 4810 +3 3329 4810 3405 +3 4810 3480 3405 +3 4839 3480 4810 +3 4839 4810 4967 +3 4810 5059 4967 +3 5219 5059 4810 +3 5219 4810 5399 +3 4810 6232 5399 +3 6232 5491 5399 +3 5599 5491 6232 +3 5779 5599 6839 +3 5923 5779 6675 +3 6185 5923 6531 +3 5925 6185 6259 +3 5781 5925 6533 +3 5605 5781 6677 +3 5493 5605 6845 +3 6992 5493 6969 +3 7296 6992 7067 +3 7296 7067 7241 +3 7296 7241 7423 +3 7296 7423 7519 +3 7296 7519 8428 +3 7519 7631 8428 +3 7631 7811 8428 +3 7811 7963 8428 +3 7963 8211 8428 +3 8211 7961 8428 +3 7961 7809 8428 +3 7809 8366 8428 +3 2256 2263 2439 +3 2373 2344 2362 +3 2344 2357 2362 +3 2282 2344 2373 +3 2282 2373 2273 +3 2373 2263 2273 +3 2439 2263 2373 +3 2439 2373 2519 +3 2517 2370 2516 +3 2371 2370 2517 +3 2373 2518 2519 +3 2372 2518 2373 +3 3553 3477 3476 +3 3554 3477 3553 +3 3554 3553 3657 +3 3554 3657 3658 +3 3691 3657 3690 +3 3658 3657 3691 +3 3797 3690 3796 +3 3691 3690 3797 +3 4081 3796 4080 +3 3797 3796 4081 +3 4086 4108 4083 +3 4108 4080 4083 +3 4081 4080 4108 +3 4081 4108 4084 +3 4108 4087 4084 +3 4085 4810 4082 +3 3479 3659 3692 +3 3555 3659 3479 +3 3555 3479 3478 +3 4664 4809 4810 +3 4664 4810 4556 +3 4810 4412 4556 +3 4082 3479 3798 +3 3479 3692 3798 +3 4810 3479 4082 +3 4412 4810 4085 +3 4412 4085 4256 +3 4085 4087 4256 +3 4087 4108 4256 +3 4108 4411 4256 +3 4409 4805 4553 +3 4805 4661 4553 +3 4806 4661 4805 +3 4107 4409 4255 +3 4805 4409 4107 +3 4663 4662 4808 +3 4662 4807 4808 +3 4554 4662 4663 +3 4554 4663 4555 +3 4554 4555 4410 +3 4555 4411 4410 +3 4411 4108 4410 +3 4108 4255 4410 +3 4107 4255 4108 +3 8272 7688 8268 +3 8264 8268 7832 +3 6557 6556 6697 +3 6697 6696 6809 +3 6809 6808 6901 +3 6900 6995 6901 +3 6995 6994 7087 +3 7086 7205 7087 +3 7351 7205 7204 +3 7351 7350 7443 +3 7443 7442 7503 +3 7502 7595 7503 +3 7687 7595 7594 +3 7687 7686 7831 +3 8087 7943 8259 +3 7830 8263 7831 +3 8263 7943 7831 +3 8259 7943 8263 +3 8364 8288 8363 +3 8262 7942 8258 +3 7942 8086 8258 +3 7830 7942 8262 +3 8271 8288 8289 +3 8288 8364 8289 +3 8270 8288 8271 +3 8270 8271 8267 +3 8270 8267 8266 +3 8267 8263 8266 +3 8263 8262 8266 +3 7830 8262 8263 +3 7686 7830 7831 +3 7594 7686 7687 +3 7502 7594 7595 +3 7442 7502 7503 +3 7350 7442 7443 +3 7204 7350 7351 +3 7086 7204 7205 +3 6994 7086 7087 +3 6900 6994 6995 +3 6808 6900 6901 +3 6696 6808 6809 +3 6556 6696 6697 +3 6412 6556 6557 +3 6412 6557 6413 +3 6412 6413 6255 +3 7349 8361 7441 +3 8361 7501 7441 +3 7593 7501 8361 +3 7593 8361 7685 +3 7829 8261 7941 +3 7941 8257 8085 +3 8261 8257 7941 +3 8265 8261 7829 +3 8265 7829 7685 +3 8265 7685 8269 +3 7685 8361 8269 +3 8361 8287 8269 +3 8362 8287 8361 +3 6231 6255 6256 +3 6255 6413 6256 +3 6411 6255 6231 +3 6411 6231 6555 +3 6231 6695 6555 +3 6807 6695 6231 +3 6807 6231 6899 +3 6231 6993 6899 +3 7085 6993 6231 +3 7085 6231 7203 +3 6231 7349 7203 +3 8361 7349 6231 +3 7206 7352 6232 +3 7206 6232 7088 +3 6232 6996 7088 +3 6902 6996 6232 +3 6902 6232 6810 +3 6232 6698 6810 +3 6558 6698 6232 +3 6558 6232 6414 +3 6232 6256 6414 +3 6231 6256 6232 +3 8366 7596 7688 +3 7504 7596 8366 +3 7504 8366 7444 +3 8366 7352 7444 +3 6232 7352 8366 +3 8264 7944 8260 +3 7944 8088 8260 +3 7832 7944 8264 +3 7688 7832 8268 +3 8366 7688 8272 +3 8366 8272 8290 +3 8366 8290 8365 +3 7050 7051 7090 +3 7200 7090 7091 +3 7200 7201 7293 +3 7201 7294 7293 +3 7091 7201 7200 +3 7051 7091 7090 +3 6990 7050 6989 +3 7051 7050 6990 +3 6991 6992 7052 +3 6992 7094 7052 +3 7094 7092 7052 +3 7202 7092 7094 +3 7202 7094 7296 +3 7202 7296 7295 +3 7292 7291 7199 +3 7291 7093 7199 +3 7093 7089 7199 +3 7049 7089 7093 +3 7049 7093 6987 +3 7049 6987 6988 +3 1556 1555 1476 +3 1336 1337 1342 +3 1342 1390 1391 +3 1337 1390 1342 +3 1334 1337 1336 +3 1334 1336 1335 +3 1334 1335 1338 +3 1388 1338 1341 +3 1338 1335 1341 +3 1392 1338 1388 +3 1392 1388 1438 +3 1392 1438 1473 +3 1438 1476 1473 +3 1476 1555 1473 +3 2260 2261 2253 +3 2261 2254 2253 +3 1524 1525 1391 +3 1524 1391 1390 +3 2255 2263 2256 +3 2262 2263 2255 +3 2300 2283 2281 +3 2281 2275 2272 +3 2272 2267 2258 +3 2267 2259 2258 +3 2275 2267 2272 +3 2283 2275 2281 +3 2301 2283 2300 +3 2341 2353 2354 +3 2341 2342 2289 +3 2290 2276 2289 +3 2276 2277 2268 +3 2268 2269 2260 +3 2269 2261 2260 +3 2277 2269 2268 +3 2290 2277 2276 +3 2342 2290 2289 +3 2354 2342 2341 +3 2359 2353 2358 +3 2354 2353 2359 +3 2367 2358 2366 +3 2359 2358 2367 +3 2371 2366 2370 +3 2367 2366 2371 +3 2282 2291 2344 +3 2362 2368 2373 +3 2368 2372 2373 +3 2360 2368 2362 +3 2360 2362 2357 +3 2360 2357 2355 +3 2357 2344 2355 +3 2344 2343 2355 +3 2291 2343 2344 +3 2278 2291 2282 +3 2278 2282 2273 +3 2278 2273 2270 +3 2273 2263 2270 +3 2263 2262 2270 +3 8545 7267 7073 +3 7429 7267 8545 +3 7429 8545 7525 +3 8545 7657 7525 +3 7817 7657 8545 +3 7817 8545 7969 +3 8545 8239 7969 +3 4223 5256 5412 +3 5072 5256 4223 +3 5072 4223 4980 +3 4223 4876 4980 +3 4690 4876 4223 +3 4690 4223 4542 +3 4223 4287 4542 +3 6683 5635 6871 +3 5635 6975 6871 +3 5791 5635 6683 +3 5791 6683 6539 +3 5791 6539 5935 +3 6540 5792 5936 +3 6540 5936 6213 +3 6540 6213 6285 +3 6213 6539 6285 +3 5935 6539 6213 +3 7073 5411 4222 +3 5411 5255 4222 +3 5255 5071 4222 +3 5071 4979 4222 +3 4979 4875 4222 +3 4875 4689 4222 +3 4689 4541 4222 +3 4541 4287 4222 +3 4287 4223 4222 +3 6872 5792 6684 +3 5792 6540 6684 +3 5636 5792 6872 +3 5636 6872 5504 +3 6872 6976 5504 +3 6976 7074 5504 +3 7074 5412 5504 +3 4223 5412 7074 +3 4223 7074 8546 +3 7074 7268 8546 +3 7268 7430 8546 +3 7430 7526 8546 +3 7526 7658 8546 +3 7658 7818 8546 +3 7818 7970 8546 +3 7970 8239 8546 +3 8239 8545 8546 +3 5411 6975 5503 +3 6975 5635 5503 +3 7073 6975 5411 +3 8545 7073 4222 +3 8551 4228 8550 +3 8550 4227 8549 +3 8549 4226 8548 +3 8548 4225 8547 +3 8546 8547 4223 +3 8547 4224 4223 +3 4225 4224 8547 +3 4226 4225 8548 +3 4227 4226 8549 +3 4228 4227 8550 +3 4229 4228 8551 +3 4229 8551 8552 +3 4219 4221 4212 +3 4217 4200 4216 +3 4200 4193 4202 +3 4220 4221 4229 +3 4212 4221 4220 +3 4205 4220 4218 +3 4205 4212 4220 +3 4201 4194 4192 +3 4204 4191 4200 +3 4204 4197 4191 +3 4197 4184 4191 +3 4197 4192 4184 +3 4183 4184 4192 +3 4203 4201 4215 +3 4194 4201 4203 +3 4217 4219 4204 +3 4219 4212 4204 +3 4205 4204 4212 +3 4205 4197 4204 +3 4218 4201 4205 +3 4218 4215 4201 +3 4192 4205 4201 +3 4192 4197 4205 +3 4183 4192 4194 +3 4193 4191 4182 +3 4191 4184 4182 +3 4184 4177 4182 +3 4183 4177 4184 +3 4215 4218 4229 +3 4218 4220 4229 +3 4175 4177 4180 +3 4180 4183 4187 +3 4187 4194 4198 +3 4198 4203 4213 +3 4198 4213 4210 +3 4213 4215 4229 +3 4210 4213 4229 +3 4224 4225 4216 +3 4224 4216 4214 +3 4224 4214 4223 +3 4214 4209 4223 +3 4196 4214 4202 +3 4214 4216 4202 +3 4209 4214 4196 +3 4217 4225 4226 +3 4216 4225 4217 +3 4202 4216 4200 +3 4196 4202 4193 +3 4196 4193 4186 +3 4228 4229 4221 +3 4228 4221 4227 +3 4221 4219 4227 +3 4219 4226 4227 +3 4217 4226 4219 +3 4200 4217 4204 +3 4193 4200 4191 +3 4186 4193 4182 +3 4186 4182 4179 +3 4182 4177 4179 +3 4177 4174 4179 +3 4203 4215 4213 +3 4194 4203 4198 +3 4183 4194 4187 +3 4177 4183 4180 +3 4174 4177 4175 +3 4174 4175 4146 +3 4178 4179 4174 +3 4185 4186 4179 +3 4186 4195 4196 +3 4196 4208 4209 +3 4209 4222 4223 +3 4208 4222 4209 +3 4195 4208 4196 +3 4185 4195 4186 +3 4178 4185 4179 +3 4173 4178 4174 +3 4173 4174 4146 +3 4173 4146 4145 +3 6979 5507 6881 +3 6543 6217 6289 +3 6289 5937 6541 +3 5637 6873 5793 +3 6977 6873 5637 +3 5413 6977 5505 +3 6977 5637 5505 +3 7075 6977 5413 +3 6541 5793 6685 +3 5793 6873 6685 +3 5937 5793 6541 +3 6217 5937 6289 +3 5939 6217 6543 +3 5939 6543 5795 +3 6543 6687 5795 +3 6687 6881 5795 +3 6881 5645 5795 +3 5507 5645 6881 +3 5415 5507 6979 +3 5415 6979 7077 +3 5415 7077 4230 +3 5415 4230 5265 +3 4230 5075 5265 +3 4983 5075 4230 +3 4983 4230 4885 +3 4230 4693 4885 +3 4545 4693 4230 +3 4545 4230 4291 +3 4230 4229 4291 +3 4229 4543 4291 +3 4691 4543 4229 +3 4691 4229 4877 +3 4229 4981 4877 +3 5073 4981 4229 +3 5073 4229 5257 +3 4229 5413 5257 +3 7075 5413 4229 +3 7075 4229 7269 +3 4229 8552 7269 +3 8552 7431 7269 +3 7527 7431 8552 +3 7527 8552 7659 +3 8552 7819 7659 +3 7971 7819 8552 +3 7971 8552 8243 +3 8552 8625 8243 +3 8625 7973 8243 +3 7821 7973 8625 +3 7821 8625 7667 +3 8625 7529 7667 +3 7433 7529 8625 +3 7433 8625 7277 +3 8625 7077 7277 +3 4230 7077 8625 +3 4163 4172 4165 +3 4172 4167 4165 +3 4169 4167 4172 +3 4169 4172 4170 +3 4158 4160 4171 +3 4160 4162 4171 +3 4162 4164 4171 +3 4164 4166 4171 +3 4166 4168 4171 +3 4168 4170 4171 +3 4170 4172 4171 +3 4159 4172 4161 +3 4172 4163 4161 +3 4146 4172 4159 +3 4146 4159 4157 +3 4146 4157 4155 +3 4146 4155 4153 +3 4146 4153 4151 +3 4146 4151 4149 +3 4146 4149 4147 +3 4146 4147 4145 +3 4147 4148 4145 +3 4148 4150 4145 +3 4150 4152 4145 +3 4152 4154 4145 +3 4154 4156 4145 +3 4156 4158 4145 +3 4158 4171 4145 +3 4211 4210 4229 +3 4210 4199 4198 +3 4188 4187 4198 +3 4181 4180 4187 +3 4176 4175 4180 +3 4175 4172 4146 +3 4176 4172 4175 +3 4181 4176 4180 +3 4188 4181 4187 +3 4199 4188 4198 +3 4211 4199 4210 +3 4230 4211 4229 +3 2162 2499 2352 +3 2685 1931 2581 +3 2581 2064 2498 +3 2506 2072 2588 +3 2692 2588 1939 +3 2692 1806 2796 +3 2274 2802 2698 +3 2797 2346 2693 +3 2693 2347 2589 +3 2589 2348 2507 +3 2499 2065 2582 +3 2582 1932 2686 +3 2686 1799 2790 +3 2679 1924 2575 +3 2575 2057 2492 +3 2574 2491 2056 +3 2574 1923 2678 +3 1790 2782 2678 +3 2185 2511 2080 +3 2080 2593 1951 +3 1815 2697 2801 +3 1815 2801 1694 +3 2796 1694 2878 +3 1694 2801 2878 +3 1806 1694 2796 +3 1939 1806 2692 +3 2072 1939 2588 +3 2169 2072 2506 +3 2169 2506 2240 +3 2506 2421 2240 +3 2421 2498 2240 +3 2498 2161 2240 +3 2064 2161 2498 +3 1931 2064 2581 +3 1798 1931 2685 +3 1798 2685 2789 +3 1798 2789 1684 +3 2782 1684 2870 +3 1684 2789 2870 +3 1790 1684 2782 +3 1923 1790 2678 +3 2056 1923 2574 +3 2153 2056 2491 +3 2153 2491 2416 +3 2153 2416 2233 +3 2416 2492 2233 +3 2492 2154 2233 +3 2057 2154 2492 +3 1924 2057 2575 +3 1791 1924 2679 +3 1791 2679 2783 +3 1791 2783 1685 +3 2790 1685 2871 +3 1685 2783 2871 +3 1799 1685 2790 +3 1932 1799 2686 +3 2065 1932 2582 +3 2162 2065 2499 +3 2241 2162 2352 +3 2507 2352 2422 +3 2352 2499 2422 +3 2348 2352 2507 +3 2347 2348 2589 +3 2346 2347 2693 +3 2293 2346 2797 +3 2293 2797 2879 +3 2293 2879 2284 +3 2879 2802 2284 +3 2802 2274 2284 +3 2265 2698 2594 +3 2274 2698 2265 +3 1951 2697 1859 +3 2697 1815 1859 +3 2593 2697 1951 +3 2511 2593 2080 +3 2429 2511 2185 +3 2429 2185 2188 +3 2429 2188 2512 +3 2188 2083 2512 +3 2083 2594 2512 +3 2265 2594 2083 +3 3915 4015 4014 +3 3689 3662 3791 +3 3662 3661 3549 +3 3230 3160 3111 +3 3160 3110 3111 +3 3229 3160 3230 +3 3229 3230 3279 +3 3230 3350 3279 +3 3350 3349 3279 +3 3400 3349 3350 +3 3400 3350 3426 +3 3400 3426 3425 +3 3426 3549 3425 +3 3549 3543 3425 +3 3661 3543 3549 +3 3689 3661 3662 +3 3790 3689 3791 +3 3790 3791 3913 +3 3791 4014 3913 +3 4014 4013 3913 +3 4015 4013 4014 +3 3914 4015 3915 +3 4895 3546 4894 +3 2882 2883 1701 +3 7439 7438 7535 +3 8626 7979 7978 +3 8626 7978 8255 +3 7827 7679 7678 +3 7679 7535 7678 +3 7535 7534 7678 +3 7438 7534 7535 +3 7288 7438 7439 +3 7288 7439 7289 +3 7288 7289 7082 +3 8625 7435 7285 +3 7531 7435 8625 +3 7531 8625 7675 +3 8625 7823 7675 +3 7975 7823 8625 +3 7975 8625 8254 +3 8625 7976 8254 +3 7824 7677 7676 +3 7437 7436 7533 +3 7286 7436 7437 +3 7286 7437 7287 +3 7286 7287 7080 +3 7287 7081 7080 +3 7081 6983 7080 +3 6983 6982 7080 +3 6890 6982 6983 +3 5802 6894 5658 +3 4895 4986 4987 +3 6229 6301 5944 +3 5944 6548 5800 +3 5658 6986 5514 +3 6986 5422 5514 +3 6894 6986 5658 +3 6694 6894 5802 +3 6694 5802 6550 +3 5802 5946 6550 +3 5946 6230 6550 +3 6230 6302 6550 +3 6549 6302 6230 +3 6549 6230 5945 +3 6549 5945 5801 +3 6549 5801 6693 +3 5801 5657 6693 +3 5657 6893 6693 +3 5656 6893 5657 +3 5656 5657 5513 +3 5656 5513 5512 +3 5513 5421 5512 +3 5421 5420 5512 +3 5276 5420 5421 +3 5276 5421 5277 +3 5276 5277 5080 +3 5797 5653 6689 +3 6228 6545 6300 +3 6228 6300 6546 +3 6228 6546 5942 +3 6890 5798 6690 +3 5798 6546 6690 +3 5942 6546 5798 +3 5654 6890 6891 +3 6890 6983 6891 +3 5798 6890 5654 +3 6985 7082 7083 +3 7082 7289 7083 +3 6984 7082 6985 +3 6984 6985 6892 +3 6985 6893 6892 +3 6893 5656 6892 +3 5656 5800 6892 +3 5800 6692 6892 +3 6548 6692 5800 +3 6301 6548 5944 +3 6547 6301 6229 +3 6547 6229 5943 +3 6547 5943 5799 +3 6547 5799 6691 +3 5799 5655 6691 +3 5655 6891 6691 +3 5654 6891 5655 +3 5654 5655 5511 +3 5654 5511 5510 +3 5511 5419 5510 +3 5419 5418 5510 +3 5274 5418 5419 +3 5274 5419 5275 +3 5274 5275 5078 +3 4696 4894 3682 +3 4696 3682 4548 +3 2883 2980 2981 +3 4079 4303 3817 +3 3817 4550 3684 +3 2611 1842 2728 +3 4199 3814 3681 +3 4987 5078 5079 +3 5078 5275 5079 +3 4986 5078 4987 +3 4894 4986 4895 +3 3682 4894 3546 +3 4989 5080 5081 +3 5080 5277 5081 +3 4988 5080 4989 +3 4988 4989 4897 +3 4988 4897 4896 +3 4897 3548 4896 +3 3548 3684 4896 +3 3684 4698 4896 +3 4550 4698 3684 +3 4303 4550 3817 +3 4549 4303 4079 +3 4549 4079 3816 +3 4549 3816 3683 +3 4549 3683 4697 +3 3683 3547 4697 +3 3547 4895 4697 +3 3546 4895 3547 +3 3546 3547 3423 +3 3546 3423 3422 +3 3423 3347 3422 +3 3347 3346 3422 +3 3218 3346 3347 +3 3218 3347 3219 +3 3218 3219 3057 +3 2882 1843 2729 +3 1843 2612 2729 +3 3420 4172 3344 +3 2978 3055 3056 +3 2340 1840 2339 +3 2339 1327 344 +3 1209 1330 1340 +3 1340 1466 1472 +3 1552 1560 1472 +3 1702 1560 1701 +3 1702 2883 1816 +3 1952 1816 2730 +3 1952 2613 2186 +3 2186 2432 2084 +3 3230 3348 3350 +3 3350 3424 3426 +3 3426 3548 3549 +3 3549 4897 3662 +3 3662 4699 3791 +3 4014 3791 4551 +3 4014 4304 3915 +3 7676 7533 7532 +3 7533 7436 7532 +3 7677 7533 7676 +3 7825 7677 7824 +3 7825 7824 7977 +3 7824 7976 7977 +3 7976 8625 7977 +3 8625 8255 7977 +3 8626 8255 8625 +3 4230 7285 7079 +3 8625 7285 4230 +3 5797 6545 5941 +3 6545 6228 5941 +3 6689 6545 5797 +3 6889 6689 5653 +3 6889 5653 6981 +3 5653 5509 6981 +3 5509 5417 6981 +3 5417 7079 6981 +3 4230 7079 5417 +3 4230 5417 5273 +3 4230 5273 5077 +3 4230 5077 4985 +3 4230 4985 4893 +3 4230 4893 4695 +3 4230 4695 4211 +3 4078 4548 3815 +3 4548 3682 3815 +3 4302 4548 4078 +3 4302 4078 4547 +3 4078 3814 4547 +3 3814 4211 4547 +3 4211 4695 4547 +3 4199 4211 3814 +3 4188 4199 3681 +3 4188 3681 3545 +3 4188 3545 4181 +3 4176 3545 3421 +3 4181 3545 4176 +3 2978 2979 2880 +3 2979 2881 2880 +3 3056 2979 2978 +3 3217 3056 3055 +3 3217 3055 3216 +3 3217 3216 3345 +3 3216 3344 3345 +3 3344 4172 3345 +3 4172 3421 3345 +3 4176 3421 4172 +3 4138 4171 4172 +3 4137 4171 4138 +3 3680 4172 3544 +3 4172 3420 3544 +3 4138 4172 3680 +3 4138 3680 3813 +3 4138 3813 4077 +3 345 344 639 +3 345 639 640 +3 345 640 416 +3 1465 1464 1551 +3 2728 1700 2881 +3 1842 1700 2728 +3 1989 1842 2611 +3 1989 2611 2249 +3 2611 2431 2249 +3 2431 2612 2249 +3 2612 1990 2249 +3 1843 1990 2612 +3 2981 3057 3058 +3 3057 3219 3058 +3 2980 3057 2981 +3 2882 2980 2883 +3 1843 2882 1701 +3 7978 7827 7826 +3 7827 7678 7826 +3 7979 7827 7978 +3 8256 7979 8626 +3 8256 8626 7980 +3 8626 7828 7980 +3 7680 7828 8626 +3 7680 8626 7536 +3 8626 7440 7536 +3 7290 7440 8626 +3 7290 8626 7084 +3 8626 4232 7084 +3 4232 5422 7084 +3 5422 6986 7084 +3 5278 5422 4232 +3 5278 4232 5082 +3 4232 4990 5082 +3 4898 4990 4232 +3 4898 4232 4700 +3 4232 3915 4700 +3 3915 4552 4700 +3 4304 4552 3915 +3 4551 4304 4014 +3 4699 4551 3791 +3 4897 4699 3662 +3 3548 4897 3549 +3 3424 3548 3426 +3 3348 3424 3350 +3 3220 3348 3230 +3 3220 3230 3111 +3 3220 3111 3059 +3 3111 2982 3059 +3 2884 2982 3111 +3 2884 3111 2084 +3 2884 2084 2731 +3 2084 2614 2731 +3 2432 2614 2084 +3 2613 2432 2186 +3 2730 2613 1952 +3 2883 2730 1816 +3 1701 2883 1702 +3 1552 1701 1560 +3 1466 1552 1472 +3 1330 1466 1340 +3 1161 1330 1209 +3 1161 1209 1079 +3 1209 345 1079 +3 345 985 1079 +3 786 985 345 +3 786 345 641 +3 345 416 641 +3 982 783 344 +3 982 344 1076 +3 344 1158 1076 +3 1327 1158 344 +3 1463 1327 2339 +3 1463 2339 1549 +3 2339 1698 1549 +3 1840 1698 2339 +3 1987 1840 2340 +3 1987 2340 2248 +3 2340 1988 2248 +3 1841 1988 2340 +3 2727 2340 2610 +3 2340 2430 2610 +3 1841 2340 2727 +3 1841 2727 2880 +3 1841 2880 1699 +3 2880 2881 1699 +3 2881 1700 1699 +3 1700 1551 1699 +3 1551 1550 1699 +3 1464 1550 1551 +3 1328 1464 1465 +3 1328 1465 1329 +3 1328 1329 1159 +3 1329 1160 1159 +3 1160 1078 1159 +3 1078 1077 1159 +3 983 1077 1078 +3 983 1078 984 +3 983 984 784 +3 984 785 784 +3 785 640 784 +3 640 639 784 +3 415 344 638 +3 344 783 638 +3 639 344 415 +3 347 1468 3163 +3 347 642 417 +3 346 1080 986 +3 1162 1080 346 +3 1162 346 1331 +3 346 1467 1331 +3 1553 1467 346 +3 1553 346 1703 +3 346 3163 1703 +3 3163 1844 1703 +3 1991 1844 3163 +3 1991 3163 2250 +3 3163 1992 2250 +3 1845 1992 3163 +3 1845 3163 1704 +3 3163 1554 1704 +3 1468 1554 3163 +3 1332 1468 347 +3 1332 347 1163 +3 347 1081 1163 +3 987 1081 347 +3 987 347 788 +3 347 643 788 +3 642 346 787 +3 346 986 787 +3 347 346 642 +3 643 347 417 +3 1205 1208 1253 +3 1323 1253 1257 +3 1323 1339 1383 +3 1394 1435 1383 +3 503 502 598 +3 598 597 731 +3 867 731 730 +3 866 969 867 +3 969 968 1040 +3 1040 1039 1120 +3 1119 1198 1120 +3 1197 1246 1198 +3 1510 1428 1427 +3 1798 1797 1931 +3 1930 2064 1931 +3 1939 1805 1806 +3 1806 1693 1694 +3 1601 1559 1694 +3 1435 1471 1517 +3 1394 1471 1435 +3 1339 1394 1383 +3 1257 1339 1323 +3 1208 1257 1253 +3 1130 1205 1127 +3 1208 1205 1130 +3 1082 1127 1047 +3 1130 1127 1082 +3 1000 1047 978 +3 1082 1047 1000 +3 894 978 874 +3 1000 978 894 +3 789 874 738 +3 894 874 789 +3 656 738 605 +3 789 738 656 +3 522 605 510 +3 656 605 522 +3 502 406 405 +3 406 510 405 +3 522 510 406 +3 1559 1517 1522 +3 1517 1471 1522 +3 1601 1517 1559 +3 1693 1601 1694 +3 1805 1693 1806 +3 1938 1805 1939 +3 1938 1939 2072 +3 1938 2072 2071 +3 2072 2169 2071 +3 2169 2168 2071 +3 2239 2168 2169 +3 2239 2169 2240 +3 2239 2240 2160 +3 2240 2161 2160 +3 2161 2064 2160 +3 2064 2063 2160 +3 1930 2063 2064 +3 1797 1930 1931 +3 1683 1797 1798 +3 1683 1798 1684 +3 1683 1684 1593 +3 1684 1594 1593 +3 1594 1510 1593 +3 1510 1509 1593 +3 1427 1509 1510 +3 1375 1427 1428 +3 1375 1428 1376 +3 1375 1376 1313 +3 1376 1314 1313 +3 1314 1246 1313 +3 1246 1245 1313 +3 1197 1245 1246 +3 1119 1197 1198 +3 1039 1119 1120 +3 968 1039 1040 +3 866 968 969 +3 730 866 867 +3 597 730 731 +3 502 597 598 +3 406 502 503 +3 406 503 407 +3 301 407 503 +3 301 503 292 +3 731 292 598 +3 292 503 598 +3 284 292 731 +3 284 731 867 +3 284 867 276 +3 859 276 969 +3 276 867 969 +3 268 276 859 +3 268 859 723 +3 268 723 260 +3 495 260 590 +3 260 723 590 +3 254 260 495 +3 254 495 399 +3 254 399 496 +3 254 496 261 +3 724 261 591 +3 261 496 591 +3 269 261 724 +3 269 724 860 +3 269 860 277 +3 333 348 340 +3 349 348 333 +3 349 333 326 +3 349 326 350 +3 326 319 350 +3 319 351 350 +3 352 351 319 +3 352 319 312 +3 352 312 353 +3 312 305 353 +3 305 354 353 +3 355 354 305 +3 355 305 302 +3 355 302 356 +3 868 277 970 +3 277 860 970 +3 285 277 868 +3 285 868 732 +3 285 732 293 +3 732 599 293 +3 599 504 293 +3 504 302 293 +3 356 302 504 +3 356 504 408 +3 289 282 281 +3 274 273 281 +3 264 216 272 +3 272 209 280 +3 196 197 190 +3 253 239 258 +3 186 181 179 +3 165 155 158 +3 158 151 164 +3 164 144 171 +3 178 177 184 +3 178 184 185 +3 184 190 185 +3 190 191 185 +3 197 191 190 +3 205 197 196 +3 205 196 204 +3 205 204 211 +3 198 206 202 +3 41 42 33 +3 24 31 32 +3 32 39 40 +3 6 7 1 +3 6 1 14 +3 1 22 14 +3 30 22 1 +3 30 1 38 +3 1 46 38 +3 56 46 1 +3 56 1 59 +3 62 78 66 +3 80 86 81 +3 86 83 81 +3 90 86 80 +3 90 80 79 +3 90 79 97 +3 79 78 97 +3 78 103 97 +3 183 129 123 +3 136 129 176 +3 136 169 143 +3 162 150 143 +3 150 157 156 +3 149 156 163 +3 149 170 142 +3 142 177 135 +3 122 118 114 +3 114 112 109 +3 109 106 104 +3 98 104 100 +3 125 121 127 +3 121 119 115 +3 115 113 110 +3 110 107 105 +3 101 99 105 +3 99 94 93 +3 101 94 99 +3 107 101 105 +3 113 107 110 +3 119 113 115 +3 125 119 121 +3 131 125 127 +3 131 127 133 +3 131 133 181 +3 131 181 139 +3 146 139 174 +3 146 167 153 +3 167 160 153 +3 174 167 146 +3 181 174 139 +3 251 286 248 +3 278 246 248 +3 246 270 244 +3 244 262 242 +3 242 230 240 +3 188 132 182 +3 182 138 175 +3 175 145 168 +3 168 152 161 +3 154 159 161 +3 141 134 180 +3 141 180 173 +3 141 173 147 +3 159 147 166 +3 147 173 166 +3 154 147 159 +3 152 154 161 +3 145 152 168 +3 138 145 175 +3 132 138 182 +3 126 132 188 +3 126 188 194 +3 126 194 120 +3 194 199 120 +3 199 116 120 +3 89 72 87 +3 87 74 84 +3 84 75 82 +3 82 73 77 +3 82 77 85 +3 77 88 85 +3 95 88 77 +3 77 71 69 +3 58 54 57 +3 57 44 53 +3 53 36 52 +3 51 52 43 +3 52 35 43 +3 27 52 28 +3 35 52 27 +3 27 20 19 +3 19 12 11 +3 11 2 4 +3 33 34 25 +3 42 34 33 +3 50 42 41 +3 50 41 49 +3 305 310 302 +3 302 303 293 +3 251 293 294 +3 285 293 251 +3 285 251 250 +3 285 250 277 +3 269 250 249 +3 277 250 269 +3 261 249 247 +3 269 249 261 +3 254 247 245 +3 261 247 254 +3 260 245 243 +3 254 245 260 +3 237 229 241 +3 229 221 241 +3 221 268 241 +3 268 243 241 +3 260 243 268 +3 171 137 178 +3 144 137 171 +3 151 144 164 +3 155 151 158 +3 148 155 165 +3 148 165 172 +3 148 172 140 +3 172 179 140 +3 179 133 140 +3 181 133 179 +3 187 181 186 +3 187 186 192 +3 187 192 193 +3 192 198 193 +3 198 200 193 +3 202 200 198 +3 208 202 206 +3 208 206 212 +3 208 212 214 +3 212 219 214 +3 219 276 214 +3 276 221 214 +3 268 221 276 +3 217 211 210 +3 211 204 210 +3 218 211 217 +3 218 217 274 +3 218 274 266 +3 218 266 226 +3 266 258 226 +3 258 233 226 +3 239 233 258 +3 234 239 253 +3 234 253 259 +3 234 259 227 +3 259 267 227 +3 267 275 227 +3 275 219 227 +3 276 219 275 +3 276 275 283 +3 276 283 284 +3 300 309 316 +3 299 309 300 +3 299 300 291 +3 300 284 291 +3 284 283 291 +3 292 284 300 +3 292 300 301 +3 280 203 288 +3 209 203 280 +3 216 209 272 +3 224 216 264 +3 224 264 231 +3 264 256 231 +3 256 252 231 +3 252 238 231 +3 232 238 252 +3 232 252 257 +3 232 257 265 +3 232 265 225 +3 265 273 225 +3 273 217 225 +3 274 217 273 +3 282 274 281 +3 290 282 289 +3 290 289 298 +3 289 297 298 +3 297 307 298 +3 307 308 298 +3 315 308 307 +3 315 307 314 +3 315 314 321 +3 315 321 322 +3 321 328 322 +3 328 329 322 +3 336 329 328 +3 336 328 335 +3 336 335 345 +3 336 345 342 +3 345 337 342 +3 330 337 345 +3 330 345 323 +3 345 316 323 +3 300 316 345 +3 98 92 91 +3 100 92 98 +3 106 100 104 +3 112 106 109 +3 118 112 114 +3 124 118 122 +3 124 122 128 +3 124 128 130 +3 128 135 130 +3 135 178 130 +3 178 137 130 +3 177 178 135 +3 170 177 142 +3 163 170 149 +3 157 163 156 +3 162 157 150 +3 169 162 143 +3 176 169 136 +3 183 176 129 +3 189 183 123 +3 189 123 117 +3 189 117 195 +3 117 344 195 +3 344 203 195 +3 288 203 344 +3 288 344 296 +3 344 306 296 +3 313 306 344 +3 313 344 320 +3 344 327 320 +3 334 327 344 +3 334 344 341 +3 344 335 341 +3 345 335 344 +3 66 76 70 +3 78 76 66 +3 103 78 62 +3 103 62 59 +3 103 59 111 +3 59 1 111 +3 1 117 111 +3 344 117 1 +3 40 47 48 +3 39 47 40 +3 31 39 32 +3 23 31 24 +3 23 24 16 +3 23 16 15 +3 16 8 15 +3 8 7 15 +3 1 7 8 +3 1 8 3 +3 1 3 2 +3 287 213 279 +3 279 220 271 +3 271 228 263 +3 235 255 263 +3 242 255 236 +3 262 255 242 +3 270 262 244 +3 278 270 246 +3 286 278 248 +3 294 286 251 +3 303 294 293 +3 310 303 302 +3 317 310 305 +3 317 305 312 +3 317 312 324 +3 346 333 340 +3 326 333 346 +3 326 346 319 +3 346 324 319 +3 324 312 319 +3 331 324 346 +3 331 346 338 +3 346 347 338 +3 347 343 338 +3 339 343 347 +3 339 347 332 +3 347 325 332 +3 318 325 347 +3 318 347 311 +3 304 347 295 +3 311 347 304 +3 2 45 55 +3 37 45 2 +3 37 2 29 +3 2 21 29 +3 13 21 2 +3 13 2 5 +3 2 12 5 +3 18 25 26 +3 25 34 26 +3 17 25 18 +3 17 18 10 +3 17 10 9 +3 10 4 9 +3 4 3 9 +3 2 3 4 +3 12 2 11 +3 20 12 19 +3 28 20 27 +3 36 28 52 +3 44 36 53 +3 54 44 57 +3 60 54 58 +3 60 58 63 +3 60 63 64 +3 63 69 64 +3 69 67 64 +3 71 67 69 +3 73 71 77 +3 75 73 82 +3 74 75 84 +3 72 74 87 +3 68 72 89 +3 68 89 96 +3 68 96 65 +3 96 102 65 +3 102 61 65 +3 240 222 223 +3 222 215 223 +3 230 222 240 +3 236 230 242 +3 235 236 255 +3 228 235 263 +3 220 228 271 +3 213 220 279 +3 207 213 287 +3 207 287 295 +3 207 295 201 +3 295 347 201 +3 347 199 201 +3 116 199 347 +3 116 347 2 +3 116 2 108 +3 2 61 108 +3 61 102 108 +3 55 61 2 +3 6844 6838 5598 +3 6860 6850 5610 +3 2841 1642 2845 +3 3537 4884 4874 +3 770 936 927 +3 927 1065 1063 +3 1642 2721 1827 +3 1660 2723 1831 +3 963 973 1071 +3 1980 2607 1833 +3 1540 1669 1660 +3 1669 2852 1660 +3 1542 1669 1540 +3 1542 1540 1456 +3 1290 1456 1454 +3 1456 1540 1454 +3 1298 1456 1290 +3 1298 1290 1151 +3 1290 1149 1151 +3 1149 1067 1151 +3 1067 1069 1151 +3 954 1069 1067 +3 954 1067 945 +3 954 945 776 +3 945 774 776 +3 774 629 776 +3 629 631 776 +3 347 633 393 +3 347 393 379 +3 393 629 379 +3 631 629 393 +3 2595 1986 1839 +3 1986 2426 2244 +3 1837 2874 1688 +3 3181 3184 3338 +3 2971 3048 1449 +3 2971 1449 1535 +3 2971 1535 2838 +3 1535 1639 2838 +3 1639 1826 2838 +3 1826 2720 2838 +3 2203 2603 1973 +3 2603 1826 1973 +3 2720 1826 2603 +3 2392 2203 2604 +3 2603 2203 2392 +3 3513 4680 3676 +3 3508 3414 3415 +3 3050 3181 3049 +3 3184 3181 3050 +3 2841 2973 2972 +3 2973 3049 2972 +3 3050 3049 2973 +3 1827 2604 1974 +3 2604 2203 1974 +3 2721 2604 1827 +3 2841 2721 1642 +3 2973 2841 2845 +3 1452 1278 1282 +3 1278 1147 1282 +3 1450 1278 1452 +3 1450 1452 1536 +3 1452 1538 1536 +3 1538 1651 1536 +3 1651 1642 1536 +3 2845 1642 1651 +3 2845 1651 1829 +3 2845 1829 2722 +3 2605 1829 1976 +3 2722 1829 2605 +3 2606 2397 2213 +3 2397 1976 2213 +3 2605 1976 2397 +3 3529 4874 3678 +3 3521 4850 3513 +3 3521 3513 3416 +3 3521 3416 3417 +3 3416 3340 3417 +3 3340 3341 3417 +3 3195 3341 3340 +3 3195 3340 3188 +3 3195 3188 3052 +3 2974 3052 3051 +3 3052 3188 3051 +3 2975 3052 2974 +3 2975 2974 2852 +3 2975 2852 2859 +3 1831 2606 1978 +3 2606 2213 1978 +3 2723 2606 1831 +3 2852 2723 1660 +3 2859 2852 1669 +3 2859 1669 1833 +3 2859 1833 2724 +3 1833 2607 2724 +3 2725 1835 2866 +3 1982 1835 2725 +3 1982 2725 2608 +3 1982 2608 2227 +3 2608 2409 2227 +3 2409 1980 2227 +3 2607 1980 2409 +3 4528 3674 4676 +3 5598 6674 5778 +3 625 369 2 +3 369 624 2 +3 624 769 2 +3 769 923 2 +3 923 1062 2 +3 1062 1144 2 +3 1144 1276 2 +3 1276 1449 2 +3 1449 3048 2 +3 3048 3178 2 +3 3178 5208 2 +3 5056 5208 3178 +3 5056 3178 3337 +3 5056 3337 4964 +3 3495 4964 3413 +3 4964 3337 3413 +3 4828 4964 3495 +3 4828 3495 3673 +3 4828 3673 4674 +3 4526 3673 3806 +3 4674 3673 4526 +3 4676 3503 4838 +3 3674 3503 4676 +3 3807 3674 4528 +3 3807 4528 4032 +3 4528 4250 4032 +3 4250 3806 4032 +3 4526 3806 4250 +3 5610 6678 5782 +3 5780 6844 5604 +3 5224 5218 5060 +3 4844 3503 3508 +3 4844 3508 3675 +3 4844 3675 4678 +3 4530 3675 3808 +3 4678 3675 4530 +3 4532 4264 4041 +3 4264 3808 4041 +3 4530 3808 4264 +3 4874 4982 4978 +3 5244 5230 5068 +3 4232 4892 4694 +3 4984 4892 4232 +3 4984 4232 5076 +3 4232 5272 5076 +3 5416 4232 7078 +3 5272 4232 5416 +3 6688 5796 5652 +3 5794 6880 5644 +3 5410 5264 5414 +3 7962 7960 7808 +3 7806 7958 8300 +3 7806 8300 7614 +3 8300 7514 7614 +3 7418 7514 8300 +3 7418 8300 7224 +3 8300 7062 7224 +3 6264 5924 6190 +3 6264 6190 6534 +3 7520 7646 7636 +3 7636 7814 7812 +3 8300 7962 8216 +3 7960 8300 8206 +3 8300 7958 8206 +3 7962 8300 7960 +3 7810 7962 7808 +3 7810 7808 7624 +3 7810 7624 7630 +3 7624 7516 7630 +3 7516 7518 7630 +3 7422 7518 7516 +3 7422 7516 7420 +3 7422 7420 7234 +3 7422 7234 7240 +3 6966 7066 7064 +3 7066 7234 7064 +3 7240 7234 7066 +3 6968 6966 6838 +3 7066 6966 6968 +3 5778 6530 5922 +3 6530 6176 5922 +3 6674 6530 5778 +3 6838 6674 5598 +3 6968 6838 6844 +3 3415 3338 3339 +3 3338 3184 3339 +3 3414 3338 3415 +3 3503 3414 3508 +3 4838 3503 4844 +3 4838 4844 4968 +3 4838 4968 4966 +3 4968 5060 4966 +3 5060 5058 4966 +3 5218 5058 5060 +3 5398 5218 5224 +3 5398 5224 5400 +3 5398 5400 5492 +3 5398 5492 5490 +3 5492 5604 5490 +3 5604 5598 5490 +3 6844 5598 5604 +3 6676 6844 5780 +3 6676 5780 6532 +3 5780 5924 6532 +3 5924 6264 6532 +3 7524 7666 7656 +3 7812 7966 7964 +3 7966 8216 7964 +3 7814 7966 7812 +3 7646 7814 7636 +3 7522 7646 7520 +3 7522 7520 7426 +3 7520 7424 7426 +3 7424 7246 7426 +3 7246 7256 7426 +3 6970 7070 7068 +3 7070 7246 7068 +3 7256 7246 7070 +3 6972 6970 6850 +3 7070 6970 6972 +3 5782 6534 5926 +3 6534 6190 5926 +3 6678 6534 5782 +3 6850 6678 5610 +3 6972 6850 6860 +3 4850 4864 4976 +3 4850 4976 4970 +3 4976 5068 4970 +3 5068 5062 4970 +3 5230 5062 5068 +3 5402 5230 5244 +3 5402 5244 5408 +3 5402 5408 5500 +3 5402 5500 5494 +3 5500 5624 5494 +3 5624 5610 5494 +3 6860 5610 5624 +3 6860 5624 5788 +3 6860 5788 6680 +3 6536 5788 5932 +3 6680 5788 6536 +3 6538 5790 6682 +3 5790 6870 6682 +3 5934 5790 6538 +3 5934 6538 6208 +3 6538 6280 6208 +3 6280 5932 6208 +3 6536 5932 6280 +3 6296 6224 6544 +3 5796 6544 5940 +3 6544 6224 5940 +3 6688 6544 5796 +3 6888 6688 5652 +3 6888 5652 6980 +3 7972 7968 7820 +3 7656 7820 7816 +3 7820 7968 7816 +3 7666 7820 7656 +3 7528 7666 7524 +3 7528 7524 7432 +3 7266 7432 7428 +3 7432 7524 7428 +3 7276 7432 7266 +3 7276 7266 7076 +3 6974 7076 7072 +3 7076 7266 7072 +3 6978 7076 6974 +3 6978 6974 6870 +3 6978 6870 6880 +3 5264 5254 5074 +3 5410 5254 5264 +3 5502 5410 5414 +3 5502 5414 5506 +3 5502 5506 5644 +3 5502 5644 5634 +3 5644 6870 5634 +3 6870 5790 5634 +3 6880 6870 5644 +3 6686 6880 5794 +3 6686 5794 6542 +3 5794 5938 6542 +3 5938 6224 6542 +3 6224 6296 6542 +3 1063 1147 1145 +3 1147 1278 1145 +3 1065 1147 1063 +3 936 1065 927 +3 772 936 770 +3 772 770 625 +3 772 625 627 +3 625 2 627 +3 2 379 627 +3 347 379 2 +3 6528 6176 6250 +3 6176 6530 6250 +3 5920 6176 6528 +3 5920 6528 5776 +3 6528 6672 5776 +3 6672 6828 5776 +3 6828 5588 5776 +3 5488 5588 6828 +3 5488 6828 6964 +3 5488 6964 5396 +3 6964 7062 5396 +3 7062 8300 5396 +3 8300 5208 5396 +3 2 5208 8300 +3 7078 8626 7284 +3 8626 7434 7284 +3 7530 7434 8626 +3 7530 8626 7674 +3 8626 7822 7674 +3 7974 7822 8626 +3 7974 8626 8250 +3 8626 7972 8250 +3 7968 7972 8626 +3 7968 8626 8234 +3 8626 8216 8234 +3 8216 7966 8234 +3 8300 8216 8626 +3 5416 6980 5508 +3 6980 5652 5508 +3 7078 6980 5416 +3 8626 7078 4232 +3 4298 4231 4546 +3 4231 4694 4546 +3 4232 4694 4231 +3 4073 4231 3812 +3 4692 4884 3679 +3 4692 3679 4544 +3 3679 4231 4544 +3 4231 4298 4544 +3 3812 4231 3679 +3 4978 5074 5070 +3 5074 5254 5070 +3 4982 5074 4978 +3 4884 4982 4874 +3 3679 4884 3537 +3 3676 4532 3809 +3 4532 4041 3809 +3 4680 4532 3676 +3 4850 4680 3513 +3 4864 4850 3521 +3 4864 3521 3677 +3 4864 3677 4686 +3 3677 3810 4686 +3 3810 4538 4686 +3 4282 4538 3810 +3 4282 3810 4057 +3 4282 4057 4540 +3 4057 3811 4540 +3 3811 3678 4540 +3 3678 4688 4540 +3 4874 4688 3678 +3 3537 4874 3529 +3 3537 3529 3418 +3 3537 3418 3419 +3 3418 3342 3419 +3 3342 3343 3419 +3 3210 3343 3342 +3 3210 3342 3202 +3 3210 3202 3054 +3 2976 3054 3053 +3 3054 3202 3053 +3 2977 3054 2976 +3 2977 2976 2866 +3 2977 2866 2874 +3 1544 1460 1546 +3 1544 1546 1688 +3 1544 1688 1678 +3 1688 2866 1678 +3 2866 1835 1678 +3 2874 2866 1688 +3 2726 2874 1837 +3 2726 1837 2609 +3 2244 2609 1984 +3 2609 1837 1984 +3 2426 2609 2244 +3 2595 2426 1986 +3 2712 2595 1839 +3 2712 1839 1697 +3 2712 1697 2823 +3 1306 1460 1458 +3 1460 1544 1458 +3 1318 1460 1306 +3 1318 1306 1155 +3 1306 1153 1155 +3 1153 1071 1155 +3 1071 1073 1155 +3 973 1073 1071 +3 780 973 963 +3 780 963 778 +3 780 778 633 +3 780 633 635 +3 633 347 635 +3 347 411 635 +3 637 411 347 +3 637 347 782 +3 347 981 782 +3 1075 981 347 +3 1075 347 1157 +3 347 1326 1157 +3 1462 1326 347 +3 1462 347 3163 +3 1462 3163 1548 +3 3163 1697 1548 +3 2823 1697 3163 +3 2823 3163 2963 +3 3163 3040 2963 +3 3162 3040 3163 +3 3023 2978 2951 +3 2430 2427 2508 +3 2430 2508 2610 +3 2694 2610 2590 +3 2610 2508 2590 +3 2727 2610 2694 +3 2727 2694 2798 +3 2727 2798 2880 +3 2951 2880 2875 +3 2880 2798 2875 +3 2978 2880 2951 +3 3055 2978 3023 +3 3055 3023 3098 +3 3055 3098 3145 +3 3055 3145 3216 +3 3145 3211 3216 +3 3211 3267 3216 +3 3267 3344 3216 +3 3388 3344 3313 +3 3344 3267 3313 +3 3420 3344 3388 +3 3420 3388 3460 +3 3420 3460 3544 +3 3652 3544 3538 +3 3544 3460 3538 +3 3680 3544 3652 +3 3680 3652 3785 +3 3680 3785 3813 +3 4008 3813 3908 +3 3813 3785 3908 +3 4077 3813 4008 +3 4077 4008 4074 +3 3632 3625 3758 +3 3447 3453 3375 +3 3381 3300 3375 +3 3254 3300 3306 +3 3254 3260 3196 +3 3196 3203 3132 +3 2944 2938 3010 +3 2670 2675 2565 +3 2565 2571 2482 +3 2410 2482 2414 +3 2482 2488 2414 +3 2571 2488 2482 +3 2675 2571 2565 +3 2779 2675 2670 +3 2779 2670 2774 +3 2779 2774 2867 +3 2938 2867 2860 +3 2867 2774 2860 +3 2944 2867 2938 +3 3016 2944 3010 +3 3016 3010 3085 +3 3016 3085 3091 +3 3085 3132 3091 +3 3132 3138 3091 +3 3203 3138 3132 +3 3260 3203 3196 +3 3306 3260 3254 +3 3381 3306 3300 +3 3453 3381 3375 +3 3530 3453 3447 +3 3625 3530 3522 +3 3530 3447 3522 +3 3632 3530 3625 +3 3765 3632 3758 +3 3765 3758 3881 +3 3765 3881 3888 +3 3881 3981 3888 +3 3981 3988 3888 +3 4062 3988 3981 +3 4062 3981 4058 +3 6987 5407 4206 +3 4539 4195 4273 +3 6271 5933 6199 +3 6271 6199 6535 +3 6199 5931 6535 +3 5931 5787 6535 +3 5787 6679 6535 +3 4143 4273 4109 +3 4273 4185 4109 +3 4537 4273 4143 +3 4537 4143 4189 +3 4537 4189 4685 +3 4189 4206 4685 +3 4206 4855 4685 +3 4975 4855 4206 +3 4975 4206 5067 +3 4206 5235 5067 +3 5407 5235 4206 +3 5499 5407 6987 +3 5499 6987 5615 +3 6987 5787 5615 +3 6679 5787 6987 +3 6679 6987 6851 +3 6987 6971 6851 +3 7069 6971 6987 +3 7069 6987 7093 +3 7069 7093 7247 +3 7093 7291 7247 +3 7291 7425 7247 +3 7521 7425 7291 +3 7521 7291 8423 +3 7521 8423 7637 +3 8423 7813 7637 +3 7965 7813 8423 +3 7965 8423 8225 +3 8423 8545 8225 +3 8545 7967 8225 +3 7815 7967 8545 +3 7815 8545 7647 +3 8545 7523 7647 +3 7427 7523 8545 +3 7427 8545 7257 +3 8545 7071 7257 +3 4145 4171 4137 +3 4145 4137 4109 +3 4145 4109 4173 +3 4109 4178 4173 +3 4185 4178 4109 +3 4195 4185 4273 +3 4208 4195 4539 +3 4208 4539 4687 +3 4208 4687 4222 +3 4687 4865 4222 +3 4865 4977 4222 +3 4977 5069 4222 +3 5069 5245 4222 +3 5245 5409 4222 +3 5409 7071 4222 +3 7071 8545 4222 +3 6973 7071 5409 +3 6973 5409 5501 +3 6973 5501 6861 +3 5789 6861 5625 +3 6861 5501 5625 +3 6681 6861 5789 +3 6681 5789 6537 +3 5789 5933 6537 +3 5933 6271 6537 +3 7957 8361 8197 +3 8361 7959 8197 +3 7807 7959 8361 +3 7807 8361 7615 +3 8361 7515 7615 +3 6671 5775 5579 +3 6527 6241 6167 +3 6241 6529 6167 +3 6529 5921 6167 +3 5777 6529 6673 +3 5921 6529 5777 +3 4107 4241 4527 +3 4829 4107 4675 +3 4107 4527 4675 +3 4805 4107 4829 +3 4805 4829 4965 +3 4805 4965 5057 +3 4805 5057 5209 +3 4805 5209 5397 +3 4805 5397 6231 +3 5397 5489 6231 +3 5489 5589 6231 +3 5589 5777 6231 +3 5777 6673 6231 +3 6673 6829 6231 +3 6829 6965 6231 +3 6965 7063 6231 +3 7063 7225 6231 +3 7225 7419 6231 +3 7419 7515 6231 +3 7515 8361 6231 +3 7215 7061 8299 +3 7215 8299 7417 +3 8299 7513 7417 +3 7605 7513 8299 +3 7605 8299 7805 +3 8299 7957 7805 +3 8361 7957 8299 +3 5775 6527 5919 +3 6527 6167 5919 +3 6671 6527 5775 +3 6819 6671 5579 +3 6819 5579 6963 +3 5579 5487 6963 +3 5487 5395 6963 +3 5395 7061 6963 +3 8299 7061 5395 +3 8299 5395 4092 +3 5395 5199 4092 +3 5199 5055 4092 +3 5055 4963 4092 +3 4963 4819 4092 +3 4819 4673 4092 +3 4673 4525 4092 +3 4525 4241 4092 +3 4241 4107 4092 +3 1555 1556 1617 +3 1555 1617 1814 +3 1555 1814 2302 +3 2251 2257 8628 +3 2257 2266 1948 +3 2266 1814 1948 +3 2302 1814 2266 +3 2302 2266 2280 +3 2302 2280 2303 +3 2462 2119 2545 +3 2545 2023 2650 +3 2650 1890 2754 +3 2708 1884 2625 +3 2625 2017 2520 +3 1653 1756 2309 +3 1653 2309 1750 +3 1877 2304 1744 +3 1717 2266 1849 +3 1953 1849 2257 +3 1953 2251 2085 +3 1953 0 8627 +3 2257 2251 1953 +3 2266 2257 1849 +3 2280 2266 1717 +3 2280 1717 1644 +3 2280 1644 2303 +3 1644 1744 2303 +3 1744 2304 2303 +3 2106 2305 2010 +3 2305 1877 2010 +3 2304 1877 2305 +3 2306 2106 2207 +3 2305 2106 2306 +3 2016 2306 2112 +3 2306 2207 2112 +3 2307 2306 2016 +3 2307 2016 1883 +3 2307 1883 2308 +3 1883 1750 2308 +3 1750 2309 2308 +3 2310 1756 1889 +3 2309 1756 2310 +3 2118 2311 2022 +3 2311 1889 2022 +3 2310 1889 2311 +3 2119 2312 2214 +3 2312 2118 2214 +3 2311 2118 2312 +3 2285 1645 1705 +3 1745 1645 2285 +3 1745 2285 2349 +3 1745 2349 1878 +3 2349 2363 1878 +3 2363 2011 1878 +3 2107 2011 2363 +3 2107 2363 2520 +3 2107 2520 2208 +3 2520 2113 2208 +3 2017 2113 2520 +3 1884 2017 2625 +3 1751 1884 2708 +3 1751 2708 2812 +3 1751 2812 1654 +3 2812 2846 1654 +3 2846 2754 1654 +3 2754 1757 1654 +3 1890 1757 2754 +3 2023 1890 2650 +3 2119 2023 2545 +3 2312 2119 2462 +3 2312 2462 2398 +3 4162 4133 4164 +3 4164 4134 4166 +3 4166 4135 4168 +3 4159 3995 4157 +3 4150 4126 4152 +3 4152 4127 4154 +3 4154 4128 4156 +3 4129 4158 4156 +3 4149 3888 3988 +3 3765 3888 4149 +3 3765 4149 4151 +3 3765 4151 3632 +3 4151 4153 3632 +3 4153 3530 3632 +3 3639 3530 4153 +3 3639 4153 4155 +3 3639 4155 3772 +3 4155 4157 3772 +3 4157 3895 3772 +3 3995 3895 4157 +3 4066 3995 4159 +3 4066 4159 4002 +3 4159 4161 4002 +3 4161 3902 4002 +3 3779 3902 4161 +3 3779 4161 4163 +3 3779 4163 3646 +3 4163 4165 3646 +3 4165 3538 3646 +3 3652 3538 4165 +3 3652 4165 4167 +3 3652 4167 3785 +3 4167 4169 3785 +3 4169 3908 3785 +3 4008 3908 4169 +3 4008 4169 4136 +3 4008 4136 4074 +3 4168 4136 4170 +3 4136 4169 4170 +3 4135 4136 4168 +3 4134 4135 4166 +3 4133 4134 4164 +3 4132 4133 4162 +3 4132 4162 4160 +3 4132 4160 4131 +3 4160 4158 4131 +3 4158 4130 4131 +3 4129 4130 4158 +3 4128 4129 4156 +3 4127 4128 4154 +3 4126 4127 4152 +3 4125 4126 4150 +3 4125 4150 4148 +3 4125 4148 4124 +3 4148 4147 4124 +3 4147 4149 4124 +3 4149 3988 4124 +3 3988 4062 4124 +3 2631 2713 2735 +3 3919 4017 4021 +3 3799 4017 3919 +3 3799 3919 3819 +3 3799 3819 3696 +3 3799 3696 3666 +3 3696 3563 3666 +3 3563 3481 3666 +3 3427 3481 3488 +3 3481 3563 3488 +3 3406 3481 3427 +3 3406 3427 3355 +3 3406 3355 3330 +3 3234 3330 3280 +3 3330 3355 3280 +3 3164 3330 3234 +3 3164 3234 3171 +3 3164 3171 3112 +3 3164 3112 3041 +3 2990 3041 3065 +3 3041 3112 3065 +3 2964 3041 2990 +3 2964 2990 2918 +3 2964 2918 2824 +3 2735 2824 2831 +3 2824 2918 2831 +3 2713 2824 2735 +3 2596 2713 2631 +3 2596 2631 2526 +3 2596 2526 2443 +3 2596 2443 2382 +3 2443 2386 2382 +3 1260 1 1136 +3 1 1054 1136 +3 907 1054 1 +3 907 1 761 +3 1 616 761 +3 357 1 617 +3 616 1 357 +3 358 359 619 +3 1444 1445 1530 +3 1443 1442 1262 +3 1262 1261 1138 +3 909 762 763 +3 617 618 763 +3 1 358 618 +3 912 1060 1059 +3 1446 1447 1532 +3 1823 1628 2828 +3 768 2 914 +3 2 1061 914 +3 1143 1061 2 +3 1143 2 1267 +3 2 1448 1267 +3 2829 2828 1629 +3 2828 1628 1629 +3 1628 1532 1629 +3 1532 1533 1629 +3 1447 1533 1532 +3 1266 1447 1446 +3 1266 1446 1265 +3 1266 1265 1142 +3 360 2 623 +3 2 768 623 +3 622 2 360 +3 8300 3170 2 +3 1059 1142 1141 +3 1142 1265 1141 +3 1060 1142 1059 +3 913 1060 912 +3 913 912 767 +3 912 766 767 +3 766 621 767 +3 621 622 767 +3 2 622 621 +3 2 621 359 +3 2 359 1 +3 2294 1623 1818 +3 1527 1623 2294 +3 1527 2294 1441 +3 2294 1260 1441 +3 1 1260 2294 +3 2295 1966 1819 +3 2193 1966 2295 +3 2193 2295 1965 +3 2295 1818 1965 +3 2294 1818 2295 +3 2713 1819 2824 +3 2295 1819 2713 +3 2295 2713 2596 +3 2295 2596 2382 +3 1821 2715 2598 +3 3483 4668 3668 +3 3331 3330 3165 +3 3165 3164 3042 +3 2965 3042 3041 +3 2965 2964 2825 +3 2714 2825 1625 +3 2714 1625 1820 +3 2714 1820 1967 +3 2714 1967 2597 +3 2715 1626 2826 +3 1821 1626 2715 +3 1968 1821 2598 +3 1968 2598 2194 +3 2598 2383 2194 +3 2383 1967 2194 +3 2597 1967 2383 +3 2968 2828 2969 +3 3669 4815 3484 +3 3484 4814 3483 +3 3484 3483 3408 +3 3484 3408 3409 +3 3408 3332 3409 +3 3332 3333 3409 +3 3167 3333 3332 +3 3167 3332 3166 +3 3167 3166 3044 +3 2966 3044 3043 +3 3044 3166 3043 +3 2967 3044 2966 +3 2967 2966 2826 +3 2967 2826 2827 +3 1972 2602 2196 +3 2602 2385 2196 +3 2719 2602 1972 +3 2719 1972 1825 +3 2719 1825 2830 +3 1534 2830 1630 +3 2830 1825 1630 +3 2970 2830 1534 +3 2970 1534 3047 +3 1534 1448 3047 +3 1448 2 3047 +3 2 3170 3047 +3 4962 3412 3336 +3 3485 4816 3670 +3 3486 4816 3485 +3 3486 3485 3410 +3 3486 3410 3411 +3 3410 3334 3411 +3 3334 3335 3411 +3 3169 3335 3334 +3 3169 3334 3168 +3 3169 3168 3046 +3 2968 3046 3045 +3 3046 3168 3045 +3 2969 3046 2968 +3 2829 2969 2828 +3 2718 2829 1629 +3 2718 1629 1824 +3 2718 1824 2601 +3 1824 1971 2601 +3 1971 2196 2601 +3 2196 2385 2601 +3 4233 4093 4518 +3 4093 4666 4518 +3 3666 4093 3799 +3 4093 4017 3799 +3 4666 4093 3666 +3 4666 3666 4812 +3 5572 6664 5768 +3 5767 6811 5571 +3 5574 6666 5770 +3 5769 6813 5573 +3 5573 6812 5572 +3 5573 5572 5480 +3 5573 5480 5481 +3 5480 5388 5481 +3 5388 5389 5481 +3 5193 5389 5388 +3 5193 5388 5192 +3 5193 5192 5049 +3 4956 5049 5048 +3 5049 5192 5048 +3 4957 5049 4956 +3 4957 4956 4812 +3 4957 4812 4813 +3 2600 1823 2717 +3 1823 2828 2717 +3 1970 1823 2600 +3 1970 2600 2195 +3 2600 2384 2195 +3 2384 2599 2195 +3 2599 1969 2195 +3 1822 1969 2599 +3 1822 2599 2716 +3 1822 2716 2827 +3 1822 2827 1627 +3 2827 2826 1627 +3 2826 1626 1627 +3 1626 1530 1627 +3 1530 1531 1627 +3 1445 1531 1530 +3 1264 1445 1444 +3 1264 1444 1263 +3 1264 1263 1140 +3 1263 1139 1140 +3 1139 1057 1140 +3 1057 1058 1140 +3 911 1058 1057 +3 911 1057 910 +3 911 910 765 +3 910 764 765 +3 764 619 765 +3 619 620 765 +3 359 620 619 +3 1 359 358 +3 617 1 618 +3 762 617 763 +3 908 762 909 +3 908 909 1056 +3 908 1056 1055 +3 1056 1138 1055 +3 1138 1137 1055 +3 1261 1137 1138 +3 1442 1261 1262 +3 1528 1442 1443 +3 1528 1443 1529 +3 1528 1529 1625 +3 1528 1625 1624 +3 1625 2825 1624 +3 2825 2824 1624 +3 2824 1819 1624 +3 2964 2824 2825 +3 3041 2964 2965 +3 3164 3041 3042 +3 3330 3164 3165 +3 3406 3330 3331 +3 3406 3331 3407 +3 3406 3407 3481 +3 3407 3482 3481 +3 3482 4812 3481 +3 4812 3666 3481 +3 4813 4812 3482 +3 4813 3482 3667 +3 4813 3667 4667 +3 3667 3800 4667 +3 3800 4519 4667 +3 4520 4234 4018 +3 4234 3800 4018 +3 4519 3800 4234 +3 4522 4235 4019 +3 4522 4019 3803 +3 4522 3803 3670 +3 4522 3670 4670 +3 3670 4816 4670 +3 5575 6814 5574 +3 5575 5574 5482 +3 5575 5482 5483 +3 5482 5390 5483 +3 5390 5391 5483 +3 5195 5391 5390 +3 5195 5390 5194 +3 5195 5194 5051 +3 4958 5051 5050 +3 5051 5194 5050 +3 4959 5051 4958 +3 4959 4958 4814 +3 4959 4814 4815 +3 3668 4520 3801 +3 4520 4018 3801 +3 4668 4520 3668 +3 4814 4668 3483 +3 4815 4814 3484 +3 4669 4815 3669 +3 4669 3669 4521 +3 3669 3802 4521 +3 3802 4019 4521 +3 4019 4235 4521 +3 3805 4524 4020 +3 4672 4524 3805 +3 4672 3805 3672 +3 4672 3672 4818 +3 3412 4818 3487 +3 4818 3672 3487 +3 4962 4818 3412 +3 5054 4962 3336 +3 5054 3336 5198 +3 3336 3170 5198 +3 3170 8300 5198 +3 8300 5394 5198 +3 5393 5392 5197 +3 5197 5196 5053 +3 6233 6159 6520 +3 7410 7411 7506 +3 7053 5387 6955 +3 5571 6955 5479 +3 6955 5387 5479 +3 6811 6955 5571 +3 6663 6811 5767 +3 6663 5767 6519 +3 5767 5911 6519 +3 5911 6159 6519 +3 6159 6233 6519 +3 6234 5913 6160 +3 6234 6160 6522 +3 7508 7601 7600 +3 7798 7951 7950 +3 7799 7951 7798 +3 7799 7798 7599 +3 7798 7598 7599 +3 7598 7506 7599 +3 7506 7507 7599 +3 7411 7507 7506 +3 7209 7411 7410 +3 7209 7410 7208 +3 7209 7208 7055 +3 6956 7055 7054 +3 7055 7208 7054 +3 6957 7055 6956 +3 6957 6956 6812 +3 6957 6812 6813 +3 5768 6520 5912 +3 6520 6159 5912 +3 6664 6520 5768 +3 6812 6664 5572 +3 6813 6812 5573 +3 6665 6813 5769 +3 6665 5769 5913 +3 6665 5913 6521 +3 5913 6234 6521 +3 6235 6161 6524 +3 7955 8300 7954 +3 8300 8191 7954 +3 4665 4093 4517 +3 4093 4233 4517 +3 4092 4093 4665 +3 4092 4665 4811 +3 4092 4811 4955 +3 4092 4955 5047 +3 4092 5047 5191 +3 4092 5191 5387 +3 4092 5387 8299 +3 5387 7053 8299 +3 7053 7207 8299 +3 7207 7409 8299 +3 7409 7505 8299 +3 7505 7597 8299 +3 7597 7797 8299 +3 7797 7949 8299 +3 7949 8189 8299 +3 8189 7950 8299 +3 7950 7951 8299 +3 7951 8190 8299 +3 8190 8191 8299 +3 8191 8300 8299 +3 7953 8191 8190 +3 7953 8190 7952 +3 7953 7952 7801 +3 7600 7801 7800 +3 7801 7952 7800 +3 7601 7801 7600 +3 7509 7601 7508 +3 7509 7508 7413 +3 7210 7413 7412 +3 7413 7508 7412 +3 7211 7413 7210 +3 7211 7210 7057 +3 7210 7056 7057 +3 7056 6958 7057 +3 6958 6959 7057 +3 6815 6958 6814 +3 6959 6958 6815 +3 5770 6522 5914 +3 6522 6160 5914 +3 6666 6522 5770 +3 6814 6666 5574 +3 6815 6814 5575 +3 6815 5575 5771 +3 6815 5771 6667 +3 6161 6523 5915 +3 6523 5771 5915 +3 6667 5771 6523 +3 6816 6668 5772 +3 6668 6524 5772 +3 6524 5916 5772 +3 6161 5916 6524 +3 6523 6161 6235 +3 6236 6162 6526 +3 6526 5918 6670 +3 6670 5774 6818 +3 7416 8300 7512 +3 8300 7604 7512 +3 7804 7604 8300 +3 7804 8300 7956 +3 8300 8192 7956 +3 7955 8192 8300 +3 7803 7955 7954 +3 7803 7954 7802 +3 7803 7802 7603 +3 7510 7603 7602 +3 7603 7802 7602 +3 7511 7603 7510 +3 7511 7510 7415 +3 7510 7414 7415 +3 7414 7212 7415 +3 7212 7213 7415 +3 7059 7213 7212 +3 7059 7212 7058 +3 7059 7058 6960 +3 7059 6960 6961 +3 6817 6960 6816 +3 6961 6960 6817 +3 4523 4020 4236 +3 4020 4524 4236 +3 3804 4020 4523 +3 3804 4523 4671 +3 3804 4671 3671 +3 4671 4817 3671 +3 4817 3486 3671 +3 4816 3486 4817 +3 4816 4817 4961 +3 4816 4961 4960 +3 4961 5053 4960 +3 5053 5052 4960 +3 5196 5052 5053 +3 5392 5196 5197 +3 5484 5392 5393 +3 5484 5393 5485 +3 5484 5485 5577 +3 5484 5577 5576 +3 5577 6816 5576 +3 6816 5772 5576 +3 6817 6816 5577 +3 6817 5577 5773 +3 6817 5773 6669 +3 6162 6525 5917 +3 6525 5773 5917 +3 6669 5773 6525 +3 7060 8300 7214 +3 8300 7416 7214 +3 5394 8300 7060 +3 5394 7060 6962 +3 5394 6962 5486 +3 6962 6818 5486 +3 6818 5578 5486 +3 5774 5578 6818 +3 5918 5774 6670 +3 6162 5918 6526 +3 6525 6162 6236 +3 355 525 354 +3 354 657 353 +3 353 792 352 +3 352 899 351 +3 1005 350 351 +3 350 1084 349 +3 349 1164 348 +3 2989 2374 2917 +3 2822 2917 2375 +3 2822 2376 2734 +3 2734 2377 2630 +3 2630 2378 2525 +3 2525 2379 2502 +3 2502 2380 2425 +3 2380 2381 2425 +3 2379 2380 2502 +3 2378 2379 2525 +3 2377 2378 2630 +3 2376 2377 2734 +3 2375 2376 2822 +3 2374 2375 2917 +3 2369 2989 3064 +3 2374 2989 2369 +3 3163 3064 3162 +3 2369 3064 3163 +3 2369 3163 2361 +3 1386 2356 346 +3 2356 3163 346 +3 2361 3163 2356 +3 2271 2279 1608 +3 2271 1715 2264 +3 2264 1848 2252 +3 2252 1950 2086 +3 1848 1950 2252 +3 1715 1848 2264 +3 1608 1715 2271 +3 1523 1608 2279 +3 1523 2279 2292 +3 1523 2292 1474 +3 2356 1474 2345 +3 1474 2292 2345 +3 1386 1474 2356 +3 1256 1386 346 +3 1256 346 1164 +3 348 346 340 +3 1164 346 348 +3 1084 1164 349 +3 1005 1084 350 +3 899 1005 351 +3 792 899 352 +3 657 792 353 +3 525 657 354 +3 428 525 355 +3 428 355 356 +3 428 356 408 +3 4142 4231 4072 +3 4231 4073 4072 +3 2242 2423 2424 +3 2352 2423 2242 +3 2352 2242 2241 +3 406 407 300 +3 407 301 300 +3 4139 4091 4231 +3 4139 4231 4140 +3 4231 4141 4140 +3 4142 4141 4231 +3 3915 4232 3914 +3 4232 4088 3914 +3 4089 4088 4232 +3 4089 4232 4090 +3 4232 4091 4090 +3 4231 4091 4232 +3 406 300 522 +3 300 656 522 +3 789 656 300 +3 789 300 894 +3 1209 1208 1130 +3 1209 1130 345 +3 1130 1082 345 +3 1082 1000 345 +3 1000 894 345 +3 894 300 345 +3 2913 2274 2983 +3 2265 2083 2084 +3 2265 2084 2274 +3 3110 3038 3111 +3 3038 2983 3111 +3 2983 2084 3111 +3 2274 2084 2983 +3 2284 2274 2913 +3 2284 2913 2816 +3 2284 2816 2293 +3 2816 2732 2293 +3 2732 2346 2293 +3 2347 2732 2629 +3 2346 2732 2347 +3 2348 2629 2524 +3 2347 2629 2348 +3 2352 2524 2423 +3 2348 2524 2352 +3 4108 4105 4104 +3 4106 4105 4108 +3 4093 4095 4094 +3 4096 4095 4093 +3 4096 4093 4097 +3 4093 4092 4097 +3 4092 4098 4097 +3 4099 4098 4092 +3 4099 4092 4100 +3 4092 4107 4100 +3 4107 4101 4100 +3 4102 4101 4107 +3 4102 4107 4103 +3 4107 4104 4103 +3 4108 4104 4107 +3 2301 2300 2294 +3 2301 2294 2299 +3 2294 2295 2299 +3 2295 2298 2299 +3 2297 2298 2295 +3 2297 2295 2296 +3 2339 2335 2340 +3 2338 2340 2337 +3 2340 2336 2337 +3 2335 2336 2340 +3 2334 2335 2339 +3 2334 2339 2333 +3 2339 2332 2333 +3 2321 2330 2331 +3 2328 2324 2327 +3 2327 2325 2326 +3 2324 2325 2327 +3 2323 2324 2328 +3 2323 2328 2322 +3 2308 2316 2317 +3 2316 2309 2315 +3 2314 2315 2310 +3 2314 2311 2313 +3 2311 2312 2313 +3 2310 2311 2314 +3 2309 2310 2315 +3 2308 2309 2316 +3 2307 2308 2317 +3 2307 2317 2318 +3 2307 2318 2306 +3 2330 2322 2329 +3 2322 2328 2329 +3 2321 2322 2330 +3 2320 2321 2331 +3 2320 2331 2319 +3 2331 2332 2319 +3 2332 2339 2319 +3 2339 2302 2319 +3 2302 2306 2319 +3 2306 2318 2319 +3 2305 2306 2302 +3 2305 2302 2304 +3 2302 2303 2304 +3 2386 2295 2382 +3 2296 2295 2386 +3 2313 2312 2401 +3 2312 2398 2401 +3 2325 2414 2326 +3 2410 2414 2325 +3 2340 2338 2427 +3 2340 2427 2430 +3 4074 4138 4077 +3 4136 4138 4074 +3 4123 4124 4062 +3 4123 4062 4058 +3 4046 4044 4110 +3 4046 4110 4111 +3 4086 4106 4108 +3 4093 4094 4021 +3 4093 4021 4017 +3 4127 4120 4128 +3 4133 4138 4134 +3 4138 4135 4134 +3 4136 4135 4138 +3 4137 4133 4132 +3 4138 4133 4137 +3 4117 4109 4137 +3 4109 4114 4110 +3 4111 4110 4112 +3 4110 4113 4112 +3 4114 4113 4110 +3 4115 4114 4109 +3 4115 4109 4116 +3 4109 4117 4116 +3 4130 4137 4131 +3 4137 4132 4131 +3 4117 4137 4130 +3 4117 4130 4129 +3 4117 4129 4118 +3 4129 4128 4118 +3 4128 4119 4118 +3 4120 4119 4128 +3 4121 4120 4127 +3 4121 4127 4126 +3 4121 4126 4125 +3 4121 4125 4122 +3 4123 4125 4124 +3 4122 4125 4123 +3 0 1953 2085 +3 1948 8628 2257 +3 8628 1948 8627 +3 0 2251 8628 +3 0 8628 8627 +3 2251 0 2085 diff --git a/Mesh_3/examples/Mesh_3/mesh_3D_image.cpp b/Mesh_3/examples/Mesh_3/mesh_3D_image.cpp index a1f697d1db0..b5f1ee1832d 100644 --- a/Mesh_3/examples/Mesh_3/mesh_3D_image.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_3D_image.cpp @@ -13,7 +13,15 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Labeled_image_mesh_domain_3 Mesh_domain; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, // Same as sequential + CGAL::Parallel_tag // Tag to activate parallelism + >::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; // Criteria diff --git a/Mesh_3/examples/Mesh_3/mesh_3D_image_variable_size.cpp b/Mesh_3/examples/Mesh_3/mesh_3D_image_variable_size.cpp index 0acdfdf5157..b4f85519dda 100644 --- a/Mesh_3/examples/Mesh_3/mesh_3D_image_variable_size.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_3D_image_variable_size.cpp @@ -14,7 +14,15 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Labeled_image_mesh_domain_3 Mesh_domain; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, // Same as sequential + CGAL::Parallel_tag // Tag to activate parallelism + >::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; // Criteria diff --git a/Mesh_3/examples/Mesh_3/mesh_implicit_ellipsoid.cpp b/Mesh_3/examples/Mesh_3/mesh_implicit_ellipsoid.cpp index dbc162aa2c4..66de13b3476 100644 --- a/Mesh_3/examples/Mesh_3/mesh_implicit_ellipsoid.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_implicit_ellipsoid.cpp @@ -60,7 +60,7 @@ int main() CGAL::perturb_mesh_3(c3t3, domain, time_limit=5, sliver_bound=12); // Exudation - CGAL::exude_mesh_3(c3t3); + CGAL::exude_mesh_3(c3t3, domain); // Output medit_file.open("out_optimized.mesh"); diff --git a/Mesh_3/examples/Mesh_3/mesh_implicit_sphere.cpp b/Mesh_3/examples/Mesh_3/mesh_implicit_sphere.cpp index 55a9350f40b..7cc091fc6ce 100644 --- a/Mesh_3/examples/Mesh_3/mesh_implicit_sphere.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_implicit_sphere.cpp @@ -15,7 +15,15 @@ typedef FT (Function)(const Point&); typedef CGAL::Implicit_mesh_domain_3 Mesh_domain; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, // Same as sequential + CGAL::Parallel_tag // Tag to activate parallelism + >::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; // Criteria diff --git a/Mesh_3/examples/Mesh_3/mesh_implicit_sphere_variable_size.cpp b/Mesh_3/examples/Mesh_3/mesh_implicit_sphere_variable_size.cpp index acf57d24fa6..1fa591d77c6 100644 --- a/Mesh_3/examples/Mesh_3/mesh_implicit_sphere_variable_size.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_implicit_sphere_variable_size.cpp @@ -15,7 +15,15 @@ typedef FT (Function)(const Point&); typedef CGAL::Implicit_mesh_domain_3 Mesh_domain; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, // Same as sequential + CGAL::Parallel_tag // Tag to activate parallelism + >::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; // Criteria diff --git a/Mesh_3/examples/Mesh_3/mesh_optimization_example.cpp b/Mesh_3/examples/Mesh_3/mesh_optimization_example.cpp index 31b12b91429..25cf73dc012 100644 --- a/Mesh_3/examples/Mesh_3/mesh_optimization_example.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_optimization_example.cpp @@ -13,7 +13,15 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Labeled_image_mesh_domain_3 Mesh_domain; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, // Same as sequential + CGAL::Parallel_tag // Tag to activate parallelism + >::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; // Mesh Criteria diff --git a/Mesh_3/examples/Mesh_3/mesh_optimization_lloyd_example.cpp b/Mesh_3/examples/Mesh_3/mesh_optimization_lloyd_example.cpp index 5f5062d2322..04a2b869653 100644 --- a/Mesh_3/examples/Mesh_3/mesh_optimization_lloyd_example.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_optimization_lloyd_example.cpp @@ -13,7 +13,15 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Labeled_image_mesh_domain_3 Mesh_domain; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, // Same as sequential + CGAL::Parallel_tag // Tag to activate parallelism + >::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; // Mesh Criteria @@ -44,7 +52,7 @@ int main() no_perturb(), no_exude()); CGAL::lloyd_optimize_mesh_3(c3t3_bis, domain, time_limit=30); - CGAL::exude_mesh_3(c3t3_bis, sliver_bound=10, time_limit=10); + CGAL::exude_mesh_3(c3t3_bis, domain, sliver_bound=10, time_limit=10); // Output std::ofstream medit_file("out.mesh"); diff --git a/Mesh_3/examples/Mesh_3/mesh_polyhedral_domain.cpp b/Mesh_3/examples/Mesh_3/mesh_polyhedral_domain.cpp index 1cc6a6c5acf..a03462e0f29 100644 --- a/Mesh_3/examples/Mesh_3/mesh_polyhedral_domain.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_polyhedral_domain.cpp @@ -17,7 +17,15 @@ typedef CGAL::Polyhedron_3 Polyhedron; typedef CGAL::Polyhedral_mesh_domain_3 Mesh_domain; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, // Same as sequential + CGAL::Parallel_tag // Tag to activate parallelism + >::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; // Criteria diff --git a/Mesh_3/examples/Mesh_3/mesh_polyhedral_domain_with_features.cpp b/Mesh_3/examples/Mesh_3/mesh_polyhedral_domain_with_features.cpp index 5d30be19e2d..118aa0a0198 100644 --- a/Mesh_3/examples/Mesh_3/mesh_polyhedral_domain_with_features.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_polyhedral_domain_with_features.cpp @@ -12,7 +12,15 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Polyhedral_mesh_domain_with_features_3 Mesh_domain; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, // Same as sequential + CGAL::Parallel_tag // Tag to activate parallelism + >::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3< Tr,Mesh_domain::Corner_index,Mesh_domain::Curve_segment_index> C3t3; diff --git a/Mesh_3/examples/Mesh_3/mesh_two_implicit_spheres_with_balls.cpp b/Mesh_3/examples/Mesh_3/mesh_two_implicit_spheres_with_balls.cpp index c2ede3260ba..15309842222 100644 --- a/Mesh_3/examples/Mesh_3/mesh_two_implicit_spheres_with_balls.cpp +++ b/Mesh_3/examples/Mesh_3/mesh_two_implicit_spheres_with_balls.cpp @@ -23,7 +23,15 @@ typedef std::vector Polyline_3; typedef std::list Polylines; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, // Same as sequential + CGAL::Parallel_tag // Tag to activate parallelism + >::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3< Tr,Mesh_domain::Corner_index,Mesh_domain::Curve_segment_index> C3t3; diff --git a/Mesh_3/include/CGAL/Compact_mesh_cell_base_3.h b/Mesh_3/include/CGAL/Compact_mesh_cell_base_3.h index 114469e3d87..0f995e30aed 100644 --- a/Mesh_3/include/CGAL/Compact_mesh_cell_base_3.h +++ b/Mesh_3/include/CGAL/Compact_mesh_cell_base_3.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -33,17 +34,147 @@ #include namespace CGAL { - + +// Class Compact_mesh_cell_base_3_base +// Base for Compact_mesh_cell_base_3, with specializations +// for different values of Concurrency_tag +// Sequential +template +class Compact_mesh_cell_base_3_base +{ +protected: + Compact_mesh_cell_base_3_base() + : bits_(0) {} + +public: +#if defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) \ + || defined(CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE) + + // Erase counter (cf. Compact_container) + unsigned int erase_counter() const + { + return this->m_erase_counter; + } + void set_erase_counter(unsigned int c) + { + this->m_erase_counter = c; + } + void increment_erase_counter() + { + ++this->m_erase_counter; + } +#endif + + /// Marks \c facet as visited + void set_facet_visited (const int facet) + { + CGAL_precondition(facet>=0 && facet <4); + bits_ |= (1 << facet); + } + + /// Marks \c facet as not visited + void reset_visited (const int facet) + { + CGAL_precondition(facet>=0 && facet<4); + bits_ &= (15 & ~(1 << facet)); + } + + /// Returns \c true if \c facet is marked as visited + bool is_facet_visited (const int facet) const + { + CGAL_precondition(facet>=0 && facet<4); + return ( (bits_ & (1 << facet)) != 0 ); + } + +private: + char bits_; + +#if defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) \ + || defined(CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE) + + typedef unsigned int Erase_counter_type; + Erase_counter_type m_erase_counter; +#endif +}; + + +#ifdef CGAL_LINKED_WITH_TBB +// Class Compact_mesh_cell_base_3_base +// Specialization for parallel +template <> +class Compact_mesh_cell_base_3_base +{ +protected: + Compact_mesh_cell_base_3_base() + { + bits_ = 0; + } + +public: + // Erase counter (cf. Compact_container) + unsigned int erase_counter() const + { + return this->m_erase_counter; + } + void set_erase_counter(unsigned int c) + { + this->m_erase_counter = c; + } + void increment_erase_counter() + { + ++this->m_erase_counter; + } + + /// Marks \c facet as visited + void set_facet_visited (const int facet) + { + CGAL_precondition(facet>=0 && facet<4); + char current_bits = bits_; + while (bits_.compare_and_swap(current_bits | (1 << facet), current_bits) != current_bits) + { + current_bits = bits_; + } + } + + /// Marks \c facet as not visited + void reset_visited (const int facet) + { + CGAL_precondition(facet>=0 && facet<4); + char current_bits = bits_; + while (bits_.compare_and_swap(current_bits & (15 & ~(1 << facet)), current_bits) != current_bits) + { + current_bits = bits_; + } + } + + /// Returns \c true if \c facet is marked as visited + bool is_facet_visited (const int facet) const + { + CGAL_precondition(facet>=0 && facet<4); + return ( (bits_ & (1 << facet)) != 0 ); + } + +private: + typedef tbb::atomic Erase_counter_type; + Erase_counter_type m_erase_counter; + /// Stores visited facets (4 first bits) + tbb::atomic bits_; +}; + +#endif // CGAL_LINKED_WITH_TBB + + // Class Compact_mesh_cell_base_3 // Cell base class used in 3D meshing process. // Adds information to Cb about the cell of the input complex containing it template< class GT, class MD, - class TDS = void > + class TDS = void > class Compact_mesh_cell_base_3 + : public Compact_mesh_cell_base_3_base { typedef typename GT::FT FT; - + public: typedef TDS Triangulation_data_structure; typedef typename TDS::Vertex_handle Vertex_handle; @@ -63,10 +194,10 @@ public: typedef typename MD::Subdomain_index Subdomain_index; typedef typename MD::Surface_patch_index Surface_patch_index; typedef typename MD::Index Index; - + typedef GT Geom_traits; typedef typename GT::Point_3 Point; - + typedef Point* Point_container; typedef Point* Point_iterator; typedef const Point* Point_const_iterator; @@ -92,21 +223,21 @@ public: , surface_center_index_table_() , sliver_value_(FT(0.)) , subdomain_index_() - , bits_(0) , sliver_cache_validity_(false) { } - Compact_mesh_cell_base_3(const Compact_mesh_cell_base_3& rhs) + Compact_mesh_cell_base_3(const Compact_mesh_cell_base_3& rhs) : circumcenter_(NULL) + , sliver_value_(rhs.sliver_value_) + , subdomain_index_(rhs.subdomain_index_) + , sliver_cache_validity_(false) #ifdef CGAL_INTRUSIVE_LIST , next_intrusive_(rhs.next_intrusive_) , previous_intrusive_(rhs.previous_intrusive_) #endif - , sliver_value_(rhs.sliver_value_) - , subdomain_index_(rhs.subdomain_index_) - , bits_(0) - , sliver_cache_validity_(false) + , V(rhs.V) + , N(rhs.N) { for(int i=0; i <4; i++){ surface_index_table_[i] = rhs.surface_index_table_[i]; @@ -114,7 +245,7 @@ public: surface_center_index_table_[i] = rhs.surface_center_index_table_[i]; } } - + Compact_mesh_cell_base_3 (Vertex_handle v0, Vertex_handle v1, Vertex_handle v2, @@ -128,11 +259,10 @@ public: #endif , surface_center_index_table_() , sliver_value_(FT(0.)) - , subdomain_index_() - , bits_(0) + , subdomain_index_() , sliver_cache_validity_(false) + , V(CGAL::make_array(v0, v1, v2, v3)) { - set_vertices(v0, v1, v2, v3); } @@ -154,11 +284,10 @@ public: , surface_center_index_table_() , sliver_value_(FT(0.)) , subdomain_index_() - , bits_(0) , sliver_cache_validity_(false) + , V(CGAL::make_array(v0, v1, v2, v3)) + , N(CGAL::make_array(n0, n1, n2, n3)) { - set_neighbors(n0, n1, n2, n3); - set_vertices(v0, v1, v2, v3); } ~Compact_mesh_cell_base_3() @@ -327,11 +456,11 @@ public: // Returns the index of the cell of the input complex that contains the cell Subdomain_index subdomain_index() const { return subdomain_index_; } - + // Sets the index of the cell of the input complex that contains the cell void set_subdomain_index(const Subdomain_index& index) - { subdomain_index_ = index; } - + { subdomain_index_ = index; } + void set_sliver_value(const FT& value) { sliver_cache_validity_ = true; @@ -361,27 +490,6 @@ public: return surface_index_table_[facet]; } - /// Marks \c facet as visited - void set_facet_visited (const int facet) - { - CGAL_precondition(facet>=0 && facet <4); - bits_ |= (1 << facet); - } - - /// Marks \c facet as not visited - void reset_visited (const int facet) - { - CGAL_precondition(facet>=0 && facet<4); - bits_ &= (15 & ~(1 << facet)); - } - - /// Returns \c true if \c facet is marked as visited - bool is_facet_visited (const int facet) const - { - CGAL_precondition(facet>=0 && facet<4); - return ( (bits_ & (1 << facet)) != 0 ); - } - /// Sets surface center of \c facet to \c point void set_facet_surface_center(const int facet, const Point& point) { @@ -416,16 +524,16 @@ public: CGAL_precondition(facet>=0 && facet<4); return ( Surface_patch_index() != surface_index_table_[facet]); } - + // ----------------------------------- // Backward Compatibility // ----------------------------------- #ifndef CGAL_MESH_3_NO_DEPRECATED_SURFACE_INDEX typedef Surface_patch_index Surface_index; - + void set_surface_index(const int facet, const Surface_index& index) { set_surface_patch_index(facet,index); } - + /// Returns surface index of facet \c facet Surface_index surface_index(const int facet) const { return surface_patch_index(facet); } @@ -437,7 +545,7 @@ public: static std::string io_signature() { - return + return Get_io_signature()() + "+" + Get_io_signature >()() + "+(" + Get_io_signature()() + ")[4]"; @@ -450,7 +558,7 @@ public: { next_intrusive_ = c; } - + Cell_handle previous_intrusive() const { return previous_intrusive_; } void set_previous_intrusive(Cell_handle c) { @@ -488,7 +596,6 @@ private: Subdomain_index subdomain_index_; TDS_data _tds_data; - char bits_; mutable bool sliver_cache_validity_; diff --git a/Mesh_3/include/CGAL/IO/File_maya.h b/Mesh_3/include/CGAL/IO/File_maya.h new file mode 100644 index 00000000000..d30e2f16d1a --- /dev/null +++ b/Mesh_3/include/CGAL/IO/File_maya.h @@ -0,0 +1,323 @@ +// Copyright (c) 2012 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: $ +// $Id: $ +// +// +// Author(s) : Clement Jamin + +#ifndef CGAL_IO_FILE_MAYA_H +#define CGAL_IO_FILE_MAYA_H + +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { + +//------------------------------------------------------- +// IO functions +//------------------------------------------------------- + +template +void +output_to_maya(std::ostream& os, + const C3T3& c3t3, + bool surfaceOnly = true) +{ + typedef typename C3T3::Triangulation Tr; + typedef typename C3T3::Facets_in_complex_iterator Facet_iterator; + typedef typename C3T3::Cells_in_complex_iterator Cell_iterator; + + typedef typename Tr::Finite_vertices_iterator Finite_vertices_iterator; + typedef typename Tr::Vertex_handle Vertex_handle; + typedef typename Tr::Point Point_3; + +#ifdef CGAL_MESH_3_IO_VERBOSE + std::cerr << "Output to maya:\n"; +#endif + + const Tr& tr = c3t3.triangulation(); + + //------------------------------------------------------- + // File output + //------------------------------------------------------- + + //------------------------------------------------------- + // Header + //------------------------------------------------------- + os << std::setprecision(20); + + os << "//Maya ASCII 2011 scene" << std::endl; + os << "//Name: testMaya3.ma" << std::endl; + os << "//Last modified: Wed, Jan 25, 2012 05:54:26 PM" << std::endl; + os << "//Codeset: 1252" << std::endl; + os << "requires maya \"2011\";" << std::endl; + os << "currentUnit -l centimeter -a degree -t film;" << std::endl; + os << "fileInfo \"application\" \"maya\";" << std::endl; + os << "fileInfo \"product\" \"Maya 2011\";" << std::endl; + os << "fileInfo \"version\" \"2011\";" << std::endl; + os << "fileInfo \"cutIdentifier\" \"201003190014-771504\";" << std::endl; + os << "fileInfo \"license\" \"education\";" << std::endl; + + std::string name = "Mesh_3"; + os << "createNode mesh -n \"" << name << "Shape\" -p \"" << name << "\";" << std::endl; + os << " setAttr -k off \".v\";" << std::endl; + os << " setAttr \".uvst[0].uvsn\" -type \"string\" \"map1\";" << std::endl; + os << " setAttr \".cuvs\" -type \"string\" \"map1\";" << std::endl; + os << " setAttr \".dcol\" yes;" << std::endl; + os << " setAttr \".dcc\" -type \"string\" \"Ambient+Diffuse\";" << std::endl; + + os << " connectAttr \"" << name << "Shape.iog\" \":initialShadingGroup.dsm\" -na;\n\n"; + + //------------------------------------------------------- + // Colors + //------------------------------------------------------ + + /*os << " setAttr \".ccls\" -type \"string\" \"colorSet\";\n"; + os << " setAttr \".clst[0].clsn\" -type \"string\" \"colorSet\";\n"; + os << " setAttr \".clst[0].rprt\" 3;\n"; + os << " setAttr -s " << 3 << " \".clst[0].clsp[0:" << 3-1 << "]\"" << std::endl; + os << " 10 50 250" << std::endl; + os << " 100 250 50" << std::endl; + os << " 0 200 200" << std::endl; + os << " ;\n";*/ + + //------------------------------------------------------- + // Vertices + //------------------------------------------------------ + + std::map V; + std::stringstream vertices_sstr; + int num_vertices = 0; + for( Finite_vertices_iterator vit = tr.finite_vertices_begin(); + vit != tr.finite_vertices_end(); + ++vit) + { + if ( (surfaceOnly && c3t3.in_dimension(vit) <= 2) + || !surfaceOnly) + { + V[vit] = num_vertices++; + Point_3 p = vit->point(); + vertices_sstr << " " << CGAL::to_double(p.x()) << " " << CGAL::to_double(p.y()) << " " << CGAL::to_double(p.z()) << std::endl; + } + } + + os << " setAttr -s " << num_vertices << " \".vt[0:" << num_vertices-1 << "]\"" << std::endl; + os << vertices_sstr.str(); + os << ";\n"; + + /* + // Triangles + os << "setAttr -s " << QString().setNum(number_of_triangles) << " \".fc[0:" << QString().setNum(number_of_triangles-1) << "]\" -type \"polyFaces\" \n"; + for (int i=0;i > EdgeList; + EdgeList edges; + + // Surface only + if (surfaceOnly) + { + facets_sstr << " setAttr -s " << number_of_triangles + << " \".fc[0:" << number_of_triangles-1 << "]\" -type \"polyFaces\" \n"; + int c = 0; + for( Facet_iterator fit = c3t3.facets_in_complex_begin(); + fit != c3t3.facets_in_complex_end(); + ++fit, ++c) + { + int indices[3]; + //Point_3 points[3]; + facets_sstr << " f 3 "; + for (int j = 0, i = (fit->second + 1) % 4 ; j < 3 ; i = (i+1)%4, ++j) + { + const Vertex_handle& vh = fit->first->vertex(i); + indices[j] = V[vh]; + //points[j] = vh->point(); + } + + // Reverse triangle orientation? + bool reverse_triangle = + (fit->second % 2 == 0 && !c3t3.is_in_complex(fit->first)) + || (fit->second % 2 != 0 && c3t3.is_in_complex(fit->first)); + if (reverse_triangle) + { + std::swap(indices[1], indices[2]); + //std::swap(points[1], points[2]); + } + //Kernel::Vector_3 n = cross_product(points[1] - points[0], points[2] - points[0]); + //n = n / CGAL::sqrt(n*n); + // Add the normal 3 times + //normals_sstr << " " << n.x() << " " << n.y() << " " << n.z() << std::endl; + //normals_sstr << " " << n.x() << " " << n.y() << " " << n.z() << std::endl; + //normals_sstr << " " << n.x() << " " << n.y() << " " << n.z() << std::endl; + + // 3 edges + for (int i = 0 ; i < 3 ; ++i) + { + std::pair edge = std::make_pair( + (std::min)(indices[i], indices[(i+1)%3]), + (std::max)(indices[i], indices[(i+1)%3])); + size_t pos = std::find(edges.begin(), edges.end(), edge) - edges.begin(); + if (pos == edges.size()) // Not found? + { + edges.push_back(edge); + } + // ith edge of triangle + facets_sstr << pos << " "; + } + + // 1 triangles + facets_sstr << std::endl; + // Colors + //facets_sstr << " mc 0 3 " << rand()%3 << " " << rand()%3 << " " << rand()%3 << std::endl; + } + } + // Tetrahedra = 4 facets for each + else + { + facets_sstr << " setAttr -s " << 4*c3t3.number_of_cells_in_complex() + << " \".fc[0:" << 4*c3t3.number_of_cells_in_complex()-1 << "]\" -type \"polyFaces\" \n"; + int c = 0; + for( Cell_iterator cit = c3t3.cells_in_complex_begin(); + cit != c3t3.cells_in_complex_end(); + ++cit, ++c) + { + for (int facet_i = 0 ; facet_i < 4 ; ++facet_i) + { + int indices[3]; + //Point_3 points[3]; + facets_sstr << " f 3 "; + for (int j = 0, i = (facet_i + 1) % 4 ; j < 3 ; i = (i+1)%4, ++j) + { + const Vertex_handle& vh = cit->vertex(i); + indices[j] = V[vh]; + //points[j] = vh->point(); + } + + // Reverse triangle orientation? + bool reverse_triangle = (facet_i % 2 != 0 && c3t3.is_in_complex(cit, facet_i)); + if (reverse_triangle) + { + std::swap(indices[1], indices[2]); + //std::swap(points[1], points[2]); + } + //Kernel::Vector_3 n = cross_product(points[1] - points[0], points[2] - points[0]); + //n = n / CGAL::sqrt(n*n); + // Add the normal 3 times + //normals_sstr << " " << n.x() << " " << n.y() << " " << n.z() << std::endl; + //normals_sstr << " " << n.x() << " " << n.y() << " " << n.z() << std::endl; + //normals_sstr << " " << n.x() << " " << n.y() << " " << n.z() << std::endl; + + // 3 edges + for (int i = 0 ; i < 3 ; ++i) + { + std::pair edge = std::make_pair( + (std::min)(indices[i], indices[(i+1)%3]), + (std::max)(indices[i], indices[(i+1)%3])); + size_t pos = std::find(edges.begin(), edges.end(), edge) - edges.begin(); + if (pos == edges.size()) // Not found? + { + edges.push_back(edge); + } + // ith edge of triangle + facets_sstr << pos << " "; + } + + // 1 triangles + facets_sstr << std::endl; + // Colors + //facets_sstr << " mc 0 3 " << rand()%3 << " " << rand()%3 << " " << rand()%3 << std::endl; + } + } + } + facets_sstr << ";\n\n"; + //normals_sstr << ";\n\n"; + + //------------------------------------------------------- + // Edges + //------------------------------------------------------- + os << " setAttr -s " << edges.size() << " \".ed[0:" + << edges.size() - 1 << "]\"" << std::endl; + + for (EdgeList::const_iterator it = edges.begin(), it_end = edges.end() ; it != it_end ; ++it) + os << " " << it->first << " " << it->second << " " << 0 << std::endl; + + os << ";\n"; + + //------------------------------------------------------- + // Normals + //------------------------------------------------------- + + //os << normals_sstr.str(); + + //------------------------------------------------------- + // Facets + //------------------------------------------------------- + + os << facets_sstr.str(); + + //------------------------------------------------------- + // Tetrahedra + //------------------------------------------------------- + /*os << "Tetrahedra" << std::endl + << c3t3.number_of_cells_in_complex() << std::endl; + + for( Cell_iterator cit = c3t3.cells_in_complex_begin() ; + cit != c3t3.cells_in_complex_end() ; + ++cit ) + { + for (int i=0; i<4; i++) + os << V[cit->vertex(i)] << " "; + + os << get(cell_pmap, cit) << std::endl; + }*/ + + //------------------------------------------------------- + // End + //------------------------------------------------------- + +#ifdef CGAL_MESH_3_IO_VERBOSE + std::cerr << "done.\n"; +#endif +} // end output_to_maya(...) + +} // end namespace CGAL + +#endif // CGAL_IO_FILE_MAYA_H diff --git a/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h b/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h index 475ba87ed7d..e27bc1b4c55 100644 --- a/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h +++ b/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h @@ -33,6 +33,11 @@ #include #include #include +#include + +#ifdef CGAL_MESH_3_PROFILING + #include +#endif #include #include @@ -42,6 +47,12 @@ #include #include #include +#include +#include + +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif #include #include @@ -50,12 +61,11 @@ namespace CGAL { namespace Mesh_3 { - #ifdef CGAL_INTRUSIVE_LIST template class Intrusive_list { public: - + typedef Type Type_handle; typedef Type_handle& reference; typedef const Type_handle& const_reference; @@ -79,17 +89,17 @@ public: #ifdef CGAL_CONSTRUCT_INTRUSIVE_LIST_RANGE_CONSTRUCTOR template Intrusive_list(IT first, IT last) - : f(), b(), n(0) + : f(), b(), n(0) { if(first == last){ return; } - + f = *first; Type_handle ch = f; ++n; ++first; - while(first != last){ + while(first != last){ if((ch != Type(*first)) && ((*first)->next_intrusive()==Type_handle())){ // not yet inserted ch->set_next_intrusive(*first); @@ -98,7 +108,7 @@ public: ++n; } ++first; - } + } b = ch; b->set_next_intrusive(f); f->set_previous_intrusive(b); @@ -148,8 +158,8 @@ public: return true; } - - void clear() + + void clear() { if(!empty()){ while( f!= b ){ @@ -194,9 +204,9 @@ public: if(pos != Type_handle()){ if(pos == b){ pos = Type_handle(); // past the end - }else { + }else { pos = pos->next_intrusive(); - } + } } return *this; } @@ -209,10 +219,10 @@ public: } bool operator==(const iterator& i) const - { + { return pos == i.pos; } - + bool operator!=(const iterator& i) const { return !(*this == i); @@ -265,10 +275,10 @@ public: iterator insert(iterator /* position */, const Type_handle& ch) { - CGAL_assertion( (ch->next_intrusive() == Type_handle() && ch->previous_intrusive() == Type_handle()) || + CGAL_assertion( (ch->next_intrusive() == Type_handle() && ch->previous_intrusive() == Type_handle()) || (ch->next_intrusive() != Type_handle() && ch->previous_intrusive() != Type_handle()) ); CGAL_expensive_assertion(is_valid()); - + if(ch->next_intrusive() != Type_handle()){ return iterator(ch->next_intrusive()/*first*/, ch/*last*/); } @@ -280,10 +290,10 @@ public: void insert(Type_handle ch) { - CGAL_assertion( (ch->next_intrusive() == Type_handle() && ch->previous_intrusive() == Type_handle()) || + CGAL_assertion( (ch->next_intrusive() == Type_handle() && ch->previous_intrusive() == Type_handle()) || (ch->next_intrusive() != Type_handle() && ch->previous_intrusive() != Type_handle()) ); CGAL_expensive_assertion(is_valid()); - + if(ch->next_intrusive() != Type_handle()){ return; } @@ -303,7 +313,7 @@ public: void erase(Type_handle ch) { - CGAL_assertion( (ch->next_intrusive() == Type_handle() && ch->previous_intrusive() == Type_handle()) || + CGAL_assertion( (ch->next_intrusive() == Type_handle() && ch->previous_intrusive() == Type_handle()) || (ch->next_intrusive() != Type_handle() && ch->previous_intrusive() != Type_handle()) ); CGAL_expensive_assertion(is_valid()); if(ch->next_intrusive() == Type_handle()){ @@ -312,7 +322,7 @@ public: if(f == b){ // only 1 element in the list CGAL_assertion(f == ch); CGAL_assertion(n == 1); - + f = b = Type_handle(); } else { if(f == ch){ @@ -350,46 +360,293 @@ public: } else return false; } - + void push_back(Type_handle ch) { insert(ch); } private: - Type_handle f,b; + Type_handle f,b; std::size_t n; }; #endif // #ifdef CGAL_INTRUSIVE_LIST -template + +/************************************************ +// Class C3T3_helpers_base +// Two versions: sequential / parallel +************************************************/ + +// Sequential +template +class C3T3_helpers_base +{ +protected: + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::Point_3 Point_3; + typedef typename Tr::Vertex_handle Vertex_handle; + typedef typename Tr::Cell_handle Cell_handle; + typedef typename Tr::Facet Facet; + typedef typename Tr::Lock_data_structure Lock_data_structure; + + C3T3_helpers_base(Lock_data_structure *) {} + + Lock_data_structure *get_lock_data_structure() const + { + return 0; + } + +public: + // Dummy locks/unlocks + bool try_lock_point(const Point_3 &p, int lock_radius = 0) const + { + return true; + } + + bool try_lock_vertex(Vertex_handle vh, int lock_radius = 0) const + { + return true; + } + + bool try_lock_point_no_spin(const Point_3 &p, int lock_radius = 0) const + { + return true; + } + + bool try_lock_vertex_no_spin(Vertex_handle vh, int lock_radius = 0) const + { + return true; + } + + bool try_lock_element(Cell_handle cell_handle, int lock_radius = 0) const + { + return true; + } + + bool try_lock_element(const Facet &facet, int lock_radius = 0) const + { + return true; + } + + + bool is_point_locked_by_this_thread(const Point_3 &p) const + { return false; } + + bool is_cell_locked_by_this_thread(const Cell_handle &cell_handle) const + { return false; } + + void unlock_all_elements() const {} + + // Dummy locks/unlocks + void lock_outdated_cells() const {} + void unlock_outdated_cells() const {} + void lock_moving_vertices() const {} + void unlock_moving_vertices() const {} + void lock_vertex_to_proj() const {} + void unlock_vertex_to_proj() const {} +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template +class C3T3_helpers_base +{ +protected: + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::Point_3 Point_3; + typedef typename Tr::Vertex_handle Vertex_handle; + typedef typename Tr::Cell_handle Cell_handle; + typedef typename Tr::Facet Facet; + typedef typename Tr::Lock_data_structure Lock_data_structure; + + C3T3_helpers_base(Lock_data_structure *lock_ds) + : m_lock_ds(lock_ds) {} + + +public: + // LOCKS (CONCURRENCY) + + /*Lock_data_structure *get_lock_data_structure() const + { + return m_lock_ds; + }*/ + + bool try_lock_point(const Point_3 &p, int lock_radius = 0) const + { + if (m_lock_ds) + { + return m_lock_ds->try_lock(p, lock_radius); + } + return true; + } + + bool try_lock_vertex(Vertex_handle vh, int lock_radius = 0) const + { + if (m_lock_ds) + { + return m_lock_ds->try_lock(vh->point(), lock_radius); + } + return true; + } + + bool try_lock_point_no_spin(const Point_3 &p, int lock_radius = 0) const + { + if (m_lock_ds) + { + return m_lock_ds->template try_lock(p, lock_radius); + } + return true; + } + + bool try_lock_vertex_no_spin(Vertex_handle vh, int lock_radius = 0) const + { + return try_lock_point_no_spin(vh->point(), lock_radius); + } + + bool try_lock_element(Cell_handle cell_handle, int lock_radius = 0) const + { + bool success = true; + + // Lock the element area on the grid + for (int iVertex = 0 ; success && iVertex < 4 ; ++iVertex) + { + Vertex_handle vh = cell_handle->vertex(iVertex); + success = try_lock_vertex(vh, lock_radius); + } + + return success; + } + + bool try_lock_element(const Facet &facet, int lock_radius = 0) const + { + bool success = true; + + // Lock the element area on the grid + Cell_handle cell = facet.first; + for (int iVertex = (facet.second+1)&3 ; + success && iVertex != facet.second ; iVertex = (iVertex+1)&3) + { + Vertex_handle vh = cell->vertex(iVertex); + success = try_lock_vertex(vh, lock_radius); + } + + return success; + } + + bool is_point_locked_by_this_thread(const Point_3 &p) const + { + bool locked = true; + if (m_lock_ds) + { + locked = m_lock_ds->is_locked_by_this_thread(p); + } + return locked; + } + + bool is_cell_locked_by_this_thread(const Cell_handle &cell_handle) const + { + bool locked = true; + if (m_lock_ds) + { + for (int iVertex = 0 ; locked && iVertex < 4 ; ++iVertex) + { + locked = m_lock_ds->is_locked_by_this_thread( + cell_handle->vertex(iVertex)->point()); + } + } + return locked; + } + + void unlock_all_elements() const + { + if (m_lock_ds) + { + m_lock_ds->unlock_all_points_locked_by_this_thread(); + } + } + + void lock_outdated_cells() const + { + m_mut_outdated_cells.lock(); + } + void unlock_outdated_cells() const + { + m_mut_outdated_cells.unlock(); + } + + void lock_moving_vertices() const + { + m_mut_moving_vertices.lock(); + } + void unlock_moving_vertices() const + { + m_mut_moving_vertices.unlock(); + } + + void lock_vertex_to_proj() const + { + m_mut_vertex_to_proj.lock(); + } + void unlock_vertex_to_proj() const + { + m_mut_vertex_to_proj.unlock(); + } + +protected: + Lock_data_structure *m_lock_ds; + + typedef tbb::mutex Mutex_type; + mutable Mutex_type m_mut_outdated_cells; + mutable Mutex_type m_mut_moving_vertices; + mutable Mutex_type m_mut_vertex_to_proj; +}; +#endif // CGAL_LINKED_WITH_TBB + + +/************************************************ + * + * C3T3_helpers class + * + ************************************************/ + +template class C3T3_helpers +: public C3T3_helpers_base { // ----------------------------------- // Private types // ----------------------------------- - typedef typename C3T3::Triangulation Tr; - typedef Tr Triangulation; - typedef typename Tr::Geom_traits Gt; - + typedef C3T3_helpers Self; + typedef C3T3_helpers_base Base; + typedef typename C3T3::Concurrency_tag Concurrency_tag; + + typedef typename Base::Lock_data_structure Lock_data_structure; + typedef typename C3T3::Triangulation Tr; + typedef Tr Triangulation; + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::Vector_3 Vector_3; typedef typename Gt::Point_3 Point_3; typedef typename Gt::Plane_3 Plane_3; typedef typename Gt::FT FT; typedef typename Gt::Tetrahedron_3 Tetrahedron; - + typedef typename Tr::Vertex_handle Vertex_handle; typedef typename Tr::Cell_handle Cell_handle; typedef typename Tr::Cell Cell; typedef typename Tr::Facet Facet; - + typedef typename C3T3::Surface_patch_index Surface_patch_index; typedef typename C3T3::Subdomain_index Subdomain_index; typedef typename C3T3::Index Index; typedef boost::optional Surface_patch; typedef boost::optional Subdomain; - + typedef std::vector Cell_vector; typedef std::set Cell_set; typedef std::vector Tet_vector; @@ -397,10 +654,10 @@ class C3T3_helpers typedef std::vector Facet_vector; typedef std::vector Vertex_vector; typedef std::set Vertex_set; - + #ifdef CGAL_INTRUSIVE_LIST typedef Intrusive_list Outdated_cell_set; -#else +#else typedef Cell_set Outdated_cell_set; #endif //CGAL_INTRUSIVE_LIST @@ -410,7 +667,6 @@ class C3T3_helpers typedef Vertex_set Moving_vertices_set; #endif //CGAL_INTRUSIVE_LIST - private: // Facet_boundary stores the edges, of the boundary of surface facets, // with meta-data. @@ -420,30 +676,47 @@ private: // facet. typedef std::pair Facet_topology_description; typedef std::map Facet_boundary; - + typedef Triangulation_helpers Th; - + public: // ----------------------------------- // Public interface // ----------------------------------- typedef boost::optional Update_mesh; - + + using Base::try_lock_point; + using Base::try_lock_vertex; + using Base::try_lock_point_no_spin; + using Base::try_lock_vertex_no_spin; + using Base::try_lock_element; + using Base::is_point_locked_by_this_thread; + using Base::is_cell_locked_by_this_thread; + using Base::unlock_all_elements; + using Base::lock_outdated_cells; + using Base::unlock_outdated_cells; + using Base::lock_moving_vertices; + using Base::unlock_moving_vertices; + using Base::lock_vertex_to_proj; + using Base::unlock_vertex_to_proj; + /** * Constructor */ - C3T3_helpers(C3T3& c3t3, const MeshDomain& domain) - : c3t3_(c3t3) + C3T3_helpers(C3T3& c3t3, const MeshDomain& domain, + Lock_data_structure *lock_ds = NULL) + : Base(lock_ds) + , c3t3_(c3t3) , tr_(c3t3.triangulation()) , domain_(domain) { } - + /** * @brief tries to move \c old_vertex to \c new_position in the mesh * @param new_position the new position of \c old_vertex * @param old_vertex the old vertex - * @param criterion the criterion which will be used to verify the new + * @param criterion the criterion which will be used to verify the new * position is ok. c3t3 minimal value of new criterion shall not decrease. - * @param modified_vertices contains the vertices incident to cells which + * @param modified_vertices contains the vertices incident to cells which * may have been impacted by relocation * @return a pair which contains: * - a bool which is \c true if the move has been done. @@ -456,21 +729,23 @@ public: update_mesh(const Point_3& new_position, const Vertex_handle& old_vertex, const SliverCriterion& criterion, - OutputIterator modified_vertices); + OutputIterator modified_vertices, + bool *could_lock_zone = NULL); /** @brief tries to move \c old_vertex to \c new_position in the mesh * - * Same as update_mesh, but with the precondition that + * Same as update_mesh, but with the precondition that * Th().no_topological_change(tr_, old_vertex, new_position, - * incident_cells) return false. + * incident_cells_) return false. */ template std::pair update_mesh_topo_change(const Point_3& new_position, const Vertex_handle& old_vertex, const SliverCriterion& criterion, - OutputIterator modified_vertices); - + OutputIterator modified_vertices, + bool *could_lock_zone = NULL); + /** * Updates mesh moving vertex \c old_vertex to \c new_position. Returns the * new vertex of the triangulation. @@ -482,7 +757,7 @@ public: const Vertex_handle& old_vertex, OutputIterator modified_vertices, bool fill_modified_vertices = true); - + /** * Updates mesh moving vertex \c old_vertex to \c new_position. Returns the * new vertex of the triangulation. @@ -492,7 +767,7 @@ public: { return update_mesh(new_position, old_vertex, Emptyset_iterator(), false); } - + /** * Rebuilds restricted Delaunay */ @@ -500,7 +775,7 @@ public: void rebuild_restricted_delaunay(ForwardIterator first_cell, ForwardIterator last_cell, Moving_vertices_set& moving_vertices); - + #ifdef CGAL_INTRUSIVE_LIST template void rebuild_restricted_delaunay(OutdatedCells& outdated_cells, @@ -520,25 +795,74 @@ public: * the fitting plane. */ Point_3 - project_on_surface(const Point_3& p, const Vertex_handle& v, + project_on_surface(const Point_3& p, const Vertex_handle& v, Surface_patch_index index = Surface_patch_index()) const; /** - * Returns the minimum value for criterion for incident cells of \c vh + * Returns the minimum value for criterion for incident cells of \c vh */ - template + template FT min_incident_value(const Vertex_handle& vh, const SliverCriterion& criterion) const; - + /** * Moves \c old_vertex to \c new_position * Stores the cells which have to be updated in \c outdated_cells * Updates the Vertex_handle old_vertex to its new value in \c moving_vertices + * The second one (with the could_lock_zone param) is for the parallel version */ Vertex_handle move_point(const Vertex_handle& old_vertex, const Point_3& new_position, Outdated_cell_set& outdated_cells_set, - Moving_vertices_set& moving_vertices); + Moving_vertices_set& moving_vertices) const; + Vertex_handle move_point(const Vertex_handle& old_vertex, + const Point_3& new_position, + Outdated_cell_set& outdated_cells_set, + Moving_vertices_set& moving_vertices, + bool *could_lock_zone) const; + + /** + * Try to lock the incident cells and return them in \c cells + * Return value: + * - false: everything is unlocked and \c cells is empty + * - true: incident cells are locked and \c cells contains all of them + */ + bool + try_lock_and_get_incident_cells(const Vertex_handle& v, + Cell_vector &cells) const; + + /** + * Try to lock ALL the incident cells and return in \c cells the ones + * whose \c filter says "true". + * Return value: + * - false: everything is unlocked and \c cells is empty + * - true: ALL incident cells are locked and \c cells is filled + */ + template + bool + try_lock_and_get_incident_cells(const Vertex_handle& v, + Cell_vector &cells, + const Filter &filter) const; + + /** + * Try to lock ALL the incident cells and return in \c cells the slivers + * Return value: + * - false: everything is unlocked and \c cells is empty + * - true: incident cells are locked and \c cells contains all slivers + */ + template + bool + try_lock_and_get_incident_slivers(const Vertex_handle& v, + const SliverCriterion& criterion, + const FT& sliver_bound, + Cell_vector &cells) const; + + template + void + get_incident_slivers_without_using_tds_data(const Vertex_handle& v, + const SliverCriterion& criterion, + const FT& sliver_bound, + Cell_vector &slivers) const; /** * Outputs to out the sliver (wrt \c criterion and \c sliver_bound) incident @@ -561,8 +885,8 @@ public: /** * Returns the sliver (wrt \c criterion and \c sliver_bound) incident to \c v - */ - template + */ + template Cell_vector incident_slivers(const Vertex_handle& v, const SliverCriterion& criterion, @@ -573,7 +897,7 @@ public: return slivers; } - template + template Cell_vector new_incident_slivers(const Vertex_handle& v, const SliverCriterion& criterion, @@ -588,13 +912,13 @@ public: /** * Returns the number of slivers incident to \c v */ - template + template std::size_t number_of_incident_slivers(const Vertex_handle& v, const SliverCriterion& criterion, const FT& sliver_bound) const; - - template + + template bool is_sliver(const Cell_handle& ch, const SliverCriterion& criterion, @@ -608,8 +932,8 @@ public: template FT min_sliver_value(const Cell_vector& cells, const SliverCriterion& criterion, - const bool use_cache = true) const; - + const bool use_cache = true) const; + /** * Reset cache validity of all cells of c3t3_ */ @@ -619,8 +943,8 @@ public: std::for_each(c3t3_.cells_in_complex_begin(),c3t3_.cells_in_complex_end(), bl::bind(&Cell::reset_cache_validity, bl::_1) ); } - -private: + +private: // ----------------------------------- // Usefull Functors // ----------------------------------- @@ -636,7 +960,7 @@ private: Get_all_facets(const Triangulation& tr, OutputIterator out) : tr_(tr) , out_(out) {} - + void operator()(const Cell_handle& cell) { #ifndef CGAL_MESH_3_NEW_GET_FACETS @@ -650,7 +974,7 @@ private: // This approach makes less tests if vertices are infinite int i=0; for ( ; i<4 ; ++i ){ - if ( tr_.is_infinite(cell->vertex(i)) ){ + if ( tr_.is_infinite(cell->vertex(i)) ){ *out_++ = canonical_facet(cell,i); return; } @@ -660,7 +984,7 @@ private: } #endif } - + private: Facet canonical_facet(const Cell_handle& c, const int i) const { @@ -669,7 +993,7 @@ private: Facet mirror = tr_.mirror_facet(facet); return ( (mirrorneighbor(i); + Cell_handle n = c->neighbor(i); if(c < n){ return Facet(c,i); }else{ @@ -677,13 +1001,13 @@ private: } #endif } - + private: const Triangulation& tr_; OutputIterator out_; }; - - + + /** * @class Is_in_c3t3 * @@ -695,11 +1019,11 @@ private: public: Is_in_c3t3(const C3T3& c3t3) : c3t3_(c3t3) { } bool operator()(const Handle& h) const { return c3t3_.is_in_complex(h); } - + private: const C3T3& c3t3_; }; - + /** * @class Is_sliver @@ -715,13 +1039,13 @@ private: : c3t3_(c3t3) , criterion_(criterion) , bound_(bound) { } - + bool operator()(const Cell_handle& c) const { if ( c3t3_.is_in_complex(c) ) { CGAL_assertion(!c3t3_.triangulation().is_infinite(c)); - + if ( ! c->is_cache_valid() ) { Sliver_criterion_value sc_value(c3t3_.triangulation(), @@ -740,14 +1064,14 @@ private: else return false; } - + private: const C3T3& c3t3_; const SliverCriterion& criterion_; const FT bound_; }; - - + + /** * @class Update_c3t3 * @@ -759,7 +1083,7 @@ private: Update_c3t3(const MeshDomain& domain, C3T3& c3t3) : domain_(domain) , c3t3_(c3t3) {} - + /** * @brief Updates facet \c facet in c3t3 * @param facet the facet to update @@ -790,24 +1114,24 @@ private: typedef typename Gt::Segment_3 Segment_3; typedef typename Gt::Ray_3 Ray_3; typedef typename Gt::Line_3 Line_3; - + // Nothing to do for infinite facets if ( c3t3_.triangulation().is_infinite(facet) ) return Surface_patch(); - + // Functors - typename Gt::Is_degenerate_3 is_degenerate = + typename Gt::Is_degenerate_3 is_degenerate = Gt().is_degenerate_3_object(); - + // Get dual of facet Object dual = c3t3_.triangulation().dual(facet); // The dual is a segment, a ray or a line if ( const Segment_3* p_segment = object_cast(&dual) ) { - if (is_degenerate(*p_segment)) + if (is_degenerate(*p_segment)) return Surface_patch(); - + return dual_intersect(*p_segment,facet, update_c3t3, update_surface_center); @@ -816,7 +1140,7 @@ private: { if (is_degenerate(*p_ray)) return Surface_patch(); - + return dual_intersect(*p_ray,facet,update_c3t3, update_surface_center); } @@ -825,11 +1149,11 @@ private: return dual_intersect(*p_line,facet,update_c3t3, update_surface_center); } - + CGAL_error_msg("This should not happen"); return Surface_patch(); } - + /** * @brief Updates cell \c ch in c3t3 * @param ch the cell to update @@ -840,12 +1164,12 @@ private: { if ( c3t3_.triangulation().is_infinite(ch) ) return false; - + // treat cell const Subdomain subdomain = domain_.is_in_domain_object()(c3t3_.triangulation().dual(ch)); // function dual(cell) updates the circumcenter cache if there is one - + if ( subdomain && update ) { c3t3_.add_to_complex(ch,*subdomain); @@ -857,9 +1181,9 @@ private: return subdomain; } - + private: - + // Returns true if query intersects the surface. template Surface_patch dual_intersect(const Query& dual, @@ -868,12 +1192,12 @@ private: const bool update_surface_center) const { typedef typename MeshDomain::Intersection Intersection; - + typename MeshDomain::Construct_intersection construct_intersection = domain_.construct_intersection_object(); -#ifndef CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 - +#ifndef CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 + typename MeshDomain::Do_intersect_surface do_intersect_surface = domain_.do_intersect_surface_object(); Surface_patch surface = do_intersect_surface(dual); @@ -881,16 +1205,16 @@ private: #else // CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 Intersection intersection = construct_intersection(dual); - Surface_patch surface = - (CGAL::cpp0x::get<2>(intersection) == 0) ? Surface_patch() : + Surface_patch surface = + (CGAL::cpp0x::get<2>(intersection) == 0) ? Surface_patch() : domain_.surface_patch_index(CGAL::cpp0x::get<1>(intersection)); #endif // CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 - + // Update if needed - if(update_c3t3) + if(update_c3t3) { - // Update status in c3t3 + // Update status in c3t3 if(surface) c3t3_.add_to_complex(facet,*surface); else @@ -917,11 +1241,11 @@ private: facet_m.first->set_facet_surface_center(facet_m.second,Point_3()); } } - + return surface; } - - + + private: const MeshDomain& domain_; C3T3& c3t3_; @@ -959,16 +1283,18 @@ private: { const Vertex_handle& v = f.first->vertex((k+i)&3); if ( c3t3_.in_dimension(v) > 2 ) - { + { + //lock_vertex_to_proj(); vertex_to_proj.insert(v); + //unlock_vertex_to_proj(); } } } } }; // end class Facet_updater - - + + /** * @class Sliver_criterion_value * @@ -984,11 +1310,11 @@ private: const SliverCriterion& criterion) : p_tr_(&tr) , criterion_(criterion) {} - + FT operator()(const Cell_handle& ch) const { CGAL_precondition(!p_tr_->is_infinite(ch)); - + if ( ! ch->is_cache_valid() ) { double sliver_value = criterion_(ch); @@ -1000,7 +1326,7 @@ private: } return ch->sliver_value(); } - + private: // '=' is used, so p_tr_ must be a pointer ... const Tr* p_tr_; @@ -1053,7 +1379,7 @@ private: const bool do_backup = true) : cell_ids_(c) { - //backup is not done when constructor is called to + //backup is not done when constructor is called to //convert a newly created cell (has nothing to backup) //to a Cell_data_backup if(do_backup) @@ -1077,7 +1403,7 @@ private: surface_center_index_table_[i] = c->get_facet_surface_center_index(ii); } //note c->next_intrusive() and c->previous_intrusive() - //are lost by 'backup' and 'restore', + //are lost by 'backup' and 'restore', //because all cells are changing during the move //they are not used in update_mesh functions involving a Sliver_criterion } @@ -1089,7 +1415,7 @@ private: } /** - * new_cell has the same vertices as cell_ids_ + * new_cell has the same vertices as cell_ids_ * (checked before function is called) * resets new_cell's meta-data to its back-uped values */ @@ -1099,7 +1425,7 @@ private: CGAL_assertion_code(unsigned int nbv_found = 0); for(int i = 0; i < 4; ++i) { - std::size_t new_vi_index = + std::size_t new_vi_index = static_cast(new_cell->vertex(i)->meshing_info()); for(std::size_t j = 0; j < 4; ++j) { @@ -1118,7 +1444,7 @@ private: private: typedef CGAL::cpp11::array IndexMap; - + void restore(Cell_handle c, const IndexMap& index_map,//new_to_old_indices C3T3& c3t3) @@ -1143,7 +1469,7 @@ private: { std::size_t old_i = index_map.at(static_cast(i)); Surface_patch_index index = surface_index_table_[old_i]; - //add_to_complex sets the index, and updates the facet counter + //add_to_complex sets the index, and updates the facet counter if(Surface_patch_index() != index) c3t3.add_to_complex(Facet(c, i), index); else @@ -1151,7 +1477,7 @@ private: c->set_facet_surface_center(i, facet_surface_center_[old_i]); c->set_facet_surface_center_index(i, surface_center_index_table_[old_i]); - //here we don't need to update mirror_facet because it's been either + //here we don't need to update mirror_facet because it's been either //backuped, or unchanged } } @@ -1165,7 +1491,7 @@ private: FT sliver_value_; Subdomain_index subdomain_index_; CGAL::cpp11::array surface_index_table_; - CGAL::cpp11::array facet_surface_center_; + CGAL::cpp11::array facet_surface_center_; CGAL::cpp11::array surface_center_index_table_; }; @@ -1185,7 +1511,7 @@ private: Cell_vector c3t3_cells_ = c3t3_cells(cells); return min_sliver_value(c3t3_cells_, criterion, use_cache); } - + Cell_vector c3t3_cells(const Cell_vector& cells) const { Cell_vector c3t3_cells; @@ -1200,24 +1526,24 @@ private: * Removes objects of [begin,end[ range from \c c3t3_ */ template - void remove_from_c3t3(ForwardIterator begin, ForwardIterator end) + void remove_from_c3t3(ForwardIterator begin, ForwardIterator end) const { while ( begin != end ) c3t3_.remove_from_complex(*begin++); } - + /** * Remove cells and facets of \c cells from c3t3 */ template < typename ForwardIterator > void remove_cells_and_facets_from_c3t3(ForwardIterator cells_begin, - ForwardIterator cells_end) + ForwardIterator cells_end) const { Facet_vector facets = get_facets_not_inplace(cells_begin,cells_end); remove_from_c3t3(facets.begin(), facets.end()); - remove_from_c3t3(cells_begin, cells_end); + remove_from_c3t3(cells_begin, cells_end); } - + /** * Insert into \c out the vertices of range [cells_begin,cells_end[ */ @@ -1231,14 +1557,14 @@ private: * Backup cells meta-data to a vector of Cell_data_backup */ template - void fill_cells_backup(const CellsVector& cells, + void fill_cells_backup(const CellsVector& cells, CellDataSet& cells_backup) const; template void restore_from_cells_backup(const CellsVector& cells, CellDataSet& cells_backup) const; - - + + /** * Update mesh iff sliver criterion value does not decrease. */ @@ -1249,7 +1575,7 @@ private: const SliverCriterion& criterion, OutputIterator modified_vertices, const Cell_vector& conflict_cells); - + /** * Move point and returns the set of cells that are not valid anymore, and * the set of cells which have been deleted by the move process. @@ -1259,12 +1585,13 @@ private: Vertex_handle move_point(const Vertex_handle& old_vertex, const Point_3& new_position, OutdatedCellsOutputIterator outdated_cells, - DeletedCellsOutputIterator deleted_cells); + DeletedCellsOutputIterator deleted_cells) const; - Vertex_handle + Vertex_handle move_point_topo_change(const Vertex_handle& old_vertex, const Point_3& new_position, - Outdated_cell_set& outdated_cells_set); + Outdated_cell_set& outdated_cells_set, + bool *could_lock_zone = NULL) const; template < typename OutdatedCellsOutputIterator, typename DeletedCellsOutputIterator > @@ -1272,37 +1599,37 @@ private: move_point_topo_change(const Vertex_handle& old_vertex, const Point_3& new_position, OutdatedCellsOutputIterator outdated_cells, - DeletedCellsOutputIterator deleted_cells); - + DeletedCellsOutputIterator deleted_cells) const; + Vertex_handle move_point_topo_change(const Vertex_handle& old_vertex, - const Point_3& new_position); - + const Point_3& new_position) const; + template < typename OutdatedCellsOutputIterator > Vertex_handle move_point_no_topo_change(const Vertex_handle& old_vertex, const Point_3& new_position, - OutdatedCellsOutputIterator outdated_cells); + OutdatedCellsOutputIterator outdated_cells) const; Vertex_handle move_point_no_topo_change(const Vertex_handle& old_vertex, - const Point_3& new_position); - + const Point_3& new_position) const; + /** * Returns the least square plane from v, using adjacent surface points */ Plane_3 get_least_square_surface_plane(const Vertex_handle& v, Point_3& ref_point, Surface_patch_index index = Surface_patch_index()) const; - + /** - * @brief Returns the projection of \c p, using direction of + * @brief Returns the projection of \c p, using direction of * \c projection_vector */ Point_3 project_on_surface_aux(const Point_3& p, const Point_3& ref_point, const Vector_3& projection_vector) const; - + /** * Reverts the move from \c old_point to \c new_vertex. Returns the inserted * vertex located at \c old_point @@ -1314,16 +1641,16 @@ private: OutputIterator outdated_cells) { // Move vertex - Vertex_handle revert_vertex = + Vertex_handle revert_vertex = move_point_topo_change(new_vertex, old_point, outdated_cells, CGAL::Emptyset_iterator()); //deleted cells CGAL_assertion(Vertex_handle() != revert_vertex); - + return revert_vertex; } - + /** * Returns the boundary of restricted facets of \c facets, and the list of vertices of all restricted facets, @@ -1333,7 +1660,7 @@ private: get_surface_boundary(const Vertex_handle& moving_vertex, const Facet_vector& facets, Vertex_set& incident_surface_vertices) const; - + /** * Returns the boundary of restricted facets of \c cells and the list of vertices of all restricted facets. @@ -1347,13 +1674,13 @@ private: get_facets(cells), incident_surface_vertices); } - + /** - * Returns false if there is a vertex belonging to one facet of \c facets + * Returns false if there is a vertex belonging to one facet of \c facets * which has not his dimension < 3 */ bool check_no_inside_vertices(const Facet_vector& facets) const; - + /** * Returns the impacted cells when moving \c vertex to \c conflict_point */ @@ -1361,36 +1688,37 @@ private: OutputIterator get_conflict_zone_no_topo_change(const Vertex_handle& vertex, OutputIterator conflict_cells) const; - + template OutputIterator get_conflict_zone_topo_change(const Vertex_handle& vertex, const Point_3& conflict_point, OutputIterator conflict_cells) const; - - template void get_conflict_zone_topo_change(const Vertex_handle& v, const Point_3& conflict_point, CellsOutputIterator insertion_conflict_cells, FacetsOutputIterator insertion_conflict_boundary, - CellsOutputIterator removal_conflict_cells) const; + CellsOutputIterator removal_conflict_cells, + bool *could_lock_zone = NULL) const; + - template < typename ConflictCellsInputIterator, typename OutdatedCellsOutputIterator, typename DeletedCellsOutputIterator > - Vertex_handle + Vertex_handle move_point_topo_change_conflict_zone_known(const Vertex_handle& old_vertex, const Point_3& new_position, const Facet& insertion_boundary_facet, ConflictCellsInputIterator insertion_conflict_cells_begin, ConflictCellsInputIterator insertion_conflict_cells_end, ConflictCellsInputIterator removal_conflict_cells_begin, - ConflictCellsInputIterator removal_conflict_cells_end, + ConflictCellsInputIterator removal_conflict_cells_end, OutdatedCellsOutputIterator outdated_cells, - DeletedCellsOutputIterator deleted_cells); + DeletedCellsOutputIterator deleted_cells) const; /** * Updates \c boundary wrt \c edge: if edge is already in boundary we remove @@ -1401,7 +1729,7 @@ private: const Vertex_handle third_vertex, const Surface_patch_index& surface_index) const { - const typename Facet_boundary::value_type x = + const typename Facet_boundary::value_type x = std::make_pair(edge, std::make_pair(surface_index, std::make_pair(c3t3_.in_dimension(third_vertex), @@ -1411,13 +1739,13 @@ private: ); typename Facet_boundary::iterator boundary_it = boundary.find(edge); - + if ( boundary_it != boundary.end() ) boundary.erase(boundary_it); else boundary.insert(x); } - + /** * Returns the facets of \c cells (returns each facet only once i.e. use * canonical facet) @@ -1426,7 +1754,7 @@ private: { return get_facets(cells.begin(),cells.end()); } - + // TODO: write get_facets so that it uses update_facets with a FacetUpdater that calls push_back #if defined(CGAL_MESH_3_GET_FACETS_USING_INTRUSIVE_LIST) && defined(CGAL_INTRUSIVE_LIST) @@ -1437,13 +1765,13 @@ private: Facet_vector result; // AF: todo: resize? #ifdef CGAL_CONSTRUCT_INTRUSIVE_LIST_RANGE_CONSTRUCTOR Intrusive_list outdated_cells(first_cell, last_cell); -#else +#else Intrusive_list outdated_cells; for( ;first_cell!= last_cell; ++first_cell){ - outdated_cells.insert(*first_cell); + outdated_cells.insert(*first_cell); } #endif - + for(typename Intrusive_list::iterator it = outdated_cells.begin(); it != outdated_cells.end(); ++it){ @@ -1459,7 +1787,7 @@ private: result.push_back(Facet(cell,i)); } } else { // report it now or never - if(cell < n){ + if(cell < n){ result.push_back(Facet(cell,i)); }else { result.push_back(Facet(n,n->index(cell))); @@ -1475,7 +1803,7 @@ private: result.push_back(Facet(cell,i)); } } else { // report it now or never - if(cell < n){ + if(cell < n){ result.push_back(Facet(cell,i)); }else { result.push_back(Facet(n,n->index(cell))); @@ -1497,15 +1825,15 @@ private: { // Get all facets typedef Get_all_facets > Get_facets; - + Facet_vector all_facets; all_facets.reserve(64); std::for_each(first_cell, last_cell, Get_facets(tr_,std::back_inserter(all_facets))); - + std::sort(all_facets.begin(), all_facets.end()); - + // Keep one copy of each facet (maybe copy could be avoided) // typename Facet_vector::iterator all_facets_end = // std::unique(all_facets.begin(), all_facets.end()); @@ -1514,7 +1842,7 @@ private: std::unique_copy(all_facets.begin(), all_facets.end(), std::back_inserter(facets)); - + return facets; } #endif @@ -1523,52 +1851,60 @@ private: template void update_facets(Intrusive_list& outdated_cells, FacetUpdater updater) { - typename Intrusive_list::iterator it; - for(it = outdated_cells.begin(); - it != outdated_cells.end(); - ++it) +# ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) { - Cell_handle cell = *it; - - int i=0; - bool inf = false; - for ( ; i<4 && (!inf) ; ++i ){ - if ( tr_.is_infinite(cell->vertex(i)) ){ - inf = true; - Cell_handle n = cell->neighbor(i); - if(n->next_intrusive() != Cell_handle()){// the neighbor is also outdated - if(cell < n){ // otherwise n will report it later - updater(Facet(cell,i)); - } - } else { // report it now or never - if(cell < n){ - updater(Facet(cell,i)); - }else { - updater(Facet(n,n->index(cell))); - } - } - } - } - if(! inf){ - for ( i=0 ; i<4 ; ++i ){ - Cell_handle n = cell->neighbor(i); - if(n->next_intrusive() != Cell_handle()){// the neighbor is also outdated - if(cell < n){ // otherwise n will report it later - updater(Facet(cell,i)); - } - } else { // report it now or never - if(cell < n){ - updater(Facet(cell,i)); - }else { - updater(Facet(n,n->index(cell))); - } - } - } + tbb::parallel_do( + outdated_cells.begin(), outdated_cells.end(), + Update_cell_facets(tr_, updater)); + } + // Sequential + else +# endif // CGAL_LINKED_WITH_TBB + { + typename Intrusive_list::iterator it; + for(it = outdated_cells.begin(); + it != outdated_cells.end(); + ++it) + { + Update_cell_facets ucf(tr_, updater); + ucf(*it); } } } #endif //CGAL_INTRUSIVE_LIST + // Used by the parallel version + template + void update_facets(std::vector& outdated_cells_vector, FacetUpdater updater) + { +# ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { + tbb::parallel_for + ( + tbb::blocked_range(0, outdated_cells_vector.size()), + Update_cell_facets_for_parallel_for( + tr_, updater, outdated_cells_vector) + ); + } + // Sequential + else +# endif // CGAL_LINKED_WITH_TBB + { + typename std::vector::iterator it; + for(it = outdated_cells_vector.begin(); + it != outdated_cells_vector.end(); + ++it) + { + Update_cell_facets ucf(tr_, updater); + ucf(*it); + } + } + } + /** * Returns the facets of \c cells (returns each facet only once i.e. use @@ -1579,15 +1915,15 @@ private: ForwardIterator last_cell) const { typedef Get_all_facets > Get_facets; - + Facet_vector all_facets; all_facets.reserve(64); std::for_each(first_cell, last_cell, Get_facets(tr_,std::back_inserter(all_facets))); - + std::sort(all_facets.begin(), all_facets.end()); - + // Keep one copy of each facet (maybe copy could be avoided) // typename Facet_vector::iterator all_facets_end = // std::unique(all_facets.begin(), all_facets.end()); @@ -1599,7 +1935,7 @@ private: CGAL_HISTOGRAM_PROFILER("|facets|", facets.size()); return facets; } - + /** * Returns false iff a surface facet of `cells` has entered or left the @@ -1615,7 +1951,7 @@ private: // Todo: improve this (maybe we don't have to check if no facet is on surface) Facet_vector facets = get_facets(cells); Facet_vector surface_facets; - + // Check that nothing changed Update_c3t3 checker(domain_,c3t3_); for ( typename Facet_vector::iterator fit = facets.begin() ; @@ -1634,20 +1970,20 @@ private: ((bool)sp && c3t3_.surface_patch_index(*fit) != sp.get()) ) return false; } - + return true; } /** * Restore mesh for cells and facets of \c cells, using domain_ - */ + */ template void restore_mesh(ForwardIterator first_cell, ForwardIterator last_cell) { Facet_vector facets = get_facets(first_cell, last_cell); restore_mesh(first_cell, last_cell, facets.begin(), facets.end()); } - + /** * Restore mesh for cells of \c cells and facets of \c facets, using domain_ */ @@ -1662,9 +1998,9 @@ private: std::for_each(first_facet, last_facet, updater); std::for_each(first_cell, last_cell, updater); } - + /** - * Returns true if facets of \c facets have the same boundary as + * Returns true if facets of \c facets have the same boundary as * \c old_boundary, and if the list of vertices has not changed. */ bool check_surface_mesh(const Vertex_handle& moving_vertex, @@ -1682,17 +2018,18 @@ private: new_boundary.end(), old_boundary.begin()) ); } - + + void set_facet_visited(const Facet& facet) { facet.first->set_facet_visited(facet.second); const Facet mirror_facet = tr_.mirror_facet(facet); - mirror_facet.first->set_facet_visited(mirror_facet.second); + mirror_facet.first->set_facet_visited(mirror_facet.second); } - + /** * Orders handles \c h1, \c h2 & \c h3 - */ + */ template void order_handles(Handle& h1, Handle& h2, Handle& h3) const { @@ -1700,11 +2037,11 @@ private: if ( h2 < h1 ) std::swap(h1,h2); - + if ( h3 < h2 ) { std::swap(h2,h3); - + if ( h2 < h1 ) // don't need to compare h2 & h1 if h2 didn't change std::swap(h1,h2); } @@ -1733,7 +2070,7 @@ private: reset_circumcenter_cache(boost::begin(cell_range), boost::end(cell_range)); } - + template void reset_circumcenter_cache(CellForwardIterator cells_begin, CellForwardIterator cells_end) const @@ -1743,53 +2080,305 @@ private: bl::bind(&Cell::invalidate_circumcenter, *bl::_1) ); } + private: + + // Functor for update_facets function (base) + template + class Update_cell_facets + { + Tr & m_tr; + FacetUpdater_ & m_facet_updater; + + protected: + + void update(const Cell_handle& cell) const + { + Cell_handle null_cell; + bool inf = false; + for (int i=0 ; i<4 && (!inf) ; ++i ){ + if ( m_tr.is_infinite(cell->vertex(i)) ){ + inf = true; + Cell_handle n = cell->neighbor(i); + if(n->next_intrusive() != null_cell){// the neighbor is also outdated + if(cell < n){ // otherwise n will report it later + Facet f(cell,i); + m_facet_updater(f); + } + } else { // report it now or never + if(cell < n){ + Facet f(cell,i); + m_facet_updater(f); + }else { + Facet f(n,n->index(cell)); + m_facet_updater(f); + } + } + } + } + if(! inf){ + for ( int i=0 ; i<4 ; ++i ){ + Cell_handle n = cell->neighbor(i); + if(n->next_intrusive() != null_cell){// the neighbor is also outdated + if(cell < n){ // otherwise n will report it later + Facet f(cell,i); + m_facet_updater(f); + } + } else { // report it now or never + if(cell < n){ + Facet f(cell,i); + m_facet_updater(f); + }else { + Facet f(n,n->index(cell)); + m_facet_updater(f); + } + } + } + } + } + + public: + // Constructor + Update_cell_facets(Tr &tr, + FacetUpdater_& fu) + : m_tr(tr), m_facet_updater(fu) + {} + + // Constructor + Update_cell_facets(const Update_cell_facets &uf) + : m_tr(uf.m_tr), m_facet_updater(uf.m_facet_updater) + {} + + // operator() + void operator()(const Cell_handle& cell) const + { + update(cell); + } + }; + +#ifdef CGAL_LINKED_WITH_TBB + // Same functor: special version for tbb:parallel_for + template + class Update_cell_facets_for_parallel_for + : Update_cell_facets + { + typedef Update_cell_facets Base; + using Base::update; + + const std::vector & m_outdated_cells; + + public: + // Constructor + Update_cell_facets_for_parallel_for( + Tr &tr, + FacetUpdater_& fu, + const std::vector &oc) + : Base(tr, fu), m_outdated_cells(oc) + {} + + // Constructor + Update_cell_facets_for_parallel_for( + const Update_cell_facets_for_parallel_for &uf) + : Base(uf), m_outdated_cells(uf.m_outdated_cells) + {} + + // operator() + void operator()(const tbb::blocked_range& r) const + { + for( size_t i = r.begin() ; i != r.end() ; ++i) + update(m_outdated_cells[i]); + } + }; + + // ----------------------------------- + // ----------------------------------- + // ----------------------------------- + + // Functor for rebuild_restricted_delaunay function + template + class Update_cell + { + C3T3 & m_c3t3; + Update_c3t3_ & m_updater; + + protected: + typedef typename C3T3_::Cell_handle Cell_handle; + + void update(const Cell_handle& cell) const + { + m_c3t3.remove_from_complex(cell); + m_updater(cell); + } + + public: + // Constructor + Update_cell(C3T3_ &c3t3, Update_c3t3_& updater) + : m_c3t3(c3t3), m_updater(updater) + {} + + // Constructor + Update_cell(const Update_cell &uc) + : m_c3t3(uc.m_c3t3), m_updater(uc.m_updater) + {} + + // operator() + void operator()(const Cell_handle& cell) const + { + update(cell); + } + }; + + + // Same functor: special version for tbb:parallel_for + template + class Update_cell_for_parallel_for + : Update_cell + { + typedef Update_cell Base; + using Base::update; + + const std::vector & m_outdated_cells; + + public: + // Constructor + Update_cell_for_parallel_for( + C3T3_ &c3t3, + Update_c3t3_& updater, + const std::vector &oc) + : Base(c3t3, updater), m_outdated_cells(oc) + {} + + // Constructor + Update_cell_for_parallel_for( + const Update_cell_for_parallel_for &uc) + : Base(uc), m_outdated_cells(uc.m_outdated_cells) + {} + + // operator() + void operator()(const tbb::blocked_range& r) const + { + for( size_t i = r.begin() ; i != r.end() ; ++i) + update(m_outdated_cells[i]); + } + }; +#endif + + // ----------------------------------- + // ----------------------------------- + // ----------------------------------- + + // Functor for rebuild_restricted_delaunay function +#ifdef CGAL_LINKED_WITH_TBB + template + class Update_facet + { + const C3T3_helpers_ & m_c3t3_helpers; + C3T3_ & m_c3t3; + Update_c3t3_ & m_updater; + Vertex_to_proj_set_ & m_vertex_to_proj; + + typedef typename C3T3_::Vertex_handle Vertex_handle; + typedef typename C3T3_::Cell_handle Cell_handle; + typedef typename C3T3_::Facet Facet; + typedef typename C3T3::Surface_patch_index Surface_patch_index; + + public: + // Constructor + Update_facet(const C3T3_helpers_ & c3t3_helpers, + C3T3_ &c3t3, Update_c3t3_& updater, + Vertex_to_proj_set_ &vertex_to_proj) + : m_c3t3_helpers(c3t3_helpers), m_c3t3(c3t3), m_updater(updater), + m_vertex_to_proj(vertex_to_proj) + {} + + // Constructor + Update_facet(const Update_facet &uc) + : m_c3t3_helpers(uc.m_c3t3_helpers), m_c3t3(uc.m_c3t3), + m_updater(uc.m_updater), m_vertex_to_proj(uc.m_vertex_to_proj) + {} + + // operator() + void operator()( const Facet& facet ) const + { + // Update facet + m_c3t3.remove_from_complex(facet); + m_updater(facet); + + // Update m_vertex_to_proj + if ( m_c3t3.is_in_complex(facet) ) + { + // Iterate on vertices + int k = facet.second; + for ( int i=1 ; i<4 ; ++i ) + { + const Vertex_handle& v = facet.first->vertex((k+i)&3); + if ( m_c3t3.in_dimension(v) > 2 ) + { + std::pair p + = std::make_pair(v, m_c3t3.surface_patch_index(facet)); + m_c3t3_helpers.lock_vertex_to_proj(); + m_vertex_to_proj.insert(p); + m_c3t3_helpers.unlock_vertex_to_proj(); + } + } + } + } + }; +#endif + // ----------------------------------- // Private data // ----------------------------------- C3T3& c3t3_; Tr& tr_; const MeshDomain& domain_; -}; - - +}; // class C3T3_helpers + + template template std::pair::Vertex_handle> -C3T3_helpers:: +C3T3_helpers:: update_mesh(const Point_3& new_position, const Vertex_handle& old_vertex, const SliverCriterion& criterion, - OutputIterator modified_vertices) + OutputIterator modified_vertices, + bool *could_lock_zone) { // std::cerr << "\nupdate_mesh[v1](" << new_position << ",\n" // << " " << (void*)(&*old_vertex) << "=" << old_vertex->point() // << ")\n"; - Cell_vector incident_cells; - incident_cells.reserve(64); - tr_.incident_cells(old_vertex, std::back_inserter(incident_cells)); - if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells) ) + if (could_lock_zone) + *could_lock_zone = true; + + Cell_vector incident_cells_; + incident_cells_.reserve(64); + tr_.incident_cells(old_vertex, std::back_inserter(incident_cells_)); + if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells_) ) { + return update_mesh_no_topo_change(new_position, old_vertex, criterion, modified_vertices, - incident_cells); + incident_cells_); } else { return update_mesh_topo_change(new_position, old_vertex, criterion, - modified_vertices); + modified_vertices, + could_lock_zone); } } template template std::pair::Vertex_handle> -C3T3_helpers:: +C3T3_helpers:: update_mesh_no_topo_change(const Point_3& new_position, const Vertex_handle& old_vertex, const SliverCriterion& criterion, @@ -1814,11 +2403,11 @@ update_mesh_no_topo_change(const Point_3& new_position, reset_circumcenter_cache(conflict_cells); reset_sliver_cache(conflict_cells); move_point_no_topo_change(old_vertex,new_position); - + // Check that surface mesh is still valid - // and Get new criterion value (conflict_zone did not change) + // and Get new criterion value (conflict_zone did not change) // warnings : valid_move updates caches - // verify_surface does not change c3t3 when returns false, + // verify_surface does not change c3t3 when returns false, // but it does change circumcenters if( verify_surface(conflict_cells) && criterion.valid_move(c3t3_cells(conflict_cells))) @@ -1849,11 +2438,12 @@ update_mesh_no_topo_change(const Point_3& new_position, template template std::pair::Vertex_handle> -C3T3_helpers:: +C3T3_helpers:: update_mesh_topo_change(const Point_3& new_position, const Vertex_handle& old_vertex, const SliverCriterion& criterion, - OutputIterator modified_vertices) + OutputIterator modified_vertices, + bool *could_lock_zone) { // std::cerr << "update_mesh_topo_change(\n" // << new_position << ",\n" @@ -1867,7 +2457,11 @@ update_mesh_topo_change(const Point_3& new_position, get_conflict_zone_topo_change(old_vertex, new_position, std::inserter(insertion_conflict_cells,insertion_conflict_cells.end()), std::back_inserter(insertion_conflict_boundary), - std::inserter(removal_conflict_cells, removal_conflict_cells.end())); + std::inserter(removal_conflict_cells, removal_conflict_cells.end()), + could_lock_zone); + + if (could_lock_zone && *could_lock_zone == false) + return std::make_pair(false, Vertex_handle()); if(insertion_conflict_boundary.empty()) return std::make_pair(false,old_vertex); //new_location is a vertex already @@ -1876,7 +2470,7 @@ update_mesh_topo_change(const Point_3& new_position, conflict_cells.reserve(insertion_conflict_cells.size()+removal_conflict_cells.size()); std::set_union(insertion_conflict_cells.begin(), insertion_conflict_cells.end(), removal_conflict_cells.begin(), removal_conflict_cells.end(), - std::back_inserter(conflict_cells)); + std::back_inserter(conflict_cells)); //backup metadata std::set cells_backup; @@ -1890,13 +2484,13 @@ update_mesh_topo_change(const Point_3& new_position, Vertex_set old_incident_surface_vertices; Facet_boundary old_surface_boundary = get_surface_boundary(old_vertex, conflict_cells, old_incident_surface_vertices); - + reset_circumcenter_cache(conflict_cells); reset_sliver_cache(conflict_cells); Cell_vector outdated_cells; outdated_cells.reserve(64); - Vertex_handle new_vertex = + Vertex_handle new_vertex = move_point_topo_change_conflict_zone_known(old_vertex, new_position, insertion_conflict_boundary[0], insertion_conflict_cells.begin(), @@ -1907,18 +2501,18 @@ update_mesh_topo_change(const Point_3& new_position, CGAL::Emptyset_iterator()); // If nothing changed, return - if ( old_position == new_vertex->point() ) + if ( old_position == new_vertex->point() ) { // std::cerr << "update_mesh_topo_change: no move!\n"; // check_c3t3(c3t3_); return std::make_pair(false,old_vertex); } - + restore_mesh(outdated_cells.begin(),outdated_cells.end()); // std::cerr << "new_sliver_value=" << new_sliver_value << std::endl; // Check that surface boundary does not change. - // This check ensures that vertices which are inside c3t3 stay inside. + // This check ensures that vertices which are inside c3t3 stay inside. if (criterion.valid_move(c3t3_cells(outdated_cells)) && check_surface_mesh(new_vertex, get_facets(outdated_cells), @@ -1956,11 +2550,11 @@ update_mesh_topo_change(const Point_3& new_position, return std::make_pair(false,revert_vertex); } } - + template -template +template typename C3T3_helpers::Vertex_handle -C3T3_helpers:: +C3T3_helpers:: update_mesh(const Point_3& new_position, const Vertex_handle& old_vertex, OutputIterator modified_vertices, @@ -1975,51 +2569,117 @@ update_mesh(const Point_3& new_position, std::back_inserter(outdated_cells), CGAL::Emptyset_iterator()); // move_point has invalidated caches - + restore_mesh(outdated_cells.begin(),outdated_cells.end()); - + // Fill modified vertices - if ( fill_vertices + if ( fill_vertices && !(boost::is_same::value)) { fill_modified_vertices(outdated_cells.begin(), outdated_cells.end(), - new_vertex, modified_vertices); + new_vertex, modified_vertices); } - - return new_vertex; + + return new_vertex; } - + #ifdef CGAL_INTRUSIVE_LIST template template void -C3T3_helpers:: +C3T3_helpers:: rebuild_restricted_delaunay(OutdatedCells& outdated_cells, Moving_vertices_set& moving_vertices) { typename OutdatedCells::iterator first_cell = outdated_cells.begin(); typename OutdatedCells::iterator last_cell = outdated_cells.end(); Update_c3t3 updater(domain_,c3t3_); - + +# ifdef CGAL_MESH_3_PROFILING + std::cerr << std::endl << " Updating cells..."; + WallClockTimer t; + size_t num_cells = c3t3_.number_of_cells_in_complex(); +# endif + // Updates cells - while ( first_cell != last_cell ) + // Note: ~58% of rebuild_restricted_delaunay time + + std::set vertex_to_proj; + +# ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) { - const Cell_handle cell = *first_cell++; - c3t3_.remove_from_complex(cell); - updater(cell); + std::vector outdated_cells_vector; + outdated_cells_vector.reserve(outdated_cells.size()); + for ( ; first_cell != last_cell ; ++first_cell) + { + outdated_cells_vector.push_back(*first_cell); + } + + tbb::parallel_for( + tbb::blocked_range(0, outdated_cells_vector.size()), + Update_cell_for_parallel_for( + c3t3_, updater, outdated_cells_vector)); + +# ifdef CGAL_MESH_3_PROFILING + std::cerr << " done in " << t.elapsed() << " seconds (#cells from " + << num_cells << " to " << c3t3_.number_of_cells_in_complex() << ")." + << std::endl; + std::cerr << " Updating facets..."; + t.reset(); +# endif + + // Get facets (returns each canonical facet only once) + // Note: ~42% of rebuild_restricted_delaunay time + // Facet_vector facets; + lock_vertex_to_proj(); + Facet_updater facet_updater(c3t3_,vertex_to_proj, updater); + unlock_vertex_to_proj(); + update_facets(outdated_cells_vector, facet_updater); + + // now we can clear + outdated_cells.clear(); + } + // Sequential + else +# endif // CGAL_LINKED_WITH_TBB + { + while ( first_cell != last_cell ) + { + const Cell_handle& cell = *first_cell++; + c3t3_.remove_from_complex(cell); + updater(cell); + } + +# ifdef CGAL_MESH_3_PROFILING + std::cerr << " done in " << t.elapsed() << " seconds (#cells from " + << num_cells << " to " << c3t3_.number_of_cells_in_complex() << ")." + << std::endl; + std::cerr << " Updating facets..."; + t.reset(); +# endif + + // Get facets (returns each canonical facet only once) + // Note: ~42% of rebuild_restricted_delaunay time + // Facet_vector facets; + Facet_updater facet_updater(c3t3_,vertex_to_proj, updater); + update_facets(outdated_cells, facet_updater); + + // now we can clear + outdated_cells.clear(); } - // Get facets (returns each canonical facet only once) - // Facet_vector facets; - std::set vertex_to_proj; - Facet_updater facet_updater(c3t3_,vertex_to_proj, updater); - update_facets(outdated_cells, facet_updater); - - // now we can clear - outdated_cells.clear(); +# ifdef CGAL_MESH_3_PROFILING + std::cerr << " done in " << t.elapsed() << " seconds (" + << vertex_to_proj.size() << " vertices to project)." << std::endl; + std::cerr << " Projecting interior vertices..."; + t.reset(); +# endif CGAL_HISTOGRAM_PROFILER("|vertex_to_proj|=", vertex_to_proj.size()); // Project interior vertices + // Note: ~0% of rebuild_restricted_delaunay time // TODO : iterate to be sure no interior vertice become on the surface // because of move ? for ( typename std::set::iterator it = vertex_to_proj.begin() ; @@ -2029,68 +2689,101 @@ rebuild_restricted_delaunay(OutdatedCells& outdated_cells, Point_3 new_pos = project_on_surface((*it)->point(),*it); if ( new_pos != Point_3() ) - { + { //freezing needs 'erase' to be done before the vertex is actually destroyed // Update moving vertices (it becomes new_vertex) moving_vertices.erase(*it); - + Vertex_handle new_vertex = update_mesh(new_pos,*it); c3t3_.set_dimension(new_vertex,2); moving_vertices.insert(new_vertex); } } + +# ifdef CGAL_MESH_3_PROFILING + std::cerr << " done in " << t.elapsed() << " seconds." << std::endl; +# endif } #endif //CGAL_INTRUSIVE_LIST template template void -C3T3_helpers:: +C3T3_helpers:: rebuild_restricted_delaunay(ForwardIterator first_cell, ForwardIterator last_cell, Moving_vertices_set& moving_vertices) { Update_c3t3 updater(domain_,c3t3_); - + // Get facets (returns each canonical facet only once) Facet_vector facets = get_facets(first_cell, last_cell); - - // Updates cells - while ( first_cell != last_cell ) - { - const Cell_handle& cell = *first_cell++; - c3t3_.remove_from_complex(cell); - updater(cell); - } - - // Updates facets - std::set > vertex_to_proj; - for ( typename Facet_vector::iterator fit = facets.begin() ; - fit != facets.end() ; - ++fit ) - { - // Update facet - c3t3_.remove_from_complex(*fit); - updater(*fit); - // Update vertex_to_proj - if ( c3t3_.is_in_complex(*fit) ) + // Updates cells + // Note: ~58% of rebuild_restricted_delaunay time +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { + tbb::parallel_do(first_cell, last_cell, + Update_cell(c3t3_, updater)); + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + while ( first_cell != last_cell ) { - // Iterate on vertices - int k = fit->second; - for ( int i=1 ; i<4 ; ++i ) + Update_cell uc(c3t3_, updater); + uc(*first_cell++); + } + } + + // Updates facets + typedef std::set > + Vertex_to_proj_set; + Vertex_to_proj_set vertex_to_proj; +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { + tbb::parallel_do( + facets.begin(), facets.end(), + Update_facet( + *this, c3t3_, updater, vertex_to_proj) + ); + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + for ( typename Facet_vector::iterator fit = facets.begin() ; + fit != facets.end() ; + ++fit ) + { + // Update facet + c3t3_.remove_from_complex(*fit); + updater(*fit); + + // Update vertex_to_proj + if ( c3t3_.is_in_complex(*fit) ) { - const Vertex_handle& v = fit->first->vertex((k+i)&3); - if ( c3t3_.in_dimension(v) > 2 ) - { - vertex_to_proj.insert - (std::make_pair(v, c3t3_.surface_patch_index(*fit))); + // Iterate on vertices + int k = fit->second; + for ( int i=1 ; i<4 ; ++i ) + { + const Vertex_handle& v = fit->first->vertex((k+i)&3); + if ( c3t3_.in_dimension(v) > 2 ) + { + vertex_to_proj.insert + (std::make_pair(v, c3t3_.surface_patch_index(*fit))); + } } } } } - + // Project interior vertices // TODO : iterate to be sure no interior vertice become on the surface // because of move ? @@ -2109,7 +2802,7 @@ rebuild_restricted_delaunay(ForwardIterator first_cell, Vertex_handle new_vertex = update_mesh(new_pos,it->first); c3t3_.set_dimension(new_vertex,2); - + moving_vertices.insert(new_vertex); } } @@ -2119,24 +2812,24 @@ rebuild_restricted_delaunay(ForwardIterator first_cell, template template -typename C3T3_helpers::Vertex_handle -C3T3_helpers:: +typename C3T3_helpers::Vertex_handle +C3T3_helpers:: move_point(const Vertex_handle& old_vertex, const Point_3& new_position, OutdatedCellsOutputIterator outdated_cells, - DeletedCellsOutputIterator deleted_cells) + DeletedCellsOutputIterator deleted_cells) const { - // std::cerr << "C3T3_helpers::move_point[v2](" + // std::cerr << "C3T3_helpers::move_point[v2](" // << (void*)(&*old_vertex) << " = " << old_vertex->point() // << " , " << new_position << ")\n"; - Cell_vector incident_cells; - incident_cells.reserve(64); - tr_.incident_cells(old_vertex, std::back_inserter(incident_cells)); - if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells) ) + Cell_vector incident_cells_; + incident_cells_.reserve(64); + tr_.incident_cells(old_vertex, std::back_inserter(incident_cells_)); + if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells_) ) { - reset_circumcenter_cache(incident_cells); - reset_sliver_cache(incident_cells); - std::copy(incident_cells.begin(),incident_cells.end(), outdated_cells); + reset_circumcenter_cache(incident_cells_); + reset_sliver_cache(incident_cells_); + std::copy(incident_cells_.begin(),incident_cells_.end(), outdated_cells); return move_point_no_topo_change(old_vertex, new_position); } @@ -2149,22 +2842,23 @@ move_point(const Vertex_handle& old_vertex, } } +// Sequential template -typename C3T3_helpers::Vertex_handle -C3T3_helpers:: +typename C3T3_helpers::Vertex_handle +C3T3_helpers:: move_point(const Vertex_handle& old_vertex, const Point_3& new_position, - Outdated_cell_set& outdated_cells_set, - Moving_vertices_set& moving_vertices) + Outdated_cell_set& outdated_cells_set, + Moving_vertices_set& moving_vertices) const { - Cell_vector incident_cells; - incident_cells.reserve(64); - tr_.incident_cells(old_vertex, std::back_inserter(incident_cells)); - if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells) ) + Cell_vector incident_cells_; + incident_cells_.reserve(64); + tr_.incident_cells(old_vertex, std::back_inserter(incident_cells_)); + if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells_) ) { - reset_circumcenter_cache(incident_cells); - reset_sliver_cache(incident_cells); - std::copy(incident_cells.begin(),incident_cells.end(), + reset_circumcenter_cache(incident_cells_); + reset_sliver_cache(incident_cells_); + std::copy(incident_cells_.begin(),incident_cells_.end(), std::inserter(outdated_cells_set, outdated_cells_set.end())); return move_point_no_topo_change(old_vertex, new_position); } @@ -2176,36 +2870,123 @@ move_point(const Vertex_handle& old_vertex, moving_vertices.insert(new_vertex); return new_vertex; - } -} + } +} + +// Parallel +// In case of success (could_lock_zone = true), the zone is locked after the call +// ==> the caller needs to call "unlock_all_elements" by itself +// In case of failure (could_lock_zone = false), the zone is unlocked by this function +template +typename C3T3_helpers::Vertex_handle +C3T3_helpers:: +move_point(const Vertex_handle& old_vertex, + const Point_3& new_position, + Outdated_cell_set& outdated_cells_set, + Moving_vertices_set& moving_vertices, + bool *could_lock_zone) const +{ + CGAL_assertion(could_lock_zone != NULL); + *could_lock_zone = true; + + if (!try_lock_vertex(old_vertex)) // LOCK + { + *could_lock_zone = false; + unlock_all_elements(); + return Vertex_handle(); + } + + //======= Get incident cells ========== + Cell_vector incident_cells_; + incident_cells_.reserve(64); + if (try_lock_and_get_incident_cells(old_vertex, incident_cells_) == false) + { + *could_lock_zone = false; + return Vertex_handle(); + } + //======= /Get incident cells ========== + + if (!try_lock_point(new_position)) // LOCK + { + *could_lock_zone = false; + unlock_all_elements(); + return Vertex_handle(); + } + if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells_) ) + { + reset_circumcenter_cache(incident_cells_); + reset_sliver_cache(incident_cells_); + + lock_outdated_cells(); + std::copy(incident_cells_.begin(),incident_cells_.end(), + std::inserter(outdated_cells_set, outdated_cells_set.end())); + unlock_outdated_cells(); + + Vertex_handle new_vertex = + move_point_no_topo_change(old_vertex, new_position); + + // Don't "unlock_all_elements" here, the caller may need it to do it himself + return new_vertex; + } + else + { + //moving_vertices.erase(old_vertex); MOVED BELOW + + Vertex_handle new_vertex = + move_point_topo_change(old_vertex, new_position, outdated_cells_set, + could_lock_zone); + + if (*could_lock_zone == false) + { + unlock_all_elements(); + return Vertex_handle(); + } + + + lock_moving_vertices(); + moving_vertices.erase(old_vertex); + moving_vertices.insert(new_vertex); + unlock_moving_vertices(); + + // Don't "unlock_all_elements" here, the caller may need it to do it himself + return new_vertex; + } +} template -typename C3T3_helpers::Vertex_handle -C3T3_helpers:: +typename C3T3_helpers::Vertex_handle +C3T3_helpers:: move_point_topo_change(const Vertex_handle& old_vertex, const Point_3& new_position, - Outdated_cell_set& outdated_cells_set) + Outdated_cell_set& outdated_cells_set, + bool *could_lock_zone) const { Cell_set insertion_conflict_cells; Cell_set removal_conflict_cells; Facet_vector insertion_conflict_boundary; insertion_conflict_boundary.reserve(64); - + get_conflict_zone_topo_change(old_vertex, new_position, std::inserter(insertion_conflict_cells,insertion_conflict_cells.end()), std::back_inserter(insertion_conflict_boundary), - std::inserter(removal_conflict_cells, removal_conflict_cells.end())); + std::inserter(removal_conflict_cells, removal_conflict_cells.end()), + could_lock_zone); reset_circumcenter_cache(removal_conflict_cells); reset_sliver_cache(removal_conflict_cells); reset_circumcenter_cache(insertion_conflict_cells); reset_sliver_cache(insertion_conflict_cells); + if (could_lock_zone && *could_lock_zone == false) + return Vertex_handle(); + + lock_outdated_cells(); for(typename Cell_set::iterator it = insertion_conflict_cells.begin(); it != insertion_conflict_cells.end(); ++it) outdated_cells_set.erase(*it); for(typename Cell_set::iterator it = removal_conflict_cells.begin(); it != removal_conflict_cells.end(); ++it) outdated_cells_set.erase(*it); + unlock_outdated_cells(); Cell_vector outdated_cells; Vertex_handle nv = move_point_topo_change_conflict_zone_known(old_vertex, new_position, @@ -2217,28 +2998,30 @@ move_point_topo_change(const Vertex_handle& old_vertex, std::back_inserter(outdated_cells), CGAL::Emptyset_iterator()); // deleted_cells + lock_outdated_cells(); for(typename Cell_vector::iterator it = outdated_cells.begin(); it != outdated_cells.end(); ++it) outdated_cells_set.insert(*it); - + unlock_outdated_cells(); + return nv; } template template -typename C3T3_helpers::Vertex_handle -C3T3_helpers:: +typename C3T3_helpers::Vertex_handle +C3T3_helpers:: move_point_topo_change(const Vertex_handle& old_vertex, const Point_3& new_position, OutdatedCellsOutputIterator outdated_cells, - DeletedCellsOutputIterator deleted_cells) + DeletedCellsOutputIterator deleted_cells) const { Cell_set insertion_conflict_cells; Cell_set removal_conflict_cells; Facet_vector insertion_conflict_boundary; insertion_conflict_boundary.reserve(64); - + get_conflict_zone_topo_change(old_vertex, new_position, std::inserter(insertion_conflict_cells,insertion_conflict_cells.end()), std::back_inserter(insertion_conflict_boundary), @@ -2256,6 +3039,7 @@ move_point_topo_change(const Vertex_handle& old_vertex, removal_conflict_cells.end(), outdated_cells, deleted_cells); + return nv; } @@ -2264,8 +3048,8 @@ template template < typename ConflictCellsInputIterator, typename OutdatedCellsOutputIterator, typename DeletedCellsOutputIterator > -typename C3T3_helpers::Vertex_handle -C3T3_helpers:: +typename C3T3_helpers::Vertex_handle +C3T3_helpers:: move_point_topo_change_conflict_zone_known( const Vertex_handle& old_vertex, const Point_3& new_position, @@ -2273,13 +3057,14 @@ move_point_topo_change_conflict_zone_known( ConflictCellsInputIterator insertion_conflict_cells_begin,//ordered ConflictCellsInputIterator insertion_conflict_cells_end, ConflictCellsInputIterator removal_conflict_cells_begin,//ordered - ConflictCellsInputIterator removal_conflict_cells_end, + ConflictCellsInputIterator removal_conflict_cells_end, OutdatedCellsOutputIterator outdated_cells, DeletedCellsOutputIterator deleted_cells)//warning : this should not be an iterator to Intrusive_list //o.w. deleted_cells will point to null pointer or so and crash + const { Point_3 old_position = old_vertex->point(); - // make one set with conflict zone + // make one set with conflict zone Cell_set conflict_zone; std::set_union(insertion_conflict_cells_begin, insertion_conflict_cells_end, removal_conflict_cells_begin, removal_conflict_cells_end, @@ -2287,28 +3072,28 @@ move_point_topo_change_conflict_zone_known( // Remove conflict zone cells from c3t3 (they will be deleted by insert/remove) remove_cells_and_facets_from_c3t3(conflict_zone.begin(), conflict_zone.end()); - + // Start Move point // Insert new_vertex, remove old_vertex int dimension = c3t3_.in_dimension(old_vertex); Index vertex_index = c3t3_.index(old_vertex); FT meshing_info = old_vertex->meshing_info(); // insert new point - Vertex_handle new_vertex = tr_.insert_in_hole(new_position, + Vertex_handle new_vertex = tr_.insert_in_hole(new_position, insertion_conflict_cells_begin, insertion_conflict_cells_end, - insertion_boundary_facet.first, + insertion_boundary_facet.first, insertion_boundary_facet.second); // If new_position is hidden, update what should be and return default constructed handle - if ( Vertex_handle() == new_vertex ) - { + if ( Vertex_handle() == new_vertex ) + { std::copy(conflict_zone.begin(), conflict_zone.end(), outdated_cells); - return old_vertex; + return old_vertex; } // remove old point tr_.remove(old_vertex); - + c3t3_.set_dimension(new_vertex,dimension); c3t3_.set_index(new_vertex,vertex_index); new_vertex->set_meshing_info(meshing_info); @@ -2319,7 +3104,7 @@ move_point_topo_change_conflict_zone_known( Cell_vector new_conflict_cells; new_conflict_cells.reserve(64); get_conflict_zone_topo_change(new_vertex, old_position, - std::back_inserter(new_conflict_cells)); + std::back_inserter(new_conflict_cells)); std::copy(new_conflict_cells.begin(),new_conflict_cells.end(),outdated_cells); // Fill deleted_cells @@ -2330,10 +3115,10 @@ move_point_topo_change_conflict_zone_known( } template -typename C3T3_helpers::Vertex_handle +typename C3T3_helpers::Vertex_handle C3T3_helpers:: move_point_topo_change(const Vertex_handle& old_vertex, - const Point_3& new_position) + const Point_3& new_position) const { // Insert new_vertex, remove old_vertex int dimension = c3t3_.in_dimension(old_vertex); @@ -2346,47 +3131,51 @@ move_point_topo_change(const Vertex_handle& old_vertex, if ( Vertex_handle() == new_vertex ) { return Vertex_handle(); } // remove old point tr_.remove(old_vertex); - + c3t3_.set_dimension(new_vertex,dimension); c3t3_.set_index(new_vertex,vertex_index); new_vertex->set_meshing_info(meshing_info); return new_vertex; } - + template template -typename C3T3_helpers::Vertex_handle -C3T3_helpers:: +typename C3T3_helpers::Vertex_handle +C3T3_helpers:: move_point_no_topo_change(const Vertex_handle& old_vertex, const Point_3& new_position, - OutdatedCellsOutputIterator outdated_cells) + OutdatedCellsOutputIterator outdated_cells) const { + + lock_outdated_cells(); get_conflict_zone_no_topo_change(old_vertex, outdated_cells); + unlock_outdated_cells(); + return move_point_no_topo_change(old_vertex, new_position); } template -typename C3T3_helpers::Vertex_handle -C3T3_helpers:: +typename C3T3_helpers::Vertex_handle +C3T3_helpers:: move_point_no_topo_change(const Vertex_handle& old_vertex, - const Point_3& new_position) -{ + const Point_3& new_position) const +{ // Change vertex position old_vertex->set_point(new_position); - return old_vertex; + return old_vertex; } /** - * @brief Returns the projection of \c p, using direction of + * @brief Returns the projection of \c p, using direction of * \c projection_vector */ template typename C3T3_helpers::Point_3 -C3T3_helpers:: +C3T3_helpers:: project_on_surface_aux(const Point_3& p, const Point_3& ref_point, const Vector_3& projection_vector) const @@ -2396,33 +3185,33 @@ project_on_surface_aux(const Point_3& p, // Build a segment directed as projection_direction, typename Gt::Compute_squared_distance_3 sq_distance = Gt().compute_squared_distance_3_object(); - + typename Gt::Compute_squared_length_3 sq_length = Gt().compute_squared_length_3_object(); - + typename Gt::Construct_scaled_vector_3 scale = Gt().construct_scaled_vector_3_object(); - + typename Gt::Is_degenerate_3 is_degenerate = Gt().is_degenerate_3_object(); typename MD::Construct_intersection construct_intersection = domain_.construct_intersection_object(); - + const FT sq_dist = sq_distance(p,ref_point); const FT sq_proj_length = sq_length(projection_vector); - + if ( CGAL_NTS is_zero(sq_proj_length) ) return ref_point; - + const Vector_3 projection_scaled_vector = scale(projection_vector, CGAL::sqrt(sq_dist/sq_proj_length)); - + const Point_3 source = p + projection_scaled_vector; const Point_3 target = p - projection_scaled_vector; - + const Segment_3 proj_segment(source,target); - + if ( is_degenerate(proj_segment) ) return ref_point; @@ -2434,7 +3223,7 @@ project_on_surface_aux(const Point_3& p, if ( do_intersect(proj_segment) ) return CGAL::cpp0x::get<0>(construct_intersection(proj_segment)); else - return ref_point; + return ref_point; #else // CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 @@ -2442,23 +3231,34 @@ project_on_surface_aux(const Point_3& p, Intersection intersection = construct_intersection(proj_segment); if(CGAL::cpp0x::get<2>(intersection) == 2) return CGAL::cpp0x::get<0>(intersection); - else + else return ref_point; #endif // CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 } - + template typename C3T3_helpers::Plane_3 -C3T3_helpers:: +C3T3_helpers:: get_least_square_surface_plane(const Vertex_handle& v, Point_3& reference_point, Surface_patch_index patch_index) const { // Get incident facets Facet_vector facets; - tr_.finite_incident_facets(v,std::back_inserter(facets)); +# ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { + tr_.finite_incident_facets_threadsafe(v, std::back_inserter(facets)); + } + // Sequential + else +# endif // CGAL_LINKED_WITH_TBB + { + tr_.finite_incident_facets(v,std::back_inserter(facets)); + } // Get adjacent surface points std::vector surface_point_vector; @@ -2466,13 +3266,13 @@ get_least_square_surface_plane(const Vertex_handle& v, fit != facets.end() ; ++fit ) { - if ( c3t3_.is_in_complex(*fit) && - (patch_index == Surface_patch_index() || + if ( c3t3_.is_in_complex(*fit) && + (patch_index == Surface_patch_index() || c3t3_.surface_patch_index(*fit) == patch_index) ) { const Cell_handle& cell = fit->first; const int& i = fit->second; - + surface_point_vector.push_back(cell->get_facet_surface_center(i)); } } @@ -2480,24 +3280,24 @@ get_least_square_surface_plane(const Vertex_handle& v, // In some cases point is not a real surface point if ( surface_point_vector.empty() ) return Plane_3(); - + // Compute least square fitting plane Plane_3 plane; CGAL::linear_least_squares_fitting_3(surface_point_vector.begin(), surface_point_vector.end(), plane, Dimension_tag<0>()); - + reference_point = surface_point_vector.front(); return plane; } - - - + + + template typename C3T3_helpers::Point_3 -C3T3_helpers:: +C3T3_helpers:: project_on_surface(const Point_3& p, const Vertex_handle& v, Surface_patch_index index) const @@ -2506,10 +3306,10 @@ project_on_surface(const Point_3& p, // Get plane Point_3 reference_point(CGAL::ORIGIN); Plane_3 plane = get_least_square_surface_plane(v,reference_point, index); - + if ( reference_point == CGAL::ORIGIN ) return p; - + // Project if ( p != v->point() ) return project_on_surface_aux(p, @@ -2521,19 +3321,19 @@ project_on_surface(const Point_3& p, plane.orthogonal_vector()); } - - + + template -template +template typename C3T3_helpers::FT C3T3_helpers:: min_incident_value(const Vertex_handle& vh, const SliverCriterion& criterion) const { - Cell_vector incident_cells; - tr_.finite_incident_cells(vh,std::back_inserter(incident_cells)); - - return min_sliver_in_c3t3_value(incident_cells, criterion); + Cell_vector incident_cells_; + tr_.finite_incident_cells(vh,std::back_inserter(incident_cells_)); + + return min_sliver_in_c3t3_value(incident_cells_, criterion); } template @@ -2542,7 +3342,7 @@ struct Filter { mutable OutputIterator out; const Fct& fct; - Filter(OutputIterator out, const Fct& fct) + Filter(OutputIterator out, const Fct& fct) : out(out), fct(fct) {} @@ -2554,14 +3354,14 @@ struct Filter { } }; - + template struct Counter { const Fct& fct; std::size_t& count; - Counter(const Fct& fct, std::size_t& count) + Counter(const Fct& fct, std::size_t& count) : fct(fct), count(count) {} @@ -2574,6 +3374,110 @@ struct Counter { }; +template +template +void +C3T3_helpers:: +get_incident_slivers_without_using_tds_data(const Vertex_handle& v, + const SliverCriterion& criterion, + const FT& sliver_bound, + Cell_vector &slivers) const +{ + Is_sliver i_s(c3t3_, criterion, sliver_bound); + tr_.incident_cells_threadsafe(v, std::back_inserter(slivers), i_s); +} + +// CJTODO: call tr_.try_lock_and_get_incident_cells instead? +template +bool +C3T3_helpers:: +try_lock_and_get_incident_cells(const Vertex_handle& v, + Cell_vector &cells) const +{ + // We need to lock v individually first, to be sure v->cell() is valid + if (!try_lock_vertex(v)) + return false; + + Cell_handle d = v->cell(); + if (!try_lock_element(d)) // LOCK + { + unlock_all_elements(); + return false; + } + cells.push_back(d); + d->tds_data().mark_in_conflict(); + int head=0; + int tail=1; + do { + Cell_handle c = cells[head]; + + for (int i=0; i<4; ++i) { + if (c->vertex(i) == v) + continue; + Cell_handle next = c->neighbor(i); + + if (!try_lock_element(next)) // LOCK + { + BOOST_FOREACH(Cell_handle& ch, + std::make_pair(cells.begin(), cells.end())) + { + ch->tds_data().clear(); + } + cells.clear(); + unlock_all_elements(); + return false; + } + if (! next->tds_data().is_clear()) + continue; + cells.push_back(next); + ++tail; + next->tds_data().mark_in_conflict(); + } + ++head; + } while(head != tail); + BOOST_FOREACH(Cell_handle& ch, std::make_pair(cells.begin(), cells.end())) + { + ch->tds_data().clear(); + } + return true; +} + +template +template +bool +C3T3_helpers:: +try_lock_and_get_incident_cells(const Vertex_handle& v, + Cell_vector &cells, + const Filter &filter) const +{ + std::vector tmp_cells; + tmp_cells.reserve(64); + bool ret = try_lock_and_get_incident_cells(v, tmp_cells); + if (ret) + { + BOOST_FOREACH(Cell_handle& ch, + std::make_pair(tmp_cells.begin(), tmp_cells.end())) + { + if (filter(ch)) + cells.push_back(ch); + } + } + return ret; +} + +template +template +bool +C3T3_helpers:: +try_lock_and_get_incident_slivers(const Vertex_handle& v, + const SliverCriterion& criterion, + const FT& sliver_bound, + Cell_vector &slivers) const +{ + Is_sliver i_s(c3t3_, criterion, sliver_bound); + return try_lock_and_get_incident_cells(v, slivers, i_s); +} + template template @@ -2585,15 +3489,15 @@ incident_slivers(const Vertex_handle& v, OutputIterator out) const { typedef SliverCriterion Sc; - - std::vector incident_cells; - tr_.incident_cells(v, std::back_inserter(incident_cells)); - - std::remove_copy_if(incident_cells.begin(), - incident_cells.end(), + + std::vector incident_cells_; + tr_.incident_cells(v, std::back_inserter(incident_cells_)); + + std::remove_copy_if(incident_cells_.begin(), + incident_cells_.end(), out, std::not1(Is_sliver(c3t3_,criterion,sliver_bound))); - + return out; } @@ -2608,7 +3512,7 @@ new_incident_slivers(const Vertex_handle& v, { typedef SliverCriterion Sc; typedef Filter > F; - + Is_sliver i_s(c3t3_, criterion, sliver_bound); F f(out, i_s); tr_.incident_cells(v,boost::make_function_output_iterator(f)); @@ -2647,7 +3551,7 @@ number_of_incident_slivers(const Vertex_handle& v, return count; } - + template template typename C3T3_helpers::FT @@ -2657,31 +3561,31 @@ min_sliver_value(const Cell_vector& cells, const bool use_cache) const { using boost::make_transform_iterator; - + if ( cells.empty() ) return criterion.get_max_value(); - + if ( ! use_cache ) - { + { reset_sliver_cache(cells.begin(),cells.end()); } - + // Return min dihedral angle //Sliver_criterion_value sc_value(tr_,criterion); // //return *(std::min_element(make_transform_iterator(cells.begin(),sc_value), // make_transform_iterator(cells.end(),sc_value))); FT min_value = criterion.get_max_value(); - for(typename Cell_vector::const_iterator it = cells.begin(); - it != cells.end(); + for(typename Cell_vector::const_iterator it = cells.begin(); + it != cells.end(); ++it) { min_value = (std::min)(criterion(*it), min_value); - } + } return min_value; } - - + + template template void @@ -2694,12 +3598,12 @@ fill_modified_vertices(InputIterator cells_begin, std::set already_inserted_vertices; // Dont insert vertex in out already_inserted_vertices.insert(vertex); - + for ( InputIterator it = cells_begin ; it != cells_end ; ++it ) { for ( int i=0 ; i<4 ; ++i ) { - // Insert vertices if not already inserted + // Insert vertices if not already inserted const Vertex_handle& current_vertex = (*it)->vertex(i); if ( !tr_.is_infinite(current_vertex) && already_inserted_vertices.insert(current_vertex).second ) @@ -2709,8 +3613,8 @@ fill_modified_vertices(InputIterator cells_begin, } } } - - + + template template void @@ -2742,7 +3646,7 @@ restore_from_cells_backup(const CellsVector& cells, if(tr_.is_infinite(*cit)) continue;//don't restore infinite cells, they have not been backed-up - typename CellDataSet::const_iterator cd_it + typename CellDataSet::const_iterator cd_it = cells_backup.find(Cell_data_backup(*cit, false/*don't backup*/)); if(cd_it != cells_backup.end()) { @@ -2761,7 +3665,7 @@ OutputIterator C3T3_helpers:: get_conflict_zone_no_topo_change(const Vertex_handle& vertex, OutputIterator conflict_cells) const -{ +{ return tr_.incident_cells(vertex,conflict_cells); } @@ -2774,27 +3678,35 @@ get_conflict_zone_topo_change(const Vertex_handle& v, const Point_3& conflict_point, CellsOutputIterator insertion_conflict_cells, FacetsOutputIterator insertion_conflict_boundary, - CellsOutputIterator removal_conflict_cells) const + CellsOutputIterator removal_conflict_cells, + bool *could_lock_zone) const { // Get triangulation_vertex incident cells : removal conflict zone + // TODO: hasn't it already been computed in "perturb_vertex" (when getting the slivers)? + // We don't try to lock the incident cells since they've already been locked tr_.incident_cells(v, removal_conflict_cells); - // Get conflict_point conflict zone + // Get conflict_point conflict zone int li=0; int lj=0; typename Tr::Locate_type lt; - Cell_handle cell = tr_.locate(conflict_point, lt, li, lj, v->cell()); - - if ( lt == Tr::VERTEX ) // Vertex removal is forbidden + Cell_handle cell = tr_.locate( + conflict_point, lt, li, lj, v->cell(), could_lock_zone); + + if (could_lock_zone && *could_lock_zone == false) return; - + + if ( lt == Tr::VERTEX ) // Vertex removal is forbidden + return; + // Find conflict zone tr_.find_conflicts(conflict_point, cell, insertion_conflict_boundary, - insertion_conflict_cells); + insertion_conflict_cells, + could_lock_zone); } - + template template OutputIterator @@ -2804,15 +3716,15 @@ get_conflict_zone_topo_change(const Vertex_handle& vertex, OutputIterator conflict_cells) const { // Get triangulation_vertex incident cells - Cell_vector incident_cells; - incident_cells.reserve(64); - tr_.incident_cells(vertex, std::back_inserter(incident_cells)); - + Cell_vector incident_cells_; + incident_cells_.reserve(64); + tr_.incident_cells(vertex, std::back_inserter(incident_cells_)); + // Get conflict_point conflict zone Cell_vector deleted_cells; deleted_cells.reserve(64); - - // Vertex removal is forbidden + + // Vertex removal is forbidden int li=0; int lj=0; typename Tr::Locate_type locate_type; @@ -2821,30 +3733,30 @@ get_conflict_zone_topo_change(const Vertex_handle& vertex, li, lj, vertex->cell()); - + if ( Tr::VERTEX == locate_type ) return conflict_cells; - + // Find conflict zone tr_.find_conflicts(conflict_point, cell, CGAL::Emptyset_iterator(), std::back_inserter(deleted_cells), CGAL::Emptyset_iterator()); - + // Compute union of conflict_point conflict zone and triangulation_vertex // incident cells std::sort(deleted_cells.begin(),deleted_cells.end()); - std::sort(incident_cells.begin(),incident_cells.end()); - + std::sort(incident_cells_.begin(),incident_cells_.end()); + std::set_union(deleted_cells.begin(), deleted_cells.end(), - incident_cells.begin(), incident_cells.end(), + incident_cells_.begin(), incident_cells_.end(), conflict_cells); - + return conflict_cells; } - - + + template typename C3T3_helpers::Facet_boundary C3T3_helpers:: @@ -2866,7 +3778,7 @@ get_surface_boundary(const Vertex_handle& moving_vertex, incident_surface_vertices.insert(v1); incident_surface_vertices.insert(v2); incident_surface_vertices.insert(v3); - + // Check that each vertex is a surface one // This is a trick to ensure that in_domain vertices stay inside if ( c3t3_.in_dimension(v1) > 2 @@ -2877,12 +3789,12 @@ get_surface_boundary(const Vertex_handle& moving_vertex, return boundary; // return an empty boundary, that cannot be equal // to a real boundary } - + order_handles(v1,v2,v3); - + CGAL_assertion(v1 bool C3T3_helpers:: @@ -2916,7 +3828,7 @@ check_no_inside_vertices(const Facet_vector& facets) const const Vertex_handle& v1 = fit->first->vertex((k+1)&3); const Vertex_handle& v2 = fit->first->vertex((k+2)&3); const Vertex_handle& v3 = fit->first->vertex((k+3)&3); - + // Check that each vertex is a surface one if ( c3t3_.in_dimension(v1) > 2 || c3t3_.in_dimension(v2) > 2 @@ -2926,7 +3838,7 @@ check_no_inside_vertices(const Facet_vector& facets) const } } } - + return true; } diff --git a/Mesh_3/include/CGAL/Mesh_3/Concurrent_mesher_config.h b/Mesh_3/include/CGAL/Mesh_3/Concurrent_mesher_config.h new file mode 100644 index 00000000000..b367bffe987 --- /dev/null +++ b/Mesh_3/include/CGAL/Mesh_3/Concurrent_mesher_config.h @@ -0,0 +1,177 @@ +// Copyright (c) 2012 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s) : Clement Jamin +// +//****************************************************************************** +// File Description : +//****************************************************************************** + +#ifndef CGAL_MESH_3_CONCURRENT_MESHER_CONFIG_H +#define CGAL_MESH_3_CONCURRENT_MESHER_CONFIG_H + +#ifdef CGAL_USE_BOOST_PROGRAM_OPTIONS +# include + namespace po = boost::program_options; +#endif + +#include +#include + +// class Concurrent_mesher_config +/// Singleton containing config +class Concurrent_mesher_config +{ + // Private constructor (singleton) + Concurrent_mesher_config() + : m_config_file_loaded(false), + locking_grid_num_cells_per_axis(50), + first_grid_lock_radius(0), + work_stats_grid_num_cells_per_axis(5), + num_work_items_per_batch(50), + refinement_grainsize(10), + refinement_batch_size(10000), + min_num_vertices_of_coarse_mesh(100), + num_vertices_of_coarse_mesh_per_core(3.5f), + num_pseudo_infinite_vertices_per_core(5.0f) + {} + +public: + static Concurrent_mesher_config &get() + { + static Concurrent_mesher_config singleton; + return singleton; + } + + static bool load_config_file(const char *filename, + bool reload_if_already_loaded = false) + { + return get().load_file(filename, reload_if_already_loaded); + } + + + //=============== PUBLIC PARAMETERS ============== + + // From config file (or default) + int locking_grid_num_cells_per_axis; + int first_grid_lock_radius; + int work_stats_grid_num_cells_per_axis; + int num_work_items_per_batch; + int refinement_grainsize; + int refinement_batch_size; + int min_num_vertices_of_coarse_mesh; + float num_vertices_of_coarse_mesh_per_core; + float num_pseudo_infinite_vertices_per_core; + + // Others + + + //================================================ + +protected: + + bool load_file( + const char *filename, + bool reload_if_already_loaded = false) + { +#ifdef CGAL_USE_BOOST_PROGRAM_OPTIONS + if (m_config_file_loaded && reload_if_already_loaded == false) + return true; + + try + { + std::ifstream in(filename); + if (in.fail()) + { + std::string err = "could not open file '"; + err += filename; + err += "'. Using default values."; + throw std::runtime_error(err); + } + + // Declare the supported options. + po::options_description desc("Allowed options"); + desc.add_options() + ("locking_grid_num_cells_per_axis", po::value(), "") + ("first_grid_lock_radius", po::value(), "") + ("work_stats_grid_num_cells_per_axis", po::value(), "") + ("num_work_items_per_batch", po::value(), "") + ("refinement_grainsize", po::value(), "") + ("refinement_batch_size", po::value(), "") + ("min_num_vertices_of_coarse_mesh", po::value(), "") + ("num_vertices_of_coarse_mesh_per_core", po::value(), "") + ("num_pseudo_infinite_vertices_per_core", po::value(), ""); + + + po::store(po::parse_config_file(in, desc), m_variables_map); + po::notify(m_variables_map); + } + catch (std::exception &e) + { + std::cerr << "Concurrency configuration file error: " + << e.what() << std::endl; + return false; + } + + locking_grid_num_cells_per_axis = + get_config_file_option_value("locking_grid_num_cells_per_axis"); + first_grid_lock_radius = + get_config_file_option_value("first_grid_lock_radius"); + work_stats_grid_num_cells_per_axis = + get_config_file_option_value("work_stats_grid_num_cells_per_axis"); + num_work_items_per_batch = + get_config_file_option_value("num_work_items_per_batch"); + refinement_grainsize = + get_config_file_option_value("refinement_grainsize"); + refinement_batch_size = + get_config_file_option_value("refinement_batch_size"); + min_num_vertices_of_coarse_mesh = + get_config_file_option_value("min_num_vertices_of_coarse_mesh"); + num_vertices_of_coarse_mesh_per_core = + get_config_file_option_value("num_vertices_of_coarse_mesh_per_core"); + num_pseudo_infinite_vertices_per_core = + get_config_file_option_value("num_pseudo_infinite_vertices_per_core"); + + m_config_file_loaded = true; + +#else // CGAL_USE_BOOST_PROGRAM_OPTIONS not defined + std::cerr << "Warning: could not load concurrency configuration file '" + << filename << "'. Default values will be used." + << std::endl; +#endif // CGAL_USE_BOOST_PROGRAM_OPTIONS + return true; + } + +#ifdef CGAL_USE_BOOST_PROGRAM_OPTIONS + template + OptionType get_config_file_option_value(const char *option_name) + { + if (m_variables_map.count(option_name)) + return m_variables_map[option_name].as(); + else + return OptionType(); + } +#endif + +#ifdef CGAL_USE_BOOST_PROGRAM_OPTIONS + po::variables_map m_variables_map; +#endif + bool m_config_file_loaded; +}; + +#endif // CGAL_MESH_3_CONCURRENT_MESHER_CONFIG_H diff --git a/Mesh_3/include/CGAL/Mesh_3/Lloyd_move.h b/Mesh_3/include/CGAL/Mesh_3/Lloyd_move.h index 8db9d0536c2..c3614223f66 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Lloyd_move.h +++ b/Mesh_3/include/CGAL/Mesh_3/Lloyd_move.h @@ -86,7 +86,10 @@ public: break; case 1: case 0: + case -1: // Don't move edge or corner vertices + // N.B.: dimension = -1 is possible if we added points on a far sphere + // during initialization return CGAL::NULL_VECTOR; break; default: @@ -99,7 +102,8 @@ public: return CGAL::NULL_VECTOR; } -#ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE +#if defined(CGAL_MESH_3_OPTIMIZER_VERBOSE) \ + || defined (CGAL_MESH_3_EXPORT_PERFORMANCE_DATA) static std::string name() { return std::string("Lloyd"); } #endif diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h index 47a4260e1b0..0614aedfa7c 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h @@ -30,11 +30,16 @@ #include #include #include +#include #include #include #include #include +#ifdef CGAL_LINKED_WITH_TBB + #include +#endif + namespace CGAL { namespace Mesh_3 { @@ -43,10 +48,10 @@ namespace Mesh_3 { * @brief A data-structure to represent and maintain a 3D complex embedded * in a 3D triangulation. */ -template +template class Mesh_complex_3_in_triangulation_3_base { - typedef Mesh_complex_3_in_triangulation_3_base Self; + typedef Mesh_complex_3_in_triangulation_3_base Self; public: // Triangulation types @@ -70,15 +75,21 @@ public: * Builds an empty 3D complex. */ Mesh_complex_3_in_triangulation_3_base() - : number_of_facets_(0) - , tr_() - , number_of_cells_(0) {} - + : tr_() + { + // We don't put it in the initialization list because + // tbb::atomic has no contructors + number_of_facets_ = 0; + number_of_cells_ = 0; + } + /// Copy constructor Mesh_complex_3_in_triangulation_3_base(const Self& rhs) - : number_of_facets_(rhs.number_of_facets_) - , tr_(rhs.tr_) - , number_of_cells_(rhs.number_of_cells_) {} + : tr_(rhs.tr_) + { + number_of_facets_ = rhs.number_of_facets_; + number_of_cells_ = rhs.number_of_cells_; + } /// Destructor ~Mesh_complex_3_in_triangulation_3_base() {} @@ -88,7 +99,7 @@ public: number_of_facets_ = 0; tr_.clear(); } - + /// Assignment operator Self& operator=(Self rhs) { @@ -130,7 +141,7 @@ public: /// Sets surface index of facet(\c cell, \c i) to \c index void set_surface_patch_index(const Cell_handle& cell, const int i, - const Surface_patch_index& index) + const Surface_patch_index& index) const { cell->set_surface_patch_index(i, index); } @@ -188,19 +199,19 @@ public: /// Sets subdomain index of cell \c cell to \c index void set_subdomain_index(const Cell_handle& cell, - const Subdomain_index& index) + const Subdomain_index& index) const { cell->set_subdomain_index(index); } /// Sets index of vertex \c vertex to \c index - void set_index(const Vertex_handle& vertex, const Index& index) + void set_index(const Vertex_handle& vertex, const Index& index) const { vertex->set_index(index); } - + /// Sets dimension of vertex \c vertex to \c dimension - void set_dimension(const Vertex_handle& vertex, int dimension) + void set_dimension(const Vertex_handle& vertex, int dimension) const { vertex->set_dimension(dimension); } @@ -229,7 +240,7 @@ public: /// Returns the index of vertex \c v Index index(const Vertex_handle& v) const { return v->index(); } - + /// Outputs the mesh to medit void output_to_medit(std::ofstream& os, bool rebind = true, @@ -238,6 +249,14 @@ public: // Call global function CGAL::output_to_medit(os,*this,rebind,show_patches); } + + /// Outputs the mesh to medit + void output_to_maya(std::ofstream& os, + bool surfaceOnly = true) const + { + // Call global function + CGAL::output_to_maya(os,*this,surfaceOnly); + } //------------------------------------------------------- // Undocumented features @@ -283,7 +302,7 @@ public: ++first; } } - + /// Swaps this & rhs void swap(Self& rhs) { @@ -291,16 +310,16 @@ public: tr_.swap(rhs.tr_); std::swap(rhs.number_of_cells_, number_of_cells_); } - + /// Returns bbox Bbox_3 bbox() const; - + //------------------------------------------------------- // Traversal //------------------------------------------------------- private: typedef Mesh_3::internal::Iterator_not_in_complex Iterator_not_in_complex; - + class Facet_iterator_not_in_complex { const Self* c3t3_; @@ -311,15 +330,15 @@ private: const Surface_patch_index& index = Surface_patch_index()) : c3t3_(&c3t3) , index_(index) { } - + template bool operator()(Iterator it) const - { + { if ( index_ == Surface_patch_index() ) { return ! c3t3_->is_in_complex(*it); } else { return c3t3_->surface_patch_index(*it) != index_; } } }; - + /** * @class Cell_not_in_complex * @brief A class to filter cells which do not belong to the complex @@ -336,12 +355,12 @@ private: , index_(index) { } bool operator()(Cell_handle ch) const - { + { if ( index_ == Subdomain_index() ) { return !r_self_->is_in_complex(ch); } else { return r_self_->subdomain_index(ch) != index_; } } }; // end class Cell_not_in_complex - + public: /// Iterator type to visit the facets of the 2D complex. typedef Filter_iterator< @@ -355,7 +374,7 @@ public: Facet_iterator_not_in_complex(*this), tr_.finite_facets_begin()); } - + /// Returns a Facets_in_complex_iterator to the first facet of the 2D complex Facets_in_complex_iterator facets_in_complex_begin(const Surface_patch_index& index) const @@ -410,7 +429,7 @@ public: Cell_not_in_complex(*this), tr_.finite_cells_begin()); } - + /// Returns a \c Cells_in_complex_iterator to the first cell of the 3D complex Cells_in_complex_iterator cells_in_complex_begin(const Subdomain_index& index) const @@ -426,7 +445,7 @@ public: return CGAL::filter_iterator(tr_.finite_cells_end(), Cell_not_in_complex(*this)); } - + // ----------------------------------- // Backward Compatibility // ----------------------------------- @@ -435,30 +454,30 @@ public: void set_surface_index(const Facet& f, const Surface_index& index) { set_surface_patch_index(f, index); } - + void set_surface_index(const Cell_handle& c, const int i, const Surface_index& index) { set_surface_patch_index(c,i,index); } - + Surface_index surface_index(const Facet& f) const { return surface_patch_index(f); } - + Surface_index surface_index(const Cell_handle& c, const int i) const { return surface_patch_index(c,i); } #endif // CGAL_MESH_3_NO_DEPRECATED_SURFACE_INDEX - + #ifndef CGAL_MESH_3_NO_DEPRECATED_C3T3_ITERATORS typedef Facets_in_complex_iterator Facet_iterator; typedef Cells_in_complex_iterator Cell_iterator; - + Facet_iterator facets_begin() const { return facets_in_complex_begin(); } - + Facet_iterator facets_end() const { return facets_in_complex_end(); } - + Cell_iterator cells_begin() const { return cells_in_complex_begin(); } - + Cell_iterator cells_end() const { return cells_in_complex_end(); } #endif // CGAL_MESH_3_NO_DEPRECATED_C3T3_ITERATORS @@ -473,11 +492,11 @@ public: { return number_of_cells_in_complex(); } public: - template + template friend - std::istream & - operator>> (std::istream& is, - Mesh_complex_3_in_triangulation_3_base &c3t3); + std::istream & + operator>> (std::istream& is, + Mesh_complex_3_in_triangulation_3_base &c3t3); static std::string io_signature() @@ -486,17 +505,34 @@ public: Get_io_signature()(); } private: - // Private date members - size_type number_of_facets_; - Triangulation tr_; - size_type number_of_cells_; + // Sequential: non-atomic + // "dummy" is here to allow the specialization (see below) + // See http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/285ab1eec49e1cb6 + template + struct Number_of_elements + { + typedef size_type type; + }; +#ifdef CGAL_LINKED_WITH_TBB + // Parallel: atomic + template + struct Number_of_elements + { + typedef tbb::atomic type; + }; +#endif // CGAL_LINKED_WITH_TBB + + // Private date members + Triangulation tr_; + typename Number_of_elements::type number_of_facets_; + typename Number_of_elements::type number_of_cells_; }; // end class Mesh_complex_3_in_triangulation_3_base -template +template void -Mesh_complex_3_in_triangulation_3_base::add_to_complex( +Mesh_complex_3_in_triangulation_3_base::add_to_complex( const Cell_handle& cell, const int i, const Surface_patch_index& index) @@ -513,9 +549,9 @@ Mesh_complex_3_in_triangulation_3_base::add_to_complex( } -template +template void -Mesh_complex_3_in_triangulation_3_base::remove_from_complex(const Facet& facet) +Mesh_complex_3_in_triangulation_3_base::remove_from_complex(const Facet& facet) { if ( is_in_complex(facet) ) { @@ -525,46 +561,46 @@ Mesh_complex_3_in_triangulation_3_base::remove_from_complex(const Facet& fac --number_of_facets_; } } - + // ----------------------------------- // Undocumented // ----------------------------------- -template +template Bbox_3 -Mesh_complex_3_in_triangulation_3_base:: +Mesh_complex_3_in_triangulation_3_base:: bbox() const { if ( 0 == triangulation().number_of_vertices() ) { return Bbox_3(); } - + typename Tr::Finite_vertices_iterator vit = tr_.finite_vertices_begin(); Bbox_3 result = (vit++)->point().bbox(); - + for(typename Tr::Finite_vertices_iterator end = tr_.finite_vertices_end(); vit != end ; ++vit) { result = result + vit->point().bbox(); } - + return result; } -template < class Tr> -std::ostream & -operator<< (std::ostream& os, - const Mesh_complex_3_in_triangulation_3_base &c3t3) +template +std::ostream & +operator<< (std::ostream& os, + const Mesh_complex_3_in_triangulation_3_base &c3t3) { return os << c3t3.triangulation(); } -template < class Tr> -std::istream & -operator>> (std::istream& is, - Mesh_complex_3_in_triangulation_3_base &c3t3) +template +std::istream & +operator>> (std::istream& is, + Mesh_complex_3_in_triangulation_3_base &c3t3) { c3t3.clear(); is >> c3t3.triangulation(); @@ -574,20 +610,20 @@ operator>> (std::istream& is, return is; } - for(typename Tr::Finite_facets_iterator + for(typename Tr::Finite_facets_iterator fit = c3t3.triangulation().finite_facets_begin(), end = c3t3.triangulation().finite_facets_end(); - fit != end; ++fit) + fit != end; ++fit) { if ( c3t3.is_in_complex(*fit) ) { ++c3t3.number_of_facets_; } } - for(typename Tr::Finite_cells_iterator + for(typename Tr::Finite_cells_iterator cit = c3t3.triangulation().finite_cells_begin(), end = c3t3.triangulation().finite_cells_end(); - cit != end; ++cit) + cit != end; ++cit) { if ( c3t3.is_in_complex(cit) ) { ++c3t3.number_of_cells_; diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h index d8c321a8d42..5c4b33af44c 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h @@ -19,7 +19,7 @@ // Author(s) : Stephane Tayeb // //****************************************************************************** -// File Description : +// File Description : //****************************************************************************** #ifndef CGAL_MESH_3_MESH_GLOBAL_OPTIMIZER_H @@ -34,45 +34,213 @@ #include #include #include +#include + +#include + +#ifdef CGAL_MESH_3_PROFILING + #include +#endif #include #include +#include #include #include +#include + +#ifdef CGAL_LINKED_WITH_TBB +# include +# include +# include +#endif namespace CGAL { namespace Mesh_3 { - - + + +/************************************************ +// Class Mesh_global_optimizer_base +// Two versions: sequential / parallel +************************************************/ + +// Sequential +template +class Mesh_global_optimizer_base +{ +protected: + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::FT FT; + typedef typename Tr::Lock_data_structure Lock_data_structure; + + typedef std::vector > Moves_vector; + typedef unsigned int Nb_frozen_points_type ; + + Mesh_global_optimizer_base(const Bbox_3 &, int) + : big_moves_size_(0) {} + + void update_big_moves(const FT& new_sq_move) + { + if (big_moves_.size() < big_moves_size_ ) + big_moves_.insert(new_sq_move); + else + { + FT smallest = *(big_moves_.begin()); + if( new_sq_move > smallest ) + { + big_moves_.erase(big_moves_.begin()); + big_moves_.insert(new_sq_move); + } + } + } + + void clear_big_moves() + { + big_moves_.clear(); + } + + Lock_data_structure *get_lock_data_structure() { return 0; } + void unlock_all_elements() {} + +protected: + std::size_t big_moves_size_; + std::multiset big_moves_; +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template +class Mesh_global_optimizer_base +{ +protected: + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::FT FT; + typedef typename Tr::Lock_data_structure Lock_data_structure; + typedef tbb::concurrent_vector > Moves_vector; + typedef tbb::atomic Nb_frozen_points_type ; + + Mesh_global_optimizer_base(const Bbox_3 &bbox, int num_grid_cells_per_axis) + : big_moves_size_(0) + , m_lock_ds(bbox, num_grid_cells_per_axis) + { + big_moves_current_size_ = 0; + big_moves_smallest_ = std::numeric_limits::max(); + } + + void update_big_moves(const FT& new_sq_move) + { + if (++big_moves_current_size_ <= big_moves_size_ ) + { + tbb::mutex::scoped_lock lock(m_big_moves_mutex); + typename std::multiset::const_iterator it = big_moves_.insert(new_sq_move); + + // New smallest move of all big moves? + if (it == big_moves_.begin()) + big_moves_smallest_ = new_sq_move; + } + else + { + --big_moves_current_size_; + + if( new_sq_move > big_moves_smallest_ ) + { + tbb::mutex::scoped_lock lock(m_big_moves_mutex); + // Test it again since it may have been modified by another + // thread in the meantime + if( new_sq_move > big_moves_smallest_ ) + { + big_moves_.erase(big_moves_.begin()); + typename std::multiset::const_iterator it = big_moves_.insert(new_sq_move); + + // New smallest move of all big moves? + if (it == big_moves_.begin()) + big_moves_smallest_ = new_sq_move; + } + } + } + } + + void clear_big_moves() + { + big_moves_current_size_ = 0; + big_moves_smallest_ = std::numeric_limits::max(); + big_moves_.clear(); + } + + Lock_data_structure *get_lock_data_structure() + { + return &m_lock_ds; + } + + void unlock_all_elements() + { + m_lock_ds.unlock_all_points_locked_by_this_thread(); + } + +public: + +protected: + tbb::atomic big_moves_current_size_; + tbb::atomic big_moves_smallest_; + std::size_t big_moves_size_; + std::multiset big_moves_; + tbb::mutex m_big_moves_mutex; + + /// Lock data structure + Lock_data_structure m_lock_ds; +}; +#endif // CGAL_LINKED_WITH_TBB + + + + +/************************************************ +// Class Mesh_global_optimizer +************************************************/ + template > class Mesh_global_optimizer -{ +: public Mesh_global_optimizer_base +{ // Types + typedef typename C3T3::Concurrency_tag Concurrency_tag; + + typedef Mesh_global_optimizer Self; + typedef Mesh_global_optimizer_base< + typename C3T3::Triangulation, typename C3T3::Concurrency_tag> Base; + + using Base::get_lock_data_structure; + using Base::big_moves_; + using Base::big_moves_size_; + typedef typename C3T3::Triangulation Tr; typedef typename Tr::Geom_traits Gt; - + typedef typename Tr::Point Point_3; typedef typename Tr::Cell_handle Cell_handle; typedef typename Tr::Vertex_handle Vertex_handle; typedef typename Tr::Edge Edge; typedef typename Tr::Vertex Vertex; - + typedef typename Gt::FT FT; typedef typename Gt::Vector_3 Vector_3; - + typedef typename std::vector Cell_vector; typedef typename std::vector Vertex_vector; typedef typename std::set Vertex_set; - typedef std::vector > Moves_vector; - + typedef typename Base::Moves_vector Moves_vector; + typedef typename Base::Nb_frozen_points_type Nb_frozen_points_type; + #ifdef CGAL_INTRUSIVE_LIST typedef Intrusive_list Outdated_cell_set; -#else +#else typedef std::set Outdated_cell_set; #endif //CGAL_INTRUSIVE_LIST @@ -83,9 +251,9 @@ class Mesh_global_optimizer #endif typedef typename MoveFunction::Sizing_field Sizing_field; - + typedef class C3T3_helpers C3T3_helpers; - + // Visitor class // Should define: // - after_compute_moves() @@ -93,7 +261,7 @@ class Mesh_global_optimizer // - after_rebuild_restricted_delaunay() // - end_of_iteration(int iteration_number) typedef Visitor_ Visitor; - + public: /** * Constructor @@ -104,7 +272,7 @@ public: const bool do_freeze, const FT& convergence_ratio, const MoveFunction move_function = MoveFunction()); - + /** * Launch optimization process * @@ -122,25 +290,20 @@ public: /// Time accessors void set_time_limit(double time) { time_limit_ = time; } double time_limit() const { return time_limit_; } - + private: /** * Returns moves for vertices of set \c moving_vertices */ Moves_vector compute_moves(Moving_vertices_set& moving_vertices); - + /** * Returns the move for vertex \c v * warning : this function should be called only on moving vertices * even for frozen vertices, it could return a non-zero vector */ Vector_3 compute_move(const Vertex_handle& v); - - /** - * update big_moves_ vector with new_sq_move value - */ - void update_big_moves(const FT& new_sq_move); - + /** * Updates mesh using moves of \c moves vector. Updates moving_vertices with * the new set of moving vertices after the move. @@ -148,42 +311,223 @@ private: void update_mesh(const Moves_vector& moves, Moving_vertices_set& moving_vertices, Visitor& visitor); - + /** * Fill sizing field using sizes (avg circumradius) contained in tr_ */ void fill_sizing_field(); - + /** * Returns true if convergence is reached */ bool check_convergence() const; - + /** * Returns the average circumradius length of cells incident to \c v */ FT average_circumradius_length(const Vertex_handle& v) const; - + /** * Returns the minimum cicumradius length of cells incident to \c v */ - FT min_circumradius_sq_length(const Vertex_handle& v, const Cell_vector& incident_cells) const; - + FT min_circumradius_sq_length(const Vertex_handle& v, const Cell_vector& incident_cells) const; + /** * Returns the squared circumradius length of cell \c cell */ FT sq_circumradius_length(const Cell_handle& cell, const Vertex_handle& v) const; - + /** * Returns true if time_limit is reached */ bool is_time_limit_reached() const { - return ( (time_limit() > 0) && (running_time_.time() > time_limit()) ); + return ( (time_limit() > 0) && (running_time_.time() > time_limit()) ); } - + private: + +#ifdef CGAL_LINKED_WITH_TBB + // Functor for compute_moves function + template + class Compute_move + { + typedef tbb::concurrent_vector Vertex_conc_vector; + + MGO & m_mgo; + const Sizing_field_ & m_sizing_field; + Moves_vector_ & m_moves; + bool m_do_freeze; + Vertex_conc_vector & m_vertices_not_moving_any_more; + const CTOP3 & m_translate; + + public: + // Constructor + Compute_move(MGO &mgo, + const Sizing_field_ &sizing_field, + Moves_vector_ &moves, + bool do_freeze, + Vertex_conc_vector & vertices_not_moving_any_more, + const CTOP3 & translate) + : m_mgo(mgo), + m_sizing_field(sizing_field), + m_moves(moves), + m_do_freeze(do_freeze), + m_vertices_not_moving_any_more(vertices_not_moving_any_more), + m_translate(translate) + {} + + // Constructor + Compute_move(const Compute_move &cm) + : m_mgo(cm.m_mgo), + m_sizing_field(cm.m_sizing_field), + m_moves(cm.m_moves), + m_do_freeze(cm.m_do_freeze), + m_vertices_not_moving_any_more(cm.m_vertices_not_moving_any_more), + m_translate(cm.m_translate) + {} + + // operator() + void operator()(const Vertex_handle& oldv) const + { + Vector_3 move = m_mgo.compute_move(oldv); + + if ( CGAL::NULL_VECTOR != move ) + { + Point_3 new_position = m_translate(oldv->point(), move); + FT size = (MGO::Sizing_field::is_vertex_update_needed ? + m_sizing_field(new_position, oldv) : 0); + // typedef Triangulation_helpers Th; + //if( !Th().inside_protecting_balls(tr_, oldv, new_position)) + //note : this is not happening for Lloyd and ODT so it's commented + // maybe for a new global optimizer it should be de-commented + m_moves.push_back(cpp11::make_tuple(oldv, new_position, size)); + } + else // CGAL::NULL_VECTOR == move + { + if(m_do_freeze) + { + m_vertices_not_moving_any_more.push_back(oldv); + } + } + + if ( m_mgo.is_time_limit_reached() ) + tbb::task::self().cancel_group_execution(); + } + }; + + // Functor for fill_sizing_field function + template + class Compute_sizing_field_value + { + MGO & m_mgo; + Local_list_ & m_local_lists; + + public: + // Constructor + Compute_sizing_field_value(MGO &mgo, + Local_list_ & local_lists) + : m_mgo(mgo), + m_local_lists(local_lists) + {} + + // Constructor + Compute_sizing_field_value(const Compute_sizing_field_value &csfv) + : m_mgo(csfv.m_mgo), + m_local_lists(csfv.m_local_lists) + {} + + // operator() + void operator()(Vertex& v) const + { + Vertex_handle vh + = Tr_::Triangulation_data_structure::Vertex_range::s_iterator_to(v); + m_local_lists.local().push_back( + std::make_pair(v.point(), m_mgo.average_circumradius_length(vh))); + } + }; + + // Functor for update_mesh function + template + class Move_vertex + { + MGO & m_mgo; + const Helper & m_helper; + const Moves_vector & m_moves; + Moving_vertices_set_ & m_moving_vertices; + Outdated_cell_set_ & m_outdated_cells; + + typedef typename Tr_::Point Point_3; + typedef typename Tr_::Vertex_handle Vertex_handle; + + public: + // Constructor + Move_vertex(MGO &mgo, const Helper &helper, const Moves_vector &moves, + Moving_vertices_set_ &moving_vertices, + Outdated_cell_set_ &outdated_cells) + : m_mgo(mgo), m_helper(helper), m_moves(moves), + m_moving_vertices(moving_vertices), m_outdated_cells(outdated_cells) + {} + + // Constructor + Move_vertex(const Move_vertex &mv) + : m_mgo(mv.m_mgo), m_helper(mv.m_helper), m_moves(mv.m_moves), + m_moving_vertices(mv.m_moving_vertices), + m_outdated_cells(mv.m_outdated_cells) + {} + + // operator() + void operator()( const tbb::blocked_range& r ) const + { + for( size_t i = r.begin() ; i != r.end() ; ++i) + { + const Vertex_handle& v = cpp11::get<0>(m_moves[i]); + const Point_3& new_position = cpp11::get<1>(m_moves[i]); + // Get size at new position + if ( MGO::Sizing_field::is_vertex_update_needed ) + { + //FT size = sizing_field_(new_position,v); + FT size = cpp11::get<2>(m_moves[i]); + + // Move point + bool could_lock_zone; + Vertex_handle new_v = m_helper.move_point( + v, new_position, m_outdated_cells, m_moving_vertices, &could_lock_zone); + while (could_lock_zone == false) + { + new_v = m_helper.move_point( + v, new_position, m_outdated_cells, m_moving_vertices, &could_lock_zone); + } + + // Restore size in meshing_info data + new_v->set_meshing_info(size); + } + else // Move point + { + bool could_lock_zone; + do { + m_helper.move_point( + v, new_position, m_outdated_cells, m_moving_vertices, &could_lock_zone); + } while (!could_lock_zone); + } + + m_mgo.unlock_all_elements(); + + // Stop if time_limit_ is reached, here we can't return without rebuilding + // restricted delaunay + if ( m_mgo.is_time_limit_reached() ) + { + tbb::task::self().cancel_group_execution(); + break; + } + } + } + }; +#endif // CGAL_LINKED_WITH_TBB + // ----------------------------------- // Private data // ----------------------------------- @@ -197,19 +541,16 @@ private: Sizing_field sizing_field_; double time_limit_; CGAL::Timer running_time_; - - std::size_t big_moves_size_; - std::set big_moves_; bool do_freeze_; - mutable unsigned int nb_frozen_points_; + mutable Nb_frozen_points_type nb_frozen_points_; #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE mutable FT sum_moves_; #endif }; - - + + template Mesh_global_optimizer:: Mesh_global_optimizer(C3T3& c3t3, @@ -218,42 +559,45 @@ Mesh_global_optimizer(C3T3& c3t3, const bool do_freeze, const FT& convergence_ratio, const Mf move_function) -: c3t3_(c3t3) +: Base(c3t3.bbox(), + Concurrent_mesher_config::get().locking_grid_num_cells_per_axis) +, c3t3_(c3t3) , tr_(c3t3_.triangulation()) , domain_(domain) , sq_freeze_ratio_(freeze_ratio*freeze_ratio) , convergence_ratio_(convergence_ratio) -, helper_(c3t3_,domain_) +, helper_(c3t3_,domain_, get_lock_data_structure()) , move_function_(move_function) , sizing_field_(c3t3.triangulation()) , time_limit_(-1) , running_time_() -, big_moves_size_(0) -, big_moves_() - , do_freeze_(do_freeze) -, nb_frozen_points_(0) #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE , sum_moves_(0) #endif // CGAL_MESH_3_OPTIMIZER_VERBOSE { + nb_frozen_points_ = 0; // We put it here in case it's an "atomic" + + // If we're multi-thread + tr_.set_lock_data_structure(get_lock_data_structure()); + #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE std::cerr << "Fill sizing field..."; CGAL::Timer timer; timer.start(); #endif - + fill_sizing_field(); - + #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE std::cerr << "done (" << timer.time() << "s)\n"; #endif } - + template Mesh_optimization_return_code Mesh_global_optimizer:: @@ -262,6 +606,10 @@ operator()(int nb_iterations, Visitor visitor) running_time_.reset(); running_time_.start(); +#ifdef CGAL_MESH_3_PROFILING + WallClockTimer t; +#endif + // Fill set containing moving vertices // first, take them all #ifdef CGAL_CONSTRUCT_INTRUSIVE_LIST_RANGE_CONSTRUCTOR @@ -276,15 +624,15 @@ operator()(int nb_iterations, Visitor visitor) std::size_t initial_vertices_nb = moving_vertices.size(); #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE double step_begin = running_time_.time(); - std::cerr << "Running " << Mf::name() << "-smoothing (" + std::cerr << "Running " << Mf::name() << "-smoothing (" << initial_vertices_nb << " vertices)" << std::endl; #endif //CGAL_MESH_3_OPTIMIZER_VERBOSE // Initialize big moves (stores the largest moves) - big_moves_.clear(); - big_moves_size_ = + this->clear_big_moves(); + big_moves_size_ = (std::max)(std::size_t(1), std::size_t(moving_vertices.size()/500)); - + std::size_t nb_vertices_moved = -1; bool convergence_stop = false; @@ -292,7 +640,7 @@ operator()(int nb_iterations, Visitor visitor) int i = -1; while ( ++i < nb_iterations && ! is_time_limit_reached() ) { - if(!do_freeze_) + if(!do_freeze_) nb_frozen_points_ = 0; else nb_vertices_moved = moving_vertices.size(); @@ -303,11 +651,11 @@ operator()(int nb_iterations, Visitor visitor) //Pb with Freeze : sometimes a few vertices continue moving indefinitely //if the nb of moving vertices is < 1% of total nb AND does not decrease - if(do_freeze_ + if(do_freeze_ && nb_vertices_moved < 0.005 * initial_vertices_nb && nb_vertices_moved == moving_vertices.size()) - { - // we should stop because we are + { + // we should stop because we are // probably entering an infinite instable loop convergence_stop = true; break; @@ -316,13 +664,13 @@ operator()(int nb_iterations, Visitor visitor) // Stop if time_limit is reached if ( is_time_limit_reached() ) break; - + // Update mesh with those moves update_mesh(moves, moving_vertices, visitor); visitor.end_of_iteration(i); #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE - std::size_t moving_vertices_size = moving_vertices.size(); + std::size_t moving_vertices_size = moving_vertices.size(); std::cerr << boost::format("\r \r" "end iter.%1%, %2% / %3%, last step:%4$.2fs, step avg:%5$.2fs, avg big moves:%6$.3f ") % (i+1) @@ -340,9 +688,16 @@ operator()(int nb_iterations, Visitor visitor) if(check_convergence()) break; - } + } running_time_.stop(); - + +#ifdef CGAL_MESH_3_PROFILING + double optim_time = t.elapsed(); +# ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA + CGAL_MESH_3_SET_PERFORMANCE_DATA(std::string(Mf::name()) + "_optim_time", optim_time); +# endif +#endif + #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE if ( do_freeze_ && nb_frozen_points_ == initial_vertices_nb ) std::cerr << "All vertices frozen" << std::endl; @@ -354,34 +709,39 @@ operator()(int nb_iterations, Visitor visitor) std::cerr << "Convergence reached" << std::endl; else if( i >= nb_iterations ) std::cerr << "Max iteration number reached" << std::endl; - + std::cerr << "Total optimization time: " << running_time_.time() << "s" << std::endl << std::endl; #endif +#ifdef CGAL_MESH_3_PROFILING + std::cerr << std::endl << "Total optimization 'wall-clock' time: " + << optim_time << "s" << std::endl; +#endif + if ( do_freeze_ && nb_frozen_points_ == initial_vertices_nb ) return ALL_VERTICES_FROZEN; - + else if ( do_freeze_ && convergence_stop ) return CANT_IMPROVE_ANYMORE; - + else if ( is_time_limit_reached() ) return TIME_LIMIT_REACHED; - + else if ( check_convergence() ) return CONVERGENCE_REACHED; - + return MAX_ITERATION_NUMBER_REACHED; } template -void +void Mesh_global_optimizer:: collect_all_vertices(Moving_vertices_set& moving_vertices) { typename Tr::Finite_vertices_iterator vit = tr_.finite_vertices_begin(); for(; vit != tr_.finite_vertices_end(); ++vit ) - moving_vertices.insert(vit); + moving_vertices.insert(vit); } template @@ -395,154 +755,219 @@ compute_moves(Moving_vertices_set& moving_vertices) // Store new position of points which have to move Moves_vector moves; moves.reserve(moving_vertices.size()); - - // reset worst_move list - big_moves_.clear(); - - // Get move for each moving vertex - typename Moving_vertices_set::iterator vit = moving_vertices.begin(); - for ( ; vit != moving_vertices.end() ; ) - { - Vertex_handle oldv = *vit; - Vector_3 move = compute_move(oldv); - ++vit; - - if ( CGAL::NULL_VECTOR != move ) - { - Point_3 new_position = translate(oldv->point(),move); - // typedef Triangulation_helpers Th; - //if( !Th().inside_protecting_balls(tr_, oldv, new_position)) - //note : this is not happening for Lloyd and ODT so it's commented - // maybe for a new global optimizer it should be de-commented - moves.push_back(std::make_pair(oldv,new_position)); - } - else // CGAL::NULL_VECTOR == move - { - if(do_freeze_) - moving_vertices.erase(oldv); - } - // Stop if time_limit_ is reached - if ( is_time_limit_reached() ) - break; - } + // reset worst_move list + this->clear_big_moves(); + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "Computing moves..."; + WallClockTimer t; +#endif + + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { + tbb::concurrent_vector vertices_not_moving_any_more; + + // Get move for each moving vertex + tbb::parallel_do( + moving_vertices.begin(), moving_vertices.end(), + Compute_move( + *this, sizing_field_, moves, do_freeze_, vertices_not_moving_any_more, + translate) + ); + + typename tbb::concurrent_vector::const_iterator it + = vertices_not_moving_any_more.begin(); + typename tbb::concurrent_vector::const_iterator it_end + = vertices_not_moving_any_more.end(); + for ( ; it != it_end ; ++it) + { + moving_vertices.erase(*it); + } + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + // Get move for each moving vertex + typename Moving_vertices_set::iterator vit = moving_vertices.begin(); + for ( ; vit != moving_vertices.end() ; ) + { + Vertex_handle oldv = *vit; + ++vit; + Vector_3 move = compute_move(oldv); + + if ( CGAL::NULL_VECTOR != move ) + { + Point_3 new_position = translate(oldv->point(),move); + FT size = (Sizing_field::is_vertex_update_needed ? + sizing_field_(new_position, oldv) : 0); + moves.push_back(cpp11::make_tuple(oldv,new_position,size)); + } + else // CGAL::NULL_VECTOR == move + { + if(do_freeze_) + moving_vertices.erase(oldv); // TODO: if non-intrusive, + // we can optimize since we have the iterator, + // don't forget to do "vit = mv.erase(vit)" instead ++vit + } + + // Stop if time_limit_ is reached + if ( is_time_limit_reached() ) + break; + } + } + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "done in " << t.elapsed() << " seconds." << std::endl; +#endif return moves; } - - - + + + template typename Mesh_global_optimizer::Vector_3 Mesh_global_optimizer:: compute_move(const Vertex_handle& v) -{ +{ typename Gt::Compute_squared_length_3 sq_length = Gt().compute_squared_length_3_object(); - + typename Gt::Construct_vector_3 vector = Gt().construct_vector_3_object(); - + typename Gt::Construct_translated_point_3 translate = Gt().construct_translated_point_3_object(); Cell_vector incident_cells; incident_cells.reserve(64); - tr_.incident_cells(v, std::back_inserter(incident_cells)); +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { + tr_.incident_cells_threadsafe(v, std::back_inserter(incident_cells)); + } + else +#endif //CGAL_LINKED_WITH_TBB + { + tr_.incident_cells(v, std::back_inserter(incident_cells)); + } // Get move from move function Vector_3 move = move_function_(v, incident_cells, c3t3_, sizing_field_); - + // Project surface vertex if ( c3t3_.in_dimension(v) == 2 ) { Point_3 new_position = translate(v->point(),move); move = vector(v->point(), helper_.project_on_surface(new_position,v)); } - + FT local_sq_size = min_circumradius_sq_length(v, incident_cells); if ( FT(0) == local_sq_size ) return CGAL::NULL_VECTOR; - + FT local_move_sq_ratio = sq_length(move) / local_sq_size; - + // Move point only if displacement is big enough w.r.t local size if ( local_move_sq_ratio < sq_freeze_ratio_ ) { nb_frozen_points_++; return CGAL::NULL_VECTOR; } - + // Update big moves - update_big_moves(local_move_sq_ratio); - + this->update_big_moves(local_move_sq_ratio); + return move; } - - -template -void -Mesh_global_optimizer:: -update_big_moves(const FT& new_sq_move) -{ - if (big_moves_.size() < big_moves_size_ ) - big_moves_.insert(new_sq_move); - else - { - FT smallest = *(big_moves_.begin()); - if( new_sq_move > smallest ) - { - big_moves_.erase(big_moves_.begin()); - big_moves_.insert(new_sq_move); - } - } -} - - + + template void Mesh_global_optimizer:: update_mesh(const Moves_vector& moves, Moving_vertices_set& moving_vertices, Visitor& visitor) -{ +{ // Cells which have to be updated Outdated_cell_set outdated_cells; - - // Apply moves in triangulation - for ( typename Moves_vector::const_iterator it = moves.begin() ; - it != moves.end() ; - ++it ) - { - const Vertex_handle& v = it->first; - const Point_3& new_position = it->second; - // Get size at new position - if ( Sizing_field::is_vertex_update_needed ) - { - FT size = sizing_field_(new_position,v); - - // Move point - Vertex_handle new_v = helper_.move_point(v, new_position, outdated_cells, moving_vertices); - // Restore size in meshing_info data - new_v->set_meshing_info(size); - } - else // Move point - { - helper_.move_point(v, new_position, outdated_cells, moving_vertices); - } - - // Stop if time_limit_ is reached, here we can't return without rebuilding - // restricted delaunay - if ( is_time_limit_reached() ) - break; +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "Moving vertices..."; + WallClockTimer t; +#endif + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { + // Apply moves in triangulation + tbb::parallel_for(tbb::blocked_range(0, moves.size()), + Move_vertex< + Self, C3T3_helpers, Tr, Moves_vector, + Moving_vertices_set, Outdated_cell_set>( + *this, helper_, moves, moving_vertices, outdated_cells) + ); } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + // Apply moves in triangulation + for ( typename Moves_vector::const_iterator it = moves.begin() ; + it != moves.end() ; + ++it ) + { + const Vertex_handle& v = cpp11::get<0>(*it); + const Point_3& new_position = cpp11::get<1>(*it); + // Get size at new position + if ( Sizing_field::is_vertex_update_needed ) + { + //FT size = sizing_field_(new_position,v); + FT size = cpp11::get<2>(*it); + + // Move point + Vertex_handle new_v = helper_.move_point(v, new_position, outdated_cells, moving_vertices); + + // Restore size in meshing_info data + new_v->set_meshing_info(size); + } + else // Move point + { + helper_.move_point(v, new_position, outdated_cells, moving_vertices); + } + + // Stop if time_limit_ is reached, here we can't return without rebuilding + // restricted delaunay + if ( is_time_limit_reached() ) + break; + } + } + + visitor.after_move_points(); - + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "done in " << t.elapsed() << " seconds." << std::endl; +#endif + + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "Updating C3T3 (rebuilding restricted Delaunay)..."; + t.reset(); +#endif + // Update c3t3 #ifdef CGAL_INTRUSIVE_LIST // AF: rebuild_restricted_delaunay does more cell insertion/removal - // which clashes with our inplace list + // which clashes with our inplace list // That's why we hand it in, and call clear() when we no longer need it helper_.rebuild_restricted_delaunay(outdated_cells, moving_vertices); @@ -550,9 +975,14 @@ update_mesh(const Moves_vector& moves, helper_.rebuild_restricted_delaunay(outdated_cells.begin(), outdated_cells.end(), moving_vertices); -#endif - +#endif + visitor.after_rebuild_restricted_delaunay(); + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "Updating C3T3 done in " << t.elapsed() << " seconds." << std::endl; +#endif + } @@ -562,45 +992,69 @@ Mesh_global_optimizer:: fill_sizing_field() { std::map value_map; - - // Fill map with local size - for(typename Tr::Finite_vertices_iterator vit = tr_.finite_vertices_begin(); - vit != tr_.finite_vertices_end(); - ++vit) + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) { - value_map.insert(std::make_pair(vit->point(), - average_circumradius_length(vit))); + typedef tbb::enumerable_thread_specific< + std::vector< std::pair > > Local_list; + Local_list local_lists; + + tbb::parallel_do( + tr_.finite_vertices_begin(), tr_.finite_vertices_end(), + Compute_sizing_field_value(*this, local_lists) + ); + + for(typename Local_list::iterator it_list = local_lists.begin() ; + it_list != local_lists.end() ; + ++it_list ) + { + value_map.insert(it_list->begin(), it_list->end()); + } } - + else +#endif //CGAL_LINKED_WITH_TBB + { + // Fill map with local size + for(typename Tr::Finite_vertices_iterator vit = tr_.finite_vertices_begin(); + vit != tr_.finite_vertices_end(); + ++vit) + { + value_map.insert(std::make_pair(vit->point(), + average_circumradius_length(vit))); + } + } + // fill sizing field sizing_field_.fill(value_map); } - + template bool Mesh_global_optimizer:: check_convergence() const { namespace bl = boost::lambda; - + FT sum(0); - for( typename std::set::const_iterator + for( typename std::multiset::const_iterator it = big_moves_.begin(), end = big_moves_.end() ; it != end ; ++it ) { sum += CGAL::sqrt(*it); } - + FT average_move = sum/big_moves_size_;/*even if set is not full, divide*/ /*by max size so that if only 1 point moves, it goes to 0*/ #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE sum_moves_ = average_move; #endif - + return ( average_move < convergence_ratio_ ); } - - + + template typename Mesh_global_optimizer::FT Mesh_global_optimizer:: @@ -608,11 +1062,21 @@ average_circumradius_length(const Vertex_handle& v) const { Cell_vector incident_cells; incident_cells.reserve(64); - tr_.incident_cells(v, std::back_inserter(incident_cells)); - +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { + tr_.incident_cells_threadsafe(v, std::back_inserter(incident_cells)); + } + else +#endif //CGAL_LINKED_WITH_TBB + { + tr_.incident_cells(v, std::back_inserter(incident_cells)); + } + FT sum_len (0); unsigned int nb = 0; - + for ( typename Cell_vector::iterator cit = incident_cells.begin() ; cit != incident_cells.end() ; ++cit) @@ -623,7 +1087,7 @@ average_circumradius_length(const Vertex_handle& v) const ++nb; } } - + // nb == 0 could happen if there is an isolated point. if ( 0 != nb ) { @@ -649,32 +1113,32 @@ average_circumradius_length(const Vertex_handle& v) const } } - + template typename Mesh_global_optimizer::FT Mesh_global_optimizer:: min_circumradius_sq_length(const Vertex_handle& v, const Cell_vector& incident_cells) const { - // Get first cell sq_circumradius_length + // Get first cell sq_circumradius_length typename Cell_vector::const_iterator cit = incident_cells.begin(); while ( incident_cells.end() != cit && !c3t3_.is_in_complex(*cit) ) { ++cit; } - + // if vertex is isolated ... if ( incident_cells.end() == cit ) return FT(0); - + // Initialize min FT min_sq_len = sq_circumradius_length(*cit++,v); - + // Find the minimum value for ( ; cit != incident_cells.end() ; ++cit ) { if ( !c3t3_.is_in_complex(*cit) ) continue; - + min_sq_len = (std::min)(min_sq_len,sq_circumradius_length(*cit,v)); } - + return min_sq_len; } @@ -686,11 +1150,11 @@ sq_circumradius_length(const Cell_handle& cell, const Vertex_handle& v) const { typename Gt::Compute_squared_distance_3 sq_distance = Gt().compute_squared_distance_3_object(); - + const Point_3 circumcenter = tr_.dual(cell); return ( sq_distance(v->point(), circumcenter) ); } - + } // end namespace Mesh_3 } //namespace CGAL diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_sizing_field.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_sizing_field.h index 3fc92e1b97b..f1b68bd1595 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_sizing_field.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_sizing_field.h @@ -26,16 +26,70 @@ #ifndef CGAL_MESH_3_MESH_SIZING_FIELD_H #define CGAL_MESH_3_MESH_SIZING_FIELD_H +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif + namespace CGAL { namespace Mesh_3 { - + +/** + * @class Mesh_sizing_field_base + */ +// Sequential +template +class Mesh_sizing_field_base +{ +protected: + Cell_handle get_last_cell() const + { + return last_cell_; + } + + void set_last_cell(Cell_handle c) const + { + last_cell_ = c; + } + +private: + /// A cell that is used to accelerate location queries + mutable Cell_handle last_cell_; +}; + +#ifdef CGAL_LINKED_WITH_TBB +/** + * @class Mesh_sizing_field_base specialization + */ +// Parallel +template +class Mesh_sizing_field_base +{ +protected: + Cell_handle get_last_cell() const + { + return last_cell_.local(); + } + + void set_last_cell(Cell_handle c) const + { + last_cell_.local() = c; + } + +private: + /// A cell that is used to accelerate location queries + mutable tbb::enumerable_thread_specific last_cell_; +}; +#endif // CGAL_LINKED_WITH_TBB + /** * @class Mesh_sizing_field */ template class Mesh_sizing_field + : public Mesh_sizing_field_base { // Types typedef typename Tr::Geom_traits Gt; @@ -44,91 +98,88 @@ class Mesh_sizing_field typedef typename Tr::Vertex_handle Vertex_handle; typedef typename Tr::Cell_handle Cell_handle; - + public: - // update vertices of mesh triangulation ? + // update vertices of mesh triangulation ? static const bool is_vertex_update_needed = Need_vertex_update; - + public: /** * Constructor */ Mesh_sizing_field(Tr& tr); - + /** * Fill sizing field, using size associated to point in \c value_map */ void fill(const std::map& value_map); - + /** * Returns size at point \c p. */ FT operator()(const Point_3& p) const - { return this->operator()(p,last_cell_); } - + { return this->operator()(p, this->get_last_cell()); } + /** * Returns size at point \c p, using \c v to accelerate \c p location * in triangulation */ FT operator()(const Point_3& p, const Vertex_handle& v) const { return this->operator()(p,v->cell()); } - + /** * Returns size at point \c p. */ FT operator()(const Point_3& p, const Cell_handle& c) const; - + /** * Returns size at point \c p. Assumes that p is the centroid of c. */ FT operator()(const Point_3& p, const std::pair& c) const; - + private: /** * Returns size at point \c p, by interpolation into tetrahedron. */ FT interpolate_on_cell_vertices(const Point_3& p, const Cell_handle& cell) const; - + /** * Returns size at point \c p, by interpolation into facet (\c cell is assumed * to be an infinite cell). */ FT interpolate_on_facet_vertices(const Point_3& p, const Cell_handle& cell) const; - + private: /// The triangulation Tr& tr_; - /// A cell that is used to accelerate location queries - mutable Cell_handle last_cell_; }; - - - + + + template Mesh_sizing_field:: Mesh_sizing_field(Tr& tr) : tr_(tr) - , last_cell_() { -} - - +} + + template void Mesh_sizing_field:: fill(const std::map& value_map) { typedef typename Tr::Finite_vertices_iterator Fvi; - + for ( Fvi vit = tr_.finite_vertices_begin() ; vit != tr_.finite_vertices_end() ; ++ vit ) { - typename std::map::const_iterator find_result = + typename std::map::const_iterator find_result = value_map.find(vit->point()); - + if ( find_result != value_map.end() ) { vit->set_meshing_info(find_result->second); @@ -139,14 +190,14 @@ fill(const std::map& value_map) vit->set_meshing_info(FT(0)); } } -} +} template typename Mesh_sizing_field::FT Mesh_sizing_field:: -operator()(const Point_3& p, const Cell_handle& c) const -{ -#ifdef CGAL_MESH_3_SIZING_FIELD_INEXACT_LOCATE +operator()(const Point_3& p, const Cell_handle& c) const +{ +#ifdef CGAL_MESH_3_SIZING_FIELD_INEXACT_LOCATE //use the inexact locate (much faster than locate) to get a hint //and then use locate to check whether p is really inside hint // if not, an exact locate will be performed @@ -155,8 +206,8 @@ operator()(const Point_3& p, const Cell_handle& c) const #else const Cell_handle cell = tr_.locate(p,c); #endif - last_cell_ = cell; - + this->set_last_cell(cell); + if ( !tr_.is_infinite(cell) ) return interpolate_on_cell_vertices(p,cell); else @@ -171,17 +222,17 @@ operator()(const Point_3&, const std::pair& c) const { // Assumes that p is the centroid of c const Cell_handle& cell = c.first; - + // Interpolate value using tet vertices values const FT& va = cell->vertex(0)->meshing_info(); const FT& vb = cell->vertex(1)->meshing_info(); const FT& vc = cell->vertex(2)->meshing_info(); const FT& vd = cell->vertex(3)->meshing_info(); - + return ( (va+vb+vc+vd)/4 ); } - + template typename Mesh_sizing_field::FT Mesh_sizing_field:: @@ -189,32 +240,32 @@ interpolate_on_cell_vertices(const Point_3& p, const Cell_handle& cell) const { typename Gt::Compute_volume_3 volume = Gt().compute_volume_3_object(); - + // Interpolate value using tet vertices values const FT& va = cell->vertex(0)->meshing_info(); const FT& vb = cell->vertex(1)->meshing_info(); const FT& vc = cell->vertex(2)->meshing_info(); const FT& vd = cell->vertex(3)->meshing_info(); - + const Point_3& a = cell->vertex(0)->point(); const Point_3& b = cell->vertex(1)->point(); const Point_3& c = cell->vertex(2)->point(); const Point_3& d = cell->vertex(3)->point(); - + const FT abcp = CGAL::abs(volume(a,b,c,p)); const FT abdp = CGAL::abs(volume(a,d,b,p)); const FT acdp = CGAL::abs(volume(a,c,d,p)); const FT bcdp = CGAL::abs(volume(b,d,c,p)); - + // If volume is 0, then compute the average value if ( is_zero(abcp+abdp+acdp+bcdp) ) return (va+vb+vc+vd)/4.; - + return ( (abcp*vd + abdp*vc + acdp*vb + bcdp*va) / (abcp+abdp+acdp+bcdp) ); } - - - + + + template typename Mesh_sizing_field::FT Mesh_sizing_field:: @@ -222,44 +273,44 @@ interpolate_on_facet_vertices(const Point_3& p, const Cell_handle& cell) const { typename Gt::Compute_area_3 area = Gt().compute_area_3_object(); - + // Find infinite vertex and put it in k0 int k0 = 0; int k1 = 1; int k2 = 2; int k3 = 3; - + if ( tr_.is_infinite(cell->vertex(1)) ) std::swap(k0,k1); if ( tr_.is_infinite(cell->vertex(2)) ) std::swap(k0,k2); if ( tr_.is_infinite(cell->vertex(3)) ) std::swap(k0,k3); - + // Interpolate value using tet vertices values const FT& va = cell->vertex(k1)->meshing_info(); const FT& vb = cell->vertex(k2)->meshing_info(); const FT& vc = cell->vertex(k3)->meshing_info(); - + const Point_3& a = cell->vertex(k1)->point(); const Point_3& b = cell->vertex(k2)->point(); const Point_3& c = cell->vertex(k3)->point(); - + const FT abp = area(a,b,p); const FT acp = area(a,c,p); const FT bcp = area(b,c,p); - + CGAL_assertion(abp >= 0); CGAL_assertion(acp >= 0); CGAL_assertion(bcp >= 0); - + // If area is 0, then compute the average value if ( is_zero(abp+acp+bcp) ) return (va+vb+vc)/3.; - + return ( (abp*vc + acp*vb + bcp*va ) / (abp+acp+bcp) ); } - + } // end namespace Mesh_3 diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_surface_cell_base_3.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_surface_cell_base_3.h index 76856e65a1b..0a26379c877 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_surface_cell_base_3.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_surface_cell_base_3.h @@ -31,6 +31,10 @@ #include #include +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif + #ifdef _MSC_VER // Kill warning "C4351: new behavior: elements of array // 'CGAL::Mesh_3::Mesh_surface_cell_base_3::surface_index_table_' @@ -42,78 +46,20 @@ namespace CGAL { namespace Mesh_3 { + +/************************************************ +// Class Mesh_surface_cell_base_3_base +// Two versions: sequential / parallel +************************************************/ -/** - * @class Mesh_surface_cell_base_3 - */ -template > -class Mesh_surface_cell_base_3 -: public Cb +// Sequential +template +class Mesh_surface_cell_base_3_base { public: - // Indices - typedef typename MT::Surface_patch_index Surface_patch_index; - typedef typename MT::Index Index; - - // Triangulation types - typedef typename Cb::Triangulation_data_structure Tds; - typedef typename Tds::Vertex_handle Vertex_handle; - typedef typename Tds::Cell_handle Cell_handle; - typedef typename GT::Point_3 Point; - - // To get correct cell type in TDS - template < class TDS3 > - struct Rebind_TDS - { - typedef typename Cb::template Rebind_TDS::Other Cb3; - typedef Mesh_surface_cell_base_3 Other; - }; - - /// Constructors - Mesh_surface_cell_base_3() - : Cb() - , surface_index_table_() - , surface_center_table_() - , bits_(0) { } - - Mesh_surface_cell_base_3(Vertex_handle v0, Vertex_handle v1, - Vertex_handle v2, Vertex_handle v3) - : Cb (v0, v1, v2, v3) - , surface_index_table_() - , surface_center_table_() - , bits_(0) { } - - Mesh_surface_cell_base_3(Vertex_handle v0, Vertex_handle v1, - Vertex_handle v2, Vertex_handle v3, - Cell_handle n0, Cell_handle n1, - Cell_handle n2, Cell_handle n3) - : Cb (v0, v1, v2, v3, n0, n1, n2, n3) - , surface_index_table_() - , surface_center_table_() - , bits_(0) { } - - - /// Destructor - ~Mesh_surface_cell_base_3() { } - - // Default copy constructor and assignment operator are ok - - /// Set surface index of \c facet to \c index - void set_surface_patch_index(const int facet, const Surface_patch_index& index) - { - CGAL_precondition(facet>=0 && facet<4); - surface_index_table_[facet] = index; - } - - /// Returns surface index of facet \c facet - Surface_patch_index surface_patch_index(const int facet) const - { - CGAL_precondition(facet>=0 && facet<4); - return surface_index_table_[facet]; - } - + Mesh_surface_cell_base_3_base() + : bits_(0) {} + /// Marks \c facet as visited void set_facet_visited (const int facet) { @@ -135,6 +81,131 @@ public: return ( (bits_ & (1 << facet)) != 0 ); } +protected: + /// Stores visited facets (4 first bits) + char bits_; +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template<> +class Mesh_surface_cell_base_3_base +{ +public: + Mesh_surface_cell_base_3_base() + { + bits_ = 0; + } + + /// Marks \c facet as visited + void set_facet_visited (const int facet) + { + CGAL_precondition(facet>=0 && facet<4); + char current_bits = bits_; + while (bits_.compare_and_swap(current_bits | (1 << facet), current_bits) != current_bits) + { + current_bits = bits_; + } + } + + /// Marks \c facet as not visited + void reset_visited (const int facet) + { + CGAL_precondition(facet>=0 && facet<4); + char current_bits = bits_; + while (bits_.compare_and_swap(current_bits & (15 & ~(1 << facet)), current_bits) != current_bits) + { + current_bits = bits_; + } + } + + /// Returns \c true if \c facet is marked as visited + bool is_facet_visited (const int facet) const + { + CGAL_precondition(facet>=0 && facet<4); + return ( (bits_ & (1 << facet)) != 0 ); + } + +protected: + /// Stores visited facets (4 first bits) + tbb::atomic bits_; +}; +#endif // CGAL_LINKED_WITH_TBB + + +/** + * @class Mesh_surface_cell_base_3 + */ +template +class Mesh_surface_cell_base_3 +: public Mesh_surface_cell_base_3_base< + typename Cb::Triangulation_data_structure::Concurrency_tag> +, public Cb +{ +public: + // Indices + typedef typename MT::Surface_patch_index Surface_patch_index; + typedef typename MT::Index Index; + + // Triangulation types + typedef typename Cb::Triangulation_data_structure Tds; + typedef typename Tds::Vertex_handle Vertex_handle; + typedef typename Tds::Cell_handle Cell_handle; + typedef typename GT::Point_3 Point; + + // To get correct cell type in TDS + template < class TDS3 > + struct Rebind_TDS + { + typedef typename Cb::template Rebind_TDS::Other Cb3; + typedef Mesh_surface_cell_base_3 Other; + }; + + /// Constructors + Mesh_surface_cell_base_3() + : Cb() + , surface_index_table_() + , surface_center_table_() + { } + + Mesh_surface_cell_base_3(Vertex_handle v0, Vertex_handle v1, + Vertex_handle v2, Vertex_handle v3) + : Cb (v0, v1, v2, v3) + , surface_index_table_() + , surface_center_table_() + { } + + Mesh_surface_cell_base_3(Vertex_handle v0, Vertex_handle v1, + Vertex_handle v2, Vertex_handle v3, + Cell_handle n0, Cell_handle n1, + Cell_handle n2, Cell_handle n3) + : Cb (v0, v1, v2, v3, n0, n1, n2, n3) + , surface_index_table_() + , surface_center_table_() + { } + + + /// Destructor + ~Mesh_surface_cell_base_3() { } + + // Default copy constructor and assignment operator are ok + + /// Set surface index of \c facet to \c index + void set_surface_patch_index(const int facet, const Surface_patch_index& index) + { + CGAL_precondition(facet>=0 && facet<4); + surface_index_table_[facet] = index; + } + + /// Returns surface index of facet \c facet + Surface_patch_index surface_patch_index(const int facet) const + { + CGAL_precondition(facet>=0 && facet<4); + return surface_index_table_[facet]; + } + /// Sets surface center of \c facet to \c point void set_facet_surface_center(const int facet, const Point& point) { @@ -201,8 +272,6 @@ private: Point surface_center_table_[4]; /// Stores surface center index of each facet of the cell Index surface_center_index_table_[4]; - /// Stores visited facets (4 first bits) - char bits_; }; // end class Mesh_surface_cell_base_3 diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesher_3.h b/Mesh_3/include/CGAL/Mesh_3/Mesher_3.h index 30d16aac8b9..d5260fa8f6e 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesher_3.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesher_3.h @@ -35,51 +35,150 @@ #include #include #include +#include #ifdef CGAL_MESH_3_USE_OLD_SURFACE_RESTRICTED_DELAUNAY_UPDATE #include #endif +#include #include +#ifdef CGAL_MESH_3_PROFILING + #include +#endif + +#ifdef CGAL_LINKED_WITH_TBB +# if TBB_IMPLEMENT_CPP0X +# include +# else +# include +# endif +#endif + #include +#include +#include #include namespace CGAL { - namespace Mesh_3 { - - -// Class Mesher_3 -// + +/************************************************ +// Class Mesher_3_base +// Two versions: sequential / parallel +************************************************/ + +// Sequential +template +class Mesher_3_base +{ +protected: + typedef typename Tr::Lock_data_structure Lock_data_structure; + + Mesher_3_base(const Bbox_3 &, int) {} + + Lock_data_structure *get_lock_data_structure() { return 0; } + WorksharingDataStructureType *get_worksharing_data_structure() { return 0; } + void set_bbox(const Bbox_3 &) {} +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template +class Mesher_3_base +{ +protected: + typedef typename Tr::Lock_data_structure Lock_data_structure; + + Mesher_3_base(const Bbox_3 &bbox, int num_grid_cells_per_axis) + : m_lock_ds(bbox, num_grid_cells_per_axis), + m_worksharing_ds(bbox) + {} + + Lock_data_structure *get_lock_data_structure() + { + return &m_lock_ds; + } + WorksharingDataStructureType *get_worksharing_data_structure() + { + return &m_worksharing_ds; + } + + void set_bbox(const Bbox_3 &bbox) + { + m_lock_ds.set_bbox(bbox); + m_worksharing_ds.set_bbox(bbox); + } + + /// Lock data structure + Lock_data_structure m_lock_ds; + /// Worksharing data structure + WorksharingDataStructureType m_worksharing_ds; +}; +#endif // CGAL_LINKED_WITH_TBB + + +/************************************************ + * + * Mesher_3 class + * + ************************************************/ + template class Mesher_3 +: public Mesher_3_base< + typename C3T3::Triangulation, +#ifdef CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT + Sequential_tag +#else + typename C3T3::Concurrency_tag +#endif + > { public: +#ifdef CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT + typedef Sequential_tag Concurrency_tag; +#else + typedef typename C3T3::Concurrency_tag Concurrency_tag; +#endif + typedef typename C3T3::Triangulation Triangulation; + typedef typename Triangulation::Point Point; + typedef typename Kernel_traits::Kernel Kernel; + typedef typename Kernel::Vector_3 Vector; + typedef typename MeshDomain::Index Index; + // Self - typedef Mesher_3 Self; - - typedef typename C3T3::Triangulation Triangulation; - + typedef Mesher_3 Self; +#ifdef CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT + typedef Mesher_3_base Base; +#else + typedef Mesher_3_base Base; +#endif + + using Base::get_lock_data_structure; + //------------------------------------------------------- // Mesher_levels //------------------------------------------------------- /// Facets mesher level - typedef Mesh_3::Refine_facets_3< + typedef Refine_facets_3< Triangulation, typename MeshCriteria::Facet_criteria, MeshDomain, C3T3, - Null_mesher_level> Facets_level; - + Null_mesher_level, + Concurrency_tag> Facets_level; + /// Cells mesher level - typedef Mesh_3::Refine_cells_3< + typedef Refine_cells_3< Triangulation, typename MeshCriteria::Cell_criteria, MeshDomain, C3T3, - Facets_level> Cells_level; - + Facets_level, + Concurrency_tag> Cells_level; + //------------------------------------------------------- // Visitors //------------------------------------------------------- @@ -88,7 +187,7 @@ public: Triangulation, Cells_level, Null_mesh_visitor> Facets_visitor; - + #ifndef CGAL_MESH_3_USE_OLD_SURFACE_RESTRICTED_DELAUNAY_UPDATE /// Cells visitor : it just need to know previous level typedef Null_mesh_visitor_level Cells_visitor; @@ -105,67 +204,74 @@ public: Mesher_3(C3T3& c3t3, const MeshDomain& domain, const MeshCriteria& criteria); - + /// Destructor ~Mesher_3() { } - + /// Launch mesh refinement double refine_mesh(std::string dump_after_refine_surface_prefix = ""); /// Debug std::string debug_info() const; std::string debug_info_header() const; - + // Step-by-step methods void initialize(); void fix_c3t3(); + void display_number_of_bad_elements(); void one_step(); bool is_algorithm_done(); - + #ifdef CGAL_MESH_3_MESHER_STATUS_ACTIVATED struct Mesher_status - { + { std::size_t vertices, facet_queue, cells_queue; - + Mesher_status(std::size_t v, std::size_t f, std::size_t c) : vertices(v), facet_queue(f), cells_queue(c) {} }; - + Mesher_status status() const; #endif - + private: void remove_cells_from_c3t3(); - + private: + /// The oracle + const MeshDomain& r_oracle_; + /// Meshers Null_mesher_level null_mesher_; Facets_level facets_mesher_; Cells_level cells_mesher_; - + /// Visitors Null_mesh_visitor null_visitor_; Facets_visitor facets_visitor_; Cells_visitor cells_visitor_; - + /// The container of the resulting mesh C3T3& r_c3t3_; - + private: // Disabled copy constructor Mesher_3(const Self& src); // Disabled assignment operator Self& operator=(const Self& src); - + }; // end class Mesher_3 - - - + + + template Mesher_3::Mesher_3(C3T3& c3t3, const MD& domain, const MC& criteria) -: null_mesher_() +: Base(c3t3.bbox(), + Concurrent_mesher_config::get().locking_grid_num_cells_per_axis) +, r_oracle_(domain) +, null_mesher_() , facets_mesher_(c3t3.triangulation(), criteria.facet_criteria_object(), domain, @@ -185,6 +291,10 @@ Mesher_3::Mesher_3(C3T3& c3t3, #endif , r_c3t3_(c3t3) { + facets_mesher_.set_lock_ds(this->get_lock_data_structure()); + facets_mesher_.set_worksharing_ds(this->get_worksharing_data_structure()); + cells_mesher_.set_lock_ds(this->get_lock_data_structure()); + cells_mesher_.set_worksharing_ds(this->get_worksharing_data_structure()); } @@ -196,15 +306,42 @@ Mesher_3::refine_mesh(std::string dump_after_refine_surface_prefix) CGAL::Timer timer; timer.start(); double elapsed_time = 0.; - + // First surface mesh could modify c3t3 without notifying cells_mesher // So we have to ensure that no old cell will be left in c3t3 remove_cells_from_c3t3(); - + #ifndef CGAL_MESH_3_VERBOSE // Scan surface and refine it - facets_mesher_.scan_triangulation(); + initialize(); + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "Refining facets..." << std::endl; + WallClockTimer t; +#endif facets_mesher_.refine(facets_visitor_); +#ifdef CGAL_MESH_3_PROFILING + double facet_ref_time = t.elapsed(); + std::cerr << "==== Facet refinement: " << facet_ref_time << " seconds ====" + << std::endl << std::endl; +# ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA + // If it's parallel but the refinement is forced to sequential, we don't + // output the value +# ifndef CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT + CGAL_MESH_3_SET_PERFORMANCE_DATA("Facets_time", facet_ref_time); +# endif +# endif +#endif + +#if defined(CHECK_AND_DISPLAY_THE_NUMBER_OF_BAD_ELEMENTS_IN_THE_END) + std::cerr << std::endl + << "===============================================================" << std::endl + << "=== CHECK_AND_DISPLAY_THE_NUMBER_OF_BAD_ELEMENTS_IN_THE_END ===" << std::endl; + display_number_of_bad_elements(); + std::cerr + << "===============================================================" + << std::endl << std::endl; +#endif // Then activate facet to surface visitor (surface could be // refined again if it is encroached) @@ -214,26 +351,50 @@ Mesher_3::refine_mesh(std::string dump_after_refine_surface_prefix) // Then scan volume and refine it cells_mesher_.scan_triangulation(); +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "Refining cells..." << std::endl; + t.reset(); +#endif cells_mesher_.refine(cells_visitor_); -#else // if defined(CGAL_MESH_3_VERBOSE) +#ifdef CGAL_MESH_3_PROFILING + double cell_ref_time = t.elapsed(); + std::cerr << "==== Cell refinement: " << cell_ref_time << " seconds ====" + << std::endl << std::endl; +# ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA + // If it's parallel but the refinement is forced to sequential, we don't + // output the value +# ifndef CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT + CGAL_MESH_3_SET_PERFORMANCE_DATA("Cells_refin_time", cell_ref_time); +# endif +# endif +#endif + +#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr + << "Vertices: " << r_c3t3_.triangulation().number_of_vertices() << std::endl + << "Facets : " << r_c3t3_.number_of_facets_in_complex() << std::endl + << "Tets : " << r_c3t3_.number_of_cells_in_complex() << std::endl; +#endif + +#else // ifdef CGAL_MESH_3_VERBOSE std::cerr << "Start surface scan..."; - facets_mesher_.scan_triangulation(); + initialize(); std::cerr << "end scan. [Bad facets:" << facets_mesher_.size() << "]"; std::cerr << std::endl << std::endl; elapsed_time += timer.time(); timer.stop(); timer.reset(); timer.start(); - + const Triangulation& r_tr = r_c3t3_.triangulation(); int nbsteps = 0; - + std::cerr << "Refining Surface...\n"; - std::cerr << "Legende of the following line: " + std::cerr << "Legend of the following line: " << "(#vertices,#steps," << cells_mesher_.debug_info_header() << ")\n"; - + std::cerr << "(" << r_tr.number_of_vertices() << "," << nbsteps << "," << cells_mesher_.debug_info() << ")"; - + while ( ! facets_mesher_.is_algorithm_done() ) { facets_mesher_.one_step(facets_visitor_); @@ -252,7 +413,7 @@ Mesher_3::refine_mesh(std::string dump_after_refine_surface_prefix) elapsed_time += timer.time(); timer.stop(); timer.reset(); timer.start(); nbsteps = 0; - + facets_visitor_.activate(); dump_c3t3(r_c3t3_, dump_after_refine_surface_prefix); std::cerr << "Start volume scan..."; @@ -261,9 +422,9 @@ Mesher_3::refine_mesh(std::string dump_after_refine_surface_prefix) std::cerr << std::endl << std::endl; elapsed_time += timer.time(); timer.stop(); timer.reset(); timer.start(); - + std::cerr << "Refining...\n"; - std::cerr << "Legende of the following line: " + std::cerr << "Legend of the following line: " << "(#vertices,#steps," << cells_mesher_.debug_info_header() << ")\n"; std::cerr << "(" << r_tr.number_of_vertices() << "," @@ -286,9 +447,21 @@ Mesher_3::refine_mesh(std::string dump_after_refine_surface_prefix) std::cerr << "Total refining time: " << timer.time()+elapsed_time << "s" << std::endl; std::cerr << std::endl; #endif - + timer.stop(); elapsed_time += timer.time(); + +#if defined(CHECK_AND_DISPLAY_THE_NUMBER_OF_BAD_ELEMENTS_IN_THE_END) \ + || defined(SHOW_REMAINING_BAD_ELEMENT_IN_RED) + std::cerr << std::endl + << "===============================================================" << std::endl + << "=== CHECK_AND_DISPLAY_THE_NUMBER_OF_BAD_ELEMENTS_IN_THE_END ===" << std::endl; + display_number_of_bad_elements(); + std::cerr + << "===============================================================" + << std::endl << std::endl; +#endif + return elapsed_time; } @@ -298,7 +471,138 @@ void Mesher_3:: initialize() { - facets_mesher_.scan_triangulation(); +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "Initializing... "; + WallClockTimer t; +#endif + //===================================== + // Bounding box estimation + //===================================== + typedef std::vector > Points_vector; + Points_vector random_points_on_surface; + r_oracle_.construct_initial_points_object()( + std::back_inserter(random_points_on_surface), 1000); + typename Points_vector::const_iterator + it = random_points_on_surface.begin(), + it_end = random_points_on_surface.end(); + Bbox_3 estimated_bbox = it->first.bbox(); + ++it; + for( ; it != it_end ; ++it) + estimated_bbox = estimated_bbox + it->first.bbox(); + + Base::set_bbox(estimated_bbox); + + //======================================== + // Initialization: parallel or sequential + //======================================== + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { + // we're not multi-thread, yet + r_c3t3_.triangulation().set_lock_data_structure(0); + +# ifndef CGAL_PARALLEL_MESH_3_DO_NOT_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE + + if (r_c3t3_.number_of_facets() == 0) + { + const Bbox_3 &bbox = estimated_bbox; + + // Compute radius for far sphere + const double& xdelta = bbox.xmax()-bbox.xmin(); + const double& ydelta = bbox.ymax()-bbox.ymin(); + const double& zdelta = bbox.zmax()-bbox.zmin(); + const double radius = 1.3 * 0.5 * std::sqrt(xdelta*xdelta + + ydelta*ydelta + + zdelta*zdelta); + const Vector center( + bbox.xmin() + 0.5*xdelta, + bbox.ymin() + 0.5*ydelta, + bbox.zmin() + 0.5*zdelta); +# ifdef CGAL_CONCURRENT_MESH_3_VERBOSE + std::cerr << "Adding points on a far sphere (radius = " << radius <<")..."; +# endif + Random_points_on_sphere_3 random_point(radius); + const int NUM_PSEUDO_INFINITE_VERTICES = static_cast( + boost::thread::hardware_concurrency() + * Concurrent_mesher_config::get().num_pseudo_infinite_vertices_per_core); + for (int i = 0 ; i < NUM_PSEUDO_INFINITE_VERTICES ; ++i, ++random_point) + r_c3t3_.triangulation().insert(*random_point + center); + +# ifdef CGAL_CONCURRENT_MESH_3_VERBOSE + std::cerr << "done." << std::endl; +# endif + } +# endif // CGAL_PARALLEL_MESH_3_DO_NOT_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE + +#ifdef CGAL_MESH_3_PROFILING + double init_time = t.elapsed(); + std::cerr << "done in " << init_time << " seconds." << std::endl; +#endif + + // Scan triangulation + facets_mesher_.scan_triangulation(); + + // From now on, we're multi-thread + r_c3t3_.triangulation().set_lock_data_structure(get_lock_data_structure()); + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { +#ifdef CGAL_SEQUENTIAL_MESH_3_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE + if (r_c3t3_.number_of_facets() == 0) + { + /*std::cerr << "A little bit of refinement... "; + + // Start by a little bit of refinement to get a coarse mesh + // => Good approx of bounding box + const int NUM_VERTICES_OF_COARSE_MESH = 40; + facets_mesher_.refine_sequentially_up_to_N_vertices( + facets_visitor_, NUM_VERTICES_OF_COARSE_MESH); + + std::cerr << "done." << std::endl; + std::cerr + << "Vertices: " << r_c3t3_.triangulation().number_of_vertices() << std::endl + << "Facets : " << r_c3t3_.number_of_facets_in_complex() << std::endl + << "Tets : " << r_c3t3_.number_of_cells_in_complex() << std::endl;*/ + + // Compute radius for far sphere + //const Bbox_3 &bbox = r_c3t3_.bbox(); + const Bbox_3 &bbox = estimated_bbox; + const double& xdelta = bbox.xmax()-bbox.xmin(); + const double& ydelta = bbox.ymax()-bbox.ymin(); + const double& zdelta = bbox.zmax()-bbox.zmin(); + const double radius = 1.3 * 0.5 * std::sqrt(xdelta*xdelta + + ydelta*ydelta + + zdelta*zdelta); + const Vector center( + bbox.xmin() + 0.5*xdelta, + bbox.ymin() + 0.5*ydelta, + bbox.zmin() + 0.5*zdelta); +# ifdef CGAL_MESH_3_VERBOSE + std::cerr << "Adding points on a far sphere (radius = " << radius << ")..."; +# endif + Random_points_on_sphere_3 random_point(radius); + const int NUM_PSEUDO_INFINITE_VERTICES = 12*2; + for (int i = 0 ; i < NUM_PSEUDO_INFINITE_VERTICES ; ++i, ++random_point) + r_c3t3_.triangulation().insert(*random_point + center); +# ifdef CGAL_MESH_3_VERBOSE + std::cerr << "done." << std::endl; +# endif + } +#endif // CGAL_SEQUENTIAL_MESH_3_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE + +#ifdef CGAL_MESH_3_PROFILING + double init_time = t.elapsed(); + std::cerr << "done in " << init_time << " seconds." << std::endl; +#endif + + // Scan triangulation + facets_mesher_.scan_triangulation(); + + } } @@ -309,11 +613,21 @@ fix_c3t3() { if ( ! facets_visitor_.is_active() ) { - cells_mesher_.scan_triangulation(); + cells_mesher_.scan_triangulation(); } } +template +void +Mesher_3:: +display_number_of_bad_elements() +{ + int nf = facets_mesher_.number_of_bad_elements(); + int nc = cells_mesher_.number_of_bad_elements(); + std::cerr << "Bad facets: " << nf << " - Bad cells: " << nc << std::endl; +} + template void Mesher_3:: @@ -322,7 +636,7 @@ one_step() if ( ! facets_visitor_.is_active() ) { facets_mesher_.one_step(facets_visitor_); - + if ( facets_mesher_.is_algorithm_done() ) { facets_visitor_.activate(); @@ -331,10 +645,10 @@ one_step() } else { - cells_mesher_.one_step(cells_visitor_); + cells_mesher_.one_step(cells_visitor_); } } - + template bool Mesher_3:: @@ -353,7 +667,7 @@ status() const return Mesher_status(r_c3t3_.triangulation().number_of_vertices(), facets_mesher_.queue_size(), cells_mesher_.queue_size()); -} +} #endif @@ -362,7 +676,7 @@ void Mesher_3:: remove_cells_from_c3t3() { - for ( typename C3T3::Triangulation::Finite_cells_iterator + for ( typename C3T3::Triangulation::Finite_cells_iterator cit = r_c3t3_.triangulation().finite_cells_begin(), end = r_c3t3_.triangulation().finite_cells_end() ; cit != end ; ++cit ) { @@ -372,22 +686,22 @@ remove_cells_from_c3t3() template inline -std::string +std::string Mesher_3::debug_info() const { return cells_mesher_.debug_info(); } - + template inline -std::string +std::string Mesher_3::debug_info_header() const { return cells_mesher_.debug_info_header(); } } // end namespace Mesh_3 - + } // end namespace CGAL diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesher_level.h b/Mesh_3/include/CGAL/Mesh_3/Mesher_level.h new file mode 100644 index 00000000000..37cb8d5c742 --- /dev/null +++ b/Mesh_3/include/CGAL/Mesh_3/Mesher_level.h @@ -0,0 +1,1220 @@ +// Copyright (c) 2004-2005 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s) : Laurent RINEAU, Clement JAMIN + +#ifndef CGAL_MESH_3_MESHER_LEVEL_H +#define CGAL_MESH_3_MESHER_LEVEL_H + +#include + +#ifdef CGAL_MESH_3_PROFILING + #include +#endif + +#include + +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING +# define CGAL_PROFILE +# include +#endif + +#include + +#ifdef CGAL_LINKED_WITH_TBB +# include +# include +#endif + +#include + +namespace CGAL { namespace Mesh_3 { + +enum Mesher_level_conflict_status { + NO_CONFLICT = 0 + , CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED + , CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED + , THE_FACET_TO_REFINE_IS_NOT_IN_ITS_CONFLICT_ZONE + , ELEMENT_WAS_A_ZOMBIE + , COULD_NOT_LOCK_ZONE + , COULD_NOT_LOCK_ELEMENT +}; + +/************************************************ + * + * Null_mesher_level class + * + ************************************************/ + +struct Null_mesher_level { + + template + void refine(Visitor) {} + + // For sequential version + template + Mesher_level_conflict_status test_point_conflict_from_superior(P, Z) + { + return NO_CONFLICT; + } + // For parallel version + template + Mesher_level_conflict_status test_point_conflict_from_superior(P, Z, MV &) + { + return NO_CONFLICT; + } + + bool is_algorithm_done() const + { + return true; + } + + template + bool try_to_insert_one_point(Visitor) + { + return false; + } + + template + bool one_step(Visitor) + { + return false; + } + + //============================================== + // For parallel version + void add_to_TLS_lists(bool) {} + void splice_local_lists() {} + template + void before_next_element_refinement_in_superior(Mesh_visitor visitor) {} + void before_next_element_refinement() {} + //============================================== + + std::string debug_info_class_name_impl() const + { + return "Null_mesher_level"; + } + + std::string debug_info() const + { + return ""; + } + std::string debug_info_header() const + { + return ""; + } + +}; // end Null_mesher_level + + +/************************************************ + * + * Mesher_level_base class + * + ************************************************/ + +template < + class Tr, /**< The triangulation type. */ + class Derived, /**< Derived class, that implements methods. */ + class Element, /**< Type of elements that this level refines. */ + class Previous, /* = Null_mesher_level, */ + /**< Previous level type, defaults to + \c Null_mesher_level. */ + class Triangulation_traits /** Traits class that defines types for the + triangulation. */ +> +class Mesher_level_base +{ +public: + /** Type of triangulation that is meshed. */ + typedef Tr Triangulation; + /** Type of point that are inserted into the triangulation. */ + typedef typename Triangulation::Point Point; + /** Type of vertex handles that are returns by insertions into the + triangulation. */ + typedef typename Triangulation::Vertex_handle Vertex_handle; + /** Type of lock data structure for concurrency */ + typedef typename Triangulation::Lock_data_structure Lock_data_structure; + /** Type of facet & cell handles */ + typedef typename Triangulation::Cell_handle Cell_handle; + typedef typename Cell_handle::value_type Cell; + typedef typename Triangulation::Facet Facet; + /** Type of the conflict zone for a point that can be inserted. */ + typedef typename Triangulation_traits::Zone Zone; + + typedef Element Element_type; + typedef Previous Previous_level; + +protected: + /** \name Private member functions */ + + /** Curiously recurring template pattern. */ + //@{ + Derived& derived() + { + return static_cast(*this); + } + + const Derived& derived() const + { + return static_cast(*this); + } + //@} + + /// debug info: class name + std::string debug_info_class_name() const + { + return derived().debug_info_class_name_impl(); + } + + std::string debug_info_element(const Element &e) const + { + return derived().debug_info_element_impl(e); + } + + /** \name Private member datas */ + + Previous_level& previous_level; /**< The previous level of the refinement + process. */ + +#ifdef CGAL_MESH_3_PROFILING +protected: + WallClockTimer m_timer; +#endif + +public: + typedef Mesher_level_base Self; + + /** \name CONSTRUCTORS */ + Mesher_level_base(Previous_level& previous) + : previous_level(previous) + { + } + + /** \name FUNCTIONS IMPLEMENTED IN THE CLASS \c Derived */ + + /** Access to the triangulation */ + Triangulation& triangulation() + { + return derived().triangulation_ref_impl(); + } + + /** Access to the triangulation */ + const Triangulation& triangulation() const + { + return derived().triangulation_ref_impl(); + } + + const Previous_level& previous() const + { + return previous_level; + } + + Vertex_handle insert(Point p, Zone& z) + { + return derived().insert_impl(p, z); + } + + void clear_refinement_queue() + { + derived().clear(); // Clear refinement queue + } + + /** Called before the first refinement, to initialized the queue of + elements that should be refined. */ + void scan_triangulation() + { + //derived().clear(); // Clear refinement queue + derived().scan_triangulation_impl(); + +#if defined(CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE)\ + && defined(CGAL_MESH_3_IF_UNSORTED_QUEUE_JUST_SORT_AFTER_SCAN) + std::cerr << "Sorting..."; + derived().sort(); + std::cerr << " done." << std::endl; +#endif + } + + /** For diagnostics. */ + int number_of_bad_elements() + { + return derived().number_of_bad_elements_impl(); + } + + /** Tells if, as regards the elements of type \c Element, the refinement is + done. */ + bool no_longer_element_to_refine() + { + return derived().no_longer_element_to_refine_impl(); + } + + /** It includes zombie elements */ + int number_of_elements_in_queue() + { + return derived().size(); + } + + /** Retrieves the next element that could be refined. */ + Element get_next_element() + { + return derived().get_next_element_impl(); + } + + /** Remove from the list the next element that could be refined. */ + void pop_next_element() + { + derived().pop_next_element_impl(); + } + + Point circumcenter_of_element(const Element& e) + { + return derived().circumcenter_impl(e); + } + + template + void before_next_element_refinement_in_superior(Mesh_visitor visitor) + { + derived().before_next_element_refinement_in_superior_impl(visitor); + } + + template + void before_next_element_refinement(Mesh_visitor visitor) + { + derived().before_next_element_refinement_impl(); + previous_level.before_next_element_refinement_in_superior( + visitor.previous_level()); + } + + /** Gives the point that should be inserted to refine the element \c e */ + Point refinement_point(const Element& e) + { + return derived().refinement_point_impl(e); + } + + /** Actions before testing conflicts for point \c p and element \c e */ + template + void before_conflicts(const Element& e, const Point& p, + Mesh_visitor visitor) + { + visitor.before_conflicts(e, p); + derived().before_conflicts_impl(e, p); + } + + /** Tells if, as regards this level of the refinement process, if the + point conflicts with something, and do what is needed. The return + type is made of two booleans: + - the first one tells if the point can be inserted, + - in case of, the first one is \c false, the second one tells if + the tested element should be reconsidered latter. + */ + Mesher_level_conflict_status private_test_point_conflict(const Point& p, + Zone& zone) + { + return derived().private_test_point_conflict_impl(p, zone); + } + + /** + * Actions before inserting the point \c p in order to refine the + * element \c e. The zone of conflicts is \c zone. + */ + template + void before_insertion(Element& e, const Point& p, Zone& zone, + Mesh_visitor visitor) + { + visitor.before_insertion(e, p, zone); + derived().before_insertion_impl(e, p, zone); + } + + /** Actions after having inserted the point. + * \param vh is the vertex handle of the inserted point, + * \param visitor is the visitor. + */ + template + void after_insertion(Vertex_handle vh, Mesh_visitor visitor) + { + derived().after_insertion_impl(vh); + visitor.after_insertion(vh); + } + + /** Actions after testing conflicts for point \c p and element \c e + * if no point is inserted. */ + template + void after_no_insertion(const Element& e, const Point& p, Zone& zone, + Mesh_visitor visitor) + { + derived().after_no_insertion_impl(e, p, zone); + visitor.after_no_insertion(e, p, zone); + } + + /** \name MESHING PROCESS + * + * The following functions use the functions that are implemented in the + * derived classes. + * + */ + + /** + * Tells it the algorithm is done, regarding elements of type \c Element + * or elements of previous levels. + */ + bool is_algorithm_done() + { +#ifdef CGAL_MESH_3_PROFILING + bool done = ( previous_level.is_algorithm_done() && + no_longer_element_to_refine() ); + /*if (done) + { + std::cerr << "done in " << m_timer.elapsed() << " seconds." << std::endl; + m_timer.reset(); + }*/ + return done; +#else + return ( previous_level.is_algorithm_done() && + no_longer_element_to_refine() ); +#endif + } + + /** + * This function takes one element from the queue, and try to refine + * it. It returns \c true if one point has been inserted. + * @todo Merge with try_to_refine_element(). + */ + template + bool process_one_element(Mesh_visitor visitor) + { + Element e = get_next_element(); + + const Mesher_level_conflict_status result + = derived().try_to_refine_element(e, visitor); + + if(result == CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED) + { + pop_next_element(); + } + + return result == NO_CONFLICT; + } + + void get_valid_vertices_of_element(const Cell_handle &e, Vertex_handle vertices[4]) const + { + for (int i = 0 ; i < 4 ; ++i) + vertices[i] = e->vertex(i); + } + // Among the 4 values, one of them will be Vertex_handle() (~= NULL) + void get_valid_vertices_of_element(const Facet &e, Vertex_handle vertices[4]) const + { + for (int i = 0 ; i < 4 ; ++i) + vertices[i] = (i != e.second ? e.first->vertex(i) : Vertex_handle()); + } + + Cell_handle get_cell_from_element(const Cell_handle &e) const + { + return e; + } + Cell_handle get_cell_from_element(const Facet &e) const + { + return e.first; + } + + /** \name STEP BY STEP FUNCTIONS */ + + /** + * Inserts exactly one point, if possible, and returns \c false if no + * point has been inserted because the algorithm is done. + */ + template + bool try_to_insert_one_point(Mesh_visitor visitor) + { + while(! is_algorithm_done() ) + { + if( previous_level.try_to_insert_one_point(visitor.previous_level()) ) + return true; + if(! no_longer_element_to_refine() ) + if( process_one_element(visitor) ) + return true; + } + return false; + } + +}; // end Mesher_level_base + + +/************************************************ +// Class Mesher_level +// Two versions: sequential / parallel +************************************************/ +// Sequential +template < + class Tr, /**< The triangulation type. */ + class Derived, /**< Derived class, that implements methods. */ + class Element, /**< Type of elements that this level refines. */ + class Previous, /* = Null_mesher_level, */ + /**< Previous level type, defaults to + \c Null_mesher_level. */ + class Triangulation_traits, /** Traits class that defines types for the + triangulation. */ + typename Concurrency_tag> +class Mesher_level + : public Mesher_level_base +{ +public: + + typedef Mesher_level Self; + + typedef Mesher_level_base Base; + + typedef typename Base::Lock_data_structure Lock_data_structure; + typedef typename Base::Zone Zone; + typedef typename Base::Point Point; + typedef typename Base::Vertex_handle Vertex_handle; + using Base::derived; + using Base::is_algorithm_done; + using Base::triangulation; + using Base::insert; + using Base::before_conflicts; + using Base::previous_level; + using Base::no_longer_element_to_refine; + using Base::pop_next_element; + using Base::debug_info_class_name; + using Base::debug_info_element; + + /** \name CONSTRUCTORS */ + + Mesher_level(Previous& previous) + : Base(previous) + { + } + + void add_to_TLS_lists(bool) {} + void splice_local_lists() {} + bool no_longer_local_element_to_refine() {} + Element get_next_local_element() {} + void pop_next_local_element() {} + + Zone conflicts_zone(const Point& p + , Element e + , bool &facet_is_in_its_cz) + { + return derived().conflicts_zone_impl(p, e, facet_is_in_its_cz); + } + + /** Tells if, as regards this level of the refinement process, if the + point conflicts with something, and do what is needed. The return + type is made of two booleans: + - the first one tells if the point can be inserted, + - in case of, the first one is \c false, the second one tells if + the tested element should be reconsidered latter. + This function is called by the superior level, if any. + */ + Mesher_level_conflict_status + test_point_conflict_from_superior(const Point& p, Zone& zone) + { + return derived().test_point_conflict_from_superior_impl(p, zone); + } + + /** Refines elements of this level and previous levels (SEQUENTIAL VERSION). */ + template + void refine(Mesh_visitor visitor) + { + while(! is_algorithm_done() ) + { + previous_level.refine(visitor.previous_level()); + if(! no_longer_element_to_refine() ) + { + this->process_one_element(visitor); + } + } + } + + template + Mesher_level_conflict_status + try_to_refine_element(Element e, Mesh_visitor visitor) + { + const Point& p = this->refinement_point(e); + +#ifdef CGAL_MESH_3_VERY_VERBOSE + std::cerr << "Trying to insert point: " << p << + " inside element " << debug_info_element(e) << std::endl; +#endif + + Mesher_level_conflict_status result; + Zone zone; + + before_conflicts(e, p, visitor); + + bool facet_is_in_its_cz = true; + zone = conflicts_zone(p, e, facet_is_in_its_cz); + if (!facet_is_in_its_cz) + result = THE_FACET_TO_REFINE_IS_NOT_IN_ITS_CONFLICT_ZONE; + else + result = test_point_conflict(p, zone); + +#ifdef CGAL_MESHES_DEBUG_REFINEMENT_POINTS + std::cerr << "(" << p << ") "; + switch( result ) + { + case NO_CONFLICT: + std::cerr << "accepted\n"; + break; + case CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED: + std::cerr << "rejected (temporarily)\n"; + break; + case CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED: + std::cerr << "rejected (permanent)\n"; + break; + case THE_FACET_TO_REFINE_IS_NOT_IN_ITS_CONFLICT_ZONE: + std::cerr << "the facet to refine was not in the conflict zone " + "(switching to exact)\n"; + break; + case ELEMENT_WAS_A_ZOMBIE: + std::cerr << "element was a zombie\n"; + break; + case COULD_NOT_LOCK_ELEMENT: + std::cerr << "could not lock element\n"; + break; + case COULD_NOT_LOCK_ZONE: + std::cerr << "could not lock zone\n"; + break; + } +#endif + + if(result == NO_CONFLICT) + { + this->before_insertion(e, p, zone, visitor); + + Vertex_handle vh = insert(p, zone); + + this->after_insertion(vh, visitor); + } + else + { + this->after_no_insertion(e, p, zone, visitor); + } + + return result; + } + + /** Refines elements of this level and previous levels. + * Stops when algorithm is done + * or when num vertices > approx_max_num_mesh_vertices + */ + template + void + refine_sequentially_up_to_N_vertices(Mesh_visitor visitor, + int approx_max_num_mesh_vertices) + { + int count = 0; + + while(! is_algorithm_done() + && triangulation().number_of_vertices() < approx_max_num_mesh_vertices) + { + previous_level.refine(visitor.previous_level()); + if(! no_longer_element_to_refine() ) + { + process_one_element(visitor); + } + } + } + + /** Return (can_split_the_element, drop_element). */ + Mesher_level_conflict_status + test_point_conflict(const Point& p, Zone& zone) + { + const Mesher_level_conflict_status result = + previous_level.test_point_conflict_from_superior(p, zone); + + if( result != NO_CONFLICT ) + return result; + + return this->private_test_point_conflict(p, zone); + } + + /** + * Applies one step of the algorithm: tries to refine one element of + * previous level or one element of this level. Return \c false iff + * is_algorithm_done()==true . + */ + template + bool one_step(Mesh_visitor visitor) + { + if( ! previous_level.is_algorithm_done() ) + previous_level.one_step(visitor.previous_level()); + else if( ! no_longer_element_to_refine() ) + { + process_one_element(visitor); + } + return ! is_algorithm_done(); + } + + // Useless here + void set_lock_ds(Lock_data_structure *) {} + void set_worksharing_ds(WorksharingDataStructureType *) {} + +protected: +}; + +// Parallel +#ifdef CGAL_LINKED_WITH_TBB +template < + class Tr, /**< The triangulation type. */ + class Derived, /**< Derived class, that implements methods. */ + class Element, /**< Type of elements that this level refines. */ + class Previous, /* = Null_mesher_level, */ + /**< Previous level type, defaults to + \c Null_mesher_level. */ + class Triangulation_traits> /** Traits class that defines types for the + triangulation. */ +class Mesher_level + : public Mesher_level_base +{ +private: + typedef Derived Derived_; + template class Enqueue_element; +public: + + typedef Mesher_level Self; + + typedef Mesher_level_base Base; + + + typedef typename Base::Lock_data_structure Lock_data_structure; + typedef typename Base::Zone Zone; + typedef typename Base::Point Point; + typedef typename Base::Vertex_handle Vertex_handle; + using Base::derived; + using Base::is_algorithm_done; + using Base::triangulation; + using Base::insert; + using Base::before_conflicts; + using Base::before_insertion; + using Base::after_insertion; + using Base::previous_level; + using Base::no_longer_element_to_refine; + using Base::pop_next_element; + using Base::debug_info_class_name; + using Base::debug_info_element; + + /** \name CONSTRUCTORS */ + + Mesher_level(Previous& previous) + : Base(previous), + FIRST_GRID_LOCK_RADIUS( + Concurrent_mesher_config::get().first_grid_lock_radius) + , MESH_3_REFINEMENT_GRAINSIZE( + Concurrent_mesher_config::get().first_grid_lock_radius) + , REFINEMENT_BATCH_SIZE( + Concurrent_mesher_config::get().refinement_batch_size) + , m_lock_ds(0) + , m_worksharing_ds(0) + , m_empty_root_task(0) + { + } + + void add_to_TLS_lists(bool add) + { + derived().add_to_TLS_lists_impl(add); + } + void splice_local_lists() + { + derived().splice_local_lists_impl(); + } + + bool no_longer_local_element_to_refine() + { + return derived().no_longer_local_element_to_refine_impl(); + } + + Element get_next_local_element() + { + return derived().get_next_local_element_impl(); + } + + void pop_next_local_element() + { + derived().pop_next_local_element_impl(); + } + + Zone conflicts_zone(const Point& p + , Element e + , bool &facet_is_in_its_cz + , bool &could_lock_zone) + { + return derived().conflicts_zone_impl(p, e, facet_is_in_its_cz, + could_lock_zone); + } + + template + void treat_local_refinement_queue(Mesh_visitor visitor) + { + // We treat the elements of the local (TLS) refinement queue + while (no_longer_local_element_to_refine() == false) + { + typedef typename Derived::Container::Element Container_element; + Container_element ce = derived().get_next_local_raw_element_impl().second; + + Mesher_level_conflict_status status; + do + { + status = try_lock_and_refine_element(ce, visitor); + } + while (status != NO_CONFLICT + && status != CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED + && status != ELEMENT_WAS_A_ZOMBIE); + + pop_next_local_element(); + } + } + + /** Tells if, as regards this level of the refinement process, if the + point conflicts with something, and do what is needed. The return + type is made of two booleans: + - the first one tells if the point can be inserted, + - in case of, the first one is \c false, the second one tells if + the tested element should be reconsidered latter. + This function is called by the superior level, if any. + */ + template + Mesher_level_conflict_status test_point_conflict_from_superior( + const Point& p, Zone& zone, Mesh_visitor &visitor) + { + return derived().test_point_conflict_from_superior_impl(p, zone, visitor); + } + + /** Refines elements of this level and previous levels (SEQUENTIAL VERSION). */ + template + void refine(Mesh_visitor visitor) + { + while(! is_algorithm_done() ) + { + previous_level.refine(visitor.previous_level()); + if(! no_longer_element_to_refine() ) + { + process_a_batch_of_elements(visitor); + } + } + } + + /** Refines elements of this level and previous levels. + * Stops when algorithm is done + * or when num vertices > approx_max_num_mesh_vertices + */ + template + void + refine_sequentially_up_to_N_vertices(Mesh_visitor visitor, + int approx_max_num_mesh_vertices) + { + + CGAL_assertion_msg(triangulation().get_lock_data_structure() == 0, + "In refine_sequentially_up_to_N_vertices, the triangulation's locking data structure should be NULL"); + + int count = 0; + + while(! is_algorithm_done() + && triangulation().number_of_vertices() < approx_max_num_mesh_vertices) + { + previous_level.refine(visitor.previous_level()); + if(! no_longer_element_to_refine() ) + { + process_one_element(visitor); + } + } + } + + void unlock_all_thread_local_elements() + { + if (m_lock_ds) + { + m_lock_ds->unlock_all_points_locked_by_this_thread(); + } + } + + template + void enqueue_task( + const Container_element &ce, const Quality &quality, Mesh_visitor visitor) + { + CGAL_assertion(m_empty_root_task != 0); + + m_worksharing_ds->enqueue_work( + Enqueue_element( + *this, ce, quality, visitor), + quality, + *m_empty_root_task + // NOTE: if you uncomment this line (Load_based_worksharing_ds), the element may + // be a zombie at this point => thus, it may be "infinite" and cause an assertion error + // in debug mode when computing the circumcenter + //, circumcenter_of_element(derived().extract_element_from_container_value(ce)) + ); + } + + /** + * This function takes N elements from the queue, and try to refine + * it in parallel. + */ + template + void process_a_batch_of_elements(Mesh_visitor visitor) + { + typedef typename Derived::Container::value_type Container_quality_and_element; + typedef typename Derived::Container::Element Container_element; + typedef typename Derived::Container::Quality Container_quality; + +#ifdef CGAL_CONCURRENT_MESH_3_VERBOSE + std::cerr << "Refining elements..."; +#endif + + previous_level.add_to_TLS_lists(true); + add_to_TLS_lists(true); + + m_empty_root_task = new( tbb::task::allocate_root() ) tbb::empty_task; + m_empty_root_task->set_ref_count(1); + + while (!no_longer_element_to_refine()) + { + Container_quality_and_element qe = derived().get_next_raw_element_impl(); + pop_next_element(); + enqueue_task(qe.second, qe.first, visitor); + } + + m_empty_root_task->wait_for_all(); + +#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << " Flushing"; +#endif + bool keep_flushing = true; + while (keep_flushing) + { + m_empty_root_task->set_ref_count(1); + keep_flushing = m_worksharing_ds->flush_work_buffers(*m_empty_root_task); + m_empty_root_task->wait_for_all(); +#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "."; +#endif + } + + tbb::task::destroy(*m_empty_root_task); + m_empty_root_task = 0; + + splice_local_lists(); + //previous_level.splice_local_lists(); // useless + previous_level.add_to_TLS_lists(false); + add_to_TLS_lists(false); + +#ifdef CGAL_CONCURRENT_MESH_3_VERBOSE + std::cerr << " done." << std::endl; +#endif + + } + + template + Mesher_level_conflict_status + try_to_refine_element(Element e, Mesh_visitor visitor) + { + const Point& p = this->refinement_point(e); + +#ifdef CGAL_MESH_3_VERY_VERBOSE + std::cerr << "Trying to insert point: " << p << + " inside element " << debug_info_element(e) << std::endl; +#endif + + before_conflicts(e, p, visitor); + + bool could_lock_zone; + bool facet_is_in_its_cz = true; + Zone zone = conflicts_zone(p, e, facet_is_in_its_cz, could_lock_zone); + Mesher_level_conflict_status result; + if (!could_lock_zone) + result = COULD_NOT_LOCK_ZONE; + else if (!facet_is_in_its_cz) + result = THE_FACET_TO_REFINE_IS_NOT_IN_ITS_CONFLICT_ZONE; + else + result = test_point_conflict(p, zone, visitor); + +#ifdef CGAL_MESHES_DEBUG_REFINEMENT_POINTS + std::cerr << "(" << p << ") "; + switch( result ) + { + case NO_CONFLICT: + std::cerr << "accepted\n"; + break; + case CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED: + std::cerr << "rejected (temporarily)\n"; + break; + case CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED: + std::cerr << "rejected (permanent)\n"; + break; + case THE_FACET_TO_REFINE_IS_NOT_IN_ITS_CONFLICT_ZONE: + std::cerr << "the facet to refine was not in the conflict zone " + "(switching to exact)\n"; + break; + case ELEMENT_WAS_A_ZOMBIE: + std::cerr << "element was a zombie\n"; + break; + case COULD_NOT_LOCK_ELEMENT: + std::cerr << "could not lock element\n"; + break; + case COULD_NOT_LOCK_ZONE: + std::cerr << "could not lock zone\n"; + break; + } +#endif + + if(result == NO_CONFLICT) + { + this->before_insertion(e, p, zone, visitor); + + Vertex_handle vh = insert(p, zone); + + if (vh == Vertex_handle()) + { + this->after_no_insertion(e, p, zone, visitor); + result = COULD_NOT_LOCK_ZONE; + } + else + { + this->after_insertion(vh, visitor); + } + } + else + { + this->after_no_insertion(e, p, zone, visitor); + } + + return result; + } + + template + Mesher_level_conflict_status + try_lock_and_refine_element(const Container_element &ce, Mesh_visitor visitor) + { +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + static Profile_branch_counter_3 bcounter( + std::string("early withdrawals / late withdrawals / successes [") + debug_info_class_name() + "]"); +#endif + + Mesher_level_conflict_status result; + Derived &derivd = derived(); + if( !derivd.is_zombie(ce) ) + { + // Lock the element area on the grid + Element element = derivd.extract_element_from_container_value(ce); + bool locked = derivd.try_lock_element(element, FIRST_GRID_LOCK_RADIUS); + + if( locked ) + { + // Test it again as it may have changed in the meantime + if( !derivd.is_zombie(ce) ) + { + result = try_to_refine_element(element, visitor); + + //lock.release(); + + if (result == CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED + || result == THE_FACET_TO_REFINE_IS_NOT_IN_ITS_CONFLICT_ZONE) + { +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + ++bcounter; // It's not a withdrawal +#endif + } + else if (result == COULD_NOT_LOCK_ZONE) + { +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + bcounter.increment_branch_1(); // THIS is a late withdrawal! +#endif + } + else + { +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + ++bcounter; +#endif + } + } + else + { + result = ELEMENT_WAS_A_ZOMBIE; + } + + // Unlock + unlock_all_thread_local_elements(); + } + // else, we will try it again + else + { +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + bcounter.increment_branch_2(); // THIS is an early withdrawal! +#endif + // Unlock + unlock_all_thread_local_elements(); + + std::this_thread::yield(); + result = COULD_NOT_LOCK_ELEMENT; + } + } + else + { + result = ELEMENT_WAS_A_ZOMBIE; + } + + return result; + } + + /** Return (can_split_the_element, drop_element). */ + template + Mesher_level_conflict_status + test_point_conflict(const Point& p, Zone& zone, Mesh_visitor &visitor) + { + const Mesher_level_conflict_status result = + previous_level.test_point_conflict_from_superior( + p, zone, visitor.previous_level()); + + if( result != NO_CONFLICT ) + return result; + + return this->private_test_point_conflict(p, zone); + } + + /** + * Applies one step of the algorithm: tries to refine one element of + * previous level or one element of this level. Return \c false iff + * is_algorithm_done()==true . + */ + template + bool one_step(Mesh_visitor visitor) + { + if( ! previous_level.is_algorithm_done() ) + previous_level.one_step(visitor.previous_level()); + else if( ! no_longer_element_to_refine() ) + { + process_a_batch_of_elements(visitor); + } + return ! is_algorithm_done(); + } + + void set_lock_ds(Lock_data_structure *p) + { + m_lock_ds = p; + } + + void set_worksharing_ds(WorksharingDataStructureType *p) + { + m_worksharing_ds = p; + } + +protected: + + // Member variables + const int FIRST_GRID_LOCK_RADIUS; + const int MESH_3_REFINEMENT_GRAINSIZE; + const int REFINEMENT_BATCH_SIZE; + Lock_data_structure *m_lock_ds; + WorksharingDataStructureType *m_worksharing_ds; + + tbb::task *m_empty_root_task; + +private: + + // Functor for enqueue_task function + template + class Enqueue_element + { + ML & m_mesher_level; + Container_element m_container_element; + Quality m_quality; + Mesh_visitor m_visitor; + + public: + // Constructor + Enqueue_element(ML &ml, + const Container_element &ce, + const Quality &quality, + Mesh_visitor visitor) + : m_mesher_level(ml), + m_container_element(ce), + m_quality(quality), + m_visitor(visitor) + { + } + + // operator() + void operator()() const + { + typedef typename ML::Derived_::Container::value_type + Container_quality_and_element; + + Mesher_level_conflict_status status; + do + { + status = m_mesher_level.try_lock_and_refine_element(m_container_element, + m_visitor); + } + while (status != NO_CONFLICT + && status != CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED + && status != CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED + && status != ELEMENT_WAS_A_ZOMBIE); + + // Refine the new bad facets + m_mesher_level.before_next_element_refinement(m_visitor); + + // We can now reconsider the element if requested + if (status == CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED) + m_mesher_level.enqueue_task(m_container_element, m_quality, m_visitor); + + // Finally we add the new local bad_elements to the feeder + while (m_mesher_level.no_longer_local_element_to_refine() == false) + { + Container_quality_and_element qe = + m_mesher_level.derived().get_next_local_raw_element_impl(); + m_mesher_level.pop_next_local_element(); + m_mesher_level.enqueue_task(qe.second, qe.first, m_visitor); + } + } + }; + +}; +#endif // CGAL_LINKED_WITH_TBB + +} } // end namespace CGAL::Mesh_3 + +#include +#include + +#endif // CGAL_MESH_3_MESHER_LEVEL_H diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesher_level_default_implementations.h b/Mesh_3/include/CGAL/Mesh_3/Mesher_level_default_implementations.h new file mode 100644 index 00000000000..3ac897160c5 --- /dev/null +++ b/Mesh_3/include/CGAL/Mesh_3/Mesher_level_default_implementations.h @@ -0,0 +1,148 @@ +// Copyright (c) 2005 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s) : Laurent RINEAU, Clement JAMIN + +#ifndef CGAL_MESH_3_MESHER_LEVEL_DEFAULT_IMPLEMENTATIONS_H +#define CGAL_MESH_3_MESHER_LEVEL_DEFAULT_IMPLEMENTATIONS_H + +#include + +namespace CGAL { namespace Mesh_3 { + +/** This class implements the two get_triangulation_ref() functions. + \param Tr The triangulation type */ +template +class Triangulation_ref_impl +{ + Tr& tr; +public: + Triangulation_ref_impl(Tr& t) : tr(t) + { + } + + Tr& triangulation_ref_impl() + { + return tr; + } + const Tr& triangulation_ref_impl() const + { + return tr; + } + +}; // end class Triangulation_ref_impl + +/** This struct implements an empty private_test_point_conflict_impl() + function. */ +struct No_private_test_point_conflict +{ + template + Mesher_level_conflict_status + private_test_point_conflict_impl(const Point&, const Zone&) const + { + return NO_CONFLICT; + } +}; // end No_private_test_point_conflict + +/** This struct implements an empty test_point_conflict_from_superior_impl() + function. */ +struct No_test_point_conflict_from_superior +{ + // For sequential + template + Mesher_level_conflict_status + test_point_conflict_from_superior_impl(const Point&, const Zone&) const + { + return NO_CONFLICT; + } + + // For parallel + template + Mesher_level_conflict_status + test_point_conflict_from_superior_impl(const Point&, const Zone&, + Mesh_visitor &) const + { + return NO_CONFLICT; + } +}; // end No_test_point_conflict_from_superior + +/** This struct implements empty functions: + - private_test_point_conflict_impl() and + - test_point_conflict_from_superior_impl(). +*/ +struct No_test_point_conflict : + public No_private_test_point_conflict, + public No_test_point_conflict_from_superior +{ +}; + +/** This struct implements an empty before_insertion_impl() + function. */ +struct No_before_insertion +{ + template + void before_insertion_impl(const Cell_handle&, const Point&, + Zone& ) + { + } +}; // end No_before_insertion + +/** This struct implements an empty after_insertion_impl() + function. */ +struct No_after_insertion +{ + template + void after_insertion_impl(const Vertex_handle&) + { + } +}; // end No_after_insertion + +/** This struct implements an empty after_insertion_impl() + function. */ +struct No_after_no_insertion +{ + template + void after_no_insertion_impl(const Cell_handle&, const Point&, + const Zone& ) + { + } +}; // end No_after_no_insertion + +/** This struct implements empty functions: + - before_insertion_impl(), + - after_insertion_impl(), + - after_no_insertion_impl() +*/ +struct No_before_after_insertion : + public No_after_insertion, + public No_before_insertion, + public No_after_no_insertion +{ +}; + +/** This struct implements an empty before_conflicts_impl() function. */ +struct No_before_conflicts { + template + void before_conflicts_impl(const Face_handle&, const Point&) + { + } +}; + +} } // end namespace CGAL::Mesh_3 + +#endif // CGAL_MESH_3_MESHER_LEVEL_DEFAULT_IMPLEMENTATIONS_H diff --git a/Mesh_3/include/CGAL/Mesh_3/Odt_move.h b/Mesh_3/include/CGAL/Mesh_3/Odt_move.h index 19ef341c497..46de71ae04e 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Odt_move.h +++ b/Mesh_3/include/CGAL/Mesh_3/Odt_move.h @@ -113,8 +113,8 @@ public: return CGAL::NULL_VECTOR; } - -#ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE +#if defined(CGAL_MESH_3_OPTIMIZER_VERBOSE) \ + || defined (CGAL_MESH_3_EXPORT_PERFORMANCE_DATA) static std::string name() { return std::string("Odt"); } #endif diff --git a/Mesh_3/include/CGAL/Mesh_3/Profiling_tools.h b/Mesh_3/include/CGAL/Mesh_3/Profiling_tools.h new file mode 100644 index 00000000000..eb436c93af3 --- /dev/null +++ b/Mesh_3/include/CGAL/Mesh_3/Profiling_tools.h @@ -0,0 +1,69 @@ +// Copyright (c) 2012 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s) : Clement Jamin +// +//****************************************************************************** +// File Description : +//****************************************************************************** + +#ifndef CGAL_MESH_3_PROFILING_TOOLS_H +#define CGAL_MESH_3_PROFILING_TOOLS_H + +// TBB timers +#ifdef CGAL_LINKED_WITH_TBB + #include + struct WallClockTimer + { + tbb::tick_count t; + WallClockTimer() + { + t = tbb::tick_count::now(); + } + void reset() + { + t = tbb::tick_count::now(); + } + double elapsed() const + { + return (tbb::tick_count::now() - t).seconds(); + } + }; + +#else + #include + + struct WallClockTimer + { + CGAL::Real_timer t; + WallClockTimer() + { + t.start(); + } + void reset() + { + t.reset(); + } + double elapsed() const + { + return t.time(); + } + }; +#endif + +#endif // CGAL_MESH_3_PROFILING_TOOLS_H diff --git a/Mesh_3/include/CGAL/Mesh_3/Refine_cells_3.h b/Mesh_3/include/CGAL/Mesh_3/Refine_cells_3.h index 12cedea4ee1..077c3051642 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Refine_cells_3.h +++ b/Mesh_3/include/CGAL/Mesh_3/Refine_cells_3.h @@ -14,7 +14,6 @@ // // $URL$ // $Id$ -// // // Author(s) : Laurent Rineau, Stéphane Tayeb @@ -24,18 +23,30 @@ #include #include -#include -#include +#include +#include #include +#ifdef CGAL_LINKED_WITH_TBB + #include +#endif + +#include +#include #include +#ifdef CGAL_MESH_3_PROFILING + #include +#endif + #include #include +#include +#include #include namespace CGAL { - + namespace Mesh_3 { // Helper meta-programming functions, to allow backward compatibility. @@ -52,7 +63,7 @@ BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_Is_cell_bad, Is_cell_bad, true) BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_Cell_badness, Cell_badness, false) // template class, used when use_cell_badness = false -template ::value) && Has_Cell_badness::value > struct Get_Is_cell_bad { @@ -67,8 +78,116 @@ struct Get_Is_cell_bad { typedef Type type; }; +// Predicate to know if a cell in a refinement queue is a zombie +template +class Cell_to_refine_is_not_zombie +{ +public: + Cell_to_refine_is_not_zombie() {} + bool operator()(const CC_safe_handle &c) const + { + return !c.is_zombie(); + } +}; +/************************************************ +// Class Refine_cells_3_base +// Two versions: sequential / parallel +************************************************/ + +// Sequential +template +class Refine_cells_3_base +{ +protected: + Refine_cells_3_base() : m_last_vertex_index() {} + + Index get_last_vertex_index() const + { + return m_last_vertex_index; + } + + void set_last_vertex_index(Index i) const + { + m_last_vertex_index = i; + } + +#if defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) \ + || defined(CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE) + CC_safe_handle + from_cell_to_refinement_queue_element(Cell_handle ch) const + { + return make_cc_safe_handle(ch); + } + +public: + template + Cell_handle extract_element_from_container_value(const Container_element &e) const + { + // We get the Cell_handle from the safe handle + return e.cc_iterator(); + } + +#else + Cell_handle + from_cell_to_refinement_queue_element(Cell_handle ch) const + { + return ch; + } + +public: + template + Cell_handle extract_element_from_container_value(const Container_element &e) const + { + return e; + } +#endif + +protected: + /// Stores index of vertex that may be inserted into triangulation + mutable Index m_last_vertex_index; +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template +class Refine_cells_3_base +{ +protected: + Refine_cells_3_base() : m_last_vertex_index(Index()) {} + + Index get_last_vertex_index() const + { + return m_last_vertex_index.local(); + } + + void set_last_vertex_index(Index i) const + { + m_last_vertex_index.local() = i; + } + + CC_safe_handle + from_cell_to_refinement_queue_element(Cell_handle ch) const + { + return make_cc_safe_handle(ch); + } + +public: + template + Cell_handle extract_element_from_container_value(const Container_element &e) const + { + // We get the Cell_handle from the safe handle + return e.cc_iterator(); + } + +protected: + /// Stores index of vertex that may be inserted into triangulation + mutable tbb::enumerable_thread_specific m_last_vertex_index; +}; +#endif // CGAL_LINKED_WITH_TBB + +/************************************************ // Class Refine_cells_3 // // Template parameters should be models of @@ -77,46 +196,141 @@ struct Get_Is_cell_bad { // MeshDomain : MeshTraits_3 // // Implements a Mesher_level for cells +************************************************/ + template > + class Concurrency_tag, +#ifdef CGAL_LINKED_WITH_TBB + class Container_ = typename boost::mpl::if_c // (parallel/sequential?) + < + boost::is_convertible::value, + + // Parallel +# ifdef CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE + Meshes::Filtered_deque_container +# else + Meshes::Filtered_multimap_container +# endif + < + CC_safe_handle, + typename Criteria::Cell_quality, + Cell_to_refine_is_not_zombie, + Concurrency_tag + >, + // Sequential +# ifdef CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE + Meshes::Filtered_deque_container + < + CC_safe_handle, + typename Criteria::Cell_quality, + Cell_to_refine_is_not_zombie, + Concurrency_tag + > +# elif defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) + Meshes::Filtered_multimap_container + < + CC_safe_handle, + typename Criteria::Cell_quality, + Cell_to_refine_is_not_zombie, + Concurrency_tag + > +# else + Meshes::Double_map_container +# endif + >::type // boost::if (parallel/sequential) + +#else // !CGAL_LINKED_WITH_TBB + + // Sequential + class Container_ = +# ifdef CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE + Meshes::Filtered_deque_container + < + CC_safe_handle, + typename Criteria::Cell_quality, + Cell_to_refine_is_not_zombie, + Concurrency_tag + > +# elif defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) + Meshes::Filtered_multimap_container + < + CC_safe_handle, + typename Criteria::Cell_quality, + Cell_to_refine_is_not_zombie, + Concurrency_tag + > +# else + Meshes::Double_map_container +# endif + +#endif // CGAL_LINKED_WITH_TBB +> class Refine_cells_3 - : public Mesher_level, - typename Tr::Cell_handle, - Previous_, - Triangulation_mesher_level_traits_3 > - , public Container_ - , public No_test_point_conflict - , public No_after_no_insertion - , public No_before_conflicts +: public Refine_cells_3_base +, public Mesher_level, + typename Tr::Cell_handle, + Previous_, + Triangulation_mesher_level_traits_3, + Concurrency_tag> +, public Container_ +, public No_test_point_conflict +, public No_after_no_insertion +, public No_before_conflicts { private: // Internal types typedef typename Tr::Facet Facet; + typedef typename Tr::Lock_data_structure Lock_data_structure; typedef typename MeshDomain::Subdomain_index Subdomain_index; typedef typename MeshDomain::Index Index; typedef typename Get_Is_cell_bad::Type Is_cell_bad; - + // Self typedef Refine_cells_3 Self; - -public: + Criteria, + MeshDomain, + Complex3InTriangulation3, + Previous_, + Concurrency_tag, + Container_> Self; + + typedef Refine_cells_3_base Base; + + typedef Mesher_level, + typename Tr::Cell_handle, + Previous_, + Triangulation_mesher_level_traits_3, + Concurrency_tag> Base_ML; + +public: + using Base_ML::add_to_TLS_lists; + using Base_ML::splice_local_lists; + + typedef Container_ Container; // Because we need it in Mesher_level + typedef typename Container::Element Container_element; typedef typename Tr::Point Point; typedef typename Tr::Cell Cell; typedef typename Tr::Cell_handle Cell_handle; @@ -124,44 +338,81 @@ public: typedef typename Criteria::Cell_quality Cell_quality; typedef typename Triangulation_mesher_level_traits_3::Zone Zone; typedef Complex3InTriangulation3 C3T3; - - + + // Constructor + // For sequential Refine_cells_3(Tr& triangulation, const Criteria& criteria, const MeshDomain& oracle, Previous_& previous, - C3T3& c3t3) ; - + C3T3& c3t3); + // For parallel + Refine_cells_3(Tr& triangulation, + const Criteria& criteria, + const MeshDomain& oracle, + Previous_& previous, + C3T3& c3t3, + Lock_data_structure *lock_ds, + WorksharingDataStructureType *worksharing_ds); + // Destructor virtual ~Refine_cells_3() { } - + // Get a reference on triangulation Tr& triangulation_ref_impl() { return r_tr_; } const Tr& triangulation_ref_impl() const { return r_tr_; } - + // Initialization function void scan_triangulation_impl(); - + + int number_of_bad_elements_impl(); + + Point circumcenter_impl(const Cell_handle& cell) const + { + return r_tr_.dual(cell); + } + + template + void before_next_element_refinement_in_superior_impl(Mesh_visitor) + { + } + + void before_next_element_refinement_impl() + { + } + + Cell_handle get_next_element_impl() + { + return this->extract_element_from_container_value(Container_::get_next_element_impl()); + } + // Gets the point to insert from the element to refine Point refinement_point_impl(const Cell_handle& cell) const { - last_vertex_index_ = r_oracle_.index_from_subdomain_index( - cell->subdomain_index()); + this->set_last_vertex_index( + r_oracle_.index_from_subdomain_index(cell->subdomain_index()) ); + // last_vertex_index_ = Index(cell->subdomain_index()); // NB : dual() is optimized when the cell base class has circumcenter() return r_tr_.dual(cell); } - + // Returns the conflicts zone - Zone conflicts_zone_impl(const Point& point, const Cell_handle& cell) const; - + Zone conflicts_zone_impl(const Point& point + , const Cell_handle& cell + , bool &facet_is_in_its_cz) const; + Zone conflicts_zone_impl(const Point& point + , const Cell_handle& cell + , bool &facet_is_in_its_cz + , bool &could_lock_zone) const; + // Job to do before insertion void before_insertion_impl(const Cell_handle&, const Point&, Zone& zone) { before_insertion_handle_cells_in_conflict_zone(zone); } - + // Job to do after insertion void after_insertion_impl(const Vertex_handle& v) #ifndef CGAL_MESH_3_USE_OLD_SURFACE_RESTRICTED_DELAUNAY_UPDATE @@ -172,54 +423,128 @@ public: // Insertion implementation ; returns the inserted vertex Vertex_handle insert_impl(const Point& p, const Zone& zone); - + // Updates cells incident to vertex, and add them to queue if needed void update_star(const Vertex_handle& vertex); - + + // Sequential + void remove_element_from_refinement_queue(Cell_handle c, Sequential_tag) + { + // If sequential AND NOT lazy, remove cell from refinement queue + #if !defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) \ + && !defined(CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE) + this->remove_element(c); + #endif + } + // Parallel: it's always lazy, so do nothing + void remove_element_from_refinement_queue(Cell_handle, Parallel_tag) {} + /// Handle cells contained in \c zone (before their destruction by insertion) void before_insertion_handle_cells_in_conflict_zone(Zone& zone); - + + bool try_lock_element(const Cell_handle &ch, int lock_radius = 0) const + { + return this->triangulation().try_lock_cell(ch, lock_radius); + } + + /// debug info: class name + std::string debug_info_class_name_impl() const + { + return "Refine_cells_3"; + } + std::string debug_info() const { std::stringstream s; s << this->previous().debug_info() << "," << this->size(); return s.str(); } - + std::string debug_info_header() const { std::stringstream s; s << this->previous().debug_info_header() << "," << "#tets to refine"; return s.str(); } + + std::string debug_info_element_impl(const Cell_handle &ch) const + { + std::stringstream sstr; + sstr << "Cell { " << std::endl + << " - " << *ch->vertex(0) << std::endl + << " - " << *ch->vertex(1) << std::endl + << " - " << *ch->vertex(2) << std::endl + << " - " << *ch->vertex(3) << std::endl + << "}" << std::endl; + + return sstr.str(); + } + /// Adds \c cell to the refinement queue if needed + void treat_new_cell(const Cell_handle& cell); + #ifdef CGAL_MESH_3_MESHER_STATUS_ACTIVATED std::size_t queue_size() const { return this->size(); } #endif - + private: - /// Adds \c cell to the refinement queue if needed - void treat_new_cell(const Cell_handle& cell); + +#ifdef CGAL_LINKED_WITH_TBB + // Functor for scan_triangulation_impl function + template + class Scan_cell + { + Refine_cells_ & m_refine_cells; + const std::vector & m_cells; + + public: + // Constructor + Scan_cell(Refine_cells_ & rc, + const std::vector & cells) + : m_refine_cells(rc), m_cells(cells) + {} + + // Constructor + Scan_cell(const Scan_cell &sc) + : m_refine_cells(sc.m_refine_cells), m_cells(sc.m_cells) + {} + + // operator() + void operator()( const tbb::blocked_range& r ) const + { + for( size_t i = r.begin() ; i != r.end() ; ++i) + { + Cell_handle c = m_cells[i]; + if (!m_refine_cells.triangulation().is_infinite(c)) + m_refine_cells.treat_new_cell(c); + } + } + }; +#endif // CGAL_LINKED_WITH_TBB + // ----------------------------------- + // ----------------------------------- + // ----------------------------------- + /// Computes badness and add to queue if needed void compute_badness(const Cell_handle& cell); - + // Updates cells incident to vertex, and add them to queue if needed void update_star_self(const Vertex_handle& vertex); - + /// Set \c cell to domain, with subdomain index \c index void set_cell_in_domain(const Cell_handle& cell, const Subdomain_index& index) { r_c3t3_.add_to_complex(cell, index); } - + /// Removes \c cell from domain void remove_cell_from_domain(const Cell_handle& cell) { r_c3t3_.remove_from_complex(cell); } - + /// Sets index and dimension of vertex \c v void set_vertex_properties(Vertex_handle& v, const Index& index) { @@ -227,12 +552,12 @@ private: // Set dimension of v: v is inside volume by construction, so dimension=3 v->set_dimension(3); } - + /// Get mirror facet Facet mirror_facet(const Facet& f) const { return r_tr_.mirror_facet(f); }; Facet mirror_facet(const Cell_handle& c, const int i) const { return mirror_facet(std::make_pair(c,i)); } - + private: /// The triangulation Tr& r_tr_; @@ -242,35 +567,27 @@ private: const MeshDomain& r_oracle_; /// The mesh result C3T3& r_c3t3_; - - //------------------------------------------------------- - // Cache objects - //------------------------------------------------------- - /// Stores index of vertex that may be inserted into triangulation - mutable Index last_vertex_index_; - + private: // Disabled copy constructor Refine_cells_3(const Self& src); // Disabled assignment operator Self& operator=(const Self& src); - + }; // end class Refine_cells_3 - - - -template -Refine_cells_3:: +// For sequential +template +Refine_cells_3:: Refine_cells_3(Tr& triangulation, const Cr& criteria, const MD& oracle, P_& previous, C3T3& c3t3) : Mesher_level >(previous) + Triangulation_mesher_level_traits_3, Ct >(previous) , C_() , No_test_point_conflict() , No_after_no_insertion() @@ -279,78 +596,238 @@ Refine_cells_3(Tr& triangulation, , r_criteria_(criteria) , r_oracle_(oracle) , r_c3t3_(c3t3) - , last_vertex_index_() { } +// For parallel +template +Refine_cells_3:: +Refine_cells_3(Tr& triangulation, + const Cr& criteria, + const MD& oracle, + P_& previous, + C3T3& c3t3, + Lock_data_structure *lock_ds, + WorksharingDataStructureType *worksharing_ds) + : Mesher_level, Ct >(previous, lock_ds, worksharing_ds) + , C_() + , No_test_point_conflict() + , No_after_no_insertion() + , No_before_conflicts() + , r_tr_(triangulation) + , r_criteria_(criteria) + , r_oracle_(oracle) + , r_c3t3_(c3t3) +{ +} -template +template void -Refine_cells_3:: +Refine_cells_3:: scan_triangulation_impl() { typedef typename Tr::Finite_cells_iterator Finite_cell_iterator; - + typedef typename Tr::All_cells_iterator All_cells_iterator; + +#ifdef CGAL_MESH_3_PROFILING + WallClockTimer t; +#endif + + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { +# if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "Scanning triangulation for bad cells (in parallel)"; +# endif + add_to_TLS_lists(true); + + // WITH PARALLEL_FOR + // Copy cells into an std::vector to allow the use of tbb::parallel_for + // which requires random-access. + // Note that we're using all_cells_begin() instead of finite_cells_begin() + // because it's faster to do the is_infinite() test in parallel. + std::vector cells; + cells.reserve(r_tr_.number_of_cells()); + for(All_cells_iterator cell_it = r_tr_.all_cells_begin(); + cell_it != r_tr_.all_cells_end(); + ++cell_it) + { + cells.push_back(cell_it); + } + +# if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << " - Num cells to scan = " << cells.size() << "..." << std::endl; +# endif + tbb::parallel_for( + tbb::blocked_range(0, cells.size(), 1000), + Scan_cell(*this, cells) + ); + + splice_local_lists(); + add_to_TLS_lists(false); + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { +#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "Scanning triangulation for bad cells (sequential)... "; +#endif + + int count = 0; + for(Finite_cell_iterator cell_it = r_tr_.finite_cells_begin(); + cell_it != r_tr_.finite_cells_end(); + ++cell_it) + { + treat_new_cell(cell_it); + ++count; + } +#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << count << " cells scanned, "; +#endif + } + +#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "done." << std::endl; +#endif + +#ifdef CGAL_MESH_3_PROFILING + double cell_scan_time = t.elapsed(); + std::cerr << "==== Cell scan: " << cell_scan_time << " seconds ====" + << std::endl << std::endl; +# ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA + // If it's parallel but the refinement is forced to sequential, we don't + // output the value +# ifndef CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT + CGAL_MESH_3_SET_PERFORMANCE_DATA("Cells_scan_time", cell_scan_time); +# endif +# endif + std::cerr << "Refining... "; +#endif + +#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "Number of bad cells: " << C_::size() << std::endl; +#endif +} + + +template +int +Refine_cells_3:: +number_of_bad_elements_impl() +{ + typedef typename MD::Subdomain Subdomain; + typedef typename Tr::Finite_cells_iterator Finite_cell_iterator; + + int count = 0; +#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "Scanning triangulation for bad cells - " + "number of finite cells = " + << r_c3t3_.triangulation().number_of_finite_cells() << "..."; +#endif for(Finite_cell_iterator cell_it = r_tr_.finite_cells_begin(); cell_it != r_tr_.finite_cells_end(); ++cell_it) { - treat_new_cell(cell_it); + // treat cell + const Subdomain subdomain = r_oracle_.is_in_domain_object()(r_tr_.dual(cell_it)); + if ( subdomain ) + { + const Is_cell_bad is_cell_bad = r_criteria_(cell_it); + if( is_cell_bad ) + ++count; + } } +# if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "done." << std::endl; +# endif + + return count; } - -template -typename Refine_cells_3::Zone -Refine_cells_3:: -conflicts_zone_impl(const Point& point, - const Cell_handle& cell) const +template +typename Refine_cells_3::Zone +Refine_cells_3:: +conflicts_zone_impl(const Point& point + , const Cell_handle& cell + , bool &facet_is_in_its_cz) const { Zone zone; zone.cell = cell; zone.locate_type = Tr::CELL; - + r_tr_.find_conflicts(point, zone.cell, std::back_inserter(zone.boundary_facets), std::back_inserter(zone.cells), std::back_inserter(zone.internal_facets)); - CGAL_HISTOGRAM_PROFILER("Mesh_3::Refine_cells::conflict zone", zone.cells.size()); + + facet_is_in_its_cz = true; // Always true + + CGAL_HISTOGRAM_PROFILER("Mesh_3::Refine_cells::conflict zone", zone.cells.size()); return zone; } +template +typename Refine_cells_3::Zone +Refine_cells_3:: +conflicts_zone_impl(const Point& point + , const Cell_handle& cell + , bool &facet_is_in_its_cz + , bool &could_lock_zone + ) const +{ + Zone zone; + zone.cell = cell; + zone.locate_type = Tr::CELL; -template + r_tr_.find_conflicts(point, + zone.cell, + std::back_inserter(zone.boundary_facets), + std::back_inserter(zone.cells), + std::back_inserter(zone.internal_facets), + &could_lock_zone); + + facet_is_in_its_cz = true; // Always true + + return zone; +} + +template void -Refine_cells_3:: +Refine_cells_3:: before_insertion_handle_cells_in_conflict_zone(Zone& zone) { typename Zone::Cells_iterator cit = zone.cells.begin(); for ( ; cit != zone.cells.end() ; ++cit ) { - // Remove cell from refinement queue - this->remove_element(*cit); - + // Remove element (if needed - see + // remove_element_from_refinement_queue implementation) + this->remove_element_from_refinement_queue(*cit, Ct()); + // Remove cell from complex remove_cell_from_domain(*cit); } } -template +template void -Refine_cells_3:: +Refine_cells_3:: update_star(const Vertex_handle& vertex) { typedef std::vector Cells; typedef typename Cells::iterator Cell_iterator; - + // Get the star of v Cells incident_cells; r_tr_.incident_cells(vertex, std::back_inserter(incident_cells)); - + // Scan tets of the star of v for( Cell_iterator cell_it = incident_cells.begin(); cell_it != incident_cells.end(); @@ -364,35 +841,35 @@ update_star(const Vertex_handle& vertex) } } - -template + +template void -Refine_cells_3:: +Refine_cells_3:: update_star_self(const Vertex_handle& vertex) { typedef std::vector Cells; typedef typename Cells::iterator Cell_iterator; - + // Get the star of v Cells incident_cells; r_tr_.incident_cells(vertex, std::back_inserter(incident_cells)); - + // Get subdomain index Subdomain_index cells_subdomain = r_oracle_.subdomain_index(vertex->index()); - + // Restore surface & domain for( Cell_iterator cell_it = incident_cells.begin(); cell_it != incident_cells.end(); ++cell_it ) { CGAL_assertion(!r_tr_.is_infinite(*cell_it)); - + // Restore surface const int& k = (*cell_it)->index(vertex); const Facet mirror_f = mirror_facet(*cell_it,k); const Cell_handle& neighbor_cell = mirror_f.first; const int& neighb_k = mirror_f.second; - + if ( neighbor_cell->is_facet_on_surface(neighb_k) ) { // Facet(*cell_it,k) is on surface @@ -405,29 +882,29 @@ update_star_self(const Vertex_handle& vertex) (*cell_it)->set_facet_surface_center_index( k,neighbor_cell->get_facet_surface_center_index(neighb_k)); } - + // Set subdomain index set_cell_in_domain(*cell_it, cells_subdomain); - + // Add to queue compute_badness(*cell_it); } } -template +template void -Refine_cells_3:: +Refine_cells_3:: treat_new_cell(const Cell_handle& cell) { typedef boost::optional Subdomain; - + // treat cell const Subdomain subdomain = r_oracle_.is_in_domain_object()(r_tr_.dual(cell)); if ( subdomain ) { set_cell_in_domain(cell, *subdomain); - + // Add to refinement queue if needed compute_badness(cell); } @@ -436,23 +913,22 @@ treat_new_cell(const Cell_handle& cell) remove_cell_from_domain(cell); } } - -template +template void -Refine_cells_3:: +Refine_cells_3:: compute_badness(const Cell_handle& cell) { const Is_cell_bad is_cell_bad = r_criteria_(cell); if( is_cell_bad ) { - this->add_bad_element(cell, *is_cell_bad); + this->add_bad_element(this->from_cell_to_refinement_queue_element(cell), *is_cell_bad); } } -template -typename Refine_cells_3::Vertex_handle -Refine_cells_3:: +template +typename Refine_cells_3::Vertex_handle +Refine_cells_3:: insert_impl(const Point& point, const Zone& zone) { @@ -461,18 +937,17 @@ insert_impl(const Point& point, { return zone.cell->vertex(zone.i); } - + const Facet& facet = *(zone.boundary_facets.begin()); - + Vertex_handle v = r_tr_.insert_in_hole(point, zone.cells.begin(), zone.cells.end(), facet.first, facet.second); - + // Set index and dimension of v - set_vertex_properties(v, last_vertex_index_); - + set_vertex_properties(v, Base::get_last_vertex_index()); return v; } diff --git a/Mesh_3/include/CGAL/Mesh_3/Refine_facets_3.h b/Mesh_3/include/CGAL/Mesh_3/Refine_facets_3.h index c68dceaf23d..2003dbfc487 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Refine_facets_3.h +++ b/Mesh_3/include/CGAL/Mesh_3/Refine_facets_3.h @@ -26,18 +26,32 @@ #ifndef CGAL_MESH_3_REFINE_FACETS_3_H #define CGAL_MESH_3_REFINE_FACETS_3_H -#include -#include +#include +#include +#ifdef CGAL_LINKED_WITH_TBB + #include +#endif + +#include +#include #include + #include +#ifdef CGAL_MESH_3_PROFILING + #include +#endif + #include #include #include #include +#include #include +#include #include +#include namespace CGAL { @@ -57,7 +71,7 @@ BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_Is_facet_bad, Is_facet_bad, true) BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_Facet_badness, Facet_badness, false) // template class, used when use_facet_badness = false -template ::value) && Has_Facet_badness::value > struct Get_Is_facet_bad { @@ -72,7 +86,172 @@ struct Get_Is_facet_bad { typedef Type type; }; + // Predicate to know if a facet in a refinement queue is a zombie + // A facet is a pair . + // A facet is a "zombie" if at least one of its two adjacent cells + // has been erased. We test it thanks to the "erase counter" which + // is inside each cell (incremented by the compact container). + // In the refinement queue, we store a tuple + // + // where facet2 = mirror_facet(facet1) and facetx_erase_counter is + // the erase_counter of facetx's cell when added to the queue> + template + class Facet_to_refine_is_not_zombie + { + public: + Facet_to_refine_is_not_zombie() {} + bool operator()(const boost::tuple< + Facet, unsigned int, Facet, unsigned int> &f) const + { +#ifdef _DEBUG + int f1_current_erase_counter = boost::get<0>(f).first->erase_counter(); + int f1_saved_erase_counter = boost::get<1>(f); + int f2_current_erase_counter = boost::get<2>(f).first->erase_counter(); + int f2_saved_erase_counter = boost::get<3>(f); + //f1_current_erase_counter - f1_saved_erase_counter + f2_current_erase_counter - f2_saved_erase_counter == 1 + + /*if (f1_current_erase_counter - f1_saved_erase_counter + f2_current_erase_counter - f2_saved_erase_counter == 1) + { +#ifdef CGAL_LINKED_WITH_TBB + tbb::queuing_mutex mut; + tbb::queuing_mutex::scoped_lock l(mut); +#endif + + std::stringstream sstr; + Facet facet = boost::get<0>(f); + sstr << "Facet 1 { " << std::endl + << " - " << *facet.first->vertex((facet.second+1)%4) << std::endl + << " - " << *facet.first->vertex((facet.second+2)%4) << std::endl + << " - " << *facet.first->vertex((facet.second+3)%4) << std::endl + << " - 4th vertex in cell: " << *facet.first->vertex(facet.second) << std::endl + << "}" << std::endl; + + facet = boost::get<2>(f); + sstr << "Facet 2 { " << std::endl + << " - " << *facet.first->vertex((facet.second+1)%4) << std::endl + << " - " << *facet.first->vertex((facet.second+2)%4) << std::endl + << " - " << *facet.first->vertex((facet.second+3)%4) << std::endl + << " - 4th vertex in cell: " << *facet.first->vertex(facet.second) << std::endl + << "}" << std::endl; + + std::string s = sstr.str(); + //std::cerr << s << std::endl; + }*/ +#endif + return (boost::get<0>(f).first->erase_counter() == boost::get<1>(f) + && boost::get<2>(f).first->erase_counter() == boost::get<3>(f) ); + } + }; + +/************************************************ +// Class Refine_facets_3_base +// Two versions: sequential / parallel +************************************************/ + +// Sequential +template +class Refine_facets_3_base +{ +protected: + Refine_facets_3_base() : m_last_vertex_index() {} + + Index get_last_vertex_index() const + { + return m_last_vertex_index; + } + + void set_last_vertex_index(Index i) const + { + m_last_vertex_index = i; + } + +#if defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) \ + || defined(CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE) + + boost::tuple + from_facet_to_refinement_queue_element(const Facet &facet, + const Facet &mirror) const + { + return boost::make_tuple( + facet, facet.first->erase_counter(), + mirror, mirror.first->erase_counter()); + } + +public: + template + Facet extract_element_from_container_value(const Container_element &e) const + { + // We get the first Facet inside the tuple + return CGAL::cpp11::get<0>(e); + } + +#else + + Facet + from_facet_to_refinement_queue_element(const Facet &facet, + const Facet &mirror) const + { + // Returns canonical facet + return (facet < mirror) ? facet : mirror; + } + +public: + template + Facet extract_element_from_container_value(const Container_element &e) const + { + return e; + } + +#endif + +protected: + /// Stores index of vertex that may be inserted into triangulation + mutable Index m_last_vertex_index; +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template +class Refine_facets_3_base +{ +protected: + Refine_facets_3_base() : m_last_vertex_index(Index()) {} + + Index get_last_vertex_index() const + { + return m_last_vertex_index.local(); + } + + void set_last_vertex_index(Index i) const + { + m_last_vertex_index.local() = i; + } + + boost::tuple + from_facet_to_refinement_queue_element(const Facet &facet, + const Facet &mirror) const + { + return boost::make_tuple( + facet, facet.first->erase_counter(), + mirror, mirror.first->erase_counter()); + } + +public: + template + Facet extract_element_from_container_value(const Container_element &e) const + { + // We get the first Facet inside the tuple + return CGAL::cpp11::get<0>(e); + } + +protected: + /// Stores index of vertex that may be inserted into triangulation + mutable tbb::enumerable_thread_specific m_last_vertex_index; +}; +#endif // CGAL_LINKED_WITH_TBB + +/************************************************ // Class Refine_facets_3 // // Template parameters should be models of @@ -81,6 +260,7 @@ struct Get_Is_facet_bad { // MeshDomain : MeshTraits_3 // // Implements a Mesher_level for facets +************************************************/ // TODO document Container_ requirements template > + class Concurrency_tag, +#ifdef CGAL_LINKED_WITH_TBB + class Container_ = typename boost::mpl::if_c // (parallel/sequential?) + < + boost::is_convertible::value, + // Parallel +# ifdef CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE + Meshes::Filtered_deque_container +# else + Meshes::Filtered_multimap_container +# endif + < + boost::tuple, + typename Criteria::Facet_quality, + Facet_to_refine_is_not_zombie, + Concurrency_tag + >, + // Sequential +# ifdef CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE + Meshes::Filtered_deque_container + < + boost::tuple, + typename Criteria::Facet_quality, + Facet_to_refine_is_not_zombie, + Concurrency_tag + > +# elif defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) + Meshes::Filtered_multimap_container + < + boost::tuple, + typename Criteria::Facet_quality, + Facet_to_refine_is_not_zombie, + Concurrency_tag + > +# else + Meshes::Double_map_container +# endif + >::type // boost::if (parallel/sequential) + +#else // !CGAL_LINKED_WITH_TBB + + // Sequential + class Container_ = +# ifdef CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE + Meshes::Filtered_deque_container + < + boost::tuple, + typename Criteria::Facet_quality, + Facet_to_refine_is_not_zombie, + Concurrency_tag + > +# elif defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) + Meshes::Filtered_multimap_container + < + boost::tuple, + typename Criteria::Facet_quality, + Facet_to_refine_is_not_zombie, + Concurrency_tag + > +# else + Meshes::Double_map_container +# endif +#endif // CGAL_LINKED_WITH_TBB +> class Refine_facets_3 -: public Mesher_level +, public Mesh_3::Mesher_level, + Previous_level_, + Concurrency_tag, + Container_>, typename Tr::Facet, Previous_level_, - Triangulation_mesher_level_traits_3 > + Triangulation_mesher_level_traits_3, + Concurrency_tag > , public Container_ , public No_after_no_insertion , public No_before_conflicts @@ -110,9 +363,35 @@ class Refine_facets_3 Criteria, MeshDomain, Complex3InTriangulation3, - Previous_level_> Self; + Previous_level_, + Concurrency_tag, + Container_> Self; + + typedef Refine_facets_3_base Base; + + typedef Mesher_level, + typename Tr::Facet, + Previous_level_, + Triangulation_mesher_level_traits_3, + Concurrency_tag > Base_ML; + + typedef typename Tr::Lock_data_structure Lock_data_structure; public: + using Base_ML::add_to_TLS_lists; + using Base_ML::splice_local_lists; + + typedef Container_ Container; // Because we need it in Mesher_level + typedef typename Container::Element Container_element; typedef typename Tr::Point Point; typedef typename Tr::Facet Facet; typedef typename Tr::Vertex_handle Vertex_handle; @@ -120,11 +399,20 @@ public: typedef Complex3InTriangulation3 C3T3; /// Constructor + // For sequential Refine_facets_3(Tr& triangulation, const Criteria& criteria, const MeshDomain& oracle, Previous_level_& previous, C3T3& c3t3); + // For parallel + Refine_facets_3(Tr& triangulation, + const Criteria& criteria, + const MeshDomain& oracle, + Previous_level_& previous, + C3T3& c3t3, + Lock_data_structure *lock_ds, + WorksharingDataStructureType *worksharing_ds); /// Destructor virtual ~Refine_facets_3() { } @@ -136,27 +424,66 @@ public: /// Initialization function void scan_triangulation_impl(); + int number_of_bad_elements_impl(); + + Point circumcenter_impl(const Facet& facet) const + { + return get_facet_surface_center(facet); + } + + template + void before_next_element_refinement_in_superior_impl(Mesh_visitor visitor) + { + // Before refining any cell, we refine the facets in the local refinement + // queue + this->treat_local_refinement_queue(visitor); + } + + void before_next_element_refinement_impl() + { + } + + Facet get_next_element_impl() + { + return this->extract_element_from_container_value( + Container_::get_next_element_impl()); + } + + Facet get_next_local_element_impl() + { + return extract_element_from_container_value( + Container_::get_next_local_element_impl()); + } + /// Gets the point to insert from the element to refine Point refinement_point_impl(const Facet& facet) const { #ifdef CGAL_MESHES_DEBUG_REFINEMENT_POINTS const Cell_handle c = facet.first; const int i = facet.second; - std::cerr << "Facet (" + std::cerr << "Facet (" << c->vertex((i+1)&3)->point() << " , " << c->vertex((i+2)&3)->point() << " , " << c->vertex((i+3)&3)->point() << ") : refinement point is " << get_facet_surface_center(facet) << std::endl; #endif CGAL_assertion (is_facet_on_surface(facet)); - last_vertex_index_ = get_facet_surface_center_index(facet); + this->set_last_vertex_index(get_facet_surface_center_index(facet)); return get_facet_surface_center(facet); }; /// Tests if p encroaches facet from zone + // For sequential Mesher_level_conflict_status test_point_conflict_from_superior_impl(const Point& p, Zone& zone); + /// Tests if p encroaches facet from zone + // For parallel + template + Mesher_level_conflict_status + test_point_conflict_from_superior_impl(const Point& p, Zone& zone, + Mesh_visitor &visitor); + /// Useless here Mesher_level_conflict_status private_test_point_conflict_impl( const Point& p, @@ -174,7 +501,13 @@ public: } /// Returns the conflicts zone - Zone conflicts_zone_impl(const Point& point, const Facet& facet) const; + Zone conflicts_zone_impl(const Point& point + , const Facet& facet + , bool &facet_is_in_its_cz); + Zone conflicts_zone_impl(const Point& point + , const Facet& facet + , bool &facet_is_in_its_cz + , bool &could_lock_zone); /// Job to do before insertion void before_insertion_impl(const Facet& facet, @@ -183,7 +516,9 @@ public: /// Job to do after insertion void after_insertion_impl(const Vertex_handle& v) - { restore_restricted_Delaunay(v); } + { + restore_restricted_Delaunay(v); + } /// Insert p into triangulation Vertex_handle insert_impl(const Point& p, const Zone& zone); @@ -191,6 +526,17 @@ public: /// Restore restricted Delaunay ; may be call by Cells_mesher visitor void restore_restricted_Delaunay(const Vertex_handle& v); + bool try_lock_element(const Facet &f, int lock_radius = 0) const + { + return this->triangulation().try_lock_facet(f, lock_radius); + } + + /// debug info: class name + std::string debug_info_class_name_impl() const + { + return "Refine_facets_3"; + } + /// debug info std::string debug_info() const { @@ -204,9 +550,22 @@ public: { return "#facets to refine"; } - + + std::string debug_info_element_impl(const Facet &facet) const + { + std::stringstream sstr; + sstr << "Facet { " << std::endl + << " - " << *facet.first->vertex((facet.second+1)%4) << std::endl + << " - " << *facet.first->vertex((facet.second+2)%4) << std::endl + << " - " << *facet.first->vertex((facet.second+3)%4) << std::endl + << " - 4th vertex in cell: " << *facet.first->vertex(facet.second) << std::endl + << "}" << std::endl; + + return sstr.str(); + } + /// for debugging - std::string display_dual(Facet f) const + std::string display_dual(Facet f) const { std::stringstream stream; stream.precision(17); @@ -218,7 +577,7 @@ public: } else if ( const Ray_3* p_ray = object_cast(&dual) ) { stream << "Ray(" << p_ray->point(0) - << " , " << p_ray->point(1) + << " , " << p_ray->point(1) << "), with vector (" << p_ray->to_vector() << ")"; } else if ( const Line_3* p_line = object_cast(&dual) ) { @@ -234,6 +593,35 @@ public: private: + + // Functor for scan_triangulation_impl function + template + class Scan_facet + { + Refine_facets_ & m_refine_facets; + + typedef typename Refine_facets_::Facet Facet; + + public: + // Constructor + Scan_facet(Refine_facets_ & rf) + : m_refine_facets(rf) + {} + + // Constructor + Scan_facet(const Scan_facet &sf) + : m_refine_facets(sf.m_refine_facets) + {} + + // operator() + // f cannot be const, see treat_new_facet signature + void operator()( Facet f ) const + { + m_refine_facets.treat_new_facet(f); + } + }; + + //------------------------------------------------------- // Private types //------------------------------------------------------- @@ -341,12 +729,16 @@ private: /// Computes facet properties and add facet to the refinement queue if needed void treat_new_facet(Facet& facet); + /// Compute the exact dual of a facet + Object dual_exact(const Facet & f) const; + /** * Computes at once is_facet_on_surface and facet_surface_center. * @param facet The input facet * @return \c true if \c facet is on surface, \c false otherwise */ - void compute_facet_properties(const Facet& facet, Facet_properties& fp ) const; + void compute_facet_properties(const Facet& facet, Facet_properties& fp, + bool force_exact = false ) const; /// Returns true if point encroaches facet bool is_facet_encroached(const Facet& facet, const Point& point) const; @@ -357,10 +749,13 @@ private: /// Insert facet into refinement queue void insert_bad_facet(Facet& facet, const Quality& quality) { - // Insert canonical facet - this->add_bad_element(this->canonical_facet(facet), quality); + // Insert the facet and its mirror + Facet mirror = mirror_facet(facet); + this->add_bad_element( + this->from_facet_to_refinement_queue_element(facet, mirror_facet(facet)), + quality); } - + /// Insert encroached facet into refinement queue void insert_encroached_facet_in_queue(Facet& facet) { @@ -368,12 +763,22 @@ private: } /// Removes facet from refinement queue - void remove_bad_facet(Facet& facet) + // Sequential + void remove_bad_facet(Facet& facet, Sequential_tag) { + // If sequential AND NOT lazy, remove cell from refinement queue +#if !defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) \ + && !defined(CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE) // Remove canonical facet Facet canonical_facet = this->canonical_facet(facet); this->remove_element(canonical_facet); +#endif } +#ifdef CGAL_LINKED_WITH_TBB + /// Removes facet from refinement queue + // Parallel: it's always lazy, so do nothing + void remove_bad_facet(Facet& facet, Parallel_tag) {} +#endif // CGAL_LINKED_WITH_TBB /** * Action to perform on a facet inside the conflict zone before insertion @@ -414,12 +819,6 @@ private: /// The mesh result C3T3& r_c3t3_; - //------------------------------------------------------- - // Cache objects - //------------------------------------------------------- - /// Stores index of vertex that may be inserted into triangulation - mutable Index last_vertex_index_; - private: // Disabled copy constructor Refine_facets_3(const Self& src); @@ -430,16 +829,16 @@ private: - -template -Refine_facets_3:: +// For sequential +template +Refine_facets_3:: Refine_facets_3(Tr& triangulation, const Cr& criteria, const MD& oracle, P_& previous, C3T3& c3t3) : Mesher_level >(previous) + Triangulation_mesher_level_traits_3, Ct>(previous) , C_() , No_after_no_insertion() , No_before_conflicts() @@ -447,37 +846,279 @@ Refine_facets_3(Tr& triangulation, , r_criteria_(criteria) , r_oracle_(oracle) , r_c3t3_(c3t3) - , last_vertex_index_() { } +// For parallel +template +Refine_facets_3:: +Refine_facets_3(Tr& triangulation, + const Cr& criteria, + const MD& oracle, + P_& previous, + C3T3& c3t3, + Lock_data_structure *lock_ds, + WorksharingDataStructureType *worksharing_ds) + : Mesher_level, Ct>(previous) + , C_() + , No_after_no_insertion() + , No_before_conflicts() + , r_tr_(triangulation) + , r_criteria_(criteria) + , r_oracle_(oracle) + , r_c3t3_(c3t3) +{ + Base::set_lock_ds(lock_ds); + Base::set_worksharing_ds(worksharing_ds); +} -template + +template void -Refine_facets_3:: +Refine_facets_3:: scan_triangulation_impl() { typedef typename Tr::Finite_facets_iterator Finite_facet_iterator; - for(Finite_facet_iterator facet_it = r_tr_.finite_facets_begin(); - facet_it != r_tr_.finite_facets_end(); - ++facet_it) +#ifdef CGAL_MESH_3_PROFILING + WallClockTimer t; +#endif + +#ifdef CGAL_MESH_3_VERY_VERBOSE + std::cerr + << "Vertices: " << r_c3t3_.triangulation().number_of_vertices() << std::endl + << "Facets : " << r_c3t3_.number_of_facets_in_complex() << std::endl + << "Tets : " << r_c3t3_.number_of_cells_in_complex() << std::endl; +#endif + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) { - // Cannot be const, see treat_new_facet signature - Facet facet = *facet_it; - treat_new_facet(facet); +# if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "Scanning triangulation for bad facets (in parallel) - " + "number of finite facets = " + << r_c3t3_.triangulation().number_of_finite_facets() << "..." + << std::endl; +# endif + add_to_TLS_lists(true); + + // PARALLEL_DO + tbb::parallel_do( + r_tr_.finite_facets_begin(), r_tr_.finite_facets_end(), + Scan_facet(*this) + ); + + splice_local_lists(); + add_to_TLS_lists(false); } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { +#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "Scanning triangulation for bad facets (sequential) - " + "number of finite facets = " + << r_c3t3_.triangulation().number_of_finite_facets() << "..." + << std::endl; +#endif + for(Finite_facet_iterator facet_it = r_tr_.finite_facets_begin(); + facet_it != r_tr_.finite_facets_end(); + ++facet_it) + { + // Cannot be const, see treat_new_facet signature + Facet facet = *facet_it; + /*std::cerr << "*" << *facet.first->vertex((facet.second+1)%4) << std::endl + << " " << *facet.first->vertex((facet.second+2)%4) << std::endl + << " " << *facet.first->vertex((facet.second+3)%4) << std::endl;*/ + treat_new_facet(facet); + } + } + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "==== Facet scan: " << t.elapsed() << " seconds ====" + << std::endl << std::endl; +#endif + +#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "Number of bad facets: " << C_::size() << std::endl; +#endif + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << "Refining... "; + Base_ML::m_timer.reset(); +#endif } +template +int +Refine_facets_3:: +number_of_bad_elements_impl() +{ + typedef typename Tr::Finite_facets_iterator Finite_facet_iterator; -template + int count = 0, count_num_bad_surface_facets = 0; + int num_internal_facets_that_should_be_on_surface = 0; +#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "Scanning triangulation for bad facets - " + "number of finite facets = " + << r_c3t3_.triangulation().number_of_finite_facets() << "..."; +#endif + int num_tested_facets = 0; + for(Finite_facet_iterator facet_it = r_tr_.finite_facets_begin(); + facet_it != r_tr_.finite_facets_end(); + ++facet_it) + { + Facet facet = *facet_it; + Facet_properties properties; + compute_facet_properties(facet, properties); + +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + //facet.first->mark = 0; +#endif + + // On surface? + if ( properties ) + { + // This facet should be on surface... + if (!is_facet_on_surface(facet)) + { + std::cerr << "\n\n*** The facet f is on surface but is NOT MARKED ON SURFACE. " << std::endl; + + Cell_handle c = facet.first; + int ind = facet.second; + Cell_handle mc = mirror_facet(facet).first; + int mind = mirror_facet(facet).second; + +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + c->mark2 = ind; +#endif + + // c and mc are the cells adjacent to f + // browse each facet ff of c and mc, and mark it if it is "on surface" + int num_erroneous_surface_facets_in_c = 0; + int num_erroneous_surface_facets_in_mc = 0; + int num_real_surface_facets_in_c = 0; + int num_real_surface_facets_in_mc = 0; + for (int i = 0 ; i < 4 ; ++i) + { + if (i != ind) + { + const Facet f1(c, i); + if (is_facet_on_surface(f1)) + { + std::cerr << "*** f1 is " << (r_criteria_(f1) ? "bad" : "good") << std::endl; + +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + c->mark = i; +#endif + Facet_properties properties; + compute_facet_properties(f1, properties); + if (properties) + ++num_real_surface_facets_in_c; + else + ++num_erroneous_surface_facets_in_c; + } + } + if (i != mind) + { + const Facet f2(c, i); + if (is_facet_on_surface(f2)) + { + std::cerr << "*** f2 is " << (r_criteria_(f2) ? "bad" : "good") << std::endl; + +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + mc->mark = i; +#endif + Facet_properties properties; + compute_facet_properties(f2, properties); + if (properties) + ++num_real_surface_facets_in_mc; + else + ++num_erroneous_surface_facets_in_mc; + } + } + } + + std::cerr + << "*** Num of erroneous surface facets in c: " << num_erroneous_surface_facets_in_c << std::endl + << "*** Num of erroneous surface facets in mc: " << num_erroneous_surface_facets_in_mc << std::endl + << "*** Num of real surface facets in c: " << num_real_surface_facets_in_c << std::endl + << "*** Num of real surface facets in mc: " << num_real_surface_facets_in_mc << std::endl; + + typedef typename MD::Subdomain Subdomain; + const bool is_c_in_domain = r_oracle_.is_in_domain_object()(r_tr_.dual(c)); + const bool is_mc_in_domain = r_oracle_.is_in_domain_object()(r_tr_.dual(mc)); + + std::cerr << "*** Is in complex? c is marked in domain: " << r_c3t3_.is_in_complex(c) + << " / c is really in domain: " << is_c_in_domain + << " / mc is marked in domain: " << r_c3t3_.is_in_complex(mc) + << " / mc is really in domain: " << is_mc_in_domain + << std::endl; + + + // ... if it's not, count it + ++num_internal_facets_that_should_be_on_surface; + + } + + const Surface_patch_index& surface_index = CGAL::cpp11::get<0>(*properties); + const Index& surface_center_index = CGAL::cpp11::get<1>(*properties); + const Point& surface_center = CGAL::cpp11::get<2>(*properties); + + // Facet is on surface: set facet properties + //set_facet_surface_center(facet, surface_center, surface_center_index); + //set_facet_on_surface(facet, surface_index); + + const Is_facet_bad is_facet_bad = r_criteria_(facet); + if ( is_facet_bad ) + { + ++count; + if (is_facet_on_surface(facet)) + ++count_num_bad_surface_facets; + +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + //facet.first->mark = facet.second; +#endif + } + ++ num_tested_facets; + } + // Not on surface? + else + { + // Facet is not on surface + //remove_facet_from_surface(facet); + + // Marked on surface? + if (is_facet_on_surface(facet)) + { + std::cerr << "************** The facet is marked on surface whereas it's not! **************" << std::endl; +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + facet.first->mark = facet.second; +#endif + } + } + } + + /*std::cerr << "done (" << num_internal_facets_that_should_be_on_surface + << " facets which were internal facets were added to the surface)." << std::endl;*/ + std::cerr << "done (" << num_internal_facets_that_should_be_on_surface + << " facets that should be on surface are actually internal facets)." << std::endl; + std::cerr << std::endl << "Num_tested_facets = " << num_tested_facets << std::endl; + std::cerr << std::endl << "Num bad surface-marked facets = " << count_num_bad_surface_facets << std::endl; + + return count; +} + +// For sequential +template Mesher_level_conflict_status -Refine_facets_3:: -test_point_conflict_from_superior_impl(const Point& point, - Zone& zone) +Refine_facets_3:: +test_point_conflict_from_superior_impl(const Point& point, Zone& zone) { typedef typename Zone::Facets_iterator Facet_iterator; @@ -519,12 +1160,63 @@ test_point_conflict_from_superior_impl(const Point& point, return NO_CONFLICT; } +// For parallel +template +template +Mesher_level_conflict_status +Refine_facets_3:: +test_point_conflict_from_superior_impl(const Point& point, Zone& zone, + Mesh_visitor &visitor) +{ + typedef typename Zone::Facets_iterator Facet_iterator; -template -typename Refine_facets_3::Zone -Refine_facets_3:: -conflicts_zone_impl(const Point& point, - const Facet& facet) const + for (Facet_iterator facet_it = zone.internal_facets.begin(); + facet_it != zone.internal_facets.end(); + ++facet_it) + { + // surface facets which are internal facets of the conflict zone are + // encroached + if( is_facet_on_surface(*facet_it) ) + { + if ( is_encroached_facet_refinable(*facet_it) ) + { + // Even if it doesn't succeed, it will be tried again + this->try_to_refine_element(*facet_it, visitor); + return CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED; + } + else + return CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED; + } + } + + for (Facet_iterator facet_it = zone.boundary_facets.begin(); + facet_it != zone.boundary_facets.end(); + ++facet_it) + { + if( is_facet_encroached(*facet_it, point) ) + { + // Insert already existing surface facet into refinement queue + if ( is_encroached_facet_refinable(*facet_it) ) + { + // Even if it doesn't succeed, it will be tried again + this->try_to_refine_element(*facet_it, visitor); + return CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED; + } + else + return CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED; + } + } + + return NO_CONFLICT; +} + + +template +typename Refine_facets_3::Zone +Refine_facets_3:: +conflicts_zone_impl(const Point& point + , const Facet& facet + , bool &facet_is_in_its_cz) { Zone zone; @@ -537,11 +1229,103 @@ conflicts_zone_impl(const Point& point, if(zone.locate_type != Tr::VERTEX) { + const Facet *p_facet = (facet == Facet() ? 0 : &facet); + r_tr_.find_conflicts(point, zone.cell, std::back_inserter(zone.boundary_facets), std::back_inserter(zone.cells), - std::back_inserter(zone.internal_facets)); + std::back_inserter(zone.internal_facets) + , 0 + , p_facet + , &facet_is_in_its_cz); + + if (p_facet != 0 && !facet_is_in_its_cz) + { +# ifdef CGAL_MESH_3_VERBOSE + std::cerr << "Info: the facet is not in its conflict zone. " + "Switching to exact computation." << std::endl; +# endif + + Facet_properties properties; + compute_facet_properties(facet, properties, /*force_exact=*/true); + if ( properties ) + { + const Surface_patch_index& surface_index = CGAL::cpp11::get<0>(*properties); + const Index& surface_center_index = CGAL::cpp11::get<1>(*properties); + const Point& surface_center = CGAL::cpp11::get<2>(*properties); + + // Facet is on surface: set facet properties + set_facet_surface_center(facet, surface_center, surface_center_index); + set_facet_on_surface(facet, surface_index); + } + else + { + // Facet is not on surface + remove_facet_from_surface(facet); + } + } + } + + return zone; +} + +template +typename Refine_facets_3::Zone +Refine_facets_3:: +conflicts_zone_impl(const Point& point + , const Facet& facet + , bool &facet_is_in_its_cz + , bool &could_lock_zone) +{ + Zone zone; + + // TODO may be avoid the locate here + zone.cell = r_tr_.locate(point, + zone.locate_type, + zone.i, + zone.j, + facet.first, + &could_lock_zone); + + if(could_lock_zone && zone.locate_type != Tr::VERTEX) + { + const Facet *p_facet = (facet == Facet() ? 0 : &facet); + + r_tr_.find_conflicts(point, + zone.cell, + std::back_inserter(zone.boundary_facets), + std::back_inserter(zone.cells), + std::back_inserter(zone.internal_facets) + , &could_lock_zone + , p_facet + , &facet_is_in_its_cz); + + if (could_lock_zone && p_facet != 0 && !facet_is_in_its_cz) + { +#ifdef CGAL_MESH_3_VERBOSE + std::cerr << "Info: the facet is not in its conflict zone. " + "Switching to exact computation." << std::endl; +#endif + + Facet_properties properties; + compute_facet_properties(facet, properties, /*force_exact=*/true); + if ( properties ) + { + const Surface_patch_index& surface_index = CGAL::cpp11::get<0>(*properties); + const Index& surface_center_index = CGAL::cpp11::get<1>(*properties); + const Point& surface_center = CGAL::cpp11::get<2>(*properties); + + // Facet is on surface: set facet properties + set_facet_surface_center(facet, surface_center, surface_center_index); + set_facet_on_surface(facet, surface_index); + } + else + { + // Facet is not on surface + remove_facet_from_surface(facet); + } + } } return zone; @@ -549,10 +1333,9 @@ conflicts_zone_impl(const Point& point, - -template +template void -Refine_facets_3:: +Refine_facets_3:: before_insertion_impl(const Facet& facet, const Point& point, Zone& zone) @@ -561,6 +1344,11 @@ before_insertion_impl(const Facet& facet, bool source_facet_is_in_conflict = false; + /*std::cerr << "before_insertion_impl:" << std::endl + << "* " << *facet.first->vertex((facet.second+1)%4) << std::endl + << " " << *facet.first->vertex((facet.second+2)%4) << std::endl + << " " << *facet.first->vertex((facet.second+3)%4) << std::endl;*/ + // Iterate on conflict zone facets for (Facets_iterator facet_it = zone.internal_facets.begin(); facet_it != zone.internal_facets.end(); @@ -586,6 +1374,8 @@ before_insertion_impl(const Facet& facet, // called from a Mesh_3 visitor. if ( !source_facet_is_in_conflict && facet != Facet() ) { + const Facet source_other_side = mirror_facet(facet); + using boost::io::group; using std::setprecision; @@ -596,7 +1386,10 @@ before_insertion_impl(const Facet& facet, "Debugging informations:\n" " Facet: (%1%, %2%) = (%6%, %7%, %8%)\n" " Dual: %3%\n" - " Refinement point: %5%\n") + " Refinement point: %5%\n" + " Cells adjacent to facet:\n" + " ( %9% , %10% , %11% , %12% )\n" + " ( %13% , %14% , %15% , %16% )\n") % group(setprecision(17), (&*facet.first)) % group(setprecision(17), facet.second) % display_dual(facet) @@ -604,7 +1397,15 @@ before_insertion_impl(const Facet& facet, % group(setprecision(17), point) % group(setprecision(17), facet.first->vertex((facet.second + 1)&3)->point()) % group(setprecision(17), facet.first->vertex((facet.second + 2)&3)->point()) - % group(setprecision(17), facet.first->vertex((facet.second + 3)&3)->point()); + % group(setprecision(17), facet.first->vertex((facet.second + 3)&3)->point()) + % facet.first->vertex(0)->point() + % facet.first->vertex(1)->point() + % facet.first->vertex(2)->point() + % facet.first->vertex(3)->point() + % source_other_side.first->vertex(0)->point() + % source_other_side.first->vertex(1)->point() + % source_other_side.first->vertex(2)->point() + % source_other_side.first->vertex(3)->point(); CGAL_error_msg(error_msg.str().c_str()); } @@ -612,9 +1413,9 @@ before_insertion_impl(const Facet& facet, -template -typename Refine_facets_3::Vertex_handle -Refine_facets_3:: +template +typename Refine_facets_3::Vertex_handle +Refine_facets_3:: insert_impl(const Point& point, const Zone& zone) { @@ -634,16 +1435,16 @@ insert_impl(const Point& point, facet.second); // Set index and dimension of v - set_vertex_properties(v, last_vertex_index_); + set_vertex_properties(v, Base::get_last_vertex_index()); return v; } -template +template void -Refine_facets_3:: +Refine_facets_3:: restore_restricted_Delaunay(const Vertex_handle& vertex) { typedef std::vector Cell_handle_vector; @@ -675,9 +1476,9 @@ restore_restricted_Delaunay(const Vertex_handle& vertex) //------------------------------------------------------- // Private methods //------------------------------------------------------- -template +template void -Refine_facets_3:: +Refine_facets_3:: treat_new_facet(Facet& facet) { // Treat facet @@ -695,9 +1496,16 @@ treat_new_facet(Facet& facet) // Insert facet into refinement queue if needed const Is_facet_bad is_facet_bad = r_criteria_(facet); + if ( is_facet_bad ) { insert_bad_facet(facet, *is_facet_bad); + + /*std::cerr << "INSERT BAD FACET : " << std::endl + << "* " << *facet.first->vertex((facet.second+1)%4) << std::endl + << " " << *facet.first->vertex((facet.second+2)%4) << std::endl + << " " << *facet.first->vertex((facet.second+3)%4) << std::endl + << " Quality=" << is_facet_bad->second << std::endl;*/ } } else @@ -712,12 +1520,70 @@ treat_new_facet(Facet& facet) set_facet_visited(mirror); } +template +Object +Refine_facets_3:: +dual_exact(const Facet& facet) const +{ + typedef typename Gt::Bare_point Bare_point; -template + Cell_handle c = facet.first; + int i = facet.second; + Cell_handle n = c->neighbor(i); + if ( ! r_tr_.is_infinite(c) && ! r_tr_.is_infinite(n) ) + { + Bare_point p1 = Gt().construct_weighted_circumcenter_3_object()( + c->vertex(0)->point(), + c->vertex(1)->point(), + c->vertex(2)->point(), + c->vertex(3)->point(), + true); + Bare_point p2 = Gt().construct_weighted_circumcenter_3_object()( + n->vertex(0)->point(), + n->vertex(1)->point(), + n->vertex(2)->point(), + n->vertex(3)->point(), + true); + return Gt().construct_object_3_object()( + Gt().construct_segment_3_object()(p1, p2)); + } + + // either n or c is infinite + int in; + if ( r_tr_.is_infinite(c) ) + in = n->index(c); + else { + n = c; + in = i; + } + // n now denotes a finite cell, either c or c->neighbor(i) + int ind[3] = {(in+1)&3,(in+2)&3,(in+3)&3}; + if ( (in&1) == 1 ) + std::swap(ind[0], ind[1]); + const Point& p = n->vertex(ind[0])->point(); + const Point& q = n->vertex(ind[1])->point(); + const Point& r = n->vertex(ind[2])->point(); + + typename Gt::Line_3 l = Gt().construct_perpendicular_line_3_object() + ( Gt().construct_plane_3_object()(p,q,r), + Gt().construct_weighted_circumcenter_3_object()(p,q,r) ); + return Gt().construct_object_3_object()( + Gt().construct_ray_3_object()( + Gt().construct_weighted_circumcenter_3_object()( + n->vertex(0)->point(), + n->vertex(1)->point(), + n->vertex(2)->point(), + n->vertex(3)->point(), + true), + l)); +} + +template void -Refine_facets_3:: +Refine_facets_3:: compute_facet_properties(const Facet& facet, - Facet_properties& fp) const + Facet_properties& fp, + bool force_exact) const { //------------------------------------------------------- // Facet must be finite @@ -736,7 +1602,7 @@ compute_facet_properties(const Facet& facet, // Get dual of facet - Object dual = r_tr_.dual(facet); + Object dual = (force_exact ? dual_exact(facet) : r_tr_.dual(facet)); // If the dual is a segment if ( const Segment_3* p_segment = object_cast(&dual) ) @@ -766,17 +1632,17 @@ compute_facet_properties(const Facet& facet, Intersection intersect = construct_intersection(segment); #ifdef CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 - // In the following, CGAL::cpp0x::get<2>(intersect) == 0 is a way to + // In the following, CGAL::cpp11::get<2>(intersect) == 0 is a way to // test "intersect == Intersection()" (aka empty intersection), but // the later does not work. - Surface_patch surface = - (CGAL::cpp0x::get<2>(intersect) == 0) ? Surface_patch() : - r_oracle_.surface_patch_index(CGAL::cpp0x::get<1>(intersect)); + Surface_patch surface = + (CGAL::cpp11::get<2>(intersect) == 0) ? Surface_patch() : + r_oracle_.surface_patch_index(CGAL::cpp11::get<1>(intersect)); if(surface) #endif // CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 - fp = Facet_properties(CGAL::cpp0x::make_tuple(*surface, - CGAL::cpp0x::get<1>(intersect), - CGAL::cpp0x::get<0>(intersect))); + fp = Facet_properties(CGAL::cpp11::make_tuple(*surface, + CGAL::cpp11::get<1>(intersect), + CGAL::cpp11::get<0>(intersect))); return; } } @@ -784,7 +1650,7 @@ compute_facet_properties(const Facet& facet, else if ( const Ray_3* p_ray = object_cast(&dual) ) { // If a facet is on the convex hull, and if its finite incident - // cell has a very bid Delaunay ball, then the dual of the facet is + // cell has a very big Delaunay ball, then the dual of the facet is // a ray constructed with a point with very big coordinates, and a // vector with small coordinates. Its can happen than the // constructed ray is degenerate (the point(1) of the ray is @@ -801,15 +1667,15 @@ compute_facet_properties(const Facet& facet, Intersection intersect = construct_intersection(*p_ray); #ifdef CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 - Surface_patch surface = - (CGAL::cpp0x::get<2>(intersect) == 0) ? Surface_patch() : - r_oracle_.surface_patch_index(CGAL::cpp0x::get<1>(intersect)); + Surface_patch surface = + (CGAL::cpp11::get<2>(intersect) == 0) ? Surface_patch() : + r_oracle_.surface_patch_index(CGAL::cpp11::get<1>(intersect)); if(surface) #endif // CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 { - fp = Facet_properties(CGAL::cpp0x::make_tuple(*surface, - CGAL::cpp0x::get<1>(intersect), - CGAL::cpp0x::get<0>(intersect))); + fp = Facet_properties(CGAL::cpp11::make_tuple(*surface, + CGAL::cpp11::get<1>(intersect), + CGAL::cpp11::get<0>(intersect))); return; } @@ -857,9 +1723,9 @@ compute_facet_properties(const Facet& facet, } -template +template bool -Refine_facets_3:: +Refine_facets_3:: is_facet_encroached(const Facet& facet, const Point& point) const { @@ -867,68 +1733,68 @@ is_facet_encroached(const Facet& facet, { return false; } - + typename Gt::Compare_power_distance_3 compare_distance = r_tr_.geom_traits().compare_power_distance_3_object(); - + const Cell_handle& cell = facet.first; const int& facet_index = facet.second; const Point& center = get_facet_surface_center(facet); const Point& reference_point = cell->vertex((facet_index+1)&3)->point(); - + // facet is encroached if the new point is near from center than // one vertex of the facet return ( compare_distance(center, reference_point, point) != CGAL::SMALLER ); } -template +template bool -Refine_facets_3:: +Refine_facets_3:: is_encroached_facet_refinable(Facet& facet) const { typedef typename Gt::Point_3 Point_3; typedef typename Gt::FT FT; - + typename Gt::Compute_squared_radius_smallest_orthogonal_sphere_3 sq_radius = Gt().compute_squared_radius_smallest_orthogonal_sphere_3_object(); - + typename Gt::Compare_weighted_squared_radius_3 compare = Gt().compare_weighted_squared_radius_3_object(); - + const Cell_handle& c = facet.first; const int& k = facet.second; - + int k1 = (k+1)&3; int k2 = (k+2)&3; int k3 = (k+3)&3; - + // Get number of weighted points, and ensure that they will be accessible // using k1...ki, if i is the number of weighted points. int wp_nb = 0; if(c->vertex(k1)->point().weight() > FT(0)) - { + { ++wp_nb; } - + if(c->vertex(k2)->point().weight() > FT(0)) - { + { if ( 0 == wp_nb ) { std::swap(k1,k2); } ++wp_nb; } - + if(c->vertex(k3)->point().weight() > FT(0)) - { + { if ( 0 == wp_nb ) { std::swap(k1,k3); } if ( 1 == wp_nb ) { std::swap(k2,k3); } ++wp_nb; } - + const Point_3& p1 = c->vertex(k1)->point(); const Point_3& p2 = c->vertex(k2)->point(); const Point_3& p3 = c->vertex(k3)->point(); - + const FT min_ratio (0.16); // (0.2*2)^2 - + // Check ratio switch ( wp_nb ) { @@ -938,7 +1804,7 @@ is_encroached_facet_refinable(Facet& facet) const if ( r < min_ratio*p1.weight() ) { return false; } break; } - + case 2: { bool do_spheres_intersect = (compare(p1,p2,FT(0)) != CGAL::LARGER); @@ -947,38 +1813,42 @@ is_encroached_facet_refinable(Facet& facet) const FT r13 = sq_radius(p1,p3) / p1.weight(); FT r23 = sq_radius(p2,p3) / p2.weight(); FT r = (std::max)(r13,r23); - + if ( r < min_ratio ) { return false; } } break; } - + case 3: { bool do_spheres_intersect = (compare(p1,p2,p3,FT(0)) != CGAL::LARGER); if ( do_spheres_intersect ) { return false; } break; - } - + } + default: break; } return true; } - -template +/** + * \c facet is an internal facet we are going to remove + * \c source_facet is the facet we want to refine by inserting a new point + */ +template bool -Refine_facets_3:: +Refine_facets_3:: before_insertion_handle_facet_in_conflict_zone(Facet& facet, const Facet& source_facet) { Facet other_side = mirror_facet(facet); + // Is the facet on the surface of the complex if ( is_facet_on_surface(facet) ) { - // Remove facet from refinement queue - remove_bad_facet(facet); + // Remove element (if needed - see remove_bad_facet implementation) + remove_bad_facet(facet, Ct()); // Remove facet from complex remove_facet_from_surface(facet); @@ -993,9 +1863,9 @@ before_insertion_handle_facet_in_conflict_zone(Facet& facet, -template +template void -Refine_facets_3:: +Refine_facets_3:: after_insertion_handle_incident_facet(Facet& facet) { // If the facet is infinite or has been already visited, diff --git a/Mesh_3/include/CGAL/Mesh_3/Robust_weighted_circumcenter_filtered_traits_3.h b/Mesh_3/include/CGAL/Mesh_3/Robust_weighted_circumcenter_filtered_traits_3.h index d5e7012f7f0..539fec50d4c 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Robust_weighted_circumcenter_filtered_traits_3.h +++ b/Mesh_3/include/CGAL/Mesh_3/Robust_weighted_circumcenter_filtered_traits_3.h @@ -165,7 +165,8 @@ public: Bare_point operator() ( const Weighted_point_3 & p, const Weighted_point_3 & q, const Weighted_point_3 & r, - const Weighted_point_3 & s ) const + const Weighted_point_3 & s, + bool force_exact = false) const { CGAL_precondition(Rt().orientation_3_object()(p,q,r,s) == CGAL::POSITIVE); @@ -181,7 +182,7 @@ public: s.x(), s.y(), s.z(), s.weight(), num_x, num_y, num_z, den); - if ( ! CGAL_NTS is_zero(den) ) + if ( ! force_exact && ! CGAL_NTS is_zero(den) ) { FT inv = FT(1)/(FT(2) * den); Bare_point res(p.x() + num_x*inv, p.y() - num_y*inv, p.z() + num_z*inv); diff --git a/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h b/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h index b50c7e67d76..8b828bdfc77 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h +++ b/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h @@ -19,7 +19,7 @@ // Author(s) : Stephane Tayeb // //****************************************************************************** -// File Description : +// File Description : //****************************************************************************** #ifndef CGAL_MESH_3_SLIVER_PERTURBER_H @@ -47,6 +47,18 @@ #include #include +#include +#include + +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING +# define CGAL_PROFILE +# include +#endif + +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif + #include #ifdef CGAL_MESH_3_USE_RELAXED_HEAP #include @@ -56,35 +68,401 @@ #include #include #include +#include -#include +#include + +#include namespace CGAL { namespace Mesh_3 { - + + +/** +* @class PVertex +* Vertex with associated perturbation datas +*/ +// Sequential +template< typename FT + , typename Vertex_handle + , typename Point_3 + , typename SliverCriterion + , typename Perturbation + , typename Concurrency_tag> +class PVertex_ +{ +public: +typedef PVertex_ Self; +typedef unsigned int id_type; + +/// Constructor +PVertex_() +: vertex_handle_() +, incident_sliver_nb_(0) +, min_value_(SliverCriterion::max_value) +, try_nb_(0) +, p_perturbation_(NULL) +, id_() +{ } + +PVertex_(const Vertex_handle& vh, id_type id) +: vertex_handle_(vh) +, incident_sliver_nb_(0) +, min_value_((std::numeric_limits::max)()) +, try_nb_(0) +, p_perturbation_(NULL) +, id_(id) +{ } + +/// Associated vertex +const Vertex_handle& vertex() const { return vertex_handle_; } +void set_vertex(const Vertex_handle& vh) { vertex_handle_ = vh; } + +/// Incident slivers number +unsigned int sliver_nb() const { return incident_sliver_nb_; } +void set_sliver_nb(const unsigned int n) { incident_sliver_nb_ = n; } + +/// Current perturbation +const Perturbation* perturbation() const { return p_perturbation_; } +void set_perturbation(const Perturbation* p) { p_perturbation_ = p; } + +/// Is perturbable +bool is_perturbable() const +{ + return ( (vertex_handle_->in_dimension() > 1) + && (NULL != perturbation()) + && (sliver_nb() != 0) ); +} + +/// Min sliver value +const FT& min_value() const { return min_value_; } +void set_min_value(const FT& min_value){ min_value_ = min_value; } + +/// Try nb +const unsigned int& try_nb() const { return try_nb_; } +void set_try_nb(const unsigned int& try_nb) { try_nb_ = try_nb; } +void increment_try_nb() { ++try_nb_; } + +/// Id +void set_id(const id_type& id) { id_ = id; } +id_type id() const { return id_; } + +/// Operators +bool operator==(const Self& pv) const { return ( id() == pv.id() ); } + +bool operator<(const Self& pv) const +{ + // vertex type (smallest-interior first) + if ( vertex()->in_dimension() != pv.vertex()->in_dimension() ) + return vertex()->in_dimension() > pv.vertex()->in_dimension(); + // nb incident slivers (smallest first) + else if ( sliver_nb() != pv.sliver_nb() ) + return sliver_nb() < pv.sliver_nb(); + // min angle (smallest first) + else if ( min_value() != pv.min_value() ) + return min_value() < pv.min_value(); + // try nb (smallest first) + else if ( try_nb() != pv.try_nb() ) + return try_nb() < pv.try_nb(); + // perturbation type (smallest first) + else if ( perturbation() != pv.perturbation() ) + return *perturbation() < *pv.perturbation(); + return ( id() < pv.id() ); // all characteristics are the same! +} + +/// Dummy functions +void update_saved_erase_counter() {} +bool is_zombie() { return false; } + +private: +/// Private datas +Vertex_handle vertex_handle_; +unsigned int incident_sliver_nb_; +FT min_value_; +unsigned int try_nb_; +const Perturbation* p_perturbation_; +id_type id_; +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template< typename FT + , typename Vertex_handle + , typename Point_3 + , typename SliverCriterion + , typename Perturbation> +class PVertex_ +{ +public: +typedef PVertex_ Self; +typedef unsigned int id_type; + +/// Constructor +PVertex_() +: vertex_handle_() +, in_dimension_(-1) +, incident_sliver_nb_(0) +, min_value_((std::numeric_limits::max)()) +, try_nb_(0) +, p_perturbation_(NULL) +, id_() +{ } + +PVertex_(const Vertex_handle& vh, id_type id) +: vertex_handle_(vh) +, in_dimension_(vh->in_dimension()) +, vh_erase_counter_when_added_(vh->erase_counter()) +, incident_sliver_nb_(0) +, min_value_((std::numeric_limits::max)()) +, try_nb_(0) +, p_perturbation_(NULL) +, id_(id) +{ } + +/// Associated vertex +const Vertex_handle& vertex() const { return vertex_handle_; } +void set_vertex(const Vertex_handle& vh) +{ + vertex_handle_ = vh; + update_saved_erase_counter(); +} +void update_saved_erase_counter() +{ + vh_erase_counter_when_added_ = vertex_handle_->erase_counter(); +} + +int in_dimension() const { return in_dimension_; } + +/// Incident slivers number +unsigned int sliver_nb() const { return incident_sliver_nb_; } +void set_sliver_nb(const unsigned int n) { incident_sliver_nb_ = n; } + +/// Current perturbation +const Perturbation* perturbation() const { return p_perturbation_; } +void set_perturbation(const Perturbation* p) { p_perturbation_ = p; } + +/// Is perturbable +bool is_perturbable() const +{ + return ( (vertex_handle_->in_dimension() > 1) + && (NULL != perturbation()) + && (sliver_nb() != 0) ); +} + +/// Min sliver value +const FT& min_value() const { return min_value_; } +void set_min_value(const FT& min_value){ min_value_ = min_value; } + +/// Try nb +const unsigned int& try_nb() const { return try_nb_; } +void set_try_nb(const unsigned int& try_nb) { try_nb_ = try_nb; } +void increment_try_nb() { ++try_nb_; } + +/// Id +void set_id(const id_type& id) { id_ = id; } +id_type id() const { return id_; } + +/// Zombie +bool is_zombie() const +{ + return vertex_handle_->erase_counter() != vh_erase_counter_when_added_; +} + +/// Operators +bool operator==(const Self& pv) const { return ( id() == pv.id() ); } + +bool operator<(const Self& pv) const +{ + // vertex type (smallest-interior first) + if ( in_dimension() != pv.in_dimension() ) + return in_dimension() > pv.in_dimension(); + // nb incident slivers (smallest first) + else if ( sliver_nb() != pv.sliver_nb() ) + return sliver_nb() < pv.sliver_nb(); + // min angle (smallest first) + else if ( min_value() != pv.min_value() ) + return min_value() < pv.min_value(); + // try nb (smallest first) + else if ( try_nb() != pv.try_nb() ) + return try_nb() < pv.try_nb(); + // perturbation type (smallest first) + else if ( perturbation() != pv.perturbation() ) + return *perturbation() < *pv.perturbation(); + return ( id() < pv.id() ); // all characteristics are the same! +} + +private: +/// Private datas +Vertex_handle vertex_handle_; +unsigned int vh_erase_counter_when_added_; +int in_dimension_; +unsigned int incident_sliver_nb_; +FT min_value_; +unsigned int try_nb_; +const Perturbation* p_perturbation_; +id_type id_; +}; +#endif + +/************************************************ +// Class Sliver_perturber_base +// Two versions: sequential / parallel +************************************************/ + +// Sequential +template +class Sliver_perturber_base +{ +protected: + typedef typename Tr::Vertex_handle Vertex_handle; + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::FT FT; + typedef typename std::vector Bad_vertices_vector; + typedef typename Tr::Lock_data_structure Lock_data_structure; + + + Sliver_perturber_base(const Bbox_3 &, int) {} + + Lock_data_structure * + get_lock_data_structure() const { return 0; } + void unlock_all_elements() const {} + void create_root_task() const {} + bool flush_work_buffers() const { return true; } + void wait_for_all() const {} + void destroy_root_task() const {} + template + void enqueue_work(Func, const PVertex &) const {} + + void increment_erase_counter(const Vertex_handle &vh) const {} +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template +class Sliver_perturber_base +{ +protected: + typedef typename Tr::Vertex_handle Vertex_handle; + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::FT FT; + typedef typename tbb::concurrent_vector Bad_vertices_vector; + typedef typename Tr::Lock_data_structure Lock_data_structure; + + Sliver_perturber_base(const Bbox_3 &bbox, int num_grid_cells_per_axis) + : m_lock_ds(bbox, num_grid_cells_per_axis) + , m_worksharing_ds(bbox) + { + } + + Lock_data_structure *get_lock_data_structure() const + { + return &m_lock_ds; + } + + void unlock_all_elements() const + { + m_lock_ds.unlock_all_points_locked_by_this_thread(); + } + + void create_root_task() const + { + m_empty_root_task = new( tbb::task::allocate_root() ) tbb::empty_task; + m_empty_root_task->set_ref_count(1); + } + + bool flush_work_buffers() const + { + m_empty_root_task->set_ref_count(1); + bool keep_flushing = m_worksharing_ds.flush_work_buffers(*m_empty_root_task); + wait_for_all(); + return keep_flushing; + } + + void wait_for_all() const + { + m_empty_root_task->wait_for_all(); + } + + void destroy_root_task() const + { + tbb::task::destroy(*m_empty_root_task); + m_empty_root_task = 0; + } + + template + void enqueue_work(Func f, const PVertex &pv) const + { + CGAL_assertion(m_empty_root_task != 0); + m_worksharing_ds.enqueue_work(f, pv, *m_empty_root_task); + } + + void increment_erase_counter(const Vertex_handle &vh) const + { + vh->increment_erase_counter(); + } + +public: + +protected: + mutable Lock_data_structure m_lock_ds; + mutable Mesh_3::Auto_worksharing_ds m_worksharing_ds; + mutable tbb::task *m_empty_root_task; +}; +#endif // CGAL_LINKED_WITH_TBB + + + +/************************************************ +// Class Sliver_perturber +************************************************/ + template < typename C3T3, typename MeshDomain, typename SliverCriterion = Mesh_3::Min_dihedral_angle_criterion , typename Visitor_ = Null_perturber_visitor > class Sliver_perturber +: public Sliver_perturber_base { + // Types + typedef typename C3T3::Concurrency_tag Concurrency_tag; + + typedef Sliver_perturber Self; + typedef Sliver_perturber_base< + typename C3T3::Triangulation, Concurrency_tag> Base; + typedef typename C3T3::Triangulation Tr; typedef typename Tr::Geom_traits Gt; - + typedef typename Tr::Cell_handle Cell_handle; - typedef typename Tr::Vertex_handle Vertex_handle; + typedef typename Base::Vertex_handle Vertex_handle; typedef typename Tr::Vertex Vertex; - + typedef typename MeshDomain::Point_3 Point_3; + typedef typename std::vector Cell_vector; typedef typename std::vector Vertex_vector; - + typedef typename Base::Bad_vertices_vector Bad_vertices_vector; + typedef typename Gt::FT FT; - + // Helper typedef class C3T3_helpers C3T3_helpers; - + + using Base::get_lock_data_structure; + // Visitor // Should define // - bound_reached(FT bound) @@ -95,112 +473,22 @@ class Sliver_perturber public: typedef Abstract_perturbation Perturbation; typedef boost::ptr_vector Perturbation_vector; - + private: // Relaxed heap - // ----------------------------------- - // Private classes - // ----------------------------------- - /** - * @class PVertex - * Vertex with associated perturbation datas - */ - class PVertex - { - public: - typedef std::size_t id_type; - - /// Constructor - PVertex() - : vertex_handle_() - , incident_sliver_nb_(0) - , min_value_((std::numeric_limits::max)()) - , try_nb_(0) - , p_perturbation_(NULL) - , id_() - { } - PVertex(const Vertex_handle& vh, id_type id) - : vertex_handle_(vh) - , incident_sliver_nb_(0) - , min_value_((std::numeric_limits::max)()) - , try_nb_(0) - , p_perturbation_(NULL) - , id_(id) - { } - - /// Associated vertex - const Vertex_handle& vertex() const { return vertex_handle_; } - void set_vertex(const Vertex_handle& vh) { vertex_handle_ = vh; } - - /// Incident slivers number - unsigned int sliver_nb() const { return incident_sliver_nb_; } - void set_sliver_nb(const unsigned int n) { incident_sliver_nb_ = n; } - - /// Current perturbation - const Perturbation* perturbation() const { return p_perturbation_; } - void set_perturbation(const Perturbation* p) { p_perturbation_ = p; } - - /// Is perturbable - bool is_perturbable() const - { - return ( (vertex_handle_->in_dimension() > 1) - && (NULL != perturbation()) - && (sliver_nb() != 0) ); - } - - /// Min sliver value - const FT& min_value() const { return min_value_; } - void set_min_value(const FT& min_value){ min_value_ = min_value; } + typedef PVertex_ PVertex; - /// Try nb - const unsigned int& try_nb() const { return try_nb_; } - void set_try_nb(const unsigned int& try_nb) { try_nb_ = try_nb; } - void increment_try_nb() { ++try_nb_; } - - /// Id - void set_id(const id_type& id) { id_ = id; } - id_type id() const { return id_; } - - /// Operators - bool operator==(const PVertex& pv) const { return ( id() == pv.id() ); } - - bool operator<(const PVertex& pv) const - { - // vertex type (smallest-interior first) - if ( vertex()->in_dimension() != pv.vertex()->in_dimension() ) - return vertex()->in_dimension() > pv.vertex()->in_dimension(); - // nb incident slivers (smallest first) - else if ( sliver_nb() != pv.sliver_nb() ) - return sliver_nb() < pv.sliver_nb(); - // min angle (smallest first) - else if ( min_value() != pv.min_value() ) - return min_value() < pv.min_value(); - // try nb (smallest first) - else if ( try_nb() != pv.try_nb() ) - return try_nb() < pv.try_nb(); - // perturbation type (smallest first) - else if ( perturbation() != pv.perturbation() ) - return *perturbation() < *pv.perturbation(); - return ( id() < pv.id() ); // all characteristics are the same! - } - - private: - /// Private datas - Vertex_handle vertex_handle_; - unsigned int incident_sliver_nb_; - FT min_value_; - unsigned int try_nb_; - const Perturbation* p_perturbation_; - id_type id_; - }; - - /** * @class PVertex_id * relaxed heap */ - class PVertex_id : + class PVertex_id : public boost::put_get_helper { public: @@ -208,17 +496,17 @@ private: typedef typename PVertex::id_type value_type; typedef typename PVertex::id_type reference; typedef PVertex key_type; - + value_type operator[] (const key_type& pv) const { return pv.id(); } }; - + typedef std::less less_PVertex; #ifdef CGAL_MESH_3_USE_RELAXED_HEAP - typedef boost::relaxed_heap PQueue; + typedef boost::relaxed_heap PQueue; #else - typedef ::CGAL::internal::mutable_queue_with_remove, less_PVertex, PVertex_id> PQueue; + typedef ::CGAL::internal::mutable_queue_with_remove, less_PVertex, PVertex_id> PQueue; #endif //CGAL_MESH_3_USE_RELAXED_HEAP - + public: /** * Constructor @@ -226,7 +514,7 @@ public: Sliver_perturber(C3T3& c3t3, const MeshDomain& domain, const SliverCriterion& criterion); - + /** * @brief Launch perturbation * @param sliver_bound the bound the perturber will try to achieve @@ -234,39 +522,39 @@ public: * * Runs explicit perturbation. The goal is that for each tet of the mesh, * SliverCriterion(tet) > sliver_bound. - * The perturber runs step by step, using delta as step size. + * The perturber runs step by step, using delta as step size. */ Mesh_optimization_return_code operator()(Visitor visitor = Visitor()); - + /** * Adds a perturbation at the end of the perturbation queue - */ + */ void add_perturbation(Perturbation* perturbation); - + /// Time accessors void set_time_limit(double time) { time_limit_ = time; } double time_limit() const { return time_limit_; } - + private: - struct VHash + struct VHash { std::size_t operator()(Vertex_handle vh) const { - return boost::hash_value(&*vh); + return boost::hash_value(&*vh); } }; // ----------------------------------- // Private methods // ----------------------------------- - + /** * One step perturbation: tries to achieve sliver_bound quality in the mesh */ - bool perturb(const FT& sliver_bound, PQueue& pqueue, Visitor& v) const; - + bool perturb(const FT& sliver_bound, PQueue& pqueue, Visitor& v) const; + /** * Builds priority queue. It will contain all vertices that have quality below * sliver_bound. @@ -275,19 +563,36 @@ private: * precondition: pqueue.empty() */ int build_priority_queue(const FT& sliver_bound, PQueue& pqueue) const; - + /** * Updates priority queue for all vertices of \c vertices */ + // Sequential int update_priority_queue(const Vertex_vector& vertices, const FT& sliver_bound, PQueue& pqueue) const; - +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + int update_priority_queue( const Vertex_vector& vertices + , const FT& sliver_bound + , Visitor& visitor + , Bad_vertices_vector &bad_vertices) const; +#endif + /** * Updates \c pv in priority queue */ int update_priority_queue(const PVertex& pv, PQueue& pqueue) const; - + + // For parallel version + void + perturb_vertex( PVertex pv + , const FT& sliver_bound + , Visitor& visitor + , Bad_vertices_vector &bad_vertices + , bool *could_lock_zone + ) const; + /** * Returns a pvertex from a vertex handle \c vh, using id \c pv_id */ @@ -295,12 +600,18 @@ private: make_pvertex(const Vertex_handle& vh, const FT& sliver_bound, const typename PVertex::id_type& pv_id) const; - + PVertex + make_pvertex__concurrent( + const Vertex_handle& vh, + const FT& sliver_bound, + const typename PVertex::id_type& pv_id) const; + /** * Updates a pvertex \c pv */ void update_pvertex(PVertex& pv, const FT& sliver_bound) const; - + void update_pvertex__concurrent(PVertex& pv, const FT& sliver_bound) const; + /** * Returns \c vh pvertex id */ @@ -308,35 +619,105 @@ private: { return static_cast(vh->meshing_info()); } - + /** * Update bad vertices vector, wrt \c sliver_bound */ - void update_bad_vertices(Vertex_vector& bad_vertices, + // Sequential + void update_bad_vertices(std::vector &bad_vertices, const FT& sliver_bound) const; - +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + void update_bad_vertices(tbb::concurrent_vector &bad_vertices, + const FT& sliver_bound) const; +#endif + /** * Initializes vertices ids */ void initialize_vertices_id() const; - + /** * Returns true if time_limit is reached */ bool is_time_limit_reached() const { - return ( (time_limit() > 0) && (running_time_.time() > time_limit()) ); + return ( (time_limit() > 0) && (running_time_.time() > time_limit()) ); } - - + + #ifdef CGAL_MESH_3_PERTURBER_VERBOSE /// Verbose mode methods void print_perturbations_statistics() const; void print_final_perturbations_statistics() const; void reset_perturbation_counters(); #endif - + +#ifdef CGAL_LINKED_WITH_TBB + // For parallel version + void + enqueue_task(const PVertex &pv, + const FT& sliver_bound, + Visitor& visitor, + Bad_vertices_vector &bad_vertices + ) const; +#endif + private: + +#ifdef CGAL_LINKED_WITH_TBB + + // Functor for enqueue_task function + template + class Perturb_vertex + { + const SP & m_sliver_perturber; + PVertex m_pv; + FT m_sliver_bound; + Visitor & m_visitor; + Bad_vertices_vector_ & m_bad_vertices; + + public: + // Constructor + Perturb_vertex(const SP &sp, + const PVertex &pv, + FT sliver_bound, + Visitor& visitor, + Bad_vertices_vector_ &bad_vertices) + : m_sliver_perturber(sp), + m_pv(pv), + m_sliver_bound(sliver_bound), + m_visitor(visitor), + m_bad_vertices(bad_vertices) + { + } + + // Constructor + Perturb_vertex(const Perturb_vertex &pvx) + : m_sliver_perturber(pvx.m_sliver_perturber), + m_pv(pvx.m_pv), + m_sliver_bound(pvx.m_sliver_bound), + m_visitor(pvx.m_visitor), + m_bad_vertices(pvx.m_bad_vertices) + {} + + // operator() + void operator()() const + { + bool could_lock_zone; + do + { + m_sliver_perturber.perturb_vertex( + m_pv, m_sliver_bound, m_visitor, m_bad_vertices, &could_lock_zone); + m_sliver_perturber.unlock_all_elements(); + } while (!could_lock_zone); + + if ( m_sliver_perturber.is_time_limit_reached() ) + tbb::task::self().cancel_group_execution(); + } + }; +#endif + // ----------------------------------- // Private data // ----------------------------------- @@ -346,38 +727,43 @@ private: SliverCriterion sliver_criterion_; Perturbation_vector perturbation_vector_; C3T3_helpers helper_; - + // Internal perturbation ordering int next_perturbation_order_; - + // Timer double time_limit_; CGAL::Timer running_time_; }; - - - - - - - + + + + + + + template Sliver_perturber:: Sliver_perturber(C3T3& c3t3, const Md& domain, const Sc& criterion) - : c3t3_(c3t3) + : Base(c3t3.bbox(), + Concurrent_mesher_config::get().locking_grid_num_cells_per_axis) + , c3t3_(c3t3) , tr_(c3t3_.triangulation()) , domain_(domain) , sliver_criterion_(criterion) - , helper_(c3t3_,domain_) + , helper_(c3t3_,domain_,get_lock_data_structure()) , next_perturbation_order_(0) , time_limit_(-1) - , running_time_() -{} - - - + , running_time_() +{ + // If we're multi-thread + tr_.set_lock_data_structure(get_lock_data_structure()); +} + + + template Mesh_optimization_return_code Sliver_perturber:: @@ -385,31 +771,38 @@ operator()(Visitor visitor) { //check criterion bound if ( sliver_criterion_.sliver_bound() == 0 ) - sliver_criterion_.set_sliver_bound(Sc::default_value); + sliver_criterion_.set_sliver_bound(Sc::default_value); // Reset sliver value cache helper_.reset_cache(); - + // Init time counter + if (running_time_.is_running()) + running_time_.stop(); running_time_.reset(); running_time_.start(); - + +#ifdef CGAL_MESH_3_PROFILING + WallClockTimer t; +#endif + // Build priority queue (we use one queue for all steps) PQueue pqueue(tr_.number_of_vertices()); // Initialize vertices ids initialize_vertices_id(); - - -#ifdef CGAL_MESH_3_PERTURBER_VERBOSE + + +#if defined(CGAL_MESH_3_PERTURBER_VERBOSE) \ + || defined(CGAL_MESH_3_PROFILING) std::cerr << "Running sliver perturbation..." << std::endl; #endif - + #ifdef CGAL_MESH_3_PERTURBER_LOW_VERBOSITY std::cerr << "Legend of the following line: " << "(#vertices in pqueue, #iterations, #fails)" << std::endl; #endif - + const FT& delta = sliver_criterion_.get_perturbation_unit(); FT current_bound = delta; bool perturbation_ok = true; @@ -418,51 +811,78 @@ operator()(Visitor visitor) #ifdef CGAL_MESH_3_PERTURBER_HIGH_VERBOSITY // reset_perturbation_counters is not const reset_perturbation_counters(); -#endif +#endif perturbation_ok = perturb(current_bound, pqueue, visitor); - + visitor.bound_reached(current_bound); - + current_bound += delta; if ( (current_bound >= sliver_criterion_.sliver_bound()) && (current_bound < sliver_criterion_.sliver_bound() + delta) ) - { + { current_bound = sliver_criterion_.sliver_bound(); } } - + +#ifdef CGAL_MESH_3_PROFILING + double perturbation_time = t.elapsed(); +#endif + running_time_.stop(); helper_.reset_cache();//in case we re-use caches in another operation // after this perturbation - + #ifdef CGAL_MESH_3_PERTURBER_VERBOSE std::cerr << std::endl << "Total perturbation time: " << running_time_.time() << "s"; std::cerr << std::endl << "Perturbation statistics:" << std::endl; print_final_perturbations_statistics(); #endif - + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << std::endl << "Total perturbation 'wall-clock' time: " + << perturbation_time << "s" << std::endl; +#endif + + Mesh_optimization_return_code ret; + if ( is_time_limit_reached() ) { -#ifdef CGAL_MESH_3_PERTURBER_VERBOSE +#if defined(CGAL_MESH_3_PERTURBER_VERBOSE) || defined(CGAL_MESH_3_PROFILING) std::cerr << "Perturbation return code: TIME_LIMIT_REACHED\n\n"; #endif // CGAL_MESH_3_PERTURBER_VERBOSE - return TIME_LIMIT_REACHED; + ret = TIME_LIMIT_REACHED; } - - if ( !perturbation_ok ) { -#ifdef CGAL_MESH_3_PERTURBER_VERBOSE + else if ( !perturbation_ok ) { +#if defined(CGAL_MESH_3_PERTURBER_VERBOSE) || defined(CGAL_MESH_3_PROFILING) std::cerr << "Perturbation return code: CANT_IMPROVE_ANYMORE\n\n"; #endif // CGAL_MESH_3_PERTURBER_VERBOSE - return CANT_IMPROVE_ANYMORE; + ret = CANT_IMPROVE_ANYMORE; } -#ifdef CGAL_MESH_3_PERTURBER_VERBOSE - std::cerr << "Perturbation return code: BOUND_REACHED\n\n"; + else + { +#if defined(CGAL_MESH_3_PERTURBER_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "Perturbation return code: BOUND_REACHED\n\n"; #endif // CGAL_MESH_3_PERTURBER_VERBOSE - return BOUND_REACHED; + ret = BOUND_REACHED; + } + +#if defined(CGAL_MESH_3_EXPORT_PERFORMANCE_DATA) \ + && defined(CGAL_MESH_3_PROFILING) + if (ret == BOUND_REACHED) + { + CGAL_MESH_3_SET_PERFORMANCE_DATA("Perturber_optim_time", perturbation_time); + } + else + { + CGAL_MESH_3_SET_PERFORMANCE_DATA("Perturber_optim_time", + (ret == CANT_IMPROVE_ANYMORE ? + "CANT_IMPROVE_ANYMORE" : "TIME_LIMIT_REACHED")); + } +#endif + + return ret; } - - template void Sliver_perturber:: @@ -470,25 +890,25 @@ add_perturbation(Perturbation* perturbation) { if ( !perturbation_vector_.empty() ) perturbation_vector_.back().set_next(perturbation); - + if ( NULL != perturbation ) { // Set order perturbation->set_order(next_perturbation_order_++); - + // Add perturbation perturbation_vector_.push_back(perturbation); } -} - - - - +} + + + + // ----------------------------------- // Private methods -// ----------------------------------- +// ----------------------------------- template -bool +bool Sliver_perturber:: perturb(const FT& sliver_bound, PQueue& pqueue, Visitor& visitor) const { @@ -496,18 +916,18 @@ perturb(const FT& sliver_bound, PQueue& pqueue, Visitor& visitor) const CGAL::Timer timer; timer.start(); std::streamsize prec = std::cerr.precision(4); - std::cerr << "Perturb sliver vertices (bound: " << sliver_bound + std::cerr << "Perturb sliver vertices (bound: " << sliver_bound << ") ..." << std::endl; std::cerr.precision(prec); #endif - + // build priority queue int pqueue_size = build_priority_queue(sliver_bound, pqueue); - + #ifdef CGAL_MESH_3_PERTURBER_HIGH_VERBOSITY std::cerr << "Legend of the following line: " << "(#vertices in pqueue, #iterations, #fails)" << std::endl; - + // Store construction time timer.stop(); double construction_time = timer.time(); @@ -515,125 +935,164 @@ perturb(const FT& sliver_bound, PQueue& pqueue, Visitor& visitor) const timer.start(); #endif -#ifdef CGAL_MESH_3_PERTURBER_VERBOSE - int iteration_nb = 0; -#endif - // Stores the vertices for which perturbation has failed - Vertex_vector bad_vertices; - - while ( !is_time_limit_reached() && !pqueue.empty() ) - { - // Get pqueue head - PVertex pv = pqueue.top(); - pqueue.pop(); - --pqueue_size; - - CGAL_assertion(pv.is_perturbable()); - - // Get pvertex slivers list -#ifdef CGAL_NEW_INCIDENT_SLIVERS - Cell_vector slivers; - helper_.new_incident_slivers(pv.vertex(), sliver_criterion_, sliver_bound, - std::back_inserter(slivers)); -#else - Cell_vector slivers = - helper_.incident_slivers(pv.vertex(), sliver_criterion_, sliver_bound); -#endif + Bad_vertices_vector bad_vertices; - CGAL_assertion(slivers.size() == pv.sliver_nb()); - - // Perturb vertex - Vertex_vector modified_vertices; - - // pv.perturbation() should not be NULL if pv is in pqueue - CGAL_assertion(pv.perturbation() != NULL); - - std::pair perturbation_ok = - pv.perturbation()->operator()(pv.vertex(), - slivers, - c3t3_, - domain_, - sliver_criterion_, - sliver_bound, - modified_vertices); - - // If vertex has changed - may happen in two cases: vertex has been moved - // or vertex has been reverted to the same location - - if ( perturbation_ok.second != pv.vertex() ) +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { +# ifdef CGAL_MESH_3_PERTURBER_VERBOSE + int iteration_nb = 0; +# endif + + this->create_root_task(); + + while (pqueue.size() > 0) { - // Update pvertex vertex - pv.set_vertex(perturbation_ok.second); + PVertex pv = pqueue.top(); + pqueue.pop(); + enqueue_task(pv, sliver_bound, + visitor, bad_vertices); } - - // If v has been moved - if ( perturbation_ok.first ) + + this->wait_for_all(); + +# if defined(CGAL_MESH_3_PERTURBER_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << " Flushing"; +# endif + bool keep_flushing = true; + while (keep_flushing) { - // Update pvertex - update_pvertex(pv,sliver_bound); - - // If pv needs to be modified again, try first perturbation - pv.set_perturbation(&perturbation_vector_.front()); - pv.increment_try_nb(); - - // update modified vertices - pqueue_size += update_priority_queue(modified_vertices, - sliver_bound, - pqueue); + keep_flushing = this->flush_work_buffers(); +# if defined(CGAL_MESH_3_PERTURBER_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "."; +# endif } - else - { - // If perturbation fails, try next one - pv.set_perturbation(pv.perturbation()->next()); - - if ( NULL == pv.perturbation() ) - { - bad_vertices.push_back(pv.vertex()); - } - } - - // Update pqueue in every cases, because pv was poped - pqueue_size += update_priority_queue(pv, pqueue); - visitor.end_of_perturbation_iteration(pqueue_size); - -#ifdef CGAL_MESH_3_PERTURBER_HIGH_VERBOSITY - ++iteration_nb; - std::cerr << boost::format("\r \r" - "(%1%,%2%,%4%) (%|3$.1f| iteration/s)") - % pqueue_size - % iteration_nb - % (iteration_nb / timer.time()) - % bad_vertices.size(); -#endif - -#ifdef CGAL_MESH_3_PERTURBER_LOW_VERBOSITY - ++iteration_nb; - std::cerr << boost::format("\r \r" - "bound %5%: (%1%,%2%,%4%) (%|3$.1f| iteration/s)") - % pqueue_size - % iteration_nb - % (iteration_nb / running_time_.time()) - % bad_vertices.size() - % sliver_bound; -#endif + + this->destroy_root_task(); } - + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { +# ifdef CGAL_MESH_3_PERTURBER_VERBOSE + int iteration_nb = 0; +# endif + + while ( !is_time_limit_reached() && !pqueue.empty() ) + { + // Get pqueue head + PVertex pv = pqueue.top(); + pqueue.pop(); + --pqueue_size; + + CGAL_assertion(pv.is_perturbable()); + + // Get pvertex slivers list +# ifdef CGAL_NEW_INCIDENT_SLIVERS + Cell_vector slivers; + helper_.new_incident_slivers(pv.vertex(), sliver_criterion_, sliver_bound, + std::back_inserter(slivers)); +# else + Cell_vector slivers = + helper_.incident_slivers(pv.vertex(), sliver_criterion_, sliver_bound); +# endif + + CGAL_assertion(slivers.size() == pv.sliver_nb()); + + // Perturb vertex + Vertex_vector modified_vertices; + + // pv.perturbation() should not be NULL if pv is in pqueue + CGAL_assertion(pv.perturbation() != NULL); + + std::pair perturbation_ok = + pv.perturbation()->operator()(pv.vertex(), + slivers, + c3t3_, + domain_, + sliver_criterion_, + sliver_bound, + modified_vertices); + + // If vertex has changed - may happen in two cases: vertex has been moved + // or vertex has been reverted to the same location - + if ( perturbation_ok.second != pv.vertex() ) + { + // Update pvertex vertex + pv.set_vertex(perturbation_ok.second); + } + + // If v has been moved + if ( perturbation_ok.first ) + { + // Update pvertex + update_pvertex(pv,sliver_bound); + + // If pv needs to be modified again, try first perturbation + pv.set_perturbation(&perturbation_vector_.front()); + pv.increment_try_nb(); + + // update modified vertices + pqueue_size += update_priority_queue(modified_vertices, + sliver_bound, + pqueue); + } + else + { + // If perturbation fails, try next one + pv.set_perturbation(pv.perturbation()->next()); + + if ( NULL == pv.perturbation() ) + { + bad_vertices.push_back(pv.vertex()); + } + } + + // Update pqueue in every cases, because pv was poped + pqueue_size += update_priority_queue(pv, pqueue); + visitor.end_of_perturbation_iteration(pqueue_size); + +# ifdef CGAL_MESH_3_PERTURBER_HIGH_VERBOSITY + ++iteration_nb; + std::cerr << boost::format("\r \r" + "(%1%,%2%,%4%) (%|3$.1f| iteration/s)") + % pqueue_size + % iteration_nb + % (iteration_nb / timer.time()) + % bad_vertices.size(); +# endif + +# ifdef CGAL_MESH_3_PERTURBER_LOW_VERBOSITY + ++iteration_nb; + std::cerr << boost::format("\r \r" + "bound %5%: (%1%,%2%,%4%) (%|3$.1f| iteration/s)") + % pqueue_size + % iteration_nb + % (iteration_nb / running_time_.time()) + % bad_vertices.size() + % sliver_bound; +# endif + } + } + #ifdef CGAL_MESH_3_PERTURBER_HIGH_VERBOSITY std::cerr << std::endl; print_perturbations_statistics(); std::cerr << "Step perturbation time: " << timer.time() + construction_time - << "s" << std::endl << std::endl; + << "s" << std::endl << std::endl; #endif - + if ( is_time_limit_reached() ) return false; - + // update bad vertices list (remove those which are not bad anymore) update_bad_vertices(bad_vertices,sliver_bound); return bad_vertices.empty(); } - - + + #ifdef CGAL_FASTER_BUILD_QUEUE template @@ -642,7 +1101,7 @@ Sliver_perturber:: build_priority_queue(const FT& sliver_bound, PQueue& pqueue) const { CGAL_precondition(pqueue.empty()); - + #ifdef CGAL_MESH_3_PERTURBER_HIGH_VERBOSITY CGAL::Timer timer; timer.start(); @@ -670,8 +1129,8 @@ build_priority_queue(const FT& sliver_bound, PQueue& pqueue) const pv.set_sliver_nb(1); pv.set_min_value(d); pv.set_perturbation(&perturbation_vector_.front()); - } - else + } + else { pv.set_sliver_nb(pv.sliver_nb()+1); if(d < pv.min_value()) @@ -684,25 +1143,25 @@ build_priority_queue(const FT& sliver_bound, PQueue& pqueue) const for( typename M::iterator vit = vpm.begin(); vit != vpm.end() ; ++vit ) - pqueue_size += update_priority_queue(vit->second, pqueue); - + pqueue_size += update_priority_queue(vit->second, pqueue); + #ifdef CGAL_MESH_3_PERTURBER_HIGH_VERBOSITY std::cerr << "done (" << pqueue_size << " vertices inserted in " << timer.time() << "s)\n"; #endif - + return pqueue_size; } - + #else // not CGAL_FASTER_BUILD_QUEUE - + template int Sliver_perturber:: build_priority_queue(const FT& sliver_bound, PQueue& pqueue) const { CGAL_precondition(pqueue.empty()); - + #ifdef CGAL_MESH_3_PERTURBER_HIGH_VERBOSITY CGAL::Timer timer; timer.start(); @@ -710,25 +1169,25 @@ build_priority_queue(const FT& sliver_bound, PQueue& pqueue) const #endif int pqueue_size = 0; - + for ( typename Tr::Finite_vertices_iterator vit = tr_.finite_vertices_begin(); vit != tr_.finite_vertices_end() ; ++vit ) { PVertex pv = make_pvertex(vit, sliver_bound, get_pvertex_id(vit)); - pqueue_size += update_priority_queue(pv, pqueue); + pqueue_size += update_priority_queue(pv, pqueue); } - + #ifdef CGAL_MESH_3_PERTURBER_HIGH_VERBOSITY std::cerr << "done (" << pqueue_size << " vertices inserted in " << timer.time() << "s)\n"; #endif - + return pqueue_size; } -#endif // not CGAL_FASTER_BUILD_QUEUE +#endif // not CGAL_FASTER_BUILD_QUEUE + - template int Sliver_perturber:: @@ -744,11 +1203,37 @@ update_priority_queue(const Vertex_vector& vertices, PVertex pv = make_pvertex(*vit,sliver_bound,get_pvertex_id(*vit)); modified_pv_nb += update_priority_queue(pv, pqueue); } - + return modified_pv_nb; } +#ifdef CGAL_LINKED_WITH_TBB +// For parallel version +template +int +Sliver_perturber:: +update_priority_queue( const Vertex_vector& vertices + , const FT& sliver_bound + , Visitor& visitor + , Bad_vertices_vector &bad_vertices) const +{ + int modified_pv_nb = 0; + for ( typename Vertex_vector::const_iterator vit = vertices.begin() ; + vit != vertices.end() ; + ++vit ) + { + PVertex pv = make_pvertex__concurrent(*vit,sliver_bound,get_pvertex_id(*vit)); + if (pv.is_perturbable()) + { + enqueue_task(pv, sliver_bound, visitor, bad_vertices); + ++modified_pv_nb; + } + } + + return modified_pv_nb; +} +#endif template int @@ -776,11 +1261,157 @@ update_priority_queue(const PVertex& pv, PQueue& pqueue) const return 1; } } - + return 0; } +#ifdef CGAL_LINKED_WITH_TBB +// For parallel version +template +void +Sliver_perturber:: +perturb_vertex( PVertex pv + , const FT& sliver_bound + , Visitor& visitor + , Bad_vertices_vector &bad_vertices + , bool *could_lock_zone + ) const +{ +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + static Profile_branch_counter_3 bcounter( + "early withdrawals / late withdrawals / successes [Perturber]"); +#endif + *could_lock_zone = true; + + // Zombie? + if (pv.is_zombie()) + { + return; + } + + Point_3 p = pv.vertex()->point(); + if (!helper_.try_lock_point_no_spin(p) || p != pv.vertex()->point()) + { +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + bcounter.increment_branch_2(); // THIS is an early withdrawal! +#endif + *could_lock_zone = false; + return; + } + + // Zombie? (in case the vertex has changed in the meantime) + if (pv.is_zombie()) + { + return; + } + + CGAL_assertion(pv.is_perturbable()); + + int num_new_vertices_to_treat = 0; + + Cell_vector slivers; + slivers.reserve(8); + if (!helper_.try_lock_and_get_incident_slivers( + pv.vertex(), sliver_criterion_, sliver_bound, slivers)) + { + *could_lock_zone = false; +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + bcounter.increment_branch_1(); // THIS is a late withdrawal! +#endif + } + else + { + // Slivers may be empty if the vertex has been modified by another thread in the meatime + if (slivers.empty()) + { + return; + } + + // Perturb vertex + Vertex_vector modified_vertices; + + // pv.perturbation() should not be NULL if pv is in pqueue + CGAL_assertion(pv.perturbation() != NULL); + + std::pair perturbation_ok = + pv.perturbation()->operator()(pv.vertex(), + slivers, + c3t3_, + domain_, + sliver_criterion_, + sliver_bound, + modified_vertices, + could_lock_zone); + + if (*could_lock_zone) + { + // If vertex has changed - may happen in two cases: vertex has been moved + // or vertex has been reverted to the same location - + if ( perturbation_ok.second != pv.vertex() ) + { + // Update pvertex vertex + pv.set_vertex(perturbation_ok.second); + } + // If the vertex hasn't changed, we still need to "virtually" increment + // the erase counter, because we need to invalidate the PVertex that + // may be in other threads' queues + else + { + this->increment_erase_counter(pv.vertex()); + } + + // If v has been moved + if ( perturbation_ok.first ) + { + // Update pvertex + update_pvertex__concurrent(pv,sliver_bound); + + // If pv needs to be modified again, try first perturbation + pv.set_perturbation(&perturbation_vector_.front()); + pv.increment_try_nb(); + + // update modified vertices + num_new_vertices_to_treat += + update_priority_queue(modified_vertices, sliver_bound, visitor, bad_vertices); + } + else + { + // If perturbation fails, try next one + pv.set_perturbation(pv.perturbation()->next()); + pv.update_saved_erase_counter(); + + if ( NULL == pv.perturbation() ) + { + bad_vertices.push_back(pv.vertex()); + } + } + +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + ++bcounter; +#endif + + // Update pqueue in every cases, because pv was poped + if (pv.is_perturbable()) + { + enqueue_task(pv, sliver_bound, visitor, bad_vertices); + ++num_new_vertices_to_treat; + } + } + else + { +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + bcounter.increment_branch_1(); // THIS is a late withdrawal! +#endif + } + } + + visitor.end_of_perturbation_iteration(0); +} +#endif + + +// Sequential template typename Sliver_perturber::PVertex Sliver_perturber:: @@ -794,12 +1425,29 @@ make_pvertex(const Vertex_handle& vh, PVertex pv(vh,pv_id); pv.set_perturbation(&perturbation_vector_.front()); update_pvertex(pv, sliver_bound); - + return pv; } - - +// Parallel +template +typename Sliver_perturber::PVertex +Sliver_perturber:: +make_pvertex__concurrent( + const Vertex_handle& vh, + const FT& sliver_bound, + const typename PVertex::id_type& pv_id) const +{ + // Make pvertex in all cases + PVertex pv(vh,pv_id); + pv.set_perturbation(&perturbation_vector_.front()); + update_pvertex__concurrent(pv, sliver_bound); + + return pv; +} + + +// Sequential template void Sliver_perturber:: @@ -812,19 +1460,35 @@ update_pvertex(PVertex& pv, const FT& sliver_bound) const Cell_vector slivers = helper_.incident_slivers(pv.vertex(), sliver_criterion_, sliver_bound); #endif - + pv.set_sliver_nb(static_cast(slivers.size())); pv.set_min_value(helper_.min_sliver_value(slivers, sliver_criterion_)); } - - + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel template void Sliver_perturber:: -update_bad_vertices(Vertex_vector& bad_vertices, +update_pvertex__concurrent(PVertex& pv, const FT& sliver_bound) const +{ + Cell_vector slivers; + helper_.get_incident_slivers_without_using_tds_data( + pv.vertex(), sliver_criterion_, sliver_bound, slivers); + + pv.set_sliver_nb(static_cast(slivers.size())); + pv.set_min_value(helper_.min_sliver_value(slivers, sliver_criterion_)); +} +#endif + +// Sequential +template +void +Sliver_perturber:: +update_bad_vertices(std::vector &bad_vertices, const FT& sliver_bound) const { - typename Vertex_vector::iterator vit = bad_vertices.begin(); + typename std::vector::iterator vit = bad_vertices.begin(); while ( vit != bad_vertices.end() ) { if ( tr_.is_vertex(*vit) @@ -833,26 +1497,51 @@ update_bad_vertices(Vertex_vector& bad_vertices, ++vit; } else - { + { vit = bad_vertices.erase(vit); } - } + } } - - + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template +void +Sliver_perturber:: +update_bad_vertices(tbb::concurrent_vector &bad_vertices, + const FT& sliver_bound) const +{ + tbb::concurrent_vector tmpv; + + typename tbb::concurrent_vector::iterator vit + = bad_vertices.begin(); + while ( vit != bad_vertices.end() ) + { + if ( tr_.is_vertex(*vit) + && helper_.min_incident_value(*vit,sliver_criterion_) <= sliver_bound ) + { + tmpv.push_back(*vit); + } + ++vit; + } + bad_vertices.swap(tmpv); +} +#endif // CGAL_LINKED_WITH_TBB + + template void Sliver_perturber:: initialize_vertices_id() const { namespace bl = boost::lambda; - int cur_id = 0; - + int cur_id = 0; + std::for_each(tr_.finite_vertices_begin(), tr_.finite_vertices_end(), bl::bind(&Vertex::set_meshing_info, &bl::_1, bl::var(cur_id)++)); } - - + + #ifdef CGAL_MESH_3_PERTURBER_VERBOSE template void @@ -865,25 +1554,25 @@ print_perturbations_statistics() const { total_perturbation_nb += it->counter(); } - + if ( 0 == total_perturbation_nb ) { std::cerr << "No perturbation done at this step" << std::endl; - return; + return; } - + for ( it = perturbation_vector_.begin() ; it != perturbation_vector_.end() ; ++it ) { - std::cerr << it->perturbation_name() << ": " + std::cerr << it->perturbation_name() << ": " << (double)it->counter() / (double)total_perturbation_nb * 100. << "% (" << it->counter() << " in " << it->time() << "s)" << std::endl; } } - - + + template void @@ -896,25 +1585,25 @@ print_final_perturbations_statistics() const { total_perturbation_nb += it->total_counter(); } - + if ( 0 == total_perturbation_nb ) { std::cerr << "No perturbation done" << std::endl; - return; + return; } - + for ( it = perturbation_vector_.begin() ; it != perturbation_vector_.end() ; ++it ) { - std::cerr << it->perturbation_name() << ": " + std::cerr << it->perturbation_name() << ": " << (double)it->total_counter() / (double)total_perturbation_nb * 100. << "% (" << it->total_counter() << " in " << it->total_time() << "s)" << std::endl; } } - - + + template void @@ -926,12 +1615,29 @@ reset_perturbation_counters() { it->reset_counter(); it->reset_timer(); - } + } } #endif - - - + + +#ifdef CGAL_LINKED_WITH_TBB +// For parallel version +template +void +Sliver_perturber:: +enqueue_task(const PVertex &pv, + const FT& sliver_bound, + Visitor& visitor, + Bad_vertices_vector &bad_vertices + ) const +{ + this->enqueue_work( + Perturb_vertex( + *this, pv, sliver_bound, visitor, bad_vertices), + pv); +} +#endif + } // end namespace Mesh_3 diff --git a/Mesh_3/include/CGAL/Mesh_3/Slivers_exuder.h b/Mesh_3/include/CGAL/Mesh_3/Slivers_exuder.h index f87fb352367..346567ccf8f 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Slivers_exuder.h +++ b/Mesh_3/include/CGAL/Mesh_3/Slivers_exuder.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include @@ -44,6 +46,15 @@ #include #include +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING +# define CGAL_PROFILE +# include +#endif + +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif + #ifdef CGAL_MESH_3_VERBOSE #define CGAL_MESH_3_EXUDER_VERBOSE @@ -51,15 +62,15 @@ namespace CGAL { - + namespace Mesh_3 { - + namespace details { // various function objects - + // That functor Second_of takes a pair as input (the value type of a // map), and returns the ".second" member of that pair. It is used in - // Sliver_exuder, to constructor a transform iterator. - + // Slivers_exuder, to constructor a transform iterator. + // It should be doable using STL bind operators, but i am not sure how // to use them. -- Laurent Rineau, 2007/07/27 template @@ -71,18 +82,18 @@ namespace Mesh_3 { const typename Map::mapped_type&> Base; typedef typename Base::result_type result_type; typedef typename Base::argument_type argument_type; - + const typename Map::mapped_type& operator()(const typename Map::value_type& p) const { return p.second; } }; // end class Second_of - + // That function is constructed with a vertex handle v1. // Then, its operator() takes an other vertex handle v2 as input, and // returns the distance d(v1, v2). - // It is used in Sliver_exuder, to constructor a transform iterator. + // It is used in Slivers_exuder, to constructor a transform iterator. template class Min_distance_from_v : public std::unary_function @@ -98,7 +109,7 @@ namespace Mesh_3 { : v(&vh), gt(geom_traits), dist(dist) { } - + void operator()(const Vertex_handle& vh) const { @@ -106,27 +117,270 @@ namespace Mesh_3 { Compute_squared_distance_3; Compute_squared_distance_3 distance = gt.compute_squared_distance_3_object(); - + const double d = CGAL::to_double(distance((*v)->point(), vh->point())); if(d < dist){ dist = d; } } }; // end class Min_distance_from_v - + } // end namespace details - - - + + + +/************************************************ +// Class Slivers_exuder_base +// Two versions: sequential / parallel +************************************************/ + +// Sequential +template +class Slivers_exuder_base +{ +protected: + typedef typename Tr::Vertex_handle Vertex_handle; + typedef typename Tr::Cell_handle Cell_handle; + typedef std::vector Cell_vector; + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::FT FT; + typedef typename std::vector Bad_vertices_vector; + typedef typename Tr::Lock_data_structure Lock_data_structure; + + // A priority queue ordered on Tet quality (SliverCriteria) + typedef CGAL::Double_map Tet_priority_queue; + typedef typename Tet_priority_queue::reverse_iterator Queue_iterator; + typedef typename Tet_priority_queue::Reverse_entry Queue_value_type; + + Slivers_exuder_base(const Bbox_3 &, int) {} + + Lock_data_structure * get_lock_data_structure() const { return 0; } + void unlock_all_elements() const {} + void create_root_task() const {} + bool flush_work_buffers() const { return true; } + void wait_for_all() const {} + void destroy_root_task() const {} + template + void enqueue_work(Func, double) const {} + +protected: + Cell_handle extract_cell_handle_from_queue_value(const Queue_value_type &qv) const + { + return qv.second; + } + double extract_cell_quality_from_queue_value(const Queue_value_type &qv) const + { + return qv.first; + } + unsigned int extract_erase_counter_from_queue_value(const Queue_value_type &qv) const + { + return 0; + } + + // Dummy + unsigned int erase_counter(const Cell_handle &ch) const { return 0;} + + std::size_t cells_queue_size() const { return cells_queue_.size(); } + bool cells_queue_empty() const { return cells_queue_.empty(); } + Queue_iterator + cells_queue_front() { return cells_queue_.front(); } + void cells_queue_pop_front() { cells_queue_.pop_front(); } + void cells_queue_clear() { cells_queue_.clear(); } + void cells_queue_insert(const Cell_handle &ch, double quality_value) + { + cells_queue_.insert(ch, quality_value); + } + + /** + * A functor to remove one \c Cell_handle from a priority queue + */ + class Erase_from_queue + { + public: + Erase_from_queue(Tet_priority_queue& queue) + : r_queue_(queue) { } + + void operator()(const Cell_handle& cell) + { r_queue_.erase(cell); } + + private: + Tet_priority_queue& r_queue_; + }; + + /** + * Delete cells of \c cells from \c cells_queue + */ + void delete_cells_from_queue(const Cell_vector& cells) + { + std::for_each(cells.begin(), cells.end(), + Erase_from_queue(cells_queue_)); + } + +private: + + Tet_priority_queue cells_queue_; +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template +class Slivers_exuder_base +{ +protected: + typedef typename Tr::Vertex_handle Vertex_handle; + typedef typename Tr::Cell_handle Cell_handle; + typedef std::vector Cell_vector; + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::FT FT; + typedef typename tbb::concurrent_vector Bad_vertices_vector; + typedef typename Tr::Lock_data_structure Lock_data_structure; + + // A priority queue ordered on Tet quality (SliverCriteria) + typedef std::multimap< + double, std::pair > Tet_priority_queue; + typedef typename Tet_priority_queue::iterator Queue_iterator; + typedef typename Tet_priority_queue::value_type Queue_value_type; + + Slivers_exuder_base(const Bbox_3 &bbox, int num_grid_cells_per_axis) + : m_lock_ds(bbox, num_grid_cells_per_axis) + , m_worksharing_ds(bbox) + { + } + + Lock_data_structure *get_lock_data_structure() const + { + return &m_lock_ds; + } + + void unlock_all_elements() const + { + m_lock_ds.unlock_all_points_locked_by_this_thread(); + } + + void create_root_task() const + { + m_empty_root_task = new( tbb::task::allocate_root() ) tbb::empty_task; + m_empty_root_task->set_ref_count(1); + } + + bool flush_work_buffers() const + { + m_empty_root_task->set_ref_count(1); + bool keep_flushing = m_worksharing_ds.flush_work_buffers(*m_empty_root_task); + wait_for_all(); + return keep_flushing; + } + + void wait_for_all() const + { + m_empty_root_task->wait_for_all(); + } + + void destroy_root_task() const + { + tbb::task::destroy(*m_empty_root_task); + m_empty_root_task = 0; + } + + template + void enqueue_work(Func f, double value) const + { + CGAL_assertion(m_empty_root_task != 0); + m_worksharing_ds.enqueue_work(f, value, *m_empty_root_task); + } + +public: + +protected: + Cell_handle extract_cell_handle_from_queue_value(const Queue_value_type &qv) const + { + return qv.second.first; + } + double extract_cell_quality_from_queue_value(const Queue_value_type &qv) const + { + return qv.first; + } + unsigned int extract_erase_counter_from_queue_value(const Queue_value_type &qv) const + { + return qv.second.second; + } + + unsigned int erase_counter(const Cell_handle &ch) const + { + return ch->erase_counter(); + } + + std::size_t cells_queue_size() const { return cells_queue_.size(); } + bool cells_queue_empty() const { return cells_queue_.empty(); } + Queue_iterator + cells_queue_front() { return cells_queue_.begin(); } + void cells_queue_pop_front() { cells_queue_.erase(cells_queue_front()); } + void cells_queue_clear() { cells_queue_.clear(); } + void cells_queue_insert(const Cell_handle &ch, double quality_value) + { + cells_queue_.insert(std::make_pair( + quality_value, + std::make_pair(ch, ch->erase_counter()))); + } + + /** + * A functor to remove one \c Cell_handle from a priority queue + */ + class Erase_from_queue + { + public: + Erase_from_queue(Tet_priority_queue&) {} + + void operator()(const Cell_handle& cell) + { cell->increment_erase_counter(); } + }; + + /** + * Delete cells of \c cells from \c cells_queue + */ + void delete_cells_from_queue(const Cell_vector& cells) + { + std::for_each(cells.begin(), cells.end(), + Erase_from_queue(cells_queue_)); + } + + mutable Lock_data_structure m_lock_ds; + mutable Mesh_3::Auto_worksharing_ds m_worksharing_ds; + mutable tbb::task *m_empty_root_task; + +private: + + Tet_priority_queue cells_queue_; +}; +#endif // CGAL_LINKED_WITH_TBB + + +/************************************************ +// Class Slivers_exuder +************************************************/ + template < typename C3T3, + typename MeshDomain, typename SliverCriteria, typename Visitor_ = Null_exuder_visitor, typename FT = typename C3T3::Triangulation::Geom_traits::FT > class Slivers_exuder +: public Slivers_exuder_base { - // Types + +public: // Types + + typedef typename C3T3::Concurrency_tag Concurrency_tag; + typedef Slivers_exuder_base< + typename C3T3::Triangulation, Concurrency_tag> Base; + +private: // Types + + typedef Slivers_exuder Self; + typedef typename C3T3::Triangulation Tr; typedef typename Tr::Weighted_point Weighted_point; typedef typename Tr::Bare_point Bare_point; @@ -134,50 +388,52 @@ class Slivers_exuder typedef typename Tr::Facet Facet; typedef typename Tr::Vertex_handle Vertex_handle; typedef typename Weighted_point::Weight Weight; - + typedef typename Base::Queue_value_type Queue_value_type; + typedef typename Base::Cell_vector Cell_vector; + typedef typename Tr::Geom_traits Geom_traits; typedef typename Geom_traits::Tetrahedron_3 Tetrahedron_3; - + typedef typename C3T3::Cells_in_complex_iterator Cell_iterator; - typedef std::vector Cell_vector; typedef std::vector Facet_vector; - + typedef typename C3T3::Surface_patch_index Surface_patch_index; typedef typename C3T3::Subdomain_index Subdomain_index; typedef typename C3T3::Index Index; - + // Umbrella will store the surface_index of internal facets of a new // weighted point conflict zone. Such facets are represented by their edge // which do not contain the pumped vertex typedef std::pair Ordered_edge; typedef std::map Umbrella; - + // Boundary_facets_from_outside represents the facet of the conflict zone // seen from outside of it. It stores Surface_patch_index of the facet, and - // Subdomain_index of the cell which is inside the conflict zone. + // Subdomain_index of the cell which is inside the conflict zone. typedef std::map > Boundary_facets_from_outside; - + /** Pre_star will represent the pre-star of a point. It is a (double)-map * of Facet (viewed from cells inside the star), ordered by the * critial_radius of the point with the cell that lies on the facet, at * the exterior of the pre-star. */ typedef CGAL::Double_map Pre_star; - + // Stores the value of facet for the sliver criterion functor typedef std::map Sliver_values; - - // A priority queue ordered on Tet quality (SliverCriteria) - typedef CGAL::Double_map Tet_priority_queue; - + // Visitor class // Should define // - after_cell_pumped(std::size_t cells_left_number) typedef Visitor_ Visitor; - + // Helper + typedef class C3T3_helpers C3T3_helpers; + + using Base::get_lock_data_structure; + public: // methods - + /** * @brief Constructor * @param c3t3 The mesh to exude @@ -186,9 +442,10 @@ public: // methods * max_weight(v) < d*dist(v,nearest_vertice(v)) */ Slivers_exuder(C3T3& c3t3, + const MeshDomain& domain, const SliverCriteria& criterion, double d = 0.45); - + /** * @brief pumps vertices * @param criterion_value_limit All vertices of tetrahedra that have a @@ -197,13 +454,42 @@ public: // methods Mesh_optimization_return_code operator()(Visitor visitor = Visitor()) { - return pump_vertices(sliver_criteria_.sliver_bound(), visitor); +#ifdef CGAL_MESH_3_PROFILING + WallClockTimer t; +#endif + + // Reset sliver value cache + helper_.reset_cache(); + + Mesh_optimization_return_code ret = + pump_vertices(sliver_criteria_.sliver_bound(), visitor); + +#ifdef CGAL_MESH_3_PROFILING + double exudation_time = t.elapsed(); + std::cerr << std::endl << "==== Total exudation 'wall-clock' time: " + << exudation_time << "s ====" << std::endl; +#endif + +#ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA + if (ret == BOUND_REACHED) + { + CGAL_MESH_3_SET_PERFORMANCE_DATA("Exuder_optim_time", exudation_time); + } + else + { + CGAL_MESH_3_SET_PERFORMANCE_DATA("Exuder_optim_time", + (ret == CANT_IMPROVE_ANYMORE ? + "CANT_IMPROVE_ANYMORE" : "TIME_LIMIT_REACHED")); + } +#endif + + return ret; } - + /// Time accessors void set_time_limit(double time) { time_limit_ = time; } double time_limit() const { return time_limit_; } - + private: // ----------------------------------- // Private Methods @@ -214,25 +500,29 @@ private: template Mesh_optimization_return_code pump_vertices(double criterion_value_limit, Visitor& v); - + /** * Pump one vertex */ - bool pump_vertex(const Vertex_handle& v); - + template + bool pump_vertex(const Vertex_handle& v, + bool *could_lock_zone = NULL); + /** * Returns the best_weight of v */ - double get_best_weight(const Vertex_handle& v) const; - + double get_best_weight(const Vertex_handle& v, + bool *could_lock_zone = NULL) const; + /** * Initializes pre_star and criterion_values */ void initialize_prestar_and_criterion_values(const Vertex_handle& v, Pre_star& pre_star, - Sliver_values& criterion_values) const; - + Sliver_values& criterion_values, + bool *could_lock_zone = NULL) const; + /** * Expand pre_star with cell_to_add */ @@ -240,41 +530,44 @@ private: const Vertex_handle& pumped_vertex, Pre_star& pre_star, Sliver_values& criterion_values) const; - + /** * Returns Ordered_edge of facet which do not contains vertex */ Ordered_edge get_opposite_ordered_edge(const Facet& facet, const Vertex_handle& vertex) const; - + /** * Returns the umbrella of internal_facets vector */ Umbrella get_umbrella(const Facet_vector& internal_facets, const Vertex_handle& v) const; - + /** * Updates the mesh with new_point */ + template void update_mesh(const Weighted_point& new_point, - const Vertex_handle& old_vertex); - + const Vertex_handle& old_vertex, + bool *could_lock_zone = NULL); + /** * Restores cells and boundary facets of conflict zone of new_vertex in c3t3_ */ + template void restore_cells_and_boundary_facets( const Boundary_facets_from_outside& boundary_facets_from_outside, const Vertex_handle& new_vertex); - + /** * Restore internal facets of conflict zone of new_vertex in c3t3_ */ void restore_internal_facets(const Umbrella& umbrella, const Vertex_handle& new_vertex); - + /** * Orders handles \c h1 & \c h2 - */ + */ template static void order_two_handles(Handle& h1, Handle& h2) @@ -282,7 +575,7 @@ private: if( h2 < h1 ) std::swap(h1, h2); } - + /** * Initialization */ @@ -292,12 +585,12 @@ private: sliver_criteria_.set_sliver_bound(limit_value); else sliver_criteria_.set_sliver_bound(SliverCriteria::max_value); - - cells_queue_.clear(); + + this->cells_queue_clear(); initialize_cells_priority_queue(); initialized_ = true; } - + /** * Initialize cells_queue w.r.t sliver_bound_ */ @@ -307,14 +600,14 @@ private: cit != c3t3_.cells_in_complex_end() ; ++cit) { - const double value + const double value = sliver_criteria_(cit); if( value < sliver_criteria_.sliver_bound() ) - cells_queue_.insert(cit, value); + this->cells_queue_insert(cit, value); } } - + /** * Returns critical radius of (v,c) */ @@ -323,17 +616,17 @@ private: { typedef typename Geom_traits::Compute_critical_squared_radius_3 Critical_radius; - + Critical_radius critical_radius = tr_.geom_traits().compute_critical_squared_radius_3_object(); - + return CGAL::to_double(critical_radius(c->vertex(0)->point(), c->vertex(1)->point(), c->vertex(2)->point(), c->vertex(3)->point(), v->point())); } - + /** * Returns the squared distance from vh to its closest vertice */ @@ -345,23 +638,23 @@ private: min_distance_from_v(vh, dist); tr_.adjacent_vertices(vh, boost::make_function_output_iterator(min_distance_from_v)); - + return dist; } - - /** + + /** * Returns the min value of second element of Ratio */ double get_min_value(const Sliver_values& criterion_values) const { using boost::make_transform_iterator; typedef details::Second_of Second_of; - + return *(std::min_element( make_transform_iterator(criterion_values.begin(), Second_of()), make_transform_iterator(criterion_values.end(), Second_of()))); } - + /** * Returns the \c Boundary_facets_from_outside object containing mirror facets * of \c facets @@ -370,7 +663,7 @@ private: get_boundary_facets_from_outside(const Facet_vector& facets) const { Boundary_facets_from_outside boundary_facets_from_outside; - + for(typename Facet_vector::const_iterator fit = facets.begin(); fit != facets.end(); ++fit) @@ -380,34 +673,28 @@ private: std::make_pair(c3t3_.surface_patch_index(*fit), c3t3_.subdomain_index(fit->first)))); } - + return boundary_facets_from_outside; } - + /** - * A functor to remove one \c Cell_handle from a priority queue + * Add a cell \c ch to \c cells_queue */ - class Erase_from_queue + template + void add_cell_to_queue(Cell_handle ch, double criterion_value) { - public: - Erase_from_queue(Tet_priority_queue& queue) - : r_queue_(queue) { } - - void operator()(const Cell_handle& cell) - { r_queue_.erase(cell); } - - private: - Tet_priority_queue& r_queue_; - }; - - /** - * Delete cells of \c cells from \c cells_queue - */ - void delete_cells_from_queue(const Cell_vector& cells) - { - std::for_each(cells.begin(), cells.end(), Erase_from_queue(cells_queue_)); +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + enqueue_task( + ch, this->erase_counter(ch), criterion_value); + // Sequential + else +#endif + this->cells_queue_insert(ch, criterion_value); + } - + /** * A functor to remove one handle (Cell_handle/Facet_handle) from complex */ @@ -416,15 +703,15 @@ private: public: Remove_from_complex(C3T3& c3t3) : c3t3_(c3t3) { } - + template void operator()(const Handle_& handle) { c3t3_.remove_from_complex(handle); } - + private: C3T3& c3t3_; }; - + /** * Removes objects of [begin,end[ range from \c c3t3_ */ @@ -433,15 +720,15 @@ private: { std::for_each(begin, end, Remove_from_complex(c3t3_)); } - + /** * Returns true if time_limit is reached */ bool is_time_limit_reached() const { - return ( (time_limit() > 0) && (running_time_.time() > time_limit()) ); + return ( (time_limit() > 0) && (running_time_.time() > time_limit()) ); } - + /** * Returns true if all cells of mesh have a sliver_criteria_ value greater * than sliver_bound_ @@ -452,36 +739,139 @@ private: cit != c3t3_.cells_in_complex_end() ; ++cit) { - const double value = + const double value = sliver_criteria_(cit); if( value < sliver_criteria_.sliver_bound() ) return false; } - + return true; } - + +#ifdef CGAL_LINKED_WITH_TBB + // For parallel version + template + void + enqueue_task(Cell_handle ch, unsigned int erase_counter, double value); +#endif + private: + + +#ifdef CGAL_LINKED_WITH_TBB + + // Functor for enqueue_task function + template + class Pump_vertex + { + SE & m_sliver_exuder; + const C3T3 & m_c3t3; + Cell_handle m_cell_handle; + unsigned int m_erase_counter; + + + public: + // Constructor + Pump_vertex(SE &sliver_exuder, + const C3T3 &c3t3, + Cell_handle cell_handle, + unsigned int erase_counter) + : m_sliver_exuder(sliver_exuder), + m_c3t3(c3t3), + m_cell_handle(cell_handle), + m_erase_counter(erase_counter) + { + } + + // Constructor + Pump_vertex(const Pump_vertex &pvx) + : m_sliver_exuder(pvx.m_sliver_exuder), + m_c3t3(pvx.m_c3t3), + m_cell_handle(pvx.m_cell_handle), + m_erase_counter(pvx.m_erase_counter) + {} + + // operator() + void operator()() const + { +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + static Profile_branch_counter_3 bcounter( + "early withdrawals / late withdrawals / successes [Exuder]"); +#endif + + for( int i = 0; i < 4; ++i ) + { + bool could_lock_zone; + do + { + could_lock_zone = true; + + if (m_sliver_exuder.erase_counter(m_cell_handle) != m_erase_counter) + break; + + if (!m_c3t3.triangulation().try_lock_cell(m_cell_handle)) + { +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + bcounter.increment_branch_2(); // THIS is an early withdrawal! +#endif + could_lock_zone = false; + m_sliver_exuder.unlock_all_elements(); + continue; + } + + if (m_sliver_exuder.erase_counter(m_cell_handle) != m_erase_counter) + { + m_sliver_exuder.unlock_all_elements(); + break; + } + + // pump_vertices_on_surfaces is a boolean template parameter. The + // following condition is pruned at compiled time, if + // pump_vertices_on_surfaces==false. + if (pump_vertices_on_surfaces + || m_c3t3.in_dimension(m_cell_handle->vertex(i)) > 2) + { + m_sliver_exuder.template pump_vertex( + m_cell_handle->vertex(i), &could_lock_zone); + +#ifdef CGAL_CONCURRENT_MESH_3_PROFILING + if (!could_lock_zone) + bcounter.increment_branch_1(); // THIS is a late withdrawal! + else + ++bcounter; // Success! +#endif + } + + m_sliver_exuder.unlock_all_elements(); + } while (!could_lock_zone); + } + + if ( m_sliver_exuder.is_time_limit_reached() ) + tbb::task::self().cancel_group_execution(); + } + }; +#endif + // ----------------------------------- // Private data // ----------------------------------- C3T3& c3t3_; Tr& tr_; double sq_delta_; - + int num_of_pumped_vertices_; int num_of_ignored_vertices_; int num_of_treated_vertices_; - + bool initialized_; SliverCriteria sliver_criteria_; - Tet_priority_queue cells_queue_; - + C3T3_helpers helper_; + // Timer double time_limit_; CGAL::Timer running_time_; - + #ifdef CGAL_MESH_3_DEBUG_SLIVERS_EXUDER // ----------------------------------- // Debug Helpers @@ -493,9 +883,9 @@ private: static bool near_equal(const double& d1, const double& d2) { const double epsilon = 1e-8; - return ( ((d1-d2) >= -1*epsilon) && ((d1-d2) <= epsilon) ); + return ( ((d1-d2) >= -1*epsilon) && ((d1-d2) <= epsilon) ); } - + /** * Prints a double */ @@ -503,10 +893,10 @@ private: { std::cerr << d << " ; "; } - + /** This function verifies that the pre_star contains exactly the set of facets given by the sequence [begin, end[. - + If v!=0, it also fills another Pre_star object, from the sequence [begin, end[, and checks that is in the same order as pre_star. */ @@ -515,18 +905,18 @@ private: Input_facet_it begin, Input_facet_it end, const Vertex_handle v = Vertex_handle()) const; - + /** This function verifies that the pre_star contains exactly the set of facets on the boundary of the conflict zone of the weighted point wp. The vertex handle vh is an hint for the location of wp. - + It also fills another Pre_star object, and checks that is in the same order as pre_star. */ bool check_pre_star(const Pre_star& pre_star, const Weighted_point& wp, const Vertex_handle& vh) const; - + /** * Checks if the sliver criterion values from \c criterion_values are the same as * those that will be found if wp is inserted in the triangulation @@ -536,15 +926,17 @@ private: const Vertex_handle& vh) const; #endif // CGAL_MESH_3_DEBUG_SLIVERS_EXUDER - + }; // end class Slivers_exuder - - -template -Slivers_exuder:: -Slivers_exuder(C3T3& c3t3, const SC& criteria, double d) - : c3t3_(c3t3) + + +template +Slivers_exuder:: +Slivers_exuder(C3T3& c3t3, const Md& domain, const SC& criteria, double d) + : Base(c3t3.bbox(), + Concurrent_mesher_config::get().locking_grid_num_cells_per_axis) + , c3t3_(c3t3) , tr_(c3t3_.triangulation()) , sq_delta_(d*d) , num_of_pumped_vertices_(0) @@ -552,136 +944,216 @@ Slivers_exuder(C3T3& c3t3, const SC& criteria, double d) , num_of_treated_vertices_(0) , initialized_(false) , sliver_criteria_(criteria) + , helper_(c3t3_,domain,get_lock_data_structure()) , time_limit_(-1) , running_time_() { -} - + // If we're multi-thread + tr_.set_lock_data_structure(get_lock_data_structure()); +} -template + +template template Mesh_optimization_return_code -Slivers_exuder:: +Slivers_exuder:: pump_vertices(double sliver_criterion_limit, Visitor& visitor) { +#ifdef CGAL_MESH_3_PROFILING + WallClockTimer t; +#endif + init(sliver_criterion_limit); - + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << std::endl << "==== Init time: " + << t.elapsed() << "s ====" << std::endl; +#endif + #ifdef CGAL_MESH_3_EXUDER_VERBOSE std::cerr << "Exuding...\n"; std::cerr << "Legend of the following line: " << "(#cells left,#vertices pumped,#vertices ignored)" << std::endl; - std::cerr << "(" << cells_queue_.size() << ",0,0)"; + std::cerr << "(" << this->cells_queue_size() << ",0,0)"; #endif // CGAL_MESH_3_EXUDER_VERBOSE - + running_time_.reset(); running_time_.start(); - - while( !cells_queue_.empty() && !is_time_limit_reached() ) - { - typename Tet_priority_queue::Reverse_entry front = *(cells_queue_.front()); - Cell_handle c = front.second; - - bool vertex_pumped = false; - for( int i = 0; i < 4; ++i ) - { - // pump_vertices_on_surfaces is a boolean template parameter. The - // following condition is pruned at compiled time, if - // pump_vertices_on_surfaces==false. - if( pump_vertices_on_surfaces || c3t3_.in_dimension(c->vertex(i)) > 2 ) - { - if( pump_vertex(c->vertex(i)) ) - { - vertex_pumped = true; - ++num_of_pumped_vertices_; - break; - } - else - ++num_of_ignored_vertices_; - - ++num_of_treated_vertices_; - } - } - - // if the tet could not be deleted - if ( ! vertex_pumped ) - cells_queue_.pop_front(); - visitor.after_cell_pumped(cells_queue_.size()); -#ifdef CGAL_MESH_3_EXUDER_VERBOSE - std::cerr << boost::format("\r \r" - "(%1%,%2%,%3%) (%|4$.1f| vertices/s)") - % cells_queue_.size() - % num_of_pumped_vertices_ - % num_of_ignored_vertices_ - % (num_of_treated_vertices_ / running_time_.time()); -#endif // CGAL_MESH_3_EXUDER_VERBOSE +#ifdef CGAL_MESH_3_PROFILING + t.reset(); +#endif + + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_convertible::value) + { + this->create_root_task(); + + while (!this->cells_queue_empty()) + { + Queue_value_type front = *(this->cells_queue_front()); + this->cells_queue_pop_front(); + Cell_handle c = this->extract_cell_handle_from_queue_value(front); + double q = this->extract_cell_quality_from_queue_value(front); + unsigned int ec = this->extract_erase_counter_from_queue_value(front); + // Low quality first (i.e. low value of q) + enqueue_task(c, ec, q); + } + + this->wait_for_all(); + +# if defined(CGAL_MESH_3_EXUDER_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << " Flushing"; +# endif + bool keep_flushing = true; + while (keep_flushing) + { + keep_flushing = this->flush_work_buffers(); +# if defined(CGAL_MESH_3_EXUDER_VERBOSE) || defined(CGAL_MESH_3_PROFILING) + std::cerr << "."; +# endif + } + + this->destroy_root_task(); } - + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + while( !this->cells_queue_empty() && !is_time_limit_reached() ) + { + Queue_value_type front = *(this->cells_queue_front()); + Cell_handle c = this->extract_cell_handle_from_queue_value(front); + + // Low quality first (i.e. low value of cell quality) + bool vertex_pumped = false; + for( int i = 0; i < 4; ++i ) + { + // pump_vertices_on_surfaces is a boolean template parameter. The + // following condition is pruned at compiled time, if + // pump_vertices_on_surfaces==false. + if( pump_vertices_on_surfaces || c3t3_.in_dimension(c->vertex(i)) > 2 ) + { + if( pump_vertex(c->vertex(i)) ) + { + vertex_pumped = true; + ++num_of_pumped_vertices_; + break; + } + else + ++num_of_ignored_vertices_; + + ++num_of_treated_vertices_; + } + } + + // if the tet could not be deleted + if ( ! vertex_pumped ) + this->cells_queue_pop_front(); + + visitor.after_cell_pumped(this->cells_queue_size()); + #ifdef CGAL_MESH_3_EXUDER_VERBOSE + std::cerr << boost::format("\r \r" + "(%1%,%2%,%3%) (%|4$.1f| vertices/s)") + % this->cells_queue_size() + % num_of_pumped_vertices_ + % num_of_ignored_vertices_ + % (num_of_treated_vertices_ / running_time_.time()); + #endif // CGAL_MESH_3_EXUDER_VERBOSE + } + } + running_time_.stop(); - -#ifdef CGAL_MESH_3_EXUDER_VERBOSE + +#ifdef CGAL_MESH_3_PROFILING + std::cerr << std::endl << "==== Iterations time: " + << t.elapsed() << "s ====" << std::endl; +#endif + + +#ifdef CGAL_MESH_3_EXUDER_VERBOSE std::cerr << std::endl; std::cerr << "Total exuding time: " << running_time_.time() << "s"; std::cerr << std::endl; -#endif // CGAL_MESH_3_EXUDER_VERBOSE - +#endif // CGAL_MESH_3_EXUDER_VERBOSE + if ( is_time_limit_reached() ) { #ifdef CGAL_MESH_3_EXUDER_VERBOSE std::cerr << "Exuding return code: TIME_LIMIT_REACHED\n\n"; #endif // CGAL_MESH_3_EXUDER_VERBOSE return TIME_LIMIT_REACHED; } - + if ( check_sliver_bound() ) { #ifdef CGAL_MESH_3_EXUDER_VERBOSE std::cerr << "Exuding return code: BOUND_REACHED\n\n"; #endif // CGAL_MESH_3_EXUDER_VERBOSE return BOUND_REACHED; } - + #ifdef CGAL_MESH_3_EXUDER_VERBOSE std::cerr << "Exuding return code: CANT_IMPROVE_ANYMORE\n\n"; #endif // CGAL_MESH_3_EXUDER_VERBOSE return CANT_IMPROVE_ANYMORE; - + } // end function pump_vertices -template +template +template bool -Slivers_exuder:: -pump_vertex(const Vertex_handle& pumped_vertex) +Slivers_exuder:: +pump_vertex(const Vertex_handle& pumped_vertex, + bool *could_lock_zone) { // Get best_weight - double best_weight = get_best_weight(pumped_vertex); - + double best_weight = get_best_weight(pumped_vertex, could_lock_zone); + if (could_lock_zone && *could_lock_zone == false) + return false; + // If best_weight < pumped_vertex weight, nothing to do if ( best_weight > pumped_vertex->point().weight() ) { Weighted_point wp(pumped_vertex->point(), best_weight); - + // Insert weighted point into mesh - update_mesh(wp, pumped_vertex); - + update_mesh(wp, pumped_vertex, could_lock_zone); + return true; } - + return false; } - - -template + + +template void -Slivers_exuder:: +Slivers_exuder:: initialize_prestar_and_criterion_values(const Vertex_handle& v, Pre_star& pre_star, - Sliver_values& criterion_values) const + Sliver_values& criterion_values, + bool *could_lock_zone) const { std::vector incident_cells; incident_cells.reserve(64); - tr_.incident_cells(v, std::back_inserter(incident_cells)); + // Parallel + if (could_lock_zone) + { + if (!helper_.try_lock_and_get_incident_cells(v, incident_cells)) + { + *could_lock_zone = false; + return; + } + } + // Sequential + else + { + tr_.incident_cells(v, std::back_inserter(incident_cells)); + } for ( typename Cell_vector::const_iterator cit = incident_cells.begin() ; cit != incident_cells.end() ; @@ -690,30 +1162,30 @@ initialize_prestar_and_criterion_values(const Vertex_handle& v, const int index = (*cit)->index(v); const Facet f = Facet(*cit, index); const Facet opposite_facet = tr_.mirror_facet(f); - + // Sliver criterion values initialization if( c3t3_.is_in_complex(*cit) ) { criterion_values[f] = sliver_criteria_(*cit); } - + // Pre_star initialization // If facet is adjacent to and infinite cell, no need to put it in prestar // (infinite critical radius) if ( tr_.is_infinite(opposite_facet.first) ) continue; - + // Insert facet in prestar (even if it is not in complex) double critical_radius = compute_critical_radius(v, opposite_facet.first); - pre_star.insert(f, critical_radius); + pre_star.insert(f, critical_radius); } } - - -template + + +template bool -Slivers_exuder:: +Slivers_exuder:: expand_prestar(const Cell_handle& cell_to_add, const Vertex_handle& pumped_vertex, Pre_star& pre_star, @@ -728,21 +1200,21 @@ expand_prestar(const Cell_handle& cell_to_add, pre_star.pop_front(); if ( c3t3_.is_in_complex(cell_to_add) ) { - criterion_values.erase(start_facet); + criterion_values.erase(start_facet); } - + int start_mirror_facet_index = tr_.mirror_facet(start_facet).second; - + // For each facet of cell_to_add for(int i = 0; i<4 ; ++i) { // We have already treated start_facet if ( i == start_mirror_facet_index ) continue; - + const Facet current_facet(cell_to_add, i); const Facet current_mirror_facet(tr_.mirror_facet(current_facet)); - + // If current_facet_mirror is in prestar, delete it // (it may happen than pre_star contains two facets of the same cell) if ( pre_star.erase(current_mirror_facet) ) @@ -752,84 +1224,89 @@ expand_prestar(const Cell_handle& cell_to_add, { return false; } - + // Update criterion_values if ( c3t3_.is_in_complex(cell_to_add) ) - { + { criterion_values.erase(current_mirror_facet); } } // If current_mirror_facet is not in prestar: - // expand prestar & update criterion_values - else + // expand prestar & update criterion_values + else { const Cell_handle& current_mirror_cell = current_mirror_facet.first; - + CGAL_assertion(current_mirror_cell != start_facet.first); CGAL_assertion(pumped_vertex != current_mirror_facet.first->vertex(0)); CGAL_assertion(pumped_vertex != current_mirror_facet.first->vertex(1)); CGAL_assertion(pumped_vertex != current_mirror_facet.first->vertex(2)); CGAL_assertion(pumped_vertex != current_mirror_facet.first->vertex(3)); - + // Update pre_star (we do not insert facets with infinite critical radius) - // We do insert facet of cells which are outside the complex (we just + // We do insert facet of cells which are outside the complex (we just // don't use their sliver criterion value to get best weight) if ( ! tr_.is_infinite(current_mirror_cell) ) { - double new_critical_radius = + double new_critical_radius = compute_critical_radius(pumped_vertex, current_mirror_cell); pre_star.insert(current_facet, new_critical_radius); -#ifdef CGAL_MESH_3_DEBUG_SLIVERS_EXUDER +#ifdef CGAL_MESH_3_DEBUG_SLIVERS_EXUDER if ( new_critical_radius < critical_radius ) std::cerr << "new critical radius:" << new_critical_radius << " / current critical radius:" << critical_radius - << std::endl; + << std::endl; #endif // CGAL_MESH_3_DEBUG_SLIVERS_EXUDER } - + // Update ratio (ratio is needed for cells of complex only) if ( c3t3_.is_in_complex(cell_to_add) ) - { + { Tetrahedron_3 tet(pumped_vertex->point(), cell_to_add->vertex((i+1)&3)->point(), cell_to_add->vertex((i+2)&3)->point(), cell_to_add->vertex((i+3)&3)->point()); - + double new_value = sliver_criteria_(tet); criterion_values.insert(std::make_pair(current_facet,new_value)); } } - } - + } + return true; } - -template + +template double -Slivers_exuder:: -get_best_weight(const Vertex_handle& v) const +Slivers_exuder:: +get_best_weight(const Vertex_handle& v, bool *could_lock_zone) const { // Get pre_star and criterion_values Pre_star pre_star; Sliver_values criterion_values; - initialize_prestar_and_criterion_values(v, pre_star, criterion_values); + initialize_prestar_and_criterion_values( + v, pre_star, criterion_values, could_lock_zone); -#ifdef CGAL_MESH_3_DEBUG_SLIVERS_EXUDER + if (could_lock_zone && *could_lock_zone == false) + return 0.; + +#ifdef CGAL_MESH_3_DEBUG_SLIVERS_EXUDER Pre_star pre_star_copy; Sliver_values ratios_copy; #endif - + double worst_criterion_value = get_min_value(criterion_values); double best_weight = 0; + // TODO: it seems that this computes the incident cells again double sq_d_v = get_closest_vertice_squared_distance(v); - + // If that boolean is set to false, it means that a facet in the complex // is about to be flipped. In that case, the pumping is stopped. bool can_flip = true; - + // Main loop: find the weight which maximizes the minimum value of ratio while( can_flip && ! pre_star.empty() @@ -838,57 +1315,63 @@ get_best_weight(const Vertex_handle& v) const { // Store critial radius (pre_star will be modified in expand_prestar) double critical_r = pre_star.front()->first; - - // expand prestar (insert opposite_cell facets in pre_star) + + // expand prestar (insert opposite_cell facets in pre_star) Facet link = pre_star.front()->second; const Cell_handle& opposite_cell = tr_.mirror_facet(link).first; + + if (could_lock_zone && !tr_.try_lock_cell(opposite_cell)) + { + *could_lock_zone = false; + return 0.; + } can_flip = expand_prestar(opposite_cell, v, pre_star, criterion_values); - + // Update best_weight if needed if(can_flip) { double min_of_pre_star = get_min_value(criterion_values); - + if( min_of_pre_star > worst_criterion_value ) { // Update worst_criterion_value worst_criterion_value = min_of_pre_star; - + // Update best_weight CGAL_assertion(!pre_star.empty()); double next_r = pre_star.front()->first; best_weight = (critical_r + next_r) / 2; - -#ifdef CGAL_MESH_3_DEBUG_SLIVERS_EXUDER + +#ifdef CGAL_MESH_3_DEBUG_SLIVERS_EXUDER pre_star_copy = pre_star; ratios_copy = criterion_values; -#endif // CGAL_MESH_3_DEBUG_SLIVERS_EXUDER +#endif // CGAL_MESH_3_DEBUG_SLIVERS_EXUDER } } } // end while(... can pump...) - - -#ifdef CGAL_MESH_3_DEBUG_SLIVERS_EXUDER + + +#ifdef CGAL_MESH_3_DEBUG_SLIVERS_EXUDER if ( best_weight > v->point().weight() ) { Weighted_point wp(v->point(), best_weight); check_pre_star(pre_star_copy, wp, v); check_ratios(ratios_copy, wp, v); } -#endif // CGAL_MESH_3_DEBUG_SLIVERS_EXUDER - +#endif // CGAL_MESH_3_DEBUG_SLIVERS_EXUDER + return best_weight; } - -template -typename Slivers_exuder::Umbrella -Slivers_exuder:: + +template +typename Slivers_exuder::Umbrella +Slivers_exuder:: get_umbrella(const Facet_vector& facets, const Vertex_handle& v) const { Umbrella umbrella; - + // Insert into umbrella surface_index of facets which are on the surface typename Facet_vector::const_iterator fit = facets.begin(); for ( ; fit != facets.end() ; ++fit ) @@ -899,14 +1382,15 @@ get_umbrella(const Facet_vector& facets, umbrella.insert(std::make_pair(edge, c3t3_.surface_patch_index(*fit))); } } - + return umbrella; } - -template + +template +template void -Slivers_exuder:: +Slivers_exuder:: restore_cells_and_boundary_facets( const Boundary_facets_from_outside& boundary_facets_from_outside, const Vertex_handle& new_vertex) @@ -914,10 +1398,10 @@ restore_cells_and_boundary_facets( Cell_vector new_cells; new_cells.reserve(64); tr_.incident_cells(new_vertex, std::back_inserter(new_cells)); - + // Each cell must have a facet on the boundary of the conflict zone CGAL_assertion(boundary_facets_from_outside.size() == new_cells.size()); - + // Restore attributes of each cell for(typename Cell_vector::iterator cit = new_cells.begin(); cit != new_cells.end(); @@ -927,51 +1411,51 @@ restore_cells_and_boundary_facets( const int index = (*cit)->index(new_vertex); const Facet new_facet = std::make_pair(*cit, index); const Facet new_facet_from_outside = tr_.mirror_facet(new_facet); - + // Search new_facet_from_outside in boundary_facets_from_outside. // That search cannot fail. typename Boundary_facets_from_outside::const_iterator it = boundary_facets_from_outside.find(new_facet_from_outside); - + CGAL_assertion(it != boundary_facets_from_outside.end()); - + // Restore facet attributes if ( it->second.first != Surface_patch_index() ) c3t3_.add_to_complex(new_facet, it->second.first); - + // Restore cell attributes if ( it->second.second != Subdomain_index() ) c3t3_.add_to_complex(*cit, it->second.second); - + // if the new cell is in the domain, and it criterion value is less that // the maximum, push it in the cells queue. if( c3t3_.is_in_complex(*cit) ) { - double criterion_value + double criterion_value = sliver_criteria_(*cit); - - if( criterion_value < sliver_criteria_.sliver_bound() ) - cells_queue_.insert(*cit, criterion_value); - } - } -} - - -template -typename Slivers_exuder::Ordered_edge -Slivers_exuder::get_opposite_ordered_edge( + if( criterion_value < sliver_criteria_.sliver_bound() ) + add_cell_to_queue(*cit, criterion_value); + } + } +} + + + +template +typename Slivers_exuder::Ordered_edge +Slivers_exuder::get_opposite_ordered_edge( const Facet& facet, const Vertex_handle& vertex) const { Vertex_handle v1; Vertex_handle v2; - + // Get the two vertex of *fit which are not new_vertex for ( int i = 0 ; i < 4 ; ++i ) { const Vertex_handle current_vertex = facet.first->vertex(i); - + if ( current_vertex != vertex && tr_.has_vertex(facet, current_vertex) ) { if ( v1 == Vertex_handle() ) @@ -980,24 +1464,24 @@ Slivers_exuder::get_opposite_ordered_edge( v2 = current_vertex; } } - + CGAL_assertion(v1 != Vertex_handle() && v2 != Vertex_handle()); - + order_two_handles(v1,v2); return Ordered_edge(v1,v2); } - - -template + + +template void -Slivers_exuder:: +Slivers_exuder:: restore_internal_facets(const Umbrella& umbrella, const Vertex_handle& new_vertex) { Facet_vector new_internal_facets; new_internal_facets.reserve(64); tr_.incident_facets(new_vertex, std::back_inserter(new_internal_facets)); - + // Restore attributes of each facet for(typename Facet_vector::iterator fit = new_internal_facets.begin(); fit != new_internal_facets.end(); @@ -1015,65 +1499,91 @@ restore_internal_facets(const Umbrella& umbrella, } } - -template + +template +template void -Slivers_exuder:: +Slivers_exuder:: update_mesh(const Weighted_point& new_point, - const Vertex_handle& old_vertex) + const Vertex_handle& old_vertex, + bool *could_lock_zone) { - CGAL_assertion_code(std::size_t nb_vert = + CGAL_assertion_code(std::size_t nb_vert = tr_.number_of_vertices()); Cell_vector deleted_cells; Facet_vector internal_facets; Facet_vector boundary_facets; - + deleted_cells.reserve(64); internal_facets.reserve(64); boundary_facets.reserve(64); - + tr_.find_conflicts(new_point, old_vertex->cell(), std::back_inserter(boundary_facets), std::back_inserter(deleted_cells), - std::back_inserter(internal_facets)); - + std::back_inserter(internal_facets), + could_lock_zone); + + if (could_lock_zone && *could_lock_zone == false) + return; + // Get some datas to restore mesh Boundary_facets_from_outside boundary_facets_from_outside = get_boundary_facets_from_outside(boundary_facets); - + Umbrella umbrella = get_umbrella(internal_facets, old_vertex); // Delete old cells from queue (they aren't in the triangulation anymore) - delete_cells_from_queue(deleted_cells); - + this->delete_cells_from_queue(deleted_cells); + // Delete old cells & facets from c3t3 remove_from_c3t3(deleted_cells.begin(),deleted_cells.end()); remove_from_c3t3(boundary_facets.begin(),boundary_facets.end()); remove_from_c3t3(internal_facets.begin(),internal_facets.end()); - + // Insert new point (v will be updated using a wp) int dimension = c3t3_.in_dimension(old_vertex); Index vertice_index = c3t3_.index(old_vertex); - - Vertex_handle new_vertex = tr_.insert(new_point); + + Vertex_handle new_vertex = tr_.insert(new_point, old_vertex->cell()); c3t3_.set_dimension(new_vertex,dimension); c3t3_.set_index(new_vertex,vertice_index); - CGAL_assertion(nb_vert == tr_.number_of_vertices()); - + // Only true for sequential version + CGAL_assertion(could_lock_zone || nb_vert == tr_.number_of_vertices()); + // Restore mesh - restore_cells_and_boundary_facets(boundary_facets_from_outside, new_vertex); + restore_cells_and_boundary_facets( + boundary_facets_from_outside, new_vertex); restore_internal_facets(umbrella, new_vertex); - CGAL_assertion(nb_vert == tr_.number_of_vertices()); + + // Only true for sequential version + CGAL_assertion(could_lock_zone || nb_vert == tr_.number_of_vertices()); } - -#ifdef CGAL_MESH_3_DEBUG_SLIVERS_EXUDER -template + +#ifdef CGAL_LINKED_WITH_TBB +// For parallel version +template +template +void +Slivers_exuder:: +enqueue_task(Cell_handle ch, unsigned int erase_counter, double value) +{ + this->enqueue_work( + Pump_vertex( + *this, c3t3_, ch, erase_counter), + value); +} +#endif + + +#ifdef CGAL_MESH_3_DEBUG_SLIVERS_EXUDER +template template bool -Slivers_exuder:: +Slivers_exuder:: check_pre_star(const Pre_star& pre_star, Input_facet_it begin, Input_facet_it end, @@ -1083,7 +1593,7 @@ check_pre_star(const Pre_star& pre_star, if(v != Vertex_handle()) { Pre_star pre_star2; - + // fill pre_star2 for(Input_facet_it fit = begin; fit != end; @@ -1096,7 +1606,7 @@ check_pre_star(const Pre_star& pre_star, opposite_facet.first)); } } - + while(!pre_star_copy.empty() && !pre_star2.empty()) { if(pre_star_copy.front()->first != pre_star2.front()->first) { @@ -1105,7 +1615,7 @@ check_pre_star(const Pre_star& pre_star, % pre_star_copy.front()->first % pre_star2.front()->first; return false; } - if ( pre_star_copy.front()->second != pre_star2.front()->second ) + if ( pre_star_copy.front()->second != pre_star2.front()->second ) { Facet f1 = pre_star_copy.front()->second; Facet f2 = pre_star2.front()->second; @@ -1131,7 +1641,7 @@ check_pre_star(const Pre_star& pre_star, pre_star_copy.pop_front(); } } - + if(pre_star2.empty() && ! pre_star_copy.empty()) { std::cerr << "pre_star is too big!\n"; while(!pre_star_copy.empty()) @@ -1145,7 +1655,7 @@ check_pre_star(const Pre_star& pre_star, } return false; } - + if( pre_star_copy.empty() && ! pre_star2.empty() ) { std::cerr << "pre_star is too small!\n"; while(!pre_star2.empty()) @@ -1158,9 +1668,9 @@ check_pre_star(const Pre_star& pre_star, return false; } } - + pre_star_copy = pre_star; - + for(Input_facet_it fit = begin; fit != end; ++fit) @@ -1171,28 +1681,28 @@ check_pre_star(const Pre_star& pre_star, } if( !pre_star_copy.empty() ) return false; - + return true; } - -template + +template bool -Slivers_exuder:: +Slivers_exuder:: check_pre_star(const Pre_star& pre_star, const Weighted_point& wp, const Vertex_handle& vh) const { std::vector boundary_facets; boundary_facets.reserve(64); - + tr_.find_conflicts(wp, vh->cell(), std::back_inserter(boundary_facets), CGAL::Emptyset_iterator(), CGAL::Emptyset_iterator()); - + const bool result = check_pre_star(pre_star, boundary_facets.begin(), boundary_facets.end(), @@ -1205,10 +1715,10 @@ check_pre_star(const Pre_star& pre_star, return result; } - -template + +template bool -Slivers_exuder:: +Slivers_exuder:: check_ratios(const Sliver_values& criterion_values, const Weighted_point& wp, const Vertex_handle& vh) const @@ -1216,40 +1726,40 @@ check_ratios(const Sliver_values& criterion_values, Cell_vector deleted_cells; Facet_vector internal_facets; Facet_vector boundary_facets; - + tr_.find_conflicts(wp, vh->cell(), std::back_inserter(boundary_facets), std::back_inserter(deleted_cells), std::back_inserter(internal_facets)); - + bool result = true; std::vector expected_ratios; std::vector ratio_vector; - + for ( typename Sliver_values::const_iterator rit = criterion_values.begin() ; rit != criterion_values.end() ; ++rit ) { ratio_vector.push_back(rit->second); } - + for ( typename Facet_vector::const_iterator it = boundary_facets.begin() ; it != boundary_facets.end() ; ++ it ) { if ( !c3t3_.is_in_complex((it->first)) ) continue; - + int k = it->second; Tetrahedron_3 tet(vh->point(), it->first->vertex((k+1)&3)->point(), it->first->vertex((k+2)&3)->point(), it->first->vertex((k+3)&3)->point()); - + double ratio = sliver_criteria_(tet); - expected_ratios.push_back(ratio); - + expected_ratios.push_back(ratio); + bool found = false; for ( typename Sliver_values::const_iterator rit = criterion_values.begin() ; rit != criterion_values.end() ; @@ -1262,14 +1772,14 @@ check_ratios(const Sliver_values& criterion_values, } } if ( ! found ) - { + { result = false; } } - + if (expected_ratios.size() != criterion_values.size()) result = false; - + if ( !result ) { std::sort(expected_ratios.begin(),expected_ratios.end()); @@ -1278,8 +1788,8 @@ check_ratios(const Sliver_values& criterion_values, std::set_difference(expected_ratios.begin(),expected_ratios.end(), ratio_vector.begin(),ratio_vector.end(), std::back_inserter(diff)); - - + + std::cerr << "\nExpected criterion_values:["; std::for_each(expected_ratios.begin(), expected_ratios.end(), print_double); std::cerr << "]\nRatios:["; @@ -1288,11 +1798,11 @@ check_ratios(const Sliver_values& criterion_values, std::for_each(diff.begin(),diff.end(), print_double); std::cerr << "]\n"; } - + return result; } #endif // CGAL_MESH_3_DEBUG_SLIVERS_EXUDER - + } // end namespace Mesh_3 diff --git a/Mesh_3/include/CGAL/Mesh_3/Triangulation_helpers.h b/Mesh_3/include/CGAL/Mesh_3/Triangulation_helpers.h index f001a67c722..200d4f816e5 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Triangulation_helpers.h +++ b/Mesh_3/include/CGAL/Mesh_3/Triangulation_helpers.h @@ -19,7 +19,7 @@ // Author(s) : Stephane Tayeb // //****************************************************************************** -// File Description : +// File Description : //****************************************************************************** #ifndef CGAL_MESH_3_TRIANGULATION_HELPERS_H @@ -31,8 +31,8 @@ namespace CGAL { namespace Mesh_3 { - - + + template class Triangulation_helpers { @@ -41,7 +41,7 @@ class Triangulation_helpers typedef typename Tr::Vertex_handle Vertex_handle; typedef typename Tr::Cell_handle Cell_handle; typedef std::vector Cell_vector; - + /** * A functor to reset visited flag of each facet of a cell */ @@ -53,19 +53,41 @@ class Triangulation_helpers c->reset_visited(i); } }; - + + /** + * A functor to get the point of a vertex vh, but replacing + * it by m_p when vh == m_vh + */ + struct Point_getter + { + /// When the requested will be about vh, the returned point will be p + /// instead of vh->point() + Point_getter(const Vertex_handle &vh, const Point_3&p) + : m_vh(vh), m_p(p) + {} + + const Point_3& operator()(const Vertex_handle &vh) const + { + return (vh == m_vh ? m_p : vh->point()); + } + + private: + const Vertex_handle m_vh; + const Point_3 &m_p; + }; + public: /// Constructor / Destructor Triangulation_helpers() {} ~Triangulation_helpers() {} - + /** * Moves point from \c v to \c p. */ void move_point(Tr& tr, const Vertex_handle& v, const Point_3& p) const; - + /** * Returns true if moving \c v to \c p makes no topological * change in \c tr @@ -74,11 +96,20 @@ public: const Vertex_handle& v, const Point_3& p, Cell_vector& cells_tos) const; - + bool no_topological_change__without_set_point( + const Tr& tr, + const Vertex_handle& v, + const Point_3& p, + Cell_vector& cells_tos) const; bool no_topological_change(const Tr& tr, const Vertex_handle& v, const Point_3& p) const; + bool no_topological_change__without_set_point( + const Tr& tr, + const Vertex_handle& v, + const Point_3& p) const; + bool inside_protecting_balls(const Tr& tr, const Vertex_handle& v, @@ -88,11 +119,16 @@ private: /** * Returns true if \c v is well_oriented on each cell of \c cell_tos */ + // For sequential version bool well_oriented(const Tr& tr, const Cell_vector& cell_tos) const; + // For parallel version + bool well_oriented(const Tr& tr, + const Cell_vector& cell_tos, + const Point_getter& pg) const; }; - - + + template void Triangulation_helpers:: @@ -108,7 +144,7 @@ move_point(Tr& tr, tr.remove(v); } } - + template bool Triangulation_helpers:: @@ -120,66 +156,149 @@ no_topological_change(const Tr& tr, bool np = true; Point_3 fp = v0->point(); v0->set_point(p); - -/// @TODO: One can do the same checks without the set_point. -/// In the following orientation or side_of_power_sphere tests, just -/// replace v0->point() by p. - if(!well_oriented(tr, cells_tos)) + if(!well_oriented(tr, cells_tos)) { // Reset (restore) v0 v0->set_point(fp); return false; } - + // Reset visited tags of facets std::for_each(cells_tos.begin(), cells_tos.end(), Reset_facet_visited()); - + for ( typename Cell_vector::iterator cit = cells_tos.begin() ; cit != cells_tos.end() ; ++cit ) { Cell_handle c = *cit; - for(int j=0; j<4; j++) + for(int j=0; j<4; j++) { // Treat each facet only once if(c->is_facet_visited(j)) continue; - + // Set facet and it's mirror's one visited Cell_handle cj = c->neighbor(j); int mj = tr.mirror_index(c, j); c->set_facet_visited(j); - cj->set_facet_visited(mj); - + cj->set_facet_visited(mj); + Vertex_handle v1 = c->vertex(j); - if(tr.is_infinite(v1)) + if(tr.is_infinite(v1)) { - if(tr.side_of_power_sphere(c, cj->vertex(mj)->point(), false) - != CGAL::ON_UNBOUNDED_SIDE) + if(tr.side_of_power_sphere(c, cj->vertex(mj)->point(), false) + != CGAL::ON_UNBOUNDED_SIDE) { - np = false; + np = false; break; } } else { - if(tr.side_of_power_sphere(cj, v1->point(), false) - != CGAL::ON_UNBOUNDED_SIDE) + if(tr.side_of_power_sphere(cj, v1->point(), false) + != CGAL::ON_UNBOUNDED_SIDE) { - np = false; + np = false; break; } } } } - + // Reset (restore) v0 v0->set_point(fp); return np; } - + +template +bool +Triangulation_helpers:: +no_topological_change__without_set_point( + const Tr& tr, + const Vertex_handle& v0, + const Point_3& p, + Cell_vector& cells_tos) const +{ + bool np = true; + + Point_getter pg(v0, p); + + if(!well_oriented(tr, cells_tos, pg)) + { + return false; + } + + // Reset visited tags of facets + std::for_each(cells_tos.begin(), cells_tos.end(), Reset_facet_visited()); + + for ( typename Cell_vector::iterator cit = cells_tos.begin() ; + cit != cells_tos.end() ; + ++cit ) + { + Cell_handle c = *cit; + for(int j=0; j<4; j++) + { + // Treat each facet only once + if(c->is_facet_visited(j)) + continue; + + // Set facet and it's mirror's one visited + Cell_handle cj = c->neighbor(j); + int mj = tr.mirror_index(c, j); + c->set_facet_visited(j); + cj->set_facet_visited(mj); + + Vertex_handle v1 = c->vertex(j); + if(tr.is_infinite(v1)) + { + // Build a copy of c, and replace V0 by a temporary vertex (position "p") + typename Cell_handle::value_type c_copy (*c); + int i_v0; + typename Vertex_handle::value_type v; + if (c_copy.has_vertex(v0, i_v0)) + { + v.set_point(p); + c_copy.set_vertex(i_v0, + Tr::Triangulation_data_structure::Vertex_range::s_iterator_to(v)); + } + + if(tr.side_of_power_sphere(&c_copy, pg(cj->vertex(mj)), false) + != CGAL::ON_UNBOUNDED_SIDE) + { + np = false; + break; + } + } + else + { + // Build a copy of cj, and replace V0 by a temporary vertex (position "p") + typename Cell_handle::value_type cj_copy (*cj); + int i_v0; + typename Vertex_handle::value_type v; + if (cj_copy.has_vertex(v0, i_v0)) + { + v.set_point(p); + cj_copy.set_vertex(i_v0, + Tr::Triangulation_data_structure::Vertex_range::s_iterator_to(v)); + } + + Cell_handle cj_copy_h = + Tr::Triangulation_data_structure::Cell_range::s_iterator_to(cj_copy); + if(tr.side_of_power_sphere(cj_copy_h, pg(v1), false) + != CGAL::ON_UNBOUNDED_SIDE) + { + np = false; + break; + } + } + } + } + + return np; +} + template bool @@ -194,6 +313,21 @@ no_topological_change(const Tr& tr, return no_topological_change(tr, v0, p, cells_tos); } +template +bool +Triangulation_helpers:: +no_topological_change__without_set_point( + const Tr& tr, + const Vertex_handle& v0, + const Point_3& p) const +{ + Cell_vector cells_tos; + cells_tos.reserve(64); + tr.incident_cells(v0, std::back_inserter(cells_tos)); + return no_topological_change__without_set_point(tr, v0, p, cells_tos); +} + + template bool Triangulation_helpers:: @@ -211,7 +345,6 @@ inside_protecting_balls(const Tr& tr, /// This function well_oriented is called by no_topological_change after a /// v->set_point(p) -/// @TODO: One can do the same checks without the set_point. template bool Triangulation_helpers:: @@ -222,7 +355,7 @@ well_oriented(const Tr& tr, for( ; it != cells_tos.end() ; ++it) { Cell_handle c = *it; - if( tr.is_infinite(c) ) + if( tr.is_infinite(c) ) { int iv = c->index(tr.infinite_vertex()); Cell_handle cj = c->neighbor(iv); @@ -240,12 +373,46 @@ well_oriented(const Tr& tr, return false; } return true; -} +} + +/// Another version for the parallel version +/// Here, the set_point is not done before, but we use a Point_getter instance +/// to get the point of a vertex. +template +bool +Triangulation_helpers:: +well_oriented(const Tr& tr, + const Cell_vector& cells_tos, + const Point_getter& pg) const +{ + typename Cell_vector::const_iterator it = cells_tos.begin(); + for( ; it != cells_tos.end() ; ++it) + { + Cell_handle c = *it; + if( tr.is_infinite(c) ) + { + int iv = c->index(tr.infinite_vertex()); + Cell_handle cj = c->neighbor(iv); + int mj = tr.mirror_index(c, iv); + if(CGAL::orientation(pg(cj->vertex(mj)), + pg(c->vertex((iv+1)&3)), + pg(c->vertex((iv+2)&3)), + pg(c->vertex((iv+3)&3))) != CGAL::NEGATIVE) + return false; + } + else if(CGAL::orientation(pg(c->vertex(0)), + pg(c->vertex(1)), + pg(c->vertex(2)), + pg(c->vertex(3))) != CGAL::POSITIVE) + return false; + } + return true; +} -} // end namespace Mesh_3 - +} // end namespace Mesh_3 + } //namespace CGAL #endif // CGAL_MESH_3_TRIANGULATION_HELPERS_H diff --git a/Mesh_3/include/CGAL/Mesh_3/Worksharing_data_structures.h b/Mesh_3/include/CGAL/Mesh_3/Worksharing_data_structures.h new file mode 100644 index 00000000000..ad4d7c5eb13 --- /dev/null +++ b/Mesh_3/include/CGAL/Mesh_3/Worksharing_data_structures.h @@ -0,0 +1,882 @@ +// Copyright (c) 2012 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: $ +// $Id: $ +// +// Author(s) : Clement Jamin + +#ifndef CGAL_MESH_3_WORKSHARING_DATA_STRUCTURES_H +#define CGAL_MESH_3_WORKSHARING_DATA_STRUCTURES_H + +#ifdef CGAL_LINKED_WITH_TBB + +#include + +#include + +#include +#include +#include +#include +#include + + +#include +#ifdef CGAL_MESH_3_TASK_SCHEDULER_SORTED_BATCHES_WITH_MULTISET +# include +#endif + +namespace CGAL { namespace Mesh_3 { + +// Forward declarations +class Load_based_worksharing_ds; +class Auto_worksharing_ds; + +// Typedef + +// Load-based +#ifdef CGAL_MESH_3_LOAD_BASED_WORKSHARING + typedef Load_based_worksharing_ds WorksharingDataStructureType; +// Task-scheduler with TLS work buffers +// => 1 work-buffer / thread +#else + typedef Auto_worksharing_ds WorksharingDataStructureType; +#endif + + + +class Work_statistics +{ +public: + // Constructors + + Work_statistics(const Bbox_3 &bbox, + int num_grid_cells_per_axis) + : m_num_grid_cells_per_axis(num_grid_cells_per_axis) + { + m_laziest_cell_index = 0; + m_laziest_cell_occupation = 1000; + + m_num_cells = + num_grid_cells_per_axis*num_grid_cells_per_axis*num_grid_cells_per_axis; + m_occupation_grid = new tbb::atomic[m_num_cells]; + m_num_batches_grid = new tbb::atomic[m_num_cells]; + // Initialize grid + for (int i = 0 ; i < m_num_cells ; ++i) + { + m_occupation_grid[i] = 0; + m_num_batches_grid[i] = 0; + } + + set_bbox(bbox); + } + + /// Destructor + virtual ~Work_statistics() + { + delete [] m_occupation_grid; + delete [] m_num_batches_grid; + } + + void set_bbox(const Bbox_3 &bbox) + { + // Keep mins and resolutions + m_xmin = bbox.xmin(); + m_ymin = bbox.ymin(); + m_zmin = bbox.zmin(); + double n = static_cast(m_num_grid_cells_per_axis); + m_resolution_x = n / (bbox.xmax() - m_xmin); + m_resolution_y = n / (bbox.ymax() - m_ymin); + m_resolution_z = n / (bbox.zmax() - m_zmin); + +#ifdef CGAL_CONCURRENT_MESH_3_VERBOSE + std::cerr << "Worksharing data structure Bounding Box = [" + << bbox.xmin() << ", " << bbox.xmax() << "], " + << bbox.ymin() << ", " << bbox.ymax() << "], " + << bbox.zmin() << ", " << bbox.zmax() << "]" + << std::endl; +#endif + } + + void add_batch(int cell_index, int to_add) + { + m_num_batches_grid[cell_index].fetch_and_add(to_add); + } + + void add_occupation(int cell_index, int to_add, int num_items_in_work_queue) + { + m_occupation_grid[cell_index].fetch_and_add(to_add); + + /*int new_occupation = + (m_occupation_grid[cell_index].fetch_and_add(to_add)) + + to_add; + //m_num_batches_grid[cell_index] = num_items_in_work_queue; + + // If this cell is the current most lazy, update the value + if (cell_index == m_laziest_cell_index) + { + if (num_items_in_work_queue == 0) + // So that it won't stay long the laziest + m_laziest_cell_occupation = 999999; + else + m_laziest_cell_occupation = new_occupation; + } + else if (num_items_in_work_queue > 0 + && new_occupation <= m_laziest_cell_occupation) + { + m_laziest_cell_index = cell_index; + m_laziest_cell_occupation = new_occupation; + }*/ + } + + void add_occupation(int index_x, int index_y, int index_z, + int to_add, int num_items_in_work_queue) + { + int index = + index_z*m_num_grid_cells_per_axis*m_num_grid_cells_per_axis + + index_y*m_num_grid_cells_per_axis + + index_x; + return add_occupation(index, to_add, num_items_in_work_queue); + } + + /// P3 must provide .x(), .y(), .z() + template + int compute_index(const P3 &point) const + { + // Compute indices on grid + int index_x = static_cast( (to_double(point.x()) - m_xmin) * m_resolution_x); + index_x = std::max( 0, std::min(index_x, m_num_grid_cells_per_axis - 1) ); + int index_y = static_cast( (to_double(point.y()) - m_ymin) * m_resolution_y); + index_y = std::max( 0, std::min(index_y, m_num_grid_cells_per_axis - 1) ); + int index_z = static_cast( (to_double(point.z()) - m_zmin) * m_resolution_z); + index_z = std::max( 0, std::min(index_z, m_num_grid_cells_per_axis - 1) ); + + int index = + index_z*m_num_grid_cells_per_axis*m_num_grid_cells_per_axis + + index_y*m_num_grid_cells_per_axis + + index_x; + + return index; + } + + /// P3 must provide .x(), .y(), .z() + // Returns index in grid + template + int add_occupation(const P3 &point, int to_add, int num_items_in_work_queue) + { + int index = compute_index(point); + add_occupation(index, to_add, num_items_in_work_queue); + return index; + } + + int get_laziest_cell_index() const + { + //return m_laziest_cell_index; + + + /* + // Look for best occupation/work ratio + int laziest_index = 0; + float laziest_ratio = 200000.f; + for (int i = 0 ; i < m_num_cells ; ++i) + { + if (m_num_batches_grid[i] > 0) + { + float ratio = + static_cast(m_occupation_grid[i]) + / m_num_batches_grid[i]; + if (ratio < laziest_ratio) + { + laziest_index = i; + laziest_ratio = ratio; + } + } + } + return laziest_index;*/ + + // Look for the least occupied + /*int laziest_index = 0; + int smallest_occupation = 99999; + for (int i = 0 ; i < m_num_cells ; ++i) + { + if (m_num_batches_grid[i] > 1) + { + if (m_occupation_grid[i] < smallest_occupation) + { + laziest_index = i; + smallest_occupation = m_occupation_grid[i]; + } + } + } + //std::cerr << "Occ=" << m_occupation_grid[laziest_index] + // << " / Bat=" << m_num_batches_grid[laziest_index] + // << std::endl; + return laziest_index;*/ + + + // Rotate + static tbb::atomic last_cell_index; + //std::cerr << "last=" << last_cell_index << std::endl; + int i = (last_cell_index + 1) % m_num_cells; + for ( ; i != last_cell_index ; i = (i + 1) % m_num_cells) + { + //std::cerr << "#" << i << "=" << m_num_batches_grid[i] << std::endl; + if (m_num_batches_grid[i] > 0) + { + break; + } + } + last_cell_index = i; + return i; + } + +protected: + double m_xmin; + double m_ymin; + double m_zmin; + double m_resolution_x; + double m_resolution_y; + double m_resolution_z; + + int m_num_grid_cells_per_axis; + int m_num_cells; + tbb::atomic * m_occupation_grid; + tbb::atomic * m_num_batches_grid; + + tbb::atomic m_laziest_cell_index; + tbb::atomic m_laziest_cell_occupation; +}; + + +/* + * ============== + * class WorkItem + * Abstract base class for a piece of work. + * ============== + */ +class WorkItem +{ +public: + WorkItem() {} + // Derived class defines the actual work. + virtual void run() = 0; + virtual bool less_than(const WorkItem &) const = 0; +}; + +struct CompareTwoWorkItems +{ + bool operator()(const WorkItem *p1, const WorkItem *p2) const + { + return p1->less_than(*p2); + } +}; + +/* + * ============== + * class MeshRefinementWorkItem + * Concrete class for a piece of work in the refinement process. + * ============== + */ +template +class MeshRefinementWorkItem + : public WorkItem +{ +public: + MeshRefinementWorkItem(const Func& func, const Quality &quality) + : m_func(func), m_quality(quality) + {} + + void run() + { + m_func(); + tbb::scalable_allocator >().deallocate(this, 1); + } + + bool less_than (const WorkItem &other) const + { + /*try + { + const MeshRefinementWorkItem& other_cwi = dynamic_cast&>(other); + return m_quality < other_cwi.m_quality; + } + catch (const std::bad_cast&) + { + return false; + }*/ + const MeshRefinementWorkItem& other_cwi = static_cast&>(other); + return m_quality < other_cwi.m_quality; + } + +private: + Func m_func; + Quality m_quality; +}; + + + + +/* + * ============== + * class SimpleFunctorWorkItem + * Concrete class for a work item embedding a simple functor + * ============== + */ +template +class SimpleFunctorWorkItem + : public WorkItem +{ +public: + SimpleFunctorWorkItem(const Func& func) + : m_func(func) + {} + + void run() + { + m_func(); + tbb::scalable_allocator >().deallocate(this, 1); + } + + // Irrelevant here + bool less_than (const WorkItem &other) const + { + // Just compare addresses + return this < &other; + } + +private: + Func m_func; +}; + + +/* + * =============== + * class WorkBatch + * =============== + */ +class WorkBatch +{ +public: + +#ifdef CGAL_MESH_3_TASK_SCHEDULER_SORTED_BATCHES_WITH_MULTISET + typedef std::multiset Batch; +#else + typedef std::vector Batch; +#endif + typedef Batch::const_iterator BatchConstIterator; + typedef Batch::iterator BatchIterator; + + WorkBatch() {} + + void add_work_item(WorkItem *p_item) + { +#ifdef CGAL_MESH_3_TASK_SCHEDULER_SORTED_BATCHES_WITH_MULTISET + m_batch.insert(p_item); +#else + m_batch.push_back(p_item); +#endif + } + + void move_first_elements(WorkBatch &dest, int num_elements) + { + BatchIterator it = m_batch.begin(); + BatchIterator it_end = m_batch.end(); + for (int i = 0 ; i < num_elements && it != it_end ; ++it) + { + dest.add_work_item(*it); + } + m_batch.erase(m_batch.begin(), it); + } + + void run() + { +#ifdef CGAL_MESH_3_TASK_SCHEDULER_SORTED_BATCHES_WITH_SORT + std::sort(m_batch.begin(), m_batch.end(), CompareTwoWorkItems()); +#endif + BatchIterator it = m_batch.begin(); + BatchIterator it_end = m_batch.end(); + for ( ; it != it_end ; ++it) + (*it)->run(); + } + + size_t size() const + { + return m_batch.size(); + } + + void clear() + { + m_batch.clear(); + } + +protected: + Batch m_batch; +}; + + + + +/* + * =================== + * class WorkItemTask + * =================== + */ +class WorkItemTask + : public tbb::task +{ +public: + WorkItemTask(WorkItem *pwi) + : m_pwi(pwi) + { + } + +private: + /*override*/inline tbb::task* execute(); + + WorkItem *m_pwi; +}; + + +/* + * ======================================= + * class Simple_worksharing_ds + * ======================================= + */ +class Simple_worksharing_ds +{ +public: + // Constructors + Simple_worksharing_ds() + { + } + + /// Destructor + virtual ~Simple_worksharing_ds() + { + } + + template + void enqueue_work(Func f, tbb::task &parent_task) const + { + //WorkItem *p_item = new SimpleFunctorWorkItem(f); + WorkItem *p_item = + tbb::scalable_allocator >().allocate(1); + new (p_item) SimpleFunctorWorkItem(f); + enqueue_task(create_task(p_item, parent_task)); + } + +protected: + + WorkItemTask *create_task(WorkItem *pwi, tbb::task &parent_task) const + { + return new(tbb::task::allocate_additional_child_of(parent_task)) WorkItemTask(pwi); + } + + void enqueue_task(WorkItemTask *t) const + { + tbb::task::spawn(*t); + } +}; + + + +/* + * ================== + * class TokenTask + * ================== + */ +class TokenTask + : public tbb::task +{ +public: + TokenTask(Load_based_worksharing_ds *p_wsds) + : m_worksharing_ds(p_wsds) {} + +private: + /*override*/inline tbb::task* execute(); + + Load_based_worksharing_ds *m_worksharing_ds; +}; + +/* + * ======================================= + * class Load_based_worksharing_ds + * ======================================= + */ +class Load_based_worksharing_ds +{ +public: + // Constructors + Load_based_worksharing_ds(const Bbox_3 &bbox) + : m_num_cells_per_axis( + Concurrent_mesher_config::get().work_stats_grid_num_cells_per_axis), + m_stats(bbox, m_num_cells_per_axis), + m_num_cells(m_num_cells_per_axis*m_num_cells_per_axis*m_num_cells_per_axis), + NUM_WORK_ITEMS_PER_BATCH( + Concurrent_mesher_config::get().num_work_items_per_batch) + { + m_tls_work_buffers = new TLS_WorkBuffer[m_num_cells]; + m_work_batches = new tbb::concurrent_queue[m_num_cells]; + m_num_batches = new tbb::atomic[m_num_cells]; + + for (int i = 0 ; i < m_num_cells ; ++i) + m_num_batches[i] = 0; + + set_bbox(bbox); + } + + /// Destructor + virtual ~Load_based_worksharing_ds() + { + delete [] m_tls_work_buffers; + delete [] m_work_batches; + delete [] m_num_batches; + } + + void set_bbox(const Bbox_3 &bbox) + { + m_stats.set_bbox(bbox); + } + + template + void enqueue_work(Func f, const Quality &quality, tbb::task &parent_task, const P3 &point) + { + WorkItem *p_item = new MeshRefinementWorkItem(f, quality); + int index = m_stats.compute_index(point); + WorkBatch &wb = m_tls_work_buffers[index].local(); + wb.add_work_item(p_item); + if (wb.size() >= NUM_WORK_ITEMS_PER_BATCH) + { + add_batch_and_enqueue_task(wb, index, parent_task); + wb.clear(); + } + } + + // Returns true if some items were flushed + bool flush_work_buffers(tbb::task &parent_task) + { + int num_flushed_items = 0; + + for (int i = 0 ; i < m_num_cells ; ++i) + { + for (TLS_WorkBuffer::iterator it_buffer = m_tls_work_buffers[i].begin() ; + it_buffer != m_tls_work_buffers[i].end() ; + ++it_buffer ) + { + if (it_buffer->size() > 0) + { + add_batch(*it_buffer, i); + it_buffer->clear(); + ++num_flushed_items; + } + } + } + + for (int i = 0 ; i < num_flushed_items ; ++i) + enqueue_task(parent_task); + + return (num_flushed_items > 0); + } + + void run_next_work_item() + { + WorkBuffer wb; + int index = m_stats.get_laziest_cell_index(); + bool popped = m_work_batches[index].try_pop(wb); + + if (!popped) + { + // Look for an non-empty queue + for (index = 0 ; !popped ; ++index) + { + CGAL_assertion(index < m_num_cells); + popped = m_work_batches[index].try_pop(wb); + } + + --index; + } + + CGAL_assertion(index < m_num_cells); + + --m_num_batches[index]; + m_stats.add_batch(index, -1); + add_occupation(index, 1); + +#ifdef CGAL_CONCURRENT_MESH_3_VERY_VERBOSE + std::cerr << "Running a batch of " << wb.size() << + " elements on cell #" << index << std::endl; +#endif + wb.run(); + add_occupation(index, -1); + } + +protected: + + // TLS + typedef WorkBatch WorkBuffer; + typedef tbb::enumerable_thread_specific TLS_WorkBuffer; + + void add_batch(const WorkBuffer &wb, int index) + { + m_work_batches[index].push(wb); + ++m_num_batches[index]; + m_stats.add_batch(index, 1); + } + + void enqueue_task(tbb::task &parent_task) + { + parent_task.increment_ref_count(); + // Warning: when using "enqueue", the system will use up to two threads + // even if you told task_scheduler_init to use only one + // (see http://software.intel.com/en-us/forums/showthread.php?t=101669) + tbb::task::spawn(*new(parent_task.allocate_child()) TokenTask(this)); + } + + void add_batch_and_enqueue_task(const WorkBuffer &wb, int index, tbb::task &parent_task) + { + add_batch(wb, index); + enqueue_task(parent_task); + } + + void add_occupation(int cell_index, int to_add, int occupation_radius = 1) + { + int index_z = cell_index/(m_num_cells_per_axis* + m_num_cells_per_axis); + cell_index -= index_z* + m_num_cells_per_axis* + m_num_cells_per_axis; + int index_y = cell_index/m_num_cells_per_axis; + cell_index -= index_y*m_num_cells_per_axis; + int index_x = cell_index; + + // For each cell inside the square + for (int i = std::max(0, index_x-occupation_radius) ; + i <= std::min(m_num_cells_per_axis - 1, index_x+occupation_radius) ; + ++i) + { + for (int j = std::max(0, index_y-occupation_radius) ; + j <= std::min(m_num_cells_per_axis - 1, index_y+occupation_radius) ; + ++j) + { + for (int k = std::max(0, index_z-occupation_radius) ; + k <= std::min(m_num_cells_per_axis - 1, index_z+occupation_radius) ; + ++k) + { + int index = + k*m_num_cells_per_axis*m_num_cells_per_axis + + j*m_num_cells_per_axis + + i; + + int weight = + (occupation_radius + 1 - std::abs(i - index_x)) + *(occupation_radius + 1 - std::abs(j - index_y)) + *(occupation_radius + 1 - std::abs(k - index_z)); + + m_stats.add_occupation(index, to_add*weight, m_num_batches[index]); + } + } + } + + } + + const int NUM_WORK_ITEMS_PER_BATCH; + + int m_num_cells_per_axis; + int m_num_cells; + Work_statistics m_stats; + TLS_WorkBuffer *m_tls_work_buffers; + tbb::concurrent_queue *m_work_batches; + tbb::atomic *m_num_batches; +}; + + + + + + + + +/* + * =================== + * class WorkBatchTask + * =================== + */ +class WorkBatchTask + : public tbb::task +{ +public: + WorkBatchTask(const WorkBatch &wb) + : m_wb(wb) + { + //set_affinity(tbb::task::self().affinity()); + } + +private: + /*override*/inline tbb::task* execute(); + + WorkBatch m_wb; +}; + +/* + * ======================================= + * class Auto_worksharing_ds + * ======================================= + */ +class Auto_worksharing_ds +{ +public: + // Constructors + Auto_worksharing_ds(const Bbox_3 &bbox) + : NUM_WORK_ITEMS_PER_BATCH( + Concurrent_mesher_config::get().num_work_items_per_batch) + { + set_bbox(bbox); + } + + /// Destructor + virtual ~Auto_worksharing_ds() + { + } + + void set_bbox(const Bbox_3 &/*bbox*/) + { + // We don't need it. + } + + template + void enqueue_work(Func f, tbb::task &parent_task) + { + //WorkItem *p_item = new SimpleFunctorWorkItem(f); + WorkItem *p_item = + tbb::scalable_allocator >().allocate(1); + new (p_item) SimpleFunctorWorkItem(f); + WorkBatch &workbuffer = m_tls_work_buffers.local(); + workbuffer.add_work_item(p_item); + if (workbuffer.size() >= NUM_WORK_ITEMS_PER_BATCH) + { + /*WorkBatch wb; + workbuffer.move_first_elements(wb, NUM_WORK_ITEMS_PER_BATCH); + add_batch_and_enqueue_task(wb, parent_task);*/ + add_batch_and_enqueue_task(workbuffer, parent_task); + workbuffer.clear(); + } + } + + template + void enqueue_work(Func f, const Quality &quality, tbb::task &parent_task) + { + //WorkItem *p_item = new MeshRefinementWorkItem(f, quality); + WorkItem *p_item = + tbb::scalable_allocator >() + .allocate(1); + new (p_item) MeshRefinementWorkItem(f, quality); + WorkBatch &workbuffer = m_tls_work_buffers.local(); + workbuffer.add_work_item(p_item); + if (workbuffer.size() >= NUM_WORK_ITEMS_PER_BATCH) + { + /*WorkBatch wb; + workbuffer.move_first_elements(wb, NUM_WORK_ITEMS_PER_BATCH); + add_batch_and_enqueue_task(wb, parent_task);*/ + add_batch_and_enqueue_task(workbuffer, parent_task); + workbuffer.clear(); + } + } + + // Returns true if some items were flushed + bool flush_work_buffers(tbb::task &parent_task) + { + int num_flushed_items = 0; + + std::vector tasks; + + for (TLS_WorkBuffer::iterator it_buffer = m_tls_work_buffers.begin() ; + it_buffer != m_tls_work_buffers.end() ; + ++it_buffer ) + { + if (it_buffer->size() > 0) + { + tasks.push_back(create_task(*it_buffer, parent_task)); + it_buffer->clear(); + ++num_flushed_items; + } + } + + for (std::vector::const_iterator it = tasks.begin() ; + it != tasks.end() ; ++it) + { + enqueue_task(*it, parent_task); + } + + return (num_flushed_items > 0); + } + +protected: + + // TLS + typedef WorkBatch WorkBuffer; + typedef tbb::enumerable_thread_specific TLS_WorkBuffer; + + WorkBatchTask *create_task(const WorkBuffer &wb, tbb::task &parent_task) const + { + return new(tbb::task::allocate_additional_child_of(parent_task)) WorkBatchTask(wb); + } + + void enqueue_task(WorkBatchTask *task, + tbb::task &parent_task) const + { + tbb::task::spawn(*task); + } + + void add_batch_and_enqueue_task(const WorkBuffer &wb, + tbb::task &parent_task) const + { + enqueue_task(create_task(wb, parent_task), parent_task); + } + + const int NUM_WORK_ITEMS_PER_BATCH; + TLS_WorkBuffer m_tls_work_buffers; +}; + + + + +inline tbb::task* TokenTask::execute() +{ + m_worksharing_ds->run_next_work_item(); + return NULL; +} + +inline tbb::task* WorkItemTask::execute() +{ + m_pwi->run(); + return NULL; +} + +inline tbb::task* WorkBatchTask::execute() +{ + m_wb.run(); + return NULL; +} + +} } //namespace CGAL::Mesh_3 + +#else // !CGAL_LINKED_WITH_TBB + +namespace CGAL { namespace Mesh_3 { + typedef void WorksharingDataStructureType; +} } //namespace CGAL::Mesh_3 + +#endif // CGAL_LINKED_WITH_TBB + +#endif // CGAL_MESH_3_WORKSHARING_DATA_STRUCTURES_H diff --git a/Mesh_3/include/CGAL/Mesh_3/config.h b/Mesh_3/include/CGAL/Mesh_3/config.h index e0c7be1384d..870d0d91805 100644 --- a/Mesh_3/include/CGAL/Mesh_3/config.h +++ b/Mesh_3/include/CGAL/Mesh_3/config.h @@ -35,6 +35,8 @@ //experimental # define CGAL_FASTER_BUILD_QUEUE 1 +//# define CGAL_SEQUENTIAL_MESH_3_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE +//# define CGAL_PARALLEL_MESH_3_DO_NOT_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE // slower / not recommended //should not be used //#define CGAL_MESH_3_OLD_MINIMUM_DIHEDRAL_ANGLE 1 diff --git a/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h b/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h index 5ed80d48f63..0263f76184b 100644 --- a/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h +++ b/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h @@ -31,6 +31,10 @@ #include #include +#ifdef CGAL_MESH_3_PERTURBER_VERBOSE + #include +#endif + #include #include #include @@ -224,18 +228,19 @@ public: const MeshDomain& domain, const SliverCriterion& criterion, const FT& sliver_bound, - std::vector& modified_vertices) const + std::vector& modified_vertices, + bool *could_lock_zone = NULL) const { #ifndef CGAL_MESH_3_PERTURBER_VERBOSE return do_perturb(v, slivers, c3t3, domain, criterion, - sliver_bound, modified_vertices); + sliver_bound, modified_vertices, could_lock_zone); #else timer_.start(); // Virtual call std::pair perturb = do_perturb(v, slivers, c3t3, domain, criterion, - sliver_bound, modified_vertices); + sliver_bound, modified_vertices, could_lock_zone); if ( perturb.first ) ++counter_; @@ -300,7 +305,8 @@ protected: const MeshDomain& domain, const SliverCriterion& criterion, const FT& sliver_bound, - std::vector& modified_vertices) const = 0; + std::vector& modified_vertices, + bool *could_lock_zone = NULL) const = 0; /** @@ -390,7 +396,8 @@ protected: const MeshDomain& domain, const SliverCriterion& criterion, const FT& sliver_bound, - std::vector& modified_vertices) const = 0; + std::vector& modified_vertices, + bool *could_lock_zone = NULL) const = 0; protected: // ----------------------------------- @@ -407,7 +414,8 @@ protected: C3T3& c3t3, const MeshDomain& domain, const SliverCriterion& criterion, - std::vector& modified_vertices) const + std::vector& modified_vertices, + bool *could_lock_zone = NULL) const { typedef typename C3T3::Triangulation::Geom_traits Gt; typedef typename Gt::FT FT; @@ -434,27 +442,46 @@ protected: // as long as no topological change takes place unsigned int i = 0; - while( Th().no_topological_change(c3t3.triangulation(), v, final_loc) - && (++i <= max_step_nb_) ) + // Concurrent-safe version + if (could_lock_zone) { - new_loc = new_loc + step_length * gradient_vector; + while(Th().no_topological_change__without_set_point(c3t3.triangulation(), + v, final_loc) + && (++i <= max_step_nb_) ) + { + new_loc = new_loc + step_length * gradient_vector; - if ( c3t3.in_dimension(v) == 3 ) - final_loc = new_loc; - else - final_loc = helper.project_on_surface(new_loc, v); + if ( c3t3.in_dimension(v) == 3 ) + final_loc = new_loc; + else + final_loc = helper.project_on_surface(new_loc, v); + } + } + else + { + while( Th().no_topological_change(c3t3.triangulation(), v, final_loc) + && (++i <= max_step_nb_) ) + { + new_loc = new_loc + step_length * gradient_vector; + + if ( c3t3.in_dimension(v) == 3 ) + final_loc = new_loc; + else + final_loc = helper.project_on_surface(new_loc, v); + } } // Topology could not change moving this vertex if ( i > max_step_nb_ || Th().inside_protecting_balls(c3t3.triangulation(), v, final_loc)) return std::make_pair(false,v); - + // we know that there will be a combinatorial change return helper.update_mesh_topo_change(final_loc, v, criterion, - std::back_inserter(modified_vertices)); + std::back_inserter(modified_vertices), + could_lock_zone); } @@ -515,7 +542,8 @@ protected: const MeshDomain& domain, const SliverCriterion& criterion, const FT&, - std::vector& modified_vertices) const + std::vector& modified_vertices, + bool *could_lock_zone = NULL) const { CGAL_precondition(!slivers.empty()); @@ -530,7 +558,8 @@ protected: c3t3, domain, criterion, - modified_vertices); + modified_vertices, + could_lock_zone); } private: @@ -671,7 +700,8 @@ protected: const MeshDomain& domain, const SliverCriterion& criterion, const FT&, - std::vector& modified_vertices) const + std::vector& modified_vertices, + bool *could_lock_zone = NULL) const { CGAL_precondition(!slivers.empty()); @@ -686,7 +716,8 @@ protected: c3t3, domain, criterion, - modified_vertices); + modified_vertices, + could_lock_zone); } private: @@ -810,7 +841,8 @@ protected: const MeshDomain& domain, const SliverCriterion& criterion, const FT&, - std::vector& modified_vertices) const + std::vector& modified_vertices, + bool *could_lock_zone = NULL) const { CGAL_precondition(!slivers.empty()); @@ -825,7 +857,8 @@ protected: c3t3, domain, criterion, - modified_vertices); + modified_vertices, + could_lock_zone); } private: @@ -1009,7 +1042,8 @@ protected: const MeshDomain& domain, const SliverCriterion& criterion, const FT& sliver_bound, - std::vector& modified_vertices) const = 0; + std::vector& modified_vertices, + bool *could_lock_zone = NULL) const = 0; protected: // ----------------------------------- @@ -1140,12 +1174,14 @@ protected: const MeshDomain& domain, const SliverCriterion& criterion, const FT& sliver_bound, - std::vector& modified_vertices) const + std::vector& modified_vertices, + bool *could_lock_zone = NULL) const { CGAL_precondition(!slivers.empty()); return apply_perturbation(v, slivers, c3t3, domain, criterion, - sliver_bound, modified_vertices); + sliver_bound, modified_vertices, + could_lock_zone); } private: @@ -1163,7 +1199,8 @@ private: const MeshDomain& domain, const SliverCriterion& criterion, const FT& sliver_bound, - std::vector& modified_vertices) const + std::vector& modified_vertices, + bool *could_lock_zone = NULL) const { typedef Triangulation_helpers Th; @@ -1206,8 +1243,12 @@ private: helper.update_mesh(new_location, moving_vertex, criterion, - std::back_inserter(tmp_mod_vertices)); + std::back_inserter(tmp_mod_vertices), + could_lock_zone); + if (could_lock_zone && *could_lock_zone == false) + return std::make_pair(false, Vertex_handle()); + // get new vertex moving_vertex = update.second; diff --git a/Mesh_3/include/CGAL/Mesh_cell_base_3.h b/Mesh_3/include/CGAL/Mesh_cell_base_3.h index 40178ede670..63b06f17ebb 100644 --- a/Mesh_3/include/CGAL/Mesh_cell_base_3.h +++ b/Mesh_3/include/CGAL/Mesh_cell_base_3.h @@ -34,8 +34,68 @@ #include #include +#include + +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif + namespace CGAL { + +// Sequential +template +class Mesh_cell_base_3_base +{ +public: +#if defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) \ + || defined(CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE) + + // Erase counter (cf. Compact_container) + unsigned int erase_counter() const + { + return this->m_erase_counter; + } + void set_erase_counter(unsigned int c) + { + this->m_erase_counter = c; + } + void increment_erase_counter() + { + ++this->m_erase_counter; + } + +private: + typedef unsigned int Erase_counter_type; + Erase_counter_type m_erase_counter; +#endif +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Specialized version (parallel) +template <> +class Mesh_cell_base_3_base +{ +public: + // Erase counter (cf. Compact_container) + unsigned int erase_counter() const + { + return this->m_erase_counter; + } + void set_erase_counter(unsigned int c) + { + this->m_erase_counter = c; + } + void increment_erase_counter() + { + ++this->m_erase_counter; + } +protected: + typedef tbb::atomic Erase_counter_type; + Erase_counter_type m_erase_counter; +}; +#endif // CGAL_LINKED_WITH_TBB + // Class Mesh_cell_base_3 // Cell base class used in 3D meshing process. // Adds information to Cb about the cell of the input complex containing it @@ -44,7 +104,9 @@ template< class GT, class Cb= CGAL::Regular_triangulation_cell_base_with_weighted_circumcenter_3< GT, CGAL::Regular_triangulation_cell_base_3 > > class Mesh_cell_base_3 -: public Mesh_3::Mesh_surface_cell_base_3 +: public Mesh_3::Mesh_surface_cell_base_3, + public Mesh_cell_base_3_base< + typename Mesh_3::Mesh_surface_cell_base_3::Tds::Concurrency_tag> { typedef typename GT::FT FT; diff --git a/Mesh_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h b/Mesh_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h index a72f9e9573a..999f921061d 100644 --- a/Mesh_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h +++ b/Mesh_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h @@ -20,23 +20,24 @@ // Author(s) : Stephane Tayeb // //****************************************************************************** -// File Description : +// File Description : //****************************************************************************** #ifndef CGAL_MESH_COMPLEX_3_IN_TRIANGULATION_3_H #define CGAL_MESH_COMPLEX_3_IN_TRIANGULATION_3_H -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include namespace CGAL { @@ -45,57 +46,63 @@ template class Mesh_complex_3_in_triangulation_3 : - public Mesh_3::Mesh_complex_3_in_triangulation_3_base + public Mesh_3::Mesh_complex_3_in_triangulation_3_base< + Tr, typename Tr::Concurrency_tag> { +public: + typedef typename Tr::Concurrency_tag Concurrency_tag; + +private: typedef Mesh_complex_3_in_triangulation_3< Tr,CornerIndex,CurveSegmentIndex> Self; - typedef Mesh_3::Mesh_complex_3_in_triangulation_3_base Base; - + typedef Mesh_3::Mesh_complex_3_in_triangulation_3_base< + Tr,Concurrency_tag> Base; + public: typedef typename Base::size_type size_type; - + typedef typename Base::Edge Edge; typedef typename Base::Vertex_handle Vertex_handle; typedef CornerIndex Corner_index; typedef CurveSegmentIndex Curve_segment_index; - + typedef typename Base::Triangulation Triangulation; - + private: // Type to store the edges: // - a set of std::pair (ordered at insertion) // - which allows fast lookup from one Vertex_handle // - each element of the set has an associated info (Curve_segment_index) value - typedef boost::bimaps::bimap< + typedef boost::bimaps::bimap< boost::bimaps::multiset_of, boost::bimaps::multiset_of, boost::bimaps::set_of_relation<>, boost::bimaps::with_info > Edge_map; typedef typename Edge_map::value_type Internal_edge; - + // Type to store the corners typedef std::map Corner_map; - + public: /** * Constructor */ - Mesh_complex_3_in_triangulation_3() + Mesh_complex_3_in_triangulation_3() : Base() , edges_() , corners_() {} - + /** * Copy constructor */ Mesh_complex_3_in_triangulation_3(const Self& rhs); - + /** * Destructor */ virtual ~Mesh_complex_3_in_triangulation_3() {} - + /** * Assignement operator */ @@ -104,7 +111,7 @@ public: swap(rhs); return *this; } - + /** * Swaps this & rhs */ @@ -114,7 +121,7 @@ public: edges_.swap(rhs.edges_); corners_.swap(rhs.corners_); } - + /** * Clears data of c3t3 */ @@ -124,16 +131,16 @@ public: edges_.clear(); corners_.clear(); } - + /// Import Base functions using Base::is_in_complex; using Base::add_to_complex; using Base::remove_from_complex; - + /** * Add edge e to complex, with Curve_segment_index index - */ + */ void add_to_complex(const Edge& e, const Curve_segment_index& index) { @@ -141,7 +148,7 @@ public: e.first->vertex(e.third), index); } - + /** * Add edge (v1,v2) to complex, with Curve_segment_index index */ @@ -151,7 +158,7 @@ public: { add_to_complex(make_internal_edge(v1,v2), index); } - + /** * Mark vertex \c v as a corner of the complex */ @@ -163,12 +170,12 @@ public: /** * Remove edge \c e from complex - */ + */ void remove_from_complex(const Edge& e) { remove_from_complex(e.first->vertex(e.second), e.first->vertex(e.third)); } - + /** * Remove edge (v1,v2) from complex */ @@ -176,7 +183,7 @@ public: { remove_from_complex(make_internal_edge(v1,v2)); } - + /** * Remove vertex \c v from complex */ @@ -185,7 +192,7 @@ public: corners_.erase(v); v->set_dimension(-1); } - + /** * Returns the number of edges of c3t3 */ @@ -205,7 +212,7 @@ public: { return corners_.size(); } - + /** * Returns true if edge \c e is in complex */ @@ -213,7 +220,7 @@ public: { return is_in_complex(e.first->vertex(e.second), e.first->vertex(e.third)); } - + /** * Returns true if edge (v1,v2) is in C3T3 */ @@ -229,7 +236,7 @@ public: { return (corners_.find(v) != corners_.end()); } - + /** * Returns Curve_segment_index of edge \c e */ @@ -238,7 +245,7 @@ public: return curve_segment_index(e.first->vertex(e.second), e.first->vertex(e.third)); } - + /** * Returns Curve_segment_index of edge \c (v1,v2) */ @@ -247,7 +254,7 @@ public: { return curve_index(make_internal_edge(v1,v2)); } - + /** * Returns Corner_index of vertex \c v */ @@ -257,25 +264,25 @@ public: if ( corners_.end() != it ) { return it->second; } return Corner_index(); } - + /** * Fills \c out with incident edges (1-dimensional features of \c v. * OutputIterator value type is std::pair - * \pre v->in_dimension() < 2 + * \pre v->in_dimension() < 2 */ template OutputIterator adjacent_vertices_in_complex(const Vertex_handle& v, OutputIterator out) const; - + // ----------------------------------- // Undocumented // ----------------------------------- - + /** * Returns true if c3t3 is valid */ bool is_valid(bool verbose = false) const; - + // ----------------------------------- // Complex traversal // ----------------------------------- @@ -289,15 +296,15 @@ private: const Curve_segment_index& index = Curve_segment_index()) : c3t3_(c3t3) , index_(index) { } - + template bool operator()(Iterator it) const - { + { if ( index_ == Curve_segment_index() ) { return ! c3t3_.is_in_complex(*it); } else { return c3t3_.curve_segment_index(*it) != index_; } } }; - + class Vertex_iterator_not_in_complex { const Self& c3t3_; @@ -307,15 +314,15 @@ private: const Corner_index& index = Corner_index()) : c3t3_(c3t3) , index_(index) { } - + template bool operator()(const ItMap it) const - { + { if ( index_ == Corner_index() ) { return false; } else { return it->second != index_; } } }; - + // Filtered iterator typedef Filter_iterator< typename Corner_map::const_iterator, @@ -325,7 +332,7 @@ private: typedef boost::transform_iterator < Mesh_3::internal::First_of, Vertex_map_filter_iterator > Vertex_map_iterator_first; - + // Iterator type to remove a level of referencing class Vertex_map_iterator_first_dereference : public boost::iterator_adaptor < @@ -345,26 +352,26 @@ private: public: typedef typename Vertex_map_iterator_first::reference pointer; typedef typename iterator_adaptor_::reference reference; - + Vertex_map_iterator_first_dereference() : Self::iterator_adaptor_() { } - + template < typename Iterator > Vertex_map_iterator_first_dereference(Iterator i) : Self::iterator_adaptor_(typename Self::iterator_adaptor_::base_type(i)) { } - + pointer operator->() const { return *(this->base()); } reference operator*() const { return **(this->base()); } operator Vertex_handle() { return Vertex_handle(*(this->base())); } }; - + public: /// Iterator type to visit the edges of the 1D complex. typedef Filter_iterator< typename Triangulation::Finite_edges_iterator, Edge_iterator_not_in_complex > Edges_in_complex_iterator; - + /// Returns a Facets_in_complex_iterator to the first facet of the 1D complex Edges_in_complex_iterator edges_in_complex_begin() const { @@ -372,7 +379,7 @@ public: Edge_iterator_not_in_complex(*this), this->triangulation().finite_edges_begin()); } - + /// Returns a Facets_in_complex_iterator to the first facet of the 1D complex Edges_in_complex_iterator edges_in_complex_begin(const Curve_segment_index& index) const @@ -381,17 +388,17 @@ public: Edge_iterator_not_in_complex(*this,index), this->triangulation().finite_edges_begin()); } - + /// Returns past-the-end iterator on facet of the 1D complex Edges_in_complex_iterator edges_in_complex_end(const Curve_segment_index& = Curve_segment_index()) const { return CGAL::filter_iterator(this->triangulation().finite_edges_end(), Edge_iterator_not_in_complex(*this)); } - + /// Iterator type to visit the edges of the 0D complex. typedef Vertex_map_iterator_first_dereference Vertices_in_complex_iterator; - + /// Returns a Vertices_in_complex_iterator to the first vertex of the 0D complex Vertices_in_complex_iterator vertices_in_complex_begin() const { @@ -407,20 +414,20 @@ public: return CGAL::filter_iterator(corners_.end(), Vertex_iterator_not_in_complex(*this,index), corners_.begin()); - } - + } + /// Returns past-the-end iterator on facet of the 0D complex Vertices_in_complex_iterator vertices_in_complex_end() const { return CGAL::filter_iterator(corners_.end(), Vertex_iterator_not_in_complex(*this)); - } - - + } + + private: /** * Creates an Internal_edge object (i.e a pair of ordered Vertex_handle) - */ + */ Internal_edge make_internal_edge(const Vertex_handle& v1, const Vertex_handle& v2) const { @@ -435,7 +442,7 @@ private: { return (curve_index(edge) != Curve_segment_index() ); } - + /** * Add edge \c edge to complex, with Curve_segment_index index */ @@ -450,7 +457,7 @@ private: std::pair it = edges_.insert(edge); it.first->info = index; } - + /** * Remove edge \c edge from complex */ @@ -468,7 +475,7 @@ private: if ( edges_.end() != it ) { return it->info; } return Curve_segment_index(); } - + private: Edge_map edges_; Corner_map corners_; @@ -483,23 +490,23 @@ Mesh_complex_3_in_triangulation_3(const Self& rhs) , corners_() { // Copy edges - for ( typename Edge_map::const_iterator it = rhs.edges_.begin(), + for ( typename Edge_map::const_iterator it = rhs.edges_.begin(), end = rhs.edges_.end() ; it != end ; ++it ) { const Vertex_handle& va = it->right; const Vertex_handle& vb = it->left; - + Vertex_handle new_va; this->triangulation().is_vertex(va->point(), new_va); - + Vertex_handle new_vb; this->triangulation().is_vertex(vb->point(), new_vb); - + this->add_to_complex(make_internal_edge(new_va,new_vb), it->info); } - + // Copy corners - for ( typename Corner_map::const_iterator it = rhs.corners_.begin(), + for ( typename Corner_map::const_iterator it = rhs.corners_.begin(), end = rhs.corners_.end() ; it != end ; ++it ) { Vertex_handle new_v; @@ -516,7 +523,7 @@ Mesh_complex_3_in_triangulation_3:: adjacent_vertices_in_complex(const Vertex_handle& v, OutputIterator out) const { CGAL_precondition(v->in_dimension() < 2); - + typedef typename Edge_map::right_const_iterator Rcit; typedef typename Edge_map::left_const_iterator Lcit; @@ -526,14 +533,14 @@ adjacent_vertices_in_complex(const Vertex_handle& v, OutputIterator out) const { *out++ = std::make_pair(rit->second, rit->info); } - + // Add edges containing v on the right std::pair range_left = edges_.left.equal_range(v); for ( Lcit lit = range_left.first ; lit != range_left.second ; ++lit ) { *out++ = std::make_pair(lit->second, lit->info); } - + return out; } @@ -548,7 +555,7 @@ is_valid(bool verbose) const typedef Weight FT; std::map vertex_map; - + // Fill map counting neighbor number for each vertex of an edge for ( typename Edge_map::const_iterator it = edges_.begin(), end = edges_.end() ; it != end ; ++it ) @@ -556,12 +563,12 @@ is_valid(bool verbose) const const Vertex_handle& v1 = it->right; if ( vertex_map.find(v1) == vertex_map.end() ) { vertex_map[v1] = 1; } else { vertex_map[v1] += 1; } - + const Vertex_handle& v2 = it->left; if ( vertex_map.find(v2) == vertex_map.end() ) { vertex_map[v2] = 1; } else { vertex_map[v2] += 1; } } - + // Verify that each vertex has 2 neighbors if it's not a corner for ( typename std::map::iterator vit = vertex_map.begin(), vend = vertex_map.end() ; vit != vend ; ++vit ) @@ -576,53 +583,57 @@ is_valid(bool verbose) const return false; } } - + // Verify that balls of each edge intersect for ( typename Edge_map::const_iterator it = edges_.begin(), end = edges_.end() ; it != end ; ++it ) { const Bare_point& p = it->right->point().point(); const Bare_point& q = it->left->point().point(); - - typename Tr::Geom_traits::Construct_sphere_3 sphere = + + typename Tr::Geom_traits::Construct_sphere_3 sphere = this->triangulation().geom_traits().construct_sphere_3_object(); - typename Tr::Geom_traits::Do_intersect_3 do_intersect = + typename Tr::Geom_traits::Do_intersect_3 do_intersect = this->triangulation().geom_traits().do_intersect_3_object(); const FT& sq_rp = it->right->point().weight(); const FT& sq_rq = it->left->point().weight(); - + if ( ! do_intersect(sphere(p, sq_rp), sphere(q, sq_rq)) ) { - std::cerr << "Point p[" << p << "], dim=" << it->right->in_dimension() - << " and q[" << q << "], dim=" << it->left->in_dimension() + std::cerr << "Point p[" << p << "], dim=" << it->right->in_dimension() + << " and q[" << q << "], dim=" << it->left->in_dimension() << " form an edge but do not intersect !\n"; return false; } } - + return true; } -template < class Tr, class CI_, class CSI_> -std::ostream & -operator<< (std::ostream& os, +template +std::ostream & +operator<< (std::ostream& os, const Mesh_complex_3_in_triangulation_3 &c3t3) { // TODO: implement edge saving - return os << static_cast&>(c3t3); + typedef typename Mesh_complex_3_in_triangulation_3::Concurrency_tag Concurrency_tag; + return os << static_cast< + const Mesh_3::Mesh_complex_3_in_triangulation_3_base&>(c3t3); } -template < class Tr, class CI_, class CSI_> -std::istream & -operator>> (std::istream& is, +template +std::istream & +operator>> (std::istream& is, Mesh_complex_3_in_triangulation_3 &c3t3) { // TODO: implement edge loading - is >> static_cast&>(c3t3); + typedef typename Mesh_complex_3_in_triangulation_3::Concurrency_tag Concurrency_tag; + is >> static_cast< + Mesh_3::Mesh_complex_3_in_triangulation_3_base&>(c3t3); return is; } diff --git a/Mesh_3/include/CGAL/Mesh_triangulation_3.h b/Mesh_3/include/CGAL/Mesh_triangulation_3.h index 50f9b35860c..6aacc048dac 100644 --- a/Mesh_3/include/CGAL/Mesh_triangulation_3.h +++ b/Mesh_3/include/CGAL/Mesh_triangulation_3.h @@ -35,41 +35,46 @@ #include namespace CGAL { - + namespace details { - + template struct Mesh_geom_traits_generator { private: typedef Robust_weighted_circumcenter_filtered_traits_3 Geom_traits; - + public: typedef Geom_traits type; typedef type Type; }; // end struct Mesh_geom_traits_generator - + } // end namespace details - - + + // Struct Mesh_triangulation_3 // template::Kernel, - class Concurrency_tag = Default, + class Concurrency_tag = Sequential_tag, class Vertex_base_ = Default, class Cell_base_ = Default> +struct Mesh_triangulation_3; + +// Sequential version (default) +template struct Mesh_triangulation_3 - { +{ private: typedef typename details::Mesh_geom_traits_generator::type Geom_traits; typedef typename Default::Get< - Vertex_base_, + Vertex_base_, Mesh_vertex_base_3 >::type Vertex_base; typedef typename Default::Get< - Cell_base_, + Cell_base_, Compact_mesh_cell_base_3 >::type Cell_base; typedef Triangulation_data_structure_3 Tds; @@ -80,6 +85,33 @@ public: typedef type Type; }; // end struct Mesh_triangulation_3 +#ifdef CGAL_LINKED_WITH_TBB +// Parallel version (specialization) +// +template +struct Mesh_triangulation_3 +{ +private: + typedef typename details::Mesh_geom_traits_generator::type Geom_traits; + + typedef typename Default::Get< + Vertex_base_, + Mesh_vertex_base_3 >::type Vertex_base; + typedef typename Default::Get< + Cell_base_, + Compact_mesh_cell_base_3 >::type Cell_base; + + typedef Triangulation_data_structure_3< + Vertex_base, Cell_base, Parallel_tag> Tds; + typedef Regular_triangulation_3 Triangulation; + +public: + typedef Triangulation type; + typedef type Type; +}; // end struct Mesh_triangulation_3 +#endif // CGAL_LINKED_WITH_TBB + } // end namespace CGAL #endif // CGAL_MESH_TRIANGULATION_3_H diff --git a/Mesh_3/include/CGAL/Mesh_vertex_base_3.h b/Mesh_3/include/CGAL/Mesh_vertex_base_3.h index c802d377811..558de99a49b 100644 --- a/Mesh_3/include/CGAL/Mesh_vertex_base_3.h +++ b/Mesh_3/include/CGAL/Mesh_vertex_base_3.h @@ -35,6 +35,62 @@ #include namespace CGAL { + +// Without erase counter +template +class Mesh_vertex_base_3_base +{ +#if defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) \ + || defined(CGAL_MESH_3_USE_LAZY_UNSORTED_REFINEMENT_QUEUE) + +public: + // Erase counter (cf. Compact_container) + unsigned int erase_counter() const + { + return this->m_erase_counter; + } + void set_erase_counter(unsigned int c) + { + this->m_erase_counter = c; + } + void increment_erase_counter() + { + ++this->m_erase_counter; + } + +protected: + typedef unsigned int Erase_counter_type; + Erase_counter_type m_erase_counter; +#endif +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Specialized version (parallel) +template <> +class Mesh_vertex_base_3_base +{ +public: + + // Erase counter (cf. Compact_container) + unsigned int erase_counter() const + { + return this->m_erase_counter; + } + void set_erase_counter(unsigned int c) + { + this->m_erase_counter = c; + } + void increment_erase_counter() + { + ++this->m_erase_counter; + } + +protected: + typedef tbb::atomic Erase_counter_type; + Erase_counter_type m_erase_counter; + +}; +#endif // CGAL_LINKED_WITH_TBB // Class Mesh_vertex_base_3 // Vertex base class used in 3D meshing process. @@ -44,7 +100,9 @@ template > class Mesh_vertex_base_3 -: public Vb +: public Vb, + public Mesh_vertex_base_3_base< + typename Vb::Triangulation_data_structure::Concurrency_tag> { public: typedef Vb Cmvb3_base; diff --git a/Mesh_3/include/CGAL/Meshes/Filtered_deque_container.h b/Mesh_3/include/CGAL/Meshes/Filtered_deque_container.h new file mode 100644 index 00000000000..e8314bdd4c8 --- /dev/null +++ b/Mesh_3/include/CGAL/Meshes/Filtered_deque_container.h @@ -0,0 +1,318 @@ +// Copyright (c) 2012 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: $ +// $Id: $ +// +// +// Author(s) : Clement JAMIN + +#ifndef CGAL_MESHES_FILTERED_DEQUE_CONTAINER_H +#define CGAL_MESHES_FILTERED_DEQUE_CONTAINER_H + +#include +#include +#include +#ifdef CGAL_LINKED_WITH_TBB + #include +#endif + +namespace CGAL { + +namespace Meshes { + + /************************************************ + // Class Filtered_deque_container_base + // Two versions: sequential / parallel + ************************************************/ + + // Sequential + template + class Filtered_deque_container_base + { + public: + typedef std::deque > Container; + typedef typename Container::size_type size_type; + typedef typename Container::value_type value_type; + + void add_to_TLS_lists_impl(bool add) {} + Element get_next_local_element_impl() + { return Element(); } + value_type get_next_local_raw_element_impl() + { return value_type(); } + void pop_next_local_element_impl() {} + + protected: + Filtered_deque_container_base() {} + Filtered_deque_container_base(bool) {} + + template + void splice_local_lists_impl(Container &) + {} + + template + bool no_longer_local_element_to_refine_impl(const Predicate &) + { + return true; + } + + template + void insert_raw_element(const value_type &re, Container &container) + { + container.push_back(re); + } + }; + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + template + class Filtered_deque_container_base + { + public: + typedef std::deque > Container; + typedef typename Container::size_type size_type; + typedef typename Container::value_type value_type; + + void add_to_TLS_lists_impl(bool add) + { + m_add_to_TLS_lists = add; + } + + // Warning: no_longer_local_element_to_refine_impl must have been called + // just before calling get_next_local_element_impl + // (successive calls to "get_next_local_element_impl" are not allowed) + Element get_next_local_element_impl() + { + CGAL_assertion(!m_local_lists.local().empty()); + // Add this? It shouldn't be necessary as user + // is supposed to call "no_longer_element_to_refine_impl" first + /*while( !test(container.front()) ) + { + container.pop_front(); + }*/ + return m_local_lists.local().front().second; + } + + // Warning: no_longer_local_element_to_refine_impl must have been called + // just before calling get_next_local_raw_element_impl + // (successive calls to "get_next_local_raw_element_impl" are not allowed) + value_type get_next_local_raw_element_impl() + { + CGAL_assertion(!m_local_lists.local().empty()); + return m_local_lists.local().front(); + } + + void pop_next_local_element_impl() + { + // Erase last element + m_local_lists.local().pop_front(); + } + + protected: + Filtered_deque_container_base(bool add_to_TLS_lists = false) + : m_add_to_TLS_lists(add_to_TLS_lists) {} + + + template + void splice_local_lists_impl(Container &container) + { + for(typename LocalList::iterator it_list = m_local_lists.begin() ; + it_list != m_local_lists.end() ; + ++it_list ) + { +#ifdef _DEBUG + size_t deque_size = container.size(); + size_t local_list_size = it_list->size(); +#endif + container.insert(container.end(), it_list->begin(), it_list->end()); + it_list->clear(); + } + } + + template + bool no_longer_local_element_to_refine_impl(const Predicate &test) + { + bool is_empty = m_local_lists.local().empty(); + while( !is_empty && !test(m_local_lists.local().front().second) ) + { + pop_next_local_element_impl(); + is_empty = m_local_lists.local().empty(); + } + return is_empty; + } + + template + void insert_raw_element(const value_type &re, Container &container) + { + if (m_add_to_TLS_lists) + m_local_lists.local().push_back(re); + else + container.push_back(re); + } + + + // === Member variables === + + typedef tbb::enumerable_thread_specific< + std::deque > > LocalList; + LocalList m_local_lists; + bool m_add_to_TLS_lists; + }; +#endif // CGAL_LINKED_WITH_TBB + + /************************************************ + // Class Filtered_deque_container + // + // This container is a filtered deque: + // front() and empty() use an object predicate + // to test if the element is ok. + ************************************************/ + + template + class Filtered_deque_container + : public Filtered_deque_container_base + { + public: + typedef Filtered_deque_container_base Base; + typedef typename Base::Container Container; + typedef typename Base::value_type value_type; + typedef typename Base::size_type size_type; + typedef Quality_ Quality; + typedef Element_ Element; + + protected: + // --- protected datas --- + Container container; + Predicate test; + + static bool CompareTwoElements(std::pair e1, + std::pair e2) + { + return (e1.first < e2.first); + } + + public: + + // Constructors - For sequential + Filtered_deque_container() {} + explicit Filtered_deque_container(const Predicate &p) + : test(p) {} + + // Constructors - For parallel + explicit Filtered_deque_container(bool add_to_TLS_lists) + : Base(add_to_TLS_lists) {} + explicit Filtered_deque_container(const Predicate &p, bool add_to_TLS_lists) + : test(p), Base(add_to_TLS_lists) {} + + void splice_local_lists_impl() + { + Base::splice_local_lists_impl(container); + } + + bool no_longer_local_element_to_refine_impl() + { + return Base::no_longer_local_element_to_refine_impl(test); + } + + void insert_raw_element(const value_type &re) + { + Base::insert_raw_element(re, container); + } + + bool no_longer_element_to_refine_impl() + { +#ifdef _DEBUG + size_t deque_size = container.size(); +#endif + bool is_empty = container.empty(); + while( !is_empty && !test(container.front().second) ) + { + pop_next_element_impl(); + is_empty = container.empty(); + } + return is_empty; + } + + // Warning: no_longer_element_to_refine_impl must have been called + // just before calling get_next_element_impl + // (successive calls to "get_next_element_impl" are not allowed) + Element get_next_element_impl() const + { + CGAL_assertion(!container.empty()); + // Add this? It shouldn't be necessary as user + // is supposed to call "no_longer_element_to_refine_impl" first + /*while( !test(container.front()) ) + { + container.pop_front(); + }*/ + return container.front().second; + } + + void add_bad_element(const Element& e, const Quality& q) + { + insert_raw_element(std::make_pair(q, e)); + } + + void pop_next_element_impl() + { + // Erase last element + container.pop_front(); + } + + // Sort + // Worst (smallest) quality first + void sort () + { + std::sort(container.begin(), container.end(), CompareTwoElements); + } + + // Clear + void clear () + { + container.clear(); + } + + // Random shuffle + void random_shuffle () + { + std::random_shuffle(container.begin(), container.end()); + } + + size_type size() const + { + return container.size(); + } + + // Warning: no_longer_element_to_refine_impl must have been called + // just before calling get_next_raw_element_impl + // (successive calls to "get_next_raw_element_impl" are not allowed) + value_type get_next_raw_element_impl() + { + CGAL_assertion(!container.empty()); + return container.front(); + } + + bool is_zombie(const Element &e) const + { + return !test(e); + } + + }; // end Filtered_deque_container + +} // end namespace Mesh_3 +} // end namespace CGAL + +#endif // CGAL_MESHES_FILTERED_DEQUE_CONTAINER_H diff --git a/Mesh_3/include/CGAL/Meshes/Filtered_multimap_container.h b/Mesh_3/include/CGAL/Meshes/Filtered_multimap_container.h new file mode 100644 index 00000000000..00d1f584ab1 --- /dev/null +++ b/Mesh_3/include/CGAL/Meshes/Filtered_multimap_container.h @@ -0,0 +1,309 @@ +// Copyright (c) 2012 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: $ +// $Id: $ +// +// +// Author(s) : Clement JAMIN + +#ifndef CGAL_MESHES_FILTERED_MULTIMAP_CONTAINER_H +#define CGAL_MESHES_FILTERED_MULTIMAP_CONTAINER_H + +#include +#include +#ifdef CGAL_LINKED_WITH_TBB + #include +#endif + +namespace CGAL { + + namespace Meshes { + + /************************************************ + // Class Filtered_multimap_container_base + // Two versions: sequential / parallel + ************************************************/ + + // Sequential + template + class Filtered_multimap_container_base + { + public: + typedef std::multimap Map; + typedef typename Map::size_type size_type; + typedef typename Map::value_type value_type; + + void add_to_TLS_lists_impl(bool add) {} + Element get_next_local_element_impl() + { return Element(); } + value_type get_next_local_raw_element_impl() + { return value_type(); } + void pop_next_local_element_impl() {} + + protected: + Filtered_multimap_container_base() {} + Filtered_multimap_container_base(bool) {} + + template + void splice_local_lists_impl(Container &) + {} + + template + bool no_longer_local_element_to_refine_impl(const Predicate &) + { + return true; + } + + template + void insert_raw_element(const value_type &re, Container &container) + { + container.insert(re); + } + }; + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + template + class Filtered_multimap_container_base + { + public: + typedef std::multimap Map; + typedef typename Map::size_type size_type; + typedef typename Map::value_type value_type; + + void add_to_TLS_lists_impl(bool add) + { + m_add_to_TLS_lists = add; + } + + // Warning: no_longer_local_element_to_refine_impl must have been called + // just before calling get_next_local_element_impl + // (successive calls to "get_next_local_element_impl" are not allowed) + Element get_next_local_element_impl() + { + CGAL_assertion(!m_local_lists.local().empty()); + // Add this? It shouldn't be necessary as user + // is supposed to call "no_longer_element_to_refine_impl" first + /*while( !test(container.front()) ) + { + container.pop_front(); + }*/ + return m_local_lists.local().front().second; + } + + // Warning: no_longer_local_element_to_refine_impl must have been called + // just before calling get_next_local_raw_element_impl + // (successive calls to "get_next_local_raw_element_impl" are not allowed) + value_type get_next_local_raw_element_impl() + { + CGAL_assertion(!m_local_lists.local().empty()); + return m_local_lists.local().front(); + } + + void pop_next_local_element_impl() + { + // Erase last element + m_local_lists.local().pop_front(); + } + + protected: + Filtered_multimap_container_base(bool add_to_TLS_lists = false) + : m_add_to_TLS_lists(add_to_TLS_lists) {} + + template + void splice_local_lists_impl(Container &container) + { + for(typename LocalList::iterator it_list = m_local_lists.begin() ; + it_list != m_local_lists.end() ; + ++it_list ) + { +#ifdef _DEBUG + size_t multimap_size = container.size(); + size_t local_list_size = it_list->size(); +#endif + container.insert(it_list->begin(), it_list->end()); + it_list->clear(); + } + } + + template + bool no_longer_local_element_to_refine_impl(const Predicate &test) + { + bool is_empty = m_local_lists.local().empty(); + while( !is_empty && !test(m_local_lists.local().front().second) ) + { + pop_next_local_element_impl(); + is_empty = m_local_lists.local().empty(); + } + return is_empty; + } + + template + void insert_raw_element(const value_type &re, Container &container) + { + if (m_add_to_TLS_lists) + m_local_lists.local().push_back(re); + else + container.insert(re); + } + + // === Member variables === + + typedef tbb::enumerable_thread_specific< + std::deque > > LocalList; + LocalList m_local_lists; + bool m_add_to_TLS_lists; + }; +#endif // CGAL_LINKED_WITH_TBB + + /************************************************ + // Class Filtered_multimap_container + // + // This container is a filtered multimap: + // front() and empty() use an object predicate + // to test if the element is ok. + ************************************************/ + + template + class Filtered_multimap_container + : public Filtered_multimap_container_base + { + public: + typedef Quality_ Quality; + typedef Element_ Element; + typedef Filtered_multimap_container_base Base; + typedef typename Base::Map Map; + typedef typename Base::value_type value_type; + typedef typename Base::size_type size_type; + + protected: + // --- protected datas --- + Map container; + Predicate test; + + public: + + // Constructors - For sequential + Filtered_multimap_container() {} + explicit Filtered_multimap_container(const Predicate &p) + : test(p) {} + + // Constructors - For parallel + explicit Filtered_multimap_container(bool add_to_TLS_lists) + : Base(add_to_TLS_lists) {} + explicit Filtered_multimap_container(const Predicate &p, bool add_to_TLS_lists) + : test(p), Base(add_to_TLS_lists) {} + + void splice_local_lists_impl() + { +#ifdef _DEBUG + size_t s = size(); +#endif + Base::splice_local_lists_impl(container); + } + + bool no_longer_local_element_to_refine_impl() + { + return Base::no_longer_local_element_to_refine_impl(test); + } + + void insert_raw_element(const value_type &re) + { + Base::insert_raw_element(re, container); + } + + bool no_longer_element_to_refine_impl() + { +#ifdef _DEBUG + size_t multimap_size = container.size(); +#endif + bool is_empty = container.empty(); + while( !is_empty && !test(container.begin()->second) ) + { + pop_next_element_impl(); + is_empty = container.empty(); + } + return is_empty; + } + + // Warning: no_longer_element_to_refine_impl must have been called + // just before calling get_next_element_impl + // (successive calls to "get_next_element_impl" are not allowed) + Element get_next_element_impl() const + { + CGAL_assertion(!container.empty()); + // Add this? It shouldn't be necessary as user + // is supposed to call "no_longer_element_to_refine_impl" first + /*while( !test(container.front()) ) + { + container.pop_front(); + }*/ + return container.begin()->second; + } + + void add_bad_element(const Element& e, const Quality& q) + { + insert_raw_element(std::make_pair(q, e)); + } + + void pop_next_element_impl() + { + // Erase last element + container.erase( container.begin() ); + } + + /*void remove_element(const Element& e) + { + container.erase(container.find(e)); + } + + const Quality& quality(const Element& e) + { + return container[e]; + }*/ + + size_type size() const + { + return container.size(); + } + + // Clear + void clear () + { + container.clear(); + } + + // Warning: no_longer_element_to_refine_impl must have been called + // just before calling get_next_raw_element_impl + // (successive calls to "get_next_raw_element_impl" are not allowed) + value_type get_next_raw_element_impl() + { + CGAL_assertion(!container.empty()); + return *container.begin(); + } + + bool is_zombie(const Element &e) const + { + return !test(e); + } + + }; // end Filtered_multimap_container + +} // end namespace Mesh_3 +} // end namespace CGAL + +#endif // CGAL_MESHES_FILTERED_MULTIMAP_CONTAINER_H diff --git a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h index dceddaca71c..c3fa1d864c3 100644 --- a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h +++ b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h @@ -50,6 +50,10 @@ #include #include +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif + namespace CGAL { namespace Mesh_3 { @@ -202,8 +206,8 @@ public: /// Default constructor Polyhedral_mesh_domain_3() : tree_() - , bounding_tree_(&tree_) - , has_cache(false) {} + , bounding_tree_(&tree_) + {} /** * @brief Constructor. Contruction from a polyhedral surface @@ -211,9 +215,8 @@ public: */ Polyhedral_mesh_domain_3(const Polyhedron& p) : tree_(TriangleAccessor().triangles_begin(p), - TriangleAccessor().triangles_end(p)), - bounding_tree_(&tree_) // the bounding tree is tree_ - , has_cache(false) + TriangleAccessor().triangles_end(p)) + , bounding_tree_(&tree_) // the bounding tree is tree_ { if(!p.is_pure_triangle()) { std::cerr << "Your input polyhedron must be triangulated!\n"; @@ -227,7 +230,6 @@ public: TriangleAccessor().triangles_end(p)) , bounding_tree_(new AABB_tree_(TriangleAccessor().triangles_begin(bounding_polyhedron), TriangleAccessor().triangles_end(bounding_polyhedron))) - , has_cache(false) { tree_.insert(TriangleAccessor().triangles_begin(bounding_polyhedron), TriangleAccessor().triangles_end(bounding_polyhedron)); @@ -250,7 +252,6 @@ public: Polyhedral_mesh_domain_3(InputPolyhedraPtrIterator begin, InputPolyhedraPtrIterator end, const Polyhedron& bounding_polyhedron) - : has_cache(false) { if(begin != end) { for(; begin != end; ++begin) { @@ -285,7 +286,6 @@ public: template Polyhedral_mesh_domain_3(InputPolyhedraPtrIterator begin, InputPolyhedraPtrIterator end) - : has_cache(false) { if(begin != end) { for(; begin != end; ++begin) { @@ -423,14 +423,14 @@ public: #ifndef CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 if(r_domain_.query_is_cached(q)) { - const AABB_primitive_id primitive_id = r_domain_.cached_primitive_id; + const AABB_primitive_id primitive_id = r_domain_.cached_primitive_id(); typename cpp11::result_of< typename IGT::Intersect_3(typename Primitive::Datum, Query)>::type o = IGT().intersect_3_object()(Primitive(primitive_id).datum(),q); intersection = o ? Intersection_and_primitive_id(*o, primitive_id) : AABB_intersection(); - } else + } else #endif // not CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 { #ifndef CGAL_MESH_3_NO_LONGER_CALLS_DO_INTERSECT_3 @@ -589,11 +589,20 @@ private: AABB_tree_* bounding_tree_; - // cache queries and intersected primitive + // cache queries and intersected primitive typedef typename boost::make_variant_over::type Cached_query; - mutable bool has_cache; - mutable Cached_query cached_query; - mutable AABB_primitive_id cached_primitive_id; + struct Query_cache + { + Query_cache() : has_cache(false) {} + bool has_cache; + Cached_query cached_query; + AABB_primitive_id cached_primitive_id; + }; +#ifdef CGAL_LINKED_WITH_TBB + mutable tbb::enumerable_thread_specific query_cache; +#else + mutable Query_cache query_cache; +#endif public: @@ -601,14 +610,35 @@ public: void cache_primitive(const Query& q, const AABB_primitive_id id) const { - cached_query = Cached_query(q); - has_cache = true; - cached_primitive_id = id; +#ifdef CGAL_LINKED_WITH_TBB + Query_cache &qc = query_cache.local(); + qc.cached_query = Cached_query(q); + qc.has_cache = true; + qc.cached_primitive_id = id; +#else + query_cache.cached_query = Cached_query(q); + query_cache.has_cache = true; + query_cache.cached_primitive_id = id; +#endif } template bool query_is_cached(const Query& q) const { - return has_cache && (cached_query == Cached_query(q)); +#ifdef CGAL_LINKED_WITH_TBB + Query_cache &qc = query_cache.local(); + return qc.has_cache && (qc.cached_query == Cached_query(q)); +#else + return query_cache.has_cache + && (query_cache.cached_query == Cached_query(q)); +#endif + } + + AABB_primitive_id cached_primitive_id() const { +#ifdef CGAL_LINKED_WITH_TBB + return query_cache.local().cached_primitive_id; +#else + return query_cache.cached_primitive_id; +#endif } private: @@ -641,9 +671,9 @@ Construct_initial_points::operator()(OutputIterator pts, Random_points_on_sphere_3 random_point(1.); int i = n; -#ifdef CGAL_MESH_3_VERBOSE +# ifdef CGAL_MESH_3_VERBOSE std::cerr << "construct initial points:" << std::endl; -#endif +# endif // Point construction by ray shooting from the center of the enclosing bbox while ( i > 0 ) { @@ -666,11 +696,11 @@ Construct_initial_points::operator()(OutputIterator pts, "%1%/%2% initial point(s) found...") % (n - i) % n; -#endif +# endif } ++random_point; } - + #ifdef CGAL_MESH_3_VERBOSE std::cerr << std::endl; #endif 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 65ebf82fa4a..a3ebfd5bf20 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 @@ -58,7 +58,7 @@ template < class IGT_, class Polyhedron_ = typename Mesh_polyhedron_3::type, class TriangleAccessor=Triangle_accessor_3, class Use_patch_id_tag = Tag_true, - class Use_exact_intersection_construction_tag = CGAL::Tag_true > + class Use_exact_intersection_construction_tag = Tag_true > class Polyhedral_mesh_domain_with_features_3 : public Mesh_domain_with_polyline_features_3< Polyhedral_mesh_domain_3< Polyhedron_, diff --git a/Mesh_3/include/CGAL/exude_mesh_3.h b/Mesh_3/include/CGAL/exude_mesh_3.h index 96a56238bc2..ce24b1dfa20 100644 --- a/Mesh_3/include/CGAL/exude_mesh_3.h +++ b/Mesh_3/include/CGAL/exude_mesh_3.h @@ -38,32 +38,34 @@ BOOST_PARAMETER_FUNCTION( (Mesh_optimization_return_code), exude_mesh_3, parameters::tag, - (required (in_out(c3t3),*) ) + (required (in_out(c3t3),*) (domain,*) ) (optional (time_limit_, *, 0 ) (sliver_bound_, *, parameters::default_values::exude_sliver_bound ) ) ) { - return exude_mesh_3_impl(c3t3, time_limit_, sliver_bound_); + return exude_mesh_3_impl(c3t3, domain, time_limit_, sliver_bound_); } -template +template Mesh_optimization_return_code exude_mesh_3_impl(C3T3& c3t3, + const MeshDomain& domain, const double time_limit, const double sliver_bound) { + typedef MeshDomain Md; typedef typename C3T3::Triangulation Tr; typedef Mesh_3::Min_dihedral_angle_criterion Sc; //typedef Mesh_3::Radius_radio_criterion Sc; - typedef typename Mesh_3::Slivers_exuder Exuder; + typedef typename Mesh_3::Slivers_exuder Exuder; // Create exuder Sc criterion(sliver_bound, c3t3.triangulation()); - Exuder exuder(c3t3, criterion); + Exuder exuder(c3t3, domain, criterion); // Set time_limit exuder.set_time_limit(time_limit); diff --git a/Mesh_3/include/CGAL/make_mesh_3.h b/Mesh_3/include/CGAL/make_mesh_3.h index 41f83852532..de9d6490331 100644 --- a/Mesh_3/include/CGAL/make_mesh_3.h +++ b/Mesh_3/include/CGAL/make_mesh_3.h @@ -187,7 +187,7 @@ init_c3t3_with_features(C3T3& c3t3, { typedef typename MeshCriteria::Edge_criteria Edge_criteria; typedef Edge_criteria_sizing_field_wrapper Sizing_field; - + CGAL::Mesh_3::Protect_edges_sizing_field protect_edges(c3t3, domain, Sizing_field(criteria.edge_criteria_object())); @@ -402,6 +402,10 @@ void make_mesh_3_impl(C3T3& c3t3, const parameters::internal::Mesh_3_options& mesh_options = parameters::internal::Mesh_3_options()) { +#ifdef CGAL_MESH_3_INITIAL_POINTS_NO_RANDOM_SHOOTING + CGAL::default_random = CGAL::Random(0); +#endif + // Initialize c3t3 internal::Mesh_3::C3t3_initializer< C3T3, diff --git a/Mesh_3/include/CGAL/refine_mesh_3.h b/Mesh_3/include/CGAL/refine_mesh_3.h index 0c4cc81a56f..d7208c8ce06 100644 --- a/Mesh_3/include/CGAL/refine_mesh_3.h +++ b/Mesh_3/include/CGAL/refine_mesh_3.h @@ -463,6 +463,7 @@ void refine_mesh_3_impl(C3T3& c3t3, exude_time_limit = exude.time_limit(); exude_mesh_3(c3t3, + domain, parameters::time_limit = exude_time_limit, parameters::sliver_bound = exude.bound()); } diff --git a/Mesh_3/test/Mesh_3/CMakeLists.txt b/Mesh_3/test/Mesh_3/CMakeLists.txt index 9b791b1cde3..9a635172092 100644 --- a/Mesh_3/test/Mesh_3/CMakeLists.txt +++ b/Mesh_3/test/Mesh_3/CMakeLists.txt @@ -11,12 +11,18 @@ else() cmake_policy(VERSION 2.6) endif() -find_package(CGAL QUIET COMPONENTS Core ImageIO) +find_package(CGAL QUIET COMPONENTS ImageIO) if ( CGAL_FOUND ) - include( ${CGAL_USE_FILE} ) + find_package( TBB QUIET ) + + if( TBB_FOUND ) + include(${TBB_USE_FILE}) + list(APPEND CGAL_3RD_PARTY_LIBRARIES ${TBB_LIBRARIES}) + endif() + include( CGAL_CreateSingleSourceCGALProgram ) include_directories (BEFORE ../../include) diff --git a/Mesh_3/test/Mesh_3/XML_exporter.h b/Mesh_3/test/Mesh_3/XML_exporter.h new file mode 100644 index 00000000000..158d3d648d4 --- /dev/null +++ b/Mesh_3/test/Mesh_3/XML_exporter.h @@ -0,0 +1,236 @@ +// Copyright (c) 2012 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: $ +// $Id: $ +// +// +// Author(s) : Clement Jamin +// + +#include +#include +#include +#include +#include + +template +class Simple_XML_exporter +{ +public: + typedef value_type Value_type; + typedef std::vector Element; + typedef std::map Element_with_map; + typedef std::vector List_of_elements; + + Simple_XML_exporter( + const std::string &list_name, + const std::string &element_name, + const std::vector &subelement_names, + bool add_timestamp = true) + : m_list_name(list_name), + m_element_name(element_name), + m_subelement_names(subelement_names), + m_add_timestamp(add_timestamp) + {} + + bool add_element(const Element &element) + { + if (element.size() == m_subelement_names.size()) + { + m_list_of_elements.push_back(element); + return true; + } + else + { + std::cerr << "ERROR: element.size() == m_subelement_names.size()" << std::endl; + return false; + } + } + + bool add_element(Element_with_map &element) + { + Element elt; + + std::vector::const_iterator + it_subelement_name = m_subelement_names.begin(); + std::vector::const_iterator + it_subelement_name_end = m_subelement_names.end(); + for ( ; it_subelement_name != it_subelement_name_end ; ++it_subelement_name) + { + elt.push_back(element[*it_subelement_name]); + } + + return add_element(elt); + } + + bool export_to_xml(const std::string &filename) const + { + std::ofstream xmlfile; + xmlfile.open(filename.c_str()); + xmlfile << "" << std::endl; + xmlfile << "<" << m_list_name << ">" << std::endl; + + typename List_of_elements::const_iterator it_element = m_list_of_elements.begin(); + typename List_of_elements::const_iterator it_element_end = m_list_of_elements.end(); + for (int id = 1 ; it_element != it_element_end ; ++it_element, ++id) + { + xmlfile << " <" << m_element_name << ">" << std::endl; + std::vector::const_iterator + it_subelement_name = m_subelement_names.begin(); + std::vector::const_iterator + it_subelement_name_end = m_subelement_names.end(); + + if (m_add_timestamp) + xmlfile << " " << time(NULL) << " " << std::endl; + + for (int i = 0 ; + it_subelement_name != it_subelement_name_end ; + ++it_subelement_name, ++i) + { + xmlfile + << " <" << *it_subelement_name << "> " + << (*it_element)[i] + << " " << std::endl; + } + xmlfile << " " << std::endl; + } + + xmlfile << "" << std::endl; + xmlfile.close(); + return 0; + + } + +protected: + std::string m_list_name; + std::string m_element_name; + std::vector m_subelement_names; + List_of_elements m_list_of_elements; + bool m_add_timestamp; +}; + + + + + +template +class Streaming_XML_exporter +{ +public: + typedef value_type Value_type; + typedef std::vector Element; + typedef std::map Element_with_map; + typedef std::vector List_of_elements; + + Streaming_XML_exporter( + const std::string &filename, + const std::string &list_name, + const std::string &element_name, + const std::vector &subelement_names, + bool add_timestamp = true) + : m_list_name(list_name), + m_element_name(element_name), + m_subelement_names(subelement_names), + m_add_timestamp(add_timestamp) + { + m_xml_fstream.open(filename.c_str()); + if (m_xml_fstream.good()) + { + m_xml_fstream << "" << std::endl; + m_xml_fstream << "<" << m_list_name << ">" << std::endl; + } + else + { + std::cerr << "Could not open file '" << filename << "'." << std::endl; + } + } + + virtual ~Streaming_XML_exporter() + { + close_file(); + } + + void close_file() + { + m_xml_fstream.close(); + } + + bool add_element(const Element &element) + { + if (element.size() == m_subelement_names.size()) + { + m_xml_fstream << " <" << m_element_name << ">" << std::endl; + std::vector::const_iterator + it_subelement_name = m_subelement_names.begin(); + std::vector::const_iterator + it_subelement_name_end = m_subelement_names.end(); + + if (m_add_timestamp) + { + m_xml_fstream << " " << time(NULL) << " " << std::endl; + } + + for (int i = 0 ; + it_subelement_name != it_subelement_name_end ; + ++it_subelement_name, ++i) + { + m_xml_fstream + << " <" << *it_subelement_name << "> " + << element[i] + << " " << std::endl; + } + m_xml_fstream << " " << std::endl; + + // Save current pointer position + std::ofstream::streampos pos = m_xml_fstream.tellp(); + // Close the XML file (temporarily) so that the XML file is always correct + m_xml_fstream << "" << std::endl; + // Restore the pointer position so that the next "add_element" will overwrite + // the end of the file + m_xml_fstream.seekp(pos); + + m_xml_fstream.flush(); + return true; + } + else + { + std::cerr << "ERROR: element.size() == m_subelement_names.size()" << std::endl; + return false; + } + } + + bool add_element(Element_with_map &element) + { + Element elt; + + std::vector::const_iterator + it_subelement_name = m_subelement_names.begin(); + std::vector::const_iterator + it_subelement_name_end = m_subelement_names.end(); + for ( ; it_subelement_name != it_subelement_name_end ; ++it_subelement_name) + { + elt.push_back(element[*it_subelement_name]); + } + + return add_element(elt); + } + +protected: + std::ofstream m_xml_fstream; + std::string m_list_name; + std::string m_element_name; + std::vector m_subelement_names; + bool m_add_timestamp; +}; diff --git a/Mesh_3/test/Mesh_3/test_backward_compatibility.cpp b/Mesh_3/test/Mesh_3/test_backward_compatibility.cpp index af28e961706..2015088d1ee 100644 --- a/Mesh_3/test/Mesh_3/test_backward_compatibility.cpp +++ b/Mesh_3/test/Mesh_3/test_backward_compatibility.cpp @@ -94,7 +94,14 @@ typedef FT (Function)(const Point&); typedef CGAL::Implicit_mesh_domain_3 Mesh_domain; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, + CGAL::Parallel_tag>::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; // Criteria diff --git a/Mesh_3/test/Mesh_3/test_c3t3_io.cpp b/Mesh_3/test/Mesh_3/test_c3t3_io.cpp index e67994131ba..400f2ce1b56 100644 --- a/Mesh_3/test/Mesh_3/test_c3t3_io.cpp +++ b/Mesh_3/test/Mesh_3/test_c3t3_io.cpp @@ -255,6 +255,12 @@ struct Test_c3t3_io { typename Tr::Cell_handle c2 = fit2->first; int i1 = fit1->second; int i2 = fit2->second; + // CJ: this may cause an assertion because the 2 C3T3s may have + // facets in different orders. + // This is because the Finite_facets_iterator compares the + // addresses of cells to ensure parsing unique facets. The + // facets are stored in a Compact_container, which doesn't + /// guarantee any order in memory (and even in the container itself) assert(i1 == i2); if( c1->surface_patch_index(i1) != c2->surface_patch_index(i2) ) diff --git a/Mesh_3/test/Mesh_3/test_domain_with_polyline_features.cpp b/Mesh_3/test/Mesh_3/test_domain_with_polyline_features.cpp index 3b5319d2ec2..076729acebb 100644 --- a/Mesh_3/test/Mesh_3/test_domain_with_polyline_features.cpp +++ b/Mesh_3/test/Mesh_3/test_domain_with_polyline_features.cpp @@ -42,7 +42,14 @@ struct Dummy_domain typedef Dummy_domain Smooth_domain; typedef CGAL::Mesh_domain_with_polyline_features_3 Mesh_domain; -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, + CGAL::Parallel_tag>::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; typedef Mesh_domain::Point_3 Point; diff --git a/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp b/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp index b5c342dc124..fd4e9170605 100644 --- a/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp +++ b/Mesh_3/test/Mesh_3/test_mesh_criteria_creation.cpp @@ -8,7 +8,14 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Polyhedral_mesh_domain_with_features_3 Mesh_domain; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, + CGAL::Parallel_tag>::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif // Criteria typedef CGAL::Mesh_criteria_3 Mc; typedef CGAL::Mesh_constant_domain_field_3 Mesh_domain; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef typename CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, + CGAL::Parallel_tag>::type Tr; +#else typedef typename CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; typedef CGAL::Mesh_criteria_3 Mesh_criteria; diff --git a/Mesh_3/test/Mesh_3/test_meshing_implicit_function.cpp b/Mesh_3/test/Mesh_3/test_meshing_implicit_function.cpp index 68737e1ae46..27004dd0315 100644 --- a/Mesh_3/test/Mesh_3/test_meshing_implicit_function.cpp +++ b/Mesh_3/test/Mesh_3/test_meshing_implicit_function.cpp @@ -43,7 +43,14 @@ struct Implicit_tester : public Tester typedef CGAL::Implicit_mesh_domain_3 Mesh_domain; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef typename CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, + CGAL::Parallel_tag>::type Tr; +#else typedef typename CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; typedef CGAL::Mesh_criteria_3 Mesh_criteria; diff --git a/Mesh_3/test/Mesh_3/test_meshing_polyhedron.cpp b/Mesh_3/test/Mesh_3/test_meshing_polyhedron.cpp index b49ee30ea83..606ace1e4a3 100644 --- a/Mesh_3/test/Mesh_3/test_meshing_polyhedron.cpp +++ b/Mesh_3/test/Mesh_3/test_meshing_polyhedron.cpp @@ -26,7 +26,7 @@ #include #include -template +template struct Polyhedron_tester : public Tester { void polyhedron() const @@ -35,7 +35,10 @@ struct Polyhedron_tester : public Tester typedef CGAL::Polyhedron_3 Polyhedron; typedef CGAL::Polyhedral_mesh_domain_3 Mesh_domain; - typedef typename CGAL::Mesh_triangulation_3::type Tr; + typedef typename CGAL::Mesh_triangulation_3< + Mesh_domain, + typename CGAL::Kernel_traits::Kernel, + Concurrency_tag>::type Tr; typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; typedef CGAL::Mesh_criteria_3 Mesh_criteria; @@ -85,6 +88,15 @@ int main() Polyhedron_tester test_epic; std::cerr << "Mesh generation from a polyhedron:\n"; test_epic.polyhedron(); - + +#ifdef CGAL_LINKED_WITH_TBB + Polyhedron_tester test_epic_parallel; + std::cerr << "Mesh generation from a polyhedron using Parallel_tag:\n"; + test_epic_parallel.polyhedron(); +#else + std::cerr << "TBB is not installed, or not configured." + << "The parallel version cannot be tested.\n"; +#endif + return EXIT_SUCCESS; } diff --git a/Mesh_3/test/Mesh_3/test_meshing_polyhedron_with_features.cpp b/Mesh_3/test/Mesh_3/test_meshing_polyhedron_with_features.cpp index 2d35bd2907c..84c899b942b 100644 --- a/Mesh_3/test/Mesh_3/test_meshing_polyhedron_with_features.cpp +++ b/Mesh_3/test/Mesh_3/test_meshing_polyhedron_with_features.cpp @@ -37,7 +37,14 @@ struct Polyhedron_with_features_tester : public Tester typedef CGAL::Mesh_3::Robust_intersection_traits_3 Gt; typedef CGAL::Polyhedral_mesh_domain_with_features_3 Mesh_domain; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef typename CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, + CGAL::Parallel_tag>::type Tr; +#else typedef typename CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3 < Tr, typename Mesh_domain::Corner_index, diff --git a/Mesh_3/test/Mesh_3/test_meshing_polylines_only.cpp b/Mesh_3/test/Mesh_3/test_meshing_polylines_only.cpp index 9a9603ff04a..d5fdbcb4816 100644 --- a/Mesh_3/test/Mesh_3/test_meshing_polylines_only.cpp +++ b/Mesh_3/test/Mesh_3/test_meshing_polylines_only.cpp @@ -18,7 +18,14 @@ typedef CGAL::Polyhedral_mesh_domain_with_features_3 Mesh_domain; typedef CGAL::Mesh_polyhedron_3::type Polyhedron; // Triangulation -typedef CGAL::Mesh_triangulation_3::type Tr; +#ifdef CGAL_CONCURRENT_MESH_3 + typedef CGAL::Mesh_triangulation_3< + Mesh_domain, + CGAL::Kernel_traits::Kernel, + CGAL::Parallel_tag>::type Tr; +#else + typedef CGAL::Mesh_triangulation_3::type Tr; +#endif typedef CGAL::Mesh_complex_3_in_triangulation_3< Tr,Mesh_domain::Corner_index,Mesh_domain::Curve_segment_index> C3t3; diff --git a/Mesh_3/test/Mesh_3/test_meshing_utilities.h b/Mesh_3/test/Mesh_3/test_meshing_utilities.h index 4d0738ac3d5..1e81bb73d95 100644 --- a/Mesh_3/test/Mesh_3/test_meshing_utilities.h +++ b/Mesh_3/test/Mesh_3/test_meshing_utilities.h @@ -107,15 +107,16 @@ struct Tester int n = 0; while ( c3t3.triangulation().number_of_vertices() != v && ++n < 11 ) { + v = c3t3.triangulation().number_of_vertices(); + refine_mesh_3(c3t3,domain,criteria, CGAL::parameters::no_exude(), CGAL::parameters::no_perturb(), CGAL::parameters::no_reset_c3t3()); - - v = c3t3.triangulation().number_of_vertices(); - f = c3t3.number_of_facets_in_complex(); - c = c3t3.number_of_cells_in_complex(); } + + f = c3t3.number_of_facets_in_complex(); + c = c3t3.number_of_cells_in_complex(); assert ( n < 11 ); #endif @@ -128,7 +129,7 @@ struct Tester // Quality should increase C3t3 exude_c3t3(c3t3); std::cerr << "Exude...\n"; - CGAL::exude_mesh_3(exude_c3t3); + CGAL::exude_mesh_3(exude_c3t3, domain); verify_c3t3(exude_c3t3,domain,domain_type,v,v,f,f); verify_c3t3_quality(c3t3,exude_c3t3); verify_c3t3_volume(exude_c3t3, volume*0.95, volume*1.05); diff --git a/Miscellany/doc/Miscellany/CGAL/Unique_hash_map.h b/Miscellany/doc/Miscellany/CGAL/Unique_hash_map.h index f36b6a8e270..364240a2e93 100644 --- a/Miscellany/doc/Miscellany/CGAL/Unique_hash_map.h +++ b/Miscellany/doc/Miscellany/CGAL/Unique_hash_map.h @@ -15,6 +15,10 @@ objects \f$ key\f$ stored in `map`. The template parameter has as default the `Handle_hash_function` that hashes all types of pointers, handles, iterators, and circulators. +The parameter `Allocator` has to match the standard allocator +requirements, with value type `Data`. This parameter has the default +value `CGAL_ALLOCATOR(Data)`. + All variables are initialized to `default_data`, a value of type `Data` specified in the definition of `map`. @@ -34,7 +38,7 @@ allow for a more time- and space-efficient implementation, see also of sentinels that lead to defined keys that have not been inserted. */ -template< typename Key, typename Data, typename UniqueHashFunction > +template< typename Key, typename Data, typename UniqueHashFunction, typename Allocator> class Unique_hash_map { public: diff --git a/Profiling_tools/include/CGAL/Profile_counter.h b/Profiling_tools/include/CGAL/Profile_counter.h index b4ee13ae604..69c9a417475 100644 --- a/Profiling_tools/include/CGAL/Profile_counter.h +++ b/Profiling_tools/include/CGAL/Profile_counter.h @@ -1,4 +1,4 @@ -// Copyright (c) 2005,2006,2008 INRIA Sophia-Antipolis (France). +//r Copyright (c) 2005,2006,2008 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or @@ -38,6 +38,8 @@ // - Profile_branch_counter_3 which keeps track of 3 counters, aiming at measuring // the ratios corresponding to the number of times 2 branches are taken. // +// If CGAL_CONCURRENT_PROFILE is defined, the counters can be concurrently updated +// // See also CGAL/Profile_timer.h // TODO : @@ -54,12 +56,31 @@ #include #include +// Automatically define CGAL_CONCURRENT_PROFILE if we're linked with TBB +#ifdef CGAL_LINKED_WITH_TBB +# ifndef CGAL_CONCURRENT_PROFILE +# define CGAL_CONCURRENT_PROFILE +# endif +#else +// Automatically UNdefine CGAL_CONCURRENT_PROFILE if we're NOT linked with TBB +# ifdef CGAL_CONCURRENT_PROFILE +# undef CGAL_CONCURRENT_PROFILE +# endif +#endif + +#ifdef CGAL_CONCURRENT_PROFILE +# include "tbb/concurrent_hash_map.h" +#endif + namespace CGAL { struct Profile_counter { Profile_counter(const std::string & ss) - : i(0), s(ss) {} + : s(ss) + { + i = 0; // needed here because of tbb::atomic + } void operator++() { ++i; } @@ -70,7 +91,11 @@ struct Profile_counter } private: +#ifdef CGAL_CONCURRENT_PROFILE + tbb::atomic i; +#else unsigned int i; +#endif const std::string s; }; @@ -78,10 +103,27 @@ private: struct Profile_histogram_counter { +private: +#ifdef CGAL_CONCURRENT_PROFILE + typedef tbb::concurrent_hash_map Counters; +#else + typedef std::map Counters; +#endif + +public: Profile_histogram_counter(const std::string & ss) : s(ss) {} - void operator()(unsigned i) { ++counters[i]; } + void operator()(unsigned i) + { +#ifdef CGAL_CONCURRENT_PROFILE + Counters::accessor a; + counters.insert(a, i); + ++a->second; +#else + ++counters[i]; +#endif + } ~Profile_histogram_counter() { @@ -100,7 +142,6 @@ struct Profile_histogram_counter } private: - typedef std::map Counters; Counters counters; const std::string s; }; @@ -109,7 +150,10 @@ private: struct Profile_branch_counter { Profile_branch_counter(const std::string & ss) - : i(0), j(0), s(ss) {} + : s(ss) + { + i = j = 0; // needed here because of tbb::atomic + } void operator++() { ++i; } @@ -123,7 +167,11 @@ struct Profile_branch_counter } private: +#ifdef CGAL_CONCURRENT_PROFILE + tbb::atomic i, j; +#else unsigned int i, j; +#endif const std::string s; }; @@ -131,7 +179,10 @@ private: struct Profile_branch_counter_3 { Profile_branch_counter_3(const std::string & ss) - : i(0), j(0), k(0), s(ss) {} + : s(ss) + { + i = j = k = 0; // needed here because of tbb::atomic + } void operator++() { ++i; } @@ -147,7 +198,11 @@ struct Profile_branch_counter_3 } private: +#ifdef CGAL_CONCURRENT_PROFILE + tbb::atomic i, j, k; +#else unsigned int i, j, k; +#endif const std::string s; }; diff --git a/STL_Extension/benchmark/compact_container_benchmark/CMakeLists.txt b/STL_Extension/benchmark/compact_container_benchmark/CMakeLists.txt new file mode 100644 index 00000000000..3fd60ef3cec --- /dev/null +++ b/STL_Extension/benchmark/compact_container_benchmark/CMakeLists.txt @@ -0,0 +1,37 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + +project( Compact_container_benchmark ) + +cmake_minimum_required(VERSION 2.6.2) +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6) + if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3) + cmake_policy(VERSION 2.8.4) + else() + cmake_policy(VERSION 2.6) + endif() +endif() + +find_package(CGAL QUIET COMPONENTS Core ) + +if ( CGAL_FOUND ) + include( ${CGAL_USE_FILE} ) + + find_package( TBB ) + + if( TBB_FOUND ) + include(${TBB_USE_FILE}) + list(APPEND CGAL_3RD_PARTY_LIBRARIES ${TBB_LIBRARIES}) + endif() + + include( CGAL_CreateSingleSourceCGALProgram ) + + include_directories (BEFORE "../../include") + + create_single_source_cgal_program( "cc_benchmark.cpp" ) + +else() + + message(STATUS "This program requires the CGAL library, and will not be compiled.") + +endif() diff --git a/STL_Extension/benchmark/compact_container_benchmark/cc_benchmark.cpp b/STL_Extension/benchmark/compact_container_benchmark/cc_benchmark.cpp index 6d216c80acc..8daa0bcf94e 100644 --- a/STL_Extension/benchmark/compact_container_benchmark/cc_benchmark.cpp +++ b/STL_Extension/benchmark/compact_container_benchmark/cc_benchmark.cpp @@ -47,6 +47,7 @@ inline void compute_the_thing(Truc &thing) } #ifdef CGAL_LINKED_WITH_TBB +// For parallel_for template class Change_array_functor { @@ -54,6 +55,9 @@ public: Change_array_functor(Array_t &v) : m_v(v) {} + Change_array_functor(const Change_array_functor &caf) + : m_v(caf.m_v) {} + void operator() (const tbb::blocked_range& r) const { for(size_t i = r.begin(); i != r.end(); i++ ) @@ -65,12 +69,17 @@ private: Array_t &m_v; }; +// For parallel_for +// Specialization for std::vector template <> class Change_array_functor > { public: Change_array_functor(std::vector &v) : m_v(v) {} + + Change_array_functor(const Change_array_functor &caf) + : m_v(caf.m_v) {} void operator() (const tbb::blocked_range& r) const { @@ -82,6 +91,17 @@ private: std::vector &m_v; }; +// For parallel_do +template +class Change_array_functor_2 +{ +public: + void operator() (typename Array_t::value_type& truc) const + { + compute_the_thing(truc); + } +}; + // Parallel_for // For vector only double change_array(std::vector &v, Parallel_for_tag) @@ -125,10 +145,7 @@ double change_array(Array_t &v, Parallel_do_tag) t.start(); tbb::parallel_do( v.begin(), v.end(), - []( typename Array_t::value_type& truc ) // CJTODO: lambdas ok? - { - compute_the_thing(truc); - }); + Change_array_functor_2()); t.stop(); std::cout << " done in " << t.time() << " seconds." << std::endl; return t.time(); diff --git a/STL_Extension/doc/STL_Extension/CGAL/CC_safe_handle.h b/STL_Extension/doc/STL_Extension/CGAL/CC_safe_handle.h new file mode 100644 index 00000000000..8b1f42a1eb8 --- /dev/null +++ b/STL_Extension/doc/STL_Extension/CGAL/CC_safe_handle.h @@ -0,0 +1,65 @@ + +namespace CGAL { + +/// \ingroup PkgStlExtension + +/*! +\ingroup CompactContainer + +The class `CC_safe_handle` is a helper class that stores an iterator on a +`Compact_container` (or `Concurrent_compact_container`) and +is able to know if the pointee has been erased after the creation of the +`CC_safe_handle` instance. +It stores the iterator and the erase counter value of the pointee when the +`CC_safe_handle` instance was created. +It can only be used when the pointee type is a model of the +`ObjectWithEraseCounter` concept. + +\tparam CC_iterator is the type of the stored iterator (on a `Compact_container` + or a `Concurrent_compact_container`) + +\sa `Compact_container` +\sa `Concurrent_compact_container` +*/ + +template +class CC_safe_handle +{ + typedef typename CC_iterator::Strategy Strategy; + +public: + /// \name Creation + /*! + Introduces a safe handle from a `Compact_container` iterator. + */ + CC_safe_handle(CC_iterator iterator); + + /// \name Access Member Functions + /// @{ + /*! + Returns `true` if the pointee has been erased, i.e.\ if the iterator points to + a freed object or to another object. + */ + bool is_zombie() const; + + /*! + Returns the stored `Compact_container` iterator. + */ + CC_iterator cc_iterator() const; + /// @} +}; + + +/*! +\ingroup CompactContainer + +The class `make_cc_safe_handle` function allows to build a `CC_safe_handle` +from an iterator on a `Compact_container` (or `Concurrent_compact_container`). + +\sa `CC_safe_handle` +*/ + +template +CC_safe_handle make_cc_safe_handle(CC_iterator iterator); + +} //namespace CGAL \ No newline at end of file diff --git a/STL_Extension/doc/STL_Extension/CGAL/Compact_container.h b/STL_Extension/doc/STL_Extension/CGAL/Compact_container.h index 97a19f7140e..260e751fae2 100644 --- a/STL_Extension/doc/STL_Extension/CGAL/Compact_container.h +++ b/STL_Extension/doc/STL_Extension/CGAL/Compact_container.h @@ -48,7 +48,9 @@ namespace CGAL { \ingroup CompactContainer An object of the class `Compact_container` -is a container of objects of type `T`. It matches all the +is a container of objects of type `T`. + +This container matches all the standard requirements for reversible containers, except that the complexity of its iterator increment and decrement operations is not always guaranteed to be amortized constant time. @@ -97,7 +99,16 @@ In addition, in a way inspired from the Boost.Intrusive containers, it is possible to construct iterators from references to values in containers using the `iterator_to` and `s_iterator_to` functions. - +The objects stored in the `Compact_container` can optionally store an +"erase counter". If it exists, i.e.\ if the object is a model of the +`ObjectWithEraseCounter` concept, each time an object is erased from the +container, the erase counter of the object will be incremented. +For example, this erase counter can be exploited using the `CC_safe_handle` +helper class, so that one can know if a handle is still pointing to the same +element. +Note that this is meaningful only because the +`CGAL::Compact_container` doesn't +deallocate elements until the destruction or clear() of the container. \cgalHeading{Parameters} @@ -479,7 +490,8 @@ size_type size() const; /// \name Access Member Functions /// @{ /*! -returns the maximum possible size of the container `cc`. +returns the maximum possible size of the container `cc`. +This is the allocator's max_size value. */ size_type max_size() const; diff --git a/STL_Extension/doc/STL_Extension/CGAL/Concurrent_compact_container.h b/STL_Extension/doc/STL_Extension/CGAL/Concurrent_compact_container.h new file mode 100644 index 00000000000..8b73200f258 --- /dev/null +++ b/STL_Extension/doc/STL_Extension/CGAL/Concurrent_compact_container.h @@ -0,0 +1,328 @@ + +namespace CGAL { + +/// \ingroup PkgStlExtension + +/*! +\ingroup CompactContainer + +The traits class `Concurrent_compact_container_traits` provides +the way to access the internal pointer required for `T` to be +used in a `Concurrent_compact_container`. Note that this +pointer needs to be accessible even when the object is not constructed, +which means it has to reside in the same memory place as `T`. + +You can specialize this class for your own type `T` +if the default template is not suitable. + +You can also use `Compact_container_base` as base class for your own +types `T` to make them usable with the default `Concurrent_compact_container`. + +\cgalHeading{Parameters} + +`T` is any type providing the following member functions: +`void * t.for_compact_container() const;` +`void *& t.for_compact_container();`. +*/ +template< typename T > +class Concurrent_compact_container_traits { +public: + +/// \name Operations +/// @{ + /*! + Returns the pointer held by `t`. + The template version defines this function as: `return t.for_compact_container(); + */ + static void * pointer(const T &t); + +/// @} + +/// \name Operations +/// @{ + /*! + Returns a reference to the pointer held by `t`. + The template version defines this function as: `return t.for_compact_container();` + + */ + static void * & pointer(T &t); + +/// @} + +}; /* end Concurrent_compact_container_traits */ + + +/*! +\ingroup CompactContainer + +An object of the class `Concurrent_compact_container` +is a container of objects of type `T`, which allows to call +`insert` and `erase` operations concurrently. +Other operations are not concurrency-safe. +For example, one should not parse the container while others are modifying it. +It matches all the +standard requirements for reversible containers, except that +the complexity of its iterator increment and decrement operations +is not always guaranteed to be amortized constant time. + +This container is not a standard sequence nor associative container, +which means the elements are stored in no particular order, and it is not +possible to specify a particular place in the iterator sequence where to +insert new objects. However, all dereferenceable iterators are +still valid after calls to `insert()` and `erase()`, except those +that have been erased (it behaves similarly to `std::list`). + +The main feature of this container is that it is very memory efficient: +its memory size is `N*sizeof(T)+o(N)`, where `N` is the maximum size +that the container has had in its past history, its `capacity()` +(the memory of erased elements is not deallocated until destruction of the +container or a call to `clear()`). This container has been developed in +order to store large graph-like data structures like the triangulation and +the halfedge data structures. + +It supports bidirectional iterators and allows a constant time amortized +`insert()` operation. You cannot specify where to insert new objects +(i.e.\ you don't know where they will end up in the iterator sequence, +although `insert()` returns an iterator pointing to the newly inserted +object). You can erase any element with a constant time complexity. + +Summary of the differences with `std::list`: it is more compact in +memory since it doesn't store two additional pointers for the iterator needs. +It doesn't deallocate elements until the destruction or `clear()` of the +container. The iterator does not have constant amortized time complexity for +the increment and decrement operations in all cases, only when not too many +elements have not been freed (i.e.\ when the `size()` is close to the +`capacity()`). Iterating from `begin()` to `end()` takes +`O(capacity())` time, not `size()`. In the case where the container +has a small `size()` compared to its `capacity()`, we advise to +\"defragment the memory\" by copying the container if the iterator performance +is needed. + +The iterators themselves can be used as `T`, they provide the necessary +functions to be used by `Compact_container_traits`. Moreover, they +also provide a default constructor value which is not singular: it is +copyable, comparable, and guaranteed to be unique under comparison +(like `NULL` for pointers). This makes them suitable for use in +geometric graphs like handles to vertices in triangulations. + +In addition, in a way inspired from the Boost.Intrusive containers, it is +possible to construct iterators from references to values in containers +using the `iterator_to` and `s_iterator_to` functions. + +The objects stored in the `Concurrent_compact_container` can optionally store an +"erase counter". If it exists, i.e.\ if the object is a model of the +`ObjectWithEraseCounter` concept, each time an object is erased from the +container, the erase counter of the object will be incremented. +For example, this erase counter can be exploited using the `CC_safe_handle` +helper class, so that one can know if a handle is still pointing to the same +element. +Note that this is meaningful only because the +`CGAL::Concurrent_compact_container` doesn't +deallocate elements until the destruction or clear() of the container. + +\cgalHeading{Parameters} + +The parameter `T` is required to have a copy constructor and an +assignment operator. It also needs to provide access to an internal +pointer via `Compact_container_traits`. + +The equality test and the relational order require the operators +`==` and `<` for `T` respectively. + +The parameter `Allocator` has to match the standard allocator +requirements, with value type `T`. This parameter has the default +value `CGAL_ALLOCATOR(T)`. + +*/ + +template < class T, class Allocator > +class Concurrent_compact_container +{ +public: +/// \name Types +/// @{ + typedef unspecified_type value_type; + typedef unspecified_type allocator_type; + typedef unspecified_type reference; + typedef unspecified_type const_reference; + typedef unspecified_type pointer; + typedef unspecified_type const_pointer; + typedef unspecified_type size_type; + typedef unspecified_type difference_type; + typedef unspecified_type iterator; + typedef unspecified_type const_iterator; + typedef unspecified_type reverse_iterator; + typedef unspecified_type const_reverse_iterator; +/// @} + + +/// \name Creation +/// @{ +/*! +introduces an empty container `ccc`, eventually specifying a particular +allocator `a` as well. +*/ + explicit Concurrent_compact_container(const Allocator &a = Allocator()); + +/*! +a container with copies from the range [`first,last`), eventually +specifying a particular allocator. +*/ + template < class InputIterator > + Concurrent_compact_container(InputIterator first, InputIterator last, + const Allocator & a = Allocator()); + +/*! +copy constructor. Each item in `ccc2` is copied. The allocator +is copied. The iterator order is preserved. +*/ + // The copy constructor and assignment operator preserve the iterator order + Concurrent_compact_container(const Concurrent_compact_container &ccc2); + +/*! +assignment. Each item in `ccc2` is copied. The allocator is copied. +Each item in `ccc` is deleted. The iterator order is preserved. +*/ + Concurrent_compact_container & operator=(const Concurrent_compact_container &ccc2); + +/*! +swaps the contents of `ccc` and `ccc2` in constant time +complexity. No exception is thrown. +*/ + void swap(Self &ccc2); + +/// @} + +/// \name Access Member Functions +/// @{ + + /// returns a mutable iterator referring to the first element in `ccc`. + iterator begin(); + /// returns a constant iterator referring to the first element in `ccc`. + const_iterator begin() const; + /// returns a mutable iterator which is the past-end-value of `ccc`. + iterator end(); + /// returns a constant iterator which is the past-end-value of `ccc`. + const_iterator end(); + + /// returns a mutable reverse iterator referring to the reverse beginning in `ccc`. + reverse_iterator rbegin(); + /// returns a constant reverse iterator referring to the reverse beginning in `ccc`. + const_reverse_iterator rbegin() const; + /// returns a mutable reverse iterator which is the reverse past-end-value of `ccc`. + reverse_iterator rend(); + /// returns a constant reverse iterator which is the reverse past-end-value of `ccc`. + const_reverse_iterator rend() const; + + /// returns an iterator which points to `value`. + iterator iterator_to(reference value) const; + /// returns a constant iterator which points to `value`. + const_iterator iterator_to(const_reference value) const; + /// returns an iterator which points to `value`. + static iterator s_iterator_to(reference value); + /// returns a constant iterator which points to `value`. + static const_iterator s_iterator_to(const_reference value); + + /// returns `true` iff `ccc` is empty. + bool empty() const; + /// returns the number of items in `ccc`. + /// Note: do not call this function while others are inserting/erasing elements + size_type size() const; + /// returns the maximum possible size of the container `ccc`. + /// This is the allocator's max_size value + size_type max_size() const; + /// returns the total number of elements that `ccc` can hold without requiring reallocation. + size_type capacity() const; + /// returns the allocator + Allocator get_allocator() const; + +/// @} + + +/// \name Insertion +/// @{ + /*! + constructs an object of type `T` with the constructor that takes + `t1` as argument, inserts it in `ccc`, and returns the iterator pointing + to it. Overloads of this member function are defined that take additional + arguments, up to 9. + */ + template < class T1 > + iterator emplace(const T1& t1); + + /*! + inserts a copy of `t` in `ccc` and returns the iterator pointing + to it. + */ + iterator insert(const T &t); + + /// inserts the range [`first, last`) in `ccc`. + template < class InputIterator > + void insert(InputIterator first, InputIterator last); + + /*! + erases all the elements of `ccc`, then inserts the range + [`first, last`) in `ccc`. + */ + template < class InputIterator > + void assign(InputIterator first, InputIterator last); +/// @} + + +/// \name Removal +/// @{ + /// removes the item pointed by `pos` from `ccc`. + void erase(iterator x); + /// removes the items from the range [`first, last`) from `ccc`. + void erase(iterator first, iterator last); + /*! + all items in `ccc` are deleted, and the memory is deallocated. + After this call, `ccc` is in the same state as if just default + constructed. + */ + void clear(); +/// @} + +/// \name Ownership testing +/// The following functions are mostly helpful for efficient debugging, since +/// their complexity is \f$ O(\sqrt{\mathrm{c.capacity()}})\f$. +/// @{ + /// returns whether `pos` is in the range `[ccc.begin(), ccc.end()]` (`ccc.end()` included). + bool owns(const_iterator pos); + /// returns whether `pos` is in the range `[ccc.begin(), ccc`.end())` (`ccc.end()` excluded). + bool owns_dereferencable(const_iterator pos); + +/// @} + +/// \name Merging +/// @{ +/*! +adds the items of `ccc2` to the end of `ccc` and `ccc2` becomes empty. +The time complexity is O(`ccc`.`capacity()`-`ccc`.`size()`). +\pre `ccc2` must not be the same as `ccc`, and the allocators of `ccc` and `ccc2` must be compatible: `ccc.get_allocator() == ccc2.get_allocator()`. +*/ +void merge(Concurrent_compact_container &ccc2); + +/// @} + +/// \name Comparison Operations +/// @{ + /*! + test for equality: Two containers are equal, iff they have the + same size and if their corresponding elements are equal. + */ + bool operator==(const Concurrent_compact_container &ccc2) const; + /// test for inequality: returns `!(ccc == ccc2)`. + bool operator!=(const Concurrent_compact_container &ccc2) const; + /// compares in lexicographical order. + bool operator<(const Concurrent_compact_container &ccc2) const; + /// returns `ccc2 < ccc`. + bool operator>(const Concurrent_compact_container &ccc2) const; + /// returns `!(ccc > ccc2)`. + bool operator<=(const Concurrent_compact_container &ccc2) const; + /// returns `!(ccc < ccc2)`. + bool operator>=(const Concurrent_compact_container &ccc2) const; +/// @} + +}; /* end Concurrent_compact_container */ +} /* end namespace CGAL */ diff --git a/STL_Extension/doc/STL_Extension/CGAL/Spatial_lock_grid_3.h b/STL_Extension/doc/STL_Extension/CGAL/Spatial_lock_grid_3.h new file mode 100644 index 00000000000..d537d8976e2 --- /dev/null +++ b/STL_Extension/doc/STL_Extension/CGAL/Spatial_lock_grid_3.h @@ -0,0 +1,56 @@ + +namespace CGAL { + +/*! +\ingroup PkgStlExtension + +The class `Spatial_lock_grid_3` allows to lock +points with coordinates (x, y, z) in a 3D grid. +The point type is called `P3` here. `P3` must provide x(), y() and z() functions, +returning the respective point coordinates as numbers whose type is a +model of the concept of `CGAL::RealEmbeddable`. + +It is a model of `SurjectiveLockDataStructure`, with `T` being +`P3` and `S` being the function that maps a point to +the cell of the 3D grid containing this point. + +For example, it can be used by concurrent algorithms to lock simplices. + +\tparam Grid_lock_tag allows to choose the locking strategy used by the +structure. The following tags are available: +- `Tag_non_blocking` is non-blocking (i.e.\ try_lock will always +return immediately) and uses atomics to perform lock operations. +- `Tag_priority_blocking` provides both non-blocking and +partially-blocking `try_lock` versions. The partially-blocking version will +block (spin) if the thread owning the lock has a lower \"ID\" (each thread is +given an arbitrary ID) or return immediately otherwise. It uses atomics to +perform lock operations. + +\cgalModels `SurjectiveLockDataStructure` +*/ + +template +class Spatial_lock_grid_3 +{ +public: + +/// \name Creation +/// @{ + + /// Constructs the lock grid of size `bbox`, with `num_grid_cells_per_axis` + /// cells per axis. + Spatial_lock_grid_3(const Bbox_3 &bbox, + int num_grid_cells_per_axis); + +/// @} + +/// \name Operations +/// @{ + + /// Sets the bounding box of the domain. + void set_bbox(const CGAL::Bbox_3 &bbox); + +/// @} + +}; /* end Spatial_lock_grid_3 */ +} /* end namespace CGAL */ diff --git a/STL_Extension/doc/STL_Extension/Concepts/ObjectWithEraseCounter.h b/STL_Extension/doc/STL_Extension/Concepts/ObjectWithEraseCounter.h new file mode 100644 index 00000000000..6e7798e09e6 --- /dev/null +++ b/STL_Extension/doc/STL_Extension/Concepts/ObjectWithEraseCounter.h @@ -0,0 +1,24 @@ + +/*! +\ingroup PkgStlExtensionConcepts +\cgalConcept + +The concept `ObjectWithEraseCounter` describes the functionalities +an object must provide so that its erase counter is updated by +a `CGAL::Compact_container` or a `CGAL::Concurrent_compact_container`. + +\sa `CGAL::Compact_container` +\sa `CGAL::Concurrent_compact_container` +*/ +class ObjectWithEraseCounter { +public: +/// \name Operations +/// @{ + /// Gets the value of the erase counter + unsigned int erase_counter() const; + /// Sets the value of the erase counter + void set_erase_counter(unsigned int c); + /// Increment the value of the erase counter + void increment_erase_counter(); +/// @} +}; \ No newline at end of file diff --git a/STL_Extension/doc/STL_Extension/Concepts/SurjectiveLockDataStructure.h b/STL_Extension/doc/STL_Extension/Concepts/SurjectiveLockDataStructure.h new file mode 100644 index 00000000000..7b6c6cb7de7 --- /dev/null +++ b/STL_Extension/doc/STL_Extension/Concepts/SurjectiveLockDataStructure.h @@ -0,0 +1,59 @@ + +/*! +\ingroup PkgStlExtensionConcepts +\cgalConcept + +The concept `SurjectiveLockDataStructure` describes functionalities +of a data structure whose goal is to lock +objects in a multi-threaded environment. +Such data structures are intended to be used by concurrent +algorithms. + +Note that it is allowed to \"lock too much\". E.g., the data structure +might be a voxel grid and locking a point might be locking the +voxel containing this point. +Thus, a point may also be locked because +another point in the same voxel has been locked. +The only requirement is that when a thread owns the lock of an object, no other +thread can lock the same object. + +We call `S` the surjective function such that `S(object)` +is the \"thing\" that is locked when one tries to lock `object`. +In the previous example, `S(point)` is the voxel containing `point`. + +\cgalHasModel `CGAL::Spatial_lock_grid_3` + +*/ +class SurjectiveLockDataStructure { +public: + +/// \name Operations +/// @{ + /// Test if `object` is locked (by this thread or by any other thread). + template + bool is_locked(const T &object); + + /// Test if `object` is locked by this thread. + template + bool is_locked_by_this_thread(const T &object); + + /// Try to lock `object`. Returns `true` if the object is already locked by this thread or if the object could be locked. + template + bool try_lock(const T &object); + + /// Try to lock `object`. Returns `true` if the object is already locked by this thread or if the object could be locked. + /// \tparam no_spin If `true`, force non-blocking operation (in any case, the + /// function will return immediately, i.e.\ it will not + /// wait for the ressource to be free). + /// If `false`, use the default behavior (same as previous function). + template + bool try_lock(const T &object); + + /// Unlock everything that is locked by this thread. + void unlock_everything_locked_by_this_thread(); + + /// Unlock everything that is locked by this thread except `S(object)`. + template + void unlock_everything_locked_by_this_thread_but_one(const T &object); +/// @} +}; \ No newline at end of file diff --git a/STL_Extension/doc/STL_Extension/STL_Extension.txt b/STL_Extension/doc/STL_Extension/STL_Extension.txt index 61a5cacb25b..bd3ee2b4b6f 100644 --- a/STL_Extension/doc/STL_Extension/STL_Extension.txt +++ b/STL_Extension/doc/STL_Extension/STL_Extension.txt @@ -5,7 +5,7 @@ namespace CGAL { \anchor Chapter_STL_Extensions_for_CGAL \cgalAutoToc -\authors Michael Hoffmann, Lutz Kettner, Sylvain Pion, and Ron Wein +\authors Michael Hoffmann, Clément Jamin, Lutz Kettner, Sylvain Pion, and Ron Wein \section stl_intro Introduction @@ -44,7 +44,7 @@ This used to simplify mutually pointed data structures like a halfedge data structure for planar maps or polyhedral surfaces (the current design does not need this anymore). The usual iterators are also available. -\section stl_compact Compact Container +\section stl_compact Compact Containers The class `Compact_container` is an \stl like container which provides a very compact storage for its elements. It achieves this goal @@ -69,10 +69,37 @@ when the container used to contain lots of elements, but now has far less. In this case, we suggest to do a copy of the container in order to "defragment" the internal representation. +The objects stored in this container can optionally store an +"erase counter". If it exists, i.e.\ if the object is a model of the +`ObjectWithEraseCounter` concept, each time an object is erased from the +container, the erase counter of the object will be incremented. +For example, this erase counter can be exploited using the `CC_safe_handle` +helper class, so that one can know if a handle is still pointing to the same +element. +Note that this is meaningful only because the container doesn't +deallocate elements until the destruction or clear() of the container. +For example, this counter is used by +the parallel 3D mesh generation engine to lazily manage the queues of bad cells: +an element in the queue is a pair containing a cell iterator and the +erase counter value of the cell when it has been inserted. When an element +is popped from the queue, the algorithm checks if the current value of +the erase counter matches the stored value. If it doesn't match, it means +the cell has been destroyed in the meantime and the algorithm ignores it. Without this +lazy management, each time a cell is destroyed, the algorithm has to look +for it in the queue and remove it. This mechanism is even more useful for the parallel +version of the meshing process, since each thread has its own queue and looking +for a cell in all the queues would be very slow. + This container has been developed in order to efficiently handle large data structures like the triangulation and halfedge data structures. It can probably be useful for other kinds of graphs as well. +The class `Concurrent_compact_container` +provides the same features, but enables concurrency-safe +`insert` and `erase` operations. Other operations are not concurrency-safe. +It requires the program to be linked against +the Intel TBB library. + \section stl_multi Multiset with Extended Functionality The class `Multiset` represents a diff --git a/STL_Extension/include/CGAL/CC_safe_handle.h b/STL_Extension/include/CGAL/CC_safe_handle.h new file mode 100644 index 00000000000..504596405d0 --- /dev/null +++ b/STL_Extension/include/CGAL/CC_safe_handle.h @@ -0,0 +1,61 @@ +// Copyright (c) 2012 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: $ +// $Id: $ +// +// Author(s) : Clement Jamin + +#ifndef CGAL_CC_SAFE_HANDLE_H +#define CGAL_CC_SAFE_HANDLE_H + +namespace CGAL { + +// CC_safe_handle is a helper that store a CC handle and its erase +// counter value (value when the CC_safe_handle instance was created). +// The is_zombie() function allows to know if the pointee was erased since. +template +class CC_safe_handle +{ +public: + CC_safe_handle(CC_iterator iterator) + : m_handle(iterator) + , m_erase_counter_value(iterator->erase_counter()) + { + } + + bool is_zombie() const + { + return m_handle->erase_counter() != m_erase_counter_value; + } + + CC_iterator cc_iterator() const + { + return m_handle; + } + +protected: + CC_iterator m_handle; + unsigned int m_erase_counter_value; +}; + +template +CC_safe_handle make_cc_safe_handle(CC_iterator iterator) +{ + return CC_safe_handle(iterator); +} + +} //namespace CGAL + +#endif // CGAL_CC_SAFE_HANDLE_H \ No newline at end of file diff --git a/STL_Extension/include/CGAL/Compact_container.h b/STL_Extension/include/CGAL/Compact_container.h index cf198f53d24..dd5f0ebbd3f 100644 --- a/STL_Extension/include/CGAL/Compact_container.h +++ b/STL_Extension/include/CGAL/Compact_container.h @@ -30,6 +30,7 @@ #include #include +#include #include @@ -82,6 +83,24 @@ namespace CGAL { +#define GENERATE_MEMBER_DETECTOR(X) \ +template class has_##X { \ + struct Fallback { int X; }; \ + struct Derived : T, Fallback { }; \ + \ + template struct Check; \ + \ + typedef char ArrayOfOne[1]; \ + typedef char ArrayOfTwo[2]; \ + \ + template static ArrayOfOne & func( \ + Check *); \ + template static ArrayOfTwo & func(...); \ + public: \ + typedef has_##X type; \ + enum { value = sizeof(func(0)) == 2 }; \ +}; + #define CGAL_INIT_COMPACT_CONTAINER_BLOCK_SIZE 14 #define CGAL_INCREMENT_COMPACT_CONTAINER_BLOCK_SIZE 16 @@ -161,8 +180,50 @@ struct Compact_container_traits { namespace internal { template < class DSC, bool Const > class CC_iterator; + + GENERATE_MEMBER_DETECTOR(increment_erase_counter); + + // A basic "no erase counter" strategy + template + class Erase_counter_strategy { + public: + // Do nothing + template + static unsigned int erase_counter(const Element &) { return 0; } + template + static void set_erase_counter(Element &, unsigned int) {} + template + static void increment_erase_counter(Element &) {} + }; + + + // A strategy managing an internal counter + template <> + class Erase_counter_strategy + { + public: + template + static unsigned int erase_counter(const Element &e) + { + return e.erase_counter(); + } + + template + static void set_erase_counter(Element &e, unsigned int c) + { + e.set_erase_counter(c); + } + + template + static void increment_erase_counter(Element &e) + { + e.increment_erase_counter(); + } + }; } +// Class Compact_container +// template < class T, class Allocator_ = Default, class Increment_policy =Addition_size_policy > @@ -197,7 +258,7 @@ public: explicit Compact_container(const Allocator &a = Allocator()) : alloc(a) { - init(); + init (); } template < class InputIterator > @@ -493,11 +554,15 @@ public: void erase(iterator x) { + typedef internal::Erase_counter_strategy< + internal::has_increment_erase_counter::value> EraseCounterStrategy; + CGAL_precondition(type(&*x) == USED); + EraseCounterStrategy::increment_erase_counter(*x); alloc.destroy(&*x); -#ifndef CGAL_NO_ASSERTIONS +/*#ifndef CGAL_NO_ASSERTIONS std::memset(&*x, 0, sizeof(T)); -#endif +#endif*/ put_on_free_list(&*x); --size_; } @@ -768,6 +833,9 @@ void Compact_container::clear() template < class T, class Allocator, class Increment_policy > void Compact_container::allocate_new_block() { + typedef internal::Erase_counter_strategy< + internal::has_increment_erase_counter::value> EraseCounterStrategy; + pointer new_block = alloc.allocate(block_size + 2); all_items.push_back(std::make_pair(new_block, block_size + 2)); capacity_ += block_size; @@ -775,7 +843,10 @@ void Compact_container::allocate_new_block() // We mark them free in reverse order, so that the insertion order // will correspond to the iterator order... for (size_type i = block_size; i >= 1; --i) + { + EraseCounterStrategy::set_erase_counter(*(new_block + i), 0); put_on_free_list(new_block + i); + } // We insert this new block at the end. if (last_item == NULL) // First time { @@ -1047,7 +1118,7 @@ namespace internal { { CGAL_assertion( n == NULL); return &*rhs != NULL; - } + } } // namespace internal diff --git a/STL_Extension/include/CGAL/Concurrent_compact_container.h b/STL_Extension/include/CGAL/Concurrent_compact_container.h new file mode 100644 index 00000000000..9a4b8e731e3 --- /dev/null +++ b/STL_Extension/include/CGAL/Concurrent_compact_container.h @@ -0,0 +1,1025 @@ +// Copyright (c) 2012 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: $ +// $Id: $ +// +// Author(s) : Clement Jamin + +#ifdef CGAL_LINKED_WITH_TBB + +#ifndef CGAL_CONCURRENT_COMPACT_CONTAINER_H +#define CGAL_CONCURRENT_COMPACT_CONTAINER_H + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +namespace CGAL { + +#define GENERATE_MEMBER_DETECTOR(X) \ +template class has_##X { \ + struct Fallback { int X; }; \ + struct Derived : T, Fallback { }; \ + \ + template struct Check; \ + \ + typedef char ArrayOfOne[1]; \ + typedef char ArrayOfTwo[2]; \ + \ + template static ArrayOfOne & func( \ + Check *); \ + template static ArrayOfTwo & func(...); \ + public: \ + typedef has_##X type; \ + enum { value = sizeof(func(0)) == 2 }; \ +}; + +#define CGAL_INIT_CONCURRENT_COMPACT_CONTAINER_BLOCK_SIZE 14 +#define CGAL_INCREMENT_CONCURRENT_COMPACT_CONTAINER_BLOCK_SIZE 16 + +// The traits class describes the way to access the pointer. +// It can be specialized. +template < class T > +struct Concurrent_compact_container_traits { + static void * pointer(const T &t) { return t.for_compact_container(); } + static void * & pointer(T &t) { return t.for_compact_container(); } +}; + +namespace CCC_internal { + template < class CCC, bool Const > + class CCC_iterator; + + GENERATE_MEMBER_DETECTOR(increment_erase_counter); + + // A basic "no erase counter" strategy + template + class Erase_counter_strategy { + public: + // Do nothing + template + static unsigned int erase_counter(const Element &) { return 0; } + template + static void set_erase_counter(Element &, unsigned int) {} + template + static void increment_erase_counter(Element &) {} + }; + + + // A strategy managing an internal counter + template <> + class Erase_counter_strategy + { + public: + template + static unsigned int erase_counter(const Element &e) + { + return e.erase_counter(); + } + + template + static void set_erase_counter(Element &e, unsigned int c) + { + e.set_erase_counter(c); + } + + template + static void increment_erase_counter(Element &e) + { + e.increment_erase_counter(); + } + }; +} + +// Free list (head and size) +template< typename pointer, typename size_type, typename CCC > +class Free_list { +public: + Free_list() : m_head(NULL), m_size(0) {} + + void init() { m_head = NULL; m_size = 0; } + pointer head() const { return m_head; } + void set_head(pointer p) { m_head = p; } + size_type size() const { return m_size; } + void set_size(size_type s) { m_size = s; } + void inc_size() { ++m_size; } + void dec_size() { --m_size; } + bool empty() { return size() == 0; } + // Warning: copy the pointer, not the data! + Free_list& operator= (const Free_list& other) + { + m_head = other.m_head; + m_size = other.m_size; + return *this; + } + + void merge(Free_list &other) + { + if (m_head == NULL) { + *this = other; + } + else if (!other.empty()) + { + pointer p = m_head; + while (CCC::clean_pointee(p) != NULL) + p = CCC::clean_pointee(p); + CCC::set_type(p, other.m_head, CCC::FREE); + m_size += other.m_size; + } + other.init(); // clear other + } + +protected: + pointer m_head; // the free list head pointer + size_type m_size; // the free list size +}; + +// Class Concurrent_compact_container +// +// Safe concurrent "insert" and "erase". +// Do not parse the container while others are modifying it. +// +template < class T, class Allocator_ = Default > +class Concurrent_compact_container +{ + typedef Allocator_ Al; + typedef typename Default::Get::type Allocator; + typedef Concurrent_compact_container Self; + typedef Concurrent_compact_container_traits Traits; + +public: + typedef T value_type; + typedef Allocator allocator_type; + typedef typename Allocator::reference reference; + typedef typename Allocator::const_reference const_reference; + typedef typename Allocator::pointer pointer; + typedef typename Allocator::const_pointer const_pointer; + typedef typename Allocator::size_type size_type; + typedef typename Allocator::difference_type difference_type; + typedef CCC_internal::CCC_iterator iterator; + typedef CCC_internal::CCC_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + +private: + typedef Free_list FreeList; + typedef tbb::enumerable_thread_specific Free_lists; + + // FreeList can access our private function (clean_pointee...) + friend class Free_list; + +public: + friend class CCC_internal::CCC_iterator; + friend class CCC_internal::CCC_iterator; + + explicit Concurrent_compact_container(const Allocator &a = Allocator()) + : m_alloc(a) + { + init (); + } + + template < class InputIterator > + Concurrent_compact_container(InputIterator first, InputIterator last, + const Allocator & a = Allocator()) + : m_alloc(a) + { + init(); + std::copy(first, last, CGAL::inserter(*this)); + } + + // The copy constructor and assignment operator preserve the iterator order + Concurrent_compact_container(const Concurrent_compact_container &c) + : m_alloc(c.get_allocator()) + { + init(); + m_block_size = c.m_block_size; + std::copy(c.begin(), c.end(), CGAL::inserter(*this)); + } + + Concurrent_compact_container & operator=(const Concurrent_compact_container &c) + { + if (&c != this) { + Self tmp(c); + swap(tmp); + } + return *this; + } + + ~Concurrent_compact_container() + { + clear(); + } + + void swap(Self &c) + { + std::swap(m_alloc, c.m_alloc); + std::swap(m_capacity, c.m_capacity); + std::swap(m_block_size, c.m_block_size); + std::swap(m_first_item, c.m_first_item); + std::swap(m_last_item, c.m_last_item); + std::swap(m_free_lists, c.m_free_lists); + m_all_items.swap(c.m_all_items); + } + + iterator begin() { return iterator(m_first_item, 0, 0); } + iterator end() { return iterator(m_last_item, 0); } + + const_iterator begin() const { return const_iterator(m_first_item, 0, 0); } + const_iterator end() const { return const_iterator(m_last_item, 0); } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + + const_reverse_iterator + rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator + rend() const { return const_reverse_iterator(begin()); } + + // Boost.Intrusive interface + iterator iterator_to(reference value) const { + return iterator(&value, 0); + } + const_iterator iterator_to(const_reference value) const { + return const_iterator(&value, 0); + } + static iterator s_iterator_to(reference value) { + return iterator(&value, 0); + } + static const_iterator s_iterator_to(const_reference value) { + return const_iterator(&value, 0); + } + + // Special insert methods that construct the objects in place + // (just forward the arguments to the constructor, to optimize a copy). +#ifndef CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES + template < typename... Args > + iterator + emplace(const Args&... args) + { + FreeList * fl = get_free_list(); + pointer ret = init_insert(fl); + new (ret) value_type(args...); + return finalize_insert(ret, fl); + } +#else + // inserts a default constructed item. + iterator emplace() + { + FreeList * fl = get_free_list(); + pointer ret = init_insert(fl); + new (ret) value_type(); + return finalize_insert(ret, fl); + } + + template < typename T1 > + iterator + emplace(const T1 &t1) + { + FreeList * fl = get_free_list(); + pointer ret = init_insert(fl); + new (ret) value_type(t1); + return finalize_insert(ret, fl); + } + + template < typename T1, typename T2 > + iterator + emplace(const T1 &t1, const T2 &t2) + { + FreeList * fl = get_free_list(); + pointer ret = init_insert(fl); + new (ret) value_type(t1, t2); + return finalize_insert(ret, fl); + } + + template < typename T1, typename T2, typename T3 > + iterator + emplace(const T1 &t1, const T2 &t2, const T3 &t3) + { + FreeList * fl = get_free_list(); + pointer ret = init_insert(fl); + new (ret) value_type(t1, t2, t3); + return finalize_insert(ret, fl); + } + + template < typename T1, typename T2, typename T3, typename T4 > + iterator + emplace(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) + { + FreeList * fl = get_free_list(); + pointer ret = init_insert(fl); + new (ret) value_type(t1, t2, t3, t4); + return finalize_insert(ret, fl); + } + + template < typename T1, typename T2, typename T3, typename T4, typename T5 > + iterator + emplace(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, + const T5 &t5) + { + FreeList * fl = get_free_list(); + pointer ret = init_insert(fl); + new (ret) value_type(t1, t2, t3, t4, t5); + return finalize_insert(ret, fl); + } + + template < typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6 > + iterator + emplace(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, + const T5 &t5, const T6 &t6) + { + FreeList * fl = get_free_list(); + pointer ret = init_insert(fl); + new (ret) value_type(t1, t2, t3, t4, t5, t6); + return finalize_insert(ret, fl); + } + + template < typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7 > + iterator + emplace(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, + const T5 &t5, const T6 &t6, const T7 &t7) + { + FreeList * fl = get_free_list(); + pointer ret = init_insert(fl); + new (ret) value_type(t1, t2, t3, t4, t5, t6, t7); + return finalize_insert(ret, fl); + } + + template < typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8 > + iterator + emplace(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, + const T5 &t5, const T6 &t6, const T7 &t7, const T8 &t8) + { + FreeList * fl = get_free_list(); + pointer ret = init_insert(fl); + new (ret) value_type(t1, t2, t3, t4, t5, t6, t7, t8); + return finalize_insert(ret, fl); + } +#endif // CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES + + iterator insert(const T &t) + { + FreeList * fl = get_free_list(); + pointer ret = init_insert(fl); + m_alloc.construct(ret, t); + return finalize_insert(ret, fl); + } + + template < class InputIterator > + void insert(InputIterator first, InputIterator last) + { + for (; first != last; ++first) + insert(*first); + } + + template < class InputIterator > + void assign(InputIterator first, InputIterator last) + { + clear(); // erase(begin(), end()); // ? + insert(first, last); + } + +private: + void erase(iterator x, FreeList * fl) + { + typedef CCC_internal::Erase_counter_strategy< + CCC_internal::has_increment_erase_counter::value> EraseCounterStrategy; + + CGAL_precondition(type(x) == USED); + EraseCounterStrategy::increment_erase_counter(*x); + m_alloc.destroy(&*x); +/* WE DON'T DO THAT BECAUSE OF THE ERASE COUNTER +#ifndef CGAL_NO_ASSERTIONS + std::memset(&*x, 0, sizeof(T)); +#endif*/ + put_on_free_list(&*x, fl); + } +public: + + void erase(iterator x) + { + erase(x, get_free_list()); + } + + void erase(iterator first, iterator last) { + while (first != last) + erase(first++); + } + + void clear(); + + // Merge the content of d into *this. d gets cleared. + // The complexity is O(size(free list = capacity-size)). + void merge(Self &d); + + // Do not call this function while others are inserting/erasing elements + size_type size() const + { + size_type size = m_capacity; + for( typename Free_lists::iterator it_free_list = m_free_lists.begin() ; + it_free_list != m_free_lists.end() ; + ++it_free_list ) + { + size -= it_free_list->size(); + } + return size; + } + + size_type max_size() const + { + return m_alloc.max_size(); + } + + size_type capacity() const + { + return m_capacity; + } + + // void resize(size_type sz, T c = T()); // TODO makes sense ??? + + bool empty() const + { + return size() == 0; + } + + allocator_type get_allocator() const + { + return m_alloc; + } + + // Returns whether the iterator "cit" is in the range [begin(), end()]. + // Complexity : O(#blocks) = O(sqrt(capacity())). + // This function is mostly useful for purposes of efficient debugging at + // higher levels. + bool owns(const_iterator cit) const + { + // We use the block structure to provide an efficient version : + // we check if the address is in the range of each block, + // and then test whether it is valid (not a free element). + + if (cit == end()) + return true; + + const_pointer c = &*cit; + + Mutex::scoped_lock lock(m_mutex); + + for (typename All_items::const_iterator it = m_all_items.begin(), itend = m_all_items.end(); + it != itend; ++it) { + const_pointer p = it->first; + size_type s = it->second; + + // Are we in the address range of this block (excluding first and last + // elements) ? + if (c <= p || (p+s-1) <= c) + continue; + + CGAL_assertion_msg( (c-p)+p == c, "wrong alignment of iterator"); + + return type(c) == USED; + } + return false; + } + + bool owns_dereferencable(const_iterator cit) const + { + return cit != end() && owns(cit); + } + + /** Reserve method to ensure that the capacity of the Concurrent_compact_container be + * greater or equal than a given value n. + */ + // TODO? + //void reserve(size_type n) + //{ + // Does it really make sense: it will reserve size for the current + // thread only! + /*Mutex::scoped_lock lock; + if ( m_capacity >= n ) return; + size_type tmp = m_block_size; + // TODO: use a tmpBlockSize instead of m_block_size + m_block_size = (std::max)( n - m_capacity, m_block_size ); + allocate_new_block(free_list()); + m_block_size = tmp + CGAL_INCREMENT_CONCURRENT_COMPACT_CONTAINER_BLOCK_SIZE;*/ + //} + +private: + + FreeList* get_free_list() { return & m_free_lists.local(); } + const FreeList* get_free_list() const { return & m_free_lists.local(); } + + // Two helper functions for the emplace() methods + + // allocate new space if needed get the pointer from + // the free list and then clean it + pointer init_insert(FreeList * fl) + { + pointer fl2 = fl->head(); + if (fl2 == NULL) { + allocate_new_block(fl); + fl2 = fl->head(); + } + pointer ret = fl2; + fl->set_head(clean_pointee(ret)); + return ret; + } + + // get verify the return pointer increment size and + // return as iterator + iterator finalize_insert(pointer ret, FreeList * fl) + { + CGAL_assertion(type(ret) == USED); + fl->dec_size(); + return iterator(ret, 0); + } + + void allocate_new_block(FreeList *fl); + + void put_on_free_list(pointer x, FreeList * fl) + { + set_type(x, fl->head(), FREE); + fl->set_head(x); + fl->inc_size(); + } + + // Definition of the bit squatting : + // ================================= + // ptr is composed of a pointer part and the last 2 bits. + // Here is the meaning of each of the 8 cases. + // + // value of the last 2 bits as "Type" + // pointer part 0 1 2 3 + // NULL user elt unused free_list end start/end + // != NULL user elt block boundary free elt unused + // + // meaning of ptr : user stuff next/prev block free_list unused + + enum Type { USED = 0, BLOCK_BOUNDARY = 1, FREE = 2, START_END = 3 }; + + // The bit squatting is implemented by casting pointers to (char *), then + // subtracting to NULL, doing bit manipulations on the resulting integer, + // and converting back. + + static char * clean_pointer(char * p) + { + return ((p - (char *) NULL) & ~ (std::ptrdiff_t) START_END) + (char *) NULL; + } + + // Returns the pointee, cleaned up from the squatted bits. + static pointer clean_pointee(const_pointer ptr) + { + return (pointer) clean_pointer((char *) Traits::pointer(*ptr)); + } + + // Get the type of the pointee. + static Type type(const_pointer ptr) + { + char * p = (char *) Traits::pointer(*ptr); + return (Type) (p - clean_pointer(p)); + } + + static Type type(const_iterator ptr) + { + return type(&*ptr); + } + + // Sets the pointer part and the type of the pointee. + static void set_type(pointer p_element, void * pointer, Type t) + { + CGAL_precondition(0 <= t && t < 4); + Traits::pointer(*p_element) = + (void *) ((clean_pointer((char *) pointer)) + (int) t); + } + + typedef tbb::queuing_mutex Mutex; + + // We store a vector of pointers to all allocated blocks and their sizes. + // Knowing all pointers, we don't have to walk to the end of a block to reach + // the pointer to the next block. + // Knowing the sizes allows to deallocate() without having to compute the size + // by walking through the block till its end. + // This opens up the possibility for the compiler to optimize the clear() + // function considerably when has_trivial_destructor. + typedef std::vector > All_items; + + + void init() + { + m_block_size = CGAL_INIT_CONCURRENT_COMPACT_CONTAINER_BLOCK_SIZE; + m_capacity = 0; + for( typename Free_lists::iterator it_free_list = m_free_lists.begin() ; + it_free_list != m_free_lists.end() ; + ++it_free_list ) + { + it_free_list->set_head(0); + it_free_list->set_size(0); + } + m_first_item = NULL; + m_last_item = NULL; + m_all_items = All_items(); + } + + allocator_type m_alloc; + size_type m_capacity; + size_type m_block_size; + Free_lists m_free_lists; + pointer m_first_item; + pointer m_last_item; + All_items m_all_items; + mutable Mutex m_mutex; +}; + +template < class T, class Allocator > +void Concurrent_compact_container::merge(Self &d) +{ + CGAL_precondition(&d != this); + + // Allocators must be "compatible" : + CGAL_precondition(get_allocator() == d.get_allocator()); + + // Concatenate the free_lists. + // Iterates over TLS free lists of "d". Note that the number of TLS freelists + // may be different. + typename Free_lists::iterator it_free_list = m_free_lists.begin(); + if (it_free_list == m_free_lists.end()) + { + // No free list at all? Create our local one... empty. + get_free_list()->set_head(0); + get_free_list()->set_size(0); + // Now there is one TLS free list: ours! + it_free_list = m_free_lists.begin(); + } + for( typename Free_lists::iterator it_free_list_d = d.m_free_lists.begin() ; + it_free_list_d != d.m_free_lists.end() ; + ++it_free_list_d, ++it_free_list ) + { + // If we run out of TLS free lists in *this, let's start again from "begin" + if (it_free_list == m_free_lists.end()) + it_free_list = m_free_lists.begin(); + + it_free_list->merge(*it_free_list_d); + } + // Concatenate the blocks. + if (m_last_item == NULL) { // empty... + m_first_item = d.m_first_item; + m_last_item = d.m_last_item; + } else if (d.m_last_item != NULL) { + set_type(m_last_item, d.m_first_item, BLOCK_BOUNDARY); + set_type(d.m_first_item, m_last_item, BLOCK_BOUNDARY); + m_last_item = d.m_last_item; + } + // Add the capacities. + m_capacity += d.m_capacity; + // It seems reasonnable to take the max of the block sizes. + m_block_size = (std::max)(m_block_size, d.m_block_size); + // Clear d. + d.init(); +} + +template < class T, class Allocator > +void Concurrent_compact_container::clear() +{ + for (typename All_items::iterator it = m_all_items.begin(), itend = m_all_items.end(); + it != itend; ++it) { + pointer p = it->first; + size_type s = it->second; + for (pointer pp = p + 1; pp != p + s - 1; ++pp) { + if (type(pp) == USED) + m_alloc.destroy(pp); + } + m_alloc.deallocate(p, s); + } + init(); +} + +template < class T, class Allocator > +void Concurrent_compact_container:: + allocate_new_block(FreeList * fl) +{ + typedef CCC_internal::Erase_counter_strategy< + CCC_internal::has_increment_erase_counter::value> EraseCounterStrategy; + + size_type old_block_size; + pointer new_block; + + { + Mutex::scoped_lock lock(m_mutex); + old_block_size = m_block_size; + new_block = m_alloc.allocate(old_block_size + 2); + m_all_items.push_back(std::make_pair(new_block, old_block_size + 2)); + m_capacity += old_block_size; + + // We insert this new block at the end. + if (m_last_item == NULL) // First time + { + m_first_item = new_block; + m_last_item = new_block + old_block_size + 1; + set_type(m_first_item, NULL, START_END); + } + else + { + set_type(m_last_item, new_block, BLOCK_BOUNDARY); + set_type(new_block, m_last_item, BLOCK_BOUNDARY); + m_last_item = new_block + old_block_size + 1; + } + set_type(m_last_item, NULL, START_END); + // Increase the m_block_size for the next time. + m_block_size += CGAL_INCREMENT_CONCURRENT_COMPACT_CONTAINER_BLOCK_SIZE; + } + + // We don't touch the first and the last one. + // We mark them free in reverse order, so that the insertion order + // will correspond to the iterator order... + for (size_type i = old_block_size; i >= 1; --i) + { + EraseCounterStrategy::set_erase_counter(*(new_block + i), 0); + put_on_free_list(new_block + i, fl); + } +} + +template < class T, class Allocator > +inline +bool operator==(const Concurrent_compact_container &lhs, + const Concurrent_compact_container &rhs) +{ + return lhs.size() == rhs.size() && + std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template < class T, class Allocator > +inline +bool operator!=(const Concurrent_compact_container &lhs, + const Concurrent_compact_container &rhs) +{ + return ! (lhs == rhs); +} + +template < class T, class Allocator > +inline +bool operator< (const Concurrent_compact_container &lhs, + const Concurrent_compact_container &rhs) +{ + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end()); +} + +template < class T, class Allocator > +inline +bool operator> (const Concurrent_compact_container &lhs, + const Concurrent_compact_container &rhs) +{ + return rhs < lhs; +} + +template < class T, class Allocator > +inline +bool operator<=(const Concurrent_compact_container &lhs, + const Concurrent_compact_container &rhs) +{ + return ! (lhs > rhs); +} + +template < class T, class Allocator > +inline +bool operator>=(const Concurrent_compact_container &lhs, + const Concurrent_compact_container &rhs) +{ + return ! (lhs < rhs); +} + +namespace CCC_internal { + + template < class CCC, bool Const > + class CCC_iterator + { + typedef typename CCC::iterator iterator; + typedef CCC_iterator Self; + public: + typedef typename CCC::value_type value_type; + typedef typename CCC::size_type size_type; + typedef typename CCC::difference_type difference_type; + typedef typename boost::mpl::if_c< Const, const value_type*, + value_type*>::type pointer; + typedef typename boost::mpl::if_c< Const, const value_type&, + value_type&>::type reference; + typedef std::bidirectional_iterator_tag iterator_category; + + // the initialization with NULL is required by our Handle concept. + CCC_iterator() + { + m_ptr.p = NULL; + } + + // Either a harmless copy-ctor, + // or a conversion from iterator to const_iterator. + CCC_iterator (const iterator &it) + { + m_ptr.p = &(*it); + } + + // Same for assignment operator (otherwise MipsPro warns) + CCC_iterator & operator= (const iterator &it) + { + m_ptr.p = &(*it); + return *this; + } + + // Construction from NULL + CCC_iterator (Nullptr_t CGAL_assertion_code(n)) + { + CGAL_assertion (n == NULL); + m_ptr.p = NULL; + } + + private: + + union { + pointer p; + void *vp; + } m_ptr; + + // Only Concurrent_compact_container should access these constructors. + friend class Concurrent_compact_container; + + // For begin() + CCC_iterator(pointer ptr, int, int) + { + m_ptr.p = ptr; + if (m_ptr.p == NULL) // empty container. + return; + + ++(m_ptr.p); // if not empty, p = start + if (CCC::type(m_ptr.p) == CCC::FREE) + increment(); + } + + // Construction from raw pointer and for end(). + CCC_iterator(pointer ptr, int) + { + m_ptr.p = ptr; + } + + // NB : in case empty container, begin == end == NULL. + void increment() + { + // It's either pointing to end(), or valid. + CGAL_assertion_msg(m_ptr.p != NULL, + "Incrementing a singular iterator or an empty container iterator ?"); + CGAL_assertion_msg(CCC::type(m_ptr.p) != CCC::START_END, + "Incrementing end() ?"); + + // If it's not end(), then it's valid, we can do ++. + do { + ++(m_ptr.p); + if (CCC::type(m_ptr.p) == CCC::USED || + CCC::type(m_ptr.p) == CCC::START_END) + return; + + if (CCC::type(m_ptr.p) == CCC::BLOCK_BOUNDARY) + m_ptr.p = CCC::clean_pointee(m_ptr.p); + } while (true); + } + + void decrement() + { + // It's either pointing to end(), or valid. + CGAL_assertion_msg(m_ptr.p != NULL, + "Decrementing a singular iterator or an empty container iterator ?"); + CGAL_assertion_msg(CCC::type(m_ptr.p - 1) != CCC::START_END, + "Decrementing begin() ?"); + + // If it's not begin(), then it's valid, we can do --. + do { + --m_ptr.p; + if (CCC::type(m_ptr.p) == CCC::USED || + CCC::type(m_ptr.p) == CCC::START_END) + return; + + if (CCC::type(m_ptr.p) == CCC::BLOCK_BOUNDARY) + m_ptr.p = CCC::clean_pointee(m_ptr.p); + } while (true); + } + + public: + + Self & operator++() + { + CGAL_assertion_msg(m_ptr.p != NULL, + "Incrementing a singular iterator or an empty container iterator ?"); + CGAL_assertion_msg(CCC::type(m_ptr.p) == CCC::USED, + "Incrementing an invalid iterator."); + increment(); + return *this; + } + + Self & operator--() + { + CGAL_assertion_msg(m_ptr.p != NULL, + "Decrementing a singular iterator or an empty container iterator ?"); + CGAL_assertion_msg(CCC::type(m_ptr.p) == CCC::USED + || CCC::type(m_ptr.p) == CCC::START_END, + "Decrementing an invalid iterator."); + decrement(); + return *this; + } + + Self operator++(int) { Self tmp(*this); ++(*this); return tmp; } + Self operator--(int) { Self tmp(*this); --(*this); return tmp; } + + reference operator*() const { return *(m_ptr.p); } + + pointer operator->() const { return (m_ptr.p); } + + // For std::less... + bool operator<(const CCC_iterator& other) const + { + return (m_ptr.p < other.m_ptr.p); + } + + bool operator>(const CCC_iterator& other) const + { + return (m_ptr.p > other.m_ptr.p); + } + + bool operator<=(const CCC_iterator& other) const + { + return (m_ptr.p <= other.m_ptr.p); + } + + bool operator>=(const CCC_iterator& other) const + { + return (m_ptr.p >= other.m_ptr.p); + } + + // Can itself be used for bit-squatting. + void * for_compact_container() const { return (m_ptr.vp); } + void * & for_compact_container() { return (m_ptr.vp); } + }; + + template < class CCC, bool Const1, bool Const2 > + inline + bool operator==(const CCC_iterator &rhs, + const CCC_iterator &lhs) + { + return &*rhs == &*lhs; + } + + template < class CCC, bool Const1, bool Const2 > + inline + bool operator!=(const CCC_iterator &rhs, + const CCC_iterator &lhs) + { + return &*rhs != &*lhs; + } + + // Comparisons with NULL are part of CGAL's Handle concept... + template < class CCC, bool Const > + inline + bool operator==(const CCC_iterator &rhs, + Nullptr_t CGAL_assertion_code(n)) + { + CGAL_assertion( n == NULL); + return &*rhs == NULL; + } + + template < class CCC, bool Const > + inline + bool operator!=(const CCC_iterator &rhs, + Nullptr_t CGAL_assertion_code(n)) + { + CGAL_assertion( n == NULL); + return &*rhs != NULL; + } + +} // namespace CCC_internal + +} //namespace CGAL + +#endif // CGAL_CONCURRENT_COMPACT_CONTAINER_H + +#endif // CGAL_LINKED_WITH_TBB diff --git a/STL_Extension/include/CGAL/Spatial_lock_grid_3.h b/STL_Extension/include/CGAL/Spatial_lock_grid_3.h new file mode 100644 index 00000000000..1754bcbe21b --- /dev/null +++ b/STL_Extension/include/CGAL/Spatial_lock_grid_3.h @@ -0,0 +1,682 @@ +// Copyright (c) 2012 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Clement Jamin + +#ifndef CGAL_STL_EXTENSION_SPATIAL_LOCK_GRID_3_H +#define CGAL_STL_EXTENSION_SPATIAL_LOCK_GRID_3_H + +#ifdef CGAL_LINKED_WITH_TBB + +#include + +#include + +#include +#if TBB_IMPLEMENT_CPP0X +# include +#else +# include +#endif +#include +#include + +#include +#include + +namespace CGAL { + +struct Tag_no_lock {}; +struct Tag_non_blocking {}; +struct Tag_non_blocking_with_mutexes {}; +struct Tag_priority_blocking {}; + +//***************************************************************************** +// class Spatial_lock_grid_base_3 +// (Uses Curiously recurring template pattern) +//***************************************************************************** + +template +class Spatial_lock_grid_base_3 +{ +private: + static bool *init_TLS_grid(int num_cells_per_axis) + { + int num_cells = num_cells_per_axis* + num_cells_per_axis*num_cells_per_axis; + bool *local_grid = new bool[num_cells]; + for (int i = 0 ; i < num_cells ; ++i) + local_grid[i] = false; + return local_grid; + } + +public: + bool *get_thread_local_grid() + { + return m_tls_grids.local(); + } + + void set_bbox(const Bbox_3 &bbox) + { + // Compute resolutions + m_bbox = bbox; + double n = static_cast(m_num_grid_cells_per_axis); + m_resolution_x = n / (bbox.xmax() - bbox.xmin()); + m_resolution_y = n / (bbox.ymax() - bbox.ymin()); + m_resolution_z = n / (bbox.zmax() - bbox.zmin()); + +#ifdef CGAL_CONCURRENT_MESH_3_VERBOSE + std::cerr << "Locking data structure Bounding Box = " + << "[" << bbox.xmin() << ", " << bbox.xmax() << "], " + << "[" << bbox.ymin() << ", " << bbox.ymax() << "], " + << "[" << bbox.zmin() << ", " << bbox.zmax() << "]" + << std::endl; +#endif + } + + const Bbox_3 &get_bbox() const + { + return m_bbox; + } + + bool is_locked_by_this_thread(int cell_index) + { + return get_thread_local_grid()[cell_index]; + } + + template + bool is_locked(const P3 &point) + { + return is_cell_locked(get_grid_index(point)); + } + + template + bool is_locked_by_this_thread(const P3 &point) + { + return get_thread_local_grid()[get_grid_index(point)]; + } + + bool try_lock(int cell_index) + { + return try_lock(cell_index); + } + + template + bool try_lock(int cell_index) + { + return get_thread_local_grid()[cell_index] + || try_lock_cell(cell_index); + } + + + bool try_lock(int index_x, int index_y, int index_z, int lock_radius) + { + return try_lock(index_x, index_y, index_z, lock_radius); + } + + template + bool try_lock(int index_x, int index_y, int index_z, int lock_radius) + { + if (lock_radius == 0) + { + int index_to_lock = + index_z*m_num_grid_cells_per_axis*m_num_grid_cells_per_axis + + index_y*m_num_grid_cells_per_axis + + index_x; + return try_lock(index_to_lock); + } + else + { + // We have to lock the square + std::vector locked_cells_tmp; + + // For each cell inside the square + for (int i = std::max(0, index_x-lock_radius) ; + i <= std::min(m_num_grid_cells_per_axis - 1, index_x+lock_radius) ; + ++i) + { + for (int j = std::max(0, index_y-lock_radius) ; + j <= std::min(m_num_grid_cells_per_axis - 1, index_y+lock_radius) ; + ++j) + { + for (int k = std::max(0, index_z-lock_radius) ; + k <= std::min(m_num_grid_cells_per_axis - 1, index_z+lock_radius) ; + ++k) + { + int index_to_lock = + k*m_num_grid_cells_per_axis*m_num_grid_cells_per_axis + + j*m_num_grid_cells_per_axis + + i; + // Try to lock it + if (try_lock(index_to_lock)) + { + locked_cells_tmp.push_back(index_to_lock); + } + else + { + // failed => we unlock already locked cells and return false + std::vector::const_iterator it = locked_cells_tmp.begin(); + std::vector::const_iterator it_end = locked_cells_tmp.end(); + for( ; it != it_end ; ++it) + { + unlock(*it); + } + return false; + } + } + } + } + + return true; + } + } + + + bool try_lock(int cell_index, int lock_radius) + { + return try_lock(cell_index, lock_radius); + } + + template + bool try_lock(int cell_index, int lock_radius) + { + if (lock_radius == 0) + { + return try_lock(cell_index); + } + else + { + int index_z = cell_index/(m_num_grid_cells_per_axis*m_num_grid_cells_per_axis); + cell_index -= index_z*m_num_grid_cells_per_axis*m_num_grid_cells_per_axis; + int index_y = cell_index/m_num_grid_cells_per_axis; + cell_index -= index_y*m_num_grid_cells_per_axis; + int index_x = cell_index; + + return try_lock(index_x, index_y, index_z, lock_radius); + } + } + + // P3 must provide .x(), .y(), .z() + template + bool try_lock(const P3 &point, int lock_radius = 0) + { + return try_lock(point, lock_radius); + } + + // P3 must provide .x(), .y(), .z() + template + bool try_lock(const P3 &point, int lock_radius = 0) + { + // Compute index on grid + int index_x = static_cast( (CGAL::to_double(point.x()) - m_bbox.xmin()) * m_resolution_x); + //index_x = std::max( 0, std::min(index_x, m_num_grid_cells_per_axis - 1) ); + index_x = + (index_x < 0 ? + 0 + : (index_x >= m_num_grid_cells_per_axis ? + m_num_grid_cells_per_axis - 1 + : index_x + ) + ); + int index_y = static_cast( (CGAL::to_double(point.y()) - m_bbox.ymin()) * m_resolution_y); + //index_y = std::max( 0, std::min(index_y, m_num_grid_cells_per_axis - 1) ); + index_y = + (index_y < 0 ? + 0 + : (index_y >= m_num_grid_cells_per_axis ? + m_num_grid_cells_per_axis - 1 + : index_y + ) + ); + int index_z = static_cast( (CGAL::to_double(point.z()) - m_bbox.zmin()) * m_resolution_z); + //index_z = std::max( 0, std::min(index_z, m_num_grid_cells_per_axis - 1) ); + index_z = + (index_z < 0 ? + 0 + : (index_z >= m_num_grid_cells_per_axis ? + m_num_grid_cells_per_axis - 1 + : index_z + ) + ); + + if (lock_radius == 0) + { + int index = + index_z*m_num_grid_cells_per_axis*m_num_grid_cells_per_axis + + index_y*m_num_grid_cells_per_axis + + index_x; + return try_lock(index); + } + else + { + return try_lock(index_x, index_y, index_z, lock_radius); + } + } + + void unlock(int cell_index) + { + // Unlock lock and shared grid + unlock_cell(cell_index); + get_thread_local_grid()[cell_index] = false; + } + + void unlock_all_points_locked_by_this_thread() + { + std::vector &tls_locked_cells = m_tls_locked_cells.local(); + std::vector::const_iterator it = tls_locked_cells.begin(); + std::vector::const_iterator it_end = tls_locked_cells.end(); + for( ; it != it_end ; ++it) + { + // If we still own the lock + int cell_index = *it; + if (get_thread_local_grid()[cell_index] == true) + unlock(cell_index); + } + tls_locked_cells.clear(); + } + + void unlock_all_tls_locked_cells_but_one(int cell_index_to_keep_locked) + { + std::vector &tls_locked_cells = m_tls_locked_cells.local(); + std::vector::const_iterator it = tls_locked_cells.begin(); + std::vector::const_iterator it_end = tls_locked_cells.end(); + bool cell_to_keep_found = false; + for( ; it != it_end ; ++it) + { + // If we still own the lock + int cell_index = *it; + if (get_thread_local_grid()[cell_index] == true) + { + if (cell_index == cell_index_to_keep_locked) + cell_to_keep_found = true; + else + unlock(cell_index); + } + } + tls_locked_cells.clear(); + if (cell_to_keep_found) + tls_locked_cells.push_back(cell_index_to_keep_locked); + } + + template + void unlock_all_tls_locked_locations_but_one_point(const P3 &point) + { + unlock_all_tls_locked_cells_but_one(get_grid_index(point)); + } + + bool check_if_all_cells_are_unlocked() + { + int num_cells = m_num_grid_cells_per_axis* + m_num_grid_cells_per_axis*m_num_grid_cells_per_axis; + bool unlocked = true; + for (int i = 0 ; unlocked && i < num_cells ; ++i) + unlocked = !is_cell_locked(i); + return unlocked; + } + + bool check_if_all_tls_cells_are_unlocked() + { + int num_cells = m_num_grid_cells_per_axis* + m_num_grid_cells_per_axis*m_num_grid_cells_per_axis; + bool unlocked = true; + for (int i = 0 ; unlocked && i < num_cells ; ++i) + unlocked = (get_thread_local_grid()[i] == false); + return unlocked; + } + +protected: + + // Constructor + Spatial_lock_grid_base_3(const Bbox_3 &bbox, + int num_grid_cells_per_axis) + : m_num_grid_cells_per_axis(num_grid_cells_per_axis), + m_tls_grids(boost::bind(init_TLS_grid, num_grid_cells_per_axis)) + { + set_bbox(bbox); + } + + /// Destructor + ~Spatial_lock_grid_base_3() + { + for( TLS_grid::iterator it_grid = m_tls_grids.begin() ; + it_grid != m_tls_grids.end() ; + ++it_grid ) + { + delete [] *it_grid; + } + } + + template + int get_grid_index(const P3& point) const + { + // Compute indices on grid + int index_x = static_cast( (CGAL::to_double(point.x()) - m_bbox.xmin()) * m_resolution_x); + //index_x = std::max( 0, std::min(index_x, m_num_grid_cells_per_axis - 1) ); + index_x = + (index_x < 0 ? + 0 + : (index_x >= m_num_grid_cells_per_axis ? + m_num_grid_cells_per_axis - 1 + : index_x + ) + ); + int index_y = static_cast( (CGAL::to_double(point.y()) - m_bbox.ymin()) * m_resolution_y); + //index_y = std::max( 0, std::min(index_y, m_num_grid_cells_per_axis - 1) ); + index_y = + (index_y < 0 ? + 0 + : (index_y >= m_num_grid_cells_per_axis ? + m_num_grid_cells_per_axis - 1 + : index_y + ) + ); + int index_z = static_cast( (CGAL::to_double(point.z()) - m_bbox.zmin()) * m_resolution_z); + //index_z = std::max( 0, std::min(index_z, m_num_grid_cells_per_axis - 1) ); + index_z = + (index_z < 0 ? + 0 + : (index_z >= m_num_grid_cells_per_axis ? + m_num_grid_cells_per_axis - 1 + : index_z + ) + ); + + return + index_z*m_num_grid_cells_per_axis*m_num_grid_cells_per_axis + + index_y*m_num_grid_cells_per_axis + + index_x; + } + + bool is_cell_locked(int cell_index) + { + return static_cast(this)->is_cell_locked_impl(cell_index); + } + + bool try_lock_cell(int cell_index) + { + return try_lock_cell(cell_index); + } + + template + bool try_lock_cell(int cell_index) + { + return static_cast(this) + ->template try_lock_cell_impl(cell_index); + } + void unlock_cell(int cell_index) + { + static_cast(this)->unlock_cell_impl(cell_index); + } + + int m_num_grid_cells_per_axis; + Bbox_3 m_bbox; + double m_resolution_x; + double m_resolution_y; + double m_resolution_z; + + // TLS + typedef tbb::enumerable_thread_specific< + bool*, + tbb::cache_aligned_allocator, + tbb::ets_key_per_instance> TLS_grid; + typedef tbb::enumerable_thread_specific > TLS_locked_cells; + + TLS_grid m_tls_grids; + TLS_locked_cells m_tls_locked_cells; +}; + + + +//***************************************************************************** +// class Spatial_lock_grid_3 +//***************************************************************************** +template +class Spatial_lock_grid_3; + + +//***************************************************************************** +// class Spatial_lock_grid_3 +//***************************************************************************** +template <> +class Spatial_lock_grid_3 + : public Spatial_lock_grid_base_3< + Spatial_lock_grid_3 > +{ + typedef Spatial_lock_grid_base_3< + Spatial_lock_grid_3 > Base; + +public: + // Constructors + Spatial_lock_grid_3(const Bbox_3 &bbox, int num_grid_cells_per_axis) + : Base(bbox, num_grid_cells_per_axis) + { + int num_cells = + num_grid_cells_per_axis*num_grid_cells_per_axis*num_grid_cells_per_axis; + + m_grid.resize(num_cells); + // Initialize grid (useless?) + for (int i = 0 ; i < num_cells ; ++i) + m_grid[i] = false; + } + + ~Spatial_lock_grid_3() + { + } + + bool is_cell_locked_impl(int cell_index) + { + return (m_grid[cell_index] == true); + } + + template + bool try_lock_cell_impl(int cell_index) + { + bool old_value = m_grid[cell_index].compare_and_swap(true, false); + if (old_value == false) + { + get_thread_local_grid()[cell_index] = true; + m_tls_locked_cells.local().push_back(cell_index); + return true; + } + return false; + } + + void unlock_cell_impl(int cell_index) + { + m_grid[cell_index] = false; + } + +protected: + + std::vector > m_grid; +}; + + +//***************************************************************************** +// class Spatial_lock_grid_3 +//***************************************************************************** + +template <> +class Spatial_lock_grid_3 + : public Spatial_lock_grid_base_3 > +{ + typedef Spatial_lock_grid_base_3< + Spatial_lock_grid_3 > Base; + +public: + // Constructors + + Spatial_lock_grid_3(const Bbox_3 &bbox, int num_grid_cells_per_axis) + : Base(bbox, num_grid_cells_per_axis), + m_tls_thread_ids(init_TLS_thread_ids) + { + int num_cells = + num_grid_cells_per_axis*num_grid_cells_per_axis*num_grid_cells_per_axis; + m_grid.resize(num_cells); + } + + /// Destructor + ~Spatial_lock_grid_3() + { + } + + bool is_cell_locked_impl(int cell_index) + { + return (m_grid[cell_index] != 0); + } + + template + bool try_lock_cell_impl(int cell_index) + { + unsigned int this_thread_id = m_tls_thread_ids.local(); + + // NO SPIN + if (no_spin) + { + unsigned int old_value = + m_grid[cell_index].compare_and_swap(this_thread_id, 0); + if (old_value == 0) + { + get_thread_local_grid()[cell_index] = true; + m_tls_locked_cells.local().push_back(cell_index); + return true; + } + } + // SPIN + else + { + for(;;) + { + unsigned int old_value = + m_grid[cell_index].compare_and_swap(this_thread_id, 0); + if (old_value == 0) + { + get_thread_local_grid()[cell_index] = true; + m_tls_locked_cells.local().push_back(cell_index); + return true; + } + else if (old_value > this_thread_id) + { + // Another "more prioritary" thread owns the lock, we back off + return false; + } + else + { + std::this_thread::yield(); + } + } + } + + return false; + } + + void unlock_cell_impl(int cell_index) + { + m_grid[cell_index] = 0; + } + +private: + static unsigned int init_TLS_thread_ids() + { + static tbb::atomic last_id; + unsigned int id = ++last_id; + // Ensure it is > 0 + return (1 + id%(std::numeric_limits::max())); + } + +protected: + + std::vector > m_grid; + + typedef tbb::enumerable_thread_specific TLS_thread_uint_ids; + TLS_thread_uint_ids m_tls_thread_ids; +}; + +//***************************************************************************** +// class Spatial_lock_grid_3 +// Note: undocumented, for testing only... +//***************************************************************************** + +template <> +class Spatial_lock_grid_3 + : public Spatial_lock_grid_base_3< + Spatial_lock_grid_3 > +{ + typedef Spatial_lock_grid_base_3< + Spatial_lock_grid_3 > Base; + +public: + // Constructors + Spatial_lock_grid_3(const Bbox_3 &bbox, int num_grid_cells_per_axis) + : Base(bbox, num_grid_cells_per_axis) + { + int num_cells = + num_grid_cells_per_axis*num_grid_cells_per_axis*num_grid_cells_per_axis; + m_grid.resize(num_cells); + } + + /// Destructor + ~Spatial_lock_grid_3() + { + } + + bool is_cell_locked_impl(int cell_index) + { + bool locked = m_grid[cell_index].try_lock(); + if (locked) + m_grid[cell_index].unlock(); + return !locked; + } + + template + bool try_lock_cell_impl(int cell_index) + { + bool success = m_grid[cell_index].try_lock(); + if (success) + { + get_thread_local_grid()[cell_index] = true; + m_tls_locked_cells.local().push_back(cell_index); + } + return success; + } + + void unlock_cell_impl(int cell_index) + { + m_grid[cell_index].unlock(); + } + +protected: + + std::vector m_grid; +}; + +} //namespace CGAL + +#else // !CGAL_LINKED_WITH_TBB + +namespace CGAL { + +template +class Spatial_lock_grid_3 +{ +}; + +} + +#endif // CGAL_LINKED_WITH_TBB + +#endif // CGAL_STL_EXTENSION_SPATIAL_LOCK_GRID_3_H diff --git a/STL_Extension/include/CGAL/iterator.h b/STL_Extension/include/CGAL/iterator.h index 78202cee67d..e04890aade3 100644 --- a/STL_Extension/include/CGAL/iterator.h +++ b/STL_Extension/include/CGAL/iterator.h @@ -495,6 +495,8 @@ template < class I, class P > struct Filter_iterator; template < class I, class P > bool operator==(const Filter_iterator&, const Filter_iterator&); +template < class I, class P > +bool operator<(const Filter_iterator&, const Filter_iterator&); template < class I, class P > struct Filter_iterator { @@ -529,6 +531,10 @@ public: ++c_; } + template + Filter_iterator(Filter_iterator const& otherFI) + : e_(otherFI.end()), c_(otherFI.base()), p_(otherFI.predicate()) {} + Self& operator++() { do { ++c_; } while (c_ != e_ && p_(c_)); return *this; @@ -552,15 +558,17 @@ public: --(*this); return tmp; } - + reference operator*() const { return *c_; } pointer operator->() const { return &*c_; } const Predicate& predicate() const { return p_; } Iterator base() const { return c_; } + Iterator end() const { return e_; } bool is_end() const { return (c_ == e_); } friend bool operator== <>(const Self&, const Self&); + friend bool operator< <>(const Self&, const Self&); }; template < class I, class P > @@ -582,6 +590,14 @@ bool operator==(const Filter_iterator& it1, return it1.base() == it2.base(); } +template < class I, class P > +inline +bool operator<(const Filter_iterator& it1, + const Filter_iterator& it2) +{ + return it1.base() < it2.base(); +} + template < class I, class P > inline bool operator!=(const Filter_iterator& it1, diff --git a/STL_Extension/test/STL_Extension/CMakeLists.txt b/STL_Extension/test/STL_Extension/CMakeLists.txt new file mode 100644 index 00000000000..a831c6e08d8 --- /dev/null +++ b/STL_Extension/test/STL_Extension/CMakeLists.txt @@ -0,0 +1,63 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + + +project( STL_Extension_test ) + +cmake_minimum_required(VERSION 2.6.2) +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6) + if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3) + cmake_policy(VERSION 2.8.4) + else() + cmake_policy(VERSION 2.6) + endif() +endif() + +find_package(CGAL QUIET COMPONENTS Core ) + +if ( CGAL_FOUND ) + + include( ${CGAL_USE_FILE} ) + + find_package( TBB QUIET ) + + if( TBB_FOUND ) + include(${TBB_USE_FILE}) + list(APPEND CGAL_3RD_PARTY_LIBRARIES ${TBB_LIBRARIES}) + endif() + + include( CGAL_CreateSingleSourceCGALProgram ) + + include_directories (BEFORE "../../include") + + create_single_source_cgal_program( "test_Boolean_tag.cpp" ) + create_single_source_cgal_program( "test_Cache.cpp" ) + create_single_source_cgal_program( "test_Compact_container.cpp" ) + create_single_source_cgal_program( "test_complexity_tags.cpp" ) + create_single_source_cgal_program( "test_composition.cpp" ) + create_single_source_cgal_program( "test_Concatenate_iterator.cpp" ) + create_single_source_cgal_program( "test_Concurrent_compact_container.cpp" ) + create_single_source_cgal_program( "test_dispatch_output.cpp" ) + create_single_source_cgal_program( "test_Flattening_iterator.cpp" ) + create_single_source_cgal_program( "test_Handle_with_policy.cpp" ) + create_single_source_cgal_program( "test_In_place_list.cpp" ) + create_single_source_cgal_program( "test_is_iterator.cpp" ) + create_single_source_cgal_program( "test_is_streamable.cpp" ) + create_single_source_cgal_program( "test_lexcompare_outputrange.cpp" ) + create_single_source_cgal_program( "test_Modifiable_priority_queue.cpp" ) + create_single_source_cgal_program( "test_multiset.cpp" ) + create_single_source_cgal_program( "test_N_tuple.cpp" ) + create_single_source_cgal_program( "test_namespaces.cpp" ) + create_single_source_cgal_program( "test_Nested_iterator.cpp" ) + create_single_source_cgal_program( "test_Object.cpp" ) + create_single_source_cgal_program( "test_stl_extension.cpp" ) + create_single_source_cgal_program( "test_type_traits.cpp" ) + create_single_source_cgal_program( "test_Uncertain.cpp" ) + create_single_source_cgal_program( "test_vector.cpp" ) + +else() + + message(STATUS "This program requires the CGAL library, and will not be compiled.") + +endif() + diff --git a/STL_Extension/test/STL_Extension/test_Compact_container.cpp b/STL_Extension/test/STL_Extension/test_Compact_container.cpp index fa31d3c3f71..f43a597e3db 100644 --- a/STL_Extension/test/STL_Extension/test_Compact_container.cpp +++ b/STL_Extension/test/STL_Extension/test_Compact_container.cpp @@ -18,6 +18,22 @@ struct Node_1 bool operator==(const Node_1 &) const { return true; } bool operator!=(const Node_1 &) const { return false; } bool operator< (const Node_1 &) const { return false; } + + // Erase counter (cf. Compact_container) + unsigned int erase_counter() const + { + return this->m_erase_counter; + } + void set_erase_counter(unsigned int c) + { + this->m_erase_counter = c; + } + void increment_erase_counter() + { + ++this->m_erase_counter; + } + + int m_erase_counter; }; class Node_2 diff --git a/STL_Extension/test/STL_Extension/test_Concurrent_compact_container.cpp b/STL_Extension/test/STL_Extension/test_Concurrent_compact_container.cpp new file mode 100644 index 00000000000..5794411d442 --- /dev/null +++ b/STL_Extension/test/STL_Extension/test_Concurrent_compact_container.cpp @@ -0,0 +1,441 @@ +// test program for Concurrent_compact_container. + +#include + +#ifndef CGAL_LINKED_WITH_TBB + +int main() +{ + std::cout << + "NOTICE: this test needs CGAL_LINKED_WITH_TBB, and will not be tested." + << std::endl; + return 0; +} + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +# include +# include + +struct Node_1 +: public CGAL::Compact_container_base +{ + bool operator==(const Node_1 &) const { return true; } + bool operator!=(const Node_1 &) const { return false; } + bool operator< (const Node_1 &) const { return false; } +}; + +class Node_2 +{ + union { + Node_2 * p; + void * p_cc; + }; + +public: + + int rnd; + + Node_2() + : p(NULL), rnd(CGAL::default_random.get_int(0, 100)) {} + + bool operator==(const Node_2 &n) const { return rnd == n.rnd; } + bool operator!=(const Node_2 &n) const { return rnd != n.rnd; } + bool operator< (const Node_2 &n) const { return rnd < n.rnd; } + + void * for_compact_container() const { return p_cc; } + void * & for_compact_container() { return p_cc; } +}; + +template < class Cont > +inline bool check_empty(const Cont &c) +{ + return c.empty() && c.size() == 0 && c.begin() == c.end(); +} + +// For parallel_for +template +class Insert_in_CCC_functor +{ + typedef std::vector Iterators_vec; + +public: + Insert_in_CCC_functor( + const Values_vec &values, Cont &cont, Iterators_vec &iterators) + : m_values(values), m_cont(cont), m_iterators(iterators) + {} + + Insert_in_CCC_functor(const Insert_in_CCC_functor &other) + : m_values(other.m_values), m_cont(other.m_cont), + m_iterators(other.m_iterators) + {} + + void operator() (const tbb::blocked_range& r) const + { + for( size_t i = r.begin() ; i != r.end() ; ++i) + m_iterators[i] = m_cont.insert(m_values[i]); + } + +private: + const Values_vec & m_values; + Cont & m_cont; + Iterators_vec & m_iterators; +}; + +// For parallel_for +template +class Erase_in_CCC_functor +{ + typedef std::vector Iterators_vec; + +public: + Erase_in_CCC_functor( + Cont &cont, Iterators_vec &iterators) + : m_cont(cont), m_iterators(iterators) + {} + + Erase_in_CCC_functor(const Erase_in_CCC_functor &other) + : m_cont(other.m_cont), + m_iterators(other.m_iterators) + {} + + void operator() (const tbb::blocked_range& r) const + { + for( size_t i = r.begin() ; i != r.end() ; ++i) + m_cont.erase(m_iterators[i]); + } + +private: + Cont & m_cont; + Iterators_vec & m_iterators; +}; + +// For parallel_for +template +class Insert_and_erase_in_CCC_functor +{ + typedef std::vector Iterators_vec; + typedef std::vector > Free_elts_vec; + +public: + Insert_and_erase_in_CCC_functor( + const Values_vec &values, Cont &cont, Iterators_vec &iterators, + Free_elts_vec &free_elements, tbb::atomic &num_erasures) + : m_values(values), m_cont(cont), m_iterators(iterators), + m_free_elements(free_elements), m_num_erasures(num_erasures) + {} + + Insert_and_erase_in_CCC_functor(const Insert_and_erase_in_CCC_functor &other) + : m_values(other.m_values), m_cont(other.m_cont), + m_iterators(other.m_iterators), m_free_elements(other.m_free_elements), + m_num_erasures(other.m_num_erasures) + {} + + void operator() (const tbb::blocked_range& r) const + { + for( size_t i = r.begin() ; i != r.end() ; ++i) + { + m_iterators[i] = m_cont.insert(m_values[i]); + // Random-pick an element to erase + int index_to_erase = rand() % m_values.size(); + // If it exists + if (m_free_elements[index_to_erase].compare_and_swap(true, false) == false) + { + m_cont.erase(m_iterators[index_to_erase]); + ++m_num_erasures; + } + } + } + +private: + const Values_vec & m_values; + Cont & m_cont; + Iterators_vec & m_iterators; + Free_elts_vec & m_free_elements; + tbb::atomic & m_num_erasures; +}; + +template < class Cont > +void test(const Cont &) +{ + // Testing if all types are provided. + + typename Cont::value_type t0; + typename Cont::reference t1 = t0; CGAL_USE(t1); + typename Cont::const_reference t2 = t0; CGAL_USE(t2); + typename Cont::pointer t3 = &t0; + typename Cont::const_pointer t4 = &t0; CGAL_USE(t4); + typename Cont::size_type t5 = 0; CGAL_USE(t5); + typename Cont::difference_type t6 = t3-t3; CGAL_USE(t6); + typename Cont::iterator t7; CGAL_USE(t7); + typename Cont::const_iterator t8; CGAL_USE(t8); + typename Cont::reverse_iterator t9; CGAL_USE(t9); + typename Cont::const_reverse_iterator t10; CGAL_USE(t10); + typename Cont::allocator_type t15; + + std::cout << "Testing empty containers." << std::endl; + + Cont c0, c1; + Cont c2(t15); + Cont c3(c2); + Cont c4; + c4 = c2; + + typedef std::vector Vect; + Vect v0; + const Cont c5(v0.begin(), v0.end()); + Cont c6(c5.begin(), c5.end()); + typename Cont::allocator_type Al; + Cont c7(c0.begin(), c0.end(), Al); + Cont c8; + c8.insert(c0.rbegin(), c0.rend()); + + // test conversion iterator-> const_iterator. + typename Cont::const_iterator t16 = c5.begin(); CGAL_USE(t16); + assert(t16 == c5.begin()); + + assert(c0 == c1); + assert(! (c0 < c1)); + + assert(check_empty(c0)); + assert(check_empty(c1)); + assert(check_empty(c2)); + assert(check_empty(c3)); + assert(check_empty(c4)); + assert(check_empty(c5)); + assert(check_empty(c6)); + assert(check_empty(c7)); + assert(check_empty(c8)); + + c1.swap(c0); + + assert(check_empty(c0)); + assert(check_empty(c1)); + + c1.merge(c0); + + assert(check_empty(c0)); + assert(check_empty(c1)); + + typename Cont::allocator_type t20 = c0.get_allocator(); + + std::cout << "Now filling some containers" << std::endl; + + Vect v1(10000); + Cont c9(v1.begin(), v1.end()); + + assert(c9.size() == v1.size()); + assert(c9.max_size() >= v1.size()); + assert(c9.capacity() >= c9.size()); + + Cont c10 = c9; + + assert(c10 == c9); + assert(c10.size() == v1.size()); + assert(c10.max_size() >= v1.size()); + assert(c10.capacity() >= c10.size()); + + c9.clear(); + + assert(check_empty(c9)); + assert(c9.capacity() >= c9.size()); + assert(c0 == c9); + + c9.merge(c10); + c10.swap(c9); + + assert(check_empty(c9)); + assert(c9.capacity() >= c9.size()); + + assert(c10.size() == v1.size()); + assert(c10.max_size() >= v1.size()); + assert(c10.capacity() >= c10.size()); + + std::cout << "Testing insertion methods" << std::endl; + + c9.assign(c10.begin(), c10.end()); + + assert(c9 == c10); + + c10.assign(c9.begin(), c9.end()); + + assert(c9 == c10); + + c9.insert(c10.begin(), c10.end()); + + assert(c9.size() == 2*v1.size()); + + c9.clear(); + + assert(c9 != c10); + + c9.insert(c10.begin(), c10.end()); + + assert(c9.size() == v1.size()); + assert(c9 == c10); + + + typename Cont::iterator it = c9.iterator_to(*c9.begin()); + assert(it == c9.begin()); + typename Cont::const_iterator cit = c9.iterator_to(const_cast(*c9.begin())); + assert(cit == c9.begin()); + + typename Cont::iterator s_it = Cont::s_iterator_to(*c9.begin()); + assert(s_it == c9.begin()); + typename Cont::const_iterator s_cit = Cont::s_iterator_to(const_cast(*c9.begin())); + assert(s_cit == c9.begin()); + + + c10 = Cont(); + + assert(check_empty(c10)); + + for(typename Vect::const_iterator it = v1.begin(); it != v1.end(); ++it) + c10.insert(*it); + + assert(c10.size() == v1.size()); + assert(c9 == c10); + + c9.erase(c9.begin()); + c9.erase(c9.begin()); + + assert(c9.size() == v1.size() - 2); + + // test reserve + /*Cont c11; + c11.reserve(v1.size()); + for(typename Vect::const_iterator it = v1.begin(); it != v1.end(); ++it) + c11.insert(*it); + + assert(c11.size() == v1.size()); + assert(c10 == c11);*/ + + // owns() and owns_dereferencable(). + for(typename Cont::const_iterator it = c9.begin(), end = c9.end(); it != end; ++it) { + assert(c9.owns(it)); + assert(c9.owns_dereferencable(it)); + assert(! c10.owns(it)); + assert(! c10.owns_dereferencable(it)); + } + assert(c9.owns(c9.end())); + assert(! c9.owns_dereferencable(c9.end())); + + + c9.erase(c9.begin(), c9.end()); + + assert(check_empty(c9)); + + std::cout << "Testing parallel insertion" << std::endl; + { + Cont c11; + Vect v11(1000000); + std::vector iterators(v11.size()); + tbb::parallel_for( + tbb::blocked_range( 0, v11.size() ), + Insert_in_CCC_functor(v11, c11, iterators) + ); + assert(c11.size() == v11.size()); + + std::cout << "Testing parallel erasure" << std::endl; + tbb::parallel_for( + tbb::blocked_range( 0, v11.size() ), + Erase_in_CCC_functor(c11, iterators) + ); + assert(c11.empty()); + } + + std::cout << "Testing parallel insertion AND erasure" << std::endl; + { + Cont c12; + Vect v12(1000000); + std::vector > free_elements(v12.size()); + for(typename std::vector >::iterator + it = free_elements.begin(), end = free_elements.end(); it != end; ++it) + { + *it = true; + } + + tbb::atomic num_erasures; + num_erasures = 0; + std::vector iterators(v12.size()); + tbb::parallel_for( + tbb::blocked_range( 0, v12.size() ), + Insert_and_erase_in_CCC_functor( + v12, c12, iterators, free_elements, num_erasures) + ); + assert(c12.size() == v12.size() - num_erasures); + } +} + + +int main() +{ + CGAL::Concurrent_compact_container C1; + CGAL::Concurrent_compact_container C2; + test(C1); + test(C2); + + /* + // Verbose merging test + typedef CGAL::Concurrent_compact_container CCC; + CCC cc1, cc2; + tbb::parallel_for( + tbb::blocked_range( 0, 100, 1 ), + [&] (const tbb::blocked_range& r) // TODO: lambdas ok? + { + for( size_t i = r.begin() ; i != r.end() ; ++i) + { + Node_2 n; + n.rnd = i; + cc1.insert(n); + } + }); + + for (int i = 10 ; i < 14 ; ++i) + { + Node_2 n; + n.rnd = i; + cc2.insert(n); + } + + std::cout << "cc1 capacity: " << cc1.capacity() << std::endl; + std::cout << "cc1 size: " << cc1.size() << std::endl; + for(CCC::const_iterator it = cc1.begin(), end = cc1.end(); it != end; ++it) { + std::cout << "cc1: " << it->rnd << " / " << std::endl; + } + std::cout << "cc2 capacity: " << cc2.capacity() << std::endl; + std::cout << "cc2 size: " << cc2.size() << std::endl; + for(CCC::const_iterator it = cc2.begin(), end = cc2.end(); it != end; ++it) { + std::cout << "cc2: " << it->rnd << " / " << std::endl; + } + std::cout << "Merging..."; + //cc1.merge(cc2); + cc2.merge(cc1); + std::cout << " done." << std::endl; + std::cout << "cc1 capacity: " << cc1.capacity() << std::endl; + std::cout << "cc1 size: " << cc1.size() << std::endl; + for(CCC::const_iterator it = cc1.begin(), end = cc1.end(); it != end; ++it) { + std::cout << "cc1: " << it->rnd << " / " << std::endl; + } + std::cout << "cc2 capacity: " << cc2.capacity() << std::endl; + std::cout << "cc2 size: " << cc2.size() << std::endl; + for(CCC::const_iterator it = cc2.begin(), end = cc2.end(); it != end; ++it) { + std::cout << "cc2: " << it->rnd << " / " << std::endl; + }*/ + + return 0; +} + +#endif // CGAL_LINKED_WITH_TBB + +// EOF // diff --git a/Triangulation_3/benchmark/Triangulation_3/Triangulation_benchmark_3.cpp b/Triangulation_3/benchmark/Triangulation_3/Triangulation_benchmark_3.cpp index 7ca9ebbbf7a..ca8a1da7b70 100644 --- a/Triangulation_3/benchmark/Triangulation_3/Triangulation_benchmark_3.cpp +++ b/Triangulation_3/benchmark/Triangulation_3/Triangulation_benchmark_3.cpp @@ -27,8 +27,12 @@ // - replace drand48() by CGAL Generators // - move/document Time_accumulator to CGAL/Profiling_tools (?) +#define CGAL_TRIANGULATION_3_PROFILING +//#define CGAL_CONCURRENT_TRIANGULATION_3_ADD_TEMPORARY_POINTS_ON_FAR_SPHERE + #include #include +#include #include #include #include @@ -77,9 +81,54 @@ typedef Exact_predicates_inexact_constructions_kernel K; typedef Regular_triangulation_euclidean_traits_3 WK; typedef K::Point_3 Point; +#ifdef CONCURRENT_TRIANGULATION_3 + typedef CGAL::Spatial_lock_grid_3< + CGAL::Tag_priority_blocking> Lock_ds; + + // Delaunay T3 + typedef CGAL::Triangulation_data_structure_3< + CGAL::Triangulation_vertex_base_3, + CGAL::Triangulation_cell_base_3, + CGAL::Parallel_tag > DT_Tds; + typedef CGAL::Delaunay_triangulation_3< + K, DT_Tds, CGAL::Default, Lock_ds> DT3; + /*typedef CGAL::Delaunay_triangulation_3< + K, DT_Tds, Fast_location, Lock_ds> DT3_FastLoc;*/ // (no parallel fast location for now) + + // Regular T3 with hidden points kept + typedef CGAL::Triangulation_data_structure_3< + CGAL::Triangulation_vertex_base_3, + CGAL::Regular_triangulation_cell_base_3, + CGAL::Parallel_tag> RT_Tds_WithHP; + typedef CGAL::Regular_triangulation_3< + WK, RT_Tds_WithHP, Lock_ds> RT3_WithHP; + + // Regular T3 with hidden points discarded + typedef CGAL::Triangulation_data_structure_3< + CGAL::Triangulation_vertex_base_3, + CGAL::Triangulation_cell_base_3, + CGAL::Parallel_tag > RT_Tds_NoHP; + typedef CGAL::Regular_triangulation_3< + WK, RT_Tds_NoHP, Lock_ds> RT3_NoHP; + +#else + typedef CGAL::Delaunay_triangulation_3 DT3; + typedef CGAL::Delaunay_triangulation_3 DT3_FastLoc; + + // Regular T3 with hidden points kept + typedef CGAL::Regular_triangulation_3 RT3_WithHP; + + // Regular T3 with hidden points discarded + typedef CGAL::Triangulation_data_structure_3< + CGAL::Triangulation_vertex_base_3, + CGAL::Triangulation_cell_base_3 > RT_Tds_NoHP; + typedef CGAL::Regular_triangulation_3 RT3_NoHP; +#endif + vector pts, pts2; +Bbox_3 pts_bbox, pts2_bbox; size_t min_pts = 100; -size_t max_pts = 100000; +size_t max_pts = 1000000; bool input_file_selected = false; std::ifstream input_file; @@ -87,37 +136,64 @@ std::ifstream input_file; class Time_accumulator { - double &accumulator; - Timer timer; + double &accumulator; + Timer timer; public: - Time_accumulator(double &acc) : accumulator(acc) { timer.reset(); timer.start(); } - ~Time_accumulator() { timer.stop(); accumulator += timer.time(); } + Time_accumulator(double &acc) : accumulator(acc) { timer.reset(); timer.start(); } + ~Time_accumulator() { timer.stop(); accumulator += timer.time(); } }; #define drand48 CGAL::default_random.get_double Point rnd_point() { - return Point(drand48(), drand48(), drand48()); + return Point(drand48(), drand48(), drand48()); } void generate_points() { - if (input_file_selected) { - Point p; - while (input_file >> p) - pts.push_back(p); - cout << " [ Read " << pts.size() << " points from file ] " << endl; - min_pts = max_pts = pts.size(); - } - else { - pts.reserve(max_pts); - pts2.reserve(max_pts); - for(size_t i = 0; i < (std::max)(std::size_t(100000), max_pts); ++i) { - pts.push_back(rnd_point()); - pts2.push_back(rnd_point()); - } - } + if (input_file_selected) { + Point p; + if (input_file >> p) + { + pts.push_back(p); + pts_bbox = Bbox_3(p.bbox()); + + while (input_file >> p) + { + pts.push_back(p); + pts_bbox = pts_bbox + p.bbox(); + } + } + cout << " [ Read " << pts.size() << " points from file ] " << endl; + min_pts = max_pts = pts.size(); + } + else { + pts.reserve(max_pts); + pts2.reserve(max_pts); + + Point p = rnd_point(); + pts.push_back(p); + pts_bbox = Bbox_3(p.bbox()); + p = rnd_point(); + pts2.push_back(p); + pts2_bbox = Bbox_3(p.bbox()); + + for(size_t i = 1; i < (std::max)(std::size_t(100000), max_pts); ++i) { + p = rnd_point(); + pts.push_back(p); + pts_bbox = pts_bbox + p.bbox(); + p = rnd_point(); + pts2.push_back(p); + pts2_bbox = pts2_bbox + p.bbox(); + } + } + + cout << "Bounding box = " + << "[" << pts_bbox.xmin() << ", " << pts_bbox.xmax() << "], " + << "[" << pts_bbox.ymin() << ", " << pts_bbox.ymax() << "], " + << "[" << pts_bbox.zmin() << ", " << pts_bbox.zmax() << "]" + << endl; } @@ -125,27 +201,32 @@ void generate_points() template < typename Tr > void benchmark_construction() { - cout << "\nTriangulation construction : " << endl; - cout << "#pts\tTime" << endl; - size_t mem_size_init = Memory_sizer().virtual_size(); - size_t mem_size = 0; + cout << "\nTriangulation construction : " << endl; + cout << "#pts\tTime" << endl; + size_t mem_size_init = Memory_sizer().virtual_size(); + size_t mem_size = 0; - for (size_t nb_pts = min_pts; nb_pts <= max_pts; nb_pts *= 10) - { - double time = 0; - size_t iterations = 0; - do { - ++iterations; - Time_accumulator tt(time); - Tr tr(pts.begin(), pts.begin() + nb_pts); - mem_size = Memory_sizer().virtual_size(); - // cout << "#vertices = " << tr.number_of_vertices() << endl; - // cout << "#cells = " << tr.number_of_cells() << endl; - } while (time < BENCH_MIN_TIME); - cout << nb_pts << "\t" << time/iterations << SHOW_ITERATIONS; - } - cout << "\nMemory usage : " << (mem_size - mem_size_init)*1./max_pts << " Bytes/Point" - << " (observed for the largest data set, and may be unreliable)" << endl; + for (size_t nb_pts = min_pts; nb_pts <= max_pts; nb_pts *= 10) + { + double time = 0; + size_t iterations = 0; + do { + ++iterations; + Time_accumulator tt(time); +#ifdef CONCURRENT_TRIANGULATION_3 + Lock_ds locking_ds(pts_bbox, 50); + Tr tr(pts.begin(), pts.begin() + nb_pts, &locking_ds); +#else + Tr tr(pts.begin(), pts.begin() + nb_pts); +#endif + mem_size = Memory_sizer().virtual_size(); + // cout << "#vertices = " << tr.number_of_vertices() << endl; + // cout << "#cells = " << tr.number_of_cells() << endl; + } while (time < BENCH_MIN_TIME); + cout << nb_pts << "\t" << time/iterations << SHOW_ITERATIONS; + } + cout << "\nMemory usage : " << (mem_size - mem_size_init)*1./max_pts << " Bytes/Point" + << " (observed for the largest data set, and may be unreliable)" << endl; } @@ -153,22 +234,27 @@ void benchmark_construction() template < typename Tr > void benchmark_location() { - cout << "\nPoint location : " << endl; - cout << "#pts\tTime" << endl; - for (size_t nb_pts = min_pts; nb_pts <= max_pts; nb_pts *= 10) - { - Tr tr(pts.begin(), pts.begin() + nb_pts); - double time = 0; - size_t iterations = 0; - do { - ++iterations; - Time_accumulator tt(time); - // We do chunks of 100000 point locations at once. - for(size_t i = 0; i < 100000; ++i) - tr.locate(pts2[i]); - } while (time < BENCH_MIN_TIME); - cout << nb_pts << "\t" << (time/iterations)/100000 << SHOW_ITERATIONS; - } + cout << "\nPoint location : " << endl; + cout << "#pts\tTime" << endl; + for (size_t nb_pts = min_pts; nb_pts <= max_pts; nb_pts *= 10) + { +#ifdef CONCURRENT_TRIANGULATION_3 + Lock_ds locking_ds(pts_bbox, 50); + Tr tr(pts.begin(), pts.begin() + nb_pts, &locking_ds); +#else + Tr tr(pts.begin(), pts.begin() + nb_pts); +#endif + double time = 0; + size_t iterations = 0; + do { + ++iterations; + Time_accumulator tt(time); + // We do chunks of 100000 point locations at once. + for(size_t i = 0; i < 100000; ++i) + tr.locate(pts2[i]); + } while (time < BENCH_MIN_TIME); + cout << nb_pts << "\t" << (time/iterations)/100000 << SHOW_ITERATIONS; + } } @@ -176,76 +262,91 @@ void benchmark_location() template < typename Tr > void benchmark_remove() { - typedef typename Tr::Vertex_handle Vertex_handle; - typedef typename Tr::Vertex_iterator Vertex_iterator; + typedef typename Tr::Vertex_handle Vertex_handle; + typedef typename Tr::Vertex_iterator Vertex_iterator; - cout << "\nVertex removal : " << endl; - cout << "#pts\tTime" << endl; - size_t nb_pts = 100000; // only one size of triangulation hard-coded. - { - Tr tr(pts.begin(), pts.begin() + nb_pts); - vector vhs; - for (Vertex_iterator vit = tr.finite_vertices_begin(), end = tr.finite_vertices_end(); - vit != end; ++vit) - vhs.push_back(vit); - double time = 0; - size_t iterations = 0; - size_t j = 0; - do { - ++iterations; - Time_accumulator tt(time); - // We do chunks of 1024 vertex removal at once. - for(size_t i = 0; i < 1024; ++i, ++j) - tr.remove(vhs[j]); - } while (time < BENCH_MIN_TIME); - cout << nb_pts << "\t" << (time/iterations)/1024 << SHOW_ITERATIONS; - } + cout << "\nVertex removal : " << endl; + cout << "#pts\tTime\tTime/removal" << endl; + size_t nb_pts = 1000000; // only one size of triangulation hard-coded. + const size_t NUM_VERTICES_TO_REMOVE = 100000; + double time = 0; + size_t iterations = 0; + + if (nb_pts > max_pts) + { + std::cerr << "ERROR: nb_pts > max_pts. Cancelling..." << std::endl; + return; + } + + do { +#ifdef CONCURRENT_TRIANGULATION_3 + Lock_ds locking_ds(pts_bbox, 50); + Tr tr(pts.begin(), pts.begin() + nb_pts, &locking_ds); +#else + Tr tr(pts.begin(), pts.begin() + nb_pts); +#endif + vector vhs; + for (Vertex_iterator vit = tr.finite_vertices_begin(), end = tr.finite_vertices_end(); + vit != end; ++vit) + vhs.push_back(vit); + + Time_accumulator tt(time); + tr.remove(&vhs[0], &vhs[NUM_VERTICES_TO_REMOVE - 1]); + ++iterations; + } while (time < BENCH_MIN_TIME); + + cout << NUM_VERTICES_TO_REMOVE << "\t" + << (time/iterations) << "\t" + << (time/iterations)/NUM_VERTICES_TO_REMOVE << SHOW_ITERATIONS; } template < typename Tr > void do_benchmarks(string name) { - cout << "\n\nBenchmarking configuration : " << name << endl; - benchmark_construction(); - if (input_file_selected) - return; - benchmark_location(); - benchmark_remove(); + cout << "\n\nBenchmarking configuration : " << name << endl; + // tbb::task_scheduler_init tbb_init(10); // Set number of threads + benchmark_construction(); + if (input_file_selected) + return; + benchmark_location(); + benchmark_remove(); } int main(int argc, char **argv) { - if (argc >= 2) { - input_file.open(argv[1], std::ios::in); - if (input_file.is_open()) - input_file_selected = true; - else { - input_file_selected = false; - max_pts = atoi(argv[1]); - } - } + if (argc >= 2) { + input_file.open(argv[1], std::ios::in); + if (input_file.is_open()) + input_file_selected = true; + else { + input_file_selected = false; + max_pts = atoi(argv[1]); + } + } - cout << "Usage : " << argv[0] << " [filename]" - << " [max_points = " << max_pts << ", and please use a power of 10]" << endl; - cout << "Benchmarking the Triangulation_3 package for "; - if (input_file_selected) - cout << "data file : " << argv[1] << endl; - else - cout << "up to " << max_pts << " random points." << endl; + cout << "Usage : " << argv[0] << " [filename]" + << " [max_points = " << max_pts << ", and please use a power of 10]" << endl; + cout << "Benchmarking the Triangulation_3 package for "; + if (input_file_selected) + cout << "data file : " << argv[1] << endl; + else + cout << "up to " << max_pts << " random points." << endl; - cout.precision(3); + cout.precision(3); - generate_points(); + generate_points(); - cout << "\nProcessor : " - << ((sizeof(void*)==4) ? 32 : (sizeof(void*)==8) ? 64 : -1) << " bits\n"; - // cout << "Kernel : EPICK\n"; + cout << "\nProcessor : " + << ((sizeof(void*)==4) ? 32 : (sizeof(void*)==8) ? 64 : -1) << " bits\n"; + // cout << "Kernel : EPICK\n"; - do_benchmarks >("Delaunay [Compact_location]"); - if (input_file_selected) - return 0; - do_benchmarks >("Delaunay with Fast_location"); - do_benchmarks >("Regular [with hidden points kept, except there's none in the data sets]"); - do_benchmarks, Triangulation_cell_base_3 > > >("Regular with hidden points discarded"); + do_benchmarks("Delaunay [Compact_location]"); + if (input_file_selected) + return 0; +#ifndef CONCURRENT_TRIANGULATION_3 + do_benchmarks("Delaunay with Fast_location"); +#endif + do_benchmarks("Regular [with hidden points kept, except there's none in the data sets]"); + do_benchmarks("Regular with hidden points discarded"); } diff --git a/Triangulation_3/benchmark/Triangulation_3/simple.cpp b/Triangulation_3/benchmark/Triangulation_3/simple.cpp index 8fa8557b648..64356ffa2cd 100644 --- a/Triangulation_3/benchmark/Triangulation_3/simple.cpp +++ b/Triangulation_3/benchmark/Triangulation_3/simple.cpp @@ -28,7 +28,7 @@ int main() } Timer timer; timer.start(); - int N = 0; + size_t N = 0; for(int i = 0; i < 5; i++){ DT dt; dt.insert(points.begin(), points.end()); diff --git a/Triangulation_3/demo/Triangulation_3/CMakeLists.txt b/Triangulation_3/demo/Triangulation_3/CMakeLists.txt index 689461a7f16..aef32041b08 100644 --- a/Triangulation_3/demo/Triangulation_3/CMakeLists.txt +++ b/Triangulation_3/demo/Triangulation_3/CMakeLists.txt @@ -27,6 +27,28 @@ if(QT4_FOUND) find_package(QGLViewer) endif(QT4_FOUND) +# Activate concurrency ? (turned OFF by default) +option(ACTIVATE_CONCURRENT_TRIANGULATION_3 + "Activate parallelism in Triangulation_3" + OFF) + +# And add -DCONCURRENT_TRIANGULATION_3 if that option is ON +if( ACTIVATE_CONCURRENT_TRIANGULATION_3 ) + add_definitions( -DCONCURRENT_TRIANGULATION_3 ) + find_package( TBB REQUIRED ) +else( ACTIVATE_CONCURRENT_TRIANGULATION_3 ) + option( LINK_WITH_TBB + "Link with TBB anyway so we can use TBB timers for profiling" + ON) + if( LINK_WITH_TBB ) + find_package( TBB ) + endif( LINK_WITH_TBB ) +endif() + +if( TBB_FOUND ) + include(${TBB_USE_FILE}) +endif() + if ( CGAL_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND ) include(${QT_USE_FILE}) @@ -53,7 +75,7 @@ if ( CGAL_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS T3_demo ) target_link_libraries( T3_demo ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES}) - target_link_libraries( T3_demo ${QT_LIBRARIES} ${QGLVIEWER_LIBRARIES} ) + target_link_libraries( T3_demo ${QT_LIBRARIES} ${QGLVIEWER_LIBRARIES} ${TBB_LIBRARIES}) target_link_libraries( T3_demo ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ) else( CGAL_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND ) diff --git a/Triangulation_3/demo/Triangulation_3/Scene.cpp b/Triangulation_3/demo/Triangulation_3/Scene.cpp index 8ecd6570a77..5fb8a5c47d4 100644 --- a/Triangulation_3/demo/Triangulation_3/Scene.cpp +++ b/Triangulation_3/demo/Triangulation_3/Scene.cpp @@ -36,6 +36,13 @@ void Scene::generatePoints(int num) /* Insert the points to build a Delaunay triangulation */ /* Note: this function returns the number of inserted points; it is not guaranteed to insert the points following the order of iteraror. */ +#ifdef CONCURRENT_TRIANGULATION_3 + // To define the max number of threads TBB can use + //tbb::task_scheduler_init init(10); + + Lock_ds locking_ds(CGAL::Bbox_3(-1.,-1.,-1.,1,1,1), 50); + m_dt.set_lock_data_structure(&locking_ds); + m_dt.insert( pts.begin(), pts.end() ); /* Check the combinatorial validity of the triangulation */ /* Note: when it is set to be true, diff --git a/Triangulation_3/demo/Triangulation_3/Viewer.cpp b/Triangulation_3/demo/Triangulation_3/Viewer.cpp index 2d4e4d04697..87092ac4a90 100644 --- a/Triangulation_3/demo/Triangulation_3/Viewer.cpp +++ b/Triangulation_3/demo/Triangulation_3/Viewer.cpp @@ -992,8 +992,8 @@ void Viewer::wheelEvent(QWheelEvent *event) // note: most mouse types work in steps of 15 degrees // positive value: rotate forwards away from the user; // negative value: rotate backwards toward the user. - m_fRadius += (event->delta()*1. / m_iStep ); // inc-/decrease by 0.1 per step - if( m_fRadius < 0.1 ) + m_fRadius += (event->delta()*1.f / m_iStep ); // inc-/decrease by 0.1 per step + if( m_fRadius < 0.1f ) m_fRadius = 0.1f; // redraw @@ -1006,8 +1006,8 @@ void Viewer::wheelEvent(QWheelEvent *event) // positive value: rotate forwards away from the user; // negative value: rotate backwards toward the user. float origR = m_fRadius; - m_fRadius += (event->delta()*1. / m_iStep ); // inc-/decrease by 0.1 per step - if( m_fRadius < 0.1 ) + m_fRadius += (event->delta()*1.f / m_iStep ); // inc-/decrease by 0.1 per step + if( m_fRadius < 0.1f ) m_fRadius = 0.1f; // update the new point and its conflict region if( m_hasNewPt ) { @@ -1024,8 +1024,8 @@ void Viewer::wheelEvent(QWheelEvent *event) // resize the trackball when moving a point else if( m_curMode == MOVE && modifiers == Qt::SHIFT && m_isMoving ) { float origR = m_fRadius; - m_fRadius += (event->delta()*1. / m_iStep ); // inc-/decrease by 0.1 per step - if( m_fRadius < 0.1 ) + m_fRadius += (event->delta()*1.f / m_iStep ); // inc-/decrease by 0.1 per step + if( m_fRadius < 0.1f ) m_fRadius = 0.1f; origR = m_fRadius / origR; Point_3 pt = m_pScene->m_vhArray.at( m_vidMoving )->point(); diff --git a/Triangulation_3/demo/Triangulation_3/typedefs.h b/Triangulation_3/demo/Triangulation_3/typedefs.h index f754ff5a400..69cbd513899 100644 --- a/Triangulation_3/demo/Triangulation_3/typedefs.h +++ b/Triangulation_3/demo/Triangulation_3/typedefs.h @@ -1,6 +1,8 @@ #ifndef TYPEDEFS_H #define TYPEDEFS_H +#define CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + #include //dynamic array #include //linked list @@ -32,12 +34,15 @@ typedef Kernel::Direction_3 Direction_3; /* * The user has several ways to add his own data in the vertex - * and cell base classes used by the TDS. He can either: * 1. use the classes Triangulation vertex base with info + * and cell base classes used by the TDS. He can either: + * 1. use the classes Triangulation vertex base with info * and Triangulation cell base with info, which allow to - * add one data member of a user provided type, and give access to it. * 2. derive his own classes from the default base classes + * add one data member of a user provided type, and give access to it. + * 2. derive his own classes from the default base classes * Triangulation ds vertex base, and Triangulation ds cell base * (or the geometric versions typically used by the geometric layer, - * Triangulation vertex base, and Triangulation cell base). * 3. write his own base classes following the requirements given by the concepts + * Triangulation vertex base, and Triangulation cell base). + * 3. write his own base classes following the requirements given by the concepts * TriangulationCellBase 3 and TriangulationVertexBase 3 * (described in page 2494 and page 2495). */ @@ -69,7 +74,6 @@ private: bool m_isSelected; // whether it is selected }; -typedef CGAL::Triangulation_data_structure_3< Vertex_base > Tds; /* * Delaunay_triangulation_3 * arg1: a model of the DelaunayTriangulationTraits_3 concept @@ -81,7 +85,21 @@ typedef CGAL::Triangulation_data_structure_3< Vertex_base > Tds; * Compact_location saves memory by avoiding the separate data structure * and point location is then O(n^(1/3)) time */ -typedef CGAL::Delaunay_triangulation_3 DT3; +#ifdef CONCURRENT_TRIANGULATION_3 +typedef CGAL::Spatial_lock_grid_3< + CGAL::Tag_priority_blocking> Lock_ds; +typedef CGAL::Triangulation_data_structure_3< + Vertex_base, + CGAL::Triangulation_ds_cell_base_3<>, + CGAL::Parallel_tag > Tds; +typedef CGAL::Delaunay_triangulation_3< + Kernel, Tds, CGAL::Default, Lock_ds> DT3; + +#else +typedef CGAL::Triangulation_data_structure_3< Vertex_base > Tds; +typedef CGAL::Delaunay_triangulation_3< + Kernel, Tds/*, CGAL::Fast_location*/> DT3; +#endif typedef DT3::Object Object_3; typedef DT3::Point Point_3; diff --git a/Triangulation_3/doc/TDS_3/CGAL/Triangulation_data_structure_3.h b/Triangulation_3/doc/TDS_3/CGAL/Triangulation_data_structure_3.h index a7b829f7f5c..742ea25c03c 100644 --- a/Triangulation_3/doc/TDS_3/CGAL/Triangulation_data_structure_3.h +++ b/Triangulation_3/doc/TDS_3/CGAL/Triangulation_data_structure_3.h @@ -10,7 +10,8 @@ geometric functionalities to be used as a parameter for a 3D-geometric triangulation (see Chapter \ref chapterTriangulation3 "3D Triangulations"). The vertices and cells are stored in two nested containers, which are -implemented using `Compact_container`. The class may offer some +implemented using `Compact_container` (or `Concurrent_compact_container`, +see below). The class may offer some flexibility for the choice of container in the future, in the form of additional template parameters. @@ -23,6 +24,14 @@ the requirements for the concepts `TriangulationDSCellBase_3` and They have the default values `Triangulation_ds_vertex_base_3` and `Triangulation_ds_cell_base_3` respectively. +The `Concurrency_tag` parameter allows to enable the use of a concurrent +container to store vertices and cells. It can be `Sequential_tag` (use of a +`Compact_container` to store vertices and cells) or `Parallel_tag` +(use of a `Concurrent_compact_container`). If it is +`Parallel_tag`, the following functions can be called concurrently: +`create_vertex`, `create_cell`, `delete_vertex`, `delete_cell`. +`Sequential_tag` is the default value. + \cgalModels `TriangulationDataStructure_3` The base class `Triangulation_utils_3` defines basic computations on @@ -36,7 +45,9 @@ specified by the concept. \sa `CGAL::Triangulation_vertex_base_with_info_3` \sa `CGAL::Triangulation_cell_base_with_info_3` */ -template< typename TriangulationDSVertexBase_3, typename TriangulationDSCellBase_3 > +template< typename TriangulationDSVertexBase_3, + typename TriangulationDSCellBase_3, + typename Concurrency_tag > class Triangulation_data_structure_3 : public CGAL::Triangulation_utils_3 { public: @@ -44,15 +55,16 @@ public: /// @{ /*! -Vertex container type. +Vertex container type. If Concurrency_tag is Parallel_tag, a +`Concurrent_compact_container` is used instead of a `Compact_container`. */ -typedef Compact_container Vertex_range; +typedef Compact_container Vertex_range; /*! -Cell container type. +Cell container type. If Concurrency_tag is Parallel_tag, a +`Concurrent_compact_container` is used instead of a `Compact_container`. */ -typedef Compact_container Cell_range; - +typedef Compact_container Cell_range; /// @} /// \name Operations diff --git a/Triangulation_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h b/Triangulation_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h index 00be6f0b8ed..5cf89db8033 100644 --- a/Triangulation_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h +++ b/Triangulation_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h @@ -110,6 +110,13 @@ typedef unspecified_type Vertex_handle; */ typedef unspecified_type Cell_handle; +/*! +Can be `CGAL::Sequential_tag` or `CGAL::Parallel_tag`. If it is +`CGAL::Parallel_tag`, the following functions can be called concurrently: +`create_vertex`, `create_cell`, `delete_vertex`, `delete_cell`. +*/ +typedef unspecified_type Concurrency_tag; + /*! \cgalAdvancedBegin This template class allows to get the type of a triangulation diff --git a/Triangulation_3/doc/TDS_3/PackageDescription.txt b/Triangulation_3/doc/TDS_3/PackageDescription.txt index 7aaf8b9a119..6c220ea61e0 100644 --- a/Triangulation_3/doc/TDS_3/PackageDescription.txt +++ b/Triangulation_3/doc/TDS_3/PackageDescription.txt @@ -12,7 +12,7 @@ \cgalPkgDescriptionBegin{3D Triangulation Data Structure,PkgTDS3Summary} \cgalPkgPicture{tds3_small.png} \cgalPkgSummaryBegin -\cgalPkgAuthors{Sylvain Pion and Monique Teillaud} +\cgalPkgAuthors{Clément Jamin, Sylvain Pion and Monique Teillaud} \cgalPkgDesc{This package provides a data structure to store a three-dimensional triangulation that has the topology of a three-dimensional sphere. The package acts as a container for the vertices and cells of the triangulation and provides basic combinatorial operations on the triangulation.} \cgalPkgManuals{Chapter_3D_Triangulation_Data_Structure,PkgTDS3} \cgalPkgSummaryEnd @@ -56,7 +56,7 @@ Section \ref TDS3secintro.) ## Classes ## -- `CGAL::Triangulation_data_structure_3` is a model for the concept of the 3D-triangulation data structure `TriangulationDataStructure_3`. It is templated by base classes for vertices and cells. +- `CGAL::Triangulation_data_structure_3` is a model for the concept of the 3D-triangulation data structure `TriangulationDataStructure_3`. It is templated by base classes for vertices and cells. \cgal provides base vertex classes and base cell classes: diff --git a/Triangulation_3/doc/TDS_3/TriangulationDS_3.txt b/Triangulation_3/doc/TDS_3/TriangulationDS_3.txt index 4b7c4e283a2..0446c9b2573 100644 --- a/Triangulation_3/doc/TDS_3/TriangulationDS_3.txt +++ b/Triangulation_3/doc/TDS_3/TriangulationDS_3.txt @@ -6,7 +6,7 @@ \anchor chapterTDS3 \cgalAutoToc -\authors Sylvain Pion and Monique Teillaud +\authors Clément Jamin, Sylvain Pion and Monique Teillaud A geometric triangulation has two aspects: the combinatorial structure, which gives the incidence and adjacency relations between faces, and the @@ -301,6 +301,14 @@ typedef Triangulation_vertex_base_3 Other; \endcode +\subsection tds3parallel Parallel Operations + +The third template parameter of `Triangulation_data_structure_3` is +`Concurrency_tag`. It enables the use of a concurrent +container (`Concurrent_compact_container`) to store vertices and cells. +If it is `Parallel_tag`, then `create_vertex`, `create_cell`, `delete_vertex` +and `delete_cell` can be called concurrently. + \section TDS3secexamples Examples \subsection TDS_3IncrementalConstruction Incremental Construction @@ -326,6 +334,8 @@ triangulations and handle degenerate dimensions \cgalCite{t-tdtc-99}. Sylvain Pion improved the software in several ways, in particular regarding the memory management. +In 2013, Clément Jamin added the ability to create/delete vertices and cells +in parallel. This feature is used by the parallel triangulation. */ } /* namespace CGAL */ diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Delaunay_triangulation_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Delaunay_triangulation_3.h index 70a27a22a7c..7f3c6ac23d2 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Delaunay_triangulation_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Delaunay_triangulation_3.h @@ -23,6 +23,8 @@ hierarchy data structure \cgalCite{cgal:d-dh-02}. The default is `Compact_location`, which saves memory (3-5%) by avoiding the need for this separate data structure, and point location is then performed roughly in \f$ O(n^{1/3})\f$ time. +If the triangulation is parallel (see user manual), the default compact +location policy must be used. Note that this argument can also come in second position, which can be useful when the default value for the `TriangulationDataStructure_3` parameter is satisfactory (this is using so-called deduced parameters). @@ -31,16 +33,33 @@ provided before \cgal 3.6 by `Triangulation_hierarchy_3`. An example of use can be found in the user manual \ref Triangulation3exfastlocation. +\tparam SurjectiveLockDataStructure is an optional parameter to specify the type of the spatial lock data structure. + It is only used if the triangulation data structure used is concurrency-safe (i.e.\ when + TriangulationDataStructure_3::Concurrency_tag is Parallel_tag). + It must be a model of the `SurjectiveLockDataStructure` concept, + with `Object` being a `Point`. + The default value is `Spatial_lock_grid_3` if + the triangulation data structure is concurrency-safe, and `void` otherwise. + In order to use concurrent operations, the user must provide a + reference to a `SurjectiveLockDataStructure` + instance via the constructor or `Triangulation_3::set_lock_data_structure`. + +If `TriangulationDataStructure_3::Concurrency_tag` is `Parallel_tag`, some operations, +such as insertion/removal of a range of points, are performed in parallel. See +the documentation of the operations for more details. + \sa `CGAL::Regular_triangulation_3` */ -template< typename DelaunayTriangulationTraits_3, typename TriangulationDataStructure_3, typename LocationPolicy > +template< typename DelaunayTriangulationTraits_3, typename TriangulationDataStructure_3, typename LocationPolicy, typename SurjectiveLockDataStructure > class Delaunay_triangulation_3 : public Triangulation_3::Triangulation_data_structure + LocationPolicy>::Triangulation_data_structure, + SurjectiveLockDataStructure > + { public: @@ -53,6 +72,11 @@ public: */ typedef LocationPolicy Location_policy; +/*! + +*/ +typedef SurjectiveLockDataStructure Lock_data_structure; + /// @} /*! \name @@ -88,21 +112,36 @@ typedef DelaunayTriangulationTraits_3::Object_3 Object; /*! Creates an empty Delaunay triangulation, possibly specifying a traits class `traits`. +`lock_ds` is an optional pointer to the lock data structure for parallel operations. It +must be provided if concurrency is enabled. */ Delaunay_triangulation_3 -(const DelaunayTriangulationTraits_3& traits = DelaunayTriangulationTraits_3()); +(const DelaunayTriangulationTraits_3& traits = DelaunayTriangulationTraits_3(), +Lock_data_structure *lock_ds = NULL); /*! Copy constructor. +The pointer to the lock data structure is not copied. Thus, the copy won't be +concurrency-safe as long as the user has not called `Triangulation_3::set_lock_data_structure`. */ Delaunay_triangulation_3 (const Delaunay_triangulation_3 & dt1); /*! Equivalent to constructing an empty triangulation with the optional -traits class argument and calling `insert(first,last)`. +traits class argument and calling `insert(first,last)`. +If parallelism is enabled, the points will be inserted in parallel. */ template < class InputIterator > Delaunay_triangulation_3 (InputIterator first, InputIterator last, +const DelaunayTriangulationTraits_3& traits = DelaunayTriangulationTraits_3(), +Lock_data_structure *lock_ds = NULL); + +/*! +Same as before, with last two parameters in reverse order. +*/ +template < class InputIterator > +Delaunay_triangulation_3 (InputIterator first, InputIterator last, +Lock_data_structure *lock_ds, const DelaunayTriangulationTraits_3& traits = DelaunayTriangulationTraits_3()); /// @} @@ -116,14 +155,23 @@ Inserts point `p` in the triangulation and returns the corresponding vertex. Similar to the insertion in a triangulation, but ensures in addition the empty sphere property of all the created faces. The optional argument `start` is used as a starting place for the search. + +The optional argument `could_lock_zone` is used by the concurrency-safe +version of the triangulation. If the pointer is not null, the insertion will +try to lock all the cells of the conflict zone, i.e.\ all the vertices that are +inside or on the boundary of the conflict zone. If it succeeds, `*could_lock_zone` +is true, otherwise it is false and the return value is Vertex_handle() +(the point is not inserted). In any case, the locked cells are not unlocked by the +function, leaving this choice to the user. */ Vertex_handle insert(const Point & p, -Cell_handle start = Cell_handle() ); +Cell_handle start = Cell_handle(), bool *could_lock_zone = NULL); /*! Same as above but uses `hint` as a starting place for the search. */ -Vertex_handle insert(const Point & p, Vertex_handle hint); +Vertex_handle insert(const Point & p, Vertex_handle hint, + bool *could_lock_zone = NULL); /*! Inserts point `p` in the triangulation and returns the corresponding @@ -132,13 +180,16 @@ parameter the return values of a previous location query. See description of `Triangulation_3::locate()`. */ Vertex_handle insert(const Point & p, Locate_type lt, -Cell_handle loc, int li, int lj); +Cell_handle loc, int li, int lj, +bool *could_lock_zone = NULL); /*! Inserts the points in the iterator range `[first,last)`. Returns the number of inserted points. Note that this function is not guaranteed to insert the points following the order of `PointInputIterator`, as `spatial_sort()` is used to improve efficiency. +If parallelism is enabled, the points will be inserted in parallel. + \tparam PointInputIterator must be an input iterator with the value type `Point`. */ @@ -153,6 +204,7 @@ Returns the number of inserted points. Note that this function is not guaranteed to insert the points following the order of `PointWithInfoInputIterator`, as `spatial_sort()` is used to improve efficiency. +If parallelism is enabled, the points will be inserted in parallel. Given a pair `(p,i)`, the vertex `v` storing `p` also stores `i`, that is `v.point() == p` and `v.info() == i`. If several pairs have the same point, only one vertex is created, and one of the objects of type `Vertex::Info` will be stored in the vertex. @@ -209,14 +261,41 @@ decreases drastically, it might be interesting to defragment the /*! Removes the vertex `v` from the triangulation. + \pre `v` is a finite vertex of the triangulation. */ void remove(Vertex_handle v); -/*! -Removes the vertices specified by the iterator range `[first, beyond)`. -The function `remove(Vertex_handle)` is called over each element of the range. -The number of vertices removed is returned. +/*! +Removes the vertex `v` from the triangulation. + +This function is concurrency-safe if the triangulation is concurrency-safe. +It will first +try to lock all the cells adjacent to `v`. If it succeeds, `*could_lock_zone` +is true, otherwise it is false (and the point is not removed). In any case, +the locked cells are not unlocked by the function, leaving this choice to the user. + +This function will try to remove `v` only if the removal does not +decrease the dimension. + +The return value is only meaningful if `*could_lock_zone` is `true`: + - returns true if the vertex was removed + - returns false if the vertex wasn't removed since it would decrease + the dimension. + +\pre `v` is a finite vertex of the triangulation. +\pre `dt`.`dimension()` \f$ =3\f$. + +*/ +bool remove(Vertex_handle v, bool *could_lock_zone); + +/*! +Removes the vertices specified by the iterator range `[first, beyond)`. +The number of vertices removed is returned. +If parallelism is enabled, the points will be removed in parallel. +Note that if at some step, the triangulation dimension becomes lower than 3, +the removal of the remaining points will go on sequentially. + \pre (i) all vertices of the range are finite vertices of the triangulation; and (ii) no vertices are repeated in the range. \tparam InputIterator must be an input iterator with value type `Vertex_handle`. @@ -228,7 +307,8 @@ int remove(InputIterator first, InputIterator beyond); This function has exactly the same result and the same preconditions as `remove(first, beyond)`. The difference is in the implementation and efficiency. This version does not re-triangulate the hole after each point removal but only after removing all vertices. This is more efficient if (and only if) the removed points -are organized in a small number of connected components of the Delaunay triangulation. +are organized in a small number of connected components of the Delaunay triangulation. +Another difference is that there is no parallel version of this function. \tparam InputIterator must be an input iterator with value type `Vertex_handle`. */ @@ -338,6 +418,14 @@ respectively in the output iterators: (resp. edges) `(t, i)` where the cell (resp. facet) `t` is in conflict, but `t->neighbor(i)` is not. +- `could_lock_zone`: The optional argument `could_lock_zone` is used by the concurrency-safe + version of the triangulation. If the pointer is not null, the algorithm will + try to lock all the cells of the conflict zone, i.e.\ all the vertices that are + inside or on the boundary of the conflict zone (as a result, the boundary cells become + partially locked). If it succeeds, `*could_lock_zone` + is true, otherwise it is false (and the returned conflict zone is only partial). In any case, + the locked cells are not unlocked by the function, leaving this choice to the user. + This function can be used in conjunction with `insert_in_hole()` in order to decide the insertion of a point after seeing which elements of the triangulation are affected. @@ -350,7 +438,7 @@ class OutputIteratorCells> std::pair find_conflicts(Point p, Cell_handle c, OutputIteratorBoundaryFacets bfit, -OutputIteratorCells cit); +OutputIteratorCells cit, bool *could_lock_zone = NULL); /*! Same as the other `find_conflicts()` function, except that it also @@ -367,6 +455,14 @@ conflict, but `t->neighbor(i)` is not. - `ifit`: the facets (resp. edges) inside the hole, that is, delimiting two cells (resp facets) in conflict. +- `could_lock_zone`: The optional argument `could_lock_zone` is used by the concurrency-safe + version of the triangulation. If the pointer is not null, the algorithm will + try to lock all the cells of the conflict zone, i.e.\ all the vertices that are + inside or on the boundary of the conflict zone (as a result, the boundary cells become + partially locked). If it succeeds, `*could_lock_zone` + is true, otherwise it is false (and the returned conflict zone is only partial). In any case, + the locked cells are not unlocked by the function, leaving this choice to the user. + Returns the `Triple` composed of the resulting output iterators. \pre `dt`.`dimension()` \f$ \geq2\f$, and `c` is in conflict with `p`. @@ -380,7 +476,8 @@ OutputIteratorInternalFacets> find_conflicts(Point p, Cell_handle c, OutputIteratorBoundaryFacets bfit, OutputIteratorCells cit, -OutputIteratorInternalFacets ifit); +OutputIteratorInternalFacets ifit, +bool *could_lock_zone = NULL); /*! \deprecated This function is renamed `vertices_on_conflict_zone_boundary` since CGAL-3.8. diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_3.h index eafbbe66c84..caa38ad1f8e 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_3.h @@ -27,15 +27,30 @@ the power sphere. A sphere \f$ {z}^{(w)}\f$ is said to be A triangulation of \f$ {S}^{(w)}\f$ is regular if the power spheres of all simplices are regular. - \tparam RegularTriangulationTraits_3 is the geometric traits class. \tparam TriangulationDataStructure_3 is the triangulation data structure. It has the default value `Triangulation_data_structure_3, Regular_triangulation_cell_base_3 >`. +\tparam SurjectiveLockDataStructure is an optional parameter to specify the type of the spatial lock data structure. + It is only used if the triangulation data structure used is concurrency-safe (i.e.\ when + TriangulationDataStructure_3::Concurrency_tag is Parallel_tag). + It must be a model of the `SurjectiveLockDataStructure` concept, + with `Object` being a `Point`. + The default value is `Spatial_lock_grid_3` if + the triangulation data structure is concurrency-safe, and `void` otherwise. + In order to use concurrent operations, the user must provide a + reference to a `SurjectiveLockDataStructure` + instance via the constructor or `Triangulation_3::set_lock_data_structure`. + +If `TriangulationDataStructure_3::Concurrency_tag` is `Parallel_tag`, some operations, +such as insertion/removal of a range of points, are performed in parallel. See +the documentation of the operations for more details. + +\sa `CGAL::Delaunay_triangulation_3` */ -template< typename RegularTriangulationTraits_3, typename TriangulationDataStructure_3 > -class Regular_triangulation_3 : public Triangulation_3 { +template< typename RegularTriangulationTraits_3, typename TriangulationDataStructure_3, typename SurjectiveLockDataStructure > +class Regular_triangulation_3 : public Triangulation_3 { public: /// \name Types @@ -52,6 +67,11 @@ typedef RegularTriangulationTraits_3::Bare_point Bare_point; */ typedef RegularTriangulationTraits_3::Weighted_point_3 Weighted_point; +/*! + +*/ +typedef SurjectiveLockDataStructure Lock_data_structure; + /// @} /// \name Creation @@ -60,12 +80,17 @@ typedef RegularTriangulationTraits_3::Weighted_point_3 Weighted_point; /*! Creates an empty regular triangulation, possibly specifying a traits class `traits`. +`lock_ds` is an optional pointer to the lock data structure for parallel operations. It +must be provided if concurrency is enabled. */ Regular_triangulation_3 -(const RegularTriangulationTraits_3 & traits = RegularTriangulationTraits_3()); +(const RegularTriangulationTraits_3 & traits = RegularTriangulationTraits_3(), +Lock_data_structure *lock_ds = NULL); /*! Copy constructor. +The pointer to the lock data structure is not copied. Thus, the copy won't be +concurrency-safe as long as the user has not called `Triangulation_3::set_lock_data_structure`. */ Regular_triangulation_3 (const Regular_triangulation_3 & rt1); @@ -73,12 +98,21 @@ Regular_triangulation_3 /*! Equivalent to constructing an empty triangulation with the optional traits class argument and calling `insert(first,last)`. +If parallelism is enabled, the points will be inserted in parallel. \tparam InputIterator must be an input iterator with value type `Weighted_point`. */ template < class InputIterator > Regular_triangulation_3 (InputIterator first, InputIterator last, -const RegularTriangulationTraits_3& traits = RegularTriangulationTraits_3()); +const RegularTriangulationTraits_3& traits = RegularTriangulationTraits_3(), +Lock_data_structure *lock_ds = NULL); +/*! +Same as before, with last two parameters in reverse order. +*/ +template < class InputIterator > +Regular_triangulation_3 (InputIterator first, InputIterator last, +Lock_data_structure *lock_ds, +const RegularTriangulationTraits_3& traits = RegularTriangulationTraits_3()); /// @} /*!\name Insertion @@ -104,14 +138,21 @@ remains unchanged. Otherwise if `p` does not appear as a vertex of the triangulation, then it is stored as a hidden point and this method returns the default constructed handle. + +The optional argument `could_lock_zone` is used by the concurrency-safe +version of the triangulation. If the pointer is not null, the insertion will +try to lock all the cells of the conflict zone, i.e.\ all the vertices that are +inside or on the boundary of the conflict zone. If it succeeds, `*could_lock_zone` +is true, otherwise it is false (and the point is not inserted). In any case, +the locked cells are not unlocked by the function, leaving this choice to the user. */ Vertex_handle insert(const Weighted_point & p, -Cell_handle start = Cell_handle() ); +Cell_handle start = Cell_handle(), bool *could_lock_zone = NULL); /*! Same as above but uses `hint` as a starting place for the search. */ -Vertex_handle insert(const Weighted_point & p, Vertex_handle hint); +Vertex_handle insert(const Weighted_point & p, Vertex_handle hint, bool *could_lock_zone = NULL); /*! Inserts weighted point `p` in the triangulation and returns the corresponding @@ -120,7 +161,7 @@ parameter the return values of a previous location query. See description of `Triangulation_3::locate()`. */ Vertex_handle insert(const Weighted_point & p, Locate_type lt, -Cell_handle loc, int li, int lj); +Cell_handle loc, int li, int lj, bool *could_lock_zone = NULL); /*! Inserts the weighted points in the range `[first,last)`. @@ -129,6 +170,7 @@ before the insertions (it may be negative due to hidden points). Note that this function is not guaranteed to insert the points following the order of `InputIterator`, as `spatial_sort()` is used to improve efficiency. +If parallelism is enabled, the points will be inserted in parallel. \tparam InputIterator must be an input iterator with value type `Weighted_point`. */ @@ -144,6 +186,7 @@ before the insertions (it may be negative due to hidden points). Note that this function is not guaranteed to insert the weighted points following the order of `WeightedPointWithInfoInputIterator`, as `spatial_sort()` is used to improve efficiency. +If parallelism is enabled, the points will be inserted in parallel. Given a pair `(p,i)`, the vertex `v` storing `p` also stores `i`, that is `v.point() == p` and `v.info() == i`. If several pairs have the same point, only one vertex is created, one of the objects of type `Vertex::Info` will be stored in the vertex. @@ -203,9 +246,33 @@ Removes the vertex `v` from the triangulation. void remove(Vertex_handle v); /*! -Removes the vertices specified by the iterator range `[first, beyond)`. -The function `remove(Vertex_handle)` is called over each element of the range. -The number of vertices removed is returned. +Removes the vertex `v` from the triangulation. + +This function is concurrency-safe if the triangulation is concurrency-safe. +It will first +try to lock all the cells adjacent to `v`. If it succeeds, `*could_lock_zone` +is true, otherwise it is false (and the point is not removed). In any case, +the locked cells are not unlocked by the function, leaving this choice to the user. + +This function will try to remove `v` only if the removal does not +decrease the dimension. +The return value is only meaningful if `*could_lock_zone` is true: + - returns true if the vertex was removed + - returns false if the vertex wasn't removed since it would decrease + the dimension. + +\pre `v` is a finite vertex of the triangulation. +\pre `dt`.`dimension()` \f$ =3\f$. +*/ +bool remove(Vertex_handle v, bool *could_lock_zone); + +/*! +Removes the vertices specified by the iterator range `[first, beyond)`. +The number of vertices removed is returned. +If parallelism is enabled, the points will be removed in parallel. +Note that if at some step, the triangulation dimension becomes lower than 3, +the removal of the remaining points will go on sequentially. + \pre (i) all vertices of the range are finite vertices of the triangulation; and (ii) no vertices are repeated in the range. \tparam InputIterator must be an input iterator with value type `Vertex_handle`. @@ -367,11 +434,25 @@ A weighted point `p` is said to be in conflict with a cell `c` in dimension 3 (r Compute the conflicts with `p`. -@param p The query point. -@param c The starting cell. -@param cit The cells (resp. facets) in conflict with `p`. -@param bfit The facets (resp. edges) on the boundary of the conflict zone, that is, the facets (resp.\ edges) `(t, i)` where the cell (resp.. facet) `t` is in conflict, but `t->neighbor(i)` is not. -@param ifit The facets (resp.\ edges) inside the conflict zone, that facets incident to two cells (resp.\ facets) in conflict. +@param p The query point. +@param c The starting cell. +@param cit The cells (resp. facets) in conflict with `p`. +@param bfit The facets (resp. edges) on the boundary of the conflict zone, that is, the facets (resp.\ edges) `(t, i)` where the cell (resp.. facet) `t` is in conflict, but `t->neighbor(i)` is not. +@param ifit The facets (resp.\ edges) inside the conflict zone, that facets incident to two cells (resp.\ facets) in conflict. +@param could_lock_zone The optional argument `could_lock_zone` is used by the concurrency-safe + version of the triangulation. If the pointer is not null, the algorithm will + try to lock all the cells of the conflict zone, i.e.\ all the vertices that are + inside or on the boundary of the conflict zone (as a result, the boundary cells become + partially locked). If it succeeds, `*could_lock_zone` + is true, otherwise it is false (and the returned conflict zone is only partial). In any case, + the locked cells are not unlocked by the function, leaving this choice to the user. +@param this_facet_must_be_in_the_cz + If the optional argument `this_facet_must_be_in_the_cz` is not null, the algorithm will check + if this facet is in the conflict zone (it may be internal as well as boundary). +@param the_facet_is_in_its_cz + This argument must be not null if the previous `this_facet_must_be_in_the_cz` argument is not null. + The boolean value pointed by this pointer is set to true if *`this_facet_must_be_in_the_cz` is + among the internal or boundary facets of the conflict zone, and false otherwise. \pre The starting cell (resp.\ facet) `c` must be in conflict with `p`. \pre `rt`.`dimension()` \f$ \geq2\f$, and `c` is in conflict with `p`. @@ -389,7 +470,10 @@ OutputIteratorInternalFacets> find_conflicts(const Weighted_point p, Cell_handle c, OutputIteratorBoundaryFacets bfit, OutputIteratorCells cit, -OutputIteratorInternalFacets ifit); +OutputIteratorInternalFacets ifit, +bool *could_lock_zone = NULL, +const Facet *this_facet_must_be_in_the_cz = NULL, +bool *the_facet_is_in_its_cz = NULL); /*! \deprecated This function is renamed `vertices_on_conflict_zone_boundary` since CGAL-3.8. diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_filtered_traits_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_filtered_traits_3.h index 37b8bb9da28..2ea300b658b 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_filtered_traits_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_filtered_traits_3.h @@ -6,7 +6,7 @@ namespace CGAL { \deprecated This class is deprecated since \cgal 3.6. The class `CGAL::Regular_triangulation_euclidean_traits_3` should be used instead. -Filtered predicates are automatically used if the boolean `Has_filtered_predicates` +Filtered predicates are automatically used if the Boolean `Has_filtered_predicates` in the kernel provided as template parameter of that class is set to `true`. The class `Regular_triangulation_filtered_traits_3` is designed as a traits class for the diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h index 335fa5407a9..0dc036ec797 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h @@ -12,6 +12,17 @@ of points. \tparam TriangulationDataStructure_3 is the triangulation data structure. It has the default value `Triangulation_data_structure_3< Triangulation_vertex_base_3,Triangulation_cell_base_3 >`. +\tparam SurjectiveLockDataStructure is an optional parameter to specify the type of the spatial lock data structure. + It is only used if the triangulation data structure used is concurrency-safe (i.e.\ when + TriangulationDataStructure_3::Concurrency_tag is Parallel_tag). + It must be a model of the `SurjectiveLockDataStructure` concept, + with `Object` being a `Point`. + The default value is `Spatial_lock_grid_3` if + the triangulation data structure is concurrency-safe, and `void` otherwise. + In order to use concurrent operations, the user must provide a + reference to a `SurjectiveLockDataStructure` + instance via the constructor or `Triangulation_3::set_lock_data_structure`. + \cgalHeading{Traversal of the Triangulation} The triangulation class provides several iterators and circulators @@ -21,7 +32,8 @@ that allow one to traverse it (completely or partially). \sa `TriangulationDataStructure_3::Cell` */ -template< typename TriangulationTraits_3, typename TriangulationDataStructure_3 > +template< typename TriangulationTraits_3, typename TriangulationDataStructure_3, + typename SurjectiveLockDataStructure > class Triangulation_3 : public Triangulation_utils_3 { public: @@ -44,6 +56,11 @@ typedef TriangulationDataStructure_3 Triangulation_data_structure; /*! +*/ +typedef SurjectiveLockDataStructure Lock_data_structure; + +/*! + */ typedef TriangulationTraits_3 Geom_traits; @@ -194,6 +211,11 @@ circulator over all facets incident to a given edge */ typedef TriangulationDataStructure_3::Facet_circulator Facet_circulator; +/*! +Concurrency tag (from the TDS). +*/ +typedef TriangulationDataStructure_3::Concurrency_tag Concurrency_tag; + /// @} /// \name Creation @@ -201,13 +223,25 @@ typedef TriangulationDataStructure_3::Facet_circulator Facet_circulator; /*! Introduces a triangulation `t` having only one vertex which is the -infinite vertex. +infinite vertex. +`lock_ds` is an optional pointer to the lock data structure for parallel operations. It +must be provided if concurrency is enabled. */ Triangulation_3 -(const TriangulationTraits_3 & traits = TriangulationTraits_3()); +(const TriangulationTraits_3 & traits = TriangulationTraits_3(), + Lock_data_structure *lock_ds = NULL); + +/*! +Same as the previous one, but with parameters in reverse order. +*/ +Triangulation_3 +(Lock_data_structure *lock_ds = NULL, + const TriangulationTraits_3 & traits = TriangulationTraits_3()); /*! Copy constructor. All vertices and faces are duplicated. +The pointer to the lock data structure is not copied. Thus, the copy won't be +concurrency-safe as long as the user has not call `Triangulation_3::set_lock_data_structure`. */ Triangulation_3 (const Triangulation_3 & tr); @@ -217,7 +251,8 @@ traits class argument and calling `insert(first,last)`. */ template < class InputIterator> Triangulation_3 (InputIterator first, InputIterator last, -const TriangulationTraits_3 & traits = TriangulationTraits_3() ); +const TriangulationTraits_3 & traits = TriangulationTraits_3(), +Lock_data_structure *lock_ds = NULL); /// @} @@ -245,7 +280,7 @@ Deletes all finite vertices and all cells of `t`. void clear(); /*! -Equality operator. Returns true iff there exist a bijection between the +Equality operator. Returns `true` iff there exist a bijection between the vertices of `t1` and those of `t2` and a bijection between the cells of `t1` and those of `t2`, which preserve the geometry of the triangulation, that is, the points of each corresponding pair of vertices are @@ -584,15 +619,22 @@ the facet (resp. edge, vertex) containing the query point. The optional argument `start` is used as a starting place for the search. +The optional argument `could_lock_zone` is used by the concurrency-safe +version of the triangulation. When the pointer is not null, the locate will +try to lock all the cells along the walk. If it succeeds, `*could_lock_zone` +is `true`, otherwise it is false. In any case, the locked cells are not +unlocked by `locate`, leaving this choice to the user. */ Cell_handle -locate(const Point & query, Cell_handle start = Cell_handle()) const; +locate(const Point & query, Cell_handle start = Cell_handle(), + bool *could_lock_zone = NULL) const; /*! Same as above but uses `hint` as the starting place for the search. */ Cell_handle -locate(const Point & query, Vertex_handle hint) const; +locate(const Point & query, Vertex_handle hint, + bool *could_lock_zone = NULL) const; /*! Same as `locate()` but uses inexact predicates. @@ -629,17 +671,24 @@ triangulation, `lt` is set to `OUTSIDE_AFFINE_HULL` and The optional argument `start` is used as a starting place for the search. +The optional argument `could_lock_zone` is used by the concurrency-safe +version of the triangulation. When the pointer is not null, the locate will +try to lock all the cells along the walk. If it succeeds, `*could_lock_zone` +is `true`, otherwise it is false. In any case, the locked cells are not +unlocked by `locate`, leaving this choice to the user. */ Cell_handle locate(const Point & query, Locate_type & lt, -int & li, int & lj, Cell_handle start = Cell_handle() ) const; +int & li, int & lj, Cell_handle start = Cell_handle(), +bool *could_lock_zone = NULL ) const; /*! Same as above but uses `hint` as the starting place for the search. */ Cell_handle locate(const Point & query, Locate_type & lt, -int & li, int & lj, Vertex_handle hint) const; +int & li, int & lj, Vertex_handle hint, +bool *could_lock_zone = NULL) const; /*! @@ -1170,6 +1219,18 @@ template OutputIterator incident_cells(Vertex_handle v, OutputIterator cells) const; +/*! +Try to lock and copy the `Cell_handle`s of all cells incident to `v` into +`cells`. +Returns `true` in case of success. Otherwise, `cells` is emptied and the function +returns false. In any case, the locked cells are not unlocked by +`try_lock_and_get_incident_cells`, leaving this choice to the user. + +\pre `t.dimension() == 3`, `v != Vertex_handle()`, `t.is_vertex(v)`. +*/ +bool + try_lock_and_get_incident_cells(Vertex_handle v, + std::vector& cells) const; /*! Copies the `Cell_handle`s of all finite cells incident to `v` to the output iterator `cells`. @@ -1283,7 +1344,7 @@ Facet mirror_facet(Facet f) const; Checks the combinatorial validity of the triangulation. Checks also the validity of its geometric embedding (see Section \ref Triangulation3secintro). -When `verbose` is set to true, +When `verbose` is set to `true`, messages describing the first invalidity encountered are printed. \cgalDebugEnd */ @@ -1347,5 +1408,17 @@ ostream& operator<< (ostream& os, const Triangulation_3 &t); /// @} +/// @} + +/// \name Concurrency +/// @{ + +/*! +Set the pointer to the lock data structure. +*/ +void set_lock_data_structure(Lock_data_structure *lock_ds) const; + +/// @} + }; /* end Triangulation_3 */ } /* end namespace CGAL */ diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_cell_base_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_cell_base_3.h index 7c7c57d5865..9427b288f6b 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_cell_base_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_cell_base_3.h @@ -14,8 +14,9 @@ application. \tparam TriangulationTraits_3 is the geometric traits class. It is actually not used by this class. -\tparam TriangulationDSCellBase_3 is a combinatorial cell base class from which -`Triangulation_cell_base_3` derives. +\tparam TriangulationDSCellBase_3_ is a combinatorial cell base class from which +`Triangulation_cell_base_3` derives. +It must be a model of the `TriangulationDSCellBase_3` concept. It has the default value `Triangulation_ds_cell_base_3`. \cgalModels `TriangulationCellBase_3` @@ -25,8 +26,8 @@ It has the default value `Triangulation_ds_cell_base_3`. \sa `CGAL::Triangulation_vertex_base_3` */ -template< typename TriangulationTraits_3, typename TriangulationDSCellBase_3 > -class Triangulation_cell_base_3 : public TriangulationDSCellBase_3 { +template< typename TriangulationTraits_3, typename TriangulationDSCellBase_3_ > +class Triangulation_cell_base_3 : public TriangulationDSCellBase_3_ { public: /// @} diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_cell_base_with_info_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_cell_base_with_info_3.h index 8cd21ed2a03..c377dd7183d 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_cell_base_with_info_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_cell_base_with_info_3.h @@ -16,8 +16,10 @@ to a cell. It has to be `DefaultConstructible` and `Assignable`. \tparam TriangulationTraits_3 is the geometric traits class. It is actually not used by this class. -\tparam TriangulationCellBase_3 is a cell base class from which -`Triangulation_cell_base_with_info_3` derives. It has the default value +\tparam TriangulationCellBase_3_ is a cell base class from which +`Triangulation_cell_base_with_info_3` derives. +It must be a model of the `TriangulationCellBase_3` concept. +It has the default value `Triangulation_cell_base_3`. \cgalModels `TriangulationCellBase_3` @@ -28,8 +30,8 @@ It is actually not used by this class. \sa `CGAL::Triangulation_vertex_base_with_info_3` */ -template< typename Info, typename TriangulationTraits_3, typename TriangulationCellBase_3 > -class Triangulation_cell_base_with_info_3 : public TriangulationCellBase_3 { +template< typename Info, typename TriangulationTraits_3, typename TriangulationCellBase_3_ > +class Triangulation_cell_base_with_info_3 : public TriangulationCellBase_3_ { public: /// \name Types diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_vertex_base_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_vertex_base_3.h index 4709f9aa614..da60403f75d 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_vertex_base_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_vertex_base_3.h @@ -20,8 +20,9 @@ geometric traits class `TriangulationTraits_3` as the one used for `Triangulation_3`. This way, the point type defined by the base vertex is the same as the point type defined by the geometric traits class. -\tparam TriangulationDSVertexBase_3 is a combinatorial vertex base class from which -`Triangulation_vertex_base_3` derives. +\tparam TriangulationDSVertexBase_3_ is a combinatorial vertex base class from which +`Triangulation_vertex_base_3` derives. +It must be a model of the `TriangulationDSVertexBase_3` concept. It has the default value `Triangulation_ds_vertex_base_3`. \cgalModels `TriangulationVertexBase_3` @@ -31,8 +32,8 @@ It has the default value `Triangulation_ds_vertex_base_3`. \sa `CGAL::Triangulation_vertex_base_with_info_3` */ -template< typename TriangulationTraits_3, typename TriangulationDSVertexBase_3 > -class Triangulation_vertex_base_3 : public TriangulationDSVertexBase_3 { +template< typename TriangulationTraits_3, typename TriangulationDSVertexBase_3_ > +class Triangulation_vertex_base_3 : public TriangulationDSVertexBase_3_ { public: /// \name Types diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_vertex_base_with_info_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_vertex_base_with_info_3.h index 993704c650c..4a9f48e4cca 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_vertex_base_with_info_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_vertex_base_with_info_3.h @@ -15,8 +15,10 @@ to a vertex. It has to be `DefaultConstructible` and `Assignable`. \tparam TriangulationTraits_3 is the geometric traits class which provides the `Point_3`. -\tparam TriangulationVertexBase_3 is a vertex base class from which -`Triangulation_vertex_base_with_info_3` derives. It has the default +\tparam TriangulationVertexBase_3_ is a vertex base class from which +`Triangulation_vertex_base_with_info_3` derives. +It must be a model of the `TriangulationVertexBase_3` concept. +It has the default value `Triangulation_vertex_base_3`. \cgalModels `TriangulationVertexBase_3` @@ -26,8 +28,8 @@ value `Triangulation_vertex_base_3`. \sa `CGAL::Triangulation_vertex_base_3` */ -template< typename Info, typename TriangulationTraits_3, typename TriangulationVertexBase_3 > -class Triangulation_vertex_base_with_info_3 : public TriangulationVertexBase_3 { +template< typename Info, typename TriangulationTraits_3, typename TriangulationVertexBase_3_ > +class Triangulation_vertex_base_with_info_3 : public TriangulationVertexBase_3_ { public: /// \name Types diff --git a/Triangulation_3/doc/Triangulation_3/PackageDescription.txt b/Triangulation_3/doc/Triangulation_3/PackageDescription.txt index 6ac5889021d..494c2a87644 100644 --- a/Triangulation_3/doc/Triangulation_3/PackageDescription.txt +++ b/Triangulation_3/doc/Triangulation_3/PackageDescription.txt @@ -19,8 +19,8 @@ \cgalPkgDescriptionBegin{3D Triangulations,PkgTriangulation3Summary} \cgalPkgPicture{twotets.png} \cgalPkgSummaryBegin -\cgalPkgAuthors{Sylvain Pion and Monique Teillaud} -\cgalPkgDesc{This package allows to build and handle triangulations for point sets in three dimensions. Any \cgal triangulation covers the convex hull of its vertices. Triangulations are build incrementally and can be modified by insertion, displacements or removal of vertices. They offer point location facilities. The package provides plain triangulation (whose faces depends on the insertion order of the vertices) and Delaunay triangulations. Regular triangulations are also provided for sets of weighted points. Delaunay and regular triangulations offer nearest neighbor queries and primitives to build the dual Voronoi and power diagrams.} +\cgalPkgAuthors{Clément Jamin, Sylvain Pion and Monique Teillaud} +\cgalPkgDesc{This package allows to build and handle triangulations for point sets in three dimensions. Any \cgal triangulation covers the convex hull of its vertices. Triangulations are build incrementally and can be modified by insertion, displacements or removal of vertices. They offer point location facilities. The package provides plain triangulation (whose faces depends on the insertion order of the vertices) and Delaunay triangulations. Regular triangulations are also provided for sets of weighted points. Delaunay and regular triangulations offer nearest neighbor queries and primitives to build the dual Voronoi and power diagrams. Optionally, the main Delaunay and regular triangulation algorithms (insert, remove) support multi-core shared-memory architectures to take advantage of available parallelism.} \cgalPkgManuals{Chapter_3D_Triangulations,PkgTriangulation3} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin @@ -84,9 +84,10 @@ is opposite to the vertex with the same index. See ### Main Classes ### -- `CGAL::Triangulation_3` -- `CGAL::Delaunay_triangulation_3` -- `CGAL::Regular_triangulation_3` +- `CGAL::Triangulation_3` +- `CGAL::Delaunay_triangulation_3` +- `CGAL::Triangulation_hierarchy_3` +- `CGAL::Regular_triangulation_3` - `CGAL::Triangulation_vertex_base_3` - `CGAL::Triangulation_vertex_base_with_info_3` - `CGAL::Triangulation_cell_base_3` diff --git a/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt b/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt index 1d510e3ccd5..53c33b33fbe 100644 --- a/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt +++ b/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt @@ -6,7 +6,7 @@ namespace CGAL { \anchor chapterTriangulation3 \cgalAutoToc -\authors Sylvain Pion and Monique Teillaud +\authors Clément Jamin, Sylvain Pion and Monique Teillaud \image html triangulation3.png \image latex triangulation3.png @@ -223,6 +223,16 @@ Chapter \ref chapterTDS3 "3D Triangulation Data Structure". triangulation class, described in Section \ref Triangulation3seclocpol.
    +Optionally, the main Delaunay and regular triangulations algorithms (insert, remove) +support multi-core shared-memory architectures to take advantage of available parallelism. +For this purpose, a model of the concept `SurjectiveLockDataStructure` can be +given as fourth template parameter; it defaults to +`Spatial_lock_grid_3`. This data structure +allows to lock points with coordinates (x, y, z) in a 3D domain. When a thread owns the +lock on a point, no other thread can lock this point. Locking a facet (resp. a cell) +boils down to locking all its 3 (resp. 4) incident vertices. +See Section \ref Triangulation_3ParallelAlgorithms for more details. + \subsection Triangulation3secTraits The Geometric Traits Parameter The first template parameter of the triangulation class @@ -402,6 +412,29 @@ My_vertex(const Point&p, Cell_handle c) : Vb(p, c) {} The situation is exactly similar for cell base classes. Section \ref TDS3secdesign "Software Design" provides more detailed information. +\subsection Triangulation_3ParallelAlgorithms Parallel Algorithms + +Parallel algorithms of `Delaunay_triangulation_3` and +`Regular_triangulation_3` are enabled +if the `TriangulationDataStructure_3::Concurrency_tag` type is `Parallel_tag` and a +reference to a lock data structure instance is provided via the constructor or +by using `Triangulation_3::set_lock_data_structure`. This data structure +must be a model of the concept `SurjectiveLockDataStructure` and can be +optionally given as a template parameter of the triangulation; +it defaults to `Spatial_lock_grid_3`. + +Note that the parallel Delaunay +triangulation must use the default compact location policy (and not the fast +one). If those conditions are fulfilled, the insertion/removal of a +range of points will be performed in parallel, and the individual +insert/remove operations will be optionally thread-safe. + +Parallel algorithms require the program to be linked against +the Intel TBB library. +To control the number of threads used, the user may use the tbb::task_scheduler_init class. +See the TBB documentation +for more details. + \section Triangulation3secexamples Examples \subsection Triangulation_3BasicExample Basic Example @@ -498,6 +531,19 @@ Another difference is that a specific traits class has to be used \cgalExample{Triangulation_3/regular_3.cpp} +\subsection Triangulation_3ParallelDelaunay Parallel insertion in Delaunay triangulation + +This example shows the parallel building of a Delaunay triangulation. + +\cgalExample{Triangulation_3/parallel_insertion_in_delaunay_3.cpp} + +\subsection Triangulation_3ParallelRegular Parallel insertion and removal in Regular triangulation + +This example shows the parallel building of a Regular triangulation, followed by the parallel +removal of the first 100,000 vertices. + +\cgalExample{Triangulation_3/parallel_insertion_and_removal_in_regular_3.cpp} + \section Triangulation3seccomplexity Complexity and Performance In 3D, the worst case complexity of a triangulation is quadratic in the number @@ -729,6 +775,22 @@ Running times in seconds for algorithms on 3D triangulations. More benchmarks comparing \cgal to other software can be found in \cgalCite{msri52:liu-snoeyink-05}. +\subsection Triangulation_3ParallelPerformance Parallel Performance + +Figure \cgalFigureRef{Triangulation3figparallelspeedup} shows insertion +and removal speed-ups obtained using the parallel version of the +triangulation algorithms of \cgal 4.5. The machine used is a PC running +Windows 7 64-bits with two 6-core +Intel Xeon CPU X5660 clocked at 2.80 GHz +with 32GB of RAM. The program has been compiled with +Microsoft Visual C++ 2012 in Release mode. + +\cgalFigureBegin{Triangulation3figparallelspeedup,DT3_parallel_benchmark.png} +Speed-up obtained for the insertion of 1M points randomly generated inside +a cube (red), and the removal of 100K of them (blue), compared +to the sequential version of the algorithm. +\cgalFigureEnd + \subsection Triangulation_3MemoryUsage Memory Usage We give here some indication about the memory usage of the triangulations. @@ -1035,6 +1097,9 @@ A new demo of this package was introduced in \cgal 3.8, coded by Fei (Sophie) Che, who was co-mentored by Manuel Caroli and Monique Teillaud in the framework of the Google Summer of Code, 2010. +In 2013, Clément Jamin added parallel algorithms (insert, remove) to the +Delaunay and regular triangulations. + The authors wish to thank Lutz Kettner for inspiring discussions about the design of \cgal. Jean-Daniel Boissonnat is also acknowledged \cgalCite{bdty-tcgal-00}. diff --git a/Triangulation_3/doc/Triangulation_3/examples.txt b/Triangulation_3/doc/Triangulation_3/examples.txt index f663908a517..44f09d428a1 100644 --- a/Triangulation_3/doc/Triangulation_3/examples.txt +++ b/Triangulation_3/doc/Triangulation_3/examples.txt @@ -10,4 +10,6 @@ \example Triangulation_3/find_conflicts_3.cpp \example Triangulation_3/regular_3.cpp \example Triangulation_3/copy_triangulation_3.cpp +\example Triangulation_3/parallel_insertion_in_delaunay_3.cpp +\example Triangulation_3/parallel_insertion_and_removal_in_regular_3.cpp */ diff --git a/Triangulation_3/doc/Triangulation_3/fig/DT3_parallel_benchmark.png b/Triangulation_3/doc/Triangulation_3/fig/DT3_parallel_benchmark.png new file mode 100644 index 00000000000..12cff9cef04 Binary files /dev/null and b/Triangulation_3/doc/Triangulation_3/fig/DT3_parallel_benchmark.png differ diff --git a/Triangulation_3/examples/Triangulation_3/CMakeLists.txt b/Triangulation_3/examples/Triangulation_3/CMakeLists.txt new file mode 100644 index 00000000000..a3cc3618260 --- /dev/null +++ b/Triangulation_3/examples/Triangulation_3/CMakeLists.txt @@ -0,0 +1,87 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + + +project( Triangulation_3_example ) + +cmake_minimum_required(VERSION 2.6.2) +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6) + if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3) + cmake_policy(VERSION 2.8.4) + else() + cmake_policy(VERSION 2.6) + endif() +endif() + +find_package(CGAL QUIET COMPONENTS Core ) + +if ( CGAL_FOUND ) + + include( ${CGAL_USE_FILE} ) + + # Activate concurrency ? (turned OFF by default) + option(ACTIVATE_CONCURRENT_MESH_3 + "Activate parallelism in Mesh_3" + OFF) + + # And add -DCGAL_CONCURRENT_MESH_3 if that option is ON + if( ACTIVATE_CONCURRENT_MESH_3 ) + add_definitions( -DCGAL_CONCURRENT_MESH_3 ) + find_package( TBB REQUIRED ) + endif() + + if( TBB_FOUND ) + include(${TBB_USE_FILE}) + list(APPEND CGAL_3RD_PARTY_LIBRARIES ${TBB_LIBRARIES}) + endif() + + # Activate concurrency ? (turned OFF by default) + option(ACTIVATE_CONCURRENT_MESH_3 + "Activate parallelism in Mesh_3" + OFF) + + # And add -DCGAL_CONCURRENT_MESH_3 if that option is ON + if( ACTIVATE_CONCURRENT_MESH_3 ) + add_definitions( -DCGAL_CONCURRENT_MESH_3 ) + find_package( TBB REQUIRED ) + else( ACTIVATE_CONCURRENT_MESH_3 ) + option( LINK_WITH_TBB + "Link with TBB anyway so we can use TBB timers for profiling" + ON) + if( LINK_WITH_TBB ) + find_package( TBB ) + endif( LINK_WITH_TBB ) + endif() + + if( TBB_FOUND ) + include(${TBB_USE_FILE}) + list(APPEND CGAL_3RD_PARTY_LIBRARIES ${TBB_LIBRARIES}) + endif() + + include( CGAL_CreateSingleSourceCGALProgram ) + + include_directories (BEFORE "../../include") + + create_single_source_cgal_program( "adding_handles_3.cpp" ) + create_single_source_cgal_program( "color.cpp" ) + create_single_source_cgal_program( "fast_location_3.cpp" ) + create_single_source_cgal_program( "find_conflicts_3.cpp" ) + create_single_source_cgal_program( "info_insert_with_pair_iterator.cpp" ) + create_single_source_cgal_program( "info_insert_with_pair_iterator_regular.cpp" ) + create_single_source_cgal_program( "info_insert_with_transform_iterator.cpp" ) + create_single_source_cgal_program( "info_insert_with_zip_iterator.cpp" ) + create_single_source_cgal_program( "linking_2d_and_3d.cpp" ) + create_single_source_cgal_program( "sequential_parallel.cpp" ) + create_single_source_cgal_program( "parallel_insertion_in_delaunay_3.cpp" ) + create_single_source_cgal_program( "parallel_insertion_and_removal_in_regular_3.cpp" ) + create_single_source_cgal_program( "regular_3.cpp" ) + create_single_source_cgal_program( "simple_triangulation_3.cpp" ) + create_single_source_cgal_program( "simplex.cpp" ) + create_single_source_cgal_program( "tds.cpp" ) + +else() + + message(STATUS "This program requires the CGAL library, and will not be compiled.") + +endif() + diff --git a/Triangulation_3/examples/Triangulation_3/parallel_insertion_and_removal_in_regular_3.cpp b/Triangulation_3/examples/Triangulation_3/parallel_insertion_and_removal_in_regular_3.cpp new file mode 100644 index 00000000000..d946642c138 --- /dev/null +++ b/Triangulation_3/examples/Triangulation_3/parallel_insertion_and_removal_in_regular_3.cpp @@ -0,0 +1,54 @@ +#include +#include +#include +#include + +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; + +typedef CGAL::Regular_triangulation_euclidean_traits_3 Traits; + +typedef Traits::RT Weight; +typedef Traits::Bare_point Point; +typedef Traits::Weighted_point Weighted_point; + +// Regular T3 +typedef CGAL::Triangulation_data_structure_3< + CGAL::Triangulation_vertex_base_3, + CGAL::Regular_triangulation_cell_base_3, + CGAL::Parallel_tag> Tds; + +typedef CGAL::Regular_triangulation_3 Rt; +typedef Rt::Vertex_handle Vertex_handle; + +int main() +{ + CGAL::Random_points_in_cube_3 rnd(1.); + + // Construction from a vector of 1,000,000 points + std::vector V; + V.reserve(1000000); + for (int i = 0; i != 1000000; ++i) + V.push_back(*rnd++); + + // Construct the locking data-structure, using the bounding-box of the points + Rt::Lock_data_structure locking_ds( + CGAL::Bbox_3(-1., -1., -1., 1., 1., 1.), 50); + // Contruct the triangulation in parallel + Rt rtr(V.begin(), V.end(), &locking_ds); + + std::cerr << "Remove"; + // Remove the first 100,000 vertices + std::vector vertices_to_remove; + int i = 0; + Rt::Finite_vertices_iterator vit = rtr.finite_vertices_begin(); + for (int i = 0 ; i < 100000 ; ++i) + vertices_to_remove.push_back(vit++); + // Parallel remove + rtr.remove(vertices_to_remove.begin(), vertices_to_remove.end()); + + return 0; +} diff --git a/Triangulation_3/examples/Triangulation_3/parallel_insertion_in_delaunay_3.cpp b/Triangulation_3/examples/Triangulation_3/parallel_insertion_in_delaunay_3.cpp new file mode 100644 index 00000000000..7d74ed255e2 --- /dev/null +++ b/Triangulation_3/examples/Triangulation_3/parallel_insertion_in_delaunay_3.cpp @@ -0,0 +1,37 @@ +#include +#include +#include + +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; + +// Delaunay T3 +typedef CGAL::Triangulation_data_structure_3< + CGAL::Triangulation_vertex_base_3, + CGAL::Triangulation_cell_base_3, + CGAL::Parallel_tag> Tds; +typedef CGAL::Delaunay_triangulation_3 Triangulation; + +typedef Triangulation::Point Point; + +int main() +{ + CGAL::Random_points_in_cube_3 rnd(1.); + + // Construction from a vector of 1,000,000 points + std::vector V; + V.reserve(1000000); + for (int i = 0; i != 1000000; ++i) + V.push_back(*rnd++); + + // Construct the locking data-structure, using the bounding-box of the points + Triangulation::Lock_data_structure locking_ds( + CGAL::Bbox_3(-1., -1., -1., 1., 1., 1.), 50); + // Construct the triangulation in parallel + Triangulation T(V.begin(), V.end(), &locking_ds); + + return 0; +} diff --git a/Triangulation_3/examples/Triangulation_3/sequential_parallel.cpp b/Triangulation_3/examples/Triangulation_3/sequential_parallel.cpp new file mode 100644 index 00000000000..14c03f33e97 --- /dev/null +++ b/Triangulation_3/examples/Triangulation_3/sequential_parallel.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::Point_3 Point; +typedef CGAL::Timer Timer; + +// Delaunay T3 +typedef CGAL::Delaunay_triangulation_3 SequentialTriangulation; + +typedef CGAL::Triangulation_data_structure_3< + CGAL::Triangulation_vertex_base_3, + CGAL::Triangulation_cell_base_3, + CGAL::Parallel_tag> ParallelTds; +typedef CGAL::Delaunay_triangulation_3 ParallelTriangulation; + + + +int main() +{ + CGAL::Random_points_in_cube_3 rnd(1.); + + std::cerr << "Construction of a 3D Delaunay triangulation from a vector of 1,000,000 random points in a cube" << std::endl; + std::vector V; + V.reserve(1000000); + for (int i = 0; i != 1000000; ++i) + V.push_back(*rnd++); + + Timer t; + t.start(); + SequentialTriangulation S(V.begin(), V.end()); + t.stop(); + std::cerr << "Sequential construction takes " << t.time() << " sec." << std::endl; + t.reset(); + + t.start(); + // Construct the locking data-structure, using the bounding-box of the points + ParallelTriangulation::Lock_data_structure locking_ds( + CGAL::Bbox_3(-1., -1., -1., 1., 1., 1.), 50); + // Construct the triangulation in parallel + ParallelTriangulation T(V.begin(), V.end(), &locking_ds); + t.stop(); + std::cerr << "Parallel construction takes " << t.time() << " sec. with " + << tbb::task_scheduler_init::default_num_threads() << " threads" << std::endl; + return 0; +} diff --git a/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h b/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h index 894fee0afbe..f3d85a9ec2b 100644 --- a/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h +++ b/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h @@ -19,18 +19,27 @@ // Author(s) : Monique Teillaud // Sylvain Pion // Andreas Fabri +// Clement Jamin #ifndef CGAL_DELAUNAY_TRIANGULATION_3_H #define CGAL_DELAUNAY_TRIANGULATION_3_H #include +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING +# define CGAL_PROFILE +# include +#endif + #include #include #include #include #include +#ifdef CGAL_TRIANGULATION_3_PROFILING +# include +#endif #ifndef CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO #include @@ -41,6 +50,14 @@ #include #endif //CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO +#ifdef CGAL_LINKED_WITH_TBB +# include +# include +# include +# include +# include +#endif + #ifdef CGAL_DELAUNAY_3_OLD_REMOVE # error "The old remove() code has been removed. Please report any issue you may have with the current one." #endif @@ -51,7 +68,8 @@ namespace CGAL { // having a default value. There is no definition of that class template. template < class Gt, class Tds_ = Default, - class Location_policy = Default > + class Location_policy = Default, + class Lock_data_structure_ = Default > class Delaunay_triangulation_3; // There is a specialization Delaunay_triangulation_3 @@ -59,12 +77,14 @@ class Delaunay_triangulation_3; // Here is the specialization Delaunay_triangulation_3, with two // arguments, that is if Location_policy being the default value 'Default'. -template < class Gt, class Tds_ > -class Delaunay_triangulation_3 - : public Triangulation_3 +template < class Gt, class Tds_, + class Lock_data_structure_ > +class Delaunay_triangulation_3 + : public Triangulation_3 { - typedef Delaunay_triangulation_3 Self; - typedef Triangulation_3 Tr_Base; + typedef Delaunay_triangulation_3 Self; + typedef Triangulation_3 Tr_Base; public: @@ -73,10 +93,13 @@ public: typedef Gt Geom_traits; typedef Compact_location Location_policy; + typedef typename Tr_Base::Lock_data_structure Lock_data_structure; + typedef typename Gt::Point_3 Point; typedef typename Gt::Segment_3 Segment; typedef typename Gt::Triangle_3 Triangle; typedef typename Gt::Tetrahedron_3 Tetrahedron; + typedef typename Gt::Vector_3 Vector; // types for dual: typedef typename Gt::Line_3 Line; @@ -148,11 +171,11 @@ protected: Oriented_side side_of_oriented_sphere(const Point &p0, const Point &p1, const Point &p2, - const Point &p3, const Point &t, bool perturb = false) const; + const Point &p3, const Point &t, bool perturb = false) const; Bounded_side coplanar_side_of_bounded_circle(const Point &p, const Point &q, - const Point &r, const Point &s, bool perturb = false) const; + const Point &r, const Point &s, bool perturb = false) const; // for dual: Point @@ -200,10 +223,24 @@ protected: public: - Delaunay_triangulation_3(const Gt& gt = Gt()) - : Tr_Base(gt) + Delaunay_triangulation_3(const Gt& gt = Gt(), Lock_data_structure *lock_ds = NULL) + : Tr_Base(gt, lock_ds) {} + Delaunay_triangulation_3(Lock_data_structure *lock_ds, const Gt& gt = Gt()) + : Tr_Base(lock_ds, gt) + {} + + // Create a 3D triangulation from 4 points which must be well-oriented + // AND non-coplanar + Delaunay_triangulation_3(const Point &p0, const Point &p1, + const Point &p2, const Point &p3, + const Gt& gt = Gt(), + Lock_data_structure *lock_ds = NULL) + : Tr_Base(p0, p1, p2, p3, gt, lock_ds) + {} + + // copy constructor duplicates vertices and cells Delaunay_triangulation_3(const Delaunay_triangulation_3 & tr) : Tr_Base(tr) @@ -213,8 +250,17 @@ public: template < typename InputIterator > Delaunay_triangulation_3(InputIterator first, InputIterator last, + const Gt& gt = Gt(), Lock_data_structure *lock_ds = NULL) + : Tr_Base(gt, lock_ds) + { + insert(first, last); + } + + template < typename InputIterator > + Delaunay_triangulation_3(InputIterator first, InputIterator last, + Lock_data_structure *lock_ds, const Gt& gt = Gt()) - : Tr_Base(gt) + : Tr_Base(gt, lock_ds) { insert(first, last); } @@ -236,21 +282,108 @@ public: insert( InputIterator first, InputIterator last) #endif //CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO { +#ifdef CGAL_TRIANGULATION_3_PROFILING + WallClockTimer t; +#endif + size_type n = number_of_vertices(); std::vector points (first, last); spatial_sort (points.begin(), points.end(), geom_traits()); - Vertex_handle hint; - for (typename std::vector::const_iterator p = points.begin(), end = points.end(); - p != end; ++p) - hint = insert(*p, hint); + // Parallel +#ifdef CGAL_LINKED_WITH_TBB + if (this->is_parallel()) + { + size_t num_points = points.size(); + + Vertex_handle hint; + std::vector far_sphere_vertices; + +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_ADD_TEMPORARY_POINTS_ON_FAR_SPHERE + const size_t MIN_NUM_POINTS_FOR_FAR_SPHERE_POINTS = 1000000; + if (num_points >= MIN_NUM_POINTS_FOR_FAR_SPHERE_POINTS) + { + // Add temporary vertices on a "far sphere" to reduce contention on + // the infinite vertex + + // Get bbox + const Bbox_3 &bbox = *this->get_bbox(); + // Compute radius for far sphere + const double& xdelta = bbox.xmax() - bbox.xmin(); + const double& ydelta = bbox.ymax() - bbox.ymin(); + const double& zdelta = bbox.zmax() - bbox.zmin(); + const double radius = 1.3 * 0.5 * std::sqrt(xdelta*xdelta + + ydelta*ydelta + + zdelta*zdelta); + const Vector center( + bbox.xmin() + 0.5*xdelta, + bbox.ymin() + 0.5*ydelta, + bbox.zmin() + 0.5*zdelta); + Random_points_on_sphere_3 random_point(radius); + const int NUM_PSEUDO_INFINITE_VERTICES = static_cast( + boost::thread::hardware_concurrency() * 3.5); + std::vector points_on_far_sphere; + for (int i = 0 ; i < NUM_PSEUDO_INFINITE_VERTICES ; ++i, ++random_point) + points_on_far_sphere.push_back(*random_point + center); + + spatial_sort(points_on_far_sphere.begin(), + points_on_far_sphere.end(), + geom_traits()); + + std::vector::const_iterator it_p = points_on_far_sphere.begin(); + std::vector::const_iterator it_p_end = points_on_far_sphere.end(); + for ( ; it_p != it_p_end ; ++it_p) + { + hint = insert(*it_p, hint); + far_sphere_vertices.push_back(hint); + } + } +#endif // CGAL_CONCURRENT_TRIANGULATION_3_ADD_TEMPORARY_POINTS_ON_FAR_SPHERE + + int i = 0; + // Insert "num_points_seq" points sequentially + // (or more if dim < 3 after that) + size_t num_points_seq = (std::min)(num_points, (size_t)100); + while (dimension() < 3 || i < num_points_seq) + { + hint = insert(points[i], hint); + ++i; + } + + tbb::enumerable_thread_specific tls_hint(hint); + tbb::parallel_for( + tbb::blocked_range( i, num_points ), + Insert_point(*this, points, tls_hint) + ); + +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_ADD_TEMPORARY_POINTS_ON_FAR_SPHERE + if (num_points >= MIN_NUM_POINTS_FOR_FAR_SPHERE_POINTS) + { + // Remove the temporary vertices on far sphere + remove(far_sphere_vertices.begin(), far_sphere_vertices.end()); + } +#endif // CGAL_CONCURRENT_TRIANGULATION_3_ADD_TEMPORARY_POINTS_ON_FAR_SPHERE + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + Vertex_handle hint; + for (typename std::vector::const_iterator p = points.begin(), end = points.end(); + p != end; ++p) + hint = insert(*p, hint); + } + +#ifdef CGAL_TRIANGULATION_3_PROFILING + std::cerr << "Triangulation computed in " << t.elapsed() << " seconds." << std::endl; +#endif return number_of_vertices() - n; } - - + + #ifndef CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO -private: +private: //top stands for tuple-or-pair template const Point& top_get_first(const std::pair& pair) const { return pair.first; } @@ -277,7 +410,7 @@ private: } typedef Spatial_sort_traits_adapter_3 Search_traits; - + spatial_sort(indices.begin(),indices.end(),Search_traits(&(points[0]),geom_traits())); Vertex_handle hint; @@ -290,7 +423,7 @@ private: return number_of_vertices() - n; } - + public: template < class InputIterator > @@ -322,24 +455,28 @@ public: return insert_with_info< boost::tuple::type> >(first,last); } #endif //CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO - - Vertex_handle insert(const Point & p, Vertex_handle hint) + + Vertex_handle insert(const Point & p, Vertex_handle hint, + bool *could_lock_zone = NULL) { - return insert(p, hint == Vertex_handle() ? this->infinite_cell() : hint->cell()); + return insert(p, hint == Vertex_handle() ? this->infinite_cell() : hint->cell(), + could_lock_zone); } - Vertex_handle insert(const Point & p, Cell_handle start = Cell_handle()); + Vertex_handle insert(const Point & p, Cell_handle start = Cell_handle(), + bool *could_lock_zone = NULL); Vertex_handle insert(const Point & p, Locate_type lt, - Cell_handle c, int li, int); - + Cell_handle c, int li, int, + bool *could_lock_zone = NULL); + public: // internal methods - + template - Vertex_handle insert_and_give_new_cells(const Point &p, + Vertex_handle insert_and_give_new_cells(const Point &p, OutputItCells fit, Cell_handle start = Cell_handle() ); - + template Vertex_handle insert_and_give_new_cells(const Point& p, OutputItCells fit, @@ -348,14 +485,14 @@ public: // internal methods template Vertex_handle insert_and_give_new_cells(const Point& p, Locate_type lt, - Cell_handle c, int li, int lj, - OutputItCells fit); + Cell_handle c, int li, int lj, + OutputItCells fit); + +public: -public: - #ifndef CGAL_NO_DEPRECATED_CODE CGAL_DEPRECATED Vertex_handle move_point(Vertex_handle v, const Point & p); -#endif +#endif template find_conflicts(const Point &p, Cell_handle c, - OutputIteratorBoundaryFacets bfit, + OutputIteratorBoundaryFacets bfit, OutputIteratorCells cit, - OutputIteratorInternalFacets ifit) const + OutputIteratorInternalFacets ifit, + bool *could_lock_zone = NULL) const { CGAL_triangulation_precondition(dimension() >= 2); @@ -377,33 +515,33 @@ public: if (dimension() == 2) { Conflict_tester_2 tester(p, this); - ifit = Tr_Base::find_conflicts - (c, tester, - make_triple(std::back_inserter(facets), - std::back_inserter(cells), - ifit)).third; + ifit = Tr_Base::find_conflicts + (c, tester, + make_triple(std::back_inserter(facets), + std::back_inserter(cells), + ifit), could_lock_zone).third; } else { Conflict_tester_3 tester(p, this); - ifit = Tr_Base::find_conflicts - (c, tester, - make_triple(std::back_inserter(facets), - std::back_inserter(cells), - ifit)).third; + ifit = Tr_Base::find_conflicts + (c, tester, + make_triple(std::back_inserter(facets), + std::back_inserter(cells), + ifit), could_lock_zone).third; } // Reset the conflict flag on the boundary. for(typename std::vector::iterator fit=facets.begin(); fit != facets.end(); ++fit) { fit->first->neighbor(fit->second)->tds_data().clear(); - *bfit++ = *fit; + *bfit++ = *fit; } // Reset the conflict flag in the conflict cells. for(typename std::vector::iterator ccit=cells.begin(); ccit != cells.end(); ++ccit) { (*ccit)->tds_data().clear(); - *cit++ = *ccit; + *cit++ = *ccit; } return make_triple(bfit, cit, ifit); } @@ -411,13 +549,15 @@ public: template std::pair find_conflicts(const Point &p, Cell_handle c, - OutputIteratorBoundaryFacets bfit, - OutputIteratorCells cit) const + OutputIteratorBoundaryFacets bfit, + OutputIteratorCells cit, + bool *could_lock_zone = NULL) const { Triple t = find_conflicts(p, c, bfit, cit, - Emptyset_iterator()); + Emptyset_iterator> t = find_conflicts(p, c, bfit, cit, + Emptyset_iterator(), + could_lock_zone); return std::make_pair(t.first, t.second); } @@ -442,22 +582,22 @@ public: // Get the facets on the boundary of the hole. std::vector facets; find_conflicts(p, c, std::back_inserter(facets), - Emptyset_iterator(), Emptyset_iterator()); + Emptyset_iterator(), Emptyset_iterator()); // Then extract uniquely the vertices. std::set vertices; if (dimension() == 3) { for (typename std::vector::const_iterator i = facets.begin(); - i != facets.end(); ++i) { - vertices.insert(i->first->vertex((i->second+1)&3)); - vertices.insert(i->first->vertex((i->second+2)&3)); - vertices.insert(i->first->vertex((i->second+3)&3)); + i != facets.end(); ++i) { + vertices.insert(i->first->vertex((i->second+1)&3)); + vertices.insert(i->first->vertex((i->second+2)&3)); + vertices.insert(i->first->vertex((i->second+3)&3)); } } else { for (typename std::vector::const_iterator i = facets.begin(); - i != facets.end(); ++i) { - vertices.insert(i->first->vertex(cw(i->second))); - vertices.insert(i->first->vertex(ccw(i->second))); + i != facets.end(); ++i) { + vertices.insert(i->first->vertex(cw(i->second))); + vertices.insert(i->first->vertex(ccw(i->second))); } } @@ -466,10 +606,13 @@ public: // REMOVE void remove(Vertex_handle v); + // Concurrency-safe + // See Triangulation_3::remove for more information + bool remove(Vertex_handle v, bool *could_lock_zone); // return new cells (internal) template - void remove_and_give_new_cells(Vertex_handle v, + void remove_and_give_new_cells(Vertex_handle v, OutputItCells fit); template < typename InputIterator > @@ -477,13 +620,51 @@ public: { CGAL_triangulation_precondition(!this->does_repeat_in_range(first, beyond)); size_type n = number_of_vertices(); - while (first != beyond) { - remove(*first); - ++first; + +#ifdef CGAL_TRIANGULATION_3_PROFILING + WallClockTimer t; +#endif + + // Parallel +#ifdef CGAL_LINKED_WITH_TBB + if (this->is_parallel()) + { + // TODO: avoid that by asking for random-access iterators? + std::vector vertices(first, beyond); + tbb::concurrent_vector vertices_to_remove_sequentially; + + tbb::parallel_for( + tbb::blocked_range( 0, vertices.size()), + Remove_point(*this, vertices, vertices_to_remove_sequentially) + ); + + // Do the rest sequentially + for ( typename tbb::concurrent_vector::const_iterator + it = vertices_to_remove_sequentially.begin(), + it_end = vertices_to_remove_sequentially.end() + ; it != it_end + ; ++it) + { + remove(*it); + } } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + while (first != beyond) { + remove(*first); + ++first; + } + } + +#ifdef CGAL_TRIANGULATION_3_PROFILING + double elapsed = t.elapsed(); + std::cerr << "Points removed in " << elapsed << " seconds." << std::endl; +#endif return n - number_of_vertices(); } - + template < typename InputIterator > size_type remove_cluster(InputIterator first, InputIterator beyond) { @@ -499,22 +680,22 @@ public: // return new cells (internal) template - Vertex_handle move_if_no_collision_and_give_new_cells(Vertex_handle v, - const Point &p, + Vertex_handle move_if_no_collision_and_give_new_cells(Vertex_handle v, + const Point &p, OutputItCells fit); private: Bounded_side side_of_sphere(Vertex_handle v0, Vertex_handle v1, - Vertex_handle v2, Vertex_handle v3, - const Point &p, bool perturb) const; + Vertex_handle v2, Vertex_handle v3, + const Point &p, bool perturb) const; public: // Queries Bounded_side side_of_sphere(Cell_handle c, const Point & p, - bool perturb = false) const + bool perturb = false) const { return side_of_sphere(c->vertex(0), c->vertex(1), c->vertex(2), c->vertex(3), p, perturb); @@ -528,7 +709,7 @@ public: Bounded_side side_of_circle( Cell_handle c, int i, const Point & p, - bool perturb = false) const; + bool perturb = false) const; Vertex_handle nearest_vertex_in_cell(const Point& p, Cell_handle c) const; @@ -541,7 +722,7 @@ public: bool is_Gabriel(const Facet& f)const ; bool is_Gabriel(const Edge& e) const; - bool is_delaunay_after_displacement(Vertex_handle v, + bool is_delaunay_after_displacement(Vertex_handle v, const Point &p) const; // Dual functions @@ -558,16 +739,16 @@ public: bool is_valid(Cell_handle c, bool verbose = false, int level = 0) const; - template < class Stream> + template < class Stream> Stream& draw_dual(Stream & os) { for (Finite_facets_iterator fit = finite_facets_begin(), end = finite_facets_end(); fit != end; ++fit) { - Object o = dual(*fit); - if (const Segment *s = object_cast(&o)) os << *s; - else if (const Ray *r = object_cast(&o)) os << *r; - else if (const Point *p = object_cast(&o)) os << *p; + Object o = dual(*fit); + if (const Segment *s = object_cast(&o)) os << *s; + else if (const Ray *r = object_cast(&o)) os << *r; + else if (const Point *p = object_cast(&o)) os << *p; } return os; } @@ -581,9 +762,9 @@ protected: CGAL_triangulation_precondition(v != w); if (is_infinite(v)) - return w; + return w; if (is_infinite(w)) - return v; + return v; return less_distance(p, w->point(), v->point()) ? w : v; } @@ -644,7 +825,7 @@ protected: void process_cells_in_conflict(InputIterator, InputIterator) const {} void reinsert_vertices(Vertex_handle ) {} Vertex_handle replace_vertex(Cell_handle c, int index, - const Point &) { + const Point &) { return c->vertex(index); } void hide_point(Cell_handle, const Point &) {} @@ -655,13 +836,137 @@ protected: public: Perturbation_order(const Self *tr) - : t(tr) {} + : t(tr) {} bool operator()(const Point *p, const Point *q) const { - return t->compare_xyz(*p, *q) == SMALLER; + return t->compare_xyz(*p, *q) == SMALLER; } }; +#ifdef CGAL_LINKED_WITH_TBB + // Functor for parallel insert(begin, end) function + template + class Insert_point + { + typedef typename DT::Point Point; + typedef typename DT::Vertex_handle Vertex_handle; + + DT & m_dt; + const std::vector & m_points; + tbb::enumerable_thread_specific & m_tls_hint; + + public: + // Constructor + Insert_point(DT & dt, + const std::vector & points, + tbb::enumerable_thread_specific & tls_hint) + : m_dt(dt), m_points(points), m_tls_hint(tls_hint) + {} + + // Constructor + Insert_point(const Insert_point &ip) + : m_dt(ip.m_dt), m_points(ip.m_points), m_tls_hint(ip.m_tls_hint) + {} + + // operator() + void operator()( const tbb::blocked_range& r ) const + { +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + static Profile_branch_counter_3 bcounter( + "early withdrawals / late withdrawals / successes [Delaunay_tri_3::insert]"); +#endif + + Vertex_handle &hint = m_tls_hint.local(); + for( std::size_t i_point = r.begin() ; i_point != r.end() ; ++i_point) + { + bool success = false; + while(!success) + { + if (m_dt.try_lock_vertex(hint) && m_dt.try_lock_point(m_points[i_point])) + { + bool could_lock_zone; + Vertex_handle new_hint = m_dt.insert( + m_points[i_point], hint, &could_lock_zone); + + m_dt.unlock_all_elements(); + + if (could_lock_zone) + { + hint = new_hint; + success = true; +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + ++bcounter; +#endif + } +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + else + { + bcounter.increment_branch_1(); // THIS is a late withdrawal! + } +#endif + } + else + { + m_dt.unlock_all_elements(); + +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + bcounter.increment_branch_2(); // THIS is an early withdrawal! +#endif + } + } + + } + } + }; + + // Functor for parallel remove(begin, end) function + template + class Remove_point + { + typedef typename DT::Point Point; + typedef typename DT::Vertex_handle Vertex_handle; + + DT & m_dt; + const std::vector & m_vertices; + tbb::concurrent_vector & m_vertices_to_remove_sequentially; + + public: + // Constructor + Remove_point(DT & dt, + const std::vector & vertices, + tbb::concurrent_vector & + vertices_to_remove_sequentially) + : m_dt(dt), m_vertices(vertices), + m_vertices_to_remove_sequentially(vertices_to_remove_sequentially) + {} + + // Constructor + Remove_point(const Remove_point &rp) + : m_dt(rp.m_dt), m_vertices(rp.m_vertices), + m_vertices_to_remove_sequentially(rp.m_vertices_to_remove_sequentially) + {} + + // operator() + void operator()( const tbb::blocked_range& r ) const + { + for( size_t i_vertex = r.begin() ; i_vertex != r.end() ; ++i_vertex) + { + Vertex_handle v = m_vertices[i_vertex]; + bool could_lock_zone, needs_to_be_done_sequentially; + do + { + needs_to_be_done_sequentially = + !m_dt.remove(v, &could_lock_zone); + m_dt.unlock_all_elements(); + } while (!could_lock_zone); + + if (needs_to_be_done_sequentially) + m_vertices_to_remove_sequentially.push_back(v); + } + } + }; +#endif // CGAL_LINKED_WITH_TBB + template < class DelaunayTriangulation_3 > class Vertex_remover; @@ -675,35 +980,51 @@ protected: Hidden_point_visitor hidden_point_visitor; }; -template < class Gt, class Tds > -typename Delaunay_triangulation_3::Vertex_handle -Delaunay_triangulation_3:: -insert(const Point & p, Cell_handle start) +template < class Gt, class Tds, class Lds > +typename Delaunay_triangulation_3::Vertex_handle +Delaunay_triangulation_3:: +insert(const Point & p, Cell_handle start, bool *could_lock_zone) { - Locate_type lt; - int li, lj; + Locate_type lt; + int li, lj; + + // Parallel + if (could_lock_zone) + { + Cell_handle c = locate(p, lt, li, lj, start, could_lock_zone); + if (*could_lock_zone) + return insert(p, lt, c, li, lj, could_lock_zone); + else + return Vertex_handle(); + } + // Sequential + else + { Cell_handle c = locate(p, lt, li, lj, start); return insert(p, lt, c, li, lj); + } + } -template < class Gt, class Tds > -typename Delaunay_triangulation_3::Vertex_handle -Delaunay_triangulation_3:: -insert(const Point & p, Locate_type lt, Cell_handle c, int li, int lj) +template < class Gt, class Tds, class Lds > +typename Delaunay_triangulation_3::Vertex_handle +Delaunay_triangulation_3:: +insert(const Point & p, Locate_type lt, Cell_handle c, int li, int lj, + bool *could_lock_zone) { switch (dimension()) { case 3: { Conflict_tester_3 tester(p, this); Vertex_handle v = insert_in_conflict(p, lt, c, li, lj, - tester, hidden_point_visitor); + tester, hidden_point_visitor, could_lock_zone); return v; }// dim 3 case 2: { Conflict_tester_2 tester(p, this); return insert_in_conflict(p, lt, c, li, lj, - tester, hidden_point_visitor); + tester, hidden_point_visitor, could_lock_zone); }//dim 2 default : // dimension <= 1 @@ -712,11 +1033,11 @@ insert(const Point & p, Locate_type lt, Cell_handle c, int li, int lj) } } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > template -typename Delaunay_triangulation_3::Vertex_handle -Delaunay_triangulation_3:: -insert_and_give_new_cells(const Point &p, +typename Delaunay_triangulation_3::Vertex_handle +Delaunay_triangulation_3:: +insert_and_give_new_cells(const Point &p, OutputItCells fit, Cell_handle start) { @@ -730,8 +1051,8 @@ insert_and_give_new_cells(const Point &p, *fit++ = c; int i = c->index(v); c = c->neighbor((i+1)%3); - } while(c != end); - } + } while(c != end); + } else if(dimension == 1) { Cell_handle c = v->cell(); @@ -739,13 +1060,13 @@ insert_and_give_new_cells(const Point &p, *fit++ = c->neighbor((~(c->index(v)))&1); } else *fit++ = v->cell(); // dimension = 0 - return v; + return v; } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > template -typename Delaunay_triangulation_3::Vertex_handle -Delaunay_triangulation_3:: +typename Delaunay_triangulation_3::Vertex_handle +Delaunay_triangulation_3:: insert_and_give_new_cells(const Point& p, OutputItCells fit, Vertex_handle hint) @@ -760,8 +1081,8 @@ insert_and_give_new_cells(const Point& p, *fit++ = c; int i = c->index(v); c = c->neighbor((i+1)%3); - } while(c != end); - } + } while(c != end); + } else if(dimension == 1) { Cell_handle c = v->cell(); @@ -772,13 +1093,13 @@ insert_and_give_new_cells(const Point& p, return v; } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > template -typename Delaunay_triangulation_3::Vertex_handle -Delaunay_triangulation_3:: +typename Delaunay_triangulation_3::Vertex_handle +Delaunay_triangulation_3:: insert_and_give_new_cells(const Point& p, Locate_type lt, - Cell_handle c, int li, int lj, + Cell_handle c, int li, int lj, OutputItCells fit) { Vertex_handle v = insert(p, lt, c, li, lj); @@ -791,22 +1112,22 @@ insert_and_give_new_cells(const Point& p, *fit++ = c; int i = c->index(v); c = c->neighbor((i+1)%3); - } while(c != end); - } + } while(c != end); + } else if(dimension == 1) { Cell_handle c = v->cell(); *fit++ = c; *fit++ = c->neighbor((~(c->index(v)))&1); } - else *fit++ = v->cell(); // dimension = 0 + else *fit++ = v->cell(); // dimension = 0 return v; } #ifndef CGAL_NO_DEPRECATED_CODE -template < class Gt, class Tds > -typename Delaunay_triangulation_3::Vertex_handle -Delaunay_triangulation_3:: +template < class Gt, class Tds, class Lds > +typename Delaunay_triangulation_3::Vertex_handle +Delaunay_triangulation_3:: move_point(Vertex_handle v, const Point & p) { CGAL_triangulation_precondition(! is_infinite(v)); @@ -823,14 +1144,14 @@ move_point(Vertex_handle v, const Point & p) remove(v); if (dimension() <= 0) - return insert(p); + return insert(p); return insert(p, old_neighbor->cell()); } #endif -template +template template -class Delaunay_triangulation_3::Vertex_remover { +class Delaunay_triangulation_3::Vertex_remover { typedef DelaunayTriangulation_3 Delaunay; public: typedef Nullptr_t Hidden_points_iterator; @@ -849,9 +1170,9 @@ public: } }; -template +template template -class Delaunay_triangulation_3::Vertex_inserter { +class Delaunay_triangulation_3::Vertex_inserter { typedef DelaunayTriangulation_3 Delaunay; public: typedef Nullptr_t Hidden_points_iterator; @@ -865,7 +1186,7 @@ public: Hidden_points_iterator hidden_points_end() { return NULL; } Vertex_handle insert(const Point& p, - Locate_type lt, Cell_handle c, int li, int lj) { + Locate_type lt, Cell_handle c, int li, int lj) { return tmp.insert(p, lt, c, li, lj); } @@ -878,21 +1199,34 @@ public: } }; -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > void -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: remove(Vertex_handle v) { Self tmp; Vertex_remover remover (tmp); - Tr_Base::remove(v,remover); + Tr_Base::remove(v, remover); CGAL_triangulation_expensive_postcondition(is_valid()); } -template < class Gt, class Tds > -typename Delaunay_triangulation_3::Vertex_handle -Delaunay_triangulation_3:: +template < class Gt, class Tds, class Lds > +bool +Delaunay_triangulation_3:: +remove(Vertex_handle v, bool *could_lock_zone) +{ + Self tmp; + Vertex_remover remover (tmp); + bool ret = Tr_Base::remove(v, remover, could_lock_zone); + + CGAL_triangulation_expensive_postcondition(is_valid()); + return ret; +} + +template < class Gt, class Tds, class Lds > +typename Delaunay_triangulation_3::Vertex_handle +Delaunay_triangulation_3:: move_if_no_collision(Vertex_handle v, const Point &p) { Self tmp; @@ -900,26 +1234,26 @@ move_if_no_collision(Vertex_handle v, const Point &p) Vertex_inserter inserter (*this); Vertex_handle res = Tr_Base::move_if_no_collision(v,p,remover,inserter); - CGAL_triangulation_expensive_postcondition(is_valid()); - return res; + CGAL_triangulation_expensive_postcondition(is_valid()); + return res; } -template -typename Delaunay_triangulation_3::Vertex_handle -Delaunay_triangulation_3:: +template +typename Delaunay_triangulation_3::Vertex_handle +Delaunay_triangulation_3:: move(Vertex_handle v, const Point &p) { CGAL_triangulation_precondition(!is_infinite(v)); if(v->point() == p) return v; Self tmp; Vertex_remover remover (tmp); Vertex_inserter inserter (*this); - return Tr_Base::move(v,p,remover,inserter); + return Tr_Base::move(v,p,remover,inserter); } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > template void -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: remove_and_give_new_cells(Vertex_handle v, OutputItCells fit) { Self tmp; @@ -929,37 +1263,37 @@ remove_and_give_new_cells(Vertex_handle v, OutputItCells fit) CGAL_triangulation_expensive_postcondition(is_valid()); } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > template -typename Delaunay_triangulation_3::Vertex_handle -Delaunay_triangulation_3:: +typename Delaunay_triangulation_3::Vertex_handle +Delaunay_triangulation_3:: move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, OutputItCells fit) { Self tmp; Vertex_remover remover (tmp); Vertex_inserter inserter (*this); - Vertex_handle res = + Vertex_handle res = Tr_Base::move_if_no_collision_and_give_new_cells(v,p, remover,inserter,fit); - CGAL_triangulation_expensive_postcondition(is_valid()); - return res; + CGAL_triangulation_expensive_postcondition(is_valid()); + return res; } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > Oriented_side -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: side_of_oriented_sphere(const Point &p0, const Point &p1, const Point &p2, - const Point &p3, const Point &p, bool perturb) const + const Point &p3, const Point &p, bool perturb) const { CGAL_triangulation_precondition( orientation(p0, p1, p2, p3) == POSITIVE ); Oriented_side os = - geom_traits().side_of_oriented_sphere_3_object()(p0, p1, p2, p3, p); + geom_traits().side_of_oriented_sphere_3_object()(p0, p1, p2, p3, p); if (os != ON_ORIENTED_BOUNDARY || !perturb) - return os; + return os; // We are now in a degenerate case => we do a symbolic perturbation. @@ -973,7 +1307,7 @@ side_of_oriented_sphere(const Point &p0, const Point &p1, const Point &p2, for (int i=4; i>2; --i) { if (points[i] == &p) return ON_NEGATIVE_SIDE; // since p0 p1 p2 p3 are non coplanar - // and positively oriented + // and positively oriented Orientation o; if (points[i] == &p3 && (o = orientation(p0,p1,p2,p)) != COPLANAR ) return o; @@ -989,21 +1323,21 @@ side_of_oriented_sphere(const Point &p0, const Point &p1, const Point &p2, return ON_NEGATIVE_SIDE; } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > Bounded_side -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: coplanar_side_of_bounded_circle(const Point &p0, const Point &p1, - const Point &p2, const Point &p, bool perturb) const + const Point &p2, const Point &p, bool perturb) const { // In dim==2, we should even be able to assert orient == POSITIVE. CGAL_triangulation_precondition( coplanar_orientation(p0, p1, p2) - != COLLINEAR ); + != COLLINEAR ); Bounded_side bs = geom_traits().coplanar_side_of_bounded_circle_3_object()(p0, p1, p2, p); if (bs != ON_BOUNDARY || !perturb) - return bs; + return bs; // We are now in a degenerate case => we do a symbolic perturbation. @@ -1019,17 +1353,17 @@ coplanar_side_of_bounded_circle(const Point &p0, const Point &p1, for (int i=3; i>0; --i) { if (points[i] == &p) return Bounded_side(NEGATIVE); // since p0 p1 p2 are non collinear - // but not necessarily positively oriented + // but not necessarily positively oriented Orientation o; if (points[i] == &p2 - && (o = coplanar_orientation(p0,p1,p)) != COLLINEAR ) - // [syl] : TODO : I'm not sure of the signs here (nor the rest :) + && (o = coplanar_orientation(p0,p1,p)) != COLLINEAR ) + // [syl] : TODO : I'm not sure of the signs here (nor the rest :) return Bounded_side(o*local); if (points[i] == &p1 - && (o = coplanar_orientation(p0,p,p2)) != COLLINEAR ) + && (o = coplanar_orientation(p0,p,p2)) != COLLINEAR ) return Bounded_side(o*local); if (points[i] == &p0 - && (o = coplanar_orientation(p,p1,p2)) != COLLINEAR ) + && (o = coplanar_orientation(p,p1,p2)) != COLLINEAR ) return Bounded_side(o*local); } @@ -1042,51 +1376,51 @@ coplanar_side_of_bounded_circle(const Point &p0, const Point &p1, return Bounded_side(-local); //ON_UNBOUNDED_SIDE; } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > Bounded_side -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: side_of_sphere(Vertex_handle v0, Vertex_handle v1, - Vertex_handle v2, Vertex_handle v3, - const Point &p, bool perturb) const + Vertex_handle v2, Vertex_handle v3, + const Point &p, bool perturb) const { CGAL_triangulation_precondition( dimension() == 3 ); if (is_infinite(v0)) { - Orientation o = orientation(v2->point(), v1->point(), v3->point(), p); - if (o != COPLANAR) - return Bounded_side(o); - return coplanar_side_of_bounded_circle(v2->point(), v1->point(), v3->point(), p, perturb); + Orientation o = orientation(v2->point(), v1->point(), v3->point(), p); + if (o != COPLANAR) + return Bounded_side(o); + return coplanar_side_of_bounded_circle(v2->point(), v1->point(), v3->point(), p, perturb); } if (is_infinite(v1)) { - Orientation o = orientation(v2->point(), v3->point(), v0->point(), p); - if (o != COPLANAR) - return Bounded_side(o); - return coplanar_side_of_bounded_circle(v2->point(), v3->point(), v0->point(), p, perturb); + Orientation o = orientation(v2->point(), v3->point(), v0->point(), p); + if (o != COPLANAR) + return Bounded_side(o); + return coplanar_side_of_bounded_circle(v2->point(), v3->point(), v0->point(), p, perturb); } if (is_infinite(v2)) { - Orientation o = orientation(v1->point(), v0->point(), v3->point(), p); - if (o != COPLANAR) - return Bounded_side(o); - return coplanar_side_of_bounded_circle(v1->point(), v0->point(), v3->point(), p, perturb); + Orientation o = orientation(v1->point(), v0->point(), v3->point(), p); + if (o != COPLANAR) + return Bounded_side(o); + return coplanar_side_of_bounded_circle(v1->point(), v0->point(), v3->point(), p, perturb); } if (is_infinite(v3)) { - Orientation o = orientation(v0->point(), v1->point(), v2->point(), p); - if (o != COPLANAR) - return Bounded_side(o); - return coplanar_side_of_bounded_circle(v0->point(), v1->point(), v2->point(), p, perturb); + Orientation o = orientation(v0->point(), v1->point(), v2->point(), p); + if (o != COPLANAR) + return Bounded_side(o); + return coplanar_side_of_bounded_circle(v0->point(), v1->point(), v2->point(), p, perturb); } return (Bounded_side) side_of_oriented_sphere(v0->point(), v1->point(), v2->point(), v3->point(), p, perturb); } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > Bounded_side -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: side_of_circle(Cell_handle c, int i, - const Point & p, bool perturb) const + const Point & p, bool perturb) const // precondition : dimension >=2 // in dimension 3, - for a finite facet // returns ON_BOUNDARY if the point lies on the circle, @@ -1110,27 +1444,27 @@ side_of_circle(Cell_handle c, int i, // with vertices 0 1 2 in this order is positively oriented if ( ! c->has_vertex( infinite_vertex(), i3 ) ) return coplanar_side_of_bounded_circle( c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point(), - p, perturb); + c->vertex(1)->point(), + c->vertex(2)->point(), + p, perturb); // else infinite facet // v1, v2 finite vertices of the facet such that v1,v2,infinite // is positively oriented Vertex_handle v1 = c->vertex( ccw(i3) ), v2 = c->vertex( cw(i3) ); CGAL_triangulation_assertion(coplanar_orientation(v1->point(), v2->point(), - mirror_vertex(c, i3)->point()) == NEGATIVE); + mirror_vertex(c, i3)->point()) == NEGATIVE); Orientation o = coplanar_orientation(v1->point(), v2->point(), p); if ( o != COLLINEAR ) - return Bounded_side( o ); + return Bounded_side( o ); // because p is in f iff // it does not lie on the same side of v1v2 as vn int i_e; Locate_type lt; // case when p collinear with v1v2 return side_of_segment( p, - v1->point(), v2->point(), - lt, i_e ); + v1->point(), v2->point(), + lt, i_e ); } // else dimension == 3 @@ -1143,13 +1477,13 @@ side_of_circle(Cell_handle c, int i, int i1 = (i>1) ? 1 : 2; int i2 = (i>2) ? 2 : 3; CGAL_triangulation_precondition( coplanar( c->vertex(i0)->point(), - c->vertex(i1)->point(), - c->vertex(i2)->point(), - p ) ); + c->vertex(i1)->point(), + c->vertex(i2)->point(), + p ) ); return coplanar_side_of_bounded_circle( c->vertex(i0)->point(), - c->vertex(i1)->point(), - c->vertex(i2)->point(), - p, perturb); + c->vertex(i1)->point(), + c->vertex(i2)->point(), + p, perturb); } //else infinite facet @@ -1159,7 +1493,7 @@ side_of_circle(Cell_handle c, int i, v2 = c->vertex( next_around_edge(i,i3) ); Orientation o = (Orientation) (coplanar_orientation( v1->point(), v2->point(), - c->vertex(i)->point()) * + c->vertex(i)->point()) * coplanar_orientation( v1->point(), v2->point(), p )); // then the code is duplicated from 2d case if ( o != COLLINEAR ) @@ -1170,13 +1504,13 @@ side_of_circle(Cell_handle c, int i, Locate_type lt; // case when p collinear with v1v2 return side_of_segment( p, - v1->point(), v2->point(), - lt, i_e ); + v1->point(), v2->point(), + lt, i_e ); } -template < class Gt, class Tds > -typename Delaunay_triangulation_3::Vertex_handle -Delaunay_triangulation_3:: +template < class Gt, class Tds, class Lds > +typename Delaunay_triangulation_3::Vertex_handle +Delaunay_triangulation_3:: nearest_vertex_in_cell(const Point& p, Cell_handle c) const // Returns the finite vertex of the cell c which is the closest to p. { @@ -1184,36 +1518,36 @@ nearest_vertex_in_cell(const Point& p, Cell_handle c) const Vertex_handle nearest = nearest_vertex(p, c->vertex(0), c->vertex(1)); if (dimension() >= 2) { - nearest = nearest_vertex(p, nearest, c->vertex(2)); + nearest = nearest_vertex(p, nearest, c->vertex(2)); if (dimension() == 3) - nearest = nearest_vertex(p, nearest, c->vertex(3)); + nearest = nearest_vertex(p, nearest, c->vertex(3)); } return nearest; } -template < class Gt, class Tds > -typename Delaunay_triangulation_3::Vertex_handle -Delaunay_triangulation_3:: +template < class Gt, class Tds, class Lds > +typename Delaunay_triangulation_3::Vertex_handle +Delaunay_triangulation_3:: nearest_vertex(const Point& p, Cell_handle start) const { if (number_of_vertices() == 0) - return Vertex_handle(); + return Vertex_handle(); // Use a brute-force algorithm if dimension < 3. if (dimension() < 3) { - Finite_vertices_iterator vit = finite_vertices_begin(); - Vertex_handle res = vit; - ++vit; - for (Finite_vertices_iterator end = finite_vertices_end(); vit != end; ++vit) - res = nearest_vertex(p, res, vit); - return res; + Finite_vertices_iterator vit = finite_vertices_begin(); + Vertex_handle res = vit; + ++vit; + for (Finite_vertices_iterator end = finite_vertices_end(); vit != end; ++vit) + res = nearest_vertex(p, res, vit); + return res; } Locate_type lt; int li, lj; Cell_handle c = locate(p, lt, li, lj, start); if (lt == Tr_Base::VERTEX) - return c->vertex(li); + return c->vertex(li); // - start with the closest vertex from the located cell. // - repeatedly take the nearest of its incident vertices if any @@ -1222,36 +1556,36 @@ nearest_vertex(const Point& p, Cell_handle start) const std::vector vs; vs.reserve(32); while (true) { - Vertex_handle tmp = nearest; + Vertex_handle tmp = nearest; adjacent_vertices(nearest, std::back_inserter(vs)); for (typename std::vector::const_iterator - vsit = vs.begin(); vsit != vs.end(); ++vsit) - tmp = nearest_vertex(p, tmp, *vsit); - if (tmp == nearest) - break; - vs.clear(); - nearest = tmp; + vsit = vs.begin(); vsit != vs.end(); ++vsit) + tmp = nearest_vertex(p, tmp, *vsit); + if (tmp == nearest) + break; + vs.clear(); + nearest = tmp; } return nearest; } // This is not a fast version. -// The optimized version needs an int for book-keeping in +// The optimized version needs an int for book-keeping in // tds() so as to avoiding the need to clear // the tds marker in each cell (which is an unsigned char) // Also the visitor in TDS could be more clever. // The Delaunay triangulation which filters displacements -// will do these optimizations. -template -bool -Delaunay_triangulation_3:: +// will do these optimizations. +template +bool +Delaunay_triangulation_3:: is_delaunay_after_displacement(Vertex_handle v, const Point &p) const { - CGAL_triangulation_precondition(!this->is_infinite(v)); - CGAL_triangulation_precondition(this->dimension() == 2); + CGAL_triangulation_precondition(!this->is_infinite(v)); + CGAL_triangulation_precondition(this->dimension() == 2); CGAL_triangulation_precondition(!this->test_dim_down(v)); - if(v->point() == p) return true; + if(v->point() == p) return true; Point ant = v->point(); v->set_point(p); @@ -1266,18 +1600,18 @@ is_delaunay_after_displacement(Vertex_handle v, const Point &p) const { Cell_handle c = cells[i]; if(this->is_infinite(c)) continue; - if(this->orientation(c->vertex(0)->point(), c->vertex(1)->point(), - c->vertex(2)->point(), c->vertex(3)->point()) + if(this->orientation(c->vertex(0)->point(), c->vertex(1)->point(), + c->vertex(2)->point(), c->vertex(3)->point()) != POSITIVE) { v->set_point(ant); return false; - } + } } - // are incident bi-cells Delaunay? + // are incident bi-cells Delaunay? std::vector facets; - facets.reserve(128); + facets.reserve(128); this->incident_facets(v, std::back_inserter(facets)); size = facets.size(); for(std::size_t i=0; imirror_index(c, j); Vertex_handle h1 = c->vertex(j); if(this->is_infinite(h1)) { - if(this->side_of_sphere(c, cj->vertex(mj)->point(), true) + if(this->side_of_sphere(c, cj->vertex(mj)->point(), true) != ON_UNBOUNDED_SIDE) { v->set_point(ant); return false; @@ -1301,22 +1635,22 @@ is_delaunay_after_displacement(Vertex_handle v, const Point &p) const } } } - + v->set_point(ant); return true; } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > bool -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: is_Gabriel(const Facet& f) const { return is_Gabriel(f.first, f.second); } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > bool -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: is_Gabriel(Cell_handle c, int i) const { CGAL_triangulation_precondition(dimension() == 3 && !is_infinite(c,i)); @@ -1326,34 +1660,34 @@ is_Gabriel(Cell_handle c, int i) const if ((!is_infinite(c->vertex(i))) && side_of_bounded_sphere ( - c->vertex(vertex_triple_index(i,0))->point(), - c->vertex(vertex_triple_index(i,1))->point(), - c->vertex(vertex_triple_index(i,2))->point(), - c->vertex(i)->point()) == ON_BOUNDED_SIDE ) return false; + c->vertex(vertex_triple_index(i,0))->point(), + c->vertex(vertex_triple_index(i,1))->point(), + c->vertex(vertex_triple_index(i,2))->point(), + c->vertex(i)->point()) == ON_BOUNDED_SIDE ) return false; Cell_handle neighbor = c->neighbor(i); int in = neighbor->index(c); if ((!is_infinite(neighbor->vertex(in))) && side_of_bounded_sphere( - c->vertex(vertex_triple_index(i,0))->point(), - c->vertex(vertex_triple_index(i,1))->point(), - c->vertex(vertex_triple_index(i,2))->point(), - neighbor->vertex(in)->point()) == ON_BOUNDED_SIDE ) return false; + c->vertex(vertex_triple_index(i,0))->point(), + c->vertex(vertex_triple_index(i,1))->point(), + c->vertex(vertex_triple_index(i,2))->point(), + neighbor->vertex(in)->point()) == ON_BOUNDED_SIDE ) return false; return true; } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > bool -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: is_Gabriel(const Edge& e) const { return is_Gabriel(e.first, e.second, e.third); } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > bool -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: is_Gabriel(Cell_handle c, int i, int j) const { CGAL_triangulation_precondition(dimension() == 3 && !is_infinite(c,i,j)); @@ -1371,17 +1705,17 @@ is_Gabriel(Cell_handle c, int i, int j) const Cell_handle cc = (*fcirc).first; int ii = (*fcirc).second; if (!is_infinite(cc->vertex(ii)) && - side_of_bounded_sphere( v1->point(), - v2->point(), - cc->vertex(ii)->point()) - == ON_BOUNDED_SIDE ) return false; + side_of_bounded_sphere( v1->point(), + v2->point(), + cc->vertex(ii)->point()) + == ON_BOUNDED_SIDE ) return false; } while(++fcirc != fdone); return true; } -template < class Gt, class Tds > -typename Delaunay_triangulation_3::Point -Delaunay_triangulation_3:: +template < class Gt, class Tds, class Lds > +typename Delaunay_triangulation_3::Point +Delaunay_triangulation_3:: dual(Cell_handle c) const { CGAL_triangulation_precondition(dimension()==3); @@ -1390,9 +1724,9 @@ dual(Cell_handle c) const } -template < class Gt, class Tds > -typename Delaunay_triangulation_3::Object -Delaunay_triangulation_3:: +template < class Gt, class Tds, class Lds > +typename Delaunay_triangulation_3::Object +Delaunay_triangulation_3:: dual(Cell_handle c, int i) const { CGAL_triangulation_precondition(dimension()>=2); @@ -1401,8 +1735,8 @@ dual(Cell_handle c, int i) const if ( dimension() == 2 ) { CGAL_triangulation_precondition( i == 3 ); return construct_object( construct_circumcenter(c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point()) ); + c->vertex(1)->point(), + c->vertex(2)->point()) ); } // dimension() == 3 @@ -1436,9 +1770,9 @@ dual(Cell_handle c, int i) const -template < class Gt, class Tds > -typename Delaunay_triangulation_3::Line -Delaunay_triangulation_3:: +template < class Gt, class Tds, class Lds > +typename Delaunay_triangulation_3::Line +Delaunay_triangulation_3:: dual_support(Cell_handle c, int i) const { CGAL_triangulation_precondition(dimension()>=2); @@ -1447,31 +1781,31 @@ dual_support(Cell_handle c, int i) const if ( dimension() == 2 ) { CGAL_triangulation_precondition( i == 3 ); return construct_equidistant_line( c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point() ); + c->vertex(1)->point(), + c->vertex(2)->point() ); } return construct_equidistant_line( c->vertex((i+1)&3)->point(), - c->vertex((i+2)&3)->point(), - c->vertex((i+3)&3)->point() ); + c->vertex((i+2)&3)->point(), + c->vertex((i+3)&3)->point() ); } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > bool -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: is_valid(bool verbose, int level) const { if ( ! tds().is_valid(verbose,level) ) { if (verbose) - std::cerr << "invalid data structure" << std::endl; + std::cerr << "invalid data structure" << std::endl; CGAL_triangulation_assertion(false); return false; } if ( infinite_vertex() == Vertex_handle() ) { if (verbose) - std::cerr << "no infinite vertex" << std::endl; + std::cerr << "no infinite vertex" << std::endl; CGAL_triangulation_assertion(false); return false; } @@ -1480,51 +1814,51 @@ is_valid(bool verbose, int level) const case 3: { for(Finite_cells_iterator it = finite_cells_begin(), end = finite_cells_end(); it != end; ++it) { - is_valid_finite(it); - for(int i=0; i<4; i++ ) { - if ( !is_infinite - (it->neighbor(i)->vertex(it->neighbor(i)->index(it))) ) { - if ( side_of_sphere - (it, - it->neighbor(i)->vertex(it->neighbor(i)->index(it))->point()) - == ON_BOUNDED_SIDE ) { - if (verbose) - std::cerr << "non-empty sphere " << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } - } + is_valid_finite(it); + for(int i=0; i<4; i++ ) { + if ( !is_infinite + (it->neighbor(i)->vertex(it->neighbor(i)->index(it))) ) { + if ( side_of_sphere + (it, + it->neighbor(i)->vertex(it->neighbor(i)->index(it))->point()) + == ON_BOUNDED_SIDE ) { + if (verbose) + std::cerr << "non-empty sphere " << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + } + } } break; } case 2: { for(Finite_facets_iterator it = finite_facets_begin(), end = finite_facets_end(); it != end; ++it) { - is_valid_finite((*it).first); - for(int i=0; i<3; i++ ) { - if( !is_infinite - ((*it).first->neighbor(i)->vertex( (((*it).first)->neighbor(i)) - ->index((*it).first))) ) { - if ( side_of_circle ( (*it).first, 3, - (*it).first->neighbor(i)-> - vertex( (((*it).first)->neighbor(i)) - ->index((*it).first) )->point() ) - == ON_BOUNDED_SIDE ) { - if (verbose) - std::cerr << "non-empty circle " << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } - } + is_valid_finite((*it).first); + for(int i=0; i<3; i++ ) { + if( !is_infinite + ((*it).first->neighbor(i)->vertex( (((*it).first)->neighbor(i)) + ->index((*it).first))) ) { + if ( side_of_circle ( (*it).first, 3, + (*it).first->neighbor(i)-> + vertex( (((*it).first)->neighbor(i)) + ->index((*it).first) )->point() ) + == ON_BOUNDED_SIDE ) { + if (verbose) + std::cerr << "non-empty circle " << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + } + } } break; } case 1: { for(Finite_edges_iterator it = finite_edges_begin(), end = finite_edges_end(); it != end; ++it) - is_valid_finite((*it).first); + is_valid_finite((*it).first); break; } } @@ -1533,16 +1867,16 @@ is_valid(bool verbose, int level) const return true; } -template < class Gt, class Tds > +template < class Gt, class Tds, class Lds > bool -Delaunay_triangulation_3:: +Delaunay_triangulation_3:: is_valid(Cell_handle c, bool verbose, int level) const { if ( ! Tr_Base::is_valid(c,verbose,level) ) { if (verbose) { std::cerr << "combinatorically invalid cell" ; for (int i=0; i <= dimension(); i++ ) - std::cerr << c->vertex(i)->point() << ", " ; + std::cerr << c->vertex(i)->point() << ", " ; std::cerr << std::endl; } CGAL_triangulation_assertion(false); @@ -1552,31 +1886,31 @@ is_valid(Cell_handle c, bool verbose, int level) const case 3: { if ( ! is_infinite(c) ) { - is_valid_finite(c,verbose,level); - for (int i=0; i<4; i++ ) { - if (side_of_sphere(c, c->vertex((c->neighbor(i))->index(c))->point()) - == ON_BOUNDED_SIDE ) { - if (verbose) - std::cerr << "non-empty sphere " << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } + is_valid_finite(c,verbose,level); + for (int i=0; i<4; i++ ) { + if (side_of_sphere(c, c->vertex((c->neighbor(i))->index(c))->point()) + == ON_BOUNDED_SIDE ) { + if (verbose) + std::cerr << "non-empty sphere " << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + } } break; } case 2: { if ( ! is_infinite(c,3) ) { - for (int i=0; i<2; i++ ) { - if (side_of_circle(c, 3, c->vertex(c->neighbor(i)->index(c))->point()) - == ON_BOUNDED_SIDE ) { - if (verbose) - std::cerr << "non-empty circle " << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } + for (int i=0; i<2; i++ ) { + if (side_of_circle(c, 3, c->vertex(c->neighbor(i)->index(c))->point()) + == ON_BOUNDED_SIDE ) { + if (verbose) + std::cerr << "non-empty circle " << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + } } break; } diff --git a/Triangulation_3/include/CGAL/Regular_triangulation_3.h b/Triangulation_3/include/CGAL/Regular_triangulation_3.h index f6e3ed96418..0fdc112d163 100644 --- a/Triangulation_3/include/CGAL/Regular_triangulation_3.h +++ b/Triangulation_3/include/CGAL/Regular_triangulation_3.h @@ -19,6 +19,7 @@ // Author(s) : Monique Teillaud // Sylvain Pion // Christophe Delage +// Clement Jamin #ifndef CGAL_REGULAR_TRIANGULATION_3_H #define CGAL_REGULAR_TRIANGULATION_3_H @@ -26,6 +27,9 @@ #include #include +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif #include #include @@ -38,6 +42,9 @@ #include #include #endif //CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO +#ifdef CGAL_TRIANGULATION_3_PROFILING +# include +#endif #if defined(BOOST_MSVC) # pragma warning(push) @@ -46,269 +53,403 @@ namespace CGAL { -template < class Gt, class Tds_ = Default > -class Regular_triangulation_3 - : public Triangulation_3, - Regular_triangulation_cell_base_3 > >::type> -{ - typedef Regular_triangulation_3 Self; + /************************************************ + * + * Regular_triangulation_3 class + * + ************************************************/ - typedef typename Default::Get, - Regular_triangulation_cell_base_3 > >::type Tds; + template < class Gt, class Tds_ = Default, class Lock_data_structure_ = Default > + class Regular_triangulation_3 + : public Triangulation_3< + Gt, + typename Default::Get, + Regular_triangulation_cell_base_3 > >::type, + Lock_data_structure_> + { + typedef Regular_triangulation_3 Self; - typedef Triangulation_3 Tr_Base; + typedef typename Default::Get, + Regular_triangulation_cell_base_3 > >::type Tds; -public: + typedef Triangulation_3 Tr_Base; - typedef Tds Triangulation_data_structure; - typedef Gt Geom_traits; + public: - typedef typename Tr_Base::Vertex_handle Vertex_handle; - typedef typename Tr_Base::Cell_handle Cell_handle; - typedef typename Tr_Base::Vertex Vertex; - typedef typename Tr_Base::Cell Cell; - typedef typename Tr_Base::Facet Facet; - typedef typename Tr_Base::Edge Edge; + typedef Tds Triangulation_data_structure; + typedef Gt Geom_traits; - typedef typename Tr_Base::size_type size_type; - typedef typename Tr_Base::Locate_type Locate_type; - typedef typename Tr_Base::Cell_iterator Cell_iterator; - typedef typename Tr_Base::Facet_iterator Facet_iterator; - typedef typename Tr_Base::Edge_iterator Edge_iterator; - typedef typename Tr_Base::Facet_circulator Facet_circulator; + typedef typename Tr_Base::Concurrency_tag Concurrency_tag; + typedef typename Tr_Base::Lock_data_structure Lock_data_structure; - typedef typename Tr_Base::Finite_vertices_iterator Finite_vertices_iterator; - typedef typename Tr_Base::Finite_cells_iterator Finite_cells_iterator; - typedef typename Tr_Base::Finite_facets_iterator Finite_facets_iterator; - typedef typename Tr_Base::Finite_edges_iterator Finite_edges_iterator; - typedef typename Tr_Base::All_cells_iterator All_cells_iterator; + typedef typename Tr_Base::Vertex_handle Vertex_handle; + typedef typename Tr_Base::Cell_handle Cell_handle; + typedef typename Tr_Base::Vertex Vertex; + typedef typename Tr_Base::Cell Cell; + typedef typename Tr_Base::Facet Facet; + typedef typename Tr_Base::Edge Edge; - typedef typename Gt::Weighted_point_3 Weighted_point; - typedef typename Gt::Bare_point Bare_point; - typedef typename Gt::Segment_3 Segment; - typedef typename Gt::Triangle_3 Triangle; - typedef typename Gt::Tetrahedron_3 Tetrahedron; + typedef typename Tr_Base::size_type size_type; + typedef typename Tr_Base::Locate_type Locate_type; + typedef typename Tr_Base::Cell_iterator Cell_iterator; + typedef typename Tr_Base::Facet_iterator Facet_iterator; + typedef typename Tr_Base::Edge_iterator Edge_iterator; + typedef typename Tr_Base::Facet_circulator Facet_circulator; - // types for dual: - typedef typename Gt::Line_3 Line; - typedef typename Gt::Ray_3 Ray; - typedef typename Gt::Plane_3 Plane; - typedef typename Gt::Object_3 Object; + typedef typename Tr_Base::Finite_vertices_iterator Finite_vertices_iterator; + typedef typename Tr_Base::Finite_cells_iterator Finite_cells_iterator; + typedef typename Tr_Base::Finite_facets_iterator Finite_facets_iterator; + typedef typename Tr_Base::Finite_edges_iterator Finite_edges_iterator; + typedef typename Tr_Base::All_cells_iterator All_cells_iterator; - //Tag to distinguish Delaunay from Regular triangulations - typedef Tag_true Weighted_tag; + typedef typename Gt::Weighted_point_3 Weighted_point; + typedef typename Gt::Bare_point Bare_point; + typedef typename Gt::Segment_3 Segment; + typedef typename Gt::Triangle_3 Triangle; + typedef typename Gt::Tetrahedron_3 Tetrahedron; + typedef typename Gt::Vector_3 Vector; - using Tr_Base::cw; - using Tr_Base::ccw; + // types for dual: + typedef typename Gt::Line_3 Line; + typedef typename Gt::Ray_3 Ray; + typedef typename Gt::Plane_3 Plane; + typedef typename Gt::Object_3 Object; + + //Tag to distinguish Delaunay from Regular triangulations + typedef Tag_true Weighted_tag; + + using Tr_Base::cw; + using Tr_Base::ccw; #ifndef CGAL_CFG_USING_BASE_MEMBER_BUG_2 - using Tr_Base::geom_traits; + using Tr_Base::geom_traits; #endif - using Tr_Base::number_of_vertices; - using Tr_Base::dimension; - using Tr_Base::finite_facets_begin; - using Tr_Base::finite_facets_end; - using Tr_Base::finite_vertices_begin; - using Tr_Base::finite_vertices_end; - using Tr_Base::finite_cells_begin; - using Tr_Base::finite_cells_end; - using Tr_Base::finite_edges_begin; - using Tr_Base::finite_edges_end; - using Tr_Base::tds; - using Tr_Base::infinite_vertex; - using Tr_Base::next_around_edge; - using Tr_Base::vertex_triple_index; - using Tr_Base::mirror_vertex; - using Tr_Base::mirror_index; - using Tr_Base::orientation; - using Tr_Base::coplanar_orientation; - using Tr_Base::adjacent_vertices; - using Tr_Base::construct_segment; - using Tr_Base::incident_facets; - using Tr_Base::insert_in_conflict; - using Tr_Base::is_infinite; - using Tr_Base::is_valid_finite; - using Tr_Base::locate; - using Tr_Base::side_of_segment; - using Tr_Base::side_of_edge; - using Tr_Base::find_conflicts; - using Tr_Base::is_valid; + using Tr_Base::number_of_vertices; + using Tr_Base::dimension; + using Tr_Base::finite_facets_begin; + using Tr_Base::finite_facets_end; + using Tr_Base::finite_vertices_begin; + using Tr_Base::finite_vertices_end; + using Tr_Base::finite_cells_begin; + using Tr_Base::finite_cells_end; + using Tr_Base::finite_edges_begin; + using Tr_Base::finite_edges_end; + using Tr_Base::tds; + using Tr_Base::infinite_vertex; + using Tr_Base::next_around_edge; + using Tr_Base::vertex_triple_index; + using Tr_Base::mirror_vertex; + using Tr_Base::mirror_index; + using Tr_Base::orientation; + using Tr_Base::coplanar_orientation; + using Tr_Base::adjacent_vertices; + using Tr_Base::construct_segment; + using Tr_Base::incident_facets; + using Tr_Base::insert_in_conflict; + using Tr_Base::is_infinite; + using Tr_Base::is_valid_finite; + using Tr_Base::locate; + using Tr_Base::side_of_segment; + using Tr_Base::side_of_edge; + using Tr_Base::find_conflicts; + using Tr_Base::is_valid; - Regular_triangulation_3(const Gt & gt = Gt()) - : Tr_Base(gt), hidden_point_visitor(this) - {} + Regular_triangulation_3(const Gt & gt = Gt(), Lock_data_structure *lock_ds = NULL) + : Tr_Base(gt, lock_ds), hidden_point_visitor(this) + {} - Regular_triangulation_3(const Regular_triangulation_3 & rt) - : Tr_Base(rt), hidden_point_visitor(this) - { + Regular_triangulation_3(Lock_data_structure *lock_ds, const Gt & gt = Gt()) + : Tr_Base(lock_ds, gt), hidden_point_visitor(this) + {} + + Regular_triangulation_3(const Regular_triangulation_3 & rt) + : Tr_Base(rt), hidden_point_visitor(this) + { CGAL_triangulation_postcondition( is_valid() ); - } + } - //insertion - template < typename InputIterator > - Regular_triangulation_3(InputIterator first, InputIterator last, - const Gt & gt = Gt()) - : Tr_Base(gt), hidden_point_visitor(this) - { + //insertion + template < typename InputIterator > + Regular_triangulation_3(InputIterator first, InputIterator last, + const Gt & gt = Gt(), Lock_data_structure *lock_ds = NULL) + : Tr_Base(gt, lock_ds), hidden_point_visitor(this) + { insert(first, last); - } + } + + template < typename InputIterator > + Regular_triangulation_3(InputIterator first, InputIterator last, + Lock_data_structure *lock_ds, const Gt & gt = Gt()) + : Tr_Base(gt, lock_ds), hidden_point_visitor(this) + { + insert(first, last); + } #ifndef CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO - template < class InputIterator > - std::ptrdiff_t - insert( InputIterator first, InputIterator last, - typename boost::enable_if< - boost::is_convertible< - typename std::iterator_traits::value_type, - Weighted_point - > - >::type* = NULL - ) + template < class InputIterator > + std::ptrdiff_t + insert( InputIterator first, InputIterator last, + typename boost::enable_if< + boost::is_convertible< + typename std::iterator_traits::value_type, + Weighted_point + > + >::type* = NULL + ) #else - template < class InputIterator > - std::ptrdiff_t - insert( InputIterator first, InputIterator last) + template < class InputIterator > + std::ptrdiff_t + insert( InputIterator first, InputIterator last) #endif //CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO - { - size_type n = number_of_vertices(); - - std::vector points(first, last); - spatial_sort (points.begin(), points.end(), geom_traits()); - - Cell_handle hint; - for (typename std::vector::const_iterator p = points.begin(), - end = points.end(); p != end; ++p) { +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + static Profile_branch_counter_3 bcounter( + "early withdrawals / late withdrawals / successes [Regular_tri_3::insert]"); +#endif + +#ifdef CGAL_TRIANGULATION_3_PROFILING + WallClockTimer t; +#endif + + size_type n = number_of_vertices(); + std::vector points(first, last); + spatial_sort (points.begin(), points.end(), geom_traits()); + + // Parallel +#ifdef CGAL_LINKED_WITH_TBB + if (this->is_parallel()) + { + size_t num_points = points.size(); + Cell_handle hint; + std::vector far_sphere_vertices; + +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_ADD_TEMPORARY_POINTS_ON_FAR_SPHERE + const size_t MIN_NUM_POINTS_FOR_FAR_SPHERE_POINTS = 1000000; + if (num_points >= MIN_NUM_POINTS_FOR_FAR_SPHERE_POINTS) + { + // Add temporary vertices on a "far sphere" to reduce contention on + // the infinite vertex + + // Get bbox + const Bbox_3 &bbox = *this->get_bbox(); + // Compute radius for far sphere + const double& xdelta = bbox.xmax() - bbox.xmin(); + const double& ydelta = bbox.ymax() - bbox.ymin(); + const double& zdelta = bbox.zmax() - bbox.zmin(); + const double radius = 1.3 * 0.5 * std::sqrt(xdelta*xdelta + + ydelta*ydelta + + zdelta*zdelta); + const Vector center( + bbox.xmin() + 0.5*xdelta, + bbox.ymin() + 0.5*ydelta, + bbox.zmin() + 0.5*zdelta); + Random_points_on_sphere_3 random_point(radius); + const int NUM_PSEUDO_INFINITE_VERTICES = static_cast( + boost::thread::hardware_concurrency() * 3.5); + std::vector points_on_far_sphere; + for (int i = 0 ; i < NUM_PSEUDO_INFINITE_VERTICES ; ++i, ++random_point) + points_on_far_sphere.push_back(*random_point + center); + + spatial_sort(points_on_far_sphere.begin(), + points_on_far_sphere.end(), + geom_traits()); + + std::vector::const_iterator it_p = points_on_far_sphere.begin(); + std::vector::const_iterator it_p_end = points_on_far_sphere.end(); + for ( ; it_p != it_p_end ; ++it_p) + { + Locate_type lt; + Cell_handle c; + int li, lj; + + c = locate (*it_p, lt, li, lj, hint); + Vertex_handle v = insert (*it_p, lt, c, li, lj); + hint = (v == Vertex_handle() ? c : v->cell()); + + far_sphere_vertices.push_back(v); + } + } +#endif // CGAL_CONCURRENT_TRIANGULATION_3_ADD_TEMPORARY_POINTS_ON_FAR_SPHERE + + int i = 0; + // Insert "num_points_seq" points sequentially + // (or more if dim < 3 after that) + size_t num_points_seq = (std::min)(num_points, (size_t)500); + while (dimension() < 3 || i < num_points_seq) + { + Locate_type lt; + Cell_handle c; + int li, lj; + + c = locate (points[i], lt, li, lj, hint); + Vertex_handle v = insert (points[i], lt, c, li, lj); + + hint = (v == Vertex_handle() ? c : v->cell()); + ++i; + } + + tbb::enumerable_thread_specific tls_hint(hint->vertex(0)); + tbb::parallel_for( + tbb::blocked_range( i, num_points ), + Insert_point(*this, points, tls_hint) + ); + +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_ADD_TEMPORARY_POINTS_ON_FAR_SPHERE + if (num_points >= MIN_NUM_POINTS_FOR_FAR_SPHERE_POINTS) + { + // Remove the temporary vertices on far sphere + remove(far_sphere_vertices.begin(), far_sphere_vertices.end()); + } +#endif // CGAL_CONCURRENT_TRIANGULATION_3_ADD_TEMPORARY_POINTS_ON_FAR_SPHERE + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + Cell_handle hint; + for (typename std::vector::const_iterator p = points.begin(), + end = points.end(); p != end; ++p) + { + Locate_type lt; + Cell_handle c; + int li, lj; + c = locate (*p, lt, li, lj, hint); + + Vertex_handle v = insert (*p, lt, c, li, lj); + + hint = v == Vertex_handle() ? c : v->cell(); + } + } +#ifdef CGAL_TRIANGULATION_3_PROFILING + std::cerr << "Points inserted in " << t.elapsed() << " seconds." << std::endl; +#endif + return number_of_vertices() - n; + } + + +#ifndef CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO + private: + //top stands for tuple-or-pair + template + const Weighted_point& top_get_first(const std::pair& pair) const { return pair.first; } + template + const Info& top_get_second(const std::pair& pair) const { return pair.second; } + template + const Weighted_point& top_get_first(const boost::tuple& tuple) const { return boost::get<0>(tuple); } + template + const Info& top_get_second(const boost::tuple& tuple) const { return boost::get<1>(tuple); } + + template + std::ptrdiff_t insert_with_info(InputIterator first,InputIterator last) + { + size_type n = number_of_vertices(); + std::vector indices; + std::vector points; + std::vector infos; + std::ptrdiff_t index=0; + for (InputIterator it=first;it!=last;++it){ + Tuple_or_pair pair = *it; + points.push_back( top_get_first(pair) ); + infos.push_back ( top_get_second(pair) ); + indices.push_back(index++); + } + + typedef Spatial_sort_traits_adapter_3 Search_traits; + + spatial_sort( indices.begin(),indices.end(),Search_traits(&(points[0]),geom_traits()) ); + + Cell_handle hint; + for (typename std::vector::const_iterator + it = indices.begin(), end = indices.end(); + it != end; ++it) + { Locate_type lt; Cell_handle c; int li, lj; - c = locate (*p, lt, li, lj, hint); + c = locate (points[*it], lt, li, lj, hint); - Vertex_handle v = insert (*p, lt, c, li, lj); - - hint = v == Vertex_handle() ? c : v->cell(); - } - return number_of_vertices() - n; - } - - -#ifndef CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO -private: - //top stands for tuple-or-pair - template - const Weighted_point& top_get_first(const std::pair& pair) const { return pair.first; } - template - const Info& top_get_second(const std::pair& pair) const { return pair.second; } - template - const Weighted_point& top_get_first(const boost::tuple& tuple) const { return boost::get<0>(tuple); } - template - const Info& top_get_second(const boost::tuple& tuple) const { return boost::get<1>(tuple); } - - template - std::ptrdiff_t insert_with_info(InputIterator first,InputIterator last) - { - size_type n = number_of_vertices(); - std::vector indices; - std::vector points; - std::vector infos; - std::ptrdiff_t index=0; - for (InputIterator it=first;it!=last;++it){ - Tuple_or_pair pair = *it; - points.push_back( top_get_first(pair) ); - infos.push_back ( top_get_second(pair) ); - indices.push_back(index++); - } - - typedef Spatial_sort_traits_adapter_3 Search_traits; - - spatial_sort( indices.begin(),indices.end(),Search_traits(&(points[0]),geom_traits()) ); - - Cell_handle hint; - for (typename std::vector::const_iterator - it = indices.begin(), end = indices.end(); - it != end; ++it) - { - Locate_type lt; - Cell_handle c; - int li, lj; - c = locate (points[*it], lt, li, lj, hint); - - Vertex_handle v = insert (points[*it], lt, c, li, lj); - if (v!=Vertex_handle()){ - v->info()=infos[*it]; - hint=v->cell(); + Vertex_handle v = insert (points[*it], lt, c, li, lj); + if (v!=Vertex_handle()){ + v->info()=infos[*it]; + hint=v->cell(); + } + else + hint=c; } - else - hint=c; + + return number_of_vertices() - n; } - return number_of_vertices() - n; - } - -public: + public: - template < class InputIterator > - std::ptrdiff_t - insert( InputIterator first, - InputIterator last, - typename boost::enable_if< - boost::is_convertible< - typename std::iterator_traits::value_type, - std::pair::type> - > - >::type* = NULL - ) - {return insert_with_info< std::pair::type> >(first,last);} - - template - std::ptrdiff_t - insert( boost::zip_iterator< boost::tuple > first, - boost::zip_iterator< boost::tuple > last, - typename boost::enable_if< - boost::mpl::and_< - typename boost::is_convertible< typename std::iterator_traits::value_type, Weighted_point >, - typename boost::is_convertible< typename std::iterator_traits::value_type, typename internal::Info_check::type > - > - >::type* =NULL - ) - {return insert_with_info< boost::tuple::type> >(first,last);} + template < class InputIterator > + std::ptrdiff_t + insert( InputIterator first, + InputIterator last, + typename boost::enable_if< + boost::is_convertible< + typename std::iterator_traits::value_type, + std::pair::type> + > + >::type* = NULL + ) + {return insert_with_info< std::pair::type> >(first,last);} + + template + std::ptrdiff_t + insert( boost::zip_iterator< boost::tuple > first, + boost::zip_iterator< boost::tuple > last, + typename boost::enable_if< + boost::mpl::and_< + typename boost::is_convertible< typename std::iterator_traits::value_type, Weighted_point >, + typename boost::is_convertible< typename std::iterator_traits::value_type, typename internal::Info_check::type > + > + >::type* =NULL + ) + {return insert_with_info< boost::tuple::type> >(first,last);} #endif //CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO - - Vertex_handle insert(const Weighted_point & p, Vertex_handle hint) - { - return insert(p, hint == Vertex_handle() ? this->infinite_cell() : hint->cell()); - } - Vertex_handle insert(const Weighted_point & p, - Cell_handle start = Cell_handle()); + Vertex_handle insert(const Weighted_point & p, Vertex_handle hint, + bool *could_lock_zone = NULL) + { + return insert(p, + hint == Vertex_handle() ? this->infinite_cell() : hint->cell(), + could_lock_zone); + } - Vertex_handle insert(const Weighted_point & p, Locate_type lt, - Cell_handle c, int li, int); - - template - Vertex_handle - insert_in_hole(const Weighted_point & p, CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i); - - template - Vertex_handle - insert_in_hole(const Weighted_point & p, CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i, Vertex_handle newv); + Vertex_handle insert(const Weighted_point & p, + Cell_handle start = Cell_handle(), bool *could_lock_zone = NULL); - template - Triple - find_conflicts(const Weighted_point &p, Cell_handle c, - OutputIteratorBoundaryFacets bfit, - OutputIteratorCells cit, - OutputIteratorInternalFacets ifit) const - { + Vertex_handle insert(const Weighted_point & p, Locate_type lt, + Cell_handle c, int li, int, bool *could_lock_zone = NULL); + + template + Vertex_handle + insert_in_hole(const Weighted_point & p, CellIt cell_begin, CellIt cell_end, + Cell_handle begin, int i); + + template + Vertex_handle + insert_in_hole(const Weighted_point & p, CellIt cell_begin, CellIt cell_end, + Cell_handle begin, int i, Vertex_handle newv); + + template + Triple + find_conflicts(const Weighted_point &p, Cell_handle c, + OutputIteratorBoundaryFacets bfit, + OutputIteratorCells cit, + OutputIteratorInternalFacets ifit + , bool *could_lock_zone = NULL + , const Facet *this_facet_must_be_in_the_cz = NULL + , bool *the_facet_is_in_its_cz = NULL + ) const + { CGAL_triangulation_precondition(dimension() >= 2); std::vector cells; @@ -317,73 +458,84 @@ public: facets.reserve(64); if (dimension() == 2) { - Conflict_tester_2 tester(p, this); - if (! tester (c)) return make_triple (bfit, cit, ifit); - ifit = Tr_Base::find_conflicts - (c, tester, - make_triple(std::back_inserter(facets), - std::back_inserter(cells), - ifit)).third; + Conflict_tester_2 tester(p, this); + if (! tester (c)) return make_triple (bfit, cit, ifit); + ifit = Tr_Base::find_conflicts + (c, tester, + make_triple(std::back_inserter(facets), + std::back_inserter(cells), + ifit) + , could_lock_zone + , this_facet_must_be_in_the_cz + , the_facet_is_in_its_cz + ).third; } else { - Conflict_tester_3 tester(p, this); - if (! tester (c)) return make_triple (bfit, cit, ifit); - ifit = Tr_Base::find_conflicts - (c, tester, - make_triple(std::back_inserter(facets), - std::back_inserter(cells), - ifit)).third; + Conflict_tester_3 tester(p, this); + if (! tester (c)) return make_triple (bfit, cit, ifit); + ifit = Tr_Base::find_conflicts + (c, tester, + make_triple(std::back_inserter(facets), + std::back_inserter(cells), + ifit) + , could_lock_zone + , this_facet_must_be_in_the_cz + , the_facet_is_in_its_cz + ).third; } // Reset the conflict flag on the boundary. for(typename std::vector::iterator fit=facets.begin(); - fit != facets.end(); ++fit) { - fit->first->neighbor(fit->second)->tds_data().clear(); - *bfit++ = *fit; + fit != facets.end(); ++fit) { + fit->first->neighbor(fit->second)->tds_data().clear(); + *bfit++ = *fit; } // Reset the conflict flag in the conflict cells. for(typename std::vector::iterator ccit=cells.begin(); ccit != cells.end(); ++ccit) { - (*ccit)->tds_data().clear(); - *cit++ = *ccit; + (*ccit)->tds_data().clear(); + *cit++ = *ccit; } return make_triple(bfit, cit, ifit); - } + } - template - std::pair - find_conflicts(const Weighted_point &p, Cell_handle c, - OutputIteratorBoundaryFacets bfit, - OutputIteratorCells cit) const - { + template + std::pair + find_conflicts(const Weighted_point &p, Cell_handle c, + OutputIteratorBoundaryFacets bfit, + OutputIteratorCells cit + , bool *could_lock_zone = NULL + ) const + { Triple t = find_conflicts(p, c, bfit, cit, - Emptyset_iterator()); + OutputIteratorCells, + Emptyset_iterator> t = find_conflicts(p, c, bfit, cit, + Emptyset_iterator(), + could_lock_zone); return std::make_pair(t.first, t.second); - } + } - // Returns the vertices on the interior of the conflict hole. - template - OutputIterator - vertices_inside_conflict_zone(const Weighted_point&p, Cell_handle c, - OutputIterator res) const - { + // Returns the vertices on the interior of the conflict hole. + template + OutputIterator + vertices_inside_conflict_zone(const Weighted_point&p, Cell_handle c, + OutputIterator res) const + { CGAL_triangulation_precondition(dimension() >= 2); // Get the facets on the boundary of the hole, and the cells of the hole std::vector cells; std::vector facets; find_conflicts(p, c, std::back_inserter(facets), - std::back_inserter(cells), Emptyset_iterator()); + std::back_inserter(cells), Emptyset_iterator()); // Put all vertices on the hole in 'vertices' const int d = dimension(); std::set vertices; - for (typename std::vector::const_iterator - it = cells.begin(), - end = cells.end(); it != end; ++it) + for (typename std::vector::const_iterator + it = cells.begin(), + end = cells.end(); it != end; ++it) { for(int i = 0; i <= d; ++i) { vertices.insert((*it)->vertex(i)); @@ -392,527 +544,767 @@ public: // Then extract the vertices of the boundary and remove them from // 'vertices' if (dimension() == 3) { - for (typename std::vector::const_iterator i = facets.begin(); - i != facets.end(); ++i) { - vertices.erase(i->first->vertex((i->second+1)&3)); - vertices.erase(i->first->vertex((i->second+2)&3)); - vertices.erase(i->first->vertex((i->second+3)&3)); - } + for (typename std::vector::const_iterator i = facets.begin(); + i != facets.end(); ++i) { + vertices.erase(i->first->vertex((i->second+1)&3)); + vertices.erase(i->first->vertex((i->second+2)&3)); + vertices.erase(i->first->vertex((i->second+3)&3)); + } } else { - for (typename std::vector::const_iterator i = facets.begin(); - i != facets.end(); ++i) { - vertices.erase(i->first->vertex(cw(i->second))); - vertices.erase(i->first->vertex(ccw(i->second))); - } + for (typename std::vector::const_iterator i = facets.begin(); + i != facets.end(); ++i) { + vertices.erase(i->first->vertex(cw(i->second))); + vertices.erase(i->first->vertex(ccw(i->second))); + } } return std::copy(vertices.begin(), vertices.end(), res); - } + } #ifndef CGAL_NO_DEPRECATED_CODE - // Returns the vertices on the boundary of the conflict hole. - template - OutputIterator - vertices_in_conflict(const Weighted_point&p, Cell_handle c, OutputIterator res) const - { - return vertices_on_conflict_zone_boundary(p, c, res); - } + // Returns the vertices on the boundary of the conflict hole. + template + OutputIterator + vertices_in_conflict(const Weighted_point&p, Cell_handle c, OutputIterator res) const + { + return vertices_on_conflict_zone_boundary(p, c, res); + } #endif // CGAL_NO_DEPRECATED_CODE - // Returns the vertices on the boundary of the conflict hole. - template - OutputIterator - vertices_on_conflict_zone_boundary(const Weighted_point&p, Cell_handle c, - OutputIterator res) const - { + // Returns the vertices on the boundary of the conflict hole. + template + OutputIterator + vertices_on_conflict_zone_boundary(const Weighted_point&p, Cell_handle c, + OutputIterator res) const + { CGAL_triangulation_precondition(dimension() >= 2); // Get the facets on the boundary of the hole. std::vector facets; find_conflicts(p, c, std::back_inserter(facets), - Emptyset_iterator(), Emptyset_iterator()); + Emptyset_iterator(), Emptyset_iterator()); // Then extract uniquely the vertices. std::set vertices; if (dimension() == 3) { - for (typename std::vector::const_iterator i = facets.begin(); - i != facets.end(); ++i) { - vertices.insert(i->first->vertex((i->second+1)&3)); - vertices.insert(i->first->vertex((i->second+2)&3)); - vertices.insert(i->first->vertex((i->second+3)&3)); - } + for (typename std::vector::const_iterator i = facets.begin(); + i != facets.end(); ++i) { + vertices.insert(i->first->vertex((i->second+1)&3)); + vertices.insert(i->first->vertex((i->second+2)&3)); + vertices.insert(i->first->vertex((i->second+3)&3)); + } } else { - for (typename std::vector::const_iterator i = facets.begin(); - i != facets.end(); ++i) { - vertices.insert(i->first->vertex(cw(i->second))); - vertices.insert(i->first->vertex(ccw(i->second))); - } + for (typename std::vector::const_iterator i = facets.begin(); + i != facets.end(); ++i) { + vertices.insert(i->first->vertex(cw(i->second))); + vertices.insert(i->first->vertex(ccw(i->second))); + } } return std::copy(vertices.begin(), vertices.end(), res); - } - - void remove (Vertex_handle v); - - template < typename InputIterator > - size_type remove(InputIterator first, InputIterator beyond) - { - CGAL_triangulation_precondition(!this->does_repeat_in_range(first, beyond)); - size_type n = number_of_vertices(); - while (first != beyond) { - remove (*first); - ++first; } - return n - number_of_vertices(); - } - // DISPLACEMENT - Vertex_handle move_point(Vertex_handle v, const Weighted_point & p); + void remove (Vertex_handle v); + // Concurrency-safe + // See Triangulation_3::remove for more information + bool remove (Vertex_handle v, bool *could_lock_zone); - // Displacement works only for Regular triangulation - // without hidden points at any time - Vertex_handle move_if_no_collision(Vertex_handle v, const Weighted_point & p); - Vertex_handle move(Vertex_handle v, const Weighted_point & p); + template < typename InputIterator > + size_type remove(InputIterator first, InputIterator beyond) + { + CGAL_triangulation_precondition(!this->does_repeat_in_range(first, beyond)); + size_type n = number_of_vertices(); - // REMOVE CLUSTER - works only when Regular has no hidden point at all - // "regular as Delaunay" - template < typename InputIterator > - size_type remove_cluster(InputIterator first, InputIterator beyond) - { - Self tmp; - Vertex_remover remover (tmp); - return Tr_Base::remove(first, beyond, remover); - } +#ifdef CGAL_TRIANGULATION_3_PROFILING + WallClockTimer t; +#endif -protected: + // Parallel +#ifdef CGAL_LINKED_WITH_TBB + if (this->is_parallel()) + { + // TODO: avoid that by asking for ramdom-access iterators? + std::vector vertices(first, beyond); + tbb::concurrent_vector vertices_to_remove_sequentially; - Oriented_side - side_of_oriented_power_sphere(const Weighted_point &p0, - const Weighted_point &p1, - const Weighted_point &p2, - const Weighted_point &p3, - const Weighted_point &p, - bool perturb = false) const; + tbb::parallel_for( + tbb::blocked_range( 0, vertices.size()), + Remove_point(*this, vertices, vertices_to_remove_sequentially) + ); - Oriented_side - side_of_oriented_power_circle(const Weighted_point &p0, - const Weighted_point &p1, - const Weighted_point &p2, - const Weighted_point &p, - bool perturb = false) const; + // Do the rest sequentially + for ( typename tbb::concurrent_vector::const_iterator + it = vertices_to_remove_sequentially.begin(), + it_end = vertices_to_remove_sequentially.end() + ; it != it_end + ; ++it) + { + remove(*it); + } + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + while (first != beyond) { + remove(*first); + ++first; + } + } - Bounded_side - side_of_bounded_power_circle(const Weighted_point &p0, - const Weighted_point &p1, - const Weighted_point &p2, - const Weighted_point &p, - bool perturb = false) const; +#ifdef CGAL_TRIANGULATION_3_PROFILING + std::cerr << "Points removed in " << t.elapsed() << " seconds." << std::endl; +#endif + return n - number_of_vertices(); + } - Bounded_side - side_of_bounded_power_segment(const Weighted_point &p0, - const Weighted_point &p1, - const Weighted_point &p, - bool perturb = false) const; + // DISPLACEMENT + Vertex_handle move_point(Vertex_handle v, const Weighted_point & p); + + // Displacement works only for Regular triangulation + // without hidden points at any time + Vertex_handle move_if_no_collision(Vertex_handle v, const Weighted_point & p); + Vertex_handle move(Vertex_handle v, const Weighted_point & p); + + // REMOVE CLUSTER - works only when Regular has no hidden point at all + // "regular as Delaunay" + template < typename InputIterator > + size_type remove_cluster(InputIterator first, InputIterator beyond) + { + Self tmp; + Vertex_remover remover (tmp); + return Tr_Base::remove(first, beyond, remover); + } + + protected: + + Oriented_side + side_of_oriented_power_sphere(const Weighted_point &p0, + const Weighted_point &p1, + const Weighted_point &p2, + const Weighted_point &p3, + const Weighted_point &p, + bool perturb = false) const; + + Oriented_side + side_of_oriented_power_circle(const Weighted_point &p0, + const Weighted_point &p1, + const Weighted_point &p2, + const Weighted_point &p, + bool perturb = false) const; + + Bounded_side + side_of_bounded_power_circle(const Weighted_point &p0, + const Weighted_point &p1, + const Weighted_point &p2, + const Weighted_point &p, + bool perturb = false) const; + + Bounded_side + side_of_bounded_power_segment(const Weighted_point &p0, + const Weighted_point &p1, + const Weighted_point &p, + bool perturb = false) const; -public: + public: - // Queries - Bounded_side - side_of_power_sphere(Cell_handle c, const Weighted_point &p, - bool perturb = false) const; + // Queries + Bounded_side + side_of_power_sphere(Cell_handle c, const Weighted_point &p, + bool perturb = false) const; - Bounded_side - side_of_power_circle(const Facet & f, const Weighted_point & p, - bool /* perturb */ = false) const - { + Bounded_side + side_of_power_circle(const Facet & f, const Weighted_point & p, + bool /* perturb */ = false) const + { return side_of_power_circle(f.first, f.second, p); - } + } - Bounded_side - side_of_power_circle(Cell_handle c, int i, const Weighted_point &p, - bool perturb = false) const; + Bounded_side + side_of_power_circle(Cell_handle c, int i, const Weighted_point &p, + bool perturb = false) const; - Bounded_side - side_of_power_segment(Cell_handle c, const Weighted_point &p, - bool perturb = false) const; + Bounded_side + side_of_power_segment(Cell_handle c, const Weighted_point &p, + bool perturb = false) const; - Vertex_handle - nearest_power_vertex_in_cell(const Bare_point& p, - Cell_handle c) const; + Vertex_handle + nearest_power_vertex_in_cell(const Bare_point& p, + Cell_handle c) const; - Vertex_handle - nearest_power_vertex(const Bare_point& p, Cell_handle c = - Cell_handle()) const; + Vertex_handle + nearest_power_vertex(const Bare_point& p, Cell_handle c = + Cell_handle()) const; - bool is_Gabriel(Cell_handle c, int i) const; - bool is_Gabriel(Cell_handle c, int i, int j) const; - bool is_Gabriel(const Facet& f)const ; - bool is_Gabriel(const Edge& e) const; - bool is_Gabriel(Vertex_handle v) const; + bool is_Gabriel(Cell_handle c, int i) const; + bool is_Gabriel(Cell_handle c, int i, int j) const; + bool is_Gabriel(const Facet& f)const ; + bool is_Gabriel(const Edge& e) const; + bool is_Gabriel(Vertex_handle v) const; - // Dual functions - Bare_point dual(Cell_handle c) const; + // Dual functions + Bare_point dual(Cell_handle c) const; - Object dual(const Facet & f) const + Object dual(const Facet & f) const { return dual( f.first, f.second ); } - Object dual(Cell_handle c, int i) const; + Object dual(Cell_handle c, int i) const; - template < class Stream> - Stream& draw_dual(Stream & os) + template < class Stream> + Stream& draw_dual(Stream & os) { for (Finite_facets_iterator fit = finite_facets_begin(), - end = finite_facets_end(); - fit != end; ++fit) { - Object o = dual(*fit); - if (const Segment *s = object_cast(&o)) os << *s; - else if (const Ray *r = object_cast(&o)) os << *r; - else if (const Bare_point *p = object_cast(&o)) os << *p; + end = finite_facets_end(); + fit != end; ++fit) { + Object o = dual(*fit); + if (const Segment *s = object_cast(&o)) os << *s; + else if (const Ray *r = object_cast(&o)) os << *r; + else if (const Bare_point *p = object_cast(&o)) os << *p; } return os; } - bool is_valid(bool verbose = false, int level = 0) const; + bool is_valid(bool verbose = false, int level = 0) const; -protected: - bool - less_power_distance(const Bare_point &p, - const Weighted_point &q, - const Weighted_point &r) const - { - return - geom_traits().compare_power_distance_3_object()(p, q, r) == SMALLER; - } + protected: + bool + less_power_distance(const Bare_point &p, + const Weighted_point &q, + const Weighted_point &r) const + { + return + geom_traits().compare_power_distance_3_object()(p, q, r) == SMALLER; + } - Bare_point - construct_weighted_circumcenter(const Weighted_point &p, - const Weighted_point &q, - const Weighted_point &r, - const Weighted_point &s) const - { - return geom_traits().construct_weighted_circumcenter_3_object()(p,q,r,s); - } + Bare_point + construct_weighted_circumcenter(const Weighted_point &p, + const Weighted_point &q, + const Weighted_point &r, + const Weighted_point &s) const + { + return geom_traits().construct_weighted_circumcenter_3_object()(p,q,r,s); + } - Bare_point - construct_weighted_circumcenter(const Weighted_point &p, - const Weighted_point &q, - const Weighted_point &r) const - { - return geom_traits().construct_weighted_circumcenter_3_object()(p,q,r); - } + Bare_point + construct_weighted_circumcenter(const Weighted_point &p, + const Weighted_point &q, + const Weighted_point &r) const + { + return geom_traits().construct_weighted_circumcenter_3_object()(p,q,r); + } - Line - construct_perpendicular_line(const Plane &pl, const Bare_point &p) const - { + Line + construct_perpendicular_line(const Plane &pl, const Bare_point &p) const + { return geom_traits().construct_perpendicular_line_3_object()(pl, p); - } + } - Plane - construct_plane(const Bare_point &p, const Bare_point &q, const Bare_point &r) const - { + Plane + construct_plane(const Bare_point &p, const Bare_point &q, const Bare_point &r) const + { return geom_traits().construct_plane_3_object()(p, q, r); - } + } - Ray - construct_ray(const Bare_point &p, const Line &l) const - { + Ray + construct_ray(const Bare_point &p, const Line &l) const + { return geom_traits().construct_ray_3_object()(p, l); - } + } - Object - construct_object(const Bare_point &p) const - { + Object + construct_object(const Bare_point &p) const + { return geom_traits().construct_object_3_object()(p); - } + } - Object - construct_object(const Segment &s) const - { + Object + construct_object(const Segment &s) const + { return geom_traits().construct_object_3_object()(s); - } + } - Object - construct_object(const Ray &r) const - { + Object + construct_object(const Ray &r) const + { return geom_traits().construct_object_3_object()(r); - } + } - Vertex_handle - nearest_power_vertex(const Bare_point &p, - Vertex_handle v, - Vertex_handle w) const - { + Vertex_handle + nearest_power_vertex(const Bare_point &p, + Vertex_handle v, + Vertex_handle w) const + { // In case of equality, v is returned. CGAL_triangulation_precondition(v != w); if (is_infinite(v)) return w; if (is_infinite(w)) return v; return less_power_distance(p, w->point(), v->point()) ? w : v; - } + } - Oriented_side - power_test(const Weighted_point &p, const Weighted_point &q) const - { + Oriented_side + power_test(const Weighted_point &p, const Weighted_point &q) const + { CGAL_triangulation_precondition(this->equal(p, q)); return geom_traits().power_test_3_object()(p, q); - } + } - Oriented_side - power_test(const Weighted_point &p, const Weighted_point &q, - const Weighted_point &r) const - { + Oriented_side + power_test(const Weighted_point &p, const Weighted_point &q, + const Weighted_point &r) const + { CGAL_triangulation_precondition(this->collinear(p, q, r)); return geom_traits().power_test_3_object()(p, q, r); - } + } - Oriented_side - power_test(const Weighted_point &p, const Weighted_point &q, - const Weighted_point &r, const Weighted_point &s) const - { + Oriented_side + power_test(const Weighted_point &p, const Weighted_point &q, + const Weighted_point &r, const Weighted_point &s) const + { CGAL_triangulation_precondition(this->coplanar(p, q, r, s)); return geom_traits().power_test_3_object()(p, q, r, s); - } + } - Oriented_side - power_test(const Weighted_point &p, const Weighted_point &q, - const Weighted_point &r, const Weighted_point &s, - const Weighted_point &t) const - { + Oriented_side + power_test(const Weighted_point &p, const Weighted_point &q, + const Weighted_point &r, const Weighted_point &s, + const Weighted_point &t) const + { return geom_traits().power_test_3_object()(p, q, r, s, t); - } + } - bool in_conflict_3(const Weighted_point &p, const Cell_handle c) const - { + bool in_conflict_3(const Weighted_point &p, const Cell_handle c) const + { return side_of_power_sphere(c, p, true) == ON_BOUNDED_SIDE; - } + } - bool in_conflict_2(const Weighted_point &p, const Cell_handle c, int i) const - { + bool in_conflict_2(const Weighted_point &p, const Cell_handle c, int i) const + { return side_of_power_circle(c, i, p, true) == ON_BOUNDED_SIDE; - } + } - bool in_conflict_1(const Weighted_point &p, const Cell_handle c) const - { + bool in_conflict_1(const Weighted_point &p, const Cell_handle c) const + { return side_of_power_segment(c, p, true) == ON_BOUNDED_SIDE; - } + } - bool in_conflict_0(const Weighted_point &p, const Cell_handle c) const - { + bool in_conflict_0(const Weighted_point &p, const Cell_handle c) const + { return power_test(c->vertex(0)->point(), p) == ON_POSITIVE_SIDE; - } + } - bool in_conflict(const Weighted_point &p, const Cell_handle c) const - { + bool in_conflict(const Weighted_point &p, const Cell_handle c) const + { switch (dimension()) { - case 0: return in_conflict_0(p, c); - case 1: return in_conflict_1(p, c); - case 2: return in_conflict_2(p, c, 3); - case 3: return in_conflict_3(p, c); + case 0: return in_conflict_0(p, c); + case 1: return in_conflict_1(p, c); + case 2: return in_conflict_2(p, c, 3); + case 3: return in_conflict_3(p, c); } return true; - } - - class Conflict_tester_3 - { - const Weighted_point &p; - const Self *t; - - public: - - Conflict_tester_3(const Weighted_point &pt, const Self *tr) - : p(pt), t(tr) {} - - bool operator()(const Cell_handle c) const { - return t->in_conflict_3(p, c); } - bool test_initial_cell(const Cell_handle c) const { - return operator()(c); - } - Oriented_side compare_weight(const Weighted_point &wp1, - const Weighted_point &wp2) const + class Conflict_tester_3 { - return t->power_test (wp1, wp2); - } - }; - - class Conflict_tester_2 - { - const Weighted_point &p; - const Self *t; - public: - - Conflict_tester_2(const Weighted_point &pt, const Self *tr) - : p(pt), t(tr) {} - - bool operator()(const Cell_handle c) const - { - return t->in_conflict_2(p, c, 3); - } - bool test_initial_cell(const Cell_handle c) const { - return operator()(c); - } - Oriented_side compare_weight(const Weighted_point &wp1, - const Weighted_point &wp2) const - { - return t->power_test (wp1, wp2); - } - }; - - class Conflict_tester_1 - { const Weighted_point &p; const Self *t; - public: + public: - Conflict_tester_1(const Weighted_point &pt, const Self *tr) - : p(pt), t(tr) {} + Conflict_tester_3(const Weighted_point &pt, const Self *tr) + : p(pt), t(tr) {} - bool operator()(const Cell_handle c) const + bool operator()(const Cell_handle c) const { + return t->in_conflict_3(p, c); + } + + bool test_initial_cell(const Cell_handle c) const { + return operator()(c); + } + Oriented_side compare_weight(const Weighted_point &wp1, + const Weighted_point &wp2) const + { + return t->power_test (wp1, wp2); + } + }; + + class Conflict_tester_2 { - return t->in_conflict_1(p, c); - } - bool test_initial_cell(const Cell_handle c) const { - return operator()(c); - } - Oriented_side compare_weight(const Weighted_point &wp1, - const Weighted_point &wp2) const - { - return t->power_test (wp1, wp2); - } - }; + const Weighted_point &p; + const Self *t; + public: - class Conflict_tester_0 - { + Conflict_tester_2(const Weighted_point &pt, const Self *tr) + : p(pt), t(tr) {} + + bool operator()(const Cell_handle c) const + { + return t->in_conflict_2(p, c, 3); + } + bool test_initial_cell(const Cell_handle c) const { + return operator()(c); + } + Oriented_side compare_weight(const Weighted_point &wp1, + const Weighted_point &wp2) const + { + return t->power_test (wp1, wp2); + } + }; + + class Conflict_tester_1 + { const Weighted_point &p; const Self *t; - public: + public: - Conflict_tester_0(const Weighted_point &pt, const Self *tr) - : p(pt), t(tr) {} + Conflict_tester_1(const Weighted_point &pt, const Self *tr) + : p(pt), t(tr) {} - bool operator()(const Cell_handle c) const + bool operator()(const Cell_handle c) const + { + return t->in_conflict_1(p, c); + } + bool test_initial_cell(const Cell_handle c) const { + return operator()(c); + } + Oriented_side compare_weight(const Weighted_point &wp1, + const Weighted_point &wp2) const + { + return t->power_test (wp1, wp2); + } + }; + + class Conflict_tester_0 { - return t->in_conflict_0(p, c); - } - bool test_initial_cell(const Cell_handle c) const { - return operator()(c); - } - int compare_weight(const Weighted_point &wp1, - const Weighted_point &wp2) const - { - return t->power_test (wp1, wp2); - } - }; + const Weighted_point &p; + const Self *t; - class Hidden_point_visitor + public: + + Conflict_tester_0(const Weighted_point &pt, const Self *tr) + : p(pt), t(tr) {} + + bool operator()(const Cell_handle c) const + { + return t->in_conflict_0(p, c); + } + bool test_initial_cell(const Cell_handle c) const { + return operator()(c); + } + int compare_weight(const Weighted_point &wp1, + const Weighted_point &wp2) const + { + return t->power_test (wp1, wp2); + } + }; + + // Sequential version + // "dummy" is here to allow the specialization (see below) + // See http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/285ab1eec49e1cb6 + template + class Hidden_point_visitor + { + Self *t; + mutable std::vector vertices; + mutable std::vector hidden_points; + + public: + + Hidden_point_visitor(Self *tr) : t(tr) {} + + template + void process_cells_in_conflict(InputIterator start, InputIterator end) const + { + int dim = t->dimension(); + while (start != end) { + std::copy((*start)->hidden_points_begin(), + (*start)->hidden_points_end(), + std::back_inserter(hidden_points)); + + for (int i=0; i<=dim; i++) { + Vertex_handle v = (*start)->vertex(i); + if (v->cell() != Cell_handle()) { + vertices.push_back(v); + v->set_cell(Cell_handle()); + } + } + start ++; + } + } + void reinsert_vertices(Vertex_handle v) { + Cell_handle hc = v->cell(); + for (typename std::vector::iterator + vi = vertices.begin(); vi != vertices.end(); ++vi) { + if ((*vi)->cell() != Cell_handle()) continue; + hc = t->locate ((*vi)->point(), hc); + hide_point(hc, (*vi)->point()); + t->tds().delete_vertex(*vi); + } + vertices.clear(); + for (typename std::vector::iterator + hp = hidden_points.begin(); hp != hidden_points.end(); ++hp) { + hc = t->locate (*hp, hc); + hide_point (hc, *hp); + } + hidden_points.clear(); + } + Vertex_handle replace_vertex(Cell_handle c, int index, + const Weighted_point &p) { + Vertex_handle v = c->vertex(index); + hide_point(c, v->point()); + v->set_point(p); + return v; + } + void hide_point(Cell_handle c, const Weighted_point &p) { + c->hide_point(p); + } + }; + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel version specialization + template + class Hidden_point_visitor + { + typedef Hidden_point_visitor HPV; + + Self *t; + mutable tbb::enumerable_thread_specific > vertices; + mutable tbb::enumerable_thread_specific > hidden_points; + + public: + + Hidden_point_visitor(Self *tr) : t(tr) {} + + template + void process_cells_in_conflict(InputIterator start, InputIterator end) const + { + int dim = t->dimension(); + while (start != end) { + std::copy((*start)->hidden_points_begin(), + (*start)->hidden_points_end(), + std::back_inserter(hidden_points.local())); + + for (int i=0; i<=dim; i++) { + Vertex_handle v = (*start)->vertex(i); + if (v->cell() != Cell_handle()) { + vertices.local().push_back(v); + v->set_cell(Cell_handle()); + } + } + start ++; + } + } + void reinsert_vertices(Vertex_handle v) { + Cell_handle hc = v->cell(); + for (typename std::vector::iterator + vi = vertices.local().begin(); vi != vertices.local().end(); ++vi) { + if ((*vi)->cell() != Cell_handle()) continue; + hc = t->locate ((*vi)->point(), hc); + hide_point(hc, (*vi)->point()); + t->tds().delete_vertex(*vi); + } + vertices.local().clear(); + for (typename std::vector::iterator + hp = hidden_points.local().begin(); hp != hidden_points.local().end(); ++hp) { + hc = t->locate (*hp, hc); + hide_point (hc, *hp); + } + hidden_points.local().clear(); + } + Vertex_handle replace_vertex(Cell_handle c, int index, + const Weighted_point &p) { + Vertex_handle v = c->vertex(index); + hide_point(c, v->point()); + v->set_point(p); + return v; + } + void hide_point(Cell_handle c, const Weighted_point &p) { + c->hide_point(p); + } + }; + + // Functor for parallel insert(begin, end) function + template + class Insert_point { - Self *t; - mutable std::vector vertices; - mutable std::vector hidden_points; + typedef typename RT::Weighted_point Weighted_point; + typedef typename RT::Vertex_handle Vertex_handle; + + RT & m_rt; + const std::vector & m_points; + tbb::enumerable_thread_specific & m_tls_hint; public: + // Constructor + Insert_point(RT & rt, + const std::vector & points, + tbb::enumerable_thread_specific & tls_hint) + : m_rt(rt), m_points(points), m_tls_hint(tls_hint) + {} - Hidden_point_visitor(Self *tr) : t(tr) {} + // Constructor + Insert_point(const Insert_point &ip) + : m_rt(ip.m_rt), m_points(ip.m_points), m_tls_hint(ip.m_tls_hint) + {} - template - void process_cells_in_conflict(InputIterator start, InputIterator end) const + // operator() + void operator()( const tbb::blocked_range& r ) const { - int dim = t->dimension(); - while (start != end) { - std::copy((*start)->hidden_points_begin(), - (*start)->hidden_points_end(), - std::back_inserter(hidden_points)); - - for (int i=0; i<=dim; i++) { - Vertex_handle v = (*start)->vertex(i); - if (v->cell() != Cell_handle()) { - vertices.push_back(v); - v->set_cell(Cell_handle()); - } - } - start ++; +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + static Profile_branch_counter_3 bcounter( + "early withdrawals / late withdrawals / successes [Delaunay_tri_3::insert]"); +#endif + + Vertex_handle &hint = m_tls_hint.local(); + for( size_t i_point = r.begin() ; i_point != r.end() ; ++i_point) + { + bool success = false; + const Weighted_point &p = m_points[i_point]; + while(!success) + { + if (m_rt.try_lock_vertex(hint) && m_rt.try_lock_point(p)) + { + bool could_lock_zone; + Locate_type lt; + int li, lj; + + Cell_handle c = m_rt.locate (p, lt, li, lj, hint->cell(), + &could_lock_zone); + Vertex_handle v; + if (could_lock_zone) + v = m_rt.insert (p, lt, c, li, lj, &could_lock_zone); + + if (could_lock_zone) + { + hint = (v == Vertex_handle() ? c->vertex(0) : v); + m_rt.unlock_all_elements(); + success = true; +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + ++bcounter; +#endif + } + else + { + m_rt.unlock_all_elements(); +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + bcounter.increment_branch_1(); // THIS is a late withdrawal! +#endif + } + } + else + { + m_rt.unlock_all_elements(); +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + bcounter.increment_branch_2(); // THIS is an early withdrawal! +#endif + } + } } } - void reinsert_vertices(Vertex_handle v) { - Cell_handle hc = v->cell(); - for (typename std::vector::iterator - vi = vertices.begin(); vi != vertices.end(); ++vi) { - if ((*vi)->cell() != Cell_handle()) continue; - hc = t->locate ((*vi)->point(), hc); - hide_point(hc, (*vi)->point()); - t->tds().delete_vertex(*vi); - } - vertices.clear(); - for (typename std::vector::iterator - hp = hidden_points.begin(); hp != hidden_points.end(); ++hp) { - hc = t->locate (*hp, hc); - hide_point (hc, *hp); - } - hidden_points.clear(); - } - Vertex_handle replace_vertex(Cell_handle c, int index, - const Weighted_point &p) { - Vertex_handle v = c->vertex(index); - hide_point(c, v->point()); - v->set_point(p); - return v; - } - void hide_point(Cell_handle c, const Weighted_point &p) { - c->hide_point(p); - } }; - template < class RegularTriangulation_3 > - class Vertex_remover; + // Functor for parallel remove(begin, end) function + template + class Remove_point + { + typedef typename RT::Weighted_point Weighted_point; + typedef typename RT::Vertex_handle Vertex_handle; - template < class RegularTriangulation_3 > - class Vertex_inserter; + RT & m_rt; + const std::vector & m_vertices; + tbb::concurrent_vector & m_vertices_to_remove_sequentially; - Hidden_point_visitor hidden_point_visitor; -}; + public: + // Constructor + Remove_point(RT & rt, + const std::vector & vertices, + tbb::concurrent_vector & + vertices_to_remove_sequentially) + : m_rt(rt), m_vertices(vertices), + m_vertices_to_remove_sequentially(vertices_to_remove_sequentially) + {} + + // Constructor + Remove_point(const Remove_point &rp) + : m_rt(rp.m_rt), m_vertices(rp.m_vertices), + m_vertices_to_remove_sequentially(rp.m_vertices_to_remove_sequentially) + {} + + // operator() + void operator()( const tbb::blocked_range& r ) const + { + for( size_t i_vertex = r.begin() ; i_vertex != r.end() ; ++i_vertex) + { + Vertex_handle v = m_vertices[i_vertex]; + bool could_lock_zone, needs_to_be_done_sequentially; + do + { + needs_to_be_done_sequentially = + !m_rt.remove(v, &could_lock_zone); + m_rt.unlock_all_elements(); + } while (!could_lock_zone); + + if (needs_to_be_done_sequentially) + m_vertices_to_remove_sequentially.push_back(v); + } + } + }; +#endif // CGAL_LINKED_WITH_TBB + + Hidden_point_visitor &get_hidden_point_visitor() + { + return hidden_point_visitor; + } + + template < class RegularTriangulation_3 > + class Vertex_remover; + + template < class RegularTriangulation_3 > + class Vertex_inserter; + + Hidden_point_visitor hidden_point_visitor; + }; -template < class Gt, class Tds > -typename Regular_triangulation_3::Vertex_handle -Regular_triangulation_3:: -nearest_power_vertex_in_cell(const Bare_point& p, - Cell_handle c) const -// Returns the finite vertex of the cell c with smaller -// power distance to p. -{ + template < class Gt, class Tds, class Lds > + typename Regular_triangulation_3::Vertex_handle + Regular_triangulation_3:: + nearest_power_vertex_in_cell(const Bare_point& p, + Cell_handle c) const + // Returns the finite vertex of the cell c with smaller + // power distance to p. + { CGAL_triangulation_precondition(dimension() >= 1); Vertex_handle nearest = nearest_power_vertex(p, - c->vertex(0), - c->vertex(1)); + c->vertex(0), + c->vertex(1)); if (dimension() >= 2) { - nearest = nearest_power_vertex(p, nearest, c->vertex(2)); - if (dimension() == 3) - nearest = nearest_power_vertex(p, nearest, c->vertex(3)); + nearest = nearest_power_vertex(p, nearest, c->vertex(2)); + if (dimension() == 3) + nearest = nearest_power_vertex(p, nearest, c->vertex(3)); } return nearest; -} + } -template < class Gt, class Tds > -typename Regular_triangulation_3::Vertex_handle -Regular_triangulation_3:: -nearest_power_vertex(const Bare_point& p, Cell_handle start) const -{ + template < class Gt, class Tds, class Lds > + typename Regular_triangulation_3::Vertex_handle + Regular_triangulation_3:: + nearest_power_vertex(const Bare_point& p, Cell_handle start) const + { if (number_of_vertices() == 0) return Vertex_handle(); // Use a brute-force algorithm if dimension < 3. if (dimension() < 3) { - Finite_vertices_iterator vit = finite_vertices_begin(); - Vertex_handle res = vit; - ++vit; - for (Finite_vertices_iterator end = finite_vertices_end(); vit != end; ++vit) - res = nearest_power_vertex(p, res, vit); - return res; + Finite_vertices_iterator vit = finite_vertices_begin(); + Vertex_handle res = vit; + ++vit; + for (Finite_vertices_iterator end = finite_vertices_end(); vit != end; ++vit) + res = nearest_power_vertex(p, res, vit); + return res; } Locate_type lt; @@ -928,22 +1320,22 @@ nearest_power_vertex(const Bare_point& p, Cell_handle start) const std::vector vs; vs.reserve(32); while (true) { - Vertex_handle tmp = nearest; - adjacent_vertices(nearest, std::back_inserter(vs)); - for (typename std::vector::const_iterator - vsit = vs.begin(); vsit != vs.end(); ++vsit) - tmp = nearest_power_vertex(p, tmp, *vsit); - if (tmp == nearest) - break; - vs.clear(); - nearest = tmp; + Vertex_handle tmp = nearest; + adjacent_vertices(nearest, std::back_inserter(vs)); + for (typename std::vector::const_iterator + vsit = vs.begin(); vsit != vs.end(); ++vsit) + tmp = nearest_power_vertex(p, tmp, *vsit); + if (tmp == nearest) + break; + vs.clear(); + nearest = tmp; } return nearest; -} + } -template < class Gt, class Tds > -typename Regular_triangulation_3::Bare_point -Regular_triangulation_3:: +template < class Gt, class Tds, class Lds > +typename Regular_triangulation_3::Bare_point +Regular_triangulation_3:: dual(Cell_handle c) const { CGAL_triangulation_precondition(dimension()==3); @@ -952,59 +1344,59 @@ dual(Cell_handle c) const return c->weighted_circumcenter(geom_traits()); } -template < class Gt, class Tds > -typename Regular_triangulation_3::Object -Regular_triangulation_3:: -dual(Cell_handle c, int i) const -{ - CGAL_triangulation_precondition(dimension()>=2); - CGAL_triangulation_precondition( ! is_infinite(c,i) ); + template < class Gt, class Tds, class Lds > + typename Regular_triangulation_3::Object + Regular_triangulation_3:: + dual(Cell_handle c, int i) const + { + CGAL_triangulation_precondition(dimension()>=2); + CGAL_triangulation_precondition( ! is_infinite(c,i) ); - if ( dimension() == 2 ) { - CGAL_triangulation_precondition( i == 3 ); - return construct_object( - construct_weighted_circumcenter(c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point()) ); - } + if ( dimension() == 2 ) { + CGAL_triangulation_precondition( i == 3 ); + return construct_object( + construct_weighted_circumcenter(c->vertex(0)->point(), + c->vertex(1)->point(), + c->vertex(2)->point()) ); + } - // dimension() == 3 - Cell_handle n = c->neighbor(i); - if ( ! is_infinite(c) && ! is_infinite(n) ) - return construct_object(construct_segment( dual(c), dual(n) )); + // dimension() == 3 + Cell_handle n = c->neighbor(i); + if ( ! is_infinite(c) && ! is_infinite(n) ) + return construct_object(construct_segment( dual(c), dual(n) )); - // either n or c is infinite - int in; - if ( is_infinite(c) ) - in = n->index(c); - else { - n = c; - in = i; - } - // n now denotes a finite cell, either c or c->neighbor(i) - int ind[3] = {(in+1)&3,(in+2)&3,(in+3)&3}; - if ( (in&1) == 1 ) + // either n or c is infinite + int in; + if ( is_infinite(c) ) + in = n->index(c); + else { + n = c; + in = i; + } + // n now denotes a finite cell, either c or c->neighbor(i) + int ind[3] = {(in+1)&3,(in+2)&3,(in+3)&3}; + if ( (in&1) == 1 ) std::swap(ind[0], ind[1]); - const Weighted_point& p = n->vertex(ind[0])->point(); - const Weighted_point& q = n->vertex(ind[1])->point(); - const Weighted_point& r = n->vertex(ind[2])->point(); + const Weighted_point& p = n->vertex(ind[0])->point(); + const Weighted_point& q = n->vertex(ind[1])->point(); + const Weighted_point& r = n->vertex(ind[2])->point(); - Line l = - construct_perpendicular_line( construct_plane(p,q,r), - construct_weighted_circumcenter(p,q,r) ); - return construct_object(construct_ray( dual(n), l)); -} + Line l = + construct_perpendicular_line( construct_plane(p,q,r), + construct_weighted_circumcenter(p,q,r) ); + return construct_object(construct_ray( dual(n), l)); + } -template < class Gt, class Tds > -Oriented_side -Regular_triangulation_3:: -side_of_oriented_power_sphere(const Weighted_point &p0, - const Weighted_point &p1, - const Weighted_point &p2, - const Weighted_point &p3, - const Weighted_point &p, bool perturb) const -{ + template < class Gt, class Tds, class Lds > + Oriented_side + Regular_triangulation_3:: + side_of_oriented_power_sphere(const Weighted_point &p0, + const Weighted_point &p1, + const Weighted_point &p2, + const Weighted_point &p3, + const Weighted_point &p, bool perturb) const + { CGAL_triangulation_precondition( orientation(p0, p1, p2, p3) == POSITIVE ); using namespace boost; @@ -1012,109 +1404,109 @@ side_of_oriented_power_sphere(const Weighted_point &p0, Oriented_side os = power_test(p0, p1, p2, p3, p); if (os != ON_ORIENTED_BOUNDARY || !perturb) - return os; + return os; // We are now in a degenerate case => we do a symbolic perturbation. // We sort the points lexicographically. const Weighted_point * points[5] = {&p0, &p1, &p2, &p3, &p}; std::sort(points, points + 5, - boost::bind(geom_traits().compare_xyz_3_object(), - boost::bind(Dereference(), _1), - boost::bind(Dereference(), _2)) == SMALLER); + boost::bind(geom_traits().compare_xyz_3_object(), + boost::bind(Dereference(), _1), + boost::bind(Dereference(), _2)) == SMALLER); // We successively look whether the leading monomial, then 2nd monomial // of the determinant has non null coefficient. for (int i=4; i>1; --i) { - if (points[i] == &p) - return ON_NEGATIVE_SIDE; // since p0 p1 p2 p3 are non coplanar - // and positively oriented - Orientation o; - if (points[i] == &p3 && (o = orientation(p0,p1,p2,p)) != COPLANAR ) - return o; - if (points[i] == &p2 && (o = orientation(p0,p1,p,p3)) != COPLANAR ) - return o; - if (points[i] == &p1 && (o = orientation(p0,p,p2,p3)) != COPLANAR ) - return o; - if (points[i] == &p0 && (o = orientation(p,p1,p2,p3)) != COPLANAR ) - return o; + if (points[i] == &p) + return ON_NEGATIVE_SIDE; // since p0 p1 p2 p3 are non coplanar + // and positively oriented + Orientation o; + if (points[i] == &p3 && (o = orientation(p0,p1,p2,p)) != COPLANAR ) + return o; + if (points[i] == &p2 && (o = orientation(p0,p1,p,p3)) != COPLANAR ) + return o; + if (points[i] == &p1 && (o = orientation(p0,p,p2,p3)) != COPLANAR ) + return o; + if (points[i] == &p0 && (o = orientation(p,p1,p2,p3)) != COPLANAR ) + return o; } CGAL_triangulation_assertion(false); return ON_NEGATIVE_SIDE; -} - - -template < class Gt, class Tds > -Bounded_side -Regular_triangulation_3:: -side_of_power_sphere(Cell_handle c, const Weighted_point &p, - bool perturb) const -{ - CGAL_triangulation_precondition( dimension() == 3 ); - int i3; - if ( ! c->has_vertex( infinite_vertex(), i3 ) ) { - return Bounded_side( side_of_oriented_power_sphere(c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point(), - c->vertex(3)->point(), - p, perturb) ); - } - // else infinite cell : - int i0,i1,i2; - if ( (i3%2) == 1 ) { - i0 = (i3+1)&3; - i1 = (i3+2)&3; - i2 = (i3+3)&3; - } - else { - i0 = (i3+2)&3; - i1 = (i3+1)&3; - i2 = (i3+3)&3; } - // general case - Orientation o = orientation(c->vertex(i0)->point(), - c->vertex(i1)->point(), - c->vertex(i2)->point(), p); - if (o != ZERO) - return Bounded_side(o); - // else p coplanar with i0,i1,i2 - return side_of_bounded_power_circle(c->vertex(i0)->point(), - c->vertex(i1)->point(), - c->vertex(i2)->point(), - p, perturb); -} + template < class Gt, class Tds, class Lds > + Bounded_side + Regular_triangulation_3:: + side_of_power_sphere(Cell_handle c, const Weighted_point &p, + bool perturb) const + { + CGAL_triangulation_precondition( dimension() == 3 ); + int i3; + if ( ! c->has_vertex( infinite_vertex(), i3 ) ) { + return Bounded_side( side_of_oriented_power_sphere(c->vertex(0)->point(), + c->vertex(1)->point(), + c->vertex(2)->point(), + c->vertex(3)->point(), + p, perturb) ); + } + // else infinite cell : + int i0,i1,i2; + if ( (i3%2) == 1 ) { + i0 = (i3+1)&3; + i1 = (i3+2)&3; + i2 = (i3+3)&3; + } + else { + i0 = (i3+2)&3; + i1 = (i3+1)&3; + i2 = (i3+3)&3; + } + + // general case + Orientation o = orientation(c->vertex(i0)->point(), + c->vertex(i1)->point(), + c->vertex(i2)->point(), p); + if (o != ZERO) + return Bounded_side(o); + + // else p coplanar with i0,i1,i2 + return side_of_bounded_power_circle(c->vertex(i0)->point(), + c->vertex(i1)->point(), + c->vertex(i2)->point(), + p, perturb); + } -template < class Gt, class Tds > -Bounded_side -Regular_triangulation_3:: -side_of_bounded_power_circle(const Weighted_point &p0, - const Weighted_point &p1, - const Weighted_point &p2, - const Weighted_point &p, bool perturb) const -{ + template < class Gt, class Tds, class Lds > + Bounded_side + Regular_triangulation_3:: + side_of_bounded_power_circle(const Weighted_point &p0, + const Weighted_point &p1, + const Weighted_point &p2, + const Weighted_point &p, bool perturb) const + { CGAL_triangulation_precondition(coplanar_orientation(p0, p1, p2) != 0); if (coplanar_orientation(p0, p1, p2) == POSITIVE) - return Bounded_side (side_of_oriented_power_circle(p0, p1, p2, p, perturb)); + return Bounded_side (side_of_oriented_power_circle(p0, p1, p2, p, perturb)); // Wrong because the low level power test already does a coplanar orientation // test. // return Bounded_side (- side_of_oriented_power_circle (p0, p2, p1, p, // perturb)); return Bounded_side (side_of_oriented_power_circle(p0, p2, p1, p, perturb)); -} + } -template < class Gt, class Tds > -Oriented_side -Regular_triangulation_3:: -side_of_oriented_power_circle(const Weighted_point &p0, - const Weighted_point &p1, - const Weighted_point &p2, - const Weighted_point &p, bool perturb) const -{ + template < class Gt, class Tds, class Lds > + Oriented_side + Regular_triangulation_3:: + side_of_oriented_power_circle(const Weighted_point &p0, + const Weighted_point &p1, + const Weighted_point &p2, + const Weighted_point &p, bool perturb) const + { CGAL_triangulation_precondition( coplanar_orientation(p0, p1, p2) == POSITIVE ); using namespace boost; @@ -1122,398 +1514,422 @@ side_of_oriented_power_circle(const Weighted_point &p0, Oriented_side os = power_test(p0, p1, p2, p); if (os != ON_ORIENTED_BOUNDARY || !perturb) - return os; + return os; // We are now in a degenerate case => we do a symbolic perturbation. // We sort the points lexicographically. const Weighted_point * points[4] = {&p0, &p1, &p2, &p}; std::sort(points, points + 4, - boost::bind(geom_traits().compare_xyz_3_object(), - boost::bind(Dereference(), _1), - boost::bind(Dereference(), _2)) == SMALLER); + boost::bind(geom_traits().compare_xyz_3_object(), + boost::bind(Dereference(), _1), + boost::bind(Dereference(), _2)) == SMALLER); // We successively look whether the leading monomial, then 2nd monomial // of the determinant has non null coefficient. // 2 iterations are enough (cf paper) for (int i=3; i>1; --i) { - if (points[i] == &p) - return ON_NEGATIVE_SIDE; // since p0 p1 p2 are non collinear - // and positively oriented - Orientation o; - if (points[i] == &p2 && (o = coplanar_orientation(p0,p1,p)) != COPLANAR ) - return o; - if (points[i] == &p1 && (o = coplanar_orientation(p0,p,p2)) != COPLANAR ) - return o; - if (points[i] == &p0 && (o = coplanar_orientation(p,p1,p2)) != COPLANAR ) - return o; + if (points[i] == &p) + return ON_NEGATIVE_SIDE; // since p0 p1 p2 are non collinear + // and positively oriented + Orientation o; + if (points[i] == &p2 && (o = coplanar_orientation(p0,p1,p)) != COPLANAR ) + return o; + if (points[i] == &p1 && (o = coplanar_orientation(p0,p,p2)) != COPLANAR ) + return o; + if (points[i] == &p0 && (o = coplanar_orientation(p,p1,p2)) != COPLANAR ) + return o; } CGAL_triangulation_assertion(false); return ON_NEGATIVE_SIDE; -} + } -template < class Gt, class Tds > -Bounded_side -Regular_triangulation_3:: -side_of_power_circle(Cell_handle c, int i, const Weighted_point &p, - bool perturb) const -{ - CGAL_triangulation_precondition( dimension() >= 2 ); - int i3 = 5; - if ( dimension() == 2 ) { - CGAL_triangulation_precondition( i == 3 ); - // the triangulation is supposed to be valid, ie the facet - // with vertices 0 1 2 in this order is positively oriented - if ( ! c->has_vertex( infinite_vertex(), i3 ) ) - return Bounded_side( side_of_oriented_power_circle(c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point(), - p, perturb) ); - // else infinite facet + template < class Gt, class Tds, class Lds > + Bounded_side + Regular_triangulation_3:: + side_of_power_circle(Cell_handle c, int i, const Weighted_point &p, + bool perturb) const + { + CGAL_triangulation_precondition( dimension() >= 2 ); + int i3 = 5; + if ( dimension() == 2 ) { + CGAL_triangulation_precondition( i == 3 ); + // the triangulation is supposed to be valid, ie the facet + // with vertices 0 1 2 in this order is positively oriented + if ( ! c->has_vertex( infinite_vertex(), i3 ) ) + return Bounded_side( side_of_oriented_power_circle(c->vertex(0)->point(), + c->vertex(1)->point(), + c->vertex(2)->point(), + p, perturb) ); + // else infinite facet + // v1, v2 finite vertices of the facet such that v1,v2,infinite + // is positively oriented + Vertex_handle v1 = c->vertex( ccw(i3) ), + v2 = c->vertex( cw(i3) ); + CGAL_triangulation_assertion(coplanar_orientation(v1->point(), v2->point(), + mirror_vertex(c, i3)->point()) == NEGATIVE); + Orientation o = coplanar_orientation(v1->point(), v2->point(), p); + if ( o != ZERO ) + return Bounded_side( o ); + // case when p collinear with v1v2 + return side_of_bounded_power_segment(v1->point(), + v2->point(), + p, perturb); + }// dim 2 + + // else dimension == 3 + CGAL_triangulation_precondition( (i >= 0) && (i < 4) ); + if ( ( ! c->has_vertex(infinite_vertex(),i3) ) || ( i3 != i ) ) { + // finite facet + // initialization of i0 i1 i2, vertices of the facet positively + // oriented (if the triangulation is valid) + int i0 = (i>0) ? 0 : 1; + int i1 = (i>1) ? 1 : 2; + int i2 = (i>2) ? 2 : 3; + CGAL_triangulation_precondition(this->coplanar(c->vertex(i0)->point(), + c->vertex(i1)->point(), + c->vertex(i2)->point(), p)); + return side_of_bounded_power_circle(c->vertex(i0)->point(), + c->vertex(i1)->point(), + c->vertex(i2)->point(), + p, perturb); + } + //else infinite facet // v1, v2 finite vertices of the facet such that v1,v2,infinite // is positively oriented - Vertex_handle v1 = c->vertex( ccw(i3) ), - v2 = c->vertex( cw(i3) ); - CGAL_triangulation_assertion(coplanar_orientation(v1->point(), v2->point(), - mirror_vertex(c, i3)->point()) == NEGATIVE); - Orientation o = coplanar_orientation(v1->point(), v2->point(), p); + Vertex_handle v1 = c->vertex( next_around_edge(i3,i) ), + v2 = c->vertex( next_around_edge(i,i3) ); + Orientation o = (Orientation) + (coplanar_orientation( v1->point(), v2->point(), + c->vertex(i)->point()) * + coplanar_orientation( v1->point(), v2->point(), p)); + // then the code is duplicated from 2d case if ( o != ZERO ) - return Bounded_side( o ); - // case when p collinear with v1v2 - return side_of_bounded_power_segment(v1->point(), - v2->point(), - p, perturb); - }// dim 2 - - // else dimension == 3 - CGAL_triangulation_precondition( (i >= 0) && (i < 4) ); - if ( ( ! c->has_vertex(infinite_vertex(),i3) ) || ( i3 != i ) ) { - // finite facet - // initialization of i0 i1 i2, vertices of the facet positively - // oriented (if the triangulation is valid) - int i0 = (i>0) ? 0 : 1; - int i1 = (i>1) ? 1 : 2; - int i2 = (i>2) ? 2 : 3; - CGAL_triangulation_precondition(this->coplanar(c->vertex(i0)->point(), - c->vertex(i1)->point(), - c->vertex(i2)->point(), p)); - return side_of_bounded_power_circle(c->vertex(i0)->point(), - c->vertex(i1)->point(), - c->vertex(i2)->point(), - p, perturb); - } - //else infinite facet - // v1, v2 finite vertices of the facet such that v1,v2,infinite - // is positively oriented - Vertex_handle v1 = c->vertex( next_around_edge(i3,i) ), - v2 = c->vertex( next_around_edge(i,i3) ); - Orientation o = (Orientation) - (coplanar_orientation( v1->point(), v2->point(), - c->vertex(i)->point()) * - coplanar_orientation( v1->point(), v2->point(), p)); - // then the code is duplicated from 2d case - if ( o != ZERO ) return Bounded_side( -o ); - // because p is in f iff - // it is not on the same side of v1v2 as c->vertex(i) - // case when p collinear with v1v2 : - return side_of_bounded_power_segment(v1->point(), - v2->point(), - p, perturb); -} + // because p is in f iff + // it is not on the same side of v1v2 as c->vertex(i) + // case when p collinear with v1v2 : + return side_of_bounded_power_segment(v1->point(), + v2->point(), + p, perturb); + } -template < class Gt, class Tds > -Bounded_side -Regular_triangulation_3:: -side_of_bounded_power_segment(const Weighted_point &p0, - const Weighted_point &p1, - const Weighted_point &p, bool perturb) const -{ + template < class Gt, class Tds, class Lds > + Bounded_side + Regular_triangulation_3:: + side_of_bounded_power_segment(const Weighted_point &p0, + const Weighted_point &p1, + const Weighted_point &p, bool perturb) const + { Oriented_side os = power_test(p0, p1, p); if (os != ON_ORIENTED_BOUNDARY || !perturb) - return Bounded_side(os); + return Bounded_side(os); // We are now in a degenerate case => we do a symbolic perturbation. switch (this->collinear_position(p0, p, p1)) { - case Tr_Base::BEFORE: case Tr_Base::AFTER: - return ON_UNBOUNDED_SIDE; - case Tr_Base::MIDDLE: - return ON_BOUNDED_SIDE; - default: - ; + case Tr_Base::BEFORE: case Tr_Base::AFTER: + return ON_UNBOUNDED_SIDE; + case Tr_Base::MIDDLE: + return ON_BOUNDED_SIDE; + default: + ; } CGAL_triangulation_assertion(false); return ON_UNBOUNDED_SIDE; -} + } -template < class Gt, class Tds > -Bounded_side -Regular_triangulation_3:: -side_of_power_segment(Cell_handle c, const Weighted_point &p, - bool perturb) const -{ - CGAL_triangulation_precondition( dimension() == 1 ); - if ( ! is_infinite(c,0,1) ) - return side_of_bounded_power_segment(c->vertex(0)->point(), - c->vertex(1)->point(), - p, perturb); - Locate_type lt; int i; - Bounded_side soe = side_of_edge( p, c, lt, i ); - if (soe != ON_BOUNDARY) - return soe; - // Either we compare weights, or we use the finite neighboring edge - Cell_handle finite_neighbor = c->neighbor(c->index(infinite_vertex())); - CGAL_triangulation_assertion(!is_infinite(finite_neighbor,0,1)); - return side_of_bounded_power_segment(finite_neighbor->vertex(0)->point(), - finite_neighbor->vertex(1)->point(), - p, perturb); -} + template < class Gt, class Tds, class Lds > + Bounded_side + Regular_triangulation_3:: + side_of_power_segment(Cell_handle c, const Weighted_point &p, + bool perturb) const + { + CGAL_triangulation_precondition( dimension() == 1 ); + if ( ! is_infinite(c,0,1) ) + return side_of_bounded_power_segment(c->vertex(0)->point(), + c->vertex(1)->point(), + p, perturb); + Locate_type lt; int i; + Bounded_side soe = side_of_edge( p, c, lt, i ); + if (soe != ON_BOUNDARY) + return soe; + // Either we compare weights, or we use the finite neighboring edge + Cell_handle finite_neighbor = c->neighbor(c->index(infinite_vertex())); + CGAL_triangulation_assertion(!is_infinite(finite_neighbor,0,1)); + return side_of_bounded_power_segment(finite_neighbor->vertex(0)->point(), + finite_neighbor->vertex(1)->point(), + p, perturb); + } -template < class Gt, class Tds > -bool -Regular_triangulation_3:: -is_Gabriel(const Facet& f) const -{ - return is_Gabriel(f.first, f.second); -} + template < class Gt, class Tds, class Lds > + bool + Regular_triangulation_3:: + is_Gabriel(const Facet& f) const + { + return is_Gabriel(f.first, f.second); + } -template < class Gt, class Tds > -bool -Regular_triangulation_3:: -is_Gabriel(Cell_handle c, int i) const -{ - CGAL_triangulation_precondition(dimension() == 3 && !is_infinite(c,i)); - typename Geom_traits::Side_of_bounded_orthogonal_sphere_3 - side_of_bounded_orthogonal_sphere = - geom_traits().side_of_bounded_orthogonal_sphere_3_object(); + template < class Gt, class Tds, class Lds > + bool + Regular_triangulation_3:: + is_Gabriel(Cell_handle c, int i) const + { + CGAL_triangulation_precondition(dimension() == 3 && !is_infinite(c,i)); + typename Geom_traits::Side_of_bounded_orthogonal_sphere_3 + side_of_bounded_orthogonal_sphere = + geom_traits().side_of_bounded_orthogonal_sphere_3_object(); - if ((!is_infinite(c->vertex(i))) && + if ((!is_infinite(c->vertex(i))) && side_of_bounded_orthogonal_sphere( - c->vertex(vertex_triple_index(i,0))->point(), - c->vertex(vertex_triple_index(i,1))->point(), - c->vertex(vertex_triple_index(i,2))->point(), - c->vertex(i)->point()) == ON_BOUNDED_SIDE ) return false; + c->vertex(vertex_triple_index(i,0))->point(), + c->vertex(vertex_triple_index(i,1))->point(), + c->vertex(vertex_triple_index(i,2))->point(), + c->vertex(i)->point()) == ON_BOUNDED_SIDE ) return false; - Cell_handle neighbor = c->neighbor(i); - int in = neighbor->index(c); + Cell_handle neighbor = c->neighbor(i); + int in = neighbor->index(c); - if ((!is_infinite(neighbor->vertex(in))) && + if ((!is_infinite(neighbor->vertex(in))) && side_of_bounded_orthogonal_sphere( - c->vertex(vertex_triple_index(i,0))->point(), - c->vertex(vertex_triple_index(i,1))->point(), - c->vertex(vertex_triple_index(i,2))->point(), - neighbor->vertex(in)->point()) == ON_BOUNDED_SIDE ) return false; + c->vertex(vertex_triple_index(i,0))->point(), + c->vertex(vertex_triple_index(i,1))->point(), + c->vertex(vertex_triple_index(i,2))->point(), + neighbor->vertex(in)->point()) == ON_BOUNDED_SIDE ) return false; - return true; -} + return true; + } -template < class Gt, class Tds > -bool -Regular_triangulation_3:: -is_Gabriel(const Edge& e) const -{ - return is_Gabriel(e.first, e.second, e.third); -} + template < class Gt, class Tds, class Lds > + bool + Regular_triangulation_3:: + is_Gabriel(const Edge& e) const + { + return is_Gabriel(e.first, e.second, e.third); + } -template < class Gt, class Tds > -bool -Regular_triangulation_3:: -is_Gabriel(Cell_handle c, int i, int j) const -{ - CGAL_triangulation_precondition(dimension() == 3 && !is_infinite(c,i,j)); - typename Geom_traits::Side_of_bounded_orthogonal_sphere_3 - side_of_bounded_orthogonal_sphere = - geom_traits().side_of_bounded_orthogonal_sphere_3_object(); + template < class Gt, class Tds, class Lds > + bool + Regular_triangulation_3:: + is_Gabriel(Cell_handle c, int i, int j) const + { + CGAL_triangulation_precondition(dimension() == 3 && !is_infinite(c,i,j)); + typename Geom_traits::Side_of_bounded_orthogonal_sphere_3 + side_of_bounded_orthogonal_sphere = + geom_traits().side_of_bounded_orthogonal_sphere_3_object(); - Facet_circulator fcirc = incident_facets(c,i,j), - fdone(fcirc); - Vertex_handle v1 = c->vertex(i); - Vertex_handle v2 = c->vertex(j); - do { + Facet_circulator fcirc = incident_facets(c,i,j), + fdone(fcirc); + Vertex_handle v1 = c->vertex(i); + Vertex_handle v2 = c->vertex(j); + do { // test whether the vertex of cc opposite to *fcirc // is inside the sphere defined by the edge e = (s, i,j) Cell_handle cc = (*fcirc).first; int ii = (*fcirc).second; if (!is_infinite(cc->vertex(ii)) && - side_of_bounded_orthogonal_sphere( v1->point(), - v2->point(), - cc->vertex(ii)->point()) - == ON_BOUNDED_SIDE ) return false; - } while(++fcirc != fdone); - return true; -} + side_of_bounded_orthogonal_sphere( v1->point(), + v2->point(), + cc->vertex(ii)->point()) + == ON_BOUNDED_SIDE ) return false; + } while(++fcirc != fdone); + return true; + } -template < class Gt, class Tds > -bool -Regular_triangulation_3:: -is_Gabriel(Vertex_handle v) const -{ - return nearest_power_vertex( v->point().point(), v->cell()) == v; -} + template < class Gt, class Tds, class Lds > + bool + Regular_triangulation_3:: + is_Gabriel(Vertex_handle v) const + { + return nearest_power_vertex( v->point().point(), v->cell()) == v; + } -template < class Gt, class Tds > -typename Regular_triangulation_3::Vertex_handle -Regular_triangulation_3:: -insert(const Weighted_point & p, Cell_handle start) -{ + // Returns + template < class Gt, class Tds, class Lds > + typename Regular_triangulation_3::Vertex_handle + Regular_triangulation_3:: + insert(const Weighted_point & p, Cell_handle start, bool *could_lock_zone) + { Locate_type lt; int li, lj; - Cell_handle c = locate(p, lt, li, lj, start); - return insert(p, lt, c, li, lj); -} -template < class Gt, class Tds > -typename Regular_triangulation_3::Vertex_handle -Regular_triangulation_3:: -insert(const Weighted_point & p, Locate_type lt, Cell_handle c, int li, int lj) -{ - switch (dimension()) { - case 3: + // Parallel + if (could_lock_zone) { - Conflict_tester_3 tester (p, this); - return insert_in_conflict(p, lt,c,li,lj, tester, hidden_point_visitor); + Cell_handle c = locate(p, lt, li, lj, start, could_lock_zone); + if (*could_lock_zone) + return insert(p, lt, c, li, lj, could_lock_zone); + else + return Vertex_handle(); } - case 2: + // Sequential + else { - Conflict_tester_2 tester (p, this); - return insert_in_conflict(p, lt,c,li,lj, tester, hidden_point_visitor); - } - case 1: - { - Conflict_tester_1 tester (p, this); - return insert_in_conflict(p, lt,c,li,lj, tester, hidden_point_visitor); + Cell_handle c = locate(p, lt, li, lj, start); + return insert(p, lt, c, li, lj); } } - Conflict_tester_0 tester (p, this); - return insert_in_conflict(p, lt,c,li,lj, tester, hidden_point_visitor); -} + template < class Gt, class Tds, class Lds > + typename Regular_triangulation_3::Vertex_handle + Regular_triangulation_3:: + insert(const Weighted_point & p, Locate_type lt, Cell_handle c, + int li, int lj, bool *could_lock_zone) + { + switch (dimension()) { + case 3: + { + Conflict_tester_3 tester (p, this); + return insert_in_conflict(p, lt,c,li,lj, tester, + get_hidden_point_visitor(), + could_lock_zone); + } + case 2: + { + Conflict_tester_2 tester (p, this); + return insert_in_conflict(p, lt,c,li,lj, tester, + get_hidden_point_visitor(), + could_lock_zone); + } + case 1: + { + Conflict_tester_1 tester (p, this); + return insert_in_conflict(p, lt,c,li,lj, tester, + get_hidden_point_visitor(), + could_lock_zone); + } + } + + Conflict_tester_0 tester (p, this); + return insert_in_conflict(p, lt,c,li,lj, tester, + get_hidden_point_visitor(), + could_lock_zone); + } -template < class Gt, class Tds > -template -typename Regular_triangulation_3::Vertex_handle -Regular_triangulation_3:: -insert_in_hole(const Weighted_point & p, CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i) -{ - CGAL_triangulation_precondition(cell_begin != cell_end); - - hidden_point_visitor.process_cells_in_conflict(cell_begin,cell_end); - - Vertex_handle v = - Tr_Base::insert_in_hole(p, cell_begin, cell_end, begin, i); - - // Store the hidden points in their new cells and hide vertices that - // have to be hidden - hidden_point_visitor.reinsert_vertices(v); - return v; -} + template < class Gt, class Tds, class Lds > + template + typename Regular_triangulation_3::Vertex_handle + Regular_triangulation_3:: + insert_in_hole(const Weighted_point & p, CellIt cell_begin, CellIt cell_end, + Cell_handle begin, int i) + { + CGAL_triangulation_precondition(cell_begin != cell_end); + + get_hidden_point_visitor().process_cells_in_conflict(cell_begin,cell_end); + + Vertex_handle v = + Tr_Base::insert_in_hole(p, cell_begin, cell_end, begin, i); + + // Store the hidden points in their new cells and hide vertices that + // have to be hidden + get_hidden_point_visitor().reinsert_vertices(v); + return v; + } -template < class Gt, class Tds > -template -typename Regular_triangulation_3::Vertex_handle -Regular_triangulation_3:: -insert_in_hole(const Weighted_point & p, CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i, Vertex_handle newv) -{ - CGAL_triangulation_precondition(cell_begin != cell_end); + template < class Gt, class Tds, class Lds > + template + typename Regular_triangulation_3::Vertex_handle + Regular_triangulation_3:: + insert_in_hole(const Weighted_point & p, CellIt cell_begin, CellIt cell_end, + Cell_handle begin, int i, Vertex_handle newv) + { + CGAL_triangulation_precondition(cell_begin != cell_end); - hidden_point_visitor.process_cells_in_conflict(cell_begin,cell_end); + get_hidden_point_visitor().process_cells_in_conflict(cell_begin,cell_end); - Vertex_handle v = - Tr_Base::insert_in_hole(p, cell_begin, cell_end, begin, i, newv); + Vertex_handle v = + Tr_Base::insert_in_hole(p, cell_begin, cell_end, begin, i, newv); - // Store the hidden points in their new cells and hide vertices that - // have to be hidden - hidden_point_visitor.reinsert_vertices(v); - return v; -} + // Store the hidden points in their new cells and hide vertices that + // have to be hidden + get_hidden_point_visitor().reinsert_vertices(v); + return v; + } -template -template -class Regular_triangulation_3::Vertex_remover { - typedef RegularTriangulation_3 Regular; - typedef typename Gt::Point_3 Point; -public: - typedef typename std::vector::iterator + template + template + class Regular_triangulation_3::Vertex_remover { + typedef RegularTriangulation_3 Regular; + typedef typename Gt::Point_3 Point; + public: + typedef typename std::vector::iterator Hidden_points_iterator; - Vertex_remover(Regular &tmp_) : tmp(tmp_) {} + Vertex_remover(Regular &tmp_) : tmp(tmp_) {} - Regular &tmp; + Regular &tmp; - void add_hidden_points(Cell_handle ch) { - std::copy (ch->hidden_points_begin(), ch->hidden_points_end(), - std::back_inserter(hidden)); - } + void add_hidden_points(Cell_handle ch) { + std::copy (ch->hidden_points_begin(), ch->hidden_points_end(), + std::back_inserter(hidden)); + } - Hidden_points_iterator hidden_points_begin() { - return hidden.begin(); - } - Hidden_points_iterator hidden_points_end() { - return hidden.end(); - } + Hidden_points_iterator hidden_points_begin() { + return hidden.begin(); + } + Hidden_points_iterator hidden_points_end() { + return hidden.end(); + } - Bounded_side side_of_bounded_circle(const Point &p, const Point &q, - const Point &r, const Point &s, bool perturb = false) const { - return tmp.side_of_bounded_power_circle(p,q,r,s,perturb); - } + Bounded_side side_of_bounded_circle(const Point &p, const Point &q, + const Point &r, const Point &s, bool perturb = false) const { + return tmp.side_of_bounded_power_circle(p,q,r,s,perturb); + } -private: - // The removal of v may un-hide some points, - // Space functions output them. - std::vector hidden; -}; + private: + // The removal of v may un-hide some points, + // Space functions output them. + std::vector hidden; + }; -// The displacement method works only -// on regular triangulation without hidden points at any time -// the vertex inserter is used only -// for the purpose of displacements -template -template -class Regular_triangulation_3::Vertex_inserter { - typedef RegularTriangulation_3 Regular; -public: - typedef Nullptr_t Hidden_points_iterator; + // The displacement method works only + // on regular triangulation without hidden points at any time + // the vertex inserter is used only + // for the purpose of displacements + template + template + class Regular_triangulation_3::Vertex_inserter { + typedef RegularTriangulation_3 Regular; + public: + typedef Nullptr_t Hidden_points_iterator; - Vertex_inserter(Regular &tmp_) : tmp(tmp_) {} + Vertex_inserter(Regular &tmp_) : tmp(tmp_) {} - Regular &tmp; + Regular &tmp; - void add_hidden_points(Cell_handle) {} - Hidden_points_iterator hidden_points_begin() { return NULL; } - Hidden_points_iterator hidden_points_end() { return NULL; } + void add_hidden_points(Cell_handle) {} + Hidden_points_iterator hidden_points_begin() { return NULL; } + Hidden_points_iterator hidden_points_end() { return NULL; } - Vertex_handle insert(const Weighted_point& p, - Locate_type lt, Cell_handle c, int li, int lj) { - return tmp.insert(p, lt, c, li, lj); - } + Vertex_handle insert(const Weighted_point& p, + Locate_type lt, Cell_handle c, int li, int lj) { + return tmp.insert(p, lt, c, li, lj); + } - Vertex_handle insert(const Weighted_point& p, Cell_handle c) { - return tmp.insert(p, c); - } + Vertex_handle insert(const Weighted_point& p, Cell_handle c) { + return tmp.insert(p, c); + } - Vertex_handle insert(const Weighted_point& p) { - return tmp.insert(p); - } -}; + Vertex_handle insert(const Weighted_point& p) { + return tmp.insert(p); + } + }; -template < class Gt, class Tds > -void -Regular_triangulation_3:: -remove(Vertex_handle v) -{ + template < class Gt, class Tds, class Lds > + void + Regular_triangulation_3:: + remove(Vertex_handle v) + { Cell_handle c; if (dimension() > 0) - c = v->cell()->neighbor(v->cell()->index(v)); + c = v->cell()->neighbor(v->cell()->index(v)); Self tmp; Vertex_remover remover(tmp); @@ -1521,20 +1937,64 @@ remove(Vertex_handle v) // Re-insert the points that v was hiding. for (typename Vertex_remover::Hidden_points_iterator - hi = remover.hidden_points_begin(); - hi != remover.hidden_points_end(); ++hi) { - Vertex_handle hv = insert (*hi, c); - if (hv != Vertex_handle()) c = hv->cell(); + hi = remover.hidden_points_begin(); + hi != remover.hidden_points_end(); ++hi) { + Vertex_handle hv = insert (*hi, c); + if (hv != Vertex_handle()) c = hv->cell(); } CGAL_triangulation_expensive_postcondition (is_valid()); -} + } -// Again, verbatim copy from Delaunay. -template < class Gt, class Tds > -typename Regular_triangulation_3::Vertex_handle -Regular_triangulation_3:: -move_point(Vertex_handle v, const Weighted_point & p) -{ + template < class Gt, class Tds, class Lds > + bool + Regular_triangulation_3:: + remove(Vertex_handle v, bool *could_lock_zone) + { + bool removed = true; + + // Locking vertex v... + if (!this->try_lock_vertex(v)) + { + *could_lock_zone = false; + } + else + { + Vertex_handle hint = (v->cell()->vertex(0) == v ? + v->cell()->vertex(1) : v->cell()->vertex(0)); + + Self tmp; + Vertex_remover remover(tmp); + removed = Tr_Base::remove(v, remover, could_lock_zone); + + if (*could_lock_zone && removed) + { + // Re-insert the points that v was hiding. + for (typename Vertex_remover::Hidden_points_iterator + hi = remover.hidden_points_begin(); + hi != remover.hidden_points_end(); ++hi) + { + bool could_lock_zone = false; + Vertex_handle hv; + while (!could_lock_zone) + { + hv = insert (*hi, hint, &could_lock_zone); + } + if (hv != Vertex_handle()) + hint = hv; + } + CGAL_triangulation_expensive_postcondition (is_valid()); + } + } + + return removed; + } + + // Again, verbatim copy from Delaunay. + template < class Gt, class Tds, class Lds > + typename Regular_triangulation_3::Vertex_handle + Regular_triangulation_3:: + move_point(Vertex_handle v, const Weighted_point & p) + { CGAL_triangulation_precondition(! is_infinite(v)); CGAL_triangulation_expensive_precondition(is_vertex(v)); @@ -1549,125 +2009,125 @@ move_point(Vertex_handle v, const Weighted_point & p) remove(v); if (dimension() <= 0) - return insert(p); + return insert(p); return insert(p, old_neighbor->cell()); -} + } -// Displacement works only for Regular triangulation -// without hidden points at any time -template < class Gt, class Tds > -typename Regular_triangulation_3::Vertex_handle -Regular_triangulation_3:: -move_if_no_collision(Vertex_handle v, const Weighted_point &p) -{ - Self tmp; - Vertex_remover remover (tmp); - Vertex_inserter inserter (*this); - Vertex_handle res = Tr_Base::move_if_no_collision(v,p,remover,inserter); + // Displacement works only for Regular triangulation + // without hidden points at any time + template < class Gt, class Tds, class Lds > + typename Regular_triangulation_3::Vertex_handle + Regular_triangulation_3:: + move_if_no_collision(Vertex_handle v, const Weighted_point &p) + { + Self tmp; + Vertex_remover remover (tmp); + Vertex_inserter inserter (*this); + Vertex_handle res = Tr_Base::move_if_no_collision(v,p,remover,inserter); - CGAL_triangulation_expensive_postcondition(is_valid()); - return res; -} + CGAL_triangulation_expensive_postcondition(is_valid()); + return res; + } -template -typename Regular_triangulation_3::Vertex_handle -Regular_triangulation_3:: -move(Vertex_handle v, const Weighted_point &p) { - CGAL_triangulation_precondition(!is_infinite(v)); - if(v->point() == p) return v; - Self tmp; - Vertex_remover remover (tmp); - Vertex_inserter inserter (*this); - return Tr_Base::move(v,p,remover,inserter); -} + template + typename Regular_triangulation_3::Vertex_handle + Regular_triangulation_3:: + move(Vertex_handle v, const Weighted_point &p) { + CGAL_triangulation_precondition(!is_infinite(v)); + if(v->point() == p) return v; + Self tmp; + Vertex_remover remover (tmp); + Vertex_inserter inserter (*this); + return Tr_Base::move(v,p,remover,inserter); + } -template < class Gt, class Tds > -bool -Regular_triangulation_3:: -is_valid(bool verbose, int level) const -{ - if ( ! Tr_Base::is_valid(verbose,level) ) { + template < class Gt, class Tds, class Lds > + bool + Regular_triangulation_3:: + is_valid(bool verbose, int level) const + { + if ( ! Tr_Base::is_valid(verbose,level) ) { + if (verbose) + std::cerr << "invalid base triangulation" << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + + switch ( dimension() ) { + case 3: + { + for(Finite_cells_iterator it = finite_cells_begin(), end = finite_cells_end(); it != end; ++it) { + is_valid_finite(it, verbose, level); + for(int i=0; i<4; i++) { + if ( !is_infinite + (it->neighbor(i)->vertex(it->neighbor(i)->index(it))) ) { + if ( side_of_power_sphere + (it, + it->neighbor(i)->vertex(it->neighbor(i)->index(it))->point()) + == ON_BOUNDED_SIDE ) { + if (verbose) + std::cerr << "non-empty sphere " << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + } + } + } + break; + } + case 2: + { + for(Finite_facets_iterator it = finite_facets_begin(), end = finite_facets_end(); it!= end; ++it) { + is_valid_finite((*it).first, verbose, level); + for(int i=0; i<3; i++) { + if( !is_infinite + ((*it).first->neighbor(i)->vertex( (((*it).first)->neighbor(i)) + ->index((*it).first))) ) { + if ( side_of_power_circle + ( (*it).first, 3, + (*it).first->neighbor(i)-> + vertex( (((*it).first)->neighbor(i)) + ->index((*it).first) )->point() ) + == ON_BOUNDED_SIDE ) { + if (verbose) + std::cerr << "non-empty circle " << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + } + } + } + break; + } + case 1: + { + for(Finite_edges_iterator it = finite_edges_begin(), end = finite_edges_end(); it != end; ++it) { + is_valid_finite((*it).first, verbose, level); + for(int i=0; i<2; i++) { + if( !is_infinite + ((*it).first->neighbor(i)->vertex( (((*it).first)->neighbor(i)) + ->index((*it).first))) ) { + if ( side_of_power_segment + ( (*it).first, + (*it).first->neighbor(i)-> + vertex( (((*it).first)->neighbor(i)) + ->index((*it).first) )->point() ) + == ON_BOUNDED_SIDE ) { + if (verbose) + std::cerr << "non-empty edge " << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + } + } + } + break; + } + } if (verbose) - std::cerr << "invalid base triangulation" << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - - switch ( dimension() ) { - case 3: - { - for(Finite_cells_iterator it = finite_cells_begin(), end = finite_cells_end(); it != end; ++it) { - is_valid_finite(it, verbose, level); - for(int i=0; i<4; i++) { - if ( !is_infinite - (it->neighbor(i)->vertex(it->neighbor(i)->index(it))) ) { - if ( side_of_power_sphere - (it, - it->neighbor(i)->vertex(it->neighbor(i)->index(it))->point()) - == ON_BOUNDED_SIDE ) { - if (verbose) - std::cerr << "non-empty sphere " << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } - } - } - break; - } - case 2: - { - for(Finite_facets_iterator it = finite_facets_begin(), end = finite_facets_end(); it!= end; ++it) { - is_valid_finite((*it).first, verbose, level); - for(int i=0; i<3; i++) { - if( !is_infinite - ((*it).first->neighbor(i)->vertex( (((*it).first)->neighbor(i)) - ->index((*it).first))) ) { - if ( side_of_power_circle - ( (*it).first, 3, - (*it).first->neighbor(i)-> - vertex( (((*it).first)->neighbor(i)) - ->index((*it).first) )->point() ) - == ON_BOUNDED_SIDE ) { - if (verbose) - std::cerr << "non-empty circle " << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } - } - } - break; - } - case 1: - { - for(Finite_edges_iterator it = finite_edges_begin(), end = finite_edges_end(); it != end; ++it) { - is_valid_finite((*it).first, verbose, level); - for(int i=0; i<2; i++) { - if( !is_infinite - ((*it).first->neighbor(i)->vertex( (((*it).first)->neighbor(i)) - ->index((*it).first))) ) { - if ( side_of_power_segment - ( (*it).first, - (*it).first->neighbor(i)-> - vertex( (((*it).first)->neighbor(i)) - ->index((*it).first) )->point() ) - == ON_BOUNDED_SIDE ) { - if (verbose) - std::cerr << "non-empty edge " << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } - } - } - break; - } - } - if (verbose) std::cerr << "valid Regular triangulation" << std::endl; - return true; -} + return true; + } } //namespace CGAL diff --git a/Triangulation_3/include/CGAL/Triangulation_3.h b/Triangulation_3/include/CGAL/Triangulation_3.h index 4f25a549d69..3824a08471a 100644 --- a/Triangulation_3/include/CGAL/Triangulation_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_3.h @@ -17,12 +17,18 @@ // // Author(s) : Monique Teillaud // Sylvain Pion +// Clement Jamin #ifndef CGAL_TRIANGULATION_3_H #define CGAL_TRIANGULATION_3_H #include +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING +# define CGAL_PROFILE +# include +#endif + #include #include #include @@ -43,25 +49,36 @@ #include #include #include -#include #include +#include +#include + #include #include #include #include +#include #ifndef CGAL_NO_STRUCTURAL_FILTERING #include #include #endif // no CGAL_NO_STRUCTURAL_FILTERING +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif + +#define CGAL_TRIANGULATION_3_USE_THE_4_POINTS_CONSTRUCTOR + namespace CGAL { -template < class GT, class Tds = Default > class Triangulation_3; +template < class GT, class Tds = Default, + class Lock_data_structure = Default > +class Triangulation_3; -template < class GT, class Tds > std::istream& operator>> -(std::istream& is, Triangulation_3 &tr); +template < class GT, class Tds, class Lds > std::istream& operator>> +(std::istream& is, Triangulation_3 &tr); #ifndef CGAL_NO_STRUCTURAL_FILTERING namespace internal { @@ -85,21 +102,285 @@ struct Structural_filtering_selector_3 { } #endif // no CGAL_NO_STRUCTURAL_FILTERING -template < class GT, class Tds_ > -class Triangulation_3 - : public Triangulation_utils_3 +/************************************************ +// Class Triangulation_3_base +// Two versions: Sequential (no locking) / Parallel (with locking) +************************************************/ + +// Sequential (without locking) +template +class Triangulation_3_base { - friend std::istream& operator>> <> - (std::istream& is, Triangulation_3 &tr); +public: + // If Lock_data_structure_ = Default => void + typedef typename Default::Get< + Lock_data_structure_, void>::type Lock_data_structure; - typedef Triangulation_3 Self; +protected: + Triangulation_3_base() {} - typedef typename Default::Get, - Triangulation_cell_base_3 > >::type Tds; + Triangulation_3_base(Lock_data_structure *) {} + + void swap(Triangulation_3_base &tr){} + + template + struct Vertex_triple_Facet_map_generator + { + typedef std::map type; + }; + + template + struct Vertex_handle_unique_hash_map_generator + { + typedef Unique_hash_map type; + }; + +public: + bool is_parallel() const + { + return false; + } + + // LOCKS (no-op functions) + + template + bool try_lock_point(const Point_3 &p, int = 0) const + { return true; } + + template + bool try_lock_vertex(const Vertex_handle &, int = 0) const + { return true; } + + template + bool try_lock_cell(const Cell_handle &, int = 0) const + { return true; } + + template + bool try_lock_facet(const Facet &, int = 0) const + { return true; } + + template + bool is_point_locked_by_this_thread(const P3 &) const + { return false; } + + template + bool is_cell_locked_by_this_thread(const Cell_handle &) const + { return false; } + + void *get_lock_data_structure() const + { + return 0; + } + + void set_lock_data_structure(void *) const + { + } + + void unlock_all_elements() const {} + template void unlock_all_elements_but_one_point(const P3 &) const {} + + const Bbox_3 *get_bbox() const + { + return NULL; + } +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel (with locking) +template +class Triangulation_3_base +{ +public: + // If Lock_data_structure_ = Default => use Spatial_lock_grid_3 + typedef typename Default::Get< + Lock_data_structure_, Spatial_lock_grid_3 > + ::type Lock_data_structure; + +protected: + Triangulation_3_base() + : m_lock_ds(0) {} + + Triangulation_3_base(Lock_data_structure *lock_ds) + : m_lock_ds(lock_ds) {} + + void swap(Triangulation_3_base &tr) + { + std::swap(tr.m_lock_ds, m_lock_ds); + } + + template + struct Vertex_triple_Facet_map_generator + { + typedef std::map + < + Vertex_triple, + Facet, + std::less, + tbb::scalable_allocator > + > type; + }; + + template + struct Vertex_handle_unique_hash_map_generator + { + typedef Unique_hash_map > type; + }; public: + bool is_parallel() const + { + return m_lock_ds != 0; + } + + // LOCKS + template + bool try_lock_point(const Point_3 &p, int lock_radius = 0) const + { + bool locked = true; + if (m_lock_ds) + { + locked = m_lock_ds->try_lock(p, lock_radius); + } + return locked; + } + + template + bool try_lock_vertex(const Vertex_handle &vh, int lock_radius = 0) const + { + bool locked = true; + if (m_lock_ds) + { + locked = m_lock_ds->try_lock(vh->point(), lock_radius); + } + return locked; + } + + template + bool try_lock_cell(const Cell_handle &cell_handle, int lock_radius = 0) const + { + bool success = true; + // Lock the element area on the grid + for (int iVertex = 0 ; success && iVertex < 4 ; ++iVertex) + { + success = try_lock_vertex(cell_handle->vertex(iVertex), lock_radius); + } + return success; + } + + template + bool try_lock_facet(const Facet &facet, int lock_radius = 0) const + { + bool success = true; + + // Lock the element area on the grid + for (int iVertex = (facet.second+1)&3 ; + success && iVertex != facet.second ; iVertex = (iVertex+1)&3) + { + success = try_lock_vertex(facet.first->vertex(iVertex), lock_radius); + } + + return success; + } + + template + bool is_point_locked_by_this_thread(const P3 &p) const + { + bool locked = true; + if (m_lock_ds) + { + locked = m_lock_ds->is_locked_by_this_thread(p); + } + return locked; + } + + template + bool is_cell_locked_by_this_thread(const Cell_handle &cell_handle) const + { + bool locked = true; + if (m_lock_ds) + { + for (int iVertex = 0 ; locked && iVertex < 4 ; ++iVertex) + { + locked = m_lock_ds->is_locked_by_this_thread( + cell_handle->vertex(iVertex)->point()); + } + } + return locked; + } + + Lock_data_structure *get_lock_data_structure() const + { + return m_lock_ds; + } + + void set_lock_data_structure(Lock_data_structure *lock_ds) const + { + m_lock_ds = lock_ds; + } + + void unlock_all_elements() const + { + if (m_lock_ds) + m_lock_ds->unlock_all_points_locked_by_this_thread(); + } + + template + void unlock_all_elements_but_one_point(const P3 &point) const + { + if (m_lock_ds) + m_lock_ds->unlock_all_tls_locked_locations_but_one_point(point); + } + + const Bbox_3 *get_bbox() const + { + return &m_lock_ds->get_bbox(); + } + +protected: + mutable Lock_data_structure *m_lock_ds; +}; +#endif // CGAL_LINKED_WITH_TBB + +/************************************************ + * + * Triangulation_3 class + * + ************************************************/ + +template < class GT, class Tds_, class Lock_data_structure_ > +class Triangulation_3 + : public Triangulation_3_base< + // Get Concurrency_tag from TDS + typename Default::Get< Tds_, + Triangulation_data_structure_3 + < + Triangulation_vertex_base_3, + Triangulation_cell_base_3 + > + >::type::Concurrency_tag, + Lock_data_structure_> + , public Triangulation_utils_3 +{ + friend std::istream& operator>> <> + (std::istream& is, Triangulation_3 &tr); + + typedef typename Default::Get, + Triangulation_cell_base_3 > >::type Tds; + + typedef Triangulation_3 Self; + typedef Triangulation_3_base< + typename Tds::Concurrency_tag, Lock_data_structure_> Base; + +public: + + typedef typename Base::Lock_data_structure Lock_data_structure; typedef Tds Triangulation_data_structure; typedef GT Geom_traits; @@ -108,6 +389,8 @@ public: typedef typename GT::Triangle_3 Triangle; typedef typename GT::Tetrahedron_3 Tetrahedron; + typedef typename Tds::Concurrency_tag Concurrency_tag; + typedef typename Tds::Vertex Vertex; typedef typename Tds::Cell Cell; typedef typename Tds::Facet Facet; @@ -147,26 +430,31 @@ private: Infinite_tester() {} Infinite_tester(const Self *tr) - : t(tr) {} + : t(tr) {} bool operator()(const Vertex_iterator & v) const { - return t->is_infinite(v); + return t->is_infinite(v); + } + + bool operator()(typename std::vector::const_iterator v) const + { + return t->is_infinite(*v); } bool operator()(const Cell_iterator & c) const { - return t->is_infinite(c); + return t->is_infinite(c); } bool operator()(const Edge_iterator & e) const { - return t->is_infinite(*e); + return t->is_infinite(*e); } bool operator()(const Facet_iterator & f) const { - return t->is_infinite(*f); + return t->is_infinite(*f); } }; @@ -220,7 +508,7 @@ private: public: typedef Iterator_project Point_iterator; @@ -260,14 +548,14 @@ protected: Orientation orientation(const Point &p, const Point &q, - const Point &r, const Point &s) const + const Point &r, const Point &s) const { return geom_traits().orientation_3_object()(p, q, r, s); } bool coplanar(const Point &p, const Point &q, - const Point &r, const Point &s) const + const Point &r, const Point &s) const { return orientation(p, q, r, s) == COPLANAR; } @@ -298,7 +586,7 @@ protected: Tetrahedron construct_tetrahedron(const Point &p, const Point &q, - const Point &r, const Point &s) const + const Point &r, const Point &s) const { return geom_traits().construct_tetrahedron_3_object()(p, q, r, s); } @@ -317,15 +605,15 @@ protected: Comparison_result ps = compare_xyz(p, s); if (ps == EQUAL) - return SOURCE; + return SOURCE; Comparison_result st = compare_xyz(s, t); if (ps == st) - return BEFORE; + return BEFORE; Comparison_result pt = compare_xyz(p, t); if (pt == EQUAL) - return TARGET; + return TARGET; if (pt == st) - return MIDDLE; + return MIDDLE; return AFTER; } @@ -334,18 +622,48 @@ protected: infinite = _tds.insert_increase_dimension(); } + void init_tds(const Point &p0, const Point &p1, + const Point &p2, const Point &p3) + { + Vertex_handle v0, v1, v2, v3; + infinite = _tds.insert_first_finite_cell(v0, v1, v2, v3, infinite); + v0->set_point(p0); + v1->set_point(p1); + v2->set_point(p2); + v3->set_point(p3); + } + + void init_tds(const Point &p0, const Point &p1, + const Point &p2, const Point &p3, + Vertex_handle &vh0, Vertex_handle &vh1, + Vertex_handle &vh2, Vertex_handle &vh3) + { + infinite = _tds.insert_first_finite_cell(vh0, vh1, vh2, vh3, infinite); + vh0->set_point(p0); + vh1->set_point(p1); + vh2->set_point(p2); + vh3->set_point(p3); + } + public: // CONSTRUCTORS - Triangulation_3(const GT & gt = GT()) - : _tds(), _gt(gt) + Triangulation_3(const GT & gt = GT(), Lock_data_structure *lock_ds = NULL) + : Base(lock_ds), _tds(), _gt(gt) + { + init_tds(); + } + + Triangulation_3(Lock_data_structure *lock_ds, const GT & gt = GT()) + : Base(lock_ds), _tds(), _gt(gt) { init_tds(); } // copy constructor duplicates vertices and cells Triangulation_3(const Triangulation_3 & tr) - : _gt(tr._gt) + : _gt(tr._gt), + Base(tr.get_lock_data_structure()) { infinite = _tds.copy_tds(tr._tds, tr.infinite); CGAL_triangulation_expensive_postcondition(*this == tr); @@ -353,13 +671,24 @@ public: template < typename InputIterator > Triangulation_3(InputIterator first, InputIterator last, - const GT & gt = GT()) - : _gt(gt) + const GT & gt = GT(), Lock_data_structure *lock_ds = NULL) + : Base(lock_ds), _gt(gt) { init_tds(); insert(first, last); } + // Create the 3D triangulation of p0, p1, p3 and p4 + // Precondition: p0, p1, p3 and p4 MUST BE positively oriented + Triangulation_3(const Point &p0, const Point &p1, + const Point &p3, const Point &p4, + const GT & gt = GT(), Lock_data_structure *lock_ds = NULL) + : Base(lock_ds), _gt(gt) + { + CGAL_triangulation_precondition(orientation(p0, p1, p3, p4) == POSITIVE); + init_tds(p0, p1, p3, p4); + } + void clear() { _tds.clear(); @@ -368,7 +697,7 @@ public: Triangulation_3 & operator=(Triangulation_3 tr) { - // The triangulation passed as argument has been copied, + // The triangulation passed as argument has been copied, // because the parameter tr is passed by value. Then the following // swap consumes the *copy*. The original triangulation is left // untouched. @@ -383,6 +712,7 @@ public: std::swap(tr._gt, _gt); std::swap(tr.infinite, infinite); _tds.swap(tr._tds); + Base::swap(tr); } //ACCESS FUNCTIONS @@ -415,14 +745,14 @@ public: Vertex_handle infinite_vertex() const { return infinite; } - + void set_infinite_vertex(Vertex_handle v) { infinite=v;} Cell_handle infinite_cell() const { CGAL_triangulation_assertion(infinite_vertex()->cell()-> - has_vertex(infinite_vertex())); + has_vertex(infinite_vertex())); return infinite_vertex()->cell(); } @@ -433,9 +763,9 @@ public: CGAL_triangulation_precondition( dimension() == 3 ); CGAL_triangulation_precondition( ! is_infinite(c) ); return construct_tetrahedron(c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point(), - c->vertex(3)->point()); + c->vertex(1)->point(), + c->vertex(2)->point(), + c->vertex(3)->point()); } Triangle triangle(const Cell_handle c, int i) const; @@ -481,23 +811,22 @@ public: bool is_infinite(const Edge & e) const { return is_infinite(e.first,e.second,e.third); } - //QUERIES bool is_vertex(const Point & p, Vertex_handle & v) const; bool is_vertex(Vertex_handle v) const; bool is_edge(Vertex_handle u, Vertex_handle v, - Cell_handle & c, int & i, int & j) const; + Cell_handle & c, int & i, int & j) const; bool is_facet(Vertex_handle u, Vertex_handle v, Vertex_handle w, - Cell_handle & c, int & i, int & j, int & k) const; + Cell_handle & c, int & i, int & j, int & k) const; bool is_cell(Cell_handle c) const; bool is_cell(Vertex_handle u, Vertex_handle v, - Vertex_handle w, Vertex_handle t, - Cell_handle & c, int & i, int & j, int & k, int & l) const; + Vertex_handle w, Vertex_handle t, + Cell_handle & c, int & i, int & j, int & k, int & l) const; bool is_cell(Vertex_handle u, Vertex_handle v, - Vertex_handle w, Vertex_handle t, - Cell_handle & c) const; + Vertex_handle w, Vertex_handle t, + Cell_handle & c) const; bool has_vertex(const Facet & f, Vertex_handle v, int & j) const; bool has_vertex(Cell_handle c, int i, Vertex_handle v, int & j) const; @@ -511,8 +840,9 @@ public: #ifdef CGAL_NO_STRUCTURAL_FILTERING Cell_handle locate(const Point & p, - Locate_type & lt, int & li, int & lj, - Cell_handle start = Cell_handle()) const; + Locate_type & lt, int & li, int & lj, + Cell_handle start = Cell_handle(), + bool *could_lock_zone = NULL) const; #else // no CGAL_NO_STRUCTURAL_FILTERING # ifndef CGAL_T3_STRUCTURAL_FILTERING_MAX_VISITED_CELLS # define CGAL_T3_STRUCTURAL_FILTERING_MAX_VISITED_CELLS 2500 @@ -522,32 +852,44 @@ public: public: Cell_handle inexact_locate(const Point& p, - Cell_handle start = Cell_handle(), - int max_num_cells = CGAL_T3_STRUCTURAL_FILTERING_MAX_VISITED_CELLS) const; + Cell_handle start = Cell_handle(), + int max_num_cells = CGAL_T3_STRUCTURAL_FILTERING_MAX_VISITED_CELLS, + bool *could_lock_zone = NULL) const; protected: Cell_handle exact_locate(const Point& p, Locate_type& lt, int& li, int & lj, - Cell_handle start) const; + Cell_handle start, + bool *could_lock_zone = NULL + ) const; Cell_handle generic_locate(const Point& p, Locate_type& lt, int& li, int & lj, Cell_handle start, - internal::Structural_filtering_3_tag) const { - return exact_locate(p, lt, li, lj, inexact_locate(p, start)); - } + internal::Structural_filtering_3_tag, + bool *could_lock_zone = NULL) const + { + Cell_handle ch = inexact_locate( + p, start, CGAL_T3_STRUCTURAL_FILTERING_MAX_VISITED_CELLS, could_lock_zone); + if (could_lock_zone && *could_lock_zone == false) + return ch; // = Cell_handle() here + else + return exact_locate(p, lt, li, lj, ch, could_lock_zone); + } Cell_handle generic_locate(const Point& p, Locate_type& lt, int& li, int & lj, Cell_handle start, - internal::No_structural_filtering_3_tag) const { - return exact_locate(p, lt, li, lj, start); - } + internal::No_structural_filtering_3_tag + , bool *could_lock_zone = NULL) const + { + return exact_locate(p, lt, li, lj, start, could_lock_zone); + } public: Orientation @@ -586,82 +928,90 @@ public: } public: - + Cell_handle locate(const Point & p, Locate_type & lt, int & li, int & lj, - Cell_handle start = Cell_handle()) const + Cell_handle start = Cell_handle() + , bool *could_lock_zone = NULL + ) const { typedef Triangulation_structural_filtering_traits TSFT; - typedef typename internal::Structural_filtering_selector_3< + typedef typename internal::Structural_filtering_selector_3< TSFT::Use_structural_filtering_tag::value >::Tag Should_filter_tag; - return generic_locate(p, lt, li, lj, start, Should_filter_tag()); + return generic_locate(p, lt, li, lj, start, Should_filter_tag(), could_lock_zone); } #endif // no CGAL_NO_STRUCTURAL_FILTERING Cell_handle - locate(const Point & p, Cell_handle start = Cell_handle()) const + locate(const Point & p, Cell_handle start = Cell_handle(), + bool *could_lock_zone = NULL) const { Locate_type lt; int li, lj; - return locate( p, lt, li, lj, start); + return locate( p, lt, li, lj, start, could_lock_zone); } Cell_handle locate(const Point & p, - Locate_type & lt, int & li, int & lj, Vertex_handle hint) const + Locate_type & lt, int & li, int & lj, Vertex_handle hint, + bool *could_lock_zone = NULL) const { - return locate(p, lt, li, lj, hint == Vertex_handle() ? infinite_cell() : hint->cell()); + return locate(p, lt, li, lj, + hint == Vertex_handle() ? infinite_cell() : hint->cell(), + could_lock_zone); } Cell_handle - locate(const Point & p, Vertex_handle hint) const - { - return locate(p, hint == Vertex_handle() ? infinite_cell() : hint->cell()); + locate(const Point & p, Vertex_handle hint, + bool *could_lock_zone = NULL) const + { + return locate(p, hint == Vertex_handle() ? infinite_cell() : hint->cell(), + could_lock_zone); } // PREDICATES ON POINTS ``TEMPLATED'' by the geom traits Bounded_side side_of_tetrahedron(const Point & p, - const Point & p0, - const Point & p1, - const Point & p2, - const Point & p3, - Locate_type & lt, int & i, int & j ) const; + const Point & p0, + const Point & p1, + const Point & p2, + const Point & p3, + Locate_type & lt, int & i, int & j ) const; Bounded_side side_of_cell(const Point & p, - Cell_handle c, - Locate_type & lt, int & i, int & j) const; + Cell_handle c, + Locate_type & lt, int & i, int & j) const; Bounded_side side_of_triangle(const Point & p, - const Point & p0, const Point & p1, const Point & p2, - Locate_type & lt, int & i, int & j ) const; + const Point & p0, const Point & p1, const Point & p2, + Locate_type & lt, int & i, int & j ) const; Bounded_side side_of_facet(const Point & p, - Cell_handle c, - Locate_type & lt, int & li, int & lj) const; + Cell_handle c, + Locate_type & lt, int & li, int & lj) const; Bounded_side side_of_facet(const Point & p, - const Facet & f, - Locate_type & lt, int & li, int & lj) const + const Facet & f, + Locate_type & lt, int & li, int & lj) const { CGAL_triangulation_precondition( f.second == 3 ); return side_of_facet(p, f.first, lt, li, lj); } Bounded_side side_of_segment(const Point & p, - const Point & p0, const Point & p1, - Locate_type & lt, int & i ) const; + const Point & p0, const Point & p1, + Locate_type & lt, int & i ) const; Bounded_side side_of_edge(const Point & p, - Cell_handle c, - Locate_type & lt, int & li) const; + Cell_handle c, + Locate_type & lt, int & li) const; Bounded_side side_of_edge(const Point & p, - const Edge & e, - Locate_type & lt, int & li) const + const Edge & e, + Locate_type & lt, int & li) const { CGAL_triangulation_precondition( e.second == 0 ); CGAL_triangulation_precondition( e.third == 1 ); @@ -716,15 +1066,15 @@ public: } Vertex_handle insert(const Point & p, Cell_handle start = Cell_handle()); Vertex_handle insert(const Point & p, Locate_type lt, Cell_handle c, - int li, int lj); - + int li, int lj); + //protected: // internal methods - + template - Vertex_handle insert_and_give_new_cells(const Point &p, + Vertex_handle insert_and_give_new_cells(const Point &p, OutputItCells fit, Cell_handle start = Cell_handle() ); - + template Vertex_handle insert_and_give_new_cells(const Point& p, OutputItCells fit, @@ -733,15 +1083,16 @@ public: template Vertex_handle insert_and_give_new_cells(const Point& p, Locate_type lt, - Cell_handle c, int li, int lj, - OutputItCells fit); + Cell_handle c, int li, int lj, + OutputItCells fit); template < class Conflict_tester, class Hidden_points_visitor > inline Vertex_handle insert_in_conflict(const Point & p, - Locate_type lt, - Cell_handle c, int li, int lj, - const Conflict_tester &tester, - Hidden_points_visitor &hider); + Locate_type lt, + Cell_handle c, int li, int lj, + const Conflict_tester &tester, + Hidden_points_visitor &hider, + bool *could_lock_zone = NULL); template < class InputIterator > std::ptrdiff_t insert(InputIterator first, InputIterator last) @@ -789,7 +1140,7 @@ public: template Vertex_handle insert_in_hole(const Point & p, CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i) + Cell_handle begin, int i) { // Some geometric preconditions should be tested... Vertex_handle v = _tds.insert_in_hole(cell_begin, cell_end, begin, i); @@ -800,7 +1151,7 @@ public: template Vertex_handle insert_in_hole(const Point & p, CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i, Vertex_handle newv) + Cell_handle begin, int i, Vertex_handle newv) { // Some geometric preconditions should be tested... newv->set_point(p); @@ -811,7 +1162,7 @@ public: template Vertex_handle _insert_in_hole(const Point & p, CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i) + Cell_handle begin, int i) { // Some geometric preconditions should be tested... Vertex_handle v = _tds._insert_in_hole(cell_begin, cell_end, begin, i); @@ -823,7 +1174,7 @@ public: template Vertex_handle _insert_in_hole(const Point & p, CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i, Vertex_handle newv) + Cell_handle begin, int i, Vertex_handle newv) { // Some geometric preconditions should be tested... newv->set_point(p); @@ -831,61 +1182,136 @@ public: } protected: - + template < class InputIterator > bool does_repeat_in_range(InputIterator first, InputIterator beyond) const; template < class InputIterator > bool infinite_vertex_in_range(InputIterator first, InputIterator beyond) const; - + + // - c is the current cell, which must be in conflict. // - tester is the function object that tests if a cell is in conflict. - template < - class Conflict_test, + template Triple - find_conflicts(Cell_handle d, const Conflict_test &tester, - Triple it) const + find_conflicts( + Cell_handle d, + const Conflict_test &tester, + Triple it + , bool *could_lock_zone = NULL + , const Facet *this_facet_must_be_in_the_cz = NULL + , bool *the_facet_is_in_its_cz = NULL + ) const { CGAL_triangulation_precondition( dimension()>=2 ); + + if (the_facet_is_in_its_cz) + *the_facet_is_in_its_cz = false; + + if (could_lock_zone) + *could_lock_zone = true; + + if (could_lock_zone) + { + if (!this->try_lock_cell(d)) + { + *could_lock_zone = false; + return it; + } + } + CGAL_triangulation_precondition( tester(d) ); + // To store the boundary cells, in case we need to rollback std::stack cell_stack; cell_stack.push(d); d->tds_data().mark_in_conflict(); + *it.second++ = d; do { - Cell_handle c = cell_stack.top(); - cell_stack.pop(); + Cell_handle c = cell_stack.top(); + cell_stack.pop(); - for (int i=0; ineighbor(i); - if (test->tds_data().is_in_conflict()) { - if (c < test) - *it.third++ = Facet(c, i); // Internal facet. - continue; // test was already in conflict. - } - if (test->tds_data().is_clear()) { - if (tester(test)) { - if (c < test) - *it.third++ = Facet(c, i); // Internal facet. + // For each neighbor cell + for (int i=0; ineighbor(i); - cell_stack.push(test); - test->tds_data().mark_in_conflict(); - *it.second++ = test; - continue; - } - test->tds_data().mark_on_boundary(); - } - *it.first++ = Facet(c, i); + // "test" is either in the conflict zone, + // either facet-adjacent to the CZ + + if (test->tds_data().is_in_conflict()) { + + Facet f(c, i); // Internal facet. + // Is it the facet where're looking for? + if (this_facet_must_be_in_the_cz && the_facet_is_in_its_cz + && f == *this_facet_must_be_in_the_cz) + { + *the_facet_is_in_its_cz = true; + } + if (c < test) + { + *it.third++ = f; + } + continue; // test was already in conflict. } + if (test->tds_data().is_clear()) { + if (tester(test)) { + + // "test" is in the conflict zone + if (could_lock_zone) + { + if (!this->try_lock_cell(test)) + { + *could_lock_zone = false; + // Unlock + return it; + } + } + + + Facet f(c, i); // Internal facet. + // Is it the facet where're looking for? + if (this_facet_must_be_in_the_cz && the_facet_is_in_its_cz + && f == *this_facet_must_be_in_the_cz) + { + *the_facet_is_in_its_cz = true; + } + + if (c < test) + { + *it.third++ = f; + } + + cell_stack.push(test); + test->tds_data().mark_in_conflict(); + *it.second++ = test; + continue; + } + + test->tds_data().mark_on_boundary(); + } + + Facet f(c, i); // Boundary facet. + // Is it the facet where're looking for? + if (this_facet_must_be_in_the_cz + && the_facet_is_in_its_cz + && + (mirror_facet(f) == *this_facet_must_be_in_the_cz + || f == *this_facet_must_be_in_the_cz) ) + { + *the_facet_is_in_its_cz = true; + } + + *it.first++ = f; + } } while (!cell_stack.empty()); return it; } @@ -909,17 +1335,17 @@ protected: switch (dimension()) { case 3: find_conflicts(c, tester, make_triple(Oneset_iterator(facet), - std::back_inserter(cells), - Emptyset_iterator())); + std::back_inserter(cells), + Emptyset_iterator())); break; case 2: find_conflicts(c, tester, make_triple(Oneset_iterator(facet), - std::back_inserter(cells), - Emptyset_iterator())); + std::back_inserter(cells), + Emptyset_iterator())); } // Create the new cells and delete the old. return _tds._insert_in_hole(cells.begin(), cells.end(), - facet.first, facet.second); + facet.first, facet.second); } private: @@ -933,13 +1359,13 @@ private: public: Conflict_tester_outside_convex_hull_3(const Point &pt, const Self *tr) - : p(pt), t(tr) {} + : p(pt), t(tr) {} bool operator()(const Cell_handle c) const { - Locate_type loc; + Locate_type loc; int i, j; - return t->side_of_cell( p, c, loc, i, j ) == ON_BOUNDED_SIDE; + return t->side_of_cell( p, c, loc, i, j ) == ON_BOUNDED_SIDE; } }; @@ -951,13 +1377,13 @@ private: public: Conflict_tester_outside_convex_hull_2(const Point &pt, const Self *tr) - : p(pt), t(tr) {} + : p(pt), t(tr) {} bool operator()(const Cell_handle c) const { - Locate_type loc; + Locate_type loc; int i, j; - return t->side_of_facet( p, c, loc, i, j ) == ON_BOUNDED_SIDE; + return t->side_of_facet( p, c, loc, i, j ) == ON_BOUNDED_SIDE; } }; @@ -968,9 +1394,23 @@ protected: // others inherited triangulations bool test_dim_down(Vertex_handle v) const; + bool test_dim_down_using_incident_cells_3( + Vertex_handle v, std::vector &incident_cells, + std::vector &adj_vertices, + bool *could_lock_zone = NULL) const; + // REMOVAL template < class VertexRemover > void remove(Vertex_handle v, VertexRemover &remover); + template < class VertexRemover > + // Concurrency-safe version + // Pre-condition: dimension = 3 + // The return value is only meaningful if *could_lock_zone = true: + // * returns true if the vertex was removed + // * returns false if the vertex wasn't removed since it would decrease + // the dimension => needs to be done sequentially + bool remove(Vertex_handle v, VertexRemover &remover, + bool *could_lock_zone); template < class VertexRemover, class OutputItCells > void remove_and_give_new_cells(Vertex_handle v, VertexRemover &remover, @@ -983,15 +1423,15 @@ protected: // By doing these kind of remove followed by inserting the cluster, // we achieve fast relocations for a batch of points (in a Delaunay triangulation). template < class InputIterator, class VertexRemover > - size_type remove(InputIterator first, InputIterator beyond, + size_type remove(InputIterator first, InputIterator beyond, VertexRemover &remover); enum REMOVE_VERTEX_STATE {CLEAR, TO_REMOVE, PROCESSED, EXTREMITY}; - + // MOVE template < class VertexRemover, class VertexInserter > Vertex_handle move_if_no_collision(Vertex_handle v, const Point &p, VertexRemover &remover, - VertexInserter &inserter); + VertexInserter &inserter); template < class VertexRemover, class VertexInserter > Vertex_handle move(Vertex_handle v, const Point &p, @@ -1014,17 +1454,17 @@ protected: int cwi = (i+2)%3; int ccwi = (i+1)%3; - int cwni = (ni+2)%3; - int ccwni = (ni+1)%3; + int cwni = (ni+2)%3; + int ccwni = (ni+1)%3; Vertex_handle v_cw = f->vertex(cwi); Vertex_handle v_ccw = f->vertex(ccwi); // bl == bottom left, tr == top right Cell_handle tr = f->neighbor(ccwi); - int tri = this->_tds.mirror_index(f,ccwi); + int tri = this->_tds.mirror_index(f,ccwi); Cell_handle bl = n->neighbor(ccwni); - int bli = this->_tds.mirror_index(n,ccwni); + int bli = this->_tds.mirror_index(n,ccwni); f->set_vertex(cwi, n->vertex(ni)); n->set_vertex(cwni, f->vertex(i)); @@ -1044,13 +1484,13 @@ protected: } template < class VertexRemover, class VertexInserter > - void restore_edges_after_decrease_dimension(Vertex_handle v, + void restore_edges_after_decrease_dimension(Vertex_handle v, VertexRemover &remover, VertexInserter &inserter) { - + Cell_handle fkstart = v->cell(); Cell_handle start = fkstart->neighbor(fkstart->index(v)); - + std::list hole; make_hole_2D(v, hole, remover); fill_hole_2D(hole, remover); @@ -1058,18 +1498,18 @@ protected: // the aim here is Delaunay triangulations // to make it more general one could have an internal function here // to remove v without touching its handle - + // This insert must be from Delaunay (or the particular trian.) - // not the basic Triangulation_3. + // not the basic Triangulation_3. // Here we correct the recent triangulation (with decreased dimension) formed // in particular here a 2D (from 3D to 2D displacement) Vertex_handle inserted = inserter.insert(v->point(), start); - + // fixing pointer Cell_handle fc = inserted->cell(), done(fc); std::vector faces_pt; faces_pt.reserve(16); - do { + do { faces_pt.push_back(fc); fc = fc->neighbor((fc->index(inserted) + 1)%3); } while(fc != done); @@ -1088,6 +1528,10 @@ protected: private: typedef Facet Edge_2D; typedef Triple Vertex_triple; + typedef typename Base::template Vertex_triple_Facet_map_generator< + Vertex_triple, Facet>::type Vertex_triple_Facet_map; + typedef typename Base::template Vertex_handle_unique_hash_map_generator< + Vertex_handle>::type Vertex_handle_unique_hash_map; Vertex_triple make_vertex_triple(const Facet& f) const; void make_canonical(Vertex_triple& t) const; @@ -1097,14 +1541,19 @@ private: VertexRemover &remover); template < class VertexRemover > VertexRemover& make_hole_2D(Vertex_handle v, std::list & hole, - VertexRemover &remover, + VertexRemover &remover, std::set &cells_set); template < class VertexRemover > void fill_hole_2D(std::list & hole, VertexRemover &remover); - void make_hole_3D( Vertex_handle v, std::map& outer_map, + void make_hole_3D( Vertex_handle v, Vertex_triple_Facet_map& outer_map, std::vector & hole); + // When the incident cells are already known + void make_hole_3D( + Vertex_handle v, + const std::vector & incident_cells, + Vertex_triple_Facet_map& outer_map); template < class VertexRemover > VertexRemover& remove_dim_down(Vertex_handle v, VertexRemover &remover); @@ -1114,6 +1563,12 @@ private: VertexRemover& remove_2D(Vertex_handle v, VertexRemover &remover); template < class VertexRemover > VertexRemover& remove_3D(Vertex_handle v, VertexRemover &remover); + // Version of remove_3D if the incident cells and the adjacent vertices + // are already known + template < class VertexRemover > + VertexRemover& remove_3D(Vertex_handle v, VertexRemover &remover, + const std::vector &inc_cells, + std::vector &adj_vertices); template < class VertexRemover, class OutputItCells > VertexRemover& remove_dim_down(Vertex_handle v, VertexRemover &remover, @@ -1130,7 +1585,7 @@ private: template < class VertexRemover, class OutputItCells > VertexRemover& remove_3D(Vertex_handle v, VertexRemover &remover, OutputItCells fit); - + template < class VertexRemover, class OutputItCells > void fill_hole_2D(std::list & hole, VertexRemover &remover, OutputItCells fit); @@ -1144,7 +1599,7 @@ private: // remove cluster template < class InputIterator > - void _mark_vertices_to_remove(InputIterator first, InputIterator beyond, + void _mark_vertices_to_remove(InputIterator first, InputIterator beyond, std::map &vstates) const { while (first != beyond) vstates[*first++] = TO_REMOVE; @@ -1158,20 +1613,20 @@ private: CGAL_triangulation_precondition( dimension() == 3 ); int k=0; Vertex_handle v[4]; - for (Finite_vertices_iterator fit = finite_vertices_begin(); + for (Finite_vertices_iterator fit = finite_vertices_begin(); fit != finite_vertices_end(); ++fit ) { if(vstates[fit] == TO_REMOVE) continue; v[k++] = fit; if(k == 4) { - if (!coplanar(v[0]->point(), v[1]->point(), + if (!coplanar(v[0]->point(), v[1]->point(), v[2]->point(), v[3]->point())) return false; k--; } } return k < 4; } - + template < class InputIterator, class VertexRemover > bool _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover &remover, @@ -1189,9 +1644,9 @@ public: Finite_cells_iterator finite_cells_begin() const { if ( dimension() < 3 ) - return finite_cells_end(); + return finite_cells_end(); return CGAL::filter_iterator(cells_end(), Infinite_tester(this), - cells_begin()); + cells_begin()); } Finite_cells_iterator finite_cells_end() const { @@ -1219,9 +1674,9 @@ public: Finite_vertices_iterator finite_vertices_begin() const { if ( number_of_vertices() <= 0 ) - return finite_vertices_end(); + return finite_vertices_end(); return CGAL::filter_iterator(vertices_end(), Infinite_tester(this), - vertices_begin()); + vertices_begin()); } Finite_vertices_iterator finite_vertices_end() const { @@ -1249,9 +1704,9 @@ public: Finite_edges_iterator finite_edges_begin() const { if ( dimension() < 1 ) - return finite_edges_end(); + return finite_edges_end(); return CGAL::filter_iterator(edges_end(), Infinite_tester(this), - edges_begin()); + edges_begin()); } Finite_edges_iterator finite_edges_end() const { @@ -1279,9 +1734,9 @@ public: Finite_facets_iterator finite_facets_begin() const { if ( dimension() < 2 ) - return finite_facets_end(); + return finite_facets_end(); return CGAL::filter_iterator(facets_end(), Infinite_tester(this), - facets_begin()); + facets_begin()); } Finite_facets_iterator finite_facets_end() const { @@ -1329,7 +1784,7 @@ public: return _tds.incident_cells(e, start); } Cell_circulator incident_cells(Cell_handle c, int i, int j, - Cell_handle start) const + Cell_handle start) const { return _tds.incident_cells(c, i, j, start); } @@ -1348,17 +1803,17 @@ public: return _tds.incident_facets(e, start); } Facet_circulator incident_facets(Cell_handle c, int i, int j, - const Facet & start) const + const Facet & start) const { return _tds.incident_facets(c, i, j, start); } Facet_circulator incident_facets(const Edge & e, - Cell_handle start, int f) const + Cell_handle start, int f) const { return _tds.incident_facets(e, start, f); } Facet_circulator incident_facets(Cell_handle c, int i, int j, - Cell_handle start, int f) const + Cell_handle start, int f) const { return _tds.incident_facets(c, i, j, start, f); } @@ -1389,19 +1844,148 @@ public: } }; - template + template OutputIterator incident_cells(Vertex_handle v, OutputIterator cells) const { return _tds.incident_cells(v, cells); } + + template + void incident_cells_threadsafe(Vertex_handle v, + OutputIterator cells) const + { + _tds.incident_cells_threadsafe(v, cells); + } + + template + void incident_cells_threadsafe(Vertex_handle v, + OutputIterator cells, + const Filter &filter) const + { + _tds.incident_cells_threadsafe(v, cells, filter); + } + + bool + try_lock_and_get_incident_cells(Vertex_handle v, + std::vector& cells) const + { + // We need to lock v individually first, to be sure v->cell() is valid + if (!this->try_lock_vertex(v)) + return false; + + Cell_handle d = v->cell(); + if (!this->try_lock_cell(d)) // LOCK + { + return false; + } + cells.push_back(d); + d->tds_data().mark_in_conflict(); + int head=0; + int tail=1; + do { + Cell_handle c = cells[head]; + + for (int i=0; i<4; ++i) { + if (c->vertex(i) == v) + continue; + Cell_handle next = c->neighbor(i); + + if (!this->try_lock_cell(next)) // LOCK + { + BOOST_FOREACH(Cell_handle& ch, + std::make_pair(cells.begin(), cells.end())) + { + ch->tds_data().clear(); + } + cells.clear(); + return false; + } + if (! next->tds_data().is_clear()) + continue; + cells.push_back(next); + ++tail; + next->tds_data().mark_in_conflict(); + } + ++head; + } while(head != tail); + BOOST_FOREACH(Cell_handle& ch, std::make_pair(cells.begin(), cells.end())) + { + ch->tds_data().clear(); + } + return true; + } + + template + bool + try_lock_and_get_adjacent_vertices_and_cells_3( + Vertex_handle v, OutputIterator vertices, + std::vector &cells) const + { + + // We need to lock v individually first, to be sure v->cell() is valid + if (!this->try_lock_vertex(v)) + return false; + + Cell_handle d = v->cell(); + if (!this->try_lock_cell(d)) // LOCK + { + return false; + } + cells.push_back(d); + d->tds_data().mark_in_conflict(); + int head=0; + int tail=1; + do { + Cell_handle c = cells[head]; + + for (int i=0; i<4; ++i) { + if (c->vertex(i) == v) + continue; + Cell_handle next = c->neighbor(i); + + if (!this->try_lock_cell(next)) // LOCK + { + BOOST_FOREACH(Cell_handle& ch, + std::make_pair(cells.begin(), cells.end())) + { + ch->tds_data().clear(); + } + cells.clear(); + return false; + } + if (! next->tds_data().is_clear()) + continue; + cells.push_back(next); + ++tail; + next->tds_data().mark_in_conflict(); + } + ++head; + } while(head != tail); + + std::set tmp_vertices; + BOOST_FOREACH(Cell_handle& ch, std::make_pair(cells.begin(), cells.end())) + { + ch->tds_data().clear(); + for (int i = 0; i < 4; ++i) + { + Vertex_handle w = ch->vertex(i); + if (w != v && tmp_vertices.insert(w).second) + { + *vertices = w; + + } + } + } + return true; + } template OutputIterator finite_incident_cells(Vertex_handle v, OutputIterator cells) const { - if(dimension() == 2) - return _tds.incident_cells(v, cells, Finite_filter_2D(this)); + if(dimension() == 2) + return _tds.incident_cells(v, cells, Finite_filter_2D(this)); return _tds.incident_cells(v, cells, Finite_filter(this)); } @@ -1419,6 +2003,20 @@ public: return _tds.incident_facets(v, facets, Finite_filter(this)); } + template + OutputIterator + incident_facets_threadsafe(Vertex_handle v, OutputIterator facets) const + { + return _tds.incident_facets_threadsafe(v, facets); + } + + template + OutputIterator + finite_incident_facets_threadsafe(Vertex_handle v, OutputIterator facets) const + { + return _tds.incident_facets_threadsafe(v, facets, Finite_filter(this)); + } + // old name (up to CGAL 3.4) // kept for backwards compatibility but not documented template @@ -1436,6 +2034,14 @@ public: return _tds.adjacent_vertices(v, vertices); } + template + OutputIterator + adjacent_vertices_and_cells_3(Vertex_handle v, OutputIterator vertices, + std::vector &cells) const + { + return _tds.adjacent_vertices_and_cells_3(v, vertices, cells); + } + // old name (up to CGAL 3.4) // kept for backwards compatibility but not documented template @@ -1482,9 +2088,9 @@ public: bool is_valid_finite(Cell_handle c, bool verbose = false, int level=0) const; }; -template < class GT, class Tds > +template < class GT, class Tds, class Lds > std::istream & -operator>> (std::istream& is, Triangulation_3 &tr) +operator>> (std::istream& is, Triangulation_3 &tr) // reads // the dimension // the number of finite vertices @@ -1534,9 +2140,9 @@ operator>> (std::istream& is, Triangulation_3 &tr) return is; } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > std::ostream & -operator<< (std::ostream& os, const Triangulation_3 &tr) +operator<< (std::ostream& os, const Triangulation_3 &tr) // writes : // the dimension // the number of finite vertices @@ -1554,7 +2160,7 @@ operator<< (std::ostream& os, const Triangulation_3 &tr) typedef typename Triangulation::Cell_iterator Cell_iterator; typedef typename Triangulation::Edge_iterator Edge_iterator; typedef typename Triangulation::Facet_iterator Facet_iterator; - + // outputs dimension and number of vertices size_type n = tr.number_of_vertices(); if (is_ascii(os)) @@ -1574,7 +2180,7 @@ operator<< (std::ostream& os, const Triangulation_3 &tr) // write the vertices for (Vertex_iterator it = tr.vertices_begin(), end = tr.vertices_end(); - it != end; ++it) + it != end; ++it) TV[i++] = it; CGAL_triangulation_assertion( i == n+1 ); @@ -1587,7 +2193,7 @@ operator<< (std::ostream& os, const Triangulation_3 &tr) os << *TV[i]; V[TV[i]] = i; if (is_ascii(os)) - os << std::endl; + os << std::endl; } // asks the tds for the combinatorial information @@ -1602,7 +2208,7 @@ operator<< (std::ostream& os, const Triangulation_3 &tr) case 3: { for(Cell_iterator it = tr.cells_begin(), end = tr.cells_end(); it != end; ++it) { - os << *it; // other information + os << *it; // other information if(is_ascii(os)) os << std::endl; } @@ -1611,7 +2217,7 @@ operator<< (std::ostream& os, const Triangulation_3 &tr) case 2: { for(Facet_iterator it = tr.facets_begin(), end = tr.facets_end(); it != end; ++it) { - os << *((*it).first); // other information + os << *((*it).first); // other information if(is_ascii(os)) os << std::endl; } @@ -1620,7 +2226,7 @@ operator<< (std::ostream& os, const Triangulation_3 &tr) case 1: { for(Edge_iterator it = tr.edges_begin(), end = tr.edges_end(); it != end; ++it) { - os << *((*it).first); // other information + os << *((*it).first); // other information if(is_ascii(os)) os << std::endl; } @@ -1632,118 +2238,118 @@ operator<< (std::ostream& os, const Triangulation_3 &tr) return os ; } -template < class GT, class Tds > -typename Triangulation_3::size_type -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::size_type +Triangulation_3:: number_of_finite_cells() const { if ( dimension() < 3 ) return 0; return std::distance(finite_cells_begin(), finite_cells_end()); } -template < class GT, class Tds > -typename Triangulation_3::size_type -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::size_type +Triangulation_3:: number_of_cells() const { return _tds.number_of_cells(); } -template < class GT, class Tds > -typename Triangulation_3::size_type -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::size_type +Triangulation_3:: number_of_finite_facets() const { if ( dimension() < 2 ) return 0; return std::distance(finite_facets_begin(), finite_facets_end()); } -template < class GT, class Tds > -typename Triangulation_3::size_type -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::size_type +Triangulation_3:: number_of_facets() const { return _tds.number_of_facets(); } -template < class GT, class Tds > -typename Triangulation_3::size_type -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::size_type +Triangulation_3:: number_of_finite_edges() const { if ( dimension() < 1 ) return 0; return std::distance(finite_edges_begin(), finite_edges_end()); } -template < class GT, class Tds > -typename Triangulation_3::size_type -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::size_type +Triangulation_3:: number_of_edges() const { return _tds.number_of_edges(); } -template < class GT, class Tds > -typename Triangulation_3::Triangle -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::Triangle +Triangulation_3:: triangle(const Cell_handle c, int i) const { CGAL_triangulation_precondition( dimension() == 2 || dimension() == 3 ); CGAL_triangulation_precondition( (dimension() == 2 && i == 3) - || (dimension() == 3 && i >= 0 && i <= 3) ); + || (dimension() == 3 && i >= 0 && i <= 3) ); CGAL_triangulation_precondition( ! is_infinite(Facet(c, i)) ); if ( (i&1)==0 ) return construct_triangle(c->vertex( (i+2)&3 )->point(), - c->vertex( (i+1)&3 )->point(), - c->vertex( (i+3)&3 )->point()); + c->vertex( (i+1)&3 )->point(), + c->vertex( (i+3)&3 )->point()); return construct_triangle(c->vertex( (i+1)&3 )->point(), - c->vertex( (i+2)&3 )->point(), - c->vertex( (i+3)&3 )->point()); + c->vertex( (i+2)&3 )->point(), + c->vertex( (i+3)&3 )->point()); } -template < class GT, class Tds > -typename Triangulation_3::Segment -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::Segment +Triangulation_3:: segment(const Cell_handle c, int i, int j) const { CGAL_triangulation_precondition( i != j ); CGAL_triangulation_precondition( dimension() >= 1 && dimension() <= 3 ); CGAL_triangulation_precondition( i >= 0 && i <= dimension() - && j >= 0 && j <= dimension() ); + && j >= 0 && j <= dimension() ); CGAL_triangulation_precondition( ! is_infinite(Edge(c, i, j)) ); return construct_segment( c->vertex(i)->point(), c->vertex(j)->point() ); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline bool -Triangulation_3:: +Triangulation_3:: is_infinite(const Cell_handle c, int i) const { CGAL_triangulation_precondition( dimension() == 2 || dimension() == 3 ); CGAL_triangulation_precondition( (dimension() == 2 && i == 3) - || (dimension() == 3 && i >= 0 && i <= 3) ); + || (dimension() == 3 && i >= 0 && i <= 3) ); return is_infinite(c->vertex(i<=0 ? 1 : 0)) || - is_infinite(c->vertex(i<=1 ? 2 : 1)) || - is_infinite(c->vertex(i<=2 ? 3 : 2)); + is_infinite(c->vertex(i<=1 ? 2 : 1)) || + is_infinite(c->vertex(i<=2 ? 3 : 2)); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline bool -Triangulation_3:: +Triangulation_3:: is_infinite(const Cell_handle c, int i, int j) const { CGAL_triangulation_precondition( i != j ); CGAL_triangulation_precondition( dimension() >= 1 && dimension() <= 3 ); CGAL_triangulation_precondition( - i >= 0 && i <= dimension() && j >= 0 && j <= dimension() ); + i >= 0 && i <= dimension() && j >= 0 && j <= dimension() ); return is_infinite( c->vertex(i) ) || is_infinite( c->vertex(j) ); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > bool -Triangulation_3:: +Triangulation_3:: is_vertex(const Point & p, Vertex_handle & v) const { Locate_type lt; @@ -1755,135 +2361,135 @@ is_vertex(const Point & p, Vertex_handle & v) const return true; } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline bool -Triangulation_3:: +Triangulation_3:: is_vertex(Vertex_handle v) const { return _tds.is_vertex(v); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > bool -Triangulation_3:: +Triangulation_3:: is_edge(Vertex_handle u, Vertex_handle v, - Cell_handle & c, int & i, int & j) const + Cell_handle & c, int & i, int & j) const { return _tds.is_edge(u, v, c, i, j); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > bool -Triangulation_3:: +Triangulation_3:: is_facet(Vertex_handle u, Vertex_handle v, Vertex_handle w, - Cell_handle & c, int & i, int & j, int & k) const + Cell_handle & c, int & i, int & j, int & k) const { return _tds.is_facet(u, v, w, c, i, j, k); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline bool -Triangulation_3:: +Triangulation_3:: is_cell(Cell_handle c) const { return _tds.is_cell(c); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > bool -Triangulation_3:: +Triangulation_3:: is_cell(Vertex_handle u, Vertex_handle v, - Vertex_handle w, Vertex_handle t, - Cell_handle & c, int & i, int & j, int & k, int & l) const + Vertex_handle w, Vertex_handle t, + Cell_handle & c, int & i, int & j, int & k, int & l) const { return _tds.is_cell(u, v, w, t, c, i, j, k, l); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > bool -Triangulation_3:: +Triangulation_3:: is_cell(Vertex_handle u, Vertex_handle v, - Vertex_handle w, Vertex_handle t, - Cell_handle & c) const + Vertex_handle w, Vertex_handle t, + Cell_handle & c) const { int i,j,k,l; return _tds.is_cell(u, v, w, t, c, i, j, k, l); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline bool -Triangulation_3:: +Triangulation_3:: has_vertex(const Facet & f, Vertex_handle v, int & j) const { return _tds.has_vertex(f.first, f.second, v, j); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline bool -Triangulation_3:: +Triangulation_3:: has_vertex(Cell_handle c, int i, Vertex_handle v, int & j) const { return _tds.has_vertex(c, i, v, j); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline bool -Triangulation_3:: +Triangulation_3:: has_vertex(const Facet & f, Vertex_handle v) const { return _tds.has_vertex(f.first, f.second, v); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline bool -Triangulation_3:: +Triangulation_3:: has_vertex(Cell_handle c, int i, Vertex_handle v) const { return _tds.has_vertex(c, i, v); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline bool -Triangulation_3:: +Triangulation_3:: are_equal(Cell_handle c, int i, Cell_handle n, int j) const { return _tds.are_equal(c, i, n, j); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline bool -Triangulation_3:: +Triangulation_3:: are_equal(const Facet & f, const Facet & g) const { return _tds.are_equal(f.first, f.second, g.first, g.second); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline bool -Triangulation_3:: +Triangulation_3:: are_equal(const Facet & f, Cell_handle n, int j) const { return _tds.are_equal(f.first, f.second, n, j); } -template < class GT, class Tds > -typename Triangulation_3::Cell_handle -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::Cell_handle +Triangulation_3:: #ifdef CGAL_NO_STRUCTURAL_FILTERING locate(const Point & p, Locate_type & lt, int & li, int & lj, - Cell_handle start ) const + Cell_handle start, bool *could_lock_zone) const #else exact_locate(const Point & p, Locate_type & lt, int & li, int & lj, - Cell_handle start ) const + Cell_handle start, bool *could_lock_zone) const #endif // returns the (finite or infinite) cell p lies in // starts at cell "start" @@ -1899,6 +2505,9 @@ exact_locate(const Point & p, Locate_type & lt, int & li, int & lj, { CGAL_triangulation_expensive_assertion(start == Cell_handle() || tds().is_simplex(start) ); + if (could_lock_zone) + *could_lock_zone = true; + if ( dimension() >= 1 ) { // Make sure we continue from here with a finite cell. if ( start == Cell_handle() ) @@ -1909,111 +2518,145 @@ exact_locate(const Point & p, Locate_type & lt, int & li, int & lj, start = start->neighbor(ind_inf); } - boost::rand48 rng; + boost::rand48 rng; switch (dimension()) { case 3: + { + CGAL_triangulation_precondition( start != Cell_handle() ); + CGAL_triangulation_precondition( ! start->has_vertex(infinite) ); + + // We implement the remembering visibility/stochastic walk. + + // Remembers the previous cell to avoid useless orientation tests. + Cell_handle previous = Cell_handle(); + Cell_handle c = start; + + if (could_lock_zone) { - CGAL_triangulation_precondition( start != Cell_handle() ); - CGAL_triangulation_precondition( ! start->has_vertex(infinite) ); - - // We implement the remembering visibility/stochastic walk. - - // Remembers the previous cell to avoid useless orientation tests. - Cell_handle previous = Cell_handle(); - Cell_handle c = start; - - // Stores the results of the 4 orientation tests. It will be used - // at the end to decide if p lies on a face/edge/vertex/interior. - Orientation o[4]; - - boost::uniform_smallint<> four(0, 3); - boost::variate_generator > die4(rng, four); - - // Now treat the cell c. - try_next_cell: - - // We know that the 4 vertices of c are positively oriented. - // So, in order to test if p is seen outside from one of c's facets, - // we just replace the corresponding point by p in the orientation - // test. We do this using the array below. - const Point* pts[4] = { &(c->vertex(0)->point()), - &(c->vertex(1)->point()), - &(c->vertex(2)->point()), - &(c->vertex(3)->point()) }; - - // For the remembering stochastic walk, - // we need to start trying with a random index : - int i = die4(); - // For the remembering visibility walk (Delaunay and Regular only), we don't : - // int i = 0; - - for (int j=0; j != 4; ++j, i = (i+1)&3) { - Cell_handle next = c->neighbor(i); - if (previous == next) { - o[i] = POSITIVE; - continue; - } - // We temporarily put p at i's place in pts. - const Point* backup = pts[i]; - pts[i] = &p; - o[i] = orientation(*pts[0], *pts[1], *pts[2], *pts[3]); - if ( o[i] != NEGATIVE ) { - pts[i] = backup; - continue; - } - if ( next->has_vertex(infinite, li) ) { - // We are outside the convex hull. - lt = OUTSIDE_CONVEX_HULL; - return next; - } - previous = c; - c = next; - goto try_next_cell; - } - - // now p is in c or on its boundary - int sum = ( o[0] == COPLANAR ) - + ( o[1] == COPLANAR ) - + ( o[2] == COPLANAR ) - + ( o[3] == COPLANAR ); - switch (sum) { - case 0: - { - lt = CELL; - break; - } - case 1: - { - lt = FACET; - li = ( o[0] == COPLANAR ) ? 0 : - ( o[1] == COPLANAR ) ? 1 : - ( o[2] == COPLANAR ) ? 2 : 3; - break; - } - case 2: - { - lt = EDGE; - li = ( o[0] != COPLANAR ) ? 0 : - ( o[1] != COPLANAR ) ? 1 : 2; - lj = ( o[li+1] != COPLANAR ) ? li+1 : - ( o[li+2] != COPLANAR ) ? li+2 : li+3; - CGAL_triangulation_assertion(collinear( p, - c->vertex( li )->point(), - c->vertex( lj )->point())); - break; - } - case 3: - { - lt = VERTEX; - li = ( o[0] != COPLANAR ) ? 0 : - ( o[1] != COPLANAR ) ? 1 : - ( o[2] != COPLANAR ) ? 2 : 3; - break; - } - } - return c; + if (!this->try_lock_cell(c)) + { + *could_lock_zone = false; + return Cell_handle(); + } } + + // Stores the results of the 4 orientation tests. It will be used + // at the end to decide if p lies on a face/edge/vertex/interior. + Orientation o[4]; + + boost::uniform_smallint<> four(0, 3); + boost::variate_generator > die4(rng, four); + + // Now treat the cell c. + bool try_next_cell = true; + while(try_next_cell) + { + try_next_cell = false; + // We know that the 4 vertices of c are positively oriented. + // So, in order to test if p is seen outside from one of c's facets, + // we just replace the corresponding point by p in the orientation + // test. We do this using the array below. + const Point* pts[4] = { &(c->vertex(0)->point()), + &(c->vertex(1)->point()), + &(c->vertex(2)->point()), + &(c->vertex(3)->point()) }; + + // For the remembering stochastic walk, + // we need to start trying with a random index : + int i = die4(); + // For the remembering visibility walk (Delaunay and Regular only), we don't : + // int i = 0; + + bool stop = false; + // for each vertex + for (int j=0; !try_next_cell && j != 4; ++j, i = (i+1)&3) + { + Cell_handle next = c->neighbor(i); + + if (previous == next) + { + o[i] = POSITIVE; + } + else + { + // We temporarily put p at i's place in pts. + const Point* backup = pts[i]; + pts[i] = &p; + o[i] = orientation(*pts[0], *pts[1], *pts[2], *pts[3]); + if ( o[i] != NEGATIVE ) + { + pts[i] = backup; + } + else + { + if ( next->has_vertex(infinite, li) ) + { + // We are outside the convex hull. + lt = OUTSIDE_CONVEX_HULL; + return next; + } + previous = c; + c = next; + if (could_lock_zone) + { + //previous->unlock(); // DON'T do that, "c" may be in + // the same locking cell as "previous" + if (!this->try_lock_cell(c)) + { + *could_lock_zone = false; + return Cell_handle(); + } + } + try_next_cell = true; + } + } + } // next vertex + } // next cell + + // now p is in c or on its boundary + int sum = ( o[0] == COPLANAR ) + + ( o[1] == COPLANAR ) + + ( o[2] == COPLANAR ) + + ( o[3] == COPLANAR ); + switch (sum) { + case 0: + { + lt = CELL; + break; + } + case 1: + { + lt = FACET; + li = ( o[0] == COPLANAR ) ? 0 : + ( o[1] == COPLANAR ) ? 1 : + ( o[2] == COPLANAR ) ? 2 : 3; + break; + } + case 2: + { + lt = EDGE; + li = ( o[0] != COPLANAR ) ? 0 : + ( o[1] != COPLANAR ) ? 1 : 2; + lj = ( o[li+1] != COPLANAR ) ? li+1 : + ( o[li+2] != COPLANAR ) ? li+2 : li+3; + CGAL_triangulation_assertion(collinear( p, + c->vertex( li )->point(), + c->vertex( lj )->point())); + break; + } + case 3: + { + lt = VERTEX; + li = ( o[0] != COPLANAR ) ? 0 : + ( o[1] != COPLANAR ) ? 1 : + ( o[2] != COPLANAR ) ? 2 : 3; + break; + } + } + return c; + } + case 2: { CGAL_triangulation_precondition( start != Cell_handle() ); @@ -2025,80 +2668,80 @@ exact_locate(const Point & p, Locate_type & lt, int & li, int & lj, //first tests whether p is coplanar with the current triangulation if ( orientation( c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point(), - p ) != DEGENERATE ) { - lt = OUTSIDE_AFFINE_HULL; - li = 3; // only one facet in dimension 2 - return c; + c->vertex(1)->point(), + c->vertex(2)->point(), + p ) != DEGENERATE ) { + lt = OUTSIDE_AFFINE_HULL; + li = 3; // only one facet in dimension 2 + return c; } // if p is coplanar, location in the triangulation // only the facet numbered 3 exists in each cell while (1) { - int inf; - if ( c->has_vertex(infinite,inf) ) { - // c must contain p in its interior - lt = OUTSIDE_CONVEX_HULL; - li = cw(inf); - lj = ccw(inf); - return c; - } + int inf; + if ( c->has_vertex(infinite,inf) ) { + // c must contain p in its interior + lt = OUTSIDE_CONVEX_HULL; + li = cw(inf); + lj = ccw(inf); + return c; + } - // else c is finite - // we test its edges in a random order until we find a - // neighbor to go further - int i = die3(); - const Point & p0 = c->vertex( i )->point(); - const Point & p1 = c->vertex( ccw(i) )->point(); - const Point & p2 = c->vertex( cw(i) )->point(); + // else c is finite + // we test its edges in a random order until we find a + // neighbor to go further + int i = die3(); + const Point & p0 = c->vertex( i )->point(); + const Point & p1 = c->vertex( ccw(i) )->point(); + const Point & p2 = c->vertex( cw(i) )->point(); Orientation o[3]; - CGAL_triangulation_assertion(coplanar_orientation(p0,p1,p2)==POSITIVE); - o[0] = coplanar_orientation(p0,p1,p); - if ( o[0] == NEGATIVE ) { - c = c->neighbor( cw(i) ); - continue; - } - o[1] = coplanar_orientation(p1,p2,p); - if ( o[1] == NEGATIVE ) { - c = c->neighbor( i ); - continue; - } - o[2] = coplanar_orientation(p2,p0,p); - if ( o[2] == NEGATIVE ) { - c = c->neighbor( ccw(i) ); - continue; - } + CGAL_triangulation_assertion(coplanar_orientation(p0,p1,p2)==POSITIVE); + o[0] = coplanar_orientation(p0,p1,p); + if ( o[0] == NEGATIVE ) { + c = c->neighbor( cw(i) ); + continue; + } + o[1] = coplanar_orientation(p1,p2,p); + if ( o[1] == NEGATIVE ) { + c = c->neighbor( i ); + continue; + } + o[2] = coplanar_orientation(p2,p0,p); + if ( o[2] == NEGATIVE ) { + c = c->neighbor( ccw(i) ); + continue; + } - // now p is in c or on its boundary - int sum = ( o[0] == COLLINEAR ) - + ( o[1] == COLLINEAR ) - + ( o[2] == COLLINEAR ); - switch (sum) { - case 0: - { - lt = FACET; - li = 3; // useless ? - break; - } - case 1: - { - lt = EDGE; - li = ( o[0] == COLLINEAR ) ? i : - ( o[1] == COLLINEAR ) ? ccw(i) : - cw(i); - lj = ccw(li); - break; - } - case 2: - { - lt = VERTEX; - li = ( o[0] != COLLINEAR ) ? cw(i) : - ( o[1] != COLLINEAR ) ? i : - ccw(i); - break; - } - } - return c; + // now p is in c or on its boundary + int sum = ( o[0] == COLLINEAR ) + + ( o[1] == COLLINEAR ) + + ( o[2] == COLLINEAR ); + switch (sum) { + case 0: + { + lt = FACET; + li = 3; // useless ? + break; + } + case 1: + { + lt = EDGE; + li = ( o[0] == COLLINEAR ) ? i : + ( o[1] == COLLINEAR ) ? ccw(i) : + cw(i); + lj = ccw(li); + break; + } + case 2: + { + lt = VERTEX; + li = ( o[0] != COLLINEAR ) ? cw(i) : + ( o[1] != COLLINEAR ) ? i : + ccw(i); + break; + } + } + return c; } } case 1: @@ -2109,55 +2752,55 @@ exact_locate(const Point & p, Locate_type & lt, int & li, int & lj, //first tests whether p is collinear with the current triangulation if ( ! collinear( p, - c->vertex(0)->point(), - c->vertex(1)->point()) ) { - lt = OUTSIDE_AFFINE_HULL; - return c; + c->vertex(0)->point(), + c->vertex(1)->point()) ) { + lt = OUTSIDE_AFFINE_HULL; + return c; } // if p is collinear, location : while (1) { - if ( c->has_vertex(infinite) ) { - // c must contain p in its interior - lt = OUTSIDE_CONVEX_HULL; - return c; - } + if ( c->has_vertex(infinite) ) { + // c must contain p in its interior + lt = OUTSIDE_CONVEX_HULL; + return c; + } - // else c is finite - // we test on which direction to continue the traversal - switch (collinear_position(c->vertex(0)->point(), - p, - c->vertex(1)->point()) ) { - case AFTER: - c = c->neighbor(0); - continue; - case BEFORE: - c = c->neighbor(1); - continue; - case MIDDLE: - lt = EDGE; - li = 0; - lj = 1; - return c; - case SOURCE: - lt = VERTEX; - li = 0; - return c; - case TARGET: - lt = VERTEX; - li = 1; - return c; - } + // else c is finite + // we test on which direction to continue the traversal + switch (collinear_position(c->vertex(0)->point(), + p, + c->vertex(1)->point()) ) { + case AFTER: + c = c->neighbor(0); + continue; + case BEFORE: + c = c->neighbor(1); + continue; + case MIDDLE: + lt = EDGE; + li = 0; + lj = 1; + return c; + case SOURCE: + lt = VERTEX; + li = 0; + return c; + case TARGET: + lt = VERTEX; + li = 1; + return c; + } } } case 0: { Finite_vertices_iterator vit = finite_vertices_begin(); if ( ! equal( p, vit->point() ) ) { - lt = OUTSIDE_AFFINE_HULL; + lt = OUTSIDE_AFFINE_HULL; } else { - lt = VERTEX; - li = 0; + lt = VERTEX; + li = 0; } return vit->cell(); } @@ -2175,20 +2818,34 @@ exact_locate(const Point & p, Locate_type & lt, int & li, int & lj, } #ifndef CGAL_NO_STRUCTURAL_FILTERING -template -inline -typename Triangulation_3::Cell_handle -Triangulation_3:: -inexact_locate(const Point & t, Cell_handle start, int n_of_turns) const +template +inline +typename Triangulation_3::Cell_handle +Triangulation_3:: +inexact_locate(const Point & t, Cell_handle start, int n_of_turns, + bool *could_lock_zone) const { CGAL_triangulation_expensive_assertion(start == Cell_handle() || tds().is_simplex(start) ); + if (could_lock_zone) + *could_lock_zone = true; + if(dimension() < 3) return start; // Make sure we continue from here with a finite cell. if ( start == Cell_handle() ) start = infinite_cell(); + // CJTODO: useless? + if (could_lock_zone) + { + if (!this->try_lock_cell(start)) + { + *could_lock_zone = false; + return Cell_handle(); + } + } + int ind_inf; if( start->has_vertex(infinite, ind_inf) ) start = start->neighbor(ind_inf); @@ -2203,6 +2860,15 @@ inexact_locate(const Point & t, Cell_handle start, int n_of_turns) const Cell_handle previous = Cell_handle(); Cell_handle c = start; + if (could_lock_zone) + { + if (!this->try_lock_cell(c)) + { + *could_lock_zone = false; + return Cell_handle(); + } + } + // Now treat the cell c. try_next_cell: @@ -2235,6 +2901,16 @@ inexact_locate(const Point & t, Cell_handle start, int n_of_turns) const } previous = c; c = next; + if (could_lock_zone) + { + //previous->unlock(); // DON'T do that, "c" may be in + // the same locking cell as "previous" + if (!this->try_lock_cell(c)) + { + *could_lock_zone = false; + return Cell_handle(); + } + } if(n_of_turns) goto try_next_cell; } @@ -2242,15 +2918,15 @@ inexact_locate(const Point & t, Cell_handle start, int n_of_turns) const } #endif // no CGAL_NO_STRUCTURAL_FILTERING -template < class GT, class Tds > +template < class GT, class Tds, class Lds > Bounded_side -Triangulation_3:: +Triangulation_3:: side_of_tetrahedron(const Point & p, - const Point & p0, - const Point & p1, - const Point & p2, - const Point & p3, - Locate_type & lt, int & i, int & j ) const + const Point & p0, + const Point & p1, + const Point & p2, + const Point & p3, + Locate_type & lt, int & i, int & j ) const // p0,p1,p2,p3 supposed to be non coplanar // tetrahedron p0,p1,p2,p3 is supposed to be well oriented // returns : @@ -2288,9 +2964,9 @@ side_of_tetrahedron(const Point & p, lt = FACET; // i = index such that p lies on facet(i) i = ( o0 == ZERO ) ? 0 : - ( o1 == ZERO ) ? 1 : - ( o2 == ZERO ) ? 2 : - 3; + ( o1 == ZERO ) ? 1 : + ( o2 == ZERO ) ? 2 : + 3; return ON_BOUNDARY; } case 2: @@ -2299,13 +2975,13 @@ side_of_tetrahedron(const Point & p, // i = smallest index such that p does not lie on facet(i) // i must be < 3 since p lies on 2 facets i = ( o0 == POSITIVE ) ? 0 : - ( o1 == POSITIVE ) ? 1 : - 2; + ( o1 == POSITIVE ) ? 1 : + 2; // j = larger index such that p not on facet(j) // j must be > 0 since p lies on 2 facets j = ( o3 == POSITIVE ) ? 3 : - ( o2 == POSITIVE ) ? 2 : - 1; + ( o2 == POSITIVE ) ? 2 : + 1; return ON_BOUNDARY; } case 3: @@ -2313,9 +2989,9 @@ side_of_tetrahedron(const Point & p, lt = VERTEX; // i = index such that p does not lie on facet(i) i = ( o0 == POSITIVE ) ? 0 : - ( o1 == POSITIVE ) ? 1 : - ( o2 == POSITIVE ) ? 2 : - 3; + ( o1 == POSITIVE ) ? 1 : + ( o2 == POSITIVE ) ? 2 : + 3; return ON_BOUNDARY; } default: @@ -2327,12 +3003,12 @@ side_of_tetrahedron(const Point & p, } } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > Bounded_side -Triangulation_3:: +Triangulation_3:: side_of_cell(const Point & p, - Cell_handle c, - Locate_type & lt, int & i, int & j) const + Cell_handle c, + Locate_type & lt, int & i, int & j) const // returns // ON_BOUNDED_SIDE if p inside the cell // (for an infinite cell this means that p lies strictly in the half space @@ -2347,11 +3023,11 @@ side_of_cell(const Point & p, CGAL_triangulation_precondition( dimension() == 3 ); if ( ! is_infinite(c) ) { return side_of_tetrahedron(p, - c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point(), - c->vertex(3)->point(), - lt, i, j); + c->vertex(0)->point(), + c->vertex(1)->point(), + c->vertex(2)->point(), + c->vertex(3)->point(), + lt, i, j); } else { int inf = c->index(infinite); @@ -2368,69 +3044,69 @@ side_of_cell(const Point & p, switch (o) { case POSITIVE: { - lt = CELL; - return ON_BOUNDED_SIDE; + lt = CELL; + return ON_BOUNDED_SIDE; } case NEGATIVE: return ON_UNBOUNDED_SIDE; case ZERO: { - // location in the finite facet - int i_f, j_f; - Bounded_side side = - side_of_triangle(p, v1->point(), v2->point(), v3->point(), - lt, i_f, j_f); - // lt need not be modified in most cases : - switch (side) { - case ON_BOUNDED_SIDE: - { - // lt == FACET ok - i = inf; - return ON_BOUNDARY; - } - case ON_BOUNDARY: - { - // lt == VERTEX OR EDGE ok - i = ( i_f == 0 ) ? ((inf+1)&3) : - ( i_f == 1 ) ? ((inf+2)&3) : - ((inf+3)&3); - if ( lt == EDGE ) { - j = (j_f == 0 ) ? ((inf+1)&3) : - ( j_f == 1 ) ? ((inf+2)&3) : - ((inf+3)&3); - } - return ON_BOUNDARY; - } - case ON_UNBOUNDED_SIDE: - { - // p lies on the plane defined by the finite facet - // lt must be initialized - return ON_UNBOUNDED_SIDE; - } - default: - { - CGAL_triangulation_assertion(false); - return ON_BOUNDARY; - } - } // switch side + // location in the finite facet + int i_f, j_f; + Bounded_side side = + side_of_triangle(p, v1->point(), v2->point(), v3->point(), + lt, i_f, j_f); + // lt need not be modified in most cases : + switch (side) { + case ON_BOUNDED_SIDE: + { + // lt == FACET ok + i = inf; + return ON_BOUNDARY; + } + case ON_BOUNDARY: + { + // lt == VERTEX OR EDGE ok + i = ( i_f == 0 ) ? ((inf+1)&3) : + ( i_f == 1 ) ? ((inf+2)&3) : + ((inf+3)&3); + if ( lt == EDGE ) { + j = (j_f == 0 ) ? ((inf+1)&3) : + ( j_f == 1 ) ? ((inf+2)&3) : + ((inf+3)&3); + } + return ON_BOUNDARY; + } + case ON_UNBOUNDED_SIDE: + { + // p lies on the plane defined by the finite facet + // lt must be initialized + return ON_UNBOUNDED_SIDE; + } + default: + { + CGAL_triangulation_assertion(false); + return ON_BOUNDARY; + } + } // switch side }// case ZERO default: { - CGAL_triangulation_assertion(false); - return ON_BOUNDARY; + CGAL_triangulation_assertion(false); + return ON_BOUNDARY; } } // switch o } // else infinite cell } // side_of_cell -template < class GT, class Tds > +template < class GT, class Tds, class Lds > Bounded_side -Triangulation_3:: +Triangulation_3:: side_of_triangle(const Point & p, - const Point & p0, - const Point & p1, - const Point & p2, - Locate_type & lt, int & i, int & j ) const + const Point & p0, + const Point & p1, + const Point & p2, + Locate_type & lt, int & i, int & j ) const // p0,p1,p2 supposed to define a plane // p supposed to lie on plane p0,p1,p2 // triangle p0,p1,p2 defines the orientation of the plane @@ -2471,20 +3147,20 @@ side_of_triangle(const Point & p, { lt = EDGE; i = ( o0 == ZERO ) ? 0 : - ( o1 == ZERO ) ? 1 : - 2; + ( o1 == ZERO ) ? 1 : + 2; if ( i == 2 ) - j=0; + j=0; else - j = i+1; + j = i+1; return ON_BOUNDARY; } case 2: { lt = VERTEX; i = ( o0 == o012 ) ? 2 : - ( o1 == o012 ) ? 0 : - 1; + ( o1 == o012 ) ? 0 : + 1; return ON_BOUNDARY; } default: @@ -2496,12 +3172,12 @@ side_of_triangle(const Point & p, } } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > Bounded_side -Triangulation_3:: +Triangulation_3:: side_of_facet(const Point & p, - Cell_handle c, - Locate_type & lt, int & li, int & lj) const + Cell_handle c, + Locate_type & lt, int & li, int & lj) const // supposes dimension 2 otherwise does not work for infinite facets // returns : // ON_BOUNDED_SIDE if p inside the facet @@ -2526,10 +3202,10 @@ side_of_facet(const Point & p, // c->vertex(2)->point) ); int i_t, j_t; Bounded_side side = side_of_triangle(p, - c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point(), - lt, i_t, j_t); + c->vertex(0)->point(), + c->vertex(1)->point(), + c->vertex(2)->point(), + lt, i_t, j_t); // We protect the following code by this test to avoid valgrind messages. if (side == ON_BOUNDARY) { // indices in the original cell : @@ -2554,7 +3230,7 @@ side_of_facet(const Point & p, v2 = c->vertex(i2); CGAL_triangulation_assertion(coplanar_orientation(v1->point(), v2->point(), - mirror_vertex(c, inf)->point()) == POSITIVE); + mirror_vertex(c, inf)->point()) == POSITIVE); switch (coplanar_orientation(v1->point(), v2->point(), p)) { case POSITIVE: @@ -2569,30 +3245,30 @@ side_of_facet(const Point & p, // p collinear with v1v2 int i_e; switch (side_of_segment(p, v1->point(), v2->point(), lt, i_e)) { - // computation of the indices in the original cell + // computation of the indices in the original cell case ON_BOUNDED_SIDE: - // lt == EDGE ok - li = i1; - lj = i2; - return ON_BOUNDARY; + // lt == EDGE ok + li = i1; + lj = i2; + return ON_BOUNDARY; case ON_BOUNDARY: - // lt == VERTEX ok - li = ( i_e == 0 ) ? i1 : i2; - return ON_BOUNDARY; + // lt == VERTEX ok + li = ( i_e == 0 ) ? i1 : i2; + return ON_BOUNDARY; default: // case ON_UNBOUNDED_SIDE: - // p lies on the line defined by the finite edge - return ON_UNBOUNDED_SIDE; + // p lies on the line defined by the finite edge + return ON_UNBOUNDED_SIDE; } } } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > Bounded_side -Triangulation_3:: +Triangulation_3:: side_of_segment(const Point & p, - const Point & p0, - const Point & p1, - Locate_type & lt, int & i ) const + const Point & p0, + const Point & p1, + Locate_type & lt, int & i ) const // p0, p1 supposed to be different // p supposed to be collinear to p0, p1 // returns : @@ -2621,12 +3297,12 @@ side_of_segment(const Point & p, } } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > Bounded_side -Triangulation_3:: +Triangulation_3:: side_of_edge(const Point & p, - Cell_handle c, - Locate_type & lt, int & li) const + Cell_handle c, + Locate_type & lt, int & li) const // supposes dimension 1 otherwise does not work for infinite edges // returns : // ON_BOUNDED_SIDE if p inside the edge @@ -2641,15 +3317,15 @@ side_of_edge(const Point & p, CGAL_triangulation_precondition( dimension() == 1 ); if ( ! is_infinite(c,0,1) ) return side_of_segment(p, c->vertex(0)->point(), c->vertex(1)->point(), - lt, li); + lt, li); // else infinite edge int inf = c->index(infinite); switch (collinear_position(c->vertex(1-inf)->point(), p, - mirror_vertex(c, inf)->point())) { + mirror_vertex(c, inf)->point())) { case SOURCE: - lt = VERTEX; - li = 1-inf; - return ON_BOUNDARY; + lt = VERTEX; + li = 1-inf; + return ON_BOUNDARY; case BEFORE: lt = EDGE; return ON_BOUNDED_SIDE; @@ -2658,13 +3334,13 @@ side_of_edge(const Point & p, } } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > bool -Triangulation_3:: +Triangulation_3:: flip( Cell_handle c, int i ) { CGAL_triangulation_precondition( (dimension() == 3) && (0<=i) && (i<4) - && (number_of_vertices() >= 5) ); + && (number_of_vertices() >= 5) ); Cell_handle n = c->neighbor(i); int in = n->index(c); @@ -2672,104 +3348,104 @@ flip( Cell_handle c, int i ) if ( i%2 == 1 ) { if ( orientation( c->vertex((i+1)&3)->point(), - c->vertex((i+2)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - != POSITIVE ) return false; + c->vertex((i+2)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + != POSITIVE ) return false; if ( orientation( c->vertex((i+2)&3)->point(), - c->vertex((i+3)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - != POSITIVE ) return false; + c->vertex((i+3)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + != POSITIVE ) return false; if ( orientation( c->vertex((i+3)&3)->point(), - c->vertex((i+1)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - != POSITIVE ) return false; + c->vertex((i+1)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + != POSITIVE ) return false; } else { if ( orientation( c->vertex((i+2)&3)->point(), - c->vertex((i+1)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - != POSITIVE ) return false; + c->vertex((i+1)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + != POSITIVE ) return false; if ( orientation( c->vertex((i+3)&3)->point(), - c->vertex((i+2)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - != POSITIVE ) return false; + c->vertex((i+2)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + != POSITIVE ) return false; if ( orientation( c->vertex((i+1)&3)->point(), - c->vertex((i+3)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - != POSITIVE ) return false; + c->vertex((i+3)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + != POSITIVE ) return false; } _tds.flip_flippable(c, i); return true; } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > void -Triangulation_3:: +Triangulation_3:: flip_flippable( Cell_handle c, int i ) { CGAL_triangulation_precondition( (dimension() == 3) && (0<=i) && (i<4) - && (number_of_vertices() >= 5) ); + && (number_of_vertices() >= 5) ); CGAL_triangulation_precondition_code( Cell_handle n = c->neighbor(i); ); CGAL_triangulation_precondition_code( int in = n->index(c); ); CGAL_triangulation_precondition( ( ! is_infinite( c ) ) && - ( ! is_infinite( n ) ) ); + ( ! is_infinite( n ) ) ); if ( i%2 == 1 ) { CGAL_triangulation_precondition( orientation( c->vertex((i+1)&3)->point(), - c->vertex((i+2)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - == POSITIVE ); + c->vertex((i+2)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + == POSITIVE ); CGAL_triangulation_precondition( orientation( c->vertex((i+2)&3)->point(), - c->vertex((i+3)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - == POSITIVE ); + c->vertex((i+3)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + == POSITIVE ); CGAL_triangulation_precondition( orientation( c->vertex((i+3)&3)->point(), - c->vertex((i+1)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - == POSITIVE ); + c->vertex((i+1)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + == POSITIVE ); } else { CGAL_triangulation_precondition( orientation( c->vertex((i+2)&3)->point(), - c->vertex((i+1)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - == POSITIVE ); + c->vertex((i+1)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + == POSITIVE ); CGAL_triangulation_precondition( orientation( c->vertex((i+3)&3)->point(), - c->vertex((i+2)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - == POSITIVE ); + c->vertex((i+2)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + == POSITIVE ); CGAL_triangulation_precondition( orientation( c->vertex((i+1)&3)->point(), - c->vertex((i+3)&3)->point(), - n->vertex(in)->point(), - c->vertex(i)->point() ) - == POSITIVE ); + c->vertex((i+3)&3)->point(), + n->vertex(in)->point(), + c->vertex(i)->point() ) + == POSITIVE ); } _tds.flip_flippable(c, i); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > bool -Triangulation_3:: +Triangulation_3:: flip( Cell_handle c, int i, int j ) // flips edge i,j of cell c { CGAL_triangulation_precondition( (dimension() == 3) - && (0<=i) && (i<4) - && (0<=j) && (j<4) - && ( i != j ) - && (number_of_vertices() >= 5) ); + && (0<=i) && (i<4) + && (0<=j) && (j<4) + && ( i != j ) + && (number_of_vertices() >= 5) ); // checks that degree 3 and not on the convex hull int degree = 0; @@ -2788,33 +3464,33 @@ flip( Cell_handle c, int i, int j ) int in = n->index( c->vertex(i) ); int jn = n->index( c->vertex(j) ); if ( orientation( c->vertex(next_around_edge(i,j))->point(), - c->vertex(next_around_edge(j,i))->point(), - n->vertex(next_around_edge(jn,in))->point(), - c->vertex(j)->point() ) + c->vertex(next_around_edge(j,i))->point(), + n->vertex(next_around_edge(jn,in))->point(), + c->vertex(j)->point() ) != POSITIVE ) return false; if ( orientation( c->vertex(i)->point(), - c->vertex(next_around_edge(j,i))->point(), - n->vertex(next_around_edge(jn,in))->point(), - c->vertex(next_around_edge(i,j))->point() ) + c->vertex(next_around_edge(j,i))->point(), + n->vertex(next_around_edge(jn,in))->point(), + c->vertex(next_around_edge(i,j))->point() ) != POSITIVE ) return false; _tds.flip_flippable(c, i, j); return true; } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > void -Triangulation_3:: +Triangulation_3:: flip_flippable( Cell_handle c, int i, int j ) // flips edge i,j of cell c { #if !defined CGAL_TRIANGULATION_NO_PRECONDITIONS && \ !defined CGAL_NO_PRECONDITIONS && !defined NDEBUG CGAL_triangulation_precondition( (dimension() == 3) - && (0<=i) && (i<4) - && (0<=j) && (j<4) - && ( i != j ) - && (number_of_vertices() >= 5) ); + && (0<=i) && (i<4) + && (0<=j) && (j<4) + && ( i != j ) + && (number_of_vertices() >= 5) ); int degree = 0; Cell_circulator ccir = incident_cells(c,i,j); Cell_circulator cdone = ccir; @@ -2830,21 +3506,21 @@ flip_flippable( Cell_handle c, int i, int j ) int jn = n->index( c->vertex(j) ); CGAL_triangulation_precondition ( orientation( c->vertex(next_around_edge(i,j))->point(), - c->vertex(next_around_edge(j,i))->point(), - n->vertex(next_around_edge(jn,in))->point(), - c->vertex(j)->point() ) == POSITIVE ); + c->vertex(next_around_edge(j,i))->point(), + n->vertex(next_around_edge(jn,in))->point(), + c->vertex(j)->point() ) == POSITIVE ); CGAL_triangulation_precondition ( orientation( c->vertex(i)->point(), - c->vertex(next_around_edge(j,i))->point(), - n->vertex(next_around_edge(jn,in))->point(), - c->vertex(next_around_edge(i,j))->point() ) == POSITIVE ); + c->vertex(next_around_edge(j,i))->point(), + n->vertex(next_around_edge(jn,in))->point(), + c->vertex(next_around_edge(i,j))->point() ) == POSITIVE ); #endif _tds.flip_flippable(c, i, j); } -template < class GT, class Tds > -typename Triangulation_3::Vertex_handle -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::Vertex_handle +Triangulation_3:: insert(const Point & p, Cell_handle start) { Locate_type lt; @@ -2853,9 +3529,9 @@ insert(const Point & p, Cell_handle start) return insert(p, lt, c, li, lj); } -template < class GT, class Tds > -typename Triangulation_3::Vertex_handle -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::Vertex_handle +Triangulation_3:: insert(const Point & p, Locate_type lt, Cell_handle c, int li, int lj) { switch (lt) { @@ -2877,26 +3553,30 @@ insert(const Point & p, Locate_type lt, Cell_handle c, int li, int lj) -template < class GT, class Tds > +template < class GT, class Tds, class Lds > template < class Conflict_tester, class Hidden_points_visitor > -typename Triangulation_3::Vertex_handle -Triangulation_3:: +typename Triangulation_3::Vertex_handle +Triangulation_3:: insert_in_conflict(const Point & p, - Locate_type lt, Cell_handle c, int li, int /*lj*/, - const Conflict_tester &tester, - Hidden_points_visitor &hider) + Locate_type lt, Cell_handle c, int li, int /*lj*/, + const Conflict_tester &tester, + Hidden_points_visitor &hider, + bool *could_lock_zone) { + if (could_lock_zone) + *could_lock_zone = true; + switch (dimension()) { case 3: { if ((lt == VERTEX) && - (tester.compare_weight(c->vertex(li)->point(), p)==0) ) { - return c->vertex(li); + (tester.compare_weight(c->vertex(li)->point(), p)==0) ) { + return c->vertex(li); } // If the new point is not in conflict with its cell, it is hidden. if (!tester.test_initial_cell(c)) { - hider.hide_point(c,p); - return Vertex_handle(); + hider.hide_point(c,p); + return Vertex_handle(); } // Ok, we really insert the point now. @@ -2905,17 +3585,60 @@ insert_in_conflict(const Point & p, Facet facet; cells.reserve(32); - find_conflicts - (c, tester, make_triple(Oneset_iterator(facet), - std::back_inserter(cells), - Emptyset_iterator())); + + // Parallel + if (could_lock_zone) + { + std::vector facets; + facets.reserve(32); + + find_conflicts( + c, + tester, + make_triple( + std::back_inserter(facets), + std::back_inserter(cells), + Emptyset_iterator()), + could_lock_zone); + + if (*could_lock_zone == false) + { + BOOST_FOREACH(Cell_handle& ch, + std::make_pair(cells.begin(), cells.end())) + { + ch->tds_data().clear(); + } + + BOOST_FOREACH(Facet& f, + std::make_pair(facets.begin(), facets.end())) + { + f.first->neighbor(f.second)->tds_data().clear(); + } + return Vertex_handle(); + } + + facet = facets.back(); + } + // Sequential + else + { + cells.reserve(32); + find_conflicts( + c, + tester, + make_triple( + Oneset_iterator(facet), + std::back_inserter(cells), + Emptyset_iterator())); + } + // Remember the points that are hidden by the conflicting cells, // as they will be deleted during the insertion. hider.process_cells_in_conflict(cells.begin(), cells.end()); Vertex_handle v = _insert_in_hole(p, cells.begin(), cells.end(), - facet.first, facet.second); + facet.first, facet.second); // Store the hidden points in their new cells. hider.reinsert_vertices(v); @@ -2925,16 +3648,16 @@ insert_in_conflict(const Point & p, { // This check is added compared to the 3D case if (lt == OUTSIDE_AFFINE_HULL) - return insert_outside_affine_hull (p); + return insert_outside_affine_hull (p); if ((lt == VERTEX) && - (tester.compare_weight(c->vertex(li)->point(), p)==0) ) { - return c->vertex(li); + (tester.compare_weight(c->vertex(li)->point(), p)==0) ) { + return c->vertex(li); } // If the new point is not in conflict with its cell, it is hidden. if (!tester.test_initial_cell(c)) { - hider.hide_point(c,p); - return Vertex_handle(); + hider.hide_point(c,p); + return Vertex_handle(); } // Ok, we really insert the point now. @@ -2944,16 +3667,16 @@ insert_in_conflict(const Point & p, cells.reserve(32); find_conflicts - (c, tester, make_triple(Oneset_iterator(facet), - std::back_inserter(cells), - Emptyset_iterator())); + (c, tester, make_triple(Oneset_iterator(facet), + std::back_inserter(cells), + Emptyset_iterator())); // Remember the points that are hidden by the conflicting cells, // as they will be deleted during the insertion. hider.process_cells_in_conflict(cells.begin(), cells.end()); Vertex_handle v = _insert_in_hole(p, cells.begin(), cells.end(), - facet.first, facet.second); + facet.first, facet.second); // Store the hidden points in their new cells. hider.reinsert_vertices(v); @@ -2963,21 +3686,21 @@ insert_in_conflict(const Point & p, { // dimension() <= 1 if (lt == OUTSIDE_AFFINE_HULL) - return insert_outside_affine_hull (p); + return insert_outside_affine_hull (p); if (lt == VERTEX && - tester.compare_weight(c->vertex(li)->point(), p) == 0) { - return c->vertex(li); + tester.compare_weight(c->vertex(li)->point(), p) == 0) { + return c->vertex(li); } // If the new point is not in conflict with its cell, it is hidden. if (! tester.test_initial_cell(c)) { - hider.hide_point(c,p); - return Vertex_handle(); + hider.hide_point(c,p); + return Vertex_handle(); } if (dimension() == 0) { - return hider.replace_vertex(c, li, p); + return hider.replace_vertex(c, li, p); } @@ -2995,12 +3718,12 @@ insert_in_conflict(const Point & p, cells.push_back(c); for (int j = 0; j<2; ++j) { - Cell_handle n = c->neighbor(j); - while ( tester(n) ) { - cells.push_back(n); - n = n->neighbor(j); - } - bound[j] = n; + Cell_handle n = c->neighbor(j); + while ( tester(n) ) { + cells.push_back(n); + n = n->neighbor(j); + } + bound[j] = n; } // Insertion. @@ -3027,9 +3750,9 @@ insert_in_conflict(const Point & p, } } -template < class GT, class Tds > -typename Triangulation_3::Vertex_handle -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::Vertex_handle +Triangulation_3:: insert_in_cell(const Point & p, Cell_handle c) { CGAL_triangulation_precondition( dimension() == 3 ); @@ -3038,54 +3761,54 @@ insert_in_cell(const Point & p, Cell_handle c) int i; int j; ); CGAL_triangulation_precondition ( side_of_tetrahedron( p, - c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point(), - c->vertex(3)->point(), - lt,i,j ) == ON_BOUNDED_SIDE ); + c->vertex(0)->point(), + c->vertex(1)->point(), + c->vertex(2)->point(), + c->vertex(3)->point(), + lt,i,j ) == ON_BOUNDED_SIDE ); Vertex_handle v = _tds.insert_in_cell(c); v->set_point(p); return v; } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > inline -typename Triangulation_3::Vertex_handle -Triangulation_3:: +typename Triangulation_3::Vertex_handle +Triangulation_3:: insert_in_facet(const Point & p, Cell_handle c, int i) { CGAL_triangulation_precondition( dimension() == 2 || dimension() == 3); CGAL_triangulation_precondition( (dimension() == 2 && i == 3) - || (dimension() == 3 && i >= 0 && i <= 3) ); + || (dimension() == 3 && i >= 0 && i <= 3) ); CGAL_triangulation_exactness_precondition_code ( Locate_type lt; int li; int lj; ); CGAL_triangulation_exactness_precondition ( coplanar( p, c->vertex((i+1)&3)->point(), - c->vertex((i+2)&3)->point(), - c->vertex((i+3)&3)->point() ) + c->vertex((i+2)&3)->point(), + c->vertex((i+3)&3)->point() ) && side_of_triangle( p, - c->vertex((i+1)&3)->point(), - c->vertex((i+2)&3)->point(), - c->vertex((i+3)&3)->point(), - lt, li, lj) == ON_BOUNDED_SIDE ); + c->vertex((i+1)&3)->point(), + c->vertex((i+2)&3)->point(), + c->vertex((i+3)&3)->point(), + lt, li, lj) == ON_BOUNDED_SIDE ); Vertex_handle v = _tds.insert_in_facet(c, i); v->set_point(p); return v; } -template < class GT, class Tds > -typename Triangulation_3::Vertex_handle -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::Vertex_handle +Triangulation_3:: insert_in_edge(const Point & p, Cell_handle c, int i, int j) { CGAL_triangulation_precondition( i != j ); CGAL_triangulation_precondition( dimension() >= 1 && dimension() <= 3 ); CGAL_triangulation_precondition( i >= 0 && i <= dimension() - && j >= 0 && j <= dimension() ); + && j >= 0 && j <= dimension() ); CGAL_triangulation_exactness_precondition_code( Locate_type lt; int li; ); switch ( dimension() ) { case 3: @@ -3094,18 +3817,18 @@ insert_in_edge(const Point & p, Cell_handle c, int i, int j) CGAL_triangulation_precondition( ! is_infinite(c, i, j) ); CGAL_triangulation_exactness_precondition( collinear( c->vertex(i)->point(), - p, - c->vertex(j)->point() ) - && side_of_segment( p, - c->vertex(i)->point(), - c->vertex(j)->point(), - lt, li ) == ON_BOUNDED_SIDE ); + p, + c->vertex(j)->point() ) + && side_of_segment( p, + c->vertex(i)->point(), + c->vertex(j)->point(), + lt, li ) == ON_BOUNDED_SIDE ); break; } case 1: { CGAL_triangulation_exactness_precondition( side_of_edge(p, c, lt, li) - == ON_BOUNDED_SIDE ); + == ON_BOUNDED_SIDE ); break; } } @@ -3115,9 +3838,9 @@ insert_in_edge(const Point & p, Cell_handle c, int i, int j) return v; } -template < class GT, class Tds > -typename Triangulation_3::Vertex_handle -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::Vertex_handle +Triangulation_3:: insert_outside_convex_hull(const Point & p, Cell_handle c) // c is an infinite cell containing p // p is strictly outside the convex hull @@ -3152,9 +3875,9 @@ insert_outside_convex_hull(const Point & p, Cell_handle c) } } -template < class GT, class Tds > -typename Triangulation_3::Vertex_handle -Triangulation_3:: +template < class GT, class Tds, class Lds > +typename Triangulation_3::Vertex_handle +Triangulation_3:: insert_outside_affine_hull(const Point & p) { CGAL_triangulation_precondition( dimension() < 3 ); @@ -3165,7 +3888,7 @@ insert_outside_affine_hull(const Point & p) Cell_handle c = infinite_cell(); Cell_handle n = c->neighbor(c->index(infinite_vertex())); Orientation o = coplanar_orientation(n->vertex(0)->point(), - n->vertex(1)->point(), p); + n->vertex(1)->point(), p); CGAL_triangulation_precondition ( o != COLLINEAR ); reorient = o == NEGATIVE; break; @@ -3175,8 +3898,8 @@ insert_outside_affine_hull(const Point & p) Cell_handle c = infinite_cell(); Cell_handle n = c->neighbor(c->index(infinite_vertex())); Orientation o = orientation( n->vertex(0)->point(), - n->vertex(1)->point(), - n->vertex(2)->point(), p ); + n->vertex(1)->point(), + n->vertex(2)->point(), p ); CGAL_triangulation_precondition ( o != COPLANAR ); reorient = o == NEGATIVE; break; @@ -3194,10 +3917,10 @@ insert_outside_affine_hull(const Point & p) return v; } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > template < class OutputItCells > -typename Triangulation_3::Vertex_handle -Triangulation_3::insert_and_give_new_cells(const Point &p, +typename Triangulation_3::Vertex_handle +Triangulation_3::insert_and_give_new_cells(const Point &p, OutputItCells fit, Cell_handle start) { @@ -3211,8 +3934,8 @@ Triangulation_3::insert_and_give_new_cells(const Point &p, *fit++ = c; int i = c->index(v); c = c->neighbor((i+1)%3); - } while(c != end); - } + } while(c != end); + } else if(dimension == 1) { Cell_handle c = v->cell(); @@ -3220,13 +3943,13 @@ Triangulation_3::insert_and_give_new_cells(const Point &p, *fit++ = c->neighbor((~(c->index(v)))&1); } else *fit++ = v->cell(); // dimension = 0 - return v; + return v; } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > template < class OutputItCells > -typename Triangulation_3::Vertex_handle -Triangulation_3::insert_and_give_new_cells(const Point& p, +typename Triangulation_3::Vertex_handle +Triangulation_3::insert_and_give_new_cells(const Point& p, OutputItCells fit, Vertex_handle hint) { @@ -3240,8 +3963,8 @@ Triangulation_3::insert_and_give_new_cells(const Point& p, *fit++ = c; int i = c->index(v); c = c->neighbor((i+1)%3); - } while(c != end); - } + } while(c != end); + } else if(dimension == 1) { Cell_handle c = v->cell(); @@ -3252,12 +3975,12 @@ Triangulation_3::insert_and_give_new_cells(const Point& p, return v; } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > template < class OutputItCells > -typename Triangulation_3::Vertex_handle -Triangulation_3::insert_and_give_new_cells(const Point& p, +typename Triangulation_3::Vertex_handle +Triangulation_3::insert_and_give_new_cells(const Point& p, Locate_type lt, - Cell_handle c, int li, int lj, + Cell_handle c, int li, int lj, OutputItCells fit) { Vertex_handle v = insert(p, lt, c, li, lj); @@ -3270,21 +3993,21 @@ Triangulation_3::insert_and_give_new_cells(const Point& p, *fit++ = c; int i = c->index(v); c = c->neighbor((i+1)%3); - } while(c != end); - } + } while(c != end); + } else if(dimension == 1) { Cell_handle c = v->cell(); *fit++ = c; *fit++ = c->neighbor((~(c->index(v)))&1); } - else *fit++ = v->cell(); // dimension = 0 + else *fit++ = v->cell(); // dimension = 0 return v; } -template < class Gt, class Tds > -typename Triangulation_3::Vertex_triple -Triangulation_3:: +template +typename Triangulation_3::Vertex_triple +Triangulation_3:: make_vertex_triple(const Facet& f) const { Cell_handle ch = f.first; @@ -3295,9 +4018,9 @@ make_vertex_triple(const Facet& f) const ch->vertex(vertex_triple_index(i,2))); } -template < class Gt, class Tds > +template void -Triangulation_3:: +Triangulation_3:: make_canonical(Vertex_triple& t) const { int i = (&*(t.first) < &*(t.second))? 0 : 1; @@ -3323,9 +4046,9 @@ make_canonical(Vertex_triple& t) const } } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > bool -Triangulation_3:: +Triangulation_3:: test_dim_down(Vertex_handle v) const // tests whether removing v decreases the dimension of the triangulation // true iff @@ -3350,8 +4073,8 @@ test_dim_down(Vertex_handle v) const if ( ! cit->has_vertex(v,iv) ) return false; for (int i=1; i<4; i++ ) - if ( !coplanar(p1,p2,p3,cit->vertex((iv+i)&3)->point()) ) - return false; + if ( !coplanar(p1,p2,p3,cit->vertex((iv+i)&3)->point()) ) + return false; } } else if (dimension() == 2) @@ -3369,8 +4092,8 @@ test_dim_down(Vertex_handle v) const if ( ! cit->first->has_vertex(v,iv) ) return false; if ( !collinear(p1, p2, cit->first->vertex(cw(iv))->point()) || - !collinear(p1, p2, cit->first->vertex(ccw(iv))->point()) ) - return false; + !collinear(p1, p2, cit->first->vertex(ccw(iv))->point()) ) + return false; } } else // dimension() == 1 or 0 @@ -3379,15 +4102,71 @@ test_dim_down(Vertex_handle v) const return true; } -template +template < class GT, class Tds, class Lds > +bool +Triangulation_3:: +test_dim_down_using_incident_cells_3( + Vertex_handle v, std::vector &incident_cells, + std::vector &adj_vertices, + bool *could_lock_zone) const +{ + CGAL_triangulation_precondition(dimension() == 3); + CGAL_triangulation_precondition(! is_infinite(v) ); + + // Collect all vertices on the boundary + // and all incident cells + if (could_lock_zone) + { + *could_lock_zone = try_lock_and_get_adjacent_vertices_and_cells_3( + v, std::back_inserter(adj_vertices), incident_cells); + if (*could_lock_zone == false) + return false; + } + else + { + adjacent_vertices_and_cells_3( + v, std::back_inserter(adj_vertices), incident_cells); + } + + typedef Filter_iterator< typename std::vector::const_iterator, + Infinite_tester + > Finite_vertex_iterator; + Finite_vertex_iterator vit( + adj_vertices.end(), Infinite_tester(this), adj_vertices.begin()); + Finite_vertex_iterator vit_end( + adj_vertices.end(), Infinite_tester(this)); + const Point &p1 = (*vit++)->point(); + const Point &p2 = (*vit++)->point(); + const Point &p3 = (*vit++)->point(); + + for ( ; vit != vit_end ; ++vit ) + { + if (!coplanar(p1, p2, p3, (*vit)->point())) + return false; + } + + for (typename std::vector::const_iterator it_inc_cell + = incident_cells.begin() ; + it_inc_cell != incident_cells.end() ; + ++it_inc_cell) + { + if (!is_infinite(*it_inc_cell)) + return is_infinite(mirror_vertex( + *it_inc_cell, (*it_inc_cell)->index(v))); + } + + return true; +} + +template template < class VertexRemover > VertexRemover& -Triangulation_3:: +Triangulation_3:: make_hole_2D(Vertex_handle v, std::list &hole, VertexRemover &remover) { std::vector to_delete; to_delete.reserve(32); - + Face_circulator fc = tds().incident_faces(v); Face_circulator done(fc); @@ -3417,10 +4196,10 @@ make_hole_2D(Vertex_handle v, std::list &hole, VertexRemover &remover) // this one also erases a set of cells // which is useful to the move method // outputting newly created cells -template +template template < class VertexRemover > VertexRemover& -Triangulation_3:: +Triangulation_3:: make_hole_2D(Vertex_handle v, std::list &hole, VertexRemover &remover, std::set &cells_set) { @@ -3456,10 +4235,10 @@ make_hole_2D(Vertex_handle v, std::list &hole, VertexRemover &remover, return remover; } -template +template template < class VertexRemover > void -Triangulation_3:: +Triangulation_3:: fill_hole_2D(std::list & first_hole, VertexRemover &remover) { typedef std::list Hole; @@ -3478,12 +4257,12 @@ fill_hole_2D(std::list & first_hole, VertexRemover &remover) // if the hole has only three edges, create the triangle if (hole.size() == 3) { - typename Hole::iterator hit = hole.begin(); - f = (*hit).first; i = (*hit).second; - ff = (* ++hit).first; ii = (*hit).second; - fn = (* ++hit).first; in = (*hit).second; - tds().create_face(f, i, ff, ii, fn, in); - continue; + typename Hole::iterator hit = hole.begin(); + f = (*hit).first; i = (*hit).second; + ff = (* ++hit).first; ii = (*hit).second; + fn = (* ++hit).first; in = (*hit).second; + tds().create_face(f, i, ff, ii, fn, in); + continue; } // else find an edge with two finite vertices @@ -3495,15 +4274,15 @@ fill_hole_2D(std::list & first_hole, VertexRemover &remover) // whose vertices on the hole boundary are finite // is the first of the hole while (1) { - ff = (hole.front()).first; - ii = (hole.front()).second; - if ( is_infinite(ff->vertex(cw(ii))) || - is_infinite(ff->vertex(ccw(ii)))) { + ff = (hole.front()).first; + ii = (hole.front()).second; + if ( is_infinite(ff->vertex(cw(ii))) || + is_infinite(ff->vertex(ccw(ii)))) { hole.push_back(hole.front()); hole.pop_front(); - } - else - break; + } + else + break; } // take the first neighboring face and pop it; @@ -3527,25 +4306,25 @@ fill_hole_2D(std::list & first_hole, VertexRemover &remover) // stop at the before last face; hdone--; for (; hit != hdone; ++hit) { - fn = hit->first; - in = hit->second; + fn = hit->first; + in = hit->second; Vertex_handle vv = fn->vertex(ccw(in)); - if (is_infinite(vv)) { - if (is_infinite(v2)) - cut_after = hit; - } - else { // vv is a finite vertex - const Point &p = vv->point(); - if (coplanar_orientation(p0, p1, p) == COUNTERCLOCKWISE) { - if (is_infinite(v2) || - remover.side_of_bounded_circle(p0, p1, *p2, p, true) - == ON_BOUNDED_SIDE) { - v2 = vv; - p2 = &p; - cut_after = hit; - } - } - } + if (is_infinite(vv)) { + if (is_infinite(v2)) + cut_after = hit; + } + else { // vv is a finite vertex + const Point &p = vv->point(); + if (coplanar_orientation(p0, p1, p) == COUNTERCLOCKWISE) { + if (is_infinite(v2) || + remover.side_of_bounded_circle(p0, p1, *p2, p, true) + == ON_BOUNDED_SIDE) { + v2 = vv; + p2 = &p; + cut_after = hit; + } + } + } } // create new triangle and update adjacency relations @@ -3559,44 +4338,44 @@ fill_hole_2D(std::list & first_hole, VertexRemover &remover) fn = (hole.front()).first; in = (hole.front()).second; if (fn->has_vertex(v2, i) && i == ccw(in)) { - newf = tds().create_face(ff, ii, fn, in); - hole.pop_front(); - hole.push_front(Edge_2D(newf, 1)); - hole_list.push_back(hole); + newf = tds().create_face(ff, ii, fn, in); + hole.pop_front(); + hole.push_front(Edge_2D(newf, 1)); + hole_list.push_back(hole); } else{ - fn = (hole.back()).first; - in = (hole.back()).second; - if (fn->has_vertex(v2, i) && i == cw(in)) { - newf = tds().create_face(fn, in, ff, ii); - hole.pop_back(); - hole.push_back(Edge_2D(newf, 1)); - hole_list.push_back(hole); - } - else{ - // split the hole in two holes - newf = tds().create_face(ff, ii, v2); - Hole new_hole; - ++cut_after; - while( hole.begin() != cut_after ) + fn = (hole.back()).first; + in = (hole.back()).second; + if (fn->has_vertex(v2, i) && i == cw(in)) { + newf = tds().create_face(fn, in, ff, ii); + hole.pop_back(); + hole.push_back(Edge_2D(newf, 1)); + hole_list.push_back(hole); + } + else{ + // split the hole in two holes + newf = tds().create_face(ff, ii, v2); + Hole new_hole; + ++cut_after; + while( hole.begin() != cut_after ) { new_hole.push_back(hole.front()); hole.pop_front(); } - hole.push_front(Edge_2D(newf, 1)); - new_hole.push_front(Edge_2D(newf, 0)); - hole_list.push_back(hole); - hole_list.push_back(new_hole); - } + hole.push_front(Edge_2D(newf, 1)); + new_hole.push_front(Edge_2D(newf, 0)); + hole_list.push_back(hole); + hole_list.push_back(new_hole); + } } } } -template +template template < class VertexRemover, class OutputItCells > void -Triangulation_3:: +Triangulation_3:: fill_hole_2D(std::list & first_hole, VertexRemover &remover, OutputItCells fit) { @@ -3731,12 +4510,12 @@ fill_hole_2D(std::list & first_hole, VertexRemover &remover, } } -template < class Gt, class Tds > +template void -Triangulation_3:: +Triangulation_3:: make_hole_3D( Vertex_handle v, - std::map& outer_map, - std::vector & hole) + Vertex_triple_Facet_map& outer_map, + std::vector & hole) { CGAL_triangulation_expensive_precondition( ! test_dim_down(v) ); @@ -3752,14 +4531,38 @@ make_hole_3D( Vertex_handle v, outer_map[vt] = f; for (int i=0; i<4; i++) if ( i != indv ) - (*cit)->vertex(i)->set_cell(opp_cit); + (*cit)->vertex(i)->set_cell(opp_cit); } } -template < class Gt, class Tds > +// When the incident cells are already known +template +void +Triangulation_3:: +make_hole_3D( Vertex_handle v, + const std::vector & incident_cells, + Vertex_triple_Facet_map& outer_map) +{ + CGAL_triangulation_expensive_precondition( ! test_dim_down(v) ); + + for (typename std::vector::const_iterator cit = incident_cells.begin(), + end = incident_cells.end(); cit != end; ++cit) { + int indv = (*cit)->index(v); + Cell_handle opp_cit = (*cit)->neighbor( indv ); + Facet f(opp_cit, opp_cit->index(*cit)); + Vertex_triple vt = make_vertex_triple(f); + make_canonical(vt); + outer_map[vt] = f; + for (int i=0; i<4; i++) + if ( i != indv ) + (*cit)->vertex(i)->set_cell(opp_cit); + } +} + +template template < class VertexRemover > VertexRemover& -Triangulation_3:: +Triangulation_3:: remove_dim_down(Vertex_handle v, VertexRemover &remover) { CGAL_triangulation_precondition (dimension() >= 0); @@ -3783,10 +4586,10 @@ remove_dim_down(Vertex_handle v, VertexRemover &remover) return remover; } -template < class Gt, class Tds > +template template < class VertexRemover > VertexRemover& -Triangulation_3:: +Triangulation_3:: remove_1D(Vertex_handle v, VertexRemover &remover) { CGAL_triangulation_precondition (dimension() == 1); @@ -3801,10 +4604,10 @@ remove_1D(Vertex_handle v, VertexRemover &remover) return remover; } -template < class Gt, class Tds > +template template < class VertexRemover > VertexRemover& -Triangulation_3:: +Triangulation_3:: remove_2D(Vertex_handle v, VertexRemover &remover) { CGAL_triangulation_precondition(dimension() == 2); @@ -3815,10 +4618,10 @@ remove_2D(Vertex_handle v, VertexRemover &remover) return remover; } -template < class Gt, class Tds > +template template < class VertexRemover > VertexRemover& -Triangulation_3:: +Triangulation_3:: remove_3D(Vertex_handle v, VertexRemover &remover) { std::vector hole; @@ -3826,7 +4629,6 @@ remove_3D(Vertex_handle v, VertexRemover &remover) // Construct the set of vertex triples on the boundary // with the facet just behind - typedef std::map Vertex_triple_Facet_map; Vertex_triple_Facet_map outer_map; Vertex_triple_Facet_map inner_map; @@ -3840,7 +4642,6 @@ remove_3D(Vertex_handle v, VertexRemover &remover) remover.add_hidden_points(*hi); bool inf = false; - unsigned int i; // collect all vertices on the boundary std::vector vertices; vertices.reserve(64); @@ -3851,9 +4652,49 @@ remove_3D(Vertex_handle v, VertexRemover &remover) // and make a map from the vertices in remover.tmp towards the vertices // in *this - Unique_hash_map vmap; + unsigned int i = 0; + Vertex_handle_unique_hash_map vmap; Cell_handle ch = Cell_handle(); - for(i=0; i < vertices.size(); i++){ +#ifdef CGAL_TRIANGULATION_3_USE_THE_4_POINTS_CONSTRUCTOR + size_t num_vertices = vertices.size(); + if (num_vertices >= 5) + { + //std::random_shuffle(vertices.begin(), vertices.end()); + for (int j = 0 ; j < 4 ; ++j) + { + if (is_infinite(vertices[j])) + { + std::swap(vertices[j], vertices[4]); + break; + } + } + Orientation o = orientation( + vertices[0]->point(), + vertices[1]->point(), + vertices[2]->point(), + vertices[3]->point()); + + if (o == NEGATIVE) + std::swap(vertices[0], vertices[1]); + + if (o != ZERO) + { + Vertex_handle vh1, vh2, vh3, vh4; + remover.tmp.init_tds( + vertices[0]->point(), vertices[1]->point(), + vertices[2]->point(), vertices[3]->point(), + vh1, vh2, vh3, vh4); + ch = vh1->cell(); + vmap[vh1] = vertices[0]; + vmap[vh2] = vertices[1]; + vmap[vh3] = vertices[2]; + vmap[vh4] = vertices[3]; + i = 4; + } + } +#endif + + for(; i < vertices.size(); i++){ if(! is_infinite(vertices[i])){ Vertex_handle vh = remover.tmp.insert(vertices[i]->point(), ch); ch = vh->cell(); @@ -3878,24 +4719,24 @@ remove_3D(Vertex_handle v, VertexRemover &remover) if(inf){ for(All_cells_iterator it = remover.tmp.all_cells_begin(), - end = remover.tmp.all_cells_end(); it != end; ++it){ + end = remover.tmp.all_cells_end(); it != end; ++it){ for(i=0; i < 4; i++){ - Facet f = std::pair(it,i); - Vertex_triple vt_aux = make_vertex_triple(f); - Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); - make_canonical(vt); - inner_map[vt]= f; + Facet f = std::pair(it,i); + Vertex_triple vt_aux = make_vertex_triple(f); + Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); + make_canonical(vt); + inner_map[vt]= f; } } } else { for(Finite_cells_iterator it = remover.tmp.finite_cells_begin(), - end = remover.tmp.finite_cells_end(); it != end; ++it){ + end = remover.tmp.finite_cells_end(); it != end; ++it){ for(i=0; i < 4; i++){ - Facet f = std::pair(it,i); - Vertex_triple vt_aux = make_vertex_triple(f); - Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); - make_canonical(vt); - inner_map[vt]= f; + Facet f = std::pair(it,i); + Vertex_triple vt_aux = make_vertex_triple(f); + Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); + make_canonical(vt); + inner_map[vt]= f; } } } @@ -3903,8 +4744,8 @@ remove_3D(Vertex_handle v, VertexRemover &remover) while(! outer_map.empty()){ typename Vertex_triple_Facet_map::iterator oit = outer_map.begin(); while(is_infinite(oit->first.first) || - is_infinite(oit->first.second) || - is_infinite(oit->first.third)){ + is_infinite(oit->first.second) || + is_infinite(oit->first.third)){ ++oit; // otherwise the lookup in the inner_map fails // because the infinite vertices are different @@ -3923,7 +4764,7 @@ remove_3D(Vertex_handle v, VertexRemover &remover) // create a new cell and glue it to the outer surface Cell_handle new_ch = tds().create_cell(); new_ch->set_vertices(vmap[i_ch->vertex(0)], vmap[i_ch->vertex(1)], - vmap[i_ch->vertex(2)], vmap[i_ch->vertex(3)]); + vmap[i_ch->vertex(2)], vmap[i_ch->vertex(3)]); o_ch->set_neighbor(o_i,new_ch); new_ch->set_neighbor(i_i, o_ch); @@ -3931,23 +4772,23 @@ remove_3D(Vertex_handle v, VertexRemover &remover) // for the other faces check, if they can also be glued for(i = 0; i < 4; i++){ if(i != i_i){ - Facet f = std::pair(new_ch,i); - Vertex_triple vt = make_vertex_triple(f); - make_canonical(vt); - std::swap(vt.second,vt.third); - typename Vertex_triple_Facet_map::iterator oit2 = outer_map.find(vt); - if(oit2 == outer_map.end()){ - std::swap(vt.second,vt.third); - outer_map[vt]= f; - } else { - // glue the faces - typename Vertex_triple_Facet_map::value_type o_vt_f_pair2 = *oit2; - Cell_handle o_ch2 = o_vt_f_pair2.second.first; - int o_i2 = o_vt_f_pair2.second.second; - o_ch2->set_neighbor(o_i2,new_ch); - new_ch->set_neighbor(i, o_ch2); - outer_map.erase(oit2); - } + Facet f = std::pair(new_ch,i); + Vertex_triple vt = make_vertex_triple(f); + make_canonical(vt); + std::swap(vt.second,vt.third); + typename Vertex_triple_Facet_map::iterator oit2 = outer_map.find(vt); + if(oit2 == outer_map.end()){ + std::swap(vt.second,vt.third); + outer_map[vt]= f; + } else { + // glue the faces + typename Vertex_triple_Facet_map::value_type o_vt_f_pair2 = *oit2; + Cell_handle o_ch2 = o_vt_f_pair2.second.first; + int o_i2 = o_vt_f_pair2.second.second; + o_ch2->set_neighbor(o_i2,new_ch); + new_ch->set_neighbor(i, o_ch2); + outer_map.erase(oit2); + } } } outer_map.erase(oit); @@ -3958,10 +4799,186 @@ remove_3D(Vertex_handle v, VertexRemover &remover) return remover; } -template < class Gt, class Tds > +template +template < class VertexRemover > +VertexRemover& +Triangulation_3:: +remove_3D(Vertex_handle v, VertexRemover &remover, + const std::vector &inc_cells, + std::vector &adj_vertices) +{ + // Construct the set of vertex triples on the boundary + // with the facet just behind + Vertex_triple_Facet_map outer_map; + Vertex_triple_Facet_map inner_map; + + make_hole_3D(v, inc_cells, outer_map); + + CGAL_assertion(remover.hidden_points_begin() == + remover.hidden_points_end() ); + + // Output the hidden points. + for (typename std::vector::const_iterator + hi = inc_cells.begin(), hend = inc_cells.end(); hi != hend; ++hi) + remover.add_hidden_points(*hi); + + bool inf = false; + + // create a Delaunay triangulation of the points on the boundary + // and make a map from the vertices in remover.tmp towards the vertices + // in *this + + unsigned int i = 0; + Vertex_handle_unique_hash_map vmap; + Cell_handle ch = Cell_handle(); +#ifdef CGAL_TRIANGULATION_3_USE_THE_4_POINTS_CONSTRUCTOR + size_t num_vertices = adj_vertices.size(); + if (num_vertices >= 5) + { + //std::random_shuffle(adj_vertices.begin(), adj_vertices.end()); + for (int j = 0 ; j < 4 ; ++j) + { + if (is_infinite(adj_vertices[j])) + { + std::swap(adj_vertices[j], adj_vertices[4]); + break; + } + } + Orientation o = orientation( + adj_vertices[0]->point(), + adj_vertices[1]->point(), + adj_vertices[2]->point(), + adj_vertices[3]->point()); + + if (o == NEGATIVE) + std::swap(adj_vertices[0], adj_vertices[1]); + + if (o != ZERO) + { + Vertex_handle vh1, vh2, vh3, vh4; + remover.tmp.init_tds( + adj_vertices[0]->point(), adj_vertices[1]->point(), + adj_vertices[2]->point(), adj_vertices[3]->point(), + vh1, vh2, vh3, vh4); + ch = vh1->cell(); + vmap[vh1] = adj_vertices[0]; + vmap[vh2] = adj_vertices[1]; + vmap[vh3] = adj_vertices[2]; + vmap[vh4] = adj_vertices[3]; + i = 4; + } + } +#endif + + for(; i < adj_vertices.size(); i++){ + if(! is_infinite(adj_vertices[i])){ + Vertex_handle vh = remover.tmp.insert(adj_vertices[i]->point(), ch); + ch = vh->cell(); + vmap[vh] = adj_vertices[i]; + }else { + inf = true; + } + } + + if(remover.tmp.dimension()==2){ + Vertex_handle fake_inf = remover.tmp.insert(v->point()); + vmap[fake_inf] = infinite_vertex(); + } else { + vmap[remover.tmp.infinite_vertex()] = infinite_vertex(); + } + + CGAL_triangulation_assertion(remover.tmp.dimension() == 3); + + // Construct the set of vertex triples of remover.tmp + // We reorient the vertex triple so that it matches those from outer_map + // Also note that we use the vertices of *this, not of remover.tmp + + if(inf){ + for(All_cells_iterator it = remover.tmp.all_cells_begin(), + end = remover.tmp.all_cells_end(); it != end; ++it){ + for(i=0; i < 4; i++){ + Facet f = std::pair(it,i); + Vertex_triple vt_aux = make_vertex_triple(f); + Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); + make_canonical(vt); + inner_map[vt]= f; + } + } + } else { + for(Finite_cells_iterator it = remover.tmp.finite_cells_begin(), + end = remover.tmp.finite_cells_end(); it != end; ++it){ + for(i=0; i < 4; i++){ + Facet f = std::pair(it,i); + Vertex_triple vt_aux = make_vertex_triple(f); + Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); + make_canonical(vt); + inner_map[vt]= f; + } + } + } + // Grow inside the hole, by extending the surface + while(! outer_map.empty()){ + typename Vertex_triple_Facet_map::iterator oit = outer_map.begin(); + while(is_infinite(oit->first.first) || + is_infinite(oit->first.second) || + is_infinite(oit->first.third)){ + ++oit; + // otherwise the lookup in the inner_map fails + // because the infinite vertices are different + } + typename Vertex_triple_Facet_map::value_type o_vt_f_pair = *oit; + Cell_handle o_ch = o_vt_f_pair.second.first; + unsigned int o_i = o_vt_f_pair.second.second; + + typename Vertex_triple_Facet_map::iterator iit = + inner_map.find(o_vt_f_pair.first); + CGAL_triangulation_assertion(iit != inner_map.end()); + typename Vertex_triple_Facet_map::value_type i_vt_f_pair = *iit; + Cell_handle i_ch = i_vt_f_pair.second.first; + unsigned int i_i = i_vt_f_pair.second.second; + + // create a new cell and glue it to the outer surface + Cell_handle new_ch = tds().create_cell(); + new_ch->set_vertices(vmap[i_ch->vertex(0)], vmap[i_ch->vertex(1)], + vmap[i_ch->vertex(2)], vmap[i_ch->vertex(3)]); + + o_ch->set_neighbor(o_i,new_ch); + new_ch->set_neighbor(i_i, o_ch); + + // for the other faces check, if they can also be glued + for(i = 0; i < 4; i++){ + if(i != i_i){ + Facet f = std::pair(new_ch,i); + Vertex_triple vt = make_vertex_triple(f); + make_canonical(vt); + std::swap(vt.second,vt.third); + typename Vertex_triple_Facet_map::iterator oit2 = outer_map.find(vt); + if(oit2 == outer_map.end()){ + std::swap(vt.second,vt.third); + outer_map[vt]= f; + } else { + // glue the faces + typename Vertex_triple_Facet_map::value_type o_vt_f_pair2 = *oit2; + Cell_handle o_ch2 = o_vt_f_pair2.second.first; + int o_i2 = o_vt_f_pair2.second.second; + o_ch2->set_neighbor(o_i2,new_ch); + new_ch->set_neighbor(i, o_ch2); + outer_map.erase(oit2); + } + } + } + outer_map.erase(oit); + } + tds().delete_vertex(v); + tds().delete_cells(inc_cells.begin(), inc_cells.end()); + + return remover; +} + +template template < class VertexRemover > void -Triangulation_3:: +Triangulation_3:: remove(Vertex_handle v, VertexRemover &remover) { CGAL_triangulation_precondition( v != Vertex_handle()); CGAL_triangulation_precondition( !is_infinite(v)); @@ -3981,25 +4998,85 @@ remove(Vertex_handle v, VertexRemover &remover) { } } +template +template < class VertexRemover > +bool +Triangulation_3:: +remove(Vertex_handle v, VertexRemover &remover, bool *could_lock_zone) +{ + // N.B.: dimension doesn't need to be atomic since the parallel removal + // will never decrease the dimension (the last few removes are done + // sequentially) + CGAL_triangulation_precondition( v != Vertex_handle()); + CGAL_triangulation_precondition( !is_infinite(v)); + CGAL_triangulation_precondition( dimension() == 3); + CGAL_triangulation_expensive_precondition( tds().is_vertex(v) ); + +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + static Profile_branch_counter_3 bcounter( + "early withdrawals / late withdrawals / successes [Delaunay_tri_3::remove]"); +#endif + + bool removed = true; + + // Locking vertex v is a good start + if (!this->try_lock_vertex(v)) + { + *could_lock_zone = false; +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + bcounter.increment_branch_2(); // THIS is an early withdrawal! +#endif + } + else + { + std::vector incident_cells; + incident_cells.reserve(64); + std::vector adj_vertices; + adj_vertices.reserve(64); + bool dim_down = test_dim_down_using_incident_cells_3( + v, incident_cells, adj_vertices, could_lock_zone); + + if (*could_lock_zone) + { + if (dim_down) + removed = false; + else + remove_3D (v, remover, incident_cells, adj_vertices); + } + } + +#ifdef CGAL_CONCURRENT_TRIANGULATION_3_PROFILING + if (could_lock_zone) + { + if (*could_lock_zone) + ++bcounter; + else + bcounter.increment_branch_1(); // THIS is a late withdrawal! + } +#endif + + return removed; +} + // The remove here uses the remover, but // no function envolving hidden points // will be used in this internal version -template < class Gt, class Tds > +template template < class VertexRemover, class OutputItCells > VertexRemover& -Triangulation_3:: +Triangulation_3:: remove_dim_down(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { remove_dim_down(v, remover); - for(All_cells_iterator afi = tds().raw_cells_begin(); - afi != tds().raw_cells_end(); + for(All_cells_iterator afi = tds().raw_cells_begin(); + afi != tds().raw_cells_end(); afi++) *fit++ = afi; return remover; } -template < class Gt, class Tds > +template template < class VertexRemover, class OutputItCells > VertexRemover& -Triangulation_3:: +Triangulation_3:: remove_1D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { Point p = v->point(); remove_1D(v, remover); @@ -4007,10 +5084,10 @@ remove_1D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { return remover; } -template < class Gt, class Tds > +template template < class VertexRemover, class OutputItCells > VertexRemover& -Triangulation_3:: +Triangulation_3:: remove_2D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { CGAL_triangulation_precondition(dimension() == 2); std::list hole; @@ -4020,10 +5097,10 @@ remove_2D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { return remover; } -template < class Gt, class Tds > +template template < class VertexRemover, class OutputItCells > VertexRemover& -Triangulation_3:: +Triangulation_3:: remove_3D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { CGAL_triangulation_precondition(dimension() == 3); @@ -4032,7 +5109,6 @@ remove_3D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { // Construct the set of vertex triples on the boundary // with the facet just behind - typedef std::map Vertex_triple_Facet_map; Vertex_triple_Facet_map outer_map; Vertex_triple_Facet_map inner_map; @@ -4058,7 +5134,7 @@ remove_3D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { // and make a map from the vertices in remover.tmp towards the vertices // in *this - Unique_hash_map vmap; + Vertex_handle_unique_hash_map vmap; Cell_handle ch = Cell_handle(); for(i=0; i < vertices.size(); i++){ if(! is_infinite(vertices[i])){ @@ -4088,23 +5164,23 @@ remove_3D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { end = remover.tmp.all_cells_end(); it != end; ++it) { for(i=0; i < 4; i++){ - Facet f = std::pair(it,i); - Vertex_triple vt_aux = make_vertex_triple(f); - Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); - make_canonical(vt); - inner_map[vt]= f; + Facet f = std::pair(it,i); + Vertex_triple vt_aux = make_vertex_triple(f); + Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); + make_canonical(vt); + inner_map[vt]= f; } } } else { for(Finite_cells_iterator it = remover.tmp.finite_cells_begin(), - end = remover.tmp.finite_cells_end(); it != end; ++it) + end = remover.tmp.finite_cells_end(); it != end; ++it) { for(i=0; i < 4; i++){ - Facet f = std::pair(it,i); - Vertex_triple vt_aux = make_vertex_triple(f); - Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); - make_canonical(vt); - inner_map[vt]= f; + Facet f = std::pair(it,i); + Vertex_triple vt_aux = make_vertex_triple(f); + Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); + make_canonical(vt); + inner_map[vt]= f; } } } @@ -4112,8 +5188,8 @@ remove_3D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { while(! outer_map.empty()){ typename Vertex_triple_Facet_map::iterator oit = outer_map.begin(); while(is_infinite(oit->first.first) || - is_infinite(oit->first.second) || - is_infinite(oit->first.third)){ + is_infinite(oit->first.second) || + is_infinite(oit->first.third)){ ++oit; // otherwise the lookup in the inner_map fails // because the infinite vertices are different @@ -4131,10 +5207,10 @@ remove_3D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { // create a new cell and glue it to the outer surface Cell_handle new_ch = tds().create_cell(); - *fit++ = new_ch; + *fit++ = new_ch; new_ch->set_vertices(vmap[i_ch->vertex(0)], vmap[i_ch->vertex(1)], - vmap[i_ch->vertex(2)], vmap[i_ch->vertex(3)]); + vmap[i_ch->vertex(2)], vmap[i_ch->vertex(3)]); o_ch->set_neighbor(o_i,new_ch); new_ch->set_neighbor(i_i, o_ch); @@ -4142,23 +5218,23 @@ remove_3D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { // for the other faces check, if they can also be glued for(i = 0; i < 4; i++){ if(i != i_i){ - Facet f = std::pair(new_ch,i); - Vertex_triple vt = make_vertex_triple(f); - make_canonical(vt); - std::swap(vt.second,vt.third); - typename Vertex_triple_Facet_map::iterator oit2 = outer_map.find(vt); - if(oit2 == outer_map.end()){ - std::swap(vt.second,vt.third); - outer_map[vt]= f; - } else { - // glue the faces - typename Vertex_triple_Facet_map::value_type o_vt_f_pair2 = *oit2; - Cell_handle o_ch2 = o_vt_f_pair2.second.first; - int o_i2 = o_vt_f_pair2.second.second; - o_ch2->set_neighbor(o_i2,new_ch); - new_ch->set_neighbor(i, o_ch2); - outer_map.erase(oit2); - } + Facet f = std::pair(new_ch,i); + Vertex_triple vt = make_vertex_triple(f); + make_canonical(vt); + std::swap(vt.second,vt.third); + typename Vertex_triple_Facet_map::iterator oit2 = outer_map.find(vt); + if(oit2 == outer_map.end()){ + std::swap(vt.second,vt.third); + outer_map[vt]= f; + } else { + // glue the faces + typename Vertex_triple_Facet_map::value_type o_vt_f_pair2 = *oit2; + Cell_handle o_ch2 = o_vt_f_pair2.second.first; + int o_i2 = o_vt_f_pair2.second.second; + o_ch2->set_neighbor(o_i2,new_ch); + new_ch->set_neighbor(i, o_ch2); + outer_map.erase(oit2); + } } } outer_map.erase(oit); @@ -4170,10 +5246,10 @@ remove_3D(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { } -template < class Gt, class Tds > +template template < class VertexRemover, class OutputItCells > void -Triangulation_3:: +Triangulation_3:: remove_and_give_new_cells(Vertex_handle v, VertexRemover &remover, OutputItCells fit) { CGAL_triangulation_precondition( v != Vertex_handle()); @@ -4194,21 +5270,21 @@ remove_and_give_new_cells(Vertex_handle v, VertexRemover &remover, } } -// The VertexInserter is needed so as to +// The VertexInserter is needed so as to // allow us the usage of the insertion method // from the particular triangulation -template +template template < class VertexRemover, class VertexInserter > -typename Triangulation_3::Vertex_handle -Triangulation_3:: -move_if_no_collision(Vertex_handle v, const Point &p, +typename Triangulation_3::Vertex_handle +Triangulation_3:: +move_if_no_collision(Vertex_handle v, const Point &p, VertexRemover &remover, VertexInserter &inserter) { CGAL_assertion(remover.hidden_points_begin() == remover.hidden_points_end() ); CGAL_triangulation_precondition(!is_infinite(v)); if(v->point() == p) return v; const int dim = dimension(); - + // If displacements are known to be small // we might want to optimize by checking // whether there is a topological change @@ -4246,7 +5322,7 @@ move_if_no_collision(Vertex_handle v, const Point &p, } if((lt != OUTSIDE_AFFINE_HULL) && (dim == 1)) { - + if(loc->has_vertex(v)) { v->set_point(p); } else { @@ -4282,7 +5358,7 @@ move_if_no_collision(Vertex_handle v, const Point &p, int iinf; Cell_handle finf = infinite_vertex()->cell(), fdone; fdone = finf; - do { + do { iinf = finf->index(infinite_vertex()); if(!finf->has_vertex(v)) break; finf = finf->neighbor((iinf+1)%3); @@ -4298,23 +5374,23 @@ move_if_no_collision(Vertex_handle v, const Point &p, } } - if(((dim == 2) && (lt != OUTSIDE_AFFINE_HULL)) || + if(((dim == 2) && (lt != OUTSIDE_AFFINE_HULL)) || ((lt == OUTSIDE_AFFINE_HULL) && (dim == 1))) { - + // This is insert must be from Delaunay (or the particular trian.) // not Triangulation_3 ! Vertex_handle inserted = inserter.insert(p, lt, loc, li, lj); - + std::list hole; - make_hole_2D(v, hole, remover); + make_hole_2D(v, hole, remover); fill_hole_2D(hole, remover); - + // fixing pointer Cell_handle fc = inserted->cell(), done(fc); std::vector faces_pt; faces_pt.reserve(16); - do { + do { faces_pt.push_back(fc); fc = fc->neighbor((fc->index(inserted) + 1)%3); } while(fc != done); @@ -4345,9 +5421,9 @@ move_if_no_collision(Vertex_handle v, const Point &p, } int iinf = finf->index(infinite_vertex()); if(remover.tmp.coplanar(finf->vertex((iinf+1)&3)->point(), - finf->vertex((iinf+2)&3)->point(), - finf->vertex((iinf+3)&3)->point(), - p)) + finf->vertex((iinf+2)&3)->point(), + finf->vertex((iinf+3)&3)->point(), + p)) { v->set_point(p); _tds.decrease_dimension(loc, loc->index(v)); @@ -4362,7 +5438,7 @@ move_if_no_collision(Vertex_handle v, const Point &p, } // This is insert must be from Delaunay (or the particular trian.) - // not Triangulation_3 ! + // not Triangulation_3 ! Vertex_handle inserted = inserter.insert(p, lt, loc, li, lj); std::vector hole; @@ -4370,7 +5446,6 @@ move_if_no_collision(Vertex_handle v, const Point &p, // Construct the set of vertex triples on the boundary // with the facet just behind - typedef std::map Vertex_triple_Facet_map; Vertex_triple_Facet_map outer_map; Vertex_triple_Facet_map inner_map; @@ -4396,7 +5471,7 @@ move_if_no_collision(Vertex_handle v, const Point &p, // and make a map from the vertices in remover.tmp towards the vertices // in *this - Unique_hash_map vmap; + Vertex_handle_unique_hash_map vmap; Cell_handle ch = Cell_handle(); for(i=0; i < vertices.size(); i++){ if(! is_infinite(vertices[i])){ @@ -4425,22 +5500,22 @@ move_if_no_collision(Vertex_handle v, const Point &p, for(All_cells_iterator it = remover.tmp.all_cells_begin(), end = remover.tmp.all_cells_end(); it != end; ++it){ for(i=0; i < 4; i++){ - Facet f = std::pair(it,i); - Vertex_triple vt_aux = make_vertex_triple(f); - Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); - make_canonical(vt); - inner_map[vt]= f; + Facet f = std::pair(it,i); + Vertex_triple vt_aux = make_vertex_triple(f); + Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); + make_canonical(vt); + inner_map[vt]= f; } } } else { for(Finite_cells_iterator it = remover.tmp.finite_cells_begin(), end = remover.tmp.finite_cells_end(); it != end; ++it){ for(i=0; i < 4; i++){ - Facet f = std::pair(it,i); - Vertex_triple vt_aux = make_vertex_triple(f); - Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); - make_canonical(vt); - inner_map[vt]= f; + Facet f = std::pair(it,i); + Vertex_triple vt_aux = make_vertex_triple(f); + Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); + make_canonical(vt); + inner_map[vt]= f; } } } @@ -4448,8 +5523,8 @@ move_if_no_collision(Vertex_handle v, const Point &p, while(! outer_map.empty()){ typename Vertex_triple_Facet_map::iterator oit = outer_map.begin(); while(is_infinite(oit->first.first) || - is_infinite(oit->first.second) || - is_infinite(oit->first.third)){ + is_infinite(oit->first.second) || + is_infinite(oit->first.third)){ ++oit; // otherwise the lookup in the inner_map fails // because the infinite vertices are different @@ -4469,7 +5544,7 @@ move_if_no_collision(Vertex_handle v, const Point &p, Cell_handle new_ch = tds().create_cell(); new_ch->set_vertices(vmap[i_ch->vertex(0)], vmap[i_ch->vertex(1)], - vmap[i_ch->vertex(2)], vmap[i_ch->vertex(3)]); + vmap[i_ch->vertex(2)], vmap[i_ch->vertex(3)]); o_ch->set_neighbor(o_i,new_ch); new_ch->set_neighbor(i_i, o_ch); @@ -4477,23 +5552,23 @@ move_if_no_collision(Vertex_handle v, const Point &p, // for the other faces check, if they can also be glued for(i = 0; i < 4; i++){ if(i != i_i){ - Facet f = std::pair(new_ch,i); - Vertex_triple vt = make_vertex_triple(f); - make_canonical(vt); - std::swap(vt.second,vt.third); - typename Vertex_triple_Facet_map::iterator oit2 = outer_map.find(vt); - if(oit2 == outer_map.end()){ - std::swap(vt.second,vt.third); - outer_map[vt]= f; - } else { - // glue the faces - typename Vertex_triple_Facet_map::value_type o_vt_f_pair2 = *oit2; - Cell_handle o_ch2 = o_vt_f_pair2.second.first; - int o_i2 = o_vt_f_pair2.second.second; - o_ch2->set_neighbor(o_i2,new_ch); - new_ch->set_neighbor(i, o_ch2); - outer_map.erase(oit2); - } + Facet f = std::pair(new_ch,i); + Vertex_triple vt = make_vertex_triple(f); + make_canonical(vt); + std::swap(vt.second,vt.third); + typename Vertex_triple_Facet_map::iterator oit2 = outer_map.find(vt); + if(oit2 == outer_map.end()){ + std::swap(vt.second,vt.third); + outer_map[vt]= f; + } else { + // glue the faces + typename Vertex_triple_Facet_map::value_type o_vt_f_pair2 = *oit2; + Cell_handle o_ch2 = o_vt_f_pair2.second.first; + int o_i2 = o_vt_f_pair2.second.second; + o_ch2->set_neighbor(o_i2,new_ch); + new_ch->set_neighbor(i, o_ch2); + outer_map.erase(oit2); + } } } outer_map.erase(oit); @@ -4513,14 +5588,14 @@ move_if_no_collision(Vertex_handle v, const Point &p, tds().delete_vertex(inserted); tds().delete_cells(hole.begin(), hole.end()); return v; -} // end of Vertex_handle - // Triangulation_3:: +} // end of Vertex_handle + // Triangulation_3:: // move_if_no_collision(Vertex_handle,Point, VertexRemover, VertexInserter) -template +template template < class VertexRemover, class VertexInserter > -typename Triangulation_3::Vertex_handle -Triangulation_3:: +typename Triangulation_3::Vertex_handle +Triangulation_3:: move(Vertex_handle v, const Point &p, VertexRemover &remover, VertexInserter &inserter) { CGAL_assertion(remover.hidden_points_begin() == @@ -4535,21 +5610,21 @@ move(Vertex_handle v, const Point &p, return v; } -// The VertexInserter is needed so as to +// The VertexInserter is needed so as to // allow us the usage of the insertion method // from the particular triangulation -template +template template < class VertexRemover, class VertexInserter, class OutputItCells > -typename Triangulation_3::Vertex_handle -Triangulation_3:: -move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, +typename Triangulation_3::Vertex_handle +Triangulation_3:: +move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, VertexRemover &remover, VertexInserter &inserter, OutputItCells fit) { CGAL_assertion(remover.hidden_points_begin() == remover.hidden_points_end() ); CGAL_triangulation_precondition(!is_infinite(v)); if(v->point() == p) return v; const int dim = dimension(); - + // If displacements are known to be small // we might want to optimize by checking // whether there is a topological change @@ -4562,7 +5637,7 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, // However, a non-fully optimized but good version of // is_delaunay_after_displacement is provided as an internal method of // Delaunay_triangulation_3 (see the class for more details). - + Locate_type lt; int li, lj; Cell_handle loc = locate(p, lt, li, lj, v->cell()); @@ -4578,16 +5653,16 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, if((lt == OUTSIDE_AFFINE_HULL) && (dim == 1) && (n_vertices == 3)) { v->set_point(p); - for(All_cells_iterator afi = tds().raw_cells_begin(); - afi != tds().raw_cells_end(); + for(All_cells_iterator afi = tds().raw_cells_begin(); + afi != tds().raw_cells_end(); afi++) *fit++ = afi; return v; } if((lt == OUTSIDE_AFFINE_HULL) && (dim == 2) && (n_vertices == 4)) { v->set_point(p); - for(All_cells_iterator afi = tds().raw_cells_begin(); - afi != tds().raw_cells_end(); + for(All_cells_iterator afi = tds().raw_cells_begin(); + afi != tds().raw_cells_end(); afi++) *fit++ = afi; return v; } @@ -4620,9 +5695,9 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, tds().delete_vertex(inserted); } *fit++ = v->cell(); - if(v->cell()->neighbor(0)->has_vertex(v)) + if(v->cell()->neighbor(0)->has_vertex(v)) *fit++ = v->cell()->neighbor(0); - if(v->cell()->neighbor(1)->has_vertex(v)) + if(v->cell()->neighbor(1)->has_vertex(v)) *fit++ = v->cell()->neighbor(1); return v; } @@ -4634,7 +5709,7 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, int iinf; Cell_handle finf = infinite_vertex()->cell(), fdone; fdone = finf; - do { + do { iinf = finf->index(infinite_vertex()); if(!finf->has_vertex(v)) break; finf = finf->neighbor((iinf+1)%3); @@ -4646,37 +5721,37 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, { v->set_point(p); _tds.decrease_dimension(loc, loc->index(v)); - for(All_cells_iterator afi = tds().raw_cells_begin(); - afi != tds().raw_cells_end(); + for(All_cells_iterator afi = tds().raw_cells_begin(); + afi != tds().raw_cells_end(); afi++) *fit++ = afi; return v; } } - if(((dim == 2) && (lt != OUTSIDE_AFFINE_HULL)) || + if(((dim == 2) && (lt != OUTSIDE_AFFINE_HULL)) || ((lt == OUTSIDE_AFFINE_HULL) && (dim == 1))) { - + std::set cells_set; // This is insert must be from Delaunay (or the particular trian.) // not Triangulation_3 ! Vertex_handle inserted = inserter.insert(p, lt, loc, li, lj); Cell_handle c = inserted->cell(), end = c; - do { - cells_set.insert(c); - int i = c->index(inserted); - c = c->neighbor((i+1)%3); + do { + cells_set.insert(c); + int i = c->index(inserted); + c = c->neighbor((i+1)%3); } while(c != end); - + std::list hole; make_hole_2D(v, hole, remover, cells_set); fill_hole_2D(hole, remover, fit); - + // fixing pointer Cell_handle fc = inserted->cell(), done(fc); std::vector faces_pt; faces_pt.reserve(16); - do { + do { faces_pt.push_back(fc); fc = fc->neighbor((fc->index(inserted) + 1)%3); } while(fc != done); @@ -4691,9 +5766,9 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, v->set_cell(inserted->cell()); tds().delete_vertex(inserted); - + for(typename std::set::const_iterator ib = cells_set.begin(), - iend = cells_set.end(); ib != iend; ib++) *fit++ = *ib; + iend = cells_set.end(); ib != iend; ib++) *fit++ = *ib; return v; } @@ -4710,9 +5785,9 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, } int iinf = finf->index(infinite_vertex()); if(remover.tmp.coplanar(finf->vertex((iinf+1)&3)->point(), - finf->vertex((iinf+2)&3)->point(), - finf->vertex((iinf+3)&3)->point(), - p)) + finf->vertex((iinf+2)&3)->point(), + finf->vertex((iinf+3)&3)->point(), + p)) { v->set_point(p); _tds.decrease_dimension(loc, loc->index(v)); @@ -4722,8 +5797,8 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, f.first->vertex(2)->point()) == NEGATIVE) tds().reorient(); restore_edges_after_decrease_dimension(v, remover,inserter); - for(All_cells_iterator afi = tds().raw_cells_begin(); - afi != tds().raw_cells_end(); + for(All_cells_iterator afi = tds().raw_cells_begin(); + afi != tds().raw_cells_end(); afi++) *fit++ = afi; return v; } @@ -4732,7 +5807,7 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, std::set cells_set; // This is insert must be from Delaunay (or the particular trian.) - // not Triangulation_3 ! + // not Triangulation_3 ! Vertex_handle inserted = inserter.insert(p, lt, loc, li, lj); std::vector cells_tmp; @@ -4748,14 +5823,13 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, // Construct the set of vertex triples on the boundary // with the facet just behind - typedef std::map Vertex_triple_Facet_map; Vertex_triple_Facet_map outer_map; Vertex_triple_Facet_map inner_map; make_hole_3D(v, outer_map, hole); - + for(typename std::vector::const_iterator ib = hole.begin(), - iend = hole.end(); ib != iend; ib++) cells_set.erase(*ib); + iend = hole.end(); ib != iend; ib++) cells_set.erase(*ib); CGAL_assertion(remover.hidden_points_begin() == remover.hidden_points_end() ); @@ -4777,7 +5851,7 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, // and make a map from the vertices in remover.tmp towards the vertices // in *this - Unique_hash_map vmap; + Vertex_handle_unique_hash_map vmap; Cell_handle ch = Cell_handle(); for(i=0; i < vertices.size(); i++){ if(! is_infinite(vertices[i])){ @@ -4806,22 +5880,22 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, for(All_cells_iterator it = remover.tmp.all_cells_begin(), end = remover.tmp.all_cells_end(); it != end; ++it){ for(i=0; i < 4; i++){ - Facet f = std::pair(it,i); - Vertex_triple vt_aux = make_vertex_triple(f); - Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); - make_canonical(vt); - inner_map[vt]= f; + Facet f = std::pair(it,i); + Vertex_triple vt_aux = make_vertex_triple(f); + Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); + make_canonical(vt); + inner_map[vt]= f; } } } else { for(Finite_cells_iterator it = remover.tmp.finite_cells_begin(), end = remover.tmp.finite_cells_end(); it != end; ++it){ for(i=0; i < 4; i++){ - Facet f = std::pair(it,i); - Vertex_triple vt_aux = make_vertex_triple(f); - Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); - make_canonical(vt); - inner_map[vt]= f; + Facet f = std::pair(it,i); + Vertex_triple vt_aux = make_vertex_triple(f); + Vertex_triple vt(vmap[vt_aux.first],vmap[vt_aux.third],vmap[vt_aux.second]); + make_canonical(vt); + inner_map[vt]= f; } } } @@ -4829,8 +5903,8 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, while(! outer_map.empty()){ typename Vertex_triple_Facet_map::iterator oit = outer_map.begin(); while(is_infinite(oit->first.first) || - is_infinite(oit->first.second) || - is_infinite(oit->first.third)){ + is_infinite(oit->first.second) || + is_infinite(oit->first.third)){ ++oit; // otherwise the lookup in the inner_map fails // because the infinite vertices are different @@ -4849,9 +5923,9 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, // create a new cell and glue it to the outer surface Cell_handle new_ch = tds().create_cell(); *fit++ = new_ch; - + new_ch->set_vertices(vmap[i_ch->vertex(0)], vmap[i_ch->vertex(1)], - vmap[i_ch->vertex(2)], vmap[i_ch->vertex(3)]); + vmap[i_ch->vertex(2)], vmap[i_ch->vertex(3)]); o_ch->set_neighbor(o_i,new_ch); new_ch->set_neighbor(i_i, o_ch); @@ -4859,23 +5933,23 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, // for the other faces check, if they can also be glued for(i = 0; i < 4; i++){ if(i != i_i){ - Facet f = std::pair(new_ch,i); - Vertex_triple vt = make_vertex_triple(f); - make_canonical(vt); - std::swap(vt.second,vt.third); - typename Vertex_triple_Facet_map::iterator oit2 = outer_map.find(vt); - if(oit2 == outer_map.end()){ - std::swap(vt.second,vt.third); - outer_map[vt]= f; - } else { - // glue the faces - typename Vertex_triple_Facet_map::value_type o_vt_f_pair2 = *oit2; - Cell_handle o_ch2 = o_vt_f_pair2.second.first; - int o_i2 = o_vt_f_pair2.second.second; - o_ch2->set_neighbor(o_i2,new_ch); - new_ch->set_neighbor(i, o_ch2); - outer_map.erase(oit2); - } + Facet f = std::pair(new_ch,i); + Vertex_triple vt = make_vertex_triple(f); + make_canonical(vt); + std::swap(vt.second,vt.third); + typename Vertex_triple_Facet_map::iterator oit2 = outer_map.find(vt); + if(oit2 == outer_map.end()){ + std::swap(vt.second,vt.third); + outer_map[vt]= f; + } else { + // glue the faces + typename Vertex_triple_Facet_map::value_type o_vt_f_pair2 = *oit2; + Cell_handle o_ch2 = o_vt_f_pair2.second.first; + int o_i2 = o_vt_f_pair2.second.second; + o_ch2->set_neighbor(o_i2,new_ch); + new_ch->set_neighbor(i, o_ch2); + outer_map.erase(oit2); + } } } outer_map.erase(oit); @@ -4894,37 +5968,37 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point &p, v->set_cell(inserted->cell()); tds().delete_vertex(inserted); tds().delete_cells(hole.begin(), hole.end()); - + for(typename std::set::const_iterator ib = cells_set.begin(), iend = cells_set.end(); ib != iend; ib++) *fit++ = *ib; return v; } -template < class Gt, class Tds > +template void -Triangulation_3:: +Triangulation_3:: _make_big_hole_3D( Vertex_handle v, std::map& outer_map, std::vector & hole, std::vector & vertices, std::map &vstates) { - + Cell_handle start = v->cell(); start->tds_data().mark_processed(); hole.push_back(start); std::size_t i=0, n=1; while(i < n) { - + Cell_handle c = hole[i++]; - + for(int k=0; k<4; k++) { Vertex_handle v0 = c->vertex(k); - + const REMOVE_VERTEX_STATE vst = vstates[v0]; - + if(vst == CLEAR) { vstates[v0] = EXTREMITY; @@ -4932,46 +6006,46 @@ _make_big_hole_3D( Vertex_handle v, } else if(vst == TO_REMOVE) { // we mark the vertices, so all the vertices // from the same cluster will be skipped - // in the remove_cluster_3D function + // in the remove_cluster_3D function vstates[v0] = PROCESSED; } - + int i1 = vertex_triple_index(k, 0); int i2 = vertex_triple_index(k, 1); int i3 = vertex_triple_index(k, 2); - + Vertex_handle v1 = c->vertex(i1); Vertex_handle v2 = c->vertex(i2); Vertex_handle v3 = c->vertex(i3); - + Cell_handle opp_cit = c->neighbor(k); int opp_i = tds().mirror_index(c,k); Vertex_handle vm = opp_cit->vertex(opp_i); - + bool pb1 = false, pb2 = false, pb3 = false, pbm = false; - + const REMOVE_VERTEX_STATE vst1 = vstates[v1]; pb1 = vst1 == TO_REMOVE || vst1 == PROCESSED; - + if(!pb1) { const REMOVE_VERTEX_STATE vst2 = vstates[v2]; pb2 = vst2 == TO_REMOVE || vst2 == PROCESSED; - + if(!pb2) { const REMOVE_VERTEX_STATE vst3 = vstates[v3]; pb3 = vst3 == TO_REMOVE || vst3 == PROCESSED; - + if(!pb3) { const REMOVE_VERTEX_STATE vstm = vstates[vm]; pbm = vstm == TO_REMOVE || vstm == PROCESSED; } - + } - + } bool bad_opposite_cell = pb1 || pb2 || pb3 || pbm; - + // update the hole if needed // when the vertex is not to be removed if(bad_opposite_cell) @@ -4993,32 +6067,32 @@ _make_big_hole_3D( Vertex_handle v, v2->set_cell(opp_cit); v3->set_cell(opp_cit); vm->set_cell(opp_cit); - + } } - + std::size_t vsize = vertices.size(); for(std::size_t i=0; i +template template < class InputIterator, class VertexRemover > bool -Triangulation_3:: +Triangulation_3:: _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover &remover, std::map &vstates) { InputIterator init = first; while(first != beyond) { Vertex_handle v = *first++; - + if(vstates[v] == PROCESSED) continue; - + // _make_big_hole_3D and we fill the hole for each cluster vstates[v] = PROCESSED; - + // here, we make the hole for the cluster with v inside typedef std::map Vertex_triple_Facet_map; std::vector hole; @@ -5027,7 +6101,7 @@ _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover &rem vertices.reserve(32); Vertex_triple_Facet_map outer_map; _make_big_hole_3D(v, outer_map, hole, vertices, vstates); - + // the connectivity is totally lost, we need to rebuild if(!outer_map.size()) { @@ -5035,14 +6109,14 @@ _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover &rem for(std::size_t i=0; itds_data().clear(); return false; } - + std::size_t vsi = vertices.size(); - + bool inf = false; std::size_t i; - Unique_hash_map vmap; + Vertex_handle_unique_hash_map vmap; Cell_handle ch = Cell_handle(); - + if(vsi > 100) { // spatial sort if too many points @@ -5057,14 +6131,14 @@ _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover &rem } else inf = true; } spatial_sort(vps.begin(), vps.end()); - + std::size_t svps = vps.size(); - + for(i=0; i < svps; i++){ Vertex_handle vv = mp_vps[vps[i]]; Vertex_handle vh = remover.tmp.insert(vv->point(), ch); ch = vh->cell(); - vmap[vh] = vv; + vmap[vh] = vv; } if(remover.tmp.dimension()==2){ @@ -5074,14 +6148,14 @@ _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover &rem vmap[remover.tmp.infinite_vertex()] = this->infinite_vertex(); } } else { - + for(i=0; i < vsi; i++){ if(!this->is_infinite(vertices[i])){ Vertex_handle vh = remover.tmp.insert(vertices[i]->point(), ch); ch = vh->cell(); - vmap[vh] = vertices[i]; + vmap[vh] = vertices[i]; } else { - inf = true; + inf = true; } } @@ -5092,9 +6166,9 @@ _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover &rem vmap[remover.tmp.infinite_vertex()] = this->infinite_vertex(); } } - + Vertex_triple_Facet_map inner_map; - + if(inf){ for(All_cells_iterator it = remover.tmp.all_cells_begin(), end = remover.tmp.all_cells_end(); it != end; ++it){ @@ -5122,7 +6196,7 @@ _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover &rem // Grow inside the hole, by extending the surface while(! outer_map.empty()){ typename Vertex_triple_Facet_map::iterator oit = outer_map.begin(); - + while(this->is_infinite(oit->first.first) || this->is_infinite(oit->first.second) || this->is_infinite(oit->first.third)){ @@ -5148,9 +6222,9 @@ _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover &rem o_ch->set_neighbor(o_i,new_ch); new_ch->set_neighbor(i_i, o_ch); - + for(int j=0;j<4;j++) new_ch->vertex(j)->set_cell(new_ch); - + // for the other faces check, if they can also be glued for(unsigned int index = 0; index < 4; index++){ if(index != i_i){ @@ -5176,40 +6250,40 @@ _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover &rem outer_map.erase(oit); } - + this->tds().delete_cells(hole.begin(), hole.end()); remover.tmp.clear(); } - + this->tds().delete_vertices(init, beyond); - + return true; } -template < class Gt, class Tds > +template template < class InputIterator > -bool -Triangulation_3:: +bool +Triangulation_3:: does_repeat_in_range(InputIterator first, InputIterator beyond) const { std::set s; while (first!=beyond) if (! s.insert(*first++).second ) return true; return false; } -template < class Gt, class Tds > +template template < class InputIterator > -bool -Triangulation_3:: +bool +Triangulation_3:: infinite_vertex_in_range(InputIterator first, InputIterator beyond) const { while(first != beyond) if(is_infinite(*first++)) return true; return false; } -template < class Gt, class Tds > +template template < class InputIterator, class VertexRemover > -typename Triangulation_3::size_type -Triangulation_3:: +typename Triangulation_3::size_type +Triangulation_3:: remove(InputIterator first, InputIterator beyond, VertexRemover &remover) { CGAL_triangulation_precondition(!does_repeat_in_range(first, beyond)); CGAL_triangulation_precondition(!infinite_vertex_in_range(first, beyond)); @@ -5239,21 +6313,21 @@ remove(InputIterator first, InputIterator beyond, VertexRemover &remover) { return n - number_of_vertices(); } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > bool -Triangulation_3:: +Triangulation_3:: is_valid(bool verbose, int level) const { if ( ! _tds.is_valid(verbose,level) ) { if (verbose) - std::cerr << "invalid data structure" << std::endl; + std::cerr << "invalid data structure" << std::endl; CGAL_triangulation_assertion(false); return false; } if ( infinite_vertex() == Vertex_handle() ) { if (verbose) - std::cerr << "no infinite vertex" << std::endl; + std::cerr << "no infinite vertex" << std::endl; CGAL_triangulation_assertion(false); return false; } @@ -5262,22 +6336,22 @@ is_valid(bool verbose, int level) const case 3: { for(Finite_cells_iterator it = finite_cells_begin(), end = finite_cells_end(); - it != end; ++it) - is_valid_finite(it, verbose, level); + it != end; ++it) + is_valid_finite(it, verbose, level); break; } case 2: { for(Finite_facets_iterator it = finite_facets_begin(), end = finite_facets_end(); - it != end; ++it) - is_valid_finite(it->first,verbose,level); + it != end; ++it) + is_valid_finite(it->first,verbose,level); break; } case 1: { for(Finite_edges_iterator it = finite_edges_begin(), end = finite_edges_end(); - it != end; ++it) - is_valid_finite(it->first,verbose,level); + it != end; ++it) + is_valid_finite(it->first,verbose,level); break; } } @@ -5286,16 +6360,16 @@ is_valid(bool verbose, int level) const return true; } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > bool -Triangulation_3:: +Triangulation_3:: is_valid(Cell_handle c, bool verbose, int level) const { if ( ! _tds.is_valid(c,verbose,level) ) { if (verbose) { std::cerr << "combinatorially invalid cell"; for (int i=0; i <= dimension(); i++ ) - std::cerr << c->vertex(i)->point() << ", "; + std::cerr << c->vertex(i)->point() << ", "; std::cerr << std::endl; } CGAL_triangulation_assertion(false); @@ -5309,42 +6383,42 @@ is_valid(Cell_handle c, bool verbose, int level) const } -template < class GT, class Tds > +template < class GT, class Tds, class Lds > bool -Triangulation_3:: +Triangulation_3:: is_valid_finite(Cell_handle c, bool verbose, int) const { switch ( dimension() ) { case 3: { if ( orientation(c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point(), - c->vertex(3)->point()) != POSITIVE ) { - if (verbose) - std::cerr << "badly oriented cell " - << c->vertex(0)->point() << ", " - << c->vertex(1)->point() << ", " - << c->vertex(2)->point() << ", " - << c->vertex(3)->point() << std::endl; - CGAL_triangulation_assertion(false); - return false; + c->vertex(1)->point(), + c->vertex(2)->point(), + c->vertex(3)->point()) != POSITIVE ) { + if (verbose) + std::cerr << "badly oriented cell " + << c->vertex(0)->point() << ", " + << c->vertex(1)->point() << ", " + << c->vertex(2)->point() << ", " + << c->vertex(3)->point() << std::endl; + CGAL_triangulation_assertion(false); + return false; } break; } case 2: { - if (coplanar_orientation(c->vertex(0)->point(), - c->vertex(1)->point(), - c->vertex(2)->point()) != POSITIVE) { - if (verbose) - std::cerr << "badly oriented face " - << c->vertex(0)->point() << ", " - << c->vertex(1)->point() << ", " - << c->vertex(2)->point() << std::endl; - CGAL_triangulation_assertion(false); - return false; - } + if (coplanar_orientation(c->vertex(0)->point(), + c->vertex(1)->point(), + c->vertex(2)->point()) != POSITIVE) { + if (verbose) + std::cerr << "badly oriented face " + << c->vertex(0)->point() << ", " + << c->vertex(1)->point() << ", " + << c->vertex(2)->point() << std::endl; + CGAL_triangulation_assertion(false); + return false; + } break; } case 1: @@ -5355,33 +6429,33 @@ is_valid_finite(Cell_handle c, bool verbose, int) const Vertex_handle v = c->neighbor(0)->vertex(c->neighbor(0)->index(c)); if ( ! is_infinite(v) ) { - if ( collinear_position(p0, p1, v->point()) != MIDDLE ) { - if (verbose) - std::cerr << "badly oriented edge " - << p0 << ", " << p1 << std::endl - << "with neighbor 0" - << c->neighbor(0)->vertex(1-c->neighbor(0)->index(c)) - ->point() - << ", " << v->point() << std::endl; - CGAL_triangulation_assertion(false); - return false; - } + if ( collinear_position(p0, p1, v->point()) != MIDDLE ) { + if (verbose) + std::cerr << "badly oriented edge " + << p0 << ", " << p1 << std::endl + << "with neighbor 0" + << c->neighbor(0)->vertex(1-c->neighbor(0)->index(c)) + ->point() + << ", " << v->point() << std::endl; + CGAL_triangulation_assertion(false); + return false; + } } v = c->neighbor(1)->vertex(c->neighbor(1)->index(c)); if ( ! is_infinite(v) ) { - if ( collinear_position(p1, p0, v->point()) != MIDDLE ) { - if (verbose) - std::cerr << "badly oriented edge " - << p0 << ", " << p1 << std::endl - << "with neighbor 1" - << c->neighbor(1)->vertex(1-c->neighbor(1)->index(c)) - ->point() - << ", " << v->point() << std::endl; - CGAL_triangulation_assertion(false); - return false; - } + if ( collinear_position(p1, p0, v->point()) != MIDDLE ) { + if (verbose) + std::cerr << "badly oriented edge " + << p0 << ", " << p1 << std::endl + << "with neighbor 1" + << c->neighbor(1)->vertex(1-c->neighbor(1)->index(c)) + ->point() + << ", " << v->point() << std::endl; + CGAL_triangulation_assertion(false); + return false; + } } break; } @@ -5393,16 +6467,16 @@ is_valid_finite(Cell_handle c, bool verbose, int) const namespace internal { // Internal function used by operator==. -template < class GT, class Tds1, class Tds2 > +template < class GT, class Tds1, class Tds2, class Lds > bool -test_next(const Triangulation_3 &t1, - const Triangulation_3 &t2, - typename Triangulation_3::Cell_handle c1, - typename Triangulation_3::Cell_handle c2, - std::map::Cell_handle, - typename Triangulation_3::Cell_handle> &Cmap, - std::map::Vertex_handle, - typename Triangulation_3::Vertex_handle> &Vmap) +test_next(const Triangulation_3 &t1, + const Triangulation_3 &t2, + typename Triangulation_3::Cell_handle c1, + typename Triangulation_3::Cell_handle c2, + std::map::Cell_handle, + typename Triangulation_3::Cell_handle> &Cmap, + std::map::Vertex_handle, + typename Triangulation_3::Vertex_handle> &Vmap) { // This function tests and registers the 4 neighbors of c1/c2, @@ -5419,8 +6493,8 @@ test_next(const Triangulation_3 &t1, CGAL_triangulation_precondition(t1.dimension() == 2 || Vmap.find(c1->vertex(3)) != Vmap.end()); - typedef Triangulation_3 Tr1; - typedef Triangulation_3 Tr2; + typedef Triangulation_3 Tr1; + typedef Triangulation_3 Tr2; typedef typename Tr1::Vertex_handle Vertex_handle1; typedef typename Tr1::Cell_handle Cell_handle1; typedef typename Tr2::Vertex_handle Vertex_handle2; @@ -5439,17 +6513,17 @@ test_next(const Triangulation_3 &t1, cell_stack.pop_back(); for (int i=0; i <= t1.dimension(); ++i) { - Cell_handle1 n1 = c1->neighbor(i); - Cit cit = Cmap.find(n1); - Vertex_handle1 v1 = c1->vertex(i); - Vertex_handle2 v2 = Vmap[v1]; - Cell_handle2 n2 = c2->neighbor(c2->index(v2)); - if (cit != Cmap.end()) { + Cell_handle1 n1 = c1->neighbor(i); + Cit cit = Cmap.find(n1); + Vertex_handle1 v1 = c1->vertex(i); + Vertex_handle2 v2 = Vmap[v1]; + Cell_handle2 n2 = c2->neighbor(c2->index(v2)); + if (cit != Cmap.end()) { // n1 was already registered. if (cit->second != n2) - return false; + return false; continue; - } + } // n1 has not yet been registered. // We check that the new vertices match geometrically. // And we register them. @@ -5484,10 +6558,10 @@ test_next(const Triangulation_3 &t1, } // namespace internal -template < class GT, class Tds1, class Tds2 > +template < class GT, class Tds1, class Tds2, class Lds > bool -operator==(const Triangulation_3 &t1, - const Triangulation_3 &t2) +operator==(const Triangulation_3 &t1, + const Triangulation_3 &t2) { typedef typename Triangulation_3::Vertex_handle Vertex_handle1; typedef typename Triangulation_3::Cell_handle Cell_handle1; @@ -5506,7 +6580,7 @@ operator==(const Triangulation_3 &t1, if (t1.dimension() != t2.dimension() || t1.number_of_vertices() != t2.number_of_vertices() || t1.number_of_cells() != t2.number_of_cells()) - return false; + return false; int dim = t1.dimension(); // Special case for dimension < 1. @@ -5549,60 +6623,60 @@ operator==(const Triangulation_3 &t1, std::vector ics; t2.incident_cells(iv2, std::back_inserter(ics)); for (typename std::vector::const_iterator cit = ics.begin(); - cit != ics.end(); ++cit) { - int inf = (*cit)->index(iv2); + cit != ics.end(); ++cit) { + int inf = (*cit)->index(iv2); - if (equal(p2, (*cit)->vertex((inf+1)%(dim+1))->point())) - Vmap.insert(std::make_pair(v2, (*cit)->vertex((inf+1)%(dim+1)))); - else if (equal(p2, (*cit)->vertex((inf+2)%(dim+1))->point())) - Vmap.insert(std::make_pair(v2, (*cit)->vertex((inf+2)%(dim+1)))); - else if (dim == 3 && + if (equal(p2, (*cit)->vertex((inf+1)%(dim+1))->point())) + Vmap.insert(std::make_pair(v2, (*cit)->vertex((inf+1)%(dim+1)))); + else if (equal(p2, (*cit)->vertex((inf+2)%(dim+1))->point())) + Vmap.insert(std::make_pair(v2, (*cit)->vertex((inf+2)%(dim+1)))); + else if (dim == 3 && equal(p2, (*cit)->vertex((inf+3)%(dim+1))->point())) - Vmap.insert(std::make_pair(v2, (*cit)->vertex((inf+3)%(dim+1)))); - else - continue; // None matched v2. + Vmap.insert(std::make_pair(v2, (*cit)->vertex((inf+3)%(dim+1)))); + else + continue; // None matched v2. - if (equal(p3, (*cit)->vertex((inf+1)%(dim+1))->point())) - Vmap.insert(std::make_pair(v3, (*cit)->vertex((inf+1)%(dim+1)))); - else if (equal(p3, (*cit)->vertex((inf+2)%(dim+1))->point())) - Vmap.insert(std::make_pair(v3, (*cit)->vertex((inf+2)%(dim+1)))); - else if (dim == 3 && + if (equal(p3, (*cit)->vertex((inf+1)%(dim+1))->point())) + Vmap.insert(std::make_pair(v3, (*cit)->vertex((inf+1)%(dim+1)))); + else if (equal(p3, (*cit)->vertex((inf+2)%(dim+1))->point())) + Vmap.insert(std::make_pair(v3, (*cit)->vertex((inf+2)%(dim+1)))); + else if (dim == 3 && equal(p3, (*cit)->vertex((inf+3)%(dim+1))->point())) - Vmap.insert(std::make_pair(v3, (*cit)->vertex((inf+3)%(dim+1)))); - else - continue; // None matched v3. + Vmap.insert(std::make_pair(v3, (*cit)->vertex((inf+3)%(dim+1)))); + else + continue; // None matched v3. if (dim == 3) { - if (equal(p4, (*cit)->vertex((inf+1)%(dim+1))->point())) - Vmap.insert(std::make_pair(v4, + if (equal(p4, (*cit)->vertex((inf+1)%(dim+1))->point())) + Vmap.insert(std::make_pair(v4, (*cit)->vertex((inf+1)%(dim+1)))); - else if (equal(p4, (*cit)->vertex((inf+2)%(dim+1))->point())) - Vmap.insert(std::make_pair(v4, + else if (equal(p4, (*cit)->vertex((inf+2)%(dim+1))->point())) + Vmap.insert(std::make_pair(v4, (*cit)->vertex((inf+2)%(dim+1)))); - else if (equal(p4, (*cit)->vertex((inf+3)%(dim+1))->point())) - Vmap.insert(std::make_pair(v4, + else if (equal(p4, (*cit)->vertex((inf+3)%(dim+1))->point())) + Vmap.insert(std::make_pair(v4, (*cit)->vertex((inf+3)%(dim+1)))); - else - continue; // None matched v4. + else + continue; // None matched v4. } - // Found it ! - Cmap.insert(std::make_pair(c, *cit)); - break; + // Found it ! + Cmap.insert(std::make_pair(c, *cit)); + break; } if (Cmap.size() == 0) - return false; + return false; // We now have one cell, we need to propagate recursively. return internal::test_next(t1, t2, - Cmap.begin()->first, Cmap.begin()->second, Cmap, Vmap); + Cmap.begin()->first, Cmap.begin()->second, Cmap, Vmap); } template < class GT, class Tds1, class Tds2 > inline bool operator!=(const Triangulation_3 &t1, - const Triangulation_3 &t2) + const Triangulation_3 &t2) { return ! (t1 == t2); } diff --git a/Triangulation_3/include/CGAL/Triangulation_cell_base_with_circumcenter_3.h b/Triangulation_3/include/CGAL/Triangulation_cell_base_with_circumcenter_3.h index 9cd328beda2..603f1d7f990 100644 --- a/Triangulation_3/include/CGAL/Triangulation_cell_base_with_circumcenter_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_cell_base_with_circumcenter_3.h @@ -82,12 +82,12 @@ public: } Triangulation_cell_base_with_circumcenter_3( - Vertex_handle v0, Vertex_handle v1, + Vertex_handle v0, Vertex_handle v1, Vertex_handle v2, Vertex_handle v3) : Cb(v0, v1, v2, v3), circumcenter_(NULL) {} Triangulation_cell_base_with_circumcenter_3( - Vertex_handle v0, Vertex_handle v1, + Vertex_handle v0, Vertex_handle v1, Vertex_handle v2, Vertex_handle v3, Cell_handle n0, Cell_handle n1, Cell_handle n2, Cell_handle n3) @@ -124,7 +124,7 @@ public: circumcenter(const Geom_traits& gt = Geom_traits()) const { if (circumcenter_ == NULL) { - circumcenter_ = new Point_3(this->Cb::circumcenter(gt)); + circumcenter_ = new Point_3(this->Cb::circumcenter(gt)); } else { CGAL_expensive_assertion( this->Cb::circumcenter(gt) == *circumcenter); diff --git a/Triangulation_3/include/CGAL/Triangulation_data_structure_3.h b/Triangulation_3/include/CGAL/Triangulation_data_structure_3.h index c0299a16fbc..06937a9f473 100644 --- a/Triangulation_3/include/CGAL/Triangulation_data_structure_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_data_structure_3.h @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -51,32 +52,46 @@ #include #ifdef CGAL_HAS_THREADS -# include +# ifdef CGAL_LINKED_WITH_TBB +# include +# else +# include +# endif #endif +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif + +#include +#include namespace CGAL { // TODO : noms : Vb != Vertex_base : clarifier. template < class Vb = Triangulation_ds_vertex_base_3<>, - class Cb = Triangulation_ds_cell_base_3<> > + class Cb = Triangulation_ds_cell_base_3<>, + class Concurrency_tag_ = Sequential_tag +> class Triangulation_data_structure_3 : public Triangulation_utils_3 { - typedef Triangulation_data_structure_3 Tds; + typedef Triangulation_data_structure_3 Tds; public: + typedef Concurrency_tag_ Concurrency_tag; + // Tools to change the Vertex and Cell types of the TDS. template < typename Vb2 > struct Rebind_vertex { - typedef Triangulation_data_structure_3 Other; + typedef Triangulation_data_structure_3 Other; }; template < typename Cb2 > struct Rebind_cell { - typedef Triangulation_data_structure_3 Other; + typedef Triangulation_data_structure_3 Other; }; // Put this TDS inside the Vertex and Cell types. @@ -108,10 +123,36 @@ private: friend class internal::Triangulation_ds_facet_circulator_3; public: + + // Cells + // N.B.: Concurrent_compact_container requires TBB +#ifdef CGAL_LINKED_WITH_TBB + typedef typename boost::mpl::if_c + < + boost::is_convertible::value, + Concurrent_compact_container >, + Compact_container + >::type Cell_range; - typedef Compact_container Cell_range; - typedef Compact_container Vertex_range; +# else + typedef Compact_container Cell_range; +#endif + // Vertices + // N.B.: Concurrent_compact_container requires TBB +#ifdef CGAL_LINKED_WITH_TBB + typedef typename boost::mpl::if_c + < + boost::is_convertible::value, + Concurrent_compact_container >, + Compact_container + >::type Vertex_range; + +# else + typedef Compact_container Vertex_range; +#endif + + typedef typename Cell_range::size_type size_type; typedef typename Cell_range::difference_type difference_type; @@ -237,15 +278,15 @@ public: } Cell_handle create_cell(Vertex_handle v0, Vertex_handle v1, - Vertex_handle v2, Vertex_handle v3) + Vertex_handle v2, Vertex_handle v3) { return cells().emplace(v0, v1, v2, v3); } Cell_handle create_cell(Vertex_handle v0, Vertex_handle v1, - Vertex_handle v2, Vertex_handle v3, - Cell_handle n0, Cell_handle n1, - Cell_handle n2, Cell_handle n3) + Vertex_handle v2, Vertex_handle v3, + Cell_handle n0, Cell_handle n1, + Cell_handle n2, Cell_handle n3) { return cells().emplace(v0, v1, v2, v3, n0, n1, n2, n3); } @@ -257,7 +298,7 @@ public: } Cell_handle create_face(Vertex_handle v0, Vertex_handle v1, - Vertex_handle v2) + Vertex_handle v2) { CGAL_triangulation_precondition(dimension()<3); return cells().emplace(v0, v1, v2, Vertex_handle()); @@ -265,13 +306,13 @@ public: // The following functions come from TDS_2. Cell_handle create_face(Cell_handle f0, int i0, - Cell_handle f1, int i1, - Cell_handle f2, int i2) + Cell_handle f1, int i1, + Cell_handle f2, int i2) { CGAL_triangulation_precondition(dimension() <= 2); Cell_handle newf = create_face(f0->vertex(cw(i0)), - f1->vertex(cw(i1)), - f2->vertex(cw(i2))); + f1->vertex(cw(i1)), + f2->vertex(cw(i2))); set_adjacency(newf, 2, f0, i0); set_adjacency(newf, 0, f1, i1); set_adjacency(newf, 1, f2, i2); @@ -279,12 +320,12 @@ public: } Cell_handle create_face(Cell_handle f0, int i0, - Cell_handle f1, int i1) + Cell_handle f1, int i1) { CGAL_triangulation_precondition(dimension() <= 2); Cell_handle newf = create_face(f0->vertex(cw(i0)), - f1->vertex(cw(i1)), - f1->vertex(ccw(i1))); + f1->vertex(cw(i1)), + f1->vertex(ccw(i1))); set_adjacency(newf, 2, f0, i0); set_adjacency(newf, 0, f1, i1); return newf; @@ -294,8 +335,8 @@ public: { CGAL_triangulation_precondition(dimension() <= 2); Cell_handle newf = create_face(f->vertex(cw(i)), - f->vertex(ccw(i)), - v); + f->vertex(ccw(i)), + v); set_adjacency(newf, 2, f, i); return newf; } @@ -325,14 +366,14 @@ public: void delete_vertices(InputIterator begin, InputIterator end) { for(; begin != end; ++begin) - delete_vertex(*begin); + delete_vertex(*begin); } template void delete_cells(InputIterator begin, InputIterator end) { for(; begin != end; ++begin) - delete_cell(*begin); + delete_cell(*begin); } // QUERIES @@ -341,27 +382,27 @@ public: bool is_vertex(Vertex_handle v) const; bool is_edge(Cell_handle c, int i, int j) const; bool is_edge(Vertex_handle u, Vertex_handle v, Cell_handle & c, - int & i, int & j) const; + int & i, int & j) const; bool is_edge(Vertex_handle u, Vertex_handle v) const; bool is_facet(Cell_handle c, int i) const; bool is_facet(Vertex_handle u, Vertex_handle v, - Vertex_handle w, - Cell_handle & c, int & i, int & j, int & k) const; + Vertex_handle w, + Cell_handle & c, int & i, int & j, int & k) const; bool is_cell(Cell_handle c) const; bool is_cell(Vertex_handle u, Vertex_handle v, - Vertex_handle w, Vertex_handle t, - Cell_handle & c, int & i, int & j, int & k, int & l) const; + Vertex_handle w, Vertex_handle t, + Cell_handle & c, int & i, int & j, int & k, int & l) const; bool is_cell(Vertex_handle u, Vertex_handle v, - Vertex_handle w, Vertex_handle t) const; + Vertex_handle w, Vertex_handle t) const; bool has_vertex(const Facet & f, Vertex_handle v, int & j) const; bool has_vertex(Cell_handle c, int i, - Vertex_handle v, int & j) const; + Vertex_handle v, int & j) const; bool has_vertex(const Facet & f, Vertex_handle v) const; bool has_vertex(Cell_handle c, int i, Vertex_handle v) const; bool are_equal(Cell_handle c, int i, - Cell_handle n, int j) const; + Cell_handle n, int j) const; bool are_equal(const Facet & f, const Facet & g) const; bool are_equal(const Facet & f, Cell_handle n, int j) const; @@ -387,36 +428,36 @@ private: // common to flip and flip_flippable void flip_really(Cell_handle c, int i, Cell_handle n, int in); void flip_really(Cell_handle c, int i, int j, - Cell_handle c1, Vertex_handle v1, - int i1, int j1, int next1, - Cell_handle c2, Vertex_handle v2, - int i2, int j2, int next2, - Vertex_handle v3); + Cell_handle c1, Vertex_handle v1, + int i1, int j1, int next1, + Cell_handle c2, Vertex_handle v2, + int i2, int j2, int next2, + Vertex_handle v3); #ifdef CGAL_TDS_USE_RECURSIVE_CREATE_STAR_3 Cell_handle create_star_3(Vertex_handle v, Cell_handle c, - int li, int prev_ind2 = -1); + int li, int prev_ind2 = -1); #else Cell_handle recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind2,int depth); Cell_handle non_recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind2); Cell_handle create_star_3(Vertex_handle v, Cell_handle c, - int li, int prev_ind2 = -1) + int li, int prev_ind2 = -1) { return recursive_create_star_3(v,c,li,prev_ind2,0); } #endif Cell_handle create_star_2(Vertex_handle v, - Cell_handle c, int li); + Cell_handle c, int li); public: // Internal function : assumes the conflict cells are marked. template Vertex_handle _insert_in_hole(CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i, - Vertex_handle newv) + Cell_handle begin, int i, + Vertex_handle newv) { CGAL_triangulation_precondition(begin != Cell_handle()); // if begin == NULL (default arg), we could compute one by walking in @@ -425,9 +466,9 @@ public: Cell_handle cnew; if (dimension() == 3) - cnew = create_star_3(newv, begin, i); + cnew = create_star_3(newv, begin, i); else - cnew = create_star_2(newv, begin, i); + cnew = create_star_2(newv, begin, i); newv->set_cell(cnew); delete_cells(cell_begin, cell_end); @@ -437,7 +478,7 @@ public: // Internal function : assumes the conflict cells are marked. template Vertex_handle _insert_in_hole(CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i) + Cell_handle begin, int i) { return _insert_in_hole(cell_begin, cell_end, begin, i, create_vertex()); } @@ -445,11 +486,11 @@ public: // Mark the cells in conflict, then calls the internal function. template Vertex_handle insert_in_hole(CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i, - Vertex_handle newv) + Cell_handle begin, int i, + Vertex_handle newv) { for (CellIt cit = cell_begin; cit != cell_end; ++cit) - (*cit)->tds_data().mark_in_conflict(); + (*cit)->tds_data().mark_in_conflict(); return _insert_in_hole(cell_begin, cell_end, begin, i, newv); } @@ -457,12 +498,18 @@ public: // Mark the cells in conflict, then calls the internal function. template Vertex_handle insert_in_hole(CellIt cell_begin, CellIt cell_end, - Cell_handle begin, int i) + Cell_handle begin, int i) { return insert_in_hole(cell_begin, cell_end, begin, i, create_vertex()); } //INSERTION + + // Create a finite cell with v1, v2, v3 and v4 + // Precondition: v1, v2, v3 and v4 MUST BE positively oriented + Vertex_handle insert_first_finite_cell( + Vertex_handle &v1, Vertex_handle &v2, Vertex_handle &v3, Vertex_handle &v4, + Vertex_handle v_infinite = Vertex_handle()); Vertex_handle insert_in_cell(Cell_handle c); @@ -498,8 +545,8 @@ public: { CGAL_triangulation_precondition(dimension() >= 1); for (Cell_iterator i = cells().begin(); - i != cells().end(); ++i) - change_orientation(i); + i != cells().end(); ++i) + change_orientation(i); } // ITERATOR METHODS @@ -507,7 +554,7 @@ public: Cell_iterator cells_begin() const { if ( dimension() < 3 ) - return cells_end(); + return cells_end(); return cells().begin(); } @@ -529,7 +576,7 @@ public: Facet_iterator facets_begin() const { if ( dimension() < 2 ) - return facets_end(); + return facets_end(); return Facet_iterator(this); } @@ -541,7 +588,7 @@ public: Edge_iterator edges_begin() const { if ( dimension() < 1 ) - return edges_end(); + return edges_end(); return Edge_iterator(this); } @@ -580,7 +627,7 @@ public: return Cell_circulator(e, start); } Cell_circulator incident_cells(Cell_handle ce, int i, int j, - Cell_handle start) const + Cell_handle start) const { CGAL_triangulation_precondition( dimension() == 3 ); return Cell_circulator(ce, i, j, start); @@ -603,19 +650,19 @@ public: return Facet_circulator(e, start); } Facet_circulator incident_facets(Cell_handle ce, int i, int j, - const Facet & start) const + const Facet & start) const { CGAL_triangulation_precondition( dimension() == 3 ); return Facet_circulator(ce, i, j, start); } Facet_circulator incident_facets(const Edge & e, - Cell_handle start, int f) const + Cell_handle start, int f) const { CGAL_triangulation_precondition( dimension() == 3 ); return Facet_circulator(e, start, f); } Facet_circulator incident_facets(Cell_handle ce, int i, int j, - Cell_handle start, int f) const + Cell_handle start, int f) const { CGAL_triangulation_precondition( dimension() == 3 ); return Facet_circulator(ce, i, j, start, f); @@ -634,35 +681,65 @@ private: template std::pair incident_cells_3(Vertex_handle v, Cell_handle d, - std::pair it) const + std::pair it) const { - CGAL_triangulation_precondition(dimension() == 3); - - std::stack cell_stack; - cell_stack.push(d); - d->tds_data().mark_in_conflict(); - *it.first++ = d; - - do { - Cell_handle c = cell_stack.top(); - cell_stack.pop(); - - for (int i=0; i<4; ++i) { - if (c->vertex(i) == v) - continue; - Cell_handle next = c->neighbor(i); - if (c < next) - *it.second++ = Facet(c, i); // Incident facet. - if (! next->tds_data().is_clear()) - continue; - cell_stack.push(next); - next->tds_data().mark_in_conflict(); - *it.first++ = next; - } - } while(!cell_stack.empty()); + CGAL_triangulation_precondition(dimension() == 3); + + std::stack cell_stack; + cell_stack.push(d); + d->tds_data().mark_in_conflict(); + *it.first++ = d; + + do { + Cell_handle c = cell_stack.top(); + cell_stack.pop(); + + for (int i=0; i<4; ++i) { + if (c->vertex(i) == v) + continue; + Cell_handle next = c->neighbor(i); + if (c < next) + *it.second++ = Facet(c, i); // Incident facet. + if (! next->tds_data().is_clear()) + continue; + cell_stack.push(next); + next->tds_data().mark_in_conflict(); + *it.first++ = next; + } + } while(!cell_stack.empty()); - return it; + return it; + } + + template + void + incident_cells_3_threadsafe(Vertex_handle v, Cell_handle d, + std::vector &cells, + IncidentFacetIterator facet_it) const + { + boost::unordered_set found_cells; + + cells.push_back(d); + found_cells.insert(d); + int head=0; + int tail=1; + do { + Cell_handle c = cells[head]; + + for (int i=0; i<4; ++i) { + if (c->vertex(i) == v) + continue; + Cell_handle next = c->neighbor(i); + if (c < next) + *facet_it++ = Facet(c, i); // Incident facet + if (! found_cells.insert(next).second ) + continue; + cells.push_back(next); + ++tail; + } + ++head; + } while(head != tail); } void just_incident_cells_3(Vertex_handle v, @@ -683,7 +760,7 @@ private: continue; Cell_handle next = c->neighbor(i); if (! next->tds_data().is_clear()) - continue; + continue; cells.push_back(next); ++tail; next->tds_data().mark_in_conflict(); @@ -695,28 +772,16 @@ private: template void incident_cells_2(Vertex_handle v, Cell_handle c, - OutputIterator cells) const + OutputIterator cells) const { CGAL_triangulation_precondition(dimension() == 2); - // TODO : in 2D, there's no real need for tds_data, we could use - // a smarter algorithm. We could use the 2D Face_circulator. - // Should we just have this Face_circulator ? - - // Flag values : - // 1 : incident cell already visited - // 0 : unknown - c->tds_data().mark_in_conflict(); - *cells++ = c; - - for (int i=0; i<3; ++i) { - if (c->vertex(i) == v) - continue; - Cell_handle next = c->neighbor(i); - if (! next->tds_data().is_clear()) - continue; - incident_cells_2(v, next, cells); - } + Face_circulator fc = incident_faces(v); + Face_circulator done(fc); + do { + *cells++ = fc; + ++fc; + } while (fc != done); } public: @@ -730,8 +795,8 @@ public: } }; - // Visitor for visit_incident_cells: - // outputs the facets + // Visitor for visit_incident_cells: + // outputs the facets template class Facet_extractor { OutputIterator output; @@ -755,15 +820,15 @@ public: Facet_it operator++(int) {return *this;}; template Facet_it& operator=(const T& e) { - if(filter(e)) - return *this; - *output++ = e; - return *this; + if(filter(e)) + return *this; + *output++ = e; + return *this; } Facet_it& operator=(const Facet_it& f) { - output = f.output; - filter = f.filter; - return *this; + output = f.output; + filter = f.filter; + return *this; } }; Facet_it facet_it() { @@ -771,8 +836,8 @@ public: } }; - // Visitor for visit_incident_cells: - // outputs the cells + // Visitor for visit_incident_cells: + // outputs the cells template class Cell_extractor { OutputIterator output; @@ -783,7 +848,7 @@ public: void operator()(Cell_handle c) { if(filter(c)) - return; + return; *output++ = c; } CGAL::Emptyset_iterator facet_it() {return CGAL::Emptyset_iterator();} @@ -806,7 +871,7 @@ public: void operator()(Cell_handle c) { Facet f = Facet(c,3); if(filter(f)) - return; + return; *output++ = f; } CGAL::Emptyset_iterator facet_it() {return CGAL::Emptyset_iterator();} @@ -818,8 +883,8 @@ public: template class Vertex_extractor; - // Visitor for visit_incident_cells: - // outputs the result of Treatment applied to the vertices + // Visitor for visit_incident_cells: + // outputs the result of Treatment applied to the vertices template class Vertex_extractor { Vertex_handle v; @@ -840,14 +905,13 @@ public: void operator()(Cell_handle c) { for (int j=0; j<= t->dimension(); ++j) { - Vertex_handle w = c->vertex(j); - if(filter(w)) - continue; - if (w != v){ - - if(tmp_vertices.insert(w).second) { - treat(c, v, j); - } + Vertex_handle w = c->vertex(j); + if(filter(w)) + continue; + if (w != v) { + if(tmp_vertices.insert(w).second) { + treat(c, v, j); + } } } @@ -958,12 +1022,27 @@ public: just_incident_cells_3(v, cells); typename std::vector::iterator cit,end; for(cit = cells.begin(), end = cells.end(); - cit != end; - ++cit) + cit != end; + ++cit) { (*cit)->tds_data().clear(); } } + + template + OutputIterator + incident_cells_threadsafe(Vertex_handle v, OutputIterator cells, Filter f = Filter()) const + { + return visit_incident_cells_threadsafe, + OutputIterator>(v, cells, f); + } + + template + OutputIterator + incident_cells_threadsafe(Vertex_handle v, OutputIterator cells) const + { + return incident_cells_threadsafe(v, cells); + } template OutputIterator @@ -971,9 +1050,9 @@ public: { CGAL_triangulation_precondition( dimension() > 1 ); if(dimension() == 3) - return visit_incident_cells, OutputIterator>(v, facets, f); + return visit_incident_cells, OutputIterator>(v, facets, f); else - return visit_incident_cells, OutputIterator>(v, facets, f); + return visit_incident_cells, OutputIterator>(v, facets, f); } template @@ -982,6 +1061,24 @@ public: { return incident_facets(v, facets); } + + template + OutputIterator + incident_facets_threadsafe(Vertex_handle v, OutputIterator facets, Filter f = Filter()) const + { + CGAL_triangulation_precondition( dimension() > 1 ); + if(dimension() == 3) + return visit_incident_cells_threadsafe, OutputIterator>(v, facets, f); + else + return visit_incident_cells_threadsafe, OutputIterator>(v, facets, f); + } + + template + OutputIterator + incident_facets_threadsafe(Vertex_handle v, OutputIterator facets) const + { + return incident_facets(v, facets); + } BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_member_visited,Has_visited_for_vertex_extractor,false) @@ -1091,8 +1188,8 @@ public: typename std::vector::iterator cit; for(cit = tmp_cells.begin(); - cit != tmp_cells.end(); - ++cit) + cit != tmp_cells.end(); + ++cit) { (*cit)->tds_data().clear(); visit(*cit); @@ -1100,6 +1197,130 @@ public: return visit.result(); } + + template + OutputIterator + visit_incident_cells_threadsafe( + Vertex_handle v, OutputIterator output, Filter f) const + { + CGAL_triangulation_precondition( v != Vertex_handle() ); + CGAL_triangulation_expensive_precondition( is_vertex(v) ); + + if ( dimension() < 2 ) + return output; + + Visitor visit(v, output, this, f); + + std::vector tmp_cells; + tmp_cells.reserve(64); + if ( dimension() == 3 ) + incident_cells_3_threadsafe( + v, v->cell(), tmp_cells, visit.facet_it()); + else + incident_cells_2(v, v->cell(), std::back_inserter(tmp_cells)); + + typename std::vector::iterator cit; + for(cit = tmp_cells.begin(); + cit != tmp_cells.end(); + ++cit) + { + visit(*cit); + } + + return visit.result(); + } + + template + OutputIterator + visit_incident_cells(Vertex_handle v, OutputIterator output, + std::vector &cells, Filter f) const + { + CGAL_triangulation_precondition( v != Vertex_handle() ); + CGAL_triangulation_expensive_precondition( is_vertex(v) ); + + if ( dimension() < 2 ) + return output; + + Visitor visit(v, output, this, f); + + if ( dimension() == 3 ) + incident_cells_3(v, v->cell(), std::make_pair(std::back_inserter(cells), visit.facet_it())); + else + incident_cells_2(v, v->cell(), std::back_inserter(cells)); + + typename std::vector::iterator cit; + for(cit = cells.begin(); + cit != cells.end(); + ++cit) + { + (*cit)->tds_data().clear(); + visit(*cit); + } + return visit.result(); + } + + template + OutputIterator + visit_just_incident_cells(Vertex_handle v, OutputIterator output, Filter f) const + { + CGAL_triangulation_precondition( v != Vertex_handle() ); + CGAL_triangulation_expensive_precondition( is_vertex(v) ); + + if ( dimension() < 2 ) + return output; + + Visitor visit(v, output, this, f); + + std::vector tmp_cells; + tmp_cells.reserve(64); + + if ( dimension() == 3 ) + just_incident_cells_3(v, tmp_cells); + else + incident_cells_2(v, v->cell(), std::back_inserter(tmp_cells)); + + typename std::vector::iterator cit; + for(cit = tmp_cells.begin(); + cit != tmp_cells.end(); + ++cit) + { + (*cit)->tds_data().clear(); + visit(*cit); + } + return visit.result(); + } + + // For dimension 3 only + template + OutputVertexIterator + adjacent_vertices_and_cells_3(Vertex_handle v, OutputVertexIterator vertices, + std::vector &cells, + VertexFilter f = VertexFilter()) const + { + CGAL_triangulation_precondition( v != Vertex_handle() ); + CGAL_triangulation_precondition( dimension() == 3 ); + CGAL_triangulation_expensive_precondition( is_vertex(v) ); + CGAL_triangulation_expensive_precondition( is_valid() ); + + return + visit_incident_cells + < + Vertex_extractor, + OutputVertexIterator, + VertexFilter, + Has_member_visited::value>, + OutputVertexIterator + >(v, vertices, cells, f); + } + + // For dimension 3 only + template + OutputVertexIterator + adjacent_vertices_and_cells_3(Vertex_handle v, OutputVertexIterator vertices, + std::vector &cells) const + { + return adjacent_vertices_and_cells_3(v, vertices, cells); + } size_type degree(Vertex_handle v) const; @@ -1111,7 +1332,7 @@ public: // Helping functions template Vertex_handle copy_tds(const TDS_src & tds, - typename TDS_src::Vertex_handle vert); + typename TDS_src::Vertex_handle vert); template Vertex_handle copy_tds(const TDS_src & tds) @@ -1129,7 +1350,7 @@ public: void clear(); void set_adjacency(Cell_handle c0, int i0, - Cell_handle c1, int i1) const + Cell_handle c1, int i1) const { CGAL_triangulation_assertion(i0 >= 0 && i0 <= dimension()); CGAL_triangulation_assertion(i1 >= 0 && i1 <= dimension()); @@ -1197,9 +1418,9 @@ private: }; #ifdef CGAL_TDS_USE_RECURSIVE_CREATE_STAR_3 -template -typename Triangulation_data_structure_3::Cell_handle -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::Cell_handle +Triangulation_data_structure_3:: create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind2) { CGAL_triangulation_precondition( dimension() == 3); @@ -1207,9 +1428,9 @@ create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind2) CGAL_triangulation_precondition( ! c->neighbor(li)->tds_data().is_in_conflict() ); Cell_handle cnew = create_cell(c->vertex(0), - c->vertex(1), - c->vertex(2), - c->vertex(3)); + c->vertex(1), + c->vertex(2), + c->vertex(3)); cnew->set_vertex(li, v); Cell_handle c_li = c->neighbor(li); set_adjacency(cnew, li, c_li, c_li->index(c)); @@ -1217,7 +1438,7 @@ create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind2) // Look for the other neighbors of cnew. for (int ii=0; ii<4; ++ii) { if (ii == prev_ind2 || cnew->neighbor(ii) != Cell_handle()) - continue; + continue; cnew->vertex(ii)->set_cell(cnew); // Indices of the vertices of cnew such that ii,vj1,vj2,li positive. @@ -1228,13 +1449,12 @@ create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind2) Cell_handle n = cur->neighbor(zz); // turn around the oriented edge vj1 vj2 while ( n->tds_data().is_in_conflict() ) { - CGAL_triangulation_assertion( n != c ); - cur = n; - zz = next_around_edge(n->index(vj1), n->index(vj2)); - n = cur->neighbor(zz); + CGAL_triangulation_assertion( n != c ); + cur = n; + zz = next_around_edge(n->index(vj1), n->index(vj2)); + n = cur->neighbor(zz); } // Now n is outside region, cur is inside. - n->tds_data().clear(); // Reset the flag for boundary cells. int jj1 = n->index(vj1); @@ -1243,9 +1463,9 @@ create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind2) Cell_handle nnn = n->neighbor(next_around_edge(jj2, jj1)); int zzz = nnn->index(vvv); if (nnn == cur) { - // Neighbor relation is reciprocal, ie - // the cell we are looking for is not yet created. - nnn = create_star_3(v, nnn, zz, zzz); + // Neighbor relation is reciprocal, ie + // the cell we are looking for is not yet created. + nnn = create_star_3(v, nnn, zz, zzz); } set_adjacency(nnn, zzz, cnew, ii); @@ -1254,9 +1474,9 @@ create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind2) return cnew; } #else -template -typename Triangulation_data_structure_3::Cell_handle -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::Cell_handle +Triangulation_data_structure_3:: recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind2, int depth) { @@ -1266,9 +1486,9 @@ recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, CGAL_triangulation_precondition( ! c->neighbor(li)->tds_data().is_in_conflict() ); Cell_handle cnew = create_cell(c->vertex(0), - c->vertex(1), - c->vertex(2), - c->vertex(3)); + c->vertex(1), + c->vertex(2), + c->vertex(3)); cnew->set_vertex(li, v); Cell_handle c_li = c->neighbor(li); set_adjacency(cnew, li, c_li, c_li->index(c)); @@ -1276,7 +1496,7 @@ recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, // Look for the other neighbors of cnew. for (int ii=0; ii<4; ++ii) { if (ii == prev_ind2 || cnew->neighbor(ii) != Cell_handle()) - continue; + continue; cnew->vertex(ii)->set_cell(cnew); // Indices of the vertices of cnew such that ii,vj1,vj2,li positive. @@ -1287,13 +1507,12 @@ recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, Cell_handle n = cur->neighbor(zz); // turn around the oriented edge vj1 vj2 while ( n->tds_data().is_in_conflict() ) { - CGAL_triangulation_assertion( n != c ); - cur = n; - zz = next_around_edge(n->index(vj1), n->index(vj2)); - n = cur->neighbor(zz); + CGAL_triangulation_assertion( n != c ); + cur = n; + zz = next_around_edge(n->index(vj1), n->index(vj2)); + n = cur->neighbor(zz); } // Now n is outside region, cur is inside. - n->tds_data().clear(); // Reset the flag for boundary cells. int jj1 = n->index(vj1); @@ -1302,9 +1521,9 @@ recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, Cell_handle nnn = n->neighbor(next_around_edge(jj2, jj1)); int zzz = nnn->index(vvv); if (nnn == cur) { - // Neighbor relation is reciprocal, ie - // the cell we are looking for is not yet created. - nnn = recursive_create_star_3(v, nnn, zz, zzz,depth+1); + // Neighbor relation is reciprocal, ie + // the cell we are looking for is not yet created. + nnn = recursive_create_star_3(v, nnn, zz, zzz,depth+1); } set_adjacency(nnn, zzz, cnew, ii); @@ -1315,9 +1534,9 @@ recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, //We use the class iAdjacency_info instead of a tuple because //at the moment we made the change it was faster like this. -template -typename Triangulation_data_structure_3::Cell_handle -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::Cell_handle +Triangulation_data_structure_3:: non_recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind2) { CGAL_triangulation_precondition( dimension() == 3); @@ -1325,9 +1544,9 @@ non_recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind CGAL_triangulation_precondition( ! c->neighbor(li)->tds_data().is_in_conflict() ); Cell_handle cnew = create_cell(c->vertex(0), - c->vertex(1), - c->vertex(2), - c->vertex(3)); + c->vertex(1), + c->vertex(2), + c->vertex(3)); cnew->set_vertex(li, v); Cell_handle c_li = c->neighbor(li); set_adjacency(cnew, li, c_li, c_li->index(c)); @@ -1355,7 +1574,6 @@ non_recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind n = cur->neighbor(zz); } // Now n is outside region, cur is inside. - n->tds_data().clear(); // Reset the flag for boundary cells. int jj1 = n->index(vj1); @@ -1393,9 +1611,9 @@ non_recursive_create_star_3(Vertex_handle v, Cell_handle c, int li, int prev_ind } #endif -template -typename Triangulation_data_structure_3::Cell_handle -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::Cell_handle +Triangulation_data_structure_3:: create_star_2(Vertex_handle v, Cell_handle c, int li ) { CGAL_triangulation_assertion( dimension() == 2 ); @@ -1423,7 +1641,7 @@ create_star_2(Vertex_handle v, Cell_handle c, int li ) // here cur has an edge on the boundary of region cnew = create_face( v, v1, cur->vertex( ccw(i1) ) ); set_adjacency(cnew, 0, cur->neighbor(cw(i1)), - cur->neighbor(cw(i1))->index(cur)); + cur->neighbor(cw(i1))->index(cur)); cnew->set_neighbor(1, Cell_handle()); cnew->set_neighbor(2, pnew); // pnew is null at the first iteration @@ -1443,9 +1661,9 @@ create_star_2(Vertex_handle v, Cell_handle c, int li ) return cnew; } -template < class Vb, class Cb> +template std::istream& -operator>>(std::istream& is, Triangulation_data_structure_3& tds) +operator>>(std::istream& is, Triangulation_data_structure_3& tds) // reads : // the dimension // the number of vertices @@ -1454,7 +1672,7 @@ operator>>(std::istream& is, Triangulation_data_structure_3& tds) // the neighbors of each cell by their index in the preceding list of cells // when dimension < 3 : the same with faces of maximal dimension { - typedef Triangulation_data_structure_3 Tds; + typedef Triangulation_data_structure_3 Tds; typedef typename Tds::Vertex_handle Vertex_handle; typedef typename Tds::Cell_handle Cell_handle; @@ -1491,9 +1709,9 @@ operator>>(std::istream& is, Triangulation_data_structure_3& tds) return is; } -template < class Vb, class Cb> +template std::ostream& -operator<<(std::ostream& os, const Triangulation_data_structure_3 &tds) +operator<<(std::ostream& os, const Triangulation_data_structure_3 &tds) // writes : // the dimension // the number of vertices @@ -1502,7 +1720,7 @@ operator<<(std::ostream& os, const Triangulation_data_structure_3 &tds) // the neighbors of each cell by their index in the preceding list of cells // when dimension < 3 : the same with faces of maximal dimension { - typedef Triangulation_data_structure_3 Tds; + typedef Triangulation_data_structure_3 Tds; typedef typename Tds::size_type size_type; typedef typename Tds::Vertex_handle Vertex_handle; typedef typename Tds::Vertex_iterator Vertex_iterator; @@ -1536,9 +1754,9 @@ operator<<(std::ostream& os, const Triangulation_data_structure_3 &tds) return os; } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_simplex( Cell_handle c ) const { switch(dimension()) { @@ -1551,19 +1769,19 @@ is_simplex( Cell_handle c ) const return false; } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_vertex(Vertex_handle v) const { return vertices().owns_dereferencable(v); } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_edge(Vertex_handle u, Vertex_handle v, - Cell_handle &c, int &i, int &j) const + Cell_handle &c, int &i, int &j) const // returns false when dimension <1 or when indices wrong { CGAL_triangulation_expensive_precondition( is_vertex(u) && is_vertex(v) ); @@ -1576,18 +1794,18 @@ is_edge(Vertex_handle u, Vertex_handle v, incident_cells(u, std::back_inserter(cells)); for (typename std::vector::iterator cit = cells.begin(); - cit != cells.end(); ++cit) + cit != cells.end(); ++cit) if ((*cit)->has_vertex(v, j)) { - c = *cit; - i = c->index(u); - return true; - } + c = *cit; + i = c->index(u); + return true; + } return false; } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_edge(Vertex_handle u, Vertex_handle v) const { Cell_handle c; @@ -1595,9 +1813,9 @@ is_edge(Vertex_handle u, Vertex_handle v) const return is_edge(u, v, c, i, j); } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_edge(Cell_handle c, int i, int j) const { if (dimension() < 1) @@ -1612,40 +1830,40 @@ is_edge(Cell_handle c, int i, int j) const return cells().owns_dereferencable(c); } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_facet(Vertex_handle u, Vertex_handle v, - Vertex_handle w, - Cell_handle & c, int & i, int & j, int & k) const + Vertex_handle w, + Cell_handle & c, int & i, int & j, int & k) const // returns false when dimension <2 or when indices wrong { CGAL_triangulation_expensive_precondition( is_vertex(u) && - is_vertex(v) && - is_vertex(w) ); + is_vertex(v) && + is_vertex(w) ); if ( u==v || u==w || v==w ) - return false; + return false; if (dimension() < 2) - return false; + return false; std::vector cells; cells.reserve(64); incident_cells(u, std::back_inserter(cells)); for (typename std::vector::iterator cit = cells.begin(); - cit != cells.end(); ++cit) + cit != cells.end(); ++cit) if ((*cit)->has_vertex(v, j) && (*cit)->has_vertex(w, k)) { - c = *cit; - i = c->index(u); - return true; - } + c = *cit; + i = c->index(u); + return true; + } return false; } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_facet(Cell_handle c, int i) const { CGAL_triangulation_precondition(i>=0 && i<4); @@ -1659,9 +1877,9 @@ is_facet(Cell_handle c, int i) const return cells().owns_dereferencable(c); } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_cell( Cell_handle c ) const // returns false when dimension <3 { @@ -1671,18 +1889,18 @@ is_cell( Cell_handle c ) const return cells().owns_dereferencable(c); } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_cell(Vertex_handle u, Vertex_handle v, - Vertex_handle w, Vertex_handle t, - Cell_handle & c, int & i, int & j, int & k, int & l) const + Vertex_handle w, Vertex_handle t, + Cell_handle & c, int & i, int & j, int & k, int & l) const // returns false when dimension <3 { CGAL_triangulation_expensive_precondition( is_vertex(u) && - is_vertex(v) && - is_vertex(w) && - is_vertex(t) ); + is_vertex(v) && + is_vertex(w) && + is_vertex(t) ); if ( u==v || u==w || u==t || v==w || v==t || w==t ) return false; @@ -1692,21 +1910,21 @@ is_cell(Vertex_handle u, Vertex_handle v, incident_cells(u, std::back_inserter(cells)); for (typename std::vector::iterator cit = cells.begin(); - cit != cells.end(); ++cit) + cit != cells.end(); ++cit) if ((*cit)->has_vertex(v, j) && (*cit)->has_vertex(w, k) && - (*cit)->has_vertex(t, l)) { - c = *cit; - i = c->index(u); - return true; - } + (*cit)->has_vertex(t, l)) { + c = *cit; + i = c->index(u); + return true; + } return false; } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_cell(Vertex_handle u, Vertex_handle v, - Vertex_handle w, Vertex_handle t) + Vertex_handle w, Vertex_handle t) const // returns false when dimension <3 { @@ -1715,10 +1933,10 @@ is_cell(Vertex_handle u, Vertex_handle v, return is_cell(u, v, w, t, c, i, j, k, l); } -template < class Vb, class Cb> +template inline bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: has_vertex(Cell_handle c, int i, Vertex_handle v, int & j) const // computes the index j of the vertex in the cell c giving the query // facet (c,i) @@ -1728,10 +1946,10 @@ has_vertex(Cell_handle c, int i, Vertex_handle v, int & j) const return ( c->has_vertex(v,j) && (j != i) ); } -template < class Vb, class Cb> +template inline bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: has_vertex(Cell_handle c, int i, Vertex_handle v) const // checks whether the query facet (c,i) has vertex v { @@ -1740,27 +1958,27 @@ has_vertex(Cell_handle c, int i, Vertex_handle v) const return ( c->has_vertex(v,j) && (j != i) ); } -template < class Vb, class Cb> +template inline bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: has_vertex(const Facet & f, Vertex_handle v, int & j) const { return has_vertex(f.first, f.second, v, j); } -template < class Vb, class Cb> +template inline bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: has_vertex(const Facet & f, Vertex_handle v) const { return has_vertex(f.first, f.second, v); } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: are_equal(Cell_handle c, int i, Cell_handle n, int j) const // tests whether facets c,i and n,j, have the same 3 vertices // the triangulation is supposed to be valid, the orientation of the @@ -1777,30 +1995,30 @@ are_equal(Cell_handle c, int i, Cell_handle n, int j) const int j1,j2,j3; return( n->has_vertex( c->vertex((i+1)&3), j1 ) && - n->has_vertex( c->vertex((i+2)&3), j2 ) && - n->has_vertex( c->vertex((i+3)&3), j3 ) && - ( j1+j2+j3+j == 6 ) ); + n->has_vertex( c->vertex((i+2)&3), j2 ) && + n->has_vertex( c->vertex((i+3)&3), j3 ) && + ( j1+j2+j3+j == 6 ) ); } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: are_equal(const Facet & f, const Facet & g) const { return are_equal(f.first, f.second, g.first, g.second); } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: are_equal(const Facet & f, Cell_handle n, int j) const { return are_equal(f.first, f.second, n, j); } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: flip( Cell_handle c, int i ) // returns false if the facet is not flippable // true other wise and @@ -1808,7 +2026,7 @@ flip( Cell_handle c, int i ) // c will be replaced by one of the new cells { CGAL_triangulation_precondition( (dimension() == 3) && (0<=i) && (i<4) - && (number_of_vertices() >= 6) ); + && (number_of_vertices() >= 6) ); CGAL_triangulation_expensive_precondition( is_cell(c) ); Cell_handle n = c->neighbor(i); @@ -1823,15 +2041,15 @@ flip( Cell_handle c, int i ) return true; } -template < class Vb, class Cb> +template void -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: flip_flippable(Cell_handle c, int i ) // flips facet i of cell c // c will be replaced by one of the new cells { CGAL_triangulation_precondition( (dimension() == 3) && (0<=i) && (i<4) - && (number_of_vertices() >= 6) ); + && (number_of_vertices() >= 6) ); CGAL_triangulation_expensive_precondition( is_cell(c) ); Cell_handle n = c->neighbor(i); @@ -1840,14 +2058,14 @@ flip_flippable(Cell_handle c, int i ) // checks that the facet is flippable, // ie the future edge does not already exist CGAL_triangulation_expensive_precondition( !is_edge(c->vertex(i), - n->vertex(in))); + n->vertex(in))); flip_really(c,i,n,in); } -template < class Vb, class Cb> +template inline void -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: flip_really( Cell_handle c, int i, Cell_handle n, int in ) // private - used by flip and flip_flippable { @@ -1866,7 +2084,7 @@ flip_really( Cell_handle c, int i, Cell_handle n, int in ) n->set_vertex( in1, c->vertex(i) ); Cell_handle cnew = create_cell(c->vertex(i), c->vertex(i1), - n->vertex(in), n->vertex(in3)); + n->vertex(in), n->vertex(in3)); set_adjacency(cnew, 0, n->neighbor(in2), n->neighbor(in2)->index(n)); set_adjacency(cnew, 1, n, in2); @@ -1884,9 +2102,9 @@ flip_really( Cell_handle c, int i, Cell_handle n, int in ) // CGAL_triangulation_precondition( (0<=i) && (i<3) ); } -template < class Vb, class Cb> +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: flip( Cell_handle c, int i, int j ) // returns false if the edge is not flippable // true otherwise and @@ -1894,10 +2112,10 @@ flip( Cell_handle c, int i, int j ) // c will be deleted { CGAL_triangulation_precondition( (dimension() == 3) - && (0<=i) && (i<4) - && (0<=j) && (j<4) - && ( i != j ) - && (number_of_vertices() >= 6) ); + && (0<=i) && (i<4) + && (0<=j) && (j<4) + && ( i != j ) + && (number_of_vertices() >= 6) ); CGAL_triangulation_expensive_precondition( is_cell(c) ); // checks that the edge is flippable ie degree 3 @@ -1936,18 +2154,18 @@ flip( Cell_handle c, int i, int j ) return true; } -template < class Vb, class Cb> +template void -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: flip_flippable( Cell_handle c, int i, int j ) // flips edge i,j of cell c // c will be deleted { CGAL_triangulation_precondition( (dimension() == 3) - && (0<=i) && (i<4) - && (0<=j) && (j<4) - && ( i != j ) - && (number_of_vertices() >= 6) ); + && (0<=i) && (i<4) + && (0<=j) && (j<4) + && ( i != j ) + && (number_of_vertices() >= 6) ); CGAL_triangulation_expensive_precondition( is_cell(c) ); // checks that the edge is flippable ie degree 3 @@ -1957,7 +2175,7 @@ flip_flippable( Cell_handle c, int i, int j ) CGAL_triangulation_precondition_code( Cell_circulator cdone = ccir; ); CGAL_triangulation_precondition_code( do { ++degree; - ++ccir; + ++ccir; } while ( ccir != cdone ); ); CGAL_triangulation_precondition( degree == 3 ); @@ -1985,16 +2203,16 @@ flip_flippable( Cell_handle c, int i, int j ) flip_really(c,i,j,c1,v1,i1,j1,next1,c2,v2,i2,j2,next2,v3); } -template < class Vb, class Cb> +template inline void -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: flip_really( Cell_handle c, int i, int j, - Cell_handle c1, Vertex_handle v1, - int i1, int j1, int next1, - Cell_handle c2, Vertex_handle v2, - int i2, int j2, int next2, - Vertex_handle v3 ) + Cell_handle c1, Vertex_handle v1, + int i1, int j1, int next1, + Cell_handle c2, Vertex_handle v2, + int i2, int j2, int next2, + Vertex_handle v3 ) { c->vertex(i)->set_cell(c1); c->vertex(j)->set_cell(c2); @@ -2017,11 +2235,11 @@ flip_really( Cell_handle c, int i, int j, delete_cell( c ); } -template < class Vb, class Cb > +template void -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: read_cells(std::istream& is, std::map< std::size_t, Vertex_handle > &V, - std::size_t & m, std::map< std::size_t, Cell_handle > &C) + std::size_t & m, std::map< std::size_t, Cell_handle > &C) { // creation of the cells and neighbors switch (dimension()) { @@ -2035,28 +2253,28 @@ read_cells(std::istream& is, std::map< std::size_t, Vertex_handle > &V, read(is, m); for(std::size_t i = 0; i < m; i++) { - Cell_handle c = create_cell(); - for (int k=0; k<=dimension(); ++k) { + Cell_handle c = create_cell(); + for (int k=0; k<=dimension(); ++k) { std::size_t ik; if(is_ascii(is)) is >> ik; else read(is, ik); - c->set_vertex(k, V[ik]); - V[ik]->set_cell(c); - } - C[i] = c; + c->set_vertex(k, V[ik]); + V[ik]->set_cell(c); + } + C[i] = c; } for(std::size_t j = 0; j < m; j++) { Cell_handle c = C[j]; - for (int k=0; k<=dimension(); ++k) { + for (int k=0; k<=dimension(); ++k) { std::size_t ik; if(is_ascii(is)) is >> ik; else read(is, ik); - c->set_neighbor(k, C[ik]); - } + c->set_neighbor(k, C[ik]); + } } break; } @@ -2066,12 +2284,12 @@ read_cells(std::istream& is, std::map< std::size_t, Vertex_handle > &V, // CGAL_triangulation_assertion( n == 2 ); for (int i=0; i < 2; i++) { - Cell_handle c = create_face(V[i], Vertex_handle(), Vertex_handle()); - C[i] = c; - V[i]->set_cell(c); + Cell_handle c = create_face(V[i], Vertex_handle(), Vertex_handle()); + C[i] = c; + V[i]->set_cell(c); } for (int j=0; j < 2; j++) { - Cell_handle c = C[j]; + Cell_handle c = C[j]; c->set_neighbor(0, C[1-j]); } break; @@ -2088,9 +2306,9 @@ read_cells(std::istream& is, std::map< std::size_t, Vertex_handle > &V, } } -template < class Vb, class Cb> +template void -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: print_cells(std::ostream& os, const Unique_hash_map &V ) const { std::map C; @@ -2108,34 +2326,34 @@ print_cells(std::ostream& os, const Unique_hash_map // write the cells Cell_iterator it; for(it = cells_begin(); it != cells_end(); ++it) { - C[it] = i++; - for(int j = 0; j < 4; j++){ - if(is_ascii(os)) { + C[it] = i++; + for(int j = 0; j < 4; j++){ + if(is_ascii(os)) { os << V[it->vertex(j)]; - if ( j==3 ) - os << std::endl; - else - os << ' '; - } + if ( j==3 ) + os << std::endl; + else + os << ' '; + } else write(os, V[it->vertex(j)]); - } + } } CGAL_triangulation_assertion( i == m ); // write the neighbors for(it = cells_begin(); it != cells_end(); ++it) { - for (int j = 0; j < 4; j++) { - if(is_ascii(os)){ + for (int j = 0; j < 4; j++) { + if(is_ascii(os)){ os << C[it->neighbor(j)]; - if(j==3) - os << std::endl; - else - os << ' '; + if(j==3) + os << std::endl; + else + os << ' '; } else write(os, C[it->neighbor(j)]); - } + } } break; } @@ -2150,36 +2368,36 @@ print_cells(std::ostream& os, const Unique_hash_map // write the facets Facet_iterator it; for(it = facets_begin(); it != facets_end(); ++it) { - C[(*it).first] = i++; - for(int j = 0; j < 3; j++){ - if(is_ascii(os)) { - os << V[(*it).first->vertex(j)]; - if ( j==2 ) - os << std::endl; - else - os << ' '; - } - else { - write(os, V[(*it).first->vertex(j)]); - } - } + C[(*it).first] = i++; + for(int j = 0; j < 3; j++){ + if(is_ascii(os)) { + os << V[(*it).first->vertex(j)]; + if ( j==2 ) + os << std::endl; + else + os << ' '; + } + else { + write(os, V[(*it).first->vertex(j)]); + } + } } CGAL_triangulation_assertion( i == m ); // write the neighbors for(it = facets_begin(); it != facets_end(); ++it) { - for (int j = 0; j < 3; j++) { - if(is_ascii(os)){ - os << C[(*it).first->neighbor(j)]; - if(j==2) - os << std::endl; - else - os << ' '; - } - else { - write(os, C[(*it).first->neighbor(j)]); - } - } + for (int j = 0; j < 3; j++) { + if(is_ascii(os)){ + os << C[(*it).first->neighbor(j)]; + if(j==2) + os << std::endl; + else + os << ' '; + } + else { + write(os, C[(*it).first->neighbor(j)]); + } + } } break; } @@ -2193,45 +2411,93 @@ print_cells(std::ostream& os, const Unique_hash_map // write the edges Edge_iterator it; for(it = edges_begin(); it != edges_end(); ++it) { - C[(*it).first] = i++; - for(int j = 0; j < 2; j++){ - if(is_ascii(os)) { - os << V[(*it).first->vertex(j)]; - if ( j==1 ) - os << std::endl; - else - os << ' '; - } - else { - write(os, V[(*it).first->vertex(j)]); - } - } + C[(*it).first] = i++; + for(int j = 0; j < 2; j++){ + if(is_ascii(os)) { + os << V[(*it).first->vertex(j)]; + if ( j==1 ) + os << std::endl; + else + os << ' '; + } + else { + write(os, V[(*it).first->vertex(j)]); + } + } } CGAL_triangulation_assertion( i == m ); // write the neighbors for(it = edges_begin(); it != edges_end(); ++it) { - for (int j = 0; j < 2; j++) { - if(is_ascii(os)){ - os << C[(*it).first->neighbor(j)]; - if(j==1) - os << std::endl; - else - os << ' '; - } - else { - write(os, C[(*it).first->neighbor(j)]); - } - } + for (int j = 0; j < 2; j++) { + if(is_ascii(os)){ + os << C[(*it).first->neighbor(j)]; + if(j==1) + os << std::endl; + else + os << ' '; + } + else { + write(os, C[(*it).first->neighbor(j)]); + } + } } break; } } } -template -typename Triangulation_data_structure_3::Vertex_handle -Triangulation_data_structure_3:: + +template +typename Triangulation_data_structure_3::Vertex_handle +Triangulation_data_structure_3::insert_first_finite_cell( + Vertex_handle &v0, Vertex_handle &v1, Vertex_handle &v2, Vertex_handle &v3, + Vertex_handle v_infinite) +{ + CGAL_triangulation_precondition( + (v_infinite == Vertex_handle() && dimension() == -2) + || (v_infinite != Vertex_handle() && dimension() == -1)); + + if (v_infinite == Vertex_handle()) + v_infinite = create_vertex(); + + set_dimension(3); + + v0 = create_vertex(); + v1 = create_vertex(); + v2 = create_vertex(); + v3 = create_vertex(); + + Cell_handle c0123 = create_cell(v0, v1, v2, v3); + Cell_handle ci012 = create_cell(v_infinite, v0, v1, v2); + Cell_handle ci103 = create_cell(v_infinite, v1, v0, v3); + Cell_handle ci023 = create_cell(v_infinite, v0, v2, v3); + Cell_handle ci132 = create_cell(v_infinite, v1, v3, v2); + + v_infinite->set_cell(ci012); + v0->set_cell(c0123); + v1->set_cell(c0123); + v2->set_cell(c0123); + v3->set_cell(c0123); + + set_adjacency(c0123, 0, ci132, 0); + set_adjacency(c0123, 1, ci023, 0); + set_adjacency(c0123, 2, ci103, 0); + set_adjacency(c0123, 3, ci012, 0); + + set_adjacency(ci012, 3, ci103, 3); + set_adjacency(ci012, 2, ci023, 3); + set_adjacency(ci012, 1, ci132, 2); + set_adjacency(ci103, 1, ci023, 2); + set_adjacency(ci023, 1, ci132, 1); + set_adjacency(ci103, 2, ci132, 3); + + return v_infinite; +} + +template +typename Triangulation_data_structure_3::Vertex_handle +Triangulation_data_structure_3:: insert_in_cell(Cell_handle c) { CGAL_triangulation_precondition( dimension() == 3 ); @@ -2274,9 +2540,9 @@ insert_in_cell(Cell_handle c) return v; } -template -typename Triangulation_data_structure_3::Vertex_handle -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::Vertex_handle +Triangulation_data_structure_3:: insert_in_facet(Cell_handle c, int i) { // inserts v in the facet opposite to vertex i of cell c @@ -2291,15 +2557,15 @@ insert_in_facet(Cell_handle c, int i) { CGAL_triangulation_expensive_precondition( is_cell(c) ); CGAL_triangulation_precondition( i == 0 || i == 1 || - i == 2 || i == 3 ); + i == 2 || i == 3 ); // c will be modified to have v replacing vertex(i+3) int i1,i2,i3; if ( (i&1) == 0 ) { - i1=(i+1)&3; i2=(i+2)&3; i3=6-i-i1-i2; + i1=(i+1)&3; i2=(i+2)&3; i3=6-i-i1-i2; } else { - i1=(i+1)&3; i2=(i+3)&3; i3=6-i-i1-i2; + i1=(i+1)&3; i2=(i+3)&3; i3=6-i-i1-i2; } // i,i1,i2,i3 is well oriented // so v will "replace" the vertices in this order @@ -2383,9 +2649,9 @@ insert_in_facet(Cell_handle c, int i) return v; } -template -typename Triangulation_data_structure_3::Vertex_handle -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::Vertex_handle +Triangulation_data_structure_3:: insert_in_edge(Cell_handle c, int i, int j) // inserts a vertex in the edge of cell c with vertices i and j { @@ -2403,10 +2669,10 @@ insert_in_edge(Cell_handle c, int i, int j) cells.reserve(32); Cell_circulator ccir = incident_cells(c, i, j); do { - Cell_handle cc = ccir; - cells.push_back(cc); - cc->tds_data().mark_in_conflict(); - ++ccir; + Cell_handle cc = ccir; + cells.push_back(cc); + cc->tds_data().mark_in_conflict(); + ++ccir; } while (c != ccir); return _insert_in_hole(cells.begin(), cells.end(), c, i); @@ -2465,9 +2731,9 @@ insert_in_edge(Cell_handle c, int i, int j) } } -template -typename Triangulation_data_structure_3::Vertex_handle -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::Vertex_handle +Triangulation_data_structure_3:: insert_increase_dimension(Vertex_handle star) // star = vertex from which we triangulate the facet of the // incremented dimension @@ -2538,32 +2804,32 @@ insert_increase_dimension(Vertex_handle star) CGAL_assertion(i==0 || i==1); int j = (i == 0) ? 1 : 0; Cell_handle d = c->neighbor(j); - + c->set_vertex(2,v); Cell_handle e = c->neighbor(i); Cell_handle cnew = c; Cell_handle enew = Cell_handle(); - + while( e != d ){ - enew = create_cell(); - enew->set_vertex(i,e->vertex(j)); - enew->set_vertex(j,e->vertex(i)); - enew->set_vertex(2,star); - - set_adjacency(enew, i, cnew, j); - // false at the first iteration of the loop where it should - // be neighbor 2 - // it is corrected after the loop - set_adjacency(enew, 2, e, 2); - // neighbor j will be set during next iteration of the loop - - e->set_vertex(2,v); + enew = create_cell(); + enew->set_vertex(i,e->vertex(j)); + enew->set_vertex(j,e->vertex(i)); + enew->set_vertex(2,star); + + set_adjacency(enew, i, cnew, j); + // false at the first iteration of the loop where it should + // be neighbor 2 + // it is corrected after the loop + set_adjacency(enew, 2, e, 2); + // neighbor j will be set during next iteration of the loop + + e->set_vertex(2,v); - e = e->neighbor(i); - cnew = enew; + e = e->neighbor(i); + cnew = enew; } - + d->set_vertex(2,v); set_adjacency(enew, j, d, 2); @@ -2591,47 +2857,47 @@ insert_increase_dimension(Vertex_handle star) v->set_cell(it); // ok since there is at least one ``cell'' for(; it != cells_end(); ++it) { - // Here we must be careful since we create_cells in a loop controlled - // by an iterator. So we first take care of the cells newly created - // by the following test : - if (it->neighbor(0) == Cell_handle()) - continue; - it->set_neighbor(3, Cell_handle()); - it->set_vertex(3, v); - if ( ! it->has_vertex(star) ) { - Cell_handle cnew = create_cell( it->vertex(0), it->vertex(2), - it->vertex(1), star); - // The Intel compiler has a problem with passing "it" directly to - // function "set_adjacency": the adjacency is not changed. - Cell_handle ch_it = it; - set_adjacency(cnew, 3, ch_it, 3); - cnew->set_neighbor(0, Cell_handle()); - new_cells.push_back(cnew); - } + // Here we must be careful since we create_cells in a loop controlled + // by an iterator. So we first take care of the cells newly created + // by the following test : + if (it->neighbor(0) == Cell_handle()) + continue; + it->set_neighbor(3, Cell_handle()); + it->set_vertex(3, v); + if ( ! it->has_vertex(star) ) { + Cell_handle cnew = create_cell( it->vertex(0), it->vertex(2), + it->vertex(1), star); + // The Intel compiler has a problem with passing "it" directly to + // function "set_adjacency": the adjacency is not changed. + Cell_handle ch_it = it; + set_adjacency(cnew, 3, ch_it, 3); + cnew->set_neighbor(0, Cell_handle()); + new_cells.push_back(cnew); + } } // traversal of the new cells only, to add missing neighbors for(typename std::vector::iterator ncit = new_cells.begin(); ncit != new_cells.end(); ++ncit) { - Cell_handle n = (*ncit)->neighbor(3); // opposite to star - for ( int i=0; i<3; i++ ) { - int j; - if ( i==0 ) j=0; - else j=3-i; // vertex 1 and vertex 2 are always switched when - // creating a new cell (see above) + Cell_handle n = (*ncit)->neighbor(3); // opposite to star + for ( int i=0; i<3; i++ ) { + int j; + if ( i==0 ) j=0; + else j=3-i; // vertex 1 and vertex 2 are always switched when + // creating a new cell (see above) Cell_handle c = n->neighbor(i)->neighbor(3); - if ( c != Cell_handle() ) { - // i.e. star is not a vertex of n->neighbor(i) - (*ncit)->set_neighbor(j, c); - // opposite relation will be set when ncit arrives on c - // this avoids to look for the correct index - // and to test whether *ncit already has neighbor i - } - else { - // star is a vertex of n->neighbor(i) - set_adjacency(*ncit, j, n->neighbor(i), 3);//neighbor opposite to v - } - } + if ( c != Cell_handle() ) { + // i.e. star is not a vertex of n->neighbor(i) + (*ncit)->set_neighbor(j, c); + // opposite relation will be set when ncit arrives on c + // this avoids to look for the correct index + // and to test whether *ncit already has neighbor i + } + else { + // star is a vertex of n->neighbor(i) + set_adjacency(*ncit, j, n->neighbor(i), 3);//neighbor opposite to v + } + } } } }// end switch @@ -2639,21 +2905,21 @@ insert_increase_dimension(Vertex_handle star) return v; } -template +template void -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: remove_decrease_dimension(Vertex_handle v, Vertex_handle w) { CGAL_triangulation_expensive_precondition( is_valid() ); CGAL_triangulation_precondition( dimension() >= -1 ); CGAL_triangulation_precondition( dimension() != 1 || - number_of_vertices() == 3); + number_of_vertices() == 3); CGAL_triangulation_precondition( number_of_vertices() > - (size_type) dimension() + 1 ); + (size_type) dimension() + 1 ); CGAL_triangulation_precondition( degree(v) == number_of_vertices()-1 ); if (dimension() <= 0) { - delete_cell(v->cell()); + delete_cell(v->cell()); } else { // the cells incident to w are down graded one dimension @@ -2663,28 +2929,28 @@ remove_decrease_dimension(Vertex_handle v, Vertex_handle w) for (Cell_iterator ib = cells().begin(); ib != cells().end(); ++ib) { if ( ib->has_vertex(w) ) - to_downgrade.push_back(ib); + to_downgrade.push_back(ib); else - to_delete.push_back(ib); + to_delete.push_back(ib); } typename std::vector::iterator lfit=to_downgrade.begin(); for( ; lfit != to_downgrade.end(); ++lfit) { - Cell_handle f = *lfit; - int j = f->index(w); - int k; if (f->has_vertex(v, k)) f->set_vertex(k, w); + Cell_handle f = *lfit; + int j = f->index(w); + int k; if (f->has_vertex(v, k)) f->set_vertex(k, w); if (j != dimension()) { - f->set_vertex(j, f->vertex(dimension())); - f->set_neighbor(j, f->neighbor(dimension())); - if (dimension() >= 1) - change_orientation(f); - } - f->set_vertex(dimension(), Vertex_handle()); - f->set_neighbor(dimension(), Cell_handle()); + f->set_vertex(j, f->vertex(dimension())); + f->set_neighbor(j, f->neighbor(dimension())); + if (dimension() >= 1) + change_orientation(f); + } + f->set_vertex(dimension(), Vertex_handle()); + f->set_neighbor(dimension(), Cell_handle()); - // Update vertex->cell() pointers. - for (int i = 0; i < dimension(); ++i) - f->vertex(i)->set_cell(f); + // Update vertex->cell() pointers. + for (int i = 0; i < dimension(); ++i) + f->vertex(i)->set_cell(f); } delete_cells(to_delete.begin(), to_delete.end()); @@ -2694,33 +2960,33 @@ remove_decrease_dimension(Vertex_handle v, Vertex_handle w) CGAL_triangulation_postcondition(is_valid()); } -template -typename Triangulation_data_structure_3::Cell_handle -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::Cell_handle +Triangulation_data_structure_3:: remove_from_maximal_dimension_simplex(Vertex_handle v) { CGAL_triangulation_precondition(dimension() >= 1); CGAL_triangulation_precondition(degree(v) == (size_type) dimension() + 1); CGAL_triangulation_precondition(number_of_vertices() > - (size_type) dimension() + 1); + (size_type) dimension() + 1); if (number_of_vertices() == (size_type) dimension() + 2) { - remove_decrease_dimension(v); - return Cell_handle(); + remove_decrease_dimension(v); + return Cell_handle(); } if (dimension() == 3) - return remove_degree_4(v); + return remove_degree_4(v); if (dimension() == 2) - return remove_degree_3(v); + return remove_degree_3(v); // dimension() == 1 return remove_degree_2(v); } -template -typename Triangulation_data_structure_3::Cell_handle -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::Cell_handle +Triangulation_data_structure_3:: remove_degree_2(Vertex_handle v) { CGAL_triangulation_precondition(dimension() == 1); @@ -2740,7 +3006,7 @@ remove_degree_2(Vertex_handle v) // New cell : we copy the content of c0, so we keep the orientation. Cell_handle newc = create_face(c0->vertex(0), c0->vertex(1), - Vertex_handle()); + Vertex_handle()); newc->set_vertex(i0, c1->vertex(c1->index(c0))); @@ -2757,9 +3023,9 @@ remove_degree_2(Vertex_handle v) return newc; } -template -typename Triangulation_data_structure_3::Cell_handle -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::Cell_handle +Triangulation_data_structure_3:: remove_degree_3(Vertex_handle v) { CGAL_triangulation_precondition(dimension() == 2); @@ -2801,9 +3067,9 @@ remove_degree_3(Vertex_handle v) return newc; } -template -typename Triangulation_data_structure_3::Cell_handle -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::Cell_handle +Triangulation_data_structure_3:: remove_degree_4(Vertex_handle v) { CGAL_triangulation_precondition(dimension() == 3); @@ -2851,9 +3117,9 @@ remove_degree_4(Vertex_handle v) return newc; } -template +template void -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: decrease_dimension(Cell_handle c, int i) { CGAL_triangulation_expensive_precondition( is_valid() );; @@ -2910,13 +3176,13 @@ decrease_dimension(Cell_handle c, int i) Vertex_handle v0 = c->vertex(0); Vertex_handle v1 = c->vertex(1); Vertex_handle v2 = c->vertex(2); - + int i0 = 0, i1 = 0, i2 = 0; - + for(int i=0; i<3; i++) if(n0->neighbor(i) == c) { i0 = i; break; } for(int i=0; i<3; i++) if(n1->neighbor(i) == c) { i1 = i; break; } - for(int i=0; i<3; i++) if(n2->neighbor(i) == c) { i2 = i; break; } - + for(int i=0; i<3; i++) if(n2->neighbor(i) == c) { i2 = i; break; } + Cell_handle c1 = create_cell(v, v0, v1, Vertex_handle()); Cell_handle c2 = create_cell(v, v1, v2, Vertex_handle()); @@ -2925,74 +3191,74 @@ decrease_dimension(Cell_handle c, int i) c->set_vertex(2, v0); c->set_vertex(3, Vertex_handle()); - //Cell_handle c3 = create_cell(v, v2, v0, Vertex_handle()); + //Cell_handle c3 = create_cell(v, v2, v0, Vertex_handle()); Cell_handle c3 = c; - + c1->set_neighbor(0, n2); n2->set_neighbor(i2, c1); c1->set_neighbor(1, c2); c1->set_neighbor(2, c3); c1->set_neighbor(3, Cell_handle()); - + c2->set_neighbor(0, n0); n0->set_neighbor(i0, c2); c2->set_neighbor(1, c3); c2->set_neighbor(2, c1); - c2->set_neighbor(3, Cell_handle()); - + c2->set_neighbor(3, Cell_handle()); + c3->set_neighbor(0, n1); n1->set_neighbor(i1, c3); c3->set_neighbor(1, c1); c3->set_neighbor(2, c2); c3->set_neighbor(3, Cell_handle()); - + v->set_cell(c1); v0->set_cell(c1); v1->set_cell(c1); - v2->set_cell(c2); + v2->set_cell(c2); } - + if(dimension() == 1) { Cell_handle n0 = c->neighbor(0); Cell_handle n1 = c->neighbor(1); Vertex_handle v0 = c->vertex(0); Vertex_handle v1 = c->vertex(1); - + int i0 = 0 , i1 = 0; - + for(int i=0; i<2; i++) if(n0->neighbor(i) == c) { i0 = i; break; } for(int i=0; i<2; i++) if(n1->neighbor(i) == c) { i1 = i; break; } - + Cell_handle c1 = create_cell(v0, v, Vertex_handle(), Vertex_handle()); - + c->set_vertex(0, v); c->set_vertex(1, v1); c->set_vertex(2, Vertex_handle()); c->set_vertex(3, Vertex_handle()); - //Cell_handle c2 = create_cell(v, v1, Vertex_handle(), Vertex_handle()); + //Cell_handle c2 = create_cell(v, v1, Vertex_handle(), Vertex_handle()); Cell_handle c2 = c; - + c1->set_neighbor(0, c2); c1->set_neighbor(1, n1); n1->set_neighbor(i1, c1); c1->set_neighbor(2, Cell_handle()); c1->set_neighbor(3, Cell_handle()); - + c2->set_neighbor(0, n0); n0->set_neighbor(i0, c2); c2->set_neighbor(1, c1); c2->set_neighbor(2, Cell_handle()); c2->set_neighbor(3, Cell_handle()); - + v->set_cell(c1); v0->set_cell(c1); v1->set_cell(c2); } - + CGAL_triangulation_postcondition(is_valid()); } -template -typename Triangulation_data_structure_3::size_type -Triangulation_data_structure_3:: +template +typename Triangulation_data_structure_3::size_type +Triangulation_data_structure_3:: degree(Vertex_handle v) const { std::size_t res; @@ -3000,30 +3266,30 @@ degree(Vertex_handle v) const return res; } -template +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_valid(bool verbose, int level ) const { switch ( dimension() ) { case 3: { - + if(number_of_vertices() <= 4) { if (verbose) std::cerr << "wrong number of vertices" << std::endl; CGAL_triangulation_assertion(false); return false; } - + size_type vertex_count; if ( ! count_vertices(vertex_count,verbose,level) ) return false; if ( number_of_vertices() != vertex_count ) { - if (verbose) + if (verbose) std::cerr << "wrong number of vertices" << std::endl; - CGAL_triangulation_assertion(false); - return false; + CGAL_triangulation_assertion(false); + return false; } size_type cell_count; @@ -3031,125 +3297,125 @@ is_valid(bool verbose, int level ) const return false; size_type edge_count; if ( ! count_edges(edge_count,verbose,level) ) - return false; + return false; size_type facet_count; if ( ! count_facets(facet_count,verbose,level) ) - return false; + return false; // Euler relation if ( cell_count - facet_count + edge_count - vertex_count != 0 ) { - if (verbose) - std::cerr << "Euler relation unsatisfied" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "Euler relation unsatisfied" << std::endl; + CGAL_triangulation_assertion(false); + return false; } break; } case 2: { - + if(number_of_vertices() <= 3) { if (verbose) std::cerr << "wrong number of vertices" << std::endl; CGAL_triangulation_assertion(false); return false; } - + size_type vertex_count; if ( ! count_vertices(vertex_count,verbose,level) ) return false; if ( number_of_vertices() != vertex_count ) { - if (verbose) - std::cerr << "false number of vertices" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "false number of vertices" << std::endl; + CGAL_triangulation_assertion(false); + return false; } size_type edge_count; if ( ! count_edges(edge_count,verbose,level) ) - return false; + return false; // Euler for edges if ( edge_count != 3 * vertex_count - 6 ) { - if (verbose) - std::cerr << "Euler relation unsatisfied - edges/vertices" - << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "Euler relation unsatisfied - edges/vertices" + << std::endl; + CGAL_triangulation_assertion(false); + return false; } size_type facet_count; if ( ! count_facets(facet_count,verbose,level) ) - return false; + return false; // Euler for facets if ( facet_count != 2 * vertex_count - 4 ) { - if (verbose) - std::cerr << "Euler relation unsatisfied - facets/vertices" - << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "Euler relation unsatisfied - facets/vertices" + << std::endl; + CGAL_triangulation_assertion(false); + return false; } break; } case 1: { - + if(number_of_vertices() <= 1) { if (verbose) std::cerr << "wrong number of vertices" << std::endl; CGAL_triangulation_assertion(false); return false; } - + size_type vertex_count; if ( ! count_vertices(vertex_count,verbose,level) ) - return false; + return false; if ( number_of_vertices() != vertex_count ) { - if (verbose) - std::cerr << "false number of vertices" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "false number of vertices" << std::endl; + CGAL_triangulation_assertion(false); + return false; } size_type edge_count; if ( ! count_edges(edge_count,verbose,level) ) - return false; + return false; // Euler for edges if ( edge_count != vertex_count ) { - if (verbose) - std::cerr << "false number of edges" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "false number of edges" << std::endl; + CGAL_triangulation_assertion(false); + return false; } break; } case 0: { if ( number_of_vertices() < 2 ) { - if (verbose) - std::cerr << "less than 2 vertices but dimension 0" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "less than 2 vertices but dimension 0" << std::endl; + CGAL_triangulation_assertion(false); + return false; } // no break; continue } case -1: { if ( number_of_vertices() < 1 ) { - if (verbose) - std::cerr << "no vertex but dimension -1" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "no vertex but dimension -1" << std::endl; + CGAL_triangulation_assertion(false); + return false; } // vertex count size_type vertex_count; if ( ! count_vertices(vertex_count,verbose,level) ) - return false; + return false; if ( number_of_vertices() != vertex_count ) { - if (verbose) - std::cerr << "false number of vertices" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "false number of vertices" << std::endl; + CGAL_triangulation_assertion(false); + return false; } } } // end switch @@ -3158,9 +3424,9 @@ is_valid(bool verbose, int level ) const return true; } -template +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_valid(Vertex_handle v, bool verbose, int level) const { bool result = v->is_valid(verbose,level); @@ -3173,38 +3439,38 @@ is_valid(Vertex_handle v, bool verbose, int level) const return result; } -template +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: is_valid(Cell_handle c, bool verbose, int level) const { if ( ! c->is_valid(verbose, level) ) - return false; + return false; switch (dimension()) { case -2: case -1: { if ( c->vertex(0) == Vertex_handle() ) { - if (verbose) - std::cerr << "vertex 0 NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "vertex 0 NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; } is_valid(c->vertex(0),verbose,level); if ( c->vertex(1) != Vertex_handle() || c->vertex(2) != Vertex_handle()) { - if (verbose) - std::cerr << "vertex 1 or 2 != NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "vertex 1 or 2 != NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; } if ( c->neighbor(0) != Cell_handle() || - c->neighbor(1) != Cell_handle() || - c->neighbor(2) != Cell_handle()) { - if (verbose) - std::cerr << "one neighbor != NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; + c->neighbor(1) != Cell_handle() || + c->neighbor(2) != Cell_handle()) { + if (verbose) + std::cerr << "one neighbor != NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; } break; } @@ -3212,38 +3478,38 @@ is_valid(Cell_handle c, bool verbose, int level) const case 0: { if ( c->vertex(0) == Vertex_handle() ) { - if (verbose) - std::cerr << "vertex 0 NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "vertex 0 NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; } is_valid(c->vertex(0),verbose,level); if ( c->neighbor (0) == Cell_handle() ) { - if (verbose) - std::cerr << "neighbor 0 NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "neighbor 0 NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; } if ( c->vertex(1) != Vertex_handle() || c->vertex(2) != Vertex_handle() ) { - if (verbose) - std::cerr << "vertex 1 or 2 != NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "vertex 1 or 2 != NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; } if ( c->neighbor(1) != Cell_handle() || c->neighbor(2) != Cell_handle() ) { - if (verbose) - std::cerr << "neighbor 1 or 2 != NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "neighbor 1 or 2 != NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; } if ( ! c->neighbor(0)->has_vertex(c->vertex(0)) ) { - if (verbose) - std::cerr << "neighbor 0 does not have vertex 0" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "neighbor 0 does not have vertex 0" << std::endl; + CGAL_triangulation_assertion(false); + return false; } break; } @@ -3256,48 +3522,48 @@ is_valid(Cell_handle c, bool verbose, int level) const Cell_handle n1 = c->neighbor(1); if ( v0 == Vertex_handle() || v1 == Vertex_handle() ) { - if (verbose) - std::cerr << "vertex 0 or 1 NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "vertex 0 or 1 NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; } is_valid(c->vertex(0),verbose,level); is_valid(c->vertex(1),verbose,level); if ( n0 == Cell_handle() || n1 == Cell_handle() ) { - if (verbose) - std::cerr << "neighbor 0 or 1 NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "neighbor 0 or 1 NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; } if ( v0 != n1->vertex(1) ) { - if (verbose) - std::cerr << "neighbor 1 does not have vertex 0 as vertex 1" - << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "neighbor 1 does not have vertex 0 as vertex 1" + << std::endl; + CGAL_triangulation_assertion(false); + return false; } if ( v1 != n0->vertex(0) ) { - if (verbose) - std::cerr << "neighbor 0 does not have vertex 1 as vertex 0" - << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "neighbor 0 does not have vertex 1 as vertex 0" + << std::endl; + CGAL_triangulation_assertion(false); + return false; } if ( n0->neighbor(1) != c ) { - if (verbose) - std::cerr << "neighbor 0 does not have this as neighbor 1" - << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "neighbor 0 does not have this as neighbor 1" + << std::endl; + CGAL_triangulation_assertion(false); + return false; } if ( n1->neighbor(0) != c ) { - if (verbose) - std::cerr << "neighbor 1 does not have this as neighbor 0" - << std::endl; - CGAL_triangulation_assertion(false); - return false; + if (verbose) + std::cerr << "neighbor 1 does not have this as neighbor 0" + << std::endl; + CGAL_triangulation_assertion(false); + return false; } break; @@ -3306,12 +3572,12 @@ is_valid(Cell_handle c, bool verbose, int level) const case 2: { if ( c->vertex(0) == Vertex_handle() || - c->vertex(1) == Vertex_handle() || - c->vertex(2) == Vertex_handle() ) { - if (verbose) - std::cerr << "vertex 0, 1, or 2 NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; + c->vertex(1) == Vertex_handle() || + c->vertex(2) == Vertex_handle() ) { + if (verbose) + std::cerr << "vertex 0, 1, or 2 NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; } is_valid(c->vertex(0),verbose,level); is_valid(c->vertex(1),verbose,level); @@ -3319,181 +3585,182 @@ is_valid(Cell_handle c, bool verbose, int level) const int in; Cell_handle n; for(int i = 0; i < 3; i++) { - n = c->neighbor(i); - if ( n == Cell_handle() ) { - if (verbose) - std::cerr << "neighbor " << i << " NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - if ( ! n->has_vertex(c->vertex(cw(i)),in ) ) { - if (verbose) - std::cerr << "vertex " << cw(i) - << " not vertex of neighbor " << i << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - in = cw(in); - if ( n->neighbor(in) != c ) { - if (verbose) - std::cerr << "neighbor " << i - << " does not have this as neighbor " - << in << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - if ( c->vertex(ccw(i)) != n->vertex(cw(in)) ) { - if (verbose) - std::cerr << "vertex " << ccw(i) - << " is not vertex " << cw(in) - << " of neighbor " << i << std::endl; - CGAL_triangulation_assertion(false); - return false; - } + n = c->neighbor(i); + if ( n == Cell_handle() ) { + if (verbose) + std::cerr << "neighbor " << i << " NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + if ( ! n->has_vertex(c->vertex(cw(i)),in ) ) { + if (verbose) + std::cerr << "vertex " << cw(i) + << " not vertex of neighbor " << i << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + in = cw(in); + if ( n->neighbor(in) != c ) { + if (verbose) + std::cerr << "neighbor " << i + << " does not have this as neighbor " + << in << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + if ( c->vertex(ccw(i)) != n->vertex(cw(in)) ) { + if (verbose) + std::cerr << "vertex " << ccw(i) + << " is not vertex " << cw(in) + << " of neighbor " << i << std::endl; + CGAL_triangulation_assertion(false); + return false; + } } break; } case 3: { - int i; - for(i = 0; i < 4; i++) { - if ( c->vertex(i) == Vertex_handle() ) { - if (verbose) - std::cerr << "vertex " << i << " NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - is_valid(c->vertex(i),verbose,level); - } + int i; + for(i = 0; i < 4; i++) { + if ( c->vertex(i) == Vertex_handle() ) { + if (verbose) + std::cerr << "vertex " << i << " NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; + } + is_valid(c->vertex(i),verbose,level); + } - for(i = 0; i < 4; i++) { - Cell_handle n = c->neighbor(i); - if ( n == Cell_handle() ) { - if (verbose) - std::cerr << "neighbor " << i << " NULL" << std::endl; - CGAL_triangulation_assertion(false); - return false; - } + for(i = 0; i < 4; i++) { + Cell_handle n = c->neighbor(i); + if ( n == Cell_handle() ) { + if (verbose) + std::cerr << "neighbor " << i << " NULL" << std::endl; + CGAL_triangulation_assertion(false); + return false; + } - int in = 5; - // if ( ! n->has_neighbor(handle(), in) ) { + int in = 5; + // if ( ! n->has_neighbor(handle(), in) ) { if ( n->neighbor(0) == c) in = 0; if ( n->neighbor(1) == c) in = 1; if ( n->neighbor(2) == c) in = 2; if ( n->neighbor(3) == c) in = 3; if (in == 5) { - if (verbose) + if (verbose) std::cerr << "neighbor of c has not c as neighbor" << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - - int j1n,j2n,j3n; - if ( ! n->has_vertex(c->vertex((i+1)&3),j1n) ) { - if (verbose) { std::cerr << "vertex " << ((i+1)&3) - << " not vertex of neighbor " - << i << std::endl; } - CGAL_triangulation_assertion(false); - return false; - } - if ( ! n->has_vertex(c->vertex((i+2)&3),j2n) ) { - if (verbose) { std::cerr << "vertex " << ((i+2)&3) - << " not vertex of neighbor " - << i << std::endl; } - CGAL_triangulation_assertion(false); - return false; - } - if ( ! n->has_vertex(c->vertex((i+3)&3),j3n) ) { - if (verbose) { std::cerr << "vertex " << ((i+3)&3) - << " not vertex of neighbor " - << i << std::endl; } - CGAL_triangulation_assertion(false); - return false; - } - - if ( in+j1n+j2n+j3n != 6) { - if (verbose) { std::cerr << "sum of the indices != 6 " - << std::endl; } - CGAL_triangulation_assertion(false); - return false; - } - - // tests whether the orientations of this and n are consistent - if ( ((i+in)&1) == 0 ) { // i and in have the same parity - if ( j1n == ((in+1)&3) ) { - if ( ( j2n != ((in+3)&3) ) || ( j3n != ((in+2)&3) ) ) { - if (verbose) + CGAL_triangulation_assertion(false); + return false; + } + + int j1n,j2n,j3n; + if ( ! n->has_vertex(c->vertex((i+1)&3),j1n) ) { + if (verbose) { std::cerr << "vertex " << ((i+1)&3) + << " not vertex of neighbor " + << i << std::endl; } + CGAL_triangulation_assertion(false); + return false; + } + if ( ! n->has_vertex(c->vertex((i+2)&3),j2n) ) { + if (verbose) { std::cerr << "vertex " << ((i+2)&3) + << " not vertex of neighbor " + << i << std::endl; } + CGAL_triangulation_assertion(false); + return false; + } + if ( ! n->has_vertex(c->vertex((i+3)&3),j3n) ) { + if (verbose) { std::cerr << "vertex " << ((i+3)&3) + << " not vertex of neighbor " + << i << std::endl; } + CGAL_triangulation_assertion(false); + return false; + } + + if ( in+j1n+j2n+j3n != 6) { + if (verbose) { std::cerr << "sum of the indices != 6 " + << std::endl; } + CGAL_triangulation_assertion(false); + return false; + } + + // tests whether the orientations of this and n are consistent + if ( ((i+in)&1) == 0 ) { // i and in have the same parity + if ( j1n == ((in+1)&3) ) { + if ( ( j2n != ((in+3)&3) ) || ( j3n != ((in+2)&3) ) ) { + if (verbose) std::cerr << " pb orientation with neighbor " << i << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } - if ( j1n == ((in+2)&3) ) { - if ( ( j2n != ((in+1)&3) ) || ( j3n != ((in+3)&3) ) ) { - if (verbose) + CGAL_triangulation_assertion(false); + return false; + } + } + if ( j1n == ((in+2)&3) ) { + if ( ( j2n != ((in+1)&3) ) || ( j3n != ((in+3)&3) ) ) { + if (verbose) std::cerr << " pb orientation with neighbor " << i << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } - if ( j1n == ((in+3)&3) ) { - if ( ( j2n != ((in+2)&3) ) || ( j3n != ((in+1)&3) ) ) { - if (verbose) + CGAL_triangulation_assertion(false); + return false; + } + } + if ( j1n == ((in+3)&3) ) { + if ( ( j2n != ((in+2)&3) ) || ( j3n != ((in+1)&3) ) ) { + if (verbose) std::cerr << " pb orientation with neighbor " << i << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } - } - else { // i and in do not have the same parity - if ( j1n == ((in+1)&3) ) { - if ( ( j2n != ((in+2)&3) ) || ( j3n != ((in+3)&3) ) ) { - if (verbose) + CGAL_triangulation_assertion(false); + return false; + } + } + } + else { // i and in do not have the same parity + if ( j1n == ((in+1)&3) ) { + if ( ( j2n != ((in+2)&3) ) || ( j3n != ((in+3)&3) ) ) { + if (verbose) std::cerr << " pb orientation with neighbor " << i << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } - if ( j1n == ((in+2)&3) ) { - if ( ( j2n != ((in+3)&3) ) || ( j3n != ((in+1)&3) ) ) { - if (verbose) + CGAL_triangulation_assertion(false); + return false; + } + } + if ( j1n == ((in+2)&3) ) { + if ( ( j2n != ((in+3)&3) ) || ( j3n != ((in+1)&3) ) ) { + if (verbose) std::cerr << " pb orientation with neighbor " << i << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } - if ( j1n == ((in+3)&3) ) { - if ( ( j2n != ((in+1)&3) ) || ( j3n != ((in+2)&3) ) ) { - if (verbose) + CGAL_triangulation_assertion(false); + return false; + } + } + if ( j1n == ((in+3)&3) ) { + if ( ( j2n != ((in+1)&3) ) || ( j3n != ((in+2)&3) ) ) { + if (verbose) std::cerr << " pb orientation with neighbor " << i << std::endl; - CGAL_triangulation_assertion(false); - return false; - } - } - } - } // end looking at neighbors + CGAL_triangulation_assertion(false); + return false; + } + } + } + } // end looking at neighbors }// end case dim 3 } // end switch return true; } -template + +template template -typename Triangulation_data_structure_3::Vertex_handle -Triangulation_data_structure_3:: +typename Triangulation_data_structure_3::Vertex_handle +Triangulation_data_structure_3:: copy_tds(const TDS_src& tds, typename TDS_src::Vertex_handle vert, const ConvertVertex& convert_vertex, const ConvertCell& convert_cell) { CGAL_triangulation_expensive_precondition( vert == Vertex_handle() - || tds.is_vertex(vert) ); + || tds.is_vertex(vert) ); clear(); @@ -3526,7 +3793,7 @@ copy_tds(const TDS_src& tds, // Create the cells. for (typename TDS_src::Cell_iterator cit = tds.cells().begin(); - cit != tds.cells_end(); ++cit) { + cit != tds.cells_end(); ++cit) { Cell_handle ch=create_cell(convert_cell(*cit)); F[cit]=ch; for (int j = 0; j < dim; j++) @@ -3541,7 +3808,7 @@ copy_tds(const TDS_src& tds, // Hook neighbor pointers of the cells. for (typename TDS_src::Cell_iterator cit2 = tds.cells().begin(); - cit2 != tds.cells_end(); ++cit2) { + cit2 != tds.cells_end(); ++cit2) { for (int j = 0; j < dim; j++) F[cit2]->set_neighbor(j, F[cit2->neighbor(j)] ); } @@ -3593,10 +3860,10 @@ namespace internal { namespace TDS_3{ }; } } //namespace internal::TDS_3 -template +template template -typename Triangulation_data_structure_3::Vertex_handle -Triangulation_data_structure_3:: +typename Triangulation_data_structure_3::Vertex_handle +Triangulation_data_structure_3:: copy_tds(const TDS_src& src,typename TDS_src::Vertex_handle vert) { internal::TDS_3::Default_vertex_converter setv; @@ -3604,9 +3871,9 @@ copy_tds(const TDS_src& src,typename TDS_src::Vertex_handle vert) return copy_tds(src,vert,setv,setc); } -template +template void -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: swap(Tds & tds) { CGAL_triangulation_expensive_precondition(tds.is_valid() && is_valid()); @@ -3616,9 +3883,9 @@ swap(Tds & tds) vertices().swap(tds.vertices()); } -template +template void -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: clear() { cells().clear(); @@ -3626,9 +3893,9 @@ clear() set_dimension(-2); } -template +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: count_vertices(size_type & i, bool verbose, int level) const // counts AND checks the validity { @@ -3637,7 +3904,7 @@ count_vertices(size_type & i, bool verbose, int level) const for (Vertex_iterator it = vertices_begin(); it != vertices_end(); ++it) { if ( ! is_valid(it,verbose,level) ) { if (verbose) - std::cerr << "invalid vertex" << std::endl; + std::cerr << "invalid vertex" << std::endl; CGAL_triangulation_assertion(false); return false; } @@ -3646,9 +3913,9 @@ count_vertices(size_type & i, bool verbose, int level) const return true; } -template +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: count_facets(size_type & i, bool verbose, int level) const // counts but does not check { @@ -3657,7 +3924,7 @@ count_facets(size_type & i, bool verbose, int level) const for (Facet_iterator it = facets_begin(); it != facets_end(); ++it) { if ( ! is_valid((*it).first,verbose, level) ) { if (verbose) - std::cerr << "invalid facet" << std::endl; + std::cerr << "invalid facet" << std::endl; CGAL_triangulation_assertion(false); return false; } @@ -3666,9 +3933,9 @@ count_facets(size_type & i, bool verbose, int level) const return true; } -template +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: count_edges(size_type & i, bool verbose, int level) const // counts but does not check { @@ -3677,7 +3944,7 @@ count_edges(size_type & i, bool verbose, int level) const for (Edge_iterator it = edges_begin(); it != edges_end(); ++it) { if ( ! is_valid((*it).first,verbose, level) ) { if (verbose) - std::cerr << "invalid edge" << std::endl; + std::cerr << "invalid edge" << std::endl; CGAL_triangulation_assertion(false); return false; } @@ -3686,9 +3953,9 @@ count_edges(size_type & i, bool verbose, int level) const return true; } -template +template bool -Triangulation_data_structure_3:: +Triangulation_data_structure_3:: count_cells(size_type & i, bool verbose, int level) const // counts AND checks the validity { @@ -3697,7 +3964,7 @@ count_cells(size_type & i, bool verbose, int level) const for (Cell_iterator it = cells_begin(); it != cells_end(); ++it) { if ( ! is_valid(it,verbose, level) ) { if (verbose) - std::cerr << "invalid cell" << std::endl; + std::cerr << "invalid cell" << std::endl; CGAL_triangulation_assertion(false); return false; } diff --git a/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h b/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h index 0c59e0eab57..cce0eaf173c 100644 --- a/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h @@ -33,24 +33,42 @@ template < typename TDS = void > class Triangulation_ds_cell_base_3 { public: - typedef TDS Triangulation_data_structure; - typedef typename TDS::Vertex_handle Vertex_handle; - typedef typename TDS::Cell_handle Cell_handle; - typedef typename TDS::Vertex Vertex; - typedef typename TDS::Cell Cell; - typedef typename TDS::Cell_data TDS_data; + typedef TDS Triangulation_data_structure; + typedef typename TDS::Vertex_handle Vertex_handle; + typedef typename TDS::Cell_handle Cell_handle; + typedef typename TDS::Vertex Vertex; + typedef typename TDS::Cell Cell; + typedef typename TDS::Cell_data TDS_data; template struct Rebind_TDS { typedef Triangulation_ds_cell_base_3 Other; }; - Triangulation_ds_cell_base_3() {} + Triangulation_ds_cell_base_3() + { +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + mark = -1; + mark2 = -1; +#endif + } Triangulation_ds_cell_base_3(Vertex_handle v0, Vertex_handle v1, Vertex_handle v2, Vertex_handle v3) #ifndef CGAL_CFG_NO_CPP0X_UNIFIED_INITIALIZATION_SYNTAX - : V{v0, v1, v2, v3} {} + : V{v0, v1, v2, v3} + { +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + mark = -1; + mark2 = -1; +#endif + } #else - { set_vertices(v0, v1, v2, v3); } + { + set_vertices(v0, v1, v2, v3); +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + mark = -1; + mark2 = -1; +#endif + } #endif Triangulation_ds_cell_base_3(Vertex_handle v0, Vertex_handle v1, @@ -63,6 +81,10 @@ public: { set_neighbors(n0, n1, n2, n3); set_vertices(v0, v1, v2, v3); +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + mark = -1; + mark2 = -1; +#endif } #endif @@ -201,6 +223,11 @@ public: // TDS internal data access functions. TDS_data& tds_data() { return _tds_data; } const TDS_data& tds_data() const { return _tds_data; } + +#ifdef SHOW_REMAINING_BAD_ELEMENT_IN_RED + int mark; + int mark2; +#endif private: diff --git a/Triangulation_3/include/CGAL/Triangulation_ds_vertex_base_3.h b/Triangulation_3/include/CGAL/Triangulation_ds_vertex_base_3.h index b60eb717c14..e2f238ba4f6 100644 --- a/Triangulation_3/include/CGAL/Triangulation_ds_vertex_base_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_ds_vertex_base_3.h @@ -36,6 +36,7 @@ public: template struct Rebind_TDS { typedef Triangulation_ds_vertex_base_3 Other; }; + Triangulation_ds_vertex_base_3() : _c(), visited_for_vertex_extractor(false) {} @@ -44,11 +45,13 @@ public: : _c(c), visited_for_vertex_extractor(false) {} - Cell_handle cell() const - { return _c; } + Cell_handle cell() const + { return _c; } void set_cell(Cell_handle c) - { _c = c; } + { + _c = c; + } // the following trivial is_valid allows // the user of derived cell base classes diff --git a/Triangulation_3/include/CGAL/internal/Dummy_tds_3.h b/Triangulation_3/include/CGAL/internal/Dummy_tds_3.h index 28e76a03815..01129937777 100644 --- a/Triangulation_3/include/CGAL/internal/Dummy_tds_3.h +++ b/Triangulation_3/include/CGAL/internal/Dummy_tds_3.h @@ -25,6 +25,8 @@ namespace CGAL { namespace internal { // Dummy TDS which provides all types that a vertex_base or cell_base can use. struct Dummy_tds_3 { + struct Concurrency_tag {}; + struct Vertex {}; struct Cell {}; struct Facet {}; diff --git a/Triangulation_3/test/Triangulation_3/CMakeLists.txt b/Triangulation_3/test/Triangulation_3/CMakeLists.txt new file mode 100644 index 00000000000..81584049232 --- /dev/null +++ b/Triangulation_3/test/Triangulation_3/CMakeLists.txt @@ -0,0 +1,53 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + + +project( Triangulation_3_test ) + +cmake_minimum_required(VERSION 2.6.2) +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6) + if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3) + cmake_policy(VERSION 2.8.4) + else() + cmake_policy(VERSION 2.6) + endif() +endif() + +find_package(CGAL QUIET COMPONENTS Core ) + +if ( CGAL_FOUND ) + + include( ${CGAL_USE_FILE} ) + + find_package( TBB QUIET ) + + if( TBB_FOUND ) + include(${TBB_USE_FILE}) + list(APPEND CGAL_3RD_PARTY_LIBRARIES ${TBB_LIBRARIES}) + endif() + + include( CGAL_CreateSingleSourceCGALProgram ) + + include_directories (BEFORE "../../include") + + include_directories (BEFORE "include") + + create_single_source_cgal_program( "test_delaunay_3.cpp" ) + create_single_source_cgal_program( "test_delaunay_hierarchy_3.cpp" ) + create_single_source_cgal_program( "test_delaunay_hierarchy_3_old.cpp" ) + create_single_source_cgal_program( "test_regular_3.cpp" ) + create_single_source_cgal_program( "test_regular_as_delaunay_3.cpp" ) + create_single_source_cgal_program( "test_regular_insert_range_with_info.cpp" ) + create_single_source_cgal_program( "test_regular_remove_3.cpp" ) + create_single_source_cgal_program( "test_regular_traits_3.cpp" ) + create_single_source_cgal_program( "test_simplex_3.cpp" ) + create_single_source_cgal_program( "test_static_filters.cpp" ) + create_single_source_cgal_program( "test_triangulation_3.cpp" ) + create_single_source_cgal_program( "test_triangulation_tds_3.cpp" ) + +else() + + message(STATUS "This program requires the CGAL library, and will not be compiled.") + +endif() + diff --git a/Triangulation_3/test/Triangulation_3/include/CGAL/_test_cls_parallel_triangulation_3.h b/Triangulation_3/test/Triangulation_3/include/CGAL/_test_cls_parallel_triangulation_3.h new file mode 100644 index 00000000000..149b98bd701 --- /dev/null +++ b/Triangulation_3/test/Triangulation_3/include/CGAL/_test_cls_parallel_triangulation_3.h @@ -0,0 +1,69 @@ +// Copyright (c) 2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s) : Clement Jamin + +#include + +#include +#include +#include + +#include + +template +void +_test_cls_parallel_triangulation_3(const Parallel_triangulation &) +{ + typedef Parallel_triangulation Cls; + typedef typename Cls::Vertex_handle Vertex_handle; + typedef typename boost::mpl::if_::type::Point + Point; + + CGAL::Random_points_in_cube_3 rnd(1.); + + // Construction from a vector of 1,000,000 points + std::vector points; + points.reserve(1000000); + for (int i = 0; i != 1000000; ++i) + points.push_back(*rnd++); + + // Construct the locking data-structure, using the bounding-box of the points + typename Cls::Lock_data_structure locking_ds( + CGAL::Bbox_3(-1., -1., -1., 1., 1., 1.), 50); + // Contruct the triangulation in parallel + std::cout << "Construction and parallel insertion" << std::endl; + Cls tr(points.begin(), points.end(), &locking_ds); + + std::cout << "Parallel removal" << std::endl; + // Remove the first 100,000 vertices + std::vector vertices_to_remove; + int i = 0; + typename Cls::Finite_vertices_iterator vit = tr.finite_vertices_begin(); + for (int i = 0 ; i < 100000 ; ++i) + vertices_to_remove.push_back(vit++); + // Parallel remove + tr.remove(vertices_to_remove.begin(), vertices_to_remove.end()); + + assert(tr.is_valid()); + tr.clear(); + assert(tr.is_valid()); + assert(tr.dimension()==-1); + assert(tr.number_of_vertices()==0); +} diff --git a/Triangulation_3/test/Triangulation_3/test_delaunay_3.cpp b/Triangulation_3/test/Triangulation_3/test_delaunay_3.cpp index e092d8ac757..b047ff638c1 100644 --- a/Triangulation_3/test/Triangulation_3/test_delaunay_3.cpp +++ b/Triangulation_3/test/Triangulation_3/test_delaunay_3.cpp @@ -27,6 +27,7 @@ bool del=true; #include #include +#include // Explicit instantiation of the whole class : template class CGAL::Delaunay_triangulation_3; @@ -35,9 +36,25 @@ int main() { typedef CGAL::Delaunay_triangulation_3 Cls; typedef CGAL::Delaunay_triangulation_3 Cls_with_epec; - + _test_cls_delaunay_3( Cls() ); _test_cls_delaunay_3( Cls_with_epec() ); + +#ifdef CGAL_LINKED_WITH_TBB + typedef CGAL::Spatial_lock_grid_3< + CGAL::Tag_priority_blocking> Lock_ds; + typedef CGAL::Triangulation_data_structure_3< + CGAL::Triangulation_vertex_base_3, + CGAL::Triangulation_cell_base_3, + CGAL::Parallel_tag > Tds_parallel; + typedef CGAL::Delaunay_triangulation_3< + EPIC, Tds_parallel, CGAL::Default, Lock_ds> Cls_parallel; + // The following test won't do things in parallel since it doesn't provide + // a lock data structure + _test_cls_delaunay_3( Cls_parallel() ); + // This test performs parallel operations + _test_cls_parallel_triangulation_3( Cls_parallel() ); +#endif // Second version for the circumcenter storing cell base class. typedef CGAL::Triangulation_vertex_base_3 Vb; diff --git a/Triangulation_3/test/Triangulation_3/test_regular_3.cpp b/Triangulation_3/test/Triangulation_3/test_regular_3.cpp index b47331d67db..274a6a53609 100644 --- a/Triangulation_3/test/Triangulation_3/test_regular_3.cpp +++ b/Triangulation_3/test/Triangulation_3/test_regular_3.cpp @@ -28,6 +28,7 @@ #include #include +#include bool del=true; @@ -37,24 +38,22 @@ typedef CGAL::Regular_triangulation_euclidean_traits_3 traits; // Explicit instantiation of the whole class : template class CGAL::Regular_triangulation_3; -int main() +template +void test_RT() { - std::cout << " with CGAL::Regular_triangulation_euclidean_traits_3: " - << std::endl; - - typedef CGAL::Regular_triangulation_3 Cls; + typedef RT Cls; // _test_cls_regular_3( Cls() ); typedef traits::Bare_point Point; typedef traits::Weighted_point Weighted_point; - typedef Cls::Vertex_handle Vertex_handle; - typedef Cls::Cell_handle Cell_handle; - typedef Cls::Facet Facet; - typedef Cls::Edge Edge; + typedef typename Cls::Vertex_handle Vertex_handle; + typedef typename Cls::Cell_handle Cell_handle; + typedef typename Cls::Facet Facet; + typedef typename Cls::Edge Edge; typedef std::list list_point; - typedef Cls::Finite_cells_iterator Finite_cells_iterator; + typedef typename Cls::Finite_cells_iterator Finite_cells_iterator; // temporary version @@ -94,7 +93,7 @@ int main() } assert( T1.is_valid() ); std::cout << std::endl << " number of vertices : " - << T1.number_of_vertices() << std::endl; + << T1.number_of_vertices() << std::endl; std::cout << " number of inserted points : " ; Weighted_point q[5]; @@ -109,14 +108,14 @@ int main() std::cout << count << '\b' ; else if (count < 100) - std::cout << count << '\b' << '\b' ; + std::cout << count << '\b' << '\b' ; else - std::cout << count << '\b' << '\b' << '\b' ; + std::cout << count << '\b' << '\b' << '\b' ; std::cout.flush(); } assert( T1.is_valid() ); std::cout << std::endl << " number of vertices : " - << T1.number_of_vertices() << std::endl; + << T1.number_of_vertices() << std::endl; std::cout << " number of inserted points : " ; Weighted_point r[10]; @@ -131,14 +130,14 @@ int main() std::cout << count << '\b' ; else if (count < 100) - std::cout << count << '\b' << '\b' ; + std::cout << count << '\b' << '\b' ; else - std::cout << count << '\b' << '\b' << '\b' ; + std::cout << count << '\b' << '\b' << '\b' ; std::cout.flush(); } assert( T1.is_valid() ); std::cout << std::endl << " number of vertices : " - << T1.number_of_vertices() << std::endl; + << T1.number_of_vertices() << std::endl; assert( T1.dimension()==1 ); // The following is distilled from a bug report by Wulue Zhao @@ -225,12 +224,12 @@ int main() T2.insert( s[m+20*n] ); count++; if (count <10) - std::cout << count << '\b' ; + std::cout << count << '\b' ; else - if (count < 100) - std::cout << count << '\b' << '\b' ; - else - std::cout << count << '\b' << '\b' << '\b' ; + if (count < 100) + std::cout << count << '\b' << '\b' ; + else + std::cout << count << '\b' << '\b' << '\b' ; std::cout.flush(); } for (m=10; m<20; m++) @@ -239,12 +238,12 @@ int main() T2.insert( s[m+20*n] ); count++; if (count <10) - std::cout << count << '\b' ; + std::cout << count << '\b' ; else - if (count < 100) - std::cout << count << '\b' << '\b' ; - else - std::cout << count << '\b' << '\b' << '\b' ; + if (count < 100) + std::cout << count << '\b' << '\b' ; + else + std::cout << count << '\b' << '\b' << '\b' ; std::cout.flush(); } for (m=0; m<10; m++) @@ -253,12 +252,12 @@ int main() T2.insert( s[m+20*n] ); count++; if (count <10) - std::cout << count << '\b' ; + std::cout << count << '\b' ; else - if (count < 100) - std::cout << count << '\b' << '\b' ; - else - std::cout << count << '\b' << '\b' << '\b' ; + if (count < 100) + std::cout << count << '\b' << '\b' ; + else + std::cout << count << '\b' << '\b' << '\b' ; std::cout.flush(); } for (m=10; m<20; m++) @@ -267,17 +266,17 @@ int main() T2.insert( s[m+20*n] ); count++; if (count <10) - std::cout << count << '\b' ; + std::cout << count << '\b' ; else - if (count < 100) - std::cout << count << '\b' << '\b' ; - else - std::cout << count << '\b' << '\b' << '\b' ; + if (count < 100) + std::cout << count << '\b' << '\b' ; + else + std::cout << count << '\b' << '\b' << '\b' ; std::cout.flush(); } std::cout << std::endl << " number of vertices : " - << T2.number_of_vertices() << std::endl; + << T2.number_of_vertices() << std::endl; assert( T2.dimension()==2 ); assert( T2.is_valid() ); @@ -292,10 +291,10 @@ int main() for (b=0;b!=5;b++) // for (d=0;d!=10;d++) for (d=0;d!=5;d++) - lp.push_back(Weighted_point( Point(a*b-d*a + (a-b)*10 +a , - a-b+d +5*b, - a*a-d*d+b), - a*b-a*d) ); + lp.push_back(Weighted_point( Point(a*b-d*a + (a-b)*10 +a , + a-b+d +5*b, + a*a-d*d+b), + a*b-a*d) ); list_point::iterator it; count = 0 ; std::cout << " number of inserted points : " ; @@ -311,13 +310,13 @@ int main() if (count < 1000) std::cout << count << '\b' << '\b' << '\b' ; else - std::cout << count << std::endl; + std::cout << count << std::endl; std::cout.flush(); } std::cout << std::endl; std::cout << " number of vertices : " - << T.number_of_vertices() << std::endl; + << T.number_of_vertices() << std::endl; assert(T.is_valid()); assert(T.dimension()==3); @@ -326,7 +325,7 @@ int main() T.insert (lp.begin(), lp.end()); std::cout << " number of vertices : " - << T.number_of_vertices() << std::endl; + << T.number_of_vertices() << std::endl; assert(T.is_valid()); assert(T.dimension()==3); @@ -435,6 +434,30 @@ int main() assert(T5.nearest_power_vertex(v0->point().point()) == v3); assert(T5.is_Gabriel(v3)); assert(!T5.is_Gabriel(v0)); +} + +int main() +{ + std::cout << " with CGAL::Regular_triangulation_euclidean_traits_3: " + << std::endl; + + test_RT >(); + +#ifdef CGAL_LINKED_WITH_TBB + typedef CGAL::Spatial_lock_grid_3< + CGAL::Tag_priority_blocking> Lock_ds; + typedef CGAL::Triangulation_data_structure_3< + CGAL::Triangulation_vertex_base_3, + CGAL::Regular_triangulation_cell_base_3, + CGAL::Parallel_tag > Tds_parallel; + typedef CGAL::Regular_triangulation_3< + traits, Tds_parallel, Lock_ds> RT_parallel; + // The following test won't do things in parallel since it doesn't provide + // a lock data structure + test_RT(); + // This test performs parallel operations + _test_cls_parallel_triangulation_3( RT_parallel() ); +#endif std::cout << " quit " << std::endl; return 0; diff --git a/Triangulation_3/test/Triangulation_3/test_regular_as_delaunay_3.cpp b/Triangulation_3/test/Triangulation_3/test_regular_as_delaunay_3.cpp index 182e7a3a32d..54dab06c6c2 100644 --- a/Triangulation_3/test/Triangulation_3/test_regular_as_delaunay_3.cpp +++ b/Triangulation_3/test/Triangulation_3/test_regular_as_delaunay_3.cpp @@ -24,8 +24,8 @@ bool del=true; -#include -#include +#include "include/CGAL/_test_types.h" +#include "include/CGAL/_test_cls_delaunay_3.h" typedef CGAL::Regular_triangulation_euclidean_traits_3 Traits;