Home
Fractals
Tutorials
Books
Archive
My blog
My LinkedIn Profile

BOOKS i'm reading

Napoleon Hill Keys to Success: The 17 Principles of Personal Achievement, Napoleon Hill, ISBN: 978-0452272811
The 4-Hour Workweek: Escape 9-5, Live Anywhere, and Join the New Rich (Expanded and Updated), Timothy Ferriss, ISBN: 978-0307465351
The Fountainhead, Ayn Rand, ISBN: 0452273331

/*
 * Module ID: voronoi.cpp
 * Titre    : Construction d'un diagrame de Voronoi.
 * Utilite  : Utilise l'algorithme de Steven Fortune des laboratoires
 *            Bell AT&T comme decrit dans 'Computational Geometry in C' de
 *            J. O'Rourke. (P. 179)
 *
 * Limite   : Cet algorithme n'est pas le plus appropriƩ lorsque l'on
 *            desire ajouter ou supprimer des sites de l'ensemble de sites
 *            de depart.
 *            De plus, avec certaines conditions (inconnues) le diagramme
 *            resultant de cet algorithme est errone.
 *
 * Auteur   : Olivier Langlois (olivier@olivierlanglois.net)
 * Date     : 07 Mars 1998
 */

#ifdef __BORLANDC__
// Indique au compilateur que les instances de template utilisees dans ce
// module seront definies dans un autre module.
#pragma option -Jgx
#endif

#ifdef _MSC_VER
#define __WIN32__ _WIN32
#endif

#ifdef __GNUG__
#include <std/typeinfo.h>
#endif
#include "collect/idlist.h"
#include "geo/point.h"
#include "geo/segment.h"
#include "geo/circle.h"
#include "../tools/collect/pq.cpp"
#include "collect/colvar.h"
#include "collect/dict.h"
#include "geo/dcel.h"
#include "collect/vector.h"
#include "geo/hedge.h"
#include "geo/voronoi.h"
#ifdef __GNUG__
#include "umath.h"
#else
#include <math.h>
#endif
#include "debug.h"
#ifdef __WIN32__
#include "diagwin.h"
#else
#include "diagdos.h"
#endif

Boolean yStarIsSmallest( circle &star, IDList &sl)
{
  IDListIterator it(sl);
  point *p;
  while( ( p = (point *)++it) &&
              star.inside(*p) == BOOL_FALSE)
     if( p->ycoord() > star.center().ycoord()+star.radius()  ||
         (p->ycoord() == star.center().ycoord()+star.radius() &&
          p->xcoord() >  star.center().xcoord()) ) return BOOL_TRUE;
  return BOOL_FALSE;
}

/******************************************************************************
 *
 * Nom       : Voronoi
 *
 * Utilite   : Contruire un diagrame de Voronoi.
 *
 * Reference : voronoi.h
 *
 ****************************************************************************/
DCEL *Voronoi( IDList &sl )
{
  face *newsite, *bot, *top, *bottomsite, *temp;
  vertex *v, *p;
  point *tmpPoint;
  circle newintstar;
  halfEdge *lbnd, *rbnd, *llbnd, *rrbnd, *bisector;
  edge *e;
  line  l;
  char  direction;
  float xmax = 0;

  // Prepare un 'plane sweep' en triant les sites
  sl.sort(sortSites);

  IDListIterator it(sl);

  while( tmpPoint = (point *)++it )
  {
     D( cout << *tmpPoint << endl; )
     if( tmpPoint->xcoord() < point::xmin ) point::xmin = tmpPoint->xcoord();
     if( tmpPoint->xcoord() > xmax        ) xmax        = tmpPoint->xcoord();
  }
  if( xmax - point::xmin )
     point::deltax = (xmax - point::xmin);

  DCEL *edgeList = new DCEL;
  halfEdge::init( sl.entries() );

  PQ<halfEdge> pQueue;
  // Assigne un Sentinel a la PQ.
  lbnd = new halfEdge;
  lbnd->setYStar( new vertex(point( -HUGE_VAL, -HUGE_VAL )),
                             point( -HUGE_VAL, -HUGE_VAL ));
  pQueue.setSentinel( lbnd );

  tmpPoint = (point *)sl.get();
  if(tmpPoint)
  {
     bottomsite = new face(*tmpPoint);
     delete tmpPoint;
  }
  else bottomsite = NULL;

  tmpPoint = (point *)sl.get();
  if(tmpPoint)
  {
     newsite    = new face(*tmpPoint);
     delete tmpPoint;
  }
  else newsite = NULL;

try{
  while(1)
  {
     if(pQueue.isEmpty() == BOOL_FALSE)
     {
        newintstar = pQueue.first()->getYStar();
     }

     if( newsite != NULL
          && (pQueue.isEmpty() == BOOL_TRUE
           /*
            * Chaque vertex du diagramme est le centre d'un cercle dont
            * ses 3 sites sont cocirculaires.
            * newintstar sert a determiner si le nouveau site est a
            * l'interieur du rayon du cercle des 3 derniers sites traites
            */
          || newintstar.inside(newsite->getLocation()) == BOOL_TRUE
          || yStarIsSmallest( newintstar, sl) == BOOL_FALSE ))

     {
        /* Le nouveau site est le plus petit */
        D( if( newsite ) cout << " newsite :" << newsite->getLocation() << endl; )
        lbnd = halfEdge::leftbnd(newsite->getLocation());
/*
        if( sl.first() &&
             lbnd->ve   &&
             lbnd->rightSite()->getLocation().distance(*(point *)sl.first()) <
             lbnd->rightSite()->getLocation().distance(newsite->getLocation()) &&
             lbnd->next() != halfEdge::rightEnd &&
             lbnd->next()->atRight(newsite->getLocation()) == BOOL_TRUE )
          lbnd = lbnd->next();
*/
        rbnd = lbnd->next();
//      D( if( lbnd == halfEdge::leftEnd || lbnd == halfEdge::rightEnd ) DiagOutWin("Voronoi").DisplayMsg("Mauvais lbnd"); )

        if( !lbnd->ve ) bot = bottomsite;
        else bot = lbnd->rightSite();

        l = p_bisector(bot->getLocation(), newsite->getLocation());
        D( cout << "Bissectrice :" << l << endl;                           )
        D( if( lbnd->ve ) cout << "lbnd :" << lbnd->ve->getSegment() << ((lbnd->direction)?"right":"left") << lbnd->ve->getF1()->getLocation() << lbnd->ve->getF2()->getLocation() << endl; )
        D( if( rbnd->ve ) cout << "rbnd :" << rbnd->ve->getSegment() << ((rbnd->direction)?"right":"left") << rbnd->ve->getF1()->getLocation() << rbnd->ve->getF2()->getLocation() << endl; )

        e = new edge( edgeList, bot, newsite, l );
        bisector = new halfEdge( e, 0 );
        bisector->insert( lbnd );
        if ((p = lbnd->intersection(bisector)) != NULL)
        {
          pQueue.remove(lbnd);
          lbnd->removeYStar();
          lbnd->setYStar(p,newsite->getLocation());
          pQueue.insert(lbnd);
        }
        lbnd = bisector;
        bisector = new halfEdge( e, 1 );
        bisector->insert(lbnd);
        if ((p = bisector->intersection(rbnd)) != NULL)
        {
          bisector->setYStar(p,newsite->getLocation());
          pQueue.insert(bisector);
        }
        tmpPoint = (point *)sl.get();
        if(tmpPoint)
        {
          newsite    = new face(*tmpPoint);
          delete tmpPoint;
        }
        else
        {
          newsite = NULL;
        }
     }
     else if ( pQueue.isEmpty() == BOOL_FALSE )
     /* l'intersection est la plus petite */
     {
        lbnd  = pQueue.removeFirst();
        llbnd = lbnd->previous();
        rbnd  = lbnd->next();
        rrbnd = rbnd->next();
        bot   = lbnd->leftSite();
        top   = rbnd->rightSite();
        v     = lbnd->Vertex;

        D( cout << "Vertex :" << *(point *)v << endl; )
        D( if( lbnd->ve ) cout << "lbnd :" << lbnd->ve->getSegment() << ((lbnd->direction)?"right":"left") << lbnd->ve->getF1()->getLocation() << lbnd->ve->getF2()->getLocation() << endl; )
        D( if( rbnd->ve ) cout << "rbnd :" << rbnd->ve->getSegment() << ((rbnd->direction)?"right":"left") << rbnd->ve->getF1()->getLocation() << rbnd->ve->getF2()->getLocation() << endl; )
        D( if( llbnd->ve) cout << "llbnd:" << lbnd->ve->getSegment() << ((llbnd->direction)?"right":"left") << llbnd->ve->getF1()->getLocation() << llbnd->ve->getF2()->getLocation() << endl; )
        D( if( rrbnd->ve) cout << "rrbnd:" << rbnd->ve->getSegment() << ((rrbnd->direction)?"right":"left") << rrbnd->ve->getF1()->getLocation() << rrbnd->ve->getF2()->getLocation() << endl; )
      D( if( pQueue.first() ) cout << "Next intersection: " << pQueue.first()->ve->getSegment() << endl; )

        D( if(line(lbnd->ve->getSegment()).contains(*v) == BOOL_FALSE) cout << "Mauvais vertex" << endl; )
        if( lbnd->direction == 0 )
        // 1
          lbnd->setV1(v);
        else
          lbnd->setV2(v);


        D( if(line(rbnd->ve->getSegment()).contains(*v) == BOOL_FALSE) cout << "Mauvais vertex" << endl; )
        if( rbnd->direction == 0 )
        // 2
          rbnd->setV1(v);
        else
          rbnd->setV2(v);

        D( cout << "Site 1:" << bot->getLocation() << " Site 2:" << top->getLocation() << endl; )

        if( bot->getLocation().ycoord() > top->getLocation().ycoord() )
        { temp = bot; bot = top; top = temp; direction = 1; }
        else direction = 0;

        l = p_bisector(bot->getLocation(), top->getLocation());
        e = new edge( edgeList, bot, top, l );
        bisector = new halfEdge(e, direction);
        D( cout << "Bissectrice :" << l << endl; )
        /*
         * Chaque vertex du diagramme de Voronoi possede exactement 3
         * aretes. ( Computational Geometry, [PREPARATA,SHAMOS] P.206 )
         */
        // 3
        if( direction == 1 )
          bisector->setV1(v);
        else
          bisector->setV2(v);

        D( if(l.contains(*v) == BOOL_FALSE) cout << "Mauvais vertex" << endl; )
        D( if(lbnd == halfEdge::leftEnd) cout << "lbnd == halfEdge::leftEnd" << endl; )
        D( if(rbnd == halfEdge::rightEnd) cout << "rbnd == halfEdge::rightEnd" << endl; )

        // Insere le edge dans le DCEL
        delete lbnd;
        pQueue.remove(rbnd);
        delete rbnd;

        bisector->insert(llbnd);

        if ((p = llbnd->intersection(bisector)) != NULL)
        {
          pQueue.remove(llbnd);
          llbnd->removeYStar();
          llbnd->setYStar(p,bot->getLocation());
          pQueue.insert(llbnd);
        }
        if ((p = bisector->intersection(rrbnd)) != NULL)
        {
          bisector->setYStar(p,bot->getLocation());
          pQueue.insert(bisector);
        }
     }
     else break;
  }
} catch( GeoEx &ex )
{
#ifdef __WIN32__
  ex.Explain( DiagOutWin("Erreur") );
#else
  DiagOutDOS out(cerr);
  ex.Explain( out );
#endif
}
  // Les halfEdges restant sont les edges non connectees du diagramme.
/*
  for(lbnd=ELright(ELleftend); lbnd != ELrightend; lbnd=ELright(lbnd))
  {
     e = lbnd -> ELedge;
     out_ep(e);
  }
*/
  pQueue.clear();
  delete pQueue.getSentinel();
  halfEdge::terminate();

  // Sanity Check
  /*
   * Un diagramme de Voronoi de N sites possede au plus 2N - 5 vertices
   * et 3N - 6 aretes.
   * ( Computational Geometry, [PREPARATA,SHAMOS] P.211 )
   */
  D( size_t N = edgeList->Faces().entries(); )
  D( cout << "Sites :" << N << " Vertices :" << edgeList->Vertices().entries() << " Aretes :" << edgeList->Edges().entries() << endl; )

  // Ne tient pas compte des vertices non attaches au diagrame
  // Cela peut parfois donner une fausse alarme.
  D( if( edgeList->Vertices().entries() > 2*N - 5 ) cout << "Voronoi: N = " << N << " numVertices = " << edgeList->Vertices().entries() << endl; )
  D( if( edgeList->Edges().entries() > 3*N - 6 ) cout << "Voronoi: N = " << N << " numEdges = " << edgeList->Edges().entries() << endl; )

  return edgeList;
}

#ifdef __GNUG__
template class PQ<halfEdge>;
#endif

Home :: Fractals :: Tutorials :: Books :: Archive :: My blog :: My LinkedIn Profile :: Contact