15#include <getSpkAbCorrState.hpp>
19#include <nlohmann/json.hpp>
20using json = nlohmann::json;
25#include "EllipsoidShape.h"
26#include "EndianSwapper.h"
28#include "IException.h"
32#include "LightTimeCorrectionState.h"
33#include "NaifStatus.h"
34#include "ShapeModel.h"
35#include "SpacecraftPosition.h"
66 if (cube.
hasBlob(
"CSMState",
"String")) {
71 bool hasTables = (kernels[
"TargetPosition"][0] ==
"Table");
73 init(lab, !hasTables);
188 m_usingNaif = !lab.hasObject(
"NaifKeywords") || noTables;
199 std::ostringstream kernel_pvl;
200 kernel_pvl << kernels;
203 if (kernels[
"InstrumentPointing"][0].toUpper() ==
"NADIR") {
204 props[
"nadir"] =
true;
207 props[
"kernels"] = kernel_pvl.str();
209 isd = ale::load(lab.fileName().toStdString(), props.dump(),
"ale",
false,
false,
true);
212 json aleNaifKeywords = isd[
"naif_keywords"];
216 load(kernels[
"LeapSecond"], noTables);
218 load(kernels[
"SpacecraftClock"], noTables);
225 load(kernels[
"TargetPosition"], noTables);
226 load(kernels[
"InstrumentPosition"], noTables);
227 load(kernels[
"InstrumentPointing"], noTables);
231 load(kernels[
"Frame"], noTables);
234 load(kernels[
"TargetAttitudeShape"], noTables);
236 load(kernels[
"Instrument"], noTables);
239 if (kernels.
hasKeyword(
"InstrumentAddendum")) {
240 load(kernels[
"InstrumentAddendum"], noTables);
244 load(kernels[
"LeapSecond"], noTables);
246 load(kernels[
"SpacecraftClock"], noTables);
252 load(kernels[
"Extra"], noTables);
269 load(ringPck, noTables);
298 QString trykey =
"NaifIkCode";
299 if (kernels.
hasKeyword(
"NaifFrameCode")) trykey =
"NaifFrameCode";
325 *
m_spkCode = (int) kernels[
"NaifSpkCode"];
329 *
m_ckCode = (int) kernels[
"NaifCkCode"];
353 cidfrm_c(*
m_spkBodyCode,
sizeof(frameName), &frameCode, frameName, &found);
356 QString naifTarget =
"IAU_" +
m_target->
name().toUpper();
357 namfrm_c(naifTarget.toLatin1().data(), &frameCode);
358 if (frameCode == 0) {
359 QString msg =
"Can not find NAIF BODY_FRAME_CODE for target ["
365 QVariant result = (int)frameCode;
373 QString msg =
"Unable to read BODY_FRAME_CODE from naifkeywords group";
387 ltState.checkSpkKernelsForAberrationCorrection();
390 Distance targetRadius((radius[0] + radius[2])/2.0);
392 ltState, targetRadius);
411 else if (kernels[
"TargetPosition"][0].toUpper() ==
"TABLE") {
412 Table t(
"SunPosition", lab.fileName(), lab);
415 Table t2(
"BodyRotation", lab.fileName(), lab);
417 if (t2.Label().hasKeyword(
"SolarLongitude")) {
432 if (kernels[
"InstrumentPointing"].size() == 0) {
434 "No camera pointing available",
440 if (kernels[
"InstrumentPointing"][0].toUpper() ==
"NADIR" && !isUsingAle()) {
455 else if (kernels[
"InstrumentPointing"][0].toUpper() ==
"TABLE") {
456 Table t(
"InstrumentPointing", lab.fileName(), lab);
461 if (kernels[
"InstrumentPosition"].size() == 0) {
463 "No instrument position available",
470 else if (kernels[
"InstrumentPosition"][0].toUpper() ==
"TABLE") {
471 Table t(
"InstrumentPosition", lab.fileName(), lab);
489 for (
int i = 0; i < key.
size(); i++) {
490 if (key[i] ==
"")
continue;
491 if (key[i].toUpper() ==
"NULL")
break;
492 if (key[i].toUpper() ==
"NADIR")
break;
493 if (key[i].toUpper() ==
"TABLE" && !noTables)
break;
494 if (key[i].toUpper() ==
"TABLE" && noTables)
continue;
496 if (!file.fileExists()) {
497 QString msg =
"Spice file does not exist [" + file.expanded() +
"]";
500 QString fileName = file.expanded();
501 furnsh_c(fileName.toLatin1().data());
607 QString fileName = file.expanded();
608 unload_c(fileName.toLatin1().data());
650 int cacheSize,
double tol) {
654 if (cacheSize <= 0) {
655 QString msg =
"Argument cacheSize must be greater than zero";
659 if (startTime > endTime) {
660 QString msg =
"Argument startTime must be less than or equal to endTime";
665 QString msg =
"A cache has already been created";
670 QString msg =
"This instrument does not support time padding";
675 if (getSpkAbCorrState(abcorr)) {
679 iTime avgTime((startTime.
Et() + endTime.
Et()) / 2.0);
684 int bodyRotationCacheSize = cacheSize;
685 if (cacheSize > 2) bodyRotationCacheSize = 2;
689 bodyRotationCacheSize);
709 if (aleCacheSize > 3) {
716 int sunPositionCacheSize = cacheSize;
717 if (cacheSize > 2) sunPositionCacheSize = 2;
721 sunPositionCacheSize);
731 for (
int i = 0; i <
m_kernels->size(); i++) {
733 QString fileName = file.expanded();
734 unload_c(fileName.toLatin1().data());
799 && getSpkAbCorrState(abcorr)) {
844 QString msg =
"Unable to retrieve instrument's body fixed position."
845 " Spice::SetTime must be called first.";
862 QString msg =
"Unable to retrieve instrument's body fixed velocity."
863 " Spice::SetTime must be called first.";
867 std::vector<double> state;
893 QString msg =
"Unable to retrieve the time."
894 " Spice::SetTime must be called first.";
911 QString msg =
"Unable to retrieve sun's position."
912 " Spice::SetTime must be called first.";
927 return sqrt(pow(sB[0], 2) + pow(sB[1], 2) + pow(sB[2], 2));
938 for (
int i = 0; i < 3; i++)
1061 if (sclkCode == -1) {
1067 QString key =
"CLOCK_ET_" +
Isis::toString(sclkCode) +
"_" + clockValue;
1070 if (storedClockTime.isNull()) {
1071 SpiceDouble timeOutput;
1074 sct2e_c(sclkCode, (SpiceDouble) clockValue.toDouble(), &timeOutput);
1077 scs2e_c(sclkCode, clockValue.toLatin1().data(), &timeOutput);
1080 storedClockTime = timeOutput;
1084 result = storedClockTime.toDouble();
1107 SpiceBoolean found =
false;
1111 SpiceInt numValuesRead;
1114 SpiceDouble kernelValue;
1115 gdpool_c(key.toLatin1().data(), (SpiceInt)index, 1,
1116 &numValuesRead, &kernelValue, &found);
1118 if (found && numValuesRead > 0)
1119 result = kernelValue;
1122 char kernelValue[512];
1123 gcpool_c(key.toLatin1().data(), (SpiceInt)index, 1,
sizeof(kernelValue),
1124 &numValuesRead, kernelValue, &found);
1126 if (found && numValuesRead > 0)
1127 result = kernelValue;
1130 SpiceInt kernelValue;
1131 gipool_c(key.toLatin1().data(), (SpiceInt)index, 1, &numValuesRead,
1132 &kernelValue, &found);
1134 if (found && numValuesRead > 0)
1135 result = (int)kernelValue;
1139 QString msg =
"Can not find [" + key +
"] in text kernels";
1142 else if (numValuesRead == 0){
1143 QString msg =
"Found " + key +
"] in text kernels, but no values were identified and read.";
1147 storeValue(key, index, type, result);
1152 result = readStoredValue(key, type, index);
1154 if (result.isNull()) {
1155 QString msg =
"The camera is requesting spice data [" + key +
"] that "
1156 "was not attached, please re-run spiceinit";
1165 void Spice::storeResult(QString name, SpiceValueType type, QVariant value) {
1169 double doubleVal = value.toDouble();
1170 doubleVal = swapper.Double(&doubleVal);
1171 QByteArray byteCode((
char *) &doubleVal,
sizeof(
double));
1176 storeValue(name +
"_COMPUTED", 0, type, value);
1180 QVariant Spice::getStoredResult(QString name, SpiceValueType type) {
1181 bool wasDouble =
false;
1188 QVariant stored = readStoredValue(name +
"_COMPUTED", type, 0);
1190 if (wasDouble && !stored.isNull()) {
1191 EndianSwapper swapper(
"LSB");
1192 double doubleVal = swapper.Double((
void *)QByteArray::fromHex(
1193 stored.toByteArray()).data());
1201 void Spice::storeValue(QString key,
int index, SpiceValueType type,
1209 while(index >= storedKey.size()) {
1214 storedKey[index] = QString(value.toByteArray().toHex().data());
1217 storedKey[index] = value.toString();
1220 storedKey[index] =
toString(value.toDouble());
1223 storedKey[index] =
toString(value.toInt());
1226 QString msg =
"Unable to store variant in labels for key [" + key +
"]";
1232 QVariant Spice::readStoredValue(QString key, SpiceValueType type,
1242 result =
toDouble(storedKeyword[index]);
1245 result = storedKeyword[index];
1248 result = storedKeyword[index].toLatin1();
1251 result =
toInt(storedKeyword[index]);
1254 catch(IException &e) {
1294 QString msg =
"Unable to retrieve subspacecraft position."
1295 " Spice::SetTime must be called first.";
1299 SpiceDouble usB[3], dist;
1305 unorm_c(sB, usB, &dist);
1308 SpiceDouble a =
radii[0].kilometers();
1309 SpiceDouble b =
radii[1].kilometers();
1310 SpiceDouble c =
radii[2].kilometers();
1312 SpiceDouble originB[3];
1313 originB[0] = originB[1] = originB[2] = 0.0;
1316 SpiceDouble subB[3];
1318 surfpt_c(originB, usB, a, b, c, subB, &found);
1320 SpiceDouble mylon, mylat;
1321 reclat_c(subB, &a, &mylon, &mylat);
1322 lat = mylat * 180.0 /
PI;
1323 lon = mylon * 180.0 /
PI;
1324 if (lon < 0.0) lon += 360.0;
1345 QString msg =
"Unable to retrieve subsolar point."
1346 " Spice::SetTime must be called first.";
1350 SpiceDouble uuB[3], dist;
1351 unorm_c(
m_uB, uuB, &dist);
1354 SpiceDouble a =
radii[0].kilometers();
1355 SpiceDouble b =
radii[1].kilometers();
1356 SpiceDouble c =
radii[2].kilometers();
1358 SpiceDouble originB[3];
1359 originB[0] = originB[1] = originB[2] = 0.0;
1362 SpiceDouble subB[3];
1363 surfpt_c(originB, uuB, a, b, c, subB, &found);
1365 SpiceDouble mylon, mylat;
1366 reclat_c(subB, &a, &mylon, &mylat);
1368 lat = mylat * 180.0 /
PI;
1369 lon = mylon * 180.0 /
PI;
1370 if (lon < 0.0) lon += 360.0;
1395 double Spice::sunToBodyDist()
const {
1399 double sunPosFromTarget[3];
1402 return vnorm_c(sunPosFromTarget);
1430 ucrss_c(&sunPos[0], &sunVel[0], sunAv);
1433 for (
int i = 0; i < 3; i++) {
1434 npole[i] = bodyRotMat[6+i];
1437 double x[3], y[3], z[3];
1439 ucrss_c(npole, z, x);
1443 for (
int i = 0; i < 3; i++) {
1450 mxv_c(trans, &sunPos[0], pos);
1452 double radius, ls, lat;
1453 reclat_c(pos, &radius, &ls, &lat);
1465 double tipm[3][3], npole[3];
1470 cidfrm_c(*
m_spkBodyCode,
sizeof(frameName), &frameCode, frameName, &found);
1473 pxform_c(
"J2000", frameName, et.
Et(), tipm);
1479 for (
int i = 0; i < 3; i++) {
1480 npole[i] = tipm[2][i];
1483 double state[6], lt;
1487 ucrss_c(state, &state[3], uavel);
1489 double x[3], y[3], z[3];
1491 ucrss_c(npole, z, x);
1495 for (
int i = 0; i < 3; i++) {
1504 mxv_c(trans, state, pos);
1506 double radius, ls, lat;
1507 reclat_c(pos, &radius, &ls, &lat);
1542 std::vector<string> keywords;
1543 keywords.push_back(
"TargetPosition");
1545 if (kernels.
hasKeyword(
"SpacecraftPosition")) {
1546 keywords.push_back(
"SpacecraftPosition");
1549 keywords.push_back(
"InstrumentPosition");
1552 if (kernels.
hasKeyword(
"SpacecraftPointing")) {
1553 keywords.push_back(
"SpacecraftPointing");
1556 keywords.push_back(
"InstrumentPointing");
1560 keywords.push_back(
"Frame");
1564 keywords.push_back(
"Extra");
1568 for (
int ikey = 0; ikey < (int) keywords.size(); ikey++) {
1569 key = kernels[ikey];
1571 for (
int i = 0; i < key.
size(); i++) {
1572 if (key[i] ==
"")
return false;
1573 if (key[i].toUpper() ==
"NULL")
return false;
1574 if (key[i].toUpper() ==
"NADIR")
return false;
1575 if (key[i].toUpper() ==
"TABLE")
return false;
1590 return !(
m_et == NULL);
1638 bool Spice::isUsingAle(){
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
@ Radians
Radians are generally used in mathematical equations, 0-2*PI is one circle, however these are more di...
IO Handler for Isis Cubes.
bool hasBlob(const QString &name, const QString &type)
Check to see if the cube contains a BLOB.
Pvl * label() const
Returns a pointer to the IsisLabel object associated with the cube.
Distance measurement, usually in meters.
@ Kilometers
The distance is being specified in kilometers.
File name manipulation and expansion.
@ Unknown
A type of error that cannot be classified as any of the other error types.
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
@ Programmer
This error is for when a programmer made an API call that was illegal.
@ Io
A type of error that occurred when performing an actual I/O operation.
Provides interface to user configurable Light Time correction feature.
This class is designed to encapsulate the concept of a Longitude.
Longitude force360Domain() const
This returns a longitude that is constricted to 0-360 degrees.
static void CheckErrors(bool resetNaif=true)
This method looks for any naif errors that might have occurred.
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
void addKeyword(const PvlKeyword &keyword, const InsertMode mode=Append)
Add a keyword to the container.
Contains multiple PvlContainers.
Container for cube-like labels.
A single keyword-value pair.
int size() const
Returns the number of values stored in this keyword.
void addValue(QString value, QString unit="")
Adds a value with units.
Contains Pvl Groups and Pvl Objects.
bool hasKeyword(const QString &kname, FindOptions opts) const
See if a keyword is in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within ...
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
@ Traverse
Search child objects.
PvlKeyword & findKeyword(const QString &kname, FindOptions opts)
Finds a keyword in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within this...
QString name() const
Gets the shape name.
Provides swap observer/target and improved light time correction.
virtual void setTime(const iTime &time)
Sets the ephemeris time and reads the spacecraft and sun position from the kernels at that instant in...
QString getString(const QString &key, int index=0)
This returns a value from the NAIF text pool.
virtual iTime getClockTime(QString clockValue, int sclkCode=-1, bool clockTicks=false)
This converts the spacecraft clock ticks value (clockValue) to an iTime.
SpiceDouble * m_startTimePadding
Kernels pvl group StartPadding keyword value.
Target * m_target
Target of the observation.
bool m_usingNaif
Indicates whether we are reading values from the NaifKeywords PvlObject in cube.
QVariant readValue(QString key, SpiceValueType type, int index=0)
This should be used for reading ALL text naif kernel values.
Longitude * m_solarLongitude
Body rotation solar longitude value.
bool m_usingAle
Indicate whether we are reading values from an ISD returned from ALE.
virtual Longitude solarLongitude()
Returns the solar longitude.
Spice(Cube &cube)
Constructs a Spice object and loads SPICE kernels using information from the label object.
SpiceInt * m_ikCode
Instrument kernel (IK) code.
virtual void instrumentBodyFixedVelocity(double v[3]) const
Returns the spacecraft velocity in body-fixed frame km/sec units.
SpiceRotation * m_instrumentRotation
Instrument spice rotation.
SpiceInt * m_sclkCode
Spacecraft clock correlation kernel (SCLK) code.
void csmInit(Cube &cube, Pvl label)
Initialize the Spice object for a CSMCamera.
virtual void computeSolarLongitude(iTime et)
Computes the solar longitude for the given ephemeris time.
SpicePosition * m_instrumentPosition
Instrument spice position.
bool m_allowDownsizing
Indicates whether to allow downsizing.
SpiceDouble * m_endTimePadding
Kernels pvl group EndPadding keyword value.
SpicePosition * m_sunPosition
Sun spice position.
SpiceInt * m_bodyFrameCode
Naif's BODY_FRAME_CODE value.
virtual SpiceRotation * bodyRotation() const
Accessor method for the body rotation.
virtual double targetCenterDistance() const
Calculates and returns the distance from the spacecraft to the target center.
virtual void subSolarPoint(double &lat, double &lon)
Returns the sub-solar latitude/longitude in universal coordinates (0-360 positive east,...
virtual void createCache(iTime startTime, iTime endTime, const int size, double tol)
This method creates an internal cache of spacecraft and sun positions over a specified time range.
virtual iTime cacheEndTime() const
Accessor method for the cache end time.
virtual ~Spice()
Destroys the Spice object.
void radii(Distance r[3]) const
Returns the radii of the body in km.
SpiceValueType
NAIF value primitive type.
@ SpiceByteCodeType
SpiceByteCode type.
@ SpiceIntType
SpiceInt type.
@ SpiceStringType
SpiceString type.
@ SpiceDoubleType
SpiceDouble type.
PvlObject * m_naifKeywords
NaifKeywords PvlObject from cube.
void init(Pvl &pvl, bool noTables, nlohmann::json isd=NULL)
Initialization of Spice object.
SpiceInt naifBodyCode() const
This returns the NAIF body code of the target indicated in the labels.
SpiceInt naifSpkCode() const
This returns the NAIF SPK code to use when reading from SPK kernels.
virtual void instrumentBodyFixedPosition(double p[3]) const
Returns the spacecraft position in body-fixed frame km units.
PvlObject getStoredNaifKeywords() const
This returns the PvlObject that stores all of the requested Naif data and can be a replacement for fu...
SpiceInt naifCkCode() const
This returns the NAIF CK code to use when reading from CK kernels.
virtual Target * target() const
Returns a pointer to the target object.
SpiceInt * m_spkBodyCode
Spacecraft and planet ephemeris kernel (SPK) body code.
virtual iTime time() const
Returns the ephemeris time in seconds which was used to obtain the spacecraft and sun positions.
SpiceInt * m_ckCode
Camera kernel (CK) code.
SpiceInt * m_spkCode
Spacecraft and planet ephemeris kernel (SPK) code.
bool hasKernels(Pvl &lab)
Returns true if the kernel group has kernel files.
virtual SpiceRotation * instrumentRotation() const
Accessor method for the instrument rotation.
SpiceDouble * m_cacheSize
Cache size. Note: This value is 1 for Framing cameras.
void defaultInit()
Default initialize the members of the SPICE object.
virtual SpicePosition * instrumentPosition() const
Accessor method for the instrument position.
SpiceInt naifIkCode() const
This returns the NAIF IK code to use when reading from instrument kernels.
SpiceInt naifSclkCode() const
This returns the NAIF SCLK code to use when reading from instrument kernels.
QString targetName() const
Returns the QString name of the target.
SpiceInt naifBodyFrameCode() const
This returns the NAIF body frame code.
void load(PvlKeyword &key, bool notab)
Loads/furnishes NAIF kernel(s)
SpiceDouble m_uB[3]
This contains the sun position (u) in the bodyfixed reference frame (B).
virtual iTime cacheStartTime() const
Accessor method for the cache start time.
iTime * m_endTime
Corrected end (shutter close) time of the observation.
iTime * m_et
Ephemeris time (read NAIF documentation for a detailed description)
bool isTimeSet()
Returns true if time has been initialized.
QVector< QString > * m_kernels
Vector containing kernels filenames.
SpiceRotation * m_bodyRotation
Body spice rotation.
iTime * m_startTime
Corrected start (shutter open) time of the observation.
virtual SpicePosition * sunPosition() const
Accessor method for the sun position.
SpiceDouble getDouble(const QString &key, int index=0)
This returns a value from the NAIF text pool.
SpiceInt getInteger(const QString &key, int index=0)
This returns a value from the NAIF text pool.
virtual void subSpacecraftPoint(double &lat, double &lon)
Returns the sub-spacecraft latitude/longitude in universal coordinates (0-360 positive east,...
virtual double resolution()
Virtual method that returns the pixel resolution of the sensor in meters/pix.
Obtain SPICE position information for a body.
int cacheSize() const
Get the size of the current cached positions.
void Memcache2HermiteCache(double tolerance)
This method reduces the cache for position, time and velocity to the minimum number of values needed ...
bool HasVelocity()
Return the flag indicating whether the velocity exists.
const std::vector< double > & Velocity()
Return the current J2000 velocity.
@ Memcache
Object is reading from cached table.
void LoadCache(double startTime, double endTime, int size)
Cache J2000 position over a time range.
bool IsCached() const
Is this position cached.
virtual const std::vector< double > & SetEphemerisTime(double et)
Return J2000 coordinate at given time.
Source GetSource()
Return the source of the position.
virtual const std::vector< double > & Coordinate()
Return the current J2000 position.
Obtain SPICE rotation information for a body.
std::vector< double > Matrix()
Return the full rotation TJ as a matrix.
double EphemerisTime() const
Accessor method to get current ephemeris time.
Source GetSource()
Accessor method to get the rotation source.
void LoadTimeCache()
Load the time cache.
void LoadCache(double startTime, double endTime, int size)
Cache J2000 rotation quaternion over a time range.
std::vector< double > ReferenceVector(const std::vector< double > &jVec)
Given a direction vector in J2000, return a reference frame direction.
void SetEphemerisTime(double et)
Return the J2000 to reference frame quaternion at given time.
@ Memcache
From cached table.
void MinimizeCache(DownsizeStatus status)
Set the downsize status to minimize cache.
bool IsCached() const
Checks if the cache is empty.
Class for storing Table blobs information.
This class is used to create and store valid Isis targets.
SpiceInt naifBodyCode() const
This returns the NAIF body code of the target.
void setRadii(std::vector< Distance > radii)
Sets the radii of the body.
std::vector< Distance > radii() const
Returns the radii of the body in km.
ShapeModel * shape() const
Return the shape.
bool isSky() const
Return if our target is the sky.
QString name() const
Return target name.
Parse and return pieces of a time string.
double Et() const
Returns the ephemeris time (TDB) representation of the time as a double.
This is free and unencumbered software released into the public domain.
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
int toInt(const QString &string)
Global function to convert from a string to an integer.
double toDouble(const QString &string)
Global function to convert from a string to a double.
const double PI
The mathematical constant PI.
Namespace for the standard library.