// Copyright (c) 2005 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you may redistribute it under // the terms of the Q Public License version 1.0. // See the file LICENSE.QPL distributed with CGAL. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // // // Author(s) : Michal Meyerovitch #ifndef CGAL_PARTIAL_VERTICAL_DECOMPOSITION_2_H #define CGAL_PARTIAL_VERTICAL_DECOMPOSITION_2_H //#define CGAL_DEBUG_PARTIAL_VD #include #include #include #include #include #include #include #include #include CGAL_BEGIN_NAMESPACE // To use this partial vertical decomposition, the arrangement's traits // should supply 2 additional methods: // 1. construct_vertical_2 - to construct a vertical X_monotone_curve_2 // from 2 points with same x coordinate // 2. vertical_ray_shoot_2 - to get a point on a X_monotone_curve_2 with // a given x coordinate (assuming it is in the curve's x-range) template class Partial_vertical_decomposition_2 { public: typedef Arrangement_ Arrangement; // Arrangement types: typedef typename Arrangement::Traits_2 Traits_2; typedef typename Traits_2::X_monotone_curve_2 Base_X_monotone_curve_2; typedef typename Traits_2::Point_2 Base_Point_2; typedef typename Arrangement::Halfedge_const_handle Halfedge_const_handle; typedef typename Arrangement::Vertex_const_handle Vertex_const_handle; typedef typename Arrangement::Vertex_const_iterator Vertex_const_iterator; typedef typename Arrangement::Edge_const_iterator Edge_const_iterator; typedef typename Arrangement::Halfedge_const_iterator Halfedge_const_iterator; typedef typename Arrangement::Halfedge_handle Halfedge_handle; typedef typename Arrangement::Vertex_handle Vertex_handle; typedef typename Arrangement::Size Size; // Define meta-traits class for the batched point location: typedef Partial_vd_meta_traits Meta_traits_2; typedef typename Meta_traits_2::X_monotone_curve_2 X_monotone_curve_2; typedef typename Meta_traits_2::Point_2 Point_2; typedef std::pair Vd_pair; typedef std::list Vd_pairs_container; typedef std::list::iterator Vd_pairs_iter; typedef std::back_insert_iterator Vd_pairs_oiter; // Define the sweep-line visitor: typedef Partial_vd_visitor Visitor; typedef Basic_sweep_line_2 Sweep_line; typedef Unique_hash_map Halfedges_map; // Do a partial vertical decomposition on existing arrangement "arr" void operator()(Arrangement& arr) { #ifdef CGAL_DEBUG_PARTIAL_VD cout << "before partial vd: print edges of arr" << endl; for(Halfedge_const_iterator hi = arr.halfedges_begin(); hi != arr.halfedges_end(); ++hi, ++hi) cout << hi->curve() << endl; cout << "before partial vd: print isolated vertices of arr" << endl; for(Vertex_const_iterator vi = arr.vertices_begin(); vi != arr.vertices_end(); ++vi) if (vi->is_isolated()) cout << vi->point() << endl; #endif // Go over all arrangement edges. std::vector xcurves_vec; xcurves_vec.resize(arr.number_of_edges()); typename Traits_2::Compare_xy_2 comp_xy = arr.get_traits()->compare_xy_2_object(); Edge_const_iterator eit; Size i = 0; for (eit = arr.edges_begin(); eit != arr.edges_end(); ++eit, ++i) { // Associate each x-monotone curve with the halfedge that represent it // that is directed from left to right. if(comp_xy(eit->source()->point(), eit->target()->point()) == SMALLER) xcurves_vec[i] = X_monotone_curve_2(eit->curve(),eit); else xcurves_vec[i] = X_monotone_curve_2(eit->curve(),eit->twin()); } // Associate each isolated point with the vertex that represents it std::vector iso_points; for(Vertex_const_iterator v_itr = arr.vertices_begin(); v_itr != arr.vertices_end(); ++v_itr) { if(v_itr->is_isolated()) iso_points.push_back(Point_2(v_itr->point(), v_itr)); } // Perform the sweep Vd_pairs_container vd_pairs; Visitor visitor (arr, std::back_inserter(vd_pairs)); Sweep_line sweep_line (&visitor); sweep_timer.start(); sweep_line.sweep(xcurves_vec.begin(), xcurves_vec.end(), iso_points.begin(), iso_points.end()); sweep_timer.stop(); add_timer.start(); _add_vertical_edges(arr, vd_pairs); add_timer.stop(); #ifdef CGAL_DEBUG_PARTIAL_VD std::cout << "finish partial vd" << std::endl; print_times(); #endif } protected: // add the vertical edges (that were determined by the sweep) to the // arrangement void _add_vertical_edges(Arrangement& arr, Vd_pairs_container& vd_pairs) { Vertex_const_handle invalid_v(NULL); Halfedge_const_handle invalid_he(NULL); Halfedge_handle prev_split_he(NULL); Base_Point_2 prev_split_pt; Vertex_handle prev_split_v(NULL); // map original halfedge in the arrangement to its current rightmost part // which should be split when more than one split of this halfedge is needed Halfedges_map map_orig_to_rightmost; Vd_pairs_iter it = vd_pairs.begin(); for(; it != vd_pairs.end(); ++it) { Vd_pair cur_pair = *it; Vertex_const_handle v1, v2; Halfedge_const_handle h1, h2; if (!CGAL::assign(v1, cur_pair.first)) { CGAL_assertion(CGAL::assign(h1, cur_pair.first)); CGAL::assign(h1, cur_pair.first); } if (!CGAL::assign(v2, cur_pair.second)) { CGAL_assertion(CGAL::assign(h2, cur_pair.second)); CGAL::assign(h2, cur_pair.second); } // we have 2 vertices, no split is needed if (v1 != invalid_v && v2 != invalid_v) { if (should_add_vertical_edge(arr.non_const_handle(v1), arr.non_const_handle(v2))) { #ifdef CGAL_DEBUG_PARTIAL_VD std::cout << "got vertex-vertex pair: " << v1->point() << " and " << v2->point() << std::endl; #endif insert_timer.start(); #ifdef CGAL_DEBUG_PARTIAL_VD std::cout << "before insert at vertices: " << v1->point() << " , " << v2->point() << std::endl; #endif arr.insert_at_vertices( arr.get_traits()->construct_vertical_2_object()(v1->point(), v2->point()), arr.non_const_handle(v1), arr.non_const_handle(v2)); insert_timer.stop(); } continue; } Vertex_handle v; Halfedge_handle orig_split_he, split_he; if (v1 != invalid_v) { // we must have h2 valid CGAL_assertion(h2 != invalid_he); v = arr.non_const_handle(v1); orig_split_he = arr.non_const_handle(h2); } else { // we must have v2 and h1 valid CGAL_assertion(v2 != invalid_v); CGAL_assertion(h1 != invalid_he); v = arr.non_const_handle(v2); orig_split_he = arr.non_const_handle(h1); } if (!should_add_vertical_edge(v, orig_split_he)) continue; #ifdef CGAL_DEBUG_PARTIAL_VD std::cout << "got vertex-halfedge pair: " << v->point() << " and " << orig_split_he->curve() << std::endl; #endif // split split_he and connect the split point with v if (map_orig_to_rightmost.is_defined(orig_split_he)) // we should split the rightmost halfedge instead split_he = map_orig_to_rightmost[orig_split_he]; else split_he = orig_split_he; Base_Point_2 split_p; Vertex_handle split_v; if (prev_split_he == orig_split_he && arr.get_traits()->compare_x_2_object()(prev_split_pt, v->point()) == EQUAL) { split_p = prev_split_pt; split_v = prev_split_v; } else { split_p = arr.get_traits()->vertical_ray_shoot_2 (v->point(), split_he->curve()); Base_X_monotone_curve_2 a,b; #ifdef CGAL_DEBUG_PARTIAL_VD std::cout << "before edge_split, curve=" << split_he->curve() << std::endl << " point= " << split_p << std::endl; #endif arr.get_traits()->split_2_object()(split_he->curve(), split_p, a, b); split_he = arr.split_edge(split_he, a, b); // split always returns the halfedge with source = original source // so the current rightmost part is split_he->next() map_orig_to_rightmost[orig_split_he] = split_he->next(); split_v = split_he->target(); } prev_split_he = orig_split_he; prev_split_pt = split_p; prev_split_v = split_v; // insert the vertical edge insert_timer.start(); #ifdef CGAL_DEBUG_PARTIAL_VD std::cout << "before insert at vertices: " << v->point() << " , " << split_p << std::endl; #endif arr.insert_at_vertices( arr.get_traits()->construct_vertical_2_object()(v->point(), split_p), v, split_v); insert_timer.stop(); // insert_x_monotone(arr, Base_X_monotone_curve_2(v->point(), split_p)); } vd_pairs.clear(); } bool should_add_vertical_edge(Vertex_handle v1, Vertex_handle v2) { return true; // return (!v1->get_is_intersection() || !v2->get_is_intersection()); } bool should_add_vertical_edge(Vertex_handle v, Halfedge_handle he) { return true; // return (!v->get_is_intersection()); } void print_times() { std::cout << "Partial vd times: " << std::endl; std::cout << "sweep: " << sweep_timer.time() << " seconds" << std::endl; std::cout << "add vertical edges: " << add_timer.time() << " seconds" << std::endl; std::cout << "insert edges: " << insert_timer.time() << " seconds" << std::endl; } protected: mutable Timer sweep_timer; mutable Timer add_timer; mutable Timer insert_timer; }; CGAL_END_NAMESPACE #endif