1
0
mirror of https://github.com/FULU-Foundation/OrcaSlicer-bambulab.git synced 2026-07-14 08:34:26 +00:00
Files
OrcaSlicer-bambulab/xs/src/visilibity.cpp
T
2014-05-13 20:06:01 +02:00

3660 lines
103 KiB
C++

/**
* \file visilibity.cpp
* \author Karl J. Obermeyer
* \date March 20, 2008
*
\remarks
VisiLibity: A Floating-Point Visibility Algorithms Library,
Copyright (C) 2008 Karl J. Obermeyer (karl.obermeyer [ at ] gmail.com)
This file is part of VisiLibity.
VisiLibity is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
VisiLibity is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with VisiLibity. If not, see <http://www.gnu.org/licenses/>.
*/
#include "visilibity.hpp" //VisiLibity header
#include <cmath> //math functions in std namespace
#include <vector>
#include <queue> //queue and priority_queue
#include <set> //priority queues with iteration,
//integrated keys
#include <list>
#include <algorithm> //sorting, min, max, reverse
#include <cstdlib> //rand and srand
#include <ctime> //Unix time
#include <fstream> //file I/O
#include <iostream>
#include <cstring> //gives C-string manipulation
#include <string> //string class
#include <cassert> //assertions
///Hide helping functions in unnamed namespace (local to .C file).
namespace
{
}
/// VisiLibity's sole namespace
namespace VisiLibity
{
double uniform_random_sample(double lower_bound, double upper_bound)
{
assert( lower_bound <= upper_bound );
if( lower_bound == upper_bound )
return lower_bound;
double sample_point;
double span = upper_bound - lower_bound;
sample_point = lower_bound
+ span * static_cast<double>( std::rand() )
/ static_cast<double>( RAND_MAX );
return sample_point;
}
//Point
Point Point::projection_onto(const Line_Segment& line_segment_temp) const
{
assert( *this == *this
and line_segment_temp.size() > 0 );
if(line_segment_temp.size() == 1)
return line_segment_temp.first();
//The projection of point_temp onto the line determined by
//line_segment_temp can be represented as an affine combination
//expressed in the form projection of Point =
//theta*line_segment_temp.first +
//(1.0-theta)*line_segment_temp.second. if theta is outside
//the interval [0,1], then one of the Line_Segment's endpoints
//must be closest to calling Point.
double theta =
( (line_segment_temp.second().x()-x())
*(line_segment_temp.second().x()
-line_segment_temp.first().x())
+ (line_segment_temp.second().y()-y())
*(line_segment_temp.second().y()
-line_segment_temp.first().y()) )
/ ( pow(line_segment_temp.second().x()
-line_segment_temp.first().x(),2)
+ pow(line_segment_temp.second().y()
-line_segment_temp.first().y(),2) );
//std::cout << "\E[1;37;40m" << "Theta is: " << theta << "\x1b[0m"
//<< std::endl;
if( (0.0<=theta) and (theta<=1.0) )
return theta*line_segment_temp.first()
+ (1.0-theta)*line_segment_temp.second();
//Else pick closest endpoint.
if( distance(*this, line_segment_temp.first())
< distance(*this, line_segment_temp.second()) )
return line_segment_temp.first();
return line_segment_temp.second();
}
Point Point::projection_onto(const Ray& ray_temp) const
{
assert( *this == *this
and ray_temp == ray_temp );
//Construct a Line_Segment parallel with the Ray which is so long,
//that the projection of the the calling Point onto that
//Line_Segment must be the same as the projection of the calling
//Point onto the Ray.
double R = distance( *this , ray_temp.base_point() );
Line_Segment seg_approx =
Line_Segment( ray_temp.base_point(), ray_temp.base_point() +
Point( R*std::cos(ray_temp.bearing().get()),
R*std::sin(ray_temp.bearing().get()) ) );
return projection_onto( seg_approx );
}
Point Point::projection_onto(const Polyline& polyline_temp) const
{
assert( *this == *this
and polyline_temp.size() > 0 );
Point running_projection = polyline_temp[0];
double running_min = distance(*this, running_projection);
Point point_temp;
for(unsigned i=0; i<=polyline_temp.size()-1; i++){
point_temp = projection_onto( Line_Segment(polyline_temp[i],
polyline_temp[i+1]) );
if( distance(*this, point_temp) < running_min ){
running_projection = point_temp;
running_min = distance(*this, running_projection);
}
}
return running_projection;
}
Point Point::projection_onto_vertices_of(const Polygon& polygon_temp) const
{
assert(*this == *this
and polygon_temp.vertices_.size() > 0 );
Point running_projection = polygon_temp[0];
double running_min = distance(*this, running_projection);
for(unsigned i=1; i<=polygon_temp.n()-1; i++){
if( distance(*this, polygon_temp[i]) < running_min ){
running_projection = polygon_temp[i];
running_min = distance(*this, running_projection);
}
}
return running_projection;
}
Point Point::projection_onto_vertices_of(const Environment&
environment_temp) const
{
assert(*this == *this
and environment_temp.n() > 0 );
Point running_projection
= projection_onto_vertices_of(environment_temp.outer_boundary_);
double running_min = distance(*this, running_projection);
Point point_temp;
for(unsigned i=0; i<environment_temp.h(); i++){
point_temp = projection_onto_vertices_of(environment_temp.holes_[i]);
if( distance(*this, point_temp) < running_min ){
running_projection = point_temp;
running_min = distance(*this, running_projection);
}
}
return running_projection;
}
Point Point::projection_onto_boundary_of(const Polygon& polygon_temp) const
{
assert( *this == *this
and polygon_temp.n() > 0 );
Point running_projection = polygon_temp[0];
double running_min = distance(*this, running_projection);
Point point_temp;
for(unsigned i=0; i<=polygon_temp.n()-1; i++){
point_temp = projection_onto( Line_Segment(polygon_temp[i],
polygon_temp[i+1]) );
if( distance(*this, point_temp) < running_min ){
running_projection = point_temp;
running_min = distance(*this, running_projection);
}
}
return running_projection;
}
Point Point::projection_onto_boundary_of(const Environment&
environment_temp) const
{
assert( *this == *this
and environment_temp.n() > 0 );
Point running_projection
= projection_onto_boundary_of(environment_temp.outer_boundary_);
double running_min = distance(*this, running_projection);
Point point_temp;
for(unsigned i=0; i<environment_temp.h(); i++){
point_temp = projection_onto_boundary_of(environment_temp.holes_[i]);
if( distance(*this, point_temp) < running_min ){
running_projection = point_temp;
running_min = distance(*this, running_projection);
}
}
return running_projection;
}
bool Point::on_boundary_of(const Polygon& polygon_temp,
double epsilon) const
{
assert( *this == *this
and polygon_temp.vertices_.size() > 0 );
if( distance(*this, projection_onto_boundary_of(polygon_temp) )
<= epsilon ){
return true;
}
return false;
}
bool Point::on_boundary_of(const Environment& environment_temp,
double epsilon) const
{
assert( *this == *this
and environment_temp.outer_boundary_.n() > 0 );
if( distance(*this, projection_onto_boundary_of(environment_temp) )
<= epsilon ){
return true;
}
return false;
}
bool Point::in(const Line_Segment& line_segment_temp,
double epsilon) const
{
assert( *this == *this
and line_segment_temp.size() > 0 );
if( distance(*this, line_segment_temp) < epsilon )
return true;
return false;
}
bool Point::in_relative_interior_of(const Line_Segment& line_segment_temp,
double epsilon) const
{
assert( *this == *this
and line_segment_temp.size() > 0 );
return in(line_segment_temp, epsilon)
and distance(*this, line_segment_temp.first()) > epsilon
and distance(*this, line_segment_temp.second()) > epsilon;
}
bool Point::in(const Polygon& polygon_temp,
double epsilon) const
{
assert( *this == *this
and polygon_temp.vertices_.size() > 0 );
int n = polygon_temp.vertices_.size();
if( on_boundary_of(polygon_temp, epsilon) )
return true;
// Then check the number of times a ray emanating from the Point
// crosses the boundary of the Polygon. An odd number of
// crossings indicates the Point is in the interior of the
// Polygon. Based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
int i, j; bool c = false;
for (i = 0, j = n-1; i < n; j = i++){
if ( (((polygon_temp[i].y() <= y())
and (y() < polygon_temp[j].y()))
or ((polygon_temp[j].y() <= y())
and (y() < polygon_temp[i].y())))
and ( x() < (polygon_temp[j].x()
- polygon_temp[i].x())
* (y() - polygon_temp[i].y())
/ (polygon_temp[j].y()
- polygon_temp[i].y())
+ polygon_temp[i].x()) )
c = !c;
}
return c;
}
bool Point::in(const Environment& environment_temp, double epsilon) const
{
assert( *this == *this
and environment_temp.outer_boundary_.n() > 0 );
//On outer boundary?
if( on_boundary_of(environment_temp, epsilon) )
return true;
//Not in outer boundary?
if( !in(environment_temp.outer_boundary_, epsilon) )
return false;
//In hole?
for(unsigned i=0; i<environment_temp.h(); i++)
if( in(environment_temp.holes_[i]) )
return false;
//Must be in interior.
return true;
}
bool Point::is_endpoint_of(const Line_Segment& line_segment_temp,
double epsilon) const
{
assert( *this == *this
and line_segment_temp.size() > 0 );
if( distance(line_segment_temp.first(), *this)<=epsilon
or distance(line_segment_temp.second(), *this)<=epsilon )
return true;
return false;
}
void Point::snap_to_vertices_of(const Polygon& polygon_temp,
double epsilon)
{
assert( *this == *this
and polygon_temp.n() > 0 );
Point point_temp( this->projection_onto_vertices_of(polygon_temp) );
if( distance( *this , point_temp ) <= epsilon )
*this = point_temp;
}
void Point::snap_to_vertices_of(const Environment& environment_temp,
double epsilon)
{
assert( *this == *this
and environment_temp.n() > 0 );
Point point_temp( this->projection_onto_vertices_of(environment_temp) );
if( distance( *this , point_temp ) <= epsilon )
*this = point_temp;
}
void Point::snap_to_boundary_of(const Polygon& polygon_temp,
double epsilon)
{
assert( *this == *this
and polygon_temp.n() > 0 );
Point point_temp( this->projection_onto_boundary_of(polygon_temp) );
if( distance( *this , point_temp ) <= epsilon )
*this = point_temp;
}
void Point::snap_to_boundary_of(const Environment& environment_temp,
double epsilon)
{
assert( *this == *this
and environment_temp.n() > 0 );
Point point_temp( this->projection_onto_boundary_of(environment_temp) );
if( distance( *this , point_temp ) <= epsilon )
*this = point_temp;
}
bool operator == (const Point& point1, const Point& point2)
{ return ( ( point1.x() == point2.x() )
and ( point1.y() == point2.y() ) ); }
bool operator != (const Point& point1, const Point& point2)
{ return !( point1 == point2 ); }
bool operator < (const Point& point1, const Point& point2)
{
if( point1 != point1 or point2 != point2 )
return false;
if(point1.x() < point2.x())
return true;
else if( ( point1.x() == point2.x() )
and ( point1.y() < point2.y() ) )
return true;
return false;
}
bool operator > (const Point& point1, const Point& point2)
{
if( point1 != point1 or point2 != point2 )
return false;
if( point1.x() > point2.x() )
return true;
else if( ( point1.x() == point2.x() )
and ( point1.y() > point2.y() ) )
return true;
return false;
}
bool operator >= (const Point& point1, const Point& point2)
{
if( point1 != point1 or point2 != point2 )
return false;
return !( point1 < point2 );
}
bool operator <= (const Point& point1, const Point& point2)
{
if( point1 != point1 or point2 != point2 )
return false;
return !( point1 > point2 );
}
Point operator + (const Point& point1, const Point& point2)
{
return Point( point1.x() + point2.x(),
point1.y() + point2.y() );
}
Point operator - (const Point& point1, const Point& point2)
{
return Point( point1.x() - point2.x(),
point1.y() - point2.y() );
}
Point operator * (const Point& point1, const Point& point2)
{
return Point( point1.x()*point2.x(),
point1.y()*point2.y() );
}
Point operator * (double scalar, const Point& point2)
{
return Point( scalar*point2.x(),
scalar*point2.y());
}
Point operator * (const Point& point1, double scalar)
{
return Point( scalar*point1.x(),
scalar*point1.y());
}
double cross(const Point& point1, const Point& point2)
{
assert( point1 == point1
and point2 == point2 );
//The area of the parallelogram created by the Points viewed as vectors.
return point1.x()*point2.y() - point2.x()*point1.y();
}
double distance(const Point& point1, const Point& point2)
{
assert( point1 == point1
and point2 == point2 );
return sqrt( pow( point1.x() - point2.x() , 2 )
+ pow( point1.y() - point2.y() , 2 ) );
}
double distance(const Point& point_temp,
const Line_Segment& line_segment_temp)
{
assert( point_temp == point_temp
and line_segment_temp.size() > 0 );
return distance( point_temp,
point_temp.projection_onto(line_segment_temp) );
}
double distance(const Line_Segment& line_segment_temp,
const Point& point_temp)
{
return distance( point_temp,
line_segment_temp );
}
double distance(const Point& point_temp,
const Ray& ray_temp)
{
assert( point_temp == point_temp
and ray_temp == ray_temp );
return distance( point_temp,
point_temp.projection_onto(ray_temp) );
}
double distance(const Ray& ray_temp,
const Point& point_temp)
{
return distance( point_temp,
point_temp.projection_onto(ray_temp) );
}
double distance(const Point& point_temp,
const Polyline& polyline_temp)
{
assert( point_temp == point_temp
and polyline_temp.size() > 0 );
double running_min = distance(point_temp, polyline_temp[0]);
double distance_temp;
for(unsigned i=0; i<polyline_temp.size()-1; i++){
distance_temp = distance(point_temp, Line_Segment(polyline_temp[i],
polyline_temp[i+1]) );
if(distance_temp < running_min)
running_min = distance_temp;
}
return running_min;
}
double distance(const Polyline& polyline_temp,
const Point& point_temp)
{
return distance(point_temp, polyline_temp);
}
double boundary_distance(const Point& point_temp,
const Polygon& polygon_temp)
{
assert( point_temp == point_temp
and polygon_temp.n() > 0);
double running_min = distance(point_temp, polygon_temp[0]);
double distance_temp;
for(unsigned i=0; i<=polygon_temp.n(); i++){
distance_temp = distance(point_temp, Line_Segment(polygon_temp[i],
polygon_temp[i+1]) );
if(distance_temp < running_min)
running_min = distance_temp;
}
return running_min;
}
double boundary_distance(const Polygon& polygon_temp, const Point& point_temp)
{
return boundary_distance(point_temp, polygon_temp);
}
double boundary_distance(const Point& point_temp,
const Environment& environment_temp)
{
assert( point_temp == point_temp
and environment_temp.n() > 0 );
double running_min = distance(point_temp, environment_temp[0][0]);
double distance_temp;
for(unsigned i=0; i <= environment_temp.h(); i++){
distance_temp = boundary_distance(point_temp, environment_temp[i]);
if(distance_temp < running_min)
running_min = distance_temp;
}
return running_min;
}
double boundary_distance(const Environment& environment_temp,
const Point& point_temp)
{
return boundary_distance(point_temp, environment_temp);
}
std::ostream& operator << (std::ostream& outs, const Point& point_temp)
{
outs << point_temp.x() << " " << point_temp.y();
return outs;
}
//Line_Segment
Line_Segment::Line_Segment()
{
endpoints_ = NULL;
size_ = 0;
}
Line_Segment::Line_Segment(const Line_Segment& line_segment_temp)
{
switch(line_segment_temp.size_){
case 0:
endpoints_ = NULL;
size_ = 0;
break;
case 1:
endpoints_ = new Point[1];
endpoints_[0] = line_segment_temp.endpoints_[0];
size_ = 1;
break;
case 2:
endpoints_ = new Point[2];
endpoints_[0] = line_segment_temp.endpoints_[0];
endpoints_[1] = line_segment_temp.endpoints_[1];
size_ = 2;
}
}
Line_Segment::Line_Segment(const Point& point_temp)
{
endpoints_ = new Point[1];
endpoints_[0] = point_temp;
size_ = 1;
}
Line_Segment::Line_Segment(const Point& first_point_temp,
const Point& second_point_temp, double epsilon)
{
if( distance(first_point_temp, second_point_temp) <= epsilon ){
endpoints_ = new Point[1];
endpoints_[0] = first_point_temp;
size_ = 1;
}
else{
endpoints_ = new Point[2];
endpoints_[0] = first_point_temp;
endpoints_[1] = second_point_temp;
size_ = 2;
}
}
Point Line_Segment::first() const
{
assert( size() > 0 );
return endpoints_[0];
}
Point Line_Segment::second() const
{
assert( size() > 0 );
if(size_==2)
return endpoints_[1];
else
return endpoints_[0];
}
Point Line_Segment::midpoint() const
{
assert( size_ > 0 );
return 0.5*( first() + second() );
}
double Line_Segment::length() const
{
assert( size_ > 0 );
return distance(first(), second());
}
bool Line_Segment::is_in_standard_form() const
{
assert( size_ > 0);
if(size_<2)
return true;
return first() <= second();
}
Line_Segment& Line_Segment::operator = (const Line_Segment& line_segment_temp)
{
//Makes sure not to delete dynamic vars before they're copied.
if(this==&line_segment_temp)
return *this;
delete [] endpoints_;
switch(line_segment_temp.size_){
case 0:
endpoints_ = NULL;
size_ = 0;
break;
case 1:
endpoints_ = new Point[1];
endpoints_[0] = line_segment_temp.endpoints_[0];
size_ = 1;
break;
case 2:
endpoints_ = new Point[2];
endpoints_[0] = line_segment_temp.endpoints_[0];
endpoints_[1] = line_segment_temp.endpoints_[1];
size_ = 2;
}
return *this;
}
void Line_Segment::set_first(const Point& point_temp, double epsilon)
{
Point second_point_temp;
switch(size_){
case 0:
endpoints_ = new Point[1];
endpoints_[0] = point_temp;
size_ = 1;
break;
case 1:
if( distance(endpoints_[0], point_temp) <= epsilon )
{ endpoints_[0] = point_temp; return; }
second_point_temp = endpoints_[0];
delete [] endpoints_;
endpoints_ = new Point[2];
endpoints_[0] = point_temp;
endpoints_[1] = second_point_temp;
size_ = 2;
break;
case 2:
if( distance(point_temp, endpoints_[1]) > epsilon )
{ endpoints_[0] = point_temp; return; }
delete [] endpoints_;
endpoints_ = new Point[1];
endpoints_[0] = point_temp;
size_ = 1;
}
}
void Line_Segment::set_second(const Point& point_temp, double epsilon)
{
Point first_point_temp;
switch(size_){
case 0:
endpoints_ = new Point[1];
endpoints_[0] = point_temp;
size_ = 1;
break;
case 1:
if( distance(endpoints_[0], point_temp) <= epsilon )
{ endpoints_[0] = point_temp; return; }
first_point_temp = endpoints_[0];
delete [] endpoints_;
endpoints_ = new Point[2];
endpoints_[0] = first_point_temp;
endpoints_[1] = point_temp;
size_ = 2;
break;
case 2:
if( distance(endpoints_[0], point_temp) > epsilon )
{ endpoints_[1] = point_temp; return; }
delete [] endpoints_;
endpoints_ = new Point[1];
endpoints_[0] = point_temp;
size_ = 1;
}
}
void Line_Segment::reverse()
{
if(size_<2)
return;
Point point_temp(first());
endpoints_[0] = second();
endpoints_[1] = point_temp;
}
void Line_Segment::enforce_standard_form()
{
if(first() > second())
reverse();
}
void Line_Segment::clear()
{
delete [] endpoints_;
endpoints_ = NULL;
size_ = 0;
}
Line_Segment::~Line_Segment()
{
delete [] endpoints_;
}
bool operator == (const Line_Segment& line_segment1,
const Line_Segment& line_segment2)
{
if( line_segment1.size() != line_segment2.size()
or line_segment1.size() == 0
or line_segment2.size() == 0 )
return false;
else if( line_segment1.first() == line_segment2.first()
and line_segment1.second() == line_segment2.second() )
return true;
else
return false;
}
bool operator != (const Line_Segment& line_segment1,
const Line_Segment& line_segment2)
{
return !( line_segment1 == line_segment2 );
}
bool equivalent(Line_Segment line_segment1,
Line_Segment line_segment2, double epsilon)
{
if( line_segment1.size() != line_segment2.size()
or line_segment1.size() == 0
or line_segment2.size() == 0 )
return false;
else if( ( distance( line_segment1.first(),
line_segment2.first() ) <= epsilon
and distance( line_segment1.second(),
line_segment2.second() ) <= epsilon )
or ( distance( line_segment1.first(),
line_segment2.second() ) <= epsilon
and distance( line_segment1.second(),
line_segment2.first() ) <= epsilon ) )
return true;
else
return false;
}
double distance(const Line_Segment& line_segment1,
const Line_Segment& line_segment2)
{
assert( line_segment1.size() > 0 and line_segment2.size() > 0 );
if(intersect_proper(line_segment1, line_segment2))
return 0;
//But if two line segments intersect improperly, the distance
//between them is equal to the minimum of the distances between
//all 4 endpoints_ and their respective projections onto the line
//segment they don't belong to.
double running_min, distance_temp;
running_min = distance(line_segment1.first(), line_segment2);
distance_temp = distance(line_segment1.second(), line_segment2);
if(distance_temp<running_min)
running_min = distance_temp;
distance_temp = distance(line_segment2.first(), line_segment1);
if(distance_temp<running_min)
running_min = distance_temp;
distance_temp = distance(line_segment2.second(), line_segment1);
if(distance_temp<running_min)
return distance_temp;
return running_min;
}
double boundary_distance(const Line_Segment& line_segment,
const Polygon& polygon)
{
assert( line_segment.size() > 0 and polygon.n() > 0 );
double running_min = distance( line_segment , polygon[0] );
if( polygon.n() > 1 )
for(unsigned i=0; i<polygon.n(); i++){
double d = distance( line_segment,
Line_Segment( polygon[i] , polygon[i+1] ) );
if( running_min > d )
running_min = d;
}
return running_min;
}
double boundary_distance(const Polygon& polygon,
const Line_Segment& line_segment)
{ return boundary_distance( line_segment , polygon ); }
bool intersect(const Line_Segment& line_segment1,
const Line_Segment& line_segment2, double epsilon)
{
if( line_segment1.size() == 0
or line_segment2.size() == 0 )
return false;
if( distance(line_segment1, line_segment2) <= epsilon )
return true;
return false;
}
bool intersect_proper(const Line_Segment& line_segment1,
const Line_Segment& line_segment2, double epsilon)
{
if( line_segment1.size() == 0
or line_segment2.size() == 0 )
return false;
//Declare new vars just for readability.
Point a( line_segment1.first() );
Point b( line_segment1.second() );
Point c( line_segment2.first() );
Point d( line_segment2.second() );
//First find the minimum of the distances between all 4 endpoints_
//and their respective projections onto the opposite line segment.
double running_min, distance_temp;
running_min = distance(a, line_segment2);
distance_temp = distance(b, line_segment2);
if(distance_temp<running_min)
running_min = distance_temp;
distance_temp = distance(c, line_segment1);
if(distance_temp<running_min)
running_min = distance_temp;
distance_temp = distance(d, line_segment1);
if(distance_temp<running_min)
running_min = distance_temp;
//If an endpoint is close enough to the other segment, the
//intersection is not considered proper.
if(running_min <= epsilon)
return false;
//This test is from O'Rourke's "Computational Geometry in C",
//p.30. Checks left and right turns.
if( cross(b-a, c-b) * cross(b-a, d-b) < 0
and cross(d-c, b-d) * cross(d-c, a-d) < 0 )
return true;
return false;
}
Line_Segment intersection(const Line_Segment& line_segment1,
const Line_Segment& line_segment2, double epsilon)
{
//Initially empty.
Line_Segment line_segment_temp;
if( line_segment1.size() == 0
or line_segment2.size() == 0 )
return line_segment_temp;
//No intersection => return empty segment.
if( !intersect(line_segment1, line_segment2, epsilon) )
return line_segment_temp;
//Declare new vars just for readability.
Point a( line_segment1.first() );
Point b( line_segment1.second() );
Point c( line_segment2.first() );
Point d( line_segment2.second() );
if( intersect_proper(line_segment1, line_segment2, epsilon) ){
//Use formula from O'Rourke's "Computational Geometry in C", p. 221.
//Note D=0 iff the line segments are parallel.
double D = a.x()*( d.y() - c.y() )
+ b.x()*( c.y() - d.y() )
+ d.x()*( b.y() - a.y() )
+ c.x()*( a.y() - b.y() );
double s = ( a.x()*( d.y() - c.y() )
+ c.x()*( a.y() - d.y() )
+ d.x()*( c.y() - a.y() ) ) / D;
line_segment_temp.set_first( a + s * ( b - a ) );
return line_segment_temp;
}
//Otherwise if improper...
double distance_temp_a = distance(a, line_segment2);
double distance_temp_b = distance(b, line_segment2);
double distance_temp_c = distance(c, line_segment1);
double distance_temp_d = distance(d, line_segment1);
//Check if the intersection is nondegenerate segment.
if( distance_temp_a <= epsilon and distance_temp_b <= epsilon ){
line_segment_temp.set_first(a, epsilon);
line_segment_temp.set_second(b, epsilon);
return line_segment_temp;
}
else if( distance_temp_c <= epsilon and distance_temp_d <= epsilon ){
line_segment_temp.set_first(c, epsilon);
line_segment_temp.set_second(d, epsilon);
return line_segment_temp;
}
else if( distance_temp_a <= epsilon and distance_temp_c <= epsilon ){
line_segment_temp.set_first(a, epsilon);
line_segment_temp.set_second(c, epsilon);
return line_segment_temp;
}
else if( distance_temp_a <= epsilon and distance_temp_d <= epsilon ){
line_segment_temp.set_first(a, epsilon);
line_segment_temp.set_second(d, epsilon);
return line_segment_temp;
}
else if( distance_temp_b <= epsilon and distance_temp_c <= epsilon ){
line_segment_temp.set_first(b, epsilon);
line_segment_temp.set_second(c, epsilon);
return line_segment_temp;
}
else if( distance_temp_b <= epsilon and distance_temp_d <= epsilon ){
line_segment_temp.set_first(b, epsilon);
line_segment_temp.set_second(d, epsilon);
return line_segment_temp;
}
//Check if the intersection is a single point.
else if( distance_temp_a <= epsilon ){
line_segment_temp.set_first(a, epsilon);
return line_segment_temp;
}
else if( distance_temp_b <= epsilon ){
line_segment_temp.set_first(b, epsilon);
return line_segment_temp;
}
else if( distance_temp_c <= epsilon ){
line_segment_temp.set_first(c, epsilon);
return line_segment_temp;
}
else if( distance_temp_d <= epsilon ){
line_segment_temp.set_first(d, epsilon);
return line_segment_temp;
}
return line_segment_temp;
}
std::ostream& operator << (std::ostream& outs,
const Line_Segment& line_segment_temp)
{
switch(line_segment_temp.size()){
case 0:
return outs;
break;
case 1:
outs << line_segment_temp.first() << std::endl
<< line_segment_temp.second() << std::endl;
return outs;
break;
case 2:
outs << line_segment_temp.first() << std::endl
<< line_segment_temp.second() << std::endl;
return outs;
}
return outs;
}
//Angle
Angle::Angle(double data_temp)
{
if(data_temp >= 0)
angle_radians_ = fmod(data_temp, 2*M_PI);
else{
angle_radians_ = 2*M_PI + fmod(data_temp, -2*M_PI);
if(angle_radians_ == 2*M_PI)
angle_radians_ = 0;
}
}
Angle::Angle(double rise_temp, double run_temp)
{
if( rise_temp == 0 and run_temp == 0 )
angle_radians_ = 0;
//First calculate 4 quadrant inverse tangent into [-pi,+pi].
angle_radians_ = std::atan2(rise_temp, run_temp);
//Correct so angles specified in [0, 2*PI).
if(angle_radians_ < 0)
angle_radians_ = 2*M_PI + angle_radians_;
}
void Angle::set(double data_temp)
{
*this = Angle(data_temp);
}
void Angle::randomize()
{
angle_radians_ = fmod( uniform_random_sample(0, 2*M_PI), 2*M_PI );
}
bool operator == (const Angle& angle1, const Angle& angle2)
{
return (angle1.get() == angle2.get());
}
bool operator != (const Angle& angle1, const Angle& angle2)
{
return !(angle1.get() == angle2.get());
}
bool operator > (const Angle& angle1, const Angle& angle2)
{
return angle1.get() > angle2.get();
}
bool operator < (const Angle& angle1, const Angle& angle2)
{
return angle1.get() < angle2.get();
}
bool operator >= (const Angle& angle1, const Angle& angle2)
{
return angle1.get() >= angle2.get();
}
bool operator <= (const Angle& angle1, const Angle& angle2)
{
return angle1.get() <= angle2.get();
}
Angle operator + (const Angle& angle1, const Angle& angle2)
{
return Angle( angle1.get() + angle2.get() );
}
Angle operator - (const Angle& angle1, const Angle& angle2)
{
return Angle( angle1.get() - angle2.get() );
}
double geodesic_distance(const Angle& angle1, const Angle& angle2)
{
assert( angle1.get() == angle1.get()
and angle2.get() == angle2.get() );
double distance1 = std::fabs( angle1.get()
- angle2.get() );
double distance2 = 2*M_PI - distance1;
if(distance1 < distance2)
return distance1;
return distance2;
}
double geodesic_direction(const Angle& angle1, const Angle& angle2)
{
assert( angle1.get() == angle1.get()
and angle2.get() == angle2.get() );
double distance1 = std::fabs( angle1.get()
- angle2.get() );
double distance2 = 2*M_PI - distance1;
if(angle1 <= angle2){
if(distance1 < distance2)
return 1.0;
return -1.0;
}
//Otherwise angle1 > angle2.
if(distance1 < distance2)
return -1.0;
return 1.0;
}
std::ostream& operator << (std::ostream& outs, const Angle& angle_temp)
{
outs << angle_temp.get();
return outs;
}
//Polar_Point
Polar_Point::Polar_Point(const Point& polar_origin_temp,
const Point& point_temp,
double epsilon) : Point(point_temp)
{
polar_origin_ = polar_origin_temp;
if( polar_origin_==polar_origin_
and point_temp==point_temp
and distance(polar_origin_, point_temp) <= epsilon ){
bearing_ = Angle(0.0);
range_ = 0.0;
}
else if( polar_origin_==polar_origin_
and point_temp==point_temp){
bearing_ = Angle( point_temp.y()-polar_origin_temp.y(),
point_temp.x()-polar_origin_temp.x() );
range_ = distance(polar_origin_temp, point_temp);
}
}
void Polar_Point::set_polar_origin(const Point& polar_origin_temp)
{
*this = Polar_Point( polar_origin_temp, Point(x(), y()) );
}
void Polar_Point::set_x(double x_temp)
{
*this = Polar_Point( polar_origin_, Point(x_temp, y()) );
}
void Polar_Point::set_y(double y_temp)
{
*this = Polar_Point( polar_origin_, Point(x(), y_temp) );
}
void Polar_Point::set_range(double range_temp)
{
range_ = range_temp;
x_ = polar_origin_.x()
+ range_*std::cos( bearing_.get() );
y_ = polar_origin_.y()
+ range_*std::sin( bearing_.get() );
}
void Polar_Point::set_bearing(const Angle& bearing_temp)
{
bearing_ = bearing_temp;
x_ = polar_origin_.x()
+ range_*std::cos( bearing_.get() );
y_ = polar_origin_.y()
+ range_*std::sin( bearing_.get() );
}
bool operator == (const Polar_Point& polar_point1,
const Polar_Point& polar_point2)
{
if( polar_point1.polar_origin() == polar_point2.polar_origin()
and polar_point1.range() == polar_point2.range()
and polar_point1.bearing() == polar_point2.bearing()
)
return true;
return false;
}
bool operator != (const Polar_Point& polar_point1,
const Polar_Point& polar_point2)
{
return !( polar_point1 == polar_point2 );
}
bool operator > (const Polar_Point& polar_point1,
const Polar_Point& polar_point2)
{
if( polar_point1.polar_origin() != polar_point1.polar_origin()
or polar_point1.range() != polar_point1.range()
or polar_point1.bearing() != polar_point1.bearing()
or polar_point2.polar_origin() != polar_point2.polar_origin()
or polar_point2.range() != polar_point2.range()
or polar_point2.bearing() != polar_point2.bearing()
)
return false;
if( polar_point1.bearing() > polar_point2.bearing() )
return true;
else if( polar_point1.bearing() == polar_point2.bearing()
and polar_point1.range() > polar_point2.range() )
return true;
return false;
}
bool operator < (const Polar_Point& polar_point1,
const Polar_Point& polar_point2)
{
if( polar_point1.polar_origin() != polar_point1.polar_origin()
or polar_point1.range() != polar_point1.range()
or polar_point1.bearing() != polar_point1.bearing()
or polar_point2.polar_origin() != polar_point2.polar_origin()
or polar_point2.range() != polar_point2.range()
or polar_point2.bearing() != polar_point2.bearing()
)
return false;
if( polar_point1.bearing() < polar_point2.bearing() )
return true;
else if( polar_point1.bearing() == polar_point2.bearing()
and polar_point1.range() < polar_point2.range() )
return true;
return false;
}
bool operator >= (const Polar_Point& polar_point1,
const Polar_Point& polar_point2)
{
if( polar_point1.polar_origin() != polar_point1.polar_origin()
or polar_point1.range() != polar_point1.range()
or polar_point1.bearing() != polar_point1.bearing()
or polar_point2.polar_origin() != polar_point2.polar_origin()
or polar_point2.range() != polar_point2.range()
or polar_point2.bearing() != polar_point2.bearing()
)
return false;
return !(polar_point1<polar_point2);
}
bool operator <= (const Polar_Point& polar_point1,
const Polar_Point& polar_point2)
{
if( polar_point1.polar_origin() != polar_point1.polar_origin()
or polar_point1.range() != polar_point1.range()
or polar_point1.bearing() != polar_point1.bearing()
or polar_point2.polar_origin() != polar_point2.polar_origin()
or polar_point2.range() != polar_point2.range()
or polar_point2.bearing() != polar_point2.bearing()
)
return false;
return !(polar_point1>polar_point2);
}
std::ostream& operator << (std::ostream& outs,
const Polar_Point& polar_point_temp)
{
outs << polar_point_temp.bearing() << " " << polar_point_temp.range();
return outs;
}
//Ray
Ray::Ray(Point base_point_temp, Point bearing_point)
{
assert( !( base_point_temp == bearing_point ) );
base_point_ = base_point_temp;
bearing_ = Angle( bearing_point.y()-base_point_temp.y(),
bearing_point.x()-base_point_temp.x() );
}
bool operator == (const Ray& ray1,
const Ray& ray2)
{
if( ray1.base_point() == ray2.base_point()
and ray1.bearing() == ray2.bearing() )
return true;
else
return false;
}
bool operator != (const Ray& ray1,
const Ray& ray2)
{
return !( ray1 == ray2 );
}
Line_Segment intersection(const Ray ray_temp,
const Line_Segment& line_segment_temp,
double epsilon)
{
assert( ray_temp == ray_temp
and line_segment_temp.size() > 0 );
//First construct a Line_Segment parallel with the Ray which is so
//long, that it's intersection with line_segment_temp will be
//equal to the intersection of ray_temp with line_segment_temp.
double R = distance(ray_temp.base_point(), line_segment_temp)
+ line_segment_temp.length();
Line_Segment seg_approx =
Line_Segment( ray_temp.base_point(), ray_temp.base_point() +
Point( R*std::cos(ray_temp.bearing().get()),
R*std::sin(ray_temp.bearing().get()) ) );
Line_Segment intersect_seg = intersection(line_segment_temp,
seg_approx,
epsilon);
//Make sure point closer to ray_temp's base_point is listed first.
if( intersect_seg.size() == 2
and distance( intersect_seg.first(), ray_temp.base_point() ) >
distance( intersect_seg.second(), ray_temp.base_point() ) ){
intersect_seg.reverse();
}
return intersect_seg;
}
Line_Segment intersection(const Line_Segment& line_segment_temp,
const Ray& ray_temp,
double epsilon)
{
return intersection( ray_temp , line_segment_temp , epsilon );
}
//Polyline
double Polyline::length() const
{
double length_temp = 0;
for(unsigned i=1; i <= vertices_.size()-1; i++)
length_temp += distance( vertices_[i-1] , vertices_[i] );
return length_temp;
}
double Polyline::diameter() const
{
//Precondition: nonempty Polyline.
assert( size() > 0 );
double running_max=0;
for(unsigned i=0; i<size()-1; i++){
for(unsigned j=i+1; j<size(); j++){
if( distance( (*this)[i] , (*this)[j] ) > running_max )
running_max = distance( (*this)[i] , (*this)[j] );
}}
return running_max;
}
Bounding_Box Polyline::bbox () const
{
//Precondition: nonempty Polyline.
assert( vertices_.size() > 0 );
Bounding_Box bounding_box;
double x_min=vertices_[0].x(), x_max=vertices_[0].x(),
y_min=vertices_[0].y(), y_max=vertices_[0].y();
for(unsigned i = 1; i < vertices_.size(); i++){
if(x_min > vertices_[i].x()) { x_min=vertices_[i].x(); }
if(x_max < vertices_[i].x()) { x_max=vertices_[i].x(); }
if(y_min > vertices_[i].y()) { y_min=vertices_[i].y(); }
if(y_max < vertices_[i].y()) { y_max=vertices_[i].y(); }
}
bounding_box.x_min=x_min; bounding_box.x_max=x_max;
bounding_box.y_min=y_min; bounding_box.y_max=y_max;
return bounding_box;
}
void Polyline::eliminate_redundant_vertices(double epsilon)
{
//Trivial case
if(vertices_.size() < 3)
return;
//Store new minimal length list of vertices
std::vector<Point> vertices_temp;
vertices_temp.reserve(vertices_.size());
//Place holders
unsigned first = 0;
unsigned second = 1;
unsigned third = 2;
//Add first vertex
vertices_temp.push_back((*this)[first]);
while( third < vertices_.size() ){
//if second redundant
if( distance( Line_Segment( (*this)[first],
(*this)[third] ) ,
(*this)[second] )
<= epsilon ){
//=>skip it
second = third;
third++;
}
//else second not redundant
else{
//=>add it.
vertices_temp.push_back((*this)[second]);
first = second;
second = third;
third++;
}
}
//Add last vertex
vertices_temp.push_back(vertices_.back());
//Update list of vertices
vertices_ = vertices_temp;
}
void Polyline::reverse()
{
std::reverse( vertices_.begin() , vertices_.end() );
}
std::ostream& operator << (std::ostream& outs,
const Polyline& polyline_temp)
{
for(unsigned i=0; i<polyline_temp.size(); i++)
outs << polyline_temp[i] << std::endl;
return outs;
}
void Polyline::append( const Polyline& polyline ){
vertices_.reserve( vertices_.size() + polyline.vertices_.size() );
for(unsigned i=0; i<polyline.vertices_.size(); i++){
vertices_.push_back( polyline.vertices_[i] );
}
}
//Polygon
Polygon::Polygon (const std::string& filename)
{
std::ifstream fin(filename.c_str());
//if(fin.fail()) { std::cerr << "\x1b[5;31m" << "Input file
//opening failed." << "\x1b[0m\n" << "\a \n"; exit(1);}
assert( !fin.fail() );
Point point_temp;
double x_temp, y_temp;
while (fin >> x_temp and fin >> y_temp){
point_temp.set_x(x_temp);
point_temp.set_y(y_temp);
vertices_.push_back(point_temp);
}
fin.close();
}
Polygon::Polygon(const std::vector<Point>& vertices_temp)
{
vertices_ = vertices_temp;
}
Polygon::Polygon(const Point& point0,
const Point& point1,
const Point& point2)
{
vertices_.push_back(point0);
vertices_.push_back(point1);
vertices_.push_back(point2);
}
unsigned Polygon::r () const
{
int r_count = 0;
if( vertices_.size() > 1 ){
//Use cross product to count right turns.
for(unsigned i=0; i<=n()-1; i++)
if( ((*this)[i+1].x()-(*this)[i].x())
*((*this)[i+2].y()-(*this)[i].y())
- ((*this)[i+1].y()-(*this)[i].y())
*((*this)[i+2].x()-(*this)[i].x()) < 0 )
r_count++;
if( area() < 0 ){
r_count = n() - r_count;
}
}
return r_count;
}
bool Polygon::is_simple(double epsilon) const
{
if(n()==0 or n()==1 or n()==2)
return false;
//Make sure adjacent edges only intersect at a single point.
for(unsigned i=0; i<=n()-1; i++)
if( intersection( Line_Segment((*this)[i],(*this)[i+1]) ,
Line_Segment((*this)[i+1],(*this)[i+2]) ,
epsilon ).size() > 1 )
return false;
//Make sure nonadjacent edges do not intersect.
for(unsigned i=0; i<n()-2; i++)
for(unsigned j=i+2; j<=n()-1; j++)
if( 0!=(j+1)%vertices_.size()
and distance( Line_Segment((*this)[i],(*this)[i+1]) ,
Line_Segment((*this)[j],(*this)[j+1]) ) <= epsilon )
return false;
return true;
}
bool Polygon::is_in_standard_form() const
{
if(vertices_.size() > 1) //if more than one point in the polygon.
for(unsigned i=1; i<vertices_.size(); i++)
if(vertices_[0] > vertices_[i])
return false;
return true;
}
double Polygon::boundary_length() const
{
double length_temp=0;
if(n()==0 or n()==1)
return 0;
for(unsigned i=0; i<n()-1; i++)
length_temp += distance( vertices_[i] , vertices_[i+1] );
length_temp += distance( vertices_[n()-1] ,
vertices_[0] );
return length_temp;
}
double Polygon::area() const
{
double area_temp = 0;
if(n()==0)
return 0;
for(unsigned i=0; i<=n()-1; i++)
area_temp += (*this)[i].x()*(*this)[i+1].y()
- (*this)[i+1].x()*(*this)[i].y();
return area_temp/2.0;
}
Point Polygon::centroid() const
{
assert( vertices_.size() > 0 );
double area_temp=area();
if(area_temp==0)
{ std::cerr << "\x1b[5;31m"
<< "Warning: tried to compute centoid of polygon with zero area!"
<< "\x1b[0m\n" << "\a \n"; exit(1); }
double x_temp=0;
for(unsigned i=0; i<=n()-1; i++)
x_temp += ( (*this)[i].x() + (*this)[i+1].x() )
* ( (*this)[i].x()*(*this)[i+1].y()
- (*this)[i+1].x()*(*this)[i].y() );
double y_temp=0;
for(unsigned i=0; i<=n()-1; i++)
y_temp += ( (*this)[i].y() + (*this)[i+1].y() )
* ( (*this)[i].x()*(*this)[i+1].y()
- (*this)[i+1].x()*(*this)[i].y() );
return Point(x_temp/(6*area_temp), y_temp/(6*area_temp));
}
double Polygon::diameter() const
{
//Precondition: nonempty Polygon.
assert( n() > 0 );
double running_max=0;
for(unsigned i=0; i<n()-1; i++){
for(unsigned j=i+1; j<n(); j++){
if( distance( (*this)[i] , (*this)[j] ) > running_max )
running_max = distance( (*this)[i] , (*this)[j] );
}}
return running_max;
}
Bounding_Box Polygon::bbox () const
{
//Precondition: nonempty Polygon.
assert( vertices_.size() > 0 );
Bounding_Box bounding_box;
double x_min=vertices_[0].x(), x_max=vertices_[0].x(),
y_min=vertices_[0].y(), y_max=vertices_[0].y();
for(unsigned i = 1; i < vertices_.size(); i++){
if(x_min > vertices_[i].x()) { x_min=vertices_[i].x(); }
if(x_max < vertices_[i].x()) { x_max=vertices_[i].x(); }
if(y_min > vertices_[i].y()) { y_min=vertices_[i].y(); }
if(y_max < vertices_[i].y()) { y_max=vertices_[i].y(); }
}
bounding_box.x_min=x_min; bounding_box.x_max=x_max;
bounding_box.y_min=y_min; bounding_box.y_max=y_max;
return bounding_box;
}
std::vector<Point> Polygon::random_points(const unsigned& count,
double epsilon) const
{
//Precondition: nonempty Polygon.
assert( vertices_.size() > 0 );
Bounding_Box bounding_box = bbox();
std::vector<Point> pts_in_polygon; pts_in_polygon.reserve(count);
Point pt_temp( uniform_random_sample(bounding_box.x_min,
bounding_box.x_max),
uniform_random_sample(bounding_box.y_min,
bounding_box.y_max) );
while(pts_in_polygon.size() < count){
while(!pt_temp.in(*this, epsilon)){
pt_temp.set_x( uniform_random_sample(bounding_box.x_min,
bounding_box.x_max) );
pt_temp.set_y( uniform_random_sample(bounding_box.y_min,
bounding_box.y_max) );
}
pts_in_polygon.push_back(pt_temp);
pt_temp.set_x( uniform_random_sample(bounding_box.x_min,
bounding_box.x_max) );
pt_temp.set_y( uniform_random_sample(bounding_box.y_min,
bounding_box.y_max) );
}
return pts_in_polygon;
}
void Polygon::write_to_file(const std::string& filename,
int fios_precision_temp)
{
assert( fios_precision_temp >= 1 );
std::ofstream fout( filename.c_str() );
//fout.open( filename.c_str() ); //Alternatives.
//fout << *this;
fout.setf(std::ios::fixed);
fout.setf(std::ios::showpoint);
fout.precision(fios_precision_temp);
for(unsigned i=0; i<n(); i++)
fout << vertices_[i] << std::endl;
fout.close();
}
void Polygon::enforce_standard_form()
{
int point_count=vertices_.size();
if(point_count > 1){ //if more than one point in the polygon.
std::vector<Point> vertices_temp;
vertices_temp.reserve(point_count);
//Find index of lexicographically smallest point.
int index_of_smallest=0;
int i; //counter.
for(i=1; i<point_count; i++)
if(vertices_[i]<vertices_[index_of_smallest])
index_of_smallest=i;
//Fill vertices_temp starting with lex. smallest.
for(i=index_of_smallest; i<point_count; i++)
vertices_temp.push_back(vertices_[i]);
for(i=0; i<index_of_smallest; i++)
vertices_temp.push_back(vertices_[i]);
vertices_=vertices_temp;
}
}
void Polygon::eliminate_redundant_vertices(double epsilon)
{
//Degenerate case.
if( vertices_.size() < 4 )
return;
//Store new minimal length list of vertices.
std::vector<Point> vertices_temp;
vertices_temp.reserve( vertices_.size() );
//Place holders.
unsigned first = 0;
unsigned second = 1;
unsigned third = 2;
while( third <= vertices_.size() ){
//if second is redundant
if( distance( Line_Segment( (*this)[first],
(*this)[third] ) ,
(*this)[second] )
<= epsilon ){
//=>skip it
second = third;
third++;
}
//else second not redundant
else{
//=>add it
vertices_temp.push_back( (*this)[second] );
first = second;
second = third;
third++;
}
}
//decide whether to add original first point
if( distance( Line_Segment( vertices_temp.front(),
vertices_temp.back() ) ,
vertices_.front() )
> epsilon )
vertices_temp.push_back( vertices_.front() );
//Update list of vertices.
vertices_ = vertices_temp;
}
void Polygon::reverse()
{
if( n() > 2 )
std::reverse( ++vertices_.begin() , vertices_.end() );
}
bool operator == (Polygon polygon1, Polygon polygon2)
{
if( polygon1.n() != polygon2.n()
or polygon1.n() == 0
or polygon2.n() == 0 )
return false;
for(unsigned i=0; i<polygon1.n(); i++)
if( !(polygon1[i] == polygon2[i]) )
return false;
return true;
}
bool operator != (Polygon polygon1, Polygon polygon2)
{
return !( polygon1 == polygon2 );
}
bool equivalent(Polygon polygon1, Polygon polygon2, double epsilon)
{
if( polygon1.n() == 0 or polygon2.n() == 0 )
return false;
if( polygon1.n() != polygon2.n() )
return false;
//Try all cyclic matches
unsigned n = polygon1.n();//=polygon2.n()
for( unsigned offset = 0 ; offset < n ; offset++ ){
bool successful_match = true;
for(unsigned i=0; i<n; i++){
if( distance( polygon1[ i ] , polygon2[ i + offset ] ) > epsilon )
{ successful_match = false; break; }
}
if( successful_match )
return true;
}
return false;
}
double boundary_distance(const Polygon& polygon1, const Polygon& polygon2)
{
assert( polygon1.n() > 0 and polygon2.n() > 0 );
//Handle single point degeneracy.
if(polygon1.n() == 1)
return boundary_distance(polygon1[0], polygon2);
else if(polygon2.n() == 1)
return boundary_distance(polygon2[0], polygon1);
//Handle cases where each polygon has at least 2 points.
//Initialize to an upper bound.
double running_min = boundary_distance(polygon1[0], polygon2);
double distance_temp;
//Loop over all possible pairs of line segments.
for(unsigned i=0; i<=polygon1.n()-1; i++){
for(unsigned j=0; j<=polygon2.n()-1; j++){
distance_temp = distance( Line_Segment(polygon1[i], polygon1[i+1]) ,
Line_Segment(polygon2[j], polygon2[j+1]) );
if(distance_temp < running_min)
running_min = distance_temp;
}}
return running_min;
}
std::ostream& operator << (std::ostream& outs,
const Polygon& polygon_temp)
{
for(unsigned i=0; i<polygon_temp.n(); i++)
outs << polygon_temp[i] << std::endl;
return outs;
}
//Environment
Environment::Environment(const std::vector<Polygon>& polygons)
{
outer_boundary_ = polygons[0];
for(unsigned i=1; i<polygons.size(); i++)
holes_.push_back( polygons[i] );
update_flattened_index_key();
}
Environment::Environment(const std::string& filename)
{
std::ifstream fin(filename.c_str());
//if(fin.fail()) { std::cerr << "\x1b[5;31m" << "Input file
//opening failed." << "\x1b[0m\n" << "\a \n"; exit(1);}
assert( !fin.fail() );
//Temporary vars for numbers to be read from file.
double x_temp, y_temp;
std::vector<Point> vertices_temp;
//Skip comments
while( fin.peek() == '/' )
fin.ignore(200,'\n');
//Read outer_boundary.
while ( fin.peek() != '/' ){
fin >> x_temp >> y_temp;
//Skip to next line.
fin.ignore(1);
if( fin.eof() )
{
outer_boundary_.set_vertices(vertices_temp);
fin.close();
update_flattened_index_key(); return;
}
vertices_temp.push_back( Point(x_temp, y_temp) );
}
outer_boundary_.set_vertices(vertices_temp);
vertices_temp.clear();
//Read holes.
Polygon polygon_temp;
while(1){
//Skip comments
while( fin.peek() == '/' )
fin.ignore(200,'\n');
if( fin.eof() )
{ fin.close(); update_flattened_index_key(); return; }
while( fin.peek() != '/' ){
fin >> x_temp >> y_temp;
if( fin.eof() )
{
polygon_temp.set_vertices(vertices_temp);
holes_.push_back(polygon_temp);
fin.close();
update_flattened_index_key(); return;
}
vertices_temp.push_back( Point(x_temp, y_temp) );
//Skips to next line.
fin.ignore(1);
}
polygon_temp.set_vertices(vertices_temp);
holes_.push_back(polygon_temp);
vertices_temp.clear();
}
update_flattened_index_key();
}
const Point& Environment::operator () (unsigned k) const
{
//std::pair<unsigned,unsigned> ij(one_to_two(k));
std::pair<unsigned,unsigned> ij( flattened_index_key_[k] );
return (*this)[ ij.first ][ ij.second ];
}
unsigned Environment::n() const
{
int n_count = 0;
n_count = outer_boundary_.n();
for(unsigned i=0; i<h(); i++)
n_count += holes_[i].n();
return n_count;
}
unsigned Environment::r() const
{
int r_count = 0;
Polygon polygon_temp;
r_count = outer_boundary_.r();
for(unsigned i=0; i<h(); i++){
r_count += holes_[i].n() - holes_[i].r();
}
return r_count;
}
bool Environment::is_in_standard_form() const
{
if( outer_boundary_.is_in_standard_form() == false
or outer_boundary_.area() < 0 )
return false;
for(unsigned i=0; i<holes_.size(); i++)
if( holes_[i].is_in_standard_form() == false
or holes_[i].area() > 0 )
return false;
return true;
}
bool Environment::is_valid(double epsilon) const
{
if( n() <= 2 )
return false;
//Check all Polygons are simple.
if( !outer_boundary_.is_simple(epsilon) ){
std::cerr << std::endl << "\x1b[31m"
<< "The outer boundary is not simple."
<< "\x1b[0m" << std::endl;
return false;
}
for(unsigned i=0; i<h(); i++)
if( !holes_[i].is_simple(epsilon) ){
std::cerr << std::endl << "\x1b[31m"
<< "Hole " << i << " is not simple."
<< "\x1b[0m" << std::endl;
return false;
}
//Check none of the Polygons' boundaries intersect w/in epsilon.
for(unsigned i=0; i<h(); i++)
if( boundary_distance(outer_boundary_, holes_[i]) <= epsilon ){
std::cerr << std::endl << "\x1b[31m"
<< "The outer boundary intersects the boundary of hole " << i << "."
<< "\x1b[0m" << std::endl;
return false;
}
for(unsigned i=0; i<h(); i++)
for(unsigned j=i+1; j<h(); j++)
if( boundary_distance(holes_[i], holes_[j]) <= epsilon ){
std::cerr << std::endl << "\x1b[31m"
<< "The boundary of hole " << i
<< " intersects the boundary of hole " << j << "."
<< "\x1b[0m" << std::endl;
return false;
}
//Check that the vertices of each hole are in the outside_boundary
//and not in any other holes.
//Loop over holes.
for(unsigned i=0; i<h(); i++){
//Loop over vertices of a hole
for(unsigned j=0; j<holes_[i].n(); j++){
if( !holes_[i][j].in(outer_boundary_, epsilon) ){
std::cerr << std::endl << "\x1b[31m"
<< "Vertex " << j << " of hole " << i
<< " is not within the outer boundary."
<< "\x1b[0m" << std::endl;
return false;
}
//Second loop over holes.
for(unsigned k=0; k<h(); k++)
if( i!=k and holes_[i][j].in(holes_[k], epsilon) ){
std::cerr << std::endl << "\x1b[31m"
<< "Vertex " << j
<< " of hole " << i
<< " is in hole " << k << "."
<< "\x1b[0m" << std::endl;
return false;
}
}
}
//Check outer_boundary is ccw and holes are cw.
if( outer_boundary_.area() <= 0 ){
std::cerr << std::endl << "\x1b[31m"
<< "The outer boundary vertices are not listed ccw."
<< "\x1b[0m" << std::endl;
return false;
}
for(unsigned i=0; i<h(); i++)
if( holes_[i].area() >= 0 ){
std::cerr << std::endl << "\x1b[31m"
<< "The vertices of hole " << i << " are not listed cw."
<< "\x1b[0m" << std::endl;
return false;
}
return true;
}
double Environment::boundary_length() const
{
//Precondition: nonempty Environment.
assert( outer_boundary_.n() > 0 );
double length_temp = outer_boundary_.boundary_length();
for(unsigned i=0; i<h(); i++)
length_temp += holes_[i].boundary_length();
return length_temp;
}
double Environment::area() const
{
double area_temp = outer_boundary_.area();
for(unsigned i=0; i<h(); i++)
area_temp += holes_[i].area();
return area_temp;
}
std::vector<Point> Environment::random_points(const unsigned& count,
double epsilon) const
{
assert( area() > 0 );
Bounding_Box bounding_box = bbox();
std::vector<Point> pts_in_environment;
pts_in_environment.reserve(count);
Point pt_temp( uniform_random_sample(bounding_box.x_min,
bounding_box.x_max),
uniform_random_sample(bounding_box.y_min,
bounding_box.y_max) );
while(pts_in_environment.size() < count){
while(!pt_temp.in(*this, epsilon)){
pt_temp.set_x( uniform_random_sample(bounding_box.x_min,
bounding_box.x_max) );
pt_temp.set_y( uniform_random_sample(bounding_box.y_min,
bounding_box.y_max) );
}
pts_in_environment.push_back(pt_temp);
pt_temp.set_x( uniform_random_sample(bounding_box.x_min,
bounding_box.x_max) );
pt_temp.set_y( uniform_random_sample(bounding_box.y_min,
bounding_box.y_max) );
}
return pts_in_environment;
}
Polyline Environment::shortest_path(const Point& start,
const Point& finish,
const Visibility_Graph& visibility_graph,
double epsilon)
{
//true => data printed to terminal
//false => silent
const bool PRINTING_DEBUG_DATA = false;
//For now, just find one shortest path, later change this to a
//vector to find all shortest paths (w/in epsilon).
Polyline shortest_path_output;
Visibility_Polygon start_visibility_polygon(start, *this, epsilon);
//Trivial cases
if( distance(start,finish) <= epsilon ){
shortest_path_output.push_back(start);
return shortest_path_output;
}
else if( finish.in(start_visibility_polygon, epsilon) ){
shortest_path_output.push_back(start);
shortest_path_output.push_back(finish);
return shortest_path_output;
}
Visibility_Polygon finish_visibility_polygon(finish, *this, epsilon);
//Connect start and finish Points to the visibility graph
bool *start_visible; //start row of visibility graph
bool *finish_visible; //finish row of visibility graph
start_visible = new bool[n()];
finish_visible = new bool[n()];
for(unsigned k=0; k<n(); k++){
if( (*this)(k).in( start_visibility_polygon , epsilon ) )
start_visible[k] = true;
else
start_visible[k] = false;
if( (*this)(k).in( finish_visibility_polygon , epsilon ) )
finish_visible[k] = true;
else
finish_visible[k] = false;
}
//Initialize search tree of visited nodes
std::list<Shortest_Path_Node> T;
//:WARNING:
//If T is a vector it is crucial to make T large enough that it
//will not be resized. If T were resized, any iterators pointing
//to its contents would be invalidated, thus causing the program
//to fail.
//T.reserve( n() + 3 );
//Initialize priority queue of unexpanded nodes
std::set<Shortest_Path_Node> Q;
//Construct initial node
Shortest_Path_Node current_node;
//convention vertex_index == n() => corresponds to start Point
//vertex_index == n() + 1 => corresponds to finish Point
current_node.vertex_index = n();
current_node.cost_to_come = 0;
current_node.estimated_cost_to_go = distance( start , finish );
//Put in T and on Q
T.push_back( current_node );
T.begin()->search_tree_location = T.begin();
current_node.search_tree_location = T.begin();
T.begin()->parent_search_tree_location = T.begin();
current_node.parent_search_tree_location = T.begin();
Q.insert( current_node );
//Initialize temporary variables
Shortest_Path_Node child; //children of current_node
std::vector<Shortest_Path_Node> children;
//flags
bool solution_found = false;
bool child_already_visited = false;
//-----------Begin Main Loop-----------
while( !Q.empty() ){
//Pop top element off Q onto current_node
current_node = *Q.begin(); Q.erase( Q.begin() );
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<<"=============="
<<" current_node just poped off of Q "
<<"=============="
<< std::endl;
current_node.print();
std::cout << std::endl;
}
//Check for goal state
//(if current node corresponds to finish)
if( current_node.vertex_index == n() + 1 ){
if( PRINTING_DEBUG_DATA ){
std::cout <<"solution found!"
<< std::endl
<< std::endl;
}
solution_found = true;
break;
}
//Expand current_node (compute children)
children.clear();
if( PRINTING_DEBUG_DATA ){
std::cout << "-------------------------------------------"
<< std::endl
<< "Expanding Current Node (Computing Children)"
<< std::endl
<< "current size of search tree T = "
<< T.size()
<< std::endl
<< "-------------------------------------------"
<< std::endl;
}
//if current_node corresponds to start
if( current_node.vertex_index == n() ){
//loop over environment vertices
for(unsigned i=0; i < n(); i++){
if( start_visible[i] ){
child.vertex_index = i;
child.parent_search_tree_location
= current_node.search_tree_location;
child.cost_to_come = distance( start , (*this)(i) );
child.estimated_cost_to_go = distance( (*this)(i) , finish );
children.push_back( child );
if( PRINTING_DEBUG_DATA ){
std::cout << std::endl << "computed child: "
<< std::endl;
child.print();
}
}
}
}
//else current_node corresponds to a vertex of the environment
else{
//check which environment vertices are visible
for(unsigned i=0; i < n(); i++){
if( current_node.vertex_index != i )
if( visibility_graph( current_node.vertex_index , i ) ){
child.vertex_index = i;
child.parent_search_tree_location
= current_node.search_tree_location;
child.cost_to_come = current_node.cost_to_come
+ distance( (*this)(current_node.vertex_index),
(*this)(i) );
child.estimated_cost_to_go = distance( (*this)(i) , finish );
children.push_back( child );
if( PRINTING_DEBUG_DATA ){
std::cout << std::endl << "computed child: "
<< std::endl;
child.print();
}
}
}
//check if finish is visible
if( finish_visible[ current_node.vertex_index ] ){
child.vertex_index = n() + 1;
child.parent_search_tree_location
= current_node.search_tree_location;
child.cost_to_come = current_node.cost_to_come
+ distance( (*this)(current_node.vertex_index) , finish );
child.estimated_cost_to_go = 0;
children.push_back( child );
if( PRINTING_DEBUG_DATA ){
std::cout << std::endl << "computed child: "
<< std::endl;
child.print();
}
}
}
if( PRINTING_DEBUG_DATA ){
std::cout << std::endl
<<"-----------------------------------------"
<< std::endl
<< "Processing " << children.size()
<< " children" << std::endl
<< "-----------------------------------------"
<< std::endl;
}
//Process children
for( std::vector<Shortest_Path_Node>::iterator
children_itr = children.begin();
children_itr != children.end();
children_itr++ ){
child_already_visited = false;
if( PRINTING_DEBUG_DATA ){
std::cout << std::endl << "current child being processed: "
<< std::endl;
children_itr->print();
}
//Check if child state has already been visited
//(by looking in search tree T)
for( std::list<Shortest_Path_Node>::iterator T_itr = T.begin();
T_itr != T.end(); T_itr++ ){
if( children_itr->vertex_index
== T_itr->vertex_index ){
children_itr->search_tree_location = T_itr;
child_already_visited = true;
break;
}
}
if( !child_already_visited ){
//Add child to search tree T
T.push_back( *children_itr );
(--T.end())->search_tree_location = --T.end();
children_itr->search_tree_location = --T.end();
Q.insert( *children_itr );
}
else if( children_itr->search_tree_location->cost_to_come >
children_itr->cost_to_come ){
//redirect parent pointer in search tree
children_itr->search_tree_location->parent_search_tree_location
= children_itr->parent_search_tree_location;
//and update cost data
children_itr->search_tree_location->cost_to_come
= children_itr->cost_to_come;
//update Q
for(std::set<Shortest_Path_Node>::iterator
Q_itr = Q.begin();
Q_itr!= Q.end();
Q_itr++){
if( children_itr->vertex_index == Q_itr->vertex_index ){
Q.erase( Q_itr );
break;
}
}
Q.insert( *children_itr );
}
//If not already visited, insert into Q
if( !child_already_visited )
Q.insert( *children_itr );
if( PRINTING_DEBUG_DATA ){
std::cout << "child already visited? "
<< child_already_visited
<< std::endl;
}
}
}
//-----------End Main Loop-----------
//Recover solution
if( solution_found ){
shortest_path_output.push_back( finish );
std::list<Shortest_Path_Node>::iterator
backtrace_itr = current_node.parent_search_tree_location;
Point waypoint;
if( PRINTING_DEBUG_DATA ){
std::cout << "----------------------------" << std::endl
<< "backtracing to find solution" << std::endl
<< "----------------------------" << std::endl;
}
while( true ){
if( PRINTING_DEBUG_DATA ){
std::cout << "backtrace node is "
<< std::endl;
backtrace_itr->print();
std::cout << std::endl;
}
if( backtrace_itr->vertex_index < n() )
waypoint = (*this)( backtrace_itr->vertex_index );
else if( backtrace_itr->vertex_index == n() )
waypoint = start;
//Add vertex if not redundant
if( shortest_path_output.size() > 0
and distance( shortest_path_output[ shortest_path_output.size()
- 1 ],
waypoint ) > epsilon )
shortest_path_output.push_back( waypoint );
if( backtrace_itr->cost_to_come == 0 )
break;
backtrace_itr = backtrace_itr->parent_search_tree_location;
}
shortest_path_output.reverse();
}
//free memory
delete [] start_visible;
delete [] finish_visible;
//shortest_path_output.eliminate_redundant_vertices( epsilon );
//May not be desirable to eliminate redundant vertices, because
//those redundant vertices can make successive waypoints along the
//shortest path robustly visible (and thus easier for a robot to
//navigate)
return shortest_path_output;
}
Polyline Environment::shortest_path(const Point& start,
const Point& finish,
double epsilon)
{
return shortest_path( start,
finish,
Visibility_Graph(*this, epsilon),
epsilon );
}
void Environment::write_to_file(const std::string& filename,
int fios_precision_temp)
{
assert( fios_precision_temp >= 1 );
std::ofstream fout( filename.c_str() );
//fout.open( filename.c_str() ); //Alternatives.
//fout << *this;
fout.setf(std::ios::fixed);
fout.setf(std::ios::showpoint);
fout.precision(fios_precision_temp);
fout << "//Environment Model" << std::endl;
fout << "//Outer Boundary" << std::endl << outer_boundary_;
for(unsigned i=0; i<h(); i++)
{
fout << "//Hole" << std::endl << holes_[i];
}
//fout << "//EOF marker";
fout.close();
}
Point& Environment::operator () (unsigned k)
{
//std::pair<unsigned,unsigned> ij( one_to_two(k) );
std::pair<unsigned,unsigned> ij( flattened_index_key_[k] );
return (*this)[ ij.first ][ ij.second ];
}
void Environment::enforce_standard_form()
{
if( outer_boundary_.area() < 0 )
outer_boundary_.reverse();
outer_boundary_.enforce_standard_form();
for(unsigned i=0; i<h(); i++){
if( holes_[i].area() > 0 )
holes_[i].reverse();
holes_[i].enforce_standard_form();
}
}
void Environment::eliminate_redundant_vertices(double epsilon)
{
outer_boundary_.eliminate_redundant_vertices(epsilon);
for(unsigned i=0; i<holes_.size(); i++)
holes_[i].eliminate_redundant_vertices(epsilon);
update_flattened_index_key();
}
void Environment::reverse_holes()
{
for(unsigned i=0; i < holes_.size(); i++)
holes_[i].reverse();
}
void Environment::update_flattened_index_key()
{
flattened_index_key_.clear();
std::pair<unsigned, unsigned> pair_temp;
for(unsigned i=0; i<=h(); i++){
for(unsigned j=0; j<(*this)[i].n(); j++){
pair_temp.first = i;
pair_temp.second = j;
flattened_index_key_.push_back( pair_temp );
}}
}
std::pair<unsigned,unsigned> Environment::one_to_two(unsigned k) const
{
std::pair<unsigned,unsigned> two(0,0);
//Strategy: add up vertex count of each Polygon (outer boundary +
//holes) until greater than k
unsigned current_polygon_index = 0;
unsigned vertex_count_up_to_current_polygon = (*this)[0].n();
unsigned vertex_count_up_to_last_polygon = 0;
while( k >= vertex_count_up_to_current_polygon
and current_polygon_index < (*this).h() ){
current_polygon_index++;
two.first = two.first + 1;
vertex_count_up_to_last_polygon = vertex_count_up_to_current_polygon;
vertex_count_up_to_current_polygon += (*this)[current_polygon_index].n();
}
two.second = k - vertex_count_up_to_last_polygon;
return two;
}
std::ostream& operator << (std::ostream& outs,
const Environment& environment_temp)
{
outs << "//Environment Model" << std::endl;
outs << "//Outer Boundary" << std::endl << environment_temp[0];
for(unsigned i=1; i<=environment_temp.h(); i++){
outs << "//Hole" << std::endl << environment_temp[i];
}
//outs << "//EOF marker";
return outs;
}
//Guards
Guards::Guards(const std::string& filename)
{
std::ifstream fin(filename.c_str());
//if(fin.fail()) { std::cerr << "\x1b[5;31m" << "Input file
//opening failed." << "\x1b[0m\n" << "\a \n"; exit(1);}
assert( !fin.fail() );
//Temp vars for numbers to be read from file.
double x_temp, y_temp;
//Skip comments
while( fin.peek() == '/' )
fin.ignore(200,'\n');
//Read positions.
while (1){
fin >> x_temp >> y_temp;
if( fin.eof() )
{ fin.close(); return; }
positions_.push_back( Point(x_temp, y_temp) );
//Skip to next line.
fin.ignore(1);
//Skip comments
while( fin.peek() == '/' )
fin.ignore(200,'\n');
}
}
bool Guards::are_lex_ordered() const
{
//if more than one guard.
if(positions_.size() > 1)
for(unsigned i=0; i<positions_.size()-1; i++)
if(positions_[i] > positions_[i+1])
return false;
return true;
}
bool Guards::noncolocated(double epsilon) const
{
for(unsigned i=0; i<positions_.size(); i++)
for(unsigned j=i+1; j<positions_.size(); j++)
if( distance(positions_[i], positions_[j]) <= epsilon )
return false;
return true;
}
bool Guards::in(const Polygon& polygon_temp, double epsilon) const
{
for(unsigned i=0; i<positions_.size(); i++)
if(!positions_[i].in(polygon_temp, epsilon))
return false;
return true;
}
bool Guards::in(const Environment& environment_temp, double epsilon) const
{
for(unsigned i=0; i<positions_.size(); i++)
if(!positions_[i].in(environment_temp, epsilon))
return false;
return true;
}
double Guards::diameter() const
{
//Precondition: more than 0 guards
assert( N() > 0 );
double running_max=0;
for(unsigned i=0; i<N()-1; i++){
for(unsigned j=i+1; j<N(); j++){
if( distance( (*this)[i] , (*this)[j] ) > running_max )
running_max = distance( (*this)[i] , (*this)[j] );
}}
return running_max;
}
Bounding_Box Guards::bbox() const
{
//Precondition: nonempty Guard set
assert( positions_.size() > 0 );
Bounding_Box bounding_box;
double x_min=positions_[0].x(), x_max=positions_[0].x(),
y_min=positions_[0].y(), y_max=positions_[0].y();
for(unsigned i = 1; i < positions_.size(); i++){
if(x_min > positions_[i].x()) { x_min=positions_[i].x(); }
if(x_max < positions_[i].x()) { x_max=positions_[i].x(); }
if(y_min > positions_[i].y()) { y_min=positions_[i].y(); }
if(y_max < positions_[i].y()) { y_max=positions_[i].y(); }
}
bounding_box.x_min=x_min; bounding_box.x_max=x_max;
bounding_box.y_min=y_min; bounding_box.y_max=y_max;
return bounding_box;
}
void Guards::write_to_file(const std::string& filename,
int fios_precision_temp)
{
assert( fios_precision_temp >= 1 );
std::ofstream fout( filename.c_str() );
//fout.open( filename.c_str() ); //Alternatives.
//fout << *this;
fout.setf(std::ios::fixed);
fout.setf(std::ios::showpoint);
fout.precision(fios_precision_temp);
fout << "//Guard Positions" << std::endl;
for(unsigned i=0; i<positions_.size(); i++)
fout << positions_[i].x() << " " << positions_[i].y() << std::endl;
//fout << "//EOF marker";
fout.close();
}
void Guards::enforce_lex_order()
{
//std::stable_sort(positions_.begin(), positions_.end());
std::sort(positions_.begin(), positions_.end());
}
void Guards::reverse()
{
std::reverse( positions_.begin() , positions_.end() );
}
void Guards::snap_to_vertices_of(const Environment& environment_temp,
double epsilon)
{
for(unsigned i=0; i<positions_.size(); i++)
positions_[i].snap_to_vertices_of(environment_temp);
}
void Guards::snap_to_vertices_of(const Polygon& polygon_temp,
double epsilon)
{
for(unsigned i=0; i<positions_.size(); i++)
positions_[i].snap_to_vertices_of(polygon_temp);
}
void Guards::snap_to_boundary_of(const Environment& environment_temp,
double epsilon)
{
for(unsigned i=0; i<positions_.size(); i++)
positions_[i].snap_to_boundary_of(environment_temp);
}
void Guards::snap_to_boundary_of(const Polygon& polygon_temp,
double epsilon)
{
for(unsigned i=0; i<positions_.size(); i++)
positions_[i].snap_to_boundary_of(polygon_temp);
}
std::ostream& operator << (std::ostream& outs, const Guards& guards)
{
outs << "//Guard Positions" << std::endl;
for(unsigned i=0; i<guards.N(); i++)
outs << guards[i].x() << " " << guards[i].y() << std::endl;
//outs << "//EOF marker";
return outs;
}
//Visibility_Polygon
bool Visibility_Polygon::is_spike( const Point& observer,
const Point& point1,
const Point& point2,
const Point& point3,
double epsilon) const
{
return(
//Make sure observer not colocated with any of the points.
distance( observer , point1 ) > epsilon
and distance( observer , point2 ) > epsilon
and distance( observer , point3 ) > epsilon
//Test whether there is a spike with point2 as the tip
and ( ( distance(observer,point2)
>= distance(observer,point1)
and distance(observer,point2)
>= distance(observer,point3) )
or ( distance(observer,point2)
<= distance(observer,point1)
and distance(observer,point2)
<= distance(observer,point3) ) )
//and the pike is sufficiently sharp,
and std::max( distance( Ray(observer, point1), point2 ),
distance( Ray(observer, point3), point2 ) )
<= epsilon
);
//Formerly used
//std::fabs( Polygon(point1, point2, point3).area() ) < epsilon
}
void Visibility_Polygon::chop_spikes_at_back(const Point& observer,
double epsilon)
{
//Eliminate "special case" vertices of the visibility polygon.
//While the top three vertices form a spike.
while( vertices_.size() >= 3
and is_spike( observer,
vertices_[vertices_.size()-3],
vertices_[vertices_.size()-2],
vertices_[vertices_.size()-1], epsilon ) ){
vertices_[vertices_.size()-2] = vertices_[vertices_.size()-1];
vertices_.pop_back();
}
}
void Visibility_Polygon::chop_spikes_at_wrap_around(const Point& observer,
double epsilon)
{
//Eliminate "special case" vertices of the visibility polygon at
//wrap-around. While the there's a spike at the wrap-around,
while( vertices_.size() >= 3
and is_spike( observer,
vertices_[vertices_.size()-2],
vertices_[vertices_.size()-1],
vertices_[0], epsilon ) ){
//Chop off the tip of the spike.
vertices_.pop_back();
}
}
void Visibility_Polygon::chop_spikes(const Point& observer,
double epsilon)
{
std::set<Point> spike_tips;
std::vector<Point> vertices_temp;
//Middle point is potentially the tip of a spike
for(unsigned i=0; i<vertices_.size(); i++)
if( distance( (*this)[i+2],
Line_Segment( (*this)[i], (*this)[i+1] ) )
<= epsilon
or
distance( (*this)[i],
Line_Segment( (*this)[i+1], (*this)[i+2] ) )
<= epsilon )
spike_tips.insert( (*this)[i+1] );
for(unsigned i=0; i<vertices_.size(); i++)
if( spike_tips.find(vertices_[i]) == spike_tips.end() )
vertices_temp.push_back( vertices_[i] );
vertices_.swap( vertices_temp );
}
void Visibility_Polygon::
print_cv_and_ae(const Polar_Point_With_Edge_Info& current_vertex,
const std::list<Polar_Edge>::iterator&
active_edge)
{
std::cout << " current_vertex [x y bearing range is_first] = ["
<< current_vertex.x() << " "
<< current_vertex.y() << " "
<< current_vertex.bearing() << " "
<< current_vertex.range() << " "
<< current_vertex.is_first << "]" << std::endl;
std::cout << "1st point of current_vertex's edge [x y bearing range] = ["
<< (current_vertex.incident_edge->first).x() << " "
<< (current_vertex.incident_edge->first).y() << " "
<< (current_vertex.incident_edge->first).bearing() << " "
<< (current_vertex.incident_edge->first).range() << "]"
<< std::endl;
std::cout << "2nd point of current_vertex's edge [x y bearing range] = ["
<< (current_vertex.incident_edge->second).x() << " "
<< (current_vertex.incident_edge->second).y() << " "
<< (current_vertex.incident_edge->second).bearing() << " "
<< (current_vertex.incident_edge->second).range() << "]"
<< std::endl;
std::cout << " 1st point of active_edge [x y bearing range] = ["
<< (active_edge->first).x() << " "
<< (active_edge->first).y() << " "
<< (active_edge->first).bearing() << " "
<< (active_edge->first).range() << "]" << std::endl;
std::cout << " 2nd point of active_edge [x y bearing range] = ["
<< (active_edge->second).x() << " "
<< (active_edge->second).y() << " "
<< (active_edge->second).bearing() << " "
<< (active_edge->second).range() << "]" << std::endl;
}
Visibility_Polygon::Visibility_Polygon(const Point& observer,
const Environment& environment_temp,
double epsilon)
: observer_(observer)
{
//Visibility polygon algorithm for environments with holes
//Radial line (AKA angular plane) sweep technique.
//
//Based on algorithms described in
//
//[1] "Automated Camera Layout to Satisfy Task-Specific and
//Floorplan-Specific Coverage Requirements" by Ugur Murat Erdem
//and Stan Scarloff, April 15, 2004
//available at BUCS Technical Report Archive:
//http://www.cs.bu.edu/techreports/pdf/2004-015-camera-layout.pdf
//
//[2] "Art Gallery Theorems and Algorithms" by Joseph O'Rourke
//
//[3] "Visibility Algorithms in the Plane" by Ghosh
//
//We define a k-point is a point seen on the other side of a
//visibility occluding corner. This name is appropriate because
//the vertical line in the letter "k" is like a line-of-sight past
//the corner of the "k".
//
//Preconditions:
//(1) the Environment is epsilon-valid,
//(2) the Point observer is actually in the Environment
// environment_temp,
//(3) the guard has been epsilon-snapped to the boundary, followed
// by vertices of the environment (the order of the snapping
// is important).
//
//:WARNING:
//For efficiency, the assertions corresponding to these
//preconditions have been excluded.
//
//assert( environment_temp.is_valid(epsilon) );
//assert( environment_temp.is_in_standard_form() );
//assert( observer.in(environment_temp, epsilon) );
//true => data printed to terminal
//false => silent
const bool PRINTING_DEBUG_DATA = false;
//The visibility polygon cannot have more vertices than the environment.
vertices_.reserve( environment_temp.n() );
//
//--------PREPROCESSING--------
//
//Construct a POLAR EDGE LIST from environment_temp's outer
//boundary and holes. During this construction, those edges are
//split which either (1) cross the ray emanating from the observer
//parallel to the x-axis (of world coords), or (2) contain the
//observer in their relative interior (w/in epsilon). Also, edges
//having first vertex bearing >= second vertex bearing are
//eliminated because they cannot possibly contribute to the
//visibility polygon.
std::list<Polar_Edge> elp;
Polar_Point ppoint1, ppoint2;
Polar_Point split_bottom, split_top;
double t;
//If the observer is standing on the Enviroment boundary with its
//back to the wall, these will be the bearings of the next vertex
//to the right and to the left, respectively.
Angle right_wall_bearing;
Angle left_wall_bearing;
for(unsigned i=0; i<=environment_temp.h(); i++){
for(unsigned j=0; j<environment_temp[i].n(); j++){
ppoint1 = Polar_Point( observer, environment_temp[i][j] );
ppoint2 = Polar_Point( observer, environment_temp[i][j+1] );
//If the observer is in the relative interior of the edge.
if( observer.in_relative_interior_of( Line_Segment(ppoint1, ppoint2),
epsilon ) ){
//Split the edge at the observer and add the resulting two
//edges to elp (the polar edge list).
split_bottom = Polar_Point(observer, observer);
split_top = Polar_Point(observer, observer);
if( ppoint2.bearing() == Angle(0.0) )
ppoint2.set_bearing_to_2pi();
left_wall_bearing = ppoint1.bearing();
right_wall_bearing = ppoint2.bearing();
elp.push_back( Polar_Edge( ppoint1 , split_bottom ) );
elp.push_back( Polar_Edge( split_top , ppoint2 ) );
continue;
}
//Else if the observer is on first vertex of edge.
else if( distance(observer, ppoint1) <= epsilon ){
if( ppoint2.bearing() == Angle(0.0) )
ppoint2.set_bearing_to_2pi();
//Get right wall bearing.
right_wall_bearing = ppoint2.bearing();
elp.push_back( Polar_Edge( Polar_Point(observer, observer),
ppoint2 ) );
continue;
}
//Else if the observer is on second vertex of edge.
else if( distance(observer, ppoint2) <= epsilon ){
//Get left wall bearing.
left_wall_bearing = ppoint1.bearing();
elp.push_back( Polar_Edge( ppoint1,
Polar_Point(observer, observer) ) );
continue;
}
//Otherwise the observer is not on the edge.
//If edge not horizontal (w/in epsilon).
else if( std::fabs( ppoint1.y() - ppoint2.y() ) > epsilon ){
//Possible source of numerical instability?
t = ( observer.y() - ppoint2.y() )
/ ( ppoint1.y() - ppoint2.y() );
//If edge crosses the ray emanating horizontal and right of
//the observer.
if( 0 < t and t < 1 and
observer.x() < t*ppoint1.x() + (1-t)*ppoint2.x() ){
//If first point is above, omit edge because it runs
//'against the grain'.
if( ppoint1.y() > observer.y() )
continue;
//Otherwise split the edge, making sure angles are assigned
//correctly on each side of the split point.
split_bottom = split_top
= Polar_Point( observer,
Point( t*ppoint1.x() + (1-t)*ppoint2.x(),
observer.y() ) );
split_top.set_bearing( Angle(0.0) );
split_bottom.set_bearing_to_2pi();
elp.push_back( Polar_Edge( ppoint1 , split_bottom ) );
elp.push_back( Polar_Edge( split_top , ppoint2 ) );
continue;
}
//If the edge is not horizontal and doesn't cross the ray
//emanating horizontal and right of the observer.
else if( ppoint1.bearing() >= ppoint2.bearing()
and ppoint2.bearing() == Angle(0.0)
and ppoint1.bearing() > Angle(M_PI) )
ppoint2.set_bearing_to_2pi();
//Filter out edges which run 'against the grain'.
else if( ( ppoint1.bearing() == Angle(0,0)
and ppoint2.bearing() > Angle(M_PI) )
or ppoint1.bearing() >= ppoint2.bearing() )
continue;
elp.push_back( Polar_Edge( ppoint1, ppoint2 ) );
continue;
}
//If edge is horizontal (w/in epsilon).
else{
//Filter out edges which run 'against the grain'.
if( ppoint1.bearing() >= ppoint2.bearing() )
continue;
elp.push_back( Polar_Edge( ppoint1, ppoint2 ) );
}
}}
//Construct a SORTED LIST, q1, OF VERTICES represented by
//Polar_Point_With_Edge_Info objects. A
//Polar_Point_With_Edge_Info is a derived class of Polar_Point
//which includes (1) a pointer to the corresponding edge
//(represented as a Polar_Edge) in the polar edge list elp, and
//(2) a boolean (is_first) which is true iff that vertex is the
//first Point of the respective edge (is_first == false => it's
//second Point). q1 is sorted according to lex. order of polar
//coordinates just as Polar_Points are, but with the additional
//requirement that if two vertices have equal polar coordinates,
//the vertex which is the first point of its respective edge is
//considered greater. q1 will serve as an event point queue for
//the radial sweep.
std::list<Polar_Point_With_Edge_Info> q1;
Polar_Point_With_Edge_Info ppoint_wei1, ppoint_wei2;
std::list<Polar_Edge>::iterator elp_iterator;
for(elp_iterator=elp.begin();
elp_iterator!=elp.end();
elp_iterator++){
ppoint_wei1.set_polar_point( elp_iterator->first );
ppoint_wei1.incident_edge = elp_iterator;
ppoint_wei1.is_first = true;
ppoint_wei2.set_polar_point( elp_iterator->second );
ppoint_wei2.incident_edge = elp_iterator;
ppoint_wei2.is_first = false;
//If edge contains the observer, then adjust the bearing of
//the Polar_Point containing the observer.
if( distance(observer, ppoint_wei1) <= epsilon ){
if( right_wall_bearing > left_wall_bearing ){
ppoint_wei1.set_bearing( right_wall_bearing );
(elp_iterator->first).set_bearing( right_wall_bearing );
}
else{
ppoint_wei1.set_bearing( Angle(0.0) );
(elp_iterator->first).set_bearing( Angle(0.0) );
}
}
else if( distance(observer, ppoint_wei2) <= epsilon ){
if( right_wall_bearing > left_wall_bearing ){
ppoint_wei2.set_bearing(right_wall_bearing);
(elp_iterator->second).set_bearing( right_wall_bearing );
}
else{
ppoint_wei2.set_bearing_to_2pi();
(elp_iterator->second).set_bearing_to_2pi();
}
}
q1.push_back(ppoint_wei1);
q1.push_back(ppoint_wei2);
}
//Put event point in correct order.
//STL list's sort method is a stable sort.
q1.sort();
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "\E[1;37;40m"
<< "COMPUTING VISIBILITY POLYGON " << std::endl
<< "for an observer located at [x y] = ["
<< observer << "]"
<< "\x1b[0m"
<< std::endl << std::endl
<< "\E[1;37;40m" <<"PREPROCESSING" << "\x1b[0m"
<< std::endl << std::endl
<< "q1 is" << std::endl;
std::list<Polar_Point_With_Edge_Info>::iterator q1_itr;
for(q1_itr=q1.begin(); q1_itr!=q1.end(); q1_itr++){
std::cout << "[x y bearing range is_first] = ["
<< q1_itr->x() << " "
<< q1_itr->y() << " "
<< q1_itr->bearing() << " "
<< q1_itr->range() << " "
<< q1_itr->is_first << "]"
<< std::endl;
}
}
//
//-------PREPARE FOR MAIN LOOP-------
//
//current_vertex is used to hold the event point (from q1)
//considered at iteration of the main loop.
Polar_Point_With_Edge_Info current_vertex;
//Note active_edge and e are not actually edges themselves, but
//iterators pointing to edges. active_edge keeps track of the
//current edge visibile during the sweep. e is an auxiliary
//variable used in calculation of k-points
std::list<Polar_Edge>::iterator active_edge, e;
//More aux vars for computing k-points.
Polar_Point k;
double k_range;
Line_Segment xing;
//Priority queue of edges, where higher priority indicates closer
//range to observer along current ray (of ray sweep).
Incident_Edge_Compare my_iec(observer, current_vertex, epsilon);
std::priority_queue<std::list<Polar_Edge>::iterator,
std::vector<std::list<Polar_Edge>::iterator>,
Incident_Edge_Compare> q2(my_iec);
//Initialize main loop.
current_vertex = q1.front(); q1.pop_front();
active_edge = current_vertex.incident_edge;
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "\E[1;37;40m"
<< "INITIALIZATION"
<< "\x1b[0m"
<< std::endl << std::endl
<< "\x1b[35m"
<< "Pop first vertex off q1"
<< "\x1b[0m"
<< ", set as current_vertex, \n"
<< "and set active_edge to the corresponding "
<< "incident edge."
<< std::endl;
print_cv_and_ae(current_vertex, active_edge);
}
//Insert e into q2 as long as it doesn't contain the
//observer.
if( distance(observer,active_edge->first) > epsilon
and distance(observer,active_edge->second) > epsilon ){
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "Push current_vertex's edge onto q2."
<< std::endl;
}
q2.push(active_edge);
}
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "\E[32m"
<< "Add current_vertex to visibility polygon."
<< "\x1b[0m"
<< std::endl << std::endl
<< "\E[1;37;40m"
<< "MAIN LOOP"
<< "\x1b[0m"
<< std::endl;
}
vertices_.push_back(current_vertex);
//-------BEGIN MAIN LOOP-------//
//
//Perform radial sweep by sequentially considering each vertex
//(event point) in q1.
while( !q1.empty() ){
//Pop current_vertex from q1.
current_vertex = q1.front(); q1.pop_front();
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "\x1b[35m"
<< "Pop next vertex off q1" << "\x1b[0m"
<< " and set as current_vertex."
<< std::endl;
print_cv_and_ae(current_vertex, active_edge);
}
//---Handle Event Point---
//TYPE 1: current_vertex is the _second_vertex_ of active_edge.
if( current_vertex.incident_edge == active_edge
and !current_vertex.is_first ){
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "\E[36m" << "TYPE 1:" << "\x1b[0m"
<< " current_vertex is the second vertex of active_edge."
<< std::endl;
}
if( !q1.empty() ){
//If the next vertex in q1 is contiguous.
if( distance( current_vertex, q1.front() ) <= epsilon ){
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "current_vertex is contiguous "
<< "with the next vertex in q1."
<< std::endl;
}
continue;
}
}
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "\E[32m" << "Add current_vertex to visibility polygon."
<< "\x1b[0m" << std::endl;
}
//Push current_vertex onto visibility polygon
vertices_.push_back( current_vertex );
chop_spikes_at_back(observer, epsilon);
while( !q2.empty() ){
e = q2.top();
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "Examine edge at top of q2." << std::endl
<< "1st point of e [x y bearing range] = ["
<< (e->first).x() << " "
<< (e->first).y() << " "
<< (e->first).bearing() << " "
<< (e->first).range() << "]" << std::endl
<< "2nd point of e [x y bearing range] = ["
<< (e->second).x() << " "
<< (e->second).y() << " "
<< (e->second).bearing() << " "
<< (e->second).range() << "]" << std::endl;
}
//If the current_vertex bearing has not passed, in the
//lex. order sense, the bearing of the second point of the
//edge at the front of q2.
if( ( current_vertex.bearing().get()
<= e->second.bearing().get() )
//For robustness.
and distance( Ray(observer, current_vertex.bearing()),
e->second ) >= epsilon
/* was
and std::min( distance(Ray(observer, current_vertex.bearing()),
e->second),
distance(Ray(observer, e->second.bearing()),
current_vertex)
) >= epsilon
*/
){
//Find intersection point k of ray (through
//current_vertex) with edge e.
xing = intersection( Ray(observer, current_vertex.bearing()),
Line_Segment(e->first,
e->second),
epsilon );
//assert( xing.size() > 0 );
if( xing.size() > 0 ){
k = Polar_Point( observer , xing.first() );
}
else{ //Error contingency.
k = current_vertex;
e = current_vertex.incident_edge;
}
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "\E[32m"
<< "Add a type 1 k-point to visibility polygon."
<< "\x1b[0m" << std::endl
<< std::endl
<< "Set active_edge to edge at top of q2."
<< std::endl;
}
//Push k onto the visibility polygon.
vertices_.push_back(k);
chop_spikes_at_back(observer, epsilon);
active_edge = e;
break;
}
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "Pop edge off top of q2." << std::endl;
}
q2.pop();
}
} //Close Type 1.
//If current_vertex is the _first_vertex_ of its edge.
if( current_vertex.is_first ){
//Find intersection point k of ray (through current_vertex)
//with active_edge.
xing = intersection( Ray(observer, current_vertex.bearing()),
Line_Segment(active_edge->first,
active_edge->second),
epsilon );
if( xing.size() == 0
or ( distance(active_edge->first, observer) <= epsilon
and active_edge->second.bearing()
<= current_vertex.bearing() )
or active_edge->second < current_vertex ){
k_range = INFINITY;
}
else{
k = Polar_Point( observer , xing.first() );
k_range = k.range();
}
//Incident edge of current_vertex.
e = current_vertex.incident_edge;
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< " k_range = "
<< k_range
<< " (range of active edge along "
<< "bearing of current vertex)" << std::endl
<< "current_vertex.range() = "
<< current_vertex.range() << std::endl;
}
//Insert e into q2 as long as it doesn't contain the
//observer.
if( distance(observer, e->first) > epsilon
and distance(observer, e->second) > epsilon ){
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "Push current_vertex's edge onto q2."
<< std::endl;
}
q2.push(e);
}
//TYPE 2: current_vertex is (1) a first vertex of some edge
//other than active_edge, and (2) that edge should not become
//the next active_edge. This happens, e.g., if that edge is
//(rangewise) in back along the current bearing.
if( k_range < current_vertex.range() ){
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "\E[36m" << "TYPE 2:" << "\x1b[0m"
<< " current_vertex is" << std::endl
<< "(1) a first vertex of some edge "
"other than active_edge, and" << std::endl
<< "(2) that edge should not become "
<< "the next active_edge."
<< std::endl;
}
} //Close Type 2.
//TYPE 3: current_vertex is (1) the first vertex of some edge
//other than active_edge, and (2) that edge should become the
//next active_edge. This happens, e.g., if that edge is
//(rangewise) in front along the current bearing.
if( k_range >= current_vertex.range()
){
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "\E[36m" << "TYPE 3:" << "\x1b[0m"
<< " current_vertex is" << std::endl
<< "(1) the first vertex of some edge "
"other than active edge, and" << std::endl
<< "(2) that edge should become "
<< "the next active_edge."
<< std::endl;
}
//Push k onto the visibility polygon unless effectively
//contiguous with current_vertex.
if( xing.size() > 0
//and k == k
and k_range != INFINITY
and distance(k, current_vertex) > epsilon
and distance(active_edge->first, observer) > epsilon
){
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "\E[32m"
<< "Add type 3 k-point to visibility polygon."
<< "\x1b[0m" << std::endl;
}
//Push k-point onto the visibility polygon.
vertices_.push_back(k);
chop_spikes_at_back(observer, epsilon);
}
//Push current_vertex onto the visibility polygon.
vertices_.push_back(current_vertex);
chop_spikes_at_back(observer, epsilon);
//Set active_edge to edge of current_vertex.
active_edge = e;
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "\E[32m" << "Add current_vertex to visibility polygon."
<< "\x1b[0m" << std::endl
<< std::endl
<< "Set active_edge to edge of current_vertex."
<< std::endl;
}
} //Close Type 3.
}
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "visibility polygon vertices so far are \n"
<< Polygon(vertices_) << std::endl
<< std::endl;
}
} //
//
//-------END MAIN LOOP-------//
//The Visibility_Polygon should have a minimal representation
chop_spikes_at_wrap_around( observer , epsilon );
eliminate_redundant_vertices( epsilon );
chop_spikes( observer, epsilon );
enforce_standard_form();
if(PRINTING_DEBUG_DATA){
std::cout << std::endl
<< "Final visibility polygon vertices are \n"
<< Polygon(vertices_) << std::endl
<< std::endl;
}
}
Visibility_Polygon::Visibility_Polygon(const Point& observer,
const Polygon& polygon_temp,
double epsilon)
{
*this = Visibility_Polygon( observer, Environment(polygon_temp), epsilon );
}
//Visibility_Graph
Visibility_Graph::Visibility_Graph( const Visibility_Graph& vg2 )
{
n_ = vg2.n_;
vertex_counts_ = vg2.vertex_counts_;
//Allocate adjacency matrix
adjacency_matrix_ = new bool*[n_];
adjacency_matrix_[0] = new bool[n_*n_];
for(unsigned i=1; i<n_; i++)
adjacency_matrix_[i] = adjacency_matrix_[i-1] + n_;
//copy each entry
for(unsigned i=0; i<n_; i++){
for(unsigned j=0; j<n_; j++){
adjacency_matrix_[i][j]
= vg2.adjacency_matrix_[i][j];
}}
}
Visibility_Graph::Visibility_Graph(const Environment& environment,
double epsilon)
{
n_ = environment.n();
//fill vertex_counts_
vertex_counts_.reserve( environment.h() );
for(unsigned i=0; i<environment.h(); i++)
vertex_counts_.push_back( environment[i].n() );
//allocate a contiguous chunk of memory for adjacency_matrix_
adjacency_matrix_ = new bool*[n_];
adjacency_matrix_[0] = new bool[n_*n_];
for(unsigned i=1; i<n_; i++)
adjacency_matrix_[i] = adjacency_matrix_[i-1] + n_;
// fill adjacency matrix by checking for inclusion in the
// visibility polygons
Polygon polygon_temp;
for(unsigned k1=0; k1<n_; k1++){
polygon_temp = Visibility_Polygon( environment(k1),
environment,
epsilon );
for(unsigned k2=0; k2<n_; k2++){
if( k1 == k2 )
adjacency_matrix_[ k1 ][ k1 ] = true;
else
adjacency_matrix_[ k1 ][ k2 ] =
adjacency_matrix_[ k2 ][ k1 ] =
environment(k2).in( polygon_temp , epsilon );
}
}
}
Visibility_Graph::Visibility_Graph(const std::vector<Point> points,
const Environment& environment,
double epsilon)
{
n_ = points.size();
//fill vertex_counts_
vertex_counts_.push_back( n_ );
//allocate a contiguous chunk of memory for adjacency_matrix_
adjacency_matrix_ = new bool*[n_];
adjacency_matrix_[0] = new bool[n_*n_];
for(unsigned i=1; i<n_; i++)
adjacency_matrix_[i] = adjacency_matrix_[i-1] + n_;
// fill adjacency matrix by checking for inclusion in the
// visibility polygons
Polygon polygon_temp;
for(unsigned k1=0; k1<n_; k1++){
polygon_temp = Visibility_Polygon( points[k1],
environment,
epsilon );
for(unsigned k2=0; k2<n_; k2++){
if( k1 == k2 )
adjacency_matrix_[ k1 ][ k1 ] = true;
else
adjacency_matrix_[ k1 ][ k2 ] =
adjacency_matrix_[ k2 ][ k1 ] =
points[k2].in( polygon_temp , epsilon );
}
}
}
Visibility_Graph::Visibility_Graph(const Guards& guards,
const Environment& environment,
double epsilon)
{
*this = Visibility_Graph( guards.positions_,
environment,
epsilon );
}
bool Visibility_Graph::operator () (unsigned i1,
unsigned j1,
unsigned i2,
unsigned j2) const
{
return adjacency_matrix_[ two_to_one(i1,j1) ][ two_to_one(i2,j2) ];
}
bool Visibility_Graph::operator () (unsigned k1,
unsigned k2) const
{
return adjacency_matrix_[ k1 ][ k2 ];
}
bool& Visibility_Graph::operator () (unsigned i1,
unsigned j1,
unsigned i2,
unsigned j2)
{
return adjacency_matrix_[ two_to_one(i1,j1) ][ two_to_one(i2,j2) ];
}
bool& Visibility_Graph::operator () (unsigned k1,
unsigned k2)
{
return adjacency_matrix_[ k1 ][ k2 ];
}
Visibility_Graph& Visibility_Graph::operator =
(const Visibility_Graph& visibility_graph_temp)
{
if( this == &visibility_graph_temp )
return *this;
n_ = visibility_graph_temp.n_;
vertex_counts_ = visibility_graph_temp.vertex_counts_;
//resize adjacency_matrix_
if( adjacency_matrix_ != NULL ){
delete [] adjacency_matrix_[0];
delete [] adjacency_matrix_;
}
adjacency_matrix_ = new bool*[n_];
adjacency_matrix_[0] = new bool[n_*n_];
for(unsigned i=1; i<n_; i++)
adjacency_matrix_[i] = adjacency_matrix_[i-1] + n_;
//copy each entry
for(unsigned i=0; i<n_; i++){
for(unsigned j=0; j<n_; j++){
adjacency_matrix_[i][j]
= visibility_graph_temp.adjacency_matrix_[i][j];
}}
return *this;
}
unsigned Visibility_Graph::two_to_one(unsigned i,
unsigned j) const
{
unsigned k=0;
for(unsigned counter=0; counter<i; counter++)
k += vertex_counts_[counter];
k += j;
return k;
}
Visibility_Graph::~Visibility_Graph()
{
if( adjacency_matrix_ != NULL ){
delete [] adjacency_matrix_[0];
delete [] adjacency_matrix_;
}
}
std::ostream& operator << (std::ostream& outs,
const Visibility_Graph& visibility_graph)
{
for(unsigned k1=0; k1<visibility_graph.n(); k1++){
for(unsigned k2=0; k2<visibility_graph.n(); k2++){
outs << visibility_graph( k1, k2 );
if( k2 < visibility_graph.n()-1 )
outs << " ";
else
outs << std::endl;
}
}
return outs;
}
}