RinexMetHeader.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: RinexMetHeader.cpp 438 2007-03-21 17:22:21Z btolman $"
00002 
00003 
00004 
00005 //============================================================================
00006 //
00007 //  This file is part of GPSTk, the GPS Toolkit.
00008 //
00009 //  The GPSTk is free software; you can redistribute it and/or modify
00010 //  it under the terms of the GNU Lesser General Public License as published
00011 //  by the Free Software Foundation; either version 2.1 of the License, or
00012 //  any later version.
00013 //
00014 //  The GPSTk is distributed in the hope that it will be useful,
00015 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 //  GNU Lesser General Public License for more details.
00018 //
00019 //  You should have received a copy of the GNU Lesser General Public
00020 //  License along with GPSTk; if not, write to the Free Software Foundation,
00021 //  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //  
00023 //  Copyright 2004, The University of Texas at Austin
00024 //
00025 //============================================================================
00026 
00027 //============================================================================
00028 //
00029 //This software developed by Applied Research Laboratories at the University of
00030 //Texas at Austin, under contract to an agency or agencies within the U.S. 
00031 //Department of Defense. The U.S. Government retains all rights to use,
00032 //duplicate, distribute, disclose, or release this software. 
00033 //
00034 //Pursuant to DoD Directive 523024 
00035 //
00036 // DISTRIBUTION STATEMENT A: This software has been approved for public 
00037 //                           release, distribution is unlimited.
00038 //
00039 //=============================================================================
00040 
00041 
00042 
00043 
00044 
00045 
00051 #include <algorithm>       // for find
00052 
00053 #include "StringUtils.hpp"
00054 #include "DayTime.hpp"
00055 #include "RinexMetHeader.hpp"
00056 #include "RinexMetStream.hpp"
00057 
00058 using namespace gpstk::StringUtils;
00059 using namespace std;
00060 
00061 namespace gpstk
00062 {
00063    const int RinexMetHeader::maxObsPerLine = 9;
00064 
00065    const string RinexMetHeader::versionString = "RINEX VERSION / TYPE";
00066    const string RinexMetHeader::runByString = "PGM / RUN BY / DATE";
00067    const string RinexMetHeader::commentString = "COMMENT";
00068    const string RinexMetHeader::markerNameString = "MARKER NAME";
00069    const string RinexMetHeader::markerNumberString = "MARKER NUMBER";
00070    const string RinexMetHeader::obsTypeString = "# / TYPES OF OBSERV";
00071    const string RinexMetHeader::sensorTypeString = "SENSOR MOD/TYPE/ACC";
00072    const string RinexMetHeader::sensorPosString = "SENSOR POS XYZ/H";
00073    const string RinexMetHeader::endOfHeader = "END OF HEADER";
00074 
00075 
00076    
00077    std::string RinexMetHeader::bitString(unsigned long vb, char quote,
00078                                          std::string sep)
00079    {
00080       unsigned long b = 1;
00081       std::string rv;
00082       while (b)
00083       {
00084          if (vb & b)
00085          {
00086             if (rv.length())
00087                rv += sep;
00088             if (quote)
00089                rv += quote + bitsAsString((validBits)b) + quote;
00090             else
00091                rv += bitsAsString((validBits)b);
00092          }
00093          b <<= 1;
00094       }
00095       return rv;
00096    }
00097 
00098    void RinexMetHeader::reallyPutRecord(FFStream& ffs) const
00099       throw(std::exception, FFStreamError,
00100             gpstk::StringUtils::StringException)
00101    {
00102       RinexMetStream& strm = dynamic_cast<RinexMetStream&>(ffs);
00103       
00104          // since they want to output this header, let's store
00105          // it internally for use by the data
00106       strm.header = (*this);
00107       
00108          // i'm casting out const here to set the correct required valid bits.
00109          // deal with it =P
00110          
00111 
00112       unsigned long allValid;
00113       if (version == 2.0)        allValid = allValid20;
00114       else if (version == 2.1)   allValid = allValid21;
00115       else
00116       {
00117          FFStreamError err("Unknown RINEX version: " + asString(version,2));
00118          err.addText("Make sure to set the version correctly.");
00119          GPSTK_THROW(err);
00120       }
00121       
00122       if ((valid & allValid) != allValid)
00123       {
00124          string errstr("Incomplete or invalid header: missing: ");
00125          errstr += bitString(allValid & ~valid);
00126          FFStreamError err(errstr);
00127          err.addText("Make sure you set all header valid bits for all of the available data.");
00128          GPSTK_THROW(err);
00129       }
00130       
00131       string line;
00132          // line by line, let's do this.
00133       if (valid & versionValid)
00134       {
00135          line  = rightJustify(asString(version,2), 9);
00136          line += string(11, ' ');
00137          line += leftJustify(fileType, 40);
00138          line += versionString;
00139          strm << line << endl;
00140          strm.lineNumber++;
00141       }
00142       if (valid & runByValid)
00143       {
00144          line  = leftJustify(fileProgram,20);
00145          line += leftJustify(fileAgency,20);
00146          DayTime dt;
00147          dt.setLocalTime();
00148          string dat = dt.printf("%02m/%02d/%04Y %02H:%02M:%02S");
00149          line += leftJustify(dat, 20);
00150          line += runByString;
00151          strm << line << endl;
00152          strm.lineNumber++;
00153       }
00154       if (valid & commentValid)
00155       {
00156          vector<string>::const_iterator itr = commentList.begin();
00157          while (itr != commentList.end())
00158          {
00159             line  = leftJustify((*itr), 60);
00160             line += commentString;
00161             strm << line << endl;
00162             strm.lineNumber++;
00163             itr++;
00164          }
00165       }
00166       if (valid & markerNameValid)
00167       {
00168          line  = leftJustify(markerName, 60);
00169          line += markerNameString;
00170          strm << line << endl;
00171          strm.lineNumber++;
00172       }
00173       if (valid & markerNumberValid)
00174       {
00175          line  = leftJustify(markerNumber, 60);
00176          line += markerNumberString;
00177          strm << line << endl;
00178          strm.lineNumber++;
00179       }
00180       if (valid & obsTypeValid)
00181       {
00182          line  = rightJustify(asString(obsTypeList.size()),6);
00183          vector<RinexMetType>::const_iterator itr = obsTypeList.begin();
00184          size_t numWritten = 0;
00185          while (itr != obsTypeList.end())
00186          {
00187             numWritten++;
00188                // stupid continuation lines =P
00189             if ((numWritten % (maxObsPerLine+1)) == 0)
00190             {
00191                line += obsTypeString;
00192                strm << line << endl;
00193                strm.lineNumber++;
00194                line = string(6,' ');
00195             }
00196             line += rightJustify(convertObsType(*itr), 6);
00197             itr++;
00198          }
00199             // pad the line out to 60 chrs and add label
00200          line += string(60 - line.size(), ' ');
00201          line += obsTypeString;
00202          strm << line << endl;
00203          strm.lineNumber++;
00204       }
00205       if (valid & sensorTypeValid)
00206       {
00207             // only write out the sensor types that are 
00208             // in the obsTypeList
00209          vector<sensorType>::const_iterator itr = sensorTypeList.begin();
00210          while (itr != sensorTypeList.end())
00211          {
00212             if (std::find(obsTypeList.begin(), obsTypeList.end(),
00213                           (*itr).obsType) != obsTypeList.end())
00214             {
00215                line  = leftJustify((*itr).model, 20);
00216                line += leftJustify((*itr).type, 20);
00217                line += string(6, ' ');
00218                line += rightJustify(asString((*itr).accuracy,1),7);
00219                line += string(4, ' ');
00220                line += convertObsType((*itr).obsType);
00221                line += string(1, ' ');
00222                line += sensorTypeString;
00223                strm << line << endl;
00224                strm.lineNumber++;
00225             }
00226             itr++;
00227          }
00228       }
00229       if (valid & sensorPosValid)
00230       {
00231             // only write out the sensor positions that are 
00232             // in the obsTypeList
00233          vector<sensorPosType>::const_iterator itr = sensorPosList.begin();
00234          while (itr != sensorPosList.end())
00235          {
00236             if (std::find(obsTypeList.begin(), obsTypeList.end(),
00237                      (*itr).obsType) != obsTypeList.end())
00238             {
00239                line  = rightJustify(asString((*itr).position[0],4),14);
00240                line += rightJustify(asString((*itr).position[1],4),14);
00241                line += rightJustify(asString((*itr).position[2],4),14);
00242                line += rightJustify(asString((*itr).height,4),14);
00243                line += string(1, ' ');
00244                line += convertObsType((*itr).obsType);
00245                line += string(1, ' ');
00246                line += sensorPosString;
00247                strm << line << endl;
00248                strm.lineNumber++;
00249             }
00250             itr++;
00251          }
00252       }
00253       if (valid & endValid)
00254       {
00255          line  = string(60, ' ');
00256          line += endOfHeader;
00257          strm << line << endl;
00258          strm.lineNumber++;
00259       }
00260    }     
00261    
00262 
00263    void RinexMetHeader::reallyGetRecord(FFStream& ffs) 
00264       throw(std::exception, FFStreamError, 
00265             gpstk::StringUtils::StringException)
00266    {
00267 
00268       RinexMetStream& strm = dynamic_cast<RinexMetStream&>(ffs);
00269          // if already read, just return
00270       if (strm.headerRead == true)
00271          return;
00272 
00273       valid = 0;
00274       
00275          // clear out structures in case the last read was a partial header
00276          // and there's cruft left
00277       commentList.clear();
00278       obsTypeList.clear();
00279       sensorTypeList.clear();
00280       sensorPosList.clear();
00281       
00282       int numObs;
00283       
00284       while (! (valid & endValid))
00285       {
00286          string line;
00287          strm.formattedGetLine(line);
00288          
00289          if (line.length()<60 || line.length()>81)
00290          {
00291             FFStreamError e("Bad line length");
00292             GPSTK_THROW(e);
00293          }
00294          
00295          string thisLabel(line, 60, 20);
00296          
00297          if (thisLabel == versionString)
00298          {
00299             version = asDouble(line.substr(0,20));
00300             fileType = strip(line.substr(20,20));
00301             if ( (fileType[0] != 'M') &&
00302                  (fileType[0] != 'm'))
00303             {
00304                FFStreamError e("This isn't a Rinex Met file");
00305                GPSTK_THROW(e);
00306             }
00307             valid |= versionValid;
00308          }
00309          else if (thisLabel == runByString)
00310          {
00311             fileProgram = strip(line.substr(0,20));
00312             fileAgency = strip(line.substr(20,20));
00313             date = strip(line.substr(40,20));
00314             valid |= runByValid;
00315          }
00316          else if (thisLabel == commentString)
00317          {
00318             commentList.push_back(strip(line.substr(0,60)));
00319             valid |= commentValid;
00320          }
00321          else if (thisLabel == markerNameString)
00322          {
00323             markerName = strip(line.substr(0,60));
00324             valid |= markerNameValid;
00325          }
00326          else if (thisLabel == markerNumberString)
00327          {
00328             markerNumber = strip(line.substr(0,20));
00329             valid |= markerNumberValid;
00330          }
00331          else if (thisLabel == obsTypeString)
00332          {
00333                // read the first line
00334             if (! (valid & obsTypeValid))
00335             {
00336                numObs = gpstk::StringUtils::asInt(line.substr(0,6));
00337                for (int i = 0; (i < numObs) && (i < maxObsPerLine); i++)
00338                {
00339                   int currPos = i * 6 + 6;
00340                   if (line.substr(currPos, 4) != string(4, ' '))
00341                   {
00342                      FFStreamError e("Format error for line type " +
00343                                      obsTypeString);
00344                      GPSTK_THROW(e);
00345                   }
00346                   
00347                   obsTypeList.push_back(convertObsType(line.substr(currPos + 4, 2)));
00348                }
00349                valid |= obsTypeValid;
00350             }
00351                // read continuation lines
00352             else
00353             {
00354                int currentObsTypes = obsTypeList.size();
00355                for (int i = currentObsTypes; 
00356                     (i < numObs) && (i < (maxObsPerLine + currentObsTypes));
00357                     i++)
00358                {
00359                   int currPos = (i % maxObsPerLine) * 6 + 6;
00360                   if (line.substr(currPos, 4) != string(4,' '))
00361                   {
00362                      FFStreamError e("Format error for line type " +
00363                                      obsTypeString);
00364                      GPSTK_THROW(e);
00365                   }
00366                   obsTypeList.push_back(convertObsType(line.substr(currPos + 4, 2)));
00367                }
00368             }
00369          }
00370          else if (thisLabel == sensorTypeString)
00371          {
00372             if (line.substr(40,6) != string(6, ' '))
00373             {
00374                FFStreamError e("Format error for line type " + 
00375                                sensorTypeString);
00376                GPSTK_THROW(e);
00377             }
00378             sensorType st;
00379             st.model = strip(line.substr(0,20));
00380             st.type = strip(line.substr(20,20));
00381             st.accuracy = asDouble(line.substr(46,9));
00382             st.obsType = convertObsType(line.substr(57,2));
00383             
00384             sensorTypeList.push_back(st);
00385             
00386                // only set this valid if there are exactly
00387                // the same number in both lists
00388             if (sensorTypeList.size() == obsTypeList.size())
00389             {
00390                valid |= sensorTypeValid;
00391             }
00392             else
00393             {
00394                valid &= ~(long)sensorTypeValid;
00395             }
00396          }
00397          else if (thisLabel == sensorPosString)
00398          {
00399                // read XYZ and H and obs type
00400             sensorPosType sp;
00401             sp.position[0] = asDouble(line.substr(0,14));
00402             sp.position[1] = asDouble(line.substr(14,14));
00403             sp.position[2] = asDouble(line.substr(28,14));
00404             sp.height = asDouble(line.substr(42,14));
00405             
00406             sp.obsType = convertObsType(line.substr(57,2));
00407             
00408             sensorPosList.push_back(sp);
00409             
00410                // only barometer is required, so
00411                // set it valid only if you see that record.
00412             if (sp.obsType == PR)
00413             {
00414                valid |= sensorPosValid;
00415             }
00416          }
00417          else if (thisLabel == endOfHeader)
00418          {
00419             valid |= endValid;
00420          }
00421          else
00422          {
00423             FFStreamError e("Unknown header label " + thisLabel);
00424             GPSTK_THROW(e);
00425          }
00426       }
00427       
00428       unsigned long allValid;
00429       if      (version == 2.0)      allValid = allValid20;
00430       else if (version == 2.1)      allValid = allValid21;
00431       else
00432       {
00433          FFStreamError e("Unknown or unsupported RINEX version " + 
00434                          asString(version));
00435          GPSTK_THROW(e);
00436       }
00437       
00438       if ( (allValid & valid) != allValid)
00439       {
00440          string errstr("Incomplete or invalid header: missing: ");
00441          errstr += bitString(allValid & ~valid);
00442          FFStreamError err(errstr);
00443          GPSTK_THROW(err);               
00444       }
00445       
00446          // we got here, so something must be right...
00447       strm.header = *this;
00448       strm.headerRead = true;
00449    } 
00450 
00451    void RinexMetHeader::dump(ostream& s) const
00452    {
00453       s << "Marker " << markerName << endl;
00454 
00455       if (!obsTypeList.empty())
00456       {
00457          cout << "Obs types:" << endl;
00458          vector<RinexMetType>::const_iterator itr = obsTypeList.begin();
00459          while (itr != obsTypeList.end())
00460          {
00461             cout << convertObsType(*itr) << " ";
00462             itr++;
00463          }
00464          cout << endl;
00465       }
00466    }
00467 
00468 
00469    RinexMetHeader::RinexMetType 
00470    RinexMetHeader::convertObsType(const string& oneObs)
00471       throw(FFStreamError)
00472    {
00473       if      (oneObs == "PR") return PR;
00474       else if (oneObs == "TD") return TD;
00475       else if (oneObs == "HR") return HR;
00476       else if (oneObs == "ZW") return ZW;
00477       else if (oneObs == "ZD") return ZD;
00478       else if (oneObs == "ZT") return ZT;
00479       else if (oneObs == "WD") return WD;
00480       else if (oneObs == "WS") return WS;
00481       else if (oneObs == "RI") return RI;
00482       else if (oneObs == "HI") return HI;
00483       else
00484       {
00485          FFStreamError e("Bad obs type:" + oneObs);
00486          GPSTK_THROW(e);
00487       } 
00488    }
00489 
00490    string RinexMetHeader::convertObsType(const RinexMetHeader::RinexMetType& oneObs)
00491       throw(FFStreamError)
00492    {
00493       if      (oneObs == PR) return "PR";
00494       else if (oneObs == TD) return "TD";
00495       else if (oneObs == HR) return "HR";
00496       else if (oneObs == ZW) return "ZW";
00497       else if (oneObs == ZD) return "ZD";
00498       else if (oneObs == ZT) return "ZT";
00499       else if (oneObs == WD) return "WD";
00500       else if (oneObs == WS) return "WS";
00501       else if (oneObs == RI) return "RI";
00502       else if (oneObs == HI) return "HI";
00503       else
00504       {
00505          FFStreamError e("Bad obs type:" + asString(oneObs));
00506          GPSTK_THROW(e);
00507       } 
00508    }
00509 
00510 
00511 } // namespace

Generated on Thu Sep 9 03:30:55 2010 for GPS ToolKit Software Library by  doxygen 1.3.9.1