diff --git a/Visibility_2/doc/Visibility_2/CGAL/Preprocessed_rotational_sweep_visibility_2.h b/Visibility_2/doc/Visibility_2/CGAL/Preprocessed_rotational_sweep_visibility_2.h index fceb9ed25d1..747e4324a49 100644 --- a/Visibility_2/doc/Visibility_2/CGAL/Preprocessed_rotational_sweep_visibility_2.h +++ b/Visibility_2/doc/Visibility_2/CGAL/Preprocessed_rotational_sweep_visibility_2.h @@ -54,6 +54,11 @@ public: */ typedef Input_arrangement_2::Halfedge_const_handle Halfedge_const_handle; + /*! + Face_handle type of the output arrangement. + */ + typedef Output_arrangement_2::Face_handle Face_handle; + /// @} @@ -81,7 +86,7 @@ public: /// @{ /*! -Default constructor creates an empty 'Preprocessed_rotational_sweep_visibility_2' object that is not +Default constructor creates an empty `Preprocessed_rotational_sweep_visibility_2` object that is not attached to any arrangement yet. */ Preprocessed_rotational_sweep_visibility_2(); @@ -104,7 +109,7 @@ Returns whether an arrangement is attached to the visibility object /*! Attaches the given arrangement to the visibility object and applies preprocessing. In case the object is already attached to another arrangement, -the visibility object gets detached before being attached to 'arr'. +the visibility object gets detached before being attached to `arr`. */ void attach(const Input_arrangement_2& arr); diff --git a/Visibility_2/doc/Visibility_2/CGAL/Rotational_sweep_visibility_2.h b/Visibility_2/doc/Visibility_2/CGAL/Rotational_sweep_visibility_2.h index aa0a9cb9e03..80c287cc6b9 100644 --- a/Visibility_2/doc/Visibility_2/CGAL/Rotational_sweep_visibility_2.h +++ b/Visibility_2/doc/Visibility_2/CGAL/Rotational_sweep_visibility_2.h @@ -52,6 +52,11 @@ public: */ typedef Input_arrangement_2::Halfedge_const_handle Halfedge_const_handle; + /*! + Face_handle type of the output arrangement. + */ + typedef Output_arrangement_2::Face_handle Face_handle; + /// @} /// \name Tags @@ -76,7 +81,7 @@ public: /// @{ /*! -Default constructor creates an empty 'Rotational_sweep_visibility_2' object that is not +Default constructor creates an empty `Rotational_sweep_visibility_2` object that is not attached to any arrangement yet. */ Rotational_sweep_visibility_2(); @@ -99,7 +104,7 @@ Returns whether an arrangement is attached to the visibility object /*! Attaches the given arrangement to the visibility object. In case the object is already attached to another arrangement, -the visibility object gets detached before being attached to 'arr'. +the visibility object gets detached before being attached to `arr`. */ void attach(const Input_arrangement_2& arr); diff --git a/Visibility_2/doc/Visibility_2/CGAL/Simple_polygon_visibility_2.h b/Visibility_2/doc/Visibility_2/CGAL/Simple_polygon_visibility_2.h index 585ef2d2c34..8a84f509f14 100644 --- a/Visibility_2/doc/Visibility_2/CGAL/Simple_polygon_visibility_2.h +++ b/Visibility_2/doc/Visibility_2/CGAL/Simple_polygon_visibility_2.h @@ -17,12 +17,8 @@ will have at most 2\f$ n \f$ points pushed and popped, thus the time and space c algorithm are \f$ O(n) \f$ even in case of degeneracies such as needles, where n is the number of the vertices of the polygon. -The class offers the option to either compute the visibility region or the visibility polygon, which can be chosen -at compile time via the second template argument RegularizationTag. The default for the RegularizationTag -is ::Tag_false, which implies that the visibility region will be computed. Setting the template argument -to ::Tag_true will produce the output as a visibility polygon. -\tparam Arrangement_2 is the type of input polygonal environment and output visibility polygon. +\tparam Arrangement_2 is the type of input polygonal environment and output visibility region. \tparam RegularizationTag indicates whether the output should be regularized. It can be specified by one of the following: ::Tag_true or ::Tag_false, where ::Tag_false is the default value. @@ -64,6 +60,11 @@ public: Halfedge_const_handle type of input arrangement. */ typedef Input_arrangement_2::Halfedge_const_handle Halfedge_const_handle; + + /*! + Face_handle type of the output arrangement. + */ + typedef Output_arrangement_2::Face_handle Face_handle; /// @} @@ -92,7 +93,7 @@ public: /// @{ /*! -Default constructor creates an empty 'Simple_polygon_visibility_2' object that is not +Default constructor creates an empty `Simple_polygon_visibility_2` object that is not attached to any arrangement yet. */ Simple_polygon_visibility_2(); @@ -115,7 +116,7 @@ Returns whether an arrangement is attached to the visibility object /*! Attaches the given arrangement to the visibility object. In case the object is already attached to another arrangement, -the visibility object gets detached before being attached to 'arr'. +the visibility object gets detached before being attached to `arr`. */ void attach (const Input_arrangement_2& arr); diff --git a/Visibility_2/doc/Visibility_2/CGAL/Triangular_expansion_visibility_2.h b/Visibility_2/doc/Visibility_2/CGAL/Triangular_expansion_visibility_2.h index 4e04503deac..4d9728daf15 100644 --- a/Visibility_2/doc/Visibility_2/CGAL/Triangular_expansion_visibility_2.h +++ b/Visibility_2/doc/Visibility_2/CGAL/Triangular_expansion_visibility_2.h @@ -55,6 +55,11 @@ public: */ typedef Input_arrangement_2::Halfedge_const_handle Halfedge_const_handle; + /*! + Face_handle type of the output arrangement. + */ + typedef Output_arrangement_2::Face_handle Face_handle; + /// @} @@ -82,7 +87,7 @@ public: /// @{ /*! -Default constructor creates an empty 'Triangular_expansion_visibility_2' object that is not +Default constructor creates an empty `Triangular_expansion_visibility_2` object that is not attached to any arrangement yet. */ Triangular_expansion_visibility_2(); @@ -108,7 +113,7 @@ This takes \f$ O(n) \f$ time, where \f$ n \f$ of vertices. Modifying the attache also changes the stored restricted triangulation which in the worst may again take \f$ O(n) \f$ time. In case the object is already attached to another arrangement, -the visibility object gets detached before being attached to 'arr'. +the visibility object gets detached before being attached to `arr`. */ void attach(const Input_arrangement_2& arr); diff --git a/Visibility_2/doc/Visibility_2/Concepts/Visibility_2.h b/Visibility_2/doc/Visibility_2/Concepts/Visibility_2.h index 5ba7cc49cdc..9c5a7762183 100644 --- a/Visibility_2/doc/Visibility_2/Concepts/Visibility_2.h +++ b/Visibility_2/doc/Visibility_2/Concepts/Visibility_2.h @@ -33,7 +33,7 @@ public: typedef Input_arrangement_2::Point_2 Point_2; /*! - * The supported Face handle type of the input arrangement. + * The supported face handle type of the input arrangement. */ typedef Input_arrangement_2::Face_const_handle Face_const_handle; @@ -90,7 +90,7 @@ Returns whether an arrangement is attached to the visibility object /*! Attaches the given arrangement `arr` to the visibility object. In case the object is already attached to another arrangement, -the visibility object gets detached before being attached to 'arr'. +the visibility object gets detached before being attached to `arr`. */ void attach (const Input_arrangement_2& arr); diff --git a/Visibility_2/doc/Visibility_2/fig/general_polygon_example.png b/Visibility_2/doc/Visibility_2/fig/general_polygon_example.png index aed1385f46e..a58448aa65e 100644 Binary files a/Visibility_2/doc/Visibility_2/fig/general_polygon_example.png and b/Visibility_2/doc/Visibility_2/fig/general_polygon_example.png differ diff --git a/Visibility_2/doc/Visibility_2/visibility_2.txt b/Visibility_2/doc/Visibility_2/visibility_2.txt index 8b76f00b511..03abf40f0f9 100644 --- a/Visibility_2/doc/Visibility_2/visibility_2.txt +++ b/Visibility_2/doc/Visibility_2/visibility_2.txt @@ -73,11 +73,12 @@ Two different visibility regions in the example above. \cgalFigureEnd \section general_polygon_example Example of Visibility in a Polygon with Holes -The following example shows how to obtain the regularized visibility region by model `Triangular_expansion_visibility_2`. The query point \f$ q \f$ is on a vertex. -\cgalExample{Visibility_2/general_polygon_example.cpp} +The following example shows how to obtain the regularized visibility region by model `Triangular_expansion_visibility_2`. See \cgalFigureRef{general_polygon}. The arrangement has six bounded faces and an unbounded face. The query point \f$ q \f$ is on a vertex. The red arrow denotes the halfedge \f$ \overrightarrow{pq} \f$, which helps to identify the face in which the visibility region is computed. \cgalFigureBegin{general_polygon, general_polygon_example.png} -The visibility region of \f$ q \f$ in a polygon with hole. +The visibility region of \f$ q \f$ in a polygon with two holes. \cgalFigureEnd +\cgalExample{Visibility_2/general_polygon_example.cpp} + */ diff --git a/Visibility_2/examples/Visibility_2/general_polygon_example.cpp b/Visibility_2/examples/Visibility_2/general_polygon_example.cpp index 51b3f011d47..fe09cac6313 100644 --- a/Visibility_2/examples/Visibility_2/general_polygon_example.cpp +++ b/Visibility_2/examples/Visibility_2/general_polygon_example.cpp @@ -1,12 +1,9 @@ -#include #include #include #include #include -#include -#include #include -#include + #include diff --git a/Visibility_2/include/CGAL/Rotational_sweep_visibility_2.h b/Visibility_2/include/CGAL/Rotational_sweep_visibility_2.h new file mode 100644 index 00000000000..8099457ee14 --- /dev/null +++ b/Visibility_2/include/CGAL/Rotational_sweep_visibility_2.h @@ -0,0 +1,857 @@ +// 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_ROTATIONAL_SWEEP_VISIBILITY_2_H +#define CGAL_ROTATIONAL_SWEEP_VISIBILITY_2_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { + +//debug +template +void print(Point_2 p){ + std::cout< +void print(std::vector ps){ + for (int i=0; i(ps[i]); + } +} + + +template +void print_edges(std::vector es){ + for (int i=0; icurve() << std::endl; + } +} +template +class Rotational_sweep_visibility_2 { +public: + typedef Arrangement_2 Input_arrangement_2; + typedef Arrangement_2 Output_arrangement_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_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::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Face_handle Face_handle; + + 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::Direction_2 Direction_2; + typedef typename Geometry_traits_2::FT Number_type; + typedef typename Geometry_traits_2::Object_2 Object_2; + + typedef RegularizationTag Regularization_tag; + typedef CGAL::Tag_true Supports_general_polygon_tag; + typedef CGAL::Tag_true Supports_simple_polygon_tag; + + enum Intersection_type { UNBOUNDED, CORNER, INNER }; + + Rotational_sweep_visibility_2(): p_arr(NULL) {} + Rotational_sweep_visibility_2(const Input_arrangement_2 &arr): p_arr(&arr) {} + + + Face_handle compute_visibility(const Point_2 &q, const Halfedge_const_handle e, Arrangement_2 &out_arr) { + Arrangement_2 arrc = arr_in ; //copy of arr; + Halfedge_handle ec; //copy of edge; + for (Halfedge_handle eh = arrc.edges_begin(); eh != arrc.edges_end(); eh++) { + if (eh->source()->point() == e-> source()->point() && eh->target()->point() == e->target()->point()) { + ec = eh; + break; + } + } + //print_arrangement(arrc); + //Insert a bounding box; + Number_type xmin, xmax, ymin, ymax; + Point_2 q1 = arrc.vertices_begin()->point(); + xmax = xmin = q1.x(); + ymin = ymax = q1.y(); + for (Vertex_const_handle vh = arrc.vertices_begin(); vh != arrc.vertices_end(); vh++) { + if (vh->point().x() < xmin) + xmin = vh->point().x(); + if (vh->point().x() > xmax) + xmax = vh->point().x(); + if (vh->point().y() < ymin) + ymin = vh->point().y(); + if (vh->point().y() > ymax) + ymax = vh->point().y(); + } + xmin -= 10; + xmax += 10; + ymin -= 10; + ymax += 10; + Point_2 p1(xmin, ymin), p2(xmax, ymin), p3(xmax, ymax), p4(xmin, ymax); + CGAL::insert(arrc, Segment_2(p1, p2)); + CGAL::insert(arrc, Segment_2(p2, p3)); + CGAL::insert(arrc, Segment_2(p3, p4)); + CGAL::insert(arrc, Segment_2(p4, p1)); + + if (ec->target()->point() == q) { + Point_2 source = ec->source()->point(); + Point_2 target = ec->next()->target()->point(); + Halfedge_handle prev = ec->prev(); +// arrc.remove_edge(ec->next()); +// arrc.remove_edge(ec); + + bool check_remove; + do { + check_remove = false; + for (Halfedge_handle eh = arrc.edges_begin(); eh != arrc.edges_end(); eh++) { + if (eh->target()->point() == q || eh->source()->point() == q) { + arrc.remove_edge(eh); + check_remove = true; + break; + } + } + } while (check_remove); + + std::vector polygon; + visibility_region_impl(q, prev->face(), polygon); + //Decide which inside of the visibility butterfly is needed. + int source_i, target_i ; + for (int i = 0; i != polygon.size(); i++) { + if ( polygon[i]== source ) { + source_i = i; + } + else if ( polygon[i] == target ) { + target_i = i; + } + } + int small, big; + if ( source_i < target_i ) { + small = source_i; + big = target_i; + } + else { + small = target_i; + big = source_i; + } + int next_i = small + 1; + bool is_between; + if (CGAL::right_turn(source, q, target)) { + is_between = false; + while (next_i != big) { + if (CGAL::left_turn(source, q, polygon[next_i]) || CGAL::left_turn(q, target, polygon[next_i])) { + is_between = true; + break; + } + next_i ++; + } + } + else { + is_between = true; + while (next_i != big) { + if (CGAL::right_turn(source, q, polygon[next_i]) || CGAL::right_turn(q, target, polygon[next_i])) { + is_between = false; + break; + } + next_i ++; + } + } + typename std::vector::iterator first = polygon.begin() + small; + typename std::vector::iterator last = polygon.begin() + big; + if (is_between) { + std::vector polygon1(first, last+1); + polygon1.push_back(q); + build_arr(polygon1, out_arr); + } + else { + std::vector polygon1(polygon.begin(), first+1); + polygon1.push_back(q); + for (int i = big; i != polygon.size(); i++) { + polygon1.push_back(polygon[i]); + } + build_arr(polygon1, out_arr); + } + + } + else { + Point_2 source = ec->source()->point(); + Point_2 target = ec->target()->point(); + Halfedge_handle eh1 = ec->next(); + arrc.remove_edge(ec); + Face_handle fh = eh1->face(); + std::vector polygon; + visibility_region_impl(q, fh, polygon); + int source_i, target_i; + for (int i = 0; i != polygon.size(); i++) { + if ( polygon[i]== source ) { + source_i = i; + } + else if ( polygon[i] == target ) { + target_i = i; + } + } + int small, big; + if ( source_i < target_i ) { + small = source_i; + big = target_i; + } + else { + small = target_i; + big = source_i; + } + + int next_i = small + 1; + while (CGAL::collinear(source, polygon[next_i], target)) + next_i++; + typename std::vector::iterator first = polygon.begin() + small; + typename std::vector::iterator last = polygon.begin() + big; + if (CGAL::left_turn(source, target, polygon[next_i])) { + std::vector polygon1(first, last+1); + build_arr(polygon1, out_arr); + } + else { + std::vector polygon1(polygon.begin(), first+1); + for (int i = big; i != polygon.size(); i++) { + polygon1.push_back(polygon[i]); + } + build_arr(polygon1, out_arr); + } + + } + conditional_regularize(out_arr, Regularization_tag()); + + if (out_arr.faces_begin()->is_unbounded()) + return ++out_arr.faces_begin(); + else + return out_arr.faces_begin(); + + } + + Face_handle compute_visibility(const Point_2 &q, const Face_const_handle f, Output_arrangement_2 &out_arr) { + out_arr->clear(); + + std::vector polygon; + visibility_region_impl(q, f, polygon); + build_arr(polygon, out_arr); + + conditional_regularize(out_arr, Regularization_tag()); + if (out_arr.faces_begin()->is_unbounded()) + return ++out_arr.faces_begin(); + else + return out_arr.faces_begin(); + } + +bool is_attached() { + return (p_arr != NULL); +} + +void attach(const Input_arrangement_2 &arr) { + p_arr = &arr; +// geom_traits = p_arr->geometry_traits(); +} + +void detach() { + p_arr = NULL; +// geom_traits = NULL; + vertices.clear(); +} + +const Input_arrangement_2& arr() { + return *p_arr; +} + + +private: + //members + typedef std::vector Vend; + const Input_arrangement_2 *p_arr; + bool attach_tag; + std::vector polygon; //visibility polygon + std::map vmap; //vertex and two edges incident to it that might block vision + + + //methods + //compute visibility region between qa and qb + void visibility_region_impl(const Point_2& q, const Point_2& a, const Point_2& b) { + std::vector vertices; //all vertices of the face. + std::vector edges, active_edges; //edges stores all halfedges of the face; and active_edges stores all halfedges that is currently intersected by the view ray. + //preprocess the face + input_face(fh, vertices, edges, q); + + //debug +// for (int i = 0; ipoint()); +// } + + //initiation of vision ray + Vector_2 dir; + if (Direction_2(-1, 0) < Direction_2(Vector_2(q, (*vertices.rbegin())->point()))) + { + dir = Vector_2(1, 0) + Vector_2(q, (*vertices.rbegin())->point()); + } + else { + dir = Vector_2(0, -1); + } + Ray_2 init_vision_ray(q, dir); + //initiation of active_edges + typename std::vector::iterator iter1; + for (iter1 = edges.begin(); iter1 != edges.end(); iter1++) + { + insert_halfedge(active_edges, init_vision_ray, *iter1); + } + + //angular sweep begins + Ray_2 curr_vision_ray = init_vision_ray; + typename std::vector::iterator vit = vertices.begin(), begin_it, end_it; + Halfedge_const_handle closest_edge; + while (vit != vertices.end()) + { + if (active_edges.empty()) + { + begin_it = vit; + end_it = vit; + curr_vision_ray= Ray_2(q, (*begin_it)->point()); + Direction_2 d1(curr_vision_ray), d2; + do { + d2 = Direction_2(Ray_2(q, (*end_it)->point())); + if (d1 != d2) break; + } while (++end_it != vertices.end()); + add_edges(begin_it, end_it, active_edges, curr_vision_ray); + + //since active_edges is empty, that means adding new edges will bring in an unbounded edge to arrangement. + Point_2 p1 = intersection_point(curr_vision_ray, active_edges[0]); + polygon.push_back(p1); +//todo CGAL::insert_curve(out_arr, Ray_2(p1, d1)); + closest_edge = active_edges[0]; + remove_edges(active_edges, curr_vision_ray); + + if (active_edges.empty()) { + //this means there is no edge that intersects curr_vision_ray + //except those collinear ones. + //because one unbounded ray has been inserted before, + //we don't need to do anything here. + } + else { + Point_2 p2 = intersection_point(curr_vision_ray, active_edges[0]); + update_visibility(p2, polygon); + } + } + else { + Point_2 right_p, left_p, mid_p; + begin_it = vit; + end_it = vit; + curr_vision_ray= Ray_2(q, (*begin_it)->point()); + right_p = intersection_point(curr_vision_ray, active_edges[0]); + Direction_2 d1(curr_vision_ray), d2; + //find end_it such that all vertices between begin_it and end_it(not included) are collinear with query point. + do { + d2 = Direction_2(Ray_2(q, (*end_it)->point())); + if (d1 != d2) break; + } while (++end_it != vertices.end()); + add_edges(begin_it, end_it, active_edges, curr_vision_ray); +// std::cout<<"after adding\n"; +// print_edges(active_edges); + mid_p = intersection_point(curr_vision_ray, active_edges[0]); + std::vector collinear_vertices; + Intersection_type i_type = needle(active_edges, curr_vision_ray, collinear_vertices); + switch (i_type) { + case UNBOUNDED : + //todo:this part is not finished. + //remove right and collinear; + remove_edges(active_edges, curr_vision_ray); + update_visibility(right_p, polygon); + update_visibility(mid_p, polygon); + //todo CGAL::insert_curve(); + if (!active_edges.empty()) { + left_p = intersection_point(curr_vision_ray, active_edges[0]); + update_visibility(left_p, polygon); + } + break; + case CORNER : + //remove right and collinear; + remove_edges(active_edges, curr_vision_ray); + +// std::cout<<"after removing\n"; +// print_edges(active_edges); + + left_p = intersection_point(curr_vision_ray, active_edges[0]); + update_visibility(right_p, polygon); + if (right_p == collinear_vertices[0]) { + insert_needle(collinear_vertices, polygon, true); + } + else if (left_p == collinear_vertices[0]) { + insert_needle(collinear_vertices, polygon, false); + } + update_visibility(left_p, polygon); + break; + case INNER : + //remove right and collinear; + remove_edges(active_edges, curr_vision_ray); + if (collinear_vertices.size() < 2) { + //this means mid_p = left_p = right_p = furthest_p. no new vertex is found. + } + else { + //debug +// std::cout<<"print a needle:\n"; +// print(collinear_vertices); +// std::cout<<"the left_p is "<(&result)) { + return *ipoint; + } else + //if result is a segment, return the end closer to the source of ray. + if (const Segment_2 *iseg = CGAL::object_cast(&result)) { + switch (CGAL::compare_distance_to_point(ray.source(), iseg->source(), iseg->target())) { + case (CGAL::SMALLER): + return iseg->source(); + break; + case (CGAL::LARGER) : + return iseg->target(); + break; + } + + } else { + // if no intersection, return the source of ray. + return ray.source(); + } + } + + Point_2 intersection_point(Ray_2 ray, Halfedge_const_handle seg) { + return intersection_point(ray, halfedge2seg(seg)); + } + + //convertor for halfedge to segment + Segment_2 halfedge2seg(Halfedge_const_handle e){ + return Segment_2(e->source()->point(), e->target()->point()); + } + + + //given two edges incident to a vision ray at the same point, find which one is first seen in sweeping. + bool is_closer(const Ray_2 &ray, Halfedge_const_handle seg1, Halfedge_const_handle seg2) { + Point_2 shared = intersection_point(ray, seg1); + Point_2 end1, end2; + if (shared == seg1->source()->point()) + end1 = seg1->target()->point(); + else + end1 = seg1->source()->point(); + + if (shared == seg2->source()->point()) + end2 = seg2->target()->point(); + else + end2 = seg2->source()->point(); + if (CGAL::right_turn(ray.source(), shared, end1) && !CGAL::right_turn(ray.source(), shared, end2)) + return true; + if (CGAL::right_turn(ray.source(), shared, end2) && !CGAL::right_turn(ray.source(), shared, end1)) + return false; + switch (CGAL::orientation(ray.source(), shared, end1)) { + case CGAL::COLLINEAR: + return (CGAL::left_turn(ray.source(), shared, end2)); + case CGAL::RIGHT_TURN: + return (CGAL::right_turn(end1, shared, end2)); + case CGAL::LEFT_TURN: + return (CGAL::left_turn(end1, shared, end2)); + } + } + + //insert newly-discovered edges into active_edges according to its intersection with the view ray. + void insert_halfedge(std::vector &active_edges, const Ray_2 &ray, Halfedge_const_handle edge) + { + Point_2 cross_of_e = intersection_point(ray, edge); + if (cross_of_e != ray.source()) + { + typename std::vector::iterator curr = active_edges.begin(); + while (curr != active_edges.end()) + { + + Point_2 cross_of_curr = intersection_point(ray, *curr); + if (CGAL::compare_distance_to_point(ray.source(), cross_of_e, cross_of_curr) == CGAL::SMALLER) + break; + if (cross_of_curr == cross_of_e && is_closer(ray, edge, *curr)) + break; + ++curr; + } + active_edges.insert(curr, edge); + } + } + + //insert vh into vertices by the angle between ray and positive x-ray. + //if the angles are the same, compare their distances to p. + void sort_vertex(std::vector& vertices, Vertex_const_handle vh, const Point_2& p) + { + typename std::vector::iterator first = vertices.begin(); + Vector_2 vector_of_v(p, vh->point()); + Direction_2 dir_of_v(vector_of_v); + while (first != vertices.end()) + { + if (vh->point() == (*first)->point()) { + return; + } + Vector_2 vector1(p, (*first)->point()); + Direction_2 d1(vector1); + if (dir_of_v < d1) + break; + //if same angles are the same, put the vertex which is closer to query point before. + if (dir_of_v == d1 && CGAL::compare_distance_to_point(p, vh->point(), (*first)->point()) == CGAL::SMALLER) + break; + ++first; + } + vertices.insert(first, vh); + } + + + //traverse the face to get all edges and sort vertices in counter-clockwise order. + void input_face (Face_const_handle fh, + std::vector& vertices, + std::vector& edges, + const Point_2& p) + { + typename Arrangement_2::Ccb_halfedge_const_circulator curr = fh->outer_ccb(); + typename Arrangement_2::Ccb_halfedge_const_circulator circ = curr; + do { + sort_vertex(vertices, curr->source(), p); + edges.push_back(curr); + } while (++curr != circ); + typename Arrangement_2::Hole_const_iterator hi; + for (hi = fh->holes_begin(); hi != fh->holes_end(); ++hi) { + typename Arrangement_2::Ccb_halfedge_const_circulator c1 = *hi, c2 = *hi; + do { + sort_vertex(vertices, c1->source(), p); + edges.push_back(c1); + } while (++c1 != c2); + } + } + + + + + //insert new vertice to polygon. before insertion, check if this vertice has been added before. + void update_visibility(const Point_2 p, std::vector& polygon){ + if (polygon.empty()) + polygon.push_back(p); + else + { + if (polygon.back() != p) { + polygon.push_back(p); + } + } + } + + void insert_needle(const std::vector& points, std::vector& polygon, bool is_right_close){ + if (is_right_close) { + for (int i = 0; i != points.size(); i++) { + update_visibility(points[i], polygon); + } + } + else { + for (int i = points.size()-1; i != -1; i--) { + update_visibility(points[i], polygon); + } + } + } + + + //add a new edge when vision ray passes a vertex + void add_edge(Vertex_const_handle vh, + std::vector& edges, + const Ray_2& r) { + typename Arrangement_2::Halfedge_around_vertex_const_circulator first, curr; + first = curr = vh->incident_halfedges(); + do { + if (!CGAL::right_turn(r.source(), vh->point(), curr->source()->point())) + { + insert_halfedge(edges, r, curr); + } + } while (++curr != first); + + } + //add new edges + void add_edges(typename std::vector::iterator begin_it, + typename std::vector::iterator end_it, + std::vector& edges, + const Ray_2& r) + { + do { + add_edge(*begin_it, edges, r); + } while (++begin_it != end_it); + + } + + //remove edges that are not active any longer + void remove_edges(std::vector& edges, const Ray_2& r) { + typename std::vector::iterator eit = edges.begin(); + while (eit != edges.end()) { + Point_2 p1 = (*eit)->target()->point(); + Point_2 p2 = (*eit)->source()->point(); + bool is_incident(false); + if (is_on_ray(r, p1)) { + is_incident = true; + } + else if (is_on_ray(r, p2)) { + Point_2 tmp = p1; + p1 = p2; + p2 = tmp; + is_incident = true; + } + if ( (is_incident && !CGAL::left_turn(r.source(), p1, p2)) || intersection_point(r, *eit) == r.source() ) + { + eit = edges.erase(eit); + continue; + } + + else { + eit++; + } + } + } + + bool is_on_ray(const Ray_2& r, const Point_2& p) { + return Direction_2(Vector_2(r.source(), p)) == Direction_2(r); + } + //return the type of the needle. + //the vertices on the needle will be saved in collinear_vertices. + Intersection_type needle(std::vector& edges, Ray_2& r, std::vector& collinear_vertices) { + typename std::vector::iterator curr = edges.begin(); +// Point_2 p = r.source(), end1, end2; + Vertex_const_handle vertex1; + //flag shows whether the left side or right side of needle is blocked. + bool block_left, block_right; + do { + Point_2 cross = intersection_point(r, *curr); + if (cross != (*curr)->source()->point() && cross != (*curr)->target()->point()) { + collinear_vertices.push_back(cross); + return INNER; + } + if (CGAL::orientation(r.source(), (*curr)->source()->point(), (*curr)->target()->point()) == CGAL::COLLINEAR) { + if (CGAL::compare_distance_to_point(r.source(), (*curr)->source()->point(), (*curr)->target()->point()) == CGAL::SMALLER) + vertex1 = (*curr)->source(); + else + vertex1 = (*curr)->target(); + } + else { + if (cross == (*curr)->source()->point()) { + vertex1 = (*curr)->source(); + } + else { + vertex1 = (*curr)->target(); + } + } + if (collinear_vertices.empty() || vertex1->point() != collinear_vertices.back()) { + collinear_vertices.push_back(vertex1->point()); + //flag shows whether the left side or right side of current vertex is blocked. + //has_predecessor indicates whether this vertex is incident to an edge whose another end is between the source of ray and it, + //because that will effect the value of block_left, block_right. + bool left_v(false), right_v(false), has_predecessor(false); + + typename Arrangement_2::Halfedge_around_vertex_const_circulator first_edge, curr_edge; + first_edge = curr_edge = vertex1->incident_halfedges(); + do { + switch (CGAL::orientation(r.source(), curr_edge->target()->point(), curr_edge->source()->point())) { + case CGAL::RIGHT_TURN : + right_v = true; + break; + case CGAL::LEFT_TURN : + left_v = true; + break; + case CGAL::COLLINEAR : + if (CGAL::compare_distance_to_point(r.source(), curr_edge->target()->point(), curr_edge->source()->point()) == CGAL::LARGER) { + has_predecessor = true; + } + } + + } while (++curr_edge != first_edge); + if (has_predecessor) { + block_left = block_left || left_v; + block_right = block_right || right_v; + } + else { + block_left = left_v; + block_right = right_v; + } + if (block_left && block_right) { + return CORNER; + } + } + } while (++curr != edges.end()); + return UNBOUNDED; + } + //debug + void print_edges(std::vector& edges){ + for (int i = 0; i != edges.size(); i++) { + Point_2 p1, p2; + p1 = edges[i]->source()->point(); + p2 = edges[i]->target()->point(); + std::cout<"<& polygon) { + for (int i = 0; i != polygon.size(); i++) { + std::cout<& polygon, Arrangement_2& arr ) { + for (int i = 0; i != polygon.size()-1; i++ ) { + CGAL::insert(arr, Segment_2(polygon[i], polygon[i+1])); + } + //print_vectex(polygon); + CGAL::insert(arr, Segment_2(polygon.front(), polygon.back())); + } + + + + + //angular sweep a vertice of face. + void sweep_vertex(std::vector &active_edges, const Point_2 &query, Vertex_const_handle vh, std::vector &polygon ) + { + //closest_edge_copy is a copy of the closest edge to query point in active_edges before sweeping. + Halfedge_const_handle closest_edge_copy = active_edges[0]; + Ray_2 ray(query, vh->point()); + int add_count(0); + int del_count(0); + + //delete all edges in active_edges which is incident to v, because they has been sweeped over + typename std::vector::iterator edge_iter = active_edges.begin(); + while (edge_iter != active_edges.end()) { + if (((*edge_iter)->source()->point() == vh->point()) || ((*edge_iter)->target()->point() == vh->point())) + { + edge_iter = active_edges.erase(edge_iter); + ++del_count; + } + else { + ++edge_iter; + } + } + + //add all edges which is incident to v but not in active_edges before to active_edges + typename Arrangement_2::Halfedge_around_vertex_const_circulator first, curr; + first = curr = vh->incident_halfedges(); + do { + if (CGAL::left_turn(query, vh->point(), curr->source()->point())) + { + insert_halfedge(active_edges, ray, curr); + ++add_count; + } + else if (CGAL::collinear(query, vh->point(), curr->source()->point()) && + CGAL::compare_distance_to_point(query, vh->point(), curr->source()->point()) == CGAL::SMALLER) + { + insert_halfedge(active_edges, ray, curr); + ++add_count; + } + } while (++curr != first); + + //update the visibility region + if (closest_edge_copy != active_edges[0]) { + //when the closest edge changed + if (del_count > 0 && add_count > 0) { + //some edges are added and some are deleted, which means the vertice sweeped is a vertice of visibility polygon. + update_visibility(vh->point(), polygon); + } + if (del_count == 0 && add_count > 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 sweeped. + update_visibility(intersection_point(ray, halfedge2seg(closest_edge_copy)), polygon); + update_visibility(vh->point(), polygon); + } + if (del_count > 0 && add_count == 0) { + //only delete some edges, means some block is moved and the view ray can reach the segments after the block. + update_visibility(vh->point(), polygon); + update_visibility(intersection_point(ray, halfedge2seg(active_edges[0])), polygon); + } + } + + } + + void conditional_regularize(Output_arrangement_2 &out_arr, CGAL::Tag_true) { + regularize_output(out_arr); + } + + void conditional_regularize(Output_arrangement_2 &out_arr, CGAL::Tag_false) { + //do nothing + } + + void regularize_output(Arrangement_2 &out_arr) { + typename Output_arrangement_2::Edge_iterator e_itr; + for (e_itr = out_arr.edges_begin() ; + e_itr != out_arr.edges_end() ; e_itr++) { + Halfedge_handle he = e_itr; + Halfedge_handle he_twin = he->twin(); + if (he->face() == he_twin->face()) { + out_arr.remove_edge(he); + } + } + } + +}; + + +//For debug. Print all edges of arrangements into console. +template +void print_arrangement(const Arrangement_2 &arr) { + typedef typename Arrangement_2::Edge_const_iterator Edge_const_iterator; + Edge_const_iterator eit; + std::cout << arr.number_of_edges() << " edges:" << std::endl; + for (eit = arr.edges_begin(); eit != arr.edges_end(); ++eit) + std::cout << "[" << eit->curve() << "]" << std::endl; +} + +} // end namespace CGAL + + + +#endif + + diff --git a/Visibility_2/include/CGAL/Simple_polygon_visibility_2.h b/Visibility_2/include/CGAL/Simple_polygon_visibility_2.h index 6154d355c23..5b10a8421a8 100644 --- a/Visibility_2/include/CGAL/Simple_polygon_visibility_2.h +++ b/Visibility_2/include/CGAL/Simple_polygon_visibility_2.h @@ -66,7 +66,7 @@ public: Simple_polygon_visibility_2(const Input_arrangement_2 &arr): p_arr(&arr) { geom_traits = p_arr->geometry_traits(); - }; + } bool is_attached() { return (p_arr != NULL); diff --git a/Visibility_2/include/CGAL/Simple_polygon_visibility_2_.h b/Visibility_2/include/CGAL/Simple_polygon_visibility_2_.h new file mode 100644 index 00000000000..c318d1a869a --- /dev/null +++ b/Visibility_2/include/CGAL/Simple_polygon_visibility_2_.h @@ -0,0 +1,661 @@ +// 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): Francisc Bungiu +// Michael Hemmer + +#ifndef CGAL_SIMPLE_POLYGON_VISIBILITY_2__H +#define CGAL_SIMPLE_POLYGON_VISIBILITY_2__H + +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { + +template +class Simple_polygon_visibility_2_ { + +public: + // Currently only consider with same type for both + typedef Arrangement_2 Input_arrangement_2; + typedef Arrangement_2 Output_arrangement_2; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + + 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::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Face_handle Face_handle; + + 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::Direction_2 Direction_2; + typedef typename Geometry_traits_2::FT Number_type; + typedef typename Geometry_traits_2::Object_2 Object_2; + + typedef RegularizationTag Regularization_tag; + typedef CGAL::Tag_false Supports_general_polygon_tag; + typedef CGAL::Tag_true Supports_simple_polygon_tag; + + Simple_polygon_visibility_2_() : p_arr(NULL), geom_traits(NULL) {}; + + /*! Constructor given an arrangement and the Regularization tag. */ + Simple_polygon_visibility_2_(const Input_arrangement_2 &arr): + p_arr(&arr) { + geom_traits = p_arr->geometry_traits(); + }; + + bool is_attached() { + return (p_arr != NULL); + } + + void attach(const Input_arrangement_2 &arr) { + p_arr = &arr; + geom_traits = p_arr->geometry_traits(); + } + + void detach() { + p_arr = NULL; + geom_traits = NULL; + vertices.clear(); + } + + const Input_arrangement_2& arr() { + return *p_arr; + } + + Face_handle compute_visibility(Point_2 &q, const Face_const_handle face, + Output_arrangement_2 &out_arr) { + + CGAL::Visibility_2::print_arrangement_by_face(*p_arr); + + typename Input_arrangement_2::Ccb_halfedge_const_circulator circ = + face->outer_ccb(); + typename Input_arrangement_2::Ccb_halfedge_const_circulator curr = circ; + typename Input_arrangement_2::Halfedge_const_handle he = curr; + + std::vector temp_vertices; + Point_2 min_intersect_pt; + bool intersect_on_endpoint = false; + Segment_2 curr_edge(he->source()->point(), he->target()->point()); + Segment_2 curr_min_edge(he->source()->point(), he->target()->point()); + Point_2 curr_vertex = he->target()->point(); + temp_vertices.push_back(curr_vertex); + Number_type min_dist = CGAL::Visibility_2::Compute_squared_distance_2 + (geom_traits, q, curr_edge); + int min_dist_index = 0; + int index = 1; + curr++; + // Push all vertices and determine edge minimum in terms + // of squared distance to query point + do { + he = curr; + curr_edge = Segment_2(he->source()->point(), he->target()->point()); + Number_type curr_dist = CGAL::Visibility_2::Compute_squared_distance_2 + (geom_traits, q, curr_edge); + + if (curr_dist < min_dist) { + min_dist = curr_dist; + min_dist_index = index; + curr_min_edge = curr_edge; + } + temp_vertices.push_back(he->target()->point()); + index++; + } while (++curr != circ); + + // Only now compute the intersection point + min_intersect_pt = CGAL::Visibility_2::Construct_projected_point_2 + (geom_traits, curr_min_edge, q); + + bool intersect_pt_on_seg_endpoint = false; + if (min_intersect_pt != curr_min_edge.source() && + min_intersect_pt != curr_min_edge.target()) { + vertices.push_back(min_intersect_pt); + } + else { + intersect_pt_on_seg_endpoint = true; + } + // Now create vector so that first vertex v0 is visible + for (unsigned int k = min_dist_index ; k < temp_vertices.size() ; k++) { + vertices.push_back(temp_vertices[k]); + } + for (unsigned int k = 0 ; k < min_dist_index ; k++) { + vertices.push_back(temp_vertices[k]); + } + + // Push first vertex again to fulfill algo precondition + if (min_intersect_pt != curr_min_edge.source() && + min_intersect_pt != curr_min_edge.target()) { + vertices.push_back(min_intersect_pt); + } + else { + vertices.push_back(vertices[0]); + } + std::cout << "******VERTICES***************\n"; + for (unsigned int i = 0 ; i < vertices.size() ; i++) { + std::cout << vertices[i] << std::endl; + } + std::cout << "*********************\n"; + + compute_angular_displacement(q); + print_angular_displacement(); + visibility_region_impl(q); + + typename std::vector points; + if (!s.empty()) { + Point_2 prev_pt = s.top(); + if (prev_pt == min_intersect_pt) { + if (intersect_pt_on_seg_endpoint) { + points.push_back(prev_pt); + } + s.pop(); + if (!s.empty()) { + prev_pt = s.top(); + points.push_back(prev_pt); + } + } + if (!s.empty()) { + s.pop(); + } + while(!s.empty()) { + Point_2 curr_pt = s.top(); + if (curr_pt == min_intersect_pt) { + if (intersect_pt_on_seg_endpoint) { + points.push_back(curr_pt); + } + s.pop(); + } + else { + points.push_back(curr_pt); + prev_pt = curr_pt; + s.pop(); + } + } + } + + std::reverse(points.begin(), points.end()); + std::cout << "POINTS\n"; + for (unsigned int k = 0 ; k < points.size() ; k++) { + std::cout << points[k] << std::endl; + } + std::cout << "END POINTS\n"; + CGAL::Visibility_2::report_while_handling_needles + (geom_traits, + q, + points, + out_arr); + std::cout << "OUTPUT\n"; + CGAL::Visibility_2::print_arrangement_by_face(out_arr); + std::cout << "END OUTPUT\n"; + CGAL_precondition(out_arr.number_of_isolated_vertices() == 0); + CGAL_precondition(s.size() == 0); + conditional_regularize(out_arr, Regularization_tag()); + vertices.clear(); + if (out_arr.faces_begin()->is_unbounded()) { + return ++out_arr.faces_begin(); + } + else { + return out_arr.faces_begin(); + } + } + + Face_handle compute_visibility(const Point_2 &q, const Halfedge_const_handle he, + Output_arrangement_2 &out_arr ) { +/* + query_pt_is_vertex = false; + if (q != he->source()->point()) { + if (q != he->target()->point()) { + vertices.push_back(q); + vertices.push_back(he->target()->point()); + } + else { + vertices.push_back(q); + query_pt_is_vertex = true; + } + } + + typename Input_arrangement_2::Face_const_handle face = he->face(); + typename Input_arrangement_2::Ccb_halfedge_const_circulator circ = + face->outer_ccb(); + typename Input_arrangement_2::Ccb_halfedge_const_circulator curr; + typename Input_arrangement_2::Halfedge_const_handle he_handle = circ; + + while (he_handle != he) { + circ++; + he_handle = circ; + } + circ++; + curr = circ; + do { + he_handle = curr; + Point_2 curr_vertex = he_handle->target()->point(); + vertices.push_back(curr_vertex); + } while (++curr != circ); + + vertices.pop_back(); + vertices.push_back(vertices[0]); + std::cout << "******VERTICES***************\n"; + for (unsigned int i = 0 ; i < vertices.size() ; i++) { + std::cout << vertices[i] << std::endl; + } + std::cout << "*********************\n"; + + visibility_region_impl(q); + + std::cout << "STACK\n"; + while (!s.empty()) { + std::cout << s.top() << std::endl; + s.pop(); + } + std::cout << "END STACK\n"; + + 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::reverse(points.begin(), points.end()); + + std::cout << "POINTS\n"; + for (unsigned int i = 0 ; i < points.size() ; i++) { + std::cout << points[i] << std::endl; + } + std::cout << "*****************\n"; + 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_tag()); + vertices.clear(); +// CGAL::Visibility_2::print_arrangement_by_face(out_arr); + if (out_arr.faces_begin()->is_unbounded()) { + return ++out_arr.faces_begin(); + } + else { + return out_arr.faces_begin(); + }*/ + } + +private: + const Input_arrangement_2 *p_arr; + const Geometry_traits_2 *geom_traits; + std::stack s; + std::vector vertices; + std::map angular_displacement; + std::pair angular_displacement_vn; + enum {ADVANCE, SCAN, RETARD, FINISH} upcase; + enum {RAY, SEGMENT} polar_mode; + + bool do_overlap(const Point_2 &a, const Point_2 &b, const Point_2 &c) { + if (CGAL::Visibility_2::Collinear(geom_traits, a, b, c)) { + Segment_2 s1(a, b); + Segment_2 s2(a, c); + const Segment_2 *seg_overlap; + Object_2 result = CGAL::Visibility_2::Intersect_2 + (geom_traits, s1, s2); + if (seg_overlap = CGAL::object_cast(&result)) { + return true; + } + } + return false; + } + + void conditional_regularize(Output_arrangement_2 &out_arr, CGAL::Tag_true) { + regularize_output(out_arr); + } + + void conditional_regularize(Output_arrangement_2 &out_arr, CGAL::Tag_false) { + //do nothing + } + + double angle(const Point_2 &r, const Point_2 &p, const Point_2 &q) { + + } + + void compute_angular_displacement(const Point_2 &q) { + + Point_2 v0 = vertices[0]; + angular_displacement.insert(std::pair(v0, 0)); + + for (unsigned int k = 1 ; k < vertices.size() ; k++) { + Vector_2 vec1(vertices[k-1].x() - q.x(), vertices[k-1].y() - q.y()); + Vector_2 vec2(vertices[k].x() - q.x(), vertices[k].y() - q.y()); + Number_type scalar_prod = vec1*vec2; + Number_type len1 = vec1.squared_length(); + Number_type len2 = vec2.squared_length(); + double angle = acos(CGAL::to_double(scalar_prod)/ + sqrt(CGAL::to_double(len1*len2))); + switch(CGAL::Visibility_2::Orientation_2(geom_traits, + q, + vertices[k-1], + vertices[k])) { + case CGAL::LEFT_TURN: + if (k == vertices.size() - 1) { + angular_displacement_vn = std::make_pair(vertices[k], + angular_displacement[vertices[k-1]] + angle); + } + else { + angular_displacement.insert(std::pair(vertices[k], + angular_displacement[vertices[k-1]] + angle)); + } + break; + case CGAL::RIGHT_TURN: + if (k == vertices.size() - 1) { + angular_displacement_vn = std::make_pair(vertices[k], + angular_displacement[vertices[k-1]] - angle); + } + else { + angular_displacement.insert(std::pair(vertices[k], + angular_displacement[vertices[k-1]] - angle)); + } + break; + case CGAL::COLLINEAR: + if (k == vertices.size() - 1) { + angular_displacement_vn = std::make_pair(vertices[k], + angular_displacement[vertices[k-1]]); + } + else { + angular_displacement.insert(std::pair(vertices[k], + angular_displacement[vertices[k-1]])); + } + break; + } + } + } + + double get_angular_displacement(const Point_2 &pt, const int i) { + if (i == vertices.size() - 1) { + return angular_displacement_vn.second; + } + else { + return angular_displacement[pt]; + } + } + + void print_angular_displacement() { + typename std::map::iterator it = angular_displacement.begin(); + for (it ; it != angular_displacement.end() ; it++) { + std::cout << it->first << " - " << it->second << std::endl; + } + std::cout << angular_displacement_vn.first << " - " + << angular_displacement_vn.second << std::endl; + } + + void regularize_output(Output_arrangement_2 &out_arr) { + typename Output_arrangement_2::Edge_iterator e_itr; + for (e_itr = out_arr.edges_begin() ; + e_itr != out_arr.edges_end() ; e_itr++) { + + Halfedge_handle he = e_itr; + Halfedge_handle he_twin = he->twin(); + if (he->face() == he_twin->face()) { + out_arr.remove_edge(he); + } + } + } + + void visibility_region_impl(const Point_2 &q) { + + int i = 0; + Point_2 w; + + bool ccw = false; + s.push(vertices[0]); + if (angular_displacement[vertices[1]] >= angular_displacement[vertices[0]]){ + upcase = ADVANCE; + } + else { + upcase = SCAN; + ccw = true; + w = Point_2(vertices[0]); + polar_mode = RAY; + } + while (upcase != FINISH) { + switch(upcase) { + case ADVANCE: + advance(q, i, ccw, w); + break; + case RETARD: + retard(q, i, ccw, w); + break; + case SCAN: + scan(q, i, ccw, w); + break; + } + } + } + + void advance(const Point_2 &q, int &i, bool &ccw, Point_2 &w) { + + while (upcase == ADVANCE) { + + if (get_angular_displacement(vertices[i+1], i+1) <= 2*CGAL_PI) { + i++; + s.push(vertices[i]); + + if (i == vertices.size()-1) { + upcase = FINISH; + } + else if (get_angular_displacement(vertices[i+1], i+1) < get_angular_displacement(vertices[i], i) + && CGAL::Visibility_2::Orientation_2(geom_traits, + vertices[i-1], + vertices[i], + vertices[i+1]) == CGAL::RIGHT_TURN) { + upcase = SCAN; + ccw = true; + w = Point_2(vertices[i]); + polar_mode = RAY; + } + else if (get_angular_displacement(vertices[i+1], i+1) < get_angular_displacement(vertices[i], i) + && CGAL::Visibility_2::Orientation_2(geom_traits, + vertices[i-1], + vertices[i], + vertices[i+1]) == CGAL::LEFT_TURN) { + upcase = RETARD; + } + } + else { + if (angular_displacement[s.top()] < 2*CGAL_PI) { + // Compute intersection of v[i]v[i+1] and line qv[0] + Segment_2 seg(vertices[i], vertices[i+1]); + Ray_2 ray(q, vertices[0]); + Object_2 result = CGAL::Visibility_2::Intersect_2 + (geom_traits, seg, ray); + if (const Point_2 *ipoint = CGAL::object_cast(&result)) { + s.push(*ipoint); + angular_displacement.insert(std::make_pair(*ipoint, 2*CGAL_PI)); + } + } + upcase = SCAN; + ccw = false; + w = vertices[0]; + polar_mode = SEGMENT; + } + } + } + + void retard(const Point_2 &q, int &i, bool &ccw, Point_2 &w) { + + while (upcase == RETARD && !s.empty()) { + + Point_2 s_j_prev = s.top(); + + if (!s.empty()) { + s.pop(); + Point_2 s_j = s.top(); + + if (angular_displacement[s_j] < get_angular_displacement(vertices[i+1], i+1) + && get_angular_displacement(vertices[i+1], i+1) > angular_displacement[s_j]) { + + i++; + // Compute intersection of s[j]s[j+1] and line qv[i] + Segment_2 seg(s_j, s_j_prev); + Ray_2 ray(q, vertices[i]); + Object_2 result = CGAL::Visibility_2::Intersect_2 + (geom_traits, seg, ray); + + if (const Point_2 *ipoint = CGAL::object_cast(&result)) { + + angular_displacement.insert(std::pair(*ipoint, CGAL::to_double(2*CGAL_PI))); + s.push(*ipoint); + } + s.push(vertices[i]); + if (i == vertices.size() - 1) { + upcase = FINISH; + } + else if (get_angular_displacement(vertices[i], i) <= get_angular_displacement(vertices[i+1], i+1) + && CGAL::Visibility_2::Orientation_2(geom_traits, + vertices[i-1], + vertices[i], + vertices[i+1]) == CGAL::RIGHT_TURN) { + + upcase = ADVANCE; + } + else if (get_angular_displacement(vertices[i], i) < get_angular_displacement(vertices[i+1], i+1) + && CGAL::Visibility_2::Orientation_2(geom_traits, + vertices[i-1], + vertices[i], + vertices[i+1]) == CGAL::LEFT_TURN) { + + upcase = SCAN; + ccw = false; + w = vertices[i]; + polar_mode = SEGMENT; + s.pop(); + } + else { + s.pop(); + } + } + else { + + if (get_angular_displacement(vertices[i+1], i+1) == angular_displacement[s_j] + && get_angular_displacement(vertices[i+2], i+2) > get_angular_displacement(vertices[i+1], i+1) + && CGAL::Visibility_2::Orientation_2(geom_traits, + vertices[i], + vertices[i+1], + vertices[i+2]) == CGAL::RIGHT_TURN) { + upcase = ADVANCE; + i++; + s.push(vertices[i]); + } + else { + Segment_2 seg_fst(vertices[i], vertices[i+1]); + Segment_2 seg_snd(s_j, s_j_prev); + Object_2 result = CGAL::Visibility_2::Intersect_2 + (geom_traits, seg_fst, seg_snd); + + if (const Point_2 *ipoint = CGAL::object_cast(&result)) { + w = *ipoint; + polar_mode = SEGMENT; + upcase = SCAN; + ccw = true; + } + } + } + } + } + } + + void scan(const Point_2 &q, int &i, bool &ccw, Point_2 &w) { + + while (upcase == SCAN && i < vertices.size()-2) { + i++; + + if (ccw && get_angular_displacement(vertices[i+1], i+1) > angular_displacement[s.top()] + && angular_displacement[s.top()] >= get_angular_displacement(vertices[i], i)) { + + Segment_2 seg(vertices[i], vertices[i+1]); + if (polar_mode == RAY) { + Ray_2 w_ray(q, w); + Object_2 result = CGAL::Visibility_2::Intersect_2 + (geom_traits, seg, w_ray); + if (const Point_2 *ipoint = CGAL::object_cast(&result)) { + upcase = ADVANCE; + s.push(*ipoint); + } + } + else { + Segment_2 w_seg(s.top(), w); + Object_2 result = CGAL::Visibility_2::Intersect_2 + (geom_traits, seg, w_seg); + if (const Point_2 *ipoint = CGAL::object_cast(&result)) { + upcase = ADVANCE; + s.push(*ipoint); + } + } + } + else if (!ccw && get_angular_displacement(vertices[i+1], i+1) <= angular_displacement[s.top()] + && angular_displacement[s.top()] < get_angular_displacement(vertices[i], i)) { + + Segment_2 seg(vertices[i], vertices[i+1]); + if (polar_mode == RAY) { + Ray_2 w_ray(q, w); + Object_2 result = CGAL::Visibility_2::Intersect_2 + (geom_traits, seg, w_ray); + if (const Point_2 *ipoint = CGAL::object_cast(&result)) { + upcase = RETARD; + } + } + else { + Segment_2 w_seg(s.top(), w); + Object_2 result = CGAL::Visibility_2::Intersect_2 + (geom_traits, seg, w_seg); + if (const Point_2 *ipoint = CGAL::object_cast(&result)) { + upcase = RETARD; + } + } + } + } + } +}; +} // namespace CGAL + +#endif diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_11.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_11.dat new file mode 100644 index 00000000000..d541a8e3189 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_11.dat @@ -0,0 +1,23 @@ +# Test case 10 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +8 2 +8 2 + +0 +7 +0 0 14 0 +14 0 14 7 +14 7 7 7 +7 7 6 4 +6 4 6 2 +6 2 0 2 +0 2 0 0 + +0 +7 +0 0 14 0 +14 0 14 7 +14 7 7 7 +7 7 6 4 +6 4 6 2 +6 2 0 2 +0 2 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_12.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_12.dat new file mode 100644 index 00000000000..50293f02a44 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_12.dat @@ -0,0 +1,27 @@ +# Test case 10 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +8 2 +8 2 + +0 +9 +0 0 8 0 +8 0 12 4 +12 4 14 0 +14 0 14 7 +14 7 7 7 +7 7 6 4 +6 4 6 2 +6 2 0 2 +0 2 0 0 + +0 +9 +0 0 8 0 +8 0 12 4 +12 4 14 5 +14 5 14 7 +14 7 7 7 +7 7 6 4 +6 4 6 2 +6 2 0 2 +0 2 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_13.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_13.dat new file mode 100644 index 00000000000..89a50356237 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_13.dat @@ -0,0 +1,26 @@ +# Test case 10 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +5 2 +5 2 + +0 +11 +0 0 12 0 +12 0 12 4 +12 4 8 7 +8 7 11 9 +11 9 11 12 +11 12 6 9 +6 9 0 12 +0 12 0 10 +0 10 8 5 +8 5 0 5 +0 5 0 0 + +0 +6 +0 0 12 0 +12 0 12 4 +12 4 64/7 43/7 +64/7 43/7 8 5 +8 5 0 5 +0 5 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_14.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_14.dat new file mode 100644 index 00000000000..1f3f06be81f --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_14.dat @@ -0,0 +1,26 @@ +# Test case 10 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +2 3 +2 3 + +0 +10 +0 0 8 0 +8 0 10 3 +10 3 10 6 +10 6 9 4 +9 4 8 6 +8 6 8 2 +8 2 6 3 +6 3 6 7 +6 7 0 7 +0 7 0 0 + +0 +7 +0 0 8 0 +8 0 46/5 9/5 +46/5 9/5 8 2 +8 2 6 3 +6 3 6 7 +6 7 0 7 +0 7 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_15.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_15.dat new file mode 100644 index 00000000000..f5e0a064fa7 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_15.dat @@ -0,0 +1,21 @@ +# Test case 15 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +5 4 +5 4 + +0 +6 +0 0 8 0 +8 0 8 8 +8 8 3 8 +3 8 3 4 +3 4 0 6 +0 6 0 0 + +0 +6 +0 0 8 0 +8 0 8 8 +8 8 3 8 +3 8 3 4 +3 4 0 4 +0 4 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_16.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_16.dat new file mode 100644 index 00000000000..1a22709c2e5 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_16.dat @@ -0,0 +1,22 @@ +# Test case 16 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +3 3 +3 3 + +0 +7 +0 0 12 0 +12 0 12 3 +12 3 9 5 +9 5 6 3 +6 3 3 5 +3 5 0 3 +0 3 0 0 + +0 +6 +0 0 12 0 +12 0 12 3 +12 3 6 3 +6 3 3 5 +3 5 0 3 +0 3 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_17.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_17.dat new file mode 100644 index 00000000000..5f58092bdda --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_17.dat @@ -0,0 +1,24 @@ +# Test case 17 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +2 3 +2 3 + +0 +8 +0 0 12 0 +12 0 12 3 +12 3 9 5 +9 5 6 3 +6 3 4 3 +4 3 2 6 +2 6 0 3 +0 3 0 0 + +0 +7 +0 0 12 0 +12 0 12 3 +12 3 6 3 +6 3 4 3 +4 3 2 6 +2 6 0 3 +0 3 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/test_simple_visibility.cpp b/Visibility_2/test/Visibility_2/test_simple_visibility.cpp index 970a570f225..73fdc551f26 100644 --- a/Visibility_2/test/Visibility_2/test_simple_visibility.cpp +++ b/Visibility_2/test/Visibility_2/test_simple_visibility.cpp @@ -27,7 +27,8 @@ #include #include #include -#include +//#include +#include #include #include @@ -40,15 +41,15 @@ int main() { typedef Traits_2::Point_2 Point_2; typedef Traits_2::X_monotone_curve_2 Segment_2; typedef CGAL::Arrangement_2 Arrangement_2; - typedef CGAL::Simple_polygon_visibility_2 + typedef CGAL::Simple_polygon_visibility_2_ Simple_polygon_visibility_2; std::cout << "Running model tests - "; - CGAL::test_model_methods(); +// CGAL::test_model_methods(); std::cout << GREEN << "Done!" << RESET << std::endl; std::cout << "Running test suite with " << GREEN << "Cartesian" << RESET << " Kernel..." << std::endl; - CGAL::run_tests(10, 2); -} + CGAL::run_tests(17, 0); +}/* { typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Arr_segment_traits_2 Traits_2; @@ -63,6 +64,6 @@ int main() { std::cout << "Running test suite with " << GREEN << "EPECK" << RESET << " Kernel..." << std::endl; CGAL::run_tests(10, 2); -} +}*/ return 0; }