//////////////////////////////////////////////////////////////////////////////// // Scorched3D (c) 2000-2004 // // This file is part of Scorched3D. // // Scorched3D is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // Scorched3D is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Scorched3D; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //////////////////////////////////////////////////////////////////////////////// #include // // This code is taken from // http://astronomy.swin.edu.au/~pbourke/curves/spline/ // with some changes to make it less reliant on fixed c arrays // /* 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 */ static float splineBlend(int k,int t,int *u,float v) { float 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); } /* This returns the point "output" on the spline curve. The parameter "v" indicates the position, it ranges from 0 to n-t+2 */ static void splinePoint(int *u,int n,int t,float v, std::vector &control, Vector &output) { output[0] = 0; output[1] = 0; output[2] = 0; for (int k=0;k<=n;k++) { float b = splineBlend(k,t,u,v); output[0] += (control[k])[0] * b; output[1] += (control[k])[1] * b; output[2] += (control[k])[2] * b; } } /* 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. */ static 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". Ouput curve "outp", "res" of them. */ static void splineCurve(std::vector &inp_list,int n,int *knots,int t, std::vector &outp_list,int res) { int i; float interval,increment; interval = 0; increment = (n - t + 2) / (float)(res - 1); for (i=0;i<=res-1;i++) { Vector outp; splinePoint(knots,n,t,interval,inp_list,outp); outp_list.push_back(outp); interval += increment; } outp_list[res-1] = inp_list[n]; } void SplineCurve::generate( std::vector &inPoints, std::vector &outPoints, int resolution, int polynomials) { int N = int(inPoints.size()) - 1; int T = polynomials; int *knots = new int[N + T + 1]; splineKnots(knots,N,T); splineCurve(inPoints,N,knots,T,outPoints,resolution); delete [] knots; }