Click here to Skip to main content
15,896,557 members
Articles / Multimedia / GDI

Curve representation by ICAS (Inner Centered Arcs)

Rate me:
Please Sign up or sign in to vote.
4.80/5 (13 votes)
13 Nov 2011CPOL7 min read 30.3K   1.7K   25  
Suggestion about another curve representation
#include "IcasBase.h"
#include <math.h>
//#include <stdio.h> //NULL
#ifndef TRACE_ON
#define NULL (void*)0
#endif

static double    g_t    = 0.0;
static int       g_reso = 0;//density of curve points
static int       g_deg  = 0;
static int       g_asiz = 0;
static double    g_grid_dist = 5.0;
static ICASPOINT g_a[ L_ICAS_MAX ];//working area
ICASPOINT        g_C[ L_ICAS_MAX ];//porting area

//Get Inner Center
int GetInC(ICASPOINT *S,  ICASPOINT *E,  ICASPOINT *C, 
		   ICASPOINT *SS, ICASPOINT *EE, ICASPOINT *I,
		   double *ds, double *de)
{
	double s,e,c;//length of edges
	double x1,y1,x2,y2,x3,y3,t,ix,iy;
	double sx,sy,ex,ey;

	//OutputDebugString("OK");//Windows.h

	x1 = (E->x - S->x);
	y1 = (E->y - S->y);
	c = sqrt(x1*x1 + y1*y1);//SE
	x2 = (C->x - S->x);
	y2 = (C->y - S->y);
	e = sqrt(x2*x2 + y2*y2);//SC
	x3 = (C->x - E->x);
	y3 = (C->y - E->y);
	s = sqrt(x3*x3 + y3*y3);//CE
	t = s + e + c;//surround length of triangle
	if (t <= EPS) {
		return -1;
	}
	ix = ((s*S->x+e*E->x+c*C->x)/t);
	iy = ((s*S->y+e*E->y+c*C->y)/t);
	I->x = ix;//Inner Center
	I->y = iy;

	s = (x1 *(iy-S->y) - y1 *(ix-S->x))/(x1 * y2 - x2 * y1);
	sx = S->x + s * x2;
	sy = S->y + s * y2;
	SS->x = sx;//Next Control point (front)
	SS->y = sy;

	e = (x1 *(iy-E->y) - y1 *(ix-E->x))/(x1 * y3 - x3 * y1);
	ex = E->x + e * x3;
	ey = E->y + e * y3;
	EE->x = ex;//Next Control point (rear)
	EE->y = ey;

	//length of IS and IE 
	if (NULL != ds ) {
		*ds = sqrt((ix-S->x)*(ix-S->x)+(iy-S->y)*(iy-S->y));
	}
	if (NULL != de ) {
		*de = sqrt((ix-E->x)*(ix-E->x)+(iy-E->y)*(iy-E->y));
	}
	return 0;
}
//Get Edge Center
int GetMidC(ICASPOINT *S,  ICASPOINT *E,  ICASPOINT *C, 
		    ICASPOINT *SS, ICASPOINT *EE, ICASPOINT *I,
		   double *ds, double *de)
{
	double s;//length of edges
	double Mx,My,x1,y1;

	Mx = (E->x + S->x)*0.5;
	My = (E->y + S->y)*0.5;
	I->x = Mx;//Mid Center
	I->y = My;
	x1 = (C->x - E->x)*0.5;
	y1 = (C->y - E->y)*0.5;
	SS->x = S->x - x1;//Next Control point (front)
	SS->y = S->y - y1;
	EE->x = E->x + x1;//Next Control point (rear)
	EE->y = E->y + y1;

	if ((ds != NULL) || (de != NULL)) {
		s = sqrt((Mx-S->x)*(Mx-S->x)+(My-S->y)*(My-S->y));
		//length of MS and ME
		if (NULL != ds ) {
			*ds = s;
		}
		if (NULL != de ) {
			*de = s;
		}
	}
	return 0;
}
//Biarc initiator
int BrcInC(ICASPOINT *S,  ICASPOINT *C,  ICASPOINT *E,
		   ICASPOINT *SS, ICASPOINT *EE, ICASPOINT *I,
		   int Typ, double *ds, double *de)
{
	int sts = 0;
	switch(Typ & L_SEG_TANGENT)
	{
	case L_LEFT_TAN:
		if (0 == g_deg) {
			if (GetInC(S, C, E, SS, EE, I, ds, de)<0) return -2;
			sts = L_LEFT_TAN;
		}
		break;
	case L_LEFT_TAN2:
		if (1 == g_deg) {
			if (GetMidC(S, E, C, SS, EE, I, ds, de)<0) return -3;
			sts = L_LEFT_TAN2;
		}
		break;
	case L_RIGHT_TAN:
		if (0 == g_deg) {
			if (GetInC(C, E, S, SS, EE, I, ds, de)<0) return -2;
			sts = L_RIGHT_TAN;
		}
		break;
	case L_RIGHT_TAN2:
		if (1 == g_deg) {
			if (GetMidC(E, S, C, EE, SS, I, de, ds)<0) return -3;
			sts = L_RIGHT_TAN2;
		}
		break;
	default://not tangent to data segment
		break;
	}
	if (sts) return 0;//

	switch(Typ & L_CURV_TANGENT)
	{
	default://
	case L_NORMAL:
	case L_BRIDGE:
		if (GetInC(S, E, C, SS, EE, I, ds, de)<0) return -4;
		break;
	case L_LINE:
	case L_IDENTDIR:
		I->x = S->x + (E->x - S->x)*g_t;
		I->y = S->y + (E->y - S->y)*g_t;
		return 1;//break;
	}
	return 0;
}

ICASPOINT * GetParametricPoint(ICASTRI *T, double tt)
{
	static ICASPOINT P;
	double s = 0.5;//from here to tt
	//Set Global parameters (g_deg, g_t)
	g_deg = 0;
	g_t   = tt;
	//get the point parametricaly, corresponding g_t [0.0-1.0)
	GetPointR(&(T->P[0]), &(T->P[1]), &(T->P[2]), T->Typ, &s, &P);

	return &P;
}

//get parametric curve point
//'R'ecurrsive
int GetPointR(ICASPOINT *S, ICASPOINT *C, ICASPOINT *E,
			  int Typ, double *s, ICASPOINT *P )
{
	static double ss = 0.5;//difference
	ICASPOINT SS,EE,I;
	//Get Inner Center
	if (1 == BrcInC(S, C, E, &SS, &EE, &I, Typ, NULL, NULL)) {
		*P = I;  //L_LINE | L_IDENTDIR
		return 0;
	}
	//match g_t?
	if (fabs(g_t - *s) < EPS) {
		*P = I;
		//TRACE("R(%d)\n",g_deg);
	}
	//go reccursive
	else {
		g_deg++;
		ss *= 0.5;
		//
		if (*s > g_t) {
			*s = *s - ss;
			GetPointR(S, &SS, &I, Typ & L_LEFTMASK,  s, P);
		}
		else {//if (g_t > *s) {
			*s = *s + ss;
			GetPointR(&I, &EE, E, Typ & L_RIGHTMASK, s, P);
		}
		//
		g_deg--;
		ss *= 2.0;
	}
	return 0;
}
//interpolate by precision
//'R'ecurrsive
int GetArrayR(ICASPOINT *S, ICASPOINT *C, ICASPOINT *E, int Typ )
{
	ICASPOINT SS,EE,I;
	double ds, de;
	//Get Inner Center
	if (1 == BrcInC(S, C, E, &SS, &EE, &I, Typ, &ds, &de)) return 0;//L_LINE

	//enough precision?
	if (g_grid_dist >= ds && g_grid_dist >= de) {
		if (g_asiz >= L_ICAS_MAX) return 0;
		g_a[ g_asiz ] = I;
		++g_asiz;
		//TRACE("ArrayR[%d]\n",g_asiz);
	}
	//go reccursive
	else {
		//g_deg++;

		//Left first
		if (g_grid_dist < ds)
		GetArrayR(S, &SS, &I, Typ & L_LEFTMASK);

		//Right last
		if (g_grid_dist < de)
		GetArrayR(&I, &EE, E, Typ & L_RIGHTMASK);

		//g_deg--;
	}
	return 0;
}
//interpolate by tesselate degree
//'R'ecurrsive 2
int GetArrayR2(ICASPOINT *S, ICASPOINT *C, ICASPOINT *E, int Typ, int dig )
{
	ICASPOINT SS,EE,I;
	//enough tesselation?
	if (dig >= g_reso) {
		return 0;
	}
	//Get Inner Center
	if (1 == BrcInC(S, C, E, &SS, &EE, &I, Typ, NULL, NULL)) return 0;//L_LINE

	//go reccursive
	g_deg++;

	//Left first
	GetArrayR2(S, &SS, &I, Typ & L_LEFTMASK, dig+1);

	if (g_asiz >= L_ICAS_MAX) {
		g_deg--;
		return 0;
	}
	g_a[ g_asiz ] = I;
	++g_asiz;
	//TRACE("ArrayR2<%d>\n",g_asiz);

	//Right last
	GetArrayR2(&I, &EE, E, Typ & L_RIGHTMASK, dig+1);

	g_deg--;
	return 0;
}

//Inner Center-ed Curve inside Triangle
int IcasCurve(ICASTRI *Tri, int CurvTyp, int Reso, double dReso)
{
	int i,Csiz = 0;

	if (CurvTyp & L_CLOSE) {//CurvTyp & 0x1 : close
	}
	else {//CurvTyp==0 : open
		if (Tri->Typ & L_BRIDGE) return 0;//elliminate BRIDGE part
	}
	//
	if (Tri->Typ & L_IDENTDIR) Reso = 0;//to be flat line
	//
	g_asiz = 0;//max L_ICAS_MAX
	g_deg  = 0;//tesselate degree
	//apply resolution
	switch( Reso )
	{
	case 0://line segment
	case 1://single inner center
	case 2://three inner centers
	case 3://seven inner centers
	case 4://if you want more tesselation, set bigger 'g_reso' and call GetArrayR2().
		g_reso = Reso;
		GetArrayR2(&(Tri->P[0]), &(Tri->P[1]), &(Tri->P[2]), Tri->Typ, 0);//tesselate degree
		break;
	case 5://if you want more resolution, set smaller 'g_grid_dist' and call GetArrayR().
		g_grid_dist = dReso;
		GetArrayR(&(Tri->P[0]), &(Tri->P[1]), &(Tri->P[2]), Tri->Typ);//resolution 
		break;
	}
	//copy to porting area
	g_C[0]        = Tri->P[0];//first
	for(i=0; i<g_asiz; ++i) {
		g_C[i+1]  = g_a[i];
	}
	g_C[g_asiz+1] = Tri->P[2];//last
	Csiz = g_asiz+2;
	//TRACE("Csiz=%d\n",Csiz);
	return Csiz;
}
//move Control point = Q
int GetSideTri(ICASTRI *Tri, ICASPOINT *Q, int Idx)
{
	int a = 0, b = 2;
	double P1ax,P1ay,Pbax,Pbay,PbQx,PbQy,s,d;
	if (Tri->Typ & L_IDENTDIR) return 0;
	if (Idx!=0) {
		a = 2; b = 0;
	}
	P1ax = Tri->P[1].x - Tri->P[a].x;
	P1ay = Tri->P[1].y - Tri->P[a].y;
	Pbax = Tri->P[b].x - Tri->P[a].x;
	Pbay = Tri->P[b].y - Tri->P[a].y;
	PbQx = Tri->P[b].x - Q->x;
	PbQy = Tri->P[b].y - Q->y;
	d = P1ax * PbQy - P1ay * PbQx;
	if (fabs(d) > EPS) {
		s = (PbQy * Pbax - PbQx * Pbay)/d;
		Tri->P[1].x = Tri->P[a].x + s * P1ax;
		Tri->P[1].y = Tri->P[a].y + s * P1ay;
	}
	return 0;
}
//move Data point = Q
int GetSideTri2(ICASTRI *Tri, ICASPOINT *Q, int Idx)
{
	int a = 0, b = 2;
	double P1ax,P1ay,P1bx,P1by,PaQx,PaQy,s,d;
	if (Tri->Typ & L_IDENTDIR) return 0;
	if (Idx!=0) {
		a = 2; b = 0;
	}
	P1ax = Tri->P[1].x - Tri->P[a].x;
	P1ay = Tri->P[1].y - Tri->P[a].y;
	P1bx = Tri->P[1].x - Tri->P[b].x;
	P1by = Tri->P[1].y - Tri->P[b].y;
	PaQx = Tri->P[a].x - Q->x;
	PaQy = Tri->P[a].y - Q->y;
	d = P1ax * P1by - P1ay * P1bx;
	if (fabs(d) > EPS) {
		s = (P1bx * PaQy - PaQx * P1by)/d;
		Tri->P[1].x = Tri->P[a].x + s * P1ax;
		Tri->P[1].y = Tri->P[a].y + s * P1ay;
		Tri->P[b]   = *Q;
	}
	return 0;
}
//Terminal control point //isosceles triangle 
int GetCntlTerm(ICASPOINT *S, ICASPOINT *E, ICASPOINT *EE, ICASPOINT *P )
{
	double Sx,Sy,Ux,Uy,Vx,Vy,s,t,u,v;
	Ux = (E->x - S->x);
	Uy = (E->y - S->y);
	Vx = (EE->x - E->x);
	Vy = (EE->y - E->y);
	u  = sqrt(Ux*Ux + Uy*Uy);
	v  = sqrt(Vx*Vx + Vy*Vy);

	if ( u < EPS || v < EPS ) return -1;
	//unit vector
	Ux = Ux / u;
	Uy = Uy / u;
	Vx = Vx / v;
	Vy = Vy / v;
	//vector of control line
	Vx = Ux + Vx;
	Vy = Uy + Vy;
	//perpendicular vector to SE
	Ux = E->y - S->y;
	Uy = S->x - E->x;
	//constant vector
	Sx = (S->x - E->x)*0.5;
	Sy = (S->y - E->y)*0.5;

	t = Ux * Vy - Vx * Uy;
	if ( fabs(t) < EPS ) return -2;
	s = (Ux * Sy - Uy * Sx)/t;

	//Terminal control point
	P->x = E->x + s*Vx;
	P->y = E->y + s*Vy;
	return 0;
}
//
int GetCross(ICASPOINT *D1, ICASPOINT *D2,
			 ICASPOINT *C1, ICASPOINT *C2, ICASPOINT *P)
{
	double D21x,D21y,C21x,C21y,DCx,DCy,t,d;
	D21x = D1->x - D2->x;
	D21y = D1->y - D2->y;
	C21x = C1->x - C2->x;
	C21y = C1->y - C2->y;
	DCx  = D2->x - C2->x;
	DCy  = D2->y - C2->y;
	d = D21x * C21y - C21x * D21y;
	if (fabs(d) > EPS) {
		t = (C21x * DCy - C21y * DCx)/d;
		P->x = D2->x + t*D21x;
		P->y = D2->y + t*D21y;
	}
	return 0;
}
//Hit test
BOOL CSClip(double *sx, double *sy,double *x, double *y, 
		    double *l,  double *r, double *t, double *b )
{
	double s,x0,x1,y0,y1,xd,yd;
	//Cohen-Sutherland Clipping algorithm
	if      (*x < *l && *sx < *l) return FALSE;//B0100
	else if (*x > *r && *sx > *r) return FALSE;//B0001
	if      (*y > *t && *sy > *t) return FALSE;//B1000
	else if (*y < *b && *sy < *b) return FALSE;//B0010
	//
	x0 = *l - *sx;
	x1 = *r - *sx;
	y0 = *b - *sy;
	y1 = *t - *sy;
	xd = *x - *sx;
	yd = *y - *sy;
	//
	s = *sx + y0 * xd / yd;
	if ( *l < s && s < *r ) {
		return TRUE;
	}
	s = *sx + y1 * xd / yd;
	if ( *l < s && s < *r ) {
		return TRUE;
	}

	s = *sy + x0 * yd / xd;
	if ( *b < s && s < *t ) {
		return TRUE;
	}
	s = *sy + x1 * yd / xd;
	if ( *b < s && s < *t ) {
		return TRUE;
	}
	return FALSE;
}
BOOL TriInsideChk(ICASPOINT P[], ICASPOINT *Q)
{
	double P1x,P1y,P10x,P10y,P12x,P12y,QPx,QPy,u,v,d;
	P1x  = P[1].x ;
	P1y  = P[1].y ;
	P10x = P[0].x - P1x;
	P10y = P[0].y - P1y;
	P12x = P[2].x - P1x;
	P12y = P[2].y - P1y;

	d = P10x * P12y - P10y * P12x;
	if (fabs(d) < EPS) return FALSE;
	QPx  = Q->x - P1x;
	QPy  = Q->y - P1y;

	u = (P12y * QPx - P12x * QPy) / d;
	if (0.0 < u && u < 1.0)
	{
		v = (P10x * QPy - P10y * QPx) / d;
		if (0.0 < v && v < 1.0)
		{
			if ( u+v < 1.0)
			{
				return TRUE;
			}
		}
	}
	return FALSE;
}
//Get ControlPoints
int GetCntl3(ICASPOINT *S, ICASPOINT *C, ICASPOINT *E,
		     ICASPOINT *C1,ICASPOINT *C2,ICASPOINT *C3 )
{
	double Ux,Uy;
	Ux = (C->x - E->x);
	Uy = (C->y - E->y);
	if (Ux*Ux + Uy*Uy < EPS) return -1;
	C1->x = S->x + Ux;
	C1->y = S->y + Uy;
	C3->x = S->x - Ux;
	C3->y = S->y - Uy;

	Ux = (E->x - S->x);
	Uy = (E->y - S->y);
	if (Ux*Ux + Uy*Uy < EPS) return -2;
	C2->x = C->x + Ux;
	C2->y = C->y + Uy;
	return 0;
}
void Point2Work(ICASWORK *pW, ICASPOINT *pP)
{
	pW->typ = pP->typ;
	pW->x   = pP->x;
	pW->y   = pP->y;
	pW->l   = 0.0;
	pW->ex  = 0.0;
	pW->ey  = 0.0;
	pW->vx  = 0.0;
	pW->vy  = 0.0;
	pW->sts = 0;//not ready
}
//complete E members from E and S values
int Work2Vector(ICASWORK *pS, ICASWORK *pE)
{
	if (0 == pE->sts) {//not ready
		pE->vx = pE->x - pS->x;
		pE->vy = pE->y - pS->y;
		pE->l  = sqrt((pE->vx * pE->vx) + (pE->vy * pE->vy));
		pE->ex = pE->vx / pE->l;//unit vector x
		pE->ey = pE->vy / pE->l;//unit vector y
		pE->sts = 1;//Done
	}
	return pE->sts;
}
int ChkCntl(ICASWORK *SS, ICASWORK *S,
			ICASWORK *E,  ICASWORK *EE,
		    ICASPOINT *C1, ICASPOINT *M )
{
	if (( S->typ & L_MULTIPLE)&&( E->typ & L_MULTIPLE)) {
		if (fabs(S->x - E->x) < EPS && fabs(S->y - E->y) < EPS) {//S=E  prevent store
			//TRACE("ChkCntl:S==E\n");
			return -3;//S=E  prevent to store
		}
	}
	//SE middle point
	M->x = (S->x + E->x)*0.5;
	M->y = (S->y + E->y)*0.5;

	if ((SS->typ & L_MULTIPLE)&&( S->typ & L_MULTIPLE)) {//SS=S
		if (fabs(SS->x - S->x) < EPS && fabs(SS->y - S->y) < EPS) {
			if (( E->typ & L_MULTIPLE)&&(EE->typ & L_MULTIPLE)) {//E=EE
				if (fabs(E->x - EE->x) < EPS && fabs(E->y - EE->y) < EPS) {
					//TRACE("ChkCntl:SS==S && E==EE\n");
					*C1 = *M;//C1 = SE middle point
					return -4;//L_MLTSTART | L_MLTEND
				}
			}
			else {
				//TRACE("ChkCntl:SS==S\n");
				//GetCntlTerm(S,E,EE,C1);
				GetCntlTerm((ICASPOINT*)S,(ICASPOINT*)E,(ICASPOINT*)EE,C1);
				return -5;//L_MLTSTART
			}
		}
	}
	else if (( E->typ & L_MULTIPLE)&&(EE->typ & L_MULTIPLE)) {//E=EE
		if (fabs(E->x - EE->x) < EPS && fabs(E->y - EE->y) < EPS) {
			//TRACE("ChkCntl:E=EE\n");
			//GetCntlTerm(E,S,SS,C1);
			GetCntlTerm((ICASPOINT*)E,(ICASPOINT*)S,(ICASPOINT*)SS,C1);
			return -6;//L_MLTEND
		}
	}
	return 0;
}
//calculate control point
int GetCntl(ICASWORK *SS, ICASWORK *S,
			ICASWORK *E,  ICASWORK *EE,
		    ICASPOINT *C1, ICASPOINT *C2, ICASPOINT *M )
{
	double Vx,Vy,Sx,Sy,Ex,Ey,s,t,u;

	int sts = ChkCntl(SS, S, E, EE, C1, M );//set M
	if (0 > sts) return sts;//MULTIPLE check valid

	Work2Vector(SS,S);//A
	Work2Vector(S,E); //B
	Work2Vector(E,EE);//C

	//vector product
	//S-SS(A) vs S-E(B)
	s = S->vx * E->vy  - S->vy * E->vx;
	if (fabs(s) < EPS) {//M = SE middle point
		return -1;//S-SS and S-E are the identical line
	}
	//S-E(B)  vs E-EE(C)
	t = E->vx * EE->vy - E->vy * EE->vx;
	if (fabs(t) < EPS) {//M = SE middle point
		return -2;//S-E and E-EE are the identical line
	}
	//E-EE(C) vs S-SS(A)
	u = S->vx * EE->vy - S->vy * EE->vx;

	Sx = S->ex + E->ex; //A.ex + B.ex;//unit vector
	Sy = S->ey + E->ey; //A.ey + B.ey;
	Ex = E->ex + EE->ex;//B.ex + C.ex;
	Ey = E->ey + EE->ey;//B.ey + C.ey;
	Vx = E->vx;
	Vy = E->vy;

	if (L_PARALLEL == SS->typ) {//point SS on the identical line
		Sx = S->ex; //A.ex;
		Sy = S->ey; //A.ey;
	}
	if (L_PARALLEL == EE->typ) {//point EE on the identical line
		Ex = EE->ex;//C.ex;
		Ey = EE->ey;//C.ey;
	}
	//identical turnnig direction
	if (s*t > 0)
	{
		if (fabs(u) < EPS && (L_PARALLEL == SS->typ && L_PARALLEL == EE->typ)) {
			double l = E->l * 0.5;
			C1->x = S->x + S->ex * l; //A.ex * l;
			C1->y = S->y + S->ey * l; //A.ey * l;
			C2->x = E->x - EE->ex * l;//C.ex * l;
			C2->y = E->y - EE->ey * l;//C.ey * l;
			//boxy
			M->x = (C1->x + C2->x)*0.5;//C1C2 middle point
			M->y = (C1->y + C2->y)*0.5;
			return 2;
		}
		s  = (Ey*Vx - Ex*Vy)/(Sx*Ey - Ex*Sy);
		C1->x = S->x + (Sx*s);
		C1->y = S->y + (Sy*s);
		return 1;
	}
	//vector SS-S || vector E-EE (|| = parallel)
	else if (fabs(u) < EPS) {
		double l = E->l * 0.5;
		C1->x = S->x + S->ex * l; //Ax * l;
		C1->y = S->y + S->ey * l; //Ay * l;
		C2->x = E->x - EE->ex * l;//Cx * l;
		C2->y = E->y - EE->ey * l;//Cy * l;
		//Z fold//M = SE middle point
		return 2;
	}
	//Z fold
	else {
		double Ax,Ay,Cx,Cy;
		double C12x,C12y,w,v;
		double l = E->l * 0.5;
		w = sqrt(Sx*Sx + Sy*Sy);
		v = sqrt(Ex*Ex + Ey*Ey);
		Ax = Sx / w;
		Ay = Sy / w;
		Cx = Ex / v;
		Cy = Ey / v;
		C1->x = S->x + Ax * l;
		C1->y = S->y + Ay * l;
		C2->x = E->x - Cx * l;
		C2->y = E->y - Cy * l;
		C12x = C2->x - C1->x;
		C12y = C2->y - C1->y;
		u = Vx * C12y - Vy * C12x;

		if (fabs(u) < EPS) {//fail safe//M = SE middle point
		}
		//cross point SE and C1C2
		else {
			s = ((S->y - C1->y)*C12x - C12y*(S->x - C1->x))/u;
			M->x = S->x + (Vx*s);
			M->y = S->y + (Vy*s);
		}
		return 2;
	}
}
int ChkParallel(ICASPOINT Seg[], int SegCnt)
{
	int i, cnt = 0;
	int siz = SegCnt;
	int typ = L_NORMAL;
	double s,t;
	ICASPOINT U,V;
	if (siz < 3) return 0;
	--siz;//last -1
	U.x = Seg[0].x - Seg[siz].x;
	U.y = Seg[0].y - Seg[siz].y;
	for(i=0; i<siz; ++i)
	{
		V.x = Seg[i+1].x - Seg[i].x;
		V.y = Seg[i+1].y - Seg[i].y;
		s = V.x * V.x + V.y * V.y;//square length
		t = U.x * V.y - U.y * V.x;//vector product
		//identical check
		if (s < EPS) {//fabs(s) < EPS) {
			typ = L_MULTIPLE;
			Seg[i].typ = L_MULTIPLE;//same point also next too
			//TRACE("ChkParallel[%d]:MULTIPLE\n",i);
		}
		//parallel check
		else if (typ != L_MULTIPLE && fabs(t) < EPS) {
			typ = L_NORMAL;
			Seg[i].typ = L_PARALLEL;//on the unique line
			++cnt;
			//TRACE("ChkParallel[%d]:PARALLEL\n",i);
		}
		else {
			//TRACE("ChkParallel[%d]:%d\n",i,typ);
			Seg[i].typ = typ;//for previous L_MULTIPLE
			typ = L_NORMAL;
		}
		//
		U = V;
	}
	V.x = Seg[siz].x - Seg[0].x;
	V.y = Seg[siz].y - Seg[0].y;
	s = V.x * V.x + V.y * V.y;
	t = U.x * V.y - U.y * V.x;
	if (s < EPS) {//fabs(s) < EPS) {
		Seg[siz].typ = L_MULTIPLE;//same point 
		//TRACE("ChkParallelEND[%d]:MULTIPLE\n",siz);
	}
	else if (typ != L_MULTIPLE && fabs(t) < EPS) {
		Seg[siz].typ = L_PARALLEL;//on the line between Pre/Post 
		++cnt;
		//TRACE("ChkParallelEND[%d]:PARALLEL\n",siz);
	}
	else {
		//TRACE("ChkParallelEND[%d]:%d\n",siz,typ);
		Seg[siz].typ = typ;
	}
	return cnt;
}
int get_quad( ICASPOINT *O, ICASPOINT *P )//O:origin P:segment data
{
	if ( P->x > O->x + EPS ) {
		if ( P->y  < O->y - EPS ) return( 4 );
		else                      return( 1 );
	}
	else if ( P->x < O->x - EPS ) {
		if ( P->y  > O->y + EPS ) return( 2 );
		else                      return( 3 );
	}
	else {
		if (P->y  > O->y )        return( 2 );
		else                      return( 4 );
	}
}
//
BOOL ChkArea(ICASPOINT Seg[], int SegCnt, ICASPOINT *O)
{
    int i, j, q_ang, vs_quad, ve_quad, q_dif;
    double x_mid;
	int cnt = SegCnt;

	q_ang = 0;
	//Which quad is Seg[LAST] in?
	j = cnt-1;
	vs_quad = get_quad(O,&Seg[j]);

	for(i = 0; i < cnt; ++i)
	{
		//vertex on vertex
		if (fabs(Seg[i].x - O->x)<EPS && fabs(Seg[i].y - O->y)<EPS) {
		    return TRUE;//V_ON_V;
		}
		//Which quad is m_Seg[i] in?
		ve_quad = get_quad(O,&Seg[i]);

		//get quad transit
		q_dif = ve_quad - vs_quad;
		switch(q_dif) {
		case 2: case -2:
			if (fabs(Seg[j].y - Seg[i].y) < EPS) {
				x_mid = O->x;
			}
			else {
				x_mid = Seg[j].x - (((Seg[j].y-O->y)*(Seg[i].x-Seg[j].x))/(Seg[i].y-Seg[j].y));
			}
			if ( x_mid > O->x + EPS ) {
				q_dif *= -1;
			}
			else if ( x_mid < O->x - EPS ) {
			}
			else {//vertex on edge
				return TRUE;//V_ON_E;
			}
			break;
		case 3:
			q_dif = -1; break;
		case -3:
			q_dif = 1; break;
		}
		q_ang += q_dif;
		vs_quad = ve_quad;
		j = i;
	}
	q_ang = abs(q_ang);
	if (q_ang > 0 && 0 == q_ang%4) {//IN
		return TRUE;//V_IN;
	}
	else {//OUT
		return FALSE;//V_OUT;
	}
}

//add new Triangle
int SetInC(ICASTRI Tri[], int TriCnt, 
		   ICASPOINT *S, ICASPOINT *E, ICASPOINT *C,
		   int IcasTyp)
{
	if (NULL == Tri || TriCnt >= L_ICAS_MAX) return 0;
	Tri[TriCnt].Typ = IcasTyp;
	Tri[TriCnt].P[0] = *S;
	Tri[TriCnt].P[0].typ = L_NORMAL;
	Tri[TriCnt].P[1] = *C;
	Tri[TriCnt].P[1].typ = L_NORMAL;
	Tri[TriCnt].P[2] = *E;
	Tri[TriCnt].P[2].typ = L_NORMAL;
	++TriCnt;
	return TriCnt;
}
//dispatch by number of Control points
int SetTriangle(ICASTRI Tri[], int TriCnt,
				int cnt, int addflg,
				ICASPOINT *S,  ICASPOINT *E,
				ICASPOINT *C1, ICASPOINT *C2, ICASPOINT *M )
{
	if (cnt == 1) {
		TriCnt = SetInC(Tri, TriCnt, S, E, C1, (L_NORMAL | addflg));
	}
	else if (cnt == 2) {
		TriCnt = SetInC(Tri, TriCnt, S, M, C1, (L_NORMAL | L_AUTO_R | addflg));
		TriCnt = SetInC(Tri, TriCnt, M, E, C2, (L_NORMAL | L_AUTO_L | addflg));
	}
	//identical line
	else if (cnt == -1 || cnt == -2) {
		TriCnt = SetInC(Tri, TriCnt, S, E, M, (L_IDENTDIR | addflg));
	}
	//multiple points(start & end)
	else if (cnt == -4) {
		TriCnt = SetInC(Tri, TriCnt, S, E, C1, (L_MLTSTART | L_MLTEND | L_LINE | addflg));
	}
	//multiple point(start)
	else if (cnt == -5) {
		TriCnt = SetInC(Tri, TriCnt, S, E, C1, (L_MLTSTART | addflg));
	}
	//multiple point(end)
	else if (cnt == -6) {
		TriCnt = SetInC(Tri, TriCnt, S, E, C1, (L_MLTEND | addflg));
	}
	return TriCnt;
}
//make Control points
BOOL IcasSetCntl(int Type, ICASPOINT Seg[], int *pSegCnt, ICASTRI Tri[], int *pTriCnt)
{
	int siz = *pSegCnt, cnt, tsiz = 0, i;
	ICASPOINT C1, C2, M;
	ICASWORK  SS, S, E, EE, E2, E3;
	//
	if (siz < 3) return FALSE;
	//
	*pTriCnt = 0;
	//
	ChkParallel(Seg, siz);
	//
	//Start part
	Point2Work(&SS, &(Seg[siz-1]));//Point2Work(ICASPOINT *pP, ICASWORK *pW)
	Point2Work(&S,  &(Seg[0]));
	Point2Work(&E,  &(Seg[1]));
	Point2Work(&EE, &(Seg[2]));

	if (Type) {//Close
		cnt = GetCntl( &SS, &S, &E, &EE, &C1, &C2, &M );
	}
	else {//Open
		if ( 0 == GetCntlTerm( (ICASPOINT*)&S, (ICASPOINT*)&E, (ICASPOINT*)&EE, &C1 ) ) cnt = 1;
		else return FALSE;
	}
	tsiz = SetTriangle(Tri, tsiz, cnt, L_START, (ICASPOINT*)&S, (ICASPOINT*)&E, &C1, &C2, &M );
	//Main part
	for(i=3; i<siz; i++) {
		SS = S;
		S  = E;
		E  = EE;
		Point2Work(&EE, &(Seg[i]));
		//
		cnt  = GetCntl( &SS, &S, &E, &EE, &C1, &C2, &M );
		tsiz = SetTriangle(Tri, tsiz, cnt, L_MAIN, (ICASPOINT*)&S, (ICASPOINT*)&E, &C1, &C2, &M );
	}
	if (Type) {//Close
		//End part
		Point2Work(&E2, &(Seg[0]));
		cnt  = GetCntl( &S, &E, &EE, &E2, &C1, &C2, &M );
		tsiz = SetTriangle(Tri, tsiz, cnt, L_END, (ICASPOINT*)&E, (ICASPOINT*)&EE, &C1, &C2, &M );
		//Bridge part
		Point2Work(&E3, &(Seg[1]));
		cnt  = GetCntl( &E, &EE, &E2, &E3, &C1, &C2, &M );
		tsiz = SetTriangle(Tri, tsiz, cnt, L_BRIDGE, (ICASPOINT*)&EE, (ICASPOINT*)&E2, &C1, &C2, &M );
	}
	else {//Open
		//End part
		if ( 0 == GetCntlTerm( (ICASPOINT*)&EE, (ICASPOINT*)&E, (ICASPOINT*)&S, &C1 ) ) cnt = 1;
		else return FALSE;
		tsiz = SetTriangle(Tri, tsiz, cnt, L_END, (ICASPOINT*)&E, (ICASPOINT*)&EE, &C1, &C2, &M );
	}
	//
	*pTriCnt = tsiz;
	return TRUE;
}
BOOL IcasOpen(ICASPOINT Seg[], int *pSegCnt, ICASTRI Tri[], int *pTriCnt)
{
	int siz = *pSegCnt, tsiz = *pTriCnt, cnt, i;
	ICASPOINT C1;
	ICASWORK  S, E, EE;//,SS;
	//
	if (siz < 3) return FALSE;
	//
	if (!(Tri[tsiz-1].Typ & L_BRIDGE)) return FALSE; //already open, perhaps...
	//
	if (   fabs(Tri[0].P[0].x - Tri[tsiz-1].P[2].x) > EPS
		|| fabs(Tri[0].P[0].y - Tri[tsiz-1].P[2].y) > EPS ) return FALSE;

	//Start part
	Point2Work(&S,  &(Seg[0]));//Point2Work(ICASPOINT *pP, ICASWORK *pW)
	Point2Work(&E,  &(Seg[1]));
	Point2Work(&EE, &(Seg[2]));

	cnt = GetCntlTerm( (ICASPOINT*)&S, (ICASPOINT*)&E, (ICASPOINT*)&EE, &C1 );
	if (0 == cnt) {
		if (Tri[0].Typ & L_AUTO_R) {
			//delete Tri[1]
			for(i=1; i<tsiz; ++i)
			{
				Tri[i] = Tri[i+1];
			}
			tsiz--;
		}
		Tri[0].P[0] = Seg[0];
		Tri[0].P[1] = C1;
		Tri[0].P[2] = Seg[1];
		Tri[0].Typ  = L_NORMAL;
	}
	else return FALSE;

	//End part
	Point2Work(&S,  &(Seg[siz-3]));
	Point2Work(&E,  &(Seg[siz-2]));
	Point2Work(&EE, &(Seg[siz-1]));//last

	cnt = GetCntlTerm( (ICASPOINT*)&S, (ICASPOINT*)&E, (ICASPOINT*)&EE, &C1 );
	if (0 == cnt) {
		cnt = tsiz -3;//delete max
		for(i=tsiz-1; i>=cnt; --i) {
			if (Tri[i].Typ & (L_AUTO_R | L_AUTO_L)) {
				tsiz--;
			}
		}
		Tri[tsiz-1].P[0] = Seg[siz-2];
		Tri[tsiz-1].P[1] = C1;
		Tri[tsiz-1].P[2] = Seg[siz-1];
		Tri[tsiz-1].Typ  = L_NORMAL;
	}
	else return FALSE;

	*pTriCnt = tsiz;
	return TRUE;
}
BOOL IcasClose(ICASPOINT Seg[], int *pSegCnt, ICASTRI Tri[], int *pTriCnt)
{
	int siz = *pSegCnt, tsiz = *pTriCnt, cnt, i;
	ICASPOINT C1, C2, M;
	ICASWORK  SS, S, E, EE, E2, E3;
	//
	if (siz < 3) return FALSE;
	//
	if (Tri[tsiz-1].Typ & L_BRIDGE) return FALSE; //already close, perhaps...
	//
	if (   fabs(Tri[0].P[0].x - Tri[tsiz-1].P[2].x) < EPS
		&& fabs(Tri[0].P[0].y - Tri[tsiz-1].P[2].y) < EPS ) return FALSE;

	//Start part
	Point2Work(&SS, &(Seg[siz-1]));//Point2Work(ICASPOINT *pP, ICASWORK *pW)
	Point2Work(&S,  &(Seg[0]));
	Point2Work(&E,  &(Seg[1]));
	Point2Work(&EE, &(Seg[2]));

	cnt = GetCntl( &SS, &S, &E, &EE, &C1, &C2, &M );
	if (1 == cnt) {
		Tri[0].P[1] = C1;
		Tri[0].Typ  = L_NORMAL;
	}
	else if (2 == cnt) {
		//Insert
		//make space //to be m_Tri[i] == m_Tri[i+1]
		for(i=tsiz; i>0; --i)
		{
			Tri[i] = Tri[i-1];
		}
		tsiz++;
		//
		Tri[0].P[0] = Seg[0];
		Tri[0].P[1] = C1;
		Tri[0].P[2] = M;
		Tri[0].Typ  = L_NORMAL | L_AUTO_R;
		Tri[1].P[0] = M;
		Tri[1].P[1] = C2;
		Tri[1].P[2] = Seg[1];
		Tri[1].Typ  = L_NORMAL | L_AUTO_L;
		//tsiz = SetTriangle(Tri, tsiz, cnt, L_START, (ICASPOINT*)&S, (ICASPOINT*)&E, &C1, &C2, &M );
	}
	else return FALSE;

	//End part
	Point2Work(&S,  &(Seg[siz-3]));
	Point2Work(&E,  &(Seg[siz-2]));
	Point2Work(&EE, &(Seg[siz-1]));//last
	Point2Work(&E2, &(Seg[0]));

	cnt  = GetCntl( &S, &E, &EE, &E2, &C1, &C2, &M );
	if (1 == cnt) {
		Tri[tsiz-1].P[0] = Seg[siz-2];
		Tri[tsiz-1].P[1] = C1;
		Tri[tsiz-1].P[2] = Seg[siz-1];//last
		Tri[tsiz-1].Typ  = L_NORMAL;
	}
	else if (2 == cnt) {
		tsiz = SetTriangle(Tri, tsiz, cnt, L_END, (ICASPOINT*)&E, (ICASPOINT*)&EE, &C1, &C2, &M );
	}
	else return FALSE;

	//Bridge part
	Point2Work(&E3, &(Seg[1]));
	cnt  = GetCntl( &E, &EE, &E2, &E3, &C1, &C2, &M );
	tsiz = SetTriangle(Tri, tsiz, cnt, L_BRIDGE, (ICASPOINT*)&EE, (ICASPOINT*)&E2, &C1, &C2, &M );

	*pTriCnt = tsiz;
	return TRUE;
}
BOOL MoveRecord(ICASTRI Tri[], int TriCnt,
				ICASPOINT Seg[], int SegCnt, ICASPOINT *D)
{
	int i;
	for(i=0; i<SegCnt; ++i) {
		Seg[i].x = Seg[i].x + D->x;
		Seg[i].y = Seg[i].y + D->y;
	}
	for(i=0; i<TriCnt; ++i) {
		Tri[i].P[0].x = Tri[i].P[0].x + D->x;
		Tri[i].P[0].y = Tri[i].P[0].y + D->y;
		Tri[i].P[1].x = Tri[i].P[1].x + D->x;
		Tri[i].P[1].y = Tri[i].P[1].y + D->y;
		Tri[i].P[2].x = Tri[i].P[2].x + D->x;
		Tri[i].P[2].y = Tri[i].P[2].y + D->y;
	}
	return TRUE;
}

BOOL RotateRecord(ICASTRI Tri[], int TriCnt,
				  ICASPOINT Seg[], int SegCnt, int iD, 
				  ICASPOINT *D, int init)
{
	static ICASPOINT Mat;
	ICASPOINT u, w;
	ICASPOINT o = Seg[iD];//rotate origin 
	ICASPOINT v = *D;
	double d;
	int i,j;
	v.x -= o.x;//
	v.y -= o.y;
	d = sqrt(v.x*v.x + v.y*v.y);
	if (fabs(d) < EPS ) return FALSE;
	v.x = v.x / d;//unit vector
	v.y = v.y / d;
	if (init) {
		Mat.x = v.x;
		Mat.y = v.y;
		//TRACE("0:[%d]%lf,%lf",m_iD,v.x,v.y);
		return TRUE;
	}
	else {
		u.x = Mat.x * v.x + Mat.y * v.y;
		u.y = Mat.x * v.y - Mat.y * v.x;
		//TRACE("[%d]%lf,%lf\n",m_iD,u.x,u.y);
	}
	for(i=0; i<SegCnt; ++i) {
		if (i == iD) continue;
		w.x = Seg[i].x - o.x;
		w.y = Seg[i].y - o.y;
		Seg[i].x = u.x * w.x - u.y * w.y + o.x;
		Seg[i].y = u.y * w.x + u.x * w.y + o.y;
	}
	for(i=0; i<TriCnt; ++i) {
		for(j=0; j<3; ++j) {
			w.x = Tri[i].P[j].x - o.x;
			w.y = Tri[i].P[j].y - o.y;
			if(fabs(w.x) < EPS && fabs(w.y) < EPS ) continue;
			Tri[i].P[j].x = u.x * w.x - u.y * w.y + o.x;
			Tri[i].P[j].y = u.y * w.x + u.x * w.y + o.y;
		}
	}
	return TRUE;
}

BOOL MoveVirtualPoint(ICASTRI Tri[], int TriCnt,
					  int iT, int iTR,
					  ICASPOINT *C, ICASPOINT *P, ICASPOINT *Q,
					  ICASPOINT *D, int init)
{
	static ICASPOINT A,B,AB,CD,AC,BD;
	ICASPOINT M;
	double d,s,t;

	if (init) {
		A = Tri[iT ].P[0];
		B = Tri[iTR].P[2];
		AB.x = B.x - A.x;
		AB.y = B.y - A.y;
		d = sqrt(AB.x * AB.x + AB.y * AB.y);
		if (fabs(d) > EPS) {
			AB.x = AB.x / d;//unit vector
			AB.y = AB.y / d;
		}
		else return FALSE;

		CD.x = Tri[iTR].P[1].x - Tri[iT].P[1].x;
		CD.y = Tri[iTR].P[1].y - Tri[iT].P[1].y;
		AC.x = Tri[iT ].P[1].x - A.x;
		AC.y = Tri[iT ].P[1].y - A.y;
		BD.x = Tri[iTR].P[1].x - B.x;
		BD.y = Tri[iTR].P[1].y - B.y;
		return TRUE;
	}
	M = A;
	d = AB.x * (D->x - M.x) + AB.y * (D->y - M.y);//Inner product
	//New Auto = M
	M.x += d * AB.x;//scale unit vector
	M.y += d * AB.y;
	M.typ = L_NORMAL;
	*C = M;

	d = AC.y * CD.x - AC.x * CD.y;
	if (fabs(d) < EPS) return FALSE;
	s = ((M.y - A.y)*CD.x - (M.x - A.x)*CD.y)/d;

	d = BD.y * CD.x - BD.x * CD.y;
	if (fabs(d) < EPS) return FALSE;
	t = ((M.y - B.y)*CD.x - (M.x - B.x)*CD.y)/d;

	P->x = A.x + s * AC.x;
	P->y = A.y + s * AC.y;
	Q->x = B.x + t * BD.x;
	Q->y = B.y + t * BD.y;
	P->typ = L_NORMAL;
	Q->typ = L_NORMAL;
	return TRUE;
}

int ChkLinear(ICASPOINT Seg[], int iDL, int iDR, ICASPOINT *D)
{
	int sts = L_NORMAL;
	double Ux,Uy,d1,Vx,Vy,d2;
	Ux = Seg[iDL].x - D->x;
	Uy = Seg[iDL].y - D->y;
	d1 = Ux*Ux + Uy*Uy;
	if (fabs(d1) < EPS) {
		//TRACE("ChkLiner1:L_MULTIPLE\n");
		sts = L_MULTIPLE;
	}
	else {
		Vx = Seg[iDR].x - D->x;
		Vy = Seg[iDR].y - D->y;
		d2 = Vx*Vx + Vy*Vy;
		if (fabs(d2) < EPS) {
			//TRACE("ChkLiner2:L_MULTIPLE\n");
			sts = L_MULTIPLE;
		}
		else {
			d1 = Ux*Vy - Vx*Uy;
			if (fabs(d1) < EPS ) {
				//TRACE("ChkLiner3:L_PARALLEL\n");
				sts = L_PARALLEL;
			}
		}
	}
	return sts;
}

void CalcInsertCntl(ICASTRI Tri[], int iT,
					ICASPOINT *M, ICASPOINT *C)
{
	M->x = (Tri[iT].P[0].x + Tri[iT].P[2].x)*0.5;
	M->y = (Tri[iT].P[0].y + Tri[iT].P[2].y)*0.5;
	C->x = (M->x - Tri[iT].P[1].x)*0.5;
	C->y = (M->y - Tri[iT].P[1].y)*0.5;
	C->x += M->x;
	C->y += M->y;
	M->typ = L_NORMAL;
	C->typ = L_NORMAL;
}

void MidPoint(ICASPOINT Seg[], int iDS, int iDE,
			  ICASPOINT *M )
{
	M->x = (Seg[iDS].x + Seg[iDE].x)*0.5;
	M->y = (Seg[iDS].y + Seg[iDE].y)*0.5;
	M->typ = L_NORMAL;
}

/////////////////////////////////////////////////////////////////////////////

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Japan Japan
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions