Merge branch 'next' of git://gitorious.org/fg/flightgear into next
This commit is contained in:
commit
121190e73a
17 changed files with 1319 additions and 1600 deletions
|
@ -721,6 +721,10 @@
|
|||
<ClCompile Include="..\..\..\src\Environment\fgwind.cxx" />
|
||||
<ClCompile Include="..\..\..\src\Environment\precipitation_mgr.cxx" />
|
||||
<ClCompile Include="..\..\..\src\Environment\ridge_lift.cxx" />
|
||||
<ClCompile Include="..\..\..\src\Environment\realwx_ctrl.cxx" />
|
||||
<ClCompile Include="..\..\..\src\Environment\metarproperties.cxx" />
|
||||
<ClCompile Include="..\..\..\src\Environment\metarairportfilter.cxx" />
|
||||
<ClCompile Include="..\..\..\src\Environment\terrainsampler.cxx" />
|
||||
<ClCompile Include="..\..\..\src\Model\acmodel.cxx" />
|
||||
<ClCompile Include="..\..\..\src\Model\model_panel.cxx" />
|
||||
<ClCompile Include="..\..\..\src\Model\modelmgr.cxx" />
|
||||
|
@ -1289,6 +1293,10 @@
|
|||
<ClInclude Include="..\..\..\src\Environment\fgwind.hxx" />
|
||||
<ClInclude Include="..\..\..\src\Environment\precipitation_mgr.hxx" />
|
||||
<ClInclude Include="..\..\..\src\Environment\ridge_lift.hxx" />
|
||||
<ClCompile Include="..\..\..\src\Environment\realwx_ctrl.hxx" />
|
||||
<ClCompile Include="..\..\..\src\Environment\metarproperties.hxx" />
|
||||
<ClCompile Include="..\..\..\src\Environment\metarairportfilter.hxx" />
|
||||
<ClCompile Include="..\..\..\src\Environment\terrainsampler.hxx" />
|
||||
<ClInclude Include="..\..\..\src\Model\acmodel.hxx" />
|
||||
<ClInclude Include="..\..\..\src\Model\model_panel.hxx" />
|
||||
<ClInclude Include="..\..\..\src\Model\modelmgr.hxx" />
|
||||
|
@ -1423,4 +1431,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -4659,6 +4659,38 @@
|
|||
RelativePath="..\..\..\src\Environment\ridge_lift.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\realwx_ctrl.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\realwx_ctrl.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\metarproperties.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\metarproperties.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\metarairportfilter.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\metarairportfilter.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\terrainsampler.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Environment\terrainsampler.hxx"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Lib_Model"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -108,7 +108,7 @@ pair<double,double> PT_vs_hpt(
|
|||
}
|
||||
|
||||
// Should never get here.
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "PT_vs_hpt: ran out of layers");
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "PT_vs_hpt: ran out of layers for h=" << hh );
|
||||
return make_pair(d0, d0);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,41 @@ 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);
|
||||
if( thesky->get_cloud_layer(index)->getCoverageString() == coverage_name )
|
||||
return;
|
||||
|
||||
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( type < 0 || type >= SGCloudLayer::SG_MAX_CLOUD_COVERAGES ) {
|
||||
SG_LOG(SG_ALL,SG_WARN,"Unknown cloud layer type " << type << " ignored" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( static_cast<SGCloudLayer::Coverage>(type) == thesky->get_cloud_layer(index)->getCoverage() )
|
||||
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
|
||||
|
|
38
src/Environment/metarairportfilter.cxx
Normal file
38
src/Environment/metarairportfilter.cxx
Normal file
|
@ -0,0 +1,38 @@
|
|||
// 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.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#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
|
216
src/Environment/metarproperties.cxx
Normal file
216
src/Environment/metarproperties.cxx
Normal file
|
@ -0,0 +1,216 @@
|
|||
// 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.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#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