]> git.mxchange.org Git - flightgear.git/blobdiff - src/Environment/environment_ctrl.cxx
bugfix
[flightgear.git] / src / Environment / environment_ctrl.cxx
index b11dc450e938535ce89ab3880928252e1794bf60..0aa3572f6dca179ae109da33ddbe0ce45fc45490 100644 (file)
@@ -34,6 +34,7 @@
 #include <Main/fg_props.hxx>
 #include <Main/util.hxx>
 
+#include "atmosphere.hxx"
 #include "fgmetar.hxx"
 #include "environment_ctrl.hxx"
 
@@ -44,6 +45,10 @@ public:
        virtual bool passAirport(FGAirport* aApt) const {
                return aApt->getMetar();
        }
+  
+  // permit heliports and seaports too
+  virtual FGPositioned::Type maxType() const
+  { return FGPositioned::SEAPORT; }
 };
 
 static AirportWithMetar airportWithMetarFilter;
@@ -141,9 +146,9 @@ FGInterpolateEnvironmentCtrl::read_table (const SGPropertyNode * node, vector<bu
 {
        double last_altitude_ft = 0.0;
        double sort_required = false;
-       int i;
+       size_t i;
 
-       for (i = 0; i < node->nChildren(); i++) {
+       for (i = 0; i < (size_t)node->nChildren(); i++) {
                const SGPropertyNode * child = node->getChild(i);
                if ( strcmp(child->getName(), "entry") == 0
                 && child->getStringValue("elevation-ft", "")[0] != '\0'
@@ -264,8 +269,7 @@ FGInterpolateEnvironmentCtrl::bucket::lessThan(bucket *a, bucket *b)
 ////////////////////////////////////////////////////////////////////////
 
 FGMetarCtrl::FGMetarCtrl( SGSubsystem * environmentCtrl )
-       : _environmentCtrl(environmentCtrl),
-       station_elevation_ft(0.0),
+       :
        metar_valid(false),
        setup_winds_aloft(true),
        wind_interpolation_required(true),
@@ -277,7 +281,8 @@ FGMetarCtrl::FGMetarCtrl( SGSubsystem * environmentCtrl )
        MaxCloudAltitudeChangeFtSec( 20.0 ),
        MaxCloudThicknessChangeFtSec( 50.0 ),
        MaxCloudInterpolationHeightFt( 5000.0 ),
-       MaxCloudInterpolationDeltaFt( 4000.0 )
+       MaxCloudInterpolationDeltaFt( 4000.0 ),
+       _environmentCtrl(environmentCtrl)
 {
        windModulator = new FGBasicWindModulator();
 
@@ -433,6 +438,25 @@ static inline double convert_to_180( double d )
        return d > 180.0 ? d - 360.0 : d;
 }
 
+// Return the sea level pressure for a metar observation, in inHg.
+// This is different from QNH because it accounts for the current
+// temperature at the observation point.
+// metarPressure in inHg
+// fieldHt in ft
+// fieldTemp in C
+
+static double reducePressureSl(double metarPressure, double fieldHt,
+                               double fieldTemp)
+{
+    double elev = fieldHt * SG_FEET_TO_METER;
+    double fieldPressure
+        = FGAtmo::fieldPressure(elev, metarPressure * atmodel::inHg);
+    double slPressure = P_layer(0, elev, fieldPressure,
+                                fieldTemp + atmodel::freezing,
+                                atmodel::ISA::lam0);
+    return slPressure / atmodel::inHg;
+}
+
 void
 FGMetarCtrl::update(double dt)
 {
@@ -444,6 +468,7 @@ FGMetarCtrl::update(double dt)
 
        bool reinit_required = false;
        bool layer_rebuild_required = false;
+        double station_elevation_ft = station_elevation_n->getDoubleValue();
 
        if (first_update) {
                double dir = base_wind_dir_n->getDoubleValue()+magnetic_variation_n->getDoubleValue();
@@ -455,7 +480,10 @@ FGMetarCtrl::update(double dt)
                fgDefaultWeatherValue("visibility-m", metarvis);
 
                double metarpressure = pressure_n->getDoubleValue();
-               fgDefaultWeatherValue("pressure-sea-level-inhg", metarpressure);
+               fgDefaultWeatherValue("pressure-sea-level-inhg",
+                                      reducePressureSl(metarpressure,
+                                                       station_elevation_ft,
+                                                       temperature_n->getDoubleValue()));
 
                // We haven't already loaded a METAR, so apply it immediately.
                vector<SGPropertyNode_ptr> layers = clouds_n->getChildren("layer");
@@ -597,8 +625,11 @@ FGMetarCtrl::update(double dt)
 
                double pressure = boundary_sea_level_pressure_n->getDoubleValue();
                double metarpressure = pressure_n->getDoubleValue();
-               if( pressure != metarpressure ) {
-                       pressure = interpolate_val( pressure, metarpressure, MaxPressureChangeInHgSec );
+                double newpressure = reducePressureSl(metarpressure,
+                                                      station_elevation_ft,
+                                                      temperature_n->getDoubleValue());
+               if( pressure != newpressure ) {
+                       pressure = interpolate_val( pressure, newpressure, MaxPressureChangeInHgSec );
                        fgDefaultWeatherValue("pressure-sea-level-inhg", pressure);
                        reinit_required = true;
                }
@@ -666,9 +697,8 @@ FGMetarCtrl::update(double dt)
                        }
                }
        }
-
-       set_temp_at_altitude(temperature_n->getDoubleValue(), station_elevation_ft);
-       set_dewpoint_at_altitude(dewpoint_n->getDoubleValue(), station_elevation_ft);
+        set_temp_at_altitude(temperature_n->getDoubleValue(), station_elevation_ft);
+        set_dewpoint_at_altitude(dewpoint_n->getDoubleValue(), station_elevation_ft);
        //TODO: check if temperature/dewpoint have changed. This requires reinit.
 
        // Force an update of the 3D clouds
@@ -823,7 +853,7 @@ void MetarThread::run()
                        break;
                }
 
-                       metar_fetcher->fetch( airport_id );
+               metar_fetcher->fetch( airport_id );
        }
 }
 #endif
@@ -836,7 +866,8 @@ FGMetarFetcher::FGMetarFetcher() :
        search_timer(0.0),
        error_timer(0.0),
        _stale_count(0),
-       _error_count(0)
+       _error_count(0),
+       enabled(false)
 {
        longitude_n = fgGetNode( "/position/longitude-deg", true );
        latitude_n  = fgGetNode( "/position/latitude-deg", true );
@@ -874,6 +905,22 @@ void FGMetarFetcher::init ()
        _stale_count = 0;
        _error_count = 0;
        current_airport_id.clear();
+       /* Torsten Dreyer:
+          hack to stop startup.nas complaining if metar arrives after nasal-dir-initialized
+          is fired. Immediately fetch and wait for the METAR before continuing. This gets the
+          /environment/metar/xxx properties filled before nasal-dir is initialized.
+          Maybe the runway selection should happen here to make startup.nas obsolete?
+       */
+       const char * startup_airport = fgGetString("/sim/startup/options/airport");
+       if( *startup_airport ) {
+               FGAirport * a = FGAirport::getByIdent( startup_airport );
+               if( a ) {
+                       SGGeod pos = SGGeod::fromDeg(a->getLongitude(), a->getLatitude());
+                       a = FGAirport::findClosest(pos, 10000.0, &airportWithMetarFilter);
+                       current_airport_id = a->getId();
+                       fetch( current_airport_id );
+               }
+       }
 }
 
 void FGMetarFetcher::reinit ()
@@ -901,8 +948,19 @@ void FGMetarFetcher::update (double delta_time_sec)
                _error_count = 0;
        }
 
-       if( enable_n->getBoolValue() == false ) 
+       if( enable_n->getBoolValue() == false ) {
+               enabled = false;
                return;
+       }
+
+       // we were just enabled, reset all timers to 
+       // trigger immediate metar fetch
+       if( !enabled ) {
+               search_timer = 0.0;
+               fetch_timer = 0.0;
+               error_timer = error_timer_sec;
+               enabled = true;
+       }
 
        FGAirport * a = NULL;
 
@@ -933,6 +991,9 @@ void FGMetarFetcher::update (double delta_time_sec)
 
 void FGMetarFetcher::fetch( const string & id )
 {
+       if( enable_n->getBoolValue() == false ) 
+               return;
+
        SGSharedPtr<FGMetar> result = NULL;
 
        // fetch current metar data
@@ -954,11 +1015,16 @@ void FGMetarFetcher::fetch( const string & id )
                        }
                } else {
                        _stale_count = 0;
-                       }
+               }
 
        } catch (const sg_io_exception& e) {
                SG_LOG( SG_GENERAL, SG_WARN, "Error fetching live weather data: " << e.getFormattedMessage().c_str() );
                result = NULL;
+               // remove METAR flag from the airport
+               FGAirport * a = FGAirport::findByIdent( id );
+               if( a ) a->setMetar( false );
+               // immediately schedule a new search
+               search_timer = 0.0;
        }
 
        // write the metar to the property node, the rest is done by the methods tied to this property