Merge branch 'gsoc2013-Visibility_doc-hemmer' of ssh://scm.cgal.org/var/git/cgal-gsoc into gsoc2013-Visibility_doc-hemmer

This commit is contained in:
Michael Hemmer 2013-08-22 09:33:16 +02:00
commit 6bd60ece3a
19 changed files with 1731 additions and 29 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -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}
*/

View File

@ -1,12 +1,9 @@
#include <CGAL/basic.h>
#include <CGAL/Cartesian.h>
#include <CGAL/Gmpq.h>
#include <CGAL/Arr_segment_traits_2.h>
#include <CGAL/Arrangement_2.h>
#include <CGAL/test_model_methods.h>
#include <CGAL/test_utils.h>
#include <CGAL/Triangular_expansion_visibility_2_.h>
#include <CGAL/test_utils.h>
#include <iostream>

View File

@ -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 <huangkandiy@gmail.com>
#ifndef CGAL_ROTATIONAL_SWEEP_VISIBILITY_2_H
#define CGAL_ROTATIONAL_SWEEP_VISIBILITY_2_H
#include <iostream>
#include <vector>
#include <map>
#include <CGAL/Arrangement_2.h>
#include <CGAL/Direction_2.h>
#include <CGAL/Vector_2.h>
#include <CGAL/intersections.h>
#include <CGAL/Ray_2.h>
#include <CGAL/tags.h>
#include <CGAL/enum.h>
namespace CGAL {
//debug
template<typename Point_2>
void print(Point_2 p){
std::cout<<p.x()<<","<< p.y()<<std::endl;
}
template<typename Point_2>
void print(std::vector<Point_2> ps){
for (int i=0; i<ps.size(); i++)
{
print<Point_2>(ps[i]);
}
}
template<typename Halfedge_handle>
void print_edges(std::vector<Halfedge_handle> es){
for (int i=0; i<es.size(); i++)
{
std::cout << es->curve() << std::endl;
}
}
template <typename Arrangement_2, typename RegularizationTag>
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<Point_2> 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<Point_2>::iterator first = polygon.begin() + small;
typename std::vector<Point_2>::iterator last = polygon.begin() + big;
if (is_between) {
std::vector<Point_2> polygon1(first, last+1);
polygon1.push_back(q);
build_arr(polygon1, out_arr);
}
else {
std::vector<Point_2> 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<Point_2> 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<Point_2>::iterator first = polygon.begin() + small;
typename std::vector<Point_2>::iterator last = polygon.begin() + big;
if (CGAL::left_turn(source, target, polygon[next_i])) {
std::vector<Point_2> polygon1(first, last+1);
build_arr(polygon1, out_arr);
}
else {
std::vector<Point_2> 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<Point_2> 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<Point_2> Vend;
const Input_arrangement_2 *p_arr;
bool attach_tag;
std::vector<Point_2> polygon; //visibility polygon
std::map<Point_2, Vend> 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<Vertex_const_handle> vertices; //all vertices of the face.
std::vector<Halfedge_const_handle> 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; i<vertices.size(); i++) {
// print(vertices[i]->point());
// }
//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<Halfedge_const_handle>::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<Vertex_const_handle>::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<Point_2> 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 "<<left_p.x()<<' '<<left_p.y()<<std::endl;
// std::cout<<"the right_p is "<<right_p.x()<<' '<<right_p.y()<<std::endl;
// std::cout<<"the front_p is "<<collinear_vertices[0].x()<<' '<<collinear_vertices[0].y()<<std::endl;
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;
}
}
vit = end_it;
}
}
Point_2 intersection_point(Ray_2 ray, Segment_2 seg )
{
CGAL::Object result = CGAL::intersection(ray, seg);
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&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<Segment_2 >(&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<Halfedge_const_handle> &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<Halfedge_const_handle>::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<p, vh> and positive x-ray.
//if the angles are the same, compare their distances to p.
void sort_vertex(std::vector<Vertex_const_handle>& vertices, Vertex_const_handle vh, const Point_2& p)
{
typename std::vector<Vertex_const_handle>::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<Vertex_const_handle>& vertices,
std::vector<Halfedge_const_handle>& 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<Point_2>& polygon){
if (polygon.empty())
polygon.push_back(p);
else
{
if (polygon.back() != p) {
polygon.push_back(p);
}
}
}
void insert_needle(const std::vector<Point_2>& points, std::vector<Point_2>& 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<Halfedge_const_handle>& 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<Vertex_const_handle>::iterator begin_it,
typename std::vector<Vertex_const_handle>::iterator end_it,
std::vector<Halfedge_const_handle>& 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<Halfedge_const_handle>& edges, const Ray_2& r) {
typename std::vector<Halfedge_const_handle>::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<Halfedge_const_handle>& edges, Ray_2& r, std::vector<Point_2>& collinear_vertices) {
typename std::vector<Halfedge_const_handle>::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<Halfedge_const_handle>& 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<<p1<<"->"<<p2<<std::endl;
}
}
void print_vertex(const std::vector<Point_2>& polygon) {
for (int i = 0; i != polygon.size(); i++) {
std::cout<<polygon[i]<<std::endl;
}
}
void build_arr(const std::vector<Point_2>& 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<Halfedge_const_handle> &active_edges, const Point_2 &query, Vertex_const_handle vh, std::vector<Point_2> &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<Halfedge_const_handle>::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 <typename Arrangement_2>
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

View File

@ -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);

View File

@ -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 <fbungiu@gmail.com>
// Michael Hemmer <michael.hemmer@cgal.org>
#ifndef CGAL_SIMPLE_POLYGON_VISIBILITY_2__H
#define CGAL_SIMPLE_POLYGON_VISIBILITY_2__H
#include <CGAL/Arrangement_2.h>
#include <CGAL/rational_rotation.h>
#include <CGAL/tags.h>
#include <CGAL/enum.h>
#include <CGAL/Visibility_2/visibility_utils.h>
#include <stack>
#include <map>
namespace CGAL {
template<class Arrangement_2, class RegularizationTag>
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<Input_arrangement_2>(*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<Point_2> 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
<Geometry_traits_2, Point_2, Segment_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
<Geometry_traits_2, Point_2, Segment_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
<Geometry_traits_2, Segment_2, 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<Point_2> 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
<Simple_polygon_visibility_2_>(geom_traits,
q,
points,
out_arr);
std::cout << "OUTPUT\n";
CGAL::Visibility_2::print_arrangement_by_face<Output_arrangement_2>(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<Point_2> 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
<Simple_polygon_visibility_2>(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<Output_arrangement_2>(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<Point_2> s;
std::vector<Point_2> vertices;
std::map<Point_2, double> angular_displacement;
std::pair<Point_2, double> 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
<Geometry_traits_2, Segment_2, Segment_2>(geom_traits, s1, s2);
if (seg_overlap = CGAL::object_cast<Segment_2>(&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<Point_2, double>(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<Point_2, double>(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<Point_2, double>(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<Point_2, double>(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<Point_2, double>::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
<Geometry_traits_2, Segment_2, Ray_2>(geom_traits, seg, ray);
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&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
<Geometry_traits_2, Segment_2, Ray_2>(geom_traits, seg, ray);
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
angular_displacement.insert(std::pair<Point_2, double>(*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
<Geometry_traits_2, Segment_2, Segment_2>(geom_traits, seg_fst, seg_snd);
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&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
<Geometry_traits_2, Segment_2, Ray_2>(geom_traits, seg, w_ray);
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
upcase = ADVANCE;
s.push(*ipoint);
}
}
else {
Segment_2 w_seg(s.top(), w);
Object_2 result = CGAL::Visibility_2::Intersect_2
<Geometry_traits_2, Segment_2, Segment_2>(geom_traits, seg, w_seg);
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&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
<Geometry_traits_2, Segment_2, Ray_2>(geom_traits, seg, w_ray);
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
upcase = RETARD;
}
}
else {
Segment_2 w_seg(s.top(), w);
Object_2 result = CGAL::Visibility_2::Intersect_2
<Geometry_traits_2, Segment_2, Segment_2>(geom_traits, seg, w_seg);
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
upcase = RETARD;
}
}
}
}
}
};
} // namespace CGAL
#endif

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -27,7 +27,8 @@
#include <CGAL/Arrangement_2.h>
#include <CGAL/test_model_methods.h>
#include <CGAL/test_utils.h>
#include <CGAL/Simple_polygon_visibility_2.h>
//#include <CGAL/Simple_polygon_visibility_2.h>
#include <CGAL/Simple_polygon_visibility_2_.h>
#include <iostream>
#include <fstream>
@ -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<Traits_2> Arrangement_2;
typedef CGAL::Simple_polygon_visibility_2<Arrangement_2, CGAL::Tag_false>
typedef CGAL::Simple_polygon_visibility_2_<Arrangement_2, CGAL::Tag_false>
Simple_polygon_visibility_2;
std::cout << "Running model tests - ";
CGAL::test_model_methods<Simple_polygon_visibility_2>();
// CGAL::test_model_methods<Simple_polygon_visibility_2>();
std::cout << GREEN << "Done!" << RESET << std::endl;
std::cout << "Running test suite with " << GREEN
<< "Cartesian" << RESET << " Kernel..." << std::endl;
CGAL::run_tests<Simple_polygon_visibility_2>(10, 2);
}
CGAL::run_tests<Simple_polygon_visibility_2>(17, 0);
}/*
{
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef CGAL::Arr_segment_traits_2<Kernel> Traits_2;
@ -63,6 +64,6 @@ int main() {
std::cout << "Running test suite with " << GREEN
<< "EPECK" << RESET << " Kernel..." << std::endl;
CGAL::run_tests<Simple_polygon_visibility_2>(10, 2);
}
}*/
return 0;
}