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

1958 lines
63 KiB
C
Raw Normal View History

// Copyright (c) 1997, 2012 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
2020-10-13 12:44:25 +00:00
// $URL: https://github.com/CGAL/cgal/blob/v5.1/Alpha_shapes_3/include/CGAL/Alpha_shape_3.h $
// $Id: Alpha_shape_3.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Tran Kai Frank DA <Frank.Da@sophia.inria.fr>
// Andreas Fabri <Andreas.Fabri@geometryfactory.com>
// Mariette Yvinec <Mariette.Yvinec@sophia.inria.fr>
#ifndef CGAL_ALPHA_SHAPE_3_H
#define CGAL_ALPHA_SHAPE_3_H
#include <CGAL/license/Alpha_shapes_3.h>
#include <CGAL/internal/Lazy_alpha_nt_3.h>
#include <CGAL/Alpha_shape_cell_base_3.h> // for Alpha_status
#include <CGAL/basic.h>
#include <CGAL/Compact_container.h>
#include <CGAL/iterator.h>
#include <CGAL/Object.h>
#include <CGAL/Unique_hash_map.h>
#ifdef CGAL_USE_GEOMVIEW
#include <CGAL/IO/Geomview_stream.h> // TBC
#endif
#include <CGAL/Triangulation_utils_3.h>
#include <boost/type_traits/is_same.hpp>
#include <algorithm>
#include <iostream>
#include <map>
#include <list>
#include <set>
#include <utility>
#include <vector>
//-------------------------------------------------------------------
namespace CGAL {
//-------------------------------------------------------------------
template < class Dt, class ExactAlphaComparisonTag = Tag_false >
class Alpha_shape_3 : public Dt
{
// DEFINITION The class Alpha_shape_3<Dt> represents the family
// of alpha-shapes for a set of points (or a set of weighted points)
// for all possible values of alpha. The alphashape is defined through
// the Delaunay tetrahedralization of the points
// (or the Regular tetrahedralization in case of weighted points)
// and depends on the value of a parameter called alpha.
// The alpha_shape is the domain of a subcomplex of this triangulation
// called the Alpha_complex. The alpha_complex includes any simplex
// having a circumscribing sphere (an orthogonal sphere
// in case of weighted points) empty of other points
// (or suborthogonal to other sites in case of weighted points)
// with squared radius equal or less than alpha
2020-10-13 12:44:25 +00:00
// The alpha_shapes comes in two versions : GENERAL or REGULARIZED
// where the REGULARIZED version is onbtaining by restricting the
// alpha complex ti is pure 3D component.
// The cells of the triangulation are classified as INTERIOR
2020-10-13 12:44:25 +00:00
// or EXTERIOR according to the value alpha_cell of their circumsphere
// squared radius compared to alpha.
// In GENERAL mode each k-dimensional simplex of the triangulation
2020-10-13 12:44:25 +00:00
// for (k=0,1,2)
// can be classified as EXTERIOR, SINGULAR, REGULAR
// or INTERIOR with respect to the alpha shape.
// In GENERAL mode a $k$ simplex is REGULAR if it is on the boundary
// of the alpha_complex and belongs to a $k+1$ simplex in the complex
// and it is SINGULAR simplex if it is a boundary simplex tht is not
// included in a $k+1$ simplex of the complex.
2020-10-13 12:44:25 +00:00
// In REGULARIZED mode each k-dimensional simplex of the triangulation
2020-10-13 12:44:25 +00:00
// for (k=0,1,2)
// can be classified as EXTERIOR, REGULAR
// or INTERIOR with respect to the alpha shape.
// A $k$ simplex is REGULAR if it is on the boundary of alpha complex
// and belong to a tetrahedral cell of the complex.
2020-10-13 12:44:25 +00:00
// Roughly, the Alpha_shapes data structure computes and stores,
// for each simplex
// the at most three critical value (alpha_min, alpha_mid and alpha_max)
// which compared to the actual alpha value
// determine the classification of the simplex.
//------------------------- TYPES ------------------------------------
public:
typedef Dt Triangulation;
typedef typename Dt::Geom_traits Gt;
typedef typename Dt::Triangulation_data_structure Tds;
// The Exact Comparison Tag cannot be used in conjonction with periodic triangulations
// because the periodic triangulations' point() function returns a temporary
// value while the lazy predicate evaluations that are used when the Exact tag
// is set to true rely on a permanent and safe access to the points.
CGAL_static_assertion(
(boost::is_same<ExactAlphaComparisonTag, Tag_false>::value) ||
(boost::is_same<typename Dt::Periodic_tag, Tag_false>::value));
//extra the type used for representing alpha according to ExactAlphaComparisonTag
typedef typename internal::Alpha_nt_selector_3<Gt,ExactAlphaComparisonTag,typename Dt::Weighted_tag>::Type_of_alpha NT;
typedef typename internal::Alpha_nt_selector_3<Gt,ExactAlphaComparisonTag,typename Dt::Weighted_tag>::Compute_squared_radius_3 Compute_squared_radius_3;
typedef NT FT;
typedef typename Gt::FT Coord_type;
//checks whether tags are correctly set in Vertex and Cell classes
CGAL_static_assertion( (boost::is_same<NT,typename Dt::Cell::NT>::value) );
CGAL_static_assertion( (boost::is_same<NT,typename Dt::Vertex::Alpha_status::NT>::value) );
typedef typename Dt::Point Point;
2020-10-13 12:44:25 +00:00
typedef typename Dt::Cell_handle Cell_handle;
typedef typename Dt::Vertex_handle Vertex_handle;
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::size_type size_type;
typedef typename Dt::Locate_type Locate_type;
typedef typename Dt::Weighted_tag Weighted_tag;
using Dt::dimension;
using Dt::finite_facets_begin;
using Dt::finite_facets_end;
using Dt::finite_edges_begin;
using Dt::finite_edges_end;
using Dt::finite_vertices_begin;
using Dt::finite_vertices_end;
using Dt::finite_cells_begin;
using Dt::finite_cells_end;
using Dt::vertex_triple_index;
using Dt::is_infinite;
using Dt::is_Gabriel;
using Dt::incident_cells;
using Dt::incident_vertices;
using Dt::incident_facets;
using Dt::locate;
using Dt::point;
using Dt::VERTEX;
using Dt::EDGE;
using Dt::FACET;
using Dt::CELL;
using Dt::OUTSIDE_CONVEX_HULL;
using Dt::OUTSIDE_AFFINE_HULL;
enum Classification_type {EXTERIOR,
SINGULAR,
REGULAR,
INTERIOR};
enum Mode {GENERAL, REGULARIZED};
typedef CGAL::Alpha_status< NT > Alpha_status;
typedef Compact_container<Alpha_status> Alpha_status_container;
2020-10-13 12:44:25 +00:00
typedef typename Alpha_status_container::const_iterator
Alpha_status_const_iterator;
2020-10-13 12:44:25 +00:00
typedef typename Alpha_status_container::iterator
Alpha_status_iterator;
typedef std::vector< NT > Alpha_spectrum;
typedef std::multimap< NT, Cell_handle > Alpha_cell_map;
typedef std::multimap< NT, Facet> Alpha_facet_map;
typedef std::multimap< NT, Edge > Alpha_edge_map;
typedef std::multimap< NT, Vertex_handle> Alpha_vertex_map;
typedef std::pair<Vertex_handle, Vertex_handle> Vertex_handle_pair;
typedef std::map<Vertex_handle_pair,Alpha_status_iterator> Edge_alpha_map;
2020-10-13 12:44:25 +00:00
typedef typename std::list< Vertex_handle >::iterator
Alpha_shape_vertices_iterator;
typedef typename std::list< Facet >::iterator
Alpha_shape_facets_iterator;
2020-10-13 12:44:25 +00:00
//test if a cell is exterior to the alphashape
class Exterior_cell_test{
const Alpha_shape_3 * _as;
public:
Exterior_cell_test() {}
Exterior_cell_test(const Alpha_shape_3 * as) {_as = as;}
bool operator() ( const Finite_cells_iterator& fci) const {
return _as->classify(fci) == EXTERIOR ;
}
};
typedef Filter_iterator< Finite_cells_iterator, Exterior_cell_test>
Alpha_shape_cells_iterator;
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 NT
private:
typedef Unique_hash_map<Cell_handle, bool > Marked_cell_set;
private:
NT _alpha;
NT _alpha_solid;
Mode _mode;
mutable bool use_vertex_cache;
mutable bool use_facet_cache;
// only finite facets and simplices are inserted into the maps
Alpha_cell_map alpha_cell_map;
Alpha_facet_map alpha_min_facet_map;
Alpha_edge_map alpha_min_edge_map;
Alpha_vertex_map alpha_min_vertex_map;
Alpha_spectrum alpha_spectrum;
Alpha_status_container alpha_status_container;
Edge_alpha_map edge_alpha_map;
//deprecated - for backward compatibility
mutable std::list< Vertex_handle > alpha_shape_vertices_list;
mutable std::list< Facet > alpha_shape_facets_list;
//------------------------- CONSTRUCTORS ------------------------------
public:
2020-10-13 12:44:25 +00:00
// Introduces an empty alpha-shape `A' for a
// alpha-value `alpha'.
Alpha_shape_3(NT alpha = 0,
Mode m = REGULARIZED)
: _alpha(alpha), _mode(m),
use_vertex_cache(false), use_facet_cache(false)
{}
Alpha_shape_3(Dt& dt, NT alpha = 0, Mode m = REGULARIZED)
2020-10-13 12:44:25 +00:00
:_alpha(alpha), _mode(m),
use_vertex_cache(false), use_facet_cache(false)
{
Dt::swap(dt);
if (dimension() == 3) initialize_alpha();
}
2020-10-13 12:44:25 +00:00
// Introduces an alpha-shape `A' for the alpha-value
// `alpha' that is initialized with the points in the range
// from first to last
2020-10-13 12:44:25 +00:00
template < class InputIterator >
Alpha_shape_3(const InputIterator& first,
const InputIterator& last,
const NT& alpha = 0,
Mode m = REGULARIZED)
: _alpha(alpha), _mode(m),
use_vertex_cache(false), use_facet_cache(false)
{
Dt::insert(first, last);
2020-10-13 12:44:25 +00:00
if (dimension() == 3) initialize_alpha();
}
2020-10-13 12:44:25 +00:00
public:
//----------------------- OPERATIONS ---------------------------------
2020-10-13 12:44:25 +00:00
template < class InputIterator >
std::ptrdiff_t make_alpha_shape(const InputIterator& first,
const InputIterator& last)
{
clear();
size_type n = Dt::insert(first, last);
if (dimension() == 3){
initialize_alpha();
}
return n;
}
2020-10-13 12:44:25 +00:00
// Introduces an alpha-shape `A'
// that is initialized with the points in the range
// from first to last
private :
//--------------------- INITIALIZATION OF PRIVATE MEMBERS -----------
// called with reinitialize=false on first initialization
// reinitialize=true when switching the mode.
void initialize_alpha_cell_map();
void initialize_alpha_facet_maps(bool reinitialize = false);
void initialize_alpha_edge_maps(bool reinitialize = false);
void initialize_alpha_vertex_maps(bool reinitialize = false);
void initialize_alpha_spectrum();
void initialize_alpha(bool reinitialize = false) {
if (reinitialize == false) initialize_alpha_cell_map();
initialize_alpha_facet_maps(reinitialize);
initialize_alpha_edge_maps(reinitialize);
initialize_alpha_vertex_maps(reinitialize);
initialize_alpha_spectrum();
}
private :
Vertex_handle_pair
make_vertex_handle_pair( Vertex_handle v1, Vertex_handle v2) const {
return v1 < v2 ? std::make_pair(v1,v2)
: std::make_pair(v2,v1);
}
Vertex_handle_pair
make_vertex_handle_pair(const Edge& e) const {
return make_vertex_handle_pair(e.first->vertex(e.second),
e.first->vertex(e.third));
}
// the version to be used with Tag_true is templated to avoid
// instanciation through explicit instantiation of the whole class
2020-10-13 12:44:25 +00:00
void set_alpha_min_of_vertices(Tag_false)
{
for( Finite_vertices_iterator vit = finite_vertices_begin();
vit != finite_vertices_end(); ++vit){
Alpha_status* as = vit->get_alpha_status();
2020-10-13 12:44:25 +00:00
as->set_is_Gabriel(true);
as->set_alpha_min(NT(0));
}
2020-10-13 12:44:25 +00:00
// insert a single vertex into the map because they all have the
// same alpha_min value
alpha_min_vertex_map.insert(typename Alpha_vertex_map::value_type
2020-10-13 12:44:25 +00:00
( NT(0), finite_vertices_begin()));
}
template <class Tag>
2020-10-13 12:44:25 +00:00
void set_alpha_min_of_vertices(Tag)
{
2020-10-13 12:44:25 +00:00
for( Finite_vertices_iterator vit = finite_vertices_begin();
vit != finite_vertices_end(); ++vit) {
if (is_Gabriel(vit)) {
2020-10-13 12:44:25 +00:00
Alpha_status* as = vit->get_alpha_status();
as->set_is_Gabriel(true);
as->set_alpha_min(squared_radius(vit));
alpha_min_vertex_map.insert(typename Alpha_vertex_map::value_type
(as->alpha_min(),vit));
}
}
return;
}
//---------------------------------------------------------------------
public:
void clear()
{
// clears the structure
alpha_status_container.clear();
Dt::clear();
alpha_cell_map.clear();
alpha_min_facet_map.clear();
alpha_min_edge_map.clear();
alpha_min_vertex_map.clear();
2020-10-13 12:44:25 +00:00
alpha_spectrum.clear();
alpha_shape_vertices_list.clear();
alpha_shape_facets_list.clear();
use_vertex_cache = false;
use_facet_cache = false;
}
//---------------------------------------------------------------------
public:
NT set_alpha(const NT& alpha)
// Sets the alpha-value to `alpha'. Precondition: `alpha' >= 0.
// Returns the previous alpha
{
NT previous_alpha = _alpha;
_alpha = alpha;
use_vertex_cache = false;
use_facet_cache = false;
return previous_alpha;
}
const NT& get_alpha() const
// Returns the current alpha-value.
{
return _alpha;
}
2020-10-13 12:44:25 +00:00
const NT& get_nth_alpha(int n) const
// Returns the n-th alpha-value.
// n < size()
{
2020-10-13 12:44:25 +00:00
CGAL_triangulation_assertion( n > 0 &&
n <= static_cast<int>(alpha_spectrum.size()) );
return alpha_spectrum[n-1];
}
2020-10-13 12:44:25 +00:00
size_type number_of_alphas() const
// Returns the number of different alpha-values
{
return alpha_spectrum.size();
}
const Edge_alpha_map* get_edge_alpha_map() const
{
return &edge_alpha_map;
2020-10-13 12:44:25 +00:00
}
//---------------------------------------------------------------------
private:
// the dynamic version is not yet implemented
// desactivate the tetrahedralization member functions
void 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;
if (previous_mode != _mode) {
2020-10-13 12:44:25 +00:00
initialize_alpha(true);
use_vertex_cache = false;
use_facet_cache = false;
}
return previous_mode;
}
Mode get_mode() const
// Returns whether `A' is general or regularized.
{
return _mode;
}
//---------------------------------------------------------------------
private:
void update_alpha_shape_vertex_list() const;
2020-10-13 12:44:25 +00:00
void update_alpha_shape_facet_list() const;
//---------------------------------------------------------------------
public:
Alpha_shape_vertices_iterator alpha_shape_vertices_begin() const
{
if(!use_vertex_cache) update_alpha_shape_vertex_list();
return alpha_shape_vertices_list.begin();
}
Alpha_shape_vertices_iterator Alpha_shape_vertices_begin() const
{
return alpha_shape_vertices_begin();
}
//---------------------------------------------------------------------
Alpha_shape_vertices_iterator alpha_shape_vertices_end() const
{
return alpha_shape_vertices_list.end();
}
Alpha_shape_vertices_iterator Alpha_shape_vertices_end() const
{
return alpha_shape_vertices_end();
}
//---------------------------------------------------------------------
Alpha_shape_facets_iterator alpha_shape_facets_begin() const
{
2020-10-13 12:44:25 +00:00
if(! use_facet_cache) update_alpha_shape_facet_list();
return alpha_shape_facets_list.begin();
}
Alpha_shape_facets_iterator Alpha_shape_facets_begin() const
{
return alpha_shape_facets_begin();
}
//---------------------------------------------------------------------
Alpha_shape_facets_iterator alpha_shape_facets_end() const
{
return alpha_shape_facets_list.end();
}
Alpha_shape_facets_iterator Alpha_shape_facets_end() const
{
return alpha_shape_facets_end();
}
2020-10-13 12:44:25 +00:00
Alpha_shape_cells_iterator alpha_shape_cells_begin() const
{
return CGAL::filter_iterator(finite_cells_end(),
2020-10-13 12:44:25 +00:00
Exterior_cell_test(this),
finite_cells_begin());
}
2020-10-13 12:44:25 +00:00
Alpha_shape_cells_iterator alpha_shape_cells_end() const
{
return CGAL::filter_iterator(finite_cells_end(),
2020-10-13 12:44:25 +00:00
Exterior_cell_test(this));
}
2020-10-13 12:44:25 +00:00
public:
// Traversal of the alpha-Values
2020-10-13 12:44:25 +00:00
//
// 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 NT.
Alpha_iterator alpha_begin() const { return alpha_spectrum.begin(); }
Alpha_iterator alpha_end() const {return alpha_spectrum.end();}
Alpha_iterator alpha_find(const NT& 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 std::find(alpha_spectrum.begin(),
2020-10-13 12:44:25 +00:00
alpha_spectrum.end(),
alpha);
}
Alpha_iterator alpha_lower_bound(const NT& alpha) const
// Returns an iterator pointing to the first element with
// alpha-value not less than `alpha'.
{
return std::lower_bound(alpha_spectrum.begin(),
2020-10-13 12:44:25 +00:00
alpha_spectrum.end(),
alpha);
}
Alpha_iterator alpha_upper_bound(const NT& alpha) const
// Returns an iterator pointing to the first element with
// alpha-value greater than `alpha'.
{
return std::upper_bound(alpha_spectrum.begin(),
2020-10-13 12:44:25 +00:00
alpha_spectrum.end(),
alpha);
}
//--------------------- PREDICATES -----------------------------------
public:
2020-10-13 12:44:25 +00:00
void compute_edge_status( const Cell_handle& c,
int i,
int j,
Alpha_status& as) const;
Classification_type classify(const Alpha_status& as, const NT& alpha) const;
Classification_type classify(const Alpha_status* as, const NT& alpha) const;
2020-10-13 12:44:25 +00:00
Classification_type classify(const Alpha_status_const_iterator as,
const NT& alpha) const;
public:
Classification_type classify(const Point& p) const
{
return classify(p, get_alpha());
}
2020-10-13 12:44:25 +00:00
Classification_type classify(const Point& p,
const NT& 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)
2020-10-13 12:44:25 +00:00
{
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());
}
2020-10-13 12:44:25 +00:00
Classification_type classify(const Cell_handle& s,
const NT& alpha) const
// Classifies the cell `f' of the underlying Delaunay
// tetrahedralization with respect to `A'.
// s->radius == alpha => f interior
{
if (is_infinite(s)) return EXTERIOR;
return (s->get_alpha() <= alpha) ? INTERIOR : EXTERIOR;
}
//---------------------------------------------------------------------
2020-10-13 12:44:25 +00:00
Classification_type classify(const Facet& f) const
2020-10-13 12:44:25 +00:00
{
return classify(f.first, f.second, get_alpha());
}
2020-10-13 12:44:25 +00:00
Classification_type classify(const Cell_handle& s, int i) const
{
return classify(s, i, get_alpha());
}
2020-10-13 12:44:25 +00:00
Classification_type classify(const Facet& f, const NT& alpha) const
{
return classify(f.first, f.second, alpha);
}
2020-10-13 12:44:25 +00:00
Classification_type classify(const Cell_handle& s,
int i,
const NT& alpha) const;
// Classifies the face `f' of the underlying Delaunay
// tetrahedralization with respect to `A'.
//---------------------------------------------------------------------
Classification_type classify(const Edge& e) const
2020-10-13 12:44:25 +00:00
{
return classify(e.first, e.second, e.third, get_alpha());
}
2020-10-13 12:44:25 +00:00
Classification_type classify(const Cell_handle& s,
int i,
int j) const
{
return classify(s, i, j, get_alpha());
}
Classification_type classify(const Edge& e,
2020-10-13 12:44:25 +00:00
const NT& alpha ) const
{
return classify(e.first, e.second, e.third, alpha);
}
2020-10-13 12:44:25 +00:00
Classification_type classify(const Cell_handle& s,
int i,
int j,
const NT& alpha) const;
// Classifies the edge `e' of the underlying Delaunay
// tetrahedralization with respect to `A'.
2020-10-13 12:44:25 +00:00
//---------------------------------------------------------------------
Classification_type classify(const Vertex_handle& v) const
{
return classify(v, get_alpha());
}
Classification_type classify(const Vertex_handle& v,
2020-10-13 12:44:25 +00:00
const NT& alpha) const;
// Classifies the vertex `v' of the underlying Delaunay
// tetrahedralization with respect to `A'.
//--------------------- NB COMPONENTS ---------------------------------
size_type
number_solid_components() const
{
return number_of_solid_components(get_alpha());
}
size_type
number_of_solid_components() const
{
return number_of_solid_components(get_alpha());
}
size_type
number_solid_components(const NT& alpha) const
{
return number_of_solid_components(alpha);
}
size_type
number_of_solid_components(const NT& alpha) const;
2020-10-13 12:44:25 +00:00
// 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(Cell_handle pCell,
2020-10-13 12:44:25 +00:00
Marked_cell_set& marked_cell_set,
const NT alpha) const;
//----------------------------------------------------------------------
public:
Alpha_iterator find_optimal_alpha(size_type nb_components) const;
// find the minimum alpha that satisfies the properties
// (1) all data points are on the boundary of some 3d component
// or in its interior
// (2) the nb of solid components is equal or less than nb_component
2020-10-13 12:44:25 +00:00
NT find_alpha_solid() const;
2020-10-13 12:44:25 +00:00
// compute the minumum alpha such that all data points
// are either on the boundary or in the interior
// not necessarily connected
2020-10-13 12:44:25 +00:00
// starting point for searching
// takes O(#alpha_shape) time
//------------------- GEOMETRIC PRIMITIVES ----------------------------
private:
NT squared_radius(const Cell_handle& s) const
{
return Compute_squared_radius_3()(*this)(point(s,0), point(s,1),
point(s,2), point(s,3));
}
NT squared_radius(const Cell_handle& s, const int& i) const
{
return Compute_squared_radius_3()(*this)(point(s,vertex_triple_index(i,0)),
point(s,vertex_triple_index(i,1)),
point(s,vertex_triple_index(i,2)));
}
NT squared_radius(const Facet& f) const {
return squared_radius(f.first, f.second);
}
NT squared_radius(const Cell_handle& s, const int& i, const int& j) const
{
return Compute_squared_radius_3()(*this)(point(s,i), point(s,j));
}
NT squared_radius(const Edge& e) const {
return squared_radius(e.first,e.second,e.third);
}
NT squared_radius(const Vertex_handle& v) const {
2020-10-13 12:44:25 +00:00
return Compute_squared_radius_3()(*this)(v->point());
}
//---------------------------------------------------------------------
private:
// prevent default copy constructor and default assigment
Alpha_shape_3(const Alpha_shape_3&);
void operator=(const Alpha_shape_3&);
//---------------------------------------------------------------------
2020-10-13 12:44:25 +00:00
public:
#ifdef CGAL_USE_GEOMVIEW
void show_triangulation_edges(Geomview_stream &gv) const;
void show_alpha_shape_faces(Geomview_stream &gv) const;
#endif
// to Debug
2020-10-13 12:44:25 +00:00
void print_maps() const;
void print_alphas() const;
void print_alpha_status( const Alpha_status& as) const;
2020-10-13 12:44:25 +00:00
// To extract the alpha_shape faces for a given alpha value
template<class OutputIterator>
2020-10-13 12:44:25 +00:00
OutputIterator get_alpha_shape_cells(OutputIterator it,
Classification_type type,
const NT& alpha) const
{
Finite_cells_iterator cit = finite_cells_begin();
for( ; cit != finite_cells_end() ; ++cit){
if (classify(cit, alpha) == type) *it++ = Cell_handle(cit);
}
return it;
}
template<class OutputIterator>
2020-10-13 12:44:25 +00:00
OutputIterator get_alpha_shape_facets(OutputIterator it,
Classification_type type,
const NT& alpha) const
{
Finite_facets_iterator fit = finite_facets_begin();
for( ; fit != finite_facets_end() ; ++fit){
if (classify(*fit, alpha) == type) *it++ = *fit;
}
return it;
}
template<class OutputIterator>
2020-10-13 12:44:25 +00:00
OutputIterator get_alpha_shape_edges(OutputIterator it,
Classification_type type,
const NT& alpha) const
{
Finite_edges_iterator eit = finite_edges_begin();
for( ; eit != finite_edges_end() ; ++eit){
if (classify(*eit, alpha) == type) *it++ = *eit;
}
return it;
}
template<class OutputIterator>
2020-10-13 12:44:25 +00:00
OutputIterator get_alpha_shape_vertices(OutputIterator it,
Classification_type type,
const NT& alpha) const
{
Finite_vertices_iterator vit = finite_vertices_begin();
for( ; vit != finite_vertices_end() ; ++vit){
if (classify(vit, alpha) == type) *it++ = Vertex_handle(vit);
}
return it;
}
Alpha_status
get_alpha_status(const Edge& e) const
{
return *edge_alpha_map.find(make_vertex_handle_pair(e))->second;
}
Alpha_status
get_alpha_status(const Facet& f) const
{
return *(f.first->get_facet_status(f.second));
}
template<class OutputIterator>
2020-10-13 12:44:25 +00:00
OutputIterator get_alpha_shape_cells(OutputIterator it,
Classification_type type) const
{ return get_alpha_shape_cells(it, type, get_alpha());}
template<class OutputIterator>
2020-10-13 12:44:25 +00:00
OutputIterator get_alpha_shape_facets(OutputIterator it,
Classification_type type) const
{ return get_alpha_shape_facets(it, type, get_alpha());}
template<class OutputIterator>
2020-10-13 12:44:25 +00:00
OutputIterator get_alpha_shape_edges(OutputIterator it,
Classification_type type) const
{ return get_alpha_shape_edges(it, type, get_alpha());}
template<class OutputIterator>
2020-10-13 12:44:25 +00:00
OutputIterator get_alpha_shape_vertices(OutputIterator it,
Classification_type type) const
{ return get_alpha_shape_vertices(it, type, get_alpha());}
2020-10-13 12:44:25 +00:00
template<class OutputIterator>
OutputIterator filtration_with_alpha_values(OutputIterator it) const
2020-10-13 12:44:25 +00:00
// scan the alpha_cell_map, alpha_min_facet_map, alpha_min_edge_map
// and alpha_min_vertex in GENERAL mode
// only alpha_cell_map in REGULARIZED mode
// and output all the faces in order of alpha value of their appearing
// in the alpha complexe
{
typename Alpha_cell_map::const_iterator cit ;
typename Alpha_facet_map::const_iterator fit ;
typename Alpha_edge_map::const_iterator eit ;
typename Alpha_vertex_map::const_iterator vit;
2020-10-13 12:44:25 +00:00
if (get_mode() == GENERAL) {
cit = alpha_cell_map.begin();
fit = alpha_min_facet_map.begin();
eit = alpha_min_edge_map.begin();
vit = alpha_min_vertex_map.begin();
}
else { //mode==REGULARIZED do not scan maps of Gabriel elements
cit = alpha_cell_map.begin();
fit = alpha_min_facet_map.end();
eit = alpha_min_edge_map.end();
vit = alpha_min_vertex_map.end();
}
2020-10-13 12:44:25 +00:00
// sets to avoid multiple output of the same face
// as a regular subfaces of different faces
std::set<Facet> facet_set;
std::set<Vertex_handle_pair> edge_set;
std::set<Vertex_handle> vertex_set;
NT alpha_current = 0;
while (cit != alpha_cell_map.end()) {
if ( vit != alpha_min_vertex_map.end()
&& (eit == alpha_min_edge_map.end() || (vit->first <= eit->first))
&& (fit == alpha_min_facet_map.end()|| (vit->first <= fit->first))
&& (cit == alpha_cell_map.end() || (vit->first <= cit->first)))
{
//advance on vit
filtration_set_management(vit, alpha_current,
facet_set, edge_set, vertex_set);
filtration_output(vit->first, vit->second, it);
vit++;
}
if ( eit != alpha_min_edge_map.end()
&& ( fit == alpha_min_facet_map.end() || (eit->first <= fit->first) )
&& ( cit == alpha_cell_map.end() || (eit->first <= cit->first) )
&& ( vit == alpha_min_vertex_map.end()|| (vit->first > eit->first) )
) { //advance on eit
filtration_set_management(eit, alpha_current,
facet_set, edge_set, vertex_set);
filtration_output(eit->first, eit->second, it, vertex_set);
eit++;
}
if ( fit != alpha_min_facet_map.end()
&& (cit == alpha_cell_map.end() || (fit->first <= cit->first))
&& (eit == alpha_min_edge_map.end() || (eit->first > fit->first))
&& (vit == alpha_min_vertex_map.end()|| (vit->first > fit->first))
) { //advance on fit
filtration_set_management(fit, alpha_current,
facet_set, edge_set, vertex_set);
filtration_output(fit->first, fit->second, it,
edge_set, vertex_set);
fit++;
}
if ( cit != alpha_cell_map.end()
&& (fit == alpha_min_facet_map.end() || (fit->first > cit->first) )
&& (eit == alpha_min_edge_map.end() || (eit->first > cit->first) )
&& (vit == alpha_min_vertex_map.end()|| (vit->first > cit->first) )
) { //advance on cit
filtration_set_management(cit, alpha_current,
facet_set, edge_set, vertex_set);
filtration_output(cit->first, cit->second, it,
facet_set, edge_set, vertex_set);
cit++;
}
}
return it;
}
template<class OutputIterator>
OutputIterator filtration(OutputIterator it) const
{
2020-10-13 12:44:25 +00:00
Dispatch_or_drop_output_iterator<std::tuple<CGAL::Object>, std::tuple<OutputIterator> > out(it);
return std::template get<0>( filtration_with_alpha_values(out) );
}
2020-10-13 12:44:25 +00:00
private:
template<class Alpha_face_iterator>
void
filtration_set_management ( Alpha_face_iterator afit,
NT& alpha_current,
std::set<Facet>& facet_set,
std::set<Vertex_handle_pair>& edge_set,
std::set<Vertex_handle>& vertex_set) const
{
if (afit->first != alpha_current) { //new alpha_value
alpha_current = afit->first;
facet_set.clear();
edge_set.clear();
vertex_set.clear();
}
return;
}
template<class OutputIterator>
OutputIterator
filtration_output( const NT & alpha,
2020-10-13 12:44:25 +00:00
Vertex_handle vh,
OutputIterator it,
Tag_true) const
{
*it++ = make_object(vh);
*it++ = alpha;
2020-10-13 12:44:25 +00:00
//std::cerr << "filtration " << alpha << " \t VERTEX " << std::endl;
return it;
}
2020-10-13 12:44:25 +00:00
template<class OutputIterator>
OutputIterator
filtration_output( const NT& alpha,
2020-10-13 12:44:25 +00:00
Vertex_handle vh,
OutputIterator it,
Tag_false) const
{
// when Delaunay, the alpha_min_vertex_map contains a single vertex
// because all vertices are Gabriel with the same alpha_min=0
// this affects only the GENERAL mode
if (get_mode() == GENERAL){
2020-10-13 12:44:25 +00:00
Finite_vertices_iterator vit=finite_vertices_begin();
for( ; vit != finite_vertices_end(); vit++) {
*it++ = make_object( Vertex_handle(vit));
*it++ = alpha;
2020-10-13 12:44:25 +00:00
}
}
else {
*it++ = make_object(vh);
*it++ = alpha;
}
2020-10-13 12:44:25 +00:00
//std::cerr << "filtration " << alpha << " \t VERTEX " << std::endl;
return it;
}
template<class OutputIterator>
OutputIterator
filtration_output( const NT& alpha,
Vertex_handle vh,
OutputIterator it) const
{
return filtration_output(alpha, vh, it, Weighted_tag());
}
template<class OutputIterator>
OutputIterator
filtration_output( const NT& alpha,
Edge e,
OutputIterator it,
std::set<Vertex_handle>& vertex_set) const
{
Vertex_handle vh[] = {e.first->vertex(e.second),
e.first->vertex(e.third)};
for(int i=0; i<2; i++) {
Alpha_status* as = vh[i]->get_alpha_status();
if ( (get_mode()== REGULARIZED || !as->is_Gabriel())
&& as->alpha_mid() == alpha
&& vertex_set.find(vh[i]) == vertex_set.end() ) {
filtration_output( alpha, vh[i], it);
vertex_set.insert(vh[i]);
}
}
*it++ = make_object(e);
*it++ = alpha;
//std::cerr << "filtration " << alpha << " \t EDGE " << std::endl;
return it;
}
template<class OutputIterator>
OutputIterator
filtration_output( const NT& alpha,
Facet f,
OutputIterator it,
std::set<Vertex_handle_pair>& edge_set,
std::set<Vertex_handle>& vertex_set ) const
{
Cell_handle c = f.first;
int facet_index = f.second;
for(int k=0; k<3; k++) {
int i = vertex_triple_index(facet_index, k );
int j = vertex_triple_index(facet_index, this->ccw(k));
Alpha_status as;
Vertex_handle_pair
vhp = make_vertex_handle_pair(c->vertex(i),c->vertex(j));
if (get_mode() == GENERAL) {
as = *(edge_alpha_map.find(vhp)->second);
}
else{ //no edge map in REGULARIZED mode - classify on the fly
compute_edge_status( c, i, j, as);
}
if ( (get_mode()== REGULARIZED || !as.is_Gabriel())
2020-10-13 12:44:25 +00:00
&& as.alpha_mid() == alpha
&& edge_set.find(vhp)== edge_set.end() ) {
filtration_output( alpha, make_triple(c,i,j), it, vertex_set);
edge_set.insert(vhp);
}
}
*it++ = make_object(f);
*it++ = alpha;
//std::cerr << "filtration " << alpha << " \t FACET " << std::endl;
return it;
}
template<class OutputIterator>
OutputIterator
filtration_output( const NT& alpha,
Cell_handle c,
OutputIterator it,
std::set<Facet>& facet_set,
std::set<Vertex_handle_pair>& edge_set,
std::set<Vertex_handle>& vertex_set) const
{
for(int i=0; i<4; i++) {
Alpha_status_iterator as = c->get_facet_status(i);
Facet f = std::make_pair(c,i);
if ((get_mode()== REGULARIZED || !as->is_Gabriel())
2020-10-13 12:44:25 +00:00
&& as->alpha_mid() == alpha
&& facet_set.find(f) == facet_set.end()
&& facet_set.find(std::make_pair(c->neighbor(i),
this->mirror_index(c, i)))
== facet_set.end()) {
filtration_output( alpha, f, it, edge_set, vertex_set);
facet_set.insert(f);
}
}
*it++ = make_object(c);
*it++ = alpha;
2020-10-13 12:44:25 +00:00
//std::cerr << "filtration " << alpha << " \t CELL " << std::endl;
return it;
}
};
//---------------------------------------------------------------------
//--------------------- MEMBER FUNCTIONS-------------------------------
//---------------------------------------------------------------------
//--------------------- INITIALIZATION OF PRIVATE MEMBERS -------------
2020-10-13 12:44:25 +00:00
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
void
Alpha_shape_3<Dt,EACT>::initialize_alpha_cell_map()
2020-10-13 12:44:25 +00:00
{
Finite_cells_iterator cell_it, done = finite_cells_end();
NT alpha ;
for( cell_it = finite_cells_begin(); cell_it != done; ++cell_it) {
alpha = squared_radius(cell_it);
alpha_cell_map.insert(typename Alpha_cell_map::value_type(alpha, cell_it));
// cross references
cell_it->set_alpha(alpha);
}
return;
}
//---------------------------------------------------------------------
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
void
Alpha_shape_3<Dt,EACT>::initialize_alpha_facet_maps(bool reinitialize)
{
2020-10-13 12:44:25 +00:00
Finite_facets_iterator fit;
Cell_handle pCell, pNeighbor ;
int i, iNeigh;
Alpha_status_iterator as;
if (!reinitialize) {
NT alpha_max, alpha_mid;
2020-10-13 12:44:25 +00:00
for( fit = finite_facets_begin();
fit != finite_facets_end(); ++fit) {
as = alpha_status_container.insert(Alpha_status());
2020-10-13 12:44:25 +00:00
pCell = fit->first;
i = fit->second;
pNeighbor = pCell->neighbor(i);
iNeigh = pNeighbor->index(pCell);
2020-10-13 12:44:25 +00:00
// not on the convex hull
2020-10-13 12:44:25 +00:00
if(!is_infinite(pCell) && !is_infinite(pNeighbor)) {
NT alpha_Cell = pCell->get_alpha();
NT alpha_Neighbor = pNeighbor->get_alpha();
if ( alpha_Cell < alpha_Neighbor) {
alpha_mid = alpha_Cell;
alpha_max = alpha_Neighbor;
}
else {
alpha_mid = alpha_Neighbor;
alpha_max = alpha_Cell;
}
as->set_is_on_chull(false);
as->set_alpha_mid(alpha_mid);
as->set_alpha_max(alpha_max);
// alpha_mid_facet_map.insert(typename
// Alpha_facet_map::value_type(alpha_mid, *fit));
}
else { // on the convex hull
2020-10-13 12:44:25 +00:00
alpha_mid = !is_infinite(pCell) ? pCell->get_alpha()
: pNeighbor->get_alpha();
as->set_alpha_mid(alpha_mid);
as->set_is_on_chull(true);
}
//cross links
pCell->set_facet_status(i, as);
pNeighbor->set_facet_status(iNeigh,as);
}
}
2020-10-13 12:44:25 +00:00
// initialize alpha_min if mode GENERAL
if(get_mode() == GENERAL && alpha_min_facet_map.empty()) {
//already done if !alpha_min_facet_map.empty()
NT alpha_min;
2020-10-13 12:44:25 +00:00
for( fit = finite_facets_begin();
fit != finite_facets_end(); ++fit) {
as = fit->first->get_facet_status(fit->second);
if (is_Gabriel(*fit)) {
2020-10-13 12:44:25 +00:00
as->set_is_Gabriel(true);
alpha_min = squared_radius(*fit);
as->set_alpha_min(alpha_min);
alpha_min_facet_map.insert(typename
Alpha_facet_map::value_type(alpha_min, *fit));
}
else{
as->set_is_Gabriel(false);
as->set_alpha_min(as->alpha_mid());
}
}
}
return;
}
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
void
Alpha_shape_3<Dt,EACT>::initialize_alpha_edge_maps(bool )
{
2020-10-13 12:44:25 +00:00
// alpha_status for edges, edge_alpha_map
// and alpha_mid_edge and alpha_min_edge
// are initialized only in GENERAL mode
if(get_mode() == REGULARIZED) {return;} //no_edge_map in REGULARIZED mode
if ( !edge_alpha_map.empty()) return; // already done
Finite_edges_iterator eit;
Alpha_status_iterator as;
2020-10-13 12:44:25 +00:00
for (eit = finite_edges_begin();
eit != finite_edges_end(); ++eit) {
as = alpha_status_container.insert(Alpha_status());
compute_edge_status(eit->first, eit->second, eit->third, *as);
if ( as->is_Gabriel()) {
alpha_min_edge_map.insert(typename
2020-10-13 12:44:25 +00:00
Alpha_edge_map::value_type(as->alpha_min(),
*eit));
}
//cross links
2020-10-13 12:44:25 +00:00
Vertex_handle_pair
vhp = make_vertex_handle_pair( eit->first->vertex(eit->second),
2020-10-13 12:44:25 +00:00
eit->first->vertex(eit->third));
edge_alpha_map.insert(std::make_pair(vhp, as));
}
return;
}
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
void
Alpha_shape_3<Dt,EACT>::initialize_alpha_vertex_maps(bool reinitialize)
{
2020-10-13 12:44:25 +00:00
//for a vertex
// alpha_max = max of alpha values of incident cells
// alpha_mid = min of alpha values of incident cells in REGULAR mode
// = min of alpha values of incidents faces in GENERAL mode
2020-10-13 12:44:25 +00:00
// alpha_min = -squared_radius of weighted point,
// if the vertex is Gabriel set only in GENERAL mode
NT alpha, alpha_mid;
Finite_vertices_iterator vit;
if (reinitialize == false) _alpha_solid = alpha_cell_map.begin()->first;
2020-10-13 12:44:25 +00:00
for( vit = finite_vertices_begin();
vit != finite_vertices_end(); ++vit) {
Alpha_status* as = vit->get_alpha_status();
if (reinitialize == false) {
2020-10-13 12:44:25 +00:00
// set is_on_chull, compute alpha_max
// and alpha_mid (version REGULAR)
// compute _alpha_solid (max of alpha_mid of vertices in REGULAR mode)
as->set_is_on_chull(false);
std::list<Cell_handle> incidents;
incident_cells(static_cast<Vertex_handle>(vit),
2020-10-13 12:44:25 +00:00
back_inserter(incidents));
typename std::list<Cell_handle>::iterator chit=incidents.begin();
if (is_infinite(*chit)) as->set_is_on_chull(true);
while (is_infinite(*chit)) ++chit; //skip infinte cells
alpha = (*chit)->get_alpha();
as->set_alpha_mid(alpha);
as->set_alpha_max(alpha);
++chit;
for( ; chit != incidents.end(); ++chit) {
2020-10-13 12:44:25 +00:00
if (is_infinite(*chit)) as->set_is_on_chull(true);
else {
alpha = (*chit)->get_alpha();
if (alpha < as->alpha_mid()) as->set_alpha_mid(alpha);
if (alpha > as->alpha_max()) as->set_alpha_max(alpha);
}
}
if (as->alpha_mid() > _alpha_solid) _alpha_solid = as->alpha_mid();
}
2020-10-13 12:44:25 +00:00
if (get_mode() == GENERAL) { //reset alpha_mid, set alph_min
std::list<Vertex_handle> incidentv;
incident_vertices(static_cast<Vertex_handle>(vit),
2020-10-13 12:44:25 +00:00
back_inserter(incidentv));
typename std::list<Vertex_handle>::iterator vvit=incidentv.begin();
for( ; vvit != incidentv.end(); ++vvit) {
2020-10-13 12:44:25 +00:00
if (!is_infinite(*vvit)) {
Vertex_handle_pair vhp = make_vertex_handle_pair( *vvit, vit);
Alpha_status_iterator asedge = edge_alpha_map[vhp];
alpha_mid = asedge->is_Gabriel() ? asedge->alpha_min()
: asedge->alpha_mid();
if ( alpha_mid < as->alpha_mid()) as->set_alpha_mid(alpha_mid);
}
}
}
if (get_mode()== REGULARIZED && reinitialize == true) {
// reset alpha_mid
std::list<Cell_handle> incidents;
incident_cells(static_cast<Vertex_handle>(vit),
2020-10-13 12:44:25 +00:00
back_inserter(incidents));
typename std::list<Cell_handle>::iterator chit=incidents.begin();
while (is_infinite(*chit)) ++chit; //skip infinte cells
alpha = (*chit)->get_alpha();
as->set_alpha_mid(alpha);
for( ; chit != incidents.end(); ++chit) {
2020-10-13 12:44:25 +00:00
if (is_infinite(*chit)) as->set_is_on_chull(true);
else {
alpha = (*chit)->get_alpha();
if (alpha < as->alpha_mid()) as->set_alpha_mid(alpha);
}
}
}
2020-10-13 12:44:25 +00:00
}
2020-10-13 12:44:25 +00:00
// set alpha_min in case GENERAL
if (get_mode() == GENERAL && alpha_min_vertex_map.empty()) {
set_alpha_min_of_vertices(Weighted_tag());
}
return;
}
//---------------------------------------------------------------------
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
void
Alpha_shape_3<Dt,EACT>::initialize_alpha_spectrum()
2020-10-13 12:44:25 +00:00
// merges the alpha values of alpha_cell_map
// and alpha_min_facet_map alpha_min_edge_map alpha_min_vertex in GENERAL mode
// only alpha_cell_map in REGULARIZED mode
{
typename Alpha_cell_map::iterator cit ;
typename Alpha_facet_map::iterator fit ;
typename Alpha_edge_map::iterator eit ;
typename Alpha_vertex_map::iterator vit;
alpha_spectrum.clear();
if (get_mode() == GENERAL) {
cit = alpha_cell_map.begin();
fit = alpha_min_facet_map.begin();
eit = alpha_min_edge_map.begin();
vit = alpha_min_vertex_map.begin();
alpha_spectrum.reserve(alpha_cell_map.size() +
2020-10-13 12:44:25 +00:00
alpha_min_facet_map.size() +
alpha_min_edge_map.size() +
alpha_min_vertex_map.size());
}
else {
alpha_spectrum.reserve(alpha_cell_map.size());
cit = alpha_cell_map.begin();
fit = alpha_min_facet_map.end();
eit = alpha_min_edge_map.end();
vit = alpha_min_vertex_map.end();
}
while (cit != alpha_cell_map.end() ||
2020-10-13 12:44:25 +00:00
fit != alpha_min_facet_map.end() ||
eit != alpha_min_edge_map.end() ) {
if ( cit != alpha_cell_map.end()
&& ( fit == alpha_min_facet_map.end() || !(fit->first < cit->first) )
&& ( eit == alpha_min_edge_map.end() || !(eit->first < cit->first) )
&& ( vit == alpha_min_vertex_map.end() || !(vit->first < cit->first) )
) { //advance on cit
if (alpha_spectrum.empty() || alpha_spectrum.back() < cit->first){
2020-10-13 12:44:25 +00:00
alpha_spectrum.push_back(cit->first);
}
cit++;
}
2020-10-13 12:44:25 +00:00
if ( fit != alpha_min_facet_map.end()
&& ( cit == alpha_cell_map.end() || !(cit->first < fit->first) )
&& ( eit == alpha_min_edge_map.end() || !(eit->first < fit->first) )
&& ( vit == alpha_min_vertex_map.end() || !(vit->first < fit->first) )
) { //advance on fit
if (alpha_spectrum.empty() || alpha_spectrum.back() < fit->first){
2020-10-13 12:44:25 +00:00
alpha_spectrum.push_back(fit->first);
}
fit++;
}
2020-10-13 12:44:25 +00:00
if ( eit != alpha_min_edge_map.end()
&& ( fit == alpha_min_facet_map.end() || !(fit->first < eit->first) )
&& ( cit == alpha_cell_map.end() || !(cit->first < eit->first) )
&& ( vit == alpha_min_vertex_map.end() || !(vit->first < eit->first) )
) { //advance on eit
if (alpha_spectrum.empty() || alpha_spectrum.back() < eit->first) {
2020-10-13 12:44:25 +00:00
alpha_spectrum.push_back(eit->first);
}
eit++;
}
2020-10-13 12:44:25 +00:00
if ( vit != alpha_min_vertex_map.end()
&& ( fit == alpha_min_facet_map.end() || !(fit->first < vit->first) )
&& ( cit == alpha_cell_map.end() || !(cit->first < vit->first) )
&& ( eit == alpha_min_edge_map.end() || !(eit->first < vit->first) )
) { //advance on vit
if (alpha_spectrum.empty() || alpha_spectrum.back() < vit->first) {
2020-10-13 12:44:25 +00:00
alpha_spectrum.push_back(vit->first);
}
vit++;
}
}
}
2020-10-13 12:44:25 +00:00
//---------------------------------------------------------------------
#if 0
// Obviously not ready yet
template <class Dt,class EACT>
std::istream& operator>>(std::istream& is, const Alpha_shape_3<Dt,EACT>& A)
// Reads a alpha shape from stream `is' and assigns it to
// Unknown creationvariable. Precondition: The extract operator must
// be defined for `Point'.
{}
#endif
//---------------------------------------------------------------------
template <class Dt,class EACT>
std::ostream& operator<<(std::ostream& os, const Alpha_shape_3<Dt,EACT>& A)
2020-10-13 12:44:25 +00:00
// Inserts the alpha shape into the stream `os' as an indexed face set.
// Precondition: The insert operator must be defined for `Point'
{
typedef Alpha_shape_3<Dt,EACT> AS;
typedef typename AS::size_type size_type;
typedef typename AS::Vertex_handle Vertex_handle;
typedef typename AS::Cell_handle Cell_handle;
2020-10-13 12:44:25 +00:00
typedef typename AS::Alpha_shape_vertices_iterator
Alpha_shape_vertices_iterator;
typedef typename AS::Alpha_shape_facets_iterator
Alpha_shape_facets_iterator;
Unique_hash_map< Vertex_handle, size_type > V;
size_type number_of_vertices = 0;
Alpha_shape_vertices_iterator vit;
for( vit = A.alpha_shape_vertices_begin();
vit != A.alpha_shape_vertices_end();
++vit) {
V[*vit] = number_of_vertices++;
os << (*vit)->point() << std::endl;
}
Cell_handle c;
int i;
Alpha_shape_facets_iterator fit;
for( fit = A.alpha_shape_facets_begin();
fit != A.alpha_shape_facets_end();
++fit) {
c = fit->first;
i = fit->second;
// the following ensures that regular facets are output
// in ccw order
if (A.classify(*fit) == AS::REGULAR && (A.classify(c) == AS::INTERIOR)){
c = c->neighbor(i);
i = c->index(fit->first);
}
int i0 = Triangulation_utils_3::vertex_triple_index(i,0);
int i1 = Triangulation_utils_3::vertex_triple_index(i,1);
int i2 = Triangulation_utils_3::vertex_triple_index(i,2);
2020-10-13 12:44:25 +00:00
os << V[c->vertex(i0)] << ' '
<< V[c->vertex(i1)] << ' '
<< V[c->vertex(i2)] << std::endl;
}
return os;
}
//---------------------------------------------------------------------
template <class Dt,class EACT>
void
Alpha_shape_3<Dt,EACT>::update_alpha_shape_vertex_list() const
{
alpha_shape_vertices_list.clear();
use_vertex_cache = true;
std::back_insert_iterator<std::list< Vertex_handle > >
it = back_inserter(alpha_shape_vertices_list);
get_alpha_shape_vertices(it, REGULAR);
if (get_mode()==GENERAL) get_alpha_shape_vertices(it, SINGULAR);
2020-10-13 12:44:25 +00:00
return;
}
2020-10-13 12:44:25 +00:00
//---------------------------------------------------------------------
template <class Dt,class EACT>
void
Alpha_shape_3<Dt,EACT>::update_alpha_shape_facet_list() const
{
alpha_shape_facets_list.clear();
use_facet_cache = true;
// Writes the faces of the alpha shape `A' for the current 'alpha'-value
// to the container where 'out' refers to.
std::back_insert_iterator<std::list< Facet> >
it = back_inserter(alpha_shape_facets_list);
get_alpha_shape_facets(it, REGULAR);
if (get_mode()==GENERAL) get_alpha_shape_facets(it, SINGULAR);
2020-10-13 12:44:25 +00:00
return;
}
//---------------------------------------------------------------------
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
typename Alpha_shape_3<Dt,EACT>::Classification_type
Alpha_shape_3<Dt,EACT>::classify(const Alpha_status& as,
2020-10-13 12:44:25 +00:00
const NT& alpha) const
{
//tetrahedra with circumradius=alpha are considered inside
if ( !as.is_on_chull() && alpha >= as.alpha_max()) return INTERIOR;
else if ( alpha >= as.alpha_mid()) return REGULAR;
2020-10-13 12:44:25 +00:00
else if ( get_mode() == GENERAL &&
as.is_Gabriel() &&
alpha >= as.alpha_min()) return SINGULAR;
else return EXTERIOR;
}
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
typename Alpha_shape_3<Dt,EACT>::Classification_type
Alpha_shape_3<Dt,EACT>::classify(const Alpha_status* as,
2020-10-13 12:44:25 +00:00
const NT& alpha) const
{
//tetrahedra with circumradius=alpha are considered inside
if ( !as->is_on_chull() && alpha >= as->alpha_max()) return INTERIOR;
else if ( alpha >= as->alpha_mid()) return REGULAR;
2020-10-13 12:44:25 +00:00
else if ( get_mode() == GENERAL &&
as->is_Gabriel() &&
alpha >= as->alpha_min()) return SINGULAR;
else return EXTERIOR;
}
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
typename Alpha_shape_3<Dt,EACT>::Classification_type
Alpha_shape_3<Dt,EACT>::classify(Alpha_status_const_iterator as,
2020-10-13 12:44:25 +00:00
const NT& alpha) const
{
return classify(&(*as), alpha);
}
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
typename Alpha_shape_3<Dt,EACT>::Classification_type
Alpha_shape_3<Dt,EACT>::classify(const Cell_handle& s,
int i,
const NT& alpha) const
// Classifies the face `f' of the underlying Delaunay
// tetrahedralization with respect to `A'.
2020-10-13 12:44:25 +00:00
{
if (is_infinite(s,i)) return EXTERIOR;
Alpha_status_iterator as = s->get_facet_status(i);
return classify(as, alpha);
}
2020-10-13 12:44:25 +00:00
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
typename Alpha_shape_3<Dt,EACT>::Classification_type
Alpha_shape_3<Dt,EACT>::classify(const Cell_handle& c,
int i,
int j,
const NT& alpha) const
// Classifies the edge `e' of the underlying Delaunay
// tetrahedralization with respect to `A'.
2020-10-13 12:44:25 +00:00
{
if (is_infinite(c, i, j)) return EXTERIOR;
if (get_mode() == GENERAL) {
Alpha_status_iterator asit;
Vertex_handle_pair
vhp=make_vertex_handle_pair(c->vertex(i),c->vertex(j));
asit = edge_alpha_map.find(vhp)->second;
return classify(asit,alpha);
}
2020-10-13 12:44:25 +00:00
//no edge map in REGULARIZED mode - classify on the fly
Alpha_status as;
compute_edge_status( c, i, j, as);
return classify(as, alpha);
}
template <class Dt,class EACT>
void
Alpha_shape_3<Dt,EACT>::
2020-10-13 12:44:25 +00:00
compute_edge_status( const Cell_handle& c,
int i,
int j,
Alpha_status& as) const
{
Facet_circulator fcirc, done;
Alpha_status_iterator asf;
NT alpha;
as.set_is_on_chull(false);
2020-10-13 12:44:25 +00:00
Cell_circulator ccirc, last;
ccirc = incident_cells(c,i,j);
last=ccirc;
while (is_infinite(ccirc) ) ++ccirc; //skip infinite incident cells
alpha = (*ccirc).get_alpha();
as.set_alpha_mid(alpha); // initialise as.alpha_mid to alpha value of an incident cell
2020-10-13 12:44:25 +00:00
as.set_alpha_max(alpha); // same for as.alpha_max
while (++ccirc != last)
{
if (!is_infinite(ccirc)) {
alpha = (*ccirc).get_alpha();
if (alpha < as.alpha_mid())
as.set_alpha_mid(alpha);
if ( ! as.is_on_chull()) {
if( as.alpha_max() < alpha)
as.set_alpha_max( alpha );
}
}
2020-10-13 12:44:25 +00:00
}
fcirc = incident_facets(c,i,j);
2020-10-13 12:44:25 +00:00
done = fcirc;
do {
if (!is_infinite(*fcirc)) {
asf = (*fcirc).first->get_facet_status((*fcirc).second);
if (get_mode() == GENERAL && asf->is_Gabriel()){
alpha = asf->alpha_min();
if (alpha < as.alpha_mid()) as.set_alpha_mid(alpha);
}
if (asf->is_on_chull())
as.set_is_on_chull(true);
}
2020-10-13 12:44:25 +00:00
} while (++fcirc != done);
// initialize alphamin
if ( get_mode() == GENERAL){
if (is_Gabriel(c,i,j)) {
alpha = squared_radius(c,i,j);
as.set_is_Gabriel(true);
as.set_alpha_min(alpha);
}
else{
as.set_is_Gabriel(false);
as.set_alpha_min(as.alpha_mid());
}
2020-10-13 12:44:25 +00:00
}
}
//---------------------------------------------------------------------
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
typename Alpha_shape_3<Dt,EACT>::Classification_type
Alpha_shape_3<Dt,EACT>::classify(const Vertex_handle& v,
2020-10-13 12:44:25 +00:00
const NT& alpha) const
// Classifies the vertex `v' of the underlying Delaunay
// tetrahedralization with respect to `A'.
{
if (is_infinite(v)) return EXTERIOR;
Alpha_status* as = v->get_alpha_status();
return classify(as, alpha);
}
//--------------------- NB COMPONENTS ---------------------------------
template <class Dt,class EACT>
typename Alpha_shape_3<Dt,EACT>::size_type
Alpha_shape_3<Dt,EACT>::number_of_solid_components(const NT& alpha) const
2020-10-13 12:44:25 +00:00
// Determine the number of connected solid components
// takes time O(#alpha_shape) amortized if STL_HASH_TABLES
// O(#alpha_shape log n) otherwise
{
typedef typename Marked_cell_set::Data Data;
Marked_cell_set marked_cell_set(false);
Finite_cells_iterator cell_it, done = finite_cells_end();
size_type nb_solid_components = 0;
// only finite simplices
for( cell_it = finite_cells_begin(); cell_it != done; ++cell_it)
{
Cell_handle pCell = cell_it;
2020-10-13 12:44:25 +00:00
CGAL_triangulation_assertion(pCell != nullptr);
if (classify(pCell, alpha) == INTERIOR){
2020-10-13 12:44:25 +00:00
Data& data = marked_cell_set[pCell];
if(data == false) {
// we traverse only interior simplices
data = true;
traverse(pCell, marked_cell_set, alpha);
nb_solid_components++;
}
}
}
return nb_solid_components;
}
template <class Dt,class EACT>
void Alpha_shape_3<Dt,EACT>::traverse(Cell_handle pCell,
2020-10-13 12:44:25 +00:00
Marked_cell_set& marked_cell_set,
const NT alpha) const
{
typedef typename Marked_cell_set::Data Data;
std::list<Cell_handle> cells;
cells.push_back(pCell);
Cell_handle pNeighbor;
while(! cells.empty()){
pCell = cells.back();
cells.pop_back();
for (int i=0; i<=3; i++)
{
2020-10-13 12:44:25 +00:00
pNeighbor = pCell->neighbor(i);
CGAL_triangulation_assertion(pNeighbor != nullptr);
if (classify(pNeighbor, alpha) == INTERIOR){
Data& data = marked_cell_set[pNeighbor];
if(data == false){
data = true;
cells.push_back(pNeighbor);
}
}
}
2020-10-13 12:44:25 +00:00
}
}
//----------------------------------------------------------------------
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
typename Alpha_shape_3<Dt,EACT>::Alpha_iterator
Alpha_shape_3<Dt,EACT>::find_optimal_alpha(size_type nb_components) const
// find the minimum alpha that satisfies the properties
// (1) nb_components solid components <= nb_components
// (2) all data points on the boundary or in its interior
{
NT alpha = find_alpha_solid();
// from this alpha on the alpha_solid satisfies property (2)
2020-10-13 12:44:25 +00:00
Alpha_iterator first = alpha_lower_bound(alpha);
if (number_of_solid_components(alpha) == nb_components)
{
2020-10-13 12:44:25 +00:00
// if ((first+1) < alpha_end())
// return (first+1);
// else
return first;
}
// do binary search on the alpha values
2020-10-13 12:44:25 +00:00
// number_of_solid_components() is a monotone function
// if we start with find_alpha_solid
2020-10-13 12:44:25 +00:00
Alpha_iterator last = alpha_end();
Alpha_iterator middle;
2020-10-13 12:44:25 +00:00
std::ptrdiff_t len = last - first - 1;
std::ptrdiff_t half;
while (len > 0)
{
half = len / 2;
middle = first + half;
#ifdef CGAL_DEBUG_ALPHA_SHAPE_3
std::cerr << "first : " << *first
<< " last : "
<< ((first+len != last) ? *(first+len) : *(last-1))
<< " mid : " << *middle
<< " nb comps : " << number_of_solid_components(*middle)
<< std::endl;
#endif
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;
}
}
#ifdef CGAL_DEBUG_ALPHA_SHAPE_3
std::cerr << "In the end: " << std::endl
<< "first : " << *first
<< " nb comps : " << number_of_solid_components(*first)
<< std::endl;
if ((first+1) < alpha_end())
std::cerr << "first+1 " << *(first+1)
<< " nb comps : " << number_of_solid_components(*(first+1))
<< std::endl;
std::cerr << std::endl;
#endif
if (number_of_solid_components(*first) <= nb_components )
return first;
else
return first+1;
}
//----------------------------------------------------------------------
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
typename Alpha_shape_3<Dt,EACT>::NT
Alpha_shape_3<Dt,EACT>::find_alpha_solid() const
2020-10-13 12:44:25 +00:00
// compute the minumum alpha such that all data points
// are either on the boundary or in the interior
// not necessarily connected
{
return _alpha_solid;
}
// TO DEBUG
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
void
Alpha_shape_3<Dt,EACT>::print_maps() const
{
typename Alpha_cell_map::const_iterator cit ;
typename Alpha_facet_map::const_iterator fit ;
typename Alpha_edge_map::const_iterator eit ;
typename Alpha_vertex_map::const_iterator vit;
2020-10-13 12:44:25 +00:00
std::cerr << "size of cell map " << alpha_cell_map.size()
<< std::endl;
std::cerr << "size of facet map " << alpha_min_facet_map.size() <<
std::endl;
std::cerr << "size of edge map " << alpha_min_edge_map.size() <<
std::endl;
std::cerr << "size of vertex map " << alpha_min_vertex_map.size() <<
std::endl;
std::cerr << std::endl;
std::cerr << "alpha_cell_map " << std::endl;
for(cit = alpha_cell_map.begin();
cit != alpha_cell_map.end(); ++cit) {
std::cerr << cit->first << std::endl;
}
std::cerr << std::endl;
std::cerr << "alpha_min_facet_map " << std::endl;
for(fit = alpha_min_facet_map.begin();
fit != alpha_min_facet_map.end(); ++fit) {
std::cerr << fit->first << std::endl;
}
std::cerr << std::endl;
std::cerr << "alpha_min_edge_map " << std::endl;
for(eit = alpha_min_edge_map.begin();
eit != alpha_min_edge_map.end(); ++eit) {
std::cerr << eit->first << std::endl;
}
std::cerr << std::endl;
std::cerr << "alpha_min_vertex_map " << std::endl;
for(vit = alpha_min_vertex_map.begin();
vit != alpha_min_vertex_map.end(); ++vit) {
std::cerr << vit->first << std::endl;
}
std::cerr << std::endl;
}
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
void
Alpha_shape_3<Dt,EACT>::print_alphas() const
{
std::cerr << std::endl;
std::cerr << " alpha values of facets" << std::endl;
for(Finite_facets_iterator fit = finite_facets_begin();
fit != finite_facets_end();
++fit) {
Alpha_status_iterator as = fit->first->get_facet_status(fit->second);
print_alpha_status(*as);
}
std::cerr << std::endl;
std::cerr << " alpha values of edges " << std::endl;
if (get_mode() == GENERAL) {
for(Finite_edges_iterator eit = finite_edges_begin();
2020-10-13 12:44:25 +00:00
eit != finite_edges_end();
++eit) {
Vertex_handle_pair
vhp = make_vertex_handle_pair(eit->first->vertex(eit->second),
eit->first->vertex(eit->third));
Alpha_status_iterator as = edge_alpha_map.find(vhp)->second;
print_alpha_status(*as);
}
}
std::cerr << std::endl;
std::cerr << " alpha values of vertices " << std::endl;
for(Finite_vertices_iterator vit = finite_vertices_begin();
vit != finite_vertices_end();
++vit) {
Alpha_status* as = vit->get_alpha_status();
print_alpha_status(*as);
}
}
template <class Dt,class EACT>
2020-10-13 12:44:25 +00:00
void
Alpha_shape_3<Dt,EACT>::print_alpha_status(const Alpha_status& as) const
{
if ( get_mode() == GENERAL && as.is_Gabriel())
std::cerr << as.alpha_min() ;
else std::cerr << "--- " ;
std::cerr << "\t";
std::cerr << as.alpha_mid() << "\t";
if(as.is_on_chull()) std::cerr << "--- ";
else std::cerr << as.alpha_max();
std::cerr << std::endl;
}
} //namespace CGAL
#ifdef CGAL_USE_GEOMVIEW
#include <CGAL/IO/alpha_shape_geomview_ostream_3.h>
#endif
#endif //CGAL_ALPHA_SHAPE_3_H