TSplineGridFunctionBase.h
Go to the documentation of this file.
1 #ifndef imath_TSplineGridFunctionBase_included
2 #define imath_TSplineGridFunctionBase_included
3 
4 
5 // ACF includes
6 #include <istd/TArray.h>
7 #include <imath/TVector.h>
10 
11 
12 namespace imath
13 {
14 
15 
25 template <class Argument, class Result, class Fulcrums, class Degree>
26 class TSplineGridFunctionBase: public TFulcrumGridFunctionBase<Argument, Result, Fulcrums>
27 {
28 public:
30 
31  typedef Degree DerivativeDegreeType;
32 
33  // reimplemented (imath::TIMathFunction<Argument, Result>)
34  virtual bool GetValueAt(const Argument& argument, Result& result) const;
35  virtual Result GetValueAt(const Argument& argument) const;
36 
37 protected:
56  const Argument& argument,
57  int dimension,
58  const typename BaseClass::FulcrumSizes& sizes,
59  typename BaseClass::FulcrumIndex& index,
60  DerivativeDegreeType& degree,
61  double cumulationFactor,
62  Result& result) const;
63 
64  // abstract methods
68  virtual const typename BaseClass::ResultType& GetFulcrumDerivativeAtIndex(
69  const typename BaseClass::FulcrumIndex& index,
70  const DerivativeDegreeType& degree) const = 0;
71 
75  virtual bool IsDerivativeDegreeSupported(const DerivativeDegreeType& degree) const = 0;
76 };
77 
78 
79 // public methods
80 
81 // reimplemented (imath::TIMathFunction<Argument, Result>)
82 
83 template <class Argument, class Result, class Fulcrums, class Degree>
84 bool TSplineGridFunctionBase<Argument, Result, Fulcrums, Degree>::GetValueAt(const Argument& argument, Result& result) const
85 {
86  result.Clear();
87 
88  if (BaseClass::EnsureCacheValid()){
89  typename BaseClass::FulcrumIndex index = this->FindIndices(argument);
90 
91  typename BaseClass::FulcrumSizes gridSize = BaseClass::GetGridSize();
92 
93  if (index.IsInside(gridSize)){
94  int dimensionsCount = BaseClass::GetDimensionsCount();
95  Degree degree;
96  degree.SetDimensionsCount(dimensionsCount);
97 
98  CumulateRecursiveValueAt(argument, dimensionsCount - 1, gridSize, index, degree, 1.0, result);
99 
100  return true;
101  }
102  }
103 
104  return false;
105 }
106 
107 
108 template <class Argument, class Result, class Fulcrums, class Degree>
110 {
111  typename BaseClass::ResultType retVal;
112 
113  GetValueAt(argument, retVal);
114 
115  return retVal;
116 }
117 
118 
119 // protected methods
120 
121 template <class Argument, class Result, class Fulcrums, class Degree>
123  const Argument& argument,
124  int dimension,
125  const typename BaseClass::FulcrumSizes& sizes,
126  typename BaseClass::FulcrumIndex& index,
127  DerivativeDegreeType& derivativeDegree,
128  double cumulationFactor,
129  Result& result) const
130 {
131  Q_ASSERT(dimension < BaseClass::GetDimensionsCount());
132  Q_ASSERT(sizes.GetDimensionsCount() == BaseClass::GetDimensionsCount());
133  Q_ASSERT(index.GetDimensionsCount() == BaseClass::GetDimensionsCount());
134 
135  if (dimension < 0){
136  result.ScaledCumulate(GetFulcrumDerivativeAtIndex(index, derivativeDegree), cumulationFactor);
137 
138  return;
139  }
140 
141  int& indexElement = index[dimension];
142 
143  if (indexElement >= 0){
144  if (indexElement < sizes[dimension] - 1){
145  double firstPosition = BaseClass::GetLayerPosition(dimension, indexElement);
146  double secondPosition = BaseClass::GetLayerPosition(dimension, indexElement + 1);
147  double layersDistance = secondPosition - firstPosition;
148  Q_ASSERT(layersDistance >= 0);
149  Q_ASSERT(argument[dimension] >= firstPosition);
150  Q_ASSERT(argument[dimension] <= secondPosition);
151  Q_ASSERT(derivativeDegree[dimension] == 0);
152 
153  bool useDerivative = false;
154  if (derivativeDegree.IncreaseAt(dimension)){
155  useDerivative = IsDerivativeDegreeSupported(derivativeDegree);
156  derivativeDegree.DecreaseAt(dimension);
157  }
158 
159  double alpha = (argument[dimension] - firstPosition) / layersDistance;
160 
161  double firstValueFactor = useDerivative? CSplineSegmentFunction::GetValueKernelAt(alpha): (1 - alpha); // use linear interpolation if no derivative is available
162  if (firstValueFactor > I_BIG_EPSILON){
163  CumulateRecursiveValueAt(
164  argument,
165  dimension - 1,
166  sizes,
167  index,
168  derivativeDegree,
169  cumulationFactor * firstValueFactor,
170  result);
171  }
172 
173  double secondValueFactor = useDerivative? CSplineSegmentFunction::GetValueKernelAt(1.0 - alpha): alpha; // use linear interpolation if no derivative is available
174 
175  if (secondValueFactor > I_BIG_EPSILON){
176  ++indexElement;
177  CumulateRecursiveValueAt(
178  argument,
179  dimension - 1,
180  sizes,
181  index,
182  derivativeDegree,
183  cumulationFactor * secondValueFactor,
184  result);
185  --indexElement;
186  }
187 
188  if (useDerivative){
189  derivativeDegree.IncreaseAt(dimension);
190 
191  double firstDerivativeFactor = CSplineSegmentFunction::GetDerivativeKernelAt(alpha) * layersDistance;
192  if (firstDerivativeFactor > I_BIG_EPSILON){
193  CumulateRecursiveValueAt(
194  argument,
195  dimension - 1,
196  sizes,
197  index,
198  derivativeDegree,
199  cumulationFactor * firstDerivativeFactor,
200  result);
201  }
202 
203  ++indexElement;
204 
205  double secondDerivativeFactor = -CSplineSegmentFunction::GetDerivativeKernelAt(1.0 - alpha) * layersDistance;
206  if (secondDerivativeFactor < -I_BIG_EPSILON){
207  CumulateRecursiveValueAt(
208  argument,
209  dimension - 1,
210  sizes,
211  index,
212  derivativeDegree,
213  cumulationFactor * secondDerivativeFactor,
214  result);
215  }
216 
217  --indexElement;
218 
219  derivativeDegree.DecreaseAt(dimension);
220  }
221  }
222  else{
223  // element out of boundaries at this dimension
224  Q_ASSERT(indexElement == sizes[dimension] - 1);
225 
226  CumulateRecursiveValueAt(
227  argument,
228  dimension - 1,
229  sizes,
230  index,
231  derivativeDegree,
232  cumulationFactor,
233  result);
234  }
235  }
236  else{
237  // element out of boundaries at this dimension
238  Q_ASSERT(indexElement == -1);
239 
240  ++indexElement;
241  CumulateRecursiveValueAt(
242  argument,
243  dimension - 1,
244  sizes,
245  index,
246  derivativeDegree,
247  cumulationFactor,
248  result);
249  --indexElement;
250  }
251 }
252 
253 
254 } // namespace imath
255 
256 
257 #endif // !imath_TSplineGridFunctionBase_included
258 
259 
virtual bool GetValueAt(const Argument &argument, Result &result) const
Get function value for specified argument value.
Base class for interpolated functions based on fulcrums in multi-dimesional grid. ...
virtual bool IsDerivativeDegreeSupported(const DerivativeDegreeType &degree) const =0
Check, if this or higher degree derrivatives are supported.
static double GetDerivativeKernelAt(double alpha)
Get kernel of derivative normalized to range [0, 1].
TFulcrumGridFunctionBase< Argument, Result, Fulcrums > BaseClass
Spline interpolation function using polynomial 3 degree segments.
static const double I_BIG_EPSILON
Definition: istd.h:26
void CumulateRecursiveValueAt(const Argument &argument, int dimension, const typename BaseClass::FulcrumSizes &sizes, typename BaseClass::FulcrumIndex &index, DerivativeDegreeType &degree, double cumulationFactor, Result &result) const
Cumulate interpolated value or derivative at specified recursion level.
virtual const BaseClass::ResultType & GetFulcrumDerivativeAtIndex(const typename BaseClass::FulcrumIndex &index, const DerivativeDegreeType &degree) const =0
Get derivative of specified degree at specified index position.
static double GetValueKernelAt(double alpha)
Get kernel of value normalized to range [0, 1].

© 2007-2017 Witold Gantzke and Kirill Lepskiy