gps_pvt 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/CHANGELOG.md +5 -0
  4. data/CODE_OF_CONDUCT.md +84 -0
  5. data/Gemfile +10 -0
  6. data/README.md +86 -0
  7. data/Rakefile +86 -0
  8. data/bin/console +15 -0
  9. data/bin/setup +8 -0
  10. data/ext/gps_pvt/Coordinate/Coordinate_wrap.cxx +6613 -0
  11. data/ext/gps_pvt/GPS/GPS_wrap.cxx +16019 -0
  12. data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +21050 -0
  13. data/ext/gps_pvt/extconf.rb +70 -0
  14. data/ext/ninja-scan-light/tool/navigation/EGM.h +2971 -0
  15. data/ext/ninja-scan-light/tool/navigation/GPS.h +2432 -0
  16. data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +479 -0
  17. data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +1081 -0
  18. data/ext/ninja-scan-light/tool/navigation/GPS_Solver_MultiFrequency.h +199 -0
  19. data/ext/ninja-scan-light/tool/navigation/GPS_Solver_RAIM.h +210 -0
  20. data/ext/ninja-scan-light/tool/navigation/MagneticField.h +928 -0
  21. data/ext/ninja-scan-light/tool/navigation/NTCM.h +211 -0
  22. data/ext/ninja-scan-light/tool/navigation/RINEX.h +1781 -0
  23. data/ext/ninja-scan-light/tool/navigation/WGS84.h +186 -0
  24. data/ext/ninja-scan-light/tool/navigation/coordinate.h +406 -0
  25. data/ext/ninja-scan-light/tool/param/bit_array.h +145 -0
  26. data/ext/ninja-scan-light/tool/param/complex.h +558 -0
  27. data/ext/ninja-scan-light/tool/param/matrix.h +4049 -0
  28. data/ext/ninja-scan-light/tool/param/matrix_fixed.h +665 -0
  29. data/ext/ninja-scan-light/tool/param/matrix_special.h +562 -0
  30. data/ext/ninja-scan-light/tool/param/quaternion.h +765 -0
  31. data/ext/ninja-scan-light/tool/param/vector3.h +651 -0
  32. data/ext/ninja-scan-light/tool/swig/Coordinate.i +177 -0
  33. data/ext/ninja-scan-light/tool/swig/GPS.i +1102 -0
  34. data/ext/ninja-scan-light/tool/swig/SylphideMath.i +1234 -0
  35. data/ext/ninja-scan-light/tool/swig/extconf.rb +5 -0
  36. data/ext/ninja-scan-light/tool/swig/makefile +53 -0
  37. data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +417 -0
  38. data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +489 -0
  39. data/gps_pvt.gemspec +57 -0
  40. data/lib/gps_pvt/receiver.rb +375 -0
  41. data/lib/gps_pvt/ubx.rb +148 -0
  42. data/lib/gps_pvt/version.rb +5 -0
  43. data/lib/gps_pvt.rb +9 -0
  44. data/sig/gps_pvt.rbs +4 -0
  45. metadata +117 -0
@@ -0,0 +1,1781 @@
1
+ /*
2
+ * Copyright (c) 2017, M.Naruoka (fenrir)
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without modification,
6
+ * are permitted provided that the following conditions are met:
7
+ *
8
+ * - Redistributions of source code must retain the above copyright notice,
9
+ * this list of conditions and the following disclaimer.
10
+ * - Redistributions in binary form must reproduce the above copyright notice,
11
+ * this list of conditions and the following disclaimer in the documentation
12
+ * and/or other materials provided with the distribution.
13
+ * - Neither the name of the naruoka.org nor the names of its contributors
14
+ * may be used to endorse or promote products derived from this software
15
+ * without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
21
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ *
30
+ */
31
+
32
+ /** @file
33
+ * @brief RINEX Loader, support RINEX 2 and 3
34
+ *
35
+ */
36
+
37
+ #ifndef __RINEX_H__
38
+ #define __RINEX_H__
39
+
40
+ #include <istream>
41
+ #include <ostream>
42
+ #include <sstream>
43
+ #include <map>
44
+ #include <string>
45
+ #include <queue>
46
+ #include <vector>
47
+ #include <iomanip>
48
+ #include <ctime>
49
+ #include <exception>
50
+ #include <algorithm>
51
+ #include <cstddef>
52
+ #include <cstring>
53
+
54
+ #include "GPS.h"
55
+
56
+ template <class U = void>
57
+ class RINEX_Reader {
58
+ public:
59
+ typedef RINEX_Reader<U> self_t;
60
+ typedef std::map<std::string, std::vector<std::string> > header_t;
61
+
62
+ protected:
63
+ header_t _header;
64
+ struct src_stream_t : public std::istream {
65
+ src_stream_t(std::istream &is) : std::istream(is.rdbuf()) {}
66
+ /**
67
+ * getline() for multi-platform (in addition to \n, \r\n and \r are supported)
68
+ *
69
+ * @see https://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf
70
+ * @see https://en.cppreference.com/w/cpp/io/basic_istream/getline
71
+ * TODO gcount() mismatch
72
+ */
73
+ std::istream& getline(
74
+ typename std::istream::char_type* s,
75
+ std::streamsize n){
76
+ std::streamsize i(1), consumed(0);
77
+ typename std::istream::sentry se(*this, true);
78
+ if((bool)se){
79
+ std::streambuf* sb(this->rdbuf());
80
+ for(; i < n; ++i){
81
+ int c(sb->sbumpc());
82
+ if(c == std::streambuf::traits_type::eof()){
83
+ this->setstate(std::ios::eofbit);
84
+ break;
85
+ }
86
+ ++consumed;
87
+ if(c == '\n'){
88
+ break;
89
+ }else if(c == '\r'){
90
+ if(sb->sgetc() == '\n'){
91
+ sb->sbumpc();
92
+ ++consumed;
93
+ }
94
+ break;
95
+ }
96
+ *(s++) = (typename std::istream::char_type)c;
97
+ }
98
+ }
99
+ if(((i == 1) && (consumed == 0)) || (i == n)){
100
+ this->setstate(std::ios::failbit);
101
+ }else{
102
+ *s = '\0';
103
+ }
104
+ return *this;
105
+ }
106
+ } src;
107
+ bool _has_next;
108
+
109
+ public:
110
+ struct version_type_t {
111
+ int version;
112
+ enum file_type_t {
113
+ FTYPE_UNKNOWN = 0,
114
+ FTYPE_OBSERVATION,
115
+ FTYPE_NAVIGATION,
116
+ FTYPE_METEOROLOGICAL,
117
+ } file_type;
118
+ enum sat_system_t {
119
+ SYS_UNKNOWN = 0,
120
+ SYS_GPS,
121
+ SYS_GLONASS,
122
+ SYS_GALILEO,
123
+ SYS_QZSS,
124
+ SYS_BDS,
125
+ SYS_IRNSS,
126
+ SYS_SBAS,
127
+ SYS_TRANSIT,
128
+ SYS_MIXED,
129
+ } sat_system;
130
+ version_type_t(
131
+ const int &ver = 0, const file_type_t &ftype = FTYPE_UNKNOWN, const sat_system_t &sys = SYS_UNKNOWN)
132
+ : version(ver), file_type(ftype), sat_system(sys) {}
133
+ void parse(const std::string &buf);
134
+ void dump(std::string &buf) const;
135
+ };
136
+ protected:
137
+ version_type_t version_type;
138
+
139
+ public:
140
+ RINEX_Reader(
141
+ std::istream &in,
142
+ std::string &(*modify_header)(std::string &, std::string &) = NULL)
143
+ : src(in), _has_next(false),
144
+ version_type() {
145
+ if(src.fail()){return;}
146
+
147
+ char buf[256];
148
+
149
+ // Read header
150
+ while(!src.eof()){
151
+ src.getline(buf, sizeof(buf));
152
+
153
+ std::string content(buf);
154
+ std::string label(content, 60, 20);
155
+ {
156
+ int real_length(label.find_last_not_of(' ') + 1);
157
+ if(real_length < (int)label.length()){
158
+ label = label.substr(0, real_length);
159
+ }
160
+ }
161
+ // std::cerr << label << " (" << label.length() << ")" << std::endl;
162
+
163
+ if(label.find("END OF HEADER") == 0){break;}
164
+
165
+ content = content.substr(0, 60);
166
+ if(modify_header){content = modify_header(label, content);}
167
+ _header[label].push_back(content);
168
+ }
169
+
170
+ // version and type extraction
171
+ for(const header_t::const_iterator it(_header.find("RINEX VERSION / TYPE"));
172
+ it != _header.end(); ){
173
+ version_type.parse(it->second.front());
174
+ break;
175
+ }
176
+
177
+ }
178
+ virtual ~RINEX_Reader(){_header.clear();}
179
+ header_t &header() {return _header;}
180
+ const header_t &header() const {return const_cast<self_t *>(this)->header();}
181
+ bool has_next() const {return _has_next;}
182
+
183
+ template <class T>
184
+ struct conv_t {
185
+ static void d(
186
+ std::string &buf, const int &offset, const int &length, void *value, const int &opt = 0, const bool &str2val = true){
187
+ if(str2val){
188
+ std::stringstream(buf.substr(offset, length)) >> *(T *)value;
189
+ }else{
190
+ std::stringstream ss;
191
+ ss << std::setfill(opt == 1 ? '0' : ' ') << std::right << std::setw(length) << *(T *)value;
192
+ buf.replace(offset, length, ss.str());
193
+ }
194
+ }
195
+ static void f(
196
+ std::string &buf, const int &offset, const int &length, void *value, const int &precision = 0, const bool &str2val = true){
197
+ if(str2val){
198
+ std::stringstream(buf.substr(offset, length)) >> *(T *)value;
199
+ }else{
200
+ std::stringstream ss;
201
+ ss << std::setfill(' ') << std::right << std::setw(length)
202
+ << std::setprecision(precision) << std::fixed
203
+ << *(T *)value;
204
+ std::string s(ss.str());
205
+ if((*(T *)value) >= 0){
206
+ if((*(T *)value) < 1){
207
+ int i(length - precision - 2);
208
+ if(i >= 0){s[i] = ' ';}
209
+ }
210
+ }else{
211
+ if((*(T *)value) > -1){
212
+ int i(length - precision - 2);
213
+ if(i >= 0){s[i] = '-';}
214
+ if(--i >= 0){s[i] = ' ';}
215
+ }
216
+ }
217
+ buf.replace(offset, length, s);
218
+ }
219
+ }
220
+ static void e(
221
+ std::string &buf, const int &offset, const int &length, void *value, const int &precision = 0, const bool &str2val = true){
222
+ if(str2val){
223
+ std::string s(buf.substr(offset, length));
224
+ std::string::size_type pos(s.find("D"));
225
+ if(pos != std::string::npos){
226
+ s.replace(pos, 1, "E");
227
+ }
228
+ std::stringstream(s) >> *(T *)value;
229
+ }else{
230
+ int w((std::max)(length, precision + 6)); // parentheses of std::max mitigates error C2589 under Windows VC
231
+
232
+ std::stringstream ss;
233
+ ss << std::setprecision(precision - 1) << std::scientific
234
+ << ((*(T *)value) * 1E1);
235
+ std::string s(ss.str());
236
+
237
+ // -1.2345E+06 => -.12345E+06
238
+ int index(s[0] == '-' ? 1 : 0);
239
+ s[index + 1] = s[index + 0];
240
+ s[index + 0] = '.';
241
+
242
+ // -.12345E+06 => -.12345D+06
243
+ s[index + precision + 1] = 'D';
244
+ // If exponent portion digits are more than 2, then truncate it.
245
+ s.erase(index + precision + 3, s.size() - (index + precision + 5));
246
+
247
+ ss.str("");
248
+ ss << std::setfill(' ') << std::right << std::setw(w) << s;
249
+ buf.replace(offset, length, ss.str());
250
+ }
251
+ }
252
+ };
253
+
254
+ struct convert_item_t {
255
+ void (*func)(
256
+ std::string &buf, const int &offset, const int &length, void *value,
257
+ const int &opt, const bool &str2val);
258
+ int offset;
259
+ int length;
260
+ int value_offset;
261
+ int opt;
262
+ };
263
+
264
+ static void convert(const convert_item_t *items, const int &size, const std::string &buf, void *values){
265
+ // str => value
266
+ for(int i(0); i < size; ++i){
267
+ (*items[i].func)(
268
+ const_cast<std::string &>(buf), items[i].offset, items[i].length, (char *)values + items[i].value_offset,
269
+ items[i].opt, true);
270
+ }
271
+ }
272
+ template <int N>
273
+ static inline void convert(const convert_item_t (&items)[N], const std::string &buf, void *values){
274
+ convert(items, N, buf, values);
275
+ }
276
+ };
277
+
278
+ template <class U>
279
+ void RINEX_Reader<U>::version_type_t::parse(const std::string &buf){
280
+ int temp;
281
+ conv_t<int>::d(const_cast<std::string &>(buf), 0, 6, &temp);
282
+ version = temp * 100;
283
+ conv_t<int>::d(const_cast<std::string &>(buf), 7, 2, &temp);
284
+ version += temp;
285
+ switch(version / 100){
286
+ case 2:
287
+ switch(buf[20]){
288
+ case 'O':
289
+ file_type = FTYPE_OBSERVATION;
290
+ switch(buf[40]){
291
+ case ' ':
292
+ case 'G': sat_system = SYS_GPS; break;
293
+ case 'R': sat_system = SYS_GLONASS; break;
294
+ case 'S': sat_system = SYS_SBAS; break;
295
+ case 'M': sat_system = SYS_MIXED; break;
296
+ case 'T': sat_system = SYS_TRANSIT; break;
297
+ }
298
+ break;
299
+ case 'M': file_type = FTYPE_METEOROLOGICAL; break;
300
+ case 'N': file_type = FTYPE_NAVIGATION; sat_system = SYS_GPS; break;
301
+ case 'G': file_type = FTYPE_NAVIGATION; sat_system = SYS_GLONASS; break;
302
+ case 'H': file_type = FTYPE_NAVIGATION;
303
+ sat_system = SYS_SBAS; // TODO: Is geostational as SBAS?
304
+ break;
305
+ }
306
+ break;
307
+ case 3:
308
+ switch(buf[20]){
309
+ case 'O': file_type = FTYPE_OBSERVATION; break;
310
+ case 'N': file_type = FTYPE_NAVIGATION; break;
311
+ case 'M': file_type = FTYPE_METEOROLOGICAL; break;
312
+ }
313
+ if((file_type == FTYPE_OBSERVATION) || (file_type == FTYPE_NAVIGATION)){
314
+ switch(buf[40]){
315
+ case 'G': sat_system = SYS_GPS; break;
316
+ case 'R': sat_system = SYS_GLONASS; break;
317
+ case 'E': sat_system = SYS_GALILEO; break;
318
+ case 'J': sat_system = SYS_QZSS; break;
319
+ case 'C': sat_system = SYS_BDS; break;
320
+ case 'I': sat_system = SYS_IRNSS; break;
321
+ case 'S': sat_system = SYS_SBAS; break;
322
+ case 'M': sat_system = SYS_MIXED; break;
323
+ }
324
+ }
325
+ break;
326
+ }
327
+ }
328
+ template <class U>
329
+ void RINEX_Reader<U>::version_type_t::dump(std::string &buf) const {
330
+ int temp;
331
+ conv_t<int>::d(buf, 0, 6, &(temp = version / 100), 0, false);
332
+ if(version % 100 != 0){
333
+ buf[6] = '.';
334
+ conv_t<int>::d(buf, 7, 2, &(temp = version % 100), 1, false);
335
+ }
336
+ const char *type_str(NULL), *sys_str(NULL);
337
+ switch(version / 100){
338
+ case 2: {
339
+ switch(file_type){
340
+ case FTYPE_OBSERVATION: {
341
+ type_str = "OBSERVATION DATA";
342
+ switch(sat_system){
343
+ case SYS_GPS: sys_str = "G: GPS"; break;
344
+ case SYS_GLONASS: sys_str = "R: GLONASS"; break;
345
+ case SYS_SBAS: sys_str = "S: Geostat"; break;
346
+ case SYS_MIXED: sys_str = "M: MIXED"; break;
347
+ case SYS_TRANSIT: sys_str = "T: TRANSIT"; break;
348
+ default: break;
349
+ }
350
+ break;
351
+ }
352
+ case FTYPE_NAVIGATION:
353
+ switch(sat_system){
354
+ case SYS_GPS: type_str = "N: GPS NAV DATA"; break;
355
+ case SYS_GLONASS: type_str = "G: GLONASS NAV DATA"; break;
356
+ case SYS_SBAS: type_str = "H: GEO NAV MSG DATA"; break;
357
+ default: break;
358
+ }
359
+ break;
360
+ case FTYPE_METEOROLOGICAL: type_str = "METEOROLOGICAL DATA"; break;
361
+ default: break;
362
+ }
363
+ break;
364
+ }
365
+ case 3: {
366
+ switch(file_type){
367
+ case FTYPE_OBSERVATION: type_str = "OBSERVATION DATA"; break;
368
+ case FTYPE_NAVIGATION: type_str = "N: GNSS NAV DATA"; break;
369
+ case FTYPE_METEOROLOGICAL: type_str = "METEOROLOGICAL DATA"; break;
370
+ default: break;
371
+ }
372
+ if((file_type != FTYPE_OBSERVATION) && (file_type != FTYPE_NAVIGATION)){break;}
373
+ switch(sat_system){
374
+ case SYS_GPS: sys_str = "G: GPS"; break;
375
+ case SYS_GLONASS: sys_str = "R: GLONASS"; break;
376
+ case SYS_GALILEO: sys_str = "G: GALILEO"; break;
377
+ case SYS_QZSS: sys_str = "Q: QZSS"; break;
378
+ case SYS_BDS: sys_str = "B: BDS"; break;
379
+ case SYS_IRNSS: sys_str = "I: IRNSS"; break;
380
+ case SYS_SBAS: sys_str = "S: SBAS"; break;
381
+ case SYS_MIXED: sys_str = "M: MIXED"; break;
382
+ default: break;
383
+ }
384
+ break;
385
+ }
386
+ }
387
+ if(type_str){
388
+ int n(std::strlen(type_str));
389
+ buf.replace(20, n, type_str, n);
390
+ }
391
+ if(sys_str){
392
+ int n(std::strlen(sys_str));
393
+ buf.replace(40, n, sys_str, n);
394
+ }
395
+ }
396
+
397
+
398
+ template <class FloatT>
399
+ struct RINEX_NAV {
400
+ typedef GPS_SpaceNode<FloatT> space_node_t;
401
+ typedef typename space_node_t::Satellite::Ephemeris ephemeris_t;
402
+ struct message_t {
403
+ ephemeris_t eph;
404
+ std::tm t_oc_tm;
405
+ int t_oc_year4, t_oc_year2, t_oc_mon12;
406
+ FloatT t_oc_sec;
407
+ FloatT iodc_f, iode_f; // originally int type
408
+ FloatT t_oe_WN;
409
+ FloatT ura_meter;
410
+ FloatT SV_health_f;
411
+ FloatT t_ot; ///< Transmitting time [s]
412
+ FloatT fit_interval_hr;
413
+ FloatT dummy;
414
+
415
+ message_t() {}
416
+ message_t(const ephemeris_t &eph_)
417
+ : eph(eph_),
418
+ t_oc_tm(typename space_node_t::gps_time_t(eph.WN, eph.t_oc).c_tm()),
419
+ t_oc_year4(t_oc_tm.tm_year + 1900),
420
+ t_oc_year2(t_oc_tm.tm_year % 100),
421
+ t_oc_mon12(t_oc_tm.tm_mon + 1),
422
+ t_oc_sec(std::fmod(eph.t_oc, 60)),
423
+ iodc_f(eph.iodc), iode_f(eph.iode),
424
+ t_oe_WN(eph.WN),
425
+ ura_meter(ephemeris_t::URA_meter(eph.URA)),
426
+ SV_health_f(((eph.SV_health & 0x20) && (eph.SV_health & 0x1F == 0)) ? 1 : eph.SV_health),
427
+ t_ot(0), // TODO
428
+ fit_interval_hr(eph.fit_interval / (60 * 60)),
429
+ dummy(0) {
430
+ }
431
+ void update() {
432
+ typename space_node_t::gps_time_t t_oc(t_oc_tm);
433
+ t_oc += (t_oc_sec - t_oc_tm.tm_sec);
434
+ eph.WN = t_oc.week;
435
+ eph.t_oc = t_oc.seconds;
436
+
437
+ eph.iodc = iodc_f;
438
+ eph.iode = iode_f;
439
+
440
+ eph.URA = ephemeris_t::URA_index(ura_meter); // meter to index
441
+
442
+ /* @see ftp://igs.org/pub/data/format/rinex210.txt
443
+ * 6.7 Satellite Health
444
+ * RINEX Value: 0 Health OK
445
+ * RINEX Value: 1 Health not OK (bits 18-22 not stored)
446
+ * RINEX Value: >32 Health not OK (bits 18-22 stored)
447
+ */
448
+ eph.SV_health = (unsigned int)SV_health_f;
449
+ if(eph.SV_health > 32){
450
+ eph.SV_health &= 0x3F; // 0b111111
451
+ }else if(eph.SV_health > 0){
452
+ eph.SV_health = 0x20; // 0b100000
453
+ }
454
+
455
+ // At least 4 hour validity, then, hours => seconds;
456
+ eph.fit_interval = ((fit_interval_hr < 4) ? 4 : fit_interval_hr) * 60 * 60;
457
+ }
458
+ };
459
+ };
460
+
461
+ template <class FloatT = double>
462
+ class RINEX_NAV_Reader : public RINEX_Reader<> {
463
+ protected:
464
+ typedef RINEX_NAV_Reader<FloatT> self_t;
465
+ typedef RINEX_Reader<> super_t;
466
+ public:
467
+ typedef typename RINEX_NAV<FloatT>::space_node_t space_node_t;
468
+ typedef typename RINEX_NAV<FloatT>::message_t message_t;
469
+ typedef typename space_node_t::Ionospheric_UTC_Parameters iono_utc_t;
470
+
471
+ static const typename super_t::convert_item_t eph0_v2[10], eph0_v3[10];
472
+ static const typename super_t::convert_item_t eph1_v2[4], eph1_v3[4];
473
+ static const typename super_t::convert_item_t eph2_v2[4], eph2_v3[4];
474
+ static const typename super_t::convert_item_t eph3_v2[4], eph3_v3[4];
475
+ static const typename super_t::convert_item_t eph4_v2[4], eph4_v3[4];
476
+ static const typename super_t::convert_item_t eph5_v2[4], eph5_v3[4];
477
+ static const typename super_t::convert_item_t eph6_v2[4], eph6_v3[4];
478
+ static const typename super_t::convert_item_t eph7_v2[2], eph7_v3[2];
479
+
480
+ protected:
481
+ message_t msg;
482
+
483
+ void seek_next_v2() {
484
+ char buf[256];
485
+
486
+ for(int i = 0; (i < 8) && (super_t::src.good()); i++){
487
+ if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
488
+ std::string line(buf);
489
+
490
+ switch(i){
491
+ case 0: {
492
+ super_t::convert(eph0_v2, line, &msg);
493
+ msg.t_oc_tm.tm_year = msg.t_oc_year2 + (msg.t_oc_year2 < 80 ? 100 : 0); // greater than 1980
494
+ msg.t_oc_tm.tm_mon = msg.t_oc_mon12 - 1; // month [0, 11]
495
+ msg.t_oc_tm.tm_sec = (int)msg.t_oc_sec;
496
+ break;
497
+ }
498
+ case 1: super_t::convert(eph1_v2, line, &msg); break;
499
+ case 2: super_t::convert(eph2_v2, line, &msg); break;
500
+ case 3: super_t::convert(eph3_v2, line, &msg); break;
501
+ case 4: super_t::convert(eph4_v2, line, &msg); break;
502
+ case 5: super_t::convert(eph5_v2, line, &msg); break;
503
+ case 6: super_t::convert(eph6_v2, line, &msg); break;
504
+ case 7: super_t::convert(eph7_v2, line, &msg); break;
505
+ }
506
+ }
507
+ msg.update();
508
+ super_t::_has_next = true;
509
+ }
510
+
511
+ void seek_next_v3() {
512
+ char buf[256];
513
+
514
+ for(int i = 0; (i < 8) && (super_t::src.good()); i++){
515
+ if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
516
+ std::string line(buf);
517
+
518
+ switch(i){
519
+ case 0: {
520
+ // if(line_data[0] != 'G'){} // TODO check GPS before parsing
521
+ super_t::convert(eph0_v3, line, &msg);
522
+ msg.t_oc_tm.tm_year = msg.t_oc_year4 - 1900; // tm_year base is 1900
523
+ msg.t_oc_tm.tm_mon = msg.t_oc_mon12 - 1; // month [0, 11]
524
+ msg.t_oc_sec = msg.t_oc_tm.tm_sec;
525
+ break;
526
+ }
527
+ case 1: super_t::convert(eph1_v3, line, &msg); break;
528
+ case 2: super_t::convert(eph2_v3, line, &msg); break;
529
+ case 3: super_t::convert(eph3_v3, line, &msg); break;
530
+ case 4: super_t::convert(eph4_v3, line, &msg); break;
531
+ case 5: super_t::convert(eph5_v3, line, &msg); break;
532
+ case 6: super_t::convert(eph6_v3, line, &msg); break;
533
+ case 7: super_t::convert(eph7_v3, line, &msg); break;
534
+ }
535
+ }
536
+ msg.update();
537
+ super_t::_has_next = true;
538
+ }
539
+
540
+ void seek_next() {
541
+ super_t::version_type.version >= 300 ? seek_next_v3() : seek_next_v2();
542
+ }
543
+
544
+ public:
545
+ RINEX_NAV_Reader(std::istream &in) : super_t(in) {
546
+ seek_next();
547
+ }
548
+ ~RINEX_NAV_Reader(){}
549
+
550
+ typename space_node_t::Satellite::Ephemeris next() {
551
+ typename space_node_t::Satellite::Ephemeris current(msg.eph);
552
+ super_t::_has_next = false;
553
+ seek_next();
554
+ return current;
555
+ }
556
+
557
+ static const typename super_t::convert_item_t iono_alpha_v2[4];
558
+ static const typename super_t::convert_item_t iono_beta_v2[4];
559
+ static const typename super_t::convert_item_t utc_v2[4];
560
+ static const typename super_t::convert_item_t utc_leap_v2[1];
561
+
562
+ /**
563
+ * Obtain ionospheric delay coefficient and UTC parameters.
564
+ *
565
+ * @return true when successfully obtained, otherwise false
566
+ */
567
+ bool extract_iono_utc_v2(GPS_SpaceNode<FloatT> &space_node) const {
568
+ iono_utc_t iono_utc;
569
+ bool alpha, beta, utc, leap;
570
+ super_t::header_t::const_iterator it;
571
+
572
+ if(alpha = ((it = _header.find("ION ALPHA")) != _header.end())){
573
+ super_t::convert(iono_alpha_v2, it->second.front(), &iono_utc);
574
+ }
575
+
576
+ if(beta = ((it = _header.find("ION BETA")) != _header.end())){
577
+ super_t::convert(iono_beta_v2, it->second.front(), &iono_utc);
578
+ }
579
+
580
+ if(utc = ((it = _header.find("DELTA-UTC: A0,A1,T,W")) != _header.end())){
581
+ super_t::convert(utc_v2, it->second.front(), &iono_utc);
582
+ }
583
+
584
+ if(leap = ((it = _header.find("LEAP SECONDS")) != _header.end())){
585
+ super_t::convert(utc_leap_v2, it->second.front(), &iono_utc);
586
+ }
587
+
588
+ space_node.update_iono_utc(iono_utc, alpha && beta, utc && leap);
589
+ return alpha && beta && utc && leap;
590
+ }
591
+
592
+ static const typename super_t::convert_item_t iono_alpha_v3[4];
593
+ static const typename super_t::convert_item_t iono_beta_v3[4];
594
+ static const typename super_t::convert_item_t utc_v3[4];
595
+ static const typename super_t::convert_item_t utc_leap_v301[4];
596
+
597
+ bool extract_iono_utc_v3(GPS_SpaceNode<FloatT> &space_node) const {
598
+ iono_utc_t iono_utc;
599
+ bool alpha(false), beta(false), utc(false), leap(false);
600
+ typedef super_t::header_t::const_iterator it_t;
601
+ typedef super_t::header_t::mapped_type::const_iterator it2_t;
602
+
603
+ it_t it;
604
+
605
+ if((it = _header.find("IONOSPHERIC CORR")) != _header.end()){
606
+ for(it2_t it2(it->second.begin()), it2_end(it->second.end()); it2 != it2_end; ++it2){
607
+ if(it2->find("GPSA") != it2->npos){
608
+ super_t::convert(iono_alpha_v3, *it2, &iono_utc);
609
+ alpha = true;
610
+ }else if(it2->find("GPSB") != it2->npos){
611
+ super_t::convert(iono_beta_v3, *it2, &iono_utc);
612
+ beta = true;
613
+ }
614
+ }
615
+ }
616
+
617
+ if((it = _header.find("TIME SYSTEM CORR")) != _header.end()){
618
+ for(it2_t it2(it->second.begin()), it2_end(it->second.end()); it2 != it2_end; ++it2){
619
+ if(it2->find("GPUT") == it2->npos){continue;}
620
+ super_t::convert(utc_v3, *it2, &iono_utc);
621
+ utc = true;
622
+ }
623
+ }
624
+
625
+ if((it = _header.find("LEAP SECONDS")) != _header.end()){
626
+ if(version_type.version >= 301){
627
+ super_t::convert(utc_leap_v301, it->second.front(), &iono_utc);
628
+ }else{
629
+ super_t::convert(utc_leap_v2, it->second.front(), &iono_utc);
630
+ }
631
+ leap = true;
632
+ }
633
+
634
+ space_node.update_iono_utc(iono_utc, alpha && beta, utc && leap);
635
+ return alpha && beta && utc && leap;
636
+ }
637
+
638
+ static int read_all(std::istream &in, space_node_t &space_node){
639
+ int res(-1);
640
+ RINEX_NAV_Reader reader(in);
641
+ (reader.version_type.version >= 300)
642
+ ? reader.extract_iono_utc_v3(space_node)
643
+ : reader.extract_iono_utc_v2(space_node);
644
+ res++;
645
+ for(; reader.has_next(); ++res){
646
+ typename space_node_t::Satellite::Ephemeris eph(reader.next());
647
+ space_node.satellite(eph.svid).register_ephemeris(eph);
648
+ }
649
+ return res;
650
+ }
651
+ };
652
+
653
+ template <class FloatT>
654
+ struct RINEX_OBS {
655
+ struct epoch_flag_t {
656
+ std::tm epoch;
657
+ int epoch_year4, epoch_year2, epoch_mon12;
658
+ FloatT epoch_sec;
659
+ int flag;
660
+ int items_followed;
661
+ FloatT receiver_clock_error;
662
+
663
+ epoch_flag_t &operator=(const GPS_Time<FloatT> &t){
664
+ epoch = t.c_tm();
665
+ epoch_year4 = epoch.tm_year + 1900;
666
+ epoch_year2 = epoch.tm_year % 100;
667
+ epoch_mon12 = epoch.tm_mon + 1;
668
+ epoch_sec = std::fmod(t.seconds, 60);
669
+ return *this;
670
+ }
671
+ operator GPS_Time<FloatT>() const {
672
+ return GPS_Time<FloatT>(epoch) + (epoch_sec - epoch.tm_sec);
673
+ }
674
+ };
675
+
676
+ struct observation_t {
677
+ GPS_Time<FloatT> t_epoch;
678
+ FloatT receiver_clock_error;
679
+ struct record_t {
680
+ bool valid;
681
+ FloatT value;
682
+ int lli, ss; // if negative
683
+ };
684
+ typedef std::map<int, std::vector<record_t> > per_satellite_t;
685
+ per_satellite_t per_satellite;
686
+
687
+ observation_t &operator=(const epoch_flag_t &epoch_flag){
688
+ t_epoch = (GPS_Time<FloatT>)epoch_flag;
689
+ receiver_clock_error = epoch_flag.receiver_clock_error;
690
+ return *this;
691
+ }
692
+ operator epoch_flag_t() const {
693
+ epoch_flag_t res = {0};
694
+ res = t_epoch;
695
+ res.receiver_clock_error = receiver_clock_error;
696
+ return res;
697
+ }
698
+ };
699
+ };
700
+
701
+ template <class FloatT = double>
702
+ class RINEX_OBS_Reader : public RINEX_Reader<> {
703
+ protected:
704
+ typedef RINEX_OBS_Reader<FloatT> self_t;
705
+ typedef RINEX_Reader<> super_t;
706
+ public:
707
+ typedef typename RINEX_OBS<FloatT>::epoch_flag_t epoch_flag_t;
708
+ typedef typename RINEX_OBS<FloatT>::observation_t::record_t record_t;
709
+
710
+ static const typename super_t::convert_item_t epoch_flag_v2[9], epoch_flag_v3[9];
711
+ static const typename super_t::convert_item_t record_v2v3[3];
712
+
713
+ typedef typename RINEX_OBS<FloatT>::observation_t observation_t;
714
+
715
+ static int sys2serial(const char &c){
716
+ switch(c){
717
+ case ' ':
718
+ case 'G': return 0; // NAVSTAR
719
+ case 'R': return 0x100; break; // GLONASS
720
+ case 'E': return 0x200; break; // Galileo, since ver 2.11
721
+ case 'J': return 192; break; // QZSS, since ver 3.02, J01 = PRN193
722
+ case 'C': return 0x300; break; // BDS, since ver 3.02
723
+ case 'I': return 0x400; break; // IRNSS, since ver 3.03
724
+ case 'S': return 100; break; // SBAS, S20 = PRN120
725
+ default: return 0x800;
726
+ }
727
+ }
728
+ static char serial2sys(const int &serial, int &offset){
729
+ switch(serial & 0xF00){
730
+ case 0:
731
+ if(serial < 100){
732
+ offset = serial; return 'G'; // NAVSTAR
733
+ }else if(serial < 192){
734
+ offset = serial - 100; return 'S'; // SBAS, S20 = PRN120
735
+ }else{
736
+ offset = serial - 192; return 'J'; // QZSS, since ver 3.02, J01 = PRN193
737
+ }
738
+ break;
739
+ case 0x100: offset = serial - 0x100; return 'R'; // GLONASS
740
+ case 0x200: offset = serial - 0x200; return 'E'; // Galileo, since ver 2.11
741
+ case 0x300: offset = serial - 0x300; return 'C'; // BDS, since ver 3.02
742
+ case 0x400: offset = serial - 0x400; return 'I'; // IRNSS, since ver 3.03
743
+ }
744
+ offset = serial - 0x800; return ' '; // unknown
745
+ }
746
+
747
+
748
+ protected:
749
+ typedef std::map<char, std::vector<std::string> > obs_types_t;
750
+ obs_types_t obs_types;
751
+ observation_t obs;
752
+ static std::string &modify_header(std::string &label, std::string &content){
753
+ return content;
754
+ }
755
+
756
+ void seek_next_v2() {
757
+ char buf[256];
758
+ typedef std::vector<int> sat_list_t;
759
+ sat_list_t sat_list;
760
+ obs.per_satellite.clear();
761
+
762
+ while(true){
763
+
764
+ // Read lines for epoch
765
+ {
766
+ if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
767
+ std::string epoch_str(buf);
768
+ if((epoch_str.size() < 80) && (epoch_str.size() >= 32)){ // minimum 32 characters are required.
769
+ epoch_str.append(80 - epoch_str.size(), ' '); // add blank in case line is truncated
770
+ }
771
+
772
+ epoch_flag_t epoch_flag;
773
+ super_t::convert(epoch_flag_v2, epoch_str, &epoch_flag);
774
+ epoch_flag.epoch.tm_year = epoch_flag.epoch_year2 + (epoch_flag.epoch_year2 < 80 ? 100 : 0); // greater than 1980
775
+ epoch_flag.epoch.tm_mon = epoch_flag.epoch_mon12 - 1; // month [0, 11]
776
+ epoch_flag.epoch.tm_sec = (int)epoch_flag.epoch_sec;
777
+ obs = epoch_flag;
778
+
779
+ if(epoch_flag.flag >= 2){
780
+ for(int i(0); i < epoch_flag.items_followed; ++i){
781
+ if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
782
+ }
783
+ continue;
784
+ }
785
+
786
+ int prn;
787
+ for(int items(0), i(0); items < epoch_flag.items_followed; items++, i++){
788
+ if(i >= 12){ // if number of satellites is greater than 12, move to the next line
789
+ if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
790
+ epoch_str = std::string(buf);
791
+ i = 0;
792
+ }
793
+ super_t::template conv_t<int>::d(epoch_str, 33 + (i * 3), 2, &prn);
794
+ sat_list.push_back(prn + sys2serial(epoch_str[32 + (i * 3)]));
795
+ }
796
+ }
797
+
798
+ // Observation data per satellite
799
+ int types(obs_types[' '].size());
800
+ for(typename sat_list_t::const_iterator it(sat_list.begin()), it_end(sat_list.end());
801
+ it != it_end; ++it){
802
+ std::string obs_str;
803
+ for(int i(0), offset(80); i < types; i++, offset += 16){
804
+ if(offset >= 80){
805
+ if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
806
+ obs_str = std::string(buf);
807
+ if(obs_str.size() < 80){
808
+ obs_str.append(80 - obs_str.size(), ' '); // add blank in case line is truncated
809
+ }
810
+ offset = 0;
811
+ }
812
+ typename observation_t::record_t record = {false, 0};
813
+ std::string record_str(obs_str.substr(offset, 16));
814
+ if(record_str[10] == '.'){
815
+ record.valid = true;
816
+ super_t::convert(record_v2v3, record_str, &record);
817
+ }
818
+ obs.per_satellite[*it].push_back(record);
819
+ }
820
+ }
821
+
822
+ break;
823
+ }
824
+
825
+ super_t::_has_next = true;
826
+ }
827
+
828
+ void seek_next_v3() {
829
+ char buf[1024];
830
+ typedef std::vector<int> sat_list_t;
831
+ sat_list_t sat_list;
832
+ obs.per_satellite.clear();
833
+
834
+ while(true){
835
+
836
+ // Read lines for epoch
837
+ epoch_flag_t epoch_flag;
838
+ {
839
+ if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
840
+ std::string epoch_str(buf);
841
+ if((epoch_str.size() < 56) && (epoch_str.size() >= 35)){
842
+ epoch_str.append(56 - epoch_str.size(), ' ');
843
+ }
844
+
845
+ super_t::convert(epoch_flag_v3, epoch_str, &epoch_flag);
846
+ epoch_flag.epoch.tm_year = epoch_flag.epoch_year4 - 1900; // greater than 1980
847
+ epoch_flag.epoch.tm_mon = epoch_flag.epoch_mon12 - 1; // month [0, 11]
848
+ epoch_flag.epoch.tm_sec = (int)epoch_flag.epoch_sec;
849
+ obs = epoch_flag;
850
+
851
+ if(epoch_flag.flag >= 2){
852
+ for(int i(0); i < epoch_flag.items_followed; ++i){
853
+ if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
854
+ }
855
+ continue;
856
+ }
857
+ }
858
+
859
+ // Observation data per satellite
860
+ for(int i(0); i < epoch_flag.items_followed; ++i){
861
+ if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
862
+ std::string obs_str(buf);
863
+ int types(obs_types[obs_str[0]].size()), serial;
864
+ super_t::template conv_t<int>::d(obs_str, 1, 3, &serial);
865
+ serial += sys2serial(obs_str[0]);
866
+ do{
867
+ int truncated((3 + 16 * types) - obs_str.size());
868
+ if(truncated <= 0){break;}
869
+ obs_str.append(truncated, ' ');
870
+ }while(false);
871
+ for(int j(0), offset(3); j < types; j++, offset += 16){
872
+ typename observation_t::record_t record = {false, 0};
873
+ std::string record_str(obs_str.substr(offset, 16));
874
+ if(record_str[10] == '.'){
875
+ record.valid = true;
876
+ super_t::convert(record_v2v3, record_str, &record);
877
+ }
878
+ obs.per_satellite[serial].push_back(record);
879
+ }
880
+ }
881
+
882
+ break;
883
+ }
884
+
885
+ super_t::_has_next = true;
886
+ }
887
+
888
+ void seek_next(){
889
+ if(obs_types.size() == 0){return;}
890
+ switch(super_t::version_type.version / 100){
891
+ case 2: seek_next_v2(); break;
892
+ case 3: seek_next_v3(); break;
893
+ }
894
+ }
895
+
896
+ public:
897
+ RINEX_OBS_Reader(std::istream &in)
898
+ : super_t(in, self_t::modify_header),
899
+ obs_types() {
900
+ typedef super_t::header_t::const_iterator it_t;
901
+ typedef super_t::header_t::mapped_type::const_iterator it2_t;
902
+ it_t it;
903
+ switch(super_t::version_type.version / 100){
904
+ case 2: if((it = _header.find("# / TYPES OF OBSERV")) != _header.end()){
905
+ int types(0);
906
+ for(it2_t it2(it->second.begin()), it2_end(it->second.end()); it2 != it2_end; ++it2){
907
+ if(types == 0){super_t::conv_t<int>::d(const_cast<std::string &>(*it2), 0, 6, &types);}
908
+ for(int i(0); i < 9; ++i){
909
+ std::string param_name(it2->substr(6 * i + 10, 2));
910
+ if(param_name != " "){
911
+ obs_types[' '].push_back(param_name);
912
+ }
913
+ }
914
+ }
915
+ }
916
+ break;
917
+ case 3: if((it = _header.find("SYS / # / OBS TYPES")) != _header.end()){
918
+ int types(0); char sys;
919
+ for(it2_t it2(it->second.begin()), it2_end(it->second.end()); it2 != it2_end; ++it2){
920
+ if(types == 0){
921
+ sys = (*it2)[0];
922
+ super_t::conv_t<int>::d(const_cast<std::string &>(*it2), 3, 3, &types);
923
+ }
924
+ for(int i(0); i < 13; ++i){
925
+ std::string param_name(it2->substr(4 * i + 7, 3));
926
+ if(param_name == " "){continue;}
927
+ obs_types[sys].push_back(param_name);
928
+ if((int)(obs_types[sys].size()) >= types){
929
+ types = 0;
930
+ break;
931
+ }
932
+ }
933
+ }
934
+ }
935
+ break;
936
+ }
937
+ seek_next();
938
+ }
939
+ ~RINEX_OBS_Reader(){}
940
+
941
+ observation_t next() {
942
+ observation_t current(obs);
943
+ super_t::_has_next = false;
944
+ seek_next();
945
+ return current;
946
+ }
947
+ /**
948
+ * Return index on data lines corresponding to specified label
949
+ * If not found, return -1.
950
+ *
951
+ */
952
+ int observed_index(const std::string &label, const char &system = ' ') const {
953
+ obs_types_t::const_iterator it(obs_types.find(system));
954
+ if(it == obs_types.end()){return -1;}
955
+ int res(distance(it->second.begin(),
956
+ find(it->second.begin(), it->second.end(), label)));
957
+ return (res >= (int)(it->second.size()) ? -1 : res);
958
+ }
959
+ };
960
+
961
+ #define GEN_D(offset, length, container_type, container_member, value_type) \
962
+ {super_t::template conv_t<value_type>::d, offset, length, \
963
+ offsetof(container_type, container_member)}
964
+ #define GEN_I(offset, length, container_type, container_member, value_type) \
965
+ {super_t::template conv_t<value_type>::d, offset, length, \
966
+ offsetof(container_type, container_member), 1}
967
+ #define GEN_F(offset, length, precision, container_type, container_member) \
968
+ {super_t::template conv_t<FloatT>::f, offset, length, \
969
+ offsetof(container_type, container_member), precision}
970
+ #define GEN_E(offset, length, precision, container_type, container_member) \
971
+ {super_t::template conv_t<FloatT>::e, offset, length, \
972
+ offsetof(container_type, container_member), precision}
973
+
974
+ template <class FloatT>
975
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph0_v2[] = {
976
+ GEN_D( 0, 2, message_t, eph.svid, int),
977
+ GEN_D( 3, 2, message_t, t_oc_year2, int),
978
+ GEN_D( 6, 2, message_t, t_oc_mon12, int),
979
+ GEN_D( 9, 2, message_t, t_oc_tm.tm_mday, int),
980
+ GEN_D(12, 2, message_t, t_oc_tm.tm_hour, int),
981
+ GEN_D(15, 2, message_t, t_oc_tm.tm_min, int),
982
+ GEN_F(17, 5, 1, message_t, t_oc_sec),
983
+ GEN_E(22, 19, 12, message_t, eph.a_f0),
984
+ GEN_E(41, 19, 12, message_t, eph.a_f1),
985
+ GEN_E(60, 19, 12, message_t, eph.a_f2),
986
+ };
987
+ template <class FloatT>
988
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph0_v3[] = {
989
+ GEN_I( 1, 2, message_t, eph.svid, int),
990
+ GEN_I( 4, 4, message_t, t_oc_year4, int),
991
+ GEN_I( 9, 2, message_t, t_oc_mon12, int),
992
+ GEN_I(12, 2, message_t, t_oc_tm.tm_mday, int),
993
+ GEN_I(15, 2, message_t, t_oc_tm.tm_hour, int),
994
+ GEN_I(18, 2, message_t, t_oc_tm.tm_min, int),
995
+ GEN_I(21, 2, message_t, t_oc_tm.tm_sec, int),
996
+ GEN_E(23, 19, 12, message_t, eph.a_f0),
997
+ GEN_E(42, 19, 12, message_t, eph.a_f1),
998
+ GEN_E(61, 19, 12, message_t, eph.a_f2),
999
+ };
1000
+
1001
+ template <class FloatT>
1002
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph1_v2[] = {
1003
+ GEN_E( 3, 19, 12, message_t, iode_f),
1004
+ GEN_E(22, 19, 12, message_t, eph.c_rs),
1005
+ GEN_E(41, 19, 12, message_t, eph.delta_n),
1006
+ GEN_E(60, 19, 12, message_t, eph.M0),
1007
+ };
1008
+ template <class FloatT>
1009
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph1_v3[] = {
1010
+ GEN_E( 4, 19, 12, message_t, iode_f),
1011
+ GEN_E(23, 19, 12, message_t, eph.c_rs),
1012
+ GEN_E(42, 19, 12, message_t, eph.delta_n),
1013
+ GEN_E(61, 19, 12, message_t, eph.M0),
1014
+ };
1015
+
1016
+ template <class FloatT>
1017
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph2_v2[] = {
1018
+ GEN_E( 3, 19, 12, message_t, eph.c_uc),
1019
+ GEN_E(22, 19, 12, message_t, eph.e),
1020
+ GEN_E(41, 19, 12, message_t, eph.c_us),
1021
+ GEN_E(60, 19, 12, message_t, eph.sqrt_A),
1022
+ };
1023
+ template <class FloatT>
1024
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph2_v3[] = {
1025
+ GEN_E( 4, 19, 12, message_t, eph.c_uc),
1026
+ GEN_E(23, 19, 12, message_t, eph.e),
1027
+ GEN_E(42, 19, 12, message_t, eph.c_us),
1028
+ GEN_E(61, 19, 12, message_t, eph.sqrt_A),
1029
+ };
1030
+
1031
+ template <class FloatT>
1032
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph3_v2[] = {
1033
+ GEN_E( 3, 19, 12, message_t, eph.t_oe),
1034
+ GEN_E(22, 19, 12, message_t, eph.c_ic),
1035
+ GEN_E(41, 19, 12, message_t, eph.Omega0),
1036
+ GEN_E(60, 19, 12, message_t, eph.c_is),
1037
+ };
1038
+ template <class FloatT>
1039
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph3_v3[] = {
1040
+ GEN_E( 4, 19, 12, message_t, eph.t_oe),
1041
+ GEN_E(23, 19, 12, message_t, eph.c_ic),
1042
+ GEN_E(42, 19, 12, message_t, eph.Omega0),
1043
+ GEN_E(61, 19, 12, message_t, eph.c_is),
1044
+ };
1045
+
1046
+ template <class FloatT>
1047
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph4_v2[] = {
1048
+ GEN_E( 3, 19, 12, message_t, eph.i0),
1049
+ GEN_E(22, 19, 12, message_t, eph.c_rc),
1050
+ GEN_E(41, 19, 12, message_t, eph.omega),
1051
+ GEN_E(60, 19, 12, message_t, eph.dot_Omega0),
1052
+ };
1053
+ template <class FloatT>
1054
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph4_v3[] = {
1055
+ GEN_E( 4, 19, 12, message_t, eph.i0),
1056
+ GEN_E(23, 19, 12, message_t, eph.c_rc),
1057
+ GEN_E(42, 19, 12, message_t, eph.omega),
1058
+ GEN_E(61, 19, 12, message_t, eph.dot_Omega0),
1059
+ };
1060
+
1061
+ template <class FloatT>
1062
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph5_v2[] = {
1063
+ GEN_E( 3, 19, 12, message_t, eph.dot_i0),
1064
+ GEN_E(22, 19, 12, message_t, dummy), // Codes on L2 channel
1065
+ GEN_E(41, 19, 12, message_t, t_oe_WN),
1066
+ GEN_E(60, 19, 12, message_t, dummy), // L2 P data flag
1067
+ };
1068
+ template <class FloatT>
1069
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph5_v3[] = {
1070
+ GEN_E( 4, 19, 12, message_t, eph.dot_i0),
1071
+ GEN_E(23, 19, 12, message_t, dummy), // Codes on L2 channel
1072
+ GEN_E(42, 19, 12, message_t, t_oe_WN),
1073
+ GEN_E(61, 19, 12, message_t, dummy), // L2 P data flag
1074
+ };
1075
+
1076
+ template <class FloatT>
1077
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph6_v2[] = {
1078
+ GEN_E( 3, 19, 12, message_t, ura_meter),
1079
+ GEN_E(22, 19, 12, message_t, SV_health_f),
1080
+ GEN_E(41, 19, 12, message_t, eph.t_GD),
1081
+ GEN_E(60, 19, 12, message_t, iodc_f),
1082
+ };
1083
+ template <class FloatT>
1084
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph6_v3[] = {
1085
+ GEN_E( 4, 19, 12, message_t, ura_meter),
1086
+ GEN_E(23, 19, 12, message_t, SV_health_f),
1087
+ GEN_E(42, 19, 12, message_t, eph.t_GD),
1088
+ GEN_E(61, 19, 12, message_t, iodc_f),
1089
+ };
1090
+
1091
+ template <class FloatT>
1092
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph7_v2[] = {
1093
+ GEN_E( 3, 19, 12, message_t, t_ot),
1094
+ GEN_E(22, 19, 12, message_t, fit_interval_hr),
1095
+ };
1096
+ template <class FloatT>
1097
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph7_v3[] = {
1098
+ GEN_E( 4, 19, 12, message_t, t_ot),
1099
+ GEN_E(23, 19, 12, message_t, fit_interval_hr),
1100
+ };
1101
+
1102
+ template <class FloatT>
1103
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::iono_alpha_v2[] = {
1104
+ GEN_E( 2, 12, 4, iono_utc_t, alpha[0]),
1105
+ GEN_E(14, 12, 4, iono_utc_t, alpha[1]),
1106
+ GEN_E(26, 12, 4, iono_utc_t, alpha[2]),
1107
+ GEN_E(38, 12, 4, iono_utc_t, alpha[3]),
1108
+ };
1109
+
1110
+ template <class FloatT>
1111
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::iono_beta_v2[] = {
1112
+ GEN_E( 2, 12, 4, iono_utc_t, beta[0]),
1113
+ GEN_E(14, 12, 4, iono_utc_t, beta[1]),
1114
+ GEN_E(26, 12, 4, iono_utc_t, beta[2]),
1115
+ GEN_E(38, 12, 4, iono_utc_t, beta[3]),
1116
+ };
1117
+
1118
+ template <class FloatT>
1119
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::utc_v2[] = {
1120
+ GEN_E( 3, 19, 12, iono_utc_t, A0),
1121
+ GEN_E( 22, 19, 12, iono_utc_t, A1),
1122
+ GEN_D( 41, 9, iono_utc_t, t_ot, int),
1123
+ GEN_D( 50, 9, iono_utc_t, WN_t, int),
1124
+ };
1125
+
1126
+ template <class FloatT>
1127
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::utc_leap_v2[] = {
1128
+ GEN_D(0, 6, iono_utc_t, delta_t_LS, int),
1129
+ };
1130
+
1131
+
1132
+ template <class FloatT>
1133
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::iono_alpha_v3[] = {
1134
+ GEN_E( 5, 12, 4, iono_utc_t, alpha[0]),
1135
+ GEN_E(17, 12, 4, iono_utc_t, alpha[1]),
1136
+ GEN_E(29, 12, 4, iono_utc_t, alpha[2]),
1137
+ GEN_E(41, 12, 4, iono_utc_t, alpha[3]),
1138
+ };
1139
+
1140
+ template <class FloatT>
1141
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::iono_beta_v3[] = {
1142
+ GEN_E( 5, 12, 4, iono_utc_t, beta[0]),
1143
+ GEN_E(17, 12, 4, iono_utc_t, beta[1]),
1144
+ GEN_E(29, 12, 4, iono_utc_t, beta[2]),
1145
+ GEN_E(41, 12, 4, iono_utc_t, beta[3]),
1146
+ };
1147
+
1148
+ template <class FloatT>
1149
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::utc_v3[] = {
1150
+ GEN_E( 5, 17, 10, iono_utc_t, A0),
1151
+ GEN_E(22, 16, 9, iono_utc_t, A1),
1152
+ GEN_D(39, 6, iono_utc_t, t_ot, int),
1153
+ GEN_D(46, 4, iono_utc_t, WN_t, int),
1154
+ };
1155
+
1156
+ template <class FloatT>
1157
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::utc_leap_v301[] = {
1158
+ GEN_D( 0, 6, iono_utc_t, delta_t_LS, int),
1159
+ GEN_D( 6, 6, iono_utc_t, delta_t_LSF, int),
1160
+ GEN_D(12, 6, iono_utc_t, WN_LSF, int),
1161
+ GEN_D(18, 6, iono_utc_t, DN, int),
1162
+ };
1163
+
1164
+ template <class FloatT>
1165
+ const typename RINEX_OBS_Reader<FloatT>::convert_item_t RINEX_OBS_Reader<FloatT>::epoch_flag_v2[] = {
1166
+ GEN_I( 1, 2, epoch_flag_t, epoch_year2, int),
1167
+ GEN_D( 4, 2, epoch_flag_t, epoch_mon12, int),
1168
+ GEN_D( 7, 2, epoch_flag_t, epoch.tm_mday, int),
1169
+ GEN_D(10, 2, epoch_flag_t, epoch.tm_hour, int),
1170
+ GEN_D(13, 2, epoch_flag_t, epoch.tm_min, int),
1171
+ GEN_F(15, 11, 7, epoch_flag_t, epoch_sec),
1172
+ GEN_D(28, 1, epoch_flag_t, flag, int),
1173
+ GEN_D(29, 3, epoch_flag_t, items_followed, int), // Satellite(flag = 0/1) or Line number(except for 0/1)
1174
+ GEN_F(68, 12, 9, epoch_flag_t, receiver_clock_error),
1175
+ };
1176
+
1177
+ template <class FloatT>
1178
+ const typename RINEX_OBS_Reader<FloatT>::convert_item_t RINEX_OBS_Reader<FloatT>::epoch_flag_v3[] = {
1179
+ GEN_I( 2, 4, epoch_flag_t, epoch_year4, int),
1180
+ GEN_I( 7, 2, epoch_flag_t, epoch_mon12, int),
1181
+ GEN_I(10, 2, epoch_flag_t, epoch.tm_mday, int),
1182
+ GEN_I(13, 2, epoch_flag_t, epoch.tm_hour, int),
1183
+ GEN_I(16, 2, epoch_flag_t, epoch.tm_min, int),
1184
+ GEN_F(18, 11, 7, epoch_flag_t, epoch_sec),
1185
+ GEN_D(31, 1, epoch_flag_t, flag, int),
1186
+ GEN_D(32, 3, epoch_flag_t, items_followed, int), // Satellite(flag = 0/1) or Line number(except for 0/1)
1187
+ GEN_F(41, 15, 12, epoch_flag_t, receiver_clock_error),
1188
+ };
1189
+
1190
+ template <class FloatT>
1191
+ const typename RINEX_OBS_Reader<FloatT>::convert_item_t RINEX_OBS_Reader<FloatT>::record_v2v3[] = {
1192
+ GEN_F( 0, 14, 3, record_t, value),
1193
+ GEN_D(14, 1, record_t, lli, int),
1194
+ GEN_D(15, 1, record_t, ss, int),
1195
+ };
1196
+
1197
+ #undef GEN_D
1198
+ #undef GEN_I
1199
+ #undef GEN_F
1200
+ #undef GEN_E
1201
+
1202
+ template <class U = void>
1203
+ class RINEX_Writer {
1204
+ public:
1205
+ typedef typename RINEX_Reader<U>::version_type_t version_type_t;
1206
+ typedef struct {const char *key, *value;} header_item_t;
1207
+
1208
+ struct header_t : public std::vector<std::pair<std::string, std::string> > {
1209
+ typedef std::vector<std::pair<std::string, std::string> > super_t;
1210
+
1211
+ using super_t::operator[];
1212
+ struct bracket_accessor_t {
1213
+ header_t &header;
1214
+ typename super_t::value_type::first_type key;
1215
+ typename super_t::iterator it_head, it_tail;
1216
+ bracket_accessor_t(header_t &_header, const typename super_t::value_type::first_type &_key)
1217
+ : header(_header), key(_key), it_head(header.end()), it_tail(header.end()) {
1218
+ for(typename super_t::iterator it(header.begin()), it_end(header.end());
1219
+ it != it_end; ++it){
1220
+ if(it->first != key){continue;}
1221
+ it_head = it;
1222
+ break;
1223
+ }
1224
+ for(typename super_t::reverse_iterator it(header.rbegin()), it_end(header.rend());
1225
+ it != it_end; ++it){
1226
+ if(it->first != key){continue;}
1227
+ it_tail = it.base() - 1;
1228
+ break;
1229
+ }
1230
+ }
1231
+ /**
1232
+ * replace value corresponding to key with erase of other entries having the same key
1233
+ */
1234
+ bracket_accessor_t &operator=(
1235
+ const typename super_t::value_type::second_type &value){
1236
+ if(it_head == header.end()){
1237
+ header.push_back(typename super_t::value_type(key, value));
1238
+ it_head = it_tail = header.rbegin().base();
1239
+ return *this;
1240
+ }
1241
+ it_head->second = value;
1242
+ for(; it_tail != it_head; --it_tail){
1243
+ if(it_tail->first == key){continue;}
1244
+ header.erase(it_tail);
1245
+ }
1246
+ return *this;
1247
+ }
1248
+ /**
1249
+ * add value corresponding to key after the last entry having the same key
1250
+ */
1251
+ bracket_accessor_t &operator<<(
1252
+ const typename super_t::value_type::second_type &value){
1253
+ if(it_tail == header.end()){
1254
+ header.push_back(typename super_t::value_type(key, value));
1255
+ it_head = it_tail = header.rbegin().base();
1256
+ return *this;
1257
+ }
1258
+ header.insert(++it_tail, typename super_t::value_type(key, value));
1259
+ return *this;
1260
+ }
1261
+ };
1262
+ bracket_accessor_t operator[]( // mimic of std::map::operator[]=
1263
+ const typename super_t::value_type::first_type &key){
1264
+ return bracket_accessor_t(*this, key);
1265
+ }
1266
+ /**
1267
+ * @param mask Defualt key-value pairs; its order is preserved for ourputs
1268
+ * @param mask_size size of masked items
1269
+ */
1270
+ header_t(
1271
+ const header_item_t *mandatory_items = NULL,
1272
+ const int &mandatory_item_size = 0)
1273
+ : super_t() {
1274
+ for(int i(0); i < mandatory_item_size; i++){
1275
+ super_t::push_back(typename super_t::value_type(
1276
+ mandatory_items[i].key, mandatory_items[i].value ? mandatory_items[i].value : ""));
1277
+ }
1278
+ }
1279
+ ~header_t() {}
1280
+ friend std::ostream &operator<<(std::ostream &out, const header_t &header){
1281
+ std::stringstream ss;
1282
+ ss << std::setfill(' ') << std::left;
1283
+ for(header_t::const_iterator it(header.begin()), it_end(header.end());
1284
+ it != it_end; ++it){
1285
+ ss << std::setw(60) << it->second.substr(0, 60)
1286
+ << std::setw(20) << it->first.substr(0, 20)
1287
+ << std::endl;
1288
+ }
1289
+ ss << std::setw(60) << "" << std::setw(20) << "END OF HEADER" << std::endl;
1290
+ return out << ss.str();
1291
+ }
1292
+ };
1293
+ protected:
1294
+ version_type_t _version_type;
1295
+ header_t _header;
1296
+ std::ostream &dist;
1297
+
1298
+ void set_version_type(const version_type_t &version_type){
1299
+ _version_type = version_type;
1300
+ std::string buf(60, ' ');
1301
+ _version_type.dump(buf);
1302
+ _header["RINEX VERSION / TYPE"] = buf;
1303
+ }
1304
+
1305
+ public:
1306
+ typedef RINEX_Writer<U> self_t;
1307
+ RINEX_Writer(
1308
+ std::ostream &out,
1309
+ const header_item_t *header_mask = NULL,
1310
+ const int header_mask_size = 0)
1311
+ : _version_type(), _header(header_mask, header_mask_size), dist(out) {
1312
+ }
1313
+ virtual ~RINEX_Writer() {_header.clear();}
1314
+
1315
+ header_t &header(){return _header;}
1316
+ const header_t &header() const {return const_cast<self_t *>(this)->header();}
1317
+
1318
+ template <class FloatT>
1319
+ static std::string RINEX_Float(
1320
+ const FloatT &value, const int width = 19, const int precision = 12){
1321
+ std::string s;
1322
+ RINEX_Reader<U>::template conv_t<FloatT>::f(s, 0, width, &const_cast<FloatT &>(value), precision, false);
1323
+ return s;
1324
+ }
1325
+ template <class FloatT>
1326
+ static std::string RINEX_FloatD(
1327
+ const FloatT &value, const int width = 19, const int precision = 12){
1328
+ std::string s;
1329
+ RINEX_Reader<U>::template conv_t<FloatT>::e(s, 0, width, &const_cast<FloatT &>(value), precision, false);
1330
+ return s;
1331
+ }
1332
+ template <class T>
1333
+ static std::string RINEX_Value(const T &value, const int width = 6){
1334
+ std::string s;
1335
+ RINEX_Reader<U>::template conv_t<T>::d(s, 0, width, &const_cast<T &>(value), 0, false);
1336
+ return s;
1337
+ }
1338
+
1339
+ static void convert(
1340
+ const typename RINEX_Reader<U>::convert_item_t *items, const int &size,
1341
+ std::string &buf, const void *values){
1342
+ // value => string
1343
+ for(int i(0); i < size; ++i){
1344
+ (*items[i].func)(
1345
+ buf, items[i].offset, items[i].length, (char *)(const_cast<void *>(values)) + items[i].value_offset,
1346
+ items[i].opt, false);
1347
+ }
1348
+ }
1349
+ template <int N>
1350
+ static inline void convert(
1351
+ const typename RINEX_Reader<U>::convert_item_t (&items)[N], std::string &buf, const void *values){
1352
+ convert(items, N, buf, values);
1353
+ }
1354
+
1355
+ void pgm_runby_date(
1356
+ const std::string &pgm, const std::string &runby,
1357
+ const std::tm &t, const char *tz = "UTC"){
1358
+ // ex) "XXRINEXO V9.9 AIUB 19900912 124300 UTC"
1359
+ char buf[21] = {0};
1360
+ std::strftime(buf, sizeof(buf) - 1, "%Y%m%d %H%M%S", &t);
1361
+ std::sprintf(&buf[15], " %-4s", tz);
1362
+ std::stringstream ss;
1363
+ ss << std::setfill(' ') << std::left
1364
+ << std::setw(20) << pgm.substr(0, 20)
1365
+ << std::setw(20) << runby.substr(0, 20)
1366
+ << buf;
1367
+ _header["PGM / RUN BY / DATE"] = ss.str();
1368
+ }
1369
+ };
1370
+
1371
+ template <class FloatT>
1372
+ class RINEX_NAV_Writer : public RINEX_Writer<> {
1373
+ public:
1374
+ typedef RINEX_NAV_Reader<FloatT> reader_t;
1375
+ typedef RINEX_NAV_Writer self_t;
1376
+ typedef RINEX_Writer<> super_t;
1377
+ protected:
1378
+ using super_t::_header;
1379
+ using super_t::dist;
1380
+ public:
1381
+ typedef typename RINEX_NAV<FloatT>::space_node_t space_node_t;
1382
+ typedef typename RINEX_NAV<FloatT>::message_t message_t;
1383
+
1384
+ static const typename super_t::header_item_t default_header[];
1385
+ static const int default_header_size;
1386
+ void iono_alpha(const space_node_t &space_node){
1387
+ std::string s(60, ' ');
1388
+ switch(super_t::_version_type.version / 100){
1389
+ case 2:
1390
+ super_t::convert(reader_t::iono_alpha_v2, s, &space_node.iono_utc());
1391
+ _header["ION ALPHA"] = s;
1392
+ break;
1393
+ case 3:
1394
+ super_t::convert(reader_t::iono_alpha_v3, s, &space_node.iono_utc());
1395
+ _header["IONOSPHERIC CORR"] << s.replace(0, 4, "GPSA", 4);
1396
+ break;
1397
+ }
1398
+ }
1399
+ void iono_beta(const space_node_t &space_node){
1400
+ std::string s(60, ' ');
1401
+ switch(super_t::_version_type.version / 100){
1402
+ case 2:
1403
+ super_t::convert(reader_t::iono_beta_v2, s, &space_node.iono_utc());
1404
+ _header["ION BETA"] = s;
1405
+ break;
1406
+ case 3:
1407
+ super_t::convert(reader_t::iono_beta_v3, s, &space_node.iono_utc());
1408
+ _header["IONOSPHERIC CORR"] << s.replace(0, 4, "GPSB", 4);
1409
+ break;
1410
+ }
1411
+ }
1412
+ void utc_params(const space_node_t &space_node){
1413
+ std::string s(60, ' ');
1414
+ switch(super_t::_version_type.version / 100){
1415
+ case 2:
1416
+ super_t::convert(reader_t::utc_v2, s, &space_node.iono_utc());
1417
+ _header["DELTA-UTC: A0,A1,T,W"] = s;
1418
+ break;
1419
+ case 3:
1420
+ super_t::convert(reader_t::utc_v3, s, &space_node.iono_utc());
1421
+ _header["TIME SYSTEM CORR"] << s.replace(0, 4, "GPUT", 4);
1422
+ break;
1423
+ }
1424
+ }
1425
+ void leap_seconds(const space_node_t &space_node){
1426
+ std::string s(60, ' ');
1427
+ if(super_t::_version_type.version >= 301){
1428
+ super_t::convert(reader_t::utc_leap_v301, s, &space_node.iono_utc());
1429
+ }else{
1430
+ super_t::convert(reader_t::utc_leap_v2, s, &space_node.iono_utc());
1431
+ }
1432
+ _header["LEAP SECONDS"] = s;
1433
+ }
1434
+ RINEX_NAV_Writer(std::ostream &out)
1435
+ : super_t(out, default_header, default_header_size) {}
1436
+ ~RINEX_NAV_Writer(){}
1437
+
1438
+ self_t &operator<<(const message_t &msg){
1439
+ std::stringstream buf;
1440
+ switch(super_t::_version_type.version / 100){
1441
+ case 2:
1442
+ for(int i(0); i < 8; ++i){
1443
+ std::string s(80, ' ');
1444
+ switch(i){
1445
+ case 0: super_t::convert(reader_t::eph0_v2, s, &msg); break;
1446
+ case 1: super_t::convert(reader_t::eph1_v2, s, &msg); break;
1447
+ case 2: super_t::convert(reader_t::eph2_v2, s, &msg); break;
1448
+ case 3: super_t::convert(reader_t::eph3_v2, s, &msg); break;
1449
+ case 4: super_t::convert(reader_t::eph4_v2, s, &msg); break;
1450
+ case 5: super_t::convert(reader_t::eph5_v2, s, &msg); break;
1451
+ case 6: super_t::convert(reader_t::eph6_v2, s, &msg); break;
1452
+ case 7: super_t::convert(reader_t::eph7_v2, s, &msg); break;
1453
+ }
1454
+ buf << s << std::endl;
1455
+ }
1456
+ break;
1457
+ case 3:
1458
+ for(int i(0); i < 8; ++i){
1459
+ std::string s(80, ' ');
1460
+ switch(i){
1461
+ case 0: super_t::convert(reader_t::eph0_v3, s, &msg); s[0] = 'G'; break;
1462
+ case 1: super_t::convert(reader_t::eph1_v3, s, &msg); break;
1463
+ case 2: super_t::convert(reader_t::eph2_v3, s, &msg); break;
1464
+ case 3: super_t::convert(reader_t::eph3_v3, s, &msg); break;
1465
+ case 4: super_t::convert(reader_t::eph4_v3, s, &msg); break;
1466
+ case 5: super_t::convert(reader_t::eph5_v3, s, &msg); break;
1467
+ case 6: super_t::convert(reader_t::eph6_v3, s, &msg); break;
1468
+ case 7: super_t::convert(reader_t::eph7_v3, s, &msg); break;
1469
+ }
1470
+ buf << s << std::endl;
1471
+ }
1472
+ break;
1473
+ }
1474
+ dist << buf.str();
1475
+ return *this;
1476
+ }
1477
+
1478
+ protected:
1479
+ struct WriteAllFunctor {
1480
+ RINEX_NAV_Writer &w;
1481
+ int &counter;
1482
+ void operator()(const typename space_node_t::Satellite::Ephemeris &eph) {
1483
+ w << message_t(eph);
1484
+ counter++;
1485
+ }
1486
+ };
1487
+
1488
+ public:
1489
+ void set_version(
1490
+ const int &version,
1491
+ const super_t::version_type_t::sat_system_t &sys = super_t::version_type_t::SYS_GPS){
1492
+ super_t::set_version_type(typename super_t::version_type_t(
1493
+ version, super_t::version_type_t::FTYPE_NAVIGATION, sys));
1494
+ }
1495
+
1496
+ int write_all(const space_node_t &space_node, const int &version = 304){
1497
+ int res(-1);
1498
+ set_version(version);
1499
+ if(space_node.is_valid_iono_utc()){
1500
+ iono_alpha(space_node);
1501
+ iono_beta(space_node);
1502
+ utc_params(space_node);
1503
+ leap_seconds(space_node);
1504
+ }
1505
+ super_t::dist << header();
1506
+ res++;
1507
+
1508
+ WriteAllFunctor functor = {*this, res};
1509
+ for(typename space_node_t::satellites_t::const_iterator
1510
+ it(space_node.satellites().begin()), it_end(space_node.satellites().end());
1511
+ it != it_end; ++it){
1512
+ it->second.each_ephemeris(
1513
+ functor,
1514
+ space_node_t::Satellite::eph_list_t::EACH_ALL_INVERTED);
1515
+ }
1516
+ return res;
1517
+ }
1518
+ static int write_all(std::ostream &out, const space_node_t &space_node, const int &version = 304){
1519
+ RINEX_NAV_Writer writer(out);
1520
+ return writer.write_all(space_node, version);
1521
+ }
1522
+ };
1523
+ template <class FloatT>
1524
+ const typename RINEX_Writer<>::header_item_t RINEX_NAV_Writer<FloatT>::default_header[] = {
1525
+ {"RINEX VERSION / TYPE",
1526
+ " 2 NAVIGATION DATA"},
1527
+ {"PGM / RUN BY / DATE", NULL}};
1528
+ template <class FloatT>
1529
+ const int RINEX_NAV_Writer<FloatT>::default_header_size
1530
+ = sizeof(RINEX_NAV_Writer<FloatT>::default_header) / sizeof(RINEX_NAV_Writer<FloatT>::default_header[0]);
1531
+
1532
+ template <class FloatT>
1533
+ class RINEX_OBS_Writer : public RINEX_Writer<> {
1534
+ public:
1535
+ typedef typename RINEX_OBS<FloatT>::observation_t observation_t;
1536
+ typedef RINEX_OBS_Writer self_t;
1537
+ typedef RINEX_Writer<> super_t;
1538
+ typedef RINEX_OBS_Reader<FloatT> reader_t;
1539
+ protected:
1540
+ using super_t::RINEX_Float;
1541
+ using super_t::RINEX_FloatD;
1542
+ using super_t::RINEX_Value;
1543
+ using super_t::_header;
1544
+ using super_t::dist;
1545
+ public:
1546
+ void set_version(
1547
+ const int &version,
1548
+ const super_t::version_type_t::sat_system_t &sys = super_t::version_type_t::SYS_GPS){
1549
+ super_t::set_version_type(typename super_t::version_type_t(
1550
+ version, super_t::version_type_t::FTYPE_OBSERVATION, sys));
1551
+ }
1552
+
1553
+ static const header_item_t default_header[];
1554
+ static const int default_header_size;
1555
+ void maker_name(
1556
+ const std::string &name){
1557
+ _header["MARKER NAME"] = name.substr(0, 60);
1558
+ }
1559
+ void observer_agency(
1560
+ const std::string &observer, const std::string &agency){
1561
+ // ex) "BILL SMITH ABC INSTITUTE"
1562
+ std::stringstream ss;
1563
+ ss << std::setfill(' ') << std::left
1564
+ << std::setw(20) << observer.substr(0, 20)
1565
+ << std::setw(20) << agency.substr(0, 20);
1566
+ _header["OBSERVER / AGENCY"] = ss.str();
1567
+ }
1568
+ void receiver_spec(
1569
+ const std::string &num, const std::string &type, const std::string &vers){
1570
+ // ex) "X1234A123 XX ZZZ"
1571
+ std::stringstream ss;
1572
+ ss << std::setfill(' ') << std::left
1573
+ << std::setw(20) << num.substr(0, 20)
1574
+ << std::setw(20) << type.substr(0, 20)
1575
+ << std::setw(20) << vers.substr(0, 20);
1576
+ _header["REC # / TYPE / VERS"] = ss.str();
1577
+ }
1578
+ void antenna_spec(
1579
+ const std::string &num, const std::string &type){
1580
+ // ex) "234 YY"
1581
+ std::stringstream ss;
1582
+ ss << std::setfill(' ') << std::left
1583
+ << std::setw(20) << num.substr(0, 20)
1584
+ << std::setw(20) << type.substr(0, 20);
1585
+ _header["ANT # / TYPE"] = ss.str();
1586
+ }
1587
+ void wavelength_fact(
1588
+ const int l1, const int l2){
1589
+ // ex) " 1 1"
1590
+ std::stringstream ss;
1591
+ ss << RINEX_Value(l1, 6) << RINEX_Value(l2, 6);
1592
+ _header["WAVELENGTH FACT L1/2"] = ss.str();
1593
+ }
1594
+ void approx_position(
1595
+ const FloatT &x, const FloatT &y, const FloatT &z){
1596
+ std::stringstream ss;
1597
+ ss << RINEX_Float(x, 14, 4)
1598
+ << RINEX_Float(y, 14, 4)
1599
+ << RINEX_Float(z, 14, 4);
1600
+ _header["APPROX POSITION XYZ"] = ss.str();
1601
+ }
1602
+ void antenna_delta_hew(
1603
+ const FloatT &h, const FloatT &e, const FloatT &w){
1604
+ std::stringstream ss;
1605
+ ss << RINEX_Float(h, 14, 4)
1606
+ << RINEX_Float(e, 14, 4)
1607
+ << RINEX_Float(w, 14, 4);
1608
+ _header["ANTENNA: DELTA H/E/W"] = ss.str();
1609
+ }
1610
+ void types_of_obs(
1611
+ const char *type_list[], const int list_size){
1612
+ std::stringstream ss;
1613
+ ss << RINEX_Value(list_size, 6);
1614
+ for(int i(0); i < list_size; i++){
1615
+ ss << RINEX_Value(
1616
+ std::string(type_list[i]).substr(0, 6), 6);
1617
+ }
1618
+ _header["# / TYPES OF OBSERV"] = ss.str();
1619
+ }
1620
+ void interval(const FloatT &seconds){
1621
+ std::stringstream ss;
1622
+ ss << RINEX_Float(seconds, 6, 4);
1623
+ _header["INTERVAL"] = ss.str();
1624
+ }
1625
+ void interval(const int seconds){
1626
+ std::stringstream ss;
1627
+ ss << RINEX_Value(seconds, 6);
1628
+ _header["INTERVAL"] = ss.str();
1629
+ }
1630
+ void insert_header_time_item(
1631
+ const char *label,
1632
+ const struct tm &t, const FloatT &rest_second = 0,
1633
+ const bool is_gps_time = true){
1634
+ std::stringstream ss;
1635
+ if(t.tm_year < 80){
1636
+ ss << RINEX_Value(2000 + t.tm_year, 6);
1637
+ }else{
1638
+ ss << RINEX_Value(1900 + t.tm_year, 6);
1639
+ }
1640
+ ss << RINEX_Value(t.tm_mon + 1, 6);
1641
+ ss << RINEX_Value(t.tm_mday, 6);
1642
+ ss << RINEX_Value(t.tm_hour, 6);
1643
+ ss << RINEX_Value(t.tm_min, 6);
1644
+ ss << RINEX_Float(rest_second + t.tm_sec, 12, 6);
1645
+ if(is_gps_time){
1646
+ ss << RINEX_Value("GPS", 9);
1647
+ }
1648
+ _header[label] = ss.str();
1649
+ }
1650
+ void insert_header_time_item(
1651
+ const char *label, const GPS_Time<FloatT> &t){
1652
+ FloatT sec_f(t.seconds), sec_i;
1653
+ sec_f = std::modf(sec_f, &sec_i);
1654
+ insert_header_time_item(label,
1655
+ t.c_tm(), sec_f, true);
1656
+ }
1657
+ void first_obs(
1658
+ const struct tm &t, const double rest_second = 0,
1659
+ const bool is_gps_time = true){
1660
+ insert_header_time_item("TIME OF FIRST OBS",
1661
+ t, rest_second, is_gps_time);
1662
+ }
1663
+ void first_obs(const GPS_Time<FloatT> &t){
1664
+ insert_header_time_item("TIME OF FIRST OBS", t);
1665
+ }
1666
+ void last_obs(
1667
+ const struct tm &t, const double rest_second = 0,
1668
+ const bool is_gps_time = true){
1669
+ insert_header_time_item("TIME OF LAST OBS",
1670
+ t, rest_second, is_gps_time);
1671
+ }
1672
+ void last_obs(const GPS_Time<FloatT> &t){
1673
+ insert_header_time_item("TIME OF LAST OBS", t);
1674
+ }
1675
+ RINEX_OBS_Writer(std::ostream &out)
1676
+ : super_t(out, default_header, default_header_size) {}
1677
+ ~RINEX_OBS_Writer(){}
1678
+ self_t &operator<<(const observation_t &obs){
1679
+ if(obs.per_satellite.size() <= 0){return *this;}
1680
+
1681
+ typedef typename observation_t::per_satellite_t per_satellite_t;
1682
+
1683
+ std::stringstream top, rest;
1684
+
1685
+ std::string buf(80, ' ');
1686
+ int ver_major(super_t::_version_type.version / 100);
1687
+ { // epoch
1688
+ typename RINEX_OBS<FloatT>::epoch_flag_t epoch_flag(obs);
1689
+ epoch_flag.items_followed = obs.per_satellite.size(); // Num. of satellites
1690
+ switch(ver_major){
1691
+ case 2: super_t::convert(reader_t::epoch_flag_v2, buf, &epoch_flag); break;
1692
+ case 3: super_t::convert(reader_t::epoch_flag_v3, buf, &epoch_flag); buf[0] = '>'; break;
1693
+ default: return *this;
1694
+ }
1695
+ }
1696
+
1697
+ int i(0);
1698
+ for(typename per_satellite_t::const_iterator
1699
+ it(obs.per_satellite.begin()), it_end(obs.per_satellite.end());
1700
+ it != it_end; ++it, ++i){ // Enumerate satellites
1701
+
1702
+ // If satellites are more than 12, then use the next line
1703
+ if((i == 12) && (ver_major == 2)){
1704
+ i = 0;
1705
+ top << buf << std::endl;
1706
+ buf = std::string(80, ' ');
1707
+ }
1708
+
1709
+ // Write PRN number to list
1710
+ {
1711
+ int serial(it->first), prn;
1712
+ char sys(reader_t::serial2sys(serial, prn));
1713
+ std::string sat_str(3, ' ');
1714
+ sat_str[0] = sys;
1715
+ reader_t::template conv_t<int>::d(sat_str, 1, 2, &prn, 1, false);
1716
+ switch(ver_major){
1717
+ case 2: buf.replace(32 + i * 3, 3, sat_str); break;
1718
+ case 3: rest << sat_str; break;
1719
+ }
1720
+ }
1721
+
1722
+ // Observation data
1723
+ int i2(5);
1724
+ for(typename per_satellite_t::mapped_type::const_iterator it2(it->second.begin()),
1725
+ it2_end(it->second.end());
1726
+ it2 != it2_end; ++it2){
1727
+ if((ver_major == 2) && (i2-- == 0)){
1728
+ i2 = 4;
1729
+ rest << std::endl;
1730
+ }
1731
+ std::string buf2(16, ' ');
1732
+ if(it2->valid){
1733
+ super_t::convert(reader_t::record_v2v3, buf2, &(*it2));
1734
+ if(it2->lli == 0){buf2[14] = ' ';}
1735
+ if(it2->ss == 0){buf2[15] = ' ';}
1736
+ }
1737
+ rest << buf2;
1738
+ }
1739
+ if(ver_major == 2){
1740
+ rest << std::string(16 * i2, ' ');
1741
+ }
1742
+ rest << std::endl;
1743
+ }
1744
+ top << buf << std::endl;
1745
+
1746
+ dist << top.str() << rest.str();
1747
+ return *this;
1748
+ }
1749
+ };
1750
+ template <class FloatT>
1751
+ const typename RINEX_Writer<>::header_item_t RINEX_OBS_Writer<FloatT>::default_header[] = {
1752
+ {"RINEX VERSION / TYPE",
1753
+ " 2 OBSERVATION DATA"},
1754
+ {"PGM / RUN BY / DATE",
1755
+ "XXRINEXO V9.9 AIUB 12-SEP-90 12:43"},
1756
+ {"COMMENT", NULL},
1757
+ {"MARKER NAME", "A 9080"},
1758
+ {"MARKER NUMBER", NULL},
1759
+ {"OBSERVER / AGENCY",
1760
+ "BILL SMITH ABC INSTITUTE"},
1761
+ {"REC # / TYPE / VERS",
1762
+ "X1234A123 XX ZZZ"},
1763
+ {"ANT # / TYPE", "234 YY"},
1764
+ {"APPROX POSITION XYZ",
1765
+ " -3947762.7496 3364399.8789 3699428.5111"},
1766
+ {"ANTENNA: DELTA H/E/W",
1767
+ " 0.0000 0.0000 0.0000"},
1768
+ {"WAVELENGTH FACT L1/2",
1769
+ " 1 1"},
1770
+ {"# / TYPES OF OBSERV",
1771
+ " 4 P1 L1 L2 P2"},
1772
+ {"INTERVAL", " 1"},
1773
+ {"TIME OF FIRST OBS", " 1990 3 24 13 10 36.000000"},
1774
+ {"TIME OF LAST OBS", NULL},
1775
+ {"# OF SATELLITES", NULL},
1776
+ {"PRN / # OF OBS", NULL}};
1777
+ template <class FloatT>
1778
+ const int RINEX_OBS_Writer<FloatT>::default_header_size
1779
+ = sizeof(RINEX_OBS_Writer<FloatT>::default_header) / sizeof(RINEX_OBS_Writer<FloatT>::default_header[0]);
1780
+
1781
+ #endif // __RINEX_H__