Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unique simplex iterators for periodic triangulations #7586

Merged
merged 2 commits into from
Jul 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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