00001 #pragma ident "$Id: IonexHeader.cpp 1398 2008-09-11 14:30:26Z coandrei $"
00002
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <cctype>
00032
00033 #include "StringUtils.hpp"
00034 #include "MathBase.hpp"
00035 #include "IonexHeader.hpp"
00036 #include "IonexStream.hpp"
00037
00038 using namespace std;
00039 using namespace gpstk::StringUtils;
00040
00041 namespace gpstk
00042 {
00043 const string IonexHeader::versionString = "IONEX VERSION / TYPE";
00044 const string IonexHeader::runByString = "PGM / RUN BY / DATE";
00045 const string IonexHeader::descriptionString = "DESCRIPTION";
00046 const string IonexHeader::commentString = "COMMENT";
00047 const string IonexHeader::firstTimeString = "EPOCH OF FIRST MAP";
00048 const string IonexHeader::lastTimeString = "EPOCH OF LAST MAP";
00049 const string IonexHeader::intervalString = "INTERVAL";
00050 const string IonexHeader::numMapsString = "# OF MAPS IN FILE";
00051 const string IonexHeader::mappingFunctionString = "MAPPING FUNCTION";
00052 const string IonexHeader::elevationString = "ELEVATION CUTOFF";
00053 const string IonexHeader::observablesUsedString = "OBSERVABLES USED";
00054 const string IonexHeader::numStationsString = "# OF STATIONS";
00055 const string IonexHeader::numSatsString = "# OF SATELLITES";
00056 const string IonexHeader::baseRadiusString = "BASE RADIUS";
00057 const string IonexHeader::mapDimensionString = "MAP DIMENSION";
00058 const string IonexHeader::hgtGridString = "HGT1 / HGT2 / DHGT";
00059 const string IonexHeader::latGridString = "LAT1 / LAT2 / DLAT";
00060 const string IonexHeader::lonGridString = "LON1 / LON2 / DLON";
00061 const string IonexHeader::exponentString = "EXPONENT";
00062 const string IonexHeader::startAuxDataString = "START OF AUX DATA";
00063 const string IonexHeader::endAuxDataString = "END OF AUX DATA";
00064 const string IonexHeader::endOfHeader = "END OF HEADER";
00065
00066 const string IonexHeader::DCB::svsAuxDataString = "PRN / BIAS / RMS";
00067 const string IonexHeader::DCB::stationsAuxDataString =
00068 "STATION / BIAS / RMS";
00069
00070
00071
00072 void IonexHeader::clear(void)
00073 {
00074
00075 version = 1.0;
00076 descriptionList.clear();
00077 commentList.clear();
00078 interval = 0;
00079 numMaps = numStations = numSVs = mapDims = 0;
00080 elevation = baseRadius = 0;
00081
00082 hgt[0] = hgt[1] = hgt[2] = 0.0;
00083 lat[0] = lat[1] = lat[2] = 0.0;
00084 lon[0] = lon[1] = lon[2] = 0.0;
00085
00086 exponent = -1;
00087 svsmap.clear();
00088 valid = auxDataFlag = false;
00089
00090 return;
00091
00092 }
00093
00094
00095
00096
00097
00098
00099
00100
00101 void IonexHeader::dump(std::ostream& os) const
00102 {
00103
00104 os << "-------------------------------- IONEX HEADER"
00105 << "--------------------------------" << endl;
00106
00107 os << "First epoch : " << firstEpoch << endl;
00108 os << "Last epoch : " << lastEpoch << endl;
00109 os << "Interval : " << interval << endl;
00110 os << "Number of ionex maps : " << numMaps << endl;
00111 os << "Mapping function : " << mappingFunction << endl;
00112 os << "Elevation cut off : " << elevation << endl;
00113 os << "Number of stations : " << numStations << endl;
00114 os << "Number of satellites : " << numSVs << endl;
00115 os << "Map dimensions : " << mapDims << endl;
00116
00117 os << "HGT1 / HGT2 / DHGT : " << hgt[0] << " / "
00118 << hgt[1] << " / "
00119 << hgt[2] << endl;
00120 os << "LAT1 / LAT2 / DLAT : " << lat[0] << " / "
00121 << lat[1] << " / "
00122 << lat[2] << endl;
00123 os << "LON1 / LON2 / DLON : " << lon[0] << " / "
00124 << lon[1] << " / "
00125 << lon[2] << endl;
00126 os << "Valid object? : " << valid << endl;
00127
00128 os << "-------------------------------- END OF HEADER"
00129 << "-------------------------------" << endl;
00130
00131 os << endl;
00132
00133 }
00134
00135
00136
00137
00138
00139
00140
00141 void IonexHeader::ParseDcbRecord(std::string &line)
00142 throw (FFStreamError)
00143 {
00144
00145 string label(line, 60, 20);
00146
00147 if (label == DCB::svsAuxDataString)
00148 {
00149
00150 char c = isspace(line[3]) ? 'G' : line[3];
00151 int prn = asInt(line.substr(4,2));
00152 double bias = asDouble(line.substr(6,16));
00153 double rms = asDouble(line.substr(16,26));
00154
00155
00156 SatID::SatelliteSystem system;
00157 switch(line[3])
00158 {
00159
00160 case ' ': case 'G': case 'g':
00161 system = SatID::systemGPS;
00162 break;
00163
00164 case 'R': case 'r':
00165 system = SatID::systemGlonass;
00166 break;
00167
00168 default:
00169 FFStreamError e(std::string("Invalid system character \"")
00170 + c + std::string("\""));
00171 GPSTK_THROW(e);
00172
00173 }
00174
00175 SatID svid = SatID(prn,system);
00176
00177
00178 svsmap[svid] = DCB(c,prn,bias,rms);
00179
00180 }
00181 else if (label == DCB::stationsAuxDataString)
00182 {
00183
00184
00185
00186
00187 }
00188 else if (label == commentString)
00189 {
00190
00191
00192 string s = strip(line.substr(0,60));
00193 commentList.push_back(s);
00194
00195 }
00196 else if (label == endAuxDataString)
00197 {
00198
00199 auxDataFlag = false;
00200
00201 }
00202 else
00203 {
00204
00205 FFStreamError e(std::string( "Unidentified IONEX::DCB label: "
00206 + label) );
00207
00208 GPSTK_THROW(e);
00209
00210 }
00211
00212 return;
00213
00214 }
00215
00216
00217
00218
00219
00220
00221
00222 void IonexHeader::ParseHeaderRecord(std::string &line)
00223 throw (FFStreamError)
00224 {
00225
00226 string label(line, 60, 20);
00227
00228 if (label == versionString)
00229 {
00230
00231 version = asDouble(line.substr(0,20));
00232 fileType = strip(line.substr(20,20));
00233 system = strip(line.substr(40,20));
00234
00235 }
00236 else if (label == runByString)
00237 {
00238
00239 fileProgram = strip(line.substr( 0,20));
00240 fileAgency = strip(line.substr(20,20));
00241 date = strip(line.substr(40,20));
00242
00243 }
00244 else if (label == descriptionString)
00245 {
00246
00247 string s = line.substr(0,60);
00248 descriptionList.push_back(s);
00249
00250 }
00251 else if (label == commentString)
00252 {
00253
00254 string s = line.substr(0,60);
00255 commentList.push_back(s);
00256
00257 }
00258 else if (label == firstTimeString)
00259 {
00260
00261 firstEpoch = parseTime(line);
00262
00263 }
00264 else if (label == lastTimeString)
00265 {
00266
00267 lastEpoch = parseTime(line);
00268
00269 }
00270 else if (label == intervalString)
00271 {
00272
00273 interval = asInt(line.substr(0,6));
00274
00275 }
00276 else if (label == numMapsString)
00277 {
00278
00279 numMaps = asInt(line.substr(0,6));
00280
00281 }
00282 else if (label == mappingFunctionString)
00283 {
00284
00285 mappingFunction = strip(line.substr(0, 6));
00286
00287 }
00288 else if (label == elevationString)
00289 {
00290
00291 elevation = asDouble(line.substr(0, 8));
00292
00293 }
00294 else if (label == observablesUsedString)
00295 {
00296
00297 observablesUsed = strip(line.substr(0,60));
00298
00299 }
00300 else if (label == numStationsString)
00301 {
00302
00303 numStations = asInt(line.substr(0,6));
00304
00305 }
00306 else if (label == numSatsString)
00307 {
00308
00309 numSVs = asInt(line.substr(0,6));
00310
00311 }
00312 else if (label == baseRadiusString)
00313 {
00314
00315 baseRadius = asDouble(line.substr(0, 8));
00316
00317 }
00318 else if (label == mapDimensionString)
00319 {
00320
00321 mapDims = asInt(line.substr(0,6));
00322
00323 }
00324 else if (label == hgtGridString)
00325 {
00326
00327 hgt[0] = asDouble(line.substr( 2, 6));
00328 hgt[1] = asDouble(line.substr( 8, 6));
00329 hgt[2] = asDouble(line.substr(14, 6));
00330
00331 }
00332 else if (label == latGridString)
00333 {
00334
00335 lat[0] = asDouble(line.substr( 2, 6));
00336 lat[1] = asDouble(line.substr( 8, 6));
00337 lat[2] = asDouble(line.substr(14, 6));
00338
00339 }
00340 else if (label == lonGridString)
00341 {
00342
00343 lon[0] = asDouble(line.substr( 2, 6));
00344 lon[1] = asDouble(line.substr( 8, 6));
00345 lon[2] = asDouble(line.substr(14, 6));
00346
00347 }
00348 else if (label == exponentString)
00349 {
00350
00351 exponent = asInt(line.substr(0,6));
00352
00353 }
00354 else if (label == startAuxDataString)
00355 {
00356
00357 auxData = strip(line.substr(0,60));
00358 auxDataFlag = true;
00359
00360 }
00361 else if (label == endOfHeader)
00362 {
00363
00364 auxDataFlag = true;
00365 valid = true;
00366
00367 }
00368 else
00369 {
00370
00371 FFStreamError e("Unidentified IONEX header record: " + label);
00372
00373 GPSTK_THROW(e);
00374
00375 }
00376
00377 return;
00378
00379 }
00380
00381
00382
00383
00384 void IonexHeader::reallyGetRecord(FFStream& ffs)
00385 throw(exception, FFStreamError, StringException)
00386 {
00387
00388 IonexStream& strm = dynamic_cast<IonexStream&> (ffs);
00389
00390
00391 if (strm.headerRead == true)
00392 {
00393 return;
00394 }
00395
00396
00397
00398
00399
00400
00401 clear();
00402
00403 string line;
00404
00405 while (!valid)
00406 {
00407
00408 strm.formattedGetLine(line);
00409 StringUtils::stripTrailing(line);
00410
00411
00412 if (line.length() == 0)
00413 {
00414 continue;
00415 }
00416 else
00417 {
00418
00419 if (line.length() < 60 || line.length() > 80)
00420 {
00421
00422 FFStreamError e("Invalid line length");
00423 GPSTK_THROW(e);
00424
00425 }
00426
00427 }
00428
00429
00430 if (auxDataFlag)
00431 {
00432
00433 try
00434 {
00435 ParseDcbRecord(line);
00436 }
00437 catch (FFStreamError& e)
00438 {
00439 GPSTK_RETHROW(e);
00440 }
00441
00442 }
00443 else
00444 {
00445
00446 try
00447 {
00448 ParseHeaderRecord(line);
00449 }
00450 catch (FFStreamError& e)
00451 {
00452 GPSTK_RETHROW(e);
00453 }
00454
00455 }
00456
00457 }
00458
00459
00460
00461
00462 if (version != 1.0)
00463 {
00464 FFStreamError e( "Invalid IONEX version number " +
00465 asString(version));
00466 GPSTK_THROW(e);
00467 }
00468
00469
00470 double interval0( (lastEpoch - firstEpoch) / (numMaps -1.0) );
00471 if (interval != static_cast<int>(interval0))
00472 {
00473 FFStreamError e("Inconsistent time arguments.");
00474 GPSTK_THROW(e);
00475 }
00476
00477
00478 if (mapDims == 2)
00479 {
00480
00481 if ( (hgt[0] != hgt[1]) || (hgt[2] != 0.0) )
00482 {
00483 FFStreamError e("Error concerning map dimension.");
00484 GPSTK_THROW(e);
00485 }
00486
00487 }
00488 else
00489 {
00490
00491 if ( (hgt[0] == hgt[1]) || (hgt[2] == 0.0) )
00492 {
00493 FFStreamError e("Error concerning map dimension.");
00494 GPSTK_THROW(e);
00495 }
00496
00497 }
00498
00499
00500 double grdfac[4];
00501 try
00502 {
00503 grdfac[0] = lat[0]/lat[2];
00504 grdfac[1] = lat[1]/lat[2];
00505 grdfac[2] = lon[0]/lon[2];
00506 grdfac[3] = lon[1]/lon[2];
00507 }
00508 catch(exception& e)
00509 {
00510 cerr << "Problems computing grdfac: " << e.what() << endl;
00511 throw;
00512 }
00513
00514 for (int i = 0; i < 4; i++)
00515 {
00516 double xdif1( grdfac[i] - static_cast<int>(grdfac[i]) );
00517 double xdif( ABS(grdfac[i] - static_cast<int>(grdfac[i])) );
00518
00519 if (xdif > 1e-4)
00520 {
00521 FFStreamError e("Irregular Ionex data grid.");
00522 GPSTK_THROW(e);
00523 }
00524
00525 }
00526
00527
00528 strm.header = *this;
00529 strm.headerRead = true;
00530
00531 return;
00532
00533 }
00534
00535
00536
00537 void IonexHeader::reallyPutRecord(FFStream& ffs) const
00538 throw(exception, FFStreamError, StringException)
00539 {
00540
00541 IonexStream& strm = dynamic_cast<IonexStream&>(ffs);
00542
00543 if (version != 1.0)
00544 {
00545 FFStreamError err( "Unknown IONEX version: " + asString(version,2) );
00546 err.addText("Make sure to set the version correctly.");
00547 GPSTK_THROW(err);
00548 }
00549
00550 try
00551 {
00552 WriteHeaderRecords(strm);
00553 }
00554 catch(FFStreamError& e)
00555 {
00556 GPSTK_RETHROW(e);
00557 }
00558 catch(StringException& e)
00559 {
00560 GPSTK_RETHROW(e);
00561 }
00562
00563 }
00564
00565
00566
00567 void IonexHeader::WriteHeaderRecords(FFStream& ffs) const
00568 throw(FFStreamError, StringException)
00569 {
00570 IonexStream& strm = dynamic_cast<IonexStream&>(ffs);
00571 string line;
00572
00573 if (valid)
00574 {
00575
00576
00577 line.clear();
00578 line = rightJustify(asString(version,1), 8);
00579 line += string(12, ' ');
00580 if ((fileType[0] != 'I') && (fileType[0] != 'i'))
00581 {
00582 FFStreamError err("This isn't a Ionex file: " +
00583 fileType.substr(0,1));
00584 GPSTK_THROW(err);
00585 }
00586
00587 line += leftJustify(fileType, 20);
00588 line += leftJustify(system, 20);
00589 line += leftJustify(versionString,20);
00590 strm << line << endl;
00591 strm.lineNumber++;
00592
00593
00594
00595 line.clear();
00596 line += leftJustify(fileProgram,20);
00597 line += leftJustify(fileAgency,20);
00598 line += leftJustify(date,20);
00599 line += leftJustify(runByString,20);
00600 strm << line << endl;
00601 strm.lineNumber++;
00602
00603
00604
00605 if( commentList.size() > 0 )
00606 {
00607 line.clear();
00608 line += leftJustify(commentList[0],60);
00609 line += leftJustify(commentString,20);
00610 strm << line << endl;
00611 strm.lineNumber++;
00612 }
00613
00614
00615
00616 if (descriptionList.size() > 0)
00617 {
00618
00619 vector<std::string>::size_type i = 0;
00620
00621 for( ; i < descriptionList.size(); i++)
00622 {
00623
00624 line.clear();
00625 line += leftJustify(descriptionList[i],60);
00626 line += leftJustify(descriptionString,20);
00627 strm << line << endl;
00628 strm.lineNumber++;
00629
00630 }
00631
00632 }
00633
00634
00635
00636 line.clear();
00637 line += writeTime(firstEpoch);
00638 line += string(24, ' ');
00639 line += leftJustify(firstTimeString,20);
00640 strm << line << endl;
00641 strm.lineNumber++;
00642
00643
00644
00645 line.clear();
00646 line += writeTime(lastEpoch);
00647 line += string(24, ' ');
00648 line += leftJustify(lastTimeString,20);
00649 strm << line << endl;
00650 strm.lineNumber++;
00651
00652
00653
00654 line.clear();
00655 line += rightJustify( asString(interval), 6 );
00656 line += string(54, ' ');
00657 line += leftJustify(intervalString,20);
00658 strm << line << endl;
00659 strm.lineNumber++;
00660
00661
00662
00663 line.clear();
00664 line += rightJustify( asString<short>(numMaps), 6 );
00665 line += string(54, ' ');
00666 line += leftJustify(numMapsString,20);
00667 strm << line << endl;
00668 strm.lineNumber++;
00669
00670
00671
00672 line.clear();
00673 line += string(2, ' ');
00674 line += rightJustify(mappingFunction, 4);
00675 line += string(54, ' ');
00676 line += leftJustify(mappingFunctionString,20);
00677 strm << line << endl;
00678 strm.lineNumber++;
00679
00680
00681
00682 line.clear();
00683 line += rightJustify( asString(elevation,1), 8 );
00684 line += string(52, ' ');
00685 line += leftJustify(elevationString,20);
00686 strm << line << endl;
00687 strm.lineNumber++;
00688
00689
00690
00691 line.clear();
00692 line += leftJustify(observablesUsed,60);
00693 line += leftJustify(observablesUsedString,20);
00694 strm << line << endl;
00695 strm.lineNumber++;
00696
00697
00698
00699 if (numStations > 0)
00700 {
00701 line.clear();
00702 line += rightJustify( asString<short>(numStations), 6 );
00703 line += string(54, ' ');
00704 line += leftJustify(numStationsString,20);
00705 strm << line << endl;
00706 strm.lineNumber++;
00707 }
00708
00709
00710
00711 if (numSVs > 0)
00712 {
00713 line.clear();
00714 line += rightJustify( asString<short>(numSVs), 6 );
00715 line += string(54, ' ');
00716 line += leftJustify(numSatsString,20);
00717 strm << line << endl;
00718 strm.lineNumber++;
00719 }
00720
00721
00722
00723 line.clear();
00724 line += rightJustify( asString(baseRadius,1), 8 );
00725 line += string(52, ' ');
00726 line += leftJustify(baseRadiusString,20);
00727 strm << line << endl;
00728 strm.lineNumber++;
00729
00730
00731
00732 line.clear();
00733 line += rightJustify( asString(mapDims), 6 );
00734 line += string(54, ' ');
00735 line += leftJustify(mapDimensionString,20);
00736 strm << line << endl;
00737 strm.lineNumber++;
00738
00739
00740
00741 line.clear();
00742 line += string(2, ' ');
00743 line += rightJustify( asString(hgt[0],1), 6 );
00744 line += rightJustify( asString(hgt[1],1), 6 );
00745 line += rightJustify( asString(hgt[2],1), 6 );
00746 line += string(40, ' ');
00747 line += leftJustify(hgtGridString,20);
00748 strm << line << endl;
00749 strm.lineNumber++;
00750
00751 line.clear();
00752 line += string(2, ' ');
00753 line += rightJustify( asString(lat[0],1), 6 );
00754 line += rightJustify( asString(lat[1],1), 6 );
00755 line += rightJustify( asString(lat[2],1), 6 );
00756 line += string(40, ' ');
00757 line += leftJustify(latGridString,20);
00758 strm << line << endl;
00759 strm.lineNumber++;
00760
00761 line.clear();
00762 line += string(2, ' ');
00763 line += rightJustify( asString(lon[0],1), 6 );
00764 line += rightJustify( asString(lon[1],1), 6 );
00765 line += rightJustify( asString(lon[2],1), 6 );
00766 line += string(40, ' ');
00767 line += leftJustify(lonGridString,20);
00768 strm << line << endl;
00769 strm.lineNumber++;
00770
00771
00772
00773 line.clear();
00774 line += rightJustify( asString(exponent), 6 );
00775 line += string(54, ' ');
00776 line += leftJustify(exponentString,20);
00777 strm << line << endl;
00778 strm.lineNumber++;
00779
00780
00781
00782 for( vector<std::string>::size_type i = 1;
00783 i < commentList.size(); i++)
00784 {
00785 line.clear();
00786 line += leftJustify(commentList[i],60);
00787 line += leftJustify(commentString,20);
00788 strm << line << endl;
00789 strm.lineNumber++;
00790 }
00791
00792
00793
00794 if (auxDataFlag)
00795 {
00796
00797
00798 line.clear();
00799 line += leftJustify(auxData,60);
00800 line += leftJustify(startAuxDataString,20);
00801 strm << line << endl;
00802 strm.lineNumber++;
00803
00804 IonexHeader::SatDCBMap::const_iterator isv = svsmap.begin();
00805
00806 for(; isv != svsmap.end(); isv++)
00807 {
00808 line.clear();
00809 line += isv->second.toString();
00810 line += string(34, ' ');
00811 line += leftJustify(DCB::svsAuxDataString,20);
00812 strm << line << endl;
00813 strm.lineNumber++;
00814 }
00815
00816
00817 line.clear();
00818 line += leftJustify(auxData,60);
00819 line += leftJustify(endAuxDataString,20);
00820 strm << line << endl;
00821 strm.lineNumber++;
00822
00823 }
00824
00825
00826
00827 line.clear();
00828 line += string(60, ' ');
00829 line += leftJustify(endOfHeader,20);
00830 strm << line << endl;
00831 strm.lineNumber++;
00832
00833 }
00834 }
00835
00836
00837
00838
00839
00840
00841 DayTime IonexHeader::parseTime(const string& line) const
00842 {
00843
00844 int year, month, day, hour, min, sec;
00845
00846 year = asInt(line.substr( 0,6));
00847 month = asInt(line.substr( 6,6));
00848 day = asInt(line.substr(12,6));
00849 hour = asInt(line.substr(18,6));
00850 min = asInt(line.substr(24,6));
00851 sec = asInt(line.substr(30,6));
00852
00853 return DayTime(year, month, day, hour, min, (double)sec);
00854
00855 }
00856
00857
00861 string IonexHeader::writeTime(const DayTime& dt) const
00862 {
00863
00864 string line;
00865
00866 line = rightJustify(asString<short>(dt.year()), 6);
00867 line += rightJustify(asString<short>(dt.month()), 6);
00868 line += rightJustify(asString<short>(dt.day()), 6);
00869 line += rightJustify(asString<short>(dt.hour()), 6);
00870 line += rightJustify(asString<short>(dt.minute()), 6);
00871 line += rightJustify(asString (static_cast<int>(dt.second())), 6);
00872
00873 return line;
00874
00875 }
00876
00877
00878
00879 }