1
0
Fork 0

Merge branch 'next' of git://gitorious.org/fg/flightgear into next

This commit is contained in:
Frederic Bouvier 2010-09-11 22:14:07 +02:00
commit 121190e73a
17 changed files with 1319 additions and 1600 deletions

View file

@ -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>

View file

@ -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"

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View file

@ -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 },