55 #if (_MSC_VER == 1700)
56 #define strtoll _strtoi64
64 using namespace StringUtils;
66 const string RinexClockHeader::versionString =
"RINEX VERSION / TYPE";
67 const string RinexClockHeader::runByString =
"PGM / RUN BY / DATE";
68 const string RinexClockHeader::commentString =
"COMMENT";
69 const string RinexClockHeader::leapSecondsString =
"LEAP SECONDS";
70 const string RinexClockHeader::dataTypesString =
"# / TYPES OF DATA";
71 const string RinexClockHeader::stationNameString =
"STATION NAME / NUM";
72 const string RinexClockHeader::calibrationClkString =
"STATION CLK REF";
73 const string RinexClockHeader::acNameString =
"ANALYSIS CENTER";
74 const string RinexClockHeader::numRefClkString =
"# OF CLK REF";
75 const string RinexClockHeader::analysisClkRefString =
"ANALYSIS CLK REF";
76 const string RinexClockHeader::numStationsString =
"# OF SOLN STA / TRF";
77 const string RinexClockHeader::solnStaNameString =
"SOLN STA NAME / NUM";
78 const string RinexClockHeader::numSatsString =
"# OF SOLN SATS";
79 const string RinexClockHeader::prnListString =
"PRN LIST";
80 const string RinexClockHeader::endOfHeader =
"END OF HEADER";
83 bool RinexClockHeader::isValid()
const
85 if ( !(dataTypeList.size() >= 1) )
90 list<RinexClkType>::const_iterator itr;
91 for (itr = dataTypeList.begin(); itr != dataTypeList.end(); itr++)
95 if ( !(
valid & allValidAR) )
100 if ( !(
valid & allValidAS) )
105 if ( !(
valid & allValidCR) )
110 if ( !(
valid & allValidDR) )
115 if ( !(
valid & allValidMS) )
127 void RinexClockHeader::clear()
137 dataTypeList.clear();
139 stationNumber.clear();
140 stationClkRef.clear();
155 s <<
"---------------------- REQUIRED ---------------------" << endl;
156 s <<
"Rinex Version: " << fixed << setw(4) << setprecision(2) <<
version
157 <<
", File type: " <<
fileType << endl;
160 <<
", Date: " <<
date << endl;
162 s <<
"Clock data types: ";
163 bool ar, as, cr, dr, ms;
164 ar = as = cr = dr = ms =
false;
165 list<RinexClkType>::const_iterator dataTypeListItr;
166 for(dataTypeListItr = dataTypeList.begin();
167 dataTypeListItr != dataTypeList.end(); dataTypeListItr++)
170 if (*dataTypeListItr == AS) as =
true;
171 else if (*dataTypeListItr == AR) ar =
true;
172 else if (*dataTypeListItr == CR) cr =
true;
173 else if (*dataTypeListItr == DR) dr =
true;
174 else if (*dataTypeListItr == MS) ms =
true;
178 if ( cr || dr || (
valid & stationNameValid) )
180 s <<
"Station/Reciever: " << stationName
181 <<
' ' << stationNumber << endl;
184 if ( cr || (
valid & calibrationClkValid) )
186 s <<
"Station Clock Ref: " << stationClkRef << endl;
189 if ( ar || as || ms || (
valid & acNameValid) )
191 s <<
"Analysis Center: " << ac
192 <<
' ' << acName << endl;
195 if ( ar || as || (
valid & numRefClkValid) )
197 list<RefClkRecord>::const_iterator refClkListItr;
198 for (refClkListItr = refClkList.begin();
199 refClkListItr != refClkList.end(); refClkListItr++)
201 s <<
"Clock References from: " << refClkListItr->startEpoch
202 <<
", to: " << refClkListItr->stopEpoch
203 <<
", count: " << refClkListItr->numClkRef
205 list<RefClk>::const_iterator clocksItr;
206 for (clocksItr = refClkListItr->clocks.begin();
207 clocksItr != refClkListItr->clocks.end(); clocksItr++)
209 s <<
" " <<
"name: " << clocksItr->name
210 <<
", number: " << clocksItr->number
211 <<
", constraint: " << clocksItr->clkConstraint
217 if ( ar || as || (
valid & numStationsValid) )
219 s <<
"# of Solution Stations: " << numSta
224 if ( ar || as || (
valid & solnStaNameValid) )
226 list<SolnSta>::const_iterator solnStaListItr;
227 for (solnStaListItr = solnStaList.begin();
228 solnStaListItr != solnStaList.end(); solnStaListItr++)
230 s <<
"Soln. station/reciever name: " << solnStaListItr->name
231 <<
", number: " << solnStaListItr->number
240 if ( as || (
valid & numSatsValid) )
242 s <<
"Soln. PRN count: " << numSats << endl;
245 if ( as || (
valid & prnListValid) )
248 list<SatID>::const_iterator prnListItr;
249 for (prnListItr =
prnList.begin();
250 prnListItr !=
prnList.end(); prnListItr++)
254 switch(prnListItr->system)
256 case SatelliteSystem::GPS: sat =
"G";
break;
257 case SatelliteSystem::Glonass: sat =
"R";
break;
258 default: sat =
"?";
break;
266 s <<
"---------------------- OPTIONAL* --------------------" << endl;
267 s <<
"*If data type is AS or AR some comments are required." << endl;
269 if ( as || ar || (
valid & commentValid) )
271 s <<
"Comment(s): " << endl;
272 list<string>::const_iterator commentListItr;
273 for (commentListItr = commentList.begin();
274 commentListItr != commentList.end(); commentListItr++)
276 s <<
" " << *commentListItr << endl;
280 if (
valid & leapSecondsValid )
282 s <<
"Leap Seconds: " << leapSeconds << endl;
285 s <<
"-------------------- END OF HEADER ------------------" << endl;
290 void RinexClockHeader::reallyPutRecord(
FFStream& ffs)
const
298 FFStreamError
err(
"Incomplete or invalid header.");
299 err.addText(
"Make sure you set all header valid bits for all "
300 "of the available data.");
304 if (
valid & versionValid)
306 strm << right << setw(9) << setprecision(2) << fixed <<
version << left
310 if (
valid & runByValid)
317 if (
valid & commentValid)
319 list<string>::const_iterator itr;
320 for (itr = commentList.begin(); itr != commentList.end(); itr++)
322 strm << setw(60) << (*itr) << commentString <<
endlpp;
325 if (
valid & leapSecondsValid)
327 strm << right << setw(6) << leapSeconds << left
328 << setw(54) <<
' ' << leapSecondsString <<
endlpp;
330 if (
valid & dataTypesValid )
332 strm << right << setw(6) << numType;
333 for (
const auto& itr : dataTypeList)
335 strm <<
" " << right << setw(2) << itr.type;
337 strm << left << setw(54 - ((dataTypeList.size())*6)) <<
' '
338 << dataTypesString <<
endlpp;
340 if (
valid & stationNameValid )
342 strm << setw(4) << stationName
343 <<
' ' << setw(20) << stationNumber
344 << setw(35) <<
' ' << stationNameString <<
endlpp;
346 if (
valid & calibrationClkValid )
348 strm << setw(60) << stationClkRef << calibrationClkString <<
endlpp;
350 if (
valid & acNameValid )
352 strm << setw(3) << ac <<
" " << setw(55) << acName << acNameString
355 if (
valid & numStationsValid )
357 for (
const auto& recItr : refClkList)
359 strm << right << setw(6) << recItr.numClkRef << left
360 <<
' ' << writeTime(recItr.startEpoch)
361 <<
' ' << writeTime(recItr.stopEpoch)
362 << numRefClkString <<
endlpp;
364 for (
const auto& clkItr : recItr.clocks)
366 strm << setw(4) << clkItr.name
367 <<
' ' << setw(20) << clkItr.number
369 if (clkItr.clkConstraint != 0)
371 strm << clkItr.clkConstraint;
375 strm << setw(19) <<
' ';
377 strm <<
' ' << analysisClkRefString <<
endlpp;
381 if (
valid & numStationsValid )
383 strm << right << setw(6) << numSta << left
384 <<
" " << setw(50) << trf
385 << numStationsString <<
endlpp;
387 if (
valid & solnStaNameValid )
389 for (
const auto& itr : solnStaList)
391 strm << setw(4) << itr.name
392 <<
' ' << setw(20) << itr.number
393 << right << setw(11) << itr.posX <<
' '
394 << right << setw(11) << itr.posY <<
' '
395 << right << setw(11) << itr.posZ << left
396 << solnStaNameString <<
endlpp;
399 if (
valid & numSatsValid )
401 strm << right << setw(6) << numSats << left << setw(54) <<
' '
402 << numSatsString <<
endlpp;
404 if (
valid & prnListValid )
407 for (
const auto& itr :
prnList)
411 if (itr.system == SatelliteSystem::GPS)
413 else if (itr.system == SatelliteSystem::Glonass)
417 strm << right << setw(2) << setfill(
'0') << itr.id << setfill(
' ')
419 if ( (prnCount % 15) == 0 )
421 strm << prnListString <<
endlpp;
425 if ( (prnCount % 15) != 0 )
427 strm << setw((15-(prnCount % 15)) * 4) <<
' ' << prnListString
433 strm << setw(60) <<
' ' << endOfHeader <<
endlpp;
439 void RinexClockHeader::reallyGetRecord(
FFStream& ffs)
452 while ( !(
valid & endValid) )
457 if ( line.length() == 0 )
459 FFStreamError ffse(
"No data read!");
462 else if ( line.length() < 60 || line.length() > 80 )
464 FFStreamError ffse(
"Invalid line length");
470 ParseHeaderRecord(line);
472 catch(FFStreamError& ffse)
486 void RinexClockHeader::ParseHeaderRecord(
const string& line)
488 string label(line, 60, 20);
491 if (label == versionString)
499 FFStreamError e(
"Incorrect file type: " +
fileType);
503 valid |= versionValid;
507 else if (label == runByString)
517 else if (label == commentString)
519 string s = line.substr(0, 60);
520 commentList.push_back(s);
522 valid |= commentValid;
526 else if (label == leapSecondsString)
528 leapSeconds =
asInt(line.substr(0,6));
530 valid |= leapSecondsValid;
534 else if (label == dataTypesString)
536 numType =
asInt(line.substr(0,6));
537 if ( numType < 0 || numType > 5 )
540 FFStreamError e(
"Invalid number of data types: " +
544 dataTypeList.clear();
545 for(
int i = 0; i < numType; i++)
547 string dtype = line.substr(i*6+10, 2);
548 if (
upperCase(dtype) ==
"AR" ) dataTypeList.push_back(AR);
549 else if (
upperCase(dtype) ==
"AS" ) dataTypeList.push_back(AS);
550 else if (
upperCase(dtype) ==
"CR" ) dataTypeList.push_back(CR);
551 else if (
upperCase(dtype) ==
"DR" ) dataTypeList.push_back(DR);
552 else if (
upperCase(dtype) ==
"MS" ) dataTypeList.push_back(MS);
555 FFStreamError e(
"Invalid data type: " + dtype);
560 valid |= dataTypesValid;
564 else if (label == stationNameString)
566 stationName = line.substr(0,4);
567 stationNumber =
strip(line.substr(4,20));
569 valid |= stationNameValid;
573 else if (label == calibrationClkString)
575 stationClkRef =
strip( line.substr(0,60) );
577 valid |= calibrationClkValid;
581 else if (label == acNameString)
583 ac = line.substr(0, 3);
584 acName =
strip(line.substr(5,55));
586 valid |= acNameValid;
590 else if (label == numRefClkString)
594 if(
asInt(line.substr(7,4)) )
596 record.
startEpoch = parseTime(line.substr(7,26));
597 if (
asInt(line.substr(34,26)) )
599 record.
stopEpoch = parseTime(line.substr(34,26));
602 FFStreamError e(
"Invalid Start/Stop Epoch start: " +
603 line.substr(7,26) +
", stop: " +
610 FFStreamError e(
"Invalid Start/Stop Epoch start: " +
611 line.substr(7,26) +
", stop: " +
619 if (
asInt(line.substr(34,26)) )
621 FFStreamError e(
"Invalid Start/Stop Epoch start: " +
622 line.substr(7,26) +
", stop: " +
632 refClkList.push_back(record);
634 valid |= numRefClkValid;
638 else if (label == analysisClkRefString)
640 if ( refClkList.empty() )
642 FFStreamError e(
"\"ANALYSIS CLK REF\" record without previous "
643 "\"# OF CLK REF\" record.");
648 std::list<RefClkRecord>::iterator itr = refClkList.end();
651 if ( itr->numClkRef <= itr->clocks.size() )
653 FFStreamError e(
"\"ANALYSIS CLK REF\" entry exceeds "
654 "\"# of CLK REF\": " +
asString(itr->numClkRef));
659 refclk.
name = line.substr(0,4);
662 itr->clocks.push_back(refclk);
666 else if (label == numStationsString)
668 numSta =
asInt( line.substr(0,6) );
669 trf =
strip(line.substr(10,50));
671 valid |= numStationsValid;
675 else if (label == solnStaNameString)
679 solnSta.
name = line.substr(0,4);
681 solnSta.
posX = strtoll(
strip(line.substr(25,11)).c_str(), 0, 10);
682 solnSta.
posY = strtoll(
strip(line.substr(37,11)).c_str(), 0, 10);
683 solnSta.
posZ = strtoll(
strip(line.substr(49,11)).c_str(), 0, 10);
685 solnStaList.push_back(solnSta);
687 valid |= solnStaNameValid;
691 else if (label == numSatsString)
693 numSats =
asInt(line.substr(0,6));
695 valid |= numSatsValid;
699 else if (label == prnListString)
701 string s = line.substr(0,60);
704 while ( !
word.empty() )
706 if (
word[0] ==
'G' ||
word[0] ==
'g' )
709 SatelliteSystem::GPS));
711 else if (
word[0] ==
'R' ||
word[0] ==
'r' )
714 SatelliteSystem::Glonass));
718 FFStreamError e(
"Invalid PRN: " +
word);
725 valid |= prnListValid;
729 else if (label == endOfHeader)
736 FFStreamError e(
"Invalid label: " + label);