Isis 3 Programmer Reference
VimsGroundMap.cpp
1
7/* SPDX-License-Identifier: CC0-1.0 */
8
9#include "VimsGroundMap.h"
10
11#include <iostream>
12#include <iomanip>
13
14#include <QDebug>
15#include <QVector>
16
17#include "BasisFunction.h"
18#include "Camera.h"
19#include "Constants.h"
20#include "Distance.h"
21#include "FileName.h"
22#include "IException.h"
23#include "IString.h"
24#include "iTime.h"
25#include "Latitude.h"
26#include "LeastSquares.h"
27#include "Longitude.h"
28#include "PolynomialBivariate.h"
29#include "Preference.h"
30#include "SpecialPixel.h"
31#include "Target.h"
32
33using namespace std;
34
35namespace Isis {
43 CameraGroundMap(parent) {
44
45 p_minX = DBL_MAX;
46 p_maxX = -DBL_MAX;
47 p_minY = DBL_MAX;
48 p_maxY = -DBL_MAX;
49 p_minZ = DBL_MAX;
50 p_maxZ = -DBL_MAX;
51
52 if (parent->ParentSamples() > 64 || parent->ParentLines() > 64) {
53 IString msg = "The Vims ground map does not understand cubes that "
54 "initially have more than 64 lines or 64 samples.";
55 throw IException(IException::Programmer, msg, _FILEINFO_);
56 }
57 }
58
59
60
67
68
69
117
118 PvlGroup inst = lab.findGroup("Instrument", Pvl::Traverse);
119
120 // Vis or IR
121 p_channel = (QString) inst ["Channel"];
122 // Get the start time in et
123 QString stime = (QString) inst ["NativeStartTime"];
124 QString intTime = stime.split(".").first();
125 stime = stime.split(".").last();
126
127 p_etStart = p_camera->getClockTime(intTime).Et();
128 p_etStart += toDouble(stime) / 15959.0;
129 //----------------------------------------------------------------------
130 // Because of inaccuracy with the 15 Mhz clock, the IR exposure and
131 // interline delay need to be adjusted.
132 //----------------------------------------------------------------------
133 p_irExp = (toDouble(inst ["ExposureDuration"][0]) * 1.01725) / 1000.;
134 p_visExp = (toDouble(inst ["ExposureDuration"][1])) / 1000.;
135 p_interlineDelay = (toDouble(inst ["InterlineDelayDuration"]) * 1.01725) / 1000.;
136
137 // Get summation mode
138 QString sampMode = QString((QString)inst ["SamplingMode"]).toUpper();
139
140 // Get sample/line offsets
141 int sampOffset = inst ["XOffset"];
142 int lineOffset = inst ["ZOffset"];
143
144 // Get swath width/length which will be image size unless occultation image
145 p_swathWidth = inst ["SwathWidth"];
146 p_swathLength = inst ["SwathLength"];
147
148 if (p_channel == "VIS") {
149 if (sampMode == "NORMAL") {
150 p_xPixSize = p_yPixSize = 0.00051;
151 p_xBore = p_yBore = 31;
152 p_camSampOffset = sampOffset - 1;
153 p_camLineOffset = lineOffset - 1;
154
155 }
156 else if (sampMode == "HI-RES") {
157 p_xPixSize = p_yPixSize = 0.00051 / 3.0;
158 p_xBore = p_yBore = 94;
159 //New as of 2009-08-04 per Dyer Lytle's email
160 // Old Values:p_camSampOffset = 3 * (sampOffset - 1) + p_swathWidth;
161 // p_camLineOffset = 3 * (lineOffset - 1) + p_swathLength;
162 p_camSampOffset = (3 * (sampOffset + p_swathWidth / 2)) - p_swathWidth / 2;
163 p_camLineOffset = (3 * (lineOffset + p_swathLength / 2)) - p_swathLength / 2;
164 }
165 else {
166 string msg = "Unsupported SamplingMode [" + IString(sampMode) + "]";
167 throw IException(IException::Programmer, msg, _FILEINFO_);
168 }
169 }
170 else if (p_channel == "IR") {
171 if (sampMode == "NORMAL") {
172 p_xPixSize = p_yPixSize = 0.000495;
173 p_xBore = p_yBore = 31;
174 p_camSampOffset = sampOffset - 1;
175 p_camLineOffset = lineOffset - 1;
176 }
177 else if (sampMode == "HI-RES") {
178 p_xPixSize = 0.000495 / 2.0;
179 p_yPixSize = 0.000495;
180 p_xBore = 62.5;
181 p_yBore = 31;
182 p_camSampOffset = 2 * ((sampOffset - 1) + ((p_swathWidth - 1) / 4));
183 p_camLineOffset = lineOffset - 1;
184 }
185 else {
186 string msg = "Unsupported SamplingMode [" + IString(sampMode) + "]";
187 throw IException(IException::Programmer, msg, _FILEINFO_);
188 }
189 }
190
191 //---------------------------------------------------------------------
192 // Loop for each pixel in cube, get pointing information and calculate
193 // control point (line, sample, x, y, z) for later use in latlon_to_linesamp.
194 //---------------------------------------------------------------------
196 for (int line = 0; line < p_camera->ParentLines(); line++) {
197
198 // VIS exposure is for a single line. According to SIS,
199 // NATIVE_START_TIME is for the first pixel of the IR exposure.
200 // "The offset from IR start to VIS start is calculated by
201 // IrExposMsec - VisExposMsec)/2".
202 // This needs to be moved to forward routine
203
204 if (p_channel == "VIS") {
205 double et = ((double)p_etStart + (((p_irExp * p_swathWidth) - p_visExp) / 2.)) +
206 ((line + 0.5) * p_visExp);
207 p_camera->setTime(et);
208 }
209
210 for (int samp = 0; samp < p_camera->ParentSamples(); samp++) {
211 if (p_channel == "IR") {
212 double et = (double)p_etStart +
213 (line * p_camera->ParentSamples() * p_irExp) +
214 (line * p_interlineDelay) + ((samp + 0.5) * p_irExp);
215 p_camera->setTime(et);
216 }
217
218 if (p_camera->SetImage((double) samp + 1, (double)line + 1)) {
219
220 double xyz[3];
221 p_camera->Coordinate(xyz);
222
223 if (xyz[0] != Null && xyz[1] != Null && xyz[2] != Null) {
224 p_xyzMap[line][samp].setX(xyz[0]);
225 p_xyzMap[line][samp].setY(xyz[1]);
226 p_xyzMap[line][samp].setZ(xyz[2]);
227
228// if (samp !=0 ) {
229// QVector3D deltaXyz = p_xyzMap[line][samp-1] - p_xyzMap[line][samp];
230// qDebug()<<"samp:line = "<<samp<<" : "<<line<<" xyzMap[line][samp-1] = "<<p_xyzMap[line][samp-1]<<" xyzMap[line][samp] = "<<p_xyzMap[line][samp]<<" delta = "<<deltaXyz.length();
231// }
232
233 // Find min/max x,y,z for use in SetGround method to make sure incoming lat/lon falls
234 // within image.
235 if (xyz[0] < p_minX) p_minX = xyz[0];
236 if (xyz[0] > p_maxX) p_maxX = xyz[0];
237 if (xyz[1] < p_minY) p_minY = xyz[1];
238 if (xyz[1] > p_maxY) p_maxY = xyz[1];
239 if (xyz[2] < p_minZ) p_minZ = xyz[2];
240 if (xyz[2] > p_maxZ) p_maxZ = xyz[2];
241 }
242 }
243 }
244 }
245
246 // Fine tune min/max Z so that if the pole is actually in the image, it will be found in
247 // the SetGround method. If the min/max values found for pixels centers is used, the pole
248 // will not be found even if it is actually in the image. if the min/max z values are within
249 // 1 km of the radius, set to the radius.
250
251 // NOTE: IF THERE ARE PROBLEMS FOUND IN THE CAMERA MODEL, THIS WOULD BE THE FIRST PLACE
252 // I WOULD LOOK.
253 Distance radii[3];
254 p_camera->radii(radii);
255 if (abs(abs(p_minZ) - radii[2].kilometers()) < 1.0) {
256 p_minZ = radii[2].kilometers() * (int(abs(p_minZ) / p_minZ));
257 }
258 if (abs(abs(p_maxZ) - radii[2].kilometers()) < 1.0) {
259 p_maxZ = radii[2].kilometers() * (int(abs(p_maxZ) / p_maxZ));
260 }
261
263 }
264
265
287 bool VimsGroundMap::SetFocalPlane(const double ux, const double uy,
288 const double uz) {
289
290 p_ux = ux;
291 p_uy = uy;
292 p_uz = uz;
293
294 double imgSamp = ux;
295 double imgLine = uy;
296
297 if ((imgLine < 0.5) || (imgLine > p_camera->ParentLines() + 0.5) ||
298 (imgSamp < 0.5) || (imgSamp > p_camera->ParentSamples() + 0.5)) {
299 return false;
300 }
301 imgLine--;
302 imgSamp--;
303
304 // does interline_delay & exposure-duration account for summing modes?
305 // if not, won't use p_parentLine/p_parentSample
306 double et = 0.;
307 if (p_channel == "VIS") {
308 et = (p_etStart + ((p_irExp * p_swathWidth) - p_visExp) / 2.) +
309 ((imgLine + 0.5) * p_visExp);
310 }
311 else if (p_channel == "IR") {
312 et = (double)p_etStart +
313 (imgLine * p_camera->ParentSamples() * p_irExp) +
314 (imgLine * p_interlineDelay) + ((imgSamp + 0.5) * p_irExp);
315 }
316 p_camera->setTime(et);
317
318 // get Look Direction
319 SpiceDouble lookC[3];
320 LookDirection(lookC);
321
322 SpiceDouble unitLookC[3];
323 vhat_c(lookC, unitLookC);
324 return p_camera->SetLookDirection(unitLookC);
325 }
326
327
359 bool VimsGroundMap::SetGround(const Latitude &lat, const Longitude &lon) {
360
361
362 // Make sure at least 1 pixel in image has projected onto surface
363 if (p_minX == DBL_MAX || p_maxX == -DBL_MAX ||
364 p_minY == DBL_MAX || p_maxY == -DBL_MAX ||
365 p_minZ == DBL_MAX || p_maxZ == -DBL_MAX) return false;
366
367 QVector3D xyz;
368 if (p_camera->target()->shape()->name() == "Plane") {
369 double radius = lat.degrees();
370 if(radius <= 0.0)
371 return false;
372
373 double xCheck = radius * 0.001 * cos(lon.radians());
374 double yCheck = radius * 0.001 * sin(lon.radians());
375
376 xyz.setX(xCheck);
377 xyz.setY(yCheck);
378 xyz.setZ(0.);
379 }
380 else {
381 // Convert lat/lon to x/y/z
382 Distance radius = p_camera->LocalRadius(lat, lon);
383 SpiceDouble pB[3];
384 latrec_c(radius.kilometers(), lon.radians(), lat.radians(), pB);
385
386 // Make sure this point falls within range of image
387 if (pB[0] < p_minX || pB[0] > p_maxX ||
388 pB[1] < p_minY || pB[1] > p_maxY ||
389 pB[2] < p_minZ || pB[2] > p_maxZ) return false;
390
391 xyz.setX(pB[0]);
392 xyz.setY(pB[1]);
393 xyz.setZ(pB[2]);
394 }
395
396 double minDist = DBL_MAX;
397 int minSamp = -1;
398 int minLine = -1;
399
400 // Find closest points ??? what tolerance ???
401 for (int line = 0; line < p_camera->ParentLines(); line++) {
402 for (int samp = 0; samp < p_camera->ParentSamples(); samp++) {
403
404 if (p_xyzMap[line][samp].isNull()) continue;
405
406 // Subtract map from coordinate then get length
407 QVector3D deltaXyz = xyz - p_xyzMap[line][samp];
408 if (deltaXyz.length() < minDist) {
409 minDist = deltaXyz.length();
410 minSamp = samp;
411 minLine = line;
412 }
413 }
414 }
415
416 //-----------------------------------------------------------------
417 // If dist is less than some ??? tolerance ??? this is the
418 // closest point. Use this point and surrounding 8 pts as
419 // control pts.
420 //----------------------------------------------------------------
421 if (minDist >= DBL_MAX) return false;
422
423 //-------------------------------------------------------------
424 // Set-up for LU decomposition (least2 fit).
425 // Assume we will have 9 control points, this may not be true
426 // and will need to be adjusted before the final solution.
427 //-------------------------------------------------------------
428 BasisFunction sampXyzBasis("Sample", 4, 4);
429 BasisFunction lineXyzBasis("Line", 4, 4);
430 LeastSquares sampXyzLsq(sampXyzBasis);
431 LeastSquares lineXyzLsq(lineXyzBasis);
432 vector<double> knownXyz(4);
433
434 // Solve using x/y/z
435 for (int line = minLine - 1; line < minLine + 2; line++) {
436 if (line < 0 || line > p_camera->ParentLines() - 1) continue;
437 for (int samp = minSamp - 1; samp < minSamp + 2; samp++) {
438 // Check for edges
439 if (samp < 0 || samp > p_camera->ParentSamples() - 1) continue;
440 if (p_xyzMap[line][samp].isNull()) continue;
441
442 knownXyz[0] = p_xyzMap[line][samp].x();
443 knownXyz[1] = p_xyzMap[line][samp].y();
444 knownXyz[2] = p_xyzMap[line][samp].z();
445 knownXyz[3] = 1;
446 sampXyzLsq.AddKnown(knownXyz, samp + 1);
447 lineXyzLsq.AddKnown(knownXyz, line + 1);
448 }
449 }
450
451 if (sampXyzLsq.Knowns() < 4) return false;
452
453 sampXyzLsq.Solve();
454 lineXyzLsq.Solve();
455
456 // Solve for sample, line position corresponding to input lat, lon
457 knownXyz[0] = xyz.x();
458 knownXyz[1] = xyz.y();
459 knownXyz[2] = xyz.z();
460 knownXyz[3] = 1;
461 double inSamp = sampXyzLsq.Evaluate(knownXyz);
462 double inLine = lineXyzLsq.Evaluate(knownXyz);
463
464
465 if (inSamp < 0.5 || inSamp > p_camera->ParentSamples() + 0.5 ||
466 inLine < 0.5 || inLine > p_camera->ParentLines() + 0.5) {
467 return false;
468 }
469
470 // Sanity check
472 p_camera->SetImage(inSamp, inLine);
474 if (!p_camera->HasSurfaceIntersection()) return false;
475
476 p_focalPlaneX = inSamp;
477 p_focalPlaneY = inLine;
478
479 return true;
480 }
481
482
492 bool VimsGroundMap::SetGround(const SurfacePoint &surfacePoint) {
493 return SetGround(surfacePoint.GetLatitude(), surfacePoint.GetLongitude());
494// return SetGroundwithLatitudeLongitude(surfacePoint.GetLatitude(), surfacePoint.GetLongitude());
495 }
496
497
512
513 double x = p_ux - 1. + p_camSampOffset;
514 double y = p_uy - 1. + p_camLineOffset;
515
516 // Compute pointing angles based on pixel size separation
517 double theta = Isis::HALFPI - (y - p_yBore) * p_yPixSize;
518 double phi = (-1. * Isis::HALFPI) + (x - p_xBore) * p_xPixSize;
519
520 v[0] = sin(theta) * cos(phi);
521 v[1] = cos(theta);
522 v[2] = sin(theta) * sin(phi) / -1.;
523 }
524}
Generic linear equation class.
Convert between undistorted focal plane and ground coordinates.
double p_focalPlaneX
Camera's x focal plane coordinate.
Camera * p_camera
Camera.
double p_focalPlaneY
Camera's y focal plane coordinate.
int ParentLines() const
Returns the number of lines in the parent alphacube.
Definition Camera.cpp:2836
void IgnoreProjection(bool ignore)
Set whether or not the camera should ignore the Projection.
Definition Camera.cpp:2955
int ParentSamples() const
Returns the number of samples in the parent alphacube.
Definition Camera.cpp:2846
virtual bool SetImage(const double sample, const double line)
Sets the sample/line values of the image to get the lat/lon values.
Definition Camera.cpp:156
Distance measurement, usually in meters.
Definition Distance.h:34
double kilometers() const
Get the distance in kilometers.
Definition Distance.cpp:106
Isis exception class.
Definition IException.h:91
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
Adds specific functionality to C++ strings.
Definition IString.h:165
This class is designed to encapsulate the concept of a Latitude.
Definition Latitude.h:51
Generic least square fitting class.
This class is designed to encapsulate the concept of a Longitude.
Definition Longitude.h:40
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
@ Traverse
Search child objects.
Definition PvlObject.h:158
void setTime(const iTime &time)
By setting the time you essential set the position of the spacecraft and body as indicated in the cla...
Definition Sensor.cpp:99
bool HasSurfaceIntersection() const
Returns if the last call to either SetLookDirection or SetUniversalGround had a valid intersection wi...
Definition Sensor.cpp:188
void Coordinate(double p[3]) const
Returns the x,y,z of the surface intersection in BodyFixed km.
Definition Sensor.cpp:198
Distance LocalRadius() const
Returns the local radius at the intersection point.
Definition Sensor.cpp:269
bool SetLookDirection(const double v[3])
Sets the look direction of the spacecraft.
Definition Sensor.cpp:143
virtual iTime getClockTime(QString clockValue, int sclkCode=-1, bool clockTicks=false)
This converts the spacecraft clock ticks value (clockValue) to an iTime.
Definition Spice.cpp:1060
void radii(Distance r[3]) const
Returns the radii of the body in km.
Definition Spice.cpp:937
virtual Target * target() const
Returns a pointer to the target object.
Definition Spice.cpp:1380
This class defines a body-fixed surface point.
Latitude GetLatitude() const
Return the body-fixed latitude for the surface point.
Longitude GetLongitude() const
Return the body-fixed longitude for the surface point.
double p_visExp
VIS exposure duration, divided by 1000.
virtual ~VimsGroundMap()
Destroys the VimsGroundMap object.
double p_xPixSize
X pixel size.
double p_uz
Distorted focal plane z, in millimeters.
double p_irExp
IR exposure duration, divided by 1000.
QString p_channel
Channel keyword value from the instrument group of the labels.
double p_ux
Distorted focal plane x, in millimeters.
void LookDirection(double v[3])
Determines the look direction in the camera coordinate system.
virtual bool SetGround(const Latitude &lat, const Longitude &lon)
Compute undistorted focal plane coordinate from ground position.
double p_xBore
X boresight.
double p_interlineDelay
InterlineDelayDuration keyword value from the instrument group of the labels, divided by 1000.
int p_swathLength
SwathLength keyword value from the instrument group of the labels.
double p_yBore
Y boresight.
double p_uy
Distorted focal plane y, in millimeters.
VimsGroundMap(Camera *parent, Pvl &lab)
Constructs the VimsGroundMap object.
virtual bool SetFocalPlane(const double ux, const double uy, const double uz)
Compute ground position from focal plane coordinate.
int p_camSampOffset
Sample offset.
int p_swathWidth
SwathWidth keyword value from the instrument group of the labels.
void Init(Pvl &lab)
Initialize vims camera model.
SpiceDouble p_etStart
Start ephemeris time.
int p_camLineOffset
Line offset.
double p_yPixSize
Y pixel size.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
const double Null
Value for an Isis Null pixel.
const double HALFPI
The mathematical constant PI/2.
Definition Constants.h:41
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition IString.cpp:149
Namespace for the standard library.