frame.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:19k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // frame.cpp
  2. // 
  3. // Reference frame base class.
  4. //
  5. // Copyright (C) 2003-2008, Chris Laurel <claurel@shatters.net>
  6. //
  7. // This program is free software; you can redistribute it and/or
  8. // modify it under the terms of the GNU General Public License
  9. // as published by the Free Software Foundation; either version 2
  10. // of the License, or (at your option) any later version.
  11. #include <cassert>
  12. #include <celengine/frame.h>
  13. using namespace std;
  14. // Velocity for two-vector frames is computed by differentiation; units
  15. // are Julian days.
  16. static const double ANGULAR_VELOCITY_DIFF_DELTA = 1.0 / 1440.0;
  17. /*** ReferenceFrame ***/
  18. ReferenceFrame::ReferenceFrame(Selection center) :
  19.     centerObject(center),
  20.     refCount(0)
  21. {
  22. }
  23. int
  24. ReferenceFrame::addRef() const
  25. {
  26.     return ++refCount;
  27. }
  28. int
  29. ReferenceFrame::release() const
  30. {
  31.     --refCount;
  32.     assert(refCount >= 0);
  33.     if (refCount <= 0)
  34.         delete this;
  35.     return refCount;
  36. }
  37. // High-precision rotation using 64.64 fixed point path. Rotate uc by
  38. // the rotation specified by unit quaternion q.
  39. static UniversalCoord rotate(const UniversalCoord& uc, const Quatd& q)
  40. {
  41.     Mat3d r = q.toMatrix3();
  42.     UniversalCoord uc1;
  43.     
  44.     uc1.x = uc.x * BigFix(r[0].x) + uc.y * BigFix(r[1].x) + uc.z * BigFix(r[2].x);
  45.     uc1.y = uc.x * BigFix(r[0].y) + uc.y * BigFix(r[1].y) + uc.z * BigFix(r[2].y);
  46.     uc1.z = uc.x * BigFix(r[0].z) + uc.y * BigFix(r[1].z) + uc.z * BigFix(r[2].z);
  47.     
  48.     return uc1;
  49. }
  50. /*! Convert from universal coordinates to frame coordinates. This method
  51.  *  uses 64.64 fixed point arithmetic in conversion, and is thus /much/ slower
  52.  *  than convertFromAstrocentric(), which works with double precision
  53.  *  floating points values. For cases when the bodies are all in the same
  54.  *  solar system, convertFromAstrocentric() should be used.
  55.  */
  56. UniversalCoord
  57. ReferenceFrame::convertFromUniversal(const UniversalCoord& uc, double tjd) const
  58. {
  59.     UniversalCoord uc1 = uc.difference(centerObject.getPosition(tjd));
  60.     return rotate(uc1, conjugate(getOrientation(tjd)));
  61. }
  62. Quatd
  63. ReferenceFrame::convertFromUniversal(const Quatd& q, double tjd) const
  64. {
  65.     return q * conjugate(getOrientation(tjd));
  66. }
  67. /*! Convert from local coordinates to universal coordinates. This method
  68.  *  uses 64.64 fixed point arithmetic in conversion, and is thus /much/ slower
  69.  *  than convertFromAstrocentric(), which works with double precision
  70.  *  floating points values. For cases when the bodies are all in the same
  71.  *  solar system, convertFromAstrocentric() should be used.
  72.  *
  73.  *  To get the position of a solar system object in universal coordinates,
  74.  *  it usually suffices to get the astrocentric position and then add that
  75.  *  to the position of the star in universal coordinates. This avoids any
  76.  *  expensive high-precision multiplication.
  77.  */
  78. UniversalCoord
  79. ReferenceFrame::convertToUniversal(const UniversalCoord& uc, double tjd) const
  80. {
  81.     return centerObject.getPosition(tjd) + rotate(uc, getOrientation(tjd));
  82. }
  83. Quatd
  84. ReferenceFrame::convertToUniversal(const Quatd& q, double tjd) const
  85. {
  86.     return q * getOrientation(tjd);
  87. }
  88. Point3d
  89. ReferenceFrame::convertFromAstrocentric(const Point3d& p, double tjd) const
  90. {
  91.     if (centerObject.getType() == Selection::Type_Body)
  92.     {
  93.         Point3d center = centerObject.body()->getAstrocentricPosition(tjd);
  94.         return Point3d(0.0, 0.0, 0.0) + (p - center) * conjugate(getOrientation(tjd)).toMatrix3();
  95.     }
  96.     else if (centerObject.getType() == Selection::Type_Star)
  97.     {
  98.         return p * conjugate(getOrientation(tjd)).toMatrix3();
  99.     }
  100.     else
  101.     {
  102.         // TODO:
  103.         // bad if the center object is a galaxy
  104.         // what about locations?
  105.         return Point3d(0.0, 0.0, 0.0);
  106.     }
  107. }
  108. Point3d
  109. ReferenceFrame::convertToAstrocentric(const Point3d& p, double tjd) const
  110. {
  111.     if (centerObject.getType() == Selection::Type_Body)
  112.     {
  113.         Point3d center = centerObject.body()->getAstrocentricPosition(tjd);
  114.         return center + p * getOrientation(tjd).toMatrix3();
  115.     }
  116.     else if (centerObject.getType() == Selection::Type_Star)
  117.     {
  118.         return p * getOrientation(tjd).toMatrix3();
  119.     }
  120.     else
  121.     {
  122.         // TODO:
  123.         // bad if the center object is a galaxy
  124.         // what about locations?
  125.         return Point3d(0.0, 0.0, 0.0);
  126.     }    
  127. }
  128. /*! Return the object that is the defined origin of the reference frame.
  129.  */
  130. Selection
  131. ReferenceFrame::getCenter() const
  132. {
  133.     return centerObject;
  134. }
  135. Vec3d
  136. ReferenceFrame::getAngularVelocity(double tjd) const
  137. {
  138. Quatd q0 = getOrientation(tjd);
  139. Quatd q1 = getOrientation(tjd + ANGULAR_VELOCITY_DIFF_DELTA);
  140. Quatd dq = ~q0 * q1;
  141. if (fabs(dq.w) > 0.99999999)
  142. return Vec3d(0.0, 0.0, 0.0);
  143. Vec3d v(dq.x, dq.y, dq.z);
  144. v.normalize();
  145. return v * (2.0 * acos(dq.w) / ANGULAR_VELOCITY_DIFF_DELTA);
  146. }
  147. unsigned int
  148. ReferenceFrame::nestingDepth(unsigned int maxDepth, FrameType frameType) const
  149. {
  150.     return this->nestingDepth(0, maxDepth, frameType);
  151. }
  152. static unsigned int
  153. getFrameDepth(const Selection& sel, unsigned int depth, unsigned int maxDepth,
  154.               ReferenceFrame::FrameType frameType)
  155. {
  156.     if (depth > maxDepth)
  157.         return depth;
  158.     Body* body = sel.body();
  159.     if (sel.location() != NULL)
  160.         body = sel.location()->getParentBody();
  161.     if (body == NULL)
  162.     {
  163.         return depth;
  164.     }
  165.     unsigned int orbitFrameDepth = depth;
  166.     unsigned int bodyFrameDepth = depth;
  167.     // TODO: need to check /all/ orbit frames of body
  168.     if (body->getOrbitFrame(0.0) != NULL && frameType == ReferenceFrame::PositionFrame)
  169.     {
  170.         orbitFrameDepth = body->getOrbitFrame(0.0)->nestingDepth(depth + 1, maxDepth, frameType);
  171.         if (orbitFrameDepth > maxDepth)
  172.             return orbitFrameDepth;
  173.     }
  174.         
  175.     if (body->getBodyFrame(0.0) != NULL && frameType == ReferenceFrame::OrientationFrame)
  176.     {
  177.         bodyFrameDepth = body->getBodyFrame(0.0)->nestingDepth(depth + 1, maxDepth, frameType);
  178.     }
  179.     return max(orbitFrameDepth, bodyFrameDepth);
  180. }
  181. /*** J2000EclipticFrame ***/
  182. J2000EclipticFrame::J2000EclipticFrame(Selection center) :
  183.     ReferenceFrame(center)
  184. {
  185. }
  186. bool
  187. J2000EclipticFrame::isInertial() const
  188. {
  189. return true;
  190. }
  191. unsigned int
  192. J2000EclipticFrame::nestingDepth(unsigned int depth,
  193.                                  unsigned int maxDepth,
  194.                                  FrameType) const
  195. {
  196.     return getFrameDepth(getCenter(), depth, maxDepth, PositionFrame);
  197. }
  198. /*** J2000EquatorFrame ***/
  199. J2000EquatorFrame::J2000EquatorFrame(Selection center) :
  200.     ReferenceFrame(center)
  201. {
  202. }
  203. Quatd
  204. J2000EquatorFrame::getOrientation(double /* tjd */) const
  205. {
  206.     return Quatd::xrotation(astro::J2000Obliquity);
  207. }
  208. bool
  209. J2000EquatorFrame::isInertial() const
  210. {
  211. return true;
  212. }
  213. unsigned int
  214. J2000EquatorFrame::nestingDepth(unsigned int depth,
  215.                                 unsigned int maxDepth,
  216.                                 FrameType) const
  217. {
  218.     return getFrameDepth(getCenter(), depth, maxDepth, PositionFrame);
  219. }
  220. /*** BodyFixedFrame ***/
  221. BodyFixedFrame::BodyFixedFrame(Selection center, Selection obj) :
  222.     ReferenceFrame(center),
  223.     fixObject(obj)
  224. {
  225. }
  226. Quatd
  227. BodyFixedFrame::getOrientation(double tjd) const
  228. {
  229.     // Rotation of 180 degrees about the y axis is required
  230.     // TODO: this rotation could go in getEclipticalToBodyFixed()
  231.     Quatd yrot180 = Quatd(0.0, 0.0, 1.0, 0.0);
  232.     switch (fixObject.getType())
  233.     {
  234.     case Selection::Type_Body:
  235.         return yrot180 * fixObject.body()->getEclipticToBodyFixed(tjd);
  236.     case Selection::Type_Star:
  237.         return yrot180 * fixObject.star()->getRotationModel()->orientationAtTime(tjd);
  238.     default:
  239.         return yrot180;
  240.     }
  241. }
  242. Vec3d
  243. BodyFixedFrame::getAngularVelocity(double tjd) const
  244. {
  245. switch (fixObject.getType())
  246. {
  247. case Selection::Type_Body:
  248. return fixObject.body()->getAngularVelocity(tjd);
  249. case Selection::Type_Star:
  250. return fixObject.star()->getRotationModel()->angularVelocityAtTime(tjd);
  251. default:
  252. return Vec3d(0.0, 0.0, 0.0);
  253. }
  254. }
  255. bool
  256. BodyFixedFrame::isInertial() const
  257. {
  258. return false;
  259. }
  260. unsigned int
  261. BodyFixedFrame::nestingDepth(unsigned int depth,
  262.                              unsigned int maxDepth,
  263.                              FrameType) const
  264. {
  265.     unsigned int n = getFrameDepth(getCenter(), depth, maxDepth, PositionFrame);
  266.     if (n > maxDepth)
  267.     {
  268.         return n;
  269.     }
  270.     else
  271.     {
  272.         unsigned int m = getFrameDepth(fixObject, depth, maxDepth, OrientationFrame);
  273.         return max(m, n);
  274.     }
  275. }
  276. /*** BodyMeanEquatorFrame ***/
  277. BodyMeanEquatorFrame::BodyMeanEquatorFrame(Selection center,
  278.                                            Selection obj) :
  279.     ReferenceFrame(center),
  280.     equatorObject(obj),
  281.     freezeEpoch(astro::J2000),
  282.     isFrozen(false)
  283. {
  284. }
  285. BodyMeanEquatorFrame::BodyMeanEquatorFrame(Selection center,
  286.                                            Selection obj,
  287.                                            double freeze) :
  288.     ReferenceFrame(center),
  289.     equatorObject(obj),
  290.     freezeEpoch(freeze),
  291.     isFrozen(true)
  292. {
  293. }
  294. Quatd
  295. BodyMeanEquatorFrame::getOrientation(double tjd) const
  296. {
  297.     double t = isFrozen ? freezeEpoch : tjd;
  298.     switch (equatorObject.getType())
  299.     {
  300.     case Selection::Type_Body:
  301.         return equatorObject.body()->getEclipticToEquatorial(t);
  302.     case Selection::Type_Star:
  303.         return equatorObject.star()->getRotationModel()->equatorOrientationAtTime(t);
  304.     default:
  305.         return Quatd(1.0);
  306.     }
  307. }
  308. Vec3d
  309. BodyMeanEquatorFrame::getAngularVelocity(double tjd) const
  310. {
  311. if (isFrozen)
  312. {
  313. return Vec3d(0.0, 0.0, 0.0);
  314. }
  315. else
  316. {
  317.         if (equatorObject.body() != NULL)
  318.         {
  319.             return equatorObject.body()->getBodyFrame(tjd)->getAngularVelocity(tjd);
  320.         }
  321.         else
  322.         {
  323.             return Vec3d(0.0, 0.0, 0.0);
  324.         }
  325. }
  326. }
  327. bool
  328. BodyMeanEquatorFrame::isInertial() const
  329. {
  330. if (isFrozen)
  331. {
  332. return true;
  333. }
  334. else
  335. {
  336. // Although the mean equator of an object may vary slightly due to precession,
  337. // treat it as an inertial frame as long as the body frame of the object is
  338. // also inertial.
  339. if (equatorObject.body() != NULL)
  340. {
  341.             // TIMELINE-TODO: isInertial must take a time argument.
  342. return equatorObject.body()->getBodyFrame(0.0)->isInertial();
  343. }
  344.         else
  345.         {
  346.             return true;
  347.         }
  348. }
  349. }
  350. unsigned int
  351. BodyMeanEquatorFrame::nestingDepth(unsigned int depth,
  352.                                    unsigned int maxDepth,
  353.                                    FrameType) const
  354. {
  355.     // Test origin and equator object (typically the same) frames
  356.     unsigned int n =  getFrameDepth(getCenter(), depth, maxDepth, PositionFrame);
  357.     if (n > maxDepth)
  358.     {
  359.         return n;
  360.     }
  361.     else
  362.     {
  363.         unsigned int m = getFrameDepth(equatorObject, depth, maxDepth, OrientationFrame);
  364.         return max(m, n);
  365.     }
  366. }
  367. /*** CachingFrame ***/
  368. CachingFrame::CachingFrame(Selection _center) :
  369.     ReferenceFrame(_center),
  370.     lastTime(-1.0e50),
  371.     lastOrientation(1.0),
  372. lastAngularVelocity(0.0, 0.0, 0.0),
  373. orientationCacheValid(false),
  374. angularVelocityCacheValid(false)
  375. {
  376. }
  377. Quatd
  378. CachingFrame::getOrientation(double tjd) const
  379. {
  380. if (tjd != lastTime)
  381. {
  382. lastTime = tjd;
  383. lastOrientation = computeOrientation(tjd);
  384. orientationCacheValid = true;
  385. angularVelocityCacheValid = false;
  386. }
  387. else if (!orientationCacheValid)
  388. {
  389. lastOrientation = computeOrientation(tjd);
  390. orientationCacheValid = true;
  391. }
  392. return lastOrientation;
  393. }
  394. Vec3d CachingFrame::getAngularVelocity(double tjd) const
  395. {
  396. if (tjd != lastTime)
  397. {
  398. lastTime = tjd;
  399. lastAngularVelocity = computeAngularVelocity(tjd);
  400. orientationCacheValid = false;
  401. angularVelocityCacheValid = true;
  402. }
  403. else if (!angularVelocityCacheValid)
  404. {
  405. lastAngularVelocity = computeAngularVelocity(tjd);
  406. angularVelocityCacheValid = true;
  407. }
  408. return lastAngularVelocity;
  409. }
  410. /*! Calculate the angular velocity at the specified time (units are
  411.  *  radians / Julian day.) The default implementation just
  412.  *  differentiates the orientation.
  413.  */
  414. Vec3d CachingFrame::computeAngularVelocity(double tjd) const
  415. {
  416. Quatd q0 = getOrientation(tjd);
  417. // Call computeOrientation() instead of getOrientation() so that we
  418. // don't affect the cached value. 
  419. // TODO: check the valid ranges of the frame to make sure that
  420. // jd+dt is still in range.
  421. Quatd q1 = computeOrientation(tjd + ANGULAR_VELOCITY_DIFF_DELTA);
  422. Quatd dq = ~q0 * q1;
  423. if (fabs(dq.w) > 0.99999999)
  424. return Vec3d(0.0, 0.0, 0.0);
  425. Vec3d v(dq.x, dq.y, dq.z);
  426. v.normalize();
  427. return v * (2.0 * acos(dq.w) / ANGULAR_VELOCITY_DIFF_DELTA);
  428. }
  429. /*** TwoVectorFrame ***/
  430. // Minimum angle permitted between primary and secondary axes of
  431. // a two-vector frame.
  432. const double TwoVectorFrame::Tolerance = 1.0e-6;
  433. TwoVectorFrame::TwoVectorFrame(Selection center,
  434.                                const FrameVector& prim,
  435.                                int primAxis,
  436.                                const FrameVector& sec,
  437.                                int secAxis) :
  438.     CachingFrame(center),
  439.     primaryVector(prim),
  440.     primaryAxis(primAxis),
  441.     secondaryVector(sec),
  442.     secondaryAxis(secAxis)
  443. {
  444.     // Verify that primary and secondary axes are valid
  445.     assert(primaryAxis != 0 && secondaryAxis != 0);
  446.     assert(abs(primaryAxis) <= 3 && abs(secondaryAxis) <= 3);
  447.     // Verify that the primary and secondary axes aren't collinear
  448.     assert(abs(primaryAxis) != abs(secondaryAxis));
  449.     if ((abs(primaryAxis) != 1 && abs(secondaryAxis) != 1))
  450.     {
  451.         tertiaryAxis = 1;
  452.     }
  453.     else if (abs(primaryAxis) != 2 && abs(secondaryAxis) != 2)
  454.     {
  455.         tertiaryAxis = 2;
  456.     }
  457.     else
  458.     {
  459.         tertiaryAxis = 3;
  460.     }
  461. }
  462. Quatd
  463. TwoVectorFrame::computeOrientation(double tjd) const
  464. {
  465.     Vec3d v0 = primaryVector.direction(tjd);
  466.     Vec3d v1 = secondaryVector.direction(tjd);
  467.     // TODO: verify that v0 and v1 aren't zero length
  468.     v0.normalize();
  469.     v1.normalize();
  470.     if (primaryAxis < 0)
  471.         v0 = -v0;
  472.     if (secondaryAxis < 0)
  473.         v1 = -v1;
  474.     Vec3d v2 = v0 ^ v1;
  475.     // Check for degenerate case when the primary and secondary vectors
  476.     // are collinear. A well-chosen two vector frame should never have this
  477.     // problem.
  478.     double length = v2.length();
  479.     if (length < Tolerance)
  480.     {
  481.         // Just return identity . . .
  482.         return Quatd(1.0);
  483.     }
  484.     else
  485.     {
  486.         v2 = v2 / length;
  487.         // Determine whether the primary and secondary axes are in
  488.         // right hand order.
  489.         int rhAxis = abs(primaryAxis) + 1;
  490.         if (rhAxis > 3)
  491.             rhAxis = 1;
  492.         bool rhOrder = rhAxis == abs(secondaryAxis);
  493.         // Set the rotation matrix axes
  494.         Vec3d v[3];
  495.         v[abs(primaryAxis) - 1] = v0;
  496.         // Reverse the cross products if the axes are not in right
  497.         // hand order.
  498.         if (rhOrder)
  499.         {
  500.             v[abs(secondaryAxis) - 1] = v2 ^ v0;
  501.             v[abs(tertiaryAxis) - 1] = v2;
  502.         }
  503.         else
  504.         {
  505.             v[abs(secondaryAxis) - 1] = v0 ^ -v2;
  506.             v[abs(tertiaryAxis) - 1] = -v2;
  507.         }
  508.         // The axes are the rows of a rotation matrix. The getOrientation
  509.         // method must return the quaternion representation of the 
  510.         // orientation, so convert the rotation matrix to a quaternion now.
  511.         Quatd q = Quatd::matrixToQuaternion(Mat3d(v[0], v[1], v[2]));
  512.         // A rotation matrix will have a determinant of 1; if the matrix also
  513.         // includes a reflection, the determinant will be -1, indicating that
  514.         // there's a bug and there's a reversed cross-product or sign error
  515.         // somewhere.
  516.         // assert(Mat3d(v[0], v[1], v[2]).determinant() > 0);
  517.         return q;
  518.     }
  519. }
  520. bool
  521. TwoVectorFrame::isInertial() const
  522. {
  523. // Although it's possible to specify an inertial two-vector frame, we won't
  524. // bother trying to distinguish these cases: all two-vector frames will be
  525. // treated as non-inertial.
  526. return true;
  527. }
  528. unsigned int
  529. TwoVectorFrame::nestingDepth(unsigned int depth,
  530.                              unsigned int maxDepth,
  531.                              FrameType) const
  532. {
  533.     // Check nesting of the origin object as well as frames references by
  534.     // the primary and secondary axes.
  535.     unsigned int n = getFrameDepth(getCenter(), depth, maxDepth, PositionFrame);
  536.     if (n > maxDepth)
  537.         return n;
  538.     unsigned int m = primaryVector.nestingDepth(depth, maxDepth);
  539.     n = max(m, n);
  540.     if (n > maxDepth)
  541.         return n;
  542.     m = secondaryVector.nestingDepth(depth, maxDepth);
  543.     return max(m, n);
  544. }
  545. // Copy constructor
  546. FrameVector::FrameVector(const FrameVector& fv) :
  547.     vecType(fv.vecType),
  548.     observer(fv.observer),
  549.     target(fv.target),
  550.     vec(fv.vec),
  551.     frame(fv.frame)
  552. {
  553.     if (frame != NULL)
  554.         frame->addRef();
  555. }
  556. // Assignment operator (since we have a copy constructor)
  557. FrameVector&
  558. FrameVector::operator=(const FrameVector& fv)
  559. {
  560.     vecType = fv.vecType;
  561.     observer = fv.observer;
  562.     target = fv.target;
  563.     vec = fv.vec;
  564.     if (frame != NULL)
  565.         frame->release();
  566.     frame = fv.frame;
  567.     if (frame != NULL)
  568.         frame->addRef();
  569.     
  570.     return *this;
  571. }
  572. FrameVector::FrameVector(FrameVectorType t) :
  573.     vecType(t),
  574.     observer(),
  575.     target(),
  576.     vec(0.0, 0.0, 0.0),
  577.     frame(NULL)
  578. {
  579. }
  580. FrameVector::~FrameVector()
  581. {
  582.     if (frame != NULL)
  583.         frame->release();
  584. }
  585. FrameVector
  586. FrameVector::createRelativePositionVector(const Selection& _observer,
  587.                                           const Selection& _target)
  588. {
  589.     FrameVector fv(RelativePosition);
  590.     fv.observer = _observer;
  591.     fv.target = _target;
  592.     return fv;
  593. }
  594. FrameVector
  595. FrameVector::createRelativeVelocityVector(const Selection& _observer,
  596.                                           const Selection& _target)
  597. {
  598.     FrameVector fv(RelativeVelocity);
  599.     fv.observer = _observer;
  600.     fv.target = _target;
  601.     return fv;
  602. }
  603. FrameVector
  604. FrameVector::createConstantVector(const Vec3d& _vec,
  605.                                   const ReferenceFrame* _frame)
  606. {
  607.     FrameVector fv(ConstantVector);
  608.     fv.vec = _vec;
  609.     fv.frame = _frame;
  610.     if (fv.frame != NULL)
  611.         fv.frame->addRef();
  612.     return fv;
  613. }
  614. Vec3d
  615. FrameVector::direction(double tjd) const
  616. {
  617.     Vec3d v;
  618.     switch (vecType)
  619.     {
  620.     case RelativePosition:
  621.         v = target.getPosition(tjd) - observer.getPosition(tjd);
  622.         break;
  623.     case RelativeVelocity:
  624.         {
  625. Vec3d v0 = observer.getVelocity(tjd);
  626. Vec3d v1 = target.getVelocity(tjd);
  627.             v = v1 - v0;
  628.         }
  629.         break;
  630.     case ConstantVector:
  631.         if (frame == NULL)
  632.             v = vec;
  633.         else
  634.             v = vec * frame->getOrientation(tjd).toMatrix3();
  635.         break;
  636.     default:
  637.         // unhandled vector type
  638.         v = Vec3d(0.0, 0.0, 0.0);
  639.         break;
  640.     }
  641.     return v;
  642. }
  643. unsigned int
  644. FrameVector::nestingDepth(unsigned int depth,
  645.                           unsigned int maxDepth) const
  646. {
  647.     switch (vecType)
  648.     {
  649.     case RelativePosition:
  650.     case RelativeVelocity:
  651.         {
  652.             unsigned int n = getFrameDepth(observer, depth, maxDepth, ReferenceFrame::PositionFrame);
  653.             if (n > maxDepth)
  654.             {
  655.                 return n;
  656.             }
  657.             else
  658.             {
  659.                 unsigned int m = getFrameDepth(target, depth, maxDepth, ReferenceFrame::PositionFrame);
  660.                 return max(m, n);
  661.             }
  662.         }
  663.         break;
  664.     case ConstantVector:
  665.         if (depth > maxDepth)
  666.             return depth;
  667.         else
  668.             return frame->nestingDepth(depth + 1, maxDepth, ReferenceFrame::OrientationFrame);
  669.         break;
  670.     default:
  671.         return depth;
  672.     }
  673. }