PATHS.C

Go to the documentation of this file.
00001 /* file PATHS.C - Path functions */
00002 
00003 #define MODULE_PATH
00004 
00005 #include "animate.h"
00006 
00007 static short    Ni;
00008 static double dtau;    /* 1.0/Ni  */
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 //int GetYpathCoord(int x, PATHEDITCONTROL *pe);
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 //  SplinesK(kx,vl[0],v1[0],v2[0],vn[0]);
00109 //  SplinesK(ky,vl[1],v1[1],v2[1],vn[1]);
00110 //  SplinesK(kz,vl[2],v1[2],v2[2],vn[2]);
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{   /* draw the control point */
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 // if(View == TRIVIEW){ Ni= 5; dtau=0.2; }
00163 // else               { Ni=10; dtau=0.1; }
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  /* Vpp is extrapolated point before first Vpn is extrapolated after last */
00184  if(Op->pathtype == OPEN){ /* prepare extrapolation points from Vp[] */
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){ /* loop thru all points */
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{ /* closed path */
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; // we have exceeded the distance so 
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          ;/* no length calc necessary for last segment */
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{ /* closed path */
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 //if(debug != NULL)fprintf(debug,"path length %lf\n",length);
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, /* new iterative method */
00393                 pathpoint *Ppp, point ObjectOffset,  /* to try and smooth    */
00394                 double distance, pathpoint *Fpp,     /* jumps in movement    */
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;                     /* measured from start of path */
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 // SplinesK(kx,p1->p[0],p2->p[0],p3->p[0],p4->p[0]);
00427 // SplinesK(ky,p1->p[1],p2->p[1],p3->p[1],p4->p[1]);
00428 // SplinesK(kz,p1->p[2],p2->p[2],p3->p[2],p4->p[2]);
00429  taul=0.0; taur=1.0; nc=0;
00430  tau=pathposition  - Lpp->distance;  /* Lpp is start of segment     */
00431  tau /= (distance  - Lpp->distance); /* distance is end of segment  */
00432 //if(debug != NULL)fprintf(debug,"%ld t=%.3lf  d=%.1lf Lpp=%.1lf",CurrentFrame,tau,
00433 //pathposition,Lpp->distance);
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 //if(nc == 0)dotau=d;
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 //if(debug != NULL)fprintf(debug," it=%ld nt=%.3lf nd=%.1lf od=%.1lf\n",nc,tau,d,dotau);
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  // used by robot position to determine the location of a point on a path
00462  // we will need to take into accout any position of the path with a position Pp 
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          ;/* no length calc necessary for last segment */
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{ /* closed path */
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    // get to this point we are beyond the end of the path
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; /* Np is pointer to Path type object Op will be current path*/
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){ /* only 1 frame for path */
00570        CopyPoint(Op->firstpathpoint->p,ObjectOffset);
00571      }
00572      else{ /* get (0-1)position parameter */
00573        if(*position0_1 < 0.0){  /* get path posn from path look up table */
00574          if(Op->v != NULL){
00575            long ip;
00576            ip=frame - Op->firstframe;
00577            if(ip > 0){       // use dframe as fraction (dframe default is 1.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; /* scale to length */
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;     /* always at least 2 points in path */
00592          while(Ppp != NULL && pathposition >= Ppp->distance){
00593                Lpp=Ppp; Ppp=Ppp->next;}
00594          if(Ppp == NULL){  /* after last pathpoint  Lpp points to last point*/
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 /*     rotational transform is not allowed for paths if it is in future  */
00607 /*     do it here                                                        */
00608      }
00609      *lengthonpath=pathposition;
00610      return Op;
00611    }
00612    Op=Op->next;
00613  }
00614  return NULL; /* no path at this frame to follow etc */
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;/* no changes necessary */
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){/* allocate a new velocity(distance) profile */
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);   /* if not copying then X__Free old memory */
00642  }
00643  else{
00644    if(oldn < 0){ /* old n not available - just reset */
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++){ /* interpolate onto new path position array */
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++){ /* interpolate onto new path position array */
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 //     CentreDialogOnScreen(hwnd);
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; /* should not happen */
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){ /* one Lagrangian */
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){  /* spline */
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){ /* so loop is completed */
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){  /* pieces */
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

Generated on Sun Apr 27 14:20:09 2014 for OpenFX by  doxygen 1.5.6