OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimGeoidEgm96.cpp
Go to the documentation of this file.
1 //*******************************************************************
2 // License: See top level LICENSE.txt file.
3 //
4 // Author: David Burken
5 //
6 //*******************************************************************
7 // $Id: ossimGeoidEgm96.cpp 22900 2014-09-30 09:56:11Z dburken $
8 
11 #include <ossim/base/ossimCommon.h> /* for ossim::nan() */
12 #include <ossim/base/ossimGpt.h>
14 #include <ossim/base/ossimEndian.h>
15 #include <ossim/base/ossimTrace.h>
18 #include <fstream>
19 
20 static ossimTrace traceDebug ("ossimGeoidEgm96:debug");
21 
22 
23 #define NumbGeoidCols 1441 /* 360 degrees of longitude at 15 minute spacing */
24 #define NumbGeoidRows 721 /* 180 degrees of latitude at 15 minute spacing */
25 #define NumbHeaderItems 6 /* min, max lat, min, max long, lat, long spacing*/
26 #define ScaleFactor 4 /* 4 grid cells per degree at 15 minute spacing */
27 #define NumbGeoidElevs NumbGeoidCols * NumbGeoidRows
28 // #define PI 3.14159265358979323e0
29 
30 
31 RTTI_DEF1(ossimGeoidEgm96, "ossimGeoidEgm96", ossimGeoid)
32 
34  :theGeoidHeightBufferPtr(0)
35 {
36 }
37 
40  :theGeoidHeightBufferPtr(0)
41 {
42  open(grid_file, byteOrder);
44  {
45  theGeoidHeightBuffer.clear();
46  }
47 }
48 
50 {
51 }
52 
54 {
55  return "geoid1996";
56 }
57 
58 bool ossimGeoidEgm96::open(const ossimFilename& grid_file,
60 {
61  static const char MODULE[] = "ossimGeoidEgm96::open";
62 
63  if (traceDebug())
64  {
65  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " Entered...\n";
66  }
67 
69  {
72  }
73 
74  // int ItemsRead = 0;
75  long ElevationsRead = 0;
76  // long ItemsDiscarded = 0;
77  long num = 0;
78 
79  ossimFilename grid = grid_file;
80  if (grid_file.isDir())
81  {
82  grid = grid_file.dirCat("egm96.grd");
83  }
84 
85  if (traceDebug())
86  {
87  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " Grid file:" << grid << "\n";
88  }
89 
90  // Open the File READONLY, or Return Error Condition:
91  std::ifstream gridHeightFile(grid.c_str(), std::ios::in|std::ios::binary);
92 // FILE* GeoidHeightFile;
93 
94  if ( gridHeightFile.fail())
95  {
96  if(traceDebug())
97  {
98  ossimNotify(ossimNotifyLevel_WARN) << MODULE << " could not open file "
99  << grid.c_str() << "\n";
100  }
101  setErrorStatus();
102  return false;
103  }
104 
105  // Skip the Header Line:
106  ossimEndian oe;
107  bool swap_bytes = (ossim::byteOrder() != byteOrder) ? true : false;
108  while ( (num < NumbHeaderItems)&&(!gridHeightFile.fail()))
109  {
110  float f;
111  gridHeightFile.read( (char*)(&f), 4);
112  if (swap_bytes) oe.swap(f);
113  theGeoidHeightBuffer[num] = f;
114  ++num;
115  }
116  // Determine if header read properly, or NOT:
117  if ((!ossim::almostEqual(theGeoidHeightBuffer[0], (float)-90.0)) ||
118  (!ossim::almostEqual(theGeoidHeightBuffer[1], (float)90.0)) ||
119  (!ossim::almostEqual(theGeoidHeightBuffer[2], (float)0.0)) ||
120  (!ossim::almostEqual(theGeoidHeightBuffer[3],(float)360.0))||
121  (!ossim::almostEqual(theGeoidHeightBuffer[4],(float)(1.0 / ScaleFactor ))) ||
122  (!ossim::almostEqual(theGeoidHeightBuffer[5],(float)( 1.0 / ScaleFactor ))) ||
123  gridHeightFile.fail())
124  {
125  if(traceDebug())
126  {
127  ossimNotify(ossimNotifyLevel_WARN) << MODULE << " bad header file "
128  << grid.c_str() << "\n";
129  }
130  setErrorStatus();
131  return false;
132  }
133 
134  // Extract elements from the file:
135  num = 0;
136  while ( (num < NumbGeoidElevs)&&(!gridHeightFile.fail()) )
137  {
138 // if (feof( GeoidHeightFile )) break;
139 // if (ferror( GeoidHeightFile )) break;
140 
141  float f;
142  gridHeightFile.read( (char*)(&f), 4);
143  if (swap_bytes) oe.swap(f);
144  theGeoidHeightBuffer[num] = f;
145  ++ElevationsRead;
146  ++num;
147  }
148 
149 // fclose(GeoidHeightFile);
150 
151  // Determine if all elevations of file read properly, or NOT:
152  if (ElevationsRead != NumbGeoidElevs)
153  {
154  setErrorStatus();
155  ossimSetError("ossimGeoidEgm96::open",
157  "Bad grid file...%s", grid.c_str());
158  return false;
159  }
160 
161  if (traceDebug())
162  {
164  << "Opened geoid grid: " << grid.c_str() << std::endl;
165  }
166 
167  return true;
168 }
169 
171 {
172  double offset = ossim::nan();
173  ossimGpt savedGpt = gpt;
174  if(ossimDatumFactory::instance()->wgs84())
175  {
176  savedGpt.changeDatum(ossimDatumFactory::instance()->wgs84());
177  }
178 
180  {
181  if(traceDebug())
182  {
184  << "ossimGeoidEgm96::offsetFromEllipsoid, "
185  << "Object not initialized!\n";
186  }
187 
188  return offset;
189  }
190 
191  long Index;
192  double DeltaX, DeltaY;
193  double ElevationSE, ElevationSW, ElevationNE, ElevationNW;
194  double LatitudeDD, LongitudeDD;
195  double OffsetX, OffsetY;
196  double PostX, PostY;
197  double UpperY, LowerY;
198 
199  LatitudeDD = savedGpt.latd();
200 
201  // Check for wrap.
202  if (LatitudeDD < -90.0)
203  {
204  LatitudeDD = -180.0 - LatitudeDD;
205  }
206  else if (LatitudeDD > 90.0)
207  {
208  LatitudeDD = 180.0 - LatitudeDD;
209  }
210 
211  if ( (LatitudeDD < -90.0) || LatitudeDD > 90.0)
212  {
213  if(traceDebug())
214  {
215  // Latitude out of range
217  << "FATAL: " << "ossimGeoidEgm96::offsetFromEllipsoid, "
218  << "Point out of range: " << savedGpt << "\n";
219  }
220  return offset;
221  }
222 
223  LongitudeDD = savedGpt.lond();
224 
225  // Check for wrap.
226  if (LongitudeDD < -180)
227  {
228  LongitudeDD = LongitudeDD + 360.0;
229  }
230  else if (LongitudeDD > 180.0)
231  {
232  LongitudeDD = LongitudeDD - 360.0;
233  }
234 
235  if ( (LongitudeDD < -180.0) || (LongitudeDD > 180.0) )
236  {
237  // Longitude out of range
238  if(traceDebug())
239  {
241  << "FATAL: " << "ossimGeoidEgm96::offsetFromEllipsoid, "
242  << "Point out of range: " << savedGpt << "\n";
243  }
244  return offset;
245  }
246 
247  // Compute X and Y Offsets into Geoid Height Array:
248 
249  if (LongitudeDD < 0.0)
250  {
251  OffsetX = ( LongitudeDD + 360.0 ) * ScaleFactor;
252  }
253  else
254  {
255  OffsetX = LongitudeDD * ScaleFactor;
256  }
257  OffsetY = ( 90.0 - LatitudeDD ) * ScaleFactor;
258 
259  //---
260  // Find Four Nearest Geoid Height Cells for specified Latitude,
261  // Longitude; Assumes that (0,0) of Geoid Height Array is at
262  // Northwest corner:
263  //---
264  PostX = floor( OffsetX );
265  if ((PostX + 1) == NumbGeoidCols)
266  PostX--;
267  PostY = floor( OffsetY );
268  if ((PostY + 1) == NumbGeoidRows)
269  PostY--;
270 
271  Index = (long)(PostY * NumbGeoidCols + PostX);
272  ElevationNW = theGeoidHeightBufferPtr[ Index ];
273  ElevationNE = theGeoidHeightBufferPtr[ Index+ 1 ];
274 
275  Index = (long)((PostY + 1) * NumbGeoidCols + PostX);
276  ElevationSW = theGeoidHeightBufferPtr[ Index ];
277  ElevationSE = theGeoidHeightBufferPtr[ Index + 1 ];
278 
279  //Perform Bi-Linear Interpolation to compute Height above Ellipsoid:
280  DeltaX = OffsetX - PostX;
281  DeltaY = OffsetY - PostY;
282 
283  UpperY = ElevationNW + DeltaX * ( ElevationNE - ElevationNW );
284  LowerY = ElevationSW + DeltaX * ( ElevationSE - ElevationSW );
285 
286  offset = UpperY + DeltaY * ( LowerY - UpperY );
287 
288  return offset;
289 }
290 
292  double lon,
293  double geoidHeight)
294 {
295  ossimGpt gpt(lat, lon);
296  double height = offsetFromEllipsoid(gpt);
297  if (!ossim::isnan(height))
298  {
299  height += geoidHeight;
300  }
301  return height;
302 }
303 
305  double lon,
306  double ellipsoidHeight)
307 {
308  ossimGpt gpt(lat, lon);
309  double height = offsetFromEllipsoid(gpt);
310  if (!ossim::isnan(height))
311  {
312  return (ellipsoidHeight - height);
313  }
314  return height; // nan
315 }
OSSIMDLLEXPORT void ossimSetError(const char *className, ossim_int32 error, const char *fmtString=0,...)
#define ScaleFactor
double lond() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:97
static const ossimErrorCode OSSIM_OK
std::basic_ifstream< char > ifstream
Class for char input file streams.
Definition: ossimIosFwd.h:44
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
OSSIM_DLL ossimByteOrder byteOrder()
Definition: ossimCommon.cpp:54
static const ossimErrorCode OSSIM_ERROR
virtual double offsetFromEllipsoid(const ossimGpt &gpt)
bool isDir() const
double latd() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:87
#define NumbGeoidElevs
#define NumbHeaderItems
virtual ossimString getShortName() const
void changeDatum(const ossimDatum *datum)
This will actually perform a shift.
Definition: ossimGpt.cpp:316
virtual ~ossimGeoidEgm96()
static ossimDatumFactory * instance()
std::vector< float > theGeoidHeightBuffer
ossimByteOrder
#define NumbGeoidRows
virtual ossimErrorCode getErrorStatus() const
double geoidToEllipsoidHeight(double lat, double lon, double geoidHeight)
ossimFilename dirCat(const ossimFilename &file) const
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
double ellipsoidToGeoidHeight(double lat, double lon, double ellipsoidHeight)
#define RTTI_DEF1(cls, name, b1)
Definition: ossimRtti.h:485
#define NumbGeoidCols
void swap(ossim_sint8 &)
Definition: ossimEndian.h:26
float * theGeoidHeightBufferPtr
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
virtual bool open(const ossimFilename &grid_file, ossimByteOrder byteOrder=OSSIM_BIG_ENDIAN)
bool isnan(const float &v)
isnan Test for floating point Not A Number (NAN) value.
Definition: ossimCommon.h:91