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

OpenGL

开发平台:

Visual C++

  1. // jpleph.cpp
  2. //
  3. // Copyright (C) 2004, 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. // Load JPL's DE200, DE405, and DE406 ephemerides and compute planet
  11. // positions.
  12. #include <fstream>
  13. #include <iomanip>
  14. #include <cstdio>
  15. #include <cassert>
  16. #include <celutil/bytes.h>
  17. #include <celutil/basictypes.h>
  18. #include "jpleph.h"
  19. using namespace std;
  20. static const unsigned int DE200RecordSize    =  826;
  21. static const unsigned int DE405RecordSize    = 1018;
  22. static const unsigned int DE406RecordSize    =  728;
  23. static const unsigned int NConstants         =  400;
  24. static const unsigned int ConstantNameLength =  6;
  25. static const unsigned int MaxChebyshevCoeffs = 32;
  26. static const int LabelSize = 84;
  27. // Read a big-endian 32-bit unsigned integer
  28. static int32 readUint(istream& in)
  29. {
  30.     int32 ret;
  31.     in.read((char*) &ret, sizeof(int32));
  32.     BE_TO_CPU_INT32(ret, ret);
  33.     return (uint32) ret;
  34. }
  35. // Read a big-endian 64-bit IEEE double--if the native double format isn't
  36. // IEEE 754, there will be troubles.
  37. static double readDouble(istream& in)
  38. {
  39.     double d;
  40.     in.read((char*) &d, sizeof(double));
  41.     BE_TO_CPU_DOUBLE(d, d);
  42.     return d;
  43. }
  44. JPLEphRecord::~JPLEphRecord()
  45. {
  46.     if (coeffs != NULL)
  47. delete coeffs;
  48. }
  49. JPLEphemeris::JPLEphemeris()
  50. {
  51. }
  52. JPLEphemeris::~JPLEphemeris()
  53. {
  54. }
  55. unsigned int JPLEphemeris::getDENumber() const
  56. {
  57.     return DENum;
  58. }
  59. double JPLEphemeris::getStartDate() const
  60. {
  61.     return startDate;
  62. }
  63. double JPLEphemeris::getEndDate() const
  64. {
  65.     return endDate;
  66. }
  67. // Return the position of an object relative to the solar system barycenter
  68. // or the Earth (in the case of the Moon) at a specified TDB Julian date tjd.
  69. // If tjd is outside the span covered by the ephemeris it is clamped to a
  70. // valid time.
  71. Point3d JPLEphemeris::getPlanetPosition(JPLEphemItem planet, double tjd) const
  72. {
  73.     // Solar system barycenter is the origin
  74.     if (planet == JPLEph_SSB)
  75.     {
  76.         return Point3d(0.0, 0.0, 0.0);
  77.     }
  78.     // The position of the Earth must be computed from the positions of the
  79.     // Earth-Moon barycenter and Moon
  80.     if (planet == JPLEph_Earth)
  81.     {
  82.         Point3d embPos = getPlanetPosition(JPLEph_EarthMoonBary, tjd);
  83.         // Get the geocentric position of the Moon
  84.         Point3d moonPos = getPlanetPosition(JPLEph_Moon, tjd);
  85.         return embPos - Vec3d(moonPos.x, moonPos.y, moonPos.z) * (1.0 / (earthMoonMassRatio + 1.0));
  86.     }
  87.     // Clamp time to [ startDate, endDate ]
  88.     if (tjd < startDate)
  89.         tjd = startDate;
  90.     else if (tjd > endDate)
  91. tjd = endDate;
  92.     // recNo is always >= 0:
  93.     unsigned int recNo = (unsigned int) ((tjd - startDate) / daysPerInterval);
  94.     // Make sure we don't go past the end of the array if t == endDate
  95.     if (recNo >= records.size())
  96.         recNo = records.size() - 1;
  97.     const JPLEphRecord* rec = &records[recNo];
  98.     assert(coeffInfo[planet].nGranules >= 1);
  99.     assert(coeffInfo[planet].nGranules <= 32);
  100.     assert(coeffInfo[planet].nCoeffs <= MaxChebyshevCoeffs);
  101.     // u is the normalized time (in [-1, 1]) for interpolating
  102.     // coeffs is a pointer to the Chebyshev coefficients
  103.     double u = 0.0;
  104.     double* coeffs = NULL;
  105.     // nGranules is unsigned int so it will be compared against FFFFFFFF:
  106.     if (coeffInfo[planet].nGranules == (unsigned int) -1)
  107.     {
  108.      coeffs = rec->coeffs + coeffInfo[planet].offset;
  109.      u = 2.0 * (tjd - rec->t0) / daysPerInterval - 1.0;
  110.     }
  111.     else
  112.     {
  113. double daysPerGranule = daysPerInterval / coeffInfo[planet].nGranules;
  114. int granule = (int) ((tjd - rec->t0) / daysPerGranule);
  115. double granuleStartDate = rec->t0 + daysPerGranule * (double) granule;
  116. coeffs = rec->coeffs + coeffInfo[planet].offset +
  117.             granule * coeffInfo[planet].nCoeffs * 3;
  118. u = 2.0 * (tjd - granuleStartDate) / daysPerGranule - 1.0;
  119.     }
  120.     // Evaluate the Chebyshev polynomials
  121.     double sum[3];
  122.     double cc[MaxChebyshevCoeffs];
  123.     unsigned int nCoeffs = coeffInfo[planet].nCoeffs;
  124.     for (int i = 0; i < 3; i++)
  125.     {
  126.      cc[0] = 1.0;
  127.      cc[1] = u;
  128.      sum[i] = coeffs[i * nCoeffs] + coeffs[i * nCoeffs + 1] * u;
  129.      for (unsigned int j = 2; j < nCoeffs; j++)
  130.      {
  131.             cc[j] = 2.0 * u * cc[j - 1] - cc[j - 2];
  132.             sum[i] += coeffs[i * nCoeffs + j] * cc[j];
  133.         }
  134.     }
  135.     return Point3d(sum[0], sum[1], sum[2]);
  136. }
  137. JPLEphemeris* JPLEphemeris::load(istream& in)
  138. {
  139.     JPLEphemeris* eph = NULL;
  140.     // Skip past three header labels
  141.     in.ignore(LabelSize * 3);
  142.     if (!in.good())
  143.         return NULL;
  144.     // Skip past the constant names
  145.     in.ignore(NConstants * ConstantNameLength);
  146.     if (!in.good())
  147.         return NULL;
  148.     eph = new JPLEphemeris();
  149.     if (eph == NULL)
  150.         return NULL;
  151.     // Read the start time, end time, and time interval
  152.     eph->startDate = readDouble(in);
  153.     eph->endDate = readDouble(in);
  154.     eph->daysPerInterval = readDouble(in);
  155.     if (!in.good())
  156.     {
  157.         delete eph;
  158.         return NULL;
  159.     }
  160.     // Number of constants with valid values; not useful for us
  161.     (void) readUint(in);
  162.     eph->au = readDouble(in);     // kilometers per astronomical unit
  163.     eph->earthMoonMassRatio = readDouble(in);
  164.     // Read the coefficient information for each item in the ephemeris
  165.     unsigned int i;
  166.     for (i = 0; i < JPLEph_NItems; i++)
  167.     {
  168.         eph->coeffInfo[i].offset = readUint(in) - 3;
  169.         eph->coeffInfo[i].nCoeffs = readUint(in);
  170.         eph->coeffInfo[i].nGranules = readUint(in);
  171.     }
  172.     if (!in.good())
  173.     {
  174.         delete eph;
  175.         return NULL;
  176.     }
  177.     eph->DENum = readUint(in);
  178.     switch (eph->DENum)
  179.     {
  180.     case 200:
  181.         eph->recordSize = DE200RecordSize;
  182.         break;
  183.     case 405:
  184.         eph->recordSize = DE405RecordSize;
  185.         break;
  186.     case 406:
  187.         eph->recordSize = DE406RecordSize;
  188.         break;
  189.     default:
  190.         delete eph;
  191.         return NULL;
  192.     }
  193.     eph->librationCoeffInfo.offset        = readUint(in);
  194.     eph->librationCoeffInfo.nCoeffs       = readUint(in);
  195.     eph->librationCoeffInfo.nGranules     = readUint(in);
  196.     if (!in.good())
  197.     {
  198.         delete eph;
  199.         return NULL;
  200.     }
  201.     // Skip past the rest of the record
  202.     in.ignore(eph->recordSize * 8 - 2856);
  203.     // The next record contains constant values (which we don't need)
  204.     in.ignore(eph->recordSize * 8);
  205.     if (!in.good())
  206.     {
  207.         delete eph;
  208.         return NULL;
  209.     }
  210.     unsigned int nRecords = (unsigned int) ((eph->endDate - eph->startDate) /
  211.     eph->daysPerInterval);
  212.     eph->records.resize(nRecords);
  213.     for (i = 0; i < nRecords; i++)
  214.     {
  215.      eph->records[i].t0 = readDouble(in);
  216.      eph->records[i].t1 = readDouble(in);
  217.      // Allocate coefficient array for this record; the first two
  218.      // 'coefficients' are actually the start and end time (t0 and t1)
  219.      eph->records[i].coeffs = new double[eph->recordSize - 2];
  220.      for (unsigned int j = 0; j < eph->recordSize - 2; j++)
  221.          eph->records[i].coeffs[j] = readDouble(in);
  222.      // Make sure that we read this record successfully
  223.      if (!in.good())
  224.      {
  225.          delete eph;
  226.          return NULL;
  227.      }
  228.     }
  229.     return eph;
  230. }