dust3d/thirdparty/cgal/CGAL-4.13/include/CGAL/Fixed_alpha_shape_3.h

1125 lines
39 KiB
C
Raw Normal View History

// Copyright (c) 2009 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the so
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Sebastien Loriot
//
#ifndef CGAL_FIXED_ALPHA_SHAPE_3_H
#define CGAL_FIXED_ALPHA_SHAPE_3_H
#include <CGAL/license/Alpha_shapes_3.h>
#include <CGAL/basic.h>
#include <set>
#include <map>
#include <list>
#include <vector>
#include <algorithm>
#include <utility>
#include <iostream>
#include <queue>
#include <boost/next_prior.hpp>
#include <CGAL/Triangulation_utils_3.h>
#include <CGAL/Unique_hash_map.h>
#include <CGAL/iterator.h>
#ifdef CGAL_USE_GEOMVIEW
#include <CGAL/IO/Geomview_stream.h> // TBC
#endif
#include <CGAL/internal/Classification_type.h>
#include <CGAL/Triangulation_3.h>
namespace CGAL{
namespace internal{
//small utility to select the correct predicate in the weighted case
template <class One_alpha,class Weighted_tag>
struct Simplex_classif_predicate;
template <class One_alpha>
struct Simplex_classif_predicate<One_alpha,Tag_false>{
static
typename One_alpha::Triangulation::Geom_traits::Compare_squared_radius_3
predicate(const typename One_alpha::Triangulation& T){
return T.geom_traits().compare_squared_radius_3_object();
}
};
template <class One_alpha>
struct Simplex_classif_predicate<One_alpha,Tag_true>{
static
typename One_alpha::Triangulation::Geom_traits::Compare_weighted_squared_radius_3
predicate(const typename One_alpha::Triangulation& T){
return T.geom_traits().compare_weighted_squared_radius_3_object();
}
};
//small utility to insert hidden vertices after a removal (in non-weighted case do nothing)
template <class One_alpha,class Weighted_tag=::CGAL::Tag_true>
struct Hidden_inserter
{
typedef typename One_alpha::Triangulation Dt;
template <class Vertex_remover>
static void insert(One_alpha& one_alpha, Vertex_remover& remover)
{
typename One_alpha::Cell_handle c;
for (typename Vertex_remover::Hidden_points_iterator
hi = remover.hidden_points_begin();
hi != remover.hidden_points_end(); ++hi)
{
typename One_alpha::Vertex_handle hv = one_alpha.insert (*hi, c);
if (hv != typename One_alpha::Vertex_handle()) c = hv->cell();
}
}
};
template <class One_alpha>
struct Hidden_inserter<One_alpha,::CGAL::Tag_false>{
typedef typename One_alpha::Triangulation Dt;
template <class Vertex_remover>
static void insert(const One_alpha&,const Vertex_remover&){}
};
} //internal
template < class Dt >
class Fixed_alpha_shape_3 : public Dt
{
// DEFINITION The class Fixed_alpha_shape_3<Dt> represents the
// alpha-shape for a set of points (or a set of weighted points)
// for a given value 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
// In each k-dimensional simplex of the triangulation
// for (k=0,1,2)
// can be classified as EXTERIOR, SINGULAR, REGULAR
// or INTERIOR with respect to the alpha shape.
// 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.
// Roughly, the Fixed_alpha_shape data structure computes and stores,
// for each simplex it classification type.
//------------------------- TYPES ------------------------------------
public:
typedef Dt Triangulation;
typedef typename Dt::Geom_traits Gt;
typedef typename Dt::Triangulation_data_structure Tds;
//Classification type: no longer an enum inside the class as Vertex and cell must know it
typedef internal::Classification_type Classification_type;
static const Classification_type EXTERIOR = internal::EXTERIOR;
static const Classification_type REGULAR = internal::REGULAR;
static const Classification_type INTERIOR = internal::INTERIOR;
static const Classification_type SINGULAR = internal::SINGULAR;
typedef typename Gt::FT Coord_type;
typedef Coord_type NT;
typedef Coord_type FT;
typedef typename Dt::Point Point;
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::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::all_edges_begin;
using Dt::all_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;
using Dt::EDGE;
using Dt::FACET;
using Dt::CELL;
using Dt::OUTSIDE_CONVEX_HULL;
using Dt::OUTSIDE_AFFINE_HULL;
using Dt::vertex_triple_index;
using Dt::finite_adjacent_vertices;
using Dt::find_conflicts;
using Dt::is_edge;
using Dt::incident_vertices;
using Dt::incident_facets;
using Dt::is_infinite;
using Dt::is_Gabriel;
using Dt::tds;
typedef std::pair<Vertex_handle, Vertex_handle> Vertex_handle_pair;
typedef std::map<Vertex_handle_pair,Classification_type> Edge_status_map;
//test if a simplex is exterior to the alpha-shape
class Exterior_simplex_test{
const Fixed_alpha_shape_3 * _as;
public:
Exterior_simplex_test() {}
Exterior_simplex_test(const Fixed_alpha_shape_3 * as) {_as = as;}
bool operator() ( const Finite_cells_iterator& fci) const {
return _as->classify(fci) == EXTERIOR ;
}
bool operator() ( const Finite_vertices_iterator& fvi) const {
return _as->classify(fvi) == EXTERIOR ;
}
bool operator() ( const Finite_facets_iterator& ffi) const {
return _as->classify(*ffi) == EXTERIOR ;
}
bool operator() ( const Finite_edges_iterator& fei) const {
return _as->classify(*fei) == EXTERIOR ;
}
};
typedef Filter_iterator< Finite_vertices_iterator, Exterior_simplex_test> Alpha_shape_vertices_iterator;
typedef Filter_iterator< Finite_facets_iterator, Exterior_simplex_test> Alpha_shape_facets_iterator;
typedef Filter_iterator< Finite_edges_iterator, Exterior_simplex_test> Alpha_shape_edges_iterator;
typedef Filter_iterator< Finite_cells_iterator, Exterior_simplex_test> Alpha_shape_cells_iterator;
Vertex_handle
insert(const Point& p,Cell_handle start=Cell_handle())
{
if (this->dimension() < 3){
Vertex_handle new_v=Triangulation::insert(p,start);
if (this->dimension() == 3) initialize_alpha();
return new_v;
}
//Handle only case of dimension 3 of insert_in_conflict from Triangulation_3 class.
typename Triangulation::Locate_type lt;
int li, lj;
Cell_handle c = this->locate(p, lt, li, lj, start);
typename Triangulation::Conflict_tester_3 tester(p, this);
if ((lt == VERTEX) &&
(tester.compare_weight(c->vertex(li)->point(), p)==0) ) {
return c->vertex(li);
}
// If the new point is not in conflict with its cell, it is hidden.
if (!tester.test_initial_cell(c)) {
this->hidden_point_visitor.hide_point(c,p);
return Vertex_handle();
}
// Ok, we really insert the point now.
// First, find the conflict region.
std::vector<Cell_handle> cells;
std::vector<Facet> facets_on_the_boundary_of_the_hole;
cells.reserve(32);
this->find_conflicts
(c, tester, make_triple(std::back_inserter(facets_on_the_boundary_of_the_hole),
std::back_inserter(cells),
Emptyset_iterator()));
Facet facet=*boost::prior(facets_on_the_boundary_of_the_hole.end());
// Remember the points that are hidden by the conflicting cells,
// as they will be deleted during the insertion.
this->hidden_point_visitor.process_cells_in_conflict(cells.begin(), cells.end());
//Before insertion:
//recover edges on the boundary of the hole.
std::set<Edge,Compare_edge> hole_boundary_edges;
const int indices[3]={1,2,3};
for (typename std::vector<Facet>::iterator
it=facets_on_the_boundary_of_the_hole.begin();
it!=facets_on_the_boundary_of_the_hole.end();
++it)
{
Facet f=it->first->tds_data().is_in_conflict()?this->mirror_facet(*it):*it;
CGAL_precondition(!f.first->tds_data().is_in_conflict());
for (int i=0;i<3;++i){
Edge edge(f.first,(indices[i]+f.second)%4,(indices[(i+1)%3]+f.second)%4);
if (!this->is_infinite(edge))
hole_boundary_edges.insert(edge);
}
}
// Erase from edge_status_map, edges that will disappear:
// they are not on the boudary of the hole
std::set<Edge,Compare_edge> hole_edges;
std::pair<typename std::set<Edge,Compare_edge>::iterator,bool> it_hedge_and_not_already_seen;
for (typename std::vector<Cell_handle>::iterator it=cells.begin();it!=cells.end();++it){
for (int i=0;i<3;++i)
for (int k=i+1;k<4;++k)
{
Edge edge(*it,i,k);
if (this->is_infinite(edge) || hole_boundary_edges.find(edge)!=hole_boundary_edges.end() ) continue;
it_hedge_and_not_already_seen=hole_edges.insert(edge);
if (!it_hedge_and_not_already_seen.second){
edge_status_map.erase(make_vertex_handle_pair(*(it_hedge_and_not_already_seen.first))); //for infinite edges it does nothing
}
}
}
//Insertion using base triangulation
Vertex_handle v = this->_insert_in_hole(p, cells.begin(), cells.end(),
facet.first, facet.second);
//After insertion
//--set classification of new cells and facets that were on the boundary of the hole
cells.clear();
this->finite_incident_cells(v,std::back_inserter(cells));
for (typename std::vector<Cell_handle>::iterator it=cells.begin();it!=cells.end();++it){
set_cell_status(*it); //set cell status
set_facet_classification_type( Facet( (*it),(*it)->index(v) ) ); //set facet status (incident to one cell of the hole)
}
//--set classification of new facets
std::vector<Facet> facets;
this->finite_incident_facets(v,std::back_inserter(facets));
for (typename std::vector<Facet>::iterator fit=facets.begin();fit!=facets.end();++fit)
set_facet_classification_type(*fit);
//--init classif of new vertex
v->set_classification_type(SINGULAR);
std::vector<Edge> edges;
this->finite_incident_edges(v,std::back_inserter(edges));
//--set status of new edges + update status of new vertex
for (typename std::vector<Edge>::iterator eit=edges.begin();eit!=edges.end();++eit){
Classification_type status=compute_edge_status(eit->first, eit->second, eit->third);
Vertex_handle_pair vhp = make_vertex_handle_pair( *eit );
CGAL_precondition( edge_status_map.find(vhp)==edge_status_map.end() );
edge_status_map.insert(std::make_pair(vhp, status));
update_vertex_status(v,status);
}
//--set final status of new vertex
Cell_handle tmp;
int itmp1,itmp2;
v->is_on_chull( this->is_edge(this->infinite_vertex(),v,tmp,itmp1,itmp2) );
finalize_status_of_vertex(v);
//--set classification of old edges
for (typename std::set<Edge,Compare_edge>::iterator
eit=hole_boundary_edges.begin();eit!=hole_boundary_edges.end();++eit)
{
CGAL_precondition (!this->is_infinite(*eit));
Classification_type status=compute_edge_status(eit->first, eit->second, eit->third);
Vertex_handle_pair vhp = make_vertex_handle_pair( *eit );
typename Edge_status_map::iterator it_status=edge_status_map.find(vhp);
CGAL_precondition(it_status!=edge_status_map.end());
it_status->second = status;
}
//--set status of old vertices + update is_on_chull
//TODO: find a better way to do it : make an update
std::vector<Vertex_handle> vertices;
this->finite_adjacent_vertices(v,std::back_inserter(vertices));
for (typename std::vector<Vertex_handle>::iterator vit=vertices.begin();vit!=vertices.end();++vit){
if ( (*vit)->is_on_chull() )
{
(*vit)->is_on_chull( this->is_edge(this->infinite_vertex(),(*vit),tmp,itmp1,itmp2) );
}
set_vertex_status(*vit);
}
// Store the hidden points in their new cells.
this->hidden_point_visitor.reinsert_vertices(v);
return v;
}
void remove (Vertex_handle vertex_to_remove)
{
CGAL_precondition(vertex_to_remove!=Vertex_handle());
CGAL_precondition(vertex_to_remove!=this->infinite_vertex());
std::vector<Facet> link;
std::vector<Vertex_handle> vertices_to_update;
std::map<Vertex_handle,Classification_type> old_classification;
if (this->dimension() == 3)
{
//recover facet of the link: they are bounding
//the hole made when removing the vertex
std::vector<Cell_handle> incident_cells;
this->finite_incident_cells(vertex_to_remove,std::back_inserter(incident_cells));
for (typename std::vector<Cell_handle>::iterator it=
incident_cells.begin();it!=incident_cells.end();++it)
{
int index=(*it)->index(vertex_to_remove);
link.push_back( this->mirror_facet(Facet(*it,index)) );
CGAL_assertion (!this->is_infinite(link.back()));
}
//get vertices that will need to be updated
this->finite_adjacent_vertices(vertex_to_remove,std::back_inserter(vertices_to_update));
//1-erase removed edges from edge_map
//2-store old classification of vertices and set it to SINGULAR
for(typename std::vector<Vertex_handle>::iterator it=vertices_to_update.begin();it!=vertices_to_update.end();++it){
CGAL_precondition(edge_status_map.find(make_vertex_handle_pair(*it,vertex_to_remove)) != edge_status_map.end());
edge_status_map.erase(make_vertex_handle_pair(*it,vertex_to_remove));
old_classification.insert(std::make_pair(*it,(*it)->get_classification_type()));
(*it)->set_classification_type(SINGULAR);
}
}
//Do remove the vertex from the underlying triangulation
Dt tmp;
typename Dt:: template Vertex_remover<Dt> remover(tmp);
typedef typename Dt::Tr_Base Tr_Base;
Tr_Base::remove(vertex_to_remove,remover);
if (this->dimension()<3){
edge_status_map.clear();
return;
}
//recover new cells
std::set<Cell_handle> new_cells;//cells in the hole
std::set<Cell_handle> outer;//cells that are not in the hole
std::queue<Cell_handle> to_visit;
for (typename std::vector<Facet>::iterator it=link.begin();it!=link.end();++it){
Facet mirror_facet=this->mirror_facet(*it);
if ( !this->is_infinite(mirror_facet.first) )
{
to_visit.push( mirror_facet.first );
outer.insert(it->first);
}
}
while (!to_visit.empty()){
Cell_handle cell=to_visit.front();
to_visit.pop();
if ( !new_cells.insert(cell).second ) continue; //already explored
//explore neighbor cells
for (int i=0;i<4;++i){
Cell_handle candidate=cell->neighbor(i);
if ( !this->is_infinite(candidate) && outer.find(candidate)==outer.end())
to_visit.push(candidate);
}
}
//set status of new cells
for (typename std::set<Cell_handle>::iterator it=new_cells.begin();it!=new_cells.end();++it){
CGAL_precondition(!this->is_infinite(*it));
set_cell_status(*it);
}
//recover new facets + link facets
//set vertex that are on the convex hull (those on a facet incident to infinite cell)
while (!new_cells.empty())
{
Cell_handle cell=*new_cells.begin();
new_cells.erase(new_cells.begin());
for (int i=0;i<4;++i){
if ( new_cells.find(cell->neighbor(i)) != new_cells.end() )
link.push_back(Facet(cell,i));
else{
if ( this->is_infinite( cell->neighbor(i) ) ){
link.push_back(Facet(cell,i));
cell->vertex((i+1)%4)->is_on_chull(true);
cell->vertex((i+2)%4)->is_on_chull(true);
cell->vertex((i+3)%4)->is_on_chull(true);
}
}
}
}
std::set<Edge,Compare_edge> new_edges;
//1- set status of these facets
//2- recover new edges + edges incident to link facets
const int index[3]={1,2,3};
for (typename std::vector<Facet>::iterator it=link.begin();it!=link.end();++it){
set_facet_classification_type(*it);
for (int i=0;i<3;++i){
new_edges.insert(Edge(it->first,(it->second+index[i])%4,(it->second+index[(i+1)%3])%4));
}
}
//set status of these edges
for(typename std::set<Edge,Compare_edge>::iterator it=new_edges.begin();it!=new_edges.end();++it){
Classification_type status=compute_edge_status(it->first, it->second, it->third);
//cross links
Vertex_handle_pair vhp = make_vertex_handle_pair( *it );
edge_status_map[vhp]=status;
//update status of incident vertices
update_vertex_status(it->first->vertex(it->second),status);
update_vertex_status(it->first->vertex(it->third),status);
}
//set final status of vertices
for(typename std::vector<Vertex_handle>::iterator it=vertices_to_update.begin();it!=vertices_to_update.end();++it){
//this one is working but should be more expensive
//set_vertex_status(*it); continue;
Classification_type old_status=old_classification[*it];
Classification_type status=(*it)->get_classification_type();
CGAL_precondition( status!=SINGULAR ); // at least on edge is incident to that vertex
if (status==INTERIOR){
if (old_status!=INTERIOR || (*it)->is_on_chull())
(*it)->set_classification_type(REGULAR);
else
(*it)->set_classification_type(INTERIOR);
continue;
}
if (status==REGULAR) continue;
if ( status==EXTERIOR && ( old_status==REGULAR || old_status==INTERIOR) ){ //if vertex was EXTERIOR or SINGULAR other edges are not in the alpha complex
//check if former REGULAR vertex becomes EXTERIOR or SINGULAR
std::list<Vertex_handle> incidentv;
finite_adjacent_vertices(*it,back_inserter(incidentv));
typename std::list<Vertex_handle>::iterator vvit=incidentv.begin();
for( ; vvit != incidentv.end(); ++vvit) {
//TODO: We take all edges -> WE SHOULD ONLY TAKE THOSE NOT IN THE HOLE
Vertex_handle_pair vhp = make_vertex_handle_pair( *vvit, *it);
CGAL_assertion(edge_status_map.find(vhp)!=edge_status_map.end());
Classification_type status=edge_status_map[vhp];
if (status!=EXTERIOR){
(*it)->set_classification_type(REGULAR);
break;
}
}
if ( vvit != incidentv.end() ) continue;
}
if ( is_vertex_Gabriel((*it),Weighted_tag()) && is_gabriel_simplex_in_alpha_complex((*it)) )
(*it)->set_classification_type(SINGULAR);
else
(*it)->set_classification_type(EXTERIOR);
}
//Insert possible hidden points
internal::Hidden_inserter<Fixed_alpha_shape_3<Dt>,Weighted_tag>::insert(*this,remover);
}
private:
typedef internal::Simplex_classif_predicate<Fixed_alpha_shape_3<Dt>,Weighted_tag> Simplex_classif;
//data members
NT _alpha; //the value of alpha
Edge_status_map edge_status_map; //the map containing the status of edges
//------------------------- CONSTRUCTORS ------------------------------
public:
Fixed_alpha_shape_3(NT alpha=0):_alpha(alpha){}
Fixed_alpha_shape_3(Dt& dt, NT alpha = 0):_alpha(alpha){
Dt::swap(dt);
if (dimension() == 3) initialize_alpha();
}
// Introduces an alpha-shape `A' for the alpha-value
// `alpha' that is initialized with the points in the range
// from first to last
template < class InputIterator >
Fixed_alpha_shape_3(const InputIterator& first,
const InputIterator& last,
const NT& alpha = 0): _alpha(alpha)
{
Dt::insert(first, last);
if (dimension() == 3) initialize_alpha();
}
private :
template < class InputIterator >
int make_alpha_shape(const InputIterator& first,
const InputIterator& last)
{
clear();
int n = Dt::insert(first, last);
if (dimension() == 3) initialize_alpha();
return n;
}
//--------------------- INITIALIZATION OF PRIVATE MEMBERS -----------
void initialize_status_of_cells();
void initialize_status_of_facets();
void initialize_status_of_edges();
void initialize_status_of_vertices();
void finalize_status_of_vertex(Vertex_handle);
void initialize_alpha() {
//identify vertices on the convex hull
std::vector<Vertex_handle> chull;
incident_vertices(this->infinite_vertex(),std::back_inserter(chull));
for ( typename std::vector<Vertex_handle>::iterator it=chull.begin();it!=chull.end();++it)
(*it)->is_on_chull(true);
initialize_status_of_cells();
initialize_status_of_facets();
initialize_status_of_edges();
initialize_status_of_vertices();
}
private :
// prevent default copy constructor and default assigment
Fixed_alpha_shape_3(const Fixed_alpha_shape_3&);
void operator=(const Fixed_alpha_shape_3&);
static
Vertex_handle_pair
make_vertex_handle_pair( Vertex_handle v1, Vertex_handle v2) {
return v1 < v2 ? std::make_pair(v1,v2)
: std::make_pair(v2,v1);
}
static
Vertex_handle_pair
make_vertex_handle_pair( const Edge& e) {
return make_vertex_handle_pair(e.first->vertex(e.second),e.first->vertex(e.third));
}
struct Compare_edge{
bool operator()(const Edge& e1,const Edge& e2) const
{
return make_vertex_handle_pair(e1)<make_vertex_handle_pair(e2);
}
};
bool is_vertex_Gabriel(Vertex_handle,Tag_false){return true;}
template <class Vertexhandle>
bool is_vertex_Gabriel(Vertexhandle v,Tag_true){return is_Gabriel(v);}
void update_vertex_status(Vertex_handle v,Classification_type edge_status);
void set_facet_classification_type(const Facet& f);
void set_vertex_status(Vertex_handle v);
inline void set_cell_status (Cell_handle c);
Classification_type compute_edge_status( const Cell_handle& c,int i,int j) const;
//---------------------------------------------------------------------
public:
// Returns the current alpha-value.
const NT& get_alpha() const
{
return _alpha;
}
void clear()
{
// clears the structure
Dt::clear();
edge_status_map.clear();
}
//--------------------- PREDICATES -----------------------------------
public:
Classification_type classify(const Cell_handle& s) const {
if (is_infinite(s)) return EXTERIOR;
return s->get_classification_type();
}
Classification_type classify(const Facet& f) const {
if (is_infinite(f)) return EXTERIOR;
return f.first->get_facet_classification_type(f.second);
}
Classification_type classify(const Edge& e) const {
if (is_infinite(e)) return EXTERIOR;
return edge_status_map.find(make_vertex_handle_pair(e))->second;
}
Classification_type classify(const Vertex_handle& v) const {
if (is_infinite(v)) return EXTERIOR;
return v->get_classification_type();
}
//------------------- GEOMETRIC PRIMITIVES ----------------------------
private:
bool
is_gabriel_simplex_in_alpha_complex (const Cell_handle& s) const{
return
Simplex_classif::predicate(*this)(
s->vertex(0)->point(),
s->vertex(1)->point(),
s->vertex(2)->point(),
s->vertex(3)->point(),
get_alpha()
) !=POSITIVE;
}
bool
is_gabriel_simplex_in_alpha_complex (const Cell_handle& s, const int& i) const{
return
Simplex_classif::predicate(*this)(
s->vertex(vertex_triple_index(i,0))->point(),
s->vertex(vertex_triple_index(i,1))->point(),
s->vertex(vertex_triple_index(i,2))->point(),
get_alpha()
) != POSITIVE;
}
bool
is_gabriel_simplex_in_alpha_complex (const Facet& f) {
return is_gabriel_simplex_in_alpha_complex(f.first, f.second);
}
bool
is_gabriel_simplex_in_alpha_complex (const Cell_handle& s, const int& i, const int& j) const {
return
Simplex_classif::predicate(*this)(
s->vertex(i)->point(),
s->vertex(j)->point(),
get_alpha()
) !=POSITIVE;
}
bool
is_gabriel_simplex_in_alpha_complex (const Edge& e) const {
return is_gabriel_simplex_in_alpha_complex(e.first,e.second,e.third);
}
bool
is_gabriel_simplex_in_alpha_complex (const Vertex_handle& v) const {
return
Simplex_classif::predicate(*this)(
v->point(),
get_alpha()
) !=POSITIVE;
}
//---------------------------------------------------------------------
public:
#ifdef CGAL_USE_GEOMVIEW
void show_alpha_shape_faces(Geomview_stream &gv) const;
#endif
//Iterators
//---------------------------------------------------------------------
Alpha_shape_vertices_iterator alpha_shape_vertices_begin() const {
return CGAL::filter_iterator(finite_vertices_end(),Exterior_simplex_test(this),finite_vertices_begin());}
Alpha_shape_vertices_iterator alpha_shape_vertices_end() const {
return CGAL::filter_iterator(finite_vertices_end(),Exterior_simplex_test(this));}
//---------------------------------------------------------------------
Alpha_shape_facets_iterator alpha_shape_facets_begin() const{
return CGAL::filter_iterator(finite_facets_end(),Exterior_simplex_test(this),finite_facets_begin());}
Alpha_shape_facets_iterator alpha_shape_facets_end() const {
return CGAL::filter_iterator(finite_facets_end(),Exterior_simplex_test(this));}
//---------------------------------------------------------------------
Alpha_shape_edges_iterator alpha_shape_edges_begin() const{
return CGAL::filter_iterator(finite_edges_end(),Exterior_simplex_test(this),finite_edges_begin());}
Alpha_shape_edges_iterator alpha_shape_edges_end() const {
return CGAL::filter_iterator(finite_edges_end(),Exterior_simplex_test(this));}
//---------------------------------------------------------------------
Alpha_shape_cells_iterator alpha_shape_cells_begin() const {
return CGAL::filter_iterator(finite_cells_end(),Exterior_simplex_test(this),finite_cells_begin());
}
Alpha_shape_cells_iterator alpha_shape_cells_end() const {
return CGAL::filter_iterator(finite_cells_end(),Exterior_simplex_test(this));
}
//---------------------------------------------------------------------
// To extract simplices given a classification type
template<class OutputIterator>
OutputIterator get_alpha_shape_cells(OutputIterator it,
Classification_type type) const
{
Finite_cells_iterator cit = finite_cells_begin();
for( ; cit != finite_cells_end() ; ++cit){
if (classify(cit) == type) *it++ = Cell_handle(cit);
}
return it;
}
template<class OutputIterator>
OutputIterator get_alpha_shape_facets(OutputIterator it,
Classification_type type) const
{
Finite_facets_iterator fit = finite_facets_begin();
for( ; fit != finite_facets_end() ; ++fit){
if (classify(*fit) == type) *it++ = *fit;
}
return it;
}
template<class OutputIterator>
OutputIterator get_alpha_shape_edges(OutputIterator it,
Classification_type type) const
{
Finite_edges_iterator eit = finite_edges_begin();
for( ; eit != finite_edges_end() ; ++eit){
if (classify(*eit) == type) *it++ = *eit;
}
return it;
}
template<class OutputIterator>
OutputIterator get_alpha_shape_vertices(OutputIterator it,
Classification_type type) const
{
Finite_vertices_iterator vit = finite_vertices_begin();
for( ; vit != finite_vertices_end() ; ++vit){
if (classify(vit) == type) *it++ = Vertex_handle(vit);
}
return it;
}
};
template < class Dt >
const typename Fixed_alpha_shape_3<Dt>::Classification_type Fixed_alpha_shape_3<Dt>::EXTERIOR;
template < class Dt >
const typename Fixed_alpha_shape_3<Dt>::Classification_type Fixed_alpha_shape_3<Dt>::REGULAR;
template < class Dt >
const typename Fixed_alpha_shape_3<Dt>::Classification_type Fixed_alpha_shape_3<Dt>::INTERIOR;
template < class Dt >
const typename Fixed_alpha_shape_3<Dt>::Classification_type Fixed_alpha_shape_3<Dt>::SINGULAR;
//---------------------------------------------------------------------
//--------------------- MEMBER FUNCTIONS-------------------------------
//---------------------------------------------------------------------
//--------------------- INITIALIZATION OF PRIVATE MEMBERS -------------
template <class Dt>
void Fixed_alpha_shape_3<Dt>::set_cell_status(Cell_handle c){
Classification_type status=is_infinite(c) ? EXTERIOR:( is_gabriel_simplex_in_alpha_complex(c) ? INTERIOR : EXTERIOR );
c->set_classification_type(status);
}
template <class Dt>
void
Fixed_alpha_shape_3<Dt>::initialize_status_of_cells()
{
Finite_cells_iterator cell_it, done = finite_cells_end();
for( cell_it = finite_cells_begin(); cell_it != done; ++cell_it) {
set_cell_status(cell_it);
}
}
//---------------------------------------------------------------------
template < class Dt >
void
Fixed_alpha_shape_3<Dt>::
set_facet_classification_type( const Facet& f) {
Cell_handle pCell = f.first;
int i = f.second;
Cell_handle pNeighbor = pCell->neighbor(i);
int iNeigh = pNeighbor->index(pCell);
unsigned nb_interior_cells=0;
if(!is_infinite(pCell)){
if (pCell->get_classification_type()==INTERIOR)
++nb_interior_cells;
}
if(!is_infinite(pNeighbor)){
if (pNeighbor->get_classification_type()==INTERIOR)
++nb_interior_cells;
}
Classification_type status=EXTERIOR;
switch (nb_interior_cells){
case 2:
status=INTERIOR;
break;
case 1:
status=REGULAR;
break;
default:
{
if ( is_Gabriel(f) ){
if ( is_gabriel_simplex_in_alpha_complex(f) ) status=SINGULAR;
}
}
}
pCell->set_facet_classification_type(i,status);
pNeighbor->set_facet_classification_type(iNeigh,status);
}
template <class Dt>
void
Fixed_alpha_shape_3<Dt>::initialize_status_of_facets()
{
for(Finite_facets_iterator fit = finite_facets_begin();
fit != finite_facets_end(); ++fit)
set_facet_classification_type(*fit);
}
template < class Dt >
typename Fixed_alpha_shape_3<Dt>::Classification_type
Fixed_alpha_shape_3<Dt>::
compute_edge_status( const Cell_handle& c, int i, int j) const
{
Facet_circulator fcirc, done;
fcirc = incident_facets(c,i,j);
done = fcirc;
bool is_regular=false;
bool is_interior=true;
do{
if (!is_infinite(*fcirc)){
Classification_type status=(*fcirc).first->get_facet_classification_type((*fcirc).second);
if (status!=INTERIOR) is_interior=false;
if (status!=EXTERIOR)
is_regular=true;
else
if (is_regular)
break;
}
}while(++fcirc!=done);
if (is_interior) return INTERIOR;
if (is_regular) return REGULAR;
if ( is_Gabriel(c,i,j) ){
if ( is_gabriel_simplex_in_alpha_complex(c,i,j) ) return SINGULAR;
}
return EXTERIOR;
}
template <class Dt>
void
Fixed_alpha_shape_3<Dt>::initialize_status_of_edges()
{
for (Finite_edges_iterator eit = finite_edges_begin();
eit != finite_edges_end(); ++eit)
{
Classification_type status=compute_edge_status(eit->first, eit->second, eit->third);
//cross links
Vertex_handle_pair vhp = make_vertex_handle_pair( *eit );
edge_status_map.insert(std::make_pair(vhp, status));
}
}
//this function is only to use for update (removal/update)
template <class Dt>
void
Fixed_alpha_shape_3<Dt>::set_vertex_status(Vertex_handle v){
std::list<Vertex_handle> incidentv;
finite_adjacent_vertices(v,back_inserter(incidentv));
bool is_interior=true;
bool is_regular=false;
typename std::list<Vertex_handle>::iterator vvit=incidentv.begin();
for( ; vvit != incidentv.end(); ++vvit) {
Vertex_handle_pair vhp = make_vertex_handle_pair( *vvit, v);
Classification_type status=edge_status_map[vhp];
if (status!=INTERIOR) is_interior=false;
if (!is_interior && status!=EXTERIOR){
is_regular=true;
break;
}
}
Classification_type status=EXTERIOR;
if (is_interior)
status=v->is_on_chull() ? REGULAR : INTERIOR;
else{
if (is_regular)
status=REGULAR;
else{
if ( is_vertex_Gabriel(v,Weighted_tag()) ){
if ( is_gabriel_simplex_in_alpha_complex(v) ) status=SINGULAR;
}
}
}
v->set_classification_type(status);
}
template <class Dt>
void
Fixed_alpha_shape_3<Dt>::update_vertex_status(Vertex_handle v,Classification_type edge_status){
Classification_type status=v->get_classification_type();
switch(status){
case SINGULAR:
switch(edge_status){
case INTERIOR:
status=INTERIOR;
break;
case EXTERIOR:
status=EXTERIOR;
break;
case REGULAR:
case SINGULAR:
status=REGULAR;
}
break;
case INTERIOR:
switch(edge_status){
case INTERIOR:
break;
case EXTERIOR:
case REGULAR:
case SINGULAR:
status=REGULAR;
}
break;
case EXTERIOR:
switch(edge_status){
case EXTERIOR:
break;
case INTERIOR:
case REGULAR:
case SINGULAR:
status=REGULAR;
}
break;
case REGULAR:
break;
}
v->set_classification_type(status);
}
template <class Dt>
void
Fixed_alpha_shape_3<Dt>::finalize_status_of_vertex(Vertex_handle v)
{
Classification_type status=v->get_classification_type();
if (v->is_on_chull() && status==INTERIOR){
v->set_classification_type(REGULAR);
return;
}
if (status==INTERIOR || status==REGULAR)
return;
//when dimension is 3 any vertex has at least one incident edge,
// thus can't be SINGULAR again (because of update_vertex_status behavior)
CGAL_assertion(v->get_classification_type()==EXTERIOR);
if ( is_vertex_Gabriel(v,Weighted_tag()) && is_gabriel_simplex_in_alpha_complex(v) )
v->set_classification_type(SINGULAR);
}
template <class Dt>
void
Fixed_alpha_shape_3<Dt>::initialize_status_of_vertices()
{
#if 1 //approach avoiding extensive use of the map on 3hfli we move from 0.110983 to 0.082987
for( Finite_vertices_iterator vit = finite_vertices_begin(); vit != finite_vertices_end(); ++vit)
vit->set_classification_type(SINGULAR);
for (typename Edge_status_map::const_iterator eit=edge_status_map.begin();eit!=edge_status_map.end();++eit){
Classification_type edge_status=eit->second;
Vertex_handle_pair vhp=eit->first;
update_vertex_status(vhp.first,edge_status);
update_vertex_status(vhp.second,edge_status);
}
for( Finite_vertices_iterator vit = finite_vertices_begin(); vit != finite_vertices_end(); ++vit)
finalize_status_of_vertex(vit);
#else
//This method is slower because it always makes queries in the edge classification map
for( Finite_vertices_iterator vit = finite_vertices_begin();
vit != finite_vertices_end(); ++vit)
set_vertex_status(vit);
#endif
}
//---------------------------------------------------------------------
template <class Dt>
std::ostream& operator<<(std::ostream& os, const Fixed_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 Fixed_alpha_shape_3<Dt> AS;
typedef typename AS::Vertex_handle Vertex_handle;
typedef typename AS::Cell_handle Cell_handle;
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, int > V;
int 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);
os << V[c->vertex(i0)] << ' '
<< V[c->vertex(i1)] << ' '
<< V[c->vertex(i2)] << std::endl;
}
return os;
}
} //namespace CGAL
#endif //CGAL_FIXED_ALPHA_SHAPE_3_H