cgal/Packages/Planar_map/include/CGAL/Pm_default_point_location.h

382 lines
11 KiB
C++

// Copyright (c) 1997 Tel-Aviv University (Israel).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL distributed with CGAL.
//
// 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.
//
// $Source$
// $Revision$ $Date$
// $Name$
//
// Author(s) : Oren Nechushtan <theoren@math.tau.ac.il>
// Iddo Hanniel <hanniel@math.tau.ac.il>
#ifndef CGAL_PM_DEFAULT_POINT_LOCATION_H
#define CGAL_PM_DEFAULT_POINT_LOCATION_H
#include <CGAL/Pm_point_location_base.h>
#include <CGAL/Trapezoidal_decomposition_2.h>
#include <CGAL/Td_traits.h>
CGAL_BEGIN_NAMESPACE
////////////////////////////////////////////////////////////////////
// DEFAULT PLANAR MAP STRATEGY
///////////////////////////////////////////////////////////////////
template <class Planar_map_>
class PL_X_curve_plus: public Planar_map_::Traits::X_curve
{
public:
typedef Planar_map_ Planar_map;
typedef typename Planar_map::Traits Traits;
typedef typename Traits::X_curve curve;
typedef typename Traits::Point Point;
typedef typename Planar_map::Locate_type Locate_type;
typedef typename Planar_map::Halfedge_handle Halfedge_handle;
typedef typename Planar_map::Halfedge_iterator Halfedge_iterator;
PL_X_curve_plus() : curve(),parent() {};
PL_X_curve_plus(const curve &cv,const Halfedge_handle& p) :
curve(cv), parent(p) {}
PL_X_curve_plus(const Halfedge_handle& p) : curve(p->curve()),parent(p){}
// used when no Halfedge_handle is supplied.
PL_X_curve_plus(const curve &cv) : curve(cv),parent() {};
PL_X_curve_plus(const PL_X_curve_plus &cv) : curve(cv),parent(cv.parent){}
~PL_X_curve_plus(){}
PL_X_curve_plus& operator=(const PL_X_curve_plus &cv)
{
// Workaround a bug in the Irix compiler
#if ((SGI == _sgi) && (_COMPILER_VERSION <= 730))
static_cast<curve&>(*this) = cv;
#else
curve::operator=(cv);
#endif
parent=cv.get_parent();
return *this;
}
Halfedge_handle get_parent() const
{
return parent;
}
protected:
Halfedge_handle parent;
};
//------------------------------------------------------------------
template <class Planar_map_>
class Pm_default_point_location : public Pm_point_location_base<Planar_map_> {
public:
typedef Planar_map_ Planar_map;
typedef Pm_point_location_base<Planar_map_> Base;
typedef Pm_default_point_location<Planar_map> Self;
typedef typename Planar_map::Traits Pm_traits;
typedef typename Planar_map::Traits_wrap Pm_traits_wrap;
typedef typename Planar_map::Locate_type Locate_type;
typedef typename Planar_map::Halfedge_handle Halfedge_handle;
typedef typename Planar_map::Halfedge_iterator Halfedge_iterator;
typedef typename Planar_map::Ccb_halfedge_circulator Ccb_halfedge_circulator;
typedef PL_X_curve_plus<Planar_map> X_curve_plus;
// SunPro gets confused (a bug) because of the two Td_traits in the same
// class scope. We add the CGAL namespace as a workaround.
typedef CGAL::Td_traits<Pm_traits_wrap,X_curve_plus> Td_traits;
typedef Trapezoidal_decomposition_2<Td_traits> Trapezoidal_decomposition;
typedef Pm_bounding_box_base<Planar_map> Bounding_box;
typedef typename Pm_traits::Point Point;
typedef typename Pm_traits::X_curve X_curve;
typedef typename Pm_point_location_base<Planar_map>::
Halfedge_handle_container Halfedge_handle_container;
typedef typename Pm_point_location_base<Planar_map>::Halfedge_handle_iterator
Halfedge_handle_iterator;
typedef typename Base::Token Token;
protected:
typedef Trapezoidal_decomposition TD;
typedef Planar_map PM;
typedef const Self* cPLp;
public:
Pm_default_point_location(bool rebuild=true) :
pm(NULL),
traits(NULL)
{
td.set_needs_update(rebuild);
}
~Pm_default_point_location()
{
if (traits) delete traits;
}
/*
Postcondition:
h->curve() with a reference back to h
is inserted into TD.
*/
void insert(Halfedge_handle h,
const X_curve& cv) //additions by iddo for arrangement
{
td.insert(X_curve_plus(cv,h));
}
Halfedge_handle locate(const Point& p, Locate_type& lt) const;
Halfedge_handle locate(const Point& p, Locate_type& lt);
Halfedge_handle vertical_ray_shoot(const Point& p, Locate_type& lt, bool up)
const;
Halfedge_handle vertical_ray_shoot(const Point& p, Locate_type& lt, bool up);
//the function is called after the combinatoric split
//we want O(1) is it possible?? no!
void split_edge(const X_curve &cv,
Halfedge_handle e1,
Halfedge_handle e2
//additions by iddo for arrangement
,const X_curve& cv1, const X_curve& cv2
//end additions
)
{
// td.split_edge(X_curve_plus(cv),X_curve_plus(e1),X_curve_plus(e2));
td.split_edge(X_curve_plus(cv),X_curve_plus(cv1,e1),X_curve_plus(cv2,e2));
}
/*
called after combinatoric merge
e is the new edge cv1,cv2 are the original curves
*/
void merge_edge(const X_curve &cv1,
const X_curve &cv2,
Halfedge_handle e
//additions by iddo for arrangement
,const X_curve& cv
//end additions
)
{
td.merge_edge(
X_curve_plus(cv1),
X_curve_plus(cv2),
// X_curve_plus(e)
X_curve_plus(cv,e)
);
}
//called before combinatoric deletion
void remove_edge(Halfedge_handle e)
{
td.remove(X_curve_plus(e));
}
void remove_edge(const Halfedge_handle_iterator& begin,
const Halfedge_handle_iterator& end)
{
std::vector<X_curve_plus> c;
Halfedge_handle_iterator it=begin;
while (it!=end) { c.push_back((*it)->curve());++it;}
td.remove(c.begin(),c.end());
}
inline void clear() { td.clear(); }
inline void update(const Halfedge_handle_iterator& begin,
const Halfedge_handle_iterator& end,
const Token& token)
// Shuffle curves, remove them from the map and reinsert them afterwards.
{
#ifdef CGAL_PMBB_DEBUG
std::cout << "\nPL::update called with traits = ";
traits->debug();
#endif
if (begin!=end)
{
Halfedge_handle_container c;
Halfedge_handle_iterator it=begin;
while (it!=end)
{
c.push_back(Halfedge_handle(*it));
++it;
}
remove_edge(begin,end);
Halfedge_handle_iterator cend=c.end();
it=c.begin();
token.rebuild_bounding_box(this);
while(it!=cend)
{
insert(*it,(*it)->curve());
++it;
}
}
else
{
token.rebuild_bounding_box(this);
}
#ifdef CGAL_PMBB_DEBUG
std::cout << "\nPL::update exited with traits = ";
traits->debug();
#endif
}
const TD* get_trapezoidal_decomposition() const {return &td;}
inline const Pm_traits* get_traits() const {return traits;}
void init(Planar_map& pmp, Pm_traits& tr)
{
CGAL_precondition_msg(pm == NULL,
"Point location instance should be uninitialized "
"(Do not use the same instance for more than one map).");
pm = &pmp;
if (traits) delete traits;
traits = new Td_traits(tr);
td.init_traits(traits);
}
#ifdef CGAL_PM_DEBUG
public:
void debug()
{
#ifdef CGAL_TD_DEBUG
td.debug();
#endif
}
#endif
protected:
TD td;
private:
Planar_map* pm;
Td_traits* traits;
bool halfedge_represents_point(const Halfedge_handle& h,const Point& p) const
{
const Point
&source=h->source()->point(),
&target=h->target()->point();
return !(!traits->point_equal_x(target,p)||
traits->point_equal_x(source,p)&&
(traits->point_is_right_top(p,target)&&
traits->point_is_left_low(target,source)||
traits->point_is_left_low(p,target)&&
traits->point_is_right_top(target,source)
));
}
/*
description:
returns if the point is located in the
open halfplane on the right side of the
input curve
(considering the halfedge orientation)
preconditions:
the input curve is not vertical,
p is in its x range but not on its closure
*/
bool halfedge_represents_point_inside_face(const Halfedge_handle& h,
const Point& p) const
{
return (traits->point_in_x_range(h->curve(),p) &&
traits->curve_compare_y_at_x(p, h->curve()) == LARGER) ==
traits->point_is_left(h->source()->point(),h->target()->point());
}
Halfedge_handle halfedge_representing_unbounded_face() const
{
CGAL_assertion(pm);
if (pm->unbounded_face()->holes_begin()!=pm->unbounded_face()->holes_end())
{
// case PM is not empty
//return *(pm->unbounded_face()->holes_begin());
typename Planar_map::Holes_iterator hot =
pm->unbounded_face()->holes_begin();
return (*hot);
}
else
// case PM is empty
return pm->halfedges_end();
}
//use the latter
//to workaround internal compiler error in egcs1.1
//Locate_type convert(const Point& p,const TD::Locate_type& lt,
// Halfedge_handle& h,bool up=true) const
Locate_type convert(const Point & p,const int & lt,Halfedge_handle & h,
bool up = true) const
{
switch(lt)
{
// h->target() should represent p
case TD::POINT:
if (!halfedge_represents_point(h,p)) h=h->twin();
return PM::VERTEX;
case TD::CURVE:
/* special case:
h->source()->point(),p,h->target()->point() have same x
coardinates.
return value should be h(no h->twin()).
*/
// orientation of h
if (up==traits->point_is_left(h->source()->point(),
h->target()->point()))
h=h->twin();
return PM::EDGE;
case TD::TRAPEZOID:
if (!halfedge_represents_point_inside_face(h,p)) h=h->twin();
CGAL_postcondition(halfedge_represents_point_inside_face(h,p));
if (!h->face()->is_unbounded())
return PM::FACE;
// otherwise pass to UNBOUNDED_TRAPEZOID case
case TD::UNBOUNDED_TRAPEZOID:
h=halfedge_representing_unbounded_face();
CGAL_postcondition(h->face()->is_unbounded());
return PM::UNBOUNDED_FACE;
default:
CGAL_assertion(lt==TD::POINT||lt==TD::CURVE||lt==TD::TRAPEZOID||
lt==TD::UNBOUNDED_TRAPEZOID);
}
return Locate_type();
}
const Bounding_box* get_bounding_box() const {return pm->get_bounding_box();}
};
CGAL_END_NAMESPACE
#ifdef CGAL_CFG_NO_AUTOMATIC_TEMPLATE_INCLUSION
#include <CGAL/Pm_default_point_location.C>
#endif
#endif
/*
X_curve msvc6 workaround:
typedef typename Traits::X_curve X_curve;
causes
error C2086: '<Unknown>' : redefinition
*/
/*
egcs workaround:
To solve the internal compiler errors egcs had when dealing
with nested templated classes we moved them outside:
template <class Planar_map_>
class PL_X_curve_plus: public Planar_map_::Traits::X_curve
*/