int tessComputeInterior( TESStesselator *tess ) /* * tessComputeInterior( tess ) computes the planar arrangement specified * by the given contours, and further subdivides this arrangement * into regions. Each region is marked "inside" if it belongs * to the polygon, according to the rule given by tess->windingRule. * Each interior region is guaranteed be monotone. */ { TESSvertex *v, *vNext; /* Each vertex defines an event for our sweep line. Start by inserting * all the vertices in a priority queue. Events are processed in * lexicographic order, ie. * * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y) */ RemoveDegenerateEdges( tess ); if ( !InitPriorityQ( tess ) ) return 0; /* if error */ InitEdgeDict( tess ); while( (v = (TESSvertex *)pqExtractMin( tess->pq )) != NULL ) { for( ;; ) { vNext = (TESSvertex *)pqMinimum( tess->pq ); if( vNext == NULL || ! VertEq( vNext, v )) break; /* Merge together all vertices at exactly the same location. * This is more efficient than processing them one at a time, * simplifies the code (see ConnectLeftDegenerate), and is also * important for correct handling of certain degenerate cases. * For example, suppose there are two identical edges A and B * that belong to different contours (so without this code they would * be processed by separate sweep events). Suppose another edge C * crosses A and B from above. When A is processed, we split it * at its intersection point with C. However this also splits C, * so when we insert B we may compute a slightly different * intersection point. This might leave two edges with a small * gap between them. This kind of error is especially obvious * when using boundary extraction (TESS_BOUNDARY_ONLY). */ vNext = (TESSvertex *)pqExtractMin( tess->pq ); SpliceMergeVertices( tess, v->anEdge, vNext->anEdge ); } SweepEvent( tess, v ); } /* Set tess->event for debugging purposes */ tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org; DebugEvent( tess ); DoneEdgeDict( tess ); DonePriorityQ( tess ); if ( !RemoveDegenerateFaces( tess, tess->mesh ) ) return 0; tessMeshCheckMesh( tess->mesh ); return 1; }
int tessTesselate( TESStesselator *tess, int windingRule, int elementType, int polySize, int vertexSize, const TESSreal* normal ) { TESSmesh *mesh; int rc = 1; if (tess->vertices != NULL) { tess->alloc.memfree( tess->alloc.userData, tess->vertices ); tess->vertices = 0; } if (tess->elements != NULL) { tess->alloc.memfree( tess->alloc.userData, tess->elements ); tess->elements = 0; } if (tess->vertexIndices != NULL) { tess->alloc.memfree( tess->alloc.userData, tess->vertexIndices ); tess->vertexIndices = 0; } tess->vertexIndexCounter = 0; if (normal) { tess->normal[0] = normal[0]; tess->normal[1] = normal[1]; tess->normal[2] = normal[2]; } tess->windingRule = windingRule; if (vertexSize < 2) vertexSize = 2; if (vertexSize > 3) vertexSize = 3; if (setjmp(tess->env) != 0) { /* come back here if out of memory */ return 0; } if (!tess->mesh) { return 0; } /* Determine the polygon normal and project vertices onto the plane * of the polygon. */ tessProjectPolygon( tess ); /* tessComputeInterior( tess ) computes the planar arrangement specified * by the given contours, and further subdivides this arrangement * into regions. Each region is marked "inside" if it belongs * to the polygon, according to the rule given by tess->windingRule. * Each interior region is guaranteed be monotone. */ if ( !tessComputeInterior( tess ) ) { longjmp(tess->env,1); /* could've used a label */ } mesh = tess->mesh; /* If the user wants only the boundary contours, we throw away all edges * except those which separate the interior from the exterior. * Otherwise we tessellate all the regions marked "inside". */ if (elementType == TESS_BOUNDARY_CONTOURS) { rc = tessMeshSetWindingNumber( mesh, 1, TRUE ); } else { rc = tessMeshTessellateInterior( mesh ); } if (rc == 0) longjmp(tess->env,1); /* could've used a label */ tessMeshCheckMesh( mesh ); if (elementType == TESS_BOUNDARY_CONTOURS) { OutputContours( tess, mesh, vertexSize ); /* output contours */ } else { OutputPolymesh( tess, mesh, elementType, polySize, vertexSize ); /* output polygons */ } tessMeshDeleteMesh( &tess->alloc, mesh ); tess->mesh = NULL; if (tess->outOfMemory) return 0; return 1; }