Isis 3 Programmer Reference
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 {
34  GroundGrid::GroundGrid(UniversalGroundMap *gmap,
35  bool splitLatLon,
36  bool extendGrid,
37  unsigned int width,
38  unsigned int height) {
39  p_width = width;
40  p_height = height;
41  m_extendGrid = extendGrid;
42 
43  // Initialize our grid pointer to null
44  p_grid = 0;
45  p_latLinesGrid = 0;
46  p_lonLinesGrid = 0;
47 
48  // Now let's figure out how big the grid needs to be, then allocate and
49  // initialize
50  p_gridSize = (unsigned long)(ceil(width * height / 8.0) + 0.5);
51 
52  if (!splitLatLon) {
53  p_grid = new char[p_gridSize];
54  }
55  else {
56  p_latLinesGrid = new char[p_gridSize];
57  p_lonLinesGrid = new char[p_gridSize];
58  }
59 
60  for (unsigned long i = 0; i < p_gridSize; i++) {
61  if (p_grid) p_grid[i] = 0;
62  if (p_latLinesGrid) p_latLinesGrid[i] = 0;
63  if (p_lonLinesGrid) p_lonLinesGrid[i] = 0;
64  }
65 
66  // The first call of CreateGrid doesn't have to reinitialize
67  p_reinitialize = false;
68 
69  p_groundMap = gmap;
70 
71  // We need a lat/lon range for gridding, use the mapping group
72  // (in case of camera, use BasicMapping)
73  p_minLat = NULL;
74  p_minLon = NULL;
75  p_maxLat = NULL;
76  p_maxLon = NULL;
77 
78  p_mapping = new PvlGroup;
79 
80  if (p_groundMap->Camera()) {
81  Pvl tmp;
82  p_groundMap->Camera()->BasicMapping(tmp);
83  *p_mapping = tmp.findGroup("Mapping");
84  }
85  else {
86  *p_mapping = p_groundMap->Projection()->Mapping();
87  }
88 
89  Distance radius1 = Distance((double)(*p_mapping)["EquatorialRadius"],
90  Distance::Meters);
91  Distance radius2 = Distance((double)(*p_mapping)["PolarRadius"],
92  Distance::Meters);
93 
94  if (p_mapping->hasKeyword("MinimumLatitude")) {
95  p_minLat = new Latitude(toDouble((*p_mapping)["MinimumLatitude"][0]),
96  *p_mapping,
97  Angle::Degrees,
98  Latitude::AllowPastPole);
99  }
100  else {
101  p_minLat = new Latitude;
102  }
103 
104  if (p_mapping->hasKeyword("MaximumLatitude")) {
105  p_maxLat = new Latitude(toDouble((*p_mapping)["MaximumLatitude"][0]),
106  *p_mapping,
107  Angle::Degrees);
108  }
109  else {
110  p_maxLat = new Latitude;
111  }
112 
113  if (p_mapping->hasKeyword("MinimumLongitude")) {
114  p_minLon = new Longitude(toDouble((*p_mapping)["MinimumLongitude"][0]),
115  *p_mapping,
116  Angle::Degrees);
117  }
118  else {
119  p_minLon = new Longitude;
120  }
121 
122  if (p_mapping->hasKeyword("MaximumLongitude")) {
123  p_maxLon = new Longitude(toDouble((*p_mapping)["MaximumLongitude"][0]),
124  *p_mapping,
125  Angle::Degrees);
126  }
127  else {
128  p_maxLon = new Longitude;
129  }
130 
131  if (p_minLon->isValid() && p_maxLon->isValid()) {
132  if (*p_minLon > *p_maxLon) {
133  Longitude tmp(*p_minLon);
134  *p_minLon = *p_maxLon;
135  *p_maxLon = tmp;
136  }
137  }
138 
139  Distance largerRadius = max(radius1, radius2);
140 
141  // p_defaultResolution is in degrees/pixel
142 
143  if (p_groundMap->HasCamera()) {
144  p_defaultResolution =
145  (p_groundMap->Camera()->HighestImageResolution() /
146  largerRadius.meters()) * 10;
147  }
148  else {
149  p_defaultResolution = (p_groundMap->Resolution() /
150  largerRadius.meters()) * 10;
151  }
152 
153  if (p_defaultResolution < 0) {
154  p_defaultResolution = 10.0 / largerRadius.meters();
155  }
156  }
157 
161  GroundGrid::~GroundGrid() {
162  if (p_minLat) {
163  delete p_minLat;
164  p_minLat = NULL;
165  }
166 
167  if (p_minLon) {
168  delete p_minLon;
169  p_minLon = NULL;
170  }
171 
172  if (p_maxLat) {
173  delete p_maxLat;
174  p_maxLat = NULL;
175  }
176 
177  if (p_maxLon) {
178  delete p_maxLon;
179  p_maxLon = NULL;
180  }
181 
182  if (p_mapping) {
183  delete p_mapping;
184  p_mapping = NULL;
185  }
186 
187  if (p_grid) {
188  delete[] p_grid;
189  p_grid = NULL;
190  }
191 
192  if (p_latLinesGrid) {
193  delete[] p_latLinesGrid;
194  p_latLinesGrid = NULL;
195  }
196 
197  if (p_lonLinesGrid) {
198  delete[] p_lonLinesGrid;
199  p_lonLinesGrid = NULL;
200  }
201  }
202 
212  void GroundGrid::CreateGrid(Latitude baseLat,
213  Longitude baseLon,
214  Angle latInc,
215  Angle lonInc,
216  Progress *progress) {
217  CreateGrid(baseLat, baseLon, latInc, lonInc, progress, Angle(), Angle());
218  }
219 
220 
233  void GroundGrid::CreateGrid(Latitude baseLat,
234  Longitude baseLon,
235  Angle latInc,
236  Angle lonInc,
237  Progress *progress,
238  Angle latRes,
239  Angle lonRes) {
240  if (p_groundMap == NULL ||
241  (p_grid == NULL && p_latLinesGrid == NULL && p_lonLinesGrid == NULL)) {
242  IString msg = "GroundGrid::CreateGrid missing ground map or grid array";
243  throw IException(IException::Programmer, msg, _FILEINFO_);
244  }
245 
246  if (p_reinitialize) {
247  for (unsigned long i = 0; i < p_gridSize; i++) {
248  if (p_grid) p_grid[i] = 0;
249  if (p_latLinesGrid) p_latLinesGrid[i] = 0;
250  if (p_lonLinesGrid) p_lonLinesGrid[i] = 0;
251  }
252  }
253 
254  // Verify lat/lon range is okay
255  bool badLatLonRange = false;
256  QVector<IString> badLatLonValues;
257  if (!p_minLat || !p_minLat->isValid()) {
258  badLatLonValues.append("MinimumLatitude");
259  badLatLonRange = true;
260  }
261 
262  if (!p_maxLat || !p_maxLat->isValid()) {
263  badLatLonValues.append("MaximumLatitude");
264  badLatLonRange = true;
265  }
266 
267  if (!p_minLon || !p_minLon->isValid()) {
268  badLatLonValues.append("MinimumLongitude");
269  badLatLonRange = true;
270  }
271 
272  if (!p_maxLon || !p_maxLon->isValid()) {
273  badLatLonValues.append("MaximumLongitude");
274  badLatLonRange = true;
275  }
276 
277 
278  if (badLatLonRange) {
279  IString msg = "Could not determine values for [";
280  for (int i = 0; i < badLatLonValues.size(); i++) {
281  if (i != 0)
282  msg += ",";
283 
284  msg += badLatLonValues[i];
285  }
286 
287  msg += "], please specify them explicitly";
288 
289  // I chose parse because it's not really the user's fault or the
290  // programmer's. It's a stripped keyword in a Pvl.
291  throw IException(IException::Unknown, msg, _FILEINFO_);
292  }
293 
294  // subsequent calls to this method must always reinitialize the grid
295  p_reinitialize = true;
296 
297  // Find starting points for lat/lon
298  Latitude startLat = Latitude(baseLat - Angle(floor((baseLat - *p_minLat) / latInc) * latInc),
299  *GetMappingGroup(),
300  Latitude::AllowPastPole);
301 
302  Longitude startLon = Longitude(baseLon - Angle(floor((baseLon - *p_minLon) / lonInc) * lonInc));
303 
304  if (!latRes.isValid() || latRes <= Angle(0, Angle::Degrees)) {
305  latRes = Angle(p_defaultResolution,
306  Angle::Degrees);
307  }
308 
309  if (!lonRes.isValid() || lonRes <= Angle(0, Angle::Degrees)) {
310  lonRes = Angle(p_defaultResolution,
311  Angle::Degrees);
312  }
313 
314  Latitude endLat = Latitude((long)((*p_maxLat - startLat) / latInc) * latInc + startLat,
315  *GetMappingGroup());
316  Longitude endLon =
317  (long)((*p_maxLon - startLon) / lonInc) * lonInc + startLon;
318 
319  if (progress) {
320  double numSteps = (double)((endLat - startLat) / latInc) + 1;
321  numSteps += (double)((endLon - startLon) / lonInc) + 1;
322 
323  if (numSteps <= 0) {
324  IString msg = "No gridlines would intersect the image";
325  throw IException(IException::Programmer, msg, _FILEINFO_);
326  }
327 
328  progress->SetMaximumSteps((long)(numSteps + 0.5));
329  progress->CheckStatus();
330  }
331 
332  // Ensure that the Latitude being incremented does not throw an exception
333  // if incremented past -90 or 90 degrees.
334  Latitude latStep = startLat;
335  latStep.setErrorChecking(Latitude::AllowPastPole);
336  for (; latStep <= endLat + latInc / 2; latStep += latInc) {
337  unsigned int previousX = 0;
338  unsigned int previousY = 0;
339  bool havePrevious = false;
340 
341  for (Longitude lon = *p_minLon; lon <= *p_maxLon; lon += latRes) {
342  unsigned int x = 0;
343  unsigned int y = 0;
344  bool valid = GetXY(latStep, lon, x, y);
345 
346  if (valid && havePrevious) {
347  if (previousX != x || previousY != y) {
348  DrawLineOnGrid(previousX, previousY, x, y, true);
349  }
350  }
351 
352  havePrevious = valid;
353  previousX = x;
354  previousY = y;
355  }
356 
357  if (progress) {
358  progress->CheckStatus();
359  }
360  }
361 
362  for (Longitude lon = startLon; lon <= endLon + lonInc / 2; lon += lonInc) {
363  unsigned int previousX = 0;
364  unsigned int previousY = 0;
365  bool havePrevious = false;
366 
367  // Ensure that the Latitude being incremented does not throw an exception
368  // if incremented past -90 or 90 degrees.
369  latStep = *p_minLat;
370  latStep.setErrorChecking(Latitude::AllowPastPole);
371  for (; latStep <= *p_maxLat; latStep += lonRes) {
372  unsigned int x = 0;
373  unsigned int y = 0;
374 
375  bool valid = GetXY(latStep, lon, x, y);
376 
377  if (valid && havePrevious) {
378  if (previousX == x && previousY == y) {
379  continue;
380  }
381 
382  DrawLineOnGrid(previousX, previousY, x, y, false);
383  }
384 
385  havePrevious = valid;
386  previousX = x;
387  previousY = y;
388  }
389 
390  if (progress) {
391  progress->CheckStatus();
392  }
393  }
394  }
395 
396 
405  void GroundGrid::SetGroundLimits(Latitude minLat, Longitude minLon,
406  Latitude maxLat, Longitude maxLon) {
407  if (minLat.isValid()) *p_minLat = minLat;
408  if (maxLat.isValid()) *p_maxLat = maxLat;
409  if (minLon.isValid()) *p_minLon = minLon;
410  if (maxLon.isValid()) *p_maxLon = maxLon;
411 
412  if (p_minLat->isValid() && p_maxLat->isValid() && *p_minLat > *p_maxLat) {
413  Latitude tmp(*p_minLat);
414  *p_minLat = *p_maxLat;
415  *p_maxLat = tmp;
416  }
417 
418  if (p_minLon->isValid() && p_maxLon->isValid() && *p_minLon > *p_maxLon) {
419  Longitude tmp(*p_minLon);
420  *p_minLon = *p_maxLon;
421  *p_maxLon = tmp;
422  }
423  }
424 
428  void GroundGrid::WalkBoundary() {
429  Angle latRes = Angle(p_defaultResolution, Angle::Degrees);
430  Angle lonRes = Angle(p_defaultResolution, Angle::Degrees);
431 
432  const Latitude &minLat = *p_minLat;
433  const Latitude &maxLat = *p_maxLat;
434  const Longitude &minLon = *p_minLon;
435  const Longitude &maxLon = *p_maxLon;
436 
437  // Walk the minLat/maxLat lines
438  // Ensure that the Latitude being incremented does not throw an exception
439  // if incremented past -90 or 90 degrees.
440  Latitude latStep = minLat;
441  latStep.setErrorChecking(Latitude::AllowPastPole);
442  for (; latStep <= maxLat; latStep += (maxLat - minLat)) {
443  unsigned int previousX = 0;
444  unsigned int previousY = 0;
445  bool havePrevious = false;
446 
447  for (Longitude lon = minLon; lon <= maxLon; lon += latRes) {
448  unsigned int x = 0;
449  unsigned int y = 0;
450  bool valid = GetXY(latStep, lon, x, y);
451 
452  if (valid && havePrevious) {
453  if (previousX != x || previousY != y) {
454  DrawLineOnGrid(previousX, previousY, x, y, true);
455  }
456  }
457 
458  havePrevious = valid;
459  previousX = x;
460  previousY = y;
461  }
462  }
463 
464  // Walk the minLon/maxLon lines
465  for (Longitude lon = minLon; lon <= maxLon; lon += (maxLon - minLon)) {
466  unsigned int previousX = 0;
467  unsigned int previousY = 0;
468  bool havePrevious = false;
469 
470  // Ensure that the Latitude being incremented does not throw an exception
471  // if incremented past -90 or 90 degrees.
472  latStep = minLat;
473  latStep.setErrorChecking(Latitude::AllowPastPole);
474  for (; latStep <= maxLat; latStep += lonRes) {
475  unsigned int x = 0;
476  unsigned int y = 0;
477  bool valid = GetXY(latStep, lon, x, y);
478 
479  if (valid && havePrevious) {
480  if (previousX != x || previousY != y) {
481  DrawLineOnGrid(previousX, previousY, x, y, false);
482  }
483  }
484 
485  havePrevious = valid;
486  previousX = x;
487  previousY = y;
488  }
489  }
490  }
491 
492 
504  bool GroundGrid::PixelOnGrid(int x, int y, bool latGrid) {
505  if (x < 0) return false;
506  if (y < 0) return false;
507 
508  if (x >= (int)p_width) return false;
509  if (y >= (int)p_height) return false;
510 
511  return GetGridBit(x, y, latGrid);
512  }
513 
514 
523  bool GroundGrid::PixelOnGrid(int x, int y) {
524  if (x < 0) return false;
525  if (y < 0) return false;
526 
527  if (x >= (int)p_width) return false;
528  if (y >= (int)p_height) return false;
529 
530  return GetGridBit(x, y, true); // third argument shouldnt matter
531  }
532 
533 
540  PvlGroup *GroundGrid::GetMappingGroup() {
541  return p_mapping;
542  }
543 
544 
551  Latitude GroundGrid::minLatitude() const {
552  if (p_minLat) {
553  return *p_minLat;
554  }
555  return Latitude();
556  }
557 
558 
565  Longitude GroundGrid::minLongitude() const {
566  if (p_minLon) {
567  return *p_minLon;
568  }
569  return Longitude();
570  }
571 
572 
579  Latitude GroundGrid::maxLatitude() const {
580  if (p_maxLat) {
581  return *p_maxLat;
582  }
583  return Latitude();
584  }
585 
586 
593  Longitude GroundGrid::maxLongitude() const {
594  if (p_maxLon) {
595  return *p_maxLon;
596  }
597  return Longitude();
598  }
599 
600 
612  bool GroundGrid::GetXY(Latitude lat, Longitude lon,
613  unsigned int &x, unsigned int &y) {
614  if (!GroundMap()) return false;
615  if (m_extendGrid) {
616  if (!GroundMap()->SetUnboundGround(lat, lon)) return false;
617  }
618  else {
619  if (!GroundMap()->SetGround(lat, lon)) return false;
620  }
621  if (p_groundMap->Sample() < 0.5 || p_groundMap->Line() < 0.5) return false;
622  if (p_groundMap->Sample() < 0.5 || p_groundMap->Line() < 0.5) return false;
623 
624  x = (int)(p_groundMap->Sample() - 0.5);
625  y = (int)(p_groundMap->Line() - 0.5);
626 
627  if (x >= p_width || y >= p_height) return false;
628 
629  return true;
630  }
631 
632 
637  UniversalGroundMap *GroundGrid::GroundMap() {
638  return p_groundMap;
639  }
640 
641 
649  void GroundGrid::SetGridBit(unsigned int x, unsigned int y, bool latGrid) {
650  unsigned long bitPosition = (y * p_width) + x;
651  unsigned long byteContainer = bitPosition / 8;
652  unsigned int bitOffset = bitPosition % 8;
653 
654  if (byteContainer > p_gridSize) return;
655 
656  if (p_grid) {
657  char &importantByte = p_grid[byteContainer];
658  importantByte |= (1 << bitOffset);
659  }
660  else if (latGrid && p_latLinesGrid) {
661  char &importantByte = p_latLinesGrid[byteContainer];
662  importantByte |= (1 << bitOffset);
663  }
664  else if (!latGrid && p_lonLinesGrid) {
665  char &importantByte = p_lonLinesGrid[byteContainer];
666  importantByte |= (1 << bitOffset);
667  }
668  else {
669  IString msg = "GroundGrid::SetGridBit no grids available";
670  throw IException(IException::Programmer, msg, _FILEINFO_);
671  }
672  }
673 
674 
685  bool GroundGrid::GetGridBit(unsigned int x, unsigned int y, bool latGrid) {
686  unsigned long bitPosition = (y * p_width) + x;
687  unsigned long byteContainer = bitPosition / 8;
688  unsigned int bitOffset = bitPosition % 8;
689 
690  if (byteContainer > p_gridSize) return false;
691 
692  bool result = false;
693 
694  if (p_grid) {
695  char &importantByte = p_grid[byteContainer];
696  result = (importantByte >> bitOffset) & 1;
697  }
698  else if (latGrid && p_latLinesGrid) {
699  char &importantByte = p_latLinesGrid[byteContainer];
700  result = (importantByte >> bitOffset) & 1;
701  }
702  else if (!latGrid && p_lonLinesGrid) {
703  char &importantByte = p_lonLinesGrid[byteContainer];
704  result = (importantByte >> bitOffset) & 1;
705  }
706  else {
707  IString msg = "GroundGrid::GetGridBit no grids available";
708  throw IException(IException::Programmer, msg, _FILEINFO_);
709  }
710 
711  return result;
712  }
713 
714 
724  void GroundGrid::DrawLineOnGrid(unsigned int x1, unsigned int y1,
725  unsigned int x2, unsigned int y2,
726  bool isLatLine) {
727  int dx = x2 - x1;
728  int dy = y2 - y1;
729 
730  SetGridBit(x1, y1, isLatLine);
731 
732  if (dx != 0) {
733  double m = (double)dy / (double)dx;
734  double b = y1 - m * x1;
735 
736  dx = (x2 > x1) ? 1 : -1;
737  while (x1 != x2) {
738  x1 += dx;
739  y1 = (int)(m * x1 + b + 0.5);
740  SetGridBit(x1, y1, isLatLine);
741  }
742  }
743  }
744 };
void setErrorChecking(ErrorChecking errors)
Set the error checking status.
Definition: Latitude.cpp:433
double meters() const
Get the distance in meters.
Definition: Distance.cpp:97
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.
Namespace for the standard library.
This class is designed to encapsulate the concept of a Latitude.
Definition: Latitude.h:63
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
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
Container for cube-like labels.
Definition: Pvl.h:135
Defines an angle and provides unit conversions.
Definition: Angle.h:62
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
Isis exception class.
Definition: IException.h:107
Adds specific functionality to C++ strings.
Definition: IString.h:181
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
bool isValid() const
This indicates whether we have a legitimate angle stored or are in an unset, or invalid, state.
Definition: Angle.cpp:110
Unless noted otherwise, the portions of Isis written by the USGS are public domain.