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)
This commit is contained in:
parent
a3691ac013
commit
33b6694311
6 changed files with 257 additions and 51 deletions
|
@ -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
|
||||
|
|
|
@ -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<SGMetarCloud> cv = m->getClouds();
|
||||
vector<SGMetarCloud>::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());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
159
src/Environment/fgmetar.cxx
Normal file
159
src/Environment/fgmetar.cxx
Normal file
|
@ -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 <simgear/math/sg_random.h>
|
||||
#include <simgear/timing/sg_time.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#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<SGMetarCloud> 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<SGMetarCloud> cv = _clouds;
|
||||
vector<SGMetarCloud>::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<string, SGMetarRunway> rm = getRunways();
|
||||
map<string, SGMetarRunway>::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;
|
||||
}
|
||||
|
56
src/Environment/fgmetar.hxx
Normal file
56
src/Environment/fgmetar.hxx
Normal file
|
@ -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 <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
|
||||
#include <simgear/environment/metar.hxx>
|
||||
|
||||
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
|
|
@ -265,7 +265,7 @@ void printReport(SGMetar *m)
|
|||
|
||||
// assemble surface string
|
||||
vector<string> 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);
|
||||
|
|
Loading…
Add table
Reference in a new issue