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

OpenGL

开发平台:

Visual C++

  1. // spiceorbit.cpp
  2. //
  3. // Interface to the SPICE Toolkit
  4. //
  5. // Copyright (C) 2006, 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 <iostream>
  12. #include <cstdio>
  13. #include "SpiceUsr.h"
  14. #include "astro.h"
  15. #include "spiceorbit.h"
  16. #include "spiceinterface.h"
  17. using namespace std;
  18. static const double MILLISEC = astro::secsToDays(0.001);
  19. /*! Create a new SPICE orbit using with a valid interval specified
  20.  *  by beginning and ending.
  21.  */
  22. SpiceOrbit::SpiceOrbit(const std::string& _targetBodyName,
  23.                        const std::string& _originName,
  24.                        double _period,
  25.                        double _boundingRadius,
  26.                        double _beginning,
  27.                        double _ending) :
  28.     targetBodyName(_targetBodyName),
  29.     originName(_originName),
  30.     period(_period),
  31.     boundingRadius(_boundingRadius),
  32.     spiceErr(false),
  33.     validIntervalBegin(_beginning),
  34.     validIntervalEnd(_ending),
  35. useDefaultTimeInterval(false)
  36. {
  37. }
  38. /*! Create a new SPICE orbit. The valid time interval is the first
  39.  *  window over which there is trajectory information for the target
  40.  *  object. All currently loaded kernels are considered when computing
  41.  *  the window. If there's noncontiguous coverage and a time interval
  42.  *  other than the first coverage span is desired, the SPICE orbit must
  43.  *  be constructed with an explicitly specified time range.
  44.  */
  45. SpiceOrbit::SpiceOrbit(const std::string& _targetBodyName,
  46.                    const std::string& _originName,
  47.                        double _period,
  48.                        double _boundingRadius) :
  49. targetBodyName(_targetBodyName),
  50. originName(_originName),
  51. period(_period),
  52. boundingRadius(_boundingRadius),
  53. spiceErr(false),
  54. validIntervalBegin(0.0),
  55. validIntervalEnd(0.0),
  56. useDefaultTimeInterval(true)
  57. {
  58. }
  59. SpiceOrbit::~SpiceOrbit()
  60. {
  61. }
  62. bool
  63. SpiceOrbit::isPeriodic() const
  64. {
  65.     return period != 0.0;
  66. };
  67. double
  68. SpiceOrbit::getPeriod() const
  69. {
  70.     if (isPeriodic())
  71.     {
  72.         return period;
  73.     }
  74.     else
  75.     {
  76.         return validIntervalEnd - validIntervalBegin;
  77.     }
  78. }
  79. bool
  80. SpiceOrbit::init(const string& path,
  81.                  const list<string>* requiredKernels)
  82. {
  83.     // Load required kernel files
  84.     if (requiredKernels != NULL)
  85.     {
  86.         for (list<string>::const_iterator iter = requiredKernels->begin(); iter != requiredKernels->end(); iter++)
  87.         {
  88.             string filepath = path + string("/data/") + *iter;
  89.         if (!LoadSpiceKernel(filepath))
  90.             {    
  91.         spiceErr = true;
  92.                 break;
  93.             }
  94.         }
  95.     }
  96.     // Get the ID codes for the target
  97.     if (!GetNaifId(targetBodyName, &targetID))
  98.     {
  99.         clog << "Couldn't find SPICE ID for " << targetBodyName << "n";
  100.         spiceErr = true;
  101.         return false;
  102.     }
  103.     if (!GetNaifId(originName, &originID))
  104.     {
  105.         clog << "Couldn't find SPICE ID for " << originName << "n";
  106.         spiceErr = true;
  107.         return false;
  108.     }
  109. SpiceInt spkCount = 0;
  110. ktotal_c("spk", &spkCount);
  111.     // Get coverage window for target and origin object
  112. const int MaxIntervals = 10;
  113. SPICEDOUBLE_CELL ( targetCoverage, MaxIntervals * 2 );
  114.     // Clear the coverage window.
  115.     scard_c(0, &targetCoverage);
  116. for (SpiceInt i = 0; i < spkCount; i++)
  117. {
  118. SpiceChar filename[512];
  119. SpiceChar filetype[32];
  120. SpiceChar source[256];
  121. SpiceInt handle;
  122. SpiceBoolean found;
  123. kdata_c(i, "spk",
  124. sizeof(filename), sizeof(filetype), sizeof(source),
  125. filename, filetype, source, &handle, &found);
  126. // First check the coverage window of the target. No interval
  127. // is required for ID 0 (the solar system barycenter) which is
  128. // always at (0, 0, 0).
  129. if (targetID != 0)
  130. {
  131. spkcov_c(filename, targetID, &targetCoverage);
  132. }
  133. }
  134.    
  135. SpiceInt nIntervals = card_c(&targetCoverage) / 2;
  136. if (nIntervals <= 0 && targetID != 0)
  137. {
  138.         clog << "Couldn't find object " << targetBodyName << " in SPICE kernel pool.n";
  139.         spiceErr = true;
  140.     if (failed_c())
  141. {
  142. reset_c();
  143. }
  144. return false;
  145. }
  146. // TODO: need to consider the origin object as well as the target
  147. if (useDefaultTimeInterval)
  148. {
  149. // Set the valid time interval for this orbit to the first interval
  150. // in the coverage window for the target.
  151. SpiceDouble targetBeginning = -1.0e50;
  152. SpiceDouble targetEnding    = +1.0e50;
  153. if (targetID == 0)
  154. {
  155. // Time range for solar system barycenter is infinite
  156. validIntervalBegin = targetBeginning;
  157. validIntervalEnd = targetEnding;
  158. }
  159. else
  160. {
  161. wnfetd_c(&targetCoverage, 0, &targetBeginning, &targetEnding);
  162. // SPICE times are seconds since J2000.0
  163. validIntervalBegin = astro::secsToDays(targetBeginning) + astro::J2000;
  164. validIntervalEnd = astro::secsToDays(targetEnding) + astro::J2000;
  165.             // Reduce interval by a millisecond at each end; otherwise, rounding error
  166.             // can cause us to get SPICE errors when computing states right at the edge
  167.             // of the valid window.
  168.             validIntervalBegin += MILLISEC;
  169.             validIntervalEnd -= MILLISEC;
  170. }
  171. }
  172. else
  173. {
  174.         // Reduce valid interval by a millisecond at each end.
  175.         validIntervalBegin += MILLISEC;
  176.         validIntervalEnd -= MILLISEC;
  177. SpiceDouble beginningSecondsJ2000 = astro::daysToSecs(validIntervalBegin - astro::J2000);
  178. SpiceDouble endingSecondsJ2000    = astro::daysToSecs(validIntervalEnd - astro::J2000);
  179. // A time interval was specified--make sure that it's covered in the SPICE kernel.
  180. if (targetID != 0 &&
  181. !wnincd_c(beginningSecondsJ2000, endingSecondsJ2000, &targetCoverage))
  182. {
  183. clog << "Specified time interval for target " << targetBodyName << " not available.n";
  184. return false;
  185. }
  186. }
  187.     // Test getting the position of the object to make sure that there's
  188.     // adequate data in the kernel to compute the position of the target
  189.     // relative to the origin. Even if both objects are present and have
  190.     // adequate coverage, it's possible that there might be a missing frame
  191.     // definition or itermediate object.
  192.     double beginning = astro::daysToSecs(validIntervalBegin - astro::J2000);
  193.     double position[3];
  194.     double lt = 0.0;
  195.     spkgps_c(targetID, beginning, "eclipj2000", originID,
  196.              position, &lt);
  197.     if (failed_c())
  198.     {
  199.         // Print the error message
  200.         char errMsg[1024];
  201.         getmsg_c("long", sizeof(errMsg), errMsg);
  202.         clog << errMsg << "n";
  203.         spiceErr = true;
  204.         reset_c();
  205.     }
  206.     return !spiceErr;
  207. }
  208. Point3d
  209. SpiceOrbit::computePosition(double jd) const
  210. {
  211.     if (jd < validIntervalBegin)
  212.         jd = validIntervalBegin;
  213.     else if (jd > validIntervalEnd)
  214.         jd = validIntervalEnd;
  215.     if (spiceErr)
  216.     {
  217.         return Point3d(0.0, 0.0, 0.0);
  218.     }
  219.     else
  220.     {
  221.         // Input time for SPICE is seconds after J2000
  222.         double t = astro::daysToSecs(jd - astro::J2000);
  223.         double position[3];
  224.         double lt;          // One way light travel time
  225.         spkgps_c(targetID,
  226.                  t,
  227.                  "eclipj2000",
  228.                  originID,
  229.                  position,
  230.                  &lt);
  231.         // This shouldn't happen, since we've already computed the valid
  232.         // coverage interval.
  233.         if (failed_c())
  234.         {
  235.             // Print the error message
  236.             char errMsg[1024];
  237.             getmsg_c("long", sizeof(errMsg), errMsg);
  238.             clog << errMsg << "n";
  239.             // Reset the error state
  240.             reset_c();
  241.         }
  242.         // Transform into Celestia's coordinate system
  243.         return Point3d(position[0], position[2], -position[1]);
  244.     }
  245. }
  246. Vec3d
  247. SpiceOrbit::computeVelocity(double jd) const
  248. {
  249.     if (jd < validIntervalBegin)
  250.         jd = validIntervalBegin;
  251.     else if (jd > validIntervalEnd)
  252.         jd = validIntervalEnd;
  253.     if (spiceErr)
  254.     {
  255.         return Vec3d(0.0, 0.0, 0.0);
  256.     }
  257.     else
  258.     {
  259.         // Input time for SPICE is seconds after J2000
  260.         double t = astro::daysToSecs(jd - astro::J2000);
  261.         double state[6];
  262.         double lt;          // One way light travel time
  263.         spkgeo_c(targetID,
  264.                  t,
  265.                  "eclipj2000",
  266.                  originID,
  267.                  state,
  268.                  &lt);
  269.         // This shouldn't happen, since we've already computed the valid
  270.         // coverage interval.
  271.         if (failed_c())
  272.         {
  273.             // Print the error message
  274.             char errMsg[1024];
  275.             getmsg_c("long", sizeof(errMsg), errMsg);
  276.             clog << errMsg << "n";
  277.             // Reset the error state
  278.             reset_c();
  279.         }
  280.         // Transform into Celestia's coordinate system, and from km/s to km/day
  281.         double d2s = astro::daysToSecs(1.0);
  282.         return Vec3d(state[3] * d2s, state[5] * d2s, -state[4] * d2s);
  283.     }
  284. }
  285. void SpiceOrbit::getValidRange(double& begin, double& end) const
  286. {
  287.     begin = validIntervalBegin;
  288.     end = validIntervalEnd;
  289. }