mirror of https://github.com/CGAL/cgal
454 lines
16 KiB
C++
454 lines
16 KiB
C++
// Copyright (c) 2000 Max-Planck-Institute Saarbruecken (Germany).
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org); you may redistribute it under
|
|
// the terms of the Q Public License version 1.0.
|
|
// See the file LICENSE.QPL distributed with CGAL.
|
|
//
|
|
// Licensees holding a valid commercial license may use this file in
|
|
// accordance with the commercial license agreement provided with the software.
|
|
//
|
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// $Source$
|
|
// $Revision$ $Date$
|
|
// $Name$
|
|
//
|
|
// Author(s) : Susan Hert <hert@mpi-sb.mpg.de>
|
|
|
|
/*
|
|
Provides an implementation of the algorithm of Overmars and Welzl
|
|
for computing the visibility graph of a set of non-intersecting
|
|
line segments in the plane.
|
|
|
|
@inproceedings{ow-nmcvg-88
|
|
, author = "M. H. Overmars and Emo Welzl"
|
|
, title = "New methods for computing visibility graphs"
|
|
, booktitle = "Proc. 4th Annu. ACM Sympos. Comput. Geom."
|
|
, year = 1988
|
|
, pages = "164--171"
|
|
}
|
|
|
|
The running time is $O(n^2)$ with linear space requirements.
|
|
|
|
The algorithm implemented uses a sweep-line technique to construct the
|
|
visibility graph. The sweep data structure is a rotation tree, implemented
|
|
in the class CGAL::Rotation_tree_2.
|
|
|
|
A direction vector $d$ is swept from $-\pi/2$ to $\pi/2$,
|
|
and the sweep data structure, and whenever the direction of this vector
|
|
coincides with the slope of an edge in the rotation tree, the tree $G$
|
|
is updated and edges of the visibility graph are reported. To accomplish
|
|
the updates, it is necessary to keep track of all the leaves that are
|
|
leftmost children of their parents. In particular, one needs to know the
|
|
rightmost of these leftmost children.
|
|
|
|
Two data structures are needed for the implementation of the algorithm:
|
|
the sweep data structure $G$, and a stack $S$ that contains all the
|
|
leaves in $G$ that are the leftmost children of their parents.
|
|
|
|
TODO:
|
|
--is_valid function is not complete
|
|
--??? would a list of list of sorted vertices be a better representation?
|
|
|
|
*/
|
|
|
|
#ifndef CGAL_VERTEX_VISIBILITY_GRAPH_2_H
|
|
#define CGAL_VERTEX_VISIBILITY_GRAPH_2_H
|
|
|
|
#include <CGAL/Segment_2.h>
|
|
#include <CGAL/Rotation_tree_2.h>
|
|
#include <CGAL/Indirect_less_xy_2.h>
|
|
#include <CGAL/Iterator_list.h>
|
|
#include <CGAL/Turn_reverser.h>
|
|
#include <CGAL/Point_pair_less_xy_2.h>
|
|
#include <CGAL/Segment_2_Ray_2_intersection.h>
|
|
#include <CGAL/Segment_less_yx_2.h>
|
|
#include <cmath>
|
|
#include <list>
|
|
#include <stack>
|
|
#include <vector>
|
|
#include <set>
|
|
#include <map>
|
|
#include <iostream>
|
|
|
|
namespace CGAL {
|
|
|
|
template <class Traits>
|
|
class Vertex_visibility_graph_2
|
|
{
|
|
private:
|
|
typedef Vertex_visibility_graph_2<Traits> Self;
|
|
typedef typename Traits::Point_2 Point_2;
|
|
typedef typename Traits::Segment_2 Segment_2;
|
|
typedef typename Traits::Ray_2 Ray_2;
|
|
typedef typename Traits::Object_2 Object_2;
|
|
typedef typename Traits::Left_turn_2 Left_turn_2;
|
|
typedef typename Traits::Less_xy_2 Less_xy_2;
|
|
typedef typename Traits::Orientation_2 Orientation_2;
|
|
typedef typename Traits::Collinear_are_ordered_along_line_2
|
|
Collinear_are_ordered_along_line_2;
|
|
typedef typename Traits::Are_strictly_ordered_along_line_2
|
|
Are_strictly_ordered_along_line_2;
|
|
typedef typename Traits::Construct_segment_2
|
|
Construct_segment_2;
|
|
typedef typename Traits::Construct_ray_2 Construct_ray_2;
|
|
typedef typename Traits::Intersect_2 Intersect_2;
|
|
typedef typename Traits::Assign_2 Assign_2;
|
|
typedef Segment_less_yx_2<Traits> Segment_less_yx_2;
|
|
|
|
typedef Rotation_tree_2<Traits> Tree;
|
|
typedef typename Tree::iterator Tree_iterator;
|
|
|
|
typedef std::list< Point_2 > Polygon;
|
|
typedef typename Polygon::const_iterator Polygon_const_iterator;
|
|
typedef typename Polygon::iterator Polygon_iterator;
|
|
|
|
// the edge set is simply a set of point pairs.
|
|
typedef std::pair<Point_2, Point_2> Point_pair;
|
|
typedef Point_pair_less_xy_2<Traits> Point_pair_compare;
|
|
typedef std::set< Point_pair, Point_pair_compare > Edge_set;
|
|
|
|
// this map associates with each point (vertex), the iterator in the
|
|
// original list that it originated from and its current visibility
|
|
// point iterator.
|
|
typedef std::pair<Polygon_const_iterator, Polygon_const_iterator>
|
|
Iterator_pair;
|
|
typedef std::map<Point_2, Iterator_pair, Less_xy_2> Vertex_map;
|
|
typedef typename Vertex_map::iterator Vertex_map_iterator;
|
|
|
|
public:
|
|
typedef typename Edge_set::iterator iterator;
|
|
typedef typename Edge_set::const_iterator const_iterator;
|
|
|
|
|
|
#ifdef CGAL_CFG_RWSTD_NO_MEMBER_TEMPLATES
|
|
static Indirect_less_xy_2<Traits> indirect_less_xy_2;
|
|
static bool compare(const Polygon_const_iterator& pit1, const Polygon_const_iterator& pit2)
|
|
{
|
|
return indirect_less_xy_2(pit1, pit2);
|
|
}
|
|
#endif
|
|
|
|
Vertex_visibility_graph_2() {}
|
|
|
|
//
|
|
// first and beyond should be iterators over vertices of a polygon
|
|
//
|
|
template <class ForwardIterator>
|
|
Vertex_visibility_graph_2(ForwardIterator first, ForwardIterator beyond):
|
|
left_turn_2(Traits().left_turn_2_object()),
|
|
orientation_2(Traits().orientation_2_object()),
|
|
collinear_ordered_2(Traits().collinear_are_ordered_along_line_2_object()),
|
|
are_strictly_ordered_along_line_2(
|
|
Traits().are_strictly_ordered_along_line_2_object()),
|
|
less_xy_2(Traits().less_xy_2_object()),
|
|
construct_segment_2(Traits().construct_segment_2_object()),
|
|
construct_ray_2(Traits().construct_ray_2_object()),
|
|
intersect_2(Traits().intersect_2_object()),
|
|
assign_2(Traits().assign_2_object())
|
|
{
|
|
build(first, beyond);
|
|
}
|
|
|
|
// Pre: ccw order of points; no repeated points
|
|
template <class ForwardIterator>
|
|
void build(ForwardIterator first, ForwardIterator beyond)
|
|
{
|
|
#ifdef CGAL_CFG_RWSTD_NO_MEMBER_TEMPLATES
|
|
Polygon polygon;
|
|
|
|
for(ForwardIterator fit = first; fit != beyond; fit++){
|
|
polygon.push_back(*fit);
|
|
}
|
|
#else
|
|
Polygon polygon(first,beyond);
|
|
#endif
|
|
Tree tree(polygon.begin(), polygon.end());
|
|
|
|
Vertex_map vertex_map;
|
|
initialize_vertex_map(polygon, vertex_map);
|
|
|
|
// NOTE: use the std::list as the basis here because otherwise the basis
|
|
// is a deque, which is buggy under MSVC++
|
|
std::stack<Tree_iterator, std::list<Tree_iterator> > stack;
|
|
// push on p_0, the rightmost point
|
|
stack.push(tree.rightmost_point_ref());
|
|
|
|
Tree_iterator p, p_r, q;
|
|
Tree_iterator z;
|
|
|
|
while (!stack.empty())
|
|
{
|
|
p = stack.top();
|
|
#ifdef CGAL_VISIBILITY_GRAPH_DEBUG
|
|
if (p != tree.end())
|
|
std::cout << "p = " << *p << std::endl;
|
|
else
|
|
std::cout << "p == NULL" << std::endl;
|
|
#endif
|
|
stack.pop();
|
|
p_r = tree.right_sibling(p);
|
|
#ifdef CGAL_VISIBILITY_GRAPH_DEBUG
|
|
if (p_r != tree.end())
|
|
std::cout << "p_r = " << *p_r << std::endl;
|
|
else
|
|
std::cout << "p_r == NULL" << std::endl;
|
|
#endif
|
|
q = tree.parent(p);
|
|
#ifdef CGAL_VISIBILITY_GRAPH_DEBUG
|
|
if (q != tree.end())
|
|
std::cout << "q = " << *q << std::endl;
|
|
else
|
|
std::cout << "q == NULL" << std::endl;
|
|
#endif
|
|
if (!tree.parent_is_p_minus_infinity(p))
|
|
{
|
|
#ifdef CGAL_VISIBILITY_GRAPH_DEBUG
|
|
std::cout << "q is not p_minus_infinity" << std::endl;
|
|
#endif
|
|
handle(p,q,polygon,vertex_map);
|
|
}
|
|
z = tree.left_sibling(q);
|
|
#ifdef CGAL_VISIBILITY_GRAPH_DEBUG
|
|
if (z != tree.end())
|
|
std::cout << "z = " << *z << std::endl;
|
|
else
|
|
std::cout << "z == NULL" << std::endl;
|
|
std::cout << "erasing " << *p << " from tree " << std::endl;
|
|
#endif
|
|
tree.erase(p);
|
|
if ((z == tree.end()) || !left_turn_to_parent(p,z,tree))
|
|
{
|
|
#ifdef CGAL_VISIBILITY_GRAPH_DEBUG
|
|
std::cout << "making " << *p << " the left sibling of " << *q
|
|
<< std::endl;
|
|
#endif
|
|
tree.set_left_sibling(p,q);
|
|
}
|
|
else
|
|
{
|
|
// NOTE: no need to check here if z is p_infinity since you are
|
|
// moving DOWN the tree instead of up and p_infinity is at the root
|
|
Turn_reverser<Point_2, Left_turn_2> right_turn(left_turn_2);
|
|
|
|
while ((tree.rightmost_child(z) != tree.end()) &&
|
|
!right_turn(*p,*tree.rightmost_child(z),*z))
|
|
{
|
|
z = tree.rightmost_child(z);
|
|
#ifdef CGAL_VISIBILITY_GRAPH_DEBUG
|
|
std::cout << " z = " << *z << std::endl;
|
|
#endif
|
|
}
|
|
tree.set_rightmost_child(p,z);
|
|
if (!stack.empty() && z == stack.top())
|
|
{
|
|
#ifdef CGAL_VISIBILITY_GRAPH_DEBUG
|
|
std::cout << "popping " << *z << " from top of stack "
|
|
<< std::endl;
|
|
#endif
|
|
z = stack.top();
|
|
stack.pop();
|
|
}
|
|
}
|
|
#ifdef CGAL_VISIBILITY_GRAPH_DEBUG
|
|
std::cout << " p is now " << *p << std::endl;
|
|
#endif
|
|
if (tree.left_sibling(p) == tree.end() &&
|
|
!tree.parent_is_p_infinity(p))
|
|
{
|
|
#ifdef CGAL_VISIBILITY_GRAPH_DEBUG
|
|
std::cout << "pushing " << *p << std::endl;
|
|
#endif
|
|
stack.push(p);
|
|
}
|
|
if (p_r != tree.end()) stack.push(p_r);
|
|
}
|
|
// print_edge_set(edges);
|
|
}
|
|
|
|
|
|
void clear()
|
|
{
|
|
edges.clear();
|
|
}
|
|
|
|
iterator begin()
|
|
{
|
|
return edges.begin();
|
|
}
|
|
|
|
const_iterator begin() const
|
|
{
|
|
return edges.begin();
|
|
}
|
|
|
|
const_iterator end() const
|
|
{
|
|
return edges.end();
|
|
}
|
|
|
|
iterator end()
|
|
{
|
|
return edges.end();
|
|
}
|
|
|
|
void insert_edge(const Point_pair& edge)
|
|
{
|
|
if (less_xy_2(edge.first,edge.second))
|
|
edges.insert(edge);
|
|
else
|
|
edges.insert(Point_pair(edge.second, edge.first));
|
|
}
|
|
|
|
bool is_an_edge(const Point_pair& edge)
|
|
{
|
|
if (less_xy_2(edge.first,edge.second))
|
|
return edges.find(edge) != edges.end();
|
|
else
|
|
return edges.find(Point_pair(edge.second, edge.first)) != edges.end();
|
|
}
|
|
|
|
#if 0
|
|
// ??? need to finish this ???
|
|
template <class ForwardIterator>
|
|
bool is_valid(ForwardIterator first, ForwardIterator beyond)
|
|
{
|
|
std::vector<Point_2> vertices(first, beyond);
|
|
bool edge_there[vertices.size()];
|
|
|
|
// for each edge in the graph determine if it is either an edge of the
|
|
// polygon or, if not, if it intersects the polygon in the interior of
|
|
// the edge.
|
|
for (iterator e_it = edges.begin(); e_it != edges.end(); e_it++)
|
|
{
|
|
Segment_2 s = construct_segment_2((*e_it).first, (*e_it).second);
|
|
if (is_an_edge(*e_it))
|
|
edge_there[edge_num] = true;
|
|
else if (do_intersect_in_interior(s, first, beyond))
|
|
return false;
|
|
}
|
|
// check if all the edges of the polygon are present
|
|
//
|
|
// ??? how do you check if there are missing edges ???
|
|
}
|
|
#endif
|
|
|
|
|
|
private:
|
|
|
|
void print_vertex_map(const Vertex_map& vertex_map,
|
|
const Polygon& polygon)
|
|
{
|
|
typedef typename Vertex_map::const_iterator const_iterator;
|
|
|
|
for (const_iterator it = vertex_map.begin(); it != vertex_map.end();it++)
|
|
{
|
|
if ((*it).second.second != polygon.end())
|
|
std::cout << (*it).first << " sees " << *((*it).second.second)
|
|
<< std::endl;
|
|
}
|
|
}
|
|
|
|
template<class E>
|
|
void print_edge_set(const E& edges)
|
|
{
|
|
typedef typename E::iterator iterator;
|
|
for (iterator it = edges.begin(); it != edges.end(); it++)
|
|
{
|
|
std::cout << (*it).first << " " << (*it).second << std::endl;
|
|
}
|
|
}
|
|
|
|
// want to determine, for each vertex p of the polygon, the line segment
|
|
// immediately below it. For vertical edges, the segment below is not the
|
|
// one that begins at the other endpoint of the edge.
|
|
void initialize_vertex_map(const Polygon& polygon,
|
|
Vertex_map& vertex_map);
|
|
|
|
// determines if one makes a left turn going from p to q to q's parent.
|
|
// if q's parent is p_infinity, then a left turn is made when p's x value
|
|
// is less than q's x value or the x values are the same and p's y value is
|
|
// less than q's.
|
|
// if p, q, and q's parent are collinear, then one makes a "left turn"
|
|
// if q is between p and q's parent (since this means that p can't see
|
|
// q's parent and thus should not become a child of that node)
|
|
bool left_turn_to_parent(Tree_iterator p, Tree_iterator q, Tree& tree);
|
|
|
|
|
|
// returns true if q is the vertex after p
|
|
bool is_next_to(const Polygon& polygon, Polygon_const_iterator p,
|
|
Polygon_const_iterator q) const
|
|
{
|
|
Polygon_const_iterator next = p; next++;
|
|
if (next == polygon.end()) next = polygon.begin();
|
|
return (q == next);
|
|
}
|
|
|
|
// returns true if q is the vertex before or after p
|
|
bool are_adjacent(const Polygon& polygon, Polygon_const_iterator p,
|
|
Polygon_const_iterator q) const
|
|
{
|
|
Polygon_const_iterator next = p; next++;
|
|
if (next == polygon.end()) next = polygon.begin();
|
|
if (q == next) return true;
|
|
next = q; next++;
|
|
if (next == polygon.end()) next = polygon.begin();
|
|
if (p == next) return true;
|
|
return false;
|
|
}
|
|
|
|
// returns true if the diagonal from p to q cuts the interior angle at p
|
|
bool diagonal_in_interior(const Polygon& polygon,
|
|
Polygon_const_iterator p,
|
|
Polygon_const_iterator q);
|
|
|
|
|
|
// returns true if the looker can see the point_to_see
|
|
bool point_is_visible(const Polygon& polygon,
|
|
Polygon_const_iterator point_to_see,
|
|
Vertex_map_iterator looker);
|
|
|
|
void update_visibility(Vertex_map_iterator p_it,
|
|
Vertex_map_iterator q_it,
|
|
const Polygon& polygon, int are_adjacent);
|
|
|
|
void update_collinear_visibility(Vertex_map_iterator p_it,
|
|
Vertex_map_iterator q_it,
|
|
const Polygon& polygon);
|
|
|
|
// The segment between points p and q is a potential visibility edge
|
|
// This function determines if the edge should be added or not (based
|
|
// on p's current visibility point) and updates p's visibility point
|
|
// where appropriate
|
|
void handle(Tree_iterator p, Tree_iterator q, const Polygon& polygon,
|
|
Vertex_map& vertex_map);
|
|
|
|
private:
|
|
Left_turn_2 left_turn_2;
|
|
Orientation_2 orientation_2;
|
|
Collinear_are_ordered_along_line_2 collinear_ordered_2;
|
|
Are_strictly_ordered_along_line_2 are_strictly_ordered_along_line_2;
|
|
Less_xy_2 less_xy_2;
|
|
Construct_segment_2 construct_segment_2;
|
|
Construct_ray_2 construct_ray_2;
|
|
Intersect_2 intersect_2;
|
|
Assign_2 assign_2;
|
|
Edge_set edges;
|
|
};
|
|
|
|
|
|
#ifdef CGAL_CFG_RWSTD_NO_MEMBER_TEMPLATES
|
|
template <class Traits>
|
|
Indirect_less_xy_2<Traits>
|
|
Vertex_visibility_graph_2<Traits>::indirect_less_xy_2;
|
|
#endif
|
|
}
|
|
|
|
#ifdef CGAL_CFG_NO_AUTOMATIC_TEMPLATE_INCLUSION
|
|
#include <CGAL/Vertex_visibility_graph_2.C>
|
|
#endif // CGAL_CFG_NO_AUTOMATIC_TEMPLATE_INCLUSION
|
|
|
|
#endif // CGAL_VERTEX_VISIBILITY_GRAPH_2_H
|