DList* DList_Copy( DList *self ) { DList *copy = DList_New( self->type ); DList_Assign( copy, self ); return copy; }
void DaoxTriangulator_Triangulate( DaoxTriangulator *self ) { DaoxVertexData *V, *A, *B, *C, *inside; DaoxVector2D PA, PB, PC, P, *points = self->points->data.vectors2d; int i, imin, imax, contours, K = 0, N = self->vertices->size; double dist, area, ymin, ymax, dmax, dmin; double AB, BC, CA, min_area = 1E-16; if( self->vertices->size == 0 ) return; DaoxTriangulator_InitContourOrientation( self ); V = (DaoxVertexData*) self->vertices->items.pVoid[N-1]; contours = V->contour; DList_Assign( self->worklist, self->vertices ); while( self->worklist->size && (++K) < 10*N ){ A = (DaoxVertexData*) self->worklist->items.pVoid[self->worklist->size-1]; if( A->done ){ DList_PopBack( self->worklist ); continue; } B = A->next; C = A->prev; PA = points[A->index]; PB = points[B->index]; PC = points[C->index]; area = DaoxTriangle_Area( PA, PB, PC ); if( B->next == C ){ /* already a triangle: */ if( fabs( area ) > min_area ) DaoxTriangulator_MakeTriangle( self, A ); A->next->prev = A->prev; A->prev->next = A->next; A->done = B->done = C->done = 1; DList_PopBack( self->worklist ); continue; } ymin = ymax = PA.y; if( PB.y < ymin ) ymin = PB.y; else if( PB.y > ymax ) ymax = PB.y; if( PC.y < ymin ) ymin = PC.y; else if( PC.y > ymax ) ymax = PC.y; imin = B->sorting < C->sorting ? B->sorting : C->sorting; imax = A->sorting; inside = NULL; dmax = - 1.0; dmin = 1E9; /* // find the closest point to the triangle: // // Note: no need to distinguish duplicated vertices, because: // 1. if they are outside of the trianlge, they cause no problem; // 2. they cannot be the "closest" vertex to "A" or another vertex again, // so no problem for joining inner contour or splitting outer contour. // // The reason that they cannot be the "closest" vertex is that, // only a concave vertex from the outer contour or a convex // vertex from an inner contour for a hole can be chosen as the // the "closest" vertex. // // And when its original vertex was choose as the "closest" vertex, // the associated "A" will always be processed until it is removed // from the polygon(s), which will leave the duplicated vertices // as convex vertices on the outer contour! */ for(i=imin+1; i<imax; ++i){ V = (DaoxVertexData*) self->vertices->items.pVoid[i]; P = points[V->index]; if( V->done ) continue; //printf( "%3i: %12f %12f %9p, %3i %3i %3i %3i\n", i, P.x, P.y, V, V->contour, A->contour, V->direction, A->direction ); /* Ingore vertex from other contour with the same direction: */ if( V->contour != A->contour && V->direction == A->direction ) continue; if( V->sorting == A->sorting || V->sorting == B->sorting || V->sorting == C->sorting ) continue; if( P.y > ymax ) continue; if( P.y < ymin ) continue; //printf( "%3i: %12f %12f %9p, %3i %3i %3i %3i\n", i, P.x, P.y, V, V->contour, A->contour, V->direction, A->direction ); BC = DaoxTriangle_Area( P, PB, PC ); AB = DaoxTriangle_Area( P, PA, PB ); CA = DaoxTriangle_Area( P, PC, PA ); if( area < 0.0 ){ AB = -AB; BC = -BC; CA = -CA; } //printf( "%3i: %12f %12f %12f\n", i, AB, BC, CA ); if( BC >= 0.0 && AB >= 0.0 && CA >= 0.0 ){ float d = DaoxVector2D_Dist( P, PA ); if( d < dmin ){ dmin = d; inside = V; } } } #if 0 printf( "A: %15f %15f %9p\n", PA.x, PA.y, A ); printf( "B: %15f %15f %9p\n", PB.x, PB.y, B ); printf( "C: %15f %15f %9p\n", PC.x, PC.y, C ); if( inside ) printf( "I: %15f %15f\n", points[inside->index].x, points[inside->index].y ); printf( "%p\n", inside ); printf( "area: %15f\n", area ); #endif if( inside == NULL ){ A->done = 1; //printf( "area: %15f\n", DaoxTriangle_Area( PA, PB, PC ) ); if( fabs( area ) > min_area ) DaoxTriangulator_MakeTriangle( self, A ); A->next->prev = A->prev; A->prev->next = A->next; DList_PopBack( self->worklist ); //if( self->triangles->size >= 3*111 ) break; }else{ /* point inside the triangle: */ DaoxVertexData *A2, *N2; int breaking = inside->contour == A->contour; if( inside->contour != A->contour ){ /* joining contour: */ /* the "inside" vertex is from a hole: */ DaoxVertexData *V2 = inside; //printf( "joining\n" ); /* update contour: */ do { V2->contour = A->contour; V2->direction = A->direction; V2 = V2->next; } while( V2 != inside ); } /* // connect "inside" to "A" with duplicated vertices, this will either: // 1. connect the inner contour with the outer contour; // 2. or break the outer contour. */ N2 = DaoxTriangulator_GetVertex( self, inside->index ); A2 = DaoxTriangulator_GetVertex( self, A->index ); N2->sorting = inside->sorting; A2->sorting = A->sorting; A2->contour = N2->contour = A->contour; A2->direction = N2->direction = A->direction; A2->prev = A->prev; A->prev->next = A2; A2->next = N2; N2->prev = A2; N2->next = inside->next; inside->next->prev = N2; inside->next = A; A->prev = inside; //printf( "dup: %9p %9p\n", A2, N2 ); if( breaking ){ contours += 1; //printf( "contours = %3i\n", contours ); DaoxVertexData *V2 = inside; /* update contour: */ do { V2->contour = contours; V2 = V2->next; } while( V2 != inside ); } DList_PushBack( self->vertices, N2 ); DList_PushBack( self->vertices, A2 ); DList_PopBack( self->worklist ); DList_PushBack( self->worklist, N2 ); DList_PushBack( self->worklist, A2 ); DList_PushBack( self->worklist, A ); } } }