library of assembled shared sources

http://lass.cocamware.com

spline_bezier_path.inl

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  Distributed under the terms of the GPL (GNU Public License)
00006  *
00007  *  The LASS License:
00008  *
00009  *  Copyright 2004-2006 Bram de Greve and Tom De Muer
00010  *
00011  *  LASS is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public License
00022  *  along with this program; if not, write to the Free Software
00023  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 // --- public --------------------------------------------------------------------------------------
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     // (6-6*t)*A+(18*t-12)*B+(-18*t+6)*C+6*t*D
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     // -1/4*(1-t)^4*A+3*B*(1/4*t^4-2/3*t^3+1/2*t^2)+3*C*(-1/4*t^4+1/3*t^3)+1/4*t^4*D
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         //const TScalar s4 = num::sqr(num::sqr(1 - end)) - num::sqr(num::sqr(1 - begin));
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 /** return true if the spline contains any nodes at all.
00270  *  @par complexity: 
00271  *      O(1)
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 /** return the range of control values for which the spline can interpolate.
00282  *  @par complexity: 
00283  *      O(1)
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 // --- private -------------------------------------------------------------------------------------
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& /* dummy */)
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& /* dummy */)
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& /* dummy */)
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& /* dummy */)
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     // are there any nodes at all?  we need at least one!
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         // check for increasing control components
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         // check dimension of data
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 /** binary search to find node that belongs to x
00453  *
00454  *  @return
00455  *  @arg the iterator to node such that @a x is in the interval [@c node->x, @c next(node)->x)
00456  *  @arg nodes_.begin() @a x is smaller than @c nodes_.front().x</tt>
00457  *  @arg prev(nodes_.end(), 2) if @a x is greater than @c nodes_.back().x
00458  *
00459  *  complexity: O(ln N)
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     // early outs
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     // binary search
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 // EOF

Generated on Mon Nov 10 14:21:39 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo