gps_pvt 0.2.1 → 0.3.3

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.
@@ -49,11 +49,7 @@ struct SBAS_SinglePositioning_Options : public GPS_Solver_GeneralOptions<FloatT>
49
49
 
50
50
  typename GPS_Solver_Base<FloatT>::options_t::template exclude_prn_t<120, 158> exclude_prn; // SBAS PRN ranges from 120 to 158
51
51
  SBAS_SinglePositioning_Options()
52
- : super_t() {
53
- // default: SBAS IGP, then broadcasted Klobuchar.
54
- super_t::ionospheric_models[0] = super_t::IONOSPHERIC_SBAS;
55
- super_t::ionospheric_models[1] = super_t::IONOSPHERIC_KLOBUCHAR;
56
-
52
+ : super_t(), exclude_prn() {
57
53
  exclude_prn.set(true); // SBAS ranging is default off.
58
54
  }
59
55
  };
@@ -86,6 +82,8 @@ class SBAS_SinglePositioning : public SolverBaseT {
86
82
 
87
83
  typedef typename base_t::measurement_t measurement_t;
88
84
  typedef typename base_t::range_error_t range_error_t;
85
+ typedef typename base_t::range_corrector_t range_corrector_t;
86
+ typedef typename base_t::range_correction_t range_correction_t;
89
87
 
90
88
  inheritate_type(relative_property_t);
91
89
  #undef inheritate_type
@@ -93,8 +91,6 @@ class SBAS_SinglePositioning : public SolverBaseT {
93
91
  typedef typename GPS_Solver_Base<float_t>::options_t::template merge_t<
94
92
  SBAS_SinglePositioning_Options<float_t>, base_t> options_t;
95
93
 
96
- typedef GPS_SpaceNode<float_t> gps_space_node_t;
97
- const gps_space_node_t *space_node_gps; ///< optional
98
94
  protected:
99
95
  const space_node_t &_space_node;
100
96
  SBAS_SinglePositioning_Options<float_t> _options;
@@ -102,40 +98,47 @@ class SBAS_SinglePositioning : public SolverBaseT {
102
98
  public:
103
99
  const space_node_t &space_node() const {return _space_node;}
104
100
 
105
- /**
106
- * Check availability of ionospheric models
107
- * If a model is completely unavailable, it will be replaced to IONOSPHERIC_SKIP.
108
- * It implies that when a model has conditional applicability (such as SBAS), it will be retained.
109
- *
110
- * @return (int) number of (possibly) available models
111
- */
112
- int filter_ionospheric_models(SBAS_SinglePositioning_Options<float_t> &opt) const {
113
- int available_models(0);
114
- for(std::size_t i(0); i < sizeof(opt.ionospheric_models) / sizeof(opt.ionospheric_models[0]); ++i){
115
- bool usable(false);
116
- switch(opt.ionospheric_models[i]){
117
- case options_t::IONOSPHERIC_KLOBUCHAR:
118
- // check whether Klobuchar parameters alpha and beta have been already received
119
- if(space_node_gps && space_node_gps->is_valid_iono()){usable = true;}
120
- break;
121
- case options_t::IONOSPHERIC_SBAS:
122
- usable = true;
123
- break;
124
- case options_t::IONOSPHERIC_NTCM_GL:
125
- if(opt.f_10_7 >= 0){usable = true;}
126
- // check F10.7 has been already configured
127
- break;
128
- default:
129
- break;
130
- }
131
- if(usable){
132
- available_models++;
133
- }else{
134
- opt.ionospheric_models[i] = options_t::IONOSPHERIC_SKIP;
101
+ struct ionospheric_sbas_t : public range_corrector_t {
102
+ const space_node_t &space_node;
103
+ ionospheric_sbas_t(const space_node_t &sn) : range_corrector_t(), space_node(sn) {}
104
+ bool is_available(const gps_time_t &t) const {
105
+ return true;
106
+ }
107
+ float_t *calculate(
108
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
109
+ float_t &buf) const {
110
+
111
+ // placeholder of checking availability and performing correction
112
+ typedef typename space_node_t::available_satellites_t sats_t;
113
+ sats_t sats(space_node.available_satellites(usr_pos.llh.longitude()));
114
+
115
+ typename space_node_t::IonosphericGridPoints::PointProperty prop;
116
+ for(typename sats_t::const_iterator it(sats.begin()); it != sats.end(); ++it){
117
+ prop = it->second
118
+ ->ionospheric_grid_points().iono_correction(sat_rel_pos, usr_pos.llh);
119
+ if(prop.is_available()){
120
+ return &(buf = prop.delay);
121
+ }
122
+ break; // TODO The nearest satellite is only checked
135
123
  }
124
+ return NULL;
136
125
  }
137
- return available_models;
138
- }
126
+ } ionospheric_sbas;
127
+
128
+ struct tropospheric_sbas_t : public range_corrector_t {
129
+ tropospheric_sbas_t() : range_corrector_t() {}
130
+ bool is_available(const gps_time_t &t) const {
131
+ return true;
132
+ }
133
+ float_t *calculate(
134
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
135
+ float_t &buf) const {
136
+ return &(buf = space_node_t::tropo_correction(
137
+ t.year(), sat_rel_pos, usr_pos.llh));
138
+ }
139
+ } tropospheric_sbas;
140
+
141
+ range_correction_t ionospheric_correction, tropospheric_correction;
139
142
 
140
143
  options_t available_options() const {
141
144
  return options_t(base_t::available_options(), _options);
@@ -143,19 +146,24 @@ class SBAS_SinglePositioning : public SolverBaseT {
143
146
 
144
147
  options_t available_options(const options_t &opt_wish) const {
145
148
  SBAS_SinglePositioning_Options<float_t> opt(opt_wish);
146
- filter_ionospheric_models(opt);
147
149
  return options_t(base_t::available_options(opt_wish), opt);
148
150
  }
149
151
 
150
152
  options_t update_options(const options_t &opt_wish){
151
- filter_ionospheric_models(_options = opt_wish);
153
+ _options = opt_wish;
152
154
  return options_t(base_t::update_options(opt_wish), _options);
153
155
  }
154
156
 
155
- SBAS_SinglePositioning(const space_node_t &sn, const options_t &opt_wish = options_t())
156
- : base_t(),
157
- _space_node(sn), space_node_gps(NULL),
158
- _options(available_options(opt_wish)) {}
157
+ SBAS_SinglePositioning(const space_node_t &sn)
158
+ : base_t(), _space_node(sn), _options(available_options(options_t())),
159
+ ionospheric_sbas(sn), tropospheric_sbas() {
160
+
161
+ // default ionospheric correction: Broadcasted IGP.
162
+ ionospheric_correction.push_front(&ionospheric_sbas);
163
+
164
+ // default troposheric correction: SBAS
165
+ tropospheric_correction.push_front(&tropospheric_sbas);
166
+ }
159
167
 
160
168
  ~SBAS_SinglePositioning(){}
161
169
 
@@ -245,43 +253,12 @@ class SBAS_SinglePositioning : public SolverBaseT {
245
253
 
246
254
  // Tropospheric (2.1.4.10.3, A.4.2.4)
247
255
  res.range_residual += (range_error.unknown_flag & range_error_t::MASK_TROPOSPHERIC)
248
- ? _space_node.tropo_correction(time_arrival.year(), relative_pos, usr_pos.llh)
256
+ ? tropospheric_correction(time_arrival, usr_pos, relative_pos)
249
257
  : range_error.value[range_error_t::TROPOSPHERIC];
250
258
 
251
259
  // Ionospheric (2.1.4.10.2, A.4.4.10.4)
252
260
  if(range_error.unknown_flag & range_error_t::MASK_IONOSPHERIC){
253
- // Ionospheric model selection, the fall back is no correction
254
- bool iono_model_hit(false);
255
- for(std::size_t i(0); i < sizeof(_options.ionospheric_models) / sizeof(_options.ionospheric_models[0]); ++i){
256
- switch(_options.ionospheric_models[i]){
257
- case options_t::IONOSPHERIC_KLOBUCHAR: // 20.3.3.5.2.5
258
- res.range_residual += space_node_gps->iono_correction(relative_pos, usr_pos.llh, time_arrival);
259
- break;
260
- case options_t::IONOSPHERIC_SBAS: { // 2.1.4.10.2, A.4.4.10.4
261
- typename space_node_t::IonosphericGridPoints::PointProperty prop(
262
- sat->ionospheric_grid_points().iono_correction(relative_pos, usr_pos.llh));
263
- if(!prop.is_available()){continue;}
264
- res.range_residual += prop.delay;
265
- break;
266
- }
267
- case options_t::IONOSPHERIC_NTCM_GL: {
268
- // TODO f_10_7 setup, optimization (mag_model etc.)
269
- typename gps_space_node_t::pierce_point_res_t pp(gps_space_node_t::pierce_point(relative_pos, usr_pos.llh));
270
- res.range_residual -= gps_space_node_t::tec2delay(
271
- gps_space_node_t::slant_factor(relative_pos)
272
- * NTCM_GL_Generic<float_t>::tec_vert(
273
- pp.latitude, pp.longitude,
274
- time_arrival.year(), _options.f_10_7));
275
- break;
276
- }
277
- case options_t::IONOSPHERIC_NONE:
278
- break;
279
- default:
280
- continue;
281
- }
282
- iono_model_hit = true;
283
- break;
284
- }
261
+ res.range_residual += ionospheric_correction(time_arrival, usr_pos, relative_pos);
285
262
  }else{
286
263
  res.range_residual += range_error.value[range_error_t::IONOSPHERIC];
287
264
  }
@@ -60,6 +60,7 @@ struct const_div_t<denom, denom, log2, 0> {
60
60
  template <int MAX_SIZE, class ContainerT = unsigned char>
61
61
  struct BitArray {
62
62
  static const int bits_per_addr = (int)sizeof(ContainerT) * CHAR_BIT;
63
+ static const int max_size = MAX_SIZE;
63
64
  ContainerT buf[(MAX_SIZE + bits_per_addr - 1) / bits_per_addr];
64
65
  void set(const bool &new_bit = false) {
65
66
  std::memset(buf, (new_bit ? (~0) : 0), sizeof(buf));
@@ -128,14 +129,14 @@ struct BitArray {
128
129
  std::vector<int> res;
129
130
  int idx(0);
130
131
  static const const_div_t<bits_per_addr> qr(MAX_SIZE);
131
- int rem(qr.rem);
132
- for(int i(0); i < qr.quot; ++i, idx += bits_per_addr){
132
+ int rem(qr.rem), i(0);
133
+ for(; i < qr.quot; ++i, idx += bits_per_addr){
133
134
  int idx2(idx);
134
135
  for(ContainerT temp(buf[i]); temp > 0; temp >>= 1, ++idx2){
135
136
  if(temp & 0x1){res.push_back(idx2);}
136
137
  }
137
138
  }
138
- for(ContainerT temp(buf[qr.quot + 1]); (temp > 0) && (rem > 0); --rem, ++idx, temp >>= 1){
139
+ for(ContainerT temp(buf[i]); (temp > 0) && (rem > 0); --rem, ++idx, temp >>= 1){
139
140
  if(temp & 0x1){res.push_back(idx);}
140
141
  }
141
142
  return res;
@@ -153,12 +153,26 @@ static std::string inspect_str(const VALUE &v){
153
153
  $1 = (TYPE($input) == T_ARRAY) ? 1 : 0;
154
154
  }
155
155
  #endif
156
+ %ignore canonicalize();
157
+ %ignore GPS_Time(const int &_week, const float_t &_seconds);
158
+ %typemap(in, numinputs=0) void *dummy "";
159
+ GPS_Time(const int &week_, const float_t &seconds_, void *dummy){
160
+ return &((new GPS_Time<FloatT>(week_, seconds_))->canonicalize());
161
+ }
156
162
  %apply int *OUTPUT { int *week };
157
163
  %apply FloatT *OUTPUT { FloatT *seconds };
158
164
  void to_a(int *week, FloatT *seconds) const {
159
165
  *week = self->week;
160
166
  *seconds = self->seconds;
161
167
  }
168
+ #if defined(SWIG)
169
+ int __cmp__(const GPS_Time<FloatT> &t) const {
170
+ return ((self->week < t.week) ? -1
171
+ : ((self->week > t.week) ? 1
172
+ : (self->seconds < t.seconds ? -1
173
+ : (self->seconds > t.seconds ? 1 : 0))));
174
+ }
175
+ #endif
162
176
  }
163
177
 
164
178
  %define MAKE_ACCESSOR(name, type)
@@ -413,8 +427,6 @@ struct GPS_Ephemeris : public GPS_SpaceNode<FloatT>::SatelliteProperties::Epheme
413
427
  %append_output(swig::from($1.latitude));
414
428
  %append_output(swig::from($1.longitude));
415
429
  }
416
- %ignore iono_correction() const;
417
- %ignore tropo_correction() const;
418
430
  int read(const char *fname) {
419
431
  std::fstream fin(fname, std::ios::in | std::ios::binary);
420
432
  typename RINEX_NAV_Reader<FloatT>::space_node_list_t space_nodes = {self};
@@ -800,6 +812,7 @@ struct GPS_Measurement {
800
812
  L1_RANGE_RATE_SIGMA,
801
813
  L1_SIGNAL_STRENGTH_dBHz,
802
814
  L1_LOCK_SEC,
815
+ L1_FREQUENCY,
803
816
  ITEMS_PREDEFINED,
804
817
  };
805
818
  void add(const int &prn, const int &key, const FloatT &value){
@@ -821,71 +834,15 @@ const type &get_ ## name () const {
821
834
  %enddef
822
835
  MAKE_ACCESSOR2(elevation_mask, FloatT);
823
836
  MAKE_ACCESSOR2(residual_mask, FloatT);
824
- MAKE_ACCESSOR2(f_10_7, FloatT);
825
837
  #undef MAKE_ACCESSOR2
826
838
  MAKE_VECTOR2ARRAY(int);
827
839
  %ignore cast_base;
828
- #ifdef SWIGRUBY
829
- %rename("ionospheric_models=") set_ionospheric_models;
830
- %rename("ionospheric_models") get_ionospheric_models;
831
- #endif
832
- %typemap(in) const std::vector<int> &models (std::vector<int> temp) {
833
- $1 = &temp;
834
- #ifdef SWIGRUBY
835
- if(RB_TYPE_P($input, T_ARRAY)){
836
- for(int i(0), i_max(RARRAY_LEN($input)); i < i_max; ++i){
837
- SWIG_Object obj(RARRAY_AREF($input, i));
838
- int v;
839
- if(SWIG_IsOK(SWIG_AsVal(int)(obj, &v))){
840
- temp.push_back(v);
841
- }else{
842
- SWIG_exception(SWIG_TypeError, "$*1_ltype is expected");
843
- }
844
- }
845
- }
846
- #endif
847
- }
848
840
  }
849
841
  %inline %{
850
842
  template <class FloatT>
851
843
  struct GPS_SolverOptions_Common {
852
- enum {
853
- IONOSPHERIC_KLOBUCHAR,
854
- IONOSPHERIC_SBAS,
855
- IONOSPHERIC_NTCM_GL,
856
- IONOSPHERIC_NONE, // which allows no correction
857
- IONOSPHERIC_MODELS,
858
- IONOSPHERIC_SKIP = IONOSPHERIC_MODELS, // which means delegating the next slot
859
- };
860
844
  virtual GPS_Solver_GeneralOptions<FloatT> *cast_general() = 0;
861
845
  virtual const GPS_Solver_GeneralOptions<FloatT> *cast_general() const = 0;
862
- std::vector<int> get_ionospheric_models() const {
863
- typedef GPS_Solver_GeneralOptions<FloatT> general_t;
864
- const general_t *general(this->cast_general());
865
- std::vector<int> res;
866
- for(int i(0); i < general_t::IONOSPHERIC_MODELS; ++i){
867
- int v((int)(general->ionospheric_models[i]));
868
- if(v == general_t::IONOSPHERIC_SKIP){break;}
869
- res.push_back(v);
870
- }
871
- return res;
872
- }
873
- std::vector<int> set_ionospheric_models(const std::vector<int> &models){
874
- typedef GPS_Solver_GeneralOptions<FloatT> general_t;
875
- general_t *general(this->cast_general());
876
- typedef typename general_t::ionospheric_model_t model_t;
877
- for(int i(0), j(0), j_max(models.size()); i < general_t::IONOSPHERIC_MODELS; ++i){
878
- model_t v(general_t::IONOSPHERIC_SKIP);
879
- if(j < j_max){
880
- if((models[j] >= 0) && (models[j] < general_t::IONOSPHERIC_SKIP)){
881
- v = (model_t)models[j];
882
- }
883
- ++j;
884
- }
885
- general->ionospheric_models[i] = v;
886
- }
887
- return get_ionospheric_models();
888
- }
889
846
  };
890
847
  %}
891
848
 
@@ -927,6 +884,27 @@ struct SBAS_SolverOptions
927
884
  };
928
885
  %}
929
886
 
887
+ %header {
888
+ template <class FloatT>
889
+ struct GPS_RangeCorrector
890
+ : public GPS_Solver_Base<FloatT>::range_corrector_t {
891
+ SWIG_Object callback;
892
+ GPS_RangeCorrector(const SWIG_Object &callback_)
893
+ : GPS_Solver_Base<FloatT>::range_corrector_t(),
894
+ callback(callback_) {}
895
+ bool is_available(const typename GPS_Solver_Base<FloatT>::gps_time_t &t) const {
896
+ return false;
897
+ }
898
+ FloatT *calculate(
899
+ const typename GPS_Solver_Base<FloatT>::gps_time_t &t,
900
+ const typename GPS_Solver_Base<FloatT>::pos_t &usr_pos,
901
+ const typename GPS_Solver_Base<FloatT>::enu_t &sat_rel_pos,
902
+ FloatT &buf) const {
903
+ return NULL;
904
+ }
905
+ };
906
+ }
907
+
930
908
  %extend GPS_Solver {
931
909
  %ignore super_t;
932
910
  %ignore base_t;
@@ -938,6 +916,8 @@ struct SBAS_SolverOptions
938
916
  %ignore relative_property;
939
917
  %ignore satellite_position;
940
918
  %ignore update_position_solution;
919
+ %ignore user_correctors_t;
920
+ %ignore user_correctors;
941
921
  %immutable hooks;
942
922
  %ignore mark;
943
923
  %fragment("hook"{GPS_Solver<FloatT>}, "header",
@@ -1022,7 +1002,9 @@ struct SBAS_SolverOptions
1022
1002
  SWIG_NewPointerObj(&geomat_.W,
1023
1003
  $descriptor(Matrix<FloatT, Array2D_Dense<FloatT>, MatrixViewBase<> > *), 0),
1024
1004
  SWIG_NewPointerObj(&geomat_.delta_r,
1025
- $descriptor(Matrix<FloatT, Array2D_Dense<FloatT>, MatrixViewBase<> > *), 0)};
1005
+ $descriptor(Matrix<FloatT, Array2D_Dense<FloatT>, MatrixViewBase<> > *), 0),
1006
+ SWIG_NewPointerObj(&res,
1007
+ $descriptor(GPS_User_PVT<FloatT> *), 0)};
1026
1008
  proc_call_throw_if_error(hook, sizeof(values) / sizeof(values[0]), values);
1027
1009
  }while(false);
1028
1010
  #endif
@@ -1075,6 +1057,152 @@ struct SBAS_SolverOptions
1075
1057
  }
1076
1058
  }
1077
1059
  %fragment("hook"{GPS_Solver<FloatT>});
1060
+ %ignore update_correction;
1061
+ #ifdef SWIGRUBY
1062
+ %fragment("correction"{GPS_Solver<FloatT>}, "header",
1063
+ fragment=SWIG_From_frag(int),
1064
+ fragment=SWIG_Traits_frag(FloatT)){
1065
+ template <>
1066
+ bool GPS_RangeCorrector<FloatT>::is_available(
1067
+ const typename GPS_Solver_Base<FloatT>::gps_time_t &t) const {
1068
+ VALUE values[] = {
1069
+ SWIG_NewPointerObj(
1070
+ %const_cast(&t, GPS_Time<FloatT> *), $descriptor(GPS_Time<FloatT> *), 0),
1071
+ };
1072
+ VALUE res(proc_call_throw_if_error(
1073
+ callback, sizeof(values) / sizeof(values[0]), values));
1074
+ return RTEST(res) ? true : false;
1075
+ }
1076
+ template <>
1077
+ FloatT *GPS_RangeCorrector<FloatT>::calculate(
1078
+ const typename GPS_Solver_Base<FloatT>::gps_time_t &t,
1079
+ const typename GPS_Solver_Base<FloatT>::pos_t &usr_pos,
1080
+ const typename GPS_Solver_Base<FloatT>::enu_t &sat_rel_pos,
1081
+ FloatT &buf) const {
1082
+ VALUE values[] = {
1083
+ SWIG_NewPointerObj(
1084
+ %const_cast(&t, GPS_Time<FloatT> *),
1085
+ $descriptor(GPS_Time<FloatT> *), 0),
1086
+ SWIG_NewPointerObj(
1087
+ (%const_cast(&usr_pos.xyz, System_XYZ<FloatT, WGS84> *)),
1088
+ $descriptor(System_XYZ<FloatT, WGS84> *), 0),
1089
+ SWIG_NewPointerObj(
1090
+ (%const_cast(&sat_rel_pos, System_ENU<FloatT, WGS84> *)),
1091
+ $descriptor(System_ENU<FloatT, WGS84> *), 0),
1092
+ };
1093
+ VALUE res(proc_call_throw_if_error(
1094
+ callback, sizeof(values) / sizeof(values[0]), values));
1095
+ return SWIG_IsOK(swig::asval(res, &buf)) ? &buf : NULL;
1096
+ }
1097
+ template<>
1098
+ VALUE GPS_Solver<FloatT>::update_correction(
1099
+ const bool &update, const VALUE &hash){
1100
+ typedef range_correction_list_t list_t;
1101
+ static const VALUE k_root[] = {
1102
+ ID2SYM(rb_intern("gps_ionospheric")),
1103
+ ID2SYM(rb_intern("gps_tropospheric")),
1104
+ ID2SYM(rb_intern("sbas_ionospheric")),
1105
+ ID2SYM(rb_intern("sbas_tropospheric")),
1106
+ };
1107
+ static const VALUE k_opt(ID2SYM(rb_intern("options")));
1108
+ static const VALUE k_f_10_7(ID2SYM(rb_intern("f_10_7")));
1109
+ static const VALUE k_known(ID2SYM(rb_intern("known")));
1110
+ struct {
1111
+ VALUE sym;
1112
+ list_t::mapped_type::value_type obj;
1113
+ } item[] = {
1114
+ {ID2SYM(rb_intern("no_correction")), &base_t::no_correction},
1115
+ {ID2SYM(rb_intern("klobuchar")), &this->gps.solver.ionospheric_klobuchar},
1116
+ {ID2SYM(rb_intern("ntcm_gl")), &this->gps.solver.ionospheric_ntcm_gl},
1117
+ {ID2SYM(rb_intern("hopfield")), &this->gps.solver.tropospheric_simplified},
1118
+ {ID2SYM(rb_intern("sbas_igp")), &this->sbas.solver.ionospheric_sbas},
1119
+ {ID2SYM(rb_intern("sbas_tropo")), &this->sbas.solver.tropospheric_sbas},
1120
+ };
1121
+ list_t input;
1122
+ if(update){
1123
+ if(!RB_TYPE_P(hash, T_HASH)){
1124
+ throw std::runtime_error(
1125
+ std::string("Hash is expected, however ").append(inspect_str(hash)));
1126
+ }
1127
+ for(std::size_t i(0); i < sizeof(k_root) / sizeof(k_root[0]); ++i){
1128
+ VALUE ary = rb_hash_lookup(hash, k_root[i]);
1129
+ if(NIL_P(ary)){continue;}
1130
+ if(!RB_TYPE_P(ary, T_ARRAY)){
1131
+ ary = rb_ary_new_from_values(1, &ary);
1132
+ }
1133
+ for(int j(0); j < RARRAY_LEN(ary); ++j){
1134
+ std::size_t k(0);
1135
+ VALUE v(rb_ary_entry(ary, j));
1136
+ for(; k < sizeof(item) / sizeof(item[0]); ++k){
1137
+ if(v == item[k].sym){break;}
1138
+ }
1139
+ if(k >= sizeof(item) / sizeof(item[0])){ // other than symbol
1140
+ user_correctors.push_back(GPS_RangeCorrector<FloatT>(v));
1141
+ input[i].push_back(&user_correctors.back());
1142
+ }else{
1143
+ input[i].push_back(item[k].obj);
1144
+ }
1145
+ }
1146
+ }
1147
+ VALUE opt(rb_hash_lookup(hash, k_opt));
1148
+ if(RB_TYPE_P(opt, T_HASH)){
1149
+ swig::asval(rb_hash_lookup(opt, k_f_10_7), // ntcm_gl
1150
+ &this->gps.solver.ionospheric_ntcm_gl.f_10_7);
1151
+ }
1152
+ }
1153
+ list_t output(update_correction(update, input));
1154
+ VALUE res = rb_hash_new();
1155
+ for(list_t::const_iterator it(output.begin()), it_end(output.end());
1156
+ it != it_end; ++it){
1157
+ VALUE k;
1158
+ if((it->first < 0) || (it->first >= (int)(sizeof(k_root) / sizeof(k_root[0])))){
1159
+ k = SWIG_From(int)(it->first);
1160
+ }else{
1161
+ k = k_root[it->first];
1162
+ }
1163
+ VALUE v = rb_ary_new();
1164
+ for(list_t::mapped_type::const_iterator
1165
+ it2(it->second.begin()), it2_end(it->second.end());
1166
+ it2 != it2_end; ++it2){
1167
+ std::size_t i(0);
1168
+ for(; i < sizeof(item) / sizeof(item[0]); ++i){
1169
+ if(*it2 == item[i].obj){break;}
1170
+ }
1171
+ if(i >= sizeof(item) / sizeof(item[0])){ // other than built-in corrector
1172
+ rb_ary_push(v,
1173
+ reinterpret_cast<const GPS_RangeCorrector<FloatT> *>(*it2)->callback);
1174
+ }else{
1175
+ rb_ary_push(v, item[i].sym);
1176
+ }
1177
+ }
1178
+ rb_hash_aset(res, k, v);
1179
+ }
1180
+ { // common options
1181
+ VALUE opt = rb_hash_new();
1182
+ rb_hash_aset(res, k_opt, opt);
1183
+ rb_hash_aset(opt, k_f_10_7, // ntcm_gl
1184
+ swig::from(this->gps.solver.ionospheric_ntcm_gl.f_10_7));
1185
+ }
1186
+ { // known models
1187
+ VALUE ary = rb_ary_new_capa((int)(sizeof(item) / sizeof(item[0])));
1188
+ for(std::size_t i(0); i < sizeof(item) / sizeof(item[0]); ++i){
1189
+ rb_ary_push(ary, item[i].sym);
1190
+ }
1191
+ rb_hash_aset(res, k_known, ary);
1192
+ }
1193
+ return res;
1194
+ }
1195
+ }
1196
+ %fragment("correction"{GPS_Solver<FloatT>});
1197
+ %rename("correction") get_correction;
1198
+ %rename("correction=") set_correction;
1199
+ VALUE get_correction() const {
1200
+ return const_cast<GPS_Solver<FloatT> *>(self)->update_correction(false, Qnil);
1201
+ }
1202
+ VALUE set_correction(VALUE hash){
1203
+ return self->update_correction(true, hash);
1204
+ }
1205
+ #endif
1078
1206
  }
1079
1207
  %inline {
1080
1208
  template <class FloatT>
@@ -1097,19 +1225,36 @@ struct GPS_Solver
1097
1225
  sbas_t() : space_node(), options(), solver(space_node) {}
1098
1226
  } sbas;
1099
1227
  SWIG_Object hooks;
1228
+ typedef std::vector<GPS_RangeCorrector<FloatT> > user_correctors_t;
1229
+ user_correctors_t user_correctors;
1100
1230
  #ifdef SWIGRUBY
1101
1231
  static void mark(void *ptr){
1102
1232
  GPS_Solver<FloatT> *solver = (GPS_Solver<FloatT> *)ptr;
1103
- if(solver->hooks == Qnil){return;}
1104
1233
  rb_gc_mark(solver->hooks);
1234
+ for(typename user_correctors_t::const_iterator
1235
+ it(solver->user_correctors.begin()), it_end(solver->user_correctors.end());
1236
+ it != it_end; ++it){
1237
+ rb_gc_mark(it->callback);
1238
+ }
1105
1239
  }
1106
1240
  #endif
1107
- GPS_Solver() : super_t(), gps(), sbas(), hooks() {
1108
- gps.solver.space_node_sbas = &sbas.space_node;
1109
- sbas.solver.space_node_gps = &gps.space_node;
1241
+ GPS_Solver() : super_t(),
1242
+ gps(), sbas(),
1243
+ hooks(), user_correctors() {
1110
1244
  #ifdef SWIGRUBY
1111
1245
  hooks = rb_hash_new();
1112
1246
  #endif
1247
+ typename base_t::range_correction_t ionospheric, tropospheric;
1248
+ ionospheric.push_back(&sbas.solver.ionospheric_sbas);
1249
+ ionospheric.push_back(&gps.solver.ionospheric_klobuchar);
1250
+ tropospheric.push_back(&sbas.solver.tropospheric_sbas);
1251
+ tropospheric.push_back(&gps.solver.tropospheric_simplified);
1252
+ gps.solver.ionospheric_correction
1253
+ = sbas.solver.ionospheric_correction
1254
+ = ionospheric;
1255
+ gps.solver.tropospheric_correction
1256
+ = sbas.solver.tropospheric_correction
1257
+ = tropospheric;
1113
1258
  }
1114
1259
  GPS_SpaceNode<FloatT> &gps_space_node() {return gps.space_node;}
1115
1260
  GPS_SolverOptions<FloatT> &gps_options() {return gps.options;}
@@ -1149,6 +1294,53 @@ struct GPS_Solver
1149
1294
  const_cast<sbas_t &>(sbas).solver.update_options(sbas.options);
1150
1295
  return super_t::solve().user_pvt(measurement.items, receiver_time);
1151
1296
  }
1297
+ typedef
1298
+ std::map<int, std::vector<const typename base_t::range_corrector_t *> >
1299
+ range_correction_list_t;
1300
+ range_correction_list_t update_correction(
1301
+ const bool &update,
1302
+ const range_correction_list_t &list = range_correction_list_t()){
1303
+ range_correction_list_t res;
1304
+ typename base_t::range_correction_t *root[] = {
1305
+ &gps.solver.ionospheric_correction,
1306
+ &gps.solver.tropospheric_correction,
1307
+ &sbas.solver.ionospheric_correction,
1308
+ &sbas.solver.tropospheric_correction,
1309
+ };
1310
+ for(std::size_t i(0); i < sizeof(root) / sizeof(root[0]); ++i){
1311
+ do{
1312
+ if(!update){break;}
1313
+ typename range_correction_list_t::const_iterator it(list.find(i));
1314
+ if(it == list.end()){break;}
1315
+
1316
+ // Remove user defined unused correctors
1317
+ for(typename base_t::range_correction_t::const_iterator
1318
+ it2(root[i]->begin()), it2_end(root[i]->end());
1319
+ it2 != it2_end; ++it2){
1320
+ for(typename user_correctors_t::const_iterator
1321
+ it3(user_correctors.begin()), it3_end(user_correctors.end());
1322
+ it3 != it3_end; ++it3){
1323
+ if(*it2 != &(*it3)){continue;}
1324
+ user_correctors.erase(it3);
1325
+ }
1326
+ }
1327
+
1328
+ root[i]->clear();
1329
+ for(typename range_correction_list_t::mapped_type::const_iterator
1330
+ it2(it->second.begin()), it2_end(it->second.end());
1331
+ it2 != it2_end; ++it2){
1332
+ root[i]->push_back(*it2);
1333
+ }
1334
+ }while(false);
1335
+ for(typename base_t::range_correction_t::const_iterator
1336
+ it(root[i]->begin()), it_end(root[i]->end());
1337
+ it != it_end; ++it){
1338
+ res[i].push_back(*it);
1339
+ }
1340
+ }
1341
+ return res;
1342
+ }
1343
+ SWIG_Object update_correction(const bool &update, const SWIG_Object &hash);
1152
1344
  };
1153
1345
  }
1154
1346