// Starting with a valid triangulation, uses the Edge Flip algorithm to // refine the triangulation into a Constrained Delaunay Triangulation. void tessMeshRefineDelaunay( TESSmesh *mesh, TESSalloc *alloc ) { // At this point, we have a valid, but not optimal, triangulation. // We refine the triangulation using the Edge Flip algorithm // // 1) Find all internal edges // 2) Mark all dual edges // 3) insert all dual edges into a queue TESSface *f; EdgeStack stack; TESShalfEdge *e; int maxFaces = 0, maxIter = 0, iter = 0; stackInit(&stack, alloc); for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { if ( f->inside) { e = f->anEdge; do { e->mark = EdgeIsInternal(e); // Mark internal edges if (e->mark && !e->Sym->mark) stackPush(&stack, e); // Insert into queue e = e->Lnext; } while (e != f->anEdge); maxFaces++; } } // The algorithm should converge on O(n^2), since the predicate is not robust, // we'll save guard against infinite loop. maxIter = maxFaces * maxFaces; // Pop stack until we find a reversed edge // Flip the reversed edge, and insert any of the four opposite edges // which are internal and not already in the stack (!marked) while (!stackEmpty(&stack) && iter < maxIter) { e = stackPop(&stack); e->mark = e->Sym->mark = 0; if (!tesedgeIsLocallyDelaunay(e)) { TESShalfEdge *edges[4]; int i; tessMeshFlipEdge(mesh, e); // for each opposite edge edges[0] = e->Lnext; edges[1] = e->Lprev; edges[2] = e->Sym->Lnext; edges[3] = e->Sym->Lprev; for (i = 0; i < 4; i++) { if (!edges[i]->mark && EdgeIsInternal(edges[i])) { edges[i]->mark = edges[i]->Sym->mark = 1; stackPush(&stack, edges[i]); } } } iter++; } stackDelete(&stack); }
/* Starting with a valid triangulation, uses the Edge Flip algorithm to refine the triangulation into a Constrained Delaunay Triangulation. */ int tessMeshRefineDelaunay( TESSmesh *mesh, TESSalloc *alloc ) { /* At this point, we have a valid, but not optimal, triangulation. We refine the triangulation using the Edge Flip algorithm */ /* 1) Find all internal edges 2) Mark all dual edges 3) insert all dual edges into a queue */ TESSface *f; EdgeStack stack; TESShalfEdge *e; TESShalfEdge *edges[4]; stackInit(&stack, alloc); for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { if ( f->inside) { e = f->anEdge; do { e->mark = EdgeIsInternal(e); /* Mark internal edges */ if (e->mark && !e->Sym->mark) stackPush(&stack, e); /* Insert into queue */ e = e->Lnext; } while (e != f->anEdge); } } // Pop stack until we find a reversed edge // Flip the reversed edge, and insert any of the four opposite edges // which are internal and not already in the stack (!marked) while (!stackEmpty(&stack)) { e = stackPop(&stack); e->mark = e->Sym->mark = 0; if (!tesedgeIsLocallyDelaunay(e)) { int i; tessMeshFlipEdge(mesh, e); // for each opposite edge edges[0] = e->Lnext; edges[1] = e->Lprev; edges[2] = e->Sym->Lnext; edges[3] = e->Sym->Lprev; for (i=0;i<3;i++) { if (!edges[i]->mark && EdgeIsInternal(edges[i])) { edges[i]->mark = edges[i]->Sym->mark = 1; stackPush(&stack, edges[i]); } } } } stackDelete(&stack); return 1; }
void tessMeshFlipEdge( TESSmesh *mesh, TESShalfEdge *edge ) { TESShalfEdge *a0 = edge; TESShalfEdge *a1 = a0->Lnext; TESShalfEdge *a2 = a1->Lnext; TESShalfEdge *b0 = edge->Sym; TESShalfEdge *b1 = b0->Lnext; TESShalfEdge *b2 = b1->Lnext; TESSvertex *aOrg = a0->Org; TESSvertex *aOpp = a2->Org; TESSvertex *bOrg = b0->Org; TESSvertex *bOpp = b2->Org; TESSface *fa = a0->Lface; TESSface *fb = b0->Lface; assert(EdgeIsInternal(edge)); assert(a2->Lnext == a0); assert(b2->Lnext == b0); a0->Org = bOpp; a0->Onext = b1->Sym; b0->Org = aOpp; b0->Onext = a1->Sym; a2->Onext = b0; b2->Onext = a0; b1->Onext = a2->Sym; a1->Onext = b2->Sym; a0->Lnext = a2; a2->Lnext = b1; b1->Lnext = a0; b0->Lnext = b2; b2->Lnext = a1; a1->Lnext = b0; a1->Lface = fb; b1->Lface = fa; fa->anEdge = a0; fb->anEdge = b0; if (aOrg->anEdge == a0) aOrg->anEdge = b1; if (bOrg->anEdge == b0) bOrg->anEdge = a1; assert( a0->Lnext->Onext->Sym == a0 ); assert( a0->Onext->Sym->Lnext == a0 ); assert( a0->Org->anEdge->Org == a0->Org ); assert( a1->Lnext->Onext->Sym == a1 ); assert( a1->Onext->Sym->Lnext == a1 ); assert( a1->Org->anEdge->Org == a1->Org ); assert( a2->Lnext->Onext->Sym == a2 ); assert( a2->Onext->Sym->Lnext == a2 ); assert( a2->Org->anEdge->Org == a2->Org ); assert( b0->Lnext->Onext->Sym == b0 ); assert( b0->Onext->Sym->Lnext == b0 ); assert( b0->Org->anEdge->Org == b0->Org ); assert( b1->Lnext->Onext->Sym == b1 ); assert( b1->Onext->Sym->Lnext == b1 ); assert( b1->Org->anEdge->Org == b1->Org ); assert( b2->Lnext->Onext->Sym == b2 ); assert( b2->Onext->Sym->Lnext == b2 ); assert( b2->Org->anEdge->Org == b2->Org ); assert(aOrg->anEdge->Org == aOrg); assert(bOrg->anEdge->Org == bOrg); assert(a0->Oprev->Onext->Org == a0->Org); }