USGS

Isis 3.0 Object Programmers' Reference

Home

ShapeModel.cpp
1 #include "ShapeModel.h"
2 
3 #include <algorithm>
4 #include <cfloat>
5 #include <vector>
6 
7 #include <cmath>
8 
9 #include <SpiceUsr.h>
10 #include <SpiceZfc.h>
11 #include <SpiceZmc.h>
12 
13 #include "Distance.h"
14 #include "SurfacePoint.h"
15 #include "IException.h"
16 #include "IString.h"
17 #include "NaifStatus.h"
18 #include "Spice.h"
19 #include "Target.h"
20 
21 using namespace std;
22 
23 namespace Isis {
27  ShapeModel::ShapeModel() {
28  Initialize();
29  m_target = NULL;
30  }
31 
32 
38  ShapeModel::ShapeModel(Target *target, Pvl &pvl) {
39  Initialize();
40  m_target = target;
41  }
42 
43 
49  ShapeModel::ShapeModel(Target *target) {
50  Initialize();
51  m_target = target;
52  }
53 
54 
58  void ShapeModel::Initialize() {
59  m_name = new QString();
60  m_surfacePoint = new SurfacePoint();
61  m_hasIntersection = false;
62  m_hasNormal = false;
63  m_normal.resize(3,0.);
64  m_hasEllipsoidIntersection = false;
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 (!surfaceIntersection()->Valid() || !m_hasIntersection) {
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 
123  double ShapeModel::emissionAngle(const std::vector<double> & sB) {
124 
125  // Calculate the surface normal if we haven't yet
126  if (!hasNormal()) calculateDefaultNormal();
127 
128  // Get vector from center of body to surface point
129  SpiceDouble pB[3];
130  pB[0] = surfaceIntersection()->GetX().kilometers();
131  pB[1] = surfaceIntersection()->GetY().kilometers();
132  pB[2] = surfaceIntersection()->GetZ().kilometers();
133 
134  // Get vector from surface point to observer and normalize it
135  SpiceDouble psB[3], upsB[3], dist;
136  vsub_c((ConstSpiceDouble *) &sB[0], pB, psB);
137  unorm_c(psB, upsB, &dist);
138 
139  double angle = vdot_c((SpiceDouble *) &m_normal[0], upsB);
140  if(angle > 1.0) return 0.0;
141  if(angle < -1.0) return 180.0;
142  return acos(angle) * RAD2DEG;
143  }
144 
145 
150  bool ShapeModel::hasEllipsoidIntersection() {
151  return m_hasEllipsoidIntersection;
152  }
153 
154 
160  double ShapeModel::incidenceAngle(const std::vector<double> &uB) {
161 
162  // Calculate the surface normal if we haven't yet.
163  if (!m_hasNormal) calculateDefaultNormal();
164 
165  // Get vector from center of body to surface point
166  SpiceDouble pB[3];
167  pB[0] = surfaceIntersection()->GetX().kilometers();
168  pB[1] = surfaceIntersection()->GetY().kilometers();
169  pB[2] = surfaceIntersection()->GetZ().kilometers();
170 
171  // Get vector from surface point to sun and normalize it
172  SpiceDouble puB[3], upuB[3], dist;
173  vsub_c((SpiceDouble *) &uB[0], pB, puB);
174  unorm_c(puB, upuB, &dist);
175 
176  double angle = vdot_c((SpiceDouble *) &m_normal[0], upuB);
177  if(angle > 1.0) return 0.0;
178  if(angle < -1.0) return 180.0;
179  return acos(angle) * RAD2DEG;
180  }
181 
182 
186  bool ShapeModel::intersectEllipsoid(const std::vector<double> observerBodyFixedPosition,
187  const std::vector<double> &observerLookVectorToTarget) {
188 
189  // Clear out previous surface point and normal
190  clearSurfacePoint();
191 
192  SpiceDouble lookB[3];
193 
194  // This memcpy does:
195  // lookB[0] = observerLookVectorToTarget[0];
196  // lookB[1] = observerLookVectorToTarget[1];
197  // lookB[2] = observerLookVectorToTarget[2];
198  memcpy(lookB,&observerLookVectorToTarget[0], 3*sizeof(double));
199 
200  // get target radii
201  std::vector<Distance> radii = targetRadii();
202  SpiceDouble a = radii[0].kilometers();
203  SpiceDouble b = radii[1].kilometers();
204  SpiceDouble c = radii[2].kilometers();
205 
206  // check if observer look vector intersects the target
207  SpiceDouble intersectionPoint[3];
208  SpiceBoolean intersected = false;
209  surfpt_c((SpiceDouble *) &observerBodyFixedPosition[0], lookB, a, b, c,
210  intersectionPoint, &intersected);
211 
212  NaifStatus::CheckErrors();
213 
214  if (intersected) {
215  m_surfacePoint->FromNaifArray(intersectionPoint);
216  m_hasIntersection = true;
217  }
218  else {
219  m_hasIntersection = false;
220  }
221 
222  m_hasEllipsoidIntersection = m_hasIntersection;
223  return m_hasIntersection;
224  }
225 
226 
232  double ShapeModel::phaseAngle(const std::vector<double> & sB, const std::vector<double> &uB) {
233 
234  // Get vector from center of body to surface point
235  SpiceDouble pB[3];
236  pB[0] = surfaceIntersection()->GetX().kilometers();
237  pB[1] = surfaceIntersection()->GetY().kilometers();
238  pB[2] = surfaceIntersection()->GetZ().kilometers();
239 
240  // Get vector from surface point to observer and normalize it
241  SpiceDouble psB[3], upsB[3], dist;
242  vsub_c((SpiceDouble *) &sB[0], pB, psB);
243  unorm_c(psB, upsB, &dist);
244 
245  // Get vector from surface point to sun and normalize it
246  SpiceDouble puB[3], upuB[3];
247  vsub_c((SpiceDouble *) &uB[0], pB, puB);
248  unorm_c(puB, upuB, &dist);
249 
250  double angle = vdot_c(upsB, upuB);
251 
252  // How can these lines be tested???
253  if(angle > 1.0) return 0.0;
254  if(angle < -1.0) return 180.0;
255  return acos(angle) * RAD2DEG;
256  }
257 
258 
262  SurfacePoint *ShapeModel::surfaceIntersection() const {
263  return m_surfacePoint;
264  }
265 
266 
270  bool ShapeModel::hasIntersection() {
271  return m_hasIntersection;
272  }
273 
274 
278  bool ShapeModel::hasNormal() const {
279  return m_hasNormal;
280  }
281 
282 
286  void ShapeModel::clearSurfacePoint() {
287  setHasIntersection(false);
288  m_hasEllipsoidIntersection = false;
289  }
290 
291 
297  std::vector<double> ShapeModel::normal() {
298  if (m_hasNormal ) {
299  return m_normal;
300  }
301  else {
302  QString message = "The local normal has not been computed.";
303  throw IException(IException::Unknown, message, _FILEINFO_);
304  }
305 
306  }
307 
308 
309  bool ShapeModel::hasValidTarget() const {
310  return (m_target != NULL);
311  }
312 
317  std::vector<Distance> ShapeModel::targetRadii() const {
318  if (hasValidTarget()) {
319  return m_target->radii();
320  }
321  else {
322  QString message = "Unable to find target radii for ShapeModel. Target is NULL. ";
323  throw IException(IException::Programmer, message, _FILEINFO_);
324  }
325  }
326 
327 
331  void ShapeModel::setNormal(const std::vector<double> normal) {
332  if (m_hasIntersection) {
333  m_normal = normal;
334  m_hasNormal = true;
335  }
336  else {
337  QString message = "No intersection point in known. A normal can not be set.";
338  throw IException(IException::Unknown, message, _FILEINFO_);
339  }
340  }
341 
342 
346  void ShapeModel::setNormal(const double a, const double b, const double c) {
347  if (m_hasIntersection) {
348  m_normal[0] = a;
349  m_normal[1] = b;
350  m_normal[2] = c;
351  m_hasNormal = true;
352  }
353  else {
354  QString message = "No intersection point in known. A normal can not be set.";
355  throw IException(IException::Unknown, message, _FILEINFO_);
356  }
357  }
358 
359 
363  void ShapeModel::setName(QString name) {
364  *m_name = name;
365  }
366 
367 
371  QString ShapeModel::name() const{
372  return *m_name;
373  }
374 
375 
379  void ShapeModel::setHasIntersection(bool b) {
380  m_hasIntersection = b;
381  m_hasNormal = false;
382  }
383 
384 
388  void ShapeModel::setSurfacePoint(const SurfacePoint &surfacePoint) {
389  *m_surfacePoint = surfacePoint;
390 
391  // Update status of intersection and normal
392  m_hasIntersection = true;
393  // Set normal as not calculated
394  setHasNormal(false);
395  }
396 
397 
401  void ShapeModel::setHasNormal(bool status) {
402  m_hasNormal = status;
403  }
404 
405 
409  double ShapeModel::resolution() {
410  if (m_hasIntersection && hasValidTarget()) {
411  return m_target->spice()->resolution();
412  }
413  else {
414  QString message = "No valid intersection point for computing resolution.";
415  throw IException(IException::Programmer, message, _FILEINFO_);
416  }
417  }
418 
419 }