OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimERS.cpp
Go to the documentation of this file.
1 //*******************************************************************
2 //
3 // License: See top level LICENSE.txt file.
4 //
5 // Author: Chong-Ket Chuah
6 // Contributor: Anrew Huang
7 //
8 // Description:
9 // Implementation of ossimERS class for parsing a ER Mapper raster
10 // file format header.
11 //
12 //********************************************************************
13 // $Id: ossimERS.cpp 17501 2010-06-02 11:14:55Z dburken $
14 
15 #include <cstdio>
16 #include <fstream>
17 #include <iostream>
18 #include <iomanip>
19 
20 #include <ossim/base/ossimCommon.h>
21 #include <ossim/base/ossimTrace.h>
25 
26 static ossimTrace traceDebug("ossimERS:debug");
27 
28 
30  :
32 {
33  clearFields();
34 }
35 
36 ossimERS::ossimERS(const char* headerFile)
37  :
39 {
40  clearFields();
41 
42  // open the header file:
43  std::ifstream in;
44  in.open(headerFile, std::ios::in | std::ios::binary);
45 
46  if (!in)
47  {
49  }
50 
51  // Begin parsing records:
52  if (!theErrorStatus)
53  {
54  parseHeader(in);
55  }
56 
57  if (traceDebug())
58  {
60  << "ossimERS DEBUG:"
61  << *this
62  << std::endl;
63  }
64 }
65 
66 void ossimERS::parseError(const char* /* msg*/ )
67 {
69 }
70 
72 {
73  std::vector<ossimString> tokens;
74 
75  bool done = false;
76  while (!done)
77  {
78  tokens = parseLine(in);
79  if (tokens.empty())
80  {
81  parseError("premature end of header file.");
82  return;
83  }
84  if (tokens[0] == "CellType")
85  {
86  if (tokens[1] == "Unsigned8BitInteger")
87  {
89  }
90  else if (tokens[1] == "Unsigned16BitInteger")
91  {
93  }
94  else if (tokens[1] == "Signed16BitInteger")
95  {
97  }
98  else if (tokens[1] == "IEEE4ByteReal")
99  {
101  }
102  else if (tokens[1] == "IEEE8ByteReal")
103  {
105  }
106  else
107  {
108  parseError("Unsupported CellType.");
109  }
110  }
111  else if (tokens[0] == "NullCellValue")
112  {
113  theHasNullCells = true;
114  theNullCell = tokens[1].toInt(); // float nullcell value?
115  }
116  else if (tokens[0] == "Xdimension")
117  { // ignore "CellInfo"
118  theCellSizeX = tokens[1].toDouble();
119  }
120  else if (tokens[0] == "Ydimension")
121  { // ignore "CellInfo"
122  theCellSizeY = tokens[1].toDouble();
123  }
124  else if (tokens[0] == "NrOfLines")
125  {
126  theLine = tokens[1].toInt();
127  }
128  else if (tokens[0] == "NrOfCellsPerLine")
129  {
130  theSample = tokens[1].toInt();
131  }
132  else if (tokens[0] == "Eastings")
133  { // ignore "RegistrationCoord"
135  theOriginX = tokens[1].toDouble();
136  }
137  else if (tokens[0] == "Northings")
138  { // ignore "RegistrationCoord"
140  theOriginY = tokens[1].toDouble();
141  }
142  else if (tokens[0] == "Longitude")
143  { // ignore "RegistrationCoord"
144  // need to check coordinatestype ("Cannot use Latitude with UTM projection")
145  double deg, min, sec;
146  sscanf (tokens[1].chars(), "%lg:%lg:%lg", &deg, &min, &sec);
147  theOriginX = std::abs(deg) + min/60.0 + sec/3600.0;
148  if (deg < 0.0)
149  {
151  }
153  }
154  else if (tokens[0] == "Latitude")
155  { // ignore "RegistrationCoord"
156  double deg, min, sec;
157  sscanf (tokens[1].chars(), "%lg:%lg:%lg", &deg, &min, &sec);
158  theOriginY = std::abs(deg) + min/60.0 + sec/3600.0;
159  if (deg < 0.0)
160  {
162  }
164  }
165  else if (tokens[0] == "NrOfBands")
166  {
167  theBands = tokens[1].toInt();
168  }
169  else if (tokens[0] == "Value")
170  { // ignore "BandID"
171  // keep adding to the bandID vector
172  // delete Value key then join the rest of tokens
173  tokens.erase(tokens.begin());
174  ossimString id;
175  id.join(tokens, " ");
176  theBandID.push_back(id);
177  }
178  else if (tokens[0] == "RasterInfo")
179  {
180  done = true;
181  }
182  }
183 }
184 
185 
187 {
188  std::vector<ossimString> tokens;
189 
190  bool done = false;
191  while (!done)
192  {
193  tokens = parseLine(in);
194  if (tokens.empty())
195  {
196  parseError("premature end of header file.");
197  return;
198  }
199  if (tokens[0] == "Datum")
200  {
201  theDatum = tokens[1];
202  if (theDatum != "WGS84" && theDatum != "RAW")
203  {
204  parseError("Datum must be WGS84 or RAW");
205  }
206  }
207  else if (tokens[0] == "Projection")
208  {
209  theProjection = tokens[1];
210  // need to parse projection string
211  /*(EqualStrings (tok(1,3), "UTM")) {
212  coordinateSystem = 'U';
213  if (tok(0) == 'N')
214  northernHemisphere = 1;
215  else
216  northernHemisphere = 0;
217  spString zoneStr = tok(4,2);
218  sscanf (zoneStr.chars(), "%d", &zone);
219  */
220  }
221  else if (tokens[0] == "CoordinateType")
222  {
223  // ignore it
224  }
225  else if (tokens[0] == "Units")
226  {
227  // ignore it for now
228  }
229  else if (tokens[0] == "Rotation")
230  {
231  double deg, min, sec;
232  sscanf (tokens[1].chars(), "%lg:%lg:%lg", &deg, &min, &sec);
233  theRotation = deg + min/60.0 + sec/3600.0;
234  }
235  else if (tokens[0] == "CoordinateSpace")
236  {
237  done = true;
238  }
239  }
240 
241  // requires more error checking on unit and rotation here
242  return;
243 }
244 
246 {
248  char magicNumberTest[14];
249  in.read(magicNumberTest, 13);
250  if(ossimString(magicNumberTest,
251  magicNumberTest+13) != "DatasetHeader")
252  {
253  parseError("First line must be DatasetHeader");
254  return;
255  }
256  in.seekg(0);
257  std::vector<ossimString> tokens = parseLine(in);
258  if(!tokens.size())
259  {
260  parseError("First line must be DatasetHeader");
261  return;
262  }
263  if (tokens[0] != "DatasetHeader")
264  {
265  parseError("First line must be DatasetHeader");
266  return;
267  }
268 
269  bool done = false;
270  while (!done)
271  {
272  tokens = parseLine(in);
273  if (tokens.empty())
274  {
275  parseError("premature end of header file.");
276  return;
277  }
278  if (tokens[0] == "Version")
279  {
280  theVersion = tokens[1].toDouble();
281  if (theVersion < 4.0)
282  {
283  parseError("Version must be 4.0 or greater");
284  }
285  }
286  else if (tokens[0] == "DataSetType")
287  {
288  theDatasetType = tokens[1];
289  if (theDatasetType != "ERStorage")
290  {
291  parseError("DataSetType must be ERStorage");
292  }
293  }
294  else if (tokens[0] == "DataType")
295  {
296  theDatatype = tokens[1];
297  if (theDatatype != "Raster")
298  {
299  parseError("DataType must be Raster");
300  }
301  }
302  else if (tokens[0] == "ByteOrder")
303  {
304  theByteorder = tokens[1];
305  if (theByteorder != "MSBFirst" && theByteorder != "LSBFirst")
306  {
307  parseError("ByteOrder must either be MSBFirst or LSBFirst");
308  }
309  }
310  else if (tokens[0] == "CoordinateSpace")
311  {
312  if (tokens[1] == "Begin")
313  {
315  }
316  }
317  else if (tokens[0] == "RasterInfo")
318  {
319  if (tokens[1] == "Begin")
320  {
321  parseRasterInfo(in);
322  }
323  }
324  else if (tokens[0] == "SenseDate")
325  {
326  // ignore for now
327  }
328  else if (tokens[0] == "Comments")
329  {
330  // ignore for now
331  }
332  else if (tokens[0] == "DatasetHeader")
333  {
334  done = true;
335  }
336  }
337 
338  if(theProjection.contains("GEODETIC"))
339  {
341  }
342 
343  return;
344 }
345 
346 
347 // read a line from the file, split it using "= \t\n" delimiters.
348 // if the first token is empty, if the line begins with a tab, delete
349 // the token. The second token, the value for the key, may be quoted.
350 // trim the quotes.
351 std::vector<ossimString> ossimERS::parseLine(std::istream& in)
352 {
353 /* const int bufSize = 500; */
354  ossimString line;
355  std::vector<ossimString> tokens;
356  bool invalidCharHit = false;
357  const int MAX_LENGTH = 10000;
358  int tempCount = 0;
359  // read a line, skipping empty line
360  while (tokens.empty()&&(in)&&(tempCount < MAX_LENGTH))
361  {
362  tempCount = 1;
363  char c = in.get();
364  while( (c != '\n')&&
365  (!in.eof())&&
366  (!invalidCharHit))
367  {
368  if(c > 0x7e)
369  {
370  invalidCharHit = true;
371  }
372  else
373  {
374  line += (char)c;
375  c = in.get();
376  ++tempCount;
377  }
378  }
379 
380  if(!invalidCharHit)
381  {
382  line.trim('\t');
383  line.trim('\n');
384  line.trim('\r');
385  line.trim(' ');
386 
387  if(line != "")
388  {
389  tokens = line.split("= \t");
390  if (tokens.size() > 1)
391  {
392  tokens[1].trim('\"');
393  tokens.back().trim('\"');
394  }
395  }
396  }
397  else
398  {
399  tokens.clear();
400  return tokens;
401  }
402  }
403  if(in.bad()||(tempCount>=MAX_LENGTH))
404  {
405  tokens.clear();
406  }
407 
408  return tokens;
409 }
410 
412 {
413  if (theDescription.empty())
414  {
415  theDescription = file;
416  }
417 
418  std::ofstream out(file.c_str(), std::ios_base::out);
419 
420  if (!out)
421  {
422  return false;
423  }
424 
425  print(out);
426  out.close();
427  return true;
428 
429 }
430 
432 {
433  out<< std::setiosflags(std::ios::fixed) << std::setprecision(12);
434  out<<"DatasetHeader Begin" <<std::endl;
435  out<<" Version = \"5.5\"" <<std::endl;
436  out<<" DataSetType = " <<theDatasetType <<std::endl;
437  out<<" DataType = " <<theDatatype <<std::endl;
438  out<<" ByteOrder = " <<theByteorder <<std::endl;
439 
440  out<<" CoordinateSpace Begin" <<std::endl;
441  out<<" Datum = \"" <<theDatum <<"\"" <<std::endl;
442  out<<" Projection = \"" <<theProjection <<"\"" <<std::endl;
443  out<<" CoordinateType = " <<theCoordSysType <<std::endl;
444  out<<" CoordinateSpace End" <<std::endl;
445 
446  ossimString celltype;
447  if (theCelltype == OSSIM_UINT8)
448  celltype = "Unsigned8BitInteger";
449  else if (theCelltype == OSSIM_SINT8)
450  celltype = "Signed8BitInteger";
451  else if (theCelltype == OSSIM_UINT16)
452  celltype = "Unsigned16BitInteger";
453  else if (theCelltype == OSSIM_SINT16)
454  celltype = "Signed16BitInteger";
455  else if (theCelltype == OSSIM_UINT32)
456  celltype = "Unsigned32BitInteger";
457  else if (theCelltype == OSSIM_SINT32)
458  celltype = "Signed32BitInteger";
459  else if (theCelltype == OSSIM_USHORT11)
460  celltype = "Unsigned16BitInteger";
461  else if (theCelltype == OSSIM_USHORT12)
462  celltype = "Unsigned16BitInteger";
463  else if (theCelltype == OSSIM_USHORT13)
464  celltype = "Unsigned16BitInteger";
465  else if (theCelltype == OSSIM_USHORT14)
466  celltype = "Unsigned16BitInteger";
467  else if (theCelltype == OSSIM_USHORT15)
468  celltype = "Unsigned16BitInteger";
469  else if (theCelltype == OSSIM_USHORT16)
470  celltype = "Unsigned16BitInteger";
471 
472  out<<" RasterInfo Begin" <<std::endl;
473  out<<" CellType = " <<celltype <<std::endl;
474 
475  out<<" CellInfo Begin" <<std::endl;
476  out<<" Xdimension = " <<theCellSizeX <<std::endl;
477  out<<" Ydimension = " <<theCellSizeY <<std::endl;
478  out<<" CellInfo End" <<std::endl;
479 
480  out<<" NrOfLines = " <<theLine <<std::endl;
481  out<<" NrOfCellsPerLine = " <<theSample <<std::endl;
482 
483  out<<" RegistrationCoord Begin" <<std::endl;
485  {
486  out<<" Eastings = " <<theOriginX <<std::endl;
487  out<<" Northings = " <<theOriginY <<std::endl;
488  }
489  else if (theTieUnitType == OSSIM_DEGREES)
490  {
491  bool minus = false;
492  int min;
493  double degrees, seconds;
494  degrees = theOriginY;
495  if (theOriginY < 0)
496  {
497  minus = true;
498  degrees *=-1;
499  }
500  min = (int)((degrees-(int)degrees)*60);
501  seconds = ((degrees-(int)degrees)*60 - min)*60;
502  if (minus)
503  degrees *= -1;
504  out<<" Latitude = "
505  <<(int)degrees<<":"<<min<<":"<<seconds<<std::endl;
506 
507  minus = false;
508  degrees = theOriginX;
509  if (theOriginX < 0)
510  {
511  minus = true;
512  degrees *=-1;
513  }
514  min = (int)((degrees-(int)degrees)*60);
515  seconds = ((degrees-(int)degrees)*60 - min)*60;
516  if (minus)
517  degrees *= -1;
518  out<<" Longitude = "
519  <<(int)degrees<<":"<<min<<":"<<seconds<<std::endl;
520  }
521  out<<" RegistrationCoord End" <<std::endl;
522 
523  out<<" NrOfBands = " <<theBands <<std::endl;
524  out<<" RasterInfo End" <<std::endl;
525 
526  out<<"DatasetHeader End" <<std::endl;
527 
528  return out;
529 }
530 
532  const char* prefix)const
533 {
535  ossimString datum = toOssimDatum();
536 
537  if(proj == "")
538  {
539  return false;
540  }
541 
542  kwl.add(prefix,
544  proj.c_str(),
545  true);
546 
547  kwl.add(prefix,
549  datum.c_str(),
550  true);
551 
552  // if it's UTM we have to extract out zone and hemisphere
553  // from the projection name stored by ERMapper.
554  //
555  if(proj == "ossimUtmProjection")
556  {
558  theProjection.end());
559  ossimString hemisphere(theProjection.begin(),
560  theProjection.begin()+1);
561  kwl.add(prefix,
563  zone.c_str(),
564  true);
565  kwl.add(prefix,
567  hemisphere.c_str(),
568  true);
569  }
570 
572  {
573  kwl.add(prefix,
576  true);
577  kwl.add(prefix,
580  true);
581  kwl.add(prefix,
583  theCellSizeX,
584  true);
585  kwl.add(prefix,
587  theCellSizeY,
588  true);
589 
590  }
591  else if(theTieUnitType == OSSIM_DEGREES)
592  {
593  kwl.add(prefix,
596  true);
597  kwl.add(prefix,
600  true);
601  kwl.add(prefix,
603  theCellSizeX,
604  true);
605  kwl.add(prefix,
607  theCellSizeY,
608  true);
609  }
610 
611  return true;
612 }
613 
615 {
616  ossimString result = "";
617 
618  if(theProjection.contains("UTM"))
619  {
620  result = "ossimUtmProjection";
621  }
622  else if(theProjection.contains("GEODETIC"))
623  {
624  result = "ossimEquDistCylProjection";
625  }
626 
627  return result;
628 }
629 
631 {
632  ossimString result = "WGE"; // wgs 84 default datum code
633 
634  if(theDatum != "WGS84")
635  {
636  ossimNotify(ossimNotifyLevel_WARN) << "WARNING Datum ossimERS::toOssimDatum: " << theDatum << " is not handled in ossimERS::toOssimDatum()\n"
637  << "Please notify us with the datum name so we can add it\n";
638  }
639 
640  return result;
641 }
642 
643 //***************************************************************************
644 // PRIVATE METHOD: ossimERS::initialize()
645 // Initializes all fields to blanks (or 0's) and null terminates strings.
646 //***************************************************************************
648 {
649 // static const char source[] = "";
650 
652  theVersion = 0;
653  theFilename = "";
654  theDescription = "";
655  theSensorname = "";
656  theHeaderOffset = 0;
657  theDatasetType = "";
658  theDatatype = "";
659  theByteorder = "";
660  theComments = "";
661  theDatum = "";
662  theProjection = "";
663  theCoordSysType = "";
664  theUnits = "";
665  theRotation = 0.0;
667  theCellsizeof = 0;
668  theHasNullCells = false;
669  theNullCell = 0;
670  theCellSizeX = 0;
671  theCellSizeY = 0;
672  theLine = 0;
673  theSample = 0;
674  theOriginX = 0;
675  theOriginY = 0;
676  theBands = 0;
678  theBandID.clear();
679 
680  return;
681 }
void parseHeader(std::istream &fptr)
Definition: ossimERS.cpp:245
16 bit unsigned integer (15 bits used)
8 bit signed integer
double theOriginX
Definition: ossimERS.h:66
static const char * DECIMAL_DEGREES_PER_PIXEL_LAT
ossimString theComments
Definition: ossimERS.h:47
ossimString theSensorname
Definition: ossimERS.h:41
static const char * DATUM_KW
double theRotation
Definition: ossimERS.h:54
const ossimString & join(const std::vector< ossimString > &stringList, const ossimString &separator)
16 bit unsigned integer
ossimUnitType theTieUnitType
Definition: ossimERS.h:56
ossimString theCoordSysType
Definition: ossimERS.h:52
Represents serializable keyword/value map.
static const ossimErrorCode OSSIM_OK
std::basic_ifstream< char > ifstream
Class for char input file streams.
Definition: ossimIosFwd.h:44
ossimString theDescription
Definition: ossimERS.h:38
ossimString toOssimProjection() const
Definition: ossimERS.cpp:614
std::vector< ossimString > theBandID
Definition: ossimERS.h:69
bool contains(char aChar) const
Definition: ossimString.h:58
ossimString theDatum
Definition: ossimERS.h:50
static const char * TIE_POINT_LON_KW
ossimString theByteorder
Definition: ossimERS.h:46
std::vector< ossimString > parseLine(std::istream &in)
Definition: ossimERS.cpp:351
16 bit signed integer
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.
ossim_int32 theCellsizeof
Definition: ossimERS.h:59
16 bit unsigned integer (14 bits used)
static const ossimErrorCode OSSIM_ERROR
bool toOssimProjectionGeom(ossimKeywordlist &kwl, const char *prefix=NULL) const
Definition: ossimERS.cpp:531
16 bit unsigned integer (13 bits used)
#define abs(a)
Definition: auxiliary.h:74
void clearFields()
Definition: ossimERS.cpp:647
32 bit unsigned integer
static const char * METERS_PER_PIXEL_Y_KW
static const char * TYPE_KW
std::string::iterator end()
Definition: ossimString.h:423
ossimScalarType theCelltype
Definition: ossimERS.h:58
double theCellSizeX
Definition: ossimERS.h:62
double theVersion
Definition: ossimERS.h:36
static const char * TIE_POINT_NORTHING_KW
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
bool theHasNullCells
Definition: ossimERS.h:60
static const char * ZONE_KW
virtual std::ostream & print(std::ostream &out) const
Outputs theErrorStatus as an ossimErrorCode and an ossimString.
Definition: ossimERS.cpp:431
double theNullCell
Definition: ossimERS.h:61
ossim_int32 theBands
Definition: ossimERS.h:68
void parseError(const char *msg)
Definition: ossimERS.cpp:66
static const char * TIE_POINT_EASTING_KW
32 bit signed integer
std::string::iterator begin()
Definition: ossimString.h:420
ossimString trim(const ossimString &valueToTrim=ossimString(" \\)) const
this will strip lead and trailing character passed in.
static const char * DECIMAL_DEGREES_PER_PIXEL_LON
double theCellSizeY
Definition: ossimERS.h:63
16 bit unsigned integer (11 bits used)
std::basic_istream< char > istream
Base class for char input streams.
Definition: ossimIosFwd.h:20
double theOriginY
Definition: ossimERS.h:67
ossimString theUnits
Definition: ossimERS.h:53
ossimString theFilename
Definition: ossimERS.h:37
ossimString toOssimDatum() const
Definition: ossimERS.cpp:630
static const char * HEMISPHERE_KW
ossimERS()
Definition: ossimERS.cpp:29
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
bool empty() const
Definition: ossimString.h:411
ossimString theDatatype
Definition: ossimERS.h:45
ossim_int32 theSample
Definition: ossimERS.h:65
bool writeFile(const ossimFilename &file)
Definition: ossimERS.cpp:411
static const char * TIE_POINT_LAT_KW
std::basic_ofstream< char > ofstream
Class for char output file streams.
Definition: ossimIosFwd.h:47
8 bit unsigned integer
ossimString theProjection
Definition: ossimERS.h:51
ossim_int32 theLine
Definition: ossimERS.h:64
void parseCoordinateSpace(std::istream &fptr)
Definition: ossimERS.cpp:186
32 bit floating point
ossimString theDatasetType
Definition: ossimERS.h:44
ossim_int32 theHeaderOffset
Definition: ossimERS.h:43
16 bit unsigned iteger
64 bit floating point
static const char * METERS_PER_PIXEL_X_KW
16 bit signed integer
void parseRasterInfo(std::istream &fptr)
Definition: ossimERS.cpp:71
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
8 bit unsigned iteger
#define min(a, b)
Definition: auxiliary.h:75
16 bit unsigned integer (12 bits used)