OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimDblGrid.cpp
Go to the documentation of this file.
1 //*******************************************************************
2 //
3 // License: See top level LICENSE.txt file.
4 //
5 // AUTHOR: Oscar Kramer (okramer@imagelinks.com)
6 //
7 // DESCRIPTION:
8 // Contains implementation of class ossimDblGrid. This class maintains
9 // a regular grid of floating point (double) values. Access methods to the
10 // grid include interpolation between grid nodes. Capability is included
11 // to address the grid in an arbitrary, floating-point x, y coordinate
12 // system.
13 //
14 //*****************************************************************************
15 // $Id: ossimDblGrid.cpp 23329 2015-05-27 14:24:19Z dburken $
16 
18 #include <ossim/base/ossimDrect.h>
19 #include <ossim/base/ossimNotify.h>
20 #include <ossim/base/ossimTrace.h>
21 
22 #include <climits>
23 #include <cstring>
24 #include <iostream>
25 #include <vector>
26 using namespace std;
27 
28 //***
29 // Define Trace flags for use within this file:
30 //***
31 static ossimTrace traceExec ("ossimDblGrid:exec");
32 static ossimTrace traceDebug ("ossimDblGrid:debug");
33 
34 static const ossimString MAGIC_NUMBER ("OSSIM_DBL_GRID");
35 
36 /*!****************************************************************************
37 * DEFAULT CONSTRUCTOR: ossimDblGrid
38 *
39 *****************************************************************************/
41 :
42 theGridData (0),
43 theSize (0, 0),
44 theOrigin (0.0, 0.0),
45 theSpacing (0.0, 0.0),
46 theMinValue (OSSIM_DEFAULT_MIN_PIX_DOUBLE),
47 theMaxValue (OSSIM_DEFAULT_MAX_PIX_DOUBLE),
48 theNullValue (OSSIM_DEFAULT_NULL_PIX_DOUBLE),
49 theMeanValue (0.0),
50 theDeviation (0.0),
51 theMeanIsComputed (false),
52 theExtrapIsEnabled (true),
53 theDomainType (CONTINUOUS)
54 { }
55 
56 
57 /*!****************************************************************************
58 * COPY CONSTRUCTOR: ossimDblGrid
59 *
60 *****************************************************************************/
62 :
63 theGridData (0),
64 theMinValue (OSSIM_DEFAULT_MIN_PIX_DOUBLE),
65 theMaxValue (OSSIM_DEFAULT_MAX_PIX_DOUBLE),
66 theExtrapIsEnabled (true),
67 theDomainType (CONTINUOUS)
68 {
69  static const char MODULE[] = "ossimDblGrid Constructor";
70  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entering...\n";
71 
72  *this = source;
76  // int buflen = theSize.x * theSize.y;
77  // theGridData = new double [buflen];
78 
79  // for (int i=0; i<buflen; i++)
80  // theGridData[i] = source.theGridData[i];
81 
82  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " returning...\n";
83 }
84 
85 /*!****************************************************************************
86 * CONSTRUCTOR: ossimDblGrid
87 *
88 *****************************************************************************/
90  const ossimDpt& origin,
91  const ossimDpt& spacing,
92  double null_value)
93  :
94 theGridData (0),
95 theMinValue (OSSIM_DEFAULT_MIN_PIX_DOUBLE),
96 theMaxValue (OSSIM_DEFAULT_MAX_PIX_DOUBLE),
97 theExtrapIsEnabled (true),
98 theDomainType (CONTINUOUS)
99 {
100  static const char MODULE[] = "ossimDblGrid Constructor";
101  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entering...\n";
102 
103  initialize(size, origin, spacing, null_value);
104 
105  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " returning...\n";
106 }
107 
108 /*!****************************************************************************
109 * CONSTRUCTOR: ossimDblGrid
110 *
111 *****************************************************************************/
113  const ossimDpt& spacing,
114  double null_value)
115  :
116 theGridData (0),
117 theMinValue (OSSIM_DEFAULT_MIN_PIX_DOUBLE),
118 theMaxValue (OSSIM_DEFAULT_MAX_PIX_DOUBLE),
119 theExtrapIsEnabled (true),
120 theDomainType (CONTINUOUS)
121 {
122  static const char MODULE[] = "ossimDblGrid Constructor";
123  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entering...\n";
124 
125  ossimIpt size ((int) (rect.width()/spacing.x) + 1,
126  (int) (rect.height()/spacing.y) + 1);
127 
128  initialize(size, rect.ul(), spacing, null_value);
129 
130  if (traceExec()) ossimNotify(ossimNotifyLevel_WARN) << MODULE << " returning...\n";
131 }
132 
133 //*****************************************************************************
134 // DESTRUCTOR: ~ossimDblGrid()
135 //
136 //*****************************************************************************
138 {
139  if(theGridData)
140  {
141  delete [] theGridData;
142  theGridData = NULL;
143  }
144 }
145 
146 //*****************************************************************************
147 // METHOD: ossimDblGrid::initialize()
148 //
149 // Permits initialization after construction
150 //
151 //*****************************************************************************
153  const ossimDpt& origin,
154  const ossimDpt& spacing,
155  double null_value)
156 {
157  static const char MODULE[] = "ossimDblGrid::initialize()";
158  if (traceExec()) ossimNotify(ossimNotifyLevel_WARN) << MODULE << " entering...\n";
159 
160  //***
161  // Delete any existing grid:
162  //***
163  if (theGridData)
164  {
165  delete [] theGridData;
166  theGridData = 0;
167  }
168 
169  //***
170  // Initialize data members:
171  //***
172  theSize = size;
173  theOrigin = origin;
175  theNullValue = null_value;
178  theMeanIsComputed = false;
179 
183  ossim_uint32 buflen = theSize.x * theSize.y;
184  if(buflen > 0)
185  {
186  theGridData = new double [buflen];
187 
188  for (ossim_uint32 i=0; i<buflen; i++)
190  }
191  if (traceExec()) ossimNotify(ossimNotifyLevel_WARN) << MODULE << " returning...\n";
192 
193  return;
194 }
195 
196 //*****************************************************************************
197 // METHOD: ossimDblGrid::initialize()
198 //
199 // Permits initialization after construction
200 //
201 //*****************************************************************************
203  const ossimDpt& spacing,
204  double null_value)
205 {
206  static const char MODULE[] = "ossimDblGrid::initialize()";
207  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entering...\n";
208 
209  ossimIpt size ((int) (uv_rect.width()/spacing.x) + 1,
210  (int) (uv_rect.height()/spacing.y) + 1);
211 
212  initialize(size, uv_rect.ul(), spacing, null_value);
213 
214  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " returning...\n";
215  return;
216 }
217 
218 //**************************************************************************************************
220 {
221  if(theGridData)
222  {
223  delete [] theGridData;
224  theGridData = 0;
225  }
226  theSize = ossimIpt(0,0);
227 }
228 
229 /*!****************************************************************************
230 * METHOD: ossimDblGrid::setNode(x, y) NON-CONST
231 *
232 * This method is used to assign the grid data values.
233 *
234 *****************************************************************************/
235 void ossimDblGrid::setNode (int x, int y, const double& input)
236 {
237  if(!theGridData) return;
238 
239  // Insure the value passed in is allowed:
240  double value = input;
241  constrain(value);
242 
243  if ((x>=0)&&(x<theSize.x)&&(y>=0)&&(y<theSize.y))
244  {
245  theGridData[index(x, y)] = value;
246 
247  if (value != theNullValue)
248  {
249  if (value < theMinValue)
250  theMinValue = value;
251  if (value > theMaxValue)
252  theMaxValue = value;
253  }
254 
255  theMeanIsComputed = false;
256  }
257 
258  return;
259 }
260 
261 /*!****************************************************************************
262 * METHOD: ossimDblGrid::setNearestNode(uv)
263 *
264 * Sets the node nearest the U,V point specified to the value given. This is
265 * different from setNode() in that the UV coordinate system is used to
266 * address a node instead of an XY grid point.
267 *
268 *****************************************************************************/
270  const double& input)
271 {
272  if(!theGridData) return;
273 
274  // Insure the value passed in is allowed:
275  double value = input;
276  constrain(value);
277 
278  //***
279  // Establish the grid indexes:
280  //***
281  int xi = ossim::round<int>((uv_point.u - theOrigin.u)/theSpacing.x);
282  int yi = ossim::round<int>((uv_point.v - theOrigin.v)/theSpacing.y);
283 
284  if (xi < 0)
285  xi = 0;
286  if (xi >= theSize.x)
287  xi = theSize.x - 1;
288  if (yi < 0)
289  yi = 0;
290  if (yi >= theSize.y)
291  yi = theSize.y - 1;
292 
293  setNode (xi, yi, value);
294 
295  return;
296 }
297 
298 /*!****************************************************************************
299 * METHOD: ossimDblGrid::getNode(x, y) CONST
300 *
301 * This method is used to return the grid data values.
302 *
303 *****************************************************************************/
304 double ossimDblGrid::getNode (int x, int y) const
305 {
306  if(!theGridData) return theNullValue;
307  if ((x>=0)&&(x<theSize.x)&&(y>=0)&&(y<theSize.y))
308  {
309  ossim_uint32 i = index(x, y);
310  double val = theGridData[i];
311  return val;
312  }
313  return theNullValue;
314 }
315 
316 /*!****************************************************************************
317 * METHOD: ossimDblGrid::operator(double, double)
318 *
319 * This method interpolates between grid points given a fractional location
320 * in UV (external) world space.
321 *
322 *****************************************************************************/
323 double ossimDblGrid::operator() (const double& u, const double& v) const
324 {
325  if(!theGridData) return theNullValue;
326 
327  double xi = (u - theOrigin.u)/theSpacing.x;
328  double yi = (v - theOrigin.v)/theSpacing.y;
329 
330  if ((xi >= 0.0) && (xi <= (double)theSize.x-1) && (yi >= 0.0) && (yi <= (double)theSize.y-1))
331  return interpolate(xi, yi);
332 
333  else if (theExtrapIsEnabled)
334  return extrapolate(xi, yi);
335 
336  return theNullValue;
337 }
338 
339 //*************************************************************************************************
341 //*************************************************************************************************
342 double ossimDblGrid::interpolate(double xi, double yi) const
343 {
344  if(!theGridData)
345  return theNullValue;
346 
347  // Establish the grid cell origin indices:
348  int x0 = (int) xi;
349  int y0 = (int) yi;
350 
351  // Compute bilinear interpolation weights:
352  double wx1 = xi - x0;
353  double wy1 = yi - y0;
354  double wx0 = 1.0 - wx1;
355  double wy0 = 1.0 - wy1;
356  double w00 = wx0 * wy0;
357  double w01 = wx0 * wy1;
358  double w10 = wx1 * wy0;
359  double w11 = wx1 * wy1;
360 
361  // Establish grid indices for 4 surrounding points:
362  int index00 = theSize.x*y0 + x0;
363  int index10 = index00;
364  int index11 = index00;
365  int index01 = index00;
366 
367  if (x0 < (theSize.x-1)) index10 = index00 + 1;
368  if (y0 < (theSize.y-1)) index01 = index00 + theSize.x;
369  if (y0 < (theSize.y-1)) index01 = index00 + theSize.x;
370  if (x0 < (theSize.x-1)) index11 = index01 + 1;
371 
372  // Safety check:
373  int max_idx = theSize.x * theSize.y;
374  if ((index00 > max_idx) || (index10 > max_idx) || (index11 > max_idx) || (index01 > max_idx))
375  return ossim::nan();
376 
377  // Extract the four data points:
378  double p00 = theGridData[index00];
379  double p01 = theGridData[index01];
380  double p10 = theGridData[index10];
381  double p11 = theGridData[index11];
382 
383  // Consider the numerical domain to catch any wrap condition:
384  if (theDomainType >= WRAP_180)
385  {
386  double dp01_00 = p01 - p00;
387  double dp10_00 = p10 - p00;
388  double dp11_00 = p11 - p00;
389 
390  if (dp01_00 > 180.0)
391  p01 -= 360.0;
392  else if (dp01_00 < -180.0)
393  p01 += 360.0;
394 
395  if (dp10_00 > 180.0)
396  p10 -= 360.0;
397  else if (dp10_00 < -180.0)
398  p10 += 360.0;
399 
400  if (dp11_00 > 180.0)
401  p11 -= 360.0;
402  else if (dp11_00 < -180.0)
403  p11 += 360.0;
404  }
405 
406  // Perform interpolation:
407  double value = (p00*w00 + p01*w01 + p10*w10 + p11*w11) / (w00 + w01 + w10 + w11);
408  constrain(value);
409 
410  return value;
411 }
412 
413 //**************************************************************************************************
414 // METHOD: ossimDblGrid::extrapolate()
415 //
416 // Establishes bilinear extrapolation value for point outside of the grid.
417 //
418 //**************************************************************************************************
419 double ossimDblGrid::extrapolate(double x, double y) const
420 {
421  if(!theGridData)
422  return theNullValue;
423 
424 
425  // Decide which extra-grid region contains the input point:
426  double dx=0, dy=0, dR_dx=0, dR_dy=0, R0;
427  if (y < 0)
428  {
429  // The point is above the top edge of grid space:
430  dy = y;
431  if (x < 0)
432  {
433  // The point is in the top-left region. Use UL corner alone as reference, and compute first
434  // and second partials:
435  R0 = getNode(0, 0);
436  dx = x;
437  dR_dx = getNode(1, 0) - R0;
438  dR_dy = getNode(0, 1) - R0;
439  }
440  else if (x <= theSize.x-1)
441  {
442  // The point directly above the grid, use the dR_dy of the edge pixel:
443  R0 = interpolate(x, 0);
444  dR_dy = interpolate(x, 1.0) - R0;
445  }
446  else
447  {
448  // The point is in the top-right region:
449  R0 = getNode(theSize.x - 1, 0);
450  dx = x - theSize.x + 1;
451  dR_dx = R0 - getNode(theSize.x-2, 0);
452  dR_dy = getNode(theSize.x-1, 1) - R0;
453  }
454  }
455  else if (y <= theSize.y-1)
456  {
457  // The point is either to the left, the right, or inside of the grid:
458  if (x < 0)
459  {
460  // The point is directly to the left of the grid:
461  R0 = interpolate(0, y);
462  dx = x;
463  dR_dx = interpolate(1.0, y) - R0;
464  }
465  else if (x <= theSize.x-1)
466  {
467  // The point is inside the grid. This should never happen, but handle just in case:
468  return interpolate(x, y);
469  }
470  else
471  {
472  // The point directly to the right of the grid:
473  R0 = interpolate((double)theSize.x-1, y);
474  dx = x - theSize.x + 1;
475  dR_dx = R0 - interpolate((double)theSize.x-2, y);
476  }
477  }
478  else
479  {
480  // The point is below the bottom edge of grid space:
481  dy = y - theSize.y + 1;
482  if (x < 0)
483  {
484  // The point is in the bottom-left region:
485  R0 = getNode(0, theSize.y-1);
486  dx = x;
487  dR_dx = getNode(1, theSize.y-1) - R0;
488  dR_dy = R0 - getNode(0, theSize.y-2);
489  }
490  else if (x < theSize.x-1)
491  {
492  // The point directly below the grid:
493  R0 = interpolate(x, (double)theSize.y-1);
494  dR_dy = R0 - interpolate(x, (double)theSize.y-2);
495  }
496  else
497  {
498  // The point is in the bottom-right region:
499  R0 = getNode(theSize.x - 1, theSize.y-1);
500  dx = x - theSize.x + 1;
501  dR_dx = R0 - getNode(theSize.x-2, theSize.y-1);
502  dR_dy = R0 - getNode(theSize.x-1, theSize.y-2);
503  }
504  }
505 
506  // Consider the numerical domain and adjust potential wrap conditions in the differences:
507  if (theDomainType >= WRAP_180)
508  {
509  if (dR_dx > 180.0) dR_dx -= 360.0;
510  else if (dR_dx < -180.0) dR_dx += 360.0;
511 
512  if (dR_dy > 180.0) dR_dy -= 360.0;
513  else if (dR_dy < -180.0) dR_dy += 360.0;
514  }
515 
516  double R = R0 + dR_dx*dx + dR_dy*dy;
517  constrain(R);
518  return R;
519 }
520 
521 //*****************************************************************************
522 // OPERATOR: =
523 //
524 //*****************************************************************************
526 {
527  if(&source == this) return *this;
528 
529  if (theGridData)
530  {
531  delete [] theGridData;
532  theGridData = 0;
533  }
534 
535  //***
536  // Assign data members:
537  //***
538  theSize = source.theSize;
539  theOrigin = source.theOrigin;
540  theSpacing = source.theSpacing;
541  theMinValue = source.theMinValue;
542  theMaxValue = source.theMaxValue;
543  theNullValue = source.theNullValue;
544  theMeanValue = source.theMeanValue;
545  theDeviation = source.theDeviation;
547  theDomainType = source.theDomainType;
549 
550  //***
551  // Allocate mem for the grid, and initialize:
552  //***
553  int buflen = theSize.x * theSize.y;
554  if(buflen>0)
555  {
556  theGridData = new double [buflen];
557 
558  for (int i=0; i<buflen; i++)
559  {
560  theGridData[i] = source.theGridData[i];
561  }
562  }
563 
564  return *this;
565 }
566 
567 
568 /*!****************************************************************************
569 * METHOD: ossimDblGrid::meanValue()
570 *
571 *****************************************************************************/
573 {
574  static const char MODULE[] = "ossimDblGrid::meanValue()";
575  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entering...\n";
576 
577  if (!theMeanIsComputed)
578  {
579  computeMean();
580  }
581 
582  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " returning...\n";
583  return theMeanValue;
584 }
585 
586 /*!****************************************************************************
587 * METHOD: ossimDblGrid::meanStdDev()
588 *
589 *****************************************************************************/
591 {
592  static const char MODULE[] = "ossimDblGrid::meanStdDev()";
593  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entering...\n";
594 
595  if (!theMeanIsComputed)
596  computeMean();
597 
598  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " returning...\n";;
599  return theDeviation;
600 }
601 
602 /*!****************************************************************************
603 * METHOD: ossimDblGrid::computeMean()
604 *
605 *****************************************************************************/
607 {
608  static const char MODULE[] = "ossimDblGrid::meanStdDev()";
609  if(!theGridData) return;
610  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "entering...\n";
611 
612  if (!theMeanIsComputed)
613  {
614  double accum = 0.0;
615  double num_samples = 0.0;
616 
620  for (int i=0; i<(theSize.x*theSize.y); i++)
621  {
622  if (theGridData[i] != theNullValue)
623  {
624  accum += theGridData[i];
625  num_samples += 1.0;
626  }
627  }
628  theMeanValue = accum/num_samples;
629 
633  accum = 0.0;
634  double diff;
635  for (int i=0; i<(theSize.x*theSize.y); i++)
636  {
637  if (theGridData[i] != theNullValue)
638  {
639  diff = theMeanValue - theGridData[i];
640  accum += diff*diff;
641  }
642  }
643  theDeviation = sqrt(accum/num_samples);
644 
645  theMeanIsComputed = true;
646  }
647 
648  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " returning...\n";
649  return;
650 }
651 
652 /*!****************************************************************************
653 * INLINE METHOD: ossimDblGrid::isInside(const ossimDpt& pt) const
654 *****************************************************************************/
655 bool ossimDblGrid::isInside(const double& u, const double& v) const
656 {
657  double xi = (u - theOrigin.u)/theSpacing.x;
658  double yi = (v - theOrigin.v)/theSpacing.y;
659  return ((xi >= 0.0) && (xi <= ((double)theSize.x - 1.0)) &&
660  (yi >= 0.0) && (yi <= ((double)theSize.y - 1.0)));
661  //return ((xi >= 0.0) && (xi < ((double)theSize.x)) &&
662  // (yi >= 0.0) && (yi < ((double)theSize.y)));
663 }
664 
665 
666 //*****************************************************************************
667 // METHOD: ossimDblGrid::save()
668 //
669 // Saves the grid to the stream in compact ASCII format (not necessarily
670 // human readable).
671 //
672 //*****************************************************************************
673 bool ossimDblGrid::save(ostream& os, const char* descr) const
674 {
675  static const char MODULE[] = "ossimDblGrid::save()";
676  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entering...\n";
677 
678  //***
679  // Preserve the stream's settings:
680  //***
681  ios::fmtflags new_options = ios::scientific|ios::dec;
682  //ios::streamsize new_precision = 12;
683  int new_precision = 12;
684 
685  ios::fmtflags old_options = os.flags(new_options);
686  int old_precision = os.precision(new_precision);
687 
688  //***
689  // Verify the description string is not too long:
690  //***
691  char descr_buf[81];
692  std::strncpy(descr_buf, descr, 80);
693  descr_buf[80] = '\0';
694 
695  //***
696  // write magic number tag and the grid size X, Y, num params:
697  //***
698  os << MAGIC_NUMBER << " " << descr_buf << "\n"
699  << theSize.x << " "
700  << theSize.y << " "
701  << theOrigin.u << " "
702  << theOrigin.v << " "
703  << theSpacing.u << " "
704  << theSpacing.v << " "
705  << theNullValue << " "
706  << (int) theDomainType << "\n";
707 
708  if(theGridData)
709  {
710  //***
711  // Loop to write grid points:
712  //***
713  int max_index = theSize.x*theSize.y;
714  for (int i=0; i<max_index; i++)
715  os << theGridData[i] << " ";
716  }
717  os << "\n";
718 
719  //***
720  // Restore the stream's state:
721  //***
722  os.flags(old_options);
723  os.precision(old_precision);
724 
725  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " returning...\n";
726  return true;
727 }
728 
729 //*****************************************************************************
730 // METHOD: ossimDblGrid::load()
731 //
732 // Loads the grid from the stream in compact ASCII format (not necessarily
733 // human readable).
734 //
735 //*****************************************************************************
737 {
738  static const char MODULE[] = "ossimDblGrid::load()";
739  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entering...\n";
740 
741  ossimString strbuf;
742 
743  //***
744  // Read magic number tag to insure it is an ossimDblGrid record:
745  //***
746  getline(is, strbuf);
747  if (!strbuf.contains(MAGIC_NUMBER))
748  {
749  ossimNotify(ossimNotifyLevel_FATAL) << MODULE << "Error reading OSSIM_DBL_GRID magic number from stream. "
750  << "Aborting...\n";
751  return false;
752  }
753 
754  theSize = ossimDpt(0,0);
755  theOrigin = ossimDpt(0,0);
756  theSpacing = ossimDpt(0,0);
759  // theNullValue = theNullValue;
760  theMeanIsComputed = false;
761 
762  //***
763  // Read the grid size, origin, and spacing:
764  //***
765  ossimIpt size;
767  double null_value;
768  getline(is, strbuf);
769  vector<ossimString> items = strbuf.split(" ", true);
770  if (items.size() < 7)
771  {
772  ossimNotify(ossimNotifyLevel_FATAL) << MODULE << "Error reading OSSIM_DBL_GRID parameters. "
773  << "Aborting...\n";
774  return false;
775  }
776  size.x = items[0].toInt();
777  size.y = items[1].toInt();
778  origin.u = items[2].toDouble();
779  origin.v = items[3].toDouble();
780  spacing.u = items[4].toDouble();
781  spacing.v = items[5].toDouble();
782  null_value = items[6].toDouble();
783 
784  // Check for possible domain type 7th parameter (Added Sep 2016 OLK)
785  if ((items.size() > 7))
786  theDomainType = (DomainType) items[7].toInt();
787 
788  initialize(size, origin, spacing, null_value);
789 
790  //***
791  // Loop to read grid points:
792  //***
793  int max_index = theSize.x*theSize.y;
794  for (int i=0; i<max_index; i++)
795  {
796  is >> theGridData[i];
797  }
798  getline(is, strbuf);
799 
800  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " returning...\n";
801 
802  return true;
803 }
804 
805 //*****************************************************************************
806 // PRIVATE FUNCTION: isBlocked()
807 //
808 // Used by interpolateNullValuedNodes. Returns true if the direction indicated
809 // by the vector (x, y) has been blocked from further sampling. This occurs if
810 // a sample has already been found in that general direction. The directions
811 // are discrete (16) evenly distributed about a "compass rose." Each index
812 // corresponds to one of the directions as illustrated here:
813 //
814 // 15 0 1
815 // 14 | 2
816 // 13 | 3
817 // 12------+------4
818 // 11 | 5
819 // 10 | 6
820 // 9 8 7
821 //
822 //*****************************************************************************
823 bool isBlocked(bool* blocked, int x, int y)
824 {
825  if (y == 0)
826  {
827  if (x > 0) return blocked[4];
828  return blocked[12];
829  }
830 
831  double r = x/y;
832  int c = 0;
833  int i;
834  if (x < 0.0) c = 8;
835 
836  //***
837  // Test the tangent value instead of computing angle:
838  //***
839  if (r > 5.02734) i = 12 + c;
840  else if (r > 1.49660) i = 13 + c;
841  else if (r > 0.66818) i = 14 + c;
842  else if (r > 0.19891) i = 15 + c;
843  else if (r > -0.19891) i = 0 + c;
844  else if (r > -0.66818) i = 1 + c;
845  else if (r > -1.49660) i = 2 + c;
846  else if (r > -5.02734) i = 3 + c;
847  else i = 4 + c;
848 
849  if (i > 15) i -= 16; // modulo 16
850 
851  return blocked[i];
852 }
853 
854 //*****************************************************************************
855 // PRIVATE FUNCTION: blockDirection()
856 //
857 // Used by interpolateNullValuedNodes. Blocks the resampler from exploring
858 // further in a general direction, specified by thevector (x, y). The blocking
859 // is requested when a sample is found. This prevents a sample that is shadowed
860 // by a closer sample from having influence.
861 //
862 // See method isBlocked() above for a description of the compass rose indexing.
863 //
864 //*****************************************************************************
865 void blockDirection(bool* blocked, int x, int y)
866 {
867  if (y == 0)
868  {
869  if (x > 0) blocked[4] = true;
870  else blocked[12] = true;
871  return;
872  }
873 
874  double r = x/y;
875  int c = 0;
876  int i;
877  if (x < 0.0) c = 8;
878 
879  //***
880  // Test the tangent value instead of computing angle:
881  //***
882  if (r > 5.02734) i = 12 + c;
883  else if (r > 1.49660) i = 13 + c;
884  else if (r > 0.66818) i = 14 + c;
885  else if (r > 0.19891) i = 15 + c;
886  else if (r > -0.19891) i = 0 + c;
887  else if (r > -0.66818) i = 1 + c;
888  else if (r > -1.49660) i = 2 + c;
889  else if (r > -5.02734) i = 3 + c;
890  else i = 4 + c;
891 
892  if (i > 15) i -= 16; // modulo 16
893  blocked[i] = true;
894 
895  return;
896 }
897 
898 //*****************************************************************************
899 // METHOD: ossimDblGrid::interpolateNullValuedNodes(decay_rate)
900 //
901 // This method performs a resampling of the defined grid nodes in order to
902 // compute interpolated values for those uninitialized nodes. This is
903 // necessary when only a subset of nodes are available for initializing the
904 // grid.
905 //
906 // The decay rate is a geometric (1/r) factor applied to the weights to
907 // amplify the rate at which a neighbor's influence diminishes. For a
908 // decay_rate = 1, the influence of a sample diminishes linearly with the
909 // distance.
910 //
911 //*****************************************************************************
912 void ossimDblGrid::interpolateNullValuedNodes(const double& decay_rate)
913 {
914  static const char MODULE[] = "ossimDblGrid::interpolateNullValuedNodes()";
915  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entering...\n";
916  if(!theGridData) return;
917 
918  //***
919  // Allocate buffer to store resampled nodes:
920  //***
921  int buf_size = theSize.x*theSize.y;
922 
923  //---
924  // Note: Changed resampled_grid from double* to vector<double> to fix
925  // coverity scan uninitialized error. This calls the fill constructor.
926  // drb - 20150527
927  //---
928  std::vector<double> resampled_grid( buf_size, 0.0 );
929 
930  double min_weight_needed = 4.0/decay_rate;
931 
932  int start_x, start_y, end_x, end_y;
933  int diameter;
934  double sum_weights;
935  double accumulator;
936  double weight;
937  double sample;
938  double node_value;
939  bool sample_found;
940  int node_idx;
941  double adj_delta;
942  int dx, dy;
943  bool blocked[16];
944 
945  //***
946  // Loop over the entire grid to resample all NULL nodes:
947  //***
948  for (int y=0; y<theSize.y; ++y)
949  {
950  for (int x=0; x<theSize.x; ++x)
951  {
952  //***
953  // Only resample those nodes that contain NULL:
954  //***
955  node_idx = index(x, y);
956  node_value = theGridData[node_idx];
957  if (node_value != theNullValue)
958  {
959  //***
960  // This node had a value. Simply copy it into the resample_grid:
961  //***
962  resampled_grid[node_idx] = node_value;
963  }
964 
965  else
966  {
967  //***
968  // Resampling is necessary. Initialize quantities used:
969  //***
970  start_x = x;
971  start_y = y;
972  diameter = 0;
973  sum_weights = 0;
974  accumulator = 0;
975  weight = 1.0;
976  sample_found = true;
977 
978  for (int i=0; i<16; i++)
979  blocked[i] = false;
980 
981  //***
982  // Loop collecting contributions from non-null neighbors. Begin with
983  // a small kernel size (diameter) and successively grow until a
984  // sufficient number of contributors is found:
985  //***
986  while ((sum_weights < min_weight_needed) && sample_found)
987  {
988  diameter += 2;
989  start_x -= 1;
990  start_y -= 1;
991  weight *= decay_rate;
992  sample_found = false;
993 
994  //***
995  // Loop over each pixel in kernel and sum in it's contribution:
996  //***
997  end_y = start_y + diameter;
998  end_x = start_x + diameter;
999 
1000  for (int yn=start_y; yn<=end_y; ++yn)
1001  {
1002  if ((yn == start_y) || (yn == end_y))
1003  {
1004  //***
1005  // This is the top edge or bottom edge, need samples from
1006  // each x along kernel edge:
1007  //***
1008  for (int xn=start_x; xn<=end_x; ++xn)
1009  {
1010  sample_found = sample_found || isInside(xn, yn);
1011  sample = getNode(xn, yn);
1012  if (sample != theNullValue)
1013  {
1014  dx = x - xn; dy = y - yn;
1015  if (!isBlocked(blocked, dx, dy))
1016  {
1017  adj_delta = weight*sqrt((double)(dx*dx + dy*dy));
1018  accumulator += sample/adj_delta;
1019  sum_weights += 1.0/adj_delta;
1020  blockDirection(blocked, dx, dy);
1021  }
1022  }
1023  }
1024  }
1025  else
1026  {
1027  //***
1028  // For the left/right edge of the kernel, need to sample
1029  // only the first (start_x) and last (end_x):
1030  //***
1031  sample_found = sample_found || isInside(start_x, yn);
1032  sample = getNode(start_x, yn);
1033  if (sample != theNullValue)
1034  {
1035  dx = x - start_x; dy = y - yn;
1036  if (!isBlocked(blocked, dx, dy))
1037  {
1038  adj_delta = weight*sqrt((double)(dx*dx + dy*dy));
1039  accumulator += sample/adj_delta;
1040  sum_weights += 1.0/adj_delta;
1041  blockDirection(blocked, dx, dy);
1042  }
1043  }
1044 
1045  sample_found = sample_found || isInside(end_x, yn);
1046  sample = getNode(end_x, yn);
1047  if (sample != theNullValue)
1048  {
1049  dx = x - end_x; dy = y - yn;
1050  if (!isBlocked(blocked, dx, dy))
1051  {
1052  adj_delta = weight*sqrt((double)(dx*dx + dy*dy));
1053  accumulator += sample/adj_delta;
1054  sum_weights += 1.0/adj_delta;
1055  blockDirection(blocked, dx, dy);
1056  }
1057  }
1058  } // end else
1059  } // end for loop over all rows in kernel
1060  } // end while loop inflating kernel size
1061 
1062  //***
1063  // Finished collecting sample contributions for this node. compute
1064  // convolution and save in buffer:
1065  //***
1066  if (sum_weights != 0)
1067  resampled_grid[node_idx] = accumulator/sum_weights;
1068  else
1069  resampled_grid[node_idx] = theNullValue;
1070 
1071  } // end else (if input node is NULL)
1072  } // end for loop over all columns in grid
1073  } // end for loop over all lines in grid
1074 
1075  //***
1076  // Now copy the resampled grid back into the original buffer:
1077  //***
1078  for (node_idx=0; node_idx<buf_size; node_idx++)
1079  theGridData[node_idx] = resampled_grid[node_idx];
1080 
1081  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " returning...\n";
1082  return;
1083 }
1084 
1085 //*****************************************************************************
1086 // METHOD: ossimDblGrid::filter(size_x, size_y, kernel)
1087 //
1088 // Passes the grid data through a convolution filter given in the kernel array.
1089 // The grid must not contain any NULL nodes as these are not scanned for.
1090 // The kernel sizes should be odd numbers.
1091 //
1092 //*****************************************************************************
1093 void ossimDblGrid::filter(int size_x, int size_y, double* kernel)
1094 {
1095  static const char MODULE[] = "ossimDblGrid::filter()";
1096  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << "entering...\n";
1097  if(!theGridData) return;
1098 
1099  int rx = (size_x - 1)/2; // kernel radii
1100  int ry = (size_y - 1)/2;
1101  int start_x = rx; // indexes to start sampling grid
1102  int start_y = ry;
1103  int end_x = theSize.x - rx; // indexes to end buffer sampling
1104  int end_y = theSize.y - ry;
1105  int knl_ctr = ry*size_x + rx; // offset to center of kernel buffer
1106  double node_value, kernel_value;
1107  int resample_node_idx;
1108 
1109  // The resampled data is accumulated and stored in a temporary ossimDblGrid object so that we
1110  // can take advantage of the extrapolation feature later in this method.
1111  ossimIpt resample_grid_size(end_x-start_x, end_y-start_y);
1112  ossimDpt resample_grid_origin(start_x, start_y);
1113  ossimDpt resample_grid_spacing(1,1);
1114  ossimDblGrid resample_grid(resample_grid_size, resample_grid_origin, resample_grid_spacing);
1115  resample_grid.enableExtrapolation();
1116  resample_grid.fill(0.0);
1117 
1118  // Loop over the entire grid to resample all NULL nodes:
1119  for (int y=start_y; y<end_y; y++)
1120  {
1121  for (int x=start_x; x<end_x; x++)
1122  {
1123  resample_node_idx = resample_grid.index(x-start_x, y-start_y);
1124 
1125  // Fetch samples for each kernel element, apply gain, then accumulate
1126  // in output buffer:
1127  for (int ky=-ry; ky<=ry; ky++)
1128  {
1129  for (int kx=-rx; kx<=rx; kx++)
1130  {
1131  node_value = theGridData[index(x+kx, y+ky)];
1132  kernel_value = kernel[knl_ctr + ky*size_x + kx];
1133  resample_grid.theGridData[resample_node_idx] += kernel_value*node_value;
1134  }
1135  }
1136  }
1137  }
1138 
1139  // Copy the resampled data to the original grid.
1140  // Note: the grid margin has unfiltered data due to the kernel radius. Use the resample_grid's
1141  // inherent extrapolator to fill in these unfiltered border nodes:
1142  for (int y=0; y<theSize.y; y++)
1143  {
1144  for (int x=0; x<theSize.x; x++)
1145  {
1146  theGridData[index(x, y)] = resample_grid(x, y); // automatically extrapolates if necessary
1147  }
1148  }
1149 
1150  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " returning...\n";
1151  return;
1152 }
1153 
1154 
1155 //*****************************************************************************
1156 // METHOD: ossimDblGrid::fill
1157 //
1158 // Fills the current grid with constant value provided.
1159 //
1160 //*****************************************************************************
1161 void ossimDblGrid::fill(double fill_value)
1162 {
1163  if (!theGridData)
1164  {
1165  return;
1166  }
1167 
1168  int size = theSize.x * theSize.y;
1169  for (int i=0; i<size; i++)
1170  theGridData[i] = fill_value;
1171 
1172  return;
1173 }
1174 
1175 //*************************************************************************************************
1176 // Constrains the value to the numerical domain specified in theDomainType.
1177 //*************************************************************************************************
1178 void ossimDblGrid::constrain(double& value) const
1179 {
1180  if ((theDomainType == CONTINUOUS) || (value == theNullValue))
1181  return;
1182 
1183  // Consider again the domain to verify the value is within allowable range:
1184  if (theDomainType == WRAP_180)
1185  {
1186  if (value <= -180.0)
1187  value += 360.0;
1188  else if (value > 180.0)
1189  value -= 360.0;
1190  }
1191  else if (theDomainType == WRAP_360)
1192  {
1193  if (value < 0.0)
1194  value += 360.0;
1195  else if (value >= 360.0)
1196  value -= 360.0;
1197  }
1198  //else if (theDomainType == SAWTOOTH_90)
1199  //{
1200  // // Any adjustment here corrupts the data value since it is clipped:
1201  // if (value < -90.0)
1202  // value = -90.0;
1203  // else if (value > 90.0)
1204  // value = 90.0;
1205  //}
1206 }
1207 
1208 //*****************************************************************************
1209 // FRIEND OPERATOR: ostream& << (ostream&)
1210 //
1211 //*****************************************************************************
1213 {
1214  os << "\nDump of ossimDblGrid at " << (void*) &grid
1215  << "\n theSize: " << grid.theSize
1216  << "\n theOrigin: " << grid.theOrigin
1217  << "\n theSpacing: " << grid.theSpacing
1218  << "\n theMinValue: " << grid.theMinValue
1219  << "\n theMaxValue: " << grid.theMaxValue
1220  << "\n theNullValue: " << grid.theNullValue
1221  << "\n theMeanValue: " << grid.theMeanValue
1222  << "\n theDeviation: " << grid.theDeviation
1223  << "\n theMeanIsComputed: " << grid.theMeanIsComputed
1224  << "\n";
1225 
1226  if(grid.theGridData)
1227  {
1228 
1229  for (int y=0; y<grid.theSize.y; y++)
1230  {
1231  for (int x=0; x<grid.theSize.x; x++)
1232  {
1233  os << "\n node(" << x << ", " << y << "): " << grid.getNode(x,y);
1234  }
1235  }
1236  }
1237 
1238  return os;
1239 }
ossim_uint32 x
ossimDpt theOrigin
Definition: ossimDblGrid.h:219
bool isBlocked(bool *blocked, int x, int y)
ossimDpt theSpacing
Definition: ossimDblGrid.h:220
bool theMeanIsComputed
Definition: ossimDblGrid.h:226
double theDeviation
Definition: ossimDblGrid.h:225
ossim_float64 width() const
Definition: ossimDrect.h:522
double u
Definition: ossimDpt.h:164
#define OSSIM_DEFAULT_MAX_PIX_DOUBLE
ossim_uint32 y
bool isInside(const ossimDpt &p) const
Definition: ossimDblGrid.h:195
double nan()
Method to return ieee floating point double precision NAN.
Definition: ossimCommon.h:135
const ossimDpt & ul() const
Definition: ossimDrect.h:339
const ossimIpt & size() const
Definition: ossimDblGrid.h:187
double y
Definition: ossimDpt.h:165
bool contains(char aChar) const
Definition: ossimString.h:58
void split(std::vector< ossimString > &result, const ossimString &separatorList, bool skipBlankFields=false) const
Splits this string into a vector of strings (fields) using the delimiter list specified.
void initialize(const ossimIpt &size, const ossimDpt &origin, const ossimDpt &spacing, double null_value=OSSIM_DEFAULT_NULL_PIX_DOUBLE)
double theMeanValue
Definition: ossimDblGrid.h:224
std::istream & getline(std::istream &is, ossimString &str, char delim)
Definition: ossimString.h:916
double * theGridData
Definition: ossimDblGrid.h:217
double operator()(const ossimDpt &uv_point) const
Definition: ossimDblGrid.h:161
void blockDirection(bool *blocked, int x, int y)
void computeMean()
void enableExtrapolation(bool arg=true)
Definition: ossimDblGrid.h:91
double extrapolate(double x, double y) const
bool load(std::istream &is)
#define OSSIM_DEFAULT_NULL_PIX_DOUBLE
#define OSSIM_DEFAULT_MIN_PIX_DOUBLE
double theNullValue
Definition: ossimDblGrid.h:223
yy_size_t size
double interpolate(double x, double y) const
Interpolates given non-integral point x, y.
unsigned int ossim_uint32
bool theExtrapIsEnabled
Definition: ossimDblGrid.h:227
void setNearestNode(const ossimDpt &uv_point, const double &value)
double getNode(const ossimIpt &p) const
Definition: ossimDblGrid.h:111
ossimIpt theSize
Definition: ossimDblGrid.h:218
ossim_float64 height() const
Definition: ossimDrect.h:517
void constrain(double &value) const
Constrains the value to the numerical domain specified in theDomainType.
void filter(int size_x, int size_y, double *kernel)
bool save(std::ostream &os, const char *descr) const
if(yy_init)
std::basic_istream< char > istream
Base class for char input streams.
Definition: ossimIosFwd.h:20
ossim_uint32 index(int x, int y) const
Definition: ossimDblGrid.h:215
const ossimDblGrid & operator=(const ossimDblGrid &grid)
const ossimDpt & origin() const
Definition: ossimDblGrid.h:188
ossim_int32 y
Definition: ossimIpt.h:142
DomainType theDomainType
Definition: ossimDblGrid.h:228
double x
Definition: ossimDpt.h:164
double meanStdDev()
ostream & operator<<(ostream &os, const ossimDblGrid &grid)
ossim_int32 x
Definition: ossimIpt.h:141
void interpolateNullValuedNodes(const double &decay_rate=10.0)
double value(const ossimDpt &uv_point) const
Definition: ossimDblGrid.h:162
void fill(double fill_value)
double meanValue()
void setNode(const ossimIpt &p, const double &value)
Definition: ossimDblGrid.h:107
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
double theMinValue
Definition: ossimDblGrid.h:221
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
double v
Definition: ossimDpt.h:165
double theMaxValue
Definition: ossimDblGrid.h:222
const ossimDpt & spacing() const
Definition: ossimDblGrid.h:189