USGS

Isis 3.0 Object Programmers' Reference

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, bool splitLatLon,
33  unsigned int width, unsigned int height) {
34  p_width = width;
35  p_height = height;
36 
37  // Initialize our grid pointer to null
38  p_grid = 0;
39  p_latLinesGrid = 0;
40  p_lonLinesGrid = 0;
41 
42  // Now let's figure out how big the grid needs to be, then allocate and
43  // initialize
44  p_gridSize = (unsigned long)(ceil(width * height / 8.0) + 0.5);
45 
46  if(!splitLatLon) {
47  p_grid = new char[p_gridSize];
48  }
49  else {
50  p_latLinesGrid = new char[p_gridSize];
51  p_lonLinesGrid = new char[p_gridSize];
52  }
53 
54  for(unsigned long i = 0; i < p_gridSize; i++) {
55  if(p_grid) p_grid[i] = 0;
56  if(p_latLinesGrid) p_latLinesGrid[i] = 0;
57  if(p_lonLinesGrid) p_lonLinesGrid[i] = 0;
58  }
59 
60  // The first call of CreateGrid doesn't have to reinitialize
61  p_reinitialize = false;
62 
63  p_groundMap = gmap;
64 
65  // We need a lat/lon range for gridding, use the mapping group
66  // (in case of camera, use BasicMapping)
67  p_minLat = NULL;
68  p_minLon = NULL;
69  p_maxLat = NULL;
70  p_maxLon = NULL;
71 
72  p_mapping = new PvlGroup;
73 
74  if(p_groundMap->Camera()) {
75  Pvl tmp;
76  p_groundMap->Camera()->BasicMapping(tmp);
77  *p_mapping = tmp.findGroup("Mapping");
78  }
79  else {
80  *p_mapping = p_groundMap->Projection()->Mapping();
81  }
82 
83  Distance radius1 = Distance((double)(*p_mapping)["EquatorialRadius"],
84  Distance::Meters);
85  Distance radius2 = Distance((double)(*p_mapping)["PolarRadius"],
86  Distance::Meters);
87 
88  if(p_mapping->hasKeyword("MinimumLatitude")) {
89  p_minLat = new Latitude(
90  toDouble((*p_mapping)["MinimumLatitude"][0]), *p_mapping,
91  Angle::Degrees);
92  }
93  else {
94  p_minLat = new Latitude;
95  }
96 
97  if(p_mapping->hasKeyword("MaximumLatitude")) {
98  p_maxLat = new Latitude(
99  toDouble((*p_mapping)["MaximumLatitude"][0]), *p_mapping,
100  Angle::Degrees);
101  }
102  else {
103  p_maxLat = new Latitude;
104  }
105 
106  if(p_mapping->hasKeyword("MinimumLongitude")) {
107  p_minLon = new Longitude(
108  toDouble((*p_mapping)["MinimumLongitude"][0]), *p_mapping,
109  Angle::Degrees);
110  }
111  else {
112  p_minLon = new Longitude;
113  }
114 
115  if(p_mapping->hasKeyword("MaximumLongitude")) {
116  p_maxLon = new Longitude(
117  toDouble((*p_mapping)["MaximumLongitude"][0]), *p_mapping,
118  Angle::Degrees);
119  }
120  else {
121  p_maxLon = new Longitude;
122  }
123 
124  if(p_minLon->isValid() && p_maxLon->isValid()) {
125  if(*p_minLon > *p_maxLon) {
126  Longitude tmp(*p_minLon);
127  *p_minLon = *p_maxLon;
128  *p_maxLon = tmp;
129  }
130  }
131 
132  Distance largerRadius = max(radius1, radius2);
133 
134  // p_defaultResolution is in degrees/pixel
135 
136  if(p_groundMap->HasCamera()) {
137  p_defaultResolution =
138  (p_groundMap->Camera()->HighestImageResolution() /
139  largerRadius.meters()) * 10;
140  }
141  else {
142  p_defaultResolution = (p_groundMap->Resolution() /
143  largerRadius.meters()) * 10;
144  }
145 
146  if(p_defaultResolution < 0) {
147  p_defaultResolution = 10.0 / largerRadius.meters();
148  }
149  }
150 
154  GroundGrid::~GroundGrid() {
155  if(p_minLat) {
156  delete p_minLat;
157  p_minLat = NULL;
158  }
159 
160  if(p_minLon) {
161  delete p_minLon;
162  p_minLon = NULL;
163  }
164 
165  if(p_maxLat) {
166  delete p_maxLat;
167  p_maxLat = NULL;
168  }
169 
170  if(p_maxLon) {
171  delete p_maxLon;
172  p_maxLon = NULL;
173  }
174 
175  if(p_mapping) {
176  delete p_mapping;
177  p_mapping = NULL;
178  }
179 
180  if(p_grid) {
181  delete [] p_grid;
182  p_grid = NULL;
183  }
184 
185  if(p_latLinesGrid) {
186  delete [] p_latLinesGrid;
187  p_latLinesGrid = NULL;
188  }
189 
190  if(p_lonLinesGrid) {
191  delete [] p_lonLinesGrid;
192  p_lonLinesGrid = NULL;
193  }
194  }
195 
205  void GroundGrid::CreateGrid(Latitude baseLat, Longitude baseLon,
206  Angle latInc, Angle lonInc,
207  Progress *progress) {
208  CreateGrid(baseLat, baseLon, latInc, lonInc, progress, Angle(), Angle());
209  }
210 
211 
224  void GroundGrid::CreateGrid(Latitude baseLat, Longitude baseLon,
225  Angle latInc, Angle lonInc,
226  Progress *progress,
227  Angle latRes, Angle lonRes) {
228  if(p_groundMap == NULL ||
229  (p_grid == NULL && p_latLinesGrid == NULL && p_lonLinesGrid == NULL)) {
230  IString msg = "GroundGrid::CreateGrid missing ground map or grid array";
231  throw IException(IException::Programmer, msg, _FILEINFO_);
232  }
233 
234  if(p_reinitialize) {
235  for(unsigned long i = 0; i < p_gridSize; i++) {
236  if(p_grid) p_grid[i] = 0;
237  if(p_latLinesGrid) p_latLinesGrid[i] = 0;
238  if(p_lonLinesGrid) p_lonLinesGrid[i] = 0;
239  }
240  }
241 
242  // Verify lat/lon range is okay
243  bool badLatLonRange = false;
244  QVector<IString> badLatLonValues;
245  if(!p_minLat || !p_minLat->isValid()) {
246  badLatLonValues.append("MinimumLatitude");
247  badLatLonRange = true;
248  }
249 
250  if(!p_maxLat || !p_maxLat->isValid()) {
251  badLatLonValues.append("MaximumLatitude");
252  badLatLonRange = true;
253  }
254 
255  if(!p_minLon || !p_minLon->isValid()) {
256  badLatLonValues.append("MinimumLongitude");
257  badLatLonRange = true;
258  }
259 
260  if(!p_maxLon || !p_maxLon->isValid()) {
261  badLatLonValues.append("MaximumLongitude");
262  badLatLonRange = true;
263  }
264 
265 
266  if(badLatLonRange) {
267  IString msg = "Could not determine values for [";
268  for(int i = 0; i < badLatLonValues.size(); i++) {
269  if(i != 0)
270  msg += ",";
271 
272  msg += badLatLonValues[i];
273  }
274 
275  msg += "], please specify them explicitly";
276 
277  // I chose parse because it's not really the user's fault or the
278  // programmer's. It's a stripped keyword in a Pvl.
279  throw IException(IException::Unknown, msg, _FILEINFO_);
280  }
281 
282  // subsequent calls to this method must always reinitialize the grid
283  p_reinitialize = true;
284 
285  // Find starting points for lat/lon
286  Latitude startLat = Latitude(
287  baseLat - Angle(floor((baseLat - *p_minLat) / latInc) * latInc),
288  *GetMappingGroup());
289 
290  Longitude startLon = Longitude(
291  baseLon - Angle(floor((baseLon - *p_minLon) / lonInc) * lonInc));
292 
293  if(!latRes.isValid() || latRes <= Angle(0, Angle::Degrees)) {
294  latRes = Angle(p_defaultResolution, Angle::Degrees);
295  }
296 
297  if(!lonRes.isValid() || lonRes <= Angle(0, Angle::Degrees)) {
298  lonRes = Angle(p_defaultResolution, Angle::Degrees);
299  }
300 
301  Latitude endLat = Latitude(
302  (long)((*p_maxLat - startLat) / latInc) * latInc + startLat,
303  *GetMappingGroup());
304  Longitude endLon =
305  (long)((*p_maxLon - startLon) / lonInc) * lonInc + startLon;
306 
307  if(progress) {
308  double numSteps = (double)((endLat - startLat) / latInc) + 1;
309  numSteps += (double)((endLon - startLon) / lonInc) + 1;
310 
311  if(numSteps <= 0) {
312  IString msg = "No gridlines would intersect the image";
313  throw IException(IException::Programmer, msg, _FILEINFO_);
314  }
315 
316  progress->SetMaximumSteps((long)(numSteps + 0.5));
317  progress->CheckStatus();
318  }
319 
320  for(Latitude lat = startLat; lat <= endLat + latInc / 2; lat += latInc) {
321  unsigned int previousX = 0;
322  unsigned int previousY = 0;
323  bool havePrevious = false;
324 
325  for(Longitude lon = *p_minLon; lon <= *p_maxLon; lon += latRes) {
326  unsigned int x = 0;
327  unsigned int y = 0;
328  bool valid = GetXY(lat, lon, x, y);
329 
330  if(valid && havePrevious) {
331  if(previousX != x || previousY != y) {
332  DrawLineOnGrid(previousX, previousY, x, y, true);
333  }
334  }
335 
336  havePrevious = valid;
337  previousX = x;
338  previousY = y;
339  }
340 
341  if(progress) {
342  progress->CheckStatus();
343  }
344  }
345 
346  for(Longitude lon = startLon; lon <= endLon + lonInc / 2; lon += lonInc) {
347  unsigned int previousX = 0;
348  unsigned int previousY = 0;
349  bool havePrevious = false;
350 
351  for(Latitude lat = *p_minLat; lat <= *p_maxLat; lat += lonRes) {
352  unsigned int x = 0;
353  unsigned int y = 0;
354 
355  bool valid = GetXY(lat, lon, x, y);
356 
357  if(valid && havePrevious) {
358  if(previousX == x && previousY == y) {
359  continue;
360  }
361 
362  DrawLineOnGrid(previousX, previousY, x, y, false);
363  }
364 
365  havePrevious = valid;
366  previousX = x;
367  previousY = y;
368  }
369 
370  if(progress) {
371  progress->CheckStatus();
372  }
373  }
374  }
375 
376 
385  void GroundGrid::SetGroundLimits(Latitude minLat, Longitude minLon,
386  Latitude maxLat, Longitude maxLon) {
387  if(minLat.isValid()) *p_minLat = minLat;
388  if(maxLat.isValid()) *p_maxLat = maxLat;
389  if(minLon.isValid()) *p_minLon = minLon;
390  if(maxLon.isValid()) *p_maxLon = maxLon;
391 
392  if(p_minLat->isValid() && p_maxLat->isValid() && *p_minLat > *p_maxLat) {
393  Latitude tmp(*p_minLat);
394  *p_minLat = *p_maxLat;
395  *p_maxLat = tmp;
396  }
397 
398  if(p_minLon->isValid() && p_maxLon->isValid() && *p_minLon > *p_maxLon) {
399  Longitude tmp(*p_minLon);
400  *p_minLon = *p_maxLon;
401  *p_maxLon = tmp;
402  }
403  }
404 
408  void GroundGrid::WalkBoundary() {
409  Angle latRes = Angle(p_defaultResolution, Angle::Degrees);
410  Angle lonRes = Angle(p_defaultResolution, Angle::Degrees);
411 
412  const Latitude &minLat = *p_minLat;
413  const Latitude &maxLat = *p_maxLat;
414  const Longitude &minLon = *p_minLon;
415  const Longitude &maxLon = *p_maxLon;
416 
417  // Walk the minLat/maxLat lines
418  for(Latitude lat = minLat; lat <= maxLat; lat += (maxLat - minLat)) {
419  unsigned int previousX = 0;
420  unsigned int previousY = 0;
421  bool havePrevious = false;
422 
423  for(Longitude lon = minLon; lon <= maxLon; lon += latRes) {
424  unsigned int x = 0;
425  unsigned int y = 0;
426  bool valid = GetXY(lat, lon, x, y);
427 
428  if(valid && havePrevious) {
429  if(previousX != x || previousY != y) {
430  DrawLineOnGrid(previousX, previousY, x, y, true);
431  }
432  }
433 
434  havePrevious = valid;
435  previousX = x;
436  previousY = y;
437  }
438  }
439 
440  // Walk the minLon/maxLon lines
441  for(Longitude lon = minLon; lon <= maxLon; lon += (maxLon - minLon)) {
442  unsigned int previousX = 0;
443  unsigned int previousY = 0;
444  bool havePrevious = false;
445 
446  for(Latitude lat = minLat; lat <= maxLat; lat += lonRes) {
447  unsigned int x = 0;
448  unsigned int y = 0;
449  bool valid = GetXY(lat, lon, x, y);
450 
451  if(valid && havePrevious) {
452  if(previousX != x || previousY != y) {
453  DrawLineOnGrid(previousX, previousY, x, y, false);
454  }
455  }
456 
457  havePrevious = valid;
458  previousX = x;
459  previousY = y;
460  }
461  }
462  }
463 
464 
476  bool GroundGrid::PixelOnGrid(int x, int y, bool latGrid) {
477  if(x < 0) return false;
478  if(y < 0) return false;
479 
480  if(x >= (int)p_width) return false;
481  if(y >= (int)p_height) return false;
482 
483  return GetGridBit(x, y, latGrid);
484  }
485 
486 
495  bool GroundGrid::PixelOnGrid(int x, int y) {
496  if(x < 0) return false;
497  if(y < 0) return false;
498 
499  if(x >= (int)p_width) return false;
500  if(y >= (int)p_height) return false;
501 
502  return GetGridBit(x, y, true); // third argument shouldnt matter
503  }
504 
505 
517  bool GroundGrid::GetXY(Latitude lat, Longitude lon,
518  unsigned int &x, unsigned int &y) {
519  if(!GroundMap()) return false;
520  if(!GroundMap()->SetGround(lat, lon)) return false;
521  if(p_groundMap->Sample() < 0.5 || p_groundMap->Line() < 0.5) return false;
522  if(p_groundMap->Sample() < 0.5 || p_groundMap->Line() < 0.5) return false;
523 
524  x = (int)(p_groundMap->Sample() - 0.5);
525  y = (int)(p_groundMap->Line() - 0.5);
526 
527  if(x >= p_width || y >= p_height) return false;
528 
529  return true;
530  }
531 
532 
540  void GroundGrid::SetGridBit(unsigned int x, unsigned int y, bool latGrid) {
541  unsigned long bitPosition = (y * p_width) + x;
542  unsigned long byteContainer = bitPosition / 8;
543  unsigned int bitOffset = bitPosition % 8;
544 
545  if(byteContainer < 0 || byteContainer > p_gridSize) return;
546 
547  if(p_grid) {
548  char &importantByte = p_grid[byteContainer];
549  importantByte |= (1 << bitOffset);
550  }
551  else if(latGrid && p_latLinesGrid) {
552  char &importantByte = p_latLinesGrid[byteContainer];
553  importantByte |= (1 << bitOffset);
554  }
555  else if(!latGrid && p_lonLinesGrid) {
556  char &importantByte = p_lonLinesGrid[byteContainer];
557  importantByte |= (1 << bitOffset);
558  }
559  else {
560  IString msg = "GroundGrid::SetGridBit no grids available";
561  throw IException(IException::Programmer, msg, _FILEINFO_);
562  }
563  }
564 
565 
576  bool GroundGrid::GetGridBit(unsigned int x, unsigned int y, bool latGrid) {
577  unsigned long bitPosition = (y * p_width) + x;
578  unsigned long byteContainer = bitPosition / 8;
579  unsigned int bitOffset = bitPosition % 8;
580 
581  if(byteContainer < 0 || byteContainer > p_gridSize) return false;
582 
583  bool result = false;
584 
585  if(p_grid) {
586  char &importantByte = p_grid[byteContainer];
587  result = (importantByte >> bitOffset) & 1;
588  }
589  else if(latGrid && p_latLinesGrid) {
590  char &importantByte = p_latLinesGrid[byteContainer];
591  result = (importantByte >> bitOffset) & 1;
592  }
593  else if(!latGrid && p_lonLinesGrid) {
594  char &importantByte = p_lonLinesGrid[byteContainer];
595  result = (importantByte >> bitOffset) & 1;
596  }
597  else {
598  IString msg = "GroundGrid::GetGridBit no grids available";
599  throw IException(IException::Programmer, msg, _FILEINFO_);
600  }
601 
602  return result;
603  }
604 
605 
615  void GroundGrid::DrawLineOnGrid(unsigned int x1, unsigned int y1,
616  unsigned int x2, unsigned int y2,
617  bool isLatLine) {
618  int dx = x2 - x1;
619  int dy = y2 - y1;
620 
621  SetGridBit(x1, y1, isLatLine);
622 
623  if(dx != 0) {
624  double m = (double)dy / (double)dx;
625  double b = y1 - m * x1;
626 
627  dx = (x2 > x1) ? 1 : -1;
628  while(x1 != x2) {
629  x1 += dx;
630  y1 = (int)(m * x1 + b + 0.5);
631  SetGridBit(x1, y1, isLatLine);
632  }
633  }
634  }
635 };