OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimDtedHandler.cpp
Go to the documentation of this file.
1 //*****************************************************************************
2 // FILE: ossimDtedHandler.cc
3 //
4 // License: See top level LICENSE.txt file.
5 //
6 // DESCRIPTION:
7 // Contains implementation of class ossimDtedHandler. This class derives from
8 // ossimElevHandler. It is responsible for loading an individual DTED cell
9 // from disk. This elevation files are memory mapped.
10 //
11 //*****************************************************************************
12 // $Id: ossimDtedHandler.cpp 21214 2012-07-03 16:20:11Z dburken $
13 
14 #include <cstdlib>
15 #include <cstring> /* for memcpy */
17 #include <ossim/base/ossimCommon.h>
20 #include <ossim/base/ossimNotify.h>
21 #include <ossim/base/ossimGpt.h>
23 
24 RTTI_DEF1(ossimDtedHandler, "ossimDtedHandler" , ossimElevCellHandler)
25 
26 //***
27 // Define Trace flags for use within this file:
28 //***
29 #include <ossim/base/ossimTrace.h>
30 static ossimTrace traceExec ("ossimDtedHandler:exec");
31 static ossimTrace traceDebug ("ossimDtedHandler:debug");
32 
33 static const char ENABLE_STATS_KW[] = "elevation.compute_statistics.enabled";
34 
35 
36 ossimDtedHandler::ossimDtedHandler(const ossimFilename& dted_file, bool memoryMapFlag)
37  :
38  ossimElevCellHandler(dted_file),
39  m_fileStr(),
40  m_numLonLines(0),
41  m_numLatPoints(0),
42  m_dtedRecordSizeInBytes(0),
43  m_edition(),
44  m_productLevel(),
45  m_compilationDate(),
46  m_offsetToFirstDataRecord(0),
47  m_latSpacing(0.0),
48  m_lonSpacing(0.0),
49  m_swCornerPost(),
50  m_swapBytesFlag(false)
51 {
52 
53  static const char MODULE[] = "ossimDtedHandler (Filename) Constructor";
54  if (traceExec())
55  {
57  << "DEBUG " << MODULE <<": entering..." << std::endl;
58  }
59 
61  //---
62  // Open the dted file for reading.
63  //---
64  if (!open(dted_file, memoryMapFlag))
65  {
67 
68  if (traceDebug())
69  {
71  << "FATAL " << MODULE << ": "
72  << "\nCould not open file: " << dted_file.c_str()
73  << "\nReturning..." << std::endl;
75  << "DEBUG " << MODULE << ": returning with error..." << std::endl;
76  }
77  return;
78  }
79  else
80  {
81  if (traceDebug())
82  {
84  << "DEBUG " << MODULE <<": Loading dted file: " << dted_file
85  << std::endl;
86  }
87  }
88 
89  // DTED is stored in big endian.
90  if (traceExec())
91  {
93  << "DEBUG " << MODULE << ": returning..." << std::endl;
94  }
95 }
96 
98 {
99  close();
100 }
101 
103  const ossimGpt& /* gpt */ ) const
104 {
105  info.m_confidenceLevel = .9;
106  info.m_absoluteLE = m_acc->absLE();
107  info.m_absoluteCE = m_acc->absCE();
108  info.m_relativeLE = m_acc->relLE();
109  info.m_relativeCE = m_acc->relCE();
110 
111  info.m_surfaceName = m_dsi->productLevel();
112 
113  return info.hasValidAbsoluteError();
114 }
115 
117 {
118  if(m_memoryMap.size())
119  {
120  return getHeightAboveMSL(gpt, false);
121  }
122  else if((m_fileStr)&&(m_fileStr->good()))
123  {
124  return getHeightAboveMSL(gpt, true);
125  }
126 
127  return ossim::nan();
128 }
129 
130 bool ossimDtedHandler::open(const ossimFilename& file, bool memoryMapFlag)
131 {
132  std::string connectionString = file.c_str();
133  std::shared_ptr<ossim::istream> str = ossim::StreamFactoryRegistry::instance()->
134  createIstream( file.c_str(), std::ios_base::in|std::ios_base::binary);
135  if(!str) return false;
136  return open(str, connectionString, memoryMapFlag);
137 }
138 
139 bool ossimDtedHandler::open(std::shared_ptr<ossim::istream>& fileStr,
140  const std::string& connectionString,
141  bool memoryMapFlag)
142 {
143  static const char* MODULE = "ossimDtedHandler::open";
144  close();
145  if(!fileStr) return false;
146 
147  m_vol = std::make_shared<ossimDtedVol>();
148  m_hdr = std::make_shared<ossimDtedHdr>();
149  m_uhl = std::make_shared<ossimDtedUhl>();
150  m_dsi = std::make_shared<ossimDtedDsi>();
151  m_acc = std::make_shared<ossimDtedAcc>();
152 
153  m_connectionString = connectionString;
154 
155  m_fileStr = fileStr;
156  m_fileStr->clear();
157 
158  m_numLonLines = 0;
159  m_numLatPoints = 0;
161 
162  // Attempt to parse.
163  m_vol->parse(*m_fileStr);
164  m_hdr->parse(*m_fileStr);
165  m_uhl->parse(*m_fileStr);
166  m_dsi->parse(*m_fileStr);
167  m_acc->parse(*m_fileStr);
168 
169  //***
170  // Check for errors. Must have uhl, dsi and acc records. vol and hdr
171  // are for magnetic tape only; hence, may or may not be there.
172  //***
173  if (m_uhl->getErrorStatus() == ossimErrorCodes::OSSIM_ERROR ||
174  m_dsi->getErrorStatus() == ossimErrorCodes::OSSIM_ERROR ||
175  m_acc->getErrorStatus() == ossimErrorCodes::OSSIM_ERROR)
176  {
177  if (traceDebug())
178  {
180  << "DEBUG " << MODULE << ": "
181  << "\nError parsing file: " << m_connectionString
182  << "\nPossibly not a dted file."
183  << std::endl;
184  }
185 
187  close();
188  return false;
189  }
190  if(memoryMapFlag)
191  {
192  ossim_int64 streamSize;
193  m_fileStr->clear();
194  m_fileStr->seekg(0, std::ios::end);
195  streamSize = m_fileStr->tellg();
196  m_fileStr->seekg(0, std::ios::beg);
197 
198  m_memoryMap.resize(streamSize);//theFilename.fileSize());
199  m_fileStr->read((char*)(&m_memoryMap.front()), (std::streamsize)m_memoryMap.size());
200  m_fileStr.reset();
201  }
202 
203  m_numLonLines = m_uhl->numLonLines();
204  m_numLatPoints = m_uhl->numLatPoints();
205  m_latSpacing = m_uhl->latInterval();
206  m_lonSpacing = m_uhl->lonInterval();
208 
209  m_edition = m_dsi->edition();
210  m_productLevel = m_dsi->productLevel();
211  m_compilationDate = m_dsi->compilationDate();
212 
213  m_offsetToFirstDataRecord = m_acc->stopOffset();
214 
215  #if 0 /* Serious debug only... */
216  std::cout << m_numLonLines
217  << "\t" << m_numLatPoints
218  << "\t" << m_lonSpacing
219  << "\t" << m_latSpacing
220  << "\t" << m_dtedRecordSizeInBytes
221  << "\t" << theFilename.fileSize()
222  << "\t" << file
223  << "\t" << m_offsetToFirstDataRecord
224  << std::endl;
225  #endif
226 
227  //***
228  // initialize the bounding rectangle:
229  //***
230  double south_boundary = m_uhl->latOrigin();
231  double west_boundary = m_uhl->lonOrigin();
232  double north_boundary = south_boundary + m_latSpacing*(m_numLatPoints-1);
233  double east_boundary = west_boundary + m_lonSpacing*(m_numLonLines-1);
234 
235  // For ossimElevCellHandler::pointHasCoverage method.
236  theGroundRect = ossimGrect(ossimGpt(north_boundary, west_boundary, 0.0),
237  ossimGpt(south_boundary, east_boundary, 0.0));
238 
239  m_swCornerPost.lat = south_boundary;
240  m_swCornerPost.lon = west_boundary;
241 
242  //***
243  // Determine the mean spacing:
244  //***
245  double center_lat = (south_boundary + north_boundary)/2.0;
247  * ossimGpt().metersPerDegree().x / 2.0;
248 
249  // Initialize the accuracy values:
250  theAbsLE90 = m_acc->absLE();
251  theAbsCE90 = m_acc->absCE();
252 
253  // Set the base class null height value.
254  theNullHeightValue = -32767.0;
255 
256  //---
257  // Commented out as this writes an un-needed file. (drb 20100611)
258  // Get the statistics.
259  // gatherStatistics();
260  //---
261 
262  return true;
263 
264 }
265 
266 double ossimDtedHandler::getHeightAboveMSL(const ossimGpt& gpt, bool readFromFile)
267 {
268  // Establish the grid indexes:
269  double xi = (gpt.lon - m_swCornerPost.lon) / m_lonSpacing;
270  double yi = (gpt.lat - m_swCornerPost.lat) / m_latSpacing;
271 
272  // Check for right edge.
273  int x0 = static_cast<int>(xi);
274  int y0 = static_cast<int>(yi);
275 
276  if(x0 == (m_numLonLines-1))
277  {
278  --x0; // Move over one post.
279  }
280 
281  // Check for top edge.
282  // if (gpt.lat == theGroundRect.ul().lat)
283  if(y0 == (m_numLatPoints-1))
284  {
285  --y0; // Move down one post.
286  }
287 
288  // Do some error checking.
289  if ( xi < 0.0 || yi < 0.0 ||
290  x0 > (m_numLonLines - 2.0) ||
291  y0 > (m_numLatPoints - 2.0) )
292  {
293  return ossim::nan();
294  }
295 
296  //***
297  // Grab the four points from the dted cell needed. These are big endian,
298  // signed magnitude shorts so they must be interpreted accordingly.
299  //***
302 
304  DtedHeight postData;
305  //
306  if ( readFromFile )
307  {
308  readPostsFromFile( postData, offset );
309  }
310  else
311  {
312  ossim_uint8* buf = &m_memoryMap.front();
313  {
314  ossim_uint16 us;
315 
316  memcpy(&us, buf+offset, POST_SIZE);
317  postData.m_posts[0].m_height = convertSignedMagnitude(us);
318  postData.m_posts[0].m_status = true;
319  memcpy(&us, buf+offset+POST_SIZE, POST_SIZE);
320  postData.m_posts[1].m_height = convertSignedMagnitude(us);
321  postData.m_posts[1].m_status = true;
322 
323  // Move over to the next column.
324  offset += m_dtedRecordSizeInBytes;
325  memcpy(&us, buf+offset, POST_SIZE);
326  postData.m_posts[2].m_height = convertSignedMagnitude(us);
327  postData.m_posts[2].m_status = true;
328  memcpy(&us, buf+offset+POST_SIZE, POST_SIZE);
329  postData.m_posts[3].m_height = convertSignedMagnitude(us);
330  postData.m_posts[3].m_status = true;
331  }
332  }
333  // Perform bilinear interpolation:
334  double wx1 = xi - x0;
335  double wy1 = yi - y0;
336  double wx0 = 1.0 - wx1;
337  double wy0 = 1.0 - wy1;
338 
339  postData.m_posts[0].m_weight = wx0*wy0;
340  postData.m_posts[1].m_weight = wx0*wy1;
341  postData.m_posts[2].m_weight = wx1*wy0;
342  postData.m_posts[3].m_weight = wx1*wy1;
343 
344 #if 0 /* Serious debug only... */
345  postData.debug();
346 #endif
347 
348  return postData.calcHeight();
349 }
350 
352 {
353 
354  std::lock_guard<std::mutex> lock( m_fileStrMutex );
355  ossim_sint16 ss;
356  ossim_uint16 us;
357  int postCount = 0;
358  // read the posts in blocks 2x2.
359  for ( int column = 0; column < NUM_POSTS_PER_BLOCK ; ++column )
360  {
361  m_fileStr->seekg( offset, std::ios::beg );
362  for ( int row = 0; row < NUM_POSTS_PER_BLOCK ; ++row )
363  {
364  if ( !m_fileStr->eof() )
365  {
366  us = 0;
367  m_fileStr->read( ( char* ) &us, POST_SIZE );
368  // check the read was ok
369  if ( m_fileStr->good() )
370  {
371  postData.m_posts[postCount].m_status = true;
372  }
373  else
374  {
375  // reset the goodbit
376  m_fileStr->clear();
377  }
378  ss = convertSignedMagnitude( us );
379  postData.m_posts[postCount].m_height = ss;
380  }
381  postCount++;
382  }
383  offset += m_dtedRecordSizeInBytes;
384  }
385 }
386 
387 double ossimDtedHandler::getPostValue(const ossimIpt& gridPt) const
388 {
389  static const char MODULE[] = "ossimDtedHandler::getPostValue";
390 
391  // Do some error checking.
392  if ( gridPt.x < 0.0 || gridPt.y < 0.0 ||
393  gridPt.x > (m_numLonLines - 1) ||
394  gridPt.y > (m_numLatPoints - 1) )
395  {
396  if(traceDebug())
397  {
399  << "WARNING " << MODULE << ": No intersection..." << std::endl;
400  }
401  return ossim::nan();
402  }
403 
404  if (!isOpen())
405  {
406  return ossim::nan();
407  }
408 
409  int offset =
411  gridPt.y * 2 + DATA_RECORD_OFFSET_TO_POST;
412 
413  // Put the file pointer at the start of the first elevation post.
414  m_fileStr->seekg(offset, std::ios::beg);
415 
416  ossim_uint16 us;
417 
418  // Get the post.
419  m_fileStr->read((char*)&us, POST_SIZE);
420 
421  return double(convertSignedMagnitude(us));
422 }
423 
425 {
426  //***
427  // Check to see if there is a statistics file already. If so; do a lookup
428  // for the min and max values.
429  //***
430  ossimFilename stats_file = theFilename;//theFilename.path();
431  stats_file.setExtension("statistics");
432 
433  if (traceDebug())
434  {
436  << "DEBUG ossimDtedHandler::gatherStatistics(): Looking for "
437  << stats_file << " statistics file..." << std::endl;
438  }
439 
440  ossimKeywordlist kwl;
441  const char* min_str = NULL;
442  const char* max_str = NULL;
443 
444  if (stats_file.exists())
445  {
446  if (kwl.addFile(stats_file))
447  {
448  // Look for the min_pixel_value keyword.
449  min_str = kwl.find(ossimKeywordNames::MIN_VALUE_KW);
450  max_str = kwl.find(ossimKeywordNames::MAX_VALUE_KW);
451  }
452  }
453 
454  if (min_str && max_str)
455  {
456  theMinHeightAboveMSL = atoi(min_str);
457  theMaxHeightAboveMSL = atoi(max_str);
458  }
459  else if (theComputeStatsFlag&&!m_memoryMap.size()) // Scan the cell and gather the statistics...
460  {
461  if(traceDebug())
462  {
464  << "NOTICE ossimDtedHandler::gatherStatistics():"
465  << " scanning for min/max"
466  << "\nThis may take a while..." << std::endl;
467  }
468  // Start off with the min and max pegged.
469  theMinHeightAboveMSL = 32767;
470  theMaxHeightAboveMSL = -32767;
471 
472  // Put the file pointer at the start of the first elevation post.
473  m_fileStr->seekg(m_offsetToFirstDataRecord, std::ios::beg);
474 
475  //---
476  // Loop through all records and scan for lowest min and highest max.
477  // Each record contains a row of latitude points for a given longitude.
478  // There are eight bytes in front of the post and four checksum bytes at
479  // the end so ignore them.
480  //---
481  for (ossim_int32 i=0; i<m_numLonLines; ++i) // longitude direction
482  {
483  m_fileStr->seekg(DATA_RECORD_OFFSET_TO_POST, std::ios::cur);
484 
485  for (ossim_int32 j=0; j<m_numLatPoints; ++j) // latitude direction
486  {
487  ossim_uint16 us;
488  ossim_sint16 ss;
489  m_fileStr->read((char*)&us, POST_SIZE);
490  ss = convertSignedMagnitude(us);
491  if (ss < theMinHeightAboveMSL && ss != NULL_POST)
492  {
494  }
495  if (ss > theMaxHeightAboveMSL)
496  {
498  }
499  }
500 
501  m_fileStr->seekg(DATA_RECORD_CHECKSUM_SIZE, std::ios::cur);
502  }
503 
504  // Add the stats to the keyword list.
507 
508  // Write out the statistics file.
509  kwl.write(stats_file.c_str());
510  }
511 
512  if (traceDebug())
513  {
515  << "DEBUG ossimDtedHandler::gatherStatistics:"
516  << "\ntheMinHeightAboveMSL: " << theMinHeightAboveMSL
517  << "\ntheMaxHeightAboveMSL: " << theMaxHeightAboveMSL
518  << std::endl;
519  }
520 }
521 
523 {
525 }
526 
528 {
529  return m_edition;
530 }
531 
533 {
534  return m_productLevel;
535 }
536 
538 {
539  return m_compilationDate;
540 }
541 
543  const ossimDtedHandler& rhs)
544 {
545  return rhs;
546 }
547 
549  :
551 {}
552 
553 
556 
559 
561 
563 {
564  double sum_weights = 0;
565  double sum_posts = 0;
566  for ( int i = 0; i < TOTAL_POSTS; ++i )
567  {
568  if ( m_posts[i].m_height == NULL_POST || !m_posts[i].m_status )
569  {
570  m_posts[i].m_weight = 0.0;
571  }
572  }
573 
574  for ( int i = 0; i < TOTAL_POSTS; ++i )
575  {
576  sum_weights += m_posts[i].m_weight;
577  sum_posts += m_posts[i].m_height * m_posts[i].m_weight;
578  }
579  if ( sum_weights )
580  {
581  return sum_posts / sum_weights;
582  }
583  return ossim::nan();
584 }
585 
587 {
588  cout << "\np00: " << m_posts[0].m_height
589  << "\np01: " << m_posts[1].m_height
590  << "\np10: " << m_posts[2].m_height
591  << "\np11: " << m_posts[3].m_height
592  << "\nw00: " << m_posts[0].m_weight
593  << "\nw01: " << m_posts[1].m_weight
594  << "\nw10: " << m_posts[2].m_weight
595  << "\nw11: " << m_posts[3].m_weight
596  << "\ns00: " << m_posts[0].m_status
597  << "\ns01: " << m_posts[1].m_status
598  << "\ns10: " << m_posts[2].m_status
599  << "\ns11: " << m_posts[3].m_status
600  << std::endl;
601 }
static const char * MIN_VALUE_KW
DtedHeight()
DtedHeight methods.
virtual bool open(const ossimFilename &file, bool memoryMapFlag=false)
opens a cell
std::shared_ptr< ossimDtedVol > m_vol
virtual double getPostValue(const ossimIpt &gridPt) const
ossimString edition() const
void readPostsFromFile(DtedHeight &postData, int offset)
read the height posts from the File
ossimString m_productLevel
Represents serializable keyword/value map.
bool addFile(const char *file)
const char * find(const char *key) const
ossim_int64 fileSize() const
double theMinHeightAboveMSL
Data members:
double nan()
Method to return ieee floating point double precision NAN.
Definition: ossimCommon.h:135
std::shared_ptr< ossimDtedUhl > m_uhl
virtual void close()
static const char * MAX_VALUE_KW
ossim_int32 m_numLonLines
virtual bool getAccuracyInfo(ossimElevationAccuracyInfo &info, const ossimGpt &gpt) const
OSSIM_DLL ossimByteOrder byteOrder()
Definition: ossimCommon.cpp:54
static const ossimErrorCode OSSIM_ERROR
static StreamFactoryRegistry * instance()
std::vector< ossim_uint8 > m_memoryMap
unsigned short ossim_uint16
virtual bool write(const char *file, const char *comment=0) const
Methods to dump the ossimKeywordlist to a file on disk.
static const int NUM_POSTS_PER_BLOCK
ossimString productLevel() const
static const int TOTAL_POSTS
std::shared_ptr< ossimDtedHdr > m_hdr
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
std::shared_ptr< ossimDtedDsi > m_dsi
virtual bool isOpen() const
std::mutex m_fileStrMutex
ossimGrect theGroundRect
double lat
Definition: ossimDpt.h:165
DtedHeight is a class for storing DTED information.
ossimString m_compilationDate
bool exists() const
ossim_float64 lon
Definition: ossimGpt.h:266
signed short ossim_sint16
std::shared_ptr< ossim::istream > m_fileStr
ossimFilename theFilename
Virtual method for reading.
the DTED handler is an elevation source that allows for handling of a single cell of data...
double cosd(double x)
Definition: ossimCommon.h:259
double lon
Definition: ossimDpt.h:164
virtual ~DtedPost()
DtedPost methods.
ossim_int32 m_numLatPoints
ossim_sint16 convertSignedMagnitude(ossim_uint16 &s) const
ossim_int32 m_offsetToFirstDataRecord
ossim_int32 m_dtedRecordSizeInBytes
ossim_int32 y
Definition: ossimIpt.h:142
ossimString compilationDate() const
std::shared_ptr< ossimDtedAcc > m_acc
virtual double getHeightAboveMSL(const ossimGpt &gpt)
double x
Definition: ossimDpt.h:164
long long ossim_int64
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
const ossimDtedHandler & operator=(const ossimDtedHandler &rhs)
virtual ossimIpt getSizeOfElevCell() const
ossimDpt metersPerDegree() const
Definition: ossimGpt.cpp:498
ossim_int32 x
Definition: ossimIpt.h:141
ossim_float64 lat
Definition: ossimGpt.h:265
DtedPost m_posts[TOTAL_POSTS]
double theMaxHeightAboveMSL
#define RTTI_DEF1(cls, name, b1)
Definition: ossimRtti.h:485
virtual ~ossimDtedHandler()
ossimString m_edition
ossimDtedHandler()
Constructor.
ossimFilename & setExtension(const ossimString &e)
Sets the extension of a file name.
std::string m_connectionString
unsigned char ossim_uint8
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
int ossim_int32