- if (first_update) {
- double dir = base_wind_dir_n->getDoubleValue()+magnetic_variation_n->getDoubleValue();
- double speed = base_wind_speed_n->getDoubleValue();
- double gust = gust_wind_speed_n->getDoubleValue();
- setupWind(setup_winds_aloft, dir, speed, gust);
-
- double metarvis = min_visibility_n->getDoubleValue();
- fgDefaultWeatherValue("visibility-m", metarvis);
-
- set_temp_at_altitude(temperature_n->getDoubleValue(), station_elevation_ft);
- set_dewpoint_at_altitude(dewpoint_n->getDoubleValue(), station_elevation_ft);
-
- double metarpressure = pressure_n->getDoubleValue();
- 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");
- vector<SGPropertyNode_ptr>::const_iterator layer;
- vector<SGPropertyNode_ptr>::const_iterator layers_end = layers.end();
-
- int i;
- for (i = 0, layer = layers.begin(); layer != layers_end; ++layer, i++) {
- SGPropertyNode *target = environment_clouds_n->getChild("layer", i, true);
-
- target->setStringValue("coverage",
- (*layer)->getStringValue("coverage", "clear"));
- target->setDoubleValue("elevation-ft",
- (*layer)->getDoubleValue("elevation-ft"));
- target->setDoubleValue("thickness-ft",
- (*layer)->getDoubleValue("thickness-ft"));
- target->setDoubleValue("span-m", 40000.0);
- }
-
- first_update = false;
- reinit_required = true;
- layer_rebuild_required = true;
-
- } else {
- if( wind_interpolation_required ) {
- // Generate interpolated values between the METAR and the current
- // configuration.
-
- // Pick up the METAR wind values and convert them into a vector.
- double metar[2];
- double metar_speed = base_wind_speed_n->getDoubleValue();
- double metar_heading = base_wind_dir_n->getDoubleValue()+magnetic_variation_n->getDoubleValue();
-
- metar[0] = metar_speed * sin(metar_heading * SG_DEGREES_TO_RADIANS );
- metar[1] = metar_speed * cos(metar_heading * SG_DEGREES_TO_RADIANS);
-
- // Convert the current wind values and convert them into a vector
- double current[2];
- double speed = boundary_wind_speed_n->getDoubleValue();
- double dir_from = boundary_wind_from_heading_n->getDoubleValue();;
-
- current[0] = speed * sin(dir_from * SG_DEGREES_TO_RADIANS );
- current[1] = speed * cos(dir_from * SG_DEGREES_TO_RADIANS );
-
- // Determine the maximum component-wise value that the wind can change.
- // First we determine the fraction in the X and Y component, then
- // factor by the maximum wind change.
- double x = fabs(current[0] - metar[0]);
- double y = fabs(current[1] - metar[1]);
-
- // only interpolate if we have a difference
- if (x + y > 0.01 ) {
- double dx = x / (x + y);
- double dy = 1 - dx;
-
- double maxdx = dx * MaxWindChangeKtsSec;
- double maxdy = dy * MaxWindChangeKtsSec;
-
- // Interpolate each component separately.
- current[0] = interpolate_val(current[0], metar[0], maxdx*dt);
- current[1] = interpolate_val(current[1], metar[1], maxdy*dt);
-
- // Now convert back to polar coordinates.
- if ((fabs(current[0]) > 0.1) || (fabs(current[1]) > 0.1)) {
- // Some real wind to convert back from. Work out the speed
- // and direction value in degrees.
- speed = sqrt((current[0] * current[0]) + (current[1] * current[1]));
- dir_from = (atan2(current[0], current[1]) * SG_RADIANS_TO_DEGREES );
-
- // Normalize the direction.
- if (dir_from < 0.0)
- dir_from += 360.0;
-
- SG_LOG( SG_GENERAL, SG_DEBUG, "Wind : " << dir_from << "@" << speed);
- } else {
- // Special case where there is no wind (otherwise atan2 barfs)
- speed = 0.0;
- }
- double gust = gust_wind_speed_n->getDoubleValue();
- setupWind(setup_winds_aloft, dir_from, speed, gust);
- reinit_required = true;
- } else {
- wind_interpolation_required = false;
- }
- } else { // if(wind_interpolation_required)
- // interpolation of wind vector is finished, apply wind
- // variations and gusts for the boundary layer only
-
-
- bool wind_modulated = false;
-
- // start with the main wind direction
- double wind_dir = base_wind_dir_n->getDoubleValue()+magnetic_variation_n->getDoubleValue();
- double min = convert_to_180(base_wind_range_from_n->getDoubleValue()+magnetic_variation_n->getDoubleValue());
- double max = convert_to_180(base_wind_range_to_n->getDoubleValue()+magnetic_variation_n->getDoubleValue());
- if( max > min ) {
- // if variable winds configured, modulate the wind direction
- double f = windModulator->get_direction_offset_norm();
- wind_dir = min+(max-min)*f;
- double old = convert_to_180(boundary_wind_from_heading_n->getDoubleValue());
- wind_dir = convert_to_360(fgGetLowPass(old, wind_dir, dt ));
- wind_modulated = true;
- }
-
- // start with main wind speed
- double wind_speed = base_wind_speed_n->getDoubleValue();
- max = gust_wind_speed_n->getDoubleValue();
- if( max > wind_speed ) {
- // if gusts are configured, modulate wind magnitude
- double f = windModulator->get_magnitude_factor_norm();
- wind_speed = wind_speed+(max-wind_speed)*f;
- wind_speed = fgGetLowPass(boundary_wind_speed_n->getDoubleValue(), wind_speed, dt );
- wind_modulated = true;
- }
- if( wind_modulated ) {
- setupWind(false, wind_dir, wind_speed, max);
- reinit_required = true;
- }
- }
-
- // Now handle the visibility. We convert both visibility values
- // to X-values, then interpolate from there, then back to real values.
- // The length_scale is fixed to 1000m, so the visibility changes by
- // by MaxVisChangePercentSec or 1000m X MaxVisChangePercentSec,
- // whichever is more.
- double vis = boundary_visibility_n->getDoubleValue();;
- double metarvis = min_visibility_n->getDoubleValue();
- if( vis != metarvis ) {
- double currentxval = log(1000.0 + vis);
- double metarxval = log(1000.0 + metarvis);
-
- currentxval = interpolate_val(currentxval, metarxval, MaxVisChangePercentSec*dt);
-
- // Now convert back from an X-value to a straightforward visibility.
- vis = exp(currentxval) - 1000.0;
- fgDefaultWeatherValue("visibility-m", vis);
- reinit_required = true;
- }
-
- double pressure = boundary_sea_level_pressure_n->getDoubleValue();
- double metarpressure = pressure_n->getDoubleValue();
- double newpressure = reducePressureSl(metarpressure,
- station_elevation_ft,
- temperature_n->getDoubleValue());
- if( pressure != newpressure ) {
- pressure = interpolate_val( pressure, newpressure, MaxPressureChangeInHgSec*dt );
- fgDefaultWeatherValue("pressure-sea-level-inhg", pressure);
- reinit_required = true;
- }
-
- {
- double temperature = boundary_sea_level_temperature_n->getDoubleValue();
- double dewpoint = boundary_sea_level_dewpoint_n->getDoubleValue();
- if( metar_sealevel_temperature != temperature ) {
- temperature = interpolate_val( temperature, metar_sealevel_temperature, MaxTemperatureChangeDegcSec*dt );
- set_temp_at_altitude( temperature, 0.0 );
- }
- if( metar_sealevel_dewpoint != dewpoint ) {
- dewpoint = interpolate_val( dewpoint, metar_sealevel_dewpoint, MaxTemperatureChangeDegcSec*dt );
- set_dewpoint_at_altitude( dewpoint, 0.0 );
- }
- }
-
- // Set the cloud layers by interpolating over the METAR versions.
- vector<SGPropertyNode_ptr> layers = clouds_n->getChildren("layer");
- vector<SGPropertyNode_ptr>::const_iterator layer;
- vector<SGPropertyNode_ptr>::const_iterator layers_end = layers.end();
-
- double aircraft_alt = fgGetDouble("/position/altitude-ft");
- int i;
-
- for (i = 0, layer = layers.begin(); layer != layers_end; ++layer, i++) {
- SGPropertyNode *target = environment_clouds_n->getChild("layer", i, true);
-
- // In the case of clouds, we want to avoid writing if nothing has
- // changed, as these properties are tied to the renderer and will
- // cause the clouds to be updated, reseting the texture locations.
-
- // We don't interpolate the coverage values as no-matter how we
- // do it, it will be quite a sudden change of texture. Better to
- // have a single change than four or five.
- const char *coverage = (*layer)->getStringValue("coverage", "clear");
- SGPropertyNode *cov = target->getNode("coverage", true);
- if (strcmp(cov->getStringValue(), coverage) != 0) {
- cov->setStringValue(coverage);
- layer_rebuild_required = true;
- }
-
- double required_alt = (*layer)->getDoubleValue("elevation-ft");
- double current_alt = target->getDoubleValue("elevation-ft");
- double required_thickness = (*layer)->getDoubleValue("thickness-ft");
- SGPropertyNode *thickness = target->getNode("thickness-ft", true);
-
- if (current_alt < -9000 || required_alt < -9000 ||
- fabs(aircraft_alt - required_alt) > MaxCloudInterpolationHeightFt ||
- fabs(current_alt - required_alt) > MaxCloudInterpolationDeltaFt) {
- // We don't interpolate any layers that are
- // - too far above us to be visible
- // - too far below us to be visible
- // - with too large a difference to make interpolation sensible
- // - to or from -9999 (used as a placeholder)
- // - any values that are too high above us,
- if (current_alt != required_alt)
- target->setDoubleValue("elevation-ft", required_alt);
-
- if (thickness->getDoubleValue() != required_thickness)
- thickness->setDoubleValue(required_thickness);
-
- } else {
- // Interpolate the other values in the usual way
- if (current_alt != required_alt) {
- current_alt = interpolate_val(current_alt, required_alt, MaxCloudAltitudeChangeFtSec*dt);
- target->setDoubleValue("elevation-ft", current_alt);
- }
-
- double current_thickness = thickness->getDoubleValue();
-
- if (current_thickness != required_thickness) {
- current_thickness = interpolate_val(current_thickness,
- required_thickness,
- MaxCloudThicknessChangeFtSec*dt);
- thickness->setDoubleValue(current_thickness);
- }
- }
- }
- }
-
- // Force an update of the 3D clouds
- if( layer_rebuild_required )
- fgSetInt("/environment/rebuild-layers", 1 );
-
- // Reinitializing of the environment controller required
- if( reinit_required )
- _environmentCtrl->reinit();
-}
-
-const char * FGMetarCtrl::get_metar(void) const