Official websites use .gov
A .gov website belongs to an official government organization in the United States.

Secure .gov websites use HTTPS
A lock ( ) or https:// means you’ve safely connected to the .gov website. Share sensitive information only on official, secure websites.

Isis 3 Programmer Reference
Spice.cpp
1
5
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "Spice.h"
8
9#include <cfloat>
10#include <iomanip>
11
12#include <QDebug>
13#include <QVector>
14
15#include <getSpkAbCorrState.hpp>
16
17#include <ale/Load.h>
18
19#include <nlohmann/json.hpp>
20using json = nlohmann::json;
21
22
23#include "Constants.h"
24#include "Distance.h"
25#include "EllipsoidShape.h"
26#include "EndianSwapper.h"
27#include "FileName.h"
28#include "IException.h"
29#include "IString.h"
30#include "iTime.h"
31#include "Longitude.h"
32#include "LightTimeCorrectionState.h"
33#include "NaifStatus.h"
34#include "ShapeModel.h"
35#include "SpacecraftPosition.h"
36#include "Target.h"
37#include "Blob.h"
38#include "spiceql.h"
39
40using namespace std;
41
42namespace Isis {
63
64 // TODO: DOCUMENT EVERYTHING
66 Pvl &lab = *cube.label();
67 if (cube.hasBlob("CSMState", "String")) {
68 csmInit(cube, lab);
69 }
70 else {
71 PvlGroup kernels = lab.findGroup("Kernels", Pvl::Traverse);
72
73 // BONUS TODO: update to pull out separate init methods
74 // try using ALE
75 bool hasTables = (kernels["TargetPosition"][0] == "Table");
76 m_usingNaif = !lab.hasObject("NaifKeywords") || !hasTables;
77 m_usingAle = false;
78
79 if (m_usingNaif) {
80 try {
81 std::ostringstream kernel_pvl;
82 kernel_pvl << kernels;
83
84 json props;
85 if (kernels["InstrumentPointing"][0].toUpper() == "NADIR") {
86 props["nadir"] = true;
87 }
88
89 props["kernels"] = kernel_pvl.str();
90
91 json isd = ale::load(lab.fileName().toStdString(), props.dump(), "ale", false, false, true);
92 m_usingNaif = false;
93 m_usingAle = true;
94
95 isdInit(cube, lab, isd);
96 }
97 catch(...) {
98 init(cube, lab, !hasTables);
99 }
100 }
101 else {
102 init(cube, lab, !hasTables);
103 }
104 }
105 }
106
107
115 Spice::Spice(Cube &cube, Pvl &lab, json isd) {
116 // Set the expected member states for other parts of the Spice
117 // class
118 m_usingNaif = false;
119 m_usingAle = true;
120
121 isdInit(cube, lab, isd);
122 }
123
124 void Spice::isdInit(Cube &cube, Pvl &lab, nlohmann::json isd) {
126 // Initialize members
127 defaultInit();
128
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;
135
136 m_naifKeywords = new PvlObject("NaifKeywords");
137
138 // Get the kernel group and load main kernels
139 PvlGroup kernels = lab.findGroup("Kernels", Pvl::Traverse);
140
141 // Get the time padding first
142 if (kernels.hasKeyword("StartPadding")) {
143 *m_startTimePadding = toDouble(kernels["StartPadding"][0]);
144 }
145 else {
146 *m_startTimePadding = 0.0;
147 }
148
149 if (kernels.hasKeyword("EndPadding")) {
150 *m_endTimePadding = toDouble(kernels["EndPadding"][0]);
151 }
152 else {
153 *m_endTimePadding = 0.0;
154 }
155
156 try {
157 json aleNaifKeywords = isd["naif_keywords"];
158 m_naifKeywords = new PvlObject("NaifKeywords", aleNaifKeywords);
159
160 // Still need to load clock kernels for now
161 load(kernels["LeapSecond"], true);
162 if ( kernels.hasKeyword("SpacecraftClock")) {
163 load(kernels["SpacecraftClock"], true);
164 }
165 }
166 catch(IException &e) {
167 QString msg = "Failed to read naif_keywords from ISD";
168 throw IException(e, IException::Programmer, msg, _FILEINFO_);
169 }
170
171 // Moved the construction of the Target after the NAIF kenels have been loaded or the
172 // NAIF keywords have been pulled from the cube labels, so we can find target body codes
173 // that are defined in kernels and not just body codes build into spicelib
174 // TODO: Move this below the else once the rings code below has been refactored
175 m_target = new Target(this, lab);
176
177 // This should not be here. Consider having spiceinit add the necessary rings kernels to the
178 // Extra parameter if the user has set the shape model to RingPlane.
179 // If Target is Saturn and ShapeModel is RingPlane, load the extra rings pck file
180 // which changes the prime meridian values to report longitudes with respect to
181 // the ascending node of the ringplane.
182 if (m_target->name().toUpper() == "SATURN" && m_target->shape()->name().toUpper() == "PLANE") {
183 PvlKeyword ringPck = PvlKeyword("RingPCK","$cassini/kernels/pck/saturnRings_v001.tpc");
184 load(ringPck, true);
185 }
186
187 // Get NAIF ik, spk, sclk, and ck codes
188 //
189 // Use ikcode to get parameters from instrument kernel such as focal
190 // length, distortions, focal plane maps, etc
191 //
192 // Use spkcode to get spacecraft position from spk file
193 //
194 // Use sclkcode to transform times from et to tics
195 //
196 // Use ckcode to transform between frames
197 //
198 // Use bodycode to obtain radii and attitude (pole position/omega0)
199 //
200 // Use spkbodycode to read body position from spk
201
202 QString trykey = "NaifIkCode";
203 if (kernels.hasKeyword("NaifFrameCode")) trykey = "NaifFrameCode";
204 *m_ikCode = toInt(kernels[trykey][0]);
205
206 *m_spkCode = *m_ikCode / 1000;
208 *m_ckCode = *m_ikCode;
209
210 if (!m_target->isSky()) {
211 // Get target body code and radii and store them in the Naif group
212 // DAC modified to look for and store body code so that the radii keyword name
213 // will be able to be constructed even for new bodies not in the standard PCK yet.
214 QString radiiKey = "BODY" + Isis::toString(m_target->naifBodyCode()) + "_RADII";
215 QVariant result = m_target->naifBodyCode();
216 storeValue("BODY_CODE", 0, SpiceIntType, result);
217 std::vector<Distance> radii(3,Distance());
218 radii[0] = Distance(getDouble(radiiKey, 0), Distance::Kilometers);
219 radii[1] = Distance(getDouble(radiiKey, 1), Distance::Kilometers);
220 radii[2] = Distance(getDouble(radiiKey, 2), Distance::Kilometers);
221 // m_target doesn't have the getDouble method so Spice gets the radii for it
222 m_target->setRadii(radii);
223 }
224
225 *m_spkBodyCode = m_target->naifBodyCode();
226
227 // Override them if they exist in the labels
228 if (kernels.hasKeyword("NaifSpkCode")) {
229 *m_spkCode = (int) kernels["NaifSpkCode"];
230 }
231
232 if (kernels.hasKeyword("NaifCkCode")) {
233 *m_ckCode = (int) kernels["NaifCkCode"];
234 }
235
236 if (kernels.hasKeyword("NaifSclkCode")) {
237 *m_sclkCode = (int) kernels["NaifSclkCode"];
238 }
239
240 if (!m_target->isSky()) {
241 if (kernels.hasKeyword("NaifSpkBodyCode")) {
242 *m_spkBodyCode = (int) kernels["NaifSpkBodyCode"];
243 }
244 }
245
246 if (m_target->isSky()) {
247 // Create the identity rotation for sky targets
248 // Everything in bodyfixed will really be J2000
249 m_bodyRotation = new SpiceRotation(1);
250 }
251 else {
252 SpiceInt frameCode;
253 try {
254 frameCode = getInteger("BODY_FRAME_CODE", 0);
255 }
256 catch(IException &e) {
257 QString msg = "Unable to read BODY_FRAME_CODE from naifkeywords group";
258 throw IException(IException::Io, msg, _FILEINFO_);
259 }
260
261 m_bodyRotation = new SpiceRotation(frameCode);
262 *m_bodyFrameCode = frameCode;
263 }
264
265 m_instrumentRotation = new SpiceRotation(*m_ckCode);
266
267 // Set up for observer/target and light time correction to between s/c
268 // and target body.
269 LightTimeCorrectionState ltState(*m_ikCode, this);
270 ltState.checkSpkKernelsForAberrationCorrection();
271
272 vector<Distance> radius = m_target->radii();
273 Distance targetRadius((radius[0] + radius[2])/2.0);
274 m_instrumentPosition = new SpacecraftPosition(*m_spkCode, *m_spkBodyCode,
275 ltState, targetRadius);
276
277 m_sunPosition = new SpicePosition(10, m_target->naifBodyCode());
278
279 // Check to see if we have table blobs to load
280 if (kernels["TargetPosition"][0].toUpper() == "TABLE" &&
281 (cube.hasTable("SunPosition") && cube.hasTable("BodyRotation"))) {
282 Table t = cube.readTable("SunPosition");
283 m_sunPosition->LoadCache(t);
284
285 Table t2 = cube.readTable("BodyRotation");
286 m_bodyRotation->LoadCache(t2);
287 if (t2.Label().hasKeyword("SolarLongitude")) {
288 *m_solarLongitude = Longitude(t2.Label()["SolarLongitude"],
290 }
291 }
292 else {
293 m_sunPosition->LoadCache(isd["sun_position"]);
294 if (m_sunPosition->cacheSize() > 3) {
295 m_sunPosition->Memcache2HermiteCache(0.01);
296 }
297 m_bodyRotation->LoadCache(isd["body_rotation"]);
299 if (m_bodyRotation->cacheSize() > 5) {
300 m_bodyRotation->LoadTimeCache();
301 }
302 }
303
304 // We can't assume InstrumentPointing & InstrumentPosition exist, old
305 // files may be around with the old keywords, SpacecraftPointing &
306 // SpacecraftPosition. The old keywords were in existance before the
307 // Table option, so we don't need to check for Table under the old
308 // keywords.
309 if (kernels["InstrumentPointing"].size() == 0) {
310 throw IException(IException::Unknown,
311 "No camera pointing available",
312 _FILEINFO_);
313 }
314
315 if (kernels["InstrumentPointing"][0].toUpper() == "TABLE" &&
316 cube.hasTable("InstrumentPointing")) {
317 Table t = cube.readTable("InstrumentPointing");
318 m_instrumentRotation->LoadCache(t);
319 }
320 else {
321 m_instrumentRotation->LoadCache(isd["instrument_pointing"]);
322 if (m_instrumentRotation->cacheSize() == m_instrumentRotation->GetFullCacheTime().size() &&
323 m_instrumentRotation->cacheSize() > 5) {
325 m_instrumentRotation->LoadTimeCache();
326 }
327 else {
329 }
330 }
331
332
333 if (kernels["InstrumentPosition"].size() == 0) {
334 throw IException(IException::Unknown,
335 "No instrument position available",
336 _FILEINFO_);
337 }
338
339 if (kernels["InstrumentPosition"][0].toUpper() == "TABLE" &&
340 cube.hasTable("InstrumentPosition")) {
341 Table t = cube.readTable("InstrumentPosition");
342 m_instrumentPosition->LoadCache(t);
343 }
344 else {
345 m_instrumentPosition->LoadCache(isd["instrument_position"]);
346 }
347
348 // Add checks for loading existing tables
350 }
351
352
361 void Spice::csmInit(Cube &cube, Pvl label) {
362 defaultInit();
363 m_target = new Target;
365 }
366
367
373
374 m_et = nullptr;
376
377 m_startTime = new iTime;
378 m_endTime = new iTime;
379 m_cacheSize = new SpiceDouble;
380 *m_cacheSize = 0;
381
382 m_startTimePadding = new SpiceDouble;
384 m_endTimePadding = new SpiceDouble;
385 *m_endTimePadding = 0;
386
387 m_instrumentPosition = nullptr;
388 m_instrumentRotation = nullptr;
389
390 m_sunPosition = nullptr;
391 m_bodyRotation = nullptr;
392
393 m_allowDownsizing = false;
394
395 m_spkCode = nullptr;
396 m_ckCode = nullptr;
397 m_ikCode = nullptr;
398 m_sclkCode = nullptr;
399 m_spkBodyCode = nullptr;
400 m_bodyFrameCode = nullptr;
401 m_target = nullptr;
402 }
403
404
418 void Spice::init(Cube &cube, Pvl &lab, bool noTables) {
420 // Initialize members
421 defaultInit();
422
423 m_spkCode = new SpiceInt;
424 m_ckCode = new SpiceInt;
425 m_ikCode = new SpiceInt;
426 m_sclkCode = new SpiceInt;
427 m_spkBodyCode = new SpiceInt;
428 m_bodyFrameCode = new SpiceInt;
429
430 m_naifKeywords = new PvlObject("NaifKeywords");
431 // m_sky = false;
432
433 // Get the kernel group and load main kernels
434 PvlGroup kernels = lab.findGroup("Kernels", Pvl::Traverse);
435
436 // Get the time padding first
437 if (kernels.hasKeyword("StartPadding")) {
438 *m_startTimePadding = toDouble(kernels["StartPadding"][0]);
439 }
440 else {
441 *m_startTimePadding = 0.0;
442 }
443
444 if (kernels.hasKeyword("EndPadding")) {
445 *m_endTimePadding = toDouble(kernels["EndPadding"][0]);
446 }
447 else {
448 *m_endTimePadding = 0.0;
449 }
450
451 // Modified to load planetary ephemeris SPKs before s/c SPKs since some
452 // missions (e.g., MESSENGER) may augment the s/c SPK with new planet
453 // ephemerides. (2008-02-27 (KJB))
454 if (m_usingNaif) {
455 // Backup to standard ISIS implementation
456 if (noTables) {
457 load(kernels["TargetPosition"], noTables);
458 load(kernels["InstrumentPosition"], noTables);
459 load(kernels["InstrumentPointing"], noTables);
460 }
461
462 if (kernels.hasKeyword("Frame")) {
463 load(kernels["Frame"], noTables);
464 }
465
466 load(kernels["TargetAttitudeShape"], noTables);
467 if (kernels.hasKeyword("Instrument")) {
468 load(kernels["Instrument"], noTables);
469 }
470 // Always load after instrument
471 if (kernels.hasKeyword("InstrumentAddendum")) {
472 load(kernels["InstrumentAddendum"], noTables);
473 }
474
475 // Still need to load clock kernels for now
476 load(kernels["LeapSecond"], noTables);
477 if ( kernels.hasKeyword("SpacecraftClock")) {
478 load(kernels["SpacecraftClock"], noTables);
479 }
480
481 // Modified to load extra kernels last to allow overriding default values
482 // (2010-04-07) (DAC)
483 if (kernels.hasKeyword("Extra")) {
484 load(kernels["Extra"], noTables);
485 }
486
487 // Moved the construction of the Target after the NAIF kenels have been loaded or the
488 // NAIF keywords have been pulled from the cube labels, so we can find target body codes
489 // that are defined in kernels and not just body codes build into spicelib
490 // TODO: Move this below the else once the rings code below has been refactored
491 m_target = new Target(this, lab);
492
493 // This should not be here. Consider having spiceinit add the necessary rings kernels to the
494 // Extra parameter if the user has set the shape model to RingPlane.
495 // If Target is Saturn and ShapeModel is RingPlane, load the extra rings pck file
496 // which changes the prime meridian values to report longitudes with respect to
497 // the ascending node of the ringplane.
498 if (m_target->name().toUpper() == "SATURN" && m_target->shape()->name().toUpper() == "PLANE") {
499 PvlKeyword ringPck = PvlKeyword("RingPCK","$cassini/kernels/pck/saturnRings_v001.tpc");
500 load(ringPck, noTables);
501 }
502 }
503 else {
504 *m_naifKeywords = lab.findObject("NaifKeywords");
505
506 // Moved the construction of the Target after the NAIF kenels have been loaded or the
507 // NAIF keywords have been pulled from the cube labels, so we can find target body codes
508 // that are defined in kernels and not just body codes build into spicelib
509 // TODO: Move this below the else once the rings code above has been refactored
510
511 m_target = new Target(this, lab);
512 }
513
514 // Get NAIF ik, spk, sclk, and ck codes
515 //
516 // Use ikcode to get parameters from instrument kernel such as focal
517 // length, distortions, focal plane maps, etc
518 //
519 // Use spkcode to get spacecraft position from spk file
520 //
521 // Use sclkcode to transform times from et to tics
522 //
523 // Use ckcode to transform between frames
524 //
525 // Use bodycode to obtain radii and attitude (pole position/omega0)
526 //
527 // Use spkbodycode to read body position from spk
528
529 QString trykey = "NaifIkCode";
530 if (kernels.hasKeyword("NaifFrameCode")) trykey = "NaifFrameCode";
531 *m_ikCode = toInt(kernels[trykey][0]);
532
533 *m_spkCode = *m_ikCode / 1000;
535 *m_ckCode = *m_ikCode;
536
537 if (!m_target->isSky()) {
538 // Get target body code and radii and store them in the Naif group
539 // DAC modified to look for and store body code so that the radii keyword name
540 // will be able to be constructed even for new bodies not in the standard PCK yet.
541 QString radiiKey = "BODY" + Isis::toString(m_target->naifBodyCode()) + "_RADII";
542 QVariant result = m_target->naifBodyCode();
543 storeValue("BODY_CODE", 0, SpiceIntType, result);
544 std::vector<Distance> radii(3,Distance());
545 radii[0] = Distance(getDouble(radiiKey, 0), Distance::Kilometers);
546 radii[1] = Distance(getDouble(radiiKey, 1), Distance::Kilometers);
547 radii[2] = Distance(getDouble(radiiKey, 2), Distance::Kilometers);
548 // m_target doesn't have the getDouble method so Spice gets the radii for it
549 m_target->setRadii(radii);
550 }
551
552 *m_spkBodyCode = m_target->naifBodyCode();
553
554 // Override them if they exist in the labels
555 if (kernels.hasKeyword("NaifSpkCode")) {
556 *m_spkCode = (int) kernels["NaifSpkCode"];
557 }
558
559 if (kernels.hasKeyword("NaifCkCode")) {
560 *m_ckCode = (int) kernels["NaifCkCode"];
561 }
562
563 if (kernels.hasKeyword("NaifSclkCode")) {
564 *m_sclkCode = (int) kernels["NaifSclkCode"];
565 }
566
567 if (!m_target->isSky()) {
568 if (kernels.hasKeyword("NaifSpkBodyCode")) {
569 *m_spkBodyCode = (int) kernels["NaifSpkBodyCode"];
570 }
571 }
572
573 if (m_target->isSky()) {
574 // Create the identity rotation for sky targets
575 // Everything in bodyfixed will really be J2000
577 }
578 else {
579 // JAA - Modified to store and look for the frame body code in the cube labels
580 SpiceInt frameCode;
581 if ((m_usingNaif) || (!m_naifKeywords->hasKeyword("BODY_FRAME_CODE"))) {
582 char frameName[32];
583 SpiceBoolean found;
584 cidfrm_c(*m_spkBodyCode, sizeof(frameName), &frameCode, frameName, &found);
585
586 if (!found) {
587 QString naifTarget = "IAU_" + m_target->name().toUpper();
588 namfrm_c(naifTarget.toLatin1().data(), &frameCode);
589 if (frameCode == 0) {
590 QString msg = "Can not find NAIF BODY_FRAME_CODE for target ["
591 + m_target->name() + "]";
592 throw IException(IException::Io, msg, _FILEINFO_);
593 }
594 }
595
596 QVariant result = (int)frameCode;
597 storeValue("BODY_FRAME_CODE", 0, SpiceIntType, result);
598 }
599 else {
600 try {
601 frameCode = getInteger("BODY_FRAME_CODE", 0);
602 }
603 catch(IException &e) {
604 QString msg = "Unable to read BODY_FRAME_CODE from naifkeywords group";
605 throw IException(IException::Io, msg, _FILEINFO_);
606 }
607 }
608
609 m_bodyRotation = new SpiceRotation(frameCode);
610 *m_bodyFrameCode = frameCode;
611 }
612
614
615 // Set up for observer/target and light time correction to between s/c
616 // and target body.
617 LightTimeCorrectionState ltState(*m_ikCode, this);
619
620 vector<Distance> radius = m_target->radii();
621 Distance targetRadius((radius[0] + radius[2])/2.0);
623 ltState, targetRadius);
624
625 m_sunPosition = new SpicePosition(10, m_target->naifBodyCode());
626
627
628 // Check to see if we have nadir pointing that needs to be computed &
629 // See if we have table blobs to load
630 if (kernels["TargetPosition"][0].toUpper() == "TABLE") {
631 Table t = cube.readTable("SunPosition");
632 m_sunPosition->LoadCache(t);
633
634 Table t2 = cube.readTable("BodyRotation");
635 m_bodyRotation->LoadCache(t2);
636 if (t2.Label().hasKeyword("SolarLongitude")) {
637 *m_solarLongitude = Longitude(t2.Label()["SolarLongitude"],
639 }
640 else {
642 }
643 }
644
645 // We can't assume InstrumentPointing & InstrumentPosition exist, old
646 // files may be around with the old keywords, SpacecraftPointing &
647 // SpacecraftPosition. The old keywords were in existance before the
648 // Table option, so we don't need to check for Table under the old
649 // keywords.
650
651 if (kernels["InstrumentPointing"].size() == 0) {
652 throw IException(IException::Unknown,
653 "No camera pointing available",
654 _FILEINFO_);
655 }
656
657 // 2009-03-18 Tracie Sucharski - Removed test for old keywords, any files
658 // with the old keywords should be re-run through spiceinit.
659 if (kernels["InstrumentPointing"][0].toUpper() == "NADIR") {
663 }
664
666 }
667 else if (kernels["InstrumentPointing"][0].toUpper() == "TABLE") {
668 Table t = cube.readTable("InstrumentPointing");
669 m_instrumentRotation->LoadCache(t);
670 }
671
672
673 if (kernels["InstrumentPosition"].size() == 0) {
674 throw IException(IException::Unknown,
675 "No instrument position available",
676 _FILEINFO_);
677 }
678
679 if (kernels["InstrumentPosition"][0].toUpper() == "TABLE") {
680 Table t = cube.readTable("InstrumentPosition");
681 m_instrumentPosition->LoadCache(t);
682 }
683
685 }
686
687
696 void Spice::load(PvlKeyword &key, bool noTables) {
698
699 for (int i = 0; i < key.size(); i++) {
700 if (key[i] == "") continue;
701 if (key[i].toUpper() == "NULL") break;
702 if (key[i].toUpper() == "NADIR") break;
703 if (key[i].toUpper() == "TABLE" && !noTables) break;
704 if (key[i].toUpper() == "TABLE" && noTables) continue;
705 FileName file(key[i]);
706 if (!file.fileExists()) {
707 QString msg = "Spice file does not exist [" + file.expanded() + "]";
708 throw IException(IException::Io, msg, _FILEINFO_);
709 }
710 QString fileName = file.expanded();
711 SpiceQL::load(fileName.toLatin1().data());
712 m_kernels->push_back(key[i]);
713 }
714
716 }
717
723
724 if (m_solarLongitude != NULL) {
725 delete m_solarLongitude;
726 m_solarLongitude = NULL;
727 }
728
729 if (m_et != NULL) {
730 delete m_et;
731 m_et = NULL;
732 }
733
734 if (m_startTime != NULL) {
735 delete m_startTime;
736 m_startTime = NULL;
737 }
738
739 if (m_endTime != NULL) {
740 delete m_endTime;
741 m_endTime = NULL;
742 }
743
744 if (m_cacheSize != NULL) {
745 delete m_cacheSize;
746 m_cacheSize = NULL;
747 }
748
749 if (m_startTimePadding != NULL) {
750 delete m_startTimePadding;
751 m_startTimePadding = NULL;
752 }
753
754 if (m_endTimePadding != NULL) {
755 delete m_endTimePadding;
756 m_endTimePadding = NULL;
757 }
758
759 if (m_instrumentPosition != NULL) {
762 }
763
764 if (m_instrumentRotation != NULL) {
767 }
768
769 if (m_sunPosition != NULL) {
770 delete m_sunPosition;
771 m_sunPosition = NULL;
772 }
773
774 if (m_bodyRotation != NULL) {
775 delete m_bodyRotation;
776 m_bodyRotation = NULL;
777 }
778
779 if (m_spkCode != NULL) {
780 delete m_spkCode;
781 m_spkCode = NULL;
782 }
783
784 if (m_ckCode != NULL) {
785 delete m_ckCode;
786 m_ckCode = NULL;
787 }
788
789 if (m_ikCode != NULL) {
790 delete m_ikCode;
791 m_ikCode = NULL;
792 }
793
794 if (m_sclkCode != NULL) {
795 delete m_sclkCode;
796 m_sclkCode = NULL;
797 }
798
799 if (m_spkBodyCode != NULL) {
800 delete m_spkBodyCode;
801 m_spkBodyCode = NULL;
802 }
803
804 if (m_bodyFrameCode != NULL) {
805 delete m_bodyFrameCode;
806 m_bodyFrameCode = NULL;
807 }
808
809 if (m_target != NULL) {
810 delete m_target;
811 m_target = NULL;
812 }
813
814 // Unload the kernels (TODO: Can this be done faster)
815 for (int i = 0; m_kernels && i < m_kernels->size(); i++) {
816 FileName file(m_kernels->at(i));
817 QString fileName = file.expanded();
818 unload_c(fileName.toLatin1().data());
819 }
820
821 if (m_kernels != NULL) {
822 delete m_kernels;
823 m_kernels = NULL;
824 }
826 }
827
859 void Spice::createCache(iTime startTime, iTime endTime,
860 int cacheSize, double tol) {
862
863 // Check for errors
864 if (cacheSize <= 0) {
865 QString msg = "Argument cacheSize must be greater than zero";
866 throw IException(IException::Programmer, msg, _FILEINFO_);
867 }
868
869 if (startTime > endTime) {
870 QString msg = "Argument startTime must be less than or equal to endTime";
871 throw IException(IException::Programmer, msg, _FILEINFO_);
872 }
873
874 if (*m_cacheSize > 0) {
875 QString msg = "A cache has already been created";
876 throw IException(IException::Programmer, msg, _FILEINFO_);
877 }
878
879 if (cacheSize == 1 && (*m_startTimePadding != 0 || *m_endTimePadding != 0)) {
880 QString msg = "This instrument does not support time padding";
881 throw IException(IException::User, msg, _FILEINFO_);
882 }
883
884 string abcorr;
885 if (getSpkAbCorrState(abcorr)) {
887 }
888
889 iTime avgTime((startTime.Et() + endTime.Et()) / 2.0);
890 computeSolarLongitude(avgTime);
891
892 // Cache everything
893 if (!m_bodyRotation->IsCached()) {
894 int bodyRotationCacheSize = cacheSize;
895 if (cacheSize > 2) bodyRotationCacheSize = 2;
896 m_bodyRotation->LoadCache(
897 startTime.Et() - *m_startTimePadding,
898 endTime.Et() + *m_endTimePadding,
899 bodyRotationCacheSize);
900 }
901
903 if (cacheSize > 3) m_instrumentRotation->MinimizeCache(SpiceRotation::Yes);
904 m_instrumentRotation->LoadCache(
905 startTime.Et() - *m_startTimePadding,
906 endTime.Et() + *m_endTimePadding,
907 cacheSize);
908 }
909
911 m_instrumentPosition->LoadCache(
912 startTime.Et() - *m_startTimePadding,
913 endTime.Et() + *m_endTimePadding,
914 cacheSize);
915 if (cacheSize > 3) m_instrumentPosition->Memcache2HermiteCache(tol);
916 }
917 else if (m_instrumentPosition->GetSource() == SpicePosition::Memcache && m_instrumentPosition->HasVelocity() && isUsingAle()) {
918 int aleCacheSize = m_instrumentPosition->cacheSize();
919 if (aleCacheSize > 3) {
920 m_instrumentPosition->Memcache2HermiteCache(tol);
921 }
922 }
923
924
925 if (!m_sunPosition->IsCached()) {
926 int sunPositionCacheSize = cacheSize;
927 if (cacheSize > 2) sunPositionCacheSize = 2;
928 m_sunPosition->LoadCache(
929 startTime.Et() - *m_startTimePadding,
930 endTime.Et() + *m_endTimePadding,
931 sunPositionCacheSize);
932 }
933
934 // Save the time and cache size
935 *m_startTime = startTime;
936 *m_endTime = endTime;
937 *m_cacheSize = cacheSize;
938 m_et = NULL;
939
940 // Unload the kernels (TODO: Can this be done faster)
941 for (int i = 0; i < m_kernels->size(); i++) {
942 FileName file(m_kernels->at(i));
943 QString fileName = file.expanded();
944 unload_c(fileName.toLatin1().data());
945 }
946
947 m_kernels->clear();
948
950 }
951
952
961 if (m_startTime) {
962 return *m_startTime;
963 }
964
965 return iTime();
966 }
967
976 if (m_endTime) {
977 return *m_endTime;
978 }
979
980 return iTime();
981 }
982
997 void Spice::setTime(const iTime &et) {
998
999 if (m_et == NULL) {
1000 m_et = new iTime();
1001
1002 // Before the Spice is cached, but after the camera aberration correction
1003 // is set, check to see if the instrument position kernel was created
1004 // by spkwriter. If so turn off aberration corrections because the camera
1005 // set aberration corrections are included in the spk already.
1006 string abcorr;
1007 if (*m_cacheSize == 0) {
1008 if (m_startTime->Et() == 0.0 && m_endTime->Et() == 0.0
1009 && getSpkAbCorrState(abcorr)) {
1011 }
1012 }
1013 }
1014
1015 *m_et = et;
1016
1017 m_bodyRotation->SetEphemerisTime(et.Et());
1018 m_instrumentRotation->SetEphemerisTime(et.Et());
1019 m_instrumentPosition->SetEphemerisTime(et.Et());
1020 m_sunPosition->SetEphemerisTime(et.Et());
1021
1022 std::vector<double> uB = m_bodyRotation->ReferenceVector(m_sunPosition->Coordinate());
1023 m_uB[0] = uB[0];
1024 m_uB[1] = uB[1];
1025 m_uB[2] = uB[2];
1026
1028 }
1029
1039 void Spice::instrumentPosition(double p[3]) const {
1041 }
1042
1052 void Spice::instrumentBodyFixedPosition(double p[3]) const {
1053 if (m_et == NULL) {
1054 QString msg = "Unable to retrieve instrument's body fixed position."
1055 " Spice::SetTime must be called first.";
1056 throw IException(IException::Programmer, msg, _FILEINFO_);
1057 }
1058
1059 std::vector<double> sB = m_bodyRotation->ReferenceVector(m_instrumentPosition->Coordinate());
1060 p[0] = sB[0];
1061 p[1] = sB[1];
1062 p[2] = sB[2];
1063 }
1064
1070 void Spice::instrumentBodyFixedVelocity(double v[3]) const {
1071 if (m_et == NULL) {
1072 QString msg = "Unable to retrieve instrument's body fixed velocity."
1073 " Spice::SetTime must be called first.";
1074 throw IException(IException::Programmer, msg, _FILEINFO_);
1075 }
1076
1077 std::vector<double> state;
1078 state.push_back(m_instrumentPosition->Coordinate()[0]);
1079 state.push_back(m_instrumentPosition->Coordinate()[1]);
1080 state.push_back(m_instrumentPosition->Coordinate()[2]);
1081 state.push_back(m_instrumentPosition->Velocity()[0]);
1082 state.push_back(m_instrumentPosition->Velocity()[1]);
1083 state.push_back(m_instrumentPosition->Velocity()[2]);
1084
1085 std::vector<double> vB = m_bodyRotation->ReferenceVector(state);
1086 v[0] = vB[3];
1087 v[1] = vB[4];
1088 v[2] = vB[5];
1089 }
1090
1091
1102 if (m_et == NULL) {
1103 QString msg = "Unable to retrieve the time."
1104 " Spice::SetTime must be called first.";
1105 throw IException(IException::Programmer, msg, _FILEINFO_);
1106 }
1107 return *m_et;
1108 }
1109
1110
1119 void Spice::sunPosition(double p[3]) const {
1120 if (m_et == NULL) {
1121 QString msg = "Unable to retrieve sun's position."
1122 " Spice::SetTime must be called first.";
1123 throw IException(IException::Programmer, msg, _FILEINFO_);
1124 }
1125 p[0] = m_uB[0];
1126 p[1] = m_uB[1];
1127 p[2] = m_uB[2];
1128 }
1129
1136 std::vector<double> sB = m_bodyRotation->ReferenceVector(m_instrumentPosition->Coordinate());
1137 return sqrt(pow(sB[0], 2) + pow(sB[1], 2) + pow(sB[2], 2));
1138 }
1139
1147 void Spice::radii(Distance r[3]) const {
1148 for (int i = 0; i < 3; i++)
1149 r[i] =m_target->radii()[i];
1150 }
1151
1158 SpiceInt Spice::naifBodyCode() const {
1159 return (int) m_target->naifBodyCode();
1160 }
1161
1167 SpiceInt Spice::naifSpkCode() const {
1168 return *m_spkCode;
1169 }
1170
1176 SpiceInt Spice::naifCkCode() const {
1177 return *m_ckCode;
1178 }
1179
1185 SpiceInt Spice::naifIkCode() const {
1186 return *m_ikCode;
1187 }
1188
1195 SpiceInt Spice::naifSclkCode() const {
1196 return *m_sclkCode;
1197 }
1198
1206 SpiceInt Spice::naifBodyFrameCode() const {
1207 return *m_bodyFrameCode;
1208 }
1209
1210
1216 return *m_naifKeywords;
1217 }
1218
1219
1227 return 1.0;
1228 };
1229
1230
1242 SpiceInt Spice::getInteger(const QString &key, int index) {
1243 return readValue(key, SpiceIntType, index).toInt();
1244 }
1245
1256 SpiceDouble Spice::getDouble(const QString &key, int index) {
1257 return readValue(key, SpiceDoubleType, index).toDouble();
1258 }
1259
1260
1270 iTime Spice::getClockTime(QString clockValue, int sclkCode, bool clockTicks) {
1271 if (sclkCode == -1) {
1272 sclkCode = naifSclkCode();
1273 }
1274
1275 iTime result;
1276
1277 QString key = "CLOCK_ET_" + Isis::toString(sclkCode) + "_" + clockValue;
1278 QVariant storedClockTime = getStoredResult(key, SpiceDoubleType);
1279
1280 if (storedClockTime.isNull()) {
1281 SpiceDouble timeOutput;
1283 if (clockTicks) {
1284 sct2e_c(sclkCode, (SpiceDouble) clockValue.toDouble(), &timeOutput);
1285 }
1286 else {
1287 scs2e_c(sclkCode, clockValue.toLatin1().data(), &timeOutput);
1288 }
1290 storedClockTime = timeOutput;
1291 storeResult(key, SpiceDoubleType, timeOutput);
1292 }
1293
1294 result = storedClockTime.toDouble();
1295
1296 return result;
1297 }
1298
1299
1310 QVariant Spice::readValue(QString key, SpiceValueType type, int index) {
1311 QVariant result;
1312
1313 if (m_usingNaif && !m_usingAle) {
1315
1316 // This is the success status of the naif call
1317 SpiceBoolean found = false;
1318
1319 // Naif tells us how many values were read, but we always just read one.
1320 // Use this variable to make naif happy.
1321 SpiceInt numValuesRead;
1322
1323 if (type == SpiceDoubleType) {
1324 SpiceDouble kernelValue;
1325 gdpool_c(key.toLatin1().data(), (SpiceInt)index, 1,
1326 &numValuesRead, &kernelValue, &found);
1327
1328 if (found && numValuesRead > 0)
1329 result = kernelValue;
1330 }
1331 else if (type == SpiceStringType) {
1332 char kernelValue[512];
1333 gcpool_c(key.toLatin1().data(), (SpiceInt)index, 1, sizeof(kernelValue),
1334 &numValuesRead, kernelValue, &found);
1335
1336 if (found && numValuesRead > 0)
1337 result = QString(kernelValue);
1338 }
1339 else if (type == SpiceIntType) {
1340 SpiceInt kernelValue;
1341 gipool_c(key.toLatin1().data(), (SpiceInt)index, 1, &numValuesRead,
1342 &kernelValue, &found);
1343
1344 if (found && numValuesRead > 0)
1345 result = (int)kernelValue;
1346 }
1347
1348 if (!found) {
1349 QString msg = "Can not find [" + key + "] in text kernels";
1350 throw IException(IException::Io, msg, _FILEINFO_);
1351 }
1352 else if (numValuesRead == 0){
1353 QString msg = "Found " + key + "] in text kernels, but no values were identified and read.";
1354 throw IException(IException::Io, msg, _FILEINFO_);
1355 }
1356
1357 storeValue(key, index, type, result);
1359 }
1360 else {
1361 // Read from PvlObject that is our naif keywords
1362 result = readStoredValue(key, type, index);
1363
1364 if (result.isNull()) {
1365 QString msg = "The camera is requesting spice data [" + key + "] that "
1366 "was not attached, please re-run spiceinit";
1367 throw IException(IException::Unknown, msg, _FILEINFO_);
1368 }
1369 }
1370
1371 return result;
1372 }
1373
1374
1375 void Spice::storeResult(QString name, SpiceValueType type, QVariant value) {
1376 if (type == SpiceDoubleType) {
1377 EndianSwapper swapper("LSB");
1378
1379 double doubleVal = value.toDouble();
1380 doubleVal = swapper.Double(&doubleVal);
1381 QByteArray byteCode((char *) &doubleVal, sizeof(double));
1382 value = byteCode;
1383 type = SpiceByteCodeType;
1384 }
1385
1386 storeValue(name + "_COMPUTED", 0, type, value);
1387 }
1388
1389
1390 QVariant Spice::getStoredResult(QString name, SpiceValueType type) {
1391 bool wasDouble = false;
1392
1393 if (type == SpiceDoubleType) {
1394 wasDouble = true;
1395 type = SpiceByteCodeType;
1396 }
1397
1398 QVariant stored = readStoredValue(name + "_COMPUTED", type, 0);
1399
1400 if (wasDouble && !stored.isNull()) {
1401 EndianSwapper swapper("LSB");
1402 double doubleVal = swapper.Double((void *)QByteArray::fromHex(
1403 stored.toByteArray()).data());
1404 stored = doubleVal;
1405 }
1406
1407 return stored;
1408 }
1409
1410
1411 void Spice::storeValue(QString key, int index, SpiceValueType type,
1412 QVariant value) {
1413 if (!m_naifKeywords->hasKeyword(key)) {
1414 m_naifKeywords->addKeyword(PvlKeyword(key));
1415 }
1416
1417 PvlKeyword &storedKey = m_naifKeywords->findKeyword(key);
1418
1419 while(index >= storedKey.size()) {
1420 storedKey.addValue("");
1421 }
1422
1423 if (type == SpiceByteCodeType) {
1424 storedKey[index] = QString(value.toByteArray().toHex().data());
1425 }
1426 else if (type == SpiceStringType) {
1427 storedKey[index] = value.toString();
1428 }
1429 else if (type == SpiceDoubleType) {
1430 storedKey[index] = toString(value.toDouble());
1431 }
1432 else if (type == SpiceIntType) {
1433 storedKey[index] = toString(value.toInt());
1434 }
1435 else {
1436 QString msg = "Unable to store variant in labels for key [" + key + "]";
1437 throw IException(IException::Unknown, msg, _FILEINFO_);
1438 }
1439 }
1440
1441
1442 QVariant Spice::readStoredValue(QString key, SpiceValueType type,
1443 int index) {
1444 // Read from PvlObject that is our naif keywords
1445 QVariant result;
1446
1447 if (m_naifKeywords->hasKeyword(key) && (!m_usingNaif || m_usingAle)) {
1448 PvlKeyword &storedKeyword = m_naifKeywords->findKeyword(key);
1449
1450 try {
1451 if (type == SpiceDoubleType) {
1452 result = toDouble(storedKeyword[index]);
1453 }
1454 else if (type == SpiceStringType) {
1455 result = storedKeyword[index];
1456 }
1457 else if (type == SpiceByteCodeType || SpiceStringType) {
1458 result = storedKeyword[index].toLatin1();
1459 }
1460 else if (type == SpiceIntType) {
1461 result = toInt(storedKeyword[index]);
1462 }
1463 }
1464 catch(IException &e) {
1465 e.print();
1466 }
1467 }
1468
1469 return result;
1470 }
1471
1483 QString Spice::getString(const QString &key, int index) {
1484 return readValue(key, SpiceStringType, index).toString();
1485 }
1486
1487
1500 void Spice::subSpacecraftPoint(double &lat, double &lon) {
1502
1503 if (m_et == NULL) {
1504 QString msg = "Unable to retrieve subspacecraft position."
1505 " Spice::SetTime must be called first.";
1506 throw IException(IException::Programmer, msg, _FILEINFO_);
1507 }
1508
1509 SpiceDouble usB[3], dist;
1510 std::vector<double> vsB = m_bodyRotation->ReferenceVector(m_instrumentPosition->Coordinate());
1511 SpiceDouble sB[3];
1512 sB[0] = vsB[0];
1513 sB[1] = vsB[1];
1514 sB[2] = vsB[2];
1515 unorm_c(sB, usB, &dist);
1516
1517 std::vector<Distance> radii = target()->radii();
1518 SpiceDouble a = radii[0].kilometers();
1519 SpiceDouble b = radii[1].kilometers();
1520 SpiceDouble c = radii[2].kilometers();
1521
1522 SpiceDouble originB[3];
1523 originB[0] = originB[1] = originB[2] = 0.0;
1524
1525 SpiceBoolean found;
1526 SpiceDouble subB[3];
1527
1528 surfpt_c(originB, usB, a, b, c, subB, &found);
1529
1530 SpiceDouble mylon, mylat;
1531 reclat_c(subB, &a, &mylon, &mylat);
1532 lat = mylat * 180.0 / PI;
1533 lon = mylon * 180.0 / PI;
1534 if (lon < 0.0) lon += 360.0;
1535
1537 }
1538
1539
1551 void Spice::subSolarPoint(double &lat, double &lon) {
1553
1554 if (m_et == NULL) {
1555 QString msg = "Unable to retrieve subsolar point."
1556 " Spice::SetTime must be called first.";
1557 throw IException(IException::Programmer, msg, _FILEINFO_);
1558 }
1559
1560 SpiceDouble uuB[3], dist;
1561 unorm_c(m_uB, uuB, &dist);
1562 std::vector<Distance> radii = target()->radii();
1563
1564 SpiceDouble a = radii[0].kilometers();
1565 SpiceDouble b = radii[1].kilometers();
1566 SpiceDouble c = radii[2].kilometers();
1567
1568 SpiceDouble originB[3];
1569 originB[0] = originB[1] = originB[2] = 0.0;
1570
1571 SpiceBoolean found;
1572 SpiceDouble subB[3];
1573 surfpt_c(originB, uuB, a, b, c, subB, &found);
1574
1575 SpiceDouble mylon, mylat;
1576 reclat_c(subB, &a, &mylon, &mylat);
1577
1578 lat = mylat * 180.0 / PI;
1579 lon = mylon * 180.0 / PI;
1580 if (lon < 0.0) lon += 360.0;
1582 }
1583
1584
1591 return m_target;
1592 }
1593
1594
1600 QString Spice::targetName() const {
1601 return m_target->name();
1602 }
1603
1604
1605 double Spice::sunToBodyDist() const {
1606 std::vector<double> sunPosition = m_sunPosition->Coordinate();
1607 std::vector<double> bodyRotation = m_bodyRotation->Matrix();
1608
1609 double sunPosFromTarget[3];
1610 mxv_c(&bodyRotation[0], &sunPosition[0], sunPosFromTarget);
1611
1612 return vnorm_c(sunPosFromTarget);
1613 }
1614
1615
1624
1625 if (m_target->isSky()) {
1627 return;
1628 }
1629
1630 if (m_usingAle || !m_usingNaif) {
1631 double og_time = m_bodyRotation->EphemerisTime();
1632 m_bodyRotation->SetEphemerisTime(et.Et());
1633 m_sunPosition->SetEphemerisTime(et.Et());
1634
1635 std::vector<double> bodyRotMat = m_bodyRotation->Matrix();
1636 std::vector<double> sunPos = m_sunPosition->Coordinate();
1637 std::vector<double> sunVel = m_sunPosition->Velocity();
1638 double sunAv[3];
1639
1640 ucrss_c(&sunPos[0], &sunVel[0], sunAv);
1641
1642 double npole[3];
1643 for (int i = 0; i < 3; i++) {
1644 npole[i] = bodyRotMat[6+i];
1645 }
1646
1647 double x[3], y[3], z[3];
1648 vequ_c(sunAv, z);
1649 ucrss_c(npole, z, x);
1650 ucrss_c(z, x, y);
1651
1652 double trans[3][3];
1653 for (int i = 0; i < 3; i++) {
1654 trans[0][i] = x[i];
1655 trans[1][i] = y[i];
1656 trans[2][i] = z[i];
1657 }
1658
1659 double pos[3];
1660 mxv_c(trans, &sunPos[0], pos);
1661
1662 double radius, ls, lat;
1663 reclat_c(pos, &radius, &ls, &lat);
1664
1666
1668 m_bodyRotation->SetEphemerisTime(og_time);
1669 m_sunPosition->SetEphemerisTime(og_time);
1670 return;
1671 }
1672
1673 if (m_bodyRotation->IsCached()) return;
1674
1675 double tipm[3][3], npole[3];
1676 char frameName[32];
1677 SpiceInt frameCode;
1678 SpiceBoolean found;
1679
1680 cidfrm_c(*m_spkBodyCode, sizeof(frameName), &frameCode, frameName, &found);
1681
1682 if (found) {
1683 pxform_c("J2000", frameName, et.Et(), tipm);
1684 }
1685 else {
1686 tipbod_c("J2000", *m_spkBodyCode, et.Et(), tipm);
1687 }
1688
1689 for (int i = 0; i < 3; i++) {
1690 npole[i] = tipm[2][i];
1691 }
1692
1693 double state[6], lt;
1694 spkez_c(*m_spkBodyCode, et.Et(), "J2000", "NONE", 10, state, &lt);
1695
1696 double uavel[3];
1697 ucrss_c(state, &state[3], uavel);
1698
1699 double x[3], y[3], z[3];
1700 vequ_c(uavel, z);
1701 ucrss_c(npole, z, x);
1702 ucrss_c(z, x, y);
1703
1704 double trans[3][3];
1705 for (int i = 0; i < 3; i++) {
1706 trans[0][i] = x[i];
1707 trans[1][i] = y[i];
1708 trans[2][i] = z[i];
1709 }
1710
1711 spkez_c(10, et.Et(), "J2000", "LT+S", *m_spkBodyCode, state, &lt);
1712
1713 double pos[3];
1714 mxv_c(trans, state, pos);
1715
1716 double radius, ls, lat;
1717 reclat_c(pos, &radius, &ls, &lat);
1718
1720
1722
1723 }
1724
1725
1732 if (m_et) {
1734 return *m_solarLongitude;
1735 }
1736
1737 return Longitude();
1738 }
1739
1740
1748 bool Spice::hasKernels(Pvl &lab) {
1749
1750 // Get the kernel group and check main kernels
1751 PvlGroup kernels = lab.findGroup("Kernels", Pvl::Traverse);
1752 std::vector<string> keywords;
1753 keywords.push_back("TargetPosition");
1754
1755 if (kernels.hasKeyword("SpacecraftPosition")) {
1756 keywords.push_back("SpacecraftPosition");
1757 }
1758 else {
1759 keywords.push_back("InstrumentPosition");
1760 }
1761
1762 if (kernels.hasKeyword("SpacecraftPointing")) {
1763 keywords.push_back("SpacecraftPointing");
1764 }
1765 else {
1766 keywords.push_back("InstrumentPointing");
1767 }
1768
1769 if (kernels.hasKeyword("Frame")) {
1770 keywords.push_back("Frame");
1771 }
1772
1773 if (kernels.hasKeyword("Extra")) {
1774 keywords.push_back("Extra");
1775 }
1776
1777 PvlKeyword key;
1778 for (int ikey = 0; ikey < (int) keywords.size(); ikey++) {
1779 key = kernels[ikey];
1780
1781 for (int i = 0; i < key.size(); i++) {
1782 if (key[i] == "") return false;
1783 if (key[i].toUpper() == "NULL") return false;
1784 if (key[i].toUpper() == "NADIR") return false;
1785 if (key[i].toUpper() == "TABLE") return false;
1786 }
1787 }
1788 return true;
1789 }
1790
1791
1800 return !(m_et == NULL);
1801 }
1802
1803
1812 return m_sunPosition;
1813 }
1814
1825
1834 return m_bodyRotation;
1835 }
1836
1847
1848 bool Spice::isUsingAle(){
1849 return m_usingAle;
1850 }
1851}
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition Angle.h:56
@ Radians
Radians are generally used in mathematical equations, 0-2*PI is one circle, however these are more di...
Definition Angle.h:63
IO Handler for Isis Cubes.
Definition Cube.h:168
bool hasTable(const QString &name)
Check to see if the cube contains a pvl table by the provided name.
Definition Cube.cpp:2331
bool hasBlob(const QString &name, const QString &type)
Check to see if the cube contains a BLOB.
Definition Cube.cpp:2305
Table readTable(const QString &name)
Read a Table from the cube.
Definition Cube.cpp:1200
Pvl * label() const
Returns a pointer to the IsisLabel object associated with the cube.
Definition Cube.cpp:1975
Distance measurement, usually in meters.
Definition Distance.h:34
@ Kilometers
The distance is being specified in kilometers.
Definition Distance.h:45
Provides interface to user configurable Light Time correction feature.
bool checkSpkKernelsForAberrationCorrection()
Check for light time/stellar aberration tag in SPK comments.
This class is designed to encapsulate the concept of a Longitude.
Definition Longitude.h:40
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.
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...
Definition Spice.cpp:997
void init(Cube &cube, Pvl &pvl, bool noTables)
Initialization of Spice object.
Definition Spice.cpp:418
QString getString(const QString &key, int index=0)
This returns a value from the NAIF text pool.
Definition Spice.cpp:1483
virtual iTime getClockTime(QString clockValue, int sclkCode=-1, bool clockTicks=false)
This converts the spacecraft clock ticks value (clockValue) to an iTime.
Definition Spice.cpp:1270
SpiceDouble * m_startTimePadding
Kernels pvl group StartPadding keyword value.
Definition Spice.h:404
Target * m_target
Target of the observation.
Definition Spice.h:383
bool m_usingNaif
Indicates whether we are reading values from the NaifKeywords PvlObject in cube.
Definition Spice.h:430
QVariant readValue(QString key, SpiceValueType type, int index=0)
This should be used for reading ALL text naif kernel values.
Definition Spice.cpp:1310
Longitude * m_solarLongitude
Body rotation solar longitude value.
Definition Spice.h:385
bool m_usingAle
Indicate whether we are reading values from an ISD returned from ALE.
Definition Spice.h:433
virtual Longitude solarLongitude()
Returns the solar longitude.
Definition Spice.cpp:1731
Spice(Cube &cube)
Constructs a Spice object and loads SPICE kernels using information from the label object.
Definition Spice.cpp:65
SpiceInt * m_ikCode
Instrument kernel (IK) code.
Definition Spice.h:421
virtual void instrumentBodyFixedVelocity(double v[3]) const
Returns the spacecraft velocity in body-fixed frame km/sec units.
Definition Spice.cpp:1070
SpiceRotation * m_instrumentRotation
Instrument spice rotation.
Definition Spice.h:408
SpiceInt * m_sclkCode
Spacecraft clock correlation kernel (SCLK) code.
Definition Spice.h:422
void csmInit(Cube &cube, Pvl label)
Initialize the Spice object for a CSMCamera.
Definition Spice.cpp:361
virtual void computeSolarLongitude(iTime et)
Computes the solar longitude for the given ephemeris time.
Definition Spice.cpp:1622
SpicePosition * m_instrumentPosition
Instrument spice position.
Definition Spice.h:407
bool m_allowDownsizing
Indicates whether to allow downsizing.
Definition Spice.h:412
SpiceDouble * m_endTimePadding
Kernels pvl group EndPadding keyword value.
Definition Spice.h:405
SpicePosition * m_sunPosition
Sun spice position.
Definition Spice.h:409
SpiceInt * m_bodyFrameCode
Naif's BODY_FRAME_CODE value.
Definition Spice.h:424
virtual SpiceRotation * bodyRotation() const
Accessor method for the body rotation.
Definition Spice.cpp:1833
virtual double targetCenterDistance() const
Calculates and returns the distance from the spacecraft to the target center.
Definition Spice.cpp:1135
virtual void subSolarPoint(double &lat, double &lon)
Returns the sub-solar latitude/longitude in universal coordinates (0-360 positive east,...
Definition Spice.cpp:1551
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.
Definition Spice.cpp:859
virtual iTime cacheEndTime() const
Accessor method for the cache end time.
Definition Spice.cpp:975
virtual ~Spice()
Destroys the Spice object.
Definition Spice.cpp:721
void radii(Distance r[3]) const
Returns the radii of the body in km.
Definition Spice.cpp:1147
SpiceValueType
NAIF value primitive type.
Definition Spice.h:350
@ SpiceByteCodeType
SpiceByteCode type.
Definition Spice.h:354
@ SpiceIntType
SpiceInt type.
Definition Spice.h:353
@ SpiceStringType
SpiceString type.
Definition Spice.h:352
@ SpiceDoubleType
SpiceDouble type.
Definition Spice.h:351
PvlObject * m_naifKeywords
NaifKeywords PvlObject from cube.
Definition Spice.h:428
SpiceInt naifBodyCode() const
This returns the NAIF body code of the target indicated in the labels.
Definition Spice.cpp:1158
SpiceInt naifSpkCode() const
This returns the NAIF SPK code to use when reading from SPK kernels.
Definition Spice.cpp:1167
virtual void instrumentBodyFixedPosition(double p[3]) const
Returns the spacecraft position in body-fixed frame km units.
Definition Spice.cpp:1052
PvlObject getStoredNaifKeywords() const
This returns the PvlObject that stores all of the requested Naif data and can be a replacement for fu...
Definition Spice.cpp:1215
SpiceInt naifCkCode() const
This returns the NAIF CK code to use when reading from CK kernels.
Definition Spice.cpp:1176
virtual Target * target() const
Returns a pointer to the target object.
Definition Spice.cpp:1590
SpiceInt * m_spkBodyCode
Spacecraft and planet ephemeris kernel (SPK) body code.
Definition Spice.h:423
virtual iTime time() const
Returns the ephemeris time in seconds which was used to obtain the spacecraft and sun positions.
Definition Spice.cpp:1101
SpiceInt * m_ckCode
Camera kernel (CK) code.
Definition Spice.h:420
SpiceInt * m_spkCode
Spacecraft and planet ephemeris kernel (SPK) code.
Definition Spice.h:419
bool hasKernels(Pvl &lab)
Returns true if the kernel group has kernel files.
Definition Spice.cpp:1748
virtual SpiceRotation * instrumentRotation() const
Accessor method for the instrument rotation.
Definition Spice.cpp:1844
SpiceDouble * m_cacheSize
Cache size. Note: This value is 1 for Framing cameras.
Definition Spice.h:402
void defaultInit()
Default initialize the members of the SPICE object.
Definition Spice.cpp:371
virtual SpicePosition * instrumentPosition() const
Accessor method for the instrument position.
Definition Spice.cpp:1822
SpiceInt naifIkCode() const
This returns the NAIF IK code to use when reading from instrument kernels.
Definition Spice.cpp:1185
SpiceInt naifSclkCode() const
This returns the NAIF SCLK code to use when reading from instrument kernels.
Definition Spice.cpp:1195
QString targetName() const
Returns the QString name of the target.
Definition Spice.cpp:1600
SpiceInt naifBodyFrameCode() const
This returns the NAIF body frame code.
Definition Spice.cpp:1206
void load(PvlKeyword &key, bool notab)
Loads/furnishes NAIF kernel(s)
Definition Spice.cpp:696
SpiceDouble m_uB[3]
This contains the sun position (u) in the bodyfixed reference frame (B).
Definition Spice.h:371
virtual iTime cacheStartTime() const
Accessor method for the cache start time.
Definition Spice.cpp:960
iTime * m_endTime
Corrected end (shutter close) time of the observation.
Definition Spice.h:401
iTime * m_et
Ephemeris time (read NAIF documentation for a detailed description)
Definition Spice.h:384
bool isTimeSet()
Returns true if time has been initialized.
Definition Spice.cpp:1799
QVector< QString > * m_kernels
Vector containing kernels filenames.
Definition Spice.h:397
SpiceRotation * m_bodyRotation
Body spice rotation.
Definition Spice.h:410
iTime * m_startTime
Corrected start (shutter open) time of the observation.
Definition Spice.h:400
virtual SpicePosition * sunPosition() const
Accessor method for the sun position.
Definition Spice.cpp:1811
SpiceDouble getDouble(const QString &key, int index=0)
This returns a value from the NAIF text pool.
Definition Spice.cpp:1256
SpiceInt getInteger(const QString &key, int index=0)
This returns a value from the NAIF text pool.
Definition Spice.cpp:1242
virtual void subSpacecraftPoint(double &lat, double &lon)
Returns the sub-spacecraft latitude/longitude in universal coordinates (0-360 positive east,...
Definition Spice.cpp:1500
virtual double resolution()
Virtual method that returns the pixel resolution of the sensor in meters/pix.
Definition Spice.cpp:1226
Obtain SPICE position information for a body.
@ Memcache
Object is reading from cached table.
virtual const std::vector< double > & Coordinate()
Return the current J2000 position.
virtual void SetAberrationCorrection(const QString &correction)
Set the aberration correction (light time)
Obtain SPICE rotation information for a body.
std::vector< double > Matrix()
Return the full rotation TJ as a matrix.
@ Done
Cache is downsized.
@ Yes
Downsize the cache.
@ Memcache
From cached table.
This class is used to create and store valid Isis targets.
Definition Target.h:63
std::vector< Distance > radii() const
Returns the radii of the body in km.
Definition Target.cpp:557
Parse and return pieces of a time string.
Definition iTime.h:65
double Et() const
Returns the ephemeris time (TDB) representation of the time as a double.
Definition iTime.h:126
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(const LinearAlgebra::Vector &vector, int precision)
A global function to format LinearAlgebra::Vector as a QString with the given precision.
Namespace for the standard library.