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
ShapeModel.cpp
1
5
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "ShapeModel.h"
8
9#include <QDebug>
10
11#include <algorithm>
12#include <cfloat>
13#include <iostream>
14#include <iomanip>
15#include <vector>
16
17#include <cmath>
18
19#include <SpiceUsr.h>
20#include <SpiceZfc.h>
21#include <SpiceZmc.h>
22
23#include "Distance.h"
24#include "SurfacePoint.h"
25#include "IException.h"
26#include "IString.h"
27#include "NaifStatus.h"
28#include "Spice.h"
29#include "Target.h"
30
31using namespace std;
32
33namespace Isis {
41 Initialize();
42 m_target = NULL;
43 }
44
45
57 Initialize();
58 m_target = target;
59 }
60
61
66 m_name = new QString();
68 m_hasIntersection = false;
69 m_hasNormal = false;
70 m_hasLocalNormal = false;
71 m_normal.resize(3,0.);
72 m_localNormal.resize(3, 0.);
74 }
75
76
79
80 delete m_name;
81 m_name = NULL;
82
83 delete m_surfacePoint;
84 m_surfacePoint = NULL;
85 }
86
87
88/**
89 * @brief Compute surface intersection with optional occlusion check
90 *
91 * This method sets the surface point at the given latitude, longitude. The
92 * derived model is called to get the radius at that location to complete the
93 * accuracy of the surface point, them the derived method is called to complete
94 * the intersection.
95 *
96 * @author 2017-03-23 Kris Becker
97 *
98 * @param lat Latitude of the surface point
99 * @param lon Longitude of the surface point
100 * @param observerPos Position of the observer
101 * @param backCheck Flag to indicate occlusion check
102 *
103 * @return bool True if the intersection point is valid (visable)
104 */
105 bool ShapeModel::intersectSurface(const Latitude &lat, const Longitude &lon,
106 const std::vector<double> &observerPos,
107 const bool &backCheck) {
108 // Distance radius = localRadius(lat, lon);
109 return (intersectSurface(SurfacePoint(lat, lon, localRadius(lat, lon)), observerPos, backCheck));
110 }
111
112
129 bool ShapeModel::intersectSurface(const SurfacePoint &surfpt,
130 const std::vector<double> &observerPos,
131 const bool &backCheck) {
132
133 // The default behavior is to set the point in the model without
134 // intersection tests at all
135 setSurfacePoint(surfpt);
136 return (true);
137 }
138
145
161
162 // Sanity check on state
163 if ( !hasIntersection() ) {
164 QString msg = "An intersection must be defined before computing the surface normal.";
165 throw IException(IException::Programmer, msg, _FILEINFO_);
166 }
167
168 if ( !surfaceIntersection()->Valid() ) {
169 QString msg = "The surface point intersection must be valid to compute the surface normal.";
170 throw IException(IException::Programmer, msg, _FILEINFO_);
171 }
172
173 if (!hasValidTarget()) {
174 QString msg = "A valid target must be defined before computing the surface normal.";
175 throw IException(IException::Programmer, msg, _FILEINFO_);
176 }
177
178 // Get the coordinates of the current surface point
179 SpiceDouble pB[3];
181
182 // Get the body radii and compute the true normal of the ellipsoid
183 std::vector<double> norm(3);
184 // need a case for target == NULL
185 std::vector<Distance> radii = targetRadii();
187 surfnm_c(radii[0].kilometers(), radii[1].kilometers(), radii[2].kilometers(),
188 pB, &norm[0]);
190
191 setNormal(norm);
192 setHasNormal(true);
193 }
194
195
214 double ShapeModel::emissionAngle(const std::vector<double> &observerBodyFixedPosition) {
215
216 // Calculate the surface normal if we haven't yet
218
219 // Get vector from center of body to surface point
220 SpiceDouble pB[3];
221 pB[0] = surfaceIntersection()->GetX().kilometers();
222 pB[1] = surfaceIntersection()->GetY().kilometers();
223 pB[2] = surfaceIntersection()->GetZ().kilometers();
224
225 // Get vector from surface point to observer and normalize it
226 SpiceDouble psB[3], upsB[3], dist;
227 vsub_c((ConstSpiceDouble *) &observerBodyFixedPosition[0], pB, psB);
228 unorm_c(psB, upsB, &dist);
229
230 double angle = vdot_c((SpiceDouble *) &m_normal[0], upsB);
231 if(angle > 1.0) return 0.0;
232 if(angle < -1.0) return 180.0;
233 return acos(angle) * RAD2DEG;
234 }
235
236
245
246
261 double ShapeModel::incidenceAngle(const std::vector<double> &illuminatorBodyFixedPosition) {
262
263 // Calculate the surface normal if we haven't yet.
265
266 // Get vector from center of body to surface point
267 SpiceDouble pB[3];
268 pB[0] = surfaceIntersection()->GetX().kilometers();
269 pB[1] = surfaceIntersection()->GetY().kilometers();
270 pB[2] = surfaceIntersection()->GetZ().kilometers();
271
272 // Get vector from surface point to sun and normalize it
273 SpiceDouble puB[3], upuB[3], dist;
274 vsub_c((SpiceDouble *) &illuminatorBodyFixedPosition[0], pB, puB);
275 unorm_c(puB, upuB, &dist);
276
277 double angle = vdot_c((SpiceDouble *) &m_normal[0], upuB);
278 if(angle > 1.0) return 0.0;
279 if(angle < -1.0) return 180.0;
280 return acos(angle) * RAD2DEG;
281 }
282
283
296 bool ShapeModel::intersectEllipsoid(const std::vector<double> observerBodyFixedPosition,
297 const std::vector<double> &observerLookVectorToTarget) {
298
299 // Clear out previous surface point and normal
301
302 SpiceDouble lookB[3];
303
304 // This memcpy does:
305 // lookB[0] = observerLookVectorToTarget[0];
306 // lookB[1] = observerLookVectorToTarget[1];
307 // lookB[2] = observerLookVectorToTarget[2];
308 memcpy(lookB,&observerLookVectorToTarget[0], 3*sizeof(double));
309
310 // get target radii
311 std::vector<Distance> radii = targetRadii();
312 SpiceDouble a = radii[0].kilometers();
313 SpiceDouble b = radii[1].kilometers();
314 SpiceDouble c = radii[2].kilometers();
315
316 // check if observer look vector intersects the target
317 SpiceDouble intersectionPoint[3];
318 SpiceBoolean intersected = false;
319
321 surfpt_c((SpiceDouble *) &observerBodyFixedPosition[0], lookB, a, b, c,
322 intersectionPoint, &intersected);
324
325 if (intersected) {
326 m_surfacePoint->FromNaifArray(intersectionPoint);
327 m_hasIntersection = true;
328 }
329 else {
330 m_hasIntersection = false;
331 }
332
334 return m_hasIntersection;
335 }
336
337
353 double ShapeModel::phaseAngle(const std::vector<double> &observerBodyFixedPosition,
354 const std::vector<double> &illuminatorBodyFixedPosition) {
355
356 // Get vector from center of body to surface point
357 SpiceDouble pB[3];
358 pB[0] = surfaceIntersection()->GetX().kilometers();
359 pB[1] = surfaceIntersection()->GetY().kilometers();
360 pB[2] = surfaceIntersection()->GetZ().kilometers();
361
362 // Get vector from surface point to observer and normalize it
363 SpiceDouble psB[3], upsB[3], dist;
364 vsub_c((SpiceDouble *) &observerBodyFixedPosition[0], pB, psB);
365 unorm_c(psB, upsB, &dist);
366
367 // Get vector from surface point to sun and normalize it
368 SpiceDouble puB[3], upuB[3];
369 vsub_c((SpiceDouble *) &illuminatorBodyFixedPosition[0], pB, puB);
370 unorm_c(puB, upuB, &dist);
371
372 double angle = vdot_c(upsB, upuB);
373
374 // How can these lines be tested???
375 if(angle > 1.0) return 0.0;
376 if(angle < -1.0) return 180.0;
377 return acos(angle) * RAD2DEG;
378 }
379
380
390
391
400
401
408 return m_hasNormal;
409 }
410
411
418 return m_hasLocalNormal;
419 }
420
421
429
430
440 std::vector<double> ShapeModel::normal() {
441 if (m_hasNormal ) {
442 return m_normal;
443 }
444 else {
445 QString message = "The normal has not been computed.";
446 throw IException(IException::Unknown, message, _FILEINFO_);
447 }
448 }
449
459 std::vector<double> ShapeModel::localNormal() {
460 if (m_hasLocalNormal ) {
461 return m_localNormal;
462 }
463 else {
464 QString message = "The local normal has not been computed.";
465 throw IException(IException::Unknown, message, _FILEINFO_);
466 }
467 }
468
488 bool ShapeModel::isVisibleFrom(const std::vector<double> observerPos,
489 const std::vector<double> lookDirection) {
490 if ( hasIntersection() ) {
491 if ( fabs(emissionAngle(observerPos)) <= 90.0 ) {
492 return (true);
493 }
494 }
495
496 // All other conditions indicate the point is not visable from the observer
497 return (false);
498 }
499
507 return (m_target != NULL);
508 }
509
510
522 std::vector<Distance> ShapeModel::targetRadii() const {
523 if (hasValidTarget()) {
524 return m_target->radii();
525 }
526 else {
527 QString message = "Unable to find target radii for ShapeModel. Target is NULL. ";
528 throw IException(IException::Programmer, message, _FILEINFO_);
529 }
530 }
531
532
544 void ShapeModel::setNormal(const std::vector<double> normal) {
545 if (m_hasIntersection) {
547 m_hasNormal = true;
548 }
549 else {
550 QString message = "No intersection point is known. A normal cannot be set.";
551 throw IException(IException::Unknown, message, _FILEINFO_);
552 }
553 }
554
566 void ShapeModel::setLocalNormal(const std::vector<double> normal) {
567 if (m_hasIntersection) {
569 m_hasLocalNormal = true;
570 }
571 else {
572 QString message = "No intersection point is known. A local normal cannot be set.";
573 throw IException(IException::Unknown, message, _FILEINFO_);
574 }
575 }
576
577
591 void ShapeModel::setNormal(const double a, const double b, const double c) {
592 if (m_hasIntersection) {
593 m_normal[0] = a;
594 m_normal[1] = b;
595 m_normal[2] = c;
596 m_hasNormal = true;
597 }
598 else {
599 QString message = "No intersection point is known. A normal cannot be set.";
600 throw IException(IException::Unknown, message, _FILEINFO_);
601 }
602 }
603
617 void ShapeModel::setLocalNormal(const double a, const double b, const double c) {
618 if (m_hasIntersection) {
619 m_localNormal[0] = a;
620 m_localNormal[1] = b;
621 m_localNormal[2] = c;
622 m_hasLocalNormal = true;
623 }
624 else {
625 QString message = "No intersection point is known. A local normal cannot be set.";
626 throw IException(IException::Unknown, message, _FILEINFO_);
627 }
628 }
629
636 void ShapeModel::setName(QString name) {
637 *m_name = name;
638 }
639
640
647 QString ShapeModel::name() const{
648 return *m_name;
649 }
650
651
660 setHasNormal(false);
661 setHasLocalNormal(false);
662 }
663
664
670 void ShapeModel::setSurfacePoint(const SurfacePoint &surfacePoint) {
671 *m_surfacePoint = surfacePoint;
672
673 // Update status of intersection and normal
674 m_hasIntersection = true;
675 // Set normal as not calculated
676 setHasNormal(false);
677 setHasLocalNormal(false);
678 }
679
680
687 void ShapeModel::setHasNormal(bool status) {
688 m_hasNormal = status;
689 }
690
698 m_hasLocalNormal = status;
699 }
700
701
710 return m_target->spice()->resolution();
711 }
712 else {
713 QString message = "No valid intersection point for computing resolution.";
714 throw IException(IException::Programmer, message, _FILEINFO_);
715 }
716 }
717
718}
double kilometers() const
Get the displacement in kilometers.
This class is designed to encapsulate the concept of a Latitude.
Definition Latitude.h:51
This class is designed to encapsulate the concept of a Longitude.
Definition Longitude.h:40
static void CheckErrors(bool resetNaif=true)
This method looks for any naif errors that might have occurred.
double resolution()
Convenience method to get pixel resolution (m/pix) at current intersection point.
virtual void clearSurfacePoint()
Clears or resets the current surface point.
void setHasNormal(bool status)
Sets the flag to indicate whether this ShapeModel has a surface normal.
bool hasIntersection()
Returns intersection status.
void Initialize()
Initializes the ShapeModel private variables.
bool m_hasNormal
indicates normal has been computed
Definition ShapeModel.h:184
virtual ~ShapeModel()=0
Virtual destructor to destroy the ShapeModel object.
bool hasLocalNormal() const
Returns surface point local normal status.
void setHasIntersection(bool b)
Sets the flag to indicate whether this ShapeModel has an intersection.
void setNormal(const std::vector< double >)
Sets the surface normal for the currect intersection point.
void setLocalNormal(const std::vector< double >)
Sets the local normal for the currect intersection point.
virtual SurfacePoint * surfaceIntersection() const
Returns the surface intersection for this ShapeModel.
SurfacePoint * m_surfacePoint
< Name of the shape
Definition ShapeModel.h:189
bool m_hasEllipsoidIntersection
Indicates the ellipsoid was successfully intersected.
Definition ShapeModel.h:182
bool hasValidTarget() const
Returns the status of the target.
virtual double emissionAngle(const std::vector< double > &sB)
Computes and returns emission angle, in degrees, given the observer position.
QString name() const
Gets the shape name.
virtual bool isVisibleFrom(const std::vector< double > observerPos, const std::vector< double > lookDirection)
Default occulsion implementation.
bool intersectEllipsoid(const std::vector< double > observerPosRelativeToTarget, const std::vector< double > &observerLookVectorToTarget)
Finds the intersection point on the ellipsoid model using the given position of the observer (spacecr...
bool m_hasIntersection
indicates good intersection exists
Definition ShapeModel.h:183
virtual double incidenceAngle(const std::vector< double > &uB)
Computes and returns incidence angle, in degrees, given the illuminator position.
virtual void calculateSurfaceNormal()
Calculate surface normal.
bool hasEllipsoidIntersection()
Returns the status of the ellipsoid model intersection.
virtual void setSurfacePoint(const SurfacePoint &surfacePoint)
Set surface intersection point.
virtual double phaseAngle(const std::vector< double > &sB, const std::vector< double > &uB)
Computes and returns phase angle, in degrees, given the positions of the observer and illuminator.
virtual std::vector< double > normal()
Returns the surface normal at the current intersection point.
virtual std::vector< double > localNormal()
Returns the local surface normal at the current intersection point.
std::vector< Distance > targetRadii() const
Returns the radii of the body in km.
void setHasLocalNormal(bool status)
Sets the flag to indicate whether this ShapeModel has a local normal.
ShapeModel()
Default constructor creates ShapeModel object, initializing name to an empty string,...
virtual void calculateDefaultNormal()
Compute the true surface normal vector of an ellipsoid.
bool m_hasLocalNormal
indicates local normal has been computed
Definition ShapeModel.h:185
std::vector< double > m_normal
Surface normal of current intersection point.
Definition ShapeModel.h:186
std::vector< double > m_localNormal
Local normal of current intersection point.
Definition ShapeModel.h:187
bool hasNormal() const
Returns surface point normal status.
void setName(QString name)
Sets the shape name.
This class defines a body-fixed surface point.
void ToNaifArray(double naifOutput[3]) const
A naif array is a c-style array of size 3.
This class is used to create and store valid Isis targets.
Definition Target.h:63
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
Namespace for the standard library.