45 #include "priorityq.h"
52 #ifdef FOR_TRITE_TEST_PROGRAM
55 #define DebugEvent( tess )
90 #define MAX(x,y) ((x) >= (y) ? (x) : (y))
91 #define MIN(x,y) ((x) <= (y) ? (x) : (y))
96 #define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
97 eDst->Sym->winding += eSrc->Sym->winding)
124 if( e1->Dst == event ) {
125 if( e2->Dst == event ) {
129 if( VertLeq( e1->Org, e2->Org )) {
130 return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0;
132 return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0;
134 return EdgeSign( e2->Dst, event, e2->Org ) <= 0;
136 if( e2->Dst == event ) {
137 return EdgeSign( e1->Dst, event, e1->Org ) >= 0;
141 t1 = EdgeEval( e1->Dst, event, e1->Org );
142 t2 = EdgeEval( e2->Dst, event, e2->Org );
149 if( reg->fixUpperEdge ) {
154 assert( reg->eUp->winding == 0 );
156 reg->eUp->activeRegion = NULL;
157 dictDelete( tess->dict, reg->nodeUp );
167 assert( reg->fixUpperEdge );
168 if ( !__gl_meshDelete( reg->eUp ) )
return 0;
169 reg->fixUpperEdge = FALSE;
171 newEdge->activeRegion = reg;
183 reg = RegionAbove( reg );
184 }
while( reg->eUp->Org == org );
189 if( reg->fixUpperEdge ) {
190 e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext );
191 if (e == NULL)
return NULL;
192 if ( !FixUpperEdge( reg, e ) )
return NULL;
193 reg = RegionAbove( reg );
204 reg = RegionAbove( reg );
205 }
while( reg->eUp->Dst == dst );
220 if (regNew == NULL) longjmp(tess->env,1);
222 regNew->eUp = eNewUp;
224 regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew );
225 if (regNew->nodeUp == NULL) longjmp(tess->env,1);
226 regNew->fixUpperEdge = FALSE;
227 regNew->sentinel = FALSE;
228 regNew->dirty = FALSE;
230 eNewUp->activeRegion = regNew;
234 static GLboolean IsWindingInside(
GLUtesselator *tess,
int n )
236 switch( tess->windingRule ) {
237 case GLU_TESS_WINDING_ODD:
239 case GLU_TESS_WINDING_NONZERO:
241 case GLU_TESS_WINDING_POSITIVE:
243 case GLU_TESS_WINDING_NEGATIVE:
245 case GLU_TESS_WINDING_ABS_GEQ_TWO:
246 return (n >= 2) || (n <= -2);
257 reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding;
258 reg->inside = IsWindingInside( tess, reg->windingNumber );
274 f->inside = reg->inside;
276 DeleteRegion( tess, reg );
299 ePrev = regFirst->eUp;
300 while( regPrev != regLast ) {
301 regPrev->fixUpperEdge = FALSE;
302 reg = RegionBelow( regPrev );
304 if( e->Org != ePrev->Org ) {
305 if( ! reg->fixUpperEdge ) {
312 FinishRegion( tess, regPrev );
318 e = __gl_meshConnect( ePrev->Lprev, e->Sym );
319 if (e == NULL) longjmp(tess->env,1);
320 if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1);
324 if( ePrev->Onext != e ) {
325 if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
326 if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1);
328 FinishRegion( tess, regPrev );
352 int firstTime = TRUE;
357 assert( VertLeq( e->Org, e->Dst ));
358 AddRegionBelow( tess, regUp, e->Sym );
360 }
while ( e != eLast );
366 if( eTopLeft == NULL ) {
367 eTopLeft = RegionBelow( regUp )->eUp->Rprev;
372 reg = RegionBelow( regPrev );
374 if( e->Org != ePrev->Org )
break;
376 if( e->Onext != ePrev ) {
378 if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
379 if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1);
382 reg->windingNumber = regPrev->windingNumber - e->winding;
383 reg->inside = IsWindingInside( tess, reg->windingNumber );
388 regPrev->dirty = TRUE;
389 if( ! firstTime && CheckForRightSplice( tess, regPrev )) {
390 AddWinding( e, ePrev );
391 DeleteRegion( tess, regPrev );
392 if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1);
398 regPrev->dirty = TRUE;
399 assert( regPrev->windingNumber - e->winding == reg->windingNumber );
403 WalkDirtyRegions( tess, regPrev );
409 void *data[4], GLfloat weights[4],
int needed )
414 coords[0] = isect->coords[0];
415 coords[1] = isect->coords[1];
416 coords[2] = isect->coords[2];
419 CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data );
420 if( isect->data == NULL ) {
422 isect->data = data[0];
423 }
else if( ! tess->fatalError ) {
428 CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK );
429 tess->fatalError = TRUE;
441 void *data[4] = { NULL, NULL, NULL, NULL };
442 GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 };
444 data[0] = e1->Org->data;
445 data[1] = e2->Org->data;
446 CallCombine( tess, e1->Org, data, weights, FALSE );
447 if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1);
460 GLdouble t1 = VertL1dist( org, isect );
461 GLdouble t2 = VertL1dist( dst, isect );
463 weights[0] = 0.5 * t2 / (t1 + t2);
464 weights[1] = 0.5 * t1 / (t1 + t2);
465 isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0];
466 isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1];
467 isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2];
483 data[0] = orgUp->data;
484 data[1] = dstUp->data;
485 data[2] = orgLo->data;
486 data[3] = dstLo->data;
488 isect->coords[0] = isect->coords[1] = isect->coords[2] = 0;
489 VertexWeights( isect, orgUp, dstUp, &weights[0] );
490 VertexWeights( isect, orgLo, dstLo, &weights[2] );
492 CallCombine( tess, isect, data, weights, TRUE );
526 if( VertLeq( eUp->Org, eLo->Org )) {
527 if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 )
return FALSE;
530 if( ! VertEq( eUp->Org, eLo->Org )) {
532 if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
533 if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1);
534 regUp->dirty = regLo->dirty = TRUE;
536 }
else if( eUp->Org != eLo->Org ) {
538 pqDelete( tess->pq, eUp->Org->pqHandle );
539 SpliceMergeVertices( tess, eLo->Oprev, eUp );
542 if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 )
return FALSE;
545 RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
546 if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
547 if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
577 assert( ! VertEq( eUp->Dst, eLo->Dst ));
579 if( VertLeq( eUp->Dst, eLo->Dst )) {
580 if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 )
return FALSE;
583 RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
584 e = __gl_meshSplitEdge( eUp );
585 if (e == NULL) longjmp(tess->env,1);
586 if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1);
587 e->Lface->inside = regUp->inside;
589 if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 )
return FALSE;
592 regUp->dirty = regLo->dirty = TRUE;
593 e = __gl_meshSplitEdge( eLo );
594 if (e == NULL) longjmp(tess->env,1);
595 if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1);
596 e->Rface->inside = regUp->inside;
620 GLdouble tMinUp, tMaxLo;
624 assert( ! VertEq( dstLo, dstUp ));
625 assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 );
626 assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 );
627 assert( orgUp != tess->event && orgLo != tess->event );
628 assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge );
630 if( orgUp == orgLo )
return FALSE;
632 tMinUp = MIN( orgUp->t, dstUp->t );
633 tMaxLo = MAX( orgLo->t, dstLo->t );
634 if( tMinUp > tMaxLo )
return FALSE;
636 if( VertLeq( orgUp, orgLo )) {
637 if( EdgeSign( dstLo, orgUp, orgLo ) > 0 )
return FALSE;
639 if( EdgeSign( dstUp, orgLo, orgUp ) < 0 )
return FALSE;
645 __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect );
647 assert( MIN( orgUp->t, dstUp->t ) <= isect.t );
648 assert( isect.t <= MAX( orgLo->t, dstLo->t ));
649 assert( MIN( dstLo->s, dstUp->s ) <= isect.s );
650 assert( isect.s <= MAX( orgLo->s, orgUp->s ));
652 if( VertLeq( &isect, tess->event )) {
659 isect.s = tess->event->s;
660 isect.t = tess->event->t;
668 orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo;
669 if( VertLeq( orgMin, &isect )) {
674 if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) {
676 (void) CheckForRightSplice( tess, regUp );
680 if( (! VertEq( dstUp, tess->event )
681 && EdgeSign( dstUp, tess->event, &isect ) >= 0)
682 || (! VertEq( dstLo, tess->event )
683 && EdgeSign( dstLo, tess->event, &isect ) <= 0 ))
689 if( dstLo == tess->event ) {
691 if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
692 if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1);
693 regUp = TopLeftRegion( regUp );
694 if (regUp == NULL) longjmp(tess->env,1);
695 eUp = RegionBelow(regUp)->eUp;
696 FinishLeftRegions( tess, RegionBelow(regUp), regLo );
697 AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE );
700 if( dstUp == tess->event ) {
702 if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
703 if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1);
705 regUp = TopRightRegion( regUp );
706 e = RegionBelow(regUp)->eUp->Rprev;
707 regLo->eUp = eLo->Oprev;
708 eLo = FinishLeftRegions( tess, regLo, NULL );
709 AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE );
716 if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) {
717 RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
718 if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
719 eUp->Org->s = tess->event->s;
720 eUp->Org->t = tess->event->t;
722 if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) {
723 regUp->dirty = regLo->dirty = TRUE;
724 if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
725 eLo->Org->s = tess->event->s;
726 eLo->Org->t = tess->event->t;
740 if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
741 if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
742 if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
743 eUp->Org->s = isect.s;
744 eUp->Org->t = isect.t;
745 eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org );
746 if (eUp->Org->pqHandle == LONG_MAX) {
747 pqDeletePriorityQ(tess->pq);
749 longjmp(tess->env,1);
751 GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo );
752 RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE;
771 while( regLo->dirty ) {
773 regLo = RegionBelow(regLo);
775 if( ! regUp->dirty ) {
777 regUp = RegionAbove( regUp );
778 if( regUp == NULL || ! regUp->dirty ) {
783 regUp->dirty = FALSE;
787 if( eUp->Dst != eLo->Dst ) {
789 if( CheckForLeftSplice( tess, regUp )) {
795 if( regLo->fixUpperEdge ) {
796 DeleteRegion( tess, regLo );
797 if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1);
798 regLo = RegionBelow( regUp );
800 }
else if( regUp->fixUpperEdge ) {
801 DeleteRegion( tess, regUp );
802 if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
803 regUp = RegionAbove( regLo );
808 if( eUp->Org != eLo->Org ) {
809 if( eUp->Dst != eLo->Dst
810 && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge
811 && (eUp->Dst == tess->event || eLo->Dst == tess->event) )
821 if( CheckForIntersect( tess, regUp )) {
829 (void) CheckForRightSplice( tess, regUp );
832 if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) {
834 AddWinding( eLo, eUp );
835 DeleteRegion( tess, regUp );
836 if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
837 regUp = RegionAbove( regLo );
882 int degenerate = FALSE;
884 if( eUp->Dst != eLo->Dst ) {
885 (void) CheckForIntersect( tess, regUp );
891 if( VertEq( eUp->Org, tess->event )) {
892 if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1);
893 regUp = TopLeftRegion( regUp );
894 if (regUp == NULL) longjmp(tess->env,1);
895 eTopLeft = RegionBelow( regUp )->eUp;
896 FinishLeftRegions( tess, RegionBelow(regUp), regLo );
899 if( VertEq( eLo->Org, tess->event )) {
900 if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1);
901 eBottomLeft = FinishLeftRegions( tess, regLo, NULL );
905 AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
912 if( VertLeq( eLo->Org, eUp->Org )) {
917 eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew );
918 if (eNew == NULL) longjmp(tess->env,1);
923 AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE );
924 eNew->Sym->activeRegion->fixUpperEdge = TRUE;
925 WalkDirtyRegions( tess, regUp );
935 #define TOLERANCE_NONZERO FALSE
949 if( VertEq( e->Org, vEvent )) {
953 assert( TOLERANCE_NONZERO );
954 SpliceMergeVertices( tess, e, vEvent->anEdge );
958 if( ! VertEq( e->Dst, vEvent )) {
960 if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1);
961 if( regUp->fixUpperEdge ) {
963 if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1);
964 regUp->fixUpperEdge = FALSE;
966 if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1);
967 SweepEvent( tess, vEvent );
974 assert( TOLERANCE_NONZERO );
975 regUp = TopRightRegion( regUp );
976 reg = RegionBelow( regUp );
977 eTopRight = reg->eUp->Sym;
978 eTopLeft = eLast = eTopRight->Onext;
979 if( reg->fixUpperEdge ) {
983 assert( eTopLeft != eTopRight );
984 DeleteRegion( tess, reg );
985 if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1);
986 eTopRight = eTopLeft->Oprev;
988 if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1);
989 if( ! EdgeGoesLeft( eTopLeft )) {
993 AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE );
1021 tmp.eUp = vEvent->anEdge->Sym;
1023 regUp = (
ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp ));
1024 regLo = RegionBelow( regUp );
1029 if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) {
1030 ConnectLeftDegenerate( tess, regUp, vEvent );
1037 reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo;
1039 if( regUp->inside || reg->fixUpperEdge) {
1040 if( reg == regUp ) {
1041 eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext );
1042 if (eNew == NULL) longjmp(tess->env,1);
1044 GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge);
1045 if (tempHalfEdge == NULL) longjmp(tess->env,1);
1047 eNew = tempHalfEdge->Sym;
1049 if( reg->fixUpperEdge ) {
1050 if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1);
1052 ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew ));
1054 SweepEvent( tess, vEvent );
1059 AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE );
1073 tess->event = vEvent;
1081 while( e->activeRegion == NULL ) {
1083 if( e == vEvent->anEdge ) {
1085 ConnectLeftVertex( tess, vEvent );
1097 regUp = TopLeftRegion( e->activeRegion );
1098 if (regUp == NULL) longjmp(tess->env,1);
1099 reg = RegionBelow( regUp );
1100 eTopLeft = reg->eUp;
1101 eBottomLeft = FinishLeftRegions( tess, reg, NULL );
1108 if( eBottomLeft->Onext == eTopLeft ) {
1110 ConnectRightVertex( tess, regUp, eBottomLeft );
1112 AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
1122 #define SENTINEL_COORD (4 * GLU_TESS_MAX_COORD)
1132 if (reg == NULL) longjmp(tess->env,1);
1134 e = __gl_meshMakeEdge( tess->mesh );
1135 if (e == NULL) longjmp(tess->env,1);
1137 e->Org->s = SENTINEL_COORD;
1139 e->Dst->s = -SENTINEL_COORD;
1141 tess->event = e->Dst;
1144 reg->windingNumber = 0;
1145 reg->inside = FALSE;
1146 reg->fixUpperEdge = FALSE;
1147 reg->sentinel = TRUE;
1149 reg->nodeUp = dictInsert( tess->dict, reg );
1150 if (reg->nodeUp == NULL) longjmp(tess->env,1);
1161 tess->dict = dictNewDict( tess, (
int (*)(
void *, DictKey, DictKey)) EdgeLeq );
1162 if (tess->dict == NULL) longjmp(tess->env,1);
1164 AddSentinel( tess, -SENTINEL_COORD );
1165 AddSentinel( tess, SENTINEL_COORD );
1177 while( (reg = (
ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) {
1183 if( ! reg->sentinel ) {
1184 assert( reg->fixUpperEdge );
1185 assert( ++fixedEdges == 1 );
1187 assert( reg->windingNumber == 0 );
1188 DeleteRegion( tess, reg );
1191 dictDeleteDict( tess->dict );
1204 for( e = eHead->next; e != eHead; e = eNext ) {
1208 if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) {
1211 SpliceMergeVertices( tess, eLnext, e );
1212 if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1);
1216 if( eLnext->Lnext == e ) {
1220 if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; }
1221 if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1);
1223 if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; }
1224 if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1);
1239 pq = tess->pq = pqNewPriorityQ( (
int (*)(PQkey, PQkey)) __gl_vertLeq );
1240 if (pq == NULL)
return 0;
1242 vHead = &tess->mesh->vHead;
1243 for( v = vHead->next; v != vHead; v = v->next ) {
1244 v->pqHandle = pqInsert( pq, v );
1245 if (v->pqHandle == LONG_MAX)
break;
1247 if (v != vHead || !pqInit( pq ) ) {
1248 pqDeletePriorityQ(tess->pq);
1259 pqDeletePriorityQ( tess->pq );
1263 static int RemoveDegenerateFaces(
GLUmesh *mesh )
1283 for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
1286 assert( e->Lnext != e );
1288 if( e->Lnext->Lnext == e ) {
1290 AddWinding( e->Onext, e );
1291 if ( !__gl_meshDelete( e ) )
return 0;
1308 tess->fatalError = FALSE;
1316 RemoveDegenerateEdges( tess );
1317 if ( !InitPriorityQ( tess ) )
return 0;
1318 InitEdgeDict( tess );
1321 while( (v = (
GLUvertex *)pqExtractMin( tess->pq )) != NULL ) {
1323 vNext = (
GLUvertex *)pqMinimum( tess->pq );
1324 if( vNext == NULL || ! VertEq( vNext, v ))
break;
1340 vNext = (
GLUvertex *)pqExtractMin( tess->pq );
1341 SpliceMergeVertices( tess, v->anEdge, vNext->anEdge );
1343 SweepEvent( tess, v );
1348 tess->event = ((
ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org;
1350 DoneEdgeDict( tess );
1351 DonePriorityQ( tess );
1353 if ( !RemoveDegenerateFaces( tess->mesh ) )
return 0;
1354 __gl_meshCheckMesh( tess->mesh );