]> git.mxchange.org Git - flightgear.git/blob - src/WeatherCM/FGLocalWeatherDatabase.cpp
Erik Hofman:
[flightgear.git] / src / WeatherCM / FGLocalWeatherDatabase.cpp
1 /*****************************************************************************
2
3  Module:       FGLocalWeatherDatabase.cpp
4  Author:       Christian Mayer
5  Date started: 28.05.99
6  Called by:    main program
7
8  -------- Copyright (C) 1999 Christian Mayer (fgfs@christianmayer.de) --------
9
10  This program is free software; you can redistribute it and/or modify it under
11  the terms of the GNU General Public License as published by the Free Software
12  Foundation; either version 2 of the License, or (at your option) any later
13  version.
14
15  This program is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  details.
19
20  You should have received a copy of the GNU General Public License along with
21  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22  Place - Suite 330, Boston, MA  02111-1307, USA.
23
24  Further information about the GNU General Public License can also be found on
25  the world wide web at http://www.gnu.org.
26
27 FUNCTIONAL DESCRIPTION
28 ------------------------------------------------------------------------------
29 Database for the local weather
30 This database is the only one that gets called from FG
31
32 HISTORY
33 ------------------------------------------------------------------------------
34 28.05.1999 Christian Mayer      Created
35 16.06.1999 Durk Talsma          Portability for Linux
36 20.06.1999 Christian Mayer      added lots of consts
37 11.10.1999 Christian Mayer      changed set<> to map<> on Bernie Bright's 
38                                 suggestion
39 19.10.1999 Christian Mayer      change to use PLIB's sg instead of Point[2/3]D
40                                 and lots of wee code cleaning
41 14.12.1999 Christian Mayer      Changed the internal structure to use Dave
42                                 Eberly's spherical interpolation code. This
43                                 stops our dependancy on the (ugly) voronoi
44                                 code and simplyfies the code structure a lot.
45 07.05.2000 Tony Peden           Added functionality to get the weather data
46                                 on 'the bus'
47 18.05.2000 Christian Mayer      Minor clean-ups. Changed the code to use 
48                                 FGWeatherUtils.h for unit conversion
49 18.07.2001 Christian Mayer      Added the posibility to limit the amount of 
50                                 stations for a faster init.
51 *****************************************************************************/
52
53 /****************************************************************************/
54 /* INCLUDES                                                                 */
55 /****************************************************************************/
56 #include <simgear/compiler.h>
57 #include <simgear/constants.h>
58
59 #include <Aircraft/aircraft.hxx>
60 #include <Main/fg_props.hxx>
61
62 #include "FGLocalWeatherDatabase.h"
63
64 #include "FGWeatherParse.h"
65
66 #include "FGWeatherUtils.h"
67
68 /****************************************************************************/
69 /********************************** CODE ************************************/
70 /****************************************************************************/
71
72 FGLocalWeatherDatabase* FGLocalWeatherDatabase::theFGLocalWeatherDatabase = 0;
73 FGLocalWeatherDatabase *WeatherDatabase;
74
75 void FGLocalWeatherDatabase::init( const WeatherPrecision visibility,
76                                    const DatabaseWorkingType type,
77                                    const string &root )
78 {
79     cerr << "Initializing FGLocalWeatherDatabase\n";
80     cerr << "-----------------------------------\n";
81
82     if (theFGLocalWeatherDatabase)
83     {
84         cerr << "Error: only one local weather allowed";
85         exit(-1);
86     }
87
88     setWeatherVisibility(visibility);
89
90     DatabaseStatus = type;
91     database_logic = 0;     //just get sure...
92
93     Thunderstorm = false;
94     //I don't need to set theThunderstorm as Thunderstorm == false
95
96     switch(DatabaseStatus)
97     {
98     case use_global:
99         {
100             cerr << "Error: there's no global database anymore!\n";
101             exit(-1);
102         }
103         break;
104
105     case use_internet:
106         {
107             FGWeatherParse *parsed_data = new FGWeatherParse();
108             sgVec2       *p;
109             unsigned int *f;
110             string path_to_weather = root + "/weather/current.txt.gz";
111             parsed_data->input( path_to_weather.c_str() );
112             unsigned int n = parsed_data->stored_stations();
113             int m = fgGetInt("/environment/weather/max-stations", -1);
114
115             if ( ( m < 0 ) || ( m > n ) )
116             {
117                 m = n;
118
119                 p = new sgVec2[n];
120                 f = new unsigned int[n];
121
122                 // fill the database
123                 for (unsigned int i = 0; i < n; i++) 
124                 {
125                     f[i] = i;
126                     database_data[i] = parsed_data->getFGPhysicalProperties(i);
127                     parsed_data->getPosition(i, p[i]);
128
129                     if ( (i%100) == 0)
130                         cerr << ".";
131                 }
132             }
133             else
134             {   // we have to limit the amount of stations
135
136                 //store the "distance" between the station and the current
137                 //position. As the distance is calculated from the lat/lon
138                 //values it's not worth much - but it's good enough for
139                 //comparison
140                 map<float, unsigned int> squared_distance;
141                 sgVec2 cur_pos;
142
143                 cur_pos[0] = cache->last_known_position[0];
144                 cur_pos[1] = cache->last_known_position[1];
145                 
146                 unsigned int i;
147                 for( i = 0; i < n; i++ )
148                 {
149                   sgVec2 pos;
150                   parsed_data->getPosition(i, pos);
151                   squared_distance[sgDistanceSquaredVec2(cur_pos, pos)] = i;
152                 }
153
154                 p = new sgVec2      [m];
155                 f = new unsigned int[m];
156
157                 map<float, unsigned int>::const_iterator ci;
158                 ci = squared_distance.begin();
159
160                 // fill the database
161                 for ( i = 0; i < m; i++ ) 
162                 { 
163                     f[i] = i;
164                     database_data.push_back( parsed_data->getFGPhysicalProperties(ci->second) );
165                     parsed_data->getPosition(ci->second, p[i]);
166
167                     if ( (i%100) == 0)
168                         cerr << ".";
169
170                     ci++;
171                 }
172             }
173
174             // free the memory of the parsed data to ease the required memory
175             // for the very memory consuming spherical interpolation
176             delete parsed_data;
177
178             //and finally init the interpolation
179             cerr << "\nInitialiating Interpolation. (2-3 minutes on a PII-350 for ca. 3500 stations)\n";
180             database_logic = new SphereInterpolate(m, p, f);
181
182             //and free my allocations:
183             delete[] p;
184             delete[] f;
185             cerr << "Finished weather init.\n";
186
187         }
188         break;
189
190     case distant:
191         cerr << "FGLocalWeatherDatabase error: Distant database isn't implemented yet!\n";
192         cerr << "  using random mode instead!\n";
193     case random:
194     case manual:
195     case default_mode:
196         {
197             double x[2] = {0.0,  0.0};  //make an standard weather that's the same at the whole world
198             double y[2] = {0.0,  0.0};  //make an standard weather that's the same at the whole world
199             double z[2] = {1.0, -1.0};  //make an standard weather that's the same at the whole world
200             unsigned int f[2] = {0, 0};
201             database_data.push_back( FGPhysicalProperties() ); // == database_date[0]
202             database_logic = new SphereInterpolate(2,x,y,z,f);
203         }
204         break;
205
206     default:
207         cerr << "FGLocalWeatherDatabase error: Unknown database type specified!\n";
208     };
209
210     cache->latitude_deg  = fgGetNode("/position/latitude-deg" );
211     cache->longitude_deg = fgGetNode("/position/longitude-deg");
212     cache->altitude_ft   = fgGetNode("/position/altitude-ft"  );
213
214 }
215
216 void FGLocalWeatherDatabase::bind()
217 {
218     fgTie("/environment/weather/wind-north-mps", this, &FGLocalWeatherDatabase::get_wind_north);
219     fgTie("/environment/weather/wind-east-mps", this, &FGLocalWeatherDatabase::get_wind_east);
220     fgTie("/environment/weather/wind-up-mps", this, &FGLocalWeatherDatabase::get_wind_up);
221     fgTie("/environment/weather/temperature-K", this, &FGLocalWeatherDatabase::get_temperature);
222     fgTie("/environment/weather/air-pressure-Pa", this, &FGLocalWeatherDatabase::get_air_pressure);
223     fgTie("/environment/weather/vapor-pressure-Pa", this, &FGLocalWeatherDatabase::get_vapor_pressure);
224     fgTie("/environment/weather/air-density", this, &FGLocalWeatherDatabase::get_air_density);
225     
226
227   SGPropertyNode * station_nodes = fgGetNode("/environment/weather");
228   if (station_nodes == 0) {
229     cerr << "No weatherstations (/environment/weather)!!";
230     return;
231   }
232   
233   int index = 0;
234   for(vector<FGPhysicalProperties>::iterator it = database_data.begin(); it != database_data.end(); it++)
235   {
236       SGPropertyNode * station = station_nodes->getNode("station", index, true);
237
238       station -> tie("air-pressure-Pa", 
239         SGRawValueMethods<FGAirPressureItem,WeatherPrecision>(
240           database_data[0].AirPressure,
241           &FGAirPressureItem::getValue,
242           &FGAirPressureItem::setValue)
243         ,false);
244
245     int i;
246     for( i = 0; i < database_data[index].Wind.size(); i++)
247     {
248       SGPropertyNode * wind = station->getNode("wind", i, true);
249       wind -> tie("north-mps", 
250         SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
251           database_data[index], i,
252           &FGPhysicalProperties::getWind_x,
253           &FGPhysicalProperties::setWind_x)
254         ,false);
255       wind -> tie("east-mps", 
256         SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
257           database_data[index], i,
258           &FGPhysicalProperties::getWind_y,
259           &FGPhysicalProperties::setWind_y)
260         ,false);
261       wind -> tie("up-mps", 
262         SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
263           database_data[index], i,
264           &FGPhysicalProperties::getWind_z,
265           &FGPhysicalProperties::setWind_z)
266         ,false);
267       wind -> tie("altitude-m", 
268         SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
269           database_data[index], i,
270           &FGPhysicalProperties::getWind_a,
271           &FGPhysicalProperties::setWind_a)
272         ,false);
273     }
274
275     for( i = 0; i < database_data[index].Temperature.size(); i++)
276     {
277       SGPropertyNode * temperature = station->getNode("temperature", i, true);
278       temperature -> tie("value-K", 
279         SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
280           database_data[index], i,
281           &FGPhysicalProperties::getTemperature_x,
282           &FGPhysicalProperties::setTemperature_x)
283         ,false);
284       temperature -> tie("altitude-m", 
285         SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
286           database_data[index], i,
287           &FGPhysicalProperties::getTemperature_a,
288           &FGPhysicalProperties::setTemperature_a)
289         ,false);
290     }
291
292     for( i = 0; i < database_data[index].VaporPressure.size(); i++)
293     {
294       SGPropertyNode * vaporpressure = station->getNode("vapor-pressure", i, true);
295       vaporpressure -> tie("value-Pa", 
296         SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
297           database_data[index], i,
298           &FGPhysicalProperties::getVaporPressure_x,
299           &FGPhysicalProperties::setVaporPressure_x)
300         ,false);
301       vaporpressure -> tie("altitude-m", 
302         SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
303           database_data[index], i,
304           &FGPhysicalProperties::getVaporPressure_a,
305           &FGPhysicalProperties::setVaporPressure_a)
306         ,false);
307     }
308
309     index++;
310   }
311 }
312
313 void FGLocalWeatherDatabase::unbind()
314 {
315     fgUntie("/environment/weather/wind-north-mps");
316     fgUntie("/environment/weather/wind-east-mps");
317     fgUntie("/environment/weather/wind-up-mps");
318     fgUntie("/environment/weather/temperature-K");
319     fgUntie("/environment/weather/air-pressure-Pa");
320     fgUntie("/environment/weather/vapor-pressure-Pa");
321     fgUntie("/environment/weather/air-density");
322 }
323
324 FGLocalWeatherDatabase::~FGLocalWeatherDatabase()
325 {
326     //Tidying up:
327     delete database_logic;
328 }
329
330 /****************************************************************************/
331 /* reset the whole database                                                 */
332 /****************************************************************************/
333 void FGLocalWeatherDatabase::reset(const DatabaseWorkingType type)
334 {
335     cerr << "FGLocalWeatherDatabase::reset isn't supported yet\n";
336 }
337
338 /****************************************************************************/
339 /* update the database. Since the last call we had dt seconds               */
340 /****************************************************************************/
341 void FGLocalWeatherDatabase::update(const WeatherPrecision dt)
342 {
343     //if (DatabaseStatus==use_global)
344     //  global->update(dt);
345 }
346
347 void FGLocalWeatherDatabase::update(const sgVec3& p) //position has changed
348 {
349     //uncomment this when you are using the GlobalDatabase
350     /*
351     cerr << "****\nupdate(p) inside\n";
352     cerr << "Parameter: " << p[0] << "/" << p[1] << "/" << p[2] << "\n";
353     cerr << FGPhysicalProperties2D(get(p2d), p2d);
354     cerr << "****\n";
355     */
356     
357 }
358
359 void FGLocalWeatherDatabase::update(const sgVec3& p, const WeatherPrecision dt)   //time and/or position has changed
360 {
361 }
362
363 /****************************************************************************/
364 /* Get the physical properties on the specified point p out of the database */
365 /****************************************************************************/
366 FGPhysicalProperty FGLocalWeatherDatabase::get(const sgVec3& p) const
367 {
368   // check for bogous altitudes. Dunno why, but FGFS want's to know the
369   // weather at an altitude of roughly -3000 meters...
370   if (p[2] < -500.0f)
371     return FGPhysicalProperty(DatabaseEvaluate(p), -500.0f);
372
373   return FGPhysicalProperty(DatabaseEvaluate(p), p[2]);
374 }
375
376 #ifdef macintosh
377     /* fix a problem with mw compilers in that they don't know the
378        difference between the next two methods. Since the first one
379        doesn't seem to be used anywhere, I commented it out. This is
380        supposed to be fixed in the forthcoming CodeWarrior Release
381        6. */
382 #else
383 FGPhysicalProperties FGLocalWeatherDatabase::get(const sgVec2& p) const
384 {
385     return DatabaseEvaluate(p);
386 }
387 #endif
388
389 WeatherPrecision FGLocalWeatherDatabase::getAirDensity(const sgVec3& p) const
390 {
391     FGPhysicalProperty dummy(DatabaseEvaluate(p), p[2]);
392
393     return 
394         (dummy.AirPressure*FG_WEATHER_DEFAULT_AIRDENSITY*FG_WEATHER_DEFAULT_TEMPERATURE) / 
395         (dummy.Temperature*FG_WEATHER_DEFAULT_AIRPRESSURE);
396 }
397
398
399 void FGLocalWeatherDatabase::setSnowRainIntensity(const WeatherPrecision x, const sgVec2& p)
400 {
401     /* not supported yet */
402 }
403
404 void FGLocalWeatherDatabase::setSnowRainType(const SnowRainType x, const sgVec2& p)
405 {
406     /* not supported yet */
407 }
408
409 void FGLocalWeatherDatabase::setLightningProbability(const WeatherPrecision x, const sgVec2& p)
410 {
411     /* not supported yet */
412 }
413
414 void FGLocalWeatherDatabase::setProperties(const FGPhysicalProperties2D& x)
415 {
416     /* not supported yet */
417 }
418
419 void fgUpdateWeatherDatabase(void)
420 {
421     sgVec3 position;
422     
423     sgSetVec3(position, 
424         current_aircraft.fdm_state->get_Latitude(),
425         current_aircraft.fdm_state->get_Longitude(),
426         current_aircraft.fdm_state->get_Altitude() * SG_FEET_TO_METER);
427     
428     WeatherDatabase->update( position );
429        
430     // get the data on 'the bus' for the FDM
431
432    /*  FGPhysicalProperty porperty = WeatherDatabase->get(position);
433
434     current_aircraft.fdm_state->set_Static_temperature( Kelvin2Rankine(porperty.Temperature) );
435     current_aircraft.fdm_state->set_Static_pressure( Pascal2psf(porperty.AirPressure) );
436
437     current_aircraft.fdm_state->set_Density( SIdensity2JSBsim( Density(porperty.AirPressure, porperty.Temperature) ) );
438     
439 #define MSTOFPS  3.2808 //m/s to ft/s
440     current_aircraft.fdm_state->set_Velocities_Local_Airmass(porperty.Wind[1]*MSTOFPS,
441         porperty.Wind[0]*MSTOFPS,
442         porperty.Wind[2]*MSTOFPS); */
443
444     
445 }
446