libmoldeo (Moldeo 1.0 Core)  1.0
libmoldeo is the group of objects and functions that executes the basic operations of Moldeo 1.0 Platform.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
moMathCurve.h
Go to the documentation of this file.
1 /*******************************************************************************
2 
3  moMathCurve.h
4 
5  ****************************************************************************
6  * *
7  * This source is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This code is distributed in the hope that it will be useful, but *
13  * WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15  * General Public License for more details. *
16  * *
17  * A copy of the GNU General Public License is available on the World *
18  * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
19  * obtain it by writing to the Free Software Foundation, *
20  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21  * *
22  ****************************************************************************
23 
24  Copyright(C) 2006 Fabricio Costa
25 
26  Authors:
27  Fabricio Costa
28  Andrés Colubri
29 
30  Portions taken from
31  Wild Magic Source Code
32  David Eberly
33  http://www.geometrictools.com
34  Copyright (c) 1998-2007
35 
36 *******************************************************************************/
37 
38 #ifndef __MO_MATH_CURVE_H__
39 #define __MO_MATH_CURVE_H__
40 
41 #include "moMathVector.h"
42 #include "moMathVector3.h"
43 #include "moMathVector4.h"
45 
46 // moCurve2 class ------------------------------------------------------------
47 
48 template <class Real>
50 {
51 public:
52  // abstract base class
53 
54  moCurve2 (Real fTMin, Real fTMax)
55  {
56  m_fTMin = fTMin;
57  m_fTMax = fTMax;
58  }
59 
60 
61  virtual ~moCurve2 ()
62  {
63  }
64 
65 
66  // Interval on which curve parameter is defined. If you are interested
67  // in only a subinterval of the actual domain of the curve, you may set
68  // that subinterval with SetTimeInterval. This function requires that
69  // fTMin < fTMax.
70  Real GetMinTime () const
71  {
72  return m_fTMin;
73  }
74 
75 
76  Real GetMaxTime () const
77  {
78  return m_fTMax;
79  }
80 
81 
82  void SetTimeInterval (Real fTMin, Real fTMax)
83  {
84  m_fTMin = fTMin;
85  m_fTMax = fTMax;
86  }
87 
88 
89  // position and derivatives
90  virtual moVector2<Real> GetPosition (Real fTime) const = 0;
91  virtual moVector2<Real> GetFirstDerivative (Real fTime) const = 0;
92  virtual moVector2<Real> GetSecondDerivative (Real fTime) const = 0;
93  virtual moVector2<Real> GetThirdDerivative (Real fTime) const = 0;
94 
95  // differential geometric quantities
96  virtual Real GetLength (Real fT0, Real fT1) const = 0;
97 
98  Real GetSpeed (Real fTime) const
99  {
100  moVector2<Real> kVelocity = GetFirstDerivative(fTime);
101  Real fSpeed = kVelocity.Length();
102  return fSpeed;
103  }
104 
105 
106  Real GetTotalLength () const
107  {
108  return GetLength(m_fTMin,m_fTMax);
109  }
110 
111 
112  moVector2<Real> GetTangent (Real fTime) const
113  {
114  moVector2<Real> kVelocity = GetFirstDerivative(fTime);
115  kVelocity.Normalize();
116  return kVelocity;
117  }
118 
119 
120  moVector2<Real> GetNormal (Real fTime) const
121  {
122  moVector2<Real> kTangent = GetFirstDerivative(fTime);
123  kTangent.Normalize();
124  moVector2<Real> kNormal = kTangent.Perp();
125  return kNormal;
126  }
127 
128 
129  void GetFrame (Real fTime, moVector2<Real>& rkPosition,
130  moVector2<Real>& rkTangent, moVector2<Real>& rkNormal) const
131  {
132  rkPosition = GetPosition(fTime);
133  rkTangent = GetFirstDerivative(fTime);
134  rkTangent.Normalize();
135  rkNormal = rkTangent.Perp();
136  }
137 
138 
139  Real GetCurvature (Real fTime) const
140  {
141  moVector2<Real> kDer1 = GetFirstDerivative(fTime);
142  moVector2<Real> kDer2 = GetSecondDerivative(fTime);
143  Real fSpeedSqr = kDer1.SquaredLength();
144 
145  if (fSpeedSqr >= moMath<Real>::ZERO_TOLERANCE)
146  {
147  Real fNumer = kDer1.DotPerp(kDer2);
148  Real fDenom = moMath<Real>::Pow(fSpeedSqr,(Real)1.5);
149  return fNumer/fDenom;
150  }
151  else
152  {
153  // curvature is indeterminate, just return 0
154  return (Real)0.0;
155  }
156  }
157 
158 
159  void SubdivideByTime (int iNumPoints,
160  moVector2<Real>*& rakPoint) const
161  {
162  rakPoint = new moVector2<Real>[iNumPoints];
163 
164  Real fDelta = (m_fTMax - m_fTMin)/(iNumPoints-1);
165 
166  for (int i = 0; i < iNumPoints; i++)
167  {
168  Real fTime = m_fTMin + fDelta*i;
169  rakPoint[i] = GetPosition(fTime);
170  }
171  }
172 
173 
174 
175  // inverse mapping of s = Length(t) given by t = Length^{-1}(s)
176  virtual Real GetTime (Real fLength, int iIterations = 32,
177  Real fTolerance = (Real)1e-06) const = 0;
178 
179  // subdivision
180  void SubdivideByLength (int iNumPoints,
181  moVector2<Real>*& rakPoint) const
182  {
183  rakPoint = new moVector2<Real>[iNumPoints];
184 
185  Real fDelta = GetTotalLength()/(iNumPoints-1);
186 
187  for (int i = 0; i < iNumPoints; i++)
188  {
189  Real fLength = fDelta*i;
190  Real fTime = GetTime(fLength);
191  rakPoint[i] = GetPosition(fTime);
192  }
193  }
194 
195 
196 
197 
198 
199  void SubdivideByVariation (Real fMinVariation, int iMaxLevel,
200  int& riNumPoints, moVector2<Real>*& rakPoint) const
201  {
202  // compute end points of curve
203  moVector2<Real> kPMin = GetPosition(m_fTMin);
204  moVector2<Real> kPMax = GetPosition(m_fTMax);
205 
206  // add left end point to list
207  PointList* pkList = new PointList(kPMin,0);
208  riNumPoints = 1;
209 
210  // binary subdivision, leaf nodes add right end point of subinterval
211  SubdivideByVariation(m_fTMin,kPMin,m_fTMax,kPMax,fMinVariation,
212  iMaxLevel,riNumPoints,pkList->m_kNext);
213 
214  // repackage points in an array
215  rakPoint = new moVector2<Real>[riNumPoints];
216  for (int i = 0; i < riNumPoints; i++)
217  {
218  rakPoint[i] = pkList->m_kPoint;
219 
220  PointList* pkSave = pkList;
221  pkList = pkList->m_kNext;
222  delete pkSave;
223  }
224  }
225 
226  // Subdivision by variation. The pointers pkP0 and pkP1 correspond to the
227  // curve points at fT0 and fT1. If the pointer values are not null, the
228  // assumption is that the caller has passed in the curve points.
229  // Otherwise, the function computes the curve points.
230  virtual Real GetVariation (Real fT0, Real fT1,
231  const moVector2<Real>* pkP0 = 0, const moVector2<Real>* pkP1 = 0)
232  const = 0;
233 
234 
235 protected:
236  // curve parameter is t where tmin <= t <= tmax
237  Real m_fTMin, m_fTMax;
238 
239  // subdivision
241  {
242  public:
243  PointList (const moVector2<Real>& rkPoint, PointList* pkNext)
244  {
245  m_kPoint = rkPoint;
246  m_kNext = pkNext;
247  }
248 
251  };
252 
253  void SubdivideByVariation (Real fT0, const moVector2<Real>& rkP0,
254  Real fT1, const moVector2<Real>& rkP1, Real fMinVariation,
255  int iLevel, int& riNumPoints, PointList*& rpkList) const
256  {
257  if (iLevel > 0 && GetVariation(fT0,fT1,&rkP0,&rkP1) > fMinVariation)
258  {
259  // too much variation, subdivide interval
260  iLevel--;
261  Real fTMid = ((Real)0.5)*(fT0+fT1);
262  moVector2<Real> kPMid = GetPosition(fTMid);
263 
264  SubdivideByVariation(fT0,rkP0,fTMid,kPMid,fMinVariation,iLevel,
265  riNumPoints,rpkList);
266 
267  SubdivideByVariation(fTMid,kPMid,fT1,rkP1,fMinVariation,iLevel,
268  riNumPoints,rpkList);
269  }
270  else
271  {
272  // add right end point, left end point was added by neighbor
273  rpkList = new PointList(rkP1,rpkList);
274  riNumPoints++;
275  }
276  }
277 };
278 
280 typedef moCurve2<MOfloat> moCurve2f;
281 
283 typedef moCurve2<MOdouble> moCurve2d;
284 
285 // moSingleCurve2 class ------------------------------------------------------------
286 
287 template <class Real>
289 {
290 public:
291  // abstract base class
292 
293 
294  moSingleCurve2 (Real fTMin, Real fTMax) : moCurve2<Real>(fTMin,fTMax)
295  {
296  }
297 
298  // length-from-time and time-from-length
299  virtual Real GetLength (Real fT0, Real fT1) const {
303  return moIntegrate1<Real>::RombergIntegral(8,fT0,fT1,GetSpeedWithData,
304  (void*)this);
305  }
306  virtual Real GetTime (Real fLength, int iIterations = 32,
307  Real fTolerance = (Real)1e-06) const
308  {
309  if (fLength <= (Real)0.0)
310  {
311  return m_fTMin;
312  }
313 
314  if (fLength >= GetTotalLength())
315  {
316  return m_fTMax;
317  }
318 
319  // initial guess for Newton's method
320  Real fRatio = fLength/GetTotalLength();
321  Real fOmRatio = ((Real)1.0) - fRatio;
322  Real fTime = fOmRatio*m_fTMin + fRatio*m_fTMax;
323 
324  for (int i = 0; i < iIterations; i++)
325  {
326  Real fDifference = GetLength(m_fTMin,fTime) - fLength;
327  if (moMath<Real>::FAbs(fDifference) < fTolerance)
328  {
329  return fTime;
330  }
331 
332  fTime -= fDifference/this->GetSpeed(fTime);
333  }
334 
335  // Newton's method failed. You might want to increase iterations or
336  // tolerance or integration accuracy. However, in this application it
337  // is likely that the time values are oscillating, due to the limited
338  // numerical precision of 32-bit floats. It is safe to use the last
339  // computed time.
340  return fTime;
341  }
342 
343 protected:
347 
348  static Real GetSpeedWithData (Real fTime, void* pvData)
349  {
350  return ((moCurve2<Real>*)pvData)->GetSpeed(fTime);
351  }
352 };
353 
355 typedef moSingleCurve2<MOfloat> moSingleCurve2f;
356 
358 typedef moSingleCurve2<MOdouble> moSingleCurve2d;
359 
360 // moMultipleCurve2 class ------------------------------------------------------------
361 
362 template <class Real>
364 {
365 public:
366  // Construction and destruction for abstract base class. moMultipleCurve2
367  // accepts responsibility for deleting the input array.
368  moMultipleCurve2 (int iSegments, Real* afTime) : moCurve2<Real>(afTime[0],afTime[iSegments])
369  {
370  m_iSegments = iSegments;
371  m_afTime = afTime;
372  m_afLength = 0;
373  m_afAccumLength = 0;
374  }
375  virtual~moMultipleCurve2 () {
376  delete[] m_afTime;
377  delete[] m_afLength;
378  delete[] m_afAccumLength;
379  }
380 
381  // member access
382  int GetSegments () const {
383  return m_iSegments;
384  }
385  const Real* GetTimes () const {
386  return m_afTime;
387  }
388 
389  // length-from-time and time-from-length
390  virtual Real GetLength (Real fT0, Real fT1) const {
391  //assert(m_fTMin <= fT0 && fT0 <= m_fTMax);
392  //assert(m_fTMin <= fT1 && fT1 <= m_fTMax);
393  //assert(fT0 <= fT1);
394 
395  if (!m_afLength)
396  {
397  InitializeLength();
398  }
399 
400  int iKey0, iKey1;
401  Real fDt0, fDt1;
402  GetKeyInfo(fT0,iKey0,fDt0);
403  GetKeyInfo(fT1,iKey1,fDt1);
404 
405  Real fLength;
406  if (iKey0 < iKey1)
407  {
408  // accumulate full-segment lengths
409  fLength = (Real)0.0;
410  for (int i = iKey0+1; i < iKey1; i++)
411  {
412  fLength += m_afLength[i];
413  }
414 
415  // add on partial first segment
416  fLength += GetLengthKey(iKey0,fDt0,m_afTime[iKey0+1]-m_afTime[iKey0]);
417 
418  // add on partial last segment
419  fLength += GetLengthKey(iKey1,(Real)0.0,fDt1);
420  }
421  else
422  {
423  fLength = GetLengthKey(iKey0,fDt0,fDt1);
424  }
425 
426  return fLength;
427  }
428 
429  virtual Real GetTime (Real fLength, int iIterations = 32,
430  Real fTolerance = (Real)1e-06) const {
431  if (!m_afLength)
432  {
433  InitializeLength();
434  }
435 
436  if (fLength <= (Real)0.0)
437  {
438  return m_fTMin;
439  }
440 
441  if (fLength >= m_afAccumLength[m_iSegments-1])
442  {
443  return m_fTMax;
444  }
445 
446  int iKey;
447  for (iKey = 0; iKey < m_iSegments; iKey++)
448  {
449  if (fLength < m_afAccumLength[iKey])
450  {
451  break;
452  }
453  }
454  if (iKey >= m_iSegments)
455  {
456  return m_afTime[m_iSegments];
457  }
458 
459  // try Newton's method first for rapid convergence
460  Real fL0, fL1;
461  if (iKey == 0)
462  {
463  fL0 = fLength;
464  fL1 = m_afAccumLength[0];
465  }
466  else
467  {
468  fL0 = fLength - m_afAccumLength[iKey-1];
469  fL1 = m_afAccumLength[iKey] - m_afAccumLength[iKey-1];
470  }
471 
472  // use Newton's method to invert the arc length integral
473  Real fDt1 = m_afTime[iKey+1] - m_afTime[iKey];
474  Real fDt0 = fDt1*fL0/fL1;
475  for (int i = 0; i < iIterations; i++)
476  {
477  Real fDifference = GetLengthKey(iKey,(Real)0.0,fDt0) - fL0;
478  if (moMath<Real>::FAbs(fDifference) <= fTolerance)
479  {
480  return m_afTime[iKey] + fDt0;
481  }
482 
483  fDt0 -= fDifference/GetSpeedKey(iKey,fDt0);
484  }
485 
486  // Newton's method failed. You might want to increase iterations or
487  // tolerance or integration accuracy. However, in this application it
488  // is likely that the time values are oscillating, due to the limited
489  // numerical precision of 32-bit floats. It is safe to use the last
490  // computed time.
491  return m_afTime[iKey] + fDt0;
492  }
493 
494  // support for subdivision
495  virtual Real GetVariation (Real fT0, Real fT1,
496  const moVector2<Real>* pkP0 = 0, const moVector2<Real>* pkP1 = 0) const {
497  //assert(m_fTMin <= fT0 && fT0 <= m_fTMax);
498  //assert(m_fTMin <= fT1 && fT1 <= m_fTMax);
499  //assert(fT0 <= fT1);
500 
501  // construct line segment, A + (t-t0)*B
502  moVector2<Real> kP0, kP1;
503  if (!pkP0)
504  {
505  kP0 = this->GetPosition(fT0);
506  pkP0 = &kP0;
507  }
508  if (!pkP1)
509  {
510  kP1 = this->GetPosition(fT1);
511  pkP1 = &kP1;
512  }
513  Real fInvDT = ((Real)1.0)/(fT1 - fT0);
514  moVector2<Real> kA, kB = fInvDT*(*pkP1 - *pkP0);
515 
516  int iKey0, iKey1;
517  Real fDt0, fDt1;
518  GetKeyInfo(fT0,iKey0,fDt0);
519  GetKeyInfo(fT1,iKey1,fDt1);
520 
521  Real fVariation;
522  if (iKey0 < iKey1)
523  {
524  // accumulate full-segment variations
525  fVariation = (Real)0.0;
526  for (int i = iKey0+1; i < iKey1; i++)
527  {
528  kA = *pkP0 + (m_afTime[i] - fT0)*kB;
529  fVariation += GetVariationKey(i,(Real)0.0,
530  m_afTime[i+1]-m_afTime[i],kA,kB);
531  }
532 
533  // add on partial first segment
534  kA = *pkP0 + (m_afTime[iKey0] - fT0)*kB;
535  fVariation += GetVariationKey(iKey0,fDt0,
536  m_afTime[iKey0+1]-m_afTime[iKey0],kA,kB);
537 
538  // add on partial last segment
539  kA = *pkP0 + (m_afTime[iKey1] - fT0)*kB;
540  fVariation += GetVariationKey(iKey1,(Real)0.0,fDt1,kA,kB);
541  }
542  else
543  {
544  kA = *pkP0 + (m_afTime[iKey0] - fT0)*kB;
545  fVariation = GetVariationKey(iKey0,fDt0,fDt1,kA,kB);
546  }
547 
548  return fVariation;
549  }
550 
551 protected:
554 
556  Real* m_afTime;
557 
558  // These quantities are allocated by GetLength when they are needed the
559  // first time. The allocations occur in InitializeLength (called by
560  // GetLength), so this member function must be 'const'. In order to
561  // allocate the arrays in a 'const' function, they must be declared as
562  // 'mutable'.
563  mutable Real* m_afLength;
564  mutable Real* m_afAccumLength;
565 
566  void GetKeyInfo (Real fTime, int& riKey, Real& rfDt) const {
567  if (fTime <= m_afTime[0])
568  {
569  riKey = 0;
570  rfDt = (Real)0.0;
571  }
572  else if (fTime >= m_afTime[m_iSegments])
573  {
574  riKey = m_iSegments-1;
575  rfDt = m_afTime[m_iSegments] - m_afTime[m_iSegments-1];
576  }
577  else
578  {
579  for (int i = 0; i < m_iSegments; i++)
580  {
581  if (fTime < m_afTime[i+1])
582  {
583  riKey = i;
584  rfDt = fTime - m_afTime[i];
585  break;
586  }
587  }
588  }
589  }
590 
591  void InitializeLength () const {
592  m_afLength = new Real[m_iSegments];
593  m_afAccumLength = new Real[m_iSegments];
594 
595  // arc lengths of the segments
596  int iKey;
597  for (iKey = 0; iKey < m_iSegments; iKey++)
598  {
599  m_afLength[iKey] = GetLengthKey(iKey,(Real)0.0,
600  m_afTime[iKey+1]-m_afTime[iKey]);
601  }
602 
603  // accumulative arc length
604  m_afAccumLength[0] = m_afLength[0];
605  for (iKey = 1; iKey < m_iSegments; iKey++)
606  {
607  m_afAccumLength[iKey] = m_afAccumLength[iKey-1] + m_afLength[iKey];
608  }
609  }
610  virtual Real GetSpeedKey (int iKey, Real fTime) const = 0;
611  virtual Real GetLengthKey (int iKey, Real fT0, Real fT1) const = 0;
612  virtual Real GetVariationKey (int iKey, Real fT0, Real fT1,
613  const moVector2<Real>& rkA, const moVector2<Real>& rkB) const = 0;
614 
615  static Real GetSpeedWithData (Real fTime, void* pvData) {
616  moMultipleCurve2* pvThis = *(moMultipleCurve2**) pvData;
617  int iKey = *(int*)((char*)pvData + sizeof(pvThis));
618  return pvThis->GetSpeedKey(iKey,fTime);
619  }
620 };
621 
623 typedef moMultipleCurve2<MOfloat> moMultipleCurve2f;
624 
626 typedef moMultipleCurve2<MOdouble> moMultipleCurve2d;
627 
628 // moCurve3 class ------------------------------------------------------------
629 
630 template <class Real>
632 {
633 public:
634  // abstract base class
635  moCurve3 (Real fTMin, Real fTMax) {
636  m_fTMin = fTMin;
637  m_fTMax = fTMax;
638  }
639  virtual ~moCurve3 () {
640 
641  }
642 
643 
644  // Interval on which curve parameter is defined. If you are interested
645  // in only a subinterval of the actual domain of the curve, you may set
646  // that subinterval with SetTimeInterval. This function requires that
647  // fTMin < fTMax.
648  Real GetMinTime () const {
649  return m_fTMin;
650  }
651  Real GetMaxTime () const {
652  return m_fTMax;
653  }
654  void SetTimeInterval (Real fTMin, Real fTMax) {
655  //assert(fTMin < fTMax);
656  m_fTMin = fTMin;
657  m_fTMax = fTMax;
658  }
659 
660  // position and derivatives
661  virtual moVector3<Real> GetPosition (Real fTime) const = 0;
662  virtual moVector3<Real> GetFirstDerivative (Real fTime) const = 0;
663  virtual moVector3<Real> GetSecondDerivative (Real fTime) const = 0;
664  virtual moVector3<Real> GetThirdDerivative (Real fTime) const = 0;
665 
666  virtual Real GetTime (Real fLength, int iIterations = 32,
667  Real fTolerance = (Real)1e-06) const = 0;
668  virtual Real GetVariation (Real fT0, Real fT1,
669  const moVector3<Real>* pkP0, const moVector3<Real>* pkP1) const = 0;
670 
671  // differential geometric quantities
672 
673  virtual Real GetLength (Real fT0, Real fT1) const = 0;
674  Real GetSpeed (Real fTime) const
675  {
676  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
677  Real fSpeed = kVelocity.Length();
678  return fSpeed;
679  }
680  Real GetTotalLength () const
681  {
682  return GetLength(m_fTMin,m_fTMax);
683  }
684  moVector3<Real> GetTangent (Real fTime) const
685  {
686  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
687  kVelocity.Normalize();
688  return kVelocity;
689  }
690  moVector3<Real> GetNormal (Real fTime) const {
691  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
692  moVector3<Real> kAcceleration = GetSecondDerivative(fTime);
693  Real fVDotV = kVelocity.Dot(kVelocity);
694  Real fVDotA = kVelocity.Dot(kAcceleration);
695  moVector3<Real> kNormal = fVDotV*kAcceleration - fVDotA*kVelocity;
696  kNormal.Normalize();
697  return kNormal;
698  }
699 
700  moVector3<Real> GetBinormal (Real fTime) const
701  {
702  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
703  moVector3<Real> kAcceleration = GetSecondDerivative(fTime);
704  Real fVDotV = kVelocity.Dot(kVelocity);
705  Real fVDotA = kVelocity.Dot(kAcceleration);
706  moVector3<Real> kNormal = fVDotV*kAcceleration - fVDotA*kVelocity;
707  kNormal.Normalize();
708  kVelocity.Normalize();
709  moVector3<Real> kBinormal = kVelocity.Cross(kNormal);
710  return kBinormal;
711  }
712 
713 
714  void GetFrame (Real fTime, moVector3<Real>& rkPosition,
715  moVector3<Real>& rkTangent, moVector3<Real>& rkNormal,
716  moVector3<Real>& rkBinormal) const
717  {
718  rkPosition = GetPosition(fTime);
719  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
720  moVector3<Real> kAcceleration = GetSecondDerivative(fTime);
721  Real fVDotV = kVelocity.Dot(kVelocity);
722  Real fVDotA = kVelocity.Dot(kAcceleration);
723  rkNormal = fVDotV*kAcceleration - fVDotA*kVelocity;
724  rkNormal.Normalize();
725  rkTangent = kVelocity;
726  rkTangent.Normalize();
727  rkBinormal = rkTangent.Cross(rkNormal);
728  }
729 
730 
731  Real GetCurvature (Real fTime) const
732  {
733  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
734  Real fSpeedSqr = kVelocity.SquaredLength();
735 
736  if (fSpeedSqr >= moMath<Real>::ZERO_TOLERANCE)
737  {
738  moVector3<Real> kAcceleration = GetSecondDerivative(fTime);
739  moVector3<Real> kCross = kVelocity.Cross(kAcceleration);
740  Real fNumer = kCross.Length();
741  Real fDenom = moMath<Real>::Pow(fSpeedSqr,(Real)1.5);
742  return fNumer/fDenom;
743  }
744  else
745  {
746  // curvature is indeterminate, just return 0
747  return (Real)0.0;
748  }
749  }
750 
751 
752  Real GetTorsion (Real fTime) const
753  {
754  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
755  moVector3<Real> kAcceleration = GetSecondDerivative(fTime);
756  moVector3<Real> kCross = kVelocity.Cross(kAcceleration);
757  Real fDenom = kCross.SquaredLength();
758 
759  if (fDenom >= moMath<Real>::ZERO_TOLERANCE)
760  {
761  moVector3<Real> kJerk = GetThirdDerivative(fTime);
762  Real fNumer = kCross.Dot(kJerk);
763  return fNumer/fDenom;
764  }
765  else
766  {
767  // torsion is indeterminate, just return 0
768  return (Real)0.0;
769  }
770  }
771 
772 
773  void SubdivideByTime (int iNumPoints,
774  moVector3<Real>*& rakPoint) const
775  {
776  //assert( iNumPoints >= 2 );
777  rakPoint = new moVector3<Real>[iNumPoints];
778 
779  Real fDelta = (m_fTMax - m_fTMin)/(iNumPoints-1);
780 
781  for (int i = 0; i < iNumPoints; i++)
782  {
783  Real fTime = m_fTMin + fDelta*i;
784  rakPoint[i] = GetPosition(fTime);
785  }
786  }
787 
788 
789  void SubdivideByLength (int iNumPoints,
790  moVector3<Real>*& rakPoint) const
791  {
792  //assert(iNumPoints >= 2);
793  rakPoint = new moVector3<Real>[iNumPoints];
794 
795  Real fDelta = GetTotalLength()/(iNumPoints-1);
796 
797  for (int i = 0; i < iNumPoints; i++)
798  {
799  Real fLength = fDelta*i;
800  Real fTime = GetTime(fLength);
801  rakPoint[i] = GetPosition(fTime);
802  }
803  }
804 
805 
806 protected:
807  // curve parameter is t where tmin <= t <= tmax
808  Real m_fTMin, m_fTMax;
809 
810  // subdivision
812  {
813  public:
814  PointList (const moVector3<Real>& rkPoint, PointList* pkNext)
815  {
816  m_kPoint = rkPoint;
817  m_kNext = pkNext;
818  }
819 
822  };
823 
824  void SubdivideByVariation (Real fT0, const moVector3<Real>& rkP0,
825  Real fT1, const moVector3<Real>& rkP1, Real fMinVariation, int iLevel,
826  int& riNumPoints, PointList*& rpkList) const
827  {
828  if (iLevel > 0 && GetVariation(fT0,fT1,&rkP0,&rkP1) > fMinVariation)
829  {
830  // too much variation, subdivide interval
831  iLevel--;
832  Real fTMid = ((Real)0.5)*(fT0+fT1);
833  moVector3<Real> kPMid = GetPosition(fTMid);
834 
835  SubdivideByVariation(fT0,rkP0,fTMid,kPMid,fMinVariation,iLevel,
836  riNumPoints,rpkList);
837 
838  SubdivideByVariation(fTMid,kPMid,fT1,rkP1,fMinVariation,iLevel,
839  riNumPoints,rpkList);
840  }
841  else
842  {
843  // add right end point, left end point was added by neighbor
844  rpkList = new PointList(rkP1,rpkList);
845  riNumPoints++;
846  }
847  }
848 };
849 
851 typedef moCurve3<MOfloat> moCurve3f;
852 
854 typedef moCurve3<MOdouble> moCurve3d;
855 
856 // moSingleCurve3 ------------------------------------------------------------
857 
858 template <class Real>
860 {
861 public:
862  // abstract base class
863  moSingleCurve3 (Real fTMin, Real fTMax) :
864  moCurve3<Real>(fTMin,fTMax) {
865  }
866 
867  // length-from-time and time-from-length
868  virtual Real GetLength (Real fT0, Real fT1) const {
869  return moIntegrate1<Real>::RombergIntegral(8,fT0,fT1,GetSpeedWithData,
870  (void*)this);
871  }
872 
873  Real GetTime (Real fLength, int iIterations,
874  Real fTolerance) const
875  {
876  if (fLength <= (Real)0.0)
877  {
878  return m_fTMin;
879  }
880 
881  if (fLength >= GetTotalLength())
882  {
883  return m_fTMax;
884  }
885 
886  // initial guess for Newton's method
887  Real fRatio = fLength/GetTotalLength();
888  Real fOmRatio = (Real)1.0 - fRatio;
889  Real fTime = fOmRatio*m_fTMin + fRatio*m_fTMax;
890 
891  for (int i = 0; i < iIterations; i++)
892  {
893  Real fDifference = GetLength(m_fTMin,fTime) - fLength;
894  if (moMath<Real>::FAbs(fDifference) < fTolerance)
895  {
896  return fTime;
897  }
898 
899  fTime -= fDifference/this->GetSpeed(fTime);
900  }
901 
902  // Newton's method failed. You might want to increase iterations or
903  // tolerance or integration accuracy. However, in this application it
904  // is likely that the time values are oscillating, due to the limited
905  // numerical precision of 32-bit floats. It is safe to use the last
906  // computed time.
907  return fTime;
908  }
909 
910 
911 protected:
915 
916  static Real GetSpeedWithData (Real fTime, void* pvData) {
917  return ((moCurve3<Real>*)pvData)->GetSpeed(fTime);
918  }
919 };
920 
922 typedef moSingleCurve3<MOfloat> moSingleCurve3f;
923 
925 typedef moSingleCurve3<MOdouble> moSingleCurve3d;
926 
927 // moMultipleCurve3 ------------------------------------------------------------
928 
929 template <class Real>
931 {
932 public:
933  // Construction and destruction for abstract base class. moMultipleCurve3
934  // accepts responsibility for deleting the input array.
935  moMultipleCurve3 (int iSegments, Real* afTime)
936  :
937  moCurve3<Real>(afTime[0],afTime[iSegments])
938  {
939  m_iSegments = iSegments;
940  m_afTime = afTime;
941  m_afLength = 0;
942  m_afAccumLength = 0;
943  }
944  virtual ~moMultipleCurve3 () {
945  delete[] m_afTime;
946  delete[] m_afLength;
947  delete[] m_afAccumLength;
948  }
949 
950  // member access
951  int GetSegments () const {
952  return m_iSegments;
953  }
954  const Real* GetTimes () const {
955  return m_afTime;
956  }
957 
958  // length-from-time and time-from-length
959  virtual Real GetLength (Real fT0, Real fT1) const {
960  if (!m_afLength)
961  {
962  InitializeLength();
963  }
964 
965  int iKey0, iKey1;
966  Real fDt0, fDt1;
967  GetKeyInfo(fT0,iKey0,fDt0);
968  GetKeyInfo(fT1,iKey1,fDt1);
969 
970  Real fLength;
971  if (iKey0 < iKey1)
972  {
973  // accumulate full-segment lengths
974  fLength = (Real)0.0;
975  for (int i = iKey0+1; i < iKey1; i++)
976  fLength += m_afLength[i];
977 
978  // add on partial first segment
979  fLength += GetLengthKey(iKey0,fDt0,m_afTime[iKey0+1]-m_afTime[iKey0]);
980 
981  // add on partial last segment
982  fLength += GetLengthKey(iKey1,(Real)0.0,fDt1);
983  }
984  else
985  {
986  fLength = GetLengthKey(iKey0,fDt0,fDt1);
987  }
988 
989  return fLength;
990 
991  }
992  virtual Real GetTime (Real fLength, int iIterations = 32,
993  Real fTolerance = (Real)1e-06) const {
994  if (!m_afLength)
995  {
996  InitializeLength();
997  }
998 
999  if (fLength <= (Real)0.0)
1000  {
1001  return m_fTMin;
1002  }
1003 
1004  if (fLength >= m_afAccumLength[m_iSegments-1])
1005  {
1006  return m_fTMax;
1007  }
1008 
1009  int iKey;
1010  for (iKey = 0; iKey < m_iSegments; iKey++)
1011  {
1012  if (fLength < m_afAccumLength[iKey])
1013  {
1014  break;
1015  }
1016  }
1017  if (iKey >= m_iSegments)
1018  {
1019  return m_afTime[m_iSegments];
1020  }
1021 
1022  // try Newton's method first for rapid convergence
1023  Real fL0, fL1;
1024  if (iKey == 0)
1025  {
1026  fL0 = fLength;
1027  fL1 = m_afAccumLength[0];
1028  }
1029  else
1030  {
1031  fL0 = fLength - m_afAccumLength[iKey-1];
1032  fL1 = m_afAccumLength[iKey] - m_afAccumLength[iKey-1];
1033  }
1034 
1035  // use Newton's method to invert the arc length integral
1036  Real fDt1 = m_afTime[iKey+1] - m_afTime[iKey];
1037  Real fDt0 = fDt1*fL0/fL1;
1038  for (int i = 0; i < iIterations; i++)
1039  {
1040  Real fDifference = GetLengthKey(iKey,(Real)0.0,fDt0) - fL0;
1041  if (moMath<Real>::FAbs(fDifference) <= fTolerance)
1042  {
1043  return m_afTime[iKey] + fDt0;
1044  }
1045 
1046  fDt0 -= fDifference/GetSpeedKey(iKey,fDt0);
1047  }
1048 
1049  // Newton's method failed. You might want to increase iterations or
1050  // tolerance or integration accuracy. However, in this application it
1051  // is likely that the time values are oscillating, due to the limited
1052  // numerical precision of 32-bit floats. It is safe to use the last
1053  // computed time.
1054  return m_afTime[iKey] + fDt0;
1055 
1056  }
1057 
1058  // support for subdivision
1059  virtual Real GetVariation (Real fT0, Real fT1,
1060  const moVector3<Real>* pkP0 = 0, const moVector3<Real>* pkP1 = 0) const {
1061  //assert(m_fTMin <= fT0 && fT0 <= m_fTMax);
1062  //assert(m_fTMin <= fT1 && fT1 <= m_fTMax);
1063  //assert(fT0 <= fT1);
1064 
1065  // construct line segment, A + (t-t0)*B
1066  moVector3<Real> kP0, kP1;
1067  if (!pkP0)
1068  {
1069  kP0 = this->GetPosition(fT0);
1070  pkP0 = &kP0;
1071  }
1072  if (!pkP1)
1073  {
1074  kP1 = this->GetPosition(fT1);
1075  pkP1 = &kP1;
1076  }
1077  Real fInvDT = ((Real)1.0)/(fT1 - fT0);
1078  moVector3<Real> kA, kB = fInvDT*(*pkP1 - *pkP0);
1079 
1080  int iKey0, iKey1;
1081  Real fDt0, fDt1;
1082  GetKeyInfo(fT0,iKey0,fDt0);
1083  GetKeyInfo(fT1,iKey1,fDt1);
1084 
1085  Real fVariation;
1086  if (iKey0 < iKey1)
1087  {
1088  // accumulate full-segment variations
1089  fVariation = (Real)0.0;
1090  for (int i = iKey0+1; i < iKey1; i++)
1091  {
1092  kA = *pkP0 + (m_afTime[i] - fT0)*kB;
1093  fVariation += GetVariationKey(i,(Real)0.0,
1094  m_afTime[i+1]-m_afTime[i],kA,kB);
1095  }
1096 
1097  // add on partial first segment
1098  kA = *pkP0 + (m_afTime[iKey0] - fT0)*kB;
1099  fVariation += GetVariationKey(iKey0,fDt0,
1100  m_afTime[iKey0+1]-m_afTime[iKey0],kA,kB);
1101 
1102  // add on partial last segment
1103  kA = *pkP0 + (m_afTime[iKey1] - fT0)*kB;
1104  fVariation += GetVariationKey(iKey1,0.0f,fDt1,kA,kB);
1105  }
1106  else
1107  {
1108  kA = *pkP0 + (m_afTime[iKey0] - fT0)*kB;
1109  fVariation = GetVariationKey(iKey0,fDt0,fDt1,kA,kB);
1110  }
1111 
1112  return fVariation; }
1113 
1114 protected:
1117 
1119  Real* m_afTime;
1120 
1121  // These quantities are allocated by GetLength when they are needed the
1122  // first time. The allocations occur in InitializeLength (called by
1123  // GetLength), so this member function must be 'const'. In order to
1124  // allocate the arrays in a 'const' function, they must be declared as
1125  // 'mutable'.
1126  mutable Real* m_afLength;
1127  mutable Real* m_afAccumLength;
1128 
1129  void GetKeyInfo (Real fTime, int& riKey, Real& rfDt) const {
1130  if (fTime <= m_afTime[0])
1131  {
1132  riKey = 0;
1133  rfDt = (Real)0.0;
1134  }
1135  else if (fTime >= m_afTime[m_iSegments])
1136  {
1137  riKey = m_iSegments-1;
1138  rfDt = m_afTime[m_iSegments] - m_afTime[m_iSegments-1];
1139  }
1140  else
1141  {
1142  for (int i = 0; i < m_iSegments; i++)
1143  {
1144  if (fTime < m_afTime[i+1])
1145  {
1146  riKey = i;
1147  rfDt = fTime - m_afTime[i];
1148  break;
1149  }
1150  }
1151  }
1152  }
1153 
1154  void InitializeLength () const {
1155  m_afLength = new Real[m_iSegments];
1156  m_afAccumLength = new Real[m_iSegments];
1157 
1158  // arc lengths of the segments
1159  int iKey;
1160  for (iKey = 0; iKey < m_iSegments; iKey++)
1161  {
1162  m_afLength[iKey] = GetLengthKey(iKey,(Real)0.0,
1163  m_afTime[iKey+1]-m_afTime[iKey]);
1164  }
1165 
1166  // accumulative arc length
1167  m_afAccumLength[0] = m_afLength[0];
1168  for (iKey = 1; iKey < m_iSegments; iKey++)
1169  {
1170  m_afAccumLength[iKey] = m_afAccumLength[iKey-1] + m_afLength[iKey];
1171  }
1172  }
1173  virtual Real GetSpeedKey (int iKey, Real fTime) const = 0;
1174  virtual Real GetLengthKey (int iKey, Real fT0, Real fT1) const = 0;
1175  virtual Real GetVariationKey (int iKey, Real fT0, Real fT1,
1176  const moVector3<Real>& rkA, const moVector3<Real>& rkB) const = 0;
1177 
1178  static Real GetSpeedWithData (Real fTime, void* pvData) {
1179  moMultipleCurve3* pvThis = *(moMultipleCurve3**) pvData;
1180  int iKey = *(int*)((char*)pvData + sizeof(pvThis));
1181  return pvThis->GetSpeedKey(iKey,fTime);
1182  }
1183 };
1184 
1186 typedef moMultipleCurve3<MOfloat> moMultipleCurve3f;
1187 
1189 typedef moMultipleCurve3<MOdouble> moMultipleCurve3d;
1190 
1191 #endif
1192 
Real Length() const
moVector3< Real > GetTangent(Real fTime) const
Definition: moMathCurve.h:684
Real GetSpeed(Real fTime) const
Definition: moMathCurve.h:98
void GetKeyInfo(Real fTime, int &riKey, Real &rfDt) const
Definition: moMathCurve.h:1129
PointList * m_kNext
Definition: moMathCurve.h:250
moSingleCurve3< MOfloat > moSingleCurve3f
Definition: moMathCurve.h:922
virtual ~moCurve3()
Definition: moMathCurve.h:639
Real GetTotalLength() const
Definition: moMathCurve.h:106
moMultipleCurve2< MOfloat > moMultipleCurve2f
Definition: moMathCurve.h:623
Real * m_afAccumLength
Definition: moMathCurve.h:1127
virtual Real GetVariation(Real fT0, Real fT1, const moVector2< Real > *pkP0=0, const moVector2< Real > *pkP1=0) const
Definition: moMathCurve.h:495
Real SquaredLength() const
Real GetTime(Real fLength, int iIterations, Real fTolerance) const
Definition: moMathCurve.h:873
void SetTimeInterval(Real fTMin, Real fTMax)
Definition: moMathCurve.h:654
static Real GetSpeedWithData(Real fTime, void *pvData)
Definition: moMathCurve.h:916
moCurve3< MOfloat > moCurve3f
Definition: moMathCurve.h:851
void SubdivideByTime(int iNumPoints, moVector3< Real > *&rakPoint) const
Definition: moMathCurve.h:773
moMultipleCurve2(int iSegments, Real *afTime)
Definition: moMathCurve.h:368
static Real RombergIntegral(int iOrder, Real fA, Real fB, Function oF, void *pvUserData=0)
virtual Real GetLength(Real fT0, Real fT1) const
Definition: moMathCurve.h:868
moSingleCurve2< MOdouble > moSingleCurve2d
Definition: moMathCurve.h:358
void InitializeLength() const
Definition: moMathCurve.h:591
moMultipleCurve3< MOfloat > moMultipleCurve3f
Definition: moMathCurve.h:1186
Real GetTotalLength() const
Definition: moMathCurve.h:680
const Real * GetTimes() const
Definition: moMathCurve.h:385
Clase base abstracta de donde deben derivar los objetos [virtual pura].
Definition: moAbstract.h:191
void InitializeLength() const
Definition: moMathCurve.h:1154
virtual Real GetSpeedKey(int iKey, Real fTime) const =0
virtual ~moMultipleCurve3()
Definition: moMathCurve.h:944
virtual ~moMultipleCurve2()
Definition: moMathCurve.h:375
int GetSegments() const
Definition: moMathCurve.h:382
moVector2< Real > GetTangent(Real fTime) const
Definition: moMathCurve.h:112
Real GetMinTime() const
Definition: moMathCurve.h:648
moSingleCurve3(Real fTMin, Real fTMax)
Definition: moMathCurve.h:863
#define LIBMOLDEO_API
Definition: moTypes.h:180
moCurve2< MOdouble > moCurve2d
Definition: moMathCurve.h:283
virtual Real GetLength(Real fT0, Real fT1) const
Definition: moMathCurve.h:959
Real m_fTMin
Definition: moMathCurve.h:808
virtual Real GetVariation(Real fT0, Real fT1, const moVector3< Real > *pkP0=0, const moVector3< Real > *pkP1=0) const
Definition: moMathCurve.h:1059
void SetTimeInterval(Real fTMin, Real fTMax)
Definition: moMathCurve.h:82
virtual ~moCurve2()
Definition: moMathCurve.h:61
void GetFrame(Real fTime, moVector2< Real > &rkPosition, moVector2< Real > &rkTangent, moVector2< Real > &rkNormal) const
Definition: moMathCurve.h:129
void SubdivideByLength(int iNumPoints, moVector2< Real > *&rakPoint) const
Definition: moMathCurve.h:180
PointList(const moVector2< Real > &rkPoint, PointList *pkNext)
Definition: moMathCurve.h:243
Real Normalize()
Definition: moMathVector.h:179
Real GetSpeed(Real fTime) const
Definition: moMathCurve.h:674
Real m_fTMin
Definition: moMathCurve.h:237
Real GetMinTime() const
Definition: moMathCurve.h:70
void SubdivideByVariation(Real fT0, const moVector2< Real > &rkP0, Real fT1, const moVector2< Real > &rkP1, Real fMinVariation, int iLevel, int &riNumPoints, PointList *&rpkList) const
Definition: moMathCurve.h:253
moVector2< Real > GetNormal(Real fTime) const
Definition: moMathCurve.h:120
virtual Real GetTime(Real fLength, int iIterations=32, Real fTolerance=(Real) 1e-06) const
Definition: moMathCurve.h:992
Real GetTorsion(Real fTime) const
Definition: moMathCurve.h:752
void GetKeyInfo(Real fTime, int &riKey, Real &rfDt) const
Definition: moMathCurve.h:566
moMultipleCurve3(int iSegments, Real *afTime)
Definition: moMathCurve.h:935
Real * m_afAccumLength
Definition: moMathCurve.h:564
void SubdivideByVariation(Real fMinVariation, int iMaxLevel, int &riNumPoints, moVector2< Real > *&rakPoint) const
Definition: moMathCurve.h:199
virtual Real GetSpeedKey(int iKey, Real fTime) const =0
Real Dot(const moVector3 &rkV) const
void SubdivideByTime(int iNumPoints, moVector2< Real > *&rakPoint) const
Definition: moMathCurve.h:159
moCurve2< MOfloat > moCurve2f
Definition: moMathCurve.h:280
void SubdivideByLength(int iNumPoints, moVector3< Real > *&rakPoint) const
Definition: moMathCurve.h:789
static Real GetSpeedWithData(Real fTime, void *pvData)
Definition: moMathCurve.h:348
Real GetMaxTime() const
Definition: moMathCurve.h:76
Real Normalize()
moMultipleCurve3< MOdouble > moMultipleCurve3d
Definition: moMathCurve.h:1189
Real GetCurvature(Real fTime) const
Definition: moMathCurve.h:139
moSingleCurve2< MOfloat > moSingleCurve2f
Definition: moMathCurve.h:355
moVector3< Real > GetBinormal(Real fTime) const
Definition: moMathCurve.h:700
void SubdivideByVariation(Real fT0, const moVector3< Real > &rkP0, Real fT1, const moVector3< Real > &rkP1, Real fMinVariation, int iLevel, int &riNumPoints, PointList *&rpkList) const
Definition: moMathCurve.h:824
virtual Real GetLength(Real fT0, Real fT1) const
Definition: moMathCurve.h:299
virtual Real GetLength(Real fT0, Real fT1) const
Definition: moMathCurve.h:390
virtual Real GetTime(Real fLength, int iIterations=32, Real fTolerance=(Real) 1e-06) const
Definition: moMathCurve.h:429
moCurve3< MOdouble > moCurve3d
Definition: moMathCurve.h:854
PointList(const moVector3< Real > &rkPoint, PointList *pkNext)
Definition: moMathCurve.h:814
moVector3 Cross(const moVector3 &rkV) const
PointList * m_kNext
Definition: moMathCurve.h:821
Real SquaredLength() const
Definition: moMathVector.h:173
static Real GetSpeedWithData(Real fTime, void *pvData)
Definition: moMathCurve.h:615
Definition: moMath.h:64
const Real * GetTimes() const
Definition: moMathCurve.h:954
moCurve2(Real fTMin, Real fTMax)
Definition: moMathCurve.h:54
Real DotPerp(const moVector2 &rkV) const
returns DotPerp((x,y),(V.x,V.y)) = x*V.y - y*V.x
Definition: moMathVector.h:212
moVector2< Real > m_kPoint
Definition: moMathCurve.h:249
static Real Pow(Real fBase, Real fExponent)
Definition: moMath.h:250
int GetSegments() const
Definition: moMathCurve.h:951
moVector2 Perp() const
returns (y,-x)
Definition: moMathVector.h:199
moSingleCurve3< MOdouble > moSingleCurve3d
Definition: moMathCurve.h:925
moVector3< Real > GetNormal(Real fTime) const
Definition: moMathCurve.h:690
void GetFrame(Real fTime, moVector3< Real > &rkPosition, moVector3< Real > &rkTangent, moVector3< Real > &rkNormal, moVector3< Real > &rkBinormal) const
Definition: moMathCurve.h:714
Real Length() const
Definition: moMathVector.h:170
moVector3< Real > m_kPoint
Definition: moMathCurve.h:820
moMultipleCurve2< MOdouble > moMultipleCurve2d
Definition: moMathCurve.h:626
Real GetCurvature(Real fTime) const
Definition: moMathCurve.h:731
moSingleCurve2(Real fTMin, Real fTMax)
Definition: moMathCurve.h:294
Real GetMaxTime() const
Definition: moMathCurve.h:651
static Real GetSpeedWithData(Real fTime, void *pvData)
Definition: moMathCurve.h:1178
virtual Real GetTime(Real fLength, int iIterations=32, Real fTolerance=(Real) 1e-06) const
Definition: moMathCurve.h:306
moCurve3(Real fTMin, Real fTMax)
Definition: moMathCurve.h:635