OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimH5GridModel.cpp
Go to the documentation of this file.
1 //*****************************************************************************
2 // FILE: ossimH5GridModel.cc
3 //
4 // License: See LICENSE.txt file in the top level directory.
5 //
6 // AUTHOR: David Burken
7 //
8 // Copied from Mingjie Su's ossimHdfGridModel.
9 //
10 // DESCRIPTION:
11 // Contains implementation of class ossimH5GridModel. This is an
12 // implementation of an interpolation sensor model.
13 //
14 // IMPORTANT: The lat/lon grid is for ground points on the ellipsoid.
15 // The dLat/dHgt and dLon/dHgt partials therefore are used against
16 // elevations relative to the ellipsoid.
17 //
18 //*****************************************************************************
19 // $Id$
20 
21 #include "ossimH5GridModel.h"
22 #include "ossimH5Util.h"
23 
24 #include <ossim/base/ossimCommon.h>
25 #include <ossim/base/ossimEndian.h>
27 #include <ossim/base/ossimTrace.h>
29 
30 #include <hdf5.h>
31 #include <H5Cpp.h>
32 
33 #include <sstream>
34 
35 static ossimTrace traceDebug("ossimH5GridModel:debug");
36 
37 static const std::string CROSSES_DATELINE_KW = "crosses_dateline";
38 static const std::string GROUND_POLYGON_KW = "ground_polygon";
39 static const std::string WKT_FOOTPRINT_KW = "wkt_footprint";
40 
41 RTTI_DEF1(ossimH5GridModel, "ossimH5GridModel", ossimCoarseGridModel);
42 
44  :
46  m_crossesDateline(false),
47  m_boundGndPolygon()
48 {
50 }
51 
53 {
54 }
55 
56 bool ossimH5GridModel::setGridNodes( H5::DataSet* latDataSet,
57  H5::DataSet* lonDataSet,
58  const ossimIrect& validRect )
59 {
60  bool status = false;
61 
62  if ( latDataSet && lonDataSet )
63  {
64  m_crossesDateline = ossim_hdf5::crossesDateline( *lonDataSet, validRect );
65 
66  if ( m_crossesDateline )
67  {
69  }
70  else
71  {
73  }
74 
75  // Get dataspace of the dataset.
76  H5::DataSpace latDataSpace = latDataSet->getSpace();
77  H5::DataSpace lonDataSpace = lonDataSet->getSpace();
78  const ossim_int32 LAT_DIM_COUNT = latDataSpace.getSimpleExtentNdims();
79  const ossim_int32 LON_DIM_COUNT = lonDataSpace.getSimpleExtentNdims();
80 
81  // Number of dimensions of the input dataspace:
82  if ( ( LAT_DIM_COUNT == 2 ) && ( LON_DIM_COUNT == 2 ) )
83  {
84  const ossim_uint32 ROWS = validRect.height();
85  const ossim_uint32 COLS = validRect.width();
86  const ossim_uint32 GRID_SIZE = 4; // Only grab every 4th value.
87 
88  //---
89  // Get the extents:
90  // dimsOut[0] is height, dimsOut[1] is width:
91  //---
92  std::vector<hsize_t> latDimsOut(LAT_DIM_COUNT);
93  latDataSpace.getSimpleExtentDims( &latDimsOut.front(), 0 );
94  std::vector<hsize_t> lonDimsOut(LON_DIM_COUNT);
95  lonDataSpace.getSimpleExtentDims( &lonDimsOut.front(), 0 );
96 
97  // Verify valid rect within our bounds:
98  if ( (ROWS <= latDimsOut[0] ) && (ROWS <= lonDimsOut[0] ) &&
99  (COLS <= latDimsOut[1] ) && (COLS <= lonDimsOut[1] ) )
100  {
101  //----
102  // Initialize the ossimDblGrids:
103  //---
104  ossimDpt dspacing (GRID_SIZE, GRID_SIZE);
105 
106  ossim_uint32 gridRows = ROWS / GRID_SIZE + 1;
107  ossim_uint32 gridCols = COLS / GRID_SIZE + 1;
108 
109  // Round up if size doesn't fall on end pixel.
110  if ( ROWS % GRID_SIZE) ++gridRows;
111  if ( COLS % GRID_SIZE) ++gridCols;
112 
113  ossimIpt gridSize (gridCols, gridRows);
114 
115  // The grid as used in base class, has UV-space always at 0,0 origin
116  ossimDpt gridOrigin(0.0,0.0);
117 
118  const ossim_float64 NULL_VALUE = -999.0;
119 
122  theLatGrid.initialize(gridSize, gridOrigin, dspacing);
123  theLonGrid.initialize(gridSize, gridOrigin, dspacing);
124 
125  std::vector<hsize_t> inputCount(LAT_DIM_COUNT);
126  std::vector<hsize_t> inputOffset(LAT_DIM_COUNT);
127 
128  inputOffset[0] = 0; // row is set below.
129  inputOffset[1] = validRect.ul().x; // col
130 
131  inputCount[0] = 1; // row
132  inputCount[1] = (hsize_t)COLS; // col
133 
134  // Output dataspace dimensions. Reading a line at a time.
135  const ossim_int32 OUT_DIM_COUNT = 3;
136  std::vector<hsize_t> outputCount(OUT_DIM_COUNT);
137  outputCount[0] = 1; // band
138  outputCount[1] = 1; // row
139  outputCount[2] = COLS; // col
140 
141  // Output dataspace offset.
142  std::vector<hsize_t> outputOffset(OUT_DIM_COUNT);
143  outputOffset[0] = 0;
144  outputOffset[1] = 0;
145  outputOffset[2] = 0;
146 
147  ossimScalarType scalar = ossim_hdf5::getScalarType( latDataSet );
148  if ( scalar == OSSIM_FLOAT32 )
149  {
150  // Set the return status to true if we get here...
151  status = true;
152 
153  // See if we need to swap bytes:
154  ossimEndian* endian = 0;
155  if ( ( ossim::byteOrder() != ossim_hdf5::getByteOrder( latDataSet ) ) )
156  {
157  endian = new ossimEndian();
158  }
159 
160  // Native type:
161  H5::DataType latDataType = latDataSet->getDataType();
162  H5::DataType lonDataType = lonDataSet->getDataType();
163 
164  // Output dataspace always the same, width of one line.
165  H5::DataSpace bufferDataSpace( OUT_DIM_COUNT, &outputCount.front());
166  bufferDataSpace.selectHyperslab( H5S_SELECT_SET,
167  &outputCount.front(),
168  &outputOffset.front() );
169 
170  // Arrays to hold a single line of latitude longitude values.
171  vector<ossim_float32> latValue(COLS);
172  vector<ossim_float32> lonValue(COLS);
173  hsize_t row = 0;
174 
175  // Line loop:
176  for ( ossim_uint32 y = 0; y < gridRows; ++y )
177  {
178  // row = line in image space
179  row = y*GRID_SIZE;
180 
181  if ( row < ROWS )
182  {
183  inputOffset[0] = row + validRect.ul().y;
184 
185  latDataSpace.selectHyperslab( H5S_SELECT_SET,
186  &inputCount.front(),
187  &inputOffset.front() );
188  lonDataSpace.selectHyperslab( H5S_SELECT_SET,
189  &inputCount.front(),
190  &inputOffset.front() );
191 
192  // Read data from file into the buffer.
193  latDataSet->read( &(latValue.front()), latDataType,
194  bufferDataSpace, latDataSpace );
195  lonDataSet->read( &(lonValue.front()), lonDataType,
196  bufferDataSpace, lonDataSpace );
197 
198  if ( endian )
199  {
200  // If the endian pointer is initialized(not zero) swap the bytes.
201  endian->swap( &(latValue.front()), COLS );
202  endian->swap( &(lonValue.front()), COLS );
203  }
204 
205  // Sample loop:
206  hsize_t col = 0;
207 
208  for ( ossim_uint32 x = 0; x < gridCols; ++x )
209  {
210  ossim_float32 lat = ossim::nan();
211  ossim_float32 lon = ossim::nan();
212 
213  // col = sample in image space
214  col = x*GRID_SIZE;
215 
216  if ( col < COLS )
217  {
218  if ( (latValue[col] > NULL_VALUE)&&(lonValue[col] > NULL_VALUE) )
219  {
220  lat = latValue[col];
221  lon = lonValue[col];
222  if ( m_crossesDateline )
223  {
224  if ( lon < 0.0 ) lon += 360;
225  }
226  }
227  else // Nulls in grid!
228  {
229  std::string errMsg =
230  "ossimH5GridModel::setGridNodes encountered nans!";
231  throw ossimException(errMsg);
232  }
233  }
234  else // Last column is outside of image bounds.
235  {
236  // Get the last two latitude values:
237  ossim_float32 lat1 = theLatGrid.getNode( x-2, y );
238  ossim_float32 lat2 = theLatGrid.getNode( x-1, y );
239 
240  // Get the last two longitude values
241  ossim_float32 lon1 = theLonGrid.getNode( x-2, y );
242  ossim_float32 lon2 = theLonGrid.getNode( x-1, y );
243 
244  if ( ( lat1 > NULL_VALUE ) && ( lat2 > NULL_VALUE ) )
245  {
246  // Delta between last two latitude grid values.
247  ossim_float32 latSpacing = lat2 - lat1;
248 
249  // Compute:
250  lat = lat2 + latSpacing;
251  }
252  else // Nulls in grid!
253  {
254  std::string errMsg =
255  "ossimH5GridModel::setGridNodes encountered nans!";
256  throw ossimException(errMsg);
257  }
258 
259  if ( ( lon1 > NULL_VALUE ) && ( lon2 > NULL_VALUE ) )
260  {
261  // Delta between last two longitude values.
262  ossim_float32 lonSpacing = lon2 - lon1;
263 
264  // Compute:
265  lon = lon2 + lonSpacing;
266 
267  // Check for wrap:
268  if ( !m_crossesDateline && ( lon > 180 ) )
269  {
270  lon -= 360.0;
271  }
272  }
273  else // Nulls in grid!
274  {
275  std::string errMsg =
276  "ossimH5GridModel::setGridNodes encountered nans!";
277  throw ossimException(errMsg);
278  }
279 
280 #if 0 /* Please leave for debug. (drb) */
281  cout << "lat1: " << lat1 << " lat2 " << lat2
282  << " lon1 " << lon1 << " lon2 " << lon2
283  << "\n";
284 #endif
285  }
286 
287  // Assign the latitude and longitude.
288  theLatGrid.setNode( x, y, lat );
289  theLonGrid.setNode( x, y, lon );
290 
291 #if 0 /* Please leave for debug. (drb) */
292  cout << "x,y,col,row,lat,lon:" << x << "," << y << ","
293  << col << "," << row << ","
294  << theLatGrid.getNode(x, y)
295  << "," << theLonGrid.getNode( x, y) << "\n";
296 #endif
297 
298  } // End sample loop.
299 
300  }
301  else // Row is outside of image bounds:
302  {
303  // Sample loop:
304  for ( ossim_uint32 x = 0; x < gridCols; ++x )
305  {
306  ossim_float32 lat = ossim::nan();
307  ossim_float32 lon = ossim::nan();
308 
309  ossim_float32 lat1 = theLatGrid.getNode( x, y-2 );
310  ossim_float32 lat2 = theLatGrid.getNode( x, y-1 );
311  ossim_float32 lon1 = theLonGrid.getNode( x, y-2 );
312  ossim_float32 lon2 = theLonGrid.getNode( x, y-1 );
313 
314  if ( ( lon1 > NULL_VALUE ) && ( lon2 > NULL_VALUE ) )
315  {
316  // Delta between last two longitude values.
317  ossim_float32 lonSpacing = lon2 - lon1;
318 
319  // Compute:
320  lon = lon2 + lonSpacing;
321 
322  // Check for wrap:
323  if ( !m_crossesDateline && ( lon > 180 ) )
324  {
325  lon -= 360.0;
326  }
327  }
328  else // Nulls in grid!
329  {
330  std::string errMsg =
331  "ossimH5GridModel::setGridNodes encountered nans!";
332  throw ossimException(errMsg);
333  }
334 
335  if ( ( lat1 > NULL_VALUE ) && ( lat2 > NULL_VALUE ) )
336  {
337  // Delta between last two latitude values.
338  ossim_float32 latSpacing = lat2 - lat1;
339 
340  lat = lat2 + latSpacing;
341  }
342  else // Nulls in grid!
343  {
344  std::string errMsg =
345  "ossimH5GridModel::setGridNodes encountered nans!";
346  throw ossimException(errMsg);
347  }
348 
349 #if 0 /* Please leave for debug. (drb) */
350  hsize_t col = x*GRID_SIZE; // Sample in image space
351  cout << "lat1: " << lat1 << " lat2 " << lat2
352  << " lon1 " << lon1 << " lon2 " << lon2
353  << "\nx,y,col,row,lat,lon:" << x << "," << y << ","
354  << col << "," << row << "," << lat << "," << lon << "\n";
355 #endif
356  // Assign the latitude::
357  theLatGrid.setNode( x, y, lat );
358 
359  // Assign the longitude.
360  theLonGrid.setNode( x, y, lon );
361 
362  } // End sample loop.
363 
364  } // Matches if ( row < imageRows ){...}else{
365 
366  } // End line loop.
367 
368  latDataSpace.close();
369  lonDataSpace.close();
370 
371  if ( status )
372  {
374  *latDataSet,*lonDataSet, validRect );
375 
376  // Bileaner projection to handle
377  ossimDrect imageRect(validRect);
378  initializeModelParams(imageRect);
379 
380  // debugDump();
381  }
382 
383  if ( endian )
384  {
385  delete endian;
386  endian = 0;
387  }
388 
389  } // Matches: if ( scalar == OSSIM_FLOAT32 )
390 
391  } // Matches: if ( (latDimsOut[0] == imageRows) ...
392 
393  } // Matches: if ( ( LAT_DIM_COUNT == 2 ) ...
394 
395  } // Matches: if ( latDataSet && lonDataSet
396 
397  return status;
398 
399 } // End: bool ossimH5GridModel::setGridNodes( H5::DataSet* latDataSet, ... )
400 
401 bool ossimH5GridModel::saveState(ossimKeywordlist& kwl, const char* prefix) const
402 {
403  // Base save state. This will save the "type" key to "ossimH5GridModel".
404  bool status = ossimCoarseGridModel::saveState( kwl, prefix );
405 
406  if ( status )
407  {
408  std::string myPrefix = ( prefix ? prefix: "" );
409  std::string value;
410 
411  // m_crossesDateline:
413  kwl.addPair( myPrefix,CROSSES_DATELINE_KW, value, true );
414 
415  // Computed wkt footprint:
416  if ( getWktFootprint( value ) )
417  {
418  kwl.addPair( myPrefix, WKT_FOOTPRINT_KW, value, true );
419  }
420 
421  // m_boundGndPolygon:
423  {
424  std::string polyPrefix = myPrefix;
425  polyPrefix += GROUND_POLYGON_KW;
426  polyPrefix += ".";
427  m_boundGndPolygon.saveState( kwl, polyPrefix.c_str() );
428  }
429 
430  //---
431  // theSeedFunction: This is in the base class ossimSensorModel but is not
432  // in the ossimSensorModel::saveState so do it here.
433  //---
434  if ( theSeedFunction.valid() )
435  {
436  ossimString seedPrefix = myPrefix;
437  seedPrefix += "seed_projection.";
438  status = theSeedFunction->saveState(kwl, seedPrefix.c_str());
439  }
440  }
441 
442  return status;
443 }
444 
445 bool ossimH5GridModel::loadState(const ossimKeywordlist& kwl, const char* prefix)
446 {
447  bool result = false;
448 
449  std::string myPrefix = ( prefix ? prefix: "" );
450 
451  // Look for type key:
452  std::string key = "type";
453  std::string value = kwl.findKey( myPrefix, key );
454 
455  if ( value.size() )
456  {
457  // ossimHdfGridModel included for backward compatibility.
458  if ( ( value == "ossimH5GridModel" ) || ( value == "ossimHdfGridModel" ) )
459  {
460  //---
461  // theSeedFunction: This is in the base class ossimSensorModel but is not
462  // in the ossimSensorModel::loadState so do it here.
463  //---
464  std::string seedPrefix = myPrefix;
465  seedPrefix += "seed_projection.";
466  value = kwl.findKey( seedPrefix, key );
467  if ( value.size() )
468  {
469  // Only do expensive factory call if key is found...
471  createProjection(kwl, seedPrefix.c_str());
472  }
473 
474  // m_crossesDateline:
475  value = kwl.findKey( myPrefix, CROSSES_DATELINE_KW );
476  if ( value.size() )
477  {
479  }
480 
481  // m_boundGndPolygon:
482  std::string polyPrefix = myPrefix;
483  polyPrefix += GROUND_POLYGON_KW;
484  polyPrefix += ".";
486  m_boundGndPolygon.loadState( kwl, polyPrefix.c_str() );
487 
488  // Make a copy of kwl so we can change type.
489  ossimKeywordlist myKwl = kwl;
490  value = "ossimCoarseGridModel";
491  myKwl.addPair( myPrefix, key, value, true );
492 
493  // Load the state of base class.
494  result = ossimCoarseGridModel::loadState( myKwl, prefix );
495  }
496  }
497 
498  return result;
499 
500 } // End: ossimH5GridModel::loadState( ... )
501 
502 //---------------------------------------------------------------------------**
503 // METHOD: ossimSensorModel::worldToLineSample()
504 //
505 // Performs forward projection of ground point to image space.
506 //
507 //---------------------------------------------------------------------------**
509  ossimDpt& ip) const
510 {
511  static const double PIXEL_THRESHOLD = .1; // acceptable pixel error
512  static const int MAX_NUM_ITERATIONS = 20;
513 
514  if(worldPoint.isLatNan() || worldPoint.isLonNan())
515  {
516  ip.makeNan();
517  return;
518  }
519 
520  //---
521  // First check if the world point is inside bounding rectangle:
522  //---
523  int iters = 0;
524  ossimDpt wdp (worldPoint);
525  if ( m_crossesDateline && (wdp.x < 0.0) )
526  {
527  // Longitude points stored between 0 and 360.
528  wdp.x += 360.0;
529  }
530 
533  {
534  if (!(m_boundGndPolygon.pointWithin(wdp)))
535  {
536  // if(theSeedFunction.valid())
537  // {
538  // theSeedFunction->worldToLineSample(worldPoint, ip);
539  // }
540  // else if(!theExtrapolateGroundFlag) // if I am not already in the extrapolation routine
541  // {
542  // ip = extrapolate(worldPoint);
543  // }
544  ip.makeNan();
545  return;
546  }
547 
548  }
549 
550  //---
551  // Substitute zero for null elevation if present:
552  //---
553  double height = worldPoint.hgt;
554  if ( ossim::isnan(height) )
555  {
556  height = 0.0;
557  }
558 
559  //---
560  // Utilize iterative scheme for arriving at image point. Begin with guess
561  // at image center:
562  //---
563  if(theSeedFunction.valid())
564  {
565  theSeedFunction->worldToLineSample(worldPoint, ip);
566  }
567  else
568  {
569  ip.u = theRefImgPt.u;
570  ip.v = theRefImgPt.v;
571  }
572 
573  ossimDpt ip_du;
574  ossimDpt ip_dv;
575 
576  ossimGpt gp, gp_du, gp_dv;
577  double dlat_du, dlat_dv, dlon_du, dlon_dv;
578  double delta_lat, delta_lon, delta_u, delta_v;
579  double inverse_norm;
580  bool done = false;
581  //---
582  // Begin iterations:
583  //---
584  do
585  {
586  //---
587  // establish perturbed image points about the guessed point:
588  //---
589  ip_du.u = ip.u + 1.0;
590  ip_du.v = ip.v;
591  ip_dv.u = ip.u;
592  ip_dv.v = ip.v + 1.0;
593 
594  //---
595  // Compute numerical partials at current guessed point:
596  //---
597  lineSampleHeightToWorld(ip, height, gp);
598  lineSampleHeightToWorld(ip_du, height, gp_du);
599  lineSampleHeightToWorld(ip_dv, height, gp_dv);
600 
601  if(gp.isLatNan() || gp.isLonNan())
602  {
604  }
605  if(gp_du.isLatNan() || gp_du.isLonNan())
606  {
607  gp_du = ossimCoarseGridModel::extrapolate(ip_du);
608  }
609  if(gp_dv.isLatNan() || gp_dv.isLonNan())
610  {
611  gp_dv = ossimCoarseGridModel::extrapolate(ip_dv);
612 
613  }
614 
615  if ( m_crossesDateline )
616  {
617  // Longitude set to between 0 and 360.
618  if ( gp.lon < 0.0 ) gp.lon += 360.0;
619  if ( gp_du.lon < 0.0 ) gp_du.lon += 360.0;
620  if ( gp_dv.lon < 0.0 ) gp_dv.lon += 360.0;
621  }
622 
623  dlat_du = gp_du.lat - gp.lat; //e
624  dlon_du = gp_du.lon - gp.lon; //g
625  dlat_dv = gp_dv.lat - gp.lat; //f
626  dlon_dv = gp_dv.lon - gp.lon; //h
627 
628  //---
629  // Test for convergence:
630  // Use the wdp as it was corrected if there was a date line cross.
631  //
632  delta_lat = wdp.lat - gp.lat;
633  delta_lon = wdp.lon - gp.lon;
634 
635  // Compute linearized estimate of image point given gp delta:
636  inverse_norm = dlat_dv*dlon_du - dlat_du*dlon_dv; // fg-eh
637 
638  if (!ossim::almostEqual(inverse_norm, 0.0, DBL_EPSILON))
639  {
640  delta_u = (-dlon_dv*delta_lat + dlat_dv*delta_lon)/inverse_norm;
641  delta_v = ( dlon_du*delta_lat - dlat_du*delta_lon)/inverse_norm;
642  ip.u += delta_u;
643  ip.v += delta_v;
644  }
645  else
646  {
647  delta_u = 0;
648  delta_v = 0;
649  }
650 
651 #if 0
652  cout << "gp: " << gp
653  << "\ngp_du: " << gp_du
654  << "\ngp_dv: " << gp_dv
655  << "\ndelta_lat: " << delta_lat
656  << "\ndelta_lon: " << delta_lon
657  << "\ndelta_u: " << delta_u
658  << "\ndelta_v: " << delta_v
659  << endl;
660 #endif
661 
662  done = ((fabs(delta_u) < PIXEL_THRESHOLD)&&
663  (fabs(delta_v) < PIXEL_THRESHOLD));
664  ++iters;
665 
666  } while ( (!done) && (iters < MAX_NUM_ITERATIONS));
667 
668  //---
669  // Note that this error mesage appears only if max count was reached while
670  // iterating. A linear (no iteration) solution would finish with iters =
671  // MAX_NUM_ITERATIONS + 1:
672  //---
673 #if 0 /* please leave for debug: */
674  if (iters >= MAX_NUM_ITERATIONS)
675  {
676  std::cout << "MAX ITERATION!!!" << std::endl;
677  std::cout << "delta_u = " << delta_u
678  << "\ndelta_v = " << delta_v << "\n";
679  }
680  else
681  {
682  std::cout << "ITERS === " << iters << std::endl;
683  }
684  std::cout << "iters = " << iters << "\n";
685 #endif
686 
687  //---
688  // The image point computed this way corresponds to full image space.
689  // Apply image offset in the case this is a sub-image rectangle:
690  //---
691  ip -= theSubImageOffset;
692 
693 } // End: worldToLineSample( ... )
694 
696 {
699  theHeightEnabledFlag = false;
700 
701  // NOTE: it is assumed that the grid size and spacing is the same for ALL grids:
702  ossimIpt gridSize (theLatGrid.size());
703  ossimDpt spacing (theLatGrid.spacing());
704  ossimDpt v[4];
705  v[0].lat = theLatGrid.getNode(0,0);
706  v[0].lon = theLonGrid.getNode(0,0);
707  v[1].lat = theLatGrid.getNode(gridSize.x-1, 0);
708  v[1].lon = theLonGrid.getNode(gridSize.x-1, 0);
709  v[2].lat = theLatGrid.getNode(gridSize.x-1, gridSize.y-1);
710  v[2].lon = theLonGrid.getNode(gridSize.x-1, gridSize.y-1);
711  v[3].lat = theLatGrid.getNode(0, gridSize.y-1);
712  v[3].lon = theLonGrid.getNode(0, gridSize.y-1);
713 
714  if ( m_crossesDateline )
715  {
716  // Longitude values between 0 and 360.
718  }
719 
720  // Guaranty longitude values are -180 to 180
721  for (int i=0; i<4; ++i)
722  {
723  if (v[i].lon > 180.0) v[i].lon -= 360.0;
724  }
725 
727 
728  if ( !m_crossesDateline )
729  {
730  // Longitude values between -180 and 180.
732  }
733 
734  theImageSize = ossimDpt(imageBounds.width(), imageBounds.height());
735  theRefImgPt = imageBounds.midPoint();
738 
739  ossimDpt ref_ip_dx (theRefImgPt.x+1.0, theRefImgPt.y );
740  ossimDpt ref_ip_dy (theRefImgPt.x , theRefImgPt.y+1.0);
741  ossimGpt ref_gp_dx (theLatGrid(ref_ip_dx), theLonGrid(ref_ip_dx));
742  ossimGpt ref_gp_dy (theLatGrid(ref_ip_dy), theLonGrid(ref_ip_dy));
743 
744  theGSD.x = theRefGndPt.distanceTo(ref_gp_dx);
745  theGSD.y = theRefGndPt.distanceTo(ref_gp_dy);
746 
747  theMeanGSD = (theGSD.line + theGSD.samp)/2.0;
748  theImageClipRect = imageBounds;
749 
750  // Image is clipped to valid rect so no sub image offset.
751  theSubImageOffset = ossimDpt(0.0, 0.0); //imageBounds.ul();
752 
754 
755  // debugDump();
756 
757 } // End: initializeModelParams
758 
759 
761 {
762  if (traceDebug())
763  {
765  << "DEBUG ossimH5GridModel::extrapolate: entering... " << std::endl;
766  }
767 
769  double height = 0.0;
770 
771  //---
772  // If ground point supplied has NaN components, return now with a NaN point.
773  //---
774  if ( (ossim::isnan(gpt.lat)) || (ossim::isnan(gpt.lon)) )
775  {
776  theExtrapolateGroundFlag = false;
777  if (traceDebug())
778  {
780  << "DEBUG ossimH5GridModel::extrapolate: returning..." << std::endl;
781  }
782  return ossimDpt(ossim::nan(), ossim::nan());
783  }
784 
785  if(ossim::isnan(gpt.hgt) == false)
786  {
787  height = gpt.hgt;
788  }
789 
790  if(theSeedFunction.valid())
791  {
792  ossimDpt ipt;
793 
795 
796  theExtrapolateGroundFlag = false;
797  return ipt;
798  }
799 
800  //---
801  // Determine which edge is intersected by the radial, and establish
802  // intersection:
803  //---
804  ossimDpt edgePt (gpt);
805  ossimDpt image_center (theRefGndPt);
806  if ( m_crossesDateline )
807  {
808  // Longitude points between 0 and 360.
809  if (edgePt.lon < 0.0 ) edgePt.lon += 360.0;
810  if ( image_center.lon < 0.0 ) image_center.lon += 360.0;
811  }
812 
813  m_boundGndPolygon.clipLineSegment(image_center, edgePt);
814 
815  //---
816  // Compute an epsilon perturbation in the direction away from edgePt for
817  // later computing directional derivative:
818  //---
819  const double DEG_PER_MTR = 8.983152841e-06; // Equator WGS-84...
820  double epsilon = theMeanGSD*DEG_PER_MTR; //degrees (latitude) per pixel
821  ossimDpt deltaPt (edgePt-image_center);
822  ossimDpt epsilonPt (deltaPt*epsilon/deltaPt.length());
823  edgePt -= epsilonPt;
824  ossimDpt edgePt_prime (edgePt - epsilonPt);
825 
826  //---
827  // Establish image point corresponding to edge point and edgePt+epsilon:
828  //---
829  ossimGpt edgeGP (edgePt.lat, edgePt.lon, height);//gpt.hgt);
830  ossimGpt edgeGP_prime (edgePt_prime.lat, edgePt_prime.lon, height);//gpt.hgt);
831  if ( m_crossesDateline )
832  {
833  // Put longitude back between -180 and 180.
834  edgeGP.limitLonTo180();
835  edgeGP_prime.limitLonTo180();
836  }
837 
838  worldToLineSample(edgeGP, edgePt);
839  worldToLineSample(edgeGP_prime, edgePt_prime);
840 
841  //---
842  // Compute approximate directional derivatives of line and sample along
843  // radial at the edge:
844  //---
845  double dsamp_drad = (edgePt.samp - edgePt_prime.samp)/epsilon;
846  double dline_drad = (edgePt.line - edgePt_prime.line)/epsilon;
847 
848  //---
849  // Now extrapolate to point of interest:
850  //---
851  double delta = (ossimDpt(gpt) - ossimDpt(edgeGP)).length();
852 
853 
854  ossimDpt extrapolated_ip (edgePt.samp + delta*dsamp_drad,
855  edgePt.line + delta*dline_drad);
856 
857  if (traceDebug())
858  {
860  << "DEBUG ossimH5GridModel::extrapolate: returning..." << std::endl;
861  }
862 
863  theExtrapolateGroundFlag = false;
864  return extrapolated_ip;
865 
866 } // ossimH5GridModel::extrapolate
867 
868 bool ossimH5GridModel::getWktFootprint( std::string& s ) const
869 {
870  bool status = true;
871 
872  // Loop until complete or a "nan" is hit.
873  while ( 1 )
874  {
875  ossim_float32 lat = 0.0;
876  ossim_float32 lon = 0.0;
877 
879 
880  os << setprecision(10) << "MULTIPOLYGON(((";
881  const ossim_int32 STEP = 128;
882 
883  ossimIrect rect( 0, 0, theImageSize.x-1, theImageSize.y-1 );
884 
885  ossim_int32 x = 0;
886  ossim_int32 y = 0;
887 
888  // Walk the top line:
889  while ( x < theImageSize.x )
890  {
891  lat = theLatGrid( x, y );
892  lon = theLonGrid( x, y );
893 
894  if ( ossim::isnan(lat) || ossim::isnan(lon) )
895  {
896  status = false;
897  break;
898  }
899 
900  os << lon << " " << lat << ",";
901 
902  if ( x != rect.ur().x )
903  {
904  x = ossim::min<ossim_int32>( x+STEP, rect.ur().x );
905  }
906  else
907  {
908  break; // End of top line walk.
909  }
910  }
911 
912  if ( !status ) break; // Found "nan" so get out.
913 
914  // Walk the right edge:
915  y = ossim::min<ossim_int32>( y+STEP, rect.lr().y );
916  while ( y < theImageSize.y )
917  {
918  lat = theLatGrid( x, y );
919  lon = theLonGrid( x, y );
920 
921  if ( ossim::isnan(lat) || ossim::isnan(lon) )
922  {
923  status = false;
924  break;
925  }
926 
927  os << lon << " " << lat << ",";
928 
929  if ( y != rect.lr().y )
930  {
931  y = ossim::min<ossim_int32>( y+STEP, rect.lr().y );
932  }
933  else
934  {
935  break;
936  }
937  }
938 
939  if ( !status ) break; // Found "nan" so get out.
940 
941  // Walk the bottom line from right to left:
942  x = ossim::max<ossim_int32>( rect.lr().x-STEP, 0 );
943  while ( x >= 0 )
944  {
945  lat = theLatGrid( x, y );
946  lon = theLonGrid( x, y );
947 
948  if ( ossim::isnan(lat) || ossim::isnan(lon) )
949  {
950  status = false;
951  break;
952  }
953 
954  os << lon << " " << lat << ",";
955 
956  if ( x != 0 )
957  {
958  x = ossim::max<ossim_int32>( x-STEP, 0 );
959  }
960  else
961  {
962  break;
963  }
964  }
965 
966  if ( !status ) break; // Found "nan" so get out.
967 
968  // Walk the left edge from bottom to top:
969  y = ossim::max<ossim_int32>( y-STEP, 0 );
970  while ( y >= 0 )
971  {
972  lat = theLatGrid( x, y );
973  lon = theLonGrid( x, y );
974 
975  if ( ossim::isnan(lat) || ossim::isnan(lon) )
976  {
977  status = false;
978  break;
979  }
980 
981  if ( ( x == 0 ) && ( y == 0 ) )
982  {
983  os << lon << " " << lat; // Last point:
984  }
985  else
986  {
987  os << lon << " " << lat << ",";
988  }
989 
990  if ( y != 0 )
991  {
992  y = ossim::max<ossim_int32>( y-STEP, 0 );
993  }
994  else
995  {
996  break;
997  }
998  }
999 
1000  if ( !status ) break; // Found "nan" so get out.
1001 
1002  os << ")))";
1003  s = os.str();
1004 
1005  // Trailing break from while ( FOREVER ) loop:
1006  break;
1007 
1008  } // Matches: while ( 1 )
1009 
1010  return status;
1011 }
1012 
1014 {
1015  ossimIpt step (theImageSize/200);
1016  int margin = 0;
1017  double lat, lon;
1018  ossimDpt pt (0,0);
1019  ofstream fslat ("lat_grid.dat");
1020  ofstream fslon ("lon_grid.dat");
1021  fslat<< setprecision(10) <<endl;
1022  fslon<< setprecision(10) <<endl;
1023  for (pt.v = -margin*step.v; pt.v < theImageSize.v+margin*step.v; pt.v += step.y)
1024  {
1025  for (pt.u = -margin*step.u; pt.u < theImageSize.u+margin*step.u ; pt.u += step.u)
1026  {
1027  lat = theLatGrid(pt.u, pt.v);
1028  lon = theLonGrid(pt.u, pt.v);
1029  fslat << pt.u << " " << pt.v << " " << lat << endl;
1030  fslon << pt.u << " " << pt.v << " " << lon << endl;
1031  }
1032  }
1033  fslat.close();
1034  fslon.close();
1035 }
ossim_uint32 x
virtual void worldToLineSample(const ossimGpt &world_point, ossimDpt &image_point) const
METHOD: extrapolate() Extrapolates solutions for points outside of the image.
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
saveState Saves state of object to a keyword list.
ossim_int32 v
Definition: ossimIpt.h:142
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
Represents serializable keyword/value map.
double u
Definition: ossimDpt.h:164
const std::string & findKey(const std::string &key) const
Find methods that take std::string(s).
bool isLonNan() const
Definition: ossimGpt.h:140
virtual ~ossimH5GridModel()
virtual destructor
ossim_uint32 y
bool valid() const
Definition: ossimRefPtr.h:75
double samp
Definition: ossimDpt.h:164
float ossim_float32
bool almostEqual(T x, T y, T tolerance=FLT_EPSILON)
Definition: ossimCommon.h:53
double nan()
Method to return ieee floating point double precision NAN.
Definition: ossimCommon.h:135
const ossimIpt & size() const
Definition: ossimDblGrid.h:187
double y
Definition: ossimDpt.h:165
ossim_uint32 height() const
Definition: ossimIrect.h:487
static ossimString toString(bool aValue)
Numeric to string methods.
void setDomainType(DomainType dt)
Definition: ossimDblGrid.h:156
#define STEP(bseg)
Definition: polygrf.h:238
ossimScalarType getScalarType(const H5::DataSet *dataset)
void setNullValue(double value)
Definition: ossimDblGrid.h:183
const ossimIpt & ul() const
Definition: ossimIrect.h:274
void initialize(const ossimIpt &size, const ossimDpt &origin, const ossimDpt &spacing, double null_value=OSSIM_DEFAULT_NULL_PIX_DOUBLE)
void addPair(const std::string &key, const std::string &value, bool overwrite=true)
OSSIM_DLL ossimByteOrder byteOrder()
Definition: ossimCommon.cpp:54
ossim_float64 hgt
Height in meters above the ellipsiod.
Definition: ossimGpt.h:274
ossim_int32 u
Definition: ossimIpt.h:141
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Fulfills ossimObject base-class pure virtuals.
32 bit floating point
bool clipLineSegment(ossimDpt &p1, ossimDpt &p2) const
METHOD: clipLineSegment(p1, p2) Implements Cyrus-Beck clipping algorithm as described in: http://www...
bool isLatNan() const
Definition: ossimGpt.h:139
double distanceTo(const ossimGpt &arg_gpt) const
METHOD: distanceTo(ossimGpt) Computes straight-line distance in meters between this and arg gpt: ...
Definition: ossimGpt.cpp:431
virtual ossimGpt extrapolate(const ossimDpt &imgPt, const double &height=ossim::nan()) const
Implements its own extrapolation since this can be handled by ossimDblGrid.
double length() const
Definition: ossimDpt.h:81
void enableExtrapolation(bool arg=true)
Definition: ossimDblGrid.h:91
void limitLonTo180()
METHOD: limitLonTo180() Converts the lon data member to a value between -180 and +180: ...
Definition: ossimGpt.h:219
bool setGridNodes(H5::DataSet *latDataSet, H5::DataSet *lonDataSet, const ossimIrect &validRect)
Initializes the latitude and longitude ossimDblGrids from file.
void initializeModelParams(ossimIrect imageBounds)
Initializes base class data members after grids have been assigned.
double ossim_float64
ossimDpt theSubImageOffset
double line
Definition: ossimDpt.h:165
double lat
Definition: ossimDpt.h:165
ossim_float64 lon
Definition: ossimGpt.h:266
bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
ossimIpt midPoint() const
Definition: ossimIrect.h:750
bool toBool() const
String to numeric methods.
bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
unsigned int ossim_uint32
ossimPolygon theBoundGndPolygon
bool hasNans() const
will sequence through the polygon and check to see if any values are NAN
ossimH5GridModel()
default constructor.
double getNode(const ossimIpt &p) const
Definition: ossimDblGrid.h:111
const ossimIpt & lr() const
Definition: ossimIrect.h:276
#define DBL_EPSILON
ossim_uint32 width() const
Definition: ossimIrect.h:500
bool pointWithin(const ossimDpt &point) const
METHOD: pointWithin(ossimDpt) Returns TRUE if point is inside polygon.
double lon
Definition: ossimDpt.h:164
ossimByteOrder getByteOrder(const H5::AbstractDs *dataset)
const ossimIpt & ur() const
Definition: ossimIrect.h:275
ossimScalarType
ossimRefPtr< ossimProjection > theSeedFunction
Used as an initial guess for iterative solutions and a guess for points outside the support bounds...
static ossimProjectionFactoryRegistry * instance()
return status
ossim_uint32 getNumberOfVertices() const
ossimDrect theImageClipRect
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Fulfills ossimObject base-class pure virtuals.
ossimRefPtr< ossimProjection > getBilinearProjection(H5::DataSet &latDataSet, H5::DataSet &lonDataSet, const ossimIrect &validRect)
Gets bilinear projection from Latitude, Longitude layer.
ossim_int32 y
Definition: ossimIpt.h:142
ossimPolygon m_boundGndPolygon
virtual ossimDpt extrapolate(const ossimGpt &gp) const
extrapolate() Extrapolates solutions for points outside of the image.
bool getWktFootprint(std::string &s) const
double x
Definition: ossimDpt.h:164
const char * c_str() const
Returns a pointer to a null-terminated array of characters representing the string&#39;s contents...
Definition: ossimString.h:396
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
ossim_int32 x
Definition: ossimIpt.h:141
ossim_float64 lat
Definition: ossimGpt.h:265
std::basic_ofstream< char > ofstream
Class for char output file streams.
Definition: ossimIosFwd.h:47
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
loadState Loads state of object from a keyword list.
virtual void worldToLineSample(const ossimGpt &worldPoint, ossimDpt &lineSampPt) const =0
bool crossesDateline(H5::DataSet &dataset, const ossimIrect &validRect)
Checks for dateline cross.
void swap(ossim_sint8 &)
Definition: ossimEndian.h:26
void setNode(const ossimIpt &p, const double &value)
Definition: ossimDblGrid.h:107
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
virtual void lineSampleHeightToWorld(const ossimDpt &image_point, const double &heightEllipsoid, ossimGpt &world_pt) const
This is the virtual that performs the actual work of projecting the image point to the earth at some ...
void makeNan()
Definition: ossimDpt.h:65
ossim_float64 theMeanGSD
double v
Definition: ossimDpt.h:165
RTTI_DEF1(ossimH5GridModel, "ossimH5GridModel", ossimCoarseGridModel)
int ossim_int32
const std::string & string() const
Definition: ossimString.h:414
const ossimDpt & spacing() const
Definition: ossimDblGrid.h:189
bool isnan(const float &v)
isnan Test for floating point Not A Number (NAN) value.
Definition: ossimCommon.h:91