00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifndef LASS_GUARDIAN_OF_INCLUSION_NUM_SPLINE_BEZIER_PATH_INL
00029 #define LASS_GUARDIAN_OF_INCLUSION_NUM_SPLINE_BEZIER_PATH_INL
00030
00031 #include "num_common.h"
00032 #include "spline_bezier_path.h"
00033 #include "../stde/extended_iterator.h"
00034
00035 namespace lass
00036 {
00037 namespace num
00038 {
00039
00040
00041
00042 template <typename S, typename D, typename T>
00043 SplineBezierPath<S, D, T>::SplineBezierPath()
00044 {
00045 }
00046
00047
00048
00049 template <typename S, typename D, typename T>
00050 template <typename PairInputIterator>
00051 SplineBezierPath<S, D, T>::SplineBezierPath(
00052 PairInputIterator first, PairInputIterator last)
00053 {
00054 init(first, last, first->second);
00055 }
00056
00057
00058
00059 template <typename S, typename D, typename T>
00060 template <typename ScalarInputIterator, typename DataInputIterator>
00061 SplineBezierPath<S, D, T>::SplineBezierPath(ScalarInputIterator firstControl,
00062 ScalarInputIterator lastControl,
00063 DataInputIterator firstData)
00064 {
00065 init(firstControl, lastControl, firstData, *firstData);
00066 }
00067
00068
00069
00070 template <typename S, typename D, typename T>
00071 const typename SplineBezierPath<S, D, T>::TData
00072 SplineBezierPath<S, D, T>::operator ()(TScalar x) const
00073 {
00074 LASS_ASSERT(!isEmpty());
00075
00076 const typename TNodes::const_iterator first = findNode(x);
00077 LASS_ASSERT(first != nodes_.end());
00078 const typename TNodes::const_iterator second = stde::next(first);
00079 LASS_ASSERT(second != nodes_.end());
00080
00081 const TData& a = first->knot();
00082 const TData& b = first->right();
00083 const TData& c = second->left();
00084 const TData& d = second->knot();
00085
00086 const TScalar t = (x - first->x) / (second->x - first->x);
00087 const TScalar s = 1 - t;
00088
00089 TData y(a);
00090 TDataTraits::scale(y, s * s * s);
00091 TDataTraits::multiplyAccumulate(y, b, 3 * s * s * t);
00092 TDataTraits::multiplyAccumulate(y, c, 3 * s * t * t);
00093 TDataTraits::multiplyAccumulate(y, d, t * t * t);
00094 return y;
00095
00096 }
00097
00098
00099
00100 template <typename S, typename D, typename T>
00101 const typename SplineBezierPath<S, D, T>::TData
00102 SplineBezierPath<S, D, T>::derivative(TScalar x) const
00103 {
00104 LASS_ASSERT(!isEmpty());
00105
00106 const typename TNodes::const_iterator first = findNode(x);
00107 LASS_ASSERT(first != nodes_.end());
00108 const typename TNodes::const_iterator second = stde::next(first);
00109 LASS_ASSERT(second != nodes_.end());
00110
00111 const TData& a = first->knot();
00112 const TData& b = first->right();
00113 const TData& c = second->left();
00114 const TData& d = second->knot();
00115 const TScalar t = (x - first->x) / (second->x - first->x);
00116 const TScalar s = 1 - t;
00117
00118 TData dy = a;
00119 TDataTraits::scale(dy, -3 * s * s);
00120 TDataTraits::multiplyAccumulate(dy, b, 3 * s * (s - 2 * t));
00121 TDataTraits::multiplyAccumulate(dy, c, 3 * t * (2 * s - t));
00122 TDataTraits::multiplyAccumulate(dy, d, 3 * t * t);
00123 TDataTraits::scale(dy, num::inv(second->x - first->x));
00124 return dy;
00125 }
00126
00127
00128
00129 template <typename S, typename D, typename T>
00130 const typename SplineBezierPath<S, D, T>::TData
00131 SplineBezierPath<S, D, T>::derivative2(TScalar x) const
00132 {
00133 LASS_ASSERT(!isEmpty());
00134
00135 const typename TNodes::const_iterator first = findNode(x);
00136 LASS_ASSERT(first != nodes_.end());
00137 const typename TNodes::const_iterator second = stde::next(first);
00138 LASS_ASSERT(second != nodes_.end());
00139
00140 const TData& a = first->knot();
00141 const TData& b = first->right();
00142 const TData& c = second->left();
00143 const TData& d = second->knot();
00144 const TScalar dx = second->x - first->x;
00145 const TScalar t = (x - first->x) / dx;
00146
00147
00148
00149 TData dy = a;
00150 TDataTraits::scale(dy, 6 - 6 * t);
00151 TDataTraits::multiplyAccumulate(dy, b, 18 * t - 12);
00152 TDataTraits::multiplyAccumulate(dy, c, -18 * t + 6);
00153 TDataTraits::multiplyAccumulate(dy, d, 6 * t);
00154 TDataTraits::scale(dy, num::inv(num::sqr(dx)));
00155 return dy;
00156 }
00157
00158
00159
00160 template <typename S, typename D, typename T>
00161 const typename SplineBezierPath<S, D, T>::TData
00162 SplineBezierPath<S, D, T>::integral(TScalar begin, TScalar end) const
00163 {
00164
00165
00166 LASS_ASSERT(!isEmpty());
00167
00168 typename TNodes::const_iterator first = findNode(begin);
00169 LASS_ASSERT(first != nodes_.end());
00170 typename TNodes::const_iterator last = findNode(end);
00171 LASS_ASSERT(last != nodes_.end());
00172
00173 if (first == last)
00174 {
00175 const typename TNodes::const_iterator second = stde::next(first);
00176 LASS_ASSERT(second != nodes_.end());
00177
00178 const TData& a = first->knot();
00179 const TData& b = first->right();
00180 const TData& c = second->left();
00181 const TData& d = second->knot();
00182
00183 const TScalar dx = second->x - first->x;
00184 const TScalar invDx = num::inv(dx);
00185 const TScalar s = invDx * (begin - first->x);
00186 const TScalar t = invDx * (end - first->x);
00187
00188 const TScalar st = t - s;
00189 const TScalar st2 = num::sqr(t) - num::sqr(s);
00190 const TScalar st3 = num::cubic(t) - num::cubic(s);
00191 const TScalar st4 = num::sqr(num::sqr(t)) - num::sqr(num::sqr(s));
00192
00193
00194 TData inty(a);
00195 TDataTraits::scale(inty, dx * (-.25f * st4 + st3 - 1.5f * st2 + st));
00196 TDataTraits::multiplyAccumulate(inty, b, dx * (.75f * st4 - 2 * st3 + 1.5f * st2));
00197 TDataTraits::multiplyAccumulate(inty, c, dx * (-.75f * st4 + st3));
00198 TDataTraits::multiplyAccumulate(inty, d, dx * .25f * st4);
00199 TDataTraits::scale(inty, second->x - first->x);
00200 return inty;
00201 }
00202 else
00203 {
00204 TScalar multiplier = 1;
00205 if (end < begin)
00206 {
00207 std::swap(begin, end);
00208 std::swap(first, last);
00209 multiplier = -1;
00210 }
00211
00212 typename TNodes::const_iterator second = stde::next(first);
00213 LASS_ASSERT(second != nodes_.end());
00214
00215 TData inty(first->knot());
00216 {
00217 const TScalar dx = second->x - first->x;
00218 const TScalar s = (begin - first->x) / dx;
00219 const TScalar s2 = num::sqr(s);
00220 const TScalar s3 = num::cubic(s);
00221 const TScalar s4 = num::sqr(s2);
00222
00223 TDataTraits::scale(inty, dx * (.25f + .25f * s4 - s3 + 1.5f * s2 - s));
00224 TDataTraits::multiplyAccumulate(inty, first->right(), dx * (.25f - .75f * s4 + 2 * s3 - 1.5f * s2));
00225 TDataTraits::multiplyAccumulate(inty, second->left(), dx * (.25f + .75f * s4 - s3));
00226 TDataTraits::multiplyAccumulate(inty, second->knot(), dx * .25f * (1 - s4));
00227 }
00228
00229 first = second;
00230 second += 1;
00231 LASS_ASSERT(second != nodes_.end());
00232
00233 while (first != last)
00234 {
00235 const TScalar dx = second->x - first->x;
00236 TDataTraits::multiplyAccumulate(inty, first->knot(), dx * .25f);
00237 TDataTraits::multiplyAccumulate(inty, first->right(), dx * .25f);
00238 TDataTraits::multiplyAccumulate(inty, second->left(), dx * .25f);
00239 TDataTraits::multiplyAccumulate(inty, second->knot(), dx * .25f);
00240 first = second;
00241 second += 1;
00242 LASS_ASSERT(second != nodes_.end());
00243 }
00244
00245 {
00246 const TScalar dx = second->x - first->x;
00247 const TScalar t = (end - first->x) / dx;
00248 const TScalar t2 = num::sqr(t);
00249 const TScalar t3 = num::cubic(t);
00250 const TScalar t4 = num::sqr(t2);
00251
00252 TDataTraits::multiplyAccumulate(inty, first->knot(),
00253 dx * (-.25f * t4 + t3 - 1.5f * t2 + t));
00254 TDataTraits::multiplyAccumulate(inty, first->right(),
00255 dx * (.75f * t4 - 2 * t3 + 1.5f * t2));
00256 TDataTraits::multiplyAccumulate(inty, second->left(),
00257 dx * (-.75f * t4 + t3));
00258 TDataTraits::multiplyAccumulate(inty, second->knot(),
00259 dx * .25f * t4);
00260 }
00261
00262 TDataTraits::scale(inty, multiplier);
00263 return inty;
00264 }
00265 }
00266
00267
00268
00269
00270
00271
00272
00273 template <typename S, typename D, typename T>
00274 const bool SplineBezierPath<S, D, T>::isEmpty() const
00275 {
00276 return nodes_.empty();
00277 }
00278
00279
00280
00281
00282
00283
00284
00285 template <typename S, typename D, typename T>
00286 const typename SplineBezierPath<S, D, T>::TControlRange
00287 SplineBezierPath<S, D, T>::controlRange() const
00288 {
00289 return TControlRange(nodes_.front().x, nodes_.back().x);
00290 }
00291
00292
00293
00294
00295
00296 template <typename S, typename D, typename T>
00297 template <typename PairInputIterator>
00298 void SplineBezierPath<S, D, T>::init(
00299 PairInputIterator first, PairInputIterator last, const DataTriplet& )
00300 {
00301 while (first != last)
00302 {
00303 Node node;
00304 node.x = first->first;
00305 node.triplet = first->second;
00306 nodes_.push_back(node);
00307 ++first;
00308 }
00309 finalInit();
00310 }
00311
00312 template <typename S, typename D, typename T>
00313 template <typename PairInputIterator>
00314 void SplineBezierPath<S, D, T>::init(
00315 PairInputIterator first, PairInputIterator last, const TData& )
00316 {
00317 TSimpleNodes simpleNodes;
00318 std::copy(first, last, std::back_inserter(simpleNodes));
00319 makeFullNodes(simpleNodes);
00320 finalInit();
00321 }
00322
00323 template <typename S, typename D, typename T>
00324 template <typename ScalarInputIterator, typename DataInputIterator>
00325 void SplineBezierPath<S, D, T>::init(
00326 ScalarInputIterator firstControl, ScalarInputIterator lastControl,
00327 DataInputIterator firstData, const DataTriplet& )
00328 {
00329 while (firstControl != lastControl)
00330 {
00331 Node node;
00332 node.x = *firstControl++;
00333 node.triplet = *firstData++;
00334 nodes_.push_back(node);
00335 }
00336 finalInit();
00337 }
00338
00339 template <typename S, typename D, typename T>
00340 template <typename ScalarInputIterator, typename DataInputIterator>
00341 void SplineBezierPath<S, D, T>::init(
00342 ScalarInputIterator firstControl, ScalarInputIterator lastControl,
00343 DataInputIterator firstData, const TData& )
00344 {
00345 TSimpleNodes simpleNodes;
00346 while (firstControl != lastControl)
00347 {
00348 simpleNodes.push_back(std::make_pair(*firstControl++, *firstData++));
00349 }
00350 makeFullNodes(simpleNodes);
00351 finalInit();
00352 }
00353
00354 template <typename S, typename D, typename T>
00355 void SplineBezierPath<S, D, T>::makeFullNodes(const TSimpleNodes& simpleNodes)
00356 {
00357 const TScalar dt = TScalar(1) / 3;
00358 const typename TNodes::size_type size = simpleNodes.size();
00359
00360 TNodes nodes;
00361 switch (size)
00362 {
00363 case 0:
00364 break;
00365
00366 case 1:
00367 {
00368 const TData& knot = simpleNodes[0].second;
00369 TData null;
00370 TDataTraits::zero(null, TDataTraits::dimension(knot));
00371 nodes.push_back(Node(DataTriplet(null, knot, null), simpleNodes[0].first));
00372 }
00373 break;
00374
00375 default:
00376 {
00377 const TData& knot = simpleNodes[0].second;
00378 TData dy = simpleNodes[1].second;
00379 TDataTraits::multiplyAccumulate(dy, knot, -1);
00380 TData right = knot;
00381 TDataTraits::multiplyAccumulate(right, dy, dt);
00382 TData left = knot;
00383 TDataTraits::multiplyAccumulate(left, dy, -dt);
00384 nodes.push_back(Node(DataTriplet(left, knot, right), simpleNodes[0].first));
00385 }
00386
00387 for (size_t i = 1; i < size - 1; ++i)
00388 {
00389 const TData& knot = simpleNodes[i].second;
00390 TData dy = simpleNodes[i + 1].second;
00391 TDataTraits::multiplyAccumulate(dy, simpleNodes[i - 1].second, -1);
00392 TDataTraits::scale(dy, .5);
00393 TData right = knot;
00394 TDataTraits::multiplyAccumulate(right, dy, dt);
00395 TData left = knot;
00396 TDataTraits::multiplyAccumulate(left, dy, -dt);
00397 nodes.push_back(Node(DataTriplet(left, knot, right), simpleNodes[i].first));
00398 }
00399
00400 {
00401 const TData& knot = simpleNodes[size - 1].second;
00402 TData dy = knot;
00403 TDataTraits::multiplyAccumulate(dy, simpleNodes[size - 2].second, -1);
00404 TData right = knot;
00405 TDataTraits::multiplyAccumulate(right, dy, dt);
00406 TData left = knot;
00407 TDataTraits::multiplyAccumulate(left, dy, -dt);
00408 nodes.push_back(Node(DataTriplet(left, knot, right), simpleNodes[size - 1].first));
00409 }
00410 }
00411
00412 nodes_.swap(nodes);
00413 }
00414
00415 template <typename S, typename D, typename T>
00416 void SplineBezierPath<S, D, T>::finalInit()
00417 {
00418
00419
00420 const typename TNodes::size_type size = nodes_.size();
00421 if (size < 1)
00422 {
00423 LASS_THROW("A bezier path interpolator needs at least one node!");
00424 }
00425
00426 typename TNodes::iterator prev = nodes_.begin();
00427 dataDimension_ = TDataTraits::dimension(prev->knot());
00428 const typename TNodes::iterator end = nodes_.end();
00429 for (typename TNodes::iterator i = stde::next(nodes_.begin()); i != end; prev = i++)
00430 {
00431
00432
00433 if (prev->x >= i->x)
00434 {
00435 LASS_THROW("Nodes in bezier path interpolator must have absolutely increasing control "
00436 "values.");
00437 }
00438
00439
00440
00441 if (TDataTraits::dimension(i->left()) != dataDimension_ ||
00442 TDataTraits::dimension(i->knot()) != dataDimension_ ||
00443 TDataTraits::dimension(i->right()) != dataDimension_)
00444 {
00445 LASS_THROW("All data in linear interpolator must be of same dimension.");
00446 }
00447 }
00448 }
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461 template <typename S, typename D, typename T>
00462 const typename SplineBezierPath<S, D, T>::TNodeConstIterator
00463 SplineBezierPath<S, D, T>::findNode(TScalar x) const
00464 {
00465 LASS_ASSERT(nodes_.size() >= 2);
00466
00467
00468
00469 if (x < nodes_.front().x)
00470 {
00471 return nodes_.begin();
00472 }
00473 if (x >= nodes_.back().x)
00474 {
00475 return stde::prev(nodes_.end(), 2);
00476 }
00477
00478
00479
00480 TNodeConstIterator first = nodes_.begin();
00481 TNodeConstIterator last = nodes_.end();
00482 while (stde::next(first) != last)
00483 {
00484 TNodeConstIterator middle = stde::next(first, std::distance(first, last) / 2);
00485 LASS_ASSERT(middle != first && middle != last);
00486
00487 if (middle->x <= x)
00488 {
00489 first = middle;
00490 }
00491 else
00492 {
00493 last = middle;
00494 }
00495 LASS_ASSERT(first != last);
00496 }
00497
00498 LASS_ASSERT(first->x <= x && last->x > x);
00499 return first;
00500 }
00501
00502
00503 }
00504
00505 }
00506
00507 #endif
00508
00509