Skip to content

Commit

Permalink
Merge pull request #7586 from MaelRL/P23T23-Unique_iterators-GF
Browse files Browse the repository at this point in the history
Add unique simplex iterators for periodic triangulations
  • Loading branch information
lrineau committed Jul 17, 2023
2 parents ec1ab10 + f41e69a commit 074d631
Show file tree
Hide file tree
Showing 11 changed files with 949 additions and 546 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class Periodic_2_Delaunay_triangulation_2 : public Periodic_2_triangulation_2<Tr

/// \name
/// A point-offset pair (`p`,`off`) is said to be in conflict with a
/// cell `c` iff `dt`.`side_of_circle(c, p, off)` returns
/// face `f` iff `dt`.`side_of_circle(f, p, off)` returns
/// `ON_BOUNDED_SIDE`. The set of faces that are in conflict with
/// (`p`,`off`) is star-shaped.
/// @{
Expand Down Expand Up @@ -309,7 +309,7 @@ class Periodic_2_Delaunay_triangulation_2 : public Periodic_2_triangulation_2<Tr
Checks the combinatorial validity of the triangulation and the
validity of its geometric embedding (see
Section \ref P2Triangulation2secintro). Also checks that all the
circumscribing circles of cells are empty.
circumscribing circles of faces are empty.
When `verbose` is set to true, messages describing the first
invalidity encountered are printed.
Expand All @@ -321,9 +321,9 @@ class Periodic_2_Delaunay_triangulation_2 : public Periodic_2_triangulation_2<Tr
/*!
\cgalAdvancedFunction
\cgalAdvancedBegin
Checks the combinatorial and geometric validity of the cell (see
Checks the combinatorial and geometric validity of the face (see
Section \ref P2Triangulation2secintro). Also checks that the
circumscribing circle of cells is empty.
circumscribing circle of faces is empty.
When `verbose` is set to true, messages are printed to give
a precise indication of the kind of invalidity encountered.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ concepts `Periodic_2TriangulationFaceBase_2` and
A triangulation is stored as a collection of vertices and faces that
are linked together through incidence and adjacency relations. Each
face gives access to its three incident vertices and to its three
adjacent cells. Each vertex gives access to one of its incident
adjacent faces. Each vertex gives access to one of its incident
faces.

The three vertices of a cell are indexed with 0, 1, and 2 in positive
The three vertices of a face are indexed with 0, 1, and 2 in positive
orientation, the positive orientation being defined by the orientation
of the underlying space \f$ \mathbb T_c^3\f$. The neighbors of a face are
also indexed with 0, 1, 2 in such a way that the neighbor indexed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ A periodic triangulation is said to be `locally valid` iff
data structure, is `locally valid`
(see Chapter \ref Chapter_2D_Triangulation_Data_Structure)

<B>(c)</B> Any cell has its vertices ordered according to positive
<B>(c)</B> Any face has its vertices ordered according to positive
orientation. See \cgalFigureRef{P2Triangulation2figorient}.

\section P2T2_Delaunay Delaunay Triangulation
Expand Down Expand Up @@ -264,15 +264,15 @@ to support periodicity: the vertex and face must be models of
`Periodic_2TriangulationVertexBase_2` and `Periodic_2TriangulationFaceBase_2`.
A model of such concept is `CGAL::Triangulation_data_structure_2`. It is
parameterized by a vertex base class and a face base class, which gives the
possibility to customize the vertices and cells used by the triangulation data
possibility to customize the vertices and faces used by the triangulation data
structure, and hence by the geometric triangulation using it.
Basic models of the vertex and face concepts are provided: `CGAL::Periodic_2_triangulation_vertex_base_2`
and `CGAL::Periodic_2_triangulation_face_base_2`.

A default value for the triangulation data structure parameter is provided in
all the triangulation classes, so it does not need to be specified by
the user unless he wants to use a different triangulation data
structure or a different vertex or cell base class.
structure or a different vertex or face base class.

\subsection P2T2FlexDesign Flexibility of the Design

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,21 @@ int main()
// Gets the conflict region of 100 random points
// in the Delaunay tetrahedralization
for (int i = 0; i != 100; ++i)
{
Point p = (*rnd++);

// Locate the point
Delaunay::Locate_type lt;
int li;
Face_handle f = T.locate(p, lt, li);
if (lt == Delaunay::VERTEX)
continue; // Point already exists

// Get the cells that conflict with p in a vector V,
// and a facet on the boundary of this hole in f.
std::vector<Face_handle> V;

T.get_conflicts(p,
std::back_inserter(V), // Conflict cells in V
f);
}
{
Point p = (*rnd++);

// Locate the point
Delaunay::Locate_type lt;
int li;
Face_handle f = T.locate(p, lt, li);
if (lt == Delaunay::VERTEX)
continue; // Point already exists

// Get the faces that conflict with p in a vector V.
std::vector<Face_handle> V;

T.get_conflicts(p, std::back_inserter(V), f);
}

std::cout << "Final triangulation has " << T.number_of_vertices()
<< " vertices." << std::endl;
Expand Down
157 changes: 140 additions & 17 deletions Periodic_2_triangulation_2/include/CGAL/Periodic_2_triangulation_2.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,21 @@ class Periodic_2_triangulation_2
/// Unique_vertex_iterator iterates over exactly one representative.
typedef Periodic_2_triangulation_unique_vertex_iterator_2<Self>
Unique_vertex_iterator;
/// Iterator over the canonical edges, i.e. for each set of periodic copies the
/// Unique_edge_iterator iterates over exactly one representative.
typedef Periodic_2_triangulation_unique_edge_iterator_2<Self>
Unique_edge_iterator;
/// Iterator over the canonical faces, i.e. for each set of periodic copies the
/// Unique_face_iterator iterates over exactly one representative.
typedef Periodic_2_triangulation_unique_face_iterator_2<Self>
Unique_face_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 Vertex_iterator All_vertices_iterator;
typedef Face_iterator All_faces_iterator;
// \}

Expand Down Expand Up @@ -381,10 +390,11 @@ class Periodic_2_triangulation_2
/// 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.
/// Converts 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.

/// Converts a single sheeted cover (used for dense triangulations) to a 9 sheeted cover.
/// \pre is_1_cover();
void convert_to_9_sheeted_covering();
// \}
Expand Down Expand Up @@ -676,6 +686,32 @@ class Periodic_2_triangulation_2
Periodic_2_triangulation_2_internal::Domain_tester<Self>(this));
}

Unique_edge_iterator unique_edges_begin() const
{
return CGAL::filter_iterator(edges_end(),
Periodic_2_triangulation_2_internal::Domain_tester<Self>(this),
edges_begin());
}
/// past-the-end iterator over the canonical edges
Unique_edge_iterator unique_edges_end() const
{
return CGAL::filter_iterator(edges_end(),
Periodic_2_triangulation_2_internal::Domain_tester<Self>(this));
}

Unique_face_iterator unique_faces_begin() const
{
return CGAL::filter_iterator(faces_end(),
Periodic_2_triangulation_2_internal::Domain_tester<Self>(this),
faces_begin());
}
/// past-the-end iterator over the non-virtual vertices
Unique_face_iterator unique_faces_end() const
{
return CGAL::filter_iterator(faces_end(),
Periodic_2_triangulation_2_internal::Domain_tester<Self>(this));
}

// \}
/// \name Geometric iterators
//\{
Expand Down Expand Up @@ -972,6 +1008,32 @@ class Periodic_2_triangulation_2
return Offset();
}

// Gets the canonicalized offsets of a face.
void get_offsets(Face_handle fh,
Offset& off0, Offset& off1, Offset& off2) const
{
Offset face_off0 = int_to_off(fh->offset(0));
Offset face_off1 = int_to_off(fh->offset(1));
Offset face_off2 = int_to_off(fh->offset(2));
Offset diff_off((face_off0.x() == 1 && face_off1.x() == 1 && face_off2.x() == 1) ? -1 : 0,
(face_off0.y() == 1 && face_off1.y() == 1 && face_off2.y() == 1) ? -1 : 0);
off0 = combine_offsets(get_offset(fh, 0), diff_off);
off1 = combine_offsets(get_offset(fh, 1), diff_off);
off2 = combine_offsets(get_offset(fh, 2), diff_off);
}

// Gets the canonicalized offsets of an edge.
void get_offsets(const Edge& e,
Offset& off0, Offset& off1) const
{
Offset edge_off0 = int_to_off(e.first->offset(cw(e.second)));
Offset edge_off1 = int_to_off(e.first->offset(ccw(e.second)));
Offset diff_off((edge_off0.x() == 1 && edge_off1.x() == 1) ? -1 : 0,
(edge_off0.y() == 1 && edge_off1.y() == 1) ? -1 : 0);
off0 = combine_offsets(get_offset(e.first, cw(e.second)), diff_off);
off1 = combine_offsets(get_offset(e.first, ccw(e.second)), diff_off);
}

/// Converts an offset to a bit pattern where bit1==offx and bit0==offy.
int off_to_int(const Offset & off) const
{
Expand All @@ -986,13 +1048,12 @@ class Periodic_2_triangulation_2
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
/// Tests whether a vertex is a periodic copy of a vertex in the 3-cover.
bool is_virtual(Vertex_handle v) const
{
return _virtual_vertices_reverse;
if (is_1_cover())
return false;
return (_virtual_vertices.find(v) != _virtual_vertices.end());
}

/// [Undoc] Returns the non-virtual copy of the vertex.
Expand All @@ -1007,15 +1068,6 @@ class Periodic_2_triangulation_2
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_precondition(number_of_sheets() != make_array(1, 1) );
Expand All @@ -1024,6 +1076,77 @@ class Periodic_2_triangulation_2
return _virtual_vertices_reverse.find(v)->second;
}

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

// check whether pos points onto a unique edge or not.
// If we are computing in 1-sheeted covering this should
// always be true.
bool is_canonical(Face_handle fh) const
{
if(is_1_cover())
return true;

Offset off0, off1, off2;
get_offsets(fh, off0, off1, off2);

// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical triangle.
if (off0.x() > 1) return false;
if (off0.y() > 1) return false;
if (off1.x() > 1) return false;
if (off1.y() > 1) return false;
if (off2.x() > 1) return false;
if (off2.y() > 1) return false;

// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x() & off2.x();
int offy = off0.y() & off1.y() & off2.y();

return (offx == 0 && offy == 0);
}

bool is_canonical(const Edge& e) const
{
if(is_1_cover())
return true;

// fetch all offsets
Offset off0, off1;
get_offsets(e, off0, off1);

// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical edge.
if (off0.x() > 1) return false;
if (off0.y() > 1) return false;
if (off1.x() > 1) return false;
if (off1.y() > 1) return false;

// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x();
int offy = off0.y() & off1.y();

return (offx == 0 && offy == 0);
}

// checks whether pos points onto a vertex inside the original domain
bool is_canonical(Vertex_handle vh) const
{
return !is_virtual(vh);
}

public:
template<class Stream>
Stream& draw_triangulation(Stream& os) const
{
Expand Down
Loading

0 comments on commit 074d631

Please sign in to comment.