1 // Copyright (c) 2005,2007,2008,2009,2010,2011 Tel-Aviv University (Israel).
2 // All rights reserved.
3 //
4 // This file is part of CGAL (www.cgal.org).
5 //
6 // $URL: https://github.com/CGAL/cgal/blob/v5.3/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Arr_landmarks_pl_impl.h $
7 // $Id: Arr_landmarks_pl_impl.h 0626eb0 2020-06-11T12:32:33+03:00 Efi Fogel
8 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
9 //
10 // Author(s)     : Idit Haran   <haranidi@post.tau.ac.il>
11 //                 Ron Wein     <wein@post.tau.ac.il>
12 //                 Efi Fogel    <efif@post.tau.ac.il>
13 
14 #ifndef CGAL_ARR_LANDMARKS_PL_IMPL_H
15 #define CGAL_ARR_LANDMARKS_PL_IMPL_H
16 
17 #include <CGAL/license/Arrangement_on_surface_2.h>
18 
19 
20 /*! \file
21  * Member-function definitions for the
22  * Arr_landmarks_point_location<Arrangement, Generator> class.
23  */
24 
25 namespace CGAL {
26 
27 //-----------------------------------------------------------------------------
28 // Locate the arrangement feature containing the given point.
29 //
30 template <typename Arr, typename Gen>
31 typename Arr_landmarks_point_location<Arr, Gen>::result_type
locate(const Point_2 & p)32 Arr_landmarks_point_location<Arr, Gen>::locate(const Point_2& p) const
33 {
34   // If the arrangement is empty, return its initial (empty and
35   // non-fictitious) face.
36   if (p_arr->number_of_vertices() == 0) {
37     CGAL_assertion(p_arr->number_of_faces() == 1);
38     Face_const_handle      fh = p_arr->faces_begin();
39     return make_result(fh);
40   }
41   // Use the generator and to find the closest landmark to the query point.
42   result_type    lm_location_obj;
43   const Point_2& landmark_point = lm_gen->closest_landmark(p, lm_location_obj);
44 
45   // If the query point and the landmark point are equal, return the landmark.
46   if (m_traits->equal_2_object()(landmark_point, p))
47     return lm_location_obj;
48 
49   // Walk from the nearest_vertex to the point p, using walk algorithm,
50   // and find the location of the query point p. Note that the set fo edges
51   // we have crossed so far is initially empty.
52   Halfedge_set                   crossed_edges;
53   result_type                    out_obj;
54 
55   // Locate the arrangement feature that contains the landmark.
56   const Vertex_const_handle*   vh;
57   const Halfedge_const_handle* hh;
58   const Face_const_handle*     fh;
59   if ( ( vh = Result().template assign<Vertex_const_handle>(&lm_location_obj) ) )
60     out_obj = _walk_from_vertex(*vh, p, crossed_edges);
61   else if ( ( hh = Result().template assign<Halfedge_const_handle>(&lm_location_obj) ) )
62     out_obj = _walk_from_edge(*hh, landmark_point, p, crossed_edges);
63   else if ( ( fh =  Result().template assign<Face_const_handle>(&lm_location_obj) ) )
64     out_obj = _walk_from_face(*fh, landmark_point, p, crossed_edges);
65   else CGAL_error_msg("lm_location_obj of an unknown type.");
66 
67   if ( ( fh = Result().template assign<Face_const_handle>(&out_obj) ) ) {
68     // If we reached here, we did not locate the query point in any of the
69     // holes inside the current face, so we conclude it is contained in this
70     // face.
71     // However, we first have to check whether the query point coincides with
72     // any of the isolated vertices contained inside this face.
73     Isolated_vertex_const_iterator      iso_verts_it;
74     typename Traits_adaptor_2::Equal_2  equal = m_traits->equal_2_object();
75 
76     for (iso_verts_it = (*fh)->isolated_vertices_begin();
77          iso_verts_it != (*fh)->isolated_vertices_end(); ++iso_verts_it)
78     {
79       if (equal(p, iso_verts_it->point())) {
80         Vertex_const_handle  ivh = iso_verts_it;
81         return make_result(ivh);
82       }
83     }
84   }
85 
86   return out_obj;
87 }
88 
89 //-----------------------------------------------------------------------------
90 // Walk from a given vertex to the query point.
91 //
92 template <typename Arr, typename Gen>
93 typename Arr_landmarks_point_location<Arr, Gen>::result_type
94 Arr_landmarks_point_location<Arr, Gen>::
_walk_from_vertex(Vertex_const_handle nearest_vertex,const Point_2 & p,Halfedge_set & crossed_edges)95 _walk_from_vertex(Vertex_const_handle nearest_vertex,
96                   const Point_2& p,
97                   Halfedge_set& crossed_edges) const
98 {
99   Vertex_const_handle vh = nearest_vertex;
100   CGAL_assertion_msg(! vh->is_at_open_boundary(),
101                      "_walk_from_vertex() from a vertex at infinity.");
102 
103   // Check if the qurey point p conincides with the vertex.
104   if (m_traits->equal_2_object()(vh->point(), p))
105     return make_result(vh);
106 
107   // In case of an isolated vertex, walk to from the face that contains
108   // it toward the query point.
109   if (vh->is_isolated()) {
110     Face_const_handle  fh = vh->face();
111     return (_walk_from_face(fh, vh->point(), p, crossed_edges));
112   }
113 
114   // if we walk from a vertex this means we are crossing the
115   // halfedges that form a corridor in which seg is going through
116   Halfedge_around_vertex_const_circulator first = vh->incident_halfedges();
117   // Create an x-monotone curve connecting the point associated with the
118   // vertex vp and the query point p.
119   const Point_2&      vp = vh->point();
120   X_monotone_curve_2  seg =
121     m_traits->construct_x_monotone_curve_2_object()(vp, p);
122   const bool          seg_dir_right =
123     (m_traits->compare_xy_2_object()(vp, p) == SMALLER);
124   Halfedge_around_vertex_const_circulator curr_iter = first;
125   Halfedge_around_vertex_const_circulator next_iter = curr_iter;
126   ++next_iter;
127   typename Traits_adaptor_2::Is_between_cw_2  is_between_cw =
128     m_traits->is_between_cw_2_object();
129   // Traverse the halfedges around vp until we find the pair of adjacent
130   // halfedges such as seg is located clockwise in between them.
131   do {
132     bool eq_curr_iter, eq_next_iter;
133     if (is_between_cw(seg, seg_dir_right, curr_iter->curve(),
134                       (curr_iter->direction() == ARR_RIGHT_TO_LEFT),
135                       next_iter->curve(),
136                       (next_iter->direction() == ARR_RIGHT_TO_LEFT),
137                       vp, eq_curr_iter, eq_next_iter))
138     {
139       // the assumption is that each edge is crossed at most twice
140       CGAL_assertion_msg(crossed_edges.count (curr_iter) < 2,
141         "crossed_edges should contain each halfedge at most twice.");
142       CGAL_assertion_msg(crossed_edges.count (next_iter) < 2,
143         "crossed_edges should contain each halfedge at most twice.");
144       crossed_edges.insert(curr_iter);
145       crossed_edges.insert(curr_iter->twin());
146       crossed_edges.insert(next_iter);
147       crossed_edges.insert(next_iter->twin());
148       break;
149     }
150     ++curr_iter;
151     ++next_iter;
152   } while (curr_iter != first);
153 
154   // Locate the face around the vertex that contains the curve connecting
155   // the vertex and the query point.
156   while (true) {
157     bool new_vertex;
158     result_type obj = _find_face_around_vertex(vh, p, new_vertex);
159     if (new_vertex) {
160       // We found a vertex closer to p; Continue using this vertex.
161       const Vertex_const_handle* p_vh =
162         Result().template assign<Vertex_const_handle>(&obj);
163       CGAL_assertion(p_vh != nullptr);
164       vh = *p_vh;
165       continue;
166     }
167 
168     // If p is located on an edge or on a vertex, return the object
169     // that wraps this arrangement feature.
170     if (Result().template assign<Halfedge_const_handle>(&obj) ||
171         Result().template assign<Vertex_const_handle>(&obj))
172       return obj;
173 
174     const Face_const_handle* p_fh =
175       Result().template assign<Face_const_handle>(&obj);
176     if (p_fh)
177       // Walk to p from the face we have located:
178       return _walk_from_face(*p_fh, vh->point(), p, crossed_edges);
179 
180     CGAL_error_msg("_find_face_around_vertex() returned an unknown object.");
181   }
182 
183   // We should never reach here:
184   CGAL_error();
185   return default_result();
186 }
187 
188 //-----------------------------------------------------------------------------
189 // Locate an edge around a given vertex that is the predecessor of the curve
190 // connecting the vertex to the query point in a clockwise order.
191 //
192 template <typename Arr, typename Gen>
193 typename Arr_landmarks_point_location<Arr, Gen>::result_type
194 Arr_landmarks_point_location<Arr, Gen>::
_find_face_around_vertex(Vertex_const_handle vh,const Point_2 & p,bool & new_vertex)195 _find_face_around_vertex(Vertex_const_handle vh,
196                          const Point_2& p,
197                          bool& new_vertex) const
198 {
199   new_vertex = false;
200 
201   // Create an x-monotone curve connecting the point associated with the
202   // vertex vp and the query point p.
203   const Point_2&      vp = vh->point();
204   X_monotone_curve_2  seg =
205     m_traits->construct_x_monotone_curve_2_object()(vp, p);
206   const bool          seg_dir_right =
207     (m_traits->compare_xy_2_object()(vp, p) == SMALLER);
208 
209   // Get the first incident halfedge around v and the next halfedge.
210   Halfedge_around_vertex_const_circulator  first = vh->incident_halfedges();
211   Halfedge_around_vertex_const_circulator  curr, next;
212   bool                                     equal_curr = false;
213 
214   next = curr = first;
215   ++next;
216 
217   if (next == curr) {
218     // The vertex has a single incident edge. Check if its associated
219     // curve equals seg next to vp.
220     if (seg_dir_right && curr->direction() == ARR_RIGHT_TO_LEFT) {
221       // Both curves are defined to the right of vp:
222       equal_curr =
223         (m_traits->compare_y_at_x_right_2_object()
224          (curr->curve(), seg, vp) == EQUAL);
225     }
226     else if (! seg_dir_right && curr->direction() == ARR_LEFT_TO_RIGHT) {
227       // Both curves are defined to the left of vp:
228       equal_curr =
229         (m_traits->compare_y_at_x_left_2_object()
230          (curr->curve(), seg, vp) == EQUAL);
231     }
232 
233     // In case the curves are not equal, just return the incident face of
234     // the single halfegde (note that this is also the incident face of its
235     // twin, as v is the tip of an "antenna").
236     if (! equal_curr) {
237       CGAL_assertion(curr->face() == curr->twin()->face());
238       return make_result(curr->face());
239     }
240   }
241   else {
242     // Traverse the halfedges around v until we find the pair of adjacent
243     // halfedges such as seg is located clockwise in between them.
244     typename Traits_adaptor_2::Is_between_cw_2  is_between_cw =
245       m_traits->is_between_cw_2_object();
246     bool                                        eq_curr, eq_next;
247 
248     while (! is_between_cw(seg, seg_dir_right, curr->curve(),
249                            (curr->direction() == ARR_RIGHT_TO_LEFT),
250                            next->curve(),
251                            (next->direction() == ARR_RIGHT_TO_LEFT),
252                            vp, eq_curr, eq_next))
253     {
254       // Break the loop if seg equals one of the halfegdes next to v.
255       if (eq_curr) {
256         equal_curr = true;
257         break;
258       }
259 
260       if (eq_next) {
261         curr = next;
262         equal_curr = true;
263         break;
264       }
265 
266       // Move to the next pair of incident halfedges.
267       curr = next;
268       ++next;
269 
270       // Guard for an infinitive loop, in case we have completed a full
271       // traversal around v without locating a place for seg.
272       if (curr == first) {
273         CGAL_error_msg("Completed a full cycle around v without locating seg.");
274         return default_result();
275       }
276     }
277 
278     // In case seg is not equal to curr's curve, just return the incident face
279     // of the halfegde we have located.
280     if (! equal_curr)
281       return make_result(curr->face());
282   }
283 
284   // If we reached here, seg overlaps the curve associated with curr next to
285   // the vertex v. We first check if p equals the other end-vertex of this
286   // halfedge.
287   if (m_traits->equal_2_object()(p, curr->source()->point())) {
288     // In this case p equals the source point of the edge.
289     return make_result(curr->source());
290   }
291 
292   // Check whether p lies on the curve associated with the edge.
293   if (m_traits->is_in_x_range_2_object()(curr->curve(), p) &&
294       m_traits->compare_y_at_x_2_object()(p, curr->curve()) == EQUAL)
295   {
296     // p is located on the interior of the edge.
297     Halfedge_const_handle   he = curr;
298     return make_result(he);
299   }
300 
301   // In this case, the source vertex of the current edge is closer
302   // to the query point p.
303   new_vertex = true;
304   return make_result(curr->source());
305 }
306 
307 //-----------------------------------------------------------------------------
308 // Walk from the edge to the query point.
309 //
310 template <typename Arr, typename Gen>
311 typename Arr_landmarks_point_location<Arr, Gen>::result_type
312 Arr_landmarks_point_location<Arr, Gen>::
_walk_from_edge(Halfedge_const_handle eh,const Point_2 & np,const Point_2 & p,Halfedge_set & crossed_edges)313 _walk_from_edge(Halfedge_const_handle eh,
314                 const Point_2& np,
315                 const Point_2& p,
316                 Halfedge_set& crossed_edges) const
317 {
318   CGAL_assertion_msg(! eh->is_fictitious(),
319                      "_walk_from_edge() from a fictitious edge.");
320 
321   const X_monotone_curve_2& cv = eh->curve() ;
322   Comparison_result         res;
323 
324   X_monotone_curve_2 seg =
325     m_traits->construct_x_monotone_curve_2_object()(np, p);
326 
327   // Create an initial set of edges that have been crossed, which currently
328   // contains only the halfedge we are currently on (and its twin).
329   // the assumption is that each edge is crossed at most twice
330   CGAL_assertion_msg(crossed_edges.count (eh) < 2,
331     "crossed_edges should contain each halfedge at most twice.");
332   crossed_edges.insert(eh);
333   crossed_edges.insert(eh->twin());
334 
335   // If p equals one of the edge's endpoints, return the vertex
336   // that represents this endpoint.
337   if (! eh->source()->is_at_open_boundary()) {
338     if (m_traits->equal_2_object()(p, eh->source()->point())) {
339       Vertex_const_handle vh = eh->source();
340       return make_result(vh);
341     }
342     // if the source point of the halfedge is located on seg then we insert
343     // the predecessor of the halfedge and its twin to crossed_edges
344     Point_2 temp_p = eh->source()->point();
345     if (m_traits->is_in_x_range_2_object()(seg, temp_p)) {
346       //we must make sure that eh is not a tip on an "antena"
347       if (m_traits->compare_y_at_x_2_object()(temp_p, seg) == EQUAL &&
348           eh->prev() != eh->twin())
349       {
350         // the assumption is that each edge is crossed at most twice
351         CGAL_assertion_msg(crossed_edges.count(eh->prev()) < 2,
352           "crossed_edges should contain each halfedge at most twice.");
353         crossed_edges.insert(eh->prev());
354         crossed_edges.insert(eh->prev()->twin());
355         return _walk_from_vertex(eh->source(), p, crossed_edges);
356       }
357     }
358   }
359   if (! eh->target()->is_at_open_boundary()) {
360     if (m_traits->equal_2_object()(p, eh->target()->point())) {
361       Vertex_const_handle vh = eh->target();
362       return make_result(vh);
363     }
364     // if the target point of the halfedge is located on seg then we insert
365     // the successor of the halfedge and its twin to crossed_edges
366     Point_2 temp_p = eh->target()->point();
367     if (m_traits->is_in_x_range_2_object()(seg, temp_p)) {
368       //we must make sure that eh is not a tip on an "antena"
369       if (m_traits->compare_y_at_x_2_object()(temp_p, seg) == EQUAL &&
370           eh->next() != eh->twin())
371       {
372         // the assumption is that each edge is crossed at most twice
373         CGAL_assertion_msg(crossed_edges.count(eh->next()) < 2,
374           "crossed_edges should contain each halfedge at most twice.");
375         crossed_edges.insert(eh->next());
376         crossed_edges.insert(eh->next()->twin());
377         return _walk_from_vertex(eh->target(), p, crossed_edges);
378       }
379     }
380   }
381 
382   // Check whether p is in the x-range of the edge.
383   if (m_traits->is_in_x_range_2_object()(cv, p)) {
384     // If p is in eh's x_range, then we need to check if it is above or below
385     // it, so we can orient the halfedge eh accordingly, such that it will be
386     // incident to the face that is most likely to contain p.
387     res = m_traits->compare_y_at_x_2_object()(p, cv);
388 
389     switch (res) {
390      case EQUAL:
391       // The edge contains p in its interior:
392       return make_result(eh);
393 
394      case LARGER:
395       // p is above cv: the edge must be oriented from left to right.
396       if (eh->direction() == ARR_RIGHT_TO_LEFT)
397         eh = eh->twin();
398       break;
399 
400      case SMALLER:
401       // p is below cv: the edge must be oriented from right to left.
402       if (eh->direction() == ARR_LEFT_TO_RIGHT)
403         eh = eh->twin();
404       break;
405     }
406 
407     // Now walk in the incdient face of eh toward p.
408     return (_walk_from_face(eh->face(), np, p, crossed_edges));
409   }
410 
411   // In this case p is in not in the x-range of eh. We select the end
412   // vertex of eh that lies closer to p, and walk from this vertex.
413   Vertex_const_handle  vh = eh->source();
414 
415   if (vh->is_at_open_boundary()) {
416     vh = eh->target();
417     CGAL_assertion (! vh->is_at_open_boundary());
418   }
419   else if (! eh->target()->is_at_open_boundary()) {
420     res = m_traits->compare_xy_2_object()(p, eh->source()->point());
421 
422     if ((eh->direction() == ARR_LEFT_TO_RIGHT && res == LARGER) ||
423         (eh->direction() == ARR_RIGHT_TO_LEFT && res == SMALLER))
424       vh = eh->target();
425   }
426 
427   // Walk from the closer vertex toward the query point p.
428   return (_walk_from_vertex(vh, p, crossed_edges));
429 }
430 
431 //-----------------------------------------------------------------------------
432 // In case the arrangement's curve contained in the segment
433 // from the nearest landmark to the query point
434 //
435 template <typename Arr, typename Gen>
436 typename Arr_landmarks_point_location<Arr, Gen>::result_type
437 Arr_landmarks_point_location<Arr, Gen>::
_deal_with_curve_contained_in_segment(Halfedge_const_handle he,bool p_is_left,const Point_2 & p,Halfedge_set & crossed_edges)438 _deal_with_curve_contained_in_segment(Halfedge_const_handle he,
439                                       bool p_is_left,
440                                       const Point_2& p,
441                                       Halfedge_set& crossed_edges) const
442 {
443   // in this case we want to walk from to the query point from the nearest
444   // vertex either the halfedge's source or target
445   Vertex_const_handle  vh;
446   bool target_is_left;
447   if (m_traits->compare_xy_2_object()
448       (he->source()->point(),he->target()->point()) == LARGER)
449     target_is_left = true;
450   else
451     target_is_left = false;
452   if (p_is_left) {
453     if (target_is_left)
454       vh = he->target();
455     else
456       vh = he->source();
457   }
458   else {
459     if (target_is_left)
460       vh = he->source();
461     else
462       vh = he->target();
463   }
464   // vh is the closest vertex among the halfedge's end points
465   return (_walk_from_vertex(vh, p, crossed_edges));
466 }
467 
468 //-----------------------------------------------------------------------------
469 // Walk from the given face to the query point.
470 //
471 template <typename Arr, typename Gen>
472 typename Arr_landmarks_point_location<Arr, Gen>::result_type
473 Arr_landmarks_point_location<Arr, Gen>::
_walk_from_face(Face_const_handle face,const Point_2 & np,const Point_2 & p,Halfedge_set & crossed_edges)474 _walk_from_face(Face_const_handle face,
475                 const Point_2& np,
476                 const Point_2& p,
477                 Halfedge_set& crossed_edges) const
478 {
479   // Construct an x-monotone curve connecting the nearest landmark point np
480   // to the query point p and check which CCB intersects this segment.
481   X_monotone_curve_2             seg =
482     m_traits->construct_x_monotone_curve_2_object()(np, p);
483   const bool                     p_is_left =
484     (m_traits->compare_xy_2_object()(np, p) == LARGER);
485 
486   Inner_ccb_const_iterator       inner_ccb_iter;
487   Outer_ccb_const_iterator       outer_ccb_iter;
488   const Halfedge_const_handle    invalid_he;
489   Halfedge_const_handle          he;
490   Face_const_handle              new_face;
491   bool                           is_on_edge;
492   bool                           is_target;
493   bool                           cv_is_contained_in_seg;
494   Vertex_const_handle            new_vertex;
495   const Vertex_const_handle      invalid_vertex;
496 
497   do {
498     // Check whether p lies inside the current face (including its holes):
499     if (p_arr->topology_traits()->is_in_face(&(*face), p, nullptr))
500     {
501       // We know that p is located inside the current face, and we check
502       // whether it lies inside one of its holes (or on the boundary of
503       // its holes).
504       cv_is_contained_in_seg = false;
505       new_face = face;
506       for (inner_ccb_iter = face->inner_ccbs_begin();
507            inner_ccb_iter != face->inner_ccbs_end(); ++inner_ccb_iter)
508       {
509         he = _intersection_with_ccb(*inner_ccb_iter,seg, p, p_is_left,
510                                     crossed_edges,is_on_edge, is_target,
511                                     cv_is_contained_in_seg,new_vertex);
512         if (he == invalid_he && cv_is_contained_in_seg)
513         {
514           return _deal_with_curve_contained_in_segment(*inner_ccb_iter,
515                                                        p_is_left,p,
516                                                        crossed_edges);
517         }
518         if (he != invalid_he) {
519           // Check if the query point is located on a vertex or on an edge.
520           if (is_target)
521             return make_result(he->target());
522           else if (is_on_edge)
523             return make_result(he);
524           if (new_vertex != invalid_vertex) {
525             // if we got here it means that a closer vertex then np was found
526             return (_walk_from_vertex(new_vertex, p, crossed_edges));
527           }
528           // Otherwise, cross over he to the incident face of its twin.
529           if (face != he->twin()->face()) {
530             new_face = he->twin()->face();
531             break;
532           }
533         }
534       }
535 
536       // Check if we found a new face (hole) containing p. If not, the current
537       // face contains p.
538       if (new_face == face)
539         return make_result(face);
540 
541       // Continue from the new face (hole).
542       face = new_face;
543     }
544     else {
545       // We know that p is not located inside the current face. We therefore
546       // look for an edge on its outer boundary that intersects seg.
547       new_face = face;
548       for (outer_ccb_iter = face->outer_ccbs_begin();
549            outer_ccb_iter != face->outer_ccbs_end(); ++outer_ccb_iter)
550       {
551         he = _intersection_with_ccb(*outer_ccb_iter,seg, p, p_is_left,
552                                     crossed_edges,is_on_edge, is_target,
553                                     cv_is_contained_in_seg,new_vertex);
554         if (he == invalid_he && cv_is_contained_in_seg) {
555           return _deal_with_curve_contained_in_segment(*outer_ccb_iter,
556                                                        p_is_left,p,
557                                                        crossed_edges);
558         }
559         if (he != invalid_he) {
560           // Check if the query point is located on a vertex or on an edge.
561           if (is_target)
562             return make_result(he->target());
563           else if (is_on_edge)
564             return make_result(he);
565           if (new_vertex != invalid_vertex) {
566             // if we got here it means that a closer vertex then np was found
567             return (_walk_from_vertex(new_vertex, p, crossed_edges));
568           }
569           // Otherwise, cross over he to the incident face of its twin.
570           if (face != he->twin()->face()) {
571             new_face = he->twin()->face();
572             break;
573           }
574         }
575       }
576 
577       // Continue from the new face.
578       CGAL_assertion(new_face != face);
579       face = new_face;
580     }
581   } while (true);
582 
583   // We should never reach here:
584   CGAL_error();
585   return default_result();
586 }
587 
588 //-----------------------------------------------------------------------------
589 // Find a halfedge on the given CCB that intersects the given x-monotone
590 // curve, connecting the current landmark to the query point.
591 //
592 template <typename Arr, typename Gen>
593 typename Arr_landmarks_point_location<Arr, Gen>::Halfedge_const_handle
594 Arr_landmarks_point_location<Arr, Gen>::
_intersection_with_ccb(Ccb_halfedge_const_circulator circ,const X_monotone_curve_2 & seg,const Point_2 & p,bool p_is_left,Halfedge_set & crossed_edges,bool & is_on_edge,bool & is_target,bool & cv_is_contained_in_seg,Vertex_const_handle & new_vertex)595 _intersection_with_ccb(Ccb_halfedge_const_circulator circ,
596                        const X_monotone_curve_2& seg,
597                        const Point_2& p, bool p_is_left,
598                        Halfedge_set& crossed_edges,
599                        bool& is_on_edge, bool& is_target,
600                        bool& cv_is_contained_in_seg,
601                        Vertex_const_handle & new_vertex) const
602 {
603   is_on_edge = false;
604   is_target = false;
605 
606   // Go over the CCB.
607   typename Traits_adaptor_2::Is_in_x_range_2    is_in_x_range =
608     m_traits->is_in_x_range_2_object();
609   Ccb_halfedge_const_circulator                 curr = circ , temp_circ;
610   const Halfedge_const_handle                   invalid_he;
611   Halfedge_const_handle                         he;
612   bool cv_and_seg_overlap;
613   do {
614     he = curr;
615     // Skip fictitious halfedges.
616     if (he->is_fictitious()) {
617       ++curr;
618       continue;
619     }
620 
621     // Check if we have already crossed the current halfedge (or its twin).
622     // If so, we do not cross it again.
623     if (crossed_edges.count(he) != 0) {
624       ++curr;
625       continue;
626     }
627 
628     if (m_traits->is_vertical_2_object()(he->curve())) {
629       if (is_in_x_range(he->curve(), p)) {
630         if (m_traits->compare_y_at_x_2_object()(p, he->curve()) == EQUAL) {
631           // special treatment in case the query point is on a vertical curve
632           is_on_edge = true;
633           return _in_case_p_is_on_edge(he,crossed_edges,p,is_target);
634         }
635       }
636     }
637 
638     // Check if the x-range of the curve associated with the current edge
639     // does not overlap the x-range of seg, the two curves cannot intersect.
640     if (! is_in_x_range(he->curve(), seg)) {
641       ++curr;
642       continue;
643     }
644     cv_and_seg_overlap = false;
645     cv_is_contained_in_seg = false;
646     // Check whether the current curve intersects seg an odd number of times.
647     if (_have_odd_intersections(he->curve(), seg, p_is_left,
648                                 is_on_edge,cv_and_seg_overlap,
649                                 cv_is_contained_in_seg)
650         && !(cv_and_seg_overlap || cv_is_contained_in_seg))
651     {
652       // Check if the query point lies on the current edge, or whether
653       // it lies in its interior.
654       if (is_on_edge)
655         return _in_case_p_is_on_edge(he,crossed_edges,p,is_target);
656 
657       if ((!curr->target()->is_at_open_boundary()) &&
658           is_in_x_range(seg, curr->target()->point()))
659       {
660         // if the target point of curr is located on seg
661         // we should walk from it to the query point
662         if (m_traits->compare_y_at_x_2_object()
663             (curr->target()->point(), seg) == EQUAL)
664         {
665           new_vertex = curr->target();
666         }
667       }
668       else if ((!curr->source()->is_at_open_boundary()) &&
669                is_in_x_range(seg , curr->source()->point() ))
670       {
671         // if the source point of curr is located on seg
672         // we should walk from it to the query point
673         if (m_traits->compare_y_at_x_2_object()
674             (curr->source()->point() , seg) == EQUAL)
675         {
676           new_vertex = curr->source();
677         }
678       }
679 
680       // Return the halfedge we found, and mark that we have already crossed
681       // it (as well as its twin).
682       // the assumption is that each edge is crossed at most twice
683       CGAL_assertion_msg(crossed_edges.count(he) < 2,
684         "crossed_edges should contain each halfedge at most twice.");
685       crossed_edges.insert(he);
686       crossed_edges.insert(he->twin());
687       return he;
688     }
689     else if (cv_and_seg_overlap || cv_is_contained_in_seg) {
690       // Check if the query point lies on the current edge, or whether
691       // it lies in its interior.
692       if (cv_is_contained_in_seg) {
693         // cv is contained in seg, obviously we crossed it
694         // the assumption is that each edge is crossed at most twice
695         CGAL_assertion_msg (crossed_edges.count(he) < 2,
696           "crossed_edges should contain each halfedge at most twice.");
697         crossed_edges.insert(he);
698         crossed_edges.insert(he->twin());
699         return invalid_he;
700       }
701       if (is_on_edge)
702         return _in_case_p_is_on_edge(he,crossed_edges,p,is_target);
703     }
704     // Proceed to the next halfedge along the CCB.
705     ++curr;
706   } while (curr != circ);
707 
708   // If we reached here, we did not find any edge intersecting seg.
709   return (invalid_he);
710 }
711 
712 //-----------------------------------------------------------------------------
713 // Return the halfedge that contains the query point.
714 //
715 template <typename Arr, typename Gen>
716 typename Arr_landmarks_point_location<Arr, Gen>::Halfedge_const_handle
717 Arr_landmarks_point_location<Arr, Gen>::
_in_case_p_is_on_edge(Halfedge_const_handle he,Halfedge_set & crossed_edges,const Point_2 & p,bool & is_target)718 _in_case_p_is_on_edge(Halfedge_const_handle he,
719                       Halfedge_set& crossed_edges,
720                       const Point_2 & p,
721                       bool & is_target) const
722 {
723   // cv and seg overlap, obviously we crossed it
724   // the assumption is that each edge is crossed at most twice
725   CGAL_assertion_msg(crossed_edges.count(he) < 2,
726     "crossed_edges should contain each halfedge at most twice.");
727   crossed_edges.insert(he);
728   crossed_edges.insert(he->twin());
729   // Check if p equals one of the edge end-vertices.
730   if (! he->target()->is_at_open_boundary() &&
731       m_traits->compare_xy_2_object()(he->target()->point(), p) == EQUAL)
732   {
733     // p is the target of the current halfedge.
734     is_target = true;
735   }
736   else if (! he->source()->is_at_open_boundary() &&
737     m_traits->compare_xy_2_object()(he->source()->point(), p) == EQUAL)
738   {
739     // Take the twin halfedge, so p equals its target.
740     he = he->twin();
741     is_target = true;
742   }
743   // Return the halfedge containing p.
744   return he;
745 }
746 
747 //-----------------------------------------------------------------------------
748 // Check whether the given curve intersects a simple segment, which connects
749 // the current landmark to the query point, an odd number of times.
750 //
751 template <typename Arr, typename Gen>
752 bool Arr_landmarks_point_location<Arr, Gen>::
_have_odd_intersections(const X_monotone_curve_2 & cv,const X_monotone_curve_2 & seg,bool p_is_left,bool & p_on_curve,bool & cv_and_seg_overlap,bool & cv_is_contained_in_seg)753 _have_odd_intersections(const X_monotone_curve_2& cv,
754                         const X_monotone_curve_2& seg,
755                         bool p_is_left,
756                         bool& p_on_curve,
757                         bool& cv_and_seg_overlap,
758                         bool& cv_is_contained_in_seg) const
759 {
760   typename Traits_adaptor_2::Is_in_x_range_2    is_in_x_range =
761     m_traits->is_in_x_range_2_object();
762   p_on_curve = false;
763   cv_and_seg_overlap = false;
764   cv_is_contained_in_seg = false;
765   // Use the left and right endpoints of the segment.
766   const Point_2& seg_left = m_traits->construct_min_vertex_2_object()(seg);
767   const Point_2& seg_right = m_traits->construct_max_vertex_2_object()(seg);
768   // Use the left and right endpoints of the segment.
769   Point_2 cv_left;
770   Point_2 cv_right;
771   bool cv_left_is_closed = m_traits->is_closed_2_object()(cv, ARR_MIN_END);
772   bool cv_right_is_closed = m_traits->is_closed_2_object()(cv, ARR_MAX_END);
773   if (cv_left_is_closed)
774     cv_left = m_traits->construct_min_vertex_2_object()(cv);
775   if (cv_right_is_closed)
776     cv_right = m_traits->construct_max_vertex_2_object()(cv);
777   if (cv_left_is_closed && cv_right_is_closed) {
778     if (is_in_x_range(seg,cv_left) && is_in_x_range(seg,cv_right)) {
779       if ((m_traits->compare_y_at_x_2_object()(cv_left, seg) == EQUAL) &&
780           (m_traits->compare_y_at_x_2_object()(cv_right, seg) == EQUAL))
781       {
782         // cv is contained in seg non of the answer true or false is correct
783         // we must set a special flag to distinguish this case
784         cv_is_contained_in_seg = true;
785         return true;
786       }
787     }
788   }
789   // Check if the overlapping x-range of the two curves is trivial.
790   // In this case, they cannot cross.
791   if (cv_left_is_closed) {
792     // Check if the left endpoint of cv has the same x-coordinate as the
793     // right endpoint of seg.
794     if (m_traits->compare_x_2_object()
795         (m_traits->construct_min_vertex_2_object()(cv), seg_right) == EQUAL)
796     {
797       if (! p_is_left &&
798           m_traits->compare_xy_2_object()
799           (m_traits->construct_min_vertex_2_object()(cv), seg_right) == EQUAL)
800       {
801         p_on_curve = true;
802         return true;
803       }
804       else if (m_traits->is_vertical_2_object()(seg)) {
805         // Special treatment for vertical segments.
806         Comparison_result   res_l =
807           m_traits->compare_y_at_x_2_object()(seg_left, cv);
808         Comparison_result   res_r =
809           m_traits->compare_y_at_x_2_object()(seg_right, cv);
810         if ((p_is_left && res_l == EQUAL) || (! p_is_left && res_r == EQUAL)) {
811           p_on_curve = true;
812           return true;
813         }
814         return (res_l != res_r);
815       }
816       return false;
817     }
818   }
819   if (cv_right_is_closed) {
820     // Check if the right endpoint of cv has the same x-coordinate as the
821     // left endpoint of seg.
822     if (m_traits->compare_x_2_object()
823         (m_traits->construct_max_vertex_2_object()(cv), seg_left) == EQUAL)
824     {
825       if (p_is_left &&
826           m_traits->compare_xy_2_object()
827           (m_traits->construct_max_vertex_2_object()(cv), seg_left) == EQUAL)
828       {
829         p_on_curve = true;
830         return true;
831       }
832       else if (m_traits->is_vertical_2_object()(seg)) {
833         // Special treatment for vertical segments.
834         Comparison_result   res_l =
835           m_traits->compare_y_at_x_2_object()(seg_left, cv);
836         Comparison_result   res_r =
837           m_traits->compare_y_at_x_2_object()(seg_right, cv);
838 
839         if ((p_is_left && res_l == EQUAL) || (! p_is_left && res_r == EQUAL)) {
840           p_on_curve = true;
841           return true;
842         }
843         return (res_l != res_r);
844       }
845       return false;
846     }
847   }
848   // Compare the two left ends of cv and seg.
849   Comparison_result    left_res;
850   const Arr_parameter_space  bx_l =
851     m_traits->parameter_space_in_x_2_object()(cv, ARR_MIN_END);
852   if (bx_l == ARR_LEFT_BOUNDARY) {
853     // The left end of cv lies to the left of seg_left:
854     // Compare this point to cv.
855     left_res = m_traits->compare_y_at_x_2_object()(seg_left, cv);
856   }
857   else if (bx_l == ARR_RIGHT_BOUNDARY) {
858     // The left end of cv lies to the right of seg_left.
859     // Compare the left endpoint of cv to seg.
860     left_res = m_traits->compare_y_at_x_2_object()
861         (m_traits->construct_min_vertex_2_object()(cv), seg);
862     left_res = CGAL::opposite(left_res);
863   }
864   else {
865     const Arr_parameter_space  by_l =
866       m_traits->parameter_space_in_y_2_object()(cv, ARR_MIN_END);
867     if (by_l == ARR_BOTTOM_BOUNDARY)
868       // The left end of cv is at y = -oo, so cv obviously lies above it.
869       left_res = LARGER;
870     else if (by_l == ARR_TOP_BOUNDARY)
871       // The left end of cv is at y = +oo, so cv obviously lies below it.
872       left_res = SMALLER;
873     else {
874       // In this case cv has a valid left endpoint: Find the rightmost of
875       // these two points and compare it to the other curve.
876       Comparison_result res = m_traits->compare_xy_2_object()(cv_left, seg_left);
877       if (res != LARGER) {
878         left_res = m_traits->compare_y_at_x_2_object()(seg_left, cv);
879         if (p_is_left && left_res == EQUAL)
880         {
881           // In this case the query point p, which is the left endpoint of seg,
882           // lies on cv.
883           p_on_curve = true;
884           return true;
885         }
886       }
887       else {
888         left_res = m_traits->compare_y_at_x_2_object()(cv_left, seg);
889         left_res = CGAL::opposite(left_res);
890       }
891     }
892   }
893   if (left_res == EQUAL) {
894     // Compare the two curves to the right of their common left endpoint.
895     if (is_in_x_range(cv,seg_left))
896       left_res = m_traits->compare_y_at_x_right_2_object()(seg, cv, seg_left);
897     else if (is_in_x_range(seg,cv_left))
898       left_res = m_traits->compare_y_at_x_right_2_object()(seg, cv, cv_left);
899     else
900       CGAL_error();
901     if (left_res == EQUAL) {
902       // RWRW: In this case we have an overlap ...
903       // cv and seg overlap non of the answer true or false is correct
904       // we must set a special flag to distinguish this case
905       if (is_in_x_range(cv,( p_is_left ? seg_left : seg_right)))
906         if (m_traits->compare_y_at_x_2_object()
907             ((p_is_left ? seg_left : seg_right), cv) == EQUAL)
908         {
909           p_on_curve = true;
910         }
911       cv_and_seg_overlap = true;
912       return true;
913     }
914   }
915   // Compare the two right ends of cv and seg.
916   Comparison_result    right_res;
917   const Arr_parameter_space  bx_r =
918     m_traits->parameter_space_in_x_2_object()(cv, ARR_MAX_END);
919   if (bx_r == ARR_RIGHT_BOUNDARY) {
920     // The right end of cv lies to the right of seg_right:
921     // Compare this point to cv.
922     right_res = m_traits->compare_y_at_x_2_object()(seg_right, cv);
923   }
924   else if (bx_r == ARR_LEFT_BOUNDARY) {
925     // The right end of cv lies to the left of seg_right.
926     // Compare the right endpoint of cv to seg.
927     right_res = m_traits->compare_y_at_x_2_object()
928         (m_traits->construct_max_vertex_2_object()(cv), seg);
929     right_res = CGAL::opposite(right_res);
930   }
931   else {
932     const Arr_parameter_space  by_r =
933       m_traits->parameter_space_in_y_2_object()(cv, ARR_MAX_END);
934     if (by_r == ARR_BOTTOM_BOUNDARY)
935       // The right end of cv is at y = -oo, so cv obviously lies above it.
936       right_res = LARGER;
937     else if (by_r == ARR_TOP_BOUNDARY)
938       // The right end of cv is at y = +oo, so cv obviously lies below it.
939       right_res = SMALLER;
940     else {
941       // In this case cv has a valid right endpoint: Find the leftmost of
942       // these two points and compare it to the other curve.
943       Comparison_result res =
944         m_traits->compare_xy_2_object()(cv_right, seg_right);
945 
946       if (res != SMALLER) {
947         right_res = m_traits->compare_y_at_x_2_object()(seg_right, cv);
948         if (! p_is_left && right_res == EQUAL) {
949           // In this case the query point p, which is the right endpoint of seg,
950           // lies on cv.
951           p_on_curve = true;
952           return true;
953         }
954       }
955       else {
956         right_res = m_traits->compare_y_at_x_2_object()(cv_right, seg);
957         right_res = CGAL::opposite(right_res);
958       }
959     }
960   }
961   if (right_res == EQUAL) {
962     // Compare the two curves to the left of their common right endpoint.
963     if (is_in_x_range(cv,seg_right))
964       right_res = m_traits->compare_y_at_x_left_2_object()(seg, cv, seg_right);
965     else if (is_in_x_range(seg,cv_right))
966       right_res = m_traits->compare_y_at_x_left_2_object()(seg, cv, cv_right);
967     else
968       CGAL_error();
969     if (right_res == EQUAL) {
970       // RWRW: In this case we have an overlap ...
971       // cv and seg overlap non of the answer true or false is correct
972       // we must set a special flag to distinguish this case
973       if (is_in_x_range(cv, (p_is_left ? seg_left : seg_right)))
974         if (m_traits->compare_y_at_x_2_object()
975             ((p_is_left ? seg_left : seg_right), cv) == EQUAL)
976         {
977           p_on_curve = true;
978         }
979       cv_and_seg_overlap = true;
980       return true;
981     }
982   }
983   // The two curves intersect an odd number of times if the comparison
984   // results at the two ends are not the same (this indicates that they
985   // switch positions).
986   return (left_res != right_res);
987 }
988 
989 } //namespace CGAL
990 
991 #endif
992