ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

sweep.c
Go to the documentation of this file.
00001 /*
00002 ** License Applicability. Except to the extent portions of this file are
00003 ** made subject to an alternative license as permitted in the SGI Free
00004 ** Software License B, Version 1.1 (the "License"), the contents of this
00005 ** file are subject only to the provisions of the License. You may not use
00006 ** this file except in compliance with the License. You may obtain a copy
00007 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
00008 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
00009 **
00010 ** http://oss.sgi.com/projects/FreeB
00011 **
00012 ** Note that, as provided in the License, the Software is distributed on an
00013 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
00014 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
00015 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
00016 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
00017 **
00018 ** Original Code. The Original Code is: OpenGL Sample Implementation,
00019 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
00020 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
00021 ** Copyright in any portions created by third parties is as indicated
00022 ** elsewhere herein. All Rights Reserved.
00023 **
00024 ** Additional Notice Provisions: The application programming interfaces
00025 ** established by SGI in conjunction with the Original Code are The
00026 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
00027 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
00028 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
00029 ** Window System(R) (Version 1.3), released October 19, 1998. This software
00030 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
00031 ** published by SGI, but has not been independently verified as being
00032 ** compliant with the OpenGL(R) version 1.2.1 Specification.
00033 **
00034 */
00035 /*
00036 ** Author: Eric Veach, July 1994.
00037 **
00038 */
00039 
00040 #include "gluos.h"
00041 #include <assert.h>
00042 #include <stddef.h>
00043 #include <setjmp.h>     /* longjmp */
00044 #include <limits.h>     /* LONG_MAX */
00045 
00046 #include "mesh.h"
00047 #include "geom.h"
00048 #include "tess.h"
00049 #include "dict.h"
00050 #include "priorityq.h"
00051 #include "memalloc.h"
00052 #include "sweep.h"
00053 
00054 #define TRUE 1
00055 #define FALSE 0
00056 
00057 #ifdef FOR_TRITE_TEST_PROGRAM
00058 extern void DebugEvent( GLUtesselator *tess );
00059 #else
00060 #define DebugEvent( tess )
00061 #endif
00062 
00063 /*
00064  * Invariants for the Edge Dictionary.
00065  * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2)
00066  *   at any valid location of the sweep event
00067  * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2
00068  *   share a common endpoint
00069  * - for each e, e->Dst has been processed, but not e->Org
00070  * - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org)
00071  *   where "event" is the current sweep line event.
00072  * - no edge e has zero length
00073  *
00074  * Invariants for the Mesh (the processed portion).
00075  * - the portion of the mesh left of the sweep line is a planar graph,
00076  *   ie. there is *some* way to embed it in the plane
00077  * - no processed edge has zero length
00078  * - no two processed vertices have identical coordinates
00079  * - each "inside" region is monotone, ie. can be broken into two chains
00080  *   of monotonically increasing vertices according to VertLeq(v1,v2)
00081  *   - a non-invariant: these chains may intersect (very slightly)
00082  *
00083  * Invariants for the Sweep.
00084  * - if none of the edges incident to the event vertex have an activeRegion
00085  *   (ie. none of these edges are in the edge dictionary), then the vertex
00086  *   has only right-going edges.
00087  * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced
00088  *   by ConnectRightVertex), then it is the only right-going edge from
00089  *   its associated vertex.  (This says that these edges exist only
00090  *   when it is necessary.)
00091  */
00092 
00093 #undef  MAX
00094 #undef  MIN
00095 #define MAX(x,y)    ((x) >= (y) ? (x) : (y))
00096 #define MIN(x,y)    ((x) <= (y) ? (x) : (y))
00097 
00098 /* When we merge two edges into one, we need to compute the combined
00099  * winding of the new edge.
00100  */
00101 #define AddWinding(eDst,eSrc)   (eDst->winding += eSrc->winding, \
00102                                  eDst->Sym->winding += eSrc->Sym->winding)
00103 
00104 static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent );
00105 static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp );
00106 static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp );
00107 
00108 static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1,
00109             ActiveRegion *reg2 )
00110 /*
00111  * Both edges must be directed from right to left (this is the canonical
00112  * direction for the upper edge of each region).
00113  *
00114  * The strategy is to evaluate a "t" value for each edge at the
00115  * current sweep line position, given by tess->event.  The calculations
00116  * are designed to be very stable, but of course they are not perfect.
00117  *
00118  * Special case: if both edge destinations are at the sweep event,
00119  * we sort the edges by slope (they would otherwise compare equally).
00120  */
00121 {
00122   GLUvertex *event = tess->event;
00123   GLUhalfEdge *e1, *e2;
00124   GLdouble t1, t2;
00125 
00126   e1 = reg1->eUp;
00127   e2 = reg2->eUp;
00128 
00129   if( e1->Dst == event ) {
00130     if( e2->Dst == event ) {
00131       /* Two edges right of the sweep line which meet at the sweep event.
00132        * Sort them by slope.
00133        */
00134       if( VertLeq( e1->Org, e2->Org )) {
00135     return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0;
00136       }
00137       return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0;
00138     }
00139     return EdgeSign( e2->Dst, event, e2->Org ) <= 0;
00140   }
00141   if( e2->Dst == event ) {
00142     return EdgeSign( e1->Dst, event, e1->Org ) >= 0;
00143   }
00144 
00145   /* General case - compute signed distance *from* e1, e2 to event */
00146   t1 = EdgeEval( e1->Dst, event, e1->Org );
00147   t2 = EdgeEval( e2->Dst, event, e2->Org );
00148   return (t1 >= t2);
00149 }
00150 
00151 
00152 static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg )
00153 {
00154   if( reg->fixUpperEdge ) {
00155     /* It was created with zero winding number, so it better be
00156      * deleted with zero winding number (ie. it better not get merged
00157      * with a real edge).
00158      */
00159     assert( reg->eUp->winding == 0 );
00160   }
00161   reg->eUp->activeRegion = NULL;
00162   dictDelete( tess->dict, reg->nodeUp ); /* __gl_dictListDelete */
00163   memFree( reg );
00164 }
00165 
00166 
00167 static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge )
00168 /*
00169  * Replace an upper edge which needs fixing (see ConnectRightVertex).
00170  */
00171 {
00172   assert( reg->fixUpperEdge );
00173   if ( !__gl_meshDelete( reg->eUp ) ) return 0;
00174   reg->fixUpperEdge = FALSE;
00175   reg->eUp = newEdge;
00176   newEdge->activeRegion = reg;
00177 
00178   return 1;
00179 }
00180 
00181 static ActiveRegion *TopLeftRegion( ActiveRegion *reg )
00182 {
00183   GLUvertex *org = reg->eUp->Org;
00184   GLUhalfEdge *e;
00185 
00186   /* Find the region above the uppermost edge with the same origin */
00187   do {
00188     reg = RegionAbove( reg );
00189   } while( reg->eUp->Org == org );
00190 
00191   /* If the edge above was a temporary edge introduced by ConnectRightVertex,
00192    * now is the time to fix it.
00193    */
00194   if( reg->fixUpperEdge ) {
00195     e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext );
00196     if (e == NULL) return NULL;
00197     if ( !FixUpperEdge( reg, e ) ) return NULL;
00198     reg = RegionAbove( reg );
00199   }
00200   return reg;
00201 }
00202 
00203 static ActiveRegion *TopRightRegion( ActiveRegion *reg )
00204 {
00205   GLUvertex *dst = reg->eUp->Dst;
00206 
00207   /* Find the region above the uppermost edge with the same destination */
00208   do {
00209     reg = RegionAbove( reg );
00210   } while( reg->eUp->Dst == dst );
00211   return reg;
00212 }
00213 
00214 static ActiveRegion *AddRegionBelow( GLUtesselator *tess,
00215                      ActiveRegion *regAbove,
00216                      GLUhalfEdge *eNewUp )
00217 /*
00218  * Add a new active region to the sweep line, *somewhere* below "regAbove"
00219  * (according to where the new edge belongs in the sweep-line dictionary).
00220  * The upper edge of the new region will be "eNewUp".
00221  * Winding number and "inside" flag are not updated.
00222  */
00223 {
00224   ActiveRegion *regNew = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
00225   if (regNew == NULL) longjmp(tess->env,1);
00226 
00227   regNew->eUp = eNewUp;
00228   /* __gl_dictListInsertBefore */
00229   regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew );
00230   if (regNew->nodeUp == NULL) longjmp(tess->env,1);
00231   regNew->fixUpperEdge = FALSE;
00232   regNew->sentinel = FALSE;
00233   regNew->dirty = FALSE;
00234 
00235   eNewUp->activeRegion = regNew;
00236   return regNew;
00237 }
00238 
00239 static GLboolean IsWindingInside( GLUtesselator *tess, int n )
00240 {
00241   switch( tess->windingRule ) {
00242   case GLU_TESS_WINDING_ODD:
00243     return (n & 1);
00244   case GLU_TESS_WINDING_NONZERO:
00245     return (n != 0);
00246   case GLU_TESS_WINDING_POSITIVE:
00247     return (n > 0);
00248   case GLU_TESS_WINDING_NEGATIVE:
00249     return (n < 0);
00250   case GLU_TESS_WINDING_ABS_GEQ_TWO:
00251     return (n >= 2) || (n <= -2);
00252   }
00253   /*LINTED*/
00254   assert( FALSE );
00255   /*NOTREACHED*/
00256   return GL_FALSE;  /* avoid compiler complaints */
00257 }
00258 
00259 
00260 static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg )
00261 {
00262   reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding;
00263   reg->inside = IsWindingInside( tess, reg->windingNumber );
00264 }
00265 
00266 
00267 static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg )
00268 /*
00269  * Delete a region from the sweep line.  This happens when the upper
00270  * and lower chains of a region meet (at a vertex on the sweep line).
00271  * The "inside" flag is copied to the appropriate mesh face (we could
00272  * not do this before -- since the structure of the mesh is always
00273  * changing, this face may not have even existed until now).
00274  */
00275 {
00276   GLUhalfEdge *e = reg->eUp;
00277   GLUface *f = e->Lface;
00278 
00279   f->inside = reg->inside;
00280   f->anEdge = e;   /* optimization for __gl_meshTessellateMonoRegion() */
00281   DeleteRegion( tess, reg );
00282 }
00283 
00284 
00285 static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess,
00286            ActiveRegion *regFirst, ActiveRegion *regLast )
00287 /*
00288  * We are given a vertex with one or more left-going edges.  All affected
00289  * edges should be in the edge dictionary.  Starting at regFirst->eUp,
00290  * we walk down deleting all regions where both edges have the same
00291  * origin vOrg.  At the same time we copy the "inside" flag from the
00292  * active region to the face, since at this point each face will belong
00293  * to at most one region (this was not necessarily true until this point
00294  * in the sweep).  The walk stops at the region above regLast; if regLast
00295  * is NULL we walk as far as possible.  At the same time we relink the
00296  * mesh if necessary, so that the ordering of edges around vOrg is the
00297  * same as in the dictionary.
00298  */
00299 {
00300   ActiveRegion *reg, *regPrev;
00301   GLUhalfEdge *e, *ePrev;
00302 
00303   regPrev = regFirst;
00304   ePrev = regFirst->eUp;
00305   while( regPrev != regLast ) {
00306     regPrev->fixUpperEdge = FALSE;  /* placement was OK */
00307     reg = RegionBelow( regPrev );
00308     e = reg->eUp;
00309     if( e->Org != ePrev->Org ) {
00310       if( ! reg->fixUpperEdge ) {
00311     /* Remove the last left-going edge.  Even though there are no further
00312      * edges in the dictionary with this origin, there may be further
00313      * such edges in the mesh (if we are adding left edges to a vertex
00314      * that has already been processed).  Thus it is important to call
00315      * FinishRegion rather than just DeleteRegion.
00316      */
00317     FinishRegion( tess, regPrev );
00318     break;
00319       }
00320       /* If the edge below was a temporary edge introduced by
00321        * ConnectRightVertex, now is the time to fix it.
00322        */
00323       e = __gl_meshConnect( ePrev->Lprev, e->Sym );
00324       if (e == NULL) longjmp(tess->env,1);
00325       if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1);
00326     }
00327 
00328     /* Relink edges so that ePrev->Onext == e */
00329     if( ePrev->Onext != e ) {
00330       if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
00331       if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1);
00332     }
00333     FinishRegion( tess, regPrev );  /* may change reg->eUp */
00334     ePrev = reg->eUp;
00335     regPrev = reg;
00336   }
00337   return ePrev;
00338 }
00339 
00340 
00341 static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp,
00342        GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft,
00343        GLboolean cleanUp )
00344 /*
00345  * Purpose: insert right-going edges into the edge dictionary, and update
00346  * winding numbers and mesh connectivity appropriately.  All right-going
00347  * edges share a common origin vOrg.  Edges are inserted CCW starting at
00348  * eFirst; the last edge inserted is eLast->Oprev.  If vOrg has any
00349  * left-going edges already processed, then eTopLeft must be the edge
00350  * such that an imaginary upward vertical segment from vOrg would be
00351  * contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft
00352  * should be NULL.
00353  */
00354 {
00355   ActiveRegion *reg, *regPrev;
00356   GLUhalfEdge *e, *ePrev;
00357   int firstTime = TRUE;
00358 
00359   /* Insert the new right-going edges in the dictionary */
00360   e = eFirst;
00361   do {
00362     assert( VertLeq( e->Org, e->Dst ));
00363     AddRegionBelow( tess, regUp, e->Sym );
00364     e = e->Onext;
00365   } while ( e != eLast );
00366 
00367   /* Walk *all* right-going edges from e->Org, in the dictionary order,
00368    * updating the winding numbers of each region, and re-linking the mesh
00369    * edges to match the dictionary ordering (if necessary).
00370    */
00371   if( eTopLeft == NULL ) {
00372     eTopLeft = RegionBelow( regUp )->eUp->Rprev;
00373   }
00374   regPrev = regUp;
00375   ePrev = eTopLeft;
00376   for( ;; ) {
00377     reg = RegionBelow( regPrev );
00378     e = reg->eUp->Sym;
00379     if( e->Org != ePrev->Org ) break;
00380 
00381     if( e->Onext != ePrev ) {
00382       /* Unlink e from its current position, and relink below ePrev */
00383       if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
00384       if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1);
00385     }
00386     /* Compute the winding number and "inside" flag for the new regions */
00387     reg->windingNumber = regPrev->windingNumber - e->winding;
00388     reg->inside = IsWindingInside( tess, reg->windingNumber );
00389 
00390     /* Check for two outgoing edges with same slope -- process these
00391      * before any intersection tests (see example in __gl_computeInterior).
00392      */
00393     regPrev->dirty = TRUE;
00394     if( ! firstTime && CheckForRightSplice( tess, regPrev )) {
00395       AddWinding( e, ePrev );
00396       DeleteRegion( tess, regPrev );
00397       if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1);
00398     }
00399     firstTime = FALSE;
00400     regPrev = reg;
00401     ePrev = e;
00402   }
00403   regPrev->dirty = TRUE;
00404   assert( regPrev->windingNumber - e->winding == reg->windingNumber );
00405 
00406   if( cleanUp ) {
00407     /* Check for intersections between newly adjacent edges. */
00408     WalkDirtyRegions( tess, regPrev );
00409   }
00410 }
00411 
00412 
00413 static void CallCombine( GLUtesselator *tess, GLUvertex *isect,
00414              void *data[4], GLfloat weights[4], int needed )
00415 {
00416   GLdouble coords[3];
00417 
00418   /* Copy coord data in case the callback changes it. */
00419   coords[0] = isect->coords[0];
00420   coords[1] = isect->coords[1];
00421   coords[2] = isect->coords[2];
00422 
00423   isect->data = NULL;
00424   CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data );
00425   if( isect->data == NULL ) {
00426     if( ! needed ) {
00427       isect->data = data[0];
00428     } else if( ! tess->fatalError ) {
00429       /* The only way fatal error is when two edges are found to intersect,
00430        * but the user has not provided the callback necessary to handle
00431        * generated intersection points.
00432        */
00433       CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK );
00434       tess->fatalError = TRUE;
00435     }
00436   }
00437 }
00438 
00439 static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1,
00440                  GLUhalfEdge *e2 )
00441 /*
00442  * Two vertices with idential coordinates are combined into one.
00443  * e1->Org is kept, while e2->Org is discarded.
00444  */
00445 {
00446   void *data[4] = { NULL, NULL, NULL, NULL };
00447   GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 };
00448 
00449   data[0] = e1->Org->data;
00450   data[1] = e2->Org->data;
00451   CallCombine( tess, e1->Org, data, weights, FALSE );
00452   if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1);
00453 }
00454 
00455 static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst,
00456                GLfloat *weights )
00457 /*
00458  * Find some weights which describe how the intersection vertex is
00459  * a linear combination of "org" and "dest".  Each of the two edges
00460  * which generated "isect" is allocated 50% of the weight; each edge
00461  * splits the weight between its org and dst according to the
00462  * relative distance to "isect".
00463  */
00464 {
00465   GLdouble t1 = VertL1dist( org, isect );
00466   GLdouble t2 = VertL1dist( dst, isect );
00467 
00468   weights[0] = 0.5 * t2 / (t1 + t2);
00469   weights[1] = 0.5 * t1 / (t1 + t2);
00470   isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0];
00471   isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1];
00472   isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2];
00473 }
00474 
00475 
00476 static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect,
00477        GLUvertex *orgUp, GLUvertex *dstUp,
00478        GLUvertex *orgLo, GLUvertex *dstLo )
00479 /*
00480  * We've computed a new intersection point, now we need a "data" pointer
00481  * from the user so that we can refer to this new vertex in the
00482  * rendering callbacks.
00483  */
00484 {
00485   void *data[4];
00486   GLfloat weights[4];
00487 
00488   data[0] = orgUp->data;
00489   data[1] = dstUp->data;
00490   data[2] = orgLo->data;
00491   data[3] = dstLo->data;
00492 
00493   isect->coords[0] = isect->coords[1] = isect->coords[2] = 0;
00494   VertexWeights( isect, orgUp, dstUp, &weights[0] );
00495   VertexWeights( isect, orgLo, dstLo, &weights[2] );
00496 
00497   CallCombine( tess, isect, data, weights, TRUE );
00498 }
00499 
00500 static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp )
00501 /*
00502  * Check the upper and lower edge of "regUp", to make sure that the
00503  * eUp->Org is above eLo, or eLo->Org is below eUp (depending on which
00504  * origin is leftmost).
00505  *
00506  * The main purpose is to splice right-going edges with the same
00507  * dest vertex and nearly identical slopes (ie. we can't distinguish
00508  * the slopes numerically).  However the splicing can also help us
00509  * to recover from numerical errors.  For example, suppose at one
00510  * point we checked eUp and eLo, and decided that eUp->Org is barely
00511  * above eLo.  Then later, we split eLo into two edges (eg. from
00512  * a splice operation like this one).  This can change the result of
00513  * our test so that now eUp->Org is incident to eLo, or barely below it.
00514  * We must correct this condition to maintain the dictionary invariants.
00515  *
00516  * One possibility is to check these edges for intersection again
00517  * (ie. CheckForIntersect).  This is what we do if possible.  However
00518  * CheckForIntersect requires that tess->event lies between eUp and eLo,
00519  * so that it has something to fall back on when the intersection
00520  * calculation gives us an unusable answer.  So, for those cases where
00521  * we can't check for intersection, this routine fixes the problem
00522  * by just splicing the offending vertex into the other edge.
00523  * This is a guaranteed solution, no matter how degenerate things get.
00524  * Basically this is a combinatorial solution to a numerical problem.
00525  */
00526 {
00527   ActiveRegion *regLo = RegionBelow(regUp);
00528   GLUhalfEdge *eUp = regUp->eUp;
00529   GLUhalfEdge *eLo = regLo->eUp;
00530 
00531   if( VertLeq( eUp->Org, eLo->Org )) {
00532     if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE;
00533 
00534     /* eUp->Org appears to be below eLo */
00535     if( ! VertEq( eUp->Org, eLo->Org )) {
00536       /* Splice eUp->Org into eLo */
00537       if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
00538       if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1);
00539       regUp->dirty = regLo->dirty = TRUE;
00540 
00541     } else if( eUp->Org != eLo->Org ) {
00542       /* merge the two vertices, discarding eUp->Org */
00543       pqDelete( tess->pq, eUp->Org->pqHandle ); /* __gl_pqSortDelete */
00544       SpliceMergeVertices( tess, eLo->Oprev, eUp );
00545     }
00546   } else {
00547     if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE;
00548 
00549     /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */
00550     RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
00551     if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
00552     if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
00553   }
00554   return TRUE;
00555 }
00556 
00557 static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp )
00558 /*
00559  * Check the upper and lower edge of "regUp", to make sure that the
00560  * eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which
00561  * destination is rightmost).
00562  *
00563  * Theoretically, this should always be true.  However, splitting an edge
00564  * into two pieces can change the results of previous tests.  For example,
00565  * suppose at one point we checked eUp and eLo, and decided that eUp->Dst
00566  * is barely above eLo.  Then later, we split eLo into two edges (eg. from
00567  * a splice operation like this one).  This can change the result of
00568  * the test so that now eUp->Dst is incident to eLo, or barely below it.
00569  * We must correct this condition to maintain the dictionary invariants
00570  * (otherwise new edges might get inserted in the wrong place in the
00571  * dictionary, and bad stuff will happen).
00572  *
00573  * We fix the problem by just splicing the offending vertex into the
00574  * other edge.
00575  */
00576 {
00577   ActiveRegion *regLo = RegionBelow(regUp);
00578   GLUhalfEdge *eUp = regUp->eUp;
00579   GLUhalfEdge *eLo = regLo->eUp;
00580   GLUhalfEdge *e;
00581 
00582   assert( ! VertEq( eUp->Dst, eLo->Dst ));
00583 
00584   if( VertLeq( eUp->Dst, eLo->Dst )) {
00585     if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE;
00586 
00587     /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */
00588     RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
00589     e = __gl_meshSplitEdge( eUp );
00590     if (e == NULL) longjmp(tess->env,1);
00591     if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1);
00592     e->Lface->inside = regUp->inside;
00593   } else {
00594     if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE;
00595 
00596     /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */
00597     regUp->dirty = regLo->dirty = TRUE;
00598     e = __gl_meshSplitEdge( eLo );
00599     if (e == NULL) longjmp(tess->env,1);
00600     if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1);
00601     e->Rface->inside = regUp->inside;
00602   }
00603   return TRUE;
00604 }
00605 
00606 
00607 static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp )
00608 /*
00609  * Check the upper and lower edges of the given region to see if
00610  * they intersect.  If so, create the intersection and add it
00611  * to the data structures.
00612  *
00613  * Returns TRUE if adding the new intersection resulted in a recursive
00614  * call to AddRightEdges(); in this case all "dirty" regions have been
00615  * checked for intersections, and possibly regUp has been deleted.
00616  */
00617 {
00618   ActiveRegion *regLo = RegionBelow(regUp);
00619   GLUhalfEdge *eUp = regUp->eUp;
00620   GLUhalfEdge *eLo = regLo->eUp;
00621   GLUvertex *orgUp = eUp->Org;
00622   GLUvertex *orgLo = eLo->Org;
00623   GLUvertex *dstUp = eUp->Dst;
00624   GLUvertex *dstLo = eLo->Dst;
00625   GLdouble tMinUp, tMaxLo;
00626   GLUvertex isect, *orgMin;
00627   GLUhalfEdge *e;
00628 
00629   assert( ! VertEq( dstLo, dstUp ));
00630   assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 );
00631   assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 );
00632   assert( orgUp != tess->event && orgLo != tess->event );
00633   assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge );
00634 
00635   if( orgUp == orgLo ) return FALSE;    /* right endpoints are the same */
00636 
00637   tMinUp = MIN( orgUp->t, dstUp->t );
00638   tMaxLo = MAX( orgLo->t, dstLo->t );
00639   if( tMinUp > tMaxLo ) return FALSE;   /* t ranges do not overlap */
00640 
00641   if( VertLeq( orgUp, orgLo )) {
00642     if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE;
00643   } else {
00644     if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE;
00645   }
00646 
00647   /* At this point the edges intersect, at least marginally */
00648   DebugEvent( tess );
00649 
00650   __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect );
00651   /* The following properties are guaranteed: */
00652   assert( MIN( orgUp->t, dstUp->t ) <= isect.t );
00653   assert( isect.t <= MAX( orgLo->t, dstLo->t ));
00654   assert( MIN( dstLo->s, dstUp->s ) <= isect.s );
00655   assert( isect.s <= MAX( orgLo->s, orgUp->s ));
00656 
00657   if( VertLeq( &isect, tess->event )) {
00658     /* The intersection point lies slightly to the left of the sweep line,
00659      * so move it until it''s slightly to the right of the sweep line.
00660      * (If we had perfect numerical precision, this would never happen
00661      * in the first place).  The easiest and safest thing to do is
00662      * replace the intersection by tess->event.
00663      */
00664     isect.s = tess->event->s;
00665     isect.t = tess->event->t;
00666   }
00667   /* Similarly, if the computed intersection lies to the right of the
00668    * rightmost origin (which should rarely happen), it can cause
00669    * unbelievable inefficiency on sufficiently degenerate inputs.
00670    * (If you have the test program, try running test54.d with the
00671    * "X zoom" option turned on).
00672    */
00673   orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo;
00674   if( VertLeq( orgMin, &isect )) {
00675     isect.s = orgMin->s;
00676     isect.t = orgMin->t;
00677   }
00678 
00679   if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) {
00680     /* Easy case -- intersection at one of the right endpoints */
00681     (void) CheckForRightSplice( tess, regUp );
00682     return FALSE;
00683   }
00684 
00685   if(    (! VertEq( dstUp, tess->event )
00686       && EdgeSign( dstUp, tess->event, &isect ) >= 0)
00687       || (! VertEq( dstLo, tess->event )
00688       && EdgeSign( dstLo, tess->event, &isect ) <= 0 ))
00689   {
00690     /* Very unusual -- the new upper or lower edge would pass on the
00691      * wrong side of the sweep event, or through it.  This can happen
00692      * due to very small numerical errors in the intersection calculation.
00693      */
00694     if( dstLo == tess->event ) {
00695       /* Splice dstLo into eUp, and process the new region(s) */
00696       if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
00697       if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1);
00698       regUp = TopLeftRegion( regUp );
00699       if (regUp == NULL) longjmp(tess->env,1);
00700       eUp = RegionBelow(regUp)->eUp;
00701       FinishLeftRegions( tess, RegionBelow(regUp), regLo );
00702       AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE );
00703       return TRUE;
00704     }
00705     if( dstUp == tess->event ) {
00706       /* Splice dstUp into eLo, and process the new region(s) */
00707       if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
00708       if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1);
00709       regLo = regUp;
00710       regUp = TopRightRegion( regUp );
00711       e = RegionBelow(regUp)->eUp->Rprev;
00712       regLo->eUp = eLo->Oprev;
00713       eLo = FinishLeftRegions( tess, regLo, NULL );
00714       AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE );
00715       return TRUE;
00716     }
00717     /* Special case: called from ConnectRightVertex.  If either
00718      * edge passes on the wrong side of tess->event, split it
00719      * (and wait for ConnectRightVertex to splice it appropriately).
00720      */
00721     if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) {
00722       RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
00723       if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
00724       eUp->Org->s = tess->event->s;
00725       eUp->Org->t = tess->event->t;
00726     }
00727     if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) {
00728       regUp->dirty = regLo->dirty = TRUE;
00729       if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
00730       eLo->Org->s = tess->event->s;
00731       eLo->Org->t = tess->event->t;
00732     }
00733     /* leave the rest for ConnectRightVertex */
00734     return FALSE;
00735   }
00736 
00737   /* General case -- split both edges, splice into new vertex.
00738    * When we do the splice operation, the order of the arguments is
00739    * arbitrary as far as correctness goes.  However, when the operation
00740    * creates a new face, the work done is proportional to the size of
00741    * the new face.  We expect the faces in the processed part of
00742    * the mesh (ie. eUp->Lface) to be smaller than the faces in the
00743    * unprocessed original contours (which will be eLo->Oprev->Lface).
00744    */
00745   if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
00746   if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
00747   if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
00748   eUp->Org->s = isect.s;
00749   eUp->Org->t = isect.t;
00750   eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org ); /* __gl_pqSortInsert */
00751   if (eUp->Org->pqHandle == LONG_MAX) {
00752      pqDeletePriorityQ(tess->pq);   /* __gl_pqSortDeletePriorityQ */
00753      tess->pq = NULL;
00754      longjmp(tess->env,1);
00755   }
00756   GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo );
00757   RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE;
00758   return FALSE;
00759 }
00760 
00761 static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp )
00762 /*
00763  * When the upper or lower edge of any region changes, the region is
00764  * marked "dirty".  This routine walks through all the dirty regions
00765  * and makes sure that the dictionary invariants are satisfied
00766  * (see the comments at the beginning of this file).  Of course
00767  * new dirty regions can be created as we make changes to restore
00768  * the invariants.
00769  */
00770 {
00771   ActiveRegion *regLo = RegionBelow(regUp);
00772   GLUhalfEdge *eUp, *eLo;
00773 
00774   for( ;; ) {
00775     /* Find the lowest dirty region (we walk from the bottom up). */
00776     while( regLo->dirty ) {
00777       regUp = regLo;
00778       regLo = RegionBelow(regLo);
00779     }
00780     if( ! regUp->dirty ) {
00781       regLo = regUp;
00782       regUp = RegionAbove( regUp );
00783       if( regUp == NULL || ! regUp->dirty ) {
00784     /* We've walked all the dirty regions */
00785     return;
00786       }
00787     }
00788     regUp->dirty = FALSE;
00789     eUp = regUp->eUp;
00790     eLo = regLo->eUp;
00791 
00792     if( eUp->Dst != eLo->Dst ) {
00793       /* Check that the edge ordering is obeyed at the Dst vertices. */
00794       if( CheckForLeftSplice( tess, regUp )) {
00795 
00796     /* If the upper or lower edge was marked fixUpperEdge, then
00797      * we no longer need it (since these edges are needed only for
00798      * vertices which otherwise have no right-going edges).
00799      */
00800     if( regLo->fixUpperEdge ) {
00801       DeleteRegion( tess, regLo );
00802       if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1);
00803       regLo = RegionBelow( regUp );
00804       eLo = regLo->eUp;
00805     } else if( regUp->fixUpperEdge ) {
00806       DeleteRegion( tess, regUp );
00807       if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
00808       regUp = RegionAbove( regLo );
00809       eUp = regUp->eUp;
00810     }
00811       }
00812     }
00813     if( eUp->Org != eLo->Org ) {
00814       if(    eUp->Dst != eLo->Dst
00815       && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge
00816       && (eUp->Dst == tess->event || eLo->Dst == tess->event) )
00817       {
00818     /* When all else fails in CheckForIntersect(), it uses tess->event
00819      * as the intersection location.  To make this possible, it requires
00820      * that tess->event lie between the upper and lower edges, and also
00821      * that neither of these is marked fixUpperEdge (since in the worst
00822      * case it might splice one of these edges into tess->event, and
00823      * violate the invariant that fixable edges are the only right-going
00824      * edge from their associated vertex).
00825      */
00826     if( CheckForIntersect( tess, regUp )) {
00827       /* WalkDirtyRegions() was called recursively; we're done */
00828       return;
00829     }
00830       } else {
00831     /* Even though we can't use CheckForIntersect(), the Org vertices
00832      * may violate the dictionary edge ordering.  Check and correct this.
00833      */
00834     (void) CheckForRightSplice( tess, regUp );
00835       }
00836     }
00837     if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) {
00838       /* A degenerate loop consisting of only two edges -- delete it. */
00839       AddWinding( eLo, eUp );
00840       DeleteRegion( tess, regUp );
00841       if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
00842       regUp = RegionAbove( regLo );
00843     }
00844   }
00845 }
00846 
00847 
00848 static void ConnectRightVertex( GLUtesselator *tess, ActiveRegion *regUp,
00849                 GLUhalfEdge *eBottomLeft )
00850 /*
00851  * Purpose: connect a "right" vertex vEvent (one where all edges go left)
00852  * to the unprocessed portion of the mesh.  Since there are no right-going
00853  * edges, two regions (one above vEvent and one below) are being merged
00854  * into one.  "regUp" is the upper of these two regions.
00855  *
00856  * There are two reasons for doing this (adding a right-going edge):
00857  *  - if the two regions being merged are "inside", we must add an edge
00858  *    to keep them separated (the combined region would not be monotone).
00859  *  - in any case, we must leave some record of vEvent in the dictionary,
00860  *    so that we can merge vEvent with features that we have not seen yet.
00861  *    For example, maybe there is a vertical edge which passes just to
00862  *    the right of vEvent; we would like to splice vEvent into this edge.
00863  *
00864  * However, we don't want to connect vEvent to just any vertex.  We don''t
00865  * want the new edge to cross any other edges; otherwise we will create
00866  * intersection vertices even when the input data had no self-intersections.
00867  * (This is a bad thing; if the user's input data has no intersections,
00868  * we don't want to generate any false intersections ourselves.)
00869  *
00870  * Our eventual goal is to connect vEvent to the leftmost unprocessed
00871  * vertex of the combined region (the union of regUp and regLo).
00872  * But because of unseen vertices with all right-going edges, and also
00873  * new vertices which may be created by edge intersections, we don''t
00874  * know where that leftmost unprocessed vertex is.  In the meantime, we
00875  * connect vEvent to the closest vertex of either chain, and mark the region
00876  * as "fixUpperEdge".  This flag says to delete and reconnect this edge
00877  * to the next processed vertex on the boundary of the combined region.
00878  * Quite possibly the vertex we connected to will turn out to be the
00879  * closest one, in which case we won''t need to make any changes.
00880  */
00881 {
00882   GLUhalfEdge *eNew;
00883   GLUhalfEdge *eTopLeft = eBottomLeft->Onext;
00884   ActiveRegion *regLo = RegionBelow(regUp);
00885   GLUhalfEdge *eUp = regUp->eUp;
00886   GLUhalfEdge *eLo = regLo->eUp;
00887   int degenerate = FALSE;
00888 
00889   if( eUp->Dst != eLo->Dst ) {
00890     (void) CheckForIntersect( tess, regUp );
00891   }
00892 
00893   /* Possible new degeneracies: upper or lower edge of regUp may pass
00894    * through vEvent, or may coincide with new intersection vertex
00895    */
00896   if( VertEq( eUp->Org, tess->event )) {
00897     if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1);
00898     regUp = TopLeftRegion( regUp );
00899     if (regUp == NULL) longjmp(tess->env,1);
00900     eTopLeft = RegionBelow( regUp )->eUp;
00901     FinishLeftRegions( tess, RegionBelow(regUp), regLo );
00902     degenerate = TRUE;
00903   }
00904   if( VertEq( eLo->Org, tess->event )) {
00905     if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1);
00906     eBottomLeft = FinishLeftRegions( tess, regLo, NULL );
00907     degenerate = TRUE;
00908   }
00909   if( degenerate ) {
00910     AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
00911     return;
00912   }
00913 
00914   /* Non-degenerate situation -- need to add a temporary, fixable edge.
00915    * Connect to the closer of eLo->Org, eUp->Org.
00916    */
00917   if( VertLeq( eLo->Org, eUp->Org )) {
00918     eNew = eLo->Oprev;
00919   } else {
00920     eNew = eUp;
00921   }
00922   eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew );
00923   if (eNew == NULL) longjmp(tess->env,1);
00924 
00925   /* Prevent cleanup, otherwise eNew might disappear before we've even
00926    * had a chance to mark it as a temporary edge.
00927    */
00928   AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE );
00929   eNew->Sym->activeRegion->fixUpperEdge = TRUE;
00930   WalkDirtyRegions( tess, regUp );
00931 }
00932 
00933 /* Because vertices at exactly the same location are merged together
00934  * before we process the sweep event, some degenerate cases can't occur.
00935  * However if someone eventually makes the modifications required to
00936  * merge features which are close together, the cases below marked
00937  * TOLERANCE_NONZERO will be useful.  They were debugged before the
00938  * code to merge identical vertices in the main loop was added.
00939  */
00940 #define TOLERANCE_NONZERO   FALSE
00941 
00942 static void ConnectLeftDegenerate( GLUtesselator *tess,
00943                    ActiveRegion *regUp, GLUvertex *vEvent )
00944 /*
00945  * The event vertex lies exacty on an already-processed edge or vertex.
00946  * Adding the new vertex involves splicing it into the already-processed
00947  * part of the mesh.
00948  */
00949 {
00950   GLUhalfEdge *e, *eTopLeft, *eTopRight, *eLast;
00951   ActiveRegion *reg;
00952 
00953   e = regUp->eUp;
00954   if( VertEq( e->Org, vEvent )) {
00955     /* e->Org is an unprocessed vertex - just combine them, and wait
00956      * for e->Org to be pulled from the queue
00957      */
00958     assert( TOLERANCE_NONZERO );
00959     SpliceMergeVertices( tess, e, vEvent->anEdge );
00960     return;
00961   }
00962 
00963   if( ! VertEq( e->Dst, vEvent )) {
00964     /* General case -- splice vEvent into edge e which passes through it */
00965     if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1);
00966     if( regUp->fixUpperEdge ) {
00967       /* This edge was fixable -- delete unused portion of original edge */
00968       if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1);
00969       regUp->fixUpperEdge = FALSE;
00970     }
00971     if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1);
00972     SweepEvent( tess, vEvent ); /* recurse */
00973     return;
00974   }
00975 
00976   /* vEvent coincides with e->Dst, which has already been processed.
00977    * Splice in the additional right-going edges.
00978    */
00979   assert( TOLERANCE_NONZERO );
00980   regUp = TopRightRegion( regUp );
00981   reg = RegionBelow( regUp );
00982   eTopRight = reg->eUp->Sym;
00983   eTopLeft = eLast = eTopRight->Onext;
00984   if( reg->fixUpperEdge ) {
00985     /* Here e->Dst has only a single fixable edge going right.
00986      * We can delete it since now we have some real right-going edges.
00987      */
00988     assert( eTopLeft != eTopRight );   /* there are some left edges too */
00989     DeleteRegion( tess, reg );
00990     if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1);
00991     eTopRight = eTopLeft->Oprev;
00992   }
00993   if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1);
00994   if( ! EdgeGoesLeft( eTopLeft )) {
00995     /* e->Dst had no left-going edges -- indicate this to AddRightEdges() */
00996     eTopLeft = NULL;
00997   }
00998   AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE );
00999 }
01000 
01001 
01002 static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent )
01003 /*
01004  * Purpose: connect a "left" vertex (one where both edges go right)
01005  * to the processed portion of the mesh.  Let R be the active region
01006  * containing vEvent, and let U and L be the upper and lower edge
01007  * chains of R.  There are two possibilities:
01008  *
01009  * - the normal case: split R into two regions, by connecting vEvent to
01010  *   the rightmost vertex of U or L lying to the left of the sweep line
01011  *
01012  * - the degenerate case: if vEvent is close enough to U or L, we
01013  *   merge vEvent into that edge chain.  The subcases are:
01014  *  - merging with the rightmost vertex of U or L
01015  *  - merging with the active edge of U or L
01016  *  - merging with an already-processed portion of U or L
01017  */
01018 {
01019   ActiveRegion *regUp, *regLo, *reg;
01020   GLUhalfEdge *eUp, *eLo, *eNew;
01021   ActiveRegion tmp;
01022 
01023   /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */
01024 
01025   /* Get a pointer to the active region containing vEvent */
01026   tmp.eUp = vEvent->anEdge->Sym;
01027   /* __GL_DICTLISTKEY */ /* __gl_dictListSearch */
01028   regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp ));
01029   regLo = RegionBelow( regUp );
01030   eUp = regUp->eUp;
01031   eLo = regLo->eUp;
01032 
01033   /* Try merging with U or L first */
01034   if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) {
01035     ConnectLeftDegenerate( tess, regUp, vEvent );
01036     return;
01037   }
01038 
01039   /* Connect vEvent to rightmost processed vertex of either chain.
01040    * e->Dst is the vertex that we will connect to vEvent.
01041    */
01042   reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo;
01043 
01044   if( regUp->inside || reg->fixUpperEdge) {
01045     if( reg == regUp ) {
01046       eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext );
01047       if (eNew == NULL) longjmp(tess->env,1);
01048     } else {
01049       GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge);
01050       if (tempHalfEdge == NULL) longjmp(tess->env,1);
01051 
01052       eNew = tempHalfEdge->Sym;
01053     }
01054     if( reg->fixUpperEdge ) {
01055       if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1);
01056     } else {
01057       ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew ));
01058     }
01059     SweepEvent( tess, vEvent );
01060   } else {
01061     /* The new vertex is in a region which does not belong to the polygon.
01062      * We don''t need to connect this vertex to the rest of the mesh.
01063      */
01064     AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE );
01065   }
01066 }
01067 
01068 
01069 static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent )
01070 /*
01071  * Does everything necessary when the sweep line crosses a vertex.
01072  * Updates the mesh and the edge dictionary.
01073  */
01074 {
01075   ActiveRegion *regUp, *reg;
01076   GLUhalfEdge *e, *eTopLeft, *eBottomLeft;
01077 
01078   tess->event = vEvent;     /* for access in EdgeLeq() */
01079   DebugEvent( tess );
01080 
01081   /* Check if this vertex is the right endpoint of an edge that is
01082    * already in the dictionary.  In this case we don't need to waste
01083    * time searching for the location to insert new edges.
01084    */
01085   e = vEvent->anEdge;
01086   while( e->activeRegion == NULL ) {
01087     e = e->Onext;
01088     if( e == vEvent->anEdge ) {
01089       /* All edges go right -- not incident to any processed edges */
01090       ConnectLeftVertex( tess, vEvent );
01091       return;
01092     }
01093   }
01094 
01095   /* Processing consists of two phases: first we "finish" all the
01096    * active regions where both the upper and lower edges terminate
01097    * at vEvent (ie. vEvent is closing off these regions).
01098    * We mark these faces "inside" or "outside" the polygon according
01099    * to their winding number, and delete the edges from the dictionary.
01100    * This takes care of all the left-going edges from vEvent.
01101    */
01102   regUp = TopLeftRegion( e->activeRegion );
01103   if (regUp == NULL) longjmp(tess->env,1);
01104   reg = RegionBelow( regUp );
01105   eTopLeft = reg->eUp;
01106   eBottomLeft = FinishLeftRegions( tess, reg, NULL );
01107 
01108   /* Next we process all the right-going edges from vEvent.  This
01109    * involves adding the edges to the dictionary, and creating the
01110    * associated "active regions" which record information about the
01111    * regions between adjacent dictionary edges.
01112    */
01113   if( eBottomLeft->Onext == eTopLeft ) {
01114     /* No right-going edges -- add a temporary "fixable" edge */
01115     ConnectRightVertex( tess, regUp, eBottomLeft );
01116   } else {
01117     AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
01118   }
01119 }
01120 
01121 
01122 /* Make the sentinel coordinates big enough that they will never be
01123  * merged with real input features.  (Even with the largest possible
01124  * input contour and the maximum tolerance of 1.0, no merging will be
01125  * done with coordinates larger than 3 * GLU_TESS_MAX_COORD).
01126  */
01127 #define SENTINEL_COORD  (4 * GLU_TESS_MAX_COORD)
01128 
01129 static void AddSentinel( GLUtesselator *tess, GLdouble t )
01130 /*
01131  * We add two sentinel edges above and below all other edges,
01132  * to avoid special cases at the top and bottom.
01133  */
01134 {
01135   GLUhalfEdge *e;
01136   ActiveRegion *reg = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
01137   if (reg == NULL) longjmp(tess->env,1);
01138 
01139   e = __gl_meshMakeEdge( tess->mesh );
01140   if (e == NULL) longjmp(tess->env,1);
01141 
01142   e->Org->s = SENTINEL_COORD;
01143   e->Org->t = t;
01144   e->Dst->s = -SENTINEL_COORD;
01145   e->Dst->t = t;
01146   tess->event = e->Dst;     /* initialize it */
01147 
01148   reg->eUp = e;
01149   reg->windingNumber = 0;
01150   reg->inside = FALSE;
01151   reg->fixUpperEdge = FALSE;
01152   reg->sentinel = TRUE;
01153   reg->dirty = FALSE;
01154   reg->nodeUp = dictInsert( tess->dict, reg ); /* __gl_dictListInsertBefore */
01155   if (reg->nodeUp == NULL) longjmp(tess->env,1);
01156 }
01157 
01158 
01159 static void InitEdgeDict( GLUtesselator *tess )
01160 /*
01161  * We maintain an ordering of edge intersections with the sweep line.
01162  * This order is maintained in a dynamic dictionary.
01163  */
01164 {
01165   /* __gl_dictListNewDict */
01166   tess->dict = dictNewDict( tess, (int (*)(void *, DictKey, DictKey)) EdgeLeq );
01167   if (tess->dict == NULL) longjmp(tess->env,1);
01168 
01169   AddSentinel( tess, -SENTINEL_COORD );
01170   AddSentinel( tess, SENTINEL_COORD );
01171 }
01172 
01173 
01174 static void DoneEdgeDict( GLUtesselator *tess )
01175 {
01176   ActiveRegion *reg;
01177 #ifndef NDEBUG
01178   int fixedEdges = 0;
01179 #endif
01180 
01181   /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
01182   while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) {
01183     /*
01184      * At the end of all processing, the dictionary should contain
01185      * only the two sentinel edges, plus at most one "fixable" edge
01186      * created by ConnectRightVertex().
01187      */
01188     if( ! reg->sentinel ) {
01189       assert( reg->fixUpperEdge );
01190       assert( ++fixedEdges == 1 );
01191     }
01192     assert( reg->windingNumber == 0 );
01193     DeleteRegion( tess, reg );
01194 /*    __gl_meshDelete( reg->eUp );*/
01195   }
01196   dictDeleteDict( tess->dict ); /* __gl_dictListDeleteDict */
01197 }
01198 
01199 
01200 static void RemoveDegenerateEdges( GLUtesselator *tess )
01201 /*
01202  * Remove zero-length edges, and contours with fewer than 3 vertices.
01203  */
01204 {
01205   GLUhalfEdge *e, *eNext, *eLnext;
01206   GLUhalfEdge *eHead = &tess->mesh->eHead;
01207 
01208   /*LINTED*/
01209   for( e = eHead->next; e != eHead; e = eNext ) {
01210     eNext = e->next;
01211     eLnext = e->Lnext;
01212 
01213     if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) {
01214       /* Zero-length edge, contour has at least 3 edges */
01215 
01216       SpliceMergeVertices( tess, eLnext, e );   /* deletes e->Org */
01217       if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); /* e is a self-loop */
01218       e = eLnext;
01219       eLnext = e->Lnext;
01220     }
01221     if( eLnext->Lnext == e ) {
01222       /* Degenerate contour (one or two edges) */
01223 
01224       if( eLnext != e ) {
01225     if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; }
01226     if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1);
01227       }
01228       if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; }
01229       if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1);
01230     }
01231   }
01232 }
01233 
01234 static int InitPriorityQ( GLUtesselator *tess )
01235 /*
01236  * Insert all vertices into the priority queue which determines the
01237  * order in which vertices cross the sweep line.
01238  */
01239 {
01240   PriorityQ *pq;
01241   GLUvertex *v, *vHead;
01242 
01243   /* __gl_pqSortNewPriorityQ */
01244   pq = tess->pq = pqNewPriorityQ( (int (*)(PQkey, PQkey)) __gl_vertLeq );
01245   if (pq == NULL) return 0;
01246 
01247   vHead = &tess->mesh->vHead;
01248   for( v = vHead->next; v != vHead; v = v->next ) {
01249     v->pqHandle = pqInsert( pq, v ); /* __gl_pqSortInsert */
01250     if (v->pqHandle == LONG_MAX) break;
01251   }
01252   if (v != vHead || !pqInit( pq ) ) { /* __gl_pqSortInit */
01253     pqDeletePriorityQ(tess->pq);    /* __gl_pqSortDeletePriorityQ */
01254     tess->pq = NULL;
01255     return 0;
01256   }
01257 
01258   return 1;
01259 }
01260 
01261 
01262 static void DonePriorityQ( GLUtesselator *tess )
01263 {
01264   pqDeletePriorityQ( tess->pq ); /* __gl_pqSortDeletePriorityQ */
01265 }
01266 
01267 
01268 static int RemoveDegenerateFaces( GLUmesh *mesh )
01269 /*
01270  * Delete any degenerate faces with only two edges.  WalkDirtyRegions()
01271  * will catch almost all of these, but it won't catch degenerate faces
01272  * produced by splice operations on already-processed edges.
01273  * The two places this can happen are in FinishLeftRegions(), when
01274  * we splice in a "temporary" edge produced by ConnectRightVertex(),
01275  * and in CheckForLeftSplice(), where we splice already-processed
01276  * edges to ensure that our dictionary invariants are not violated
01277  * by numerical errors.
01278  *
01279  * In both these cases it is *very* dangerous to delete the offending
01280  * edge at the time, since one of the routines further up the stack
01281  * will sometimes be keeping a pointer to that edge.
01282  */
01283 {
01284   GLUface *f, *fNext;
01285   GLUhalfEdge *e;
01286 
01287   /*LINTED*/
01288   for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
01289     fNext = f->next;
01290     e = f->anEdge;
01291     assert( e->Lnext != e );
01292 
01293     if( e->Lnext->Lnext == e ) {
01294       /* A face with only two edges */
01295       AddWinding( e->Onext, e );
01296       if ( !__gl_meshDelete( e ) ) return 0;
01297     }
01298   }
01299   return 1;
01300 }
01301 
01302 int __gl_computeInterior( GLUtesselator *tess )
01303 /*
01304  * __gl_computeInterior( tess ) computes the planar arrangement specified
01305  * by the given contours, and further subdivides this arrangement
01306  * into regions.  Each region is marked "inside" if it belongs
01307  * to the polygon, according to the rule given by tess->windingRule.
01308  * Each interior region is guaranteed be monotone.
01309  */
01310 {
01311   GLUvertex *v, *vNext;
01312 
01313   tess->fatalError = FALSE;
01314 
01315   /* Each vertex defines an event for our sweep line.  Start by inserting
01316    * all the vertices in a priority queue.  Events are processed in
01317    * lexicographic order, ie.
01318    *
01319    *    e1 < e2  iff  e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y)
01320    */
01321   RemoveDegenerateEdges( tess );
01322   if ( !InitPriorityQ( tess ) ) return 0; /* if error */
01323   InitEdgeDict( tess );
01324 
01325   /* __gl_pqSortExtractMin */
01326   while( (v = (GLUvertex *)pqExtractMin( tess->pq )) != NULL ) {
01327     for( ;; ) {
01328       vNext = (GLUvertex *)pqMinimum( tess->pq ); /* __gl_pqSortMinimum */
01329       if( vNext == NULL || ! VertEq( vNext, v )) break;
01330 
01331       /* Merge together all vertices at exactly the same location.
01332        * This is more efficient than processing them one at a time,
01333        * simplifies the code (see ConnectLeftDegenerate), and is also
01334        * important for correct handling of certain degenerate cases.
01335        * For example, suppose there are two identical edges A and B
01336        * that belong to different contours (so without this code they would
01337        * be processed by separate sweep events).  Suppose another edge C
01338        * crosses A and B from above.  When A is processed, we split it
01339        * at its intersection point with C.  However this also splits C,
01340        * so when we insert B we may compute a slightly different
01341        * intersection point.  This might leave two edges with a small
01342        * gap between them.  This kind of error is especially obvious
01343        * when using boundary extraction (GLU_TESS_BOUNDARY_ONLY).
01344        */
01345       vNext = (GLUvertex *)pqExtractMin( tess->pq ); /* __gl_pqSortExtractMin*/
01346       SpliceMergeVertices( tess, v->anEdge, vNext->anEdge );
01347     }
01348     SweepEvent( tess, v );
01349   }
01350 
01351   /* Set tess->event for debugging purposes */
01352   /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
01353   tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org;
01354   DebugEvent( tess );
01355   DoneEdgeDict( tess );
01356   DonePriorityQ( tess );
01357 
01358   if ( !RemoveDegenerateFaces( tess->mesh ) ) return 0;
01359   __gl_meshCheckMesh( tess->mesh );
01360 
01361   return 1;
01362 }

Generated on Thu May 24 2012 04:24:19 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.