45 #include "getSpkAbCorrState.hpp"
75 bool hasTables = (kernels[
"TargetPosition"][0] ==
"Table");
77 init(lab, !hasTables);
86 Spice::Spice(
Cube &cube,
bool noTables) {
87 init(*cube.
label(), noTables);
103 void Spice::init(
Pvl &lab,
bool noTables) {
104 NaifStatus::CheckErrors();
110 m_target =
new Target(
this, lab);
112 m_startTime =
new iTime;
113 m_endTime =
new iTime;
114 m_cacheSize =
new SpiceDouble;
117 m_startTimePadding =
new SpiceDouble;
118 *m_startTimePadding = 0;
119 m_endTimePadding =
new SpiceDouble;
120 *m_endTimePadding = 0;
122 m_instrumentPosition = NULL;
123 m_instrumentRotation = NULL;
124 m_sunPosition = NULL;
125 m_bodyRotation = NULL;
127 m_allowDownsizing =
false;
129 m_spkCode =
new SpiceInt;
130 m_ckCode =
new SpiceInt;
131 m_ikCode =
new SpiceInt;
132 m_sclkCode =
new SpiceInt;
133 m_spkBodyCode =
new SpiceInt;
134 m_bodyFrameCode =
new SpiceInt;
136 m_naifKeywords =
new PvlObject(
"NaifKeywords");
145 *m_startTimePadding =
toDouble(kernels[
"StartPadding"][0]);
148 *m_startTimePadding = 0.0;
152 *m_endTimePadding =
toDouble(kernels[
"EndPadding"][0]);
155 *m_endTimePadding = 0.0;
158 m_usingNaif = !lab.
hasObject(
"NaifKeywords") || noTables;
165 load(kernels[
"TargetPosition"], noTables);
166 load(kernels[
"InstrumentPosition"], noTables);
167 load(kernels[
"InstrumentPointing"], noTables);
171 load(kernels[
"Frame"], noTables);
174 load(kernels[
"TargetAttitudeShape"], noTables);
176 load(kernels[
"Instrument"], noTables);
179 if (kernels.
hasKeyword(
"InstrumentAddendum")) {
180 load(kernels[
"InstrumentAddendum"], noTables);
182 load(kernels[
"LeapSecond"], noTables);
184 load(kernels[
"SpacecraftClock"], noTables);
190 load(kernels[
"Extra"], noTables);
196 if (m_target->name().toUpper() ==
"SATURN" && m_target->shape()->name().toUpper() ==
"PLANE") {
198 load(ringPck, noTables);
202 *m_naifKeywords = lab.
findObject(
"NaifKeywords");
220 QString trykey =
"NaifIkCode";
221 if (kernels.
hasKeyword(
"NaifFrameCode")) trykey =
"NaifFrameCode";
222 *m_ikCode =
toInt(kernels[trykey][0]);
224 *m_spkCode = *m_ikCode / 1000;
225 *m_sclkCode = *m_spkCode;
226 *m_ckCode = *m_ikCode;
228 if (!m_target->isSky()) {
229 QString radiiKey =
"BODY" +
toString(m_target->naifBodyCode()) +
"_RADII";
230 std::vector<Distance> radii(3,
Distance());
231 radii[0] =
Distance(getDouble(radiiKey, 0), Distance::Kilometers);
232 radii[1] =
Distance(getDouble(radiiKey, 1), Distance::Kilometers);
233 radii[2] =
Distance(getDouble(radiiKey, 2), Distance::Kilometers);
235 m_target->setRadii(radii);
237 *m_spkBodyCode = m_target->naifBodyCode();
241 *m_spkCode = (int) kernels[
"NaifSpkCode"];
245 *m_ckCode = (int) kernels[
"NaifCkCode"];
249 *m_sclkCode = (int) kernels[
"NaifSclkCode"];
252 if (!m_target->isSky()) {
254 *m_spkBodyCode = (int) kernels[
"NaifSpkBodyCode"];
258 if (m_target->isSky()) {
267 if ((m_usingNaif) || (!m_naifKeywords->hasKeyword(
"BODY_FRAME_CODE"))) {
270 cidfrm_c(*m_spkBodyCode,
sizeof(frameName), &frameCode, frameName,
274 QString naifTarget =
"IAU_" + QString(m_target->name()).toUpper();
275 namfrm_c(naifTarget.toAscii().data(), &frameCode);
276 if (frameCode == 0) {
277 string msg =
"Can not find NAIF BODY_FRAME_CODE for target ["
278 +
IString(m_target->name()) +
"]";
283 QVariant result = (int)frameCode;
284 storeValue(
"BODY_FRAME_CODE",0,SpiceIntType,result);
287 frameCode = getInteger(
"BODY_FRAME_CODE",0);
291 *m_bodyFrameCode = frameCode;
301 vector<Distance> radius = m_target->radii();
302 Distance targetRadius((radius[0] + radius[2])/2.0);
304 ltState, targetRadius);
306 m_sunPosition =
new SpicePosition(10, m_target->naifBodyCode());
310 if (kernels[
"TargetPosition"][0].toUpper() ==
"TABLE") {
312 m_sunPosition->LoadCache(t);
315 m_bodyRotation->LoadCache(t2);
316 if (t2.Label().hasKeyword(
"SolarLongitude")) {
317 *m_solarLongitude =
Longitude(t2.Label()[
"SolarLongitude"],
331 if (kernels[
"InstrumentPointing"].size() == 0) {
333 "No camera pointing available",
339 if (kernels[
"InstrumentPointing"][0].toUpper() ==
"NADIR") {
340 if (m_instrumentRotation) {
341 delete m_instrumentRotation;
342 m_instrumentRotation = NULL;
345 m_instrumentRotation =
new SpiceRotation(*m_ikCode, *m_spkBodyCode);
347 else if (kernels[
"InstrumentPointing"][0].toUpper() ==
"TABLE") {
349 m_instrumentRotation->LoadCache(t);
352 if (kernels[
"InstrumentPosition"].size() == 0) {
354 "No instrument position available",
358 if (kernels[
"InstrumentPosition"][0].toUpper() ==
"TABLE") {
360 m_instrumentPosition->LoadCache(t);
363 NaifStatus::CheckErrors();
376 NaifStatus::CheckErrors();
378 for (
int i = 0; i < key.
size(); i++) {
379 if (key[i] ==
"")
continue;
383 if (
IString(key[i]).
UpCase() ==
"TABLE" && noTables)
continue;
385 if (!file.fileExists()) {
386 QString msg =
"Spice file does not exist [" + file.expanded() +
"]";
389 QString fileName(file.expanded());
390 furnsh_c(fileName.toAscii().data());
391 m_kernels->push_back((QString)key[i]);
394 NaifStatus::CheckErrors();
401 NaifStatus::CheckErrors();
403 if (m_solarLongitude != NULL) {
404 delete m_solarLongitude;
405 m_solarLongitude = NULL;
413 if (m_startTime != NULL) {
418 if (m_endTime != NULL) {
423 if (m_cacheSize != NULL) {
428 if (m_startTimePadding != NULL) {
429 delete m_startTimePadding;
430 m_startTimePadding = NULL;
433 if (m_endTimePadding != NULL) {
434 delete m_endTimePadding;
435 m_endTimePadding = NULL;
438 if (m_instrumentPosition != NULL) {
439 delete m_instrumentPosition;
440 m_instrumentPosition = NULL;
443 if (m_instrumentRotation != NULL) {
444 delete m_instrumentRotation;
445 m_instrumentRotation = NULL;
448 if (m_sunPosition != NULL) {
449 delete m_sunPosition;
450 m_sunPosition = NULL;
453 if (m_bodyRotation != NULL) {
454 delete m_bodyRotation;
455 m_bodyRotation = NULL;
458 if (m_spkCode != NULL) {
463 if (m_ckCode != NULL) {
468 if (m_ikCode != NULL) {
473 if (m_sclkCode != NULL) {
478 if (m_spkBodyCode != NULL) {
479 delete m_spkBodyCode;
480 m_spkBodyCode = NULL;
483 if (m_bodyFrameCode != NULL) {
484 delete m_bodyFrameCode;
485 m_bodyFrameCode = NULL;
488 if (m_target != NULL) {
494 for (
int i = 0; m_kernels && i < m_kernels->size(); i++) {
496 QString fileName(file.expanded());
497 unload_c(fileName.toAscii().data());
500 if (m_kernels != NULL) {
505 NaifStatus::CheckErrors();
540 int cacheSize,
double tol) {
541 NaifStatus::CheckErrors();
544 if (cacheSize <= 0) {
545 string msg =
"Argument cacheSize must be greater than zero";
549 if (startTime > endTime) {
550 string msg =
"Argument startTime must be less than or equal to endTime";
554 if (*m_cacheSize > 0) {
555 string msg =
"A cache has already been created";
559 if (cacheSize == 1 && (*m_startTimePadding != 0 || *m_endTimePadding != 0)) {
560 string msg =
"This instrument does not support time padding";
565 if (getSpkAbCorrState(abcorr) ) {
566 instrumentPosition()->SetAberrationCorrection(
"NONE");
569 iTime avgTime((startTime.
Et() + endTime.
Et()) / 2.0);
570 computeSolarLongitude(avgTime);
573 if (!m_bodyRotation->IsCached()) {
574 int bodyRotationCacheSize = cacheSize;
575 if (cacheSize > 2) bodyRotationCacheSize = 2;
576 m_bodyRotation->LoadCache(
577 startTime.
Et() - *m_startTimePadding,
578 endTime.
Et() + *m_endTimePadding,
579 bodyRotationCacheSize);
582 if (m_instrumentRotation->GetSource() < SpiceRotation::Memcache) {
583 if (cacheSize > 3) m_instrumentRotation->MinimizeCache(SpiceRotation::Yes);
584 m_instrumentRotation->LoadCache(
585 startTime.
Et() - *m_startTimePadding,
586 endTime.
Et() + *m_endTimePadding,
590 if (m_instrumentPosition->GetSource() < SpicePosition::Memcache) {
591 m_instrumentPosition->LoadCache(
592 startTime.
Et() - *m_startTimePadding,
593 endTime.
Et() + *m_endTimePadding,
595 if (cacheSize > 3) m_instrumentPosition->Memcache2HermiteCache(tol);
598 if (!m_sunPosition->IsCached()) {
599 int sunPositionCacheSize = cacheSize;
600 if (cacheSize > 2) sunPositionCacheSize = 2;
601 m_sunPosition->LoadCache(
602 startTime.
Et() - *m_startTimePadding,
603 endTime.
Et() + *m_endTimePadding,
604 sunPositionCacheSize);
608 *m_startTime = startTime;
609 *m_endTime = endTime;
610 *m_cacheSize = cacheSize;
614 for (
int i = 0; i < m_kernels->size(); i++) {
616 QString fileName(file.expanded());
617 unload_c(fileName.toAscii().data());
622 NaifStatus::CheckErrors();
633 iTime Spice::cacheStartTime()
const {
670 void Spice::setTime(
const iTime &et) {
679 if (*m_cacheSize == 0) {
680 if (m_startTime->Et() == 0.0 && m_endTime->Et() == 0.0
681 && getSpkAbCorrState(abcorr)) {
682 instrumentPosition()->SetAberrationCorrection(
"NONE");
689 m_bodyRotation->SetEphemerisTime(et.
Et());
690 m_instrumentRotation->SetEphemerisTime(et.
Et());
691 m_instrumentPosition->SetEphemerisTime(et.
Et());
692 m_sunPosition->SetEphemerisTime(et.
Et());
694 std::vector<double> uB = m_bodyRotation->ReferenceVector(m_sunPosition->Coordinate());
699 computeSolarLongitude(*m_et);
711 void Spice::instrumentPosition(
double p[3])
const {
712 instrumentBodyFixedPosition(p);
724 void Spice::instrumentBodyFixedPosition(
double p[3])
const {
726 std::string msg =
"You must call SetTime first";
730 std::vector<double> sB = m_bodyRotation->ReferenceVector(m_instrumentPosition->Coordinate());
741 void Spice::instrumentBodyFixedVelocity(
double v[3])
const {
743 std::string msg =
"You must call SetTime first";
747 std::vector<double> state;
748 state.push_back(m_instrumentPosition->Coordinate()[0]);
749 state.push_back(m_instrumentPosition->Coordinate()[1]);
750 state.push_back(m_instrumentPosition->Coordinate()[2]);
751 state.push_back(m_instrumentPosition->Velocity()[0]);
752 state.push_back(m_instrumentPosition->Velocity()[1]);
753 state.push_back(m_instrumentPosition->Velocity()[2]);
755 std::vector<double> vB = m_bodyRotation->ReferenceVector(state);
779 void Spice::sunPosition(
double p[3])
const {
781 std::string msg =
"You must call SetTime first";
794 double Spice::targetCenterDistance()
const {
795 std::vector<double> sB = m_bodyRotation->ReferenceVector(m_instrumentPosition->Coordinate());
796 return sqrt(pow(sB[0], 2) + pow(sB[1], 2) + pow(sB[2], 2));
807 for (
int i = 0; i < 3; i++)
808 r[i] =m_target->radii()[i];
817 SpiceInt Spice::naifBodyCode()
const {
818 return (
int) m_target->naifBodyCode();
826 SpiceInt Spice::naifSpkCode()
const {
835 SpiceInt Spice::naifCkCode()
const {
844 SpiceInt Spice::naifIkCode()
const {
854 SpiceInt Spice::naifSclkCode()
const {
865 SpiceInt Spice::naifBodyFrameCode()
const {
866 return *m_bodyFrameCode;
875 return *m_naifKeywords;
884 double Spice::resolution() {
900 SpiceInt Spice::getInteger(
const QString &key,
int index) {
901 return readValue(key, SpiceIntType, index).toInt();
914 SpiceDouble Spice::getDouble(
const QString &key,
int index) {
915 return readValue(key, SpiceDoubleType, index).toDouble();
925 iTime Spice::getClockTime(QString clockValue,
int sclkCode) {
926 if (sclkCode == -1) {
927 sclkCode = naifSclkCode();
932 QString key =
"CLOCK_ET_" +
toString(sclkCode) +
"_" + clockValue;
933 QVariant storedClockTime = getStoredResult(key, SpiceDoubleType);
935 if (storedClockTime.isNull()) {
936 SpiceDouble timeOutput;
937 scs2e_c(sclkCode, clockValue.toAscii().data(), &timeOutput);
938 storedClockTime = timeOutput;
939 storeResult(key, SpiceDoubleType, timeOutput);
942 result = storedClockTime.toDouble();
962 NaifStatus::CheckErrors();
965 SpiceBoolean found =
false;
969 SpiceInt numValuesRead;
971 if (type == SpiceDoubleType) {
972 SpiceDouble kernelValue;
973 gdpool_c(key.toAscii().data(), (SpiceInt)index, 1,
974 &numValuesRead, &kernelValue, &found);
977 result = kernelValue;
979 else if (type == SpiceStringType) {
980 char kernelValue[512];
981 gcpool_c(key.toAscii().data(), (SpiceInt)index, 1,
sizeof(kernelValue),
982 &numValuesRead, kernelValue, &found);
985 result = kernelValue;
987 else if (type == SpiceIntType) {
988 SpiceInt kernelValue;
989 gipool_c(key.toAscii().data(), (SpiceInt)index, 1, &numValuesRead,
990 &kernelValue, &found);
993 result = (int)kernelValue;
997 QString msg =
"Can not find [" + key +
"] in text kernels";
1001 storeValue(key, index, type, result);
1005 result = readStoredValue(key, type, index);
1007 if (result.isNull()) {
1008 IString msg =
"The camera is requesting spice data [" + key +
"] that "
1009 "was not attached, please re-run spiceinit";
1018 void Spice::storeResult(QString name, SpiceValueType type, QVariant value) {
1019 if (type == SpiceDoubleType) {
1022 double doubleVal = value.toDouble();
1023 doubleVal = swapper.Double(&doubleVal);
1024 QByteArray byteCode((
char *) &doubleVal,
sizeof(
double));
1026 type = SpiceByteCodeType;
1029 storeValue(name +
"_COMPUTED", 0, type, value);
1033 QVariant Spice::getStoredResult(QString name, SpiceValueType type) {
1034 bool wasDouble =
false;
1036 if (type == SpiceDoubleType) {
1038 type = SpiceByteCodeType;
1041 QVariant stored = readStoredValue(name +
"_COMPUTED", type, 0);
1043 if (wasDouble && !stored.isNull()) {
1044 EndianSwapper swapper(
"LSB");
1045 double doubleVal = swapper.Double((
void *)QByteArray::fromHex(
1046 stored.toByteArray()).data());
1054 void Spice::storeValue(QString key,
int index, SpiceValueType type,
1056 if (!m_naifKeywords->hasKeyword(key)) {
1057 m_naifKeywords->addKeyword(PvlKeyword(key));
1060 PvlKeyword &storedKey = m_naifKeywords->findKeyword(key);
1062 while(index >= storedKey.size()) {
1063 storedKey.addValue(
"");
1066 if (type == SpiceByteCodeType) {
1067 storedKey[index] = QString(value.toByteArray().toHex().data());
1069 else if (type == SpiceStringType) {
1070 storedKey[index] = value.toString();
1072 else if (type == SpiceDoubleType) {
1073 storedKey[index] =
toString(value.toDouble());
1075 else if (type == SpiceIntType) {
1076 storedKey[index] =
toString(value.toInt());
1079 IString msg =
"Unable to store variant in labels for key [" + key +
"]";
1080 throw IException(IException::Unknown, msg,
_FILEINFO_);
1085 QVariant Spice::readStoredValue(QString key, SpiceValueType type,
1090 if (m_naifKeywords->hasKeyword(key) && !m_usingNaif) {
1091 PvlKeyword &storedKeyword = m_naifKeywords->findKeyword(key);
1094 if (type == SpiceDoubleType) {
1095 result =
toDouble(storedKeyword[index]);
1097 else if (type == SpiceStringType) {
1098 result = storedKeyword[index];
1100 else if (type == SpiceByteCodeType || SpiceStringType) {
1101 result = storedKeyword[index].toAscii();
1103 else if (type == SpiceIntType) {
1104 result =
toInt(storedKeyword[index]);
1107 catch(IException &) {
1125 QString Spice::getString(
const QString &key,
int index) {
1126 return readValue(key, SpiceStringType, index).toString();
1142 void Spice::subSpacecraftPoint(
double &lat,
double &lon) {
1143 NaifStatus::CheckErrors();
1146 std::string msg =
"You must call SetTime first";
1150 SpiceDouble usB[3], dist;
1151 std::vector<double> vsB = m_bodyRotation->ReferenceVector(m_instrumentPosition->Coordinate());
1156 unorm_c(sB, usB, &dist);
1158 std::vector<Distance> radii = target()->radii();
1159 SpiceDouble a = radii[0].kilometers();
1160 SpiceDouble b = radii[1].kilometers();
1161 SpiceDouble c = radii[2].kilometers();
1163 SpiceDouble originB[3];
1164 originB[0] = originB[1] = originB[2] = 0.0;
1167 SpiceDouble subB[3];
1168 surfpt_c(originB, usB, a, b, c, subB, &found);
1170 SpiceDouble mylon, mylat;
1171 reclat_c(subB, &a, &mylon, &mylat);
1172 lat = mylat * 180.0 /
PI;
1173 lon = mylon * 180.0 /
PI;
1174 if (lon < 0.0) lon += 360.0;
1176 NaifStatus::CheckErrors();
1190 void Spice::subSolarPoint(
double &lat,
double &lon) {
1191 NaifStatus::CheckErrors();
1194 std::string msg =
"You must call SetTime first";
1198 SpiceDouble uuB[3], dist;
1199 unorm_c(m_uB, uuB, &dist);
1201 std::vector<Distance> radii = target()->radii();
1202 SpiceDouble a = radii[0].kilometers();
1203 SpiceDouble b = radii[1].kilometers();
1204 SpiceDouble c = radii[2].kilometers();
1206 SpiceDouble originB[3];
1207 originB[0] = originB[1] = originB[2] = 0.0;
1210 SpiceDouble subB[3];
1211 surfpt_c(originB, uuB, a, b, c, subB, &found);
1213 SpiceDouble mylon, mylat;
1214 reclat_c(subB, &a, &mylon, &mylat);
1215 lat = mylat * 180.0 /
PI;
1216 lon = mylon * 180.0 /
PI;
1217 if (lon < 0.0) lon += 360.0;
1219 NaifStatus::CheckErrors();
1238 QString Spice::targetName()
const {
1239 return m_target->
name();
1249 void Spice::computeSolarLongitude(
iTime et) {
1250 NaifStatus::CheckErrors();
1252 if (m_target->isSky()) {
1257 if (m_bodyRotation->IsCached())
return;
1259 double tipm[3][3], npole[3];
1264 cidfrm_c(*m_spkBodyCode,
sizeof(frameName), &frameCode, frameName, &found);
1267 pxform_c(
"J2000", frameName, et.
Et(), tipm);
1270 tipbod_c(
"J2000", *m_spkBodyCode, et.
Et(), tipm);
1273 for (
int i = 0; i < 3; i++) {
1274 npole[i] = tipm[2][i];
1277 double state[6], lt;
1278 spkez_c(*m_spkBodyCode, et.
Et(),
"J2000",
"NONE", 10, state, <);
1281 ucrss_c(state, &state[3], uavel);
1283 double x[3], y[3], z[3];
1285 ucrss_c(npole, z, x);
1289 for (
int i = 0; i < 3; i++) {
1295 spkez_c(10, et.
Et(),
"J2000",
"LT+S", *m_spkBodyCode, state, <);
1298 mxv_c(trans, state, pos);
1300 double radius, ls, lat;
1301 reclat_c(pos, &radius, &ls, &lat);
1305 NaifStatus::CheckErrors();
1316 computeSolarLongitude(*m_et);
1317 return *m_solarLongitude;
1331 bool Spice::hasKernels(
Pvl &lab) {
1335 std::vector<string> keywords;
1336 keywords.push_back(
"TargetPosition");
1338 if (kernels.
hasKeyword(
"SpacecraftPosition")) {
1339 keywords.push_back(
"SpacecraftPosition");
1342 keywords.push_back(
"InstrumentPosition");
1345 if (kernels.
hasKeyword(
"SpacecraftPointing")) {
1346 keywords.push_back(
"SpacecraftPointing");
1349 keywords.push_back(
"InstrumentPointing");
1353 keywords.push_back(
"Frame");
1357 keywords.push_back(
"Extra");
1361 for (
int ikey = 0; ikey < (int) keywords.size(); ikey++) {
1362 key = kernels[ikey];
1364 for (
int i = 0; i < key.
size(); i++) {
1365 if (key[i] ==
"")
return false;
1382 return m_sunPosition;
1393 return m_instrumentPosition;
1404 return m_bodyRotation;
1415 return m_instrumentRotation;