Isis 3.0 Programmer Reference
Back | Home
ShapeModel.cpp
1 #include "ShapeModel.h"
2 
3 #include <QDebug>
4 
5 #include <algorithm>
6 #include <cfloat>
7 #include <vector>
8 
9 #include <cmath>
10 
11 #include <SpiceUsr.h>
12 #include <SpiceZfc.h>
13 #include <SpiceZmc.h>
14 
15 #include "Distance.h"
16 #include "SurfacePoint.h"
17 #include "IException.h"
18 #include "IString.h"
19 #include "NaifStatus.h"
20 #include "Spice.h"
21 #include "Target.h"
22 
23 using namespace std;
24 
25 namespace Isis {
32  ShapeModel::ShapeModel() {
33  Initialize();
34  m_target = NULL;
35  }
36 
37 
48  ShapeModel::ShapeModel(Target *target) {
49  Initialize();
50  m_target = target;
51  }
52 
53 
57  void ShapeModel::Initialize() {
58  m_name = new QString();
59  m_surfacePoint = new SurfacePoint();
60  m_hasIntersection = false;
61  m_hasNormal = false;
62  m_normal.resize(3,0.);
63  m_hasEllipsoidIntersection = false;
64  }
65 
66 
68  ShapeModel::~ShapeModel() {
69 
70  delete m_name;
71  m_name = NULL;
72 
73  delete m_surfacePoint;
74  m_surfacePoint = NULL;
75  }
76 
77 
81  void ShapeModel::calculateEllipsoidalSurfaceNormal() {
82  // The below code is not truly normal unless the ellipsoid is a sphere. TODO Should this be
83  // fixed? Send an email asking Jeff and Stuart. See Naif routine surfnm.c to get the true
84  // for an ellipsoid. For testing purposes to match old results do as Isis3 currently does until
85  // Jeff and Stuart respond.
86 
87  if (!m_hasIntersection || !surfaceIntersection()->Valid()) {
88  QString msg = "A valid intersection must be defined before computing the surface normal";
89  throw IException(IException::Programmer, msg, _FILEINFO_);
90  }
91 
92  // Get the coordinates of the current surface point
93  SpiceDouble pB[3];
94  pB[0] = surfaceIntersection()->GetX().kilometers();
95  pB[1] = surfaceIntersection()->GetY().kilometers();
96  pB[2] = surfaceIntersection()->GetZ().kilometers();
97 
98  // Unitize the vector
99  SpiceDouble upB[3];
100  SpiceDouble dist;
101  unorm_c(pB, upB, &dist);
102  memcpy(&m_normal[0], upB, sizeof(double) * 3);
103 
104  m_hasNormal = true;
105  }
106 
107 
126  double ShapeModel::emissionAngle(const std::vector<double> &observerBodyFixedPosition) {
127 
128  // Calculate the surface normal if we haven't yet
129  if (!hasNormal()) calculateDefaultNormal();
130 
131  // Get vector from center of body to surface point
132  SpiceDouble pB[3];
133  pB[0] = surfaceIntersection()->GetX().kilometers();
134  pB[1] = surfaceIntersection()->GetY().kilometers();
135  pB[2] = surfaceIntersection()->GetZ().kilometers();
136 
137  // Get vector from surface point to observer and normalize it
138  SpiceDouble psB[3], upsB[3], dist;
139  vsub_c((ConstSpiceDouble *) &observerBodyFixedPosition[0], pB, psB);
140  unorm_c(psB, upsB, &dist);
141 
142  double angle = vdot_c((SpiceDouble *) &m_normal[0], upsB);
143  if(angle > 1.0) return 0.0;
144  if(angle < -1.0) return 180.0;
145  return acos(angle) * RAD2DEG;
146  }
147 
148 
154  bool ShapeModel::hasEllipsoidIntersection() {
155  return m_hasEllipsoidIntersection;
156  }
157 
158 
173  double ShapeModel::incidenceAngle(const std::vector<double> &illuminatorBodyFixedPosition) {
174 
175  // Calculate the surface normal if we haven't yet.
176  if (!m_hasNormal) calculateDefaultNormal();
177 
178  // Get vector from center of body to surface point
179  SpiceDouble pB[3];
180  pB[0] = surfaceIntersection()->GetX().kilometers();
181  pB[1] = surfaceIntersection()->GetY().kilometers();
182  pB[2] = surfaceIntersection()->GetZ().kilometers();
183 
184  // Get vector from surface point to sun and normalize it
185  SpiceDouble puB[3], upuB[3], dist;
186  vsub_c((SpiceDouble *) &illuminatorBodyFixedPosition[0], pB, puB);
187  unorm_c(puB, upuB, &dist);
188 
189  double angle = vdot_c((SpiceDouble *) &m_normal[0], upuB);
190  if(angle > 1.0) return 0.0;
191  if(angle < -1.0) return 180.0;
192  return acos(angle) * RAD2DEG;
193  }
194 
195 
208  bool ShapeModel::intersectEllipsoid(const std::vector<double> observerBodyFixedPosition,
209  const std::vector<double> &observerLookVectorToTarget) {
210 
211  // Clear out previous surface point and normal
212  clearSurfacePoint();
213 
214  SpiceDouble lookB[3];
215 
216  // This memcpy does:
217  // lookB[0] = observerLookVectorToTarget[0];
218  // lookB[1] = observerLookVectorToTarget[1];
219  // lookB[2] = observerLookVectorToTarget[2];
220  memcpy(lookB,&observerLookVectorToTarget[0], 3*sizeof(double));
221 
222  // get target radii
223  std::vector<Distance> radii = targetRadii();
224  SpiceDouble a = radii[0].kilometers();
225  SpiceDouble b = radii[1].kilometers();
226  SpiceDouble c = radii[2].kilometers();
227 
228  // check if observer look vector intersects the target
229  SpiceDouble intersectionPoint[3];
230  SpiceBoolean intersected = false;
231 
232  NaifStatus::CheckErrors();
233  surfpt_c((SpiceDouble *) &observerBodyFixedPosition[0], lookB, a, b, c,
234  intersectionPoint, &intersected);
235  NaifStatus::CheckErrors();
236 
237  if (intersected) {
238  m_surfacePoint->FromNaifArray(intersectionPoint);
239  m_hasIntersection = true;
240  }
241  else {
242  m_hasIntersection = false;
243  }
244 
245  m_hasEllipsoidIntersection = m_hasIntersection;
246  return m_hasIntersection;
247  }
248 
249 
265  double ShapeModel::phaseAngle(const std::vector<double> &observerBodyFixedPosition,
266  const std::vector<double> &illuminatorBodyFixedPosition) {
267 
268  // Get vector from center of body to surface point
269  SpiceDouble pB[3];
270  pB[0] = surfaceIntersection()->GetX().kilometers();
271  pB[1] = surfaceIntersection()->GetY().kilometers();
272  pB[2] = surfaceIntersection()->GetZ().kilometers();
273 
274  // Get vector from surface point to observer and normalize it
275  SpiceDouble psB[3], upsB[3], dist;
276  vsub_c((SpiceDouble *) &observerBodyFixedPosition[0], pB, psB);
277  unorm_c(psB, upsB, &dist);
278 
279  // Get vector from surface point to sun and normalize it
280  SpiceDouble puB[3], upuB[3];
281  vsub_c((SpiceDouble *) &illuminatorBodyFixedPosition[0], pB, puB);
282  unorm_c(puB, upuB, &dist);
283 
284  double angle = vdot_c(upsB, upuB);
285 
286  // How can these lines be tested???
287  if(angle > 1.0) return 0.0;
288  if(angle < -1.0) return 180.0;
289  return acos(angle) * RAD2DEG;
290  }
291 
292 
299  SurfacePoint *ShapeModel::surfaceIntersection() const {
300  return m_surfacePoint;
301  }
302 
303 
309  bool ShapeModel::hasIntersection() {
310  return m_hasIntersection;
311  }
312 
313 
319  bool ShapeModel::hasNormal() const {
320  return m_hasNormal;
321  }
322 
323 
327  void ShapeModel::clearSurfacePoint() {
328  setHasIntersection(false);
329  m_hasEllipsoidIntersection = false;
330  }
331 
332 
342  std::vector<double> ShapeModel::normal() {
343  if (m_hasNormal ) {
344  return m_normal;
345  }
346  else {
347  QString message = "The local normal has not been computed.";
348  throw IException(IException::Unknown, message, _FILEINFO_);
349  }
350 
351  }
352 
353 
360  bool ShapeModel::hasValidTarget() const {
361  return (m_target != NULL);
362  }
363 
364 
376  std::vector<Distance> ShapeModel::targetRadii() const {
377  if (hasValidTarget()) {
378  return m_target->radii();
379  }
380  else {
381  QString message = "Unable to find target radii for ShapeModel. Target is NULL. ";
382  throw IException(IException::Programmer, message, _FILEINFO_);
383  }
384  }
385 
386 
398  void ShapeModel::setNormal(const std::vector<double> normal) {
399  if (m_hasIntersection) {
400  m_normal = normal;
401  m_hasNormal = true;
402  }
403  else {
404  QString message = "No intersection point in known. A normal can not be set.";
405  throw IException(IException::Unknown, message, _FILEINFO_);
406  }
407  }
408 
409 
423  void ShapeModel::setNormal(const double a, const double b, const double c) {
424  if (m_hasIntersection) {
425  m_normal[0] = a;
426  m_normal[1] = b;
427  m_normal[2] = c;
428  m_hasNormal = true;
429  }
430  else {
431  QString message = "No intersection point in known. A normal can not be set.";
432  throw IException(IException::Unknown, message, _FILEINFO_);
433  }
434  }
435 
436 
443  void ShapeModel::setName(QString name) {
444  *m_name = name;
445  }
446 
447 
454  QString ShapeModel::name() const{
455  return *m_name;
456  }
457 
458 
465  void ShapeModel::setHasIntersection(bool b) {
466  m_hasIntersection = b;
467  m_hasNormal = false;
468  }
469 
470 
476  void ShapeModel::setSurfacePoint(const SurfacePoint &surfacePoint) {
477  *m_surfacePoint = surfacePoint;
478 
479  // Update status of intersection and normal
480  m_hasIntersection = true;
481  // Set normal as not calculated
482  setHasNormal(false);
483  }
484 
485 
492  void ShapeModel::setHasNormal(bool status) {
493  m_hasNormal = status;
494  }
495 
496 
503  double ShapeModel::resolution() {
504  if (hasValidTarget() && m_hasIntersection) {
505  return m_target->spice()->resolution();
506  }
507  else {
508  QString message = "No valid intersection point for computing resolution.";
509  throw IException(IException::Programmer, message, _FILEINFO_);
510  }
511  }
512 
513 }
This class defines a body-fixed surface point.
Definition: SurfacePoint.h:86
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:38
This class is used to create and store valid Isis3 targets.
Definition: Target.h:63
Isis exception class.
Definition: IException.h:99
const double RAD2DEG(57.29577951308232087679815481)
Multiplier for converting from radians to degrees.

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the ISIS Support Center
File Modified: 07/12/2023 23:29:09