cgal/Nef_2/include/CGAL/Nef_2/gen_point_location.h

571 lines
20 KiB
C++

// Copyright (c) 1997-2000 Max-Planck-Institute Saarbruecken (Germany).
// 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.
//
// $URL$
// $Id$
//
//
// Author(s) : Michael Seel <seel@mpi-sb.mpg.de>
#ifndef GEN_POINT_LOCATION_H
#define GEN_POINT_LOCATION_H
#include <CGAL/LEDA_basic.h>
#if CGAL_LEDA_VERSION < 500
#include <LEDA/pp_dictionary.h>
#else
#include <LEDA/core/pp_dictionary.h>
#endif
#include <sstream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <CGAL/Nef_2/geninfo.h>
#undef CGAL_NEF_DEBUG
#define CGAL_NEF_DEBUG 17
#include <CGAL/Nef_2/debug.h>
// #define CHECKING_OFF
// for dictionary
template <class Node>
inline std::ostream& operator<<(std::ostream& o, const std::list<Node>& n)
{ return o; }
/*{\Manpage {GenericLocation}{Node, Edge}
{Return Type for Planar Point Location}{L}}*/
template <class Node, class Edge>
class GenericLocation {
/*{\Mdefinition
An instance of the data type |\Mtype| is used as return value for planar
point location. It can store a node or an edge of a graph or the special
value |nil| which is used to signal that no node or edge could be found.
}*/
typedef void* GenPtr;
public:
/*{\Mtypes}*/
enum Type { NIL, NODE, EDGE };
/*{\Menum This enumeration allows to specify the 3 basic types of the
values that a |\Mtype| can represent.}*/
/*{\Mcreation}*/
GenericLocation() { init(); }
/*{\Mcreate creates a |\Mtype| and initializes with the value |nil|.}*/
GenericLocation(Node n) { init(n); }
/*{\Mcreate creates a |\Mtype| and initializes with the node |n|.}*/
GenericLocation(Edge e) { init(e); }
/*{\Mcreate creates a |\Mtype| and initializes with the edge |e|.}*/
~GenericLocation() { clear(); }
GenericLocation(const GenericLocation<Node, Edge>& L) { assign(L); }
GenericLocation<Node, Edge>& operator=(
const GenericLocation<Node, Edge>& L)
{ clear(); assign(L); return *this; }
/*{\Moperations}*/
operator const Node&() const
{
#if !defined(CHECKING_OFF)
if (type != NODE)
CGAL_LEDA_SCOPE::error_handler(1, "Location: not convertible to node");
#endif
return geninfo<Node>::const_access(value);
}
/*{\Mconversion converts |\Mvar| into a node.\\
\precond |\Mvar| represents a node.}*/
operator const Edge&() const
{
#if !defined(CHECKING_OFF)
if (type != EDGE)
CGAL_LEDA_SCOPE::error_handler(1, "Location: not convertible to edge");
#endif
return geninfo<Edge>::const_access(value);
}
/*{\Mconversion converts |\Mvar| into an edge.\\
\precond |\Mvar| represents an edge.}*/
GenericLocation<Node, Edge>& operator=(Node n)
{ clear(); init(n); return *this; }
/*{\Mbinop makes |\Mvar| represent the node |n|.}*/
GenericLocation<Node, Edge>& operator=(Edge e)
{ clear(); init(e); return *this; }
/*{\Mbinop makes |\Mvar| represent the edge |e|.}*/
Type get_type() const { return type; }
/*{\Mop returns the type of the value contained in |\Mvar|.}*/
bool is_nil() const { return type == NIL; }
/*{\Mop returns |true| iff |\Mvar| represents the value |nil|.}*/
bool is_node() const { return type == NODE; }
/*{\Mop returns |true| iff |\Mvar| represents a node.}*/
bool is_edge() const { return type == EDGE; }
/*{\Mop returns |true| iff |\Mvar| represents an edge.}*/
private:
void init() { type = NIL; }
void init(Node n)
{ type = NODE;
geninfo<Node>::create(value);
geninfo<Node>::access(value) = n;
}
void init(Edge e)
{ type = EDGE;
geninfo<Edge>::create(value);
geninfo<Edge>::access(value) = e;
}
void clear()
{
switch(type) {
case NODE: geninfo<Node>::clear(value); break;
case EDGE: geninfo<Edge>::clear(value); break;
case NIL: break;
}
}
void assign(const GenericLocation<Node, Edge>& L)
{
type = L.type;
switch(type) {
case NODE:
geninfo<Node>::access(value) = geninfo<Node>::const_access(L.value);
break;
case EDGE:
geninfo<Edge>::access(value) = geninfo<Edge>::const_access(L.value);
break;
case NIL: break;
}
}
public:
typedef GenericLocation<Node, Edge> self;
private:
Type type;
GenPtr value;
};
/*{\Mimplementation
The data type |\Mtype| is implemented as a union of the types |Node| and
|Edge|. There is only constant time and space overhead.
}*/
template <class Node, class Edge>
inline
bool
operator==(const GenericLocation<Node, Edge>& L1,
const GenericLocation<Node, Edge>& L2)
{
if (L1.get_type() != L2.get_type()) return false;
switch (L1.get_type()) {
case GenericLocation<Node, Edge>::NIL: return true;
case GenericLocation<Node, Edge>::NODE: return Node(L1) == Node(L2);
case GenericLocation<Node, Edge>::EDGE: return Edge(L1) == Edge(L2);
}
}
template <class Node, class Edge>
inline
bool
operator!=(const GenericLocation<Node, Edge>& L1,
const GenericLocation<Node, Edge>& L2)
{ return ! (L1==L2); }
template <class Node, class Edge>
std::ostream& operator<<(std::ostream& o,
const GenericLocation<Node, Edge>& L)
{
switch (L.get_type()) {
case GenericLocation<Node, Edge>::NIL: return o<<"nil";
case GenericLocation<Node, Edge>::NODE: return o<<"node("<<&*Node(L)<<')';
case GenericLocation<Node, Edge>::EDGE: return o<<"edge("<<&*Edge(L)<<')';
}
return o;
}
template <class Node, class Edge>
std::istream& operator>>(std::istream& i, GenericLocation<Node, Edge>&)
{ return i; }
template <class XCoord, class PredLessThanX, class Sweepline>
class GenericXStructure {
public:
typedef std::vector<XCoord> Array_Coordinates;
typedef std::vector<Sweepline> Array_Sweeplines;
typedef typename Array_Coordinates::const_iterator Coord_iterator;
typedef typename Array_Sweeplines::const_iterator Sweepline_iterator;
private:
int stops;
PredLessThanX LtX;
Array_Coordinates Coordinates;
Array_Sweeplines SweepLines;
// SweepLines[0] is EmptyLine;
public:
GenericXStructure() { clear(); }
GenericXStructure(int n, const PredLessThanX& cmp) { init(n, cmp); }
~GenericXStructure() { clear(); }
void init(int n, const PredLessThanX& cmp)
{ CGAL_NEF_TRACEN("XSinit "<<n);
LtX = cmp;
Coordinates = Array_Coordinates(n);
SweepLines = Array_Sweeplines(2*n+1);
stops = 0;
}
void clear()
{ Coordinates.clear();
SweepLines.clear();
stops = 0;
}
void insertLines(const XCoord& X,
const Sweepline& atX, const Sweepline& inXplus)
{ CGAL_NEF_TRACEN("XSinsert "<<X);
Coordinates[stops] = X;
SweepLines[2*stops+1] = atX;
SweepLines[2*stops+2] = inXplus;
++stops;
}
Sweepline_iterator getLineAt(const XCoord& X) const
{ CGAL_NEF_TRACEN("XSgetLineAt "<<X);
Sweepline_iterator sit = SweepLines.begin(); // EmptyLine
if ( LtX(X,*Coordinates.begin()) ) {
CGAL_NEF_TRACEN("infinity first");
return sit; // ]-infinity, x0[
}
Coord_iterator stopit = std::lower_bound (
Coordinates.begin(),Coordinates.end(),X,LtX);
/* determines stopit maximal such that
\forall j \in [begin,stopit) : *j < X
as a consequence now: *stopit >= X */
bool found_exact = false;
if ( LtX(X,*stopit) ) --stopit; // X < *stopit
else found_exact = true; // X >= *stopit
CGAL_NEF_TRACEN("stopit "<<*stopit);
int offset = stopit-Coordinates.begin();
return found_exact ?
SweepLines.begin() + (2*offset+1) :
SweepLines.begin() + (2*offset+2);
}
Sweepline_iterator begin() const { return SweepLines.begin(); }
Sweepline_iterator end() const { return SweepLines.end();}
};
/*{\Manpage {PointLocator} {PLocTraits} {Planar Point Location} {PL}}*/
template <class PLocTraits>
class PointLocator {
/*{\Mdefinition
An instance |\Mvar| of the parameterized data type |\Mtype| can be used
to perform point location queries in the two-dimensional plane.
Every non-empty instance |\Mvar| is associated with an embedded planar
graph |G|, which has to remain unchanged while it is referenced by |PL|.\\
A location query for a point |p| returns the first object (node or edge)
of |G| which is intersected by the straight ray starting in |p| and going
vertically downwards/upwards.
If the ray does not intersect any node or edge of |G|, then |nil| is
returned.\\
The class |\Mtype| is generic, it is parameterized with a traits class
|PLocTraits| which widely controls its behaviour.
The traits may even change the return type of a query and its semantics.
There are predined traits classes for the LEDA graph types, which are
described below in a seperate section.
}*/
public:
// copied types from PLocTraits
typedef typename PLocTraits::Point Point;
typedef typename PLocTraits::XCoord XCoord;
typedef typename PLocTraits::PredLessThanX PredLessThanX;
typedef typename PLocTraits::Graph Graph;
typedef typename PLocTraits::Node Node;
typedef typename PLocTraits::Edge Edge;
typedef typename PLocTraits::NodeIterator NodeIterator;
typedef typename PLocTraits::IncEdgeIterator IncEdgeIterator;
typedef typename PLocTraits::Curve Curve;
typedef typename PLocTraits::PredCompareCurves PredCompareCurves;
typedef typename PLocTraits::QueryResult QueryResult;
/*{\Mtypes}*/
// define additional types
typedef GenericLocation<Node, Edge> Location;
/*{\Mtypedef usual return value for the point loaction.}*/
enum Direction { downwards, upwards};
/*{\Menum used to specify the direction for the point location.}*/
typedef CGAL_LEDA_SCOPE::pp_dictionary<Curve, Location, PredCompareCurves>
Sweepline;
typedef GenericXStructure<XCoord, PredLessThanX, Sweepline> XStructure;
typedef typename Sweepline::item SL_item;
typedef typename XStructure::Sweepline_iterator Sweepline_iterator;
/*{\Mcreation}*/
PointLocator() { clear(); }
/*{\Mcreate creates an empty |\Mtype|.}*/
PointLocator(const Graph& G, const PLocTraits& PLT = PLocTraits()) :
traits(PLT) { init(G); }
/*{\Mcreate creates a |\Mtype| for the graph |G| and the traits |PLT|.}*/
/*{\Moperations}*/
void clear() { X_Structure.clear(); traits.clear(); }
/*{\Mop makes |\Mvar| empty.}*/
void init(const Graph& G, const PLocTraits& PLT) { traits = PLT; init(G); }
/*{\Mop makes |\Mvar| a |\Mtype| for the graph |G| and the traits |PLT|.}*/
void init(const Graph& G);
/*{\Mop makes |\Mvar| a |\Mtype| for the graph |G|.}*/
QueryResult locate(const Point& p, const Direction dir) const
{ return dir == downwards ? locate_down(p) : locate_up(p); }
/*{\Mop locates the point |p| in the direction |dir|.}*/
QueryResult locate_down(const Point& p) const;
/*{\Mop locates the point |p| vertically downwards.}*/
QueryResult locate_up(const Point& p) const;
/*{\Mop locates the point |p| vertically upwards.}*/
Location location(Sweepline_iterator S, SL_item it) const
{ return (it == nil ? Location() : S->inf(it)); }
std::string str(const Sweepline& S) const
{ std::ostringstream os; os << "Sweepline:\n";
SL_item it;
forall_items(it,S) { os << " " << S.key(it) << std::endl; }
return os.str();
}
private:
PLocTraits traits;
XStructure X_Structure;
};
template <class PLocTraits>
void
PointLocator<PLocTraits>::init(const Graph& G)
{
traits.sweep_begin(G);
PredLessThanX LtX = traits.getLessThanX();
typedef std::map<XCoord, std::list<Node>, PredLessThanX> dictionary;
typedef typename dictionary::iterator dic_iterator;
dictionary stops(LtX);
// Note: X_Structure, Sweepline, and stops copy compare object
NodeIterator ni = traits.Nodes_begin(G), beyond = traits.Nodes_end(G);
for(; ni != beyond; ++ni) {
XCoord currentX = traits.getXCoord(G, ni);
stops[currentX].push_front(traits.toNode(ni));
}
Sweepline SL(traits.getCompareCurves());
X_Structure.init(stops.size(), LtX);
dic_iterator stop;
for(stop = stops.begin(); stop != stops.end(); ++stop) {
std::list<Node>& NodesOnSL = stop->second;
traits.sweep_moveto(traits.getXCoord(G, *NodesOnSL.begin()));
std::list<Edge> EmergingEdges, VerticalEdges;
// explore the nodes on SL
typename std::list<Node>::iterator cur_node;
for(cur_node = NodesOnSL.begin();
cur_node != NodesOnSL.end(); ++cur_node) {
IncEdgeIterator ei = traits.IncEdges_begin(G, *cur_node);
IncEdgeIterator beyond = traits.IncEdges_end(G, *cur_node);
CGAL_NEF_TRACEN("NODE: "<<(*cur_node)->point());
for(; ei != beyond; ++ei) {
switch (traits.ClassifyEdge(G, traits.toEdge(ei), *cur_node)) {
case PLocTraits::StartingNonVertical:
EmergingEdges.push_front(traits.toEdge(ei)); break;
case PLocTraits::StartingVertical:
VerticalEdges.push_front(traits.toEdge(ei)); break;
case PLocTraits::EndingNonVertical:
SL.del(traits.makeCurve(G, traits.toEdge(ei))); break;
case PLocTraits::EndingVertical: break;
}
}
}
// compute SL_at_X
typename std::list<Edge>::iterator cur_edge;
for(cur_edge=VerticalEdges.begin();
cur_edge!=VerticalEdges.end(); ++cur_edge)
SL.insert(traits.makeCurve(G, *cur_edge), Location(*cur_edge));
for(cur_node=NodesOnSL.begin();
cur_node!=NodesOnSL.end(); ++cur_node)
SL.insert(traits.makeCurve(G, *cur_node), Location(*cur_node));
Sweepline SL_at_X = SL;
// compute SL_in_X_plus
for(cur_edge=VerticalEdges.begin();
cur_edge!=VerticalEdges.end(); ++cur_edge)
SL.del(traits.makeCurve(G, *cur_edge));
for(cur_node=NodesOnSL.begin();
cur_node!=NodesOnSL.end(); ++cur_node)
SL.del(traits.makeCurve(G, *cur_node));
for(cur_edge=EmergingEdges.begin();
cur_edge!=EmergingEdges.end(); ++cur_edge)
SL.insert(traits.makeCurve(G, *cur_edge), Location(*cur_edge));
X_Structure.insertLines(traits.getXCoord(G, *NodesOnSL.begin()),
SL_at_X, SL);
}
traits.sweep_end();
}
template <class PLocTraits>
typename PointLocator<PLocTraits>::QueryResult
PointLocator<PLocTraits>::
locate_down(const typename PLocTraits::Point& p) const
{
Sweepline_iterator line_at_x = X_Structure.getLineAt(traits.getXCoord(p)),
line_plus = line_at_x;
CGAL_NEF_TRACEN("locate_down "<<str(*line_at_x));
Curve p_curve = traits.makeCurve(p);
PredCompareCurves cmp = traits.getCompareCurves();
SL_item it = line_at_x->locate_pred(p_curve), it_plus(0);
if ( it && line_at_x->inf(it).is_node() &&
cmp(p_curve, line_at_x->key(it))!=0 ) {
// p hit a feature exactly
line_plus = line_at_x+1;
if ( line_plus != X_Structure.end() )
it_plus = line_plus->locate_pred(p_curve);
}
return traits.PostProcess(location(line_at_x,it),
location(line_plus,it_plus),p);
}
template <class PLocTraits>
typename PointLocator<PLocTraits>::QueryResult
PointLocator<PLocTraits>::locate_up(const typename PLocTraits::Point& p) const
{
Sweepline_iterator line_at_x =
X_Structure.getLineAt(traits.getXCoord(p)), line_plus;
Curve p_curve = traits.makeCurve(p);
PredCompareCurves cmp = traits.getCompareCurves();
SL_item it = line_at_x->locate_succ(p_curve), it_plus(0);
if ( it && line_at_x->inf(it).is_node() &&
cmp(p_curve, line_at_x->key(it))!=0 ) {
// p hit a feature exactly
line_plus = line_at_x+1;
if ( line_plus != X_Structure.end() )
it_plus = line_plus->locate_succ(p_curve);
}
return traits.PostProcess(location(line_at_x,it),
location(line_plus,it_plus), p);
}
/*{\Mimplementation
The implementation of the data type |\Mtype| is based on partially
persistent binary search trees.
The expected space requirement is $O(k)$ where $k$ is the sum of the number
of nodes and the number of edges in the graph $G$.
The expected time needed for construction and the operation |init| is
$O(k \cdot \log k)$, for the |locate|-operations it is $O(\log k)$. The
operation |clear| runs in $O(k)$.
}*/
/*{\Mtext
\headerline{\arabic{manctr}. Predefined traits classes}
\stepcounter{manctr}
All predefined traits classes have in common that the return type of a query
is the type |Location|.
The embedding of the given graph |G| is a straight-line embedding, so that
it is totally determined by the position of the nodes of |G|.
Such a position is specified by a |Point| which can be one of the LEDA point
types |point| or |rat_point|. The positions can be specified implicitly by
the node attribute of a parameterized graph (e.g. |GRAPH<Point,...>|) or
explicitly by a |node_array<Point>|. In case of explicit specification a
|node_array| with the positions of the nodes can be passed to the constructor
of the traits class.
Further, the point location processes for maps and for standard graphs differ
slightly. As a map is a bidirected graph where each edge knows its reversal,
the traits classes for maps can ensure the following property:
If the result of a query for point |p| is an edge |e| (not containing |p|),
then |e| bounds the face of |G| which contains |p|, i.e. |p| lies to the
left of |e|.\\
Here comes a list of the predefined traits classes:\\[-5.5ex]
\begin{itemize}
\item |PLocTraits<Graph>|: standard traits for implicitly specified node
positions\\
|Graph| can be |GRAPH<Point,...>| (standard graph) or
|PLANAR_MAP<Point,...,...>| (map).
\item |PLocTraits_NodeArray<Graph,Point>|: std. traits for explicitly
specified node positions\\
|Graph| can be |graph| (standard graph) or |planar_map| (map).
\item |PLocTraits_Map<Graph>| and |PLocTraits_Map_NodeArray<Graph,Point>|:\\
The parameter |Graph| can be |GRAPH<Point,...>| and |graph| respectively.
These traits classes assume that the given graphs are maps.
\item |PLocTraits< GRAPH<Circle,Point> >|: traits class for closest-site
voronoi diagrams
\end{itemize}
Note that a traits class instantiated with |Graph| can also handle graph
types which are derived from |Graph|. Thus |PLocTraits< graph<Point,T> >|
can be used for graphs of type |ugraph<Point,T>| for example.
}*/
/*{\Mexample
First we show an example where the node positions are given implicitly
as node attributes:
\begin{verbatim}
typedef PointLocator< PLocTraits< GRAPH<Point, int> > > PLocator1;
typedef PLocator1::Location Location;
UGRAPH<Point, int> G;
... // construct G
PLocator1 PL1(G);
Point p = ...; // compute p
Location L1 = PL1.locate_down(p);
\end{verbatim}
The second example shows how a |node_array| can be used to determine the
node positions:
\begin{verbatim}
typedef PLocTraits_NodeArray<planar_map,Point> PLocTraits2;
typedef PointLocator<PLocTraits2> PLocator2;
planar_map pm;
node_array<Point> na;
... // construct pm and na
PLocator2 PL2(pm, PLocTraits2(na));
Point q = ...; // compute q
Location L2 = PL2.locate_up(q);
\end{verbatim}
}*/
#endif // GEN_POINT_LOCATION_H