From 7bef92b6d9f90cc3b827ea4f0025f7eeac690a00 Mon Sep 17 00:00:00 2001 From: Iordan Iordanov Date: Wed, 24 Feb 2016 10:44:26 +0100 Subject: [PATCH] Added new demo, changes in the folder structure, minor modifications to the code --- .../CMakeLists.txt | 38 + .../Periodic_4_Dirichlet_region_demo.cpp | 742 +++ .../icons/CGAL.qrc | 10 + .../icons/Delaunay_triangulation_2.png | Bin 0 -> 4042 bytes .../icons/Delaunay_triangulation_2.qrc | 12 + .../icons/File.qrc | 7 + .../Periodic_4_Dirichlet_region/icons/G.png | Bin 0 -> 1883 bytes .../Periodic_4_Dirichlet_region/icons/G16.png | Bin 0 -> 2492 bytes .../Periodic_4_Dirichlet_region/icons/G2.png | Bin 0 -> 2154 bytes .../Periodic_4_Dirichlet_region/icons/G4.png | Bin 0 -> 2244 bytes .../Periodic_4_Dirichlet_region/icons/G8.png | Bin 0 -> 2281 bytes .../icons/Input.qrc | 7 + .../Periodic_4_hyperbolic_triangulation_2.qrc | 13 + .../icons/Triangulation_2.qrc | 6 + .../icons/Voronoi_diagram_2.png | Bin 0 -> 3093 bytes .../Periodic_4_Dirichlet_region/icons/a.png | Bin 0 -> 1302 bytes .../icons/about_CGAL.html | 8 + .../Periodic_4_Dirichlet_region/icons/b.png | Bin 0 -> 1467 bytes .../Periodic_4_Dirichlet_region/icons/c.png | Bin 0 -> 1302 bytes .../icons/cgal_logo.xpm | 24 + .../icons/cgal_logo_ipe_2013.png | Bin 0 -> 27382 bytes .../icons/circumcenter.png | Bin 0 -> 3862 bytes .../icons/conflict_zone.png | Bin 0 -> 7715 bytes .../icons/constrained_triangulation.png | Bin 0 -> 6800 bytes .../Periodic_4_Dirichlet_region/icons/d.png | Bin 0 -> 1385 bytes .../icons/fileNew.png | Bin 0 -> 768 bytes .../icons/fileOpen.png | Bin 0 -> 1662 bytes .../icons/fileSave.png | Bin 0 -> 1205 bytes .../icons/fit-page-32.png | Bin 0 -> 1330 bytes .../icons/inputPoint.png | Bin 0 -> 1145 bytes .../icons/inputPolyline.png | Bin 0 -> 2021 bytes .../icons/license.txt | 5 + .../icons/moving_point.png | Bin 0 -> 8074 bytes .../icons/triangulation.png | Bin 0 -> 7547 bytes .../icons/zoom-best-fit.png | Bin 0 -> 3231 bytes .../CMakeLists.txt | 6 - ...odic_4_hyperbolic_triangulation_2_demo.cpp | 32 +- .../Delaunay_hyperbolic_triangulation_2.h | 21 +- .../include/CGAL/Diametric_translations.h | 3 +- .../Hyperbolic_Delaunay_triangulation_2.h | 0 .../include/CGAL/Hyperbolic_face_info_2.h | 81 + .../CGAL/Hyperbolic_random_points_in_disc_2.h | 86 + .../include/CGAL/Octagon_matrix.h | 110 +- ...c_4_Delaunay_hyperbolic_triangulation_2.h} | 171 +- ...yperbolic_Delaunay_triangulation_2.h.misha | 570 ++ .../CGAL/Periodic_4_hyperbolic_offset_2.h | 182 + .../Periodic_4_hyperbolic_triangulation_2.h | 4856 +++++++++++++++++ ...riodic_4_hyperbolic_triangulation_dummy.h} | 42 +- ...c_4_hyperbolic_triangulation_iterators_2.h | 882 +++ .../CGAL/{ => Qt}/OriginalDomainNeighbors.h | 0 .../{ => Qt}/OriginalDomainNeighborsCommon.h | 0 .../CGAL/Qt}/PointGraphicsItem.h | 0 .../include/CGAL/{ => Qt}/PointTranslation.h | 0 .../CGAL/{ => Qt}/PointTranslationWithInfo.h | 0 .../TriangulationGraphicsItemWithColorInfo.h | 128 +- .../include/CGAL/Sqrt_field.h | 518 +- .../include/CGAL/TranslationInfo.h | 2 +- .../CGAL/Triangulation_hyperbolic_traits_2.h | 54 +- .../include/CGAL/{ => unused}/GroupOfIndex2.h | 0 .../Hyperbolic_random_points_in_disc_2.h | 4 +- .../include/CGAL/{ => unused}/Translations.h | 0 .../include/CGAL/{ => unused}/temp.h | 0 62 files changed, 7859 insertions(+), 761 deletions(-) create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/CMakeLists.txt create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/Periodic_4_Dirichlet_region_demo.cpp create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/CGAL.qrc create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Delaunay_triangulation_2.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Delaunay_triangulation_2.qrc create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/File.qrc create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G16.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G2.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G4.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G8.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Input.qrc create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Periodic_4_hyperbolic_triangulation_2.qrc create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Triangulation_2.qrc create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Voronoi_diagram_2.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/a.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/about_CGAL.html create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/b.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/c.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/cgal_logo.xpm create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/cgal_logo_ipe_2013.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/circumcenter.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/conflict_zone.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/constrained_triangulation.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/d.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileNew.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileOpen.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileSave.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fit-page-32.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/inputPoint.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/inputPolyline.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/license.txt create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/moving_point.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/triangulation.png create mode 100644 Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/zoom-best-fit.png rename Periodic_4_hyperbolic_triangulation_2/{demo/Periodic_4_hyperbolic_triangulation_2/include => include/CGAL}/Delaunay_hyperbolic_triangulation_2.h (97%) create mode 100644 Periodic_4_hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_2.h create mode 100644 Periodic_4_hyperbolic_triangulation_2/include/CGAL/Hyperbolic_face_info_2.h create mode 100644 Periodic_4_hyperbolic_triangulation_2/include/CGAL/Hyperbolic_random_points_in_disc_2.h rename Periodic_4_hyperbolic_triangulation_2/{demo/Periodic_4_hyperbolic_triangulation_2/include/Periodic_2_Delaunay_hyperbolic_triangulation_2.h => include/CGAL/Periodic_4_Delaunay_hyperbolic_triangulation_2.h} (57%) create mode 100644 Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_Delaunay_triangulation_2.h.misha create mode 100644 Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_offset_2.h create mode 100644 Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_2.h rename Periodic_4_hyperbolic_triangulation_2/{demo/Periodic_4_hyperbolic_triangulation_2/include/Periodic_2_hyperbolic_triangulation_dummy.h => include/CGAL/Periodic_4_hyperbolic_triangulation_dummy.h} (89%) create mode 100644 Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_iterators_2.h rename Periodic_4_hyperbolic_triangulation_2/include/CGAL/{ => Qt}/OriginalDomainNeighbors.h (100%) rename Periodic_4_hyperbolic_triangulation_2/include/CGAL/{ => Qt}/OriginalDomainNeighborsCommon.h (100%) rename Periodic_4_hyperbolic_triangulation_2/{demo/Periodic_4_hyperbolic_triangulation_2/include => include/CGAL/Qt}/PointGraphicsItem.h (100%) rename Periodic_4_hyperbolic_triangulation_2/include/CGAL/{ => Qt}/PointTranslation.h (100%) rename Periodic_4_hyperbolic_triangulation_2/include/CGAL/{ => Qt}/PointTranslationWithInfo.h (100%) rename Periodic_4_hyperbolic_triangulation_2/include/CGAL/{ => unused}/GroupOfIndex2.h (100%) rename Periodic_4_hyperbolic_triangulation_2/{demo/Periodic_4_hyperbolic_triangulation_2/include => include/CGAL/unused}/Hyperbolic_random_points_in_disc_2.h (95%) rename Periodic_4_hyperbolic_triangulation_2/include/CGAL/{ => unused}/Translations.h (100%) rename Periodic_4_hyperbolic_triangulation_2/include/CGAL/{ => unused}/temp.h (100%) diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/CMakeLists.txt b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/CMakeLists.txt new file mode 100644 index 00000000000..31816a3b677 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/CMakeLists.txt @@ -0,0 +1,38 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + +project (Periodic_4_hyperbolic_triangulation_2_demo) + +# Find includes in corresponding build directories +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +# Instruct CMake to run moc automatically when needed. +set(CMAKE_AUTOMOC ON) + +cmake_minimum_required(VERSION 2.8.11) +if(POLICY CMP0043) + cmake_policy(SET CMP0043 OLD) +endif() + +find_package(CGAL COMPONENTS Qt5) +include(${CGAL_USE_FILE}) + +find_package(Qt5 QUIET COMPONENTS Widgets) + +include_directories (BEFORE ../../include include) + +# ui files, created with Qt Designer +qt5_wrap_ui( uis Periodic_4_hyperbolic_triangulation_2.ui ) + +# qrc files (resources files, that contain icons, at least) +qt5_add_resources ( RESOURCE_FILES resources/Periodic_4_hyperbolic_triangulation_2.qrc ) + + +# cpp files + +add_executable ( Periodic_4_Dirichlet_region_demo Periodic_4_Dirichlet_region_demo.cpp ) +qt5_use_modules( Periodic_4_Dirichlet_region_demo Widgets) +add_to_cached_list( CGAL_EXECUTABLE_TARGETS Periodic_4_Dirichlet_region_demo ) +target_link_libraries( Periodic_4_Dirichlet_region_demo ${CGAL_LIBRARIES} ${QT_LIBRARIES} ${CGAL_QT_LIBRARIES} ) + + diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/Periodic_4_Dirichlet_region_demo.cpp b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/Periodic_4_Dirichlet_region_demo.cpp new file mode 100644 index 00000000000..2337bdb8860 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/Periodic_4_Dirichlet_region_demo.cpp @@ -0,0 +1,742 @@ +#include + +// CGAL headers +#include +#include +#include +#include + +/* #include */ + +#include + +// to be deleted +#include +// + +#include + +// Qt headers +#include +#include +#include +#include +#include +#include + +#include + +// GraphicsView items and event filters (input classes) +#include "CGAL/Qt/TriangulationCircumcircle.h" + +#include "CGAL/Qt/TriangulationMovingPoint.h" +#include "CGAL/Qt/TriangulationConflictZone.h" +#include "CGAL/Qt/TriangulationRemoveVertex.h" +#include "CGAL/Qt/TriangulationPointInputAndConflictZone.h" +//#include +#include + +// store color +#include +// visualise color +#include + +// unique words +//#include +#include +#include + +#include + +// dummy points +//#include + +// for filtering +#include + +// for viewportsBbox +#include + +// the two base classes +#include "ui_Delaunay_triangulation_2.h" +#include + +#define OPTION_INSERT_DUMMY_POINTS 0 + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel InR; +typedef CGAL::Exact_predicates_exact_constructions_kernel R; +typedef CGAL::Triangulation_hyperbolic_traits_2 K; + +typedef K::Point_2 Point; +// keep color +typedef TranslationInfo Vb_info; + +typedef CGAL::Triangulation_vertex_base_with_info_2< Vb_info, K > + Vb; + +typedef CGAL::Triangulation_face_base_with_info_2 + Fb; + +typedef CGAL::Delaunay_hyperbolic_triangulation_2< K, CGAL::Triangulation_data_structure_2 > +/* typedef CGAL::Periodic_4_Delaunay_hyperbolic_triangulation_2< K, CGAL::Triangulation_data_structure_2 > */ + Delaunay; + +typedef Delaunay::Vertex_handle Vertex_handle; + +//typedef CGAL::Delaunay_hyperbolic_triangulation_2 Delaunay; + +struct PointsComparator { + static double eps; + + bool operator() (const Point& l, const Point& r) const + { + if(l.x() < r.x() - eps) { + return true; + } + if(l.x() < r.x() + eps) { + if(l.y() < r.y() - eps) { + return true; + } + } + return false; + } +}; + +double PointsComparator::eps = 0.0001; + +void apply_unique_words(std::vector& points, Point input = Point(0, 0), double threshold = 20 , int word_length = 6, double d = .999) +{ + static vector unique_words; + static bool generated = false; + if(generated == false) { + generate_unique_words(unique_words, threshold, word_length); + generated = true; + } + + //points.resize(unique_words.size()); + pair res; + for(size_t i = 0; i < unique_words.size(); i++) { + pair res; + res = unique_words[i].apply(to_double(input.x()), to_double(input.y())); + + double dist = res.first*res.first + res.second*res.second; + if(dist < d) { + points.push_back( Point(res.first, res.second) ); + } + } +} + +void apply_unique_words_G(std::vector& points, Point input = Point(0, 0), double threshold = 6/*13.5*/, int word_length = 6/*20*/) +{ + static vector unique_words; + static bool generated = false; + if(generated == false) { + generate_unique_words(unique_words, threshold, word_length); + generated = true; + + // to generate all words + /* + ofstream fwords("m_w"); + fwords << "local words;\nPrint(\"words!\\n\");\nwords := [\n"; + for(size_t i = 0; i < unique_words.size() - 1; i++) { + fwords << unique_words[i].label << "," < indices; + while(findices >> index) { + indices.push_back(index); + } + cout << "indices size " << indices.size() << endl; + + pair res; + for(size_t i = 0; i < indices.size(); i++) { + pair res; + if(indices[i] < unique_words.size() /*&& unique_words[indices[i]].length() < 13.*/) { + res = unique_words[indices[i]].apply(to_double(input.x()), to_double(input.y())); + points.push_back(Point(res.first, res.second)); + } + } + cout << "nb of points to insert " << points.size() << endl; +} + + +class MainWindow : + public CGAL::Qt::DemosMainWindow, + public Ui::Delaunay_triangulation_2 +{ + Q_OBJECT + +private: + + int cidx; + std::vector ccol; + + Delaunay dt; + QGraphicsEllipseItem * disk; + QGraphicsScene scene; + + CGAL::Qt::TriangulationGraphicsItem * dgi; + CGAL::Qt::VoronoiGraphicsItem * vgi; + + // for drawing Voronoi diagram of the orbit of the origin + CGAL::Qt::VoronoiGraphicsItem * origin_vgi; + + CGAL::Qt::TriangulationMovingPoint * mp; + CGAL::Qt::TriangulationConflictZone * cz; + CGAL::Qt::TriangulationRemoveVertex * trv; + CGAL::Qt::TriangulationPointInputAndConflictZone * pi; + CGAL::Qt::TriangulationCircumcircle * tcc; +public: + MainWindow(); + +public slots: + + void processInput(CGAL::Object o); + + void on_actionMovingPoint_toggled(bool checked); + + void on_actionShowConflictZone_toggled(bool checked); + + void on_actionCircumcenter_toggled(bool checked); + + void on_actionShowDelaunay_toggled(bool checked); + + void on_actionShowVoronoi_toggled(bool checked); + + void on_actionInsertPoint_toggled(bool checked); + + void on_actionInsertRandomPoints_triggered(); + + void on_actionLoadPoints_triggered(); + + void on_actionSavePoints_triggered(); + + void on_actionClear_triggered(); + + void on_actionRecenter_triggered(); + + virtual void open(QString fileName); + +signals: + void changed(); +}; + + +MainWindow::MainWindow() + : DemosMainWindow(), dt(K(1)) +{ + + cidx = 0; + for (int i = 0; i < 10; i++) + ccol.push_back(i); + + setupUi(this); + + this->graphicsView->setAcceptDrops(false); + + // Add Poincaré disk + qreal origin_x = 0, origin_y = 0, radius = 1, diameter = 2*radius; + qreal left_top_corner_x = origin_x - radius; + qreal left_top_corner_y = origin_y - radius; + qreal width = diameter, height = diameter; + + // set background + qreal eps = 0.01; + QGraphicsRectItem* rect = new QGraphicsRectItem(left_top_corner_x - eps, left_top_corner_y - eps, width + 2*eps, height + 2*eps); + rect->setPen(Qt::NoPen); + rect->setBrush(Qt::white); + scene.addItem(rect); + + // set disk + disk = new QGraphicsEllipseItem(left_top_corner_x, left_top_corner_y, width, height); + QPen pen; // creates a default pen + pen.setWidth(0); + //pen.setBrush(Qt::black); + pen.setBrush(QColor(200, 200, 0)); + disk->setPen(pen); + + scene.addItem(disk); + + // another input point, instead of the origin + + double phi = CGAL_PI / 8.; + double psi = CGAL_PI / 3.; + double rho = std::sqrt(cos(psi)*cos(psi) - sin(phi)*sin(phi)); + + Point origin = Point(0, 0); + const Point a(cos(phi)*cos(phi + psi)/rho, sin(phi)*cos(phi + psi)/rho); + + + // dt to form the octagon tessellation + vector origin_orbit; + apply_unique_words(origin_orbit, origin); + origin_orbit.push_back(Point(0, 0)); + // for(long i = 0; i < origin_orbit.size(); i++) { + // cout << origin_orbit[i] << endl; + // } + cout << "nb of points on the orbit of the origin: " << origin_orbit.size() << endl; + + Delaunay* dtO = new Delaunay(K(1)); + dtO->insert(origin_orbit.begin(), origin_orbit.end()); + + origin_vgi = new CGAL::Qt::VoronoiGraphicsItem(dtO); + origin_vgi->setVisible(true); + + QObject::connect(this, SIGNAL(changed()), + origin_vgi, SLOT(modelChanged())); + + QColor br(149, 179, 179); + origin_vgi->setEdgesPen(QPen(br, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + scene.addItem(origin_vgi); + + + // Add a GraphicItem for the Delaunay triangulation + dgi = new CGAL::Qt::TriangulationGraphicsItem(&dt); + + QObject::connect(this, SIGNAL(changed()), + dgi, SLOT(modelChanged())); + + dgi->setVerticesPen(QPen(Qt::red, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + dgi->setEdgesPen(QPen(QColor(200, 200, 0), 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + scene.addItem(dgi); + + // Add a GraphicItem for the Voronoi diagram + vgi = new CGAL::Qt::VoronoiGraphicsItem(&dt); + + QObject::connect(this, SIGNAL(changed()), + vgi, SLOT(modelChanged())); + + QColor brown(139, 69, 19); + vgi->setEdgesPen(QPen(brown, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + scene.addItem(vgi); + vgi->hide(); + + // Setup input handlers. They get events before the scene gets them + // and the input they generate is passed to the triangulation with + // the signal/slot mechanism + pi = new CGAL::Qt::TriangulationPointInputAndConflictZone(&scene, &dt, this ); + + QObject::connect(pi, SIGNAL(generate(CGAL::Object)), + this, SLOT(processInput(CGAL::Object))); + + mp = new CGAL::Qt::TriangulationMovingPoint(&dt, this); + // TriangulationMovingPoint emits a modelChanged() signal each + // time the moving point moves. + // The following connection is for the purpose of emitting changed(). + QObject::connect(mp, SIGNAL(modelChanged()), + this, SIGNAL(changed())); + + trv = new CGAL::Qt::TriangulationRemoveVertex(&dt, this); + QObject::connect(trv, SIGNAL(modelChanged()), + this, SIGNAL(changed())); + + tcc = new CGAL::Qt::TriangulationCircumcircle(&scene, &dt, this); + tcc->setPen(QPen(Qt::red, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + + cz = new CGAL::Qt::TriangulationConflictZone(&scene, &dt, this); + + // + // Manual handling of actions + // + + QObject::connect(this->actionQuit, SIGNAL(triggered()), + this, SLOT(close())); + + // We put mutually exclusive actions in an QActionGroup + QActionGroup* ag = new QActionGroup(this); + ag->addAction(this->actionInsertPoint); + ag->addAction(this->actionMovingPoint); + ag->addAction(this->actionCircumcenter); + ag->addAction(this->actionShowConflictZone); + + // Check two actions + this->actionInsertPoint->setChecked(true); + this->actionShowDelaunay->setChecked(true); + + // // + // // Setup the scene and the view + // // + scene.setItemIndexMethod(QGraphicsScene::NoIndex); + scene.setSceneRect(left_top_corner_x, left_top_corner_y, width, height); + this->graphicsView->setScene(&scene); + this->graphicsView->setMouseTracking(true); + + // // we want to adjust the coordinates of QGraphicsView to the coordinates of QGraphicsScene + // // the following line must do this: + //this->graphicsView->fitInView( scene.sceneRect(), Qt::KeepAspectRatio); + // // It does not do this sufficiently well. + // // Current solution: + + // QRect viewerRect = graphicsView->mapFromScene(scene.sceneRect()).boundingRect(); + // std::cout << "resolution before " << viewerRect.width() << " " << viewerRect.height() << std::endl; + + // // shear 230 230 + //this->graphicsView->shear(407, 407); + //this->graphicsView->shear(10, 10); + + // viewerRect = graphicsView->mapFromSthis->graphicsView->rotate(90);cene(scene.sceneRect()).boundingRect(); + // std::cout << "resolution after " << viewerRect.width() << " " << viewerRect.height() << std::endl; + + // // Turn the vertical axis upside down + //this->graphicsView->matrix().scale(1, -1); + + //this->graphicsView->scale(10, 10); + //this->graphicsView->centerOn(0.0, 0.0); + //this->graphicsView->translate(1.0, -20.0); + this->graphicsView->shear(230, 230); + this->graphicsView->rotate(90); + + // // The navigation adds zooming and translation functionality to the + // // QGraphicsView + this->addNavigation(this->graphicsView); + + this->setupStatusBar(); + this->setupOptionsMenu(); + this->addAboutDemo(":/cgal/help/about_Delaunay_triangulation_2.html"); + this->addAboutCGAL(); + + this->addRecentFiles(this->menuFile, this->actionQuit); + connect(this, SIGNAL(openRecentFile(QString)), + this, SLOT(open(QString))); + + +#if OPTION_INSERT_DUMMY_POINTS == 1 + + std::vector pts; + cout << "Inserting dummy points now! " << endl; + dt.insert_dummy_points(pts); + for (int i = 0; i < pts.size(); i++) { + processInput(make_object(pts[i])); + } + cout << "Dummy points inserted! " << endl; + emit(changed()); + +#endif + +} + + +void +MainWindow::processInput(CGAL::Object o) +{ + + typedef CGAL::Exact_predicates_inexact_constructions_kernel GT; + typedef GT::Point_2 Point_2; + Point_2 pp; + if (CGAL::assign(pp, o)) { + Point tmp(pp.x(), pp.y()); + o = make_object(tmp); + } + + Point p; + if(CGAL::assign(p, o)){ + QPointF qp(CGAL::to_double(p.x()), CGAL::to_double(p.y())); + + // note that if the point is on the boundary then the disk contains the point + if(disk->contains(qp)){ + //dt.insert(p); + + //delete + vector points; + apply_unique_words/*_G*/(points, p);; + points.push_back(p); + Vertex_handle v; + for(size_t j = 0; j < points.size(); j++) { + v = dt.insert(points[j]); + v->info().setColor(ccol[cidx]); + } + cidx = (cidx + 1) % ccol.size(); + // + } + // delete + else { + static double phi = CGAL_PI / 8.; + static double psi = CGAL_PI / 3.; + static double rho = std::sqrt(cos(psi)*cos(psi) - sin(phi)*sin(phi)); + + static Point origin = Point(0, 0); + static Point a(cos(phi)*cos(phi + psi)/rho, sin(phi)*cos(phi + psi)/rho); + static Point b((cos(psi)-sin(phi))/rho, 0.); + + static Point current_point_a = origin; + static Point current_point_b = origin; + static double dT = 0.05; + + static double dx_a = dT * CGAL::to_double(a.x()); + static double dy_a = dT * CGAL::to_double(a.y()); + current_point_a = Point(current_point_a.x() + dx_a, current_point_a.y() + dy_a); + if(current_point_a.x() > a.x()) { + current_point_a = origin; + } + + static double dx_b = dT * CGAL::to_double(b.x()); + static double dy_b = dT * CGAL::to_double(b.y()); + current_point_b = Point(current_point_b.x() + dx_b, current_point_b.y() + dy_b); + std::cout << current_point_b.x() << " : " << current_point_b.y() << std::endl; + if(current_point_b.x() > b.x()) { + current_point_b = origin; + } + + vector points; + + // current_point_b <-> current_point_b + Point current_point = current_point_a; + apply_unique_words/*_G*/(points, current_point, 6, 4); + points.push_back(current_point); + dt.clear(); + dt.insert(points.begin(), points.end()); + + } + + } + emit(changed()); + + cout << "v = " << dt.number_of_vertices() << ", f = " << dt.number_of_faces() << endl; + +} + + + + + +/* + * Qt Automatic Connections + * http://doc.trolltech.com/4.4/designer-using-a-component.html#automatic-connections + * + * setupUi(this) generates connections to the slots named + * "on__" + */ +void +MainWindow::on_actionInsertPoint_toggled(bool checked) +{ + if(checked){ + scene.installEventFilter(pi); + scene.installEventFilter(trv); + } else { + scene.removeEventFilter(pi); + scene.removeEventFilter(trv); + } +} + + +void +MainWindow::on_actionMovingPoint_toggled(bool checked) +{ + + if(checked){ + scene.installEventFilter(mp); + } else { + scene.removeEventFilter(mp); + } +} + + +void +MainWindow::on_actionShowConflictZone_toggled(bool checked) +{ + + if(checked){ + scene.installEventFilter(cz); + } else { + scene.removeEventFilter(cz); + } +} + +void +MainWindow::on_actionCircumcenter_toggled(bool checked) +{ + if(checked){ + scene.installEventFilter(tcc); + tcc->show(); + } else { + scene.removeEventFilter(tcc); + tcc->hide(); + } +} + + +void +MainWindow::on_actionShowDelaunay_toggled(bool checked) +{ + dgi->setVisibleEdges(checked); +} + + +void +MainWindow::on_actionShowVoronoi_toggled(bool checked) +{ + vgi->setVisible(checked); +} + + +void +MainWindow::on_actionClear_triggered() +{ + dt.clear(); + emit(changed()); +} + + +void +MainWindow::on_actionInsertRandomPoints_triggered() +{ + QRectF rect = CGAL::Qt::viewportsBbox(&scene); + CGAL::Qt::Converter convert; + //Circle_2 isor = convert(rect); + //CGAL::Random_points_in_disc_2 pg(1.0); + bool ok = false; + const int number_of_points = + QInputDialog::getInt(this, + tr("Number of random points"), + tr("Enter number of random points"), + 100, + 0, + std::numeric_limits::max(), + 1, + &ok); + + if(!ok) { + return; + } + + // wait cursor + QApplication::setOverrideCursor(Qt::WaitCursor); + //std::vector points; + //points.reserve(number_of_points); + + typedef CGAL::Exact_predicates_inexact_constructions_kernel GT; + typedef GT::Point_2 Point_2; + typedef GT::FT FT; + + vector pts; + Hyperbolic_random_points_in_disc_2(pts, number_of_points); + + for(int i = 0; i < number_of_points; ++i){ + processInput(make_object(pts[i])); + //points.push_back(*pg++); + } + //dt.insert(points.begin(), points.end()); + // default cursor + QApplication::restoreOverrideCursor(); + emit(changed()); +} + + +void +MainWindow::on_actionLoadPoints_triggered() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open Points file"), + "."); + if(! fileName.isEmpty()){ + open(fileName); + } +} + + +void +MainWindow::open(QString fileName) +{ + // wait cursor + QApplication::setOverrideCursor(Qt::WaitCursor); + std::ifstream ifs(qPrintable(fileName)); + + K::Point p; + std::vector points; + while(ifs >> p) { + points.push_back(p); + } + dt.insert(points.begin(), points.end()); + + // default cursor + QApplication::restoreOverrideCursor(); + this->addToRecentFiles(fileName); + actionRecenter->trigger(); + emit(changed()); + +} + +void +MainWindow::on_actionSavePoints_triggered() +{ +/* // dump points + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save points"), + "."); + if(! fileName.isEmpty()){ + std::ofstream ofs(qPrintable(fileName)); + for(Delaunay::Finite_vertices_iterator + vit = dt.finite_vertices_begin(), + end = dt.finite_vertices_end(); + vit!= end; ++vit) + { + ofs << vit->point() << std::endl; + } + } +*/ + + // take a snapshot + std::cout << "snapshot..."; + + const QRect viewerRect = graphicsView->mapFromScene(scene.sceneRect()).boundingRect(); + const QRect imageRect = QRect(QPoint(0, 0), viewerRect.size()); + + QImage snapshot(imageRect.size(), QImage::Format_ARGB32);//QImage::Format_ARGB32_Premultiplied + + QPainter painter(&snapshot); + painter.setRenderHint(QPainter::Antialiasing); + //painter.setRenderHint(QPainter::SmoothPixmapTransform); + + graphicsView->render(&painter, imageRect, viewerRect); + bool saved = snapshot.save("mysnap.png", "PNG", 100); + assert(saved == true); + + std::cout << "done" << std::endl; +} + + +void +MainWindow::on_actionRecenter_triggered() +{ + this->graphicsView->setSceneRect(dgi->boundingRect()); + this->graphicsView->fitInView(dgi->boundingRect(), Qt::KeepAspectRatio); +} + + +#include "Periodic_4_Dirichlet_region_demo.moc" + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + app.setOrganizationDomain("geometryfactory.com"); + app.setOrganizationName("GeometryFactory"); + app.setApplicationName("Delaunay_triangulation_2 demo"); + + // Import resources from libCGALQt4. + // See http://doc.trolltech.com/4.4/qdir.html#Q_INIT_RESOURCE + Q_INIT_RESOURCE(File); + Q_INIT_RESOURCE(Triangulation_2); + Q_INIT_RESOURCE(Input); + Q_INIT_RESOURCE(CGAL); + + MainWindow mainWindow; + mainWindow.show(); + + QStringList args = app.arguments(); + args.removeAt(0); + Q_FOREACH(QString filename, args) { + mainWindow.open(filename); + } + + return app.exec(); +} diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/CGAL.qrc b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/CGAL.qrc new file mode 100644 index 00000000000..ef08023c288 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/CGAL.qrc @@ -0,0 +1,10 @@ + + + about_CGAL.html + + + cgal_logo_ipe_2013.png + cgal_logo_ipe_2013.png + cgal_logo.xpm + + diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Delaunay_triangulation_2.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Delaunay_triangulation_2.png new file mode 100644 index 0000000000000000000000000000000000000000..36b51cf599eb8b49e801e4d6fbd2b2134e78d276 GIT binary patch literal 4042 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 + + conflict_zone.png + moving_point.png + triangulation.png + circumcenter.png + + + about_CGAL.html + about_Delaunay_triangulation_2.html + + diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/File.qrc b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/File.qrc new file mode 100644 index 00000000000..61d8ef4f390 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/File.qrc @@ -0,0 +1,7 @@ + + + fileNew.png + fileOpen.png + fileSave.png + + diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G.png new file mode 100644 index 0000000000000000000000000000000000000000..719525886db128c18b86d24eaaab352109128f63 GIT binary patch literal 1883 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 literal 0 HcmV?d00001 diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G2.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G2.png new file mode 100644 index 0000000000000000000000000000000000000000..76b3163d90107a32e1dfc68628cae3b744bb0d53 GIT binary patch literal 2154 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 D5Hv&W literal 0 HcmV?d00001 diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Input.qrc b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Input.qrc new file mode 100644 index 00000000000..8a49bd278b3 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Input.qrc @@ -0,0 +1,7 @@ + + + inputPoint.png + fit-page-32.png + inputPolyline.png + + diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Periodic_4_hyperbolic_triangulation_2.qrc b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Periodic_4_hyperbolic_triangulation_2.qrc new file mode 100644 index 00000000000..ccd4a3e3bb7 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Periodic_4_hyperbolic_triangulation_2.qrc @@ -0,0 +1,13 @@ + + + G2.png + G4.png + G8.png + G16.png + G.png + a.png + b.png + c.png + d.png + + diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Triangulation_2.qrc b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Triangulation_2.qrc new file mode 100644 index 00000000000..0daea7f0665 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Triangulation_2.qrc @@ -0,0 +1,6 @@ + + + Delaunay_triangulation_2.png + Voronoi_diagram_2.png + + diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Voronoi_diagram_2.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Voronoi_diagram_2.png new file mode 100644 index 0000000000000000000000000000000000000000..62437e6bfc9600f5cb7d68d911ac76502edb2221 GIT binary patch literal 3093 zcmXZe2{=^U8vyV-Mhud%j_lL&eIz7FVZtR+NJzGru_TdQjD0WZ`=}`Uk`}U;>@n1* zvZSmfq%>p85@X-~_gw$qGxy$S?sM-sbIzRiJ#U<`ksddv2qy$V-1=v9OpvP?a+u=T zkn@GD4OQgAW`9mkXB)*~u{?;};qW|T=>tJ~-hu;@EW1Y(+`Qqb<&0d>_aT1k)i4O+ z%F)-+G7A`(zHEKwq835I!*aN*%%rEQf<~yLPBEhP3A*qKaGIpuzRG(+iftf@5NM1S z9P2HHUS}k#cjBry1?j&7C_BaUfa~d znPG!bU;O+56_3I`$-_F5%vD_zt!>_@3(pBn< zmBMflleo_WI+kcGPJBc?h1a_GFTROS636p=zfRd(b~s0sg>;~_VSFAqs(BjNrD+9- z&^FhXXTLY{%ps?+?X6Ub^)17C^3VxcfGY;_M0@dI5iV30VB~7w+#{~aO7;LcTm3x& z2*(9D!1T?G$M!$87NZB7OhNz>QSwyq%G?hu(FgT={VQMz2L=HgE?0q(&7{Xs`24I- zJ#Uq=56Ybi+uB%NaQ34-w+{ufHec6h;>^wmpztrQf2%}3yhl$0`tK7YH9|L5h#}Mp zm%pQrPp56WcRw{uKYo4Ruel#@Zt_Sn{@;3{8n=Qvkdc@I2*YCHKq~pqT5}8+LEc8{ z*Ur={<^7N!&LnG7T>y@pdO%D{84w&9ejT(tGlZp$G+WTy#19kw{Q%4$dbi75!jB@Jp z2Fd}&@OXlPZGFJq#9rVc9J;x-IMuHJ8)d5cP4>vZ@|SCUC%O)XPXI1Ni>Rh=F;i_F zDCpP;vSHDo(dFwX$W@LIQwe%oUw-MmG&5A^KWiKQ8*qcHQA?zM)-a!5&WDCRZ5ibL z^swL^%NZl!3jDS~+SaZicy*rM=1O2)?1A(WBuIfwY5w6XQqa=xuh=81Kx^yj%Ae79 z36dBX)ng~dEb^5Pn_fy)^HCueyA|c%KqHEGvP5Yt?p%hDIx{uE;7%iJR z`79OqS<0ol#GTjE_}vAe&SyT`SbN0sE?Q!y!QsWF!)W-u^Zk(C#ZMeAuOCW}*Vn#iEa4e=N(ct;S3%3YEi{Uw;I%__3} zoj?NBwqiLfNGaEQCpfvou)o+E%F*aocKb8%K+d|-?JJC%cID+m_mYYmJhv0%4+1fX zNWwufUgAM{hgg!lecjHiuE^QHc~D*r2=|-tz9<7|mGilIBGFoQ2zO#V%mDv&b9zFR9G`dG9W!`>MVxSAKap}%A z+(7?#`S6DdAXvM6XU_2>sZd@wmq7;#fio9h7^st_CNt5xhN{+r?UwO}J+kwzB zH>}eBh;HLH>vy`X_9kE&z3HvVvX^?MACIO(C!VyeQ$^xyL}}?>Gd9X?6O+A#NJQ_V zQABEfQ^CG5*7^0PdIfvBcW}fONOH4wtG|E#H^^G0^qHKwQ};8FjJr&diu6U|PM zwa?!At$;9CUn*wOWix9;bB^iq#41TiCn4dAWHxiv&Y0B#cT|y>!Av#sB(kV_oz441 zk)ag~4g(*bjvH%M>!&m{;f6%?LQX0j9qQ*F0eRz8NY|!+2WZ!~C6$<=Z7!JfwD*Cq zBMB)Anxfbt-^t`njS`V3riqNIs(Lddt7%)#L{pe+~9B&nO%t1v_0snhmj(;drwH zLJ~i+l~o1uOQ73e2cHjBL&emoTq8dsXZ4Pd&@q`9@u%T&ACUg2^S?MGYRS4mEp5B+ z^XGRNz0OIGE1%jKnpMV-%-(=H&k)O*O|4goS0YEdZA!6|E%x^{riHsZ#;+N{d&Ew7 zj?ggh`0hJ@)P+ALcT3%Jx;HAZdhCtO+PvbKqUS(!v^c{)YJ-xnwwVO9D@uhcGR%Y1TW zO1b8{AFgISD^0VrxT?&U)HpmSwU!eI&oqn$-bCsYp)W@XZDP?36Yzm6wblEJKc!BR-sN82lA zQ26HYox1=pJZ^R1GrO`7Qu;;iRAiYP_vIJy%}HEvj+N9}RxpwE`L0K^9|+*9y0jfG z;u^%*#lh1`*q5%4-3b9nc>KYD+XXRF|II4DDR%o5eZ3LS`;KGVxbf(1sOADOELP}Q R9a1_&`lpR_N?>y2{{SxM_d@^x literal 0 HcmV?d00001 diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/a.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/a.png new file mode 100644 index 0000000000000000000000000000000000000000..40dab5cf24414505ddf49564240c9d7b9a69b621 GIT binary patch literal 1302 zcmV+x1?l>UP)WFU8GbZ8()Nlj2>E@cM*00eqTL_t(|+U?y-h#W;6 z$MJ90>?S6A(AABik_RFR*{rWaTv$X!jmjQE)I{S!f)WG|hJ@h32O)=$V=g{WK?DU4 z5{#mv7#58Og6z}{`F@~pJzeboH$C0e)m00U zBuSDaNs=TH~e%mc=NuYmo) z>%cx>+^<7k+)Ty>lfXgjqvGf4<1BaRjwtD*m zSZ!JJcLuNl_#vZUtGB;_Yb|kpH-;m?XDtY}di&l|x8ESJw4@b1HVn1l*N#`+W)bb1=T776N}JIFk-| z2A9{aIz^rUZZY8Unh(4^O@V)*HG}UR6L3*px|QnlF z+pS{)?&`pB&-SV~d$0AIfMecd%`V-*eViHxe%^p*hb~|p@O2F9P*r!!fJ^R1;Nuw5 zZ@{DRC)$2+$qfK+#&E`gr-1W(&{2N}PM>+&sNxeq$ZuZQrO&+)43?5zp=!3JD# zHvwP7ApQY%5?*}AfXi($u)8XRFM%sk9>ahO+MnGDoTv)m1(MBfFyMk4=Jd&C6NCxd zjWXbZSit1*;(vklO&-^P3t)M?zSa)@ugT!p2As3oYp%7G?eUC`Z@@WvFrKNk#r~G& zCY~8^0X#HAvA1N{jsfSO-mJd?11_%t;AEX*_vR3Ax6w3j4)8&OVlT`gU|;Xaz^a7B zzAU5mdQt?uwCu$#!b^8|C*1FbjM}>-#lDvsaPyKbIJS{&USr*uV&AL$fo)!rxk;66 zLz8W-pQevJ)7q6uzf@-duNdcKf2An+@1!3Zto%|v9K(GFcq2ud>k_u{2w@mgH4c+* z?W!@t`p-%4(1(Ec<7bZ%<|IFn@=G;Rr=1bPAjmf3oNOPBEi?EUVFkOzghjr4V|at{ zp~)`b)2jW)32%V_Y;T~w-GtX}`(pq2T;MuRUx9DHI49dlYZn!*Y@4duT-$=suY~M6)RR=Y)UEQO}Mh+c^PTZ*!nP)W=YaFeP|PCV7%U?UM63i>#C~UG*`*_dX)5~(Yk7 + +

+

Computational Geometry Algorithms Library

+

CGAL provides efficient and reliable geometric algorithms in the form of a C++ library.

+

For more information visit www.cgal.org

+ + diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/b.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/b.png new file mode 100644 index 0000000000000000000000000000000000000000..47e246a4a2c4efcee932532a9314c087bfc5d076 GIT binary patch literal 1467 zcmY*ZdpOez82$~LhFVQ?OT$SvYO-|7t=!pizjq;X8O5+7#?tuJiIlBSB*GEp+L#uV zw&jvsE0^ZJbmEcQ9Od$K=*)SZ^E~G~-}}Aq_r2fu_j}#d*?y~>nj8QCTZsf4cZt$A zdkaj$#=(a_NCXz>U~dEb+^oXJN0|}_P9>a-1^{`*&4vKEc`6c9HiqbAD=U(MBJ@?4 zUVST)Si8@8o`|uIiijXb#zMN!uV~KVgjE}0Ar;Af+uZjWX__RRDIE8pc((Rmt?G(`x7d*#orFUp z&`SkYVn*0&1DJk7vNdvKLt3>*8go?UXGMrS3(AkR7liitewz4YwJ!JV`Z26_{a%hQ zfqjbvS3*`Q+$F*PL6L$Ia=$@`GTTZpJ??9pOpEB9T^jH`B@u5{E5g+ zl;T8|xmyfEJ2PHUWDo4#|YqLr?b&T6q#Al=MTDJtVbFc`H@lbeyqT~5?3 zYKVf%DF4d$Z>2O(?uoZ`OIQ7q;qCTfbWV0`*(@ae&jIr*H-gJTVGK-F0360EGgstO z5^YjiemuzMkdf+28ngl48L(+0uA5PTdV_>-V~wIODj%oPzBy3ooSx!&Ux{VOdTyv~ zWOi+DeWU94$8=|~sVQ{)YbH`1eayP_k>pZJ@7tXr64wih=OL2+L1doBZrt{!ORVQ~ zZ6PaOGJ2se@-jq!)nX3#Vz>)XCXq@5JDA^NccMsb;EPk5u#YFzhWj**GQ|86imp+2 zhe34J#Kee4@GY%SaV_|Su`i_BOa1;G&f9~l3N7=Iy(z=xusMFFD-~K_R;c2T)1Q8R z@u*Jzv<%PJ_2x6v=4G6kt|N|C@Hx>Sd@Swy%zi4zvsBqvFsm}`XoB~59mSR^m*7nW z!}rz4!|{uks+nF~5MyvdkSplN5B^YuR#}FH3f>W zc8?58bn`_)&5Y?5_s(v%{aG_156wwu%PT_=0d{TWJxds|dn(JKL<#kBhfs8ap~prp z9VP5b-Zi6e=q989;y=tBPVH*d&G8H9$Wc~afke;Z8N)7VaR%e}51|9Ob-#=7os{%X zSKsv1?JjQNHuaO~4L(B(d6DMNO_O@LOR=xVd>Bu!p!@-Iq2UP)Ha03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00eqTL_t(|+U?v+Xk1ks z$MJ7WY7wk+y*SLtgSZ;ybMgu64oTJ1-JuP z4)mNfTP*QN67+QZ5G}Lp#TW&C zt`f#LFxcSVT?BkoWBNV<+}C02mA29sN78J?KOVn>=UV*1xbUjfI9>rxHIC*wFD{^} zO`*3p@m%-R3Ah5hZOF~D6xdgz*mpPieDi=G5<-5_Xy$Gi@O_OUKbg~cpGpY00^Dju zjavxpu2J0WKzB~(zBw`A{c*%AqwX5NPb=|a#p;}Aj!NP&YFycEs#DZwaz6h+hJar+ zu58u}7wuFnwgF=I>9 z1AJGfm>(9@m+=e%e_Mv)p3(+=7)=98Q}|xOE_NsOjqZy<_5JD+%u& zpFwzWt(UO%(NV%(paZ~Hz~_W5lYVlnNRlK;k|arzBuSDaNotaR0HAj7`;BGNcmMzZ M07*qoM6N<$g3}ULqyPW_ literal 0 HcmV?d00001 diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/cgal_logo.xpm b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/cgal_logo.xpm new file mode 100644 index 00000000000..6a69b3d67e1 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/cgal_logo.xpm @@ -0,0 +1,24 @@ +/* XPM */ +const char * demoicon_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 3 1", +" c None", +". c #FFFF00", +"+ c #000000", +/* pixels */ +"................", +"...++++...++++..", +"..+....+.+....+.", +"..+......+......", +"..+......+..+++.", +"..+......+....+.", +"..+....+.+....+.", +"...++++...++++..", +"................", +"...++++...+.....", +"..+....+..+.....", +"..+....+..+.....", +"..++++++..+.....", +"..+....+..+.....", +"..+....+..+++++.", +"................"}; diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/cgal_logo_ipe_2013.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/cgal_logo_ipe_2013.png new file mode 100644 index 0000000000000000000000000000000000000000..15fe4edb6af57dedcd629d28440e3b076bd7b8bf GIT binary patch literal 27382 zcmXtfb9i0B_IB)~Cr)GM#I}tlX-;f4YHZuKt;RMR+l_78PQKjx{q7%I&og_^nwd3A z@4LekuY-#1z56Ake?=!{K1Q&H$C+;I9j~gQBDe`0@yy&({OIt(1lX z7#QSND@b&3ev^P9Ffd{;X)$4C*Ojv@m&{D#*2k{d)np^iPCDw04L>%tKm`m$iP{cj zOb`HtV9w$0-c}b{7=Q|Z!n`{|g#tf@K;?3$Ca5-;hoF&Kxu#pqRG)lo~ zq9bG|UyLn?{BB*1!v)KX|KDDvOp!v7p9w8AjFcA`j@(Tzcu7Y5E8tB&DV&OmNfvAs zMW1MzQoom^J0BGX_}L}#P$={D&VRZKFZ$@F0~tO8p=8mwKpqOW{Rjfopt3Zvb`3+m{({D=B~VN^WK=$@Q9A%xU zN1*)QB#5Ep64lK2vpa{yBPyq`Qr$~XXi6Y?>m_)dz&llCc%DrVDQTk>)kgOFuT2B<_W z?+=Gzlh6ImMGeq5XBjy%LeuN=?hio@u-m2P-DKJ0_QX_`j*Ide7jJb%J-Tc}_vbeI6$5IK1-GH{f9yj%A;D1s`_}w#q<)izYC*FNf@)t<-*{)DChM|1w}p(~ zA4MpXbdj`GKnp?=Z$wV9Gwh7h<~uSJJ6_G2gpcT*88czX?a4%4ruc zGSTB0IkSw2$@Q^1P?jqF9Ps)lZF@7qWTv3Y=8klKk%j&SHobyCtG1)l6bTwjX11Rp zWq7(0%{)JEfdGFPFr@oI>892#&hWURe(l`f<|j1VL}|0+cy59!B7ymv;OaRY_b*ly z%k23eyA|$r{UoXFNhy;RE)>MTEi5p0`;oRAoXPnNBq*@cy3~%HOkXerOT@Il?vhsH z${dD_ch#od(5g*mX>+Ku<+Pn3>tC+h9hhXncgVGcOg3ssS%ZX`jSz-Zme2(Y0Y2HW zhxT;gQm-dAyOpQ}7u0tKp&RRx2~CHopEqV0;dvu ze;9rAfe^_9Wxyu3%sJ4;yj}X^%4F8q!BSvt)@U}|c)Z-gT>Zi}Hws_+t|((#*9)_< z08(yt^mVxo`aFzkx~eT)%z@P)Bp`8WNVqx$+t&sGOr}@^x@D6F1WMfTZp%f%yw1|x zD$fJhv}pHdWWaB_)0R^Fm_`e`xeY1G6E86Pe8FBJaLLVbqukbyO&t;~Y)XFaMlO+H zI?jE)v2HNk-y6{0LoYv`H6)i44{CXdfUOujr);w|_;_!BcUEj{?5JENEKKS*Znc3N z{UfORPbie!2cZPI{PlYK?2}h2>S5W@$^*LcoyrVR1_?x$o`9S#S;Ws(a zACxo6^rG#DgbhmaBxm+<6{Q9dvm>3|#bx@vOwZzBIpiYN5Vj0y8K;?x)kFlP${+75 z^{^A?lnh(?nJtYGd0InwM8_{pqtu-ztp~~W0cG+aLnSDoNQ}#9YmMkB#|?ks?AGI=Ud$zEY{31i+Y-dD z?kJk#j8OAQHiTcu=`>bdo;L#QFc&UmL!zF`ET@yoT6mhGkf7p(4CITMNPLzfS1@#U zhZ^6WM|%X@3dX~Hs6C+~Eku&)lvRJ>mGtz`&zqDa)ZUtx*?<1Q;q~6~ft$qRA$-xC zOnyv9kqo1E7VPYn)s+<2>zDB>P3KR$U(3+`>D`cyyO5^|Ifa#CF-4Qg72Hv>7QbwG z{W!UkegQ9gc{0hs)}QBtMJMz%nS1u9xSk>Cfs4iA&Al^nQ#Zgu+3DeTK0?AQ){q*N z!=q#^DHwG|Mng2D>r|h7E1SLduz7( z#z<1+{WjBTCIm-+!DwP8MH)i9<)P8`O}X*j9WZ{c74n_ucL#jQsc2<2#OPy&yW;bX zojx^$X4m`zWh;*v#I=;G;>qU+pVN|S8iAc3dmuK;)n+5rLlS*A)nXUu=hJ-Li966K z0GYJ7eI)U^pI@{0uKkF&XRB^Xes}%@r)7B0LvF&@jR^KDJmBM`LF_X2s0QCjx+-d? z9u?2qX4mQClK=nAGj5-06^DIc-}8sSL)} zmDBa|{`M~TnQ%bBd!_Bg9<6Zn-x?3r=?CqmFejIHNNA|M%8?$U?+6d+tx^LzaLvMAVzvCHzqK()fx>(v%=D!pTl5FtZz#mcy1ILX)byC<~opvjENm{j==FlB`h z2kFK{4q33}oC89y%a|U6?uU*m30D>pfOd_+T>QTJS>eH%=Acj8SqV(V z+af$4lw74}^I@=14cnEoo@z5X*K@s@%uCX}Rdcl>m6)Ra$m812%c=}kh38s)>YY;1 zI)1OqDEPc~X#25)-QuC?D)w*@^tc%^Uv4mjqTU?6)MQ0Yih6X^4bPP&AAf%jKoBPO zt)9vLVTg?|9m zd_vydx+R5DU?})1U|SfN|h?xuRh+dCV5Zl?I}u;@j|WE5ndn5Bi-ftNTjmb zc;bCk)g(u^g-(~zVZIHrn*sg`2iQIwLqfs`b$ORTC4km6la)JzIv9rvi?v*lfF#&^UI97N6dk^JHZcZ*XNO!?=aiq!#{(w&!W0V?^EV& zf>Zi@HDu~=H+QJ7%q;Q#nhS4$R62|)om!?tHx)`)kD)6k+nV#;H#-cfF%FKTI6=9~ zTTCKGB7-ljy9C4~865~JP?nS{n97u?rI72k!cbcQf{T!MyEJwY*V6@>^Lk*$}>++mP#eryUi^L0OnDo!i&$O_OZMY3X&c z?jwOa{*6X?f#^xb!d2J?KCap*LEgay;T$>s!!`>YD2W-memwu-I0tNiN56_8jQX`F zH7`^d;wL$1@x~D{zYgp3J*F;MHC_~0bv$m+@dvA?c z)k=_R`DG1f=hb%GKD`A35Hc(odo<55g*Tuw>E3EOdyRxTgb=-{S~GaP7~+_|QN~M8 zv#l^~N|k-1*=xx6-Si6BjX6-z7wuQ{3;WTj>-~KEbJzXJU=10$sDdNg6~g;fi$}Gp zUr%c+d_h%L>W?eBI&M@QZF=Y8T5tohOWuwrzhAHvR2T4mz0HC)DgQE>Aab)dp!V|# z_7?>BASGHRAWT6`@2BI7qhfK6y#654A1-r?Tfxu4s6rkd^+lD-KN`7Ih`H09fONP7 zuivU>O1N;`gl6i*-L#F3NN#U-+NPNXy?QCWhuHy}pV>!xpW$Pt#*%b{x7S?N;5JQ- zcEF*MQAQwE(j7^E0&lYykOYg9BB9%Z1Td*T=wU@!^=k10y_ za=qO|W~r|kgUlcON9&I7iOTBQaqkNJ7#y~auNxewu1>vVv$V>`7$Q+6EBEW&q!kuF z*HO$QMDcl$iBO1Majtzn62{Qst*K|yk8{+o3BBgDO)l_ka=l(=#WLmN^8ko`Hnxt=P0KE~VSwyl^D=fi z#D5Q=_bwz?V?w?zZ{8@pS%tyhir3DoUGlnXQT*k&IuiO!irq@C1 zt?9p-riOZMC&|3GeC$Z(ItyUbiJiGdkCWI-B&o0TDj-?WYDmp zxlvpr6RFMCD8xUjQ_gMa#aNE@M-tdC2!llYGRZrLLz*P=I;J-*5k-1-|L?%rf%Bkf z1oOq3y(DsexrBT;ok2fe17*_4EqlA0%J=i;RpaOy@Y+umTA|}{#*2(60c$G^e&m_2 zEvWV_T$j|fOWN+dm=;=A`@|Xjb0$U#7xSXB(yV!1f(3&V7wHD2Y&NSM>hce#Ogc?& z6*IDJCUFO=s&}!x?=jq#c}xiBx-}ZMp6uClUcu&J&ZpSz>u>rkjWr09qWJck;^MbS zOe{E6UNfvjh0} zN{t~XRhh`Q0}tc&=O>ZjWv8jELWOo1hZQbrSB_VSZ9)OW#u#)acqWy9C*bPz+TG22 ziHX!b^sua4s!h8CLR;jbsb8mO+)|lat;)qA0+To5ZTa|*W}kO&{hzCJ9CKxrt&V8> zcu_uxS?a%nQS&l2Iea12p|5V@cHh9PYXP$3*q0M@Jm?pQ_dN1|EuAW-GiUwY69M#M zkIoLS+ljgN6SWp?@q=A~dki+t1lMcv56qa^OetGDtT_fPAwq*uDp18L;I23iZdE*gY(9qZXd~@K8^uzTo2; zZ5UID)B|1`vs-?!)0A?gt(MRwpncrA2(?Q<*;~z|NM|9Q*Qprc z18w&eTyF1JdS(($QV&nY>DSiWXO#XP=Aq|^3aU=ws2w)>6+^pl)E*@s#OsIX6h4#%>tSq1cY}t@W z0M;AFmdF=kd@@Tmr@WOj-OYnKuzMlv+reOS)GJsK!6MPutarvz3g+hk=--C$-MS=N zqX`E`p#e^`6?%SrEJEI!GKADd$OMkbt;uEit z5VF*1^ATSAZZqZ_TmwAbu6H=SW+@v`$&TQlo~W|UttCNgPinlIaxweHbx5ycQ!fXt zgGpYmXwOSSa1NFfAyrJ2f2fi4qD|A%w!N1(%2g9Dj3O{?YEO@@U(-0vG2+(SBM#%( zEvCQR7aAOs;KWU~*!8d6a~`e5wFf6#!t&>&DX-|lS!p!PjiVPj0p+?&x@b9s z3j|9O<1537k?U8b8V0?**zi>5-h@AA4!?ef7L0X7J8z95D1zN%5MDGW!Se)uQstw~ zO~GEkRG|)d$NT0uE}J{0lIb`Tdo;9v9 z{cq1^Uv9)xzu-|DV=;+NG*muZezOQ~ov09eEEJ~EU~DlVpVYm*myC-U z!?o}x{7|te>5}&ArWmb51gqjrfn0Y#C1Ew?kY^yCbLV_X^@jV*|6YZHbBOM31ENu& z58L%hyTvF2EZDMk&pa?kis!#d#hk~eNH+@&cml&zEu-&whd~U5%WJD;K=Z!Lt&fn6XOH6&>5qunoLOC6^ho2DuBt2 z0`7WHhHHN&vk|9SGn=Ep5_DU@JULLA$D7g8d>Ry9jp_0f&nDj@AxrGHdHSYHDk;{r zg_EJ{I3QQqrv6OeIOq^Ls=?tw{{cqxh}fb--LXVK9aJ{x{?oU5!^#=Bf9mZ1<`16} z(~gUm_OX}X8czM``D&HQo8rnh$>~>&@H8qQ+!!$0BEcLUQ9uAt76@+W2zJdhRiw6N ze?kHYPh8F{&(st%y$dA1w#4r=P6!Z9ZTk3JJ8+=j`?5|FS$@J%v)eaCq@XON}S zLJ=w!L^uO3&M3EQf8B(G>8~Z0YT>wW-W-ZXjlE@#L3;@~%IZo7h`Ig3L%0w~ymUiW zC-yOchmQz0vNg+BX2tdaa5;(!v(575mz4~R!gR^SJ0SxmpXvgaioxTbfV8hT>- zS{{H=&-wcYZ50q@%M3TuM{ROT~SW1fph6wO;SZ5qjUjX%%-zs`#{e=M6sfuDn20g#+XFakG*D_ALXr z6AC0>9Ym5DABy^~ncKODe@ovwDBk|j_|`WC)){-IqtPNJk$$CbrUH=n_fH^9#3U&T z=q==`G67MH1lE`A%vzBUUzHv)YLLyvP9htxlBYKVgKCSO@?N`$>#-~&?oNa^+o$t zA5p$IX(sKdDqW>0J2-6!tVIr3`v=Tl4~4(0i(4Kp_fWDJVC~X@8=CsHz6M^Ys?=)@ zefwvY)MSFmcsg9AfP22YW|Uk+&tzah)ErE9lQLewj?kli^QZ}Qi+(fbjv zt61QgvYsIzB7p)az{`ZM{1*)@6D5=r4(vRH2D>4_y`aO0c8qRQ25V>fIAgOP6~%#c zKW8!SG_wLrx116qos$$R%o|ty`KGB2Gu6zw_30S>=hiVOu*A|LfYB$-mSsdP)n)qv zkhk27bc!Kr{1BaY1up%9V^(#Vpz&V`;TgD3tj@1`vi0+P1s8_{XM z6f>UrDQXN!gh6Xp0JkEto8+~JD-2GCH=?JC4U>&sZp-s0;!sYW@_8laBXCit@bb?e zXzR`-Bd&4G)G4T+qdZAJq%N=(m;jjeCrN&4{EkicmC(uIiknnezr6hP$@%vhwG&+$ zd@scn_KT5AVngQFL9hs0{OTsls{a6zJUSlq8%FWf3f#9mEHk*m*!RSAW zSlrta6A@6~9kS$$zA9=1tw+sP0lXK)m=V|X!ZxbYB%l*H9L79WQ7d3`vVa{kt=$E7cD|eW>Kz>3 zrl(8qOOJkhln?BrPXp*ixYScJET7U+(QZ8(x9HlEc&X0UQd(p#e6;;`Mr2?WMvN*) zwVxW8RlwCeL-^0Lbqd`~9GZ>xbyC7(>bLe%2&2^@k2@h+j{fU^KMG+``ni|IF4xmo z4Tb@V7K`=*SLFyzC5!pECEWChGepKR`5g)G;(`_N_3v?i?jF*r6hbRq)>S;)&kz}i zapA5ak*5wtTg~1nHzyFvFlp=HlkjHB5rs|z%=MGxI|nSb#`SBXMF#3&^{bM~GbaDO zC5Uq`v-j;F<^k-;&g(d>#T;6t6g;1(h>ioIwT%zHtt(*ybgxa99uv4Yu#4fNkJWNR zI!wlLOg8C-4&O51d&x`;k5H})z5b#Frp9UDw>#%?XBC=Euxw5~FLqT8yAh-vu|#Kw zYRkOGhmFq2uSP$Xp?{xSr!}qkU3~6nucAZnUe#LE0$J-!&-YATW!ti)3qGKrOjo*% zSuTFm`zFXJ2MwLf!cIg4p+C z)661>yJV`bb;M27UU{wskT57_q)fl(sOUgw9pUTOBj9OI$x|&po`}C=s$qPtzrSv~ zbOqR^<}5WloE}>qsgx!rdR-#mvx8&&0vXhjl++9(M5>7y=TGd&-NO5bA?Xg$ZX`Nk z)>Y-0TPkk{8y>lIk)efM)l3cHJ+7OgRLswHb9RN*7Zn+fi8+O<#M(J`fH0EKF?(JA zs6N7?%TsYi;fFmU>H#nO+nsxMV|F9O>QGGUWZ-O$U_u$C57Y~PRE)EV9n<$^qxfYU zSw0xw+fr07jy+!f#fw=KG7S;@K;YL%Yuj$U3yr@FLXe~@dRj{p0s7te zv!``T!UMl)iz7L*C=S$maMG#!Vn69{jqAh+ggY-8Eyk2rS1o;Mj*v0`K0&HWha$v2 zLGaDgFg0T8m3!x!g@e~~%$j-q zzDCB&RqRddF0-?-$BiG79=wmMZy#D>QqCz1PVU1N>Aqcu(2+2f9fussI0I&BW?=iH z>)Iq1W+maf%cjEi_#6<`UwH4^b<6=_Ve5B!{zk(?r$Qx!eRw>@`S+&E>I;?3al4f* znpMB{4j-S6oM+iQS`?l!@vM@L(8`-PXHJck$a{FzX#LpB zbx&4ZGWNI2zla%}yD%Th{-Pb(7pV1?xvYDQVu_wDP$B}+qghPpdjH5bqFjS23i2dW ze4ZfV7E}pmKi4-V8NFYW^3$b#bc3c&rHTn4+8~uj^q7`)#JJNj~UI&!9hL0*P_E8I%In$@#ZH4lrqvhF@! z7NfkL<0Pe8*7-u7A7+C7`uLCD>q9FfVUUgB->gKBdeqiidzDxGtVNiLkYU--q>lK_ z(I5A)`OSL0jOQsm&zh-Pw73v#sm!HU;Ge>uO*`f4{9ObEBM5X>9R_!wecA!Nv(jQ> z9HZ|GvVwGp3k7u>w3X7KdVnMK#P)Z7aKS%U_>RU~mFirB{D7_aF^0bHY&ARSFkdmr zh}0giM+YGy_aC1+1COZgD|ZvLb6f0Y^m9kBHioFmcT8R_qg>xcnQIvw1UtURH4sTO zS#Wq?&+M1>U#x30v>c>|XD^}`%P+~7L$?sANmoxI4S)2~R&{@8>Xx74mu#tw z8v5~u!VF5Dz-%ZI1!+7HnHx78@cVa#rdUEZ}tjpqI2U`zdGhmT6f?0s`q z-_m5m`KYk2uNxu{&odTOZbbA)K{_qUJ~;XZ6EhIkcsxlBs~Q+D?fPo9)-5=CMW{8v z3c3)cefRyI-+-;8E(j(ERhI?JMeRG-P`-J*w`np($vvlEG-OdN%rs0|L2pMF$f4l< zO|>XijfB2tcZa*ifk7_gN;)sM3A-%FR$SROl*I8`92=8pCspt>6%ZnS`T9=hvxn-C zq|oWnhy7RK`j*FWh0^mOF2`R3Vyj6OX-apf50Sea7>;K;!BPZNtqN?hhx@BWS=g-G zfxaIqI-k2zj3U9VPva=>FW=tppl=$#AWz#Z#x$J5(Aw|XvbCQA-`sTL`TYSHjKG=H z*QjnbOpD#9Z`tow%cls`|L!ZZQjSr_(r*{Ivf6t1_ce4#4#vK1qyt6Fnm}T|S9wG? zJhTc&JPej~1%(m}?7?>P#|0jY-CotLEodYjR z&xO7nXl7QBgD014S1XLt2pW8m9J-FMU5F z2afKKf8w=IYuTXM*c{pzd*?Wnw6qjMoh}5Xzu`b)je^g~66&|pqBv)O)5%k9^1M6l zbRzNWFI0!9Bf*x@YI92wVQYsgg1p#VnMtZW8^%mXh(v=JZsgF;X}3BJgGHACJ6!&L z1t7xr<*9Kz=|vq$CY-%hWpAuc-RoRO4~y1}X{us#@Em&WP>W}K zhi`5(;#-a^U{C5nr$LEV!t8S(+gFd$xu2$j7HFXIjHFeFZY&N=Qku z{K+?zT|7|JNa9h&IpGLBY!TM>2axFetE=BVC%IwNNMK$cwugcZ6k&iQxh93c-~@$) zSIXh8pUFNk)Bxxc`kG=m&1MUE2>bPHj_N7!NR>{{s@62K0Qi#IkJo-pEw^R}*FsUc z)8mqp47*-LYj9}(J>o2FU!g{_Jr#Mv<5<%v7KT4BemXrgkwZSH8sgjA2T?JEIK>H&9@w@|6*pl_quASjMkQa-`f40?c2fkkV<%w6)L$FNM-t7Zxo2N{TRSw)Z|T4~o~@JYMgR%Yt@rAN*nYHv zpmhAJ2fV4%5U_I0Y2_F~tQ2;Wu#oZGG}y@t4-;5}@1QySRed#zrr*l9`BddT3%})P zKbdBV>mvO%N^e0}8Dc3!el{{cx00ndl4v=Mh~XVN3|m`LNh+%cK;VK_V180T&uwel z&eG|iK;VgsLS{b-)9&5ughnbX$`-&t)tcBY|LpVBXi9i`570@ruCsnub*e}bD zh@0vAe8;4pDvB5>w=8vmkN6DktQ4ulDU-Z(xuld5$-6)%R0L+P1-jjfiU(&~p5N8J zQAa`c<$tMEjqzGxaVW%z2?2$FrlfJm@Y=+xKr%dL_3VJ8M}{IdrI;_sImbS{6|cEz zr?9@i7Jn}hvPQhS9|iTO6>WkI94Q2}9jh4BaRV;Ti|$kpKB>w5^R(ZdI?*|7(F6i3 zgfB9X>*0(WZRg1Ee+Uxuv!PYX7!oB6f{o=5NQ6@bhIQ?1?hsF# zHsG@2ml@x2$#5g5JDp)C@gUD~x|V=4!drOoW5(EVeb9h|x>2(;;^9Prom%s_j1%@6 zgi<-|h|aJ&Ko7Zkzzwek%H(y}2b4~p0NH=^Jt8OK$f=r&czo`)7c;X~ecIx8L{ zrDFP`DF|+eExI0~s9hKc28c})oRDI;#I`Fp5SicII@hu^D{Z_yqnz11ugTakx27o- zrz>TSkoOz90w)TmE&cDIlx4ZHP=?)&ZuRel_F>r|e9+4)*E)0&2!D@tlTDQ^q^FG3d;D$~!xHfN9{-qqm8<7+c5~BoU zmW+P+W{fbhE$fl#Tr=8`cydZaql>@ti-Fs+t;nZPvV}u6?~cJ89PmDtXc!mttTB#> zev;<>BJ00zT7Ri4|Ipj{Z}i|1@&W~=u z;iovS+IsSGAZP35RPG1mb?xdG=Y@Kd)2uxDta6gfzXleL2pK!qEw(^1z@nFS-*kF7waOKNM;dwRPzKXjN>eE*dtxDg|bq?(vDC7_nV#XKm#qPbuc zyxqTqX+MXrOiVNDQEe*~GRhNfPJHB$-DINI~T!;$UY zJ|6p5R@7q;zq8KlHFVjW9}$1_BDzlTPCX%J+9P~1es}x6J(FBzB71PjM;5qdzmFEv z-F?uaB4$$)`5-kSw3y-E!#pel<(iJ$*t<)2q=5^TE}@ILIlduSGkyhohr8mG6tY(# z)?gm%LYu+?<4Hhv4iP#DQFu-UbcjpQhxj4Fl8RaC5?SwWWhZ0_cxFP-VBy<0_?6=L z)A^Gc=^~?Q|Bj^olw4Z$h{1Ic^%|J`^7&OI%OhFL0JCco2^9Mg#U&{pely*H|(V!xRFxp-oea^i*bgq*?W2hpxWb2Seh^m&tvNZ z7B2yY{GnU?w2(GFhdl-i-%heUT24A{$Adnrx(GM#7g?JN0`O`C@;D=DZpVzx_7j!~ zdSO-fLjpwIE{xfiovIVWY|g27c=;7Jp1isvH1;|$-}1%^3Re#cHhsYl zMjPGl{ax{iu6~ZrTI9oEwy9@=<3|D_?tJ`O{jWHTTIFrPDQHKLC?9f1j}eRs$%v~I zn6|?t;P0ApfA|2!-nzjTlAnAJ6%BR4t&vN_3LAmVSI)xMX=eU#{hnWpy~i^~*d~gI zSfns^EV2CyM+{(Qe79h@f{+8!RR}>q_FJk;C9btHCR|Nk^5XlC6IUTW z1mKH@M5}cv%Qf)uglBCP{(1&5Wx1i-T1HA;!q$j#P{j82&49qi6Z$_s&g>8@(v?!A zwl0i?2W}Nqlvo>NE!=?G7SG`Mo&{=_OxSq^= z{8S+80fi5B>k1qEFYQ!C$|C?0>q@dyO=m!%8zG4iGh$itR-rV z>APqfJLQ3)EBx%RPRwpT__NC}B3cEZ7Vu0gG3KGDzDq}z{78M$Py}Pygs!f!+JYV} zkP5$?29!nW+rON)t;P8)-I zMZ`T6vRzZ8KbDZU=GYnvp$FV|hZ2O6{v}29b{9iYcTzEA%c}Na)qb?OgI-22n^nPX z6GcE62BfncR!Z(yK($r$G2Q$eyhqH{k-x6p z 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 literal 0 HcmV?d00001 diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/circumcenter.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/circumcenter.png new file mode 100644 index 0000000000000000000000000000000000000000..f743b7a64cacc527a5562ce0ae76d641675ad423 GIT binary patch literal 3862 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 literal 0 HcmV?d00001 diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/constrained_triangulation.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/constrained_triangulation.png new file mode 100644 index 0000000000000000000000000000000000000000..3a49172fa17b5d09511f331faf39f6c6ab637ed5 GIT binary patch literal 6800 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 literal 0 HcmV?d00001 diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileNew.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileNew.png new file mode 100644 index 0000000000000000000000000000000000000000..af5d1221412881e8727fe26930e5d0b5b0633aae GIT binary patch literal 768 zcmV+b1ONPqP)R27cmB`+Wkx8a_@65j^u^siVQp>_ zPwn8;)Y0kK7)l|lBE%wFmC-v$eL~)Yfy# z^Ob>gz1owlwa4nuL@ZOXxYpY|_=&3meg}r2l-hGYxpQ6xt+akF&AwE-Rj{%5WonE%=bMnbMjE6fFxi8F4En`*+~J=7Qars`&=Io zhuwOigX}AaoB2WbpNI;Z{V^LaLk(JDtl#%qy z0f>Sm3j{{aCY8&CEXN`MM|ZE8%R+uhohP>-UnM8m)ey5NDv83-9qxc}B#Vq3KoHKA zr9$dh3?K|tQxUGnzF?FXfupNPBJcqpK@|`Kj_Uz9$Li`v=>Q=x&=v?xE!YNlY%Pp2 z`(c97k@x;0y2r zSkx79I6z~aP_V?vz+;97?mOd?a$#bTcUmw3OasdW&9Ju0FEPu=Z0000NkluMLp6h%0z3=<;A2g_#%st8T@8|R6`^WPY zN+~|cy!}H_Tu~a@KD%tm_m%7DBeBj`kG8vQU){vgw8h}2SJgOx_Wy$a@FNi_DPZfe z`nBJwsC#Z*QE@GJoQ`tuDa(UlIM}E5i50 zBA$rOU%pfGhYOm1CieM!Vph$nt*?~TY^loi`LXV`5}%pm#t@`))-rF!=crz=2waH* z;&%?&t(Tk+00|(JQV1c$vDa8QD>{33#j+hQ&7QY9D6ARciDBIrh-i^WiBC;mWoDv} z!6`vsx{B(RFHl;wgmA7OUDr{{iz~czzq@99`0t%p{lXW}qVfl#^_OC$#}{5(QTOzo zk_Fo%L2DS5x`{{AAP_~_I{M52cSceSW=aW^ZDx7>212EvwFb$?inmyRDnA3U(o1R+5=&d7U!}&E2ZTB0{=@8pPcNL+3uBftDi44tm{OIN(koEl8E)va^lqVyXUj5-2)s2 zuHBC#0hkYqo2M57N?UsXwh`2YX_07*qo IM6N<$f-Pt`I{*Lx literal 0 HcmV?d00001 diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileSave.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileSave.png new file mode 100644 index 0000000000000000000000000000000000000000..8feec99bee8685290ec292e7baeb2e23ba4bdf0c GIT binary patch literal 1205 zcmV;m1WNmfP)NMq!WhGU zDb0?ir%%5E<_$1MjY0D7B#lW{;<)?El`Cg|1R~9@%$x6h^uLpO_>ug@xmmgJ*No_P znnEHG0)+hmDMa6YiFRG4o_LlgUp&G194;$ z#|Q7e%Hu~Tky2s+BT^*7)&c<-q*B=0DRAb}Cf_b=^dCQH;0Q1UG+z@p-S0s>z(fLJdaXofa#Y{a{XE!DHR|93_w4?hG<8kq+lom3=aj}y`daH}yY*TMGX*PU}a?k^Z$mMe=dBBKr3MP(B@#**TcTpzBa|A=h93v%QS-kjptJB{4u^z@&y0LCI4T6TSa45CS|$;yRAqEsIM__GKF%A16&yfb3{?Ev3O= zWp`NK(`0awX_vDHsHDgM8ZYP2344@ECC0|a7#$t8fc=zn6g_`~Gzu^#jRElxKudw6 z9$4;tmaREZLZad}%d_8@%6e3-*Khp}bb(|KKnidjfs}wT93TtVTG{6kY+YmJ^6l=8 z>lZ#>U;q0&umyDY?jo%iDv^z46gTJE4_y{w-(;l(uB)>!J7T{u)|M^Y%M$(Q0;0yWQjJ)lC|WuBldAVWm>@ zYqi>@@7LCS|K4h~T3%gTynM%)v;o`!%0SCx>I0b8{Dmvcx$`r{^6IAfuzWTu7V=>n zht*cAvEloba;37qRxV#(t5)yUfG*GhflRd$wsDcfR`M{f{>xbi>|uW%=st z#`gB=U1QP^==3?TwFS`Yb4+F%ysJLI!or#FfIoo|Kmay)=NJKTf0)V094!6;(N7PE TmU#bB00000NkvXXu0mjf&~!wG literal 0 HcmV?d00001 diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fit-page-32.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fit-page-32.png new file mode 100644 index 0000000000000000000000000000000000000000..98bc12d3ed62cb77729ba88caff73e6a356cc540 GIT binary patch literal 1330 zcmV-21IF@x9@EKIX4D0x-=2@ zTo3R(kC-Hc6mzbeQ+xEi+S$PQz#8!42V=*tfXIR(26*lHK|D_SVtksFU$(Pr0{^AVAuPxx} zbOQ0jF81<84cM!QyR@Fht#}ew=-k(r@8a`|ckt2PR%i!r5kXwSyq822Z|JU#IYEaf&4s>R;fS6D3PBU>VQry z4PkA6B?ZLFP;U!#GUSFz)&~RQ!3ad?a91M$nWW_va8(GT<fI|6#5JwVt7}N(%nr`BzW$V|1t!g`$faa~mx6ayz@c zjpS|)2Rj?^=BWYp5_rvLAER0l>cApcLNK2?wjW0iw(>Z>wu_R>i%29NA(JbR+hcfX zv{!n^ReeMn=Yq%8OEC*I2~Q0%GSJR$E|fg%WbzC~Lv%DpaDej0G$2c{;=tY23lVRw z+6NAHH6Z<{0Gr$#BE;sHhgdiQK!67zYLLQc`6c=8ncOFlq8ML=ODplOq;-FM=v9yt)CX^CqeE=F_xVMR>ekJxPP^GR?hDv6^ZT;uU3Tk#9S`vr5R8dmzI3JZ z2j!EAl21196h*LE>NLwtbL2a%(4IQsu+a&kgxi{8V>V|t_m5tSit{fL z*9s_VYM6E`xFUA)+l$1v4E5b7){5Dg%;dc+u{1V++RU=us%-~~o-Po3`F+poI8Mbq z0u$S(-d(Z(oY&@iroYxLKTy&mwfS)T$KN`u^R@3TUlpa}W!|~@p47(MvJ3k)w#rnzS(!?*Wal5cv}`8IV)x3+U--pb21 zh_HRxEPo_&qt4>e%)iUCt%9Ym8MYZ5>gX*!DI@mfbbFERvSkhZ*Gra}ttqvO&v-Wf z>BgqZWoIRsq_n5kZ~u4K_C!eanOiGk>M#Gk+P9{hM?O-+?sRhO(({+USJ{=ljfl

LQG!4D3T)BC)qx5E}{N$IF z+x=(S+&5*Pcco-mS&FTC*-^=hKl?0-r(O(E`+e%O%^|OX*j2xIKdf119ICAS^vrwV z%Uab(YC>LS$OZm(4UE1zr^@2-98esAF4L3TbyYxt-bi`Usa{uTWd2X{Slt%uGnIH;QbfvpOSxb(melZ zu8>XI_GMm&&5HM~w`&jIKA`y^$Vz;l?b<&QJ8mxd>a%%wvFwgR+w&vtFz0ohnBz7p z>wW?A4W%@Twb6I5=l)B}@NG?#e*UI?is#mpNAo;Op2c(RKX1p%2gOH@ z+|5jy<$Axg!n>xWlF8`AUPA~9Zw5DlWM-L+hu$W-*boFyt=akR{ E0M>H=ssI20 literal 0 HcmV?d00001 diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/inputPolyline.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/inputPolyline.png new file mode 100644 index 0000000000000000000000000000000000000000..63d0a08cca3eb3e8de9de52831d5bdb3c8594a31 GIT binary patch literal 2021 zcmXBV3p7+|902f(!g!@vkD?ln(x8wigKC!;92x5|RGOw*wI+!QO=gT(iWOEvSQ*=d z%(ljClTMRSo+~n~Ew37F%A|-CHjnK5KfiPC{m%K${eS0v|L_05_hNv*m$t@g4GhDy zN!}iTiqThbx$3Ga?#wU6QpKQ3^Y!vrL~xXu=ZYCzjCWWZhUqlHrF6wwXAMlAjoBTk z7*RZ?QtuvyVQMiXkKI8D{bRolSf4*&)OxMc<8{LBx}3O8_-K#v{PO)T_w4ZW(TSg5 ze(QOTX1-=Dp()LRY_X|g4W8^zejMAeDP0~f7?j^R7b#1OY#F`ZvsUQtJUCtICVbYx zbnOafB+YEVo0+9F)(8OGXf4orIRwl};yKIzoHvV!RNHDK<067pA!3H5U3%lPkVvp` zK!&LHz5r*gm%KN5>t3@osk?Cl@H^0GVj7G9eH|Ae{C(>VC&@c&NMPtKY1L-M3XL$j& zahYbFmq@S_RIBw`4${4a-wh3QJqDDj)2G00S9jp#7E$SR^Iq0bSM@Cfpd1qqobNx} zT<|T4U;~!rv{JC8{fH$$>opQOh;!P!~|$yK%vxcjJ>!p94k9 z_n_hK%f_~AModK*NOmbEcGW~#zY8%rNR+Zx2CV=f$OVT z;8H$p%6+6vMn+S+I)D|cT!K=hYmS65P`3=V-;vXOlsqNY+9w>>iT~gOY;+u`q$1dn zqhQluskq6UbQ_^d>a@6mtFSAW#v+ znGX)f|6%EqSL0Nj)h|@_H8>n0G(L19WY67BjdYZ)WBn^~(9$ZpMxbq6XBegH{A8Tc zC?Z|aTpcP=d#d8Q#Zqddh&H|*c>Q<9QUreIbk#6V8j@+hCG~cgWqvl5VcQ}Oq7<`k z6dkqsQtzJp3B+N2G_9OG@NllH&Gk5PdWZ5ZQIFL2tC%5Auv$x*4$n%&^E)+u3-Sr- zr*-(I-R^S=zOPR>VLzN!<79n-#y)y$nF|3O{3T6Y@JBwXGS-+NM+TN75;<4sSXf~D zxZ{WJUf>;7*3R0yy7RsmU~MZnzX@!TdYo9_?+3=1nj&j>GrB^=+kg^ zzMYni^DQHfO!D zGC0hBY$q3<3d$4&BvtkqjwW3a1js{#JSiF0p*kc~EY2C~gC-Mh?PAME6Rxs*;Sv5I z&E8<5*`kJ7+)Qamm+*4G#&T6uQ1X)qq9w_HorrHViiAPjO6L>aqC-Z%KvN>>?i;L literal 0 HcmV?d00001 diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/license.txt b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/license.txt new file mode 100644 index 00000000000..ff11c043161 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/license.txt @@ -0,0 +1,5 @@ +The following files have been copied from Qt Free Edition version 4.4: + fileNew.png + fileOpen.png + fileSave.png, + fit-page-32.png diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/moving_point.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/moving_point.png new file mode 100644 index 0000000000000000000000000000000000000000..44f431d98437646692f051fc8505293a7c95a6aa GIT binary patch literal 8074 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 #include //#include -#include +#include #include // to be deleted @@ -37,13 +37,13 @@ #include "ui_Periodic_4_hyperbolic_triangulation_2.h" #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel R; -typedef CGAL::Triangulation_hyperbolic_traits_2 K; +typedef CGAL::Exact_predicates_inexact_constructions_kernel R; +typedef CGAL::Triangulation_hyperbolic_traits_2 K; -typedef K::Point_2 Point_2; -typedef K::Iso_rectangle_2 Iso_rectangle_2; +typedef K::Point_2 Point_2; +typedef K::Iso_rectangle_2 Iso_rectangle_2; -typedef CGAL::Periodic_2_Delaunay_hyperbolic_triangulation_2 Delaunay; +typedef CGAL::Periodic_4_Delaunay_hyperbolic_triangulation_2 Delaunay; class MainWindow : public CGAL::Qt::DemosMainWindow, @@ -52,18 +52,18 @@ class MainWindow : Q_OBJECT private: - Delaunay dt; - QGraphicsEllipseItem* disk; - QGraphicsScene scene; + Delaunay dt; + QGraphicsEllipseItem* disk; + QGraphicsScene scene; - CGAL::Qt::TriangulationGraphicsItem * dgi; - CGAL::Qt::VoronoiGraphicsItem * vgi; + CGAL::Qt::TriangulationGraphicsItem * dgi; + CGAL::Qt::VoronoiGraphicsItem * vgi; - CGAL::Qt::TriangulationMovingPoint * mp; - CGAL::Qt::TriangulationConflictZone * cz; - CGAL::Qt::TriangulationRemoveVertex * trv; - CGAL::Qt::TriangulationPointInputAndConflictZone * pi; - CGAL::Qt::TriangulationCircumcircle *tcc; + CGAL::Qt::TriangulationMovingPoint * mp; + CGAL::Qt::TriangulationConflictZone * cz; + CGAL::Qt::TriangulationRemoveVertex * trv; + CGAL::Qt::TriangulationPointInputAndConflictZone * pi; + CGAL::Qt::TriangulationCircumcircle *tcc; public: MainWindow(); diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Delaunay_hyperbolic_triangulation_2.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Delaunay_hyperbolic_triangulation_2.h similarity index 97% rename from Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Delaunay_hyperbolic_triangulation_2.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/Delaunay_hyperbolic_triangulation_2.h index 9a3836f0b18..902625a1349 100644 --- a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Delaunay_hyperbolic_triangulation_2.h +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Delaunay_hyperbolic_triangulation_2.h @@ -87,8 +87,10 @@ public: typedef Delaunay_triangulation_2 Base; typedef Triangulation_face_base_with_info_2 Face_base; - typedef typename Face_base::Info Face_info; - typedef typename Base::size_type size_type; + typedef typename Face_base::Info Face_info; + + typedef typename Base::size_type size_type; + typedef typename Base::Vertex_handle Vertex_handle; typedef typename Base::Face_handle Face_handle; typedef typename Base::Edge Edge; @@ -493,8 +495,7 @@ public: class Finite_faces_iterator : public Filter_iterator { - typedef Filter_iterator Base; + typedef Filter_iterator Base; typedef Finite_faces_iterator Self; public: Finite_faces_iterator() : Base() {} @@ -526,7 +527,8 @@ public: //Finite edges iterator typedef Filter_iterator Finite_edges_iterator; + Infinite_hyperbolic_tester> + Finite_edges_iterator; Finite_edges_iterator finite_edges_begin() const @@ -587,7 +589,8 @@ public: // both faces are finite if(!is_infinite(f1) && !is_infinite(f2)) { - Segment s = this->geom_traits().construct_segment_2_object()(dual(f1),dual(f2)); + Segment s = this->geom_traits().construct_segment_2_object() + (dual(f1),dual(f2)); return make_object(s); } @@ -610,8 +613,14 @@ public: Segment ray = this->geom_traits().construct_ray_2_object()(dual(finite_face), line); return make_object(ray); } + +public: + void insert_dummy_points(std::vector& ); + }; } //namespace CGAL +#include + #endif // CGAL_DELAUNAY_HYPERBOLIC_TRIANGULATION_2_H diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Diametric_translations.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Diametric_translations.h index 25e4cb549e1..4dc5065759d 100644 --- a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Diametric_translations.h +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Diametric_translations.h @@ -1,8 +1,7 @@ #ifndef CGAL_HYPERBOLIC_DIAMETRIC_TRANSLATIONS_2_H #define CGAL_HYPERBOLIC_DIAMETRIC_TRANSLATIONS_2_H -#include - +#include template class Diametric_translations diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_2.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_2.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Hyperbolic_face_info_2.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Hyperbolic_face_info_2.h new file mode 100644 index 00000000000..d5d51dca212 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Hyperbolic_face_info_2.h @@ -0,0 +1,81 @@ +// Copyright (c) 2010 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you may redistribute it under +// the terms of the Q Public License version 1.0. +// See the file LICENSE.QPL distributed with CGAL. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/candidate-packages/Triangulation_2/include/CGAL/Delaunay_triangulation_2.h $ +// $Id: Delaunay_triangulation_2.h 57509 2010-07-15 09:14:09Z sloriot $ +// +// +// Author(s) : Mikhail Bogdanov + +#ifndef CGAL_DELAUNAY_HYPERBOLIC_FACE_INFO_2_H +#define CGAL_DELAUNAY_HYPERBOLIC_FACE_INFO_2_H + +#include +#include + +#include +#include + +namespace CGAL { + +class Hyperbolic_face_info_2 +{ +public: + Hyperbolic_face_info_2() : _is_finite_invisible(false), _invisible_edge(UCHAR_MAX) + { + } + + bool is_finite_invisible() const + { + return _is_finite_invisible; + } + + void set_finite_invisible(bool is_finite_invisible) + { + _is_finite_invisible = is_finite_invisible; + } + + // Supposed to be called before "get_invisible_edge" + bool has_invisible_edge() const + { + return _invisible_edge <= 2; + } + + // Higly recommended to call "has_invisible_edge" before + unsigned char get_invisible_edge() const + { + assert(_is_finite_invisible); + assert(_invisible_edge <= 2); + + return _invisible_edge; + } + + void set_invisible_edge(unsigned char invisible_edge) + { + assert(_is_finite_invisible); + assert(invisible_edge <= 2); + + _invisible_edge = invisible_edge; + } + +private: + // a face is invisible if its circumscribing circle intersects the circle at infinity + bool _is_finite_invisible; + + // defined only if the face is finite and invisible + unsigned char _invisible_edge; +}; + +} //namespace CGAL + +#endif // CGAL_DELAUNAY_HYPERBOLIC_FACE_INFO_2_H diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Hyperbolic_random_points_in_disc_2.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Hyperbolic_random_points_in_disc_2.h new file mode 100644 index 00000000000..1f2edaeee18 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Hyperbolic_random_points_in_disc_2.h @@ -0,0 +1,86 @@ +#ifndef HYPERBOLIC_RANDOM_POINTS_IN_DISC_2 +#define HYPERBOLIC_RANDOM_POINTS_IN_DISC_2 + +#include + +#include +#include + +// Euclidean radius vector to hyperbolic raidus vector +template +FT r_h(FT r_e) +{ + return boost::math::acosh((1 + r_e*r_e)/(1 - r_e*r_e)); +} + +// hyperbolic raidus vector to Euclidean radius vector +template +FT r_e(FT r_h) +{ + FT dist = std::tanh(r_h/FT(2)); + + if(dist > 0) { + return dist; + } + return -dist; +} + +// if seed = -1, then the seed will get a random value. +template +void Hyperbolic_random_points_in_disc_2(std::vector& output, int nb, int seed = 1, typename Gt::FT e = 0.0001) +{ + typedef typename Gt::FT FT; + typedef typename Gt::Point_2 Point_2; + typedef typename Gt::Vector_2 Vector_2; + + FT re = FT(1) - e; + FT rh = r_h(re); + + typedef CGAL::Creator_uniform_2 Creator; + + CGAL::Random rand; + if (seed != -1) { + rand = CGAL::Random(seed); + } + /* CGAL::Random_points_in_disc_2 in_Euclidean_disk(rh, rand); */ + CGAL::Random_points_in_disc_2 in_Euclidean_disk(rh, rand); + + std::vector pts; + pts.reserve(nb); + for(int i = 0; i < nb ; i++) { + pts.push_back(*in_Euclidean_disk); + in_Euclidean_disk++; + } + + for(int i = 0; i < nb ; i++) { + std::cout << "Adding!" << std::endl; + Vector_2 v = Vector_2(Point_2(0, 0), pts[i]); + + FT sq_dist = v.squared_length(); + FT dist = CGAL::sqrt(sq_dist); + + FT dist_in_disc = r_e(dist); + + output.push_back(Point_2((pts[i].x()*dist_in_disc)/dist, (pts[i].y()*dist_in_disc)/dist)); + } +} + +template +void Random_points_in_disc_2(std::vector& output, int nb, int seed = 1, typename Gt::FT e = 0.0001) +{ + typedef typename Gt::FT FT; + typedef typename Gt::Point_2 Point_2; + + FT re = FT(1) - e; + + typedef CGAL::Creator_uniform_2 Creator; + CGAL::Random rand(seed); + CGAL::Random_points_in_disc_2 in_Euclidean_disk(re, rand); + + for(int i = 0; i < nb ; i++) { + output.push_back(*in_Euclidean_disk); + in_Euclidean_disk++; + } +} + +#endif // HYPERBOLIC_RANDOM_POINTS_IN_DISC_2 diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Octagon_matrix.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Octagon_matrix.h index d3d97100ac4..a90b52e6e1d 100644 --- a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Octagon_matrix.h +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Octagon_matrix.h @@ -19,8 +19,8 @@ template class Octagon_matrix { public: - typedef Octagon_matrix Self; - typedef complex Extended_field; + typedef Octagon_matrix Self; + typedef complex Extended_field; Extended_field M11; Extended_field M12; @@ -37,8 +37,8 @@ public: Self operator*(const Self& rh) const { - return Self( M11*rh.M11 + aux*M12*conj(rh.M12), - M11*rh.M12 + M12*conj(rh.M11), merge_labels(rh) ); + return Self( M11*rh.M11 + factor*M12*conj(rh.M12), + M11*rh.M12 + M12*conj(rh.M11), merge_labels(rh) ); } Self inverse() const @@ -79,6 +79,7 @@ public: Sqrt_field BB2 = (B1 + B2)*k; assert(BB2.l % 2 == 0 && BB2.r % 2 == 0); + BB1.l = BB1.l/2; BB1.r = BB1.r/2; BB2.l = BB2.l/2; @@ -109,7 +110,7 @@ public: // determinant == 1 Extended_field det() const { - return norm(M11) - aux * norm(M12); + return norm(M11) - factor * norm(M12); } static complex toComplexDouble(Extended_field M) //const @@ -126,7 +127,7 @@ public: Cmpl m11 = toComplexDouble(M11); Cmpl m12 = toComplexDouble(M12); - double ax = sqrt(aux.l + sqrt(2.)*aux.r); + double ax = sqrt(factor.l + sqrt(2.)*factor.r); Cmpl z(x, y); Cmpl res = (m11*z + ax*m12)/(ax*(conj(m12)*z) + conj(m11)); @@ -134,12 +135,12 @@ public: } //private: - static Sqrt_field aux; + static Sqrt_field factor; }; template -Sqrt_field Octagon_matrix::aux = Sqrt_field(-1, 1); +Sqrt_field Octagon_matrix::factor = Sqrt_field(-1, 1); // just to give an order(ing) template @@ -191,24 +192,67 @@ ostream& operator<<(ostream& os, const Octagon_matrix& m) return os; } -typedef long long ll; -typedef Sqrt_field SqrtField; -typedef Octagon_matrix OctagonMatrix; -typedef OctagonMatrix::Extended_field Entry; +typedef long long ll; +typedef Sqrt_field SqrtField; +typedef Octagon_matrix OctagonMatrix; +typedef OctagonMatrix::Extended_field Entry; + + +enum Direction { + A = 0, // 0 + InvB, // 1 + C, // 2 + InvD, // 3 + InvA, // 4 + B, // 5 + InvC, // 6 + D // 7 +}; + void get_generators(vector& gens) { + // This is a in the matrix, equal to sqrt(2) + 1 Entry M11 = Entry(SqrtField(1, 1), SqrtField(0, 0)); + // This vector should hold all other elements, results of the exponentials for various k vector M12(8, Entry(SqrtField(0, 0), SqrtField(0, 0))); - M12[0] = M11 * Entry(SqrtField(0, 1), SqrtField(0, 0)); - M12[1] = M11 * Entry(SqrtField(1, 0), SqrtField(1, 0)); - M12[2] = M11 * Entry(SqrtField(0, 0), SqrtField(0, 1)); - M12[3] = M11 * Entry(SqrtField(-1, 0), SqrtField(1, 0)); - M12[4] = M11 * Entry(SqrtField(0, -1), SqrtField(0, 0)); - M12[5] = M11 * Entry(SqrtField(-1, 0), SqrtField(-1, 0)); - M12[6] = M11 * Entry(SqrtField(0, 0), SqrtField(0, -1)); - M12[7] = M11 * Entry(SqrtField(1, 0), SqrtField(-1, 0)); + + // Set everything manually + + /* + M12[A] = M11 * Entry(SqrtField(0, 0), SqrtField(-1, 0)); + M12[InvA] = M11 * Entry(SqrtField(0, 0), SqrtField(1, 0)); + M12[B] = M11 * Entry(SqrtField(0, -1), SqrtField(0, 1)); + M12[InvB] = M11 * Entry(SqrtField(0, 1), SqrtField(0, -1)); + M12[C] = M11 * Entry(SqrtField(1, 0), SqrtField(0, 0)); + M12[InvC] = M11 * Entry(SqrtField(-1, 0), SqrtField(0, 0)); + M12[D] = M11 * Entry(SqrtField(0, -1), SqrtField(0, -1)); + M12[InvD] = M11 * Entry(SqrtField(0, 1), SqrtField(0, 1)); + */ + +/* + Entry tmp = Entry(SqrtField(2, 2), SqrtField(0,0)); + M12[A] = Entry(SqrtField(0, 0), SqrtField(-1, 0)); + M12[InvA] = Entry(SqrtField(0, 0), SqrtField(1, 0)); + M12[B] = Entry(SqrtField(-1, 0), SqrtField(1, 0)); + M12[InvB] = Entry(SqrtField(1, 0), SqrtField(-1, 0)); + M12[C] = Entry(SqrtField(-1, 0), SqrtField(0, 0)); + M12[InvC] = Entry(SqrtField(1, 0), SqrtField(0, 0)); + M12[D] = Entry(SqrtField(-1, 0), SqrtField(-1, 0)); + M12[InvD] = Entry(SqrtField(1, 0), SqrtField(1, 0)); + */ + + + M12[A] = M11 * Entry(SqrtField(0, 1), SqrtField(0, 0)); + M12[InvB] = M11 * Entry(SqrtField(1, 0), SqrtField(1, 0)); + M12[C] = M11 * Entry(SqrtField(0, 0), SqrtField(0, 1)); + M12[InvD] = M11 * Entry(SqrtField(-1, 0), SqrtField(1, 0)); + M12[InvA] = M11 * Entry(SqrtField(0, -1), SqrtField(0, 0)); + M12[B] = M11 * Entry(SqrtField(-1, 0), SqrtField(-1, 0)); + M12[InvC] = M11 * Entry(SqrtField(0, 0), SqrtField(0, -1)); + M12[D] = M11 * Entry(SqrtField(1, 0), SqrtField(-1, 0)); + string labels[8] = {string("a"), string("b^-1"), string("c"), string("d^-1"), string("a^-1"), string("b"), string("c^-1"), string("d")}; @@ -222,7 +266,7 @@ vector gens; bool IsCanonical(const OctagonMatrix& m); -void generate_words( set& words, vector& prev, int depth ) +void generate_words( set& words, vector& prev, int depth, double threshold ) { if (depth == 1) { for(int i = 0; i < 8; i++) { @@ -233,7 +277,7 @@ void generate_words( set& words, vector& prev, int } vector els; - generate_words( words, els, depth - 1); + generate_words( words, els, depth - 1, threshold); OctagonMatrix temp = OctagonMatrix(Entry(), Entry()); ll size = els.size(); @@ -242,7 +286,7 @@ void generate_words( set& words, vector& prev, int for(int i = 0; i < 8; i++) { temp = els[k]*gens[i]; - if(temp.length() > 15.) { + if(temp.length() > threshold /*15.*/) { continue; } @@ -304,13 +348,13 @@ void dfs_with_info(const pair& new_pair, visited.insert(new_pair); const OctagonMatrix& current = new_pair.first; - const OctagonMatrix& current_aux = new_pair.second; - OctagonMatrix candidate = current, candidate_aux = current_aux; + const OctagonMatrix& current_factor = new_pair.second; + OctagonMatrix candidate = current, candidate_factor = current_factor; for(int i = 0; i < 8; i++) { candidate = gens[i]*current*gens[(i + 4) % 8]; if(IsCanonical(candidate) == true && visited.find(candidate) == visited.end()) { - candidate_aux = gens[i]*current_aux; - dfs_with_info(pair(candidate, candidate_aux), visited); + candidate_factor = gens[i]*current_factor; + dfs_with_info(pair(candidate, candidate_factor), visited); } } } @@ -418,20 +462,20 @@ bool haveIntersection(const OctagonMatrix& m1, const OctagonMatrix& m2) const void intersectWithInfinity(const OctagonMatrix& m, Point& p1, Point& p2) const { - Entry a = m.M11, b = m.M12, aux = m.aux; + Entry a = m.M11, b = m.M12, factor = m.factor; Entry four = Entry(SqrtField(4, 0), SqrtField(0, 0)); Entry two = Entry(SqrtField(2, 0), SqrtField(0, 0)); Entry D = (a - conj(a))*(a - conj(a)); - D += four*b*conj(b)*aux; + D += four*b*conj(b)*factor; Entry T1 = conj(a) - a; Entry T2 = two*conj(b); complex d = m.toComplexDouble(D); complex t1 = m.toComplexDouble(T1); complex t2 = m.toComplexDouble(T2); - complex au = complex(m.aux.l + sqrt(2.)*m.aux.r, 0); + complex au = complex(m.factor.l + sqrt(2.)*m.factor.r, 0); complex z1 = (t1 + sqrt(d))/(t2*sqrt(au)); complex z2 = (t1 - sqrt(d))/(t2*sqrt(au)); @@ -471,7 +515,7 @@ void generate_unique_words(vector& output, double threshold = 10, set unique_words; vector temp; - generate_words(unique_words, temp, word_length); + generate_words(unique_words, temp, word_length, threshold); double l = 0; set::iterator uit; @@ -532,3 +576,7 @@ void generate_words_union_1_cycles(vector& out) } +#endif + + + diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Periodic_2_Delaunay_hyperbolic_triangulation_2.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_Delaunay_hyperbolic_triangulation_2.h similarity index 57% rename from Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Periodic_2_Delaunay_hyperbolic_triangulation_2.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_Delaunay_hyperbolic_triangulation_2.h index cb9ec0fc95d..efa9186df32 100644 --- a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Periodic_2_Delaunay_hyperbolic_triangulation_2.h +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_Delaunay_hyperbolic_triangulation_2.h @@ -17,22 +17,28 @@ // // Author(s) : Mikhail Bogdanov -#ifndef CGAL_PERIODIC_2_DELAUNAY_HYPERBOLIC_TRIANGULATION_2_H -#define CGAL_PERIODIC_2_DELAUNAY_HYPERBOLIC_TRIANGULATION_2_H +#ifndef CGAL_PERIODIC_4_DELAUNAY_HYPERBOLIC_TRIANGULATION_2_H +#define CGAL_PERIODIC_4_DELAUNAY_HYPERBOLIC_TRIANGULATION_2_H #include -#include - // I needed to use a non-reserved word for this thing, there were problems when I (stupidly) used TYPE #define CLEARLY_MY_TYPE 2 // 1 = Cross, 2 = Diametric +#define USE_TEST_THINGS 1 // 1 = True, 0 = False +#if USE_TEST_THINGS == 1 +#include +#else +#include +#endif + +/* #if CLEARLY_MY_TYPE == 1 #include #else #include #endif - +*/ //#include namespace CGAL { @@ -40,26 +46,33 @@ namespace CGAL { template < class Gt, class Tds = Triangulation_data_structure_2 < Triangulation_vertex_base_2 > > - class Periodic_2_Delaunay_hyperbolic_triangulation_2 : public Delaunay_triangulation_2 +#if USE_TEST_THINGS == 1 + class Periodic_4_Delaunay_hyperbolic_triangulation_2 : public Periodic_4_hyperbolic_triangulation_2 +#else + class Periodic_4_Delaunay_hyperbolic_triangulation_2 : public Delaunay_triangulation_2 +#endif { public: - typedef Periodic_2_Delaunay_hyperbolic_triangulation_2 Self; - typedef Delaunay_triangulation_2 Base; + typedef Periodic_4_Delaunay_hyperbolic_triangulation_2 Self; +#if USE_TEST_THINGS == 1 + typedef Periodic_4_hyperbolic_triangulation_2 Base; +#else + typedef Delaunay_triangulation_2 Base; +#endif + typedef typename Base::Vertex_handle Vertex_handle; + typedef typename Base::Face_handle Face_handle; + typedef typename Base::Edge Edge; + typedef typename Base::Locate_type Locate_type; - typedef typename Base::Vertex_handle Vertex_handle; - typedef typename Base::Face_handle Face_handle; - typedef typename Base::Edge Edge; - typedef typename Base::Locate_type Locate_type; + typedef typename Base::Finite_edges_iterator Finite_edges_iterator; + typedef typename Base::Face_circulator Face_circulator; - typedef typename Base::Finite_edges_iterator Finite_edges_iterator; - typedef typename Base::Face_circulator Face_circulator; + typedef Gt Geom_traits; + typedef typename Geom_traits::FT FT; + typedef typename Geom_traits::Point_2 Point_2; + typedef typename Geom_traits::Segment_2 Segment; - typedef Gt Geom_traits; - typedef typename Geom_traits::FT FT; - typedef typename Geom_traits::Point_2 Point_2; - typedef typename Geom_traits::Segment_2 Segment; - - void insert_dummy_points(); + //void insert_dummy_points(std::vector& ); void Set_recursion_depth(int new_depth) { this->recursion_depth = new_depth; @@ -68,24 +81,32 @@ namespace CGAL { #ifndef CGAL_CFG_USING_BASE_MEMBER_BUG_2 using Base::tds; #endif - - Periodic_2_Delaunay_hyperbolic_triangulation_2(const Gt& gt = Gt()) + + /* + Periodic_4_Delaunay_hyperbolic_triangulation_2(const Gt& gt = Gt()) +#if USE_TEST_THINGS == 1 + : Periodic_4_hyperbolic_triangulation_2(gt) +#else : Delaunay_triangulation_2(gt) +#endif { recursion_depth = 0; } - Periodic_2_Delaunay_hyperbolic_triangulation_2(const Periodic_2_Delaunay_hyperbolic_triangulation_2 &tr) + Periodic_4_Delaunay_hyperbolic_triangulation_2(const Periodic_4_Delaunay_hyperbolic_triangulation_2 &tr) +#if USE_TEST_THINGS == 1 + : Periodic_4_hyperbolic_triangulation_2(tr) +#else : Delaunay_triangulation_2(tr) +#endif { CGAL_triangulation_postcondition( this->is_valid() ); } - /*vector*//*void insert_dummy_points() {}*/ - - + */ + /************************ INSERT OVERLOADS **************************/ - + /* Vertex_handle insert(const Point_2 &p, Face_handle start = Face_handle() ) @@ -96,6 +117,7 @@ namespace CGAL { Vertex_handle vh = Base::insert(p, start); recursive_translate(g, copies, p, recursion_depth); + for(int i = 0; i < copies.size(); i++) { vh = Base::insert(copies[i], start); } @@ -119,7 +141,9 @@ namespace CGAL { return Base::insert(first, last); } - + + */ + Object dual(const Finite_edges_iterator& ei) const { return this->dual(*ei); @@ -140,24 +164,29 @@ namespace CGAL { private: - + /* + void recursive_translate( -#if CLEARLY_MY_TYPE == 1 // This means that we must do Cross-translations (alternative identification) +#if CLEARLY_MY_TYPE == 1 Cross_translations g, #else Diametric_translations g, #endif std::vector& points, + Point_2 o, int depth, - int start, - int end) + int start = -1, + int end = -1) { if (depth > 0) { - int my_start = points.size(); - int my_end = start; - - for (int i = start; i <= end; i++){ - Point_2 subject = points[i]; + + if (start == -1 && end == -1) { + int start = points.size(); + int end = start + 8; + + Point_2 subject = o; + + // Add points in the order indicated by the group -- not necessary, but seems logical points.push_back( g.a().DoAction(subject) ); points.push_back( g.b().inverse().DoAction(subject) ); points.push_back( g.c().DoAction(subject) ); @@ -166,46 +195,37 @@ namespace CGAL { points.push_back( g.b().DoAction(subject) ); points.push_back( g.c().inverse().DoAction(subject) ); points.push_back( g.d().DoAction(subject) ); - my_end += 8; + + recursive_translate(g, points, o, depth - 1, start, end); } + else + { + int my_start = points.size(); + int my_end = start; - recursive_translate(g, points, depth - 1, my_start, my_end); + for (int i = start; i <= end; i++){ + Point_2 subject = points[i]; + points.push_back( g.a().DoAction(subject) ); + points.push_back( g.b().inverse().DoAction(subject) ); + points.push_back( g.c().DoAction(subject) ); + points.push_back( g.d().inverse().DoAction(subject) ); + points.push_back( g.a().inverse().DoAction(subject) ); + points.push_back( g.b().DoAction(subject) ); + points.push_back( g.c().inverse().DoAction(subject) ); + points.push_back( g.d().DoAction(subject) ); + my_end += 8; + } + + recursive_translate(g, points, o, depth - 1, my_start, my_end); + } } } - - - void recursive_translate( -#if CLEARLY_MY_TYPE == 1 // This means that we must do Cross-translations (alternative identification) - Cross_translations g, -#else - Diametric_translations g, -#endif - std::vector& points, - Point_2 subject, - int depth) - { - if (depth > 0) { - int start = points.size(); - int end = start + 8; - - // Add points in the order indicated by the group -- not necessary, but seems logical - points.push_back( g.a().DoAction(subject) ); - points.push_back( g.b().inverse().DoAction(subject) ); - points.push_back( g.c().DoAction(subject) ); - points.push_back( g.d().inverse().DoAction(subject) ); - points.push_back( g.a().inverse().DoAction(subject) ); - points.push_back( g.b().DoAction(subject) ); - points.push_back( g.c().inverse().DoAction(subject) ); - points.push_back( g.d().DoAction(subject) ); - - recursive_translate(g, points, depth - 1, start, end); - } - - } - - + */ + + + // Initializes the triangulation data structure void init_tds() { this->_infinite_vertex = tds().insert_first(); @@ -215,15 +235,22 @@ namespace CGAL { // The following variable defines how many copies to insert on the PoincarĂ© disk (for visualisation purposes only!) int recursion_depth; + +/* + #if CLEARLY_MY_TYPE == 1 // This means that we must do Cross-translations (alternative identification) Cross_translations g; #else Diametric_translations g; #endif + +*/ + + }; } // namespace CGAL //#include -#endif // CGAL_PERIODIC_2_DELAUNAY_HYPERBOLIC_TRIANGULATION_2_H +#endif // CGAL_PERIODIC_4_DELAUNAY_HYPERBOLIC_TRIANGULATION_2_H diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_Delaunay_triangulation_2.h.misha b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_Delaunay_triangulation_2.h.misha new file mode 100644 index 00000000000..ad5af73f686 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_Delaunay_triangulation_2.h.misha @@ -0,0 +1,570 @@ +// Copyright (c) 2010 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you may redistribute it under +// the terms of the Q Public License version 1.0. +// See the file LICENSE.QPL distributed with CGAL. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/candidate-packages/Triangulation_2/include/CGAL/Delaunay_triangulation_2.h $ +// $Id: Delaunay_triangulation_2.h 57509 2010-07-15 09:14:09Z sloriot $ +// +// +// Author(s) : Mikhail Bogdanov + +#ifndef CGAL_DELAUNAY_HYPERBOLIC_TRIANGULATION_2_H +#define CGAL_DELAUNAY_HYPERBOLIC_TRIANGULATION_2_H + +#include +#include +#include + +#include +#include + +namespace CGAL { + +template < class Gt, + class Tds = Triangulation_data_structure_2 < + Triangulation_vertex_base_2, + Triangulation_face_base_with_info_2 > > +class Delaunay_hyperbolic_triangulation_2 : public Delaunay_triangulation_2 +{ +public: + typedef Delaunay_hyperbolic_triangulation_2 Self; + typedef Delaunay_triangulation_2 Base; + + typedef Triangulation_face_base_with_info_2 Face_base; + typedef typename Face_base::Info Face_info; + typedef typename Base::size_type size_type; + typedef typename Base::Vertex_handle Vertex_handle; + typedef typename Base::Face_handle Face_handle; + typedef typename Base::Edge Edge; + +#ifndef CGAL_CFG_USING_BASE_MEMBER_BUG_2 + using Base::cw; + using Base::ccw; + using Base::geom_traits; +#endif + + typedef typename Base::Edge_circulator Edge_circulator; + typedef typename Base::Face_circulator Face_circulator; + typedef typename Base::Vertex_circulator Vertex_circulator; + + typedef typename Base::All_vertices_iterator All_vertices_iterator; + typedef typename Base::All_edges_iterator All_edges_iterator; + typedef typename Base::All_faces_iterator All_faces_iterator; + + typedef Gt Geom_traits; + typedef typename Geom_traits::FT FT; + typedef typename Geom_traits::Point_2 Point; + typedef typename Geom_traits::Segment_2 Segment; + + /* +#ifndef CGAL_CFG_USING_BASE_MEMBER_BUG_2 + using Triangulation::side_of_oriented_circle; + using Triangulation::circumcenter; + using Triangulation::collinear_between; + using Triangulation::test_dim_down; + using Triangulation::make_hole; + using Triangulation::fill_hole_delaunay; + using Triangulation::delete_vertex; +#endif +*/ + + Delaunay_hyperbolic_triangulation_2(const Gt& gt = Gt()) + : Delaunay_triangulation_2(gt) {} + + Delaunay_hyperbolic_triangulation_2( + const Delaunay_hyperbolic_triangulation_2 &tr) + : Delaunay_triangulation_2(tr) + { CGAL_triangulation_postcondition( this->is_valid() );} + + + void mark_star(Vertex_handle v) const + { + if(!is_star_bounded(v)) { + mark_star_faces(v); + } + } + + Vertex_handle insert(const Point &p, + Face_handle start = Face_handle() ) + { + Vertex_handle v = Base::insert(p, start); + mark_star(v); + + return v; + } + + Vertex_handle insert(const Point& p, + typename Base::Locate_type lt, + Face_handle loc, int li ) + { + Vertex_handle v = Base::insert(p, lt, loc, li); + mark_star(v); + + return v; + } + +#ifndef CGAL_TRIANGULATION_2_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO + template < class InputIterator > + std::ptrdiff_t + insert( InputIterator first, InputIterator last, + typename boost::enable_if< + boost::is_base_of< + Point, + typename std::iterator_traits::value_type + > + >::type* = NULL + ) +#else + template < class InputIterator > + std::ptrdiff_t + insert(InputIterator first, InputIterator last) +#endif //CGAL_TRIANGULATION_2_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO + { + size_type n = Base::insert(first, last); + + mark_faces(); + + return n; + } + + //test version of insert function + +#ifndef CGAL_TRIANGULATION_2_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO + template < class InputIterator > + std::ptrdiff_t + insert2( InputIterator first, InputIterator last, + typename boost::enable_if< + boost::is_base_of< + Point, + typename std::iterator_traits::value_type + > + >::type* = NULL + ) +#else + template < class InputIterator > + std::ptrdiff_t + insert_2(InputIterator first, InputIterator last) +#endif //CGAL_TRIANGULATION_2_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO + { + size_type n = this->number_of_vertices(); + + spatial_sort(first, last, geom_traits()); + Face_handle f; + while(first != last) { + f = insert (*first++, f)->face(); + } + + return this->number_of_vertices() - n; + } + + bool is_infinite(Vertex_handle v) const + { + return Base::is_infinite(v); + } + + bool is_infinite(Face_handle f) const + { + return has_infinite_vertex(f) || is_finite_invisible(f); + } + + bool is_infinite(Face_handle f, int i) const + { + return has_infinite_vertex(f, i) || is_finite_invisible(f, i); + } + + bool is_infinite(const Edge& e) const + { + return is_infinite(e.first, e.second); + } + + bool is_infinite(const Edge_circulator& ec) const + { + return is_infinite(*ec); + } + + bool is_infinite(const All_edges_iterator& ei) const + { + return is_infinite(*ei); + } + +private: + + bool has_infinite_vertex(Face_handle f) const + { + return Base::is_infinite(f); + } + + bool has_infinite_vertex(Face_handle f, int i) const + { + return Base::is_infinite(f, i); + } + + bool has_infinite_vertex(const Edge& e) const + { + return Base::is_infinite(e); + } + + int get_finite_invisible_edge(Face_handle f) const + { + assert(is_finite_invisible(f)); + + return f->info().get_invisible_edge(); + } + + bool is_finite_invisible(Face_handle f) const + { + return f->info().is_finite_invisible(); + } + + bool is_finite_invisible(Face_handle f, int i) const + { + if(this->dimension() <= 1) { + return false; + } + + if(is_finite_invisible(f) && get_finite_invisible_edge(f) == i) { + return true; + } + + // another incident face and corresponding index + Face_handle f2 = f->neighbor(i); + int i2 = f2->index(f); + + if(is_finite_invisible(f2) && get_finite_invisible_edge(f2) == i2) { + return true; + } + + return false; + } + + bool is_finite_invisible(const Edge& e) const + { + return is_finite_invisible(e.first, e.second); + } + + // Depth-first search (dfs) and marking the finite invisible faces. + void mark_faces() const + { + if(this->dimension() <= 1) return; + + std::set visited_faces; + + // maintain a stack to be able to backtrack + // to the most recent faces which neighbors are not visited + std::stack backtrack; + + // start from a face with infinite vertex + Face_handle current = Base::infinite_face(); + + // mark it as visited + visited_faces.insert(current); + + // put the element whose neighbors we are going to explore. + backtrack.push(current); + + // test whether a face is finite invisible or not + Mark_face test(*this); + + Face_handle next; + Face_info face_info; + + while(!backtrack.empty()) { + // take a face + current = backtrack.top(); + + // start visiting the neighbors + int i = 0; + for(; i < 3; i++) { + next = current->neighbor(i); + + // if a neighbor is already visited, then stop going deeper + if(visited_faces.find(next) != visited_faces.end()) { + continue; + } + + visited_faces.insert(next); + mark_face(next, test); + + // go deeper if the neighbor is infinite + if(is_infinite(next)) { + backtrack.push(next); + break; + } + } + + // if all the neighbors are already visited, then remove "current" face. + if(i == 3) { + backtrack.pop(); + } + } + + } + + // check if a star is bounded by finite faces + // TODO: rename this function name + bool is_star_bounded(Vertex_handle v) const + { + if(this->dimension() <= 1) { + return true; + } + + Face_handle f = v->face(); + Face_handle next; + int i; + Face_handle start(f); + + Face_handle opposite_face; + + do { + i = f->index(v); + next = f->neighbor(ccw(i)); // turn ccw around v + + opposite_face = f->neighbor(i); + if(this->is_infinite(opposite_face)) { + return false; + } + + f = next; + } while(next != start); + + return true; + } + + //use the function: insert_and_give_new_faces? + + void mark_star_faces(Vertex_handle v) const + { + // TODO: think of it + if(this->dimension() <= 1) return; + + Mark_face test(*this); + + Face_handle f = v->face(); + Face_handle start(f), next; + int i; + do { + i = f->index(v); + next = f->neighbor(ccw(i)); // turn ccw around v + + mark_face(f, test); + + f = next; + } while(next != start); + return; + } + + template + void mark_face(const Face_handle& f, const Mark_face_test& test) const + { + f->info() = test(f); + } + + void mark_face(const Face_handle& f) const + { + Mark_face test(*this); + mark_face(f, test); + } + + class Mark_face + { + public: + Mark_face(const Self& tr) : + _tr(tr) + {} + + Face_info operator ()(const Face_handle& f) const + { + typedef typename Gt::Is_hyperbolic Is_hyperbolic; + + Face_info info; + if(_tr.has_infinite_vertex(f)) { + return info; + } + + Point p0 = f->vertex(0)->point(); + Point p1 = f->vertex(1)->point(); + Point p2 = f->vertex(2)->point(); + int ind = 0; + + Is_hyperbolic is_hyperbolic = _tr.geom_traits().Is_hyperbolic_object(); + if(is_hyperbolic(p0, p1, p2, ind) == false) { + + info.set_finite_invisible(true); + info.set_invisible_edge(ind); + + return info; + } + + return info; + } + + private: + + Mark_face(const Mark_face&); + Mark_face& operator= (const Mark_face&); + + const Self& _tr; + }; + +public: + // This class is used to generate the Finite_*_iterators. + class Infinite_hyperbolic_tester + { + const Self *t; + public: + Infinite_hyperbolic_tester() {} + Infinite_hyperbolic_tester(const Self *tr) : t(tr) {} + + bool operator()(const All_vertices_iterator & vit) const { + return t->is_infinite(vit); + } + bool operator()(const All_faces_iterator & fit) const { + return t->is_infinite(fit); + } + bool operator()(const All_edges_iterator & eit ) const { + return t->is_infinite(eit); + } + }; + + Infinite_hyperbolic_tester + infinite_hyperbolic_tester() const + { + return Infinite_hyperbolic_tester(this); + } + + //Finite faces iterator + + class Finite_faces_iterator + : public Filter_iterator + { + typedef Filter_iterator Base; + typedef Finite_faces_iterator Self; + public: + Finite_faces_iterator() : Base() {} + Finite_faces_iterator(const Base &b) : Base(b) {} + Self & operator++() { Base::operator++(); return *this; } + Self & operator--() { Base::operator--(); return *this; } + Self operator++(int) { Self tmp(*this); ++(*this); return tmp; } + Self operator--(int) { Self tmp(*this); --(*this); return tmp; } + operator const Face_handle() const { return Base::base(); } + }; + + Finite_faces_iterator + finite_faces_begin() const + { + if ( this->dimension() < 2 ) + return finite_faces_end(); + return CGAL::filter_iterator(this->all_faces_end(), + Infinite_hyperbolic_tester(this), + this->all_faces_begin() ); + } + + Finite_faces_iterator + finite_faces_end() const + { + return CGAL::filter_iterator(this->all_faces_end(), + Infinite_hyperbolic_tester(this) ); + } + + //Finite edges iterator + + typedef Filter_iterator Finite_edges_iterator; + + Finite_edges_iterator + finite_edges_begin() const + { + if ( this->dimension() < 1 ) + return finite_edges_end(); + return CGAL::filter_iterator(this->all_edges_end(), + infinite_hyperbolic_tester(), + this->all_edges_begin()); + } + + Finite_edges_iterator + finite_edges_end() const + { + return CGAL::filter_iterator(this->all_edges_end(), + infinite_hyperbolic_tester() ); + } + + using Base::dual; + + Object + dual(const Finite_edges_iterator& ei) const + { + return this->dual(*ei); + } + + Object + dual(const Edge &e) const + { + CGAL_triangulation_precondition (!this->is_infinite(e)); + + if(this->dimension() == 1) { + const Point& p = (e.first)->vertex(cw(e.second))->point(); + const Point& q = (e.first)->vertex(ccw(e.second))->point(); + + // hyperbolic line + Segment line = this->geom_traits().construct_hyperbolic_bisector_2_object()(p,q); + return make_object(line); + } + + // incident faces + Face_handle f1 = e.first; + int i1 = e.second; + + Face_handle f2 = f1->neighbor(i1); + int i2 = f2->index(f1); + + // boths faces are infinite, but the incident edge is finite + if(is_infinite(f1) && is_infinite(f2)){ + const Point& p = (f1)->vertex(cw(i1))->point(); + const Point& q = (f1)->vertex(ccw(i1))->point(); + + // hyperbolic line + Segment line = this->geom_traits().construct_hyperbolic_bisector_2_object()(p,q); + return make_object(line); + } + + // both faces are finite + if(!is_infinite(f1) && !is_infinite(f2)) { + + Segment s = this->geom_traits().construct_segment_2_object()(dual(f1),dual(f2)); + + return make_object(s); + } + + // one of the incident faces is infinite + Face_handle finite_face = f1; + int i = i1; + + if(is_infinite(f1)) { + finite_face = f2; + i = i2; + } + + const Point& p = finite_face->vertex(cw(i))->point(); + const Point& q = finite_face->vertex(ccw(i))->point(); + + // ToDo: Line or Segment? + // hyperbolic line and ray + Segment line = this->geom_traits().construct_hyperbolic_bisector_2_object()(p,q); + Segment ray = this->geom_traits().construct_ray_2_object()(dual(finite_face), line); + return make_object(ray); + } +}; + +} //namespace CGAL + +#endif // CGAL_DELAUNAY_HYPERBOLIC_TRIANGULATION_2_H diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_offset_2.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_offset_2.h new file mode 100644 index 00000000000..5d18e629c49 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_offset_2.h @@ -0,0 +1,182 @@ +// Copyright (c) 1997-2013 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Nico Kruithof + +#ifndef CGAL_PERIODIC_4_HYPERBOLIC_OFFSET_2_H +#define CGAL_PERIODIC_4_HYPERBOLIC_OFFSET_2_H + +#include +#include +#include + +namespace CGAL +{ + +/// The class Periodic_4_hyperbolic_offset_2 is a model of the concept Periodic_2Offset_2. +class Periodic_4_hyperbolic_offset_2 +{ + // template + // friend std::ostream & operator<<(std::ostream &os, + // const Periodic_4_hyperbolic_offset_2 &off); + +public: + /// Default constructor. + Periodic_4_hyperbolic_offset_2() : _offx(0), _offy(0) {} + /// Constructs the offset (x,y). + Periodic_4_hyperbolic_offset_2(int x, int y) : _offx(x), _offy(y) {} + + /// Returns true if o is equal to (0,0). + inline bool is_null() const + { + return is_zero(); + } + /// Returns true if o is equal to (0,0). + inline bool is_zero() const + { + return ((_offx | _offy) == 0); + } + + /// Return the x-entry of o. + int& x() + { + return _offx; + } + /// Return the x-entry of o. + int x() const + { + return _offx; + } + /// Return the y-entry of o. + int& y() + { + return _offy; + } + /// Return the y-entry of o. + int y() const + { + return _offy; + } + + /// Return the i-th entry of o. + int &operator[](int i) + { + if (i == 0) return _offx; + CGAL_triangulation_assertion(i == 1); + return _offy; + } + /// Return the i-th entry of o. + int operator[](int i) const + { + if (i == 0) return _offx; + CGAL_triangulation_assertion(i == 1); + return _offy; + } + /// Add o' to o using vector addition. + void operator+=(const Periodic_4_hyperbolic_offset_2 &other) + { + _offx += other._offx; + _offy += other._offy; + } + /// Subtract o' from o using vector subtraction. + void operator-=(const Periodic_4_hyperbolic_offset_2 &other) + { + _offx -= other._offx; + _offy -= other._offy; + } + /// Return the negative vector of o. + Periodic_4_hyperbolic_offset_2 operator-() const + { + return Periodic_4_hyperbolic_offset_2(-_offx, -_offy); + } + /// Return true if o' and o represent the same vector. + bool operator==(const Periodic_4_hyperbolic_offset_2 &other) const + { + return ((_offx == other._offx) && + (_offy == other._offy)); + } + /// Return true if o' and o do not represent the same vector. + bool operator!=(const Periodic_4_hyperbolic_offset_2 &other) const + { + return ((_offx != other._offx) || + (_offy != other._offy)); + } + /// Compare o and o' lexicographically. + bool operator<(const Periodic_4_hyperbolic_offset_2 &other) const + { + if (_offx != other._offx) + return (_offx < other._offx); + else + { + return (_offy < other._offy); + } + } + + /// Return the vector sum of o and o'. + Periodic_4_hyperbolic_offset_2 operator+(const Periodic_4_hyperbolic_offset_2 &off2) const + { + return Periodic_4_hyperbolic_offset_2(_offx + off2.x(), _offy + off2.y()); + } + /// Return the vector difference of o and o'. + Periodic_4_hyperbolic_offset_2 operator-(const Periodic_4_hyperbolic_offset_2 &off2) const + { + return Periodic_4_hyperbolic_offset_2(_offx - off2.x(), _offy - off2.y()); + } + +private: + int _offx, _offy; +}; + +template +inline typename K::Point_2 operator+(const typename K::Point_2 &p, const Periodic_4_hyperbolic_offset_2 &off) +{ + return (off.is_null() ? p : typename K::Point_2(p.x() + off.x(), p.y() + off.y())); +} + +/// Inputs an Periodic_4_hyperbolic_offset_2 from is. +inline std::ostream +&operator<<(std::ostream &os, const Periodic_4_hyperbolic_offset_2 &off) +{ + if (is_ascii(os)) + os << off.x() << " " << off.y(); + else + { + write(os, off.x()); + write(os, off.y()); + } + return os; +} + +/// Outputs an Periodic_4_hyperbolic_offset_2 to os. +inline std::istream +&operator>>(std::istream &is, Periodic_4_hyperbolic_offset_2 &off) +{ + int x = 0, y = 0; + if (is_ascii(is)) + is >> x >> y; + else + { + read(is, x); + read(is, y); + } + off = Periodic_4_hyperbolic_offset_2(x, y); + return is; +} + +} //namespace CGAL + +#endif // CGAL_PERIODIC_4_HYPERBOLIC_OFFSET_2_H diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_2.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_2.h new file mode 100644 index 00000000000..1cc35621cee --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_2.h @@ -0,0 +1,4856 @@ +// Copyright (c) 1997-2013 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Nico Kruithof + +#ifndef CGAL_PERIODIC_4_HYPERBOLIC_TRIANGULATION_2_H +#define CGAL_PERIODIC_4_HYPERBOLIC_TRIANGULATION_2_H + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace CGAL +{ + +/// Periodic triangulation class. +/// Its main functionality is: +/// - Insertion of points +/// - Deletion of points +/// - Point location +template < class Gt, + class Tds = Triangulation_data_structure_2 < + Periodic_2_triangulation_vertex_base_2, + Periodic_2_triangulation_face_base_2 > > +class Periodic_4_hyperbolic_triangulation_2: public Triangulation_cw_ccw_2 +{ + typedef Periodic_4_hyperbolic_triangulation_2 Self; + +public: + // Public types of Periodic_4_hyperbolic_triangulation_2 + /// The triangulation data structure type + typedef Tds Triangulation_data_structure; + /// The traits class + typedef Gt Geom_traits; + + /// The periodic offset type + typedef typename Gt::Periodic_2_offset_2 Offset; + /// The iso rectangle type + typedef typename Gt::Iso_rectangle_2 Iso_rectangle; + /// Integer tuple to store the number of sheets in each direction of space. + typedef array Covering_sheets; + + /// The point type + typedef typename Gt::Point_2 Point; + /// The segment type + typedef typename Gt::Segment_2 Segment; + /// The triangle type + typedef typename Gt::Triangle_2 Triangle; + + /// Represents a point-offset pair. The point in the pair lies in the original domain. + typedef std::pair Periodic_point; + /// A pair of periodic points representing a segment in the periodic domain. + typedef array, 2> Periodic_segment; + /// A triple of periodic points representing a triangle in the periodic domain. + typedef array, 3> Periodic_triangle; + + /// The vertex type + typedef typename Tds::Vertex Vertex; + /// The face type + typedef typename Tds::Face Face; + /// The edge type + typedef typename Tds::Edge Edge; + + /// Size type (an unsigned integral type) + typedef typename Tds::size_type size_type; + /// Difference type (a signed integral type) + typedef typename Tds::difference_type difference_type; + + /// Handle to a vertex + typedef typename Tds::Vertex_handle Vertex_handle; + /// Handle to a face + typedef typename Tds::Face_handle Face_handle; + + /// Iterator over the faces + typedef typename Tds::Face_iterator Face_iterator; + /// Iterator over the edges + typedef typename Tds::Edge_iterator Edge_iterator; + /// Iterator over the vertices + typedef typename Tds::Vertex_iterator Vertex_iterator; + /// Iterator over the vertices whose corresponding points lie in the + /// original domain, i.e. for each set of periodic copies the + /// Unique_vertex_iterator iterates over exactly one representative. + typedef Periodic_4_hyperbolic_triangulation_unique_vertex_iterator_2 + Unique_vertex_iterator; + + /// \name For compatibility with the Triangulation_2 class + // \{ + typedef Face_iterator Finite_faces_iterator; + typedef Edge_iterator Finite_edges_iterator; + typedef Vertex_iterator Finite_vertices_iterator; + typedef Face_iterator All_faces_iterator; + // \} + + /// Circulator over all faces incident to a vertex + typedef typename Tds::Face_circulator Face_circulator; + /// Circulator over all edges incident to a vertex + typedef typename Tds::Edge_circulator Edge_circulator; + /// Circulator over all vertices incident to a vertex + typedef typename Tds::Vertex_circulator Vertex_circulator; + + /// \name Periodic iterator types + //\{ + /// Iterator over all periodic triangles + typedef Periodic_4_hyperbolic_triangulation_triangle_iterator_2 + Periodic_triangle_iterator; + /// Iterator over all periodic segments + typedef Periodic_4_hyperbolic_triangulation_segment_iterator_2 + Periodic_segment_iterator; + /// Iterator over all periodic points + typedef Periodic_4_hyperbolic_triangulation_point_iterator_2 + Periodic_point_iterator; + //\} + + /// \name Enumeration types + //\{ + + /// Type determining how to iterate over the stored simplices in the triangulation + enum Iterator_type + { + STORED = 0, + UNIQUE, // 1 + STORED_COVER_DOMAIN, // 2 + UNIQUE_COVER_DOMAIN // 3 + };//3 + + /// Return type of a point location query + enum Locate_type + { + /// The query point lies on a vertex + VERTEX = 0, + /// The query point lies on an edge + EDGE, + /// The query point lies on a face + FACE, + /// The query point lies outside the affine hull of the triangulation, + /// which is the case when the triangulation is empty. + EMPTY + }; + //\} + + // Auxiliary iterators for convenience + // do not use default template argument to please VC++ + /// Functor that returns the point given a vertex + typedef Project_point Proj_point; + + /// \name STL types + // \{ + /// value_type similar to stl containers + typedef Point value_type; // to have a back_inserter + /// const_reference similar to stl containers + typedef const value_type& const_reference; + /// reference similar to stl containers + typedef value_type& reference; + // \} + + + /// Tag to distinguish Regular triangulations from others; + typedef Tag_false Weighted_tag; + +protected: + // Protected types of Periodic_4_hyperbolic_triangulation_2 + typedef typename Gt::Orientation_2 Orientation_2; + typedef typename Gt::Compare_x_2 Compare_x; + typedef typename Gt::Compare_y_2 Compare_y; + + + typedef typename Gt::FT FT; + typedef std::pair Virtual_vertex; + typedef std::map Virtual_vertex_map; + typedef typename Virtual_vertex_map::const_iterator Virtual_vertex_map_it; + + /// Vector is contains virtual copies with offset off: + /// virtual copy with offset off is stored at position: i=3*off[0]+off[1]-1 + typedef std::map > + Virtual_vertex_reverse_map; + typedef typename Virtual_vertex_reverse_map::const_iterator + Virtual_vertex_reverse_map_it; + typedef std::map > Too_long_edges_map; + typedef typename Too_long_edges_map::const_iterator Too_long_edges_map_it; + + /// \name Functors + // \{ + /// Functor for symbolically perturbing points + class Perturbation_order + { + const Self *t; + + public: + // Perturbation_order, public interface + Perturbation_order(const Self *tr) : + t(tr) + { + } + + bool operator()(const Point *p, const Point *q) const + { + return t->compare_xy(*p, *q) == SMALLER; + } + bool operator()(const Periodic_point *p, const Periodic_point *q) const + { + return t->compare_xy(p->first, q->first, p->second, q->second) == SMALLER; + } + }; + // \} + friend class Perturbation_order; + +private: + // Copy constructor helpers + class Finder; + void copy_multiple_covering(const Periodic_4_hyperbolic_triangulation_2 & tr); + +public: + // Public functions of Periodic_4_hyperbolic_triangulation_2 + /// \name Constructors + //\{ + /// Constructor + Periodic_4_hyperbolic_triangulation_2( + const Iso_rectangle &domain = Iso_rectangle(0, 0, 1, 1), + const Geom_traits &geom_traits = Geom_traits()); + + /// Copy constructor + Periodic_4_hyperbolic_triangulation_2(const Periodic_4_hyperbolic_triangulation_2 &tr); + /// Assignment + Periodic_4_hyperbolic_triangulation_2 &operator=(const Periodic_4_hyperbolic_triangulation_2 &tr); + + /// Copy the triangulation + void copy_triangulation(const Periodic_4_hyperbolic_triangulation_2 &tr); + /// Swap two triangulations + void swap(Periodic_4_hyperbolic_triangulation_2 &tr); + /// Clear the triangulation + void clear(); + + /// Serialize the triangulation to an output stream + std::ostream& save(std::ostream& os) const; + + /// Deserialize the triangulation from an input stream + std::istream& load(std::istream& is); + + //\} + + /// \name Access functions + //\{ + + /// Returns the geometric traits used for the predicates and constructions. + const Geom_traits& geom_traits() const + { + return _gt; + } + /// Returns the datastructure storing the triangulation. + const Triangulation_data_structure & tds() const + { + return _tds; + } + /// Returns the datastructure storing the triangulation. + Triangulation_data_structure & tds() + { + return _tds; + } + /// Returns the domain of the 1-sheeted cover. + const Iso_rectangle & domain() const + { + return _domain; + } + /// Returns the number of copies of the 1-sheeted cover stored in each of + /// the principal directions. + Covering_sheets number_of_sheets() const + { + return _cover; + } + /// Returns the dimension of the triangulation. + int dimension() const + { + return _tds.dimension() == 2 ? 2 : 0; + } + + //\} + + /// \name Number of simplices + //\{ + /// Returns whether the triangulation is empty. + bool empty() const + { + return _tds.dimension() < 2; + } + + /// Returns the number of vertices. Counts all vertices that are + /// representatives of the same point in the 1-cover as one vertex. + size_type number_of_vertices() const + { + if (is_1_cover()) + return _tds.number_of_vertices(); + else + return _tds.number_of_vertices() / 9; + } + + /// Returns the number of edges. Counts all edges that are + /// representatives of the same segment in the 1-cover as one edge. + size_type number_of_edges() const + { + if (is_1_cover()) + return _tds.number_of_edges(); + else + return _tds.number_of_edges() / 9; + } + /// Returns the number of faces. Counts all faces that are + /// representatives of the same triangle in the 1-cover as one face. + size_type number_of_faces() const + { + if (is_1_cover()) + return _tds.number_of_faces(); + else + return _tds.number_of_faces() / 9; + } + /// Returns the number of vertices stored in the datastructure. + size_type number_of_stored_vertices() const + { + return _tds.number_of_vertices(); + } + /// Returns the number of edges stored in the datastructure. + size_type number_of_stored_edges() const + { + return _tds.number_of_edges(); + } + /// Returns the number of faces stored in the datastructure. + size_type number_of_stored_faces() const + { + return _tds.number_of_faces(); + } + //\} + + + /// \name Methods regarding the covering + /// \{ + + /// Checks whether the triangulation is a valid simplicial complex in the one cover. + /// Uses an edge-length-criterion. + bool is_extensible_triangulation_in_1_sheet_h1() const; + + /// Checks whether the triangulation is a valid simplicial complex in the one cover. + /// Uses a criterion based on the maximal radius of the circumscribing circle. + bool is_extensible_triangulation_in_1_sheet_h2() const; + + /// Checks whether the triangulation is a valid simplicial complex in the one cover. + bool is_triangulation_in_1_sheet() const; + + /// Convert a 9 sheeted cover (used for sparse triangulations) to a single sheeted cover. + /// \pre !is_1_cover(); + void convert_to_1_sheeted_covering(); + /// Convert a single sheeted cover (used for dense triangulations) to a 9 sheeted cover. + /// \pre is_1_cover(); + void convert_to_9_sheeted_covering(); + // \} + + /// \name Geometric access functions + // \{ + + /// Returns the periodic point given by vertex v. If t is + /// represented in the 1-sheeted covering space, the offset is + /// always zero. Otherwise v can correspond to a periodic copy + /// outside domain of an input point. + Periodic_point periodic_point(const Vertex_handle &v) const + { + return Periodic_point(v->point(), get_offset(v)); + } + + /// If t is represented in the 1-sheeted covering space, this + /// function returns the periodic point given by the i-th vertex of + /// face f, that is the point in the original domain and the offset + /// of the vertex in f. If t is represented in the 9-sheeted + /// covering space, this offset is possibly added to another offset + /// determining the periodic copy. + /// \pre i == {0,1,2} + Periodic_point periodic_point(const Face_handle &f, int i) const + { + return Periodic_point(f->vertex(i)->point(), get_offset(f, i)); + } + + /// Returns the periodic segment formed by the two point-offset + /// pairs corresponding to the two vertices of edge (f,i). + /// \pre i == {0,1,2} + Periodic_segment periodic_segment(const Face_handle &f, int i) const + { + CGAL_triangulation_precondition( number_of_vertices() != 0 ); + CGAL_triangulation_precondition( i >= 0 && i <= 2); + return make_array(periodic_point(f, ccw(i)), + periodic_point(f, cw(i))); + } + + /// Same as the previous method for edge e. + Periodic_segment periodic_segment(const Edge &e) const + { + return periodic_segment(e.first, e.second); + } + + /// Returns the periodic triangle formed by the three point-offset + /// pairs corresponding to the three vertices of facet f. + Periodic_triangle periodic_triangle(const Face_handle &f) const + { + return make_array(periodic_point(f, 0), + periodic_point(f, 1), + periodic_point(f, 2)); + } + + /// Converts the Periodic_point pp (point-offset pair) to the corresponding + /// Point in \f$R^2\f$. + Point point(const Periodic_point & pp) const + { + return construct_point(pp.first, pp.second); + } + Point point(const Vertex_handle &v) const + { + return point(periodic_point(v)); + } + Point point(const Face_handle &fh, int i) const + { + return point(periodic_point(fh, i)); + } + /// Converts the Periodic_segment ps to a Segment in \f$R^2\f$. + Segment segment(const Periodic_segment &ps) const + { + return construct_segment(ps[0].first, ps[1].first, ps[0].second, ps[1].second); + } + /// Converts the Periodic_triangle pt to a Triagle in \f$R^2\f$. + Triangle triangle(const Periodic_triangle &pt) const + { + Triangle triang = construct_triangle(pt[0].first, pt[1].first, pt[2].first, + pt[0].second, pt[1].second, pt[2].second); + return triang; + } + + /// Constructs the segment associated with the edge (f,i), respects the offset + Segment segment(Face_handle f, int i) const + { + return segment(periodic_segment(f, i)); + } + /// Constructs the segment associated with the edge e, respects the offset + Segment segment(const Edge& e) const + { + return segment(periodic_segment(e)); + } + /// Constructs the segment associated with the edge ec, respects the offset + Segment segment(const Edge_circulator& ec) const + { + return segment(periodic_segment(ec->first, ec->second)); + } + /// Constructs the segment associated with the edge ei, respects the offset + Segment segment(const Edge_iterator& ei) const + { + return segment(periodic_segment(ei->first, ei->second)); + } + + /// Constructs the triangle associated with the face f, respects the offset + Triangle triangle(Face_handle f) const + { + return triangle(periodic_triangle(f)); + } + //\} + + Point move_in_domain(const Point &p) + { + typename Gt::FT x = p.x(); + typename Gt::FT y = p.y(); + + while (x < _domain.xmin()) x += _domain.xmax() - _domain.xmin(); + while (x >= _domain.xmax()) x -= _domain.xmax() - _domain.xmin(); + + while (y < _domain.ymin()) y += _domain.ymax() - _domain.ymin(); + while (y >= _domain.ymax()) y -= _domain.ymax() - _domain.ymin(); + + return Point(x, y); + } + + /// \name Queries on simplices + // \{ + bool is_edge(Vertex_handle va, Vertex_handle vb) const + { + return _tds.is_edge(va, vb); + } + bool is_edge(Vertex_handle va, Vertex_handle vb, Face_handle& fr, int & i) const + { + return _tds.is_edge(va, vb, fr, i); + } + bool is_face(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3) const + { + return _tds.is_face(v1, v2, v3); + } + bool is_face(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3, + Face_handle &fr) const + { + return _tds.is_face(v1, v2, v3, fr); + } + // \} + + /// \name Queries + // \{ + + /// Wrapper function for locate if only the requested point is given. + Face_handle locate(const Point &p, Face_handle start = Face_handle()) const + { + Locate_type lt; + int li; + return locate(p, Offset(), lt, li, start); + } + + /// Wrapper function for locate if the offset is omitted. + Face_handle locate(const Point& p, Locate_type& lt, int& li, + Face_handle start = Face_handle()) const + { + return locate(p, Offset(), lt, li, start); + } + + /// Returns the oriented side of the point p with respect to the + /// triangle defined by the face f + Oriented_side oriented_side(Face_handle f, const Point& p) const + { + return oriented_side(f, p, Offset()); + } + + // \} + + + /// \name Traversal of the Triangulation + // \{ + /// Iterator over all stored vertices. Starts at an arbitrary vertex. + /// Returns vertices_end() if t.number_of_vertices()=0. + Vertex_iterator vertices_begin() const + { + return _tds.vertices_begin(); + } + /// Past the end Vertex_iterator. + Vertex_iterator vertices_end() const + { + return _tds.vertices_end(); + } + /// Iterator over all stored edges. Starts at an arbitrary edge. + /// Returns edges_end() if t.number_of_vertices()=0. + Edge_iterator edges_begin() const + { + return _tds.edges_begin(); + } + /// Past the end Edge_iterator. + Edge_iterator edges_end() const + { + return _tds.edges_end(); + } + /// Iterator over all stored faces. Starts at an arbitrary face. + /// Returns faces_end() if t.number_of_vertices()=0. + Face_iterator faces_begin() const + { + return _tds.faces_begin(); + } + /// Past the end Face_iterator. + Face_iterator faces_end() const + { + return _tds.faces_end(); + } + + /// Iterator over all stored vertices. Starts at an arbitrary vertex. + /// Returns vertices_end() if t.number_of_vertices()=0. + Vertex_iterator finite_vertices_begin() const + { + return _tds.vertices_begin(); + } + /// Past the end Vertex_iterator. + Vertex_iterator finite_vertices_end() const + { + return _tds.vertices_end(); + } + /// Iterator over all stored edges. Starts at an arbitrary edge. + /// Returns edges_end() if t.number_of_vertices()=0. + Edge_iterator finite_edges_begin() const + { + return _tds.edges_begin(); + } + /// Past the end Edge_iterator. + Edge_iterator finite_edges_end() const + { + return _tds.edges_end(); + } + /// Iterator over all stored faces. Starts at an arbitrary face. + /// Returns faces_end() if t.number_of_vertices()=0. + Face_iterator finite_faces_begin() const + { + return _tds.faces_begin(); + } + /// Past the end Face_iterator. + Face_iterator finite_faces_end() const + { + return _tds.faces_end(); + } + + /// Iterator over all stored vertices. Starts at an arbitrary vertex. + /// Returns vertices_end() if t.number_of_vertices()=0. + Vertex_iterator all_vertices_begin() const + { + return _tds.vertices_begin(); + } + /// Past the end Vertex_iterator. + Vertex_iterator all_vertices_end() const + { + return _tds.vertices_end(); + } + /// Iterator over all stored edges. Starts at an arbitrary edge. + /// Returns edges_end() if t.number_of_vertices()=0. + Edge_iterator all_edges_begin() const + { + return _tds.edges_begin(); + } + /// Past the end Edge_iterator. + Edge_iterator all_edges_end() const + { + return _tds.edges_end(); + } + /// Iterator over all stored faces. Starts at an arbitrary face. + /// Returns faces_end() if t.number_of_vertices()=0. + Face_iterator all_faces_begin() const + { + return _tds.faces_begin(); + } + /// Past the end Face_iterator. + Face_iterator all_faces_end() const + { + return _tds.faces_end(); + } + + /// begin iterator over the non-virtual vertices + Unique_vertex_iterator unique_vertices_begin() const + { + return CGAL::filter_iterator(vertices_end(), + Periodic_4_hyperbolic_triangulation_2_internal::Domain_tester(this), + vertices_begin()); + } + /// past-the-end iterator over the non-virtual vertices + Unique_vertex_iterator unique_vertices_end() const + { + return CGAL::filter_iterator(vertices_end(), + Periodic_4_hyperbolic_triangulation_2_internal::Domain_tester(this)); + } + + // \} + /// \name Geometric iterators + //\{ + + /// Start iterator over the points + Periodic_point_iterator periodic_points_begin(Iterator_type it = STORED) const + { + return Periodic_point_iterator(this, it); + } + /// Past-the-end iterator over the points + Periodic_point_iterator periodic_points_end(Iterator_type it = STORED) const + { + return Periodic_point_iterator(this, 1, it); + } + + /// Start iterator over the segments + Periodic_segment_iterator periodic_segments_begin(Iterator_type it = STORED) const + { + return Periodic_segment_iterator(this, it); + } + /// Past-the-end iterator over the segments + Periodic_segment_iterator periodic_segments_end(Iterator_type it = STORED) const + { + return Periodic_segment_iterator(this, 1, it); + } + + /// Start iterator over the triangles + Periodic_triangle_iterator periodic_triangles_begin(Iterator_type it = STORED) const + { + return Periodic_triangle_iterator(this, it); + } + /// Past-the-end iterator over the triangles + Periodic_triangle_iterator periodic_triangles_end(Iterator_type it = STORED) const + { + return Periodic_triangle_iterator(this, 1, it); + } + //\} + + /// \name Incident simplices + // \{ + + Face_circulator incident_faces(Vertex_handle v, Face_handle f = Face_handle()) const + { + return _tds.incident_faces(v, f); + } + Edge_circulator incident_edges(Vertex_handle v, Face_handle f = Face_handle()) const + { + return _tds.incident_edges(v, f); + } +/* Vertex_circulator incident_vertices(Vertex_handle v, Face_handle f = */ +/* Face_handle()) const */ +/* { */ +/* bool DEPRECATED_USE_ADJACENT_VERTICES; */ +/* return adjacent_vertices(v, f); */ +/* } */ + Vertex_circulator adjacent_vertices(Vertex_handle v, Face_handle f = + Face_handle()) const + { + return _tds.incident_vertices(v, f); + } + // \} + + /// \name Traversal between adjacent faces + // \{ + + Vertex_handle mirror_vertex(Face_handle f, int i) const + { + return _tds.mirror_vertex(f, i); + } + int mirror_index(Face_handle f, int i) const + { + return _tds.mirror_index(f, i); + } + //\} + + + /// \name Modifiers + // \{ + + /// Flips the edge and all periodic copies + void flip(Face_handle f, int i); + + /// Inserts a point in the triangulation + /// \param p the point to be inserted + /// \param start the start face for point location + /// \return The new vertex handle or an existing Vertex_handle if p was inserted before + Vertex_handle insert(const Point &p, Face_handle start = Face_handle()); + + /// Inserts a point in the triangulation + /// \pre The point has been located in the triangulation + Vertex_handle insert(const Point& p, Locate_type lt, Face_handle loc, int li); + + /// Insert a point in the triangulation + Vertex_handle push_back(const Point& p) + { + return insert(p); + } + + // \} + + /// \name Advanced modifiers + //\{ + + /// Insert the first vertex in the triangulation and creates the 9-cover. + Vertex_handle insert_first(const Point& p); + /// Inserts p in the face f and sets the offsets of the newly created faces + /// Insert periodic copies in all periodic copies of the domain + Vertex_handle insert_in_face(const Point& p, Face_handle f); + /// Inserts (p,o) in the edge (f,i) and sets the offsets of the newly created faces + /// Insert periodic copies in all periodic copies of the domain + Vertex_handle insert_in_edge(const Point& p, Face_handle f, int i); + + /// Remove a degree 3 vertex from a 2D triangulation + void remove_degree_3(Vertex_handle v); + + bool remove_degree_init(Vertex_handle v, const Offset &v_o, + std::vector &f, + std::vector &w, std::vector &offset_w, + std::vector &i, int &d, int &maxd, bool &simplicity_criterion); + + /// Remove a vertex from a 2D triangulation with number_of_vertices() == 1 + void remove_first(Vertex_handle v); + + /// Changes the domain. Note that this function calls clear(), i.e., + /// it erases the existing triangulation. + void set_domain(const Iso_rectangle &domain) + { + clear(); + _domain = domain; + _gt.set_domain(_domain); + _edge_length_threshold = + FT(0.166) * (_domain.xmax() - _domain.xmin()) * (_domain.xmax() - _domain.xmin()); + } + //\} + + + /// \name Point location + + /// Do a remembering heuristic walk to locate point (p,o) + Face_handle + march_locate_2D(Face_handle f, const Point& p, const Offset& o, + Locate_type& lt, int& li) const; + + /// Checks whether the result of two point location queries are equivalent. + bool + compare_walks(const Point& p, Face_handle c1, Face_handle c2, + Locate_type& lt1, Locate_type& lt2, int li1, int li2) const; + + /// Testing where the point (p,off) lies w.r.t. the face f + Bounded_side side_of_face(const Point &p, const Offset &off, Face_handle f, + Locate_type <, int &li) const; + /// Testing where the point (p,off) lies w.r.t. the face f + Bounded_side side_of_face(const Point &p, Face_handle f, Locate_type <, + int &li) const + { + return side_of_face(p, Offset(), f, lt, li); + } + //\} + + /// \name Predicates and Constructions + //\{ + /// Determines whether the point p lies on the (un-)bounded side of + /// the triangle (p0,p1,p2) + Bounded_side + bounded_side(const Point &p0, const Point &p1, const Point &p2, const Point &p) const; + + /// Determines whether the point (p,o) lies on the (un-)bounded side of + /// the triangle ((p0,o0),(p1,o1),(p2,o2)) + Bounded_side + bounded_side(const Point &p0, const Point &p1, const Point &p2, const Point &p, + const Offset &o0, const Offset &o1, const Offset &o2, const Offset &o) const; + + /// Determines whether the point q lies strictly between the points p and r + /// p,q and r are supposed to be collinear points + bool + collinear_between(const Point& p, const Point& q, const Point& r) const; + + /// Determines whether the point (q,o_q) lies strictly between the points (p,o_p) and (r,o_r) + /// (q,o_q), (p,o_p) and (r,o_r) are supposed to be collinear points + bool + collinear_between(const Point& p, const Point& q, const Point& r, + const Offset& o_p, const Offset& o_q, const Offset& o_r) const; + + /// Compares the x-coordinates of p and q + Comparison_result compare_x(const Point& p, const Point& q) const; + /// Compares the x-coordinates of (p,o_p) and (q,o_q) + Comparison_result compare_x(const Point& p, const Point& q, + const Offset &o_p, const Offset &o_q) const; + + /// Compares p and q lexicographically + Comparison_result compare_xy(const Point& p, const Point& q, + const Offset &o_p, const Offset &o_q) const; + /// Compares (p,o_p) and (q,o_q) lexicographically + Comparison_result compare_xy(const Point& p, const Point& q) const; + /// Compares the x-coordinates of p and q + Comparison_result compare_y(const Point& p, const Point& q) const; + /// Compares the x-coordinates of (p,o_p) and (q,o_q) + Comparison_result compare_y(const Point& p, const Point& q, + const Offset &o_p, const Offset &o_q) const; + /// Checks for equality of p and q + bool xy_equal(const Point& p, const Point& q) const; + /// Returns the orientation of p1,p2,p3 + Orientation orientation(const Point& p1, const Point& p2, const Point& p3) const; + /// Returns the orientation of (p1,o1), (p2,o2), (p3,o3) + Orientation orientation(const Point& p1, const Point& p2, const Point& p3, + const Offset& o1, const Offset& o2, const Offset& o3) const; + + /// Determines whether the point p lies on the (un-)bounded side of + /// the circle through the vertices of f + Oriented_side + side_of_oriented_circle(Face_handle f, + const Point & p, bool perturb = false) const; + /// Determines whether the point p lies on the (un-)bounded side of + /// the circle through the points p0, p1 and p2 + Oriented_side + side_of_oriented_circle(const Point &p0, const Point &p1, const Point &p2, + const Point &p, bool perturb) const; + /// Determines whether the point (p,o) lies on the (un-)bounded side of + /// the circle through the points (p0,o0), (p1,o1) and (p2,o2) + Oriented_side + side_of_oriented_circle(const Point &p0, const Point &p1, const Point &p2, + const Point &p, const Offset &o0, const Offset &o1, const Offset &o2, + const Offset &o, bool perturb) const; + + + + /// Constructs the circumcenter of the face f, respects the offset + Point circumcenter(Face_handle f) const + { + return construct_circumcenter(f->vertex(0)->point(), + f->vertex(1)->point(), + f->vertex(2)->point(), + get_offset(f, 0), + get_offset(f, 1), + get_offset(f, 2)); + } + Point construct_circumcenter(const Point &p1, const Point &p2, const Point &p3, + const Offset &o1, const Offset &o2, const Offset &o3) const + { + return geom_traits().construct_circumcenter_2_object()(p1, p2, p3, o1, o2, o3); + } + //\} + + + /// \name Miscellaneous + //\{ + + /// Returns whether the union of the faces f and f->neighbor(i) form + /// a convex quadrilateral. + bool flippable(Face_handle f, int i); + + size_type degree(Vertex_handle v) const + { + return _tds.degree(v); + } + + /// Checks if the triangulation is valid. + bool is_valid(bool verbose = false, int level = 0) const; + /// Checks if the face is valid. + bool is_valid(Face_handle fh, bool verbose = false, int level = 0) const; + + //\} + + + /// \name Undocumented functions, needed by the geometric iterators + // \{ + /// [Undoc] Returns whether the stored triangulation covers a 1-cover. + bool is_1_cover() const + { + return (_cover[0] == 1) && (_cover[1] == 1); + } + + /// [Undoc] Combines two offsets, where the first offset is defined by the + /// virtual vertex and the second by the face. + Offset combine_offsets(const Offset& o_c, const Offset& o_t) const + { + Offset o_ct(_cover[0] * o_t.x(), _cover[1] * o_t.y()); + return o_c + o_ct; + } + /// [Undoc] Returns the offset of nb==ch->neighbor(i) with respect to ch. + /// Get the offset between the origins of the internal offset coordinate + /// systems of two neighboring faces with respect from ch to nb. + /// + /// - Find two corresponding vertices from each face + /// - Return the difference of their offsets. + /// + Offset get_neighbor_offset(Face_handle fh, int i) const + { + Face_handle nb = fh->neighbor(i); + return get_neighbor_offset(fh, i, nb, nb->index(fh)); + } + /// [Undoc] Returns the offset of nb==ch->neighbor(i) with respect to ch. + /// Get the offset between the origins of the internal offset coordinate + /// systems of two neighboring faces with respect from ch to nb. + /// + /// - Find two corresponding vertices from each face + /// - Return the difference of their offsets. + /// + Offset get_neighbor_offset(Face_handle fh, int i, Face_handle nb, int j) const + { + // Redundance in the signature + CGAL_triangulation_precondition(fh->neighbor(i) == nb); + CGAL_triangulation_precondition(nb->neighbor(j) == fh); + CGAL_triangulation_precondition(fh->vertex(cw(i)) == nb->vertex(ccw(j))); + + return int_to_off(nb->offset(ccw(j))) - int_to_off(fh->offset(cw(i))); + } + /// [Undoc] returns the combined offset of the vertex + /// (if we are not on the 1-cover) and the offset defined by the face. + Offset get_offset(Face_handle f, int i) const + { + if (is_1_cover()) + return int_to_off(f->offset(i)); + + Virtual_vertex_map_it it = _virtual_vertices.find(f->vertex(i)); + if (it != _virtual_vertices.end()) + return combine_offsets(it->second.second, int_to_off(f->offset(i))); + else + return combine_offsets(Offset(), int_to_off(f->offset(i))); + } + /// [Undoc] Returns the offset of the vertex if we are not on the 1-cover. + Offset get_offset(Vertex_handle vh) const + { + if (is_1_cover()) + return Offset(); + Virtual_vertex_map_it it = _virtual_vertices.find(vh); + if (it != _virtual_vertices.end()) + return it->second.second; + else + return Offset(); + } + + /// Converts an offset to a bit pattern where bit1==offx and bit0==offy. + int off_to_int(const Offset & off) const + { + CGAL_triangulation_assertion( off.x() == 0 || off.x() == 1 ); + CGAL_triangulation_assertion( off.y() == 0 || off.y() == 1 ); + int i = ((off.x() & 1) << 1) + (off.y() & 1); + return i; + } + /// Creates an offset from a bit pattern. + Offset int_to_off(int i) const + { + return Offset((i >> 1) & 1, i & 1); + } + + // \} + // Protected functions of Periodic_4_hyperbolic_triangulation_2 + /// Const accessor to the virtual vertices reverse map, + /// used to optimize point location for periodic copies. + const Virtual_vertex_reverse_map &virtual_vertices_reverse() const + { + return _virtual_vertices_reverse; + } + + /// [Undoc] Returns the non-virtual copy of the vertex. + Vertex_handle get_original_vertex(Vertex_handle vh) const + { + if (is_1_cover()) + return vh; + Virtual_vertex_map_it it = _virtual_vertices.find(vh); + if (it != _virtual_vertices.end()) + return it->second.first; + else + return vh; + } + + + /// Tests whether a vertex is a periodic copy of a vertex in the 3-cover. + bool is_virtual(Vertex_handle v) + { + if (is_1_cover()) + return false; + return (_virtual_vertices.find(v) != _virtual_vertices.end()); + } + + const std::vector& periodic_copies(const Vertex_handle v) const + { + CGAL_triangulation_precondition(number_of_sheets() != make_array(1, 1) ); + CGAL_triangulation_precondition(_virtual_vertices.find(v) == _virtual_vertices.end()); + CGAL_triangulation_assertion(_virtual_vertices_reverse.find(v) != _virtual_vertices_reverse.end()); + return _virtual_vertices_reverse.find(v)->second; + } + + template + Stream& draw_triangulation(Stream& os) const + { + Edge_iterator it = edges_begin(); + for (; it != edges_end(); ++it) + { + os << segment(it); + } + return os; + } +protected: + std::vector insert_dummy_points(); + + + inline void try_to_convert_to_one_cover() + { + // Fall back to 1-cover if the criterion that the longest edge is shorter + // than sqrt(0.166) is fulfilled. + if (_too_long_edge_counter == 0 && !is_1_cover()) + { + CGAL_triangulation_expensive_assertion( is_valid() ); + this->convert_to_1_sheeted_covering(); + CGAL_triangulation_expensive_assertion( is_valid() ); + } + } + +protected: + // Protected functions of Periodic_4_hyperbolic_triangulation_2 + + /// Inserts a point with an offset in the triangulation + /// \pre The point has been located in the triangulation + Vertex_handle insert(const Point& p, const Offset& o, Locate_type lt, + Face_handle loc, int li, Vertex_handle vh); + + /// \name Helper functions for queries + // \{ + + /// Locates the simplex containing the point represented by p and o. + /// + /// The type of the simplex is stored in lt. + /// The simplex containing the point is returned using lt and li. + /// The Face_handle start is the start point of the heuristic walk. + Face_handle + locate(const Point& p, const Offset &o, Locate_type& lt, int& li, + Face_handle start = Face_handle()) const; + /// Returns the oriented side of the point (p,o) with respect to the + /// triangle defined by the face f + Oriented_side + oriented_side(Face_handle f, const Point& p, const Offset &o) const; + // \} + + /// \name Insertion helpers + //\{ + /// Insert too long edges in the star of v + void insert_too_long_edges_in_star(Vertex_handle v); + + /// Insert too long edge + void insert_too_long_edge(Face_handle f, int i); + + /// Remove too long edges in the star of v + void remove_too_long_edges_in_star(Vertex_handle v); + + /// Removes an edge if it is too long + void remove_too_long_edge(Face_handle f, int i); + + /// Check whether an edge is too long + bool edge_is_too_long(const Point &p1, const Point &p2) const; + + /// Flips the edge, no periodic copies are flipped + void flip_single_edge(Face_handle f, int i); + + /// Remove a vertex from the virtual copies maps + /// Used when a Delaunay vertex is removed + void remove_from_virtual_copies(Vertex_handle v); + //\} + + /// \name Wrapping the traits + //\{ + Point construct_point(const Point& p, const Offset &o) const + { + return geom_traits().construct_point_2_object()(p, o); + } + Point construct_point(const Periodic_point& pp) const + { + return construct_point(pp.first, pp.second); + } + Triangle construct_triangle(const Point &p1, const Point &p2, + const Point &p3, const Offset &o1, const Offset &o2, const Offset &o3) const + { + return geom_traits().construct_triangle_2_object()(p1, p2, p3, o1, o2, o3); + } + Triangle construct_triangle(const Periodic_triangle& tri) const + { + return construct_triangle(tri[0].first, tri[1].first, tri[2].first, + tri[0].second, tri[1].second, tri[2].second); + } + Segment construct_segment(const Point &p1, const Point &p2, const Offset &o1, + const Offset &o2) const + { + return geom_traits().construct_segment_2_object()(p1, p2, o1, o2); + } + Segment construct_segment(const Periodic_segment& seg) const + { + return construct_segment(seg[0].first, seg[1].first, seg[0].second, + seg[1].second); + } + //\} + + /// Test whether removing vertex v decreases the dimension of the triangulation. + bool test_dim_down(Vertex_handle /*v*/) const + { + //test the dimensionality of the resulting triangulation + //upon removing of vertex v + return number_of_vertices() == 1; + } + void make_hole(Vertex_handle v, std::list & hole); + + + Face_handle create_face(Face_handle f1, int i1, Face_handle f2, int i2, Face_handle f3, int i3); + Face_handle create_face(Face_handle f1, int i1, Face_handle f2, int i2); + Face_handle create_face(Face_handle f, int i, Vertex_handle v); + Face_handle create_face(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3); + Face_handle create_face(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3, Face_handle f1, Face_handle f2, Face_handle f3); + Face_handle create_face(); + Face_handle create_face(Face_handle); //calls copy constructor of Face + void delete_face(Face_handle f); + void delete_vertex(Vertex_handle v); + + // template members + + bool well_oriented(Vertex_handle v) const + { + Face_circulator fc = incident_faces(v), done(fc); + do + { + Orientation o; + + Vertex_handle v0 = fc->vertex(0); + Vertex_handle v1 = fc->vertex(1); + Vertex_handle v2 = fc->vertex(2); + if (fc->has_zero_offsets()) + { + o = orientation(v0->point(), v1->point(), v2->point()); + } + else + { + Offset off0 = get_offset(fc, 0); + Offset off1 = get_offset(fc, 1); + Offset off2 = get_offset(fc, 2); + o = orientation(v0->point(), v1->point(), v2->point(), off0, off1, off2); + } + if (o != COUNTERCLOCKWISE) return false; + } + while (++fc != done); + return true; + } + + template + Vertex_handle star_hole(const Point& p, EdgeIt edge_begin, EdgeIt edge_end) + { + std::list empty_list; + return star_hole(p, edge_begin, edge_end, empty_list.begin(), + empty_list.end()); + } + + template + Vertex_handle star_hole(const Point& p, EdgeIt edge_begin, EdgeIt edge_end, + FaceIt face_begin, FaceIt face_end) + { + CGAL_assertion(is_1_cover()); + + Vertex_handle v = _tds.star_hole(edge_begin, edge_end, face_begin, face_end); + v->set_point(p); + return v; + } + + /// Periodic functions + //\{ + + /// These functions give the pair (vertex, offset) that corresponds + /// to the i-th vertex of face f. The vertex returned is not a virtual copy. + void get_vertex(Face_handle f, int i, Vertex_handle &vh, Offset &off) const; + /// These functions give the pair (vertex, offset) that corresponds + /// to the i-th vertex of vertex vh. The vertex returned is not a virtual copy. + void get_vertex(Vertex_handle vh_i, Vertex_handle &vh, Offset &off) const; + /// Returns the face containing the three vertices defined by vh[0], vh1[1] and vh[2]. + inline Face_handle get_face(const Vertex_handle* vh) const; + /// Constructs a list of too long edges in the triangulation. + int find_too_long_edges( + std::map >& edges) const; + + /// Returns the offset such that (p, o) lies on the bounded side of the face f. + Offset get_location_offset(Face_handle f, const Point &p, const Offset &o) const + { + CGAL_triangulation_precondition( number_of_vertices() != 0 ); + + if (is_1_cover() && f->has_zero_offsets()) + { + // default case: + return Offset(); + } + else + { + int cumm_off = f->offset(0) | f->offset(1) | f->offset(2); + // Special case for the periodic space. + // Fetch vertices and respective offsets of c from _virtual_vertices + const Point *pts[3]; + Offset off[3]; + for (int i = 0; i < 3; i++) + { + pts[i] = &(f->vertex(i)->point()); + off[i] = get_offset(f, i); + } + + // Main idea seems to just test all possibilities. + for (int i = 0; i < 4; i++) + { + if (((cumm_off | (~i)) & 3) == 3) + { + if (bounded_side(*pts[0], *pts[1], *pts[2], p, off[0], off[1], + off[2], combine_offsets(o, int_to_off(i))) != ON_UNBOUNDED_SIDE) + { + return int_to_off(i); + } + } + } + } + CGAL_assertion(false); + return Offset(); + } + + /// Assigns the offsets to the vertices of the face f, and makes the offset minimal in each direction. + void set_offsets(Face_handle f, int o0, int o1, int o2) + { + int off0[2] = { (o0 >> 1) & 1, (o0 & 1) }; + int off1[2] = { (o1 >> 1) & 1, (o1 & 1) }; + int off2[2] = { (o2 >> 1) & 1, (o2 & 1) }; + // Make sure that there is at least one zero offset in every direction + for (int i = 0; i < 2; i++) + { + int min_off = (std::min)((std::min)(off0[i], off1[i]), off2[i]); + if (min_off != 0) + { + off0[i] -= min_off; + off1[i] -= min_off; + off2[i] -= min_off; + } + } + o0 = ((off0[0] & 1) << 1) + (off0[1] & 1); + o1 = ((off1[0] & 1) << 1) + (off1[1] & 1); + o2 = ((off2[0] & 1) << 1) + (off2[1] & 1); + f->set_offsets(o0, o1, o2); + } + + /// Assigns the offsets to the vertices of the face f, and makes the offset minimal in each direction. + template + void set_offsets(Face_handle f, const Offset &o0, const Offset &o1, const Offset &o2) + { + int off0[2] = { o0.x(), o0.y() }; + int off1[2] = { o1.x(), o1.y() }; + int off2[2] = { o2.x(), o2.y() }; + for (int i = 0; i < 2; i++) + { + int min_off = (std::min)((std::min)(off0[i], off1[i]), off2[i]); + if (min_off != 0) + { + off0[i] -= min_off; + off1[i] -= min_off; + off2[i] -= min_off; + } + } + + CGAL_triangulation_assertion((std::min)((std::min)(off0[0], off1[0]), off2[0]) == 0); + CGAL_triangulation_assertion((std::min)((std::min)(off0[1], off1[1]), off2[1]) == 0); + CGAL_triangulation_assertion((0 <= off0[0]) && (off0[0] < 2)); + CGAL_triangulation_assertion((0 <= off1[0]) && (off1[0] < 2)); + CGAL_triangulation_assertion((0 <= off2[0]) && (off2[0] < 2)); + CGAL_triangulation_assertion((0 <= off0[1]) && (off0[1] < 2)); + CGAL_triangulation_assertion((0 <= off1[1]) && (off1[1] < 2)); + CGAL_triangulation_assertion((0 <= off2[1]) && (off2[1] < 2)); + + int o0i = ((off0[0] & 1) << 1) + (off0[1] & 1); + int o1i = ((off1[0] & 1) << 1) + (off1[1] & 1); + int o2i = ((off2[0] & 1) << 1) + (off2[1] & 1); + f->set_offsets(o0i, o1i, o2i); + } + //\} + + /// Checks the too_long_edges bookkeeping + bool is_valid_too_long_edges(bool verbose = false, int level = 0) const; + + /** @name Checking helpers */ //@{ + /// calls has_self_edges for every face of the triangulation + bool has_self_edges() const + { + Face_iterator it; + for ( it = all_faces_begin(); it != all_faces_end(); ++it ) + if (has_self_edges(it)) return true; + return false; + } + bool has_self_edges(Face_handle fh) const + { + CGAL_triangulation_assertion((fh->vertex(0) != fh->vertex(1)) || + (fh->offset(0) != fh->offset(1))); + CGAL_triangulation_assertion((fh->vertex(0) != fh->vertex(2)) || + (fh->offset(0) != fh->offset(2))); + CGAL_triangulation_assertion((fh->vertex(1) != fh->vertex(2)) || + (fh->offset(1) != fh->offset(2))); + return ((fh->vertex(0) == fh->vertex(1)) || + (fh->vertex(0) == fh->vertex(2)) || + (fh->vertex(1) == fh->vertex(2))); + } + + //@} + + +protected: + // Protected data of Periodic_4_hyperbolic_triangulation_2 + /// \name Triangulation data members + // \{ + + /// Geometric traits + Gt _gt; + /// Triangulation data structure + Tds _tds; + // \} + + /// Returns false, no infinite simplices in the periodic triangulation + template + inline bool is_infinite(T) const + { + return false; + } + +private: + /// Inserts (p,o) in the face f and sets the offsets of the newly created faces + /// Doesn't insert periodic copies + Vertex_handle insert_in_face(const Point& p, const Offset &o, + Face_handle f, + Vertex_handle vh); + /// Inserts (p,o) in the edge (f,i) and sets the offsets of the newly created faces + /// Doesn't insert periodic copies + Vertex_handle insert_in_edge(const Point& p, const Offset &o, + Face_handle f, int i, + Vertex_handle vh); + + /// Remove a vertex without removing it's possible periodic copies. + /// Helper functions + void remove_degree_3_single_copy(Vertex_handle vh); + + // Private data of Periodic_4_hyperbolic_triangulation_2 + /// \name Periodic members + //\{ + + /// Determines if we currently compute in 3-cover or 1-cover. + Covering_sheets _cover; + + /// The domain + Iso_rectangle _domain; + + /// This threshold should be chosen such that if all edges are shorter, + /// we can be sure that there are no self-edges anymore. + FT _edge_length_threshold; + + /// This adjacency list stores all edges that are longer than + /// edge_length_threshold. + Too_long_edges_map _too_long_edges; + /// Number of edges that are too long + size_t _too_long_edge_counter; + + /// map of offsets for periodic copies of vertices + Virtual_vertex_map _virtual_vertices; + /// map of a non-virtual vertex to its virtual copies + Virtual_vertex_reverse_map _virtual_vertices_reverse; + //\} +}; // class Periodic_4_hyperbolic_triangulation_2 + +// CONSTRUCTORS +template +Periodic_4_hyperbolic_triangulation_2::Periodic_4_hyperbolic_triangulation_2( + const Iso_rectangle & domain, const Geom_traits& geom_traits) + : _gt(geom_traits), _tds() + , _cover(make_array(1, 1)) + , _domain(domain) + , _too_long_edge_counter(0) +{ + CGAL_triangulation_precondition(_domain.xmax() - _domain.xmin() == + _domain.ymax() - _domain.ymin()); + set_domain(_domain); +} + +// copy constructor duplicates vertices and faces +template +Periodic_4_hyperbolic_triangulation_2::Periodic_4_hyperbolic_triangulation_2(const Periodic_4_hyperbolic_triangulation_2 &tr) +{ + copy_triangulation(tr); +} + +//Assignment +template +Periodic_4_hyperbolic_triangulation_2 & +Periodic_4_hyperbolic_triangulation_2::operator=( + const Periodic_4_hyperbolic_triangulation_2 &tr) +{ + copy_triangulation(tr); + return *this; +} + +// Helping functions +template < class GT, class Tds > +class Periodic_4_hyperbolic_triangulation_2::Finder +{ + const Self* _t; + const Point & _p; +public: + Finder(const Self* t, const Point &p) : _t(t), _p(p) {} + bool operator()(const Vertex_handle v) + { + return _t->xy_equal(v->point(), _p); + } +}; + +template < class GT, class Tds > +inline void +Periodic_4_hyperbolic_triangulation_2:: +copy_multiple_covering(const Periodic_4_hyperbolic_triangulation_2 & tr) +{ + // Write the respective offsets in the vertices to make them + // automatically copy with the tds. + for (Vertex_iterator vit = tr.vertices_begin() ; + vit != tr.vertices_end() ; ++vit) + { + vit->set_offset(tr.get_offset(vit)); + } + // copy the tds + _tds = tr.tds(); + // make a list of all vertices that belong to the original + // domain and initialize the basic structure of + // virtual_vertices_reverse + std::list vlist; + for (Vertex_iterator vit = vertices_begin() ; + vit != vertices_end() ; ++vit) + { + if (vit->offset() == Offset()) + { + vlist.push_back(vit); + _virtual_vertices_reverse.insert( + std::make_pair(vit, std::vector(8))); + CGAL_triangulation_assertion(_virtual_vertices_reverse.find(vit) + ->second.size() == 8); + } + } + // Iterate over all vertices that are not in the original domain + // and construct the respective entries to virtual_vertices and + // virtual_vertices_reverse + for (Vertex_iterator vit2 = vertices_begin() ; + vit2 != vertices_end() ; ++vit2) + { + if (vit2->offset() != Offset()) + { + //TODO: use some binding, maybe boost instead of the Finder. + typename std::list::iterator vlist_it + = std::find_if(vlist.begin(), vlist.end(), + Finder(this, vit2->point())); + Offset off = vit2->offset(); + _virtual_vertices.insert(std::make_pair(vit2, + std::make_pair(*vlist_it, off))); + _virtual_vertices_reverse.find(*vlist_it) + ->second[3 * off[0] + off[1] - 1] = vit2; + CGAL_triangulation_assertion(get_offset(vit2) == off); + } + } + // Cleanup vertex offsets + for (Vertex_iterator vit = vertices_begin() ; + vit != vertices_end() ; ++vit) + vit->clear_offset(); + for (Vertex_iterator vit = tr.vertices_begin() ; + vit != tr.vertices_end() ; ++vit) + vit->clear_offset(); + // Build up the too_long_edges container + _too_long_edge_counter = 0; + _too_long_edges.clear(); + for (Vertex_iterator vit = vertices_begin() ; + vit != vertices_end() ; ++vit) + _too_long_edges[vit] = std::list(); + std::pair edge_to_add; + Point p1, p2; + int i, j; + for (Edge_iterator eit = edges_begin() ; + eit != edges_end() ; ++eit) + { + if (&*(eit->first->vertex(cw(eit->second))) + < &*(eit->first->vertex(ccw(eit->second)))) + { + i = cw(eit->second); + j = ccw(eit->second); + } + else + { + i = ccw(eit->second); + j = cw(eit->second); + } + edge_to_add = std::make_pair(eit->first->vertex(i), + eit->first->vertex(j)); + p1 = construct_point(eit->first->vertex(i)->point(), + get_offset(eit->first, i)); + p2 = construct_point(eit->first->vertex(j)->point(), + get_offset(eit->first, j)); + Vertex_handle v_no = eit->first->vertex(i); + if (squared_distance(p1, p2) > _edge_length_threshold) + { + CGAL_triangulation_assertion( + find(_too_long_edges[v_no].begin(), + _too_long_edges[v_no].end(), + edge_to_add.second) == _too_long_edges[v_no].end()); + _too_long_edges[v_no].push_back(edge_to_add.second); + _too_long_edge_counter++; + } + } +} + +template +void Periodic_4_hyperbolic_triangulation_2::copy_triangulation( + const Periodic_4_hyperbolic_triangulation_2 &tr) +{ + _tds.clear(); + _gt = tr._gt; + _cover = tr._cover; + _domain = tr._domain; + _edge_length_threshold = tr._edge_length_threshold; + _too_long_edge_counter = tr._too_long_edge_counter; + if (tr.is_1_cover()) + { + _tds = tr.tds(); + } + else + { + copy_multiple_covering(tr); + } + CGAL_assertion(_too_long_edge_counter == tr._too_long_edge_counter); + CGAL_triangulation_expensive_postcondition(*this == tr); +} + +template +void Periodic_4_hyperbolic_triangulation_2::swap(Periodic_4_hyperbolic_triangulation_2 &tr) +{ + _tds.swap(tr._tds); + + Geom_traits t = geom_traits(); + _gt = tr.geom_traits(); + tr._gt = t; + + std::swap(tr._cover, _cover); + std::swap(tr._domain, _domain); + + std::swap(tr._edge_length_threshold, _edge_length_threshold); + std::swap(tr._too_long_edges, _too_long_edges); + std::swap(tr._too_long_edge_counter, _too_long_edge_counter); + + std::swap(tr._virtual_vertices, _virtual_vertices); + std::swap(tr._virtual_vertices_reverse, _virtual_vertices_reverse); +} + +template +void Periodic_4_hyperbolic_triangulation_2::clear() +{ + _tds.clear(); + _tds.set_dimension(-2); + + _too_long_edges.clear(); + _too_long_edge_counter = 0; + + _virtual_vertices.clear(); + _virtual_vertices_reverse.clear(); + + _cover = make_array(1, 1); +} + +template +bool Periodic_4_hyperbolic_triangulation_2::is_valid(Face_handle fh, bool /*verbose*/, int /*level*/) const +{ + bool result = true; + + int xmin, xmax, ymin, ymax; + xmin = ymin = 3; + xmax = ymax = 0; + for (int i = 0; i < 3; ++i) + { + Offset o = get_offset(fh, i); + xmin = (std::min)(xmin, o[0]); + xmax = (std::max)(xmax, o[0]); + ymin = (std::min)(ymin, o[1]); + ymax = (std::max)(ymax, o[1]); + } + // Should at most cross 1 border in each direction + result &= (xmax - xmin <= 1); + result &= (ymax - ymin <= 1); + if (!result) + { + std::cerr << "min/max: " << xmin << "," << xmax << " " << ymin << "," << ymax << std::endl; + for (int i = 0; i < 3; ++i) + { + Offset o = get_offset(fh, i); + std::cerr << "Offset: " << o << std::endl; + } + std::cerr << std::endl; + CGAL_triangulation_assertion(false); + } + + return result; +} + +template +bool Periodic_4_hyperbolic_triangulation_2::is_valid(bool verbose, int level) const +{ + bool result = _tds.is_valid(verbose, level); + CGAL_triangulation_assertion(result); + + if (dimension() == 2) + { + // Check positive orientation: + const Point *p[3]; + Offset off[3]; + for (Face_iterator fit = faces_begin(); fit != faces_end(); ++fit) + { + for (int i = 0; i < 3; i++) + { + p[i] = &fit->vertex(i)->point(); + off[i] = get_offset(fit, i); + } + + if (orientation(*p[0], *p[1], *p[2], off[0], off[1], off[2]) != POSITIVE) + { + if (verbose) + { + std::cerr + << "Periodic_4_hyperbolic_triangulation_2: wrong orientation:" << "\n" + << *p[0] << " \t" << off[0] << "\n" + << *p[1] << " \t" << off[1] << "\n" + << *p[2] << " \t" << off[2] << std::endl; + } + result = false; + } + } + } + CGAL_triangulation_assertion(result); + + // Check for the right number of simplices + int copies = number_of_sheets()[0] * number_of_sheets()[1]; + result &= (number_of_stored_vertices() == copies * number_of_vertices()); + result &= (number_of_stored_edges() == copies * number_of_edges()); + result &= (number_of_stored_faces() == copies * number_of_faces()); + CGAL_triangulation_assertion(result); + + // check number of euler characteristic. This cannot be done by the Tds + // which does not know the genus + result &= (number_of_stored_vertices() - number_of_stored_edges() + + number_of_stored_faces() == 0); + CGAL_triangulation_assertion(result); + + result &= !has_self_edges(); + CGAL_triangulation_assertion(result); + + // Edges should not be longer than 1 periodicity + for (Face_iterator fit = faces_begin(); fit != faces_end(); ++fit) + { + result &= is_valid(fit, verbose, level); + } + CGAL_triangulation_assertion(result); + + result &= is_1_cover() == _virtual_vertices.empty(); + result &= is_1_cover() == _virtual_vertices_reverse.empty(); + result &= (_virtual_vertices.size() == (number_of_sheets()[0] + * number_of_sheets()[1] - 1) * _virtual_vertices_reverse.size()); + CGAL_triangulation_assertion(result); + + for (Virtual_vertex_map_it it = _virtual_vertices.begin(); it + != _virtual_vertices.end(); ++it) + { + const Vertex_handle © = it->first; + const Vertex_handle &orig = it->second.first; + const Offset &off = it->second.second; + size_t index = number_of_sheets()[0] * off[0] + off[1] - 1; + Virtual_vertex_reverse_map_it rev_it = _virtual_vertices_reverse.find(orig); + if (rev_it != _virtual_vertices_reverse.end()) + { + if (index < rev_it->second.size()) + { + result &= (rev_it->second[index] == copy); + } + else + { + result &= false; + } + } + else + { + result &= false; + } + } + CGAL_triangulation_assertion(result); + + for (Virtual_vertex_reverse_map_it it = _virtual_vertices_reverse.begin(); it + != _virtual_vertices_reverse.end(); ++it) + { + const std::vector &copies = it->second; + result &= copies.size() == 8; + for (size_t i = 0; i < copies.size(); ++i) + { + Virtual_vertex_map_it copy_it = _virtual_vertices.find(copies[i]); + if (copy_it != _virtual_vertices.end()) + { + result &= copy_it->second.first == it->first; + } + else + { + result &= false; + } + } + } + + // Check the too_long_edges administration + result &= is_valid_too_long_edges(verbose, level); + + return result; +} + +template +bool Periodic_4_hyperbolic_triangulation_2::is_valid_too_long_edges(bool verbose, int /*level*/) const +{ + bool result = true; + + result &= is_1_cover() == _too_long_edges.empty(); + CGAL_triangulation_assertion(result); + size_t too_long_edges = 0; + for (Too_long_edges_map_it it = _too_long_edges.begin(); it + != _too_long_edges.end(); ++it) + { + too_long_edges += it->second.size(); + } + CGAL_triangulation_assertion(result); + if (_too_long_edge_counter != too_long_edges) + { + if (verbose) std::cout << "Too long edge counter is incorrect: " << _too_long_edge_counter << " != " << too_long_edges << std::endl; + result = false; + } + CGAL_triangulation_assertion(result); + + /// Expensive check whether the right too long edges are in the list + if (is_1_cover()) + { + for (Edge_iterator eit = edges_begin(); eit != edges_end(); ++eit) + { + Vertex_handle vh1 = eit->first->vertex(ccw(eit->second)); + Vertex_handle vh2 = eit->first->vertex(cw(eit->second)); + Point p1 = construct_point(vh1->point(), get_offset(eit->first, ccw(eit->second))); + Point p2 = construct_point(vh2->point(), get_offset(eit->first, cw(eit->second))); + result &= (!edge_is_too_long(p1, p2)); + } + CGAL_triangulation_assertion(result); + } + else + { + too_long_edges = 0; + for (Edge_iterator eit = edges_begin(); eit != edges_end(); ++eit) + { + Vertex_handle vh1 = eit->first->vertex(ccw(eit->second)); + Vertex_handle vh2 = eit->first->vertex(cw(eit->second)); + Point p1 = construct_point(vh1->point(), + get_offset(eit->first, ccw(eit->second))); + Point p2 = construct_point(vh2->point(), + get_offset(eit->first, cw(eit->second))); + + if (&*vh2 < &*vh1) + std::swap(vh1, vh2); + CGAL_triangulation_assertion(&*vh1 < &*vh2); + + bool too_long = edge_is_too_long(p1, p2); + if (too_long != edge_is_too_long(p2, p1)) + { + if (verbose) std::cout << "Long edge criterion not symmetric c(v1,v2) != c(v2,v1)" << std::endl; + result = false; + } + CGAL_triangulation_assertion(result); + + Too_long_edges_map_it it = _too_long_edges.find(vh1); + if (it == _too_long_edges.end()) + { + if (too_long) + { + if (verbose) std::cout << "1. Too long edge not in the datastructure" << std::endl; + result = false; + } + result &= !too_long; + CGAL_triangulation_assertion(result); + } + else + { + typename std::list::const_iterator it2 = find(it->second.begin(), it->second.end(), vh2); + if (too_long) + { + too_long_edges++; + if (it2 == it->second.end()) + { + if (verbose) std::cout << "2. Too long edge not in the datastructure" << std::endl; + result = false; + } + CGAL_triangulation_assertion(result); + } + else + { + if (it2 != it->second.end()) + { + if (verbose) std::cout << "Edge is not too long, but contained in the datastructure" << std::endl; + result = false; + } + CGAL_triangulation_assertion(result); + } + } + } + + if (_too_long_edge_counter != too_long_edges) + { + if (verbose) + std::cout << "Counts do not match: " << _too_long_edge_counter << " != " << too_long_edges << std::endl; + result = false; + } + CGAL_triangulation_assertion(result); + } + + return result; +} + +template +bool Periodic_4_hyperbolic_triangulation_2::flippable(Face_handle f, int i) +{ + Face_handle nb = f->neighbor(i); + int j = nb->index(f); + + const Point *p[4]; + + p[0] = &f->vertex(i)->point(); // i + p[1] = &nb->vertex(j)->point(); // opposite + p[2] = &f->vertex(ccw(i))->point(); // ccw + p[3] = &f->vertex(cw(i))->point(); // cw + + if (is_1_cover() && f->has_zero_offsets() && nb->has_zero_offsets()) + { + // if (orientation(*p[0], *p[1], *p[2]) != RIGHT_TURN) + // return false; + // if (orientation(*p[0], *p[1], *p[3]) != LEFT_TURN) + // return false; + if (orientation(*p[0], *p[1], *p[2]) == LEFT_TURN) + return false; + if (orientation(*p[0], *p[1], *p[3]) == RIGHT_TURN) + return false; + } + else + { + Offset off[4]; + off[0] = get_offset(f, i); + off[1] = combine_offsets(get_offset(nb, j), get_neighbor_offset(nb, j, f, i)); + off[2] = get_offset(f, ccw(i)); + off[3] = get_offset(f, cw(i)); + + // if (orientation(*p[0], *p[1], *p[2], off[0], off[1], off[2]) != RIGHT_TURN) + // return false; + // if (orientation(*p[0], *p[1], *p[3], off[0], off[1], off[3]) != LEFT_TURN) + // return false; + if (orientation(*p[0], *p[1], *p[2], off[0], off[1], off[2]) == LEFT_TURN) + return false; + if (orientation(*p[0], *p[1], *p[3], off[0], off[1], off[3]) == RIGHT_TURN) + return false; + } + + return true; +} + +template +void Periodic_4_hyperbolic_triangulation_2::flip(Face_handle f, int i) +{ + if (is_1_cover()) + { + flip_single_edge(f, i); + return; + } + + Vertex_handle vh1 = f->vertex( cw(i)); + Vertex_handle vh2 = f->vertex(ccw(i)); + Virtual_vertex_map_it it_vh1 = _virtual_vertices.find(vh1); + Virtual_vertex_map_it it_vh2 = _virtual_vertices.find(vh2); + + Offset vh1_offset, vh2_offset; + if (it_vh1 != _virtual_vertices.end()) + { + vh1 = it_vh1->second.first; + vh1_offset = it_vh1->second.second; + } + if (it_vh2 != _virtual_vertices.end()) + { + vh2 = it_vh2->second.first; + vh2_offset = it_vh2->second.second; + } + + CGAL_triangulation_assertion( + virtual_vertices_reverse().find(vh1) != virtual_vertices_reverse().end()); + CGAL_triangulation_assertion( + virtual_vertices_reverse().find(vh2) != virtual_vertices_reverse().end()); + const std::vector &v1s = + virtual_vertices_reverse().find(vh1)->second; + const std::vector &v2s = + virtual_vertices_reverse().find(vh2)->second; + + CGAL_assertion(v1s.size() == 8); + CGAL_assertion(v1s.size() == v2s.size()); + + Face_handle fh; + int index=0; + Vertex_handle vh1_copy, vh2_copy; + + // Virtual copies + for (int x = 0; x < 3; ++x) + { + for (int y = 0; y < 3; ++y) + { + int i1 = 3 * ((x + vh1_offset.x()) % 3) + ((y + vh1_offset.y()) % 3); + int i2 = 3 * ((x + vh2_offset.x()) % 3) + ((y + vh2_offset.y()) % 3); + + if (i1 == 0) + vh1_copy = vh1; + else + vh1_copy = v1s[i1 - 1]; + if (i2 == 0) + vh2_copy = vh2; + else + vh2_copy = v2s[i2 - 1]; + + bool found = is_edge(vh1_copy, vh2_copy, fh, index); + CGAL_USE(found); + CGAL_assertion(found); + if (found) + flip_single_edge(fh, index); + } + } + + try_to_convert_to_one_cover(); +} +template +void Periodic_4_hyperbolic_triangulation_2::flip_single_edge(Face_handle f, int i) +{ + CGAL_triangulation_precondition(f != Face_handle()); + CGAL_triangulation_precondition(i == 0 || i == 1 || i == 2); + CGAL_triangulation_precondition(dimension() == 2); + + CGAL_triangulation_precondition(flippable(f, i)); + + if (!is_1_cover()) + remove_too_long_edge(f, i); + + Face_handle nb = f->neighbor(i); + if (f->has_zero_offsets() && nb->has_zero_offsets()) + { + _tds.flip(f, i); + + if (!is_1_cover()) + insert_too_long_edge(f, ccw(i)); + + return; + } + + int nb_index = nb->index(f); + int offsets[4]; + offsets[0] = f->offset(i); + offsets[1] = f->offset(cw(i)); + offsets[2] = f->offset(ccw(i)); + offsets[3] = nb->offset(nb_index); + + // Move the offsets of f and nb in the same space by correcting for nb_offset + Offset nb_offset = get_neighbor_offset(f, i, nb, nb_index); + if (nb_offset.x() != 0) + { + if (nb_offset.x() == 1) + { + CGAL_assertion(((offsets[0] & 2) | (offsets[1] & 2) | (offsets[2] & 2)) == 0); + offsets[0] |= 2; + offsets[1] |= 2; + offsets[2] |= 2; + } + else + { + CGAL_triangulation_assertion(nb_offset.x() == -1); + CGAL_assertion((offsets[3] & 2) == 0); + offsets[3] |= 2; + } + } + if (nb_offset.y() != 0) + { + if (nb_offset.y() == 1) + { + CGAL_assertion(((offsets[0] & 1) | (offsets[1] & 1) | (offsets[2] & 1)) == 0); + offsets[0] |= 1; + offsets[1] |= 1; + offsets[2] |= 1; + } + else + { + CGAL_triangulation_assertion(nb_offset.y() == -1); + CGAL_assertion((offsets[3] & 1) == 0); + offsets[3] |= 1; + } + } + CGAL_assertion((offsets[0] & offsets[1] & offsets[2] & offsets[3]) == 0); + CGAL_triangulation_assertion_code(Vertex_handle vh = f->vertex(i)); + CGAL_triangulation_assertion_code(Vertex_handle vh_ccw = f->vertex(ccw(i))); + _tds.flip(f, i); + // Combinatorial checks + CGAL_triangulation_assertion(vh == f->vertex(i)); + CGAL_triangulation_assertion(vh_ccw == f->vertex(ccw(i))); + CGAL_triangulation_assertion(f->vertex(i) == nb->vertex(cw(nb_index))); + CGAL_triangulation_assertion(f->vertex(cw(i)) == nb->vertex(nb_index)); + + // Restore the offsets + int new_off[3]; + // For face f + new_off[i] = offsets[0]; + new_off[ccw(i)] = offsets[2]; + new_off[cw(i)] = offsets[3]; + set_offsets(f, new_off[0], new_off[1], new_off[2]); + // For face nb + new_off[nb_index] = offsets[3]; + new_off[ccw(nb_index)] = offsets[1]; + new_off[cw(nb_index)] = offsets[0]; + set_offsets(nb, new_off[0], new_off[1], new_off[2]); + + if (!is_1_cover()) + insert_too_long_edge(f, ccw(i)); +} + +template +void +Periodic_4_hyperbolic_triangulation_2::remove_from_virtual_copies(Vertex_handle v) +{ + typename Virtual_vertex_reverse_map::iterator rev_it = _virtual_vertices_reverse.find(v); + CGAL_triangulation_assertion(rev_it != _virtual_vertices_reverse.end()); + + const std::vector &virtual_copies = rev_it->second; + for (size_t i = 0; i < virtual_copies.size(); ++i) + { + _virtual_vertices.erase(virtual_copies[i]); + } + _virtual_vertices_reverse.erase(rev_it); +} + +template +typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle Periodic_4_hyperbolic_triangulation_2 < +Gt, Tds >::insert_first(const Point& p) +{ + CGAL_assertion(empty()); + // The empty triangulation has a single sheeted cover + _cover = make_array(3, 3); + + /// Virtual vertices, one per periodic domain + Vertex_handle vir_vertices[3][3]; + /// Virtual faces, two per periodic domain + Face_handle faces[3][3][2]; + + // Initialise vertices: + vir_vertices[0][0] = _tds.create_vertex(); + vir_vertices[0][0]->set_point(p); + _virtual_vertices_reverse[vir_vertices[0][0]] = std::vector(); + for (int i = 0; i < _cover[0]; i++) + { + for (int j = 0; j < _cover[1]; j++) + { + if ((i != 0) || (j != 0)) + { + // Initialise virtual vertices out of the domain for debugging + vir_vertices[i][j] = _tds.create_vertex(); + vir_vertices[i][j]->set_point(p); //+Offset(i,j)); + _virtual_vertices[vir_vertices[i][j]] = Virtual_vertex( + vir_vertices[0][0], Offset(i, j)); + _virtual_vertices_reverse[vir_vertices[0][0]].push_back( + vir_vertices[i][j]); + } + } + } + + // Create faces: + for (int i = 0; i < _cover[0]; i++) + { + for (int j = 0; j < _cover[1]; j++) + { + for (int f = 0; f < 2; f++) + { + // f faces per 'rectangle' + faces[i][j][f] = _tds.create_face(); + } + } + } + + // table containing the vertex information + // index to the right vertex: [number of faces][vertex][offset] + int vertex_ind[2][3][2] = { { { 0, 0 }, { 1, 1 }, { 0, 1 } }, { { 0, 0 }, { + 1, 0 + }, { 1, 1 } + } + }; + // Table containing the neighbor information + // [number of faces][neighbor][offset,face] + int neighb_ind[2][3][3] = { { { 0, 1, 1 }, { -1, 0, 1 }, { 0, 0, 1 } }, { { + 1, 0, 0 + }, { 0, 0, 0 }, { 0, -1, 0 } + } + }; + for (int i = 0; i < _cover[0]; i++) + { + for (int j = 0; j < _cover[1]; j++) + { + int offset = + ((i == _cover[0] - 1 ? 2 : 0) | (j == _cover[1] - 1 ? 1 : 0)); + for (int f = 0; f < 2; f++) + { + faces[i][j][f]->set_vertices(vir_vertices[(i + vertex_ind[f][0][0]) + % _cover[0]][(j + vertex_ind[f][0][1]) % _cover[1]], + vir_vertices[(i + vertex_ind[f][1][0]) % _cover[0]][(j + + vertex_ind[f][1][1]) % _cover[1]], vir_vertices[(i + + vertex_ind[f][2][0]) % _cover[0]][(j + vertex_ind[f][2][1]) + % _cover[1]]); + set_offsets(faces[i][j][f], offset & (vertex_ind[f][0][0] * 2 + + vertex_ind[f][0][1] * 1), offset & (vertex_ind[f][1][0] * 2 + + vertex_ind[f][1][1] * 1), offset & (vertex_ind[f][2][0] * 2 + + vertex_ind[f][2][1] * 1)); + faces[i][j][f]->set_neighbors(faces[(i + _cover[0] + + neighb_ind[f][0][0]) % _cover[0]][(j + _cover[1] + + neighb_ind[f][0][1]) % _cover[1]][neighb_ind[f][0][2]], faces[(i + + _cover[0] + neighb_ind[f][1][0]) % _cover[0]][(j + _cover[1] + + neighb_ind[f][1][1]) % _cover[1]][neighb_ind[f][1][2]], faces[(i + + _cover[0] + neighb_ind[f][2][0]) % _cover[0]][(j + _cover[1] + + neighb_ind[f][2][1]) % _cover[1]][neighb_ind[f][2][2]]); + } + } + } + // set pointers from the vertices to incident faces. + for (int i = 0; i < _cover[0]; i++) + { + for (int j = 0; j < _cover[1]; j++) + { + vir_vertices[i][j]->set_face(faces[i][j][0]); + } + } + + _tds.set_dimension(2); + + // create the base for too_long_edges; + CGAL_triangulation_assertion(_too_long_edges.empty() ); + CGAL_triangulation_assertion(_too_long_edge_counter == 0); + + // Insert all vertices as the first vertex in the _too_long_edges list + int k = 0; + std::list empty_list; + for (Vertex_iterator vit = vertices_begin(); vit != vertices_end(); ++vit) + { + _too_long_edges[vit] = empty_list; + k++; + } + + // Insert all edges as all edges are too long + _too_long_edge_counter = 0; + for (Edge_iterator eit = edges_begin(); eit != edges_end(); eit++) + { + Vertex_handle vh1 = eit->first->vertex(ccw(eit->second)); + Vertex_handle vh2 = eit->first->vertex(cw(eit->second)); + if (&*vh1 < &*vh2) + { + _too_long_edges[vh1].push_back(vh2); + } + else + { + _too_long_edges[vh2].push_back(vh1); + } + _too_long_edge_counter++; + } + + return vir_vertices[0][0]; +} + +template +typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle +Periodic_4_hyperbolic_triangulation_2::insert_in_edge(const Point& p, + Face_handle f, int i) +{ + return insert(p, EDGE, f, i); +} +template +typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle +Periodic_4_hyperbolic_triangulation_2::insert_in_edge(const Point& p, const Offset &o, + Face_handle f, int i, + Vertex_handle vh) +{ + // Insert in edge calls an insert_in_face and a flip. + // Therefore there is no need to update the too_long_edges bookkeeping directly. + + CGAL_triangulation_assertion(number_of_vertices() != 0); + CGAL_triangulation_assertion((!is_1_cover()) || (o == Offset())); + + // Backup of the neighbor and its relative offset + Face_handle nb = f->neighbor(i); + int j = nb->index(f); + CGAL_triangulation_assertion_code(Offset current_offset = get_location_offset(f, p, o)); + CGAL_triangulation_assertion + (orientation(f->vertex(cw(i))->point(), p, f->vertex(ccw(i))->point(), + get_offset(f, cw(i)), combine_offsets(o, current_offset), get_offset(f, ccw(i))) == COLLINEAR && + collinear_between(f->vertex(cw(i))->point(), p, f->vertex(ccw(i))->point(), + get_offset(f, cw(i)), combine_offsets(o, current_offset), get_offset(f, ccw(i))) ); + + /// Insert in the face and flip an edge + Vertex_handle v = insert_in_face(p, o, f, vh); + flip_single_edge(nb, j); + + return v; +} + +template +typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle +Periodic_4_hyperbolic_triangulation_2::insert_in_face(const Point& p, Face_handle f) +{ + return insert(p, FACE, f, 0); +} +template +typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle +Periodic_4_hyperbolic_triangulation_2::insert_in_face(const Point& p, const Offset &o, + Face_handle f, + Vertex_handle vh) +{ + CGAL_triangulation_assertion(f != Face_handle()); + CGAL_triangulation_assertion(number_of_vertices() != 0); + CGAL_triangulation_assertion((!is_1_cover()) || (o == Offset())); + + const bool simplicity_criterion = f->has_zero_offsets() && o.is_zero(); + + + Offset current_off; + + // Save the neighbors and the offsets + Face_handle nb[3]; + int nb_index[3]; + int offsets[3]; + CGAL_triangulation_assertion_code( Vertex_handle vertices[3]; ) + + if (!simplicity_criterion) + { + // Choose the periodic copy of tester.point() that is inside c. + current_off = get_location_offset(f, p, o); + + CGAL_triangulation_assertion(oriented_side(f, p, combine_offsets(o, current_off)) != ON_NEGATIVE_SIDE); + + for (int i = 0; i < 3; ++i) + { + nb[i] = f->neighbor(i); + nb_index[i] = nb[i]->index(f); + offsets[i] = f->offset(i); + CGAL_triangulation_assertion_code( vertices[i] = f->vertex(i); ); + } + } + + // Insert the new vertex + Vertex_handle v = _tds.insert_in_face(f); + v->set_point(p); + + if (!simplicity_criterion) + { + // Update the offsets + int v_offset = off_to_int(current_off); + int new_offsets[3]; + for (int i = 0; i < 3; ++i) + { + Face_handle new_face = nb[i]->neighbor(nb_index[i]); + int v_index = new_face->index(v); + + CGAL_triangulation_assertion(new_face->vertex(ccw(v_index)) == vertices[ccw(i)]); + CGAL_triangulation_assertion(new_face->vertex(cw(v_index)) == vertices[cw(i)]); + + new_offsets[v_index] = v_offset; + new_offsets[ccw(v_index)] = offsets[ccw(i)]; + new_offsets[cw(v_index)] = offsets[cw(i)]; + set_offsets(new_face, new_offsets[0], new_offsets[1], new_offsets[2]); + } + } + + if (!is_1_cover()) + { + // update the book-keeping in case of a periodic copy + if (vh != Vertex_handle()) + { + _virtual_vertices[v] = Virtual_vertex(vh, o); + _virtual_vertices_reverse[vh].push_back(v); + } + + insert_too_long_edges_in_star(v); + } + + return v; +} + +template +typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle +Periodic_4_hyperbolic_triangulation_2::insert(const Point &p, Face_handle start) +{ + CGAL_triangulation_assertion((_domain.xmin() <= p.x()) && + (p.x() < _domain.xmax())); + CGAL_triangulation_assertion((_domain.ymin() <= p.y()) && + (p.y() < _domain.ymax())); + + if (number_of_stored_vertices() == 0) + { + return insert_first(p); + } + + if (start == Face_handle()) + { + start = faces_begin(); + } + + Locate_type lt; + int li; + Face_handle loc = locate(p, lt, li, start); + + if (start != Face_handle()) + { + CGAL_assertion(start->vertex(0) != Vertex_handle()); + } + return insert(p, lt, loc, li); +} + +template +typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle +Periodic_4_hyperbolic_triangulation_2::insert(const Point& p, + Locate_type lt, Face_handle loc, int li) +{ + if (number_of_stored_vertices() == 0) + { + return insert_first(p); + } + + // vstart is a vertex incident to the Face_handle start that will be used as + // for creating a start point for the virtual vertices. + // We use the virtual copies of a vertex incident to loc. + Vertex_handle vstart; + if (!is_1_cover()) + { + Virtual_vertex_map_it vvmit = _virtual_vertices.find(loc->vertex(0)); + if (vvmit == _virtual_vertices.end()) + { + vstart = loc->vertex(0); + } + else + { + vstart = vvmit->second.first; + } + + // vstart should be non-virtual, but should have virtual copies + CGAL_triangulation_assertion(_virtual_vertices.find(vstart) + == _virtual_vertices.end()); + CGAL_triangulation_assertion(_virtual_vertices_reverse.find(vstart) + != _virtual_vertices_reverse.end()); + } + + Vertex_handle vh = insert(p, Offset(), lt, loc, li, Vertex_handle()); + + // Don't add periodic copies if we are on the 1-cover + if (is_1_cover()) + return vh; + + // Don't continue if the point lies on a vertex as this will break the + // start_vertices array below. + if (lt == VERTEX) + return vh; + + const std::vector &start_vertices = + _virtual_vertices_reverse.find(vstart)->second; + CGAL_assertion(start_vertices.size() == size_t(number_of_sheets()[0] * number_of_sheets()[1] - 1)); + + for (int i = 0; i < number_of_sheets()[0]; i++) + { + for (int j = 0; j < number_of_sheets()[1]; j++) + { + if ((i != 0) || (j != 0)) + { + loc = start_vertices[i * 3 + j - 1]->face(); + Offset offset(i, j); + + loc = locate(p, offset, lt, li, loc); + + insert(p, offset, lt, loc, li, vh); + } + } + } + + return vh; +} + +template +typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle Periodic_4_hyperbolic_triangulation_2 < +Gt, Tds >::insert(const Point& p, const Offset &o, Locate_type lt, + Face_handle loc, int li, Vertex_handle vh) +// insert a point p, whose localization is known (lt, f, i) +{ + Vertex_handle result; + switch (lt) + { + case FACE: + { + result = insert_in_face(p, o, loc, vh); + break; + } + case EDGE: + { + result = insert_in_edge(p, o, loc, li, vh); + break; + } + case VERTEX: + { + // The vertex is a special case, we can return immediately + CGAL_assertion(vh == Vertex_handle()); + return loc->vertex(li); + } + case EMPTY: + { + result = insert_first(p); + break; + } + default: + { + CGAL_triangulation_assertion(false); // locate step failed + return Vertex_handle(); + } + } + + if (!is_1_cover() && (vh == Vertex_handle())) + { + _virtual_vertices_reverse[result] = std::vector(); + } + + return result; +} + +template +inline void Periodic_4_hyperbolic_triangulation_2::remove_degree_3(Vertex_handle v) +{ + CGAL_assertion(number_of_vertices() > 1); + CGAL_assertion(degree(v) == 3); + + if (is_1_cover()) + { + remove_degree_3_single_copy(v); + return; + } + + { + Virtual_vertex_map_it it = _virtual_vertices.find(v); + if (it != _virtual_vertices.end()) + { + v = it->second.first; + } + } + + remove_too_long_edges_in_star(v); + + typename Virtual_vertex_reverse_map::iterator reverse_it = + _virtual_vertices_reverse.find(v); + CGAL_assertion(reverse_it != _virtual_vertices_reverse.end()); + + const std::vector &virtual_copies = reverse_it->second; + for (typename std::vector::const_iterator it = virtual_copies.begin(); + it != virtual_copies.end(); ++it) + { + _virtual_vertices.erase(*it); + remove_degree_3_single_copy(*it); + } + + _virtual_vertices_reverse.erase(reverse_it); + remove_degree_3_single_copy(v); + +} + +template +inline void Periodic_4_hyperbolic_triangulation_2::remove_degree_3_single_copy(Vertex_handle vh) +{ + Face_handle f = vh->face(); + int i = ccw(f->index(vh)); + Face_handle f2 = f->neighbor(i); + int j = f2->index(f); + // Get the offsets in ccw order + Offset off[3]; + off[i] = get_offset(f, i); + off[ccw(i)] = get_offset(f, ccw(i)); + off[cw(i)] = combine_offsets(get_offset(f2, j), get_neighbor_offset(f2, j, f, i)); + if (off[0].x() < 0 || off[1].x() < 0 || off[2].x() < 0) + { + Offset o(number_of_sheets()[0], 0); + off[0] += o; + off[1] += o; + off[2] += o; + } + if (off[0].y() < 0 || off[1].y() < 0 || off[2].y() < 0) + { + Offset o(0, number_of_sheets()[1]); + off[0] += o; + off[1] += o; + off[2] += o; + } + + // Remove the vertex, keep face f + _tds.remove_degree_3(vh, f); + + // Reset the offsets + set_offsets(f, + (off[0].x() >= number_of_sheets()[0] ? 2 : 0) + (off[0].y() >= number_of_sheets()[1] ? 1 : 0), + (off[1].x() >= number_of_sheets()[0] ? 2 : 0) + (off[1].y() >= number_of_sheets()[1] ? 1 : 0), + (off[2].x() >= number_of_sheets()[0] ? 2 : 0) + (off[2].y() >= number_of_sheets()[1] ? 1 : 0)); +} + +template +inline void Periodic_4_hyperbolic_triangulation_2::remove_first(Vertex_handle) +{ + CGAL_assertion(number_of_vertices() == 1); + clear(); + return; +} + + +template < class Gt, class Tds > +bool +Periodic_4_hyperbolic_triangulation_2:: +remove_degree_init(Vertex_handle v, const Offset &v_o, + std::vector &f, + std::vector &w, + std::vector &offset_w, + std::vector &i, + int &d, int &maxd, + bool &simplicity_criterion) +{ + Bbox_2 bbox = v->point().bbox(); + simplicity_criterion = is_1_cover(); + + f[0] = v->face(); + d = 0; + + do + { + i[d] = f[d]->index(v); + w[d] = f[d]->vertex( ccw(i[d]) ); + offset_w[d] = get_offset(f[d], ccw(i[d])) - get_offset(f[d], i[d]) + v_o; + w[d]->set_face( f[d]->neighbor(i[d])); // do no longer bother about set_face + simplicity_criterion &= (offset_w[d] == offset_w[0]); + + bbox = bbox + this->construct_point(w[d]->point(), offset_w[d]).bbox(); + + ++d; + if ( d == maxd) + { + maxd *= 2; + f.resize(maxd); + w.resize(maxd); + offset_w.resize(maxd); + i.resize(maxd); + } + + f[d] = f[d - 1]->neighbor( ccw(i[d - 1]) ); + + } + while(f[d] != f[0]); + + return is_1_cover() && + this->edge_is_too_long(Point(bbox.xmin(), bbox.ymin()), Point(bbox.xmax(), bbox.ymax())); +} + +template +void Periodic_4_hyperbolic_triangulation_2::make_hole(Vertex_handle v, std::list & hole) +{ + remove_too_long_edges_in_star(v); + + std::list to_delete; + + Face_handle f, fn; + int i, in; + Vertex_handle vv; + + Face_circulator fc = incident_faces(v); + Face_circulator done(fc); + do + { + f = fc; + fc++; + i = f->index(v); + fn = f->neighbor(i); + in = fn->index(f); + vv = f->vertex(cw(i)); + if (vv->face() == f) + vv->set_face(fn); + vv = f->vertex(ccw(i)); + if (vv->face() == f) + vv->set_face(fn); + fn->set_neighbor(in, Face_handle()); + hole.push_back(Edge(fn, in)); + to_delete.push_back(f); + } + while (fc != done); + + while (!to_delete.empty()) + { + delete_face(to_delete.front()); + to_delete.pop_front(); + } + return; +} + +template +inline typename Periodic_4_hyperbolic_triangulation_2::Face_handle Periodic_4_hyperbolic_triangulation_2 < +Gt, Tds >::create_face(Face_handle f1, int i1, Face_handle f2, int i2, + Face_handle f3, int i3) +{ + return _tds.create_face(f1, i1, f2, i2, f3, i3); +} + +template +inline typename Periodic_4_hyperbolic_triangulation_2::Face_handle Periodic_4_hyperbolic_triangulation_2 < +Gt, Tds >::create_face(Face_handle f1, int i1, Face_handle f2, int i2) +{ + return _tds.create_face(f1, i1, f2, i2); +} + +template +inline typename Periodic_4_hyperbolic_triangulation_2::Face_handle Periodic_4_hyperbolic_triangulation_2 < +Gt, Tds >::create_face(Face_handle f, int i, Vertex_handle v) +{ + return _tds.create_face(f, i, v); +} + +template +inline typename Periodic_4_hyperbolic_triangulation_2::Face_handle Periodic_4_hyperbolic_triangulation_2 < +Gt, Tds >::create_face(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3) +{ + return _tds.create_face(v1, v2, v3); +} + +template +inline typename Periodic_4_hyperbolic_triangulation_2::Face_handle Periodic_4_hyperbolic_triangulation_2 < +Gt, Tds >::create_face(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3, + Face_handle f1, Face_handle f2, Face_handle f3) +{ + return _tds.create_face(v1, v2, v3, f1, f2, f3); +} + +template +inline typename Periodic_4_hyperbolic_triangulation_2::Face_handle Periodic_4_hyperbolic_triangulation_2 < +Gt, Tds >::create_face(Face_handle fh) +{ + return _tds.create_face(fh); +} + +template +inline typename Periodic_4_hyperbolic_triangulation_2::Face_handle Periodic_4_hyperbolic_triangulation_2 < +Gt, Tds >::create_face() +{ + return _tds.create_face(); +} + +template +inline +void Periodic_4_hyperbolic_triangulation_2::delete_face(Face_handle f) +{ + _tds.delete_face(f); +} + +template +inline +void Periodic_4_hyperbolic_triangulation_2::delete_vertex(Vertex_handle v) +{ + _tds.delete_vertex(v); +} + +template +bool Periodic_4_hyperbolic_triangulation_2::compare_walks(const Point& p, + Face_handle c1, Face_handle c2, Locate_type& lt1, Locate_type& lt2, + int li1, int li2) const +{ + bool b = true; + b &= (lt1 == lt2); + if ((lt1 == lt2) && (lt1 == VERTEX)) + { + b &= (c1->vertex(li1) == c2->vertex(li2)); + } + else if ((lt1 == lt2) && (lt1 == EDGE)) + { + b &= ((c1 == c2) + || ((c1->neighbor(li1) == c2) && (c2->neighbor(li2) == c1))); + } + else if ((lt1 == lt2) && (lt1 == EMPTY)) + { + // Skip + } + else + { + b &= (lt1 == lt2); + b &= (lt1 == FACE); + b &= (c1 == c2); + } + + if (!b) + { + std::cerr << "from compare_walks " << std::endl; + std::cerr << "point " << p << std::endl; + std::cerr << "locate 1 " << &*c1 << "\t" << lt1 << "\t" << li1 << std::endl; + std::cerr << "locate 2 " << &*c2 << "\t" << lt2 << "\t" << li2 << std::endl; + std::cerr << std::endl; + show_face(c1); + std::cerr << std::endl; + show_face(c2); + std::cerr << std::endl; + } + + CGAL_triangulation_assertion(b); + return b; +} + +template +typename Periodic_4_hyperbolic_triangulation_2::Face_handle +Periodic_4_hyperbolic_triangulation_2:: +march_locate_2D(Face_handle f, const Point& query, + const Offset& o_p, Locate_type& lt, int& li) const +{ + CGAL_assertion(!empty()); + + Offset off_query = o_p; + + // Random generator + boost::rand48 rng; + boost::uniform_smallint<> two(0, 1); + boost::variate_generator > coin(rng, two); + + // Give the point the best start-offset possible + if (is_1_cover() && !f->has_zero_offsets()) + { + int cumm_off = f->offset(0) | f->offset(1) | f->offset(2); + if (((cumm_off & 2) == 2) && + (FT(2) * query.x() < (_domain.xmax() + _domain.xmin()))) + off_query += Offset(1, 0); + if (((cumm_off & 1) == 1) && + (FT(2) * query.y() < (_domain.ymax() + _domain.ymin()))) + off_query += Offset(0, 1); + } + + Face_handle prev = Face_handle(); + int prev_index = 0; + Offset off[3]; + Orientation o[3]; + while (1) + { + // Instead of testing its edges in a random order we do the following + // until we find a neighbor to go further: + // As we come from prev we do not have to check the edge leading to prev + // Now we flip a coin in order to decide if we start checking the + // edge before or the edge after the edge leading to prev + int left_first = coin() % 2; + + bool simplicity_criterion = + f->has_zero_offsets() && off_query.is_null() && is_1_cover(); + + const Point *p[3] = + { + &f->vertex(0)->point(), + &f->vertex(1)->point(), + &f->vertex(2)->point() + }; + + // Get the offsets + if (!simplicity_criterion) + { + if (!is_1_cover()) + { + // Just fetch the vertices of c as points with offsets + for (int i = 0; i < 3; i++) + { + off[i] = get_offset(f, i); + } + } + else + { + // We are on the one cover and on the boundary between domains + // Hence, we need to check predicates with offsets + for (int i = 0; i < 3; i++) + { + off[i] = int_to_off(f->offset(i)); + } + } + } + + if (prev == Face_handle()) + { + prev = f; + // First step, also check the prev_index + if (simplicity_criterion) + { + o[ccw(prev_index)] = + orientation(*p[ccw(prev_index)], *p[cw(prev_index)], query); + } + else + { + o[ccw(prev_index)] = + orientation(*p[ccw(prev_index)], *p[cw(prev_index)], query, + off[ccw(prev_index)], off[cw(prev_index)], off_query); + } + if (o[ccw(prev_index)] == NEGATIVE) + { + // This assignment is already done: prev = f + f = f->neighbor(prev_index); + int new_index = f->index(prev); + if (!(simplicity_criterion && f->has_zero_offsets())) + off_query = combine_offsets(off_query, + get_neighbor_offset(prev, prev_index, + f, new_index)); + prev_index = new_index; + continue; + } + } + else + { + o[ccw(prev_index)] = POSITIVE; + } + + if (left_first) + { + if (simplicity_criterion) + { + o[prev_index] = + orientation(*p[prev_index], *p[ccw(prev_index)], query); + } + else + { + o[prev_index] = + orientation(*p[prev_index], *p[ccw(prev_index)], query, + off[prev_index], off[ccw(prev_index)], off_query); + } + if (o[prev_index] == NEGATIVE) + { + prev = f; + f = f->neighbor(cw(prev_index)); + int new_index = f->index(prev); + if (!(simplicity_criterion && f->has_zero_offsets())) + off_query = combine_offsets(off_query, + get_neighbor_offset(prev, cw(prev_index), f, new_index)); + prev_index = new_index; + continue; + } + } + { + // Do right side + if (simplicity_criterion) + { + o[cw(prev_index)] = + orientation(*p[cw(prev_index)], *p[prev_index], query); + } + else + { + o[cw(prev_index)] = + orientation(*p[cw(prev_index)], *p[prev_index], query, + off[cw(prev_index)], off[prev_index], off_query); + } + if (o[cw(prev_index)] == NEGATIVE) + { + prev = f; + f = f->neighbor(ccw(prev_index)); + int new_index = f->index(prev); + if (!(simplicity_criterion && f->has_zero_offsets())) + off_query = combine_offsets(off_query, + get_neighbor_offset(prev, ccw(prev_index), f, new_index)); + prev_index = new_index; + continue; + } + } + if (!left_first) + { + if (simplicity_criterion) + { + o[prev_index] = orientation(*p[prev_index], *p[ccw(prev_index)], query); + } + else + { + o[prev_index] = orientation(*p[prev_index], *p[ccw(prev_index)], query, + off[prev_index], off[ccw(prev_index)], off_query); + } + if (o[prev_index] == NEGATIVE) + { + prev = f; + f = f->neighbor(cw(prev_index)); + int new_index = f->index(prev); + if (!(simplicity_criterion && f->has_zero_offsets())) + off_query = combine_offsets(off_query, + get_neighbor_offset(prev, cw(prev_index), f, new_index)); + prev_index = new_index; + continue; + } + } + + // now p is in c or on its boundary + int sum = (o[0] == COLLINEAR) + (o[1] == COLLINEAR) + (o[2] == COLLINEAR); + switch (sum) + { + case 0: + { + lt = FACE; + li = 4; + break; + } + case 1: + { + lt = EDGE; + li = (o[0] == COLLINEAR) ? 2 : (o[1] == COLLINEAR) ? 0 : 1; + break; + } + case 2: + { + lt = VERTEX; + li = (o[0] != COLLINEAR) ? 2 : (o[1] != COLLINEAR) ? 0 : 1; + break; + } + } + return f; + } +} + +template +typename Periodic_4_hyperbolic_triangulation_2::Face_handle Periodic_4_hyperbolic_triangulation_2 < +Gt, Tds >::locate(const Point& p, const Offset &o, Locate_type& lt, int& li, + Face_handle start) const +{ + CGAL_triangulation_assertion((_domain.xmin() <= p.x()) && + (p.x() < _domain.xmax())); + CGAL_triangulation_assertion((_domain.ymin() <= p.y()) && + (p.y() < _domain.ymax())); + + if (dimension() <= 0) + { + lt = EMPTY; + li = 4; + return Face_handle(); + } + + // Triangulation is not empty + if (start == Face_handle()) + { + start = faces_begin(); + } + + return march_locate_2D(start, p, o, lt, li); +} + +/** Delete each redundant face and the not anymore needed data + * structures. + * + * This function consists of four iterations over all faces and one + * iteration over all vertices: + * -# Face iteration: mark all faces that are to delete + * -# Face iteration: redirect neighbors of remaining faces + * -# Face iteration: redirect vertices of remaining faces + * -# Face iteration: delete all faces marked in the 1. iteration + * -# Vertex iteration: delete all vertices outside the original domain. + */ +template +void Periodic_4_hyperbolic_triangulation_2::convert_to_1_sheeted_covering() +{ + // ################################################################### + // ### First face iteration ########################################## + // ################################################################### + { + if (is_1_cover()) + return; + CGAL_triangulation_expensive_assertion(is_triangulation_in_1_sheet()); + + bool to_delete, has_simplifiable_offset; + Virtual_vertex_map_it vvmit; + // First iteration over all faces: Mark the faces that are to delete. + // Faces are to delete if they cannot be translated anymore in the + // direction of one of the axes without yielding negative offsets. + for (Face_iterator it = all_faces_begin(); it != all_faces_end(); ++it) + { + to_delete = false; + // for all directions in 2D Space + for (int j = 0; j < 2; j++) + { + has_simplifiable_offset = true; + // for all vertices of face it + for (int i = 0; i < 3; i++) + { + vvmit = _virtual_vertices.find(it->vertex(i)); + if (vvmit == _virtual_vertices.end()) + { + // if it->vertex(i) lies inside the original domain: + + // the face cannot be moved any more because if we did, then + // it->vertex(i) will get at least one negative offset. + has_simplifiable_offset = false; + } + else + { + // if it->vertex(i) lies outside the original domain: + + // The face can certainly be deleted if the offset contains a 2 + to_delete |= (vvmit->second.second[j] == 2); + // The face can be moved into one direction only if the offset of + // all for vertices is >=1 for this direction. Since we already + // tested for 2 it is sufficient to test here for 1. + has_simplifiable_offset &= (vvmit->second.second[j] == 1); + } + } + // if the offset can be simplified, i.e. the face can be moved, then + // it can be deleted. + if (has_simplifiable_offset) + to_delete = true; + } + // Mark all faces that are to delete. They cannot be deleted yet, + // because neighboring information still needs to be extracted. + it->set_additional_flag(to_delete ? 1 : 0); + } + } + + // ################################################################### + // ### Second face iteration ######################################### + // ################################################################### + { + Vertex_handle vert[3], nbv[3]; + Offset off[3]; + Face_handle nb, new_neighbor; + std::vector > new_neighbor_relations; + + // Second iteration over all faces: redirect neighbors where necessary + for (Face_iterator it = all_faces_begin(); it != all_faces_end(); ++it) + { + // Skip all faces that are to delete. + if (it->get_additional_flag() == 1) + continue; + + // Redirect neighbors: Only neighbors that are marked by the + // additional_flag have to be substituted by one of their periodic + // copies. The unmarked neighbors stay the same. + for (int i = 0; i < 3; i++) + { + if (it->neighbor(i)->get_additional_flag() != 1) + continue; + + nb = it->neighbor(i); + + for (int j = 0; j < 3; j++) + { + off[j] = Offset(); + get_vertex(nb, j, vert[j], off[j]); + } + int x, y; + x = (std::min)((std::min)(off[0][0], off[1][0]), off[2][0]); + y = (std::min)((std::min)(off[0][1], off[1][1]), off[2][1]); + + // The vector from nb to the "original" periodic copy of nb, that is + // the copy that will not be deleted. + Offset difference_offset(x, y); + CGAL_triangulation_assertion( !difference_offset.is_null() ); + + // We now have to find the "original" periodic copy of nb from + // its vertices. Therefore, we first have to find the vertices. + for (int j = 0; j < 3; j++) + { + CGAL_triangulation_assertion( (off[j] - difference_offset)[0] >= 0); + CGAL_triangulation_assertion( (off[j] - difference_offset)[1] >= 0); + CGAL_triangulation_assertion( (off[j] - difference_offset)[0] < 3); + CGAL_triangulation_assertion( (off[j] - difference_offset)[1] < 3); + + // find the Vertex_handles of the vertices of the "original" + // periodic copy of nb. If the vertex is inside the original + // domain, there is nothing to do + if ((off[j] - difference_offset).is_null()) + { + nbv[j] = vert[j]; + // If the vertex is outside the original domain, we have to search + // in _virtual_vertices in the "wrong" direction. That means, we + // cannot use _virtual_vertices.find but have to use + // _virtual_vertices_reverse. + } + else + { + Offset nbo = off[j] - difference_offset; + nbv[j] = _virtual_vertices_reverse.find(vert[j]) ->second[nbo[0] + * 3 + nbo[1] - 1]; + } + } + // Find the new neighbor by its 4 vertices + new_neighbor = get_face(nbv); + + // Store the new neighbor relation. This cannot be applied yet because + // it would disturb the functioning of get_face( ... ) + new_neighbor_relations.push_back(make_triple(it, i, new_neighbor)); + } + } + // Apply the new neighbor relations now. + for (unsigned int i = 0; i < new_neighbor_relations.size(); i++) + { + new_neighbor_relations[i].first->set_neighbor( + new_neighbor_relations[i].second, new_neighbor_relations[i].third); + } + } + + // ################################################################### + // ### Third face iteration ########################################## + // ################################################################### + { + Vertex_handle vert[3]; + Offset off[3]; + // Third iteration over all faces: redirect vertices where necessary + for (Face_iterator it = all_faces_begin(); it != all_faces_end(); ++it) + { + // Skip all faces that are marked to delete + if (it->get_additional_flag() == 1) + continue; + // Find the corresponding vertices of it in the original domain + // and set them as new vertices of it. + for (int i = 0; i < 3; i++) + { + off[i] = Offset(); + get_vertex(it, i, vert[i], off[i]); + it->set_vertex(i, vert[i]); + CGAL_triangulation_assertion(vert[i]->point()[0] < _domain.xmax()); + CGAL_triangulation_assertion(vert[i]->point()[1] < _domain.ymax()); + CGAL_triangulation_assertion(vert[i]->point()[0] >= _domain.xmin()); + CGAL_triangulation_assertion(vert[i]->point()[1] >= _domain.ymin()); + + // redirect also the face pointer of the vertex. + it->vertex(i)->set_face(it); + } + // Set the offsets. + set_offsets(it, off[0], off[1], off[2]); + CGAL_triangulation_assertion( int_to_off(it->offset(0)) == off[0] ); + CGAL_triangulation_assertion( int_to_off(it->offset(1)) == off[1] ); + CGAL_triangulation_assertion( int_to_off(it->offset(2)) == off[2] ); + } + } + + // ################################################################### + // ### Fourth face iteration ######################################### + // ################################################################### + { + // Delete the marked faces. + std::vector faces_to_delete; + for (Face_iterator fit = all_faces_begin(); fit != all_faces_end(); ++fit) + { + if (fit->get_additional_flag() == 1) + faces_to_delete.push_back(fit); + } + for (typename std::vector::iterator it = + faces_to_delete.begin(); it != faces_to_delete.end(); ++it) + { + _tds.delete_face(*it); + } + } + + // ################################################################### + // ### Vertex iteration ############################################## + // ################################################################### + { + // Delete all the vertices in _virtual_vertices, that is all vertices + // outside the original domain. + std::vector vertices_to_delete; + for (Vertex_iterator vit = all_vertices_begin(); vit != all_vertices_end(); ++vit) + { + if (_virtual_vertices.count(vit) != 0) + { + CGAL_triangulation_assertion( _virtual_vertices.count( vit ) == 1 ); + vertices_to_delete.push_back(vit); + } + } + for (typename std::vector::iterator it = + vertices_to_delete.begin(); it != vertices_to_delete.end(); ++it) + { + _tds.delete_vertex(*it); + } + } + + _cover = make_array(1, 1); + _virtual_vertices.clear(); + _virtual_vertices_reverse.clear(); + _too_long_edge_counter = 0; + _too_long_edges.clear(); + + CGAL_triangulation_assertion(is_1_cover()); +} + +template +void Periodic_4_hyperbolic_triangulation_2::convert_to_9_sheeted_covering() +{ + if (_cover == make_array(3, 3)) + return; + CGAL_triangulation_precondition(is_1_cover()); + + // Create 9 copies of each vertex and write virtual_vertices and + // virtual_vertices_reverse + std::list original_vertices; + // try to use std::copy instead of the following loop. + for (Vertex_iterator vit = vertices_begin(); vit != vertices_end(); ++vit) + original_vertices.push_back(vit); + for (typename std::list::iterator vit = + original_vertices.begin(); vit != original_vertices.end(); ++vit) + { + Vertex_handle v_cp; + std::vector copies; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + { + if (i == 0 && j == 0) + continue; + v_cp = _tds.create_vertex(*vit); + copies.push_back(v_cp); + _virtual_vertices.insert(std::make_pair(v_cp, std::make_pair(*vit, + Offset(i, j)))); + } + _virtual_vertices_reverse.insert(std::make_pair(*vit, copies)); + } + + // Create 9 copies of each face from the respective copies of the + // vertices and write virtual_faces and virtual_faces_reverse. + typedef std::map > + Virtual_face_map; + typedef std::map > + Virtual_face_reverse_map; + typedef typename Virtual_face_reverse_map::const_iterator VCRMIT; + + Virtual_face_map virtual_faces; + Virtual_face_reverse_map virtual_faces_reverse; + + std::list original_faces; + for (Face_iterator fit = faces_begin(); fit != faces_end(); ++fit) + original_faces.push_back(fit); + + // Store vertex offsets in a separate data structure + std::list off_v; + for (typename std::list::iterator vit = + original_vertices.begin(); vit != original_vertices.end(); ++vit) + { + Face_handle ccc = (*vit)->face(); + int v_index = ccc->index(*vit); + off_v.push_back(int_to_off(ccc->offset(v_index))); + } + + // Store neighboring offsets in a separate data structure + std::list > off_nb; + for (typename std::list::iterator fit = original_faces.begin(); fit + != original_faces.end(); ++fit) + { + array off_nb_f; + for (int i = 0; i < 3; i++) + { + Face_handle fff = *fit; + Face_handle nnn = fff->neighbor(i); + off_nb_f[i] = get_neighbor_offset(fff, i, nnn, nnn->index(fff)); + } + off_nb.push_back(off_nb_f); + } + + // Create copies of faces + for (typename std::list::iterator fit = original_faces.begin(); fit + != original_faces.end(); ++fit) + { + Face_handle c_cp; + Vertex_handle v0, v1, v2; + std::vector copies; + Virtual_vertex_reverse_map_it vvrmit[3]; + Offset vvoff[3]; + for (int i = 0; i < 3; i++) + { + vvrmit[i] = _virtual_vertices_reverse.find((*fit)->vertex(i)); + CGAL_triangulation_assertion( + vvrmit[i] != _virtual_vertices_reverse.end()); + vvoff[i] = int_to_off((*fit)->offset(i)); + } + Vertex_handle vvh[3]; + for (int n = 0; n < 8; n++) // iterate over faces + { + for (int i = 0; i < 3; i++) // iterate over vertices of the face + { + // Decomposition of n into an offset (nx,ny): + // nx = ((n+1)/3)%3, ny = (n+1)%3 + int o_i = ((n + 1) / 3 + vvoff[i].x() + 3) % 3; + int o_j = ((n + 1) + vvoff[i].y() + 3) % 3; + int n_c = 3 * o_i + o_j - 1; + CGAL_triangulation_assertion(n_c >= -1); + if (n_c == -1) + vvh[i] = (*fit)->vertex(i); + else + vvh[i] = vvrmit[i]->second[n_c]; + } + c_cp = _tds.create_face(vvh[0], vvh[1], vvh[2]); + copies.push_back(c_cp); + } + virtual_faces_reverse.insert(std::make_pair(*fit, copies)); + } + + // Set new vertices of boundary faces of the original domain. + for (typename std::list::iterator fit = original_faces.begin(); fit + != original_faces.end(); ++fit) + { + for (int i = 0; i < 3; i++) + { + Virtual_vertex_reverse_map_it vvrmit = _virtual_vertices_reverse.find( + (*fit)->vertex(i)); + CGAL_triangulation_assertion(vvrmit != _virtual_vertices_reverse.end()); + Offset vvoff = int_to_off((*fit)->offset(i)); + if (!vvoff.is_null()) + { + int n_f = 3 * vvoff.x() + vvoff.y() - 1; + CGAL_triangulation_assertion(n_f >= 0); + CGAL_triangulation_assertion(static_cast(n_f) < vvrmit->second.size()); + (*fit)->set_vertex(i, vvrmit->second[n_f]); + } + } + } + + // Set neighboring relations of face copies + typename std::list >::iterator oit = off_nb.begin(); + for (typename std::list::iterator fit = original_faces.begin(); fit + != original_faces.end(); ++fit, ++oit) + { + CGAL_triangulation_assertion( oit != off_nb.end() ); + VCRMIT c_cp = virtual_faces_reverse.find(*fit); + CGAL_triangulation_assertion(c_cp != virtual_faces_reverse.end()); + for (int i = 0; i < 3; i++) + { + Face_handle fit_nb = (*fit)->neighbor(i); + VCRMIT c_cp_nb = virtual_faces_reverse.find(fit_nb); + CGAL_triangulation_assertion(c_cp_nb != virtual_faces_reverse.end()); + Offset nboff = (*oit)[i]; + for (int n = 0; n < 8; n++) + { + int n_nb; + if (nboff.is_null()) + n_nb = n; + else + { + int o_i = ((n + 1) / 3 - nboff.x() + 3) % 3; + int o_j = (n + 1 - nboff.y() + 3) % 3; + n_nb = 3 * o_i + o_j - 1; + } + if (n_nb == -1) + { + CGAL_triangulation_assertion(fit_nb->has_vertex(c_cp->second[n]->vertex(ccw(i))) ); + CGAL_triangulation_assertion(fit_nb->has_vertex(c_cp->second[n]->vertex( cw(i))) ); + c_cp->second[n]->set_neighbor(i, fit_nb); + } + else + { + CGAL_triangulation_assertion(n_nb >= 0); + CGAL_triangulation_assertion(static_cast(n_nb) <= c_cp_nb->second.size()); + CGAL_triangulation_assertion(c_cp_nb->second[n_nb]->has_vertex(c_cp->second[n]->vertex(ccw(i))) ); + CGAL_triangulation_assertion(c_cp_nb->second[n_nb]->has_vertex(c_cp->second[n]->vertex( cw(i))) ); + c_cp->second[n]->set_neighbor(i, c_cp_nb->second[n_nb]); + } + } + } + } + + // Set neighboring relations of original faces + oit = off_nb.begin(); + for (typename std::list::iterator fit = original_faces.begin(); fit + != original_faces.end(); ++fit, ++oit) + { + CGAL_triangulation_assertion( oit != off_nb.end() ); + for (int i = 0; i < 3; i++) + { + Offset nboff = (*oit)[i]; + if (!nboff.is_null()) + { + Face_handle fit_nb = (*fit)->neighbor(i); + VCRMIT c_cp_nb = virtual_faces_reverse.find(fit_nb); + CGAL_triangulation_assertion(c_cp_nb != virtual_faces_reverse.end()); + int o_i = (3 - nboff.x()) % 3; + int o_j = (3 - nboff.y()) % 3; + int n_nb = 3 * o_i + o_j - 1; + CGAL_triangulation_assertion(n_nb >= 0); + CGAL_triangulation_assertion(static_cast(n_nb) <= c_cp_nb->second.size()); + CGAL_triangulation_assertion(c_cp_nb->second[n_nb]->has_vertex((*fit)->vertex(ccw(i))) ); + CGAL_triangulation_assertion(c_cp_nb->second[n_nb]->has_vertex((*fit)->vertex( cw(i))) ); + (*fit)->set_neighbor(i, c_cp_nb->second[n_nb]); + } + } + } + + // Set incident faces + for (Face_iterator fit = faces_begin(); fit != faces_end(); ++fit) + { + for (int i = 0; i < 3; i++) + { + fit->vertex(i)->set_face(fit); + } + } + + // Set offsets where necessary + for (typename std::list::iterator fit = original_faces.begin(); fit + != original_faces.end(); ++fit) + { + VCRMIT c_cp = virtual_faces_reverse.find(*fit); + CGAL_triangulation_assertion( c_cp != virtual_faces_reverse.end()); + Offset off[3]; + for (int i = 0; i < 3; i++) + off[i] = int_to_off((*fit)->offset(i)); + if (off[0].is_null() && off[1].is_null() && off[2].is_null()) + continue; + for (int n = 0; n < 8; n++) + { + Offset off_cp[4]; + int o_i = ((n + 1) / 3) % 3; + int o_j = (n + 1) % 3; + if (o_i != 2 && o_j != 2) + continue; + for (int i = 0; i < 3; i++) + { + off_cp[i] = Offset((o_i == 2) ? off[i].x() : 0, (o_j == 2) ? off[i].y() + : 0); + CGAL_triangulation_assertion(off_cp[i].x() == 0 || off_cp[i].x() == 1); + CGAL_triangulation_assertion(off_cp[i].y() == 0 || off_cp[i].y() == 1); + } + set_offsets(c_cp->second[n], off_cp[0], off_cp[1], off_cp[2]); + } + } + + // Iterate over all original faces and reset offsets. + for (typename std::list::iterator fit = original_faces.begin(); fit + != original_faces.end(); ++fit) + { + //This statement does not seem to have any effect + set_offsets(*fit, 0, 0, 0); + CGAL_triangulation_assertion((*fit)->offset(0) == 0); + CGAL_triangulation_assertion((*fit)->offset(1) == 0); + CGAL_triangulation_assertion((*fit)->offset(2) == 0); + } + + _cover = make_array(3, 3); + + // Set up too long edges data structure + int i = 0; + for (Vertex_iterator vit = vertices_begin(); vit != vertices_end(); ++vit) + { + _too_long_edges[vit] = std::list(); + ++i; + } + _too_long_edge_counter = find_too_long_edges(_too_long_edges); + + CGAL_triangulation_expensive_assertion(is_valid()); + + CGAL_triangulation_assertion(!is_1_cover()); +} + +// iterate over all edges and store the ones that are longer than +// edge_length_threshold in edges. Return the number of too long edges. +template +inline int Periodic_4_hyperbolic_triangulation_2::find_too_long_edges(std::map < + Vertex_handle, std::list > & edges) const +{ + Point p1, p2; + int counter = 0; + Vertex_handle v_no, vh; + for (Edge_iterator eit = edges_begin(); eit != edges_end(); eit++) + { + p1 = construct_point(eit->first->vertex(ccw(eit->second))->point(), + get_offset(eit->first, ccw(eit->second))); + p2 = construct_point(eit->first->vertex(cw(eit->second))->point(), + get_offset(eit->first, cw(eit->second))); + if (edge_is_too_long(p1, p2)) + { + if (&*(eit->first->vertex(ccw(eit->second))) < &*(eit->first->vertex(cw( + eit->second)))) + { + v_no = eit->first->vertex(ccw(eit->second)); + vh = eit->first->vertex(cw(eit->second)); + } + else + { + v_no = eit->first->vertex(cw(eit->second)); + vh = eit->first->vertex(ccw(eit->second)); + } + edges[v_no].push_back(vh); + counter++; + } + } + return counter; +} + +/** + * - fh->offset(i) is an bit tuple encapsulated in an integer. Each bit + * represents the offset in one direction --> 2-cover! + * - int_to_off(int) decodes this again. + * - Finally the offset vector is multiplied by cover. + * So if we are working in 3-cover we translate it to the neighboring + * 3-cover and not only to the neighboring domain. + */ +template +inline void Periodic_4_hyperbolic_triangulation_2::get_vertex(Face_handle fh, + int i, Vertex_handle &vh, Offset &off) const +{ + off = combine_offsets(Offset(), int_to_off(fh->offset(i))); + vh = fh->vertex(i); + + if (is_1_cover()) + return; + Vertex_handle vh_i = vh; + get_vertex(vh_i, vh, off); + return; +} + +template +inline void Periodic_4_hyperbolic_triangulation_2::get_vertex(Vertex_handle vh_i, + Vertex_handle &vh, Offset &off) const +{ + Virtual_vertex_map_it it = _virtual_vertices.find(vh_i); + + if (it == _virtual_vertices.end()) + { + // if vh_i is not contained in virtual_vertices, then it is in the + // original domain. + vh = vh_i; + CGAL_triangulation_assertion(vh != Vertex_handle()); + } + else + { + // otherwise it has to be looked up as well as its offset. + vh = it->second.first; + off += it->second.second; + CGAL_triangulation_assertion(vh->point().x() < _domain.xmax()); + CGAL_triangulation_assertion(vh->point().y() < _domain.ymax()); + CGAL_triangulation_assertion(vh->point().x() >= _domain.xmin()); + CGAL_triangulation_assertion(vh->point().y() >= _domain.ymin()); + } +} + +/** Find the Face that consists of the three given vertices + * + * Iterates over all faces and compare the three vertices of each face + * with the three vertices in vh. + */ +template +inline typename Periodic_4_hyperbolic_triangulation_2::Face_handle Periodic_4_hyperbolic_triangulation_2 < +GT, Tds >::get_face(const Vertex_handle* vh) const +{ + bool contains_v[2]; + Face_circulator fc = incident_faces(vh[2]); + Face_circulator done(fc); + do + { + CGAL_triangulation_assertion( + fc->vertex(0) == vh[2] || + fc->vertex(1) == vh[2] || + fc->vertex(2) == vh[2]); + for (int j = 0; j < 2; j++) + { + contains_v[j] = (fc->vertex(0) == vh[j]) || (fc->vertex(1) == vh[j]) + || (fc->vertex(2) == vh[j]); + } + if (contains_v[0] && contains_v[1]) + { + return fc; + } + } + while (++fc != done); + + CGAL_triangulation_assertion(false); + return Face_handle(); +} + +template +Bounded_side Periodic_4_hyperbolic_triangulation_2::side_of_face(const Point &q, + const Offset &off, Face_handle f, Locate_type <, int &li) const +{ + CGAL_triangulation_precondition(number_of_vertices() != 0); + + Orientation o0, o1, o2; + o0 = o1 = o2 = ZERO; + int cumm_off = f->offset(0) | f->offset(1) | f->offset(2); + + if ((cumm_off == 0) && is_1_cover()) + { + CGAL_triangulation_assertion(off == Offset()); + + const Point &p0 = f->vertex(0)->point(); + const Point &p1 = f->vertex(1)->point(); + const Point &p2 = f->vertex(2)->point(); + + if (((o0 = orientation(q, p1, p2)) == NEGATIVE) || ((o1 = orientation(p0, + q, p2)) == NEGATIVE) || ((o2 = orientation(p0, p1, q)) == NEGATIVE)) + { + return ON_UNBOUNDED_SIDE; + } + } + else // Special case for the periodic space. + { + Offset off_q; + Offset offs[3]; + const Point *p[3]; + for (int i = 0; i < 3; i++) + { + p[i] = &(f->vertex(i)->point()); + offs[i] = get_offset(f, i); + } + CGAL_triangulation_assertion(orientation(*p[0], *p[1], *p[2], + offs[0], offs[1], offs[2]) == POSITIVE); + bool found = false; + for (int i = 0; (i < 4) && (!found); i++) + { + if ((cumm_off | ((~i) & 3)) == 3) + { + o0 = o1 = o2 = NEGATIVE; + off_q = combine_offsets(off, int_to_off(i)); + + if (((o0 = orientation(q, *p[1], *p[2], off_q, offs[1], offs[2])) + != NEGATIVE) && ((o1 = orientation(*p[0], q, *p[2], offs[0], off_q, + offs[2])) != NEGATIVE) && ((o2 = orientation(*p[0], *p[1], q, + offs[0], offs[1], off_q)) != NEGATIVE)) + { + found = true; + } + } + } + if (!found) + return ON_UNBOUNDED_SIDE; + } + + // now all the oi's are >=0 + // sum gives the number of facets p lies on + int sum = ((o0 == ZERO) ? 1 : 0) + ((o1 == ZERO) ? 1 : 0) + ((o2 == ZERO) ? 1 + : 0); + + switch (sum) + { + case 0: + { + lt = FACE; + return ON_BOUNDED_SIDE; + } + case 1: + { + lt = EDGE; + // i = index such that q lies on edge (f,li) + li = (o0 == ZERO) ? 0 : (o1 == ZERO) ? 1 : 2; + return ON_BOUNDARY; + } + case 2: + { + lt = VERTEX; + // i = index such that q lies on vertex li + li = (o0 != ZERO) ? 0 : (o1 != ZERO) ? 1 : 2; + return ON_BOUNDARY; + } + default: + { + // impossible : cannot be on 3 edges for a real triangle + CGAL_triangulation_assertion(false); + return ON_BOUNDARY; + } + } +} + +template +Oriented_side Periodic_4_hyperbolic_triangulation_2::oriented_side(Face_handle f, + const Point& p, const Offset &o) const +{ + Point &p0 = f->vertex(0)->point(); + Point &p1 = f->vertex(1)->point(); + Point &p2 = f->vertex(2)->point(); + + int cumm_off = f->offset(0) | f->offset(1) | f->offset(2); + + if ((cumm_off == 0) && is_1_cover()) + { + CGAL_precondition(o == Offset()); + + // return position of point p with respect to the oriented triangle p0p1p2 + // the orientation of the vertices is assumed to be counter clockwise + CGAL_assertion(orientation(p0, p1, p2) == LEFT_TURN); + + Bounded_side bs = bounded_side(p0, p1, p2, p); + switch (bs) + { + case ON_BOUNDARY: + return ON_ORIENTED_BOUNDARY; + case ON_BOUNDED_SIDE: + return ON_POSITIVE_SIDE; + case ON_UNBOUNDED_SIDE: + return ON_NEGATIVE_SIDE; + } + } + else // Special case for the periodic space. + { + Offset off_q; + Offset off0 = get_offset(f, 0); + Offset off1 = get_offset(f, 1); + Offset off2 = get_offset(f, 2); + + // return position of point p with respect to the oriented triangle p0p1p2 + // the orientation of the vertices is assumed to be counter clockwise + CGAL_assertion(orientation(p0, p1, p2, off0, off1, off2) == LEFT_TURN); + + Bounded_side bs; + for (int i = 0; (i <= 7); i++) + { + if ((cumm_off | ((~i) & 3)) == 3) + { + off_q = combine_offsets(o, int_to_off(i)); + bs = bounded_side(p0, p1, p2, p, off0, off1, off2, off_q); + if (bs != ON_UNBOUNDED_SIDE) + { + return (bs == ON_BOUNDARY ? ON_ORIENTED_BOUNDARY : ON_POSITIVE_SIDE); + } + } + } + + return ON_NEGATIVE_SIDE; + } + + CGAL_assertion(false); + return ON_NEGATIVE_SIDE; +} + +template +Bounded_side Periodic_4_hyperbolic_triangulation_2::bounded_side(const Point &p0, const Point &p1, const Point &p2, const Point &p) const +{ + + // return position of point p with respect to triangle p0p1p2 + CGAL_triangulation_precondition( orientation(p0, p1, p2) != COLLINEAR); + + Orientation o1 = orientation(p0, p1, p); + Orientation o2 = orientation(p1, p2, p); + Orientation o3 = orientation(p2, p0, p); + + if (o1 == COLLINEAR) + { + if (o2 == COLLINEAR || o3 == COLLINEAR) + return ON_BOUNDARY; + if (collinear_between(p0, p, p1)) + return ON_BOUNDARY; + return ON_UNBOUNDED_SIDE; + } + + if (o2 == COLLINEAR) + { + if (o3 == COLLINEAR) + return ON_BOUNDARY; + if (collinear_between(p1, p, p2)) + return ON_BOUNDARY; + return ON_UNBOUNDED_SIDE; + } + + if (o3 == COLLINEAR) + { + if (collinear_between(p2, p, p0)) + return ON_BOUNDARY; + return ON_UNBOUNDED_SIDE; + } + + // from here none ot, o1, o2 and o3 are known to be non null + if (o1 == o2 && o2 == o3) + return ON_BOUNDED_SIDE; + return ON_UNBOUNDED_SIDE; +} + +template +Bounded_side Periodic_4_hyperbolic_triangulation_2::bounded_side(const Point &p0, + const Point &p1, const Point &p2, const Point &p, const Offset &o0, + const Offset &o1, const Offset &o2, const Offset &o) const +{ + // return position of point p with respect to triangle p0p1p2 + CGAL_triangulation_precondition( orientation(p0, p1, p2, o0, o1, o2) != COLLINEAR); + Orientation orient1 = orientation(p0, p1, p, o0, o1, o); + Orientation orient2 = orientation(p1, p2, p, o1, o2, o); + Orientation orient3 = orientation(p2, p0, p, o2, o0, o); + + if (orient1 == COLLINEAR) + { + if (orient2 == COLLINEAR || orient3 == COLLINEAR) + return ON_BOUNDARY; + if (collinear_between(p0, p, p1, o0, o, o1)) + return ON_BOUNDARY; + return ON_UNBOUNDED_SIDE; + } + + if (orient2 == COLLINEAR) + { + if (orient3 == COLLINEAR) + return ON_BOUNDARY; + if (collinear_between(p1, p, p2, o1, o, o2)) + return ON_BOUNDARY; + return ON_UNBOUNDED_SIDE; + } + + if (orient3 == COLLINEAR) + { + if (collinear_between(p2, p, p0, o2, o, o0)) + return ON_BOUNDARY; + return ON_UNBOUNDED_SIDE; + } + + // from here none ot, o1, o2 and o3 are known to be non null + if (orient1 == orient2 && orient2 == orient3) + return ON_BOUNDED_SIDE; + return ON_UNBOUNDED_SIDE; +} + + +template +bool Periodic_4_hyperbolic_triangulation_2::collinear_between(const Point& p, + const Point& q, const Point& r) const +{ + // return true if point q is strictly between p and r + // p,q and r are supposed to be collinear points + Comparison_result c_pr = compare_x(p, r); + Comparison_result c_pq; + Comparison_result c_qr; + if(c_pr == EQUAL) + { + c_pq = compare_y(p, q); + c_qr = compare_y(q, r); + } + else + { + c_pq = compare_x(p, q); + c_qr = compare_x(q, r); + } + return ( (c_pq == SMALLER) && (c_qr == SMALLER) ) || + ( (c_pq == LARGER) && (c_qr == LARGER) ); + +} + +template +bool Periodic_4_hyperbolic_triangulation_2::collinear_between(const Point& p, + const Point& q, const Point& r, const Offset& o_p, const Offset& o_q, + const Offset& o_r) const +{ + // return true if point q is strictly between p and r + // p,q and r are supposed to be collinear points + Comparison_result c_pr = compare_x(p, r, o_p, o_r); + Comparison_result c_pq; + Comparison_result c_qr; + if (c_pr == EQUAL) + { + c_pq = compare_y(p, q, o_p, o_q); + c_qr = compare_y(q, r, o_q, o_r); + } + else + { + c_pq = compare_x(p, q, o_p, o_q); + c_qr = compare_x(q, r, o_q, o_r); + } + return (((c_pq == SMALLER) && (c_qr == SMALLER)) || + ((c_pq == LARGER) && (c_qr == LARGER))); +} + +template +inline Comparison_result Periodic_4_hyperbolic_triangulation_2::compare_x( + const Point& p, const Point& q) const +{ + return geom_traits().compare_x_2_object()(p, q); +} + +template +inline Comparison_result Periodic_4_hyperbolic_triangulation_2::compare_x( + const Point& p, const Point& q, const Offset &o_p, const Offset &o_q) const +{ + return geom_traits().compare_x_2_object()(p, q, o_p, o_q); +} + +template +inline Comparison_result Periodic_4_hyperbolic_triangulation_2::compare_xy( + const Point& p, const Point& q) const +{ + Comparison_result res = geom_traits().compare_x_2_object()(p, q); + if (res == EQUAL) + { + return geom_traits().compare_y_2_object()(p, q); + } + return res; +} + +template +inline Comparison_result Periodic_4_hyperbolic_triangulation_2::compare_xy( + const Point& p, const Point& q, const Offset &o_p, const Offset &o_q) const +{ + Comparison_result res = geom_traits().compare_x_2_object()(p, q, o_p, o_q); + if (res == EQUAL) + { + return geom_traits().compare_y_2_object()(p, q, o_p, o_q); + } + return res; +} + +template +inline Comparison_result Periodic_4_hyperbolic_triangulation_2::compare_y( + const Point& p, const Point& q) const +{ + return geom_traits().compare_y_2_object()(p, q); +} + +template +inline Comparison_result Periodic_4_hyperbolic_triangulation_2::compare_y( + const Point& p, const Point& q, const Offset &o_p, const Offset &o_q) const +{ + return geom_traits().compare_y_2_object()(p, q, o_p, o_q); +} + +template +inline +bool Periodic_4_hyperbolic_triangulation_2::xy_equal(const Point& p, + const Point& q) const +{ + return compare_xy(p, q) == EQUAL; +} + +template +inline Orientation Periodic_4_hyperbolic_triangulation_2::orientation( + const Point& p0, const Point& p1, const Point& p2) const +{ + return geom_traits().orientation_2_object()(p0, p1, p2); +} +template +inline Orientation Periodic_4_hyperbolic_triangulation_2::orientation( + const Point& p0, const Point& p1, const Point& p2, const Offset& o0, + const Offset& o1, const Offset& o2) const +{ + return geom_traits().orientation_2_object()(p0, p1, p2, o0, o1, o2); +} + + +template +Oriented_side Periodic_4_hyperbolic_triangulation_2::side_of_oriented_circle( + const Point &p0, const Point &p1, const Point &p2, const Point &p, + bool perturb) const +{ + Oriented_side os = geom_traits().side_of_oriented_circle_2_object()(p0, p1, p2, p); + if ((os != ON_ORIENTED_BOUNDARY) || (!perturb)) + return os; + + // We are now in a degenerate case => we do a symbolic perturbation. + + // We sort the points lexicographically. + const Point * points[4] = { &p0, &p1, &p2, &p }; + std::sort(points, points + 4, Perturbation_order(this)); + + // We successively look whether the leading monomial, then 2nd monomial + // of the determinant has non null coefficient. + // 2 iterations are enough (cf paper) + for (int i = 3; i > 0; --i) + { + if (points[i] == &p) + return ON_NEGATIVE_SIDE; // since p0 p1 p2 are non collinear + // and positively oriented + Orientation o; + if (points[i] == &p2 && (o = orientation(p0, p1, p)) != COLLINEAR) + return Oriented_side(o); + if (points[i] == &p1 && (o = orientation(p0, p, p2)) != COLLINEAR) + return Oriented_side(o); + if (points[i] == &p0 && (o = orientation(p, p1, p2)) != COLLINEAR) + return Oriented_side(o); + } + CGAL_triangulation_assertion(false); + return ON_NEGATIVE_SIDE; +} + +template +Oriented_side Periodic_4_hyperbolic_triangulation_2::side_of_oriented_circle( + const Point &p0, const Point &p1, const Point &p2, const Point &p, + const Offset &o0, const Offset &o1, const Offset &o2, const Offset &o, + bool perturb) const +{ + Oriented_side os = geom_traits().side_of_oriented_circle_2_object()(p0, p1, p2, p, o0, o1, o2, o); + if ((os != ON_ORIENTED_BOUNDARY) || (!perturb)) + return os; + + // We are now in a degenerate case => we do a symbolic perturbation. + // We sort the points lexicographically. + Periodic_point pts[4] = { std::make_pair(p0, o0), std::make_pair(p1, o1), + std::make_pair(p2, o2), std::make_pair(p, o) + }; + const Periodic_point *points[4] = { &pts[0], &pts[1], &pts[2], &pts[3] }; + + std::sort(points, points + 4, Perturbation_order(this)); + + // We successively look whether the leading monomial, then 2nd monomial + // of the determinant has non null coefficient. + // 2 iterations are enough (cf paper) + for (int i = 3; i > 0; --i) + { + if (points[i] == &pts[3]) + return ON_NEGATIVE_SIDE; // since p0 p1 p2 are non collinear + // and positively oriented + Orientation orient; + if ((points[i] == &pts[2]) && ((orient = orientation(p0, p1, p, o0, o1, o)) + != COLLINEAR)) + return Oriented_side(orient); + if ((points[i] == &pts[1]) && ((orient = orientation(p0, p, p2, o0, o, o2)) + != COLLINEAR)) + return Oriented_side(orient); + if ((points[i] == &pts[0]) && ((orient = orientation(p, p1, p2, o, o1, o2)) + != COLLINEAR)) + return Oriented_side(orient); + } + CGAL_triangulation_assertion(false); + return ON_NEGATIVE_SIDE; +} + +template +Oriented_side Periodic_4_hyperbolic_triangulation_2::side_of_oriented_circle( + Face_handle f, const Point & p, bool perturb) const +{ + Oriented_side os = ON_NEGATIVE_SIDE; + + int i = 0; + // TODO: optimize which copies to check depending on the offsets in + // the face. + while (os == ON_NEGATIVE_SIDE && i < 4) + { + os = side_of_oriented_circle(f->vertex(0)->point(), f->vertex(1)->point(), f->vertex(2)->point(), p, + get_offset(f, 0), get_offset(f, 1), get_offset(f, 2), combine_offsets(Offset(), int_to_off(i)), + perturb); + i++; + } + + return os; +} + + +template +void Periodic_4_hyperbolic_triangulation_2::insert_too_long_edges_in_star(Vertex_handle vh) +{ + // Insert the too long edges in the star of vh + Face_handle f = vh->face(); + Face_handle f_start = f; + + do + { + int i = ccw(f->index(vh)); + + insert_too_long_edge(f, i); + + // Proceed to the next face + f = f->neighbor(i); + } + while (f != f_start); +} + +template +void Periodic_4_hyperbolic_triangulation_2::insert_too_long_edge(Face_handle f, int i) +{ + Vertex_handle vh1 = f->vertex(ccw(i)); + Vertex_handle vh2 = f->vertex(cw(i)); + CGAL_assertion(vh1 != Vertex_handle()); + CGAL_assertion(vh2 != Vertex_handle()); + Point p1 = construct_point(vh1->point(), get_offset(f, ccw(i))); + Point p2 = construct_point(vh2->point(), get_offset(f, cw(i))); + + if (&*vh1 < &*vh2) + { + if (edge_is_too_long(p1, p2) && + (find(_too_long_edges[vh1].begin(), _too_long_edges[vh1].end(), vh2) == _too_long_edges[vh1].end())) + { + _too_long_edges[vh1].push_back(vh2); + _too_long_edge_counter++; + } + } + else + { + CGAL_triangulation_precondition(&*vh2 < &*vh1); + if (edge_is_too_long(p2, p1) && + (find(_too_long_edges[vh2].begin(), _too_long_edges[vh2].end(), vh1) == _too_long_edges[vh2].end())) + { + _too_long_edges[vh2].push_back(vh1); + _too_long_edge_counter++; + } + } +} + +template +void Periodic_4_hyperbolic_triangulation_2::remove_too_long_edges_in_star( + Vertex_handle vh) +{ + if (is_1_cover()) + return; + + // Insert the too long edges in the star of vh + Face_handle f = vh->face(); + Face_handle f_start = f; + + do + { + int i = f->index(vh); + int i2 = ccw(i); + Vertex_handle vh2 = f->vertex(i2); + + // Point corresponding to v + Point p1 = construct_point(vh->point(), get_offset(f, f->index(vh))); + // Point corresponding to the other vertex + Point p2 = construct_point(vh2->point(), get_offset(f, i2)); + + if (&*vh < &*vh2) + { + if (edge_is_too_long(p1, p2) && + (find(_too_long_edges[vh].begin(), _too_long_edges[vh].end(), vh2) != + _too_long_edges[vh].end())) + { + _too_long_edges[vh].remove(vh2); + _too_long_edge_counter--; + } + } + else + { + CGAL_triangulation_precondition(&*vh2 < &*vh); + if (edge_is_too_long(p1, p2) && + (find(_too_long_edges[vh2].begin(), _too_long_edges[vh2].end(), vh) != + _too_long_edges[vh2].end())) + { + _too_long_edges[vh2].remove(vh); + _too_long_edge_counter--; + } + } + + // Proceed to the next face + f = f->neighbor(i2); + } + while (f != f_start); +} + +template +void Periodic_4_hyperbolic_triangulation_2::remove_too_long_edge(Face_handle f, + int i) +{ + Vertex_handle vh1 = f->vertex(cw(i)); + Vertex_handle vh2 = f->vertex(ccw(i)); + Point p1 = construct_point(vh1->point(), get_offset(f, cw(i))); + Point p2 = construct_point(vh2->point(), get_offset(f, ccw(i))); + if (edge_is_too_long(p1, p2)) + { + if (&*vh1 < &*vh2) + { + typename std::list::iterator it = find( + _too_long_edges[vh1].begin(), _too_long_edges[vh1].end(), vh2); + if (it != _too_long_edges[vh1].end()) + { + _too_long_edges[vh1].erase(it); + _too_long_edge_counter--; + } + } + else + { + typename std::list::iterator it = find( + _too_long_edges[vh2].begin(), _too_long_edges[vh2].end(), vh1); + if (it != _too_long_edges[vh2].end()) + { + _too_long_edges[vh2].erase(it); + _too_long_edge_counter--; + } + } + } +} + +template +bool Periodic_4_hyperbolic_triangulation_2::edge_is_too_long(const Point &p1, + const Point &p2) const +{ + return squared_distance(p1, p2) > _edge_length_threshold; +} + +template +inline bool Periodic_4_hyperbolic_triangulation_2::is_extensible_triangulation_in_1_sheet_h1() const +{ + if (!is_1_cover()) + { + if (_too_long_edge_counter == 0) + return true; + else + return false; + } + else + { + typename Geom_traits::FT longest_edge_squared_length(0); + Segment s; + for (Periodic_segment_iterator psit = periodic_segments_begin(UNIQUE); psit + != periodic_segments_end(UNIQUE); ++psit) + { + s = construct_segment(*psit); + longest_edge_squared_length = (std::max)(longest_edge_squared_length, + s.squared_length()); + } + return (longest_edge_squared_length < _edge_length_threshold); + } +} + +template +inline bool Periodic_4_hyperbolic_triangulation_2::is_extensible_triangulation_in_1_sheet_h2() const +{ + typedef typename Geom_traits::Construct_circumcenter_2 Construct_circumcenter; + typedef typename Geom_traits::FT FT; + Construct_circumcenter construct_circumcenter = + _gt.construct_circumcenter_2_object(); + for (Periodic_triangle_iterator tit = periodic_triangles_begin(UNIQUE); tit + != periodic_triangles_end(UNIQUE); ++tit) + { + Point cc = construct_circumcenter(tit->at(0).first, tit->at(1).first, + tit->at(2).first, tit->at(0).second, tit->at(1).second, + tit->at(2).second); + + if (!(FT(16) * squared_distance(cc, point(tit->at(0))) < (_domain.xmax() + - _domain.xmin()) * (_domain.xmax() - _domain.xmin()))) + return false; + } + return true; +} + +template +inline bool Periodic_4_hyperbolic_triangulation_2::is_triangulation_in_1_sheet() const +{ + if (is_1_cover()) + return true; + for (Vertex_iterator vit = vertices_begin(); vit != vertices_end(); ++vit) + { + if (_virtual_vertices.find(vit) == _virtual_vertices.end()) + continue; + std::set nb_v_odom; + Vertex_handle vh; + Offset off; + Vertex_circulator vcir = adjacent_vertices(vit); + Vertex_circulator vstart = vcir; + size_t degree = 0; + do + { + get_vertex(vcir, vh, off); + nb_v_odom.insert(vh); + degree++; + } + while (++vcir != vstart); + if (degree != nb_v_odom.size()) + return false; + } + return true; +} + +template +std::ostream& +Periodic_4_hyperbolic_triangulation_2::save(std::ostream& os) const +{ + // writes : + // the number of vertices + // the domain as four coordinates: xmin ymin ymax zmax + // the current covering that guarantees the triangulation to be a + // simplicial complex + // the non combinatorial information on vertices (points in case of 1-sheeted + // covering, point-offset pairs otherwise) + // ALL PERIODIC COPIES OF ONE VERTEX MUST BE STORED CONSECUTIVELY + // the number of faces + // the faces by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each face + // the neighbors of each face by their index in the preceding list of faces + + // outputs dimension, domain and number of vertices + Covering_sheets cover = number_of_sheets(); + size_type n = number_of_vertices(); + + + if (is_ascii(os)) + os << domain() << std::endl + << cover[0] << " " << cover[1] << std::endl + << n*cover[0]*cover[1] << std::endl; + else + { + os << domain(); + write(os, cover[0]); + write(os, cover[1]); + write(os, n * cover[0]*cover[1]); + } + std::cout << "Line:" << __LINE__ << " cover[0]:" << cover[0] << " cover[1]:" << cover[1] << " n*c0*c1:" << (n * cover[0]*cover[1]) << std::endl; + + std::cout << "save, #Vertices: " << n << std::endl; + + if (n == 0) + return os; + + // write the vertices + Unique_hash_map V; + std::size_t i = 0; + if (is_1_cover()) + { + for (Vertex_iterator it = vertices_begin(); it != vertices_end(); ++it) + { + V[it] = i++; + os << it->point(); + if (is_ascii(os)) + os << std::endl; + } + } + else + { + Virtual_vertex_map_it vit, vvit; + std::vector vv; + for (Vertex_iterator it = vertices_begin(); it != vertices_end(); ++it) + { + vit = _virtual_vertices.find(it); + if (vit != _virtual_vertices.end()) continue; + V[it] = i++; + if (is_ascii(os)) + os << it->point() << std::endl + << Offset(0, 0) << std::endl; + else + os << it->point() << Offset(0, 0); + CGAL_triangulation_assertion(_virtual_vertices_reverse.find(it) + != _virtual_vertices_reverse.end()); + vv = _virtual_vertices_reverse.find(it)->second; + CGAL_triangulation_assertion(vv.size() == 8); + for (std::size_t j = 0; j < vv.size(); j++) + { + vvit = _virtual_vertices.find(vv[j]); + CGAL_triangulation_assertion(vvit != _virtual_vertices.end()); + V[vv[j]] = i++; + if (is_ascii(os)) + os << vv[j]->point() << std::endl + << vvit->second.second << std::endl; + else os << vv[j]->point() << vvit->second.second; + } + } + } + CGAL_triangulation_postcondition(i == _cover[0]*_cover[1]*n); + + Unique_hash_map F; + int inum = 0; + // asks the tds for the combinatorial information + // vertices of the faces + size_type m = _tds.number_of_faces(); + if (is_ascii(os)) os << std::endl << m << std::endl; + else write(os, m); + std::cout << "save, #Faces: " << m << std::endl; + + for( Face_iterator ib = faces_begin(); + ib != faces_end(); ++ib) + { + F[ib] = inum++; + for(int j = 0; j < 3 ; ++j) + { + if(is_ascii(os)) os << V[ib->vertex(j)] << " "; + else write(os, V[ib->vertex(j)]); + } + os << *ib ; + if(is_ascii(os)) os << "\n"; + } + if(is_ascii(os)) os << "\n"; + + std::cout << "save, face check: " << inum << " == " << m << std::endl; + CGAL_assertion(m == (size_type)inum); + + // neighbor pointers of the faces + for( Face_iterator it = faces_begin(); + it != faces_end(); ++it) + { + for(int j = 0; j < 3; ++j) + { + CGAL_assertion(F.is_defined(it->neighbor(j))); + if(is_ascii(os)) os << F[it->neighbor(j)] << " "; + else write(os, F[it->neighbor(j)]); + } + if(is_ascii(os)) os << "\n"; + } + + // write offsets + //for (unsigned int i=0 ; ioffset(j); + if ( j == 3 ) + os << std::endl; + else + os << ' '; + } + else write(os, ch->offset(j)); + } + } + + // write the non combinatorial information on the faces + // using the << operator of Face + // works because the iterator of the tds traverses the faces in the + // same order as the iterator of the triangulation + if(number_of_vertices() != 0) + { + for(Face_iterator it = faces_begin(); it != faces_end(); ++it) + { + os << *it; // other information + if(is_ascii(os)) + os << std::endl; + } + } + + return os; +} + +template +std::istream& +Periodic_4_hyperbolic_triangulation_2::load(std::istream& is) +{ + // reads + // the current covering that guarantees the triangulation to be a + // simplicial complex + // the number of vertices + // the non combinatorial information on vertices (points in case of 1-sheeted + // covering, point-offset pairs otherwise) + // ALL PERIODIC COPIES OF ONE VERTEX MUST BE STORED CONSECUTIVELY + // the number of faces + // the faces by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each face + // the neighbors of each face by their index in the preceding list of face + CGAL_triangulation_precondition(is.good()); + + clear(); + + Iso_rectangle domain(0, 0, 1, 1); + int cx = 0, cy = 0; + size_type n = 0; + + if (is_ascii(is)) + { + is >> domain; + is >> cx >> cy >> n; + } + else + { + is >> domain; + read(is, cx); + read(is, cy); + read(is, n); + } + std::cout << "Line:" << __LINE__ << " cx:" << cx << " cy:" << cy << " n:" << n << std::endl; + + CGAL_triangulation_assertion((n / (cx * cy))*cx*cy == n); + + tds().set_dimension((n == 0 ? -2 : 2)); + _domain = domain; + _gt.set_domain(domain); + _cover = make_array(cx, cy); + + if ( n == 0 ) return is; + + std::map< std::size_t, Vertex_handle > V; + + if (cx == 1 && cy == 1) + { + Point p; + for (std::size_t i = 0; i < n; i++) + { + V[i] = tds().create_vertex(); + is >> p; + V[i]->set_point(p); + } + } + else + { + Vertex_handle v, w; + std::vector vv; + Offset off; + Point p; + for (std::size_t i = 0; i < n; i++) + { + v = tds().create_vertex(); + V[i] = v; + is >> p >> off; + V[i]->set_point(p); + vv.clear(); + for (int j = 1; j < cx * cy; j++) + { + i++; + w = tds().create_vertex(); + V[i] = w; + is >> p >> off; + V[i]->set_point(p); + vv.push_back(w); + _virtual_vertices[w] = std::make_pair(v, off); + } + _virtual_vertices_reverse[v] = vv; + } + } + + // Creation of the faces + std::size_t index; + size_type m; + if (is_ascii(is)) is >> m; + else read(is, m); + std::vector F(m); + std::cout << "load, #Faces: " << m << std::endl; + { + for(size_t i = 0; i < m; ++i) + { + F[i] = _tds.create_face() ; + for(int j = 0; j < 3 ; ++j) + { + if (is_ascii(is)) is >> index; + else read(is, index); + CGAL_assertion(index < V.size()); + F[i]->set_vertex(j, V[index]); + // The face pointer of vertices is set too often, + // but otherwise we had to use one more map + V[index]->set_face(F[i]); + } + // read in non combinatorial info of the face + is >> *(F[i]) ; + } + } + + // Setting the neighbor pointers + { + for(size_t i = 0; i < m; ++i) + { + for(int j = 0; j < 3; ++j) + { + if (is_ascii(is)) is >> index; + else read(is, index); + if (index >= F.size()) { + std::cout << __FILE__ << ", " << __FUNCTION__ << ", l:" << __LINE__ << " f=" + << i << "<" << m << ", index=" << j << " nb=" << index << " #F=" << F.size() + << std::endl; + } + CGAL_assertion(i < F.size()); + CGAL_assertion(index < F.size()); + F[i]->set_neighbor(j, F[index]); + } + } + } + + // read offsets + int off[3] = {0, 0, 0}; + for (std::size_t j = 0 ; j < m; j++) + { + if (is_ascii(is)) + is >> off[0] >> off[1] >> off[2]; + else + { + read(is, off[0]); + read(is, off[1]); + read(is, off[2]); + } + set_offsets(F[j], off[0], off[1], off[2]); + } + + // read potential other information + for (std::size_t j = 0 ; j < m; j++) + is >> *(F[j]); + + int i = 0; + for (Vertex_iterator vi = vertices_begin(); + vi != vertices_end(); ++vi) + { + _too_long_edges[vi] = std::list(); + ++i; + } + + _edge_length_threshold = FT(0.166) * (_domain.xmax() - _domain.xmin()) + * (_domain.xmax() - _domain.xmin()); + _too_long_edge_counter = find_too_long_edges(_too_long_edges); + + CGAL_triangulation_expensive_assertion( is_valid() ); + return is; +} + + +namespace internal +{ + +/// Internal function used by operator==. +//TODO: introduce offsets +template +bool +test_next(const Periodic_4_hyperbolic_triangulation_2 &t1, + const Periodic_4_hyperbolic_triangulation_2 &t2, + typename Periodic_4_hyperbolic_triangulation_2::Face_handle c1, + typename Periodic_4_hyperbolic_triangulation_2::Face_handle c2, + std::map < typename Periodic_4_hyperbolic_triangulation_2::Face_handle, + typename Periodic_4_hyperbolic_triangulation_2::Face_handle > &Cmap, + std::map < typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle, + typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle > &Vmap) +{ + // This function tests and registers the 4 neighbors of c1/c2, + // and recursively calls itself over them. + // Returns false if an inequality has been found. + + // Precondition: c1, c2 have been registered as well as their 4 vertices. + CGAL_triangulation_precondition(t1.number_of_vertices() != 0); + CGAL_triangulation_precondition(Cmap[c1] == c2); + CGAL_triangulation_precondition(Vmap.find(c1->vertex(0)) != Vmap.end()); + CGAL_triangulation_precondition(Vmap.find(c1->vertex(1)) != Vmap.end()); + CGAL_triangulation_precondition(Vmap.find(c1->vertex(2)) != Vmap.end()); + + typedef Periodic_4_hyperbolic_triangulation_2 Tr1; + typedef Periodic_4_hyperbolic_triangulation_2 Tr2; + typedef typename Tr1::Vertex_handle Vertex_handle1; + typedef typename Tr1::Face_handle Face_handle1; + typedef typename Tr2::Vertex_handle Vertex_handle2; + typedef typename Tr2::Face_handle Face_handle2; + typedef typename std::map::const_iterator Cit; + typedef typename std::map < Vertex_handle1, + Vertex_handle2 >::const_iterator Vit; + + for (int i = 0; i <= 2; ++i) + { + Face_handle1 n1 = c1->neighbor(i); + Cit cit = Cmap.find(n1); + Vertex_handle1 v1 = c1->vertex(i); + Vertex_handle2 v2 = Vmap[v1]; + Face_handle2 n2 = c2->neighbor(c2->index(v2)); + if (cit != Cmap.end()) + { + // n1 was already registered. + if (cit->second != n2) + return false; + continue; + } + // n1 has not yet been registered. + // We check that the new vertices match geometrically. + // And we register them. + Vertex_handle1 vn1 = n1->vertex(n1->index(c1)); + Vertex_handle2 vn2 = n2->vertex(n2->index(c2)); + Vit vit = Vmap.find(vn1); + if (vit != Vmap.end()) + { + // vn1 already registered + if (vit->second != vn2) + return false; + } + else + { + if (t1.geom_traits().compare_xy_2_object()(vn1->point(), + vn2->point()) != 0) + return false; + + // We register vn1/vn2. + Vmap.insert(std::make_pair(vn1, vn2)); + } + + // We register n1/n2. + Cmap.insert(std::make_pair(n1, n2)); + // We recurse on n1/n2. + if (!test_next(t1, t2, n1, n2, Cmap, Vmap)) + return false; + } + + return true; +} + +} // namespace internal + + +template +std::istream& +operator>>(std::istream& is, Periodic_4_hyperbolic_triangulation_2 &tr) +{ + return tr.load(is); +} +template +std::ostream& +operator<<(std::ostream& os, Periodic_4_hyperbolic_triangulation_2 &tr) +{ + return tr.save(os); +} + +template < class GT, class Tds1, class Tds2 > +bool +operator==(const Periodic_4_hyperbolic_triangulation_2 &t1, + const Periodic_4_hyperbolic_triangulation_2 &t2) +{ + typedef typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle + Vertex_handle1; + typedef typename Periodic_4_hyperbolic_triangulation_2::Face_handle + Face_handle1; + typedef typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle + Vertex_handle2; + typedef typename Periodic_4_hyperbolic_triangulation_2::Vertex_handle + Vertex_iterator2; + typedef typename Periodic_4_hyperbolic_triangulation_2::Face_handle + Face_handle2; + typedef typename Periodic_4_hyperbolic_triangulation_2::Face_circulator + Face_circulator2; + + typedef typename Periodic_4_hyperbolic_triangulation_2::Point Point; + typedef typename Periodic_4_hyperbolic_triangulation_2::Offset Offset; + + // Some quick checks. + if ( t1.domain() != t2.domain() + || t1.number_of_sheets() != t2.number_of_sheets()) + return false; + + if ( t1.number_of_vertices() != t2.number_of_vertices() + || t1.number_of_faces() != t2.number_of_faces()) + return false; + + // Special case for empty triangulations + if (t1.number_of_vertices() == 0) + return true; + + // We will store the mapping between the 2 triangulations vertices and + // faces in 2 maps. + std::map Vmap; + std::map Cmap; + + // find a common point + Vertex_handle1 v1 = static_cast(t1.vertices_begin()); + Vertex_handle2 iv2; + for (Vertex_iterator2 vit2 = t2.vertices_begin() ; + vit2 != t2.vertices_end(); ++vit2) + { + if (t1.compare_xy(vit2->point(), v1->point(), + t2.get_offset(vit2), t1.get_offset(v1)) != EQUAL) + continue; + iv2 = static_cast(vit2); + break; + } + if (iv2 == Vertex_handle2()) + return false; + Vmap.insert(std::make_pair(v1, iv2)); + + // We pick one face of t1, and try to match it against the + // faces of t2. + Face_handle1 c = v1->face(); + Vertex_handle1 v2 = c->vertex(t1.cw(c->index(v1))); + Vertex_handle1 v3 = c->vertex(t1.ccw(c->index(v1))); + Point p2 = v2->point(); + Point p3 = v3->point(); + Offset o2 = t1.get_offset(v2); + Offset o3 = t1.get_offset(v3); + + Face_circulator2 fc = t2.incident_faces(iv2), done(fc); + do + { + int inf = fc->index(iv2); + + if (t1.compare_xy(p2, fc->vertex((inf + 1) % 3)->point(), + o2, t2.get_offset(fc->vertex((inf + 1) % 3))) == EQUAL) + Vmap.insert(std::make_pair(v2, fc->vertex((inf + 1) % 3))); + else if (t1.compare_xy(p2, fc->vertex((inf + 2) % 3)->point(), + o2, t2.get_offset(fc->vertex((inf + 2) % 3))) == EQUAL) + Vmap.insert(std::make_pair(v2, fc->vertex((inf + 2) % 3))); + else + continue; // None matched v2. + + if (t1.compare_xy(p3, fc->vertex((inf + 1) % 3)->point(), + o3, t2.get_offset(fc->vertex((inf + 1) % 3))) == EQUAL) + Vmap.insert(std::make_pair(v3, fc->vertex((inf + 1) % 3))); + else if (t1.compare_xy(p3, fc->vertex((inf + 2) % 3)->point(), + o3, t2.get_offset(fc->vertex((inf + 2) % 3))) == EQUAL) + Vmap.insert(std::make_pair(v3, fc->vertex((inf + 2) % 3))); + else + continue; // None matched v3. + + // Found it ! + Cmap.insert(std::make_pair(c, fc)); + break; + } + while (++fc != done); + + if (Cmap.size() == 0) + return false; + + // We now have one face, we need to propagate recursively. + return internal::test_next(t1, t2, + Cmap.begin()->first, Cmap.begin()->second, Cmap, Vmap); +} + +template < class GT, class Tds1, class Tds2 > +inline +bool +operator!=(const Periodic_4_hyperbolic_triangulation_2 &t1, + const Periodic_4_hyperbolic_triangulation_2 &t2) +{ + return ! (t1 == t2); +} + + +void insert_dummy_points(); + +#include + +} //namespace CGAL + + +#endif //CGAL_PERIODIC_4_HYPERBOLIC_TRIANGULATION_2_H diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Periodic_2_hyperbolic_triangulation_dummy.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_dummy.h similarity index 89% rename from Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Periodic_2_hyperbolic_triangulation_dummy.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_dummy.h index 010cc8758f5..d0192bd8fad 100644 --- a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Periodic_2_hyperbolic_triangulation_dummy.h +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_dummy.h @@ -17,18 +17,20 @@ // // Author(s) : Mikhail Bogdanov -#ifndef CGAL_PERIODIC_2_HYPERBOLIC_TRIANGULATION_DUMMY_H -#define CGAL_PERIODIC_2_HYPERBOLIC_TRIANGULATION_DUMMY_H +#ifndef CGAL_PERIODIC_4_HYPERBOLIC_TRIANGULATION_DUMMY_H +#define CGAL_PERIODIC_4_HYPERBOLIC_TRIANGULATION_DUMMY_H #include #include // Added by Iordanov +/* #if CLEARLY_MY_TYPE == 1 #include #else #include #endif +*/ namespace CGAL { @@ -114,7 +116,7 @@ namespace CGAL { const Point_2 a(cos(phi)*cos(phi + psi)/rho, sin(phi)*cos(phi + psi)/rho); const Point_2 b(a.x(), -a.y()); - //inner_points.push_back(a); + inner_points.push_back(a); Point_2 c = Construct_reflection()(a, b, o); Point_2 d = Construct_reflection()(a, c, b); //inner_points.push_back(d); @@ -124,22 +126,20 @@ namespace CGAL { int size = inner_points.size(); for(int i = 0; i < 7; i++) { for(int j = 0; j < size; j++) { - // inner_points.push_back(apply_rotation(inner_points[i*size + j])); + inner_points.push_back(apply_rotation(inner_points[i*size + j])); } } inner_points.push_back(o); - //points_on_boundary.push_back(c); + points_on_boundary.push_back(c); for(int i = 1; i < 4; i++) { - // points_on_boundary.push_back(apply_rotation(points_on_boundary[i-1])); + points_on_boundary.push_back(apply_rotation(points_on_boundary[i-1])); } - // points_on_vertex.push_back(apply_rotation(f)); - - + points_on_vertex.push_back(apply_rotation(f)); } - + /* template void recursive_translate(Diametric_translations g, @@ -196,17 +196,17 @@ namespace CGAL { } } - +*/ template < class GT, class TDS > - void Periodic_2_Delaunay_hyperbolic_triangulation_2::insert_dummy_points() { - clear(); + void Delaunay_hyperbolic_triangulation_2::insert_dummy_points(std::vector& all_points) { + //clear(); - std::vector inner_points, points_on_boundary, points_on_vertex; + std::vector inner_points, points_on_boundary, points_on_vertex; compute_dummy_points(inner_points, points_on_boundary, points_on_vertex); - std::vector all_points = inner_points; + /*std::vector*/ all_points = inner_points; for (int i = 0; i < points_on_boundary.size(); i++) { all_points.push_back(points_on_boundary[i]); @@ -218,8 +218,13 @@ namespace CGAL { std::cout << "All points length: " << all_points.size() << std::endl; - Base::insert(all_points.begin(), all_points.end()); + //for (int i = 0; i < all_points.size(); i++) { + // processInput(all_points[i]); + //} + + //Base::insert(all_points.begin(), all_points.end()); + /* Diametric_translations g; std::vector copies; for (int i = 0; i < all_points.size(); i++) { @@ -228,10 +233,11 @@ namespace CGAL { std::cout << "Copies length: " << copies.size() << std::endl; Base::insert(copies.begin(), copies.end()); - + */ + } } // namespace CGAL -#endif // CGAL_PERIODIC_2_HYPERBOLIC_TRIANGULATION_DUMMY_H +#endif // CGAL_PERIODIC_4_HYPERBOLIC_TRIANGULATION_DUMMY_H diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_iterators_2.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_iterators_2.h new file mode 100644 index 00000000000..0a16e2e4a75 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Periodic_4_hyperbolic_triangulation_iterators_2.h @@ -0,0 +1,882 @@ +// Copyright (c) 1997-2013 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Nico Kruithof + +#ifndef CGAL_PERIODIC_4_HYPERBOLIC_TRIANGULATION_ITERATORS_2_H +#define CGAL_PERIODIC_4_HYPERBOLIC_TRIANGULATION_ITERATORS_2_H + +#include +#include +#include + +namespace CGAL +{ + +template < class T > +class Periodic_4_hyperbolic_triangulation_triangle_iterator_2 +{ + // Iterates over the primitives in a periodic triangulation. + // Options: + // - STORED: output each primitive from the Tds exactly once + // - UNIQUE: output exactly one periodic copy of each primitive, no matter + // whether the current tds stores a n-sheeted covering for n!=1. + // - STORED_COVER_DOMAIN: output each primitive whose intersection with the + // actually used periodic domain is non-zero. + // - UNIQUE_COVER_DOMAIN: output each primitive whose intersection + // with the original domain that the user has given is non-zero + // + // Comments: + // When computing in 1-sheeted covering, there will be no difference in the + // result of STORED and UNIQUE as well as STORED_COVER_DOMAIN and + // UNIQUE_COVER_DOMAIN. + +public: + + typedef typename T::Periodic_triangle value_type; + typedef const typename T::Periodic_triangle * pointer; + typedef const typename T::Periodic_triangle & reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + typedef typename T::Periodic_triangle Periodic_triangle; + typedef Periodic_4_hyperbolic_triangulation_triangle_iterator_2 Periodic_triangle_iterator; + typedef typename T::Face Face; + typedef typename T::Face_iterator Face_iterator; + + typedef typename T::Offset Offset; + typedef typename T::Iterator_type Iterator_type; + + Periodic_4_hyperbolic_triangulation_triangle_iterator_2(Iterator_type it = T::STORED) + : _t(NULL), _it(it), _off(0) {} + + Periodic_4_hyperbolic_triangulation_triangle_iterator_2(const T * t, + Iterator_type it = T::STORED) + : _t(t), pos(_t->faces_begin()), _it(it), _off(0) + { + if (_it == T::UNIQUE || _it == T::UNIQUE_COVER_DOMAIN) + { + while (pos != _t->faces_end() && !is_canonical() ) + ++pos; + } + } + + // used to initialize the past-the-end iterator + Periodic_4_hyperbolic_triangulation_triangle_iterator_2(const T* t, int, + Iterator_type it = T::STORED) + : _t(t), pos(_t->faces_end()), _it(it), _off(0) {} + + Periodic_triangle_iterator& operator++() + { + switch (_it) + { + case T::STORED: + ++pos; + break; + case T::UNIQUE: + do + { + ++pos; + } + while (pos != _t->faces_end() && !is_canonical()); + break; + case T::STORED_COVER_DOMAIN: + case T::UNIQUE_COVER_DOMAIN: + increment_domain(); + break; + default: + CGAL_triangulation_assertion(false); + }; + return *this; + } + + Periodic_triangle_iterator& operator--() + { + switch (_it) + { + case T::STORED: + --pos; + break; + case T::UNIQUE: + do + { + --pos; + } + while (pos != _t->faces_begin() && !is_canonical()); + break; + case T::STORED_COVER_DOMAIN: + case T::UNIQUE_COVER_DOMAIN: + decrement_domain(); + }; + return *this; + } + + Periodic_triangle_iterator operator++(int) + { + Periodic_triangle_iterator tmp(*this); + ++(*this); + return tmp; + } + + Periodic_triangle_iterator operator--(int) + { + Periodic_triangle_iterator tmp(*this); + --(*this); + return tmp; + } + + bool operator==(const Periodic_triangle_iterator& ti) const + { + // We are only allowed to compare iterators of the same type. + CGAL_triangulation_assertion(_it == ti._it); + return _t == ti._t && pos == ti.pos && _off == ti._off; + } + + bool operator!=(const Periodic_triangle_iterator& ti) const + { + return !(*this == ti); + } + + reference operator*() const + { + periodic_triangle = construct_periodic_triangle(); + return periodic_triangle; + } + + pointer operator->() const + { + periodic_triangle = construct_periodic_triangle(); + return &periodic_triangle; + } + + Face_iterator get_face() const + { + return pos; + } + +private: + const T* _t; + Face_iterator pos; // current face. + Iterator_type _it; + int _off; // current offset + mutable Periodic_triangle periodic_triangle; // current triangle. + +private: + // check whether pos points onto a unique edge or not. + // If we are computing in 1-sheeted covering this should + // always be true. + bool is_canonical() + { + // fetch all offsets + Offset off0, off1, off2; + get_edge_offsets(off0, off1, off2); + + if (_t->number_of_sheets() != make_array(1, 1)) + { + // If there is one offset with entries larger than 1 then we are + // talking about a vertex that is too far away from the original + // domain to belong to a canonical triangle. + if (off0.x() > 1) return false; + if (off0.y() > 1) return false; + if (off1.x() > 1) return false; + if (off1.y() > 1) return false; + if (off2.x() > 1) return false; + if (off2.y() > 1) return false; + } + + // If there is one direction of space for which all offsets are + // non-zero then the edge is not canonical because we can + // take the copy closer towards the origin in that direction. + int offx = off0.x() & off1.x() & off2.x(); + int offy = off0.y() & off1.y() & off2.y(); + + return (offx == 0 && offy == 0); + } + + // Artificial incrementation function that takes periodic + // copies into account. + void increment_domain() + { + int off = get_drawing_offsets(); + CGAL_triangulation_assertion(_off <= off); + if (_off == off) + { + _off = 0; + do + { + ++pos; + } + while (_it == T::UNIQUE_COVER_DOMAIN + && pos != _t->faces_end() && !is_canonical()); + } + else + { + do + { + ++_off; + } + while ((((~_off) | off) & 3) != 3); // Increment until a valid + // offset has been found + } + } + + // Artificial decrementation function that takes periodic + // copies into account. + void decrement_domain() + { + if (_off == 0) + { + if (pos == _t->faces_begin()) return; + do + { + --pos; + } + while (_it == T::UNIQUE_COVER_DOMAIN && !is_canonical()); + _off = get_drawing_offsets(); + } + else + { + int off = get_drawing_offsets(); + do + { + --_off; + } + while ((((~_off) | off) & 3) != 3); // Decrement until a valid + // offset has been found + } + } + + // Get the canonicalized offsets of an edge. + // This works in any cover that is encoded in _t->combine_offsets + void get_edge_offsets(Offset &off0, Offset &off1, + Offset &off2) const + { + Offset face_off0 = _t->int_to_off(pos->offset(0)); + Offset face_off1 = _t->int_to_off(pos->offset(1)); + Offset face_off2 = _t->int_to_off(pos->offset(2)); + Offset diff_off((face_off0.x() == 1 + && face_off1.x() == 1 + && face_off2.x() == 1) ? -1 : 0, + (face_off0.y() == 1 + && face_off1.y() == 1 + && face_off2.y() == 1) ? -1 : 0); + off0 = _t->combine_offsets(_t->get_offset(pos, 0), diff_off); + off1 = _t->combine_offsets(_t->get_offset(pos, 1), diff_off); + off2 = _t->combine_offsets(_t->get_offset(pos, 2), diff_off); + } + + // return an integer that encodes the translations which have to be + // applied to the edge *pos + int get_drawing_offsets() + { + Offset off0, off1, off2; + // Choose edges that are to be duplicated. These are edges that + // intersect the boundary of the periodic domain. In UNIQUE mode + // this means that the offset with respect to drawing should + // differ in some entries. Otherwise we consider the offsets + // internally stored inside the cell telling us that this cell + // wraps around the domain. + if (_it == T::UNIQUE_COVER_DOMAIN) + get_edge_offsets(off0, off1, off2); + else + { + CGAL_triangulation_assertion(_it == T::STORED_COVER_DOMAIN); + off0 = _t->int_to_off(pos->offset(0)); + off1 = _t->int_to_off(pos->offset(1)); + off2 = _t->int_to_off(pos->offset(2)); + } + + CGAL_triangulation_assertion(off0.x() == 0 || off0.x() == 1); + CGAL_triangulation_assertion(off0.y() == 0 || off0.y() == 1); + CGAL_triangulation_assertion(off1.x() == 0 || off1.x() == 1); + CGAL_triangulation_assertion(off1.y() == 0 || off1.y() == 1); + CGAL_triangulation_assertion(off2.x() == 0 || off2.x() == 1); + CGAL_triangulation_assertion(off2.y() == 0 || off2.y() == 1); + + int offx = ( ((off0.x() == 0 && off1.x() == 0 + && off2.x() == 0) + || (off0.x() == 1 && off1.x() == 1 + && off2.x() == 1)) ? 0 : 1); + int offy = ( ((off0.y() == 0 && off1.y() == 0 + && off2.y() == 0) + || (off0.y() == 1 && off1.y() == 1 + && off2.y() == 1)) ? 0 : 1); + + return( 2 * offx + offy ); + } + + Periodic_triangle construct_periodic_triangle() const + { + CGAL_triangulation_assertion(pos != typename T::Face_handle()); + Offset off0, off1, off2; + get_edge_offsets(off0, off1, off2); + Offset transl_off = Offset((((_off >> 1) & 1) == 1 ? -1 : 0), + (((_off ) & 1) == 1 ? -1 : 0)); + if (_it == T::STORED_COVER_DOMAIN) + { + off0 = _t->combine_offsets(off0, transl_off); + off1 = _t->combine_offsets(off1, transl_off); + off2 = _t->combine_offsets(off2, transl_off); + } + if (_it == T::UNIQUE_COVER_DOMAIN) + { + off0 += transl_off; + off1 += transl_off; + off2 += transl_off; + } + return make_array(std::make_pair(pos->vertex(0)->point(), off0), + std::make_pair(pos->vertex(1)->point(), off1), + std::make_pair(pos->vertex(2)->point(), off2)); + } +}; + +template < class T > +class Periodic_4_hyperbolic_triangulation_segment_iterator_2 +{ + // Iterates over the primitives in a periodic triangulation. + // Options: + // - STORED: output each primitive from the Tds exactly once + // - UNIQUE: output exactly one periodic copy of each primitive, no matter + // whether the current tds stores a n-sheeted covering for n!=1. + // - STORED_COVER_DOMAIN: output each primitive whose intersection with the + // actually used periodic domain is non-zero. + // - UNIQUE_COVER_DOMAIN: output each primitive whose intersection + // with the original domain that the user has given is non-zero + // + // Comments: + // When computing in 1-sheeted covering, there will be no difference in the + // result of STORED and UNIQUE as well as STORED_COVER_DOMAIN and + // UNIQUE_COVER_DOMAIN. + +public: + + typedef typename T::Periodic_segment value_type; + typedef const typename T::Periodic_segment * pointer; + typedef const typename T::Periodic_segment & reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + typedef typename T::Periodic_segment Periodic_segment; + typedef Periodic_4_hyperbolic_triangulation_segment_iterator_2 + Periodic_segment_iterator; + typedef typename T::Edge Edge; + typedef typename T::Edge_iterator Edge_iterator; + + typedef typename T::Offset Offset; + typedef typename T::Iterator_type Iterator_type; + + Periodic_4_hyperbolic_triangulation_segment_iterator_2(Iterator_type it = T::STORED) + : _t(NULL), _it(it), _off(0) {} + + Periodic_4_hyperbolic_triangulation_segment_iterator_2(const T * t, + Iterator_type it = T::STORED) + : _t(t), pos(_t->edges_begin()), _it(it), _off(0) + { + if (_it == T::UNIQUE || _it == T::UNIQUE_COVER_DOMAIN) + { + while (pos != _t->edges_end() && !is_canonical() ) + ++pos; + } + } + + // used to initialize the past-the-end iterator + Periodic_4_hyperbolic_triangulation_segment_iterator_2(const T* t, int, + Iterator_type it = T::STORED) + : _t(t), pos(_t->edges_end()), _it(it), _off(0) {} + + Periodic_segment_iterator& operator++() + { + switch (_it) + { + case T::STORED: + ++pos; + break; + case T::UNIQUE: + do + { + ++pos; + } + while (pos != _t->edges_end() && !is_canonical()); + break; + case T::STORED_COVER_DOMAIN: + case T::UNIQUE_COVER_DOMAIN: + increment_domain(); + break; + default: + CGAL_triangulation_assertion(false); + }; + return *this; + } + + Periodic_segment_iterator& operator--() + { + switch (_it) + { + case T::STORED: + --pos; + break; + case T::UNIQUE: + do + { + --pos; + } + while (pos != _t->edges_begin() && !is_canonical()); + break; + case T::STORED_COVER_DOMAIN: + case T::UNIQUE_COVER_DOMAIN: + decrement_domain(); + }; + return *this; + } + + Periodic_segment_iterator operator++(int) + { + Periodic_segment_iterator tmp(*this); + ++(*this); + return tmp; + } + + Periodic_segment_iterator operator--(int) + { + Periodic_segment_iterator tmp(*this); + --(*this); + return tmp; + } + + bool operator==(const Periodic_segment_iterator& ti) const + { + // We are only allowed to compare iterators of the same type. + CGAL_triangulation_assertion(_it == ti._it); + return _t == ti._t && pos == ti.pos && _off == ti._off; + } + + bool operator!=(const Periodic_segment_iterator& ti) const + { + return !(*this == ti); + } + + reference operator*() const + { + periodic_segment = construct_periodic_segment(); + return periodic_segment; + } + + pointer operator->() const + { + periodic_segment = construct_periodic_segment(); + return &periodic_segment; + } + + Edge_iterator get_edge() const + { + return pos; + } +private: + const T* _t; + Edge_iterator pos; // current edge. + Iterator_type _it; + int _off; // current offset + mutable Periodic_segment periodic_segment; // current segment. + +private: + // check whether pos points onto a unique edge or not. + // If we are computing in 1-sheeted covering this should + // always be true. + bool is_canonical() + { + // fetch all offsets + Offset off0, off1; + get_edge_offsets(off0, off1); + + if (_t->number_of_sheets() != make_array(1, 1)) + { + // If there is one offset with entries larger than 1 then we are + // talking about a vertex that is too far away from the original + // domain to belong to a canonical triangle. + if (off0.x() > 1) return false; + if (off0.y() > 1) return false; + if (off1.x() > 1) return false; + if (off1.y() > 1) return false; + } + + // If there is one direction of space for which all offsets are + // non-zero then the edge is not canonical because we can + // take the copy closer towards the origin in that direction. + int offx = off0.x() & off1.x(); + int offy = off0.y() & off1.y(); + + return (offx == 0 && offy == 0); + } + + // Artificial incrementation function that takes periodic + // copies into account. + void increment_domain() + { + int off = get_drawing_offsets(); + CGAL_triangulation_assertion(_off <= off); + if (_off == off) + { + _off = 0; + do + { + ++pos; + } + while (_it == T::UNIQUE_COVER_DOMAIN + && pos != _t->edges_end() && !is_canonical()); + } + else + { + do + { + ++_off; + } + while ((((~_off) | off) & 3) != 3); // Increment until a valid + // offset has been found + } + } + + // Artificial decrementation function that takes periodic + // copies into account. + void decrement_domain() + { + if (_off == 0) + { + if (pos == _t->edges_begin()) return; + do + { + --pos; + } + while (_it == T::UNIQUE_COVER_DOMAIN && !is_canonical()); + _off = get_drawing_offsets(); + } + else + { + int off = get_drawing_offsets(); + do + { + --_off; + } + while ((((~_off) | off) & 3) != 3); // Decrement until a valid + // offset has been found + } + } + + // Get the canonicalized offsets of an edge. + // This works in any cover that is encoded in _t->combine_offsets + void get_edge_offsets(Offset &off0, Offset &off1) const + { + Offset cell_off0 = _t->int_to_off(pos->first->offset(_t->cw(pos->second))); + Offset cell_off1 = _t->int_to_off(pos->first->offset(_t->ccw(pos->second))); + Offset diff_off((cell_off0.x() == 1 && cell_off1.x() == 1) ? -1 : 0, + (cell_off0.y() == 1 && cell_off1.y() == 1) ? -1 : 0); + off0 = _t->combine_offsets(_t->get_offset(pos->first, _t->cw(pos->second)), + diff_off); + off1 = _t->combine_offsets(_t->get_offset(pos->first, _t->ccw(pos->second)), + diff_off); + } + + // return an integer that encodes the translations which have to be + // applied to the edge *pos + int get_drawing_offsets() + { + Offset off0, off1; + // Choose edges that are to be duplicated. These are edges that + // intersect the boundary of the periodic domain. In UNIQUE mode + // this means that the offset with respect to drawing should + // differ in some entries. Otherwise we consider the offsets + // internally stored inside the cell telling us that this cell + // wraps around the domain. + if (_it == T::UNIQUE_COVER_DOMAIN) + get_edge_offsets(off0, off1); + else + { + CGAL_triangulation_assertion(_it == T::STORED_COVER_DOMAIN); + off0 = _t->int_to_off(pos->first->offset(_t->cw(pos->second))); + off1 = _t->int_to_off(pos->first->offset(_t->ccw(pos->second))); + } + Offset diff_off = off0 - off1; + + CGAL_triangulation_assertion(diff_off.x() >= -1 || diff_off.x() <= 1); + CGAL_triangulation_assertion(diff_off.y() >= -1 || diff_off.y() <= 1); + + return( 2 * (diff_off.x() == 0 ? 0 : 1) + + (diff_off.y() == 0 ? 0 : 1)); + } + + Periodic_segment construct_periodic_segment() const + { + CGAL_triangulation_assertion(pos->first != typename T::Face_handle()); + Offset off0, off1; + get_edge_offsets(off0, off1); + Offset transl_off = Offset((((_off >> 1) & 1) == 1 ? -1 : 0), + (( _off & 1) == 1 ? -1 : 0)); + if (_it == T::STORED_COVER_DOMAIN) + { + off0 = _t->combine_offsets(off0, transl_off); + off1 = _t->combine_offsets(off1, transl_off); + } + if (_it == T::UNIQUE_COVER_DOMAIN) + { + off0 += transl_off; + off1 += transl_off; + } + return make_array( + std::make_pair(pos->first->vertex(_t->cw(pos->second))->point(), off0), + std::make_pair(pos->first->vertex(_t->ccw(pos->second))->point(), off1)); + } +}; + +template < class T > +class Periodic_4_hyperbolic_triangulation_point_iterator_2 +{ + // Iterates over the primitives in a periodic triangulation. + // Options: + // - STORED: output each primitive from the Tds exactly once + // - UNIQUE: output exactly one periodic copy of each primitive, no matter + // whether the current tds stores a n-sheeted covering for n!=1. + // - STORED_COVER_DOMAIN: output each primitive whose intersection with the + // actually used periodic domain is non-zero. + // - UNIQUE_COVER_DOMAIN: output each primitive whose intersection + // with the original domain that the user has given is non-zero + // + // Comments: + // When computing in 1-sheeted covering, there will be no difference in the + // result of STORED and UNIQUE as well as STORED_COVER_DOMAIN and + // UNIQUE_COVER_DOMAIN. + +public: + typedef typename T::Periodic_point value_type; + typedef const typename T::Periodic_point * pointer; + typedef const typename T::Periodic_point & reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + typedef typename T::Periodic_point Periodic_point; + typedef Periodic_4_hyperbolic_triangulation_point_iterator_2 Periodic_point_iterator; + + typedef typename T::Vertex Vertex; + typedef typename T::Vertex_iterator Vertex_iterator; + + typedef typename T::Offset Offset; + typedef typename T::Iterator_type Iterator_type; + + Periodic_4_hyperbolic_triangulation_point_iterator_2(Iterator_type it = T::STORED) + : _t(NULL), _it(it) {} + + Periodic_4_hyperbolic_triangulation_point_iterator_2(const T * t, + Iterator_type it = T::STORED) + : _t(t), pos(_t->vertices_begin()), _it(it) + { + if (_it == T::UNIQUE || _it == T::UNIQUE_COVER_DOMAIN) + { + while (pos != _t->vertices_end() && !is_canonical() ) + ++pos; + } + } + + // used to initialize the past-the-end iterator + Periodic_4_hyperbolic_triangulation_point_iterator_2(const T* t, int, + Iterator_type it = T::STORED) + : _t(t), pos(_t->vertices_end()), _it(it) {} + + Periodic_point_iterator& operator++() + { + switch (_it) + { + case T::STORED: + case T::STORED_COVER_DOMAIN: + ++pos; + break; + case T::UNIQUE: + case T::UNIQUE_COVER_DOMAIN: + do + { + ++pos; + } + while (pos != _t->vertices_end() && !is_canonical()); + break; + default: + CGAL_triangulation_assertion(false); + }; + return *this; + } + + Periodic_point_iterator& operator--() + { + switch (_it) + { + case T::STORED: + case T::STORED_COVER_DOMAIN: + --pos; + break; + case T::UNIQUE: + case T::UNIQUE_COVER_DOMAIN: + do + { + --pos; + } + while (pos != _t->vertices_begin() && !is_canonical()); + break; + default: + CGAL_triangulation_assertion(false); + }; + return *this; + } + + Periodic_point_iterator operator++(int) + { + Periodic_point_iterator tmp(*this); + ++(*this); + return tmp; + } + + Periodic_point_iterator operator--(int) + { + Periodic_point_iterator tmp(*this); + --(*this); + return tmp; + } + + bool operator==(const Periodic_point_iterator& pi) const + { + // We are only allowed to compare iterators of the same type. + CGAL_triangulation_assertion(_it == pi._it); + return _t == pi._t && pos == pi.pos; + } + + bool operator!=(const Periodic_point_iterator& pi) const + { + return !(*this == pi); + } + + reference operator*() const + { + periodic_point = construct_periodic_point(); + return periodic_point; + } + + pointer operator->() const + { + periodic_point = construct_periodic_point(); + return &periodic_point; + } + + Vertex_iterator get_vertex() const + { + return pos; + } +private: + const T* _t; + Vertex_iterator pos; // current vertex. + Iterator_type _it; + int _off; // current offset + mutable Periodic_point periodic_point; // current point. + +private: + // check whether pos points onto a vertex inside the original + // domain. If we are computing in 1-sheeted covering this should + // always be true. + bool is_canonical() + { + return (_t->get_offset(pos).is_null()); + } + + Periodic_point construct_periodic_point() const + { + CGAL_triangulation_assertion(pos != typename T::Vertex_handle()); + Offset off = _t->get_offset(pos); + return std::make_pair(pos->point(), off); + } +}; + +namespace Periodic_4_hyperbolic_triangulation_2_internal +{ +template +class Domain_tester +{ + const T *t; + + public: + Domain_tester() {} + Domain_tester(const T *tr) : t(tr) {} + + bool operator()(const typename T::Vertex_iterator & v) const + { + return (t->get_offset(v) != typename T::Offset(0, 0)); + } +}; +} + +// Iterates over the vertices in a periodic triangulation that are +// located inside the original cube. +// Derives from Filter_iterator in order to add a conversion to handle +// +// Comments: +// When computing in 1-sheeted covering, there will be no difference +// between a normal Vertex_iterator and this iterator +template +class Periodic_4_hyperbolic_triangulation_unique_vertex_iterator_2 + : public Filter_iterator > +{ + + typedef typename T::Vertex_handle Vertex_handle; + typedef typename T::Vertex_iterator Vertex_iterator; + + typedef typename Periodic_4_hyperbolic_triangulation_2_internal::Domain_tester Tester; + + typedef Filter_iterator Base; + typedef Periodic_4_hyperbolic_triangulation_unique_vertex_iterator_2 Self; +public: + + Periodic_4_hyperbolic_triangulation_unique_vertex_iterator_2() : Base() {} + Periodic_4_hyperbolic_triangulation_unique_vertex_iterator_2(const Base &b) : Base(b) {} + + Self & operator++() + { + Base::operator++(); + return *this; + } + Self & operator--() + { + Base::operator--(); + return *this; + } + Self operator++(int) + { + Self tmp(*this); + ++(*this); + return tmp; + } + Self operator--(int) + { + Self tmp(*this); + --(*this); + return tmp; + } + + operator Vertex_handle() const + { + return Base::base(); + } +}; + +} //namespace CGAL + +#endif // CGAL_PERIODIC_4_HYPERBOLIC_TRIANGULATION_ITERATORS_2_H diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/OriginalDomainNeighbors.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/OriginalDomainNeighbors.h similarity index 100% rename from Periodic_4_hyperbolic_triangulation_2/include/CGAL/OriginalDomainNeighbors.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/OriginalDomainNeighbors.h diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/OriginalDomainNeighborsCommon.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/OriginalDomainNeighborsCommon.h similarity index 100% rename from Periodic_4_hyperbolic_triangulation_2/include/CGAL/OriginalDomainNeighborsCommon.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/OriginalDomainNeighborsCommon.h diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/PointGraphicsItem.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/PointGraphicsItem.h similarity index 100% rename from Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/PointGraphicsItem.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/PointGraphicsItem.h diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/PointTranslation.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/PointTranslation.h similarity index 100% rename from Periodic_4_hyperbolic_triangulation_2/include/CGAL/PointTranslation.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/PointTranslation.h diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/PointTranslationWithInfo.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/PointTranslationWithInfo.h similarity index 100% rename from Periodic_4_hyperbolic_triangulation_2/include/CGAL/PointTranslationWithInfo.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/PointTranslationWithInfo.h diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/TriangulationGraphicsItemWithColorInfo.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/TriangulationGraphicsItemWithColorInfo.h index f2b08f17195..d8332158459 100644 --- a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/TriangulationGraphicsItemWithColorInfo.h +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Qt/TriangulationGraphicsItemWithColorInfo.h @@ -165,7 +165,7 @@ TriangulationGraphicsItem::drawAll(QPainter *painter) //delete QPen temp = painter->pen(); QPen old = temp; - temp.setWidthF(/*0.0035*/0.0045); + temp.setWidthF(/*0.0035*/0.0025); painter->setPen(temp); // @@ -175,7 +175,14 @@ TriangulationGraphicsItem::drawAll(QPainter *painter) for(typename T::Finite_edges_iterator eit = t->finite_edges_begin(); eit != t->finite_edges_end(); ++eit){ - painterostream << t->segment(*eit); + + //typename T::Vertex_handle vh = eit->first->finite_vertices_begin(); + //std::cout << vh << std::endl; + + //typename T::Geom_traits::Segment_2 sg = t->segment(*eit); + //std::cout << sg(0) << std::endl; + + painterostream << t->segment(*eit); } } @@ -200,59 +207,50 @@ TriangulationGraphicsItem::paintVertices(QPainter *painter) it != t->finite_vertices_end(); it++){ - // draw vertices with color storing in their info - if(it->info().getColor() == 0) { - painter->setPen(QPen(::Qt::red, 3.)); - } - - if(it->info().getColor() == 1) { - painter->setPen(QPen(::Qt::green, 3.)); - } - - if(it->info().getColor() == 2) { - painter->setPen(QPen(::Qt::cyan, 3.)); - } - - if(it->info().getColor() == 3) { - painter->setPen(QPen(::Qt::magenta, 3.)); - } - - if(it->info().getColor() == 6) { - painter->setPen(QPen(::Qt::yellow, 3.)); - } - - if(it->info().getColor() == 5) { - // brown - painter->setPen(QPen(QColor(139, 69, 19), 3.)); - } - - if(it->info().getColor() == 4) { - painter->setPen(QPen(::Qt::blue, 3.)); - } - - - if(it->info().getColor() == 7) { - // orange - QColor orange = QColor(255, 165, 0); - painter->setPen(QPen(orange, 3.)); - } - - if(it->info().getColor() == 8) { - // dark green - QColor blue = QColor(0, 102, 51); - painter->setPen(QPen(blue, 3.)); - } - - if(it->info().getColor() == 9) { - // purple - QColor blue = QColor(102, 0, 102); - painter->setPen(QPen(blue, 3.)); - } - - if(it->info().getColor() == 10) { - // close to blue - QColor blue = QColor(131, 111, 255); - painter->setPen(QPen(blue, 3.)); + + switch (it->info().getColor()) { + case 0: + painter->setPen(QPen(::Qt::red, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 1: + painter->setPen(QPen(::Qt::green, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 2: + painter->setPen(QPen(::Qt::blue, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 3: + painter->setPen(QPen(::Qt::magenta, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 4: + painter->setPen(QPen(::Qt::darkGreen, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 5: + painter->setPen(QPen(::Qt::darkRed, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 6: + painter->setPen(QPen(::Qt::darkBlue, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 7: + painter->setPen(QPen(::Qt::darkYellow, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 8: + painter->setPen(QPen(::Qt::darkCyan, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 9: + painter->setPen(QPen(::Qt::yellow, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 10: + painter->setPen(QPen(::Qt::cyan, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 11: + painter->setPen(QPen(::Qt::black, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + case 12: + painter->setPen(QPen(::Qt::lightGray, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; + default: + painter->setPen(QPen(::Qt::gray, 3., ::Qt::SolidLine, ::Qt::RoundCap, ::Qt::RoundJoin)); + break; } // @@ -266,21 +264,21 @@ TriangulationGraphicsItem::paintVertices(QPainter *painter) double py = to_double(it->point().y()); double dist = px*px + py*py; if(dist > 0.25) { - temp.setWidth(8);//6 + temp.setWidth(6);//6 } if(dist > 0.64) { - temp.setWidth(7);//5 + temp.setWidth(4);//5 } if(dist > 0.81) { - temp.setWidth(5);//3 - } - if(dist > 0.92) { - temp.setWidth(4);//3 - } - if(dist > 0.98) { temp.setWidth(3);//3 } - //painter->setPen(temp); + if(dist > 0.92) { + temp.setWidth(2);//3 + } + if(dist > 0.98) { + temp.setWidth(1);//3 + } + painter->setPen(temp); QPointF point = matrix.map(convert(it->point())); painter->drawPoint(point); @@ -337,8 +335,10 @@ TriangulationGraphicsItem::paint(QPainter *painter, painter->setPen(this->edgesPen()); // painter->drawRect(boundingRect()); if ( t->dimension()<2 || option->exposedRect.contains(boundingRect()) ) { + std::cout << "Drawing all!" << std::endl; drawAll(painter); } else { + std::cout << "Else-ing!" << std::endl; m_painter = painter; painterostream = PainterOstream(painter); CGAL::apply_to_range (*t, diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Sqrt_field.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Sqrt_field.h index 1bab8afd210..6c7ef754025 100644 --- a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Sqrt_field.h +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Sqrt_field.h @@ -213,521 +213,5 @@ Sqrt_field copysign(const Sqrt_field& x, const Sqrt_field& y) } // end MT - added to please libc++ - -#endiftemplate -class Octagon_matrix -{ -public: - typedef Octagon_matrix Self; - typedef complex Extended_field; - - Extended_field M11; - Extended_field M12; - string label; - - Octagon_matrix(const Extended_field& M11_, const Extended_field& M12_, - const string& label_ = string("") ) : - M11(M11_), M12(M12_), label(label_) {} - - string merge_labels(const Self& rh) const - { - return label + "*" + rh.label; - } - - Self operator*(const Self& rh) const - { - return Self( M11*rh.M11 + aux*M12*conj(rh.M12), - M11*rh.M12 + M12*conj(rh.M11), merge_labels(rh) ); - } - - Self inverse() const - { - Self inv = Self(conj(M11), -M12); - string inv_label; - for(long i = label.size() - 1; i >= 0; i--) { - if(label[i] >= 'a' && label[i] <= 'd') { - inv_label.push_back(label[i]); - inv_label.push_back('^'); - inv_label.push_back('-'); - inv_label.push_back('1'); - } - if(label[i] == '*') { - inv_label.push_back('*'); - } - if(label[i] == '1') { - assert(i - 3 >= 0); - assert(label[i - 3] >= 'a' && label[i - 3] <= 'd'); - inv_label.push_back(label[i - 3]); - i = i - 3; - } - } - inv.label = inv_label; - return inv; - } - - // rotation \pi/4 - Octagon_matrix rotate() const - { - Sqrt_field B1 = real(M12); - Sqrt_field B2 = imag(M12); - - // sqrt(2) - Sqrt_field k = Sqrt_field(0, 1); - - Sqrt_field BB1 = (B1 - B2)*k; - Sqrt_field BB2 = (B1 + B2)*k; - - assert(BB2.l % 2 == 0 && BB2.r % 2 == 0); - BB1.l = BB1.l/2; - BB1.r = BB1.r/2; - BB2.l = BB2.l/2; - BB2.r = BB2.r/2; - - return Octagon_matrix(M11, Extended_field(BB1, BB2)); - } - - Sqrt_field trace() const - { - return Sqrt_field(2, 0)*real(M11); - } - - double length() const - { - typedef long double ld; - - ld l = real(M11).l; - ld r = real(M11).r; - ld tr = l + sqrt(2.)*r; - if (tr < 0) { - tr = -tr; - } - - return 2.*acosh(tr); - } - - // determinant == 1 - Extended_field det() const - { - return norm(M11) - aux * norm(M12); - } - - static complex toComplexDouble(Extended_field M) //const - { - Sqrt_field rl = real(M); - Sqrt_field img = imag(M); - - return complex(rl.l + sqrt(2.)*rl.r, img.l + sqrt(2.)*img.r); - } - - pair apply(double x, double y) - { - typedef complex Cmpl; - Cmpl m11 = toComplexDouble(M11); - Cmpl m12 = toComplexDouble(M12); - - double ax = sqrt(aux.l + sqrt(2.)*aux.r); - - Cmpl z(x, y); - Cmpl res = (m11*z + ax*m12)/(ax*(conj(m12)*z) + conj(m11)); - return pair(real(res), imag(res)); - } - -//private: - static Sqrt_field aux; -}; - - -template -Sqrt_field Octagon_matrix::aux = Sqrt_field(-1, 1); - -// just to give an order(ing) -template -bool operator < (const complex >& lh, - const complex >& rh) -{ - if (real(lh) < real(rh)) { - return true; - } - - if (real(lh) == real(rh)) { - if (imag(lh) < imag(rh)) { - return true; - } - } - - return false; -} - -// just to order octagon_matrices -template -bool operator < (const Octagon_matrix& lh, - const Octagon_matrix& rh) -{ - if (lh.M11 < rh.M11) { - return true; - } - - if (lh.M11 == rh.M11 ) { - if (lh.M12 < rh.M12) { - return true; - } - } - - return false; -} - -template -bool operator == (const Octagon_matrix& lh, - const Octagon_matrix& rh) -{ - return (lh.M11 == rh.M11 && lh.M12 == rh.M12); -} - -template -ostream& operator<<(ostream& os, const Octagon_matrix& m) -{ - os << m.M11 << " " << m.M12; - return os; -} - -typedef long long ll; -typedef Sqrt_field SqrtField; -typedef Octagon_matrix OctagonMatrix; -typedef OctagonMatrix::Extended_field Entry; - -void get_generators(vector& gens) -{ - Entry M11 = Entry(SqrtField(1, 1), SqrtField(0, 0)); - - vector M12(8, Entry(SqrtField(0, 0), SqrtField(0, 0))); - M12[0] = M11 * Entry(SqrtField(0, 1), SqrtField(0, 0)); - M12[1] = M11 * Entry(SqrtField(1, 0), SqrtField(1, 0)); - M12[2] = M11 * Entry(SqrtField(0, 0), SqrtField(0, 1)); - M12[3] = M11 * Entry(SqrtField(-1, 0), SqrtField(1, 0)); - M12[4] = M11 * Entry(SqrtField(0, -1), SqrtField(0, 0)); - M12[5] = M11 * Entry(SqrtField(-1, 0), SqrtField(-1, 0)); - M12[6] = M11 * Entry(SqrtField(0, 0), SqrtField(0, -1)); - M12[7] = M11 * Entry(SqrtField(1, 0), SqrtField(-1, 0)); - - string labels[8] = {string("a"), string("b^-1"), string("c"), string("d^-1"), - string("a^-1"), string("b"), string("c^-1"), string("d")}; - for(int i = 0; i < 8; i++) { - gens.push_back(OctagonMatrix(M11, M12[i], labels[i])); - } -} - -// a, b, c, d, a^-1, b^-1, c^-1, d^-1 -vector gens; - -bool IsCanonical(const OctagonMatrix& m); - -void generate_words( set& words, vector& prev, int depth ) -{ - if (depth == 1) { - for(int i = 0; i < 8; i++) { - words.insert( gens[i] ); - prev.push_back( gens[i] ); - } - return; - } - - vector els; - generate_words( words, els, depth - 1); - - OctagonMatrix temp = OctagonMatrix(Entry(), Entry()); - ll size = els.size(); - bool is_new = false; - for(ll k = 0; k < size; k++) { - for(int i = 0; i < 8; i++) { - temp = els[k]*gens[i]; - - if(temp.length() > 15.) { - continue; - } - - is_new = words.insert(temp).second; - if(is_new == true) { - prev.push_back(temp); - } - } - } -} - -// does the axis of a given matrix go through the fundamental octagon -bool IsCanonical(const OctagonMatrix& m) -{ - OctagonMatrix temp = m; - - // rotate while |B1| < |B2| - SqrtField B1, B2; - SqrtField C = SqrtField(-1, -1); - for(int i = 0; i < 8 && C != C.abs(); i++) { - B1 = real(temp.M12).abs(); - B2 = imag(temp.M12).abs(); - C = B1 - B2; - - temp = temp.rotate(); - } - assert(C == C.abs()); - - // (2 - sqrt(2))(|B1| + (sqrt(2) - 1)|B2|) - SqrtField right = SqrtField(2, -1)*(B1 + SqrtField(-1, 1)*B2); - - // |A2| - SqrtField left = imag(temp.M11).abs(); - - // left <= right -> true - C = right - left; - return C == C.abs(); -} - -void dfs(const OctagonMatrix& m, set& visited) -{ - assert(IsCanonical(m)); - visited.insert(m); - - OctagonMatrix candidate = m; - for(int i = 0; i < 8; i++) { - candidate = gens[i]*m*gens[(i + 4) % 8]; - if(IsCanonical(candidate) == true && visited.find(candidate) == visited.end()) { - dfs(candidate, visited); - } - } -} - -// map, m = Aux * origin * Aux^{-1} -void dfs_with_info(const pair& new_pair, - map & visited) -{ - assert(IsCanonical(new_pair.first)); - visited.insert(new_pair); - - const OctagonMatrix& current = new_pair.first; - const OctagonMatrix& current_aux = new_pair.second; - OctagonMatrix candidate = current, candidate_aux = current_aux; - for(int i = 0; i < 8; i++) { - candidate = gens[i]*current*gens[(i + 4) % 8]; - if(IsCanonical(candidate) == true && visited.find(candidate) == visited.end()) { - candidate_aux = gens[i]*current_aux; - dfs_with_info(pair(candidate, candidate_aux), visited); - } - } -} - - -void dfs_with_info(const OctagonMatrix& origin, - map& visited) -{ - assert(IsCanonical(origin)); - OctagonMatrix id = OctagonMatrix(Entry(SqrtField(1, 0), SqrtField(0, 0)), - Entry(SqrtField(0, 0), SqrtField(0, 0))); - pair new_pair(origin, id); - - dfs_with_info(new_pair, visited); -} - - -class IntersectionNumber -{ -public: - -struct Point -{ - Point(double x_ = 0, double y_ = 0) : x(x_), y(y_) {} - - double x, y; -}; - -OctagonMatrix m; - -IntersectionNumber(const OctagonMatrix& m_) : m(m_) -{} - -long operator() () const -{ - set visited; - set::iterator it, it2; - map nb_map; - map::iterator mit; - - dfs(m, visited); - - set > common; - for(it = visited.begin(); it != visited.end(); ++it) { - for(it2 = it; it2 != visited.end(); ++it2) { - if(*it == *it2) { - continue; - } - if(haveIntersection(*it, *it2) == true) { - common.clear(); - count_nb(*it, *it2, common); - - mit = nb_map.find(common.size()); - if(mit != nb_map.end()) { - mit->second += 1; - } else { - nb_map.insert(pair(common.size(), 1)); - } - } - } - } - - long nb = 0; - for(mit = nb_map.begin(); mit != nb_map.end(); mit++) { - assert( mit->second % mit->first == 0 ); - nb += mit->second/mit->first; - } - return nb; -} - - -void count_nb(const OctagonMatrix& m1, const OctagonMatrix& m2, set >& visited) const -{ - typedef pair matrix_pair; - visited.insert(matrix_pair(m1, m2)); - - OctagonMatrix c1 = m1, c2 = m2; - for(int i = 0; i < 8; i++) { - c1 = gens[i]*m1*gens[(i + 4) % 8]; - c2 = gens[i]*m2*gens[(i + 4) % 8]; - if(IsCanonical(c1) == true && IsCanonical(c2) == true && visited.find(matrix_pair(c1, c2)) == visited.end()) { - count_nb(c1, c2, visited); - } - } -} - -//private: - -// check whether two axis have intersection -bool haveIntersection(const OctagonMatrix& m1, const OctagonMatrix& m2) const -{ - Point p1, p2; - intersectWithInfinity(m1, p1, p2); - - Point p3, p4; - intersectWithInfinity(m2, p3, p4); - - // orientation test - double sign1 = (p1.x - p3.x)*(p2.y - p3.y) - (p1.y - p3.y)*(p2.x - p3.x); - double sign2 = (p1.x - p4.x)*(p2.y - p4.y) - (p1.y - p4.y)*(p2.x - p4.x); - - assert( sign1 * sign2 != 0); - return (sign1 * sign2 < 0); -} - -void intersectWithInfinity(const OctagonMatrix& m, Point& p1, Point& p2) const -{ - Entry a = m.M11, b = m.M12, aux = m.aux; - - Entry four = Entry(SqrtField(4, 0), SqrtField(0, 0)); - Entry two = Entry(SqrtField(2, 0), SqrtField(0, 0)); - - Entry D = (a - conj(a))*(a - conj(a)); - D += four*b*conj(b)*aux; - Entry T1 = conj(a) - a; - Entry T2 = two*conj(b); - - complex d = m.toComplexDouble(D); - complex t1 = m.toComplexDouble(T1); - complex t2 = m.toComplexDouble(T2); - complex au = complex(m.aux.l + sqrt(2.)*m.aux.r, 0); - - complex z1 = (t1 + sqrt(d))/(t2*sqrt(au)); - complex z2 = (t1 - sqrt(d))/(t2*sqrt(au)); - - p1 = Point(real(z1), imag(z1)); - p2 = Point(real(z2), imag(z2)); - - assert(p1.x*p1.x + p1.y*p1.y > 0.99 && p1.x*p1.x + p1.y*p1.y < 1.01); - assert(p2.x*p2.x + p2.y*p2.y > 0.99 && p2.x*p2.x + p2.y*p2.y < 1.01); -} - - -}; - -void Delete(const set& canonical_set, vector& output) -{ - set redundant; - - set::iterator it; - for(it = canonical_set.begin(); it != canonical_set.end(); ++it) { - if(redundant.find(*it) != redundant.end()) { - continue; - } - - set visited; - dfs(*it, visited); - visited.erase(*it); - - redundant.insert(visited.begin(), visited.end()); - output.push_back(*it); - } -} - -void generate_unique_words(vector& output, double threshold = 10, int word_length = 13) -{ - get_generators(gens); - - set unique_words; - vector temp; - generate_words(unique_words, temp, word_length); - - double l = 0; - set::iterator uit; - for(uit = unique_words.begin(); uit != unique_words.end(); ++uit) { - l = uit->length(); - if(0. < l && l < threshold) { - output.push_back( *uit ); - } - } - - cout << "nb of unique words " << output.size() << endl; -} - -// words that correspond to union of 1-cycles -void generate_words_union_1_cycles(vector& out) -{ - if(gens.size() == 0) { - get_generators(gens); - } - OctagonMatrix f[4] = {gens[0], gens[5], gens[2], gens[7]}; - - OctagonMatrix F[8] = { - f[0]*f[0].inverse(), - f[0], - f[0]*f[1], - f[0]*f[1]*f[2], - f[0]*f[1]*f[2]*f[3], - f[3]*f[2]*f[1], - f[3]*f[2], - f[3] - }; - - long counter = 0; - for(int i = 1; i < 5; i++) { - for(int j = 0; j < 8; j++) { - for(int k = 0; k < 8; k++) { - if (j == k) { - continue; - } - // intersection - if ((0 < j && j < i) && (i < k)) { - continue; - } - if ((0 < k && k < i) && (i < j)) { - continue; - } - counter++; - - OctagonMatrix Tr = F[i]*F[k].inverse()*F[j]; - // check that Tr != Id - if(Tr.length() > 2.) { - out.push_back(Tr); - } - } - } - } - cout << counter << endl; - -} +#endif // CGAL_PERIODIC_4_HYPERBOLIC_TRIANGULATION_SQRT_FIELD_H diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/TranslationInfo.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/TranslationInfo.h index e71adf90da8..8bde5df3257 100644 --- a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/TranslationInfo.h +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/TranslationInfo.h @@ -32,7 +32,7 @@ public: color = new_color; } - int getColor() const + int getColor() const { return color; } diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Triangulation_hyperbolic_traits_2.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Triangulation_hyperbolic_traits_2.h index 6731cb9c780..f7018f5f470 100644 --- a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Triangulation_hyperbolic_traits_2.h +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Triangulation_hyperbolic_traits_2.h @@ -38,44 +38,44 @@ namespace CGAL { template < class R > class Triangulation_hyperbolic_traits_2 { public: - typedef Triangulation_hyperbolic_traits_2 Self; + typedef Triangulation_hyperbolic_traits_2 Self; - typedef R Kernel; + typedef R Kernel; - typedef R Rep; - typedef typename R::RT RT; - typedef typename R::Point_2 Point_2; - typedef typename R::Vector_2 Vector_2; - typedef typename R::Triangle_2 Triangle_2; - typedef typename R::Line_2 Line_2; - typedef typename R::Ray_2 Ray_2; + typedef R Rep; + typedef typename R::RT RT; + typedef typename R::Point_2 Point_2; + typedef typename R::Vector_2 Vector_2; + typedef typename R::Triangle_2 Triangle_2; + typedef typename R::Line_2 Line_2; + typedef typename R::Ray_2 Ray_2; - typedef typename R::Vector_3 Vector_3; - typedef typename R::Point_3 Point_3; + typedef typename R::Vector_3 Vector_3; + typedef typename R::Point_3 Point_3; - typedef typename R::Less_x_2 Less_x_2; - typedef typename R::Less_y_2 Less_y_2; - typedef typename R::Compare_x_2 Compare_x_2; - typedef typename R::Compare_y_2 Compare_y_2; - typedef typename R::Orientation_2 Orientation_2; - typedef typename R::Side_of_oriented_circle_2 Side_of_oriented_circle_2; - typedef typename R::Construct_bisector_2 Construct_bisector_2; - typedef typename R::Compare_distance_2 Compare_distance_2; - typedef typename R::Construct_triangle_2 Construct_triangle_2; - typedef typename R::Construct_direction_2 Construct_direction_2; + typedef typename R::Less_x_2 Less_x_2; + typedef typename R::Less_y_2 Less_y_2; + typedef typename R::Compare_x_2 Compare_x_2; + typedef typename R::Compare_y_2 Compare_y_2; + typedef typename R::Orientation_2 Orientation_2; + typedef typename R::Side_of_oriented_circle_2 Side_of_oriented_circle_2; + typedef typename R::Construct_bisector_2 Construct_bisector_2; + typedef typename R::Compare_distance_2 Compare_distance_2; + typedef typename R::Construct_triangle_2 Construct_triangle_2; + typedef typename R::Construct_direction_2 Construct_direction_2; typedef typename R::Angle_2 Angle_2; typedef typename R::Construct_midpoint_2 Construct_midpoint_2; typedef typename R::Compute_squared_distance_2 Compute_squared_distance_2; - typedef typename R::Iso_rectangle_2 Iso_rectangle_2; - typedef typename R::Circle_2 Circle_2; + typedef typename R::Iso_rectangle_2 Iso_rectangle_2; + typedef typename R::Circle_2 Circle_2; - typedef boost::tuple Arc_2; - typedef typename R::Segment_2 Line_segment_2; - typedef boost::variant Segment_2; + typedef boost::tuple Arc_2; + typedef typename R::Segment_2 Line_segment_2; + typedef boost::variant Segment_2; - typedef typename R::Line_2 Euclidean_line_2; + typedef typename R::Line_2 Euclidean_line_2; private: // PoincarĂ© disk diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/GroupOfIndex2.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/unused/GroupOfIndex2.h similarity index 100% rename from Periodic_4_hyperbolic_triangulation_2/include/CGAL/GroupOfIndex2.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/unused/GroupOfIndex2.h diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Hyperbolic_random_points_in_disc_2.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/unused/Hyperbolic_random_points_in_disc_2.h similarity index 95% rename from Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Hyperbolic_random_points_in_disc_2.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/unused/Hyperbolic_random_points_in_disc_2.h index 3b14c7b9447..659f177e643 100644 --- a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/include/Hyperbolic_random_points_in_disc_2.h +++ b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/unused/Hyperbolic_random_points_in_disc_2.h @@ -42,8 +42,10 @@ void Hyperbolic_random_points_in_disc_2(std::vector& outpu if (seed != -1) { rand = CGAL::Random(seed); } - CGAL::Random_points_in_disc_2 in_Euclidean_disk(rh, rand); + /*CGAL::Random_points_in_disc_2 in_Euclidean_disk(rh, rand);*/ + CGAL::Random_points_in_disc_2 in_Euclidean_disk(rh); + std::vector pts; pts.reserve(nb); for(int i = 0; i < nb ; i++) { diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/Translations.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/unused/Translations.h similarity index 100% rename from Periodic_4_hyperbolic_triangulation_2/include/CGAL/Translations.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/unused/Translations.h diff --git a/Periodic_4_hyperbolic_triangulation_2/include/CGAL/temp.h b/Periodic_4_hyperbolic_triangulation_2/include/CGAL/unused/temp.h similarity index 100% rename from Periodic_4_hyperbolic_triangulation_2/include/CGAL/temp.h rename to Periodic_4_hyperbolic_triangulation_2/include/CGAL/unused/temp.h