00001 #pragma ident "$Id: AntexData.cpp 2293 2010-02-12 18:14:16Z btolman $"
00002
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 #include "AntexData.hpp"
00048 #include "AntexStream.hpp"
00049 #include "StringUtils.hpp"
00050 #include "geometry.hpp"
00051
00052 using namespace gpstk::StringUtils;
00053 using namespace std;
00054
00055 namespace gpstk
00056 {
00057 const string AntexData::startAntennaString = "START OF ANTENNA";
00058 const string AntexData::typeSerNumString = "TYPE / SERIAL NO";
00059 const string AntexData::methodString = "METH / BY / # / DATE";
00060 const string AntexData::daziString = "DAZI";
00061 const string AntexData::zenithString = "ZEN1 / ZEN2 / DZEN";
00062 const string AntexData::numFreqString = "# OF FREQUENCIES";
00063 const string AntexData::validFromString = "VALID FROM";
00064 const string AntexData::validUntilString = "VALID UNTIL";
00065 const string AntexData::sinexCodeString = "SINEX CODE";
00066 const string AntexData::dataCommentString = "COMMENT";
00067 const string AntexData::startFreqString = "START OF FREQUENCY";
00068 const string AntexData::neuFreqString = "NORTH / EAST / UP";
00069 const string AntexData::endOfFreqString = "END OF FREQUENCY";
00070 const string AntexData::startFreqRMSString = "START OF FREQ RMS";
00071 const string AntexData::neuFreqRMSString = "NORTH / EAST / UP";
00072 const string AntexData::endOfFreqRMSString = "END OF FREQ RMS";
00073 const string AntexData::endOfAntennaString = "END OF ANTENNA";
00074
00075
00077 const int Nsattype=11;
00078 string sattype[Nsattype] =
00079 {
00080 string("BLOCK I"),
00081 string("BLOCK II"),
00082 string("BLOCK IIA"),
00083 string("BLOCK IIR"),
00084 string("BLOCK IIR-A"),
00085 string("BLOCK IIR-B"),
00086 string("BLOCK IIR-M"),
00087 string("BLOCK IIF"),
00088 string("GLONASS"),
00089 string("GLONASS-M"),
00090 string("GLONASS-K")
00091 };
00093 const vector<string> AntexData::SatelliteTypes(sattype,sattype+Nsattype);
00094
00095
00096 bool AntexData::isValid(DayTime& time) const throw()
00097 {
00098 if(!isValid())
00099 return false;
00100 if(time == DayTime::BEGINNING_OF_TIME ||
00101 (!(valid & validFromValid) && !(valid & validUntilValid))) {
00102 return true;
00103 }
00104 if((valid & validFromValid) && time < validFrom) {
00105 return false;
00106 }
00107 if((valid & validUntilValid) && time > validUntil) {
00108 return false;
00109 }
00110
00111 return true;
00112 }
00113
00114
00115 double AntexData::getTotalPhaseCenterOffset(const int freq,
00116 const double azim,
00117 const double elev_nadir) const
00118 throw(Exception)
00119 {
00120 try {
00121
00122 double pcv = getPhaseCenterVariation(freq, azim, elev_nadir);
00123 Triple pco = getPhaseCenterOffset(freq);
00124
00125 double elev = elev_nadir;
00126 if(!isRxAntenna)
00127 elev = 90. - elev_nadir;
00128
00129 double cosel = ::cos(elev * DEG_TO_RAD);
00130 double sinel = ::sin(elev * DEG_TO_RAD);
00131 double cosaz = ::cos(azim * DEG_TO_RAD);
00132 double sinaz = ::sin(azim * DEG_TO_RAD);
00133
00134
00135 return (-pcv + pco[0]*cosel*cosaz
00136 + pco[1]*cosel*sinaz
00137 + pco[2]*sinel);
00138 }
00139 catch(Exception& e) { GPSTK_RETHROW(e); }
00140 }
00141
00142
00143
00144
00145
00146 Triple AntexData::getPhaseCenterOffset(const int freq) const
00147 throw(Exception)
00148 {
00149 if(!isValid()) {
00150 gpstk::Exception e("Invalid object");
00151 GPSTK_THROW(e);
00152 }
00153 if(freq <= 0 || freq > nFreq) {
00154 gpstk::Exception e("Invalid frequency");
00155 GPSTK_THROW(e);
00156 }
00157
00158
00159 map<int, antennaPCOandPCVData>::const_iterator it = freqPCVmap.find(freq);
00160 if(it == freqPCVmap.end()) {
00161 gpstk::Exception e("Frequency " + gpstk::StringUtils::asString(freq)
00162 + " not found! object must be corrupted.");
00163 GPSTK_THROW(e);
00164 }
00165
00166
00167 Triple retval;
00168 for(int i=0; i<3; i++)
00169 retval[i] = it->second.PCOvalue[i];
00170
00171 return retval;
00172 }
00173
00174
00175
00176 double AntexData::getPhaseCenterVariation(const int freq,
00177 const double azimuth,
00178 const double elev_nadir) const
00179 throw(Exception)
00180 {
00181 if(!isValid()) {
00182 Exception e("Invalid object");
00183 GPSTK_THROW(e);
00184 }
00185 if(freq <= 0 || freq > nFreq) {
00186 Exception e("Invalid frequency");
00187 GPSTK_THROW(e);
00188 }
00189 if(elev_nadir < 0.0 || elev_nadir > 90.0) {
00190 Exception e("Invalid elevation/nadir angle");
00191 GPSTK_THROW(e);
00192 }
00193
00194 double retpco, azim, zen;
00195 zen = elev_nadir;
00196 if(isRxAntenna)
00197 zen = 90. - elev_nadir;
00198
00199
00200 if(azimuth < 0.0 || azimuth >= 360.0)
00201 azim = fmod(azimuth,360.0);
00202 else
00203 azim = azimuth;
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 double az_lo,az_hi,zn_lo,zn_hi,pco[4];
00216 map<int, antennaPCOandPCVData>::const_iterator it;
00217 map<double, zenOffsetMap>::const_iterator jt_lo,jt_hi;
00218
00219 it = freqPCVmap.find(freq);
00220 if(it == freqPCVmap.end()) {
00221 Exception e("Frequency " + StringUtils::asString(freq)
00222 + " not found! object must be corrupted.");
00223 GPSTK_THROW(e);
00224 }
00225
00226 const antennaPCOandPCVData& antpco = it->second;
00227 const azimZenMap& azzenmap = antpco.PCVvalue;
00228
00229 if(!antpco.hasAzimuth)
00230 jt_hi = azzenmap.begin();
00231 else
00232 jt_hi = azzenmap.find(azim);
00233
00234
00235 if(jt_hi != azzenmap.end()) {
00236
00237 const zenOffsetMap& zenoffmap = jt_hi->second;
00238
00239 evaluateZenithMap(zen, zenoffmap, zn_lo, zn_hi, pco[2], pco[0]);
00240 if(zn_lo == zn_hi)
00241 retpco = pco[0];
00242 else
00243 retpco = (pco[0]*(zen - zn_lo) + pco[2]*(zn_hi - zen))/(zn_hi - zn_lo);
00244 }
00245
00246 else {
00247
00248 jt_lo = jt_hi = azzenmap.lower_bound(azim);
00249
00250 if(jt_lo == azzenmap.end()) {
00251 jt_lo--;
00252 az_lo = jt_lo->first;
00253 jt_hi = azzenmap.begin();
00254 az_hi = jt_hi->first + 360.;
00255 }
00256 else if(jt_hi == azzenmap.begin()) {
00257 az_hi = jt_hi->first;
00258 (jt_lo = azzenmap.end())--;
00259 az_lo = jt_lo->first - 360.;
00260 }
00261 else {
00262 az_hi = jt_hi->first;
00263 jt_lo--;
00264 az_lo = jt_lo->first;
00265 }
00266
00267
00268 evaluateZenithMap(zen, jt_hi->second, zn_lo, zn_hi, pco[3], pco[1]);
00269 evaluateZenithMap(zen, jt_lo->second, zn_lo, zn_hi, pco[2], pco[0]);
00270
00271
00272 if(zn_hi == zn_lo)
00273 retpco = (pco[2]*(az_hi - azim) + pco[3]*(azim - az_lo))/(az_hi - az_lo);
00274 else
00275 retpco = ( pco[0] * (az_hi - azim)*(zen - zn_lo)
00276 + pco[1] * (azim - az_lo)*(zen - zn_lo)
00277 + pco[2] * (az_hi - azim)*(zn_hi - zen)
00278 + pco[3] * (azim - az_lo)*(zn_hi - zen) )
00279 / ( (az_hi - az_lo)*(zn_hi - zn_lo) );
00280 }
00281
00282
00283 return retpco;
00284 }
00285
00286 void AntexData::dump(ostream& s, int detail) const
00287 {
00288 map<int, antennaPCOandPCVData>::const_iterator it;
00289 map<double, zenOffsetMap>::const_iterator jt;
00290 map<double, double>::const_iterator kt;
00291
00292 s << "Antenna Type/SN: [" << name() << "]";
00293 if(isRxAntenna)
00294 s << " (Receiver)" << endl;
00295 else {
00296 if(PRN != -1 || SVN != -1) {
00297 s << " (" << (type == string("GLONASS") ? "GLONASS" : "GPS");
00298 if(PRN != -1) s << string(" PRN ") + asString(PRN);
00299 if(SVN != -1) s << string(" SVN ") + asString(SVN);
00300 s << ")";
00301 }
00302 s << " Sat. code: " << satCode
00303 << " COSPAR ID: " << cospar << endl;
00304 }
00305
00306 if(detail <= 0) return;
00307
00308 s << "Method: " << method << " Agency: " << agency
00309 << " #Cal.Ant.s: " << noAntCalibrated << " Date: " << date << endl;
00310 if(azimDelta > 0.0)
00311 s << "Azimuth dependence, delta azimuth = "
00312 << fixed << setprecision(1) << azimDelta << endl;
00313 else
00314 s << "No azimuth dependence" << endl;
00315 s << "Elevation dependence: from "
00316 << fixed << setprecision(1) << zenRange[0] << " to " << zenRange[1]
00317 << " in steps of " << zenRange[2] << " degrees." << endl;
00318 s << "Frequencies stored (" << nFreq << "): ";
00319
00320 it = freqPCVmap.begin();
00321 while(it != freqPCVmap.end()) {
00322 s << " " << (serialNo[0]=='G' ? "L" : "") << it->first;
00323 it++;
00324 }
00325 s << endl;
00326 s << "Valid FROM "
00327 << (validFrom == DayTime::BEGINNING_OF_TIME ? " (all time) "
00328 : validFrom.printf("%02m/%02d/%04Y %02H:%02M:%.7s"))
00329 << " TO "
00330 << (validUntil == DayTime::END_OF_TIME ? " (all time) "
00331 : validUntil.printf("%02m/%02d/%04Y %02H:%02M:%.7s"))
00332 << endl;
00333 if(!sinexCode.empty())
00334 s << "SINEX code: " << sinexCode << endl;
00335 for(int i=0; i<commentList.size(); i++) {
00336
00337 s << "Comment " << setw(2) << i+1 << ": " << commentList[i] << endl;
00338 }
00339
00340 if(detail == 1) {
00341 for(it = freqPCVmap.begin(); it != freqPCVmap.end(); it++) {
00342 const antennaPCOandPCVData& antpco = it->second;
00343 s << "PCO (" << (isRxAntenna ? "NEU from antenna reference position"
00344 : "body XYZ from center-of-mass") << ") (mm):"
00345 << " (freq " << it->first << ") "
00346 << fixed << setprecision(2) << setw(10) << antpco.PCOvalue[0]
00347 << ", " << setw(10) << antpco.PCOvalue[1]
00348 << ", " << setw(10) << antpco.PCOvalue[2] << endl;
00349 }
00350 return;
00351 }
00352
00353
00354 for(it = freqPCVmap.begin(); it != freqPCVmap.end(); it++) {
00355 s << "Offset values for frequency: " << it->first
00356 << " (" << (it->second.hasAzimuth ? "has" : "does not have")
00357 << " azimuths)" << endl;
00358 const antennaPCOandPCVData& antpco = it->second;
00359
00360
00361 s << " PCO (" << (isRxAntenna ? "NEU from antenna reference position"
00362 : "body XYZ from center-of-mass") << ") (mm):"
00363 << fixed << setprecision(2) << setw(10) << antpco.PCOvalue[0]
00364 << ", " << setw(10) << antpco.PCOvalue[1]
00365 << ", " << setw(10) << antpco.PCOvalue[2] << endl;
00366
00367
00368 if(valid & neuFreqRMSValid)
00369 s << " RMS PCO ("
00370 << (isRxAntenna ? "NEU from antenna reference position"
00371 : "body XYZ from center-of-mass") << " (mm):"
00372 << fixed << setprecision(2) << setw(10) << antpco.PCOrms[0]
00373 << ", " << setw(10) << antpco.PCOrms[1]
00374 << ", " << setw(10) << antpco.PCOrms[2] << endl;
00375
00376
00377 const azimZenMap& azel = antpco.PCVvalue;
00378 s << fixed << setprecision(2);
00379
00380 jt = azel.begin();
00381 const zenOffsetMap& zenoffmap = jt->second;
00382 s << " PCVs follow, one azimuth per row: AZ(deg) { PCVs(EL)(mm) .. .. }\n";
00383 s << " EL(deg)";
00384 for(kt = zenoffmap.begin(); kt != zenoffmap.end(); kt++)
00385 s << setw(8) << kt->first;
00386 s << endl;
00387
00388 for(jt = azel.begin(); jt != azel.end(); jt++) {
00389 double azimuth = jt->first;
00390 const zenOffsetMap& zenoffmap = jt->second;
00391 if(azimuth == -1.0) s << " (NOAZI)";
00392 else s << setw(9) << azimuth;
00393 for(kt = zenoffmap.begin(); kt != zenoffmap.end(); kt++)
00394 s << setw(8) << kt->second;
00395 s << endl;
00396 }
00397 }
00398
00399 }
00400
00401
00402
00403
00404
00405
00406 void AntexData::evaluateZenithMap(const double& zen,
00407 const zenOffsetMap& eomap,
00408 double& zen_lo, double& zen_hi,
00409 double& pco_lo, double& pco_hi) const
00410 throw()
00411 {
00412 map<double, double>::const_iterator kt;
00413
00414
00415 kt = eomap.find(zen);
00416 if(kt != eomap.end()) {
00417 zen_lo = zen_hi = zen;
00418 pco_lo = pco_hi = kt->second;
00419 return;
00420 }
00421
00422
00423 kt = eomap.lower_bound(zen);
00424
00425
00426 if(kt == eomap.end() || kt == eomap.begin()) {
00427 if(kt == eomap.end()) kt--;
00428 zen_lo = zen_hi = zen;
00429 pco_lo = pco_hi = kt->second;
00430 return;
00431 }
00432
00433
00434 zen_hi = kt->first;
00435 pco_hi = kt->second;
00436 kt--;
00437 zen_lo = kt->first;
00438 pco_lo = kt->second;
00439
00440 return;
00441 }
00442
00443 void AntexData::reallyPutRecord(FFStream& ffs) const
00444 throw(exception, FFStreamError, StringException)
00445 {
00446 if(!isValid()) {
00447 FFStreamError fse(string("Cannot write invalid AntexData"));
00448 GPSTK_THROW(fse);
00449 }
00450
00451 int i;
00452 string line;
00453 map<int, antennaPCOandPCVData>::const_iterator it;
00454 map<double, zenOffsetMap>::const_iterator jt;
00455 map<double, double>::const_iterator kt;
00456 AntexStream& strm = dynamic_cast<AntexStream&>(ffs);
00457
00458 line = rightJustify(leftJustify(startAntennaString,20),80);
00459 strm << line << endl;
00460 strm.lineNumber++;
00461
00462 line = leftJustify(type,20);
00463 line += leftJustify(serialNo,20);
00464 line += leftJustify(satCode,10);
00465 line += leftJustify(cospar,10);
00466 line += typeSerNumString;
00467 strm << leftJustify(line,80) << endl;
00468 strm.lineNumber++;
00469
00470 line = leftJustify(method,20);
00471 line += leftJustify(agency,20);
00472 line += leftJustify(rightJustify(asString(noAntCalibrated),6),10);
00473 line += leftJustify(date,10);
00474 line += methodString;
00475 strm << leftJustify(line,80) << endl;
00476 strm.lineNumber++;
00477
00478 line = string(" ");
00479 line += rightJustify(asString(azimDelta,1),6);
00480 line = leftJustify(line,60);
00481 line += daziString;
00482 strm << leftJustify(line,80) << endl;
00483 strm.lineNumber++;
00484
00485 line = string(" ");
00486 line += rightJustify(asString(zenRange[0],1),6);
00487 line += rightJustify(asString(zenRange[1],1),6);
00488 line += rightJustify(asString(zenRange[2],1),6);
00489 line = leftJustify(line,60);
00490 line += zenithString;
00491 strm << leftJustify(line,80) << endl;
00492 strm.lineNumber++;
00493
00494 line = rightJustify(asString(nFreq),6);
00495 line = leftJustify(line,60);
00496 line += numFreqString;
00497 strm << leftJustify(line,80) << endl;
00498 strm.lineNumber++;
00499
00500 if(valid & validFromValid) {
00501 if(stringValidFrom.empty())
00502 line = writeTime(validFrom);
00503 else
00504 line = stringValidFrom;
00505 line = leftJustify(line,60);
00506 line += validFromString;
00507 strm << leftJustify(line,80) << endl;
00508 strm.lineNumber++;
00509 }
00510
00511 if(valid & validUntilValid) {
00512 if(stringValidUntil.empty())
00513 line = writeTime(validUntil);
00514 else
00515 line = stringValidUntil;
00516 line = leftJustify(line,60);
00517 line += validUntilString;
00518 strm << leftJustify(line,80) << endl;
00519 strm.lineNumber++;
00520 }
00521
00522 if(valid & sinexCodeValid) {
00523 line = leftJustify(rightJustify(sinexCode,10),60);
00524 line += sinexCodeString;
00525 strm << leftJustify(line,80) << endl;
00526 strm.lineNumber++;
00527 }
00528
00529 for(i=0; i<commentList.size(); i++) {
00530 line = leftJustify(commentList[i],60);
00531 line += dataCommentString;
00532 strm << leftJustify(line,80) << endl;
00533 strm.lineNumber++;
00534 }
00535
00536
00537 string freqStr;
00538 for(it = freqPCVmap.begin(); it != freqPCVmap.end(); it++) {
00539 const antennaPCOandPCVData& antpco = it->second;
00540
00541 ostringstream oss;
00542 oss << systemChar << setfill('0') << setw(2) << it->first;
00543 freqStr = oss.str();
00544 line = string(" ");
00545 line += freqStr;
00546 line = leftJustify(line,60);
00547 line += startFreqString;
00548 strm << leftJustify(line,80) << endl;
00549 strm.lineNumber++;
00550
00551 line = string();
00552 for(i=0; i<3; i++)
00553 line += rightJustify(asString(antpco.PCOvalue[i],2),10);
00554 line = leftJustify(line,60);
00555 line += neuFreqString;
00556 strm << leftJustify(line,80) << endl;
00557 strm.lineNumber++;
00558
00559
00560 const azimZenMap& azel = antpco.PCVvalue;
00561 for(jt = azel.begin(); jt != azel.end(); jt++) {
00562 const zenOffsetMap& zenoffmap = jt->second;
00563 if(antpco.hasAzimuth && jt->first > -1.0)
00564 line = rightJustify(asString(jt->first,1),8);
00565 else
00566 line = string(" NOAZI");
00567 for(kt = zenoffmap.begin(); kt != zenoffmap.end(); kt++) {
00568 line += rightJustify(asString(kt->second,2),8);
00569 }
00570 strm << line << endl;
00571 strm.lineNumber++;
00572 }
00573
00574 line = string(" ");
00575 line += freqStr;
00576 line = leftJustify(line,60);
00577 line += endOfFreqString;
00578 strm << leftJustify(line,80) << endl;
00579 strm.lineNumber++;
00580 }
00581
00582 if(valid & (startFreqRMSValid|neuFreqRMSValid|endOfFreqRMSValid)) {
00583
00584 for(it = freqPCVmap.begin(); it != freqPCVmap.end(); it++) {
00585 const antennaPCOandPCVData& antpco = it->second;
00586 ostringstream oss;
00587 oss << systemChar << setfill('0') << setw(2) << it->first;
00588 freqStr = oss.str();
00589 line = string(" ");
00590 line += freqStr;
00591 line = leftJustify(line,60);
00592 line += startFreqRMSString;
00593 strm << leftJustify(line,80) << endl;
00594 strm.lineNumber++;
00595
00596 line = string();
00597 for(i=0; i<3; i++)
00598 line += rightJustify(asString(antpco.PCOrms[i],2),10);
00599 line = leftJustify(line,60);
00600 line += neuFreqRMSString;
00601 strm << leftJustify(line,80) << endl;
00602 strm.lineNumber++;
00603
00604
00605 const azimZenMap& azel = antpco.PCVrms;
00606 for(jt = azel.begin(); jt != azel.end(); jt++) {
00607 const zenOffsetMap& zenoffmap = jt->second;
00608 if(antpco.hasAzimuth)
00609 line = rightJustify(asString(jt->first,1),8);
00610 else
00611 line = string(" NOAZI");
00612 for(kt = zenoffmap.begin(); kt != zenoffmap.end(); kt++) {
00613 line += rightJustify(asString(kt->second,2),8);
00614 }
00615 strm << line << endl;
00616 strm.lineNumber++;
00617 }
00618
00619 line = string(" ");
00620 line += freqStr;
00621 line = leftJustify(line,60);
00622 line += endOfFreqRMSString;
00623 strm << leftJustify(line,80) << endl;
00624 strm.lineNumber++;
00625 }
00626 }
00627
00628 line = rightJustify(leftJustify(endOfAntennaString,20),80);
00629 strm << line << endl;
00630 strm.lineNumber++;
00631
00632 }
00633
00634
00635 void AntexData::reallyGetRecord(FFStream& ffs)
00636 throw(exception, FFStreamError, StringUtils::StringException)
00637 {
00638 AntexStream& strm = dynamic_cast<AntexStream&>(ffs);
00639
00640
00641 if(!strm.headerRead) strm >> strm.header;
00642
00643
00644 AntexData ad;
00645 *this = ad;
00646
00647 string line;
00648
00649 while(!(valid & endOfAntennaValid)) {
00650 strm.formattedGetLine(line, true);
00651 stripTrailing(line);
00652
00653 if(line.length() == 0)
00654 continue;
00655
00656 try {
00657 ParseDataRecord(line);
00658 }
00659 catch(FFStreamError& e) {
00660 GPSTK_THROW(e);
00661 }
00662 }
00663
00664 }
00665
00666
00667
00668
00669
00670
00671 void AntexData::throwRecordOutOfOrder(unsigned long test, string& label)
00672 {
00673 if(test & valid) {
00674 FFStreamError fse(string("Records are out of order: detected at ") + label);
00675 GPSTK_THROW(fse);
00676 }
00677 }
00678
00679
00680 void AntexData::ParseDataRecord(string& line)
00681 throw(FFStreamError)
00682 {
00683 try {
00684 static bool hasAzim;
00685 static int freq;
00686 static string freqStr;
00687 string label(line, 60, 20);
00688
00689 if(label == startAntennaString) {
00690 throwRecordOutOfOrder(typeSerNumValid,label);
00691 valid |= startAntennaValid;
00692 }
00693 else if(label == typeSerNumString) {
00694 throwRecordOutOfOrder(methodValid,label);
00695 type = stripTrailing(stripLeading(line.substr(0,20)));
00696
00697 isRxAntenna = true;
00698 for(int i=0; i<AntexData::SatelliteTypes.size(); i++)
00699 if(type == AntexData::SatelliteTypes[i]) { isRxAntenna = false; break; }
00700 serialNo = stripTrailing(stripLeading(line.substr(20,20)));
00701 satCode = stripTrailing(stripLeading(line.substr(40,10)));
00702 cospar = stripTrailing(stripLeading(line.substr(50,10)));
00703 if(!isRxAntenna) {
00704 if(serialNo.length() > 1) PRN = asInt(serialNo.substr(1,2));
00705 else PRN = -1;
00706 if(satCode.length() > 1) SVN = asInt(satCode.substr(1,3));
00707 else SVN = -1;
00708 }
00709 valid |= typeSerNumValid;
00710 }
00711 else if(label == methodString) {
00712 throwRecordOutOfOrder(daziValid,label);
00713 method = stripTrailing(stripLeading(line.substr(0,20)));
00714 agency = stripTrailing(stripLeading(line.substr(20,20)));
00715 noAntCalibrated = asInt(line.substr(40,6));
00716 date = stripTrailing(stripLeading(line.substr(50,10)));
00717 valid |= methodValid;
00718 }
00719 else if(label == daziString) {
00720 throwRecordOutOfOrder(zenithValid,label);
00721 azimDelta = asDouble(line.substr(2,6));
00722 if(azimDelta > 0.0) hasAzim = true; else hasAzim = false;
00723 valid |= daziValid;
00724 }
00725 else if(label == zenithString) {
00726 throwRecordOutOfOrder(numFreqValid,label);
00727 zenRange[0] = asDouble(line.substr(2,6));
00728 zenRange[1] = asDouble(line.substr(8,6));
00729 zenRange[2] = asDouble(line.substr(14,6));
00730 valid |= zenithValid;
00731 }
00732 else if(label == numFreqString) {
00733 throwRecordOutOfOrder(validFromValid|validUntilValid|sinexCodeValid|
00734 dataCommentValid|startFreqValid,label);
00735 nFreq = (unsigned int)(asInt(line.substr(0,6)));
00736 valid |= numFreqValid;
00737 }
00738 else if(label == validFromString) {
00739 throwRecordOutOfOrder(validUntilValid|sinexCodeValid|
00740 dataCommentValid|startFreqValid,label);
00741 stringValidFrom = line.substr(0,43);
00742 validFrom = parseTime(line);
00743 valid |= validFromValid;
00744 }
00745 else if(label == validUntilString) {
00746 throwRecordOutOfOrder(sinexCodeValid|dataCommentValid|startFreqValid,label);
00747 stringValidUntil = line.substr(0,43);
00748 validUntil = parseTime(line);
00749 if(validUntil == DayTime::BEGINNING_OF_TIME)
00750 validUntil = DayTime::END_OF_TIME;
00751 valid |= validUntilValid;
00752 }
00753 else if(label == sinexCodeString) {
00754 throwRecordOutOfOrder(dataCommentValid|startFreqValid,label);
00755 sinexCode = stripTrailing(stripLeading(line.substr(0,10)));
00756 valid |= sinexCodeValid;
00757 }
00758 else if(label == dataCommentString) {
00759 throwRecordOutOfOrder(startFreqValid,label);
00760 string str = stripTrailing(line.substr(0,60));
00761 commentList.push_back(str);
00762 valid |= dataCommentValid;
00763 }
00764 else if(label == startFreqString) {
00765 throwRecordOutOfOrder(startFreqRMSValid|neuFreqRMSValid|endOfFreqRMSValid|
00766 endOfAntennaValid,label);
00767 freqStr = line.substr(3,3);
00768 systemChar = line[3];
00769 if(systemChar == ' ') systemChar = 'G';
00770 freq = asInt(line.substr(4,2));
00771 valid |= startFreqValid;
00772 }
00773 else if(label == neuFreqString) {
00774 throwRecordOutOfOrder(startFreqRMSValid|neuFreqRMSValid|endOfFreqRMSValid|
00775 endOfAntennaValid,label);
00776 freqPCVmap[freq].PCOvalue[0] = asDouble(line.substr(0,10));
00777 freqPCVmap[freq].PCOvalue[1] = asDouble(line.substr(10,10));
00778 freqPCVmap[freq].PCOvalue[2] = asDouble(line.substr(20,10));
00779 valid |= neuFreqValid;
00780
00781 freqPCVmap[freq].hasAzimuth = hasAzim;
00782 }
00783 else if(label == endOfFreqString) {
00784 throwRecordOutOfOrder(startFreqRMSValid|neuFreqRMSValid|endOfFreqRMSValid|
00785 endOfAntennaValid,label);
00786 if(freqStr != line.substr(3,3)) {
00787 FFStreamError fse("START/END OF FREQ confused: "
00788 + freqStr + " != " + line.substr(3,3));
00789 GPSTK_THROW(fse);
00790 }
00791 valid |= endOfFreqValid;
00792 }
00793 else if(label == startFreqRMSString) {
00794 throwRecordOutOfOrder(endOfAntennaValid,label);
00795 freqStr = line.substr(3,3);
00796 freq = asInt(line.substr(4,2));
00797 valid |= startFreqRMSValid;
00798 }
00799 else if(label == neuFreqRMSString) {
00800 throwRecordOutOfOrder(endOfAntennaValid,label);
00801 freqPCVmap[freq].PCOrms[0] = asDouble(line.substr(0,10));
00802 freqPCVmap[freq].PCOrms[1] = asDouble(line.substr(10,10));
00803 freqPCVmap[freq].PCOrms[2] = asDouble(line.substr(20,10));
00804 valid |= neuFreqRMSValid;
00805 }
00806 else if(label == endOfFreqRMSString) {
00807 throwRecordOutOfOrder(endOfAntennaValid,label);
00808 if(freqStr != line.substr(3,3)) {
00809 FFStreamError fse("START/END OF FREQ RMS confused: "
00810 + freqStr + " != " + line.substr(3,3));
00811 GPSTK_THROW(fse);
00812 }
00813 valid |= endOfFreqRMSValid;
00814 }
00815 else if(label == endOfAntennaString) {
00816 valid |= endOfAntennaValid;
00817 }
00818 else {
00819 int i,n;
00820 string noazi = line.substr(3,5);
00821 double azim = asDouble(line.substr(0,8));
00822 if(!hasAzim && noazi != string("NOAZI")) {
00823 FFStreamError fse("Invalid format; zero delta azimuth without NOAZI");
00824 GPSTK_THROW(fse);
00825 }
00826
00827
00828 if(noazi == string("NOAZI")) azim = -1.0;
00829
00830 n = StringUtils::numWords(line) - 1;
00831 if(n != 1+int((zenRange[1]-zenRange[0])/zenRange[2])) {
00832 FFStreamError fse("Invalid format; wrong number of zenith/offset values");
00833 GPSTK_THROW(fse);
00834 }
00835
00836
00837 for(i=1; i<=n; i++) {
00838 double value = asDouble(line.substr(8*i,8));
00839 double zen = zenRange[0] + (i-1)*zenRange[2];
00840 if(valid & neuFreqRMSValid)
00841 freqPCVmap[freq].PCVrms[azim][zen] = value;
00842 else if(valid & neuFreqValid)
00843 freqPCVmap[freq].PCVvalue[azim][zen] = value;
00844 }
00845
00846 }
00847
00848 }
00849 catch(FFStreamError& fse) { GPSTK_RETHROW(fse); }
00850 }
00851
00852 DayTime AntexData::parseTime(const string& line) const
00853 throw(FFStreamError)
00854 {
00855 try
00856 {
00857
00858 DayTime time = DayTime::BEGINNING_OF_TIME;
00859
00860 if (line.substr(0,42) == string(42,' '))
00861 return time;
00862
00863
00864
00865
00866
00867 if((line.substr( 0,2) != string(2,' ')) ||
00868 (line.substr( 6,4) != string(4,' ')) ||
00869 (line.substr(12,4) != string(4,' ')) ||
00870 (line.substr(18,4) != string(4,' ')) ||
00871 (line.substr(24,4) != string(4,' ')) ||
00872 (line[43] != ' '))
00873 {
00874 FFStreamError e("Invalid time format");
00875 GPSTK_THROW(e);
00876 }
00877
00878
00879 int year, month, day, hour, min;
00880 double sec;
00881
00882 year = asInt( line.substr( 2, 4));
00883 month = asInt( line.substr(10, 4));
00884 day = asInt( line.substr(16, 4));
00885 hour = asInt( line.substr(22, 4));
00886 min = asInt( line.substr(28, 4));
00887 sec = asDouble(line.substr(30,13));
00888
00889 time.setYMDHMS(year, month, day, hour, min, sec);
00890
00891 return time;
00892 }
00893
00894 catch (exception &e)
00895 {
00896 FFStreamError err("std::exception: " + string(e.what()));
00897 GPSTK_THROW(err);
00898 }
00899 catch (Exception& e)
00900 {
00901 string text;
00902 for(int i=0; i<e.getTextCount(); i++) text += e.getText(i);
00903 FFStreamError err("Exception in parseTime(): " + text);
00904 GPSTK_THROW(err);
00905 }
00906 }
00907
00908 string AntexData::writeTime(const DayTime& dt) const
00909 throw(StringException)
00910 {
00911 if(dt == DayTime::BEGINNING_OF_TIME || dt == DayTime::END_OF_TIME)
00912 return string(43,' ');
00913
00914
00915
00916 string line;
00917 line = string(2,' ');
00918 line += rightJustify(asString<short>(dt.year()),4);
00919 line += string(4,' ');
00920 line += rightJustify(asString<short>(dt.month()),2);
00921 line += string(4,' ');
00922 line += rightJustify(asString<short>(dt.day()),2);
00923 line += string(4,' ');
00924 line += rightJustify(asString<short>(dt.hour()),2);
00925 line += string(4,' ');
00926 line += rightJustify(asString<short>(dt.minute()),2);
00927 line += rightJustify(asString(dt.second(),7),13);
00928
00929 return line;
00930 }
00931
00932 }