X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FWeatherCM%2FFGLocalWeatherDatabase.cpp;h=0ad64b9fa2a0587e266027d622b625fe26d77c0e;hb=a4e81f4ff075e6a3c0c2ea1b5a29c0bcdfdbc671;hp=aa2c0229066a6bf3b80deb7f0051c7de4162ccf0;hpb=b645c8cf7e4aecc006b0d90a0ff7b4b0ad95cc62;p=flightgear.git diff --git a/src/WeatherCM/FGLocalWeatherDatabase.cpp b/src/WeatherCM/FGLocalWeatherDatabase.cpp index aa2c02290..0ad64b9fa 100644 --- a/src/WeatherCM/FGLocalWeatherDatabase.cpp +++ b/src/WeatherCM/FGLocalWeatherDatabase.cpp @@ -5,7 +5,7 @@ Date started: 28.05.99 Called by: main program - ---------- Copyright (C) 1999 Christian Mayer (vader@t-online.de) ---------- + -------- Copyright (C) 1999 Christian Mayer (fgfs@christianmayer.de) -------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -34,87 +34,156 @@ HISTORY 28.05.1999 Christian Mayer Created 16.06.1999 Durk Talsma Portability for Linux 20.06.1999 Christian Mayer added lots of consts +11.10.1999 Christian Mayer changed set<> to map<> on Bernie Bright's + 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 "FGLocalWeatherDatabase.h" -#include "FGVoronoi.h" -#include "fg_constants.h" +#include +#include #include -#include +#include
-/****************************************************************************/ -/********************************** CODE ************************************/ -/****************************************************************************/ +#include "FGLocalWeatherDatabase.h" -/****************************************************************************/ -/* return the index (better: ID) of the area with point p */ -/****************************************************************************/ -unsigned int FGLocalWeatherDatabase::AreaWith(const Point2D& p) const -{ - - for (FGMicroWeatherList::size_type i = 0; i != WeatherAreas.size(); i++) - { - if (WeatherAreas[i].hasPoint(p) == true) - return i+1; - } +#include "FGWeatherParse.h" - 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 (FGPhysicalProperties2DVector::const_iterator 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 Point3D& posititon, const WeatherPrecition& 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); } setWeatherVisibility(visibility); - //WeatherVisibility = visibility; - DatabaseStatus = type; - global = 0; //just get sure... - last_known_position = posititon; + DatabaseStatus = type; + 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; @@ -125,215 +194,253 @@ FGLocalWeatherDatabase::FGLocalWeatherDatabase(const Point3D& posititon, const W 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"; }; -} -FGLocalWeatherDatabase::~FGLocalWeatherDatabase() -{ - //Tidying up: - - //delete every stored area - WeatherAreas.erase(WeatherAreas.begin(), WeatherAreas.end()); + cache->latitude_deg = fgGetNode("/position/latitude-deg" ); + cache->longitude_deg = fgGetNode("/position/longitude-deg"); + cache->altitude_ft = fgGetNode("/position/altitude-ft" ); - //delete global database if necessary - if (DatabaseStatus == use_global) - delete global; } -/****************************************************************************/ -/* reset the whole database */ -/****************************************************************************/ -void FGLocalWeatherDatabase::reset(const DatabaseWorkingType& type) +void FGLocalWeatherDatabase::bind() { - //delete global database if necessary - if ((DatabaseStatus == use_global) && (type != use_global)) - delete global; + 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); + - DatabaseStatus = type; - if (DatabaseStatus == use_global) - tileLocalWeather(global->getAll(last_known_position, WeatherVisibility, 3)); + 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 every stored area - WeatherAreas.erase(WeatherAreas.begin(), WeatherAreas.end()); -} + 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); + } -/****************************************************************************/ -/* update the database. Since the last call we had dt seconds */ -/****************************************************************************/ -void FGLocalWeatherDatabase::update(const WeatherPrecition& dt) -{ - if (DatabaseStatus==use_global) - global->update(dt); + 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::update(const Point3D& p) //position has changed +void FGLocalWeatherDatabase::unbind() { - last_known_position = p; - //cerr << "****\nupdate inside\n"; - //cerr << "Parameter: " << p << "\n"; - //cerr << "****\n"; + 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"); } -void FGLocalWeatherDatabase::update(const Point3D& p, const WeatherPrecition& dt) //time and/or position has changed +FGLocalWeatherDatabase::~FGLocalWeatherDatabase() { - last_known_position = p; - - if (DatabaseStatus==use_global) - global->update(dt); + //Tidying up: + delete database_logic; } /****************************************************************************/ -/* Get the physical properties on the specified point p out of the database */ +/* reset the whole database */ /****************************************************************************/ -FGPhysicalProperty FGLocalWeatherDatabase::get(const Point3D& p) const +void FGLocalWeatherDatabase::reset(const DatabaseWorkingType type) { - unsigned int a = AreaWith(p); - if (a != 0) - return WeatherAreas[a-1].get(p.elev()); - else //point is outside => ask GlobalWeatherDatabase - return global->get(p); + cerr << "FGLocalWeatherDatabase::reset isn't supported yet\n"; } -WeatherPrecition FGLocalWeatherDatabase::getAirDensity(const Point3D& p) const -{ - FGPhysicalProperty dummy; - unsigned int a = AreaWith(p); - if (a != 0) - dummy = WeatherAreas[a-1].get(p.elev()); - else //point is outside => ask GlobalWeatherDatabase - dummy = global->get(p); - - 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 */ +/* update the database. Since the last call we had dt seconds */ /****************************************************************************/ -void FGLocalWeatherDatabase::addWind(const FGWindItem& x, const Point2D& p) +void FGLocalWeatherDatabase::update(const WeatherPrecision dt) { - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addWind(x); + //if (DatabaseStatus==use_global) + // global->update(dt); } -void FGLocalWeatherDatabase::addTurbulence(const FGTurbulenceItem& x, const Point2D& p) +void FGLocalWeatherDatabase::update(const sgVec3& p) //position has changed { - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addTurbulence(x); + //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::addTemperature(const FGTemperatureItem& x, const Point2D& p) +void FGLocalWeatherDatabase::update(const sgVec3& p, const WeatherPrecision dt) //time and/or position has changed { - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addTemperature(x); } -void FGLocalWeatherDatabase::addAirPressure(const FGAirPressureItem& x, const Point2D& p) +/****************************************************************************/ +/* Get the physical properties on the specified point p out of the database */ +/****************************************************************************/ +FGPhysicalProperty FGLocalWeatherDatabase::get(const sgVec3& p) const { - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addAirPressure(x); -} + // 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); -void FGLocalWeatherDatabase::addVaporPressure(const FGVaporPressureItem& x, const Point2D& p) -{ - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addVaporPressure(x); + return FGPhysicalProperty(DatabaseEvaluate(p), p[2]); } -void FGLocalWeatherDatabase::addCloud(const FGCloudItem& x, const Point2D& p) +#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 { - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].addCloud(x); + return DatabaseEvaluate(p); } +#endif -void FGLocalWeatherDatabase::setSnowRainIntensity(const WeatherPrecition& x, const Point2D& p) +WeatherPrecision FGLocalWeatherDatabase::getAirDensity(const sgVec3& p) const { - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].setSnowRainIntensity(x); + FGPhysicalProperty dummy(DatabaseEvaluate(p), p[2]); + + return + (dummy.AirPressure*FG_WEATHER_DEFAULT_AIRDENSITY*FG_WEATHER_DEFAULT_TEMPERATURE) / + (dummy.Temperature*FG_WEATHER_DEFAULT_AIRPRESSURE); } -void FGLocalWeatherDatabase::setSnowRainType(const SnowRainType& x, const Point2D& p) + +void FGLocalWeatherDatabase::setSnowRainIntensity(const WeatherPrecision x, const sgVec2& p) { - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].setSnowRainType(x); + /* not supported yet */ } -void FGLocalWeatherDatabase::setLightningProbability(const WeatherPrecition& x, const Point2D& p) +void FGLocalWeatherDatabase::setSnowRainType(const SnowRainType x, const sgVec2& p) { - unsigned int a = AreaWith(p); - if (a != 0) - WeatherAreas[a-1].setLightningProbability(x); + /* not supported yet */ } -void FGLocalWeatherDatabase::addProperties(const FGPhysicalProperties2D& x) +void FGLocalWeatherDatabase::setLightningProbability(const WeatherPrecision x, const sgVec2& p) { - 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"; - WeatherDatabase->update( Point3D( - current_aircraft.fdm_state->get_Latitude(), - current_aircraft.fdm_state->get_Longitude(), - current_aircraft.fdm_state->get_Altitude() * FEET_TO_METER) ); + sgVec3 position; + + sgSetVec3(position, + 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); */ + + }