// gFilters.h #ifndef gFiltersh #define gFiltersh #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "../../Global.h" struct gFilters { //>>>>>>>>>>>>>> Periodic methods which return a parameter with interval [0,1] <<<<<<<<<<<<<<<< // x is any value. Period is in the same units as x. return values are in the Interval [0,1] static double SawTooth(const double& x, const double& Period) {return Mod(x,Period)/Period;} static double Triangle(const double& x, const double& Period) {return fabs(Signed(SawTooth(x,Period)));} // High at zero. To start at 0,0 use 1-Triangle static bool Square (const double& x, const double& Period) {return Step(SawTooth(x,Period), 0.5);} static double Stripes (const double& x, const double& Period) {return HermiteStep(Triangle(x,Period), 0.4, 0.6);} // Smoothed Square static double Repeat (const double& x, const double& Count, bool Mirror=false) {return Mirror ? 1-Triangle(x,1/Count) : SawTooth(x,1/Count);} // 2 Dimensional: static bool Chess (const double& x, const double& y, int xCount, int yCount) {return Square(x,1/xCount)==Square(y,1/yCount);} // 0,0 returns true //>>>>>>>>>>>>>> Step methods which return a parameter with interval [0,1] <<<<<<<<<<<<<<<< // x is any value, a and b are values that x is likely to pass through, in the same units as x. // return values are in the Interval [0,1] // return is 0 when x<=a and 1 when x>a. static bool Step(const double& x, const double& a) {return x>a;} // return is 0 when x<=a; 1 when x>b and unchanged in the [a,b] interval: static double Threshold(const double& x, const double& a, const double& b) {return xb, holding at 1 thereafter. static double Ramp(const double& x, const double& a, const double& b) { if(a==b) return 0; if(x>>>>>>>>>>>>> Zero-crossing methods which alter a parameter with interval [0,1] <<<<<<<<<<<<<<<< static double HermiteCurve(const double& t) {return t*t*(3-2*t);} // 3t²-2t³ Called "Ease" in some art packages static double RootCurve(const double& t) {return t==0 ? 0 : sqrt(fabs(t));} static double SinusoidalCurve(const double& t) {return sin(M_PI_2*t);} static double CircleCurve(const double& t) {return sqrt(fabs(t*(2-t)));} // 1-(1-t)*(1-t) // Full Gaussian 1D equation is: exp(-(t*t/(2*s*s))/(sqrt(2*M_PI)*s); where s is the standard deviation. This uses s=1/3.0; to make the bell peak at 1.0 static double GaussianCurve(const double& t) {return exp(-3.125*t*t)*1.0026513098524002009663061139244;} // The number is 1/(sqrt(2*M_PI)/3). // Full Gaussian 2D equation is: exp(-(x*x+y*y)/(2*s*s))/((2*M_PI)*s*s); where s is the standard deviation. static double HighContrastCurve(double t) { t=Bias( t, 0.67); if(t<0.5) t=Bias(2*t, 0.14)/2; return Bias( t, 0.35); } static double CatStepCurve(const double& t) { if(t<0.25) return 32*t*t*t*(-1/3.0 + t); if(t<0.5) return t*(t*(t*(-t*96+416/3.0)- 64)+12)- 5/6.0; // Horner's Rule if(t<0.75) return t*(t*(t*( t*96-736/3.0)+224)-84)+67/6.0; return t*(t*(t*(-t*32+352/3.0)-160)+96)-61/3.0; } //>>>>>>>>>>>>>> Methods which alter a parameter with interval [0,1] <<<<<<<<<<<<<<<< // Gain alters the slope at the mid-point of the interval. Steeper slopes come from higher values: static double Gain(const double& t, const double& Gain) { return t<0.5 ? Bias(2* t , 1-Gain)/2 : 1-Bias(2*(1-t), 1-Gain)/2; } // Bias pulls the interval; <0.5 keeps parameter lower longer static double Bias(const double& t, const double& Bias) { if( t<0.001) return 0; else if( t>0.999) return 1; else if(Bias<0.001) return 0; else if(Bias>0.999) return 1; // The long number is 1/ln(0.5); [ln in c++ is log; log in c++ is log10] else return pow(t, log(Bias) * -1.4426950408889634073599246810019); } //>>>>>>>>>>>>>> Symmetrical Filters changing a parameter with interval [-1,1] to [0,1] <<<<<<<<<<<<<<<< // Deals with t in the range [-1,1] (FilterWidth=1) // Results are in the interval [0,1] static double BoxFilter(const double& t) {return ((t>-0.5) && (t<=0.5) ? 1 : 0);} // Deals with t in the range [-1,1] (FilterWidth=1) // Results are in the interval [0,1] static double TriangleFilter(double t) { if(t<0) t=-t; if(t<1) return 1-t; return 0; } // Deals with t in the range [-1,1] (FilterWidth=1) // Results are in the interval [0,1] static double HermiteFilter(double t) { if(t<0) t=-t; return (t>=1 ? 0 : 1-HermiteCurve(t)); } //>>>>>>> Methods which take (potentially over-sized) signed intervals and return Intervals in the range [0-1] (some return small negatives) <<<<<<<<<<<< // Deals with t in the range [-1.5,1.5] (FilterWidth=1.5) // Results are in the interval [0, 0.75] static double BellFilter(double t) { if(t<0) t=-t; if(t<0.5) return 0.75-(t*t); if(t<1.5) { t-=1.5; return 0.5*(t*t); } return 0; } // Deals with t in the range [-2,2] (FilterWidth=2) // Results are in the interval [0, 0.6666] static double bSplineFilter(double t) { if(t<0) t=-t; if(t<1) { double t2=t*t; return 0.5*t2*t-t2+2/3.0; } if(t<2) { t=2-t; return 1/6.0*t*t*t; } return 0; } // Deals with t in the range [-2,2] (FilterWidth=2) // Results are in the interval [-0.074052, 1] static double CatRomFilter(double t) { double t2=t*t; if(t<0) t=-t; if(t<1) return 1.5*t2*t - 2.5*t2 + 1; if(t<2) return -0.5*t2*t + 2.5*t2 - 4*t + 2; return 0; } // Deals with t in the range [-3,3] (FilterWidth=3) // Results are in the interval [-0.147233, 1] static double LanczosFilter(double t, double FilterWidth=3) { if(t<0) t=-t; if(t>>>>>>>>>>>>>>>>>>>>>>> return any value from an interval [0-1] <<<<<<<<<<<<<<<<<<<<<<<<<<<< /* Compare the Pixel distance (P) to the Real distance (R) (just give squares: don't use sqrt). For simple antialias, Blur=3.5*r; where R=r*r; More generally, if int BlurLevel is between 1 and 5, use double Blur=(1.5*BlurLevel+2)*r; Returns a Transparency Value (0 is opaque, 1 is transparent) */ static double Antialias(const double& P, const double& R, const double& Blur) {return (P>R-1) ? 1 : ((P>R-Blur) ? (P-R)/Blur : 0);} static double Random(const double& a=0, const double& b=1) {return InterpolateLinear((1402024253UL*rand()+586950981)/double(ULONG_MAX), a,b);} static double ParameterizeLinear(const double& x, const double& a, const double& b) {return Parameterize(x,a,b);} static double InterpolateLinear(const double& t, const double& a, const double& b) {return Interpolate (t,a,b);} // InterpolateCosine is slow! Use: InterpolateHermite(t,a,a,b,a); it gives a very similar result! static double InterpolateCosine(const double& t, const double& a, const double& b) {return InterpolateLinear((1-cos(t*M_PI))/2, a,b);} // Uses four values to find a value between the two MIDDLE ones. static double InterpolateBezier(const double& t, const double& a, const double& b, const double& c, const double& d) {return InterpolateBezierStd(t, b, b+(b-a), c-(d-c), c);} // Uses four values to find a value between the two END ones (b and c indicate initial direction for a and d). static double InterpolateBezierStd(const double& t, const double& a, const double& b, const double& c, const double& d) { return t*(t*(t*(-a+3*(b-c)+d)+3*(a-b-b+c))+3*(b-a))+a; } // Uses four values to find a value between the two MIDDLE ones (passes through b and c): // If you don't have four points, a=Interpolate(-1, b,c), d=Interpolate(2, b,c); static double InterpolateHermite(const double& t, const double& a, const double& b, const double& c, const double& d) { return t*(t*(t*(a+2*(b-c)+d)-(2*a+3*(b-c)+d))+a)+b; }//[(2t^3 - 3t^2 +1) (-2t^3 + 3t^2) (t^3 - 2t^2 + t) (t^3 - t^2)] // Tension: 0 is normal; -1 is low; 1 is high. // Bias: 0 is even, positive is towards first segment, negative towards the other. static double InterpolateHermite(const double& t, const double& a,const double& b,const double& c,const double& d, const double& Tension, const double& Bias) { double t2=t*t; double t3=t2*t; double m0=(b-a)*(1+Bias)*(1-Tension) +(c-b)*(1-Bias)*(1-Tension); double m1=(c-b)*(1+Bias)*(1-Tension) +(d-c)*(1-Bias)*(1-Tension); double a0= 2*t3 - 3*t2 + 1; double a1= t3 - 2*t2 + t; double a2= t3 - t2; double a3=-2*t3 + 3*t2; return a0*b+a3*c+(a1*m0+a2*m1)/2; } // Uses four values to find a value between the two MIDDLE ones (passes through b and c): // If you don't have four points, a=Interpolate(-1, b,c), d=Interpolate(2, b,c); static double InterpolateCatmullRom(const double& t, const double& a, const double& b, const double& c, const double& d) { if(t==0) return b; // if((t==0)||(b==c)) return b; Clips it into the Hermite Curve if(t==1) return c; return 0.5*(t*(t*(t*((d-a)+3*(b-c))+(2*a - 5*b + 4*c -d))-a+c))+b; } // Uses four values to find a value between the two MIDDLE ones (passes through b and c): // If you don't have four points, a=Interpolate(-1, b,c), d=Interpolate(2, b,c); static double InterpolateCubic(const double& t, const double& a, const double& b, const double& c, const double& d) { return t*(t*(t*(-a+b-c+d)+(2*(a-b)+c-d))+(c-a))+b; } // Uses four values to find a value between the two MIDDLE ones (passes through b and c): // If you don't have four points, a=Interpolate(-1, b,c), d=Interpolate(2, b,c); static double InterpolateBSpline(const double& t, const double& a, const double& b, const double& c, const double& d) { return 1/6.0*(t*(t*(t*(-a+3*b-3*c+d)+(3*a-6*b+3*c))+3*(c-a))+(a+4*b+c)); } }; class CatmullRom1D { // Cubic Spline. Uses four values to find a value between the two middle ones: double C[4]; public: CatmullRom1D(double v[4]) { C[0]=( v[1] ); C[1]=(-v[0]/2 + v[2]/2 ); C[2]=( v[0] - 2.5*v[1] + 2*v[2] - v[3]/2); C[3]=(-v[0]/2 + 1.5*v[1] - 1.5*v[2] + v[3]/2); } CatmullRom1D(const double& a, const double& b, const double& c,const double& d) { C[0]=( b ); C[1]=(-a/2 + c/2 ); C[2]=( a - 2.5*b + 2*c - d/2); C[3]=(-a/2 + 1.5*b - 1.5*c + d/2); } double Interpolate(const double& t) const {return t*(t*(t*C[3]+C[2])+C[1])+C[0];} }; class CatmullRom2D { // Bicubic Spline. Catmull-Rom interpolation of 4x4 vertex mesh's middle square: double C[4][4]; // Coefficients matrix public: CatmullRom2D(double Grid[4][4]) { static const double M[4][4]={ // Catmull-Rom basis matrix {-0.5, 1.5, -1.5, 0.5}, { 1 , -2.5, 2 ,-0.5}, {-0.5, 0 , 0.5, 0 }, { 0 , 1 , 0 , 0 } }; double T[4][4]; for(int i=0; i<4; ++i) // T = G * MT for(int j=0; j<4; ++j) for(int k=0; k<4; ++k) T[i][j] += Grid[i][k] * M[j][k]; for(int i=0; i<4; ++i) // C = M * T for(int j=0; j<4; ++j) for(int k=0; k<4; ++k) C[i][j] += M[i][k] * T[k][j]; } double Interpolate(const double& s, const double& t) const { const double* X3=C[0]; const double* X2=C[1]; const double* X1=C[2]; const double* X0=C[3]; return s*(s*(s*(t*(t*(t*X3[0]+X3[1])+X3[2])+X3[3]) // Horner's Rule + (t*(t*(t*X2[0]+X2[1])+X2[2])+X2[3])) + (t*(t*(t*X1[0]+X1[1])+X1[2])+X1[3])) + (t*(t*(t*X0[0]+X0[1])+X0[2])+X0[3]); } }; #endif // ndef gFiltersh