static void AddSentinel( TESStesselator *tess, TESSreal smin, TESSreal smax, TESSreal t ) /* * We add two sentinel edges above and below all other edges, * to avoid special cases at the top and bottom. */ { TESShalfEdge *e; ActiveRegion *reg = (ActiveRegion *)bucketAlloc( tess->regionPool ); if (reg == NULL) longjmp(tess->env,1); e = tessMeshMakeEdge( tess->mesh ); if (e == NULL) longjmp(tess->env,1); e->Org->s = smax; e->Org->t = t; e->Dst->s = smin; e->Dst->t = t; tess->event = e->Dst; /* initialize it */ reg->eUp = e; reg->windingNumber = 0; reg->inside = FALSE; reg->fixUpperEdge = FALSE; reg->sentinel = TRUE; reg->dirty = FALSE; reg->nodeUp = dictInsert( tess->dict, reg ); if (reg->nodeUp == NULL) longjmp(tess->env,1); }
void stackPush( EdgeStack *stack, TESShalfEdge *e ) { EdgeStackNode *node = (EdgeStackNode *)bucketAlloc( stack->nodeBucket ); if ( ! node ) return; node->edge = e; node->next = stack->top; stack->top = node; }
/* tessMeshSplice( eOrg, eDst ) is the basic operation for changing the * mesh connectivity and topology. It changes the mesh so that * eOrg->Onext <- OLD( eDst->Onext ) * eDst->Onext <- OLD( eOrg->Onext ) * where OLD(...) means the value before the meshSplice operation. * * This can have two effects on the vertex structure: * - if eOrg->Org != eDst->Org, the two vertices are merged together * - if eOrg->Org == eDst->Org, the origin is split into two vertices * In both cases, eDst->Org is changed and eOrg->Org is untouched. * * Similarly (and independently) for the face structure, * - if eOrg->Lface == eDst->Lface, one loop is split into two * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. * * Some special cases: * If eDst == eOrg, the operation has no effect. * If eDst == eOrg->Lnext, the new face will have a single edge. * If eDst == eOrg->Lprev, the old face will have a single edge. * If eDst == eOrg->Onext, the new vertex will have a single edge. * If eDst == eOrg->Oprev, the old vertex will have a single edge. */ int tessMeshSplice( TESSmesh* mesh, TESShalfEdge *eOrg, TESShalfEdge *eDst ) { int joiningLoops = FALSE; int joiningVertices = FALSE; if( eOrg == eDst ) return 1; if( eDst->Org != eOrg->Org ) { /* We are merging two disjoint vertices -- destroy eDst->Org */ joiningVertices = TRUE; KillVertex( mesh, eDst->Org, eOrg->Org ); } if( eDst->Lface != eOrg->Lface ) { /* We are connecting two disjoint loops -- destroy eDst->Lface */ joiningLoops = TRUE; KillFace( mesh, eDst->Lface, eOrg->Lface ); } /* Change the edge structure */ Splice( eDst, eOrg ); if( ! joiningVertices ) { TESSvertex *newVertex = (TESSvertex*)bucketAlloc( mesh->vertexBucket ); if (newVertex == NULL) return 0; /* We split one vertex into two -- the new vertex is eDst->Org. * Make sure the old vertex points to a valid half-edge. */ MakeVertex( newVertex, eDst, eOrg->Org ); eOrg->Org->anEdge = eOrg; } if( ! joiningLoops ) { TESSface *newFace = (TESSface*)bucketAlloc( mesh->faceBucket ); if (newFace == NULL) return 0; /* We split one loop into two -- the new loop is eDst->Lface. * Make sure the old face points to a valid half-edge. */ MakeFace( newFace, eDst, eOrg->Lface ); eOrg->Lface->anEdge = eOrg; } return 1; }
/* tessMeshMakeEdge creates one edge, two vertices, and a loop (face). * The loop consists of the two new half-edges. */ TESShalfEdge *tessMeshMakeEdge( TESSmesh *mesh ) { TESSvertex *newVertex1 = (TESSvertex*)bucketAlloc(mesh->vertexBucket); TESSvertex *newVertex2 = (TESSvertex*)bucketAlloc(mesh->vertexBucket); TESSface *newFace = (TESSface*)bucketAlloc(mesh->faceBucket); TESShalfEdge *e; /* if any one is null then all get freed */ if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) { if (newVertex1 != NULL) bucketFree( mesh->vertexBucket, newVertex1 ); if (newVertex2 != NULL) bucketFree( mesh->vertexBucket, newVertex2 ); if (newFace != NULL) bucketFree( mesh->faceBucket, newFace ); return NULL; } e = MakeEdge( mesh, &mesh->eHead ); if (e == NULL) return NULL; MakeVertex( newVertex1, e, &mesh->vHead ); MakeVertex( newVertex2, e->Sym, &mesh->vHead ); MakeFace( newFace, e, &mesh->fHead ); return e; }
/* tessMeshDelete( eDel ) removes the edge eDel. There are several cases: * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop * eDel->Lface is deleted. Otherwise, we are splitting one loop into two; * the newly created loop will contain eDel->Dst. If the deletion of eDel * would create isolated vertices, those are deleted as well. * * This function could be implemented as two calls to tessMeshSplice * plus a few calls to memFree, but this would allocate and delete * unnecessary vertices and faces. */ int tessMeshDelete( TESSmesh *mesh, TESShalfEdge *eDel ) { TESShalfEdge *eDelSym = eDel->Sym; int joiningLoops = FALSE; /* First step: disconnect the origin vertex eDel->Org. We make all * changes to get a consistent mesh in this "intermediate" state. */ if( eDel->Lface != eDel->Rface ) { /* We are joining two loops into one -- remove the left face */ joiningLoops = TRUE; KillFace( mesh, eDel->Lface, eDel->Rface ); } if( eDel->Onext == eDel ) { KillVertex( mesh, eDel->Org, NULL ); } else { /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */ eDel->Rface->anEdge = eDel->Oprev; eDel->Org->anEdge = eDel->Onext; Splice( eDel, eDel->Oprev ); if( ! joiningLoops ) { TESSface *newFace= (TESSface*)bucketAlloc( mesh->faceBucket ); if (newFace == NULL) return 0; /* We are splitting one loop into two -- create a new loop for eDel. */ MakeFace( newFace, eDel, eDel->Lface ); } } /* Claim: the mesh is now in a consistent state, except that eDel->Org * may have been deleted. Now we disconnect eDel->Dst. */ if( eDelSym->Onext == eDelSym ) { KillVertex( mesh, eDelSym->Org, NULL ); KillFace( mesh, eDelSym->Lface, NULL ); } else { /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */ eDel->Lface->anEdge = eDelSym->Oprev; eDelSym->Org->anEdge = eDelSym->Onext; Splice( eDelSym, eDelSym->Oprev ); } /* Any isolated vertices or faces have already been freed. */ KillEdge( mesh, eDel ); return 1; }
/* really tessDictListInsertBefore */ DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ) { DictNode *newNode; do { node = node->prev; } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key)); newNode = (DictNode *)bucketAlloc( dict->nodePool ); if (newNode == NULL) return NULL; newNode->key = key; newNode->next = node->next; node->next->prev = newNode; newNode->prev = node; node->next = newNode; return newNode; }
/* MakeEdge creates a new pair of half-edges which form their own loop. * No vertex or face structures are allocated, but these must be assigned * before the current edge operation is completed. */ static TESShalfEdge *MakeEdge( TESSmesh* mesh, TESShalfEdge *eNext ) { TESShalfEdge *e; TESShalfEdge *eSym; TESShalfEdge *ePrev; EdgePair *pair = (EdgePair *)bucketAlloc( mesh->edgeBucket ); if (pair == NULL) return NULL; e = &pair->e; eSym = &pair->eSym; /* Make sure eNext points to the first edge of the edge pair */ if( eNext->Sym < eNext ) { eNext = eNext->Sym; } /* Insert in circular doubly-linked list before eNext. * Note that the prev pointer is stored in Sym->next. */ ePrev = eNext->Sym->next; eSym->next = ePrev; ePrev->Sym->next = e; e->next = eNext; eNext->Sym->next = eSym; e->Sym = eSym; e->Onext = e; e->Lnext = eSym; e->Org = NULL; e->Lface = NULL; e->winding = 0; e->activeRegion = NULL; e->mark = 0; eSym->Sym = e; eSym->Onext = eSym; eSym->Lnext = e; eSym->Org = NULL; eSym->Lface = NULL; eSym->winding = 0; eSym->activeRegion = NULL; eSym->mark = 0; return e; }
/* tessMeshAddEdgeVertex( eOrg ) creates a new edge eNew such that * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. * eOrg and eNew will have the same left face. */ TESShalfEdge *tessMeshAddEdgeVertex( TESSmesh *mesh, TESShalfEdge *eOrg ) { TESShalfEdge *eNewSym; TESShalfEdge *eNew = MakeEdge( mesh, eOrg ); if (eNew == NULL) return NULL; eNewSym = eNew->Sym; /* Connect the new edge appropriately */ Splice( eNew, eOrg->Lnext ); /* Set the vertex and face information */ eNew->Org = eOrg->Dst; { TESSvertex *newVertex= (TESSvertex*)bucketAlloc( mesh->vertexBucket ); if (newVertex == NULL) return NULL; MakeVertex( newVertex, eNewSym, eNew->Org ); } eNew->Lface = eNewSym->Lface = eOrg->Lface; return eNew; }
static ActiveRegion *AddRegionBelow( TESStesselator *tess, ActiveRegion *regAbove, TESShalfEdge *eNewUp ) /* * Add a new active region to the sweep line, *somewhere* below "regAbove" * (according to where the new edge belongs in the sweep-line dictionary). * The upper edge of the new region will be "eNewUp". * Winding number and "inside" flag are not updated. */ { ActiveRegion *regNew = (ActiveRegion *)bucketAlloc( tess->regionPool ); if (regNew == NULL) longjmp(tess->env,1); regNew->eUp = eNewUp; regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew ); if (regNew->nodeUp == NULL) longjmp(tess->env,1); regNew->fixUpperEdge = FALSE; regNew->sentinel = FALSE; regNew->dirty = FALSE; eNewUp->activeRegion = regNew; return regNew; }
/* tessMeshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst * to eDst->Org, and returns the corresponding half-edge eNew. * If eOrg->Lface == eDst->Lface, this splits one loop into two, * and the newly created loop is eNew->Lface. Otherwise, two disjoint * loops are merged into one, and the loop eDst->Lface is destroyed. * * If (eOrg == eDst), the new face will have only two edges. * If (eOrg->Lnext == eDst), the old face is reduced to a single edge. * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges. */ TESShalfEdge *tessMeshConnect( TESSmesh *mesh, TESShalfEdge *eOrg, TESShalfEdge *eDst ) { TESShalfEdge *eNewSym; int joiningLoops = FALSE; TESShalfEdge *eNew = MakeEdge( mesh, eOrg ); if (eNew == NULL) return NULL; eNewSym = eNew->Sym; if( eDst->Lface != eOrg->Lface ) { /* We are connecting two disjoint loops -- destroy eDst->Lface */ joiningLoops = TRUE; KillFace( mesh, eDst->Lface, eOrg->Lface ); } /* Connect the new edge appropriately */ Splice( eNew, eOrg->Lnext ); Splice( eNewSym, eDst ); /* Set the vertex and face information */ eNew->Org = eOrg->Dst; eNewSym->Org = eDst->Org; eNew->Lface = eNewSym->Lface = eOrg->Lface; /* Make sure the old face points to a valid half-edge */ eOrg->Lface->anEdge = eNewSym; if( ! joiningLoops ) { TESSface *newFace= (TESSface*)bucketAlloc( mesh->faceBucket ); if (newFace == NULL) return NULL; /* We split one loop into two -- the new loop is eNew->Lface */ MakeFace( newFace, eNew, eOrg->Lface ); } return eNew; }