Isis 3 Programmer Reference
ShapeModel.cpp
1 #include "ShapeModel.h"
2 
3 #include <QDebug>
4 
5 #include <algorithm>
6 #include <cfloat>
7 #include <iostream>
8 #include <iomanip>
9 #include <vector>
10 
11 #include <cmath>
12 
13 #include <SpiceUsr.h>
14 #include <SpiceZfc.h>
15 #include <SpiceZmc.h>
16 
17 #include "Distance.h"
18 #include "SurfacePoint.h"
19 #include "IException.h"
20 #include "IString.h"
21 #include "NaifStatus.h"
22 #include "Spice.h"
23 #include "Target.h"
24 
25 using namespace std;
26 
27 namespace Isis {
34  ShapeModel::ShapeModel() {
35  Initialize();
36  m_target = NULL;
37  }
38 
39 
50  ShapeModel::ShapeModel(Target *target) {
51  Initialize();
52  m_target = target;
53  }
54 
55 
59  void ShapeModel::Initialize() {
60  m_name = new QString();
61  m_surfacePoint = new SurfacePoint();
62  m_hasIntersection = false;
63  m_hasNormal = false;
64  m_normal.resize(3,0.);
65  m_hasEllipsoidIntersection = false;
66  }
67 
68 
70  ShapeModel::~ShapeModel() {
71 
72  delete m_name;
73  m_name = NULL;
74 
75  delete m_surfacePoint;
76  m_surfacePoint = NULL;
77  }
78 
79 
97  bool ShapeModel::intersectSurface(const Latitude &lat, const Longitude &lon,
98  const std::vector<double> &observerPos,
99  const bool &backCheck) {
100  // Distance radius = localRadius(lat, lon);
101  return (intersectSurface(SurfacePoint(lat, lon, localRadius(lat, lon)), observerPos, backCheck));
102  }
103 
104 
121  bool ShapeModel::intersectSurface(const SurfacePoint &surfpt,
122  const std::vector<double> &observerPos,
123  const bool &backCheck) {
124 
125  // The default behavior is to set the point in the model without
126  // intersection tests at all
127  setSurfacePoint(surfpt);
128  return (true);
129  }
130 
134  void ShapeModel::calculateEllipsoidalSurfaceNormal() {
135  // The below code is not truly normal unless the ellipsoid is a sphere. TODO Should this be
136  // fixed? Send an email asking Jeff and Stuart. See Naif routine surfnm.c to get the true
137  // for an ellipsoid. For testing purposes to match old results do as Isis3 currently does until
138  // Jeff and Stuart respond.
139 
140  if (!m_hasIntersection || !surfaceIntersection()->Valid()) {
141  QString msg = "A valid intersection must be defined before computing the surface normal";
142  throw IException(IException::Programmer, msg, _FILEINFO_);
143  }
144 
145  // Get the coordinates of the current surface point
146  SpiceDouble pB[3];
147  pB[0] = surfaceIntersection()->GetX().kilometers();
148  pB[1] = surfaceIntersection()->GetY().kilometers();
149  pB[2] = surfaceIntersection()->GetZ().kilometers();
150 
151  // Unitize the vector
152  SpiceDouble upB[3];
153  SpiceDouble dist;
154  unorm_c(pB, upB, &dist);
155  memcpy(&m_normal[0], upB, sizeof(double) * 3);
156 
157  m_hasNormal = true;
158  }
159 
160 
179  double ShapeModel::emissionAngle(const std::vector<double> &observerBodyFixedPosition) {
180 
181  // Calculate the surface normal if we haven't yet
182  if (!hasNormal()) calculateDefaultNormal();
183 
184  // Get vector from center of body to surface point
185  SpiceDouble pB[3];
186  pB[0] = surfaceIntersection()->GetX().kilometers();
187  pB[1] = surfaceIntersection()->GetY().kilometers();
188  pB[2] = surfaceIntersection()->GetZ().kilometers();
189 
190  // Get vector from surface point to observer and normalize it
191  SpiceDouble psB[3], upsB[3], dist;
192  vsub_c((ConstSpiceDouble *) &observerBodyFixedPosition[0], pB, psB);
193  unorm_c(psB, upsB, &dist);
194 
195  double angle = vdot_c((SpiceDouble *) &m_normal[0], upsB);
196  if(angle > 1.0) return 0.0;
197  if(angle < -1.0) return 180.0;
198  return acos(angle) * RAD2DEG;
199  }
200 
201 
207  bool ShapeModel::hasEllipsoidIntersection() {
208  return m_hasEllipsoidIntersection;
209  }
210 
211 
226  double ShapeModel::incidenceAngle(const std::vector<double> &illuminatorBodyFixedPosition) {
227 
228  // Calculate the surface normal if we haven't yet.
229  if (!m_hasNormal) calculateDefaultNormal();
230 
231  // Get vector from center of body to surface point
232  SpiceDouble pB[3];
233  pB[0] = surfaceIntersection()->GetX().kilometers();
234  pB[1] = surfaceIntersection()->GetY().kilometers();
235  pB[2] = surfaceIntersection()->GetZ().kilometers();
236 
237  // Get vector from surface point to sun and normalize it
238  SpiceDouble puB[3], upuB[3], dist;
239  vsub_c((SpiceDouble *) &illuminatorBodyFixedPosition[0], pB, puB);
240  unorm_c(puB, upuB, &dist);
241 
242  double angle = vdot_c((SpiceDouble *) &m_normal[0], upuB);
243  if(angle > 1.0) return 0.0;
244  if(angle < -1.0) return 180.0;
245  return acos(angle) * RAD2DEG;
246  }
247 
248 
261  bool ShapeModel::intersectEllipsoid(const std::vector<double> observerBodyFixedPosition,
262  const std::vector<double> &observerLookVectorToTarget) {
263 
264  // Clear out previous surface point and normal
265  clearSurfacePoint();
266 
267  SpiceDouble lookB[3];
268 
269  // This memcpy does:
270  // lookB[0] = observerLookVectorToTarget[0];
271  // lookB[1] = observerLookVectorToTarget[1];
272  // lookB[2] = observerLookVectorToTarget[2];
273  memcpy(lookB,&observerLookVectorToTarget[0], 3*sizeof(double));
274 
275  // get target radii
276  std::vector<Distance> radii = targetRadii();
277  SpiceDouble a = radii[0].kilometers();
278  SpiceDouble b = radii[1].kilometers();
279  SpiceDouble c = radii[2].kilometers();
280 
281  // check if observer look vector intersects the target
282  SpiceDouble intersectionPoint[3];
283  SpiceBoolean intersected = false;
284 
285  NaifStatus::CheckErrors();
286  surfpt_c((SpiceDouble *) &observerBodyFixedPosition[0], lookB, a, b, c,
287  intersectionPoint, &intersected);
288  NaifStatus::CheckErrors();
289 
290  if (intersected) {
291  m_surfacePoint->FromNaifArray(intersectionPoint);
292  m_hasIntersection = true;
293  }
294  else {
295  m_hasIntersection = false;
296  }
297 
298  m_hasEllipsoidIntersection = m_hasIntersection;
299  return m_hasIntersection;
300  }
301 
302 
318  double ShapeModel::phaseAngle(const std::vector<double> &observerBodyFixedPosition,
319  const std::vector<double> &illuminatorBodyFixedPosition) {
320 
321  // Get vector from center of body to surface point
322  SpiceDouble pB[3];
323  pB[0] = surfaceIntersection()->GetX().kilometers();
324  pB[1] = surfaceIntersection()->GetY().kilometers();
325  pB[2] = surfaceIntersection()->GetZ().kilometers();
326 
327  // Get vector from surface point to observer and normalize it
328  SpiceDouble psB[3], upsB[3], dist;
329  vsub_c((SpiceDouble *) &observerBodyFixedPosition[0], pB, psB);
330  unorm_c(psB, upsB, &dist);
331 
332  // Get vector from surface point to sun and normalize it
333  SpiceDouble puB[3], upuB[3];
334  vsub_c((SpiceDouble *) &illuminatorBodyFixedPosition[0], pB, puB);
335  unorm_c(puB, upuB, &dist);
336 
337  double angle = vdot_c(upsB, upuB);
338 
339  // How can these lines be tested???
340  if(angle > 1.0) return 0.0;
341  if(angle < -1.0) return 180.0;
342  return acos(angle) * RAD2DEG;
343  }
344 
345 
352  SurfacePoint *ShapeModel::surfaceIntersection() const {
353  return m_surfacePoint;
354  }
355 
356 
362  bool ShapeModel::hasIntersection() {
363  return m_hasIntersection;
364  }
365 
366 
372  bool ShapeModel::hasNormal() const {
373  return m_hasNormal;
374  }
375 
376 
380  void ShapeModel::clearSurfacePoint() {
381  setHasIntersection(false);
382  m_hasEllipsoidIntersection = false;
383  }
384 
385 
395  std::vector<double> ShapeModel::normal() {
396  if (m_hasNormal ) {
397  return m_normal;
398  }
399  else {
400  QString message = "The local normal has not been computed.";
401  throw IException(IException::Unknown, message, _FILEINFO_);
402  }
403 
404  }
405 
425  bool ShapeModel::isVisibleFrom(const std::vector<double> observerPos,
426  const std::vector<double> lookDirection) {
427  if ( hasIntersection() ) {
428  if ( fabs(emissionAngle(observerPos)) <= 90.0 ) {
429  return (true);
430  }
431  }
432 
433  // All other conditions indicate the point is not visable from the observer
434  return (false);
435  }
436 
443  bool ShapeModel::hasValidTarget() const {
444  return (m_target != NULL);
445  }
446 
447 
459  std::vector<Distance> ShapeModel::targetRadii() const {
460  if (hasValidTarget()) {
461  return m_target->radii();
462  }
463  else {
464  QString message = "Unable to find target radii for ShapeModel. Target is NULL. ";
465  throw IException(IException::Programmer, message, _FILEINFO_);
466  }
467  }
468 
469 
481  void ShapeModel::setNormal(const std::vector<double> normal) {
482  if (m_hasIntersection) {
483  m_normal = normal;
484  m_hasNormal = true;
485  }
486  else {
487  QString message = "No intersection point in known. A normal can not be set.";
488  throw IException(IException::Unknown, message, _FILEINFO_);
489  }
490  }
491 
492 
506  void ShapeModel::setNormal(const double a, const double b, const double c) {
507  if (m_hasIntersection) {
508  m_normal[0] = a;
509  m_normal[1] = b;
510  m_normal[2] = c;
511  m_hasNormal = true;
512  }
513  else {
514  QString message = "No intersection point in known. A normal can not be set.";
515  throw IException(IException::Unknown, message, _FILEINFO_);
516  }
517  }
518 
519 
526  void ShapeModel::setName(QString name) {
527  *m_name = name;
528  }
529 
530 
537  QString ShapeModel::name() const{
538  return *m_name;
539  }
540 
541 
548  void ShapeModel::setHasIntersection(bool b) {
549  m_hasIntersection = b;
550  m_hasNormal = false;
551  }
552 
553 
559  void ShapeModel::setSurfacePoint(const SurfacePoint &surfacePoint) {
560  *m_surfacePoint = surfacePoint;
561 
562  // Update status of intersection and normal
563  m_hasIntersection = true;
564  // Set normal as not calculated
565  setHasNormal(false);
566  }
567 
568 
575  void ShapeModel::setHasNormal(bool status) {
576  m_hasNormal = status;
577  }
578 
579 
586  double ShapeModel::resolution() {
587  if (hasValidTarget() && m_hasIntersection) {
588  return m_target->spice()->resolution();
589  }
590  else {
591  QString message = "No valid intersection point for computing resolution.";
592  throw IException(IException::Programmer, message, _FILEINFO_);
593  }
594  }
595 
596 }
This class defines a body-fixed surface point.
Definition: SurfacePoint.h:148
Namespace for the standard library.
This class is designed to encapsulate the concept of a Latitude.
Definition: Latitude.h:63
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
This class is designed to encapsulate the concept of a Longitude.
Definition: Longitude.h:52
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
This class is used to create and store valid Isis3 targets.
Definition: Target.h:76
Isis exception class.
Definition: IException.h:107
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
const double RAD2DEG
Multiplier for converting from radians to degrees.
Definition: Constants.h:60