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

OpenGL

开发平台:

Visual C++

  1. // samporient.cpp
  2. //
  3. // Copyright (C) 2006-2007, Chris Laurel <claurel@shatters.net>
  4. //
  5. // The SampledOrientation class models orientation of a body by interpolating
  6. // a sequence of key frames.
  7. //
  8. // This program is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU General Public License
  10. // as published by the Free Software Foundation; either version 2
  11. // of the License, or (at your option) any later version.
  12. #include <cmath>
  13. #include <cassert>
  14. #include <string>
  15. #include <algorithm>
  16. #include <vector>
  17. #include <iostream>
  18. #include <fstream>
  19. #include <celmath/mathlib.h>
  20. #include <celengine/samporient.h>
  21. using namespace std;
  22. struct OrientationSample
  23. {
  24.     double t;
  25.     Quatf q;
  26. };
  27. /*!
  28.  * Sampled orientation files are ASCII text files containing a sequence of
  29.  * time stamped quaternion keys. Each record in the file has the form:
  30.  *
  31.  *   <time> <qw> <qx> <qy> <qz>
  32.  *  
  33.  * Where (qw qx qy qz) is a unit quaternion representing a rotation of
  34.  *   theta = acos(qw)*2 radians about the axis (qx, qy, qz)*sin(theta/2).
  35.  * The time values are Julian days in Barycentric Dynamical Time. The records
  36.  * in the orientation file should be ordered so that their times are
  37.  * monotonically increasing.
  38.  *
  39.  * A very simple example file:
  40.  *
  41.  *   2454025 1     0     0     0
  42.  *   2454026 0.707 0.707 0     0
  43.  *   2454027 0     0     1     0
  44.  *
  45.  * Note that while each record of this example file is on a separate line,
  46.  * all whitespace is treated identically, so the entire file could be one
  47.  * a single line.
  48.  */
  49. // 90 degree rotation about x-axis to convert orientation to Celestia's
  50. // coordinate system.
  51. static Quatf coordSysCorrection = Quatf::xrotation((float) (PI / 2.0));
  52. bool operator<(const OrientationSample& a, const OrientationSample& b)
  53. {
  54.     return a.t < b.t;
  55. }
  56. /*! SampledOrientation is a rotation model that interpolates a sequence
  57.  *  of quaternion keyframes. Typically, an instance of SampledRotation will
  58.  *  be created from a file with LoadSampledOrientation().
  59.  */
  60. class SampledOrientation : public RotationModel
  61. {
  62. public:
  63.     SampledOrientation();
  64.     virtual ~SampledOrientation();
  65.     /*! Add another quaternion key to the sampled orientation. The keys
  66.      *  should have monotonically increasing time values.
  67.      */
  68.     void addSample(double tjd, Quatf q);
  69.     /*! The orientation of a sampled rotation model is entirely due
  70.      *  to spin (i.e. there's no notion of an equatorial frame.)
  71.      */
  72.     virtual Quatd spin(double tjd) const;
  73.     virtual bool isPeriodic() const;
  74.     virtual double getPeriod() const;
  75.     virtual void getValidRange(double& begin, double& end) const;
  76. private:
  77.     Quatf getOrientation(double tjd) const;
  78. private:
  79.     vector<OrientationSample> samples;
  80.     mutable int lastSample;
  81.     enum InterpolationType
  82.     {
  83.         Linear = 0,
  84.         Cubic = 1,
  85.     };
  86.     InterpolationType interpolation;
  87. };
  88. SampledOrientation::SampledOrientation() :
  89.     lastSample(0),
  90.     interpolation(Linear)
  91. {
  92. }
  93. SampledOrientation::~SampledOrientation()
  94. {
  95. }
  96. void SampledOrientation::addSample(double t, Quatf q)
  97. {
  98.     // TODO: add a check for out of sequence samples
  99.     OrientationSample samp;
  100.     samp.t = t;
  101.     samp.q = q * coordSysCorrection;
  102.     samples.push_back(samp);
  103. }
  104. Quatd SampledOrientation::spin(double tjd) const
  105. {
  106.     // TODO: cache the last value returned
  107.     Quatf q = getOrientation(tjd);
  108.     return Quatd(q.w, q.x, q.y, q.z);
  109. }
  110. double SampledOrientation::getPeriod() const
  111. {
  112.     return samples[samples.size() - 1].t - samples[0].t;
  113. }
  114. bool SampledOrientation::isPeriodic() const
  115. {
  116.     return false;
  117. }
  118. void SampledOrientation::getValidRange(double& begin, double& end) const
  119. {
  120.     begin = samples[0].t;
  121.     end = samples[samples.size() - 1].t;
  122. }
  123. Quatf SampledOrientation::getOrientation(double tjd) const
  124. {
  125.     Quatf orientation;
  126.     if (samples.size() == 0)
  127.     {
  128.         orientation = Quatf(1.0f);
  129.     }
  130.     else if (samples.size() == 1)
  131.     {
  132.         orientation = samples[0].q;
  133.     }
  134.     else
  135.     {
  136.         OrientationSample samp;
  137.         samp.t = tjd;
  138.         int n = lastSample;
  139.         // Do a binary search to find the samples that define the orientation
  140.         // at the current time. Cache the previous sample used and avoid
  141.         // the search if the covers the requested time.
  142.         if (n < 1 || n >= (int) samples.size() || tjd < samples[n - 1].t || tjd > samples[n].t)
  143.         {
  144.             vector<OrientationSample>::const_iterator iter = lower_bound(samples.begin(),
  145.                                                               samples.end(),
  146.                                                               samp);
  147.             if (iter == samples.end())
  148.                 n = samples.size();
  149.             else
  150.                 n = iter - samples.begin();
  151.             lastSample = n;
  152.         }
  153.         if (n == 0)
  154.         {
  155.             orientation = samples[0].q;
  156.         }
  157.         else if (n < (int) samples.size())
  158.         {
  159.             if (interpolation == Linear)
  160.             {
  161.                 OrientationSample s0 = samples[n - 1];
  162.                 OrientationSample s1 = samples[n];
  163.                 float t = (float) ((tjd - s0.t) / (s1.t - s0.t));
  164.                 orientation = Quatf::slerp(s0.q, s1.q, t);
  165.             }
  166.             else if (interpolation == Cubic)
  167.             {
  168.                 // TODO: add support for cubic interpolation of quaternions
  169.                 assert(0);
  170.             }
  171.             else
  172.             {
  173.                 // Unknown interpolation type
  174.                 orientation = Quatf(1.0f);
  175.             }
  176.         }
  177.         else
  178.         {
  179.             orientation = samples[samples.size() - 1].q;
  180.         }
  181.     }
  182.     return orientation;
  183. }
  184. RotationModel* LoadSampledOrientation(const string& filename)
  185. {
  186.     ifstream in(filename.c_str());
  187.     if (!in.good())
  188.         return NULL;
  189.     SampledOrientation* sampOrientation = new SampledOrientation();
  190.     int nSamples = 0;
  191.     while (in.good())
  192.     {
  193.         double tjd;
  194.         Quatf q;
  195.         in >> tjd;
  196.         in >> q.w;
  197.         in >> q.x;
  198.         in >> q.y;
  199.         in >> q.z;
  200.         q.normalize();
  201.         if (in.good())
  202.         {
  203.             sampOrientation->addSample(tjd, q);
  204.             nSamples++;
  205.         }
  206.     }
  207.     return sampOrientation;
  208. }