Isis 3.0 Programmer Reference
Back | Home
GroundGrid.cpp
1 #include "GroundGrid.h"
2 
3 #include <cmath>
4 #include <iomanip>
5 
6 #include <QVector>
7 
8 #include "Angle.h"
9 #include "UniversalGroundMap.h"
10 #include "Camera.h"
11 #include "Distance.h"
12 #include "Latitude.h"
13 #include "Longitude.h"
14 #include "Progress.h"
15 #include "Projection.h"
16 #include "ProjectionFactory.h"
17 
18 using namespace std;
19 
20 namespace Isis {
32  GroundGrid::GroundGrid(UniversalGroundMap *gmap,
33  bool splitLatLon,
34  unsigned int width,
35  unsigned int height) {
36  p_width = width;
37  p_height = height;
38 
39  // Initialize our grid pointer to null
40  p_grid = 0;
41  p_latLinesGrid = 0;
42  p_lonLinesGrid = 0;
43 
44  // Now let's figure out how big the grid needs to be, then allocate and
45  // initialize
46  p_gridSize = (unsigned long)(ceil(width * height / 8.0) + 0.5);
47 
48  if (!splitLatLon) {
49  p_grid = new char[p_gridSize];
50  }
51  else {
52  p_latLinesGrid = new char[p_gridSize];
53  p_lonLinesGrid = new char[p_gridSize];
54  }
55 
56  for (unsigned long i = 0; i < p_gridSize; i++) {
57  if (p_grid) p_grid[i] = 0;
58  if (p_latLinesGrid) p_latLinesGrid[i] = 0;
59  if (p_lonLinesGrid) p_lonLinesGrid[i] = 0;
60  }
61 
62  // The first call of CreateGrid doesn't have to reinitialize
63  p_reinitialize = false;
64 
65  p_groundMap = gmap;
66 
67  // We need a lat/lon range for gridding, use the mapping group
68  // (in case of camera, use BasicMapping)
69  p_minLat = NULL;
70  p_minLon = NULL;
71  p_maxLat = NULL;
72  p_maxLon = NULL;
73 
74  p_mapping = new PvlGroup;
75 
76  if (p_groundMap->Camera()) {
77  Pvl tmp;
78  p_groundMap->Camera()->BasicMapping(tmp);
79  *p_mapping = tmp.findGroup("Mapping");
80  }
81  else {
82  *p_mapping = p_groundMap->Projection()->Mapping();
83  }
84 
85  Distance radius1 = Distance((double)(*p_mapping)["EquatorialRadius"],
86  Distance::Meters);
87  Distance radius2 = Distance((double)(*p_mapping)["PolarRadius"],
88  Distance::Meters);
89 
90  if (p_mapping->hasKeyword("MinimumLatitude")) {
91  p_minLat = new Latitude(toDouble((*p_mapping)["MinimumLatitude"][0]),
92  *p_mapping,
93  Angle::Degrees,
94  Latitude::AllowPastPole);
95  }
96  else {
97  p_minLat = new Latitude;
98  }
99 
100  if (p_mapping->hasKeyword("MaximumLatitude")) {
101  p_maxLat = new Latitude(toDouble((*p_mapping)["MaximumLatitude"][0]),
102  *p_mapping,
103  Angle::Degrees);
104  }
105  else {
106  p_maxLat = new Latitude;
107  }
108 
109  if (p_mapping->hasKeyword("MinimumLongitude")) {
110  p_minLon = new Longitude(toDouble((*p_mapping)["MinimumLongitude"][0]),
111  *p_mapping,
112  Angle::Degrees);
113  }
114  else {
115  p_minLon = new Longitude;
116  }
117 
118  if (p_mapping->hasKeyword("MaximumLongitude")) {
119  p_maxLon = new Longitude(toDouble((*p_mapping)["MaximumLongitude"][0]),
120  *p_mapping,
121  Angle::Degrees);
122  }
123  else {
124  p_maxLon = new Longitude;
125  }
126 
127  if (p_minLon->isValid() && p_maxLon->isValid()) {
128  if (*p_minLon > *p_maxLon) {
129  Longitude tmp(*p_minLon);
130  *p_minLon = *p_maxLon;
131  *p_maxLon = tmp;
132  }
133  }
134 
135  Distance largerRadius = max(radius1, radius2);
136 
137  // p_defaultResolution is in degrees/pixel
138 
139  if (p_groundMap->HasCamera()) {
140  p_defaultResolution =
141  (p_groundMap->Camera()->HighestImageResolution() /
142  largerRadius.meters()) * 10;
143  }
144  else {
145  p_defaultResolution = (p_groundMap->Resolution() /
146  largerRadius.meters()) * 10;
147  }
148 
149  if (p_defaultResolution < 0) {
150  p_defaultResolution = 10.0 / largerRadius.meters();
151  }
152  }
153 
157  GroundGrid::~GroundGrid() {
158  if (p_minLat) {
159  delete p_minLat;
160  p_minLat = NULL;
161  }
162 
163  if (p_minLon) {
164  delete p_minLon;
165  p_minLon = NULL;
166  }
167 
168  if (p_maxLat) {
169  delete p_maxLat;
170  p_maxLat = NULL;
171  }
172 
173  if (p_maxLon) {
174  delete p_maxLon;
175  p_maxLon = NULL;
176  }
177 
178  if (p_mapping) {
179  delete p_mapping;
180  p_mapping = NULL;
181  }
182 
183  if (p_grid) {
184  delete[] p_grid;
185  p_grid = NULL;
186  }
187 
188  if (p_latLinesGrid) {
189  delete[] p_latLinesGrid;
190  p_latLinesGrid = NULL;
191  }
192 
193  if (p_lonLinesGrid) {
194  delete[] p_lonLinesGrid;
195  p_lonLinesGrid = NULL;
196  }
197  }
198 
208  void GroundGrid::CreateGrid(Latitude baseLat,
209  Longitude baseLon,
210  Angle latInc,
211  Angle lonInc,
212  Progress *progress) {
213  CreateGrid(baseLat, baseLon, latInc, lonInc, progress, Angle(), Angle());
214  }
215 
216 
229  void GroundGrid::CreateGrid(Latitude baseLat,
230  Longitude baseLon,
231  Angle latInc,
232  Angle lonInc,
233  Progress *progress,
234  Angle latRes,
235  Angle lonRes) {
236  if (p_groundMap == NULL ||
237  (p_grid == NULL && p_latLinesGrid == NULL && p_lonLinesGrid == NULL)) {
238  IString msg = "GroundGrid::CreateGrid missing ground map or grid array";
239  throw IException(IException::Programmer, msg, _FILEINFO_);
240  }
241 
242  if (p_reinitialize) {
243  for (unsigned long i = 0; i < p_gridSize; i++) {
244  if (p_grid) p_grid[i] = 0;
245  if (p_latLinesGrid) p_latLinesGrid[i] = 0;
246  if (p_lonLinesGrid) p_lonLinesGrid[i] = 0;
247  }
248  }
249 
250  // Verify lat/lon range is okay
251  bool badLatLonRange = false;
252  QVector<IString> badLatLonValues;
253  if (!p_minLat || !p_minLat->isValid()) {
254  badLatLonValues.append("MinimumLatitude");
255  badLatLonRange = true;
256  }
257 
258  if (!p_maxLat || !p_maxLat->isValid()) {
259  badLatLonValues.append("MaximumLatitude");
260  badLatLonRange = true;
261  }
262 
263  if (!p_minLon || !p_minLon->isValid()) {
264  badLatLonValues.append("MinimumLongitude");
265  badLatLonRange = true;
266  }
267 
268  if (!p_maxLon || !p_maxLon->isValid()) {
269  badLatLonValues.append("MaximumLongitude");
270  badLatLonRange = true;
271  }
272 
273 
274  if (badLatLonRange) {
275  IString msg = "Could not determine values for [";
276  for (int i = 0; i < badLatLonValues.size(); i++) {
277  if (i != 0)
278  msg += ",";
279 
280  msg += badLatLonValues[i];
281  }
282 
283  msg += "], please specify them explicitly";
284 
285  // I chose parse because it's not really the user's fault or the
286  // programmer's. It's a stripped keyword in a Pvl.
287  throw IException(IException::Unknown, msg, _FILEINFO_);
288  }
289 
290  // subsequent calls to this method must always reinitialize the grid
291  p_reinitialize = true;
292 
293  // Find starting points for lat/lon
294  Latitude startLat = Latitude(baseLat - Angle(floor((baseLat - *p_minLat) / latInc) * latInc),
295  *GetMappingGroup(),
296  Latitude::AllowPastPole);
297 
298  Longitude startLon = Longitude(baseLon - Angle(floor((baseLon - *p_minLon) / lonInc) * lonInc));
299 
300  if (!latRes.isValid() || latRes <= Angle(0, Angle::Degrees)) {
301  latRes = Angle(p_defaultResolution,
302  Angle::Degrees);
303  }
304 
305  if (!lonRes.isValid() || lonRes <= Angle(0, Angle::Degrees)) {
306  lonRes = Angle(p_defaultResolution,
307  Angle::Degrees);
308  }
309 
310  Latitude endLat = Latitude((long)((*p_maxLat - startLat) / latInc) * latInc + startLat,
311  *GetMappingGroup());
312  Longitude endLon =
313  (long)((*p_maxLon - startLon) / lonInc) * lonInc + startLon;
314 
315  if (progress) {
316  double numSteps = (double)((endLat - startLat) / latInc) + 1;
317  numSteps += (double)((endLon - startLon) / lonInc) + 1;
318 
319  if (numSteps <= 0) {
320  IString msg = "No gridlines would intersect the image";
321  throw IException(IException::Programmer, msg, _FILEINFO_);
322  }
323 
324  progress->SetMaximumSteps((long)(numSteps + 0.5));
325  progress->CheckStatus();
326  }
327 
328  for (Latitude lat = startLat; lat <= endLat + latInc / 2; lat += latInc) {
329  unsigned int previousX = 0;
330  unsigned int previousY = 0;
331  bool havePrevious = false;
332 
333  for (Longitude lon = *p_minLon; lon <= *p_maxLon; lon += latRes) {
334  unsigned int x = 0;
335  unsigned int y = 0;
336  bool valid = GetXY(lat, lon, x, y);
337 
338  if (valid && havePrevious) {
339  if (previousX != x || previousY != y) {
340  DrawLineOnGrid(previousX, previousY, x, y, true);
341  }
342  }
343 
344  havePrevious = valid;
345  previousX = x;
346  previousY = y;
347  }
348 
349  if (progress) {
350  progress->CheckStatus();
351  }
352  }
353 
354  for (Longitude lon = startLon; lon <= endLon + lonInc / 2; lon += lonInc) {
355  unsigned int previousX = 0;
356  unsigned int previousY = 0;
357  bool havePrevious = false;
358 
359  for (Latitude lat = *p_minLat; lat <= *p_maxLat; lat += lonRes) {
360  unsigned int x = 0;
361  unsigned int y = 0;
362 
363  bool valid = GetXY(lat, lon, x, y);
364 
365  if (valid && havePrevious) {
366  if (previousX == x && previousY == y) {
367  continue;
368  }
369 
370  DrawLineOnGrid(previousX, previousY, x, y, false);
371  }
372 
373  havePrevious = valid;
374  previousX = x;
375  previousY = y;
376  }
377 
378  if (progress) {
379  progress->CheckStatus();
380  }
381  }
382  }
383 
384 
393  void GroundGrid::SetGroundLimits(Latitude minLat, Longitude minLon,
394  Latitude maxLat, Longitude maxLon) {
395  if (minLat.isValid()) *p_minLat = minLat;
396  if (maxLat.isValid()) *p_maxLat = maxLat;
397  if (minLon.isValid()) *p_minLon = minLon;
398  if (maxLon.isValid()) *p_maxLon = maxLon;
399 
400  if (p_minLat->isValid() && p_maxLat->isValid() && *p_minLat > *p_maxLat) {
401  Latitude tmp(*p_minLat);
402  *p_minLat = *p_maxLat;
403  *p_maxLat = tmp;
404  }
405 
406  if (p_minLon->isValid() && p_maxLon->isValid() && *p_minLon > *p_maxLon) {
407  Longitude tmp(*p_minLon);
408  *p_minLon = *p_maxLon;
409  *p_maxLon = tmp;
410  }
411  }
412 
416  void GroundGrid::WalkBoundary() {
417  Angle latRes = Angle(p_defaultResolution, Angle::Degrees);
418  Angle lonRes = Angle(p_defaultResolution, Angle::Degrees);
419 
420  const Latitude &minLat = *p_minLat;
421  const Latitude &maxLat = *p_maxLat;
422  const Longitude &minLon = *p_minLon;
423  const Longitude &maxLon = *p_maxLon;
424 
425  // Walk the minLat/maxLat lines
426  for (Latitude lat = minLat; lat <= maxLat; lat += (maxLat - minLat)) {
427  unsigned int previousX = 0;
428  unsigned int previousY = 0;
429  bool havePrevious = false;
430 
431  for (Longitude lon = minLon; lon <= maxLon; lon += latRes) {
432  unsigned int x = 0;
433  unsigned int y = 0;
434  bool valid = GetXY(lat, lon, x, y);
435 
436  if (valid && havePrevious) {
437  if (previousX != x || previousY != y) {
438  DrawLineOnGrid(previousX, previousY, x, y, true);
439  }
440  }
441 
442  havePrevious = valid;
443  previousX = x;
444  previousY = y;
445  }
446  }
447 
448  // Walk the minLon/maxLon lines
449  for (Longitude lon = minLon; lon <= maxLon; lon += (maxLon - minLon)) {
450  unsigned int previousX = 0;
451  unsigned int previousY = 0;
452  bool havePrevious = false;
453 
454  for (Latitude lat = minLat; lat <= maxLat; lat += lonRes) {
455  unsigned int x = 0;
456  unsigned int y = 0;
457  bool valid = GetXY(lat, lon, x, y);
458 
459  if (valid && havePrevious) {
460  if (previousX != x || previousY != y) {
461  DrawLineOnGrid(previousX, previousY, x, y, false);
462  }
463  }
464 
465  havePrevious = valid;
466  previousX = x;
467  previousY = y;
468  }
469  }
470  }
471 
472 
484  bool GroundGrid::PixelOnGrid(int x, int y, bool latGrid) {
485  if (x < 0) return false;
486  if (y < 0) return false;
487 
488  if (x >= (int)p_width) return false;
489  if (y >= (int)p_height) return false;
490 
491  return GetGridBit(x, y, latGrid);
492  }
493 
494 
503  bool GroundGrid::PixelOnGrid(int x, int y) {
504  if (x < 0) return false;
505  if (y < 0) return false;
506 
507  if (x >= (int)p_width) return false;
508  if (y >= (int)p_height) return false;
509 
510  return GetGridBit(x, y, true); // third argument shouldnt matter
511  }
512 
513 
520  PvlGroup *GroundGrid::GetMappingGroup() {
521  return p_mapping;
522  }
523 
535  bool GroundGrid::GetXY(Latitude lat, Longitude lon,
536  unsigned int &x, unsigned int &y) {
537  if (!GroundMap()) return false;
538  if (!GroundMap()->SetGround(lat, lon)) return false;
539  if (p_groundMap->Sample() < 0.5 || p_groundMap->Line() < 0.5) return false;
540  if (p_groundMap->Sample() < 0.5 || p_groundMap->Line() < 0.5) return false;
541 
542  x = (int)(p_groundMap->Sample() - 0.5);
543  y = (int)(p_groundMap->Line() - 0.5);
544 
545  if (x >= p_width || y >= p_height) return false;
546 
547  return true;
548  }
549 
550 
555  UniversalGroundMap *GroundGrid::GroundMap() {
556  return p_groundMap;
557  }
558 
559 
567  void GroundGrid::SetGridBit(unsigned int x, unsigned int y, bool latGrid) {
568  unsigned long bitPosition = (y * p_width) + x;
569  unsigned long byteContainer = bitPosition / 8;
570  unsigned int bitOffset = bitPosition % 8;
571 
572  if (byteContainer > p_gridSize) return;
573 
574  if (p_grid) {
575  char &importantByte = p_grid[byteContainer];
576  importantByte |= (1 << bitOffset);
577  }
578  else if (latGrid && p_latLinesGrid) {
579  char &importantByte = p_latLinesGrid[byteContainer];
580  importantByte |= (1 << bitOffset);
581  }
582  else if (!latGrid && p_lonLinesGrid) {
583  char &importantByte = p_lonLinesGrid[byteContainer];
584  importantByte |= (1 << bitOffset);
585  }
586  else {
587  IString msg = "GroundGrid::SetGridBit no grids available";
588  throw IException(IException::Programmer, msg, _FILEINFO_);
589  }
590  }
591 
592 
603  bool GroundGrid::GetGridBit(unsigned int x, unsigned int y, bool latGrid) {
604  unsigned long bitPosition = (y * p_width) + x;
605  unsigned long byteContainer = bitPosition / 8;
606  unsigned int bitOffset = bitPosition % 8;
607 
608  if (byteContainer > p_gridSize) return false;
609 
610  bool result = false;
611 
612  if (p_grid) {
613  char &importantByte = p_grid[byteContainer];
614  result = (importantByte >> bitOffset) & 1;
615  }
616  else if (latGrid && p_latLinesGrid) {
617  char &importantByte = p_latLinesGrid[byteContainer];
618  result = (importantByte >> bitOffset) & 1;
619  }
620  else if (!latGrid && p_lonLinesGrid) {
621  char &importantByte = p_lonLinesGrid[byteContainer];
622  result = (importantByte >> bitOffset) & 1;
623  }
624  else {
625  IString msg = "GroundGrid::GetGridBit no grids available";
626  throw IException(IException::Programmer, msg, _FILEINFO_);
627  }
628 
629  return result;
630  }
631 
632 
642  void GroundGrid::DrawLineOnGrid(unsigned int x1, unsigned int y1,
643  unsigned int x2, unsigned int y2,
644  bool isLatLine) {
645  int dx = x2 - x1;
646  int dy = y2 - y1;
647 
648  SetGridBit(x1, y1, isLatLine);
649 
650  if (dx != 0) {
651  double m = (double)dy / (double)dx;
652  double b = y1 - m * x1;
653 
654  dx = (x2 > x1) ? 1 : -1;
655  while (x1 != x2) {
656  x1 += dx;
657  y1 = (int)(m * x1 + b + 0.5);
658  SetGridBit(x1, y1, isLatLine);
659  }
660  }
661  }
662 };
void SetMaximumSteps(const int steps)
This sets the maximum number of steps in the process.
Definition: Progress.cpp:101
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:141
Universal Ground Map.
This class is designed to encapsulate the concept of a Latitude.
Definition: Latitude.h:59
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:164
Distance measurement, usually in meters.
Definition: Distance.h:47
void CheckStatus()
Checks and updates the status.
Definition: Progress.cpp:121
This class is designed to encapsulate the concept of a Longitude.
Definition: Longitude.h:52
Program progress reporter.
Definition: Progress.h:58
double meters() const
Get the distance in meters.
Definition: Distance.cpp:97
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:38
Container for cube-like labels.
Definition: Pvl.h:135
bool isValid() const
This indicates whether we have a legitimate angle stored or are in an unset, or invalid, state.
Definition: Angle.cpp:110
Defines an angle and provides unit conversions.
Definition: Angle.h:58
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
Isis exception class.
Definition: IException.h:99
Adds specific functionality to C++ strings.
Definition: IString.h:179
Unless noted otherwise, the portions of Isis written by the USGS are public domain.

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the ISIS Support Center
File Modified: 07/12/2023 23:18:50