jpleph.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:7k
- // jpleph.cpp
- //
- // Copyright (C) 2004, Chris Laurel <claurel@shatters.net>
- //
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public License
- // as published by the Free Software Foundation; either version 2
- // of the License, or (at your option) any later version.
- //
- // Load JPL's DE200, DE405, and DE406 ephemerides and compute planet
- // positions.
- #include <fstream>
- #include <iomanip>
- #include <cstdio>
- #include <cassert>
- #include <celutil/bytes.h>
- #include <celutil/basictypes.h>
- #include "jpleph.h"
- using namespace std;
- static const unsigned int DE200RecordSize = 826;
- static const unsigned int DE405RecordSize = 1018;
- static const unsigned int DE406RecordSize = 728;
- static const unsigned int NConstants = 400;
- static const unsigned int ConstantNameLength = 6;
- static const unsigned int MaxChebyshevCoeffs = 32;
- static const int LabelSize = 84;
- // Read a big-endian 32-bit unsigned integer
- static int32 readUint(istream& in)
- {
- int32 ret;
- in.read((char*) &ret, sizeof(int32));
- BE_TO_CPU_INT32(ret, ret);
- return (uint32) ret;
- }
- // Read a big-endian 64-bit IEEE double--if the native double format isn't
- // IEEE 754, there will be troubles.
- static double readDouble(istream& in)
- {
- double d;
- in.read((char*) &d, sizeof(double));
- BE_TO_CPU_DOUBLE(d, d);
- return d;
- }
- JPLEphRecord::~JPLEphRecord()
- {
- if (coeffs != NULL)
- delete coeffs;
- }
- JPLEphemeris::JPLEphemeris()
- {
- }
- JPLEphemeris::~JPLEphemeris()
- {
- }
- unsigned int JPLEphemeris::getDENumber() const
- {
- return DENum;
- }
- double JPLEphemeris::getStartDate() const
- {
- return startDate;
- }
- double JPLEphemeris::getEndDate() const
- {
- return endDate;
- }
- // Return the position of an object relative to the solar system barycenter
- // or the Earth (in the case of the Moon) at a specified TDB Julian date tjd.
- // If tjd is outside the span covered by the ephemeris it is clamped to a
- // valid time.
- Point3d JPLEphemeris::getPlanetPosition(JPLEphemItem planet, double tjd) const
- {
- // Solar system barycenter is the origin
- if (planet == JPLEph_SSB)
- {
- return Point3d(0.0, 0.0, 0.0);
- }
- // The position of the Earth must be computed from the positions of the
- // Earth-Moon barycenter and Moon
- if (planet == JPLEph_Earth)
- {
- Point3d embPos = getPlanetPosition(JPLEph_EarthMoonBary, tjd);
- // Get the geocentric position of the Moon
- Point3d moonPos = getPlanetPosition(JPLEph_Moon, tjd);
- return embPos - Vec3d(moonPos.x, moonPos.y, moonPos.z) * (1.0 / (earthMoonMassRatio + 1.0));
- }
- // Clamp time to [ startDate, endDate ]
- if (tjd < startDate)
- tjd = startDate;
- else if (tjd > endDate)
- tjd = endDate;
- // recNo is always >= 0:
- unsigned int recNo = (unsigned int) ((tjd - startDate) / daysPerInterval);
- // Make sure we don't go past the end of the array if t == endDate
- if (recNo >= records.size())
- recNo = records.size() - 1;
- const JPLEphRecord* rec = &records[recNo];
- assert(coeffInfo[planet].nGranules >= 1);
- assert(coeffInfo[planet].nGranules <= 32);
- assert(coeffInfo[planet].nCoeffs <= MaxChebyshevCoeffs);
- // u is the normalized time (in [-1, 1]) for interpolating
- // coeffs is a pointer to the Chebyshev coefficients
- double u = 0.0;
- double* coeffs = NULL;
- // nGranules is unsigned int so it will be compared against FFFFFFFF:
- if (coeffInfo[planet].nGranules == (unsigned int) -1)
- {
- coeffs = rec->coeffs + coeffInfo[planet].offset;
- u = 2.0 * (tjd - rec->t0) / daysPerInterval - 1.0;
- }
- else
- {
- double daysPerGranule = daysPerInterval / coeffInfo[planet].nGranules;
- int granule = (int) ((tjd - rec->t0) / daysPerGranule);
- double granuleStartDate = rec->t0 + daysPerGranule * (double) granule;
- coeffs = rec->coeffs + coeffInfo[planet].offset +
- granule * coeffInfo[planet].nCoeffs * 3;
- u = 2.0 * (tjd - granuleStartDate) / daysPerGranule - 1.0;
- }
- // Evaluate the Chebyshev polynomials
- double sum[3];
- double cc[MaxChebyshevCoeffs];
- unsigned int nCoeffs = coeffInfo[planet].nCoeffs;
- for (int i = 0; i < 3; i++)
- {
- cc[0] = 1.0;
- cc[1] = u;
- sum[i] = coeffs[i * nCoeffs] + coeffs[i * nCoeffs + 1] * u;
- for (unsigned int j = 2; j < nCoeffs; j++)
- {
- cc[j] = 2.0 * u * cc[j - 1] - cc[j - 2];
- sum[i] += coeffs[i * nCoeffs + j] * cc[j];
- }
- }
- return Point3d(sum[0], sum[1], sum[2]);
- }
- JPLEphemeris* JPLEphemeris::load(istream& in)
- {
- JPLEphemeris* eph = NULL;
- // Skip past three header labels
- in.ignore(LabelSize * 3);
- if (!in.good())
- return NULL;
- // Skip past the constant names
- in.ignore(NConstants * ConstantNameLength);
- if (!in.good())
- return NULL;
- eph = new JPLEphemeris();
- if (eph == NULL)
- return NULL;
- // Read the start time, end time, and time interval
- eph->startDate = readDouble(in);
- eph->endDate = readDouble(in);
- eph->daysPerInterval = readDouble(in);
- if (!in.good())
- {
- delete eph;
- return NULL;
- }
- // Number of constants with valid values; not useful for us
- (void) readUint(in);
- eph->au = readDouble(in); // kilometers per astronomical unit
- eph->earthMoonMassRatio = readDouble(in);
- // Read the coefficient information for each item in the ephemeris
- unsigned int i;
- for (i = 0; i < JPLEph_NItems; i++)
- {
- eph->coeffInfo[i].offset = readUint(in) - 3;
- eph->coeffInfo[i].nCoeffs = readUint(in);
- eph->coeffInfo[i].nGranules = readUint(in);
- }
- if (!in.good())
- {
- delete eph;
- return NULL;
- }
- eph->DENum = readUint(in);
- switch (eph->DENum)
- {
- case 200:
- eph->recordSize = DE200RecordSize;
- break;
- case 405:
- eph->recordSize = DE405RecordSize;
- break;
- case 406:
- eph->recordSize = DE406RecordSize;
- break;
- default:
- delete eph;
- return NULL;
- }
- eph->librationCoeffInfo.offset = readUint(in);
- eph->librationCoeffInfo.nCoeffs = readUint(in);
- eph->librationCoeffInfo.nGranules = readUint(in);
- if (!in.good())
- {
- delete eph;
- return NULL;
- }
- // Skip past the rest of the record
- in.ignore(eph->recordSize * 8 - 2856);
- // The next record contains constant values (which we don't need)
- in.ignore(eph->recordSize * 8);
- if (!in.good())
- {
- delete eph;
- return NULL;
- }
- unsigned int nRecords = (unsigned int) ((eph->endDate - eph->startDate) /
- eph->daysPerInterval);
- eph->records.resize(nRecords);
- for (i = 0; i < nRecords; i++)
- {
- eph->records[i].t0 = readDouble(in);
- eph->records[i].t1 = readDouble(in);
- // Allocate coefficient array for this record; the first two
- // 'coefficients' are actually the start and end time (t0 and t1)
- eph->records[i].coeffs = new double[eph->recordSize - 2];
- for (unsigned int j = 0; j < eph->recordSize - 2; j++)
- eph->records[i].coeffs[j] = readDouble(in);
- // Make sure that we read this record successfully
- if (!in.good())
- {
- delete eph;
- return NULL;
- }
- }
- return eph;
- }