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

Triangulation on Sphere: Fix I/O #8201

Merged
merged 15 commits into from
Jun 10, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,16 @@ class TriangulationOnSphereFaceBase_2

/// provides write access to a Boolean used to indicate if the face is a ghost face.
void set_ghost(const bool b);

/*!
inputs the non-combinatorial information given by the face:
its ghost status and other possible information.
*/
std::istream& operator>>(std::istream& is, TriangulationOnSphereFaceBase_2& v);

/*!
outputs the non combinatorial operation given by the face:
its ghost status and other possible information.
*/
std::ostream& operator<<(std::ostream& os, const TriangulationOnSphereFaceBase_2& v);
};
Original file line number Diff line number Diff line change
Expand Up @@ -327,9 +327,8 @@ class Delaunay_triangulation_on_sphere_2
Arc_on_sphere_2 dual_on_sphere(const All_edges_iterator ei) const { return dual_on_sphere(*ei); }

// Validity
bool is_plane() const;
bool is_valid(bool verbose = false, int level = 0) const;
bool is_valid_face(Face_handle fh, bool verbose = false, int level = 0) const;
bool is_valid(bool verbose = false, int level = 0) const;
};

// ------------------------ PREDICATES / CONSTRUCTIONS --------------------------------//
Expand Down Expand Up @@ -1090,39 +1089,6 @@ dual_on_sphere(const Edge& e) const

//-------------------------------------------CHECK------------------------------------------------//

// checks whether a given triangulation is plane (all points are coplanar)
template <typename Gt, typename Tds>
bool
Delaunay_triangulation_on_sphere_2<Gt, Tds>::
is_plane() const
{
if(number_of_vertices() <= 3)
return true;

bool plane = true;

Vertices_iterator it1 = vertices_begin(), it2(it1), it3(it1), it4(it1);
std::advance(it2, 1);
std::advance(it3, 2);
std::advance(it4, 3);

while(it4 != vertices_end())
{
Orientation s = side_of_oriented_circle(point(it1), point(it2), point(it3), point(it4));
plane = plane && s == ON_ORIENTED_BOUNDARY;

if(!plane)
return false;

++it1;
++it2;
++it3;
++it4;
}

return true;
}

template <typename Gt, typename Tds>
bool
Delaunay_triangulation_on_sphere_2<Gt, Tds>::
Expand Down Expand Up @@ -1154,47 +1120,19 @@ bool
Delaunay_triangulation_on_sphere_2<Gt, Tds>::
is_valid(bool verbose, int level) const
{
bool result = true;

if(!tds().is_valid(verbose, level))
// in any dimension
if(verbose)
{
if(verbose)
std::cerr << "invalid data structure" << std::endl;

CGAL_triangulation_assertion(false);
return false;
std::cerr << " number of vertices " << number_of_vertices() << "\t" << std::endl;
std::cerr << " number of faces " << number_of_faces() << "\t" << std::endl;
}

bool result = Base::is_valid(verbose, level);
CGAL_triangulation_assertion(result);

for(All_faces_iterator fit=all_faces_begin(); fit!=all_faces_end(); ++fit)
result = result && is_valid_face(fit, verbose, level);

for(Vertices_iterator vit=vertices_begin(); vit!=vertices_end(); ++vit)
result = result && Base::is_valid_vertex(vit, verbose, level);

switch(dimension())
{
case 0:
break;
case 1:
CGAL_triangulation_assertion(this->is_plane());
break;
case 2:
for(All_faces_iterator it=all_faces_begin(); it!=all_faces_end(); ++it)
{
Orientation s = orientation_on_sphere(point(it, 0), point(it, 1), point(it, 2));
result = result && (s != NEGATIVE || it->is_ghost());
CGAL_triangulation_assertion(result);
}

result = result && (number_of_faces() == 2 * number_of_vertices() - 4);
CGAL_triangulation_assertion(result);
break;
}

// in any dimension
if(verbose)
std::cerr << " number of vertices " << number_of_vertices() << "\t" << std::endl;

CGAL_triangulation_assertion(result);
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Point_with_scale
mutable Base_point proj_pt;

public:
Point_with_scale() : Base_point() { } // vertex base wants a default constructor
Point_with_scale() : Base_point(), cached(false) { } // vertex base wants a default constructor
Point_with_scale(const Base_point& p) : Base_point(p), cached(false) { }

const Base_point& get_projection(const Base_point& center,
Expand Down
65 changes: 50 additions & 15 deletions Triangulation_on_sphere_2/include/CGAL/Triangulation_on_sphere_2.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ class Triangulation_on_sphere_2

//-----------------------DEBUG--------------------------------------------------------------------
void check_neighboring_faces() const;

bool is_plane() const;
bool is_valid_vertex(Vertex_handle fh, bool verbose = false, int level = 0) const;
bool is_valid(bool verbose = false, int level = 0) const;

Expand Down Expand Up @@ -1239,6 +1239,39 @@ check_neighboring_faces() const
}
}

// checks whether a given triangulation is plane (all points are coplanar)
template <typename Gt, typename Tds>
bool
Triangulation_on_sphere_2<Gt, Tds>::
is_plane() const
{
if(number_of_vertices() <= 3)
return true;

bool is_plane = true;

Vertices_iterator it1 = vertices_begin(), it2(it1), it3(it1), it4(it1);
std::advance(it2, 1);
std::advance(it3, 2);
std::advance(it4, 3);

while(it4 != vertices_end())
{
Orientation s = orientation(point(it1), point(it2), point(it3), point(it4));
is_plane = is_plane && s == COPLANAR;

if(!is_plane)
return false;

++it1;
++it2;
++it3;
++it4;
}

return true;
}

template <typename Gt, typename Tds>
bool
Triangulation_on_sphere_2<Gt, Tds>::
Expand Down Expand Up @@ -1274,27 +1307,21 @@ is_valid(bool verbose,
if(dimension() <= 0 || (dimension() == 1 && number_of_vertices() == 2))
return result;

for(Vertices_iterator vit=vertices_begin(); vit!=vertices_end(); ++vit)
result = result && is_valid_vertex(vit, verbose, level);

if(dimension() == 1)
{
Vertices_iterator it1 = vertices_begin(), it2(it1), it3(it1);
std::advance(it2, 1);
std::advance(it3, 2);
while(it3 != vertices_end())
{
const Orientation s = orientation(point(it1), point(it2), point(it3));
result = result && (s == COLLINEAR);
CGAL_triangulation_assertion(result);
++it1; ++it2; ++it3;
}
result = result && this->is_plane();
CGAL_triangulation_assertion(result);
}
else // dimension() == 2
{
for(All_faces_iterator it=all_faces_begin(); it!=all_faces_end(); ++it)
{
const Orientation s = orientation_on_sphere(point(it, 0), point(it, 1), point(it, 2));
CGAL_triangulation_assertion(s == LEFT_TURN || is_ghost(it));

result = result && (s == LEFT_TURN || is_ghost(it));
CGAL_triangulation_assertion(result);
}

// check number of faces. This cannot be done by the TDS,
Expand All @@ -1314,6 +1341,7 @@ void
Triangulation_on_sphere_2<Gt, Tds>::
file_output(std::ostream& os) const
{
os << _gt.center() << " " << _gt.radius() << "\n";
_tds.file_output(os, Vertex_handle(), true);
}

Expand All @@ -1323,7 +1351,15 @@ Triangulation_on_sphere_2<Gt, Tds>::
file_input(std::istream& is)
{
clear();
Vertex_handle v = _tds.file_input(is, true);

Point_3 center;
FT radius;
is >> center >> radius;
_gt.set_center(center);
_gt.set_radius(radius);

Vertex_handle v = _tds.file_input(is, false);
CGAL_triangulation_assertion(is_valid());
return v;
}

Expand All @@ -1340,7 +1376,6 @@ std::istream&
operator>>(std::istream& is, Triangulation_on_sphere_2<Gt, Tds>& tr)
{
tr.file_input(is);
CGAL_triangulation_assertion(tr.is_valid());
return is;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,27 @@ class Triangulation_on_sphere_face_base_2
bool _ghost_flag;
};

template < class Gt, class Fb >
std::ostream&
operator<<(std::ostream &os, const Triangulation_on_sphere_face_base_2<Gt, Fb> &f)
{
// non combinatorial information. Default = point
os << static_cast<const Fb&>(f);
os << (f.is_ghost() ? " 1" : " 0");
return os;
}

template < class Gt, class Fb >
std::istream&
operator>>(std::istream &is, Triangulation_on_sphere_face_base_2<Gt, Fb> &f)
{
int g = -1;
is >> static_cast<Fb&>(f);
is >> g;
f.set_ghost(g == 1);
return is;
}

} // namespace CGAL

#endif //CGAL_TRIANGULATION_ON_SPHERE_FACE_BASE_2_H
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ project( Triangulation_on_sphere_2_Tests )

find_package(CGAL REQUIRED COMPONENTS Core)


find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater)
include(CGAL_Eigen3_support)

Expand All @@ -15,6 +16,7 @@ if ( CGAL_FOUND )
create_single_source_cgal_program( "test_dtos_illegal_points.cpp" )
create_single_source_cgal_program( "test_dtos_projection_traits.cpp" )
create_single_source_cgal_program( "test_dtos_traits.cpp" )
create_single_source_cgal_program( "issue_8200.cpp" )

if(TARGET CGAL::Eigen3_support)
create_single_source_cgal_program( "test_dtos_dual.cpp" )
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>

#include <CGAL/Delaunay_triangulation_on_sphere_2.h>
#include <CGAL/Projection_on_sphere_traits_3.h>
#include <fstream>

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;

typedef CGAL::Projection_on_sphere_traits_3<K> Traits;
typedef CGAL::Delaunay_triangulation_on_sphere_2<Traits> DToS2;

typedef Traits::Point_3 Point_3;

int main(int, char**)
{
std::vector<Point_3> points;
points.emplace_back( 3, 1, 1);
points.emplace_back(-8, 1, 1);
points.emplace_back( 1, 2, 1);
points.emplace_back( 1, -2, 1);
points.emplace_back( 1, 1, 10);

Traits traits(Point_3(4,1,1)); // radius is 1 by default
DToS2 dtos(traits);

Traits::Construct_point_on_sphere_2 cst = traits.construct_point_on_sphere_2_object();

for(const auto& pt : points)
{
std::cout << "----- Inserting (" << pt
<< ") at squared distance " << CGAL::squared_distance(pt, traits.center())
<< " from the center of the sphere" << std::endl;
dtos.insert(cst(pt));

std::cout << "The triangulation now has dimension: " << dtos.dimension() << " and\n";
std::cout << dtos.number_of_vertices() << " vertices" << std::endl;
std::cout << dtos.number_of_edges() << " edges" << std::endl;
std::cout << dtos.number_of_solid_faces() << " solid faces" << std::endl;
std::cout << dtos.number_of_ghost_faces() << " ghost faces" << std::endl;
}

assert(dtos.is_valid());
std::ofstream out("dtos.txt");
out.precision(17);
out << dtos << std::endl;
out.close();

CGAL::IO::write_OFF("dtos.off", dtos, CGAL::parameters::stream_precision(17));

DToS2 dtos2;
std::ifstream in("dtos.txt");
in >> dtos2;
in.close();
assert(dtos2.is_valid());

std::cout << "DTOS2 center: " << dtos2.geom_traits().center() << " radius: " << dtos2.geom_traits().radius() << std::endl;
std::cout << "DTOS2 has dimension: " << dtos2.dimension() << " and\n";
std::cout << dtos2.number_of_vertices() << " vertices" << std::endl;
std::cout << dtos2.number_of_edges() << " edges" << std::endl;
std::cout << dtos2.number_of_solid_faces() << " solid faces" << std::endl;
std::cout << dtos2.number_of_ghost_faces() << " ghost faces" << std::endl;

CGAL::IO::write_OFF("dtos2.off", dtos2, CGAL::parameters::stream_precision(17));

assert(dtos.number_of_vertices() == dtos2.number_of_vertices());
assert(dtos.number_of_edges() == dtos2.number_of_edges());
assert(dtos.number_of_solid_faces() == dtos2.number_of_solid_faces());
assert(dtos.number_of_ghost_faces() == dtos2.number_of_ghost_faces());

std::cout << "Done." << std::endl;

return EXIT_SUCCESS;
}
Loading