From: ehofman Date: Thu, 20 Jan 2005 09:28:45 +0000 (+0000) Subject: Melchior FRANZ: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=33b6694311634aca283cc98e3a8e41e43e3ad7d0;p=flightgear.git Melchior FRANZ: The following patches to SimGear & FlightGear ... - create an FGMetar abstraction layer, whose purpose is: * provide defaults for unset values * interpolate/randomize data (GREATER_THAN) * derive additional values (time, age, snow cover) * consider minimum identifier (CAVOK, mil. color codes) - add rain/hail/snow/snowcover support on the METAR side - add max age of METAR data handling (currently set to - add support for an external METAR cache proxy server - add CAVOK handling - set missing year/month in regular METAR messages - fix a small bug in metar.cxx (wrong return value) --- diff --git a/src/Environment/Makefile.am b/src/Environment/Makefile.am index e3f7450d1..a16996170 100644 --- a/src/Environment/Makefile.am +++ b/src/Environment/Makefile.am @@ -7,6 +7,7 @@ noinst_LIBRARIES = libEnvironment.a libEnvironment_a_SOURCES = \ environment.cxx environment.hxx \ environment_mgr.cxx environment_mgr.hxx \ - environment_ctrl.cxx environment_ctrl.hxx + environment_ctrl.cxx environment_ctrl.hxx \ + fgmetar.cxx fgmetar.hxx INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src diff --git a/src/Environment/environment_ctrl.cxx b/src/Environment/environment_ctrl.cxx index 0e7a6db37..d426d0e6e 100644 --- a/src/Environment/environment_ctrl.cxx +++ b/src/Environment/environment_ctrl.cxx @@ -541,7 +541,13 @@ FGMetarEnvironmentCtrl::fetch_data( const string &icao ) string host = proxy_host->getStringValue(); string auth = proxy_auth->getStringValue(); string port = proxy_port->getStringValue(); - result.m = new SGMetar( icao, host, port, auth); + result.m = new FGMetar( icao, host, port, auth); + + if (result.m->getAge_min() > 4 * 60) { + SG_LOG( SG_GENERAL, SG_WARN, "METAR data too old"); + delete result.m; + result.m = NULL; + } } catch (const sg_io_exception& e) { SG_LOG( SG_GENERAL, SG_WARN, "Error fetching live weather data: " @@ -564,28 +570,24 @@ FGMetarEnvironmentCtrl::fetch_data( const string &icao ) void -FGMetarEnvironmentCtrl::update_metar_properties( SGMetar *m ) +FGMetarEnvironmentCtrl::update_metar_properties( FGMetar *m ) { int i; - double d, dt; + double d; char s[128]; - d = m->getMinVisibility().getVisibility_m(); - d = (d != SGMetarNaN) ? d : 10000; - fgSetDouble("/environment/metar/min-visibility-m", d); - - dt = m->getMaxVisibility().getVisibility_m(); - d = (dt != SGMetarNaN) ? dt : d; - fgSetDouble("/environment/metar/max-visibility-m", d); + fgSetString("/environment/metar/station-id", m->getId()); + fgSetDouble("/environment/metar/min-visibility-m", + m->getMinVisibility().getVisibility_m() ); + fgSetDouble("/environment/metar/max-visibility-m", + m->getMaxVisibility().getVisibility_m() ); SGMetarVisibility *dirvis = m->getDirVisibility(); for (i = 0; i < 8; i++, dirvis++) { const char *min = "/environment/metar/visibility[%d]/min-m"; const char *max = "/environment/metar/visibility[%d]/max-m"; - char s[128]; d = dirvis->getVisibility_m(); - d = (d != SGMetarNaN) ? d : 10000; snprintf(s, 128, min, i); fgSetDouble(s, d); @@ -593,37 +595,22 @@ FGMetarEnvironmentCtrl::update_metar_properties( SGMetar *m ) fgSetDouble(s, d); } - i = m->getWindDir(); - if ( i == -1 ) { - fgSetInt("/environment/metar/base-wind-range-from", - m->getWindRangeFrom() ); - fgSetInt("/environment/metar/base-wind-range-to", - m->getWindRangeTo() ); - } else { - fgSetInt("/environment/metar/base-wind-range-from", i); - fgSetInt("/environment/metar/base-wind-range-to", i); - } + fgSetInt("/environment/metar/base-wind-range-from", + m->getWindRangeFrom() ); + fgSetInt("/environment/metar/base-wind-range-to", + m->getWindRangeTo() ); fgSetDouble("/environment/metar/base-wind-speed-kt", m->getWindSpeed_kt() ); - - d = m->getGustSpeed_kt(); - d = (d != SGMetarNaN) ? d : 0.0; - fgSetDouble("/environment/metar/gust-wind-speed-kt", d); - - d = m->getTemperature_C(); - if (d != SGMetarNaN) { - dt = m->getDewpoint_C(); - dt = (dt != SGMetarNaN) ? dt : 0.0; - fgSetDouble("/environment/metar/dewpoint-degc", dt); - fgSetDouble("/environment/metar/rel-humidity-norm", - m->getRelHumidity() ); - } - d = (d != SGMetarNaN) ? d : 15.0; - fgSetDouble("/environment/metar/temperature-degc", d); - - d = m->getPressure_inHg(); - d = (d != SGMetarNaN) ? d : 30.0; - fgSetDouble("/environment/metar/pressure-inhg", d); + fgSetDouble("/environment/metar/gust-wind-speed-kt", + m->getGustSpeed_kt() ); + fgSetDouble("/environment/metar/temperature-degc", + m->getTemperature_C() ); + fgSetDouble("/environment/metar/dewpoint-degc", + m->getDewpoint_C() ); + fgSetDouble("/environment/metar/rel-humidity-norm", + m->getRelHumidity() ); + fgSetDouble("/environment/metar/pressure-inhg", + m->getPressure_inHg() ); vector cv = m->getClouds(); vector::iterator cloud; @@ -638,14 +625,11 @@ FGMetarEnvironmentCtrl::update_metar_properties( SGMetar *m ) snprintf(s, 128, cl, i); strncat(s, "/coverage", 128); q = cloud->getCoverage(); - q = (q != -1 ) ? q : 0; fgSetString(s, coverage_string[q] ); snprintf(s, 128, cl, i); strncat(s, "/elevation-ft", 128); - d = cloud->getAltitude_ft(); - d = (d != SGMetarNaN) ? d : -9999; - fgSetDouble(s, d + station_elevation_ft); + fgSetDouble(s, cloud->getAltitude_ft() + station_elevation_ft); snprintf(s, 128, cl, i); strncat(s, "/thickness-ft", 128); @@ -673,6 +657,11 @@ FGMetarEnvironmentCtrl::update_metar_properties( SGMetar *m ) strncat(s, "/span-m", 128); fgSetDouble(s, 40000.0); } + + fgSetDouble("/environment/metar/rain-norm", m->getRain()); + fgSetDouble("/environment/metar/hail-norm", m->getHail()); + fgSetDouble("/environment/metar/snow-norm", m->getSnow()); + fgSetBool("/environment/metar/snow-cover", m->getSnowCover()); } diff --git a/src/Environment/environment_ctrl.hxx b/src/Environment/environment_ctrl.hxx index bb3460484..b48ee5f96 100644 --- a/src/Environment/environment_ctrl.hxx +++ b/src/Environment/environment_ctrl.hxx @@ -47,6 +47,7 @@ SG_USING_STD(vector); class SGPropertyNode; #include "environment.hxx" +#include "fgmetar.hxx" @@ -141,16 +142,16 @@ private: }; -// A convenience wrapper around SGMetar +// A convenience wrapper around FGMetar struct FGMetarResult { string icao; - SGMetar *m; + FGMetar *m; }; /** - * Interplation controller using the SGMetar class + * Interplation controller using the FGMetar class */ class FGMetarEnvironmentCtrl : public FGEnvironmentCtrl { @@ -178,7 +179,7 @@ private: SGPropertyNode *proxy_auth; FGMetarResult fetch_data( const string &icao ); - virtual void update_metar_properties( SGMetar *m ); + virtual void update_metar_properties( FGMetar *m ); void update_env_config(); private: diff --git a/src/Environment/fgmetar.cxx b/src/Environment/fgmetar.cxx new file mode 100644 index 000000000..0f71c8e4b --- /dev/null +++ b/src/Environment/fgmetar.cxx @@ -0,0 +1,159 @@ +// metar interface class +// +// Written by Melchior FRANZ, started January 2005. +// +// Copyright (C) 2005 Melchior FRANZ - mfranz@aon.at +// +// 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 Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA +// +// $Id$ + +/** + * @file fgmetar.cxx + * Implements FGMetar class that inherits from SGMetar. + * + * o provide defaults for unset values + * o interpolate/randomize data (GREATER_THAN) + * o derive additional values (time, age, snow cover) + * o consider minimum identifier (CAVOK, mil. color codes) + * + * TODO + * - NSC & mil. color codes + */ + +#include +#include +#include
+ +#include "fgmetar.hxx" + + +FGMetar::FGMetar(const string& icao, const string& proxy, const string& port, const string& auth) : + SGMetar(icao, proxy, port, auth, _rq_time = globals->get_time_params()->get_cur_time()), + _snow_cover(false) +{ + int i; + double d; + + // CAVOK: visibility >= 10km; lowest cloud layer >= 5000 ft; any coverage + if (getCAVOK()) { + if (_min_visibility.getVisibility_m() == SGMetarNaN) + _min_visibility.set(12000.0); + + if (_max_visibility.getVisibility_m() == SGMetarNaN) + _min_visibility.set(12000.0); + + vector cv = _clouds;; + if (!cv.size()) { + SGMetarCloud cl; + cl.set(5500 * SG_FEET_TO_METER, 2); + _clouds.push_back(cl); + } + } + + // visibility + d = _min_visibility.getVisibility_m(); + if (d == SGMetarNaN) + d = 10000.0; + if (_min_visibility.getModifier() == SGMetarVisibility::GREATER_THAN) + d += 15000.0;// * sg_random(); + _min_visibility.set(d); + + if (_max_visibility.getVisibility_m() == SGMetarNaN) + _max_visibility.set(d); + + for (i = 0; i < 8; i++) { + d = _dir_visibility[i].getVisibility_m(); + if (d == SGMetarNaN) + _dir_visibility[i].set(10000.0); + if (_dir_visibility[i].getModifier() == SGMetarVisibility::GREATER_THAN) + d += 15000.0;// * sg_random(); + _dir_visibility[i].set(d); + } + + // wind + if (_wind_dir == -1) { + if (_wind_range_from == -1) { + _wind_dir = 0; + _wind_range_from = 0; + _wind_range_to = 359; + } else { + _wind_dir = (_wind_range_from + _wind_range_to) / 2; + } + } else if (_wind_range_from == -1) { + _wind_range_from = _wind_range_to = _wind_dir; + } + + if (_gust_speed == SGMetarNaN) + _gust_speed = 0.0; + + // clouds + vector cv = _clouds; + vector::iterator cloud; + + for (i = 0, cloud = cv.begin(); cloud != cv.end(); cloud++, i++) { + int cov = cloud->getCoverage(); + if (cov == -1) + cov = 0; + + double alt = cloud->getAltitude_ft(); + if (alt == SGMetarNaN) + alt = -9999; + + cloud->set(alt, cov); + } + + + // temperature/pressure + if (_temp == SGMetarNaN) + _temp = 15.0; + + if (_dewp == SGMetarNaN) + _dewp = 0.0; + + if (_pressure == SGMetarNaN) + _pressure = 30.0 * SG_INHG_TO_PA; + + // snow cover + map rm = getRunways(); + map::iterator runway; + for (runway = rm.begin(); runway != rm.end(); runway++) { + SGMetarRunway rwy = runway->second; + if (rwy.getDeposit() >= 3 ) { + _snow_cover = true; + break; + } + } + if (_temp < 5.0 && _snow) + _snow_cover = true; + if (_temp < 1.0 && getRelHumidity() > 80) + _snow_cover = true; + + _time = sgTimeGetGMT(_year - 1900, _month - 1, _day, _hour, _minute, 0); + + SG_LOG(SG_GENERAL, SG_INFO, _data); + if (_x_proxy) + SG_LOG(SG_GENERAL, SG_INFO, "METAR from proxy"); + else + SG_LOG(SG_GENERAL, SG_INFO, "METAR from weather.noaa.gov"); +} + + +long FGMetar::getAge_min() const +{ + time_t now = _x_proxy ? _rq_time : time(0); + return (now - _time) / 60; +} + diff --git a/src/Environment/fgmetar.hxx b/src/Environment/fgmetar.hxx new file mode 100644 index 000000000..67874d492 --- /dev/null +++ b/src/Environment/fgmetar.hxx @@ -0,0 +1,56 @@ +// metar interface class +// +// Written by Melchior FRANZ, started January 2005. +// +// Copyright (C) 2005 Melchior FRANZ - mfranz@aon.at +// +// 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 Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA +// +// $Id$ + +#ifndef _FGMETAR_HXX +#define _FGMETAR_HXX + +#include +#include +#include +#include + +#include + +SG_USING_STD(vector); +SG_USING_STD(map); +SG_USING_STD(string); + + +class FGMetar : public SGMetar { +public: + FGMetar(const string& icao, const string& proxy = "", const string& port = "", + const string &auth = ""); + + long getAge_min() const; + time_t getTime() const { return _time; } + double getRain() const { return _rain / 3.0; } + double getHail() const { return _hail / 3.0; } + double getSnow() const { return _snow / 3.0; } + bool getSnowCover() const { return _snow_cover; } + +private: + time_t _rq_time; + time_t _time; + bool _snow_cover; +}; + +#endif // _FGMETAR_HXX diff --git a/src/Main/metar_main.cxx b/src/Main/metar_main.cxx index 4519975d0..03805806b 100644 --- a/src/Main/metar_main.cxx +++ b/src/Main/metar_main.cxx @@ -265,7 +265,7 @@ void printReport(SGMetar *m) // assemble surface string vector surface; - if ((s = rwy.getDeposit()) && strlen(s)) + if ((s = rwy.getDepositString()) && strlen(s)) surface.push_back(s); if ((s = rwy.getExtentString()) && strlen(s)) surface.push_back(s);