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 00000000000..36b51cf599e Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Delaunay_triangulation_2.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Delaunay_triangulation_2.qrc b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Delaunay_triangulation_2.qrc new file mode 100644 index 00000000000..adaf1425154 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Delaunay_triangulation_2.qrc @@ -0,0 +1,12 @@ + + + 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 00000000000..719525886db Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G16.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G16.png new file mode 100644 index 00000000000..07704340074 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G16.png differ 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 00000000000..76b3163d901 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G2.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G4.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G4.png new file mode 100644 index 00000000000..865e84b4c48 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G4.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G8.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G8.png new file mode 100644 index 00000000000..4f5c3ea3d01 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/G8.png differ 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 00000000000..62437e6bfc9 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/Voronoi_diagram_2.png differ 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 00000000000..40dab5cf244 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/a.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/about_CGAL.html b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/about_CGAL.html new file mode 100644 index 00000000000..6b2b2a5d943 --- /dev/null +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/about_CGAL.html @@ -0,0 +1,8 @@ + + +

+

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 00000000000..47e246a4a2c Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/b.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/c.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/c.png new file mode 100644 index 00000000000..63574ac570c Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/c.png differ 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 00000000000..15fe4edb6af Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/cgal_logo_ipe_2013.png differ 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 00000000000..f743b7a64ca Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/circumcenter.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/conflict_zone.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/conflict_zone.png new file mode 100644 index 00000000000..5fd4d5b4ce6 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/conflict_zone.png differ 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 00000000000..3a49172fa17 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/constrained_triangulation.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/d.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/d.png new file mode 100644 index 00000000000..9bf6f7d9bb0 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/d.png differ 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 00000000000..af5d1221412 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileNew.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileOpen.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileOpen.png new file mode 100644 index 00000000000..fc6f17e9774 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileOpen.png differ 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 00000000000..8feec99bee8 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fileSave.png differ 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 00000000000..98bc12d3ed6 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/fit-page-32.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/inputPoint.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/inputPoint.png new file mode 100644 index 00000000000..e9d53a20571 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/inputPoint.png differ 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 00000000000..63d0a08cca3 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/inputPolyline.png differ 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 00000000000..44f431d9843 Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/moving_point.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/triangulation.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/triangulation.png new file mode 100644 index 00000000000..ce082a6e08f Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/triangulation.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/zoom-best-fit.png b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/zoom-best-fit.png new file mode 100644 index 00000000000..0df9f01776c Binary files /dev/null and b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_Dirichlet_region/icons/zoom-best-fit.png differ diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/CMakeLists.txt b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/CMakeLists.txt index d16b65e3a23..3ac6c2c4891 100644 --- a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/CMakeLists.txt +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/CMakeLists.txt @@ -31,14 +31,8 @@ qt5_add_resources ( RESOURCE_FILES resources/Periodic_4_hyperbolic_triangulation # cpp files add_executable ( Periodic_4_hyperbolic_triangulation_2_demo Periodic_4_hyperbolic_triangulation_2_demo.cpp ) - qt5_use_modules( Periodic_4_hyperbolic_triangulation_2_demo Widgets) - add_to_cached_list( CGAL_EXECUTABLE_TARGETS Periodic_4_hyperbolic_triangulation_2_demo ) - target_link_libraries( Periodic_4_hyperbolic_triangulation_2_demo ${CGAL_LIBRARIES} ${QT_LIBRARIES} ${CGAL_QT_LIBRARIES} ) - - - diff --git a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/Periodic_4_hyperbolic_triangulation_2_demo.cpp b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/Periodic_4_hyperbolic_triangulation_2_demo.cpp index 28ed1f12a96..b4e2538fd0c 100644 --- a/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/Periodic_4_hyperbolic_triangulation_2_demo.cpp +++ b/Periodic_4_hyperbolic_triangulation_2/demo/Periodic_4_hyperbolic_triangulation_2/Periodic_4_hyperbolic_triangulation_2_demo.cpp @@ -4,7 +4,7 @@ #include #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