00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "SeExpression.h"
00011 #include "SeExprBuiltins.h"
00012 #include <cfloat>
00013 #include <cassert>
00014 #include <algorithm>
00015
00016 #include "SeCurve.h"
00017
00018 namespace SeExpr{
00019
00020 template<> double SeCurve<double>::comp(const double& val,const int)
00021 {return val;}
00022
00023 template<> double SeCurve<SeVec3d>::comp(const SeVec3d& val,const int i)
00024 {return val[i];}
00025
00026 template<class T> bool SeCurve<T>::
00027 cvLessThan(const CV &cv1, const CV &cv2)
00028 {
00029 return cv1._pos < cv2._pos;
00030 }
00031
00032 template<class T> SeCurve<T>::
00033 SeCurve()
00034 :cacheCV(0),prepared(false)
00035 {
00036 _cvData.push_back(CV(-FLT_MAX,T(),kNone));
00037 _cvData.push_back(CV(FLT_MAX,T(),kNone));
00038 }
00039
00040 template<class T> void SeCurve<T>::
00041 addPoint(double position,const T& val,InterpType type)
00042 {
00043 prepared=false;
00044 _cvData.push_back(CV(position,val,type));
00045 }
00046
00047 template<class T> void SeCurve<T>::
00048 preparePoints()
00049 {
00050 prepared=true;
00051 cacheCV=0;
00052
00053 std::sort(_cvData.begin(), _cvData.end(), cvLessThan);
00054
00055
00056 CV& end=*(_cvData.end()-1);
00057 CV& begin=*(_cvData.begin());
00058 int realCVs=_cvData.size()-2;
00059 assert(realCVs>=0);
00060 if(realCVs>0){
00061 begin._val=_cvData[1]._val;
00062 begin._deriv=T();
00063 begin._interp=kNone;
00064 int lastIndex=_cvData.size()-1;
00065 end._val=_cvData[lastIndex-1]._val;
00066 end._deriv=T();
00067 end._interp=kNone;
00068 }else{
00069 begin._pos=end._pos=0;
00070 begin._val=end._val=T();
00071 begin._interp=kNone;
00072 begin._deriv=end._deriv=T();
00073 }
00074
00075
00076 for(unsigned int i=1;i<_cvData.size()-1;i++){
00077 _cvData[i]._deriv=(_cvData[i+1]._val-_cvData[i-1]._val)
00078 /(_cvData[i+1]._pos-_cvData[i-1]._pos);
00079 }
00080
00081
00082 for(unsigned int i=0;i<_cvData.size()-1;i++){
00083 if(_cvData[i]._interp==kMonotoneSpline){
00084 double h=_cvData[i+1]._pos-_cvData[i]._pos;
00085 if(h==0)
00086 _cvData[i]._deriv=_cvData[i+1]._deriv=T();
00087 else{
00088 T delta=(_cvData[i+1]._val-_cvData[i]._val)/h;
00089 clampCurveSegment(delta,_cvData[i]._deriv,
00090 _cvData[i+1]._deriv);
00091 }
00092 }
00093 }
00094 }
00095
00096
00097
00098 template<class T> T SeCurve<T>::
00099 getValue(const double param) const
00100 {
00101 assert(prepared);
00102
00103 const int numPoints = _cvData.size();
00104 const CV *cvDataBegin = &_cvData[0];
00105 int index = std::upper_bound(cvDataBegin, cvDataBegin + numPoints,
00106 CV(param, T(),kLinear),cvLessThan) - cvDataBegin;
00107 index=std::max(1,std::min(index,numPoints-1));
00108
00109 const float t0 = _cvData[index - 1]._pos;
00110 const T k0 = _cvData[index - 1]._val;
00111 const InterpType interp = _cvData[index - 1]._interp;
00112 const float t1 = _cvData[index]._pos;
00113 const T k1 = _cvData[index]._val;
00114 switch (interp) {
00115 case kNone:
00116 return k0;
00117 break;
00118 case kLinear:
00119 {
00120 double u = (param-t0)/(t1-t0);
00121 return k0 + u*(k1-k0);
00122 }
00123 break;
00124 case kSmooth:
00125 {
00126 double u = (param-t0)/(t1-t0);
00127 return k0*(u-1)*(u-1)*(2*u+1) + k1*u*u*(3 - 2*u);
00128 }
00129 break;
00130 case kSpline:
00131 case kMonotoneSpline:
00132 {
00133 double x=param-_cvData[index-1]._pos;
00134 double h=_cvData[index]._pos-_cvData[index-1]._pos;
00135 T y=_cvData[index-1]._val;
00136 T delta=_cvData[index]._val-_cvData[index-1]._val;
00137 T d1=_cvData[index-1]._deriv;
00138 T d2=_cvData[index]._deriv;
00139 return (x*(delta*(3*h - 2*x)*x + h*(-h + x)*(-(d1*h) + (d1 + d2)*x)))
00140 /(h*h*h) + y;
00141 }
00142 break;
00143 default:
00144 assert(false);
00145 return T();
00146 break;
00147 }
00148 }
00149
00150
00151
00152 template<class T> double SeCurve<T>::
00153 getChannelValue(const double param,int channel) const{
00154 assert(prepared);
00155
00156 const int numPoints = _cvData.size();
00157 const CV *cvDataBegin = &_cvData[0];
00158 int index = std::upper_bound(cvDataBegin, cvDataBegin + numPoints,
00159 CV(param, T(),kLinear),cvLessThan) - cvDataBegin;
00160 index=std::max(1,std::min(index,numPoints-1));
00161
00162 const float t0 = _cvData[index - 1]._pos;
00163 const double k0 = comp(_cvData[index - 1]._val,channel);
00164 const InterpType interp = _cvData[index - 1]._interp;
00165 const float t1 = _cvData[index]._pos;
00166 const double k1 = comp(_cvData[index]._val,channel);
00167 switch (interp) {
00168 case kNone:
00169 return k0;
00170 break;
00171 case kLinear:
00172 {
00173 double u = (param-t0)/(t1-t0);
00174 return k0 + u*(k1-k0);
00175 }
00176 break;
00177 case kSmooth:
00178
00179 {
00180 double u = (param-t0)/(t1-t0);
00181 return k0*(u-1)*(u-1)*(2*u+1) + k1*u*u*(3 - 2*u);
00182 }
00183 break;
00184 case kSpline:
00185 case kMonotoneSpline:
00186 {
00187 double x=param-_cvData[index-1]._pos;
00188 double h=_cvData[index]._pos-_cvData[index-1]._pos;
00189 double y=comp(_cvData[index-1]._val,channel);
00190 double delta=comp(_cvData[index]._val,channel)
00191 -comp(_cvData[index-1]._val,channel);
00192 double d1=comp(_cvData[index-1]._deriv,channel);
00193 double d2=comp(_cvData[index]._deriv,channel);
00194
00195 return (x*(delta*(3*h - 2*x)*x + h*(-h + x)*(-(d1*h) + (d1 + d2)*x)))
00196 /(h*h*h) + y;
00197 }
00198 break;
00199 default:
00200 assert(false);
00201 return 0;
00202 break;
00203 }
00204 }
00205
00206 template<class T> typename SeCurve<T>::CV SeCurve<T>::
00207 getLowerBoundCV(const double param) const
00208 {
00209 assert(prepared);
00210 const CV *cvDataBegin = &_cvData[0];
00211 int numPoints=_cvData.size();
00212 int index = std::upper_bound(cvDataBegin, cvDataBegin + numPoints,
00213 CV(param, T(),kLinear),cvLessThan) - cvDataBegin;
00214 index=std::max(1,std::min(index,numPoints-1));
00215 if(index-1 > 0) return _cvData[index-1];
00216 return _cvData[index];
00217 }
00218
00219 template<class T> bool SeCurve<T>::
00220 interpTypeValid(InterpType interp)
00221 {
00222 return interp==kNone || interp==kLinear || interp==kSmooth
00223 || interp==kSpline || interp==kMonotoneSpline;
00224 }
00225
00226 template<>
00227 inline void SeCurve<double>::clampCurveSegment(const double& delta,double& d1,double& d2)
00228 {
00229 if(delta==0) d1=d2=0;
00230 else{
00231 d1=SeExpr::clamp(d1/delta,0,3)*delta;
00232 d2=SeExpr::clamp(d2/delta,0,3)*delta;
00233 }
00234 }
00235
00236 template<>
00237 void SeCurve<SeVec3d>::clampCurveSegment(const SeVec3d& delta,SeVec3d& d1,SeVec3d& d2)
00238 {
00239 for(int i=0;i<3;i++){
00240 if(delta[i]==0) d1[i]=d2[i]=0;
00241 else{
00242 d1[i]=SeExpr::clamp(d1[i]/delta[i],0,3)*delta[i];
00243 d2[i]=SeExpr::clamp(d2[i]/delta[i],0,3)*delta[i];
00244 }
00245 }
00246 }
00247
00248 template class SeCurve<SeVec3d>;
00249 template class SeCurve<double>;
00250
00251 }