BOOKS i'm reading
 |
/*
* Module ID: hedge.cpp
* Titre : Declaration de la classe halfEdge.
* Utilite : Classe utilisee pour la construction du diagramme de Voronoi
*
* Auteur : Olivier Langlois (olivier@olivierlanglois.net)
* Date : 24 Fevrier 1998
*/
#include "debug.h"
#include "collect/idlist.h"
#include "geo/point.h"
#include "geo/segment.h"
#include "geo/line.h"
#include "geo/circle.h"
#include "collect/colvar.h"
#include "geo/dcel.h"
#include "geo/hedge.h"
#include "prime.h"
#include "collect/contx.h"
#ifdef __GNUG__
#include "umath.h"
#else
#include <math.h>
#endif
GVectorimplement(halfEdgeP)
GVector(halfEdgeP) halfEdge::table_;
halfEdge *halfEdge::leftEnd = NULL;
halfEdge *halfEdge::rightEnd = NULL;
halfEdge::halfEdge( edge *e, char dir )
{
Vertex = NULL;
Previous = NULL;
Next = NULL;
ve = e;
direction = dir;
V1isSetted = BOOL_FALSE;
V2isSetted = BOOL_FALSE;
if( ve )
{
ve->addReference();
point s1 = ve->getF1()->getLocation();
point s2 = ve->getF2()->getLocation();
segment s(s1,s2);
c = s1.xcoord()*s.dx() + s1.ycoord()*s.dy() +
(s.dx()*s.dx() + s.dy()*s.dy())*0.5;
float adx = s.dx()>0?s.dx():-s.dx();
float ady = s.dy()>0?s.dy():-s.dy();
if( adx>ady )
c /= s.dx();
else
c/= s.dy();
}
}
halfEdge::~halfEdge()
{
if( Previous && Next )
{
Previous->Next = Next;
Next->Previous = Previous;
}
if( ve && !ve->removeReference() /*&&
(V1isSetted == BOOL_TRUE || V2isSetted == BOOL_TRUE)*/)
{
if( V1isSetted == BOOL_FALSE && direction == 0)
{
vertex *v1 = ve->getV1();
vertex *v2 = ve->getV2();
// Si les 2 vertices sont du meme cote, une correction est nessecaire.
if( v1->xcoord() > v2->xcoord() ||
(v1->xcoord() == v2->xcoord() && v1->ycoord() < v2->ycoord()) )
ve->setV1( new vertex(v1->reflect( *v2 )) );
}
else if( V2isSetted == BOOL_FALSE && direction == 1)
{
vertex *v1 = ve->getV1();
vertex *v2 = ve->getV2();
// Si les 2 vertices sont du meme cote, une correction est nessecaire.
if( v2->xcoord() < v1->xcoord() ||
(v2->xcoord() == v1->xcoord() && v2->ycoord() > v1->ycoord()) )
ve->setV2( new vertex(v2->reflect( *v1 )) );
}
ve->insert();
}
removeYStar();
// Enleve les reference de cette arete de la hash table.
if( references() )
{
halfEdge *cur;
for( int i = 0; i < table_.length(); i++ )
if( (cur = table_(i)) == this )
{
if( i == 0 )
table_(0) = leftEnd;
else if( i == table_.length() - 1 )
table_(i) = rightEnd;
else table_(i) = NULL;
if( !removeReference() ) break;
}
}
}
/******************************************************************************
*
* Nom : init
*
****************************************************************************/
void halfEdge::init( size_t N )
{
#ifdef __GNUG__
table_.resize(setTable((unsigned)(2*usqrt(N))));
#else
table_.resize(setTable(2*sqrt(N)));
#endif
for( int i = 1; i < table_.length() - 1; i++ )
table_(i) = NULL;
leftEnd = new halfEdge();
rightEnd = new halfEdge();
leftEnd->Previous = leftEnd;
leftEnd->Next = rightEnd;
rightEnd->Previous = leftEnd;
rightEnd->Next = rightEnd;
leftEnd->addReference();
rightEnd->addReference();
table_(0) = leftEnd;
table_(table_.length()-1) = rightEnd;
}
/******************************************************************************
*
* Nom : setTable
*
****************************************************************************/
size_t halfEdge::setTable(size_t N)
{
size_t bucketNum, i = 0;
do
{
bucketNum = primeTab[i];
}
while( primeTab[i++] < N );
D( cout << "bucketNum : " << bucketNum << endl; )
return bucketNum;
}
/******************************************************************************
*
* Nom : terminate
*
****************************************************************************/
void halfEdge::terminate( void )
{
halfEdge *cur;
while( (cur = leftEnd->Next) != rightEnd )
delete cur;
delete leftEnd;
delete rightEnd;
}
void halfEdge::setYStar( vertex *v, const point &p )
{
Vertex = v;
v->addReference();
ystar = circle( *(point *)v, p );
}
void halfEdge::removeYStar( void )
{
if( Vertex )
{
if( !Vertex->removeReference() )
delete Vertex;
Vertex = NULL;
}
}
face *halfEdge::rightSite()
{
if(direction)
return ve->getF1();
else return ve->getF2();
}
face *halfEdge::leftSite()
{
if(direction)
return ve->getF2();
else return ve->getF1();
}
void halfEdge::setV1( vertex *v )
{
if( V1isSetted == BOOL_TRUE )
throw GeoEx(GX_VERTEX);
// Switch les vertices si necessaire
vertex *v2 = ve->getV2();
if( *v2 == *v && V2isSetted == BOOL_FALSE )
{
v2 = ve->getV1();
ve->setV2(v2);
}
ve->setV1(v);
V1isSetted = BOOL_TRUE;
}
void halfEdge::setV2( vertex *v )
{
if( V2isSetted == BOOL_TRUE )
throw GeoEx(GX_VERTEX);
// Switch les vertices si necessaire
vertex *v1 = ve->getV1();
if( *v1 == *v && V1isSetted == BOOL_FALSE )
{
v1 = ve->getV2();
ve->setV1(v1);
}
ve->setV2(v);
V2isSetted = BOOL_TRUE;
}
int halfEdge::operator==(const halfEdge &h) const
{
return point::cmp_yx( *Vertex, *h.Vertex ) == 0;
/*
return (Vertex->ycoord()+ystar.radius() ==
h.Vertex->ycoord()+h.ystar.radius() &&
Vertex->xcoord() == h.Vertex->xcoord());
*/
}
int halfEdge::operator!=(const halfEdge &h) const
{
return (!operator==(h));
}
int halfEdge::operator <(const halfEdge &he) const
{
// Note : Plus ystar est petit, plus la priorite est grande.
// return point::cmp_yx( *Vertex, *h.Vertex ) > 0;
halfEdge &h = const_cast< halfEdge & >(he);
return (Vertex->ycoord()+const_cast<circle &>(ystar).radius() >
h.Vertex->ycoord()+h.ystar.radius() ||
(Vertex->ycoord()+const_cast<circle &>(ystar).radius() ==
h.Vertex->ycoord()+h.ystar.radius() &&
Vertex->xcoord() > h.Vertex->xcoord()));
}
int halfEdge::operator >(const halfEdge &he) const
{
// Note : Plus ystar est petit, plus la priorite est grande.
// return point::cmp_yx( *Vertex, *h.Vertex ) < 0;
halfEdge &h = const_cast< halfEdge & >(he);
return (Vertex->ycoord()+const_cast<circle &>(ystar).radius() <
h.Vertex->ycoord()+h.ystar.radius() ||
(Vertex->ycoord()+const_cast<circle &>(ystar).radius() ==
h.Vertex->ycoord()+h.ystar.radius() &&
Vertex->xcoord() < h.Vertex->xcoord()));
}
int halfEdge::operator<=(const halfEdge &h) const
{
return ( operator<(h) || operator==(h) );
}
int halfEdge::operator>=(const halfEdge &h) const
{
return ( operator>(h) || operator==(h) );
}
/******************************************************************************
*
* Nom : insert
*
* Utilite : Insere une nouvelle arete.
*
****************************************************************************/
void halfEdge::insert( halfEdge *lb )
{
Previous = lb;
Next = lb->Next;
(lb->Next)->Previous = this;
lb->Next = this;
}
/******************************************************************************
*
* Nom : leftbnd
*
* Utilite : Retrouve l'arete dont le point est le plus proche.
*
****************************************************************************/
halfEdge *halfEdge::leftbnd(const point &p)
{
halfEdge *e;
halfEdge *closestEdge;
halfEdge *tmpE;
unsigned buck, i;
D( e = leftEnd; )
D( do {e = e->Next;if(e->ve) cout << e->ve->getSegment() << (e->direction?"right":"left") << e->ve->getF1()->getLocation() << e->ve->getF2()->getLocation() << endl;} while( e !=rightEnd ); )
// Utilise la hash table pour etre proche de la halfEdge
buck = (unsigned)((((float)p.hash())/UINT_MAX) * table_.length());
if(buck>=table_.length()) buck = table_.length() - 1;
e = table_(buck);
if( e == NULL )
{
for(i=1; 1; i++)
{
if ((e=table_(buck-i)) != NULL) break;
if ((e=table_(buck+i)) != NULL) break;
}
}
// recherche lineairement la liste
if( e==leftEnd || (e != rightEnd && e->atRight(p) == BOOL_TRUE) )
{
closestEdge = e;
do
{
e = e->Next;
}
while( e != rightEnd && e->atRight(p) == BOOL_TRUE );
closestEdge = e->Previous;
// Regarde a gauche
while(
closestEdge->Previous != leftEnd &&
closestEdge->Previous->atRight(p) == BOOL_TRUE &&
closestEdge->Previous->rightSite()->getLocation().distance(p) <
closestEdge->rightSite()->getLocation().distance(p) )
closestEdge = closestEdge->Previous;
// Regarde a droite
if( e != rightEnd )
do
{
e = e->Next;
}
while( e != rightEnd && e->atRight(p) == BOOL_FALSE );
if( e != rightEnd &&
e->atRight(p) == BOOL_TRUE &&
e->rightSite()->getLocation().distance(p) <
closestEdge->rightSite()->getLocation().distance(p) )
closestEdge = e;
/*
if( e != rightEnd )
{
while(
e != rightEnd &&
e->atRight(p) == BOOL_TRUE &&
e->rightSite()->getLocation().distance(p) <
closestEdge->rightSite()->getLocation().distance(p) )
{
closestEdge = e;
e = e->Next;
}
}
*/
}
else
{
tmpE = e;
do{ e = e->Previous; } while(e != leftEnd && e->atRight(p) == BOOL_FALSE);
// Regarde a gauche
closestEdge = e;
while(
closestEdge->Previous != leftEnd &&
closestEdge->Previous->atRight(p) == BOOL_TRUE &&
closestEdge->Previous->rightSite()->getLocation().distance(p) <
closestEdge->rightSite()->getLocation().distance(p) )
closestEdge = closestEdge->Previous;
// Regarde a droite
if( tmpE != rightEnd )
do
{
tmpE = tmpE->Next;
}
while( tmpE != rightEnd && tmpE->atRight(p) == BOOL_FALSE );
if( tmpE != rightEnd && closestEdge != leftEnd )
{
if( tmpE != rightEnd &&
tmpE->atRight(p) == BOOL_TRUE &&
tmpE->rightSite()->getLocation().distance(p) <
closestEdge->rightSite()->getLocation().distance(p) )
closestEdge = tmpE;
/*
while(
tmpE != rightEnd &&
tmpE->atRight(p) == BOOL_TRUE &&
tmpE->rightSite()->getLocation().distance(p) <
closestEdge->rightSite()->getLocation().distance(p) )
{
closestEdge = tmpE;
tmpE = tmpE->Next;
}
*/
}
}
// Mise a jour de la hash table et du nombre de references
if( (tmpE = table_(buck)) != closestEdge )
{
if( tmpE != NULL)
tmpE->removeReference();
table_(buck) = closestEdge;
closestEdge->addReference();
}
return closestEdge;
}
/******************************************************************************
*
* Nom : intersection
*
****************************************************************************/
vertex *halfEdge::intersection( halfEdge *e2 )
{
// Si un des 2 edges n'est pas initialise. (Ex.: Sentinel)
if(ve == NULL || e2->ve == NULL)
return NULL;
// Si les 2 halfEdges sont complementaire
if(ve->getF2Idx() == e2->ve->getF2Idx() ) return NULL;
point p;
if( ve->intersection( *e2->ve, p ) == BOOL_FALSE ) return NULL;
halfEdge *he = (halfEdge *)
(point::cmp_yx(ve->getF2()->getLocation(),e2->ve->getF2()->getLocation())< 0)?
this:e2;
D( cout << "Site :" << he->ve->getF2()->getLocation() << endl; )
// Verifie si l'intersection est a droite du site
int right_of_site = p.xcoord() > he->ve->getF2()->getLocation().xcoord();
// Verifie que l'intersection se trouve du bon cote
if ((right_of_site && he->direction == 0) ||
(!right_of_site && he->direction == 1)) return NULL;
return new vertex(p);
}
Boolean halfEdge::atRight( const point &p ) const
{
Boolean result, fast;
int right_of_site;
point topsite = ve->getF2()->getLocation();
right_of_site = p.xcoord() > topsite.xcoord();
if( right_of_site && direction == 0) return BOOL_TRUE;
if(!right_of_site && direction == 1) return BOOL_FALSE;
point bottomsite = ve->getF1()->getLocation();
segment s1( bottomsite, topsite );
if( s1.is_vertical() || s1.slope() >= 1 )
{
double yl, t1, t2, t3;
yl = c - (s1.dx()/s1.dy())*p.xcoord();
t1 = p.ycoord() - yl;
t2 = p.xcoord() - topsite.xcoord();
t3 = yl - topsite.ycoord();
result = (t1*t1 > t2*t2 + t3*t3)?BOOL_TRUE:BOOL_FALSE;
}
else
{
double dxp = p.xcoord() - topsite.xcoord();
double dyp = p.ycoord() - topsite.ycoord();
double m = s1.slope();
fast = BOOL_FALSE;
// Si le point est a gauche && la pente est negative
// || le point est a droite && la pente est positive || nulle
if( (!right_of_site && m<0.0) || (right_of_site && m >= 0.0) )
{
result = (dyp >= m*dxp)?BOOL_TRUE:BOOL_FALSE;
fast = result;
}
else
{
result = (p.xcoord() + p.ycoord()*m > c)?BOOL_TRUE:BOOL_FALSE;
if(m<0.0) result = (result == BOOL_TRUE)?BOOL_FALSE:BOOL_TRUE;
if( result == BOOL_FALSE ) fast = BOOL_TRUE;
}
if( fast == BOOL_FALSE )
{
double dxs = topsite.xcoord() - bottomsite.xcoord();
result = (m * (dxp*dxp - dyp*dyp) <
dxs*dyp*(1.0+2.0*dxp/dxs + m*m))?BOOL_TRUE:BOOL_FALSE;
if(m<0.0) (result == BOOL_TRUE)?BOOL_FALSE:BOOL_TRUE;
}
}
if( direction == 0 ) return result;
else return (result==BOOL_TRUE)?BOOL_FALSE:BOOL_TRUE;
}
|