]> git.mxchange.org Git - flightgear.git/blob - src/Environment/environment_ctrl.cxx
Fix the nmea and garmin output to a) fake a GSA sentence, b) fix a y2k bug
[flightgear.git] / src / Environment / environment_ctrl.cxx
1 // environment_ctrl.cxx -- manager for natural environment information.
2 //
3 // Written by David Megginson, started February 2002.
4 //
5 // Copyright (C) 2002  David Megginson - david@megginson.com
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23 #include <simgear/debug/logstream.hxx>
24
25 #include <stdlib.h>
26 #include <algorithm>
27
28 #include <Main/fg_props.hxx>
29
30 #include "environment_ctrl.hxx"
31
32 SG_USING_STD(sort);
33
34
35 \f
36 ////////////////////////////////////////////////////////////////////////
37 // Implementation of FGEnvironmentCtrl abstract base class.
38 ////////////////////////////////////////////////////////////////////////
39
40 FGEnvironmentCtrl::FGEnvironmentCtrl ()
41   : _environment(0),
42     _lon_deg(0),
43     _lat_deg(0),
44     _elev_ft(0)
45 {
46 }
47
48 FGEnvironmentCtrl::~FGEnvironmentCtrl ()
49 {
50 }
51
52 void
53 FGEnvironmentCtrl::setEnvironment (FGEnvironment * environment)
54 {
55   _environment = environment;
56 }
57
58 void
59 FGEnvironmentCtrl::setLongitudeDeg (double lon_deg)
60 {
61   _lon_deg = lon_deg;
62 }
63
64 void
65 FGEnvironmentCtrl::setLatitudeDeg (double lat_deg)
66 {
67   _lat_deg = lat_deg;
68 }
69
70 void
71 FGEnvironmentCtrl::setElevationFt (double elev_ft)
72 {
73   _elev_ft = elev_ft;
74 }
75
76 void
77 FGEnvironmentCtrl::setPosition (double lon_deg, double lat_deg, double elev_ft)
78 {
79   _lon_deg = lon_deg;
80   _lat_deg = lat_deg;
81   _elev_ft = elev_ft;
82 }
83
84
85 \f
86 ////////////////////////////////////////////////////////////////////////
87 // Implementation of FGUserDefEnvironmentCtrl.
88 ////////////////////////////////////////////////////////////////////////
89
90 FGUserDefEnvironmentCtrl::FGUserDefEnvironmentCtrl ()
91   : _base_wind_speed_node(0),
92     _gust_wind_speed_node(0),
93     _current_wind_speed_kt(0),
94     _delta_wind_speed_kt(0)
95 {
96 }
97
98 FGUserDefEnvironmentCtrl::~FGUserDefEnvironmentCtrl ()
99 {
100 }
101
102 void
103 FGUserDefEnvironmentCtrl::init ()
104 {
105                                 // Fill in some defaults.
106   if (!fgHasNode("/environment/params/base-wind-speed-kt"))
107     fgSetDouble("/environment/params/base-wind-speed-kt",
108                 fgGetDouble("/environment/wind-speed-kt"));
109   if (!fgHasNode("/environment/params/gust-wind-speed-kt"))
110     fgSetDouble("/environment/params/gust-wind-speed-kt",
111                 fgGetDouble("/environment/params/base-wind-speed-kt"));
112
113   _base_wind_speed_node =
114     fgGetNode("/environment/params/base-wind-speed-kt", true);
115   _gust_wind_speed_node =
116     fgGetNode("/environment/params/gust-wind-speed-kt", true);
117
118   _current_wind_speed_kt = _base_wind_speed_node->getDoubleValue();
119   _delta_wind_speed_kt = 0.1;
120 }
121
122 void
123 FGUserDefEnvironmentCtrl::update (double dt)
124 {
125   double base_wind_speed = _base_wind_speed_node->getDoubleValue();
126   double gust_wind_speed = _gust_wind_speed_node->getDoubleValue();
127
128   if (gust_wind_speed < base_wind_speed) {
129       gust_wind_speed = base_wind_speed;
130       _gust_wind_speed_node->setDoubleValue(gust_wind_speed);
131   }
132
133   if (base_wind_speed == gust_wind_speed) {
134     _current_wind_speed_kt = base_wind_speed;
135   } else {
136     int rn = rand() % 128;
137     int sign = (_delta_wind_speed_kt < 0 ? -1 : 1);
138     double gust = _current_wind_speed_kt - base_wind_speed;
139     double incr = gust / 50;
140
141     if (rn == 0)
142       _delta_wind_speed_kt = - _delta_wind_speed_kt;
143     else if (rn < 4)
144       _delta_wind_speed_kt -= incr * sign;
145     else if (rn < 16)
146       _delta_wind_speed_kt += incr * sign;
147
148     _current_wind_speed_kt += _delta_wind_speed_kt;
149
150     if (_current_wind_speed_kt < base_wind_speed) {
151       _current_wind_speed_kt = base_wind_speed;
152       _delta_wind_speed_kt = 0.01;
153     } else if (_current_wind_speed_kt > gust_wind_speed) {
154       _current_wind_speed_kt = gust_wind_speed;
155       _delta_wind_speed_kt = -0.01;
156     }
157   }
158   
159   if (_environment != 0)
160     _environment->set_wind_speed_kt(_current_wind_speed_kt);
161 }
162
163
164 \f
165 ////////////////////////////////////////////////////////////////////////
166 // Implementation of FGInterpolateEnvironmentCtrl.
167 ////////////////////////////////////////////////////////////////////////
168
169 FGInterpolateEnvironmentCtrl::FGInterpolateEnvironmentCtrl ()
170 {
171 }
172
173 FGInterpolateEnvironmentCtrl::~FGInterpolateEnvironmentCtrl ()
174 {
175     unsigned int i;
176     for (i = 0; i < _boundary_table.size(); i++)
177         delete _boundary_table[i];
178     for (i = 0; i < _aloft_table.size(); i++)
179         delete _aloft_table[i];
180 }
181
182
183
184 void
185 FGInterpolateEnvironmentCtrl::init ()
186 {
187     read_table(fgGetNode("/environment/config/boundary", true),
188                _boundary_table);
189     read_table(fgGetNode("/environment/config/aloft", true),
190                _aloft_table);
191 }
192
193 void
194 FGInterpolateEnvironmentCtrl::reinit ()
195 {
196     unsigned int i;
197     for (i = 0; i < _boundary_table.size(); i++)
198         delete _boundary_table[i];
199     for (i = 0; i < _aloft_table.size(); i++)
200         delete _aloft_table[i];
201     _boundary_table.clear();
202     _aloft_table.clear();
203     init();
204 }
205
206 void
207 FGInterpolateEnvironmentCtrl::read_table (const SGPropertyNode * node,
208                                           vector<bucket *> &table)
209 {
210     for (int i = 0; i < node->nChildren(); i++) {
211         const SGPropertyNode * child = node->getChild(i);
212         if ( strcmp(child->getName(), "entry") == 0
213              && child->getStringValue("elevation-ft", "")[0] != '\0'
214              && ( child->getDoubleValue("elevation-ft") > 0.1 || i == 0 ) )
215         {
216             bucket * b = new bucket;
217             if (i > 0)
218                 b->environment.copy(table[i-1]->environment);
219             b->environment.read(child);
220             b->altitude_ft = b->environment.get_elevation_ft();
221             table.push_back(b);
222         }
223     }
224     sort(table.begin(), table.end());
225 }
226
227 void
228 FGInterpolateEnvironmentCtrl::update (double delta_time_sec)
229 {
230                                 // FIXME
231     double altitude_ft = fgGetDouble("/position/altitude-ft");
232     double altitude_agl_ft = fgGetDouble("/position/altitude-agl-ft");
233     double boundary_transition =
234         fgGetDouble("/environment/config/boundary-transition-ft", 500);
235
236     // double ground_elevation_ft = altitude_ft - altitude_agl_ft;
237
238     int length = _boundary_table.size();
239
240     if (length > 0) {
241                                 // boundary table
242         double boundary_limit = _boundary_table[length-1]->altitude_ft;
243         if (boundary_limit >= altitude_agl_ft) {
244             do_interpolate(_boundary_table, altitude_agl_ft,
245                            _environment);
246             return;
247         } else if ((boundary_limit + boundary_transition) >= altitude_agl_ft) {
248                                 // both tables
249             do_interpolate(_boundary_table, altitude_agl_ft, &env1);
250             do_interpolate(_aloft_table, altitude_ft, &env2);
251             double fraction =
252                 (altitude_agl_ft - boundary_limit) / boundary_transition;
253             interpolate(&env1, &env2, fraction, _environment);
254             return;
255         }
256     }
257
258                                 // aloft table
259     do_interpolate(_aloft_table, altitude_ft, _environment);
260 }
261
262 void
263 FGInterpolateEnvironmentCtrl::do_interpolate (vector<bucket *> &table,
264                                               double altitude_ft,
265                                               FGEnvironment * environment)
266 {
267     int length = table.size();
268     if (length == 0)
269         return;
270
271                                 // Boundary conditions
272     if ((length == 1) || (table[0]->altitude_ft >= altitude_ft)) {
273         environment->copy(table[0]->environment);
274         return;
275     } else if (table[length-1]->altitude_ft <= altitude_ft) {
276         environment->copy(table[length-1]->environment);
277         return;
278     }
279         
280                                 // Search the interpolation table
281     for (int i = 0; i < length - 1; i++) {
282         if ((i == length - 1) || (table[i]->altitude_ft <= altitude_ft)) {
283                 FGEnvironment * env1 = &(table[i]->environment);
284                 FGEnvironment * env2 = &(table[i+1]->environment);
285                 double fraction;
286                 if (table[i]->altitude_ft == table[i+1]->altitude_ft)
287                     fraction = 1.0;
288                 else
289                     fraction =
290                         ((altitude_ft - table[i]->altitude_ft) /
291                          (table[i+1]->altitude_ft - table[i]->altitude_ft));
292                 interpolate(env1, env2, fraction, environment);
293
294                 return;
295         }
296     }
297 }
298
299 bool
300 FGInterpolateEnvironmentCtrl::bucket::operator< (const bucket &b) const
301 {
302     return (altitude_ft < b.altitude_ft);
303 }
304
305
306 // end of environment_ctrl.cxx