void DaoxCanvas_Rotate( int x, int y ) { DaoxMatrix3D rotate = {1.0,0.0,0.0,0.0,1.0,0.0}; DaoxAABBox2D box = daox_current_canvas->viewport; DaoxVector2D start, end, center = {0.0,0.0}; double W2 = 0.5 * window_width; double H2 = 0.5 * window_height; double area, cosine, sine; start.x = last_x - W2; start.y = last_y - H2; end.x = x - W2; end.y = y - H2; area = DaoxTriangle_Area( center, start, end ); cosine = DaoxTriangle_AngleCosine( center, start, end ); sine = sqrt( 1.0 - cosine * cosine ); rotate.A11 = rotate.A22 = cosine; if( area < 0.0 ){ rotate.A12 = - sine; rotate.A21 = sine; }else{ rotate.A12 = sine; rotate.A21 = - sine; } DaoxMatrix3D_Multiply( & daox_current_canvas->transform, rotate ); Done: last_x = x; last_y = y; }
void DaoxWindow_RotateCanvas( DaoxWindow *self, DaoxCanvas *canvas, int x, int y ) { DaoxMatrix3D rotate = {1.0,0.0,0.0,0.0,1.0,0.0}; DaoxVector2D start, end, center = {0.0,0.0}; double W2 = 0.5 * self->width; double H2 = 0.5 * self->height; double area, cosine, sine; start.x = self->cursorPosX - W2; start.y = self->cursorPosY - H2; end.x = x - W2; end.y = y - H2; area = DaoxTriangle_Area( center, start, end ); cosine = DaoxTriangle_AngleCosine( center, start, end ); sine = sqrt( 1.0 - cosine * cosine ); rotate.A11 = rotate.A22 = cosine; if( area < 0.0 ){ rotate.A12 = - sine; rotate.A21 = sine; }else{ rotate.A12 = sine; rotate.A21 = - sine; } DaoxMatrix3D_Multiply( & canvas->transform, rotate ); }
void DaoxTriangulator_InitContourOrientation( DaoxTriangulator *self ) { DaoxVertexData *vertex, *start, *vmax = NULL; DaoxVector2D A, B, C, *points = self->points->data.vectors2d; int i, dir, N = self->vertices->size; float xmax, ymax; /* sort vertices by the x coordinates: */ DaoxTriangulator_SortVertices( self ); for(i=0; i<N; ++i){ start = self->vertices->items.pVoid[i]; if( start->direction != 0 ) continue; A = points[start->index]; xmax = A.x; ymax = A.y; vertex = vmax = start; do { A = points[vertex->index]; if( A.x >= xmax ){ if( A.x > xmax || A.y > ymax ){ xmax = A.x; ymax = A.y; vmax = vertex; } } vertex = vertex->next; } while( vertex != start ); A = points[vmax->index]; B = points[vmax->next->index]; C = points[vmax->prev->index]; dir = DaoxTriangle_Area( A, B, C ) > 0.0 ? DAOX_COUNTER_CW : DAOX_CLOCKWISE; //printf( "contour = %i dir = %i\n", (int)vmax->contour, dir ); vertex = start; do { vertex->direction = dir; vertex = vertex->next; } while( vertex != start ); } }
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 ); } } }