-static AirportWithMetar airportWithMetarFilter;
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGEnvironmentCtrl abstract base class.
-////////////////////////////////////////////////////////////////////////
-
-FGEnvironmentCtrl::FGEnvironmentCtrl ()
- : _environment(0),
- _lon_deg(0),
- _lat_deg(0),
- _elev_ft(0)
-{
-}
-
-FGEnvironmentCtrl::~FGEnvironmentCtrl ()
-{
-}
-
-void
-FGEnvironmentCtrl::setEnvironment (FGEnvironment * environment)
-{
- _environment = environment;
-}
-
-void
-FGEnvironmentCtrl::setLongitudeDeg (double lon_deg)
-{
- _lon_deg = lon_deg;
-}
-
-void
-FGEnvironmentCtrl::setLatitudeDeg (double lat_deg)
-{
- _lat_deg = lat_deg;
-}
-
-void
-FGEnvironmentCtrl::setElevationFt (double elev_ft)
-{
- _elev_ft = elev_ft;
-}
-
-void
-FGEnvironmentCtrl::setPosition (double lon_deg, double lat_deg, double elev_ft)
-{
- _lon_deg = lon_deg;
- _lat_deg = lat_deg;
- _elev_ft = elev_ft;
-}
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGInterpolateEnvironmentCtrl.
-////////////////////////////////////////////////////////////////////////
-
-
-FGInterpolateEnvironmentCtrl::FGInterpolateEnvironmentCtrl ()
-{
- altitude_n = fgGetNode("/position/altitude-ft", true);
- altitude_agl_n = fgGetNode("/position/altitude-agl-ft", true);
- boundary_transition_n = fgGetNode("/environment/config/boundary-transition-ft", false );
- boundary_n = fgGetNode("/environment/config/boundary", true );
- aloft_n = fgGetNode("/environment/config/aloft", true );
-}
-
-FGInterpolateEnvironmentCtrl::~FGInterpolateEnvironmentCtrl ()
-{
- unsigned int i;
- for (i = 0; i < _boundary_table.size(); i++)
- delete _boundary_table[i];
- for (i = 0; i < _aloft_table.size(); i++)
- delete _aloft_table[i];
-}
-
-
-
-void
-FGInterpolateEnvironmentCtrl::init ()
-{
- read_table( boundary_n, _boundary_table);
- // pass in a pointer to the environment of the last bondary layer as
- // a starting point
- read_table( aloft_n, _aloft_table,
- _boundary_table.size() > 0 ?
- &(*(_boundary_table.end()-1))->environment : NULL );
-}
-
-void
-FGInterpolateEnvironmentCtrl::reinit ()
-{
- init();
-}
-
-void
-FGInterpolateEnvironmentCtrl::read_table (const SGPropertyNode * node, vector<bucket *> &table, FGEnvironment * parent )
-{
- double last_altitude_ft = 0.0;
- double sort_required = false;
- size_t i;
-
- for (i = 0; i < (size_t)node->nChildren(); i++) {
- const SGPropertyNode * child = node->getChild(i);
- if ( strcmp(child->getName(), "entry") == 0
- && child->getStringValue("elevation-ft", "")[0] != '\0'
- && ( child->getDoubleValue("elevation-ft") > 0.1 || i == 0 ) )
- {
- bucket * b;
- if( i < table.size() ) {
- // recycle existing bucket
- b = table[i];
- } else {
- // more nodes than buckets in table, add a new one
- b = new bucket;
- table.push_back(b);
- }
- if (i == 0 && parent != NULL )
- b->environment.copy( *parent );
- if (i > 0)
- b->environment.copy(table[i-1]->environment);
-
- b->environment.read(child);
- b->altitude_ft = b->environment.get_elevation_ft();
-
- // check, if altitudes are in ascending order
- if( b->altitude_ft < last_altitude_ft )
- sort_required = true;
- last_altitude_ft = b->altitude_ft;
- }
- }
- // remove leftover buckets
- while( table.size() > i ) {
- bucket * b = *(table.end() - 1);
- delete b;
- table.pop_back();
- }
-
- if( sort_required )
- sort(table.begin(), table.end(), bucket::lessThan);
-
- // cleanup entries with (almost)same altitude
- for( vector<bucket *>::size_type n = 1; n < table.size(); n++ ) {
- if( fabs(table[n]->altitude_ft - table[n-1]->altitude_ft ) < 1 ) {
- SG_LOG( SG_GENERAL, SG_ALERT, "Removing duplicate altitude entry in environment config for altitude " << table[n]->altitude_ft );
- table.erase( table.begin() + n );
- }
- }
-}
-
-void
-FGInterpolateEnvironmentCtrl::update (double delta_time_sec)
-{
- double altitude_ft = altitude_n->getDoubleValue();
- double altitude_agl_ft = altitude_agl_n->getDoubleValue();
- double boundary_transition =
- boundary_transition_n == NULL ? 500 : boundary_transition_n->getDoubleValue();
-
- int length = _boundary_table.size();
-
- if (length > 0) {
- // boundary table
- double boundary_limit = _boundary_table[length-1]->altitude_ft;
- if (boundary_limit >= altitude_agl_ft) {
- do_interpolate(_boundary_table, altitude_agl_ft, _environment);
- return;
- } else if ((boundary_limit + boundary_transition) >= altitude_agl_ft) {
- //TODO: this is 500ft above the top altitude of boundary layer
- //shouldn't this be +/-250 ft off of the top altitude?
- // both tables
- do_interpolate(_boundary_table, altitude_agl_ft, &env1);
- do_interpolate(_aloft_table, altitude_ft, &env2);
- double fraction = boundary_transition > SGLimitsd::min() ?
- (altitude_agl_ft - boundary_limit) / boundary_transition : 1.0;
- interpolate(&env1, &env2, fraction, _environment);
- return;
- }
- }
- // aloft table
- do_interpolate(_aloft_table, altitude_ft, _environment);
-}
-
-void
-FGInterpolateEnvironmentCtrl::do_interpolate (vector<bucket *> &table, double altitude_ft, FGEnvironment * environment)
-{
- int length = table.size();
- if (length == 0)
- return;
-
- // Boundary conditions
- if ((length == 1) || (table[0]->altitude_ft >= altitude_ft)) {
- environment->copy(table[0]->environment); // below bottom of table
- return;
- } else if (table[length-1]->altitude_ft <= altitude_ft) {
- environment->copy(table[length-1]->environment); // above top of table
- return;
- }
-
- // Search the interpolation table
- int layer;
- for ( layer = 1; // can't be below bottom layer, handled above
- layer < length && table[layer]->altitude_ft <= altitude_ft;
- layer++);
- FGEnvironment * env1 = &(table[layer-1]->environment);
- FGEnvironment * env2 = &(table[layer]->environment);
- // two layers of same altitude were sorted out in read_table
- double fraction = ((altitude_ft - table[layer-1]->altitude_ft) /
- (table[layer]->altitude_ft - table[layer-1]->altitude_ft));
- interpolate(env1, env2, fraction, environment);
-}
-
-bool
-FGInterpolateEnvironmentCtrl::bucket::operator< (const bucket &b) const
-{
- return (altitude_ft < b.altitude_ft);
-}
-
-bool
-FGInterpolateEnvironmentCtrl::bucket::lessThan(bucket *a, bucket *b)
-{
- return (a->altitude_ft) < (b->altitude_ft);
-}
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGMetarCtrl.
-////////////////////////////////////////////////////////////////////////
-
-FGMetarCtrl::FGMetarCtrl( SGSubsystem * environmentCtrl )
- :
- metar_valid(false),
- setup_winds_aloft(true),
- wind_interpolation_required(true),
- metar_sealevel_temperature(15.0),
- metar_sealevel_dewpoint(5.0),
- // Interpolation constant definitions.
- MaxWindChangeKtsSec( 0.2 ),
- MaxVisChangePercentSec( 0.05 ),
- MaxPressureChangeInHgSec( 0.0005 ), // approx 1hpa/min
- MaxTemperatureChangeDegcSec(10.0/60.0), // approx 10degc/min
- MaxCloudAltitudeChangeFtSec( 20.0 ),
- MaxCloudThicknessChangeFtSec( 50.0 ),
- MaxCloudInterpolationHeightFt( 5000.0 ),
- MaxCloudInterpolationDeltaFt( 4000.0 ),
- _environmentCtrl(environmentCtrl)
-{
- windModulator = new FGBasicWindModulator();
-
- metar_base_n = fgGetNode( "/environment/metar", true );
- station_id_n = metar_base_n->getNode("station-id", true );
- station_elevation_n = metar_base_n->getNode("station-elevation-ft", true );
- min_visibility_n = metar_base_n->getNode("min-visibility-m", true );
- max_visibility_n = metar_base_n->getNode("max-visibility-m", true );
- base_wind_range_from_n = metar_base_n->getNode("base-wind-range-from", true );
- base_wind_range_to_n = metar_base_n->getNode("base-wind-range-to", true );
- base_wind_speed_n = metar_base_n->getNode("base-wind-speed-kt", true );
- base_wind_dir_n = metar_base_n->getNode("base-wind-dir-deg", true );
- gust_wind_speed_n = metar_base_n->getNode("gust-wind-speed-kt", true );
- temperature_n = metar_base_n->getNode("temperature-degc", true );
- dewpoint_n = metar_base_n->getNode("dewpoint-degc", true );
- humidity_n = metar_base_n->getNode("rel-humidity-norm", true );
- pressure_n = metar_base_n->getNode("pressure-inhg", true );
- clouds_n = metar_base_n->getNode("clouds", true );
- rain_n = metar_base_n->getNode("rain-norm", true );
- hail_n = metar_base_n->getNode("hail-norm", true );
- snow_n = metar_base_n->getNode("snow-norm", true );
- snow_cover_n = metar_base_n->getNode("snow-cover", true );
- magnetic_variation_n = fgGetNode( "/environment/magnetic-variation-deg", true );
- ground_elevation_n = fgGetNode( "/position/ground-elev-m", true );
- longitude_n = fgGetNode( "/position/longitude-deg", true );
- latitude_n = fgGetNode( "/position/latitude-deg", true );
- environment_clouds_n = fgGetNode("/environment/clouds");
-
- boundary_wind_speed_n = fgGetNode("/environment/config/boundary/entry/wind-speed-kt", true );
- boundary_wind_from_heading_n = fgGetNode("/environment/config/boundary/entry/wind-from-heading-deg", true );
- boundary_visibility_n = fgGetNode("/environment/config/boundary/entry/visibility-m", true );
- boundary_sea_level_pressure_n = fgGetNode("/environment/config/boundary/entry/pressure-sea-level-inhg", true );
- boundary_sea_level_temperature_n = fgGetNode("/environment/config/boundary/entry/temperature-sea-level-degc", true );
- boundary_sea_level_dewpoint_n = fgGetNode("/environment/config/boundary/entry/dewpoint-sea-level-degc", true );
-}
-
-FGMetarCtrl::~FGMetarCtrl ()
-{
-}
-
-void FGMetarCtrl::bind ()
-{
- fgTie("/environment/metar/valid", this, &FGMetarCtrl::get_valid );
- fgTie("/environment/params/metar-updates-environment", this, &FGMetarCtrl::get_enabled, &FGMetarCtrl::set_enabled );
- fgTie("/environment/params/metar-updates-winds-aloft", this, &FGMetarCtrl::get_setup_winds_aloft, &FGMetarCtrl::set_setup_winds_aloft );
-}