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

1134 lines
39 KiB
C
Raw Normal View History

// Copyright (c) 1997-2000 Max-Planck-Institute Saarbruecken (Germany).
// 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.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Michael Seel <seel@mpi-sb.mpg.de>
#ifndef CGAL_NEF_POLYHEDRON_2_H
#define CGAL_NEF_POLYHEDRON_2_H
#include <CGAL/license/Nef_2.h>
#include <CGAL/disable_warnings.h>
#include <CGAL/basic.h>
#include <CGAL/Handle_for.h>
#include <CGAL/Nef_2/HDS_items.h>
#include <CGAL/HalfedgeDS_default.h>
#include <CGAL/Is_extended_kernel.h>
#include <CGAL/Nef_2/PM_explorer.h>
#include <CGAL/Nef_2/PM_decorator.h>
#include <CGAL/Nef_2/PM_io_parser.h>
#include <CGAL/Nef_2/PM_overlayer.h>
#include <CGAL/Nef_2/PM_point_locator.h>
#include <CGAL/Nef_2/Bounding_box_2.h>
#include <vector>
#include <list>
#include <boost/random/linear_congruential.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/variate_generator.hpp>
#undef CGAL_NEF_DEBUG
#define CGAL_NEF_DEBUG 11
#include <CGAL/Nef_2/debug.h>
namespace CGAL {
template <typename T, typename I, typename M> class Nef_polyhedron_2;
template <typename T, typename I, typename M> class Nef_polyhedron_2_rep;
template <typename T, typename I, typename M>
std::ostream& operator<<(std::ostream&, const Nef_polyhedron_2<T,I,M>&);
template <typename T, typename I, typename M>
std::istream& operator>>(std::istream&, Nef_polyhedron_2<T,I,M>&);
template <typename T, typename Items, typename Mark_>
class Nef_polyhedron_2_rep
{
typedef Nef_polyhedron_2_rep<T,Items,Mark_> Self;
friend class Nef_polyhedron_2<T,Items,Mark_>;
struct HDS_traits {
typedef typename T::Point_2 Point;
typedef Mark_ Mark;
};
public: // gcc-3.3 otherwise claims that Decorator in Polyhedron_2 is private
typedef CGAL_HALFEDGEDS_DEFAULT<HDS_traits,Items> Plane_map;
typedef CGAL::PM_const_decorator<Plane_map> Const_decorator;
typedef CGAL::PM_decorator<Plane_map> Decorator;
typedef CGAL::PM_naive_point_locator<Decorator,T> Slocator;
typedef CGAL::PM_point_locator<Decorator,T> Locator;
typedef CGAL::PM_overlayer<Decorator,T> Overlayer;
private:
Plane_map pm_;
Locator* pl_;
void init_locator()
{
if ( !pl_ )
pl_ = new Locator(pm_);
}
void clear_locator()
{
if ( pl_ ) {
delete pl_;
pl_=0;
}
}
public:
Nef_polyhedron_2_rep()
: pm_(), pl_(0)
{}
Nef_polyhedron_2_rep(const Self& )
: pm_(), pl_(0)
{}
~Nef_polyhedron_2_rep()
{
pm_.clear();
clear_locator();
}
};
/*{\Moptions print_title=yes }*/
/*{\Manpage {Nef_polyhedron_2}{T}{Nef Polyhedra in the Plane}{N}}*/
/*{\Mdefinition
An instance of data type |\Mname| is a subset of the plane that is
the result of forming complements and intersections starting from a
finite set |H| of half-spaces. |\Mtype| is closed under all binary set
operations |intersection|, |union|, |difference|, |complement| and
under the topological operations |boundary|, |closure|, and
|interior|.
The template parameter |T| is specified via an extended kernel
concept. |T| must be a model of the concept |ExtendedKernelTraits_2|.
}*/
template <typename T, typename Items_=HDS_items, typename Mark_=bool>
class Nef_polyhedron_2
: public Handle_for< Nef_polyhedron_2_rep<T,Items_,Mark_> >
{
public:
typedef T Extended_kernel;
static T EK; // static extended kernel
/*{\Mtypes 7}*/
typedef Mark_ Mark;
/*{\Xtypemember marking set membership or exclusion.}*/
typedef Items_ Items;
typedef Nef_polyhedron_2<T,Items,Mark> Self;
typedef Handle_for< Nef_polyhedron_2_rep<T,Items,Mark> > Base;
typedef typename T::Point_2 Extended_point;
typedef typename T::Segment_2 Extended_segment;
typedef typename T::Standard_line_2 Line;
/*{\Mtypemember the oriented lines modeling half-planes}*/
typedef typename T::Standard_point_2 Point;
/*{\Mtypemember the affine points of the plane.}*/
typedef typename T::Standard_direction_2 Direction;
/*{\Mtypemember directions in our plane.}*/
typedef typename T::Standard_aff_transformation_2 Aff_transformation;
/*{\Mtypemember affine transformations of the plane.}*/
// types for choosing the right constructor
struct Polylines {};
struct Polygons {};
typedef Polylines Polylines_tag;
typedef Polygons Polygons_tag;
enum Operation { JOIN=0 };
enum Boundary { EXCLUDED=0, INCLUDED=1 };
/*{\Menum construction selection.}*/
enum Content { EMPTY=0, COMPLETE=1 };
/*{\Menum construction selection}*/
static const Polylines POLYLINES;
static const Polygons POLYGONS;
protected:
struct AND { bool operator()(bool b1, bool b2) const { return b1&&b2; } };
struct OR { bool operator()(bool b1, bool b2) const { return b1||b2; } };
struct DIFF { bool operator()(bool b1, bool b2) const { return b1&&!b2; } };
struct XOR { bool operator()(bool b1, bool b2) const
{ return (b1&&!b2)||(!b1&&b2); } };
typedef Nef_polyhedron_2_rep<T,Items,Mark> Nef_rep;
typedef typename Nef_rep::Plane_map Plane_map;
typedef typename Nef_rep::Decorator Decorator;
typedef typename Nef_rep::Const_decorator Const_decorator;
typedef typename Nef_rep::Overlayer Overlayer;
//typedef typename Nef_rep::T Transformer;
typedef typename Nef_rep::Slocator Slocator;
typedef typename Nef_rep::Locator Locator;
using Base::ptr;
using Base::is_shared;
Plane_map& pm() { return ptr()->pm_; }
const Plane_map& pm() const { return ptr()->pm_; }
friend std::ostream& operator<< <>
(std::ostream& os, const Nef_polyhedron_2<T,Items,Mark>& NP);
friend std::istream& operator>> <>
(std::istream& is, Nef_polyhedron_2<T,Items,Mark>& NP);
typedef typename Decorator::Vertex_handle Vertex_handle;
typedef typename Decorator::Halfedge_handle Halfedge_handle;
typedef typename Decorator::Face_handle Face_handle;
typedef typename Decorator::Vertex_const_handle Vertex_const_handle;
typedef typename Decorator::Halfedge_const_handle Halfedge_const_handle;
typedef typename Decorator::Face_const_handle Face_const_handle;
typedef typename Decorator::Vertex_iterator Vertex_iterator;
typedef typename Decorator::Halfedge_iterator Halfedge_iterator;
typedef typename Decorator::Face_iterator Face_iterator;
typedef typename Const_decorator::Vertex_const_iterator
Vertex_const_iterator;
typedef typename Const_decorator::Halfedge_const_iterator
Halfedge_const_iterator;
typedef typename Const_decorator::Face_const_iterator
Face_const_iterator;
typedef Bounding_box_2<typename Is_extended_kernel<Extended_kernel>::value_type,
Extended_kernel> Box_2;
struct Except_frame_box_edges {
Decorator D_;
Face_handle f_;
Except_frame_box_edges(Plane_map& P)
: D_(P), f_(D_.faces_begin())
{}
bool
operator()(Halfedge_handle e, const Tag_true& ) const
{
return D_.face(e)==f_ || D_.face(D_.twin(e))==f_;
}
bool
operator()(Halfedge_handle /*e*/, const Tag_false& ) const
{
return false;
}
bool
operator()(Halfedge_handle e) const
{
return this->operator()(e, typename Is_extended_kernel<Extended_kernel>::value_type());
}
};
friend struct Except_frame_box_edges;
typedef std::list<Extended_segment> ES_list;
typedef typename ES_list::const_iterator ES_iterator;
void fill_with_frame_segs(ES_list& L, const Tag_true& ) const
/*{\Xop fills the list with the four segments which span our frame,
the convex hull of SW,SE,NW,NE.}*/
{ L.push_back(Extended_segment(EK.SW(),EK.NW()));
L.push_back(Extended_segment(EK.SW(),EK.SE()));
L.push_back(Extended_segment(EK.NW(),EK.NE()));
L.push_back(Extended_segment(EK.SE(),EK.NE()));
}
void fill_with_frame_segs(ES_list& , const Tag_false& ) const
{}
void fill_with_frame_segs(ES_list& L) const
{
fill_with_frame_segs(L, typename Is_extended_kernel<Extended_kernel>::value_type());
}
struct Link_to_iterator {
const Decorator& D;
Halfedge_handle _e;
Vertex_handle _v;
ES_iterator _it;
Mark _m;
Link_to_iterator(const Decorator& d, ES_iterator it, Mark m) :
D(d), _e(), _v(), _it(it), _m(m) {}
void supporting_segment(Halfedge_handle e, ES_iterator it)
{
if ( it == _it )
_e = e;
D.mark(e) = _m;
}
void trivial_segment(Vertex_handle v, ES_iterator it)
{
if ( it == _it )
_v = v;
D.mark(v) = _m;
}
void starting_segment(Vertex_handle v, ES_iterator)
{ D.mark(v) = _m; }
void passing_segment(Vertex_handle v, ES_iterator)
{ D.mark(v) = _m; }
void ending_segment(Vertex_handle v, ES_iterator)
{ D.mark(v) = _m; }
};
template<typename IT>
struct From_intersecting_polygons {
Unique_hash_map<Halfedge_handle,IT>& halfedge2iterator;
From_intersecting_polygons(Unique_hash_map<Halfedge_handle,IT>& e2i)
: halfedge2iterator(e2i) {}
void supporting_segment(Halfedge_handle e, IT it)
{
halfedge2iterator[e->opposite()] =
halfedge2iterator[e] = it; e->mark() = true;}
void trivial_segment(Vertex_handle v, IT)
{ v->mark() = true; }
void starting_segment(Vertex_handle v, IT)
{ v->mark() = true; }
void passing_segment(Vertex_handle v, IT)
{ v->mark() = true; }
void ending_segment(Vertex_handle v, IT)
{ v->mark() = true; }
};
friend struct Link_to_iterator;
void clear_outer_face_cycle_marks(const Tag_true&)
{ // unset all frame marks
Decorator D(pm());
Face_iterator f = D.faces_begin();
D.mark(f) = false;
Halfedge_handle e = D.holes_begin(f);
D.set_marks_in_face_cycle(e, false);
}
void clear_outer_face_cycle_marks(const Tag_false&)
{}
void clear_outer_face_cycle_marks()
{
clear_outer_face_cycle_marks(typename Is_extended_kernel<Extended_kernel>::value_type());
}
public:
/*{\Mcreation 3}*/
Nef_polyhedron_2(Content plane = EMPTY) : Base(Nef_rep())
/*{\Mcreate creates an instance |\Mvar| of type |\Mname|
and initializes it to the empty set if |plane == EMPTY|
and to the whole plane if |plane == COMPLETE|.}*/
{
ES_list L;
fill_with_frame_segs(L);
Overlayer D(pm());
Link_to_iterator I(D, --L.end(), false);
D.create(L.begin(),L.end(),I);
D.mark(--D.faces_end()) = bool(plane);
}
Nef_polyhedron_2(const Line& l, Boundary line = INCLUDED) : Base(Nef_rep())
/*{\Mcreate creates a Nef polyhedron |\Mvar| containing the half-plane
left of |l| including |l| if |line==INCLUDED|, excluding |l| if
|line==EXCLUDED|.}*/
{ CGAL_NEF_TRACEN("Nconstruction from line "<<l);
ES_list L;
fill_with_frame_segs(L);
if(check_tag(typename Is_extended_kernel<Extended_kernel>::value_type())) {
Extended_point ep1 = EK.construct_opposite_point(l);
Extended_point ep2 = EK.construct_point(l);
L.push_back(EK.construct_segment(ep1,ep2));
}
Overlayer D(pm());
Link_to_iterator I(D, --L.end(), false);
D.create(L.begin(),L.end(),I);
if(check_tag(typename Is_extended_kernel<Extended_kernel>::value_type())) {
CGAL_assertion( I._e != Halfedge_handle() );
Halfedge_handle el = I._e;
if ( D.point(D.target(el)) != EK.target(L.back()) )
el = D.twin(el);
D.mark(D.face(el)) = true;
D.mark(el) = bool(line);
} else {
D.mark(--D.faces_end()) = bool(EMPTY);
std::cerr << "Constructor not available with standard kernel. "
" Returned empty polygon!" << std::endl;
}
}
template <class Forward_iterator>
Nef_polyhedron_2(Forward_iterator it, Forward_iterator end,
Boundary b = INCLUDED) : Base(Nef_rep())
/*{\Mcreate creates a Nef polyhedron |\Mvar| from the simple polygon
|P| spanned by the list of points in the iterator range |[it,end)| and
including its boundary if |b = INCLUDED| and excluding the boundary
otherwise. |Forward_iterator| has to be an iterator with value type
|Point|. This construction expects that |P| is simple. The degenerate
cases where |P| contains no point, one point or spans just one segment
(two points) are correctly handled. In all degenerate cases there's
only one unbounded face adjacent to the degenerate polygon. If |b ==
INCLUDED| then |\Mvar| is just the boundary. If |b == EXCLUDED| then
|\Mvar| is the whole plane without the boundary.}*/
{
ES_list L;
fill_with_frame_segs(L);
bool empty = false;
if (it != end)
{
Extended_point ef, ep = ef = EK.construct_point(*it);
Forward_iterator itl=it; ++itl;
if (itl == end) // case only one point
L.push_back(EK.construct_segment(ep,ep));
else { // at least one segment
while( itl != end ) {
Extended_point en = EK.construct_point(*itl);
L.push_back(EK.construct_segment(ep,en));
ep = en; ++itl;
}
L.push_back(EK.construct_segment(ep,ef));
}
}
else empty = true;
Overlayer D(pm());
Link_to_iterator I(D, --L.end(), true);
D.create(L.begin(),L.end(),I);
if ( empty ) {
D.mark(--D.faces_end()) = !bool(b); return; }
CGAL_assertion( I._e != Halfedge_handle() || I._v != Vertex_handle() );
if ( EK.is_degenerate(L.back()) ) {
// its a point
CGAL_assertion(I._v != Vertex_handle());
D.mark(D.face(I._v)) = !bool(b); D.mark(I._v) = b;
} else {
// at least one segment
Halfedge_handle el = I._e;
if ( D.point(D.target(el)) != EK.target(L.back()) )
el = D.twin(el);
D.set_marks_in_face_cycle(el,bool(b));
unsigned int n =
check_tag(typename Is_extended_kernel<Extended_kernel>::value_type()) ? 2 : 1;
if ( D.number_of_faces() > n ) D.mark(D.face(el)) = true;
else D.mark(D.face(el)) = !bool(b);
}
clear_outer_face_cycle_marks();
}
// The constructor which takes an iterator range of polygons
template <class Forward_iterator>
Nef_polyhedron_2(Forward_iterator pit, Forward_iterator pend,
Polygons, Operation op = JOIN) : Base(Nef_rep()) {
CGAL_assertion(op==JOIN);
typedef typename std::iterator_traits<Forward_iterator>::value_type
iterator_pair;
typedef typename iterator_pair::first_type point_iterator;
point_iterator it, itl, end;
ES_list L;
fill_with_frame_segs(L);
for(;pit != pend; ++pit) {
it = pit->first;
end = pit->second;
if (it != end) {
Extended_point ef, ep = ef = EK.construct_point(*it);
itl=it; ++itl;
if (itl == end) // case only one point
L.push_back(EK.construct_segment(ep,ep));
else { // at least one segment
while( itl != end ) {
Extended_point en = EK.construct_point(*itl);
L.push_back(EK.construct_segment(ep,en));
ep = en; ++itl;
}
L.push_back(EK.construct_segment(ep,ef));
}
}
}
Overlayer D(pm());
Unique_hash_map<Halfedge_handle,ES_iterator> e2i;
From_intersecting_polygons<ES_iterator> fip(e2i);
D.create(L.begin(),L.end(),fip);
Face_handle outer_face;
if(check_tag(typename Is_extended_kernel<Extended_kernel>::value_type()))
outer_face = ++D.faces_begin();
else
outer_face = D.faces_begin();
Halfedge_handle e;
for(e=D.halfedges_begin(); e!=D.halfedges_end(); ++e) {
if(&*e < &*(D.twin(e)) && EK.is_standard(D.source(e)->point())) {
ES_iterator eit = e2i[e];
if(lexicographically_xy_smaller(EK.standard_point(eit->source()),
EK.standard_point(eit->target()))) {
if(lexicographically_xy_smaller(EK.standard_point(D.source(D.twin(e))->point()),
EK.standard_point(D.source(e)->point())))
e = D.twin(e);
} else
if(lexicographically_xy_smaller(EK.standard_point(D.source(e)->point()),
EK.standard_point(D.source(D.twin(e))->point())))
e = D.twin(e);
if(D.face(e) != outer_face)
D.mark(D.face(e)) = true;
}
}
D.simplify(Except_frame_box_edges(pm()));
clear_outer_face_cycle_marks();
}
// The constructor which takes an iterator range of polylines
template <class Forward_iterator>
Nef_polyhedron_2(Forward_iterator pit, Forward_iterator pend,
Polylines) : Base(Nef_rep()) {
typedef typename std::iterator_traits<Forward_iterator>::value_type
iterator_pair;
typedef typename iterator_pair::first_type point_iterator;
point_iterator it, itl, end;
ES_list L;
fill_with_frame_segs(L);
for(;pit != pend; ++pit) {
it = pit->first;
end = pit->second;
if (it != end) {
Extended_point ep = EK.construct_point(*it);
itl=it; ++itl;
if (itl == end) // case only one point
L.push_back(EK.construct_segment(ep,ep));
else { // at least one segment
while( itl != end ) {
Extended_point en = EK.construct_point(*itl);
L.push_back(EK.construct_segment(ep,en));
ep = en;
++itl;
}
}
}
}
Overlayer D(pm());
Link_to_iterator I(D, --L.end(), true);
D.create(L.begin(),L.end(),I, Overlayer::POLYLINE);
clear_outer_face_cycle_marks();
}
Nef_polyhedron_2(const Nef_polyhedron_2<T,Items,Mark>& N1) : Base(N1) {}
Nef_polyhedron_2& operator=(const Nef_polyhedron_2<T,Items,Mark>& N1)
{ Base::operator=(N1); return (*this); }
~Nef_polyhedron_2() {}
template <class Forward_iterator>
Nef_polyhedron_2(Forward_iterator first, Forward_iterator beyond,
double p) : Base(Nef_rep())
/*{\Xcreate creates a random Nef polyhedron from the arrangement of
the set of lines |S = set[first,beyond)|. The cells of the arrangement
are selected uniformly at random with probability $p$. \precond $0 < p
< 1$.}*/
{ CGAL_assertion(0<p && p<1);
ES_list L; fill_with_frame_segs(L);
while ( first != beyond ) {
Extended_point ep1 = EK.construct_opposite_point(*first);
Extended_point ep2 = EK.construct_point(*first);
L.push_back(EK.construct_segment(ep1,ep2)); ++first;
}
Overlayer D(pm());
Link_to_iterator I(D, --L.end(), false);
D.create(L.begin(),L.end(),I);
boost::rand48 rng;
boost::uniform_real<> dist(0,1);
boost::variate_generator<boost::rand48&, boost::uniform_real<> > get_double(rng,dist);
Vertex_iterator v; Halfedge_iterator e; Face_iterator f;
for (v = D.vertices_begin(); v != D.vertices_end(); ++v)
D.mark(v) = ( get_double() < p ? true : false );
for (e = D.halfedges_begin(); e != D.halfedges_end(); ++(++e))
D.mark(e) = ( get_double() < p ? true : false );
for (f = D.faces_begin(); f != D.faces_end(); ++f)
D.mark(f) = ( get_double() < p ? true : false );
D.simplify(Except_frame_box_edges(pm()));
clear_outer_face_cycle_marks();
}
protected:
Nef_polyhedron_2(const Plane_map& H, bool clone=true) : Base(Nef_rep())
/*{\Xcreate makes |\Mvar| a new object. If |clone==true| then the
underlying structure of |H| is copied into |\Mvar|.}*/
{ if (clone) {
Decorator D(pm()); // a decorator working on the rep plane map
D.clone(H); // cloning H into pm()
}
}
void clone_rep() { *this = Nef_polyhedron_2<T,Items,Mark>(pm()); }
/*{\Moperations 4 3 }*/
public:
void clear(Content plane = EMPTY)
{ *this = Nef_polyhedron_2(plane); }
/*{\Mop makes |\Mvar| the empty set if |plane == EMPTY| and the
full plane if |plane == COMPLETE|.}*/
bool is_empty() const
/*{\Mop returns true if |\Mvar| is empty, false otherwise.}*/
{ Const_decorator D(pm());
Face_const_iterator f = D.faces_begin();
if(check_tag(typename Is_extended_kernel<Extended_kernel>::
value_type()))
return (D.number_of_vertices()==4 &&
D.number_of_edges()==4 &&
D.number_of_faces()==2 &&
D.mark(++f) == false);
else
return (D.number_of_vertices()==0 &&
D.number_of_edges()==0 &&
D.number_of_faces()==1 &&
D.mark(f) == false);
}
bool is_plane() const
/*{\Mop returns true if |\Mvar| is the whole plane, false otherwise.}*/
{ Const_decorator D(pm());
Face_const_iterator f = D.faces_begin();
if(check_tag(typename Is_extended_kernel<Extended_kernel>::
value_type()))
return (D.number_of_vertices()==4 &&
D.number_of_edges()==4 &&
D.number_of_faces()==2 &&
D.mark(++f) == true);
else
return (D.number_of_vertices()==0 &&
D.number_of_edges()==0 &&
D.number_of_faces()==1 &&
D.mark(f) == true);
}
void extract_complement()
{ CGAL_NEF_TRACEN("extract complement");
if ( this->is_shared() ) {
clone_rep();
}
Overlayer D(pm());
Vertex_iterator v, vend = D.vertices_end();
for(v = D.vertices_begin(); v != vend; ++v) D.mark(v) = !D.mark(v);
Halfedge_iterator e, eend = D.halfedges_end();
for(e = D.halfedges_begin(); e != eend; ++(++e)) D.mark(e) = !D.mark(e);
Face_iterator f, fend = D.faces_end();
for(f = D.faces_begin(); f != fend; ++f) D.mark(f) = !D.mark(f);
clear_outer_face_cycle_marks();
}
void extract_interior()
{ CGAL_NEF_TRACEN("extract interior");
if ( this->is_shared() ) clone_rep();
Overlayer D(pm());
Vertex_iterator v, vend = D.vertices_end();
for(v = D.vertices_begin(); v != vend; ++v) D.mark(v) = false;
Halfedge_iterator e, eend = D.halfedges_end();
for(e = D.halfedges_begin(); e != eend; ++(++e)) D.mark(e) = false;
D.simplify(Except_frame_box_edges(pm()));
}
void extract_boundary()
{ CGAL_NEF_TRACEN("extract boundary");
if ( this->is_shared() ) clone_rep();
Overlayer D(pm());
Vertex_iterator v, vend = D.vertices_end();
for(v = D.vertices_begin(); v != vend; ++v) D.mark(v) = true;
Halfedge_iterator e, eend = D.halfedges_end();
for(e = D.halfedges_begin(); e != eend; ++(++e)) D.mark(e) = true;
Face_iterator f, fend = D.faces_end();
for(f = D.faces_begin(); f != fend; ++f) D.mark(f) = false;
clear_outer_face_cycle_marks();
D.simplify(Except_frame_box_edges(pm()));
}
void extract_closure()
/*{\Xop converts |\Mvar| to its closure. }*/
{ CGAL_NEF_TRACEN("extract closure");
extract_complement();
extract_interior();
extract_complement();
}
void extract_regularization()
/*{\Xop converts |\Mvar| to its regularization. }*/
{ CGAL_NEF_TRACEN("extract regularization");
extract_interior();
extract_closure();
}
/*{\Mtext \headerline{Constructive Operations}}*/
Nef_polyhedron_2<T,Items,Mark> complement() const
/*{\Mop returns the complement of |\Mvar| in the plane.}*/
{ Nef_polyhedron_2<T,Items,Mark> res = *this;
res.extract_complement();
return res;
}
Nef_polyhedron_2<T,Items,Mark> interior() const
/*{\Mop returns the interior of |\Mvar|.}*/
{ Nef_polyhedron_2<T,Items,Mark> res = *this;
res.extract_interior();
return res;
}
Nef_polyhedron_2<T,Items,Mark> closure() const
/*{\Mop returns the closure of |\Mvar|.}*/
{ Nef_polyhedron_2<T,Items,Mark> res = *this;
res.extract_closure();
return res;
}
Nef_polyhedron_2<T,Items,Mark> boundary() const
/*{\Mop returns the boundary of |\Mvar|.}*/
{ Nef_polyhedron_2<T,Items,Mark> res = *this;
res.extract_boundary();
return res;
}
Nef_polyhedron_2<T,Items,Mark> regularization() const
/*{\Mop returns the regularized polyhedron (closure of interior).}*/
{ Nef_polyhedron_2<T,Items,Mark> res = *this;
res.extract_regularization();
return res;
}
Nef_polyhedron_2<T,Items,Mark> intersection(const Nef_polyhedron_2<T,Items,Mark>& N1) const
/*{\Mop returns |\Mvar| $\cap$ |N1|. }*/
{ Nef_polyhedron_2<T,Items,Mark> res(pm(),false); // empty, no frame
Overlayer D(res.pm());
D.subdivide(pm(),N1.pm());
AND _and; D.select(_and);
res.clear_outer_face_cycle_marks();
D.simplify(Except_frame_box_edges(res.pm()));
return res;
}
Nef_polyhedron_2<T,Items,Mark> join(const Nef_polyhedron_2<T,Items,Mark>& N1) const
/*{\Mop returns |\Mvar| $\cup$ |N1|. }*/
{ Nef_polyhedron_2<T,Items,Mark> res(pm(),false); // empty, no frame
Overlayer D(res.pm());
D.subdivide(pm(),N1.pm());
OR _or; D.select(_or);
res.clear_outer_face_cycle_marks();
D.simplify(Except_frame_box_edges(res.pm()));
return res;
}
Nef_polyhedron_2<T,Items,Mark> difference(const Nef_polyhedron_2<T,Items,Mark>& N1) const
/*{\Mop returns |\Mvar| $-$ |N1|. }*/
{ Nef_polyhedron_2<T,Items,Mark> res(pm(),false); // empty, no frame
Overlayer D(res.pm());
D.subdivide(pm(),N1.pm());
DIFF _diff; D.select(_diff);
res.clear_outer_face_cycle_marks();
D.simplify(Except_frame_box_edges(res.pm()));
return res;
}
Nef_polyhedron_2<T,Items,Mark> symmetric_difference(
const Nef_polyhedron_2<T,Items,Mark>& N1) const
/*{\Mop returns the symmectric difference |\Mvar - T| $\cup$
|T - \Mvar|. }*/
{ Nef_polyhedron_2<T,Items,Mark> res(pm(),false); // empty, no frame
Overlayer D(res.pm());
D.subdivide(pm(),N1.pm());
XOR _xor; D.select(_xor);
res.clear_outer_face_cycle_marks();
D.simplify(Except_frame_box_edges(res.pm()));
return res;
}
#if 0
Nef_polyhedron_2<T,Items,Mark> transform(const Aff_transformation& t) const
/*{\Mop returns $t(|\Mvar|)$.}*/
{ Nef_polyhedron_2<T,Items,Mark> res(pm()); // cloned
Transformer PMT(res.pm());
PMT.transform(t);
return res;
}
#endif
/*{\Mtext Additionally there are operators |*,+,-,^,!| which
implement the binary operations \emph{intersection}, \emph{union},
\emph{difference}, \emph{symmetric difference}, and the unary
operation \emph{complement} respectively. There are also the
corresponding modification operations |*=,+=,-=,^=|.}*/
Nef_polyhedron_2<T,Items,Mark> operator*(const Nef_polyhedron_2<T,Items,Mark>& N1) const
{ return intersection(N1); }
Nef_polyhedron_2<T,Items,Mark> operator+(const Nef_polyhedron_2<T,Items,Mark>& N1) const
{ return join(N1); }
Nef_polyhedron_2<T,Items,Mark> operator-(const Nef_polyhedron_2<T,Items,Mark>& N1) const
{ return difference(N1); }
Nef_polyhedron_2<T,Items,Mark> operator^(const Nef_polyhedron_2<T,Items,Mark>& N1) const
{ return symmetric_difference(N1); }
Nef_polyhedron_2<T,Items,Mark> operator!() const
{ return complement(); }
Nef_polyhedron_2<T,Items,Mark>& operator*=(const Nef_polyhedron_2<T,Items,Mark>& N1)
{ *this = intersection(N1); return *this; }
Nef_polyhedron_2<T,Items,Mark>& operator+=(const Nef_polyhedron_2<T,Items,Mark>& N1)
{ *this = join(N1); return *this; }
Nef_polyhedron_2<T,Items,Mark>& operator-=(const Nef_polyhedron_2<T,Items,Mark>& N1)
{ *this = difference(N1); return *this; }
Nef_polyhedron_2<T,Items,Mark>& operator^=(const Nef_polyhedron_2<T,Items,Mark>& N1)
{ *this = symmetric_difference(N1); return *this; }
/*{\Mtext There are also comparison operations like |<,<=,>,>=,==,!=|
which implement the relations subset, subset or equal, superset, superset
or equal, equality, inequality, respectively.}*/
bool operator==(const Nef_polyhedron_2<T,Items,Mark>& N1) const
{ return symmetric_difference(N1).is_empty(); }
bool operator!=(const Nef_polyhedron_2<T,Items,Mark>& N1) const
{ return !operator==(N1); }
bool operator<=(const Nef_polyhedron_2<T,Items,Mark>& N1) const
{ return difference(N1).is_empty(); }
bool operator<(const Nef_polyhedron_2<T,Items,Mark>& N1) const
{ return difference(N1).is_empty() && !N1.difference(*this).is_empty(); }
bool operator>=(const Nef_polyhedron_2<T,Items,Mark>& N1) const
{ return N1.difference(*this).is_empty(); }
bool operator>(const Nef_polyhedron_2<T,Items,Mark>& N1) const
{ return N1.difference(*this).is_empty() && !difference(N1).is_empty(); }
/*{\Mtext \headerline{Exploration - Point location - Ray shooting}
As Nef polyhedra are the result of forming complements
and intersections starting from a set |H| of half-spaces that are
defined by oriented lines in the plane, they can be represented by
an attributed plane map $M = (V,E,F)$. For topological queries
within |M| the following types and operations allow exploration
access to this structure.}*/
/*{\Mtypes 3}*/
typedef Const_decorator Topological_explorer;
typedef CGAL::PM_explorer<Const_decorator,T> Explorer;
/*{\Mtypemember a decorator to examine the underlying plane map.
See the manual page of |Explorer|.}*/
typedef typename Locator::Object_handle Object_handle;
/*{\Mtypemember a generic handle to an object of the underlying
plane map. The kind of object |(vertex, halfedge, face)| can
be determined and the object can be assigned to a corresponding
handle by the three functions:\\
|bool assign(Vertex_const_handle& h, Object_handle)|\\
|bool assign(Halfedge_const_handle& h, Object_handle)|\\
|bool assign(Face_const_handle& h, Object_handle)|\\
where each function returns |true| iff the assignment to
|h| was done.}*/
enum Location_mode { DEFAULT, NAIVE, LMWT };
/*{\Menum selection flag for the point location mode.}*/
/*{\Moperations 3 1 }*/
void init_locator() const
{ const_cast<Self*>(this)->ptr()->init_locator(); }
const Locator& locator() const
{ CGAL_assertion(ptr()->pl_); return *(ptr()->pl_); }
bool contains(Object_handle h) const
/*{\Mop returns true iff the object |h| is contained in the set
represented by |\Mvar|.}*/
{ Slocator PL(pm()); return PL.mark(h); }
bool contained_in_boundary(Object_handle h) const
/*{\Mop returns true iff the object |h| is contained in the $1$-skeleton
of |\Mvar|.}*/
{ Vertex_const_handle v;
Halfedge_const_handle e;
return ( CGAL::assign(v,h) || CGAL::assign(e,h) );
}
Object_handle locate(const Point& p, Location_mode m = DEFAULT) const
/*{\Mop returns a generic handle |h| to an object (face, halfedge, vertex)
of the underlying plane map that contains the point |p| in its relative
interior. The point |p| is contained in the set represented by |\Mvar| if
|\Mvar.contains(h)| is true. The location mode flag |m| allows one to choose
between different point location strategies.}*/
{
if (m == DEFAULT || m == LMWT) {
init_locator();
Extended_point ep = EK.construct_point(p);
return locator().locate(ep);
} else if (m == NAIVE) {
Slocator PL(pm(),EK);
Extended_segment s(EK.construct_point(p),
PL.point(PL.vertices_begin()));
return PL.locate(s);
}
CGAL_error_msg("location mode not implemented.");
return Object_handle();
}
struct INSET {
const Const_decorator& D;
INSET(const Const_decorator& Di) : D(Di) {}
bool operator()(Vertex_const_handle v) const { return D.mark(v); }
bool operator()(Halfedge_const_handle e) const { return D.mark(e); }
bool operator()(Face_const_handle f) const { return D.mark(f); }
};
friend struct INSET;
Object_handle ray_shoot(const Point& p, const Direction& d,
Location_mode m = DEFAULT) const
/*{\Mop returns a handle |h| with |\Mvar.contains(h)| that can be
converted to a |Vertex_/Halfedge_/Face_const_handle| as described
above. The object returned is intersected by the ray starting in |p|
with direction |d| and has minimal distance to |p|. The operation
returns the null handle |NULL| if the ray shoot along |d| does not hit
any object |h| of |\Mvar| with |\Mvar.contains(h)|. The location mode
flag |m| allows one to choose between different point location
strategies.}*/
{
Extended_point ep, eq;
if(!check_tag(typename Is_extended_kernel<Extended_kernel>::value_type())) {
Const_decorator D(pm());
Box_2 b(D.vertices_begin(), D.vertices_end());
ep = EK.construct_point(p);
eq = b.intersection_ray_bbox(p,d);
} else {
ep = EK.construct_point(p);
eq = EK.construct_point(p,d);
}
if (m == DEFAULT || m == LMWT) {
init_locator();
return locator().ray_shoot(EK.construct_segment(ep,eq),
INSET(locator()));
} else if (m == NAIVE) {
Slocator PL(pm(),EK);
return PL.ray_shoot(EK.construct_segment(ep,eq),INSET(PL));
}
CGAL_error_msg("location mode not implemented.");
return Object_handle();
}
struct INSKEL {
bool operator()(Vertex_const_handle) const { return true; }
bool operator()(Halfedge_const_handle) const { return true; }
bool operator()(Face_const_handle) const { return false; }
};
Object_handle ray_shoot_to_boundary(const Point& p, const Direction& d,
Location_mode m = DEFAULT) const
/*{\Mop returns a handle |h| that can be converted to a
|Vertex_/Halfedge_const_handle| as described above. The object
returned is part of the $1$-skeleton of |\Mvar|, intersected by the
ray starting in |p| with direction |d| and has minimal distance to
|p|. The operation returns the null handle |NULL| if the ray shoot
along |d| does not hit any $1$-skeleton object |h| of |\Mvar|. The
location mode flag |m| allows one to choose between different point
location strategies.}*/
{
Extended_point ep, eq;
if(!check_tag(typename Is_extended_kernel<Extended_kernel>::value_type())) {
Const_decorator D(pm());
Box_2 b(D.vertices_begin(), D.vertices_end());
ep = EK.construct_point(p);
eq = b.intersection_ray_bbox(p,d);
} else {
ep = EK.construct_point(p);
eq = EK.construct_point(p,d);
}
if (m == DEFAULT || m == LMWT) {
init_locator();
return locator().ray_shoot(EK.construct_segment(ep,eq),
INSKEL());
} else if (m == NAIVE) {
Slocator PL(pm(),EK);
return PL.ray_shoot(EK.construct_segment(ep,eq),INSKEL());
}
CGAL_error_msg("location mode not implemented.");
return Object_handle();
}
Explorer explorer() const { return Explorer(pm(),EK); }
/*{\Mop returns a decorator object which allows read-only access of
the underlying plane map. See the manual page |Explorer| for its
usage.}*/
/*{\Mimplementation Nef polyhedra are implemented on top of a halfedge
data structure and use linear space in the number of vertices, edges
and facets. Operations like |empty| take constant time. The
operations |clear|, |complement|, |interior|, |closure|, |boundary|,
|regularization|, input and output take linear time. All binary set
operations and comparison operations take time $O(n \log n)$ where $n$
is the size of the output plus the size of the input.
The point location and ray shooting operations are implemented in
two flavors. The |NAIVE| operations run in linear query time without
any preprocessing, the |DEFAULT| operations (equals |LMWT|) run in
sub-linear query time, but preprocessing is triggered with the first
operation. Preprocessing takes time $O(N^2)$, the sub-linear point
location time is either logarithmic when LEDA's persistent
dictionaries are present or if not then the point location time is
worst-case linear, but experiments show often sublinear runtimes. Ray
shooting equals point location plus a walk in the constrained
triangulation overlayed on the plane map representation. The cost of
the walk is proportional to the number of triangles passed in
direction |d| until an obstacle is met. In a minimum weight
triangulation of the obstacles (the plane map representing the
polyhedron) the theory provides a $O(\sqrt{n})$ bound for the number
of steps. Our locally minimum weight triangulation approximates the
minimum weight triangulation only heuristically (the calculation of
the minimum weight triangulation is conjectured to be NP hard). Thus
we have no runtime guarantee but a strong experimental motivation for
its approximation.}*/
/*{\Mexample Nef polyhedra are parameterized by a so-called extended
geometric kernel. There are three kernels, one based on a homogeneous
representation of extended points called |Extended_homogeneous<RT>|
where |RT| is a ring type providing additionally a |gcd| operation and
one based on a cartesian representation of extended points called
|Extended_cartesian<NT>| where |NT| is a field type, and finally
|Filtered_extended_homogeneous<RT>| (an optimized version of the
first).
The member types of |Nef_polyhedron_2< Extended_homogeneous<NT> >|
map to corresponding types of the CGAL geometry kernel
(e.g. |Nef_polyhedron::Line| equals
|CGAL::Homogeneous<leda_integer>::Line_2| in the example below).
\begin{Mverb}
#include <CGAL/basic.h>
#include <CGAL/leda_integer.h>
#include <CGAL/Extended_homogeneous.h>
#include <CGAL/Nef_polyhedron_2.h>
using namespace CGAL;
typedef Extended_homogeneous<leda_integer> Extended_kernel;
typedef Nef_polyhedron_2<Extended_kernel> Nef_polyhedron;
typedef Nef_polyhedron::Line Line;
int main()
{
Nef_polyhedron N1(Line(1,0,0));
Nef_polyhedron N2(Line(0,1,0), Nef_polyhedron::EXCLUDED);
Nef_polyhedron N3 = N1 * N2; // line (*)
return 0;
}
\end{Mverb}
After line (*) |N3| is the intersection of |N1| and |N2|.}*/
}; // end of Nef_polyhedron_2
template <typename T, typename Items, typename Mark>
T Nef_polyhedron_2<T,Items,Mark>::EK;
template <typename T, typename Items, typename Mark>
const typename Nef_polyhedron_2<T,Items,Mark>::Polygons Nef_polyhedron_2<T,Items,Mark>::POLYGONS = typename Nef_polyhedron_2<T,Items,Mark>::Polygons();
template <typename T, typename Items, typename Mark>
const typename Nef_polyhedron_2<T,Items,Mark>::Polylines Nef_polyhedron_2<T,Items,Mark>::POLYLINES = typename Nef_polyhedron_2<T,Items,Mark>::Polylines();
template <typename T, typename Items, typename Mark>
std::ostream& operator<<
(std::ostream& os, const Nef_polyhedron_2<T,Items,Mark>& NP)
{
os << "Nef_polyhedron_2<" << NP.EK.output_identifier() << ">\n";
typedef typename Nef_polyhedron_2<T,Items,Mark>::Decorator Decorator;
CGAL::PM_io_parser<Decorator> O(os, NP.pm()); O.print();
return os;
}
template <typename T, typename Items, typename Mark>
std::istream& operator>>
(std::istream& is, Nef_polyhedron_2<T,Items,Mark>& NP)
{
typedef typename Nef_polyhedron_2<T,Items,Mark>::Decorator Decorator;
CGAL::PM_io_parser<Decorator> I(is, NP.pm());
if (I.check_sep("Nef_polyhedron_2<") &&
I.check_sep(NP.EK.output_identifier()) &&
I.check_sep(">")) I.read();
else {
std::cerr << "Nef_polyhedron_2 input corrupted." << std::endl;
NP = Nef_polyhedron_2<T,Items,Mark>();
}
typename Nef_polyhedron_2<T,Items,Mark>::Topological_explorer D(NP.explorer());
D.check_integrity_and_topological_planarity();
return is;
}
} //namespace CGAL
#include <CGAL/enable_warnings.h>
#endif //CGAL_NEF_POLYHEDRON_2_H