// I wrote one of these from scratch once starting with a 2d spline procedure, // but I seem to have lost that source. This version appears to have come from // http://paulbourke.net/geometry/spline/ // - I didn't have the patience to re-implement it from first principles I guess. // FOUND IT: #ifdef NEVER /* The procedure below is based on */ /* http://stackoverflow.com/questions/5443653/opengl-coordinates-from-bezier-curves */ /* - it's a 1D Bezier than can be called twice to create a 2D Bezier spline and */ /* 3 times to create a 3D Bezier spline etc. Each axis is independent. */ double bezier(double A, /* Start value */ double B, /* First control value */ double C, /* Second control value */ double D, /* Ending value */ int t, int max_slots, /* eg 0..255/256 slots */ double *delta) /* Parameter 0 <= t <= 1 */ { double s = (max_slots-1) - t; double AB = (A*s + B*t)/max_slots; double BC = (B*s + C*t)/max_slots; double CD = (C*s + D*t)/max_slots; // double ABC = (AB*s + CD*t)/max_slots; - this 'bug fix' was wrong... double ABC = (AB*s + BC*t)/max_slots; // original code was correct... double BCD = (BC*s + CD*t)/max_slots; if (delta) *delta = ABC-BCD; return (ABC*s + BCD*t)/max_slots; } #endif //---------------------------------------------------- FLIGHTPATH GENERATOR #include <stdio.h> // once code is performing properly, replace this with a version using fixed- // point arithmetic (which is currently broken :-( ) typedef struct XYZ { double x,y,z; } XYZ; double SplineBlend(int k,int t,int *u,double v); /* This returns the point "output" on the spline curve. The parameter "v" indicates the position, it ranges from 0 to n-t+2 */ void SplinePoint(int *u,int n,int t,double v,XYZ *control,XYZ *output) { int k; double b; output->x = 0; output->y = 0; output->z = 0; for (k=0;k<=n;k++) { b = SplineBlend(k,t,u,v); output->x += control[k].x * b; output->y += control[k].y * b; output->z += control[k].z * b; } } /* Calculate the blending value, this is done recursively. If the numerator and denominator are 0 the expression is 0. If the deonimator is 0 the expression is 0 */ double SplineBlend(int k,int t,int *u,double v) { double value; if (t == 1) { if ((u[k] <= v) && (v < u[k+1])) value = 1; else value = 0; } else { if ((u[k+t-1] == u[k]) && (u[k+t] == u[k+1])) value = 0; else if (u[k+t-1] == u[k]) value = (u[k+t] - v) / (u[k+t] - u[k+1]) * SplineBlend(k+1,t-1,u,v); else if (u[k+t] == u[k+1]) value = (v - u[k]) / (u[k+t-1] - u[k]) * SplineBlend(k,t-1,u,v); else value = (v - u[k]) / (u[k+t-1] - u[k]) * SplineBlend(k,t-1,u,v) + (u[k+t] - v) / (u[k+t] - u[k+1]) * SplineBlend(k+1,t-1,u,v); } return(value); } /* The positions of the subintervals of v and breakpoints, the position on the curve are called knots. Breakpoints can be uniformly defined by setting u[j] = j, a more useful series of breakpoints are defined by the function below. This set of breakpoints localises changes to the vicinity of the control point being modified. */ void SplineKnots(int *u,int n,int t) { int j; for (j=0;j<=n+t;j++) { if (j < t) u[j] = 0; else if (j <= n) u[j] = j - t + 1; else if (j > n) u[j] = n - t + 2; } } /*------------------------------------------------------------------------- Create all the points along a spline curve Control points "inp", "n" of them. Knots "knots", degree "t". Output curve "outp", "res" of them. */ void SplineCurve(XYZ *inp,int n,int *knots,int t,XYZ *outp,int res) { int i; double interval,increment; interval = 0; increment = (n - t + 2) / (double)(res - 1); for (i=0;i<res-1;i++) { SplinePoint(knots,n,t,interval,inp,&(outp[i])); interval += increment; } outp[res-1] = inp[n]; } /* Example of how to call the spline functions Basically one needs to create the control points, then compute the knot positions, then calculate points along the curve. */ #define SCL 2048 // x/y fudge factor #define ZSCL 512 // distance away #define PSCL 1024 // perspective scale #define MAXN 10 XYZ inp[] = { //X Y Z 450.0, 1000.0, 10.0, // final coord is center of 1280x1024 screen 450.0, 1000.0, 6.66, // final coord is center of 1280x1024 screen 450.0, 1000.0, 3.33, // final coord is center of 1280x1024 screen 450.0, 1000.0, 0.0, // final coord is center of 1280x1024 screen }; #define T 3 int knots[MAXN+T+1]; #define RESOLUTION 512 XYZ outp[RESOLUTION]; void newpaths(void) // yet another quick hack... { int i, N; double x,y,z,x2,y2; for (i = 0; i < MAXN; i++) { if (inp[i].z < 0.0001) break; } N = i-1; SplineKnots(knots,N,T); SplineCurve(inp,N,knots,T,outp,RESOLUTION); return; printf("static int xyflightpath[RES*2] = {\n"); for (i=0;i<RESOLUTION;i++) { x=outp[i].x; y=outp[i].y; z=outp[i].z; x2 = ((PSCL*x)/(PSCL+x)); y2 = ((PSCL*y)/(PSCL+y)); printf(" %d, %d,\n",(int)x2, (int)y2); } printf("};\n"); return; /* Display the curve */ printf("#define RES %d\n",RESOLUTION); #ifdef VERBOSE /* Control point polygon */ printf("#define POINTS %d\nstatic double controls[POINTS*3] = {\n", N+1); for (i=0;i<=N;i++) printf(" %g, %g, %g,\n",inp[i].x,inp[i].y,inp[i].z); printf("}\n"); /* Display the curve */ printf("static double curve[RES*3] = {\n",RESOLUTION); for (i=0;i<RESOLUTION;i++) printf(" %g, %g, %g,\n",outp[i].x,outp[i].y,outp[i].z); printf("}\n"); #endif printf("static int xyflightpath[RES*2] = {\n"); for (i=0;i<RESOLUTION;i++) { x=outp[i].x; y=outp[i].y; z=outp[i].z; x2 = ((PSCL*x)/(PSCL+x)); y2 = ((PSCL*y)/(PSCL+y)); printf(" %d, %d,\n",(int)x2, (int)y2); } printf("};\n"); } //------------------------------------------------ END FLIGHTPATH GENERATOR