X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FWeatherCM%2FFGLocalWeatherDatabase.cpp;h=0ad64b9fa2a0587e266027d622b625fe26d77c0e;hb=a4e81f4ff075e6a3c0c2ea1b5a29c0bcdfdbc671;hp=f88e87b7e46e157d8a845d8fa0a2c469c545f4e8;hpb=275154500802cc9405b5905b3b055e5c4a17b33f;p=flightgear.git diff --git a/src/WeatherCM/FGLocalWeatherDatabase.cpp b/src/WeatherCM/FGLocalWeatherDatabase.cpp index f88e87b7e..0ad64b9fa 100644 --- a/src/WeatherCM/FGLocalWeatherDatabase.cpp +++ b/src/WeatherCM/FGLocalWeatherDatabase.cpp @@ -38,69 +38,49 @@ HISTORY suggestion 19.10.1999 Christian Mayer change to use PLIB's sg instead of Point[2/3]D and lots of wee code cleaning +14.12.1999 Christian Mayer Changed the internal structure to use Dave + Eberly's spherical interpolation code. This + stops our dependancy on the (ugly) voronoi + code and simplyfies the code structure a lot. +07.05.2000 Tony Peden Added functionality to get the weather data + on 'the bus' +18.05.2000 Christian Mayer Minor clean-ups. Changed the code to use + FGWeatherUtils.h for unit conversion +18.07.2001 Christian Mayer Added the posibility to limit the amount of + stations for a faster init. *****************************************************************************/ /****************************************************************************/ /* INCLUDES */ /****************************************************************************/ -#include -#include +#include +#include #include +#include
#include "FGLocalWeatherDatabase.h" -#include "FGVoronoi.h" +#include "FGWeatherParse.h" -/****************************************************************************/ -/********************************** CODE ************************************/ -/****************************************************************************/ - -/****************************************************************************/ -/* return the index (better: ID) of the area with point p */ -/****************************************************************************/ -unsigned int FGLocalWeatherDatabase::AreaWith(const sgVec2& p) const -{ - - for (FGMicroWeatherList::size_type i = 0; i != WeatherAreas.size(); i++) - { - if (WeatherAreas[i].hasPoint(p) == true) - return i+1; - } - - return 0; //nothing found -} +#include "FGWeatherUtils.h" /****************************************************************************/ -/* make tiles out of points on a 2D plane */ +/********************************** CODE ************************************/ /****************************************************************************/ -void FGLocalWeatherDatabase::tileLocalWeather(const FGPhysicalProperties2DVector& EntryList) -{ - FGVoronoiInputList input; - - for (FGPhysicalProperties2DVectorConstIt it1 = EntryList.begin(); it1 != EntryList.end(); it1++) - input.push_back(FGVoronoiInput(it1->p, *it1)); - - FGVoronoiOutputList output = Voronoiate(input); - - for (FGVoronoiOutputList::iterator it2 = output.begin(); it2 != output.end(); it2++) - WeatherAreas.push_back(FGMicroWeather(it2->value, it2->boundary)); -} -/****************************************************************************/ -/* Constructor and Destructor */ -/****************************************************************************/ FGLocalWeatherDatabase* FGLocalWeatherDatabase::theFGLocalWeatherDatabase = 0; FGLocalWeatherDatabase *WeatherDatabase; -FGLocalWeatherDatabase::FGLocalWeatherDatabase(const sgVec3& posititon, const WeatherPrecision visibility, const DatabaseWorkingType type) +void FGLocalWeatherDatabase::init( const WeatherPrecision visibility, + const DatabaseWorkingType type, + const string &root ) { cerr << "Initializing FGLocalWeatherDatabase\n"; cerr << "-----------------------------------\n"; if (theFGLocalWeatherDatabase) { - //FG_LOG( FG_GENERAL, FG_ALERT, "Error: only one local weather allowed" ); cerr << "Error: only one local weather allowed"; exit(-1); } @@ -108,19 +88,102 @@ FGLocalWeatherDatabase::FGLocalWeatherDatabase(const sgVec3& posititon, const We setWeatherVisibility(visibility); DatabaseStatus = type; - global = 0; //just get sure... - sgCopyVec3(last_known_position, posititon); - + database_logic = 0; //just get sure... - theFGLocalWeatherDatabase = this; + Thunderstorm = false; + //I don't need to set theThunderstorm as Thunderstorm == false switch(DatabaseStatus) { case use_global: { - global = new FGGlobalWeatherDatabase; //initialize GlobalDatabase - global->setDatabaseStatus(FGGlobalWeatherDatabase_working); - tileLocalWeather(global->getAll(posititon, WeatherVisibility, 3)); + cerr << "Error: there's no global database anymore!\n"; + exit(-1); + } + break; + + case use_internet: + { + FGWeatherParse *parsed_data = new FGWeatherParse(); + sgVec2 *p; + unsigned int *f; + string path_to_weather = root + "/weather/current.txt.gz"; + parsed_data->input( path_to_weather.c_str() ); + unsigned int n = parsed_data->stored_stations(); + int m = fgGetInt("/environment/weather/max-stations", -1); + + if ( ( m < 0 ) || ( m > n ) ) + { + m = n; + + p = new sgVec2[n]; + f = new unsigned int[n]; + + // fill the database + for (unsigned int i = 0; i < n; i++) + { + f[i] = i; + database_data[i] = parsed_data->getFGPhysicalProperties(i); + parsed_data->getPosition(i, p[i]); + + if ( (i%100) == 0) + cerr << "."; + } + } + else + { // we have to limit the amount of stations + + //store the "distance" between the station and the current + //position. As the distance is calculated from the lat/lon + //values it's not worth much - but it's good enough for + //comparison + map squared_distance; + sgVec2 cur_pos; + + cur_pos[0] = cache->last_known_position[0]; + cur_pos[1] = cache->last_known_position[1]; + + unsigned int i; + for( i = 0; i < n; i++ ) + { + sgVec2 pos; + parsed_data->getPosition(i, pos); + squared_distance[sgDistanceSquaredVec2(cur_pos, pos)] = i; + } + + p = new sgVec2 [m]; + f = new unsigned int[m]; + + map::const_iterator ci; + ci = squared_distance.begin(); + + // fill the database + for ( i = 0; i < m; i++ ) + { + f[i] = i; + database_data.push_back( parsed_data->getFGPhysicalProperties(ci->second) ); + parsed_data->getPosition(ci->second, p[i]); + + if ( (i%100) == 0) + cerr << "."; + + ci++; + } + } + + // free the memory of the parsed data to ease the required memory + // for the very memory consuming spherical interpolation + delete parsed_data; + + //and finally init the interpolation + cerr << "\nInitialiating Interpolation. (2-3 minutes on a PII-350 for ca. 3500 stations)\n"; + database_logic = new SphereInterpolate(m, p, f); + + //and free my allocations: + delete[] p; + delete[] f; + cerr << "Finished weather init.\n"; + } break; @@ -131,26 +194,137 @@ FGLocalWeatherDatabase::FGLocalWeatherDatabase(const sgVec3& posititon, const We case manual: case default_mode: { - vector emptyList; - WeatherAreas.push_back(FGMicroWeather(FGPhysicalProperties2D(), emptyList)); //in these cases I've only got one tile + double x[2] = {0.0, 0.0}; //make an standard weather that's the same at the whole world + double y[2] = {0.0, 0.0}; //make an standard weather that's the same at the whole world + double z[2] = {1.0, -1.0}; //make an standard weather that's the same at the whole world + unsigned int f[2] = {0, 0}; + database_data.push_back( FGPhysicalProperties() ); // == database_date[0] + database_logic = new SphereInterpolate(2,x,y,z,f); } break; default: cerr << "FGLocalWeatherDatabase error: Unknown database type specified!\n"; }; + + cache->latitude_deg = fgGetNode("/position/latitude-deg" ); + cache->longitude_deg = fgGetNode("/position/longitude-deg"); + cache->altitude_ft = fgGetNode("/position/altitude-ft" ); + } -FGLocalWeatherDatabase::~FGLocalWeatherDatabase() +void FGLocalWeatherDatabase::bind() { - //Tidying up: + fgTie("/environment/weather/wind-north-mps", this, &FGLocalWeatherDatabase::get_wind_north); + fgTie("/environment/weather/wind-east-mps", this, &FGLocalWeatherDatabase::get_wind_east); + fgTie("/environment/weather/wind-up-mps", this, &FGLocalWeatherDatabase::get_wind_up); + fgTie("/environment/weather/temperature-K", this, &FGLocalWeatherDatabase::get_temperature); + fgTie("/environment/weather/air-pressure-Pa", this, &FGLocalWeatherDatabase::get_air_pressure); + fgTie("/environment/weather/vapor-pressure-Pa", this, &FGLocalWeatherDatabase::get_vapor_pressure); + fgTie("/environment/weather/air-density", this, &FGLocalWeatherDatabase::get_air_density); + - //delete every stored area - WeatherAreas.erase(WeatherAreas.begin(), WeatherAreas.end()); + SGPropertyNode * station_nodes = fgGetNode("/environment/weather"); + if (station_nodes == 0) { + cerr << "No weatherstations (/environment/weather)!!"; + return; + } + + int index = 0; + for(vector::iterator it = database_data.begin(); it != database_data.end(); it++) + { + SGPropertyNode * station = station_nodes->getNode("station", index, true); + + station -> tie("air-pressure-Pa", + SGRawValueMethods( + database_data[0].AirPressure, + &FGAirPressureItem::getValue, + &FGAirPressureItem::setValue) + ,false); + + int i; + for( i = 0; i < database_data[index].Wind.size(); i++) + { + SGPropertyNode * wind = station->getNode("wind", i, true); + wind -> tie("north-mps", + SGRawValueMethodsIndexed( + database_data[index], i, + &FGPhysicalProperties::getWind_x, + &FGPhysicalProperties::setWind_x) + ,false); + wind -> tie("east-mps", + SGRawValueMethodsIndexed( + database_data[index], i, + &FGPhysicalProperties::getWind_y, + &FGPhysicalProperties::setWind_y) + ,false); + wind -> tie("up-mps", + SGRawValueMethodsIndexed( + database_data[index], i, + &FGPhysicalProperties::getWind_z, + &FGPhysicalProperties::setWind_z) + ,false); + wind -> tie("altitude-m", + SGRawValueMethodsIndexed( + database_data[index], i, + &FGPhysicalProperties::getWind_a, + &FGPhysicalProperties::setWind_a) + ,false); + } - //delete global database if necessary - if (DatabaseStatus == use_global) - delete global; + for( i = 0; i < database_data[index].Temperature.size(); i++) + { + SGPropertyNode * temperature = station->getNode("temperature", i, true); + temperature -> tie("value-K", + SGRawValueMethodsIndexed( + database_data[index], i, + &FGPhysicalProperties::getTemperature_x, + &FGPhysicalProperties::setTemperature_x) + ,false); + temperature -> tie("altitude-m", + SGRawValueMethodsIndexed( + database_data[index], i, + &FGPhysicalProperties::getTemperature_a, + &FGPhysicalProperties::setTemperature_a) + ,false); + } + + for( i = 0; i < database_data[index].VaporPressure.size(); i++) + { + SGPropertyNode * vaporpressure = station->getNode("vapor-pressure", i, true); + vaporpressure -> tie("value-Pa", + SGRawValueMethodsIndexed( + database_data[index], i, + &FGPhysicalProperties::getVaporPressure_x, + &FGPhysicalProperties::setVaporPressure_x) + ,false); + vaporpressure -> tie("altitude-m", + SGRawValueMethodsIndexed( + database_data[index], i, + &FGPhysicalProperties::getVaporPressure_a, + &FGPhysicalProperties::setVaporPressure_a) + ,false); + } + + index++; + } +} + +void FGLocalWeatherDatabase::unbind() +{ + fgUntie("/environment/weather/wind-north-mps"); + fgUntie("/environment/weather/wind-east-mps"); + fgUntie("/environment/weather/wind-up-mps"); + fgUntie("/environment/weather/temperature-K"); + fgUntie("/environment/weather/air-pressure-Pa"); + fgUntie("/environment/weather/vapor-pressure-Pa"); + fgUntie("/environment/weather/air-density"); +} + +FGLocalWeatherDatabase::~FGLocalWeatherDatabase() +{ + //Tidying up: + delete database_logic; } /****************************************************************************/ @@ -158,16 +332,7 @@ FGLocalWeatherDatabase::~FGLocalWeatherDatabase() /****************************************************************************/ void FGLocalWeatherDatabase::reset(const DatabaseWorkingType type) { - //delete global database if necessary - if ((DatabaseStatus == use_global) && (type != use_global)) - delete global; - - DatabaseStatus = type; - if (DatabaseStatus == use_global) - tileLocalWeather(global->getAll(last_known_position, WeatherVisibility, 3)); - - //delete every stored area - WeatherAreas.erase(WeatherAreas.begin(), WeatherAreas.end()); + cerr << "FGLocalWeatherDatabase::reset isn't supported yet\n"; } /****************************************************************************/ @@ -175,24 +340,24 @@ void FGLocalWeatherDatabase::reset(const DatabaseWorkingType type) /****************************************************************************/ void FGLocalWeatherDatabase::update(const WeatherPrecision dt) { - if (DatabaseStatus==use_global) - global->update(dt); + //if (DatabaseStatus==use_global) + // global->update(dt); } void FGLocalWeatherDatabase::update(const sgVec3& p) //position has changed { - sgCopyVec3(last_known_position, p); - //cerr << "****\nupdate inside\n"; - //cerr << "Parameter: " << p << "\n"; - //cerr << "****\n"; + //uncomment this when you are using the GlobalDatabase + /* + cerr << "****\nupdate(p) inside\n"; + cerr << "Parameter: " << p[0] << "/" << p[1] << "/" << p[2] << "\n"; + cerr << FGPhysicalProperties2D(get(p2d), p2d); + cerr << "****\n"; + */ + } void FGLocalWeatherDatabase::update(const sgVec3& p, const WeatherPrecision dt) //time and/or position has changed { - sgCopyVec3(last_known_position, p); - - if (DatabaseStatus==use_global) - global->update(dt); } /****************************************************************************/ @@ -200,160 +365,82 @@ void FGLocalWeatherDatabase::update(const sgVec3& p, const WeatherPrecision dt) /****************************************************************************/ FGPhysicalProperty FGLocalWeatherDatabase::get(const sgVec3& p) const { - unsigned int a = AreaWith(p); - if (a != 0) - return WeatherAreas[a-1].get(p[3]); - else //point is outside => ask GlobalWeatherDatabase - return global->get(p); + // check for bogous altitudes. Dunno why, but FGFS want's to know the + // weather at an altitude of roughly -3000 meters... + if (p[2] < -500.0f) + return FGPhysicalProperty(DatabaseEvaluate(p), -500.0f); + + return FGPhysicalProperty(DatabaseEvaluate(p), p[2]); } +#ifdef macintosh + /* fix a problem with mw compilers in that they don't know the + difference between the next two methods. Since the first one + doesn't seem to be used anywhere, I commented it out. This is + supposed to be fixed in the forthcoming CodeWarrior Release + 6. */ +#else FGPhysicalProperties FGLocalWeatherDatabase::get(const sgVec2& p) const { - sgVec3 temp; - sgSetVec3(temp, p[0], p[1], 0.0); - - unsigned int a = AreaWith(temp); - if (a != 0) - return WeatherAreas[a-1].get(); - else //point is outside => ask GlobalWeatherDatabase - return global->get(p); + return DatabaseEvaluate(p); } +#endif WeatherPrecision FGLocalWeatherDatabase::getAirDensity(const sgVec3& p) const { - FGPhysicalProperty dummy; - unsigned int a = AreaWith(p); - if (a != 0) - dummy = WeatherAreas[a-1].get(p[3]); - else //point is outside => ask GlobalWeatherDatabase - dummy = global->get(p); + FGPhysicalProperty dummy(DatabaseEvaluate(p), p[2]); return (dummy.AirPressure*FG_WEATHER_DEFAULT_AIRDENSITY*FG_WEATHER_DEFAULT_TEMPERATURE) / (dummy.Temperature*FG_WEATHER_DEFAULT_AIRPRESSURE); } -/****************************************************************************/ -/* Add a weather feature at the point p and surrounding area */ -/****************************************************************************/ -void FGLocalWeatherDatabase::addWind(const WeatherPrecision alt, const sgVec3& x, const sgVec2& p) -{ - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addWind(alt, x); -} - -void FGLocalWeatherDatabase::addTurbulence(const WeatherPrecision alt, const sgVec3& x, const sgVec2& p) -{ - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addTurbulence(alt, x); -} - -void FGLocalWeatherDatabase::addTemperature(const WeatherPrecision alt, const WeatherPrecision x, const sgVec2& p) -{ - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addTemperature(alt, x); -} - -void FGLocalWeatherDatabase::addAirPressure(const WeatherPrecision alt, const WeatherPrecision x, const sgVec2& p) -{ - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addAirPressure(alt, x); -} - -void FGLocalWeatherDatabase::addVaporPressure(const WeatherPrecision alt, const WeatherPrecision x, const sgVec2& p) -{ - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addVaporPressure(alt, x); -} - -void FGLocalWeatherDatabase::addCloud(const WeatherPrecision alt, const FGCloudItem& x, const sgVec2& p) -{ - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addCloud(alt, x); -} void FGLocalWeatherDatabase::setSnowRainIntensity(const WeatherPrecision x, const sgVec2& p) { - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].setSnowRainIntensity(x); + /* not supported yet */ } void FGLocalWeatherDatabase::setSnowRainType(const SnowRainType x, const sgVec2& p) { - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].setSnowRainType(x); + /* not supported yet */ } void FGLocalWeatherDatabase::setLightningProbability(const WeatherPrecision x, const sgVec2& p) { - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].setLightningProbability(x); -} - -void FGLocalWeatherDatabase::addProperties(const FGPhysicalProperties2D& x) -{ - if (DatabaseStatus==use_global) - { - global->add(x); - - //BAD, BAD, BAD thing I'm doing here: I'm adding to the global database a point that - //changes my voronoi diagram but I don't update it! instead I'm changing one local value - //that could be anywhere!! - //This only *might* work when the plane moves so far so fast that the diagram gets new - //calculated soon... - unsigned int a = AreaWith(x.p); - if (a != 0) - WeatherAreas[a-1].setStoredWeather(x); - } - else - { - unsigned int a = AreaWith(x.p); - if (a != 0) - WeatherAreas[a-1].setStoredWeather(x); - } + /* not supported yet */ } void FGLocalWeatherDatabase::setProperties(const FGPhysicalProperties2D& x) { - if (DatabaseStatus==use_global) - { - global->change(x); - - //BAD, BAD, BAD thing I'm doing here: I'm adding to the global database a point that - //changes my voronoi diagram but I don't update it! Instead I'm changing one local value - //that could be anywhere!! - //This only *might* work when the plane moves so far so fast that the diagram gets newly - //calculated soon... - unsigned int a = AreaWith(x.p); - if (a != 0) - WeatherAreas[a-1].setStoredWeather(x); - } - else - { - unsigned int a = AreaWith(x.p); - if (a != 0) - WeatherAreas[a-1].setStoredWeather(x); - } + /* not supported yet */ } void fgUpdateWeatherDatabase(void) { - //cerr << "FGLocalWeatherDatabase::update()\n"; sgVec3 position; + sgSetVec3(position, - current_aircraft.fdm_state->get_Latitude(), - current_aircraft.fdm_state->get_Longitude(), - current_aircraft.fdm_state->get_Altitude() * FEET_TO_METER); - + current_aircraft.fdm_state->get_Latitude(), + current_aircraft.fdm_state->get_Longitude(), + current_aircraft.fdm_state->get_Altitude() * SG_FEET_TO_METER); + WeatherDatabase->update( position ); + + // get the data on 'the bus' for the FDM + + /* FGPhysicalProperty porperty = WeatherDatabase->get(position); + + current_aircraft.fdm_state->set_Static_temperature( Kelvin2Rankine(porperty.Temperature) ); + current_aircraft.fdm_state->set_Static_pressure( Pascal2psf(porperty.AirPressure) ); + + current_aircraft.fdm_state->set_Density( SIdensity2JSBsim( Density(porperty.AirPressure, porperty.Temperature) ) ); + +#define MSTOFPS 3.2808 //m/s to ft/s + current_aircraft.fdm_state->set_Velocities_Local_Airmass(porperty.Wind[1]*MSTOFPS, + porperty.Wind[0]*MSTOFPS, + porperty.Wind[2]*MSTOFPS); */ + + }