Changeset 11200 in ntrip for trunk/BNC/src/rinex/reqcedit.cpp
- Timestamp:
- Nov 11, 2026, 11:17:08 AM (less than one hour ago)
- File:
-
- 1 edited
-
trunk/BNC/src/rinex/reqcedit.cpp (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/BNC/src/rinex/reqcedit.cpp
r11192 r11200 327 327 // Loop over all input observation files 328 328 // ------------------------------------- 329 bncTime lastWritten; // epochs of overlapping files are written once 330 int numDuplicates = 0; 329 331 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) { 330 332 t_rnxObsFile* obsFile = _rnxObsFiles[ii]; … … 334 336 << obsFile->startTime().timestr(0).c_str() << Qt::endl; 335 337 } 338 // header records changed with respect to the previous file (after the 339 // header editing options): event with header information (flag 4) 340 editRnxObsHeader(*obsFile); 341 QList<t_rnxObsFile::t_rnxEvent> headerChange; 342 if (ii > 0) { 343 QStringList records = headerChangeRecords(_rnxObsFiles[ii-1]->header(), 344 obsFile->header(), 345 outObsFile.header().version()); 346 if (!records.isEmpty()) { 347 t_rnxObsFile::t_rnxEvent event; 348 event.flag = 4; 349 event.version = outObsFile.header().version(); 350 event.records = records; 351 headerChange.append(event); 352 if (_logStream) { 353 *_logStream << "Header changes : " << records.size() << " records (" 354 << obsFile->fileName() << ")" << Qt::endl; 355 } 356 } 357 } 336 358 if (ii == 0) { 337 359 outObsFile.setHeader(obsFile->header(), int(_rnxVersion), &useObsTypes, … … 365 387 // sampling) are written with the next epoch; events with an epoch 366 388 // outside the time window are skipped 367 QList<t_rnxObsFile::t_rnxEvent> pendingEvents; 389 QList<t_rnxObsFile::t_rnxEvent> pendingEvents = headerChange; 368 390 bool pendingPowerFail = false; 369 391 bool endReached = false; … … 379 401 endReached = true; 380 402 break; 403 } 404 if (lastWritten.valid() && !(epo->tt > lastWritten)) { 405 ++numDuplicates; // already written from the previous file 406 continue; 381 407 } 382 408 … … 396 422 } 397 423 outObsFile.writeEpoch(epo); 424 lastWritten = epo->tt; 398 425 } 399 426 else { … … 426 453 } 427 454 } 455 if (_logStream && numDuplicates) { 456 *_logStream << "Epochs skipped : " << numDuplicates 457 << " (not later than the last epoch written, e.g. overlapping files)" << Qt::endl; 458 } 459 } 460 461 // Station header records of header2 differing from header1 (e.g. new 462 // receiver or antenna in the next file), in the output RINEX version 463 //////////////////////////////////////////////////////////////////////////// 464 QStringList t_reqcEdit::headerChangeRecords(const t_rnxObsHeader& header1, 465 const t_rnxObsHeader& header2, 466 double outVersion) { 467 QMap<QString, QStringList> records1, records2; 468 QStringList labels; 469 for (int iHdr = 0; iHdr < 2; iHdr++) { 470 const t_rnxObsHeader& header = (iHdr == 0) ? header1 : header2; 471 QMap<QString, QStringList>& records = (iHdr == 0) ? records1 : records2; 472 QStringList lines = header.stationRecords(outVersion); 473 QStringList other = header.otherRecords(); 474 for (int ii = 0; ii < other.size(); ii++) { 475 QString record = t_rnxObsHeader::convertRecord(other[ii], outVersion, 476 header.otherRecordsVersion()); 477 if (!record.isEmpty()) { 478 lines << record; 479 } 480 } 481 if (header.rcvClkOffsAppl() < 0) { // not given: default 0 482 lines << QString("%1").arg(0, 6).leftJustified(60) + "RCV CLOCK OFFS APPL"; 483 } 484 for (int ii = 0; ii < lines.size(); ii++) { 485 QString label = lines[ii].mid(60).trimmed(); 486 records[label] << lines[ii]; 487 if (iHdr == 1 && !labels.contains(label)) { 488 labels << label; 489 } 490 } 491 } 492 QStringList changed; 493 for (int ii = 0; ii < labels.size(); ii++) { 494 if (records1.value(labels[ii]) != records2[labels[ii]]) { 495 changed << records2[labels[ii]]; 496 } 497 } 498 return changed; 428 499 } 429 500 … … 709 780 comments.append(comment); 710 781 } 711 QStringListIterator it(_navFileNames); 782 // (number of merged files: input files already merged count with their 783 // MERGED FILE value) 784 int mergedNavFiles = 0; 785 QStringList navFiles = expandFileNames(_navFileNames); 786 QStringListIterator it(navFiles); 712 787 while (it.hasNext()) { 713 788 QString fileName = it.next(); 714 789 715 790 t_rnxNavFile rnxNavFile(fileName, t_rnxNavFile::input); 791 mergedNavFiles += qMax(1, rnxNavFile.mergedFiles()); 716 792 QStringListIterator itCmnt(rnxNavFile.comments()); 717 793 while (itCmnt.hasNext()) { … … 813 889 } 814 890 815 int mergedNavFiles = _navFileNames.size(); 891 // Header records and RINEX 4 STO/EOP/ION records of all input files: 892 // header records of the same RINEX version (the first one of a kind), 893 // records without duplicates, in the time window 894 // --------------------------------------------------------------------- 895 QStringList headerRecords; 896 QList<t_rnxNavFile::t_rnxNavRecord> records; 897 collectNavRecords(outNavFile, headerRecords, records); 898 816 899 unsigned year, month, day; 817 900 int gps_utc = 0; … … 820 903 gps_utc = gnumleap(year, month, day); 821 904 } 822 outNavFile.writeHeader(&txtMap, mergedNavFiles, gps_utc); 905 outNavFile.writeHeader(&txtMap, mergedNavFiles, gps_utc, &headerRecords); 906 907 // records without epoch first, then in time order with the ephemerides 908 int iRec = 0; 909 while (iRec < records.size() && !records[iRec].tt.valid()) { 910 outNavFile.writeRecord(records[iRec++]); 911 } 823 912 824 913 // Loop over all ephemerides … … 850 939 } 851 940 } 941 while (iRec < records.size() && records[iRec].tt <= eph->TOC()) { 942 outNavFile.writeRecord(records[iRec++]); 943 } 852 944 outNavFile.writeEph(eph); 945 } 946 while (iRec < records.size()) { 947 outNavFile.writeRecord(records[iRec++]); 948 } 949 } 950 951 // File names with wildcards expanded (as in readEphemerides) 952 //////////////////////////////////////////////////////////////////////////// 953 QStringList t_reqcEdit::expandFileNames(const QStringList& fileNames) { 954 QStringList expanded; 955 QStringListIterator itNames(fileNames); 956 while (itNames.hasNext()) { 957 QString fileName = itNames.next(); 958 if (fileName.indexOf('*') != -1 || fileName.indexOf('?') != -1) { 959 QFileInfo fileInfo(fileName); 960 QDir dir = fileInfo.dir(); 961 QStringList filters; filters << fileInfo.fileName(); 962 QListIterator<QFileInfo> it(dir.entryInfoList(filters)); 963 while (it.hasNext()) { 964 expanded << it.next().filePath(); 965 } 966 } 967 else { 968 expanded << fileName; 969 } 970 } 971 return expanded; 972 } 973 974 // Key of a navigation header record: one record per kind is written (the 975 // first one), IONOSPHERIC CORR and TIME SYSTEM CORR per correction type 976 //////////////////////////////////////////////////////////////////////////// 977 static QString navHeaderKey(const QString& record) { 978 QString label = record.mid(60).trimmed(); 979 if (label == "IONOSPHERIC CORR") { 980 return label + record.left(4) + record.mid(54, 6); // type, time mark, SV 981 } 982 if (label == "TIME SYSTEM CORR") { 983 return label + record.left(4); 984 } 985 static const QStringList single = QStringList() 986 << "LEAP SECONDS" << "ION ALPHA" << "ION BETA" << "DELTA-UTC: A0,A1,T,W" 987 << "CORR TO SYSTEM TIME" << "D-UTC A0,A1,T,W,S,U" << "DOI"; 988 if (single.contains(label)) { 989 return label; 990 } 991 return record; // e.g. LICENSE OF USE, STATION INFORMATION: identical ones once 992 } 993 994 // Conversion of navigation header records between RINEX versions and of 995 // RINEX 4 STO/ION records to RINEX 3/2 header records (RINEX 3.05 Table A5, 996 // RINEX 2.11, RINEX 4.02 Tables 26-28, A33-A37: same sign conventions) 997 //////////////////////////////////////////////////////////////////////////// 998 namespace { 999 1000 double navField(const QString& line, int pos, int len = 19) { 1001 double value = 0.0; 1002 readDbl(line, pos, len, value); 1003 return value; 1004 } 1005 1006 bool navEpoch(const QString& line, bncTime& tt) { 1007 QTextStream in(line.mid(4, 19).toLatin1(), QIODevice::ReadOnly); 1008 int year = 0, month = 0, day = 0, hour = 0, min = 0; 1009 double sec = 0.0; 1010 in >> year >> month >> day >> hour >> min >> sec; 1011 if (year <= 0) { 1012 return false; 1013 } 1014 tt.set(year, month, day, hour, min, sec); 1015 return true; 1016 } 1017 1018 QString navRecord(const QString& value, const QString& label) { 1019 return value.leftJustified(60) + label; 1020 } 1021 1022 // RINEX 3 IONOSPHERIC CORR: A4,1X,4D12.4,1X,A1,1X,I2 1023 QString ionCorrV3(const QString& type, const double par[4], QChar timeMark, int sv) { 1024 QString value = type.leftJustified(4) + " "; 1025 for (int ii = 0; ii < 4; ii++) { 1026 value += QString("%1").arg(par[ii], 12, 'E', 4); 1027 } 1028 value += QString(" %1 ").arg(timeMark); 1029 value += (sv > 0) ? QString("%1").arg(sv, 2) : QString(" "); 1030 return navRecord(value, "IONOSPHERIC CORR"); 1031 } 1032 1033 // RINEX 3 TIME SYSTEM CORR: A4,1X,D17.10,D16.9,1X,I6,1X,I4,1X,A5,1X,I2 1034 QString timeCorrV3(const QString& type, double a0, double a1, int tt, int week, 1035 const QString& svId, int utcId) { 1036 QString value = type.leftJustified(4) + " " 1037 + QString("%1").arg(a0, 17, 'E', 10) + QString("%1").arg(a1, 16, 'E', 9) 1038 + QString(" %1 %2 %3 %4").arg(tt, 6).arg(week, 4).arg(svId, 5).arg(utcId, 2); 1039 return navRecord(value, "TIME SYSTEM CORR"); 1040 } 1041 1042 // RINEX 2 ION ALPHA/ION BETA: 2X,4D12.4 1043 QString ionV2(const QString& label, const double par[4]) { 1044 QString value = " "; 1045 for (int ii = 0; ii < 4; ii++) { 1046 value += QString("%1").arg(par[ii], 12, 'E', 4); 1047 } 1048 return navRecord(value, label); 1049 } 1050 1051 // RINEX 2 DELTA-UTC: A0,A1,T,W: 3X,2D19.12,2I9 1052 QString deltaUtcV2(double a0, double a1, int tt, int week) { 1053 QString value = " " + QString("%1").arg(a0, 19, 'E', 12) + QString("%1").arg(a1, 19, 'E', 12) 1054 + QString("%1%2").arg(tt, 9).arg(week, 9); 1055 return navRecord(value, "DELTA-UTC: A0,A1,T,W"); 1056 } 1057 1058 // RINEX 2 CORR TO SYSTEM TIME: 3I6,3X,D19.12 (-TauC) 1059 QString corrSysTimeV2(int year, int month, int day, double minusTauC) { 1060 QString value = QString("%1%2%3 ").arg(year, 6).arg(month, 6).arg(day, 6) 1061 + QString("%1").arg(minusTauC, 19, 'E', 12); 1062 return navRecord(value, "CORR TO SYSTEM TIME"); 1063 } 1064 1065 // UTC identifier of RINEX 3 TIME SYSTEM CORR from the RINEX 4 UTC ID 1066 int utcIdV3(const QString& utcId) { 1067 if (utcId == "UTC(NIST)") return 1; 1068 if (utcId == "UTC(USNO)") return 2; 1069 if (utcId == "UTC(SU)") return 3; 1070 if (utcId == "UTC(BIPM)") return 4; 1071 if (utcId == "UTCGAL") return 5; // UTC(Europe Lab) 1072 if (utcId == "UTC(CRL)" || utcId == "UTC(NICT)") return 6; 1073 if (utcId == "UTC(NTSC)") return 7; 1074 return 0; 1075 } 1076 1077 // Priority of BDS satellites for the ionosphere parameters (RINEX 3.05 1078 // Table A5 Note 2): GEO, IGSO, MEO 1079 int bdsPriority(int prn) { 1080 if (prn <= 5 || (prn >= 59 && prn <= 62)) { 1081 return 0; 1082 } 1083 if ((prn >= 6 && prn <= 10) || prn == 13 || prn == 16 || prn == 31 || 1084 (prn >= 38 && prn <= 40) || prn == 56) { 1085 return 1; 1086 } 1087 return 2; 1088 } 1089 1090 } // namespace 1091 1092 // RINEX 4 STO/ION records -> RINEX 3 or 2 header records (one per kind: 1093 // the first record in time, BDS by satellite priority); returns the number 1094 // of records not convertible 1095 //////////////////////////////////////////////////////////////////////////// 1096 int t_reqcEdit::navRecordsToHeader(const QList<t_rnxNavFile::t_rnxNavRecord>& records, 1097 double outVersion, bool outGlonass, 1098 QStringList& headerRecords, QStringList& notConverted) { 1099 QMap<QString, QPair<int, QString> > converted; // key -> (priority, record) 1100 int numNotConverted = 0; 1101 1102 for (int iRec = 0; iRec < records.size(); iRec++) { 1103 const t_rnxNavFile::t_rnxNavRecord& rec = records[iRec]; 1104 QStringList hlp = rec.lines[0].split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); 1105 QString prnStr = hlp.value(2); 1106 QString navType = hlp.value(3); 1107 QString subType = hlp.value(4); 1108 char sys = prnStr.isEmpty() ? ' ' : prnStr[0].toLatin1(); 1109 int prnNum = prnStr.mid(1).toInt(); 1110 QString key; 1111 QString record; 1112 int priority = 0; 1113 1114 // (rec.lines[0] is the "> " line, the data lines follow) 1115 if (rec.key == "ION" && rec.lines.size() >= 4 && subType.isEmpty() && 1116 ((sys == 'G' && (navType == "LNAV" || navType == "CNVX")) || 1117 (sys == 'J' && navType == "LNAV") || 1118 (sys == 'C' && navType == "D1D2") || 1119 (sys == 'I' && navType == "LNAV"))) { 1120 // Klobuchar 1121 double alpha[4], beta[4]; 1122 alpha[0] = navField(rec.lines[1], 23); 1123 alpha[1] = navField(rec.lines[1], 42); 1124 alpha[2] = navField(rec.lines[1], 61); 1125 alpha[3] = navField(rec.lines[2], 4); 1126 beta[0] = navField(rec.lines[2], 23); 1127 beta[1] = navField(rec.lines[2], 42); 1128 beta[2] = navField(rec.lines[2], 61); 1129 beta[3] = navField(rec.lines[3], 4); 1130 priority = (navType == "CNVX") ? 1 : 0; // LNAV preferred 1131 if (outVersion >= 3.0) { 1132 QString prefix = (sys == 'G') ? "GPS" : (sys == 'J') ? "QZS" : (sys == 'C') ? "BDS" : "IRN"; 1133 QChar timeMark = ' '; 1134 int sv = 0; 1135 if (sys == 'C') { // mandatory for BDS: hour of the transmission time, SV 1136 bncTime tt; 1137 if (navEpoch(rec.lines[1], tt)) { 1138 unsigned hour, min; double sec; 1139 tt.civil_time(hour, min, sec); 1140 timeMark = QChar('A' + int(hour)); 1141 } 1142 sv = prnNum; 1143 priority = bdsPriority(prnNum); 1144 } 1145 key = prefix; 1146 record = ionCorrV3(prefix + "A", alpha, timeMark, sv) + "\n" + 1147 ionCorrV3(prefix + "B", beta, timeMark, sv); 1148 } 1149 else if (sys == 'G' && !outGlonass) { 1150 key = "ION"; 1151 record = ionV2("ION ALPHA", alpha) + "\n" + ionV2("ION BETA", beta); 1152 } 1153 } 1154 else if (rec.key == "ION" && rec.lines.size() >= 2 && sys == 'E' && navType == "IFNV" && 1155 outVersion >= 3.0) { 1156 // NeQuick-G 1157 double ai[4]; 1158 ai[0] = navField(rec.lines[1], 23); 1159 ai[1] = navField(rec.lines[1], 42); 1160 ai[2] = navField(rec.lines[1], 61); 1161 ai[3] = 0.0; 1162 key = "GAL"; 1163 record = ionCorrV3("GAL", ai, ' ', 0); 1164 record = record.left(5 + 36) + QString().leftJustified(12) + record.mid(5 + 48); // ai3 blank 1165 } 1166 else if (rec.key == "STO" && rec.lines.size() >= 3) { 1167 QString type = rec.lines[1].mid(24, 18).trimmed(); 1168 QString sbas = rec.lines[1].mid(43, 18).trimmed(); 1169 QString utcId = rec.lines[1].mid(62, 18).trimmed(); 1170 double a0 = navField(rec.lines[2], 23); 1171 double a1 = navField(rec.lines[2], 42); 1172 double a2 = navField(rec.lines[2], 61); 1173 bncTime tot; 1174 static const QStringList v3Types = QStringList() 1175 << "GPUT" << "GLUT" << "GAUT" << "BDUT" << "QZUT" << "IRUT" << "SBUT" 1176 << "GLGP" << "GAGP" << "QZGP" << "IRGP"; 1177 if (a2 == 0.0 && navEpoch(rec.lines[1], tot) && v3Types.contains(type)) { 1178 int week = 0, sow = 0; 1179 if (!type.startsWith("GL")) { 1180 week = int(tot.gpsw()); 1181 sow = int(nint(tot.gpssec())); 1182 if (type.startsWith("BD")) { 1183 week -= 1356; // BDS week 1184 } 1185 } 1186 // one record per offset type (RINEX 3: no UTC ID for UTC(NPLI)); 1187 // NavIC: UTCIRN preferred to UTC(NPLI), SBAS: per SBAS ID 1188 key = type + (type == "SBUT" ? sbas : QString()); 1189 if (type == "IRUT" && utcId != "UTCIRN") { 1190 priority = 1; 1191 } 1192 if (outVersion >= 3.0) { 1193 QString svId = (type == "SBUT" && !sbas.isEmpty()) ? sbas : prnStr; 1194 record = timeCorrV3(type, a0, a1, sow, week, svId.length() > 1 ? svId : QString(), 1195 utcIdV3(utcId)); 1196 } 1197 else if (type == "GPUT" && !outGlonass) { 1198 key = "GPUT"; 1199 record = deltaUtcV2(a0, a1, sow, week); 1200 } 1201 else if (type == "GLUT" && outGlonass) { 1202 unsigned year, month, day; 1203 tot.civil_date(year, month, day); 1204 key = "GLUT"; 1205 record = corrSysTimeV2(int(year), int(month), int(day), a0); 1206 } 1207 } 1208 } 1209 1210 if (record.isEmpty()) { 1211 // not convertible to the output version (e.g. EOP, BDGIM, NavIC 1212 // L1NV, STO with A2, STO types not in RINEX 3) or not used in a 1213 // RINEX 2 file of another system 1214 bool usable = !(outVersion < 3.0 && 1215 ((outGlonass && sys != 'R') || (!outGlonass && sys != 'G'))); 1216 if (usable) { 1217 ++numNotConverted; 1218 QString what = rec.key + " " + QString(sys) + " " + navType 1219 + (subType.isEmpty() ? QString() : " " + subType); 1220 if (!notConverted.contains(what)) { 1221 notConverted << what; 1222 } 1223 } 1224 continue; 1225 } 1226 if (!converted.contains(key) || priority < converted[key].first) { 1227 converted[key] = QPair<int, QString>(priority, record); 1228 } 1229 } 1230 1231 QMapIterator<QString, QPair<int, QString> > it(converted); 1232 while (it.hasNext()) { 1233 it.next(); 1234 headerRecords << it.value().second.split("\n"); 1235 } 1236 return numNotConverted; 1237 } 1238 1239 // Navigation header record converted between RINEX 2 and 3 (GPS ionosphere 1240 // and UTC parameters, GLONASS time correction); empty list: not convertible 1241 //////////////////////////////////////////////////////////////////////////// 1242 QStringList t_reqcEdit::convertNavHeaderRecord(const QString& record, double inVersion, 1243 double outVersion, bool outGlonass) { 1244 QStringList result; 1245 QString label = record.mid(60).trimmed(); 1246 if (int(inVersion) == 2 && int(outVersion) == 3) { 1247 if (label == "ION ALPHA" || label == "ION BETA") { 1248 double par[4]; 1249 for (int ii = 0; ii < 4; ii++) { 1250 par[ii] = navField(record, 2 + 12*ii, 12); 1251 } 1252 result << ionCorrV3(label == "ION ALPHA" ? "GPSA" : "GPSB", par, ' ', 0); 1253 } 1254 else if (label == "DELTA-UTC: A0,A1,T,W") { 1255 int tt = 0, week = 0; 1256 readInt(record, 41, 9, tt); 1257 readInt(record, 50, 9, week); 1258 result << timeCorrV3("GPUT", navField(record, 3), navField(record, 22), 1259 tt, week, QString(), 2); // GPS: UTC(USNO) 1260 } 1261 else if (label == "CORR TO SYSTEM TIME") { 1262 result << timeCorrV3("GLUT", navField(record, 21), 0.0, 0, 0, QString(), 3); // UTC(SU) 1263 } 1264 } 1265 else if (int(inVersion) == 3 && int(outVersion) == 2 && !outGlonass) { 1266 QString type = record.left(4); 1267 if (label == "IONOSPHERIC CORR" && (type == "GPSA" || type == "GPSB")) { 1268 double par[4]; 1269 for (int ii = 0; ii < 4; ii++) { 1270 par[ii] = navField(record, 5 + 12*ii, 12); 1271 } 1272 result << ionV2(type == "GPSA" ? "ION ALPHA" : "ION BETA", par); 1273 } 1274 else if (label == "TIME SYSTEM CORR" && type == "GPUT") { 1275 int tt = 0, week = 0; 1276 readInt(record, 39, 6, tt); 1277 readInt(record, 46, 4, week); 1278 result << deltaUtcV2(navField(record, 5, 17), navField(record, 22, 16), tt, week); 1279 } 1280 } 1281 return result; 1282 } 1283 1284 // Header records and STO/EOP/ION records of the input navigation files 1285 //////////////////////////////////////////////////////////////////////////// 1286 void t_reqcEdit::collectNavRecords(const t_rnxNavFile& outNavFile, 1287 QStringList& headerRecords, 1288 QList<t_rnxNavFile::t_rnxNavRecord>& records) { 1289 QSet<QString> headerKeys; 1290 QSet<QString> recordKeys; 1291 int numNotConverted = 0; 1292 int numRecordsLost = 0; 1293 QStringList notConvertedLabels; 1294 1295 QStringList navFiles = expandFileNames(_navFileNames); 1296 1297 for (int iFile = 0; iFile < navFiles.size(); iFile++) { 1298 t_rnxNavFile navFile(navFiles[iFile], t_rnxNavFile::input); 1299 1300 // header records: same RINEX version (RINEX 2: same file type) 1301 bool sameVersion = (int(navFile.version()) == int(outNavFile.version())); 1302 if (sameVersion && outNavFile.version() < 3.0 && navFile.glonass() != outNavFile.glonass()) { 1303 sameVersion = false; 1304 } 1305 QStringList hdr = navFile.headerRecords(); 1306 for (int ii = 0; ii < hdr.size(); ii++) { 1307 QString label = hdr[ii].mid(60).trimmed(); 1308 QString record = hdr[ii]; 1309 if (label == "LEAP SECONDS") { // RINEX 3 and 4: same format, RINEX 2: I6 1310 if (outNavFile.version() < 3.0) { 1311 record = record.left(6).leftJustified(60) + label; 1312 } 1313 } 1314 else if (!sameVersion) { 1315 QStringList conv = convertNavHeaderRecord(record, navFile.version(), 1316 outNavFile.version(), outNavFile.glonass()); 1317 if (conv.isEmpty()) { 1318 ++numNotConverted; 1319 if (!notConvertedLabels.contains(label)) { 1320 notConvertedLabels << label; 1321 } 1322 } 1323 for (int iConv = 0; iConv < conv.size(); iConv++) { 1324 QString key = navHeaderKey(conv[iConv]); 1325 if (!headerKeys.contains(key)) { 1326 headerKeys.insert(key); 1327 headerRecords << conv[iConv]; 1328 } 1329 } 1330 continue; 1331 } 1332 QString key = navHeaderKey(record); 1333 if (!headerKeys.contains(key)) { 1334 headerKeys.insert(key); 1335 headerRecords << record; 1336 } 1337 } 1338 1339 // STO/EOP/ION records (RINEX 4) 1340 const QList<t_rnxNavFile::t_rnxNavRecord>& recs = navFile.records(); 1341 for (int ii = 0; ii < recs.size(); ii++) { 1342 const t_rnxNavFile::t_rnxNavRecord& rec = recs[ii]; 1343 if (rec.tt.valid() && 1344 ((_begTime.valid() && rec.tt < _begTime) || 1345 (_endTime.valid() && rec.tt > _endTime))) { 1346 continue; 1347 } 1348 QStringList trimmed; 1349 for (int iLine = 0; iLine < rec.lines.size(); iLine++) { 1350 trimmed << rec.lines[iLine].trimmed(); 1351 } 1352 QString key = trimmed.join("|"); 1353 if (recordKeys.contains(key)) { 1354 continue; 1355 } 1356 recordKeys.insert(key); 1357 records.append(rec); 1358 } 1359 } 1360 1361 std::stable_sort(records.begin(), records.end(), 1362 [](const t_rnxNavFile::t_rnxNavRecord& r1, 1363 const t_rnxNavFile::t_rnxNavRecord& r2) { 1364 if (!r1.tt.valid() || !r2.tt.valid()) { 1365 return !r1.tt.valid() && r2.tt.valid(); 1366 } 1367 return r1.tt < r2.tt; 1368 }); 1369 1370 // RINEX 3/2 output: STO/ION records as header records (header records of 1371 // the input files of the output version have priority) 1372 QStringList notConvertedRecords; 1373 if (outNavFile.version() < 4.0) { 1374 QStringList conv; 1375 numRecordsLost = navRecordsToHeader(records, outNavFile.version(), outNavFile.glonass(), 1376 conv, notConvertedRecords); 1377 for (int iConv = 0; iConv < conv.size(); iConv++) { 1378 QString key = navHeaderKey(conv[iConv]); 1379 if (!headerKeys.contains(key)) { 1380 headerKeys.insert(key); 1381 headerRecords << conv[iConv]; 1382 } 1383 } 1384 records.clear(); 1385 } 1386 1387 if (_logStream) { 1388 if (numNotConverted) { 1389 *_logStream << "Nav header records not converted to RINEX version " 1390 << outNavFile.version() << ": " << numNotConverted 1391 << " (" << notConvertedLabels.join(", ") << ")" << Qt::endl; 1392 } 1393 if (numRecordsLost) { 1394 *_logStream << "STO/EOP/ION records not convertible to RINEX version " 1395 << outNavFile.version() << ": " << numRecordsLost 1396 << " (" << notConvertedRecords.join(", ") << ")" << Qt::endl; 1397 } 853 1398 } 854 1399 }
Note:
See TracChangeset
for help on using the changeset viewer.
