1852 lines
54 KiB
C
1852 lines
54 KiB
C
|
// Copyright (c) 1997, 2012 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 software.
|
||
|
//
|
||
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
//
|
||
|
// SPDX-License-Identifier: GPL-3.0+
|
||
|
//
|
||
|
// $URL$
|
||
|
// $Id$
|
||
|
// Author(s) : Tran Kai Frank DA
|
||
|
// Andreas Fabri <Andreas.Fabri@geometryfactory.com>
|
||
|
|
||
|
#ifndef CGAL_ALPHA_SHAPE_2_H
|
||
|
#define CGAL_ALPHA_SHAPE_2_H
|
||
|
|
||
|
#include <CGAL/license/Alpha_shapes_2.h>
|
||
|
|
||
|
#include <CGAL/internal/Lazy_alpha_nt_2.h>
|
||
|
|
||
|
// for convenience only
|
||
|
#include <CGAL/Alpha_shape_vertex_base_2.h>
|
||
|
#include <CGAL/Alpha_shape_face_base_2.h>
|
||
|
|
||
|
#include <CGAL/assertions.h>
|
||
|
#include <CGAL/basic.h>
|
||
|
#include <CGAL/triangulation_assertions.h>
|
||
|
#include <CGAL/Unique_hash_map.h>
|
||
|
#include <CGAL/utility.h>
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <iostream>
|
||
|
#include <list>
|
||
|
#include <map>
|
||
|
#include <set>
|
||
|
#include <utility>
|
||
|
#include <vector>
|
||
|
|
||
|
namespace CGAL {
|
||
|
|
||
|
template < class Dt,class ExactAlphaComparisonTag = Tag_false>
|
||
|
class Alpha_shape_2 : public Dt
|
||
|
{
|
||
|
// DEFINITION The class Alpha_shape_2<Dt> represents the family
|
||
|
// of alpha-shapes of points in a plane for all positive alpha. It
|
||
|
// maintains the underlying Delaunay triangulation which represents
|
||
|
// connectivity and order among its faces. Each k-dimensional face of the
|
||
|
// Delaunay triangulation is associated with an interval that specifies
|
||
|
// for which values of alpha the face belongs to the alpha-shape (sorted
|
||
|
// linear arrays resp. multimaps or interval trees). There are links
|
||
|
// between the intervals and the k-dimensional faces of the Delaunay
|
||
|
// triangulation (multimaps resp. std::hashtables).
|
||
|
//
|
||
|
|
||
|
//------------------------- 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));
|
||
|
|
||
|
typedef typename internal::Alpha_nt_selector_2<
|
||
|
Gt, ExactAlphaComparisonTag, typename Dt::Weighted_tag>::Type_of_alpha Type_of_alpha;
|
||
|
typedef typename internal::Alpha_nt_selector_2<
|
||
|
Gt, ExactAlphaComparisonTag, typename Dt::Weighted_tag>::Compute_squared_radius_2 Compute_squared_radius_2;
|
||
|
typedef typename internal::Alpha_nt_selector_2<
|
||
|
Gt, ExactAlphaComparisonTag, typename Dt::Weighted_tag>::Side_of_bounded_circle_2 Side_of_bounded_circle_2;
|
||
|
|
||
|
typedef Type_of_alpha NT;
|
||
|
typedef Type_of_alpha FT;
|
||
|
|
||
|
// check that simplices are correctly instantiated
|
||
|
CGAL_static_assertion( (boost::is_same<NT, typename Dt::Face::NT>::value) );
|
||
|
CGAL_static_assertion( (boost::is_same<NT, typename Dt::Vertex::NT>::value) );
|
||
|
|
||
|
typedef typename Dt::Point Point;
|
||
|
|
||
|
typedef typename Gt::Point_2 Point_2;
|
||
|
typedef typename Gt::Segment_2 Segment;
|
||
|
typedef typename Gt::Line_2 Line;
|
||
|
|
||
|
typedef typename Dt::Face_handle Face_handle;
|
||
|
typedef typename Dt::Vertex_handle Vertex_handle;
|
||
|
typedef typename Dt::Edge Edge;
|
||
|
|
||
|
typedef typename Dt::Face_circulator Face_circulator;
|
||
|
typedef typename Dt::Edge_circulator Edge_circulator;
|
||
|
typedef typename Dt::Vertex_circulator Vertex_circulator;
|
||
|
|
||
|
typedef typename Dt::Finite_faces_iterator Finite_faces_iterator;
|
||
|
typedef typename Dt::Edge_iterator Edge_iterator;
|
||
|
typedef typename Dt::Finite_vertices_iterator Finite_vertices_iterator;
|
||
|
|
||
|
typedef typename Dt::Locate_type Locate_type;
|
||
|
typedef typename Dt::size_type size_type;
|
||
|
|
||
|
using Dt::cw;
|
||
|
using Dt::ccw;
|
||
|
using Dt::finite_vertices_begin;
|
||
|
using Dt::finite_vertices_end;
|
||
|
using Dt::faces_begin;
|
||
|
using Dt::faces_end;
|
||
|
using Dt::edges_begin;
|
||
|
using Dt::edges_end;
|
||
|
using Dt::number_of_vertices;
|
||
|
using Dt::is_infinite;
|
||
|
using Dt::locate;
|
||
|
using Dt::point;
|
||
|
|
||
|
using Dt::VERTEX;
|
||
|
using Dt::EDGE;
|
||
|
using Dt::FACE;
|
||
|
using Dt::OUTSIDE_CONVEX_HULL;
|
||
|
using Dt::OUTSIDE_AFFINE_HULL;
|
||
|
using Dt::dimension;
|
||
|
|
||
|
// for backward compatibility
|
||
|
typedef Finite_vertices_iterator Vertex_iterator;
|
||
|
typedef Finite_faces_iterator Face_iterator;
|
||
|
|
||
|
private:
|
||
|
|
||
|
typedef std::multimap< Type_of_alpha, Face_handle > Interval_face_map;
|
||
|
typedef typename Interval_face_map::value_type Interval_face;
|
||
|
|
||
|
typedef typename Tds::Face::Interval_3 Interval3;
|
||
|
|
||
|
typedef std::multimap< Interval3, Edge > Interval_edge_map;
|
||
|
typedef typename Interval_edge_map::value_type Interval_edge;
|
||
|
|
||
|
typedef std::pair< Type_of_alpha, Type_of_alpha > Interval2;
|
||
|
typedef std::multimap< Interval2, Vertex_handle > Interval_vertex_map;
|
||
|
typedef typename Interval_vertex_map::value_type Interval_vertex;
|
||
|
|
||
|
typedef Face_handle const const_void;
|
||
|
typedef std::pair<const_void, int> const_Edge;
|
||
|
|
||
|
typedef std::vector< Type_of_alpha > Alpha_spectrum;
|
||
|
|
||
|
typedef std::vector< Segment > Vect_seg;
|
||
|
|
||
|
typedef Unique_hash_map< Face_handle, bool > Marked_face_set;
|
||
|
|
||
|
public:
|
||
|
|
||
|
typedef typename std::list< Vertex_handle >::iterator
|
||
|
Alpha_shape_vertices_iterator;
|
||
|
typedef typename std::list< Edge >::iterator Alpha_shape_edges_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 Type_of_alpha
|
||
|
|
||
|
enum Classification_type {EXTERIOR, SINGULAR, REGULAR, INTERIOR};
|
||
|
// Distinguishes the different cases for classifying a
|
||
|
// k-dimensional face of the underlying Delaunay triangulation of
|
||
|
// the alpha-shape.
|
||
|
//
|
||
|
// `EXTERIOR' if the face does not belong to the alpha-complex.
|
||
|
//
|
||
|
// `SINGULAR' if the face belongs to the boundary of the
|
||
|
// alpha-shape, but is not incident to any higher-dimensional
|
||
|
// face of the alpha-complex
|
||
|
//
|
||
|
// `REGULAR' if face belongs to the boundary of the alpha-shape
|
||
|
// and is incident to a higher-dimensional face of the
|
||
|
// alpha-complex
|
||
|
//
|
||
|
// `INTERIOR' if the face belongs to the alpha-complex, but does
|
||
|
// not belong to the boundary of the alpha-shape
|
||
|
|
||
|
enum Mode {GENERAL, REGULARIZED};
|
||
|
// In general, an alpha shape is a non-connected, mixed-dimension
|
||
|
// polygon. Its regularized version is formed by the set of
|
||
|
// regular edges and their vertices
|
||
|
|
||
|
//------------------------ private VARIABLES -------------------------
|
||
|
|
||
|
private:
|
||
|
|
||
|
// only finite edges and faces are inserted into the maps
|
||
|
Interval_face_map _interval_face_map;
|
||
|
Interval_edge_map _interval_edge_map;
|
||
|
Interval_vertex_map _interval_vertex_map;
|
||
|
|
||
|
Alpha_spectrum _alpha_spectrum;
|
||
|
|
||
|
Type_of_alpha _alpha;
|
||
|
Mode _mode;
|
||
|
// should be constants
|
||
|
Type_of_alpha Infinity;
|
||
|
Type_of_alpha UNDEFINED;
|
||
|
|
||
|
mutable std::list< Vertex_handle > Alpha_shape_vertices_list;
|
||
|
mutable std::list< Edge > Alpha_shape_edges_list;
|
||
|
|
||
|
mutable bool use_vertex_cache;
|
||
|
mutable bool use_edge_cache;
|
||
|
public:
|
||
|
|
||
|
//------------------------- CONSTRUCTORS ------------------------------
|
||
|
|
||
|
// Introduces an empty alpha-shape `A' for a positive
|
||
|
// alpha-value `alpha'. Precondition: `alpha' >= 0.
|
||
|
Alpha_shape_2(Type_of_alpha alpha = Type_of_alpha(0),
|
||
|
Mode m = GENERAL)
|
||
|
: _alpha(alpha), _mode(m), Infinity(-1), UNDEFINED(-2),
|
||
|
use_vertex_cache(false), use_edge_cache(false)
|
||
|
{}
|
||
|
|
||
|
// Introduces an alpha-shape `A' for a positive alpha-value
|
||
|
// `alpha' that is initialized with the points in the range
|
||
|
// from first to last
|
||
|
template <class InputIterator>
|
||
|
Alpha_shape_2(const InputIterator& first,
|
||
|
const InputIterator& last,
|
||
|
const Type_of_alpha& alpha = Type_of_alpha(0),
|
||
|
Mode m = GENERAL)
|
||
|
: _alpha(alpha), _mode(m), Infinity(-1), UNDEFINED(-2) ,
|
||
|
use_vertex_cache(false), use_edge_cache(false)
|
||
|
{
|
||
|
Dt::insert(first, last);
|
||
|
if (dimension() == 2)
|
||
|
{
|
||
|
// Compute the associated _interval_face_map
|
||
|
initialize_interval_face_map();
|
||
|
|
||
|
// Compute the associated _interval_edge_map
|
||
|
initialize_interval_edge_map();
|
||
|
|
||
|
// Compute the associated _interval_vertex_map
|
||
|
initialize_interval_vertex_map();
|
||
|
|
||
|
// merge the two maps
|
||
|
initialize_alpha_spectrum();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Introduces an alpha-shape `A' for a positive alpha-value
|
||
|
// `alpha' that is initialized with the triangulation
|
||
|
Alpha_shape_2(Dt& dt,
|
||
|
const Type_of_alpha& alpha = Type_of_alpha(0),
|
||
|
Mode m = GENERAL)
|
||
|
: _alpha(alpha), _mode(m), Infinity(-1), UNDEFINED(-2) ,
|
||
|
use_vertex_cache(false), use_edge_cache(false)
|
||
|
{
|
||
|
Dt::swap(dt);
|
||
|
if (dimension() == 2)
|
||
|
{
|
||
|
// Compute the associated _interval_face_map
|
||
|
initialize_interval_face_map();
|
||
|
|
||
|
// Compute the associated _interval_edge_map
|
||
|
initialize_interval_edge_map();
|
||
|
|
||
|
// Compute the associated _interval_vertex_map
|
||
|
initialize_interval_vertex_map();
|
||
|
|
||
|
// merge the two maps
|
||
|
initialize_alpha_spectrum();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
|
||
|
//----------- OUTPUT POINTS CONNECTED BY PAIRS ----------------------
|
||
|
|
||
|
std::list<Point_2> Output();
|
||
|
|
||
|
std::ostream& op_ostream(std::ostream& os) const;
|
||
|
|
||
|
|
||
|
//----------------------- OPERATIONS ---------------------------------
|
||
|
|
||
|
// Introduces an alpha-shape `A' for a positive alpha-value
|
||
|
// `alpha' that is initialized with the points in the range
|
||
|
// from first to last
|
||
|
|
||
|
template < class InputIterator >
|
||
|
std::ptrdiff_t make_alpha_shape(const InputIterator& first,
|
||
|
const InputIterator& last)
|
||
|
{
|
||
|
|
||
|
clear();
|
||
|
|
||
|
size_type n = Dt::insert(first, last);
|
||
|
|
||
|
if (dimension() == 2)
|
||
|
{
|
||
|
// Compute the associated _interval_face_map
|
||
|
initialize_interval_face_map();
|
||
|
|
||
|
// Compute the associated _interval_edge_map
|
||
|
initialize_interval_edge_map();
|
||
|
|
||
|
// Compute the associated _interval_vertex_map
|
||
|
initialize_interval_vertex_map();
|
||
|
|
||
|
// merge the two maps
|
||
|
initialize_alpha_spectrum();
|
||
|
}
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
private :
|
||
|
|
||
|
//--------------------- INITIALIZATION OF PRIVATE MEMBERS -----------
|
||
|
|
||
|
void initialize_interval_face_map();
|
||
|
|
||
|
void initialize_interval_edge_map();
|
||
|
|
||
|
void initialize_interval_vertex_map();
|
||
|
|
||
|
void initialize_alpha_spectrum();
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
public:
|
||
|
|
||
|
void clear()
|
||
|
{
|
||
|
// clears the structure
|
||
|
Dt::clear();
|
||
|
|
||
|
_interval_face_map.clear();
|
||
|
_interval_edge_map.clear();
|
||
|
_interval_vertex_map.clear();
|
||
|
|
||
|
_alpha_spectrum.clear();
|
||
|
|
||
|
Alpha_shape_vertices_list.clear();
|
||
|
Alpha_shape_edges_list.clear();
|
||
|
|
||
|
set_alpha(Type_of_alpha(0));
|
||
|
set_mode(GENERAL);
|
||
|
|
||
|
}
|
||
|
|
||
|
//----------------------- PRIVATE MEMBERS --------------------------
|
||
|
|
||
|
private:
|
||
|
|
||
|
struct Less
|
||
|
{
|
||
|
bool operator()(const Interval_edge& ie,
|
||
|
const Type_of_alpha& alpha)
|
||
|
{
|
||
|
return ie.first.first < alpha;
|
||
|
}
|
||
|
|
||
|
bool operator()( const Type_of_alpha& alpha,
|
||
|
const Interval_edge& ie)
|
||
|
{
|
||
|
return alpha < ie.first.first;
|
||
|
}
|
||
|
|
||
|
// Needed for STL implementations of upper_bound which in debug mode
|
||
|
// check sortedness of range
|
||
|
bool operator()(const Interval_edge& ie,
|
||
|
const Interval_edge& ie2) const
|
||
|
{
|
||
|
return ie < ie2;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
//----------------------- ACCESS TO PRIVATE MEMBERS -----------------
|
||
|
|
||
|
private:
|
||
|
|
||
|
|
||
|
Type_of_alpha find_interval(const Face_handle& f) const
|
||
|
{
|
||
|
return f->get_alpha();
|
||
|
// return the value Alpha f the face f
|
||
|
}
|
||
|
|
||
|
Interval3 find_interval(const_Edge e) const
|
||
|
{ // corriger le parametrage
|
||
|
return (e.first)->get_ranges(e.second);
|
||
|
// return the Interval3 for the edge n
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
public:
|
||
|
|
||
|
Type_of_alpha set_alpha(const Type_of_alpha& alpha)
|
||
|
{
|
||
|
// Sets the alpha-value to `alpha'. Precondition: `alpha' >= 0.
|
||
|
// Returns the previous alpha
|
||
|
Type_of_alpha previous_alpha = _alpha;
|
||
|
_alpha = alpha;
|
||
|
use_vertex_cache = false;
|
||
|
use_edge_cache = false;
|
||
|
return previous_alpha;
|
||
|
}
|
||
|
|
||
|
const Type_of_alpha& get_alpha() const
|
||
|
{
|
||
|
// Returns the current alpha-value.
|
||
|
return _alpha;
|
||
|
}
|
||
|
|
||
|
const Type_of_alpha& get_nth_alpha(size_type n) const
|
||
|
{
|
||
|
// Returns the n-th alpha-value.
|
||
|
// n < size()
|
||
|
if (! _alpha_spectrum.empty())
|
||
|
return _alpha_spectrum[n];
|
||
|
else
|
||
|
return UNDEFINED;
|
||
|
}
|
||
|
|
||
|
size_type number_of_alphas() const
|
||
|
{
|
||
|
// Returns the number of not necessary different alpha-values
|
||
|
return _alpha_spectrum.size();
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
private:
|
||
|
|
||
|
// the dynamic version is not yet implemented
|
||
|
// desactivate the triangulation member functions
|
||
|
Vertex_handle insert(const Point& p);
|
||
|
// Inserts point `p' in the alpha shape and returns the
|
||
|
// corresponding vertex of the underlying Delaunay triangulation.
|
||
|
// 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
|
||
|
// triangulation and the associated intervals are updated.
|
||
|
|
||
|
void remove(Vertex_handle v);
|
||
|
// Removes the vertex from the underlying Delaunay triangulation.
|
||
|
// The created hole is retriangulated and the associated intervals
|
||
|
// are updated.
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
public:
|
||
|
|
||
|
Mode set_mode(Mode mode = GENERAL )
|
||
|
{
|
||
|
// Sets `A' to its general or regularized version. Returns the
|
||
|
// previous mode.
|
||
|
|
||
|
Mode previous_mode = _mode;
|
||
|
_mode = mode;
|
||
|
return previous_mode;
|
||
|
}
|
||
|
|
||
|
Mode get_mode() const
|
||
|
{
|
||
|
// Returns whether `A' is general or regularized.
|
||
|
return _mode;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
private:
|
||
|
|
||
|
|
||
|
void
|
||
|
update_alpha_shape_vertex_list()const;
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
void
|
||
|
update_alpha_shape_edges_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();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// for backward compatibility
|
||
|
Alpha_shape_vertices_iterator Alpha_shape_vertices_begin()
|
||
|
{
|
||
|
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_list.end();
|
||
|
}
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
Alpha_shape_edges_iterator alpha_shape_edges_begin() const
|
||
|
{
|
||
|
if(!use_edge_cache){
|
||
|
update_alpha_shape_edges_list();
|
||
|
}
|
||
|
return Alpha_shape_edges_list.begin();
|
||
|
}
|
||
|
|
||
|
Alpha_shape_edges_iterator Alpha_shape_edges_begin() const
|
||
|
{
|
||
|
return alpha_shape_edges_begin();
|
||
|
}
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
Alpha_shape_edges_iterator alpha_shape_edges_end() const
|
||
|
{
|
||
|
return Alpha_shape_edges_list.end();
|
||
|
}
|
||
|
|
||
|
Alpha_shape_edges_iterator Alpha_shape_edges_end() const
|
||
|
{
|
||
|
return Alpha_shape_edges_list.end();
|
||
|
}
|
||
|
public:
|
||
|
|
||
|
// Traversal of the alpha-Values
|
||
|
//
|
||
|
// The alpha shape class defines an iterator that allows to
|
||
|
// visit the sorted sequence of alpha-values. This iterator is
|
||
|
// non-mutable and bidirectional. Its value type is Type_of_alpha.
|
||
|
|
||
|
Alpha_iterator alpha_begin() const
|
||
|
{
|
||
|
// Returns an iterator that allows to traverse the sorted sequence
|
||
|
// of alpha-values of `A'.
|
||
|
return _alpha_spectrum.begin();
|
||
|
}
|
||
|
|
||
|
Alpha_iterator alpha_end() const
|
||
|
{
|
||
|
// Returns the corresponding past-the-end iterator.
|
||
|
return _alpha_spectrum.end();
|
||
|
}
|
||
|
|
||
|
Alpha_iterator alpha_find(const Type_of_alpha& 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(),
|
||
|
_alpha_spectrum.end(),
|
||
|
alpha);
|
||
|
}
|
||
|
|
||
|
Alpha_iterator alpha_lower_bound(const Type_of_alpha& alpha) const
|
||
|
{
|
||
|
// Returns an iterator pointing to the first element with
|
||
|
// alpha-value not less than `alpha'.
|
||
|
return std::lower_bound(_alpha_spectrum.begin(),
|
||
|
_alpha_spectrum.end(),
|
||
|
alpha);
|
||
|
}
|
||
|
|
||
|
Alpha_iterator alpha_upper_bound(const Type_of_alpha& alpha) const
|
||
|
{
|
||
|
// Returns an iterator pointing to the first element with
|
||
|
// alpha-value greater than `alpha'.
|
||
|
return std::upper_bound(_alpha_spectrum.begin(),
|
||
|
_alpha_spectrum.end(),
|
||
|
alpha);
|
||
|
}
|
||
|
|
||
|
//--------------------- PREDICATES -----------------------------------
|
||
|
|
||
|
// the classification predicates take
|
||
|
// amortized const time if STL_STD::HASH_TABLES
|
||
|
// O(log #alpha_shape ) otherwise
|
||
|
|
||
|
Classification_type classify(const Point& p ) const
|
||
|
{
|
||
|
return classify( p, get_alpha());
|
||
|
}
|
||
|
|
||
|
|
||
|
Classification_type classify(const Point& p,
|
||
|
const Type_of_alpha& alpha) const
|
||
|
{
|
||
|
// Classifies a point `p' with respect to `A'.
|
||
|
Locate_type type;
|
||
|
int i;
|
||
|
Face_handle pFace = locate(p, type, i);
|
||
|
switch (type)
|
||
|
{
|
||
|
case VERTEX : return classify(pFace->vertex(i), alpha);
|
||
|
case EDGE : return classify(pFace, i, alpha);
|
||
|
case FACE : return classify(pFace, alpha);
|
||
|
case OUTSIDE_CONVEX_HULL :
|
||
|
case OUTSIDE_AFFINE_HULL : return EXTERIOR;
|
||
|
default : return EXTERIOR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
Classification_type classify(const Face_handle& f) const
|
||
|
{
|
||
|
// Classifies the face `f' of the underlying Delaunay
|
||
|
// triangulation with respect to `A'.
|
||
|
return classify(f, get_alpha());
|
||
|
}
|
||
|
|
||
|
Classification_type classify(const Face_handle& f,
|
||
|
const Type_of_alpha& alpha) const
|
||
|
{
|
||
|
// Classifies the face `f' of the underlying Delaunay
|
||
|
// triangulation with respect to `A'.
|
||
|
// we consider close circles :
|
||
|
// f->radius < alpha <=> f exterior
|
||
|
// problem the operator [] is non-const
|
||
|
|
||
|
if (is_infinite(f)) return EXTERIOR;
|
||
|
|
||
|
// the version that computes the squared radius seems to be
|
||
|
// much faster
|
||
|
|
||
|
return (find_interval(f) <= alpha) ?
|
||
|
INTERIOR :
|
||
|
EXTERIOR;
|
||
|
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
Classification_type classify(const Edge& edge) const
|
||
|
{
|
||
|
return classify(edge.first, edge.second, get_alpha());
|
||
|
}
|
||
|
|
||
|
Classification_type classify(const Face_handle& f,
|
||
|
int i) const
|
||
|
{
|
||
|
return classify(f, i, get_alpha());
|
||
|
}
|
||
|
|
||
|
Classification_type classify(const Edge& edge,
|
||
|
const Type_of_alpha& alpha) const
|
||
|
{
|
||
|
return classify(edge.first, edge.second, alpha);
|
||
|
}
|
||
|
|
||
|
Classification_type classify(const Face_handle& f,
|
||
|
int i,
|
||
|
const Type_of_alpha& alpha) const;
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
Classification_type classify(const Vertex_handle& v) const
|
||
|
{
|
||
|
return classify(v, get_alpha());
|
||
|
}
|
||
|
|
||
|
Classification_type classify(const Vertex_handle& v,
|
||
|
const Type_of_alpha& alpha) const;
|
||
|
|
||
|
//--------------------- 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 Type_of_alpha& /* alpha */) const
|
||
|
{
|
||
|
return number_of_solid_components(get_alpha());
|
||
|
}
|
||
|
|
||
|
size_type
|
||
|
number_of_solid_components(const Type_of_alpha& alpha) const;
|
||
|
|
||
|
private:
|
||
|
|
||
|
void traverse(const Face_handle& pFace,
|
||
|
Marked_face_set& marked_face_set,
|
||
|
const Type_of_alpha alpha) const;
|
||
|
|
||
|
// class Line_face_circulator;
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
public:
|
||
|
|
||
|
Alpha_iterator find_optimal_alpha(size_type nb_components);
|
||
|
|
||
|
Type_of_alpha find_alpha_solid() const;
|
||
|
|
||
|
//---------------------- PREDICATES ------------------------------------
|
||
|
|
||
|
private:
|
||
|
|
||
|
bool is_attached(const Face_handle& f, int i) const
|
||
|
{
|
||
|
Bounded_side b = Side_of_bounded_circle_2()(*this)(point(f, cw(i)),
|
||
|
point(f, ccw(i)),
|
||
|
point(f, i));
|
||
|
|
||
|
return (b == ON_BOUNDED_SIDE);
|
||
|
}
|
||
|
|
||
|
//-------------------- GEOMETRIC PRIMITIVES ----------------------------
|
||
|
|
||
|
Type_of_alpha squared_radius(const Face_handle& f) const
|
||
|
{
|
||
|
return Compute_squared_radius_2()(*this)(point(f, 0), point(f, 1), point(f, 2));
|
||
|
}
|
||
|
|
||
|
Type_of_alpha squared_radius(const Face_handle& f, int i) const
|
||
|
{
|
||
|
return Compute_squared_radius_2()(*this)(point(f, ccw(i)),
|
||
|
point(f, cw(i)));
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
private:
|
||
|
// prevent default copy constructor and default assigment
|
||
|
|
||
|
Alpha_shape_2(const Alpha_shape_2& A);
|
||
|
|
||
|
Alpha_shape_2& operator=(const Alpha_shape_2& A);
|
||
|
|
||
|
|
||
|
public:
|
||
|
// to debug
|
||
|
void print_edge_map();
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
//----------------------- MEMBER FUNCTIONS -----------------------------
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
void
|
||
|
Alpha_shape_2<Dt,EACT>::initialize_interval_face_map()
|
||
|
{
|
||
|
Type_of_alpha alpha_f;
|
||
|
|
||
|
// only finite faces
|
||
|
for(Finite_faces_iterator face_it = faces_begin(); face_it != faces_end(); ++face_it)
|
||
|
{
|
||
|
alpha_f = squared_radius(face_it);
|
||
|
_interval_face_map.insert(Interval_face(alpha_f, face_it));
|
||
|
|
||
|
// cross references
|
||
|
face_it->set_alpha(alpha_f);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
void
|
||
|
Alpha_shape_2<Dt,EACT>::initialize_interval_edge_map()
|
||
|
{
|
||
|
Edge_iterator edge_it;
|
||
|
Edge edge;
|
||
|
|
||
|
// only finite faces
|
||
|
for( edge_it = edges_begin();
|
||
|
edge_it != edges_end();
|
||
|
++edge_it)
|
||
|
{
|
||
|
Interval3 interval;
|
||
|
edge = (*edge_it);
|
||
|
|
||
|
Face_handle pFace = edge.first;
|
||
|
int i = edge.second;
|
||
|
Face_handle pNeighbor = pFace->neighbor(i);
|
||
|
int Neigh_i = pNeighbor->index(pFace);
|
||
|
|
||
|
// not on the convex hull
|
||
|
|
||
|
if(!is_infinite(pFace) && !is_infinite(pNeighbor))
|
||
|
{
|
||
|
Type_of_alpha squared_radius_Face =
|
||
|
find_interval(pFace);
|
||
|
Type_of_alpha squared_radius_Neighbor =
|
||
|
find_interval(pNeighbor);
|
||
|
if (squared_radius_Neighbor < squared_radius_Face)
|
||
|
{
|
||
|
edge = Edge(pNeighbor, Neigh_i);
|
||
|
Type_of_alpha coord_tmp = squared_radius_Face;
|
||
|
squared_radius_Face = squared_radius_Neighbor;
|
||
|
squared_radius_Neighbor = coord_tmp;
|
||
|
}
|
||
|
interval = (is_attached(pFace, i) ||
|
||
|
is_attached(pNeighbor, Neigh_i)) ?
|
||
|
make_triple(UNDEFINED,
|
||
|
squared_radius_Face,
|
||
|
squared_radius_Neighbor):
|
||
|
make_triple(squared_radius(pFace, i),
|
||
|
squared_radius_Face,
|
||
|
squared_radius_Neighbor);
|
||
|
}
|
||
|
else
|
||
|
{ // on the convex hull
|
||
|
|
||
|
if(is_infinite(pFace))
|
||
|
{
|
||
|
if (!is_infinite(pNeighbor))
|
||
|
{
|
||
|
interval = (is_attached(pNeighbor,
|
||
|
Neigh_i)) ?
|
||
|
make_triple(UNDEFINED,
|
||
|
find_interval(pNeighbor),
|
||
|
Infinity):
|
||
|
make_triple(squared_radius(pNeighbor,
|
||
|
Neigh_i),
|
||
|
find_interval(pNeighbor),
|
||
|
Infinity);
|
||
|
edge = Edge(pNeighbor, Neigh_i);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// both faces are infinite by definition unattached
|
||
|
// the edge is finite by construction
|
||
|
CGAL_triangulation_precondition((is_infinite(pNeighbor)
|
||
|
&& is_infinite(pFace)));
|
||
|
interval = make_triple(squared_radius(pFace, i),
|
||
|
Infinity,
|
||
|
Infinity);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ // is_infinite(pNeighbor)
|
||
|
|
||
|
CGAL_triangulation_precondition((is_infinite(pNeighbor)
|
||
|
&& !is_infinite(pFace)));
|
||
|
if (is_attached(pFace, i))
|
||
|
interval = make_triple(UNDEFINED,
|
||
|
find_interval(pFace),
|
||
|
Infinity);
|
||
|
else
|
||
|
interval = make_triple(squared_radius(pFace, i),
|
||
|
find_interval(pFace),
|
||
|
Infinity);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_interval_edge_map.insert(Interval_edge(interval, edge));
|
||
|
|
||
|
// cross-links
|
||
|
(edge.first)->set_ranges(edge.second,interval);
|
||
|
// MY : to fix a bug I store the interval of the edge in both faces
|
||
|
Face_handle neighbor = (edge.first)->neighbor(edge.second);
|
||
|
int ni = neighbor->index(edge.first);
|
||
|
neighbor->set_ranges( ni, interval);
|
||
|
|
||
|
}
|
||
|
|
||
|
// Remark:
|
||
|
// The interval_edge_map will be sorted as follows
|
||
|
// first the attached edges on the convex hull
|
||
|
// second not on the convex hull
|
||
|
// third the un-attached edges on the convex hull
|
||
|
// finally not on the convex hull
|
||
|
//
|
||
|
// if we are in regularized mode we should sort differently
|
||
|
// by the second third first Key
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
void
|
||
|
Alpha_shape_2<Dt,EACT>::initialize_interval_vertex_map()
|
||
|
{
|
||
|
Type_of_alpha alpha_mid_v;
|
||
|
Type_of_alpha alpha_max_v;
|
||
|
Type_of_alpha alpha_f;
|
||
|
|
||
|
Finite_vertices_iterator vertex_it;
|
||
|
|
||
|
for( vertex_it = finite_vertices_begin();
|
||
|
vertex_it != finite_vertices_end();
|
||
|
++vertex_it)
|
||
|
{
|
||
|
Vertex_handle v = vertex_it;
|
||
|
Face_handle f;
|
||
|
|
||
|
alpha_max_v = Type_of_alpha(0);
|
||
|
alpha_mid_v = (!_interval_face_map.empty() ?
|
||
|
(--_interval_face_map.end())->first :
|
||
|
Type_of_alpha(0));
|
||
|
|
||
|
//----------------- examine incident edges --------------------------
|
||
|
|
||
|
// // if we used Edelsbrunner and Muecke's definition
|
||
|
// // singular means not incident to any higher-dimensional face
|
||
|
// // regular means incident to a higher-dimensional face
|
||
|
// Edge_circulator edge_circ = this->incident_edges(v),
|
||
|
// edge_done(edge_circ);
|
||
|
|
||
|
// do
|
||
|
|
||
|
// {
|
||
|
// f = (*edge_circ).first;
|
||
|
// int i = (*edge_circ).second;
|
||
|
|
||
|
// if (is_infinite(f, i))
|
||
|
|
||
|
// {
|
||
|
// alpha_max_v = Infinity;
|
||
|
// }
|
||
|
// else
|
||
|
|
||
|
// {
|
||
|
// Interval3 interval3 = find_interval(const_Edge(f, i));
|
||
|
|
||
|
|
||
|
// alpha_mid_v = (interval3.first != UNDEFINED) ?
|
||
|
// (CGAL::min)(alpha_mid_v, interval3.first):
|
||
|
// (CGAL::min)(alpha_mid_v, interval3.second);
|
||
|
|
||
|
// if (alpha_max_v != Infinity)
|
||
|
|
||
|
// {
|
||
|
// alpha_max_v = (interval3.third != Infinity) ?
|
||
|
// (CGAL::max)(alpha_max_v, interval3.third):
|
||
|
// Infinity;
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
// while(++edge_circ != edge_done);
|
||
|
|
||
|
|
||
|
//-------------- examine incident faces --------------------------
|
||
|
|
||
|
// we use a different definition than Edelsbrunner and Muecke
|
||
|
// singular means not incident to any 2-dimensional face
|
||
|
// regular means incident to a 2-dimensional face
|
||
|
|
||
|
Face_circulator face_circ = this->incident_faces(v),
|
||
|
done = face_circ;
|
||
|
|
||
|
if (!face_circ.is_empty())
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
f = face_circ;
|
||
|
if (is_infinite(f))
|
||
|
{
|
||
|
alpha_max_v = Infinity;
|
||
|
// continue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
alpha_f = find_interval(f);
|
||
|
// if we define singular as not incident to a 2-dimensional
|
||
|
// face
|
||
|
alpha_mid_v = (CGAL::min)(alpha_mid_v, alpha_f);
|
||
|
|
||
|
if (alpha_max_v != Infinity)
|
||
|
alpha_max_v = (CGAL::max)(alpha_max_v, alpha_f);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
while(++face_circ != done);
|
||
|
}
|
||
|
|
||
|
|
||
|
Interval2 interval = std::make_pair(alpha_mid_v, alpha_max_v);
|
||
|
_interval_vertex_map.insert(Interval_vertex(interval, vertex_it));
|
||
|
|
||
|
// cross references
|
||
|
vertex_it->set_range(interval);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
void
|
||
|
Alpha_shape_2<Dt,EACT>::initialize_alpha_spectrum()
|
||
|
{
|
||
|
|
||
|
// skip the attached edges
|
||
|
// <=> _interval_edge_map.first.first == UNDEFINED
|
||
|
typename Interval_edge_map::iterator
|
||
|
edge_it = std::upper_bound(_interval_edge_map.begin(),
|
||
|
_interval_edge_map.end(),
|
||
|
UNDEFINED,
|
||
|
Less());
|
||
|
|
||
|
// merge the maps which is sorted and contains the alpha-values
|
||
|
// of the unattached edges and the triangles.
|
||
|
// eliminate duplicate values due to for example attached edges
|
||
|
// merge and copy from STL since assignment should be function object
|
||
|
|
||
|
typename Interval_face_map::iterator
|
||
|
face_it = _interval_face_map.begin();
|
||
|
|
||
|
_alpha_spectrum.reserve(_interval_face_map.size() +
|
||
|
_interval_edge_map.size()/ 2 );
|
||
|
// should be only the number of unattached edges
|
||
|
// size_type nb_unattached_edges;
|
||
|
// distance(edge_it, _interval_edge_map.end(), nb_unattached_edges);
|
||
|
// however the distance function is expensive
|
||
|
|
||
|
while (edge_it != _interval_edge_map.end() ||
|
||
|
face_it != _interval_face_map.end())
|
||
|
{
|
||
|
if (face_it != _interval_face_map.end() &&
|
||
|
(edge_it == _interval_edge_map.end() ||
|
||
|
((*face_it).first < (*edge_it).first.first)))
|
||
|
{
|
||
|
if (((_alpha_spectrum.empty() ||
|
||
|
_alpha_spectrum.back() < (*face_it).first)) &&
|
||
|
((*face_it).first > Type_of_alpha(0)))
|
||
|
_alpha_spectrum.push_back((*face_it).first);
|
||
|
face_it++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (((_alpha_spectrum.empty() ||
|
||
|
_alpha_spectrum.back() < (*edge_it).first.first)) &&
|
||
|
(((*edge_it).first.first) > Type_of_alpha(0)))
|
||
|
_alpha_spectrum.push_back((*edge_it).first.first);
|
||
|
edge_it++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (edge_it != _interval_edge_map.end())
|
||
|
{
|
||
|
if (((_alpha_spectrum.empty() ||
|
||
|
_alpha_spectrum.back() < (*edge_it).first.first))&&
|
||
|
(((*edge_it).first.first) > Type_of_alpha(0)))
|
||
|
_alpha_spectrum.push_back((*edge_it).first.first);
|
||
|
edge_it++;
|
||
|
}
|
||
|
|
||
|
while (face_it != _interval_face_map.end())
|
||
|
{
|
||
|
if (((_alpha_spectrum.empty() ||
|
||
|
_alpha_spectrum.back() < (*face_it).first))&&
|
||
|
((*face_it).first > Type_of_alpha(0)))
|
||
|
_alpha_spectrum.push_back((*face_it).first);
|
||
|
face_it++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
void
|
||
|
Alpha_shape_2<Dt,EACT>::update_alpha_shape_vertex_list()const {
|
||
|
//typedef typename Alpha_shape_2<Dt,EACT>::Interval_vertex_map
|
||
|
// Interval_vertex_map;
|
||
|
typename Interval_vertex_map::const_iterator vertex_alpha_it;
|
||
|
|
||
|
//const typename Alpha_shape_2<Dt,EACT>::Interval2* pInterval2;
|
||
|
const Interval2* pInterval2;
|
||
|
Vertex_handle v;
|
||
|
Alpha_shape_vertices_list.clear();
|
||
|
// write the regular vertices
|
||
|
|
||
|
for (vertex_alpha_it = _interval_vertex_map.begin();
|
||
|
vertex_alpha_it != _interval_vertex_map.end() &&
|
||
|
(*vertex_alpha_it).first.first <= get_alpha();
|
||
|
++vertex_alpha_it)
|
||
|
{
|
||
|
pInterval2 = &(*vertex_alpha_it).first;
|
||
|
|
||
|
if((pInterval2->second > get_alpha()
|
||
|
|| pInterval2->second == Infinity))
|
||
|
{
|
||
|
// alpha must be larger than the min boundary
|
||
|
// and alpha is smaller than the upper boundary
|
||
|
// which might be infinity
|
||
|
// write the vertex
|
||
|
v = (*vertex_alpha_it).second;
|
||
|
CGAL_triangulation_assertion((classify(v) == REGULAR));
|
||
|
Alpha_shape_vertices_list.push_back(v);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (get_mode() == Alpha_shape_2<Dt,EACT>::GENERAL)
|
||
|
{
|
||
|
// write the singular vertices
|
||
|
for (;
|
||
|
vertex_alpha_it != _interval_vertex_map.end();
|
||
|
++vertex_alpha_it)
|
||
|
{
|
||
|
v = (*vertex_alpha_it).second;
|
||
|
CGAL_triangulation_assertion((classify(v) == SINGULAR));
|
||
|
|
||
|
Alpha_shape_vertices_list.push_back(v);
|
||
|
}
|
||
|
}
|
||
|
use_vertex_cache = true;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
void
|
||
|
Alpha_shape_2<Dt,EACT>::update_alpha_shape_edges_list() const
|
||
|
{
|
||
|
|
||
|
// Writes the edges of the alpha shape `A' for the current $\alpha$-value
|
||
|
// to the container where 'out' refers to. Returns an output iterator
|
||
|
// which is the end of the constructed range.
|
||
|
//typedef typename Alpha_shape_2<Dt,EACT>::Interval_edge_map Interval_edge_map;
|
||
|
typename Interval_edge_map::const_iterator edge_alpha_it;
|
||
|
|
||
|
//const typename Alpha_shape_2<Dt,EACT>::Interval3* pInterval;
|
||
|
const Interval3* pInterval;
|
||
|
Alpha_shape_edges_list.clear();
|
||
|
if (get_mode() == REGULARIZED)
|
||
|
{
|
||
|
// it is much faster looking at the sorted intervals
|
||
|
// than looking at all sorted faces
|
||
|
// alpha must be larger than the mid boundary
|
||
|
// and alpha is smaller than the upper boundary
|
||
|
for (edge_alpha_it = _interval_edge_map.begin();
|
||
|
edge_alpha_it != _interval_edge_map.end() &&
|
||
|
(*edge_alpha_it).first.first <= get_alpha();
|
||
|
++edge_alpha_it)
|
||
|
{
|
||
|
pInterval = &(*edge_alpha_it).first;
|
||
|
|
||
|
CGAL_triangulation_assertion(pInterval->second != Infinity);
|
||
|
// since this happens only for convex hull of dimension 2
|
||
|
// thus singular
|
||
|
|
||
|
if(pInterval->second <= get_alpha() &&
|
||
|
(pInterval->third > get_alpha()
|
||
|
|| pInterval->third == Infinity))
|
||
|
{
|
||
|
// alpha must be larger than the mid boundary
|
||
|
// and alpha is smaller than the upper boundary
|
||
|
// which might be infinity
|
||
|
// visualize the boundary
|
||
|
CGAL_triangulation_assertion((classify((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second)
|
||
|
== REGULAR));
|
||
|
Alpha_shape_edges_list.push_back(Edge((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ // get_mode() == GENERAL -------------------------------------------
|
||
|
// draw the edges
|
||
|
for (edge_alpha_it = _interval_edge_map.begin();
|
||
|
edge_alpha_it != _interval_edge_map.end() &&
|
||
|
(*edge_alpha_it).first.first <= get_alpha();
|
||
|
++edge_alpha_it)
|
||
|
{
|
||
|
pInterval = &(*edge_alpha_it).first;
|
||
|
|
||
|
if (pInterval->first == UNDEFINED)
|
||
|
{
|
||
|
CGAL_triangulation_assertion(pInterval->second != Infinity);
|
||
|
// since this happens only for convex hull of dimension 2
|
||
|
// thus singular
|
||
|
|
||
|
if(pInterval->second <= get_alpha() &&
|
||
|
(pInterval->third > get_alpha()
|
||
|
|| pInterval->third == Infinity))
|
||
|
{
|
||
|
// alpha must be larger than the mid boundary
|
||
|
// and alpha is smaller than the upper boundary
|
||
|
// which might be infinity
|
||
|
// visualize the boundary
|
||
|
CGAL_triangulation_assertion((classify((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second)
|
||
|
== REGULAR));
|
||
|
Alpha_shape_edges_list.push_back(Edge((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
if(pInterval->third > get_alpha()
|
||
|
|| pInterval->third == Infinity)
|
||
|
{
|
||
|
// if alpha is smaller than the upper boundary
|
||
|
// which might be infinity
|
||
|
// visualize the boundary
|
||
|
CGAL_triangulation_assertion(((classify((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second)
|
||
|
== REGULAR)
|
||
|
|| (classify((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second)
|
||
|
== SINGULAR)));
|
||
|
Alpha_shape_edges_list.push_back(Edge((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
use_edge_cache = true;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
typename Alpha_shape_2<Dt,EACT>::Classification_type
|
||
|
Alpha_shape_2<Dt,EACT>::classify(const Face_handle& f, int i,
|
||
|
const Type_of_alpha& alpha) const
|
||
|
{
|
||
|
// Classifies the edge `e' of the underlying Delaunay
|
||
|
// triangulation with respect to `A'.
|
||
|
|
||
|
// the version that uses a simplified version without crosslinks
|
||
|
// is much slower
|
||
|
if (is_infinite(f, i))
|
||
|
return EXTERIOR;
|
||
|
|
||
|
// we store only finite edges in _edge_interval_map
|
||
|
Interval3 interval = find_interval(const_Edge(f, i));
|
||
|
// (*(_edge_interval_map.find(const_Edge(f, i)))).second;
|
||
|
|
||
|
if (alpha < interval.second)
|
||
|
{
|
||
|
if (get_mode() == REGULARIZED ||
|
||
|
interval.first == UNDEFINED ||
|
||
|
alpha < interval.first)
|
||
|
return EXTERIOR;
|
||
|
else // alpha >= interval.first
|
||
|
return SINGULAR;
|
||
|
}
|
||
|
else
|
||
|
{ // alpha >= interval.second
|
||
|
if (interval.third == Infinity ||
|
||
|
alpha < interval.third)
|
||
|
return REGULAR;
|
||
|
else // alpha >= interval.third
|
||
|
return INTERIOR;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
typename Alpha_shape_2<Dt,EACT>::Classification_type
|
||
|
Alpha_shape_2<Dt,EACT>::classify(const Vertex_handle& v,
|
||
|
const Type_of_alpha& alpha) const
|
||
|
{
|
||
|
// Classifies the vertex `v' of the underlying Delaunay
|
||
|
// triangulation with respect to `A'.
|
||
|
Interval2 interval = v->get_range();
|
||
|
|
||
|
if (alpha < interval.first)
|
||
|
{
|
||
|
if (get_mode() == REGULARIZED)
|
||
|
return EXTERIOR;
|
||
|
else // general => vertices are never exterior
|
||
|
return SINGULAR;
|
||
|
}
|
||
|
else
|
||
|
{ // alpha >= interval.first
|
||
|
if (interval.second == Infinity ||
|
||
|
alpha < interval.second)
|
||
|
return REGULAR;
|
||
|
else // alpha >= interval.second
|
||
|
return INTERIOR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
typename Alpha_shape_2<Dt,EACT>::size_type
|
||
|
Alpha_shape_2<Dt,EACT>::number_of_solid_components(const Type_of_alpha& alpha) const
|
||
|
{
|
||
|
// Determine the number of connected solid components
|
||
|
typedef typename Marked_face_set::Data Data;
|
||
|
Marked_face_set marked_face_set(false);
|
||
|
Finite_faces_iterator face_it;
|
||
|
size_type nb_solid_components = 0;
|
||
|
|
||
|
if (number_of_vertices()==0)
|
||
|
return 0;
|
||
|
|
||
|
// only finite faces
|
||
|
for( face_it = faces_begin();
|
||
|
face_it != faces_end();
|
||
|
++face_it)
|
||
|
{
|
||
|
Face_handle pFace = face_it;
|
||
|
CGAL_triangulation_postcondition( pFace != NULL);
|
||
|
|
||
|
if (classify(pFace, alpha) == INTERIOR){
|
||
|
Data& data = marked_face_set[pFace];
|
||
|
if(data == false)
|
||
|
{
|
||
|
// we traverse only interior faces
|
||
|
traverse(pFace, marked_face_set, alpha);
|
||
|
nb_solid_components++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return nb_solid_components;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
void
|
||
|
Alpha_shape_2<Dt,EACT>::traverse(const Face_handle& pFace,
|
||
|
Marked_face_set& marked_face_set,
|
||
|
const Type_of_alpha alpha) const
|
||
|
{
|
||
|
typedef typename Marked_face_set::Data Data;
|
||
|
std::list<Face_handle> faces;
|
||
|
faces.push_back(pFace);
|
||
|
Face_handle pNeighbor, fh;
|
||
|
|
||
|
while(! faces.empty()){
|
||
|
fh = faces.front();
|
||
|
faces.pop_front();
|
||
|
for (int i=0; i<3; i++)
|
||
|
{
|
||
|
pNeighbor = fh->neighbor(i);
|
||
|
CGAL_triangulation_assertion(pNeighbor != NULL);
|
||
|
if (classify(pNeighbor, alpha) == INTERIOR){
|
||
|
Data& data = marked_face_set[pNeighbor];
|
||
|
if(data == false){
|
||
|
data = true;
|
||
|
faces.push_back(pNeighbor);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
typename Alpha_shape_2<Dt,EACT>::Alpha_iterator
|
||
|
Alpha_shape_2<Dt,EACT>::find_optimal_alpha(size_type nb_components)
|
||
|
{
|
||
|
// find the minimum alpha that satisfies the properties
|
||
|
// (1) nb_components solid components
|
||
|
// (2) all data points on the boundary or in its interior
|
||
|
Type_of_alpha alpha = find_alpha_solid();
|
||
|
// from this alpha on the alpha_solid satisfies property (2)
|
||
|
|
||
|
Alpha_iterator first = alpha_lower_bound(alpha);
|
||
|
|
||
|
if (number_of_solid_components(alpha) == nb_components)
|
||
|
{
|
||
|
if ((first+1) < alpha_end())
|
||
|
return (first+1);
|
||
|
else
|
||
|
return first;
|
||
|
}
|
||
|
|
||
|
// do binary search on the alpha values
|
||
|
// number_of_solid_components() is a monotone function
|
||
|
// if we start with find_alpha_solid
|
||
|
|
||
|
Alpha_iterator last = alpha_end();
|
||
|
Alpha_iterator middle;
|
||
|
|
||
|
std::ptrdiff_t len = last - first - 1;
|
||
|
std::ptrdiff_t half;
|
||
|
|
||
|
while (len > 0)
|
||
|
{
|
||
|
half = len / 2;
|
||
|
middle = first + half;
|
||
|
|
||
|
#ifdef CGAL_DEBUG_ALPHA_SHAPE_2
|
||
|
std::cout << "first : " << *first << " last : " << *(first+len)
|
||
|
<< " mid : " << *middle
|
||
|
<< " nb comps : " << number_of_solid_components(*middle)
|
||
|
<< std::endl;
|
||
|
#endif // CGAL_DEBUG_ALPHA_SHAPE_2
|
||
|
|
||
|
if (number_of_solid_components(*middle) > nb_components)
|
||
|
{
|
||
|
first = middle + 1;
|
||
|
len = len - half - 1;
|
||
|
}
|
||
|
else
|
||
|
{ // number_of_solid_components(*middle) <= nb_components
|
||
|
len = half;
|
||
|
}
|
||
|
}
|
||
|
if ((first+1) < alpha_end())
|
||
|
return (first+1);
|
||
|
else
|
||
|
return first;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
typename Alpha_shape_2<Dt,EACT>::Type_of_alpha
|
||
|
Alpha_shape_2<Dt,EACT>::find_alpha_solid() const
|
||
|
{
|
||
|
// compute the minumum alpha such that all data points
|
||
|
// are either on the boundary or in the interior
|
||
|
// not necessarily connected
|
||
|
// starting point for searching
|
||
|
// takes O(#alpha_shape) time
|
||
|
Type_of_alpha alpha_solid = 0;
|
||
|
|
||
|
if (number_of_vertices()<3) return alpha_solid;
|
||
|
|
||
|
Finite_vertices_iterator vertex_it;
|
||
|
// only finite vertices
|
||
|
for( vertex_it = finite_vertices_begin();
|
||
|
vertex_it != finite_vertices_end();
|
||
|
++vertex_it)
|
||
|
{
|
||
|
Type_of_alpha alpha_min_v = (--_interval_face_map.end())->first;
|
||
|
|
||
|
Face_circulator face_circ = this->incident_faces(vertex_it);
|
||
|
Face_circulator done = face_circ;
|
||
|
do
|
||
|
{
|
||
|
Face_handle f = face_circ;
|
||
|
if (! is_infinite(f))
|
||
|
alpha_min_v = (CGAL::min)(find_interval(f),
|
||
|
alpha_min_v);
|
||
|
}
|
||
|
while (++face_circ != done);
|
||
|
alpha_solid = (CGAL::max)(alpha_min_v, alpha_solid);
|
||
|
|
||
|
}
|
||
|
return alpha_solid;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
std::ostream&
|
||
|
Alpha_shape_2<Dt,EACT>::op_ostream(std::ostream& os) const
|
||
|
{
|
||
|
typedef typename Alpha_shape_2<Dt,EACT>::Interval_vertex_map Interval_vertex_map ;
|
||
|
typedef typename Alpha_shape_2<Dt,EACT>::Interval_edge_map Interval_edge_map;
|
||
|
|
||
|
typename Interval_vertex_map::const_iterator vertex_alpha_it;
|
||
|
const typename Alpha_shape_2<Dt,EACT>::Interval2* pInterval2;
|
||
|
typename Interval_edge_map::const_iterator edge_alpha_it;
|
||
|
const typename Alpha_shape_2<Dt,EACT>::Interval3* pInterval;
|
||
|
|
||
|
Unique_hash_map< Vertex_handle, size_type > V;
|
||
|
size_type number_of_vertices = 0;
|
||
|
|
||
|
if (get_mode() == Alpha_shape_2<Dt,EACT>::REGULARIZED)
|
||
|
{
|
||
|
typename Alpha_shape_2<Dt,EACT>::Vertex_handle v;
|
||
|
for (vertex_alpha_it = _interval_vertex_map.begin();
|
||
|
vertex_alpha_it != _interval_vertex_map.end() &&
|
||
|
(*vertex_alpha_it).first.first <= get_alpha();
|
||
|
++vertex_alpha_it)
|
||
|
{
|
||
|
pInterval2 = &(*vertex_alpha_it).first;
|
||
|
|
||
|
#ifdef CGAL_DEBUG_ALPHA_SHAPE_2
|
||
|
typename Alpha_shape_2<Dt,EACT>::Type_of_alpha alpha =
|
||
|
get_alpha();
|
||
|
typename Alpha_shape_2<Dt,EACT>::Type_of_alpha alpha_mid =
|
||
|
pInterval2->first;
|
||
|
typename Alpha_shape_2<Dt,EACT>::Type_of_alpha alpha_max =
|
||
|
pInterval2->second;
|
||
|
#endif // CGAL_DEBUG_ALPHA_SHAPE_2
|
||
|
|
||
|
if((pInterval2->second > get_alpha()
|
||
|
|| pInterval2->second == Infinity))
|
||
|
{
|
||
|
// alpha must be larger than the min boundary
|
||
|
// and alpha is smaller than the upper boundary
|
||
|
// which might be infinity
|
||
|
// write the vertex
|
||
|
|
||
|
v = (*vertex_alpha_it).second;
|
||
|
CGAL_triangulation_assertion((classify(v) ==
|
||
|
Alpha_shape_2<Dt,EACT>::REGULAR));
|
||
|
// if we used Edelsbrunner and Muecke's definition
|
||
|
// regular means incident to a higher-dimensional face
|
||
|
// we would write too many vertices
|
||
|
|
||
|
V[v] = number_of_vertices++;
|
||
|
os << v->point() << std::endl;
|
||
|
}
|
||
|
}
|
||
|
// the vertices are oriented counterclockwise
|
||
|
|
||
|
typename Alpha_shape_2<Dt,EACT>::Face_handle f;
|
||
|
int i;
|
||
|
|
||
|
for (edge_alpha_it = _interval_edge_map.begin();
|
||
|
edge_alpha_it != _interval_edge_map.end() &&
|
||
|
(*edge_alpha_it).first.first <= get_alpha();
|
||
|
++edge_alpha_it)
|
||
|
{
|
||
|
pInterval = &(*edge_alpha_it).first;
|
||
|
|
||
|
CGAL_triangulation_assertion(pInterval->second != Infinity);
|
||
|
// since this happens only for convex hull of dimension 1
|
||
|
// thus singular
|
||
|
|
||
|
if(pInterval->second <= get_alpha() &&
|
||
|
(pInterval->third > get_alpha()
|
||
|
|| pInterval->third == Infinity))
|
||
|
{
|
||
|
// alpha must be larger than the mid boundary
|
||
|
// and alpha is smaller than the upper boundary
|
||
|
// which might be infinity
|
||
|
// visualize the boundary
|
||
|
|
||
|
|
||
|
f = (*edge_alpha_it).second.first;
|
||
|
i = (*edge_alpha_it).second.second;
|
||
|
|
||
|
// assure that all vertices are in ccw order
|
||
|
if (classify(f) == Alpha_shape_2<Dt,EACT>::EXTERIOR)
|
||
|
{
|
||
|
// take the reverse face
|
||
|
typename Alpha_shape_2<Dt,EACT>::Face_handle
|
||
|
pNeighbor = f->neighbor(i);
|
||
|
i = pNeighbor->index(f);
|
||
|
f = pNeighbor;
|
||
|
}
|
||
|
|
||
|
CGAL_triangulation_assertion((classify(f) ==
|
||
|
Alpha_shape_2<Dt,EACT>::INTERIOR));
|
||
|
|
||
|
CGAL_triangulation_assertion((classify(f, i) ==
|
||
|
Alpha_shape_2<Dt,EACT>::REGULAR));
|
||
|
|
||
|
os << V[f->vertex(f->ccw(i))] << ' '
|
||
|
<< V[f->vertex(f->cw(i))] << std::endl;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ // get_mode() == GENERAL -----------------------------------------
|
||
|
typename Alpha_shape_2<Dt,EACT>::Vertex_handle v;
|
||
|
|
||
|
// write the regular vertices
|
||
|
for (vertex_alpha_it = _interval_vertex_map.begin();
|
||
|
vertex_alpha_it != _interval_vertex_map.end() &&
|
||
|
(*vertex_alpha_it).first.first <= get_alpha();
|
||
|
++vertex_alpha_it)
|
||
|
{
|
||
|
pInterval2 = &(*vertex_alpha_it).first;
|
||
|
|
||
|
if((pInterval2->second > get_alpha()
|
||
|
|| pInterval2->second == Infinity))
|
||
|
{
|
||
|
// alpha must be larger than the min boundary
|
||
|
// and alpha is smaller than the upper boundary
|
||
|
// which might be infinity
|
||
|
// write the vertex
|
||
|
|
||
|
v = (*vertex_alpha_it).second;
|
||
|
CGAL_triangulation_assertion((classify(v) ==
|
||
|
Alpha_shape_2<Dt,EACT>::REGULAR));
|
||
|
V[v] = number_of_vertices++;
|
||
|
os << v->point() << std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// write the singular vertices
|
||
|
for (;
|
||
|
vertex_alpha_it != _interval_vertex_map.end();
|
||
|
++vertex_alpha_it)
|
||
|
{
|
||
|
v = (*vertex_alpha_it).second;
|
||
|
CGAL_triangulation_assertion((classify(v) ==
|
||
|
Alpha_shape_2<Dt,EACT>::SINGULAR));
|
||
|
|
||
|
V[v] = number_of_vertices++;
|
||
|
os << v->point() << std::endl;
|
||
|
}
|
||
|
|
||
|
// the vertices are oriented counterclockwise
|
||
|
|
||
|
typename Alpha_shape_2<Dt,EACT>::Face_handle f;
|
||
|
int i;
|
||
|
|
||
|
for (edge_alpha_it = _interval_edge_map.begin();
|
||
|
edge_alpha_it != _interval_edge_map.end() &&
|
||
|
(*edge_alpha_it).first.first <= get_alpha();
|
||
|
++edge_alpha_it)
|
||
|
{
|
||
|
pInterval = &(*edge_alpha_it).first;
|
||
|
|
||
|
#ifdef CGAL_DEBUG_ALPHA_SHAPE_2
|
||
|
typename Alpha_shape_2<Dt,EACT>::Type_of_alpha alpha =
|
||
|
get_alpha();
|
||
|
typename Alpha_shape_2<Dt,EACT>::Type_of_alpha alpha_min =
|
||
|
pInterval->first;
|
||
|
typename Alpha_shape_2<Dt,EACT>::Type_of_alpha alpha_mid =
|
||
|
pInterval->second;
|
||
|
typename Alpha_shape_2<Dt,EACT>::Type_of_alpha alpha_max =
|
||
|
pInterval->third;
|
||
|
#endif // CGAL_DEBUG_ALPHA_SHAPE_2
|
||
|
|
||
|
if(pInterval->third > get_alpha()
|
||
|
|| pInterval->third == Infinity)
|
||
|
{
|
||
|
// if alpha is smaller than the upper boundary
|
||
|
// which might be infinity
|
||
|
// visualize the boundary
|
||
|
|
||
|
f = (*edge_alpha_it).second.first;
|
||
|
i = (*edge_alpha_it).second.second;
|
||
|
|
||
|
// write the regular edges
|
||
|
if (pInterval->second != Infinity &&
|
||
|
pInterval->second <= get_alpha())
|
||
|
{
|
||
|
CGAL_triangulation_assertion((classify(f, i) ==
|
||
|
Alpha_shape_2<Dt,EACT>::REGULAR));
|
||
|
// assure that all vertices are in ccw order
|
||
|
if (classify(f) == Alpha_shape_2<Dt,EACT>::EXTERIOR)
|
||
|
{
|
||
|
// take the reverse face
|
||
|
typename Alpha_shape_2<Dt,EACT>::Face_handle
|
||
|
pNeighbor = f->neighbor(i);
|
||
|
|
||
|
i = pNeighbor->index(f);
|
||
|
f = pNeighbor;
|
||
|
}
|
||
|
|
||
|
CGAL_triangulation_assertion((classify(f) ==
|
||
|
Alpha_shape_2<Dt,EACT>::INTERIOR));
|
||
|
|
||
|
os << V[f->vertex(f->ccw(i))] << ' '
|
||
|
<< V[f->vertex(f->cw(i))] << std::endl;
|
||
|
}
|
||
|
else
|
||
|
{ // pInterval->second == Infinity ||
|
||
|
// pInterval->second >= get_alpha())
|
||
|
// pInterval->second == Infinity happens only for convex hull
|
||
|
// of dimension 1 thus singular
|
||
|
|
||
|
// write the singular edges
|
||
|
if (pInterval->first != UNDEFINED)
|
||
|
{
|
||
|
CGAL_triangulation_assertion((classify(f, i) ==
|
||
|
Alpha_shape_2<Dt,EACT>::SINGULAR));
|
||
|
os << V[f->vertex(f->ccw(i))] << ' '
|
||
|
<< V[f->vertex(f->cw(i))] << std::endl;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return os;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
std::ostream&
|
||
|
operator<<(std::ostream& os, const Alpha_shape_2<Dt>& A)
|
||
|
{
|
||
|
return A.op_ostream(os);
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
std::list<typename Alpha_shape_2<Dt,EACT>::Point_2>
|
||
|
Alpha_shape_2<Dt,EACT>::Output ()
|
||
|
{
|
||
|
typename Interval_edge_map::const_iterator edge_alpha_it;
|
||
|
|
||
|
const Interval3* pInterval;
|
||
|
std::list<Point_2> L;
|
||
|
|
||
|
if (get_mode() == REGULARIZED)
|
||
|
{
|
||
|
// it is much faster looking at the sorted intervals
|
||
|
// than looking at all sorted faces
|
||
|
// alpha must be larger than the mid boundary
|
||
|
// and alpha is smaller than the upper boundary
|
||
|
for (edge_alpha_it = _interval_edge_map.begin();
|
||
|
edge_alpha_it != _interval_edge_map.end() &&
|
||
|
(*edge_alpha_it).first.first <= get_alpha();
|
||
|
++edge_alpha_it)
|
||
|
{
|
||
|
pInterval = &(*edge_alpha_it).first;
|
||
|
|
||
|
if (pInterval->second != Infinity)
|
||
|
{
|
||
|
// since this happens only for convex hull of dimension 1
|
||
|
// thus singular
|
||
|
|
||
|
if(pInterval->second <= get_alpha() &&
|
||
|
(pInterval->third > get_alpha()
|
||
|
|| pInterval->third == Infinity))
|
||
|
{
|
||
|
// alpha must be larger than the mid boundary
|
||
|
// and alpha is smaller than the upper boundary
|
||
|
// which might be infinity
|
||
|
// visualize the boundary
|
||
|
|
||
|
CGAL_triangulation_assertion((classify((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second) ==
|
||
|
REGULAR));
|
||
|
|
||
|
// if we used Edelsbrunner and Muecke's definition
|
||
|
// regular means incident to a higher-dimensional face
|
||
|
// thus we would write to many vertices
|
||
|
L.push_back((this->segment((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second))
|
||
|
.source());
|
||
|
L.push_back((this->segment((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second))
|
||
|
.target());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ // get_mode() == GENERAL
|
||
|
// draw the edges
|
||
|
for (edge_alpha_it = _interval_edge_map.begin();
|
||
|
edge_alpha_it != _interval_edge_map.end() &&
|
||
|
(*edge_alpha_it).first.first <= get_alpha();
|
||
|
++edge_alpha_it)
|
||
|
{
|
||
|
pInterval = &(*edge_alpha_it).first;
|
||
|
|
||
|
if (pInterval->first == UNDEFINED)
|
||
|
{
|
||
|
|
||
|
CGAL_triangulation_assertion(pInterval->second != Infinity);
|
||
|
// since this happens only for convex hull of dimension 1
|
||
|
// thus singular
|
||
|
|
||
|
if(pInterval->second <= get_alpha() &&
|
||
|
(pInterval->third > get_alpha()
|
||
|
|| pInterval->third == Infinity))
|
||
|
{
|
||
|
// alpha must be larger than the mid boundary
|
||
|
// and alpha is smaller than the upper boundary
|
||
|
// which might be infinity
|
||
|
// visualize the boundary
|
||
|
|
||
|
CGAL_triangulation_assertion((classify((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second) ==
|
||
|
REGULAR));
|
||
|
L.push_back((this->segment((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second))
|
||
|
.source());
|
||
|
L.push_back((this->segment((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second))
|
||
|
.target());
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(pInterval->third > get_alpha()
|
||
|
|| pInterval->third == Infinity)
|
||
|
{
|
||
|
// if alpha is smaller than the upper boundary
|
||
|
// which might be infinity
|
||
|
// visualize the boundary
|
||
|
|
||
|
CGAL_triangulation_assertion(((classify((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second) ==
|
||
|
REGULAR) ||
|
||
|
(classify((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second) ==
|
||
|
SINGULAR)));
|
||
|
L.push_back((this->segment((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second))
|
||
|
.source());
|
||
|
L.push_back((this->segment((*edge_alpha_it).second.first,
|
||
|
(*edge_alpha_it).second.second))
|
||
|
.target());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return L;
|
||
|
}
|
||
|
|
||
|
template < class Dt, class EACT >
|
||
|
void Alpha_shape_2<Dt,EACT>::print_edge_map()
|
||
|
{
|
||
|
for (typename Interval_edge_map::iterator iemapit= _interval_edge_map.begin();
|
||
|
iemapit != _interval_edge_map.end(); ++iemapit) {
|
||
|
Interval3 interval = (*iemapit).first;
|
||
|
Edge edge = (*iemapit).second;
|
||
|
Point p1 = point(edge.first, cw(edge.second));
|
||
|
Point p2 = point(edge.first, ccw(edge.second));
|
||
|
std::cout << "[ (" << p1 << ") - (" << p2 << ") ] : "
|
||
|
<< interval.first << " "
|
||
|
<< interval.second << " " << interval.third << std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} //namespace CGAL
|
||
|
|
||
|
|
||
|
#endif //CGAL_ALPHA_SHAPE_2_H
|