Example #1
0
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;
}
Example #2
0
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 );
		}
	}
}