Official websites use .gov
A .gov website belongs to an official government organization in the United States.

Secure .gov websites use HTTPS
A lock ( ) or https:// means you’ve safely connected to the .gov website. Share sensitive information only on official, secure websites.

Isis 3 Programmer Reference
DemShape.cpp
1
5
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "DemShape.h"
8
9// Qt third party includes
10#include <QDebug>
11#include <QVector>
12
13// c standard library third party includes
14#include <algorithm>
15#include <cfloat>
16#include <cmath>
17#include <iomanip>
18#include <string>
19#include <vector>
20
21// naif third party includes
22#include <SpiceUsr.h>
23#include <SpiceZfc.h>
24#include <SpiceZmc.h>
25
26#include "Cube.h"
27#include "CubeManager.h"
28#include "Distance.h"
29#include "EllipsoidShape.h"
30//#include "Geometry3D.h"
31#include "IException.h"
32#include "Interpolator.h"
33#include "Latitude.h"
34//#include "LinearAlgebra.h"
35#include "Longitude.h"
36#include "NaifStatus.h"
37#include "Portal.h"
38#include "Projection.h"
39#include "Pvl.h"
40#include "Spice.h"
41#include "SurfacePoint.h"
42#include "Table.h"
43#include "Target.h"
44#include "UniqueIOCachingAlgorithm.h"
45
46using namespace std;
47
48namespace Isis {
55 setName("DemShape");
56 m_demProj = NULL;
57 m_demCube = NULL;
58 m_interp = NULL;
59 m_portal = NULL;
60 m_demValueFound = false;
61 m_demValue = -std::numeric_limits<double>::max();
62 }
63
64
73 DemShape::DemShape(Target *target, Pvl &pvl) : ShapeModel(target) {
74 setName("DemShape");
75 m_demProj = NULL;
76 m_demCube = NULL;
77 m_interp = NULL;
78 m_portal = NULL;
79 m_demValueFound = false;
80 m_demValue = -std::numeric_limits<double>::max();
81
82 PvlGroup &kernels = pvl.findGroup("Kernels", Pvl::Traverse);
83
84 QString demCubeFile;
85 if (kernels.hasKeyword("ElevationModel")) {
86 demCubeFile = (QString) kernels["ElevationModel"];
87 }
88 else if(kernels.hasKeyword("ShapeModel")) {
89 demCubeFile = (QString) kernels["ShapeModel"];
90 }
91
92 m_demCube = CubeManager::Open(demCubeFile);
93
94 // This caching algorithm works much better for DEMs than the default,
95 // regional. This is because the uniqueIOCachingAlgorithm keeps track
96 // of a history, which for something that isn't linearly processing a
97 // cube is worth it. The regional caching algorithm tosses out results
98 // from iteration 1 of setlookdirection (first algorithm) at iteration
99 // 4 and the next setimage has to re-read the data.
100 m_demCube->addCachingAlgorithm(new UniqueIOCachingAlgorithm(5));
101 m_demProj = m_demCube->projection();
102 m_interp = new Interpolator(Interpolator::BiLinearType);
103 m_portal = new Portal(m_interp->Samples(), m_interp->Lines(),
104 m_demCube->pixelType(),
105 m_interp->HotSample(), m_interp->HotLine());
106
107 // Read in the Scale of the DEM file in pixels/degree
108 const PvlGroup &mapgrp = m_demCube->label()->findGroup("Mapping", Pvl::Traverse);
109
110 // Save map scale in pixels per degree
111 m_pixPerDegree = (double) mapgrp["Scale"];
112 }
113
114
117 m_demProj = NULL;
118
119 // We do not have ownership of p_demCube
120 m_demCube = NULL;
121
122 delete m_interp;
123 m_interp = NULL;
124
125 delete m_portal;
126 m_portal = NULL;
127 }
128
141 double DemShape::calcDemErrUpdateIntersection(vector<double> const& observerPos,
142 vector<double> const& lookDirection,
143 double t,
144 double * intersectionPoint,
145 bool & success) {
146
147 // Initialize the return value
148 success = false;
149
150 // Compute the position along the ray
151 for (size_t i = 0; i < 3; i++)
152 intersectionPoint[i] = observerPos[i] + t * lookDirection[i];
153
154 double pointRadiusKm = sqrt(intersectionPoint[0]*intersectionPoint[0] +
155 intersectionPoint[1]*intersectionPoint[1] +
156 intersectionPoint[2]*intersectionPoint[2]);
157
158 // The lat/lon calculations are done here by hand for speed & efficiency.
159 // With doing it in the SurfacePoint class using p_surfacePoint, there
160 // is a 24% slowdown (which is significant in this very tightly looped call).
161 double norm2 = intersectionPoint[0] * intersectionPoint[0] +
162 intersectionPoint[1] * intersectionPoint[1];
163 double latDD = atan2(intersectionPoint[2], sqrt(norm2)) * RAD2DEG;
164 double lonDD = atan2(intersectionPoint[1], intersectionPoint[0]) * RAD2DEG;
165 if (lonDD < 0) {
166 lonDD += 360;
167 }
168
169 // Previous Sensor version used local version of this method with lat and lon doubles.
170 // Steven made the change to improve speed. He said the difference was negligible.
171 Distance surfaceRadiusKm = localRadius(Latitude(latDD, Angle::Degrees),
172 Longitude(lonDD, Angle::Degrees));
173
174 if (Isis::IsSpecial(surfaceRadiusKm.kilometers())) {
175 setHasIntersection(false);
176 success = false;
177 return -1; // return something
178 }
179
180 // Must set these to be able to compute resolution later
181 surfaceIntersection()->FromNaifArray(intersectionPoint);
182 setHasIntersection(true);
183
184 success = true;
185 return pointRadiusKm - surfaceRadiusKm.kilometers();
186 }
187
200 bool DemShape::intersectSurface(vector<double> observerPos,
201 vector<double> lookDirection) {
202
203 // Find norm of observerPos
204 double positionNormKm = 0.0;
205 for (size_t i = 0; i < observerPos.size(); i++)
206 positionNormKm += observerPos[i]*observerPos[i];
207 positionNormKm = sqrt(positionNormKm);
208
209 // in each iteration, the current surface intersect point is saved for
210 // comparison with the new, updated surface intersect point
211 SpiceDouble newIntersectPt[3];
212
213 // An estimate for the radius of points in the DEM. Ensure the radius is
214 // strictly below the position, so that surfpt_c does not fail.
215 double r = findDemValue();
216 r = std::min(r, positionNormKm - 0.0001);
217
218 // Try to intersect the target body ellipsoid at given radius as a first
219 // approximation.
220 bool status;
221 surfpt_c((SpiceDouble *) &observerPos[0], &lookDirection[0], r, r, r, newIntersectPt,
222 (SpiceBoolean*) &status);
223
224 if (!status) {
225 // If no luck, start at the observer, and will try points along the ray.
226 for (size_t i = 0; i < 3; i++)
227 newIntersectPt[i] = observerPos[i];
228 }
229
230 // Ensure the intersection point is set
231 surfaceIntersection()->FromNaifArray(newIntersectPt);
232 setHasIntersection(true);
233
234 // Find the current position along the ray, relative to the observer
235 // Equation: newIntersectPt = observerPos + t * lookDirection
236 double t0 = ((newIntersectPt[0] - observerPos[0]) * lookDirection[0] +
237 (newIntersectPt[1] - observerPos[1]) * lookDirection[1] +
238 (newIntersectPt[2] - observerPos[2]) * lookDirection[2])
239 / (lookDirection[0] * lookDirection[0] +
240 lookDirection[1] * lookDirection[1] +
241 lookDirection[2] * lookDirection[2]);
242
243 bool success = false;
244 double intersectionPoint[3];
245
246 // Initial guess. If no luck, wiggle it around.
247 double f0 = calcDemErrUpdateIntersection(observerPos, lookDirection, t0,
248 intersectionPoint, success);
249 if (!success) {
250 std::vector<double> delta = {1.0, 0.1, 10.0, 100.0, 1000.0, 5000.0, 10000.0};
251 for (size_t i = 0; i < delta.size(); i++) {
252 double try_t = t0 + delta[i] / 1000.0; // convert to km
253 f0 = calcDemErrUpdateIntersection(observerPos, lookDirection, try_t,
254 intersectionPoint, success);
255 if (success) {
256 t0 = try_t;
257 break;
258 }
259 }
260 }
261
262 if (!success) {
263 setHasIntersection(false);
264 return false;
265 }
266
267 // Form the next guess (secant method needs two guesses). Try to add this
268 // many meters to the current guess.
269 std::vector<double> delta = {1.0, 0.1, 10.0, 0.01, 100.0};
270 double t1 = 0, f1 = 0;
271 success = false;
272 for (size_t i = 0; i < delta.size(); i++) {
273 t1 = t0 + delta[i] / 1000.0; // convert to km
274 f1 = calcDemErrUpdateIntersection(observerPos, lookDirection, t1,
275 intersectionPoint, success);
276 if (f1 == f0)
277 continue; // equal values are not a good thing for the secant method
278 if (success)
279 break;
280 }
281 if (!success) {
282 setHasIntersection(false);
283 return false;
284 }
285
286 // Secant method with at most 15 iterations. This method converges fast.
287 // If it does not converge in this many iterations, it never will.
288 bool converged = false;
289 // Use 1/1000 of a pixel as tolerance. Otherwise the results may be not
290 // accurate enough for ground-level sensors with oblique views.
291 double tolFactor = 1000.0;
292 double tol = resolution() / tolFactor;
293 for (int i = 1; i <= 15; i++) {
294
295 // Convert to meters and compare with tolerance
296 if (std::abs(f1) * 1000.0 < tol) {
297
298 // Recompute tolerance at updated surface point and recheck
299 surfaceIntersection()->FromNaifArray(intersectionPoint);
300 tol = resolution() / tolFactor;
301
302 if (std::abs(f1) * 1000.0 < tol) {
303 converged = true;
304 setHasIntersection(true);
305 break;
306 }
307 }
308
309 // If the function values are large but are equal, there is nothing we can
310 // do
311 if (f1 == f0 && std::abs(f1) * 1000.0 >= tol) {
312 converged = false;
313 break;
314 }
315
316 // Secant method iteration
317 double t2 = t1 - f1 * (t1 - t0) / (f1 - f0);
318 double f2 = calcDemErrUpdateIntersection(observerPos, lookDirection, t2,
319 intersectionPoint, success);
320
321 if (!success) {
322 converged = false;
323 setHasIntersection(false);
324 break;
325 }
326
327 // Update
328 t0 = t1; f0 = f1;
329 t1 = t2; f1 = f2;
330 }
331
332 // The intersection point must be ahead of the observer
333 if (t0 < 0.0)
334 converged = false;
335
337
338 return converged;
339 }
340
341
348
349 if (m_demValueFound)
350 return m_demValue;
351
352 int numSamples = m_demCube->sampleCount();
353 int numLines = m_demCube->lineCount();
354
355 // Try to pick about 25 samples not too close to the boundary. Stop at the
356 // first successful one.
357 int num = 5;
358 int sampleSpacing = std::max(numSamples / (num + 1), 1);
359 int lineSpacing = std::max(numLines / (num + 1), 1);
360
361 // iterate as sample from sampleSpacing to numSamples-sampleSpacing
362 for (int s = sampleSpacing; s <= numSamples - sampleSpacing; s += sampleSpacing) {
363 for (int l = lineSpacing; l <= numLines - lineSpacing; l += lineSpacing) {
364
365 m_portal->SetPosition(s, l, 1);
366 m_demCube->read(*m_portal);
367 if (!Isis::IsSpecial(m_portal->DoubleBuffer()[0])) {
368 m_demValue = m_portal->DoubleBuffer()[0] / 1000.0;
369 m_demValueFound = true;
370 return m_demValue;
371 }
372 }
373 }
374
375 // If no luck, return the mean radius of the target
376 vector<Distance> radii = targetRadii();
377 double a = radii[0].kilometers();
378 double b = radii[1].kilometers();
379 double c = radii[2].kilometers();
380
381 m_demValue = (a + b + c)/3.0;
382
383 m_demValueFound = true;
384 return m_demValue;
385 }
386
396
397 Distance distance=Distance();
398
399 if (lat.isValid() && lon.isValid()) {
400 m_demProj->SetUniversalGround(lat.degrees(), lon.degrees());
401
402 // The next if statement attempts to do the same as the previous one, but not as well so
403 // it was replaced.
404 // if (!m_demProj->IsGood())
405 // return Distance();
406
407 m_portal->SetPosition(m_demProj->WorldX(), m_demProj->WorldY(), 1);
408
409 m_demCube->read(*m_portal);
410 distance = Distance(m_interp->Interpolate(m_demProj->WorldX(),
411 m_demProj->WorldY(),
412 m_portal->DoubleBuffer()),
414 }
415
416 return distance;
417 }
418
419
426 return m_pixPerDegree;
427 }
428
435 return m_demCube;
436 }
437
438
448 bool DemShape::isDEM() const {
449 return true;
450 }
451
452
460
461 std::vector<SpiceDouble> normal(3);
462 if (neighborPoints.isEmpty()) {
463 normal[0] = normal[1] = normal[2] = 0.0;
465 setHasLocalNormal(false);
466 return;
467 }
468
469 // subtract bottom from top and left from right and store results
470 double topMinusBottom[3];
471 vsub_c(neighborPoints[0], neighborPoints[1], topMinusBottom);
472 double rightMinusLeft[3];
473 vsub_c(neighborPoints[3], neighborPoints [2], rightMinusLeft);
474
475 // take cross product of subtraction results to get normal
476 ucrss_c(topMinusBottom, rightMinusLeft, (SpiceDouble *) &normal[0]);
477
478 // unitize normal (and do sanity check for magnitude)
479 double mag;
480 unorm_c((SpiceDouble *) &normal[0], (SpiceDouble *) &normal[0], &mag);
481
482 if (mag == 0.0) {
483 normal[0] = normal[1] = normal[2] = 0.0;
485 setHasLocalNormal(false);
486 return;
487 }
488 else {
489 setHasLocalNormal(true);
490 }
491
492 // Check to make sure that the normal is pointing outward from the planet
493 // surface. This is done by taking the dot product of the normal and
494 // any one of the unitized xyz vectors. If the normal is pointing inward,
495 // then negate it.
496 double centerLookVect[3];
497 SpiceDouble pB[3];
499 unorm_c(pB, centerLookVect, &mag);
500 double dotprod = vdot_c((SpiceDouble *) &normal[0], centerLookVect);
501 if (dotprod < 0.0) {
502 vminus_c((SpiceDouble *) &normal[0], (SpiceDouble *) &normal[0]);
503 }
504
506 }
507
508}
bool isValid() const
This indicates whether we have a legitimate angle stored or are in an unset, or invalid,...
Definition Angle.cpp:96
double degrees() const
Get the angle in units of Degrees.
Definition Angle.h:232
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition Angle.h:56
IO Handler for Isis Cubes.
Definition Cube.h:168
static Cube * Open(const QString &cubeFileName)
This method calls the method OpenCube() on the static instance.
Definition CubeManager.h:84
Projection * m_demProj
The projection of the model.
Definition DemShape.h:105
Cube * m_demCube
The cube containing the model.
Definition DemShape.h:104
~DemShape()
Destroys the DemShape.
Definition DemShape.cpp:116
Interpolator * m_interp
Use bilinear interpolation from dem.
Definition DemShape.h:108
Portal * m_portal
Buffer used to read from the model.
Definition DemShape.h:107
double m_demValue
A value picked from the dem.
Definition DemShape.h:109
bool m_demValueFound
True if it was attempted to find a value in the DEM.
Definition DemShape.h:110
double calcDemErrUpdateIntersection(std::vector< double > const &observerPos, std::vector< double > const &lookDirection, double t, double *intersectionPoint, bool &success)
Given a position along a ray, compute the difference between the radius at that position and the surf...
Definition DemShape.cpp:141
Distance localRadius(const Latitude &lat, const Longitude &lon)
Gets the radius from the DEM, if we have one.
Definition DemShape.cpp:395
double demScale()
Return the scale of the DEM shape, in pixels per degree.
Definition DemShape.cpp:425
double findDemValue()
Find a value in the DEM.
Definition DemShape.cpp:347
DemShape()
Construct a DemShape object.
Definition DemShape.cpp:54
Cube * demCube()
Returns the cube defining the shape model.
Definition DemShape.cpp:434
bool isDEM() const
Indicates that this shape model is from a DEM.
Definition DemShape.cpp:448
void calculateLocalNormal(QVector< double * > cornerNeighborPoints)
This method calculates the local surface normal of the current intersection point.
Definition DemShape.cpp:459
double m_pixPerDegree
Scale of DEM file in pixels per degree.
Definition DemShape.h:106
bool intersectSurface(std::vector< double > observerPos, std::vector< double > lookDirection)
Find the intersection point with the DEM.
Definition DemShape.cpp:200
Distance measurement, usually in meters.
Definition Distance.h:34
double kilometers() const
Get the distance in kilometers.
Definition Distance.cpp:106
@ Meters
The distance is being specified in meters.
Definition Distance.h:43
Pixel interpolator.
This class is designed to encapsulate the concept of a Latitude.
Definition Latitude.h:51
This class is designed to encapsulate the concept of a Longitude.
Definition Longitude.h:40
static void CheckErrors(bool resetNaif=true)
This method looks for any naif errors that might have occurred.
Buffer for containing a two dimensional section of an image.
Definition Portal.h:36
double resolution()
Convenience method to get pixel resolution (m/pix) at current intersection point.
void setHasIntersection(bool b)
Sets the flag to indicate whether this ShapeModel has an intersection.
void setLocalNormal(const std::vector< double >)
Sets the local normal for the currect intersection point.
virtual SurfacePoint * surfaceIntersection() const
Returns the surface intersection for this ShapeModel.
virtual std::vector< double > normal()
Returns the surface normal at the current intersection point.
std::vector< Distance > targetRadii() const
Returns the radii of the body in km.
void setHasLocalNormal(bool status)
Sets the flag to indicate whether this ShapeModel has a local normal.
ShapeModel()
Default constructor creates ShapeModel object, initializing name to an empty string,...
void setName(QString name)
Sets the shape name.
void ToNaifArray(double naifOutput[3]) const
A naif array is a c-style array of size 3.
void FromNaifArray(const double naifValues[3])
A naif array is a c-style array of size 3.
This class is used to create and store valid Isis targets.
Definition Target.h:63
This algorithm is designed for applications that jump around between a couple of spots in the cube wi...
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
Namespace for the standard library.