[80a6a52] | 1 | #pragma once
|
---|
| 2 | #pragma warning(disable : 4290)
|
---|
| 3 |
|
---|
| 4 | #include <vector>
|
---|
| 5 | #include "mars_calc.h"
|
---|
| 6 | #include "coroutines.h"
|
---|
| 7 |
|
---|
| 8 | #include <assert.h>
|
---|
| 9 |
|
---|
| 10 | namespace mars
|
---|
| 11 | {
|
---|
| 12 | template <typename V, typename real = float>
|
---|
| 13 | class SplineBase
|
---|
| 14 | {
|
---|
| 15 | public:
|
---|
| 16 | typedef V VectorType;
|
---|
| 17 | typedef typename std::vector <V>::const_iterator PointsConstIterator;
|
---|
| 18 | typedef typename std::vector <V>::iterator PointsIterator;
|
---|
| 19 | typedef typename std::vector <V>::reverse_iterator PointsRIterator;
|
---|
| 20 | using Precision = real;
|
---|
| 21 |
|
---|
| 22 | protected:
|
---|
| 23 | real _M[4][4];
|
---|
| 24 |
|
---|
| 25 | struct MatV3x4
|
---|
| 26 | {
|
---|
| 27 | V p[4];
|
---|
| 28 |
|
---|
| 29 | inline const V & operator [] (const unsigned int i) const { return p[i]; }
|
---|
| 30 | inline V & operator [] (const unsigned int i) { return p[i]; }
|
---|
| 31 | };
|
---|
| 32 | std::vector< MatV3x4 > _M4p;
|
---|
| 33 |
|
---|
| 34 | private:
|
---|
| 35 | std::vector <V> _points;
|
---|
| 36 |
|
---|
| 37 | static const unsigned int
|
---|
| 38 | PAD_FRONT = 1, PAD_BACK = 2,
|
---|
| 39 | TOTAL_PAD = PAD_FRONT + PAD_BACK;
|
---|
| 40 |
|
---|
| 41 | void init (const std::vector <V> & points)
|
---|
| 42 | {
|
---|
| 43 | // Add padding points:
|
---|
| 44 | // - one at the beginning same as the first
|
---|
| 45 | // - two more at the end that toggle between the last two points in the original list
|
---|
| 46 | // NOTE: Dependency on this algorithm in CRSplineBase::move
|
---|
| 47 | assert(points.size() >= 2);
|
---|
| 48 |
|
---|
| 49 | _points.reserve(points.size() + TOTAL_PAD);
|
---|
| 50 | _points.insert(_points.begin(), 1, points.front());
|
---|
| 51 | _points.push_back(*(points.rbegin() + 1));
|
---|
| 52 | _points.push_back(points.back());
|
---|
| 53 |
|
---|
| 54 | _M4p.insert(_M4p.begin(), size(), MatV3x4());
|
---|
| 55 | computeMatrices();
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 | void computeMatrices ()
|
---|
| 59 | {
|
---|
| 60 | const unsigned int nSize = size();
|
---|
| 61 | for (unsigned int i = 0; i < nSize; ++i)
|
---|
| 62 | {
|
---|
| 63 | _M4p[i][0] = _M[0][0]*_points[i] + _M[0][1]*_points[i + 1] + _M[0][2]*_points[i + 2] + _M[0][3]*_points[i + 3];
|
---|
| 64 | _M4p[i][1] = _M[1][0]*_points[i] + _M[1][1]*_points[i + 1] + _M[1][2]*_points[i + 2] + _M[1][3]*_points[i + 3];
|
---|
| 65 | _M4p[i][2] = _M[2][0]*_points[i] + _M[2][1]*_points[i + 1] + _M[2][2]*_points[i + 2] + _M[2][3]*_points[i + 3];
|
---|
| 66 | _M4p[i][3] = _M[3][0]*_points[i] + _M[3][1]*_points[i + 1] + _M[3][2]*_points[i + 2] + _M[3][3]*_points[i + 3];
|
---|
| 67 | }
|
---|
| 68 | }
|
---|
| 69 |
|
---|
| 70 | public:
|
---|
| 71 |
|
---|
| 72 | SplineBase (const SplineBase & copy) : _points (copy._points), _M4p(copy._M4p)
|
---|
| 73 | { memcpy (_M, copy._M, sizeof (real) * 4 * 4); }
|
---|
| 74 |
|
---|
| 75 | SplineBase () : _M4p(NULL)
|
---|
| 76 | { _points.reserve(TOTAL_PAD + 2); }
|
---|
| 77 | SplineBase (const std::vector <V> & points) : _points (points)
|
---|
| 78 | { init(points); }
|
---|
| 79 |
|
---|
| 80 | const V compute( const unsigned int i, const real t0, const real t1, const real t2, const real t3) const
|
---|
| 81 | {
|
---|
| 82 | assert(i < size());
|
---|
| 83 | return t0 * _M4p[i][0] +
|
---|
| 84 | t1 * _M4p[i][1] +
|
---|
| 85 | t2 * _M4p[i][2] +
|
---|
| 86 | t3 * _M4p[i][3];
|
---|
| 87 | }
|
---|
| 88 | template <typename V3D>
|
---|
| 89 | void move (const real radius, const V3D & unormal)
|
---|
| 90 | {
|
---|
| 91 | const V3D & normal = unormal * radius;
|
---|
| 92 | unsigned int c = 0;
|
---|
| 93 | PointsIterator i = _points.begin() + 1;
|
---|
| 94 | PointsRIterator r = _points.rbegin();
|
---|
| 95 | V t1, t2;
|
---|
| 96 | const unsigned int nCount = size() - 1;
|
---|
| 97 |
|
---|
| 98 | t1 = U(compute (c++, 0, 1, 0, 0)) & normal;
|
---|
| 99 | while (c < nCount)
|
---|
| 100 | {
|
---|
| 101 | t2 = t1;
|
---|
| 102 | t1 = U(compute (c++, 0, 1, 0, 0)) & normal;
|
---|
| 103 | *i++ += t2;
|
---|
| 104 | }
|
---|
| 105 | t2 = t1;
|
---|
| 106 | t1 = U(compute(--c, 0, 1, 2, 3)) & normal;
|
---|
| 107 | *i++ += t2;
|
---|
| 108 | *i += t1;
|
---|
| 109 |
|
---|
| 110 | // Account for padding points, see class constructor for description
|
---|
| 111 | // NOTE: Dependency of point-padding algorithm in constructor
|
---|
| 112 | _points[0] = _points[1];
|
---|
| 113 | *r++ = *(i - 1);
|
---|
| 114 | *r++ = *i;
|
---|
| 115 |
|
---|
| 116 | // Recompute the cached matrices for each point
|
---|
| 117 | computeMatrices();
|
---|
| 118 | }
|
---|
| 119 |
|
---|
| 120 | // For the following points-list manipulation methods, the 2 and 3
|
---|
| 121 | // constants represent padding at the beginning and at the end
|
---|
| 122 | // TODO: Extract spline point padding offsets into constants
|
---|
| 123 | inline unsigned int size () const { return _points.size() - TOTAL_PAD; }
|
---|
| 124 | inline V & front () { return *begin(); }
|
---|
| 125 | inline const V & front () const { return *begin(); }
|
---|
| 126 | inline V & back () { return *(end() - 1); }
|
---|
| 127 | inline const V & back () const { return *(end() - 1); }
|
---|
| 128 | inline PointsConstIterator begin() const { return _points.begin() + PAD_FRONT; }
|
---|
| 129 | inline PointsConstIterator end() const { return _points.end() - PAD_BACK; }
|
---|
| 130 | inline PointsIterator begin() { return _points.begin() + PAD_FRONT; }
|
---|
| 131 | inline PointsIterator end() { return _points.end() - TOTAL_PAD; }
|
---|
| 132 | inline const V & operator [] (const unsigned int i) const
|
---|
| 133 | {
|
---|
| 134 | assert(i + PAD_FRONT < _points.size() - PAD_BACK);
|
---|
| 135 | return _points[i + PAD_FRONT];
|
---|
| 136 | }
|
---|
| 137 |
|
---|
| 138 | void operator += (const V & ptOffset)
|
---|
| 139 | {
|
---|
| 140 | for (PointsIterator i = _points.begin(); i != _points.end(); ++i)
|
---|
| 141 | *i += ptOffset;
|
---|
| 142 |
|
---|
| 143 | // Recompute the cached matrices for each point
|
---|
| 144 | computeMatrices();
|
---|
| 145 | }
|
---|
| 146 | };
|
---|
| 147 |
|
---|
| 148 | template <typename V, typename real = float>
|
---|
| 149 | class CubicBSplineBase : public SplineBase <V, real>
|
---|
| 150 | {
|
---|
| 151 | private:
|
---|
| 152 | // TODO: Optimize by initializing this matrix only once rather than each time a spline object is created
|
---|
| 153 | void init ()
|
---|
| 154 | {
|
---|
| 155 | SplineBase<V, real>::_M[0][0] = static_cast <real> (1.0/6.0);
|
---|
| 156 | SplineBase<V, real>::_M[0][1] = static_cast <real> (4.0/6.0);
|
---|
| 157 | SplineBase<V, real>::_M[0][2] = static_cast <real> (1/6.0);
|
---|
| 158 | SplineBase<V, real>::_M[0][3] = 0;
|
---|
| 159 |
|
---|
| 160 | SplineBase<V, real>::_M[1][0] = static_cast <real> (-3.0/6.0);
|
---|
| 161 | SplineBase<V, real>::_M[1][1] = static_cast <real> (0.0);
|
---|
| 162 | SplineBase<V, real>::_M[1][2] = static_cast <real> (3/6.0);
|
---|
| 163 | SplineBase<V, real>::_M[1][3] = 0;
|
---|
| 164 |
|
---|
| 165 | SplineBase<V, real>::_M[2][0] = static_cast <real> (3.0/6.0);
|
---|
| 166 | SplineBase<V, real>::_M[2][1] = static_cast <real> (-6.0/6.0);
|
---|
| 167 | SplineBase<V, real>::_M[2][2] = static_cast <real> (3/6.0);
|
---|
| 168 | SplineBase<V, real>::_M[2][3] = 0;
|
---|
| 169 |
|
---|
| 170 | SplineBase<V, real>::_M[3][0] = static_cast <real> (-1.0/6.0);
|
---|
| 171 | SplineBase<V, real>::_M[3][1] = static_cast <real> (3.0/6.0);
|
---|
| 172 | SplineBase<V, real>::_M[3][2] = static_cast <real> (-3.0/6.0);
|
---|
| 173 | SplineBase<V, real>::_M[3][3] = static_cast <real> (1.0/6.0);
|
---|
| 174 | }
|
---|
| 175 | public:
|
---|
| 176 | CubicBSplineBase () : SplineBase<V, real> ()
|
---|
| 177 | {
|
---|
| 178 | init();
|
---|
| 179 | }
|
---|
| 180 | CubicBSplineBase (const std::vector <V> & points) : SplineBase<V, real> (points)
|
---|
| 181 | {
|
---|
| 182 | init();
|
---|
| 183 | }
|
---|
| 184 | };
|
---|
| 185 |
|
---|
| 186 | template <typename V, typename real = float>
|
---|
| 187 | class CRSplineBase : public SplineBase <V, real>
|
---|
| 188 | {
|
---|
| 189 | private:
|
---|
| 190 | // TODO: Optimize by initializing this matrix only once rather than each time a spline object is created
|
---|
| 191 | void init (const real fT)
|
---|
| 192 | {
|
---|
| 193 | using S = SplineBase<V, real>;
|
---|
| 194 |
|
---|
| 195 | S::_M[0][0] = 0; S::_M[0][1] = 1; S::_M[0][2] = 0; S::_M[0][3] = 0;
|
---|
| 196 | S::_M[1][0] = -fT; S::_M[1][1] = 0; S::_M[1][2] = fT; S::_M[1][3] = 0;
|
---|
| 197 | S::_M[2][0] = 2*fT; S::_M[2][1] = fT-3; S::_M[2][2] = 3-2*fT; S::_M[2][3] = -fT;
|
---|
| 198 | S::_M[3][0] = -fT; S::_M[3][1] = 2-fT; S::_M[3][2] = fT-2; S::_M[3][3] = fT;
|
---|
| 199 | }
|
---|
| 200 |
|
---|
| 201 | public:
|
---|
| 202 | CRSplineBase (const real fT = 0.5f) : SplineBase<V, real>()
|
---|
| 203 | {
|
---|
| 204 | init (fT);
|
---|
| 205 | }
|
---|
| 206 | CRSplineBase (const std::vector <V> & points, const real fT = 0.5f) : SplineBase<V, real>(points)
|
---|
| 207 | {
|
---|
| 208 | init(fT);
|
---|
| 209 | }
|
---|
| 210 | };
|
---|
| 211 |
|
---|
| 212 | template <typename SB, typename real>
|
---|
| 213 | class ArcLengthFnPiece : public GaussLegendreInt <real, ArcLengthFnPiece <SB, real>, 5>
|
---|
| 214 | {
|
---|
| 215 | private:
|
---|
| 216 | const SB & _link;
|
---|
| 217 | const unsigned int _i;
|
---|
| 218 | mutable real _cache100;
|
---|
| 219 |
|
---|
| 220 | // Copying will break the reference with SB
|
---|
| 221 | ArcLengthFnPiece (const ArcLengthFnPiece & copy) {}
|
---|
| 222 |
|
---|
| 223 | public:
|
---|
| 224 | ArcLengthFnPiece (const SB & link, const unsigned int i)
|
---|
| 225 | : _link(link), _i(i), _cache100(-1) {}
|
---|
| 226 |
|
---|
| 227 | inline real f (const real t) const
|
---|
| 228 | {
|
---|
| 229 | return MAG(_link.compute (_i, 0, 1, 2*t, 3*t*t));
|
---|
| 230 | }
|
---|
| 231 | inline real length (const real a, const real b) const
|
---|
| 232 | {
|
---|
| 233 | #ifdef _DEBUG
|
---|
| 234 | assert (b >= a);
|
---|
| 235 | assert (b <= 1.0 && a >= 0.0 );
|
---|
| 236 | #endif
|
---|
| 237 | return GaussLegendreInt<real, ArcLengthFnPiece <SB, real>, 5>::compute(a, b);
|
---|
| 238 | }
|
---|
| 239 |
|
---|
| 240 | inline real length () const
|
---|
| 241 | { return _cache100 < 0 ? (_cache100 = length(0, 1)) : _cache100; }
|
---|
| 242 |
|
---|
| 243 | inline void clearCache () const
|
---|
| 244 | { _cache100 = -1; }
|
---|
| 245 | };
|
---|
| 246 |
|
---|
| 247 | template <typename SB>
|
---|
| 248 | class Spline
|
---|
| 249 | {
|
---|
| 250 | public:
|
---|
| 251 | typedef SB BaseType;
|
---|
| 252 | typedef Spline< SB > SplineType;
|
---|
| 253 | typedef typename SB::Precision real;
|
---|
| 254 | typedef typename SB::VectorType VectorType;
|
---|
| 255 |
|
---|
| 256 | const real ONE;
|
---|
| 257 |
|
---|
| 258 | private:
|
---|
| 259 | SB _sp;
|
---|
| 260 | ArcLengthFnPiece<SB, real> ** _lenfns;
|
---|
| 261 |
|
---|
| 262 | // Approximates the "time" along the curve at the specified physical distance
|
---|
| 263 | // This is the inverse of arclength
|
---|
| 264 | class ArcPositionFn
|
---|
| 265 | {
|
---|
| 266 | private:
|
---|
| 267 | const ArcLengthFnPiece<SB, real> & _fnLen;
|
---|
| 268 | real _fTest;
|
---|
| 269 |
|
---|
| 270 | ArcPositionFn (const ArcPositionFn & copy) {}
|
---|
| 271 |
|
---|
| 272 | public:
|
---|
| 273 | ArcPositionFn (const ArcLengthFnPiece<SB, real> & fnLen, const real fPosition)
|
---|
| 274 | : _fnLen(fnLen), _fTest(fPosition) {}
|
---|
| 275 |
|
---|
| 276 | inline const real f(const real t) const { return _fTest - _fnLen.length(0, t); }
|
---|
| 277 | };
|
---|
| 278 |
|
---|
| 279 | public:
|
---|
| 280 | typedef typename std::vector <VectorType>::const_iterator PointsConstIterator;
|
---|
| 281 | typedef typename std::vector <VectorType>::iterator PointsIterator;
|
---|
| 282 | typedef typename std::vector <VectorType>::reverse_iterator PointsRIterator;
|
---|
| 283 |
|
---|
| 284 | private:
|
---|
| 285 | template <typename L>
|
---|
| 286 | inline static void populateVector (const typename L::const_iterator ia, const typename L::const_iterator ib, std::vector <VectorType> & v)
|
---|
| 287 | { v.insert(v.begin(), ia, ib); }
|
---|
| 288 |
|
---|
| 289 | void init ()
|
---|
| 290 | {
|
---|
| 291 | const unsigned int nSegCount = segCount();
|
---|
| 292 |
|
---|
| 293 | _lenfns = new ArcLengthFnPiece< SB, real >* [nSegCount];
|
---|
| 294 | for (unsigned int i = 0; i < nSegCount; ++i)
|
---|
| 295 | _lenfns[i] = new ArcLengthFnPiece<SB, real> (_sp, i);
|
---|
| 296 | }
|
---|
| 297 | inline const ArcLengthFnPiece<SB, real> & lenfn (const unsigned int i) const
|
---|
| 298 | {
|
---|
| 299 | #ifdef _DEBUG
|
---|
| 300 | assert(i < segCount());
|
---|
| 301 | assert(_lenfns != NULL);
|
---|
| 302 | assert(_lenfns[i] != NULL);
|
---|
| 303 | #endif
|
---|
| 304 | return *_lenfns[i];
|
---|
| 305 | }
|
---|
| 306 | void clearCache () const
|
---|
| 307 | {
|
---|
| 308 | for (unsigned int i = 0; i < segCount(); ++i)
|
---|
| 309 | lenfn(i).clearCache();
|
---|
| 310 | }
|
---|
| 311 |
|
---|
| 312 | public:
|
---|
| 313 | Spline (const Spline <SB> & copy)
|
---|
| 314 | : _lenfns(NULL), _sp (copy._sp), ONE(static_cast< real > (1)) { init (); }
|
---|
| 315 | Spline (const std::vector <VectorType> & points)
|
---|
| 316 | : _lenfns(NULL), _sp(points), ONE(static_cast< real > (1)) { init(); }
|
---|
| 317 | Spline (const real fT, const std::vector <VectorType> & points)
|
---|
| 318 | : _lenfns(NULL), _sp(points, fT), ONE(static_cast< real > (1)) { init(); }
|
---|
| 319 | Spline ()
|
---|
| 320 | : _lenfns(NULL), _sp(), ONE(static_cast< real > (1)) { init (); }
|
---|
| 321 | Spline (const real fT)
|
---|
| 322 | : _lenfns(NULL), _sp(fT), ONE(static_cast< real > (1)) { init (); }
|
---|
| 323 |
|
---|
| 324 | template <typename L>
|
---|
| 325 | static Spline createFrom (const typename L::const_iterator ia, const typename L::const_iterator ib)
|
---|
| 326 | {
|
---|
| 327 | std::vector <VectorType> v;
|
---|
| 328 | populateVector <L> (ia, ib, v);
|
---|
| 329 | return Spline(v);
|
---|
| 330 | }
|
---|
| 331 |
|
---|
| 332 | template <typename L>
|
---|
| 333 | static Spline createFrom (const real fT, const typename L::const_iterator ia, const typename L::const_iterator ib)
|
---|
| 334 | {
|
---|
| 335 | std::vector <VectorType> v;
|
---|
| 336 | populateVector <L> (ia, ib, v);
|
---|
| 337 | return Spline(fT, v);
|
---|
| 338 | }
|
---|
| 339 |
|
---|
| 340 | // Returns the length of the specified curve segment [i, i+1]
|
---|
| 341 | inline real len (const unsigned int i) const { return lenfn(i).length(); }
|
---|
| 342 | // Returns the length of the specified curve segment between times tA and tB [i+tA, i+tB]
|
---|
| 343 | inline real len (const unsigned int i, const real tA, const real tB) const { return lenfn(i).length(tA, tB); }
|
---|
| 344 | // Returns the total length of the curve
|
---|
| 345 | real len () const
|
---|
| 346 | {
|
---|
| 347 | const unsigned nSegs = segCount();
|
---|
| 348 | real nLen = 0;
|
---|
| 349 |
|
---|
| 350 | for (unsigned i = 0; i < nSegs; ++i)
|
---|
| 351 | nLen += len(i);
|
---|
| 352 |
|
---|
| 353 | return nLen;
|
---|
| 354 | }
|
---|
| 355 | real distanceFast (const unsigned int i, const real t) const
|
---|
| 356 | {
|
---|
| 357 | real fLen = 0;
|
---|
| 358 |
|
---|
| 359 | for (unsigned int c = 0; c < i; ++c)
|
---|
| 360 | fLen += len(c);
|
---|
| 361 |
|
---|
| 362 | return fLen += len(i) * t;
|
---|
| 363 | }
|
---|
| 364 | real distance (const unsigned int i, const real t) const
|
---|
| 365 | {
|
---|
| 366 | real fLen = 0;
|
---|
| 367 |
|
---|
| 368 | for (unsigned int c = 0; c < i; ++c)
|
---|
| 369 | fLen += len(c);
|
---|
| 370 |
|
---|
| 371 | return fLen += lenfn(i).length(0, t);
|
---|
| 372 | }
|
---|
| 373 | inline real timeAt (const unsigned int i, const real & fPos) const
|
---|
| 374 | {
|
---|
| 375 | return mars::BisectMethod< real, ArcPositionFn > :: solve ( ArcPositionFn(lenfn(i), fPos), 0, 1 );
|
---|
| 376 | }
|
---|
| 377 | inline const VectorType compute (const unsigned int i, const real t) const
|
---|
| 378 | {
|
---|
| 379 | const real
|
---|
| 380 | t2 = t * t,
|
---|
| 381 | t3 = t2 * t;
|
---|
| 382 |
|
---|
| 383 | return _sp.compute(i, 1, t, t2, t3);
|
---|
| 384 | }
|
---|
| 385 | inline const VectorType gradient (const unsigned int i, const real t) const
|
---|
| 386 | { return _sp.compute(i, 0, 1, 2*t, 3*t*t); }
|
---|
| 387 | inline const VectorType laplace (const unsigned int i, const real t) const
|
---|
| 388 | { return _sp.compute(i, 0, 0, 2, 6*t); }
|
---|
| 389 |
|
---|
| 390 | template <typename V3D>
|
---|
| 391 | void move (const real radius, const V3D & unormal)
|
---|
| 392 | {
|
---|
| 393 | _sp.move (radius, unormal);
|
---|
| 394 | clearCache();
|
---|
| 395 | }
|
---|
| 396 | inline unsigned int segCount() const { return _sp.size() - 1; }
|
---|
| 397 | inline unsigned int size () const { return _sp.size(); }
|
---|
| 398 | inline PointsConstIterator begin() const { return _sp.begin(); }
|
---|
| 399 | inline PointsConstIterator end() const { return _sp.end(); }
|
---|
| 400 | inline PointsIterator begin() { return _sp.begin(); }
|
---|
| 401 | inline PointsIterator end() { return _sp.end(); }
|
---|
| 402 | inline const VectorType & operator [] (const unsigned int i) const { return _sp[i]; }
|
---|
| 403 | inline VectorType & operator [] (const unsigned int i) { return _sp[i]; }
|
---|
| 404 | inline VectorType & front () { return _sp.front(); }
|
---|
| 405 | inline const VectorType & front () const { return _sp.front(); }
|
---|
| 406 | inline VectorType & back () { return _sp.back(); }
|
---|
| 407 | inline const VectorType & back () const { return _sp.back(); }
|
---|
| 408 |
|
---|
| 409 | inline void operator += (const VectorType & ptOffset)
|
---|
| 410 | { _sp += ptOffset; }
|
---|
| 411 |
|
---|
| 412 | ~Spline()
|
---|
| 413 | {
|
---|
| 414 | for (unsigned int i = 0; i < segCount(); ++i)
|
---|
| 415 | delete _lenfns[i];
|
---|
| 416 |
|
---|
| 417 | delete [] _lenfns;
|
---|
| 418 | }
|
---|
| 419 |
|
---|
| 420 | };
|
---|
| 421 |
|
---|
| 422 | template <typename S, typename Vs, typename integer = short>
|
---|
| 423 | class SplineRasterIterator : public std::iterator < std::input_iterator_tag, Vs >
|
---|
| 424 | {
|
---|
| 425 | public:
|
---|
| 426 | typedef S SplineType;
|
---|
| 427 | typedef Vs RasterVecType;
|
---|
| 428 | typedef integer RasterPrecision;
|
---|
| 429 | typedef typename SplineType::real real;
|
---|
| 430 | typedef typename SplineType::VectorType VectorType;
|
---|
| 431 |
|
---|
| 432 | private:
|
---|
| 433 | const SplineType & _sp;
|
---|
| 434 | Vs _zp, // Resulting iterative raster point (also used to compare guess points against)
|
---|
| 435 | _tzp; // Guess point (integral) (current)
|
---|
| 436 | VectorType _trp; // Guess point (rational) (current)
|
---|
| 437 | unsigned int _i, // Segment number (current)
|
---|
| 438 | _k; // Iteration count
|
---|
| 439 | real _accel, // Acceleration (current) (added to current time for next guess point)
|
---|
| 440 | _t, // Time (current)
|
---|
| 441 | _t0; // Time (last)
|
---|
| 442 | const unsigned int
|
---|
| 443 | _segCount;
|
---|
| 444 |
|
---|
| 445 | CR_CONTEXT;
|
---|
| 446 |
|
---|
| 447 | int calcZDiff (const real & t)
|
---|
| 448 | {
|
---|
| 449 | using namespace mars;
|
---|
| 450 |
|
---|
| 451 | _trp = _sp.compute(_i, t);
|
---|
| 452 | _tzp = _trp;
|
---|
| 453 |
|
---|
| 454 | const Vs dzp = _tzp - _zp;
|
---|
| 455 |
|
---|
| 456 | return (SQ(dzp.x) + SQ(dzp.y));
|
---|
| 457 | }
|
---|
| 458 | inline void assignAccel (const real acc)
|
---|
| 459 | {
|
---|
| 460 | assert(acc >= 0);
|
---|
| 461 | if (acc > 0)
|
---|
| 462 | _accel = acc;
|
---|
| 463 | }
|
---|
| 464 | bool satisfy (real & acc, unsigned int & zdiff)
|
---|
| 465 | {
|
---|
| 466 | using namespace mars;
|
---|
| 467 | const real t = _t + acc;
|
---|
| 468 |
|
---|
| 469 | // Calculate integral distance from last position to guessed position
|
---|
| 470 | zdiff = calcZDiff(t);
|
---|
| 471 | if (zdiff == 1)
|
---|
| 472 | {
|
---|
| 473 | _zp = _tzp;
|
---|
| 474 | _t = t;
|
---|
| 475 | assignAccel(acc);
|
---|
| 476 | return true;
|
---|
| 477 | } else if (zdiff <= 2)
|
---|
| 478 | {
|
---|
| 479 | const VectorType drp = _trp - _zp;
|
---|
| 480 |
|
---|
| 481 | if (drp.x > abs(drp.y) && drp.x > 0) // Slope is bias to the positive x-direction
|
---|
| 482 | ++_zp.x;
|
---|
| 483 | else if (drp.y > abs(drp.x) && drp.y > 0) // Slope is bias to the positive y-direction
|
---|
| 484 | ++_zp.y;
|
---|
| 485 | else if (drp.y < -abs(drp.x) && drp.y < 0) // Slope is bias to the negative y-direction
|
---|
| 486 | --_zp.y;
|
---|
| 487 | else if (drp.x < -abs(drp.y) && drp.x < 0) // Slope is bias to the negative x-direction
|
---|
| 488 | --_zp.x;
|
---|
| 489 | else // Slope is perfectly 1:1 or 0:0
|
---|
| 490 | {
|
---|
| 491 | if (zdiff == 0)
|
---|
| 492 | {
|
---|
| 493 | if (drp.x == 0 || drp.y == 0)
|
---|
| 494 | return false;
|
---|
| 495 |
|
---|
| 496 | if (drp.x < 0)
|
---|
| 497 | --_zp.x;
|
---|
| 498 | else
|
---|
| 499 | ++_zp.x;
|
---|
| 500 |
|
---|
| 501 | if (drp.y < 0)
|
---|
| 502 | --_zp.y;
|
---|
| 503 | else
|
---|
| 504 | ++_zp.y;
|
---|
| 505 | } else
|
---|
| 506 | _zp = _tzp;
|
---|
| 507 | assignAccel(acc);
|
---|
| 508 | _t = t;
|
---|
| 509 | return true;
|
---|
| 510 | }
|
---|
| 511 |
|
---|
| 512 | if (zdiff == 2)
|
---|
| 513 | {
|
---|
| 514 | assignAccel(acc);
|
---|
| 515 | _t += _accel / 2;
|
---|
| 516 | } else
|
---|
| 517 | {
|
---|
| 518 | assignAccel(acc);
|
---|
| 519 | _t = t;
|
---|
| 520 | }
|
---|
| 521 | return true;
|
---|
| 522 | } else
|
---|
| 523 | return false;
|
---|
| 524 | }
|
---|
| 525 | template <int N> struct StaticIteration {};
|
---|
| 526 | template <int N> void drilldown (real & acc, unsigned int & zdiff) {
|
---|
| 527 | drilldown(acc, zdiff, StaticIteration<N>());
|
---|
| 528 | }
|
---|
| 529 | template <int N> void drilldown (real & acc, unsigned int & zdiff, StaticIteration<N>)
|
---|
| 530 | {
|
---|
| 531 | using namespace mars;
|
---|
| 532 |
|
---|
| 533 | // If the guessed position is not satisfied then it is will have an integral non-zero distance of at least +4 from the last position
|
---|
| 534 | if (!satisfy (acc, zdiff))
|
---|
| 535 | {
|
---|
| 536 | if (_trp != _zp)
|
---|
| 537 | {
|
---|
| 538 | const real accbak = acc;
|
---|
| 539 |
|
---|
| 540 | acc /= MAG(_trp - _zp);
|
---|
| 541 | if (acc >= 1.0)
|
---|
| 542 | acc = accbak * 2;
|
---|
| 543 | } else
|
---|
| 544 | acc *= 2;
|
---|
| 545 |
|
---|
| 546 | drilldown <N - 1> (acc, zdiff);
|
---|
| 547 | }
|
---|
| 548 | }
|
---|
| 549 | inline void drilldown (real & acc, unsigned int & zdiff, StaticIteration<0>)
|
---|
| 550 | {
|
---|
| 551 | if (!satisfy (acc, zdiff))
|
---|
| 552 | {
|
---|
| 553 | drilldownBeta(acc);
|
---|
| 554 | }
|
---|
| 555 | }
|
---|
| 556 | void drilldownBeta(real & acc)
|
---|
| 557 | {
|
---|
| 558 | using namespace mars;
|
---|
| 559 | static const real SPLINE_PREC_EPSILON = std::numeric_limits <real>::epsilon();
|
---|
| 560 |
|
---|
| 561 | real dacc = acc;
|
---|
| 562 | signed short ddd = 3;
|
---|
| 563 | unsigned int zdiff;
|
---|
| 564 |
|
---|
| 565 | do
|
---|
| 566 | {
|
---|
| 567 | if (!satisfy(acc, zdiff))
|
---|
| 568 | {
|
---|
| 569 | if (zdiff == 0)
|
---|
| 570 | {
|
---|
| 571 | if (ddd ^ 1)
|
---|
| 572 | {
|
---|
| 573 | dacc /= 2;
|
---|
| 574 | ddd = 1;
|
---|
| 575 | }
|
---|
| 576 | acc += dacc;
|
---|
| 577 | } else
|
---|
| 578 | {
|
---|
| 579 | if (ddd ^ 0)
|
---|
| 580 | {
|
---|
| 581 | dacc /= 2;
|
---|
| 582 | ddd = 0;
|
---|
| 583 | }
|
---|
| 584 | acc -= dacc;
|
---|
| 585 | }
|
---|
| 586 | } else
|
---|
| 587 | return;
|
---|
| 588 |
|
---|
| 589 | // Acc < 1.0 prevents an index-out-of-bounds exception and checking delta-acc here ensures numerical stability
|
---|
| 590 | } while (acc < 1.0 && acc > 0 && (dacc > SPLINE_PREC_EPSILON || dacc < -SPLINE_PREC_EPSILON));
|
---|
| 591 |
|
---|
| 592 | // Catch-all for acceleration values that are negative or too small, accounts for numerical instability as well as monotonic exceptions
|
---|
| 593 | if (acc > SPLINE_PREC_EPSILON)
|
---|
| 594 | _accel = acc;
|
---|
| 595 |
|
---|
| 596 | _zp = _tzp;
|
---|
| 597 | _t += _accel;
|
---|
| 598 | }
|
---|
| 599 |
|
---|
| 600 | void findAdjacentCell ()
|
---|
| 601 | {
|
---|
| 602 | using namespace mars;
|
---|
| 603 |
|
---|
| 604 | real
|
---|
| 605 | acc = _accel;
|
---|
| 606 | unsigned int
|
---|
| 607 | zdiff;
|
---|
| 608 |
|
---|
| 609 | drilldown <6> (acc, zdiff);
|
---|
| 610 | }
|
---|
| 611 | void process ()
|
---|
| 612 | {
|
---|
| 613 | CR_START();
|
---|
| 614 |
|
---|
| 615 | _t = 0;
|
---|
| 616 | _zp = _sp.compute (0, 0);
|
---|
| 617 |
|
---|
| 618 | for (_i = 0; _i < _segCount; ++_i)
|
---|
| 619 | {
|
---|
| 620 | _accel = static_cast <real> (1.0) / _sp.len(_i);
|
---|
| 621 | _t0 = _t = 0;
|
---|
| 622 |
|
---|
| 623 | while (_t < 1.0)
|
---|
| 624 | {
|
---|
| 625 | findAdjacentCell();
|
---|
| 626 | CR_RETURN_VOID;
|
---|
| 627 | _t0 = _t;
|
---|
| 628 | ++_k;
|
---|
| 629 | }
|
---|
| 630 | }
|
---|
| 631 |
|
---|
| 632 | CR_END();
|
---|
| 633 | }
|
---|
| 634 |
|
---|
| 635 | public:
|
---|
| 636 | SplineRasterIterator (const SplineRasterIterator & copy);
|
---|
| 637 | SplineRasterIterator (const SplineType & sp)
|
---|
| 638 | : _sp (sp), _segCount (sp.segCount()), _k(0)
|
---|
| 639 | {
|
---|
| 640 | CR_INIT();
|
---|
| 641 |
|
---|
| 642 | process();
|
---|
| 643 | }
|
---|
| 644 |
|
---|
| 645 | // XTODO: Optimize!!!
|
---|
| 646 | SplineRasterIterator & operator += (const real rDist)
|
---|
| 647 | {
|
---|
| 648 | if (rDist > 0)
|
---|
| 649 | {
|
---|
| 650 | const unsigned int nSegs = _sp.segCount();
|
---|
| 651 | const real fDist = distanceFast();
|
---|
| 652 | const real fTot = static_cast <real> (rDist) + fDist;
|
---|
| 653 | real fAcc = fDist;
|
---|
| 654 |
|
---|
| 655 | while (_i < nSegs)
|
---|
| 656 | {
|
---|
| 657 | const real fTesterz = _sp.len(_i);
|
---|
| 658 |
|
---|
| 659 | if (fAcc + fTesterz > fTot)
|
---|
| 660 | {
|
---|
| 661 | _t0 = _t = _sp.timeAt (_i, fTot - fAcc);
|
---|
| 662 | _zp = _sp.compute(_i, _t);
|
---|
| 663 | _accel = static_cast <real> (1.0) / _sp.len(_i);
|
---|
| 664 | _k += static_cast <unsigned int> (rDist);
|
---|
| 665 | return *this;
|
---|
| 666 | }
|
---|
| 667 | else
|
---|
| 668 | fAcc += fTesterz;
|
---|
| 669 | ++_i;
|
---|
| 670 | }
|
---|
| 671 |
|
---|
| 672 | // Terminate the loop if we get here
|
---|
| 673 | _t0 = _t = 1.0f;
|
---|
| 674 | }
|
---|
| 675 |
|
---|
| 676 | return *this;
|
---|
| 677 | }
|
---|
| 678 |
|
---|
| 679 | inline SplineRasterIterator & operator++()
|
---|
| 680 | {
|
---|
| 681 | process();
|
---|
| 682 | return *this;
|
---|
| 683 | }
|
---|
| 684 | inline SplineRasterIterator operator++(int)
|
---|
| 685 | {
|
---|
| 686 | SplineRasterIterator old = *this;
|
---|
| 687 |
|
---|
| 688 | process();
|
---|
| 689 | return old;
|
---|
| 690 | }
|
---|
| 691 | // Retrieves the number of pixels traversed thus far, or the current pixel in the iteration
|
---|
| 692 | // NOTE: This is not the same as the distance of spline curve traversed thus far, so it cannot be
|
---|
| 693 | // compared accurately with the spline length since this deals with number of pixels plotted as
|
---|
| 694 | // opposed to any physical measure of distance from the origin.
|
---|
| 695 | inline unsigned int index () const { return _k; }
|
---|
| 696 | inline unsigned int segment () const { return _i; }
|
---|
| 697 | inline real distanceFast() const { return _sp.distanceFast(_i, _t0); }
|
---|
| 698 | inline real distance() const { return _sp.distance(_i, _t0); }
|
---|
| 699 | inline const VectorType gradient () const { return _sp.gradient(_i, _t0); }
|
---|
| 700 | inline const VectorType laplace () const { return _sp.laplace(_i, _t0); }
|
---|
| 701 |
|
---|
| 702 | inline operator const Vs & () const { return _zp; }
|
---|
| 703 | inline operator bool () const { return _i < _segCount; }
|
---|
| 704 | inline const SplineType & getSpline() const { return _sp; }
|
---|
| 705 | };
|
---|
| 706 |
|
---|
| 707 | template <typename S, typename EOFn, typename EIFn, typename RasterPrec, typename Vs, typename V3>
|
---|
| 708 | class SplineZoneIterator : public std::iterator < std::input_iterator_tag, Vs >
|
---|
| 709 | {
|
---|
| 710 | protected:
|
---|
| 711 | typedef S SplineType;
|
---|
| 712 | typedef typename SplineType::real real;
|
---|
| 713 | typedef SplineRasterIterator <S, Vs, RasterPrec> SplineWalker;
|
---|
| 714 | typedef typename SplineType::VectorType VectorType;
|
---|
| 715 |
|
---|
| 716 | private:
|
---|
| 717 |
|
---|
| 718 | mutable struct TotalRadiusCache
|
---|
| 719 | {
|
---|
| 720 | unsigned int result, index, radi;
|
---|
| 721 |
|
---|
| 722 | inline TotalRadiusCache ()
|
---|
| 723 | : result(0), index(0), radi(0) {}
|
---|
| 724 |
|
---|
| 725 | } _crad;
|
---|
| 726 |
|
---|
| 727 | const unsigned int _netradius; // TODO: Genericize unsigned int _netradius
|
---|
| 728 | const EOFn _fnEaseOut;
|
---|
| 729 | const EIFn _fnEaseIn;
|
---|
| 730 | unsigned int _splnum;
|
---|
| 731 | signed int _side;
|
---|
| 732 | SplineWalker * _pItSP;
|
---|
| 733 | unsigned int _radi;
|
---|
| 734 | real _fBaseLen, _fLimit, _fOffset, _fSpLen;
|
---|
| 735 | SplineType * _pSplineA, * _pSplineB;
|
---|
| 736 | V3 _unormal;
|
---|
| 737 | typename SplineWalker::RasterVecType _p;
|
---|
| 738 | bool _done;
|
---|
| 739 |
|
---|
| 740 | CR_CONTEXT;
|
---|
| 741 |
|
---|
| 742 | public:
|
---|
| 743 | SplineZoneIterator (const SplineType & spline, const unsigned int nRadius, const EOFn & fnEaseOut, const EIFn & fnEaseIn, const V3 & unormal)
|
---|
| 744 | : _netradius (nRadius), _unormal (unormal), _done(false), _pItSP(NULL), _splnum(0), _fnEaseOut(fnEaseOut), _fnEaseIn(fnEaseIn), _radi(0)
|
---|
| 745 | {
|
---|
| 746 | using namespace mars;
|
---|
| 747 |
|
---|
| 748 | CR_INIT();
|
---|
| 749 | _pSplineB = new S (spline);
|
---|
| 750 | _pSplineA = new S (spline);
|
---|
| 751 |
|
---|
| 752 | process();
|
---|
| 753 | }
|
---|
| 754 | ~SplineZoneIterator ()
|
---|
| 755 | {
|
---|
| 756 | delete _pSplineA;
|
---|
| 757 | delete _pSplineB;
|
---|
| 758 | delete _pItSP;
|
---|
| 759 | }
|
---|
| 760 |
|
---|
| 761 | inline SplineZoneIterator & operator++()
|
---|
| 762 | {
|
---|
| 763 | process();
|
---|
| 764 | return *this;
|
---|
| 765 | }
|
---|
| 766 | inline SplineZoneIterator operator++(int)
|
---|
| 767 | {
|
---|
| 768 | SplineZoneIterator old = *this;
|
---|
| 769 |
|
---|
| 770 | process();
|
---|
| 771 | return old;
|
---|
| 772 | }
|
---|
| 773 |
|
---|
| 774 | inline const Vs & operator * () const { return _p; }
|
---|
| 775 | inline const Vs & operator -> () const { return _p; }
|
---|
| 776 |
|
---|
| 777 | inline operator const Vs & () const { return _p; }
|
---|
| 778 | inline const typename SplineWalker::RasterVecType & pos () const { return _p; }
|
---|
| 779 |
|
---|
| 780 | // Returns current radius as a ratio to the total radius
|
---|
| 781 | inline real trad () const { return static_cast <real> (radius()) / static_cast <real> (SplineZoneIterator::crad()); }
|
---|
| 782 | // Returns the present distance from the spine spline (always positive)
|
---|
| 783 | inline const unsigned int radius () const { return _radi; }
|
---|
| 784 | // Returns the present distance from the spine spline (negative if on the negative side and positive if on the positive side)
|
---|
| 785 | inline const signed int sradius () const { return static_cast< signed int > (radius()) * side(); }
|
---|
| 786 | inline const signed int side() const { return _side; }
|
---|
| 787 | // Returns the total radius of the zone at the current time
|
---|
| 788 | const unsigned int crad () const
|
---|
| 789 | {
|
---|
| 790 | if (_crad.result == 0 || _pItSP->index() != _crad.index || _radi != _crad.radi)
|
---|
| 791 | {
|
---|
| 792 | const real
|
---|
| 793 | ONE = _pItSP->getSpline().ONE,
|
---|
| 794 | frDist = static_cast <real> (_pItSP->distanceFast()) / _fSpLen;
|
---|
| 795 |
|
---|
| 796 | // FIXME: _radi ends-up being more than the calculated total radius causing the assertion to fail (see below).
|
---|
| 797 | // This may have been fixed as of the change to use accurate spline length calculation instead of approximate
|
---|
| 798 | _crad.result =
|
---|
| 799 | std::max(
|
---|
| 800 | _radi,
|
---|
| 801 | static_cast <unsigned int> (
|
---|
| 802 | _fnEaseOut.invf(frDist) * _fnEaseIn.invf(ONE - frDist) * static_cast <real> (_netradius)
|
---|
| 803 | ) + 1
|
---|
| 804 | )
|
---|
| 805 | ;
|
---|
| 806 | _crad.index = _pItSP->index();
|
---|
| 807 | _crad.radi = _radi;
|
---|
| 808 |
|
---|
| 809 | assert(_crad.radi <= _crad.result);
|
---|
| 810 | }
|
---|
| 811 |
|
---|
| 812 | return _crad.result;
|
---|
| 813 | }
|
---|
| 814 | inline operator bool () const { return !_done; }
|
---|
| 815 | inline const unsigned int splineNum () const { return _splnum; }
|
---|
| 816 | inline const unsigned int index () const { return _pItSP->index(); }
|
---|
| 817 | inline const real distance () const { return _pItSP->distance(); }
|
---|
| 818 | inline const real distanceFast () const { return _pItSP->distanceFast(); }
|
---|
| 819 | inline const VectorType gradient () const { return _pItSP->gradient(); }
|
---|
| 820 | inline const VectorType laplace () const { return _pItSP->laplace(); }
|
---|
| 821 | inline const real seglen () const { return _pItSP->getSpline().len(_pItSP->segment()); }
|
---|
| 822 | inline const VectorType & tailCP () const { return _pItSP->getSpline()[_pItSP->segment()]; }
|
---|
| 823 | inline const VectorType & leadCP () const { return _pItSP->getSpline()[_pItSP->segment() + 1]; }
|
---|
| 824 |
|
---|
| 825 | private:
|
---|
| 826 | void process ()
|
---|
| 827 | {
|
---|
| 828 | using namespace mars;
|
---|
| 829 |
|
---|
| 830 | CR_START();
|
---|
| 831 |
|
---|
| 832 | _fSpLen =
|
---|
| 833 | _fBaseLen = _pSplineB->len();
|
---|
| 834 | for (_pItSP = new SplineWalker (*_pSplineB); *_pItSP; ++*_pItSP)
|
---|
| 835 | {
|
---|
| 836 | _p = *_pItSP;
|
---|
| 837 | CR_RETURN_VOID;
|
---|
| 838 | }
|
---|
| 839 | delete _pItSP;
|
---|
| 840 | _pItSP = NULL;
|
---|
| 841 |
|
---|
| 842 | // Fill to the positive side of the curve
|
---|
| 843 | _side = +1;
|
---|
| 844 | while (_radi++ < _netradius)
|
---|
| 845 | {
|
---|
| 846 | prepareWalk(_pSplineA);
|
---|
| 847 | for (*(_pItSP = new SplineWalker (*_pSplineA)) += _fOffset;
|
---|
| 848 | *_pItSP && _pItSP->distanceFast() < _fLimit;
|
---|
| 849 | ++*_pItSP)
|
---|
| 850 | {
|
---|
| 851 | _p = *_pItSP;
|
---|
| 852 | CR_RETURN_VOID;
|
---|
| 853 | }
|
---|
| 854 | postWalk(_pSplineA);
|
---|
| 855 | }
|
---|
| 856 | _pItSP = NULL;
|
---|
| 857 |
|
---|
| 858 | // Fill to the negative side of the curve
|
---|
| 859 | _radi = 0;
|
---|
| 860 | _side = -1;
|
---|
| 861 | while (_radi++ < _netradius)
|
---|
| 862 | {
|
---|
| 863 | prepareWalk(_pSplineB);
|
---|
| 864 |
|
---|
| 865 | for (*(_pItSP = new SplineWalker (*_pSplineB)) += _fOffset;
|
---|
| 866 | *_pItSP && _pItSP->distanceFast() < _fLimit;
|
---|
| 867 | ++*_pItSP)
|
---|
| 868 | {
|
---|
| 869 | _p = *_pItSP;
|
---|
| 870 | CR_RETURN_VOID;
|
---|
| 871 | }
|
---|
| 872 | postWalk(_pSplineB);
|
---|
| 873 | }
|
---|
| 874 | _pItSP = NULL;
|
---|
| 875 |
|
---|
| 876 | _done = true;
|
---|
| 877 |
|
---|
| 878 | CR_END();
|
---|
| 879 | }
|
---|
| 880 | inline void postWalk(const S * pSpline)
|
---|
| 881 | {
|
---|
| 882 | delete _pItSP;
|
---|
| 883 | }
|
---|
| 884 | void prepareWalk (S * pSpline)
|
---|
| 885 | {
|
---|
| 886 | pSpline->move (static_cast< float > (_side), _unormal);
|
---|
| 887 | _fSpLen = pSpline->len();
|
---|
| 888 | const real
|
---|
| 889 | ONE = pSpline->ONE,
|
---|
| 890 | frRadii = static_cast <real> (_radi) / static_cast <real> (_netradius);
|
---|
| 891 |
|
---|
| 892 | _fLimit = _fnEaseOut.f( frRadii / _fnEaseIn.invf(ONE - _fnEaseIn.f(frRadii) ) ) * _fSpLen;
|
---|
| 893 | _fOffset = (ONE - _fnEaseIn.f( frRadii / _fnEaseOut.invf(ONE - _fnEaseOut.f(frRadii ) ) )) * _fSpLen;
|
---|
| 894 |
|
---|
| 895 | // FIXME: Limit and offset calculations are inaccurate, causes _radi to increment out-of-range.
|
---|
| 896 | ++_splnum;
|
---|
| 897 | }
|
---|
| 898 | };
|
---|
| 899 | }
|
---|