dust3d/thirdparty/cgal/CGAL-5.1/include/CGAL/Triangulation.h

1434 lines
47 KiB
C++

// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL: https://github.com/CGAL/cgal/blob/v5.1/Triangulation/include/CGAL/Triangulation.h $
// $Id: Triangulation.h f8fd7a6 2020-04-18T13:53:46+02:00 Marc Glisse
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Samuel Hornus
#ifndef CGAL_TRIANGULATION_H
#define CGAL_TRIANGULATION_H
#include <CGAL/license/Triangulation.h>
#include <CGAL/disable_warnings.h>
#include <CGAL/internal/Triangulation/utilities.h>
#include <CGAL/Triangulation_data_structure.h>
#include <CGAL/Triangulation_full_cell.h>
#include <CGAL/Triangulation_vertex.h>
#include <CGAL/Iterator_project.h>
#include <CGAL/spatial_sort.h>
#include <CGAL/Dimension.h>
#include <CGAL/iterator.h>
#include <CGAL/Default.h>
#include <CGAL/Random.h>
#include <boost/container/small_vector.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <CGAL/boost/iterator/transform_iterator.hpp>
namespace CGAL {
// Iterator which iterates over vertex_handle's, but returns a point when
// dereferenced. If the current
// vertex_handle vh == vh_where_point_should_be_substituted, it returns
// "subtitute_point", otherwise, it returns vh->point()
template<class VertexHandleConstIter>
class Substitute_point_in_vertex_iterator
{
typedef typename std::iterator_traits<VertexHandleConstIter>::value_type Vertex_handle;
typedef typename Vertex_handle::value_type Vertex;
typedef typename Vertex::Point Point;
public:
typedef Point const& result_type; // For result_of
Substitute_point_in_vertex_iterator(
Vertex_handle vh_where_point_should_be_substituted,
Point const *subtitute_point)
: vh_where_point_should_be_substituted_(vh_where_point_should_be_substituted)
, subtitute_point_(subtitute_point)
{}
result_type operator()(Vertex_handle vh) const
{
if (vh == vh_where_point_should_be_substituted_)
return *subtitute_point_;
else
return vh->point();
}
private:
Vertex_handle vh_where_point_should_be_substituted_;
Point const *subtitute_point_;
};
template < class TriangulationTraits, class TDS_ = Default >
class Triangulation
{
typedef typename TriangulationTraits::Dimension Maximal_dimension_;
typedef typename Default::Get<TDS_, Triangulation_data_structure
< Maximal_dimension_,
Triangulation_vertex<TriangulationTraits>,
Triangulation_full_cell<TriangulationTraits> >
>::type TDS;
typedef Triangulation<TriangulationTraits, TDS_> Self;
protected:
typedef typename TriangulationTraits::Flat_orientation_d Flat_orientation_d;
typedef typename TriangulationTraits::Construct_flat_orientation_d Construct_flat_orientation_d;
typedef typename TriangulationTraits::In_flat_orientation_d In_flat_orientation_d;
// Wrapper
struct Coaffine_orientation_d
{
boost::optional<Flat_orientation_d>* fop;
Construct_flat_orientation_d cfo;
In_flat_orientation_d ifo;
Coaffine_orientation_d(
boost::optional<Flat_orientation_d>& x,
Construct_flat_orientation_d const&y,
In_flat_orientation_d const&z)
: fop(&x), cfo(y), ifo(z) {}
template<class Iter>
CGAL::Orientation operator()(Iter a, Iter b) const
{
if (*fop)
return ifo(fop->get(),a,b);
*fop = cfo(a,b);
CGAL_assertion(ifo(fop->get(),a,b) == CGAL::POSITIVE);
return CGAL::POSITIVE;
}
};
void reset_flat_orientation()
{
if (current_dimension() == preset_flat_orientation_.first)
{
CGAL_assertion(preset_flat_orientation_.second != nullptr);
flat_orientation_ = *preset_flat_orientation_.second;
}
else
flat_orientation_ = boost::none;
}
typedef typename TriangulationTraits::Orientation_d
Orientation_d;
public:
typedef TriangulationTraits Geom_traits;
typedef TDS Triangulation_ds;
typedef typename TDS::Vertex Vertex;
typedef typename TDS::Full_cell Full_cell;
typedef typename TDS::Facet Facet;
typedef typename TDS::Face Face;
typedef typename TDS::Vertex::Point Point;
typedef Maximal_dimension_ Maximal_dimension;
typedef typename TDS::Vertex_handle Vertex_handle;
typedef typename TDS::Vertex_iterator Vertex_iterator;
typedef typename TDS::Vertex_const_handle Vertex_const_handle;
typedef typename TDS::Vertex_const_iterator Vertex_const_iterator;
typedef typename TDS::Full_cell_handle Full_cell_handle;
typedef typename TDS::Full_cell_iterator Full_cell_iterator;
typedef typename TDS::Full_cell_const_handle Full_cell_const_handle;
typedef typename TDS::Full_cell_const_iterator Full_cell_const_iterator;
typedef typename TDS::Facet_iterator Facet_iterator;
typedef typename TDS::size_type size_type;
typedef typename TDS::difference_type difference_type;
/// The type of location a new point is found lying on
enum Locate_type
{
ON_VERTEX = 0 // simplex of dimension 0
, IN_FACE = 1 // simplex of dimension in [ 1, |current_dimension()| - 2 ]
, IN_FACET = 2 // simplex of dimension |current_dimension()| - 1
, IN_FULL_CELL = 3 /// simplex of dimension |current_dimension()|
, OUTSIDE_CONVEX_HULL = 4
, OUTSIDE_AFFINE_HULL = 5
};
// Finite elements iterators
class Finiteness_predicate;
typedef boost::filter_iterator<Finiteness_predicate, Vertex_iterator>
Finite_vertex_iterator;
typedef boost::filter_iterator<Finiteness_predicate, Vertex_const_iterator>
Finite_vertex_const_iterator;
typedef boost::filter_iterator<Finiteness_predicate, Full_cell_iterator>
Finite_full_cell_iterator;
typedef boost::filter_iterator<Finiteness_predicate, Full_cell_const_iterator>
Finite_full_cell_const_iterator;
typedef boost::filter_iterator<Finiteness_predicate, Facet_iterator>
Finite_facet_iterator;
//Tag to distinguish Delaunay from regular triangulations
typedef Tag_false Weighted_tag;
// Tag to distinguish periodic triangulations from others
typedef Tag_false Periodic_tag;
protected: // DATA MEMBERS
Triangulation_ds tds_;
const Geom_traits kernel_;
Vertex_handle infinity_;
mutable boost::optional<Flat_orientation_d> flat_orientation_;
// The user can specify a Flat_orientation_d object to be used for
// orienting simplices of a specific dimension
// (= preset_flat_orientation_.first)
// preset_flat_orientation_.first = numeric_limits<int>::max() otherwise)
std::pair<int, const Flat_orientation_d *> preset_flat_orientation_;
// for stochastic walk in the locate() function:
mutable Random rng_;
#ifdef CGAL_TRIANGULATION_STATISTICS
mutable unsigned long walk_size_;
#endif
protected: // HELPER FUNCTIONS
typedef CGAL::Iterator_project<
typename Full_cell::Vertex_handle_const_iterator,
internal::Triangulation::Point_from_vertex_handle<Vertex_handle, Point>
> Point_const_iterator;
Point_const_iterator points_begin(Full_cell_const_handle c) const
{ return Point_const_iterator(c->vertices_begin()); }
Point_const_iterator points_end(Full_cell_const_handle c) const
{ return Point_const_iterator(c->vertices_end()); }
Point_const_iterator points_begin(Full_cell_handle c) const
{ return Point_const_iterator(c->vertices_begin()); }
Point_const_iterator points_end(Full_cell_handle c) const
{ return Point_const_iterator(c->vertices_end()); }
public:
// FACETS OPERATIONS
Full_cell_handle full_cell(const Facet & f) const
{
return tds().full_cell(f);
}
int index_of_covertex(const Facet & f) const
{
return tds().index_of_covertex(f);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UTILITIES
// A co-dimension 2 sub-simplex. called a Rotor because we can rotate
// the two "covertices" around the sub-simplex. Useful for traversing the
// boundary of a hole. NOT DOCUMENTED
typedef std::tuple<Full_cell_handle, int, int> Rotor;
// Commented out because it was causing "internal compiler error" in MSVC
/*Full_cell_handle full_cell(const Rotor & r) const // NOT DOCUMENTED
{
return std::get<0>(r);
}
int index_of_covertex(const Rotor & r) const // NOT DOCUMENTED
{
return std::get<1>(r);
}
int index_of_second_covertex(const Rotor & r) const // NOT DOCUMENTED
{
return std::get<2>(r);
}*/
Rotor rotate_rotor(Rotor & r) // NOT DOCUMENTED...
{
int opposite = std::get<0>(r)->mirror_index(std::get<1>(r));
Full_cell_handle s = std::get<0>(r)->neighbor(std::get<1>(r));
int new_second = s->index(std::get<0>(r)->vertex(std::get<2>(r)));
return Rotor(s, new_second, opposite);
}
// - - - - - - - - - - - - - - - - - - - - - - - - CREATION / CONSTRUCTORS
Triangulation(int dim, const Geom_traits &k = Geom_traits())
: tds_(dim)
, kernel_(k)
, infinity_()
, preset_flat_orientation_((std::numeric_limits<int>::max)(),
(Flat_orientation_d*) nullptr)
, rng_((long)0)
#ifdef CGAL_TRIANGULATION_STATISTICS
,walk_size_(0)
#endif
{
clear();
}
// With this constructor,
// the user can specify a Flat_orientation_d object to be used for
// orienting simplices of a specific dimension
// (= preset_flat_orientation_.first)
// It it used for by dark triangulations created by DT::remove
Triangulation(
int dim,
const std::pair<int, const Flat_orientation_d *> &preset_flat_orientation,
const Geom_traits k = Geom_traits())
: tds_(dim)
, kernel_(k)
, infinity_()
, preset_flat_orientation_(preset_flat_orientation)
, rng_((long)0)
#ifdef CGAL_TRIANGULATION_STATISTICS
,walk_size_(0)
#endif
{
clear();
}
Triangulation(const Triangulation & t2)
: tds_(t2.tds_)
, kernel_(t2.kernel_)
, infinity_()
, preset_flat_orientation_((std::numeric_limits<int>::max)(),
(Flat_orientation_d*) nullptr)
, rng_(t2.rng_)
#ifdef CGAL_TRIANGULATION_STATISTICS
,walk_size_(t2.walk_size_)
#endif
{
// We find the vertex at infinity by scanning the vertices of both
// triangulations. This works because Compact_container guarantees that
// the vertices in the copy (*this) are stored in the same order as in
// the original triangulation (t2)
infinity_ = vertices_begin();
Vertex_const_iterator inf2 = t2.vertices_begin();
while( inf2 != t2.infinite_vertex() )
{
++infinity_;
++inf2;
}
// Our coaffine orientation predicates HAS state member variables
reset_flat_orientation();
}
~Triangulation() {}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ACCESS FUNCTIONS
/* These three function are no longer needed since we do not use them anymore
in the Delaunay_triangulation::remove. *But*, they may reappear in the future
if we manage to passe the information that flags/TDS_data is available or not
for marking simplices in Delaunay_triangulation::remove. This would be useful
to make it a little faster, instead of binary searching if a simplex is marked
or not...
// NOT DOCUMENTED --
bool get_visited(Full_cell_handle s) const
{
return tds().get_visited(s);
}
// NOT DOCUMENTED --
bool get_visited(Full_cell_const_handle s) const
{
return tds().get_visited(s);
}
// NOT DOCUMENTED --
void set_visited(Full_cell_handle s, bool b) const
{
tds().set_visited(s, b);
} */
Coaffine_orientation_d coaffine_orientation_predicate() const
{
return Coaffine_orientation_d (
flat_orientation_,
geom_traits().construct_flat_orientation_d_object(),
geom_traits().in_flat_orientation_d_object()
);
}
const Triangulation_ds & tds() const
{
return tds_;
}
Triangulation_ds & tds()
{
return tds_;
}
const Geom_traits & geom_traits() const
{
return kernel_;
}
int maximal_dimension() const { return tds().maximal_dimension(); }
int current_dimension() const { return tds().current_dimension(); }
bool empty() const
{
return current_dimension() == -1;
}
size_type number_of_vertices() const
{
return tds().number_of_vertices() - 1;
}
size_type number_of_full_cells() const
{
return tds().number_of_full_cells();
}
Vertex_handle infinite_vertex() const
{
return infinity_;
}
Full_cell_handle infinite_full_cell() const
{
CGAL_assertion(infinite_vertex()->full_cell()->has_vertex(infinite_vertex()));
return infinite_vertex()->full_cell();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - NON CONSTANT-TIME ACCESS FUNCTIONS
size_type number_of_finite_full_cells() const
{
Full_cell_const_iterator s = full_cells_begin();
size_type result = number_of_full_cells();
for( ; s != full_cells_end(); ++s )
{
if( is_infinite(s) )
--result;
}
return result;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TRAVERSAL
Vertex_iterator vertices_begin() { return tds().vertices_begin(); }
Vertex_iterator vertices_end() { return tds().vertices_end(); }
Vertex_const_iterator vertices_begin() const { return tds().vertices_begin(); }
Vertex_const_iterator vertices_end() const { return tds().vertices_end(); }
Finite_vertex_iterator finite_vertices_begin()
{ return Finite_vertex_iterator(Finiteness_predicate(*this), vertices_begin(), vertices_end()); }
Finite_vertex_iterator finite_vertices_end()
{ return Finite_vertex_iterator(Finiteness_predicate(*this), vertices_end(), vertices_end()); }
Finite_vertex_const_iterator finite_vertices_begin() const
{ return Finite_vertex_const_iterator(Finiteness_predicate(*this), vertices_begin(), vertices_end()); }
Finite_vertex_const_iterator finite_vertices_end() const
{ return Finite_vertex_const_iterator(Finiteness_predicate(*this), vertices_end(), vertices_end()); }
Full_cell_iterator full_cells_begin() { return tds().full_cells_begin(); }
Full_cell_iterator full_cells_end() { return tds().full_cells_end(); }
Full_cell_const_iterator full_cells_begin() const { return tds().full_cells_begin(); }
Full_cell_const_iterator full_cells_end() const { return tds().full_cells_end(); }
Finite_full_cell_iterator finite_full_cells_begin()
{ return Finite_full_cell_iterator(Finiteness_predicate(*this), full_cells_begin(), full_cells_end()); }
Finite_full_cell_iterator finite_full_cells_end()
{ return Finite_full_cell_iterator(Finiteness_predicate(*this), full_cells_end(), full_cells_end()); }
Finite_full_cell_const_iterator finite_full_cells_begin() const
{ return Finite_full_cell_const_iterator(Finiteness_predicate(*this), full_cells_begin(), full_cells_end()); }
Finite_full_cell_const_iterator finite_full_cells_end() const
{ return Finite_full_cell_const_iterator(Finiteness_predicate(*this), full_cells_end(), full_cells_end()); }
Facet_iterator facets_begin() { return tds().facets_begin(); }
Facet_iterator facets_end() { return tds().facets_end(); }
Finite_facet_iterator finite_facets_begin()
{ return Finite_facet_iterator(Finiteness_predicate(*this), facets_begin(), facets_end()); }
Finite_facet_iterator finite_facets_end()
{ return Finite_facet_iterator(Finiteness_predicate(*this), facets_end(), facets_end()); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SOME PREDICATE FUNCTORS
class Finiteness_predicate
{
const Self & t_;
public:
Finiteness_predicate(const Self & t) : t_(t) {}
template < class T >
bool operator()(const T & t) const
{
return ! t_.is_infinite(t);
}
};
class Point_equality_predicate
{
const Point & o_;
public:
Point_equality_predicate(const Point & o) : o_(o) {}
bool operator()(const Point & o) const { return (o == o_ );}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SIMPLE QUERIES
/*
bool is_vertex(const Point & p, Vertex_handle & v, Full_cell_handle hint = Full_cell_handle()) const
{
Locate_type lt;
Face f(maximal_dimension());
Facet ft;
Full_cell_handle s = locate(p, lt, f, ft, hint);
if( ON_VERTEX == lt )
{
v = s->vertex(f.index(0));
return true;
}
return false;
}
bool is_vertex(Vertex_const_handle v) const
{
return tds().is_vertex(v);
}
bool is_full_cell(Full_cell_const_handle s) const
{
return tds().is_full_cell(s);
}
*/
bool is_infinite(Vertex_const_handle v) const
{
CGAL_precondition(Vertex_const_handle() != v);
return (infinite_vertex() == v);
}
bool is_infinite(const Vertex & v) const /* internal use, not documented */
{
return (&(*infinite_vertex()) == &v);
}
bool is_infinite(Full_cell_const_handle s) const
{
CGAL_precondition(Full_cell_const_handle() != s);
return is_infinite(*s);
}
bool is_infinite(const Full_cell & s) const /* internal use, not documented */
{
for(int i = 0; i <= current_dimension(); ++i)
if( is_infinite(s.vertex(i)) )
return true;
return false;
}
bool is_infinite(const Facet & ft) const
{
Full_cell_const_handle s = full_cell(ft);
CGAL_precondition(s != Full_cell_const_handle());
if( is_infinite(s) )
return (s->vertex(index_of_covertex(ft)) != infinite_vertex());
return false;
}
bool is_infinite(const Face & f) const
{
Full_cell_const_handle s = f.full_cell();
CGAL_precondition(s != Full_cell_const_handle());
if( is_infinite(s) )
{
Vertex_handle v;
for( int i(0); i<= f.face_dimension(); ++i)
if ( is_infinite( f.vertex(i) )) return true;
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ELEMENT GATHERING
template< typename OutputIterator >
OutputIterator incident_full_cells(const Face & f, OutputIterator out) const
{
return tds().incident_full_cells(f, out);
}
template< typename OutputIterator >
OutputIterator incident_full_cells(Vertex_const_handle v, OutputIterator out) const
{
return tds().incident_full_cells(v, out);
}
template< typename OutputIterator >
OutputIterator star(const Face & f, OutputIterator out) const
{
return tds().star(f, out);
}
template< typename OutputIterator >
OutputIterator incident_faces(Vertex_const_handle v, int d, OutputIterator out) const
{
return tds().incident_faces(v, d, out);
}
/*
template< typename OutputIterator, class Comparator >
OutputIterator incident_upper_faces( Vertex_const_handle v, int d,
OutputIterator out, Comparator cmp = Comparator())
{
return tds().incident_upper_faces(v, d, out, cmp);
}
template< typename OutputIterator >
OutputIterator incident_upper_faces( Vertex_const_handle v, int d,
OutputIterator out)
{ // FIXME: uncomment this function, since it uses a comparator specific to
// *geometric* triangulation (taking infinite vertex into account)
internal::Triangulation::Compare_vertices_for_upper_face<Self> cmp(*this);
return tds().incident_upper_faces(v, d, out, cmp);
}
*/
Orientation orientation(Full_cell_const_handle s, bool in_is_valid = false) const
{
if( ! in_is_valid )
CGAL_assertion( ! is_infinite(s) );
if( 0 == current_dimension() )
return POSITIVE;
if( current_dimension() == maximal_dimension() )
{
Orientation_d ori = geom_traits().orientation_d_object();
return ori(points_begin(s), points_begin(s) + 1 + current_dimension());
}
else
{
return coaffine_orientation_predicate()(points_begin(s), points_begin(s) + 1 + current_dimension());
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UPDATE OPERATIONS
void clear()
{
tds_.clear();
infinity_ = tds().insert_increase_dimension();
// Our coaffine orientation predicates HAS state member variables
reset_flat_orientation();
#ifdef CGAL_TRIANGULATION_STATISTICS
walk_size_ = 0;
#endif
}
void set_current_dimension(int d)
{
tds().set_current_dimension(d);
}
Full_cell_handle new_full_cell()
{
return tds().new_full_cell();
}
Vertex_handle new_vertex()
{
return tds().new_vertex();
}
Vertex_handle new_vertex(const Point & p)
{
return tds().new_vertex(p);
}
void set_neighbors(Full_cell_handle s, int i, Full_cell_handle s1, int j)
{
tds().set_neighbors(s, i, s1, j);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VALIDITY
bool is_valid(bool = false, int = 0) const;
bool are_incident_full_cells_valid(Vertex_const_handle, bool = false, int = 0) const;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - POINT LOCATION
protected:
template< typename OrientationPredicate >
Full_cell_handle do_locate(const Point &, Locate_type &, Face &, Facet &,
Full_cell_handle start,
const OrientationPredicate & o) const;
public:
Full_cell_handle locate(const Point &, Locate_type &, Face &, Facet &,
Full_cell_handle start = Full_cell_handle()) const;
Full_cell_handle locate(const Point &, Locate_type &, Face &, Facet &,
Vertex_handle) const;
Full_cell_handle locate(const Point & p, Full_cell_handle s = Full_cell_handle()) const;
Full_cell_handle locate(const Point & p, Vertex_handle v) const;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - REMOVALS
Vertex_handle contract_face(const Point &, const Face &);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - POINT INSERTION
template< typename ForwardIterator >
size_type insert(ForwardIterator start, ForwardIterator end)
{
size_type n = number_of_vertices();
std::vector<Point> points(start, end);
spatial_sort(points.begin(), points.end(), geom_traits());
Full_cell_handle hint = Full_cell_handle();
typename std::vector<Point>::const_iterator s = points.begin();
while( s != points.end() )
{
hint = insert(*s++, hint)->full_cell();
}
return number_of_vertices() - n;
}
Vertex_handle insert(const Point &, Locate_type, const Face &, const Facet &, Full_cell_handle);
Vertex_handle insert(const Point &, Full_cell_handle start = Full_cell_handle());
Vertex_handle insert(const Point &, Vertex_handle);
template< typename ForwardIterator >
Vertex_handle insert_in_hole(const Point & p, ForwardIterator start, ForwardIterator end, const Facet & ft)
{
Emptyset_iterator out;
return insert_in_hole(p, start, end, ft, out);
}
template< typename ForwardIterator, typename OutputIterator >
Vertex_handle insert_in_hole(const Point & p, ForwardIterator start, ForwardIterator end, const Facet & ft,
OutputIterator out)
{
Vertex_handle v = tds().insert_in_hole(start, end, ft, out);
v->set_point(p);
return v;
}
Vertex_handle insert_in_face(const Point &, const Face &);
Vertex_handle insert_in_facet(const Point &, const Facet &);
Vertex_handle insert_in_full_cell(const Point &, Full_cell_handle);
Vertex_handle insert_outside_convex_hull_1(const Point &, Full_cell_handle);
Vertex_handle insert_outside_convex_hull(const Point &, Full_cell_handle);
Vertex_handle insert_outside_affine_hull(const Point &);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - FACET-TRAVERSAL PREDICATES
template< typename OrientationPredicate >
class Outside_convex_hull_traversal_predicate
{
Triangulation & t_;
const Point & p_;
OrientationPredicate const& ori_;
int cur_dim_;
public:
Outside_convex_hull_traversal_predicate(Triangulation & t, const Point & p,
OrientationPredicate const& ori)
: t_(t), p_(p), ori_(ori), cur_dim_(t.current_dimension()) {}
// FUTURE change parameter to const reference
bool operator()(Facet f) const
{
Full_cell_handle s = t_.full_cell(f);
const int i = t_.index_of_covertex(f);
Full_cell_handle n = s->neighbor(i);
if( ! t_.is_infinite(n) )
return false;
int inf_v_index = n->index(t_.infinite_vertex());
n->vertex(inf_v_index)->set_point(p_);
bool ok = (POSITIVE == ori_(t_.points_begin(n), t_.points_begin(n) + cur_dim_ + 1));
return ok;
}
};
// make sure all full_cells have positive orientation
void reorient_full_cells();
protected:
// This is used in the |remove(v)| member function to manage sets of Full_cell_handles
template< typename FCH >
struct Full_cell_set : public std::vector<FCH>
{
typedef std::vector<FCH> Base_set;
using Base_set::begin;
using Base_set::end;
void make_searchable()
{ // sort the full cell handles
std::sort(begin(), end());
}
bool contains(const FCH & fch) const
{
return std::binary_search(begin(), end(), fch);
}
bool contains_1st_and_not_2nd(const FCH & fst, const FCH & snd) const
{
return ( ! contains(snd) ) && ( contains(fst) );
}
};
void display_all_full_cells__debugging() const
{
std::cerr << "ALL FULL CELLS:" << std::endl;
for (Full_cell_const_iterator cit = full_cells_begin() ;
cit != full_cells_end() ; ++cit )
{
std::cerr << std::hex << &*cit << ": ";
for (int jj = 0 ; jj <= current_dimension() ; ++jj)
std::cerr << (is_infinite(cit->vertex(jj)) ? 0xFFFFFFFF : (unsigned int)&*cit->vertex(jj)) << " - ";
std::cerr << std::dec << std::endl;
}
std::cerr << std::endl;
}
}; // Triangulation<...>
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// CLASS MEMBER FUNCTIONS
template < class TT, class TDS >
void
Triangulation<TT, TDS>
::reorient_full_cells()
{
if( current_dimension() < 1 )
return;
Full_cell_iterator sit = full_cells_begin();
Full_cell_iterator send = full_cells_end();
for ( ; sit != send ; ++sit)
{
if( ! (is_infinite(sit) && (1 == current_dimension())) )
{
sit->swap_vertices(current_dimension() - 1, current_dimension());
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - THE REMOVAL METHODS
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Vertex_handle
Triangulation<TT, TDS>
::contract_face(const Point & p, const Face & f)
{
CGAL_precondition( ! is_infinite(f) );
Vertex_handle v = tds().contract_face(f);
v->set_point(p);
CGAL_expensive_postcondition_msg(are_incident_full_cells_valid(v), "new point is not where it should be");
return v;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - THE INSERTION METHODS
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Vertex_handle
Triangulation<TT, TDS>
::insert(const Point & p, Locate_type lt, const Face & f, const Facet & ft, Full_cell_handle s)
{
switch( lt )
{
case IN_FULL_CELL:
return insert_in_full_cell(p, s);
break;
case OUTSIDE_CONVEX_HULL:
return insert_outside_convex_hull(p, s);
break;
case OUTSIDE_AFFINE_HULL:
return insert_outside_affine_hull(p);
break;
case IN_FACET:
{
return insert_in_facet(p, ft);
break;
}
case IN_FACE:
return insert_in_face(p, f);
break;
case ON_VERTEX:
s->vertex(f.index(0))->set_point(p);
return s->vertex(f.index(0));
break;
}
CGAL_assertion(false);
return Vertex_handle();
}
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Vertex_handle
Triangulation<TT, TDS>
::insert(const Point & p, Full_cell_handle start)
{
Locate_type lt;
Face f(maximal_dimension());
Facet ft;
Full_cell_handle s = locate(p, lt, f, ft, start);
return insert(p, lt, f, ft, s);
}
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Vertex_handle
Triangulation<TT, TDS>
::insert(const Point & p, Vertex_handle v)
{
if( Vertex_handle() == v )
v = infinite_vertex();
return insert(p, v->full_cell());
}
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Vertex_handle
Triangulation<TT, TDS>
::insert_in_face(const Point & p, const Face & f)
{
CGAL_precondition( ! is_infinite(f) );
Vertex_handle v = tds().insert_in_face(f);
v->set_point(p);
return v;
}
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Vertex_handle
Triangulation<TT, TDS>
::insert_in_facet(const Point & p, const Facet & ft)
{
CGAL_precondition( ! is_infinite(ft) );
Vertex_handle v = tds().insert_in_facet(ft);
v->set_point(p);
return v;
}
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Vertex_handle
Triangulation<TT, TDS>
::insert_in_full_cell(const Point & p, Full_cell_handle s)
{
CGAL_precondition( ! is_infinite(s) );
Vertex_handle v = tds().insert_in_full_cell(s);
v->set_point(p);
return v;
}
// NOT DOCUMENTED...
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Vertex_handle
Triangulation<TT, TDS>
::insert_outside_convex_hull_1(const Point & p, Full_cell_handle s)
{
// This is a special case for dimension 1, because in that case, the right
// infinite full_cell is not correctly oriented... (sice its first vertex is the
// infinite one...
CGAL_precondition( is_infinite(s) );
CGAL_precondition( 1 == current_dimension() );
Vertex_handle v = tds().insert_in_full_cell(s);
v->set_point(p);
return v;
}
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Vertex_handle
Triangulation<TT, TDS>
::insert_outside_convex_hull(const Point & p, Full_cell_handle s)
{
if( 1 == current_dimension() )
{
return insert_outside_convex_hull_1(p, s);
}
CGAL_precondition( is_infinite(s) );
CGAL_assertion( current_dimension() >= 2 );
std::vector<Full_cell_handle> simps;
simps.reserve(64);
std::back_insert_iterator<std::vector<Full_cell_handle> > out(simps);
if( current_dimension() < maximal_dimension() )
{
Coaffine_orientation_d ori = coaffine_orientation_predicate();
Outside_convex_hull_traversal_predicate<Coaffine_orientation_d>
ochtp(*this, p, ori);
tds().gather_full_cells(s, ochtp, out);
}
else
{
Orientation_d ori = geom_traits().orientation_d_object();
Outside_convex_hull_traversal_predicate<Orientation_d>
ochtp(*this, p, ori);
tds().gather_full_cells(s, ochtp, out);
}
int inf_v_index = s->index(infinite_vertex());
Vertex_handle v = insert_in_hole(
p, simps.begin(), simps.end(), Facet(s, inf_v_index));
return v;
}
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Vertex_handle
Triangulation<TT, TDS>
::insert_outside_affine_hull(const Point & p)
{
CGAL_precondition( current_dimension() < maximal_dimension() );
Vertex_handle v = tds().insert_increase_dimension(infinite_vertex());
// reset the orientation predicate:
reset_flat_orientation();
v->set_point(p);
if( current_dimension() >= 1 )
{
Full_cell_handle inf_v_cell = infinite_vertex()->full_cell();
int inf_v_index = inf_v_cell->index(infinite_vertex());
Full_cell_handle s = inf_v_cell->neighbor(inf_v_index);
Orientation o = orientation(s);
CGAL_assertion( COPLANAR != o );
if( NEGATIVE == o )
reorient_full_cells();
// We just inserted the second finite point and the right infinite
// cell is like : (inf_v, v), but we want it to be (v, inf_v) to be
// consistent with the rest of the cells
if (current_dimension() == 1)
{
// Is "inf_v_cell" the right infinite cell?
// Then inf_v_index should be 1
if (inf_v_cell->neighbor(inf_v_index)->index(inf_v_cell) == 0
&& inf_v_index == 0)
{
inf_v_cell->swap_vertices(
current_dimension() - 1, current_dimension());
}
// Otherwise, let's find the right infinite cell
else
{
inf_v_cell = inf_v_cell->neighbor((inf_v_index + 1) % 2);
inf_v_index = inf_v_cell->index(infinite_vertex());
// Is "inf_v_cell" the right infinite cell?
// Then inf_v_index should be 1
if (inf_v_cell->neighbor(inf_v_index)->index(inf_v_cell) == 0
&& inf_v_index == 0)
{
inf_v_cell->swap_vertices(
current_dimension() - 1, current_dimension());
}
}
}
}
return v;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - THE MAIN LOCATE(...) FUNCTION
template < class TT, class TDS >
template< typename OrientationPredicate >
typename Triangulation<TT, TDS>::Full_cell_handle
Triangulation<TT, TDS>
::do_locate(const Point & p, // query point
Locate_type & loc_type,// type of result (full_cell, face, vertex)
Face & face,// the face containing the query in its interior (when appropriate)
Facet & facet,// the facet containing the query in its interior (when appropriate)
Full_cell_handle start, // starting full_cell for the walk
OrientationPredicate const& orientation_pred
) const
{
const int cur_dim = current_dimension();
if( cur_dim == -1 )
{
loc_type = OUTSIDE_AFFINE_HULL;
return Full_cell_handle();
}
else if( cur_dim == 0 )
{
Vertex_handle vit = infinite_full_cell()->neighbor(0)->vertex(0);
if( EQUAL != geom_traits().compare_lexicographically_d_object()(p, vit->point()) )
{
loc_type = OUTSIDE_AFFINE_HULL;
return Full_cell_handle();
}
else
{
loc_type = ON_VERTEX;
face.set_full_cell(vit->full_cell());
face.set_index(0, 0);
return vit->full_cell();
}
}
Full_cell_handle s;
// if we don't know where to start, we start from any bounded full_cell
if( Full_cell_handle() == start )
{
// THE HACK THAT NOBODY SHOULD DO... BUT DIFFICULT TO WORK AROUND
// THIS... TODO: WORK AROUND IT
Full_cell_handle inf_c = const_cast<Self*>(this)->infinite_full_cell();
int inf_v_index = inf_c->index(infinite_vertex());
s = inf_c->neighbor(inf_v_index);
}
else
{
s = start;
if( is_infinite(s) )
{
int inf_v_index = s->index(infinite_vertex());
s = s->neighbor(inf_v_index);
}
}
// Check if query |p| is outside the affine hull
if( cur_dim < maximal_dimension() )
{
if( ! geom_traits().contained_in_affine_hull_d_object()(
points_begin(s),
points_begin(s) + current_dimension() + 1,
p) )
{
loc_type = OUTSIDE_AFFINE_HULL;
return Full_cell_handle();
}
}
// we remember the |previous|ly visited full_cell to avoid the evaluation
// of one |orientation| predicate
Full_cell_handle previous = Full_cell_handle();
bool full_cell_not_found = true;
// A full_cell has at most dimension + 1 facets:
boost::container::small_vector<signed char, 8> orientations_ (cur_dim + 1);
while(full_cell_not_found) // we walk until we locate the query point |p|
{
#ifdef CGAL_TRIANGULATION_STATISTICS
++walk_size_;
#endif
// For the remembering stochastic walk, we need to start trying
// with a random index:
int j, i = rng_.get_int(0, cur_dim);
// we check |p| against all the full_cell's hyperplanes in turn
for(j = 0; j <= cur_dim; ++j, i = (i + 1) % (cur_dim + 1) )
{
Full_cell_handle next = s->neighbor(i);
if( previous == next )
{ // no need to compute the orientation, we already know it
orientations_[i] = POSITIVE;
continue; // go to next full_cell's facet
}
Substitute_point_in_vertex_iterator<
typename Full_cell::Vertex_handle_const_iterator>
spivi(s->vertex(i), &p);
orientations_[i] = orientation_pred(
boost::make_transform_iterator(s->vertices_begin(), spivi),
boost::make_transform_iterator(s->vertices_begin() + cur_dim + 1,
spivi));
if( orientations_[i] != NEGATIVE )
{
// from this facet's point of view, we are inside the
// full_cell or on its boundary, so we continue to next facet
continue;
}
// At this point, we know that we have to jump to the |next|
// full_cell because orientation_[i] == NEGATIVE
previous = s;
s = next;
if( is_infinite(next) )
{ // we have arrived OUTSIDE the convex hull of the triangulation,
// so we stop the search
full_cell_not_found = false;
loc_type = OUTSIDE_CONVEX_HULL;
face.set_full_cell(s);
}
break;
} // end of the 'for' loop
if( ( cur_dim + 1 ) == j ) // we found the full_cell containing |p|
full_cell_not_found = false;
}
// Here, we know in which full_cell |p| is in.
// We now check more precisely where |p| landed:
// vertex, facet, face or full_cell.
if( ! is_infinite(s) )
{
face.set_full_cell(s);
int num(0);
int verts(0);
for(int i = 0; i < cur_dim; ++i)
{
if( orientations_[i] == COPLANAR )
{
++num;
facet = Facet(s, i);
}
else
face.set_index(verts++, i);
}
//-- We could put the if{}else{} below in the loop above, but then we would
// need to test if (verts < cur_dim) many times... we do it only once
// here:
if( orientations_[cur_dim] == COPLANAR )
{
++num;
facet = Facet(s, cur_dim);
}
else if( verts < cur_dim )
face.set_index(verts, cur_dim);
//-- end of remark above //
if( 0 == num )
{
loc_type = IN_FULL_CELL;
face.clear();
}
else if( cur_dim == num )
loc_type = ON_VERTEX;
else if( 1 == num )
loc_type = IN_FACET;
else
loc_type = IN_FACE;
}
return s;
}
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Full_cell_handle
Triangulation<TT, TDS>
::locate( const Point & p, // query point
Locate_type & loc_type,// type of result (full_cell, face, vertex)
Face & face,// the face containing the query in its interior (when appropriate)
Facet & facet,// the facet containing the query in its interior (when appropriate)
Full_cell_handle start// starting full_cell for the walk
) const
{
if( current_dimension() == maximal_dimension() )
{
Orientation_d ori = geom_traits().orientation_d_object();
return do_locate(p, loc_type, face, facet, start, ori);
}
else
return do_locate(p, loc_type, face, facet, start, coaffine_orientation_predicate());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - the locate(...) variants
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Full_cell_handle
Triangulation<TT, TDS>
::locate( const Point & p,
Locate_type & loc_type,
Face & face,
Facet & facet,
Vertex_handle start) const
{
if( Vertex_handle() == start )
start = infinite_vertex();
return locate(p, loc_type, face, facet, start->full_cell());
}
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Full_cell_handle
Triangulation<TT, TDS>
::locate(const Point & p, Full_cell_handle s) const
{
Locate_type lt;
Face face(maximal_dimension());
Facet facet;
return locate(p, lt, face, facet, s);
}
template < class TT, class TDS >
typename Triangulation<TT, TDS>::Full_cell_handle
Triangulation<TT, TDS>
::locate(const Point & p, Vertex_handle v) const
{
if( Vertex_handle() != v )
v = infinite_vertex();
return this->locate(p, v->full_cell());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VALIDITY
template < class TT, class TDS >
bool
Triangulation<TT, TDS>
::is_valid(bool verbose, int level) const
{
if( ! tds().is_valid(verbose, level) )
return false;
Full_cell_const_iterator c;
if( current_dimension() < 0 )
return true;
Orientation o;
for( c = full_cells_begin(); c != full_cells_end(); ++c )
{
if( is_infinite(c) )
{
if( current_dimension() > 1 )
{
int i = c->index( infinite_vertex() );
Full_cell_handle n = c->neighbor(i);
infinite_vertex()->set_point(n->vertex(c->mirror_index(i))->point());
o = - orientation(c, true);
}
else
o = POSITIVE;
}
else
o = orientation(c, true);
if( NEGATIVE == o )
{
if( verbose ) CGAL_warning_msg(false, "full_cell is not correctly oriented");
return false;
}
if( COPLANAR == o )
{
if( verbose ) CGAL_warning_msg(false, "full_cell is flat");
return false;
}
}
return true;
}
template < class TT, class TDS >
bool Triangulation<TT, TDS>::are_incident_full_cells_valid(Vertex_const_handle v, bool verbose, int) const
{
if( current_dimension() <= 0 )
return true;
typedef std::vector<Full_cell_const_handle> Simps;
Simps simps;
simps.reserve(64);
std::back_insert_iterator<Simps> out(simps);
incident_full_cells(v, out);
typename Simps::const_iterator sit = simps.begin();
for( ; sit != simps.end(); ++sit )
{
if( is_infinite(*sit) )
continue;
Orientation o = orientation(*sit);
if( NEGATIVE == o )
{
if( verbose ) CGAL_warning_msg(false, "full_cell is not correctly oriented");
return false;
}
if( COPLANAR == o )
{
if( verbose ) CGAL_warning_msg(false, "full_cell is flat");
return false;
}
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// FUNCTIONS THAT ARE NOT MEMBER FUNCTIONS:
template < class TT, class TDS >
std::istream &
operator>>(std::istream & is, Triangulation<TT, TDS> & tr)
// reads :
// - the dimensions (maximal and current)
// - the number of finite vertices
// - the non combinatorial information on vertices (point, etc)
// - the number of full_cells
// - the full_cells by the indices of their vertices in the preceding list
// of vertices, plus the non combinatorial information on each full_cell
// - the neighbors of each full_cell by their index in the preceding list
{
typedef Triangulation<TT, TDS> T;
typedef typename T::Vertex_handle Vertex_handle;
// read current dimension and number of vertices
size_t n;
int cd;
if( is_ascii(is) )
is >> cd >> n;
else
{
read(is, cd);
read(is, n);
}
CGAL_assertion_msg( cd <= tr.maximal_dimension(), "input Triangulation has too high dimension");
tr.clear();
tr.set_current_dimension(cd);
if( n == 0 )
return is;
std::vector<Vertex_handle> vertices;
vertices.resize(n+1);
vertices[0] = tr.infinite_vertex();
is >> (*vertices[0]);
// read the vertices:
size_t i(1);
while( i <= n )
{
vertices[i] = tr.new_vertex();
is >> (*vertices[i]); // read a vertex
++i;
}
// now, read the combinatorial information
return tr.tds().read_full_cells(is, vertices);
}
template < class TT, class TDS >
std::ostream &
operator<<(std::ostream & os, const Triangulation<TT, TDS> & tr)
// writes :
// - the dimensions (maximal and current)
// - the number of finite vertices
// - the non combinatorial information on vertices (point, etc)
// - the number of full_cells
// - the full_cells by the indices of their vertices in the preceding list
// of vertices, plus the non combinatorial information on each full_cell
// - the neighbors of each full_cell by their index in the preceding list
{
typedef Triangulation<TT, TDS> T;
typedef typename T::Vertex_const_handle Vertex_handle;
typedef typename T::Vertex_const_iterator Vertex_iterator;
// outputs dimensions and number of vertices
size_t n = tr.number_of_vertices();
if( is_ascii(os) )
os << tr.current_dimension() << std::endl << n << std::endl;
else
{
write(os, tr.current_dimension());
write(os, n);
}
if( n == 0 )
return os;
int i = 0;
// write the vertices
std::map<Vertex_handle, int> index_of_vertex;
// infinite vertex has index 0 (among all the vertices)
index_of_vertex[tr.infinite_vertex()] = i++;
if(is_ascii(os))
os << *tr.infinite_vertex() <<"\n";
else
write(os, *tr.infinite_vertex());
for( Vertex_iterator it = tr.vertices_begin(); it != tr.vertices_end(); ++it )
{
if( tr.is_infinite(it) )
continue;
if(is_ascii(os))
os << *it <<"\n"; // write the vertex
else
write(os, *it);
index_of_vertex[it] = i++;
}
CGAL_assertion( size_t(i) == n+1 );
// output the combinatorial information
return tr.tds().write_full_cells(os, index_of_vertex);
}
} //namespace CGAL
#include <CGAL/enable_warnings.h>
#endif // CGAL_TRIANGULATION_H