USGS

Isis 3.0 Object Programmers' Reference

Home

DemShape.cpp
1 #include "DemShape.h"
2 
3 // Qt third party includes
4 #include <QVector>
5 
6 // c standard library third party includes
7 #include <algorithm>
8 #include <cfloat>
9 #include <cmath>
10 #include <iomanip>
11 #include <string>
12 #include <vector>
13 
14 // naif third party includes
15 #include <SpiceUsr.h>
16 #include <SpiceZfc.h>
17 #include <SpiceZmc.h>
18 
19 #include "Cube.h"
20 #include "CubeManager.h"
21 #include "EllipsoidShape.h"
22 #include "IException.h"
23 #include "Interpolator.h"
24 #include "Latitude.h"
25 #include "Longitude.h"
26 #include "NaifStatus.h"
27 #include "Portal.h"
28 #include "Projection.h"
29 #include "Pvl.h"
30 #include "SurfacePoint.h"
32 
33 using namespace std;
34 
35 namespace Isis {
43  DemShape::DemShape(Target *target, Pvl &pvl) : ShapeModel (target, pvl) {
44  setName("DemShape");
45  m_demProj = NULL;
46  m_demCube = NULL;
47  m_interp = NULL;
48  m_portal = NULL;
49 
50  PvlGroup &kernels = pvl.findGroup("Kernels", Pvl::Traverse);
51 
52  QString demCubeFile;
53  if (kernels.hasKeyword("ElevationModel")) {
54  demCubeFile = (QString) kernels["ElevationModel"];
55  }
56  else if(kernels.hasKeyword("ShapeModel")) {
57  demCubeFile = (QString) kernels["ShapeModel"];
58  }
59 
60  m_demCube = CubeManager::Open(demCubeFile);
61 
62  // This caching algorithm works much better for DEMs than the default,
63  // regional. This is because the uniqueIOCachingAlgorithm keeps track
64  // of a history, which for something that isn't linearly processing a
65  // cube is worth it. The regional caching algorithm tosses out results
66  // from iteration 1 of setlookdirection (first algorithm) at iteration
67  // 4 and the next setimage has to re-read the data.
70  m_interp = new Interpolator(Interpolator::BiLinearType);
74 
75  // Read in the Scale of the DEM file in pixels/degree
76  const PvlGroup &mapgrp = m_demCube->label()->findGroup("Mapping", Pvl::Traverse);
77 
78  // Save map scale in pixels per degree
79  m_pixPerDegree = (double) mapgrp["Scale"];
80  }
81 
82 
89  setName("DemShape");
90  m_demProj = NULL;
91  m_demCube = NULL;
92  m_interp = NULL;
93  m_portal = NULL;
94  }
95 
96 
99  m_demProj = NULL;
100 
101  // We do not have ownership of p_demCube
102  m_demCube = NULL;
103 
104  delete m_interp;
105  m_interp = NULL;
106 
107  delete m_portal;
108  m_portal = NULL;
109  }
110 
111 
129  bool DemShape::intersectSurface(vector<double> observerPos,
130  vector<double> lookDirection) {
131  // try to intersect the target body ellipsoid as a first approximation
132  // for the iterative DEM intersection method
133  // (this method is in the ShapeModel base class)
134  if (!intersectEllipsoid(observerPos, lookDirection))
135  return false;
136 
137  double tol = resolution()/100; // 1/100 of a pixel
138  static const int maxit = 100;
139  int it = 1;
140  double dX, dY, dZ, dist2;
141  bool done = false;
142 
143  // latitude, longitude in Decimal Degrees
144  double latDD, lonDD;
145 
146  // in each iteration, the current surface intersect point is saved for
147  // comparison with the new, updated surface intersect point
148  SpiceDouble currentIntersectPt[3];
149  SpiceDouble newIntersectPt[3];
150 
151  // initialize updated surface intersection point to the ellipsoid
152  // intersection point coordinates
153  newIntersectPt[0] = surfaceIntersection()->GetX().kilometers();
154  newIntersectPt[1] = surfaceIntersection()->GetY().kilometers();
155  newIntersectPt[2] = surfaceIntersection()->GetZ().kilometers();
156 
157  double tol2 = tol * tol;
158 
159  while (!done) {
160 
161  if (it > maxit) {
162  setHasIntersection(false);
163  done = true;
164  continue;
165  }
166 
167  // The lat/lon calculations are done here by hand for speed & efficiency
168  // With doing it in the SurfacePoint class using p_surfacePoint, there
169  // is a 24% slowdown (which is significant in this very tightly looped
170  // call).
171  double t = newIntersectPt[0] * newIntersectPt[0] +
172  newIntersectPt[1] * newIntersectPt[1];
173 
174  latDD = atan2(newIntersectPt[2], sqrt(t)) * RAD2DEG;
175  lonDD = atan2(newIntersectPt[1], newIntersectPt[0]) * RAD2DEG;
176 
177  if (lonDD < 0)
178  lonDD += 360;
179 
180  // Previous Sensor version used local version of this method with lat and lon doubles.
181  // Steven made the change to improve speed. He said the difference was negilgible.
182  Distance radiusKm = localRadius(Latitude(latDD, Angle::Degrees),
183  Longitude(lonDD, Angle::Degrees));
184 
185  if (Isis::IsSpecial(radiusKm.kilometers())) {
186  setHasIntersection(false);
187  return false;
188  }
189 
190  // save current surface intersect point for comparison with new, updated
191  // surface intersect point
192  memcpy(currentIntersectPt, newIntersectPt, 3 * sizeof(double));
193 
194  double r = radiusKm.kilometers();
195  bool status;
196  surfpt_c((SpiceDouble *) &observerPos[0], &lookDirection[0], r, r, r, newIntersectPt,
197  (SpiceBoolean*) &status);
198  setHasIntersection(status);
199 
200  if (!status)
201  return status;
202 
203  dX = currentIntersectPt[0] - newIntersectPt[0];
204  dY = currentIntersectPt[1] - newIntersectPt[1];
205  dZ = currentIntersectPt[2] - newIntersectPt[2];
206  dist2 = (dX*dX + dY*dY + dZ*dZ) * 1000 * 1000;
207 
208  // Now recompute tolerance at updated surface point and recheck
209  if (dist2 < tol2) {
210  surfaceIntersection()->FromNaifArray(newIntersectPt);
211  tol = resolution() / 100.0;
212  tol2 = tol * tol;
213  if (dist2 < tol2) {
214  setHasIntersection(true);
215  done = true;
216  }
217  }
218 
219  it ++;
220  } // end of while loop
221 
222  return hasIntersection();
223  }
224 
225 
235 
236  Distance distance=Distance();
237 
238  if (lat.isValid() && lon.isValid()) {
240 
241  // The next if statement attempts to do the same as the previous one, but not as well so
242  // it was replaced.
243  // if (!m_demProj->IsGood())
244  // return Distance();
245 
247 
249 
251  m_demProj->WorldY(),
254  }
255 
256  return distance;
257  }
258 
259 
266  return m_pixPerDegree;
267  }
268 
269 
276  }
277 
278 
285  return m_demCube;
286  }
287 
288 
296  // subtract bottom from top and left from right and store results
297  double topMinusBottom[3];
298  vsub_c(neighborPoints[0], neighborPoints[1], topMinusBottom);
299  double rightMinusLeft[3];
300  vsub_c(neighborPoints[3], neighborPoints [2], rightMinusLeft);
301 
302  // take cross product of subtraction results to get normal
303  std::vector<SpiceDouble> normal(3);
304  ucrss_c(topMinusBottom, rightMinusLeft, (SpiceDouble *) &normal[0]);
305 
306  // unitize normal (and do sanity check for magnitude)
307  double mag;
308  unorm_c((SpiceDouble *) &normal[0], (SpiceDouble *) &normal[0], &mag);
309 
310  if (mag == 0.0) {
311  normal[0] = 0.;
312  normal[1] = 0.;
313  normal[2] = 0.;
314  setHasNormal(false);
315  return;
316  }
317  else {
318  setHasNormal(true);
319  }
320 
321  // Check to make sure that the normal is pointing outward from the planet
322  // surface. This is done by taking the dot product of the normal and
323  // any one of the unitized xyz vectors. If the normal is pointing inward,
324  // then negate it.
325  double centerLookVect[3];
326  SpiceDouble pB[3];
328  unorm_c(pB, centerLookVect, &mag);
329  double dotprod = vdot_c((SpiceDouble *) &normal[0], centerLookVect);
330  if (dotprod < 0.0)
331  vminus_c((SpiceDouble *) &normal[0], (SpiceDouble *) &normal[0]);
332 
333  setNormal(normal);
334  }
335 
336 
343  }
344 
345 
346 }