cgal/Triangulation_2/include/CGAL/Constrained_triangulation_s...

696 lines
22 KiB
C++

// Copyright (c) 1997 INRIA Sophia-Antipolis (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) : Mariette Yvinec
#ifndef CGAL_CONSTRAINED_TRIANGULATION_SWEEP_2_H
#define CGAL_CONSTRAINED_TRIANGULATION_SWEEP_2_H
#include <utility>
#include <list>
#include <map>
#include <cassert>
#include <CGAL/triangulation_assertions.h>
#include <CGAL/Triangulation_short_names_2.h>
#include <CGAL/Triangulation_2.h>
CGAL_BEGIN_NAMESPACE
template < class Gt, class Tds>
class Triangulation_2;
template < class Gt, class Tds>
class Constrained_triangulation_2;
template < class Gt, class Tds>
class Constrained_triangulation_sweep_2
{
public:
typedef Gt Geom_traits;
typedef typename Gt::Point Point;
typedef typename Gt::Segment Segment;
typedef Triangulation_2<Gt,Tds> Triangulation;
typedef Constrained_triangulation_2<Gt,Tds> Ctriangulation;
typedef typename Ctriangulation::Face_handle Face_handle;
typedef typename Ctriangulation::Vertex_handle Vertex_handle;
typedef typename Ctriangulation::Edge Edge;
typedef typename Ctriangulation::Vertex Vertex;
typedef typename Ctriangulation::Face Face;
typedef typename Ctriangulation::Constraint Constraint;
typedef std::pair<Face_handle, int> Neighbor;
class Neighbor_list;
class Chain;
class Event_less;
class Status_comp;
class Event_less : public std::binary_function<Point, Point, bool>
{
private:
Geom_traits t;
public:
Event_less() : t() {};
Event_less(const Geom_traits& traits) : t(traits) {};
bool operator() (const Point& p, const Point& q)
{
return(t.compare_x(p,q)== SMALLER ||
( t.compare_x(p,q)== EQUAL &&
t.compare_y(p,q) == SMALLER ) );
}
};
class Status_comp :
public std::binary_function<Constraint, Constraint, bool>
{
private:
Geom_traits t;
public:
Status_comp() : t() {};
Status_comp(const Geom_traits& traits) : t(traits){}
bool operator() (const Constraint& s1, const Constraint& s2)
{
Point p1= s1.first;
Point p2= s2.first;
Point q1= s1.second;
Point q2= s2.second;
// one of the constraint is degenerate
if ( t.compare_x(p1,q1) == EQUAL &&
t.compare_y(p1,q1) == EQUAL) {
// p1==q1, then p2 has to be != q2
// if p1==p2 or p1==q2 return true
if ( t.compare_x(p1,p2) == EQUAL &&
t.compare_y(p1,p2) == EQUAL) {return true;}
if ( t.compare_x(p1,q2) == EQUAL &&
t.compare_y(p1,q2) == EQUAL ) {return true;}
// for vertical constraint (p2,q2)
if (t.compare_x(p2,q2) == EQUAL) {
return (t.compare_y(p1,p2) == SMALLER);}
// default case
return( t.orientation(p2,q2,p1) == RIGHT_TURN);
}
else if ( t.compare_x(p2,q2) == EQUAL &&
t.compare_y(p2,q2) == EQUAL) {
// p2==q2 && p1!=q1
// if p2==p1 or p2==q1 return false
if ( t.compare_x(p2,p1) == EQUAL &&
t.compare_y(p2,p1) == EQUAL) {return false;}
if ( t.compare_x(p2,q1) == EQUAL &&
t.compare_y(p2,q1) == EQUAL) {return false;}
//for vertical (p1,q1) constraints
if (t.compare_x(p1,q1) == EQUAL) {
return ( t.compare_y(p1,p2) == SMALLER);}
// default case
return (t.orientation(p1,q1,q2) == LEFT_TURN);
}
// comparison of two non degenerate constraints
else {
//neither of the constraints are points
switch( t.compare_x(p1,p2)) {
case SMALLER:
if ( t.compare_x(q1,p2) == EQUAL &&
t.compare_y(q1,p2) == EQUAL) {return true;}
else return ( t.orientation(p1,q1,p2) == LEFT_TURN);
case LARGER :
if ( t.compare_x(p1,q2) == EQUAL &&
t.compare_y(p1,q2) == EQUAL) {return false;}
else return ( t.orientation(p2,q2,p1) == RIGHT_TURN);
case EQUAL :
return ( t.compare_y(p1,p2) == SMALLER ||
(t.compare_y(p1,p2) == EQUAL &&
t.orientation(p1,q1,q2) == LEFT_TURN));
}
}
// shouldn't get there
// CGAL_triangulation_assertion( false );
return false;
}
};
class Neighbor_list : public std::list<Neighbor>
{
private:
Ctriangulation* _tr;
public:
Neighbor_list (Ctriangulation *tr) : _tr(tr) {}
bool is_removable(Face_handle fh)
{
return ( (*fh).vertex(1) == (*fh).vertex(2) &&
(*fh).neighbor(1) != Face_handle() &&
(*fh).neighbor(2) != Face_handle() );
}
void remove_flat(Face_handle fh)
{
CGAL_triangulation_precondition((*fh).vertex(1) == (*fh).vertex(2));
Face_handle f2= (*fh).neighbor(2);
Face_handle f1= (*fh).neighbor(1);
if ( f2 != Face_handle() ) { (*f2).set_neighbor( (*f2).index(fh), f1);}
if ( f1 != Face_handle() ) { (*f1).set_neighbor( (*f1).index(fh), f2);}
( (*fh). vertex(0))->set_face( f2!= Face_handle() ? f2 : f1 );
_tr->delete_face(fh);
return;
}
Face_handle up_visit_without_test(Vertex_handle v, Face_handle last)
{
Face_handle newf;
Face_handle fn; int in;
while( !empty()){
fn= front().first;
in= front().second;
pop_front();
newf = _tr->create_face(v,
fn->vertex(fn->cw(in)),
fn->vertex(fn->ccw(in)));
last->set_neighbor(2,newf); newf->set_neighbor(1,last);
fn->set_neighbor(in, newf); newf->set_neighbor(0,fn);
newf->set_constraint(1, last->is_constrained(2));
newf->set_constraint(0, fn->is_constrained(in));
// delete fn if flat and removable
if (is_removable(fn)) { remove_flat(fn);}
last=newf;
}
return last;
}
Face_handle up_visit( Vertex_handle v, Face_handle last)
{
Geom_traits t=Geom_traits();
Face_handle newf;
Face_handle fn; int in;
Vertex_handle cwin; Vertex_handle ccwin;
while (!empty()) {
fn= front().first;
in= front().second;
cwin = fn->vertex(fn->cw(in));
ccwin = fn->vertex(fn->ccw(in));
if ( t.orientation(ccwin->point(),cwin->point(),v->point()) ==
RIGHT_TURN) {
pop_front();
newf = _tr->create_face(v,cwin,ccwin);
last->set_neighbor(2,newf); newf->set_neighbor(1,last);
fn->set_neighbor(in, newf); newf->set_neighbor(0,fn);
newf->set_constraint(1, last->is_constrained(2));
newf->set_constraint(0, fn->is_constrained(in));
// delete fn if flat and removable
if (is_removable(fn)) { remove_flat(fn);}
last=newf;
}
else{break;}
}
return last;
}
Face_handle down_visit(Vertex_handle v, Face_handle first)
{
Geom_traits t=Geom_traits();
Face_handle newf;
Face_handle fn; int in;
Vertex_handle cwin; Vertex_handle ccwin;
while (!empty()) {
fn= back().first;
in= back().second;
cwin = fn->vertex(fn->cw(in));
ccwin = fn->vertex(fn->ccw(in));
if ( t.orientation(ccwin->point(),cwin->point(),v->point()) ==
RIGHT_TURN) {
pop_back();
newf = _tr->create_face(v,cwin,ccwin);
first->set_neighbor(1,newf); newf->set_neighbor(2,first);
fn->set_neighbor(in, newf); newf->set_neighbor(0,fn);
newf->set_constraint(2, first->is_constrained(1));
newf->set_constraint(0, fn->is_constrained(in));
// delete fn if flat and removable
if (is_removable(fn)) { remove_flat(fn);}
first=newf;
}
else{break;}
}
return first;
}
};
class Chain
{
private:
Vertex_handle rm;
Neighbor_list up;
Neighbor_list down;
public:
Chain(Ctriangulation* tr) : rm(), up(tr), down(tr) {}
Vertex_handle right_most() { return rm;}
Neighbor_list* up_list(){return &up;}
Neighbor_list* down_list(){return &down;}
void set_right_most(Vertex_handle v) { rm=v;}
};
typedef std::list<Point> Out_edges;
typedef std::map<Point,Out_edges *,Event_less> Event_queue;
typedef std::map<Constraint,void *, Status_comp> Sweep_status;
// should be
//typedef std::map<Constraint, Chain *, Status_comp> Sweep_status;
// added to please MIPS Pro
typedef typename Event_queue::iterator Event_queue_iterator;
typedef typename Sweep_status::iterator Sweep_status_iterator;
protected:
Ctriangulation* _tr;
std::list<Constraint>* _lc;
Event_less event_less;
Event_queue queue;
Status_comp status_comp;
Sweep_status status;
Chain upper_chain;
public:
Constrained_triangulation_sweep_2()
: _tr(NULL), _lc(), upper_chain()
{
}
Constrained_triangulation_sweep_2( Ctriangulation* ct,
std::list<Constraint>& lc)
: _tr(ct), _lc(&lc),
event_less(ct->geom_traits()), queue(event_less),
status_comp(ct->geom_traits()), status(status_comp),
upper_chain(ct)
{
make_event_queue();
build_triangulation();
}
Geom_traits geom_traits() { return _tr->geom_traits(); }
Event_less xy_less() { return event_less;}
friend class Neighbor_list;
public:
void make_event_queue();
void build_triangulation();
Vertex_handle treat_in_edges(const Event_queue_iterator & event,
Sweep_status_iterator & loc);
void treat_out_edges(const Event_queue_iterator & event,
Sweep_status_iterator & loc);
//Vertex_handle set_infinite_faces();
void set_infinite_faces();
bool do_intersect(const Constraint& c1, const Constraint& c2 );
};
template<class Gt, class Tds>
void
Constrained_triangulation_sweep_2<Gt,Tds>::
make_event_queue()
{
if ( ! queue.empty()) {return;} // queue already done
typename std::list<Constraint>::iterator sit=_lc->begin();
typename std::list<Constraint>::iterator sdone=_lc->end();
Constraint s;
Point p,q;
Event_queue_iterator look_up;
while (sit != sdone) {
s=*sit++;
if (event_less(s.first,s.second)) { p=s.first; q = s.second;}
else { p=s.second; q = s.first;}
// p is xy_less or equal to q
look_up = queue.lower_bound(p);
if (look_up == queue.end() ||
event_less(p,(*look_up).first) ) {
// the event p does not yet exists
Out_edges* out= new Out_edges();
typename Event_queue::value_type event(p,out);
look_up=queue.insert(look_up,event);
}
if(event_less(p,q)) {
((*look_up).second)->push_front(q); //insert q in out_edges(p);
// Degenerate constraints (p==q) are not inserted in Out_egdes list.
// A duplicate constraint
// will be inserted twice in the Out_egdes list of its first
// point. The second copy will be discarded when
// insertion in status takes place
look_up = queue.lower_bound(q);
if (look_up == queue.end() ||
event_less(q,(*look_up).first)){
// the event q does not yet exists
Out_edges* out= new Out_edges();
typename Event_queue::value_type event(q,out);
look_up=queue.insert(look_up,event);
}
}
}
return;
}
template<class Gt,class Tds>
void
Constrained_triangulation_sweep_2<Gt,Tds>::
build_triangulation()
{
Point p;
Vertex_handle v;
Out_edges* out;
Event_queue_iterator event;
while (! queue.empty()) {
event = queue.begin();
// locate (p,p) dans status
p = (*event).first;
out = (*event).second;
Sweep_status_iterator loc=status.lower_bound(Constraint(p,p));
// deal with the contraints finishing at p
v = treat_in_edges(event,loc);
_tr->set_number_of_vertices( _tr->number_of_vertices() +1);
// insert constraint beginning at p
treat_out_edges(event,loc);
// delete event from event_queue
out= (*event).second;
CGAL_triangulation_assertion( (*out).empty());
delete out; //delete la liste out
queue.erase(event);
}
// make inifinite vertex, infinite faces
// at this stage status is empty
// and the lists of upper_chain correspond to the convex hull
CGAL_triangulation_assertion( status.empty());
//the_vertex = set_infinite_faces();
set_infinite_faces();
return;
}
template<class Gt, class Tds>
typename Constrained_triangulation_sweep_2<Gt,Tds>::Vertex_handle
Constrained_triangulation_sweep_2<Gt,Tds>::
treat_in_edges(const Event_queue_iterator & event,
Sweep_status_iterator & loc)
{
// loc is assumed to point to the first constraint in status
// not less than [p,p];
Vertex_handle v = (new Vertex((*event).first))->handle();
Chain* pch;
Sweep_status_iterator loc_start=loc;
if (loc == status.end()) { pch = &upper_chain;}
else { pch = (Chain*)((*loc).second);}
Vertex_handle w = pch->right_most();
if (w == Vertex_handle() ) { // first event is treated
pch->set_right_most(v);
return v;
}
Face_handle newf= _tr->create_face(v,w,w);
// test if the edge vw is a constraint
// this is not possible if loc == status.end()
if ( loc != status.end() &&
w->point() == ((*loc).first).first &&
v->point() == ((*loc).first).second ) {
// vw is a constraint
newf->set_constraints(true,true,true);
}
Neighbor_list* nl = pch->down_list();
Face_handle first;
first= nl->down_visit(v,newf);
Face_handle last = newf;
while( loc!= status.end() && ((*event).first == ((*loc).first).second ) ) {
nl= pch->up_list();
last = nl->up_visit_without_test(v,last);
last->set_constraint(2,true);
loc++;
if (loc == status.end()) { pch = &upper_chain;}
else { pch = (Chain *)((*loc).second);}
nl= pch->down_list();
last = nl->up_visit_without_test(v,last);
}
nl=pch->up_list();
last= nl->up_visit(v,last);
//delete flat newf if possible
// i. e. if at least one of its neighbor is not Face_handle()
if ( newf->neighbor(2) != Face_handle() || newf->neighbor(1)!= Face_handle() ) {
if (first == newf ) { // means newf->neighbor(1) == Face_handle()
first = newf->neighbor(2);}
if (last == newf) { // means newf->neighbor(2) == Face_handle()
last = newf->neighbor(1);}
nl->remove_flat(newf);
}
// set face pointer of vertex v.
// if no face is created except the flat one
// the pointer is set to this face.
// Thus the face pointer of f->vertex(0) has to be reset
// when the flat face f is removed through f->remove_flat()
v->set_face(last);
// update the chain of loc and status;
//update the up list of *loc
nl->push_front(Neighbor(last,2));
pch->set_right_most(v);
// update the down list of *loc
// splicing in the remaining downlist of *loc_start
// then adding Neighbor(first,1)
nl = pch->down_list();
if (loc_start != loc) {
pch = (Chain *)((*loc_start).second);
nl->splice(nl->end(), *(pch->down_list()));
}
nl->push_back(Neighbor(first,1));
//update status
while (loc_start != loc) {
pch = (Chain *)((*loc_start).second);
delete pch;
status.erase(loc_start++);
}
// test for intersection the newly adjacent constraints
if(loc_start != status.end() && loc_start != status.begin()){
CGAL_triangulation_assertion( ! do_intersect( (*loc_start).first,
(*(--loc_start)).first ) );
}
return v;
}
template<class Gt, class Tds>
void
Constrained_triangulation_sweep_2<Gt,Tds>::
treat_out_edges(const Event_queue_iterator & event,
Sweep_status_iterator & loc)
{
Point p = (*event).first;
Out_edges* out = (*event).second;
typename Out_edges::iterator outit= (*out).begin();
Chain* newpc;
Chain* pc_up;
Constraint c;
const Constraint* c_plus=NULL;
const Constraint* c_minus=NULL;
if(loc != status.end()) { c_plus= &((*loc).first);}
if(loc != status.begin()) {c_minus = &((*(--loc)).first); ++loc;}
// c_plus points to the constraint in status following
// the last constraint through p if there is one.
// c_minus points to the constraint in status preceeding
// the first constraint through p if there is one.
// These two constraints are to be tested for intersection
// when inserting the constraint through p;
if (loc == status.end()) {pc_up = & upper_chain;}
else { pc_up = (Chain*)((*loc).second);}
Vertex_handle v = pc_up->right_most();
//assert (v->point() == p);
//c= Constraint(p,p);
//Sweep_status_iterator loc_bis = status.lower_bound(Constraint(p,p));
//assert( loc == loc_bis);
while( outit != (*out).end()){
c = Constraint(p,*outit);
// test for intersection
if (c_plus != NULL){
CGAL_triangulation_assertion( ! do_intersect( (*c_plus), c));
}
if (c_minus != NULL){
CGAL_triangulation_assertion( ! do_intersect( (*c_minus), c));
}
//insert
// if the constraint of *out are sorted (with out_comp())
// loc should be always equal to status.lower_bound(c)
// and status-insert should be constant time
newpc = new Chain(_tr);
newpc->set_right_most(v);
loc = status.insert(loc,
std::pair<const Constraint, void*>(c, (void*)newpc ));
loc++;
if (loc == status.end()) {pc_up = & upper_chain;}
else { pc_up = (Chain*)((*loc).second);}
(newpc->down_list())->splice((newpc->down_list())->end(),
*(pc_up->down_list()) );
(*out).erase(outit++);
}
return;
}
template<class Gt, class Tds>
void
//Constrained_triangulation_sweep_2<Gt,Tds>::Vertex_handle
Constrained_triangulation_sweep_2<Gt,Tds>::
set_infinite_faces()
{
//Vertex_handle infinite= (new Vertex)->handle();
Vertex_handle infinite= _tr->infinite_vertex();
// Triangulation may be empty;
if (upper_chain.right_most() == Vertex_handle() ) {return;}
Neighbor_list* upper_list= upper_chain.up_list();
Neighbor_list* lower_list= upper_chain.down_list();
//Triangulation may have only one vertex
if (upper_list->empty() || lower_list->empty())
// {return upper_chain.right_most();}
{
_tr->set_number_of_vertices(0);
_tr->insert_first(upper_chain.right_most()->point());
delete &(*upper_chain.right_most());
return;
}
//Triangulation has now at least two vertices
Face_handle first, last;
Face_handle newf, fn;
int in;
// Solve the One dimensional case
first = (lower_list->front()).first;
last = (upper_list->back()).first;
if (first->vertex(1) == first->vertex(2) &&
last->vertex(1) == last ->vertex(2) ) {
//dimension 1
//both test are necessary because it may remain some flat faces
//in the upper chain.
_tr->set_dimension(1);
newf = _tr->create_face(infinite, first->vertex(1), Face_handle());
first = last = newf;
infinite->set_face(first);
typename Neighbor_list::iterator it = lower_list->begin();
for( ; it != lower_list->end(); it++) {
fn = (*it).first;
//turn the vertex [vww] into [wvNULL]
fn->set_vertex(1, fn->vertex(0));
fn->set_vertex(0, fn->vertex(2));
fn->set_vertex(2, Vertex_handle());
fn->vertex(0)->set_face(fn);
fn->set_neighbor(1,last);
last->set_neighbor(0,fn);
last = fn;
}
fn = _tr->create_face(last->vertex(1), infinite, Vertex_handle());
fn->vertex(0)->set_face(fn);
fn->set_neighbor(1,last);
last->set_neighbor(0,fn);
fn->set_neighbor(0,first);
first->set_neighbor(1,fn);
return;
}
// good 2d triangulation
_tr->set_dimension(2);
lower_list->splice(lower_list->end(), *upper_list);
// * lower_list now describes the convex-hull ccw
fn = (*(lower_list->begin())).first;
in = (*(lower_list->begin())).second;
lower_list->pop_front();
newf = _tr->create_face( infinite,
fn->vertex(fn->cw(in)),
fn->vertex(fn->ccw(in)));
fn->set_neighbor(in,newf);
newf->set_neighbor(0,fn);
newf->set_constraint(0, fn->is_constrained(in));
if (lower_list->is_removable(fn)) { lower_list->remove_flat(fn); }
first = last = newf;
while ( ! lower_list->empty()){
fn =(* (lower_list->begin())).first;
in =(* (lower_list->begin())).second;
lower_list->pop_front();
newf= _tr->create_face( infinite,
fn->vertex(fn->cw(in)),
fn->vertex(fn->ccw(in)));
fn->set_neighbor(in,newf);
newf->set_neighbor(0,fn);
last->set_neighbor(2,newf);
newf->set_neighbor(1,last);
newf->set_constraint(0, fn->is_constrained(in));
if (lower_list->is_removable(fn)) { lower_list->remove_flat(fn); }
(newf->vertex(2))->set_face(newf->neighbor(0));
last=newf;
}
last->set_neighbor(2,first);first->set_neighbor(1,last);
(first->vertex(2))->set_face(first->neighbor(0)); //cannot be done before
infinite->set_face(last);
return;
}
template<class Gt, class Tds>
bool
Constrained_triangulation_sweep_2<Gt,Tds>::
do_intersect(const Constraint& c1, const Constraint& c2 )
{
// The constraints are known to be non degenerate
// ordered (c.first Lexicographic less than c.second)
// and to span some common y-value.
// They do not have the same first point but they can share the same
// endpoint.
if ( (!event_less(c1.second, c2.second)) &&
(!event_less(c2.second, c1.second)) ) {return false;}
else{
Orientation t1 = geom_traits().orientation(c1.first,c1.second,c2.first);
Orientation t2 = geom_traits().orientation(c1.first,c1.second,c2.second);
if (t1 == COLLINEAR && t2 == COLLINEAR) {return true;}
return ( t1 != t2 &&
(geom_traits().orientation(c2.first,c2.second,c1.first) !=
geom_traits().orientation(c2.first,c2.second,c1.second)));
}
// return false;
}
CGAL_END_NAMESPACE
#endif //CGAL_CONSTRAINED_TRIANGULATION_SWEEP_2_H