curve.h

Go to the documentation of this file.
00001 
00006 /*
00007  Copyright (C) 2001-2006, William Joseph.
00008  All Rights Reserved.
00009 
00010  This file is part of GtkRadiant.
00011 
00012  GtkRadiant is free software; you can redistribute it and/or modify
00013  it under the terms of the GNU General Public License as published by
00014  the Free Software Foundation; either version 2 of the License, or
00015  (at your option) any later version.
00016 
00017  GtkRadiant is distributed in the hope that it will be useful,
00018  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  GNU General Public License for more details.
00021 
00022  You should have received a copy of the GNU General Public License
00023  along with GtkRadiant; if not, write to the Free Software
00024  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00025  */
00026 
00027 #if !defined(INCLUDED_MATH_CURVE_H)
00028 #define INCLUDED_MATH_CURVE_H
00029 
00030 #include "debugging/debugging.h"
00031 #include "container/array.h"
00032 #include <math/matrix.h>
00033 
00034 template<typename I, typename Degree>
00035 struct BernsteinPolynomial
00036 {
00037         static double apply (double t)
00038         {
00039             return 1; // general case not implemented
00040         }
00041 };
00042 
00043 typedef IntegralConstant<0> Zero;
00044 typedef IntegralConstant<1> One;
00045 typedef IntegralConstant<2> Two;
00046 typedef IntegralConstant<3> Three;
00047 typedef IntegralConstant<4> Four;
00048 
00049 template<>
00050 struct BernsteinPolynomial<Zero, Zero>
00051 {
00052         static double apply (double t)
00053         {
00054             return 1;
00055         }
00056 };
00057 
00058 template<>
00059 struct BernsteinPolynomial<Zero, One>
00060 {
00061         static double apply (double t)
00062         {
00063             return 1 - t;
00064         }
00065 };
00066 
00067 template<>
00068 struct BernsteinPolynomial<One, One>
00069 {
00070         static double apply (double t)
00071         {
00072             return t;
00073         }
00074 };
00075 
00076 template<>
00077 struct BernsteinPolynomial<Zero, Two>
00078 {
00079         static double apply (double t)
00080         {
00081             return (1 - t) * (1 - t);
00082         }
00083 };
00084 
00085 template<>
00086 struct BernsteinPolynomial<One, Two>
00087 {
00088         static double apply (double t)
00089         {
00090             return 2 * (1 - t) * t;
00091         }
00092 };
00093 
00094 template<>
00095 struct BernsteinPolynomial<Two, Two>
00096 {
00097         static double apply (double t)
00098         {
00099             return t * t;
00100         }
00101 };
00102 
00103 template<>
00104 struct BernsteinPolynomial<Zero, Three>
00105 {
00106         static double apply (double t)
00107         {
00108             return (1 - t) * (1 - t) * (1 - t);
00109         }
00110 };
00111 
00112 template<>
00113 struct BernsteinPolynomial<One, Three>
00114 {
00115         static double apply (double t)
00116         {
00117             return 3 * (1 - t) * (1 - t) * t;
00118         }
00119 };
00120 
00121 template<>
00122 struct BernsteinPolynomial<Two, Three>
00123 {
00124         static double apply (double t)
00125         {
00126             return 3 * (1 - t) * t * t;
00127         }
00128 };
00129 
00130 template<>
00131 struct BernsteinPolynomial<Three, Three>
00132 {
00133         static double apply (double t)
00134         {
00135             return t * t * t;
00136         }
00137 };
00138 
00139 typedef Array<Vector3> ControlPoints;
00140 
00141 inline Vector3 CubicBezier_evaluate (const Vector3* firstPoint, double t)
00142 {
00143     Vector3 result(0, 0, 0);
00144     double denominator = 0;
00145 
00146     {
00147         double weight = BernsteinPolynomial<Zero, Three>::apply(t);
00148         result += (*firstPoint++) * weight;
00149         denominator += weight;
00150     }
00151     {
00152         double weight = BernsteinPolynomial<One, Three>::apply(t);
00153         result += (*firstPoint++) * weight;
00154         denominator += weight;
00155     }
00156     {
00157         double weight = BernsteinPolynomial<Two, Three>::apply(t);
00158         result += (*firstPoint++) * weight;
00159         denominator += weight;
00160     }
00161     {
00162         double weight = BernsteinPolynomial<Three, Three>::apply(t);
00163         result += (*firstPoint++) * weight;
00164         denominator += weight;
00165     }
00166 
00167     return result / denominator;
00168 }
00169 
00170 inline Vector3 CubicBezier_evaluateMid (const Vector3* firstPoint)
00171 {
00172     return firstPoint[0] * 0.125 + firstPoint[1] * 0.375 + firstPoint[2] * 0.375 + firstPoint[3] * 0.125;
00173 }
00174 
00175 inline Vector3 CatmullRom_evaluate (const ControlPoints& controlPoints, double t)
00176 {
00177     // scale t to be segment-relative
00178     t *= double(controlPoints.size() - 1);
00179 
00180     // subtract segment index;
00181     std::size_t segment = 0;
00182     for (std::size_t i = 0; i < controlPoints.size() - 1; ++i) {
00183         if (t <= double(i + 1)) {
00184             segment = i;
00185             break;
00186         }
00187     }
00188     t -= segment;
00189 
00190     const double reciprocal_alpha = 1.0 / 3.0;
00191 
00192     Vector3 bezierPoints[4];
00193     bezierPoints[0] = controlPoints[segment];
00194     bezierPoints[1] = (segment > 0) ? controlPoints[segment]
00195             + (controlPoints[segment + 1] - controlPoints[segment - 1]) * (reciprocal_alpha * 0.5)
00196             : controlPoints[segment] + (controlPoints[segment + 1] - controlPoints[segment]) * reciprocal_alpha;
00197     bezierPoints[2] = (segment < controlPoints.size() - 2) ? controlPoints[segment + 1] + (controlPoints[segment]
00198             - controlPoints[segment + 2]) * (reciprocal_alpha * 0.5) : controlPoints[segment + 1]
00199             + (controlPoints[segment] - controlPoints[segment + 1]) * reciprocal_alpha;
00200     bezierPoints[3] = controlPoints[segment + 1];
00201     return CubicBezier_evaluate(bezierPoints, t);
00202 }
00203 
00204 typedef Array<float> Knots;
00205 
00206 inline double BSpline_basis (const Knots& knots, std::size_t i, std::size_t degree, double t)
00207 {
00208     if (degree == 0) {
00209         if (knots[i] <= t && t < knots[i + 1] && knots[i] < knots[i + 1]) {
00210             return 1;
00211         }
00212         return 0;
00213     }
00214     double leftDenom = knots[i + degree] - knots[i];
00215     double left = (leftDenom == 0) ? 0 : ((t - knots[i]) / leftDenom) * BSpline_basis(knots, i, degree - 1, t);
00216     double rightDenom = knots[i + degree + 1] - knots[i + 1];
00217     double right = (rightDenom == 0) ? 0 : ((knots[i + degree + 1] - t) / rightDenom) * BSpline_basis(knots, i + 1,
00218             degree - 1, t);
00219     return left + right;
00220 }
00221 
00222 inline Vector3 BSpline_evaluate (const ControlPoints& controlPoints, const Knots& knots, std::size_t degree, double t)
00223 {
00224     Vector3 result(0, 0, 0);
00225     for (std::size_t i = 0; i < controlPoints.size(); ++i) {
00226         result += controlPoints[i] * BSpline_basis(knots, i, degree, t);
00227     }
00228     return result;
00229 }
00230 
00231 typedef Array<float> NURBSWeights;
00232 
00233 inline Vector3 NURBS_evaluate (const ControlPoints& controlPoints, const NURBSWeights& weights, const Knots& knots,
00234         std::size_t degree, double t)
00235 {
00236     Vector3 result(0, 0, 0);
00237     double denominator = 0;
00238     for (std::size_t i = 0; i < controlPoints.size(); ++i) {
00239         double weight = weights[i] * BSpline_basis(knots, i, degree, t);
00240         result += controlPoints[i] * weight;
00241         denominator += weight;
00242     }
00243     return result / denominator;
00244 }
00245 
00246 inline void KnotVector_openUniform (Knots& knots, std::size_t count, std::size_t degree)
00247 {
00248     knots.resize(count + degree + 1);
00249 
00250     std::size_t equalKnots = 1;
00251 
00252     for (std::size_t i = 0; i < equalKnots; ++i) {
00253         knots[i] = 0;
00254         knots[knots.size() - (i + 1)] = 1;
00255     }
00256 
00257     std::size_t difference = knots.size() - 2 * (equalKnots);
00258     for (std::size_t i = 0; i < difference; ++i) {
00259         knots[i + equalKnots] = Knots::value_type(double(i + 1) * 1.0 / double(difference + 1));
00260     }
00261 }
00262 
00263 #endif

Generated by  doxygen 1.6.2