OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimHdf5GridModel.cpp
Go to the documentation of this file.
1 //*****************************************************************************
2 // FILE: ossimHdf5GridModel.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 ossimHdf5GridModel. 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 
22 #include <ossim/hdf5/ossimHdf5.h>
23 #include <ossim/base/ossimCommon.h>
24 #include <ossim/base/ossimEndian.h>
26 #include <ossim/base/ossimNotify.h>
27 #include <ossim/base/ossimTrace.h>
28 #include <ossim/base/ossimIpt.h>
29 #include <ossim/base/ossimIrect.h>
30 #include <ossim/base/ossimDrect.h>
33 #include <sstream>
34 #include <string>
35 
36 using namespace std;
37 using namespace H5;
38 
39 static const int GRID_SAMPLING_INTERVAL = 32;
40 
41 RTTI_DEF1(ossimHdf5GridModel, "ossimHdf5GridModel", ossimCoarseGridModel);
42 
43 
46 {
48 }
49 
51 {
52 }
53 
54 bool ossimHdf5GridModel::initialize(ossimHdf5* hdf5, const ossimString& projDataPath)
55 {
56  if (!hdf5)
57  return false;
58 
59  m_hdf5 = hdf5;
60  m_projDataPath = projDataPath;
61  theHeightEnabledFlag = false;
62 
63  try
64  {
65  initCoarseGrid("Latitude", theLatGrid);
66  initCoarseGrid("Longitude", theLonGrid);
67  }
68  catch (ossimException& x)
69  {
71  return false;
72  }
73 
76 
77  // Check for dateline crossing among the longitude grid:
79 
84  ossimDrect imageRect(0, 0, m_imageSize.x-1, m_imageSize.y-1);
85  theSeedFunction = new ossimBilinearProjection(imageRect.ul(), imageRect.ur(),
86  imageRect.lr(), imageRect.ll(),
87  ulg, urg, lrg, llg);
88 
89  // Bileaner projection to handle
90  initializeModelParams(imageRect);
91 
92  ossimIrect bounds (0, 0, theImageSize.u-1, theImageSize.v-1);
93  initializeModelParams(bounds);
94 
95  return true;
96 }
97 
98 bool ossimHdf5GridModel::initCoarseGrid(const char* datasetName, ossimDblGrid& coarseGrid)
99 {
100  ostringstream xmsg;
101 
102  // Convention used: (u,v) is file space, (x,y) is CG space
103  Group* group = m_hdf5->findGroupByName(m_projDataPath.chars(), 0, true);
104  DataSet* dataset = m_hdf5->findDatasetByName(datasetName, group, true);
105  if (dataset == NULL)
106  {
107  xmsg << "ossimHdf5GridModel:"<<__LINE__
108  <<" ERROR: Could not find dataset \""<<datasetName<<"\" in file.";
109  throw ossimException(xmsg.str());
110  }
111 
112  // Get dataspace of the dataset.
113  DataSpace dataSpace = dataset->getSpace();
114  const ossim_int32 DIM_COUNT = dataSpace.getSimpleExtentNdims();
115  if ( DIM_COUNT != 2 )
116  return false;
117 
118  // Get the extents. dimsOut[0] is height, dimsOut[1] is width:
119  std::vector<hsize_t> dimsOut(DIM_COUNT);
120  dataSpace.getSimpleExtentDims( &dimsOut.front(), 0 );
121  m_imageSize.y = dimsOut[0];
122  m_imageSize.x = dimsOut[1];
123 
124  // Initialize the ossimDblGrid. Round up if size doesn't fall on end pixel.
125  ossimDpt dspacing (GRID_SAMPLING_INTERVAL, GRID_SAMPLING_INTERVAL);
126  ossim_uint32 gridRows = m_imageSize.y / GRID_SAMPLING_INTERVAL + 1;
127  ossim_uint32 gridCols = m_imageSize.x / GRID_SAMPLING_INTERVAL + 1;
128  if ( m_imageSize.y % GRID_SAMPLING_INTERVAL)
129  ++gridRows;
130  if ( m_imageSize.x % GRID_SAMPLING_INTERVAL)
131  ++gridCols;
132  ossimIpt gridSize (gridCols, gridRows);
133 
134  // The grid as used in base class, has UV-space always at 0,0 origin
135  ossimDpt gridOrigin(0.0,0.0);
136  coarseGrid.setNullValue(ossim::nan());
137  coarseGrid.initialize(gridSize, gridOrigin, dspacing);
138 
139  std::vector<hsize_t> inputCount(DIM_COUNT);
140  std::vector<hsize_t> inputOffset(DIM_COUNT);
141 
142  inputOffset[0] = 0; // y_img is set below.
143  inputOffset[1] = 0;
144  inputCount[0] = 1; // y_img
145  inputCount[1] = (hsize_t)m_imageSize.x; // x_img
146 
147  // Output dataspace dimensions. Reading a line at a time.
148  const ossim_int32 OUT_DIM_COUNT = 3;
149  std::vector<hsize_t> outputCount(OUT_DIM_COUNT);
150  outputCount[0] = 1; // band
151  outputCount[1] = 1; // y_img
152  outputCount[2] = m_imageSize.x; // x_img
153 
154  // Output dataspace offset.
155  std::vector<hsize_t> outputOffset(OUT_DIM_COUNT);
156  outputOffset[0] = 0;
157  outputOffset[1] = 0;
158  outputOffset[2] = 0;
159 
160  ossimScalarType scalar = m_hdf5->getScalarType( *dataset);
161  if ( scalar != OSSIM_FLOAT32 )
162  return false;
163 
164  // See if we need to swap bytes:
165  ossimEndian endian;
166  bool needSwap = false;
167  if (m_hdf5->getByteOrder(dataset) != ossim::byteOrder())
168  needSwap = true;
169  DataType dataType = dataset->getDataType();
170 
171  // Output dataspace always the same, width of one line.
172  DataSpace bufferDataSpace( OUT_DIM_COUNT, &outputCount.front());
173  bufferDataSpace.selectHyperslab( H5S_SELECT_SET,
174  &outputCount.front(),
175  &outputOffset.front() );
176 
177  // Arrays to hold a single line of latitude longitude values.
178  vector<ossim_float32> values(m_imageSize.x);
179  ossim_float32 val = 0;
180  hsize_t y_img = 0;
181 
182  // Line loop:
183  for ( ossim_uint32 y = 0; y < gridRows; ++y )
184  {
185  // y_img = line in image space
186  y_img = y*GRID_SAMPLING_INTERVAL;
187  if ( y_img < (ossim_uint32) m_imageSize.y )
188  {
189  inputOffset[0] = y_img;
190  dataSpace.selectHyperslab( H5S_SELECT_SET, &inputCount.front(), &inputOffset.front() );
191 
192  // Read data from file into the buffer.
193  dataset->read( &(values.front()), dataType, bufferDataSpace, dataSpace );
194  if ( needSwap )
195  endian.swap( &(values.front()), m_imageSize.x );
196 
197  // Sample loop:
198  hsize_t x_img = 0;
199  for ( ossim_uint32 x = 0; x < gridCols; ++x )
200  {
201  // x_img = sample in image space
202  x_img = x*GRID_SAMPLING_INTERVAL;
203  if ( x_img < (ossim_uint32) m_imageSize.x )
204  {
205  val = values[x_img];
206  if (ossim::isnan(val)) // Nulls in grid!
207  {
208  xmsg << "ossimHdf5GridModel:"<<__LINE__<<" encountered nans!";
209  throw ossimException(xmsg.str());
210  }
211  }
212  else // Last column is outside of image bounds.
213  {
214  // Delta between last two latitude grid values.
215  ossim_float32 val1 = coarseGrid.getNode( x-2, y );
216  ossim_float32 val2 = coarseGrid.getNode( x-1, y );
217  ossim_float32 spacing = val2 - val1;
218  val = val2 + spacing;
219 
220 #if 0 /* Please leave for debug. (drb) */
221  cout << "val1: " << val1 << " val2 " << val2<<endl;;
222 #endif
223  }
224 
225  coarseGrid.setNode( x, y, val );
226 
227 #if 0 /* Please leave for debug. (drb) */
228  cout << "x,y,x_img,y_img,val:" << x << "," << y << ","<< x_img << "," << y_img << ","
229  << coarseGrid.getNode(x, y) << endl;
230 #endif
231  } // End sample loop.
232  }
233  else // Row is outside of image bounds:
234  {
235  // Sample loop:
236  for ( ossim_uint32 x = 0; x < gridCols; ++x )
237  {
238  ossim_float32 val = ossim::nan();
239  ossim_float32 val1 = coarseGrid.getNode( x, y-2 );
240  ossim_float32 val2 = coarseGrid.getNode( x, y-1 );
241  ossim_float32 spacing = val2 - val1;
242  val = val2 + spacing;
243  coarseGrid.setNode( x, y, val );
244 
245 #if 0 /* Please leave for debug. (drb) */
246  hsize_t x_img = x*GRID_SPACING; // Sample in image space
247  cout << "val1: " << val1 << " val2 " << val2
248  << "\nx,y,x_img,y_img,val:" << x << "," << y << ","
249  << x_img << "," << y_img << "," << val << endl;
250 #endif
251  } // End sample loop.
252  } // Matches if ( y_img < m_imageSize.y ){...}else{
253  } // End line loop.
254 
255  dataSpace.close();
256 
257  return true;
258 
259 #if 0
260  // Original refactor code ###############################################
261 
262  // Verify dimensions:
263  DataSpace dataSpace = dataset->getSpace();
264  if (dataSpace.getSimpleExtentNdims() != 2)
265  {
266  xmsg << "ossimHdf5GridModel:"<<__LINE__<<" ERROR: lat/lon grid dataspace rank != 2.";
267  throw ossimException(xmsg.str());
268  }
269 
270  // Fetch size of grid in file. Extents are assumed to be the same for both lat and lon grids:
271  hsize_t datExtents[2];
272  dataSpace.getSimpleExtentDims(datExtents);
273  if ((datExtents[0] < 2) || (datExtents[1] < 2))
274  {
275  xmsg << "ossimHdf5GridModel:"<<__LINE__<<" ERROR: lat/lon grid size is < 2.";
276  throw ossimException(xmsg.str());
277  }
278 
279  // Initialize the base class coarse grids:
280  theImageSize = ossimDpt(datExtents[0], datExtents[1]);
281  ossimDrect uvRect(0, 0, theImageSize.u-1, theImageSize.v-1);
282  ossimDpt cgSpacing(GRID_SAMPLING_INTERVAL, GRID_SAMPLING_INTERVAL);
283  coarseGrid.initialize(uvRect, cgSpacing, ossim::nan());
284 
285  // Declare data of interest in file (the whole thing):
286  hsize_t offset[2] = { 0, 0 };
287  dataSpace.selectHyperslab( H5S_SELECT_SET, datExtents, offset );
288 
289  // Initialize dataspace for memory buffer needed by dataset read operation:
290  hsize_t bufExtents[2] = { (hsize_t) theImageSize.u, 1 };
291  DataSpace bufSpace(2, bufExtents);
292  DataType dataType = dataset->getDataType();
293  string cname = dataType.fromClass();
294  cout << cname<<endl;
295  if (dataType.getClass() != H5T_FLOAT)
296  {
297  xmsg << "ossimHdf5GridModel:"<<__LINE__<<" ERROR: lat/lon grid datatype must be float.";
298  throw ossimException(xmsg.str());
299  }
300  ossim_float32* buffer = new ossim_float32 [bufExtents[0]]; // assumes float datatype
301 
302  // See if we need to swap bytes:
303  ossimEndian* endian = 0;
304  AtomType* atomType = dynamic_cast<AtomType*>(&dataType);
305  if(atomType)
306  {
308  H5T_order_t h5order = atomType->getOrder();
309  if( ((h5order == H5T_ORDER_LE) && (ossimByteOrder != OSSIM_LITTLE_ENDIAN)) ||
310  ((h5order == H5T_ORDER_BE) && (ossimByteOrder != OSSIM_BIG_ENDIAN)))
311  endian = new ossimEndian();
312  }
313 
314  // Loop over input grid rows, sampling according to desired interval to fill output
315  // coarse grid, for latitude:
316  ossimIpt cgGridSize (coarseGrid.size());
317  ossim_uint32 x=0, y=0, u=0, v=0;
318  for ( ; (y<cgGridSize.y) && (v<theImageSize.v); ++y, v+=GRID_SAMPLING_INTERVAL )
319  {
320  offset[1] = v; // offset[0] always = 0
321  dataSpace.selectHyperslab( H5S_SELECT_SET, bufExtents, offset);
322  dataset->read( buffer, dataType, bufSpace, dataSpace );
323  if ( endian )
324  endian->swap( buffer, bufExtents[0] );
325 
326  // Need to subsample the input row and save into coarse grid:
327  for ( x=0, u=0; (x<cgGridSize.x)&&(u<theImageSize.u); ++x, u+=GRID_SAMPLING_INTERVAL)
328  {
329  { // TODO REMOVE DEBUG BLOCK
330  cout<<datasetName<<" ("<<x<<", "<<y<<"): "<<buffer[u]<<endl;
331  }
332 
333  if ( ossim::isnan(buffer[u]))
334  {
335  xmsg << "ossimHdf5GridModel:"<<__LINE__<<" ERROR: encountered nans in lat/lon grid.";
336  throw ossimException(xmsg.str());
337  }
338  coarseGrid.setNode( x, y, buffer[u] );
339  }
340 
341  // Check if last column is outside of image bounds.
342  if (x < cgGridSize.x)
343  coarseGrid.setNode( x, y, coarseGrid.getNode( x-1, y ) );
344  }
345 
346  // Check if last row is outside of image bounds.
347  if (y < cgGridSize.y)
348  {
349  for ( x=0; x<cgGridSize.x; ++x)
350  coarseGrid.setNode( x, y, coarseGrid.getNode( x, y-1 ) );
351  }
352 
353  delete dataset;
354  delete buffer;
355  delete endian;
356 
357  return true;
358 #endif
359 }
360 
361 
363 {
364  bool crossesDateline = false;
365 
366  ossim_int32 longitude = 0;
367  bool found179 = false;
368  bool found181 = false;
369 
371  //double left, right;
372  //int xr = size.x-1;
373 
374  for (ossim_uint32 y=0; (y<(ossim_uint32)size.y) && !crossesDateline; ++y )
375  {
376 #if 0
377  left = theLonGrid.getNode(0, y);
378  right = theLonGrid.getNode(xr, y);
379  if (left > right)
380  crossesDateline = true;
381 #endif
382 
383  for ( ossim_uint32 x = 0; x<(ossim_uint32)size.x; ++x)
384  {
385  longitude = (ossim_int32) theLonGrid.getNode(x, y); // Cast to integer.
386 
387  // look for 179 -> -179...
388  if ( !found179 )
389  {
390  if ( longitude == 179 )
391  {
392  found179 = true;
393  continue;
394  }
395  }
396  else // found179 == true
397  {
398  if ( longitude == 178 )
399  {
400  break; // Going West, 179 -> 178
401  }
402  else if ( longitude == -179 )
403  {
404  crossesDateline = true;
405  break;
406  }
407  }
408 
409  // look for -179 -> 179...
410  if ( !found181 )
411  {
412  if ( longitude == -179 )
413  {
414  found181 = true;
415  continue;
416  }
417  }
418  else // found181 == true
419  {
420  if ( longitude == -178 )
421  {
422  break; // Going East -179 -> -178
423  }
424  else if ( longitude == 179 )
425  {
426  crossesDateline = true;
427  break;
428  }
429  }
430  }
431  }
432 
433  if ( crossesDateline )
435  else
437 
438  return crossesDateline;
439 }
440 
441 
442 bool ossimHdf5GridModel::saveState(ossimKeywordlist& kwl, const char* prefix) const
443 {
444  bool stat = ossimCoarseGridModel::saveState(kwl, prefix);
445  kwl.add(prefix, ossimKeywordNames::TYPE_KW, "ossimCoarseGridModel", true);
446 
447  return stat;
448 }
449 
ossim_uint32 x
ossim_int32 v
Definition: ossimIpt.h:142
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
RTTI_DEF1(ossimHdf5GridModel, "ossimHdf5GridModel", ossimCoarseGridModel)
Represents serializable keyword/value map.
ossim_uint32 y
float ossim_float32
double nan()
Method to return ieee floating point double precision NAN.
Definition: ossimCommon.h:135
const ossimIpt & size() const
Definition: ossimDblGrid.h:187
void setDomainType(DomainType dt)
Definition: ossimDblGrid.h:156
void setNullValue(double value)
Definition: ossimDblGrid.h:183
void initialize(const ossimIpt &size, const ossimDpt &origin, const ossimDpt &spacing, double null_value=OSSIM_DEFAULT_NULL_PIX_DOUBLE)
OSSIM_DLL ossimByteOrder byteOrder()
Definition: ossimCommon.cpp:54
ossim_int32 u
Definition: ossimIpt.h:141
double maxValue() const
Definition: ossimDblGrid.h:176
ossimString m_projDataPath
32 bit floating point
static const char * TYPE_KW
bool initialize(ossimHdf5 *hdf5, const ossimString &projDataPath="")
Initializes from an open HDF5 file.
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
static ossimByteOrder getByteOrder(const H5::AbstractDs *obj)
Definition: ossimHdf5.cpp:337
static ossimScalarType getScalarType(const H5::DataSet &dataset)
Definition: ossimHdf5.cpp:475
yy_size_t size
H5::Group * findGroupByName(const std::string &group_name, const H5::Group *parent_group=0, bool recursive=false) const
Finds a group by name.
Definition: ossimHdf5.cpp:251
double minValue() const
Definition: ossimDblGrid.h:175
unsigned int ossim_uint32
const char * chars() const
For backward compatibility.
Definition: ossimString.h:77
double getNode(const ossimIpt &p) const
Definition: ossimDblGrid.h:111
ossimByteOrder
ossimScalarType
ossimRefPtr< ossimProjection > theSeedFunction
Used as an initial guess for iterative solutions and a guess for points outside the support bounds...
Low-level OSSIM interface to HDF5 libraries.
Definition: ossimHdf5.h:27
bool initCoarseGrid(const char *datasetName, ossimDblGrid &coarseGrid)
H5::DataSet * findDatasetByName(const std::string &dataset_name, const H5::Group *group=0, bool recursive=false) const
Finds a dataset by name.
Definition: ossimHdf5.cpp:295
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Fulfills ossimObject base-class pure virtuals.
const ossimDpt & origin() const
Definition: ossimDblGrid.h:188
ossim_int32 y
Definition: ossimIpt.h:142
virtual ~ossimHdf5GridModel()
virtual destructor
void initializeModelParams(ossimIrect irect)
Initializes base class data members after grids have been assigned.
ossim_int32 x
Definition: ossimIpt.h:141
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix) const
Makes sure that the "type" keyword entry reflects the base class, not this one.
ossimRefPtr< ossimHdf5 > m_hdf5
void swap(ossim_sint8 &)
Definition: ossimEndian.h:26
ossimHdf5GridModel()
default constructor.
void setNode(const ossimIpt &p, const double &value)
Definition: ossimDblGrid.h:107
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
int ossim_int32
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