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