diff --git a/Documentation/doc/biblio/cgal_manual.bib b/Documentation/doc/biblio/cgal_manual.bib index a16cfe0015f..95a104d0a2a 100644 --- a/Documentation/doc/biblio/cgal_manual.bib +++ b/Documentation/doc/biblio/cgal_manual.bib @@ -714,6 +714,23 @@ note="Conference version: Symp. on Geometry Processing 2003" publisher={ACM New York, NY, USA} } +@InProceedings{cgal:dlpt-naihs-25, + author = {Despr\'{e}, Vincent and Lanuel, Camille and Pouget, Marc and Teillaud, Monique}, + title = {{\epsilon-Net Algorithm Implementation on Hyperbolic Surfaces}}, + booktitle = {33rd Annual European Symposium on Algorithms (ESA 2025)}, + pages = {61:1--61:18}, + series = {Leibniz International Proceedings in Informatics (LIPIcs)}, + ISBN = {978-3-95977-395-9}, + ISSN = {1868-8969}, + year = {2025}, + volume = {351}, + editor = {Benoit, Anne and Kaplan, Haim and Wild, Sebastian and Herman, Grzegorz}, + publisher = {Schloss Dagstuhl -- Leibniz-Zentrum f{\"u}r Informatik}, + address = {Dagstuhl, Germany}, + doi = {10.4230/LIPIcs.ESA.2025.61}, + annote = {Keywords: Hyperbolic surface, Delaunay triangulation, Data structure, Combinatorial map, Implementation, CGAL} +} + @article{cgal:dfg-cvtaa-99t, title={{Centroidal Voronoi Tessellations: Applications and Algorithms}}, author={Du, Q. and Faber, V. and Gunzburger, M.}, diff --git a/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Concepts/HyperbolicDelaunayTriangulationTraits_2.h b/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Concepts/HyperbolicDelaunayTriangulationTraits_2.h index 2f6cef0e871..ce97de1c62d 100644 --- a/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Concepts/HyperbolicDelaunayTriangulationTraits_2.h +++ b/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Concepts/HyperbolicDelaunayTriangulationTraits_2.h @@ -80,7 +80,7 @@ public: A predicate object. Must provide the function operator `Oriented_side operator()(Hyperbolic_point_2 p, Hyperbolic_point_2 q, Hyperbolic_point_2 query),` - which returns the position of the point `query` relative to the oriented hyperbolic + which returns the position of the point `query` relative to the circle supporting the hyperbolic segment with vertices `p` and `q`. */ typedef unspecified_type Side_of_oriented_hyperbolic_segment_2; @@ -105,6 +105,17 @@ public: */ typedef unspecified_type Is_Delaunay_hyperbolic; + /*! + A predicate object. Must provide the function operator + + `Orientation operator()(Hyperbolic_point_2 p, Hyperbolic_point_2 q, Hyperbolic_point_2 query),` + + which returns the position of the point `query` relative to the oriented hyperbolic + segment with vertices `p` and `q`. + + */ + typedef unspecified_type Hyperbolic_orientation_2; + /// @} /// \name Construction Types @@ -167,6 +178,7 @@ public: Side_of_oriented_circle_2 side_of_oriented_circle_2_object(); Side_of_oriented_hyperbolic_segment_2 side_of_oriented_hyperbolic_segment_2_object(); Is_Delaunay_hyperbolic is_Delaunay_hyperbolic_object(); + Hyperbolic_orientation_2 hyperbolic_orientation_2(); /// @} /// \name diff --git a/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_CK_traits_2.h b/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_CK_traits_2.h index ac3731b8adc..5a26a36563f 100644 --- a/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_CK_traits_2.h +++ b/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_CK_traits_2.h @@ -50,7 +50,6 @@ namespace internal { const Hyperbolic_point_2& q, const Hyperbolic_point_2& r) const { - Construct_circle_or_line_supporting_bisector cclsb(_gt); Hyperbolic_point_2 po(CGAL::ORIGIN); @@ -76,6 +75,7 @@ namespace internal { typedef typename CK2_Intersection_traits::type Intersection_result; std::vector< Intersection_result > inters; intersection(*c_pq, *c_qr, std::back_inserter(inters)); + CGAL_assertion(inters.size() != 0); CGAL_assertion_code(bool ok=) assign(pair, inters[0]); @@ -107,6 +107,7 @@ namespace internal { typedef typename CK2_Intersection_traits::type Intersection_result; std::vector< Intersection_result > inters; intersection(*l, *c, std::back_inserter(inters)); + CGAL_assertion(inters.size() != 0); CGAL_assertion_code(bool ok=) assign(pair,inters[0]); @@ -366,6 +367,7 @@ public: typedef typename internal::Construct_circle_or_line_supporting_bisector Construct_circle_or_line_supporting_bisector; typedef internal::Construct_hyperbolic_segment_2 Construct_hyperbolic_segment_2; typedef typename Base::Construct_segment_2 Construct_segment_2; + typedef typename internal::Hyperbolic_orientation_2 Hyperbolic_orientation_2; public: Hyperbolic_Delaunay_triangulation_CK_traits_2(const Base& kernel = Base()) : Base(kernel) {} @@ -411,6 +413,10 @@ public: compute_squared_Euclidean_distance_2_object() const { return this->Base::compute_squared_distance_2_object(); } + Hyperbolic_orientation_2 + hyperbolic_orientation_2() const + { return Hyperbolic_orientation_2(*this); } + }; // Take out the code below to some separate file diff --git a/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_traits_2.h b/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_traits_2.h index 0c0829309b7..91a7fb32b9e 100644 --- a/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_traits_2.h +++ b/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_traits_2.h @@ -492,6 +492,7 @@ public: typedef internal::Construct_hyperbolic_bisector_2 Construct_hyperbolic_bisector_2; typedef internal::Is_Delaunay_hyperbolic Is_Delaunay_hyperbolic; typedef internal::Side_of_oriented_hyperbolic_segment_2 Side_of_oriented_hyperbolic_segment_2; + typedef typename internal::Hyperbolic_orientation_2 Hyperbolic_orientation_2; // Needed for P4HT2 typedef typename Kernel::Construct_bisector_2 Construct_Euclidean_bisector_2; @@ -549,6 +550,10 @@ public: compute_squared_Euclidean_distance_2_object() const { return this->Base::compute_squared_distance_2_object(); } + Hyperbolic_orientation_2 + hyperbolic_orientation_2() const + { return Hyperbolic_orientation_2(*this); } + }; // class Hyperbolic_Delaunay_triangulation_traits_2 } // namespace CGAL diff --git a/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_triangulation_2/internal/Hyperbolic_Delaunay_triangulation_traits_2_functions.h b/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_triangulation_2/internal/Hyperbolic_Delaunay_triangulation_traits_2_functions.h index 63bb0c0c47f..6fbad1c7055 100644 --- a/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_triangulation_2/internal/Hyperbolic_Delaunay_triangulation_traits_2_functions.h +++ b/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_triangulation_2/internal/Hyperbolic_Delaunay_triangulation_traits_2_functions.h @@ -258,6 +258,45 @@ private: const Traits& _gt; }; +template +class Hyperbolic_orientation_2 +{ + typedef typename Traits::FT FT; + typedef typename Traits::Hyperbolic_point_2 Hyperbolic_point_2; + typedef typename Traits::Side_of_oriented_hyperbolic_segment_2 Side_of_oriented_hyperbolic_segment_2; + +public: + Hyperbolic_orientation_2(const Traits& gt = Traits()) : _gt(gt) {} + + Orientation operator()(const Hyperbolic_point_2& p, + const Hyperbolic_point_2& q, + const Hyperbolic_point_2& query) const + { + Hyperbolic_point_2 origin = Hyperbolic_point_2(FT(0), FT(0)); + Orientation orientation_to_origin = orientation(p, origin, q); + if (orientation_to_origin == COLLINEAR) { + return orientation(p, q, query); + } + + Side_of_oriented_hyperbolic_segment_2 orientation_test = _gt.side_of_oriented_hyperbolic_segment_2_object(); + Oriented_side orientation_to_disk = orientation_test(p, q, query); + if (orientation_to_disk == ON_POSITIVE_SIDE) { + return orientation_to_origin; + } else if (orientation_to_disk == ON_NEGATIVE_SIDE) { + if (orientation_to_origin == LEFT_TURN) { + return RIGHT_TURN; + } else { + return LEFT_TURN; + } + } else { + return COLLINEAR; + } + } + +private: + const Traits& _gt; +}; + } // end namespace internal } // end namespace CGAL diff --git a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/CMakeLists.txt b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/CMakeLists.txt index bea47a9213a..a872cd4223a 100644 --- a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/CMakeLists.txt +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/CMakeLists.txt @@ -12,15 +12,32 @@ set(CMAKE_AUTOMOC ON) # CGAL and its components find_package(CGAL REQUIRED COMPONENTS Core Qt6) find_package(Qt6 QUIET COMPONENTS Widgets) +find_package(Qt6 QUIET COMPONENTS Svg) if (NOT CGAL_Qt6_FOUND OR NOT Qt6_FOUND) message(STATUS "This project requires the Qt6 library, and will not be compiled.") return() endif() +# Boost and its components +find_package( Boost REQUIRED ) + +if ( NOT Boost_FOUND ) + message(STATUS "This project requires the Boost library, and will not be compiled.") + return() +endif() + # ui files, created with Qt Designer qt6_wrap_ui(UIS drawing_window_description.ui) add_executable( Triangulation_on_hyperbolic_surface_2_demo Triangulation_on_hyperbolic_surface_2_demo.cpp window.cpp ${UIS}) -target_link_libraries(Triangulation_on_hyperbolic_surface_2_demo PRIVATE CGAL::CGAL CGAL::CGAL_Qt6 Qt6::Widgets ) +target_link_libraries(Triangulation_on_hyperbolic_surface_2_demo PRIVATE CGAL::CGAL CGAL::CGAL_Qt6 Qt6::Widgets Qt6::Svg) cgal_add_compilation_test(Triangulation_on_hyperbolic_surface_2_demo) + +add_executable( Delaunay_triangulation_on_hyperbolic_surface_2_demo Delaunay_triangulation_on_hyperbolic_surface_2_demo.cpp window.cpp ${UIS}) +target_link_libraries(Delaunay_triangulation_on_hyperbolic_surface_2_demo PRIVATE CGAL::CGAL CGAL::CGAL_Qt6 Qt6::Widgets Qt6::Svg) + +add_executable( Hyperbolic_Dirichlet_domain_2_demo Hyperbolic_Dirichlet_domain_2_demo.cpp window.cpp ${UIS}) +target_link_libraries(Hyperbolic_Dirichlet_domain_2_demo PRIVATE CGAL::CGAL CGAL::CGAL_Qt6 Qt6::Widgets Qt6::Svg) + +set(CMAKE_BUILD_TYPE "Release") diff --git a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/Delaunay_triangulation_on_hyperbolic_surface_2_demo.cpp b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/Delaunay_triangulation_on_hyperbolic_surface_2_demo.cpp new file mode 100644 index 00000000000..442efe43013 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/Delaunay_triangulation_on_hyperbolic_surface_2_demo.cpp @@ -0,0 +1,110 @@ +#include "window.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace CGAL; + +typedef Gmpq NumberType; +typedef Circular_kernel_2,Algebraic_kernel_for_circles_2_2> Kernel; +typedef Hyperbolic_Delaunay_triangulation_CK_traits_2 ParentTraits; +typedef Hyperbolic_surface_traits_2 Traits; + +typedef Hyperbolic_fundamental_domain_2 Domain; +typedef Hyperbolic_isometry_2 Isometry; +typedef Hyperbolic_fundamental_domain_factory_2 Factory; +typedef Delaunay_triangulation_on_hyperbolic_surface_2 Delaunay_triangulation; + +/* + HOW TO USE THIS DEMO + ./Delaunay_triangulation_on_hyperbolic_surface_2_demo [epsilon] [surface seed] [precision] + Without arguments, uses the default values defined below. +*/ + +// DEFAULT VALUES +double epsilon = 0.25; +int seed = time(NULL); +int p = 1; + +int main(int argc, char *argv[]) +{ + if(argc == 1) { + std::cout << "HOW TO USE THIS DEMO:\n" + << "./Delaunay_triangulation_on_hyperbolic_surface_2_demo [epsilon] [surface seed] [precision]\n" + << "Without arguments, uses default values: epsilon = 0.25, random seed, precision = 1.\n" + << "WARNING: when not using the CGAL::Gmpq number type, precision is ignored and, instead, to_double is used to round coordinates of circumcenters.\n" + << "--------------------" + << std::endl; + } + // 1. Parse args and generate the input + if (argc > 1) { + epsilon = std::stod(argv[1]); + } + + Domain domain; + if (argc <= 2) { + std::cout << "Using random seed " << seed << std::endl; + } else { + seed = atoi(argv[2]); + } + Factory factory; + std::cout << "Generating surface with seed " << seed << "..." << std::endl; + domain = factory.make_hyperbolic_fundamental_domain_g2(seed); + Delaunay_triangulation dt = Delaunay_triangulation(domain); + + if (argc > 3) { + p = atoi(argv[3]); + } + + // 2. Get a vertex + // So that if you run the demo on a same surface but with different values of epsilon, + // the drawing will be centered at the same vertex and it will look similar. + Point v0 = dt.anchor().vertices[0]; + + // 3. Compute epsilon-net and display useful info + if constexpr(!std::is_same::value) { + std::cout << "WARNING: Not using the CGAL::Gmpq number type. Precision will be ignored and to_double approximation will be used instead." << std::endl; + } + std::cout << "Computing a " << epsilon << "-net with floating-point precision " << p*53 << "..." << std::endl; + Timer timer; + timer.start(); + std::cout << "Is epsilon-net? " << dt.epsilon_net(epsilon, p) << std::endl; + timer.stop(); + std::cout << "Done in " << timer.time() << " seconds." << std::endl; + dt.combinatorial_map().display_characteristics(std::cout) << std::endl; + + // 4. SET THE FIRST ANCHOR OF THE DRAWING + Anchor anchor = dt.locate(v0); + int index = 0; + for (int i = 0; i < 3; i++) { + if (v0 == anchor.vertices[i]) { + index = i; + } + } + + Anchor start = Anchor(); + start.dart = anchor.dart; + for (int i = 0; i < 3; i++) { + start.vertices[i] = anchor.vertices[(i + index) % 3]; + if (i < index) { + start.dart = dt.Base::ccw(start.dart); + } + } + + // 5. DRAW + QApplication app(argc, argv); + app.setApplicationName("Delaunay triangulation on hyperbolic surface 2 Demo"); + DemoWindow window; + window.item().draw_triangulation(dt, start); + window.show(); + QStringList args = app.arguments(); + args.removeAt(0); + return app.exec(); +} diff --git a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/Hyperbolic_Dirichlet_domain_2_demo.cpp b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/Hyperbolic_Dirichlet_domain_2_demo.cpp new file mode 100644 index 00000000000..530433251a0 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/Hyperbolic_Dirichlet_domain_2_demo.cpp @@ -0,0 +1,35 @@ +#include "window.h" + +#include +#include +#include +#include +#include + +#include +#include + +typedef CGAL::Gmpq NumberType; +typedef CGAL::Circular_kernel_2,CGAL::Algebraic_kernel_for_circles_2_2> Kernel; +typedef CGAL::Hyperbolic_Delaunay_triangulation_CK_traits_2 ParentTraits; +typedef CGAL::Hyperbolic_surface_traits_2 Traits; + +typedef CGAL::Hyperbolic_fundamental_domain_2 Domain; +typedef CGAL::Hyperbolic_fundamental_domain_factory_2 Factory; + +int main(int argc, char **argv) +{ + int seed = time(NULL); + std::cout << "Using seed " << seed << std::endl; + Factory factory; + Domain domain = factory.make_hyperbolic_fundamental_domain_g2(seed); + + QApplication app(argc, argv); + app.setApplicationName("Hyperbolic Dirichlet domain 2 Demo"); + DemoWindow window; + window.item().draw_Dirichlet(domain); + window.show(); + QStringList args = app.arguments(); + args.removeAt(0); + return app.exec(); +} \ No newline at end of file diff --git a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2_demo.cpp b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2_demo.cpp index d25d07c1b5a..83f73152c3e 100644 --- a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2_demo.cpp +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2_demo.cpp @@ -1,17 +1,22 @@ #include "window.h" #include +#include #include -#include +#include #include #include #include using namespace CGAL; -typedef Simple_cartesian Kernel; -typedef Hyperbolic_Delaunay_triangulation_traits_2 ParentTraits; +typedef Gmpq NumberType; +typedef Circular_kernel_2, Algebraic_kernel_for_circles_2_2> Kernel; +typedef Hyperbolic_Delaunay_triangulation_CK_traits_2 ParentTraits; + +// typedef Simple_cartesian Kernel; +// typedef Hyperbolic_Delaunay_triangulation_traits_2 ParentTraits; typedef Hyperbolic_surface_traits_2 Traits; typedef Hyperbolic_fundamental_domain_2 Domain; typedef Hyperbolic_fundamental_domain_factory_2 Factory; @@ -31,7 +36,7 @@ int main(int argc, char** argv) // 2. Draw the triangulation QApplication app(argc, argv); - app.setApplicationName("Hyperbolic surfaces triangulation 2 Demo"); + app.setApplicationName("Triangulation on hyperbolic surface 2 Demo"); DemoWindow window; window.item().draw_triangulation(triangulation); diff --git a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/drawing_window_description.ui b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/drawing_window_description.ui index cba64b8f300..ddc4e2ed594 100644 --- a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/drawing_window_description.ui +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/drawing_window_description.ui @@ -6,8 +6,8 @@ 0 0 - 800 - 720 + 665 + 710 @@ -25,8 +25,8 @@ 10 10 - 771 - 671 + 650 + 650 @@ -38,6 +38,34 @@ + + + + 0 + 0 + 665 + 22 + + + + + Save As... + + + + + + + + + Save as SVG + + + + + Save as PNG + + diff --git a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/window.cpp b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/window.cpp index 5113f957253..8f58d9b318b 100644 --- a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/window.cpp +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/window.cpp @@ -17,15 +17,20 @@ DemoWindowItem::DemoWindowItem() { // Clear edges_.clear(); + dirichlet_edges_.clear(); // Prepare the pens poincare_disk_pen_.setStyle(Qt::SolidLine); - poincare_disk_pen_.setWidth(8); + poincare_disk_pen_.setWidth(4); poincare_disk_pen_.setBrush(Qt::black); edges_pen_.setStyle(Qt::SolidLine); - edges_pen_.setWidth(6); + edges_pen_.setWidth(4); edges_pen_.setBrush(Qt::blue); + + dirichlet_pen_.setStyle(Qt::SolidLine); + dirichlet_pen_.setWidth(4); + dirichlet_pen_.setBrush(Qt::red); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -34,6 +39,8 @@ void DemoWindowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) { + painter->setRenderHints(QPainter::Antialiasing); // for a smoother drawing ;) + // 1. Draw the poincaré disk QRectF circle_rect = QRectF(-poincare_disk_radius_in_pixels_-3, -poincare_disk_radius_in_pixels_-3, @@ -49,6 +56,13 @@ void DemoWindowItem::paint(QPainter *painter, for (std::size_t i=0; isetBrush(QBrush()); + painter->setPen(dirichlet_pen_); + for (std::size_t i = 0; i < dirichlet_edges_.size(); i++) { + draw_edge(painter, dirichlet_edges_[i].first, dirichlet_edges_[i].second); + } } QRectF DemoWindowItem::boundingRect() const { @@ -82,13 +96,57 @@ void DemoWindowItem::draw_triangulation(Triangulation& triangulation) } } +void DemoWindowItem::draw_triangulation(Delaunay_triangulation & triangulation, Anchor & anchor) +{ + typedef std::vector < std::tuple < typename Delaunay_triangulation::Dart_const_descriptor, Point, + Point, Point >> RealizationVector; + RealizationVector realized_triangles; + realized_triangles = triangulation.lift(anchor); + + Point point_1, point_2, point_3; + for (typename RealizationVector::iterator it = realized_triangles.begin(); it != realized_triangles.end(); ++it) { + point_1 = std::get < 1 > (*it); + point_2 = std::get < 2 > (*it); + point_3 = std::get < 3 > (*it); + + edges_.push_back(std::make_pair(point_1, point_2)); + edges_.push_back(std::make_pair(point_2, point_3)); + edges_.push_back(std::make_pair(point_3, point_1)); + } +} + +void DemoWindowItem::draw_triangles(std::vector < Anchor > anchors) +{ + for (std::size_t i = 0; i < anchors.size(); i++) { + Point p0 = anchors[i].vertices[0]; + Point p1 = anchors[i].vertices[1]; + Point p2 = anchors[i].vertices[2]; + + edges_.push_back(std::make_pair(p0, p1)); + edges_.push_back(std::make_pair(p1, p2)); + edges_.push_back(std::make_pair(p2, p0)); + } +} + +void DemoWindowItem::draw_Dirichlet(Domain & domain) +{ + std::vector < Voronoi_point > vertices = CGAL::Dirichlet_vertices(domain); + int n = vertices.size(); + for (int i = 0; i < n; ++i) { + Point v0 = Point(CGAL::to_double(vertices[i].x()), CGAL::to_double(vertices[i].y())); + Point v1 = + Point(CGAL::to_double(vertices[(i + 1) % n].x()), CGAL::to_double(vertices[(i + 1) % n].y())); + dirichlet_edges_.push_back(std::make_pair(v0, v1)); + } +} + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void DemoWindowItem::draw_point(QPainter* painter, Point position) { // First convert the point in doubles, well-scaled double point_x = poincare_disk_radius_in_pixels_ * CGAL::to_double(position.x()); - double point_y = poincare_disk_radius_in_pixels_ * CGAL::to_double(position.y()); + double point_y = - poincare_disk_radius_in_pixels_ * CGAL::to_double(position.y()); // Take the opposite so that the drawing is not upside down // Then draw a small circle QRectF circle_rect = QRectF(point_x-1, point_y-1, 3, 3); @@ -100,10 +158,10 @@ void DemoWindowItem::draw_edge(QPainter* painter, Point source, Point target) // First convert the points coordinates to doubles double src_x = CGAL::to_double(source.x()); - double src_y = CGAL::to_double(source.y()); + double src_y = - CGAL::to_double(source.y()); // Take the opposite so that the drawing is not upside down double tar_x = CGAL::to_double(target.x()); - double tar_y = CGAL::to_double(target.y()); + double tar_y = - CGAL::to_double(target.y()); // Take the opposite so that the drawing is not upside down // 0. If src and tar are too colinear or too close from each other then draw a line @@ -256,7 +314,7 @@ DemoWindow::DemoWindow() : DemosMainWindow() scene_.setSceneRect(-600, -600, 1200, 1200); item_ = new DemoWindowItem(); scene_.addItem(item_); - this->graphicsView->scale(0.5, -0.5); // Y-axis inversion + this->graphicsView->scale(0.5, 0.5); setWindowTitle("Hyperbolic surfaces triangulation 2 Demo"); } @@ -267,3 +325,58 @@ DemoWindowItem& DemoWindow::item() } void DemoWindow::keyPressEvent(QKeyEvent*) {} + +void DemoWindow::on_actionSave_as_SVG_triggered() +{ + QString newPath = QFileDialog::getSaveFileName(this, tr("Save SVG"), + path_, tr("SVG files (*.svg)")); + + if (newPath.isEmpty()) + return; + + path_ = newPath; + + QRectF newSceneRect; + QGraphicsScene *tempScene = new QGraphicsScene(scene_.sceneRect()); + tempScene->setBackgroundBrush(QBrush(Qt::transparent)); + tempScene->setItemIndexMethod(QGraphicsScene::BspTreeIndex); + foreach(QGraphicsItem * item, scene_.items()) { + newSceneRect |= item->mapToScene(item->boundingRect()).boundingRect(); + tempScene->addItem(item); + } + tempScene->setSceneRect(newSceneRect); + tempScene->clearSelection(); + QSize sceneSize = newSceneRect.size().toSize(); + + QSvgGenerator generator; + generator.setFileName(path_); + generator.setSize(sceneSize); + generator.setViewBox(QRect(-3, -3, 2 * sceneSize.width(), 2 * sceneSize.height())); + generator.setDescription(QObject::tr("My canvas exported to Svg")); + generator.setTitle(path_); + QPainter painter; + painter.begin(&generator); + tempScene->render(&painter); + painter.end(); + + tempScene->clear(); + delete tempScene; +} + +void DemoWindow::on_actionSave_as_PNG_triggered() +{ + QString newPath = QFileDialog::getSaveFileName(this, tr("Save PNG"), + path_, tr("PNG files (*.png)")); + + if (newPath.isEmpty()) + return; + + path_ = newPath; + + QImage img(808, 808, QImage::Format_ARGB32_Premultiplied); + img.fill(Qt::white); + QPainter p(&img); + scene_.render(&p); + p.end(); + img.save(path_, "PNG"); +} diff --git a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/window.h b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/window.h index 0f581c4bd01..417f00df95e 100644 --- a/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/window.h +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/window.h @@ -18,21 +18,30 @@ #include #include +#include + // UI generated header #include "ui_drawing_window_description.h" #include #include -#include +#include #include #include +#include +#include -typedef CGAL::Simple_cartesian Kernel; -typedef CGAL::Hyperbolic_Delaunay_triangulation_traits_2 ParentTraits; -typedef CGAL::Hyperbolic_surface_traits_2 Traits; -typedef Traits::Hyperbolic_point_2 Point; -typedef CGAL::Triangulation_on_hyperbolic_surface_2 Triangulation; +typedef CGAL::Gmpq NumberType; +typedef CGAL::Circular_kernel_2,CGAL::Algebraic_kernel_for_circles_2_2> Kernel; +typedef CGAL::Hyperbolic_Delaunay_triangulation_CK_traits_2 ParentTraits; +typedef CGAL::Hyperbolic_surface_traits_2 Traits; +typedef Traits::Hyperbolic_point_2 Point; +typedef typename Traits::Hyperbolic_Voronoi_point_2 Voronoi_point; +typedef CGAL::Hyperbolic_fundamental_domain_2 Domain; +typedef CGAL::Triangulation_on_hyperbolic_surface_2 Triangulation; +typedef CGAL::Delaunay_triangulation_on_hyperbolic_surface_2 Delaunay_triangulation; +typedef typename Delaunay_triangulation::Anchor Anchor; class DemoWindowItem : public CGAL::Qt::GraphicsItem @@ -45,10 +54,12 @@ private: // Edges to draw std::vector > edges_; + std::vector > dirichlet_edges_; // Pens for drawing QPen poincare_disk_pen_; QPen edges_pen_; + QPen dirichlet_pen_; // radius of the poincaré disk const int poincare_disk_radius_in_pixels_ = 600; @@ -67,8 +78,11 @@ public: QRectF boundingRect() const; void modelChanged(); - // Drawing method + // Drawing methods void draw_triangulation(Triangulation& triangulation); + void draw_triangulation(Delaunay_triangulation& triangulation, Anchor& anchor); + void draw_triangles(std::vector anchors); + void draw_Dirichlet(Domain& domain); private: // Sub-methods for drawing edges and vertices @@ -95,6 +109,7 @@ class DemoWindow private: QGraphicsScene scene_; DemoWindowItem* item_; + QString path_; public: DemoWindow(); @@ -102,6 +117,10 @@ public: // Events handling void keyPressEvent(QKeyEvent* event); + +public Q_SLOTS: + void on_actionSave_as_SVG_triggered(); + void on_actionSave_as_PNG_triggered(); }; #endif // CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_DEMO_WINDOW diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Delaunay_triangulation_on_hyperbolic_surface_2.h b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Delaunay_triangulation_on_hyperbolic_surface_2.h new file mode 100644 index 00000000000..d9aafa13458 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Delaunay_triangulation_on_hyperbolic_surface_2.h @@ -0,0 +1,211 @@ +namespace CGAL { + +/*! + \ingroup PkgHyperbolicSurfaceTriangulation2MainClasses + + This item defines attributes for edges and faces. + Edge attributes are of type `Complex_number` representing cross-ratios. + Face attributes attributes are of type `Anchor` representing a lift of a triangle. + + \tparam Traits must be a model of `HyperbolicSurfaceTraits_2`. + + \cgalModels{GenericMapItems} +*/ +template +struct Delaunay_triangulation_attributes { + template + struct Dart_wrapper{ + typedef Cell_attribute> Edge_attrib; + typedef Cell_attribute>::Anchor> Face_attrib; + typedef std::tuple Attributes; + }; +}; + +/*! + \ingroup PkgHyperbolicSurfaceTriangulation2MainClasses + + represents a Delaunay triangulation of a closed orientable hyperbolic surface. + + The class provides functions such as the generation of the Delaunay triangulation from a convex fundamental domain, + the location of a point in the lifted triangulation, the insertion of a point in the Delaunay triangulation, and the \f$ \varepsilon \f$-net algorithm. + + \tparam Traits must be a model of `HyperbolicSurfaceTraits_2`. + + \sa `Triangulation_on_hyperbolic_surface_2` +*/ +template +class Delaunay_triangulation_on_hyperbolic_surface_2: public Triangulation_on_hyperbolic_surface_2> { +public: + /// \name Types + /// @{ + + typedef Triangulation_on_hyperbolic_surface_2> Base; + /*! + Type of combinatorial map whose edges are decorated with complex numbers and faces are decorated with anchors. + */ + typedef Combinatorial_map<2,Delaunay_triangulation_attributes> CMap; + typedef typename Triangulation_on_hyperbolic_surface_2>::Anchor Anchor; + + typedef typename Traits::FT Number; + typedef typename Traits::Complex Complex_number; + + + /*! + Point in the Poincaré disk. + */ + typedef typename Traits::Hyperbolic_point_2 Point; + + typedef typename CMap::Dart_descriptor Dart_descriptor; + typedef typename CMap::Dart_range Dart_range; + typedef typename CMap::template One_dart_per_cell_range<0> Vertex_range; + typedef typename CMap::template One_dart_per_cell_range<1> Edge_range; + typedef typename CMap::template One_dart_per_cell_range<2> Face_range; + typedef typename CMap::Dart_const_descriptor Dart_const_descriptor; + typedef typename CMap::Dart_const_range Dart_const_range; + typedef typename CMap::template One_dart_per_cell_const_range<1> Edge_const_range; + typedef typename CMap::template One_dart_per_cell_const_range<2> Face_const_range; + /// @} + + /// \name Enums + /// @{ + + /* + The enumeration `Locate_type` is defined to specify which case occurs when locating a point in the lifted triangulation. + */ + enum Locate_type { + VERTEX = 0, + EDGE, + FACE, + OUTSIDE + }; + /// @} + + /// \name Creation + /// Calls the corresponding constructor from #Base and sets an #Anchor for each face. + /// @{ + Delaunay_triangulation_on_hyperbolic_surface_2() {}; + Delaunay_triangulation_on_hyperbolic_surface_2(CMap & cmap, Anchor & anch); + Delaunay_triangulation_on_hyperbolic_surface_2(Hyperbolic_fundamental_domain_2 const & domain); + Delaunay_triangulation_on_hyperbolic_surface_2(Base & triangulation); + /// @} + + /// \name Access Functions + /// @{ + /*! + \return the anchor associated with the given dart. + */ + Anchor & anchor(Dart_descriptor const dart); + /*! + \return the anchor associated with the given dart. + */ + Anchor const & anchor(Dart_const_descriptor const dart) const; + /*! + \return an anchor of the triangulation. + */ + Anchor & anchor(); + /*! + \return an anchor of the triangulation. + */ + Anchor const & anchor() const; + /*! + \return the index of the given dart in its face. The index is `0` if `dart` is the dart of its associated anchor. + */ + unsigned index_in_anchor(Dart_const_descriptor const dart) const; + /*! + \return the `i`-th dart of the face associated with `anch`, where `anch.dart` is the `0`-th dart of the face. + */ + Dart_descriptor ith_dart(unsigned i, Anchor const & anch); + /// @} + + /// \name Validity + /*! + \return a Boolean that indicates whether the triangulation is a valid Delaunay triangulation. + */ + bool is_valid() const; + + /// \name Point location and insertion + /// @{ + /*! + \return a `Locate_type` that indicates whether `query` lies on a vertex, an edge, inside or outside the lifted triangle described by the given anchor. + + If `query` lies on a vertex or an edge, the index `li` is set to the index of the vertex or edge on which `query` lies. + + If `query` lies inside the triangle, `li` is set to `-1`. + + If `query` lies outside the triangle, `li` is set to the index of the first edge such that `query` and the third point of the triangle lies on different sides. + */ + Locate_type relative_position(Point const & query, unsigned & li, Anchor const & anch) const; + + /*! + \return the anchor representing the lift of the triangle in which `query` lies. + + Locates `query` in the Delaunay triangulation. + + The Boolean `use_visibility` indicates whether the visibility walk algorithm is used for the point location. When `false`, the straight walk algorithm is used. + */ + Anchor locate(Point const & query, bool use_visibility = false); // const ? + /*! + Same as above. + + Additionally, the point location algorithm starts from `hint` and `ld` is set to the number or triangle travarsed by the walk used for the point location algorithm. + + The variables `lt` and `li` contains information about the triangle in which `query` has been found. + + \sa relative_position + */ + Anchor locate(Point const & query, Locate_type & lt, unsigned & li, unsigned & ld, Anchor const & hint, bool use_visibility = false); // const ? + + /*! + Inserts `query` in the Delaunay triangulation after having located it, starting from `hint`. + + \pre is_valid() and norm(Complex_number(query.x(), query.y())) < Number(1) + */ + void insert(Point const & query, Anchor & hint); + + /*! + Inserts `query` in the Delaunay triangulation. + */ + void insert(Point const & query); + /// @} + + /// \name \f$ \varepsilon \f$-net + /// @{ + /*! + \return a Boolean that indicates whether the vertices of the Delaunay triangulation form a certified `epsilon`-net of the surface. + + Tries to compute an `epsilon`-net of the surface. + + When `Number` is `CGAL::Gmpq`, the algorithm rounds the coordinate of circumcenters to `CGAL::Gmpfr` with precision `p*53`. + When `Number` is not `CGAL::Gmpq`, `p` is ignored. + + \pre is_epsilon_packing(epsilon) and p > 0 + */ + bool epsilon_net(double const epsilon, unsigned const p = 1); + /*! + \return a Boolean that indicates whether the vertices of the Delaunay triangulation form a certified `epsilon`-covering of the surface. + */ + bool is_epsilon_covering(const double epsilon) const; + /*! + \return a Boolean that indicates whether the vertices of the Delaunay triangulation form a certified `epsilon`-packing of the surface. + */ + bool is_epsilon_packing(const double epsilon) const; + /*! + \return a Boolean that indicates whether the vertices of the Delaunay triangulation form a certified `epsilon`-net of the surface. + */ + bool is_epsilon_net(const double epsilon) const; + /// @} + + /// \name Other functions + /// @{ + /*! + \return a `double` approximation of the length of the shortest geodesic loop edge in the Delaunay triangulation. Returns 0 (NULL) if there is no loop edge. + */ + double shortest_loop_edge() const; + /*! + \return a `double` approximation of the length of the shortest non-loop edge in the Delaunay triangulation. Returns 0 (NULL) if all edges are loops. + */ + double shortest_non_loop_edge() const; + /// @} +} + +} // namespace CGAL diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_Dirichlet_domain_2.h b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_Dirichlet_domain_2.h new file mode 100644 index 00000000000..2337f1b03ab --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_Dirichlet_domain_2.h @@ -0,0 +1,11 @@ +namespace CGAL { +/*! + \ingroup PkgHyperbolicSurfaceTriangulation2DirichletDomain + + \return a vector with the vertices of a Dirichlet domain whose base point is translated to the origin of the Poincaré disk. + + @param domain must be a fundamental domain whose vertices represent a same point on the corresponding hyperbolic surface. +*/ +std::vector Dirichlet_vertices(Hyperbolic_fundamental_domain_2 & domain); + +} // namespace CGAL \ No newline at end of file diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Triangulation_on_hyperbolic_surface_2.h b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Triangulation_on_hyperbolic_surface_2.h index 785eb2f6d94..9f2cde2b881 100644 --- a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Triangulation_on_hyperbolic_surface_2.h +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Triangulation_on_hyperbolic_surface_2.h @@ -126,16 +126,6 @@ public: /// @} - /// \name Assignment - /// @{ - - /*! - \pre other.is_valid() - */ - Triangulation_on_hyperbolic_surface_2& operator=(Triangulation_on_hyperbolic_surface_2 other); - - /// @} - /// \name Access Functions /// @{ @@ -233,7 +223,18 @@ Vertex_range vertices_range(); Returns, for every triangle \f$ t \f$ of the triangulation, one of the darts of \f$ t \f$ in the combinatorial map of the triangulation, together with a triple \f$ p,q,r \f$ of points in the hyperbolic plane. The points \f$ p,q,r \f$ are the vertices of a lift of \f$ t \f$ in the hyperbolic plane. - If the center parameter is set to true, then one of the vertices of the anchor is translated to the origin \f$ 0 \f$. + If the center parameter is set to true, then the first vertex of the given anchor is translated to the origin \f$ 0 \f$. + + \pre is_valid() + */ + std::vector > lift(Anchor const & anchor, bool center=true) const; + + /*! + lifts the triangulation in the hyperbolic plane. + + Returns, for every triangle \f$ t \f$ of the triangulation, one of the darts of \f$ t \f$ in the combinatorial map of the triangulation, together with a triple \f$ p,q,r \f$ of points in the hyperbolic plane. + The points \f$ p,q,r \f$ are the vertices of a lift of \f$ t \f$ in the hyperbolic plane. + If the center parameter is set to true, then the first vertex of the anchor is translated to the origin \f$ 0 \f$. \pre is_valid() && has_anchor() */ diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Triangulation_on_hyperbolic_surface_2_IO.h b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Triangulation_on_hyperbolic_surface_2_IO.h index 710a58ea510..93398c4685c 100644 --- a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Triangulation_on_hyperbolic_surface_2_IO.h +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Triangulation_on_hyperbolic_surface_2_IO.h @@ -13,7 +13,7 @@ namespace CGAL { If the triangulation has an anchor, then the four next lines print the index of the dart of the anchor, and the three vertices of the anchor. Then, for every triangle \f$ t \f$, the indices of the three darts of \f$ t \f$ are printed on three distinct lines. - Finally, for every edge \f$ e \f$, the indices of the two darts of \f$ e \f$ are printed on two distinct lines, followed by a third line on which the cross ratio of \f$ e \f$ is printed. + Finally, for every edge \f$ e \f$, the indices of the two darts of \f$ e \f$ are printed on two distinct lines, followed by two lines on which the cross ratio of \f$ e \f$ is printed. \pre Triangulation_on_hyperbolic_surface_2::is_valid() */ @@ -24,7 +24,7 @@ std::ostream& operator<<(std::ostream& s, const Triangulation_on_hyperbolic_surf extracts the triangulation from a stream. - The format of the input should be the same as the format of the output of + The format of the input is the same as the format of the output of the '<<' operator for Triangulation_on_hyperbolic_surface_2. */ std::istream& operator>>(std::istream& s, Triangulation_on_hyperbolic_surface_2& triangulation); @@ -48,7 +48,7 @@ std::ostream& operator<<(std::ostream& s, const Hyperbolic_fundamental_domain_2< extracts the domain from a stream. - The format of the input must be the same as the format of the output of + The format of the input is the same as the format of the output of the '<<' operator for Hyperbolic_fundamental_domain_2. */ std::istream& operator>>(std::istream& s, Hyperbolic_fundamental_domain_2& domain); @@ -60,4 +60,31 @@ std::istream& operator>>(std::istream& s, Hyperbolic_fundamental_domain_2& isometry); +/*! + \ingroup PkgHyperbolicSurfaceTriangulation2InputOutput + + inserts the Delaunay triangulation in a stream. + + The format of the output is the following. + Each dart of the triangulation is given an index between \f$ 0 \f$ and \f$ n-1 \f$, where \f$ n \f$ + is the number of darts of the triangulation. + The first line contains the number \f$ n \f$ of darts. + Then, for every triangle \f$ t \f$, the indices of the three darts of \f$ t \f$ are printed on three distinct lines. + The coordinates of the three vertices of its anchor are printed on the next six lines. + Finally, for every edge \f$ e \f$, the indices of the two darts of \f$ e \f$ are printed on two distinct lines, followed by two lines on which the cross ratio of \f$ e \f$ is printed. + + \pre Triangulation_on_hyperbolic_surface_2::is_valid() +*/ +std::istream& operator>>(std::istream& s, Delaunay_triangulation_on_hyperbolic_surface_2& triangulation); + +/*! + \ingroup PkgHyperbolicSurfaceTriangulation2InputOutput + + extracts the Delaunay triangulation from a stream. + + The format of the input is the same as the format of the output of + the '<<' operator for Delaunay_triangulation_on_hyperbolic_surface_2. +*/ +std::ostream& operator<<(std::ostream& s, const Delaunay_triangulation_on_hyperbolic_surface_2& triangulation); + } // namespace CGAL diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Concepts/HyperbolicSurfaceTraits_2.h b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Concepts/HyperbolicSurfaceTraits_2.h index e9e30e73195..48e714e148d 100644 --- a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Concepts/HyperbolicSurfaceTraits_2.h +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Concepts/HyperbolicSurfaceTraits_2.h @@ -16,6 +16,11 @@ public: /// \name Types /// @{ + /*! + Field number type. + */ + typedef unspecified_type FT; + /*! represents a complex number, model of `ComplexNumber`, over the field `HyperbolicSurfaceTraits_2::FT` for its real and imaginary parts. diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/PackageDescription.txt b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/PackageDescription.txt index 34cdcf2a70e..01db687b636 100644 --- a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/PackageDescription.txt +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/PackageDescription.txt @@ -12,6 +12,9 @@ /// \defgroup PkgHyperbolicSurfaceTriangulation2InputOutput Input/Output Functions /// \ingroup PkgHyperbolicSurfaceTriangulation2Ref +/// \defgroup PkgHyperbolicSurfaceTriangulation2DirichletDomain Dirichlet Domain Function +/// \ingroup PkgHyperbolicSurfaceTriangulation2Ref + /*! \addtogroup PkgHyperbolicSurfaceTriangulation2Ref @@ -19,8 +22,8 @@ \cgalPkgPicture{cover.svg} \cgalPkgSummaryBegin -\cgalPkgAuthors{Vincent Despré, Loïc Dubois, Marc Pouget and Monique Teillaud} -\cgalPkgDesc{This package enables building and handling triangulations of closed orientable hyperbolic surfaces. It offers functions for the generation of the triangulation from a convex fundamental domain, the Delaunay flip algorithm and the construction of a portion of the lift of the triangulation in the Poincaré disk. A method is offered that generates such domains in genus two.} +\cgalPkgAuthors{Vincent Despré, Loïc Dubois, Camille Lanuel, Marc Pouget and Monique Teillaud} +\cgalPkgDesc{This package enables building and handling triangulations or Delaunay triangulations of closed orientable hyperbolic surfaces. It offers functions for the generation of the triangulation from a convex fundamental domain, the Delaunay flip algorithm and the construction of a portion of the lift of the triangulation in the Poincaré disk. A method is offered that generates such domains in genus two.} \cgalPkgManuals{Chapter_Hyperbolic_Surface_Triangulations,PkgHyperbolicSurfaceTriangulation2Ref} \cgalPkgSummaryEnd @@ -43,7 +46,9 @@ \cgalCRPSection{Classes} -- `CGAL::Triangulation_on_hyperbolic_surface_2` represents a triangulation of a closed orientable hyperbolic surface. It offers functions for the generation of the triangulation from a convex fundamental domain, the Delaunay flip algorithm and the construction of a portion of the lift of the triangulation in the Poincaré disk. +- `CGAL::Triangulation_on_hyperbolic_surface_2` represents a triangulation of a closed orientable hyperbolic surface. It offers functions for the generation of the triangulation from a convex fundamental domain, the Delaunay flip algorithm and the construction of a portion of the lift of the triangulation in the Poincaré disk. + +- `CGAL::Delaunay_triangulation_on_hyperbolic_surface_2` represents a Delaunay triangulation of a closed orientable hyperbolic surface. It offers functions for the generation of the Delaunay triangulation from a convex fundamental domain, the insertion of a point in the Delaunay triangulation, two point location algorithms and the \f$ \varepsilon \f$-net algorithm. - `CGAL::Hyperbolic_fundamental_domain_2` represents a fundamental domain of a closed orientable hyperbolic surface. @@ -57,4 +62,8 @@ Models for `HyperbolicSurfaceTraits_2` and `ComplexNumber` are provided: `CGAL:: - `operator<<` and `operator>>` are overloaded for several classes of the package. +\cgalCRPSection{Dirichlet Domain Function} + +- `CGAL::Dirichlet_vertices` computes the vertices of a Dirichlet domain from a fundamental domain whose vertices represent a same point on the corresponding hyperbolic surface. + */ diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.txt b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.txt index 781793b956d..8bb3d05499b 100644 --- a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.txt +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.txt @@ -8,15 +8,18 @@ namespace CGAL { \anchor Chapter_Hyperbolic_Surface_Triangulations \cgalAutoToc -\authors Vincent Despré, Loïc Dubois, Marc Pouget and Monique Teillaud +\authors Vincent Despré, Loïc Dubois, Camille Lanuel, Marc Pouget and Monique Teillaud
-This package introduces a data structure and algorithms for triangulations of closed orientable hyperbolic surfaces. The triangulation is represented by an enriched CGAL::Combinatorial_map with complex number attributes on edges. -Such a triangulation can be constructed from a surface given by a convex fundamental domain (see Section \ref Section_Hyperbolic_Surface_Triangulations_domains "Fundamental Domains and Triangulations"). A method is offered that randomly generates such domains for surfaces of genus two. On the other hand, the package works for any genus surface that may be provided by the user either as a fundamental domain or as an already computed triangulation. -Functionalities are offered such as the Delaunay flip algorithm and the construction of a portion of the lift of the triangulation in the Poincaré disk model of the hyperbolic plane. +This package introduces a data structure and algorithms for triangulations and Delaunay triangulation of closed orientable hyperbolic surfaces. +A triangulation is represented by an enriched CGAL::Combinatorial_map with complex number attributes on edges. +Additionally, a Delaunay triangulation has anchor attributes, representing lifts of triangles, on faces. +Such triangulations can be constructed from a surface given by a convex fundamental domain (see Section \ref Section_Hyperbolic_Surface_Triangulations_domains "Fundamental Domains and Triangulations"). A method is offered that randomly generates such domains for surfaces of genus two. On the other hand, the package works for any genus surface that may be provided by the user either as a fundamental domain or as an already computed triangulation. +For triangulations, functionalities are offered such as the Delaunay flip algorithm and the construction of a portion of the lift of the triangulation in the Poincaré disk model of the hyperbolic plane. +For Delaunay triangulations, additional functionalities include point location, point insertion, and the computation of an \f$ \varepsilon \f$-net of the hyperbolic surface. For the case of the Bolza surface, which is the most symmetric surface of genus two, we refer the user to the specific package \ref Chapter_2D_Periodic_Hyperbolic_Triangulations "2D Periodic Hyperbolic Triangulations". @@ -102,6 +105,13 @@ See \cgalCite{despre2022experimental} for details. Computation of the cross ratio of an edge. \cgalFigureCaptionEnd +\subsection Subsection_Hyperbolic_Surface_Triangulations_DS_Delaunay_Triangulations Data Structure for Delaunay Triangulations + +
+The data structure is enriched for Delaunay triangulations in order to be more convenient and more time efficient for the \f$ \varepsilon \f$-net algorithm or other algorithms that often have to access lifts of triangles in \f$ \mathbb{D} \f$. +In order to have constant time access to a lift of any triangle, an anchor is associated with each face of the triangulation. Note that the anchors associated with adjacent triangles do not necessarily correspond to adjacent lifts +in \f$ \mathbb{D} \f$. This implies that, when working with a lift of a triangle, if an operation requires the third vertex of an adjacent lift, its coordinates must first be computed using the cross-ratio of their common edge. +
\subsection Subsection_Hyperbolic_Surface_Triangulations_Delaunay Delaunay Flip Algorithm @@ -114,15 +124,49 @@ When a flip occurs, the cross ratios of the involved edges are modified via simp The Delaunay flip algorithm flips edges that do not satisfy the Delaunay until no more edges violate the criterion, with no preference on the order of the flips. This algorithm terminates, and outputs a Delaunay triangulation of \f$ S \f$ \cgalCite{despre2020flipping}. +\section Section_Hyperbolic_Surface_Triangulations_Epsilon_Nets ε-nets + +NEW SECTION + +\subsection Subsection_Hyperbolic_Surface_Triangulations_Epsilon_Net_Definition Definition + +The notion of \f$ \varepsilon \f$-net formalizes the idea of a "well-distributed" sampling of a metic space, in our case, a hyperbolic surface. + +Let \f$ (X, d) \f$ be a metric space and \f$ \varepsilon > 0 \f$. A subset \f$ P \subset X \f$ is: + +- an \f$ \varepsilon \f$-covering if \f$ d(x, P) \leq \varepsilon \f$ for all \f$ x \in X \f$, that is, the closed balls of radius \f$ \varepsilon \f$ centered at the points of \f$ P \f$ cover \f$ X \f$; +- an \f$ \varepsilon \f$-packing if \f$ d(p, q) \geq \varepsilon \f$ for all \f$ p \neq q \in P \f$, that is, the open balls of radius \f$ \varepsilon/2 \f$ centered at the points of \f$ P \f$ are pairwise disjoint; +- an \f$ \varepsilon \f$-net if it is both an \f$ \varepsilon \f$-covering and an \f$ \varepsilon \f$-packing. + +The `CGAL::Delaunay_triangulation_on_hyperbolic_surface_2` class contains the `CGAL::Delaunay_triangulation_on_hyperbolic_surface_2::epsilon_net()` method that tries to compute an \f$ \varepsilon \f$-net of a hyperbolic surface, starting from an \f$ \varepsilon \f$-packing (usually, a Delaunay triangulation with a single vertex). The construction might not result in an \f$ \varepsilon \f$-net (see next section), but the method returns a Boolean indicating whether the result is a certified \f$ \varepsilon \f$-net. + +If the result is not a certified \f$ \varepsilon \f$-net, the `CGAL::Delaunay_triangulation_on_hyperbolic_surface_2::is_epsilon_covering()` and `CGAL::Delaunay_triangulation_on_hyperbolic_surface_2::is_epsilon_packing()` methods can be used to diagnose which property fails. Additionally, the `CGAL::Delaunay_triangulation_on_hyperbolic_surface_2::shortest_non_loop_edge()` can be used to know the distance between the closest pair of points. + + +\subsection Subsection_Hyperbolic_Surface_Triangulations_Epsilon_Net_Numbers Number Type + +The algorithm is a Delaunay refinement algorithm that inserts the circumcenter of triangles whose circumradius is larger than \f$ \varepsilon \f$ until there is none. To ensure robustness and efficiency, this method should be used with a rational number type, such as `CGAL::Exact_rational` or `CGAL::Gmpq`. + +To avoid cascading square roots, each coordinate of a circumcenter is rounded to the number type provided by the user. There are two cases: + +- When the number type is not `CGAL::Gmpq`, each coordinate is rounded to a double precision number using the `CGAL::to_double()` function, and is then converted to the number type chosen by the user. +- When the number type is `CGAL::Gmpq`, each coordinates is rounded to a fixed precision floating-point number `CGAL::Gmpfr`. The precision of the `CGAL::Gmpfr` numbers involved is \f$ p\times 53 \f$, where \f$ p \f$ is an integer given to the `CGAL::Delaunay_triangulation_on_hyperbolic_surface_2::epsilon_net()` method and 53 is the precision of a `double`. When \f$ p = 1 \f$, it is thus equivalent to using the `CGAL::to_double()` approximation. + +The algorithm does not check whether the construction is correct on the go. Instead, it only checks the correctness at the end. This is why it can happen that the result is not a certified \f$ \varepsilon \f$-net. +The rounding method using the `CGAL::to_double()` approximation usually works for hyperbolic surfaces of genus 2 or 3 with a lage systole, but a higher precision is required to obtain a valid \f$ \varepsilon \f$-net on surfaces of higher genus. + + \section Section_Hyperbolic_Surface_Triangulations_Software_Design Software Design - The concept `ComplexNumber` describes a complex number type modeled by `CGAL::Complex_number`. Complex numbers are used to encode the cross ratios, for the coefficients of isometries and implicitly to work with points in the Poincaré disk. +The concept `ComplexNumber` describes a complex number type modeled by `CGAL::Complex_number`. Complex numbers are used to encode the cross ratios, for the coefficients of isometries and implicitly to work with points in the Poincaré disk. Most classes of the package are templated by the concept `HyperbolicSurfaceTraits_2`. It is a refinement of `HyperbolicDelaunayTriangulationTraits_2` and is modeled by `CGAL::Hyperbolic_surface_traits_2`. It defines the geometric objects (points, segments...) forming the lifted triangulation in the Poincaré disk. -The package offers three main classes: +The package offers four main classes: - `CGAL::Triangulation_on_hyperbolic_surface_2` represents a triangulation of a hyperbolic surface. It offers functions for the generation of the triangulation from a convex fundamental domain, the Delaunay flip algorithm and the construction of a portion of the lift of the triangulation in the Poincaré disk. +- `CGAL::Delaunay_triangulation_on_hyperbolic_surface_2` represents a Delaunay triangulation of a closed orientable hyperbolic surface. It offers functions for the generation of the Delaunay triangulation from a convex fundamental domain, the insertion of a point in the Delaunay triangulation, two point location algorithms and the \f$ \varepsilon \f$-net algorithm. + - `CGAL::Hyperbolic_fundamental_domain_2` represents a convex fundamental domain of a hyperbolic surface. - `CGAL::Hyperbolic_fundamental_domain_factory_2` generates random convex fundamental domains of surfaces of genus two. @@ -130,18 +174,42 @@ The package offers three main classes: The secondary class `CGAL::Hyperbolic_isometry_2` defines isometries in the Poincaré disk together with operations to work with them. -\section Visualization_Triangulation_lift Visualization of a Triangulation +\section Visualization Visualization -The function `CGAL::Triangulation_on_hyperbolic_surface_2::lift()` computes the lift of each triangle in the hyperbolic plane, enabling its visualization (see \cgalFigureRef{THS2-demo-output}). This package contains a demo (found in the folder Triangulation_on_hyperbolic_surface_2/demo), which can be used to display triangulations. +
changé titre (Visualization of a Triangulation -> Visualization)
+
This package contains several demos (found in the folder Triangulation_on_hyperbolic_surface_2/demo), which displays triangulations.
+ +The function `CGAL::Triangulation_on_hyperbolic_surface_2::lift()` computes the lift of each triangle in the hyperbolic plane, enabling its visualization (see \cgalFigureRef{THS2-demo-output}). \cgalFigureAnchor{THS2-demo-output}
\cgalFigureCaptionBegin{THS2-demo-output} - Lift, in the Poincaré disk, of a Delaunay triangulation of a genus two hyperbolic surface with one vertex. + Lift, in the Poincaré disk, of a Delaunay triangulation of a genus two hyperbolic surface with one vertex (from Triangulation_on_hyperbolic_surface_2_demo.cpp). \cgalFigureCaptionEnd +
+\cgalFigureAnchor{DTHS2-demo-output} +
+ +
+\cgalFigureCaptionBegin{DTHS2-demo-output} +Lift, in the Poincaré disk, of the Delaunay triangulation of a 0.1-net of a genus two hyperbolic surface with seed 123 (from Delaunay_triangulation_on_hyperbolic_surface_2_demo.cpp). +\cgalFigureCaptionEnd +
+ +
Additionally, the `CGAL::Dirichlet_vertices()` function can be used to display a Dirichlet domain.
+ +
+\cgalFigureAnchor{HDD2-demo-output} +
+ +
+\cgalFigureCaptionBegin{HDD2-demo-output} +Lift, in the Poincaré disk, of a Dirichlet domain of a genus two surface (from Hyperbolic_Dirichlet_domain_2_demo.cpp). +\cgalFigureCaptionEnd +
\section Section_Hyperbolic_Surface_Triangulations_Example Example @@ -152,8 +220,9 @@ The example below generates a convex fundamental domain of a surface of genus tw This package implements the Delaunay flip algorithm described in the hyperbolic setting by Vincent Despré, Jean-Marc Schlenker and Monique Teillaud in \cgalCite{despre2020flipping} using the data structure for representing triangulations presented in \cgalCite{despre2022experimental}). It also implements the generation of domains described by Vincent Despré, Loïc Dubois, Benedikt Kolbe and Monique Teillaud in \cgalCite{despre2022experimental}, based on results of Aline Aigon-Dupuy, Peter Buser, Michel Cibils, Alfred F Künzle and Frank Steiner \cgalCite{aigon2005hyperbolic}. -The code and the documentation of the package were written by Loïc Dubois, under regular discussions with Vincent Despré, Marc Pouget and Monique Teillaud. -The authors acknowledge support from the grants SoS and MIN-MAX of the French National Research Agency ANR. +It also implements the \f$ \varepsilon \f$-net algorithm presented by Vincent Despré, Camille Lanuel, Marc Pouget and Monique Teillaud in \cgalCite{cgal:dlpt-naihs-25}. TODO: citer thèse plutôt ? +The code and the documentation of the package were written by Loïc Dubois and Camille Lanuel, under regular discussions with Vincent Despré, Marc Pouget and Monique Teillaud. +The authors acknowledge support from the grants SoS, MIN-MAX and Abysm of the French National Research Agency ANR. */ } /* namespace CGAL */ diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/dependencies b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/dependencies index dbe174d8cc2..da1fae44036 100644 --- a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/dependencies +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/dependencies @@ -1,6 +1,7 @@ Manual Stream_support Number_types +Kernel_23 Combinatorial_map Hyperbolic_triangulation_2 Algebraic_foundations diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/examples.txt b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/examples.txt index 5d630b162a4..b402853a366 100644 --- a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/examples.txt +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/examples.txt @@ -1,3 +1,5 @@ /*! \example Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.cpp + +\example Triangulation_on_hyperbolic_surface_2/Delaunay_triangulation_on_hyperbolic_surface_2.cpp */ diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/123_01.svg b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/123_01.svg new file mode 100644 index 00000000000..bf0eea48ec9 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/123_01.svg @@ -0,0 +1,5278 @@ + + +/home/clanuel/Documents/123_01 +My canvas exported to Svg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/dirichlet.svg b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/dirichlet.svg new file mode 100644 index 00000000000..2964a6ed6d8 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/dirichlet.svg @@ -0,0 +1,76 @@ + + +/home/clanuel/Documents/cgal/cgal/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/dirichlet.svg +My canvas exported to Svg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Triangulation_on_hyperbolic_surface_2/examples/Triangulation_on_hyperbolic_surface_2/Delaunay_triangulation_on_hyperbolic_surface_2.cpp b/Triangulation_on_hyperbolic_surface_2/examples/Triangulation_on_hyperbolic_surface_2/Delaunay_triangulation_on_hyperbolic_surface_2.cpp new file mode 100644 index 00000000000..aa57563adce --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/examples/Triangulation_on_hyperbolic_surface_2/Delaunay_triangulation_on_hyperbolic_surface_2.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +typedef CGAL::Exact_rational Rational; +typedef CGAL::Circular_kernel_2,CGAL::Algebraic_kernel_for_circles_2_2> Kernel; +typedef CGAL::Hyperbolic_Delaunay_triangulation_CK_traits_2 ParentTraits; +typedef CGAL::Hyperbolic_surface_traits_2 Traits; +typedef CGAL::Hyperbolic_fundamental_domain_2 Domain; +typedef CGAL::Hyperbolic_fundamental_domain_factory_2 Factory; +typedef CGAL::Delaunay_triangulation_on_hyperbolic_surface_2 Delaunay_triangulation; + +int main() { + // Generates the domain: + Factory factory = Factory(); + Domain domain = factory.make_hyperbolic_fundamental_domain_g2(time(NULL)); // get a random seed with time(NULL) + + // Triangulates the domain: + Delaunay_triangulation dt = Delaunay_triangulation(domain); + + // Saves the triangulation: + std::ofstream output_file = std::ofstream ("OutputDelaunayTriangulation.txt"); + output_file << dt; + output_file.close(); + + // Prints the triangulation: + std::cout << dt << std::endl; + + return 0; +} diff --git a/Triangulation_on_hyperbolic_surface_2/examples/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.cpp b/Triangulation_on_hyperbolic_surface_2/examples/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.cpp index 910a6b7a593..623c91c8053 100644 --- a/Triangulation_on_hyperbolic_surface_2/examples/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.cpp +++ b/Triangulation_on_hyperbolic_surface_2/examples/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.cpp @@ -25,6 +25,7 @@ int main() { // Applies the Delaunay flip algorithm to the triangulation: triangulation.make_Delaunay(); + std::cout << "delaunay" << std::endl; // Saves the triangulation: std::ofstream output_file = std::ofstream ("OutputTriangulation.txt"); diff --git a/Triangulation_on_hyperbolic_surface_2/include/CGAL/Delaunay_triangulation_on_hyperbolic_surface_2.h b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Delaunay_triangulation_on_hyperbolic_surface_2.h new file mode 100644 index 00000000000..2ad41f59151 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Delaunay_triangulation_on_hyperbolic_surface_2.h @@ -0,0 +1,1125 @@ +// Copyright (c) 2025 +// INRIA Nancy (France), and Université de Lorraine (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Vincent Despré, Camille Lanuel, Marc Pouget, Monique Teillaud + +#ifndef CGAL_DELAUNAY_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_H +#define CGAL_DELAUNAY_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_H + +#include + +#include +#include +#include +#include +#include + + +namespace CGAL{ + +template +struct Delaunay_triangulation_attributes { + template + struct Dart_wrapper{ + typedef Cell_attribute> Edge_attrib; + typedef Cell_attribute>::Anchor> Face_attrib; + typedef std::tuple Attributes; + }; +}; + +template +class Delaunay_triangulation_on_hyperbolic_surface_2: public Triangulation_on_hyperbolic_surface_2> { +public: + typedef Triangulation_on_hyperbolic_surface_2> Base; + typedef Combinatorial_map<2,Delaunay_triangulation_attributes> CMap; + typedef typename Triangulation_on_hyperbolic_surface_2>::Anchor Anchor; + + typedef typename Traits::FT Number; + typedef typename Traits::Complex Complex_number; + typedef typename Traits::Hyperbolic_point_2 Point; + typedef typename CMap::Dart_descriptor Dart_descriptor; + typedef typename CMap::Dart_range Dart_range; + typedef typename CMap::template One_dart_per_cell_range<0> Vertex_range; + typedef typename CMap::template One_dart_per_cell_range<1> Edge_range; + typedef typename CMap::template One_dart_per_cell_range<2> Face_range; + typedef typename CMap::Dart_const_descriptor Dart_const_descriptor; + typedef typename CMap::Dart_const_range Dart_const_range; + typedef typename CMap::template One_dart_per_cell_const_range<1> Edge_const_range; + typedef typename CMap::template One_dart_per_cell_const_range<2> Face_const_range; + + // undocumented types + typedef typename Root_of_traits::Root_of_2 Algebraic_number; + typedef typename Traits::Hyperbolic_Voronoi_point_2 Voronoi_point; + typedef Hyperbolic_isometry_2 Isometry; + typedef boost::numeric::interval Interval; + + enum Locate_type { + VERTEX = 0, + EDGE, + FACE, + OUTSIDE + }; + + //---------- CONSTRUCTORS + Delaunay_triangulation_on_hyperbolic_surface_2() {}; + Delaunay_triangulation_on_hyperbolic_surface_2(CMap & cmap, Anchor & anch); + Delaunay_triangulation_on_hyperbolic_surface_2(Hyperbolic_fundamental_domain_2 const & domain); + Delaunay_triangulation_on_hyperbolic_surface_2(Base & triangulation); + + //---------- UTILITIES + Anchor & anchor(Dart_descriptor const dart); + Anchor const & anchor(Dart_const_descriptor const dart) const; + Anchor & anchor(); + Anchor const & anchor() const; + unsigned index_in_anchor(Dart_const_descriptor const dart) const; + Dart_descriptor ith_dart(unsigned i, Anchor const & anch); + bool is_valid() const; + + // undocumented + void to_stream(std::ostream & s) const; + void from_stream(std::istream & s); + + //---------- location and insertion + Locate_type relative_position(Point const & query, unsigned & li, Anchor const & anch) const; + Anchor locate(Point const & query, bool use_visibility = false); // const ? + Anchor locate(Point const & query, Locate_type & lt, unsigned & li, unsigned & ld, Anchor const & hint, bool use_visibility = false); // const ? + + //---------- Delaunay related methods + void insert(Point const & query, Anchor & hint); + void insert(Point const & query); + + //---------- eps-net methods + bool epsilon_net(double const epsilon, unsigned const p = 1); + bool is_epsilon_covering(const double epsilon) const; + bool is_epsilon_packing(const double epsilon) const; + bool is_epsilon_net(const double epsilon) const; + + double shortest_loop_edge() const; + double shortest_non_loop_edge() const; + +private: + unsigned const NULL_INDEX = -1; + unsigned const NB_SIDES = 3; + unsigned const DOUBLE_PREC = 53; + + //---------- CONSTRUCTORS + void set_anchors(); + + //---------- UTILITIES + unsigned ccw(unsigned i) const; + unsigned cw(unsigned i) const; + void set_attribute(Dart_descriptor dart, Anchor const & anchor); + void set_attribute(Dart_descriptor dart, Complex_number const & cross_ratio); + void update_infos(Dart_descriptor dart, Point const & r, Point const & s, Point const & t, Point const & query); + + //---------- location and insertion + Anchor locate_visibility_walk(Point const & query, Locate_type & lt, unsigned & li, unsigned & ld, Anchor const & hint); // const ? + Anchor locate_straight_walk(Point const & query, Locate_type & lt, unsigned & li, unsigned & ld, Anchor const & hint); // const ? + std::vector insert_in_face(Point const & query, Anchor & anch); // return dart_descriptor + std::vector insert_in_edge(Point const & query, unsigned & li, Anchor & anch); + std::vector split_insert(Point const & query, Anchor & anch, bool use_visibility = false); + + //---------- Delaunay related methods + void flip(Dart_descriptor dart); + unsigned make_Delaunay(); + void push_flippable_edge(Dart_descriptor const dart, std::list & darts_to_flip); + unsigned restore_Delaunay(std::list & darts_to_flip, std::vector & flipped_darts); + + //---------- eps-net methods + Number delta(Point const & u, Point const & v) const; + auto delta_center(Voronoi_point const & u, Point const & v) const; + Voronoi_point circumcenter(Anchor const & anch) const; + Point approx_circumcenter(Voronoi_point c, unsigned p = 1) const; + void push_triangle(Dart_descriptor const dart, std::list & triangles, size_t & triangles_list_mark); +}; + + +//---------- CONSTRUCTORS + +template +Delaunay_triangulation_on_hyperbolic_surface_2:: +Delaunay_triangulation_on_hyperbolic_surface_2(CMap & cmap, Anchor & anch) +: Base(cmap, anch) +{ + Base::make_Delaunay(); + set_anchors(); +} + +template +Delaunay_triangulation_on_hyperbolic_surface_2:: +Delaunay_triangulation_on_hyperbolic_surface_2(Hyperbolic_fundamental_domain_2 const & domain) +: Base(domain) +{ + Base::make_Delaunay(); + set_anchors(); +} + +template +Delaunay_triangulation_on_hyperbolic_surface_2:: +Delaunay_triangulation_on_hyperbolic_surface_2(Base & triangulation) +: Base(triangulation.combinatorial_map(), triangulation.anchor()) +{ + Base::make_Delaunay(); + set_anchors(); +} + +// only used in constructors +template +void +Delaunay_triangulation_on_hyperbolic_surface_2:: +set_anchors() +{ + CMap & cmap = this->combinatorial_map_; + + std::queue bfs_queue; + size_t in_queue = cmap.get_new_mark(); + cmap.unmark_all(in_queue); + bfs_queue.push(this->anchor_); + cmap.mark(this->anchor_.dart, in_queue); + cmap.mark(Base::ccw(this->anchor_.dart), in_queue); + cmap.mark(Base::cw(this->anchor_.dart), in_queue); + + while (!bfs_queue.empty()) { + Anchor & current = bfs_queue.front(); + set_attribute(current.dart, current); + Dart_descriptor invader = current.dart; + for (int i = 0; i < 3; i++) { + Dart_descriptor invaded = Base::opposite(invader); + if (!cmap.is_marked(invaded, in_queue)) { + Complex_number cross_ratio = Base::get_cross_ratio(invader); + Point & c = current.vertices[i % 3]; + Point & a = current.vertices[(i + 1) % 3]; + Point & b = current.vertices[(i + 2) % 3]; + CGAL_assertion_code(Traits gt;); + CGAL_assertion(gt.is_Delaunay_hyperbolic_2_object()(a, b, c)); + Point d = Base::fourth_point_from_cross_ratio(a, b, c, cross_ratio); + CGAL_assertion(norm(Complex_number(d.x(), d.y())) < Number(1)); + bfs_queue.push(Anchor(invaded, a, c, d)); + cmap.mark(invaded, in_queue); + cmap.mark(Base::ccw(invaded), in_queue); + cmap.mark(Base::cw(invaded), in_queue); + } + invader = Base::ccw(invader); + } + bfs_queue.pop(); + } + cmap.free_mark(in_queue); + + this->anchor_ = Anchor(); + this->has_anchor_ = false; + CGAL_assertion(is_valid()); +} + + +//---------- UTILITIES + +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Anchor& +Delaunay_triangulation_on_hyperbolic_surface_2:: +anchor(Dart_descriptor const dart) +{ + return this->combinatorial_map_.template info<2>(dart); +} + +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Anchor const & +Delaunay_triangulation_on_hyperbolic_surface_2:: +anchor(Dart_const_descriptor const dart) const +{ + return this->combinatorial_map_.template info<2>(dart); +} + +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Anchor & +Delaunay_triangulation_on_hyperbolic_surface_2:: +anchor() +{ + return anchor(this->combinatorial_map_.darts().begin()); +} + +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Anchor const & +Delaunay_triangulation_on_hyperbolic_surface_2:: +anchor() const +{ + return anchor(this->combinatorial_map_.darts().begin()); +} + +template +unsigned +Delaunay_triangulation_on_hyperbolic_surface_2:: +index_in_anchor(Dart_const_descriptor const dart) const +{ + unsigned index = NULL_INDEX; + Anchor const & anch = anchor(dart); + Dart_const_descriptor current_dart = anch.dart; + for (unsigned i = 0; i < NB_SIDES; ++i) { + if (current_dart == dart) { + index = i; + break; + } + current_dart = Base::const_ccw(current_dart); + } + CGAL_assertion(index != NULL_INDEX); + return index; +} + +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Dart_descriptor +Delaunay_triangulation_on_hyperbolic_surface_2:: +ith_dart(unsigned i, Anchor const & anch) +{ + Dart_descriptor dart = anch.dart; + for (unsigned j = 0; j < i; ++j) { + dart = Base::ccw(dart); + } + return dart; +} + +template +unsigned +Delaunay_triangulation_on_hyperbolic_surface_2:: +ccw(unsigned i) const +{ + CGAL_precondition( i <= NB_SIDES); + return (i + 1) % NB_SIDES; +} + +template +unsigned +Delaunay_triangulation_on_hyperbolic_surface_2:: +cw(unsigned i) const +{ + CGAL_precondition( i <= NB_SIDES); + return (i + 2) % NB_SIDES; +} + +template +void +Delaunay_triangulation_on_hyperbolic_surface_2:: +set_attribute(Dart_descriptor dart, Anchor const & anchor) +{ + this->combinatorial_map_.template set_attribute<2>(dart, + this->combinatorial_map_.template create_attribute<2>(anchor)); +} + +template +void +Delaunay_triangulation_on_hyperbolic_surface_2:: +set_attribute(Dart_descriptor dart, Complex_number const & cross_ratio) +{ + this->combinatorial_map_.template set_attribute<1>(dart, + this->combinatorial_map_.template create_attribute<1>(cross_ratio)); +} + +template +bool +Delaunay_triangulation_on_hyperbolic_surface_2:: +is_valid() const +{ + CGAL_assertion(Base::is_Delaunay()); + if (!Base::is_Delaunay()) { + return false; + } + + for (typename Face_const_range::const_iterator it = Base::faces_const_range().begin(); it != Base::faces_const_range().end(); ++it) { + Anchor const & current = anchor(it); + Dart_const_descriptor current_dart = current.dart; + + for (unsigned i = 0; i < NB_SIDES; ++i) { + Dart_const_descriptor opposite_dart = Base::const_opposite(current_dart); + Point const & c1 = current.vertices[i]; + Point const & a1 = current.vertices[ccw(i)]; + Point const & b1 = current.vertices[cw(i)]; + CGAL_assertion(norm(Complex_number(a1.x(), a1.y())) < Number(1)); + CGAL_assertion(norm(Complex_number(b1.x(), b1.y())) < Number(1)); + CGAL_assertion(norm(Complex_number(c1.x(), c1.y())) < Number(1)); + Complex_number cross_ratio = Base::get_cross_ratio(current_dart); + Point d1 = Base::fourth_point_from_cross_ratio(a1, b1, c1, cross_ratio); + + unsigned j = index_in_anchor(opposite_dart); + Anchor const & neighbor = anchor(opposite_dart); + Point const & a2 = neighbor.vertices[j]; + Point const & c2 = neighbor.vertices[ccw(j)]; + Isometry pair_sides = isometry_pairing_the_sides(a2, c2, a1, c1); + CGAL_assertion(pair_sides.evaluate(a2) == a1); + CGAL_assertion(pair_sides.evaluate(c2) == c1); + + Point d2 = pair_sides.evaluate(neighbor.vertices[cw(j)]); + CGAL_assertion(d2 == d1); + if (d2 != d1) { + return false; + } + current_dart = Base::const_ccw(current_dart); + } + } + return true; +} + +template +void +Delaunay_triangulation_on_hyperbolic_surface_2:: +to_stream(std::ostream & s) const +{ + CGAL_precondition(is_valid()); + + // Give indices to the darts + std::map darts_ids; + unsigned current_dart_id = 0; + for (typename Dart_const_range::const_iterator it=this->combinatorial_map_.darts().begin(); it!=this->combinatorial_map_.darts().end(); ++it) { + darts_ids[it] = current_dart_id; + current_dart_id++; + } + + // Store the number of darts + s << current_dart_id << std::endl; + + // Store the triangles and their anchor + for (typename Face_const_range::const_iterator it = Base::faces_const_range().begin(); it != Base::faces_const_range().end(); ++it) { + s << darts_ids[it] << std::endl; + s << darts_ids[Base::const_cw(it)] << std::endl; + s << darts_ids[Base::const_ccw(it)] << std::endl; + Anchor anch = anchor(it); + s << darts_ids[anch.dart] << std::endl; + for(int i = 0; i < NB_SIDES ; ++i) { + s << anch.vertices[i].x() << std::endl; + s << anch.vertices[i].y() << std::endl; + } + } + + // Store the edges and their cross-ratio + for (typename Edge_const_range::const_iterator it = Base::edges_const_range().begin(); it != Base::edges_const_range().end(); ++it) { + s << darts_ids[it] << std::endl; + s << darts_ids[Base::const_opposite(it)] << std::endl; + s << Base::get_cross_ratio(it); + } +} + +template +void +Delaunay_triangulation_on_hyperbolic_surface_2:: +from_stream(std::istream & s) +{ + this->combinatorial_map_.clear(); + + // Load the number of darts + std::string line; + s >> line; + int nb_darts = std::stoi(line); + + // Load the triangles and the anchors + Dart_descriptor darts_by_id[nb_darts]; + for (int k = 0; k < nb_darts / NB_SIDES; ++k) { + Dart_descriptor triangle_dart = this->combinatorial_map_.make_combinatorial_polygon(3); + s >> line; + int id_0 = std::stoi(line); + s >> line; + int id_1 = std::stoi(line); + s >> line; + int id_2 = std::stoi(line); + darts_by_id[id_0] = triangle_dart; + darts_by_id[id_1] = Base::cw(triangle_dart); + darts_by_id[id_2] = Base::ccw(triangle_dart); + + Anchor anch = Anchor(); + s >> line; + anch.dart = darts_by_id[std::stoi(line)]; + for(int i = 0; i < NB_SIDES; ++i) { + Number x; + s >> x; + Number y; + s >> y; + anch.vertices[i] = Point(x, y); + } + set_attribute(anch.dart, anch); + } + + // Load the edges + for (int k = 0; k < nb_darts / 2; ++k) { + s >> line; + int id_0 = std::stoi(line); + s >> line; + int id_1 = std::stoi(line); + Dart_descriptor dart_0 = darts_by_id[id_0]; + Dart_descriptor dart_1 = darts_by_id[id_1]; + this->combinatorial_map_.template sew<2>(dart_0, dart_1); + Complex_number cross_ratio; + s >> cross_ratio; + set_attribute(dart_0, cross_ratio); + } + + CGAL_assertion(is_valid()); +} + +//---------- location and insertion + +// Output: The locate type lt of query relative to the anchor, and an index corresponding to: +// - if lt == FACE: NULL_INDEX, +// - if lt == EDGE: index of the edge on which query lies, +// - if lt == VERTEX: index of the vertex on which query lies, +// - if lt == OUTSIDE: index of the first edge such that query and the third point of the triangle lies on different sides. +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Locate_type +Delaunay_triangulation_on_hyperbolic_surface_2:: +relative_position(Point const & query, unsigned & li, Anchor const & anch) const +{ + Locate_type lt = FACE; + li = NULL_INDEX; + Traits gt; + typename Traits::Hyperbolic_orientation_2 ho2 = gt.hyperbolic_orientation_2(); + for (unsigned i = 0; i < NB_SIDES; ++i) { + Orientation ori_query = ho2(anch.vertices[i], anch.vertices[ccw(i)], query); + if (ori_query == RIGHT_TURN) { + lt = OUTSIDE; + li = i; + break; + } + if (ori_query == COLLINEAR) { + lt = EDGE; + li = i; + if (ho2(anch.vertices[ccw(i)], anch.vertices[cw(i)], query) == COLLINEAR) { + lt = VERTEX; + li = ccw(i); + break; + } + } + } + return lt; +} + +// Output: an anchor of the triangle in which query lies, +// and an int corresponding to the number of traversed triangles to find it. +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Anchor +Delaunay_triangulation_on_hyperbolic_surface_2:: +locate_visibility_walk(Point const & query, Locate_type & lt, unsigned & li, unsigned & ld, Anchor const & hint) +{ + CGAL_precondition(norm(Complex_number(query.x(), query.y())) < Number(1)); + CGAL_expensive_precondition(is_valid()); + + // initialisation + ld = 0; + lt = relative_position(query, li, hint); + if (lt != OUTSIDE){ + return hint; + } + + bool found = false; + Dart_descriptor dart = ith_dart(li, hint); + Point c = hint.vertices[li]; + Point a = hint.vertices[ccw(li)]; + Point b = hint.vertices[cw(li)]; + Point d; + + // visibility walk + Traits gt; + typename Traits::Hyperbolic_orientation_2 ho2 = gt.hyperbolic_orientation_2(); + while (!found) { + Complex_number cross_ratio = Base::get_cross_ratio(dart); + d = Base::fourth_point_from_cross_ratio(a, b, c, cross_ratio); + dart = Base::opposite(dart); + if (ho2(c, d, query) == RIGHT_TURN){ + b = a; + a = d; + dart = Base::ccw(dart); + } else if (ho2(a, d, query) == LEFT_TURN) { + b = c; + c = d; + dart = Base::cw(dart); + } else { + found = true; + } + ++ld; + } + Anchor res = Anchor(dart, a, c, d); + lt = relative_position(query, li, res); + CGAL_assertion(lt != OUTSIDE); + return res; +} + +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Anchor +Delaunay_triangulation_on_hyperbolic_surface_2:: +locate_straight_walk(Point const & query, Locate_type & lt, unsigned & li, unsigned & ld, Anchor const & hint) +{ + CGAL_precondition(norm(Complex_number(query.x(), query.y())) < Number(1)); + + // initialisation + Dart_descriptor dart = hint.dart; + Point p0 = hint.vertices[0]; + Point r = hint.vertices[1]; + Point l = hint.vertices[2]; + ld = 0; + Traits gt; + typename Traits::Hyperbolic_orientation_2 ho2 = gt.hyperbolic_orientation_2(); + + if (ho2(p0, query, r) == RIGHT_TURN) { + while (ho2(p0, query, l) == RIGHT_TURN) { + dart = Base::opposite(Base::cw(dart)); + Point old_l = l; + l = Base::fourth_point_from_cross_ratio(p0, r, l, Base::get_cross_ratio(dart)); + r = old_l; + ++ld; + } + } else { + while (ho2(p0, query, r) == LEFT_TURN) { + Point old_r = r; + r = Base::fourth_point_from_cross_ratio(r, l, p0, Base::get_cross_ratio(dart)); + l = old_r; + dart = Base::ccw(Base::opposite(dart)); + ++ld; + } + } + + // straight walk + dart = Base::ccw(dart); + Point p = p0; + while (ho2(r, l, query) == RIGHT_TURN) { + Complex_number cross_ratio = Base::get_cross_ratio(dart); + Point s = Base::fourth_point_from_cross_ratio(l, p, r, cross_ratio); + if (ho2(p0, query, s) == RIGHT_TURN) { + p = r; + r = s; + dart = Base::cw(Base::opposite(dart)); + } else { + p = l; + l = s; + dart = Base::ccw(Base::opposite(dart)); + } + ++ld; + } + Anchor res = Anchor(dart, r, l, p); + lt = relative_position(query, li, res); + CGAL_assertion(lt != OUTSIDE); + return res; +} + +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Anchor +Delaunay_triangulation_on_hyperbolic_surface_2:: +locate(Point const & query, bool use_visibility) +{ + Locate_type lt = OUTSIDE; + unsigned li = 0; + unsigned ld = 0; + return locate(query, lt, li, ld, anchor(), use_visibility); +} + +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Anchor +Delaunay_triangulation_on_hyperbolic_surface_2:: +locate(Point const & query, Locate_type & lt, unsigned & li, unsigned & ld, Anchor const & hint, bool use_visibility) +{ + if (use_visibility) { + return locate_visibility_walk(query, lt, li, ld, hint); + } else { + return locate_straight_walk(query, lt, li, ld, hint); + } +} + +// Input: dart whose cross-ratio is those of the edge [t, r] and is computed with s and a fourth vertex. +// Output: modified anchor such that its vertices are {r, query, t} and its dart represents the edge between r and t. +// The cross-ratio of the edge [t, r] is updated with its value where query is replaced by s. +// The cross-ratio of the edge [r, q] is set. +// Warning: the other cross-ratios are not updated, they will be in insert_in_edge and insert_in_face. +template +void +Delaunay_triangulation_on_hyperbolic_surface_2:: +update_infos(Dart_descriptor dart, Point const & r, Point const & s, Point const & t, Point const & query) +{ + // compute new cross-ratio + Complex_number old_cr = Base::get_cross_ratio(dart); + Point u = Base::fourth_point_from_cross_ratio(r, s, t, old_cr); + Complex_number new_cr = Base::cross_ratio(r, query, t, u); + + // modify anch and cross-ratio + std::shared_ptr anch = std::make_shared(anchor(dart)); + anch->dart = dart; + this->combinatorial_map_.template info<1>(dart) = new_cr; + anch->vertices[0] = t; + anch->vertices[1] = r; + anch->vertices[2] = query; + this->combinatorial_map_.template info<2>(dart) = *anch; + + set_attribute(Base::ccw(dart), Base::cross_ratio(query, t, r, s)); +} + +// Output: the three anchors incident to query after its insertion inside anch. +// the darts of the new anchors correspond to the edges of the triangle the point was inserted in +// Note to self: No need to manage triangulation's anchor as it is done in update_infos. +template +std::vector::Dart_descriptor> +Delaunay_triangulation_on_hyperbolic_surface_2:: +insert_in_face(Point const & query, Anchor & anch) +{ + Dart_descriptor current_dart = anch.dart; + this->combinatorial_map_.insert_cell_0_in_cell_2(anch.dart); + std::vector darts_of_new_anchors; + for (unsigned i = 0; i < NB_SIDES; ++i) { + Point & c = anch.vertices[i]; + Point & a = anch.vertices[ccw(i)]; + Point & b = anch.vertices[cw(i)]; + update_infos(current_dart, a, b, c, query); + darts_of_new_anchors.push_back(current_dart); + current_dart = Base::ccw(Base::opposite(Base::ccw(current_dart))); + } + + return darts_of_new_anchors; +} + +// Output: the four anchors incident to query after its insertion on one edge of anch. +// the darts of the new anchors correspond to the edges of the triangle the point was inserted in +template +std::vector::Dart_descriptor> +Delaunay_triangulation_on_hyperbolic_surface_2:: +insert_in_edge(Point const & query, unsigned & li, Anchor & anch) +{ + // find dart on which we insert query + Dart_descriptor insertion_dart = ith_dart(li, anch); + + // gather information + std::vector darts_of_new_anchors; + Point & c = anch.vertices[li]; + Point & a = anch.vertices[ccw(li)]; + Point & b = anch.vertices[cw(li)]; + Complex_number cross_ratio = Base::get_cross_ratio(insertion_dart); + Point d = Base::fourth_point_from_cross_ratio(a, b, c, cross_ratio); + + Dart_descriptor dart_ab = Base::ccw(insertion_dart); + Dart_descriptor dart_bc = Base::ccw(dart_ab); + Dart_descriptor dart_cd = Base::ccw(Base::opposite(insertion_dart)); + Dart_descriptor dart_da = Base::ccw(dart_cd); + + // insert vertex on edge in the cmap and create new triangles + this->combinatorial_map_.insert_cell_0_in_cell_1(insertion_dart); + this->combinatorial_map_.insert_cell_1_in_cell_2(dart_bc, Base::cw(dart_ab)); + this->combinatorial_map_.insert_cell_1_in_cell_2(dart_da, Base::cw(dart_cd)); + CGAL_assertion(Base::ccw(dart_ab) == Base::opposite(Base::cw(dart_bc))); + CGAL_assertion(Base::ccw(dart_bc) == Base::opposite(Base::cw(dart_cd))); + CGAL_assertion(Base::ccw(dart_cd) == Base::opposite(Base::cw(dart_da))); + CGAL_assertion(Base::ccw(dart_da) == Base::opposite(Base::cw(dart_ab))); + + // set new anchors and cross-ratios + update_infos(dart_ab, b, c, a, query); + update_infos(dart_bc, c, a, b, query); + update_infos(dart_cd, d, a, c, query); + update_infos(dart_da, a, c, d, query); + + darts_of_new_anchors.push_back(dart_ab); + darts_of_new_anchors.push_back(dart_bc); + darts_of_new_anchors.push_back(dart_cd); + darts_of_new_anchors.push_back(dart_da); + + return darts_of_new_anchors; +} + +// the darts of the new anchors correspond to the edges of the triangle the point was inserted in +template +std::vector::Dart_descriptor> +Delaunay_triangulation_on_hyperbolic_surface_2:: +split_insert(Point const & query, Anchor & anch, bool use_visibility) +{ + Locate_type lt = OUTSIDE; + unsigned li = 0; + unsigned ld = 0; + Anchor locate_anchor = locate(query, lt, li, ld, anch, use_visibility); + CGAL_precondition(lt != OUTSIDE); + + std::vector darts_of_new_anchors; + if (lt == FACE) { + darts_of_new_anchors = insert_in_face(query, locate_anchor); + } else if (lt == EDGE) { + darts_of_new_anchors = insert_in_edge(query, li, locate_anchor); + } + return darts_of_new_anchors; +} + + +//---------- Delaunay related methods + +template +void +Delaunay_triangulation_on_hyperbolic_surface_2:: +flip(Dart_descriptor dart) +{ + CGAL_expensive_precondition(is_valid()); + CGAL_precondition(!Base::has_anchor()); + + // first gather all the information needed + Dart_descriptor opposite = Base::opposite(dart); + Anchor & anch = anchor(dart); + + unsigned index = index_in_anchor(dart); + Point & C = anch.vertices[index]; + Point & A = anch.vertices[ccw(index)]; + Point & B = anch.vertices[cw(index)]; + Complex_number cross_ratio = Base::get_cross_ratio(dart); + Point D = Base::fourth_point_from_cross_ratio(A, B, C, cross_ratio); + + // flip the edge in the cmap and update the cross-ratios + Base::flip(dart); // AC -> BD + + // update the two anchors + // WARNING: do not update dart's anchor first, + // else it will change vertices' values (due to refs) and cause errors + this->combinatorial_map_.template info<2>(opposite) = Anchor(opposite, D, B, C); + this->combinatorial_map_.template info<2>(dart) = Anchor(dart, B, D, A); + + CGAL_expensive_assertion(is_valid()); +} + +// Pushes dart in the list darts_to_flip if dart is flippable and is not already in the list +template +void +Delaunay_triangulation_on_hyperbolic_surface_2:: +push_flippable_edge(Dart_descriptor const dart, std::list& darts_to_flip) +{ + if (Base::is_Delaunay_flippable(dart)) { + bool already_there = false; + for (Dart_descriptor const & dart_to_flip : darts_to_flip) { + if (dart_to_flip == dart || dart_to_flip == Base::opposite(dart)) { + already_there = true; + break; + } + } + if (!already_there) { + darts_to_flip.push_back(dart); + } + } +} + +// Output: number of flips done to make the triangulation Delaunay given a list of darts to flip +template +unsigned +Delaunay_triangulation_on_hyperbolic_surface_2:: +restore_Delaunay(std::list & darts_to_flip, std::vector & flipped_darts) +{ + unsigned nb_of_flips_done = 0; + while (!darts_to_flip.empty()) { + Dart_descriptor current_dart = darts_to_flip.front(); + if (Base::is_Delaunay_flippable(current_dart)) { + flip(current_dart); + flipped_darts.push_back(current_dart); + ++nb_of_flips_done; + Dart_descriptor maybe_flippable[4] = {Base::ccw(current_dart), Base::cw(current_dart), + Base::ccw(Base::opposite(current_dart)), Base::cw(Base::opposite(current_dart))}; + for (int i = 0; i < 4; ++i) { + push_flippable_edge(maybe_flippable[i], darts_to_flip); + } + } + darts_to_flip.pop_front(); + } + + CGAL_expensive_assertion(is_valid()); + CGAL_expensive_assertion(Base::is_Delaunay()); + return nb_of_flips_done; +} + +template +unsigned +Delaunay_triangulation_on_hyperbolic_surface_2:: +make_Delaunay() +{ + unsigned number_of_flips_done = 0; + + Dart_descriptor edge_to_flip = Base::pick_edge_to_flip(); + while (edge_to_flip != nullptr) { + flip(edge_to_flip); + edge_to_flip = Base::pick_edge_to_flip(); + number_of_flips_done++; + } + + CGAL_expensive_assertion(is_valid()); + CGAL_expensive_assertion(Base::is_Delaunay()); + return number_of_flips_done; +} + +// Inserts query in the triangulation, with a search starting from the given anchor, and restores the Delaunay property with flips +template +void +Delaunay_triangulation_on_hyperbolic_surface_2:: +insert(Point const & query, Anchor & hint) +{ + CGAL_precondition(norm(Complex_number(query.x(), query.y())) < Number(1)); + CGAL_expensive_precondition(is_valid()); + + std::vector darts_of_new_anchors = split_insert(query, hint); + std::list darts_to_flip; + for (Dart_descriptor dart : darts_of_new_anchors) { + push_flippable_edge(darts_of_new_anchors, darts_to_flip); + push_flippable_edge(Base::ccw(darts_of_new_anchors), darts_to_flip); + } + std::vector flipped_darts; + restore_Delaunay(darts_to_flip, flipped_darts); +} + +// Same but the search starts from main anchor +template +void +Delaunay_triangulation_on_hyperbolic_surface_2:: +insert(Point const & query) +{ + insert(query, anchor()); +} + + +//---------- eps-net methods + +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Number +Delaunay_triangulation_on_hyperbolic_surface_2:: +delta(Point const & u, Point const & v) const +{ + Number num = (u.x() - v.x()) * (u.x() - v.x()) + (u.y() - v.y()) * (u.y() - v.y()); + Number den = (1 - (u.x() * u.x() + u.y() * u.y())) * (1 - (v.x() * v.x() + v.y() * v.y())); + return 2 * num / den; +} + +template +auto +Delaunay_triangulation_on_hyperbolic_surface_2:: +delta_center(Voronoi_point const & u, Point const & v) const +{ + Algebraic_number num = (u.x() - v.x()) * (u.x() - v.x()) + (u.y() - v.y()) * (u.y() - v.y()); + Algebraic_number den = (1 - (u.x() * u.x() + u.y() * u.y())) * (1 - (v.x() * v.x() + v.y() * v.y())); + return 2 * num / den; +} + +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Voronoi_point +Delaunay_triangulation_on_hyperbolic_surface_2:: +circumcenter(Anchor const & anch) const +{ + Traits gt; + CGAL_precondition(gt.is_Delaunay_hyperbolic_2_object()(anch.vertices[0], anch.vertices[1], anch.vertices[2])); + typename Traits::Construct_hyperbolic_circumcenter_2 chc = gt.construct_hyperbolic_circumcenter_2_object(); + return chc(anch.vertices[0], anch.vertices[1], anch.vertices[2]); +} + +template +typename Delaunay_triangulation_on_hyperbolic_surface_2::Point +Delaunay_triangulation_on_hyperbolic_surface_2:: +approx_circumcenter(Voronoi_point c, unsigned p) const +{ + Number x; + Number y; + if constexpr(std::is_same::value) { + CGAL_precondition(p > 0); + p *= DOUBLE_PREC; + Gmpfr a_0 = Gmpfr( c.x().a0().numerator(), p) / Gmpfr( c.x().a0().denominator(), p); + Gmpfr a_1 = Gmpfr( c.x().a1().numerator(), p) / Gmpfr( c.x().a1().denominator(), p); + Gmpfr r = Gmpfr( c.x().root().numerator(), p) / Gmpfr( c.x().root().denominator(), p); + x = a_0 + a_1 * sqrt(r); + a_0 = Gmpfr( c.y().a0().numerator(), p) / Gmpfr( c.y().a0().denominator(), p); + a_1 = Gmpfr( c.y().a1().numerator(), p) / Gmpfr( c.y().a1().denominator(), p); + r = Gmpfr( c.y().root().numerator(), p) / Gmpfr( c.y().root().denominator(), p); + y = a_0 + a_1 * sqrt(r); + } else { + x = to_double(c.x()); + y = to_double(c.y()); + } + + CGAL_assertion(norm(Complex_number(x, y)) < Number(1)); + Point approx = Point(x, y); + return approx; +} + +template +void +Delaunay_triangulation_on_hyperbolic_surface_2:: +push_triangle(Dart_descriptor const dart, std::list & triangles, size_t & triangles_list_mark) +{ + this->combinatorial_map_.unmark(Base::ccw(dart), triangles_list_mark); + this->combinatorial_map_.unmark(Base::cw(dart), triangles_list_mark); + this->combinatorial_map_.mark(dart, triangles_list_mark); + triangles.push_back(dart); +} + +template +bool +Delaunay_triangulation_on_hyperbolic_surface_2:: +epsilon_net(double const epsilon, unsigned const p) +{ + CGAL_precondition(is_epsilon_packing(epsilon)); + CGAL_precondition(p > 0); + Interval const delta_epsilon = cosh(epsilon) - 1; + Number const BOUND = upper(delta_epsilon); + size_t triangles_list_mark = this->combinatorial_map_.get_new_mark(); + + std::list triangles; + for (typename Face_range::iterator it = this->combinatorial_map_.template one_dart_per_cell<2>().begin(); + it != this->combinatorial_map_.template one_dart_per_cell<2>().end(); ++it) { + push_triangle(it, triangles, triangles_list_mark); + } + + while (!triangles.empty()) { + Dart_descriptor current_dart = triangles.front(); + Anchor & current_anchor = anchor(current_dart); + triangles.pop_front(); + if(this->combinatorial_map_.is_marked(current_dart, triangles_list_mark)){ + this->combinatorial_map_.unmark(current_dart, triangles_list_mark); + Voronoi_point c = circumcenter(current_anchor); + if (delta_center(c, current_anchor.vertices[0]) > BOUND) { + Point approx_c = approx_circumcenter(c, p); + if(norm(Complex_number(approx_c.x(), approx_c.y())) >= Number(1)) { + break; // avoid undefined behavior in case of bad approx outside of Poincaré + } + std::vector darts_of_new_anchors = split_insert(approx_c, current_anchor, true); + std::list darts_to_flip; + for (Dart_descriptor const & dart : darts_of_new_anchors) { + push_triangle(dart, triangles, triangles_list_mark); + push_flippable_edge(dart, darts_to_flip); + push_flippable_edge(Base::ccw(dart), darts_to_flip); + } + + std::vector flipped_darts; + restore_Delaunay(darts_to_flip, flipped_darts); + for (Dart_descriptor const & dart : flipped_darts) { + push_triangle(dart, triangles, triangles_list_mark); + push_triangle(Base::opposite(dart), triangles, triangles_list_mark); + } + } + } + } + this->combinatorial_map_.free_mark(triangles_list_mark); + + bool is_covering = is_epsilon_covering(epsilon); + bool is_packing = is_epsilon_packing(epsilon); + CGAL_assertion(is_covering); + CGAL_assertion(is_packing); + return is_covering && is_packing; +} + +template +bool +Delaunay_triangulation_on_hyperbolic_surface_2:: +is_epsilon_covering(const double epsilon) const +{ + Interval delta_epsilon = cosh(epsilon) - 1; + Number lower_bound = Number(lower(delta_epsilon)); + bool is_covering = true; + for (typename Face_const_range::const_iterator it = this->combinatorial_map_.template one_dart_per_cell<2>().begin(); + it != this->combinatorial_map_.template one_dart_per_cell<2>().end(); ++it) { + Anchor const & current_anchor = anchor(it); + + Traits gt; + typename Traits::Construct_hyperbolic_circumcenter_2 chc = gt.construct_hyperbolic_circumcenter_2_object(); + Voronoi_point c = chc(current_anchor.vertices[0], current_anchor.vertices[1], current_anchor.vertices[2]); + Point v0 = current_anchor.vertices[0]; + auto d = delta_center(c, v0); + if (!(d <= lower_bound)) { + is_covering = false; + break; + } + } + return is_covering; +} + +template +bool +Delaunay_triangulation_on_hyperbolic_surface_2:: +is_epsilon_packing(const double epsilon) const +{ + Interval delta_epsilon = cosh(epsilon)-1; + bool is_packing = true; + for (typename Edge_const_range::const_iterator it = this->combinatorial_map_.template one_dart_per_cell<1>().begin(); + it != this->combinatorial_map_.template one_dart_per_cell<1>().end(); ++it) { + Anchor const & current_anchor = anchor(it); + unsigned index = index_in_anchor(it); + Point const & a = current_anchor.vertices[index]; + Point const & b = current_anchor.vertices[ccw(index)]; + + if (delta(a, b) < lower(delta_epsilon)) { + is_packing = false; // consider that it's not a packing + + // check if the edge is a loop + Dart_const_descriptor next = Base::const_ccw(it); + auto doc = this->combinatorial_map_.template darts_of_cell<0>(it); + for (auto dart = doc.begin(); dart != doc.end(); ++dart) { + if (next == dart) { + is_packing = true; // the edge is a loop, so actually it's ok + } + } + } + } + return is_packing; +} + +template +bool +Delaunay_triangulation_on_hyperbolic_surface_2:: +is_epsilon_net(const double epsilon) const +{ + return is_epsilon_covering(epsilon) && is_epsilon_packing(epsilon); +} + +template +double +Delaunay_triangulation_on_hyperbolic_surface_2:: +shortest_loop_edge() const +{ + Number min_delta_length = 999; + double res = NULL; + for (typename Edge_const_range::const_iterator it = this->combinatorial_map_.template one_dart_per_cell<1>().begin(); + it != this->combinatorial_map_.template one_dart_per_cell<1>().end(); ++it) { + Anchor const & current_anchor = anchor(it); + unsigned index = index_in_anchor(it); + Point const & a = current_anchor.vertices[index]; + Point const & b = current_anchor.vertices[ccw(index)]; + + // check if the edge is a loop + Dart_const_descriptor next = Base::const_ccw(it); + auto doc = this->combinatorial_map_.template darts_of_cell<0>(it); + for (auto dart = doc.begin(); dart != doc.end(); ++dart) { + if (next == dart) { // the edge is a loop + Number delta_length = delta(a, b); + min_delta_length = min(min_delta_length,delta_length); + res = std::acosh(1 + to_double(min_delta_length)); + } + } + } + return res; +} + +template +double +Delaunay_triangulation_on_hyperbolic_surface_2:: +shortest_non_loop_edge() const +{ + Number min_delta_length = 999; + double res = NULL; + for (typename Edge_const_range::const_iterator it = this->combinatorial_map_.template one_dart_per_cell<1>().begin(); + it != this->combinatorial_map_.template one_dart_per_cell<1>().end(); ++it) { + Anchor const & current_anchor = anchor(it); + unsigned index = index_in_anchor(it); + Point const & a = current_anchor.vertices[index]; + Point const & b = current_anchor.vertices[ccw(index)]; + + // check if the edge is a loop + bool is_loop = false; + Dart_const_descriptor next = Base::const_ccw(it); + auto doc = this->combinatorial_map_.template darts_of_cell<0>(it); + for (auto dart = doc.begin(); dart != doc.end(); ++dart) { + if (next == dart) { + is_loop = true; + } + } + if(!is_loop) { + Number delta_length = delta(a, b); + min_delta_length = min(min_delta_length, delta_length); + res = std::acosh(1 + to_double(min_delta_length)); + } + } + return res; +} + +} // namespace CGAL + +#endif //CGAL_DELAUNAY_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2 diff --git a/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_Dirichlet_domain_2.h b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_Dirichlet_domain_2.h new file mode 100644 index 00000000000..30a75027725 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_Dirichlet_domain_2.h @@ -0,0 +1,112 @@ +// Copyright (c) 2025 +// INRIA Nancy (France), and Université de Lorraine (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Vincent Despré, Camille Lanuel, Marc Pouget, Monique Teillaud + +#ifndef CGAL_HYPERBOLIC_DIRICHLET_DOMAIN_2 +#define CGAL_HYPERBOLIC_DIRICHLET_DOMAIN_2 + +#include + +#include + +namespace CGAL { + +// Input: triangulation with a single vertex v +// Output: lift of this triangulation with one lift of v mapped to the origin of the Poincaré disk and all its incident triangles arout it. +template +std::vector::Dart_const_descriptor, typename Traits::Point_2, typename Traits::Point_2, typename Traits::Point_2>> +unfold(Delaunay_triangulation_on_hyperbolic_surface_2 & triangulation) +{ + typedef typename Traits::Complex Complex; + typedef typename Traits::Point_2 Point; + typedef Delaunay_triangulation_on_hyperbolic_surface_2 Delaunay_Triangulation; + typedef typename Delaunay_Triangulation::Anchor Anchor; + typedef typename Delaunay_Triangulation::CMap CMap; + typedef typename Delaunay_Triangulation::Dart_const_descriptor Dart_const_descriptor; + typedef CGAL::Hyperbolic_isometry_2 Isometry; + + Anchor & anchor = triangulation.anchor(); + CMap & cmap = triangulation.combinatorial_map(); + + std::vector> lifted_triangles; // vector of lifted triangles (future output) + std::map positions; // map that will contain the computed lift of the vertex of each dart + + // create a mark for visited darts + size_t visited = cmap.get_new_mark(); + cmap.unmark_all(visited); + + // translate the first vertex of the anchor to the origin of the Poincaré disk, and add the positions of the translated vertices of the anchor + Isometry center_the_drawing = hyperbolic_translation(anchor.vertices[0]); + positions[anchor.dart] = center_the_drawing.evaluate(anchor.vertices[0]); + positions[triangulation.const_ccw(anchor.dart)] = center_the_drawing.evaluate(anchor.vertices[1]); + positions[triangulation.const_cw(anchor.dart)] = center_the_drawing.evaluate(anchor.vertices[2]); + cmap.mark(anchor.dart, visited); + + // add the first triangle (the translated anchor) to the vector of triangles + std::tuple value = std::make_tuple(anchor.dart, positions[anchor.dart], positions[triangulation.const_ccw(anchor.dart)], positions[triangulation.const_cw(anchor.dart)]); + lifted_triangles.push_back(value); + + // visit all the darts one by one by turning around the central vertex + Dart_const_descriptor invader = anchor.dart; + while( cmap.number_of_unmarked_darts(visited) > 1 ){ // >1 because the first triangle appears twice + Dart_const_descriptor invaded = triangulation.const_opposite(invader); + + // get the positions of the vertices of the invader's triangle + Point a = positions[triangulation.const_ccw(invader)]; + Point b = positions[triangulation.const_cw(invader)]; + Point c = positions[invader]; + Complex cross_ratio = triangulation.get_cross_ratio(invader); + + // retieve the positions of the invaded's triangle + positions[invaded] = a; + positions[triangulation.const_ccw(invaded)] = c; + Point d = triangulation.fourth_point_from_cross_ratio(a, b, c, cross_ratio); + positions[triangulation.const_cw(invaded)] = d; + + // add the three vertices to the vector of lifted triangles + value = std::make_tuple(invaded, a, c, d); + lifted_triangles.push_back(value); + cmap.mark(invaded, visited); + + invader = triangulation.const_ccw(invaded); + } + + cmap.free_mark(visited); + return lifted_triangles; +} + +// Input: Fundamental domain whose vertices are the same point on the surface +// Output: vertices of a Dirichlet domain centered at the origin of the Poincaré disk +template +std::vector Dirichlet_vertices(Hyperbolic_fundamental_domain_2 & domain) +{ + typedef typename Traits::Point_2 Point; + typedef typename Traits::Hyperbolic_Voronoi_point_2 Voronoi_point; + typedef Delaunay_triangulation_on_hyperbolic_surface_2 Delaunay_Triangulation; + typedef typename Delaunay_Triangulation::Dart_const_descriptor Dart_const_descriptor; + + Delaunay_Triangulation triangulation = Delaunay_Triangulation(domain); + + std::vector> realized_triangles = unfold(triangulation); + std::vector dirichlet_vertices; + + Traits gt; + typename Traits::Construct_hyperbolic_circumcenter_2 chc = gt.construct_hyperbolic_circumcenter_2_object(); + for (std::tuple& triangle : realized_triangles){ + Voronoi_point circumcenter = chc(std::get<1>(triangle), std::get<2>(triangle), std::get<3>(triangle)); + dirichlet_vertices.push_back(circumcenter); + } + return dirichlet_vertices; +} + +} // namespace CGAL + +#endif //CGAL_HYPERBOLIC_DIRICHLET_DOMAIN_2 \ No newline at end of file diff --git a/Triangulation_on_hyperbolic_surface_2/include/CGAL/Triangulation_on_hyperbolic_surface_2.h b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Triangulation_on_hyperbolic_surface_2.h index 4112762f5cd..f05e2bbbe68 100644 --- a/Triangulation_on_hyperbolic_surface_2/include/CGAL/Triangulation_on_hyperbolic_surface_2.h +++ b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Triangulation_on_hyperbolic_surface_2.h @@ -29,6 +29,8 @@ #include #include +#include + namespace CGAL { /* @@ -108,6 +110,7 @@ public: void flip(Dart_descriptor dart); bool is_Delaunay() const; int make_Delaunay(); + std::vector > lift(Anchor const & anchor, bool center=true) const; std::vector > lift(bool center=true) const; bool is_valid() const; @@ -151,6 +154,7 @@ protected: Combinatorial_map_with_cross_ratios combinatorial_map_; bool has_anchor_ = false; Anchor anchor_; + // std::optional anchor_ = std::nullopt; Dart_descriptor pick_edge_to_flip(); Dart_const_descriptor pick_edge_to_flip() const; @@ -198,7 +202,7 @@ Triangulation_on_hyperbolic_surface_2(const Domain& domain) } // Sew the boundary edges and set their cross ratios - for (std::size_t k1=0; k1::Point, typename Triangulation_on_hyperbolic_surface_2::Point> > Triangulation_on_hyperbolic_surface_2:: -lift(bool center) const +lift(typename Triangulation_on_hyperbolic_surface_2::Anchor const & anchor, bool center) const { - CGAL_precondition(is_valid() && has_anchor()); + CGAL_precondition(is_valid()); std::vector > realizations; @@ -452,39 +458,39 @@ lift(bool center) const Dart_const_range darts = combinatorial_map_.darts(); - combinatorial_map_.mark(anchor_.dart, visited_darts_mark); - combinatorial_map_.mark(const_ccw(anchor_.dart), visited_darts_mark); - combinatorial_map_.mark(const_cw(anchor_.dart), visited_darts_mark); + combinatorial_map_.mark(anchor.dart, visited_darts_mark); + combinatorial_map_.mark(const_ccw(anchor.dart), visited_darts_mark); + combinatorial_map_.mark(const_cw(anchor.dart), visited_darts_mark); if (center) { - Isometry center_the_drawing = hyperbolic_translation(anchor_.vertices[0]); - positions[anchor_.dart] = center_the_drawing.evaluate(anchor_.vertices[0]); - positions[const_ccw(anchor_.dart)] = center_the_drawing.evaluate(anchor_.vertices[1]); - positions[const_cw(anchor_.dart)] = center_the_drawing.evaluate(anchor_.vertices[2]); + Isometry center_the_drawing = hyperbolic_translation(anchor.vertices[0]); + positions[anchor.dart] = center_the_drawing.evaluate(anchor.vertices[0]); + positions[const_ccw(anchor.dart)] = center_the_drawing.evaluate(anchor.vertices[1]); + positions[const_cw(anchor.dart)] = center_the_drawing.evaluate(anchor.vertices[2]); } else { - positions[anchor_.dart] = anchor_.vertices[0]; - positions[const_ccw(anchor_.dart)] = anchor_.vertices[1]; - positions[const_cw(anchor_.dart)] = anchor_.vertices[2]; + positions[anchor.dart] = anchor_.vertices[0]; + positions[const_ccw(anchor.dart)] = anchor.vertices[1]; + positions[const_cw(anchor.dart)] = anchor.vertices[2]; } std::tuple value = - std::make_tuple(anchor_.dart, - positions[anchor_.dart], - positions[const_ccw(anchor_.dart)], - positions[const_cw(anchor_.dart)]); + std::make_tuple(anchor.dart, + positions[anchor.dart], + positions[const_ccw(anchor.dart)], + positions[const_cw(anchor.dart)]); realizations.push_back(value); - Complex_number anchor_z0(anchor_.vertices[0].x(), anchor_.vertices[0].y()); - Complex_number anchor_z1(anchor_.vertices[1].x(), anchor_.vertices[1].y()); - Complex_number anchor_z2(anchor_.vertices[2].x(), anchor_.vertices[2].y()); + Complex_number anchor_z0(anchor.vertices[0].x(), anchor.vertices[0].y()); + Complex_number anchor_z1(anchor.vertices[1].x(), anchor.vertices[1].y()); + Complex_number anchor_z2(anchor.vertices[2].x(), anchor.vertices[2].y()); double weight_of_anchor_dart = CGAL::to_double(norm(anchor_z0) + norm(anchor_z1)); double weight_of_ccw_anchor_dart = CGAL::to_double(norm(anchor_z1) + norm(anchor_z2)); double weight_of_cw_anchor_dart = CGAL::to_double(norm(anchor_z2) + norm(anchor_z0)); - queue.push(std::make_pair(anchor_.dart, weight_of_anchor_dart)); - queue.push(std::make_pair(const_ccw(anchor_.dart), weight_of_ccw_anchor_dart)); - queue.push(std::make_pair(const_cw(anchor_.dart), weight_of_cw_anchor_dart)); + queue.push(std::make_pair(anchor.dart, weight_of_anchor_dart)); + queue.push(std::make_pair(const_ccw(anchor.dart), weight_of_ccw_anchor_dart)); + queue.push(std::make_pair(const_cw(anchor.dart), weight_of_cw_anchor_dart)); while (! queue.empty()) { Dart_const_descriptor invader = queue.top().first; @@ -530,6 +536,18 @@ lift(bool center) const return realizations; } +template +std::vector::Dart_const_descriptor, + typename Triangulation_on_hyperbolic_surface_2::Point, + typename Triangulation_on_hyperbolic_surface_2::Point, + typename Triangulation_on_hyperbolic_surface_2::Point> > +Triangulation_on_hyperbolic_surface_2:: +lift(bool center) const +{ + CGAL_precondition(is_valid() && has_anchor()); + return lift(anchor_, center); +} + //////////////////////////////////////////////////////////////////////////////// template @@ -578,7 +596,7 @@ void Triangulation_on_hyperbolic_surface_2:: to_stream(std::ostream& s) const { - CGAL_precondition(is_valid() && has_anchor()); + CGAL_precondition(is_valid()); // Give indices to the darts std::map darts_indices; @@ -832,4 +850,4 @@ fourth_point_from_cross_ratio(const Point& a, const Point& b, const Point& c, } // namespace CGAL -#endif // CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_H +#endif // CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_H \ No newline at end of file diff --git a/Triangulation_on_hyperbolic_surface_2/include/CGAL/Triangulation_on_hyperbolic_surface_2_IO.h b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Triangulation_on_hyperbolic_surface_2_IO.h index 41939c9fd28..7336a39534b 100644 --- a/Triangulation_on_hyperbolic_surface_2/include/CGAL/Triangulation_on_hyperbolic_surface_2_IO.h +++ b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Triangulation_on_hyperbolic_surface_2_IO.h @@ -1,5 +1,5 @@ // Copyright (c) 2024 -// INRIA Nancy (France), and Université Gustave Eiffel Marne-la-Vallee (France). +// INRIA Nancy (France), Université de Lorraine (France), and Université Gustave Eiffel Marne-la-Vallee (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org) @@ -16,6 +16,7 @@ #include #include +#include #include @@ -61,6 +62,21 @@ void operator>>(std::istream& s, Triangulation_on_hyperbolic_surface_2 +std::ostream& +operator<<(std::ostream& s, const Delaunay_triangulation_on_hyperbolic_surface_2& triangulation) +{ + triangulation.to_stream(s); + return s; +} + +template +void operator>>(std::istream& s, Delaunay_triangulation_on_hyperbolic_surface_2& triangulation) +{ + triangulation.from_stream(s); +} + } // namespace CGAL #endif // CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_IO_H diff --git a/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/copyright b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/copyright index f6c522d5bf5..7b3a95f8dc2 100644 --- a/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/copyright +++ b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/copyright @@ -1,3 +1,3 @@ INRIA Nancy -- France Université de Lorraine -- France -Université Gustave Eiffel Marne-la-Vallee -- France +Université Gustave Eiffel Marne-la-Vallée -- France \ No newline at end of file diff --git a/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/description.txt b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/description.txt index 11623cbdb12..3488fccb14e 100644 --- a/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/description.txt +++ b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/description.txt @@ -1,5 +1,9 @@ Package Triangulation_on_hyperbolic_surface_2 : provides triangulations of closed oriented hyperbolic surfaces, Delaunay flip algorithm on those triangulations, +Delaunay triangulations of closed oriented hyperbolic surfaces, +point location, +point insertion, construction of the triangulations from convex geodesic fundamental domains, -construction of such domains for genus 2 surfaces +construction of such domains for genus 2 surfaces, +construction of an epsilon-net of a closed oriented hyperbolic surface diff --git a/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/maintainer b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/maintainer index 6f51f82623f..3a35718fb21 100644 --- a/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/maintainer +++ b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/maintainer @@ -1,3 +1,4 @@ Vincent Despré Loïc Dubois -Monique Teillaud +Marc Pouget +Monique Teillaud \ No newline at end of file diff --git a/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_Delaunay_triangulation.cpp b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_Delaunay_triangulation.cpp new file mode 100644 index 00000000000..8efb74ccf1e --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_Delaunay_triangulation.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +using namespace CGAL; + + +typedef Simple_cartesian Kernel; +typedef Hyperbolic_Delaunay_triangulation_traits_2 ParentTraits; + +typedef Hyperbolic_surface_traits_2 Traits; +typedef Hyperbolic_fundamental_domain_2 Domain; +typedef Delaunay_triangulation_on_hyperbolic_surface_2 Delaunay_triangulation; +typedef typename Delaunay_triangulation::Anchor Anchor; +typedef typename Delaunay_triangulation::CMap CMap; + +typedef typename Traits::FT FT; +typedef typename Traits::Hyperbolic_point_2 Point; + +Domain build_domain() +{ + std::vector vertices; + Point z0 = Point(FT("4881/5000"),FT("0")); + Point z1 = Point(FT("9211/10000"),FT("2733/10000")); + Point z2 = Point(FT("1709/5000"),FT("7253/10000")); + Point z3 = Point(FT("-427262704257582473474868322141310044732400799603/1267155016747148041260345910894159385550919570000"),FT("582571804584198065321856347012850217722442509611/1267155016747148041260345910894159385550919570000")); + Point z4 = Point(FT("-4881/5000"),FT("0")); + Point z5 = Point(FT("-9211/10000"),FT("-2733/10000")); + Point z6 = Point(FT("-1709/5000"),FT("-7253/10000")); + Point z7 = Point(FT("427262704257582473474868322141310044732400799603/1267155016747148041260345910894159385550919570000"),FT("-582571804584198065321856347012850217722442509611/1267155016747148041260345910894159385550919570000")); + vertices.push_back(z0); + vertices.push_back(z1); + vertices.push_back(z2); + vertices.push_back(z3); + vertices.push_back(z4); + vertices.push_back(z5); + vertices.push_back(z6); + vertices.push_back(z7); + + std::vector pairings; + for (std::size_t k=0; k<8; ++k) { + pairings.push_back((k+4)%8); + } + return Domain(vertices, pairings); +} + +int main() +{ + Domain domain = build_domain(); + Delaunay_triangulation dt = Delaunay_triangulation(domain); + + assert(dt.is_valid()); + + std::cout << "printing triangulation for test purposes: " << std::endl << dt; + + Anchor a0 = dt.locate(Point(0.5, 0.5)); // straight walk + Anchor a1 = dt.locate(Point(0.5, 0.5), true); // visibility walk + + assert(dt.anchor(a0.dart).dart == dt.anchor(a1.dart).dart); //check that both anchors correspond to the same triangle + + bool same_vertices = true; + for (unsigned i = 0; i < 3; ++i) { + bool found = false; + for (unsigned j = 0; j < 3; ++j) { + if (a0.vertices[i] == a1.vertices[j]) { + found = true; + } + } + same_vertices = same_vertices && found; + } + + assert(same_vertices); + + assert(dt.shortest_loop_edge() != 0); + assert(dt.shortest_non_loop_edge() == 0); + + return 0; +} diff --git a/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_espilon_net.cpp b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_espilon_net.cpp new file mode 100644 index 00000000000..b1a7feb31ed --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_espilon_net.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include + +#include + +using namespace CGAL; + +typedef Gmpq NumberType; +typedef Circular_kernel_2, Algebraic_kernel_for_circles_2_2> Kernel; +typedef Hyperbolic_Delaunay_triangulation_CK_traits_2 ParentTraits; +typedef Hyperbolic_surface_traits_2 Traits; +typedef Hyperbolic_fundamental_domain_2 Domain; +typedef Delaunay_triangulation_on_hyperbolic_surface_2 Delaunay_triangulation; + +typedef typename Traits::FT FT; +typedef typename Traits::Hyperbolic_point_2 Point; + +double epsilon = 0.25; +int p = 2; + +Domain build_domain() +{ + std::vector vertices; + Point z0 = Point(FT("4881/5000"),FT("0")); + Point z1 = Point(FT("9211/10000"),FT("2733/10000")); + Point z2 = Point(FT("1709/5000"),FT("7253/10000")); + Point z3 = Point(FT("-427262704257582473474868322141310044732400799603/1267155016747148041260345910894159385550919570000"),FT("582571804584198065321856347012850217722442509611/1267155016747148041260345910894159385550919570000")); + Point z4 = Point(FT("-4881/5000"),FT("0")); + Point z5 = Point(FT("-9211/10000"),FT("-2733/10000")); + Point z6 = Point(FT("-1709/5000"),FT("-7253/10000")); + Point z7 = Point(FT("427262704257582473474868322141310044732400799603/1267155016747148041260345910894159385550919570000"),FT("-582571804584198065321856347012850217722442509611/1267155016747148041260345910894159385550919570000")); + vertices.push_back(z0); + vertices.push_back(z1); + vertices.push_back(z2); + vertices.push_back(z3); + vertices.push_back(z4); + vertices.push_back(z5); + vertices.push_back(z6); + vertices.push_back(z7); + + std::vector pairings; + for (std::size_t k=0; k<8; ++k) { + pairings.push_back((k+4)%8); + } + + return Domain(vertices, pairings); +} + +int main(int argc, char *argv[]) +{ + Domain domain = build_domain(); + Delaunay_triangulation dt = Delaunay_triangulation(domain); + + assert(dt.is_valid()); + + bool is_eps_net = dt.epsilon_net(epsilon, p); + + assert(is_eps_net); + assert(dt.is_valid()); + assert(dt.shortest_non_loop_edge() != 0); + + return 0; +} \ No newline at end of file diff --git a/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_triangulation.cpp b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_triangulation.cpp index 0ccf8b82965..91fb9188500 100644 --- a/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_triangulation.cpp +++ b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_triangulation.cpp @@ -18,7 +18,6 @@ typedef CGAL::Triangulation_on_hyperbolic_surface_2 Triangul typedef typename Traits::FT FT; typedef typename Traits::Hyperbolic_point_2 Point; -typedef typename Traits::Complex Complex; Domain build_domain() {