cgal/Visibility_complex_2/include/CGAL/Shortest_path_2.h

408 lines
13 KiB
C++

// Copyright (c) 2001-2004 ENS of Paris (France).
// 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.
//
// $URL$
// $Id$
//
//
// Author(s) : Pierre Angelier, Michel Pocchiola
#ifndef CGAL_SHORTEST_PATH_2_H
#define CGAL_SHORTEST_PATH_2_H
#include <CGAL/Visibility_complex_2.h>
#include <functional>
#include <set>
#include <list>
#include <vector>
#include <math.h>
CGAL_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
namespace Visibility_complex_2_details {
template < class Vc_ >
class Atom
{
public:
typedef typename Vc_::Vertex_handle Vertex_handle;
typedef typename Vc_::Edge_handle Edge_handle;
typedef typename Vc_::Gt::Distance_NT Distance_NT;
typedef typename Vc_::Disk_handle Disk_handle;
private:
Vertex_handle v_;
Edge_handle e_;
public:
Atom() : v_(0) , e_(0) {}
Atom(Vertex_handle v) : v_(v) , e_(0) {}
Atom(Edge_handle e) : v_(0) , e_(e) {}
bool operator==(const Atom& a) const
{ return (e_ == a.e_ && v_ == a.v_); }
bool operator!=(const Atom& a) const
{ return !(*this == a); }
Edge_handle edge() const { return e_; }
Vertex_handle vertex() const { return v_; }
long index() const
{ return (e_ == 0) ? long(v_) : long(e_); }
Distance_NT distance() const
{ return (e_ == 0) ? v_->distance() : e_->distance(); }
Distance_NT weight() const
{ return (e_ == 0) ? v_->weight() : e_->weight(); }
Atom prev() const
{ return (e_ == 0) ? v_->prev() : e_->prev() ; }
Vertex_handle next_vertex(Disk_handle s) const
{ return (e_ == 0) ? v_->next_vertex(s) : e_->next_vertex(s); }
Edge_handle next_edge(Disk_handle s) const
{ return (e_ == 0) ? v_->next_edge(s) : e_->next_edge(s); }
};
template < class Vc_ >
class Sh_edge
: public Visibility_complex_2_details::Edge_base<Vc_> // Qualified,
// because Sun CC does not understand otherwise.
{
public:
typedef typename Vc_::Gt Gt;
typedef typename Vc_::Disk_handle Disk_handle;
typedef typename Gt::Distance_NT Distance_NT;
typedef typename Gt::Arc_2 Arc;
typedef typename Gt::Point_2 Point_2;
typedef Edge_base<Vc_> Base;
typedef typename Base::Vertex_handle Vertex_handle;
typedef typename Base::Edge_handle Edge_handle;
typedef Visibility_complex_2_details::Atom<Vc_> Atom;
using Base::inf;
using Base::sup;
using Base::object;
using Base::sign;
private:
Distance_NT distance_;
Atom prev_;
typename Gt::Length length;
public:
// -------------------------------------------------------------------------
Sh_edge() : Base() , distance_(Distance_NT(-1)) { }
Sh_edge(bool s,Disk_handle p) : Base(s,p), distance_(Distance_NT(-1)) { }
Sh_edge(Vertex_handle v0 , Vertex_handle v1 , Disk_handle p)
: Base(v0,v1,p) , distance_(Distance_NT(-1)) { }
// -------------------------------------------------------------------------
Distance_NT weight() const { return length(*this,*inf(),*sup()); }
// -------------------------------------------------------------------------
Distance_NT distance() const { return distance_; }
void set_distance(Distance_NT d) { distance_ = d; }
// -------------------------------------------------------------------------
Atom prev() const { return prev_; }
void set_prev(Atom v) { prev_ = v; }
// -------------------------------------------------------------------------
Vertex_handle next_vertex(Disk_handle s)
{
if (object() != s) {
if ((sign() && sup()->target_object() == object()) ||
(!sign() && inf()->target_object() == object())) return 0;
}
return (sign()) ? sup() : inf();
}
Edge_handle next_edge(Disk_handle s)
{
if (object() != s) {
if (( sign() && sup()->is_constraint()) ||
(!sign() && inf()->is_constraint())) return 0;
}
if (sign()) return (sup()->target_object() == object()) ?
sup()->ccw_target_edge() : sup()->ccw_source_edge();
return (inf()->target_object() == object()) ?
inf()->cw_target_edge() : inf()->cw_source_edge();
}
// -------------------------------------------------------------------------
};
template < class Vc_ >
class Sh_vertex
: public Visibility_complex_2_details::Vertex_base<Vc_>
{
public:
typedef typename Vc_::Gt Gt;
typedef typename Vc_::Gt::Distance_NT Distance_NT;
typedef typename Vc_::Vertex_handle Vertex_handle;
typedef typename Vc_::Edge_handle Edge_handle;
typedef typename Vc_::Bitangent_2 Bitangent_2;
typedef Vertex_base<Vc_> Base;
typedef typename Base::Disk_handle Disk_handle;
typedef typename Base::Type Type;
typedef Visibility_complex_2_details::Atom<Vc_> Atom;
using Base::is_constraint;
using Base::source_object;
using Base::target_object;
using Base::is_left_right;
using Base::is_right_left;
using Base::is_xx_left;
using Base::cw_source_edge;
using Base::cw_target_edge;
using Base::ccw_source_edge;
using Base::ccw_target_edge;
private:
Distance_NT distance_;
Atom prev_;
typename Gt::Length length;
public:
Sh_vertex() : Base() , distance_(Distance_NT(-1)) { }
Sh_vertex(Type t , Disk_handle start , Disk_handle finish)
: Base (t,start,finish) , distance_(Distance_NT(-1)) { }
Sh_vertex(Edge_handle start , Edge_handle finish)
: Base(start,finish) , distance_(Distance_NT(-1)) { }
Sh_vertex(const Bitangent_2& b) : Base(b) , distance_(Distance_NT(-1)) { }
Sh_vertex(const Sh_vertex&sibling,bool reverse,Type t)
: Base(sibling,reverse,t),distance_(Distance_NT(-1)) {}
Distance_NT weight() const { return length(*this); }
Distance_NT distance() const { return distance_; }
void set_distance(Distance_NT d) { distance_ = d; }
Atom prev() const { return prev_; }
void set_prev(Atom e) { prev_ = e; }
Vertex_handle next_vertex(Disk_handle /*s*/) { return 0; }
Edge_handle next_edge(Disk_handle s) {
if (is_constraint() && s != source_object() && s != target_object()) {
if (is_left_right() && prev().edge() == cw_source_edge())
return 0;
if (is_right_left() && prev().edge() == ccw_source_edge())
return 0;
}
return (is_xx_left()) ? ccw_target_edge() : cw_target_edge();
}
};
class Sh_items : public Items {
public:
template <class Vc_ >
struct Edge_wrapper {
typedef Sh_edge<Vc_> Edge;
};
template <class Vc_>
struct Vertex_wrapper {
typedef Sh_vertex<Vc_> Vertex;
};
};
template <class At>
struct Less_atom {
bool operator() (const At& a, const At& b) const {
typedef typename At::Distance_NT Distance_NT;
if (a.distance() == b.distance()) return (a.index() < b.index());
if (a.distance() == Distance_NT(-1)) return false;
if (b.distance() == Distance_NT(-1)) return true;
return (a.distance() < b.distance());
}
};
}
typedef Visibility_complex_2_details::Sh_items Shortest_path_2_items;
template <class Gtr_, class Items_=Shortest_path_2_items,
class FlipTraits=Visibility_complex_2_details::Flip_traits>
class Shortest_path_2 {
typedef Shortest_path_2<Gtr_,Items_,FlipTraits> Self;
public:
typedef Gtr_ Gt;
typedef Items_ Items;
typedef CGAL::Visibility_complex_2<Gt,Items,FlipTraits>
Visibility_complex_2;
typedef typename Visibility_complex_2::Vertex Vertex;
typedef typename Visibility_complex_2::Edge Edge;
typedef typename Visibility_complex_2::Face Face;
typedef typename Gt::Distance_NT Distance_NT;
typedef typename Gt::Point_2 Point_2;
typedef typename Gt::Bitangent_2 Bitangent_2;
typedef typename Gt::Disk Disk;
typedef typename Visibility_complex_2::Disk_handle Disk_handle;
typedef typename Visibility_complex_2::Edge_handle Edge_handle;
typedef typename Visibility_complex_2::Vertex_handle Vertex_handle;
private:
Visibility_complex_2 vc;
Edge_handle p,n;
typedef typename Edge::Atom Atom;
public:
Shortest_path_2(Visibility_complex_2 V) : vc(V),p(0),n(0) {}
Shortest_path_2() :p(0),n(0) {};
void compute_shortest_paths(const Disk& s)
{
for (typename Visibility_complex_2::Vertex_iterator i=vc.vertices_begin();
i!=vc.vertices_end();++i) i->set_distance(-1);
for (typename Visibility_complex_2::Edge_iterator i=vc.edges_begin();
i!=vc.edges_end();++i) {
Edge_handle e=&*i;
e->set_distance(-1);
}
p=vc.positive_edge(s);
n=vc.negative_edge(s);
compute(p);
compute(n);
}
template <class OutputIterator>
std::pair<Distance_NT,OutputIterator>
get_path_vertices(const Disk& t, OutputIterator result) {
if (p&&n) {
std::list<Vertex_handle> pathp;
Distance_NT minp_ft = recover_path(p->object(),&t,
std::back_inserter(pathp));
std::list<Vertex_handle> pathn;
Distance_NT minn_ft = recover_path(n->object(),&t,
std::back_inserter(pathn));
// Compare the two paths and return the smallest
if (minn_ft>=0&&minn_ft<minp_ft) {
;
return std::pair<Distance_NT,OutputIterator>(minn_ft,
std::copy(pathn.rbegin(),pathn.rend(),result));
}
else if (minp_ft>=0) {
return std::pair<Distance_NT,OutputIterator>(minp_ft,
std::copy(pathp.rbegin(),pathp.rend(),result));
}
}
return std::pair<Distance_NT,OutputIterator>(-1,result);
}
template <class OutputIterator>
std::pair<Distance_NT,OutputIterator>
get_path_bitangents(const Disk& t, OutputIterator result) {
std::vector<Vertex_handle> path;
Distance_NT dist=get_path_vertices(t,std::back_inserter(path)).first;
for (typename std::vector<Vertex_handle>::const_iterator i=path.begin();
i!=path.end();++ i) {
*result=static_cast<const Bitangent_2&>(**i);
result++;
}
return std::pair<Distance_NT,OutputIterator>(dist,result);
}
private:
// Compute the shortest paths from s
void compute(Edge_handle s)
{
s->set_distance(0);
s->set_prev(Atom());
Atom start(s);
// The priority queue, we push start
typedef std::set<Atom, Visibility_complex_2_details::Less_atom<Atom> >
Queue;
Queue X;
X.insert(start);
// Dijkstra algorithm ------------------------------------------------------
while (!X.empty())
{
Atom a = *X.begin();
X.erase(X.begin());
Distance_NT da = a.distance();
Vertex_handle v = a.next_vertex(s->object());
Edge_handle e = a.next_edge(s->object());
if (v != 0) {
Distance_NT d = da + v->weight();
if (v->distance()<0 || d < v->distance()) {
if (v->distance()>=0) {
typename Queue::iterator vit = X.find(Atom(v));
if (vit != X.end()) X.erase(vit);
}
v->set_distance(d); v->set_prev(a);
X.insert(Atom(v));
}
}
if (e != 0) {
Distance_NT d=da+((e->object()==s->object()&&da==0)?0:e->weight());
if (e->distance()<0 || d < e->distance()) {
if (e->distance()>=0) {
typename Queue::iterator eit = X.find(Atom(e));
if (eit != X.end()) X.erase(eit);
}
e->set_distance(d); e->set_prev(a);
X.insert(Atom(e));
}
}
}
}
template < class OutputIterator>
Distance_NT
recover_path(Disk_handle s,Disk_handle t, OutputIterator result)
{
// Find edges two edges with opposite sign on t
Edge_handle ept,emt;
ept=vc.positive_edge(*t);
emt=vc.negative_edge(*t);
// closest edge to s on t
Edge_handle min = ept;
Edge_handle f = ept;
do {
if (min->distance()<0||
(f->distance() < min->distance()&&f->distance()>=0)) min = f;
f = f->sup()->ccw_edge(f->object());
} while (f==ept?(f=emt,true):f!=emt);
// Shortest path from s to object t
if (min->distance()<0) return -1;
recover_path(s,min,result);
return min->distance();
}
template <class OutputIterator>
OutputIterator
recover_path(Disk_handle s,Edge_handle t, OutputIterator result)
{
Atom finish(t);
std::list<Vertex_handle> path;
while (true) {
if (finish.vertex()!=0)
path.push_back(finish.vertex());
else if (finish.edge()!=0) {
if (finish.edge()->object()==s)
return std::copy(path.begin(),path.end(),result);
} else
return result;
finish=finish.prev();
}
}
};
// -----------------------------------------------------------------------------
CGAL_END_NAMESPACE
#endif