28#ifndef LASS_GUARDIAN_OF_INCLUSION_NUM_SPLINE_BEZIER_PATH_INL
29#define LASS_GUARDIAN_OF_INCLUSION_NUM_SPLINE_BEZIER_PATH_INL
42template <
typename S,
typename D,
typename T>
43SplineBezierPath<S, D, T>::SplineBezierPath()
49template <
typename S,
typename D,
typename T>
50template <
typename PairInputIterator>
51SplineBezierPath<S, D, T>::SplineBezierPath(
52 PairInputIterator first, PairInputIterator last)
54 init(first, last, first->second);
59template <
typename S,
typename D,
typename T>
60template <
typename ScalarInputIterator,
typename DataInputIterator>
61SplineBezierPath<S, D, T>::SplineBezierPath(ScalarInputIterator firstControl,
62 ScalarInputIterator lastControl,
63 DataInputIterator firstData)
65 init(firstControl, lastControl, firstData, *firstData);
70template <
typename S,
typename D,
typename T>
71const typename SplineBezierPath<S, D, T>::TData
74 LASS_ASSERT(!isEmpty());
76 const typename TNodes::const_iterator first = findNode(x);
77 LASS_ASSERT(first != nodes_.end());
78 const typename TNodes::const_iterator second = stde::next(first);
79 LASS_ASSERT(second != nodes_.end());
81 const TData& a = first->knot();
82 const TData& b = first->right();
83 const TData& c = second->left();
84 const TData& d = second->knot();
86 const TScalar t = (x - first->x) / (second->x - first->x);
87 const TScalar s = 1 - t;
90 TDataTraits::scale(y, s * s * s);
91 TDataTraits::multiplyAccumulate(y, b, 3 * s * s * t);
92 TDataTraits::multiplyAccumulate(y, c, 3 * s * t * t);
93 TDataTraits::multiplyAccumulate(y, d, t * t * t);
100template <
typename S,
typename D,
typename T>
101const typename SplineBezierPath<S, D, T>::TData
102SplineBezierPath<S, D, T>::derivative(TScalar x)
const
104 LASS_ASSERT(!isEmpty());
106 const typename TNodes::const_iterator first = findNode(x);
107 LASS_ASSERT(first != nodes_.end());
108 const typename TNodes::const_iterator second = stde::next(first);
109 LASS_ASSERT(second != nodes_.end());
111 const TData& a = first->knot();
112 const TData& b = first->right();
113 const TData& c = second->left();
114 const TData& d = second->knot();
115 const TScalar t = (x - first->x) / (second->x - first->x);
116 const TScalar s = 1 - t;
119 TDataTraits::scale(dy, -3 * s * s);
120 TDataTraits::multiplyAccumulate(dy, b, 3 * s * (s - 2 * t));
121 TDataTraits::multiplyAccumulate(dy, c, 3 * t * (2 * s - t));
122 TDataTraits::multiplyAccumulate(dy, d, 3 * t * t);
123 TDataTraits::scale(dy,
num::inv(second->x - first->x));
129template <
typename S,
typename D,
typename T>
130const typename SplineBezierPath<S, D, T>::TData
131SplineBezierPath<S, D, T>::derivative2(TScalar x)
const
133 LASS_ASSERT(!isEmpty());
135 const typename TNodes::const_iterator first = findNode(x);
136 LASS_ASSERT(first != nodes_.end());
137 const typename TNodes::const_iterator second = stde::next(first);
138 LASS_ASSERT(second != nodes_.end());
140 const TData& a = first->knot();
141 const TData& b = first->right();
142 const TData& c = second->left();
143 const TData& d = second->knot();
144 const TScalar dx = second->x - first->x;
145 const TScalar t = (x - first->x) / dx;
150 TDataTraits::scale(dy, 6 - 6 * t);
151 TDataTraits::multiplyAccumulate(dy, b, 18 * t - 12);
152 TDataTraits::multiplyAccumulate(dy, c, -18 * t + 6);
153 TDataTraits::multiplyAccumulate(dy, d, 6 * t);
160template <
typename S,
typename D,
typename T>
161const typename SplineBezierPath<S, D, T>::TData
162SplineBezierPath<S, D, T>::integral(TScalar begin, TScalar end)
const
166 LASS_ASSERT(!isEmpty());
168 typename TNodes::const_iterator first = findNode(begin);
169 LASS_ASSERT(first != nodes_.end());
170 typename TNodes::const_iterator last = findNode(end);
171 LASS_ASSERT(last != nodes_.end());
175 const typename TNodes::const_iterator second = stde::next(first);
176 LASS_ASSERT(second != nodes_.end());
178 const TData& a = first->knot();
179 const TData& b = first->right();
180 const TData& c = second->left();
181 const TData& d = second->knot();
183 const TScalar dx = second->x - first->x;
185 const TScalar s = invDx * (begin - first->x);
186 const TScalar t = invDx * (end - first->x);
188 const TScalar st = t - s;
195 TDataTraits::scale(inty, dx * (-.25f * st4 + st3 - 1.5f * st2 + st));
196 TDataTraits::multiplyAccumulate(inty, b, dx * (.75f * st4 - 2 * st3 + 1.5f * st2));
197 TDataTraits::multiplyAccumulate(inty, c, dx * (-.75f * st4 + st3));
198 TDataTraits::multiplyAccumulate(inty, d, dx * .25f * st4);
199 TDataTraits::scale(inty, second->x - first->x);
204 TScalar multiplier = 1;
207 std::swap(begin, end);
208 std::swap(first, last);
212 typename TNodes::const_iterator second = stde::next(first);
213 LASS_ASSERT(second != nodes_.end());
215 TData inty(first->knot());
217 const TScalar dx = second->x - first->x;
218 const TScalar s = (begin - first->x) / dx;
223 TDataTraits::scale(inty, dx * (.25f + .25f * s4 - s3 + 1.5f * s2 - s));
224 TDataTraits::multiplyAccumulate(inty, first->right(), dx * (.25f - .75f * s4 + 2 * s3 - 1.5f * s2));
225 TDataTraits::multiplyAccumulate(inty, second->left(), dx * (.25f + .75f * s4 - s3));
226 TDataTraits::multiplyAccumulate(inty, second->knot(), dx * .25f * (1 - s4));
231 LASS_ASSERT(second != nodes_.end());
233 while (first != last)
235 const TScalar dx = second->x - first->x;
236 TDataTraits::multiplyAccumulate(inty, first->knot(), dx * .25f);
237 TDataTraits::multiplyAccumulate(inty, first->right(), dx * .25f);
238 TDataTraits::multiplyAccumulate(inty, second->left(), dx * .25f);
239 TDataTraits::multiplyAccumulate(inty, second->knot(), dx * .25f);
242 LASS_ASSERT(second != nodes_.end());
246 const TScalar dx = second->x - first->x;
247 const TScalar t = (end - first->x) / dx;
252 TDataTraits::multiplyAccumulate(inty, first->knot(),
253 dx * (-.25f * t4 + t3 - 1.5f * t2 + t));
254 TDataTraits::multiplyAccumulate(inty, first->right(),
255 dx * (.75f * t4 - 2 * t3 + 1.5f * t2));
256 TDataTraits::multiplyAccumulate(inty, second->left(),
257 dx * (-.75f * t4 + t3));
258 TDataTraits::multiplyAccumulate(inty, second->knot(),
262 TDataTraits::scale(inty, multiplier);
273template <
typename S,
typename D,
typename T>
276 return nodes_.empty();
285template <
typename S,
typename D,
typename T>
286const typename SplineBezierPath<S, D, T>::TControlRange
289 return TControlRange(nodes_.front().x, nodes_.back().x);
296template <
typename S,
typename D,
typename T>
297template <
typename PairInputIterator>
298void SplineBezierPath<S, D, T>::init(
299 PairInputIterator first, PairInputIterator last,
const DataTriplet& )
301 while (first != last)
304 node.x = first->first;
305 node.triplet = first->second;
306 nodes_.push_back(node);
312template <
typename S,
typename D,
typename T>
313template <
typename PairInputIterator>
314void SplineBezierPath<S, D, T>::init(
315 PairInputIterator first, PairInputIterator last,
const TData& )
317 TSimpleNodes simpleNodes;
318 std::copy(first, last, std::back_inserter(simpleNodes));
319 makeFullNodes(simpleNodes);
323template <
typename S,
typename D,
typename T>
324template <
typename ScalarInputIterator,
typename DataInputIterator>
325void SplineBezierPath<S, D, T>::init(
326 ScalarInputIterator firstControl, ScalarInputIterator lastControl,
327 DataInputIterator firstData,
const DataTriplet& )
329 while (firstControl != lastControl)
332 node.x = *firstControl++;
333 node.triplet = *firstData++;
334 nodes_.push_back(node);
339template <
typename S,
typename D,
typename T>
340template <
typename ScalarInputIterator,
typename DataInputIterator>
341void SplineBezierPath<S, D, T>::init(
342 ScalarInputIterator firstControl, ScalarInputIterator lastControl,
343 DataInputIterator firstData,
const TData& )
345 TSimpleNodes simpleNodes;
346 while (firstControl != lastControl)
348 simpleNodes.push_back(std::make_pair(*firstControl++, *firstData++));
350 makeFullNodes(simpleNodes);
354template <
typename S,
typename D,
typename T>
355void SplineBezierPath<S, D, T>::makeFullNodes(
const TSimpleNodes& simpleNodes)
357 const TScalar dt = TScalar(1) / 3;
358 const typename TNodes::size_type size = simpleNodes.size();
368 const TData& knot = simpleNodes[0].second;
370 TDataTraits::zero(null, TDataTraits::dimension(knot));
371 nodes.push_back(Node(DataTriplet(null, knot, null), simpleNodes[0].first));
377 const TData& knot = simpleNodes[0].second;
378 TData dy = simpleNodes[1].second;
379 TDataTraits::multiplyAccumulate(dy, knot, -1);
381 TDataTraits::multiplyAccumulate(right, dy, dt);
383 TDataTraits::multiplyAccumulate(left, dy, -dt);
384 nodes.push_back(Node(DataTriplet(left, knot, right), simpleNodes[0].first));
387 for (
size_t i = 1; i < size - 1; ++i)
389 const TData& knot = simpleNodes[i].second;
390 TData dy = simpleNodes[i + 1].second;
391 TDataTraits::multiplyAccumulate(dy, simpleNodes[i - 1].second, -1);
392 TDataTraits::scale(dy, .5);
394 TDataTraits::multiplyAccumulate(right, dy, dt);
396 TDataTraits::multiplyAccumulate(left, dy, -dt);
397 nodes.push_back(Node(DataTriplet(left, knot, right), simpleNodes[i].first));
401 const TData& knot = simpleNodes[size - 1].second;
403 TDataTraits::multiplyAccumulate(dy, simpleNodes[size - 2].second, -1);
405 TDataTraits::multiplyAccumulate(right, dy, dt);
407 TDataTraits::multiplyAccumulate(left, dy, -dt);
408 nodes.push_back(Node(DataTriplet(left, knot, right), simpleNodes[size - 1].first));
415template <
typename S,
typename D,
typename T>
416void SplineBezierPath<S, D, T>::finalInit()
420 const typename TNodes::size_type size = nodes_.size();
423 LASS_THROW(
"A bezier path interpolator needs at least one node!");
426 typename TNodes::iterator prev = nodes_.begin();
427 dataDimension_ = TDataTraits::dimension(prev->knot());
428 const typename TNodes::iterator end = nodes_.end();
429 for (
typename TNodes::iterator i = stde::next(nodes_.begin()); i != end; prev = i++)
435 LASS_THROW(
"Nodes in bezier path interpolator must have absolutely increasing control "
441 if (TDataTraits::dimension(i->left()) != dataDimension_ ||
442 TDataTraits::dimension(i->knot()) != dataDimension_ ||
443 TDataTraits::dimension(i->right()) != dataDimension_)
445 LASS_THROW(
"All data in linear interpolator must be of same dimension.");
461template <
typename S,
typename D,
typename T>
462const typename SplineBezierPath<S, D, T>::TNodeConstIterator
463SplineBezierPath<S, D, T>::findNode(TScalar x)
const
465 LASS_ASSERT(nodes_.size() >= 2);
469 if (x < nodes_.front().x)
471 return nodes_.begin();
473 if (x >= nodes_.back().x)
475 return stde::prev(nodes_.end(), 2);
480 TNodeConstIterator first = nodes_.begin();
481 TNodeConstIterator last = nodes_.end();
482 while (stde::next(first) != last)
484 TNodeConstIterator middle = stde::next(first, std::distance(first, last) / 2);
485 LASS_ASSERT(middle != first && middle != last);
495 LASS_ASSERT(first != last);
498 LASS_ASSERT(first->x <= x && last->x > x);
connects the data nodes with cubic bezier splines.
bool isEmpty() const override
return true if the spline contains any nodes at all.
const TControlRange controlRange() const override
return the range of control values for which the spline can interpolate.
T sqr(const T &x)
return x * x
T inv(const T &x)
return x ^ -1
T cubic(const T &x)
return x * x * x
numeric types and traits.
Library for Assembled Shared Sources.