1 /*****************************************************************************
3 Module: FGLocalWeatherDatabase.cpp
4 Author: Christian Mayer
6 Called by: main program
8 -------- Copyright (C) 1999 Christian Mayer (fgfs@christianmayer.de) --------
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
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
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.
24 Further information about the GNU General Public License can also be found on
25 the world wide web at http://www.gnu.org.
27 FUNCTIONAL DESCRIPTION
28 ------------------------------------------------------------------------------
29 Database for the local weather
30 This database is the only one that gets called from FG
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
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
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 *****************************************************************************/
53 /****************************************************************************/
55 /****************************************************************************/
56 #include <simgear/compiler.h>
57 #include <simgear/constants.h>
59 #include <Aircraft/aircraft.hxx>
60 #include <Main/fg_props.hxx>
62 #include "FGLocalWeatherDatabase.h"
64 #include "FGWeatherParse.h"
66 #include "FGWeatherUtils.h"
68 /****************************************************************************/
69 /********************************** CODE ************************************/
70 /****************************************************************************/
72 FGLocalWeatherDatabase* FGLocalWeatherDatabase::theFGLocalWeatherDatabase = 0;
73 FGLocalWeatherDatabase *WeatherDatabase;
75 void FGLocalWeatherDatabase::init( const WeatherPrecision visibility,
76 const DatabaseWorkingType type,
79 cerr << "Initializing FGLocalWeatherDatabase\n";
80 cerr << "-----------------------------------\n";
82 if (theFGLocalWeatherDatabase)
84 cerr << "Error: only one local weather allowed";
88 setWeatherVisibility(visibility);
90 DatabaseStatus = type;
91 database_logic = 0; //just get sure...
94 //I don't need to set theThunderstorm as Thunderstorm == false
96 switch(DatabaseStatus)
100 cerr << "Error: there's no global database anymore!\n";
107 FGWeatherParse *parsed_data = new FGWeatherParse();
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);
115 if ( ( m < 0 ) || ( m > n ) )
120 f = new unsigned int[n];
123 for (unsigned int i = 0; i < n; i++)
126 database_data[i] = parsed_data->getFGPhysicalProperties(i);
127 parsed_data->getPosition(i, p[i]);
134 { // we have to limit the amount of stations
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
140 map<float, unsigned int> squared_distance;
143 cur_pos[0] = cache->last_known_position[0];
144 cur_pos[1] = cache->last_known_position[1];
147 for( i = 0; i < n; i++ )
150 parsed_data->getPosition(i, pos);
151 squared_distance[sgDistanceSquaredVec2(cur_pos, pos)] = i;
155 f = new unsigned int[m];
157 map<float, unsigned int>::const_iterator ci;
158 ci = squared_distance.begin();
161 for ( i = 0; i < m; i++ )
164 database_data.push_back( parsed_data->getFGPhysicalProperties(ci->second) );
165 parsed_data->getPosition(ci->second, p[i]);
174 // free the memory of the parsed data to ease the required memory
175 // for the very memory consuming spherical interpolation
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);
182 //and free my allocations:
185 cerr << "Finished weather init.\n";
191 cerr << "FGLocalWeatherDatabase error: Distant database isn't implemented yet!\n";
192 cerr << " using random mode instead!\n";
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);
207 cerr << "FGLocalWeatherDatabase error: Unknown database type specified!\n";
210 cache->latitude_deg = fgGetNode("/position/latitude-deg" );
211 cache->longitude_deg = fgGetNode("/position/longitude-deg");
212 cache->altitude_ft = fgGetNode("/position/altitude-ft" );
216 void FGLocalWeatherDatabase::bind()
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);
227 SGPropertyNode * station_nodes = fgGetNode("/environment/weather");
228 if (station_nodes == 0) {
229 cerr << "No weatherstations (/environment/weather)!!";
234 for(vector<FGPhysicalProperties>::iterator it = database_data.begin(); it != database_data.end(); it++)
236 SGPropertyNode * station = station_nodes->getNode("station", index, true);
238 station -> tie("air-pressure-Pa",
239 SGRawValueMethods<FGAirPressureItem,WeatherPrecision>(
240 database_data[0].AirPressure,
241 &FGAirPressureItem::getValue,
242 &FGAirPressureItem::setValue)
246 for( i = 0; i < database_data[index].Wind.size(); i++)
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)
255 wind -> tie("east-mps",
256 SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
257 database_data[index], i,
258 &FGPhysicalProperties::getWind_y,
259 &FGPhysicalProperties::setWind_y)
261 wind -> tie("up-mps",
262 SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
263 database_data[index], i,
264 &FGPhysicalProperties::getWind_z,
265 &FGPhysicalProperties::setWind_z)
267 wind -> tie("altitude-m",
268 SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
269 database_data[index], i,
270 &FGPhysicalProperties::getWind_a,
271 &FGPhysicalProperties::setWind_a)
275 for( i = 0; i < database_data[index].Temperature.size(); i++)
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)
284 temperature -> tie("altitude-m",
285 SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
286 database_data[index], i,
287 &FGPhysicalProperties::getTemperature_a,
288 &FGPhysicalProperties::setTemperature_a)
292 for( i = 0; i < database_data[index].VaporPressure.size(); i++)
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)
301 vaporpressure -> tie("altitude-m",
302 SGRawValueMethodsIndexed<FGPhysicalProperties,WeatherPrecision>(
303 database_data[index], i,
304 &FGPhysicalProperties::getVaporPressure_a,
305 &FGPhysicalProperties::setVaporPressure_a)
313 void FGLocalWeatherDatabase::unbind()
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");
324 FGLocalWeatherDatabase::~FGLocalWeatherDatabase()
327 delete database_logic;
330 /****************************************************************************/
331 /* reset the whole database */
332 /****************************************************************************/
333 void FGLocalWeatherDatabase::reset(const DatabaseWorkingType type)
335 cerr << "FGLocalWeatherDatabase::reset isn't supported yet\n";
338 /****************************************************************************/
339 /* update the database. Since the last call we had dt seconds */
340 /****************************************************************************/
341 void FGLocalWeatherDatabase::update(const WeatherPrecision dt)
343 //if (DatabaseStatus==use_global)
344 // global->update(dt);
347 void FGLocalWeatherDatabase::update(const sgVec3& p) //position has changed
349 //uncomment this when you are using the GlobalDatabase
351 cerr << "****\nupdate(p) inside\n";
352 cerr << "Parameter: " << p[0] << "/" << p[1] << "/" << p[2] << "\n";
353 cerr << FGPhysicalProperties2D(get(p2d), p2d);
359 void FGLocalWeatherDatabase::update(const sgVec3& p, const WeatherPrecision dt) //time and/or position has changed
363 /****************************************************************************/
364 /* Get the physical properties on the specified point p out of the database */
365 /****************************************************************************/
366 FGPhysicalProperty FGLocalWeatherDatabase::get(const sgVec3& p) const
368 // check for bogous altitudes. Dunno why, but FGFS want's to know the
369 // weather at an altitude of roughly -3000 meters...
371 return FGPhysicalProperty(DatabaseEvaluate(p), -500.0f);
373 return FGPhysicalProperty(DatabaseEvaluate(p), p[2]);
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
383 FGPhysicalProperties FGLocalWeatherDatabase::get(const sgVec2& p) const
385 return DatabaseEvaluate(p);
389 WeatherPrecision FGLocalWeatherDatabase::getAirDensity(const sgVec3& p) const
391 FGPhysicalProperty dummy(DatabaseEvaluate(p), p[2]);
394 (dummy.AirPressure*FG_WEATHER_DEFAULT_AIRDENSITY*FG_WEATHER_DEFAULT_TEMPERATURE) /
395 (dummy.Temperature*FG_WEATHER_DEFAULT_AIRPRESSURE);
399 void FGLocalWeatherDatabase::setSnowRainIntensity(const WeatherPrecision x, const sgVec2& p)
401 /* not supported yet */
404 void FGLocalWeatherDatabase::setSnowRainType(const SnowRainType x, const sgVec2& p)
406 /* not supported yet */
409 void FGLocalWeatherDatabase::setLightningProbability(const WeatherPrecision x, const sgVec2& p)
411 /* not supported yet */
414 void FGLocalWeatherDatabase::setProperties(const FGPhysicalProperties2D& x)
416 /* not supported yet */
419 void fgUpdateWeatherDatabase(void)
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);
428 WeatherDatabase->update( position );
430 // get the data on 'the bus' for the FDM
432 /* FGPhysicalProperty porperty = WeatherDatabase->get(position);
434 current_aircraft.fdm_state->set_Static_temperature( Kelvin2Rankine(porperty.Temperature) );
435 current_aircraft.fdm_state->set_Static_pressure( Pascal2psf(porperty.AirPressure) );
437 current_aircraft.fdm_state->set_Density( SIdensity2JSBsim( Density(porperty.AirPressure, porperty.Temperature) ) );
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); */