mirror of https://github.com/CGAL/cgal
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:
commit
6bd60ece3a
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 |
|
|
@ -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}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue