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

OpenGL

开发平台:

Visual C++

  1. // spice2xyzv.cpp
  2. //
  3. // Copyright (C) 2008, Chris Laurel <claurel@shatters.net>
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. //
  10. // Create a Celestia xyzv file from a pool of SPICE SPK files
  11. #include "SpiceUsr.h"
  12. #include <string>
  13. #include <vector>
  14. #include <iostream>
  15. #include <fstream>
  16. #include <iomanip>
  17. #include <cmath>
  18. #include <ctime>
  19. using namespace std;
  20. const double J2000 = 2451545.0;
  21. // Default values
  22. // Units are seconds
  23. const double MIN_STEP_SIZE = 60.0;
  24. const double MAX_STEP_SIZE = 5 * 86400.0;
  25. // Units are kilometers
  26. const double TOLERANCE     = 20.0;
  27. class Configuration
  28. {
  29. public:
  30.     Configuration() :
  31.         kernelDirectory("."),
  32.         frameName("eclipJ2000"),
  33.         minStepSize(MIN_STEP_SIZE),
  34.         maxStepSize(MAX_STEP_SIZE),
  35.         tolerance(TOLERANCE)
  36.     {
  37.     }
  38.     string kernelDirectory;
  39.     vector<string> kernelList;
  40.     string startDate;
  41.     string endDate;
  42.     string observerName;
  43.     string targetName;
  44.     string frameName;
  45.     double minStepSize;
  46.     double maxStepSize;
  47.     double tolerance;
  48. };
  49. // Very basic 3-vector class
  50. class Vec3d
  51. {
  52. public:
  53.     Vec3d() : x(0.0), y(0.0), z(0.0) {}
  54.     Vec3d(double _x, double _y, double _z) : x(_x), y(_y), z(_z) {}
  55.     Vec3d(const double v[]) : x(v[0]), y(v[1]), z(v[2]) {}
  56.     double length() const { return std::sqrt(x * x + y * y + z * z); }
  57.     double x, y, z;
  58. };
  59. // Vector add
  60. Vec3d operator+(const Vec3d& v0, const Vec3d& v1)
  61. {
  62.     return Vec3d(v0.x + v1.x, v0.y + v1.y, v0.z + v1.z);
  63. }
  64. // Vector subtract
  65. Vec3d operator-(const Vec3d& v0, const Vec3d& v1)
  66. {
  67.     return Vec3d(v0.x - v1.x, v0.y - v1.y, v0.z - v1.z);
  68. }
  69. // Additive inverse
  70. Vec3d operator-(const Vec3d& v)
  71. {
  72.     return Vec3d(-v.x, -v.y, -v.z);
  73. }
  74. // Scalar multiply
  75. Vec3d operator*(const Vec3d& v, double d)
  76. {
  77.     return Vec3d(v.x * d, v.y * d, v.z * d);
  78. }
  79. // Scalar multiply
  80. Vec3d operator*(double d, const Vec3d& v)
  81. {
  82.     return Vec3d(v.x * d, v.y * d, v.z * d);
  83. }
  84. ostream& operator<<(ostream& o, const Vec3d& v)
  85. {
  86.     return o << v.x << ' ' << v.y << ' ' << v.z;
  87. }
  88. // The StateVector object just contains the position and velocity
  89. // in 3D.
  90. class StateVector
  91. {
  92. public:
  93.     // Construct a new StateVector from an array of 6 doubles
  94.     // (as used by SPICE.)
  95.     StateVector(const double v[]) :
  96.         position(v), velocity(v + 3) {};
  97.     Vec3d position;
  98.     Vec3d velocity;
  99. };
  100. // QuotedString is used read a double quoted string from a C++ input
  101. // stream.
  102. class QuotedString
  103. {
  104. public:
  105.     string value;
  106. };
  107. istream& operator>>(istream& in, QuotedString& qs)
  108. {
  109.     char c = '';
  110.     in >> c;
  111.     while (in && isspace(c))
  112.     {
  113.         in >> c;
  114.     }
  115.     if (c != '"')
  116.     {
  117.         in.setstate(ios::failbit);
  118.         return in;
  119.     }
  120.     string s;
  121.     
  122.     in >> c;
  123.     while (in && c != '"')
  124.     {
  125.         s += c;
  126.         in.get(c);
  127.     }
  128.     if (in)
  129.         qs.value = s;
  130.     return in;
  131. }
  132. // QuoteStringList is used to read a list of double quoted strings from
  133. // a C++ input stream. The string list must be enclosed by square brackets.
  134. class QuotedStringList
  135. {
  136. public:
  137.     vector<string> value;
  138. };
  139. istream& operator>>(istream& in, QuotedStringList& qsl)
  140. {
  141.     qsl.value.clear();
  142.     char c = '';
  143.     in >> c;
  144.     if (c != '[')
  145.     {
  146.         in.setstate(ios::failbit);
  147.         return in;
  148.     }
  149.     in >> c;
  150.     while (in && c == '"')
  151.     {
  152.         in.unget();
  153.         QuotedString qs;
  154.         if (in >> qs)
  155.         {
  156.             qsl.value.push_back(qs.value);
  157.             in >> c;
  158.         }
  159.     }
  160.     if (c != ']')
  161.         in.setstate(ios::failbit);
  162.     return in;
  163. }
  164. static Vec3d cubicInterpolate(const Vec3d& p0, const Vec3d& v0,
  165.                               const Vec3d& p1, const Vec3d& v1,
  166.                               double t)
  167. {
  168.     return p0 + (((2.0 * (p0 - p1) + v1 + v0) * (t * t * t)) +
  169.                  ((3.0 * (p1 - p0) - 2.0 * v0 - v1) * (t * t)) +
  170.                  (v0 * t));
  171. }
  172. double et2jd(double et)
  173. {
  174.     return J2000 + et / 86400.0;
  175. }
  176. string etToString(double et)
  177. {
  178.     char buf[200];
  179.     et2utc_c(et, "C", 3, sizeof(buf), buf);
  180.     return string(buf);
  181. }
  182. void printRecord(ostream& out, double et, const StateVector& state)
  183. {
  184.     // < 1 second error around J2000
  185.     out << setprecision(12) << et2jd(et) << " ";
  186.     // < 1 meter error at 1 billion km
  187.     out << setprecision(12) << state.position << " ";
  188.     // < 0.1 mm/s error at 10 km/s
  189.     out << setprecision(8) << state.velocity << endl;
  190. }
  191. StateVector getStateVector(SpiceInt targetID,
  192.                            double et,
  193.                            const string& frameName,
  194.                            SpiceInt observerID)
  195. {
  196.     double stateVector[6];
  197.     double lightTime = 0.0;
  198.     spkgeo_c(targetID, et, frameName.c_str(), observerID,
  199.              stateVector, &lightTime);
  200.     return StateVector(stateVector);
  201. }
  202. bool convertSpkToXyzv(const Configuration& config,
  203.                       ostream& out)
  204. {
  205.     // Load the required SPICE kernels
  206.     for (vector<string>::const_iterator iter = config.kernelList.begin();
  207.          iter != config.kernelList.end(); iter++)
  208.     {
  209.         string pathname = config.kernelDirectory + "/" + *iter;
  210.         furnsh_c(pathname.c_str());
  211.     }
  212.     
  213.     double startET = 0.0;
  214.     double endET = 0.0;
  215.     str2et_c(config.startDate.c_str(), &startET);
  216.     str2et_c(config.endDate.c_str(),   &endET);
  217.     SpiceBoolean found = SPICEFALSE;
  218.     SpiceInt observerID = 0;
  219.     SpiceInt targetID = 0;
  220.     bodn2c_c(config.observerName.c_str(), &observerID, &found);
  221.     if (!found)
  222.     {
  223.         cerr << "Observer object " << config.observerName << " not found. Aborting.n";
  224.         return false;
  225.     }
  226.     bodn2c_c(config.targetName.c_str(), &targetID, &found);
  227.     if (!found)
  228.     {
  229.         cerr << "Target object " << config.targetName << " not found. Aborting.n";
  230.         return false;
  231.     }
  232.     StateVector lastState = getStateVector(targetID, startET, config.frameName, observerID);
  233.     double et = startET;
  234.     printRecord(out, et, lastState);
  235.     while (et + config.minStepSize < endET)
  236.     {
  237.         double dt = config.minStepSize;
  238.         StateVector s0 = getStateVector(targetID, et + dt, config.frameName, observerID);
  239.         double et0 = et + dt;
  240.         while (dt < config.maxStepSize && et + dt * 2.0 < endET)
  241.         {
  242.             dt *= 2.0;
  243.             StateVector s1 = getStateVector(targetID, et + dt, config.frameName, observerID);
  244.             double et1 = et + dt;
  245.             Vec3d pInterp = cubicInterpolate(lastState.position,
  246.                                              lastState.velocity * dt,
  247.                                              s1.position,
  248.                                              s1.velocity * dt,
  249.                                              0.5);
  250.             
  251.             double positionError = (pInterp - s0.position).length();
  252.             if (positionError > config.tolerance || dt > config.maxStepSize)
  253.                 break;
  254.             s0 = s1;
  255.             et0 = et1;
  256.         }
  257.         lastState = s0;
  258.         et = et0;
  259.         printRecord(out, et0, lastState);
  260.     }
  261.     lastState = getStateVector(targetID, endET, config.frameName, observerID);
  262.     printRecord(out, endET, lastState);
  263.     return true;
  264. }
  265. // Dump information about the xyzv file in the comment header
  266. void writeCommentHeader(const Configuration& config,
  267.                         ostream& out)
  268. {
  269.     SpiceInt observerID = 0;
  270.     SpiceInt targetID = 0;
  271.     SpiceBoolean found = SPICEFALSE;
  272.     bodn2c_c(config.observerName.c_str(), &observerID, &found);
  273.     if (!found)
  274.         return;
  275.     bodn2c_c(config.targetName.c_str(), &targetID, &found);
  276.     if (!found)
  277.         return;
  278.     out << "# Celestia xyzv file generated by spice2xyzvn";
  279.     out << "#n";
  280.     time_t now = 0;
  281.     time(&now);
  282.     out << "# Creation date: " << ctime(&now);
  283.     out << "#n";
  284.     out << "# SPICE kernel files used:n";
  285.     for (vector<string>::const_iterator iter = config.kernelList.begin();
  286.          iter != config.kernelList.end(); iter++)
  287.     {
  288.         out << "#   " << *iter << endl;
  289.     }
  290.     out << "#n";
  291.     out << "# Start date: " << config.startDate << endl;
  292.     out << "# End date:   " << config.endDate << endl;
  293.     out << "# Observer:   " << config.observerName << " (" << observerID << ")" << endl;
  294.     out << "# Target:     " << config.targetName << " (" << targetID << ")" << endl;
  295.     out << "# Frame:      " << config.frameName << endl;
  296.     out << "#n";
  297.     out << "# Min step size: " << config.minStepSize << " s" << endl;
  298.     out << "# Max step size: " << config.maxStepSize << " s" << endl;
  299.     out << "# Tolerance:     " << config.tolerance << " km" << endl;
  300.     out << "#n";
  301.     out << "# Records are <jd> <x> <y> <z> <vel x> <vel y> <vel z>n";
  302.     out << "#   Time is a TDB Julian daten";
  303.     out << "#   Position in kmn";
  304.     out << "#   Velocity in km/secn";
  305.     out << endl;
  306. }
  307. bool readConfig(istream& in, Configuration& config)
  308. {
  309.     QuotedString qs;
  310.     while (in && !in.eof())
  311.     {
  312.         string key;
  313.         in >> key;
  314.         if (in.eof())
  315.             return true;
  316.         if (!in.eof())
  317.         {
  318.             if (key == "StartDate")
  319.             {
  320.                 if (in >> qs)
  321.                     config.startDate = qs.value;
  322.             }
  323.             else if (key == "EndDate")
  324.             {
  325.                 if (in >> qs)
  326.                     config.endDate = qs.value;
  327.             }
  328.             else if (key == "Observer")
  329.             {
  330.                 if (in >> qs)
  331.                     config.observerName = qs.value;
  332.             }
  333.             else if (key == "Target")
  334.             {
  335.                 if (in >> qs)
  336.                     config.targetName = qs.value;
  337.             }
  338.             else if (key == "Frame")
  339.             {
  340.                 if (in >> qs)
  341.                     config.frameName = qs.value;
  342.             }
  343.             else if (key == "MinStep")
  344.             {
  345.                 in >> config.minStepSize;
  346.             }
  347.             else if (key == "MaxStep")
  348.             {
  349.                 in >> config.maxStepSize;
  350.             }
  351.             else if (key == "Tolerance")
  352.             {
  353.                 in >> config.tolerance;
  354.             }
  355.             else if (key == "KernelDirectory")
  356.             {
  357.                 if (in >> qs)
  358.                     config.kernelDirectory = qs.value;
  359.             }
  360.             else if (key == "Kernels")
  361.             {
  362.                 QuotedStringList qsl;
  363.                 if (in >> qsl)
  364.                 {
  365.                     config.kernelList = qsl.value;
  366.                 }
  367.             }
  368.         }
  369.     }
  370.     return in.good();
  371. }
  372. int main(int argc, char* argv[])
  373. {
  374.     // Load the leap second kernel
  375.     furnsh_c("naif0008.tls");
  376.     if (argc < 2)
  377.     {
  378.         cerr << "Usage: spice2xyzv <config filename> [output filename]n";
  379.         return 1;
  380.     }
  381.     ifstream configFile(argv[1]);
  382.     if (!configFile)
  383.     {
  384.         cerr << "Error opening configuration file.n";
  385.         return 1;
  386.     }
  387.     
  388.     Configuration config;
  389.     if (!readConfig(configFile, config))
  390.     {
  391.         cerr << "Error in configuration file.n";
  392.         return 1;
  393.     }
  394.     // Check that all required parameters are present.
  395.     if (config.startDate.empty())
  396.     {
  397.         cerr << "StartDate missing from configuration file.n";
  398.         return 1;
  399.     }
  400.     if (config.endDate.empty())
  401.     {
  402.         cerr << "EndDate missing from configuration file.n";
  403.         return 1;
  404.     }
  405.     if (config.targetName.empty())
  406.     {
  407.         cerr << "Target missing from configuration file.n";
  408.         return 1;
  409.     }
  410.     if (config.observerName.empty())
  411.     {
  412.         cerr << "Observer missing from configuration file.n";
  413.         return 1;
  414.     }
  415.     if (config.kernelList.empty())
  416.     {
  417.         cerr << "Kernels missing from configuration file.n";
  418.         return 1;
  419.     }
  420.     writeCommentHeader(config, cout);
  421.     convertSpkToXyzv(config, cout);
  422.     return 0;
  423. }