// frame.h // // Copyright (C) 2003-2009, the Celestia Development Team // Original version by Chris Laurel // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. #ifndef _CELENGINE_FRAME_H_ #define _CELENGINE_FRAME_H_ #include #include #include #include #include "shared.h" /*! A ReferenceFrame object has a center and set of orthogonal axes. * * Subclasses of ReferenceFrame must override the getOrientation method * (which specifies the coordinate axes at a given time) and the * nestingDepth() method (which is used to check for recursive frames.) */ class ReferenceFrame { public: SHARED_TYPES(ReferenceFrame) ReferenceFrame(Selection center); virtual ~ReferenceFrame() {}; UniversalCoord convertFromUniversal(const UniversalCoord& uc, double tjd) const; UniversalCoord convertToUniversal(const UniversalCoord& uc, double tjd) const; Eigen::Quaterniond convertFromUniversal(const Eigen::Quaterniond& q, double tjd) const; Eigen::Quaterniond convertToUniversal(const Eigen::Quaterniond& q, double tjd) const; Eigen::Vector3d convertFromAstrocentric(const Eigen::Vector3d& p, double tjd) const; Eigen::Vector3d convertToAstrocentric(const Eigen::Vector3d& p, double tjd) const; Selection getCenter() const; virtual Eigen::Quaterniond getOrientation(double tjd) const = 0; virtual Eigen::Vector3d getAngularVelocity(double tdb) const; virtual bool isInertial() const = 0; enum FrameType { PositionFrame = 1, OrientationFrame = 2, }; unsigned int nestingDepth(unsigned int maxDepth, FrameType) const; virtual unsigned int nestingDepth(unsigned int depth, unsigned int maxDepth, FrameType frameType) const = 0; private: Selection centerObject; }; /*! Base class for complex frames where there may be some benefit * to caching the last calculated orientation. */ class CachingFrame : public ReferenceFrame { public: SHARED_TYPES(CachingFrame) CachingFrame(Selection _center); virtual ~CachingFrame() {}; Eigen::Quaterniond getOrientation(double tjd) const; Eigen::Vector3d getAngularVelocity(double tjd) const; virtual Eigen::Quaterniond computeOrientation(double tjd) const = 0; virtual Eigen::Vector3d computeAngularVelocity(double tjd) const; private: mutable double lastTime; mutable Eigen::Quaterniond lastOrientation; mutable Eigen::Vector3d lastAngularVelocity; mutable bool orientationCacheValid; mutable bool angularVelocityCacheValid; }; //! J2000.0 Earth ecliptic frame class J2000EclipticFrame : public ReferenceFrame { public: SHARED_TYPES(J2000EclipticFrame) J2000EclipticFrame(Selection center); virtual ~J2000EclipticFrame() {}; Eigen::Quaterniond getOrientation(double /* tjd */) const { return Eigen::Quaterniond::Identity(); } virtual bool isInertial() const; virtual unsigned int nestingDepth(unsigned int depth, unsigned int maxDepth, FrameType frameType) const; }; //! J2000.0 Earth Mean Equator class J2000EquatorFrame : public ReferenceFrame { public: SHARED_TYPES(J2000EquatorFrame) J2000EquatorFrame(Selection center); virtual ~J2000EquatorFrame() {}; Eigen::Quaterniond getOrientation(double tjd) const; virtual bool isInertial() const; virtual unsigned int nestingDepth(unsigned int depth, unsigned int maxDepth, FrameType frameType) const; }; /*! A BodyFixed frame is a coordinate system with the x-axis pointing * from the body center through the intersection of the prime meridian * and the equator, and the z-axis aligned with the north pole. The * y-axis is the cross product of x and z, and points toward the 90 * meridian. */ class BodyFixedFrame : public ReferenceFrame { public: SHARED_TYPES(BodyFixedFrame) BodyFixedFrame(Selection center, Selection obj); virtual ~BodyFixedFrame() {}; Eigen::Quaterniond getOrientation(double tjd) const; virtual Eigen::Vector3d getAngularVelocity(double tjd) const; virtual bool isInertial() const; virtual unsigned int nestingDepth(unsigned int depth, unsigned int maxDepth, FrameType frameType) const; private: Selection fixObject; }; class BodyMeanEquatorFrame : public ReferenceFrame { public: SHARED_TYPES(BodyMeanEquatorFrame) BodyMeanEquatorFrame(Selection center, Selection obj, double freeze); BodyMeanEquatorFrame(Selection center, Selection obj); virtual ~BodyMeanEquatorFrame() {}; Eigen::Quaterniond getOrientation(double tjd) const; virtual Eigen::Vector3d getAngularVelocity(double tjd) const; virtual bool isInertial() const; virtual unsigned int nestingDepth(unsigned int depth, unsigned int maxDepth, FrameType frameType) const; private: Selection equatorObject; double freezeEpoch; bool isFrozen; }; /*! FrameVectors are used to define the axes for TwoVector frames */ class FrameVector { public: FrameVector(const FrameVector& fv); ~FrameVector() = default; FrameVector& operator=(const FrameVector&); Eigen::Vector3d direction(double tjd) const; /*! Frames can be defined in reference to other frames; this method * counts the depth of such nesting, up to some specified maximum * level. This method is used to test for circular references in * frames. */ unsigned int nestingDepth(unsigned int depth, unsigned int maxDepth) const; enum FrameVectorType { RelativePosition, RelativeVelocity, ConstantVector, }; static FrameVector createRelativePositionVector(const Selection& _observer, const Selection& _target); static FrameVector createRelativeVelocityVector(const Selection& _observer, const Selection& _target); static FrameVector createConstantVector(const Eigen::Vector3d& _vec, const ReferenceFrame::SharedConstPtr& _frame); private: /*! Type-only constructor is private. Code outside the class should * use create*Vector methods to create new FrameVectors. */ FrameVector(FrameVectorType t); FrameVectorType vecType; Selection observer; Selection target; Eigen::Vector3d vec; // constant vector ReferenceFrame::SharedConstPtr frame; // frame for constant vector }; /*! A two vector frame is a coordinate system defined by a primary and * secondary vector. The primary axis points in the direction of the * primary vector. The secondary axis points in the direction of the * component of the secondary vector that is orthogonal to the primary * vector. The third axis is the cross product of the primary and * secondary axis. */ class TwoVectorFrame : public CachingFrame { public: /*! primAxis and secAxis are the labels of the axes defined by * the primary and secondary vectors: * 1 = x, 2 = y, 3 = z, -1 = -x, -2 = -y, -3 = -z */ TwoVectorFrame(Selection center, const FrameVector& prim, int primAxis, const FrameVector& sec, int secAxis); virtual ~TwoVectorFrame() {}; Eigen::Quaterniond computeOrientation(double tjd) const; virtual bool isInertial() const; virtual unsigned int nestingDepth(unsigned int depth, unsigned int maxDepth, FrameType frameType) const; //! The sine of minimum angle between the primary and secondary vectors static const double Tolerance; private: FrameVector primaryVector; int primaryAxis; FrameVector secondaryVector; int secondaryAxis; int tertiaryAxis; }; #endif // _CELENGINE_FRAME_H_