gps_pvt 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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__