Isis 3 Programmer Reference
GroundGrid.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "GroundGrid.h"
8
9#include <cmath>
10#include <iomanip>
11
12#include <QVector>
13
14#include "Angle.h"
15#include "UniversalGroundMap.h"
16#include "Camera.h"
17#include "Distance.h"
18#include "Latitude.h"
19#include "Longitude.h"
20#include "Progress.h"
21#include "Projection.h"
22#include "ProjectionFactory.h"
23
24using namespace std;
25
26namespace Isis {
41 bool splitLatLon,
42 bool extendGrid,
43 unsigned int width,
44 unsigned int height) {
45 p_width = width;
46 p_height = height;
47 m_extendGrid = extendGrid;
48
49 // Initialize our grid pointer to null
50 p_grid = 0;
53
54 // Now let's figure out how big the grid needs to be, then allocate and
55 // initialize
56 p_gridSize = (unsigned long)(ceil(width * height / 8.0) + 0.5);
57
58 if (!splitLatLon) {
59 p_grid = new char[p_gridSize];
60 }
61 else {
62 p_latLinesGrid = new char[p_gridSize];
63 p_lonLinesGrid = new char[p_gridSize];
64 }
65
66 for (unsigned long i = 0; i < p_gridSize; i++) {
67 if (p_grid) p_grid[i] = 0;
70 }
71
72 // The first call of CreateGrid doesn't have to reinitialize
73 p_reinitialize = false;
74
75 p_groundMap = gmap;
76
77 // We need a lat/lon range for gridding, use the mapping group
78 // (in case of camera, use BasicMapping)
79 p_minLat = NULL;
80 p_minLon = NULL;
81 p_maxLat = NULL;
82 p_maxLon = NULL;
83
84 p_mapping = new PvlGroup;
85
86 if (p_groundMap->Camera()) {
87 Pvl tmp;
89 *p_mapping = tmp.findGroup("Mapping");
90 }
91 else {
92 *p_mapping = p_groundMap->Projection()->Mapping();
93 }
94
95 Distance radius1 = Distance((double)(*p_mapping)["EquatorialRadius"],
97 Distance radius2 = Distance((double)(*p_mapping)["PolarRadius"],
99
100 if (p_mapping->hasKeyword("MinimumLatitude")) {
101 p_minLat = new Latitude(toDouble((*p_mapping)["MinimumLatitude"][0]),
102 *p_mapping,
105 }
106 else {
107 p_minLat = new Latitude;
108 }
109
110 if (p_mapping->hasKeyword("MaximumLatitude")) {
111 p_maxLat = new Latitude(toDouble((*p_mapping)["MaximumLatitude"][0]),
112 *p_mapping,
114 }
115 else {
116 p_maxLat = new Latitude;
117 }
118
119 if (p_mapping->hasKeyword("MinimumLongitude")) {
120 p_minLon = new Longitude(toDouble((*p_mapping)["MinimumLongitude"][0]),
121 *p_mapping,
123 }
124 else {
125 p_minLon = new Longitude;
126 }
127
128 if (p_mapping->hasKeyword("MaximumLongitude")) {
129 p_maxLon = new Longitude(toDouble((*p_mapping)["MaximumLongitude"][0]),
130 *p_mapping,
132 }
133 else {
134 p_maxLon = new Longitude;
135 }
136
137 if (p_minLon->isValid() && p_maxLon->isValid()) {
138 if (*p_minLon > *p_maxLon) {
139 Longitude tmp(*p_minLon);
140 *p_minLon = *p_maxLon;
141 *p_maxLon = tmp;
142 }
143 }
144
145 Distance largerRadius = max(radius1, radius2);
146
147 // p_defaultResolution is in degrees/pixel
148
149 if (p_groundMap->HasCamera()) {
152 largerRadius.meters()) * 10;
153 }
154 else {
156 largerRadius.meters()) * 10;
157 }
158
159 if (p_defaultResolution < 0) {
160 p_defaultResolution = 10.0 / largerRadius.meters();
161 }
162 }
163
168 if (p_minLat) {
169 delete p_minLat;
170 p_minLat = NULL;
171 }
172
173 if (p_minLon) {
174 delete p_minLon;
175 p_minLon = NULL;
176 }
177
178 if (p_maxLat) {
179 delete p_maxLat;
180 p_maxLat = NULL;
181 }
182
183 if (p_maxLon) {
184 delete p_maxLon;
185 p_maxLon = NULL;
186 }
187
188 if (p_mapping) {
189 delete p_mapping;
190 p_mapping = NULL;
191 }
192
193 if (p_grid) {
194 delete[] p_grid;
195 p_grid = NULL;
196 }
197
198 if (p_latLinesGrid) {
199 delete[] p_latLinesGrid;
200 p_latLinesGrid = NULL;
201 }
202
203 if (p_lonLinesGrid) {
204 delete[] p_lonLinesGrid;
205 p_lonLinesGrid = NULL;
206 }
207 }
208
219 Longitude baseLon,
220 Angle latInc,
221 Angle lonInc,
222 Progress *progress) {
223 CreateGrid(baseLat, baseLon, latInc, lonInc, progress, Angle(), Angle());
224 }
225
226
240 Longitude baseLon,
241 Angle latInc,
242 Angle lonInc,
243 Progress *progress,
244 Angle latRes,
245 Angle lonRes) {
246 if (p_groundMap == NULL ||
247 (p_grid == NULL && p_latLinesGrid == NULL && p_lonLinesGrid == NULL)) {
248 IString msg = "GroundGrid::CreateGrid missing ground map or grid array";
249 throw IException(IException::Programmer, msg, _FILEINFO_);
250 }
251
252 if (p_reinitialize) {
253 for (unsigned long i = 0; i < p_gridSize; i++) {
254 if (p_grid) p_grid[i] = 0;
255 if (p_latLinesGrid) p_latLinesGrid[i] = 0;
256 if (p_lonLinesGrid) p_lonLinesGrid[i] = 0;
257 }
258 }
259
260 // Verify lat/lon range is okay
261 bool badLatLonRange = false;
262 QVector<IString> badLatLonValues;
263 if (!p_minLat || !p_minLat->isValid()) {
264 badLatLonValues.append("MinimumLatitude");
265 badLatLonRange = true;
266 }
267
268 if (!p_maxLat || !p_maxLat->isValid()) {
269 badLatLonValues.append("MaximumLatitude");
270 badLatLonRange = true;
271 }
272
273 if (!p_minLon || !p_minLon->isValid()) {
274 badLatLonValues.append("MinimumLongitude");
275 badLatLonRange = true;
276 }
277
278 if (!p_maxLon || !p_maxLon->isValid()) {
279 badLatLonValues.append("MaximumLongitude");
280 badLatLonRange = true;
281 }
282
283
284 if (badLatLonRange) {
285 IString msg = "Could not determine values for [";
286 for (int i = 0; i < badLatLonValues.size(); i++) {
287 if (i != 0)
288 msg += ",";
289
290 msg += badLatLonValues[i];
291 }
292
293 msg += "], please specify them explicitly";
294
295 // I chose parse because it's not really the user's fault or the
296 // programmer's. It's a stripped keyword in a Pvl.
297 throw IException(IException::Unknown, msg, _FILEINFO_);
298 }
299
300 // subsequent calls to this method must always reinitialize the grid
301 p_reinitialize = true;
302
303 // Find starting points for lat/lon
304 Latitude startLat = Latitude(baseLat - Angle(floor((baseLat - *p_minLat) / latInc) * latInc),
305 *GetMappingGroup(),
307
308 Longitude startLon = Longitude(baseLon - Angle(floor((baseLon - *p_minLon) / lonInc) * lonInc));
309
310 if (!latRes.isValid() || latRes <= Angle(0, Angle::Degrees)) {
311 latRes = Angle(p_defaultResolution,
313 }
314
315 if (!lonRes.isValid() || lonRes <= Angle(0, Angle::Degrees)) {
316 lonRes = Angle(p_defaultResolution,
318 }
319
320 Latitude endLat = Latitude((long)((*p_maxLat - startLat) / latInc) * latInc + startLat,
321 *GetMappingGroup());
322 Longitude endLon =
323 (long)((*p_maxLon - startLon) / lonInc) * lonInc + startLon;
324
325 if (progress) {
326 double numSteps = (double)((endLat - startLat) / latInc) + 1;
327 numSteps += (double)((endLon - startLon) / lonInc) + 1;
328
329 if (numSteps <= 0) {
330 IString msg = "No gridlines would intersect the image";
331 throw IException(IException::Programmer, msg, _FILEINFO_);
332 }
333
334 progress->SetMaximumSteps((long)(numSteps + 0.5));
335 progress->CheckStatus();
336 }
337
338 // Ensure that the Latitude being incremented does not throw an exception
339 // if incremented past -90 or 90 degrees.
340 Latitude latStep = startLat;
342 for (; latStep <= endLat + latInc / 2; latStep += latInc) {
343 unsigned int previousX = 0;
344 unsigned int previousY = 0;
345 bool havePrevious = false;
346
347 for (Longitude lon = *p_minLon; lon <= *p_maxLon; lon += latRes) {
348 unsigned int x = 0;
349 unsigned int y = 0;
350 bool valid = GetXY(latStep, lon, x, y);
351
352 if (valid && havePrevious) {
353 if (previousX != x || previousY != y) {
354 DrawLineOnGrid(previousX, previousY, x, y, true);
355 }
356 }
357
358 havePrevious = valid;
359 previousX = x;
360 previousY = y;
361 }
362
363 if (progress) {
364 progress->CheckStatus();
365 }
366 }
367
368 for (Longitude lon = startLon; lon <= endLon + lonInc / 2; lon += lonInc) {
369 unsigned int previousX = 0;
370 unsigned int previousY = 0;
371 bool havePrevious = false;
372
373 // Ensure that the Latitude being incremented does not throw an exception
374 // if incremented past -90 or 90 degrees.
375 latStep = *p_minLat;
377 for (; latStep <= *p_maxLat; latStep += lonRes) {
378 unsigned int x = 0;
379 unsigned int y = 0;
380
381 bool valid = GetXY(latStep, lon, x, y);
382
383 if (valid && havePrevious) {
384 if (previousX == x && previousY == y) {
385 continue;
386 }
387
388 DrawLineOnGrid(previousX, previousY, x, y, false);
389 }
390
391 havePrevious = valid;
392 previousX = x;
393 previousY = y;
394 }
395
396 if (progress) {
397 progress->CheckStatus();
398 }
399 }
400 }
401
402
412 Latitude maxLat, Longitude maxLon) {
413 if (minLat.isValid()) *p_minLat = minLat;
414 if (maxLat.isValid()) *p_maxLat = maxLat;
415 if (minLon.isValid()) *p_minLon = minLon;
416 if (maxLon.isValid()) *p_maxLon = maxLon;
417
418 if (p_minLat->isValid() && p_maxLat->isValid() && *p_minLat > *p_maxLat) {
419 Latitude tmp(*p_minLat);
420 *p_minLat = *p_maxLat;
421 *p_maxLat = tmp;
422 }
423
424 if (p_minLon->isValid() && p_maxLon->isValid() && *p_minLon > *p_maxLon) {
425 Longitude tmp(*p_minLon);
426 *p_minLon = *p_maxLon;
427 *p_maxLon = tmp;
428 }
429 }
430
437
438 const Latitude &minLat = *p_minLat;
439 const Latitude &maxLat = *p_maxLat;
440 const Longitude &minLon = *p_minLon;
441 const Longitude &maxLon = *p_maxLon;
442
443 // Walk the minLat/maxLat lines
444 // Ensure that the Latitude being incremented does not throw an exception
445 // if incremented past -90 or 90 degrees.
446 Latitude latStep = minLat;
448 for (; latStep <= maxLat; latStep += (maxLat - minLat)) {
449 unsigned int previousX = 0;
450 unsigned int previousY = 0;
451 bool havePrevious = false;
452
453 for (Longitude lon = minLon; lon <= maxLon; lon += latRes) {
454 unsigned int x = 0;
455 unsigned int y = 0;
456 bool valid = GetXY(latStep, lon, x, y);
457
458 if (valid && havePrevious) {
459 if (previousX != x || previousY != y) {
460 DrawLineOnGrid(previousX, previousY, x, y, true);
461 }
462 }
463
464 havePrevious = valid;
465 previousX = x;
466 previousY = y;
467 }
468 }
469
470 // Walk the minLon/maxLon lines
471 for (Longitude lon = minLon; lon <= maxLon; lon += (maxLon - minLon)) {
472 unsigned int previousX = 0;
473 unsigned int previousY = 0;
474 bool havePrevious = false;
475
476 // Ensure that the Latitude being incremented does not throw an exception
477 // if incremented past -90 or 90 degrees.
478 latStep = minLat;
480 for (; latStep <= maxLat; latStep += lonRes) {
481 unsigned int x = 0;
482 unsigned int y = 0;
483 bool valid = GetXY(latStep, lon, x, y);
484
485 if (valid && havePrevious) {
486 if (previousX != x || previousY != y) {
487 DrawLineOnGrid(previousX, previousY, x, y, false);
488 }
489 }
490
491 havePrevious = valid;
492 previousX = x;
493 previousY = y;
494 }
495 }
496 }
497
498
510 bool GroundGrid::PixelOnGrid(int x, int y, bool latGrid) {
511 if (x < 0) return false;
512 if (y < 0) return false;
513
514 if (x >= (int)p_width) return false;
515 if (y >= (int)p_height) return false;
516
517 return GetGridBit(x, y, latGrid);
518 }
519
520
529 bool GroundGrid::PixelOnGrid(int x, int y) {
530 if (x < 0) return false;
531 if (y < 0) return false;
532
533 if (x >= (int)p_width) return false;
534 if (y >= (int)p_height) return false;
535
536 return GetGridBit(x, y, true); // third argument shouldnt matter
537 }
538
539
549
550
558 if (p_minLat) {
559 return *p_minLat;
560 }
561 return Latitude();
562 }
563
564
572 if (p_minLon) {
573 return *p_minLon;
574 }
575 return Longitude();
576 }
577
578
586 if (p_maxLat) {
587 return *p_maxLat;
588 }
589 return Latitude();
590 }
591
592
600 if (p_maxLon) {
601 return *p_maxLon;
602 }
603 return Longitude();
604 }
605
606
619 unsigned int &x, unsigned int &y) {
620 if (!GroundMap()) return false;
621 if (m_extendGrid) {
622 if (!GroundMap()->SetUnboundGround(lat, lon)) return false;
623 }
624 else {
625 if (!GroundMap()->SetGround(lat, lon)) return false;
626 }
627 if (p_groundMap->Sample() < 0.5 || p_groundMap->Line() < 0.5) return false;
628 if (p_groundMap->Sample() < 0.5 || p_groundMap->Line() < 0.5) return false;
629
630 x = (int)(p_groundMap->Sample() - 0.5);
631 y = (int)(p_groundMap->Line() - 0.5);
632
633 if (x >= p_width || y >= p_height) return false;
634
635 return true;
636 }
637
638
646
647
655 void GroundGrid::SetGridBit(unsigned int x, unsigned int y, bool latGrid) {
656 unsigned long bitPosition = (y * p_width) + x;
657 unsigned long byteContainer = bitPosition / 8;
658 unsigned int bitOffset = bitPosition % 8;
659
660 if (byteContainer > p_gridSize) return;
661
662 if (p_grid) {
663 char &importantByte = p_grid[byteContainer];
664 importantByte |= (1 << bitOffset);
665 }
666 else if (latGrid && p_latLinesGrid) {
667 char &importantByte = p_latLinesGrid[byteContainer];
668 importantByte |= (1 << bitOffset);
669 }
670 else if (!latGrid && p_lonLinesGrid) {
671 char &importantByte = p_lonLinesGrid[byteContainer];
672 importantByte |= (1 << bitOffset);
673 }
674 else {
675 IString msg = "GroundGrid::SetGridBit no grids available";
676 throw IException(IException::Programmer, msg, _FILEINFO_);
677 }
678 }
679
680
691 bool GroundGrid::GetGridBit(unsigned int x, unsigned int y, bool latGrid) {
692 unsigned long bitPosition = (y * p_width) + x;
693 unsigned long byteContainer = bitPosition / 8;
694 unsigned int bitOffset = bitPosition % 8;
695
696 if (byteContainer > p_gridSize) return false;
697
698 bool result = false;
699
700 if (p_grid) {
701 char &importantByte = p_grid[byteContainer];
702 result = (importantByte >> bitOffset) & 1;
703 }
704 else if (latGrid && p_latLinesGrid) {
705 char &importantByte = p_latLinesGrid[byteContainer];
706 result = (importantByte >> bitOffset) & 1;
707 }
708 else if (!latGrid && p_lonLinesGrid) {
709 char &importantByte = p_lonLinesGrid[byteContainer];
710 result = (importantByte >> bitOffset) & 1;
711 }
712 else {
713 IString msg = "GroundGrid::GetGridBit no grids available";
714 throw IException(IException::Programmer, msg, _FILEINFO_);
715 }
716
717 return result;
718 }
719
720
730 void GroundGrid::DrawLineOnGrid(unsigned int x1, unsigned int y1,
731 unsigned int x2, unsigned int y2,
732 bool isLatLine) {
733 int dx = x2 - x1;
734 int dy = y2 - y1;
735
736 SetGridBit(x1, y1, isLatLine);
737
738 if (dx != 0) {
739 double m = (double)dy / (double)dx;
740 double b = y1 - m * x1;
741
742 dx = (x2 > x1) ? 1 : -1;
743 while (x1 != x2) {
744 x1 += dx;
745 y1 = (int)(m * x1 + b + 0.5);
746 SetGridBit(x1, y1, isLatLine);
747 }
748 }
749 }
750};
Defines an angle and provides unit conversions.
Definition Angle.h:45
bool isValid() const
This indicates whether we have a legitimate angle stored or are in an unset, or invalid,...
Definition Angle.cpp:95
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition Angle.h:56
void BasicMapping(Pvl &map)
Writes the basic mapping group to the specified Pvl.
Definition Camera.cpp:1367
double HighestImageResolution()
Returns the highest/best resolution in the entire image.
Definition Camera.cpp:721
Distance measurement, usually in meters.
Definition Distance.h:34
@ Meters
The distance is being specified in meters.
Definition Distance.h:43
void SetGridBit(unsigned int x, unsigned int y, bool latGrid)
This flags a bit as on the grid lines.
Longitude * p_minLon
Lowest longitude in image.
Definition GroundGrid.h:122
double p_defaultResolution
Default step size in degrees/pixel.
Definition GroundGrid.h:129
Latitude maxLatitude() const
Returns the maximum latitude for the grid.
char * p_lonLinesGrid
This stores the bits of each pixel in the grid.
Definition GroundGrid.h:115
Latitude * p_minLat
Lowest latitude in image.
Definition GroundGrid.h:121
GroundGrid(UniversalGroundMap *gmap, bool splitLatLon, bool extendGrid, unsigned int width, unsigned int height)
This method initializes the class by allocating the grid, calculating the lat/lon range,...
virtual ~GroundGrid()
Delete the object.
PvlGroup * p_mapping
The mapping group representation of the projection or camera.
Definition GroundGrid.h:127
void CreateGrid(Latitude baseLat, Longitude baseLon, Angle latInc, Angle lonInc, Progress *progress=0)
This method draws the grid internally, using default resolutions.
void SetGroundLimits(Latitude minLat, Longitude minLon, Latitude maxLat, Longitude maxLon)
This restricts (or grows) the ground range in which to draw grid lines.
bool PixelOnGrid(int x, int y)
Returns true if the grid is on this point.
Latitude minLatitude() const
Returns the minimum latitude for the grid.
UniversalGroundMap * p_groundMap
This calculates single grid pts.
Definition GroundGrid.h:119
UniversalGroundMap * GroundMap()
Returns the ground map for children.
Longitude minLongitude() const
Returns the minimum longitude for the grid.
unsigned int p_width
This is the width of the grid.
Definition GroundGrid.h:116
PvlGroup * GetMappingGroup()
Returns a mapping group representation of the projection or camera.
bool m_extendGrid
If the grid should extend past the longitude domain boundary.
Definition GroundGrid.h:132
unsigned long p_gridSize
This is width*height.
Definition GroundGrid.h:118
char * p_latLinesGrid
This stores the bits of each pixel in the grid.
Definition GroundGrid.h:114
void DrawLineOnGrid(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, bool isLatLine)
This sets the bits on the grid along the specified line.
Longitude maxLongitude() const
Returns the maximum longitude for the grid.
bool GetGridBit(unsigned int x, unsigned int y, bool latGrid)
Returns true if the specified coordinate is on the grid lines.
bool p_reinitialize
True if we need to reset p_grid in CreateGrid.
Definition GroundGrid.h:131
unsigned int p_height
This is the height of the grid.
Definition GroundGrid.h:117
char * p_grid
This stores the bits of each pixel in the grid.
Definition GroundGrid.h:113
virtual bool GetXY(Latitude lat, Longitude lon, unsigned int &x, unsigned int &y)
This method converts a lat/lon to an X/Y.
void WalkBoundary()
This draws grid lines along the extremes of the lat/lon box of the grid.
Longitude * p_maxLon
Highest longitude in image.
Definition GroundGrid.h:124
Latitude * p_maxLat
Highest latitude in image.
Definition GroundGrid.h:123
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ 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
@ AllowPastPole
Don't throw an exception if a latitude beyond -90/90 is found.
Definition Latitude.h:75
void setErrorChecking(ErrorChecking errors)
Set the error checking status.
Definition Latitude.cpp:420
This class is designed to encapsulate the concept of a Longitude.
Definition Longitude.h:40
Program progress reporter.
Definition Progress.h:42
void SetMaximumSteps(const int steps)
This sets the maximum number of steps in the process.
Definition Progress.cpp:85
void CheckStatus()
Checks and updates the status.
Definition Progress.cpp:105
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
Universal Ground Map.
double Sample() const
Returns the current line value of the camera model or projection.
double Resolution() const
Returns the resolution of the camera model or projection.
double Line() const
Returns the current line value of the camera model or projection.
bool HasCamera()
Returns whether the ground map has a camera or not.
Isis::Projection * Projection() const
Return the projection associated with the ground map (NULL implies none)
Isis::Camera * Camera() const
Return the camera associated with the ground map (NULL implies none)
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition IString.cpp:149
Namespace for the standard library.