Exemple #1
0
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);
}
Exemple #2
0
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;
}
Exemple #6
0
/* 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;
}
Exemple #7
0
/* 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;
}
Exemple #9
0
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;
}