cgal/Triangulation_3/test/Triangulation_3/test_regular_remove_3.cpp

380 lines
11 KiB
C++

// Copyright (c) 1998 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Christophe Delage (Christophe.Delage@sophia.inria.fr)
#include <CGAL/Regular_triangulation_3.h>
#include <iostream>
#include <fstream>
#include <cassert>
//#include <cstdlib>
#include <set>
#include <boost/random/linear_congruential.hpp>
#include <boost/cstdint.hpp>
#include <CGAL/_test_types.h>
//#include <CGAL/_test_cls_regular_3.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
int degeneracy_counter = 0;
// This traits class counts the number of times a power_test has returned 0.
// This gives a rough idea of how degenerate a data set is.
struct traits : public K
{
struct Power_side_of_oriented_power_sphere_3
: public K::Power_side_of_oriented_power_sphere_3
{
using Oriented_side = K::Oriented_side;
typedef K::Weighted_point_3 Weighted_point;
typedef K::Power_side_of_oriented_power_sphere_3 P3;
Oriented_side operator() (const Weighted_point &p0,
const Weighted_point &p) const
{
Oriented_side result = P3::operator()(p0, p);
if (result == 0) ++degeneracy_counter;
return result;
}
Oriented_side operator() (const Weighted_point &p0,
const Weighted_point &p1,
const Weighted_point &p) const
{
Oriented_side result = P3::operator()(p0, p1, p);
if (result == 0) ++degeneracy_counter;
return result;
}
Oriented_side operator() (const Weighted_point &p0,
const Weighted_point &p1,
const Weighted_point &p2,
const Weighted_point &p) const
{
Oriented_side result = P3::operator()(p0, p1, p2, p);
if (result == 0) ++degeneracy_counter;
return result;
}
Oriented_side operator() (const Weighted_point &p0,
const Weighted_point &p1,
const Weighted_point &p2,
const Weighted_point &p3,
const Weighted_point &p) const
{
Oriented_side result = P3::operator()(p0, p1, p2, p3, p);
if (result == 0) ++degeneracy_counter;
return result;
}
};
Power_side_of_oriented_power_sphere_3 power_side_of_oriented_power_sphere_3_object() const
{ return Power_side_of_oriented_power_sphere_3(); }
};
// Explicit instantiation of the whole class :
template class CGAL::Regular_triangulation_3<traits>;
typedef CGAL::Regular_triangulation_3<traits> Cls;
typedef K::Point_3 Point;
typedef K::Weighted_point_3 Weighted_point;
typedef Cls::Vertex_handle Vertex_handle;
// We don't want to use compare_xyz because it thinks two weighted points
// located at the same place with different weights are identical.
struct less_xyzw
{
bool operator() (const Weighted_point &p,
const Weighted_point &q) const
{
if (p.x() < q.x()) return true;
if (p.x() > q.x()) return false;
if (p.y() < q.y()) return true;
if (p.y() > q.y()) return false;
if (p.z() < q.z()) return true;
if (p.z() > q.z()) return false;
if (p.weight() < q.weight()) return true;
return false;
}
};
typedef std::set<Weighted_point,less_xyzw> point_set;
typedef point_set::iterator set_iterator;
// Base class for a weighted point generator.
class point_iterator
{
Weighted_point _wp;
int _i;
public:
point_iterator (int i = 0) : _i (i) {}
void operator++ () { --_i; }
const Weighted_point &operator* () const { return _wp; }
bool operator== (const point_iterator &i) const { return _i == i._i; }
bool operator!= (const point_iterator &i) const { return ! (*this == i); }
protected:
void set_point (int x, int y, int z, int w)
{
_wp = Weighted_point (Point (x, y, z), w);
}
};
static boost::minstd_rand randgen;
// point_iterator_x generates points randomly on a grid (thus making lots of
// degenerate cases), staying in dimension x.
struct point_iterator_0 : public point_iterator
{
point_iterator_0 () {}
point_iterator_0 (int i) : point_iterator(i + 1) { ++*this; }
void operator++ ()
{
int w = randgen() % 10;
set_point (0, 0, 0, w);
point_iterator::operator++();
}
};
struct point_iterator_1 : public point_iterator
{
point_iterator_1 () {}
point_iterator_1 (int i) : point_iterator(i + 1) { ++*this; }
void operator++ ()
{
int x = randgen() % 10;
int w = randgen() % 10;
set_point (x, 0, 0, w);
point_iterator::operator++();
}
};
struct point_iterator_2 : public point_iterator
{
point_iterator_2 () {}
point_iterator_2 (int i) : point_iterator(i + 1) { ++*this; }
void operator++ ()
{
int x = randgen() % 10;
int y = randgen() % 10;
int w = randgen() % 10;
set_point (x, y, 0, w);
point_iterator::operator++();
}
};
struct point_iterator_3 : public point_iterator
{
point_iterator_3 () {}
point_iterator_3 (int i) : point_iterator(i + 1) { ++*this; }
void operator++ ()
{
int x = randgen() % 10;
int y = randgen() % 10;
int z = randgen() % 10;
int w = randgen() % 10;
set_point (x, y, z, w);
point_iterator::operator++();
}
};
class point_reader
{
std::istream *in;
Weighted_point wp;
int nb;
public:
point_reader () : in (nullptr), wp(), nb(0) {}
point_reader (std::istream &is) : in(&is)
{
if (*in >> nb) {
++nb;
++*this;
} else
nb = 0;
}
point_reader &operator++ ()
{
if (nb > 0) {
--nb;
if (nb > 0) *in >> wp;
}
return *this;
}
bool operator== (const point_reader& p) const { return nb == p.nb; }
bool operator!= (const point_reader& p) const { return nb != p.nb; }
const Weighted_point &operator*() const { return wp; }
};
// Inserts number points in the triangulation and the multiset, using PI as the
// point generator.
template < class PI >
void insert_points (Cls &T, point_set &points, int number)
{
int i = 1;
for (PI pi (number), pend; pi != pend; ++pi, ++i) {
points.insert (*pi);
T.insert (*pi);
std::cout << "\r number of inserted points: " << i << std::flush;
}
std::cout << std::endl;
assert(T.is_valid());
std::cout << " number of vertices: " << T.number_of_vertices()
<< std::endl;
std::cout << " number of degeneracies: " << degeneracy_counter << std::endl;
degeneracy_counter = 0;
}
// Removes number points from T, and removes each one from points also.
// Checks that each point of T that is removed exists in points.
void remove (Cls &T, point_set &points, int number)
{
for (int i = 1; !points.empty(); ++i)
{
number--;
assert(T.number_of_vertices() != 0);
Vertex_handle v = T.finite_vertices_begin();
set_iterator pos = points.find (v->point());
assert(pos != points.end());
T.remove (v);
points.erase (pos);
std::cout << "\r number of removed points: " << i << std::flush;
}
std::cout << std::endl;
assert(number >= 0);
assert(T.number_of_vertices() == 0);
assert(T.is_valid());
assert(points.empty());
std::cout << " number of degeneracies: " << degeneracy_counter << std::endl;
degeneracy_counter = 0;
}
// Adds p which is supposed to increase the dimension of T from dim to dim+1,
// then removes it.
void dim_jump (Cls &T, const Point &p, int dim)
{
assert(T.dimension() == dim);
Vertex_handle v = T.insert (Weighted_point (p, 0));
assert(T.is_valid());
assert(v != Vertex_handle());
assert(T.dimension() == dim + 1);
T.remove (v);
assert(T.is_valid());
assert(T.dimension() == dim);
}
bool test_case (std::istream &is)
{
point_reader pi (is), pend;
if (pi == pend) return false;
point_set points;
Cls T;
do {
points.insert (*pi);
T.insert (*pi);
} while (++pi != pend);
assert(T.is_valid());
while(! points.empty()) {
assert(T.number_of_vertices() != 0);
Vertex_handle v = T.finite_vertices_begin();
set_iterator pos = points.find (v->point());
assert(pos != points.end());
T.remove (v);
points.erase(pos);
}
assert(T.number_of_vertices() == 0);
assert(points.empty());
return true;
}
int main(int argc, char **argv)
{
// Test various data sets that crashed the code at some point in the past.
// File format is:
// number of points of first data set
// point
// ...
// number of points of second data set
// point
// ...
{
std::ifstream fin ("data/regular_remove_3");
assert(fin);
std:: cout << " test `data/regular_remove_3'" << std::endl;
while (test_case (fin))
// semicolon
;
}
// Hardcoded seeds so that the test-suite is deterministic.
std::int32_t seed0 = 42, seed1 = 43, seed2 = 42, seed3 = 42;
// You can also pass seeds on the command line.
if (argc > 1) { std::istringstream iss(argv[1]); iss >>seed0; }
if (argc > 2) { std::istringstream iss(argv[2]); iss >>seed1; }
if (argc > 3) { std::istringstream iss(argv[3]); iss >>seed2; }
if (argc > 4) { std::istringstream iss(argv[4]); iss >>seed3; }
Cls T;
point_set points;
degeneracy_counter = 0;
std::cout << " test dimension 0" << std::endl;
randgen.seed(seed0);
insert_points<point_iterator_0> (T, points, 10);
dim_jump (T, Point (0, 0, 1), 0);
remove (T, points, 10);
std::cout << " test dimension 1" << std::endl;
randgen.seed(seed1);
insert_points<point_iterator_1> (T, points, 20);
dim_jump (T, Point (0, 0, 1), 1);
remove (T, points, 20);
std::cout << " test dimension 2" << std::endl;
randgen.seed(seed2);
insert_points<point_iterator_2> (T, points, 100);
dim_jump (T, Point (0, 0, 1), 2);
remove (T, points, 100);
std::cout << " test dimension 3" << std::endl;
randgen.seed(seed3);
insert_points<point_iterator_3> (T, points, 500);
assert(T.dimension() == 3);
remove (T, points, 500);
std::cout << " quit" << std::endl;
return 0;
}