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