00001
00002
00003 #define MODULE_PATH
00004
00005 #include "animate.h"
00006
00007 static short Ni;
00008 static double dtau;
00009
00010 static void DrawEndOfPath(HDC hdc[],
00011 point v1,
00012 short status, short pointstatus);
00013 static void DrawPathSegment(HDC hdc [],
00014 point vl ,point v1, point v2, point vn,
00015 short status, short pointstatus,
00016 double ts, double te);
00017 static double SegmentLength(point vl, point v1, point v2, point vn,
00018 double ts, double te);
00019 static void DrawPathCurve(HDC hDC);
00020 static void DrawLagrangePathCurve(HDC hDC);
00021 static PATHEDITCONTROL *GetPathEditPoint(int x, int y);
00022 static void CalculatePathPositions(object *op);
00023
00024
00025 long SplinesP(double k[], double tau){
00026 return (long)(tau*(tau*(tau*k[3] + k[2]) + k[1]) + k[0]);
00027 }
00028
00029 double SplinesR(double k[], double tau){
00030 return (double)(tau*(tau*(tau*k[3] + k[2]) + k[1]) + k[0]);
00031 }
00032
00033 void SplinesK(double k[], long vl, long v1, long v2, long vn){
00034 k[0] = (double)v1;
00035 k[1] = -0.5*(double)vl+0.5*(double)v2;
00036 k[2] = (double)vl-2.5*(double)v1+2.0*(double)v2-0.5*(double)vn;
00037 k[3] = -0.5*(double)vl+1.5*(double)v1-1.5*(double)v2+0.5*(double)vn;
00038 }
00039
00040 void SplinesG(double k[], double xi, double xi1, double xig, double xig1){
00041 k[0] = xi;
00042 k[1] = xig;
00043 k[2] = -3.0*xi+3.0*xi1-2.0*xig-xig1;
00044 k[3] = 2.0*xi-2.0*xi1+xig+xig1;
00045 }
00046
00047 static void DrawEndOfPath(HDC hdc[],
00048 point v1,
00049 short status, short pointstatus){
00050 int i,sh1,sv1;
00051 int ifd,ild;
00052 HPEN holdpen;
00053 HBRUSH holdbrush;
00054 if(View == TRIVIEW){ifd=0;ild=3;}
00055 else {ifd=ActiveView; ild=ifd+1;}
00056 if(in_stage_triview(v1)){
00057 for(i=ifd;i<ild;i++){
00058 GetWindowCoords(i,v1[0],v1[1],v1[2],&sh1,&sv1);
00059 if(tool == NOTOOL || tool == PAN || tool == INZOOM ||
00060 status == DESELECTED){
00061 if (status == SELECTED)holdpen=SelectObject(hdc[i],ghSelectedPen);
00062 else holdpen=SelectObject(hdc[i],ghDeselectedPen);
00063 }
00064 else{
00065 if(status == EDITING)holdpen=SelectObject(hdc[i],ghEditPen);
00066 else holdpen=SelectObject(hdc[i],ghInvertPen);
00067 }
00068 if(status == EDITING && pointstatus == SELECTED){
00069 SelectObject(hdc[i],ghSelectedPen);
00070 holdbrush=SelectObject(hdc[i],ghInvertBrush);
00071 Rectangle(hdc[i],
00072 (int)sh1-SelectPointSize-1,(int)sv1-SelectPointSize-1,
00073 (int)sh1+SelectPointSize+2,(int)sv1+SelectPointSize+2);
00074 SelectObject(hdc[i],holdbrush);
00075 }
00076 else{
00077 holdbrush=SelectObject(hdc[i],ghSelectedBrush);
00078 Rectangle(hdc[i],
00079 (int)sh1-SelectPointSize,(int)sv1-SelectPointSize,
00080 (int)sh1+SelectPointSize,(int)sv1+SelectPointSize);
00081 SelectObject(hdc[i],holdbrush);
00082 }
00083 SelectObject(hdc[i],holdpen);
00084 }
00085 }
00086 }
00087
00088 static void DrawPathSegment(HDC hdc[],
00089 point vl ,point v1, point v2, point vn,
00090 short status, short pointstatus,
00091 double ts, double te){
00092 int i,j,sh1,sv1,sh2,sv2;
00093 int ifd,ild;
00094 long x,y,z,xl,yl,zl;
00095 double tau,kx[4],ky[4],kz[4];
00096 HPEN holdpen;
00097 HBRUSH holdbrush;
00098 if(View == TRIVIEW){ifd=0;ild=3;}
00099 else {ifd=ActiveView; ild=ifd+1;}
00100 if(in_stage_triview(v1) || in_stage_triview(v2)){
00101 double gs,ge;
00102 gs=(double)(v2[0]-vl[0])*ts; ge=(double)(vn[0]-v1[0])*te;
00103 SplinesG(kx,v1[0],v2[0],gs,ge);
00104 gs=(double)(v2[1]-vl[1])*ts; ge=(double)(vn[1]-v1[1])*te;
00105 SplinesG(ky,v1[1],v2[1],gs,ge);
00106 gs=(double)(v2[2]-vl[2])*ts; ge=(double)(vn[2]-v1[2])*te;
00107 SplinesG(kz,v1[2],v2[2],gs,ge);
00108
00109
00110
00111 tau=0.0;
00112 for(j = 0; j <= Ni; j++){
00113 x = SplinesP(kx,tau);
00114 y = SplinesP(ky,tau);
00115 z = SplinesP(kz,tau);
00116 for(i=ifd;i<ild;i++){
00117 GetWindowCoords(i,x,y,z,&sh1,&sv1);
00118 if(j != 0)GetWindowCoords(i,xl,yl,zl,&sh2,&sv2);
00119 if(tool == NOTOOL || tool == PAN || tool == INZOOM ||
00120 status == DESELECTED){
00121 if (status == SELECTED)holdpen=SelectObject(hdc[i],ghSelectedPen);
00122 else holdpen=SelectObject(hdc[i],ghDeselectedPen);
00123 }
00124 else {
00125 if(status == EDITING)holdpen=SelectObject(hdc[i],ghEditPen);
00126 else holdpen=SelectObject(hdc[i],ghInvertPen);
00127 }
00128 MoveToEx(hdc[i],sh1,sv1,NULL);
00129 if(j != 0)LineTo(hdc[i],sh2,sv2);
00130 else{
00131 if(status == EDITING && pointstatus == SELECTED){
00132 SelectObject(hdc[i],ghSelectedPen);
00133 holdbrush=SelectObject(hdc[i],ghInvertBrush);
00134 Rectangle(hdc[i],
00135 (int)sh1-SelectPointSize-1,(int)sv1-SelectPointSize-1,
00136 (int)sh1+SelectPointSize+2,(int)sv1+SelectPointSize+2);
00137 SelectObject(hdc[i],holdbrush);
00138 }
00139 else{
00140 Rectangle(hdc[i],
00141 (int)sh1-SelectPointSize,(int)sv1-SelectPointSize,
00142 (int)sh1+SelectPointSize+1,(int)sv1+SelectPointSize+1);
00143 }
00144 }
00145 SelectObject(hdc[i],holdpen);
00146 }
00147 tau += dtau;
00148 xl=x; yl=y; zl=z;
00149 }
00150 }
00151 }
00152
00153 void DrawPath(HDC hdc[], object *Op, point Offset,
00154 double p, double t, double a,
00155 short im, double ima, short status){
00156 int i;
00157 short pointstatus;
00158 point Vpp,Vpn,Vpnn,*Vp;
00159 pathpoint *Pp;
00160 double ts,te;
00161 pointstatus=DESELECTED;
00162
00163
00164 if(View == TRIVIEW){ Ni= 3; dtau=0.3333333; }
00165 else { Ni= 4; dtau=0.25; }
00166 if((Vp=(point *)X__Malloc(Op->npathpoints * sizeof(point))) == NULL){
00167 SendPrgmQuery(IDQ_NOMEM1,0);
00168 return;
00169 }
00170 Pp=Op->firstpathpoint; i=0; while(Pp != NULL){
00171 CopyPoint(Pp->p,Vp[i]);
00172 i++; Pp=Pp->next;
00173 }
00174 if(i != Op->npathpoints){
00175 SendPrgmQuery(IDQ_PATH1,0);
00176 if(Vp != NULL)X__Free(Vp);
00177 return;
00178 }
00179 Transform((long)(Op->npathpoints),Vp,Vp,Offset,p,t,a,im,ima);
00180 if(status == SELECTED || status == EDITING){
00181 DrawArrow(hdc,Offset,p,t,a,im,ima,(double)UNIT/8);
00182 }
00183
00184 if(Op->pathtype == OPEN){
00185 SubPoints(Vp[1],Vp[0],Vpp);
00186 SubPoints(Vp[0],Vpp,Vpp);
00187 SubPoints(Vp[Op->npathpoints - 1],Vp[Op->npathpoints - 2],Vpnn);
00188 AddPoints(Vp[Op->npathpoints - 1],Vpnn,Vpn);
00189 }
00190 Pp=Op->firstpathpoint; i=0; while(Pp != NULL){
00191 pointstatus=DESELECTED;
00192 ts=Pp->tension_n;
00193 if(Pp->next != NULL)te=Pp->next->tension_p;
00194 else{
00195 if(Op->pathtype == OPEN)te=0.5;
00196 else te=Op->firstpathpoint->tension_p;
00197 }
00198 if(Pp == SelectedPathPoint)pointstatus=SELECTED;
00199 if(Op->pathtype == OPEN){
00200 if(i == 0 && Op->npathpoints == 2)DrawPathSegment(hdc,
00201 Vpp,Vp[0],Vp[1],Vpn,status,pointstatus,ts,te);
00202 else if(i == 0)DrawPathSegment(hdc,Vpp,Vp[0],Vp[1],Vp[2],
00203 status,pointstatus,ts,te);
00204 else if(i == Op->npathpoints - 2)DrawPathSegment(hdc,
00205 Vp[i-1],Vp[i],Vp[i+1],Vpn,status,pointstatus,ts,te);
00206 else if(i == Op->npathpoints - 1)
00207 DrawEndOfPath(hdc,Vp[Op->npathpoints - 1],status,pointstatus);
00208 else
00209 DrawPathSegment(hdc,Vp[i-1],Vp[i],Vp[i+1],Vp[i+2],
00210 status,pointstatus,ts,te);
00211 }
00212 else{
00213 if(i == 0 && Op->npathpoints == 3)DrawPathSegment(hdc,
00214 Vp[2],Vp[0],Vp[1],Vp[2],status,pointstatus,ts,te);
00215 else if(i == 0)DrawPathSegment(hdc,Vp[Op->npathpoints - 1],
00216 Vp[0],Vp[1],Vp[2],status,pointstatus,ts,te);
00217 else if(i == Op->npathpoints - 2)DrawPathSegment(hdc,
00218 Vp[i-1],Vp[i],Vp[i+1],Vp[0],status,pointstatus,ts,te);
00219 else if(i == Op->npathpoints - 1)DrawPathSegment(hdc,
00220 Vp[i-1],Vp[i],Vp[0],Vp[1],status,pointstatus,ts,te);
00221 else
00222 DrawPathSegment(hdc,Vp[i-1],Vp[i],Vp[i+1],Vp[i+2],
00223 status,pointstatus,ts,te);
00224 }
00225 i++; Pp=Pp->next;
00226 }
00227 X__Free(Vp);
00228 }
00229
00230
00231 static double SegmentLength(point vl, point v1, point v2, point vn,
00232 double ts, double te){
00233 short j;
00234 long x,y,z,xl,yl,zl;
00235 double result,tau,kx[4],ky[4],kz[4];
00236 double gs,ge;
00237 gs=(double)(v2[0]-vl[0])*ts; ge=(double)(vn[0]-v1[0])*te;
00238 SplinesG(kx,v1[0],v2[0],gs,ge);
00239 gs=(double)(v2[1]-vl[1])*ts; ge=(double)(vn[1]-v1[1])*te;
00240 SplinesG(ky,v1[1],v2[1],gs,ge);
00241 gs=(double)(v2[2]-vl[2])*ts; ge=(double)(vn[2]-v1[2])*te;
00242 SplinesG(kz,v1[2],v2[2],gs,ge);
00243 tau=0.0;
00244 result=0.0;
00245 for(j = 0; j <= Ni; j++){
00246 x = SplinesP(kx,tau);
00247 y = SplinesP(ky,tau);
00248 z = SplinesP(kz,tau);
00249 if(j > 0)result += sqrt((double)(x-xl)*(double)(x-xl)
00250 +(double)(y-yl)*(double)(y-yl)
00251 +(double)(z-zl)*(double)(z-zl) );
00252 tau += dtau;
00253 xl=x; yl=y; zl=z;
00254 }
00255 return result;
00256 }
00257
00258 static double GetSegmentPositionForLength(point vl, point v1, point v2, point vn,
00259 double ts, double te, double d, vector p){
00260 short j;
00261 long x,y,z,xl,yl,zl;
00262 double result,tau,kx[4],ky[4],kz[4];
00263 double gs,ge;
00264 gs=(double)(v2[0]-vl[0])*ts; ge=(double)(vn[0]-v1[0])*te;
00265 SplinesG(kx,v1[0],v2[0],gs,ge);
00266 gs=(double)(v2[1]-vl[1])*ts; ge=(double)(vn[1]-v1[1])*te;
00267 SplinesG(ky,v1[1],v2[1],gs,ge);
00268 gs=(double)(v2[2]-vl[2])*ts; ge=(double)(vn[2]-v1[2])*te;
00269 SplinesG(kz,v1[2],v2[2],gs,ge);
00270 tau=0.0;
00271 result=0.0;
00272 for(j = 0; j <= Ni; j++){
00273 x = SplinesP(kx,tau);
00274 y = SplinesP(ky,tau);
00275 z = SplinesP(kz,tau);
00276 if(j > 0)result += sqrt((double)(x-xl)*(double)(x-xl)
00277 +(double)(y-yl)*(double)(y-yl)
00278 +(double)(z-zl)*(double)(z-zl) );
00279 if(result > d){
00280 p[0]=x; p[1]=y; p[2]=z;
00281 return -1.0;
00282 }
00283 tau += dtau;
00284 xl=x; yl=y; zl=z;
00285 }
00286 return result;
00287 }
00288
00289
00290 void ReversePathDirection(object *op){
00291 double t;
00292 pathpoint *p,*pn,*lp,*fp;
00293 if(op == NULL)return;
00294 pn=op->firstpathpoint;
00295 if(pn == NULL)return;
00296 if(op->pathtype == OPEN){
00297 while(pn != NULL){
00298 p=pn;
00299 pn=p->next;
00300 p->next=p->last;
00301 p->last=pn;
00302 t=p->tension_n;
00303 p->tension_n=p->tension_p;
00304 p->tension_p=t;
00305 }
00306 op->firstpathpoint=p;
00307 }
00308 else{
00309 p=pn; fp=pn; while(p != NULL){lp=p; p=p->next;} pn=pn->next;
00310 while(pn != NULL){
00311 p=pn;
00312 pn=p->next;
00313 p->next=p->last;
00314 p->last=pn;
00315 t=p->tension_n;
00316 p->tension_n=p->tension_p;
00317 p->tension_p=t;
00318 }
00319 fp->next->next=NULL;
00320 fp->next=lp;
00321 lp->last=fp;
00322 }
00323 PathLength(op->firstpathpoint,op->pathtype,op->npathpoints);
00324 }
00325
00326
00327 double PathLength(pathpoint *Ppp, short type, short Npoints){
00328 pathpoint *tp,*fp,*fp1,*lp,*lp1;
00329 double length;
00330 point Vpp,Vpn,Vpnn;
00331 Ni=10; dtau=0.1; length = 0.0;
00332 fp=Ppp;
00333 if((tp=fp) != NULL){
00334 while(tp != NULL){lp=tp; tp=tp->next;}
00335 fp1=fp->next;
00336 lp1=lp->last;
00337 if(lp == NULL || fp1 == NULL || lp1 == NULL){
00338 SendPrgmQuery(IDQ_CATAF,0);
00339 exit(0);
00340 }
00341 if(type == OPEN){
00342 SubPoints(fp1->p,fp->p,Vpp);
00343 SubPoints(fp->p,Vpp,Vpp);
00344 SubPoints(lp->p,lp1->p,Vpnn);
00345 AddPoints(lp->p,Vpnn,Vpn);
00346 }
00347 tp=fp; while(tp != NULL){
00348 tp->distance=length;
00349 if(type == OPEN){
00350 if(tp == fp && fp1->next == NULL)
00351 length += SegmentLength(Vpp,fp->p,fp1->p,Vpn,
00352 fp->tension_n,fp1->tension_p);
00353 else if(tp == fp)
00354 length += SegmentLength(Vpp,fp->p,fp1->p,fp1->next->p,
00355 fp->tension_n,fp1->tension_p);
00356 else if(tp == lp1)
00357 length += SegmentLength(tp->last->p,tp->p,lp->p,Vpn,
00358 tp->tension_n,lp->tension_p);
00359 else if(tp == lp)
00360 ;
00361 else
00362 length += SegmentLength(tp->last->p,tp->p,
00363 tp->next->p,tp->next->next->p,
00364 tp->tension_n,tp->next->tension_p);
00365 }
00366 else{
00367 if(tp == fp)
00368 length += SegmentLength(lp->p,fp->p,fp1->p,fp1->next->p,
00369 fp->tension_n,fp1->tension_p);
00370 else if(tp == lp1)
00371 length += SegmentLength(tp->last->p,tp->p,lp->p,fp->p,
00372 tp->tension_n,lp->tension_p);
00373 else if(tp == lp)
00374 length += SegmentLength(lp1->p,lp->p,fp->p,fp1->p,
00375 lp->tension_n,fp->tension_p);
00376 else
00377 length += SegmentLength(tp->last->p,tp->p,
00378 tp->next->p,tp->next->next->p,
00379 tp->tension_n,tp->next->tension_p);
00380 }
00381 tp=tp->next;}
00382 }
00383
00384 return length;
00385 }
00386
00387
00388 #define TAUTOL 64.0
00389 #define TAUITR 50
00390 #define TAUN 10
00391
00392 void PathInterp(double pathposition, pathpoint *Lpp,
00393 pathpoint *Ppp, point ObjectOffset,
00394 double distance, pathpoint *Fpp,
00395 pathpoint *Epp, short type){
00396 long nc,j;
00397 double d,tau,taul,taur,taux,kx[4],ky[4],kz[4],x,y,z,xl,yl,zl;
00398 double gs,ge;
00399 pathpoint *p1,*p2,*p3,*p4;
00400 pathpoint Vpp,Vpn,Vpnn;
00401 p2=Lpp; p3=Ppp;
00402 if(type == OPEN){
00403 SubPoints(Fpp->next->p,Fpp->p,Vpp.p);
00404 SubPoints(Fpp->p,Vpp.p,Vpp.p);
00405 SubPoints(Epp->p,Epp->last->p,Vpnn.p);
00406 AddPoints(Epp->p,Vpnn.p,Vpn.p);
00407 if (Lpp == Fpp && Ppp->next == NULL){p1=&Vpp; p4=&Vpn;}
00408 else if(Lpp == Fpp) {p1=&Vpp; p4=Ppp->next;}
00409 else if(Lpp == Epp->last) {p1=Lpp->last; p4=&Vpn;}
00410 else {p1=Lpp->last; p4=Ppp->next;}
00411 }
00412 else{
00413 if (Lpp == Fpp) {p1=Epp; p4=Ppp->next;}
00414 else if(Lpp == Epp->last){p1=Lpp->last; p4=Fpp;}
00415 else {p1=Lpp->last; p4=Ppp->next;}
00416 }
00417 gs=(double)(p3->p[0]-p1->p[0])*p2->tension_n;
00418 ge=(double)(p4->p[0]-p2->p[0])*p3->tension_p;
00419 SplinesG(kx,p2->p[0],p3->p[0],gs,ge);
00420 gs=(double)(p3->p[1]-p1->p[1])*p2->tension_n;
00421 ge=(double)(p4->p[1]-p2->p[1])*p3->tension_p;
00422 SplinesG(ky,p2->p[1],p3->p[1],gs,ge);
00423 gs=(double)(p3->p[2]-p1->p[2])*p2->tension_n;
00424 ge=(double)(p4->p[2]-p2->p[2])*p3->tension_p;
00425 SplinesG(kz,p2->p[2],p3->p[2],gs,ge);
00426
00427
00428
00429 taul=0.0; taur=1.0; nc=0;
00430 tau=pathposition - Lpp->distance;
00431 tau /= (distance - Lpp->distance);
00432
00433
00434 for(;;){
00435 dtau=tau/TAUN; d=Lpp->distance; taux=dtau;
00436 xl=Lpp->p[0]; yl=Lpp->p[1]; zl=Lpp->p[2];
00437 for(j=0;j<TAUN;j++){
00438 x = SplinesP(kx,taux);
00439 y = SplinesP(ky,taux);
00440 z = SplinesP(kz,taux);
00441 d += sqrt((double)(x-xl)*(double)(x-xl)
00442 +(double)(y-yl)*(double)(y-yl)
00443 +(double)(z-zl)*(double)(z-zl) );
00444 taux += dtau;
00445 xl=x; yl=y; zl=z;
00446 }
00447
00448 if(fabs(d-pathposition) < TAUTOL)break;
00449 if(++nc > TAUITR)break;
00450 if(d < pathposition)taul=tau;
00451 else taur=tau;
00452 tau=0.5*(taul+taur);
00453 }
00454
00455 ObjectOffset[0] = SplinesP(kx,tau);
00456 ObjectOffset[1] = SplinesP(ky,tau);
00457 ObjectOffset[2] = SplinesP(kz,tau);
00458 }
00459
00460 void GetPathPositionAtDistance(node *Np, object *Op, double d, point pout){
00461
00462
00463 pathpoint *Ppp;
00464 short Npoints,type;
00465 pathpoint *tp,*fp,*fp1,*lp,*lp1;
00466 double length,dd;
00467 vector pos;
00468 point Vpp,Vpn,Vpnn;
00469 Ppp=Op->firstpathpoint;
00470 type=Op->pathtype;
00471 Npoints=Op->npathpoints;
00472
00473 Ni=200; dtau=0.005; length = 0.0;
00474 fp=Ppp;
00475 if((tp=fp) != NULL){
00476 while(tp != NULL){
00477 lp=tp; tp=tp->next;
00478 }
00479 fp1=fp->next;
00480 lp1=lp->last;
00481 if(lp == NULL || fp1 == NULL || lp1 == NULL){
00482 SendPrgmQuery(IDQ_CATAF,0);
00483 exit(0);
00484 }
00485 if(type == OPEN){
00486 SubPoints(fp1->p,fp->p,Vpp);
00487 SubPoints(fp->p,Vpp,Vpp);
00488 SubPoints(lp->p,lp1->p,Vpnn);
00489 AddPoints(lp->p,Vpnn,Vpn);
00490 }
00491 tp=fp; while(tp != NULL){
00492 if(type == OPEN){
00493 if(tp == fp && fp1->next == NULL){
00494 dd = GetSegmentPositionForLength(Vpp,fp->p,fp1->p,Vpn,
00495 fp->tension_n,fp1->tension_p,d-length,pos);
00496 if(dd < 0.0)goto GOTIT;
00497 else length += dd;
00498 }
00499 else if(tp == fp){
00500 dd = GetSegmentPositionForLength(Vpp,fp->p,fp1->p,fp1->next->p,
00501 fp->tension_n,fp1->tension_p,d-length,pos);
00502 if(dd < 0.0)goto GOTIT;
00503 else length += dd;
00504 }
00505 else if(tp == lp1){
00506 dd = GetSegmentPositionForLength(tp->last->p,tp->p,lp->p,Vpn,
00507 tp->tension_n,lp->tension_p,d-length,pos);
00508 if(dd < 0.0)goto GOTIT;
00509 else length += dd;
00510 }
00511 else if(tp == lp)
00512 ;
00513 else {
00514 dd = GetSegmentPositionForLength(tp->last->p,tp->p,
00515 tp->next->p,tp->next->next->p,
00516 tp->tension_n,tp->next->tension_p,d-length,pos);
00517 if(dd < 0.0)goto GOTIT;
00518 else length += dd;
00519 }
00520 }
00521 else{
00522 if(tp == fp){
00523 dd = GetSegmentPositionForLength(lp->p,fp->p,fp1->p,fp1->next->p,
00524 fp->tension_n,fp1->tension_p,d-length,pos);
00525 if(dd < 0.0)goto GOTIT;
00526 else length += dd;
00527 }
00528 else if(tp == lp1){
00529 dd = GetSegmentPositionForLength(tp->last->p,tp->p,lp->p,fp->p,
00530 tp->tension_n,lp->tension_p,d-length,pos);
00531 if(dd < 0.0)goto GOTIT;
00532 else length += dd;
00533 }
00534 else if(tp == lp){
00535 dd = GetSegmentPositionForLength(lp1->p,lp->p,fp->p,fp1->p,
00536 lp->tension_n,fp->tension_p,d-length,pos);
00537 if(dd < 0.0)goto GOTIT;
00538 else length += dd;
00539 }
00540 else {
00541 dd = GetSegmentPositionForLength(tp->last->p,tp->p,
00542 tp->next->p,tp->next->next->p,
00543 tp->tension_n,tp->next->tension_p,d-length,pos);
00544 if(dd < 0.0)goto GOTIT;
00545 else length += dd;
00546 }
00547 }
00548 tp=tp->next;
00549 }
00550
00551 VECCOPY(lp->p,pout)
00552 return;
00553 GOTIT:
00554 VECCOPY((long)pos,pout)
00555 return;
00556 }
00557 pout[0]=pout[1]=pout[2]=0;
00558 }
00559
00560 object *GetPathPosition(node *Np, long frame, double dframe,
00561 point ObjectOffset,
00562 double *position0_1, double *lengthonpath){
00563 object *Op;
00564 pathpoint *Ppp,*Lpp,*Fpp,*Epp;
00565 double pathposition;
00566 if((Op=Np->fobj) != NULL && Op->type == PATH)while(Op != NULL){
00567 if(frame >= Op->firstframe && frame <= Op->lastframe){
00568 if((Ppp=Op->firstpathpoint) == NULL)return NULL;
00569 if(Op->firstframe == Op->lastframe){
00570 CopyPoint(Op->firstpathpoint->p,ObjectOffset);
00571 }
00572 else{
00573 if(*position0_1 < 0.0){
00574 if(Op->v != NULL){
00575 long ip;
00576 ip=frame - Op->firstframe;
00577 if(ip > 0){
00578 *position0_1=(Op->v[ip])*dframe+(Op->v[ip-1])*(1.0-dframe);
00579 }
00580 else *position0_1=(Op->v[ip]);
00581 }
00582 else *position0_1=0.0;
00583 }
00584 pathposition = *position0_1 * Op->pathlength;
00585 if(pathposition == 0.0){
00586 CopyPoint(Op->firstpathpoint->p,ObjectOffset);
00587 }
00588 else{
00589 Fpp=Epp=Lpp=Ppp;
00590 while(Lpp != NULL){Epp=Lpp; Lpp=Lpp->next;}
00591 Lpp=Ppp; Ppp=Ppp->next;
00592 while(Ppp != NULL && pathposition >= Ppp->distance){
00593 Lpp=Ppp; Ppp=Ppp->next;}
00594 if(Ppp == NULL){
00595 if(Op->pathtype == CLOSED)
00596 PathInterp(pathposition,Lpp,Op->firstpathpoint,ObjectOffset
00597 ,Op->pathlength,Fpp,Epp,Op->pathtype);
00598 else
00599 CopyPoint(Lpp->p,ObjectOffset);
00600 }
00601 else{
00602 PathInterp(pathposition,Lpp,Ppp,ObjectOffset
00603 ,Ppp->distance,Fpp,Epp,Op->pathtype);
00604 }
00605 }
00606
00607
00608 }
00609 *lengthonpath=pathposition;
00610 return Op;
00611 }
00612 Op=Op->next;
00613 }
00614 return NULL;
00615 }
00616
00617 double *ReTweenVelocity(object *op, double *v,
00618 int oldn, int newn,
00619 double pathlength,
00620 int copy){
00621 double *nv,Xscale,error,ds;
00622 short i,j,lf,lc;
00623 PATHEDITCONTROL *pe,*pe1;
00624 if(v != NULL && oldn == newn && copy == 0)return v;
00625 if( (nv=(double *)X__Malloc(sizeof(double)*newn) ) == NULL){
00626 SendPrgmQuery(IDQ_NOMEM1,0);
00627 return NULL;
00628 }
00629 if((pe=op->pec) != NULL)while(pe != NULL){
00630 pe1=pe;
00631 pe=pe->next;
00632 X__Free(pe1);
00633 }
00634 op->pec=NULL; op->npec=0;
00635 if(v == NULL){
00636 ds=1.0/(double)newn;
00637 for(i=0;i<newn;i++)nv[i]=ds*i;
00638 }
00639 else if(newn == oldn){
00640 for(i=0;i<newn;i++)nv[i]=v[i];
00641 if(copy == 0)X__Free(v);
00642 }
00643 else{
00644 if(oldn < 0){
00645 ds=1.0/(double)newn;
00646 for(i=0;i<newn;i++)nv[i]=ds*i;
00647 }
00648 else if(oldn <= 1){
00649 Xscale=1.0/newn;
00650 for(i=0;i<newn;i++){
00651 nv[i]=(double)i*Xscale;
00652 }
00653 }
00654 else{
00655 Xscale=(double)(oldn-1)/(double)(newn-1);
00656 for(i=0;i<newn;i++){
00657 j=floor(Xscale*i);
00658 error=Xscale*i - j;
00659 if(error < 0.001 || j == oldn-1)nv[i] = v[j];
00660 else nv[i] = (v[j+1]-v[j])*error+v[j];
00661 }
00662 }
00663 if(copy == 0)X__Free(v);
00664 }
00665 return nv;
00666 }
00667
00668 #define XFROMFRAME(f) ((int)( \
00669 (double)(f-SelectedPath->firstframe)*(double)(CurveRect.right-1)/ \
00670 (double)(SelectedPath->lastframe-SelectedPath->firstframe) \
00671 ))
00672 #define YFROMDIST(d) (CurveRect.bottom-1-(int)( \
00673 d*(double)(CurveRect.bottom-1)/1.0 \
00674 ))
00675 #define FRAMEFROMX(x) ((int)( \
00676 (double)SelectedPath->firstframe+(double)x* \
00677 (double)(SelectedPath->lastframe-SelectedPath->firstframe)/ \
00678 (double)(CurveRect.right-1) \
00679 ))
00680 #define DISTFROMY(y) ((double)( \
00681 (double)(CurveRect.bottom-1-y)/ \
00682 (double)(CurveRect.bottom-1) \
00683 ))
00684 #define TOLL (CurveRect.right/30)
00685
00686 static HWND hPathEditorFrameID,hPathEditorDistanceID;
00687 static RECT CurveRect;
00688 static BOOL RingScale=FALSE;
00689 static int nPec=0;
00690 static PATHEDITCONTROL *Pec=NULL;
00691
00692 static BOOL CALLBACK PathPositionEditorDlgProc(HWND hwnd, UINT msg,
00693 WPARAM wparam, LPARAM lparam){
00694 static HWND hWndStatus;
00695 static int cx,cy,ox,oy;
00696 HWND hctl;
00697 int tx,ty;
00698 RECT wRect;
00699 LPRECT lpRect;
00700 PATHEDITCONTROL *pe;
00701 switch( msg ) {
00702 case WM_INITDIALOG:
00703 SetClassLong(hwnd,GCL_HICON,
00704 (LONG)LoadIcon(ghinst_main,"ANIMATORICON"));
00705 hPathEditorFrameID=GetDlgItem(hwnd,DLG_PATHEDITOR_FRAME);
00706 hPathEditorDistanceID=GetDlgItem(hwnd,DLG_PATHEDITOR_DISTANCE);
00707 pe=Pec; while(pe != NULL){
00708 pe->x=XFROMFRAME(pe->frame);
00709 pe->y=YFROMDIST(pe->distance);
00710 pe=pe->next;
00711 }
00712 if(RingScale)SendDlgItemMessage(hwnd,DLG_PATHEDITOR_LOOP,BM_SETCHECK,TRUE,0);
00713 SetDlgItemInt(hwnd,DLG_PATHEDITOR_FRAME1,SelectedPath->firstframe,TRUE);
00714 SetDlgItemInt(hwnd,DLG_PATHEDITOR_FRAMEN,SelectedPath->lastframe,TRUE);
00715 hWndStatus=CreateWindowEx(0L,STATUSCLASSNAME,"",
00716 WS_CHILD | !WS_BORDER | WS_VISIBLE,
00717 0,0,0,0,
00718 hwnd,
00719 (HMENU)NULL,
00720 (HINSTANCE)NULL,
00721 NULL);
00722 SendMessage(hWndStatus,SB_SETTEXT,(WPARAM)SBT_NOBORDERS,(LPARAM)NULL);
00723
00724 GetWindowRect(hwnd,&wRect);
00725 ox=wRect.right-wRect.left;
00726 oy=wRect.bottom-wRect.top;
00727 GetClientRect(hwnd,&wRect);
00728 cx=wRect.right;
00729 cy=wRect.bottom;
00730 PostMessage(hwnd,(WM_USER+100),0,0);
00731 return (TRUE);
00732 case (WM_USER+100):{
00733 int xp,yp,xl,yl;
00734 xp=GetPrivateProfileInt(IniSection,"PEPOSX",-1,IniFilename);
00735 yp=GetPrivateProfileInt(IniSection,"PEPOSY",-1,IniFilename);
00736 xl=GetPrivateProfileInt(IniSection,"PESIZX",-1,IniFilename);
00737 yl=GetPrivateProfileInt(IniSection,"PESIZY",-1,IniFilename);
00738 if(xp < 0 || yp < 0 || xl < 0 || yl < 0)CentreDialogOnScreen(hwnd);
00739 else SetWindowPos(hwnd,NULL,xp,yp,xl,yl,SWP_NOZORDER);
00740 ShowWindow(hwnd,SW_SHOW);
00741 }
00742 break;
00743 case WM_DESTROY:{
00744 RECT rc; char str[32];
00745 GetWindowRect(hwnd,&rc);
00746 sprintf(str,"%ld",rc.left);
00747 WritePrivateProfileString(IniSection,"PEPOSX",str,IniFilename);
00748 sprintf(str,"%ld",rc.top);
00749 WritePrivateProfileString(IniSection,"PEPOSY",str,IniFilename);
00750 sprintf(str,"%ld",rc.right-rc.left);
00751 WritePrivateProfileString(IniSection,"PESIZX",str,IniFilename);
00752 sprintf(str,"%ld",rc.bottom-rc.top);
00753 WritePrivateProfileString(IniSection,"PESIZY",str,IniFilename);
00754 }
00755 break;
00756 case WM_MOUSEMOVE:
00757 SendMessage(hPathEditorFrameID,WM_SETTEXT,0,(LPARAM)" ");
00758 SendMessage(hPathEditorDistanceID,WM_SETTEXT,0,(LPARAM)" ");
00759 break;
00760 case WM_SIZING:
00761 lpRect=(LPRECT)lparam;
00762 if((lpRect->right - lpRect->left) < ox)
00763 lpRect->right = lpRect->left+ox;
00764 if((lpRect->bottom - lpRect->top) < oy)
00765 lpRect->bottom = lpRect->top+oy;
00766 return TRUE;
00767 break;
00768 case WM_SIZE:
00769 SendMessage(hWndStatus,WM_SIZE,wparam,lparam);
00770 tx=LOWORD(lparam); ty=HIWORD(lparam);
00771 MoveCtrlWindow(hwnd,IDCANCEL,tx,ty,cx,cy,1);
00772 MoveCtrlWindow(hwnd,IDOK,tx,ty,cx,cy,1);
00773 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_FRAME,tx,ty,cx,cy,1);
00774 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_DISTANCE,tx,ty,cx,cy,1);
00775 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_DISTANCETEXT,tx,ty,cx,cy,1);
00776 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_FRAMETEXT,tx,ty,cx,cy,1);
00777 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_HELPTEXT,tx,ty,cx,cy,1);
00778 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_LOOP,tx,ty,cx,cy,1);
00779
00780 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_STARTTEXT,tx,ty,cx,cy,2);
00781 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_FRAMESTEXT,tx,ty,cx,cy,2);
00782 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_FRAME1,tx,ty,cx,cy,2);
00783 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_FRAMEN,tx,ty,cx,cy,1);
00784 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_FRAMEN,tx,ty,cx,cy,2);
00785
00786 MoveCtrlWindow(hwnd,DLG_PATHEDITOR_EDITWINDOW,tx,ty,cx,cy,0);
00787 GetClientRect(GetDlgItem(hwnd,DLG_PATHEDITOR_EDITWINDOW),&CurveRect);
00788 pe=Pec; while(pe != NULL){
00789 pe->x=XFROMFRAME(pe->frame);
00790 pe->y=YFROMDIST(pe->distance);
00791 pe=pe->next;
00792 }
00793
00794 InvalidateRect(hwnd,NULL,TRUE);
00795 cx=tx; cy=ty;
00796 break;
00797 case WM_COMMAND:
00798 switch(LOWORD(wparam)){
00799 case DLG_PATHEDITOR_LOOP:
00800 RingScale = !RingScale;
00801 break;
00802 case IDCANCEL:
00803 EndDialog(hwnd, FAIL);
00804 return(TRUE);
00805 case IDOK:
00806 EndDialog(hwnd,OK);
00807 return(TRUE);
00808 default:
00809 break;
00810 }
00811 break;
00812 default: break;
00813 }
00814 return(FALSE);
00815 }
00816
00817 static LRESULT CALLBACK PathEditorWndFn(HWND hWnd,UINT uMsg,WPARAM wParam,
00818 LPARAM lParam){
00819 HDC hDC;
00820 RECT rc;
00821 PAINTSTRUCT ps;
00822 short x,y;
00823 int f;
00824 static int xl,xr;
00825 double d;
00826 char temp[64];
00827 BOOL bOutside;
00828 PATHEDITCONTROL *pf,*pl,*p;
00829 static PATHEDITCONTROL *pe;
00830 static BOOL bCaptured=FALSE,bDeleted=FALSE;
00831 switch (uMsg) {
00832 case WM_CREATE:
00833 pe=NULL;
00834 GetClientRect(hWnd,&CurveRect);
00835 break;
00836 case WM_PAINT:
00837 hDC = BeginPaint(hWnd,&ps);
00838 Rectangle(hDC,CurveRect.left,CurveRect.top
00839 ,CurveRect.right,CurveRect.bottom);
00840 DrawPathCurve(hDC);
00841 EndPaint(hWnd, &ps);
00842 break;
00843 case WM_LBUTTONDOWN:
00844 x=(short)LOWORD(lParam); y=(short)HIWORD(lParam);
00845 x=max(0,min(CurveRect.right-1,x));
00846 y=max(0,min(CurveRect.bottom-1,y));
00847 f=FRAMEFROMX(x);
00848 d=DISTFROMY(y);
00849 sprintf(temp,"%ld",f);
00850 SendMessage(hPathEditorFrameID,WM_SETTEXT,0,(LPARAM)temp);
00851 sprintf(temp,"%ld",(int)(d*100.0+0.0001));
00852 SendMessage(hPathEditorDistanceID,WM_SETTEXT,0,(LPARAM)temp);
00853 SetCapture(hWnd);
00854 pe=GetPathEditPoint((int)x,(int)y);
00855 if(pe != NULL){
00856 if(pe->last != NULL)x=max(pe->last->x+TOLL,x);
00857 if(pe->next != NULL)x=min(pe->next->x-TOLL,x);
00858 pe->x=x; pe->y=y;
00859 }
00860 InvalidateRect(hWnd,NULL,FALSE);
00861 bCaptured=TRUE;
00862 bDeleted=FALSE;
00863 break;
00864 case WM_LBUTTONUP:
00865 if(pe != NULL){
00866 pe->frame=FRAMEFROMX(pe->x);
00867 pe->distance=DISTFROMY(pe->y);
00868 }
00869 pe=NULL;
00870 ReleaseCapture();
00871 bCaptured=FALSE;
00872 bDeleted=FALSE;
00873 break;
00874 case WM_MOUSEMOVE:
00875 x=(short)LOWORD(lParam); y=(short)HIWORD(lParam);
00876 if(x < 0 || x > CurveRect.right-1 ||
00877 y < 0 || y > CurveRect.bottom-1)bOutside=TRUE;
00878 else bOutside=FALSE;
00879 x=max(0,min(CurveRect.right-1,x));
00880 y=max(0,min(CurveRect.bottom-1,y));
00881 f=FRAMEFROMX(x);
00882 d=DISTFROMY(y);
00883 sprintf(temp,"%ld",f);
00884 SendMessage(hPathEditorFrameID,WM_SETTEXT,0,(LPARAM)temp);
00885 sprintf(temp,"%ld",(int)(d*100.0+0.0001));
00886 SendMessage(hPathEditorDistanceID,WM_SETTEXT,0,(LPARAM)temp);
00887 if(bCaptured){
00888 if(pe != NULL){
00889 pf=p=Pec; while(p != NULL){pl=p; p=p->next;}
00890 if(pf == NULL || pl == NULL)break;
00891 if(pe == pf || pe == pl){
00892 if(pe->last != NULL)x=max(pe->last->x+TOLL,x);
00893 if(pe->next != NULL)x=min(pe->next->x-TOLL,x);
00894 pe->x=x; pe->y=y;
00895 }
00896 else{
00897 if(pe->last == NULL || pe->next == NULL)break;
00898 d=abs(pe->x - pe->last->x);
00899 if(d < abs(pe->x - pe->next->x))p=pe->last;
00900 else p=pe->next;
00901 if(pe->x <= pe->last->x || pe->x >= pe->next->x)bOutside=TRUE;
00902 if(abs(p->x - pe->x) < TOLL || bOutside){
00903 xl=pe->last->x + TOLL; xr=pe->next->x - TOLL;
00904 bDeleted=TRUE;
00905 DeletePathEditControlPoint(&nPec,&Pec,pe);
00906 pe=NULL;
00907 }
00908 else{
00909 pe->x=x; pe->y=y;
00910 }
00911 }
00912 InvalidateRect(hWnd,NULL,FALSE);
00913 }
00914 else if(bDeleted){
00915 if(x > xl && x < xr && !bOutside){
00916 pe=GetPathEditPoint((int)x,(int)y);
00917 if(pe != NULL){
00918 if(pe->last != NULL)x=max(pe->last->x+TOLL,x);
00919 if(pe->next != NULL)x=min(pe->next->x-TOLL,x);
00920 pe->x=x; pe->y=y;
00921 }
00922 bDeleted=FALSE;
00923 InvalidateRect(hWnd,NULL,FALSE);
00924 }
00925 }
00926 }
00927 break;
00928 default:
00929 return(DefWindowProc(hWnd,uMsg,wParam,lParam));
00930 }
00931 return( 0L );
00932 }
00933
00934 void EditPathMovement(short type){
00935 long Npp;
00936 object *Op;
00937 char _szControlName[] = "OFX:PATHEDITORCLASS";
00938 PATHEDITCONTROL *pe,*pe1;
00939 WNDCLASS wc;
00940 if(SelectedNode == NULL){
00941 SendPrgmQuery(IDQ_NOACTORSELECTED,0);
00942 return;
00943 }
00944 if(tool != NOTOOL){
00945 SendPrgmQuery(IDQ_NOT_IN_TOOL,0);
00946 return;
00947 }
00948 if(SelectedNode->type != PATH){
00949 SendPrgmQuery(IDQ_NOPATH,0);
00950 return;
00951 }
00952 EDIT_ACTION=YES;
00953 Op=SelectedNode->fobj;
00954 while(Op != NULL){
00955 if(CurrentFrame >= Op->firstframe && CurrentFrame <= Op->lastframe){
00956 SelectedPath=Op;
00957 goto GOTIT;
00958 }
00959 Op=Op->next;
00960 }
00961 SendPrgmQuery(IDQ_NOPATH,0);
00962 return;
00963 GOTIT:
00964 Npp=SelectedPath->lastframe - SelectedPath->firstframe + 1;
00965 if(Npp < 5){
00966 SendPrgmQuery(IDQ_PATH2,0);
00967 SelectedPath=NULL;
00968 return;
00969 }
00970 wc.style = CS_HREDRAW | CS_VREDRAW;
00971 wc.lpfnWndProc = (WNDPROC)PathEditorWndFn;
00972 wc.cbClsExtra = 0;
00973 wc.cbWndExtra = 0;
00974 wc.hInstance = ghinst_main;
00975 wc.hIcon = (HICON) NULL;
00976 wc.hCursor = ghcurX;
00977 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
00978 wc.lpszMenuName = NULL;
00979 wc.lpszClassName = _szControlName;
00980 CurveRect.top=CurveRect.bottom=CurveRect.left=CurveRect.right=0;
00981 if(!RegisterClass(&wc)){
00982 SendPrgmQuery(IDQ_NOPATH,0);
00983 return;
00984 }
00985 nPec=0;
00986 Pec=NULL;
00987 if(SelectedPath->pathtype == CLOSED)RingScale=TRUE;
00988 else RingScale=FALSE;
00989 if(SelectedPath->pec != NULL && SelectedPath->npec > 0){
00990 pe1=NULL; pe=SelectedPath->pec; while(pe != NULL){
00991 pe1=CreatePathEditControlPoint(&nPec,&Pec,pe1,NULL,pe->frame,pe->distance);
00992 if(Pec == NULL){ SendPrgmQuery(IDQ_NOMEM1,0); return; }
00993 pe=pe->next;
00994 }
00995 }
00996 else {
00997 CreatePathEditControlPoint(&nPec,&Pec,NULL,NULL,
00998 (int)SelectedPath->firstframe,0.0);
00999 if(Pec == NULL){ SendPrgmQuery(IDQ_NOMEM1,0); return; }
01000 CreatePathEditControlPoint(&nPec,&Pec,Pec,NULL,
01001 (int)SelectedPath->lastframe,1.0);
01002 if(Pec == NULL){ SendPrgmQuery(IDQ_NOMEM1,0); return; }
01003 }
01004 EnableToolPannels(ALL_PANNELS,FALSE);
01005 if(DialogBox(ghinst_main,MAKEINTRESOURCE(DLG_PATHEDITOR),ghwnd_main,
01006 (DLGPROC)PathPositionEditorDlgProc) == OK){
01007 if((pe=SelectedPath->pec) != NULL)while(pe != NULL){
01008 pe1=pe; pe=pe->next; X__Free(pe1);
01009 }
01010 SelectedPath->pec=NULL; SelectedPath->npec=0;
01011 pe1=NULL; if((pe=Pec) != NULL)while(pe != NULL){
01012 pe1=CreatePathEditControlPoint(&(SelectedPath->npec),
01013 &(SelectedPath->pec),
01014 pe1,NULL,pe->frame,pe->distance);
01015 if(SelectedPath->pec == NULL){
01016 SendPrgmQuery(IDQ_NOMEM1,0);
01017 return;
01018 }
01019 pe=pe->next;
01020 }
01021 CalculatePathPositions(SelectedPath);
01022 }
01023 EnableToolPannels(ALL_PANNELS,TRUE);
01024 if((pe=Pec) != NULL)while(pe != NULL){
01025 pe1=pe; pe=pe->next; X__Free(pe1);
01026 }
01027 UnregisterClass(_szControlName,ghinst_main);
01028 return;
01029 }
01030
01031 static PATHEDITCONTROL *GetPathEditPoint(int x, int y){
01032 int d;
01033 PATHEDITCONTROL *pe,*pf,*pl;
01034 pf=pl=NULL;
01035 pf=pe=Pec; while(pe != NULL){pl=pe; pe=pe->next;}
01036 if(pf == NULL || pl == NULL)return NULL;
01037 if(x < pf->x + TOLL){
01038 if(pf->next != NULL){
01039 d=abs(x - pf->x);
01040 if(abs(x - pf->next->x) < d)return pf->next;
01041 else return pf;
01042 }
01043 return pf;
01044 }
01045 if(x > pl->x - TOLL){
01046 if(pl->last != NULL){
01047 d=abs(x - pl->x);
01048 if(abs(x - pl->last->x) < d)return pl->last;
01049 else return pl;
01050 }
01051 return pl;
01052 }
01053 pf=NULL; d=10000;
01054 pe=Pec; while(pe != NULL){
01055 if(x > pe->x - TOLL && x < pe->x + TOLL){
01056 if(abs(x - pe->x) < d){
01057 d=abs(x - pe->x);
01058 pf=pe;
01059 }
01060 }
01061 pe=pe->next;
01062 }
01063 if(pf != NULL)return pf;
01064 pe=Pec; while(pe != NULL){
01065 if(pe->next != NULL){
01066 if(x > pe->x && x < pe->next->x){
01067 return CreatePathEditControlPoint(&nPec,&Pec,pe,pe->next,0,0.0);
01068 }
01069 }
01070 pe=pe->next;
01071 }
01072 return NULL;
01073 }
01074
01075 static void DrawLagrangePathCurve(HDC hDC){
01076 int i,j;
01077 HBRUSH holdBrush;
01078 PATHEDITCONTROL *pe,*pf,*pl,*p,*p1,*p2;
01079 double x,y;
01080 holdBrush=SelectObject(hDC,GetStockObject(BLACK_BRUSH));
01081 p=pf=pe=Pec; while(pe != NULL){pl=pe; pe=pe->next;}
01082 if(pf->x > 0){
01083 MoveToEx(hDC,0,pf->y,NULL); LineTo(hDC,pf->x,pf->y);
01084 }
01085 for(i=pf->x;i<=pl->x;i++){
01086 if(p != NULL && p->x == i){
01087 Rectangle(hDC,min(p->x-2,CurveRect.right-4),
01088 min(p->y-2,CurveRect.bottom-4),
01089 max(p->x+2,4),
01090 max(p->y+2,4));
01091 p=p->next;
01092 }
01093 y=0.0;
01094 p1=Pec; while(p1 != NULL){
01095 x=1.0;
01096 p2=Pec; while (p2 != NULL){
01097 if(p2 != p1){
01098 x *= (double)(i - p2->x)/(double)(p1->x - p2->x);
01099 }
01100 p2=p2->next;
01101 }
01102 y += x*(double)p1->y;
01103 p1=p1->next;
01104 }
01105 j=(int)y;
01106 if(j < 1)j=1; if(j >= CurveRect.bottom-1)j=CurveRect.bottom-2;
01107 SetPixel(hDC,i,j,RGB(0,0,0));
01108 }
01109 if(pl->x < CurveRect.right-1){
01110 MoveToEx(hDC,pl->x,pl->y,NULL); LineTo(hDC,CurveRect.right-1,pl->y);
01111 }
01112 SelectObject(hDC,holdBrush);
01113 }
01114
01115 static void DrawPathCurve(HDC hDC){
01116 int i,j;
01117 HBRUSH holdBrush;
01118 PATHEDITCONTROL *pe,*pf,*pl;
01119 double x,y,a,b,c,d,h1,h2,ratio;
01120 if(nPec < 4){
01121 DrawLagrangePathCurve(hDC);
01122 return;
01123 }
01124 holdBrush=SelectObject(hDC,GetStockObject(BLACK_BRUSH));
01125 pf=pe=Pec; while(pe != NULL){pl=pe; pe=pe->next;}
01126 pe=pf; while(pe != NULL){
01127 pe->a=pe->b=pe->c=pe->S=pe->r=0.0;
01128 pe=pe->next;
01129 }
01130 pe=pf->next; while(pe != pl){
01131 h1=(double)(pe->x - pe->last->x);
01132 h2=(double)(pe->next->x - pe->x);
01133 pe->a=h1; pe->b=2.0*(h1+h2); pe->c=h2;
01134 pe->r=(double)(pe->next->y - pe->y)/h2
01135 -(double)(pe->y - pe->last->y)/h1;
01136 pe->r *= 6.0;
01137 pe=pe->next;
01138 }
01139 pf->next->a=0.0; pl->last->c=0.0;
01140 pe=pf->next->next; while(pe != pl){
01141 ratio = pe->a/pe->last->b;
01142 pe->b = pe->b - pe->last->c * ratio;
01143 pe->r = pe->r - pe->last->r * ratio;
01144 pe=pe->next;
01145 }
01146 pl->last->S=pl->last->r/pl->last->b;
01147 pe=pl->last->last; while(pe != pf){
01148 pe->S=(pe->r - pe->next->S * pe->c)/pe->b;
01149 pe=pe->last;
01150 }
01151 pe=Pec; while(pe != NULL){
01152 if(pe->last == NULL && pe->x > 0){
01153 MoveToEx(hDC,0,pe->y,NULL); LineTo(hDC,pe->x,pe->y);
01154 }
01155 Rectangle(hDC,min(pe->x-2,CurveRect.right-4),
01156 min(pe->y-2,CurveRect.bottom-4),
01157 max(pe->x+2,4),
01158 max(pe->y+2,4));
01159 if(pe->next != NULL){
01160 h1=(double)(pe->next->x - pe->x);
01161 a=(pe->next->S - pe->S)/6.0/h1;
01162 b=pe->S/2.0;
01163 c=(double)(pe->next->y - pe->y)/h1 - (2.0*pe->S + pe->next->S)*h1/6.0;
01164 d=(double)pe->y;
01165 for(i=pe->x; i<pe->next->x;i++){
01166 x=(double)(i - pe->x) + 0.5;
01167 y=(x*(x*(x*a+b)+c))+d;
01168 j=(int)y;
01169 if(j < 1)j=1; if(j >= CurveRect.bottom-1)j=CurveRect.bottom-2;
01170 SetPixel(hDC,i,j,RGB(0,0,0));
01171 }
01172 }
01173 pe=pe->next;
01174 }
01175 if(pl->x < CurveRect.right-1){
01176 MoveToEx(hDC,pl->x,pl->y,NULL); LineTo(hDC,CurveRect.right-1,pl->y);
01177 }
01178 SelectObject(hDC,holdBrush);
01179 }
01180
01181 static void CalculatePathPositions(object *op){
01182 int i,j;
01183 PATHEDITCONTROL *pe,*pf,*pl;
01184 double x,y,a,b,c,d,h1,h2,ratio;
01185 if(nPec < 4){
01186 PATHEDITCONTROL *p1,*p2;
01187 pf=pe=Pec; while(pe != NULL){pl=pe; pe=pe->next;}
01188 if(pf->frame > op->firstframe){
01189 for(i=op->firstframe;i<pf->frame;i++){
01190 op->v[i - op->firstframe]=pf->distance;
01191 }
01192 }
01193 for(i=pf->frame;i<=pl->frame;i++){
01194 y=0.0;
01195 p1=Pec; while(p1 != NULL){
01196 x=1.0;
01197 p2=Pec; while (p2 != NULL){
01198 if(p2 != p1){
01199 x *= (double)(i - p2->frame)/(double)(p1->frame - p2->frame);
01200 }
01201 p2=p2->next;
01202 }
01203 y += x*(double)p1->distance;
01204 p1=p1->next;
01205 }
01206 y=min(1.0,max(0.0,y));
01207 op->v[i - op->firstframe]=y;
01208 }
01209 if(pl->frame < op->lastframe){
01210 for(i=pl->frame;i<=op->lastframe;i++){
01211 op->v[i - op->firstframe]=pl->distance;
01212 }
01213 }
01214 goto XXIT;
01215 }
01216 pf=pe=Pec; while(pe != NULL){pl=pe; pe=pe->next;}
01217 pe=pf; while(pe != NULL){
01218 pe->a=pe->b=pe->c=pe->S=pe->r=0.0;
01219 pe=pe->next;
01220 }
01221 pe=pf->next; while(pe != pl){
01222 h1=(double)(pe->frame - pe->last->frame);
01223 h2=(double)(pe->next->frame - pe->frame);
01224 pe->a=h1; pe->b=2.0*(h1+h2); pe->c=h2;
01225 pe->r=(double)(pe->next->distance - pe->distance)/h2
01226 -(double)(pe->distance - pe->last->distance)/h1;
01227 pe->r *= 6.0;
01228 pe=pe->next;
01229 }
01230 pf->next->a=0.0; pl->last->c=0.0;
01231 pe=pf->next->next; while(pe != pl){
01232 ratio = pe->a/pe->last->b;
01233 pe->b = pe->b - pe->last->c * ratio;
01234 pe->r = pe->r - pe->last->r * ratio;
01235 pe=pe->next;
01236 }
01237 pl->last->S=pl->last->r/pl->last->b;
01238 pe=pl->last->last; while(pe != pf){
01239 pe->S=(pe->r - pe->next->S * pe->c)/pe->b;
01240 pe=pe->last;
01241 }
01242 pe=Pec; while(pe != NULL){
01243 if(pe->last == NULL && pe->frame > op->firstframe){
01244 for(i=op->firstframe;i<pe->frame;i++){
01245 op->v[i - op->firstframe]=pe->distance;
01246 }
01247 }
01248 if(pe->next != NULL){
01249 h1=(double)(pe->next->frame - pe->frame);
01250 a=(pe->next->S - pe->S)/6.0/h1;
01251 b=pe->S/2.0;
01252 c=(double)(pe->next->distance - pe->distance)/h1
01253 - (2.0*pe->S + pe->next->S)*h1/6.0;
01254 d=(double)pe->distance;
01255 for(i=pe->frame; i < pe->next->frame; i++){
01256 x=(double)(i - pe->frame) + 0.5;
01257 y=(x*(x*(x*a+b)+c))+d;
01258 y=min(1.0,max(0.0,y));
01259 op->v[i - op->firstframe]=y;
01260 }
01261 }
01262 if(pe->next == NULL && pl->frame <= op->lastframe){
01263 for(i=pl->frame;i<=op->lastframe;i++){
01264 op->v[i - op->firstframe]=pl->distance;
01265 }
01266 }
01267 pe=pe->next;
01268 }
01269 XXIT:
01270 if(RingScale){
01271 j=op->lastframe - op->firstframe + 1;
01272 ratio = (double)j/(double)(j+1);
01273 for(i=0;i<j;i++){
01274 op->v[i] *= ratio;
01275 }
01276 }
01277 return;
01278 }
01279
01280
01281
01282
01283
01284
01285 #if 0
01286 static void DrawPathCurve(HDC hDC){
01287 int i,j,dx;
01288 HBRUSH holdBrush;
01289 PATHEDITCONTROL *pe;
01290 double a,b,c;
01291 holdBrush=SelectObject(hDC,GetStockObject(BLACK_BRUSH));
01292 pe=Pec; while(pe != NULL){
01293 if(pe->last == NULL && pe->x > 0){
01294 MoveToEx(hDC,0,pe->y,NULL); LineTo(hDC,pe->x,pe->y);
01295 }
01296 Rectangle(hDC,pe->x-2,pe->y-2,pe->x+2,pe->y+2);
01297 MoveToEx(hDC,pe->x,pe->y,NULL);
01298 if(pe->next == NULL){
01299 LineTo(hDC,CurveRect.right-1,pe->y);
01300 }
01301 else{
01302 if(pe->last == NULL && pe->next->next == NULL){
01303 LineTo(hDC,pe->next->x,pe->next->y);
01304 }
01305 else{
01306 for(i=pe->x;i<pe->next->x;i++){
01307 j=(int)GetYpathCoord(i,pe);
01308 SetPixel(hDC,i,j,RGB(0,0,0));
01309 }
01310 }
01311 }
01312 pe=pe->next;
01313 }
01314 SelectObject(hDC,holdBrush);
01315 }
01316 int GetYpathCoord(int ix, PATHEDITCONTROL *pe){
01317 int iy;
01318 double x,y,x1,x2,x3,x4,y1,y2,y3,y4;
01319 x=(double)ix;
01320 if(pe->next == NULL)return 0;
01321 if(pe->last == NULL){
01322 x1=(double)pe->x; y1=(double)pe->y;
01323 x2=(double)pe->next->x; y2=(double)pe->next->y;
01324 x3=(double)pe->next->next->x; y3=(double)pe->next->next->y;
01325 y=(x-x2)*(x-x3)*y1/((x1-x2)*(x1-x3))+
01326 (x-x3)*(x-x1)*y2/((x2-x1)*(x2-x3))+
01327 (x-x1)*(x-x2)*y3/((x3-x1)*(x3-x2));
01328 }
01329 else if(pe->next->next == NULL){
01330 x1=(double)pe->last->x; y1=(double)pe->last->y;
01331 x2=(double)pe->x; y2=(double)pe->y;
01332 x3=(double)pe->next->x; y3=(double)pe->next->y;
01333 y=(x-x2)*(x-x3)*y1/((x1-x2)*(x1-x3))+
01334 (x-x3)*(x-x1)*y2/((x2-x1)*(x2-x3))+
01335 (x-x1)*(x-x2)*y3/((x3-x1)*(x3-x2));
01336 }
01337 else{
01338 x1=(double)pe->last->x; y1=(double)pe->last->y;
01339 x2=(double)pe->x; y2=(double)pe->y;
01340 x3=(double)pe->next->x; y3=(double)pe->next->y;
01341 x4=(double)pe->next->next->x; y4=(double)pe->next->next->y;
01342 y=(x-x2)*(x-x3)*(x-x4)*y1/((x1-x2)*(x1-x3)*(x1-x4))+
01343 (x-x3)*(x-x4)*(x-x1)*y2/((x2-x1)*(x2-x3)*(x2-x4))+
01344 (x-x4)*(x-x1)*(x-x2)*y3/((x3-x1)*(x3-x2)*(x3-x4))+
01345 (x-x1)*(x-x2)*(x-x3)*y4/((x4-x1)*(x4-x2)*(x4-x3));
01346 }
01347 iy=(int)y;
01348 if(iy < 1)iy=1; if(iy >= CurveRect.bottom-1)iy=CurveRect.bottom-2;
01349 return iy;
01350 }
01351 #endif