X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=sidebyside;f=src%2FEnvironment%2Fmetarproperties.cxx;h=aa67b355a7b8fa9bfadcfb6a08c8f6ff0322e8ba;hb=89b41395d861a49ad543af166c0bd41c14dd0d2b;hp=2f6cac2be2525b01809f289190645f89ce11a9d9;hpb=f8c7f95745ad83bc6ccd95e4a7b00e085633a931;p=flightgear.git diff --git a/src/Environment/metarproperties.cxx b/src/Environment/metarproperties.cxx index 2f6cac2be..aa67b355a 100644 --- a/src/Environment/metarproperties.cxx +++ b/src/Environment/metarproperties.cxx @@ -31,6 +31,9 @@ #include "metarairportfilter.hxx" #include #include +#include +#include +#include #include
using std::string; @@ -39,6 +42,72 @@ namespace Environment { static vector coverage_string; +/** + * @brief Helper class to wrap SGMagVar functionality and cache the variation and dip for + * a certain position. + */ +class MagneticVariation : public SGMagVar { +public: + /** + * Constructor + */ + MagneticVariation() : _lat(1), _lon(1), _alt(1) { + recalc( 0.0, 0.0, 0.0 ); + } + + /** + * @brief get the magnetic variation for a specific position at the current time + * @param lon the positions longitude in degrees + * @param lat the positions latitude in degrees + * @param alt the positions height above MSL (aka altitude) in feet + * @return the magnetic variation in degrees + */ + double get_variation_deg( double lon, double lat, double alt ); + + /** + * @brief get the magnetic dip for a specific position at the current time + * @param lon the positions longitude in degrees + * @param lat the positions latitude in degrees + * @param alt the positions height above MSL (aka altitude) in feet + * @return the magnetic dip in degrees + */ + double get_dip_deg( double lon, double lat, double alt ); +private: + void recalc( double lon, double lat, double alt ); + SGTime _time; + double _lat, _lon, _alt; +}; + +inline void MagneticVariation::recalc( double lon, double lat, double alt ) +{ + // calculation of magnetic variation is expensive. Cache the position + // and perform this calculation only if it has changed + if( _lon != lon || _lat != lat || _alt != alt ) { + SG_LOG(SG_ENVIRONMENT, SG_DEBUG, "Recalculating magvar for lon=" << lon << ", lat=" << lat << ", alt=" << alt ); + _lon = lon; + _lat = lat; + _alt = alt; + + lon *= SGD_DEGREES_TO_RADIANS; + lat *= SGD_DEGREES_TO_RADIANS; + alt *= SG_FEET_TO_METER; + _time.update( lon, lat, 0, 0 ); + update( lon, lat, alt, _time.getJD() ); + } +} + +inline double MagneticVariation::get_variation_deg( double lon, double lat, double alt ) +{ + recalc( lon, lat, alt ); + return get_magvar() * SGD_RADIANS_TO_DEGREES; +} + +inline double MagneticVariation::get_dip_deg( double lon, double lat, double alt ) +{ + recalc( lon, lat, alt ); + return get_magdip() * SGD_RADIANS_TO_DEGREES; +} + MetarProperties::MetarProperties( SGPropertyNode_ptr rootNode ) : _rootNode(rootNode), _metarValidNode( rootNode->getNode( "valid", true ) ), @@ -64,10 +133,11 @@ MetarProperties::MetarProperties( SGPropertyNode_ptr rootNode ) : _rain(0.0), _hail(0.0), _snow(0.0), - _snow_cover(false) + _snow_cover(false), + _magneticVariation(new MagneticVariation()) { // Hack to avoid static initialization order problems on OSX - if( coverage_string.size() == 0 ) { + if( coverage_string.empty() ) { coverage_string.push_back(SGCloudLayer::SG_CLOUD_CLEAR_STRING); coverage_string.push_back(SGCloudLayer::SG_CLOUD_FEW_STRING); coverage_string.push_back(SGCloudLayer::SG_CLOUD_SCATTERED_STRING); @@ -78,18 +148,20 @@ MetarProperties::MetarProperties( SGPropertyNode_ptr rootNode ) : _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-id", this, &MetarProperties::get_station_id, &MetarProperties::set_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("station-magnetic-variation-deg", this, &MetarProperties::get_magnetic_variation_deg ); + _tiedProperties.Tie("station-magnetic-dip-deg", this, &MetarProperties::get_magnetic_dip_deg ); _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("base-wind-speed-kt", this, &MetarProperties::get_wind_speed, &MetarProperties::set_wind_speed ); + _tiedProperties.Tie("base-wind-dir-deg", this, &MetarProperties::get_base_wind_dir, &MetarProperties::set_base_wind_dir ); + _tiedProperties.Tie("base-wind-from-north-fps", this, &MetarProperties::get_wind_from_north_fps, &MetarProperties::set_wind_from_north_fps ); + _tiedProperties.Tie("base-wind-from-east-fps",this, &MetarProperties::get_wind_from_east_fps, &MetarProperties::set_wind_from_east_fps ); _tiedProperties.Tie("gust-wind-speed-kt", &_gusts ); _tiedProperties.Tie("temperature-degc", &_temperature ); _tiedProperties.Tie("dewpoint-degc", &_dewpoint ); @@ -107,6 +179,7 @@ MetarProperties::MetarProperties( SGPropertyNode_ptr rootNode ) : MetarProperties::~MetarProperties() { + delete _magneticVariation; } @@ -121,14 +194,14 @@ void MetarProperties::set_metar( const char * metar ) m = new FGMetar( _metar ); } catch( sg_io_exception ) { - SG_LOG( SG_GENERAL, SG_WARN, "Can't parse metar: " << _metar ); + SG_LOG( SG_ENVIRONMENT, SG_WARN, "Can't parse metar: " << _metar ); _metarValidNode->setBoolValue(false); return; } _decoded.clear(); const vector weather = m->getWeather(); - for( vector::const_iterator it = weather.begin(); it != weather.end(); it++ ) { + for( vector::const_iterator it = weather.begin(); it != weather.end(); ++it ) { if( false == _decoded.empty() ) _decoded.append(", "); _decoded.append(*it); } @@ -145,14 +218,11 @@ void MetarProperties::set_metar( const char * metar ) vis->setDoubleValue("max-m", v); } - _base_wind_dir = m->getWindDir(); + set_base_wind_dir(m->getWindDir()); _base_wind_range_from = m->getWindRangeFrom(); _base_wind_range_to = m->getWindRangeTo(); - _wind_speed = m->getWindSpeed_kt(); + set_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(); @@ -231,9 +301,6 @@ void MetarProperties::set_metar( const char * metar ) } } - vector cv = m->getClouds(); - vector::const_iterator cloud, cloud_end = cv.end(); - { static const char * LAYER = "layer"; SGPropertyNode_ptr cloudsNode = _rootNode->getNode("clouds", true ); @@ -280,7 +347,7 @@ void MetarProperties::set_metar( const char * metar ) if( coverage != SGMetarCloud::COVERAGE_NIL ) { // if there is a layer above the fog, limit the top to one foot below that layer's bottom - if( metarClouds[0].getCoverage() != SGMetarCloud::COVERAGE_CLEAR ) + if( metarClouds.size() > 0 && metarClouds[0].getCoverage() != SGMetarCloud::COVERAGE_CLEAR ) thickness = metarClouds[0].getAltitude_ft() - LAYER_BOTTOM_STATION_OFFSET - 1; SGPropertyNode_ptr layerNode = cloudsNode->getChild(LAYER, 0, true ); @@ -304,6 +371,7 @@ void MetarProperties::set_metar( const char * metar ) -9999.0 : metarClouds[i].getAltitude_ft() + _station_elevation; + layerNode->setDoubleValue( "alpha", 1.0 ); layerNode->setStringValue( "coverage", coverage_string[coverage] ); layerNode->setDoubleValue( "coverage-type", SGCloudLayer::getCoverageType(coverage_string[coverage]) ); layerNode->setDoubleValue( "elevation-ft", elevation ); @@ -320,4 +388,58 @@ void MetarProperties::set_metar( const char * metar ) _metarValidNode->setBoolValue(true); } +void MetarProperties::setStationId( const std::string & value ) +{ + set_station_id(simgear::strutils::strip(value).c_str()); +} + +double MetarProperties::get_magnetic_variation_deg() const +{ + return _magneticVariation->get_variation_deg( _station_longitude, _station_latitude, _station_elevation ); +} + +double MetarProperties::get_magnetic_dip_deg() const +{ + return _magneticVariation->get_dip_deg( _station_longitude, _station_latitude, _station_elevation ); +} + +static inline void calc_wind_hs( double north_fps, double east_fps, int & heading_deg, double & speed_kt ) +{ + speed_kt = sqrt((north_fps)*(north_fps)+(east_fps)*(east_fps)) * 3600.0 / (SG_NM_TO_METER * SG_METER_TO_FEET); + heading_deg = SGMiscd::roundToInt( + SGMiscd::normalizeAngle2( atan2( east_fps, north_fps ) ) * SGD_RADIANS_TO_DEGREES ); +} + +void MetarProperties::set_wind_from_north_fps( double value ) +{ + _wind_from_north_fps = value; + calc_wind_hs( _wind_from_north_fps, _wind_from_east_fps, _base_wind_dir, _wind_speed ); +} + +void MetarProperties::set_wind_from_east_fps( double value ) +{ + _wind_from_east_fps = value; + calc_wind_hs( _wind_from_north_fps, _wind_from_east_fps, _base_wind_dir, _wind_speed ); +} + +static inline void calc_wind_ne( double heading_deg, double speed_kt, double & north_fps, double & east_fps ) +{ + double speed_fps = speed_kt * SG_NM_TO_METER * SG_METER_TO_FEET / 3600.0; + north_fps = speed_fps * cos(heading_deg * SGD_DEGREES_TO_RADIANS); + east_fps = speed_fps * sin(heading_deg * SGD_DEGREES_TO_RADIANS); +} + +void MetarProperties::set_base_wind_dir( double value ) +{ + _base_wind_dir = value; + calc_wind_ne( (double)_base_wind_dir, _wind_speed, _wind_from_north_fps, _wind_from_east_fps ); +} + +void MetarProperties::set_wind_speed( double value ) +{ + _wind_speed = value; + calc_wind_ne( (double)_base_wind_dir, _wind_speed, _wind_from_north_fps, _wind_from_east_fps ); +} + + } // namespace Environment