BWAPI
|
00001 // Copyright (c) 1997-2000 Max-Planck-Institute Saarbruecken (Germany). 00002 // All rights reserved. 00003 // 00004 // This file is part of CGAL (www.cgal.org); you may redistribute it under 00005 // the terms of the Q Public License version 1.0. 00006 // See the file LICENSE.QPL distributed with CGAL. 00007 // 00008 // Licensees holding a valid commercial license may use this file in 00009 // accordance with the commercial license agreement provided with the software. 00010 // 00011 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00012 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00013 // 00014 // $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Nef_2/include/CGAL/Nef_2/gen_point_location.h $ 00015 // $Id: gen_point_location.h 41627 2008-01-14 23:06:54Z spion $ 00016 // 00017 // 00018 // Author(s) : Michael Seel <seel@mpi-sb.mpg.de> 00019 00020 00021 #ifndef CGAL_NEF_2_GEN_POINT_LOCATION_H 00022 #define CGAL_NEF_2_GEN_POINT_LOCATION_H 00023 00024 #include <CGAL/LEDA_basic.h> 00025 #if CGAL_LEDA_VERSION < 500 00026 #include <LEDA/pp_dictionary.h> 00027 #else 00028 #include <LEDA/core/pp_dictionary.h> 00029 #endif 00030 #include <sstream> 00031 #include <string> 00032 #include <list> 00033 #include <vector> 00034 #include <map> 00035 #include <CGAL/Nef_2/geninfo.h> 00036 00037 #undef CGAL_NEF_DEBUG 00038 #define CGAL_NEF_DEBUG 17 00039 #include <CGAL/Nef_2/debug.h> 00040 00041 // #define CHECKING_OFF 00042 00043 // for dictionary 00044 template <class Node> 00045 inline std::ostream& operator<<(std::ostream& o, const std::list<Node>& n) 00046 { return o; } 00047 00048 /*{\Manpage {GenericLocation}{Node, Edge} 00049 {Return Type for Planar Point Location}{L}}*/ 00050 00051 template <class Node, class Edge> 00052 class GenericLocation { 00053 /*{\Mdefinition 00054 An instance of the data type |\Mtype| is used as return value for planar 00055 point location. It can store a node or an edge of a graph or the special 00056 value |nil| which is used to signal that no node or edge could be found. 00057 }*/ 00058 typedef void* GenPtr; 00059 public: 00060 /*{\Mtypes}*/ 00061 enum Type { NIL, NODE, EDGE }; 00062 /*{\Menum This enumeration allows to specify the 3 basic types of the 00063 values that a |\Mtype| can represent.}*/ 00064 00065 /*{\Mcreation}*/ 00066 GenericLocation() { init(); } 00067 /*{\Mcreate creates a |\Mtype| and initializes with the value |nil|.}*/ 00068 GenericLocation(Node n) { init(n); } 00069 /*{\Mcreate creates a |\Mtype| and initializes with the node |n|.}*/ 00070 GenericLocation(Edge e) { init(e); } 00071 /*{\Mcreate creates a |\Mtype| and initializes with the edge |e|.}*/ 00072 00073 ~GenericLocation() { clear(); } 00074 00075 GenericLocation(const GenericLocation<Node, Edge>& L) { assign(L); } 00076 GenericLocation<Node, Edge>& operator=( 00077 const GenericLocation<Node, Edge>& L) 00078 { clear(); assign(L); return *this; } 00079 00080 /*{\Moperations}*/ 00081 operator const Node&() const 00082 { 00083 #if !defined(CHECKING_OFF) 00084 if (type != NODE) 00085 CGAL_LEDA_SCOPE::error_handler(1, "Location: not convertible to node"); 00086 #endif 00087 return geninfo<Node>::const_access(value); 00088 } 00089 /*{\Mconversion converts |\Mvar| into a node.\\ 00090 \precond |\Mvar| represents a node.}*/ 00091 00092 operator const Edge&() const 00093 { 00094 #if !defined(CHECKING_OFF) 00095 if (type != EDGE) 00096 CGAL_LEDA_SCOPE::error_handler(1, "Location: not convertible to edge"); 00097 #endif 00098 return geninfo<Edge>::const_access(value); 00099 } 00100 /*{\Mconversion converts |\Mvar| into an edge.\\ 00101 \precond |\Mvar| represents an edge.}*/ 00102 00103 GenericLocation<Node, Edge>& operator=(Node n) 00104 { clear(); init(n); return *this; } 00105 /*{\Mbinop makes |\Mvar| represent the node |n|.}*/ 00106 00107 GenericLocation<Node, Edge>& operator=(Edge e) 00108 { clear(); init(e); return *this; } 00109 /*{\Mbinop makes |\Mvar| represent the edge |e|.}*/ 00110 00111 Type get_type() const { return type; } 00112 /*{\Mop returns the type of the value contained in |\Mvar|.}*/ 00113 00114 bool is_nil() const { return type == NIL; } 00115 /*{\Mop returns |true| iff |\Mvar| represents the value |nil|.}*/ 00116 00117 bool is_node() const { return type == NODE; } 00118 /*{\Mop returns |true| iff |\Mvar| represents a node.}*/ 00119 00120 bool is_edge() const { return type == EDGE; } 00121 /*{\Mop returns |true| iff |\Mvar| represents an edge.}*/ 00122 00123 private: 00124 void init() { type = NIL; } 00125 void init(Node n) 00126 { type = NODE; 00127 geninfo<Node>::create(value); 00128 geninfo<Node>::access(value) = n; 00129 } 00130 void init(Edge e) 00131 { type = EDGE; 00132 geninfo<Edge>::create(value); 00133 geninfo<Edge>::access(value) = e; 00134 } 00135 00136 void clear() 00137 { 00138 switch(type) { 00139 case NODE: geninfo<Node>::clear(value); break; 00140 case EDGE: geninfo<Edge>::clear(value); break; 00141 case NIL: break; 00142 } 00143 } 00144 00145 void assign(const GenericLocation<Node, Edge>& L) 00146 { 00147 type = L.type; 00148 switch(type) { 00149 case NODE: 00150 geninfo<Node>::access(value) = geninfo<Node>::const_access(L.value); 00151 break; 00152 case EDGE: 00153 geninfo<Edge>::access(value) = geninfo<Edge>::const_access(L.value); 00154 break; 00155 case NIL: break; 00156 } 00157 } 00158 00159 public: 00160 typedef GenericLocation<Node, Edge> self; 00161 00162 00163 private: 00164 Type type; 00165 GenPtr value; 00166 }; 00167 00168 /*{\Mimplementation 00169 The data type |\Mtype| is implemented as a union of the types |Node| and 00170 |Edge|. There is only constant time and space overhead. 00171 }*/ 00172 template <class Node, class Edge> 00173 inline 00174 bool 00175 operator==(const GenericLocation<Node, Edge>& L1, 00176 const GenericLocation<Node, Edge>& L2) 00177 { 00178 if (L1.get_type() != L2.get_type()) return false; 00179 switch (L1.get_type()) { 00180 case GenericLocation<Node, Edge>::NIL: return true; 00181 case GenericLocation<Node, Edge>::NODE: return Node(L1) == Node(L2); 00182 case GenericLocation<Node, Edge>::EDGE: return Edge(L1) == Edge(L2); 00183 } 00184 } 00185 00186 template <class Node, class Edge> 00187 inline 00188 bool 00189 operator!=(const GenericLocation<Node, Edge>& L1, 00190 const GenericLocation<Node, Edge>& L2) 00191 { return ! (L1==L2); } 00192 00193 template <class Node, class Edge> 00194 std::ostream& operator<<(std::ostream& o, 00195 const GenericLocation<Node, Edge>& L) 00196 { 00197 switch (L.get_type()) { 00198 case GenericLocation<Node, Edge>::NIL: return o<<"nil"; 00199 case GenericLocation<Node, Edge>::NODE: return o<<"node("<<&*Node(L)<<')'; 00200 case GenericLocation<Node, Edge>::EDGE: return o<<"edge("<<&*Edge(L)<<')'; 00201 } 00202 return o; 00203 } 00204 00205 template <class Node, class Edge> 00206 std::istream& operator>>(std::istream& i, GenericLocation<Node, Edge>&) 00207 { return i; } 00208 template <class XCoord, class PredLessThanX, class Sweepline> 00209 class GenericXStructure { 00210 public: 00211 typedef std::vector<XCoord> Array_Coordinates; 00212 typedef std::vector<Sweepline> Array_Sweeplines; 00213 typedef typename Array_Coordinates::const_iterator Coord_iterator; 00214 typedef typename Array_Sweeplines::const_iterator Sweepline_iterator; 00215 private: 00216 int stops; 00217 PredLessThanX LtX; 00218 Array_Coordinates Coordinates; 00219 Array_Sweeplines SweepLines; 00220 // SweepLines[0] is EmptyLine; 00221 public: 00222 GenericXStructure() { clear(); } 00223 GenericXStructure(int n, const PredLessThanX& cmp) { init(n, cmp); } 00224 ~GenericXStructure() { clear(); } 00225 00226 void init(int n, const PredLessThanX& cmp) 00227 { CGAL_NEF_TRACEN("XSinit "<<n); 00228 LtX = cmp; 00229 Coordinates = Array_Coordinates(n); 00230 SweepLines = Array_Sweeplines(2*n+1); 00231 stops = 0; 00232 } 00233 00234 void clear() 00235 { Coordinates.clear(); 00236 SweepLines.clear(); 00237 stops = 0; 00238 } 00239 00240 void insertLines(const XCoord& X, 00241 const Sweepline& atX, const Sweepline& inXplus) 00242 { CGAL_NEF_TRACEN("XSinsert "<<X); 00243 Coordinates[stops] = X; 00244 SweepLines[2*stops+1] = atX; 00245 SweepLines[2*stops+2] = inXplus; 00246 ++stops; 00247 } 00248 00249 Sweepline_iterator getLineAt(const XCoord& X) const 00250 { CGAL_NEF_TRACEN("XSgetLineAt "<<X); 00251 Sweepline_iterator sit = SweepLines.begin(); // EmptyLine 00252 if ( LtX(X,*Coordinates.begin()) ) { 00253 CGAL_NEF_TRACEN("infinity first"); 00254 return sit; // ]-infinity, x0[ 00255 } 00256 Coord_iterator stopit = std::lower_bound ( 00257 Coordinates.begin(),Coordinates.end(),X,LtX); 00258 /* determines stopit maximal such that 00259 \forall j \in [begin,stopit) : *j < X 00260 as a consequence now: *stopit >= X */ 00261 bool found_exact = false; 00262 if ( LtX(X,*stopit) ) --stopit; // X < *stopit 00263 else found_exact = true; // X >= *stopit 00264 00265 CGAL_NEF_TRACEN("stopit "<<*stopit); 00266 int offset = stopit-Coordinates.begin(); 00267 return found_exact ? 00268 SweepLines.begin() + (2*offset+1) : 00269 SweepLines.begin() + (2*offset+2); 00270 } 00271 00272 Sweepline_iterator begin() const { return SweepLines.begin(); } 00273 Sweepline_iterator end() const { return SweepLines.end();} 00274 00275 }; 00276 /*{\Manpage {PointLocator} {PLocTraits} {Planar Point Location} {PL}}*/ 00277 00278 template <class PLocTraits> 00279 class PointLocator { 00280 /*{\Mdefinition 00281 An instance |\Mvar| of the parameterized data type |\Mtype| can be used 00282 to perform point location queries in the two-dimensional plane. 00283 Every non-empty instance |\Mvar| is associated with an embedded planar 00284 graph |G|, which has to remain unchanged while it is referenced by |PL|.\\ 00285 A location query for a point |p| returns the first object (node or edge) 00286 of |G| which is intersected by the straight ray starting in |p| and going 00287 vertically downwards/upwards. 00288 If the ray does not intersect any node or edge of |G|, then |nil| is 00289 returned.\\ 00290 The class |\Mtype| is generic, it is parameterized with a traits class 00291 |PLocTraits| which widely controls its behaviour. 00292 The traits may even change the return type of a query and its semantics. 00293 There are predined traits classes for the LEDA graph types, which are 00294 described below in a seperate section. 00295 }*/ 00296 public: 00297 // copied types from PLocTraits 00298 typedef typename PLocTraits::Point Point; 00299 typedef typename PLocTraits::XCoord XCoord; 00300 typedef typename PLocTraits::PredLessThanX PredLessThanX; 00301 00302 typedef typename PLocTraits::Graph Graph; 00303 typedef typename PLocTraits::Node Node; 00304 typedef typename PLocTraits::Edge Edge; 00305 typedef typename PLocTraits::NodeIterator NodeIterator; 00306 typedef typename PLocTraits::IncEdgeIterator IncEdgeIterator; 00307 00308 typedef typename PLocTraits::Curve Curve; 00309 typedef typename PLocTraits::PredCompareCurves PredCompareCurves; 00310 00311 typedef typename PLocTraits::QueryResult QueryResult; 00312 00313 /*{\Mtypes}*/ 00314 // define additional types 00315 typedef GenericLocation<Node, Edge> Location; 00316 /*{\Mtypedef usual return value for the point loaction.}*/ 00317 00318 enum Direction { downwards, upwards}; 00319 /*{\Menum used to specify the direction for the point location.}*/ 00320 00321 typedef CGAL_LEDA_SCOPE::pp_dictionary<Curve, Location, PredCompareCurves> 00322 Sweepline; 00323 typedef GenericXStructure<XCoord, PredLessThanX, Sweepline> XStructure; 00324 typedef typename Sweepline::item SL_item; 00325 typedef typename XStructure::Sweepline_iterator Sweepline_iterator; 00326 /*{\Mcreation}*/ 00327 PointLocator() { clear(); } 00328 /*{\Mcreate creates an empty |\Mtype|.}*/ 00329 00330 PointLocator(const Graph& G, const PLocTraits& PLT = PLocTraits()) : 00331 traits(PLT) { init(G); } 00332 /*{\Mcreate creates a |\Mtype| for the graph |G| and the traits |PLT|.}*/ 00333 00334 /*{\Moperations}*/ 00335 void clear() { X_Structure.clear(); traits.clear(); } 00336 /*{\Mop makes |\Mvar| empty.}*/ 00337 00338 00339 void init(const Graph& G, const PLocTraits& PLT) { traits = PLT; init(G); } 00340 /*{\Mop makes |\Mvar| a |\Mtype| for the graph |G| and the traits |PLT|.}*/ 00341 00342 void init(const Graph& G); 00343 /*{\Mop makes |\Mvar| a |\Mtype| for the graph |G|.}*/ 00344 00345 00346 QueryResult locate(const Point& p, const Direction dir) const 00347 { return dir == downwards ? locate_down(p) : locate_up(p); } 00348 /*{\Mop locates the point |p| in the direction |dir|.}*/ 00349 00350 QueryResult locate_down(const Point& p) const; 00351 /*{\Mop locates the point |p| vertically downwards.}*/ 00352 00353 QueryResult locate_up(const Point& p) const; 00354 /*{\Mop locates the point |p| vertically upwards.}*/ 00355 00356 Location location(Sweepline_iterator S, SL_item it) const 00357 { return (it == nil ? Location() : S->inf(it)); } 00358 00359 std::string str(const Sweepline& S) const 00360 { std::ostringstream os; os << "Sweepline:\n"; 00361 SL_item it; 00362 forall_items(it,S) { os << " " << S.key(it) << std::endl; } 00363 return os.str(); 00364 } 00365 00366 00367 private: 00368 PLocTraits traits; 00369 XStructure X_Structure; 00370 00371 }; 00372 00373 template <class PLocTraits> 00374 void 00375 PointLocator<PLocTraits>::init(const Graph& G) 00376 { 00377 traits.sweep_begin(G); 00378 PredLessThanX LtX = traits.getLessThanX(); 00379 typedef std::map<XCoord, std::list<Node>, PredLessThanX> dictionary; 00380 typedef typename dictionary::iterator dic_iterator; 00381 dictionary stops(LtX); 00382 // Note: X_Structure, Sweepline, and stops copy compare object 00383 00384 NodeIterator ni = traits.Nodes_begin(G), beyond = traits.Nodes_end(G); 00385 for(; ni != beyond; ++ni) { 00386 XCoord currentX = traits.getXCoord(G, ni); 00387 stops[currentX].push_front(traits.toNode(ni)); 00388 } 00389 00390 Sweepline SL(traits.getCompareCurves()); 00391 X_Structure.init(stops.size(), LtX); 00392 dic_iterator stop; 00393 for(stop = stops.begin(); stop != stops.end(); ++stop) { 00394 std::list<Node>& NodesOnSL = stop->second; 00395 traits.sweep_moveto(traits.getXCoord(G, *NodesOnSL.begin())); 00396 std::list<Edge> EmergingEdges, VerticalEdges; 00397 00398 // explore the nodes on SL 00399 typename std::list<Node>::iterator cur_node; 00400 for(cur_node = NodesOnSL.begin(); 00401 cur_node != NodesOnSL.end(); ++cur_node) { 00402 IncEdgeIterator ei = traits.IncEdges_begin(G, *cur_node); 00403 IncEdgeIterator beyond = traits.IncEdges_end(G, *cur_node); 00404 CGAL_NEF_TRACEN("NODE: "<<(*cur_node)->point()); 00405 for(; ei != beyond; ++ei) { 00406 switch (traits.ClassifyEdge(G, traits.toEdge(ei), *cur_node)) { 00407 case PLocTraits::StartingNonVertical: 00408 EmergingEdges.push_front(traits.toEdge(ei)); break; 00409 case PLocTraits::StartingVertical: 00410 VerticalEdges.push_front(traits.toEdge(ei)); break; 00411 case PLocTraits::EndingNonVertical: 00412 SL.del(traits.makeCurve(G, traits.toEdge(ei))); break; 00413 case PLocTraits::EndingVertical: break; 00414 } 00415 } 00416 } 00417 00418 // compute SL_at_X 00419 00420 typename std::list<Edge>::iterator cur_edge; 00421 for(cur_edge=VerticalEdges.begin(); 00422 cur_edge!=VerticalEdges.end(); ++cur_edge) 00423 SL.insert(traits.makeCurve(G, *cur_edge), Location(*cur_edge)); 00424 for(cur_node=NodesOnSL.begin(); 00425 cur_node!=NodesOnSL.end(); ++cur_node) 00426 SL.insert(traits.makeCurve(G, *cur_node), Location(*cur_node)); 00427 Sweepline SL_at_X = SL; 00428 00429 // compute SL_in_X_plus 00430 00431 for(cur_edge=VerticalEdges.begin(); 00432 cur_edge!=VerticalEdges.end(); ++cur_edge) 00433 SL.del(traits.makeCurve(G, *cur_edge)); 00434 for(cur_node=NodesOnSL.begin(); 00435 cur_node!=NodesOnSL.end(); ++cur_node) 00436 SL.del(traits.makeCurve(G, *cur_node)); 00437 00438 for(cur_edge=EmergingEdges.begin(); 00439 cur_edge!=EmergingEdges.end(); ++cur_edge) 00440 SL.insert(traits.makeCurve(G, *cur_edge), Location(*cur_edge)); 00441 00442 X_Structure.insertLines(traits.getXCoord(G, *NodesOnSL.begin()), 00443 SL_at_X, SL); 00444 } 00445 00446 traits.sweep_end(); 00447 } 00448 00449 template <class PLocTraits> 00450 typename PointLocator<PLocTraits>::QueryResult 00451 PointLocator<PLocTraits>:: 00452 locate_down(const typename PLocTraits::Point& p) const 00453 { 00454 Sweepline_iterator line_at_x = X_Structure.getLineAt(traits.getXCoord(p)), 00455 line_plus = line_at_x; 00456 CGAL_NEF_TRACEN("locate_down "<<str(*line_at_x)); 00457 Curve p_curve = traits.makeCurve(p); 00458 PredCompareCurves cmp = traits.getCompareCurves(); 00459 SL_item it = line_at_x->locate_pred(p_curve), it_plus(0); 00460 if ( it && line_at_x->inf(it).is_node() && 00461 cmp(p_curve, line_at_x->key(it))!=0 ) { 00462 // p hit a feature exactly 00463 line_plus = line_at_x+1; 00464 if ( line_plus != X_Structure.end() ) 00465 it_plus = line_plus->locate_pred(p_curve); 00466 } 00467 return traits.PostProcess(location(line_at_x,it), 00468 location(line_plus,it_plus),p); 00469 } 00470 00471 template <class PLocTraits> 00472 typename PointLocator<PLocTraits>::QueryResult 00473 PointLocator<PLocTraits>::locate_up(const typename PLocTraits::Point& p) const 00474 { 00475 Sweepline_iterator line_at_x = 00476 X_Structure.getLineAt(traits.getXCoord(p)), line_plus; 00477 Curve p_curve = traits.makeCurve(p); 00478 PredCompareCurves cmp = traits.getCompareCurves(); 00479 SL_item it = line_at_x->locate_succ(p_curve), it_plus(0); 00480 if ( it && line_at_x->inf(it).is_node() && 00481 cmp(p_curve, line_at_x->key(it))!=0 ) { 00482 // p hit a feature exactly 00483 line_plus = line_at_x+1; 00484 if ( line_plus != X_Structure.end() ) 00485 it_plus = line_plus->locate_succ(p_curve); 00486 } 00487 return traits.PostProcess(location(line_at_x,it), 00488 location(line_plus,it_plus), p); 00489 } 00490 00491 /*{\Mimplementation 00492 The implementation of the data type |\Mtype| is based on partially 00493 persistent binary search trees. 00494 The expected space requirement is $O(k)$ where $k$ is the sum of the number 00495 of nodes and the number of edges in the graph $G$. 00496 The expected time needed for construction and the operation |init| is 00497 $O(k \cdot \log k)$, for the |locate|-operations it is $O(\log k)$. The 00498 operation |clear| runs in $O(k)$. 00499 }*/ 00500 /*{\Mtext 00501 \headerline{\arabic{manctr}. Predefined traits classes} 00502 \stepcounter{manctr} 00503 All predefined traits classes have in common that the return type of a query 00504 is the type |Location|. 00505 The embedding of the given graph |G| is a straight-line embedding, so that 00506 it is totally determined by the position of the nodes of |G|. 00507 Such a position is specified by a |Point| which can be one of the LEDA point 00508 types |point| or |rat_point|. The positions can be specified implicitly by 00509 the node attribute of a parameterized graph (e.g. |GRAPH<Point,...>|) or 00510 explicitly by a |node_array<Point>|. In case of explicit specification a 00511 |node_array| with the positions of the nodes can be passed to the constructor 00512 of the traits class. 00513 Further, the point location processes for maps and for standard graphs differ 00514 slightly. As a map is a bidirected graph where each edge knows its reversal, 00515 the traits classes for maps can ensure the following property: 00516 If the result of a query for point |p| is an edge |e| (not containing |p|), 00517 then |e| bounds the face of |G| which contains |p|, i.e. |p| lies to the 00518 left of |e|.\\ 00519 Here comes a list of the predefined traits classes:\\[-5.5ex] 00520 \begin{itemize} 00521 \item |PLocTraits<Graph>|: standard traits for implicitly specified node 00522 positions\\ 00523 |Graph| can be |GRAPH<Point,...>| (standard graph) or 00524 |PLANAR_MAP<Point,...,...>| (map). 00525 \item |PLocTraits_NodeArray<Graph,Point>|: std. traits for explicitly 00526 specified node positions\\ 00527 |Graph| can be |graph| (standard graph) or |planar_map| (map). 00528 \item |PLocTraits_Map<Graph>| and |PLocTraits_Map_NodeArray<Graph,Point>|:\\ 00529 The parameter |Graph| can be |GRAPH<Point,...>| and |graph| respectively. 00530 These traits classes assume that the given graphs are maps. 00531 \item |PLocTraits< GRAPH<Circle,Point> >|: traits class for closest-site 00532 voronoi diagrams 00533 \end{itemize} 00534 Note that a traits class instantiated with |Graph| can also handle graph 00535 types which are derived from |Graph|. Thus |PLocTraits< graph<Point,T> >| 00536 can be used for graphs of type |ugraph<Point,T>| for example. 00537 }*/ 00538 /*{\Mexample 00539 First we show an example where the node positions are given implicitly 00540 as node attributes: 00541 \begin{verbatim} 00542 typedef PointLocator< PLocTraits< GRAPH<Point, int> > > PLocator1; 00543 typedef PLocator1::Location Location; 00544 00545 UGRAPH<Point, int> G; 00546 ... // construct G 00547 00548 PLocator1 PL1(G); 00549 Point p = ...; // compute p 00550 Location L1 = PL1.locate_down(p); 00551 \end{verbatim} 00552 00553 The second example shows how a |node_array| can be used to determine the 00554 node positions: 00555 \begin{verbatim} 00556 typedef PLocTraits_NodeArray<planar_map,Point> PLocTraits2; 00557 typedef PointLocator<PLocTraits2> PLocator2; 00558 00559 planar_map pm; 00560 node_array<Point> na; 00561 ... // construct pm and na 00562 00563 PLocator2 PL2(pm, PLocTraits2(na)); 00564 Point q = ...; // compute q 00565 Location L2 = PL2.locate_up(q); 00566 \end{verbatim} 00567 }*/ 00568 00569 #endif // GEN_POINT_LOCATION_H