dust3d/thirdparty/cgal/CGAL-4.13/include/CGAL/Periodic_2_triangulation_2.h

4679 lines
150 KiB
C
Raw Normal View History

// 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$
// SPDX-License-Identifier: GPL-3.0+
//
// Author(s) : Nico Kruithof <Nico@nghk.nl>
#ifndef CGAL_PERIODIC_2_TRIANGULATION_2_H
#define CGAL_PERIODIC_2_TRIANGULATION_2_H
#include <CGAL/license/Periodic_2_triangulation_2.h>
#include <CGAL/basic.h>
#include <list>
#include <vector>
#include <map>
#include <algorithm>
#include <utility>
#include <iostream>
#include <CGAL/iterator.h>
#include <CGAL/Iterator_project.h>
#include <CGAL/function_objects.h>
#include <CGAL/triangulation_assertions.h>
#include <CGAL/Triangulation_utils_2.h>
#include <CGAL/Triangulation_data_structure_2.h>
#include <CGAL/Periodic_2_triangulation_face_base_2.h>
#include <CGAL/Periodic_2_triangulation_vertex_base_2.h>
#include <CGAL/Periodic_2_triangulation_iterators_2.h>
#include <CGAL/spatial_sort.h>
#include <boost/random/linear_congruential.hpp>
#include <boost/random/uniform_smallint.hpp>
#include <boost/random/variate_generator.hpp>
#include <CGAL/utility.h>
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<Gt>,
Periodic_2_triangulation_face_base_2<Gt> > >
class Periodic_2_triangulation_2
: public Triangulation_cw_ccw_2
{
typedef Periodic_2_triangulation_2<Gt, Tds> Self;
public:
// Public types of Periodic_2_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<int, 2> Covering_sheets;
/// The point type
typedef typename Gt::Point_2 Point;
/// The vector type
typedef typename Gt::Segment_2 Segment;
/// The segment type
typedef typename Gt::Vector_2 Vector;
/// 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<Point, Offset> Periodic_point;
/// A pair of periodic points representing a segment in the periodic domain.
typedef array<std::pair<Point, Offset>, 2> Periodic_segment;
/// A triple of periodic points representing a triangle in the periodic domain.
typedef array<std::pair<Point, Offset>, 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_2_triangulation_unique_vertex_iterator_2<Self>
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_2_triangulation_triangle_iterator_2<Self>
Periodic_triangle_iterator;
/// Iterator over all periodic segments
typedef Periodic_2_triangulation_segment_iterator_2<Self>
Periodic_segment_iterator;
/// Iterator over all periodic points
typedef Periodic_2_triangulation_point_iterator_2<Self>
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,
OUTSIDE_CONVEX_HULL, // unused, for compatibility with Alpha_shape_2
OUTSIDE_AFFINE_HULL // unused, for compatibility with Alpha_shape_2
};
/// Returns false, no infinite simplices in the periodic triangulation
template<class T>
bool is_infinite(const T&, int = 0) const { return false; }
//\}
// Auxiliary iterators for convenience
// do not use default template argument to please VC++
/// Functor that returns the point given a vertex
typedef Project_point<Vertex> 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;
/// Tag to distinguish periodic triangulations from others
typedef Tag_true Periodic_tag;
protected:
// Protected types of Periodic_2_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<Vertex_handle, Offset> Virtual_vertex;
typedef std::map<Vertex_handle, Virtual_vertex> 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<Vertex_handle, std::vector<Vertex_handle> >
Virtual_vertex_reverse_map;
typedef typename Virtual_vertex_reverse_map::const_iterator
Virtual_vertex_reverse_map_it;
typedef std::map<Vertex_handle, std::list<Vertex_handle> > 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_2_triangulation_2 & tr);
public:
// Public functions of Periodic_2_triangulation_2
/// \name Constructors
//\{
/// Constructor
Periodic_2_triangulation_2(
const Iso_rectangle &domain = Iso_rectangle(0, 0, 1, 1),
const Geom_traits &geom_traits = Geom_traits());
/// Copy constructor
Periodic_2_triangulation_2(const Periodic_2_triangulation_2<Gt, Tds> &tr);
/// Assignment
Periodic_2_triangulation_2 &operator=(const Periodic_2_triangulation_2 &tr);
/// Copy the triangulation
void copy_triangulation(const Periodic_2_triangulation_2 &tr);
/// Swap two triangulations
void swap(Periodic_2_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.
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(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(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(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(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(Vertex_handle v) const
{
return point(periodic_point(v));
}
Point point(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_2_triangulation_2_internal::Domain_tester<Self>(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_2_triangulation_2_internal::Domain_tester<Self>(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<Face_handle> &f,
std::vector<Vertex_handle> &w, std::vector<Offset> &offset_w,
std::vector<int> &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 &lt, 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 &lt,
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;
//\}
/// \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_2_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<Vertex_handle>& 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<class Stream>
Stream& draw_triangulation(Stream& os) const
{
Edge_iterator it = edges_begin();
for (; it != edges_end(); ++it)
{
os << segment(it);
}
return os;
}
protected:
std::vector<Vertex_handle> 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_2_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<Edge> & 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<class EdgeIt>
Vertex_handle star_hole(const Point& p, EdgeIt edge_begin, EdgeIt edge_end)
{
std::list<Face_handle> empty_list;
return star_hole(p, edge_begin, edge_end, empty_list.begin(),
empty_list.end());
}
template<class EdgeIt, class FaceIt>
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<Vertex_handle, std::list<Vertex_handle> >& 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<class Offset>
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_2_triangulation_2
/// \name Triangulation data members
// \{
/// Geometric traits
Gt _gt;
/// Triangulation data structure
Tds _tds;
// \}
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_2_triangulation_2
/// \name Periodic members
//\{
/// Determines if we currently compute in 3-cover or 1-cover.
Covering_sheets _cover;
/// The domain
Iso_rectangle _domain;
protected:
// @fixme this covering stuff should really be at the Delaunay level (will need
// to be if P2RT2 is ever introduced...)
/// 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;
private:
/// 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_2_triangulation_2
// CONSTRUCTORS
template<class Gt, class Tds>
Periodic_2_triangulation_2<Gt, Tds>::Periodic_2_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<class Gt, class Tds>
Periodic_2_triangulation_2<Gt, Tds>::Periodic_2_triangulation_2(const Periodic_2_triangulation_2 &tr)
{
copy_triangulation(tr);
}
//Assignment
template<class Gt, class Tds>
Periodic_2_triangulation_2<Gt, Tds> &
Periodic_2_triangulation_2<Gt, Tds>::operator=(
const Periodic_2_triangulation_2 &tr)
{
copy_triangulation(tr);
return *this;
}
// Helping functions
template < class GT, class Tds >
class Periodic_2_triangulation_2<GT, Tds>::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_2_triangulation_2<GT, Tds>::
copy_multiple_covering(const Periodic_2_triangulation_2<GT, Tds> & 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<Vertex_handle> 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<Vertex_handle>(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<Vertex_handle>::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<Vertex_handle>();
std::pair<Vertex_handle, Vertex_handle> 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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::copy_triangulation(
const Periodic_2_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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::swap(Periodic_2_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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
bool Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
bool Periodic_2_triangulation_2<Gt, Tds>::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_2_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 &copy = 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<Vertex_handle> &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<class Gt, class Tds>
bool Periodic_2_triangulation_2<Gt, Tds>::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<Vertex_handle>::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<class Gt, class Tds>
bool Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::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<Vertex_handle> &v1s =
virtual_vertices_reverse().find(vh1)->second;
const std::vector<Vertex_handle> &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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
void
Periodic_2_triangulation_2<Gt, Tds>::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<Vertex_handle> &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<class Gt, class Tds>
typename Periodic_2_triangulation_2<Gt, Tds>::Vertex_handle Periodic_2_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<Vertex_handle>();
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<Vertex_handle> 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<class Gt, class Tds>
typename Periodic_2_triangulation_2<Gt, Tds>::Vertex_handle
Periodic_2_triangulation_2<Gt, Tds>::insert_in_edge(const Point& p,
Face_handle f, int i)
{
return insert(p, EDGE, f, i);
}
template<class Gt, class Tds>
typename Periodic_2_triangulation_2<Gt, Tds>::Vertex_handle
Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
typename Periodic_2_triangulation_2<Gt, Tds>::Vertex_handle
Periodic_2_triangulation_2<Gt, Tds>::insert_in_face(const Point& p, Face_handle f)
{
return insert(p, FACE, f, 0);
}
template<class Gt, class Tds>
typename Periodic_2_triangulation_2<Gt, Tds>::Vertex_handle
Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
typename Periodic_2_triangulation_2<Gt, Tds>::Vertex_handle
Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
typename Periodic_2_triangulation_2<Gt, Tds>::Vertex_handle
Periodic_2_triangulation_2<Gt, Tds>::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<Vertex_handle> &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<class Gt, class Tds>
typename Periodic_2_triangulation_2<Gt, Tds>::Vertex_handle Periodic_2_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<Vertex_handle>();
}
return result;
}
template<class Gt, class Tds>
inline void Periodic_2_triangulation_2<Gt, Tds>::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<Vertex_handle> &virtual_copies = reverse_it->second;
for (typename std::vector<Vertex_handle>::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<class Gt, class Tds>
inline void Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
inline void Periodic_2_triangulation_2<Gt, Tds>::remove_first(Vertex_handle)
{
CGAL_assertion(number_of_vertices() == 1);
clear();
return;
}
template < class Gt, class Tds >
bool
Periodic_2_triangulation_2<Gt, Tds>::
remove_degree_init(Vertex_handle v, const Offset &v_o,
std::vector<Face_handle> &f,
std::vector<Vertex_handle> &w,
std::vector<Offset> &offset_w,
std::vector<int> &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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::make_hole(Vertex_handle v, std::list<Edge> & hole)
{
remove_too_long_edges_in_star(v);
std::list<Face_handle> 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<class Gt, class Tds>
inline typename Periodic_2_triangulation_2<Gt, Tds>::Face_handle Periodic_2_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<class Gt, class Tds>
inline typename Periodic_2_triangulation_2<Gt, Tds>::Face_handle Periodic_2_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<class Gt, class Tds>
inline typename Periodic_2_triangulation_2<Gt, Tds>::Face_handle Periodic_2_triangulation_2 <
Gt, Tds >::create_face(Face_handle f, int i, Vertex_handle v)
{
return _tds.create_face(f, i, v);
}
template<class Gt, class Tds>
inline typename Periodic_2_triangulation_2<Gt, Tds>::Face_handle Periodic_2_triangulation_2 <
Gt, Tds >::create_face(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3)
{
return _tds.create_face(v1, v2, v3);
}
template<class Gt, class Tds>
inline typename Periodic_2_triangulation_2<Gt, Tds>::Face_handle Periodic_2_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<class Gt, class Tds>
inline typename Periodic_2_triangulation_2<Gt, Tds>::Face_handle Periodic_2_triangulation_2 <
Gt, Tds >::create_face(Face_handle fh)
{
return _tds.create_face(fh);
}
template<class Gt, class Tds>
inline typename Periodic_2_triangulation_2<Gt, Tds>::Face_handle Periodic_2_triangulation_2 <
Gt, Tds >::create_face()
{
return _tds.create_face();
}
template<class Gt, class Tds>
inline
void Periodic_2_triangulation_2<Gt, Tds>::delete_face(Face_handle f)
{
_tds.delete_face(f);
}
template<class Gt, class Tds>
inline
void Periodic_2_triangulation_2<Gt, Tds>::delete_vertex(Vertex_handle v)
{
_tds.delete_vertex(v);
}
template<class Gt, class Tds>
bool Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
typename Periodic_2_triangulation_2<Gt, Tds>::Face_handle
Periodic_2_triangulation_2<Gt, Tds>::
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<boost::rand48&, boost::uniform_smallint<> > 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<class Gt, class Tds>
typename Periodic_2_triangulation_2<Gt, Tds>::Face_handle Periodic_2_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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::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<Triple<Face_handle, int, Face_handle> > 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<Face_handle> 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<Face_handle>::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<Vertex_handle> 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<Vertex_handle>::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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::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<Vertex_handle> 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<Vertex_handle>::iterator vit =
original_vertices.begin(); vit != original_vertices.end(); ++vit)
{
Vertex_handle v_cp;
std::vector<Vertex_handle> 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<Face_handle, std::pair<Face_handle, Offset> >
Virtual_face_map;
typedef std::map<Face_handle, std::vector<Face_handle> >
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<Face_handle> 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<Offset> off_v;
for (typename std::list<Vertex_handle>::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<array<Offset, 3> > off_nb;
for (typename std::list<Face_handle>::iterator fit = original_faces.begin(); fit
!= original_faces.end(); ++fit)
{
array<Offset, 3> 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<Face_handle>::iterator fit = original_faces.begin(); fit
!= original_faces.end(); ++fit)
{
Face_handle c_cp;
Vertex_handle v0, v1, v2;
std::vector<Face_handle> 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<Face_handle>::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<unsigned int>(n_f) < vvrmit->second.size());
(*fit)->set_vertex(i, vvrmit->second[n_f]);
}
}
}
// Set neighboring relations of face copies
typename std::list<array<Offset, 3> >::iterator oit = off_nb.begin();
for (typename std::list<Face_handle>::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<unsigned int>(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<Face_handle>::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<unsigned int>(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<Face_handle>::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<Face_handle>::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<Vertex_handle>();
++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<class GT, class Tds>
inline int Periodic_2_triangulation_2<GT, Tds>::find_too_long_edges(std::map <
Vertex_handle, std::list<Vertex_handle> > & 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<class GT, class Tds>
inline void Periodic_2_triangulation_2<GT, Tds>::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<class GT, class Tds>
inline void Periodic_2_triangulation_2<GT, Tds>::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<class GT, class Tds>
inline typename Periodic_2_triangulation_2<GT, Tds>::Face_handle Periodic_2_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<class Gt, class Tds>
Bounded_side Periodic_2_triangulation_2<Gt, Tds>::side_of_face(const Point &q,
const Offset &off, Face_handle f, Locate_type &lt, 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<class Gt, class Tds>
Oriented_side Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
Bounded_side Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
Bounded_side Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
bool Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
bool Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
inline Comparison_result Periodic_2_triangulation_2<Gt, Tds>::compare_x(
const Point& p, const Point& q) const
{
return geom_traits().compare_x_2_object()(p, q);
}
template<class Gt, class Tds>
inline Comparison_result Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
inline Comparison_result Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
inline Comparison_result Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
inline Comparison_result Periodic_2_triangulation_2<Gt, Tds>::compare_y(
const Point& p, const Point& q) const
{
return geom_traits().compare_y_2_object()(p, q);
}
template<class Gt, class Tds>
inline Comparison_result Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
inline
bool Periodic_2_triangulation_2<Gt, Tds>::xy_equal(const Point& p,
const Point& q) const
{
return compare_xy(p, q) == EQUAL;
}
template<class Gt, class Tds>
inline Orientation Periodic_2_triangulation_2<Gt, Tds>::orientation(
const Point& p0, const Point& p1, const Point& p2) const
{
return geom_traits().orientation_2_object()(p0, p1, p2);
}
template<class Gt, class Tds>
inline Orientation Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::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<class Gt, class Tds>
void Periodic_2_triangulation_2<Gt, Tds>::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<Vertex_handle>::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<Vertex_handle>::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<class Gt, class Tds>
bool Periodic_2_triangulation_2<Gt, Tds>::edge_is_too_long(const Point &p1,
const Point &p2) const
{
return squared_distance(p1, p2) > _edge_length_threshold;
}
template<class GT, class Tds>
inline bool Periodic_2_triangulation_2<GT, Tds>::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<Vertex_handle> 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<class Gt, class Tds>
std::ostream&
Periodic_2_triangulation_2<Gt, Tds>::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<Vertex_handle, std::size_t > 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<Vertex_handle> 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<Face_handle, std::size_t> 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 ; i<number_of_faces() ; i++) {
for (Face_iterator it = faces_begin(); it != faces_end(); ++it)
{
//Face_handle ch = std::find(faces_begin(), faces_end(), i);
Face_handle ch(it);
for (int j = 0; j < 3; j++)
{
if(is_ascii(os))
{
os << ch->offset(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<class Gt, class Tds>
std::istream&
Periodic_2_triangulation_2<Gt, Tds>::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<Vertex_handle> 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<Face_handle> 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<Vertex_handle>();
++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 <class GT, class Tds1, class Tds2>
bool
test_next(const Periodic_2_triangulation_2<GT, Tds1> &t1,
const Periodic_2_triangulation_2<GT, Tds2> &t2,
typename Periodic_2_triangulation_2<GT, Tds1>::Face_handle c1,
typename Periodic_2_triangulation_2<GT, Tds2>::Face_handle c2,
std::map < typename Periodic_2_triangulation_2<GT, Tds1>::Face_handle,
typename Periodic_2_triangulation_2<GT, Tds2>::Face_handle > &Cmap,
std::map < typename Periodic_2_triangulation_2<GT, Tds1>::Vertex_handle,
typename Periodic_2_triangulation_2<GT, Tds2>::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_2_triangulation_2<GT, Tds1> Tr1;
typedef Periodic_2_triangulation_2<GT, Tds2> 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<Face_handle1, Face_handle2>::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<class Gt, class Tds>
std::istream&
operator>>(std::istream& is, Periodic_2_triangulation_2<Gt, Tds> &tr)
{
return tr.load(is);
}
template<class Gt, class Tds>
std::ostream&
operator<<(std::ostream& os, Periodic_2_triangulation_2<Gt, Tds> &tr)
{
return tr.save(os);
}
template < class GT, class Tds1, class Tds2 >
bool
operator==(const Periodic_2_triangulation_2<GT, Tds1> &t1,
const Periodic_2_triangulation_2<GT, Tds2> &t2)
{
typedef typename Periodic_2_triangulation_2<GT, Tds1>::Vertex_handle
Vertex_handle1;
typedef typename Periodic_2_triangulation_2<GT, Tds1>::Face_handle
Face_handle1;
typedef typename Periodic_2_triangulation_2<GT, Tds2>::Vertex_handle
Vertex_handle2;
typedef typename Periodic_2_triangulation_2<GT, Tds2>::Vertex_handle
Vertex_iterator2;
typedef typename Periodic_2_triangulation_2<GT, Tds2>::Face_handle
Face_handle2;
typedef typename Periodic_2_triangulation_2<GT, Tds2>::Face_circulator
Face_circulator2;
typedef typename Periodic_2_triangulation_2<GT, Tds1>::Point Point;
typedef typename Periodic_2_triangulation_2<GT, Tds1>::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<Vertex_handle1, Vertex_handle2> Vmap;
std::map<Face_handle1, Face_handle2> Cmap;
// find a common point
Vertex_handle1 v1 = static_cast<Vertex_handle1>(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<Vertex_handle2>(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_2_triangulation_2<GT, Tds1> &t1,
const Periodic_2_triangulation_2<GT, Tds2> &t2)
{
return ! (t1 == t2);
}
#define CGAL_INCLUDE_FROM_PERIODIC_2_TRIANGULATION_2_H
#include <CGAL/Periodic_2_triangulation_dummy_12.h>
#undef CGAL_INCLUDE_FROM_PERIODIC_2_TRIANGULATION_2_H
} //namespace CGAL
#endif //CGAL_PERIODIC_2_TRIANGULATION_2_H