cgal/Packages/Alpha_shapes_3/include/CGAL/Alpha_shape_3.h

1908 lines
53 KiB
C++

// ======================================================================
//
// Copyright (c) 1997 The CGAL Consortium
//
// This software and related documentation is part of an INTERNAL release
// of the Computational Geometry Algorithms Library (CGAL). It is not
// intended for general use.
//
// ----------------------------------------------------------------------
//
// release : $CGAL_Revision: CGAL-2.0-I-20 $
// release_date : $CGAL_Date: 1999/06/02 $
//
// file : include/CGAL/Alpha_shape_3.h
// package : Alpha_shapes_3(1.0)
// source : $RCSfile$
// revision : $Revision$
// revision_date : $Date$
// author(s) : Tran Kai Frank DA <Frank.Da@sophia.inria.fr>
//
// coordinator : INRIA Sophia-Antipolis (<Mariette.Yvinec@sophia.inria.fr>)
//
// ======================================================================
#ifndef CGAL_ALPHA_SHAPE_3_H
#define CGAL_ALPHA_SHAPE_3_H
#include <CGAL/basic.h>
#include <cassert>
#include <set>
#include <map>
#include <vector>
#include <algorithm>
#include <utility>
#include <iostream>
#include <CGAL/utility.h>
#include <CGAL/IO/Geomview_stream.h> // TBC
//-------------------------------------------------------------------
CGAL_BEGIN_NAMESPACE
//-------------------------------------------------------------------
template < class Dt >
class Alpha_shape_3 : public Dt
{
// DEFINITION The class Alpha_shape_3<Dt> represents the family
// of alpha-shapes of points in a plane for all positive alpha. It
// maintains the underlying Delaunay tetrahedralization which represents
// connectivity and order among its simplices. Each k-dimensional simplex of
// the Delaunay tetrahedralization is associated with an interval that
// specifies for which values of alpha the simplex belongs to the alpha-shape
// (sorted linear arrays resp. multimaps or interval trees). There are links
// between the intervals and the k-dimensional simplices of the Delaunay
// tetrahedralization (multimaps resp. hashtables).
//
//------------------------- TYPES ------------------------------------
public:
typedef typename Dt::Geom_traits Gt;
typedef typename Dt::Triangulation_data_structure Tds;
typedef typename Gt::FT Coord_type;
typedef typename Gt::Point_3 Point;
typedef typename Gt::Segment_3 Segment;
// typedef typename Gt::Triangle_3 Triangle;
// typedef typename Gt::Tetrahedron_3 Tetrahedron;
typedef typename Dt::Cell_handle Cell_handle;
typedef typename Dt::Vertex_handle Vertex_handle;
typedef typename Dt::Cell Cell;
typedef typename Dt::Vertex Vertex;
typedef typename Dt::Facet Facet;
typedef typename Dt::Edge Edge;
typedef typename Dt::Cell_circulator Cell_circulator;
typedef typename Dt::Facet_circulator Facet_circulator;
typedef typename Dt::Cell_iterator Cell_iterator;
typedef typename Dt::Facet_iterator Facet_iterator;
typedef typename Dt::Edge_iterator Edge_iterator;
typedef typename Dt::Vertex_iterator Vertex_iterator;
typedef typename Dt::Finite_cells_iterator Finite_cells_iterator;
typedef typename Dt::Finite_facets_iterator Finite_facets_iterator;
typedef typename Dt::Finite_edges_iterator Finite_edges_iterator;
typedef typename Dt::Finite_vertices_iterator Finite_vertices_iterator;
typedef typename Dt::Locate_type Locate_type;
private:
typedef long Key;
typedef std::multimap< Coord_type, Cell_handle > Interval_cell_map;
typedef typename Interval_cell_map::value_type Interval_cell;
// typedef Cell_handle const const_void;
// typedef std::pair< const_void, int > const_Facet;
// typedef std::pair< const_void, int > const_Vertex;
typedef std::vector< Coord_type > Alpha_spectrum;
typedef std::set< Key > Marked_cell_set;
public:
//the following eight typedef were private,
// but operator<<(ostream) needs them
typedef Triple<Coord_type, Coord_type, Coord_type> Interval3;
typedef std::pair< Interval3, Edge > Interval_edge;
typedef std::multimap< Interval3, Edge > Interval_edge_map;
typedef std::multimap< Interval3, Facet > Interval_facet_map;
typedef typename Interval_facet_map::value_type Interval_facet;
typedef std::pair< Coord_type, Coord_type > Interval2;
typedef std::multimap< Interval2, Vertex_handle > Interval_vertex_map;
typedef typename Interval_vertex_map::value_type Interval_vertex;
typedef typename Alpha_spectrum::const_iterator Alpha_iterator;
// An iterator that allow to traverse the sorted sequence of
// different alpha-values. The iterator is bidirectional and
// non-mutable. Its value-type is Coord_type
enum Classification_type {EXTERIOR, SINGULAR, REGULAR, INTERIOR};
// Distinguishes the different cases for classifying a
// k-dimensional cell of the underlying Delaunay tetrahedralization of
// the alpha-shape.
//
// `EXTERIOR' if the cell does not belong to the alpha-complex.
//
// `SINGULAR' if the cell belongs to the boundary of the
// alpha-shape, but is not incident to any higher-dimensional
// cell of the alpha-complex
//
// `REGULAR' if cell belongs to the boundary of the alpha-shape
// and is incident to a higher-dimensional cell of the
// alpha-complex
//
// `INTERIOR' if the cell belongs to the alpha-complex, but does
// not belong to the boundary of the alpha-shape
enum Mode {GENERAL, REGULARIZED};
// In general, an alpha shape is a non-connected, mixed-dimension
// polygon. Its regularized version is formed by the set of
// regular facets and their vertices
typedef typename std::list< Vertex_handle >::iterator
Alpha_shape_vertices_iterator;
typedef typename std::list< Facet >::iterator Alpha_shape_facets_iterator;
public: // should be private ? --> operator should be wrappers
// only finite facets and simplices are inserted into the maps
Interval_cell_map _interval_cell_map;
Interval_facet_map _interval_facet_map;
Interval_edge_map _interval_edge_map;
Interval_vertex_map _interval_vertex_map;
Alpha_spectrum _alpha_spectrum;
Coord_type _alpha;
Mode _mode;
// should be constants
Coord_type Infinity;
Coord_type UNDEFINED;
std::list< Vertex_handle > Alpha_shape_vertices_list;
std::list< Facet > Alpha_shape_facets_list;
//------------------------- CONSTRUCTORS ------------------------------
// Introduces an empty alpha-shape `A' for a positive
// alpha-value `alpha'. Precondition: `alpha' >= 0.
Alpha_shape_3(Coord_type alpha = 0,
Mode m = REGULARIZED)
: _alpha(alpha), _mode(m), Infinity(-1), UNDEFINED(-2)
{}
// Introduces an alpha-shape `A' for a positive alpha-value
// `alpha' that is initialized with the points in the range
// from first to last
template < class InputIterator >
Alpha_shape_3(const InputIterator& first,
const InputIterator& last,
const Coord_type& alpha = 0,
Mode m = REGULARIZED)
: _alpha(alpha), _mode(m), Infinity(-1), UNDEFINED(-2)
{
Dt::insert(first, last);
if (dimension() == 3)
{
// Compute the associated _interval_cell_map
initialize_interval_cell_map();
// Compute the associated _interval_facet_map
initialize_interval_facet_map();
// Compute the associated _interval_edge_map
initialize_interval_edge_map();
// Compute the associated _interval_vertex_map
initialize_interval_vertex_map();
// merge the two maps
initialize_alpha_spectrum();
}
}
public:
//----------------------- OPERATIONS ---------------------------------
template < class InputIterator >
int make_alpha_shape(const InputIterator& first,
const InputIterator& last)
{
clear();
int n = Dt::insert(first, last);
#ifdef DEBUG
std::cout << "Triangulation computed" << std::endl;
#endif
if (dimension() == 3)
{
// Compute the associated _interval_cell_map
initialize_interval_cell_map();
// Compute the associated _interval_facet_map
initialize_interval_facet_map();
// Compute the associated _interval_edge_map
initialize_interval_edge_map();
// Compute the associated _interval_vertex_map
initialize_interval_vertex_map();
// merge the two maps
initialize_alpha_spectrum();
}
return n;
}
// Introduces an alpha-shape `A' for a positive alpha-value
// `alpha' that is initialized with the points in the range
// from first to last
private :
//--------------------- INITIALIZATION OF PRIVATE MEMBERS -----------
void initialize_interval_cell_map();
void initialize_interval_facet_map();
void initialize_interval_edge_map() {} //disabled here
void initialize_interval_vertex_map();
void initialize_alpha_spectrum();
//---------------------------------------------------------------------
public:
void clear()
{
// clears the structure
Dt::clear();
_interval_cell_map.clear();
_interval_facet_map.clear();
_interval_edge_map.clear();
_interval_vertex_map.clear();
_alpha_spectrum.clear();
Alpha_shape_vertices_list.clear();
Alpha_shape_facets_list.clear();
set_alpha(0);
set_mode(REGULARIZED);
}
//----------------------- PRIVATE MEMBERS --------------------
private:
struct Less
{
bool operator()(const Interval_facet& ie,
const Coord_type& alpha)
{ return ie.first.first < alpha; }
bool operator()(const Coord_type& alpha,
const Interval_facet& ie)
{ return alpha < ie.first.first; }
};
//----------------------- ACCESS TO PRIVATE MEMBERS -----------------
private:
Coord_type find_interval(Cell_handle s) const
// check whether it is faster to compute the
// radius directly instead of looking it up
{
return s->get_alpha();
}
Interval3 find_interval(const Facet& f) const
{
return (f.first)->get_facet_ranges(f.second);
}
Interval3 find_interval(const Edge& e) const
{
return (e.first)->get_edge_ranges(e.second, e.third);
}
Interval2 find_interval(const Vertex_handle& v) const
{
return v->get_range();
}
//---------------------------------------------------------------------
public:
Coord_type set_alpha(const Coord_type& alpha)
// Sets the alpha-value to `alpha'. Precondition: `alpha' >= 0.
// Returns the previous alpha
{
Coord_type previous_alpha = _alpha;
_alpha = alpha;
return previous_alpha;
}
const Coord_type& get_alpha() const
// Returns the current alpha-value.
{
return _alpha;
}
const Coord_type& get_nth_alpha(const int& n) const
// Returns the n-th alpha-value.
// n < size()
{
if (! _alpha_spectrum.empty())
return _alpha_spectrum[n];
else
return UNDEFINED;
}
int number_of_alphas() const
// Returns the number of not necessary different alpha-values
{
return _alpha_spectrum.size();
}
//---------------------------------------------------------------------
private:
// the dynamic version is not yet implemented
// desactivate the tetrahedralization member functions
Vertex_handle insert(const Point& p) {}
// Inserts point `p' in the alpha shape and returns the
// corresponding vertex of the underlying Delaunay tetrahedralization.
// If point `p' coincides with an already existing vertex, this
// vertex is returned and the alpha shape remains unchanged.
// Otherwise, the vertex is inserted in the underlying Delaunay
// tetrahedralization and the associated intervals are updated.
void remove(Vertex_handle v) {}
// Removes the vertex from the underlying Delaunay tetrahedralization.
// The created hole is retriangulated and the associated intervals
// are updated.
//---------------------------------------------------------------------
public:
Mode set_mode(Mode mode = REGULARIZED )
// Sets `A' to its general or regularized version. Returns the
// previous mode.
{
Mode previous_mode = _mode;
_mode = mode;
return previous_mode;
}
Mode get_mode() const
// Returns whether `A' is general or regularized.
{
return _mode;
}
//---------------------------------------------------------------------
private:
std::back_insert_iterator< std::list<Vertex_handle > >
get_alpha_shape_vertices(std::back_insert_iterator<
std::list<Vertex_handle > > result) const;
//---------------------------------------------------------------------
std::back_insert_iterator<std::list<std::pair< Cell_handle, int > > >
get_alpha_shape_facets(std::back_insert_iterator<
std::list<
std::pair< Cell_handle, int > > > result) const;
//---------------------------------------------------------------------
public:
Alpha_shape_vertices_iterator alpha_shape_vertices_begin()
{
Alpha_shape_vertices_list.erase(Alpha_shape_vertices_list.begin(),
Alpha_shape_vertices_list.end());
std::back_insert_iterator< std::list< Vertex_handle > >
V_it(Alpha_shape_vertices_list);
get_alpha_shape_vertices(V_it);
return Alpha_shape_vertices_list.begin();
}
Alpha_shape_vertices_iterator Alpha_shape_vertices_begin()
{
return alpha_shape_vertices_begin();
}
//---------------------------------------------------------------------
Alpha_shape_vertices_iterator alpha_shape_vertices_end()
{
return Alpha_shape_vertices_list.end();
}
Alpha_shape_vertices_iterator Alpha_shape_vertices_end()
{
return alpha_shape_vertices_end();
}
//---------------------------------------------------------------------
Alpha_shape_facets_iterator alpha_shape_facets_begin()
{
Alpha_shape_facets_list.erase(Alpha_shape_facets_list.begin(),
Alpha_shape_facets_list.end());
std::back_insert_iterator< std::list< Facet > >
E_it(Alpha_shape_facets_list);
get_alpha_shape_facets(E_it);
return Alpha_shape_facets_list.begin();
}
Alpha_shape_facets_iterator Alpha_shape_facets_begin()
{
return alpha_shape_facets_begin();
}
//---------------------------------------------------------------------
Alpha_shape_facets_iterator alpha_shape_facets_end()
{
return Alpha_shape_facets_list.end();
}
Alpha_shape_facets_iterator Alpha_shape_facets_end()
{
return alpha_shape_facets_end();
}
public:
// Traversal of the alpha-Values
//
// The alpha shape class defines an iterator that allows to
// visit the sorted sequence of alpha-values. This iterator is
// non-mutable and bidirectional. Its value type is Coord_type.
Alpha_iterator alpha_begin() const
// Returns an iterator that allows to traverse the sorted sequence
// of alpha-values of `A'.
{
return _alpha_spectrum.begin();
}
Alpha_iterator alpha_end() const
// Returns the corresponding past-the-end iterator.
{
return _alpha_spectrum.end();
}
Alpha_iterator alpha_find(const Coord_type& alpha) const
// Returns an iterator pointing to an element with alpha-value
// `alpha', or the corresponding past-the-end iterator if such an
// element is not found.
{
return find(_alpha_spectrum.begin(),
_alpha_spectrum.end(),
alpha);
}
Alpha_iterator alpha_lower_bound(const Coord_type& alpha) const
// Returns an iterator pointing to the first element with
// alpha-value not less than `alpha'.
{
return std::lower_bound(_alpha_spectrum.begin(),
_alpha_spectrum.end(),
alpha);
}
Alpha_iterator alpha_upper_bound(const Coord_type& alpha) const
// Returns an iterator pointing to the first element with
// alpha-value greater than `alpha'.
{
return std::upper_bound(_alpha_spectrum.begin(),
_alpha_spectrum.end(),
alpha);
}
//--------------------- PREDICATES -----------------------------------
// the classification predicates take
// amortized const time if STL_HASH_TABLES
// O(log #alpha_shape ) otherwise
Classification_type classify(const Point& p) const
{
return classify(p, get_alpha());
}
Classification_type classify(const Point& p,
const Coord_type& alpha) const
// Classifies a point `p' with respect to `A'.
{
Locate_type type;
int i, j;
Cell_handle pCell = locate(p, type, i, j);
switch (type)
{
case VERTEX : return classify(pCell->vertex(i), alpha);
case EDGE : return classify(pCell, i, j, alpha);
case FACET : return classify(pCell, i, alpha);
case CELL : return classify(pCell, alpha);
case OUTSIDE_CONVEX_HULL : return EXTERIOR;
case OUTSIDE_AFFINE_HULL : return EXTERIOR;
default : return EXTERIOR;
};
}
//---------------------------------------------------------------------
Classification_type classify(const Cell_handle& s) const
// Classifies the cell `f' of the underlying Delaunay
// tetrahedralization with respect to `A'.
{
return classify(s, get_alpha());
}
Classification_type classify(const Cell_handle& s,
const Coord_type& alpha) const
// Classifies the cell `f' of the underlying Delaunay
// tetrahedralization with respect to `A'.
// we consider open spheres :
// s->radius == alpha => f exterior
// problem the operator [] is non-const
{
if (is_infinite(s)) return EXTERIOR;
// the version that computes the squared radius seems to be
// much faster
return (s->get_alpha() < alpha) ?
INTERIOR :
EXTERIOR;
}
//---------------------------------------------------------------------
Classification_type classify(const Facet& f) const
{
return classify(f.first, f.second, get_alpha());
}
Classification_type classify(const Cell_handle& s,
const int& i) const
{
return classify(s, i, get_alpha());
}
Classification_type classify(const Facet& f,
const Coord_type& alpha) const
{
return classify(f.first, f.second, alpha);
}
Classification_type classify(const Cell_handle& s,
const int& i,
const Coord_type& alpha) const;
// Classifies the face `f' of the underlying Delaunay
// tetrahedralization with respect to `A'.
//---------------------------------------------------------------------
Classification_type classify(const Edge& e) const
{
return classify(e.first, e.second, e.third, get_alpha());
}
Classification_type classify(const Cell_handle& s,
const int& i,
const int& j) const
{
return classify(s, i, j, get_alpha());
}
Classification_type classify(const Edge& e,
const Coord_type& alpha ) const
{
return classify(e.first, e.second, e.third, alpha);
}
Classification_type classify(const Cell_handle& s,
const int& i,
const int& j,
const Coord_type& alpha) const;
// Classifies the edge `e' of the underlying Delaunay
// tetrahedralization with respect to `A'.
//---------------------------------------------------------------------
Classification_type classify(const Vertex_handle& v) const
{
return classify(v, get_alpha());
}
Classification_type classify(const Vertex_handle& v,
const Coord_type& alpha) const;
// Classifies the vertex `v' of the underlying Delaunay
// tetrahedralization with respect to `A'.
//--------------------- NB COMPONENTS ---------------------------------
int
number_solid_components() const
{
return number_of_solid_components(get_alpha());
}
int
number_of_solid_components() const
{
return number_of_solid_components(get_alpha());
}
int
number_solid_components(const Coord_type& alpha) const
{
return number_of_solid_components(get_alpha());
}
int
number_of_solid_components(const Coord_type& alpha) const;
// Determine the number of connected solid components
// takes time O(#alpha_shape) amortized if STL_HASH_TABLES
// O(#alpha_shape log n) otherwise
private:
void traverse(const Cell_handle& pCell,
Marked_cell_set& marked_cell_set,
const Coord_type alpha) const;
//----------------------------------------------------------------------
public:
Alpha_iterator find_optimal_alpha(const int& nb_components);
// find the minimum alpha that satisfies the properties
// (1) nb_components solid components
// (2) all data points on the boundary or in its interior
private:
Coord_type find_alpha_solid() const;
// compute the minumum alpha such that all data points
// are either on the boundary or in the interior
// not necessarily connected
// starting point for searching
// takes O(#alpha_shape) time
//--------------------- PREDICATES ------------------------------------
private:
bool is_attached(const Cell_handle& s, const int& i) const
{
int i0=(i+1)&3, i1=(i+2)&3, i2=(i+3)&3;
Bounded_side b =
Gt().side_of_bounded_sphere_3_object()(s->vertex(i0)->point(),
s->vertex(i1)->point(),
s->vertex(i2)->point(),
s->vertex(i)->point());
return (b == ON_BOUNDED_SIDE) ? true : false;
}
bool is_attached(const Cell_handle& s, const int& i0,
const int& i1, const int& i) const
{
Bounded_side b =
Gt().side_of_bounded_sphere_3_object()(s->vertex(i0)->point(),
s->vertex(i1)->point(),
s->vertex(i)->point());
return (b == ON_BOUNDED_SIDE) ? true : false;
}
//------------------- GEOMETRIC PRIMITIVES ----------------------------
Coord_type squared_radius(const Cell_handle& s) const
{
return Gt().compute_squared_radius_3_object()(s->vertex(0)->point(),
s->vertex(1)->point(),
s->vertex(2)->point(),
s->vertex(3)->point());
}
Coord_type squared_radius(const Cell_handle& s, const int& i) const
{
// test which one is faster TBC
int i0=(i+1)&3, i1=(i+2)&3, i2=(i+3)&3;
return Gt().compute_squared_radius_3_object()(s->vertex(i0)->point(),
s->vertex(i1)->point(),
s->vertex(i2)->point());
}
Coord_type squared_radius(const Cell_handle& s,
const int& i, const int& j) const
{
return Gt().compute_squared_radius_3_object()(s->vertex(i)->point(),
s->vertex(j)->point());
}
//---------------------------------------------------------------------
private:
// prevent default copy constructor and default assigment
Alpha_shape_3(const Alpha_shape_3& A)
{}
Alpha_shape_3& operator=(const Alpha_shape_3& A)
{}
//---------------------------------------------------------------------
public:
void show_alpha_shape_faces(Geomview_stream &gv);
};
//---------------------------------------------------------------------
//--------------------- MEMBER FUNCTIONS-------------------------------
//---------------------------------------------------------------------
//--------------------- INITIALIZATION OF PRIVATE MEMBERS -------------
template <class Dt>
void
Alpha_shape_3<Dt>::initialize_interval_cell_map()
{
Finite_cells_iterator cell_it;
Cell_handle pCell;
Coord_type alpha_f;
for( cell_it = finite_cells_begin();
cell_it != finite_cells_end();
++cell_it)
{
pCell = cell_it->handle();
alpha_f = squared_radius(pCell);
_interval_cell_map.insert(Interval_cell(alpha_f, (pCell)));
// cross references
pCell->set_alpha(alpha_f);
}
}
//---------------------------------------------------------------------
template <class Dt>
void
Alpha_shape_3<Dt>::initialize_interval_facet_map()
{
Finite_facets_iterator face_it; // TBC
Facet f;
Cell_handle pCell, pNeighbor ;
for( face_it = finite_facets_begin();
face_it != finite_facets_end();
++face_it)
{
f = *face_it;
pCell = f.first;
int i = f.second;
pNeighbor = pCell->neighbor(i);
int Neigh_i = pNeighbor->index(pCell);
Interval3 interval;
// not on the convex hull
if(!is_infinite(pCell) && !is_infinite(pNeighbor))
{
Coord_type squared_radius_Cell = find_interval(pCell);
Coord_type squared_radius_Neighbor = find_interval(pNeighbor);
if (squared_radius_Neighbor < squared_radius_Cell)
{
f = Facet(pNeighbor, Neigh_i);
Coord_type coord_tmp = squared_radius_Cell;
squared_radius_Cell = squared_radius_Neighbor;
squared_radius_Neighbor = coord_tmp;
}
interval = (is_attached(pCell, i) ||
is_attached(pNeighbor, Neigh_i)) ?
make_triple(UNDEFINED,
squared_radius_Cell,
squared_radius_Neighbor):
make_triple(squared_radius(pCell, i),
squared_radius_Cell,
squared_radius_Neighbor);
}
else // on the convex hull
{
if(is_infinite(pCell))
{
if (!is_infinite(pNeighbor))
{
interval = (is_attached(pNeighbor,
pNeighbor->index(pCell))) ?
make_triple(UNDEFINED,
pNeighbor->get_alpha(),
Infinity):
make_triple(squared_radius(pNeighbor,
pNeighbor->index(pCell)),
pNeighbor->get_alpha(),
Infinity);
}
else
{
// both simplices are infinite by definition unattached
// the face is finite by construction
assert(is_infinite(pNeighbor) && is_infinite(pCell));
interval = make_triple(
squared_radius(pCell, i),
Infinity,
Infinity);
}
}
else // is_infinite(pNeighbor)
{
assert(is_infinite(pNeighbor) && !is_infinite(pCell));
if (is_attached(pCell, i))
interval = make_triple(UNDEFINED,
find_interval(pCell),
Infinity);
else
interval = make_triple(squared_radius(pCell, i),
find_interval(pCell),
Infinity);
}
}
_interval_facet_map.insert(Interval_facet(interval, f));
// cross-links
(f.first)->set_facet_ranges(f.second, interval);
}
// Remark:
// The interval_facet_map will be sorted as follows
// first the attached faces on the convex hull
// second not on the convex hull
// third the un-attached faces on the convex hull
// finally not on the convex hull
//
// if we are in regularized mode we should sort differently
// by the second third first Key
// struct LessIntervalRegular
// {
// // if we are in regularized mode we should sort differently
// // by the second third Key
// bool operator()(const Interval_facet& ie1,
// const Interval_facet& ie2)
// { return ie1.first.second < ie2.first.second ||
// (ie1.first.second == ie2.first.second &&
// ie1.first.third < ie2.first.third); }
// };
}
//---------------------------------------------------------------------
// template <class Dt>
// void
// Alpha_shape_3<Dt>::initialize_interval_edge_map()
// {
// // TBC since our definition of singular and regular differs from
// // Edelsbrunner and Muecke's definition
// // verify the relation between attached edges and singular and
// // regular edges
// // _interval_edge_map.reserve(number_of_vertices()); TBC
// Coord_type alpha_min_e;
// Coord_type alpha_mid_e = (!_interval_cell_map.empty() ?
// _interval_cell_map.end()->first :
// 0);;
// Coord_type alpha_max_e = 0;
// bool b_attached = false;
// Cell_handle s;
// Edge_iterator edge_it;
// // only finite edges
// for( edge_it = edges_begin();
// edge_it != edges_end();
// ++edge_it)
// {
// Edge e = (*edge_it);
// if (! is_infinite(e)) // TBC
// {
// //-------------- examine incident faces --------------------------
// Edge_circulator edge_circ = opposite_edges(e),
// edge_done(edge_circ);
// do
// {
// // the incident face (s, i) has vertex with index j,
// s = (*edge_circ).first;
// int i = (*edge_circ).second;
// int j = (*edge_circ).third;
// if (is_infinite(std::make_pair(s,i))) // TBC
// {
// alpha_max_e = Infinity;
// }
// else
// {
// // test whether the vertex with index j
// // is inside the sphere defined by the edge e = (s, cw(i,j),
// // ccw(i,j))
// b_attached = is_attached(s, cw(i,j), ccw(i,j), j);
// Interval3 interval3 = find_interval(const_facet(s, i));
// alpha_mid_e = (interval3.first != UNDEFINED) ?
// CGAL::min(alpha_mid_e, interval3.first):
// CGAL::min(alpha_mid_e, interval3.second);
// if (alpha_max_e != Infinity)
// {
// alpha_max_e = (interval3.third != Infinity) ?
// CGAL::max(alpha_max_e, interval3.third):
// Infinity;
// }
// }
// }
// while(++edge_circ != edge_done);
// alpha_min_e = (b_attached ? UNDEFINED :
// squared_radius(e.first,
// e.second,
// e.third));
// Interval3 interval = make_triple(alpha_min_e,
// alpha_mid_e,
// alpha_max_e);
// _interval_edge_map.insert(Interval_edge(interval, e));
// // cross references
// // we need a canonic description since otherwise we have problem
// // with our access operation
// // use the two vertices
// s = e.first;
// const Edge const_edge(s,e.second, e.third);
// _edge_interval_map[const_edge] = interval;
// }
// }
// }
//---------------------------------------------------------------------
template <class Dt>
void
Alpha_shape_3<Dt>::initialize_interval_vertex_map()
{
Coord_type alpha_mid_v;
Coord_type alpha_max_v;
Coord_type alpha_s;
Finite_vertices_iterator vertex_it;
// only finite vertexs
for( vertex_it = finite_vertices_begin();
vertex_it != finite_vertices_end();
++vertex_it)
{
Vertex_handle v = vertex_it->handle();
if (!is_infinite(v)) // TBC
{
Cell_handle s;
alpha_max_v = 0;
alpha_mid_v = (!_interval_cell_map.empty() ?
(--_interval_cell_map.end())->first :
0);
//-------------- examine incident simplices --------------------
// we use a different definition than Edelsbrunner and Muecke
// singular means not incident to any 3-dimensional face
// regular means incident to a 3-dimensional face
//--------------------------------------------------------------
// Cell_circulator cell_circ = v->incident_simplices(),
// done(cell_circ);
// if ((*cell_circ) != NULL)
// {
// do
// {
// s = (*cell_circ);
// if (is_infinite(s))
// {
// alpha_max_v = Infinity;
// // continue;
// }
// else
// {
// alpha_s = find_interval(s);
// // if we define singular as not incident to a
// // 3-dimensional cell
// alpha_mid_v = CGAL::min(alpha_mid_v, alpha_s);
// if (alpha_max_v != Infinity)
// alpha_max_v = CGAL::max(alpha_max_v, alpha_s);
// }
// }
// while(++cell_circ != done);
// }
//---------------------------------------------------------------
// TBC if cell_circulator become available
// at the moment takes v*s time
Cell_iterator cell_it;
for( cell_it = cells_begin();
cell_it != cells_end();
++cell_it)
{
s = cell_it->handle();
if (s->has_vertex(vertex_it->handle()))
{
if (is_infinite(s))
{
alpha_max_v = Infinity;
// continue;
}
else
{
alpha_s = find_interval(s);
// if we define singular as not incident to a
// 3-dimensional cell
alpha_mid_v = CGAL::min(alpha_mid_v, alpha_s);
if (alpha_max_v != Infinity)
alpha_max_v = CGAL::max(alpha_max_v, alpha_s);
}
}
}
Interval2 interval = std::make_pair(alpha_mid_v, alpha_max_v);
_interval_vertex_map.insert(Interval_vertex(interval,
vertex_it->handle()));
// cross references
vertex_it->handle()->set_range(interval);
}
}
}
//---------------------------------------------------------------------
template <class Dt>
void
Alpha_shape_3<Dt>::initialize_alpha_spectrum()
// merges the alpha thresholds of the simplices faces (and edges)
{
// skip the attached faces
// <=> _interval_facet_map.first.first == UNDEFINED
typename Interval_facet_map::iterator
face_it = std::upper_bound(_interval_facet_map.begin(),
_interval_facet_map.end(),
UNDEFINED,
Less());
// merge the maps which is sorted and contains the alpha-values
// of the unattached faces and the triangles.
// eliminate duplicate values due to for example attached faces
// merge and copy from STL since assignment should be function object
typename Interval_cell_map::iterator
cell_it = _interval_cell_map.begin();
_alpha_spectrum.reserve(_interval_cell_map.size() +
_interval_facet_map.size()/ 2 );
// should be only the number of unattached faces
// size_type nb_unattached_facets;
// distance(face_it, _interval_facet_map.end(), nb_unattached_facets);
// however the distance function is expensive
while (face_it != _interval_facet_map.end() ||
cell_it != _interval_cell_map.end())
{
if (cell_it != _interval_cell_map.end() &&
(face_it == _interval_facet_map.end() ||
(*cell_it).first < (*face_it).first.first))
{
assert(cell_it != _interval_cell_map.end());
if (_alpha_spectrum.empty() ||
_alpha_spectrum.back() < (*cell_it).first)
_alpha_spectrum.push_back((*cell_it).first);
cell_it++;
}
else
{
assert (cell_it == _interval_cell_map.end() ||
(face_it != _interval_facet_map.end() &&
(*cell_it).first >= (*face_it).first.first));
if (_alpha_spectrum.empty() ||
_alpha_spectrum.back() < (*face_it).first.first)
_alpha_spectrum.push_back((*face_it).first.first);
face_it++;
}
}
}
//---------------------------------------------------------------------
template <class Dt>
std::istream& operator>>(std::istream& is, const Alpha_shape_3<Dt>& A)
// Reads a alpha shape from stream `is' and assigns it to
// Unknown creationvariable. Precondition: The extract operator must
// be defined for `Point'.
{}
//---------------------------------------------------------------------
template <class Dt>
std::ostream& operator<<(std::ostream& os, const Alpha_shape_3<Dt>& A)
// Inserts the alpha shape into the stream `os' as an indexed face set.
// Precondition: The insert operator must be defined for `Point'
{
typedef typename Alpha_shape_3<Dt>::Interval_vertex_map Interval_vertex_map;
typename Interval_vertex_map::const_iterator vertex_alpha_it;
const typename Alpha_shape_3<Dt>::Interval2* pInterval2;
typedef long Key;
std::map< Key, int > V;
int number_of_vertices = 0;
typedef typename Alpha_shape_3<Dt>::Interval_facet_map Interval_facet_map;
typename Interval_facet_map::const_iterator face_alpha_it;
const typename Alpha_shape_3<Dt>::Interval3* pInterval;
int i0, i1, i2;
if (A.get_mode() == Alpha_shape_3<Dt>::REGULARIZED)
{
typename Alpha_shape_3<Dt>::Vertex_handle v;
for (vertex_alpha_it = A._interval_vertex_map.begin();
vertex_alpha_it != A._interval_vertex_map.end() &&
(*vertex_alpha_it).first.first < A.get_alpha();
++vertex_alpha_it)
{
pInterval2 = &(*vertex_alpha_it).first;
#ifdef DEBUG
Alpha_shape_3<Dt>::Coord_type alpha =
A.get_alpha();
Alpha_shape_3<Dt>::Coord_type alpha_min =
pInterval2->first;
Alpha_shape_3<Dt>::Coord_type alpha_max =
pInterval2->second;
#endif // DEBUG
if((pInterval2->second >= A.get_alpha()
|| pInterval2->second == A.Infinity))
// alpha must be larger than the min boundary
// and alpha is smaller than the upper boundary
// which might be infinity
// write the vertex
{
v = (*vertex_alpha_it).second;
assert(A.classify(v) ==
Alpha_shape_3<Dt>::REGULAR);
V[(Key)&(*v)] = number_of_vertices++;
os << v->point() << std::endl;
}
}
// the vertices are oriented counterclockwise
typename Alpha_shape_3<Dt>::Cell_handle s;
int i;
for (face_alpha_it = A._interval_facet_map.begin();
face_alpha_it != A._interval_facet_map.end() &&
(*face_alpha_it).first.first < A.get_alpha();
++face_alpha_it)
{
pInterval = &(*face_alpha_it).first;
#ifdef DEBUG
Alpha_shape_3<Dt>::Coord_type alpha =
A.get_alpha();
Alpha_shape_3<Dt>::Coord_type alpha_mid =
pInterval->second;
Alpha_shape_3<Dt>::Coord_type alpha_max =
pInterval->third;
#endif // DEBUG
assert(pInterval->second != A.Infinity);
// since this happens only for convex hull of dimension 2
// thus singular
if(pInterval->second < A.get_alpha() &&
(pInterval->third >= A.get_alpha()
|| pInterval->third == A.Infinity))
// alpha must be larger than the mid boundary
// and alpha is smaller than the upper boundary
// which might be infinity
// visualize the boundary
{
s = (*face_alpha_it).second.first;
i = (*face_alpha_it).second.second;
// assure that all vertices are in ccw order
if (A.classify(s) == Alpha_shape_3<Dt>::EXTERIOR)
{
// take the reverse cell
typename Alpha_shape_3<Dt>::Cell_handle
pNeighbor = s->neighbor(i);
i = pNeighbor->index(s);
s = pNeighbor;
}
assert(A.classify(s) == Alpha_shape_3<Dt>::INTERIOR);
assert(A.classify(s, i) ==
Alpha_shape_3<Dt>::REGULAR);
int i0=(i+1)&3, i1=(i+2)&3, i2=(i+3)&3;
os << V[(Key)&(*s->vertex(i0))] << ' '
<< V[(Key)&(*s->vertex(i1))] << ' '
<< V[(Key)&(*s->vertex(i2))] << std::endl;
}
}
}
else // A.get_mode() == GENERAL -----------------------------------------
{
typename Alpha_shape_3<Dt>::Vertex_handle v;
// write the regular vertices
for (vertex_alpha_it = A._interval_vertex_map.begin();
vertex_alpha_it != A._interval_vertex_map.end() &&
(*vertex_alpha_it).first.first < A.get_alpha();
++vertex_alpha_it)
{
pInterval2 = &(*vertex_alpha_it).first;
if((pInterval2->second >= A.get_alpha()
|| pInterval2->second == A.Infinity))
// alpha must be larger than the min boundary
// and alpha is smaller than the upper boundary
// which might be infinity
// write the vertex
{
v = (*vertex_alpha_it).second;
CGAL_triangulation_assertion(A.classify(v) ==
Alpha_shape_3<Dt>::REGULAR);
V[(Key)&(*v)] = number_of_vertices++;
os << v->point() << std::endl;
}
}
// write the singular vertices
for (;
vertex_alpha_it != A._interval_vertex_map.end();
++vertex_alpha_it)
{
v = (*vertex_alpha_it).second;
CGAL_triangulation_assertion(A.classify(v) ==
Alpha_shape_3<Dt>::SINGULAR);
V[(Key)&(*v)] = number_of_vertices++;
os << v->point() << std::endl;
}
// the vertices are oriented counterclockwise
typename Alpha_shape_3<Dt>::Cell_handle s;
int i;
for (face_alpha_it = A._interval_facet_map.begin();
face_alpha_it != A._interval_facet_map.end() &&
(*face_alpha_it).first.first < A.get_alpha();
++face_alpha_it)
{
pInterval = &(*face_alpha_it).first;
#ifdef DEBUG
Alpha_shape_3<Dt>::Coord_type alpha =
A.get_alpha();
Alpha_shape_3<Dt>::Coord_type alpha_min =
pInterval->first;
Alpha_shape_3<Dt>::Coord_type alpha_mid =
pInterval->second;
Alpha_shape_3<Dt>::Coord_type alpha_max =
pInterval->third;
#endif // DEBUG
if(pInterval->third >= A.get_alpha()
|| pInterval->third == A.Infinity)
// if alpha is smaller than the upper boundary
// which might be infinity
// visualize the boundary
{
s = (*face_alpha_it).second.first;
i = (*face_alpha_it).second.second;
// write the regular faces
if (pInterval->second != A.Infinity &&
pInterval->second < A.get_alpha())
{
CGAL_triangulation_assertion(A.classify(s, i) ==
Alpha_shape_3<Dt>::REGULAR);
// assure that all vertices are in ccw order
if (A.classify(s) == Alpha_shape_3<Dt>::EXTERIOR)
{
// take the reverse cell
typename Alpha_shape_3<Dt>::Cell_handle
pNeighbor = s->neighbor(i);
i = pNeighbor->index(s);
s = pNeighbor;
}
CGAL_triangulation_assertion(A.classify(s) ==
Alpha_shape_3<Dt>::INTERIOR);
i0=(i+1)&3, i1=(i+2)&3, i2=(i+3)&3;
os << V[(Key)&(*s->vertex(i0))] << ' '
<< V[(Key)&(*s->vertex(i1))] << ' '
<< V[(Key)&(*s->vertex(i2))] << std::endl;
}
else // (pInterval->second == A.Infinity ||
// pInterval->second >= A.get_alpha()))
// pInterval->second == A.Infinity happens only for convex hull
// of dimension 2 thus singular
{
// write the singular faces
if (pInterval->first != A.UNDEFINED)
{
CGAL_triangulation_assertion(A.classify(s, i) ==
Alpha_shape_3<Dt>::SINGULAR);
i0=(i+1)&3, i1=(i+2)&3, i2=(i+3)&3;
os << V[(Key)&(*s->vertex(i0))] << ' '
<< V[(Key)&(*s->vertex(i1))] << ' '
<< V[(Key)&(*s->vertex(i2))] << std::endl;
}
}
}
}
}
return os;
}
//---------------------------------------------------------------------
template <class Dt>
std::back_insert_iterator<
std::list<CGAL_TYPENAME_MSVC_NULL Alpha_shape_3<Dt>::Vertex_handle > >
Alpha_shape_3<Dt>::get_alpha_shape_vertices(std::back_insert_iterator<
std::list<Vertex_handle > >
result) const
{
typedef Alpha_shape_3<Dt>::Interval_vertex_map Interval_vertex_map;
typename Interval_vertex_map::const_iterator vertex_alpha_it;
const Alpha_shape_3<Dt>::Interval2* pInterval2;
Vertex_handle v;
// write the regular vertices
for (vertex_alpha_it = _interval_vertex_map.begin();
vertex_alpha_it != _interval_vertex_map.end() &&
(*vertex_alpha_it).first.first < get_alpha();
++vertex_alpha_it)
{
pInterval2 = &(*vertex_alpha_it).first;
if((pInterval2->second >= get_alpha()
|| pInterval2->second == Infinity))
// alpha must be larger than the min boundary
// and alpha is smaller than the upper boundary
// which might be infinity
// write the vertex
{
v = (*vertex_alpha_it).second;
CGAL_triangulation_assertion(classify(v) ==
Alpha_shape_3<Dt>::REGULAR);
*result++ = v;
}
}
if (get_mode() == Alpha_shape_3<Dt>::GENERAL)
{
// write the singular vertices
for (;
vertex_alpha_it != _interval_vertex_map.end();
++vertex_alpha_it)
{
v = (*vertex_alpha_it).second;
CGAL_triangulation_assertion(classify(v) ==
Alpha_shape_3<Dt>::SINGULAR);
*result++ = v;
}
}
return result;
}
//---------------------------------------------------------------------
template <class Dt>
std::back_insert_iterator< std::list<
std::pair<CGAL_TYPENAME_MSVC_NULL Alpha_shape_3<Dt>::Cell_handle, int > > >
Alpha_shape_3<Dt>::get_alpha_shape_facets(std::back_insert_iterator<
std::list<
std::pair< Cell_handle, int > > >
result) const
{
// Writes the faces of the alpha shape `A' for the current 'alpha'-value
// to the container where 'out' refers to. Returns an output iterator
// which is the end of the constructed range.
typedef Alpha_shape_3<Dt>::Interval_facet_map Interval_facet_map;
typename Interval_facet_map::const_iterator face_alpha_it;
const Alpha_shape_3<Dt>::Interval3* pInterval;
if (get_mode() == Alpha_shape_3<Dt>::REGULARIZED)
{
// it is much faster looking at the sorted intervals
// than looking at all sorted cells
// alpha must be larger than the mid boundary
// and alpha is smaller than the upper boundary
for (face_alpha_it = _interval_facet_map.begin();
face_alpha_it != _interval_facet_map.end() &&
(*face_alpha_it).first.first < get_alpha();
++face_alpha_it)
{
pInterval = &(*face_alpha_it).first;
CGAL_triangulation_assertion(pInterval->second != Infinity);
// since this happens only for convex hull of dimension 2
// thus singular
if(pInterval->second < get_alpha() &&
(pInterval->third >= get_alpha()
|| pInterval->third == Infinity))
// alpha must be larger than the mid boundary
// and alpha is smaller than the upper boundary
// which might be infinity
// visualize the boundary
{
CGAL_triangulation_assertion(classify(
(*face_alpha_it).second.first,
(*face_alpha_it).second.second) ==
Alpha_shape_3<Dt>::REGULAR);
*result++ = Facet((*face_alpha_it).second.first,
(*face_alpha_it).second.second);
}
}
}
else // get_mode() == GENERAL -------------------------------------------
{
// draw the faces
for (face_alpha_it = _interval_facet_map.begin();
face_alpha_it != _interval_facet_map.end() &&
(*face_alpha_it).first.first < get_alpha();
++face_alpha_it)
{
pInterval = &(*face_alpha_it).first;
if (pInterval->first == UNDEFINED)
{
CGAL_triangulation_assertion(pInterval->second != Infinity);
// since this happens only for convex hull of dimension 2
// thus singular
if(pInterval->second < get_alpha() &&
(pInterval->third >= get_alpha()
|| pInterval->third == Infinity))
// alpha must be larger than the mid boundary
// and alpha is smaller than the upper boundary
// which might be infinity
// visualize the boundary
{
CGAL_triangulation_assertion(classify(
(*face_alpha_it).second.first,
(*face_alpha_it).second.second) ==
Alpha_shape_3<Dt>::REGULAR);
*result++ = Facet((*face_alpha_it).second.first,
(*face_alpha_it).second.second);
}
}
else
{
if(pInterval->third >= get_alpha()
|| pInterval->third == Infinity)
// if alpha is smaller than the upper boundary
// which might be infinity
// visualize the boundary
{
CGAL_triangulation_assertion(classify(
(*face_alpha_it).second.first,
(*face_alpha_it).second.second) ==
Alpha_shape_3<Dt>::REGULAR ||
classify((*face_alpha_it).second.first,
(*face_alpha_it).second.second) ==
Alpha_shape_3<Dt>::SINGULAR);
*result++ = Facet((*face_alpha_it).second.first,
(*face_alpha_it).second.second);
}
}
}
}
return result;
}
//---------------------------------------------------------------------
template < class Dt >
typename Alpha_shape_3<Dt>::Classification_type
Alpha_shape_3<Dt>::classify(const Cell_handle& s,
const int& i,
const Coord_type& alpha) const
// Classifies the face `f' of the underlying Delaunay
// tetrahedralization with respect to `A'.
{
// the version that uses a simplified version without crosslinks
// is much slower
if (is_infinite(s, i))
return EXTERIOR;
Interval3 interval = find_interval(Facet (s, i));
if (alpha <= interval.second)
{
if (get_mode() == REGULARIZED ||
interval.first == UNDEFINED ||
alpha <= interval.first)
return EXTERIOR;
else // alpha > interval.first
return SINGULAR;
}
else // alpha > interval.second
{
if (interval.third == Infinity ||
alpha <= interval.third)
return REGULAR;
else // alpha > interval.third
return INTERIOR;
}
}
//---------------------------------------------------------------------
template < class Dt >
typename Alpha_shape_3<Dt>::Classification_type
Alpha_shape_3<Dt>::classify(const Cell_handle& s,
const int& i,
const int& j,
const Coord_type& alpha) const
// Classifies the edge `e' of the underlying Delaunay
// tetrahedralization with respect to `A'.
{
// the version that uses a simplified version without crosslinks
// is much slower
if (is_infinite(s, i, j))
return EXTERIOR;
// FIX SUGGESTED BY JUR VAN DER BERG
//Interval3 interval = find_interval((const Edge)(s,i,j));
Interval3 interval = s->get_edge_ranges(i, j);
// (*(_facet_interval_map.find(const_facet(s, i)))).second;
if (alpha <= interval.second)
{
if (get_mode() == REGULARIZED ||
interval.first == UNDEFINED ||
alpha <= interval.first)
return EXTERIOR;
else // alpha > interval.first
return SINGULAR;
}
else // alpha > interval.second
{
if (interval.third == Infinity ||
alpha <= interval.third)
return REGULAR;
else // alpha > interval.third
return INTERIOR;
}
}
//---------------------------------------------------------------------
template < class Dt >
typename Alpha_shape_3<Dt>::Classification_type
Alpha_shape_3<Dt>::classify(const Vertex_handle& v,
const Coord_type& alpha) const
// Classifies the vertex `v' of the underlying Delaunay
// tetrahedralization with respect to `A'.
{
Interval2 interval = find_interval(v);
if (alpha <= interval.first)
{
if (get_mode() == REGULARIZED)
return EXTERIOR;
else // general => vertices are never exterior
return SINGULAR;
}
else // alpha > interval.first
{
if (interval.second == Infinity ||
alpha <= interval.second)
return REGULAR;
else // alpha > interval.second
return INTERIOR;
}
}
//--------------------- NB COMPONENTS ---------------------------------
template < class Dt >
int
Alpha_shape_3<Dt>::number_of_solid_components(const Coord_type& alpha) const
// Determine the number of connected solid components
// takes time O(#alpha_shape) amortized if STL_HASH_TABLES
// O(#alpha_shape log n) otherwise
{
Marked_cell_set marked_cell_set;
Finite_cells_iterator cell_it;
int nb_solid_components = 0;
// only finite simplices
for( cell_it = finite_cells_begin();
cell_it != finite_cells_end();
++cell_it)
{
Cell_handle pCell = cell_it->handle();
assert(pCell != NULL);
if (classify(pCell, alpha) == INTERIOR &&
((marked_cell_set.insert((Key)&(*pCell)))).second)
// we traverse only interior simplices
{
traverse(pCell, marked_cell_set, alpha);
nb_solid_components++;
}
}
return nb_solid_components;
}
//----------------------------------------------------------------------
template < class Dt >
void Alpha_shape_3<Dt>::traverse(const Cell_handle& pCell,
Marked_cell_set& marked_cell_set,
const Coord_type alpha) const
{
for (int i=0; i<=3; i++)
{
Cell_handle pNeighbor = pCell->neighbor(i);
assert(pNeighbor != NULL);
if (classify(pNeighbor, alpha) == INTERIOR &&
((marked_cell_set.insert((Key)&(*pNeighbor)))).second)
traverse(pNeighbor, marked_cell_set, alpha);
}
}
//----------------------------------------------------------------------
template <class Dt>
typename Alpha_shape_3<Dt>::Alpha_iterator
Alpha_shape_3<Dt>::find_optimal_alpha(const int& nb_components)
// find the minimum alpha that satisfies the properties
// (1) nb_components solid components
// (2) all data points on the boundary or in its interior
{
Coord_type alpha = find_alpha_solid();
// from this alpha on the alpha_solid satisfies property (2)
Alpha_iterator first = alpha_lower_bound(alpha);
if (number_of_solid_components(alpha) == nb_components)
{
if ((first+1) < alpha_end())
return (first+1);
else
return first;
}
// do binary search on the alpha values
// number_of_solid_components() is a monotone function
// if we start with find_alpha_solid
Alpha_iterator last = alpha_end();
Alpha_iterator middle;
std::ptrdiff_t len = last - first - 1;
std::ptrdiff_t half;
while (len > 0)
{
half = len / 2;
middle = first + half;
#ifdef DEBUG
cerr << "first : " << *first << " last : "
<< ((first+len != last) ? *(first+len) : *(last-1))
<< " mid : " << *middle
<< " nb comps : " << number_of_solid_components(*middle) << std::endl;
#endif // DEBUG
if (number_of_solid_components(*middle) > nb_components)
{
first = middle + 1;
len = len - half -1;
}
else // number_of_solid_components(*middle) <= nb_components
{
len = half;
}
}
if ((first+1) < alpha_end())
return (first+1);
else
return first;
}
//----------------------------------------------------------------------
template <class Dt>
typename Alpha_shape_3<Dt>::Coord_type
Alpha_shape_3<Dt>::find_alpha_solid() const
// compute the minumum alpha such that all data points
// are either on the boundary or in the interior
// not necessarily connected
// starting point for searching
// takes O(#alpha_shape) time
{
Coord_type alpha_solid = 0;
Vertex_iterator vertex_it;
// at the moment all finite + infinite vertices
for( vertex_it = vertices_begin();
vertex_it != vertices_end();
++vertex_it)
{
if (!is_infinite(vertex_it->handle()))
{
// consider only finite vertices
Coord_type alpha_min_v = (--_interval_cell_map.end())->first;
//------------------------------------------
// Cell_circulator cell_circ =
// (*vertex_it)->incident_simplices(),
// done(cell_circ);
// do
// {
// Cell_handle s = (*cell_circ);
// if (! is_infinite(s))
// alpha_min_v = CGAL::min(find_interval(s),
// alpha_min_v);
// }
// while (++cell_circ != done);
//--------------------------------------------
// TBC if cell_circulator become available
// at the moment takes v*s time
Cell_iterator cell_it;
for( cell_it = cells_begin();
cell_it != cells_end();
++cell_it)
{
Cell_handle s = cell_it->handle();
if (s->has_vertex(vertex_it->handle()))
{
if (! is_infinite(s))
{
alpha_min_v = CGAL::min(find_interval(s),
alpha_min_v);
}
}
}
alpha_solid = CGAL::max(alpha_min_v, alpha_solid);
}
}
return alpha_solid;
}
//-------------------------------------------------------------------
CGAL_END_NAMESPACE
//-------------------------------------------------------------------
#include <CGAL/IO/alpha_shape_geomview_ostream_3.h>
#endif //CGAL_ALPHA_SHAPE_3_H