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

OpenGL

开发平台:

Visual C++

  1. // samporbit.cpp
  2. //
  3. // Copyright (C) 2002-2008, Celestia Development Team
  4. // Original version by Chris Laurel <claurel@gmail.com>
  5. //
  6. // Trajectories based on unevenly spaced cartesian positions.
  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 <string>
  14. #include <algorithm>
  15. #include <vector>
  16. #include <iostream>
  17. #include <fstream>
  18. #include <limits>
  19. #include <celmath/mathlib.h>
  20. #include <celengine/astro.h>
  21. #include <celengine/orbit.h>
  22. #include <celengine/samporbit.h>
  23. using namespace std;
  24. // Trajectories are sampled adaptively for rendering.  MaxSampleInterval
  25. // is the maximum time (in days) between samples.  The threshold angle
  26. // is the maximum angle allowed between path segments.
  27. static const double MinSampleInterval = 1.0 / 1440.0; // one minute
  28. static const double MaxSampleInterval = 50.0;
  29. static const double SampleThresholdAngle = 2.0;
  30. // Position-only sample
  31. template <typename T> struct Sample
  32. {
  33.     double t;
  34.     T x, y, z;
  35. };
  36. // Position + velocity sample
  37. template <typename T> struct SampleXYZV
  38. {
  39.     double t;
  40.     Vector3<T> position;
  41.     Vector3<T> velocity;
  42. };
  43. template <typename T> bool operator<(const Sample<T>& a, const Sample<T>& b)
  44. {
  45.     return a.t < b.t;
  46. }
  47. template <typename T> bool operator<(const SampleXYZV<T>& a, const SampleXYZV<T>& b)
  48. {
  49.     return a.t < b.t;
  50. }
  51. template <typename T> class SampledOrbit : public CachingOrbit
  52. {
  53. public:
  54.     SampledOrbit(TrajectoryInterpolation);
  55.     virtual ~SampledOrbit();
  56.     void addSample(double t, double x, double y, double z);
  57.     void setPeriod();
  58.     double getPeriod() const;
  59.     double getBoundingRadius() const;
  60.     Point3d computePosition(double jd) const;
  61.     Vec3d computeVelocity(double jd) const;
  62.     bool isPeriodic() const;
  63.     void getValidRange(double& begin, double& end) const;
  64.     virtual void sample(double, double, int, OrbitSampleProc& proc) const;
  65. private:
  66.     vector<Sample<T> > samples;
  67.     double boundingRadius;
  68.     double period;
  69.     mutable int lastSample;
  70.     TrajectoryInterpolation interpolation;
  71. };
  72. template <typename T> SampledOrbit<T>::SampledOrbit(TrajectoryInterpolation _interpolation) :
  73.     boundingRadius(0.0),
  74.     period(1.0),
  75.     lastSample(0),
  76.     interpolation(_interpolation)
  77. {
  78. }
  79. template <typename T> SampledOrbit<T>::~SampledOrbit()
  80. {
  81. }
  82. template <typename T> void SampledOrbit<T>::addSample(double t, double x, double y, double z)
  83. {
  84.     double r = sqrt(x * x + y * y + z * z);
  85.     if (r > boundingRadius)
  86.         boundingRadius = r;
  87.     Sample<T> samp;
  88.     samp.x = (T) x;
  89.     samp.y = (T) y;
  90.     samp.z = (T) z;
  91.     samp.t = t;
  92.     samples.insert(samples.end(), samp);
  93. }
  94. template <typename T> double SampledOrbit<T>::getPeriod() const
  95. {
  96.     return samples[samples.size() - 1].t - samples[0].t;
  97. }
  98. template <typename T> bool SampledOrbit<T>::isPeriodic() const
  99. {
  100.     return false;
  101. }
  102. template <typename T> void SampledOrbit<T>::getValidRange(double& begin, double& end) const
  103. {
  104.     begin = samples[0].t;
  105.     end = samples[samples.size() - 1].t;
  106. }
  107. template <typename T> double SampledOrbit<T>::getBoundingRadius() const
  108. {
  109.     return boundingRadius;
  110. }
  111. static Vec3d cubicInterpolate(const Vec3d& p0, const Vec3d& v0,
  112.                               const Vec3d& p1, const Vec3d& v1,
  113.                               double t)
  114. {
  115.     return p0 + (((2.0 * (p0 - p1) + v1 + v0) * (t * t * t)) +
  116.                  ((3.0 * (p1 - p0) - 2.0 * v0 - v1) * (t * t)) +
  117.                  (v0 * t));
  118. }
  119. static Vec3d cubicInterpolateVelocity(const Vec3d& p0, const Vec3d& v0,
  120.                                       const Vec3d& p1, const Vec3d& v1,
  121.                                       double t)
  122. {
  123.     return ((2.0 * (p0 - p1) + v1 + v0) * (3.0 * t * t)) +
  124.            ((3.0 * (p1 - p0) - 2.0 * v0 - v1) * (2.0 * t)) +
  125.            v0;
  126. }
  127. template <typename T> Point3d SampledOrbit<T>::computePosition(double jd) const
  128. {
  129.     Vec3d pos;
  130.     if (samples.size() == 0)
  131.     {
  132.         pos = Vec3d(0.0, 0.0, 0.0);
  133.     }
  134.     else if (samples.size() == 1)
  135.     {
  136.         pos = Vec3d(samples[0].x, samples[1].y, samples[2].z);
  137.     }
  138.     else
  139.     {
  140.         Sample<T> samp;
  141.         samp.t = jd;
  142.         int n = lastSample;
  143.         if (n < 1 || n >= (int) samples.size() || jd < samples[n - 1].t || jd > samples[n].t)
  144.         {
  145.             typename vector<Sample<T> >::const_iterator iter = lower_bound(samples.begin(),
  146.                                                                            samples.end(),
  147.                                                                            samp);
  148.             if (iter == samples.end())
  149.                 n = samples.size();
  150.             else
  151.                 n = iter - samples.begin();
  152.             lastSample = n;
  153.         }
  154.         if (n == 0)
  155.         {
  156.             pos = Vec3d(samples[n].x, samples[n].y, samples[n].z);
  157.         }
  158.         else if (n < (int) samples.size())
  159.         {
  160.             if (interpolation == TrajectoryInterpolationLinear)
  161.             {
  162.                 Sample<T> s0 = samples[n - 1];
  163.                 Sample<T> s1 = samples[n];
  164.                 double t = (jd - s0.t) / (s1.t - s0.t);
  165.                 pos = Vec3d(Mathd::lerp(t, (double) s0.x, (double) s1.x),
  166.                             Mathd::lerp(t, (double) s0.y, (double) s1.y),
  167.                             Mathd::lerp(t, (double) s0.z, (double) s1.z));
  168.             }
  169.             else if (interpolation == TrajectoryInterpolationCubic)
  170.             {
  171.                 Sample<T> s0, s1, s2, s3;
  172.                 if (n > 1)
  173.                     s0 = samples[n - 2];
  174.                 else
  175.                     s0 = samples[n - 1];
  176.                 s1 = samples[n - 1];
  177.                 s2 = samples[n];
  178.                 if (n < (int) samples.size() - 1)
  179.                     s3 = samples[n + 1];
  180.                 else
  181.                     s3 = samples[n];
  182.                 double h = s2.t - s1.t;
  183.                 double ih = 1.0 / h;
  184.                 double t = (jd - s1.t) * ih;
  185.                 Vec3d p0(s1.x, s1.y, s1.z);
  186.                 Vec3d p1(s2.x, s2.y, s2.z);
  187.                 Vec3d v10((double) s1.x - (double) s0.x,
  188.                           (double) s1.y - (double) s0.y,
  189.                           (double) s1.z - (double) s0.z);
  190.                 Vec3d v21((double) s2.x - (double) s1.x,
  191.                           (double) s2.y - (double) s1.y,
  192.                           (double) s2.z - (double) s1.z);
  193.                 Vec3d v32((double) s3.x - (double) s2.x,
  194.                           (double) s3.y - (double) s2.y,
  195.                           (double) s3.z - (double) s2.z);
  196.                 
  197.                 // Estimate velocities by averaging the differences at adjacent spans
  198.                 // (except at the end spans, where we just use a single velocity.)
  199.                 Vec3d v0;
  200.                 if (n > 1)
  201.                 {
  202.                     v0 = v10 * (0.5 / (s1.t - s0.t)) + v21 * (0.5 * ih);
  203.                     v0 *= h;
  204.                 }
  205.                 else
  206.                 {
  207.                     v0 = v21;
  208.                 }
  209.                 
  210.                 Vec3d v1;
  211.                 if (n < (int) samples.size() - 1)
  212.                 {
  213.                     v1 = v21 * (0.5 * ih) + v32 * (0.5 / (s3.t - s2.t));
  214.                     v1 *= h;
  215.                 }
  216.                 else
  217.                 {
  218.                     v1 = v21;
  219.                 }                
  220.                 pos = cubicInterpolate(p0, v0, p1, v1, t);
  221.             }
  222.             else
  223.             {
  224.                 // Unknown interpolation type
  225.                 pos = Vec3d(0.0, 0.0, 0.0);
  226.             }
  227.         }
  228.         else
  229.         {
  230.             pos = Vec3d(samples[n - 1].x, samples[n - 1].y, samples[n - 1].z);
  231.         }
  232.     }
  233.     // Add correction for Celestia's coordinate system
  234.     return Point3d(pos.x, pos.z, -pos.y);
  235. }
  236. template <typename T> Vec3d SampledOrbit<T>::computeVelocity(double jd) const
  237. {
  238.     Vec3d vel;
  239.     if (samples.size() < 2)
  240.     {
  241.         vel = Vec3d(0.0, 0.0, 0.0);
  242.     }
  243.     else
  244.     {
  245.         Sample<T> samp;
  246.         samp.t = jd;
  247.         int n = lastSample;
  248.         if (n < 1 || n >= (int) samples.size() || jd < samples[n - 1].t || jd > samples[n].t)
  249.         {
  250.             typename vector<Sample<T> >::const_iterator iter = lower_bound(samples.begin(),
  251.                                                                            samples.end(),
  252.                                                                            samp);
  253.             if (iter == samples.end())
  254.                 n = samples.size();
  255.             else
  256.                 n = iter - samples.begin();
  257.             lastSample = n;
  258.         }
  259.         if (n == 0)
  260.         {
  261.             vel = Vec3d(0.0, 0.0, 0.0);
  262.         }
  263.         else if (n < (int) samples.size())
  264.         {
  265.             if (interpolation == TrajectoryInterpolationLinear)
  266.             {
  267.                 Sample<T> s0 = samples[n - 1];
  268.                 Sample<T> s1 = samples[n];
  269.                 double dt = (s1.t - s0.t);
  270.                 return (Vec3d(s1.x, s1.y, s1.z) - Vec3d(s0.x, s0.y, s0.z)) * (1.0 / dt);
  271.             }
  272.             else if (interpolation == TrajectoryInterpolationCubic)
  273.             {
  274.                 Sample<T> s0, s1, s2, s3;
  275.                 if (n > 1)
  276.                     s0 = samples[n - 2];
  277.                 else
  278.                     s0 = samples[n - 1];
  279.                 s1 = samples[n - 1];
  280.                 s2 = samples[n];
  281.                 if (n < (int) samples.size() - 1)
  282.                     s3 = samples[n + 1];
  283.                 else
  284.                     s3 = samples[n];
  285.                 double h = s2.t - s1.t;
  286.                 double ih = 1.0 / h;
  287.                 double t = (jd - s1.t) * ih;
  288.                 Vec3d p0(s1.x, s1.y, s1.z);
  289.                 Vec3d p1(s2.x, s2.y, s2.z);
  290.                 Vec3d v10((double) s1.x - (double) s0.x,
  291.                           (double) s1.y - (double) s0.y,
  292.                           (double) s1.z - (double) s0.z);
  293.                 Vec3d v21((double) s2.x - (double) s1.x,
  294.                           (double) s2.y - (double) s1.y,
  295.                           (double) s2.z - (double) s1.z);
  296.                 Vec3d v32((double) s3.x - (double) s2.x,
  297.                           (double) s3.y - (double) s2.y,
  298.                           (double) s3.z - (double) s2.z);
  299.                 
  300.                 // Estimate velocities by averaging the differences at adjacent spans
  301.                 // (except at the end spans, where we just use a single velocity.)
  302.                 Vec3d v0;
  303.                 if (n > 1)
  304.                 {
  305.                     v0 = v10 * (0.5 / (s1.t - s0.t)) + v21 * (0.5 * ih);
  306.                     v0 *= h;
  307.                 }
  308.                 else
  309.                 {
  310.                     v0 = v21;
  311.                 }
  312.                 
  313.                 Vec3d v1;
  314.                 if (n < (int) samples.size() - 1)
  315.                 {
  316.                     v1 = v21 * (0.5 * ih) + v32 * (0.5 / (s3.t - s2.t));
  317.                     v1 *= h;
  318.                 }
  319.                 else
  320.                 {
  321.                     v1 = v21;
  322.                 }                
  323.                 vel = cubicInterpolateVelocity(p0, v0, p1, v1, t);
  324.                 vel *= 1.0 / h;
  325.             }
  326.             else
  327.             {
  328.                 // Unknown interpolation type
  329.                 vel = Vec3d(0.0, 0.0, 0.0);
  330.             }
  331.         }
  332.         else
  333.         {
  334.             vel = Vec3d(0.0, 0.0, 0.0);
  335.         }
  336.     }
  337.     return Vec3d(vel.x, vel.z, -vel.y);
  338. }
  339. template <typename T> void SampledOrbit<T>::sample(double start, double t, int,
  340.                                                    OrbitSampleProc& proc) const
  341. {
  342.     double cosThresholdAngle = cos(degToRad(SampleThresholdAngle));
  343.     double dt = MinSampleInterval;
  344.     double end = start + t;
  345.     double current = start;
  346.     proc.sample(current, positionAtTime(current));
  347.     while (current < end)
  348.     {
  349.         double dt2 = dt;
  350.         Point3d goodpt;
  351.         double gooddt = dt;
  352.         Point3d pos0 = positionAtTime(current);
  353.         goodpt = positionAtTime(current + dt2);
  354.         while (1)
  355.         {
  356.             Point3d pos1 = positionAtTime(current + dt2);
  357.             Point3d pos2 = positionAtTime(current + dt2 * 2.0);
  358.             Vec3d vec1 = pos1 - pos0;
  359.             Vec3d vec2 = pos2 - pos0;
  360.             vec1.normalize();
  361.             vec2.normalize();
  362.             double dot = vec1 * vec2;
  363.             if (dot > cosThresholdAngle && dt2 < MaxSampleInterval)
  364.             {
  365.                 gooddt = dt2;
  366.                 goodpt = pos1;
  367.                 dt2 *= 2.0;
  368.             }
  369.             else
  370.             {
  371.                 proc.sample(current + gooddt, goodpt);
  372.                 break;
  373.             }
  374.         }
  375.         current += gooddt;
  376.     }
  377. }
  378. // Sampled orbit with positions and velocities
  379. template <typename T> class SampledOrbitXYZV : public CachingOrbit
  380. {
  381. public:
  382.     SampledOrbitXYZV(TrajectoryInterpolation);
  383.     virtual ~SampledOrbitXYZV();
  384.     void addSample(double t, const Vec3d& position, const Vec3d& velocity);
  385.     void setPeriod();
  386.     double getPeriod() const;
  387.     double getBoundingRadius() const;
  388.     Point3d computePosition(double jd) const;
  389.     Vec3d computeVelocity(double jd) const;
  390.     bool isPeriodic() const;
  391.     void getValidRange(double& begin, double& end) const;
  392.     virtual void sample(double, double, int, OrbitSampleProc& proc) const;
  393. private:
  394.     vector<SampleXYZV<T> > samples;
  395.     double boundingRadius;
  396.     double period;
  397.     mutable int lastSample;
  398.     TrajectoryInterpolation interpolation;
  399. };
  400. template <typename T> SampledOrbitXYZV<T>::SampledOrbitXYZV(TrajectoryInterpolation _interpolation) :
  401.     boundingRadius(0.0),
  402.     period(1.0),
  403.     lastSample(0),
  404.     interpolation(_interpolation)
  405. {
  406. }
  407. template <typename T> SampledOrbitXYZV<T>::~SampledOrbitXYZV()
  408. {
  409. }
  410. // Add a new sample to the trajectory:
  411. //    Position in km
  412. //    Velocity in km/Julian day
  413. template <typename T> void SampledOrbitXYZV<T>::addSample(double t, const Vec3d& position, const Vec3d& velocity)
  414. {
  415.     double r = position.length();
  416.     if (r > boundingRadius)
  417.         boundingRadius = r;
  418.     SampleXYZV<T> samp;
  419.     samp.t = t;
  420.     samp.position = Vector3<T>((T) position.x, (T) position.y, (T) position.z);
  421.     samp.velocity = Vector3<T>((T) velocity.x, (T) velocity.y, (T) velocity.z);
  422.     samples.push_back(samp);
  423. }
  424. template <typename T> double SampledOrbitXYZV<T>::getPeriod() const
  425. {
  426.     return samples[samples.size() - 1].t - samples[0].t;
  427. }
  428. template <typename T> bool SampledOrbitXYZV<T>::isPeriodic() const
  429. {
  430.     return false;
  431. }
  432. template <typename T> void SampledOrbitXYZV<T>::getValidRange(double& begin, double& end) const
  433. {
  434.     begin = samples[0].t;
  435.     end = samples[samples.size() - 1].t;
  436. }
  437. template <typename T> double SampledOrbitXYZV<T>::getBoundingRadius() const
  438. {
  439.     return boundingRadius;
  440. }
  441. template <typename T> Point3d SampledOrbitXYZV<T>::computePosition(double jd) const
  442. {
  443.     Vec3d pos;
  444.     if (samples.size() == 0)
  445.     {
  446.         pos = Vec3d(0.0, 0.0, 0.0);
  447.     }
  448.     else if (samples.size() == 1)
  449.     {
  450.         pos = Vec3d(samples[0].position.x, samples[1].position.y, samples[2].position.z);
  451.     }
  452.     else
  453.     {
  454.         SampleXYZV<T> samp;
  455.         samp.t = jd;
  456.         int n = lastSample;
  457.         if (n < 1 || n >= (int) samples.size() || jd < samples[n - 1].t || jd > samples[n].t)
  458.         {
  459.             typename vector<SampleXYZV<T> >::const_iterator iter = lower_bound(samples.begin(),
  460.                                                                                samples.end(),
  461.                                                                                samp);
  462.             if (iter == samples.end())
  463.                 n = samples.size();
  464.             else
  465.                 n = iter - samples.begin();
  466.             lastSample = n;
  467.         }
  468.         if (n == 0)
  469.         {
  470.             pos = Vec3d(samples[n].position.x, samples[n].position.y, samples[n].position.z);
  471.         }
  472.         else if (n < (int) samples.size())
  473.         {
  474.             SampleXYZV<T> s0 = samples[n - 1];
  475.             SampleXYZV<T> s1 = samples[n];
  476.             if (interpolation == TrajectoryInterpolationLinear)
  477.             {
  478.                 double t = (jd - s0.t) / (s1.t - s0.t);
  479.                 pos = Vec3d(Mathd::lerp(t, (double) s0.position.x, (double) s1.position.x),
  480.                             Mathd::lerp(t, (double) s0.position.y, (double) s1.position.y),
  481.                             Mathd::lerp(t, (double) s0.position.z, (double) s1.position.z));
  482.             }
  483.             else if (interpolation == TrajectoryInterpolationCubic)
  484.             {
  485.                 double h = s1.t - s0.t;
  486.                 double ih = 1.0 / h;
  487.                 double t = (jd - s0.t) * ih;
  488.                 Vec3d p0(s0.position.x, s0.position.y, s0.position.z);
  489.                 Vec3d v0(s0.velocity.x, s0.velocity.y, s0.velocity.z);
  490.                 Vec3d p1(s1.position.x, s1.position.y, s1.position.z);
  491.                 Vec3d v1(s1.velocity.x, s1.velocity.y, s1.velocity.z);
  492.                 pos = cubicInterpolate(p0, v0 * h, p1, v1 * h, t);
  493.             }
  494.             else
  495.             {
  496.                 // Unknown interpolation type
  497.                 pos = Vec3d(0.0, 0.0, 0.0);
  498.             }
  499.         }
  500.         else
  501.         {
  502.             pos = Vec3d(samples[n - 1].position.x, samples[n - 1].position.y, samples[n - 1].position.z);
  503.         }
  504.     }
  505.     // Add correction for Celestia's coordinate system
  506.     return Point3d(pos.x, pos.z, -pos.y);
  507. }
  508. // Velocity is computed as the derivative of the interpolating function
  509. // for position.
  510. template <typename T> Vec3d SampledOrbitXYZV<T>::computeVelocity(double jd) const
  511. {
  512.     Vec3d vel(0.0, 0.0, 0.0);
  513.     if (samples.size() >= 2)
  514.     {
  515.         SampleXYZV<T> samp;
  516.         samp.t = jd;
  517.         int n = lastSample;
  518.         if (n < 1 || n >= (int) samples.size() || jd < samples[n - 1].t || jd > samples[n].t)
  519.         {
  520.             typename vector<SampleXYZV<T> >::const_iterator iter = lower_bound(samples.begin(),
  521.                                                                                samples.end(),
  522.                                                                                samp);
  523.             if (iter == samples.end())
  524.                 n = samples.size();
  525.             else
  526.                 n = iter - samples.begin();
  527.             lastSample = n;
  528.         }
  529.         if (n > 0 && n < (int) samples.size())
  530.         {
  531.             SampleXYZV<T> s0 = samples[n - 1];
  532.             SampleXYZV<T> s1 = samples[n];
  533.             if (interpolation == TrajectoryInterpolationLinear)
  534.             {
  535.                 double h = s1.t - s0.t;
  536.                 vel = Vec3d(s1.position.x - s0.position.x,
  537.                             s1.position.y - s0.position.y,
  538.                             s1.position.z - s0.position.z) * (1.0 / h) * astro::daysToSecs(1.0);
  539.             }
  540.             else if (interpolation == TrajectoryInterpolationCubic)
  541.             {
  542.                 double h = s1.t - s0.t;
  543.                 double ih = 1.0 / h;
  544.                 double t = (jd - s0.t) * ih;
  545.                 Vec3d p0(s0.position.x, s0.position.y, s0.position.z);
  546.                 Vec3d p1(s1.position.x, s1.position.y, s1.position.z);
  547.                 Vec3d v0(s0.velocity.x, s0.velocity.y, s0.velocity.z);
  548.                 Vec3d v1(s1.velocity.x, s1.velocity.y, s1.velocity.z);
  549.                 vel = cubicInterpolateVelocity(p0, v0 * h, p1, v1 * h, t) * ih;
  550.             }
  551.             else
  552.             {
  553.                 // Unknown interpolation type
  554.                 vel = Vec3d(0.0, 0.0, 0.0);
  555.             }
  556.         }
  557.     }
  558.     // Add correction for Celestia's coordinate system
  559.     return Vec3d(vel.x, vel.z, -vel.y);
  560. }
  561. template <typename T> void SampledOrbitXYZV<T>::sample(double start, double t, int,
  562.                                                        OrbitSampleProc& proc) const
  563. {
  564.     double cosThresholdAngle = cos(degToRad(SampleThresholdAngle));
  565.     double dt = MinSampleInterval;
  566.     double end = start + t;
  567.     double current = start;
  568.     proc.sample(current, positionAtTime(current));
  569.     while (current < end)
  570.     {
  571.         double dt2 = dt;
  572.         Point3d goodpt;
  573.         double gooddt = dt;
  574.         Point3d pos0 = positionAtTime(current);
  575.         goodpt = positionAtTime(current + dt2);
  576.         while (1)
  577.         {
  578.             Point3d pos1 = positionAtTime(current + dt2);
  579.             Point3d pos2 = positionAtTime(current + dt2 * 2.0);
  580.             Vec3d vec1 = pos1 - pos0;
  581.             Vec3d vec2 = pos2 - pos0;
  582.             vec1.normalize();
  583.             vec2.normalize();
  584.             double dot = vec1 * vec2;
  585.             if (dot > 1.0)
  586.                 dot = 1.0;
  587.             else if (dot < -1.0)
  588.                 dot = -1.0;
  589.             if (dot > cosThresholdAngle && dt2 < MaxSampleInterval)
  590.             {
  591.                 gooddt = dt2;
  592.                 goodpt = pos1;
  593.                 dt2 *= 2.0;
  594.             }
  595.             else
  596.             {
  597.                 proc.sample(current + gooddt, goodpt);
  598.                 break;
  599.             }
  600.         }
  601.         current += gooddt;
  602.     }
  603. }
  604. // Scan past comments. A comment begins with the # character and ends
  605. // with a newline. Return true if the stream state is good. The stream
  606. // position will be at the first non-comment, non-whitespace character.
  607. static bool SkipComments(istream& in)
  608. {
  609.     bool inComment = false;
  610.     bool done = false;
  611.     int c = in.get();
  612.     while (!done)
  613.     {
  614.         if (in.eof())
  615.         {
  616.             done = true;
  617.         }
  618.         else 
  619.         {
  620.             if (inComment)
  621.             {
  622.                 if (c == 'n')
  623.                     inComment = false;
  624.             }
  625.             else
  626.             {
  627.                 if (c == '#')
  628.                 {
  629.                     inComment = true;
  630.                 }
  631.                 else if (!isspace(c))
  632.                 {
  633.                     in.unget();
  634.                     done = true;
  635.                 }
  636.             }
  637.         }
  638.         if (!done)
  639.             c = in.get();
  640.     }
  641.     return in.good();
  642. }
  643. // Load an ASCII xyz trajectory file. The file contains records with 4 double
  644. // precision values each:
  645. //
  646. // 1: TDB time
  647. // 2: Position x
  648. // 3: Position y
  649. // 4: Position z
  650. //
  651. // Positions are in kilometers.
  652. //
  653. // The numeric data may be preceeded by a comment block. Commented lines begin
  654. // with a #; data is read start fromt the first non-whitespace character outside
  655. // of a comment.
  656. template <typename T> SampledOrbit<T>* LoadSampledOrbit(const string& filename, TrajectoryInterpolation interpolation, T)
  657. {
  658.     ifstream in(filename.c_str());
  659.     if (!in.good())
  660.         return NULL;
  661.     if (!SkipComments(in))
  662.         return NULL;
  663.     SampledOrbit<T>* orbit = NULL;
  664.     
  665.     orbit = new SampledOrbit<T>(interpolation);
  666.     double lastSampleTime = -numeric_limits<double>::infinity();
  667.     while (in.good())
  668.     {
  669.         double tdb, x, y, z;
  670.         in >> tdb;
  671.         in >> x;
  672.         in >> y;
  673.         in >> z;
  674.         if (in.good())
  675.         {
  676.             // Skip samples with duplicate times; such trajectories are invalid, but
  677.             // are unfortunately used in some existing add-ons.
  678.             if (tdb != lastSampleTime)
  679.             {
  680.                 orbit->addSample(tdb, x, y, z);
  681.                 lastSampleTime = tdb;
  682.             }
  683.         }
  684.     }
  685.     return orbit;
  686. }
  687. // Load an xyzv sampled trajectory file. The file contains records with 7 double
  688. // precision values:
  689. //
  690. // 1: TDB time
  691. // 2: Position x
  692. // 3: Position y
  693. // 4: Position z
  694. // 5: Velocity x
  695. // 6: Velocity y
  696. // 7: Velocity z
  697. //
  698. // Positions are in kilometers, velocities are kilometers per second.
  699. //
  700. // The numeric data may be preceeded by a comment block. Commented lines begin
  701. // with a #; data is read start fromt the first non-whitespace character outside
  702. // of a comment.
  703. template <typename T> SampledOrbitXYZV<T>* LoadSampledOrbitXYZV(const string& filename, TrajectoryInterpolation interpolation, T)
  704. {
  705.     ifstream in(filename.c_str());
  706.     if (!in.good())
  707.         return NULL;
  708.     if (!SkipComments(in))
  709.         return NULL;
  710.     SampledOrbitXYZV<T>* orbit = NULL;
  711.     
  712.     orbit = new SampledOrbitXYZV<T>(interpolation);
  713.     double lastSampleTime = -numeric_limits<double>::infinity();
  714.     while (in.good())
  715.     {
  716.         double tdb = 0.0;
  717.         Vec3d position;
  718.         Vec3d velocity;
  719.         in >> tdb;
  720.         in >> position.x;
  721.         in >> position.y;
  722.         in >> position.z;
  723.         in >> velocity.x;
  724.         in >> velocity.y;
  725.         in >> velocity.z;
  726.         // Convert velocities from km/sec to km/Julian day
  727.         velocity = velocity * astro::daysToSecs(1.0);
  728.         if (in.good())
  729.         {
  730.             if (tdb != lastSampleTime)
  731.             {
  732.                 orbit->addSample(tdb, position, velocity);
  733.                 lastSampleTime = tdb;
  734.             }
  735.         }
  736.     }
  737.     return orbit;
  738. }
  739. /*! Load a trajectory file containing single precision positions.
  740.  */
  741. Orbit* LoadSampledTrajectorySinglePrec(const string& filename, TrajectoryInterpolation interpolation)
  742. {
  743.     return LoadSampledOrbit(filename, interpolation, 0.0f);
  744. }
  745. /*! Load a trajectory file containing double precision positions.
  746.  */
  747. Orbit* LoadSampledTrajectoryDoublePrec(const string& filename, TrajectoryInterpolation interpolation)
  748. {
  749.     return LoadSampledOrbit(filename, interpolation, 0.0);
  750. }
  751. /*! Load a trajectory file with single precision positions and velocities.
  752.  */
  753. Orbit* LoadXYZVTrajectorySinglePrec(const string& filename, TrajectoryInterpolation interpolation)
  754. {
  755.     return LoadSampledOrbitXYZV(filename, interpolation, 0.0f);
  756. }
  757. /*! Load a trajectory file with double precision positions and velocities.
  758.  */
  759. Orbit* LoadXYZVTrajectoryDoublePrec(const string& filename, TrajectoryInterpolation interpolation)
  760. {
  761.     return LoadSampledOrbitXYZV(filename, interpolation, 0.0);
  762. }