Environment controller overhaul
This is the initial commit for a reworked environment controller. The main intention is to decouple the individual modules like metar fetch, metar properties, environment interpolation etc. to make it easier for other weather module developers to modify environment settings. As a side effect, the dialogs for weather-scenario, weather-conditions, clouds and precipitations have been merged into a single dialog
This commit is contained in:
parent
fdbfd6fd0b
commit
5c6fe95259
14 changed files with 1262 additions and 1598 deletions
|
@ -9,10 +9,13 @@ libEnvironment_a_SOURCES = \
|
|||
environment_mgr.cxx environment_mgr.hxx \
|
||||
environment_ctrl.cxx environment_ctrl.hxx \
|
||||
fgmetar.cxx fgmetar.hxx fgclouds.cxx fgclouds.hxx \
|
||||
fgwind.cxx fgwind.hxx \
|
||||
realwx_ctrl.cxx realwx_ctrl.hxx \
|
||||
metarproperties.cxx metarproperties.hxx \
|
||||
metarairportfilter.cxx metarairportfilter.hxx \
|
||||
atmosphere.cxx atmosphere.hxx \
|
||||
precipitation_mgr.cxx precipitation_mgr.hxx \
|
||||
ridge_lift.cxx ridge_lift.hxx \
|
||||
ephemeris.cxx ephemeris.hxx
|
||||
ephemeris.cxx ephemeris.hxx \
|
||||
terrainsampler.cxx terrainsampler.cxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
|
@ -138,9 +136,6 @@ void FGEnvironment::_init()
|
|||
wind_from_north_fps = 0;
|
||||
wind_from_east_fps = 0;
|
||||
wind_from_down_fps = 0;
|
||||
thermal_lift_fps = 0;
|
||||
ridge_lift_fps= 0;
|
||||
local_weather_lift_fps=0;
|
||||
altitude_half_to_sun_m = 1000;
|
||||
altitude_tropo_top_m = 10000;
|
||||
#ifdef USING_TABLES
|
||||
|
@ -164,6 +159,13 @@ FGEnvironment::FGEnvironment (const FGEnvironment &env)
|
|||
|
||||
FGEnvironment::~FGEnvironment()
|
||||
{
|
||||
Untie();
|
||||
}
|
||||
|
||||
FGEnvironment & FGEnvironment::operator = ( const FGEnvironment & other )
|
||||
{
|
||||
copy( other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -181,9 +183,6 @@ FGEnvironment::copy (const FGEnvironment &env)
|
|||
wind_from_north_fps = env.wind_from_north_fps;
|
||||
wind_from_east_fps = env.wind_from_east_fps;
|
||||
wind_from_down_fps = env.wind_from_down_fps;
|
||||
thermal_lift_fps = env.thermal_lift_fps;
|
||||
ridge_lift_fps= env.ridge_lift_fps;
|
||||
local_weather_lift_fps = env.local_weather_lift_fps;
|
||||
turbulence_magnitude_norm = env.turbulence_magnitude_norm;
|
||||
turbulence_rate_hz = env.turbulence_rate_hz;
|
||||
}
|
||||
|
@ -260,6 +259,107 @@ FGEnvironment::read (const SGPropertyNode * node)
|
|||
set_live_update(live_update);
|
||||
}
|
||||
|
||||
void FGEnvironment::Tie( SGPropertyNode_ptr base, bool archivable )
|
||||
{
|
||||
_tiedProperties.setRoot( base );
|
||||
|
||||
_tiedProperties.Tie( "visibility-m", this,
|
||||
&FGEnvironment::get_visibility_m,
|
||||
&FGEnvironment::set_visibility_m)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("temperature-sea-level-degc", this,
|
||||
&FGEnvironment::get_temperature_sea_level_degc,
|
||||
&FGEnvironment::set_temperature_sea_level_degc)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("temperature-degc", this,
|
||||
&FGEnvironment::get_temperature_degc,
|
||||
&FGEnvironment::set_temperature_degc)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("temperature-degf", this,
|
||||
&FGEnvironment::get_temperature_degf);
|
||||
|
||||
_tiedProperties.Tie("dewpoint-sea-level-degc", this,
|
||||
&FGEnvironment::get_dewpoint_sea_level_degc,
|
||||
&FGEnvironment::set_dewpoint_sea_level_degc)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("dewpoint-degc", this,
|
||||
&FGEnvironment::get_dewpoint_degc,
|
||||
&FGEnvironment::set_dewpoint_degc)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("pressure-sea-level-inhg", this,
|
||||
&FGEnvironment::get_pressure_sea_level_inhg,
|
||||
&FGEnvironment::set_pressure_sea_level_inhg)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("pressure-inhg", this,
|
||||
&FGEnvironment::get_pressure_inhg,
|
||||
&FGEnvironment::set_pressure_inhg)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("density-slugft3", this,
|
||||
&FGEnvironment::get_density_slugft3); // read-only
|
||||
|
||||
_tiedProperties.Tie("relative-humidity", this,
|
||||
&FGEnvironment::get_relative_humidity); //ro
|
||||
|
||||
_tiedProperties.Tie("atmosphere/density-tropo-avg", this,
|
||||
&FGEnvironment::get_density_tropo_avg_kgm3); //ro
|
||||
|
||||
_tiedProperties.Tie("atmosphere/altitude-half-to-sun", this,
|
||||
&FGEnvironment::get_altitude_half_to_sun_m,
|
||||
&FGEnvironment::set_altitude_half_to_sun_m)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("atmosphere/altitude-troposphere-top", this,
|
||||
&FGEnvironment::get_altitude_tropo_top_m,
|
||||
&FGEnvironment::set_altitude_tropo_top_m)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("wind-from-heading-deg", this,
|
||||
&FGEnvironment::get_wind_from_heading_deg,
|
||||
&FGEnvironment::set_wind_from_heading_deg)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("wind-speed-kt", this,
|
||||
&FGEnvironment::get_wind_speed_kt,
|
||||
&FGEnvironment::set_wind_speed_kt)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("wind-from-north-fps", this,
|
||||
&FGEnvironment::get_wind_from_north_fps,
|
||||
&FGEnvironment::set_wind_from_north_fps)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("wind-from-east-fps", this,
|
||||
&FGEnvironment::get_wind_from_east_fps,
|
||||
&FGEnvironment::set_wind_from_east_fps)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("wind-from-down-fps", this,
|
||||
&FGEnvironment::get_wind_from_down_fps,
|
||||
&FGEnvironment::set_wind_from_down_fps)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("turbulence/magnitude-norm", this,
|
||||
&FGEnvironment::get_turbulence_magnitude_norm,
|
||||
&FGEnvironment::set_turbulence_magnitude_norm)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
|
||||
_tiedProperties.Tie("turbulence/rate-hz", this,
|
||||
&FGEnvironment::get_turbulence_rate_hz,
|
||||
&FGEnvironment::set_turbulence_rate_hz)
|
||||
->setAttribute( SGPropertyNode::ARCHIVE, archivable );
|
||||
}
|
||||
|
||||
void FGEnvironment::Untie()
|
||||
{
|
||||
_tiedProperties.Untie();
|
||||
}
|
||||
|
||||
double
|
||||
FGEnvironment::get_visibility_m () const
|
||||
|
@ -369,24 +469,6 @@ FGEnvironment::get_wind_from_down_fps () const
|
|||
return wind_from_down_fps;
|
||||
}
|
||||
|
||||
double
|
||||
FGEnvironment::get_thermal_lift_fps () const
|
||||
{
|
||||
return thermal_lift_fps;
|
||||
}
|
||||
|
||||
double
|
||||
FGEnvironment::get_ridge_lift_fps () const
|
||||
{
|
||||
return ridge_lift_fps;
|
||||
}
|
||||
|
||||
double
|
||||
FGEnvironment::get_local_weather_lift_fps () const
|
||||
{
|
||||
return local_weather_lift_fps;
|
||||
}
|
||||
|
||||
double
|
||||
FGEnvironment::get_turbulence_magnitude_norm () const
|
||||
{
|
||||
|
@ -527,33 +609,6 @@ FGEnvironment::set_wind_from_down_fps (double d)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGEnvironment::set_thermal_lift_fps (double th)
|
||||
{
|
||||
thermal_lift_fps = th;
|
||||
if( live_update ) {
|
||||
_recalc_updraft();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGEnvironment::set_ridge_lift_fps (double ri)
|
||||
{
|
||||
ridge_lift_fps = ri;
|
||||
if( live_update ) {
|
||||
_recalc_updraft();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGEnvironment::set_local_weather_lift_fps (double lwl)
|
||||
{
|
||||
local_weather_lift_fps = lwl;
|
||||
if( live_update ) {
|
||||
_recalc_updraft();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGEnvironment::set_turbulence_magnitude_norm (double t)
|
||||
{
|
||||
|
@ -600,34 +655,15 @@ FGEnvironment::set_altitude_tropo_top_m (double alt)
|
|||
void
|
||||
FGEnvironment::_recalc_hdgspd ()
|
||||
{
|
||||
double angle_rad;
|
||||
wind_from_heading_deg =
|
||||
atan2(wind_from_east_fps, wind_from_north_fps) * SGD_RADIANS_TO_DEGREES;
|
||||
|
||||
if (wind_from_east_fps == 0) {
|
||||
angle_rad = (wind_from_north_fps >= 0 ? SGD_PI_2 : -SGD_PI_2);
|
||||
} else {
|
||||
angle_rad = atan(wind_from_north_fps/wind_from_east_fps);
|
||||
}
|
||||
wind_from_heading_deg = angle_rad * SGD_RADIANS_TO_DEGREES;
|
||||
if (wind_from_east_fps >= 0)
|
||||
wind_from_heading_deg = 90 - wind_from_heading_deg;
|
||||
else
|
||||
wind_from_heading_deg = 270 - wind_from_heading_deg;
|
||||
if( wind_from_heading_deg < 0 )
|
||||
wind_from_heading_deg += 360.0;
|
||||
|
||||
#if 0
|
||||
// FIXME: Windspeed can become negative with these formulas.
|
||||
// which can cause problems for animations that rely
|
||||
// on the windspeed property.
|
||||
if (angle_rad == 0)
|
||||
wind_speed_kt = fabs(wind_from_east_fps
|
||||
* SG_METER_TO_NM * SG_FEET_TO_METER * 3600);
|
||||
else
|
||||
wind_speed_kt = (wind_from_north_fps / sin(angle_rad))
|
||||
* SG_METER_TO_NM * SG_FEET_TO_METER * 3600;
|
||||
#else
|
||||
wind_speed_kt = sqrt(wind_from_north_fps * wind_from_north_fps +
|
||||
wind_from_east_fps * wind_from_east_fps)
|
||||
* SG_METER_TO_NM * SG_FEET_TO_METER * 3600;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -642,12 +678,6 @@ FGEnvironment::_recalc_ne ()
|
|||
sin(wind_from_heading_deg * SGD_DEGREES_TO_RADIANS);
|
||||
}
|
||||
|
||||
void
|
||||
FGEnvironment::_recalc_updraft ()
|
||||
{
|
||||
wind_from_down_fps = thermal_lift_fps + ridge_lift_fps + local_weather_lift_fps ;
|
||||
}
|
||||
|
||||
// Intended to help with the interpretation of METAR data,
|
||||
// not for random in-flight outside-air temperatures.
|
||||
void
|
||||
|
@ -736,7 +766,8 @@ FGEnvironment::_recalc_alt_pt ()
|
|||
}
|
||||
}
|
||||
#endif
|
||||
double press, temp;
|
||||
double press = pressure_inhg * inHg;
|
||||
double temp = temperature_degc + freezing;
|
||||
boost::tie(press, temp) = PT_vs_hpt(elevation_ft * foot,
|
||||
pressure_sea_level_inhg * inHg, temperature_sea_level_degc + freezing);
|
||||
temperature_degc = temp - freezing;
|
||||
|
@ -830,57 +861,57 @@ do_interp_deg (double a, double b, double fraction)
|
|||
return fmod(do_interp(a, b, fraction), 360);
|
||||
}
|
||||
|
||||
void
|
||||
interpolate (const FGEnvironment * env1, const FGEnvironment * env2,
|
||||
double fraction, FGEnvironment * result)
|
||||
FGEnvironment &
|
||||
FGEnvironment::interpolate( const FGEnvironment & env2,
|
||||
double fraction, FGEnvironment * result) const
|
||||
{
|
||||
// don't calculate each internal property every time we set a single value
|
||||
// we trigger that at the end of the interpolation process
|
||||
bool live_update = result->set_live_update( false );
|
||||
|
||||
result->set_visibility_m
|
||||
(do_interp(env1->get_visibility_m(),
|
||||
env2->get_visibility_m(),
|
||||
(do_interp(get_visibility_m(),
|
||||
env2.get_visibility_m(),
|
||||
fraction));
|
||||
|
||||
result->set_temperature_sea_level_degc
|
||||
(do_interp(env1->get_temperature_sea_level_degc(),
|
||||
env2->get_temperature_sea_level_degc(),
|
||||
(do_interp(get_temperature_sea_level_degc(),
|
||||
env2.get_temperature_sea_level_degc(),
|
||||
fraction));
|
||||
|
||||
result->set_dewpoint_sea_level_degc
|
||||
(do_interp(env1->get_dewpoint_sea_level_degc(),
|
||||
env2->get_dewpoint_sea_level_degc(),
|
||||
(do_interp(get_dewpoint_sea_level_degc(),
|
||||
env2.get_dewpoint_sea_level_degc(),
|
||||
fraction));
|
||||
|
||||
result->set_pressure_sea_level_inhg
|
||||
(do_interp(env1->get_pressure_sea_level_inhg(),
|
||||
env2->get_pressure_sea_level_inhg(),
|
||||
(do_interp(get_pressure_sea_level_inhg(),
|
||||
env2.get_pressure_sea_level_inhg(),
|
||||
fraction));
|
||||
|
||||
result->set_wind_from_heading_deg
|
||||
(do_interp_deg(env1->get_wind_from_heading_deg(),
|
||||
env2->get_wind_from_heading_deg(),
|
||||
(do_interp_deg(get_wind_from_heading_deg(),
|
||||
env2.get_wind_from_heading_deg(),
|
||||
fraction));
|
||||
|
||||
result->set_wind_speed_kt
|
||||
(do_interp(env1->get_wind_speed_kt(),
|
||||
env2->get_wind_speed_kt(),
|
||||
(do_interp(get_wind_speed_kt(),
|
||||
env2.get_wind_speed_kt(),
|
||||
fraction));
|
||||
|
||||
result->set_elevation_ft
|
||||
(do_interp(env1->get_elevation_ft(),
|
||||
env2->get_elevation_ft(),
|
||||
(do_interp(get_elevation_ft(),
|
||||
env2.get_elevation_ft(),
|
||||
fraction));
|
||||
|
||||
result->set_turbulence_magnitude_norm
|
||||
(do_interp(env1->get_turbulence_magnitude_norm(),
|
||||
env2->get_turbulence_magnitude_norm(),
|
||||
(do_interp(get_turbulence_magnitude_norm(),
|
||||
env2.get_turbulence_magnitude_norm(),
|
||||
fraction));
|
||||
|
||||
result->set_turbulence_rate_hz
|
||||
(do_interp(env1->get_turbulence_rate_hz(),
|
||||
env2->get_turbulence_rate_hz(),
|
||||
(do_interp(get_turbulence_rate_hz(),
|
||||
env2.get_turbulence_rate_hz(),
|
||||
fraction));
|
||||
|
||||
// calculate derived properties here to avoid duplicate expensive computations
|
||||
|
@ -891,6 +922,8 @@ interpolate (const FGEnvironment * env1, const FGEnvironment * env2,
|
|||
result->_recalc_relative_humidity();
|
||||
|
||||
result->set_live_update(live_update);
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
// end of environment.cxx
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
|
||||
#ifndef _ENVIRONMENT_HXX
|
||||
#define _ENVIRONMENT_HXX
|
||||
|
@ -27,6 +25,7 @@
|
|||
#include <simgear/compiler.h>
|
||||
|
||||
#include <cmath>
|
||||
#include "tiedpropertylist.hxx"
|
||||
|
||||
/**
|
||||
* Model the natural environment.
|
||||
|
@ -45,9 +44,11 @@ public:
|
|||
FGEnvironment (const FGEnvironment &environment);
|
||||
virtual ~FGEnvironment();
|
||||
|
||||
virtual void copy (const FGEnvironment &environment);
|
||||
FGEnvironment & operator = ( const FGEnvironment & other );
|
||||
|
||||
virtual void read (const SGPropertyNode * node);
|
||||
virtual void Tie( SGPropertyNode_ptr base, bool setArchivable = true );
|
||||
virtual void Untie();
|
||||
|
||||
virtual double get_visibility_m () const;
|
||||
|
||||
|
@ -70,9 +71,6 @@ public:
|
|||
virtual double get_wind_from_north_fps () const;
|
||||
virtual double get_wind_from_east_fps () const;
|
||||
virtual double get_wind_from_down_fps () const;
|
||||
virtual double get_thermal_lift_fps () const;
|
||||
virtual double get_ridge_lift_fps () const;
|
||||
virtual double get_local_weather_lift_fps () const;
|
||||
|
||||
virtual double get_turbulence_magnitude_norm () const;
|
||||
virtual double get_turbulence_rate_hz () const;
|
||||
|
@ -91,9 +89,6 @@ public:
|
|||
virtual void set_wind_from_north_fps (double n);
|
||||
virtual void set_wind_from_east_fps (double e);
|
||||
virtual void set_wind_from_down_fps (double d);
|
||||
virtual void set_thermal_lift_fps (double th);
|
||||
virtual void set_ridge_lift_fps (double ri);
|
||||
virtual void set_local_weather_lift_fps (double lwl);
|
||||
|
||||
virtual void set_turbulence_magnitude_norm (double t);
|
||||
virtual void set_turbulence_rate_hz (double t);
|
||||
|
@ -105,21 +100,23 @@ public:
|
|||
|
||||
virtual bool set_live_update(bool live_update);
|
||||
|
||||
void _recalc_ne ();
|
||||
void _recalc_alt_dewpoint ();
|
||||
void _recalc_density ();
|
||||
void _recalc_relative_humidity ();
|
||||
void _recalc_alt_pt ();
|
||||
|
||||
FGEnvironment & interpolate (const FGEnvironment & env2, double fraction, FGEnvironment * result) const;
|
||||
private:
|
||||
virtual void copy (const FGEnvironment &environment);
|
||||
void _init();
|
||||
void _recalc_hdgspd ();
|
||||
void _recalc_updraft ();
|
||||
|
||||
void _recalc_sl_temperature ();
|
||||
void _recalc_sl_dewpoint ();
|
||||
void _recalc_sl_pressure ();
|
||||
|
||||
void _recalc_density_tropo_avg_kgm3 ();
|
||||
void _recalc_ne ();
|
||||
void _recalc_alt_dewpoint ();
|
||||
void _recalc_density ();
|
||||
void _recalc_relative_humidity ();
|
||||
void _recalc_alt_pt ();
|
||||
|
||||
double elevation_ft;
|
||||
double visibility_m;
|
||||
|
@ -147,15 +144,10 @@ private:
|
|||
double wind_from_north_fps;
|
||||
double wind_from_east_fps;
|
||||
double wind_from_down_fps;
|
||||
double thermal_lift_fps;
|
||||
double ridge_lift_fps;
|
||||
double local_weather_lift_fps;
|
||||
|
||||
bool live_update;
|
||||
TiedPropertyList _tiedProperties;
|
||||
|
||||
};
|
||||
|
||||
void interpolate (const FGEnvironment * env1, const FGEnvironment * env2,
|
||||
double fraction, FGEnvironment * result);
|
||||
|
||||
#endif // _ENVIRONMENT_HXX
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,243 +18,17 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef _ENVIRONMENT_CTRL_HXX
|
||||
#define _ENVIRONMENT_CTRL_HXX
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
#if defined(ENABLE_THREADS)
|
||||
# include <OpenThreads/Thread>
|
||||
# include <simgear/threads/SGQueue.hxx>
|
||||
#endif
|
||||
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include <Navaids/positioned.hxx>
|
||||
#include <Environment/environment.hxx>
|
||||
#include "fgwind.hxx"
|
||||
|
||||
// forward decls
|
||||
class SGPropertyNode;
|
||||
class SGSampleGroup;
|
||||
class FGMetar;
|
||||
|
||||
/**
|
||||
* Interface to control environment information for a specific location.
|
||||
*/
|
||||
class FGEnvironmentCtrl : public SGSubsystem
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
FGEnvironmentCtrl ();
|
||||
virtual ~FGEnvironmentCtrl ();
|
||||
|
||||
virtual void setEnvironment (FGEnvironment * environment);
|
||||
|
||||
virtual const FGEnvironment * getEnvironment () const { return _environment; }
|
||||
|
||||
virtual void setLongitudeDeg (double lon_deg);
|
||||
virtual void setLatitudeDeg (double lat_deg);
|
||||
virtual void setElevationFt (double elev_ft);
|
||||
virtual void setPosition (double lon_deg, double lat_deg, double elev_ft);
|
||||
|
||||
virtual double getLongitudeDeg () const { return _lon_deg; }
|
||||
virtual double getLatitudeDeg () const { return _lat_deg; }
|
||||
virtual double getElevationFt () const { return _elev_ft; }
|
||||
|
||||
protected:
|
||||
|
||||
FGEnvironment * _environment;
|
||||
double _lon_deg;
|
||||
double _lat_deg;
|
||||
double _elev_ft;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interplation controller using user-supplied parameters.
|
||||
*/
|
||||
class FGInterpolateEnvironmentCtrl : public FGEnvironmentCtrl
|
||||
{
|
||||
public:
|
||||
FGInterpolateEnvironmentCtrl ();
|
||||
virtual ~FGInterpolateEnvironmentCtrl ();
|
||||
|
||||
virtual void init ();
|
||||
virtual void reinit ();
|
||||
virtual void update (double delta_time_sec);
|
||||
|
||||
private:
|
||||
|
||||
struct bucket {
|
||||
double altitude_ft;
|
||||
FGEnvironment environment;
|
||||
bool operator< (const bucket &b) const;
|
||||
// LessThan predicate for bucket pointers.
|
||||
static bool lessThan(bucket *a, bucket *b);
|
||||
};
|
||||
|
||||
void read_table (const SGPropertyNode * node, std::vector<bucket *> &table, FGEnvironment * parent = NULL );
|
||||
void do_interpolate (std::vector<bucket *> &table, double altitude_ft,
|
||||
FGEnvironment * environment);
|
||||
|
||||
FGEnvironment env1, env2; // temporaries
|
||||
|
||||
std::vector<bucket *> _boundary_table;
|
||||
std::vector<bucket *> _aloft_table;
|
||||
|
||||
SGPropertyNode_ptr altitude_n;
|
||||
SGPropertyNode_ptr altitude_agl_n;
|
||||
SGPropertyNode_ptr boundary_transition_n;
|
||||
SGPropertyNode_ptr boundary_n;
|
||||
SGPropertyNode_ptr aloft_n;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interplation controller using the FGMetar class
|
||||
*/
|
||||
|
||||
class FGMetarCtrl : public SGSubsystem
|
||||
{
|
||||
public:
|
||||
FGMetarCtrl (SGSubsystem * environmentCtrl);
|
||||
virtual ~FGMetarCtrl ();
|
||||
|
||||
virtual void init ();
|
||||
virtual void reinit ();
|
||||
virtual void update (double delta_time_sec);
|
||||
|
||||
void set_metar( const char * metar );
|
||||
const char * get_metar(void) const;
|
||||
bool get_valid(void) const { return metar_valid; }
|
||||
void set_enabled(bool _enabled) { enabled = _enabled; }
|
||||
bool get_enabled(void) const { return enabled; }
|
||||
void set_setup_winds_aloft(bool _setup_winds_aloft) { setup_winds_aloft = _setup_winds_aloft; }
|
||||
bool get_setup_winds_aloft(void) const { return setup_winds_aloft; }
|
||||
|
||||
private:
|
||||
void bind();
|
||||
void unbind();
|
||||
|
||||
SGSharedPtr<FGWindModulator> windModulator;
|
||||
bool metar_valid;
|
||||
bool enabled;
|
||||
bool setup_winds_aloft;
|
||||
bool first_update;
|
||||
bool wind_interpolation_required;
|
||||
string metar;
|
||||
double metar_sealevel_temperature;
|
||||
double metar_sealevel_dewpoint;
|
||||
double interpolate_prop(const char * currentname, const char * requiredname, double dvalue);
|
||||
double interpolate_val(double currentval, double requiredval, double dvalue);
|
||||
const double MaxWindChangeKtsSec; // Max wind change in kts/sec
|
||||
const double MaxVisChangePercentSec; // Max visibility change in %/sec
|
||||
const double MaxPressureChangeInHgSec; // Max pressure change in InHg/sec
|
||||
const double MaxTemperatureChangeDegcSec; // Max temperature change in degc/s
|
||||
const double MaxCloudAltitudeChangeFtSec; // Max cloud altitude change in ft/s
|
||||
const double MaxCloudThicknessChangeFtSec; // Max cloud thickness change in ft/s
|
||||
const double MaxCloudInterpolationHeightFt; // Max distance from aircraft to
|
||||
// interpolate at. Any cloud
|
||||
// changes above this height
|
||||
// difference are not interpolated
|
||||
const double MaxCloudInterpolationDeltaFt; // Max difference in altitude to
|
||||
// interpolate. Any cloud changing height
|
||||
// by more than this value is not
|
||||
// interpolated
|
||||
|
||||
SGSubsystem * _environmentCtrl;
|
||||
|
||||
SGPropertyNode_ptr metar_base_n;
|
||||
SGPropertyNode_ptr station_id_n;
|
||||
SGPropertyNode_ptr station_elevation_n;
|
||||
SGPropertyNode_ptr min_visibility_n;
|
||||
SGPropertyNode_ptr max_visibility_n;
|
||||
SGPropertyNode_ptr base_wind_range_from_n;
|
||||
SGPropertyNode_ptr base_wind_range_to_n;
|
||||
SGPropertyNode_ptr base_wind_dir_n;
|
||||
SGPropertyNode_ptr base_wind_speed_n;
|
||||
SGPropertyNode_ptr gust_wind_speed_n;
|
||||
SGPropertyNode_ptr temperature_n;
|
||||
SGPropertyNode_ptr dewpoint_n;
|
||||
SGPropertyNode_ptr humidity_n;
|
||||
SGPropertyNode_ptr pressure_n;
|
||||
SGPropertyNode_ptr clouds_n;
|
||||
SGPropertyNode_ptr environment_clouds_n;
|
||||
SGPropertyNode_ptr rain_n;
|
||||
SGPropertyNode_ptr hail_n;
|
||||
SGPropertyNode_ptr snow_n;
|
||||
SGPropertyNode_ptr snow_cover_n;
|
||||
SGPropertyNode_ptr ground_elevation_n;
|
||||
SGPropertyNode_ptr longitude_n;
|
||||
SGPropertyNode_ptr latitude_n;
|
||||
SGPropertyNode_ptr magnetic_variation_n;
|
||||
|
||||
SGPropertyNode_ptr boundary_wind_speed_n;
|
||||
SGPropertyNode_ptr boundary_wind_from_heading_n;
|
||||
SGPropertyNode_ptr boundary_visibility_n;
|
||||
SGPropertyNode_ptr boundary_sea_level_pressure_n;
|
||||
SGPropertyNode_ptr boundary_sea_level_temperature_n;
|
||||
SGPropertyNode_ptr boundary_sea_level_dewpoint_n;
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* The subsyste to load real world weather
|
||||
*/
|
||||
class FGMetarFetcher : public SGSubsystem
|
||||
{
|
||||
public:
|
||||
FGMetarFetcher();
|
||||
virtual ~FGMetarFetcher();
|
||||
|
||||
virtual void init ();
|
||||
virtual void reinit ();
|
||||
virtual void update (double delta_time_sec);
|
||||
|
||||
private:
|
||||
friend class MetarThread;
|
||||
#if defined(ENABLE_THREADS)
|
||||
/**
|
||||
* FIFO queue which holds a pointer to the metar requests.
|
||||
*/
|
||||
SGBlockingQueue <string> request_queue;
|
||||
|
||||
OpenThreads::Thread * metar_thread;
|
||||
#endif
|
||||
|
||||
void fetch( const string & id );
|
||||
|
||||
SGPropertyNode_ptr enable_n;
|
||||
|
||||
SGPropertyNode_ptr longitude_n;
|
||||
SGPropertyNode_ptr latitude_n;
|
||||
|
||||
SGPropertyNode_ptr proxy_host_n;
|
||||
SGPropertyNode_ptr proxy_port_n;
|
||||
SGPropertyNode_ptr proxy_auth_n;
|
||||
SGPropertyNode_ptr max_age_n;
|
||||
|
||||
SGPropertyNode_ptr output_n;
|
||||
|
||||
string current_airport_id;
|
||||
double fetch_timer;
|
||||
double search_timer;
|
||||
double error_timer;
|
||||
|
||||
long _stale_count;
|
||||
long _error_count;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
namespace Environment {
|
||||
class LayerInterpolateController : public SGSubsystem {
|
||||
public:
|
||||
static LayerInterpolateController * createInstance( SGPropertyNode_ptr rootNode );
|
||||
};
|
||||
} // namespace
|
||||
|
||||
#endif // _ENVIRONMENT_CTRL_HXX
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
|
@ -39,34 +37,26 @@
|
|||
#include "environment.hxx"
|
||||
#include "environment_mgr.hxx"
|
||||
#include "environment_ctrl.hxx"
|
||||
#include "realwx_ctrl.hxx"
|
||||
#include "fgclouds.hxx"
|
||||
#include "precipitation_mgr.hxx"
|
||||
#include "ridge_lift.hxx"
|
||||
#include "terrainsampler.hxx"
|
||||
|
||||
class SGSky;
|
||||
extern SGSky *thesky;
|
||||
|
||||
|
||||
|
||||
FGEnvironmentMgr::FGEnvironmentMgr ()
|
||||
: _environment(new FGEnvironment)
|
||||
FGEnvironmentMgr::FGEnvironmentMgr () :
|
||||
_environment(new FGEnvironment()),
|
||||
fgClouds(new FGClouds()),
|
||||
_altitudeNode(fgGetNode("/position/altitude-ft", true)),
|
||||
_cloudLayersDirty(true)
|
||||
{
|
||||
set_subsystem("controller", Environment::LayerInterpolateController::createInstance( fgGetNode("/environment/config", true ) ));
|
||||
set_subsystem("realwx", Environment::RealWxController::createInstance( fgGetNode("/environment/realwx", true ) ), 1.0 );
|
||||
|
||||
_controller = new FGInterpolateEnvironmentCtrl;
|
||||
_controller->setEnvironment(_environment);
|
||||
set_subsystem("controller", _controller, 0.1 );
|
||||
|
||||
fgClouds = new FGClouds();
|
||||
|
||||
_metarcontroller = new FGMetarCtrl(_controller );
|
||||
set_subsystem("metarcontroller", _metarcontroller, 0.1 );
|
||||
|
||||
_metarfetcher = new FGMetarFetcher();
|
||||
set_subsystem("metarfetcher", _metarfetcher, 1.0 );
|
||||
|
||||
_precipitationManager = new FGPrecipitationMgr;
|
||||
set_subsystem("precipitation", _precipitationManager);
|
||||
|
||||
set_subsystem("precipitation", new FGPrecipitationMgr);
|
||||
set_subsystem("terrainsampler", Environment::TerrainSampler::createInstance( fgGetNode("/environment/terrain", true ) ));
|
||||
set_subsystem("ridgelift", new FGRidgeLift);
|
||||
}
|
||||
|
||||
|
@ -78,20 +68,27 @@ FGEnvironmentMgr::~FGEnvironmentMgr ()
|
|||
remove_subsystem( "ridgelift" );
|
||||
delete subsys;
|
||||
|
||||
subsys = get_subsystem( "terrainsampler" );
|
||||
remove_subsystem( "terrainsampler" );
|
||||
delete subsys;
|
||||
|
||||
subsys = get_subsystem( "precipitation" );
|
||||
remove_subsystem("precipitation");
|
||||
delete _precipitationManager;
|
||||
|
||||
remove_subsystem("metarcontroller");
|
||||
delete _metarfetcher;
|
||||
delete subsys;
|
||||
|
||||
subsys = get_subsystem("metarfetcher");
|
||||
remove_subsystem("metarfetcher");
|
||||
delete _metarcontroller;
|
||||
delete subsys;
|
||||
|
||||
subsys = get_subsystem("metarcontroller");
|
||||
remove_subsystem("metarcontroller");
|
||||
delete subsys;
|
||||
|
||||
subsys = get_subsystem("controller");
|
||||
remove_subsystem("controller");
|
||||
delete subsys;
|
||||
|
||||
delete fgClouds;
|
||||
|
||||
remove_subsystem("controller");
|
||||
delete _controller;
|
||||
|
||||
delete _environment;
|
||||
}
|
||||
|
||||
|
@ -100,7 +97,6 @@ FGEnvironmentMgr::init ()
|
|||
{
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "Initializing environment subsystem");
|
||||
SGSubsystemGroup::init();
|
||||
//_update_fdm();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -108,191 +104,86 @@ FGEnvironmentMgr::reinit ()
|
|||
{
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "Reinitializing environment subsystem");
|
||||
SGSubsystemGroup::reinit();
|
||||
//_update_fdm();
|
||||
}
|
||||
|
||||
void
|
||||
FGEnvironmentMgr::bind ()
|
||||
{
|
||||
SGSubsystemGroup::bind();
|
||||
fgTie("/environment/visibility-m", _environment,
|
||||
&FGEnvironment::get_visibility_m, &FGEnvironment::set_visibility_m);
|
||||
fgSetArchivable("/environment/visibility-m");
|
||||
fgTie("/environment/effective-visibility-m", thesky,
|
||||
&SGSky::get_visibility );
|
||||
fgTie("/environment/temperature-sea-level-degc", _environment,
|
||||
&FGEnvironment::get_temperature_sea_level_degc,
|
||||
&FGEnvironment::set_temperature_sea_level_degc);
|
||||
fgSetArchivable("/environment/temperature-sea-level-degc");
|
||||
fgTie("/environment/temperature-degc", _environment,
|
||||
&FGEnvironment::get_temperature_degc); // FIXME: read-only for now
|
||||
fgTie("/environment/temperature-degf", _environment,
|
||||
&FGEnvironment::get_temperature_degf); // FIXME: read-only for now
|
||||
fgTie("/environment/dewpoint-sea-level-degc", _environment,
|
||||
&FGEnvironment::get_dewpoint_sea_level_degc,
|
||||
&FGEnvironment::set_dewpoint_sea_level_degc);
|
||||
fgSetArchivable("/environment/dewpoint-sea-level-degc");
|
||||
fgTie("/environment/dewpoint-degc", _environment,
|
||||
&FGEnvironment::get_dewpoint_degc); // FIXME: read-only for now
|
||||
fgTie("/environment/pressure-sea-level-inhg", _environment,
|
||||
&FGEnvironment::get_pressure_sea_level_inhg,
|
||||
&FGEnvironment::set_pressure_sea_level_inhg);
|
||||
fgSetArchivable("/environment/pressure-sea-level-inhg");
|
||||
fgTie("/environment/pressure-inhg", _environment,
|
||||
&FGEnvironment::get_pressure_inhg); // FIXME: read-only for now
|
||||
fgTie("/environment/density-slugft3", _environment,
|
||||
&FGEnvironment::get_density_slugft3); // read-only
|
||||
fgTie("/environment/relative-humidity", _environment,
|
||||
&FGEnvironment::get_relative_humidity); //ro
|
||||
fgTie("/environment/atmosphere/density-tropo-avg", _environment,
|
||||
&FGEnvironment::get_density_tropo_avg_kgm3); //ro
|
||||
fgTie("/environment/atmosphere/altitude-half-to-sun", _environment,
|
||||
&FGEnvironment::get_altitude_half_to_sun_m,
|
||||
&FGEnvironment::set_altitude_half_to_sun_m);
|
||||
fgTie("/environment/atmosphere/altitude-troposphere-top", _environment,
|
||||
&FGEnvironment::get_altitude_tropo_top_m,
|
||||
&FGEnvironment::set_altitude_tropo_top_m);
|
||||
fgTie("/environment/wind-from-heading-deg", _environment,
|
||||
&FGEnvironment::get_wind_from_heading_deg,
|
||||
&FGEnvironment::set_wind_from_heading_deg);
|
||||
fgTie("/environment/wind-speed-kt", _environment,
|
||||
&FGEnvironment::get_wind_speed_kt, &FGEnvironment::set_wind_speed_kt);
|
||||
fgTie("/environment/wind-from-north-fps", _environment,
|
||||
&FGEnvironment::get_wind_from_north_fps,
|
||||
&FGEnvironment::set_wind_from_north_fps);
|
||||
fgSetArchivable("/environment/wind-from-north-fps");
|
||||
fgTie("/environment/wind-from-east-fps", _environment,
|
||||
&FGEnvironment::get_wind_from_east_fps,
|
||||
&FGEnvironment::set_wind_from_east_fps);
|
||||
fgSetArchivable("/environment/wind-from-east-fps");
|
||||
fgTie("/environment/wind-from-down-fps", _environment,
|
||||
&FGEnvironment::get_wind_from_down_fps,
|
||||
&FGEnvironment::set_wind_from_down_fps);
|
||||
fgSetArchivable("/environment/wind-from-down-fps");
|
||||
|
||||
fgTie("/environment/thermal-lift-fps", _environment,
|
||||
&FGEnvironment::get_thermal_lift_fps,
|
||||
&FGEnvironment::set_thermal_lift_fps);
|
||||
fgSetArchivable("/environment/thermal-lift-fps");
|
||||
fgTie("/environment/ridge-lift-fps", _environment,
|
||||
&FGEnvironment::get_ridge_lift_fps,
|
||||
&FGEnvironment::set_ridge_lift_fps);
|
||||
fgSetArchivable("/environment/ridge-lift-fps");
|
||||
_environment->Tie( fgGetNode("/environment", true ) );
|
||||
|
||||
fgTie("/environment/local-weather-lift", _environment,
|
||||
&FGEnvironment::get_local_weather_lift_fps); //read-only
|
||||
|
||||
fgTie("/environment/turbulence/magnitude-norm", _environment,
|
||||
&FGEnvironment::get_turbulence_magnitude_norm,
|
||||
&FGEnvironment::set_turbulence_magnitude_norm);
|
||||
fgSetArchivable("/environment/turbulence/magnitude-norm");
|
||||
fgTie("/environment/turbulence/rate-hz", _environment,
|
||||
&FGEnvironment::get_turbulence_rate_hz,
|
||||
&FGEnvironment::set_turbulence_rate_hz);
|
||||
fgSetArchivable("/environment/turbulence/rate-hz");
|
||||
_tiedProperties.setRoot( fgGetNode( "/environment", true ) );
|
||||
|
||||
_tiedProperties.Tie( "effective-visibility-m", thesky,
|
||||
&SGSky::get_visibility );
|
||||
|
||||
_tiedProperties.Tie("rebuild-layers", fgClouds,
|
||||
&FGClouds::get_update_event,
|
||||
&FGClouds::set_update_event);
|
||||
|
||||
_tiedProperties.Tie("turbulence/use-cloud-turbulence", &sgEnviro,
|
||||
&SGEnviro::get_turbulence_enable_state,
|
||||
&SGEnviro::set_turbulence_enable_state);
|
||||
|
||||
for (int i = 0; i < MAX_CLOUD_LAYERS; i++) {
|
||||
char buf[128];
|
||||
sprintf(buf, "/environment/clouds/layer[%d]/span-m", i);
|
||||
fgTie(buf, this, i,
|
||||
SGPropertyNode_ptr layerNode = fgGetNode("/environment/clouds",true)->getChild("layer", i, true );
|
||||
|
||||
_tiedProperties.Tie( layerNode->getNode("span-m",true), this, i,
|
||||
&FGEnvironmentMgr::get_cloud_layer_span_m,
|
||||
&FGEnvironmentMgr::set_cloud_layer_span_m);
|
||||
fgSetArchivable(buf);
|
||||
sprintf(buf, "/environment/clouds/layer[%d]/elevation-ft", i);
|
||||
fgTie(buf, this, i,
|
||||
|
||||
_tiedProperties.Tie( layerNode->getNode("elevation-ft",true), this, i,
|
||||
&FGEnvironmentMgr::get_cloud_layer_elevation_ft,
|
||||
&FGEnvironmentMgr::set_cloud_layer_elevation_ft);
|
||||
fgSetArchivable(buf);
|
||||
sprintf(buf, "/environment/clouds/layer[%d]/thickness-ft", i);
|
||||
fgTie(buf, this, i,
|
||||
|
||||
_tiedProperties.Tie( layerNode->getNode("thickness-ft",true), this, i,
|
||||
&FGEnvironmentMgr::get_cloud_layer_thickness_ft,
|
||||
&FGEnvironmentMgr::set_cloud_layer_thickness_ft);
|
||||
fgSetArchivable(buf);
|
||||
sprintf(buf, "/environment/clouds/layer[%d]/transition-ft", i);
|
||||
fgTie(buf, this, i,
|
||||
|
||||
_tiedProperties.Tie( layerNode->getNode("transition-ft",true), this, i,
|
||||
&FGEnvironmentMgr::get_cloud_layer_transition_ft,
|
||||
&FGEnvironmentMgr::set_cloud_layer_transition_ft);
|
||||
fgSetArchivable(buf);
|
||||
sprintf(buf, "/environment/clouds/layer[%d]/coverage", i);
|
||||
fgTie(buf, this, i,
|
||||
|
||||
_tiedProperties.Tie( layerNode->getNode("coverage",true), this, i,
|
||||
&FGEnvironmentMgr::get_cloud_layer_coverage,
|
||||
&FGEnvironmentMgr::set_cloud_layer_coverage);
|
||||
fgSetArchivable(buf);
|
||||
|
||||
_tiedProperties.Tie( layerNode->getNode("coverage-type",true), this, i,
|
||||
&FGEnvironmentMgr::get_cloud_layer_coverage_type,
|
||||
&FGEnvironmentMgr::set_cloud_layer_coverage_type);
|
||||
|
||||
}
|
||||
|
||||
fgTie("/environment/metar/data", _metarcontroller,
|
||||
&FGMetarCtrl::get_metar, &FGMetarCtrl::set_metar );
|
||||
_tiedProperties.setRoot( fgGetNode("/sim/rendering", true ) );
|
||||
|
||||
fgTie("/sim/rendering/clouds3d-enable", fgClouds,
|
||||
_tiedProperties.Tie( "clouds3d-enable", fgClouds,
|
||||
&FGClouds::get_3dClouds,
|
||||
&FGClouds::set_3dClouds);
|
||||
fgTie("/sim/rendering/clouds3d-density", thesky,
|
||||
|
||||
_tiedProperties.Tie( "clouds3d-density", thesky,
|
||||
&SGSky::get_3dCloudDensity,
|
||||
&SGSky::set_3dCloudDensity);
|
||||
fgTie("/sim/rendering/clouds3d-vis-range", thesky,
|
||||
|
||||
_tiedProperties.Tie("clouds3d-vis-range", thesky,
|
||||
&SGSky::get_3dCloudVisRange,
|
||||
&SGSky::set_3dCloudVisRange);
|
||||
|
||||
fgTie("/sim/rendering/precipitation-enable", &sgEnviro,
|
||||
_tiedProperties.Tie("precipitation-enable", &sgEnviro,
|
||||
&SGEnviro::get_precipitation_enable_state,
|
||||
&SGEnviro::set_precipitation_enable_state);
|
||||
fgTie("/environment/rebuild-layers", fgClouds,
|
||||
&FGClouds::get_update_event,
|
||||
&FGClouds::set_update_event);
|
||||
fgTie("/sim/rendering/lightning-enable", &sgEnviro,
|
||||
|
||||
_tiedProperties.Tie("lightning-enable", &sgEnviro,
|
||||
&SGEnviro::get_lightning_enable_state,
|
||||
&SGEnviro::set_lightning_enable_state);
|
||||
fgTie("/environment/turbulence/use-cloud-turbulence", &sgEnviro,
|
||||
&SGEnviro::get_turbulence_enable_state,
|
||||
&SGEnviro::set_turbulence_enable_state);
|
||||
|
||||
sgEnviro.config(fgGetNode("/sim/rendering/precipitation"));
|
||||
}
|
||||
|
||||
void
|
||||
FGEnvironmentMgr::unbind ()
|
||||
{
|
||||
fgUntie("/environment/visibility-m");
|
||||
fgUntie("/environment/effective-visibility-m");
|
||||
fgUntie("/environment/temperature-sea-level-degc");
|
||||
fgUntie("/environment/temperature-degc");
|
||||
fgUntie("/environment/dewpoint-sea-level-degc");
|
||||
fgUntie("/environment/dewpoint-degc");
|
||||
fgUntie("/environment/pressure-sea-level-inhg");
|
||||
fgUntie("/environment/pressure-inhg");
|
||||
fgUntie("/environment/density-inhg");
|
||||
fgUntie("/environment/relative-humidity");
|
||||
fgUntie("/environment/atmosphere/density-tropo-avg");
|
||||
fgUntie("/environment/wind-from-north-fps");
|
||||
fgUntie("/environment/wind-from-east-fps");
|
||||
fgUntie("/environment/wind-from-down-fps");
|
||||
|
||||
fgUntie("/environment/thermal-lift-fps");
|
||||
fgUntie("/environment/ridge-lift-fps");
|
||||
fgUntie("/environment/local-weather-lift");
|
||||
|
||||
fgUntie("/environment/atmosphere/altitude-half-to-sun");
|
||||
fgUntie("/environment/atmosphere/altitude-troposphere-top");
|
||||
for (int i = 0; i < MAX_CLOUD_LAYERS; i++) {
|
||||
char buf[128];
|
||||
sprintf(buf, "/environment/clouds/layer[%d]/span-m", i);
|
||||
fgUntie(buf);
|
||||
sprintf(buf, "/environment/clouds/layer[%d]/elevation-ft", i);
|
||||
fgUntie(buf);
|
||||
sprintf(buf, "/environment/clouds/layer[%d]/thickness-ft", i);
|
||||
fgUntie(buf);
|
||||
sprintf(buf, "/environment/clouds/layer[%d]/transition-ft", i);
|
||||
fgUntie(buf);
|
||||
sprintf(buf, "/environment/clouds/layer[%d]/type", i);
|
||||
fgUntie(buf);
|
||||
}
|
||||
fgUntie("/sim/rendering/clouds3d-enable");
|
||||
fgUntie("/sim/rendering/clouds3d-vis-range");
|
||||
fgUntie("/sim/rendering/clouds3d-density");
|
||||
fgUntie("/sim/rendering/precipitation-enable");
|
||||
fgUntie("/environment/rebuild-layers");
|
||||
fgUntie("/environment/weather-scenario");
|
||||
fgUntie("/sim/rendering/lightning-enable");
|
||||
fgUntie("/environment/turbulence/use-cloud-turbulence");
|
||||
_tiedProperties.Untie();
|
||||
_environment->Untie();
|
||||
SGSubsystemGroup::unbind();
|
||||
}
|
||||
|
||||
|
@ -301,14 +192,14 @@ FGEnvironmentMgr::update (double dt)
|
|||
{
|
||||
SGSubsystemGroup::update(dt);
|
||||
|
||||
_environment->set_elevation_ft(fgGetDouble("/position/altitude-ft"));
|
||||
_environment->set_local_weather_lift_fps(fgGetDouble("/local-weather/current/thermal-lift"));
|
||||
osg::Vec3 windVec(_environment->get_wind_from_north_fps(),
|
||||
-_environment->get_wind_from_east_fps(),
|
||||
0);
|
||||
simgear::Particles::setWindVector(windVec * SG_FEET_TO_METER);
|
||||
//simgear::Particles::setWindFrom( _environment->get_wind_from_heading_deg(),
|
||||
// _environment->get_wind_speed_kt() );
|
||||
_environment->set_elevation_ft( _altitudeNode->getDoubleValue() );
|
||||
|
||||
simgear::Particles::setWindFrom( _environment->get_wind_from_heading_deg(),
|
||||
_environment->get_wind_speed_kt() );
|
||||
if( _cloudLayersDirty ) {
|
||||
_cloudLayersDirty = false;
|
||||
fgClouds->set_update_event( fgClouds->get_update_event()+1 );
|
||||
}
|
||||
}
|
||||
|
||||
FGEnvironment
|
||||
|
@ -320,9 +211,9 @@ FGEnvironmentMgr::getEnvironment () const
|
|||
FGEnvironment
|
||||
FGEnvironmentMgr::getEnvironment (double lat, double lon, double alt) const
|
||||
{
|
||||
// Always returns the same environment
|
||||
// for now; we'll make it interesting
|
||||
// later.
|
||||
// Always returns the same environment
|
||||
// for now; we'll make it interesting
|
||||
// later.
|
||||
FGEnvironment env = *_environment;
|
||||
env.set_elevation_ft(alt);
|
||||
return env;
|
||||
|
@ -404,48 +295,34 @@ FGEnvironmentMgr::set_cloud_layer_transition_ft (int index,
|
|||
const char *
|
||||
FGEnvironmentMgr::get_cloud_layer_coverage (int index) const
|
||||
{
|
||||
switch (thesky->get_cloud_layer(index)->getCoverage()) {
|
||||
case SGCloudLayer::SG_CLOUD_OVERCAST:
|
||||
return "overcast";
|
||||
case SGCloudLayer::SG_CLOUD_BROKEN:
|
||||
return "broken";
|
||||
case SGCloudLayer::SG_CLOUD_SCATTERED:
|
||||
return "scattered";
|
||||
case SGCloudLayer::SG_CLOUD_FEW:
|
||||
return "few";
|
||||
case SGCloudLayer::SG_CLOUD_CIRRUS:
|
||||
return "cirrus";
|
||||
case SGCloudLayer::SG_CLOUD_CLEAR:
|
||||
return "clear";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
return thesky->get_cloud_layer(index)->getCoverageString().c_str();
|
||||
}
|
||||
|
||||
void
|
||||
FGEnvironmentMgr::set_cloud_layer_coverage (int index,
|
||||
const char * coverage_name)
|
||||
{
|
||||
SGCloudLayer::Coverage coverage;
|
||||
if (!strcmp(coverage_name, "overcast"))
|
||||
coverage = SGCloudLayer::SG_CLOUD_OVERCAST;
|
||||
else if (!strcmp(coverage_name, "broken"))
|
||||
coverage = SGCloudLayer::SG_CLOUD_BROKEN;
|
||||
else if (!strcmp(coverage_name, "scattered"))
|
||||
coverage = SGCloudLayer::SG_CLOUD_SCATTERED;
|
||||
else if (!strcmp(coverage_name, "few"))
|
||||
coverage = SGCloudLayer::SG_CLOUD_FEW;
|
||||
else if (!strcmp(coverage_name, "cirrus"))
|
||||
coverage = SGCloudLayer::SG_CLOUD_CIRRUS;
|
||||
else if (!strcmp(coverage_name, "clear"))
|
||||
coverage = SGCloudLayer::SG_CLOUD_CLEAR;
|
||||
else {
|
||||
SG_LOG(SG_INPUT, SG_WARN, "Unknown cloud type " << coverage_name);
|
||||
coverage = SGCloudLayer::SG_CLOUD_CLEAR;
|
||||
}
|
||||
thesky->get_cloud_layer(index)->setCoverage(coverage);
|
||||
thesky->get_cloud_layer(index)->setCoverageString(coverage_name);
|
||||
_cloudLayersDirty = true;
|
||||
}
|
||||
|
||||
int
|
||||
FGEnvironmentMgr::get_cloud_layer_coverage_type (int index) const
|
||||
{
|
||||
return thesky->get_cloud_layer(index)->getCoverage();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FGEnvironmentMgr::set_cloud_layer_coverage_type (int index, int type )
|
||||
{
|
||||
if( index < 0 || index >= SGCloudLayer::SG_MAX_CLOUD_COVERAGES ) {
|
||||
SG_LOG(SG_ALL,SG_WARN,"Unknown cloud layer type " << type << " ignored" );
|
||||
return;
|
||||
}
|
||||
thesky->get_cloud_layer(index)->setCoverage(static_cast<SGCloudLayer::Coverage>(type));
|
||||
_cloudLayersDirty = true;
|
||||
}
|
||||
|
||||
|
||||
// end of environment-mgr.cxx
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef _ENVIRONMENT_MGR_HXX
|
||||
#define _ENVIRONMENT_MGR_HXX
|
||||
|
@ -26,6 +25,7 @@
|
|||
#include <simgear/compiler.h>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include "tiedpropertylist.hxx"
|
||||
|
||||
#ifdef SG_HAVE_STD_INCLUDES
|
||||
# include <cmath>
|
||||
|
@ -34,7 +34,6 @@
|
|||
#endif
|
||||
|
||||
class FGEnvironment;
|
||||
class FGEnvironmentCtrl;
|
||||
class FGMetarCtrl;
|
||||
class FGMetarFetcher;
|
||||
class FGClouds;
|
||||
|
@ -86,14 +85,14 @@ private:
|
|||
void set_cloud_layer_transition_ft (int index, double transition_ft);
|
||||
const char * get_cloud_layer_coverage (int index) const;
|
||||
void set_cloud_layer_coverage (int index, const char * coverage);
|
||||
int get_cloud_layer_coverage_type (int index) const;
|
||||
void set_cloud_layer_coverage_type (int index, int type );
|
||||
|
||||
FGEnvironment * _environment; // always the same, for now
|
||||
FGEnvironmentCtrl * _controller; // always the same, for now
|
||||
FGMetarCtrl * _metarcontroller;
|
||||
FGMetarFetcher * _metarfetcher;
|
||||
FGPrecipitationMgr* _precipitationManager;
|
||||
|
||||
FGClouds *fgClouds;
|
||||
SGPropertyNode_ptr _altitudeNode;
|
||||
bool _cloudLayersDirty;
|
||||
TiedPropertyList _tiedProperties;
|
||||
};
|
||||
|
||||
#endif // _ENVIRONMENT_MGR_HXX
|
||||
|
|
34
src/Environment/metarairportfilter.cxx
Normal file
34
src/Environment/metarairportfilter.cxx
Normal file
|
@ -0,0 +1,34 @@
|
|||
// metarairportfilter.cxx -- Implementation of AirportFilter
|
||||
//
|
||||
// Written by Torsten Dreyer, August 2010
|
||||
//
|
||||
// Copyright (C) 2010 Torsten Dreyer Torsten(at)t3r(dot)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 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "metarairportfilter.hxx"
|
||||
|
||||
namespace Environment {
|
||||
|
||||
MetarAirportFilter * MetarAirportFilter::_instance = NULL;
|
||||
|
||||
MetarAirportFilter * MetarAirportFilter::instance()
|
||||
{
|
||||
return _instance != NULL ? _instance :
|
||||
(_instance = new MetarAirportFilter());
|
||||
}
|
||||
|
||||
} // namespace Environment
|
52
src/Environment/metarairportfilter.hxx
Normal file
52
src/Environment/metarairportfilter.hxx
Normal file
|
@ -0,0 +1,52 @@
|
|||
// metarairportfilter.hxx -- Implementation of AirportFilter
|
||||
//
|
||||
// Written by Torsten Dreyer, August 2010
|
||||
//
|
||||
// Copyright (C) 2010 Torsten Dreyer Torsten(at)t3r(dot)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 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef __METARAIRPORTFILTER_HXX
|
||||
#define __METARAIRPORTFILTER_HXX
|
||||
|
||||
#include <Airports/simple.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include "tiedpropertylist.hxx"
|
||||
|
||||
namespace Environment {
|
||||
|
||||
/**
|
||||
* @brief A AirportFilter for selection airports that provide a METAR
|
||||
* Singleton implementation of FGAirport::AirportFilter
|
||||
*/
|
||||
class MetarAirportFilter : public FGAirport::AirportFilter {
|
||||
public:
|
||||
static MetarAirportFilter * instance();
|
||||
protected:
|
||||
MetarAirportFilter() {}
|
||||
virtual bool passAirport(FGAirport* aApt) const {
|
||||
return aApt->getMetar();
|
||||
}
|
||||
|
||||
// permit heliports and seaports too
|
||||
virtual FGPositioned::Type maxType() const
|
||||
{ return FGPositioned::SEAPORT; }
|
||||
private:
|
||||
static MetarAirportFilter * _instance;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
212
src/Environment/metarproperties.cxx
Normal file
212
src/Environment/metarproperties.cxx
Normal file
|
@ -0,0 +1,212 @@
|
|||
// metarproperties.cxx -- Parse a METAR and write properties
|
||||
//
|
||||
// Written by David Megginson, started May 2002.
|
||||
// Rewritten by Torsten Dreyer, August 2010
|
||||
//
|
||||
// Copyright (C) 2002 David Megginson - david@megginson.com
|
||||
//
|
||||
// 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "metarproperties.hxx"
|
||||
#include "fgmetar.hxx"
|
||||
#include "environment.hxx"
|
||||
#include "atmosphere.hxx"
|
||||
#include <simgear/scene/sky/cloud.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace Environment {
|
||||
|
||||
MetarProperties::MetarProperties( SGPropertyNode_ptr rootNode ) :
|
||||
_rootNode(rootNode),
|
||||
_metarValidNode( rootNode->getNode( "valid", true ) ),
|
||||
_station_elevation(0.0),
|
||||
_station_latitude(0.0),
|
||||
_station_longitude(0.0),
|
||||
_min_visibility(16000.0),
|
||||
_max_visibility(16000.0),
|
||||
_base_wind_dir(0),
|
||||
_base_wind_range_from(0),
|
||||
_base_wind_range_to(0),
|
||||
_wind_speed(0.0),
|
||||
_wind_from_north_fps(0.0),
|
||||
_wind_from_east_fps(0.0),
|
||||
_gusts(0.0),
|
||||
_temperature(0.0),
|
||||
_dewpoint(0.0),
|
||||
_humidity(0.0),
|
||||
_pressure(0.0),
|
||||
_sea_level_temperature(0.0),
|
||||
_sea_level_dewpoint(0.0),
|
||||
_sea_level_pressure(29.92),
|
||||
_rain(0.0),
|
||||
_hail(0.0),
|
||||
_snow(0.0),
|
||||
_snow_cover(false)
|
||||
{
|
||||
// don't tie metar-valid, so listeners get triggered
|
||||
_metarValidNode->setBoolValue( false );
|
||||
_tiedProperties.setRoot( _rootNode );
|
||||
_tiedProperties.Tie("data", this, &MetarProperties::get_metar, &MetarProperties::set_metar );
|
||||
_tiedProperties.Tie("station-id", this, &MetarProperties::get_station_id );
|
||||
_tiedProperties.Tie("station-elevation-ft", &_station_elevation );
|
||||
_tiedProperties.Tie("station-latitude-deg", &_station_latitude );
|
||||
_tiedProperties.Tie("station-longitude-deg", &_station_longitude );
|
||||
_tiedProperties.Tie("min-visibility-m", &_min_visibility );
|
||||
_tiedProperties.Tie("max-visibility-m", &_max_visibility );
|
||||
_tiedProperties.Tie("base-wind-range-from", &_base_wind_range_from );
|
||||
_tiedProperties.Tie("base-wind-range-to", &_base_wind_range_to );
|
||||
_tiedProperties.Tie("base-wind-speed-kt", &_wind_speed );
|
||||
_tiedProperties.Tie("base-wind-dir-deg", &_base_wind_dir );
|
||||
_tiedProperties.Tie("base-wind-from-north-fps", &_wind_from_north_fps );
|
||||
_tiedProperties.Tie("base-wind-from-east-fps", &_wind_from_east_fps );
|
||||
_tiedProperties.Tie("gust-wind-speed-kt", &_gusts );
|
||||
_tiedProperties.Tie("temperature-degc", &_temperature );
|
||||
_tiedProperties.Tie("dewpoint-degc", &_dewpoint );
|
||||
_tiedProperties.Tie("rel-humidity-norm", &_humidity );
|
||||
_tiedProperties.Tie("pressure-inhg", &_pressure );
|
||||
_tiedProperties.Tie("temperature-sea-level-degc", &_sea_level_temperature );
|
||||
_tiedProperties.Tie("dewpoint-sea-level-degc", &_sea_level_dewpoint );
|
||||
_tiedProperties.Tie("pressure-sea-level-inhg", &_sea_level_pressure );
|
||||
_tiedProperties.Tie("rain-norm", &_rain );
|
||||
_tiedProperties.Tie("hail-norm", &_hail );
|
||||
_tiedProperties.Tie("snow-norm", &_snow);
|
||||
_tiedProperties.Tie("snow-cover", &_snow_cover );
|
||||
}
|
||||
|
||||
MetarProperties::~MetarProperties()
|
||||
{
|
||||
}
|
||||
|
||||
static const string coverage_string[] = {
|
||||
SGCloudLayer::SG_CLOUD_CLEAR_STRING,
|
||||
SGCloudLayer::SG_CLOUD_FEW_STRING,
|
||||
SGCloudLayer::SG_CLOUD_SCATTERED_STRING,
|
||||
SGCloudLayer::SG_CLOUD_BROKEN_STRING,
|
||||
SGCloudLayer::SG_CLOUD_OVERCAST_STRING,
|
||||
};
|
||||
|
||||
static const double thickness_value[] = { 0, 65, 600, 750, 1000 };
|
||||
|
||||
void MetarProperties::set_metar( const char * metar )
|
||||
{
|
||||
_metar = metar;
|
||||
|
||||
SGSharedPtr<FGMetar> m;
|
||||
try {
|
||||
m = new FGMetar( _metar );
|
||||
}
|
||||
catch( sg_io_exception ) {
|
||||
SG_LOG( SG_GENERAL, SG_WARN, "Can't parse metar: " << _metar );
|
||||
_metarValidNode->setBoolValue(false);
|
||||
return;
|
||||
}
|
||||
|
||||
_min_visibility = m->getMinVisibility().getVisibility_m();
|
||||
_max_visibility = m->getMaxVisibility().getVisibility_m();
|
||||
|
||||
const SGMetarVisibility *dirvis = m->getDirVisibility();
|
||||
for ( int i = 0; i < 8; i++, dirvis++) {
|
||||
SGPropertyNode *vis = _rootNode->getChild("visibility", i, true);
|
||||
double v = dirvis->getVisibility_m();
|
||||
|
||||
vis->setDoubleValue("min-m", v);
|
||||
vis->setDoubleValue("max-m", v);
|
||||
}
|
||||
|
||||
_base_wind_dir = m->getWindDir();
|
||||
_base_wind_range_from = m->getWindRangeFrom();
|
||||
_base_wind_range_to = m->getWindRangeTo();
|
||||
_wind_speed = m->getWindSpeed_kt();
|
||||
|
||||
double speed_fps = _wind_speed * SG_NM_TO_METER * SG_METER_TO_FEET / 3600.0;
|
||||
_wind_from_north_fps = speed_fps * cos((double)_base_wind_dir * SGD_DEGREES_TO_RADIANS);
|
||||
_wind_from_east_fps = speed_fps * sin((double)_base_wind_dir * SGD_DEGREES_TO_RADIANS);
|
||||
_gusts = m->getGustSpeed_kt();
|
||||
_temperature = m->getTemperature_C();
|
||||
_dewpoint = m->getDewpoint_C();
|
||||
_humidity = m->getRelHumidity();
|
||||
_pressure = m->getPressure_inHg();
|
||||
|
||||
{
|
||||
// 1. check the id given in the metar
|
||||
FGAirport* a = FGAirport::findByIdent(m->getId());
|
||||
/*
|
||||
// 2. if unknown, find closest airport with metar to current position
|
||||
if( a == NULL ) {
|
||||
SGGeod pos = SGGeod::fromDeg(_longitude_n->getDoubleValue(), _latitude_n->getDoubleValue());
|
||||
a = FGAirport::findClosest(pos, 10000.0, &_airportWithMetarFilter);
|
||||
}
|
||||
*/
|
||||
// 3. otherwise use ground elevation
|
||||
if( a != NULL ) {
|
||||
_station_elevation = a->getElevation();
|
||||
const SGGeod & towerPosition = a->getTowerLocation();
|
||||
_station_latitude = towerPosition.getLatitudeDeg();
|
||||
_station_longitude = towerPosition.getLongitudeDeg();
|
||||
_station_id = a->ident();
|
||||
} else {
|
||||
_station_elevation = 0.0;
|
||||
_station_latitude = 0.0;
|
||||
_station_longitude = 0.0;
|
||||
_station_id = "XXXX";
|
||||
// station_elevation_ft = _ground_elevation_n->getDoubleValue() * SG_METER_TO_FEET;
|
||||
// _station_id = m->getId();
|
||||
}
|
||||
}
|
||||
|
||||
{ // calculate sea level temperature, dewpoint and pressure
|
||||
FGEnvironment dummy; // instantiate a dummy so we can leech a method
|
||||
dummy.set_elevation_ft( _station_elevation );
|
||||
dummy.set_temperature_degc( _temperature );
|
||||
dummy.set_dewpoint_degc( _dewpoint );
|
||||
_sea_level_temperature = dummy.get_temperature_sea_level_degc();
|
||||
_sea_level_dewpoint = dummy.get_dewpoint_sea_level_degc();
|
||||
|
||||
double elevation_m = _station_elevation * SG_FEET_TO_METER;
|
||||
double fieldPressure = FGAtmo::fieldPressure( elevation_m, _pressure * atmodel::inHg );
|
||||
_sea_level_pressure = P_layer(0, elevation_m, fieldPressure, _temperature + atmodel::freezing, atmodel::ISA::lam0) / atmodel::inHg;
|
||||
}
|
||||
|
||||
vector<SGMetarCloud> cv = m->getClouds();
|
||||
vector<SGMetarCloud>::const_iterator cloud, cloud_end = cv.end();
|
||||
|
||||
{
|
||||
static const char * LAYER = "layer";
|
||||
SGPropertyNode_ptr cloudsNode = _rootNode->getNode("clouds", true );
|
||||
const vector<SGMetarCloud> & metarClouds = m->getClouds();
|
||||
for( unsigned i = 0; i < 5; i++ ) {
|
||||
SGPropertyNode_ptr layerNode = cloudsNode->getChild(LAYER, i, true );
|
||||
int coverage = i < metarClouds.size() ? metarClouds[i].getCoverage() : 0;
|
||||
double elevation = i >= metarClouds.size() || coverage == 0 ? -9999.0 : metarClouds[i].getAltitude_ft() + _station_elevation;
|
||||
layerNode->setStringValue( "coverage", coverage_string[coverage] );
|
||||
layerNode->setDoubleValue( "coverage-type", SGCloudLayer::getCoverageType(coverage_string[coverage]) );
|
||||
layerNode->setDoubleValue( "elevation-ft", elevation );
|
||||
layerNode->setDoubleValue( "thickness-ft", thickness_value[coverage]);
|
||||
layerNode->setDoubleValue( "span-m", 40000 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_rain = m->getRain();
|
||||
_hail = m->getHail();
|
||||
_snow = m->getSnow();
|
||||
_snow_cover = m->getSnowCover();
|
||||
_metarValidNode->setBoolValue(true);
|
||||
}
|
||||
|
||||
} // namespace Environment
|
77
src/Environment/metarproperties.hxx
Normal file
77
src/Environment/metarproperties.hxx
Normal file
|
@ -0,0 +1,77 @@
|
|||
// metarproperties.hxx -- Parse a METAR and write properties
|
||||
//
|
||||
// Written by David Megginson, started May 2002.
|
||||
// Rewritten by Torsten Dreyer, August 2010
|
||||
//
|
||||
// Copyright (C) 2002 David Megginson - david@megginson.com
|
||||
//
|
||||
// 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef __METARPROPERTIES_HXX
|
||||
#define __METARPROPERTIES_HXX
|
||||
|
||||
#include <Airports/simple.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include "tiedpropertylist.hxx"
|
||||
|
||||
namespace Environment {
|
||||
|
||||
class MetarProperties : public SGReferenced
|
||||
{
|
||||
public:
|
||||
MetarProperties( SGPropertyNode_ptr rootNode );
|
||||
virtual ~MetarProperties();
|
||||
|
||||
SGPropertyNode_ptr get_root_node() const { return _rootNode; }
|
||||
|
||||
private:
|
||||
const char * get_metar() const { return _metar.c_str(); }
|
||||
void set_metar( const char * metar );
|
||||
const char * get_station_id() const { return _station_id.c_str(); }
|
||||
|
||||
SGPropertyNode_ptr _rootNode;
|
||||
SGPropertyNode_ptr _metarValidNode;
|
||||
std::string _metar;
|
||||
std::string _station_id;
|
||||
double _station_elevation;
|
||||
double _station_latitude;
|
||||
double _station_longitude;
|
||||
double _min_visibility;
|
||||
double _max_visibility;
|
||||
int _base_wind_dir;
|
||||
int _base_wind_range_from;
|
||||
int _base_wind_range_to;
|
||||
double _wind_speed;
|
||||
double _wind_from_north_fps;
|
||||
double _wind_from_east_fps;
|
||||
double _gusts;
|
||||
double _temperature;
|
||||
double _dewpoint;
|
||||
double _humidity;
|
||||
double _pressure;
|
||||
double _sea_level_temperature;
|
||||
double _sea_level_dewpoint;
|
||||
double _sea_level_pressure;
|
||||
double _rain;
|
||||
double _hail;
|
||||
double _snow;
|
||||
bool _snow_cover;
|
||||
|
||||
TiedPropertyList _tiedProperties;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
#endif // __METARPROPERTIES_HXX
|
301
src/Environment/realwx_ctrl.cxx
Normal file
301
src/Environment/realwx_ctrl.cxx
Normal file
|
@ -0,0 +1,301 @@
|
|||
// realwx_ctrl.cxx -- Process real weather data
|
||||
//
|
||||
// Written by David Megginson, started February 2002.
|
||||
// Rewritten by Torsten Dreyer, August 2010
|
||||
//
|
||||
// Copyright (C) 2002 David Megginson - david@megginson.com
|
||||
//
|
||||
// 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "realwx_ctrl.hxx"
|
||||
#include "tiedpropertylist.hxx"
|
||||
#include "metarproperties.hxx"
|
||||
#include "metarairportfilter.hxx"
|
||||
#include "fgmetar.hxx"
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <algorithm>
|
||||
#if defined(ENABLE_THREADS)
|
||||
#include <OpenThreads/Thread>
|
||||
#include <simgear/threads/SGQueue.hxx>
|
||||
#endif
|
||||
|
||||
|
||||
namespace Environment {
|
||||
|
||||
class BasicRealWxController : public RealWxController
|
||||
{
|
||||
public:
|
||||
BasicRealWxController( SGPropertyNode_ptr rootNode );
|
||||
virtual ~BasicRealWxController ();
|
||||
|
||||
virtual void init ();
|
||||
virtual void reinit ();
|
||||
|
||||
protected:
|
||||
void bind();
|
||||
void unbind();
|
||||
|
||||
SGPropertyNode_ptr _rootNode;
|
||||
SGPropertyNode_ptr _longitude_n;
|
||||
SGPropertyNode_ptr _latitude_n;
|
||||
SGPropertyNode_ptr _ground_elevation_n;
|
||||
|
||||
bool _enabled;
|
||||
TiedPropertyList _tiedProperties;
|
||||
MetarProperties _metarProperties;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------------- */
|
||||
/*
|
||||
Properties
|
||||
~/enabled: bool Enables/Disables the realwx controller
|
||||
~/metar[1..n]: string Target property path for metar data
|
||||
*/
|
||||
|
||||
BasicRealWxController::BasicRealWxController( SGPropertyNode_ptr rootNode ) :
|
||||
_rootNode(rootNode),
|
||||
_longitude_n( fgGetNode( "/position/longitude-deg", true )),
|
||||
_latitude_n( fgGetNode( "/position/latitude-deg", true )),
|
||||
_ground_elevation_n( fgGetNode( "/position/ground-elev-m", true )),
|
||||
_enabled(true),
|
||||
_metarProperties( fgGetNode( rootNode->getStringValue("metar", "/environment/metar"), true ) )
|
||||
{
|
||||
}
|
||||
|
||||
BasicRealWxController::~BasicRealWxController()
|
||||
{
|
||||
}
|
||||
|
||||
void BasicRealWxController::init()
|
||||
{
|
||||
update(0); // fetch data ASAP
|
||||
}
|
||||
|
||||
void BasicRealWxController::reinit()
|
||||
{
|
||||
}
|
||||
|
||||
void BasicRealWxController::bind()
|
||||
{
|
||||
_tiedProperties.setRoot( _rootNode );
|
||||
_tiedProperties.Tie( "enabled", &_enabled );
|
||||
}
|
||||
|
||||
void BasicRealWxController::unbind()
|
||||
{
|
||||
_tiedProperties.Untie();
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------------- */
|
||||
|
||||
class NoaaMetarRealWxController : public BasicRealWxController {
|
||||
public:
|
||||
NoaaMetarRealWxController( SGPropertyNode_ptr rootNode );
|
||||
virtual ~NoaaMetarRealWxController();
|
||||
virtual void update (double delta_time_sec);
|
||||
|
||||
class MetarLoadRequest {
|
||||
public:
|
||||
MetarLoadRequest( const string & stationId ) {
|
||||
_stationId = stationId;
|
||||
_proxyHost = fgGetNode("/sim/presets/proxy/host", true)->getStringValue();
|
||||
_proxyPort = fgGetNode("/sim/presets/proxy/port", true)->getStringValue();
|
||||
_proxyAuth = fgGetNode("/sim/presets/proxy/authentication", true)->getStringValue();
|
||||
}
|
||||
string _stationId;
|
||||
string _proxyHost;
|
||||
string _proxyPort;
|
||||
string _proxyAuth;
|
||||
private:
|
||||
};
|
||||
private:
|
||||
double _metarTimeToLive;
|
||||
double _positionTimeToLive;
|
||||
double _minimumRequestInterval;
|
||||
|
||||
SGPropertyNode_ptr _metarDataNode;
|
||||
SGPropertyNode_ptr _metarValidNode;
|
||||
SGPropertyNode_ptr _metarStationIdNode;
|
||||
|
||||
|
||||
#if defined(ENABLE_THREADS)
|
||||
class MetarLoadThread : public OpenThreads::Thread {
|
||||
public:
|
||||
MetarLoadThread( NoaaMetarRealWxController & controller );
|
||||
void requestMetar( const MetarLoadRequest & metarRequest );
|
||||
bool hasMetar() { return _responseQueue.size() > 0; }
|
||||
string getMetar() { return _responseQueue.pop(); }
|
||||
virtual void run();
|
||||
private:
|
||||
NoaaMetarRealWxController & _controller;
|
||||
SGBlockingQueue <MetarLoadRequest> _requestQueue;
|
||||
SGBlockingQueue <string> _responseQueue;
|
||||
};
|
||||
|
||||
MetarLoadThread * _metarLoadThread;
|
||||
#endif
|
||||
};
|
||||
|
||||
NoaaMetarRealWxController::NoaaMetarRealWxController( SGPropertyNode_ptr rootNode ) :
|
||||
BasicRealWxController(rootNode),
|
||||
_metarTimeToLive(0.0),
|
||||
_positionTimeToLive(0.0),
|
||||
_minimumRequestInterval(0.0),
|
||||
_metarDataNode(_metarProperties.get_root_node()->getNode("data",true)),
|
||||
_metarValidNode(_metarProperties.get_root_node()->getNode("valid",true)),
|
||||
_metarStationIdNode(_metarProperties.get_root_node()->getNode("station-id",true))
|
||||
{
|
||||
#if defined(ENABLE_THREADS)
|
||||
_metarLoadThread = new MetarLoadThread(*this);
|
||||
_metarLoadThread->start();
|
||||
#endif
|
||||
}
|
||||
|
||||
NoaaMetarRealWxController::~NoaaMetarRealWxController()
|
||||
{
|
||||
#if defined(ENABLE_THREADS)
|
||||
if( _metarLoadThread ) {
|
||||
MetarLoadRequest request("");
|
||||
_metarLoadThread->requestMetar(request);
|
||||
_metarLoadThread->join();
|
||||
delete _metarLoadThread;
|
||||
}
|
||||
#endif // ENABLE_THREADS
|
||||
}
|
||||
|
||||
void NoaaMetarRealWxController::update( double dt )
|
||||
{
|
||||
if( !_enabled )
|
||||
return;
|
||||
|
||||
if( _metarLoadThread->hasMetar() )
|
||||
_metarDataNode->setStringValue( _metarLoadThread->getMetar() );
|
||||
|
||||
_metarTimeToLive -= dt;
|
||||
_positionTimeToLive -= dt;
|
||||
_minimumRequestInterval -= dt;
|
||||
|
||||
bool valid = _metarValidNode->getBoolValue();
|
||||
string stationId = valid ? _metarStationIdNode->getStringValue() : "";
|
||||
|
||||
|
||||
if( _metarTimeToLive <= 0.0 ) {
|
||||
valid = false;
|
||||
_metarTimeToLive = 900;
|
||||
_positionTimeToLive = 0;
|
||||
}
|
||||
|
||||
if( _positionTimeToLive <= 0.0 || valid == false ) {
|
||||
_positionTimeToLive = 60.0;
|
||||
|
||||
SGGeod pos = SGGeod::fromDeg(_longitude_n->getDoubleValue(), _latitude_n->getDoubleValue());
|
||||
|
||||
FGAirport * nearestAirport = FGAirport::findClosest(pos, 10000.0, MetarAirportFilter::instance() );
|
||||
if( nearestAirport == NULL ) {
|
||||
SG_LOG(SG_ALL,SG_WARN,"RealWxController::update can't find airport with METAR within 10000NM" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( stationId != nearestAirport->ident() ) {
|
||||
valid = false;
|
||||
stationId = nearestAirport->ident();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( !valid ) {
|
||||
if( _minimumRequestInterval <= 0 && stationId.length() > 0 ) {
|
||||
MetarLoadRequest request( stationId );
|
||||
_metarLoadThread->requestMetar( request );
|
||||
_minimumRequestInterval = 10;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(ENABLE_THREADS)
|
||||
NoaaMetarRealWxController::MetarLoadThread::MetarLoadThread( NoaaMetarRealWxController & controller ) :
|
||||
_controller(controller)
|
||||
{
|
||||
}
|
||||
|
||||
void NoaaMetarRealWxController::MetarLoadThread::requestMetar( const MetarLoadRequest & metarRequest )
|
||||
{
|
||||
if( _requestQueue.size() > 10 ) {
|
||||
SG_LOG(SG_ALL,SG_ALERT,
|
||||
"NoaaMetarRealWxController::MetarLoadThread::requestMetar() more than 10 outstanding METAR requests, dropping "
|
||||
<< metarRequest._stationId );
|
||||
return;
|
||||
}
|
||||
|
||||
_requestQueue.push( metarRequest );
|
||||
}
|
||||
|
||||
void NoaaMetarRealWxController::MetarLoadThread::run()
|
||||
{
|
||||
for( ;; ) {
|
||||
const MetarLoadRequest request = _requestQueue.pop();
|
||||
|
||||
if( request._stationId.size() == 0 )
|
||||
break;
|
||||
|
||||
SGSharedPtr<FGMetar> result = NULL;
|
||||
|
||||
try {
|
||||
result = new FGMetar( request._stationId, request._proxyHost, request._proxyPort, request._proxyAuth );
|
||||
} catch (const sg_io_exception& e) {
|
||||
SG_LOG( SG_GENERAL, SG_WARN, "NoaaMetarRealWxController::fetchMetar(): can't get METAR for "
|
||||
<< request._stationId << ":" << e.getFormattedMessage().c_str() );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( result == NULL )
|
||||
continue;
|
||||
|
||||
string reply = result->getData();
|
||||
std::replace(reply.begin(), reply.end(), '\n', ' ');
|
||||
string metar = simgear::strutils::strip( reply );
|
||||
if( metar.length() > 0 )
|
||||
_responseQueue.push( metar );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------------- */
|
||||
|
||||
RealWxController * RealWxController::createInstance( SGPropertyNode_ptr rootNode )
|
||||
{
|
||||
// string dataSource = rootNode->getStringValue("data-source", "noaa" );
|
||||
// if( dataSource == "nwx" ) {
|
||||
// return new NwxMetarRealWxController( rootNode );
|
||||
// } else {
|
||||
return new NoaaMetarRealWxController( rootNode );
|
||||
// }
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------------- */
|
||||
|
||||
} // namespace Environment
|
36
src/Environment/realwx_ctrl.hxx
Normal file
36
src/Environment/realwx_ctrl.hxx
Normal file
|
@ -0,0 +1,36 @@
|
|||
// realwx_ctrl.cxx -- Process real weather data
|
||||
//
|
||||
// Written by David Megginson, started May 2002.
|
||||
// Rewritten by Torsten Dreyer, August 2010
|
||||
//
|
||||
// Copyright (C) 2002 David Megginson - david@megginson.com
|
||||
//
|
||||
// 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef _REALWX_CTRL_HXX
|
||||
#define _REALWX_CTRL_HXX
|
||||
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
namespace Environment {
|
||||
class RealWxController : public SGSubsystem
|
||||
{
|
||||
public:
|
||||
static RealWxController * createInstance( SGPropertyNode_ptr rootNode );
|
||||
};
|
||||
|
||||
} // namespace
|
||||
#endif // _REALWX_CTRL_HXX
|
|
@ -1294,8 +1294,8 @@ struct OptionDesc {
|
|||
{"enable-mouse-pointer", false, OPTION_STRING, "/sim/startup/mouse-pointer", false, "enabled", 0 },
|
||||
{"disable-random-objects", false, OPTION_BOOL, "/sim/rendering/random-objects", false, "", 0 },
|
||||
{"enable-random-objects", false, OPTION_BOOL, "/sim/rendering/random-objects", true, "", 0 },
|
||||
{"disable-real-weather-fetch", false, OPTION_BOOL, "/environment/params/real-world-weather-fetch", false, "", 0 },
|
||||
{"enable-real-weather-fetch", false, OPTION_BOOL, "/environment/params/real-world-weather-fetch", true, "", 0 },
|
||||
{"disable-real-weather-fetch", false, OPTION_BOOL, "/environment/realwx/enabled", false, "", 0 },
|
||||
{"enable-real-weather-fetch", false, OPTION_BOOL, "/environment/realwx/enabled", true, "", 0 },
|
||||
{"metar", true, OPTION_STRING, "/environment/metar/data", false, "", 0 },
|
||||
{"disable-ai-models", false, OPTION_BOOL, "/sim/ai/enabled", false, "", 0 },
|
||||
{"enable-ai-models", false, OPTION_BOOL, "/sim/ai/enabled", true, "", 0 },
|
||||
|
|
Loading…
Add table
Reference in a new issue