From 8ea81e751517aea1e10a5974bec14e4f936690cd Mon Sep 17 00:00:00 2001 From: Andreas Haas Date: Thu, 26 Feb 2015 16:59:34 +0100 Subject: [PATCH] Algorithms now conform to the concept. The implementations missed const qualifiers everywhere and thus were non-conforming to the specified concept. Triangular Expansions now observes changes to the attached arrangement. Copy of the constraints on CDT initialization is now avoided with boost::transform_iterator. Fixed some bugs on Simple Polygon algorithm when the attached arrangement was changed. The compute_visibility function did not clear the given output arrangement. Added some simple test cases. --- .../Parallel_rotational_sweep_visibility_2.h | 123 ++-- ...eprocessed_rotational_sweep_visibility_2.h | 106 --- .../CGAL/Rotational_sweep_visibility_2.h | 303 +++++---- .../CGAL/Simple_polygon_visibility_2.h | 291 +++++---- .../CGAL/Triangular_expansion_visibility_2.h | 611 +++++++++++------- .../Visibility_2/include/CGAL/test_utils.h | 184 +++++- 6 files changed, 949 insertions(+), 669 deletions(-) delete mode 100644 Visibility_2/include/CGAL/Preprocessed_rotational_sweep_visibility_2.h diff --git a/Visibility_2/include/CGAL/Parallel_rotational_sweep_visibility_2.h b/Visibility_2/include/CGAL/Parallel_rotational_sweep_visibility_2.h index 2be9c9e466d..2e792833c39 100644 --- a/Visibility_2/include/CGAL/Parallel_rotational_sweep_visibility_2.h +++ b/Visibility_2/include/CGAL/Parallel_rotational_sweep_visibility_2.h @@ -691,7 +691,7 @@ private: //private methods private: - void add_box () + void add_box () const { std::vector pts; pts.reserve( vs.size()+1 ); @@ -727,7 +727,7 @@ private: es.back().set_index( es.back().source_index(), edge_base ); } - void compute_shifted_source () + void compute_shifted_source () const { if ( query_type != VERTEX_QUERY ) { shifted_source = query_pt; @@ -746,14 +746,15 @@ private: } } - void init_quadrant_each_vertex( int i ) + void init_quadrant_each_vertex( int i ) const { vs[i].init_quadrant( query_pt ); } - void init_quadrant_parallel( CGAL::Sequential_tag ) + + void init_quadrant_parallel( CGAL::Sequential_tag ) const { for ( int i = 0; i < vs.size(); i++ ) init_quadrant_each_vertex( i ); } - void init_quadrant_parallel( CGAL::Parallel_tag ) + void init_quadrant_parallel( CGAL::Parallel_tag ) const { #ifdef CGAL_LINKED_WITH_EBB Parallel_init_quadrant init( this ); @@ -763,17 +764,19 @@ private: #endif } - void init_orientation_each_edge( int i ) + void init_orientation_each_edge( int i ) const { es[i].init_orientation( query_pt, vs[es[i].source_index()].point(), vs[es[i].target_index()].point() ); } - void init_orientation_parallel( CGAL::Sequential_tag ) + + void init_orientation_parallel( CGAL::Sequential_tag ) const { for ( int i = 0; i < es.size(); i++ ) init_orientation_each_edge( i ); } - void init_orientation_parallel( CGAL::Parallel_tag ) + + void init_orientation_parallel( CGAL::Parallel_tag ) const { #ifdef CGAL_LINKED_WITH_EBB Parallel_init_orientation init( this ); @@ -783,13 +786,13 @@ private: #endif } - void sort_vertices( CGAL::Sequential_tag ) + void sort_vertices( CGAL::Sequential_tag ) const { Is_swept_earlier comp ( query_pt, &vs, shifted_source, shifted_quadrant ); std::sort( good_vdx.begin(), good_vdx.end(), comp ); } - void sort_vertices( CGAL::Parallel_tag ) + void sort_vertices( CGAL::Parallel_tag ) const { #ifdef CGAL_LINKED_WITH_TBB Is_swept_earlier comp ( query_pt, &vs, shifted_source, shifted_quadrant ); @@ -799,7 +802,7 @@ private: #endif } - void remove_duplicated_vertices() + void remove_duplicated_vertices() const { // find duplicated vertices int last = 0; @@ -816,9 +819,9 @@ private: good_vdx.erase( good_vdx.begin()+last+1, good_vdx.end() ); } - void sort_incident ( CGAL::Sequential_tag ) + void sort_incident ( CGAL::Sequential_tag ) const { std::sort( incident.begin(), incident.end() ); } - void sort_incident ( CGAL::Parallel_tag ) + void sort_incident ( CGAL::Parallel_tag ) const { #ifdef CGAL_LINKED_WITH_TBB tbb::parallel_sort( incident.begin(), incident.end() ); @@ -827,7 +830,7 @@ private: #endif } - void construct_incident_map() + void construct_incident_map() const { incident.clear(); incident.reserve( es.size()*2 ); @@ -847,7 +850,7 @@ private: } } - bool funnel_block_right( int v_idx, int e_idx ) + bool funnel_block_right( int v_idx, int e_idx ) const { int s_idx = vs[es[e_idx].source_index()].alias_index(); int t_idx = vs[es[e_idx].target_index()].alias_index(); @@ -865,7 +868,7 @@ private: } } - bool funnel_has_precedessor( int v_idx, int e_idx ) + bool funnel_has_precedessor( int v_idx, int e_idx ) const { int s_idx = vs[es[e_idx].source_index()].alias_index(); int t_idx = vs[es[e_idx].target_index()].alias_index(); @@ -876,7 +879,7 @@ private: return es[e_idx].outward(); } - void funnel ( int first, int last ) + void funnel ( int first, int last ) const { std::vector left, right; left.reserve( last - first ); @@ -910,7 +913,7 @@ private: vs[good_vdx[i]].set_sorted_index( i ); } - void process_funnel () + void process_funnel () const { // TBD: future inmprovement: parallelly compute orientation std::vector orients( good_vdx.size()-1, CGAL::LEFT_TURN ); @@ -957,7 +960,7 @@ private: } #ifndef NDEBUG - void check_consistency_after_init() + void check_consistency_after_init() const { for ( int i = 0; i < vs.size(); i++ ) { int alias = vs[i].alias_index(); @@ -993,7 +996,7 @@ private: } #endif - void keep_consistency_after_init() + void keep_consistency_after_init() const { for ( int i = 0; i < vs.size(); i++ ) { int alias = vs[i].alias_index(); @@ -1010,7 +1013,7 @@ private: } } - void init_vertices ( const Face_const_handle& fh ) + void init_vertices ( const Face_const_handle& fh ) const { Circulator circ, curr; Hole_const_iterator hi; @@ -1074,7 +1077,7 @@ private: } // Precondtion: dp != any end point of the edge. - int do_intersect_edge ( const Point_2& dp, int i ) + int do_intersect_edge ( const Point_2& dp, int i ) const { CGAL::Orientation orient1, orient2; if ( es[i].pass_query_pt() ) // ignore bad edges @@ -1089,16 +1092,17 @@ private: return 1; return 0; } + void do_intersect_parallel ( const Point_2& dp, std::vector& results, - CGAL::Sequential_tag ) + CGAL::Sequential_tag ) const { for ( int i = 0; i < es.size(); i++ ) results[i] = do_intersect_edge( dp, i ); } void do_intersect_parallel ( const Point_2& dp, std::vector& results, - CGAL::Parallel_tag ) + CGAL::Parallel_tag ) const { #ifdef CGAL_LINKED_WITH_TBB Parallel_do_intersect_edge obj( this, dp, results ); @@ -1108,12 +1112,12 @@ private: #endif } - int default_cone_size ( CGAL::Sequential_tag ) + int default_cone_size ( CGAL::Sequential_tag ) const { return vs.size(); } - int default_cone_size ( CGAL::Parallel_tag ) + int default_cone_size ( CGAL::Parallel_tag ) const { return 256; } - void partition_cones () + void partition_cones () const { Intersection_edges active_edges( es.size() ); int curr; @@ -1194,7 +1198,7 @@ private: } } - Point_2 ray_edge_intersection( int v_idx, int e_idx ) + Point_2 ray_edge_intersection( int v_idx, int e_idx ) const { const Point_2& dp = vs[v_idx].point(); const Point_2& s = vs[es[e_idx].source_index()].point(); @@ -1219,7 +1223,7 @@ private: return Point_2( ipoint->x(), ipoint->y() ); } - void compute_visibility_partition( int cone_idx ) + void compute_visibility_partition( int cone_idx ) const { const Cone& cone = cones[cone_idx]; Sub_region& result = sub_regions[cone_idx]; @@ -1303,13 +1307,13 @@ private: } } - void compute_visibility_parallel( CGAL::Sequential_tag ) + void compute_visibility_parallel( CGAL::Sequential_tag ) const { for ( int i = 0; i < cones.size(); i++ ) compute_visibility_partition( i ); } - void compute_visibility_parallel( CGAL::Parallel_tag ) + void compute_visibility_parallel( CGAL::Parallel_tag ) const { #ifdef CGAL_LINKED_WITH_TBB if ( cones.size() == 1 ) @@ -1321,7 +1325,7 @@ private: #endif } - void merge_result() + void merge_result() const { polygon.clear(); cone_end_idx = cone_start_idx = -1; @@ -1342,7 +1346,7 @@ private: assert( polygon.size() > 2 ); } - void compute_visibility_impl ( const Face_const_handle& fh ) + void compute_visibility_impl ( const Face_const_handle& fh ) const { assert( !fh->is_unbounded() ); @@ -1365,15 +1369,15 @@ private: } template - void conditional_regularize( VARR& arr_out, CGAL::Tag_true ) + void conditional_regularize( VARR& arr_out, CGAL::Tag_true ) const { regularize_output( arr_out ); } template - void conditional_regularize( VARR& arr_out, CGAL::Tag_false ) + void conditional_regularize( VARR& arr_out, CGAL::Tag_false ) const {} // do nothing template - void regularize_output( VARR& arr_out ) + void regularize_output( VARR& arr_out ) const { typename VARR::Edge_iterator eit; for ( eit = arr_out.edges_begin(); eit != arr_out.edges_end(); eit++ ) { @@ -1387,7 +1391,7 @@ private: // private trace mthods private: #ifndef NDEBUG - void trace_all ( ostream& os ) + void trace_all ( ostream& os ) const { os << "***********************************" << endl; os << " Trace All" << endl; @@ -1457,14 +1461,14 @@ public: Parallel_rotational_sweep_visibility_2 ( const Arrangement_2& arr ) : p_arr(&arr) { geom_traits = p_arr->geometry_traits(); } - const std::string name () + const std::string name () const { return std::string("R_visibility_2"); } // function to compute visibility, query point lies in the interior of a face template typename VARR::Face_handle compute_visibility( const Point_2& q, const Halfedge_const_handle& e, - VARR& arr_out ) + VARR& arr_out ) const { if ( q == e->source()->point() ) return compute_visibility( q, e->prev(), arr_out ); @@ -1556,7 +1560,7 @@ public: template typename VARR::Face_handle compute_visibility( const Point_2& q, const Face_const_handle f, - VARR& arr_out ) + VARR& arr_out ) const { arr_out.clear(); query_pt = q; @@ -1583,34 +1587,35 @@ public: { p_arr = &arr; geom_traits = p_arr->geometry_traits(); } void detach () { p_arr = NULL; geom_traits = NULL; } - const Arrangement_2& arr () const + const Arrangement_2& arrangement_2() const { return *p_arr; } + // Private data members private: const Geometry_traits_2 * geom_traits; const Arrangement_2 * p_arr; - Point_2 query_pt; - Halfedge_const_handle query_edge; - enum { VERTEX_QUERY, EDGE_QUERY, FACE_QUERY } query_type; - Vertex_vector vs; - Edge_vector es; - std::vector good_vdx; - std::vector< std::pair > incident; - std::vector cones; - std::vector sub_regions; - Point_vector polygon; + mutable Point_2 query_pt; + mutable Halfedge_const_handle query_edge; + mutable enum { VERTEX_QUERY, EDGE_QUERY, FACE_QUERY } query_type; + mutable Vertex_vector vs; + mutable Edge_vector es; + mutable std::vector good_vdx; + mutable std::vector< std::pair > incident; + mutable std::vector cones; + mutable std::vector sub_regions; + mutable Point_vector polygon; - Vertex_const_handle cone_end; - Vertex_const_handle cone_start; - int cone_end_idx; - int cone_start_idx; - Arrangement_2 arr_box; + mutable Vertex_const_handle cone_end; + mutable Vertex_const_handle cone_start; + mutable int cone_end_idx; + mutable int cone_start_idx; + mutable Arrangement_2 arr_box; - bool is_small_cone; - Point_2 shifted_source; - int shifted_quadrant; + mutable bool is_small_cone; + mutable Point_2 shifted_source; + mutable int shifted_quadrant; }; } // end namespace CGAL diff --git a/Visibility_2/include/CGAL/Preprocessed_rotational_sweep_visibility_2.h b/Visibility_2/include/CGAL/Preprocessed_rotational_sweep_visibility_2.h deleted file mode 100644 index c5724dbab79..00000000000 --- a/Visibility_2/include/CGAL/Preprocessed_rotational_sweep_visibility_2.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2013 Technical University Braunschweig (Germany). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// 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): Kan Huang -// - -#ifndef CGAL_PREPROCESSED_VISIBILITY_2_H -#define CGAL_PREPROCESSED_VISIBILITY_2_H - -#include -#include -#include -#include - -namespace CGAL { - -template -class Preprocessed_visibility_2 { - -public: - typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; - // Currently only consider with same type for both - typedef Arrangement_2 Input_Arrangement_2; - typedef Arrangement_2 Output_Arrangement_2; - - typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; - typedef typename Arrangement_2::Ccb_halfedge_const_circulator Ccb_halfedge_const_circulator; - typedef typename Arrangement_2::Face_const_handle Face_const_handle; - typedef typename Arrangement_2::Kernel Kernel; - typedef typename CGAL::Arr_linear_traits_2 Linear_traits_2; - - typedef typename Geometry_traits_2::Point_2 Point_2; - typedef typename Geometry_traits_2::Ray_2 Ray_2; - typedef typename Geometry_traits_2::Segment_2 Segment_2; - typedef typename Geometry_traits_2::Line_2 Line_2; - typedef typename Geometry_traits_2::Vector_2 Vector_2; - typedef typename Geometry_traits_2::FT Number_type; - - typedef typename CGAL::Arrangement_2 Line_Arrangement_2; - - Preprocessed_visibility_2() : p_arr(NULL) {}; - - /*! Constructor given an arrangement and the Regularization tag. */ - Preprocessed_visibility_2(Input_Arrangement_2& arr/*, Regularization_category r_t*/): p_arr(&arr) {}; - - bool is_attached() { - return (p_arr != NULL); - } - - void attach(Input_Arrangement_2& arr) { - p_arr = &arr; - } - - void detach() { - p_arr = NULL; - } - - Input_Arrangement_2 arrangement_2()() { - return *p_arr; - } - - void compute_visibility(const Point_2& q, - const Face_const_handle face, - Output_Arrangement_2& out_arr - ) { - - } - - void compute_visibility(const Point_2& q, - const Halfedge_const_handle he, - Output_Arrangement_2& out_arr - ) { - -} - -private: - Input_Arrangement_2* arr; - Line_Arrangement_2 line_arr; - void preprocess() { - - } - - Line_2 dual_line(const Point_2& p) { - return Line_2(p.x(), -1, -p.y()); - } - -}; - -} // namespace CGAL - -#endif diff --git a/Visibility_2/include/CGAL/Rotational_sweep_visibility_2.h b/Visibility_2/include/CGAL/Rotational_sweep_visibility_2.h index c3fbc0ffdbe..89d0d07c807 100644 --- a/Visibility_2/include/CGAL/Rotational_sweep_visibility_2.h +++ b/Visibility_2/include/CGAL/Rotational_sweep_visibility_2.h @@ -36,12 +36,12 @@ public: typedef Arrangement_2_ Arrangement_2; typedef typename Arrangement_2::Traits_2 Traits_2; typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; - typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; + typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; typedef typename Arrangement_2::Vertex_handle Vertex_handle; typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; - typedef typename Arrangement_2::Ccb_halfedge_const_circulator - Ccb_halfedge_const_circulator; + typedef typename Arrangement_2:: + Ccb_halfedge_const_circulator Ccb_halfedge_const_circulator; typedef typename Arrangement_2::Face_const_handle Face_const_handle; typedef typename Arrangement_2::Face_handle Face_handle; @@ -55,9 +55,9 @@ public: typedef typename Geometry_traits_2::FT Number_type; typedef typename Geometry_traits_2::Object_2 Object_2; - typedef RegularizationCategory Regularization_category; - typedef CGAL::Tag_true Supports_general_polygon_category; - typedef CGAL::Tag_true Supports_simple_polygon_category; + typedef RegularizationCategory Regularization_category; + typedef CGAL::Tag_true Supports_general_polygon_category; + typedef CGAL::Tag_true Supports_simple_polygon_category; private: typedef std::vector Points; @@ -76,11 +76,14 @@ private: return false; else { return &(*e1)<&(*e2); -// if (e1->source() == e2->source()) -// return Visibility_2::compare_xy_2(geom_traits, e1->target()->point(), e2->target()->point()) == SMALLER; -// else -// return Visibility_2::compare_xy_2(geom_traits, e1->source()->point(), e2->source()->point()) == SMALLER; - } + } +// if (e1->source() == e2->source()) +// return Visibility_2::compare_xy_2(geom_traits, +// e1->target()->point(), e2->target()->point()) == SMALLER; +// else +// return Visibility_2::compare_xy_2(geom_traits, +// e1->source()->point(), e2->source()->point()) == SMALLER; + } }; @@ -95,7 +98,8 @@ private: else // I know this is dirty but it speeds up by 25%. Michael return &(*v1)<&(*v2); -// return Visibility_2::compare_xy_2(geom_traits, v1->point(), v2->point()) == SMALLER; +// return Visibility_2:: +// compare_xy_2(geom_traits, v1->point(), v2->point()) == SMALLER; } }; @@ -104,7 +108,8 @@ private: Point_2 q; public: Closer_edge() {} - Closer_edge(const Geometry_traits_2* traits, const Point_2& q):geom_traits(traits), q(q) {} + Closer_edge(const Geometry_traits_2* traits, const Point_2& q) : + geom_traits(traits), q(q) {} int vtype(const Point_2& c, const Point_2& p) const { switch(Visibility_2::orientation_2(geom_traits, q, c, p)) { @@ -181,7 +186,7 @@ private: if (Visibility_2::collinear(geom_traits, q, s2, t2)) { //q is collinear with e1 and e2. return (Visibility_2::less_distance_to_point_2(geom_traits, q, s1, s2) - || Visibility_2::less_distance_to_point_2(geom_traits, q, t1, t2)); + || Visibility_2::less_distance_to_point_2(geom_traits, q, t1, t2)); } else { //q is collinear with e1 not with e2. @@ -203,7 +208,7 @@ private: else return false; case LEFT_TURN: - if (Visibility_2::orientation_2(geom_traits, s1, t1, t2) == RIGHT_TURN) + if(Visibility_2::orientation_2(geom_traits, s1, t1, t2) == RIGHT_TURN) return Visibility_2::orientation_2(geom_traits, s2, t2, q) == Visibility_2::orientation_2(geom_traits, s2, t2, s1); else @@ -214,7 +219,7 @@ private: case COLLINEAR: return Visibility_2::orientation_2(geom_traits, s1, t1, t2)!=e1q; case LEFT_TURN: - if (Visibility_2::orientation_2(geom_traits, s1, t1, t2) == RIGHT_TURN) + if(Visibility_2::orientation_2(geom_traits, s1, t1, t2) == RIGHT_TURN) return Visibility_2::orientation_2(geom_traits, s2, t2, q) == Visibility_2::orientation_2(geom_traits, s2, t2, s1); else @@ -231,35 +236,38 @@ private: }; -// Using hash_map or edx causes a seg fault, did not have the time to see why. Michael -// class Hash_edge: public std::unary_function::result_type> { -// public: -// typename boost::hash::result_type -// operator() (const EH e1) const { -// return boost::hash()(&(e1->curve())); -// } -// }; - const Geometry_traits_2 *geom_traits; const Arrangement_2 *p_arr; - Point_2 q; //query point - Points polygon; //visibility polygon - std::map incident_edges; //the edges that are - std::map edx; //index of active edges in the heap - // boost::unordered_map edx; //index of active edges in the heap - std::set active_edges; //a set of edges that intersect the current vision ray. - VHs vs; //angular sorted vertices - EHs bad_edges; //edges that pass the query point - VH cone_end1; //an end of visibility cone - VH cone_end2; //another end of visibility cone - int cone_end1_idx; //index of cone_end1->point() in visibility polygon - int cone_end2_idx; //index of cone_end2->point() in visibility polygon - bool is_vertex_query; - bool is_edge_query; - bool is_face_query; - bool is_big_cone; //whether the angle of visibility_cone is greater than pi. + mutable Point_2 q; //query point + mutable Points polygon; //visibility polygon + + mutable std::map incident_edges; + + mutable std::map edx; //index of active edges in + //the heap + + mutable std::set active_edges; //a set of edges that + //intersect the current + //vision ray. + + mutable VHs vs; //angular sorted vertices + mutable EHs bad_edges; //edges that pass the query point + mutable VH cone_end1; //an end of visibility cone + mutable VH cone_end2; //another end of visibility cone + + mutable int cone_end1_idx; //index of cone_end1->point() in + //visibility polygon + + mutable int cone_end2_idx; //index of cone_end2->point() in + //visibility polygon + + mutable bool is_vertex_query; + mutable bool is_edge_query; + mutable bool is_face_query; + mutable bool is_big_cone; //whether the angle of + //visibility_cone is greater than pi. public: Rotational_sweep_visibility_2(): p_arr(NULL), geom_traits(NULL) {} @@ -267,16 +275,19 @@ public: geom_traits = p_arr->geometry_traits(); } - const std::string name(){return std::string("R_visibility_2");} + const std::string name() const { return std::string("R_visibility_2"); } template typename VARR::Face_handle - compute_visibility(const Point_2& q, const Halfedge_const_handle e, VARR& arr_out) { + compute_visibility( + const Point_2& q, const Halfedge_const_handle e, VARR& arr_out) const + { arr_out.clear(); bad_edges.clear(); this->q = q; - if (Visibility_2::compare_xy_2(geom_traits, q, e->target()->point())==EQUAL) { + if (Visibility_2::compare_xy_2(geom_traits, q, e->target()->point())==EQUAL) + { is_vertex_query = true; is_edge_query = false; is_face_query = false; @@ -284,7 +295,8 @@ public: cone_end2 = e->next()->target(); is_big_cone = CGAL::right_turn(cone_end1->point(), q, cone_end2->point()); - typename Arrangement_2::Halfedge_around_vertex_const_circulator first, curr; + typename Arrangement_2:: + Halfedge_around_vertex_const_circulator first, curr; first = curr = e->target()->incident_halfedges(); do { if (curr->face() == e->face()) @@ -316,11 +328,14 @@ public: } int next_idx = small_idx + 1; bool is_between; - //indicate whether the shape between small_idx and big_idx is the visibility region required. + //indicate whether the shape between small_idx and big_idx is the visibility + //region required. if (CGAL::right_turn(cone_end1->point(), q, cone_end2->point())) { is_between = false; while (next_idx != big_idx) { - if (CGAL::left_turn(cone_end1->point(), q, polygon[next_idx]) || CGAL::left_turn(q, cone_end2->point(), polygon[next_idx])) { + if (CGAL::left_turn(cone_end1->point(), q, polygon[next_idx]) || + CGAL::left_turn(q, cone_end2->point(), polygon[next_idx])) + { is_between = true; break; } @@ -330,7 +345,9 @@ public: else { is_between = true; while (next_idx != big_idx) { - if (CGAL::right_turn(cone_end1->point(), q, polygon[next_idx]) || CGAL::right_turn(q, cone_end2->point(), polygon[next_idx])) { + if (CGAL::right_turn(cone_end1->point(), q, polygon[next_idx]) || + CGAL::right_turn(q, cone_end2->point(), polygon[next_idx])) + { is_between = false; break; } @@ -367,7 +384,9 @@ public: template typename VARR::Face_handle - compute_visibility(const Point_2& q, const Face_const_handle f, VARR& arr_out) { + compute_visibility( + const Point_2& q, const Face_const_handle f, VARR& arr_out) const + { arr_out.clear(); this->q = q; is_vertex_query = false; @@ -375,15 +394,19 @@ public: is_face_query = true; visibility_region_impl(f, q); - Visibility_2::report_while_handling_needles(geom_traits, q, polygon, arr_out); + + Visibility_2::report_while_handling_needles + (geom_traits, q, polygon, arr_out); + conditional_regularize(arr_out, Regularization_category()); + if (arr_out.faces_begin()->is_unbounded()) return ++arr_out.faces_begin(); else return arr_out.faces_begin(); } -bool is_attached() { +bool is_attached() const { return (p_arr != NULL); } @@ -397,30 +420,34 @@ void detach() { geom_traits = NULL; } -const Arrangement_2& arrangement_2() { +const Arrangement_2& arrangement_2() const { return *p_arr; } private: //get the neighbor of v along edge e - VH get_neighbor(const EH e, const VH v) { + VH get_neighbor(const EH e, const VH v) const { if (e->source() == v) return e->target(); else return e->source(); } + //check whether ray(q->dp) intersects segment(p1, p2) bool do_intersect_ray(const Point_2& q, const Point_2& dp, const Point_2& p1, - const Point_2& p2) { - return (CGAL::orientation(q, dp, p1) != CGAL::orientation(q, dp, p2) && CGAL::orientation(q, p1, dp) == CGAL::orientation(q, p1, p2)); + const Point_2& p2) const + { + return (CGAL::orientation(q, dp, p1) != CGAL::orientation(q, dp, p2) && + CGAL::orientation(q, p1, dp) == CGAL::orientation(q, p1, p2)); } //arrange vertices that on a same vision ray in a 'funnel' order - void funnel(int i, int j) { + void funnel(int i, int j) const { VHs right, left; - //whether the edges incident to a vertex block the left side and right side of current vision ray. + //whether the edges incident to a vertex block the left side and right side + //of current vision ray. bool block_left(false), block_right(false); VH former = vs[i], nb; for (int l=i; l(Closer_edge(geom_traits, q)); incident_edges = std::map(Less_vertex(geom_traits)); edx = std::map(Less_edge(geom_traits)); - EHs relevant_edges; //all edges that can affect the visibility of query point. + EHs relevant_edges; //edges that can affect the visibility of query point. Arrangement_2 bbox; if (is_face_query) input_face(f); else input_face(f, relevant_edges, bbox); - //the following code is the initiation of vision ray. the direction of the initial ray is between the direction - //from q to last vertex in vs and positive x-axis. By choosing this direction, we make - //sure that all plane is swept and there is not needle at the beginning of sweeping. + //the following code is the initiation of vision ray. + //the direction of the initial ray is between the direction from q to last + //vertex in vs and positive x-axis. By choosing this direction, we make sure + //that all plane is swept and there is not needle at the beginning of + //sweeping. Vector_2 dir; if (Direction_2(-1, 0) < Direction_2(Vector_2(q, vs.back()->point()))) dir = Vector_2(1, 0) + Vector_2(q, vs.back()->point()); @@ -491,29 +522,33 @@ private: dir = Vector_2(0, -1); Point_2 dp = q + dir; - //initiation of active_edges. for face queries, all edges on the boundary can affect visibility. + //initiation of active_edges. for face queries, + //all edges on the boundary can affect visibility. //for non-face queries, only relevant_edges has to be considered. if (is_face_query) { Ccb_halfedge_const_circulator curr = f->outer_ccb(); Ccb_halfedge_const_circulator circ = curr; do { - if (do_intersect_ray(q, dp, curr->target()->point(), curr->source()->point())) { + if (do_intersect_ray( + q, dp, curr->target()->point(), curr->source()->point())) active_edges.insert(curr); - } + } while (++curr != circ); typename Arrangement_2::Hole_const_iterator hi; for (hi = f->holes_begin(); hi != f->holes_end(); ++hi) { Ccb_halfedge_const_circulator curr = circ = *hi; do { - if (do_intersect_ray(q, dp, curr->target()->point(), curr->source()->point())) + if (do_intersect_ray( + q, dp, curr->target()->point(), curr->source()->point())) active_edges.insert(curr); } while (++curr != circ); } } else { for (int i=0; i!=relevant_edges.size(); i++) - if (do_intersect_ray(q, dp, relevant_edges[i]->source()->point(), relevant_edges[i]->target()->point())) + if (do_intersect_ray(q, dp, relevant_edges[i]->source()->point(), + relevant_edges[i]->target()->point())) active_edges.insert(relevant_edges[i]); } @@ -549,31 +584,40 @@ private: //when the closest edge changed if (is_face_query) { if (remove_cnt > 0 && insert_cnt > 0) { - //some edges are added and some are deleted, which means the vertex swept is part of visibility polygon. + //some edges are added and some are deleted, + //which means the vertex swept is part of visibility polygon. update_visibility(vh->point()); } if (remove_cnt == 0 && insert_cnt > 0) { //only add some edges, means the view ray is blocked by new edges. - //therefore first add the intersection of view ray and former closet edge, then add the vertice swept. + //therefore first add the intersection of view ray and + //former closet edge, then add the vertice swept. update_visibility(ray_seg_intersection(q, vh->point(), closest_e->target()->point(), - closest_e->source()->point())); + closest_e->source()->point()) + ); update_visibility(vh->point()); } if (remove_cnt > 0 && insert_cnt == 0) { - //only delete some edges, means some block is moved and the view ray can reach the segments after the block. + //only delete some edges, means some block is moved and the view ray + //can reach the segments after the block. update_visibility(vh->point()); - update_visibility(ray_seg_intersection(q, - vh->point(), - (*active_edges.begin())->target()->point(), - (*active_edges.begin())->source()->point())); + update_visibility( + ray_seg_intersection(q, + vh->point(), + (*active_edges.begin())->target()->point(), + (*active_edges.begin())->source()->point() + ) + ); } } else { - //extra work here for edge/vertex query is the index of cone_end1 and cone_end2 will be recorded. + //extra work here for edge/vertex query is the index of cone_end1 and + //cone_end2 will be recorded. if (remove_cnt > 0 && insert_cnt > 0) { - //some edges are added and some are deleted, which means the vertice swept is part of visibility polygon. + //some edges are added and some are deleted, + //which means the vertice swept is part of visibility polygon. if (update_visibility(vh->point())) { if (vh == cone_end1) cone_end1_idx = polygon.size()-1; @@ -583,11 +627,13 @@ private: } if (remove_cnt == 0 && insert_cnt > 0) { //only add some edges, means the view ray is blocked by new edges. - //therefore first add the intersection of view ray and former closet edge, then add the vertice swept. + //therefore first add the intersection of view ray and former closet + //edge, then add the vertice swept. update_visibility(ray_seg_intersection(q, vh->point(), closest_e->target()->point(), - closest_e->source()->point())); + closest_e->source()->point()) + ); if (update_visibility(vh->point())) { if (vh == cone_end1) cone_end1_idx = polygon.size()-1; @@ -596,25 +642,28 @@ private: } } if (remove_cnt > 0 && insert_cnt == 0) { - //only delete some edges, means some block is removed and the vision ray can reach the segments after the block. + //only delete some edges, means some block is removed and the vision + //ray can reach the segments after the block. if (update_visibility(vh->point())) { if (vh == cone_end1) cone_end1_idx = polygon.size()-1; else if (vh == cone_end2) cone_end2_idx = polygon.size()-1; } - update_visibility(ray_seg_intersection(q, - vh->point(), - (*active_edges.begin())->target()->point(), - (*active_edges.begin())->source()->point())); + update_visibility( + ray_seg_intersection(q, + vh->point(), + (*active_edges.begin())->target()->point(), + (*active_edges.begin())->source()->point()) + ); } } } } } - void print_edge(const EH e) { - std::cout<source()->point()<<"->"<target()->point()<source()->point() <<"->"<< e->target()->point() <dp) and segment(s, t) @@ -623,6 +672,7 @@ private: Point_2 ray_seg_intersection( const Point_2& q, const Point_2& dp, // the ray const Point_2& s, const Point_2& t) // the segment + const { if (CGAL::collinear(q, dp, s)) { if (CGAL::collinear(q, dp, t)) { @@ -641,24 +691,29 @@ private: } //check if p has been discovered before, if not update the visibility polygon - bool update_visibility(const Point_2& p){ + bool update_visibility(const Point_2& p) const { if (polygon.empty()) { polygon.push_back(p); return true; } - else if (Visibility_2::compare_xy_2(geom_traits, polygon.back(), p) != EQUAL) { + else if (Visibility_2::compare_xy_2(geom_traits, polygon.back(), p) + != EQUAL) + { polygon.push_back(p); return true; } return false; } - //functor to decide which vertex is swept earlier by the rotational sweeping ray + //functor to decide which vertex is swept earlier by the rotational sweeping + //ray class Is_swept_earlier:public std::binary_function { const Point_2& q; const Geometry_traits_2* geom_traits; public: - Is_swept_earlier(const Point_2& q, const Geometry_traits_2* traits):q(q), geom_traits(traits) {} + Is_swept_earlier(const Point_2& q, const Geometry_traits_2* traits) : + q(q), geom_traits(traits) {} + bool operator() (const VH v1, const VH v2) const { const Point_2& p1 = v1->point(); const Point_2& p2 = v2->point(); @@ -676,8 +731,11 @@ private: //return the quadrant of p with respect to o. int quadrant(const Point_2& o, const Point_2& p) const { - typename Geometry_traits_2::Compare_x_2 compare_x = geom_traits->compare_x_2_object(); - typename Geometry_traits_2::Compare_y_2 compare_y = geom_traits->compare_y_2_object(); + typename Geometry_traits_2::Compare_x_2 compare_x = + geom_traits->compare_x_2_object(); + + typename Geometry_traits_2::Compare_y_2 compare_y = + geom_traits->compare_y_2_object(); Comparison_result dx = compare_x(p, o); Comparison_result dy = compare_y(p, o); @@ -694,7 +752,7 @@ private: }; //when the query point is in face, every edge is good. - void input_neighbor_f( const Halfedge_const_handle e) { + void input_neighbor_f( const Halfedge_const_handle e) const { VH v = e->target(); if (!incident_edges.count(v)) vs.push_back(v); @@ -705,21 +763,26 @@ private: //check if p is in the visibility cone bool is_in_cone(const Point_2& p) const{ if (is_big_cone) - return (!CGAL::right_turn(cone_end1->point(), q, p)) || (!CGAL::left_turn(cone_end2->point(), q, p)); + return (!CGAL::right_turn(cone_end1->point(), q, p)) || + (!CGAL::left_turn(cone_end2->point(), q, p)); else - return (!CGAL::right_turn(cone_end1->point(), q, p)) && (!CGAL::left_turn(cone_end2->point(), q, p)); + return (!CGAL::right_turn(cone_end1->point(), q, p)) && + (!CGAL::left_turn(cone_end2->point(), q, p)); } //for vertex and edge query: the visibility is limited in a cone. void input_edge(const Halfedge_const_handle e, - EHs& good_edges) { + EHs& good_edges) const { for (int i=0; itarget(); VH v2 = e->source(); - //an edge will affect visibility only if it has an endpoint in the visibility cone or it crosses the boundary of the cone. - if (is_in_cone(v1->point()) || is_in_cone(v2->point()) || do_intersect_ray(q, cone_end1->point(), v1->point(), v2->point())) { + //an edge will affect visibility only if it has an endpoint in the + //visibility cone or it crosses the boundary of the cone. + if (is_in_cone(v1->point()) || is_in_cone(v2->point()) || + do_intersect_ray(q, cone_end1->point(), v1->point(), v2->point())) + { good_edges.push_back(e); if (!incident_edges.count(v1)) vs.push_back(v1); @@ -732,7 +795,7 @@ private: //for face query: traverse the face to get all edges //and sort vertices in counter-clockwise order. - void input_face (Face_const_handle fh) + void input_face (Face_const_handle fh) const { Ccb_halfedge_const_circulator curr = fh->outer_ccb(); Ccb_halfedge_const_circulator circ = curr; @@ -768,7 +831,7 @@ private: //and sort vertices in counter-clockwise order. void input_face (Face_const_handle fh, EHs& good_edges, - Arrangement_2& bbox) + Arrangement_2& bbox) const { Ccb_halfedge_const_circulator curr = fh->outer_ccb(); Ccb_halfedge_const_circulator circ = curr; @@ -786,7 +849,8 @@ private: } while (++curr != circ); } - //create a box that cover all vertices such that during the sweeping, the vision ray will always intersect at least an edge. + //create a box that cover all vertices such that during the sweeping, + //the vision ray will always intersect at least an edge. //this box doesn't intersect any relevant_edge. Points points; for (int i=0; icompute_x_2_object(); - typename Geometry_traits_2::Compute_y_2 compute_y = geom_traits->compute_y_2_object(); + typename Geometry_traits_2::Compute_x_2 compute_x = + geom_traits->compute_x_2_object(); - //make the box a little bigger than bb so that it won't intersect any relevant_edge. + typename Geometry_traits_2::Compute_y_2 compute_y = + geom_traits->compute_y_2_object(); + + //make the box a little bigger than bb so that it won't intersect any + //relevant_edge. xmin = compute_x(bb.min())-1; ymin = compute_y(bb.min())-1; xmax = compute_x(bb.max())+1; ymax = compute_y(bb.max())+1; Point_2 box[4] = {Point_2(xmin, ymin), Point_2(xmax, ymin), Point_2(xmax, ymax), Point_2(xmin, ymax)}; - Halfedge_handle e1 = bbox.insert_in_face_interior(Segment_2(box[0], box[1]), bbox.unbounded_face()); - Halfedge_handle e2 = bbox.insert_from_left_vertex(Segment_2(box[1], box[2]), e1->target()); - Halfedge_handle e3 = bbox.insert_from_right_vertex(Segment_2(box[2], box[3]), e2->target()); - bbox.insert_at_vertices(Segment_2(box[0], box[3]), e1->source(), e3->target()); + + Halfedge_handle e1 = bbox.insert_in_face_interior(Segment_2(box[0], box[1]), + bbox.unbounded_face()); + + Halfedge_handle e2 = bbox.insert_from_left_vertex(Segment_2(box[1], box[2]), + e1->target()); + + Halfedge_handle e3 = bbox.insert_from_right_vertex(Segment_2(box[2],box[3]), + e2->target()); + + bbox.insert_at_vertices(Segment_2(box[0], box[3]), + e1->source(), e3->target()); circ = curr = e1->face()->outer_ccb(); do { @@ -837,17 +914,17 @@ private: } template - void conditional_regularize(VARR& arr_out, CGAL::Tag_true) { + void conditional_regularize(VARR& arr_out, CGAL::Tag_true) const { regularize_output(arr_out); } template - void conditional_regularize(VARR& arr_out, CGAL::Tag_false) { + void conditional_regularize(VARR& arr_out, CGAL::Tag_false) const { //do nothing } template - void regularize_output(VARR& arr_out) { + void regularize_output(VARR& arr_out) const { typename VARR::Edge_iterator e_itr; for (e_itr = arr_out.edges_begin(); e_itr != arr_out.edges_end(); diff --git a/Visibility_2/include/CGAL/Simple_polygon_visibility_2.h b/Visibility_2/include/CGAL/Simple_polygon_visibility_2.h index c27a4c15e5d..87684817f5f 100644 --- a/Visibility_2/include/CGAL/Simple_polygon_visibility_2.h +++ b/Visibility_2/include/CGAL/Simple_polygon_visibility_2.h @@ -62,11 +62,11 @@ public: typedef typename Geometry_traits_2::FT Number_type; typedef typename Geometry_traits_2::Object_2 Object_2; - typedef RegularizationCategory Regularization_category; - typedef CGAL::Tag_false Supports_general_polygon_category; - typedef CGAL::Tag_true Supports_simple_polygon_category; + typedef RegularizationCategory Regularization_category; + typedef CGAL::Tag_false Supports_general_polygon_category; + typedef CGAL::Tag_true Supports_simple_polygon_category; - Simple_polygon_visibility_2() : p_arr(NULL), geom_traits(NULL) {}; + Simple_polygon_visibility_2() : p_arr(NULL), geom_traits(NULL) {} /*! Constructor given an arrangement and the Regularization tag. */ Simple_polygon_visibility_2(const Arrangement_2& arr): @@ -81,16 +81,17 @@ public: /*! Method to check if the visibility object is attached or not to an arrangement*/ - bool is_attached() { + bool is_attached() const { return (p_arr != NULL); } /*! Attaches the visibility object to the 'arr' arrangement */ void attach(const Arrangement_2& arr) { - p_arr = &arr; - geom_traits = p_arr->geometry_traits(); - query_pt_is_vertex = false; - query_pt_is_on_halfedge = false; + if(p_arr != &arr){ + detach(); + p_arr = &arr; + geom_traits = p_arr->geometry_traits(); + } } /*! Detaches the visibility object from the arrangement it is @@ -101,11 +102,11 @@ public: vertices.clear(); query_pt_is_vertex = false; query_pt_is_on_halfedge = false; - p_cdt = boost::shared_ptr(); + p_cdt.reset(); } /*! Getter method for the input arrangement*/ - const Arrangement_2& arrangement_2() { + const Arrangement_2& arrangement_2() const { return *p_arr; } @@ -113,12 +114,17 @@ public: 'face' and constructs the output in 'out_arr'*/ template typename VARR::Face_handle - compute_visibility(const Point_2& q, - const Face_const_handle face, - VARR& out_arr) { + compute_visibility(const Point_2& q, Face_const_handle face, + VARR& out_arr) const { + + CGAL_precondition_msg(p_arr->number_of_faces() == 2, + "Only simple polygons are supported."); + + out_arr.clear(); - assert(query_pt_is_vertex == false); - assert(query_pt_is_on_halfedge == false); + query_pt_is_vertex = false; + query_pt_is_on_halfedge = false; + // Now retrieve the circulator to first visible vertex from triangulation Ccb_halfedge_const_circulator circ = find_visible_start(face, q); @@ -134,31 +140,7 @@ public: visibility_region_impl(q); - typename std::vector points; - while (!s.empty()) { - Point_2 curr_point = s.top(); - points.push_back(curr_point); - s.pop(); - } - - std::reverse(points.begin(), points.end()); - - CGAL::Visibility_2::report_while_handling_needles - (geom_traits, - q, - points, - out_arr); - - CGAL_precondition(out_arr.number_of_isolated_vertices() == 0); - CGAL_precondition(s.size() == 0); - conditional_regularize(out_arr, Regularization_category()); - vertices.clear(); - if (out_arr.faces_begin()->is_unbounded()) { - return ++out_arr.faces_begin(); - } - else { - return out_arr.faces_begin(); - } + return output(q, out_arr); } /*! Computes the visibility region of the query point 'q' located on the @@ -168,8 +150,14 @@ public: compute_visibility( const Point_2& q, const Halfedge_const_handle he, - VARR& out_arr ) + VARR& out_arr ) const { + + CGAL_precondition_msg(p_arr->number_of_faces() == 2, + "Only simple polygons are supported."); + + out_arr.clear(); + query_pt_is_vertex = false; query_pt_is_on_halfedge = false; bool query_on_target = false; @@ -203,48 +191,34 @@ public: } visibility_region_impl(q); + + return output(q, out_arr); - typename std::vector points; - if (!s.empty()) { - Point_2 prev_pt = s.top(); - if (prev_pt != q) { - points.push_back(prev_pt); - } - else if (query_pt_is_vertex) { - points.push_back(prev_pt); - } - if (!s.empty()) { - s.pop(); - } - while(!s.empty()) { - Point_2 curr_pt = s.top(); - if (curr_pt != q) { - points.push_back(curr_pt); - } - else if (query_pt_is_vertex) { - points.push_back(curr_pt); - } - s.pop(); - } - } +// std::vector points; - std::reverse(points.begin(), points.end()); +// if (!s.empty()) { +// Point_2 prev_pt = s.top(); +// if (prev_pt != q) { +// points.push_back(prev_pt); +// } +// else if (query_pt_is_vertex) { +// points.push_back(prev_pt); +// } +// if (!s.empty()) { +// s.pop(); +// } +// while(!s.empty()) { +// Point_2 curr_pt = s.top(); +// if (curr_pt != q) { +// points.push_back(curr_pt); +// } +// else if (query_pt_is_vertex) { +// points.push_back(curr_pt); +// } +// s.pop(); +// } +// } - CGAL::Visibility_2::report_while_handling_needles - (geom_traits, - q, - points, - out_arr); - CGAL_precondition(out_arr.number_of_isolated_vertices() == 0); - CGAL_precondition(s.size() == 0); - conditional_regularize(out_arr, Regularization_category()); - vertices.clear(); - if (out_arr.faces_begin()->is_unbounded()) { - return ++out_arr.faces_begin(); - } - else { - return out_arr.faces_begin(); - } } private: @@ -252,43 +226,43 @@ private: typedef CGAL::Constrained_triangulation_face_base_2 Fb; typedef CGAL::Triangulation_data_structure_2 TDS; typedef CGAL::No_intersection_tag Itag; - typedef CGAL::Constrained_triangulation_2 CDT; + typedef CGAL::Constrained_triangulation_2 CDT; private: const Arrangement_2 *p_arr; + const Geometry_traits_2 *geom_traits; + /*! Boost pointer to the constrained Delaunay triangulation object*/ - boost::shared_ptr p_cdt; + mutable boost::shared_ptr p_cdt; /*! Mapping of the vertices of the input to the corresponding circulator needed for finding the first visible vertex in case of face queries*/ - std::map - point_itr_map; - const Geometry_traits_2 *geom_traits; + mutable std::map point_itr_map; /*! Stack of visibile points; manipulated when going through the sequence of input vertices; contains the vertices of the visibility region after the run of the algorithm*/ - std::stack s; + mutable std::stack s; /*! Sequence of input vertices*/ - std::vector vertices; + mutable std::vector vertices; /*! State of visibility region algorithm*/ - enum {LEFT, RIGHT, SCANA, SCANB, SCANC, SCAND, FINISH} upcase; - bool query_pt_is_vertex; - bool query_pt_is_on_halfedge; + mutable enum {LEFT, RIGHT, SCANA, SCANB, SCANC, SCAND, FINISH} upcase; + mutable bool query_pt_is_vertex; + mutable bool query_pt_is_on_halfedge; /*! Regularize output if flag is set to true*/ template - void conditional_regularize(VARR& out_arr, CGAL::Tag_true) { + void conditional_regularize(VARR& out_arr, CGAL::Tag_true) const { regularize_output(out_arr); } /*! No need to regularize output if flag is set to false*/ template - void conditional_regularize(VARR& out_arr, CGAL::Tag_false) { + void conditional_regularize(VARR& out_arr, CGAL::Tag_false) const { //do nothing } /*! Regularizes the output - removes edges that have the same face on both sides */ template - void regularize_output(VARR& out_arr) { + void regularize_output(VARR& out_arr) const { typename VARR::Edge_iterator e_itr; for (e_itr = out_arr.edges_begin() ; e_itr != out_arr.edges_end() ; e_itr++) { @@ -303,29 +277,61 @@ private: /*! Initialized the constrained Delaunay triangulation using the edges of the outer boundary of 'face' */ - void init_cdt(const Face_const_handle &face) { + void init_cdt(const Face_const_handle &face) const { + + point_itr_map.clear(); std::vector > constraints; - typename Arrangement_2::Ccb_halfedge_const_circulator circ = - face->outer_ccb(); - typename Arrangement_2::Ccb_halfedge_const_circulator curr = circ; - typename Arrangement_2::Halfedge_const_handle he; + Ccb_halfedge_const_circulator circ = face->outer_ccb(); + Ccb_halfedge_const_circulator curr = circ; do { - he = curr; - Point_2 source = he->source()->point(); - Point_2 target = he->target()->point(); + Point_2 source = curr->source()->point(); + Point_2 target = curr->target()->point(); point_itr_map.insert(std::make_pair(source, curr)); - constraints.push_back(std::make_pair(source,target)); + constraints.push_back(std::make_pair(source, target)); } while(++curr != circ); - p_cdt = boost::shared_ptr(new CDT(constraints.begin(),constraints.end())); + p_cdt = boost::shared_ptr(new CDT(constraints.begin(), + constraints.end())); + } + + template + typename VARR::Face_handle + output(const Point_2& q, VARR& out_arr) const { + + std::vector points; + while (!s.empty()) { + points.push_back(s.top()); + s.pop(); + } + +// std::reverse(points.begin(), points.end()); + + CGAL::Visibility_2::report_while_handling_needles + (geom_traits, + q, + points, + out_arr); + + CGAL_postcondition(out_arr.number_of_isolated_vertices() == 0); + CGAL_postcondition(s.empty()); + + conditional_regularize(out_arr, Regularization_category()); + vertices.clear(); + if (out_arr.faces_begin()->is_unbounded()) { + return ++out_arr.faces_begin(); + } + else { + return out_arr.faces_begin(); + } } /*! Finds a visible vertex from the query point 'q' in 'face' to start the algorithm from*/ - Ccb_halfedge_const_circulator find_visible_start(Face_const_handle face, const Point_2 &q) { + Ccb_halfedge_const_circulator find_visible_start(Face_const_handle face, + const Point_2 &q) const { init_cdt(face); typename CDT::Face_handle fh = p_cdt->locate(q); Point_2 start_point = fh->vertex(0)->point(); @@ -334,7 +340,8 @@ private: Ccb_halfedge_const_circulator circ = point_itr_map[start_point]; Halfedge_const_handle he_curr = circ; - Halfedge_around_vertex_const_circulator incident_circ = he_curr->source()->incident_halfedges(); + Halfedge_around_vertex_const_circulator incident_circ = + he_curr->source()->incident_halfedges(); Halfedge_around_vertex_const_circulator incident_curr = incident_circ; do { @@ -353,10 +360,9 @@ private: || CGAL::Visibility_2::orientation_2(geom_traits, he_next_inc->source()->point(), he_next_inc->target()->point(), - q) == CGAL::LEFT_TURN) { - Ccb_halfedge_const_circulator result_circ = incident_next; - Halfedge_const_handle he_print = result_circ; - return result_circ; + q) == CGAL::LEFT_TURN) + { + return incident_next; } } } while (++incident_curr != incident_circ); @@ -367,7 +373,7 @@ private: 'q' - query point; 'i' - current vertex' index 'w' - endpoint of ray shot from query point */ - void visibility_region_impl(const Point_2& q) { + void visibility_region_impl(const Point_2& q) const { int i = 0; Point_2 w; CGAL::Orientation orient = CGAL::Visibility_2::orientation_2(geom_traits, @@ -418,12 +424,10 @@ private: ( CGAL::Visibility_2::orientation_2 ( geom_traits, q, vertices[0],s_t ) == CGAL::LEFT_TURN ) ) { Segment_2 seg( s.top(), s_t ); - if ( CGAL::Visibility_2::do_intersect_2 - - ( geom_traits, seg, ray_origin ) ) { - Object_2 result = CGAL::Visibility_2::intersect_2 - - ( geom_traits, seg, ray_origin ); + if (Visibility_2::do_intersect_2(geom_traits, seg, ray_origin ) ) + { + Object_2 result = Visibility_2::intersect_2(geom_traits, + seg, ray_origin); const Point_2 * ipoint = CGAL::object_cast(&result); assert( ipoint != NULL ); s_t = *ipoint; @@ -436,7 +440,7 @@ private: } /*! Method that handles the left turns in the vertex algorithm */ - void left(int& i, Point_2& w, const Point_2& query_pt) { + void left(int& i, Point_2& w, const Point_2& query_pt) const { if (i >= vertices.size() - 1) { upcase = FINISH; } @@ -445,8 +449,7 @@ private: s.pop(); Point_2 s_t_prev = s.top(); s.push( s_t ); - CGAL::Orientation orient1 = CGAL::Visibility_2::orientation_2 - + CGAL::Orientation orient1 = Visibility_2::orientation_2 ( geom_traits, query_pt, vertices[i], @@ -458,8 +461,7 @@ private: w = vertices[i+1]; i++; } else { - CGAL::Orientation orient2 = CGAL::Visibility_2::orientation_2 - + CGAL::Orientation orient2 = Visibility_2::orientation_2 ( geom_traits, s_t_prev, vertices[i], @@ -481,7 +483,7 @@ private: /*! Scans the stack such that all vertices that were pushed before to the stack and are now not visible anymore. */ - void right(int& i, Point_2& w, const Point_2& query_pt) { + void right(int& i, Point_2& w, const Point_2& query_pt) const { Point_2 s_j; Point_2 s_j_prev; Point_2 u; @@ -506,12 +508,10 @@ private: Segment_2 seg2( vertices[i-1], vertices[i] ); Segment_2 seg( s_j_prev, s_j ); - if ( ( vertices[i-1] != s_j ) - && ( CGAL::Visibility_2::do_intersect_2 - - (geom_traits, seg, seg2) ) ) { - Object_2 result = CGAL::Visibility_2::intersect_2 - ( geom_traits, seg, seg2 ); + if ( vertices[i-1] != s_j && + Visibility_2::do_intersect_2(geom_traits, seg, seg2) ) + { + Object_2 result = Visibility_2::intersect_2(geom_traits, seg, seg2); const Point_2 * ipoint = CGAL::object_cast(&result); assert( ipoint != NULL ); u = *ipoint; @@ -579,7 +579,7 @@ private: /*! Scans the vertices starting from index 'i' for the first visible vertex out of the back hidden window */ - void scana(int& i, Point_2& w, const Point_2& query_pt) { + void scana(int& i, Point_2& w, const Point_2& query_pt) const { // Scan v_i, v_i+1, ..., v_n for the first edge to intersect (z, s_t) Point_2 u; int k = scan_edges( i, query_pt, s.top(), u, true ); @@ -618,7 +618,7 @@ private: } /*! Find the first edge interecting the segment (v_0, s_t) */ - void scanb(int& i, Point_2& w, const Point_2& query_pt) { + void scanb(int& i, Point_2& w, const Point_2& query_pt) const { if ( i == vertices.size() - 1 ) { upcase = FINISH; return; @@ -639,7 +639,7 @@ private: /*! Finds the exit from a general front hidden window by finding the first vertex to the right of the ray defined by the query_point and w*/ - void scanc(int& i, Point_2& w, const Point_2& query_pt) { + void scanc(int& i, Point_2& w, const Point_2& query_pt) const { Point_2 u; int k = scan_edges( i, s.top(), w, u, false ); upcase = RIGHT; @@ -648,7 +648,7 @@ private: } /*! find the first edge intersecting the given window (s_t, w) */ - void scand(int& i, Point_2& w, const Point_2& query_pt) { + void scand(int& i, Point_2& w, const Point_2& query_pt) const { Point_2 u; int k = scan_edges( i, s.top(), w, u, false ); upcase = LEFT; @@ -663,7 +663,12 @@ private: /*! Scan edges v_i,v_{i+1},...,v_n, until find an edge intersecting given ray or given segment. is_ray = true -> ray, false -> segment. The intersection point is returned by u */ - int scan_edges( int i, const Point_2& ray_begin, const Point_2& ray_end, Point_2& u, bool is_ray ) { + int scan_edges( int i, + const Point_2& ray_begin, + const Point_2& ray_end, + Point_2& u, + bool is_ray ) const + { CGAL::Orientation old_orient = CGAL::RIGHT_TURN; Ray_2 ray( ray_begin, ray_end ); Segment_2 s2( ray_begin, ray_end ); @@ -679,21 +684,15 @@ private: // Orientation switch, an intersection may occur Segment_2 seg( vertices[k], vertices[k+1] ); if ( is_ray ) { - if (CGAL::Visibility_2::do_intersect_2 - - (geom_traits, seg, ray) ) { - result = CGAL::Visibility_2::intersect_2 - < Geometry_traits_2, Segment_2, Ray_2 > - ( geom_traits, seg, ray ); + if (CGAL::Visibility_2::do_intersect_2(geom_traits, seg, ray) ) + { + result = CGAL::Visibility_2::intersect_2( geom_traits, seg, ray ); break; } } else { - if (CGAL::Visibility_2::do_intersect_2 - - (geom_traits, seg, s2) ) { - result = CGAL::Visibility_2::intersect_2 - < Geometry_traits_2, Segment_2, Segment_2 > - ( geom_traits, seg, s2 ); + if (Visibility_2::do_intersect_2(geom_traits, seg, s2) ) + { + result = Visibility_2::intersect_2( geom_traits, seg, s2 ); break; } } diff --git a/Visibility_2/include/CGAL/Triangular_expansion_visibility_2.h b/Visibility_2/include/CGAL/Triangular_expansion_visibility_2.h index aceee08fac2..4a7ba9a9ca3 100644 --- a/Visibility_2/include/CGAL/Triangular_expansion_visibility_2.h +++ b/Visibility_2/include/CGAL/Triangular_expansion_visibility_2.h @@ -19,12 +19,14 @@ // Author(s): Michael Hemmer // -#ifndef CGAL_TRIANGULAR_EXPANSION_VISIBILITY_2__H -#define CGAL_TRIANGULAR_EXPANSION_VISIBILITY_2__H +#ifndef CGAL_TRIANGULAR_EXPANSION_VISIBILITY_2_H +#define CGAL_TRIANGULAR_EXPANSION_VISIBILITY_2_H #include #include +#include #include +#include namespace CGAL { @@ -32,20 +34,27 @@ template class Triangular_expansion_visibility_2 { typedef typename Arrangement_2_::Geometry_traits_2 Geometry_traits_2; typedef typename Geometry_traits_2::Kernel K; + + typedef Triangular_expansion_visibility_2< + Arrangement_2_, RegularizationCategory> Self; + public: - // Currently only consider with same type for both - typedef Arrangement_2_ Arrangement_2; + typedef Arrangement_2_ Arrangement_2; typedef typename Arrangement_2::Traits_2 Traits_2; + typedef typename Arrangement_2::Halfedge Halfedge; typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; + typedef typename Arrangement_2::Edge_const_iterator Edge_const_iterator; typedef typename Arrangement_2::Ccb_halfedge_const_circulator - Ccb_halfedge_const_circulator; + Ccb_halfedge_const_circulator; + typedef typename Arrangement_2::Ccb_halfedge_circulator + Ccb_halfedge_circulator; typedef typename Arrangement_2::Face_const_handle Face_const_handle; typedef typename Arrangement_2::Face_handle Face_handle; typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; typedef typename Arrangement_2::Vertex_handle Vertex_handle; - typedef typename K::Point_2 Point_2; + typedef typename K::Point_2 Point_2; typedef typename Geometry_traits_2::Ray_2 Ray_2; typedef typename Geometry_traits_2::Segment_2 Segment_2; typedef typename Geometry_traits_2::Line_2 Line_2; @@ -54,11 +63,10 @@ public: typedef typename Geometry_traits_2::FT Number_type; typedef typename Geometry_traits_2::Object_2 Object_2; - // TODO typedef RegularizationCategory Regularization_category; - typedef CGAL::Tag_true Supports_general_polygon_category; - typedef CGAL::Tag_true Supports_simple_polygon_category; + typedef CGAL::Tag_true Supports_general_polygon_category; + typedef CGAL::Tag_true Supports_simple_polygon_category; private: typedef CGAL::Triangulation_vertex_base_2 Vb; @@ -66,32 +74,117 @@ private: typedef CGAL::Triangulation_data_structure_2 TDS; typedef CGAL::No_intersection_tag Itag; typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; + + typedef std::pair Constraint; + + // Functor to create edge constraints for the CDT out of Halfedges + struct Make_constraint + { + typedef Constraint result_type; + + Constraint operator()(const Halfedge& edge) const { + return std::make_pair(edge.source()->point(), + edge.target()->point()); + } + }; + + // Observer to track any changes of the attached arrangement. + class Observer : public Arr_observer + { + + typedef Arr_observer Base; + typedef Observer Self; + + + public: + bool has_changed; + + Observer() : Base(), has_changed(false) + {} + + Observer(const Arrangement_2& arr) + : Base(const_cast(arr)), has_changed(false) + {} + + // Arr_observer interface + + void after_attach() { has_changed = false; } + + + void after_global_change() { has_changed = true; } + void after_create_vertex(Vertex_handle) { has_changed = true; } + void after_create_boundary_vertex(Vertex_handle) { has_changed = true; } + void after_create_edge(Halfedge_handle) { has_changed = true; } + void after_modify_vertex(Vertex_handle) { has_changed = true; } + void after_modify_edge(Halfedge_handle) { has_changed = true; } + void after_split_edge(Halfedge_handle, Halfedge_handle) { + has_changed = true; } + void after_split_fictitious_edge(Halfedge_handle, Halfedge_handle) { + has_changed = true; } + void after_split_face(Face_handle, Face_handle, bool) { + has_changed = true; } + void after_split_outer_ccb(Face_handle, Ccb_halfedge_circulator, + Ccb_halfedge_circulator) { + has_changed = true; } + void after_split_inner_ccb(Face_handle, Ccb_halfedge_circulator, + Ccb_halfedge_circulator) { + has_changed = true; } + void after_add_outer_ccb(Ccb_halfedge_circulator) { has_changed = true; } + void after_add_inner_ccb(Ccb_halfedge_circulator) { has_changed = true; } + void after_add_isolated_vertex(Vertex_handle) { has_changed = true; } + void after_merge_edge(Halfedge_handle) { has_changed = true; } + void after_merge_fictitious_edge(Halfedge_handle) { has_changed = true; } + void after_merge_face(Face_handle) { has_changed = true; } + void after_merge_outer_ccb(Face_handle, Ccb_halfedge_circulator) { + has_changed = true; } + void after_merge_inner_ccb(Face_handle, Ccb_halfedge_circulator) { + has_changed = true; } + void after_move_outer_ccb(Ccb_halfedge_circulator) { has_changed = true; } + void after_move_inner_ccb(Ccb_halfedge_circulator) { has_changed = true; } + void after_move_isolated_vertex(Vertex_handle) { has_changed = true; } + void after_remove_vertex() { has_changed = true; } + void after_remove_edge() { has_changed = true; } + void after_remove_outer_ccb(Face_handle) { has_changed = true; } + void after_remove_inner_ccb(Face_handle) { has_changed = true; } + }; -public: - const std::string name(){return std::string("T_visibility_2");} + private: const Arrangement_2* p_arr; - boost::shared_ptr p_cdt; - std::vector needles; + + // May change during visibility computation + mutable Observer observer; + mutable boost::shared_ptr p_cdt; + mutable std::vector needles; + + // Copy constructor and assignment not supported + Triangular_expansion_visibility_2(const Self&); + Self& operator= (const Self& ); + public: Triangular_expansion_visibility_2() : p_arr(NULL){} - /*! Constructor given an arrangement and the Regularization tag. */ + /*! Constructor given an arrangement. */ Triangular_expansion_visibility_2 (const Arrangement_2& arr) - : p_arr(&arr){ + : p_arr(&arr), observer(arr) + { init_cdt(); } - bool is_attached() { + const std::string name() const { return std::string("T_visibility_2"); } + + + bool is_attached() const { //std::cout << "is_attached" << std::endl; return (p_arr != NULL); } void attach(const Arrangement_2& arr) { - // todo observe changes in arr; if(p_arr != &arr){ p_arr = &arr; + observer.detach(); + observer.attach(const_cast(arr)); init_cdt(); } //std::cout << "attach done" << std::endl; @@ -99,22 +192,209 @@ public: void detach() { //std::cout << "detach" << std::endl; + observer.detach(); p_arr = NULL; - p_cdt = boost::shared_ptr(); + p_cdt.reset(); } - const Arrangement_2& arrangement_2() { + const Arrangement_2& arrangement_2() const { return *p_arr; } - typename CDT::Edge get_edge(typename CDT::Face_handle fh, int i){ + + template + typename VARR::Face_handle + compute_visibility(const Point_2& q, + const Face_const_handle face, + VARR& out_arr ) + const { + //std::cout << "query in face interior" << std::endl; + + if(observer.has_changed) { + init_cdt(); + } + + out_arr.clear(); + needles.clear(); + assert(!face->is_unbounded()); + + + std::vector raw_output; + typename CDT::Face_handle fh = p_cdt->locate(q); + + raw_output.push_back(fh->vertex(1)->point()); + if(!p_cdt->is_constrained(get_edge(fh,0))){ + //std::cout<< "edge 0 is not constrained" << std::endl; + expand_edge( + q, + fh->vertex(2)->point(), + fh->vertex(1)->point(), + fh,0,std::back_inserter(raw_output)); + } + + raw_output.push_back(fh->vertex(2)->point()); + if(!p_cdt->is_constrained(get_edge(fh,1))){ + //std::cout << "edge 1 is not constrained" << std::endl; + expand_edge( + q, + fh->vertex(0)->point(), + fh->vertex(2)->point(), + fh,1,std::back_inserter(raw_output)); + } + + raw_output.push_back(fh->vertex(0)->point()); + if(!p_cdt->is_constrained(get_edge(fh,2))){ + //std::cout << "edge 2 is not constrained" << std::endl; + expand_edge( + q, + fh->vertex(1)->point(), + fh->vertex(0)->point(), + fh,2,std::back_inserter(raw_output)); + } + + + return output(raw_output,out_arr); + } + + template + typename VARR::Face_handle + compute_visibility(const Point_2& q, + const Halfedge_const_handle he, + VARR& out_arr) + const { + //std::cout << "visibility_region he" << std::endl; + + if(observer.has_changed) { + init_cdt(); + } + + assert(!he->face()->is_unbounded()); + out_arr.clear(); + needles.clear(); + + std::vector raw_output; + typename CDT::Locate_type location; + int index; + typename CDT::Face_handle fh = p_cdt->locate(q,location,index); + assert(location == CDT::EDGE || location == CDT::VERTEX); + //the following code tries to figure out which triangle one should start in. + + + if(location == CDT::EDGE){ + //std::cout << "query on edge" << std::endl; + // this is the easy part, there are only two possible faces + // index indicates the edge = vertex on the other side of the edge + // the next vertex in cw order should be the target of given edge + if(fh->vertex(p_cdt->cw(index))->point() != he->target()->point()){ + //std::cout << "need to swap face" << std::endl; + // take face on the other side if this is not the case + typename CDT::Face_handle nfh = fh->neighbor(index); + index = nfh->index(fh); + fh = nfh; + } + assert(fh->vertex(p_cdt->cw(index))->point() == he->target()->point()); + assert(!p_cdt->is_infinite(fh->vertex(index))); + + + // output the edge the query lies on + raw_output.push_back(he->source()->point()); + raw_output.push_back(he->target()->point()); + + if(!p_cdt->is_constrained(get_edge(fh,p_cdt->ccw(index)))){ + expand_edge( + q, + fh->vertex(index)->point(), //left + he->target()->point() , //right + fh, + p_cdt->ccw(index), + std::back_inserter(raw_output)); + } + raw_output.push_back(fh->vertex(index)->point()); + + if(!p_cdt->is_constrained(get_edge(fh,p_cdt->cw(index)))){ + expand_edge( + q, + he->source()->point() , //left + fh->vertex(index)->point(), //right + fh, + p_cdt->cw(index), + std::back_inserter(raw_output)); + } + } + + if(location == CDT::VERTEX){ + //std::cout << "query on vertex" << std::endl; + + //bool query_point_on_vertex_is_not_working_yet = false; + //assert(query_point_on_vertex_is_not_working_yet); + + assert(q == he->target()->point()); + assert(fh->vertex(index)->point() == he->target()->point()); + + // push points that are seen anyway + // raw_output.push_back(he->source()->point()); inserted last + raw_output.push_back(he->target()->point()); + raw_output.push_back(he->next()->target()->point()); + + // now start in the triangle that contains he->next() + while( + p_cdt->is_infinite(fh->vertex(p_cdt->ccw(index))) || + he->next()->target()->point() != + fh->vertex(p_cdt->ccw(index))->point() + ) + { + typename CDT::Face_handle nfh = fh->neighbor(p_cdt->ccw(index)); + int nindex = nfh->index(fh); + index = p_cdt->ccw(nindex); + fh = nfh; + assert(he->target()->point() == fh->vertex(index)->point()); + } + + + assert(he->next()->source()->point() == fh->vertex(index)->point()); + assert(he->next()->target()->point() == + fh->vertex(p_cdt->ccw(index))->point()); + assert(!p_cdt->is_infinite(fh)); + assert(p_cdt->is_constrained(get_edge(fh,p_cdt->cw(index)))); + + while(he->source()->point() != fh->vertex(p_cdt->ccw(index))->point()){ + + if(!p_cdt->is_constrained(get_edge(fh,index))){ + expand_edge( + q, + fh->vertex(p_cdt-> cw(index))->point(), //left + fh->vertex(p_cdt->ccw(index))->point(), //right + fh, + index, + std::back_inserter(raw_output)); + } + // push left end point of edge into output + raw_output.push_back(fh->vertex(p_cdt-> cw(index))->point()); + + // take the next triangle around q in ccw order + typename CDT::Face_handle nfh = fh->neighbor(p_cdt->ccw(index)); + int nindex = nfh->index(fh); + index = p_cdt->ccw(nindex); + fh = nfh; + assert(fh->vertex(index)->point() == he->target()->point()); + } + } + return output(raw_output,out_arr); + } + + + +private: + + typename CDT::Edge get_edge(typename CDT::Face_handle fh, int i) const { return std::make_pair(fh,i); } Point_2 ray_seg_intersection( const Point_2& q, const Point_2& b, // the ray - const Point_2& s, const Point_2& t) // the segment - { + const Point_2& s, const Point_2& t // the segment + ) const { + Ray_2 ray(q,b); Segment_2 seg(s,t); assert(typename K::Do_intersect_2()(ray,seg)); @@ -127,9 +407,9 @@ public: const Point_2& q, const typename CDT::Vertex_handle vh, const typename CDT::Face_handle fh, - int index){ + int index) + const { - // the expanded edge should not be constrained assert(!p_cdt->is_constrained(get_edge(fh,index))); assert(!p_cdt->is_infinite(fh)); @@ -168,29 +448,30 @@ public: //std::cout << "rvh->point() "<< rvh->point() << std::endl<< std::endl; - switch ( orient ) { case CGAL::COUNTERCLOCKWISE: // looking on to the right edge - if(p_cdt->is_constrained(re)){ - if(vh!=rvh){ - Point_2 p = ray_seg_intersection(q,vh->point(),nvh->point(),rvh->point()); + if(p_cdt->is_constrained(re)) { + if(vh != rvh) { + Point_2 p = ray_seg_intersection(q, vh->point(), + nvh->point(), rvh->point()); //std::cout << vh->point() <<" -1- "<< p <point(),p)); } - }else{ + } else { collect_needle(q,vh,nfh,rindex); } break; case CGAL::CLOCKWISE: // looking on to the left edge if(p_cdt->is_constrained(le)){ - if(vh!=lvh){ - Point_2 p = ray_seg_intersection(q,vh->point(),nvh->point(),lvh->point()); + if(vh != lvh){ + Point_2 p = ray_seg_intersection(q, vh->point(), + nvh->point(), lvh->point()); //std::cout << vh->point() <<" -2- "<< p <point(),p)); } - }else{ + } else { collect_needle(q,vh,nfh,lindex); } break; @@ -203,15 +484,16 @@ public: needles.push_back(Segment_2(vh->point(),nvh->point())); } // but we may also contiue looking along the vertex - if(!p_cdt->is_constrained(re)){ + if(!p_cdt->is_constrained(re)) { collect_needle(q,nvh,nfh,rindex); } - if(!p_cdt->is_constrained(le)){ + if(!p_cdt->is_constrained(le)) { collect_needle(q,nvh,nfh,lindex); } break; } } + template OIT expand_edge( const Point_2& q, @@ -219,7 +501,8 @@ public: const Point_2& right, typename CDT::Face_handle fh, int index, - OIT oit){ + OIT oit) + const { // the expanded edge should not be constrained assert(!p_cdt->is_constrained(get_edge(fh,index))); @@ -252,12 +535,13 @@ public: CGAL::Orientation ro = orientation(q,right,nvh->point()); CGAL::Orientation lo = orientation(q,left ,nvh->point()); - assert(typename K::Orientation_2()(q,left ,lvh->point()) != CGAL::CLOCKWISE); - assert(typename K::Orientation_2()(q,right,rvh->point()) != CGAL::COUNTERCLOCKWISE); + assert(typename K::Orientation_2()(q,left ,lvh->point()) + != CGAL::CLOCKWISE); + assert(typename K::Orientation_2()(q,right,rvh->point()) + != CGAL::COUNTERCLOCKWISE); - //std::cout << (ro == CGAL::COUNTERCLOCKWISE) << " " << (lo == CGAL::CLOCKWISE) << std::endl; - - + //std::cout << (ro == CGAL::COUNTERCLOCKWISE) << " " << + //(lo == CGAL::CLOCKWISE) << std::endl; //right edge is seen if new vertex is counter clockwise of right boarder if(ro == CGAL::COUNTERCLOCKWISE){ @@ -306,9 +590,12 @@ public: if(!Regularization_category::value){ assert(!(ro == CGAL::COLLINEAR && lo == CGAL::COLLINEAR)); // we have to check whether a needle starts here. - if(p_cdt->is_constrained(le) && !p_cdt->is_constrained(re) && ro == CGAL::COLLINEAR) - collect_needle(q,nvh,nfh,rindex); - if(p_cdt->is_constrained(re) && !p_cdt->is_constrained(le) && lo == CGAL::COLLINEAR) + if(p_cdt->is_constrained(le) && !p_cdt->is_constrained(re) + && ro == CGAL::COLLINEAR) + collect_needle(q,nvh,nfh,rindex); + + if(p_cdt->is_constrained(re) && !p_cdt->is_constrained(le) + && lo == CGAL::COLLINEAR) collect_needle(q,nvh,nfh,lindex); } @@ -347,207 +634,49 @@ public: return oit; } - template - typename VARR::Face_handle - compute_visibility(const Point_2& q, - const Face_const_handle face, - VARR& out_arr - ){ - //std::cout << "query in face interior" << std::endl; - - out_arr.clear(); - needles.clear(); - assert(!face->is_unbounded()); - - - std::vector raw_output; - typename CDT::Face_handle fh = p_cdt->locate(q); - - raw_output.push_back(fh->vertex(1)->point()); - if(!p_cdt->is_constrained(get_edge(fh,0))){ - //std::cout<< "edge 0 is not constrained" << std::endl; - expand_edge( - q, - fh->vertex(2)->point(), - fh->vertex(1)->point(), - fh,0,std::back_inserter(raw_output)); - } - - raw_output.push_back(fh->vertex(2)->point()); - if(!p_cdt->is_constrained(get_edge(fh,1))){ - //std::cout << "edge 1 is not constrained" << std::endl; - expand_edge( - q, - fh->vertex(0)->point(), - fh->vertex(2)->point(), - fh,1,std::back_inserter(raw_output)); - } - - raw_output.push_back(fh->vertex(0)->point()); - if(!p_cdt->is_constrained(get_edge(fh,2))){ - //std::cout << "edge 2 is not constrained" << std::endl; - expand_edge( - q, - fh->vertex(1)->point(), - fh->vertex(0)->point(), - fh,2,std::back_inserter(raw_output)); - } - - - return output(raw_output,out_arr); - } template typename VARR::Face_handle - compute_visibility(const Point_2& q, - const Halfedge_const_handle he, - VARR& out_arr) { - //std::cout << "visibility_region he" << std::endl; - - assert(!he->face()->is_unbounded()); - out_arr.clear(); - needles.clear(); + output(std::vector& raw_output, VARR& out_arr) const { - std::vector raw_output; - typename CDT::Locate_type location; - int index; - typename CDT::Face_handle fh = p_cdt->locate(q,location,index); - assert(location == CDT::EDGE || location == CDT::VERTEX); - // the following code tries to figure out which triangle one should start in. - - - if(location == CDT::EDGE){ - //std::cout << "query on edge" << std::endl; - // this is the easy part, there are only two possible faces - // index indicates the edge = vertex on the other side of the edge - // the next vertex in cw order should be the target of given edge - if(fh->vertex(p_cdt->cw(index))->point() != he->target()->point()){ - //std::cout << "need to swap face" << std::endl; - // take face on the other side if this is not the case - typename CDT::Face_handle nfh = fh->neighbor(index); - index = nfh->index(fh); - fh = nfh; - } - assert(fh->vertex(p_cdt->cw(index))->point() == he->target()->point()); - assert(!p_cdt->is_infinite(fh->vertex(index))); - - - // output the edge the query lies on - raw_output.push_back(he->source()->point()); - raw_output.push_back(he->target()->point()); - - if(!p_cdt->is_constrained(get_edge(fh,p_cdt->ccw(index)))){ - expand_edge( - q, - fh->vertex(index)->point(), //left - he->target()->point() , //right - fh, - p_cdt->ccw(index), - std::back_inserter(raw_output)); - } - raw_output.push_back(fh->vertex(index)->point()); - - if(!p_cdt->is_constrained(get_edge(fh,p_cdt->cw(index)))){ - expand_edge( - q, - he->source()->point() , //left - fh->vertex(index)->point(), //right - fh, - p_cdt->cw(index), - std::back_inserter(raw_output)); - } - } - - if(location == CDT::VERTEX){ - //std::cout << "query on vertex" << std::endl; - - //bool query_point_on_vertex_is_not_working_yet = false; - //assert(query_point_on_vertex_is_not_working_yet); - - assert(q == he->target()->point()); - assert(fh->vertex(index)->point() == he->target()->point()); - - // push points that are seen anyway - // raw_output.push_back(he->source()->point()); inserted last - raw_output.push_back(he->target()->point()); - raw_output.push_back(he->next()->target()->point()); - - // now start in the triangle that contains he->next() - while( - p_cdt->is_infinite(fh->vertex(p_cdt->ccw(index))) || - he->next()->target()->point() != fh->vertex(p_cdt->ccw(index))->point()){ - typename CDT::Face_handle nfh = fh->neighbor(p_cdt->ccw(index)); - int nindex = nfh->index(fh); - index = p_cdt->ccw(nindex); - fh = nfh; - assert(he->target()->point() == fh->vertex(index)->point()); - } - - - - - assert(he->next()->source()->point() == fh->vertex(index)->point()); - assert(he->next()->target()->point() == fh->vertex(p_cdt->ccw(index))->point()); - assert(!p_cdt->is_infinite(fh)); - assert(p_cdt->is_constrained(get_edge(fh,p_cdt->cw(index)))); - - while(he->source()->point() != fh->vertex(p_cdt->ccw(index))->point()){ - - if(!p_cdt->is_constrained(get_edge(fh,index))){ - expand_edge( - q, - fh->vertex(p_cdt-> cw(index))->point(), //left - fh->vertex(p_cdt->ccw(index))->point(), //right - fh, - index, - std::back_inserter(raw_output)); - } - // push left end point of edge into output - raw_output.push_back(fh->vertex(p_cdt-> cw(index))->point()); - - // take the next triangle around q in ccw order - typename CDT::Face_handle nfh = fh->neighbor(p_cdt->ccw(index)); - int nindex = nfh->index(fh); - index = p_cdt->ccw(nindex); - fh = nfh; - assert(fh->vertex(index)->point() == he->target()->point()); - } - } - return output(raw_output,out_arr); - } - - template - typename VARR::Face_handle - output(std::vector& raw_output, VARR& out_arr){ - - if(needles.size()>0){ + if(!needles.empty()){ std::vector segments(needles.begin(),needles.end()); - for(unsigned int i = 0; i target(); - }else{ - v_last = out_arr.insert_from_right_vertex(Segment_2(raw_output[i], raw_output[i+1]), v_last)->target(); + if(raw_output[i] < raw_output[(i+1)]){ + v_last = out_arr.insert_from_left_vertex ( + Segment_2(raw_output[i], raw_output[i+1]), v_last + )->target(); + } else { + v_last = out_arr.insert_from_right_vertex( + Segment_2(raw_output[i], raw_output[i+1]), v_last + )->target(); } } - out_arr.insert_at_vertices(Segment_2(raw_output.front(),raw_output.back()),v_last,v_first); + out_arr.insert_at_vertices( + Segment_2(raw_output.front(), raw_output.back()), + v_last, v_first + ); } - assert(out_arr.number_of_faces()== 2); + assert(out_arr.number_of_faces() == 2); if(out_arr.faces_begin()->is_unbounded()) return ++out_arr.faces_begin(); @@ -555,20 +684,22 @@ public: return out_arr.faces_begin(); } - void init_cdt(){ + void init_cdt() const { //std::cout<< "==============" < > constraints; - for(typename Arrangement_2::Edge_const_iterator eit = p_arr->edges_begin(); - eit != p_arr->edges_end(); eit++){ - Point_2 source = eit->source()->point(); - Point_2 target = eit->target()->point(); - //std::cout << source << " -- " << target << std::endl; - constraints.push_back(std::make_pair(source,target)); - } + + typedef typename boost::transform_iterator Iter; + + Iter begin = boost::make_transform_iterator(p_arr->edges_begin(), + Make_constraint()); + + Iter end = boost::make_transform_iterator(p_arr->edges_end(), + Make_constraint()); + //std::cout << "init_cdt new CDT" << std::endl; - p_cdt = boost::shared_ptr(new CDT(constraints.begin(),constraints.end())); + p_cdt = boost::shared_ptr(new CDT(begin, end)); + observer.has_changed = false; //std::cout << "init_cdt done" << std::endl; //std::cout << std::endl; } @@ -576,4 +707,4 @@ public: } // namespace CGAL -#endif //CGAL_TRIANGULAR_EXPANSION_VISIBILITY_2__H +#endif // CGAL_TRIANGULAR_EXPANSION_VISIBILITY_2_H diff --git a/Visibility_2/test/Visibility_2/include/CGAL/test_utils.h b/Visibility_2/test/Visibility_2/include/CGAL/test_utils.h index b286deb3749..0e34e282e96 100644 --- a/Visibility_2/test/Visibility_2/include/CGAL/test_utils.h +++ b/Visibility_2/test/Visibility_2/include/CGAL/test_utils.h @@ -333,7 +333,7 @@ bool is_regular_arr(Arrangement_2& arr){ template -bool run_test_case_from_file(Visibility_2 visibility, std::ifstream &input) { +bool run_test_case_from_file(Visibility_2& visibility, std::ifstream &input) { typedef typename Visibility_2::Arrangement_2 Arrangement_2; typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; typedef typename Geometry_traits_2::Point_2 Point_2; @@ -422,8 +422,178 @@ bool run_test_case_from_file(Visibility_2 visibility, std::ifstream &input) { return true; } +template +void test_interface() { + typedef typename Visibility_2::Arrangement_2 Arrangement_2; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Point_2 Point_2; + + Point_2 query(0.1, 0.1); + + std::vector vertices; + vertices.push_back(Point_2(0, 0)); + vertices.push_back(Point_2(1, 0)); + vertices.push_back(Point_2(1, 1)); + vertices.push_back(Point_2(0, 1)); + + + Arrangement_2 arr_out; + Arrangement_2 square; + + for(unsigned int i = 0; i < vertices.size(); ++i) { + CGAL::insert(square, Segment_2(vertices[i], + vertices[(i+1) % vertices.size()])); + } + + Face_const_handle location; + CGAL::assign(location, get_location(square, query)); + + + + const Arrangement_2& arr = square; + + // Constructor and attach method must accept a const arrangement. + Visibility_2 visibility(arr); + + visibility.detach(); + visibility.attach(arr); + + + const Visibility_2& vis = visibility; + + // compute_visibility must be const + vis.compute_visibility(query, location, arr_out); + + Halfedge_const_handle he = arr.edges_begin(); + + if(he->face()->is_unbounded()) + he = he->twin(); + + vis.compute_visibility(he->target()->point(), he, arr_out); + + // must have const arrangement_2(); + const Arrangement_2& a = vis.arrangement_2(); + + // must have const is_attached(); + vis.is_attached(); + + + + +} + +template +void run_tests_with_changes_to_arr() { + + std::cout << "\tTesting changes to attached arrangement:"; + + typedef typename Visibility_2::Arrangement_2 Arrangement_2; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::FT Number_type; + + bool all_passed = true; + + + Point_2 query(0.1, 0.1); + + std::vector vertices; + vertices.push_back(Point_2(0, 0)); + vertices.push_back(Point_2(1, 0)); + vertices.push_back(Point_2(1, 1)); + vertices.push_back(Point_2(0, 1)); + + + Arrangement_2 square; + for(unsigned int i = 0; i < vertices.size(); ++i) { + CGAL::insert(square, Segment_2(vertices[i], + vertices[(i+1) % vertices.size()])); + } + + Arrangement_2 lower_tri; + CGAL::insert(lower_tri, Segment_2(vertices[0], vertices[1])); + CGAL::insert(lower_tri, Segment_2(vertices[1], vertices[3])); + CGAL::insert(lower_tri, Segment_2(vertices[3], vertices[0])); + + Visibility_2 visibility; + Arrangement_2 arr; + Arrangement_2 arr_out; + + // Attach empty arr and fill it afterwards + visibility.attach(arr); + + + for(unsigned int i = 0; i < vertices.size(); ++i) { + CGAL::insert(arr, Segment_2(vertices[i], + vertices[(i+1) % vertices.size()])); + } + + Face_const_handle location; + CGAL::assign(location, get_location(arr, query)); + + visibility.compute_visibility(query, location, arr_out); + + all_passed &= test_are_equal(arr_out, square); + + + // Change attached arrangement and query again + + arr.clear(); + + CGAL::insert(arr, Segment_2(vertices[0], vertices[1])); + CGAL::insert(arr, Segment_2(vertices[1], vertices[3])); + CGAL::insert(arr, Segment_2(vertices[3], vertices[0])); + + CGAL::assign(location, get_location(arr, query)); + + visibility.compute_visibility(query, location, arr_out); + + all_passed &= test_are_equal(arr_out, lower_tri); + + + // Detach and attach again + + visibility.detach(); + visibility.attach(arr); + + CGAL::assign(location, get_location(arr, query)); + + visibility.compute_visibility(query, location, arr_out); + + all_passed &= test_are_equal(arr_out, lower_tri); + + + // Attach another arrangement without detaching the old one first. + + visibility.attach(square); + + CGAL::assign(location, get_location(square, query)); + + visibility.compute_visibility(query, location, arr_out); + + all_passed &= test_are_equal(arr_out, square); + + + if (!all_passed) { + std::cout << "\tFailed: Modifying attached arrangment causes wrong output.\n"; + assert(false); + } else { + std::cout << "\tPassed.\n" ; + } +} + + template void run_tests(int case_number_simple, int case_number_non_simple) { + + // Make sure the code only compiles with a conforming interface + test_interface(); + Visibility_2 visibility; bool one_failed = false; @@ -501,8 +671,12 @@ void run_tests(int case_number_simple, int case_number_non_simple) { if (one_failed) { assert(false); } + + run_tests_with_changes_to_arr(); + } + template void create_arrangement_from_file(_Arrangement_2 &arr, std::ifstream& input) { typedef _Arrangement_2 Arrangement_2; @@ -823,8 +997,8 @@ void simple_benchmark_one_unit( typename Visibility_2_fst::Arrangement_2 &arr, const Query_choice &choice, typename Visibility_2_fst::Arrangement_2::Face_const_handle &fit, - Visibility_2_fst visibility_fst, - Visibility_2_snd visibility_snd, + Visibility_2_fst& visibility_fst, + Visibility_2_snd& visibility_snd, double& qtime1, double& qtime2, int& query_cnt) { @@ -1033,7 +1207,7 @@ void pure_benchmark_one_unit( typename Visibility_2::Arrangement_2 &arr, const Query_choice &choice, typename Visibility_2::Arrangement_2::Face_const_handle &fit, - Visibility_2 visibility, + Visibility_2& visibility, double& qtime, int& query_cnt) { @@ -1215,7 +1389,7 @@ template void test_star_shape_one_face( typename Visibility_2::Arrangement_2 &arr, const Query_choice &choice, typename Visibility_2::Arrangement_2::Face_const_handle &fit, - Visibility_2 visibility) + Visibility_2& visibility) { typedef typename Visibility_2::Arrangement_2 Arrangement_2;