15 #include <getSpkAbCorrState.hpp>
19 #include <nlohmann/json.hpp>
20 using json = nlohmann::json;
23 #include "Constants.h"
25 #include "EllipsoidShape.h"
26 #include "EndianSwapper.h"
28 #include "IException.h"
31 #include "Longitude.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);
84 Spice::Spice(
Pvl &lab, json isd) {
97 void Spice::csmInit(
Cube &cube,
Pvl label) {
100 NaifStatus::CheckErrors();
107 void Spice::defaultInit() {
113 m_startTime =
new iTime;
114 m_endTime =
new iTime;
115 m_cacheSize =
new SpiceDouble;
118 m_startTimePadding =
new SpiceDouble;
119 *m_startTimePadding = 0;
120 m_endTimePadding =
new SpiceDouble;
121 *m_endTimePadding = 0;
123 m_instrumentPosition =
nullptr;
124 m_instrumentRotation =
nullptr;
126 m_sunPosition =
nullptr;
127 m_bodyRotation =
nullptr;
129 m_allowDownsizing =
false;
134 m_sclkCode =
nullptr;
135 m_spkBodyCode =
nullptr;
136 m_bodyFrameCode =
nullptr;
154 void Spice::init(
Pvl &lab,
bool noTables, json isd) {
155 NaifStatus::CheckErrors();
159 m_spkCode =
new SpiceInt;
160 m_ckCode =
new SpiceInt;
161 m_ikCode =
new SpiceInt;
162 m_sclkCode =
new SpiceInt;
163 m_spkBodyCode =
new SpiceInt;
164 m_bodyFrameCode =
new SpiceInt;
166 m_naifKeywords =
new PvlObject(
"NaifKeywords");
174 *m_startTimePadding =
toDouble(kernels[
"StartPadding"][0]);
177 *m_startTimePadding = 0.0;
181 *m_endTimePadding =
toDouble(kernels[
"EndPadding"][0]);
184 *m_endTimePadding = 0.0;
188 m_usingNaif = !lab.
hasObject(
"NaifKeywords") || noTables;
199 if (kernels[
"InstrumentPointing"][0].toUpper() ==
"NADIR") {
200 QString msg =
"Falling back to ISIS generation of nadir pointing";
201 throw IException(IException::Programmer, msg, _FILEINFO_);
206 std::ostringstream kernel_pvl;
207 kernel_pvl << kernels;
210 props[
"kernels"] = kernel_pvl.str();
212 isd = ale::load(lab.
fileName().toStdString(), props.dump(),
"ale");
215 json aleNaifKeywords = isd[
"naif_keywords"];
216 m_naifKeywords =
new PvlObject(
"NaifKeywords", aleNaifKeywords);
219 load(kernels[
"LeapSecond"], noTables);
221 load(kernels[
"SpacecraftClock"], noTables);
228 load(kernels[
"TargetPosition"], noTables);
229 load(kernels[
"InstrumentPosition"], noTables);
230 load(kernels[
"InstrumentPointing"], noTables);
234 load(kernels[
"Frame"], noTables);
237 load(kernels[
"TargetAttitudeShape"], noTables);
239 load(kernels[
"Instrument"], noTables);
242 if (kernels.
hasKeyword(
"InstrumentAddendum")) {
243 load(kernels[
"InstrumentAddendum"], noTables);
247 load(kernels[
"LeapSecond"], noTables);
249 load(kernels[
"SpacecraftClock"], noTables);
255 load(kernels[
"Extra"], noTables);
263 m_target =
new Target(
this, lab);
270 if (m_target->name().toUpper() ==
"SATURN" && m_target->shape()->name().toUpper() ==
"PLANE") {
272 load(ringPck, noTables);
276 *m_naifKeywords = lab.
findObject(
"NaifKeywords");
283 m_target =
new Target(
this, lab);
301 QString trykey =
"NaifIkCode";
302 if (kernels.
hasKeyword(
"NaifFrameCode")) trykey =
"NaifFrameCode";
303 *m_ikCode =
toInt(kernels[trykey][0]);
305 *m_spkCode = *m_ikCode / 1000;
306 *m_sclkCode = *m_spkCode;
307 *m_ckCode = *m_ikCode;
309 if (!m_target->isSky()) {
313 QString radiiKey =
"BODY" +
Isis::toString(m_target->naifBodyCode()) +
"_RADII";
314 QVariant result = m_target->naifBodyCode();
315 storeValue(
"BODY_CODE", 0, SpiceIntType, result);
316 std::vector<Distance> radii(3,
Distance());
317 radii[0] =
Distance(getDouble(radiiKey, 0), Distance::Kilometers);
318 radii[1] =
Distance(getDouble(radiiKey, 1), Distance::Kilometers);
319 radii[2] =
Distance(getDouble(radiiKey, 2), Distance::Kilometers);
321 m_target->setRadii(radii);
324 *m_spkBodyCode = m_target->naifBodyCode();
328 *m_spkCode = (int) kernels[
"NaifSpkCode"];
332 *m_ckCode = (int) kernels[
"NaifCkCode"];
336 *m_sclkCode = (int) kernels[
"NaifSclkCode"];
339 if (!m_target->isSky()) {
341 *m_spkBodyCode = (int) kernels[
"NaifSpkBodyCode"];
345 if (m_target->isSky()) {
353 if ((m_usingNaif) || (!m_naifKeywords->hasKeyword(
"BODY_FRAME_CODE"))) {
356 cidfrm_c(*m_spkBodyCode,
sizeof(frameName), &frameCode, frameName, &found);
359 QString naifTarget =
"IAU_" + m_target->name().toUpper();
360 namfrm_c(naifTarget.toLatin1().data(), &frameCode);
361 if (frameCode == 0) {
362 QString msg =
"Can not find NAIF BODY_FRAME_CODE for target ["
363 + m_target->name() +
"]";
364 throw IException(IException::Io, msg, _FILEINFO_);
368 QVariant result = (int)frameCode;
369 storeValue(
"BODY_FRAME_CODE", 0, SpiceIntType, result);
372 frameCode = getInteger(
"BODY_FRAME_CODE", 0);
376 *m_bodyFrameCode = frameCode;
386 vector<Distance> radius = m_target->radii();
387 Distance targetRadius((radius[0] + radius[2])/2.0);
389 ltState, targetRadius);
391 m_sunPosition =
new SpicePosition(10, m_target->naifBodyCode());
397 m_sunPosition->LoadCache(isd[
"sun_position"]);
398 if (m_sunPosition->cacheSize() > 3) {
399 m_sunPosition->Memcache2HermiteCache(0.01);
401 m_bodyRotation->LoadCache(isd[
"body_rotation"]);
402 m_bodyRotation->MinimizeCache(SpiceRotation::DownsizeStatus::Yes);
403 if (m_bodyRotation->cacheSize() > 5) {
404 m_bodyRotation->LoadTimeCache();
408 else if (kernels[
"TargetPosition"][0].toUpper() ==
"TABLE") {
410 m_sunPosition->LoadCache(t);
413 m_bodyRotation->LoadCache(t2);
429 if (kernels[
"InstrumentPointing"].size() == 0) {
431 "No camera pointing available",
437 if (kernels[
"InstrumentPointing"][0].toUpper() ==
"NADIR") {
438 if (m_instrumentRotation) {
439 delete m_instrumentRotation;
440 m_instrumentRotation = NULL;
443 m_instrumentRotation =
new SpiceRotation(*m_ikCode, *m_spkBodyCode);
445 else if (m_usingAle) {
446 m_instrumentRotation->LoadCache(isd[
"instrument_pointing"]);
447 m_instrumentRotation->MinimizeCache(SpiceRotation::DownsizeStatus::Yes);
448 if (m_instrumentRotation->cacheSize() > 5) {
449 m_instrumentRotation->LoadTimeCache();
452 else if (kernels[
"InstrumentPointing"][0].toUpper() ==
"TABLE") {
454 m_instrumentRotation->LoadCache(t);
458 if (kernels[
"InstrumentPosition"].size() == 0) {
460 "No instrument position available",
465 m_instrumentPosition->LoadCache(isd[
"instrument_position"]);
466 if (m_instrumentPosition->cacheSize() > 3) {
467 m_instrumentPosition->Memcache2HermiteCache(0.01);
470 else if (kernels[
"InstrumentPosition"][0].toUpper() ==
"TABLE") {
472 m_instrumentPosition->LoadCache(t);
474 NaifStatus::CheckErrors();
487 NaifStatus::CheckErrors();
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;
497 QString msg =
"Spice file does not exist [" + file.
expanded() +
"]";
498 throw IException(IException::Io, msg, _FILEINFO_);
501 furnsh_c(fileName.toLatin1().data());
502 m_kernels->push_back(key[i]);
505 NaifStatus::CheckErrors();
512 NaifStatus::CheckErrors();
514 if (m_solarLongitude != NULL) {
515 delete m_solarLongitude;
516 m_solarLongitude = NULL;
524 if (m_startTime != NULL) {
529 if (m_endTime != NULL) {
534 if (m_cacheSize != NULL) {
539 if (m_startTimePadding != NULL) {
540 delete m_startTimePadding;
541 m_startTimePadding = NULL;
544 if (m_endTimePadding != NULL) {
545 delete m_endTimePadding;
546 m_endTimePadding = NULL;
549 if (m_instrumentPosition != NULL) {
550 delete m_instrumentPosition;
551 m_instrumentPosition = NULL;
554 if (m_instrumentRotation != NULL) {
555 delete m_instrumentRotation;
556 m_instrumentRotation = NULL;
559 if (m_sunPosition != NULL) {
560 delete m_sunPosition;
561 m_sunPosition = NULL;
564 if (m_bodyRotation != NULL) {
565 delete m_bodyRotation;
566 m_bodyRotation = NULL;
569 if (m_spkCode != NULL) {
574 if (m_ckCode != NULL) {
579 if (m_ikCode != NULL) {
584 if (m_sclkCode != NULL) {
589 if (m_spkBodyCode != NULL) {
590 delete m_spkBodyCode;
591 m_spkBodyCode = NULL;
594 if (m_bodyFrameCode != NULL) {
595 delete m_bodyFrameCode;
596 m_bodyFrameCode = NULL;
599 if (m_target != NULL) {
605 for (
int i = 0; m_kernels && i < m_kernels->size(); i++) {
608 unload_c(fileName.toLatin1().data());
611 if (m_kernels != NULL) {
615 NaifStatus::CheckErrors();
650 int cacheSize,
double tol) {
651 NaifStatus::CheckErrors();
654 if (cacheSize <= 0) {
655 QString msg =
"Argument cacheSize must be greater than zero";
656 throw IException(IException::Programmer, msg, _FILEINFO_);
659 if (startTime > endTime) {
660 QString msg =
"Argument startTime must be less than or equal to endTime";
661 throw IException(IException::Programmer, msg, _FILEINFO_);
664 if (*m_cacheSize > 0) {
665 QString msg =
"A cache has already been created";
666 throw IException(IException::Programmer, msg, _FILEINFO_);
669 if (cacheSize == 1 && (*m_startTimePadding != 0 || *m_endTimePadding != 0)) {
670 QString msg =
"This instrument does not support time padding";
671 throw IException(IException::User, msg, _FILEINFO_);
675 if (getSpkAbCorrState(abcorr)) {
676 instrumentPosition()->SetAberrationCorrection(
"NONE");
679 iTime avgTime((startTime.
Et() + endTime.
Et()) / 2.0);
680 computeSolarLongitude(avgTime);
683 if (!m_bodyRotation->IsCached()) {
684 int bodyRotationCacheSize = cacheSize;
685 if (cacheSize > 2) bodyRotationCacheSize = 2;
686 m_bodyRotation->LoadCache(
687 startTime.
Et() - *m_startTimePadding,
688 endTime.
Et() + *m_endTimePadding,
689 bodyRotationCacheSize);
692 if (m_instrumentRotation->GetSource() < SpiceRotation::Memcache) {
693 if (cacheSize > 3) m_instrumentRotation->MinimizeCache(SpiceRotation::Yes);
694 m_instrumentRotation->LoadCache(
695 startTime.
Et() - *m_startTimePadding,
696 endTime.
Et() + *m_endTimePadding,
700 if (m_instrumentPosition->GetSource() < SpicePosition::Memcache) {
701 m_instrumentPosition->LoadCache(
702 startTime.
Et() - *m_startTimePadding,
703 endTime.
Et() + *m_endTimePadding,
705 if (cacheSize > 3) m_instrumentPosition->Memcache2HermiteCache(tol);
708 if (!m_sunPosition->IsCached()) {
709 int sunPositionCacheSize = cacheSize;
710 if (cacheSize > 2) sunPositionCacheSize = 2;
711 m_sunPosition->LoadCache(
712 startTime.
Et() - *m_startTimePadding,
713 endTime.
Et() + *m_endTimePadding,
714 sunPositionCacheSize);
718 *m_startTime = startTime;
719 *m_endTime = endTime;
720 *m_cacheSize = cacheSize;
724 for (
int i = 0; i < m_kernels->size(); i++) {
727 unload_c(fileName.toLatin1().data());
732 NaifStatus::CheckErrors();
743 iTime Spice::cacheStartTime()
const {
780 void Spice::setTime(
const iTime &et) {
790 if (*m_cacheSize == 0) {
791 if (m_startTime->Et() == 0.0 && m_endTime->Et() == 0.0
792 && getSpkAbCorrState(abcorr)) {
793 instrumentPosition()->SetAberrationCorrection(
"NONE");
800 m_bodyRotation->SetEphemerisTime(et.
Et());
801 m_instrumentRotation->SetEphemerisTime(et.
Et());
802 m_instrumentPosition->SetEphemerisTime(et.
Et());
803 m_sunPosition->SetEphemerisTime(et.
Et());
805 std::vector<double> uB = m_bodyRotation->ReferenceVector(m_sunPosition->Coordinate());
810 computeSolarLongitude(*m_et);
822 void Spice::instrumentPosition(
double p[3])
const {
823 instrumentBodyFixedPosition(p);
835 void Spice::instrumentBodyFixedPosition(
double p[3])
const {
837 QString msg =
"Unable to retrieve instrument's body fixed position."
838 " Spice::SetTime must be called first.";
839 throw IException(IException::Programmer, msg, _FILEINFO_);
842 std::vector<double> sB = m_bodyRotation->ReferenceVector(m_instrumentPosition->Coordinate());
853 void Spice::instrumentBodyFixedVelocity(
double v[3])
const {
855 QString msg =
"Unable to retrieve instrument's body fixed velocity."
856 " Spice::SetTime must be called first.";
857 throw IException(IException::Programmer, msg, _FILEINFO_);
860 std::vector<double> state;
861 state.push_back(m_instrumentPosition->Coordinate()[0]);
862 state.push_back(m_instrumentPosition->Coordinate()[1]);
863 state.push_back(m_instrumentPosition->Coordinate()[2]);
864 state.push_back(m_instrumentPosition->Velocity()[0]);
865 state.push_back(m_instrumentPosition->Velocity()[1]);
866 state.push_back(m_instrumentPosition->Velocity()[2]);
868 std::vector<double> vB = m_bodyRotation->ReferenceVector(state);
886 QString msg =
"Unable to retrieve the time."
887 " Spice::SetTime must be called first.";
888 throw IException(IException::Programmer, msg, _FILEINFO_);
902 void Spice::sunPosition(
double p[3])
const {
904 QString msg =
"Unable to retrieve sun's position."
905 " Spice::SetTime must be called first.";
906 throw IException(IException::Programmer, msg, _FILEINFO_);
918 double Spice::targetCenterDistance()
const {
919 std::vector<double> sB = m_bodyRotation->ReferenceVector(m_instrumentPosition->Coordinate());
920 return sqrt(pow(sB[0], 2) + pow(sB[1], 2) + pow(sB[2], 2));
931 for (
int i = 0; i < 3; i++)
932 r[i] =m_target->radii()[i];
941 SpiceInt Spice::naifBodyCode()
const {
942 return (
int) m_target->naifBodyCode();
950 SpiceInt Spice::naifSpkCode()
const {
959 SpiceInt Spice::naifCkCode()
const {
968 SpiceInt Spice::naifIkCode()
const {
978 SpiceInt Spice::naifSclkCode()
const {
989 SpiceInt Spice::naifBodyFrameCode()
const {
990 return *m_bodyFrameCode;
999 return *m_naifKeywords;
1009 double Spice::resolution() {
1025 SpiceInt Spice::getInteger(
const QString &key,
int index) {
1026 return readValue(key, SpiceIntType, index).toInt();
1039 SpiceDouble Spice::getDouble(
const QString &key,
int index) {
1040 return readValue(key, SpiceDoubleType, index).toDouble();
1053 iTime Spice::getClockTime(QString clockValue,
int sclkCode,
bool clockTicks) {
1054 if (sclkCode == -1) {
1055 sclkCode = naifSclkCode();
1060 QString key =
"CLOCK_ET_" +
Isis::toString(sclkCode) +
"_" + clockValue;
1061 QVariant storedClockTime = getStoredResult(key, SpiceDoubleType);
1063 if (storedClockTime.isNull()) {
1064 SpiceDouble timeOutput;
1065 NaifStatus::CheckErrors();
1067 sct2e_c(sclkCode, (SpiceDouble) clockValue.toDouble(), &timeOutput);
1070 scs2e_c(sclkCode, clockValue.toLatin1().data(), &timeOutput);
1072 NaifStatus::CheckErrors();
1073 storedClockTime = timeOutput;
1074 storeResult(key, SpiceDoubleType, timeOutput);
1077 result = storedClockTime.toDouble();
1096 if (m_usingNaif && !m_usingAle) {
1097 NaifStatus::CheckErrors();
1100 SpiceBoolean found =
false;
1104 SpiceInt numValuesRead;
1106 if (type == SpiceDoubleType) {
1107 SpiceDouble kernelValue;
1108 gdpool_c(key.toLatin1().data(), (SpiceInt)index, 1,
1109 &numValuesRead, &kernelValue, &found);
1112 result = kernelValue;
1114 else if (type == SpiceStringType) {
1115 char kernelValue[512];
1116 gcpool_c(key.toLatin1().data(), (SpiceInt)index, 1,
sizeof(kernelValue),
1117 &numValuesRead, kernelValue, &found);
1120 result = kernelValue;
1122 else if (type == SpiceIntType) {
1123 SpiceInt kernelValue;
1124 gipool_c(key.toLatin1().data(), (SpiceInt)index, 1, &numValuesRead,
1125 &kernelValue, &found);
1128 result = (int)kernelValue;
1132 QString msg =
"Can not find [" + key +
"] in text kernels";
1133 throw IException(IException::Io, msg, _FILEINFO_);
1136 storeValue(key, index, type, result);
1137 NaifStatus::CheckErrors();
1141 result = readStoredValue(key, type, index);
1143 if (result.isNull()) {
1144 QString msg =
"The camera is requesting spice data [" + key +
"] that "
1145 "was not attached, please re-run spiceinit";
1146 throw IException(IException::Unknown, msg, _FILEINFO_);
1154 void Spice::storeResult(QString name, SpiceValueType type, QVariant value) {
1155 if (type == SpiceDoubleType) {
1158 double doubleVal = value.toDouble();
1159 doubleVal = swapper.Double(&doubleVal);
1160 QByteArray byteCode((
char *) &doubleVal,
sizeof(
double));
1162 type = SpiceByteCodeType;
1165 storeValue(name +
"_COMPUTED", 0, type, value);
1169 QVariant Spice::getStoredResult(QString name, SpiceValueType type) {
1170 bool wasDouble =
false;
1172 if (type == SpiceDoubleType) {
1174 type = SpiceByteCodeType;
1177 QVariant stored = readStoredValue(name +
"_COMPUTED", type, 0);
1179 if (wasDouble && !stored.isNull()) {
1180 EndianSwapper swapper(
"LSB");
1181 double doubleVal = swapper.Double((
void *)QByteArray::fromHex(
1182 stored.toByteArray()).data());
1190 void Spice::storeValue(QString key,
int index, SpiceValueType type,
1192 if (!m_naifKeywords->hasKeyword(key)) {
1193 m_naifKeywords->addKeyword(PvlKeyword(key));
1196 PvlKeyword &storedKey = m_naifKeywords->findKeyword(key);
1198 while(index >= storedKey.size()) {
1199 storedKey.addValue(
"");
1202 if (type == SpiceByteCodeType) {
1203 storedKey[index] = QString(value.toByteArray().toHex().data());
1205 else if (type == SpiceStringType) {
1206 storedKey[index] = value.toString();
1208 else if (type == SpiceDoubleType) {
1209 storedKey[index] =
toString(value.toDouble());
1211 else if (type == SpiceIntType) {
1212 storedKey[index] =
toString(value.toInt());
1215 QString msg =
"Unable to store variant in labels for key [" + key +
"]";
1216 throw IException(IException::Unknown, msg, _FILEINFO_);
1221 QVariant Spice::readStoredValue(QString key, SpiceValueType type,
1226 if (m_naifKeywords->hasKeyword(key) && (!m_usingNaif || m_usingAle)) {
1227 PvlKeyword &storedKeyword = m_naifKeywords->findKeyword(key);
1230 if (type == SpiceDoubleType) {
1231 result =
toDouble(storedKeyword[index]);
1233 else if (type == SpiceStringType) {
1234 result = storedKeyword[index];
1236 else if (type == SpiceByteCodeType || SpiceStringType) {
1237 result = storedKeyword[index].toLatin1();
1239 else if (type == SpiceIntType) {
1240 result =
toInt(storedKeyword[index]);
1243 catch(IException &) {
1261 QString Spice::getString(
const QString &key,
int index) {
1262 return readValue(key, SpiceStringType, index).toString();
1278 void Spice::subSpacecraftPoint(
double &lat,
double &lon) {
1279 NaifStatus::CheckErrors();
1282 QString msg =
"Unable to retrieve subspacecraft position."
1283 " Spice::SetTime must be called first.";
1284 throw IException(IException::Programmer, msg, _FILEINFO_);
1287 SpiceDouble usB[3], dist;
1288 std::vector<double> vsB = m_bodyRotation->ReferenceVector(m_instrumentPosition->Coordinate());
1293 unorm_c(sB, usB, &dist);
1295 std::vector<Distance> radii = target()->radii();
1296 SpiceDouble a = radii[0].kilometers();
1297 SpiceDouble b = radii[1].kilometers();
1298 SpiceDouble c = radii[2].kilometers();
1300 SpiceDouble originB[3];
1301 originB[0] = originB[1] = originB[2] = 0.0;
1304 SpiceDouble subB[3];
1306 surfpt_c(originB, usB, a, b, c, subB, &found);
1308 SpiceDouble mylon, mylat;
1309 reclat_c(subB, &a, &mylon, &mylat);
1310 lat = mylat * 180.0 /
PI;
1311 lon = mylon * 180.0 /
PI;
1312 if (lon < 0.0) lon += 360.0;
1314 NaifStatus::CheckErrors();
1329 void Spice::subSolarPoint(
double &lat,
double &lon) {
1330 NaifStatus::CheckErrors();
1333 QString msg =
"Unable to retrieve subsolar point."
1334 " Spice::SetTime must be called first.";
1335 throw IException(IException::Programmer, msg, _FILEINFO_);
1338 SpiceDouble uuB[3], dist;
1339 unorm_c(m_uB, uuB, &dist);
1340 std::vector<Distance> radii = target()->radii();
1342 SpiceDouble a = radii[0].kilometers();
1343 SpiceDouble b = radii[1].kilometers();
1344 SpiceDouble c = radii[2].kilometers();
1346 SpiceDouble originB[3];
1347 originB[0] = originB[1] = originB[2] = 0.0;
1350 SpiceDouble subB[3];
1351 surfpt_c(originB, uuB, a, b, c, subB, &found);
1353 SpiceDouble mylon, mylat;
1354 reclat_c(subB, &a, &mylon, &mylat);
1356 lat = mylat * 180.0 /
PI;
1357 lon = mylon * 180.0 /
PI;
1358 if (lon < 0.0) lon += 360.0;
1359 NaifStatus::CheckErrors();
1378 QString Spice::targetName()
const {
1379 return m_target->
name();
1383 double Spice::sunToBodyDist()
const {
1384 std::vector<double> sunPosition = m_sunPosition->Coordinate();
1385 std::vector<double> bodyRotation = m_bodyRotation->Matrix();
1387 double sunPosFromTarget[3];
1388 mxv_c(&bodyRotation[0], &sunPosition[0], sunPosFromTarget);
1390 return vnorm_c(sunPosFromTarget);
1400 void Spice::computeSolarLongitude(
iTime et) {
1401 NaifStatus::CheckErrors();
1403 if (m_target->isSky()) {
1408 if (m_usingAle || !m_usingNaif) {
1409 double og_time = m_bodyRotation->EphemerisTime();
1410 m_bodyRotation->SetEphemerisTime(et.
Et());
1411 m_sunPosition->SetEphemerisTime(et.
Et());
1413 std::vector<double> bodyRotMat = m_bodyRotation->Matrix();
1414 std::vector<double> sunPos = m_sunPosition->Coordinate();
1415 std::vector<double> sunVel = m_sunPosition->Velocity();
1418 ucrss_c(&sunPos[0], &sunVel[0], sunAv);
1421 for (
int i = 0; i < 3; i++) {
1422 npole[i] = bodyRotMat[6+i];
1425 double x[3], y[3], z[3];
1427 ucrss_c(npole, z, x);
1431 for (
int i = 0; i < 3; i++) {
1438 mxv_c(trans, &sunPos[0], pos);
1440 double radius, ls, lat;
1441 reclat_c(pos, &radius, &ls, &lat);
1445 NaifStatus::CheckErrors();
1446 m_bodyRotation->SetEphemerisTime(og_time);
1447 m_sunPosition->SetEphemerisTime(og_time);
1451 if (m_bodyRotation->IsCached())
return;
1453 double tipm[3][3], npole[3];
1458 cidfrm_c(*m_spkBodyCode,
sizeof(frameName), &frameCode, frameName, &found);
1461 pxform_c(
"J2000", frameName, et.
Et(), tipm);
1464 tipbod_c(
"J2000", *m_spkBodyCode, et.
Et(), tipm);
1467 for (
int i = 0; i < 3; i++) {
1468 npole[i] = tipm[2][i];
1471 double state[6], lt;
1472 spkez_c(*m_spkBodyCode, et.
Et(),
"J2000",
"NONE", 10, state, <);
1475 ucrss_c(state, &state[3], uavel);
1477 double x[3], y[3], z[3];
1479 ucrss_c(npole, z, x);
1483 for (
int i = 0; i < 3; i++) {
1489 spkez_c(10, et.
Et(),
"J2000",
"LT+S", *m_spkBodyCode, state, <);
1492 mxv_c(trans, state, pos);
1494 double radius, ls, lat;
1495 reclat_c(pos, &radius, &ls, &lat);
1499 NaifStatus::CheckErrors();
1511 computeSolarLongitude(*m_et);
1512 return *m_solarLongitude;
1526 bool Spice::hasKernels(
Pvl &lab) {
1530 std::vector<string> keywords;
1531 keywords.push_back(
"TargetPosition");
1533 if (kernels.
hasKeyword(
"SpacecraftPosition")) {
1534 keywords.push_back(
"SpacecraftPosition");
1537 keywords.push_back(
"InstrumentPosition");
1540 if (kernels.
hasKeyword(
"SpacecraftPointing")) {
1541 keywords.push_back(
"SpacecraftPointing");
1544 keywords.push_back(
"InstrumentPointing");
1548 keywords.push_back(
"Frame");
1552 keywords.push_back(
"Extra");
1556 for (
int ikey = 0; ikey < (int) keywords.size(); ikey++) {
1557 key = kernels[ikey];
1559 for (
int i = 0; i < key.
size(); i++) {
1560 if (key[i] ==
"")
return false;
1561 if (key[i].toUpper() ==
"NULL")
return false;
1562 if (key[i].toUpper() ==
"NADIR")
return false;
1563 if (key[i].toUpper() ==
"TABLE")
return false;
1577 bool Spice::isTimeSet(){
1578 return !(m_et == NULL);
1590 return m_sunPosition;
1601 return m_instrumentPosition;
1612 return m_bodyRotation;
1623 return m_instrumentRotation;
1626 bool Spice::isUsingAle(){