|
BWAPI
|
00001 // Copyright (c) 2005 Tel-Aviv University (Israel). 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/Arrangement_on_surface_2/include/CGAL/Arr_point_location/Arr_walk_along_line_pl_impl.h $ 00015 // $Id: Arr_walk_along_line_pl_impl.h 49772 2009-06-03 21:25:53Z eric $ 00016 // 00017 // 00018 // Author(s) : Ron Wein <wein@post.tau.ac.il> 00019 // (based on old version by Oren Nechushtan 00020 // and Iddo Hanniel) 00021 00022 #ifndef CGAL_ARR_WALK_ALONG_LINE_POINT_LOCATION_IMPL_H 00023 #define CGAL_ARR_WALK_ALONG_LINE_POINT_LOCATION_IMPL_H 00024 00030 CGAL_BEGIN_NAMESPACE 00031 00032 //----------------------------------------------------------------------------- 00033 // Locate the arrangement feature containing the given point. 00034 // 00035 template <class Arrangement> 00036 Object Arr_walk_along_line_point_location<Arrangement>::locate 00037 (const Point_2& p) const 00038 { 00039 // Start from the initial face (as determined by the topology-traits class), 00040 // and an invalid halfedge representing the closest edge to p from above it 00041 // so far. 00042 typename Traits_adaptor_2::Equal_2 equal = geom_traits->equal_2_object(); 00043 Inner_ccb_const_iterator ic_it; 00044 Face_const_handle face; 00045 Halfedge_const_handle closest_he; 00046 bool is_in_face; 00047 bool is_on_edge; 00048 bool closest_to_target; 00049 bool found_containing_hole; 00050 00051 face = Face_const_handle (top_traits->initial_face()); 00052 do 00053 { 00054 // Go over the holes in the current face. 00055 found_containing_hole = false; 00056 for (ic_it = face->inner_ccbs_begin(); 00057 !found_containing_hole && ic_it != face->inner_ccbs_end(); 00058 ++ic_it) 00059 { 00060 // Check if the point is inside the current hole. 00061 is_in_face = _is_in_connected_component (p, *ic_it, 00062 true, // Shoot up. 00063 true, // Including p. 00064 closest_he, 00065 is_on_edge, 00066 closest_to_target); 00067 00068 // Check if the query point is located on the returned edge. 00069 if (is_on_edge) 00070 { 00071 // Check if the point is located on one of the edge endpoints. 00072 if (! closest_he->source()->is_at_open_boundary() && 00073 equal (p, closest_he->source()->point())) 00074 { 00075 // The query point is located on the source vertex: 00076 Vertex_const_handle vh = closest_he->source(); 00077 return (CGAL::make_object (vh)); 00078 } 00079 else if (! closest_he->target()->is_at_open_boundary() && 00080 equal (p, closest_he->target()->point())) 00081 { 00082 // The query point is located on the target vertex: 00083 Vertex_const_handle vh = closest_he->target(); 00084 return (CGAL::make_object (vh)); 00085 } 00086 00087 // The query point is located in the edge interior: 00088 return (CGAL::make_object (closest_he)); 00089 } 00090 00091 // Check if the point is contained in the interior of the current hole. 00092 if (is_in_face) 00093 { 00094 if (closest_to_target) 00095 { 00096 // Deal with the following scenario, where the definition of the 00097 // closest halfedge is not unique (all halfedges around x are 00098 // closest to p): 00099 // 00100 // +--+--+ 00101 // \ | / 00102 // \|/ 00103 // +-------x------+ 00104 // | | 00105 // | (.)p | 00106 // | | 00107 // +--------------+ 00108 // 00109 // In this case, we find the first halfegde whose target is x 00110 // in a clockwise direction from "6 o'clock" around x and take 00111 // its incident face. 00112 closest_he = _first_around_vertex (closest_he->target(), 00113 true); // Shoot up. 00114 } 00115 00116 // Move inside the faces that constitute the hole, the first one 00117 // being incident face of the twin of closest halfedge found so far. 00118 CGAL_assertion (face != closest_he->twin()->face()); 00119 00120 face = closest_he->twin()->face(); 00121 00122 // Perform a vertical walk along the faces of the hole until locating 00123 // a face that contains the qeury point. 00124 do 00125 { 00126 CGAL_assertion_code ( 00127 Halfedge_const_handle old_closest_he = closest_he; 00128 ); 00129 00130 is_in_face = _is_in_connected_component (p, face->outer_ccb(), 00131 true, // Shoot up. 00132 true, // Including p. 00133 closest_he, 00134 is_on_edge, 00135 closest_to_target); 00136 00137 // Check if the query point was located on an edge. 00138 if (is_on_edge) 00139 { 00140 // Check if the point is located on one of the edge endpoints. 00141 if (! closest_he->source()->is_at_open_boundary() && 00142 equal (p, closest_he->source()->point())) 00143 { 00144 // The query point is located on the source vertex: 00145 Vertex_const_handle vh = closest_he->source(); 00146 return (CGAL::make_object (vh)); 00147 } 00148 else if (! closest_he->target()->is_at_open_boundary() && 00149 equal (p, closest_he->target()->point())) 00150 { 00151 // The query point is located on the target vertex: 00152 Vertex_const_handle vh = closest_he->target(); 00153 return (CGAL::make_object (vh)); 00154 } 00155 00156 // The query point is located in the edge iterior: 00157 return (CGAL::make_object (closest_he)); 00158 } 00159 00160 // If the point is not contained in the face, move to the neighboring 00161 // face from below, using the closest halfedge located so far. 00162 if (! is_in_face) 00163 { 00164 if (closest_to_target) 00165 { 00166 // The query point lies below the target vertex of the closest 00167 // halfedge: In this case we have to locate the first halfedge 00168 // we encounter when going around this target vertex from 00169 // "6 o'clock" (see above). 00170 closest_he = _first_around_vertex (closest_he->target(), 00171 true); // Shoot up. 00172 } 00173 00174 CGAL_assertion (old_closest_he != closest_he); 00175 face = closest_he->twin()->face(); 00176 } 00177 00178 } while (! is_in_face); 00179 00180 // We have located a face in the hole that contains the query point. 00181 // This will break the internal loop on holes, and we shall proceed 00182 // for another iteration of the external loop, trying to locate p in 00183 // one of the hole of this new face. 00184 found_containing_hole = true; 00185 } 00186 } // End loop on the current face's holes. 00187 00188 } while (found_containing_hole); 00189 00190 // If we reached here, we did not locate the query point in any of the holes 00191 // inside the current face, so we conclude it is contained in this face. 00192 // However, we first have to check whether the query point coincides with 00193 // any of the isolated vertices contained inside this face. 00194 Isolated_vertex_const_iterator iso_verts_it; 00195 00196 for (iso_verts_it = face->isolated_vertices_begin(); 00197 iso_verts_it != face->isolated_vertices_end(); ++iso_verts_it) 00198 { 00199 if (equal (p, iso_verts_it->point())) 00200 { 00201 Vertex_const_handle vh = iso_verts_it; 00202 return (CGAL::make_object (vh)); 00203 } 00204 } 00205 00206 // The query point is contained in the face interior: 00207 return (CGAL::make_object (face)); 00208 } 00209 00210 //----------------------------------------------------------------------------- 00211 // Locate the arrangement feature which a vertical ray emanating from the 00212 // given point hits. 00213 // 00214 template <class Arrangement> 00215 Object Arr_walk_along_line_point_location<Arrangement>:: 00216 _vertical_ray_shoot (const Point_2& p, 00217 bool shoot_up) const 00218 { 00219 // Start from the initial face (as determined by the topology-traits class), 00220 // and an invalid halfedge representing the closest edge to p from above it 00221 // so far. 00222 typename Traits_adaptor_2::Is_vertical_2 is_vertical = 00223 geom_traits->is_vertical_2_object(); 00224 Inner_ccb_const_iterator ic_it; 00225 Face_const_handle face; 00226 Halfedge_const_handle closest_he; 00227 bool is_in_face; 00228 bool is_on_edge; 00229 bool closest_to_target; 00230 bool found_containing_hole; 00231 00232 face = Face_const_handle (top_traits->initial_face()); 00233 do 00234 { 00235 // Go over the holes in the current face. 00236 found_containing_hole = false; 00237 for (ic_it = face->inner_ccbs_begin(); 00238 !found_containing_hole && ic_it != face->inner_ccbs_end(); 00239 ++ic_it) 00240 { 00241 // Check if the point is inside the current hole. 00242 is_in_face = _is_in_connected_component (p, *ic_it, 00243 shoot_up, 00244 false, // Not including p. 00245 closest_he, 00246 is_on_edge, 00247 closest_to_target); 00248 00249 // Check if the query point is located on the returned edge. 00250 // This can happen only if the edge is vertical. 00251 if (is_on_edge) 00252 { 00253 CGAL_assertion (is_vertical (closest_he->curve())); 00254 return (CGAL::make_object (closest_he)); 00255 } 00256 00257 // Check if the point is contained in the interior of the current hole. 00258 if (is_in_face) 00259 { 00260 if (closest_to_target) 00261 { 00262 // The query point lies below the target vertex of the closest 00263 // halfedge: In this case we have to locate the first halfedge 00264 // we encounter when going around this target vertex from 00265 // "6 o'clock" (when shooting up) or from "12 o'clock" (when 00266 // shooting down). 00267 closest_he = _first_around_vertex (closest_he->target(), 00268 shoot_up); 00269 } 00270 00271 // Move inside the faces that constitute the hole, the first one 00272 // being incident face of the twin of closest halfedge found so far. 00273 CGAL_assertion (face != closest_he->twin()->face()); 00274 00275 face = closest_he->twin()->face(); 00276 00277 // Perform a vertical walk along the faces of the hole until locating 00278 // a face that contains the qeury point. 00279 do 00280 { 00281 CGAL_assertion_code ( 00282 Halfedge_const_handle old_closest_he = closest_he; 00283 ); 00284 00285 is_in_face = _is_in_connected_component (p, face->outer_ccb(), 00286 shoot_up, 00287 false, // Not including p. 00288 closest_he, 00289 is_on_edge, 00290 closest_to_target); 00291 00292 // Check if the query point was located on an edge. 00293 // This can happen only if the edge is vertical. 00294 if (is_on_edge) 00295 { 00296 CGAL_assertion (is_vertical (closest_he->curve())); 00297 return (CGAL::make_object (closest_he)); 00298 } 00299 00300 // If the point is not contained in the face, move to the neighboring 00301 // face from below (or above, if we shoot downward), using the 00302 // closest halfedge located so far. 00303 if (! is_in_face) 00304 { 00305 if (closest_to_target) 00306 { 00307 // The query point lies below the target vertex of the closest 00308 // halfedge: In this case we have to locate the first halfedge 00309 // we encounter when going around this target vertex from 00310 // "6 o'clock" (when shooting up) or from "12 o'clock" (when 00311 // shooting down). 00312 closest_he = _first_around_vertex (closest_he->target(), 00313 shoot_up); 00314 } 00315 00316 00317 CGAL_assertion (old_closest_he != closest_he); 00318 face = closest_he->twin()->face(); 00319 } 00320 00321 } while (! is_in_face); 00322 00323 // We have located a face in the hole that contains the query point. 00324 // This will break the internal loop on holes, and we shall proceed 00325 // for another iteration of the external loop, trying to locate p in 00326 // one of the holes of this new face. 00327 found_containing_hole = true; 00328 } 00329 } // End loop on the current face's holes. 00330 00331 } while (found_containing_hole); 00332 00333 // Check whether one of the isolated vertices in the face containing p lies 00334 // above (or below) it, closer than the closest halfdge we have located. 00335 typename Traits_adaptor_2::Compare_x_2 compare_x = 00336 geom_traits->compare_x_2_object(); 00337 typename Traits_adaptor_2::Compare_xy_2 compare_xy = 00338 geom_traits->compare_xy_2_object(); 00339 typename Traits_adaptor_2::Compare_y_at_x_2 compare_y_at_x = 00340 geom_traits->compare_y_at_x_2_object(); 00341 00342 const Comparison_result point_above_under = (shoot_up ? SMALLER : LARGER); 00343 00344 Isolated_vertex_const_iterator iso_verts_it; 00345 Vertex_const_handle closest_iso_v; 00346 const Vertex_const_handle invalid_v; 00347 const Halfedge_const_handle invalid_he; 00348 00349 for (iso_verts_it = face->isolated_vertices_begin(); 00350 iso_verts_it != face->isolated_vertices_end(); ++iso_verts_it) 00351 { 00352 // The current isolated vertex should have the same x-coordinate as the 00353 // query point in order to be below or above it. 00354 if (compare_x (p, iso_verts_it->point()) != EQUAL) 00355 continue; 00356 00357 // Make sure the isolated vertex is above the query point (if we shoot up) 00358 // or below it (if we shoot down). 00359 if (compare_xy (p, iso_verts_it->point()) != point_above_under) 00360 continue; 00361 00362 // Check if the current isolated vertex lies closer to the query point than 00363 // the closest feature so far. 00364 if (closest_iso_v == invalid_v) 00365 { 00366 // Compare the current isolated vertex with the closest halfedge. 00367 if (closest_he == invalid_he || 00368 closest_he->is_fictitious() || 00369 compare_y_at_x (iso_verts_it->point(), 00370 closest_he->curve()) == point_above_under) 00371 { 00372 // The isolated vertex is closer to the query point than thr closest 00373 // edge found so far (note that a fictitious edge means the edge is 00374 // at infinity). 00375 closest_iso_v = iso_verts_it; 00376 } 00377 } 00378 else if (compare_xy (iso_verts_it->point(), 00379 closest_iso_v->point()) == point_above_under) 00380 { 00381 // The current isolated vertex is closer to the query point than the 00382 // closest isolated vertex found so far. 00383 closest_iso_v = iso_verts_it; 00384 } 00385 } 00386 00387 if (closest_iso_v != invalid_v) 00388 { 00389 // The first object we encounter when we shoot a vertical ray from p is 00390 // an isolated vertex: 00391 return (CGAL::make_object (closest_iso_v)); 00392 } 00393 00394 // If we have no halfedge above, return the initial face. 00395 if (closest_he == invalid_he) 00396 { 00397 Face_const_handle uf = Face_const_handle (top_traits->initial_face()); 00398 00399 return (CGAL::make_object (uf)); 00400 } 00401 00402 // If we reached here, closest_he is the closest edge from above (below) 00403 // the query point. 00404 if (closest_he->is_fictitious()) 00405 { 00406 // If we have a fictitious edge, the ray we shoot is completely contained 00407 // in an unbounded face. This face is incident to closest_he: 00408 if ((shoot_up && closest_he->direction() == ARR_LEFT_TO_RIGHT) || 00409 (!shoot_up && closest_he->direction() == ARR_RIGHT_TO_LEFT)) 00410 closest_he = closest_he->twin(); 00411 00412 Face_const_handle uf = closest_he->face(); 00413 00414 CGAL_assertion (! uf->is_fictitious()); 00415 return (CGAL::make_object (uf)); 00416 } 00417 00418 // Check if one of closest_he's end vertices lies directly above (below) the 00419 // query point, and if so, return this vertex. 00420 if (! is_vertical (closest_he->curve())) 00421 { 00422 if (! closest_he->source()->is_at_open_boundary() && 00423 compare_x (p, closest_he->source()->point()) == EQUAL) 00424 { 00425 Vertex_const_handle vh = closest_he->source(); 00426 return (CGAL::make_object (vh)); 00427 } 00428 00429 if (! closest_he->target()->is_at_open_boundary() && 00430 compare_x (p, closest_he->target()->point()) == EQUAL) 00431 { 00432 Vertex_const_handle vh = closest_he->target(); 00433 return (CGAL::make_object (vh)); 00434 } 00435 } 00436 else 00437 { 00438 // The entire vertical segment is above (below) the query point: Return the 00439 // endpoint closest to it. 00440 const bool is_directed_up = (closest_he->direction() == ARR_LEFT_TO_RIGHT); 00441 00442 if ((shoot_up && is_directed_up) || 00443 (! shoot_up && ! is_directed_up)) 00444 { 00445 Vertex_const_handle vh = closest_he->source(); 00446 return (CGAL::make_object (vh)); 00447 } 00448 else 00449 { 00450 Vertex_const_handle vh = closest_he->target(); 00451 return (CGAL::make_object (vh)); 00452 } 00453 } 00454 00455 // The interior of the edge is closest to the query point: 00456 return (CGAL::make_object (closest_he)); 00457 } 00458 00459 //----------------------------------------------------------------------------- 00460 // Find the closest feature to p (and lying above or below it) along the 00461 // boundary of the given connected component. 00462 // 00463 template <class Arrangement> 00464 bool Arr_walk_along_line_point_location<Arrangement>:: 00465 _is_in_connected_component (const Point_2& p, 00466 Ccb_halfedge_const_circulator circ, 00467 bool shoot_up, 00468 bool inclusive, 00469 Halfedge_const_handle& closest_he, 00470 bool& is_on_edge, 00471 bool& closest_to_target) const 00472 { 00473 // As far as we know, we are not on an edge. 00474 is_on_edge = false; 00475 closest_to_target = false; 00476 00477 // Set the results for comparison acording to the ray direction. 00478 const Comparison_result point_above_under = (shoot_up ? SMALLER : LARGER); 00479 const Comparison_result curve_above_under = (shoot_up ? LARGER : SMALLER); 00480 00481 // Keep a counter of the number of halfedges of the connected component's 00482 // boundary that intersect an upward (or downward, if shoot_up is false) 00483 // vertical ray emanating from the query point p (except for some degenerate 00484 // cases that are explained below). 00485 unsigned int n_ray_intersections = 0; 00486 00487 typename Traits_adaptor_2::Equal_2 equal = 00488 geom_traits->equal_2_object(); 00489 typename Traits_adaptor_2::Compare_x_2 compare_x = 00490 geom_traits->compare_x_2_object(); 00491 typename Traits_adaptor_2::Is_vertical_2 is_vertical = 00492 geom_traits->is_vertical_2_object(); 00493 typename Traits_adaptor_2::Compare_y_position_2 compare_y_position = 00494 geom_traits->compare_y_position_2_object(); 00495 typename Traits_adaptor_2::Compare_y_at_x_right_2 compare_y_at_x_right = 00496 geom_traits->compare_y_at_x_right_2_object(); 00497 typename Traits_adaptor_2::Compare_y_at_x_left_2 compare_y_at_x_left = 00498 geom_traits->compare_y_at_x_left_2_object(); 00499 00500 // Start from the first non-vertical segment in the connected component. 00501 const Halfedge_const_handle invalid_he; 00502 Ccb_halfedge_const_circulator first = circ; 00503 bool found_non_vertical = false; 00504 00505 do 00506 { 00507 // In case of a fictitious edge, check whether it is horizontal; otherwise 00508 // skip it. 00509 if (first->is_fictitious()) 00510 { 00511 if (first->source()->parameter_space_in_y() != ARR_INTERIOR && 00512 first->target()->parameter_space_in_y() != ARR_INTERIOR) 00513 { 00514 found_non_vertical = true; 00515 break; 00516 } 00517 else 00518 { 00519 ++first; 00520 continue; 00521 } 00522 } 00523 00524 // Stop if we found a non-vertical curve. 00525 if (! is_vertical (first->curve())) 00526 { 00527 found_non_vertical = true; 00528 break; 00529 } 00530 00531 if (inclusive) 00532 { 00533 // Check if the current vertical curve contains the query point. 00534 if (! first->source()->is_at_open_boundary() && 00535 compare_x (p, first->source()->point()) == EQUAL && 00536 top_traits->compare_y_at_x (p, &(*first)) == EQUAL) 00537 { 00538 closest_he = first; 00539 is_on_edge = true; 00540 return (true); 00541 } 00542 } 00543 else 00544 { 00545 // Check if the current vertical curve contains the query point in its 00546 // x-range. 00547 if (! first->source()->is_at_open_boundary() && 00548 compare_x (p, first->source()->point()) == EQUAL) 00549 { 00550 // Check if the current vertical curve contains the query point in its 00551 // iterior. 00552 const Comparison_result res1 = 00553 top_traits->compare_xy (p, &(*(first->source()))); 00554 const Comparison_result res2 = 00555 top_traits->compare_xy (p, &(*(first->target()))); 00556 00557 if (res1 != res2) 00558 { 00559 if (! ((res1 == EQUAL && res2 == curve_above_under) || 00560 (res1 == curve_above_under && res2 == EQUAL))) 00561 { 00562 closest_he = first; 00563 is_on_edge = true; 00564 return (true); 00565 } 00566 } 00567 else if (res1 == point_above_under) 00568 { 00569 // Check if the vertical segment is the closest to the query point so 00570 // far. 00571 if (closest_he == invalid_he || 00572 (closest_he != first->twin() && 00573 ((! first->source()->is_at_open_boundary() && 00574 top_traits->compare_y_at_x 00575 (first->source()->point(), 00576 &(*closest_he)) == point_above_under) || 00577 (! first->target()->is_at_open_boundary() && 00578 top_traits->compare_y_at_x 00579 (first->target()->point(), 00580 &(*closest_he)) == point_above_under)))) 00581 { 00582 closest_he = first; 00583 closest_to_target = 00584 ((shoot_up && first->direction() == ARR_RIGHT_TO_LEFT) || 00585 (! shoot_up && first->direction() == ARR_LEFT_TO_RIGHT)); 00586 } 00587 } 00588 } 00589 } 00590 00591 // Move to the next curve. 00592 ++first; 00593 00594 } while (first != circ); 00595 00596 if (! found_non_vertical) 00597 { 00598 // In this case the entire component is comprised of vertical segments, 00599 // so it has an empty interior and p cannot lie inside it. 00600 return (false); 00601 } 00602 00603 // Go over all curves of the boundary, starting from the non-vertical curve 00604 // we have located, and count those which are above p. 00605 Ccb_halfedge_const_circulator curr = first; 00606 Comparison_result source_res, target_res; 00607 Comparison_result res; 00608 Comparison_result y_res; 00609 bool closest_in_ccb = (closest_he != invalid_he && 00610 closest_he->face() == circ->face()); 00611 00612 source_res = top_traits->compare_x (p, &(*(curr->source()))); 00613 do 00614 { 00615 // Ignore the current edge if p is not in its x-range. 00616 target_res = top_traits->compare_x (p, &(*(curr->target()))); 00617 00618 if (source_res == target_res && source_res != EQUAL) 00619 { 00620 ++curr; 00621 source_res = target_res; 00622 continue; 00623 } 00624 00625 // Check whether p lies above or below the current edge. 00626 res = top_traits->compare_y_at_x (p, &(*curr)); 00627 00628 if (res == EQUAL) 00629 { 00630 // The current edge contains the query point. If the seach is inclusive 00631 // we return the edge. Otherwise, we return it only if it is vertical, 00632 // and contains p in its interior. 00633 if (inclusive) 00634 { 00635 closest_he = curr; 00636 is_on_edge = true; 00637 return (true); 00638 } 00639 else 00640 { 00641 if (! curr->is_fictitious() && 00642 is_vertical (curr->curve()) && 00643 (curr->source()->is_at_open_boundary() || 00644 ! equal (curr->source()->point(), p)) && 00645 (curr->target()->is_at_open_boundary() || 00646 ! equal (curr->target()->point(), p))) 00647 { 00648 closest_he = curr; 00649 is_on_edge = true; 00650 return (true); 00651 } 00652 } 00653 } 00654 00655 // If the point is above the current edge (or below it, if we shoot down), 00656 // move to the next edge. 00657 if (res != point_above_under) 00658 { 00659 ++curr; 00660 source_res = target_res; 00661 continue; 00662 } 00663 00664 // Note that we do not have count intersections (actually these are 00665 // overlaps) of the vertical ray we shoot with vertical segments along 00666 // the boundary. 00667 if (curr->is_fictitious() || 00668 ! is_vertical (curr->curve())) 00669 { 00670 // The current curve is not vertical. Check the query point is in the 00671 // semi-open x-range (source, target] of this curve and lies below it. 00672 if (source_res != EQUAL) 00673 { 00674 if (closest_he == invalid_he || 00675 (! closest_in_ccb && closest_he->twin() == curr)) 00676 { 00677 // If we have no closests halfedge, we have just found one. 00678 // Alternatively, if the closest halfedge is not in our CCB, but it 00679 // the twin of our current halfedge, we can take our halfedge to be 00680 // the closest one. 00681 closest_he = curr; 00682 closest_in_ccb = true; 00683 closest_to_target = (target_res == EQUAL); 00684 } 00685 else 00686 { 00687 // Compare with the vertically closest curve so far and detemine the 00688 // curve closest to p. We first check the case that the two curves 00689 // have a common endpoint (note that the two curves do not intersect 00690 // in their interiors). Observe that if such a common vertex exists, 00691 // it is certainly not a vertex at infinity, therefore it is 00692 // associated with a valid point. 00693 if (! closest_he->is_fictitious() && ! curr->is_fictitious() && 00694 ((closest_he->source() == curr->source() && 00695 closest_he->direction() == curr->direction()) || 00696 (closest_he->source() == curr->target() && 00697 closest_he->direction() != curr->direction()))) 00698 { 00699 if (closest_he->direction() == ARR_LEFT_TO_RIGHT) 00700 { 00701 // Both curves extend to the right from a common point. 00702 y_res = compare_y_at_x_right (closest_he->curve(), 00703 curr->curve(), 00704 closest_he->source()->point()); 00705 } 00706 else 00707 { 00708 // Both curves extend to the left from a common point. 00709 y_res = compare_y_at_x_left (closest_he->curve(), 00710 curr->curve(), 00711 closest_he->source()->point()); 00712 } 00713 } 00714 else if (! closest_he->is_fictitious() && ! curr->is_fictitious() && 00715 ((closest_he->target() == curr->source() && 00716 closest_he->direction() != curr->direction()) || 00717 (closest_he->target() == curr->target() && 00718 closest_he->direction() == curr->direction()))) 00719 { 00720 if (closest_he->direction() == ARR_LEFT_TO_RIGHT) 00721 { 00722 // Both curves extend to the left from a common point. 00723 y_res = compare_y_at_x_left (closest_he->curve(), 00724 curr->curve(), 00725 closest_he->target()->point()); 00726 } 00727 else 00728 { 00729 // Both curves extend to the right from a common point. 00730 y_res = compare_y_at_x_right (closest_he->curve(), 00731 curr->curve(), 00732 closest_he->target()->point()); 00733 } 00734 } 00735 else 00736 { 00737 // In case the two curves do not have a common endpoint, but 00738 // overlap in their x-range (both contain p), just compare their 00739 // positions. Note that in this case one of the edges may be 00740 // fictitious, so we preform the comparsion symbolically in this 00741 // case. 00742 if (closest_he->is_fictitious()) 00743 y_res = curve_above_under; 00744 else if (curr->is_fictitious()) 00745 y_res = point_above_under; 00746 else 00747 y_res = compare_y_position (closest_he->curve(), 00748 curr->curve()); 00749 } 00750 00751 // If the current curve is closer to p than the closest curve found 00752 // so far, assign its halfedge as the closest one. 00753 if (y_res == curve_above_under) 00754 { 00755 closest_he = curr; 00756 closest_in_ccb = true; 00757 closest_to_target = (target_res == EQUAL); 00758 } 00759 } 00760 00761 // In the degenerate case where p lies below the target vertex of 00762 // the current halfedge, we have to be a bit careful: 00763 if (target_res == EQUAL) 00764 { 00765 // Locate the next halfedge along the boundary that does not 00766 // contain a vertical segment. 00767 Halfedge_const_handle next_non_vert = curr; 00768 00769 do 00770 { 00771 next_non_vert = next_non_vert->next(); 00772 00773 CGAL_assertion (next_non_vert != curr); 00774 00775 } while ((! next_non_vert->is_fictitious() && 00776 is_vertical (next_non_vert->curve())) || 00777 (next_non_vert->is_fictitious() && 00778 next_non_vert->source()->parameter_space_in_x() != 00779 next_non_vert->target()->parameter_space_in_x())); 00780 00781 // In case the source of the current curve and the target of 00782 // the next non-vertical curve lie on opposite sides of the 00783 // ray we shoot from p (case (a)), we have to count an 00784 // intersection. Otherwise, we have a "tangency" with the ray 00785 // (case (b)) and it is not necessary to count it. 00786 // 00787 // +--------+ + . 00788 // | next \ next . 00789 // | \ . 00790 // + + . 00791 // / / . 00792 // curr / curr / . 00793 // / / . 00794 // + (.)p + (.)p . 00795 // 00796 // (a) (b) 00797 // 00798 target_res = top_traits->compare_x (p, 00799 &(*(next_non_vert->target()))); 00800 00801 CGAL_assertion (source_res != EQUAL && target_res != EQUAL); 00802 00803 if (source_res != target_res) 00804 n_ray_intersections++; 00805 } 00806 else 00807 { 00808 // In this case p lies under the interior of the current x-montone 00809 // curve, so the vertical ray we shoot intersects it exactly once. 00810 n_ray_intersections++; 00811 } 00812 } 00813 } 00814 else 00815 { 00816 // Assign an edge associated with a vertical curve as the closest edge 00817 // only if the vertical curve has an endpoint closer to p than the 00818 // closest edge so far. 00819 if (closest_he == invalid_he || 00820 (! closest_in_ccb && closest_he->twin() == curr) || 00821 (! curr->source()->is_at_open_boundary() && 00822 top_traits->compare_y_at_x 00823 (curr->source()->point(), 00824 &(*closest_he)) == point_above_under) || 00825 (! curr->target()->is_at_open_boundary() && 00826 top_traits->compare_y_at_x 00827 (curr->target()->point(), 00828 &(*closest_he)) == point_above_under)) 00829 { 00830 closest_he = curr; 00831 closest_in_ccb = true; 00832 closest_to_target = 00833 ((shoot_up && curr->direction() == ARR_RIGHT_TO_LEFT) || 00834 (! shoot_up && curr->direction() == ARR_LEFT_TO_RIGHT)); 00835 } 00836 } 00837 00838 // Proceed to the next halfedge along the component boundary. 00839 ++curr; 00840 source_res = target_res; 00841 00842 } while (curr != first); 00843 00844 // The query point lies inside the connected components if and only if the 00845 // ray we shoot from it intersects the boundary an odd number of times. 00846 return ((n_ray_intersections % 2) != 0); 00847 } 00848 00849 //----------------------------------------------------------------------------- 00850 // Find the first halfedge around a given target vertex, when going clockwise 00851 // from "6 o'clock" around this vertex (when shooting up) or starting from 00852 // "12 o'clock (when shooting down). 00853 // 00854 template <class Arrangement> 00855 typename Arr_walk_along_line_point_location<Arrangement>::Halfedge_const_handle 00856 Arr_walk_along_line_point_location<Arrangement>:: 00857 _first_around_vertex (Vertex_const_handle v, bool shoot_up) const 00858 { 00859 // Travrse the incident halfedges of the current vertex and locate the 00860 // lowest one to its left and the topmost to its right. 00861 typename Traits_adaptor_2::Compare_y_at_x_right_2 compare_y_at_x_right = 00862 geom_traits->compare_y_at_x_right_2_object(); 00863 typename Traits_adaptor_2::Compare_y_at_x_left_2 compare_y_at_x_left = 00864 geom_traits->compare_y_at_x_left_2_object(); 00865 00866 Halfedge_const_handle invalid_handle; 00867 Halfedge_const_handle lowest_left; 00868 Halfedge_const_handle top_right; 00869 00870 typename Arrangement_2::Halfedge_around_vertex_const_circulator first = 00871 v->incident_halfedges(); 00872 typename Arrangement_2::Halfedge_around_vertex_const_circulator curr = first; 00873 00874 do 00875 { 00876 // Check whether the current halfedge is defined to the left or to the 00877 // right of the given vertex. 00878 if (curr->direction() == ARR_LEFT_TO_RIGHT) 00879 { 00880 // The curve associated with the current halfedge is defined to the left 00881 // of v. 00882 if (lowest_left == invalid_handle || 00883 (! curr->is_fictitious() && 00884 (lowest_left->is_fictitious() || 00885 compare_y_at_x_left (curr->curve(), 00886 lowest_left->curve(), 00887 v->point()) == SMALLER))) 00888 { 00889 lowest_left = curr; 00890 } 00891 } 00892 else 00893 { 00894 // The curve associated with the current halfedge is defined to the right 00895 // of v. 00896 if (top_right == invalid_handle || 00897 (! curr->is_fictitious() && 00898 (top_right->is_fictitious() || 00899 compare_y_at_x_right (curr->curve(), 00900 top_right->curve(), 00901 v->point()) == LARGER))) 00902 { 00903 top_right = curr; 00904 } 00905 } 00906 00907 curr++; 00908 } while (curr != first); 00909 00910 if (shoot_up) 00911 { 00912 // As we start from "6 o'clock" in a clockwsie direction, the first 00913 // halfedge we encounter is the lowest to the left. However, if there 00914 // is no edge to the left, we first encounter the topmost halfedge to the 00915 // right. 00916 if (lowest_left != invalid_handle) 00917 return (lowest_left); 00918 else 00919 return (top_right); 00920 } 00921 else 00922 { 00923 // As we start from "12 o'clock" in a clockwsie direction, the first 00924 // halfedge we encounter is the topmost to the right. However, if there 00925 // is no edge to the right, we first encounter the lowest halfedge to the 00926 // left. 00927 return (top_right != invalid_handle) ? (top_right) : (lowest_left); 00928 } 00929 } 00930 00931 CGAL_END_NAMESPACE 00932 00933 #endif
1.7.6.1