BWAPI
|
00001 // Copyright (c) 2006, 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_topology_traits/Arr_spherical_topology_traits_2_impl.h $ 00015 // $Id: Arr_spherical_topology_traits_2_impl.h 50366 2009-07-05 12:56:48Z efif $ 00016 // 00017 // Author(s) : Efi Fogel <efif@post.tau.ac.il> 00018 // Ron Wein <wein@post.tau.ac.il> 00019 00020 #ifndef CGAL_ARR_SPHERICAL_TOPOLOGY_TRAITS_2_IMPL_H 00021 #define CGAL_ARR_SPHERICAL_TOPOLOGY_TRAITS_2_IMPL_H 00022 00028 CGAL_BEGIN_NAMESPACE 00029 00031 template <class GeomTraits, class Dcel> 00032 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00033 Arr_spherical_topology_traits_2() : 00034 m_spherical_face(NULL), 00035 m_north_pole(NULL), 00036 m_south_pole(NULL), 00037 m_own_traits(true) 00038 { 00039 m_traits = new Traits_adaptor_2; 00040 m_boundary_vertices = Vertex_map(Vertex_key_comparer(m_traits)); 00041 } 00042 00044 template <class GeomTraits, class Dcel> 00045 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00046 Arr_spherical_topology_traits_2(const Geometry_traits_2 * traits) : 00047 m_spherical_face(NULL), 00048 m_north_pole(NULL), 00049 m_south_pole(NULL), 00050 m_own_traits(false) 00051 { 00052 m_traits = static_cast<const Traits_adaptor_2*>(traits); 00053 m_boundary_vertices = Vertex_map(Vertex_key_comparer(m_traits)); 00054 } 00055 00057 template <class GeomTraits, class Dcel> 00058 void Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00059 assign(const Self & other) 00060 { 00061 // Clear the current DCEL and duplicate the other DCEL. 00062 m_dcel.delete_all(); 00063 m_dcel.assign(other.m_dcel); 00064 00065 // Take care of the traits object. 00066 if (m_own_traits && m_traits != NULL) 00067 delete m_traits; 00068 00069 if (other.m_own_traits) 00070 { 00071 m_traits = new Traits_adaptor_2; 00072 m_own_traits = true; 00073 } 00074 else 00075 { 00076 m_traits = other.m_traits; 00077 m_own_traits = false; 00078 } 00079 00080 // Update the rest of the properties. 00081 dcel_updated(); 00082 00083 return; 00084 } 00085 00087 template <class GeomTraits, class Dcel> 00088 void Arr_spherical_topology_traits_2<GeomTraits, Dcel>::dcel_updated() 00089 { 00090 // Go over the DCEL vertices and locate the south and north pole (if any) 00091 // and any other vertex on the line of discontinuity. 00092 typename Dcel::Vertex_iterator vit; 00093 Arr_parameter_space bx, by; 00094 00095 m_north_pole = NULL; 00096 m_south_pole = NULL; 00097 m_boundary_vertices.clear(); 00098 00099 for (vit = this->m_dcel.vertices_begin(); 00100 vit != this->m_dcel.vertices_end(); ++vit) 00101 { 00102 bx = vit->parameter_space_in_x(); 00103 by = vit->parameter_space_in_y(); 00104 00105 if (by == ARR_BOTTOM_BOUNDARY) m_south_pole = &(*vit); 00106 else if (by == ARR_TOP_BOUNDARY) m_north_pole = &(*vit); 00107 else if (bx != ARR_INTERIOR) { 00108 const Point_2 & key = vit->point(); 00109 m_boundary_vertices.insert(Vertex_value(key, &(*vit))); 00110 } 00111 } 00112 00113 // Go over the DCEL faces and locate the spherical face, which is the only 00114 // face with no outer CCB. 00115 typename Dcel::Face_iterator fit; 00116 00117 m_spherical_face = NULL; 00118 for (fit = this->m_dcel.faces_begin(); fit != this->m_dcel.faces_end(); ++fit) 00119 { 00120 if (fit->number_of_outer_ccbs() == 0) 00121 { 00122 CGAL_assertion(m_spherical_face == NULL); 00123 00124 m_spherical_face = &(*fit); 00125 break; 00126 } 00127 } 00128 CGAL_assertion(m_spherical_face != NULL); 00129 00130 return; 00131 } 00132 00134 template <class GeomTraits, class Dcel> 00135 void Arr_spherical_topology_traits_2<GeomTraits, Dcel>::init_dcel() 00136 { 00137 // std::cout << "init_dcel()" << std::endl; 00138 // Clear the current DCEL. 00139 m_dcel.delete_all(); 00140 m_boundary_vertices.clear(); 00141 00142 // Create the face. 00143 m_spherical_face = this->m_dcel.new_face(); 00144 m_spherical_face->set_unbounded(false); 00145 m_spherical_face->set_fictitious(false); 00146 00147 m_north_pole = NULL; 00148 m_south_pole = NULL; 00149 } 00150 00152 template <class GeomTraits, class Dcel> 00153 bool Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00154 is_in_face(const Face * f, const Point_2 & p, const Vertex * v) const 00155 { 00156 // std::cout << "is_in_face()" << std::endl; 00157 CGAL_precondition(v == NULL || !v->has_null_point()); 00158 CGAL_precondition(v == NULL || m_traits->equal_2_object()(p, v->point())); 00159 00160 /* There is always one face that contains everything else. It has no 00161 * outer CCB's. When a new face is constructed, we make sure that the 00162 * face that contains everything also contains the north pole. (In the 00163 * degenerate case, where a vertex coincides with the north pole, the face 00164 * that contains everything is incident to the north pole.) 00165 * If the face has no iuter ccb's, it contains everything: 00166 */ 00167 #if 0 00168 std::cout << "p: " << p 00169 << ", f->number_of_outer_ccbs(): " << f->number_of_outer_ccbs() 00170 << std::endl; 00171 #endif 00172 if (f->number_of_outer_ccbs() == 0) return true; 00173 if (((v != NULL) && (v->parameter_space_in_y() == ARR_TOP_BOUNDARY)) || 00174 (m_traits->parameter_space_in_y_2_object()(p) == ARR_TOP_BOUNDARY)) 00175 return false; 00176 00183 typename Traits_adaptor_2::Parameter_space_in_x_2 ps_x_op = 00184 m_traits->parameter_space_in_x_2_object(); 00185 typename Traits_adaptor_2::Parameter_space_in_y_2 ps_y_op = 00186 m_traits->parameter_space_in_y_2_object(); 00187 typename Traits_adaptor_2::Compare_x_2 cmp_x_op = 00188 m_traits->compare_x_2_object(); 00189 typename Traits_adaptor_2::Compare_y_at_x_2 cmp_y_at_x_op = 00190 m_traits->compare_y_at_x_2_object(); 00191 typename Traits_adaptor_2::Compare_x_near_boundary_2 cmp_x_near_bnd = 00192 m_traits->compare_x_near_boundary_2_object(); 00193 00194 /* Maintain a counter of the number of x-monotone curves that intersect an 00195 * upward vertical ray emanating from p. Handle degenerate cases as 00196 * explained below). 00197 */ 00198 unsigned int num_intersections = 0; 00199 00200 /* Traverse all outer CCBs of the face. For each boundary component go over 00201 * all its halfedges, and count those which are above p. 00202 */ 00203 typename Face::Outer_ccb_const_iterator oit; 00204 for (oit = f->outer_ccbs_begin(); oit != f->outer_ccbs_end(); ++oit) { 00205 const Halfedge * first = *oit; 00206 const Halfedge * curr = first; 00207 00208 /* Compare p to the source vertex of the first halfedge. If p coincides 00209 * with this vertex, p is obviously not in the interior of the face. 00210 */ 00211 if (curr->opposite()->vertex() == v) return false; 00212 00213 00229 /* Indicates that a change between the x-position of p and the x-position 00230 * of the current-curve source, and the x-position of p and the x-position 00231 * of the current-curve target is pending. Used to handle case (2) above. 00232 */ 00233 bool change_pending = false; 00234 00239 bool last_pending = false; 00240 00241 Comparison_result res_pending = EQUAL, res_last = EQUAL, 00242 res_source = EQUAL, res_target; 00243 Arr_parameter_space bnd_pending = ARR_INTERIOR, bnd_last = ARR_INTERIOR, 00244 bnd_source, bnd_target = ARR_INTERIOR; 00245 00246 Arr_parameter_space bnd_p = ARR_INTERIOR; 00247 if (v != NULL) bnd_p = v->parameter_space_in_x(); 00248 00249 do { 00250 /* Compare p to the target vertex of the current halfedge. If the 00251 * vertex v is on the boundary of the component, p is not in the interior 00252 * the face. 00253 */ 00254 if (curr->vertex() == v) return false; 00255 00256 // Ignore vertical curves: 00257 bool is_vertical = m_traits->is_vertical_2_object() (curr->curve()); 00258 if (is_vertical) 00259 { 00260 /* If this outer ccb chain contains the north pole, and our point 00261 * lies horizontaly between the two vertical curves that meet at 00262 * the north pole, increase the intersection counter 00263 */ 00264 Arr_parameter_space bnd1 = ps_y_op(curr->curve(), ARR_MAX_END); 00265 Arr_parameter_space bnd2 = ps_y_op(curr->next()->curve(), ARR_MAX_END); 00266 if ((bnd1 == ARR_TOP_BOUNDARY) && (bnd2 == ARR_TOP_BOUNDARY)) { 00267 // Compare the x-coordinates: 00268 Comparison_result rc1 = 00269 cmp_x_near_bnd(p, curr->curve(), ARR_MAX_END); 00270 Comparison_result rc2 = 00271 cmp_x_near_bnd(p, curr->next()->curve(), ARR_MAX_END); 00272 if (rc1 == opposite(rc2)) ++num_intersections; 00273 } 00274 curr = curr->next(); 00275 continue; 00276 } 00277 00278 /* If the current halfedge belongs to an "antenna". Namely, its 00279 * incident face is the same as its twin's, skip it to avoid counting 00280 * it twice. 00281 */ 00282 const Face * curr_face = (curr->is_on_inner_ccb()) ? 00283 curr->inner_ccb()->face() : curr->outer_ccb()->face(); 00284 const Halfedge * opp_he = curr->opposite(); 00285 const Face * opp_curr_face = (opp_he->is_on_inner_ccb()) ? 00286 opp_he->inner_ccb()->face() : opp_he->outer_ccb()->face(); 00287 00288 if (curr_face == opp_curr_face) { 00289 curr = curr->next(); 00290 continue; 00291 } 00292 00293 Arr_curve_end ind_source, ind_target; 00294 if (curr->direction() == ARR_LEFT_TO_RIGHT) { 00295 ind_source = ARR_MIN_END; 00296 ind_target = ARR_MAX_END; 00297 } else { 00298 ind_source = ARR_MAX_END; 00299 ind_target = ARR_MIN_END; 00300 } 00301 00302 bnd_source = ps_x_op(curr->curve(), ind_source); 00303 bnd_target = ps_x_op(curr->curve(), ind_target); 00304 00305 if (bnd_p != ARR_INTERIOR) { 00306 if (bnd_source == bnd_target) { 00307 curr = curr->next(); 00308 continue; 00309 } 00310 00311 if (bnd_target != ARR_INTERIOR) { 00312 change_pending = true; 00313 bnd_pending = (bnd_target == ARR_LEFT_BOUNDARY) ? 00314 ARR_RIGHT_BOUNDARY : ARR_LEFT_BOUNDARY; 00315 } 00316 if (bnd_source != ARR_INTERIOR) { 00317 if (change_pending) { 00318 change_pending = false; 00319 if (bnd_pending == bnd_source) { 00320 Comparison_result res_y_at_x = cmp_y_at_x_op(p, curr->curve()); 00321 if (res_y_at_x == EQUAL) return false; 00322 if (res_y_at_x == SMALLER) num_intersections++; 00323 } 00324 } else { 00325 // This must be the first curve. Remember to check the last curve 00326 bnd_last = (bnd_source == ARR_LEFT_BOUNDARY) ? 00327 ARR_RIGHT_BOUNDARY : ARR_LEFT_BOUNDARY; 00328 last_pending = true; 00329 } 00330 } 00331 curr = curr->next(); 00332 continue; 00333 } 00334 00335 res_source = (bnd_source == ARR_INTERIOR) ? 00336 cmp_x_op(p, curr->opposite()->vertex()->point()) : 00337 cmp_x_near_bnd(p, curr->curve(), ind_source); 00338 00339 res_target = (bnd_target == ARR_INTERIOR) ? 00340 cmp_x_op(p, curr->vertex()->point()) : 00341 cmp_x_near_bnd(p, curr->curve(), ind_target); 00342 00343 /* If a vertical ray is shot from p upward, the x-monotone curve 00344 * associated with curr is hit once. 00345 */ 00346 if (res_source == res_target) { 00347 curr = curr->next(); 00348 continue; 00349 } 00350 00351 if (res_source != EQUAL) { 00352 change_pending = true; 00353 res_pending = (res_source == SMALLER) ? LARGER : SMALLER; 00354 } 00355 if (res_target != EQUAL) { 00356 if (change_pending) { 00357 change_pending = false; 00358 if (res_pending == res_target) { 00359 Comparison_result res_y_at_x = cmp_y_at_x_op(p, curr->curve()); 00360 if (res_y_at_x == EQUAL) return false; 00361 if (res_y_at_x == SMALLER) num_intersections++; 00362 } 00363 } else { 00364 // This must be the first curve. Remember to check the last curve 00365 res_last = (res_target == SMALLER) ? LARGER : SMALLER; 00366 last_pending = true; 00367 } 00368 } 00369 00370 /* Proceed to the next halfedge along the component boundary. 00371 * Note that the source vertex of this halfedge is the current target. 00372 */ 00373 curr = curr->next(); 00374 } while (curr != first); 00375 00376 if (last_pending) { 00377 if (bnd_p != ARR_INTERIOR) { 00378 if (bnd_last == bnd_target) { 00379 Comparison_result res_y_at_x = cmp_y_at_x_op(p, curr->curve()); 00380 if (res_y_at_x == EQUAL) return false; 00381 if (res_y_at_x == SMALLER) num_intersections++; 00382 } 00383 continue; 00384 } 00385 00386 if (res_last == res_source) { 00387 Comparison_result res_y_at_x = cmp_y_at_x_op(p, curr->curve()); 00388 if (res_y_at_x == EQUAL) return false; 00389 if (res_y_at_x == SMALLER) num_intersections++; 00390 } 00391 } 00392 } 00393 /* The query point lies inside the connected components if the face does 00394 * not contain the north pole, and the vertical ray intersects the 00395 * boundaries an odd number of times. As mentioned above, if the face does 00396 * contain the north pole, then it contains everything, (and has no outer 00397 * CCB's at all). 00398 */ 00399 return (num_intersections & 0x1); 00400 } 00401 00403 template <class GeomTraits, class Dcel> 00404 Comparison_result 00405 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00406 compare_y_at_x(const Point_2 & p, const Halfedge * he) const 00407 { 00408 // std::cout << "compare_y_at_x(Point_2&,Halfedge*)" << std::endl; 00409 return m_traits->compare_y_at_x_2_object()(p, he->curve()); 00410 } 00411 00413 template <class GeomTraits, class Dcel> 00414 bool Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00415 are_equal(const Vertex * v, 00416 const X_monotone_curve_2 & xc, Arr_curve_end ind, 00417 Arr_parameter_space ps_x, Arr_parameter_space ps_y) const 00418 { 00419 #if 0 00420 std::cout << "are_equal" 00421 << ", v: " << v->point() 00422 << ", xc: " << xc << ", " << ind 00423 << std::endl; 00424 #endif 00425 CGAL_precondition (ps_x == ARR_LEFT_BOUNDARY || ps_x == ARR_RIGHT_BOUNDARY || 00426 ps_y == ARR_BOTTOM_BOUNDARY || ps_y == ARR_TOP_BOUNDARY); 00427 00428 // If the given boundary conditions do not match those of the given 00429 // vertex, v cannot represent the curve end. 00430 if (ps_y != v->parameter_space_in_y()) return false; 00431 00432 if (ps_y != ARR_INTERIOR) return (ps_y == v->parameter_space_in_y()); 00433 00434 if (((ps_x == ARR_INTERIOR) && (v->parameter_space_in_x() != ARR_INTERIOR)) || 00435 ((ps_x != ARR_INTERIOR) && (v->parameter_space_in_x() == ARR_INTERIOR))) 00436 return false; 00437 00438 CGAL_assertion(ps_x != ARR_INTERIOR); 00439 /* Both vertices have the same x boundary conditions => 00440 * comapare their y-position. 00441 */ 00442 const Point_2 & p1 = v->point(); 00443 const Point_2 & p2 = (ind == ARR_MIN_END) ? 00444 m_traits->construct_min_vertex_2_object()(xc) : 00445 m_traits->construct_max_vertex_2_object()(xc); 00446 return (m_traits->compare_y_on_boundary_2_object()(p1, p2) == EQUAL); 00447 } 00448 00450 template <class GeomTraits, class Dcel> 00451 void 00452 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00453 notify_on_boundary_vertex_creation(Vertex * v, 00454 const X_monotone_curve_2 & xc, 00455 Arr_curve_end ind, 00456 Arr_parameter_space 00457 CGAL_assertion_code(ps_x), 00458 Arr_parameter_space ps_y) 00459 { 00460 // std::cout << "notify_on_boundary_vertex_creation()" << std::endl; 00461 if (ps_y == ARR_BOTTOM_BOUNDARY) { 00462 m_south_pole = v; 00463 return; 00464 } 00465 if (ps_y == ARR_TOP_BOUNDARY) { 00466 m_north_pole = v; 00467 return; 00468 } 00469 CGAL_assertion(ps_x != ARR_INTERIOR); 00470 const Point_2 & key = (ind == ARR_MIN_END) ? 00471 m_traits->construct_min_vertex_2_object()(xc) : 00472 m_traits->construct_max_vertex_2_object()(xc); 00473 m_boundary_vertices.insert(Vertex_value(key, v)); 00474 } 00475 00479 template <class GeomTraits, class Dcel> 00480 CGAL::Object 00481 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00482 place_boundary_vertex(Face * /* f */, 00483 const X_monotone_curve_2 & xc, Arr_curve_end ind, 00484 Arr_parameter_space ps_x, Arr_parameter_space ps_y) 00485 { 00486 // std::cout << "place_boundary_vertex()" << std::endl; 00487 if (ps_y == ARR_BOTTOM_BOUNDARY) { 00488 if (m_south_pole == NULL) return Object(); 00489 return CGAL::make_object(m_south_pole); 00490 } 00491 00492 if (ps_y == ARR_TOP_BOUNDARY) { 00493 if (m_north_pole == NULL) return Object(); 00494 return CGAL::make_object(m_north_pole); 00495 } 00496 00497 CGAL_assertion((ps_x == ARR_LEFT_BOUNDARY) || (ps_x == ARR_RIGHT_BOUNDARY)); 00498 00499 const Point_2 & key = (ind == ARR_MIN_END) ? 00500 m_traits->construct_min_vertex_2_object()(xc) : 00501 m_traits->construct_max_vertex_2_object()(xc); 00502 typename Vertex_map::iterator it = m_boundary_vertices.find(key); 00503 00504 if (it != m_boundary_vertices.end()) { 00505 Vertex * v = it->second; 00506 return CGAL::make_object(v); 00507 } 00508 00509 // The vertex hasn't been created yet, return a null object: 00510 return Object(); 00511 } 00512 00515 template <class GeomTraits, class Dcel> 00516 typename Arr_spherical_topology_traits_2<GeomTraits, Dcel>::Halfedge * 00517 Arr_spherical_topology_traits_2<GeomTraits,Dcel>:: 00518 locate_around_boundary_vertex(Vertex * v, 00519 const X_monotone_curve_2 & xc, 00520 Arr_curve_end ind, 00521 Arr_parameter_space ps_x, 00522 Arr_parameter_space ps_y) const 00523 { 00524 // std::cout << "locate_around_boundary_vertex()" << std::endl; 00525 if (ps_y == ARR_BOTTOM_BOUNDARY) { 00526 CGAL_assertion(v == m_south_pole); 00527 return (_locate_around_pole(m_south_pole, xc, ind)); 00528 } 00529 00530 if (ps_y == ARR_TOP_BOUNDARY) { 00531 CGAL_assertion(v == m_north_pole); 00532 return (_locate_around_pole(m_north_pole, xc, ind)); 00533 } 00534 00535 CGAL_assertion((ps_x == ARR_LEFT_BOUNDARY) || (ps_x == ARR_RIGHT_BOUNDARY)); 00536 00537 return (_locate_around_vertex_on_discontinuity(v, xc, ind)); 00538 } 00539 00541 template <class GeomTraits, class Dcel> 00542 CGAL::Object Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00543 locate_curve_end(const X_monotone_curve_2 & xc, Arr_curve_end ind, 00544 Arr_parameter_space ps_x, Arr_parameter_space ps_y) 00545 { 00546 // Act according to the boundary conditions. 00547 if (ps_y == ARR_TOP_BOUNDARY) { 00548 // In case the curve end coincides with the north pole, return the vertex 00549 // representing the north pole, if one exists. Otherwise, return the face 00550 // containing this pole (the spherical face). 00551 if (m_north_pole != NULL) return CGAL::make_object(m_north_pole); 00552 return CGAL::make_object(m_spherical_face); 00553 } 00554 00555 typename Vertex_map::iterator it; 00556 Vertex *v = NULL; 00557 00558 if (ps_y == ARR_BOTTOM_BOUNDARY) { 00559 // In case the curve end coincides with the south pole, return the vertex 00560 // representing the south pole, if one exists. Otherwise, search for the 00561 // face containing this pole. 00562 if (m_south_pole != NULL) return CGAL::make_object(m_south_pole); 00563 it = m_boundary_vertices.begin(); 00564 } 00565 else { 00566 CGAL_assertion((ps_x == ARR_LEFT_BOUNDARY) || 00567 (ps_x == ARR_RIGHT_BOUNDARY)); 00568 00569 // Check if the given curve end is incident to a vertex on the line of 00570 // discontinuity. If so, return this vertex. Otherwise, locate the first 00571 // vertex above it. 00572 const Point_2 & key = (ind == ARR_MIN_END) ? 00573 m_traits->construct_min_vertex_2_object()(xc) : 00574 m_traits->construct_max_vertex_2_object()(xc); 00575 it = m_boundary_vertices.find(key); 00576 if (it != m_boundary_vertices.end()) { 00577 v = it->second; 00578 return CGAL::make_object(v); 00579 } 00580 00581 it = m_boundary_vertices.lower_bound(key); 00582 } 00583 00584 // At this point, the iterator it points to a vertex on the line of 00585 // discontinuity that is strictly above the curve end. If there is none, 00586 // we know the curve end is contained in the spherical face. Otherwise, 00587 // we return the face that lies below the vertex v. 00588 if (it == m_boundary_vertices.end()) 00589 return CGAL::make_object(m_spherical_face); 00590 00591 v = it->second; 00592 return CGAL::make_object(_face_below_vertex_on_discontinuity(v)); 00593 } 00594 00596 template <class GeomTraits, class Dcel> 00597 bool 00598 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00599 is_redundant(const Vertex * v) const 00600 { 00601 return (v->halfedge() == NULL); 00602 } 00603 00604 /* \brief erases a given redundant vertex */ 00605 template <class GeomTraits, class Dcel> 00606 typename Arr_spherical_topology_traits_2<GeomTraits, Dcel>::Halfedge * 00607 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00608 erase_redundant_vertex(Vertex * v) 00609 { 00610 const Arr_parameter_space ps_y = v->parameter_space_in_y(); 00611 if (ps_y == ARR_BOTTOM_BOUNDARY) { 00612 m_south_pole = NULL; 00613 return NULL; 00614 } 00615 if (ps_y == ARR_TOP_BOUNDARY) { 00616 m_north_pole = NULL; 00617 return NULL; 00618 } 00619 CGAL_assertion_code(Arr_parameter_space ps_x = v->parameter_space_in_x()); 00620 CGAL_assertion(ps_x != ARR_INTERIOR); 00621 m_boundary_vertices.erase(v->point()); 00622 return NULL; 00623 } 00624 00626 template <class GeomTraits, class Dcel> 00627 const typename 00628 Arr_spherical_topology_traits_2<GeomTraits, Dcel>::X_monotone_curve_2& 00629 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00630 _curve(const Vertex * v, Arr_curve_end & ind) const 00631 { 00632 // std::cout << "curve()" << std::endl; 00633 const Halfedge * he = v->halfedge(); 00634 ind = (he->direction() == ARR_LEFT_TO_RIGHT) ? ARR_MAX_END : ARR_MIN_END; 00635 return he->curve(); 00636 } 00637 00642 template <class GeomTraits, class Dcel> 00643 typename Arr_spherical_topology_traits_2<GeomTraits, Dcel>::Halfedge * 00644 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00645 _locate_around_vertex_on_discontinuity(Vertex * v, 00646 const X_monotone_curve_2 & xc, 00647 Arr_curve_end ind) const 00648 { 00649 // If the vertex is isolated, there is no predecssor halfedge. 00650 if (v->is_isolated()) return NULL; 00651 00652 // Get the first incident halfedge around v and the next halfedge. 00653 Halfedge * first = v->halfedge(); 00654 Halfedge * curr = first; 00655 CGAL_assertion(curr != NULL); 00656 Halfedge * next = curr->next()->opposite(); 00657 00658 // If is only one halfedge incident to v, return this halfedge as xc's 00659 // predecessor: 00660 if (curr == next) return curr; 00661 00662 // Otherwise, we traverse the halfedges around v until we find the pair 00663 // of adjacent halfedges between which we should insert xc. 00664 typename Traits_adaptor_2::Is_between_cw_2 is_between_cw = 00665 m_traits->is_between_cw_2_object(); 00666 bool eq_curr, eq_next; 00667 00668 while (!is_between_cw(xc, (ind == ARR_MIN_END), curr->curve(), 00669 (curr->direction() == ARR_RIGHT_TO_LEFT), 00670 next->curve(), 00671 (next->direction() == ARR_RIGHT_TO_LEFT), v->point(), 00672 eq_curr, eq_next)) 00673 { 00674 // The curve must not be equal to one of the curves already incident to v. 00675 CGAL_assertion(!eq_curr && !eq_next); 00676 00677 // Move to the next pair of incident halfedges. 00678 curr = next; 00679 next = curr->next()->opposite(); 00680 00681 // Make sure we have not completed a full traversal around v without 00682 // locating a place for the new curve xc. 00683 CGAL_assertion(curr != first); 00684 } 00685 00686 // Return the halfedge we have located. 00687 return curr; 00688 } 00689 00694 template <class GeomTraits, class Dcel> 00695 typename Arr_spherical_topology_traits_2<GeomTraits, Dcel>::Halfedge * 00696 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00697 _locate_around_pole(Vertex * v, 00698 const X_monotone_curve_2 & xc, Arr_curve_end ind) const 00699 { 00700 CGAL_assertion(v == m_south_pole || v == m_north_pole); 00701 00702 // std::cout << "locate_around_pole() " << ind << std::endl; 00703 // If the vertex is isolated, return a null halfedge: 00704 if (v->is_isolated()) 00705 return NULL; 00706 00707 // Get the first incident halfedge around v and the next halfedge: 00708 Halfedge * first = v->halfedge(); 00709 Halfedge * curr = first; 00710 CGAL_assertion(curr != NULL); 00711 Halfedge * next = curr->next()->opposite(); 00712 00713 // If there is only one halfedge, it is the predecessor, return it: 00714 if (curr == next) return curr; 00715 00716 // If we compare a curve and its successor around the south (resp. north) 00717 // pole, the result LARGER (resp. SMALLER) indicates that the line of 00718 // discontinuity is located in between the two curves. 00719 const Comparison_result cross_res = (v == m_south_pole) ? LARGER : SMALLER; 00720 00721 // Traverse all other halfedges, and compare their x-positions next to the 00722 // pole with the query curve xc. 00723 typename Traits_adaptor_2::Compare_x_near_boundary_2 cmp_x_near_bnd = 00724 m_traits->compare_x_near_boundary_2_object(); 00725 Arr_curve_end curr_end, next_end; 00726 Comparison_result curr_res, next_res; 00727 Comparison_result curr_next_res; 00728 00729 curr_end = 00730 (curr->direction() == ARR_RIGHT_TO_LEFT) ? ARR_MIN_END : ARR_MAX_END; 00731 curr_res = cmp_x_near_bnd(xc, ind, curr->curve(), curr_end); 00732 do { 00733 next_end = 00734 (next->direction() == ARR_RIGHT_TO_LEFT) ? ARR_MIN_END : ARR_MAX_END; 00735 next_res = cmp_x_near_bnd(xc, ind, next->curve(), next_end); 00736 curr_next_res = 00737 cmp_x_near_bnd(curr->curve(), curr_end, next->curve(), next_end); 00738 if (curr_next_res == cross_res) { 00739 // The line of discontinuity must lie between curr and next, so the 00740 // comparison result of xc with the two curves should be equal: 00741 if (curr_res == next_res) return curr; 00742 } 00743 else { 00744 // The line of discontinuity does not lie between curr and next, so the 00745 // comparison results must be different if xc lies in between. 00746 if (curr_res != next_res) return curr; 00747 } 00748 00749 // Move to the next halfedge around the pole. 00750 curr = next; 00751 curr_end = next_end; 00752 curr_res = next_res; 00753 next = curr->next()->opposite(); 00754 } while (curr != first); 00755 00756 // We sould never reach here: 00757 CGAL_error(); 00758 return NULL; 00759 } 00760 00764 template <class GeomTraits, class Dcel> 00765 typename Arr_spherical_topology_traits_2<GeomTraits, Dcel>::Face * 00766 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00767 _face_below_vertex_on_discontinuity(Vertex * v) const 00768 { 00769 // If the vertex is isolated, just return the face that contains it. 00770 if (v->is_isolated()) 00771 return (v->isolated_vertex()->face()); 00772 00773 // Get the first incident halfedge around v and the next halfedge. 00774 Halfedge *first = v->halfedge(); 00775 Halfedge *curr = first; 00776 CGAL_assertion(curr != NULL); 00777 Halfedge *next = curr->next()->opposite(); 00778 00779 // If there is only one halfedge incident to v, return its incident 00780 // face. 00781 if (curr == next) 00782 { 00783 if (curr->is_on_inner_ccb()) 00784 return (curr->inner_ccb()->face()); 00785 else 00786 return (curr->outer_ccb()->face()); 00787 } 00788 00789 // Otherwise, we traverse the halfedges around v and locate the first 00790 // halfedge we encounter if we go from "6 o'clock" clockwise. 00791 // First locate the lower left and the top right halfedges around v. 00792 typename Traits_adaptor_2::Compare_y_at_x_right_2 cmp_y_at_x_op_right = 00793 m_traits->compare_y_at_x_right_2_object(); 00794 typename Traits_adaptor_2::Compare_y_at_x_left_2 cmp_y_at_x_op_left = 00795 m_traits->compare_y_at_x_left_2_object(); 00796 00797 Halfedge *lowest_left = NULL; 00798 Halfedge *top_right = NULL; 00799 00800 do 00801 { 00802 // Check whether the current halfedge is defined to the left or to the 00803 // right of the given vertex. 00804 if (curr->direction() == ARR_LEFT_TO_RIGHT) { 00805 // The curve associated with the current halfedge is defined to the left 00806 // of v. 00807 if (lowest_left == NULL || 00808 cmp_y_at_x_op_left(curr->curve(), lowest_left->curve(), v->point()) 00809 == SMALLER) 00810 { 00811 lowest_left = curr; 00812 } 00813 } 00814 else 00815 { 00816 // The curve associated with the current halfedge is defined to the right 00817 // of v. 00818 if (top_right == NULL || 00819 cmp_y_at_x_op_right(curr->curve(), top_right->curve(), v->point()) 00820 == LARGER) 00821 { 00822 top_right = curr; 00823 } 00824 } 00825 00826 // Move to the next halfedge around the vertex. 00827 curr = curr->next()->opposite(); 00828 00829 } while (curr != first); 00830 00831 // The first halfedge we encounter is the lowest to the left, but if there 00832 // is no edge to the left, we first encounter the topmost halfedge to the 00833 // right. Note that as the halfedge we located has v as its target, we now 00834 // have to return its twin. 00835 if (lowest_left != NULL) 00836 first = lowest_left->opposite(); 00837 else 00838 first = top_right->opposite(); 00839 00840 // Return the incident face. 00841 if (first->is_on_inner_ccb()) 00842 return (first->inner_ccb()->face()); 00843 else 00844 return (first->outer_ccb()->face()); 00845 } 00846 00851 template <class GeomTraits, class Dcel> 00852 bool 00853 Arr_spherical_topology_traits_2<GeomTraits, Dcel>:: 00854 is_on_new_perimetric_face_boundary(const Halfedge * prev1, 00855 const Halfedge * prev2, 00856 const X_monotone_curve_2 & xc, 00857 bool try_other_way) const 00858 { 00868 #if 0 00869 std::cout << std::endl; 00870 std::cout << "prev1: " 00871 << prev1->opposite()->vertex()->point() << ", " 00872 << prev1->vertex()->point() << std::endl; 00873 std::cout << "prev2: " 00874 << prev2->opposite()->vertex()->point() << ", " 00875 << prev2->vertex()->point() << std::endl; 00876 #endif 00877 int counter = 0; 00878 typename Traits_adaptor_2::Parameter_space_in_x_2 ps_x_op = 00879 m_traits->parameter_space_in_x_2_object(); 00880 00881 // Start with the next of prev1: 00882 const Halfedge * curr = prev1->next(); 00883 // Save its src condition 00884 Arr_curve_end curr_src_ind; 00885 Arr_curve_end curr_trg_ind; 00886 if (curr->direction() == ARR_LEFT_TO_RIGHT) { 00887 curr_src_ind = ARR_MIN_END; 00888 curr_trg_ind = ARR_MAX_END; 00889 } else { 00890 curr_src_ind = ARR_MAX_END; 00891 curr_trg_ind = ARR_MIN_END; 00892 } 00893 Arr_parameter_space first_src_ps = ps_x_op(curr->curve(), curr_src_ind); 00894 Arr_parameter_space curr_trg_ps = ps_x_op(curr->curve(), curr_trg_ind); 00895 while (curr != prev2) { 00896 const Halfedge * next = curr->next(); 00897 Arr_curve_end next_src_ind; 00898 Arr_curve_end next_trg_ind; 00899 if (next->direction() == ARR_LEFT_TO_RIGHT) { 00900 next_src_ind = ARR_MIN_END; 00901 next_trg_ind = ARR_MAX_END; 00902 } else { 00903 next_src_ind = ARR_MAX_END; 00904 next_trg_ind = ARR_MIN_END; 00905 } 00906 Arr_parameter_space next_src_ps = ps_x_op(next->curve(), next_src_ind); 00907 Arr_parameter_space next_trg_ps = ps_x_op(next->curve(), next_trg_ind); 00908 if (curr_trg_ps != next_src_ps) { 00909 if (curr_trg_ps == ARR_RIGHT_BOUNDARY) ++counter; 00910 else --counter; 00911 } 00912 curr = next; 00913 curr_trg_ps = next_trg_ps; 00914 } 00915 Arr_parameter_space last_trg_ps = curr_trg_ps; 00916 if (last_trg_ps != first_src_ps) { 00917 if (last_trg_ps == ARR_RIGHT_BOUNDARY) ++counter; 00918 else if (last_trg_ps == ARR_LEFT_BOUNDARY) --counter; 00919 else if (first_src_ps == ARR_LEFT_BOUNDARY) ++counter; 00920 else if (first_src_ps == ARR_RIGHT_BOUNDARY) --counter; 00921 } 00922 00923 // a temporary fix in case that if we traverse from prev1 to prev2 then 00924 // we get a perimetric curve but from prev2 to prev1 we don't get a perimetric 00925 // curve. We try the other way if we don't get a perimetric curve. 00926 if (try_other_way && (counter != -1 && counter != 1)) 00927 return is_on_new_perimetric_face_boundary(prev2, prev1, xc, false); 00928 00929 // Path must be perimetric: 00930 CGAL_assertion(counter == -1 || counter == 1); 00931 return (counter == 1); 00932 } 00933 00934 CGAL_END_NAMESPACE 00935 00936 #endif