Merge pull request #7535 from lrineau/Triangulation_3-fix_simplex_traverser-GF-CGAL-5.6

fix simplex traverser for CGAL 5.6
This commit is contained in:
Laurent Rineau 2023-07-05 16:32:36 +02:00
commit 04077e9f4f
8 changed files with 1116 additions and 715 deletions

View File

@ -78,6 +78,13 @@ namespace CGAL {
{ {
return std::tuple<const I&, const I&>{this->first, this->second}; return std::tuple<const I&, const I&>{this->first, this->second};
} }
template <template<class...> class Container>
auto to() const
{
using V = std::remove_cv_t<std::remove_reference_t<decltype(*begin())>>;
return Container<V>(begin(), end());
}
}; };
template <typename T> template <typename T>

View File

@ -96,8 +96,10 @@ public:
// returns the dimension of the simplex // returns the dimension of the simplex
int dimension () const { int dimension () const {
return (ref & 3); if(ref == -1) return -1;
else return (ref & 3);
} }
// returns an incident cell: // returns an incident cell:
Cell_handle incident_cell() { Cell_handle incident_cell() {
return ch; return ch;
@ -161,6 +163,7 @@ operator==(Triangulation_simplex_3<TriangulationDataStructure_3> s0,
typename Sim::Cell_handle neighbor; typename Sim::Cell_handle neighbor;
switch (s0.dimension()) { switch (s0.dimension()) {
case -1: return s1.dimension() == -1;
case (0): // Vertex case (0): // Vertex
return (s0.ch->vertex(s0.index(0)) == s1.ch->vertex(s1.index(0))); return (s0.ch->vertex(s0.index(0)) == s1.ch->vertex(s1.index(0)));
case (1): // Edge case (1): // Edge
@ -180,7 +183,7 @@ operator==(Triangulation_simplex_3<TriangulationDataStructure_3> s0,
} }
return false; return false;
case (3): case (3):
return (&(*s0.ch) == &(*s1.ch)); return s0.ch.operator->() == s1.ch.operator->();
} }
CGAL_error(); CGAL_error();
return false; return false;

View File

@ -36,7 +36,7 @@ Triangulation_segment_cell_iterator_3( const Tr* tr, Vertex_handle s, Vertex_han
if( c->has_vertex( _tr->infinite_vertex(), inf ) ) if( c->has_vertex( _tr->infinite_vertex(), inf ) )
c = c->neighbor(inf); c = c->neighbor(inf);
_cur = Simplex( c, Tr::VERTEX, c->index(s), -1 ); _cur = Simplex{ c, Tr::VERTEX, c->index(s), -1 };
jump_to_intersecting_cell(); jump_to_intersecting_cell();
} }
@ -62,7 +62,7 @@ Triangulation_segment_cell_iterator_3( const Tr* tr, Vertex_handle s, const Poin
if( c->has_vertex( _tr->infinite_vertex(), inf ) ) if( c->has_vertex( _tr->infinite_vertex(), inf ) )
c = c->neighbor(inf); c = c->neighbor(inf);
_cur = Simplex( c, Tr::VERTEX, c->index(s), -1 ); _cur = Simplex{ c, Tr::VERTEX, c->index(s), -1 };
jump_to_intersecting_cell(); jump_to_intersecting_cell();
} }
@ -124,7 +124,7 @@ template < class Tr, class Inc >
Triangulation_segment_cell_iterator_3<Tr,Inc> Triangulation_segment_cell_iterator_3<Tr,Inc>
Triangulation_segment_cell_iterator_3<Tr,Inc>::end() const { Triangulation_segment_cell_iterator_3<Tr,Inc>::end() const {
SCI sci(_tr); SCI sci(_tr);
std::get<0>(sci._cur) = Cell_handle(); sci._cur.cell = Cell_handle();
return sci; return sci;
} }
@ -239,8 +239,9 @@ walk_to_next() {
int ti; int ti;
if( cell()->has_vertex( _t_vertex, ti ) ) { if( cell()->has_vertex( _t_vertex, ti ) ) {
// The target is inside the cell. // The target is inside the cell.
_prev = Simplex( cell(), Tr::VERTEX, ti, -1 ); _prev = Simplex{ cell(), Tr::VERTEX, ti, -1 };
cell() = Cell_handle(); cell() = Cell_handle();
lt() = Locate_type::VERTEX;
return; return;
} }
@ -302,24 +303,24 @@ bool Triangulation_segment_cell_iterator_3<Tr, Inc>::
have_same_entry(const Simplex& s1, const Simplex& s2) const have_same_entry(const Simplex& s1, const Simplex& s2) const
{ {
//type //type
if (std::get<1>(s1) != std::get<1>(s2)) if (s1.lt != s2.lt)
return false; return false;
switch (std::get<1>(s1)) switch (s1.lt)
{ {
case Locate_type::VERTEX: case Locate_type::VERTEX:
return std::get<0>(s1)->vertex(std::get<2>(s1)) == std::get<0>(s2)->vertex(std::get<2>(s2)); return s1.cell->vertex(s1.li) == s2.cell->vertex(s2.li);
case Locate_type::EDGE: case Locate_type::EDGE:
{ {
Vertex_handle v1a = std::get<0>(s1)->vertex(std::get<2>(s1)); Vertex_handle v1a = s1.cell->vertex(s1.li);
Vertex_handle v1b = std::get<0>(s1)->vertex(std::get<3>(s1)); Vertex_handle v1b = s1.cell->vertex(s1.lj);
Vertex_handle v2a = std::get<0>(s2)->vertex(std::get<2>(s2)); Vertex_handle v2a = s2.cell->vertex(s2.li);
Vertex_handle v2b = std::get<0>(s2)->vertex(std::get<3>(s2)); Vertex_handle v2b = s2.cell->vertex(s2.lj);
return (v1a == v2a && v1b == v2b) return (v1a == v2a && v1b == v2b)
|| (v1a == v2b && v1b == v2a); || (v1a == v2b && v1b == v2a);
} }
case Locate_type::FACET: case Locate_type::FACET:
return triangulation()->are_equal(Facet(std::get<0>(s1), std::get<2>(s1)), return triangulation()->are_equal(Facet(s1.cell, s1.li),
Facet(std::get<0>(s2), std::get<2>(s2))); Facet(s2.cell, s2.li));
default: default:
CGAL_assertion(false); CGAL_assertion(false);
}; };
@ -332,305 +333,296 @@ std::pair<typename Triangulation_segment_cell_iterator_3<Tr, Inc>::Simplex,
Triangulation_segment_cell_iterator_3<Tr,Inc>::walk_to_next_3(const Simplex& prev, Triangulation_segment_cell_iterator_3<Tr,Inc>::walk_to_next_3(const Simplex& prev,
const Simplex& cur) const const Simplex& cur) const
{ {
std::array<const Point*, 4> vert const auto cur_cell = cur.cell;
= {&(std::get<0>(cur)->vertex(0)->point()), std::array<const Point*, 4> vert = {&(cur_cell->vertex(0)->point()), &(cur_cell->vertex(1)->point()),
&(std::get<0>(cur)->vertex(1)->point()), &(cur_cell->vertex(2)->point()), &(cur_cell->vertex(3)->point())};
&(std::get<0>(cur)->vertex(2)->point()),
&(std::get<0>(cur)->vertex(3)->point()) };
int inside=0,outside=0,regular_case=0,degenerate=0; int inside = 0, outside = 0, regular_case = 0, degenerate = 0;
Cell_handle nnext;
if (std::get<1>(cur) == Tr::FACET) { if(cur.lt == Tr::FACET && prev.cell != Cell_handle()) {
// [source, target] entered the cell `cur` via a facet.
// Note that, if prev.cell == Cell_handle(), that means `source` is *on*
// the facet, and the block of this `if` cannot be applied.
Simplex prev_after_walk;
Simplex cur_after_walk;
auto case_target_is_inside_cur_cell = [&](int case_nb) {
inside = case_nb;
prev_after_walk = {cur_cell, Tr::CELL, -1, -1};
cur_after_walk = {{}, Tr::CELL, -1, -1};
};
auto case_segment_exits_cur_cell_by = [&](int facet_nb, Cell_handle nnext = {}) {
if(nnext == Cell_handle{}) {
nnext = cur_cell->neighbor(facet_nb);
}
outside = facet_nb;
prev_after_walk = {cur_cell, Tr::FACET, facet_nb, -1};
cur_after_walk = {nnext, Tr::FACET, nnext->index(cur_cell), -1};
};
regular_case = 1; regular_case = 1;
int i = std::get<2>(cur); const int i = cur.li;
int j0 = Tr::vertex_triple_index(i, 0); const int j0 = Tr::vertex_triple_index(i, 0);
int j1 = Tr::vertex_triple_index(i, 1); const int j1 = Tr::vertex_triple_index(i, 1);
int j2 = Tr::vertex_triple_index(i, 2); const int j2 = Tr::vertex_triple_index(i, 2);
Orientation o0 = _tr->orientation(_source, *vert[i], *vert[j0], _target); Orientation o0 = _tr->orientation(_source, *vert[i], *vert[j0], _target);
if (o0 == POSITIVE) { if(o0 == POSITIVE) { // o0 > 0
Orientation o1 = _tr->orientation(_source, *vert[i], *vert[j1], _target); Orientation o1 = _tr->orientation(_source, *vert[i], *vert[j1], _target);
if (o1 != POSITIVE) { if(o1 != POSITIVE) { // o1 <= 0
if (_tr->orientation(*vert[i], *vert[j0], *vert[j1], _target) == POSITIVE) { Orientation oi01 = _tr->orientation(*vert[i], *vert[j0], *vert[j1], _target);
nnext = std::get<0>(cur)->neighbor(j2); if(oi01 == POSITIVE) {
outside = j2; case_segment_exits_cur_cell_by(j2);
if (o1 == ZERO) degenerate = 1; //EDGE i j1 if(o1 == ZERO)
degenerate = 1; // EDGE i j1
} else { // o0 > 0, o1 <= 0, oi01 <= 0
case_target_is_inside_cur_cell(1);
if(oi01 == ZERO) { // on FACET j2 (i, j0, j1)
degenerate = 1;
} // end oi01 == ZERO
} }
} // end o1 <= 0
else else
inside = 1; { // o1 > 0
} Orientation oi12 = _tr->orientation(*vert[i], *vert[j1], *vert[j2], _target);
else { if(oi12 == POSITIVE) {
if (_tr->orientation(*vert[i], *vert[j1], *vert[j2], _target) == POSITIVE) { case_segment_exits_cur_cell_by(j0);
nnext = std::get<0>(cur)->neighbor(j0); } else { // o0 > 0, o1 > 0, oi12 <= 0
outside = j0; case_target_is_inside_cur_cell(2);
} if(oi12 == ZERO) { // on FACET j0 (i, j1, j2)
else degenerate = 1;
inside = 2; } // end oi12 == ZERO
} }
} }
else if (o0 == ZERO) { } // end o0 > 0
else if(o0 == ZERO)
{
// target is on plane (source, vert[i], vert[j0])
Orientation o1 = _tr->orientation(_source, *vert[i], *vert[j1], _target); Orientation o1 = _tr->orientation(_source, *vert[i], *vert[j1], _target);
if (o1 == NEGATIVE) { if(o1 == NEGATIVE) {
if (_tr->orientation(*vert[i], *vert[j0], *vert[j1], _target) == POSITIVE) { Orientation oi12 = _tr->orientation(*vert[i], *vert[j0], *vert[j1], _target);
nnext = std::get<0>(cur)->neighbor(j2); //EDGE i j0 if(oi12 == POSITIVE) {
degenerate = 2; degenerate = 2;
outside = 44; case_segment_exits_cur_cell_by(44, cur_cell->neighbor(j2)); // EDGE i j0
} else {
case_target_is_inside_cur_cell(3);
if(oi12 == ZERO) { // target is *on* EDGE i j0
degenerate = 1;
} }
else
inside = 3;
} }
else if (o1 == ZERO) { } else if(o1 == ZERO) {
if (_tr->orientation(*vert[i], *vert[j0], *vert[j2], _target) == POSITIVE) // o0 == o1 == 0 -> target is on line source-vert[i]
inside = 55; if(_tr->orientation(*vert[i], *vert[j0], *vert[j2], _target) == POSITIVE)
else case_target_is_inside_cur_cell(55);
{ else {
nnext = std::get<0>(cur)->neighbor(j2); //VERTEX i
degenerate = 3; degenerate = 3;
outside = 5; case_segment_exits_cur_cell_by(5, cur_cell->neighbor(j2)); // VERTEX i
}
} else { // o0 == 0, o1 > 0
Orientation oi12 = _tr->orientation(*vert[i], *vert[j1], *vert[j2], _target);
if(oi12 == POSITIVE) {
case_segment_exits_cur_cell_by(j0);
} else {
case_target_is_inside_cur_cell(4);
if(oi12 == ZERO) { // on FACET j0 (i, j1, j2)
degenerate = 1;
} // end oi12 == ZERO
} }
} }
else { } // end o0 == 0
if (_tr->orientation(*vert[i], *vert[j1], *vert[j2], _target) == POSITIVE) {
nnext = std::get<0>(cur)->neighbor(j0);
outside = j0;
}
else else
inside = 4; { // o0 < 0
}
}
else {
Orientation o2 = _tr->orientation(_source, *vert[i], *vert[j2], _target); Orientation o2 = _tr->orientation(_source, *vert[i], *vert[j2], _target);
if (o2 != NEGATIVE) { if(o2 != NEGATIVE) {
if (_tr->orientation(*vert[i], *vert[j2], *vert[j0], _target) == POSITIVE) { // o2 >= 0
nnext = std::get<0>(cur)->neighbor(j1); Orientation oi20 = _tr->orientation(*vert[i], *vert[j2], *vert[j0], _target);
outside = j1; if(oi20 == POSITIVE) {
if (o2 == ZERO) degenerate = 4; // EDGE i j2 case_segment_exits_cur_cell_by(j1);
if(o2 == ZERO)
degenerate = 4; // EDGE i j2
} else {
case_target_is_inside_cur_cell(5);
if(oi20 == ZERO) { // on FACET j1 (i, j2, j0)
degenerate = 1;
} }
else
inside = 5;
} }
else { } else {
if (_tr->orientation(*vert[i], *vert[j1], *vert[j2], _target) == POSITIVE) { Orientation oi12 = _tr->orientation(*vert[i], *vert[j1], *vert[j2], _target);
nnext = std::get<0>(cur)->neighbor(j0); if(oi12 == POSITIVE) {
outside = j0; case_segment_exits_cur_cell_by(j0);
} else {
case_target_is_inside_cur_cell(6);
if(oi12 == ZERO) { // on FACET j0 (i, j1, j2)
degenerate = 1;
}
} }
else
inside = 6;
} }
} }
if ((!degenerate) && (!inside)) if(!degenerate) {
{ return {prev_after_walk, cur_after_walk};
Simplex prev_after_walk(std::get<0>(cur), Tr::FACET, outside, -1);
Simplex cur_after_walk( nnext, Tr::FACET, nnext->index(std::get<0>(cur)), -1);
return std::make_pair(prev_after_walk, cur_after_walk);
}
if ((!degenerate) && inside)
{
Simplex prev_after_walk(std::get<0>(cur), Tr::CELL, -1, -1);
Simplex cur_after_walk(Cell_handle(), Tr::OUTSIDE_AFFINE_HULL, -1, -1);
return std::make_pair(prev_after_walk, cur_after_walk);
} }
} }
// We check in which direction the target lies // We check in which direction the target lies
// by comparing its position relative to the planes through the // by comparing its position relative to the planes through the
// source and the edges of the cell. // source and the edges of the cell.
Orientation o[6]; std::array<Orientation, 6> o;
Orientation op[4]; std::array<Orientation, 4> op;
int pos = 0; int pos = 0;
// We keep track of which orientations are calculated. // We keep track of which orientations are calculated.
bool calc[6] = { false, false, false, false, false, false }; bool calc[6] = {false, false, false, false, false, false};
if( std::get<1>(cur) == Tr::VERTEX ) { if(cur.lt == Tr::VERTEX) {
// The three planes through the vertex are set to coplanar. // The three planes through the vertex are set to coplanar.
for( int j = 0; j < 4; ++j ) { for(int j = 0; j < 4; ++j) {
if( std::get<2>(cur) != j ) { if(cur.li != j) {
int ij = edgeIndex( std::get<2>(cur), j ); int ij = edgeIndex(cur.li, j);
o[ij] = COPLANAR; o[ij] = COPLANAR;
calc[ij] = true; calc[ij] = true;
} }
} }
} } else if(cur.lt == Tr::EDGE) {
else if( std::get<1>(cur) == Tr::EDGE ) {
// The plane through the edge is set to coplanar. // The plane through the edge is set to coplanar.
int ij = edgeIndex( std::get<2>(cur), std::get<3>(cur) ); int ij = edgeIndex(cur.li, cur.lj);
o[ij] = COPLANAR; o[ij] = COPLANAR;
calc[ij] = true; calc[ij] = true;
} }
// For the remembering stochastic walk, we start trying with a random facet. // For the remembering stochastic walk, we start trying with a random facet.
int li = 0; CGAL_assertion_code(bool incell = true;)
CGAL_assertion_code( bool incell = true; )
for( int k = 0; k < 4; ++k, ++li ) for(int li = 0; li < 4; ++li)
{ {
// Skip the previous cell. // Skip the previous cell.
Cell_handle next = std::get<0>(cur)->neighbor(li); Cell_handle next = cur_cell->neighbor(li);
if( next == std::get<0>(prev) ) if(next == prev.cell) {
{
op[li] = POSITIVE; op[li] = POSITIVE;
pos += li; pos += li;
continue; continue;
} }
const Point* backup = vert[li]; const Point* const backup_vert_li = std::exchange(vert[li], &_target);
vert[li] = &_target;
// Check if the target is on the opposite side of the supporting plane. // Check if the target is on the opposite side of the supporting plane.
op[li] = _tr->orientation( *vert[0], *vert[1], *vert[2], *vert[3] ); op[li] = _tr->orientation(*vert[0], *vert[1], *vert[2], *vert[3]);
if( op[li] == POSITIVE ) if(op[li] == POSITIVE)
pos += li; pos += li;
if( op[li] != NEGATIVE ) { if(op[li] != NEGATIVE) {
vert[li] = backup; vert[li] = backup_vert_li;
continue; continue;
} }
CGAL_assertion_code( incell = false; ) CGAL_assertion_code(incell = false;)
// Check if the target is inside the 3-wedge with // Check if the target is inside the 3-wedge with
// the source as apex and the facet as an intersection. // the source as apex and the facet as an intersection.
int lj = 0;
int Or = 0; int Or = 0;
for( int l = 0; l < 4; ++l, ++lj ) { for(int lj = 0; lj < 4; ++lj) {
if( li == lj ) if(li == lj)
continue; continue;
// We check the orientation of the target compared to the plane // We check the orientation of the target compared to the plane
// Through the source and the edge opposite of ij. // Through the source and the edge opposite of ij.
int oij = 5 - edgeIndex( li, lj ); const int oij = 5 - edgeIndex(li, lj);
if( !calc[oij] ) { if(!calc[oij]) {
const Point* backup2 = vert[lj]; const Point* const backup_vert_lj = std::exchange(vert[lj], &_source);
vert[lj] = &_source; o[oij] = _tr->orientation(*vert[0], *vert[1], *vert[2], *vert[3]);
o[oij] = _tr->orientation( *vert[0], *vert[1], *vert[2], *vert[3] ); vert[lj] = backup_vert_lj;
vert[lj] = backup2;
calc[oij] = true; calc[oij] = true;
} }
if(o[oij] == POSITIVE) {
if( o[oij] == POSITIVE ) {
// The target is not inside the pyramid. // The target is not inside the pyramid.
// Invert the planes. // Invert the planes.
// This can be safely done because either for(int j = 0; j < 4; ++j) {
// they were not calculated yet, if(li == j)
// or they will no longer be used. continue;
for( int j = 0; j < 4; ++j ) { int oij = 5 - edgeIndex(li, j);
if( li == j ) continue; if(calc[oij])
int oij = 5 - edgeIndex( li, j );
o[oij] = -o[oij]; o[oij] = -o[oij];
} }
Or = 0; Or = 0;
break; break;
} } else
else
Or -= o[oij]; Or -= o[oij];
} }
if( Or == 0 ) { if(Or == 0) {
// Either the target is not inside the pyramid, // Either the target is not inside the pyramid,
// or the pyramid is degenerate. // or the pyramid is degenerate.
vert[li] = backup; vert[li] = backup_vert_li;
continue; continue;
} }
// The target is inside the pyramid. // The target is inside the pyramid.
switch(Or) {
Simplex prev_after_walk; case 3: {
Simplex cur_after_walk; if(regular_case) {
CGAL_assertion(li == outside);
std::get<0>(prev_after_walk) = std::get<0>(cur); CGAL_assertion(!inside);
std::get<0>(cur_after_walk) = next; }
switch( Or ) { return {{cur_cell, Tr::FACET, li}, {next, Tr::FACET, next->index(cur_cell)}};
case 3: }
std::get<1>(prev_after_walk) = Tr::FACET; case 2: {
std::get<2>(prev_after_walk) = li;
std::get<1>(cur_after_walk) = Tr::FACET;
std::get<2>(cur_after_walk) = std::get<0>(cur_after_walk)->index(std::get<0>(prev_after_walk));
if(regular_case) if(regular_case)
{ CGAL_assertion(degenerate);
CGAL_assertion( std::get<0>(cur_after_walk)==nnext ); for(int j = 0; j < 4; ++j) {
CGAL_assertion( li==outside ); if(li != j && o[5 - edgeIndex(li, j)] == COPLANAR) {
CGAL_assertion( ! inside ); Edge opp = opposite_edge(prev.cell, li, j);
} return {
return std::make_pair(prev_after_walk, cur_after_walk); {cur_cell, Tr::EDGE, opp.second, opp.third},
{next, Tr::EDGE, next->index(cur_cell->vertex(opp.second)), next->index(cur_cell->vertex(opp.third))}};
case 2:
if(regular_case)
CGAL_assertion(degenerate );
std::get<1>(prev_after_walk) = Tr::EDGE;
std::get<1>(cur_after_walk) = Tr::EDGE;
for( int j = 0; j < 4; ++j ) {
if( li != j && o[ 5 - edgeIndex(li, j) ] == COPLANAR) {
Edge opp = opposite_edge( std::get<0>(prev), li, j );
std::get<2>(prev_after_walk) = opp.second;
std::get<3>(prev_after_walk) = opp.third;
std::get<2>(cur_after_walk)
= std::get<0>(cur_after_walk)->index(
std::get<0>(prev_after_walk)->vertex( std::get<2>(prev_after_walk) ) );
std::get<3>(cur_after_walk)
= std::get<0>(cur_after_walk)->index(
std::get<0>(prev_after_walk)->vertex( std::get<3>(prev_after_walk) ) );
return std::make_pair(prev_after_walk, cur_after_walk);
} }
} }
CGAL_assertion( false ); CGAL_unreachable();
return std::make_pair(prev, cur); return std::make_pair(prev, cur);
}
case 1: case 1:
if(regular_case) if(regular_case)
CGAL_assertion(degenerate ); CGAL_assertion(degenerate);
for(int j = 0; j < 4; ++j) {
std::get<1>(prev_after_walk) = Tr::VERTEX; if(li != j && o[5 - edgeIndex(li, j)] == NEGATIVE) {
std::get<1>(cur_after_walk) = Tr::VERTEX; return {{cur_cell, Tr::VERTEX, j}, {next, Tr::VERTEX, next->index(cur_cell->vertex(j))}};
for( int j = 0; j < 4; ++j ) {
if( li != j && o[ 5 - edgeIndex(li, j) ] == NEGATIVE ) {
std::get<2>(prev_after_walk) = j;
std::get<2>(cur_after_walk)
= std::get<0>(cur_after_walk)->index(
std::get<0>(prev_after_walk)->vertex(j) );
return std::make_pair(prev_after_walk, cur_after_walk);
} }
} }
CGAL_assertion( false ); CGAL_unreachable();
return std::make_pair(prev, cur); return std::make_pair(prev, cur);
default: default:
CGAL_assertion( false ); CGAL_unreachable();
return std::make_pair(prev, cur); return std::make_pair(prev, cur);
} }
CGAL_unreachable();
} }
// The target lies inside this cell. // The target lies inside this cell.
Simplex prev_after_walk;
CGAL_assertion( incell ); CGAL_assertion( incell );
return {
[&]() -> Simplex {
switch( op[0] + op[1] + op[2] + op[3] ) { switch( op[0] + op[1] + op[2] + op[3] ) {
case 4: case 4:
CGAL_assertion( pos == 6 ); CGAL_assertion( pos == 6 );
prev_after_walk = Simplex( std::get<0>(cur), Tr::CELL, -1, -1 );
CGAL_assertion( (! regular_case) || inside ); CGAL_assertion( (! regular_case) || inside );
return { cur_cell, Tr::CELL };
break; break;
case 3: case 3:
prev_after_walk = Simplex( std::get<0>(cur), Tr::FACET, 6-pos, -1 ); return { cur_cell, Tr::FACET, 6 - pos };
break; break;
case 2: case 2:
if( pos < 3 ) if( pos < 3 ) // first is 0
prev_after_walk = Simplex( std::get<0>(cur), Tr::EDGE, 0, pos+1 ); return { cur_cell, Tr::EDGE, 0, pos };
else if( pos < 5 ) else if( pos < 5 ) { // could be (0, pos), or (1, pos-1)
prev_after_walk = Simplex( std::get<0>(cur), Tr::EDGE, 1, pos-1 ); if(op[0] == POSITIVE)
return { cur_cell, Tr::EDGE, 0, pos };
else else
prev_after_walk = Simplex( std::get<0>(cur), Tr::EDGE, 2, 3 ); return { cur_cell, Tr::EDGE, 1, pos-1 };
}
else
return { cur_cell, Tr::EDGE, 2, 3 };
break; break;
case 1: case 1:
prev_after_walk = Simplex( std::get<0>(cur), Tr::VERTEX, pos, -1 ); return { cur_cell, Tr::VERTEX, pos };
break; break;
default: default:
prev_after_walk = Simplex( std::get<0>(cur), Tr::OUTSIDE_AFFINE_HULL, -1, -1 ); CGAL_unreachable();
CGAL_assertion( false );
} }
}(),
Simplex cur_after_walk(Cell_handle(), Tr::OUTSIDE_AFFINE_HULL, -1, -1); { Cell_handle() }
return std::make_pair(prev_after_walk, cur_after_walk); };
} }
template < class Tr, class Inc > template < class Tr, class Inc >
@ -643,7 +635,9 @@ walk_to_next_3_inf( int inf )
Cell_handle fin = cell()->neighbor(inf); Cell_handle fin = cell()->neighbor(inf);
if( fin == prev_cell() ) { if( fin == prev_cell() ) {
_prev = _cur; _prev = _cur;
prev_lt() = Tr::CELL;
cell() = Cell_handle(); cell() = Cell_handle();
lt() = Tr::CELL;
return; return;
} }
@ -658,7 +652,7 @@ walk_to_next_3_inf( int inf )
if( _tr->orientation( *vert[0], *vert[1], *vert[2], *vert[3] ) == POSITIVE ) { if( _tr->orientation( *vert[0], *vert[1], *vert[2], *vert[3] ) == POSITIVE ) {
// The target lies in an infinite cell. // The target lies in an infinite cell.
// Note that we do not traverse to other infinite cells. // Note that we do not traverse to other infinite cells.
_prev = Simplex( cell(), Tr::OUTSIDE_CONVEX_HULL, -1, -1 ); _prev = Simplex{ cell(), Tr::OUTSIDE_CONVEX_HULL, -1, -1 };
cell() = Cell_handle(); cell() = Cell_handle();
return; return;
} }
@ -683,20 +677,20 @@ walk_to_next_3_inf( int inf )
continue; continue;
} }
Point* backup = vert[li]; Point* backup_vert_li = vert[li];
vert[li] = &(_target); vert[li] = &(_target);
o[li] = _tr->orientation( *vert[0], *vert[1], *vert[2], *vert[3] ); o[li] = _tr->orientation( *vert[0], *vert[1], *vert[2], *vert[3] );
if( o[li] != NEGATIVE ) { if( o[li] != NEGATIVE ) {
vert[li] = backup; vert[li] = backup_vert_li;
continue; continue;
} }
// The target lies behind the plane through the source and two finite vertices. // The target lies behind the plane through the source and two finite vertices.
// Traverse to the incident infinite cell. // Traverse to the incident infinite cell.
CGAL_assertion( _tr->is_infinite( next ) ); CGAL_assertion( _tr->is_infinite( next ) );
_prev = Simplex( cell(), Tr::FACET, li, -1 ); _prev = Simplex{ cell(), Tr::FACET, li, -1 };
_cur = Simplex( next, Tr::FACET, next->index( prev_cell() ), -1 ); _cur = Simplex{ next, Tr::FACET, next->index(prev_cell()), -1 };
return; return;
} }
@ -725,7 +719,7 @@ walk_to_next_3_inf( int inf )
return; return;
} }
} }
CGAL_assertion( false ); CGAL_unreachable();
return; return;
case 1: case 1:
prev_lt() = Tr::VERTEX; prev_lt() = Tr::VERTEX;
@ -737,10 +731,10 @@ walk_to_next_3_inf( int inf )
return; return;
} }
} }
CGAL_assertion( false ); CGAL_unreachable();
return; return;
default: default:
CGAL_assertion( false ); CGAL_unreachable();
return; return;
} }
} }
@ -802,7 +796,7 @@ walk_to_next_2()
return; return;
default: default:
// The current vertex is the target. // The current vertex is the target.
CGAL_assertion(false); CGAL_unreachable();
return; return;
} }
} }
@ -810,27 +804,26 @@ walk_to_next_2()
// The target lies in this cell. // The target lies in this cell.
switch( ocw+occw+op ) { switch( ocw+occw+op ) {
case 3: case 3:
_prev = Simplex( cell(), Tr::FACET, 3, -1 ); _prev = Simplex{ cell(), Tr::FACET, 3, -1 };
break; break;
case 2: case 2:
if( ocw == 0 ) if( ocw == 0 )
_prev = Simplex( cell(), Tr::EDGE, _tr->ccw(li()), -1 ); _prev = Simplex{ cell(), Tr::EDGE, _tr->ccw(li()), -1 };
else if( occw == 0 ) else if( occw == 0 )
_prev = Simplex( cell(), Tr::EDGE, _tr->cw(li()), -1 ); _prev = Simplex{ cell(), Tr::EDGE, _tr->cw(li()), -1 };
else else
_prev = Simplex( cell(), Tr::EDGE, li(), -1 ); _prev = Simplex{ cell(), Tr::EDGE, li(), -1 };
break; break;
case 1: case 1:
if( ocw == 1 ) if( ocw == 1 )
_prev = Simplex( cell(), Tr::VERTEX, _tr->ccw(li()), -1 ); _prev = Simplex{ cell(), Tr::VERTEX, _tr->ccw(li()), -1 };
else if( occw == 1 ) else if( occw == 1 )
_prev = Simplex( cell(), Tr::VERTEX, _tr->cw(li()), -1 ); _prev = Simplex{ cell(), Tr::VERTEX, _tr->cw(li()), -1 };
else else
_prev = Simplex( cell(), Tr::VERTEX, li(), -1 ); _prev = Simplex{ cell(), Tr::VERTEX, li(), -1 };
break; break;
case 0: case 0:
CGAL_assertion(false); CGAL_unreachable();
_prev = Simplex( cell(), Tr::OUTSIDE_AFFINE_HULL, -1, -1 );
break; break;
} }
cell() = Cell_handle(); cell() = Cell_handle();
@ -927,18 +920,18 @@ walk_to_next_2()
// The target lies in this cell. // The target lies in this cell.
if( op == POSITIVE ) if( op == POSITIVE )
_prev = Simplex( cell(), Tr::FACET, 3, -1 ); _prev = Simplex{ cell(), Tr::FACET, 3, -1 };
else { else {
CGAL_assertion( op == ZERO ); CGAL_assertion( op == ZERO );
switch( o ) { switch( o ) {
case POSITIVE: case POSITIVE:
_prev = Simplex( cell(), Tr::EDGE, li(), lk ); _prev = Simplex{ cell(), Tr::EDGE, li(), lk };
break; break;
case NEGATIVE: case NEGATIVE:
_prev = Simplex( cell(), Tr::EDGE, lj(), lk ); _prev = Simplex{ cell(), Tr::EDGE, lj(), lk };
break; break;
case ZERO: case ZERO:
_prev = Simplex( cell(), Tr::VERTEX, lk, -1 ); _prev = Simplex{ cell(), Tr::VERTEX, lk, -1 };
break; break;
} }
} }
@ -969,7 +962,7 @@ walk_to_next_2()
if( o[_tr->ccw(li)] == NEGATIVE ) if( o[_tr->ccw(li)] == NEGATIVE )
continue; continue;
else if( op == COLLINEAR && o[_tr->ccw(li)] == COLLINEAR ) { else if( op == COLLINEAR && o[_tr->ccw(li)] == COLLINEAR ) {
_prev = Simplex( cell(), Tr::VERTEX, _tr->ccw(li), -1 ); _prev = Simplex{ cell(), Tr::VERTEX, _tr->ccw(li), -1 };
cell() = Cell_handle(); cell() = Cell_handle();
return; return;
} }
@ -981,7 +974,7 @@ walk_to_next_2()
if( o[_tr->cw(li)] == POSITIVE ) if( o[_tr->cw(li)] == POSITIVE )
continue; continue;
else if( op == COLLINEAR && o[_tr->cw(li)] == COLLINEAR ) { else if( op == COLLINEAR && o[_tr->cw(li)] == COLLINEAR ) {
_prev = Simplex( cell(), Tr::VERTEX, _tr->cw(li), -1 ); _prev = Simplex{ cell(), Tr::VERTEX, _tr->cw(li), -1 };
cell() = Cell_handle(); cell() = Cell_handle();
return; return;
} }
@ -1006,18 +999,18 @@ walk_to_next_2()
this->li() = cell()->index( prev_cell()->vertex( prev_li() ) ); this->li() = cell()->index( prev_cell()->vertex( prev_li() ) );
return; return;
default: default:
CGAL_assertion( false ); CGAL_unreachable();
return; return;
} }
} }
// The target lies in this cell. // The target lies in this cell.
_prev = Simplex( cell(), Tr::FACET, 3, -1 ); _prev = Simplex{ cell(), Tr::FACET, 3, -1 };
cell() = Cell_handle(); cell() = Cell_handle();
return; return;
} }
default: default:
CGAL_assertion( false ); CGAL_unreachable();
} }
} }
@ -1046,8 +1039,8 @@ walk_to_next_2_inf( int inf )
_target ); _target );
if( occw == NEGATIVE ) { if( occw == NEGATIVE ) {
Cell_handle tmp = cell()->neighbor(_tr->cw(inf)); Cell_handle tmp = cell()->neighbor(_tr->cw(inf));
_prev = Simplex( cell(), Tr::EDGE, _tr->ccw(inf), inf ); _prev = Simplex{ cell(), Tr::EDGE, _tr->ccw(inf), inf };
_cur = Simplex( tmp, Tr::EDGE, tmp->index( prev_cell()->vertex( prev_li() ) ), tmp->index( prev_cell()->vertex( prev_lj() ) ) ); _cur = Simplex{ tmp, Tr::EDGE, tmp->index(prev_cell()->vertex(prev_li())), tmp->index(prev_cell()->vertex(prev_lj())) };
return; return;
} }
Orientation ocw = coplanar_orientation( _source, Orientation ocw = coplanar_orientation( _source,
@ -1056,8 +1049,8 @@ walk_to_next_2_inf( int inf )
_target ); _target );
if( ocw == NEGATIVE ) { if( ocw == NEGATIVE ) {
Cell_handle tmp = cell()->neighbor(_tr->ccw(inf)); Cell_handle tmp = cell()->neighbor(_tr->ccw(inf));
_prev = Simplex( cell(), Tr::EDGE, _tr->cw(inf), inf ); _prev = Simplex{ cell(), Tr::EDGE, _tr->cw(inf), inf };
_cur = Simplex( tmp, Tr::EDGE, tmp->index( prev_cell()->vertex( prev_li() ) ), tmp->index( prev_cell()->vertex( prev_lj() ) ) ); _cur = Simplex{ tmp, Tr::EDGE, tmp->index(prev_cell()->vertex(prev_li())), tmp->index(prev_cell()->vertex(prev_lj())) };
return; return;
} }
Orientation op = coplanar_orientation( Orientation op = coplanar_orientation(
@ -1067,35 +1060,35 @@ walk_to_next_2_inf( int inf )
switch( op ) { switch( op ) {
case NEGATIVE: case NEGATIVE:
if( occw == COLLINEAR ) { if( occw == COLLINEAR ) {
_prev = Simplex( cell(), Tr::VERTEX, _tr->ccw(inf), -1 ); _prev = Simplex{ cell(), Tr::VERTEX, _tr->ccw(inf), -1 };
_cur = Simplex( fin, Tr::VERTEX, fin->index( prev_cell()->vertex( prev_li() ) ), -1 ); _cur = Simplex{ fin, Tr::VERTEX, fin->index(prev_cell()->vertex(prev_li())), -1 };
return; return;
} }
if( ocw == COLLINEAR ) { if( ocw == COLLINEAR ) {
_prev = Simplex( cell(), Tr::VERTEX, _tr->cw(inf), -1 ); _prev = Simplex{ cell(), Tr::VERTEX, _tr->cw(inf), -1 };
_cur = Simplex( fin, Tr::VERTEX, fin->index( prev_cell()->vertex( prev_li() ) ), -1 ); _cur = Simplex{ fin, Tr::VERTEX, fin->index(prev_cell()->vertex(prev_li())), -1 };
return; return;
} }
_prev = Simplex( cell(), Tr::EDGE, _tr->ccw(inf), _tr->cw(inf) ); _prev = Simplex{ cell(), Tr::EDGE, _tr->ccw(inf), _tr->cw(inf) };
_cur = Simplex( fin, Tr::EDGE, fin->index( prev_cell()->vertex( prev_li() ) ), fin->index( prev_cell()->vertex( prev_lj() ) ) ); _cur = Simplex{ fin, Tr::EDGE, fin->index(prev_cell()->vertex(prev_li())), fin->index(prev_cell()->vertex(prev_lj())) };
return; return;
case COLLINEAR: case COLLINEAR:
if( occw == COLLINEAR ) { if( occw == COLLINEAR ) {
_prev = Simplex( cell(), Tr::VERTEX, _tr->ccw(inf), -1 ); _prev = Simplex{ cell(), Tr::VERTEX, _tr->ccw(inf), -1 };
cell() = Cell_handle(); cell() = Cell_handle();
return; return;
} }
if( ocw == COLLINEAR ) { if( ocw == COLLINEAR ) {
_prev = Simplex( cell(), Tr::VERTEX, _tr->cw(inf), -1 ); _prev = Simplex{ cell(), Tr::VERTEX, _tr->cw(inf), -1 };
cell() = Cell_handle(); cell() = Cell_handle();
return; return;
} }
_prev = Simplex( cell(), Tr::EDGE, _tr->ccw(inf), _tr->cw(inf) ); _prev = Simplex{ cell(), Tr::EDGE, _tr->ccw(inf), _tr->cw(inf) };
cell() = Cell_handle(); cell() = Cell_handle();
return; return;
case POSITIVE: case POSITIVE:
// The tarstd::std::get lies in this infinite cell. // The tarstd::std::get lies in this infinite cell.
_prev = Simplex( cell(), Tr::OUTSIDE_CONVEX_HULL, -1, -1 ); _prev = Simplex{ cell(), Tr::OUTSIDE_CONVEX_HULL, -1, -1 };
cell() = Cell_handle(); cell() = Cell_handle();
return; return;
} }
@ -1138,7 +1131,7 @@ Triangulation_segment_cell_iterator_3<Tr, Inc>::opposite_edge(
case 5: return Edge(c, 2, 3); case 5: return Edge(c, 2, 3);
} }
CGAL_assertion(false); CGAL_unreachable();
return Edge(); return Edge();
} }

View File

@ -17,7 +17,6 @@
#include <iostream> #include <iostream>
#include <utility> #include <utility>
#include <tuple>
#include <CGAL/assertions.h> #include <CGAL/assertions.h>
#include <CGAL/Triangulation_utils_3.h> #include <CGAL/Triangulation_utils_3.h>
@ -27,6 +26,7 @@
#include <CGAL/Triangulation_vertex_base_3.h> #include <CGAL/Triangulation_vertex_base_3.h>
#include <CGAL/Triangulation_simplex_3.h> #include <CGAL/Triangulation_simplex_3.h>
#include <boost/optional.hpp>
// If defined, type casting is done statically, // If defined, type casting is done statically,
// reducing type-safety overhead. // reducing type-safety overhead.
@ -113,7 +113,13 @@ public:
typedef typename Tr::Locate_type Locate_type; //< defines the simplex type returned from location. typedef typename Tr::Locate_type Locate_type; //< defines the simplex type returned from location.
typedef std::tuple<Cell_handle,Locate_type,int,int> Simplex; //< defines the simplex type. struct Simplex //< defines the simplex type
{
Cell_handle cell = {};
Locate_type lt = Locate_type::OUTSIDE_AFFINE_HULL;
int li = -1;
int lj = -1;
};
typedef Cell value_type; //< defines the value type the iterator refers to. typedef Cell value_type; //< defines the value type the iterator refers to.
typedef Cell& reference; //< defines the reference type of the iterator. typedef Cell& reference; //< defines the reference type of the iterator.
@ -127,6 +133,55 @@ public:
template < class Tr2, class Inc2 > template < class Tr2, class Inc2 >
struct Rebind { typedef Triangulation_segment_cell_iterator_3<Tr2,Inc2> Other; }; struct Rebind { typedef Triangulation_segment_cell_iterator_3<Tr2,Inc2> Other; };
#if CGAL_DEBUG_TRIANGULATION_SEGMENT_TRAVERSER_3
static auto display_vert(Vertex_handle v)
{
std::stringstream os;
os.precision(17);
if(v->time_stamp() == 0) {
os << "inf";
} else {
os << '#' << v->time_stamp() << "=(" << v->point() << ")";
}
return os.str();
};
static auto display_lt(Locate_type lt) {
std::stringstream os;
switch(lt) {
case Locate_type::VERTEX: os << " VERTEX"; break;
case Locate_type::EDGE: os << " EDGE"; break;
case Locate_type::FACET: os << " FACET"; break;
case Locate_type::CELL: os << " CELL"; break;
case Locate_type::OUTSIDE_CONVEX_HULL: os << " OUTSIDE_CONVEX_HULL"; break;
case Locate_type::OUTSIDE_AFFINE_HULL: os << " OUTSIDE_AFFINE_HULL"; break;
}
return os.str();
}
static auto debug_simplex(Simplex s) {
std::stringstream os;
os.precision(17);
const auto [c, lt, i, j] = s;
if(c == Cell_handle{}) {
os << "end()";
} else {
os << display_vert(c->vertex(0)) << " - " << display_vert(c->vertex(1)) << " - "
<< display_vert(c->vertex(2)) << " - " << display_vert(c->vertex(3));
os << display_lt(lt) << " " << i << " " << j;
}
return os.str();
}
auto debug_iterator() const
{
std::stringstream os;
os.precision(17);
os << " prev: " << debug_simplex(_prev) << "\n cur: " << debug_simplex(_cur);
return os.str();
}
#endif // CGAL_DEBUG_TRIANGULATION_SEGMENT_TRAVERSER_3
private: private:
typedef Segment_cell_iterator SCI; typedef Segment_cell_iterator SCI;
@ -228,15 +283,17 @@ public:
*/ */
const Point& target() const { return _target; } const Point& target() const { return _target; }
Vertex_handle target_vertex() const { return _t_vertex; }
// gives a handle to the current cell. // gives a handle to the current cell.
/* By invariance, this cell is intersected by the segment /* By invariance, this cell is intersected by the segment
* between `source()` and `target()`. * between `source()` and `target()`.
* \return a handle to the current cell. * \return a handle to the current cell.
* \sa `cell()`. * \sa `cell()`.
*/ */
Cell_handle handle() Cell_handle handle() const
{ {
return std::get<0>(_cur); return _cur.cell;
} }
// gives the previous cell. // gives the previous cell.
@ -257,7 +314,7 @@ public:
*/ */
Cell* operator->() Cell* operator->()
{ {
return &*std::get<0>(_cur); return &*(_cur.cell);
} }
// provides an indirection operator. // provides an indirection operator.
@ -265,7 +322,7 @@ public:
*/ */
Cell& operator*() Cell& operator*()
{ {
return *std::get<0>(_cur); return *(_cur.cell);
} }
// provides a conversion operator. // provides a conversion operator.
@ -273,7 +330,7 @@ public:
*/ */
operator Cell_handle() const operator Cell_handle() const
{ {
return std::get<0>(_cur); return _cur.cell;
} }
// provides a conversion operator. // provides a conversion operator.
@ -299,6 +356,10 @@ public:
{ {
lt = this->lt(); li = this->li(); lj = this->lj(); lt = this->lt(); li = this->li(); lj = this->lj();
} }
std::tuple<Locate_type, int, int> entry() const
{
return { lt(), li(), lj() };
}
// gives the simplex through which the previous cell was exited. // gives the simplex through which the previous cell was exited.
/* \pre the current cell is not the initial cell. /* \pre the current cell is not the initial cell.
*/ */
@ -306,6 +367,10 @@ public:
{ {
lt = prev_lt(); li = prev_li(); lj = prev_lj(); lt = prev_lt(); li = prev_li(); lj = prev_lj();
} }
std::tuple<Locate_type, int, int> exit() const
{
return { prev_lt(), prev_li(), prev_lj() };
}
// gives the past-the-end iterator associated with this iterator. // gives the past-the-end iterator associated with this iterator.
SCI end() const; SCI end() const;
@ -364,7 +429,7 @@ public:
*/ */
bool operator==( const Cell_handle& ch ) const bool operator==( const Cell_handle& ch ) const
{ {
return ch == std::get<0>(_cur); return ch == _cur.cell;
} }
// compares the current cell with `ch`. // compares the current cell with `ch`.
@ -375,7 +440,7 @@ public:
*/ */
bool operator!=( const Cell_handle& ch ) const bool operator!=( const Cell_handle& ch ) const
{ {
return ch != std::get<0>(_cur); return ch != _cur.cell;
} }
// \} // \}
@ -439,32 +504,33 @@ private:
Edge opposite_edge(Cell_handle c, int li, int lj) const; Edge opposite_edge(Cell_handle c, int li, int lj) const;
Edge opposite_edge(const Edge& e) const; Edge opposite_edge(const Edge& e) const;
protected:
// ref-accessors to the simplex, for use in internal code // ref-accessors to the simplex, for use in internal code
// access _cur // access _cur
Cell_handle& cell() { return std::get<0>(_cur); } Cell_handle& cell() { return _cur.cell; }
Cell_handle const& cell() const { return std::get<0>(_cur); } Cell_handle const& cell() const { return _cur.cell; }
Locate_type& lt() { return std::get<1>(_cur); } Locate_type& lt() { return _cur.lt; }
Locate_type const& lt() const { return std::get<1>(_cur); } Locate_type const& lt() const { return _cur.lt; }
int& li() { return std::get<2>(_cur); } int& li() { return _cur.li; }
int const& li() const { return std::get<2>(_cur); } int const& li() const { return _cur.li; }
int& lj() { return std::get<3>(_cur); } int& lj() { return _cur.lj; }
int const& lj() const { return std::get<3>(_cur); } int const& lj() const { return _cur.lj; }
// access _prev // access _prev
Cell_handle& prev_cell() { return std::get<0>(_prev); } Cell_handle& prev_cell() { return _prev.cell; }
Cell_handle const& prev_cell() const { return std::get<0>(_prev); } Cell_handle const& prev_cell() const { return _prev.cell; }
Locate_type& prev_lt() { return std::get<1>(_prev); } Locate_type& prev_lt() { return _prev.lt; }
Locate_type const& prev_lt() const { return std::get<1>(_prev); } Locate_type const& prev_lt() const { return _prev.lt; }
int& prev_li() { return std::get<2>(_prev); } int& prev_li() { return _prev.li; }
int const& prev_li() const { return std::get<2>(_prev); } int const& prev_li() const { return _prev.li; }
int& prev_lj() { return std::get<3>(_prev); } int& prev_lj() { return _prev.lj; }
int const& prev_lj() const { return std::get<3>(_prev); } int const& prev_lj() const { return _prev.lj; }
}; // class Triangulation_segment_cell_iterator_3 }; // class Triangulation_segment_cell_iterator_3
@ -572,7 +638,7 @@ public:
const Point& source() const { return _cell_iterator.source(); } const Point& source() const { return _cell_iterator.source(); }
const Point& target() const { return _cell_iterator.target(); } const Point& target() const { return _cell_iterator.target(); }
const Tr* triangulation() const { return _cell_iterator.triangulation(); } const Tr& triangulation() const { return *_cell_iterator.triangulation(); }
private: private:
Triangulation_segment_simplex_iterator_3 Triangulation_segment_simplex_iterator_3
@ -584,20 +650,23 @@ private:
private: private:
void set_curr_simplex_to_entry() void set_curr_simplex_to_entry()
{ {
#if CGAL_DEBUG_TRIANGULATION_SEGMENT_TRAVERSER_3
std::cerr << "cell iterator is:\n" << _cell_iterator.debug_iterator() << std::endl;
#endif // #if CGAL_DEBUG_TRIANGULATION_SEGMENT_TRAVERSER_3
Locate_type lt; Locate_type lt;
int li, lj; int li, lj;
Cell_handle cell; Cell_handle cell = Cell_handle(_cell_iterator);
//check what is the entry type of _cell_iterator //check what is the entry type of _cell_iterator
if (Cell_handle(_cell_iterator) == Cell_handle()) if (cell == Cell_handle())
{ {
//where did the segment std::get out from previous cell //where did the segment get out from previous cell
cell = _cell_iterator.previous(); cell = _cell_iterator.previous();
_cell_iterator.exit(lt, li, lj); _cell_iterator.exit(lt, li, lj);
} }
else else
{ {
cell = Cell_handle(_cell_iterator);
_cell_iterator.entry(lt, li, lj); _cell_iterator.entry(lt, li, lj);
} }
@ -623,7 +692,7 @@ private:
_curr_simplex = cell; _curr_simplex = cell;
break; break;
default: default:
CGAL_assertion(false); CGAL_unreachable();
}; };
} }
@ -637,282 +706,145 @@ public:
// provides the increment postfix operator. // provides the increment postfix operator.
Simplex_iterator& operator++() Simplex_iterator& operator++()
{ {
auto increment_cell_iterator = [&]() {
++_cell_iterator;
#if CGAL_DEBUG_TRIANGULATION_SEGMENT_TRAVERSER_3
std::cerr << "increment cell iterator to:\n" << _cell_iterator.debug_iterator() << '\n';
#endif
};
CGAL_assertion(_curr_simplex.incident_cell() != Cell_handle()); CGAL_assertion(_curr_simplex.incident_cell() != Cell_handle());
switch(_curr_simplex.dimension()) if(!cell_iterator_is_ahead()) {
{ increment_cell_iterator(); // cell_iterator needs to be ahead
case 3 :/*Cell_handle*/ }
{
Cell_handle ch = Cell_handle(_cell_iterator); Cell_handle ch_next = Cell_handle(_cell_iterator);
if (ch == Cell_handle()) Cell_handle ch_prev = _cell_iterator.previous();
{ Locate_type lt_prev;
if(!triangulation()->is_infinite(Cell_handle(_curr_simplex))) int li_prev, lj_prev;
_cell_iterator.exit(lt_prev, li_prev, lj_prev);
if(_curr_simplex.dimension() == 3) {
set_curr_simplex_to_entry(); set_curr_simplex_to_entry();
return *this;
}
if(lt_prev == Locate_type::CELL ||
lt_prev == Locate_type::OUTSIDE_CONVEX_HULL ||
lt_prev == Locate_type::OUTSIDE_AFFINE_HULL)
{
CGAL_assertion(ch_next == Cell_handle());
_curr_simplex = ch_prev;
return *this;
}
switch(_curr_simplex.dimension()) {
case 2: { /*Facet*/
CGAL_assertion((ch_next == Cell_handle()) == (_cell_iterator == _cell_iterator.end()));
switch(lt_prev) {
case Locate_type::VERTEX: { // facet-cell?-vertex-outside
Vertex_handle v_prev{ch_prev->vertex(li_prev)};
if(facet_has_vertex(get_facet(), v_prev))
_curr_simplex = v_prev;
else else
_curr_simplex = ch_prev;
} break;
case Locate_type::EDGE: { // facet-cell?-edge-outside
Edge edge_prev{ch_prev, li_prev, lj_prev};
if(facet_has_edge(get_facet(), edge_prev))
_curr_simplex = edge_prev;
else
_curr_simplex = ch_prev;
} break;
case Locate_type::FACET: { // facet-cell-facet-outside
Facet f_prev{ch_prev, li_prev};
if(is_same_facet(f_prev, get_facet())) {
if(ch_next == Cell_handle())
_curr_simplex = Simplex_3(); _curr_simplex = Simplex_3();
break;
}
else else
{ _curr_simplex = ch_next;
if (!cell_iterator_is_ahead()) } else
++_cell_iterator; _curr_simplex = ch_prev;
set_curr_simplex_to_entry(); } break;
}
break;
}
case 2 :/*Facet*/
{
Cell_handle ch = Cell_handle(_cell_iterator);
if (!cell_iterator_is_ahead())
{
//cell_iterator is not ahead. get_facet() is part of cell_iterator
//we cannot be in any of the degenerate cases, only detected by
//taking cell_iterator one step forward
CGAL_assertion(cell_has_facet(Cell_handle(_cell_iterator), get_facet()));
++_cell_iterator;
if (Cell_handle(_cell_iterator) == Cell_handle())
{
_curr_simplex = _cell_iterator.previous();
break;
}
}
else
ch = _cell_iterator.previous();
Cell_handle chnext = Cell_handle(_cell_iterator);
Locate_type ltnext;
int linext, ljnext;
_cell_iterator.entry(ltnext, linext, ljnext);
switch (ltnext)//entry simplex in next cell
{
case Locate_type::VERTEX:
{
if (_cell_iterator == _cell_iterator.end())
{
_curr_simplex = Simplex_3();
break;
}
//if the entry vertex is a vertex of current facet
int i;
if (triangulation()->has_vertex(get_facet(), chnext->vertex(linext), i))
set_curr_simplex_to_entry();
else
_curr_simplex = ch;
break;
}
case Locate_type::EDGE:
if (facet_has_edge(get_facet(), Edge(chnext, linext, ljnext)))
set_curr_simplex_to_entry();
else
_curr_simplex = ch;
break;
case Locate_type::FACET:
_curr_simplex = ch;
break;
case Locate_type::OUTSIDE_AFFINE_HULL:
_curr_simplex = Simplex_3();
break;
default: default:
CGAL_assertion(false); CGAL_unreachable();
};
break;
} }
case 1:/*Edge*/ } break;
{ case 1: {/*Edge*/
Cell_handle ch = Cell_handle(_cell_iterator); switch(lt_prev) {
if (ch == _cell_iterator.previous()) case Locate_type::VERTEX: { //edge-vertex-outside
{ Vertex_handle v_prev{ch_prev->vertex(li_prev)};
if(edge_has_vertex(get_edge(), v_prev))
_curr_simplex = v_prev;
else
_curr_simplex = shared_facet(get_edge(), v_prev);
} break;
case Locate_type::EDGE: { //edge-outside or edge-cell-edge-outside
const Edge e_prev(ch_prev, li_prev, lj_prev);
if(is_same_edge(get_edge(), e_prev)) {
if(ch_next == Cell_handle()) {
_curr_simplex = Simplex_3(); _curr_simplex = Simplex_3();
break; } else {
_curr_simplex = ch_next;
} }
Locate_type lt; } else {
int li, lj; auto facet_opt = shared_facet(get_edge(), e_prev);
_cell_iterator.entry(lt, li, lj); if(static_cast<bool>(facet_opt)) {
_curr_simplex = *facet_opt;
if (!cell_iterator_is_ahead()) }
{ else {
++_cell_iterator;//cell_iterator needs to be ahead to detect degeneracies _curr_simplex = shared_cell(get_edge(), e_prev);
if (Cell_handle(_cell_iterator) == Cell_handle())
{
_curr_simplex = _cell_iterator.previous();
break;
} }
} }
} break;
Cell_handle chnext = Cell_handle(_cell_iterator); case Locate_type::FACET: {
Locate_type ltnext; Facet f_prev{ch_prev, li_prev};
int linext, ljnext; if(facet_has_edge(f_prev, get_edge()))
_cell_iterator.entry(ltnext, linext, ljnext); _curr_simplex = f_prev; //edge-facet-outside
switch (ltnext)//entry simplex in next cell
{
case Locate_type::VERTEX:
if (edge_has_vertex(get_edge(), chnext->vertex(linext)))
_curr_simplex = chnext->vertex(linext);
else else
_curr_simplex = shared_facet(get_edge(), chnext->vertex(linext)); _curr_simplex = ch_prev; //query goes through the cell
break; } break;
case Locate_type::EDGE:
{
CGAL_assertion(_cell_iterator == _cell_iterator.end()
|| triangulation()->is_infinite(chnext)
|| _curr_simplex != Simplex_3(Edge(chnext, linext, ljnext)));
if (_cell_iterator == _cell_iterator.end())
_curr_simplex = Simplex_3();
else if (triangulation()->is_infinite(chnext)
&& _curr_simplex == Simplex_3(Edge(chnext, linext, ljnext)))
_curr_simplex = chnext;
else
_curr_simplex = shared_facet(get_edge(), Edge(chnext, linext, ljnext));
break;
}
case Locate_type::FACET:
_curr_simplex = Cell_handle(_cell_iterator);//query goes through the cell
break;
case Locate_type::OUTSIDE_AFFINE_HULL:
{
Cell_handle chprev = _cell_iterator.previous();
Locate_type ltprev;
int liprev, ljprev;
_cell_iterator.exit(ltprev, liprev, ljprev);
if (ltprev == Locate_type::VERTEX) //edge-vertex-outside
_curr_simplex = chprev->vertex(liprev);
else
_curr_simplex = Simplex_3(); //edge-outside
break;
}
default: default:
CGAL_assertion(false);//should not happen CGAL_unreachable();
};
break;
} }
} break;
case 0 :/*Vertex_handle*/ case 0 :/*Vertex_handle*/
{ {
Cell_handle ch = Cell_handle(_cell_iterator); switch(lt_prev) {
if (ch == _cell_iterator.previous()) case Locate_type::VERTEX: {
{ if(ch_prev->vertex(li_prev) != get_vertex()) // avoid infinite loop edge-vertex-same edge-...
_curr_simplex = Edge(ch_prev, li_prev, ch_prev->index(get_vertex()));
else {
if(ch_next == Cell_handle()) {
_curr_simplex = Simplex_3(); _curr_simplex = Simplex_3();
break; } else {
_curr_simplex = ch_next;
} }
if (!cell_iterator_is_ahead()) //_curr_simplex does contain v
{
++_cell_iterator;//cell_iterator needs to be ahead to detect degeneracies
} }
} break;
case Locate_type::EDGE: {
const Edge e_prev(ch_prev, li_prev, lj_prev);
if(edge_has_vertex(e_prev, get_vertex()))
_curr_simplex = e_prev;
else else
ch = _cell_iterator.previous(); _curr_simplex = shared_facet(Edge(ch_prev, li_prev, lj_prev), get_vertex());
} break;
Cell_handle chnext = Cell_handle(_cell_iterator); case Locate_type::FACET: {
//_cell_iterator is one step forward _curr_simplex if(ch_prev->vertex(li_prev) != get_vertex()) // vertex-facet-outside
CGAL_assertion(ch != chnext); _curr_simplex = Facet(ch_prev, li_prev);
else // vertex-cell-facet-outside
Locate_type ltnext; _curr_simplex = ch_prev;
int linext, ljnext; } break;
_cell_iterator.entry(ltnext, linext, ljnext);
Cell_handle prev;
Locate_type ltprev;
int liprev, ljprev;
prev = _cell_iterator.previous();
_cell_iterator.exit(ltprev, liprev, ljprev);
switch (ltnext)
{
case Locate_type::VERTEX:
{
CGAL_assertion(_cell_iterator == _cell_iterator.end()
|| get_vertex() != chnext->vertex(linext)
|| triangulation()->is_infinite(chnext));
if (_cell_iterator == _cell_iterator.end())
{
if (prev == ch && ltprev == Locate_type::VERTEX)
{
CGAL_assertion(prev->vertex(liprev) == get_vertex());
_curr_simplex = ch;
}
else
{
if(ltprev == Locate_type::FACET)
_curr_simplex = Facet(prev, liprev);
else if(ltprev == Locate_type::EDGE)
_curr_simplex = Edge(prev, liprev, ljprev);
else
CGAL_assertion(false);
}
}
else
{
if (triangulation()->is_infinite(chnext) && get_vertex() == chnext->vertex(linext))
_curr_simplex = chnext;
else
{
Cell_handle ec;
int ei = -1, ej = -1;
if (!triangulation()->is_edge(get_vertex(), chnext->vertex(linext), ec, ei, ej))
CGAL_assertion(false);
_curr_simplex = Edge(ec, ei, ej);
}
}
break;
}
case Locate_type::EDGE:
{
//facet shared by get_vertex() and the edge
//none of ch and chnext is certainly shared by both endpoints
_curr_simplex = shared_facet(Edge(chnext, linext, ljnext), get_vertex());
break;
}
case Locate_type::OUTSIDE_AFFINE_HULL:
{
CGAL_assertion(_cell_iterator == _cell_iterator.end());
if (ltprev == Locate_type::VERTEX) //vertex-edge-vertex-outside
{
if(prev->vertex(liprev) != get_vertex())//avoid infinite loop edge-vertex-same edge-...
_curr_simplex = Edge(prev, liprev, prev->index(get_vertex()));
else
_curr_simplex = Simplex_3();
}
else if (ltprev == Locate_type::EDGE)//vertex-facet-edge-outside
_curr_simplex = Facet(prev, prev->index(get_vertex()));
else if (ltprev == Locate_type::FACET) //vertex-facet-outside
{
if(prev->vertex(liprev) != get_vertex()) //vertex-facet-outside
_curr_simplex = Facet(prev, liprev);
else //vertex-cell-facet-outside
_curr_simplex = prev;
}
else
{
CGAL_assertion(ltprev == Locate_type::CELL);//vertex-cell-outside
_curr_simplex = prev;
}
break;
}
default://FACET
if (chnext == Cell_handle())
_curr_simplex = Simplex_3();
else
_curr_simplex = shared_cell(Facet(chnext, linext), get_vertex());
break;
};
}
break;
default: default:
CGAL_assertion(false); CGAL_unreachable();
}
} break;
default:
CGAL_unreachable();
}; };
return *this; return *this;
} }
// provides the increment prefix operator. // provides the increment prefix operator.
Simplex_iterator operator++(int) Simplex_iterator operator++(int)
{ {
@ -1010,10 +942,10 @@ private:
case 3 ://cell case 3 ://cell
return ch != get_cell(); return ch != get_cell();
default: default:
CGAL_assertion(false); CGAL_unreachable();
} }
//should not be reached //should not be reached
CGAL_assertion(false); CGAL_unreachable();
return false; return false;
} }
@ -1048,13 +980,29 @@ private:
return false; return false;
} }
bool facet_has_vertex(const Facet& f, const Vertex_handle v) const
{
return triangulation().tds().has_vertex(f, v);
}
bool edge_has_vertex(const Edge& e, const Vertex_handle v) const bool edge_has_vertex(const Edge& e, const Vertex_handle v) const
{ {
return e.first->vertex(e.second) == v return e.first->vertex(e.second) == v
|| e.first->vertex(e.third) == v; || e.first->vertex(e.third) == v;
} }
Vertex_handle shared_vertex(const Edge& e1, const Edge& e2) const bool is_same_edge(const Edge& e1, const Edge& e2) const
{
return edge_has_vertex(e1, e2.first->vertex(e2.second))
&& edge_has_vertex(e1, e2.first->vertex(e2.third));
}
bool is_same_facet(const Facet& f1, const Facet& f2) const
{
return f1 == f2 || triangulation().mirror_facet(f1) == f2;
}
boost::optional<Vertex_handle> shared_vertex(const Edge& e1, const Edge& e2) const
{ {
Vertex_handle v1a = e1.first->vertex(e1.second); Vertex_handle v1a = e1.first->vertex(e1.second);
Vertex_handle v1b = e1.first->vertex(e1.third); Vertex_handle v1b = e1.first->vertex(e1.third);
@ -1065,22 +1013,22 @@ private:
return v1a; return v1a;
else if (v1b == v2a || v1b == v2b) else if (v1b == v2a || v1b == v2b)
return v1b; return v1b;
else
std::cerr << "There is no vertex shared by e1 and e2" << std::endl; return {};
CGAL_assertion(false);
return Vertex_handle();
} }
Facet shared_facet(const Edge& e1, const Edge& e2) const boost::optional<Facet> shared_facet(const Edge& e1, const Edge& e2) const
{ {
Vertex_handle v2a = e2.first->vertex(e2.second); Vertex_handle v2a = e2.first->vertex(e2.second);
Vertex_handle v2b = e2.first->vertex(e2.third); Vertex_handle v2b = e2.first->vertex(e2.third);
Vertex_handle sv = shared_vertex(e1, e2); auto sv_opt = shared_vertex(e1, e2);
if(!sv_opt) return {};
Vertex_handle sv = *sv_opt;
Vertex_handle nsv2 = (sv == v2a) ? v2b : v2a; Vertex_handle nsv2 = (sv == v2a) ? v2b : v2a;
typename Tr::Facet_circulator circ typename Tr::Facet_circulator circ
= triangulation()->incident_facets(e1); = triangulation().incident_facets(e1);
typename Tr::Facet_circulator end = circ; typename Tr::Facet_circulator end = circ;
do do
{ {
@ -1092,33 +1040,30 @@ private:
} }
} while (++circ != end); } while (++circ != end);
std::cerr << "There is no facet shared by e1 and e2" << std::endl; return {};
CGAL_assertion(false);
return Facet(Cell_handle(), 0);
} }
Facet shared_facet(const Edge& e, const Vertex_handle v) const Facet shared_facet(const Edge& e, const Vertex_handle v) const
{ {
typename Tr::Facet_circulator circ typename Tr::Facet_circulator circ
= triangulation()->incident_facets(e); = triangulation().incident_facets(e);
typename Tr::Facet_circulator end = circ; typename Tr::Facet_circulator end = circ;
do do
{ {
Facet f = *circ; Facet f = *circ;
int i; if (facet_has_vertex(f, v))
if (triangulation()->has_vertex(f, v, i))
return f; return f;
} while (++circ != end); } while (++circ != end);
std::cerr << "There is no facet shared by e and v" << std::endl; std::cerr << "There is no facet shared by e and v" << std::endl;
CGAL_assertion(false); CGAL_unreachable();
return Facet(Cell_handle(), 0); return Facet(Cell_handle(), 0);
} }
Cell_handle shared_cell(const Edge& e, const Vertex_handle v) const Cell_handle shared_cell(const Edge& e, const Vertex_handle v) const
{ {
typename Tr::Cell_circulator circ typename Tr::Cell_circulator circ
= triangulation()->incident_cells(e); = triangulation().incident_cells(e);
typename Tr::Cell_circulator end = circ; typename Tr::Cell_circulator end = circ;
do do
{ {
@ -1128,7 +1073,7 @@ private:
} while (++circ != end); } while (++circ != end);
std::cerr << "There is no cell shared by e and v" << std::endl; std::cerr << "There is no cell shared by e and v" << std::endl;
CGAL_assertion(false); CGAL_unreachable();
return Cell_handle(); return Cell_handle();
} }
@ -1145,6 +1090,11 @@ private:
} }
} }
Cell_handle shared_cell(const Edge e1, const Edge e2) const {
auto facet = shared_facet(e1, e2.first->vertex(e2.second));
return shared_cell(facet, e2.first->vertex(e2.third));
}
};//class Triangulation_segment_simplex_iterator_3 };//class Triangulation_segment_simplex_iterator_3
} // namespace CGAL } // namespace CGAL

View File

@ -25,6 +25,14 @@ create_single_source_cgal_program("test_simplex_3.cpp")
create_single_source_cgal_program("test_simplex_iterator_3.cpp" ) create_single_source_cgal_program("test_simplex_iterator_3.cpp" )
create_single_source_cgal_program("test_segment_cell_traverser_3.cpp" ) create_single_source_cgal_program("test_segment_cell_traverser_3.cpp" )
create_single_source_cgal_program("test_segment_simplex_traverser_3.cpp" ) create_single_source_cgal_program("test_segment_simplex_traverser_3.cpp" )
if(cxx_std_17 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
target_compile_features(test_segment_simplex_traverser_3 PRIVATE cxx_std_17)
else()
message(
STATUS
"NOTICE: test_segment_simplex_traverser_3.cpp requires C++17 and will not be compiled."
)
endif()
create_single_source_cgal_program("test_static_filters.cpp") create_single_source_cgal_program("test_static_filters.cpp")
create_single_source_cgal_program("test_triangulation_3.cpp") create_single_source_cgal_program("test_triangulation_3.cpp")
create_single_source_cgal_program("test_io_triangulation_3.cpp") create_single_source_cgal_program("test_io_triangulation_3.cpp")

View File

@ -1,5 +1,8 @@
//#define CGAL_DEBUG_TRIANGULATION_SEGMENT_TRAVERSER_3 1
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_3.h> #include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Base_with_time_stamp.h>
#include <CGAL/IO/io.h>
#include <assert.h> #include <assert.h>
#include <iostream> #include <iostream>
@ -15,18 +18,400 @@
// Define the kernel. // Define the kernel.
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point_3; typedef Kernel::Point_3 Point_3;
typedef Kernel::Segment_3 Segment_3;
typedef Kernel::Triangle_3 Triangle_3;
typedef Kernel::Tetrahedron_3 Tetrahedron_3;
// Define the structure. // Define the structure.
typedef CGAL::Delaunay_triangulation_3<Kernel> DT; typedef CGAL::Base_with_time_stamp<CGAL::Triangulation_vertex_base_3<Kernel>> Vb;
typedef CGAL::Delaunay_triangulation_cell_base_3<Kernel> Cb;
typedef CGAL::Triangulation_data_structure_3<Vb, Cb> Tds;
typedef CGAL::Delaunay_triangulation_3<Kernel, Tds> DT;
typedef DT::Cell_handle Cell_handle; typedef DT::Cell_handle Cell_handle;
typedef DT::Edge Edge;
typedef DT::Facet Facet;
typedef DT::Vertex_handle Vertex_handle;
typedef DT::Simplex Simplex;
typedef DT::Segment_simplex_iterator Segment_simplex_iterator; typedef DT::Segment_simplex_iterator Segment_simplex_iterator;
#include "test_triangulation_simplex_3_debug.h"
// a function to insert without spatial sorting
template <typename Point_it>
void insert(DT& dt, Point_it first, Point_it end) {
for(; first != end; ++first) {
dt.insert(*first);
}
}
static const std::vector<Point_3> bbox_points =
{
{ -10.1, -10, -10.08 },
{ -10.2, 10, -10.07 },
{ 10.3, 10, -10.06 },
{ 10.4, -10, -10.05 },
{ -10.5, -10, 10.04 },
{ -10.6, 10, 10.03 },
{ 10.7, 10, 10.02 },
{ 10.8, -10, 10.01 },
};
DT dt;
std::string result_string;
bool reverse_sort_vertex_handles(Vertex_handle v1, Vertex_handle v2) {
return v1.operator->() > v2.operator->();
};
auto vertices_of_simplex(Simplex simplex) -> std::array<Vertex_handle, 4> {
std::array<Vertex_handle, 4> vertices = { Vertex_handle{}, Vertex_handle{}, Vertex_handle{}, Vertex_handle{} };
switch(simplex.dimension()) {
case 0: {
vertices[0] = static_cast<Vertex_handle>(simplex);
break;
}
case 1: {
const auto [c, index1, index2] = static_cast<Edge>(simplex);
vertices[0] = c->vertex(index1);
vertices[1] = c->vertex(index2);
break;
}
case 2: {
const auto [c, index] = static_cast<Facet>(simplex);
vertices[0] = c->vertex(DT::vertex_triple_index(index, 0));
vertices[1] = c->vertex(DT::vertex_triple_index(index, 1));
vertices[2] = c->vertex(DT::vertex_triple_index(index, 2));
break;
}
case 3: {
const auto c = static_cast<Cell_handle>(simplex);
vertices[0] = c->vertex(0);
vertices[1] = c->vertex(1);
vertices[2] = c->vertex(2);
vertices[3] = c->vertex(3);
break;
}
default: CGAL_unreachable();
}
std::sort(vertices.begin(), vertices.end(), reverse_sort_vertex_handles);
for(int i = 0; i < 4; ++i) {
assert((i <= simplex.dimension()) == (vertices[i] != Vertex_handle{}));
}
return vertices;
}
std::variant<Point_3, Segment_3, Triangle_3, Tetrahedron_3> get_simplex_geometry(Simplex simplex) {
switch(simplex.dimension()) {
case 0: {
return static_cast<Vertex_handle>(simplex)->point();
}
case 1: {
const auto [c, index1, index2] = static_cast<Edge>(simplex);
return Segment_3(c->vertex(index1)->point(), c->vertex(index2)->point());
}
case 2: {
const auto [c, index] = static_cast<Facet>(simplex);
return Triangle_3(c->vertex(DT::vertex_triple_index(index, 0))->point(),
c->vertex(DT::vertex_triple_index(index, 1))->point(),
c->vertex(DT::vertex_triple_index(index, 2))->point());
}
case 3: {
const auto c = static_cast<Cell_handle>(simplex);
return Tetrahedron_3(c->vertex(0)->point(),
c->vertex(1)->point(),
c->vertex(2)->point(),
c->vertex(3)->point());
}
default: CGAL_unreachable();
}
}
void visit_simplex(Point_3 a, Point_3 b, Simplex s, std::optional<Simplex> previous_simplex_optional) {
auto d = s.dimension();
if(3 == d && dt.is_infinite(static_cast<Cell_handle>(s))) {
result_string += 'I';
} else {
result_string += std::to_string(d);
}
std::clog << debug_simplex(s) << '\n';
const bool does_intersect_ab = (3 == d && dt.is_infinite(static_cast<Cell_handle>(s))) ||
std::visit(
[&](auto geometry) { return CGAL::do_intersect(Segment_3(a, b), geometry); },
get_simplex_geometry(s));
if(!does_intersect_ab) {
CGAL_error_msg("the simplex does not intersect the query segment");
}
if(previous_simplex_optional) {
// this block checks that consecutive simplices are incident
using Set = std::array<Vertex_handle, 4>;
Set prev_vertices = vertices_of_simplex(*previous_simplex_optional);
Set s_vertices = vertices_of_simplex(s);
if(previous_simplex_optional->dimension() < s.dimension()) {
std::swap(prev_vertices, s_vertices);
std::swap(*previous_simplex_optional, s);
}
if(!std::includes(
prev_vertices.begin(), prev_vertices.begin() + 1 + previous_simplex_optional->dimension(),
s_vertices.begin(), s_vertices.begin() + 1 + s.dimension(),
reverse_sort_vertex_handles))
{
CGAL_error_msg("consecutive simplices are not incident");
}
}
};
bool test_vfefv(bool with_bbox = false)
{
std::cerr << "## test_vfefv(" << std::boolalpha << with_bbox << ")\n";
result_string.clear();
static const std::vector<Point_3> points =
{
{ -1, 0, 0 },
{ 0, 1, 0 },
{ 0, -1, 0 },
{ 5, 0, 0 },
{ 6, 2, 2 },
{ 6, -2, -2 },
};
dt.clear();
insert(dt, points.begin(), points.end());
if(with_bbox) insert(dt, bbox_points.begin(), bbox_points.end());
const auto v = dt.finite_vertex_handles().to<std::vector>();
Cell_handle c; int i, j, k;
assert(dt.is_facet(v[0], v[1], v[2], c, i, j, k));
assert(dt.is_facet(v[1], v[2], v[3], c, i, j, k));
assert(dt.is_cell (v[1], v[2], v[3], v[4], c));
assert(dt.is_cell (v[1], v[2], v[3], v[5], c));
std::optional<Simplex> previous{};
for(auto s: dt.segment_traverser_simplices(v[0], v[3])) {
visit_simplex(points[0], points[3], s, previous);
previous = s;
}
static const std::string expected_result_string = "02120";
bool ok = (result_string == expected_result_string);
if(!ok) {
std::cerr << "test_vfefv failed\n";
std::cerr << " result_string is " << result_string << " instead of "
<< expected_result_string << '\n';
}
return ok;
}
bool test_a_simple_tetrahedron(const std::vector<Point_3>& points) {
DT dt2;
for(const auto& p: points) dt2.insert(p);
bool ok = true;
auto test = [&](Point_3 a, Point_3 b, std::string expected_result) {
// This test function calls `do_test` with four configurations:
// - with [ab] and [ba],
// - and with or without a bbox around the central tetrahedron.
dt = dt2;
auto do_with_or_without_bbox = [&](Point_3 a, Point_3 b, bool with_bbox, std::string expected_result) {
auto do_it = [&](auto from, auto to) {
bool exception_thrown = false;
result_string.clear();
try {
std::optional<Simplex> previous_simplex;
for(auto s: dt.segment_traverser_simplices(from, to)) {
visit_simplex(a, b, s, previous_simplex);
previous_simplex = s;
}
} catch(const CGAL::Assertion_exception& e) {
CGAL::get_static_warning_handler()("Assertion", e.expression().c_str(),
e.filename().c_str(),
e.line_number(),
e.message().c_str());
exception_thrown = true;
}
if(result_string != expected_result || exception_thrown) {
std::cerr << "test_a_simple_tetrahedron failed on case " << expected_result
<< (with_bbox ? " with bbox\n" : "\n");
ok = false;
}
if(result_string != expected_result) {
std::cerr << " result_string is " << result_string << " instead of "
<< expected_result << '\n';
}
if(exception_thrown) {
std::cerr << " exception thrown\n";
}
}; // end do_it
std::clog << "### Case " << expected_result;
if(with_bbox) std::clog << " with bbox";
std::clog << '\n';
std::clog << "from (" << a << ") to (" << b << ")\n";
do_it(a, b);
// then re-test using vertex handles, if possible
Vertex_handle va{};
Vertex_handle vb{};
DT::Locate_type lt;
int i, j;
auto c = dt.locate(a, lt, i, j);
if(lt == DT::VERTEX) va = c->vertex(i);
c = dt.locate(b, lt, i, j);
if(lt == DT::VERTEX) vb = c->vertex(i);
if(va != Vertex_handle{} && vb != Vertex_handle{}) {
std::clog << "from vertex" << display_vert(va) << " to vertex" << display_vert(vb) << ")\n";
do_it(va, vb);
};
}; // end do_with_or_without_bbox
std::string expected_result_reversed{expected_result.rbegin(), expected_result.rend()};
do_with_or_without_bbox(a, b, false, expected_result);
do_with_or_without_bbox(b, a, false, expected_result_reversed);
std::replace(expected_result.begin(), expected_result.end(), 'I', '3');
std::replace(expected_result_reversed.begin(), expected_result_reversed.end(), 'I', '3');
insert(dt, bbox_points.begin(), bbox_points.end());
do_with_or_without_bbox(a, b, true, expected_result);
do_with_or_without_bbox(b, a, true, expected_result_reversed);
}; // end test() lambda
// [010] queries entering by a vertex and exiting by the other vertex of an incident edge,
// on the line (x,0,0)
test({ 0, 0, 0}, {.5, 0, 0}, "01");
test({ 0, 0, 0}, { 1, 0, 0}, "010");
test({ 0, 0, 0}, { 2, 0, 0}, "010I");
test({-1, 0, 0}, { 2, 0, 0}, "I010I");
test({-1, 0, 0}, { 1, 0, 0}, "I010");
test({-1, 0, 0}, {.5, 0, 0}, "I01");
// x [020] is not possible, because that would have passed through the edge -> see [010]
// [021] queries entering by a vertex and exiting by the opposite edge of a same face,
// on the line (x,x,0) (y==x)
test({ 0, 0, 0}, {.2, .2, 0}, "02");
test({ 0, 0, 0}, {.5, .5, 0}, "021");
test({ 0, 0, 0}, { 1, 1, 0}, "021I");
test({-1, -1, 0}, { 1, 1, 0}, "I021I");
test({-1, -1, 0}, {.5, .5, 0}, "I021");
test({-1, -1, 0}, {.2, .2, 0}, "I02");
// x [030] (entering by a vertex and exiting by a non-adjacent vertex) is not possible
// because that would have passed by the common edge -> see [010]
// x [031] (entering by a vertex and exiting by a non-incident edge), is not possible
// because that would have passed by the face -> see [021]
// [032] queries entering by a vertex and exiting by the opposite facet,
// on the line x==y==0.25-0.25z
test({ 0, 0, 1}, { .25, .25, .25 }, "03");
test({ 0, 0, 1}, { .25, .25, 0 }, "032");
test({ 0, 0, 1}, { .5, .5, -.1 }, "032I");
test({-.25,-.25, 2}, { .28125, .28125, -.125}, "I032I");
test({-.25,-.25, 2}, { .25, .25, 0 }, "I032");
test({-.25,-.25, 2}, { .125, .125, .5 }, "I03");
// [121] queries entering by an edge and exiting by an edge of the same face,
// on the line (x,.5,0)
test({0, .5, 0}, {.2, .5, 0}, "12");
test({0, .5, 0}, {.5 , .5, 0}, "121");
test({0, .5, 0}, {.6 , .5, 0}, "121I");
test({-.1, .5, 0}, {.6 , .5, 0}, "I121I");
test({-.1, .5, 0}, {.5 , .5, 0}, "I121");
test({-.1, .5, 0}, {.25, .5, 0}, "I12");
// x [130] (entering by an edge and exiting by a non-incident vertex) is not possible
// because that would have passed by the common face -> see [120] ([021] in reverse)
// [131] entering by an edge and exiting by the opposite edge in the cell,
// on the line x==y==0.5-z, also known as (.5-z, .5-z, z)
test({ 0, 0, .5 }, { .25, .25, .25 }, "13");
test({ 0, 0, .5 }, { .5, .5, 0 }, "131");
test({ 0, 0, .5 }, { .625, .625, -.125}, "131I");
test({ -.125, -.125, .625}, { .625, .625, -.125}, "I131I");
test({ -.125, -.125, .625}, { .5 , .5 , 0 }, "I131");
test({ -.125, -.125, .625}, { .25, .25, .25 }, "I13");
// [132] queries entering by an edge and exiting by a facet, on the line (x, .25-x, x)
test({ 0, .25, 0}, { .20, .05, .20}, "13");
test({ 0, .25, 0}, { .25, 0, .25}, "132");
test({ 0, .25, 0}, { .5 ,-.25, .5 }, "132I");
test({-.5, .75,-.5}, { .5 ,-.25, .5 }, "I132I");
test({-.5, .75,-.5}, { .25, 0, .25}, "I132");
test({-.5, .75,-.5}, { .20, .05, .20}, "I13");
// [232] queries entering by a facet and exiting by a facet, on the line (x,.5-x,.2)
test({ 0, .5, .2}, {.2, .3, .2}, "23");
test({ 0, .5, .2}, {.5, 0, .2}, "232");
test({ 0, .5, .2}, {.55, -.05, .2}, "232I");
test({-.05, .45, .2}, {.55, -.05, .2}, "I232I");
test({-.05, .45, .2}, {.5, 0, .2}, "I232");
test({-.05, .45, .2}, {.2, .3, .2}, "I23");
// special case: queries stay in a single simplex
test({ -.125, -.125, .625}, { -.125, -.125, .6251}, "I");
test({ .25, .25, .25}, { .20, .25, .25}, "3");
test({ 0, .5, .2}, { 0, .4, .2}, "2");
test({ 0, .5, .0}, { 0, .6, .0}, "1");
return ok;
}
bool test_a_simple_tetrahedron() {
bool ok = true;
std::cout << "## test_a_simple_tetrahedron()\n"
<< R"#(
This test uses with a trivial tetrahedron, and is launched with all the
24 permutations of the four vertices. There are 7 test cases, and for each of
them 6 different segments are tested:
- The segment starts at the incoming boundary of the tetrahedron and ends
inside.
- The segment starts at the incoming boundary of the tetrahedron and ends
at the outgoing boundary.
- The segment starts at the incoming boundary of the tetrahedron, goes out
and beyond.
- The segment starts before the tetrahedron, goes through it, and comes out.
- The segment starts before the tetrahedron and ends at the outgoing boundary.
- The segment starts before the tetrahedron and ends inside.
For each of those query segments, 4 tests are performed:
- with/without 8 extra vertices in the triangulation, forming a bounding
box,
- and in the direct and reverse direction.
In total, 4032 tests are performed...
)#";
std::cout.flush();
std::vector<Point_3> points = {
{0., 0., 0.},
{1., 0., 0.},
{0., 1., 0.},
{0., 0., 1.},
};
std::sort(points.begin(), points.end());
do {
std::cout << "### new permutation of the four points\n";
for(const auto& p: points) std::cout << " " << p << '\n';
std::cout << std::endl;
ok = test_a_simple_tetrahedron(points) && ok;
}
while (std::next_permutation(points.begin(), points.end()));
return ok;
}
bool test(const DT& dt, bool test(const DT& dt,
const std::pair<Point_3, Point_3>& query, const std::pair<Point_3, Point_3>& query,
const std::array<unsigned, 4>& expected_result); const std::array<unsigned, 4>& expected_result);
int main(int, char* []) int main(int, char* [])
{ {
std::cerr.precision(17);
std::clog.precision(17);
std::cout.precision(17);
bool ok = true;
ok = test_a_simple_tetrahedron() && ok;
const std::vector<Point_3> points = { { -2, 0, 0 }, const std::vector<Point_3> points = { { -2, 0, 0 },
{ 2, 0, 0 }, { 2, 0, 0 },
{ 0, 1, -1 }, { 0, 1, -1 },
@ -43,15 +428,13 @@ int main(int, char* [])
}; };
std::vector<DT::Vertex_handle> vertices; std::vector<DT::Vertex_handle> vertices;
vertices.reserve(points.size()); vertices.reserve(points.size());
DT dt; dt.clear();
for(auto p: points) vertices.push_back(dt.insert(p)); for(auto p: points) vertices.push_back(dt.insert(p));
Cell_handle c; Cell_handle c;
assert(dt.is_valid()); assert(dt.is_valid());
assert(dt.is_cell(vertices[0], vertices[2], vertices[3], vertices[4], c)); assert(dt.is_cell(vertices[0], vertices[2], vertices[3], vertices[4], c));
assert(dt.is_cell(vertices[1], vertices[2], vertices[3], vertices[4], c)); assert(dt.is_cell(vertices[1], vertices[2], vertices[3], vertices[4], c));
std::cerr << dt.number_of_finite_cells() << '\n';
const std::vector < std::pair<Point_3, Point_3>> queries = { const std::vector < std::pair<Point_3, Point_3>> queries = {
{{-1, 0, 0}, { 1, 0, 0}}, // CFC {{-1, 0, 0}, { 1, 0, 0}}, // CFC
{{-1, 0, 0}, { 2, 0, 0}}, // CFCV {{-1, 0, 0}, { 2, 0, 0}}, // CFCV
@ -74,12 +457,20 @@ int main(int, char* [])
{2, 1, 1, 0} // reverse case: FVEV {2, 1, 1, 0} // reverse case: FVEV
}; };
bool ok = true;
for(std::size_t i=0; i<queries.size(); ++i) { for(std::size_t i=0; i<queries.size(); ++i) {
if(!test(dt, queries[i], expected_results[i])) ok = false; ok = test(dt, queries[i], expected_results[i]) && ok;
} }
std::cout << "Done (" << queries.size() << " queries)\n"; std::cout << "Done (" << queries.size() << " queries)\n";
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
ok = test_vfefv() && ok;
ok = test_vfefv(true) && ok;
if(ok) {
std::cout << "All tests passed\n";
return EXIT_SUCCESS;
} else {
std::cout << "Some tests failed\n";
return EXIT_FAILURE;
}
} }
bool test(const DT& dt, bool test(const DT& dt,
@ -100,6 +491,7 @@ bool test(const DT& dt,
// Count the number of finite cells traversed. // Count the number of finite cells traversed.
unsigned int inf = 0, fin = 0; unsigned int inf = 0, fin = 0;
std::optional<Simplex> previous;
for (; st != stend; ++st) for (; st != stend; ++st)
{ {
if (st->dimension() == 3 if (st->dimension() == 3
@ -108,46 +500,18 @@ bool test(const DT& dt,
else { else {
++fin; ++fin;
visit_simplex(p1, p2, *st, previous);
previous = *st;
switch (st->dimension()) { switch (st->dimension()) {
case 2: { case 2: ++nb_facets; break;
++nb_facets; case 1: ++nb_edges; break;
std::cout << "facet " << std::endl; case 0: ++nb_vertex; break;
DT::Facet f = *st; case 3: ++nb_cells; break;
std::cout << " ( " << f.first->vertex((f.second + 1) & 3)->point() default: CGAL_unreachable();
<< " " << f.first->vertex((f.second + 2) & 3)->point()
<< " " << f.first->vertex((f.second + 3) & 3)->point()
<< " )\n";
break;
} }
case 1: {
++nb_edges;
std::cout << "edge " << std::endl;
DT::Edge e = *st;
std::cout << " ( " << e.first->vertex(e.second)->point() << " "
<< e.first->vertex(e.third)->point() << " )\n";
break;
} }
case 0: {
++nb_vertex;
std::cout << "vertex " << std::endl;
DT::Vertex_handle v = *st;
std::cout << " ( " << v->point() << " )\n";
break;
} }
case 3: {
++nb_cells;
std::cout << "cell \n ( ";
DT::Cell_handle ch = *st;
for (int i = 0; i < 4; ++i)
std::cout << ch->vertex(i)->point() << " ";
std::cout << " )\n";
break;
}
default:
CGAL_unreachable();
} // end switch
}
}
#ifdef CGAL_TRIANGULATION_3_VERBOSE_TRAVERSER_EXAMPLE #ifdef CGAL_TRIANGULATION_3_VERBOSE_TRAVERSER_EXAMPLE
std::cout << "While traversing from " << st.source() std::cout << "While traversing from " << st.source()

View File

@ -1,5 +1,7 @@
// #define CGAL_DEBUG_TRIANGULATION_SEGMENT_TRAVERSER_3 1
#include <CGAL/Exact_predicates_exact_constructions_kernel.h> #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_3.h> #include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Base_with_time_stamp.h>
#include <assert.h> #include <assert.h>
#include <iostream> #include <iostream>
@ -17,14 +19,20 @@ typedef Kernel::Vector_3 Vector_3;
typedef Kernel::Segment_3 Segment_3; typedef Kernel::Segment_3 Segment_3;
// Define the structure. // Define the structure.
typedef CGAL::Delaunay_triangulation_3< Kernel > DT; typedef CGAL::Base_with_time_stamp<CGAL::Triangulation_vertex_base_3<Kernel>> Vb;
typedef CGAL::Delaunay_triangulation_cell_base_3<Kernel> Cb;
typedef CGAL::Triangulation_data_structure_3<Vb, Cb> Tds;
typedef CGAL::Delaunay_triangulation_3< Kernel, Tds > DT;
typedef DT::Vertex_handle Vertex_handle; typedef DT::Vertex_handle Vertex_handle;
typedef DT::Cell_handle Cell_handle; typedef DT::Cell_handle Cell_handle;
typedef DT::Edge Edge; typedef DT::Edge Edge;
typedef DT::Facet Facet; typedef DT::Facet Facet;
typedef DT::Simplex Simplex;
typedef DT::Segment_simplex_iterator Segment_simplex_iterator; typedef DT::Segment_simplex_iterator Segment_simplex_iterator;
#include "test_triangulation_simplex_3_debug.h"
void test_vertex_edge_vertex(const DT& dt, const std::size_t& nb_tests) void test_vertex_edge_vertex(const DT& dt, const std::size_t& nb_tests)
{ {
std::cout << "* test_vertex_edge_vertex *" << std::endl; std::cout << "* test_vertex_edge_vertex *" << std::endl;
@ -299,8 +307,8 @@ void test_triangulation_on_a_grid()
unsigned int nb_facets = 0, nb_edges = 0, nb_vertex = 0; unsigned int nb_facets = 0, nb_edges = 0, nb_vertex = 0;
for (; st != st.end(); ++st) for (; st != st.end(); ++st)
{ {
std::cout << st->dimension() << " "; std::cerr << st->dimension() << " ";
std::cout.flush(); std::cerr << debug_simplex(*st) <<'\n';
if (st->dimension() == 3) if (st->dimension() == 3)
{ {
if (dt.is_infinite(Cell_handle(*st))) ++inf; if (dt.is_infinite(Cell_handle(*st))) ++inf;

View File

@ -0,0 +1,68 @@
template <typename Vertex_handle>
auto display_vert(Vertex_handle v) {
std::stringstream os;
os.precision(17);
if(v->time_stamp() == 0) {
os << "inf";
} else {
os << '#' << v->time_stamp() << "=(" << v->point() << ")";
}
return os.str();
};
template <typename DT>
struct Debug_simplex {
using Cell_handle = typename DT::Cell_handle;
using Edge = typename DT::Edge;
using Facet = typename DT::Facet;
using Vertex_handle = typename DT::Vertex_handle;
using Simplex = typename DT::Simplex;
Simplex simplex;
template<typename Dt, typename CharT, typename Traits>
friend
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const Debug_simplex<Dt>& d) {
auto&& simplex = d.simplex;
switch(simplex.dimension()) {
case 0: {
os << "- vertex " << display_vert(static_cast<Vertex_handle>(simplex));
break;
}
case 1: {
const auto [c, index1, index2] = static_cast<Edge>(simplex);
os << "- edge "
<< display_vert(c->vertex(index1)) << " - "
<< display_vert(c->vertex(index2));
break;
}
case 2: {
const auto [c, index] = static_cast<Facet>(simplex);
os << "- facet "
<< display_vert(c->vertex(DT::vertex_triple_index(index, 0))) << " - "
<< display_vert(c->vertex(DT::vertex_triple_index(index, 1))) << " - "
<< display_vert(c->vertex(DT::vertex_triple_index(index, 2)));
break;
}
case 3: {
const auto c = static_cast<Cell_handle>(simplex);
os << "- cell "
<< display_vert(c->vertex(0)) << " - "
<< display_vert(c->vertex(1)) << " - "
<< display_vert(c->vertex(2)) << " - "
<< display_vert(c->vertex(3));
break;
}
default: CGAL_assume(false);
}
return os;
};
};
#include <CGAL/Triangulation_simplex_3.h>
template <typename Triangulation>
auto debug_simplex(CGAL::Triangulation_simplex_3<Triangulation> simplex) {
return Debug_simplex<Triangulation>{simplex};
}