Isis 3 Programmer Reference
ShapeModel.cpp
1 
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 
31 using namespace std;
32 
33 namespace Isis {
40  ShapeModel::ShapeModel() {
41  Initialize();
42  m_target = NULL;
43  }
44 
45 
56  ShapeModel::ShapeModel(Target *target) {
57  Initialize();
58  m_target = target;
59  }
60 
61 
65  void ShapeModel::Initialize() {
66  m_name = new QString();
67  m_surfacePoint = new SurfacePoint();
68  m_hasIntersection = false;
69  m_hasNormal = false;
70  m_normal.resize(3,0.);
71  m_hasEllipsoidIntersection = false;
72  }
73 
74 
76  ShapeModel::~ShapeModel() {
77 
78  delete m_name;
79  m_name = NULL;
80 
81  delete m_surfacePoint;
82  m_surfacePoint = NULL;
83  }
84 
85 
103  bool ShapeModel::intersectSurface(const Latitude &lat, const Longitude &lon,
104  const std::vector<double> &observerPos,
105  const bool &backCheck) {
106  // Distance radius = localRadius(lat, lon);
107  return (intersectSurface(SurfacePoint(lat, lon, localRadius(lat, lon)), observerPos, backCheck));
108  }
109 
110 
127  bool ShapeModel::intersectSurface(const SurfacePoint &surfpt,
128  const std::vector<double> &observerPos,
129  const bool &backCheck) {
130 
131  // The default behavior is to set the point in the model without
132  // intersection tests at all
133  setSurfacePoint(surfpt);
134  return (true);
135  }
136 
140  void ShapeModel::calculateEllipsoidalSurfaceNormal() {
141  // The below code is not truly normal unless the ellipsoid is a sphere. TODO Should this be
142  // fixed? Send an email asking Jeff and Stuart. See Naif routine surfnm.c to get the true
143  // for an ellipsoid. For testing purposes to match old results do as Isis currently does until
144  // Jeff and Stuart respond.
145 
146  if (!m_hasIntersection || !surfaceIntersection()->Valid()) {
147  QString msg = "A valid intersection must be defined before computing the surface normal";
148  throw IException(IException::Programmer, msg, _FILEINFO_);
149  }
150 
151  // Get the coordinates of the current surface point
152  SpiceDouble pB[3];
153  pB[0] = surfaceIntersection()->GetX().kilometers();
154  pB[1] = surfaceIntersection()->GetY().kilometers();
155  pB[2] = surfaceIntersection()->GetZ().kilometers();
156 
157  // Unitize the vector
158  SpiceDouble upB[3];
159  SpiceDouble dist;
160  unorm_c(pB, upB, &dist);
161  memcpy(&m_normal[0], upB, sizeof(double) * 3);
162 
163  m_hasNormal = true;
164  }
165 
166 
185  double ShapeModel::emissionAngle(const std::vector<double> &observerBodyFixedPosition) {
186 
187  // Calculate the surface normal if we haven't yet
188  if (!hasNormal()) calculateDefaultNormal();
189 
190  // Get vector from center of body to surface point
191  SpiceDouble pB[3];
192  pB[0] = surfaceIntersection()->GetX().kilometers();
193  pB[1] = surfaceIntersection()->GetY().kilometers();
194  pB[2] = surfaceIntersection()->GetZ().kilometers();
195 
196  // Get vector from surface point to observer and normalize it
197  SpiceDouble psB[3], upsB[3], dist;
198  vsub_c((ConstSpiceDouble *) &observerBodyFixedPosition[0], pB, psB);
199  unorm_c(psB, upsB, &dist);
200 
201  double angle = vdot_c((SpiceDouble *) &m_normal[0], upsB);
202  if(angle > 1.0) return 0.0;
203  if(angle < -1.0) return 180.0;
204  return acos(angle) * RAD2DEG;
205  }
206 
207 
213  bool ShapeModel::hasEllipsoidIntersection() {
214  return m_hasEllipsoidIntersection;
215  }
216 
217 
232  double ShapeModel::incidenceAngle(const std::vector<double> &illuminatorBodyFixedPosition) {
233 
234  // Calculate the surface normal if we haven't yet.
235  if (!m_hasNormal) calculateDefaultNormal();
236 
237  // Get vector from center of body to surface point
238  SpiceDouble pB[3];
239  pB[0] = surfaceIntersection()->GetX().kilometers();
240  pB[1] = surfaceIntersection()->GetY().kilometers();
241  pB[2] = surfaceIntersection()->GetZ().kilometers();
242 
243  // Get vector from surface point to sun and normalize it
244  SpiceDouble puB[3], upuB[3], dist;
245  vsub_c((SpiceDouble *) &illuminatorBodyFixedPosition[0], pB, puB);
246  unorm_c(puB, upuB, &dist);
247 
248  double angle = vdot_c((SpiceDouble *) &m_normal[0], upuB);
249  if(angle > 1.0) return 0.0;
250  if(angle < -1.0) return 180.0;
251  return acos(angle) * RAD2DEG;
252  }
253 
254 
267  bool ShapeModel::intersectEllipsoid(const std::vector<double> observerBodyFixedPosition,
268  const std::vector<double> &observerLookVectorToTarget) {
269 
270  // Clear out previous surface point and normal
271  clearSurfacePoint();
272 
273  SpiceDouble lookB[3];
274 
275  // This memcpy does:
276  // lookB[0] = observerLookVectorToTarget[0];
277  // lookB[1] = observerLookVectorToTarget[1];
278  // lookB[2] = observerLookVectorToTarget[2];
279  memcpy(lookB,&observerLookVectorToTarget[0], 3*sizeof(double));
280 
281  // get target radii
282  std::vector<Distance> radii = targetRadii();
283  SpiceDouble a = radii[0].kilometers();
284  SpiceDouble b = radii[1].kilometers();
285  SpiceDouble c = radii[2].kilometers();
286 
287  // check if observer look vector intersects the target
288  SpiceDouble intersectionPoint[3];
289  SpiceBoolean intersected = false;
290 
291  NaifStatus::CheckErrors();
292  surfpt_c((SpiceDouble *) &observerBodyFixedPosition[0], lookB, a, b, c,
293  intersectionPoint, &intersected);
294  NaifStatus::CheckErrors();
295 
296  if (intersected) {
297  m_surfacePoint->FromNaifArray(intersectionPoint);
298  m_hasIntersection = true;
299  }
300  else {
301  m_hasIntersection = false;
302  }
303 
304  m_hasEllipsoidIntersection = m_hasIntersection;
305  return m_hasIntersection;
306  }
307 
308 
324  double ShapeModel::phaseAngle(const std::vector<double> &observerBodyFixedPosition,
325  const std::vector<double> &illuminatorBodyFixedPosition) {
326 
327  // Get vector from center of body to surface point
328  SpiceDouble pB[3];
329  pB[0] = surfaceIntersection()->GetX().kilometers();
330  pB[1] = surfaceIntersection()->GetY().kilometers();
331  pB[2] = surfaceIntersection()->GetZ().kilometers();
332 
333  // Get vector from surface point to observer and normalize it
334  SpiceDouble psB[3], upsB[3], dist;
335  vsub_c((SpiceDouble *) &observerBodyFixedPosition[0], pB, psB);
336  unorm_c(psB, upsB, &dist);
337 
338  // Get vector from surface point to sun and normalize it
339  SpiceDouble puB[3], upuB[3];
340  vsub_c((SpiceDouble *) &illuminatorBodyFixedPosition[0], pB, puB);
341  unorm_c(puB, upuB, &dist);
342 
343  double angle = vdot_c(upsB, upuB);
344 
345  // How can these lines be tested???
346  if(angle > 1.0) return 0.0;
347  if(angle < -1.0) return 180.0;
348  return acos(angle) * RAD2DEG;
349  }
350 
351 
358  SurfacePoint *ShapeModel::surfaceIntersection() const {
359  return m_surfacePoint;
360  }
361 
362 
368  bool ShapeModel::hasIntersection() {
369  return m_hasIntersection;
370  }
371 
372 
378  bool ShapeModel::hasNormal() const {
379  return m_hasNormal;
380  }
381 
382 
386  void ShapeModel::clearSurfacePoint() {
387  setHasIntersection(false);
388  m_hasEllipsoidIntersection = false;
389  }
390 
391 
401  std::vector<double> ShapeModel::normal() {
402  if (m_hasNormal ) {
403  return m_normal;
404  }
405  else {
406  QString message = "The local normal has not been computed.";
407  throw IException(IException::Unknown, message, _FILEINFO_);
408  }
409 
410  }
411 
431  bool ShapeModel::isVisibleFrom(const std::vector<double> observerPos,
432  const std::vector<double> lookDirection) {
433  if ( hasIntersection() ) {
434  if ( fabs(emissionAngle(observerPos)) <= 90.0 ) {
435  return (true);
436  }
437  }
438 
439  // All other conditions indicate the point is not visable from the observer
440  return (false);
441  }
442 
449  bool ShapeModel::hasValidTarget() const {
450  return (m_target != NULL);
451  }
452 
453 
465  std::vector<Distance> ShapeModel::targetRadii() const {
466  if (hasValidTarget()) {
467  return m_target->radii();
468  }
469  else {
470  QString message = "Unable to find target radii for ShapeModel. Target is NULL. ";
471  throw IException(IException::Programmer, message, _FILEINFO_);
472  }
473  }
474 
475 
487  void ShapeModel::setNormal(const std::vector<double> normal) {
488  if (m_hasIntersection) {
489  m_normal = normal;
490  m_hasNormal = true;
491  }
492  else {
493  QString message = "No intersection point in known. A normal can not be set.";
494  throw IException(IException::Unknown, message, _FILEINFO_);
495  }
496  }
497 
498 
512  void ShapeModel::setNormal(const double a, const double b, const double c) {
513  if (m_hasIntersection) {
514  m_normal[0] = a;
515  m_normal[1] = b;
516  m_normal[2] = c;
517  m_hasNormal = true;
518  }
519  else {
520  QString message = "No intersection point in known. A normal can not be set.";
521  throw IException(IException::Unknown, message, _FILEINFO_);
522  }
523  }
524 
525 
532  void ShapeModel::setName(QString name) {
533  *m_name = name;
534  }
535 
536 
543  QString ShapeModel::name() const{
544  return *m_name;
545  }
546 
547 
554  void ShapeModel::setHasIntersection(bool b) {
555  m_hasIntersection = b;
556  m_hasNormal = false;
557  }
558 
559 
565  void ShapeModel::setSurfacePoint(const SurfacePoint &surfacePoint) {
566  *m_surfacePoint = surfacePoint;
567 
568  // Update status of intersection and normal
569  m_hasIntersection = true;
570  // Set normal as not calculated
571  setHasNormal(false);
572  }
573 
574 
581  void ShapeModel::setHasNormal(bool status) {
582  m_hasNormal = status;
583  }
584 
585 
592  double ShapeModel::resolution() {
593  if (hasValidTarget() && m_hasIntersection) {
594  return m_target->spice()->resolution();
595  }
596  else {
597  QString message = "No valid intersection point for computing resolution.";
598  throw IException(IException::Programmer, message, _FILEINFO_);
599  }
600  }
601 
602 }
Isis::Latitude
This class is designed to encapsulate the concept of a Latitude.
Definition: Latitude.h:51
Isis::Longitude
This class is designed to encapsulate the concept of a Longitude.
Definition: Longitude.h:40
Isis::IException
Isis exception class.
Definition: IException.h:91
std
Namespace for the standard library.
Isis::Target
This class is used to create and store valid Isis targets.
Definition: Target.h:63
Isis::RAD2DEG
const double RAD2DEG
Multiplier for converting from radians to degrees.
Definition: Constants.h:44
Isis::SurfacePoint
This class defines a body-fixed surface point.
Definition: SurfacePoint.h:132
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16