libmoldeo (Moldeo 1.0 Core)  1.0
libmoldeo es el conjunto de objetos y funciones, que permiten ejecutar las operaciones básicas de la plataforma Moldeo, y que compone su núcleo.
 Todo Clases Namespaces Archivos Funciones Variables 'typedefs' Enumeraciones Valores de enumeraciones Amigas 'defines' Grupos Páginas
moMathCurve.cpp
Ir a la documentación de este archivo.
1 /*******************************************************************************
2 
3  moMathCurve.cpp
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 #include "moMathCurve.h"
39 
40 // moCurve2 class ------------------------------------------------------------
41 /*
42 template <class Real>
43 moCurve2<Real>::moCurve2 (Real fTMin, Real fTMax)
44 {
45  m_fTMin = fTMin;
46  m_fTMax = fTMax;
47 }
48 
49 template <class Real>
50 moCurve2<Real>::~moCurve2 ()
51 {
52 }
53 
54 template <class Real>
55 Real moCurve2<Real>::GetMinTime () const
56 {
57  return m_fTMin;
58 }
59 
60 template <class Real>
61 Real moCurve2<Real>::GetMaxTime () const
62 {
63  return m_fTMax;
64 }
65 
66 template <class Real>
67 void moCurve2<Real>::SetTimeInterval (Real fTMin, Real fTMax)
68 {
69  m_fTMin = fTMin;
70  m_fTMax = fTMax;
71 }
72 
73 template <class Real>
74 Real moCurve2<Real>::GetSpeed (Real fTime) const
75 {
76  moVector2<Real> kVelocity = GetFirstDerivative(fTime);
77  Real fSpeed = kVelocity.Length();
78  return fSpeed;
79 }
80 
81 template <class Real>
82 Real moCurve2<Real>::GetTotalLength () const
83 {
84  return GetLength(m_fTMin,m_fTMax);
85 }
86 
87 template <class Real>
88 moVector2<Real> moCurve2<Real>::GetTangent (Real fTime) const
89 {
90  moVector2<Real> kVelocity = GetFirstDerivative(fTime);
91  kVelocity.Normalize();
92  return kVelocity;
93 }
94 
95 template <class Real>
96 moVector2<Real> moCurve2<Real>::GetNormal (Real fTime) const
97 {
98  moVector2<Real> kTangent = GetFirstDerivative(fTime);
99  kTangent.Normalize();
100  moVector2<Real> kNormal = kTangent.Perp();
101  return kNormal;
102 }
103 
104 template <class Real>
105 void moCurve2<Real>::GetFrame (Real fTime, moVector2<Real>& rkPosition,
106  moVector2<Real>& rkTangent, moVector2<Real>& rkNormal) const
107 {
108  rkPosition = GetPosition(fTime);
109  rkTangent = GetFirstDerivative(fTime);
110  rkTangent.Normalize();
111  rkNormal = rkTangent.Perp();
112 }
113 
114 template <class Real>
115 Real moCurve2<Real>::GetCurvature (Real fTime) const
116 {
117  moVector2<Real> kDer1 = GetFirstDerivative(fTime);
118  moVector2<Real> kDer2 = GetSecondDerivative(fTime);
119  Real fSpeedSqr = kDer1.SquaredLength();
120 
121  if (fSpeedSqr >= moMath<Real>::ZERO_TOLERANCE)
122  {
123  Real fNumer = kDer1.DotPerp(kDer2);
124  Real fDenom = moMath<Real>::Pow(fSpeedSqr,(Real)1.5);
125  return fNumer/fDenom;
126  }
127  else
128  {
129  // curvature is indeterminate, just return 0
130  return (Real)0.0;
131  }
132 }
133 
134 template <class Real>
135 void moCurve2<Real>::SubdivideByTime (int iNumPoints,
136  moVector2<Real>*& rakPoint) const
137 {
138  rakPoint = new moVector2<Real>[iNumPoints];
139 
140  Real fDelta = (m_fTMax - m_fTMin)/(iNumPoints-1);
141 
142  for (int i = 0; i < iNumPoints; i++)
143  {
144  Real fTime = m_fTMin + fDelta*i;
145  rakPoint[i] = GetPosition(fTime);
146  }
147 }
148 
149 template <class Real>
150 void moCurve2<Real>::SubdivideByLength (int iNumPoints,
151  moVector2<Real>*& rakPoint) const
152 {
153  rakPoint = new moVector2<Real>[iNumPoints];
154 
155  Real fDelta = GetTotalLength()/(iNumPoints-1);
156 
157  for (int i = 0; i < iNumPoints; i++)
158  {
159  Real fLength = fDelta*i;
160  Real fTime = GetTime(fLength);
161  rakPoint[i] = GetPosition(fTime);
162  }
163 }
164 
165 template <class Real>
166 void moCurve2<Real>::SubdivideByVariation (Real fT0, const moVector2<Real>& rkP0,
167  Real fT1, const moVector2<Real>& rkP1, Real fMinVariation,
168  int iLevel, int& riNumPoints, PointList*& rpkList) const
169 {
170  if (iLevel > 0 && GetVariation(fT0,fT1,&rkP0,&rkP1) > fMinVariation)
171  {
172  // too much variation, subdivide interval
173  iLevel--;
174  Real fTMid = ((Real)0.5)*(fT0+fT1);
175  moVector2<Real> kPMid = GetPosition(fTMid);
176 
177  SubdivideByVariation(fT0,rkP0,fTMid,kPMid,fMinVariation,iLevel,
178  riNumPoints,rpkList);
179 
180  SubdivideByVariation(fTMid,kPMid,fT1,rkP1,fMinVariation,iLevel,
181  riNumPoints,rpkList);
182  }
183  else
184  {
185  // add right end point, left end point was added by neighbor
186  rpkList = new PointList(rkP1,rpkList);
187  riNumPoints++;
188  }
189 }
190 
191 template <class Real>
192 void moCurve2<Real>::SubdivideByVariation (Real fMinVariation, int iMaxLevel,
193  int& riNumPoints, moVector2<Real>*& rakPoint) const
194 {
195  // compute end points of curve
196  moVector2<Real> kPMin = GetPosition(m_fTMin);
197  moVector2<Real> kPMax = GetPosition(m_fTMax);
198 
199  // add left end point to list
200  PointList* pkList = new PointList(kPMin,0);
201  riNumPoints = 1;
202 
203  // binary subdivision, leaf nodes add right end point of subinterval
204  SubdivideByVariation(m_fTMin,kPMin,m_fTMax,kPMax,fMinVariation,
205  iMaxLevel,riNumPoints,pkList->m_kNext);
206 
207  // repackage points in an array
208  rakPoint = new moVector2<Real>[riNumPoints];
209  for (int i = 0; i < riNumPoints; i++)
210  {
211  rakPoint[i] = pkList->m_kPoint;
212 
213  PointList* pkSave = pkList;
214  pkList = pkList->m_kNext;
215  delete pkSave;
216  }
217 }
218 */
219 // moSingleCurve2 class ------------------------------------------------------------
220 /*
221 template <class Real>
222 moSingleCurve2<Real>::moSingleCurve2 (Real fTMin, Real fTMax)
223  :
224  moCurve2<Real>(fTMin,fTMax)
225 {
226 }
227 
228 template <class Real>
229 Real moSingleCurve2<Real>::GetSpeedWithData (Real fTime, void* pvData)
230 {
231  return ((moCurve2<Real>*)pvData)->GetSpeed(fTime);
232 }
233 
234 template <class Real>
235 Real moSingleCurve2<Real>::GetLength (Real fT0, Real fT1) const
236 {
240 
241  return moIntegrate1<Real>::RombergIntegral(8,fT0,fT1,GetSpeedWithData,
242  (void*)this);
243 }
244 
245 template <class Real>
246 Real moSingleCurve2<Real>::GetTime (Real fLength, int iIterations,
247  Real fTolerance) const
248 {
249  if (fLength <= (Real)0.0)
250  {
251  return m_fTMin;
252  }
253 
254  if (fLength >= GetTotalLength())
255  {
256  return m_fTMax;
257  }
258 
259  // initial guess for Newton's method
260  Real fRatio = fLength/GetTotalLength();
261  Real fOmRatio = ((Real)1.0) - fRatio;
262  Real fTime = fOmRatio*m_fTMin + fRatio*m_fTMax;
263 
264  for (int i = 0; i < iIterations; i++)
265  {
266  Real fDifference = GetLength(m_fTMin,fTime) - fLength;
267  if (moMath<Real>::FAbs(fDifference) < fTolerance)
268  {
269  return fTime;
270  }
271 
272  fTime -= fDifference/GetSpeed(fTime);
273  }
274 
275  // Newton's method failed. You might want to increase iterations or
276  // tolerance or integration accuracy. However, in this application it
277  // is likely that the time values are oscillating, due to the limited
278  // numerical precision of 32-bit floats. It is safe to use the last
279  // computed time.
280  return fTime;
281 }
282 */
283 // moMultipleCurve2 ------------------------------------------------------------
284 /*
285 template <class Real>
286 moMultipleCurve2<Real>::moMultipleCurve2 (int iSegments, Real* afTime)
287  :
288  moCurve2<Real>(afTime[0],afTime[iSegments])
289 {
290  m_iSegments = iSegments;
291  m_afTime = afTime;
292  m_afLength = 0;
293  m_afAccumLength = 0;
294 }
295 
296 template <class Real>
297 moMultipleCurve2<Real>::~moMultipleCurve2 ()
298 {
299  delete[] m_afTime;
300  delete[] m_afLength;
301  delete[] m_afAccumLength;
302 }
303 
304 template <class Real>
305 int moMultipleCurve2<Real>::GetSegments () const
306 {
307  return m_iSegments;
308 }
309 
310 template <class Real>
311 const Real* moMultipleCurve2<Real>::GetTimes () const
312 {
313  return m_afTime;
314 }
315 
316 template <class Real>
317 void moMultipleCurve2<Real>::GetKeyInfo (Real fTime, int& riKey, Real& rfDt)
318  const
319 {
320  if (fTime <= m_afTime[0])
321  {
322  riKey = 0;
323  rfDt = (Real)0.0;
324  }
325  else if (fTime >= m_afTime[m_iSegments])
326  {
327  riKey = m_iSegments-1;
328  rfDt = m_afTime[m_iSegments] - m_afTime[m_iSegments-1];
329  }
330  else
331  {
332  for (int i = 0; i < m_iSegments; i++)
333  {
334  if (fTime < m_afTime[i+1])
335  {
336  riKey = i;
337  rfDt = fTime - m_afTime[i];
338  break;
339  }
340  }
341  }
342 }
343 
344 template <class Real>
345 Real moMultipleCurve2<Real>::GetSpeedWithData (Real fTime, void* pvData)
346 {
347  moMultipleCurve2* pvThis = *(moMultipleCurve2**) pvData;
348  int iKey = *(int*)((char*)pvData + sizeof(pvThis));
349  return pvThis->GetSpeedKey(iKey,fTime);
350 }
351 
352 template <class Real>
353 void moMultipleCurve2<Real>::InitializeLength () const
354 {
355  m_afLength = new Real[m_iSegments];
356  m_afAccumLength = new Real[m_iSegments];
357 
358  // arc lengths of the segments
359  int iKey;
360  for (iKey = 0; iKey < m_iSegments; iKey++)
361  {
362  m_afLength[iKey] = GetLengthKey(iKey,(Real)0.0,
363  m_afTime[iKey+1]-m_afTime[iKey]);
364  }
365 
366  // accumulative arc length
367  m_afAccumLength[0] = m_afLength[0];
368  for (iKey = 1; iKey < m_iSegments; iKey++)
369  {
370  m_afAccumLength[iKey] = m_afAccumLength[iKey-1] + m_afLength[iKey];
371  }
372 }
373 
374 template <class Real>
375 Real moMultipleCurve2<Real>::GetLength (Real fT0, Real fT1) const
376 {
377  //assert(m_fTMin <= fT0 && fT0 <= m_fTMax);
378  //assert(m_fTMin <= fT1 && fT1 <= m_fTMax);
379  //assert(fT0 <= fT1);
380 
381  if (!m_afLength)
382  {
383  InitializeLength();
384  }
385 
386  int iKey0, iKey1;
387  Real fDt0, fDt1;
388  GetKeyInfo(fT0,iKey0,fDt0);
389  GetKeyInfo(fT1,iKey1,fDt1);
390 
391  Real fLength;
392  if (iKey0 < iKey1)
393  {
394  // accumulate full-segment lengths
395  fLength = (Real)0.0;
396  for (int i = iKey0+1; i < iKey1; i++)
397  {
398  fLength += m_afLength[i];
399  }
400 
401  // add on partial first segment
402  fLength += GetLengthKey(iKey0,fDt0,m_afTime[iKey0+1]-m_afTime[iKey0]);
403 
404  // add on partial last segment
405  fLength += GetLengthKey(iKey1,(Real)0.0,fDt1);
406  }
407  else
408  {
409  fLength = GetLengthKey(iKey0,fDt0,fDt1);
410  }
411 
412  return fLength;
413 }
414 
415 template <class Real>
416 Real moMultipleCurve2<Real>::GetTime (Real fLength, int iIterations,
417  Real fTolerance) const
418 {
419  if (!m_afLength)
420  {
421  InitializeLength();
422  }
423 
424  if (fLength <= (Real)0.0)
425  {
426  return m_fTMin;
427  }
428 
429  if (fLength >= m_afAccumLength[m_iSegments-1])
430  {
431  return m_fTMax;
432  }
433 
434  int iKey;
435  for (iKey = 0; iKey < m_iSegments; iKey++)
436  {
437  if (fLength < m_afAccumLength[iKey])
438  {
439  break;
440  }
441  }
442  if (iKey >= m_iSegments)
443  {
444  return m_afTime[m_iSegments];
445  }
446 
447  // try Newton's method first for rapid convergence
448  Real fL0, fL1;
449  if (iKey == 0)
450  {
451  fL0 = fLength;
452  fL1 = m_afAccumLength[0];
453  }
454  else
455  {
456  fL0 = fLength - m_afAccumLength[iKey-1];
457  fL1 = m_afAccumLength[iKey] - m_afAccumLength[iKey-1];
458  }
459 
460  // use Newton's method to invert the arc length integral
461  Real fDt1 = m_afTime[iKey+1] - m_afTime[iKey];
462  Real fDt0 = fDt1*fL0/fL1;
463  for (int i = 0; i < iIterations; i++)
464  {
465  Real fDifference = GetLengthKey(iKey,(Real)0.0,fDt0) - fL0;
466  if (moMath<Real>::FAbs(fDifference) <= fTolerance)
467  {
468  return m_afTime[iKey] + fDt0;
469  }
470 
471  fDt0 -= fDifference/GetSpeedKey(iKey,fDt0);
472  }
473 
474  // Newton's method failed. You might want to increase iterations or
475  // tolerance or integration accuracy. However, in this application it
476  // is likely that the time values are oscillating, due to the limited
477  // numerical precision of 32-bit floats. It is safe to use the last
478  // computed time.
479  return m_afTime[iKey] + fDt0;
480 }
481 
482 template <class Real>
483 Real moMultipleCurve2<Real>::GetVariation (Real fT0, Real fT1,
484  const moVector2<Real>* pkP0, const moVector2<Real>* pkP1) const
485 {
486  //assert(m_fTMin <= fT0 && fT0 <= m_fTMax);
487  //assert(m_fTMin <= fT1 && fT1 <= m_fTMax);
488  //assert(fT0 <= fT1);
489 
490  // construct line segment, A + (t-t0)*B
491  moVector2<Real> kP0, kP1;
492  if (!pkP0)
493  {
494  kP0 = GetPosition(fT0);
495  pkP0 = &kP0;
496  }
497  if (!pkP1)
498  {
499  kP1 = GetPosition(fT1);
500  pkP1 = &kP1;
501  }
502  Real fInvDT = ((Real)1.0)/(fT1 - fT0);
503  moVector2<Real> kA, kB = fInvDT*(*pkP1 - *pkP0);
504 
505  int iKey0, iKey1;
506  Real fDt0, fDt1;
507  GetKeyInfo(fT0,iKey0,fDt0);
508  GetKeyInfo(fT1,iKey1,fDt1);
509 
510  Real fVariation;
511  if (iKey0 < iKey1)
512  {
513  // accumulate full-segment variations
514  fVariation = (Real)0.0;
515  for (int i = iKey0+1; i < iKey1; i++)
516  {
517  kA = *pkP0 + (m_afTime[i] - fT0)*kB;
518  fVariation += GetVariationKey(i,(Real)0.0,
519  m_afTime[i+1]-m_afTime[i],kA,kB);
520  }
521 
522  // add on partial first segment
523  kA = *pkP0 + (m_afTime[iKey0] - fT0)*kB;
524  fVariation += GetVariationKey(iKey0,fDt0,
525  m_afTime[iKey0+1]-m_afTime[iKey0],kA,kB);
526 
527  // add on partial last segment
528  kA = *pkP0 + (m_afTime[iKey1] - fT0)*kB;
529  fVariation += GetVariationKey(iKey1,(Real)0.0,fDt1,kA,kB);
530  }
531  else
532  {
533  kA = *pkP0 + (m_afTime[iKey0] - fT0)*kB;
534  fVariation = GetVariationKey(iKey0,fDt0,fDt1,kA,kB);
535  }
536 
537  return fVariation;
538 }
539 */
540 // moCurve3 class ------------------------------------------------------------
541 /*
542 template <class Real>
543 Real moCurve3<Real>::GetMinTime () const
544 {
545  return m_fTMin;
546 }
547 
548 template <class Real>
549 Real moCurve3<Real>::GetMaxTime () const
550 {
551  return m_fTMax;
552 }
553 
554 template <class Real>
555 void moCurve3<Real>::SetTimeInterval (Real fTMin, Real fTMax)
556 {
557  //assert(fTMin < fTMax);
558  m_fTMin = fTMin;
559  m_fTMax = fTMax;
560 }
561 
562 template <class Real>
563 Real moCurve3<Real>::GetSpeed (Real fTime) const
564 {
565  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
566  Real fSpeed = kVelocity.Length();
567  return fSpeed;
568 }
569 
570 template <class Real>
571 Real moCurve3<Real>::GetTotalLength () const
572 {
573  return GetLength(m_fTMin,m_fTMax);
574 }
575 
576 template <class Real>
577 moVector3<Real> moCurve3<Real>::GetTangent (Real fTime) const
578 {
579  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
580  kVelocity.Normalize();
581  return kVelocity;
582 }
583 
584 template <class Real>
585 moVector3<Real> moCurve3<Real>::GetNormal (Real fTime) const
586 {
587  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
588  moVector3<Real> kAcceleration = GetSecondDerivative(fTime);
589  Real fVDotV = kVelocity.Dot(kVelocity);
590  Real fVDotA = kVelocity.Dot(kAcceleration);
591  moVector3<Real> kNormal = fVDotV*kAcceleration - fVDotA*kVelocity;
592  kNormal.Normalize();
593  return kNormal;
594 }
595 */
596 /*
597 template <class Real>
598 moVector3<Real> moCurve3<Real>::GetBinormal (Real fTime) const
599 {
600  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
601  moVector3<Real> kAcceleration = GetSecondDerivative(fTime);
602  Real fVDotV = kVelocity.Dot(kVelocity);
603  Real fVDotA = kVelocity.Dot(kAcceleration);
604  moVector3<Real> kNormal = fVDotV*kAcceleration - fVDotA*kVelocity;
605  kNormal.Normalize();
606  kVelocity.Normalize();
607  moVector3<Real> kBinormal = kVelocity.Cross(kNormal);
608  return kBinormal;
609 }
610 
611 template <class Real>
612 void moCurve3<Real>::GetFrame (Real fTime, moVector3<Real>& rkPosition,
613  moVector3<Real>& rkTangent, moVector3<Real>& rkNormal,
614  moVector3<Real>& rkBinormal) const
615 {
616  rkPosition = GetPosition(fTime);
617  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
618  moVector3<Real> kAcceleration = GetSecondDerivative(fTime);
619  Real fVDotV = kVelocity.Dot(kVelocity);
620  Real fVDotA = kVelocity.Dot(kAcceleration);
621  rkNormal = fVDotV*kAcceleration - fVDotA*kVelocity;
622  rkNormal.Normalize();
623  rkTangent = kVelocity;
624  rkTangent.Normalize();
625  rkBinormal = rkTangent.Cross(rkNormal);
626 }
627 
628 template <class Real>
629 Real moCurve3<Real>::GetCurvature (Real fTime) const
630 {
631  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
632  Real fSpeedSqr = kVelocity.SquaredLength();
633 
634  if (fSpeedSqr >= moMath<Real>::ZERO_TOLERANCE)
635  {
636  moVector3<Real> kAcceleration = GetSecondDerivative(fTime);
637  moVector3<Real> kCross = kVelocity.Cross(kAcceleration);
638  Real fNumer = kCross.Length();
639  Real fDenom = moMath<Real>::Pow(fSpeedSqr,(Real)1.5);
640  return fNumer/fDenom;
641  }
642  else
643  {
644  // curvature is indeterminate, just return 0
645  return (Real)0.0;
646  }
647 }
648 
649 template <class Real>
650 Real moCurve3<Real>::GetTorsion (Real fTime) const
651 {
652  moVector3<Real> kVelocity = GetFirstDerivative(fTime);
653  moVector3<Real> kAcceleration = GetSecondDerivative(fTime);
654  moVector3<Real> kCross = kVelocity.Cross(kAcceleration);
655  Real fDenom = kCross.SquaredLength();
656 
657  if (fDenom >= moMath<Real>::ZERO_TOLERANCE)
658  {
659  moVector3<Real> kJerk = GetThirdDerivative(fTime);
660  Real fNumer = kCross.Dot(kJerk);
661  return fNumer/fDenom;
662  }
663  else
664  {
665  // torsion is indeterminate, just return 0
666  return (Real)0.0;
667  }
668 }
669 
670 template <class Real>
671 void moCurve3<Real>::SubdivideByTime (int iNumPoints,
672  moVector3<Real>*& rakPoint) const
673 {
674  //assert( iNumPoints >= 2 );
675  rakPoint = new moVector3<Real>[iNumPoints];
676 
677  Real fDelta = (m_fTMax - m_fTMin)/(iNumPoints-1);
678 
679  for (int i = 0; i < iNumPoints; i++)
680  {
681  Real fTime = m_fTMin + fDelta*i;
682  rakPoint[i] = GetPosition(fTime);
683  }
684 }
685 
686 template <class Real>
687 void moCurve3<Real>::SubdivideByLength (int iNumPoints,
688  moVector3<Real>*& rakPoint) const
689 {
690  //assert(iNumPoints >= 2);
691  rakPoint = new moVector3<Real>[iNumPoints];
692 
693  Real fDelta = GetTotalLength()/(iNumPoints-1);
694 
695  for (int i = 0; i < iNumPoints; i++)
696  {
697  Real fLength = fDelta*i;
698  Real fTime = GetTime(fLength);
699  rakPoint[i] = GetPosition(fTime);
700  }
701 }
702 
703 template <class Real>
704 void moCurve3<Real>::SubdivideByVariation (Real fT0, const moVector3<Real>& rkP0,
705  Real fT1, const moVector3<Real>& rkP1, Real fMinVariation, int iLevel,
706  int& riNumPoints, PointList*& rpkList) const
707 {
708  if (iLevel > 0 && GetVariation(fT0,fT1,&rkP0,&rkP1) > fMinVariation)
709  {
710  // too much variation, subdivide interval
711  iLevel--;
712  Real fTMid = ((Real)0.5)*(fT0+fT1);
713  moVector3<Real> kPMid = GetPosition(fTMid);
714 
715  SubdivideByVariation(fT0,rkP0,fTMid,kPMid,fMinVariation,iLevel,
716  riNumPoints,rpkList);
717 
718  SubdivideByVariation(fTMid,kPMid,fT1,rkP1,fMinVariation,iLevel,
719  riNumPoints,rpkList);
720  }
721  else
722  {
723  // add right end point, left end point was added by neighbor
724  rpkList = new PointList(rkP1,rpkList);
725  riNumPoints++;
726  }
727 }
728 
729 template <class Real>
730 void moCurve3<Real>::SubdivideByVariation (Real fMinVariation, int iMaxLevel,
731  int& riNumPoints, moVector3<Real>*& rakPoint) const
732 {
733  // compute end points of curve
734  moVector3<Real> kPMin = GetPosition(m_fTMin);
735  moVector3<Real> kPMax = GetPosition(m_fTMax);
736 
737  // add left end point to list
738  PointList* pkList = new PointList(kPMin,0);
739  riNumPoints = 1;
740 
741  // binary subdivision, leaf nodes add right end point of subinterval
742  SubdivideByVariation(m_fTMin,kPMin,m_fTMax,kPMax,fMinVariation,
743  iMaxLevel,riNumPoints,pkList->m_kNext);
744 
745  // repackage points in an array
746  //assert(riNumPoints >= 2);
747  rakPoint = new moVector3<Real>[riNumPoints];
748  for (int i = 0; i < riNumPoints; i++)
749  {
750  //assert(pkList);
751  rakPoint[i] = pkList->m_kPoint;
752 
753  PointList* pkSave = pkList;
754  pkList = pkList->m_kNext;
755  delete pkSave;
756  }
757  //assert(pkList == 0);
758 }
759 */
760 // moSingleCurve3 ------------------------------------------------------------
761 /*
762 template <class Real>
763 moSingleCurve3<Real>::moSingleCurve3 (Real fTMin, Real fTMax)
764  :
765  moCurve3<Real>(fTMin,fTMax)
766 {
767 }
768 
769 template <class Real>
770 Real moSingleCurve3<Real>::GetSpeedWithData (Real fTime, void* pvData)
771 {
772  return ((moCurve3<Real>*)pvData)->GetSpeed(fTime);
773 }
774 */
775 /*
776 template <class Real>
777 Real moSingleCurve3<Real>::GetLength (Real fT0, Real fT1) const
778 {
779  //assert(m_fTMin <= fT0 && fT0 <= m_fTMax);
780  //assert(m_fTMin <= fT1 && fT1 <= m_fTMax);
781  //assert(fT0 <= fT1);
782 
783  return moIntegrate1<Real>::RombergIntegral(8,fT0,fT1,GetSpeedWithData,
784  (void*)this);
785 }
786 
787 template <class Real>
788 Real moSingleCurve3<Real>::GetTime (Real fLength, int iIterations,
789  Real fTolerance) const
790 {
791  if (fLength <= (Real)0.0)
792  {
793  return m_fTMin;
794  }
795 
796  if (fLength >= GetTotalLength())
797  {
798  return m_fTMax;
799  }
800 
801  // initial guess for Newton's method
802  Real fRatio = fLength/GetTotalLength();
803  Real fOmRatio = (Real)1.0 - fRatio;
804  Real fTime = fOmRatio*m_fTMin + fRatio*m_fTMax;
805 
806  for (int i = 0; i < iIterations; i++)
807  {
808  Real fDifference = GetLength(m_fTMin,fTime) - fLength;
809  if (moMath<Real>::FAbs(fDifference) < fTolerance)
810  {
811  return fTime;
812  }
813 
814  fTime -= fDifference/GetSpeed(fTime);
815  }
816 
817  // Newton's method failed. You might want to increase iterations or
818  // tolerance or integration accuracy. However, in this application it
819  // is likely that the time values are oscillating, due to the limited
820  // numerical precision of 32-bit floats. It is safe to use the last
821  // computed time.
822  return fTime;
823 }
824 */
825 // moMultipleCurve3 ------------------------------------------------------------
826 /*
827 template <class Real>
828 moMultipleCurve3<Real>::moMultipleCurve3 (int iSegments, Real* afTime)
829  :
830  moCurve3<Real>(afTime[0],afTime[iSegments])
831 {
832  m_iSegments = iSegments;
833  m_afTime = afTime;
834  m_afLength = 0;
835  m_afAccumLength = 0;
836 }
837 
838 template <class Real>
839 moMultipleCurve3<Real>::~moMultipleCurve3 ()
840 {
841  delete[] m_afTime;
842  delete[] m_afLength;
843  delete[] m_afAccumLength;
844 }
845 */
846 /*
847 template <class Real>
848 int moMultipleCurve3<Real>::GetSegments () const
849 {
850  return m_iSegments;
851 }
852 
853 template <class Real>
854 const Real* moMultipleCurve3<Real>::GetTimes () const
855 {
856  return m_afTime;
857 }*/
858 /*
859 template <class Real>
860 void moMultipleCurve3<Real>::GetKeyInfo (Real fTime, int& riKey, Real& rfDt)
861  const
862 {
863  if (fTime <= m_afTime[0])
864  {
865  riKey = 0;
866  rfDt = (Real)0.0;
867  }
868  else if (fTime >= m_afTime[m_iSegments])
869  {
870  riKey = m_iSegments-1;
871  rfDt = m_afTime[m_iSegments] - m_afTime[m_iSegments-1];
872  }
873  else
874  {
875  for (int i = 0; i < m_iSegments; i++)
876  {
877  if (fTime < m_afTime[i+1])
878  {
879  riKey = i;
880  rfDt = fTime - m_afTime[i];
881  break;
882  }
883  }
884  }
885 }
886 */
887 /*
888 template <class Real>
889 Real moMultipleCurve3<Real>::GetSpeedWithData (Real fTime, void* pvData)
890 {
891  moMultipleCurve3* pvThis = *(moMultipleCurve3**) pvData;
892  int iKey = *(int*)((char*)pvData + sizeof(pvThis));
893  return pvThis->GetSpeedKey(iKey,fTime);
894 }
895 */
896 /*
897 template <class Real>
898 void moMultipleCurve3<Real>::InitializeLength () const
899 {
900  m_afLength = new Real[m_iSegments];
901  m_afAccumLength = new Real[m_iSegments];
902 
903  // arc lengths of the segments
904  int iKey;
905  for (iKey = 0; iKey < m_iSegments; iKey++)
906  {
907  m_afLength[iKey] = GetLengthKey(iKey,(Real)0.0,
908  m_afTime[iKey+1]-m_afTime[iKey]);
909  }
910 
911  // accumulative arc length
912  m_afAccumLength[0] = m_afLength[0];
913  for (iKey = 1; iKey < m_iSegments; iKey++)
914  {
915  m_afAccumLength[iKey] = m_afAccumLength[iKey-1] + m_afLength[iKey];
916  }
917 }
918 */
919 /*
920 template <class Real>
921 Real moMultipleCurve3<Real>::GetLength (Real fT0, Real fT1) const
922 {
923  //assert(m_fTMin <= fT0 && fT0 <= m_fTMax);
924  //assert(m_fTMin <= fT1 && fT1 <= m_fTMax);
925  //assert(fT0 <= fT1);
926 
927  if (!m_afLength)
928  {
929  InitializeLength();
930  }
931 
932  int iKey0, iKey1;
933  Real fDt0, fDt1;
934  GetKeyInfo(fT0,iKey0,fDt0);
935  GetKeyInfo(fT1,iKey1,fDt1);
936 
937  Real fLength;
938  if (iKey0 < iKey1)
939  {
940  // accumulate full-segment lengths
941  fLength = (Real)0.0;
942  for (int i = iKey0+1; i < iKey1; i++)
943  fLength += m_afLength[i];
944 
945  // add on partial first segment
946  fLength += GetLengthKey(iKey0,fDt0,m_afTime[iKey0+1]-m_afTime[iKey0]);
947 
948  // add on partial last segment
949  fLength += GetLengthKey(iKey1,(Real)0.0,fDt1);
950  }
951  else
952  {
953  fLength = GetLengthKey(iKey0,fDt0,fDt1);
954  }
955 
956  return fLength;
957 }
958 */
959 /*
960 template <class Real>
961 Real moMultipleCurve3<Real>::GetTime (Real fLength, int iIterations,
962  Real fTolerance) const
963 {
964  if (!m_afLength)
965  {
966  InitializeLength();
967  }
968 
969  if (fLength <= (Real)0.0)
970  {
971  return m_fTMin;
972  }
973 
974  if (fLength >= m_afAccumLength[m_iSegments-1])
975  {
976  return m_fTMax;
977  }
978 
979  int iKey;
980  for (iKey = 0; iKey < m_iSegments; iKey++)
981  {
982  if (fLength < m_afAccumLength[iKey])
983  {
984  break;
985  }
986  }
987  if (iKey >= m_iSegments)
988  {
989  return m_afTime[m_iSegments];
990  }
991 
992  // try Newton's method first for rapid convergence
993  Real fL0, fL1;
994  if (iKey == 0)
995  {
996  fL0 = fLength;
997  fL1 = m_afAccumLength[0];
998  }
999  else
1000  {
1001  fL0 = fLength - m_afAccumLength[iKey-1];
1002  fL1 = m_afAccumLength[iKey] - m_afAccumLength[iKey-1];
1003  }
1004 
1005  // use Newton's method to invert the arc length integral
1006  Real fDt1 = m_afTime[iKey+1] - m_afTime[iKey];
1007  Real fDt0 = fDt1*fL0/fL1;
1008  for (int i = 0; i < iIterations; i++)
1009  {
1010  Real fDifference = GetLengthKey(iKey,(Real)0.0,fDt0) - fL0;
1011  if (moMath<Real>::FAbs(fDifference) <= fTolerance)
1012  {
1013  return m_afTime[iKey] + fDt0;
1014  }
1015 
1016  fDt0 -= fDifference/GetSpeedKey(iKey,fDt0);
1017  }
1018 
1019  // Newton's method failed. You might want to increase iterations or
1020  // tolerance or integration accuracy. However, in this application it
1021  // is likely that the time values are oscillating, due to the limited
1022  // numerical precision of 32-bit floats. It is safe to use the last
1023  // computed time.
1024  return m_afTime[iKey] + fDt0;
1025 }
1026 */
1027 /*
1028 template <class Real>
1029 Real moMultipleCurve3<Real>::GetVariation (Real fT0, Real fT1,
1030  const moVector3<Real>* pkP0, const moVector3<Real>* pkP1) const
1031 {
1032  //assert(m_fTMin <= fT0 && fT0 <= m_fTMax);
1033  //assert(m_fTMin <= fT1 && fT1 <= m_fTMax);
1034  //assert(fT0 <= fT1);
1035 
1036  // construct line segment, A + (t-t0)*B
1037  moVector3<Real> kP0, kP1;
1038  if (!pkP0)
1039  {
1040  kP0 = GetPosition(fT0);
1041  pkP0 = &kP0;
1042  }
1043  if (!pkP1)
1044  {
1045  kP1 = GetPosition(fT1);
1046  pkP1 = &kP1;
1047  }
1048  Real fInvDT = ((Real)1.0)/(fT1 - fT0);
1049  moVector3<Real> kA, kB = fInvDT*(*pkP1 - *pkP0);
1050 
1051  int iKey0, iKey1;
1052  Real fDt0, fDt1;
1053  GetKeyInfo(fT0,iKey0,fDt0);
1054  GetKeyInfo(fT1,iKey1,fDt1);
1055 
1056  Real fVariation;
1057  if (iKey0 < iKey1)
1058  {
1059  // accumulate full-segment variations
1060  fVariation = (Real)0.0;
1061  for (int i = iKey0+1; i < iKey1; i++)
1062  {
1063  kA = *pkP0 + (m_afTime[i] - fT0)*kB;
1064  fVariation += GetVariationKey(i,(Real)0.0,
1065  m_afTime[i+1]-m_afTime[i],kA,kB);
1066  }
1067 
1068  // add on partial first segment
1069  kA = *pkP0 + (m_afTime[iKey0] - fT0)*kB;
1070  fVariation += GetVariationKey(iKey0,fDt0,
1071  m_afTime[iKey0+1]-m_afTime[iKey0],kA,kB);
1072 
1073  // add on partial last segment
1074  kA = *pkP0 + (m_afTime[iKey1] - fT0)*kB;
1075  fVariation += GetVariationKey(iKey1,0.0f,fDt1,kA,kB);
1076  }
1077  else
1078  {
1079  kA = *pkP0 + (m_afTime[iKey0] - fT0)*kB;
1080  fVariation = GetVariationKey(iKey0,fDt0,fDt1,kA,kB);
1081  }
1082 
1083  return fVariation;
1084 }
1085 */
1086