// 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
