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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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