Isis 3 Programmer Reference
Target.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "Target.h"
8
9#include "Angle.h"
10#include "Distance.h"
11#include "EllipsoidShape.h"
12#include "FileName.h"
13#include "IException.h"
14#include "NaifStatus.h"
15#include "Pvl.h"
16#include "PvlGroup.h"
17#include "ShapeModelFactory.h"
18#include "SpecialPixel.h"
19#include "Spice.h"
20
21
22using namespace std;
23
24namespace Isis {
25
37 // TODO: what is needed to initialize?
38 Target::Target(Spice *spice, Pvl &lab) {
39
40 // Initialize members
41 init();
42 m_bodyCode = new SpiceInt;
43 m_systemCode = new SpiceInt;
44 m_radii.resize(3, Distance());
45
46 m_spice = spice;
47
48 // If we get this far, we know we have a kernels group. Spice requires it.
49 PvlGroup &kernels = lab.findGroup("Kernels", Pvl::Traverse);
50
51 PvlGroup &inst = lab.findGroup("Instrument", Pvl::Traverse);
52 m_name = new QString;
53 *m_name = inst["TargetName"][0];
54 QString trykey = "NaifIkCode";
55
56 m_systemName = new QString;
57
58 if (kernels.hasKeyword("NaifFrameCode")) {
59 trykey = "NaifFrameCode";
60 }
61
62 if (name().toUpper() == "SKY") {
63 m_radii[0] = m_radii[1] = m_radii[2] = Distance(1000.0, Distance::Meters);
64 m_sky = true;
65 int ikCode = toInt(kernels[trykey][0]);
66 *m_bodyCode = ikCode / 1000;
67 // Check for override in kernel group
68 if (kernels.hasKeyword("NaifSpkCode")) {
69 *m_bodyCode = (int) kernels["NaifSpkCode"];
70 }
71
72 *m_systemCode = -1;
73 (*m_systemName).append("THE COSMOS");
74
75 }
76 else {
78 m_sky = false;
79
80 *m_systemCode = (*m_bodyCode/100)*100 + 99;
81
82 SpiceChar naifBuf[40];
83 SpiceBoolean found;
84 bodc2n_c((SpiceInt) *m_systemCode, sizeof(naifBuf), naifBuf, &found);
86 string s(naifBuf);
87 (*m_systemName).append(s.c_str());
88
89 // QString radiiKey = "BODY" + QString((BigInt) naifBodyCode()) + "_RADII";
90 // m_radii[0] = Distance(getDouble(radiiKey, 0), Distance::Kilometers);
91 // m_radii[1] = Distance(getDouble(radiiKey, 1), Distance::Kilometers);
92 // m_radii[2] = Distance(getDouble(radiiKey, 2), Distance::Kilometers);
93 }
94 // Override it if it exists in the labels
95 if (kernels.hasKeyword("NaifBodyCode")) {
96 *m_bodyCode = (int) kernels["NaifBodyCode"];
97 }
99 }
100
101
110 // Initialize everything to null
111 m_bodyCode = new SpiceInt;
112 m_systemCode = new SpiceInt;
113 m_name = NULL;
114 m_systemName = NULL;
115 m_spice = NULL;
116 m_radii.resize(3, Distance());
117 init();
118
119 PvlGroup &inst = label.findGroup("Instrument", Pvl::Traverse);
120 QString targetName = inst["TargetName"][0];
121 setName(targetName);
122
123 PvlGroup &kernels = label.findGroup("Kernels", Pvl::Traverse);
124
125 QString trykey = "NaifIkCode";
126
127 m_systemName = new QString;
128
129 if (kernels.hasKeyword("NaifFrameCode")) {
130 trykey = "NaifFrameCode";
131 }
132
133 if (name().toUpper() == "SKY" && kernels.hasKeyword(trykey)) {
134 m_radii[0] = m_radii[1] = m_radii[2] = Distance(1000.0, Distance::Meters);
135 m_sky = true;
136 int ikCode = toInt(kernels[trykey][0]);
137 *m_bodyCode = ikCode / 1000;
138 // Check for override in kernel group
139 if (kernels.hasKeyword("NaifSpkCode")) {
140 *m_bodyCode = (int) kernels["NaifSpkCode"];
141 }
142
143 *m_systemCode = -1;
144 (*m_systemName).append("THE COSMOS");
145 }
146
147 m_shape = ShapeModelFactory::create(this, label);
148 }
149
150
160 m_bodyCode = NULL;
161 m_systemCode = NULL;
162 m_name = NULL;
163 m_systemName = NULL;
164 m_spice = NULL;
165 init();
166 }
167
168
178 m_shape = NULL;
179 m_originalShape = NULL;
180 m_sky = false;
181 }
182
183
189
190 delete m_bodyCode;
191 m_bodyCode = NULL;
192
193 delete m_systemCode;
194 m_systemCode = NULL;
195
196 delete m_name;
197 m_name = NULL;
198
199 delete m_systemName;
200 m_systemName = NULL;
201
202 if (m_radii.size() != 0) {
203 m_radii.clear();
204 }
205
206 delete m_originalShape;
207 m_originalShape = NULL;
208
209 delete m_shape;
210 m_shape = NULL;
211 }
212
213
215 bool Target::isSky() const {
216 return m_sky;
217 }
218
219
226 SpiceInt Target::lookupNaifBodyCode(Pvl &lab) const {
227 SpiceInt code;
228 try {
229 code = lookupNaifBodyCode(*m_name);
230 return code;
231 }
232 catch (IException &e) {
233 try {
234 // Get body code from Isis Naif object if it exists or Naif data pool
235 if (m_spice) {
236 code = m_spice->getInteger("BODY_CODE", 0);
237 return code;
238 }
239 // getInteger automatically calls Spice::readValue which looks in the NaifKeywords
240 else if (lab.hasObject("NaifKeywords")
241 && lab.findObject("NaifKeywords").hasKeyword("BODY_CODE") ) {
242 code = int(lab.findObject("NaifKeywords").findKeyword("BODY_CODE"));
243 return code;
244 }
245 else {
246 throw IException(e,
248 "BODY_CODE not found for this Target.",
249 _FILEINFO_);
250 }
251 }
252 catch (IException &e2) {
253 e.append(e2);
254 throw IException(e,
256 "Unable to look up NAIF body code for this Target.",
257 _FILEINFO_);
258 }
259 }
260 }
261
262
269 SpiceInt Target::lookupNaifBodyCode(QString name) {
270
272 SpiceInt code;
273 SpiceBoolean found;
274 bodn2c_c(name.toLatin1().data(), &code, &found);
275 if (!found) {
276 QString msg = "Could not convert Target [" + name +
277 "] to NAIF body code";
278 throw IException(IException::Io, msg, _FILEINFO_);
279 }
281 return code;
282
283 }
284
285
300 PvlGroup Target::radiiGroup(Pvl &cubeLab, const PvlGroup &mapGroup) {
301 PvlGroup mapping = mapGroup;
302
303 // Check to see if the mapGroup already has the target radii.
304 // If BOTH radii are already in the mapGroup then just return the given
305 // mapping group as is.
306 if (mapping.hasKeyword("EquatorialRadius")
307 && mapping.hasKeyword("PolarRadius")) {
308 return mapping;
309 }
310
311 // If radii values are not in the given mapping group, we will get the target from the mapping
312 // group or cube label and attempt to use NAIF routines to find the radii.
313 QString target = "";
314 try {
315 if (mapping.hasKeyword("TargetName")) {
316 target = mapping["TargetName"][0];
317 }
318
319 // if target name not found in mapping group or value was empty string, try instrument group
320 if (target.isEmpty()) {
321 bool hasInstrumentGroup = cubeLab.findObject("IsisCube").hasGroup("Instrument");
322 if (hasInstrumentGroup) {
323 PvlGroup inst = cubeLab.findGroup("Instrument", Pvl::Traverse);
324 if (inst.hasKeyword("TargetName")) {
325 target = inst["TargetName"][0];
326 mapping.addKeyword( PvlKeyword("TargetName", target), PvlContainer::Replace );
327 }
328 }
329 }
330
331 // target name still not found, throw error
332 if (target.isEmpty()) {
334 "Unable to find a TargetName keyword in the given PVL.",
335 _FILEINFO_);
336 }
337
338 // first, attempt to use cached values or run NAIF routine on the target name to get the
339 // radii values. if this fails, the exception will be caught and we will try to find
340 // radii in the NaifKeywords object of the labels
342
343 // Successfully found radii using target name.
344 // Copy the EquatorialRadius and PolorRadius and we are done.
345 mapping.addKeyword( radii.findKeyword("EquatorialRadius"), PvlContainer::Replace );
346 mapping.addKeyword( radii.findKeyword("PolarRadius"), PvlContainer::Replace );
347 return mapping;
348 }
349 catch (IException &e) {
350 // If all previous attempts fail, look for the radii using the body frame
351 // code in the NaifKeywords object.
352 // Note: We will only look in the given label for the values after SPICELIB
353 // routines have failed, to preserve backwards compatibility (since this
354 // label check is new).
355 if (cubeLab.hasObject("NaifKeywords")) {
356
357 PvlObject naifKeywords = cubeLab.findObject("NaifKeywords");
358
359 // Try using the target bodycode_RADII keyword in the NaifKeywords PVL object
360
361 try {
362
363 SpiceInt bodyCode = 0;
364 try {
365 // Try using the target bodycode_RADII keyword in the NaifKeywords PVL object
366 bodyCode = lookupNaifBodyCode(target);
367 }
368 catch (IException &e2) {
369 throw IException(e, IException::Unknown, e2.what(), _FILEINFO_);
370 }
371 QString radiiKeyword = "BODY" + toString(int(bodyCode)) + "_RADII";
372
373 if (naifKeywords.hasKeyword(radiiKeyword)) {
374 PvlKeyword radii = naifKeywords.findKeyword(radiiKeyword);
375 mapping.addKeyword( PvlKeyword("EquatorialRadius",
376 toString(toDouble(radii[0]) * 1000.0), "meters"),
377 PvlContainer::Replace);
378 mapping.addKeyword( PvlKeyword("PolarRadius",
379 toString(toDouble(radii[2]) * 1000.0), "meters"),
380 PvlContainer::Replace);
381 return mapping;
382 }
383 }
384 catch (IException &e) {
385 // Try using the value of the BODY_FRAME_CODE keyword in the NaifKeywords PVL object
386 if (naifKeywords.hasKeyword("BODY_FRAME_CODE")) {
387
388 PvlKeyword bodyFrame = naifKeywords.findKeyword("BODY_FRAME_CODE");
389 QString radiiKeyword = "BODY" + bodyFrame[0] + "_RADII";
390
391 if (naifKeywords.hasKeyword(radiiKeyword)) {
392 PvlKeyword radii = naifKeywords.findKeyword(radiiKeyword);
393 mapping.addKeyword( PvlKeyword("EquatorialRadius",
394 toString(toDouble(radii[0]) * 1000.0),
395 "meters"),
396 PvlContainer::Replace);
397 mapping.addKeyword( PvlKeyword("PolarRadius",
398 toString(toDouble(radii[2]) * 1000.0),
399 "meters"),
400 PvlContainer::Replace);
401 return mapping;
402 }
403 }
404 }
405 }
406
407 // If we get this far, we know the cube has no NaifKeywords object and previous attempts to
408 // find radii in the mapping group or using spice IDs have failed
409 QString msg = "Unable to find Equatorial and Polar radii for target [" + target + "].";
410 throw IException(e, IException::Unknown, msg, _FILEINFO_);
411 }
412 }
413
414
428 PvlGroup Target::radiiGroup(QString target) {
429
430 if (target.isEmpty()) {
432 "Unable to find TargetRadii. The given TargetName is empty.",
433 _FILEINFO_);
434 }
435
436 static QMap<QString, PvlGroup> cachedResults;
437
438 PvlGroup mapping("Mapping");
439 if (cachedResults.contains(target)) {
440 mapping = cachedResults[target];
441 }
442 else {
443
444 SpiceInt bodyCode = 0;
445 try {
446 bodyCode = lookupNaifBodyCode(target);
447 }
448 catch (IException &e) {
449 QString msg = "Unable to find target radii for given target ["
450 + target + "].";
451 throw IException(IException::Io, msg, _FILEINFO_);
452 }
453
454 PvlGroup radiiGroup = Target::radiiGroup(int(bodyCode));
455 mapping += PvlKeyword("TargetName", target);
456 mapping += radiiGroup.findKeyword("EquatorialRadius");
457 mapping += radiiGroup.findKeyword("PolarRadius");
458 cachedResults[target] = mapping;
459 }
460
461 return mapping;
462 }
463
464
477
478 // Load the most recent target attitude and shape kernel for NAIF
479 static bool pckLoaded = false;
480
482
483 FileName kern("$base/kernels/pck/pck?????.tpc");
484 kern = kern.highestVersion();
485 QString kernName = kern.expanded();
486
487 if(!pckLoaded) {
488 furnsh_c(kernName.toLatin1().data());
489 pckLoaded = true;
490 }
491
492 // Get the radii from NAIF
493 SpiceInt n;
494 SpiceDouble radii[3];
495 bodvar_c(bodyCode, "RADII", &n, radii);
496
497 try {
499 }
500 catch (IException &e) {
501 QString msg = "Unable to find radii for target code [" + toString(bodyCode)
502 + "]. Target code was not found in furnished kernels.";
503
504 throw IException(e, IException::Unknown, msg, _FILEINFO_);
505 }
506
508 radiiGroup += PvlKeyword("EquatorialRadius", toString(radii[0] * 1000.0), "meters");
509 radiiGroup += PvlKeyword("PolarRadius", toString(radii[2] * 1000.0), "meters");
510
511 return radiiGroup;
512
513 }
514
515
522 SpiceInt Target::naifBodyCode() const {
523 return *m_bodyCode;
524 }
525
526
536 return *m_systemCode;
537 }
538
539
541 QString Target::name() const {
542 return *m_name;
543 }
544
545
547 QString Target::systemName() const {
548 return *m_systemName;
549 }
550
551
557 std::vector<Distance> Target::radii() const {
558 return m_radii;
559 }
560
561
562 int Target::frameType() {
563 return spice()->bodyRotation()->getFrameType();
564 }
565
566
567 std::vector<Angle> Target::poleRaCoefs() {
568 return spice()->bodyRotation()->poleRaCoefs();
569 }
570
571
572 std::vector<Angle> Target::poleDecCoefs() {
573 return spice()->bodyRotation()->poleDecCoefs();
574 }
575
576
577 std::vector<Angle> Target::pmCoefs() {
578 return spice()->bodyRotation()->pmCoefs();
579 }
580
581
582 std::vector<double> Target::poleRaNutPrecCoefs() {
583 return spice()->bodyRotation()->poleRaNutPrecCoefs();
584 }
585
586
587 std::vector<double> Target::poleDecNutPrecCoefs() {
588 return spice()->bodyRotation()->poleDecNutPrecCoefs();
589 }
590
591
592 std::vector<double> Target::pmNutPrecCoefs() {
593 return spice()->bodyRotation()->pmNutPrecCoefs();
594 }
595
596
597 std::vector<Angle> Target::sysNutPrecConstants() {
598 return spice()->bodyRotation()->sysNutPrecConstants();
599 }
600
601
602 std::vector<Angle> Target::sysNutPrecCoefs() {
603 return spice()->bodyRotation()->sysNutPrecCoefs();
604 }
605
606
611 if (m_shape->name() != "Ellipsoid") {
612 // Nothing to do
613 return;
614 }
615 // If we don't have a saved original shape, just stick to the current shape
616 else if (m_originalShape == NULL) {
617 // Nothing to do
618 return;
619 }
621 m_originalShape = NULL;
622 }
623
624
629 // Save the current shape to restore later
631 m_shape = new EllipsoidShape(this);
632 }
633
634
640 void Target::setRadii(std::vector<Distance> radii) {
641 if (m_radii.size() < 3) {
642 m_radii.resize(3, Distance());
643 }
644 m_radii[0] = radii[0];
645 m_radii[1] = radii[1];
646 m_radii[2] = radii[2];
647 }
648
649
657 void Target::setName(QString name) {
658 if (m_name == NULL) {
659 m_name = new QString;
660 }
661 *m_name = name;
662 }
663
664
672 void Target::setSpice(Spice *spice) {
673 m_spice = spice;
674 }
675
676
681 return m_shape;
682 }
683
684
689 return m_spice;
690 }
691}
Distance measurement, usually in meters.
Definition Distance.h:34
@ Meters
The distance is being specified in meters.
Definition Distance.h:43
Define shapes and provide utilities for ISIS targets.
File name manipulation and expansion.
Definition FileName.h:100
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ Io
A type of error that occurred when performing an actual I/O operation.
Definition IException.h:155
static void CheckErrors(bool resetNaif=true)
This method looks for any naif errors that might have occurred.
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
A single keyword-value pair.
Definition PvlKeyword.h:87
Contains Pvl Groups and Pvl Objects.
Definition PvlObject.h:61
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
Definition PvlObject.h:276
@ Traverse
Search child objects.
Definition PvlObject.h:158
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition PvlObject.h:129
static ShapeModel * create(Target *target, Pvl &pvl)
Construct a valid shape model from the given target and contents of kernels group.
Define shapes and provide utilities for Isis targets.
Definition ShapeModel.h:66
QString name() const
Gets the shape name.
Obtain SPICE information for a spacecraft.
Definition Spice.h:283
virtual SpiceRotation * bodyRotation() const
Accessor method for the body rotation.
Definition Spice.cpp:1623
SpiceInt getInteger(const QString &key, int index=0)
This returns a value from the NAIF text pool.
Definition Spice.cpp:1032
SpiceInt naifBodyCode() const
This returns the NAIF body code of the target.
Definition Target.cpp:522
SpiceInt * m_systemCode
The NaifBodyCode of the targets planetary system If the target is sky, then what should this be?...
Definition Target.h:116
~Target()
Destroys the Target.
Definition Target.cpp:187
void init()
Initialize member variables.
Definition Target.cpp:177
Target()
Constructs an empty Target object.
Definition Target.cpp:159
QString * m_systemName
name of the planetary system of the target
Definition Target.h:119
void setSpice(Spice *spice)
Set the Spice pointer for the Target.
Definition Target.cpp:672
void setRadii(std::vector< Distance > radii)
Sets the radii of the body.
Definition Target.cpp:640
QString * m_name
target name
Definition Target.h:118
Spice * spice() const
Return the spice object.
Definition Target.cpp:688
static PvlGroup radiiGroup(QString target)
Creates a Pvl Group with keywords TargetName, EquitorialRadius, and PolarRadius.
Definition Target.cpp:428
std::vector< Distance > m_radii
target radii
Definition Target.h:120
void setShapeEllipsoid()
Set the shape to the ellipsoid and save the original shape.
Definition Target.cpp:628
std::vector< Distance > radii() const
Returns the radii of the body in km.
Definition Target.cpp:557
ShapeModel * m_shape
target shape model
Definition Target.h:122
ShapeModel * shape() const
Return the shape.
Definition Target.cpp:680
static SpiceInt lookupNaifBodyCode(QString name)
This returns the NAIF body code of the target indicated in the labels.
Definition Target.cpp:269
SpiceInt naifPlanetSystemCode() const
This returns the NAIF planet system body code of the target.
Definition Target.cpp:535
SpiceInt * m_bodyCode
The NaifBodyCode value, if it exists in the labels.
Definition Target.h:112
bool isSky() const
Return if our target is the sky.
Definition Target.cpp:215
QString name() const
Return target name.
Definition Target.cpp:541
Spice * m_spice
parent Spice object, needed to get pixel resolution in ShapeModels
Definition Target.h:129
void restoreShape()
Restores the shape to the original after setShapeEllipsoid has overridden it.
Definition Target.cpp:610
QString systemName() const
Return planet system name.
Definition Target.cpp:547
bool m_sky
flag indicating target is the sky
Definition Target.h:123
ShapeModel * m_originalShape
target original shape model
Definition Target.h:121
void setName(QString name)
Set the name for the Target.
Definition Target.cpp:657
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
int toInt(const QString &string)
Global function to convert from a string to an integer.
Definition IString.cpp:93
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition IString.cpp:149
Namespace for the standard library.