ACF $AcfVersion:0$
TSplineGridFunctionBase.h
Go to the documentation of this file.
1// SPDX-License-Identifier: LGPL-2.1-or-later OR GPL-2.0-or-later OR GPL-3.0-or-later OR LicenseRef-ACF-Commercial
2#pragma once
3
4
5// ACF includes
6#include <istd/TArray.h>
7#include <imath/TVector.h>
10
11
12namespace imath
13{
14
15
25template <class Argument, class Result, class Fulcrums, class Degree>
26class TSplineGridFunctionBase: public TFulcrumGridFunctionBase<Argument, Result, Fulcrums>
27{
28public:
30
31 typedef Degree DerivativeDegreeType;
32
33 // reimplemented (imath::TIMathFunction<Argument, Result>)
34 virtual bool GetValueAt(const Argument& argument, Result& result) const override;
35 virtual Result GetValueAt(const Argument& argument) const override;
36
37protected:
56 const Argument& argument,
57 int dimension,
58 const typename BaseClass::FulcrumSizes& sizes,
59 typename BaseClass::FulcrumIndex& index,
61 double cumulationFactor,
62 Result& result) const;
63
64 // abstract methods
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
83template <class Argument, class Result, class Fulcrums, class Degree>
84bool 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
108template <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
121template <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
static double GetValueKernelAt(double alpha)
Get kernel of value normalized to range [0, 1].
static double GetDerivativeKernelAt(double alpha)
Get kernel of derivative normalized to range [0, 1].
Base class for interpolated functions based on fulcrums in multi-dimesional grid.
Spline interpolation function using polynomial 3 degree segments.
virtual bool IsDerivativeDegreeSupported(const DerivativeDegreeType &degree) const =0
Check, if this or higher degree derrivatives are supported.
virtual bool GetValueAt(const Argument &argument, Result &result) const override
Get function value for specified argument value.
TFulcrumGridFunctionBase< Argument, Result, Fulcrums > BaseClass
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 const double I_BIG_EPSILON
Definition istd.h:26
Package with mathematical functions and algebraical primitives.