- double dir_from;
- double dir_to;
- double speed;
- double gust;
- double vis;
- double pressure;
- double temp;
- double dewpoint;
-
- if (metar_loaded) {
- // 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 = fgGetDouble("/environment/metar/base-wind-speed-kt");
- double metar_heading = fgGetDouble("/environment/metar/base-wind-range-from");
-
- metar[0] = metar_speed * sin((metar_heading / 180.0) * M_PI);
- metar[1] = metar_speed * cos((metar_heading / 180.0) * M_PI);
-
- // Convert the current wind values and convert them into a vector
- double current[2];
- double current_speed =
- fgGetDouble("/environment/config/boundary/entry/wind-speed-kt");
- double current_heading = fgGetDouble(
- "/environment/config/boundary/entry/wind-from-heading-deg");
-
- current[0] = current_speed * sin((current_heading / 180.0) * M_PI);
- current[1] = current_speed * cos((current_heading / 180.0) * M_PI);
-
- // 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]);
- 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);
- current[1] = interpolate_val(current[1], metar[1], maxdy);
-
- // Now convert back to polar coordinates.
- if ((current[0] == 0.0) && (current[1] == 0.0)) {
- // Special case where there is no wind (otherwise atan2 barfs)
- speed = 0.0;
- dir_from = current_heading;
-
- } else {
- // 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]) * 180.0 / M_PI);
-
- // Normalize the direction.
- if (dir_from < 0.0)
- dir_from += 360.0;
-
- SG_LOG( SG_GENERAL, SG_DEBUG, "Wind : " << dir_from << "@" << speed);
- }
-
- // 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 currentvis =
- fgGetDouble("/environment/config/boundary/entry/visibility-m");
- double metarvis = fgGetDouble("/environment/metar/min-visibility-m");
- double currentxval = log(1000.0 + currentvis);
- double metarxval = log(1000.0 + metarvis);
-
- currentxval = interpolate_val(currentxval, metarxval, MaxVisChangePercentSec);
-
- // Now convert back from an X-value to a straightforward visibility.
- vis = exp(currentxval) - 1000.0;
-
- pressure = interpolate_prop(
- "/environment/config/boundary/entry/pressure-sea-level-inhg",
- "/environment/metar/pressure-inhg",
- MaxPressureChangeInHgSec);
-
- dir_to = fgGetDouble("/environment/metar/base-wind-range-to");
- gust = fgGetDouble("/environment/metar/gust-wind-speed-kt");
- temp = fgGetDouble("/environment/metar/temperature-degc");
- dewpoint = fgGetDouble("/environment/metar/dewpoint-degc");
-
- // Set the cloud layers by interpolating over the METAR versions.
- SGPropertyNode * clouds = fgGetNode("/environment/metar/clouds");
-
- vector<SGPropertyNode_ptr> layers = clouds->getChildren("layer");
- vector<SGPropertyNode_ptr>::const_iterator layer;
- vector<SGPropertyNode_ptr>::const_iterator layers_end = layers.end();
-
- const char *cl = "/environment/clouds/layer[%i]";
- double aircraft_alt = fgGetDouble("/position/altitude-ft");
- char s[128];
- int i;
-
- for (i = 0, layer = layers.begin(); layer != layers_end; ++layer, i++) {
- double currentval;
- double requiredval;
-
- // 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.
- snprintf(s, 128, cl, i);
- strncat(s, "/coverage", 128);
- const char* coverage = (*layer)->getStringValue("coverage", "clear");
- if (strncmp(fgGetString(s), coverage, 128) != 0)
- fgSetString(s, coverage);
-
- snprintf(s, 128, cl, i);
- strncat(s, "/elevation-ft", 128);
- double current_alt = fgGetDouble(s);
- double required_alt = (*layer)->getDoubleValue("elevation-ft");
-
- if (current_alt < -9000 || required_alt < -9000
- || fabs(aircraft_alt - required_alt) > MaxCloudInterpolationHeightFt) {
- // We don't interpolate any values that are too high above us,
- // or too far below us to be visible. Nor do we interpolate
- // values to or from -9999, which is used as a placeholder
- // when there isn't actually a cloud layer present.
- snprintf(s, 128, cl, i);
- strncat(s, "/elevation-ft", 128);
- if (current_alt != required_alt)
- fgSetDouble(s, required_alt);
-
- snprintf(s, 128, cl, i);
- strncat(s, "/thickness-ft", 128);
- if (fgGetDouble(s) != (*layer)->getDoubleValue("thickness-ft"))
- fgSetDouble(s, (*layer)->getDoubleValue("thickness-ft"));
-
- } else {
- // Interpolate the other values in the usual way
- if (current_alt != required_alt) {
- current_alt = interpolate_val(current_alt,
- required_alt,
- MaxCloudAltitudeChangeFtSec);
- fgSetDouble(s, current_alt);
- }
-
- snprintf(s, 128, cl, i);
- strncat(s, "/thickness-ft", 128);
- currentval = fgGetDouble(s);
- requiredval = (*layer)->getDoubleValue("thickness-ft");
-
- if (currentval != requiredval) {
- currentval = interpolate_val(currentval,
- requiredval,
- MaxCloudThicknessChangeFtSec);
- fgSetDouble(s, currentval);
- }
- }
- }
-
- } else {
- // We haven't already loaded a METAR, so apply it immediately.
- dir_from = fgGetDouble("/environment/metar/base-wind-range-from");
- dir_to = fgGetDouble("/environment/metar/base-wind-range-to");
- speed = fgGetDouble("/environment/metar/base-wind-speed-kt");
- gust = fgGetDouble("/environment/metar/gust-wind-speed-kt");
- vis = fgGetDouble("/environment/metar/min-visibility-m");
- pressure = fgGetDouble("/environment/metar/pressure-inhg");
- temp = fgGetDouble("/environment/metar/temperature-degc");
- dewpoint = fgGetDouble("/environment/metar/dewpoint-degc");
-
- // Set the cloud layers by copying over the METAR versions.
- SGPropertyNode * clouds = fgGetNode("/environment/metar/clouds");
-
- vector<SGPropertyNode_ptr> layers = clouds->getChildren("layer");
- vector<SGPropertyNode_ptr>::const_iterator layer;
- vector<SGPropertyNode_ptr>::const_iterator layers_end = layers.end();
-
- const char *cl = "/environment/clouds/layer[%i]";
- char s[128];
- int i;
-
- for (i = 0, layer = layers.begin(); layer != layers_end; ++layer, i++) {
- snprintf(s, 128, cl, i);
- strncat(s, "/coverage", 128);
- fgSetString(s, (*layer)->getStringValue("coverage", "clear"));
-
- snprintf(s, 128, cl, i);
- strncat(s, "/elevation-ft", 128);
- fgSetDouble(s, (*layer)->getDoubleValue("elevation-ft"));
-
- snprintf(s, 128, cl, i);
- strncat(s, "/thickness-ft", 128);
- fgSetDouble(s, (*layer)->getDoubleValue("thickness-ft"));
-
- snprintf(s, 128, cl, i);
- strncat(s, "/span-m", 128);
- fgSetDouble(s, 40000.0);
- }
- }
-
- fgSetupWind(dir_from, dir_to, speed, gust);
- fgDefaultWeatherValue("visibility-m", vis);
- set_temp_at_altitude(temp, station_elevation_ft);
- set_dewpoint_at_altitude(dewpoint, station_elevation_ft);
- fgDefaultWeatherValue("pressure-sea-level-inhg", pressure);
-
- // We've now successfully loaded a METAR into the configuration
- metar_loaded = true;
-}
-
-double FGMetarEnvironmentCtrl::interpolate_prop(const char * currentname,
- const char * requiredname,
- double dt)
-{
- double currentval = fgGetDouble(currentname);
- double requiredval = fgGetDouble(requiredname);
- return interpolate_val(currentval, requiredval, dt);