diff --git a/Documentation/doc/Documentation/packages.txt b/Documentation/doc/Documentation/packages.txt index 9b1fa73107e..9fd4bb20491 100644 --- a/Documentation/doc/Documentation/packages.txt +++ b/Documentation/doc/Documentation/packages.txt @@ -71,6 +71,7 @@ \package_listing{Triangulation_on_sphere_2} \package_listing{Periodic_2_triangulation_2} \package_listing{Hyperbolic_triangulation_2} +\package_listing{Triangulation_on_hyperbolic_surface_2} \package_listing{Periodic_4_hyperbolic_triangulation_2} \package_listing{Triangulation_3} \package_listing{TDS_3} diff --git a/Documentation/doc/biblio/cgal_manual.bib b/Documentation/doc/biblio/cgal_manual.bib index 51dfb109004..ffde94141b4 100644 --- a/Documentation/doc/biblio/cgal_manual.bib +++ b/Documentation/doc/biblio/cgal_manual.bib @@ -22,7 +22,6 @@ - @article{ cgal:afh-pdecm-02, author = "P. K. Agarwal and E. Flato and D. Halperin", title = "Polygon Decomposition for Efficient Construction of {Minkowski} Sums", @@ -130,6 +129,21 @@ @inproceedings{ cgal:b-digph-01 ,update = "04.04 kettner" } +@book{cgal:b-gdg-83, + title={The Geometry of Discrete Groups}, + author={Beardon, A.F.}, + series={Graduate texts in mathematics}, + year={1983}, + publisher={Springer} +} + +@book{cgal:b-gscrs-92, + title={Geometry and Spectra of Compact Riemann Surfaces}, + author={Peter Buser}, + year={1992}, + publisher={Springer} +} + @article{ cgal:bbp-iayed-01 ,author = "H. Br{\"o}nnimann and C. Burnikel and S. Pion" ,title = "Interval arithmetic yields efficient dynamic filters @@ -689,6 +703,33 @@ @article{cgal:dh-pifch-96 keywords = "Convex hull problem, Frame, Linear programming, Data envelopment analysis, Redundancy" } +@inproceedings{despre2020flipping, + title={Flipping geometric triangulations on hyperbolic surfaces}, + author={Despr{\'e}, Vincent and Schlenker, Jean-Marc and Teillaud, Monique}, + booktitle={36th International Symposium on Computational Geometry}, + year={2020}, + url={https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.SoCG.2020.35} +} + +@article{despre2022experimental, + title={Experimental analysis of {Delaunay} flip algorithms on genus two hyperbolic surfaces}, + author={Despr{\'e}, Vincent and Dubois, Lo{\"\i}c and Kolbe, Benedikt and Teillaud, Monique}, + year={2022}, + url={https://inria.hal.science/hal-03665888v1/document} +} + +@article{aigon2005hyperbolic, + title={Hyperbolic octagons and {Teichm{\"u}ller} space in genus 2}, + author={Aigon-Dupuy, Aline and Buser, Peter and Cibils, Michel and K{\"u}nzle, Alfred F and Steiner, Frank}, + journal={Journal of mathematical physics}, + volume={46}, + number={3}, + year={2005}, + publisher={AIP Publishing}, + url = {https://doi.org/10.1063/1.1850177} +} + + @article{cgal:dl-cginc-19, author = {Despr\'{e}, Vincent and Lazarus, Francis}, title = {Computing the Geometric Intersection Number of Curves}, diff --git a/Documentation/doc/scripts/generate_how_to_cite.py b/Documentation/doc/scripts/generate_how_to_cite.py index ece849f18a9..809298fa408 100644 --- a/Documentation/doc/scripts/generate_how_to_cite.py +++ b/Documentation/doc/scripts/generate_how_to_cite.py @@ -230,6 +230,7 @@ def protect_accentuated_letters(authors): .replace("ş", r"{\c{s}}") .replace("%", "") .replace("đ", r"{\-d}") + .replace("ï", r"{\"i}") ) try: res.encode("ascii") 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 1aaec1a1a00..2f6cef0e871 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 @@ -170,7 +170,7 @@ class HyperbolicDelaunayTriangulationTraits_2 { /// @} /// \name - /// The following functions must be provided only if the methods of `Hyperbolic_Delaunay_triangulation_2` + /// The following functions must be provided only if the methods of `CGAL::Hyperbolic_Delaunay_triangulation_2` /// that return elements of the Voronoi diagram are instantiated: /// @{ Construct_hyperbolic_segment_2 construct_hyperbolic_segment_2_object(); diff --git a/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Hyperbolic_triangulation_2.txt b/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Hyperbolic_triangulation_2.txt index d5b32a20979..418991dc8f9 100644 --- a/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Hyperbolic_triangulation_2.txt +++ b/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Hyperbolic_triangulation_2.txt @@ -15,7 +15,7 @@ namespace CGAL { -This package enables the computation of Delaunay triangulations of +This package enables the computation of hyperbolic Delaunay triangulations of point sets in the Poincaré disk model of the hyperbolic plane. \section HT2_Poincare_model The Poincaré Disk Model of the Hyperbolic Plane diff --git a/Installation/include/CGAL/license/Triangulation_on_hyperbolic_surface_2.h b/Installation/include/CGAL/license/Triangulation_on_hyperbolic_surface_2.h new file mode 100644 index 00000000000..d3ce6f035fd --- /dev/null +++ b/Installation/include/CGAL/license/Triangulation_on_hyperbolic_surface_2.h @@ -0,0 +1,54 @@ +// Copyright (c) 2016 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Andreas Fabri +// +// Warning: this file is generated, see include/CGAL/license/README.md + +#ifndef CGAL_LICENSE_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_H +#define CGAL_LICENSE_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_H + +#include +#include + +#ifdef CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_COMMERCIAL_LICENSE + +# if CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE + +# if defined(CGAL_LICENSE_WARNING) + + CGAL_pragma_warning("Your commercial license for CGAL does not cover " + "this release of the 2D Triangulations on Hyperbolic Surfaces package.") +# endif + +# ifdef CGAL_LICENSE_ERROR +# error "Your commercial license for CGAL does not cover this release \ + of the 2D Triangulations on Hyperbolic Surfaces package. \ + You get this error, as you defined CGAL_LICENSE_ERROR." +# endif // CGAL_LICENSE_ERROR + +# endif // CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE + +#else // no CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_COMMERCIAL_LICENSE + +# if defined(CGAL_LICENSE_WARNING) + CGAL_pragma_warning("\nThe macro CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_COMMERCIAL_LICENSE is not defined." + "\nYou use the CGAL 2D Triangulations on Hyperbolic Surfaces package under " + "the terms of the GPLv3+.") +# endif // CGAL_LICENSE_WARNING + +# ifdef CGAL_LICENSE_ERROR +# error "The macro CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_COMMERCIAL_LICENSE is not defined.\ + You use the CGAL 2D Triangulations on Hyperbolic Surfaces package under the terms of \ + the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." +# endif // CGAL_LICENSE_ERROR + +#endif // no CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_COMMERCIAL_LICENSE + +#endif // CGAL_LICENSE_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_H diff --git a/Installation/include/CGAL/license/gpl_package_list.txt b/Installation/include/CGAL/license/gpl_package_list.txt index 75ff9d5c9ed..042b3d9ffed 100644 --- a/Installation/include/CGAL/license/gpl_package_list.txt +++ b/Installation/include/CGAL/license/gpl_package_list.txt @@ -105,6 +105,7 @@ Three Three Triangulation_2 2D Triangulation Triangulation_3 3D Triangulations Triangulation dD Triangulations +Triangulation_on_hyperbolic_surface_2 2D Triangulations on Hyperbolic Surfaces Triangulation_on_sphere_2 2D Triangulation on Sphere Visibility_2 2D Visibility Computation Voronoi_diagram_2 2D Voronoi Diagram Adaptor diff --git a/Periodic_4_hyperbolic_triangulation_2/doc/Periodic_4_hyperbolic_triangulation_2/Periodic_4_hyperbolic_triangulation_2.txt b/Periodic_4_hyperbolic_triangulation_2/doc/Periodic_4_hyperbolic_triangulation_2/Periodic_4_hyperbolic_triangulation_2.txt index f5bdc8e3990..60389129c57 100644 --- a/Periodic_4_hyperbolic_triangulation_2/doc/Periodic_4_hyperbolic_triangulation_2/Periodic_4_hyperbolic_triangulation_2.txt +++ b/Periodic_4_hyperbolic_triangulation_2/doc/Periodic_4_hyperbolic_triangulation_2/Periodic_4_hyperbolic_triangulation_2.txt @@ -17,9 +17,7 @@ namespace CGAL { -This package enables the computation of Delaunay triangulations of the Bolza -surface, which is the most symmetric surface of genus 2. The Bolza surface is -a hyperbolic closed compact orientable surface. +This package enables the computation of Delaunay triangulations of the Bolza surface, which is the most symmetric surface of genus 2. The Bolza surface is a hyperbolic closed compact orientable surface. For triangulations on general hyperbolic surfaces, we refer to the package \ref Chapter_Hyperbolic_Surface_Triangulations "2D Triangulations on Hyperbolic Surfaces". A triangulation of the Bolza surface can be seen as a periodic triangulation of the hyperbolic plane. diff --git a/Periodic_4_hyperbolic_triangulation_2/doc/Periodic_4_hyperbolic_triangulation_2/dependencies b/Periodic_4_hyperbolic_triangulation_2/doc/Periodic_4_hyperbolic_triangulation_2/dependencies index 65f3104fa12..54ced5da1df 100644 --- a/Periodic_4_hyperbolic_triangulation_2/doc/Periodic_4_hyperbolic_triangulation_2/dependencies +++ b/Periodic_4_hyperbolic_triangulation_2/doc/Periodic_4_hyperbolic_triangulation_2/dependencies @@ -11,4 +11,5 @@ Circular_kernel_2 Triangulation Hyperbolic_triangulation_2 Number_types -Periodic_2_triangulation_2 \ No newline at end of file +Periodic_2_triangulation_2 +Triangulation_on_hyperbolic_surface_2 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 new file mode 100644 index 00000000000..1b3df5d53d7 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.1...3.15) + +project( Triangulation_on_hyperbolic_surface_2_Demo ) + +include_directories(/Users/pougetma/dev/cgal-loic-submission-2024/Installation/include/) + +# Find includes in corresponding build directories +set(CMAKE_INCLUDE_CURRENT_DIR ON) +include_directories(${CMAKE_BINARY_DIR}) + +# Instruct CMake to run moc automatically when needed. +set(CMAKE_AUTOMOC ON) + + +# CGAL and its components +find_package(CGAL REQUIRED COMPONENTS Core Qt6) + +find_package(Qt6 QUIET COMPONENTS Widgets) + +if ( NOT CGAL_FOUND ) + + message(STATUS "This project requires the CGAL library, and will not be compiled.") + return() + +endif() + +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}) + +add_to_cached_list( CGAL_EXECUTABLE_TARGETS Triangulation_on_hyperbolic_surface_2_demo ) + +target_link_libraries(Triangulation_on_hyperbolic_surface_2_demo PRIVATE CGAL::CGAL CGAL::CGAL_Qt6 Qt6::Widgets ) + +set(CMAKE_BUILD_TYPE "Release") + +target_include_directories(Triangulation_on_hyperbolic_surface_2_demo PRIVATE ../../include/) 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 new file mode 100644 index 00000000000..8e9252a2bb7 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2_demo.cpp @@ -0,0 +1,41 @@ +#include "window.h" + +#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 Hyperbolic_fundamental_domain_factory_2 Factory; +typedef Triangulation_on_hyperbolic_surface_2 Triangulation; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int main(int argc, char** argv){ + // 1. Generate the triangulation + Factory factory; + Domain domain = factory.make_hyperbolic_fundamental_domain_g2(time(NULL)); + Triangulation triangulation = Triangulation(domain); + triangulation.make_Delaunay(); + + // 2. Draw the triangulation + QApplication app(argc, argv); + app.setApplicationName("Hyperbolic surfaces triangulation 2 Demo"); + + DemoWindow window; + window.item().draw_triangulation(triangulation); + 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/drawing_window_description.ui b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/drawing_window_description.ui new file mode 100644 index 00000000000..cba64b8f300 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/drawing_window_description.ui @@ -0,0 +1,44 @@ + + + MainWindow + + + + 0 + 0 + 800 + 720 + + + + + 0 + 0 + + + + Hyperbolic flips demo window + + + + + + 10 + 10 + 771 + 671 + + + + + 0 + 0 + + + + + + + + + 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 new file mode 100644 index 00000000000..f7ee58a3a24 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/window.cpp @@ -0,0 +1,248 @@ +// Copyright (c) 2024 +// INRIA Nancy (France), and Université Gustave Eiffel Marne-la-Vallee (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é, Loïc Dubois, Monique Teillaud + +#include "window.h" + +DemoWindowItem::DemoWindowItem() : CGAL::Qt::GraphicsItem(){ + // Clear + _edges.clear(); + + // Prepare the pens + _poincare_disk_pen.setStyle(Qt::SolidLine); + _poincare_disk_pen.setWidth(8); + _poincare_disk_pen.setBrush(Qt::black); + + _edges_pen.setStyle(Qt::SolidLine); + _edges_pen.setWidth(6); + _edges_pen.setBrush(Qt::blue); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void DemoWindowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){ + // 1. Draw the poincaré disk + QRectF circle_rect = QRectF(-_poincare_disk_radius_in_pixels-3, -_poincare_disk_radius_in_pixels-3, 2*_poincare_disk_radius_in_pixels+6, 2*_poincare_disk_radius_in_pixels+6); + painter->setPen(_poincare_disk_pen); + painter->setBrush(QBrush()); + painter->drawEllipse(circle_rect); + + // 2. Draw the edges + painter->setBrush(QBrush()); + painter->setPen(_edges_pen); + for (int i=0; i<_edges.size(); i++){ + draw_edge(painter, _edges[i].first, _edges[i].second); + } +} + +QRectF DemoWindowItem::boundingRect() const{ + return QRectF(-_poincare_disk_radius_in_pixels-3, -_poincare_disk_radius_in_pixels-3, _poincare_disk_radius_in_pixels+6, _poincare_disk_radius_in_pixels+6); +} + +void DemoWindowItem::modelChanged(){} // Only used by Qt : we don't need to fill it + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void DemoWindowItem::draw_triangulation(Triangulation& triangulation){ + typedef std::vector> RealizationVector; + RealizationVector realized_triangles; + realized_triangles = triangulation.lift(); + + 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_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()); + + // Then draw a small circle + QRectF circle_rect = QRectF(point_x-1, point_y-1, 3, 3); + painter->drawEllipse(circle_rect); + +} + +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 tar_x = CGAL::to_double(target.x()); + double tar_y = CGAL::to_double(target.y()); + + // 0. If src and tar are too colinear or too close from each other then draw a line + double determinant = src_x*tar_y - src_y*tar_x; // determinant of the matrix whose columns are the vectors src and tar : indicates colinearity + double distance_squared = (src_x-tar_x)*(src_x-tar_x) + (src_y-tar_y)*(src_y-tar_y); + if ((std::abs(determinant) < computation_treshold_squared) || (distance_squared < computation_treshold_squared)){ + // src and tar are too colinear or too close from each other + draw_line(painter, src_x, src_y, tar_x, tar_y); + return; + } + + // 1. Compute the center of the circle supporting the geodesic between src and tar + + // 1.a Inverse src and tar with respect to the unit circle and find the euclidean midpoints of the segments between respectively + // src and it's inversion, and tar and it's inversion + + double src_norm_2 = src_x*src_x + src_y*src_y; // Can't be too close to zero because determinant was not + double tar_norm_2 = tar_x*tar_x + tar_y*tar_y; // Can't be too close to zero because determinant was not + + double src_inv_x = src_x / src_norm_2; + double src_inv_y = src_y / src_norm_2; + double tar_inv_x = tar_x / tar_norm_2; + double tar_inv_y = tar_y / tar_norm_2; + + // coordinates of the euclidean midpoints of the segments [src, src_inv] and [tar, tar_inv] + double src_mid_x = (src_x + src_inv_x) / 2; + double src_mid_y = (src_y + src_inv_y) / 2; + double tar_mid_x = (tar_x + tar_inv_x) / 2; + double tar_mid_y = (tar_y + tar_inv_y) / 2; + + // 1.b Solve a system to find the intersection (center_x, center_y) of the bisectors of the two segments [src, src_inv] and [tar, tar_inv] : + // (center_x \\ center y) = (a & b \\ c & d)^{-1} \times (u_x \\ u_y) + + + // 1.b.i define the system + + double a = src_x; + double b = src_y; + double c = tar_x; + double d = tar_y; + + double u_x = a*src_mid_x + b*src_mid_y; + double u_y = c*tar_mid_x + d*tar_mid_y; + + // 1.b.ii solve the system (just a matrix inversion) + double det = a*d-b*c; // Can't be too close to zero... + double center_x = (d*u_x - b*u_y) / det; + double center_y = (-c*u_x + a*u_y) / det; + + // 2. draw the arc supported by the circle whose center is (center_x, center_y) and whose extremities are src and tar + draw_arc(painter, src_x, src_y, tar_x, tar_y, center_x, center_y); +} + + +void DemoWindowItem::draw_line(QPainter* painter, double point_1_x, double point_1_y, double point_2_x, double point_2_y){ + + // Convert to doubles and scale by the radius of the poincaré disk + double src_x = _poincare_disk_radius_in_pixels * point_1_x; + double src_y = _poincare_disk_radius_in_pixels * point_1_y; + double tar_x = _poincare_disk_radius_in_pixels * point_2_x; + double tar_y = _poincare_disk_radius_in_pixels * point_2_y; + + // Actual drawing + QLineF line (src_x, src_y, tar_x, tar_y); + painter->drawLine(line); +} + + +void DemoWindowItem::draw_arc(QPainter* painter, double point_1_x, double point_1_y, + double point_2_x, double point_2_y, double center_x, double center_y){ + // Draws the arc supported by the circle whose center is (center_x, center_y) and whose extremities are src and tar + + // 1. Scale by the radius of the poincaré disk + + double src_x = _poincare_disk_radius_in_pixels * point_1_x; + double src_y = _poincare_disk_radius_in_pixels * point_1_y; + + double tar_x = _poincare_disk_radius_in_pixels * point_2_x; + double tar_y = _poincare_disk_radius_in_pixels * point_2_y; + + double xc = _poincare_disk_radius_in_pixels * center_x; + double yc = _poincare_disk_radius_in_pixels * center_y; + + // 2. Define the radius of the circle and the box [xm, xM] \times [ym, yM] bounding the circle + + double circle_radius = sqrt((point_1_x-center_x)*(point_1_x-center_x) + (point_1_y-center_y)*(point_1_y-center_y)); + + double xm = _poincare_disk_radius_in_pixels * (center_x - circle_radius); + double xM = _poincare_disk_radius_in_pixels * (center_x + circle_radius); + double ym = _poincare_disk_radius_in_pixels * (center_y - circle_radius); + double yM = _poincare_disk_radius_in_pixels * (center_y + circle_radius); + + // If the source and the target are too close from each other (less than 10 pixels) or if the circle is very big then just draw a line + double dist_sq = (src_x-tar_x)*(src_x-tar_x) + (src_y - tar_y)*(src_y-tar_y); + double rad_sq = (xM-xc)*(xM-xc) + (yM-yc)*(yM-yc); + if ( (dist_sq < 100) || (rad_sq > 1000 * dist_sq) ){ + QLineF line (src_x, src_y, tar_x, tar_y); + painter->drawLine(line); + return; + } + + // 3. Compute angles (needed because we will draw using QPainter::drawArc) + + // src_angle is the argument, in degrees, of point_1 - center + // tar_angle is the argument, in degrees, of point_2 - center + double src_angle = deg_angle(src_x - xc, src_y - yc); + double tar_angle = deg_angle(tar_x - xc, tar_y - yc); + src_angle = 360 - src_angle; // Because of y-axis inversion + tar_angle = 360 - tar_angle; // Because of y-axis-inversion + + // Compute the sweep angle (see QPainter::drawArc) + double sweep_angle = tar_angle - src_angle; + while (sweep_angle > 180) + sweep_angle -= 360; + while (sweep_angle < -180) + sweep_angle += 360; + + // 4. Actual Drawing + + QRectF bbox_rect (xm, ym, xM-xm, yM-ym); + painter->drawArc(bbox_rect, src_angle*16, sweep_angle*16); +} + +double DemoWindowItem::deg_angle(double x, double y){ + // To avoid problems when further division by x (ok since x^2 + y^2 not too small) : + if (x*x < computation_treshold_squared){ + if (y>0) return 90; + return -90; + } + + double angle = 180. * std::atan(y / x) / M_PI; + if (x < 0){ + return angle + 180.; + } + return angle; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +DemoWindow::DemoWindow() : DemosMainWindow(){ + setupUi(this); // Method automatically generated by the ui file and here inherited from Ui::MainWindow. Builds the window and the contents for us... + this->graphicsView->setScene(&_scene); // ... in particular graphicsView is already constructed : we just put our scene in it and then do things within the scene + _scene.setItemIndexMethod(QGraphicsScene::NoIndex); + _scene.setSceneRect(-600, -600, 1200, 1200); + _item = new DemoWindowItem(); + _scene.addItem(_item); + this->graphicsView->scale(0.5, -0.5); // Y-axis inversion + + setWindowTitle("Hyperbolic surfaces triangulation 2 Demo"); +} + +DemoWindowItem& DemoWindow::item(){ + return *_item; +} + +void DemoWindow::keyPressEvent(QKeyEvent* event) {} 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 new file mode 100644 index 00000000000..56d7376e4d5 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/demo/Triangulation_on_hyperbolic_surface_2/window.h @@ -0,0 +1,101 @@ +// Copyright (c) 2024 +// INRIA Nancy (France), and Université Gustave Eiffel Marne-la-Vallee (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é, Loïc Dubois, Monique Teillaud + +#ifndef CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_DEMO_WINDOW +#define CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_DEMO_WINDOW + +// Qt headers +#include +#include +#include + +// UI generated header +#include "ui_drawing_window_description.h" + +#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; + +class DemoWindowItem : + public CGAL::Qt::GraphicsItem +{ + Q_OBJECT // Qt macro for Qt objects + // (Q_OBJECT does not support templates) +private: + typedef CGAL::Bbox_2 Bbox_2; // "Bounding box" : just a box type used for drawing + + // Edges to draw + std::vector> _edges; + + // Pens for drawing + QPen _poincare_disk_pen; + QPen _edges_pen; + + // radius of the poincaré disk + const int _poincare_disk_radius_in_pixels = 600; + // Approximation treshold : used to decide when to simplify a computation (ex : draw a line instead of an arc if an hyperbolic segment is very small) + const double computation_treshold = 0.001; + const double computation_treshold_squared = computation_treshold*computation_treshold; + +public: + // Initializer + DemoWindowItem(); + + // Qt methods + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + QRectF boundingRect() const; + void modelChanged(); + + // Drawing method + void draw_triangulation(Triangulation& triangulation); + +private: + // Sub-methods for drawing edges and vertices + void draw_point(QPainter* painter, Point position); + + void draw_edge(QPainter* painter, Point source, Point target); + void draw_line(QPainter* painter, double point_1_x, double point_1_y, double point_2_x, double point_2_y); + void draw_arc(QPainter* painter, double point_1_x, double point_1_y, double point_2_x, double point_2_y, double center_x, double center_y); + + double deg_angle(double x, double y); +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class DemoWindow : + public CGAL::Qt::DemosMainWindow, public Ui::MainWindow +{ + Q_OBJECT // Qt macro for Qt objects + // (Q_OBJECT does not support templates) +private: + QGraphicsScene _scene; + DemoWindowItem* _item; + +public: + DemoWindow(); + DemoWindowItem& item(); + + // Events handling + void keyPressEvent(QKeyEvent* event); +}; + +#endif // CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_DEMO_WINDOW diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Complex_number.h b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Complex_number.h new file mode 100644 index 00000000000..f4c50e18dba --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Complex_number.h @@ -0,0 +1,14 @@ +namespace CGAL{ + +/*! +\ingroup PkgHyperbolicSurfaceTriangulation2MainClasses + +\cgalModels{ComplexNumber} + +\tparam FT is the field type and must be a model of `FieldNumberType`. +*/ +template +class Complex_number { +}; + +}; // namespace CGAL diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_fundamental_domain_2.h b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_fundamental_domain_2.h new file mode 100644 index 00000000000..b4dc5c346f9 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_fundamental_domain_2.h @@ -0,0 +1,105 @@ +namespace CGAL{ + +/*! +\ingroup PkgHyperbolicSurfaceTriangulation2MainClasses + +represents a fundamental domain of a closed orientable hyperbolic surface. +The domain is given as a polygon \f$ P \f$ represented by the list of its vertices in the Poincaré disk model, +together with a pairing of the sides of \f$ P \f$. +The \f$ n \f$-th side of \f$ P \f$ is the side between the \f$ n \f$-th and the \f$ (n+1) \f$-th vertex, where indices are modulo the number of vertices of \f$ P \f$. +The side pairings are represented by a list of integers, such that if the \f$ n \f$-th integer of the list is \f$ m \f$, then the \f$ n \f$-th side is paired to the \f$ m \f$-th side. + +\tparam Traits must be a model of `HyperbolicSurfaceTraits_2`. + +\sa `Hyperbolic_fundamental_domain_factory_2` +*/ +template +class Hyperbolic_fundamental_domain_2 { +public: + /// \name Types + /// @{ + /*! + Point type. + */ + typedef typename Traits::Hyperbolic_point_2 Point; + /// @} + /// \name Creation + /// @{ + /*! + Default constructor + */ + Hyperbolic_fundamental_domain_2(); + + /*! + Constructor from vertices and pairings ranges. + @tparam PointRange a model of the concepts `RandomAccessContainer` whose `value_type` is `Point`. + @tparam PairingRange a model of the concepts `RandomAccessContainer` whose `value_type` is `int`. + */ + template + Hyperbolic_fundamental_domain_2(PointRange & vertices, PairingRange & pairings); + /// @} + + /// \name Access Functions + /// @{ + /*! + returns the number of vertices (equivalently, the number of sides) of the domain. + + \pre is_valid() + */ + std::size_t size() const; + + /*! + returns the i-th vertex. + + \pre is_valid() + */ + const Point& vertex(std::size_t i) const; + + /*! + returns the index of the side paired to the i-th side. + + \pre is_valid() + */ + std::size_t paired_side(std::size_t i) const; + + /*! + returns the isometry that maps side \f$ \overline A \f$ to side \f$ A + \f$, where \f$ A \f$ is the i-th side, and \f$ \overline A \f$ is the side paired to \f$ A \f$. + + \pre is_valid() + */ + Hyperbolic_isometry_2 side_pairing(std::size_t i) const; + /// @} + + /// \name Input/Output + /// @{ + /*! + writes the domain in a stream. + + The format of the output is the following. + The first line prints the number \f$n\f$ of vertices of the domain. + For \f$ i=0 \f$ to \f$ n-1 \f$ the index of the side paired to side \f$ i \f$ is printed on a separate line. + For \f$ i=0 \f$ to \f$ n-1 \f$ the i-th vertex is printed on a separate line. + + \pre is_valid() + */ + std::ostream& operator<<(std::ostream& s, const Hyperbolic_fundamental_domain_2& domain); + + /*! + reads the domain from a stream. + + The format of the input must be the same as the format of the output of 'operator<<()'. + */ + std::istream& operator>>(std::istream& s, Hyperbolic_fundamental_domain_2& domain); + /// @} + + /// @{ + /// \name Validity + /*! + checks that the number of vertices is even, that there are as many side pairings as vertices, and that the vertices all lie within the open unit disk. + */ + bool is_valid() const; + /// @} +}; + +}; // namespace CGAL diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_fundamental_domain_factory_2.h b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_fundamental_domain_factory_2.h new file mode 100644 index 00000000000..43171f4fde7 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_fundamental_domain_factory_2.h @@ -0,0 +1,36 @@ +namespace CGAL{ + +/*! +\ingroup PkgHyperbolicSurfaceTriangulation2MainClasses + +Factory class, whose only purpose is to construct random fundamental domains of +closed orientable hyperbolic surfaces. + +The method `make_hyperbolic_fundamental_domain_g2()` constructs such a domain for +a surface of genus 2. + +\tparam Traits must be a model of `HyperbolicSurfaceTraits_2`. +*/ +template +class Hyperbolic_fundamental_domain_factory_2{ +public: + /// \name Creation + /// @{ + /*! + Constructor. + */ + Hyperbolic_fundamental_domain_factory_2(); + /// @} + + /// \name Generation of a domain in genus 2. + /// @{ + /*! + randomly generates a convex domain of a closed orientable hyperbolic surface + of genus 2 from a seed. + */ + Hyperbolic_fundamental_domain_2 make_hyperbolic_fundamental_domain_g2(unsigned int seed); + /// @} + +}; + +}; // namespace CGAL diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_isometry_2.h b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_isometry_2.h new file mode 100644 index 00000000000..3727389198c --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_isometry_2.h @@ -0,0 +1,97 @@ +namespace CGAL{ + +/*! +\ingroup PkgHyperbolicSurfaceTriangulation2MainClasses + +represents an isometry in the Poincaré disk model. +The isometry \f$ f \f$ is represented by a list \f$ (c_0, c_1, c_2, c_3) \f$ of complex numbers, +so that \f$ f(z) = (c_0 z + c_1) / (c_2 z + c_3) \f$ holds on every complex \f$ z \f$ in the open unit disk. + +Functionalities are offered to compose isometries, and apply an isometry to a point. + +\tparam Traits must be a model of `HyperbolicSurfaceTraits_2`. +*/ +template +class Hyperbolic_isometry_2{ + public: + /// \name Types + /// @{ + /*! + Complex number type. + */ + typedef typename Traits::Complex Complex_number; + /*! + Point type. + */ + typedef typename Traits::Hyperbolic_point_2 Point; + /// @} + /// \name Creation + /// @{ + /*! + Default constructor to the identity. + */ + Hyperbolic_isometry_2(); + /*! + Constructor from coefficients. + */ + Hyperbolic_isometry_2(const Complex_number& c0, const Complex_number& c1, const Complex_number& c2, const Complex_number& c3); + /// @} + + /*! + sets the isometry to the identity. + */ + void set_to_identity(); + + /*! + sets the coefficients of the isometry. + \warning The implementation does not check that the + resulting transformation is an isometry. + + */ + void set_coefficients(const Complex_number& c0, const Complex_number& c1, const Complex_number& c2, const Complex_number& c3); + + /*! + sets a particular coefficient of the isometry. + \warning The implementation does not check that the + resulting transformation is an isometry. + + */ + void set_coefficient(int index, const Complex_number& coefficient); + + /// \name Access Functions + /// @{ + /*! + returns the index-th coefficient. + */ + const Complex_number& get_coefficient(int index) const; + /// @} + + /// \name Operations + /// @{ + /*! + evaluates the isometry at the point. + */ + Point evaluate(const Point& point) const; + /*! + evaluates the isometry at the point. + */ + Point operator()(const Point& point) const; + + /// @{ + /*! + returns the composition of two isometries. + */ + template + Hyperbolic_isometry_2 operator*(const Hyperbolic_isometry_2& iso1, const Hyperbolic_isometry_2& iso2); + /// @} + + /// \name Input/Output + /// @{ + /*! + writes the isometry in a stream. + */ + std::ostream& operator<<(std::ostream& s, const Hyperbolic_isometry_2& isometry); + /// @} +}; + +}; // namespace CGAL diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_surface_traits_2.h b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_surface_traits_2.h new file mode 100644 index 00000000000..07ec0e07d6e --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Hyperbolic_surface_traits_2.h @@ -0,0 +1,13 @@ +namespace CGAL{ + +/*! +\ingroup PkgHyperbolicSurfaceTriangulation2TraitsClasses + +\tparam HyperbolicTraitsClass must be a model of `HyperbolicDelaunayTriangulationTraits_2`. + +\cgalModels{HyperbolicSurfaceTraits_2} +*/ +template +class Hyperbolic_surface_traits_2 : public HyperbolicTraitsClass {}; + +}; // namespace CGAL 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 new file mode 100644 index 00000000000..e5e9206fc8c --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/CGAL/Triangulation_on_hyperbolic_surface_2.h @@ -0,0 +1,251 @@ +namespace CGAL{ + +/*! +\ingroup PkgHyperbolicSurfaceTriangulation2MainClasses + + +This item defines attributes of edges that are +`Complex_number` reprensenting cross-ratios. + +\tparam Traits must be a model of `HyperbolicSurfaceTraits_2`. + +\cgalModels{GenericMapItems} +*/ +template +struct Combinatorial_map_with_cross_ratios_item{ + template + struct Dart_wrapper{ + typedef Cell_attribute> Edge_attrib; + typedef std::tuple Attributes; + }; + }; + + +/*! +\ingroup PkgHyperbolicSurfaceTriangulation2MainClasses + +represents a triangulation of a closed orientable hyperbolic surface. + +Offers functionalities such as 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 hyperbolic plane. + +\tparam Traits must be a model of `HyperbolicSurfaceTraits_2`. + +\tparam Attributes must be a model of `GenericMapItems` whose edges are +decorated with complex numbers to represent cross ratios. +*/ +template> +class Triangulation_on_hyperbolic_surface_2 +{ +public: + /// \name Types + /// @{ + /*! + Type of combinatorial map whose edges are decorated with complex numbers. + */ + typedef Combinatorial_map<2, Attributes> Combinatorial_map_with_cross_ratios; + /*! + Combinatorial map dart descriptor type. + */ + typedef typename Combinatorial_map_with_cross_ratios::Dart_descriptor Dart_descriptor; + /*! + Combinatorial map dart const descriptor type. + */ + typedef typename Combinatorial_map_with_cross_ratios::Dart_const_descriptor Dart_const_descriptor; + /*! + Range of one dart for each vertex (that is 0-cell) of the combinatorial map. + */ + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_range<0> Vertex_range; + /*! + Range of one dart for each edge (that is 1-cell) of the combinatorial map. + */ + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_range<1> Edge_range; + /*! + Range of one dart for each face (that is 2-cell) of the combinatorial map. + */ + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_range<2> Face_range; + /*! + Range of one dart for each vertex (that is 0-cell) of the combinatorial map. + */ + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_const_range<0> Vertex_const_range; + /*! + Range of one dart for each edge (that is 1-cell) of the combinatorial map. + */ + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_const_range<1> Edge_const_range; + /*! + Range of one dart for each face (that is 2-cell) of the combinatorial map. + */ + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_const_range<2> Face_const_range; + /*! + Point type. + */ + typedef typename Traits::Hyperbolic_point_2 Point; + + /*! + stores a dart \f$ d \f$ of the combinatorial map, belonging to a triangle \f$ t \f$, and stores the three vertices of a lift of \f$ t \f$ in the hyperbolic plane. + */ + struct Anchor{ + typename Combinatorial_map_with_cross_ratios::Dart_descriptor dart; + typename Traits::Hyperbolic_point_2 vertices[3]; + }; + /// @} + + /// \name Creation + /// @{ + /*! + Default constructor. + */ + Triangulation_on_hyperbolic_surface_2() {}; + + /*! + Constructor from a convex fundamental domain: triangulates the polygon of + the domain. (The triangulation is defined by adding an internal edge + between domain.vertex(size-1) and the other vertices. The anchor has the + three vertices of indices size-1, 0 and 1 and the dart is the one between + the vertices of indices size-1 and 0.) + */ + Triangulation_on_hyperbolic_surface_2(const Hyperbolic_fundamental_domain_2& domain); + + /*! + Constructor from a decorated combinatorial map and an anchor. + */ + Triangulation_on_hyperbolic_surface_2(Combinatorial_map_with_cross_ratios& cmap, Anchor& an_anchor); + /// @} + + /// \name Assignment + /// @{ + /*! + \pre other.is_valid() + */ + Triangulation_on_hyperbolic_surface_2& operator=(Triangulation_on_hyperbolic_surface_2 other); + /// @} + + /// \name Access Functions + /// @{ + /*! + returns the decorated combinatorial map. + */ + Combinatorial_map_with_cross_ratios& combinatorial_map(); + + /*! + returns whether the triangulation has an anchor or not. + + \pre is_valid() + */ + bool has_anchor() const; + + /*! + returns the anchor. + + \pre is_valid() && has_anchor() + */ + Anchor& anchor(); + /*! + returns the anchor. + + \pre is_valid() && has_anchor() + */ + const Anchor& anchor() const; + /*! + returns the range of vertices. + */ +Vertex_range vertices_range(); + /*! + returns the range of edges. + */ +Edge_range edges_range(); + /*! + returns the range of faces. + */ +Face_range faces_range(); + /*! + returns the range of vertices. + */ +Vertex_const_range vertices_const_range() const; + /*! + returns the range of edges. + */ +Edge_const_range edges_const_range() const; + /*! + returns the range of faces. + */ +Face_const_range faces_const_range() const; + /// @} + + + /// \name Delaunay Flip Algorithm + /// @{ + /*! + returns whether the edge supported by the dart is Delaunay flippable or not. + + \pre is_valid() + */ + bool is_Delaunay_flippable(Dart_descriptor dart) const; + + /*! + flips the edge supported by the dart. + + \pre is_valid() + */ + void flip(Dart_descriptor dart); + + /*! + determines if the triangulation is a valid Delaunay triangulation. + */ + bool is_Delaunay() const; + + /*! + applies the Delaunay flip algorithm: flips Delaunay-flippable edges until there is no such edge anymore. + + \pre is_valid() + */ + int make_Delaunay(); + /// @} + + /// \name Lifting + /// @{ + /*! + 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 one of the vertices of the anchor is translated to the origin \f$ 0 \f$. + + \pre is_valid() && has_anchor() + */ + std::vector> lift(bool center=true) const; + /// @} + + /// \name Validity + /// @{ + /*! + Checks that the underlying combinatorial map \f$ M \f$ has no boundary and calls the is_valid method of \f$ M \f$. + If there is an anchor, then checks that the dart descriptor of the anchor does indeed point to a dart of \f$ M \f$, and checks that the three vertices of the anchor lie within the open unit disk. + */ + bool is_valid() const; + /// @} + + /// \name Input/Output + /// @{ + /*! + writes the 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. + The next line contains either 'yes' or 'no' and tells whether the triangulation has an anchor. + 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. + + \pre is_valid() + */ + std::ostream& operator<<(std::ostream& s, const Triangulation_on_hyperbolic_surface_2& triangulation); + + /*! + reads the triangulation from a stream. + The format of the input should be the same as the format of the output of the '<<' operator. + */ + std::istream& operator>>(std::istream& s, Triangulation_on_hyperbolic_surface_2& triangulation); + /// @} +}; + +}; // namespace CGAL diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Concepts/ComplexNumber.h b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Concepts/ComplexNumber.h new file mode 100644 index 00000000000..bc58b98dffc --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Concepts/ComplexNumber.h @@ -0,0 +1,162 @@ +// Copyright (c) 2024 INRIA Nancy - Grand Est (France). LIGM Marne-la-Vallée (France) +// All rights reserved. + +/*! +\ingroup PkgHyperbolicSurfaceTriangulation2Concepts +\cgalConcept + +Describes a complex number type over a `FieldNumberType` for its real and +imaginary parts. + +\cgalRefines{Field} + +\cgalHasModelsBegin +\cgalHasModels{CGAL::Complex_number} +\cgalHasModelsEnd +*/ +class ComplexNumber { +public: + /// \name Types + /// @{ + /*! + Number type for real and imaginary parts: must be a model of `FieldNumberType`. + */ + typedef unspecified_type FT; + /// \name Creation + /// @{ + /*! + Default constructor, sets the both the real part and the imaginary part to \f$ 0 \f$. + */ + ComplexNumber(); + + /*! + Constructor, sets the real part to real_part and the imaginary part to \f$ 0 \f$. + */ + ComplexNumber(const FT& real_part); + + /*! + Constructor, sets the real part to real_part and the imaginary part to imaginary_part . + */ + ComplexNumber(const FT& real_part, const FT& imaginary_part); + + /*! + Constructor, sets the real part to real_part and the + imaginary part to imaginary_part . U and V must be + constructible from FT. + */ + template + ComplexNumber(U&& real_part, V&& imaginary_part); + /// @} + + /// \name Get and Set + /// @{ + /*! + sets the real part to real_part . + */ + void real(const FT& real_part); + + /*! + sets the imaginary part to imaginary_part . + */ + void imag(const FT& imaginary_part); + + /*! + returns the real part. + */ + FT real() const; + + /*! + returns the imaginary part. + */ + FT imag() const; + /// @} + + /// \name Operations + /// @{ + /* /\*! */ + /* returns +z. */ + /* *\/ */ + /* //ComplexNumber operator+(const ComplexNumber& z) const; */ + + /* /\*! */ + /* returns -z. */ + /* *\/ */ + /* //ComplexNumber operator-(const ComplexNumber& z) const; */ + + /* /\*! */ + /* Unary complex addition. */ + /* *\/ */ + /* //ComplexNumber operator+=(const ComplexNumber& other) const; */ + + /* /\*! */ + /* Unary complex substraction. */ + /* *\/ */ + /* //ComplexNumber operator-=(const ComplexNumber& other) const; */ + + /* /\*! */ + /* Unary complex multiplication. */ + /* *\/ */ + /* //ComplexNumber operator*=(const ComplexNumber& other) const; */ + + /* /\*! */ + /* Unary complex division. */ + /* *\/ */ + /* //ComplexNumber operator/=(const ComplexNumber& other) const; */ + + /*! + Copy operator. + */ + ComplexNumber operator=(const ComplexNumber& other) const; + + /* /\*! */ + /* Equality test. */ + /* *\/ */ + /* //bool operator==(const ComplexNumber& z1, const ComplexNumber& z2); */ + /* /\*! */ + /* Inequality test. */ + /* *\/ */ + /* // bool operator!=(const ComplexNumber& z1, const ComplexNumber& z2); */ + + /* /\*! */ + /* Binary complex addition. */ + /* *\/ */ + /* //ComplexNumber operator+(const ComplexNumber& z1, const ComplexNumber& z2); */ + + /* /\*! */ + /* Binary complex substraction. */ + /* *\/ */ + /* //ComplexNumber operator-(const ComplexNumber& z1, const ComplexNumber& z2); */ + + /* /\*! */ + /* Binary complex multiplication. */ + /* *\/ */ + /* //ComplexNumber operator*(const ComplexNumber& z1, const ComplexNumber& z2); */ + + /* /\*! */ + /* Binary complex division. */ + /* *\/ */ + /* //ComplexNumber operator/(const ComplexNumber& z1, const ComplexNumber& z2); */ + + /*! + writes the complex in a stream. + */ + std::ostream& operator<<(std::ostream& s, const ComplexNumber& z); + /*! + reads the complex from a stream. + */ + void operator>>(std::istream& s, ComplexNumber& z); + /// @} + + /// \relates ComplexNumber + /// @{ + /*! + returns the square of the modulus. + */ + FT norm(ComplexNumber z) const; + + /*! + returns the conjugate. + */ + ComplexNumber conj(ComplexNumber z) const; + /// @} +}; 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 new file mode 100644 index 00000000000..888c98260ed --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Concepts/HyperbolicSurfaceTraits_2.h @@ -0,0 +1,24 @@ +/*! +\ingroup PkgHyperbolicSurfaceTriangulation2Concepts +\cgalConcept + +This traits class must have a type for complex numbers. + +\cgalRefines{HyperbolicDelaunayTriangulationTraits_2} + +\cgalHasModelsBegin +\cgalHasModels{CGAL::Hyperbolic_surface_traits_2} +\cgalHasModelsEnd +*/ +class HyperbolicSurfaceTraits_2 { +public: + /// \name Types + /// @{ + /*! + represents a complex number, model of + `ComplexNumber`, over the field `HyperbolicSurfaceTraits_2::FT` for its real and + imaginary parts. + */ + typedef unspecified_type Complex; + /// @} +}; diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Doxyfile.in b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Doxyfile.in new file mode 100644 index 00000000000..b6cdaaaf88e --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Doxyfile.in @@ -0,0 +1,12 @@ +@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} + +EXTRACT_PRIVATE = NO + +PROJECT_NAME = "CGAL ${CGAL_CREATED_VERSION_NUM} - 2D Triangulations on Hyperbolic Surfaces" + +IMAGE_PATH += ${CGAL_PACKAGE_DOC_DIR}/fig/cover.svg + +# custom options for this package +#EXTRACT_ALL = true +#HIDE_UNDOC_MEMBERS = true +#HIDE_UNDOC_CLASSES = true \ No newline at end of file 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 new file mode 100644 index 00000000000..d0774492051 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/PackageDescription.txt @@ -0,0 +1,56 @@ +/// \defgroup PkgHyperbolicSurfaceTriangulation2Ref 2D Triangulations on Hyperbolic Surfaces Reference + +/// \defgroup PkgHyperbolicSurfaceTriangulation2Concepts Concepts +/// \ingroup PkgHyperbolicSurfaceTriangulation2Ref + +/// \defgroup PkgHyperbolicSurfaceTriangulation2MainClasses Main Classes +/// \ingroup PkgHyperbolicSurfaceTriangulation2Ref + +/// \defgroup PkgHyperbolicSurfaceTriangulation2TraitsClasses Traits Classes +/// \ingroup PkgHyperbolicSurfaceTriangulation2Ref + + + +/*! +\addtogroup PkgHyperbolicSurfaceTriangulation2Ref + +\cgalPkgDescriptionBegin{2D Triangulations on Hyperbolic Surfaces,PkgHyperbolicSurfaceTriangulation2} +\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. 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. Triangulations can be generated by triangulating a convex fundamental domain in the Poincaré disk model. A method is offered that generates such domains in genus 2.} +\cgalPkgManuals{Chapter_Hyperbolic_Surface_Triangulations,PkgHyperbolicSurfaceTriangulation2Ref} +\cgalPkgSummaryEnd + +\cgalPkgShortInfoBegin +\cgalPkgSince{6} +\cgalPkgDependsOn{\ref PkgCombinatorialMaps} +\cgalPkgBib{cgal:y-t2} +\cgalPkgLicense{\ref licensesGPL "GPL"} +\cgalPkgDemo{2D Triangulations on Hyperbolic Surfaces,nofilefornow.zip} +\cgalPkgShortInfoEnd + +\cgalPkgDescriptionEnd + + +\cgalClassifedRefPages + +\cgalCRPSection{Concepts} + +- `HyperbolicSurfaceTraits_2` is the concept for the template parameter of most classes of the package. +- `ComplexNumber` describes a complex number type. + +\cgalCRPSection{Classes} + +- `CGAL::Triangulation_on_hyperbolic_surface_2` represents a triangulation of a closed orientable hyperbolic surface. It offers functionalities such as 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 hyperbolic plane. + +- `CGAL::Hyperbolic_fundamental_domain_2` represents a fundamental domain of a closed orientable hyperbolic surface. + +- `CGAL::Hyperbolic_fundamental_domain_factory_2` is a factory class, whose purpose is to generate some convex domains of surfaces of genus 2. + +- `CGAL::Hyperbolic_isometry_2` represents an isometry in the Poincaré disk model. Facilities are offered to compose isometries, and apply an isometry to a point. + +Models for `HyperbolicSurfaceTraits_2` and `ComplexNumber` are provided: `CGAL::Hyperbolic_surface_traits_2` and `CGAL::Complex_number`. + +*/ 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 new file mode 100644 index 00000000000..2759cc85d98 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.txt @@ -0,0 +1,145 @@ + +\page Chapter_Hyperbolic_Surface_Triangulations Triangulations of Hyperbolic Surfaces + +namespace CGAL { +/*! + +\mainpage User Manual +\anchor Chapter_Hyperbolic_Surface_Triangulations + +\cgalAutoToc +\authors Vincent Despré, Loïc Dubois, Marc Pouget and Monique Teillaud + +
+ +
+ +This package enables building and handling triangulations of closed orientable hyperbolic surfaces. +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. +A triangulation of a surface can be generated from a convex fundamental domain of the surface. A method is offered that generates such domains in genus 2. +For the case of the Bolza surface, which is the most symmetric surface of genus 2, we refer the user to the specific package \ref Chapter_2D_Periodic_Hyperbolic_Triangulations "2D Periodic Hyperbolic Triangulations". + + +\section Section_Hyperbolic_Surface_Triangulations_Background Hyperbolic Surfaces + +We assume some familiarity with basic notions from covering space theory, and from the theory of hyperbolic surfaces, see for instance \cgalCite{cgal:b-gdg-83}\cgalCite{cgal:b-gscrs-92}. +The Poincaré disk \f$ \mathbb{D} \f$ is a model of the hyperbolic plane whose point set is the open unit disk of the complex plane \f$ \mathbb{C} \f$. +In this package, every hyperbolic surface \f$ S \f$ is closed (compact, and without boundary) and orientable: this is without further mention. +The Poincaré disk \f$ \mathbb{D} \f$ is a universal covering space for \f$ S \f$, whose projection map \f$ \pi: \mathbb{D} \to S \f$ is a (local) isometry. +The pre-image set \f$ \pi^{-1}(x) \f$ of a point \f$ x \in S \f$ is infinite, its points are the lifts of \f$ x \f$. +We usually denote by \f$ \widetilde x \f$ a lift of \f$ x \f$. +Paths and triangulations of \f$ S \f$ can also be lifted in \f$ \mathbb{D} \f$. + +\subsection Section_Hyperbolic_Surface_Triangulations_domains Fundamental Domains and Triangulations + +Let \f$ S \f$ be a hyperbolic surface. For representing \f$ S \f$ on a computer, we cut \f$ S \f$ into "manageable" pieces. +A graph \f$ G \f$ embedded on \f$ S \f$ defines a cellular decomposition of \f$ S \f$ if every face (every connected component of \f$ S \setminus G \f$ ) is a topological disk. +In this document, every edge of a graph \f$ G \f$ embedded on \f$ S \f$ is a geodesic on \f$ S \f$. +We consider two types of cellular decompositions of \f$ S \f$: + +
    +
  • We consider cellular decompositions of \f$ S \f$ that have only one face. +Cutting \f$ S \f$ open at the edges of \f$ G \f$ results in a hyperbolic polygon \f$ P \f$, which is a fundamental domain for \f$ S \f$. +Edges of \f$ G \f$ are cut into two edges that are paired in \f$ P \f$. +Every hyperbolic surface admits a fundamental domain \f$ P \f$ that is convex, in that the interior angles of \f$ P \f$ do not exceed \f$ \pi \f$. + +
  • Also, we consider triangulations of \f$ S \f$. +A cellular decomposition defined by the graph \f$ T \f$ is a triangulation of \f$ S \f$ if every face of \f$ T \f$ is a "triangle": it admits three incidences with edges of \f$ T \f$. +Observe that this definition allows for triangulations with only one vertex. +
+ +A triangulation of \f$ S \f$ can be obtained from a convex fundamental domain \f$ P \f$ of \f$ S \f$ by triangulating the interior of \f$ P \f$, and by gluing back the boundary edges that are paired in \f$ P \f$. +The assumption that \f$ P \f$ is convex ensures that the interior of \f$ P \f$ can be triangulated naively by insertion of any maximal set of pairwise-disjoint arcs of \f$ P \f$. + +\subsection Section_Hyperbolic_Surface_Triangulations_generation Generation of Convex Fundamental Domains + +This package can generate a convex fundamental domain \f$ P \f$ of a surface of genus 2, with eight vertices \f$ z_0, \dots, z_7 \in \mathbb{C} \f$, whose side pairings are \f$ A B C D \overline{A} \overline{B} \overline{C} \overline{D} \f$. +The vertices and the side pairings are in counter-clockwise order, the side between \f$ z_0 \f$ and \f$ z_1 \f$ is \f$ A \f$, and the side between \f$ z_4 \f$ and \f$ z_5 \f$ is \f$ \overline{A} \f$. +These octagons are symmetric, i.e. \f$ z_i = -z_{i+4} \f$ for every \f$ i \f$, where indices are modulo eight. +Such octagons are described in \cgalCite{aigon2005hyperbolic}. + +
+ +
+ +\section Subsection_Hyperbolic_Surface_Triangulations_Representation Representation + +\subsection Subsection_Hyperbolic_Surface_Triangulations_DS_Domains Data Structure for Domains + +We represent every domain as a polygon in the Poincaré disk, given by the list of its vertices, and by the list of its side pairings. +Concerning the generation of domains, in order to perform fast and exact +computations with the generated domains, every vertex must be a complex number whose type supports fast and exact computations. +Under this constraint, it is not known how to generate domains of surfaces of genus greater than two. +In genus 2, this package generates domains whose vertices belong to \f$ \mathbb{Q} + i \mathbb{Q} \f$ (their real and imaginary parts are rational numbers). +The exact generation process can be found in \cgalCite{despre2022experimental}, together with a proof that the surfaces that can be generated in this way are dense in the space of surfaces genus 2. + +\subsection Subsection_Hyperbolic_Surface_Triangulations_DS_Triangulations Data Structure for Triangulations + +Let \f$ T \f$ be a triangulation of a hyperbolic surface. +We represent \f$ T \f$ by an instance of CGAL::Combinatorial_map whose edges are decorated with complex numbers. +The complex number \f$ R_T(e) \in \mathbb{C} \f$ decorating an edge \f$ e \f$ of \f$ T \f$ is the cross ratio of \f$ e \f$ in \f$ T \f$, defined as follows. +Consider the lift \f$ \widetilde T \f$ of \f$ T \f$ in the Poincaré disk \f$ \mathbb{D} \f$. +In \f$ \widetilde T \f$, let \f$ \widetilde e \f$ be a lift of \f$ e \f$. +Orient \f$ \widetilde e \f$ arbitrarily, and let \f$ z_0 \in \mathbb{D} \f$ and \f$ z_2 \in \mathbb{D} \f$ be respectively the first and second vertices of \f$ \widetilde e \f$. +In \f$ \widetilde T \f$, consider the triangle on the right of \f$ \widetilde e \f$, and let \f$ z_1 \in \mathbb{D} \f$ be the third vertex of this triangle (the vertex distinct from \f$ z_0 \f$ and \f$ z_2 \f$). +Similarly, consider the triangle on the left of \f$ \widetilde e \f$, and let \f$ z_3 \in \mathbb{D} \f$ be the third vertex of this triangle. +Then \f$ R_T(e) = (z_3-z_1)*(z_2-z_0) / ((z_3-z_0)*(z_2-z_1)) \f$. +This definition does not depend on the choice of the lift \f$ \widetilde e \f$, nor on the orientation of \f$ \widetilde e \f$. +See \cgalCite{despre2022experimental} for details. + +
+ +
+ +While the triangulation \f$ T \f$ is unambiguously determined by the combinatorial map and its cross ratios, the internal representation of \f$ T \f$ can contain some additional data: the anchor. +The anchor is used when building a portion of the lift of \f$ T \f$ in the Poincaré disk \f$ \mathbb{D} \f$. +It contains a lift \f$ t \f$ of a triangle of \f$ T \f$ in \f$ \mathbb{D} \f$: \f$ t \f$ is represented by its three vertices in \f$ \mathbb{D} \f$, and by a dart of the corresponding triangle in the combinatorial map of \f$ T \f$. + + +\subsection Subsection_Hyperbolic_Surface_Triangulations_Delaunay Delaunay Flip Algorithm + +Let \f$ T \f$ be a triangulation of a hyperbolic surface. An edge \f$ e \f$ of \f$ T \f$ satisfies the Delaunay criterion if the imaginary part of its cross ratio \f$R_T(e)\f$ is non-positive. +This definition is equivalent to the usual "empty disk" formulation. +Then \f$ T \f$ is a Delaunay triangulation if every edge of \f$ T \f$ satisfies the Delaunay criterion. +If an edge \f$e \f$ of \f$ T \f$ does not satisfy the Delaunay criterion, then the two triangles incident to \f$ e \f$ form a strictly convex quadrilateral, so \f$ e \f$ can be deleted from \f$ T \f$ and replaced by the other diagonal of the quadrilateron. +This operation is called a Delaunay flip. +When a flip occurs, the cross ratios of the involved edges are modified via simple formulas. +The Delaunay flip algorithm flips edges that do not satisfy the Delaunay criterion as long as possible, 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_Software_Design Software Design + + +The package contains three main classes: +- `CGAL::Triangulation_on_hyperbolic_surface_2` represents a triangulation of a hyperbolic surface. It offers functionalities such as 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::Hyperbolic_fundamental_domain_2` represents a convex fundamental domain of a hyperbolic surface. + +- `CGAL::Hyperbolic_fundamental_domain_factory_2` is a factory class, whose purpose is to generate some convex fundamental domains of surfaces of genus 2. + +The secondary class `CGAL::Hyperbolic_isometry_2` deals with isometries 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`. +Also, the concept `ComplexNumber` describes a complex number type modeled by `CGAL::Complex_number`. + + +\section Visualization_Triangulation_lift Visualization of a triangulation lifted in the hyperbolic plane + +The function `CGAL::Triangulation_on_hyperbolic_surface_2::lift()` enables to visualize a triangulation by computing a lift of every triangle in the hyperbolic plane, it is illustrated in the demo. + +\section Section_Hyperbolic_Surface_Triangulations_Example Example + +The example below generates a convex fundamental domain of a surface of genus 2, triangulates the domain, applies the Delaunay flip algorithm to the resulting triangulation, saves and prints the Delaunay triangulation. +\cgalExample{Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.cpp} + +\section Section_Hyperbolic_Surface_Implementation_History Design and Implementation History + +This package implements the Delaunay flip algorithm described in the hyperbolic setting by Vincent Despré, Jean-Marc Schlenker, and Monique Teillaud in \cgalCite{despre2020flipping} (with a different data structure for representing triangulations, see \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é and Monique Teillaud. +The authors acknowledge support from the grants SoS and MIN-MAX 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 new file mode 100644 index 00000000000..dbe174d8cc2 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/dependencies @@ -0,0 +1,7 @@ +Manual +Stream_support +Number_types +Combinatorial_map +Hyperbolic_triangulation_2 +Algebraic_foundations +Periodic_4_hyperbolic_triangulation_2 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 new file mode 100644 index 00000000000..5d630b162a4 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/examples.txt @@ -0,0 +1,3 @@ +/*! +\example Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.cpp +*/ diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/cover.svg b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/cover.svg new file mode 100644 index 00000000000..51db91191f5 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/cover.svg @@ -0,0 +1,1329 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/crossratio.svg b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/crossratio.svg new file mode 100644 index 00000000000..7532902b7cc --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/crossratio.svg @@ -0,0 +1,239 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/header.svg b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/header.svg new file mode 100644 index 00000000000..a39b10ac1d4 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/header.svg @@ -0,0 +1,20664 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/octagon.svg b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/octagon.svg new file mode 100644 index 00000000000..903623a0421 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/doc/Triangulation_on_hyperbolic_surface_2/fig/octagon.svg @@ -0,0 +1,526 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Triangulation_on_hyperbolic_surface_2/examples/Triangulation_on_hyperbolic_surface_2/CMakeLists.txt b/Triangulation_on_hyperbolic_surface_2/examples/Triangulation_on_hyperbolic_surface_2/CMakeLists.txt new file mode 100644 index 00000000000..f02b2f63907 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/examples/Triangulation_on_hyperbolic_surface_2/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.1...3.23) + +project( Triangulation_on_hyperbolic_surface_2_Examples ) + +# CGAL and its components +find_package( CGAL REQUIRED ) + +include_directories(../../include/) +include_directories(/Users/pougetma/dev/cgal-loic-submission-2024/Installation/include/) + +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() 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 new file mode 100644 index 00000000000..ef047040944 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/examples/Triangulation_on_hyperbolic_surface_2/Triangulation_on_hyperbolic_surface_2.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef CGAL::Exact_rational Rational; +typedef CGAL::Simple_cartesian Kernel; +typedef CGAL::Hyperbolic_Delaunay_triangulation_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::Triangulation_on_hyperbolic_surface_2 Triangulation; + +int main(){ + // Generates the domain: + Factory factory = Factory(); + Domain domain = factory.make_hyperbolic_fundamental_domain_g2(time(NULL)); + + // Triangulates the domain: + Triangulation triangulation = Triangulation(domain); + + // Applies the Delaunay flip algorithm to the triangulation: + triangulation.make_Delaunay(); + + // Saves the triangulation: + std::ofstream output_file = std::ofstream ("OutputTriangulation.txt"); + output_file << triangulation; + output_file.close(); + + // Prints the triangulation: + std::cout << triangulation << std::endl; + + return 0; +} diff --git a/Triangulation_on_hyperbolic_surface_2/include/CGAL/Complex_number.h b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Complex_number.h new file mode 100644 index 00000000000..8317db2d90e --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Complex_number.h @@ -0,0 +1,200 @@ +// Copyright (c) 2024 +// INRIA Nancy (France), and Université Gustave Eiffel Marne-la-Vallée (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Vincent Despré, Loïc Dubois, Marc Pouget, Monique Teillaud + +// This file contains the declaration and the implementation of the class Complex_number + +#ifndef CGAL_COMPLEX_NUMBER_H +#define CGAL_COMPLEX_NUMBER_H + +#include +#include + +namespace CGAL { +/* +Templated by a field FT. Represents a complex number over FT. +*/ +template +class Complex_number { +private: + typedef Complex_number _Self; + FT _real, _imag; + +public: + Complex_number(); + Complex_number(const FT& real_part); + Complex_number(const FT& real_part, const FT& imaginary_part); + template + Complex_number(U&& real_part, V&& imaginary_part): _real(std::forward(real_part)), _imag(std::forward(imaginary_part)) {} + + void real(const FT& real_part); + void imag(const FT& imaginary_part); + FT real() const; + FT imag() const; + + _Self& operator+=(const _Self& other); + _Self& operator-=(const _Self& other); + _Self& operator*=(const _Self& other); + _Self& operator/=(const _Self& other); + _Self& operator=(const _Self& other); + + // These member versions are not working ? + /* _Self operator+(const _Self& z) const; */ + /* _Self operator-(const _Self& z) const; */ + + // Hidden friends + friend _Self operator+(const _Self& z) { + return z; + } + + friend _Self operator-(const _Self& z) { + return _Self(-z._real,-z._imag); + } + + friend bool operator==(const _Self& z1, const _Self& z2) { + return (z1._real==z2._real && z1._imag==z2._imag); + } + + friend bool operator!=(const _Self& z1, const _Self& z2) { + return !operator==(z1, z2); + } + + friend _Self operator+(const _Self& z1, const _Self& z2){ + return _Self(z1._real+z2._real, z1._imag+z2._imag); + } + + friend _Self operator-(const _Self& z1, const _Self& z2) { + return _Self(z1._real-z2._real, z1._imag-z2._imag); + } + + friend _Self operator*(const _Self& z1, const _Self& z2) { + return _Self(z1._real*z2._real-z1._imag*z2._imag, z1._real*z2._imag+z1._imag*z2._real); + } + + friend _Self operator/(const _Self& z1, const _Self& z2){ + FT m2 = norm(z2); + return _Self(z1._real/m2, z1._imag/m2)*conj(z2); + } + + friend std::ostream& operator<<(std::ostream& s, const _Self& z){ + s << z._real << std::endl << z._imag << std::endl; + return s; + } + + friend void operator>>(std::istream& s, _Self& z){ + std::string line; + s >> line; + z.real(FT(line)); + s >> line; + z.imag(FT(line)); + } + +}; + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +template +Complex_number::Complex_number(){ + _real = FT(0); + _imag = FT(0); +} + +template +Complex_number::Complex_number(const FT& real_part){ + _real = real_part; + _imag = FT(0); +} + +template +Complex_number::Complex_number(const FT& real_part, const FT& imaginary_part){ + _real = real_part; + _imag = imaginary_part; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +void Complex_number::real(const FT& real_part){ + _real = real_part; +} + +template +void Complex_number::imag(const FT& imaginary_part){ + _imag = imaginary_part; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +FT Complex_number::real() const{ + return _real; +} + +template +FT Complex_number::imag() const{ + return _imag; +} + +//////////////////////////////////////////////////////////////////////////////// +template +Complex_number& Complex_number::operator+=(const Complex_number& other) { + _real += other.real(); + _imag += other.imag(); + return *this; +} + +template +Complex_number& Complex_number::operator-=(const Complex_number& other) { + _real -= other.real(); + _imag -= other.imag(); + return *this; +} + + template +Complex_number& Complex_number::operator*=(const Complex_number& other) { + _real = _real*other.real() - _imag*other.imag(); + _imag = _real*other.imag() + _imag*other.real(); + return *this; +} + + template +Complex_number& Complex_number::operator/=(const Complex_number& other) { + FT m2 = norm(other); + _real /= m2; + _imag /= m2; + this *= conj(other); + return *this; +} + + template +Complex_number& Complex_number::operator=(const Complex_number& other) { + _real = other.real(); + _imag = other.imag(); + return *this; +} + + template + FT norm(Complex_number z) { + return z.real()*z.real() + z.imag()*z.imag(); +} + +template +Complex_number conj(Complex_number z) { + return Complex_number(z.real(), -z.imag()); +} + + + +} // namespace CGAL + +#endif // CGAL_COMPLEX_NUMBER_H diff --git a/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_fundamental_domain_2.h b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_fundamental_domain_2.h new file mode 100644 index 00000000000..e03b8234aa1 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_fundamental_domain_2.h @@ -0,0 +1,206 @@ +// Copyright (c) 2024 +// INRIA Nancy (France), and Université Gustave Eiffel Marne-la-Vallee (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é, Loïc Dubois, Marc Pouget, Monique Teillaud + +// This file contains the declaration and the implementation of the class Hyperbolic_fundamental_domain_2 + +#ifndef CGAL_HYPERBOLIC_FUNDAMENTAL_DOMAIN_2_H +#define CGAL_HYPERBOLIC_FUNDAMENTAL_DOMAIN_2_H + +#include + +#include +#include + +#include +#include + +namespace CGAL { + +/* +Represents a convex geodesic hyperbolic domain D of a closed orientable hyperbolic surface. +The domain D is given as a convex geodesic hyperbolic polygon P given by the list of its vertices in the hyperbolic plane, +together with a pairing of the sides of P, such that every two paired sides have the same length, and such that +identifying every two paired sides in a way that respects the orientation of P would result in a closed +orientable hyperbolic surface. +*/ +template +class Hyperbolic_fundamental_domain_2 { + +public: + typedef typename Traits::Hyperbolic_point_2 Point; + + Hyperbolic_fundamental_domain_2(){}; + template + Hyperbolic_fundamental_domain_2(PointRange & vertices, PairingRange & pairings){ + _vertices = std::vector(vertices.begin(), vertices.end()); + _pairings = std::vector(pairings.begin(), pairings.end()); + } + + std::size_t size() const; // Returns the number of vertices (equivalently, the number of sides) + const Point& vertex(std::size_t index) const; // Returns the index-th vertex + std::size_t paired_side(std::size_t index) const; // Returns the index of the side paired to side A, where A is the index-th side + Hyperbolic_isometry_2 side_pairing(std::size_t index) const;// Returns the isometry that maps side A to side B, where B is the index-th side, and A is the side paired to B + + std::istream& from_stream(std::istream& s); + std::ostream& to_stream(std::ostream& s) const; + + bool is_valid() const; + +private: + std::vector _vertices; + std::vector _pairings; +}; + +template std::ostream& operator<<(std::ostream& s, const Hyperbolic_fundamental_domain_2& domain); +template std::istream& operator>>(std::istream& s, Hyperbolic_fundamental_domain_2& domain); + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +template +std::size_t Hyperbolic_fundamental_domain_2::size() const{ + CGAL_precondition(is_valid()); + return _vertices.size(); +} + +template +const typename Hyperbolic_fundamental_domain_2::Point& Hyperbolic_fundamental_domain_2::vertex(std::size_t index) const{ + CGAL_precondition(is_valid()); + return _vertices[index]; +} + +template +std::size_t Hyperbolic_fundamental_domain_2::paired_side(std::size_t index) const{ + CGAL_precondition(is_valid()); + return _pairings[index]; +} + +template +Hyperbolic_isometry_2 Hyperbolic_fundamental_domain_2::side_pairing(std::size_t index) const{ + CGAL_precondition(is_valid()); + std::size_t n = size(); + std::size_t paired_index = paired_side(index); + + //const Point& p1,p2,q1,q2; + const Point& q1 = vertex(index); + const Point& q2 = vertex((index+1)%n); + const Point& p2 = vertex(paired_index); + const Point& p1 = vertex((paired_index+1)%n); + + Hyperbolic_isometry_2 isom = isometry_pairing_the_sides(p1,p2,q1,q2); + return isom; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +std::ostream& Hyperbolic_fundamental_domain_2::to_stream(std::ostream& s) const{ + std::size_t n = size(); + + s << std::to_string(n) << std::endl; + + for (int k=0; k +std::istream& Hyperbolic_fundamental_domain_2::from_stream(std::istream& s){ + _vertices.clear(); + _pairings.clear(); + + std::string line; + s >> line; + std::size_t size = std::stoi(line); + _vertices.reserve(size); + _pairings.reserve(size); + + for (int k=0; k> line; + _pairings.push_back(std::stoi(line)); + } + + for (int k=0; k> p; + _vertices.push_back(p); + } + return s; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +std::ostream& operator<<(std::ostream& s, const Hyperbolic_fundamental_domain_2& domain){ + CGAL_precondition(domain.is_valid()); + return domain.to_stream(s); +} + +template +std::istream& operator>>(std::istream& s, Hyperbolic_fundamental_domain_2& domain){ + return domain.from_stream(s); +} + +//////////////////////////////////////////////////////////////////////////////// + +template +bool Hyperbolic_fundamental_domain_2::is_valid()const{ + // Get the number of vertices + std::size_t n = _vertices.size(); + + // Check that the number of vertices is even + if (n%2){ + return false; + } + + // Check that there are as many side pairings as vertices + if (_pairings.size() != n){ + return false; + } + + // Check that the _pairings vector encodes a perfect matching of the set {0,1,\dots,n-1} + std::vector already_paired(n); + for (int k=0; k=n)){ + return false; + } + if (already_paired[paired_side]){ + return false; + } + already_paired[paired_side] = true; + } + + // Check that the vertices all lie within the open unit disk + for (int k=0; k= typename Traits::FT(1)){ + return false; + } + } + + return true; +} + +} // namespace CGAL + +#endif // CGAL_HYPERBOLIC_FUNDAMENTAL_DOMAIN_2_H diff --git a/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_fundamental_domain_factory_2.h b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_fundamental_domain_factory_2.h new file mode 100644 index 00000000000..e8c1716acc7 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_fundamental_domain_factory_2.h @@ -0,0 +1,262 @@ +// Copyright (c) 2024 +// INRIA Nancy (France), and Université Gustave Eiffel Marne-la-Vallee (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é, Loïc Dubois, Marc Pouget, Monique Teillaud + +// This file contains the declaration and the implementation of the class Hyperbolic_fundamental_domain_factory_2 + +#ifndef CGAL_HYPERBOLIC_FUNDAMENTAL_DOMAIN_FACTORY_2_H +#define CGAL_HYPERBOLIC_FUNDAMENTAL_DOMAIN_FACTORY_2_H + +#include + +#include +#include + +#include + +namespace CGAL { + +/* +Factory class, whose only purpose is to construct random fundamental domains of +closed orientable hyperbolic surfaces. The function +`make_hyperbolic_fundamental_domain_g2()` constructs such a domain for a surface of +genus 2. +*/ +template +class Hyperbolic_fundamental_domain_factory_2{ +private: + typedef typename Traits::FT _FT; + typedef typename Traits::Complex _Cmplx; + typedef typename Traits::Hyperbolic_point_2 _Point; + + Random _random; + +public: + Hyperbolic_fundamental_domain_factory_2(); + Hyperbolic_fundamental_domain_2 make_hyperbolic_fundamental_domain_g2(unsigned int seed); + +private: + float random_positive_float(); // returns number in [0,1] + float random_float(); // returns number in [-1,1] + Complex_number random_complex_float(); // returns complex z such that modulus(z) < 1 and imag(z) > 0 + + _FT exact_number_from_float(float x); + _Cmplx exact_complex_from_float_complex(const Complex_number& z); + + bool try_to_compute_inexact_z0_from_z1_z2_z3(Complex_number& z0, Complex_number& z1, Complex_number& z2, Complex_number& z3); + bool try_to_compute_exact_z3_from_z0_z1_z2(_Cmplx& z0, _Cmplx& z1, _Cmplx& z2, _Cmplx& z3); + + bool sanity_check(_Cmplx& z0, _Cmplx& z1, _Cmplx& z2, _Cmplx& z3); + + const int CGAL_DENOMINATOR_FOR_GENERATION = 10000; +}; + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +template + Hyperbolic_fundamental_domain_factory_2::Hyperbolic_fundamental_domain_factory_2(){} + +//////////////////////////////////////////////////////////////////////////////// + +template +Hyperbolic_fundamental_domain_2 Hyperbolic_fundamental_domain_factory_2::make_hyperbolic_fundamental_domain_g2(unsigned int seed){ + + _random = Random(seed); + bool is_domain_generated = false; + _Cmplx exact_z0, exact_z1, exact_z2, exact_z3; + + while (!is_domain_generated){ + // 1. Generate inexact z0,z1,z2,z3 + Complex_number z0, z1, z2, z3; + z1 = random_complex_float(); + z2 = random_complex_float(); + z3 = random_complex_float(); + while (! try_to_compute_inexact_z0_from_z1_z2_z3(z0,z1,z2,z3)){ + z1 = random_complex_float(); + z2 = random_complex_float(); + z3 = random_complex_float(); + } + + // 2. Compute exact z0,z1,z2,z3 nearby + exact_z0 = exact_complex_from_float_complex(z0); + exact_z1 = exact_complex_from_float_complex(z1); + exact_z2 = exact_complex_from_float_complex(z2); + exact_z3 = exact_complex_from_float_complex(z3); + + // 3. Modify z3 to fix the area... + is_domain_generated = try_to_compute_exact_z3_from_z0_z1_z2(exact_z0, exact_z1, exact_z2, exact_z3); + if (is_domain_generated){ + // ... and perform a sanity check + is_domain_generated = sanity_check(exact_z0, exact_z1, exact_z2, exact_z3); + } + } + + _Cmplx exact_zero(_FT(0), _FT(0)); + std::vector<_Point> vertices; + vertices.push_back(_Point(exact_z0.real(), exact_z0.imag())); + vertices.push_back(_Point(exact_z1.real(), exact_z1.imag())); + vertices.push_back(_Point(exact_z2.real(), exact_z2.imag())); + vertices.push_back(_Point(exact_z3.real(), exact_z3.imag())); + vertices.push_back(_Point(-exact_z0.real(), -exact_z0.imag())); + vertices.push_back(_Point(-exact_z1.real(), -exact_z1.imag())); + vertices.push_back(_Point(-exact_z2.real(), -exact_z2.imag())); + vertices.push_back(_Point(-exact_z3.real(), -exact_z3.imag())); + + std::vector pairings; + for (int k=0; k<8; k++){ + pairings.push_back((k+4)%8); + } + + Hyperbolic_fundamental_domain_2 domain(vertices, pairings); + return domain; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +float Hyperbolic_fundamental_domain_factory_2::random_positive_float(){ + return _random.uniform_01(); +} + +template +float Hyperbolic_fundamental_domain_factory_2::random_float(){ + return _random.uniform_01() * 2 - 1; +} + +template +Complex_number Hyperbolic_fundamental_domain_factory_2::random_complex_float(){ + Complex_number result (random_float(), random_positive_float()); + while (norm(result) >= 1){ + result.real(random_float()); + result.imag(random_positive_float()); + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +typename Traits::FT Hyperbolic_fundamental_domain_factory_2::exact_number_from_float(float x){ + if (x< 0){ + return _FT(0)-exact_number_from_float(-x); + } + return _FT(int(x*CGAL_DENOMINATOR_FOR_GENERATION)%CGAL_DENOMINATOR_FOR_GENERATION)/_FT(CGAL_DENOMINATOR_FOR_GENERATION); +} + +template +typename Traits::Complex Hyperbolic_fundamental_domain_factory_2::exact_complex_from_float_complex(const Complex_number& z){ + return _Cmplx(exact_number_from_float(z.real()), exact_number_from_float(z.imag())); +} + +//////////////////////////////////////////////////////////////////////////////// + +template +bool Hyperbolic_fundamental_domain_factory_2::try_to_compute_inexact_z0_from_z1_z2_z3(Complex_number& z0, Complex_number& z1, Complex_number& z2, Complex_number& z3){ + if ( ((z2/z1).imag()<=0) || ((z3/z2).imag()<=0) ){ + return false; + } + + Complex_number one (1,0); + Complex_number u = (one - conj(z1*z2)) * (one - conj(z2*z3)); + float a = -(conj(u*z1)*z3).imag(); + float b = (u*(conj(z3-z1))).imag(); + float c = u.imag(); + + const float COMPUTATION_TRESHOLD = 0.00001; + if (a+b+c> 0 - COMPUTATION_TRESHOLD){ + return false; + } + + z0.real( 2*c/(std::sqrt(b*b-4*a*c)-b) ); + z0.imag(0); + return true; +} + +template +bool Hyperbolic_fundamental_domain_factory_2::try_to_compute_exact_z3_from_z0_z1_z2(_Cmplx& z0, _Cmplx& z1, _Cmplx& z2, _Cmplx& z3){ + _FT zero_number (0); + _FT one_number (1); + if ( (z0.real()<=zero_number) || (z1.imag()<=zero_number) || (z2.imag()<=zero_number) || (z3.imag()<=zero_number) ){ + return false; + } + + if ( (norm(z0)>=one_number) || (norm(z1)>=one_number) || (norm(z2)>=one_number) || (norm(z3)>=one_number) ){ + return false; + } + + if ( ((z1/z0).imag()<=zero_number) || ((z2/z1).imag()<=zero_number) || ((z3/z2).imag()<=zero_number) ){ + return false; + } + + _Cmplx one_cmplx (_FT(1), _FT(0)); + _Cmplx two_cmplx(_FT(2), _FT(0)); + + _Cmplx f_of_z0 = two_cmplx * z0 / (z0*z0 + one_cmplx); + _Cmplx f_of_z1 = (z0 + z1) / (z0*z1 + one_cmplx); + _Cmplx f_of_z2 = (z0 + z2) / (z0*z2 + one_cmplx); + _Cmplx f_of_z3 = (z0 + z3) / (z0*z3 + one_cmplx); + + _Cmplx intermediate = (one_cmplx - f_of_z0*conj(f_of_z1)) * (one_cmplx - f_of_z1*conj(f_of_z2)); + _FT P_of_zero = intermediate.imag(); + _FT P_of_one = (intermediate * (one_cmplx-f_of_z2*conj(f_of_z3))).imag(); + + if (P_of_one == P_of_zero){ + return false; + } + + _FT lbda = P_of_zero / (P_of_zero - P_of_one); + _Cmplx V (lbda*(f_of_z3.real()), lbda*(f_of_z3.imag())); + + if ( (V.imag()<=zero_number) || (norm(V)>=one_number) || ((V/f_of_z2).imag()<=zero_number) ){ + return false; + } + + z3 = (V - z0) / (one_cmplx - z0*V); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +bool Hyperbolic_fundamental_domain_factory_2::sanity_check(_Cmplx& z0, _Cmplx& z1, _Cmplx& z2, _Cmplx& z3){ + _FT zero_number(0); + _FT one_number(1); + + // 1. Check the positions + if ( (z0.imag()!=zero_number) || (z0.real()<=zero_number) || (z1.imag()<=zero_number) || (z2.imag()<=zero_number) || (z3.imag()<=zero_number) ){ + return false; + } + + if ( (norm(z0)>=one_number) || (norm(z1)>=one_number) || (norm(z2)>=one_number) || (norm(z3)>=one_number) ){ + return false; + } + + if ( ((z2/z1).imag()<=zero_number) || ((z3/z2).imag()<=zero_number) ){ + return false; + } + + // 2. Check the area + _Cmplx one_cmplx (one_number, zero_number); + _Cmplx Z = (one_cmplx-z0*conj(z1)) * (one_cmplx-z1*conj(z2)) *(one_cmplx-z2*conj(z3)) *(one_cmplx+z3*conj(z0)); + if (Z.imag()!=zero_number){ + return false; + } + + return true; +} + +} // namespace CGAL + +#endif // CGAL_HYPERBOLIC_FUNDAMENTAL_DOMAIN_FACTORY_2_H diff --git a/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_isometry_2.h b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_isometry_2.h new file mode 100644 index 00000000000..deaeab8f066 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_isometry_2.h @@ -0,0 +1,196 @@ +// Copyright (c) 2024 +// INRIA Nancy (France), and Université Gustave Eiffel Marne-la-Vallee (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é, Loïc Dubois, Marc Pouget, Monique Teillaud + +// This file contains the declaration and the implementation of the class Hyperbolic_isometry_2 + +#ifndef CGAL_HYPERBOLIC_ISOMETRY_2_H +#define CGAL_HYPERBOLIC_ISOMETRY_2_H + +#include + +#include + +namespace CGAL { + +/* +Represents a hyperbolic isometry in the Poincare disk model the hyperbolic plane. The isometry f is stored as list (c0, c1, c2, c3) of 4 complex numbers, +so that f(z) = (c0 z + c1) / (c2 z + c3) holds on every complex z in the open unit disk. +*/ +template +class Hyperbolic_isometry_2{ +public: + typedef Hyperbolic_isometry_2 Self; + typedef typename Traits::FT FT; + typedef typename Traits::Complex Complex_number; + typedef typename Traits::Hyperbolic_point_2 Point; + + Hyperbolic_isometry_2(); + Hyperbolic_isometry_2(const Complex_number& c0, const Complex_number& c1, const Complex_number& c2, const Complex_number& c3); + + void set_to_identity(); + + // Can be used to set the coefficients manually. Warning : the implementation does not check that the resulting moebius transform fixes the unit circle. + void set_coefficients(const Complex_number& c0, const Complex_number& c1, const Complex_number& c2, const Complex_number& c3); + void set_coefficient(int index, const Complex_number& coefficient); + + // Returns the index-th coefficient + const Complex_number& get_coefficient(int index) const; + + // Evaluates the isometry at point + Point evaluate(const Point& point) const; + Point operator()(const Point& point) const; + +private: + Complex_number _coefficients[4]; +}; + +// returns the composition of two isometries. +template + Hyperbolic_isometry_2 operator*(const Hyperbolic_isometry_2& iso1, const Hyperbolic_isometry_2& iso2); + + template std::ostream& operator<<(std::ostream& s, const Hyperbolic_isometry_2& isometry); + +// When inverse=false, returns the hyperbolic translation that maps -p to zero, and zero to p. Otherwise, returns the hyperbolic translation that maps p to zero, and zero to -p. +template +Hyperbolic_isometry_2 hyperbolic_translation(const typename Traits::Hyperbolic_point_2& p, bool inverse=false); + +// When inverse=false, returns the hyperbolic rotation around zero that maps p to q. Otherwise, returns the hyperbolic rotation around zero that maps q to p. +template +Hyperbolic_isometry_2 hyperbolic_rotation(const typename Traits::Hyperbolic_point_2& p, const typename Traits::Hyperbolic_point_2& q, bool inverse=false); + +// Returns the hyperbolic isometry that maps p1 to q1 and p2 to q2 +template +Hyperbolic_isometry_2 isometry_pairing_the_sides(const typename Traits::Hyperbolic_point_2& p1, const typename Traits::Hyperbolic_point_2& p2, const typename Traits::Hyperbolic_point_2& q1, const typename Traits::Hyperbolic_point_2& q2); + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +template +Hyperbolic_isometry_2::Hyperbolic_isometry_2(){ + set_to_identity(); +} + +template +Hyperbolic_isometry_2::Hyperbolic_isometry_2(const Complex_number& c0, const Complex_number& c1, const Complex_number& c2, const Complex_number& c3){ + set_coefficients(c0,c1,c2,c3); +} +//////////////////////////////////////////////////////////////////////////////// + +template +void Hyperbolic_isometry_2::set_to_identity(){ + set_coefficients(Complex_number(FT(1)), + Complex_number(FT(0)), + Complex_number(FT(0)), + Complex_number(FT(1))); +} + +template +void Hyperbolic_isometry_2::set_coefficients(const Complex_number& c0, const Complex_number& c1, const Complex_number& c2, const Complex_number& c3){ + set_coefficient(0, c0); + set_coefficient(1, c1); + set_coefficient(2, c2); + set_coefficient(3, c3); +} + +template +void Hyperbolic_isometry_2::set_coefficient(int index, const Complex_number& coefficient){ + _coefficients[index] = coefficient; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +const typename Traits::Complex& Hyperbolic_isometry_2::get_coefficient(int index) const{ + return _coefficients[index]; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +typename Traits::Hyperbolic_point_2 Hyperbolic_isometry_2::evaluate(const Point& point) const{ + Complex_number z (point.x(), point.y()); + Complex_number numerator_of_the_result = _coefficients[0] * z + _coefficients[1]; + Complex_number denominator_of_the_result = _coefficients[2] * z + _coefficients[3]; + Complex_number result = numerator_of_the_result / denominator_of_the_result; + return Point(result.real(), result.imag()); +} + + template + typename Traits::Hyperbolic_point_2 Hyperbolic_isometry_2::operator()(const Point& point) const{ + return evaluate(point); +} +//////////////////////////////////////////////////////////////////////////////// + +template + Hyperbolic_isometry_2 operator*(const Hyperbolic_isometry_2& iso1, const Hyperbolic_isometry_2& iso2) { + Hyperbolic_isometry_2 result; + for (int i=0; i<2; i++){ + for (int j=0; j<2; j++){ + result.set_coefficient(2*i+j, + iso1.get_coefficient(2*i) * iso2.get_coefficient(j) + iso1.get_coefficient(2*i+1) * iso2.get_coefficient(2+j)); + } + } + return result; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +std::ostream& operator<<(std::ostream& s, const Hyperbolic_isometry_2& isometry){ + for (int k=0; k<4; k++){ + s << isometry.get_coefficient(k); + } + return s; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +Hyperbolic_isometry_2 hyperbolic_translation(const typename Traits::Hyperbolic_point_2& p, bool inverse){ + typename Traits::Complex one (typename Traits::FT(1)); + typename Traits::Complex z; + if (inverse){ + z = typename Traits::Complex(p.x(), p.y()); + } else { + z = - typename Traits::Complex(p.x(), p.y()); + } + Hyperbolic_isometry_2 result; + result.set_coefficients(one, z, conj(z), one); + return result; +} + +template +Hyperbolic_isometry_2 hyperbolic_rotation(const typename Traits::Hyperbolic_point_2& p, const typename Traits::Hyperbolic_point_2& q, bool inverse){ + typename Traits::Complex zero (typename Traits::FT(0)); + Hyperbolic_isometry_2 result; + if (inverse){ + result.set_coefficients(typename Traits::Complex(p.x(), p.y()), zero, zero, typename Traits::Complex(q.x(), q.y())); + } else { + result.set_coefficients(typename Traits::Complex(q.x(), q.y()), zero, zero, typename Traits::Complex(p.x(), p.y())); + } + return result; +} + +template +Hyperbolic_isometry_2 isometry_pairing_the_sides(const typename Traits::Hyperbolic_point_2& p1, const typename Traits::Hyperbolic_point_2& p2, const typename Traits::Hyperbolic_point_2& q1, const typename Traits::Hyperbolic_point_2& q2){ + Hyperbolic_isometry_2 A,B,Binv,C; + A = hyperbolic_translation(p1); + B = hyperbolic_translation(q1); + Binv = hyperbolic_translation(q1,true); + C = hyperbolic_rotation(A.evaluate(p2), B.evaluate(q2)); + return (Binv*C)*A; +} + +} // namespace CGAL + +#endif // CGAL_HYPERBOLIC_ISOMETRY_2_H diff --git a/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_surface_traits_2.h b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_surface_traits_2.h new file mode 100644 index 00000000000..55cf891084d --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Hyperbolic_surface_traits_2.h @@ -0,0 +1,36 @@ +// Copyright (c) 2024 +// INRIA Nancy (France), and Université Gustave Eiffel Marne-la-Vallee (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é, Loïc Dubois, Marc Pouget, Monique Teillaud + +// This file contains the declaration and the implementation of the class Hyperbolic_surface_traits_2 + +#ifndef CGAL_HYPERBOLIC_SURFACE_TRAITS_2 +#define CGAL_HYPERBOLIC_SURFACE_TRAITS_2 + +#include + +#include + +#include + +namespace CGAL { + +template +class Hyperbolic_surface_traits_2 : public HyperbolicTraitsClass { +public: + typedef typename HyperbolicTraitsClass::FT FT; + typedef typename HyperbolicTraitsClass::Hyperbolic_point_2 Hyperbolic_point_2; + typedef Complex_number Complex; +}; + +} // namespace CGAL + +#endif // CGAL_HYPERBOLIC_SURFACE_TRAITS_2 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 new file mode 100644 index 00000000000..5d1f431d8d1 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/include/CGAL/Triangulation_on_hyperbolic_surface_2.h @@ -0,0 +1,779 @@ +// Copyright (c) 2024 +// INRIA Nancy (France), and Université Gustave Eiffel Marne-la-Vallee (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é, Loïc Dubois, Marc Pouget, Monique Teillaud + +// This file contains the declaration and the implementation of the class Triangulation_on_hyperbolic_surface_2 + +#ifndef CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_H +#define CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_H + +#include + +#include +#include +#include + +#include +#include +#include + +namespace CGAL { + +/* +Represents a geodesic triangulation of a closed orientable hyperbolic surface. +The triangulation is stored as combinatorial map decorated with one cross-ratio per edge. +It is also possible to specify an anchor for the triangulation. An anchor consists in 1) a dart of the combinatorial map, belonging by definition to a vertex V and a triangle T, together with +2) three points A,B,C in the hyperbolic plane. The points A,B,C are the three vertices in counter-clockwise order of a triangle. This triangle is a lift +of T, and A is a lift of V. +*/ + +template +struct Combinatorial_map_with_cross_ratios_item{ + template + struct Dart_wrapper{ + typedef Cell_attribute> Edge_attrib; + typedef std::tuple Attributes; + }; + }; + +template> +class Triangulation_on_hyperbolic_surface_2 +{ +public: + + typedef Combinatorial_map<2,Attributes> Combinatorial_map_with_cross_ratios; + + struct Anchor{ + typename Combinatorial_map_with_cross_ratios::Dart_descriptor dart; + typename Traits::Hyperbolic_point_2 vertices[3]; + }; + + typedef typename Combinatorial_map_with_cross_ratios::Dart_descriptor Dart_descriptor; +//typedef typename Combinatorial_map_with_cross_ratios::Dart_range Dart_range; +// typedef typename Combinatorial_map_with_cross_ratios::Dart_range::iterator Dart_iterator; + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_range<0> Vertex_range; + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_range<1> Edge_range; + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_range<2> Face_range; + + typedef typename Combinatorial_map_with_cross_ratios::Dart_const_descriptor Dart_const_descriptor; + typedef typename Combinatorial_map_with_cross_ratios::Dart_const_range Dart_const_range; + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_const_range<0> Vertex_const_range; + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_const_range<1> Edge_const_range; + typedef typename Combinatorial_map_with_cross_ratios::template One_dart_per_cell_const_range<2> Face_const_range; + + typedef typename Traits::FT Number; + typedef typename Traits::Complex Complex_number; + typedef typename Traits::Hyperbolic_point_2 Point; + typedef Hyperbolic_isometry_2 Isometry; + typedef Hyperbolic_fundamental_domain_2 Domain; + + Triangulation_on_hyperbolic_surface_2() {}; + Triangulation_on_hyperbolic_surface_2(const Hyperbolic_fundamental_domain_2& domain); +// Triangulation_on_hyperbolic_surface_2(Combinatorial_map_with_cross_ratios& cmap); + Triangulation_on_hyperbolic_surface_2(Combinatorial_map_with_cross_ratios& cmap, Anchor& anchor); + + //Triangulation_on_hyperbolic_surface_2& operator=(Triangulation_on_hyperbolic_surface_2&& other); + Triangulation_on_hyperbolic_surface_2& operator=(Triangulation_on_hyperbolic_surface_2 other); + + Combinatorial_map_with_cross_ratios& combinatorial_map(); + bool has_anchor() const; + Anchor& anchor(); + const Anchor& anchor() const; + + void to_stream(std::ostream& s) const; + void from_stream(std::istream& s); + + bool is_Delaunay_flippable(Dart_const_descriptor dart) const; + void flip(Dart_descriptor dart); + bool is_Delaunay() const; + int make_Delaunay(); + std::vector> lift(bool center=true) const; + + bool is_valid() const; + + //The following methods are not documented but they are non private for internal future use. + + Dart_descriptor ccw(Dart_descriptor dart); + Dart_descriptor cw(Dart_descriptor dart); + Dart_descriptor opposite(Dart_descriptor dart); + Dart_const_descriptor const_ccw(Dart_const_descriptor dart) const; + Dart_const_descriptor const_cw(Dart_const_descriptor dart) const; + Dart_const_descriptor const_opposite(Dart_const_descriptor dart) const; + + Complex_number get_cross_ratio(Dart_const_descriptor dart) const; + + // Returns the cross ratio of the points a,b,c,d + Complex_number cross_ratio(const Point& a, const Point& b, const Point& c, const Point& d) const; + // Returns the point d such that the cross ratio of a,b,c,d is cratio + Point fourth_point_from_cross_ratio(const Point& a, const Point& b, const Point& c, const Complex_number& cratio) const; + +// Wrapper around the Cmap for iterating over vertices, edges or faces. +Vertex_range vertices_range(){ + return _combinatorial_map.template one_dart_per_cell<0>(); +} +Edge_range edges_range(){ + return _combinatorial_map.template one_dart_per_cell<1>(); +} +Face_range faces_range(){ + return _combinatorial_map.template one_dart_per_cell<2>(); +} +Vertex_const_range vertices_const_range() const { + return _combinatorial_map.template one_dart_per_cell<0>(); +} +Edge_const_range edges_const_range() const { + return _combinatorial_map.template one_dart_per_cell<1>(); +} +Face_const_range faces_const_range() const { + return _combinatorial_map.template one_dart_per_cell<2>(); +} + +protected: + Combinatorial_map_with_cross_ratios _combinatorial_map; + bool _has_anchor = false; + Anchor _anchor; + + Dart_descriptor pick_edge_to_flip(); + Dart_const_descriptor pick_edge_to_flip() const; + + void copy_from(Combinatorial_map_with_cross_ratios& cmap); + void copy_from(Combinatorial_map_with_cross_ratios& cmap, const Anchor& anchor); +}; + + template std::ostream& operator<<(std::ostream& s, const Triangulation_on_hyperbolic_surface_2& triangulation); + template void operator>>(std::istream& s, Triangulation_on_hyperbolic_surface_2& triangulation); + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +template +Triangulation_on_hyperbolic_surface_2::Triangulation_on_hyperbolic_surface_2(const Domain& domain){ + // (Triangulates by adding an internal edge between domain.vertex(size-1) and the other vertices) + _combinatorial_map.clear(); + int size = domain.size(); + + // Make the triangles + std::vector dart_of_triangle(size-2); + for (int k=0; k(dart_1, dart_2); + _combinatorial_map.template set_attribute<1>(dart_1, _combinatorial_map.template create_attribute<1>(cross_ratio(p0,p1,p2,p3))); + } + + // Sew the boundary edges and set their cross ratios + for (int k1=0; k1(dart_1, dart_2)){ + _combinatorial_map.template sew<2>(dart_1, dart_2); + _combinatorial_map.template set_attribute<1>(dart_1, _combinatorial_map.template create_attribute<1>(cross_ratio(p0,p1,p2,p3))); + } + } + + // Set the anchor + _anchor.dart = dart_of_triangle[0]; + _anchor.vertices[0] = domain.vertex(size-1); + _anchor.vertices[1] = domain.vertex(0); + _anchor.vertices[2] = domain.vertex(1); + _has_anchor = true; +} + +/* template */ +/* Triangulation_on_hyperbolic_surface_2::Triangulation_on_hyperbolic_surface_2(Combinatorial_map_with_cross_ratios& cmap){ */ +/* copy_from(cmap); */ +/* } */ + +template + Triangulation_on_hyperbolic_surface_2::Triangulation_on_hyperbolic_surface_2(Combinatorial_map_with_cross_ratios& cmap, Anchor& anchor){ + copy_from(cmap, anchor); +} + +//////////////////////////////////////////////////////////////////////////////// + +template + Triangulation_on_hyperbolic_surface_2& Triangulation_on_hyperbolic_surface_2::operator=(Triangulation_on_hyperbolic_surface_2 other){ + CGAL_precondition(other->is_valid()); + if (other.has_anchor()){ + copy_from(other.combinatorial_map(), other.anchor()); + } + else { + copy_from(other.combinatorial_map()); + } + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +typename Triangulation_on_hyperbolic_surface_2::Combinatorial_map_with_cross_ratios& Triangulation_on_hyperbolic_surface_2::combinatorial_map(){ + return _combinatorial_map; +} + +template +bool Triangulation_on_hyperbolic_surface_2::has_anchor() const { + CGAL_precondition(is_valid()); + return _has_anchor; +} + +template +typename Triangulation_on_hyperbolic_surface_2::Anchor& +Triangulation_on_hyperbolic_surface_2::anchor() { + CGAL_precondition(is_valid() && has_anchor()); + return _anchor; +} + +template +const typename Triangulation_on_hyperbolic_surface_2::Anchor& +Triangulation_on_hyperbolic_surface_2::anchor() const { + CGAL_precondition(is_valid() && has_anchor()); + return _anchor; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +bool Triangulation_on_hyperbolic_surface_2::is_Delaunay_flippable(Dart_const_descriptor dart) const{ + CGAL_precondition(is_valid()); + return ( get_cross_ratio(dart).imag()>Number(0) ); +} + +template +void Triangulation_on_hyperbolic_surface_2::flip(Dart_descriptor dart){ + CGAL_precondition(is_valid()); + // First gather all the information needed + + Dart_descriptor a = opposite(dart); // Get a fresh descriptor + Dart_descriptor b = ccw(a); + Dart_descriptor c = cw(a); + + Dart_descriptor d = opposite(a); + Dart_descriptor e = ccw(d); + Dart_descriptor f = cw(d); + + Complex_number cross_ratio_AB = get_cross_ratio(e); + Complex_number cross_ratio_BC = get_cross_ratio(f); + Complex_number cross_ratio_CD = get_cross_ratio(b); + Complex_number cross_ratio_DA = get_cross_ratio(c); + Complex_number cross_ratio_AC = get_cross_ratio(a); + + // Modify the anchor + + if (_anchor.dart == a){ + _anchor.dart = e; + _anchor.vertices[1] = Point(fourth_point_from_cross_ratio(_anchor.vertices[1], _anchor.vertices[2], _anchor.vertices[0], cross_ratio_AC)); + } else if (_anchor.dart == b){ + _anchor.vertices[2] = Point(fourth_point_from_cross_ratio(_anchor.vertices[0], _anchor.vertices[1], _anchor.vertices[2], cross_ratio_AC)); + } else if (_anchor.dart == c){ + _anchor.vertices[2] = Point(fourth_point_from_cross_ratio(_anchor.vertices[2], _anchor.vertices[0], _anchor.vertices[1], cross_ratio_AC)); + } else if (_anchor.dart == d){ + _anchor.dart = b; + _anchor.vertices[1] = Point(fourth_point_from_cross_ratio(_anchor.vertices[1], _anchor.vertices[2], _anchor.vertices[0], cross_ratio_AC)); + } else if (_anchor.dart == e){ + _anchor.vertices[2] = Point(fourth_point_from_cross_ratio(_anchor.vertices[0], _anchor.vertices[1], _anchor.vertices[2], cross_ratio_AC)); + } else if (_anchor.dart == f){ + _anchor.vertices[2] = Point(fourth_point_from_cross_ratio(_anchor.vertices[2], _anchor.vertices[0], _anchor.vertices[1], cross_ratio_AC)); + } + + // Compute the new cross ratios + + Complex_number one (Number(1), Number(0)); + Complex_number cross_ratio_BD = (cross_ratio_AC) / ((cross_ratio_AC) - one) ; + Complex_number cross_ratio_AB_2 = one - (one - (cross_ratio_AB)) * (cross_ratio_AC) ; + Complex_number cross_ratio_BC_2 = one - (one - (cross_ratio_BC)) / (cross_ratio_BD) ; + Complex_number cross_ratio_CD_2 = one - (one - (cross_ratio_CD)) * (cross_ratio_AC) ; + Complex_number cross_ratio_DA_2 = one - (one - (cross_ratio_DA)) / (cross_ratio_BD) ; + + // Make the topological flip + + _combinatorial_map.template unlink_beta<1>(a); + _combinatorial_map.template unlink_beta<1>(b); + _combinatorial_map.template unlink_beta<1>(c); + + _combinatorial_map.template unlink_beta<1>(d); + _combinatorial_map.template unlink_beta<1>(e); + _combinatorial_map.template unlink_beta<1>(f); + + + _combinatorial_map.template link_beta<1>(b, a); + _combinatorial_map.template link_beta<1>(a, f); + _combinatorial_map.template link_beta<1>(f, b); + + _combinatorial_map.template link_beta<1>(e, d); + _combinatorial_map.template link_beta<1>(d, c); + _combinatorial_map.template link_beta<1>(c, e); + + // And give the new cross ratios to the edges + + _combinatorial_map.template info<1>(a) = cross_ratio_BD; + _combinatorial_map.template info<1>(e) = cross_ratio_AB_2; + _combinatorial_map.template info<1>(f) = cross_ratio_BC_2; + _combinatorial_map.template info<1>(b) = cross_ratio_CD_2; + _combinatorial_map.template info<1>(c) = cross_ratio_DA_2; + + // Take care of the particular cases where we need to "flip again" + + if (opposite(e) == b){ + _combinatorial_map.template info<1>(e) = one - (one - cross_ratio_AB_2) * (cross_ratio_AC) ; + } + + if (opposite(f) == c){ + _combinatorial_map.template info<1>(f) = one - (one - cross_ratio_BC_2) / (cross_ratio_BD) ; + } +} + +template +bool Triangulation_on_hyperbolic_surface_2::is_Delaunay() const{ + if (! is_valid()){ + return false; + } + return (pick_edge_to_flip() == nullptr); +} + +template +int Triangulation_on_hyperbolic_surface_2::make_Delaunay(){ + CGAL_precondition(is_valid()); + int number_of_flips_done = 0; + + Dart_descriptor edge_to_flip = pick_edge_to_flip(); + while (edge_to_flip != nullptr){ + flip(edge_to_flip); + edge_to_flip = pick_edge_to_flip(); + number_of_flips_done++; + } + + return number_of_flips_done; +} + + +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()); + std::vector> realizations; + + size_t visited_darts_mark = _combinatorial_map.get_new_mark(); + _combinatorial_map.unmark_all(visited_darts_mark); + + struct Compare { + bool operator()(std::pair const & x, std::pair const & y) { + return x.second > y.second; + } + }; + std::priority_queue, std::vector>, Compare> queue; + + std::unordered_map positions; + + 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); + + 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]); + } else { + 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)]); + 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()); + + 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)); + + + + while( ! queue.empty() ){ + Dart_const_descriptor invader = queue.top().first; + queue.pop(); + + Dart_const_descriptor invaded = const_opposite(invader); + + if (!_combinatorial_map.is_marked(invaded, visited_darts_mark)){ + _combinatorial_map.mark(invaded, visited_darts_mark); + _combinatorial_map.mark(const_ccw(invaded), visited_darts_mark); + _combinatorial_map.mark(const_cw(invaded), visited_darts_mark); + + const Point &a = positions[const_ccw(invader)]; + const Point &b = positions[const_cw(invader)]; + const Point &c = positions[invader]; + Complex_number cross_ratio = get_cross_ratio(invader); + + positions[invaded] = a; + positions[const_ccw(invaded)] = c; + Point d = fourth_point_from_cross_ratio(a, b, c, cross_ratio); + positions[const_cw(invaded)] = d; + + Complex_number za (a.x(), a.y()); + Complex_number zc (c.x(), c.y()); + double invaded_distance_to_zero = CGAL::to_double(norm(za)); + double invaded_ccw_distance_to_zero = CGAL::to_double(norm(zc)); + Complex_number znew (positions[const_cw(invaded)].x(), positions[const_cw(invaded)].y()); + double invaded_cw_distance_to_zero = CGAL::to_double(norm(znew)); + + double invaded_ccw_weight = invaded_ccw_distance_to_zero + invaded_cw_distance_to_zero; + double invaded_cw_weight = invaded_cw_distance_to_zero + invaded_distance_to_zero; + + queue.push( std::make_pair(const_ccw(invaded), invaded_ccw_weight) ); + queue.push( std::make_pair(const_cw(invaded), invaded_cw_weight) ); + + value = std::make_tuple(invaded, Point(a), Point(c), Point(d)); + realizations.push_back(value); + } + } + + _combinatorial_map.free_mark(visited_darts_mark); + + return realizations; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +bool Triangulation_on_hyperbolic_surface_2::is_valid() const{ + // 1. Check the combinatorial map + + // Check that the combinatorial map is valid + if ( !_combinatorial_map.is_valid() ){ + return false; + } + + // Check that the combinatorial map has no 1,2-boundary + for (int k=1; k<3; k++){ + if ( !_combinatorial_map.is_without_boundary(k) ){ + return false; + } + } + + // 2. Check the anchor, if any + + if (_has_anchor){ + // Check that the dart descriptor of the anchor points to a dart of the combinatorial map + if ( !_combinatorial_map.is_dart_used(_anchor.dart) ){ + return false; + } + + // Check that the three vertices of the anchor lie within the open unit disk + for (int k=0; k<3; k++){ + // if (_anchor.vertices[k].get_z() >= Number(1)){ + if ( norm(Complex_number(_anchor.vertices[k].x(),_anchor.vertices[k].y())) >= Number(1)){ + return false; + } + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +void Triangulation_on_hyperbolic_surface_2::to_stream(std::ostream& s) const{ + CGAL_precondition(is_valid() && has_anchor()); + // Give indices to the darts + std::map darts_indices; + int current_dart_index = 0; + for (typename Dart_const_range::const_iterator it=_combinatorial_map.darts().begin(); it!=_combinatorial_map.darts().end(); ++it){ + darts_indices[it] = current_dart_index; + current_dart_index++; + } + + // Store the number of darts + s << current_dart_index << std::endl; + + // Store the anchor, if any + if (_has_anchor){ + s << "yes" << std::endl; + s << darts_indices[_anchor.dart] << std::endl; + s << _anchor.vertices[0] << std::endl; + s << _anchor.vertices[1] << std::endl; + s << _anchor.vertices[2] << std::endl; + } else { + s << "no" << std::endl; + } + + // Store the triangles + for (typename Face_const_range::const_iterator it = faces_const_range().begin(); it != faces_const_range().end(); ++it){ + s << darts_indices[it] << std::endl; + s << darts_indices[const_cw(it)] << std::endl; + s << darts_indices[const_ccw(it)] << std::endl; + } + + // Store the edges + for (typename Edge_const_range::const_iterator it = edges_const_range().begin(); it != edges_const_range().end(); ++it){ + s << darts_indices[it] << std::endl; + s << darts_indices[const_opposite(it)] << std::endl; + s << get_cross_ratio(it); + } +} + +template +void Triangulation_on_hyperbolic_surface_2::from_stream(std::istream& s){ + _combinatorial_map.clear(); + + // Load the number of darts + std::string line; + s >> line; + int nb_darts = std::stoi(line); + + // Load the anchor + int anchor_dart_id; + s >> line; + if (!line.compare("yes")){ + _has_anchor = true; + + s >> line; + anchor_dart_id = std::stoi(line); // (*) _anchor.dart_id is set at the end of the function + + s >> _anchor.vertices[0]; + s >> _anchor.vertices[1]; + s >> _anchor.vertices[2]; + } else { + _has_anchor = false; + } + + // Load the triangles + std::vector darts_by_id (nb_darts); + int index1, index2, index3; + for (int k=0; k> line; + index1 = std::stoi(line); + s >> line; + index2 = std::stoi(line); + s >> line; + index3 = std::stoi(line); + + darts_by_id[index1] = triangle_dart; + darts_by_id[index2] = cw(triangle_dart); + darts_by_id[index3] = ccw(triangle_dart); + } + + // Load the edges + Dart_descriptor dart_1, dart_2; + Complex_number cross_ratio; + for (int k=0; k> line; + index1 = std::stoi(line); + s >> line; + index2 = std::stoi(line); + dart_1 = darts_by_id[index1]; + dart_2 = darts_by_id[index2]; + _combinatorial_map.template sew<2>(dart_1, dart_2); + s >> cross_ratio; + _combinatorial_map.template set_attribute<1>(dart_1, _combinatorial_map.template create_attribute<1>(cross_ratio)); + } + + // (*) here + if (_has_anchor){ + _anchor.dart = darts_by_id[anchor_dart_id]; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +template +std::ostream& operator<<(std::ostream& s, const Triangulation_on_hyperbolic_surface_2& triangulation){ + triangulation.to_stream(s); + return s; +} + +template +void operator>>(std::istream& s, Triangulation_on_hyperbolic_surface_2& triangulation){ + triangulation.from_stream(s); +} + +//////////////////////////////////////////////////////////////////////////////// + +template +typename Triangulation_on_hyperbolic_surface_2::Dart_descriptor Triangulation_on_hyperbolic_surface_2::ccw(Dart_descriptor dart){ + return _combinatorial_map.beta(dart, 1); +} + +template +typename Triangulation_on_hyperbolic_surface_2::Dart_descriptor Triangulation_on_hyperbolic_surface_2::cw(Dart_descriptor dart){ + return _combinatorial_map.beta(dart, 0); +} + +template +typename Triangulation_on_hyperbolic_surface_2::Dart_descriptor Triangulation_on_hyperbolic_surface_2::opposite(Dart_descriptor dart){ + return _combinatorial_map.opposite(dart); +} + +template +typename Triangulation_on_hyperbolic_surface_2::Dart_const_descriptor Triangulation_on_hyperbolic_surface_2::const_ccw(Dart_const_descriptor dart) const{ + return _combinatorial_map.beta(dart, 1); +} + +template +typename Triangulation_on_hyperbolic_surface_2::Dart_const_descriptor Triangulation_on_hyperbolic_surface_2::const_cw(Dart_const_descriptor dart) const{ + return _combinatorial_map.beta(dart, 0); +} + +template +typename Triangulation_on_hyperbolic_surface_2::Dart_const_descriptor Triangulation_on_hyperbolic_surface_2::const_opposite(Dart_const_descriptor dart) const{ + return _combinatorial_map.opposite(dart); +} + +//////////////////////////////////////////////////////////////////////////////// + +template +typename Triangulation_on_hyperbolic_surface_2::Complex_number Triangulation_on_hyperbolic_surface_2::get_cross_ratio(Dart_const_descriptor dart) const{ + return _combinatorial_map.template info_of_attribute<1>(_combinatorial_map.template attribute<1>(dart)); +} + +//////////////////////////////////////////////////////////////////////////////// +template + typename Triangulation_on_hyperbolic_surface_2::Dart_descriptor Triangulation_on_hyperbolic_surface_2::pick_edge_to_flip(){ + auto &cm=_combinatorial_map.darts(); + for (auto it = cm.begin(); it != cm.end(); ++it){ + if ( is_Delaunay_flippable(it) ){ + return it; + } + } + return nullptr; +} + +//////////////////////////////////////////////////////////////////////////////// + +template + typename Triangulation_on_hyperbolic_surface_2::Dart_const_descriptor Triangulation_on_hyperbolic_surface_2::pick_edge_to_flip() const{ + const auto &cm=_combinatorial_map.darts(); + for (auto it = cm.begin(); it != cm.end(); ++it){ + if ( is_Delaunay_flippable(it) ){ + return it; + } + } + return nullptr; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +void Triangulation_on_hyperbolic_surface_2::copy_from(Combinatorial_map_with_cross_ratios& cmap){ + //_combinatorial_map.copy_from_const(cmap); + _combinatorial_map.copy(cmap); + _has_anchor = false; +} + +template +void Triangulation_on_hyperbolic_surface_2::copy_from(Combinatorial_map_with_cross_ratios& cmap, const Anchor& anchor){ + // Because of the anchor, we must operate the copy ourself + _combinatorial_map.clear(); + + // Copy the triangles and fill the darts conversion table + std::map darts_table; + for (typename Face_const_range::const_iterator it=cmap.template one_dart_per_cell<2>().begin(); it!=cmap.template one_dart_per_cell<2>().end(); ++it){ + Dart_descriptor new_dart = _combinatorial_map.make_combinatorial_polygon(3); + darts_table[it] = new_dart; + darts_table[cmap.beta(it,0)] = _combinatorial_map.beta(new_dart,0); + darts_table[cmap.beta(it,1)] = _combinatorial_map.beta(new_dart,1); + } + + // Sew the edges and set their cross-ratios + for (typename Edge_const_range::const_iterator it=cmap.template one_dart_per_cell<1>().begin(); it!=cmap.template one_dart_per_cell<1>().end(); ++it){ + Dart_descriptor dart_1 = darts_table[it]; + Dart_descriptor dart_2 = darts_table[cmap.opposite(it)]; + Complex_number cratio = cmap.template info_of_attribute<1>(cmap.template attribute<1>(it)); + + _combinatorial_map.template sew<2>(dart_1, dart_2); + _combinatorial_map.template set_attribute<1>(dart_1, _combinatorial_map.template create_attribute<1>(cratio)); + } + + cmap.opposite(anchor.dart); + + // Set the anchor + _anchor.dart = darts_table[anchor.dart]; + for (int k=0; k<3; k++){ + _anchor.vertices[k] = anchor.vertices[k]; + } + _has_anchor = true; +} + +//////////////////////////////////////////////////////////////////////////////// + +template +typename Traits::Complex Triangulation_on_hyperbolic_surface_2::cross_ratio(const Point& a, const Point& b, const Point& c, const Point& d) const{ + Complex_number za (a.x(), a.y()); + Complex_number zb (b.x(), b.y()); + Complex_number zc (c.x(), c.y()); + Complex_number zd (d.x(), d.y()); + return (zd-zb)*(zc-za) / ((zd-za)*(zc-zb)); +} + +template +typename Triangulation_on_hyperbolic_surface_2::Point Triangulation_on_hyperbolic_surface_2::fourth_point_from_cross_ratio(const Point& a, const Point& b, const Point& c, const Complex_number& cratio) const{ + Complex_number za (a.x(), a.y()); + Complex_number zb (b.x(), b.y()); + Complex_number zc (c.x(), c.y()); + Complex_number result = ( cratio*za*(zc-zb) + zb*(za-zc) ) / ( cratio*(zc-zb) + (za-zc) ); + return Point(result.real(), result.imag()); +} + +} // namespace CGAL + +#endif // CGAL_TRIANGULATION_ON_HYPERBOLIC_SURFACE_2_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 new file mode 100644 index 00000000000..f6c522d5bf5 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/copyright @@ -0,0 +1,3 @@ +INRIA Nancy -- France +Université de Lorraine -- France +Université Gustave Eiffel Marne-la-Vallee -- France diff --git a/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/dependencies b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/dependencies new file mode 100644 index 00000000000..62d19a14d67 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/dependencies @@ -0,0 +1,26 @@ +Algebraic_foundations +Arithmetic_kernel +BGL +CGAL_Core +Cartesian_kernel +Circulator +Combinatorial_map +Distance_2 +Distance_3 +Filtered_kernel +Hash_map +Homogeneous_kernel +Installation +Intersections_2 +Intersections_3 +Interval_support +Kernel_23 +Kernel_d +Modular_arithmetic +Number_types +Profiling_tools +Property_map +Random_numbers +STL_Extension +Stream_support +Triangulation_on_hyperbolic_surface_2 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 new file mode 100644 index 00000000000..11623cbdb12 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/description.txt @@ -0,0 +1,5 @@ +Package Triangulation_on_hyperbolic_surface_2 : provides +triangulations of closed oriented hyperbolic surfaces, +Delaunay flip algorithm on those triangulations, +construction of the triangulations from convex geodesic fundamental domains, +construction of such domains for genus 2 surfaces diff --git a/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/license.txt b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/license.txt new file mode 100644 index 00000000000..8bb8efcb72b --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/license.txt @@ -0,0 +1 @@ +GPL (v3 or later) 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 new file mode 100644 index 00000000000..6f51f82623f --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/package_info/Triangulation_on_hyperbolic_surface_2/maintainer @@ -0,0 +1,3 @@ +Vincent Despré +Loïc Dubois +Monique Teillaud diff --git a/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/CMakeLists.txt b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/CMakeLists.txt new file mode 100644 index 00000000000..a7118ad36d6 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/CMakeLists.txt @@ -0,0 +1,21 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + +cmake_minimum_required(VERSION 3.1...3.23) +project(Triangulation_on_hyperbolic_surface_2_Tests) + +find_package(CGAL REQUIRED) + +set(CMAKE_BUILD_TYPE "Debug") + +include_directories(../../include/) +include_directories(/Users/pougetma/dev/cgal-loic-submission-2024/Installation/include/) + +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_circular_kernel.cpp b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_circular_kernel.cpp new file mode 100644 index 00000000000..fa3de900aa2 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_circular_kernel.cpp @@ -0,0 +1,62 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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::Triangulation_on_hyperbolic_surface_2 Triangulation; + +typedef typename Traits::Hyperbolic_point_2 Point; + +int main() { + Factory factory; + Domain domain = factory.make_hyperbolic_fundamental_domain_g2(3459); + Triangulation triangulation0 = Triangulation(domain); + + assert( triangulation0.is_valid() ); + + Triangulation triangulation (triangulation0); + assert( triangulation.has_anchor() ); + + std::stringstream buffer; + buffer << triangulation; + buffer >> triangulation; + + std::vector> input_not_centered; + std::vector> input_centered; + + input_not_centered = triangulation.lift(false); + input_centered = triangulation.lift(); + + triangulation.make_Delaunay(); + + assert( triangulation.is_Delaunay() ); + + std::vector> output_not_centered; + std::vector> output_centered; + + output_not_centered = triangulation.lift(false); + output_centered = triangulation.lift(); + + + Triangulation::Combinatorial_map_with_cross_ratios& cmap = triangulation.combinatorial_map(); + Triangulation::Anchor& anchor = triangulation.anchor(); + assert( cmap.is_dart_used(anchor.dart) ); + + std::cout << "printing triangulation for test purposes : " << std::endl << triangulation; + + return 0; +} diff --git a/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_complex.cpp b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_complex.cpp new file mode 100644 index 00000000000..e1d1f8c231a --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_complex.cpp @@ -0,0 +1,50 @@ +#include +#include +#include + +#include +#include + +typedef CGAL::Exact_rational Exact_rational; +typedef CGAL::Interval_nt<> Interval; +typedef CGAL::Complex_number Complex_rational; +typedef CGAL::Complex_number Complex_interval; + +int main() { + // Complex_rational tests : + Complex_rational zero_rational = Complex_rational (); + assert( zero_rational == Complex_rational(Exact_rational(0), Exact_rational(0)) ); + + Complex_rational one_rational (Exact_rational(1)); + assert( one_rational == Complex_rational(Exact_rational(1), Exact_rational(0)) ); + + Complex_rational z1_rational (Exact_rational(1,2), Exact_rational(-3)); + z1_rational = - z1_rational; + + Complex_rational z2_rational; + z2_rational.real(Exact_rational(-5,7)); + z2_rational.imag(Exact_rational(11,13)); + z2_rational = conj(z2_rational) + z1_rational - one_rational; + + assert( - z1_rational * z1_rational / z2_rational == -Complex_rational(Exact_rational(855491,632146), Exact_rational(844298,316073)) ); + assert( z1_rational.real() == Exact_rational(-1,2) ); + assert( z1_rational.imag() == Exact_rational(3) ); + assert( norm(z1_rational) == Exact_rational(37,4) ); + assert( z1_rational != z2_rational); + assert( z2_rational == z2_rational ); + assert( z2_rational == Complex_rational(Exact_rational(-31,14), Exact_rational(28,13)) ); + + std::cout << "printing a complex for test purposes : " << std::endl << z2_rational << std::endl; + + Complex_rational z3_rational; + std::stringstream buffer; + buffer << z2_rational; + buffer >> z3_rational; + assert( z3_rational == z2_rational ); + + // Complex_interval test : + Complex_interval z_interval (Interval(1, 2), Interval(1, 2)); + assert( norm(z_interval * z_interval / Complex_interval(Interval(5, 6))) < Interval(10,20) ); + + return 0; +} diff --git a/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_domain.cpp b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_domain.cpp new file mode 100644 index 00000000000..43f7a9347d7 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_domain.cpp @@ -0,0 +1,78 @@ +#include +#include + +#include +#include +#include + +#include + +typedef CGAL::Cartesian Kernel; +typedef CGAL::Hyperbolic_Delaunay_triangulation_traits_2 ParentTraits; +typedef CGAL::Hyperbolic_surface_traits_2 Traits; +typedef CGAL::Hyperbolic_fundamental_domain_2 Domain; + +typedef typename Traits::FT FT; +typedef typename Traits::Hyperbolic_point_2 Point; +typedef typename Traits::Complex Complex; + + +int main() { + 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 (int k=0; k<8; k++){ + pairings.push_back((k+4)%8); + } + + Domain domain = Domain(vertices, pairings); + assert( domain.size()==8 ); + for (int k=0; k<8; k++){ + assert( domain.vertex(k)==vertices[k] ); + assert( domain.paired_side(k)==(k+4)%8 ); + assert( domain.side_pairing(k).evaluate(domain.vertex((k+4)%8))==domain.vertex((k+1)%8) ); + assert( domain.side_pairing(k).evaluate(domain.vertex((k+5)%8))==domain.vertex(k) ); + } + + assert( domain.is_valid() ); + + Domain domain_prime = Domain(vertices, pairings); + assert( domain_prime.size()==8 ); + for (int k=0; k<8; k++){ + assert( domain_prime.vertex(k)==vertices[k]); + assert( domain_prime.paired_side(k)==(k+4)%8 ); + + assert( domain_prime.side_pairing(k).evaluate(domain_prime.vertex((k+4)%8))==domain_prime.vertex((k+1)%8) ); + assert( domain_prime.side_pairing(k).evaluate(domain_prime.vertex((k+5)%8))==domain_prime.vertex(k) ); + } + + Domain domain_ter = Domain(); + std::stringstream buffer; + buffer << domain; + buffer >> domain_ter; + assert( domain_ter.size()==8 ); + for (int k=0; k<8; k++){ + assert( domain_ter.vertex(k)==vertices[k]); + assert( domain_ter.paired_side(k)==(k+4)%8 ); + } + + std::cout << "printing a domain for test purposes : " << std::endl << domain << std::endl; + + return 0; +} diff --git a/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_factory.cpp b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_factory.cpp new file mode 100644 index 00000000000..5101c49926d --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_factory.cpp @@ -0,0 +1,50 @@ +#include +#include + +#include +#include +#include + +#include + +typedef CGAL::Cartesian Kernel; +typedef CGAL::Hyperbolic_Delaunay_triangulation_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 typename Traits::FT FT; +typedef typename Traits::Hyperbolic_point_2 Point; +typedef typename Traits::Complex Complex; + + +int main() { + Factory factory; + Domain domain = factory.make_hyperbolic_fundamental_domain_g2(3459); + + std::vector vertices; + Point z0 = Point(FT("2057/2500"),FT("0")); + Point z1 = Point(FT("6183/10000"),FT("2369/5000")); + Point z2 = Point(FT("93/625"),FT("9299/10000")); + Point z3 = Point(FT("-129263137397146717229370666475391966694612741374/530219238243800202784978257516468117328515435625"),FT("443541103604461956104066082668282544568945930056/530219238243800202784978257516468117328515435625")); + Point z4 = Point(FT("-2057/2500"),FT("0")); + Point z5 = Point(FT("-6183/10000"),FT("-2369/5000")); + Point z6 = Point(FT("-93/625"),FT("-9299/10000")); + Point z7 = Point(FT("129263137397146717229370666475391966694612741374/530219238243800202784978257516468117328515435625"),FT("-443541103604461956104066082668282544568945930056/530219238243800202784978257516468117328515435625")); + 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); + + assert( domain.size()==8 ); + for (int k=0; k<8; k++){ + assert( domain.vertex(k)==vertices[k]); + assert( domain.paired_side(k)==(k+4)%8 ); + } + + return 0; +} diff --git a/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_isometry.cpp b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_isometry.cpp new file mode 100644 index 00000000000..5afcd227910 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_isometry.cpp @@ -0,0 +1,84 @@ +#include +#include + +#include +#include +#include + +#include + +typedef CGAL::Cartesian Kernel; +typedef CGAL::Hyperbolic_Delaunay_triangulation_traits_2 ParentTraits; +typedef CGAL::Hyperbolic_surface_traits_2 Traits; +typedef CGAL::Hyperbolic_isometry_2 Isometry; + +typedef typename Traits::FT FT; +typedef typename Traits::Hyperbolic_point_2 Point; +typedef typename Traits::Complex Complex; + + +int main() { + Isometry identity_1 = Isometry (); + assert( identity_1.get_coefficient(0)==Complex(FT(1)) ); + assert( identity_1.get_coefficient(1)==Complex(FT(0)) ); + assert( identity_1.get_coefficient(2)==Complex(FT(0)) ); + assert( identity_1.get_coefficient(3)==Complex(FT(1)) ); + + Isometry identity_2; + identity_2.set_to_identity(); + assert( identity_2.get_coefficient(0)==Complex(FT(1)) ); + assert( identity_2.get_coefficient(1)==Complex(FT(0)) ); + assert( identity_2.get_coefficient(2)==Complex(FT(0)) ); + assert( identity_2.get_coefficient(3)==Complex(FT(1)) ); + + Isometry f; + f.set_coefficient(0, Complex(FT(-12,17), FT(1,3))); + f.set_coefficient(1, Complex(FT(56,7), FT(21,5))); + f.set_coefficient(2, Complex(FT(56,7), FT(-21,5))); + f.set_coefficient(3, Complex(FT(-12,17), FT(-1,3))); + assert( f.get_coefficient(0)==Complex(FT(-12,17), FT(1,3)) ); + assert( f.get_coefficient(1)==Complex(FT(56,7), FT(21,5)) ); + assert( f.get_coefficient(2)==Complex(FT(56,7), FT(-21,5)) ); + assert( f.get_coefficient(3)==Complex(FT(-12,17), FT(-1,3)) ); + + Isometry g; + g.set_coefficients(Complex(FT(-12,17), FT(1,3)), Complex(FT(56,7), FT(21,5)), Complex(FT(56,7), FT(-21,5)), Complex(FT(-12,17), FT(-1,3))); + assert( g.get_coefficient(0)==Complex(FT(-12,17), FT(1,3)) ); + assert( g.get_coefficient(1)==Complex(FT(56,7), FT(21,5)) ); + assert( g.get_coefficient(2)==Complex(FT(56,7), FT(-21,5)) ); + assert( g.get_coefficient(3)==Complex(FT(-12,17), FT(-1,3)) ); + + Isometry h = f*g; + assert( h.get_coefficient(0) == Complex(FT(5333816,65025),FT(-8,17)) ); + assert( h.get_coefficient(1) == Complex(FT(-192,17),FT(-504,85)) ); + assert( h.get_coefficient(2) == Complex(FT(-192,17),FT(504,85)) ); + assert( h.get_coefficient(3) == Complex(FT(5333816,65025),FT(8,17)) ); + + Point point (FT(3,11),FT(-1,73)); + Point image_point = h.evaluate(point); + assert( image_point==Point(FT(9146011623056232,66567955527962869), FT(-12617302915955411,133135911055925738)) ); + + std::cout << "printing an isometry for test purposes : " << std::endl << h; + + Isometry tau_1 = CGAL::hyperbolic_translation(point); + Isometry tau_1_prime = CGAL::hyperbolic_translation(Point (FT(-3,11),FT(1,73)), true); + Isometry tau_1_inv = CGAL::hyperbolic_translation(point, true); + assert( tau_1.evaluate(image_point) == tau_1_prime.evaluate(image_point) ); + assert( (tau_1*tau_1_inv).evaluate(image_point) == image_point ); + + Point p (FT(2,15),FT(0)); + Point q (FT(0),FT(17,93)); + Isometry rotation = CGAL::hyperbolic_rotation(p, q); + Isometry rotation_prime = CGAL::hyperbolic_rotation(q, p, true); + Isometry rotation_inv = CGAL::hyperbolic_rotation(p, q, true); + assert( rotation.evaluate(image_point) == rotation_prime.evaluate(image_point) ); + assert( (rotation*rotation_inv).evaluate(image_point) == image_point ); + + Point p_imag = rotation.evaluate(p); + Point q_imag = rotation.evaluate(q); + Isometry pairing = CGAL::isometry_pairing_the_sides(p, q, p_imag, q_imag); + assert( pairing.evaluate(p) == p_imag ); + assert( pairing.evaluate(q) == q_imag ); + + return 0; +} diff --git a/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_lazy_exact_nt.cpp b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_lazy_exact_nt.cpp new file mode 100644 index 00000000000..df8af42b506 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_lazy_exact_nt.cpp @@ -0,0 +1,59 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +typedef CGAL::Cartesian> Kernel; +typedef CGAL::Hyperbolic_Delaunay_triangulation_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::Triangulation_on_hyperbolic_surface_2 Triangulation; + +typedef typename Traits::Hyperbolic_point_2 Point; + +int main() { + Factory factory; + Domain domain = factory.make_hyperbolic_fundamental_domain_g2(3459); + Triangulation triangulation0 = Triangulation(domain); + + assert( triangulation0.is_valid() ); + + Triangulation triangulation (triangulation0); + assert( triangulation.has_anchor() ); + + std::stringstream buffer; + buffer << triangulation; + buffer >> triangulation; + + std::vector> input_not_centered; + std::vector> input_centered; + + input_not_centered = triangulation.lift(false); + input_centered = triangulation.lift(); + + triangulation.make_Delaunay(); + + assert( triangulation.is_Delaunay() ); + + std::vector> output_not_centered; + std::vector> output_centered; + + output_not_centered = triangulation.lift(false); + output_centered = triangulation.lift(); + + + Triangulation::Combinatorial_map_with_cross_ratios& cmap = triangulation.combinatorial_map(); + Triangulation::Anchor& anchor = triangulation.anchor(); + assert( cmap.is_dart_used(anchor.dart) ); + + std::cout << "printing triangulation for test purposes : " << std::endl << triangulation; + + return 0; +} 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 new file mode 100644 index 00000000000..e3184e4c105 --- /dev/null +++ b/Triangulation_on_hyperbolic_surface_2/test/Triangulation_on_hyperbolic_surface_2/hs_test_triangulation.cpp @@ -0,0 +1,76 @@ +#include +#include + +#include +#include +#include + +#include +#include + +typedef CGAL::Cartesian Kernel; +typedef CGAL::Hyperbolic_Delaunay_triangulation_traits_2 ParentTraits; +typedef CGAL::Hyperbolic_surface_traits_2 Traits; +typedef CGAL::Hyperbolic_fundamental_domain_2 Domain; +typedef CGAL::Triangulation_on_hyperbolic_surface_2 Triangulation; + +typedef typename Traits::FT FT; +typedef typename Traits::Hyperbolic_point_2 Point; +typedef typename Traits::Complex Complex; + +Domain build_domain(){ + std::vector vertices; + vertices.push_back( Point(FT(809,10000),FT(0)) ); + vertices.push_back( Point(FT(7359,10000),FT(1877,10000)) ); + vertices.push_back( Point(FT(-999,2500),FT(881,1000)) ); + vertices.push_back( Point(FT("-22088524601252853411192791001942853611410938513/24711029456888649611435724068315791591836010000"),FT("9482675065452890527617859332378101016513362487/24711029456888649611435724068315791591836010000")) ); + vertices.push_back( Point(FT(-809,10000),FT(0)) ); + vertices.push_back( Point(FT(-7359,10000),FT(-1877,10000)) ); + vertices.push_back( Point(FT(999,2500),FT(-881,1000)) ); + vertices.push_back( Point(FT("22088524601252853411192791001942853611410938513/24711029456888649611435724068315791591836010000"),FT("-9482675065452890527617859332378101016513362487/24711029456888649611435724068315791591836010000")) ); + + std::vector pairings; + for (int k=0; k<8; k++){ + pairings.push_back((k+4)%8); + } + + return Domain(vertices, pairings); +} + +int main() { + Domain domain = build_domain(); + Triangulation triangulation0 = Triangulation(domain); + + assert( triangulation0.is_valid() ); + + Triangulation triangulation (triangulation0); + assert( triangulation.has_anchor() ); + + std::stringstream buffer; + buffer << triangulation; + buffer >> triangulation; + + std::vector> input_not_centered; + std::vector> input_centered; + + input_not_centered = triangulation.lift(false); + input_centered = triangulation.lift(); + + triangulation.make_Delaunay(); + + assert( triangulation.is_Delaunay() ); + + std::vector> output_not_centered; + std::vector> output_centered; + + output_not_centered = triangulation.lift(false); + output_centered = triangulation.lift(); + + Triangulation::Combinatorial_map_with_cross_ratios& cmap = triangulation.combinatorial_map(); + Triangulation::Anchor& anchor = triangulation.anchor(); + assert( cmap.is_dart_used(anchor.dart) ); + + std::cout << "printing triangulation for test purposes : " << std::endl << triangulation; + + return 0; +}