1
0
Fork 0

Merge branch 'master' of git://gitorious.org/fg/fgdata

This commit is contained in:
Erik Hofman 2010-09-10 16:09:25 +02:00
commit bd51740a3f
16 changed files with 1263 additions and 506 deletions

View file

@ -7,7 +7,7 @@
<body>
<h1>Local Weather Package - v0.8</h1>
<h1>Local Weather Package - v0.85</h1>
<h2>1. Introduction</h2>
@ -15,7 +15,7 @@ The aim of a local weather system is to simulate weather phenomena tied to speci
This is in contrast to the current (v.2.0.0) weather system of Flightgear where weather changes affect the weather everywhere in the simulated world and are (with few exceptions) not tied to specific locations. In such a system, it is impossible to observe e.g. the approach of a rainfront while flying in sunshine.<p>
The local weather package ultimately aims to provide the functionality to simulate such local phenomena. In version 0.8, the package supplies various cloud placement algorithms, as well as local control over most major weather parameters (wind, visibility, pressure, temperature, rain, snow, thermal lift, turbulence...) through interpolation routines and event volumes. The dynamics of the different systems is tied together - clouds and weather effects drift in the specified wind field. The package also contains a fairly detailed algorithm to generate convective clouds and thermals with a realistic distribution. Unfortunately, as of v0.8, there is no interaction yet between the windfield and the cloud-generating algorithms, i.e. while the placement algorithms create a realistic configuration of thermals and convective clouds, the wind will simply move this configuration, not create, destroy or move clouds in altitude dynamically (which would be realistic). <p>
The local weather package ultimately aims to provide the functionality to simulate such local phenomena. In version 0.85, the package supplies various cloud placement algorithms, as well as local control over most major weather parameters (wind, visibility, pressure, temperature, rain, snow, thermal lift, turbulence...) through interpolation routines and event volumes. The dynamics of the different systems is tied together - clouds and weather effects drift in the specified wind field. The package also contains a fairly detailed algorithm to generate convective clouds and thermals with a realistic distribution. Unfortunately, as of v0.85, there is no interaction yet between the windfield and the cloud-generating algorithms, i.e. while the placement algorithms create a realistic configuration of thermals and convective clouds, the wind will simply move this configuration, not create, destroy or move clouds in altitude dynamically (which would be realistic). <p>
For long-range flights, the system automatically provides transitions between different weather patterns like fronts and low and high pressure areas. However, basically all features currently present can and will eventually be improved.<p>
@ -24,7 +24,7 @@ For long-range flights, the system automatically provides transitions between di
The package needs to be unpacked in the Flightgear root directory. It writes content into the <i>Nasal/, gui/, gui/dialogs/, Shaders, Effects/, Docs/</i>, and <i>Models/Weather/</i> subdirectories. The installation does not overwrite any of the default Flightgear files, but to be accessible from the menu, one must copy <i>gui/menubar.xml.alt</i> to the default <i>menubar.xml</i> or copy the last two lines of the environemnt menu calling <i>local_weather</i> and <i>local_weather_tiles</i> into the default file.<p>
This adds the items <i>Local Weather</i> and <i>Local weather tiles</i> to the <i>Environment</i> menu when Flightgear is up. Most of the basic functionality is contained in <i>local_weather.nas</i> which is loaded at startup and identifies itself with a message, but does not start any functions unless called from the GUI.<p>
This adds the items <i>Local Weather</i>, <i>Local Weather Tiles</i> and <i>Local Weather Settings</i> to the <i>Environment</i> menu when Flightgear is up. Most of the basic functionality is contained in <i>local_weather.nas</i> which is loaded at startup and identifies itself with a message, but does not start any functions unless called from the GUI.<p>
<h2>3. Functionality</h2>
@ -80,8 +80,11 @@ The picture illustrates the result of a layer generation call for Nimbostratus c
<img src="clouds-nimbostratus.jpg">
</center><p>
<h3>Cloudbox</h3>
The cloudbox placement is an experimental routine allowing to define a cloud core, border and bottom region and to place different texture types into these regions. The underlying idea is that this would generate better Cumulus clouds from small texture bits. However, currently the Cumulus clouds are generated by multiple layers of whole cloud photographs, creating a more realistic impression. Thus, the cloudbox is not actively developed further.<p>
<h3>Tile placement</h3>
The second menu is used to place complete weather tiles based on low-level calls. It is intended for the user to automatically create the various weather patterns during flight. <p>
@ -90,7 +93,7 @@ The second menu is used to place complete weather tiles based on low-level calls
<img src="menu2.jpg">
</center><p>
The dropdown menu is used to select the type of weather tile to build. The menu contains two groups of tiles - the first are classified by airmass, whereas the last two are scenarios intended for soaring. <p>
Weather is created in a series of 40x40 km squares, called tiles. Tiles are classified by airmass, such that the sequence of tiles can describe for example the transition from a high pressure area to a low pressure area. The dropdown menu is used to select the type of weather tile to build initially. The menu contains two groups of tiles - the first are classified by airmass, whereas the last two are scenarios intended for soaring. <p>
Below are entries for three parameters. The first two are the simplified version of wind direction and speed for the user who is not interested in specifying many different wind interpolation points.
The third parameter, the altitude offset, is to manually adjust the altitude level of clouds in the absence of terrain presampling. Cloud layer placement calls are then specified for absolute altitudes and calibrated at sea level. As a result, layers are placed too low in mountainous terrain, hence the need for an offset. The offset may at present also be useful for dynamical weather, as convective clouds with terrain presampling follow terrain altitude, which looks strange when the clouds are allowed to drift in the wind without altitude correction. <p>
@ -108,7 +111,7 @@ Below the menu are five tickboxes. 'Terrain presampling' finds the distribution
The option 'dynamical weather' ties all clouds and weather effects to the windfield. If that option is not chosen, the wind is still generated according to the chosen model, but only felt by the aircraft. This makes e.g. soaring unrealistic, as the aircraft continuously drifts out of a static thermal below a static cap cloud. When 'dynamical weather' is selected, aircraft, cloud and thermal are all displaced by the wind.<p>
The slider 'Thermal properties' is only relevant for soaring scenarios. It governs the rato of maximum lift to radius of a thermal. A setting close to 'low convection' creates large thermals with relatively small lift and virtually no turbulence, a setting close to 'rough day' creates very narrow, turbulent thermals with large lift. Unless thermals are placed, no other weather tile is affected by the settings.<p>
The slider 'Thermal properties' is mainly relevant for soaring scenarios. It governs the rato of maximum lift to radius of a thermal. A setting close to 'low convection' creates large thermals with relatively small lift and virtually no turbulence, a setting close to 'rough day' creates very narrow, turbulent thermals with large lift. However, it also affects the Cumulus textures to be used. 'low convection' creates well-formed, smooth Cumuli whereas 'rough day' biases the texture selection towards more rugged and diffuse clouds.<p>
The button 'Show winds' brings up the detailed wind menu which is needed for the wind models 'aloft interpolated' and 'aloft waypoints':<p>
@ -132,9 +135,32 @@ The following pictures show the results of tile setups 'Low-pressure-border' and
<img src="clouds-lpb01.jpg">
</center><p>
<h3>Performance settings</h3>
The performance setting menu is available from the main menubar. It controls the allocation of system resources to the various tasks.<p>
<center>
<img src="menu4.jpg">
</center><p>
The first part controls the creation of new weather tiles, the second part controls the ranges up to which clouds inside a generated weather tile are shown as part of the scenery (clouds created but not shown are stored and processed in a buffer array). Clouds are visible if and only if they are 1) part of a created tile and 2) closer than the buffering range. This is illustrated in the following figure: Tiles are only created if their center is within range, clouds are only visible if the cloud model itself is within range, the resulting region dependent on the two ranges in which clouds are displayed is shown in red.<p>
<center>
<img src="tiles.gif">
</center><p>
From this, it is apparent that the two ranges should not be drastically different. Setting tile creation range to 55 km implies lots of work trying to asses the properties of faraway terrain to generate suitable cloud distributions, setting the buffering range to 15 km means that most of these clouds are never visible. Note that in low visibility, a large tile creation range can be problematic, as Flightgear may not have loaded the terrain. Note also that setting the tile creation range above 40 km means a slow startup of the system, as it needs to create 5 tiles on startup instead of just a single one.<p>
There are additional options to do asymmetric buffering, i.e. to 'cut' out a wedge in the rear of the aircraft in which the tile creation radius or the cloud visibility radius are lower. For example, setting the buffering ratio to 0.2 and the angle to 180 degrees corresponds to a very agressive buffering in which clouds in the rear hemisphere of the aircraft are almost absent and shown only to 20% of the set distance. This may increase performance by 20-30%, but only in straight flight - in fast turns, lots of clouds have to be shuffled from the buffer into the scenery and back, which is actually slower than never trying to cut a wedge at all. Also, agressive asymmetric buffering is not nice in external views as the reference is always the aircraft course.<p>
The last option controls the amout of resources allocated to making clouds drift in the wind if dynamical weather is on. In order to avoid freezes, the weather dynamics system processes only a fixed number of clouds per frame inside the field of view. That means that faraway clouds do not necessarily move even with dynamical weather on. The slider indirectly controls the distance out to which clouds are being processed.<p>
All performance setting menu-options work at runtime, but are processed over time rather than instantaneously, i.e. it takes 10-20 seconds till the new balance between buffered clouds and active clouds is reached after the slider is moved.<p>
<h2>4. Cloud models</h2>
The package contains a number of different cloud models, both static ones for Cirrus and Cirrocumulus clouds as well as rotated ones for Altocumulus, Cirrostratus, Cumulus, Cumulonimbus, Stratus and Nimbostratus cloudlet models. Neither the cloud textures, nor the models nor the transformations are perfected, and any aspect can be improved. Currently the standard clouds cannot quite reach the sophistication of the shader-based standard 3-d clouds of Flightgear, but the detailed Cumulus clouds are on the verge of catching up. <p>
The package contains a number of different cloud models, both static ones for Cirrus and Cirrocumulus clouds as well as rotated ones for Altocumulus, Cirrostratus, Cumulus, Cumulonimbus, Stratus and Nimbostratus cloudlet models. Neither the cloud textures, nor the models nor the transformations are perfected, and any aspect can be improved.<p>
<center>
<img src="clouds-detailed01.jpg">
@ -186,7 +212,7 @@ Effect volumes are always specified between a minimum and a maximum altitude, an
where <i>geometry</i> is a flag (1: circular, 2: elliptical and 3: rectangular), <i>lat</i> and <i>lon</i> are the latitude and longitude, <i>r1</i> and <i>r2</i> are the two size parameters for the elliptic or rectangular shape (for the circular shape, only the first is used), <i>phi</i> is the rotation angle of the shape (not used for circular shape), <i>alt_low</i> and <i>alt_high</i> are the altitude boundaries, <i>vis, rain, snow, turb</i> and <i>lift</i> are weather parameters which are either set to the value they should assume, or to -1 if they are not to be used, or to -2 if a function instead of a parameter is to be used. Since thermal lift can be set to negative values in a sink, a separate flag is provided in this case.<p>
In version 0.8, thermal lift is implemented by function. There is no easy way to implement any weather parameter by function in an effect volume, as this requires some amount of Nasal coding.
In version 0.85, thermal lift is implemented by function. There is no easy way to implement any weather parameter by function in an effect volume, as this requires some amount of Nasal coding.
<h2>6. Wind models and dynamical weather</h2>
@ -243,19 +269,18 @@ To make your own tile visible, an entry in the menu <i>gui/dialogs/local_weather
<h2>9. Performance tuning</h2>
With default settings, the local weather package generates a 40x40 km weather tile when the aircraft is closer than 35 km to the tile center and unloads it when the aircraft is more than 37 km away. This means that the system can generate at most 4 tiles at once and clouds are visible for at least 15 km and up to 30 km (the latter number determined by fading in the shaders). However, rendering and managing multiple overcast cloud layers in a region of 80x80 km is a significant drain on performance. For older systems, a few things can be tried:<p>
With default settings, the local weather package generates a 40x40 km weather tile when the aircraft is closer than 39 km to the tile center and unloads it when the aircraft is more than 39.5 km away. This means that the system can generate at most 4 tiles at once and clouds are visible for at least 19 km and up to 45 km (the latter number determined by fading in the shaders). However, rendering and managing multiple overcast cloud layers in a region of 80x80 km is a significant drain on performance. For older systems, a few things can be done:<p>
<ul>
<li> the menu option 'asymmetric range' decreases loading and unloading ranges in a 45 degree sector behind the aircraft. This means that in straight flight, less tiles will be loaded at the same time, as tiles in the rear are unloaded more quickly. The option is currently experimental.<p>
<li> the menu option 'asymmetric range' decreases loading and unloading ranges in a 90 degree sector behind the aircraft. This means that in straight flight, less tiles will be loaded at the same time, as tiles in the rear are unloaded more quickly. <p>
<li> a further reduction in the amount of simultaneously generated tiles can be achieved by changing the ranges. These are exposed in the property tree as <i>local-weather/config/distance-to-load-tile-m</i> and <i>local-weather/config/distance-to-remove-tile-m</i>. Note that the removal range <b>must</b> be larger than the loading range - otherwise just generated tiles will be immediately unloaded! Ranges below 20 km will guarantee that only one tile is loaded at a time, but will create empty spots when no tile is loaded. A range above 28 km will guarantee that the aircraft never flies in an empty tile, but empty sky in front will be visible. Finally, ranges above 56 km guarantee that all 9 tiles (a region of 120x120 km) are managed at all times - but will most likely cause a severe drop in framerate for most scenarios.<p>
<li> a further reduction in the amount of simultaneously generated tiles can be achieved by changing the range for tile loading and unloading in the menu. Ranges below 20 km will guarantee that only one tile is loaded at a time, but will create empty spots when no tile is loaded. A range above 28 km will guarantee that the aircraft never flies in an empty tile, but empty sky in front will be visible. Finally, ranges above 56 km would guarantee that all 9 tiles (a region of 120x120 km) are managed at all times - but will most likely cause a severe drop in framerate for most scenarios and is currently not possible from the menu.<p>
<li> a further reduction in workload can be achieved by lowering the visibility range of clouds in the menu. This helps significantly, as clouds in the buffer array do not take significant processing power. Note that this can be done at runtime. Agressive buffering of the rear hemisphere can gain another 20-30% performance, but is only suitable for flying a straight course.<p>
<li> if this does not help, try avoiding scenarios with large cloud count. As a rule, low pressure areas have high cloud count, high pressure areas have a low cloud count. Do not use 'detailed clouds', which tend to generate large cloud counts.<p>
<li> a drastic solution is to set the visual ranges lower. Currently, cloud models are set to be visible up to 30 km. Changing the visibility range in the range animation of all cloud model xml wrappers will improve performance accordingly. To achieve a nice fading into the background instead of a sudden disappearance, it is recommended to adjust the visibility range in the shaders accordingly. It would probably be good to expose the visual range as a property, but currently it's not yet done, as passing a property to the shader requires Flightgear CVS and cannot be done in 2.0.0.
Performance for overcast layers currently is a limiting issue and there are a few ideas around how to improve it - dependent if these work or not, future releases may work better.<p>
<li> a different issue is a characteristic small pause every second. This is caused by the interpolation loop resetting the weather parameters. Currently, a computationally expensive workaround is needed to do so, causing the problem. Work on a better environment controller is on the way, however until that modification to the core Flightgear code is implemented, the best solution is to set the loop time in <i>Nasal/local-weather.nas</i> to a larger value. <p>
<li> dynamical weather uses a lot of performance. If framerate is low and you don't need it, don't use it! From fast planes, cloud drift is almost impossible to see against the relative motion of cloud and airplane anyway.<p>
@ -278,7 +303,9 @@ Performance for overcast layers currently is a limiting issue and there are a fe
<li> For dynamical weather, clouds sometimes appear to 'jump' to a position. The reason is that the control loop of cloud drift accepts for performance reasons only a limited number of clouds. If there are more in the field of view, the most distant clouds are not processed. As nearby clouds drift out of the visual field, more distant clouds move into the loop, at which point their position is suddenly updated, resulting in a jump. Short of committing potentially vast computational resources (if there is a large number of clouds in the visual field), there is no easy fix to the problem.<p>
<li> To smooth out changes in wind settings, rather than producing a sudden gust, the wind is changed over about 1 second. In sharp wind gradients, this produces a series of ripples like turbulence. This is actually a realistic behaviour in this situation and hence left as it is. Some systems seem to take an unreasonable effort to reinit the environment (as must be done to set wind) - here the function call <i>setWindSmoothly()</i> in <i>local_weather.nas</i> should perhaps be replace by <i>setWind</i> to ease the load.
<li> To smooth out changes in wind settings, rather than producing a sudden gust, the wind is changed over about 1 second. In sharp wind gradients, this produces a series of ripples like turbulence. This is actually a realistic behaviour in this situation and hence left as it is. Some systems seem to take an unreasonable effort to reinit the environment (as must be done to set wind) - here the function call <i>setWindSmoothly()</i> in <i>local_weather.nas</i> should perhaps be replace by <i>setWind</i> to ease the load.<p>
<li> Large tile creation distances can cause problems in low visibility weather, because Flightgear loads terrain only if it is within visual range. Thus, trying to sample the terrain for a tile 55 km away in 8 km visibility doesn't work because the terrain elevation and altitude is not known. This may cause improper placement of clouds - chiefly convective clouds, but also layered clouds may not appear on the proper altitude. Currently, there is a limit which restricts tile loading range to 3 times the visibility, but presumably a better solution can be found.<p>
<li> The thermals in the soaring scenarios need GIT to work.<p>
</ul>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 77 KiB

BIN
Docs/menu4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
Docs/tiles.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

View file

@ -26,6 +26,117 @@
# get_elevation_vector to get terrain elevation at given coordinate vector
# This file contains portability wrappers for the local weather system:
# http://wiki.flightgear.org/index.php/A_local_weather_system
#
# This module is intended to provide a certain degree of backward compatibility for past
# FlightGear releases, while sketching out the low level APIs used and required by the
# local weather system, as these
# are being added to FlightGear.
#
# This file contains various workarounds for doing things that are currently not yet directly
# supported by the core FlightGear/Nasal APIs (fgfs 2.0).
#
# Some of these workarounds are purely implemented in Nasal space, and may thus not provide sufficient
# performance in some situations.
#
# The goal is to move all such workarounds eventually into this module, so that the high level weather modules
# only refer to this "compatibility layer" (using an "ideal API"), while this module handles
# implementation details
# and differences among different versions of FlightGear, so that key APIs can be ported to C++ space
# for the sake
# of improving runtime performance and efficiency.
#
# This provides an abstraction layer that isolates the rest of the local weather system from low
# level implementation details.
#
# C++ developers who want to help improve the local weather system (or the FlightGear/Nasal
# interface in general) should
# check out this file (as well as the wiki page) for APIs or features that shall eventually be
# re/implemented in C++ space for
# improving the local weather system.
#
#
# This module provides a handful of helpers for dynamically querying the Nasal API of the running fgfs binary,
# so that it can make use of new APIs (where available), while still working with older fgfs versions.
#
# Note: The point of these helpers is that they should really only be used
# by this module, and not in other parts/files of the
# local weather system. Any hard coded special cases should be moved into this module.
#
# The compatibility layer is currently work in progress and will be extended as new Nasal
# APIs are being added to FlightGear.
###########################################
# header checking availability of functions
###########################################
var has_symbol = func(s) contains(globals,s);
var is_function = func(s) typeof(globals[s])=='func';
var has_function = func(f) has_symbol(f) and is_function(f);
# try to call a function with given parameters
# save exceptions to err vector
# returns 0 for no exceptions (exceptions vector is empty)
# returns >=1 for exception occurred (i.e. unsupported API call)
var try_call = func(f, params) {
var err=[];
call(globals[f], params, nil,nil,err); # see http://plausible.org/nasal/lib.html
return size(err);
};
var query = func(api,params) {
if ( has_function(api) ) {
return try_call(api, params );
}
return 1; # fail
}
var patches = { geodinfo: "http://flightgear.org/forums/viewtopic.php?f=5&t=7358&st=0&sk=t&sd=a&start=90#p82805", };
# query fgfs binary for required APIs and set values in this hash
var features = {};
#fixme: compare results from new and old API
var check_geodinfo_vec = func {
var err=[];
if ( query('geodinfo',[ [37.618,-122.374],1000])==0 ) {
printf("geodinfo found"); # now try to use it
var ksfo=[37.618, -122.374];
var alt=10000;
# see if it returns a vector or not
call( func { print (alt); (typeof(geodinfo(ksfo,alt))=='vector')?return:die(); }, [], caller()[0],nil,err);
print('-','geodinfo:', (size(err) >=1) ? "Vector support unavailable" : "Vector support available");
if(size(err) and contains(patches,'geodinfo')) print('---> A patch is available at ', patches['geodinfo']);
return size(err)?0:1;
}
return 0;
}
_setlistener("/sim/signals/nasal-dir-initialized", func {
print ("Compatibility layer: Checking available Nasal APIs:");
print ("(this may cause harmless error messages when hard-coded support is lacking)");
print ("##########################################");
features.geodinfo_supports_vectors= check_geodinfo_vec ();
print("features.geodinfo_supports_vectors=", features.geodinfo_supports_vectors);
print ("##########################################");
print("Compatibility checks done.");
});
# this is now where we can simply refer to features.geodinfo_supports_vectors
# for checking if vector support is available or not - to use the most appropriate
# APIs
####################################
# set visibility to given value
####################################
@ -223,10 +334,47 @@ settimer( func {smooth_wind_loop(vx,vy,vx_old,vy_old,counter-1, count_max); },ti
var create_cloud = func(path, lat, long, alt, heading) {
var tile_counter = getprop(lw~"tiles/tile-counter");
var buffer_flag = getprop(lw~"config/buffer-flag");
var dynamics_flag = getprop(lw~"config/dynamics-flag");
var d_max = weather_tile_management.cloud_view_distance + 1000.0;
# first check if the cloud should be stored in the buffer
# we keep it if it is in visual range or at high altitude (where visual range is different)
if (buffer_flag == 1)
{
# calculate the distance to the aircraft
var pos = geo.aircraft_position();
var cpos = geo.Coord.new();
cpos.set_latlon(lat,long,0.0);
var d = pos.distance_to(cpos);
if ((d > d_max) and (alt < 20000.0)) # we buffer the cloud
{
var b = weather_tile_management.cloudBuffer.new(lat, long, alt, path, heading, tile_counter);
if (dynamics_flag ==1) {b.timestamp = weather_dynamics.time_lw;}
append(weather_tile_management.cloudBufferArray,b);
return;
}
}
# now check if we are writing from the buffer, in this case change tile index
# to buffered one
if (getprop(lw~"tmp/buffer-status") == "placing")
{
tile_counter = getprop(lw~"tmp/buffer-tile-index");
}
# if the cloud is not buffered, get property tree nodes and write it
# into the scenery
var n = props.globals.getNode("local-weather/clouds", 1);
var c = n.getChild("tile",tile_counter,1);
var cloud_number = n.getNode("placement-index").getValue();
for (var i = cloud_number; 1; i += 1)
if (c.getChild("cloud", i, 0) == nil)
@ -266,20 +414,27 @@ model.getNode("load", 1).remove();
n.getNode("cloud-number").setValue(n.getNode("cloud-number").getValue()+1);
# sort the model nodes into a vector
# sort the model node into a vector for easy deletion
append(weather_tile_management.modelArrays[tile_counter-1],model);
# append(weather_tile_management.modelArrays[tile_counter-1],model);
# sort the cloud into the cloud hash array
# if weather dynamics is on, also create a timestamp property and sort into quadtree
if ((buffer_flag == 1) and (getprop(lw~"tmp/tile-management") != "single tile"))
{
var cs = weather_tile_management.cloudScenery.new(tile_counter, cl, model);
append(weather_tile_management.cloudSceneryArray,cs);
}
if (getprop(lw~"config/dynamics-flag") == 1)
# if weather dynamics is on, also create a timestamp property and sort the cloud node into quadtree
#if (getprop(lw~"config/dynamics-flag") == 1)
if (dynamics_flag == 1)
{
cl.getNode("timestamp-sec",1).setValue(weather_dynamics.time_lw);
var blat = getprop(lw~"tiles/tmp/latitude-deg");
var blon = getprop(lw~"tiles/tmp/longitude-deg");
var alpha = getprop(lw~"tmp/tile-orientation-deg");
#weather_dynamics.sort_into_quadtree(blat, blon, alpha, lat, long, weather_dynamics.cloudQuadtree, cl);
weather_dynamics.sort_into_quadtree(blat, blon, alpha, lat, long, weather_dynamics.cloudQuadtrees[tile_counter-1], cl);
}
@ -298,6 +453,12 @@ if ((i < 0) or (i==0))
{
print("Cloud placement from array finished!");
setprop(lw~"tmp/thread-status", "idle");
# now set flag that tile has been completely processed
var dir_index = props.globals.getNode(lw~"tiles/tmp/dir-index").getValue();
# print("dir_index: ",dir_index);
props.globals.getNode(lw~"tiles").getChild("tile",dir_index).getNode("generated-flag").setValue(2);
return;
}
@ -309,8 +470,6 @@ if (s < k_max) {k_max = s;}
for (var k = 0; k < k_max; k = k+1)
{
#print(s, " ", k, " ", s-k-1, " ", clouds_path[s-k-1]);
#create_cloud(clouds_type[s-k-1], clouds_path[s-k-1], clouds_lat[s-k-1], clouds_lon[s-k-1], clouds_alt[s-k-1], 0.0, 0);
create_cloud(clouds_path[s-k-1], clouds_lat[s-k-1], clouds_lon[s-k-1], clouds_alt[s-k-1], clouds_orientation[s-k-1]);
}
@ -412,6 +571,15 @@ else if (status == "idle") # we initialize the loop
{
mvec = weather_tile_management.modelArrays[index-1];
msize = size(mvec);
if (msize == 0)
{
print("Tile deletion loop finished!");
setprop(lw~"tmp/thread-status", "idle");
setprop(lw~"clouds/placement-index",0);
setprop(lw~"clouds/model-placement-index",0);
setsize(weather_tile_management.modelArrays[index-1],0);
return;
}
setprop(lw~"tmp/last-reading-pos-mod", msize);
setprop(lw~"tmp/thread-status", "removing");
}
@ -475,9 +643,16 @@ var get_elevation_array = func (lat, lon) {
var elevation = [];
var n = size(lat);
for(var i = 0; i < n; i=i+1)
if (features.geodinfo_supports_vectors == 0)
{
append(elevation, get_elevation(lat[i], lon[i]));
for(var i = 0; i < n; i=i+1)
{
append(elevation, get_elevation(lat[i], lon[i]));
}
}
else
{
elevation = geodinfo(lat,10000);
}
return elevation;

View file

@ -445,18 +445,18 @@ else if (wind_model_flag == 5) # aloft waypoint interpolated
var altitude_agl = getprop("/position/altitude-agl-ft");
if (getprop("tmp/presampling-flag") == 0)
if (getprop(lw~"tmp/presampling-flag") == 0)
{
var boundary_alt = 600.0;
var windspeed_ground = windspeed/3.0;
if (altitude_agl < boundary_alt)
{var windspeed_current = windspeed_ground + 2.0 * windspeed_ground * (altitude_agl/boundary_alt);}
{var windspeed_current = windspeed_ground + 2.0 * windspeed_ground * (altitude_agl/boundary_alt);}
else
{var windspeed_current = windspeed;}
}
else
else
{
var alt_median = alt_50_array[tile_index - 1];
var alt_difference = alt_median - (altitude - altitude_agl);
@ -1022,13 +1022,18 @@ else if ((type == "Cumulonimbus") or (type == "Cumulonimbus (rain)")) {
}
else if (type == "Cirrus") {
if (subtype == "large") {
if (rn > 0.66) {path = "Models/Weather/cirrus1.xml";}
else if (rn > 0.33) {path = "Models/Weather/cirrus2.xml";}
else {path = "Models/Weather/cirrus3.xml";}
if (rn > 0.833) {path = "Models/Weather/cirrus1.xml";}
else if (rn > 0.666) {path = "Models/Weather/cirrus2.xml";}
else if (rn > 0.5) {path = "Models/Weather/cirrus3.xml";}
else if (rn > 0.333) {path = "Models/Weather/cirrus4.xml";}
else if (rn > 0.166) {path = "Models/Weather/cirrus5.xml";}
else {path = "Models/Weather/cirrus6.xml";}
}
else if (subtype == "small") {
if (rn > 0.5) {path = "Models/Weather/cirrus_amorphous1.xml";}
else {path = "Models/Weather/cirrus_amorphous2.xml";}
if (rn > 0.75) {path = "Models/Weather/cirrus_amorphous1.xml";}
else if (rn > 0.5) {path = "Models/Weather/cirrus_amorphous2.xml";}
else if (rn > 0.25) {path = "Models/Weather/cirrus_amorphous3.xml";}
else {path = "Models/Weather/cirrus_amorphous4.xml";}
}
}
else if (type == "Cirrocumulus") {
@ -1037,8 +1042,14 @@ else if (type == "Cirrocumulus") {
else {path = "Models/Weather/cirrocumulus2.xml";}
}
else if (subtype == "large") {
if (rn > 0.5) {path = "Models/Weather/cirrocumulus1.xml";}
else {path = "Models/Weather/cirrocumulus4.xml";}
if (rn > 0.875) {path = "Models/Weather/cirrocumulus1.xml";}
else if (rn > 0.750){path = "Models/Weather/cirrocumulus4.xml";}
else if (rn > 0.625){path = "Models/Weather/cirrocumulus5.xml";}
else if (rn > 0.500){path = "Models/Weather/cirrocumulus6.xml";}
else if (rn > 0.385){path = "Models/Weather/cirrocumulus7.xml";}
else if (rn > 0.250){path = "Models/Weather/cirrocumulus8.xml";}
else if (rn > 0.125){path = "Models/Weather/cirrocumulus9.xml";}
else {path = "Models/Weather/cirrocumulus10.xml";}
}
}
else if (type == "Cirrocumulus (cloudlet)") {
@ -1238,7 +1249,7 @@ setprop(lwi~"ipoint-number",0);
weather_tiles.last_pressure = 0.0;
# stop the effect loop and the interpolation loop, make sure thermal generation is off
# stop all loops make sure thermal generation is off
setprop(lw~"effect-loop-flag",0);
setprop(lw~"interpolation-loop-flag",0);
@ -1246,6 +1257,8 @@ setprop(lw~"tile-loop-flag",0);
setprop(lw~"lift-loop-flag",0);
setprop(lw~"dynamics-loop-flag",0);
setprop(lw~"timing-loop-flag",0);
setprop(lw~"buffer-loop-flag",0);
setprop(lw~"housekeeping-loop-flag",0);
setprop(lw~"tmp/generate-thermal-lift-flag",0);
# also remove rain and snow effects
@ -1261,13 +1274,22 @@ setprop(lw~"effect-volumes/effect-placement-index",0);
setprop(lw~"effect-volumes/number",0);
setprop(lw~"tiles/tile-counter",0);
# remove any quadtrees and arrays
settimer ( func { setsize(weather_dynamics.cloudQuadtrees,0);},0.1); # to avoid error generation in this frame
setsize(effectVolumeArray,0);
n_effectVolumeArray = 0;
setsize(weather_tile_management.modelArrays,0);
settimer ( func {
setsize(weather_tile_management.modelArrays,0);
setsize(weather_dynamics.tile_wind_direction,0);
setsize(weather_dynamics.tile_wind_speed,0);
setsize(weather_tile_management.cloudBufferArray,0);
setsize(weather_tile_management.cloudSceneryArray,0);
setprop(lw~"clouds/buffer-count",0);
setprop(lw~"clouds/cloud-scenery-count",0);
},1.1);
}
@ -1280,7 +1302,10 @@ var create_detailed_cumulus_cloud = func (lat, lon, alt, size) {
#print(size);
var edge_bias = 0.0;
var edge_bias = convective_texture_mix;
#print("edge_bias: ",edge_bias);
var size_bias = 0.0;
if (size > 2.0)
@ -2015,7 +2040,24 @@ else
var terrain_presampling_loop = func (blat, blon, nc, size, alpha) {
var n = 25; # number of geoinfo calls per frame
if (compat_layer.features.geodinfo_supports_vectors == 0)
{var n = 25;} # number of geoinfo calls per frame
else
{var n = 25;} # vector call
var n_out = 25;
# dynamically drop accuracy if framerate is low
var dt = getprop("/sim/time/delta-sec");
if (dt > 0.2) # we have below 20 fps
{n = 5;}
else if (dt > 0.1) # we have below 10 fps
{n = 10;}
else if (dt > 0.05) # we have below 5 fps
{n = 15;}
if (nc <= 0) # we're done and may analyze the result
{
@ -2027,7 +2069,7 @@ if (nc <= 0) # we're done and may analyze the result
terrain_presampling(blat, blon, n, size, alpha);
settimer( func {terrain_presampling_loop(blat, blon, nc-n, size, alpha) },0);
settimer( func {terrain_presampling_loop(blat, blon, nc-n_out, size, alpha) },0);
}
@ -2042,21 +2084,34 @@ var elevation = 0.0;
var lat_vec = [];
var lon_vec = [];
var lat_lon_vec = [];
for (var i=0; i<ntries; i=i+1)
{
var x = (2.0 * rand() - 1.0) * size;
var y = (2.0 * rand() - 1.0) * size;
#var lat = blat + (y * math.cos(phi) - x * math.sin(phi)) * m_to_lat;
#var lon = blon + (x * math.cos(phi) + y * math.sin(phi)) * m_to_lon;
append(lat_vec, blat + (y * math.cos(phi) - x * math.sin(phi)) * m_to_lat);
append(lon_vec, blon + (x * math.cos(phi) + y * math.sin(phi)) * m_to_lon);
if (compat_layer.features.geodinfo_supports_vectors == 0)
{
append(lat_vec, blat + (y * math.cos(phi) - x * math.sin(phi)) * m_to_lat);
append(lon_vec, blon + (x * math.cos(phi) + y * math.sin(phi)) * m_to_lon);
}
else
{
append(lat_lon_vec, blat + (y * math.cos(phi) - x * math.sin(phi)) * m_to_lat);
append(lat_lon_vec, blon + (x * math.cos(phi) + y * math.sin(phi)) * m_to_lon);
}
}
var elevation_vec = compat_layer.get_elevation_array(lat_vec, lon_vec);
if (compat_layer.features.geodinfo_supports_vectors == 0)
{
var elevation_vec = compat_layer.get_elevation_array(lat_vec, lon_vec);
}
else
{
var elevation_vec = compat_layer.get_elevation_array(lat_lon_vec, lat_lon_vec);
}
#var info = geodinfo(lat, lon);
#if (info != nil) {elevation = info[0] * m_to_ft;}
@ -2139,7 +2194,7 @@ setprop(lw~"tmp/tile-alt-min-ft",alt_min);
setprop(lw~"tmp/tile-alt-layered-ft",0.5 * (alt_min + alt_offset));
append(alt_50_array, alt_med);
append(alt_20_array, alt_20);
}
###########################################################
@ -2235,6 +2290,21 @@ else {print("Wind model not implemented!"); wind_model_flag =1;}
}
###########################################################
# set texture mix for convective clouds
###########################################################
var set_texture_mix = func {
var thermal_properties = getprop(lw~"config/thermal-properties");
convective_texture_mix = -(thermal_properties - 1.0) * 0.4;
if (convective_texture_mix < -0.2) {convective_texture_mix = -0.2;}
if (convective_texture_mix > 0.2) {convective_texture_mix = 0.2;}
}
###########################################################
# create an effect volume
###########################################################
@ -2618,7 +2688,7 @@ var lon = getprop("position/longitude-deg");
setprop(lw~"tiles/tmp/latitude-deg",lat);
setprop(lw~"tiles/tmp/longitude-deg",lon);
setprop(lw~"tiles/tmp/dir-index",4);
# now see if we need to presample the terrain
@ -2792,6 +2862,19 @@ if (getprop(lw~"config/dynamics-flag") ==1)
}
# and start the buffer loop and housekeeping loop if needed
if (getprop(lw~"config/buffer-flag") ==1)
{
if (getprop(lw~"buffer-loop-flag") == 0)
{
setprop(lw~"buffer-loop-flag",1); weather_tile_management.buffer_loop(0);
setprop(lw~"housekeeping-loop-flag",1); weather_tile_management.housekeeping_loop(0);
}
}
#weather_tile_management.watchdog_loop();
}
@ -2868,7 +2951,12 @@ setlistener(lw~"tmp/effect-thread-status", func {var s = size(effects_geo); eff
setlistener(lw~"tmp/presampling-status", func {manage_presampling(); });
setlistener(lw~"config/wind-model", func {set_wind_model_flag();});
setlistener(lw~"config/thermal-properties", func {set_texture_mix();});
setlistener(lw~"config/clouds-in-dynamics-loop", func {weather_dynamics.max_clouds_in_loop = int(getprop(lw~"config/clouds-in-dynamics-loop"));});
setlistener(lw~"config/clouds-visible-range-m", func {weather_tile_management.cloud_view_distance = getprop(lw~"config/clouds-visible-range-m");});
setlistener(lw~"config/distance-to-load-tile-m", func {setprop(lw~"config/distance-to-remove-tile-m",getprop(lw~"config/distance-to-load-tile-m") + 500.0);});
}
@ -2881,7 +2969,18 @@ var test = func {
var lat = getprop("position/latitude-deg");
var lon = getprop("position/longitude-deg");
showDialog("local_weather_winds");
var v = [1,2,3,4,5,6,7];
print(v[2]);
v = weather_tile_management.delete_from_vector(v, 2);
v = weather_tile_management.delete_from_vector(v, 2);
for (var i = 0; i < size(v); i = i + 1)
{
print(v[i]);
}
#weather_dynamics.cos_beta = 1;
#weather_dynamics.sin_beta = 0;
@ -2912,9 +3011,9 @@ showDialog("local_weather_winds");
# terrain_presampling_start(lat, lon, 1000, 20000, 0.0);
#terrain_presampling_start(lat, lon, 10000, 20000, 0.0);
# test: 8 identical position tuples for KSFO
#test: 8 identical position tuples for KSFO
#var p=[ 37.6189722, -122.3748889, 37.6189722, -122.3748889,
# 37.6289722, -122.3748889, 37.6189722, -122.3648889,
# 37.6389722, -122.3748889, 37.6189722, -122.3548889,
@ -2975,7 +3074,7 @@ var clouds_orientation = [];
var terrain_n = [];
var alt_50_array = [];
var alt_20_array = [];
# array of currently existing effect volumes
@ -2987,6 +3086,10 @@ var n_effectVolumeArray = 0;
var wind_model_flag = 1;
# a global determining the relative amount of different textures in detailed convective clouds
var convective_texture_mix = 0.0;
# set all sorts of default properties for the menu
@ -3054,6 +3157,8 @@ setprop(lw~"tmp/last-reading-pos-mod",0);
setprop(lw~"tmp/thread-status", "idle");
setprop(lw~"tmp/convective-status", "idle");
setprop(lw~"tmp/presampling-status", "idle");
setprop(lw~"tmp/buffer-status", "idle");
setprop(lw~"tmp/buffer-tile-index", 0);
setprop(lw~"tmp/FL0-wind-from-heading-deg",0.0);
setprop(lw~"tmp/FL0-windspeed-kt",8.0);
setprop(lw~"tmp/FL50-wind-from-heading-deg",2.0);
@ -3078,12 +3183,21 @@ setprop(lw~"tmp/ipoint-longitude-deg",getprop("position/longitude-deg"));
# set config values
setprop(lw~"config/distance-to-load-tile-m",35000.0);
setprop(lw~"config/distance-to-remove-tile-m",37000.0);
#setprop(lw~"config/distance-to-load-tile-m",35000.0);
#setprop(lw~"config/distance-to-remove-tile-m",37000.0);
setprop(lw~"config/distance-to-load-tile-m",39000.0);
setprop(lw~"config/distance-to-remove-tile-m",39500.0);
setprop(lw~"config/detailed-clouds-flag",1);
setprop(lw~"config/dynamics-flag",1);
setprop(lw~"config/thermal-properties",1.0);
setprop(lw~"config/wind-model","constant");
setprop(lw~"config/buffer-flag",1);
setprop(lw~"config/asymmetric-reduction",0.7);
setprop(lw~"config/clouds-visible-range-m",30000.0);
setprop(lw~"config/asymmetric-buffering-flag",0);
setprop(lw~"config/asymmetric-buffering-reduction",0.3);
setprop(lw~"config/asymmetric-buffering-angle-deg",90.0);
setprop(lw~"config/clouds-in-dynamics-loop",250);
# set the default loop flags to loops inactive
@ -3092,6 +3206,8 @@ setprop(lw~"effect-loop-flag",0);
setprop(lw~"interpolation-loop-flag",0);
setprop(lw~"tile-loop-flag",0);
setprop(lw~"lift-loop-flag",0);
setprop(lw~"buffer-loop-flag",0);
setprop(lw~"housekeeping-loop-flag",0);
# create other management properties

View file

@ -102,7 +102,7 @@ foreach (t; tiles)
{
var generated_flag = t.getNode("generated-flag").getValue();
if (generated_flag == 1)
if ((generated_flag == 1) or (generated_flag ==2))
{
var index = t.getNode("tile-index").getValue();
current_tile_index_wd = index;
@ -127,9 +127,9 @@ foreach (t; tiles)
# if there are plenty of moving clouds nearby, no one pays attention to the small motion of distant clouds
# price to pay is that some clouds appear to jump once they get into range
if (cloud_counter < 150) {view_distance = view_distance * 1.1;}
else if (cloud_counter > 250) {view_distance = view_distance * 0.9;}
if (view_distance > 30000.0) {view_distance = 30000.0;}
if (cloud_counter < 0.5 * max_clouds_in_loop) {view_distance = view_distance * 1.1;}
else if (cloud_counter > max_clouds_in_loop) {view_distance = view_distance * 0.9;}
if (view_distance > weather_tile_management.cloud_view_distance) {view_distance = weather_tile_management.cloud_view_distance;}
#print(cloud_counter, " ", view_distance/1000.0);
@ -477,7 +477,6 @@ return xy_vec;
}
################################
# globals, constants, properties
################################
@ -505,6 +504,7 @@ var lw = "/local-weather/";
# globals
var time_lw = 0.0;
var max_clouds_in_loop = 250;
# the quadtree structure

View file

@ -12,6 +12,7 @@
# copy_entry to copy tile information from one node to another
# create_neighbour to set up information for a new neighbouring tile
# create_neighbours to initialize the 8 neighbours of the initial tile
# buffer_loop to manage the buffering of faraway clouds in an array
# calc_geo to get local Cartesian geometry for latitude conversion
# get_lat to get latitude from Cartesian coordinates
# get_lon to get longitude from Cartesian coordinates
@ -31,9 +32,17 @@ var d_min = 100000.0;
var i_min = 0;
var distance_to_load = getprop(lw~"config/distance-to-load-tile-m");
var distance_to_remove = getprop(lw~"config/distance-to-remove-tile-m");
var current_visibility = getprop(lw~"interpolation/visibility-m");
var current_heading = getprop("orientation/heading-deg");
var loading_flag = getprop(lw~"tmp/asymmetric-tile-loading-flag");
var this_frame_generated_flag = 0; # use this flag to avoid overlapping tile generation calls
var this_frame_action_flag = 0; # use this flag to avoid overlapping tile operations
setsize(active_tile_list,0);
if (distance_to_load > 3.0 * current_visibility)
{distance_to_load = 3.0 * current_visibility;}
if (distance_to_load < 25000.0)
{distance_to_load = 25000.0;}
foreach (var t; tNode) {
@ -43,12 +52,16 @@ foreach (var t; tNode) {
if (d < d_min) {d_min = d; i_min = i;}
var flag = t.getNode("generated-flag").getValue();
if ((flag ==2) or (flag ==1)) {append(active_tile_list,t.getNode("tile-index").getValue());}
var dir = viewpos.course_to(tpos);
var d_load = distance_to_load;
var d_remove = distance_to_remove;
if (loading_flag == 1)
{
if ((abs(dir-current_heading) > 135.0) and (abs(dir-current_heading) < 225.0))
var angle = abs(dir-current_heading);
#if (i==7) {print(angle);}
if ((angle > 135.0) and (angle < 225.0))
{
d_load = 0.7 * d_load;
d_remove = 0.7 * d_remove;
@ -59,13 +72,15 @@ foreach (var t; tNode) {
# and if no other tile has been generated in this loop cycle
# and the thread and convective system are idle
# (we want to avoid overlapping tile generation)
if ((d < distance_to_load) and (flag==0) and (this_frame_generated_flag == 0) and (getprop(lw~"tmp/thread-status") == "idle") and (getprop(lw~"tmp/convective-status") == "idle"))
if ((d < d_load) and (flag==0) and (this_frame_action_flag == 0) and (getprop(lw~"tmp/thread-status") == "idle") and (getprop(lw~"tmp/convective-status") == "idle") and (getprop(lw~"tmp/presampling-status") == "idle"))
{
this_frame_action_flag = 1;
setprop(lw~"tiles/tile-counter",getprop(lw~"tiles/tile-counter")+1);
print("Building tile unique index ",getprop(lw~"tiles/tile-counter"), " in direction ",i);
generate_tile(code, tpos.lat(), tpos.lon(),i);
append(active_tile_list,getprop(lw~"tiles/tile-counter"));
if (getprop(lw~"config/dynamics-flag") == 1)
if (getprop(lw~"config/dynamics-flag") == 1)
{
var quadtree = [];
weather_dynamics.generate_quadtree_structure(0, quadtree);
@ -76,24 +91,50 @@ foreach (var t; tNode) {
t.getNode("timestamp-sec").setValue(weather_dynamics.time_lw);
t.getNode("tile-index",1).setValue(getprop(lw~"tiles/tile-counter"));
this_frame_generated_flag = 1;
generate_tile(code, tpos.lat(), tpos.lon(),i);
}
if ((d > distance_to_remove) and (flag==1)) # the tile needs to be deleted if it exists
if ((d > d_remove) and (flag == 2) and (this_frame_action_flag == 0)) # the tile needs to be deleted if it exists
{
print("Removing tile, unique index ", t.getNode("tile-index").getValue());
print("Removing tile, unique index ", t.getNode("tile-index").getValue()," direction ",i);
remove_tile(t.getNode("tile-index").getValue());
t.getNode("generated-flag").setValue(0);
this_frame_action_flag = 1;
}
i = i + 1;
} # end foreach
#print("Minimum distance to: ",i_min);
if (i_min != 4) # we've entered a different tile
var presampling_status = getprop(lw~"tmp/presampling-status");
var convective_status = getprop(lw~"tmp/convective-status");
var thread_status = getprop(lw~"tmp/thread-status");
if ((presampling_status == "idle") and (convective_status == "idle") and (thread_status == "idle"))
{
var system_status = "idle";
}
else
{system_status = "computing";}
# and (this_frame_action_flag == 0) and (presampling_status == "idle") and (convective_status=="idle"))
# check if we've entered a different tile and if no operation is in progress
# var gen_flag = tNode[i_min].getNode("generated-flag").getValue();
if ((i_min != 4) and (system_status == "idle"))
{
var gen_flag = tNode[i_min].getNode("generated-flag").getValue();
if (gen_flag != 2){
print("Tile direction ",i_min, " not generated!");
print("Flag: ",gen_flag);
}
print("Changing active tile to direction ", i_min);
change_active_tile(i_min);
}
@ -109,17 +150,21 @@ if (getprop(lw~"tile-loop-flag") ==1) {settimer(tile_management_loop, 5.0);}
var generate_tile = func (code, lat, lon, dir_index) {
# make sure the last tile call has finished, otherwise put on hold
#if ((getprop(lw~"tmp/thread-status") != "idle") or (getprop(lw~"tmp/convective-status") != "idle"))
# {
# print("Tile generation overlap, delaying...");
# settimer( func {generate_tile(code, lat, lon, dir_index);}, 1);
# }
# the code should never be NIL, but this appears to happen under certain conditions
# so just to be on the safe side make sure it is set to current tile code if
# it actually is NIL
if (code == "")
{
print("No tile code - falling back on default!");
code = getprop(lw~"tiles/code");
}
setprop(lw~"tiles/tmp/latitude-deg", lat);
setprop(lw~"tiles/tmp/longitude-deg",lon);
setprop(lw~"tiles/tmp/code",code);
setprop(lw~"tiles/tmp/dir-index",dir_index);
# do windspeed and orientation before presampling check, but test not to do it again
@ -145,7 +190,7 @@ if (((getprop(lw~"tmp/presampling-flag") == 1) and (getprop(lw~"tmp/presampling-
var windspeed = getprop(lw~"tmp/windspeed-kt");
windspeed = windspeed + 2.0 * (rand()-0.5) * 2.0;
if (windspeed < 0) {windspeed = rand();}
setprop(lw~"tmp/windspeed-kt");
setprop(lw~"tmp/windspeed-kt", windspeed);
# store the tile orientation and wind strength in an array for fast processing
@ -180,7 +225,6 @@ if (((getprop(lw~"tmp/presampling-flag") == 1) and (getprop(lw~"tmp/presampling-
if ((getprop(lw~"tmp/presampling-flag") == 1) and (getprop(lw~"tmp/presampling-status") == "idle"))
{
local_weather.terrain_presampling_start(lat, lon, 1000, 40000, getprop(lw~"tmp/tile-orientation-deg"));
setprop(lw~"tiles/tmp/dir-index",dir_index);
return;
}
@ -338,7 +382,22 @@ else if (getprop(lw~"tmp/tile-management") == "realistic weather")
var remove_tile = func (index) {
compat_layer.remove_clouds(index);
# remove tile from active list
var s = size(active_tile_list);
for (var j = 0; j < s; j=j+1)
{
if (index == active_tile_list[j])
{
active_tile_list = delete_from_vector(active_tile_list,j);
break;
}
}
settimer( func { props.globals.getNode("local-weather/clouds", 1).removeChild("tile",index) },100);
#compat_layer.remove_clouds(index);
var effectNode = props.globals.getNode("local-weather/effect-volumes").getChildren("effect-volume");
@ -365,7 +424,7 @@ setprop(lw~"effect-volumes/effect-placement-index",0);
if (getprop(lw~"config/dynamics-flag") ==1)
{
setsize(weather_dynamics.cloudQuadtrees[index-1],0);
settimer( func {setsize(weather_dynamics.cloudQuadtrees[index-1],0);},1.0);
}
# rebuild effect volume vector
@ -505,9 +564,16 @@ t.getNode("latitude-deg").setValue(f.getNode("latitude-deg").getValue());
t.getNode("longitude-deg").setValue(f.getNode("longitude-deg").getValue());
t.getNode("generated-flag").setValue(f.getNode("generated-flag").getValue());
t.getNode("tile-index").setValue(f.getNode("tile-index").getValue());
t.getNode("code").setValue(f.getNode("code").getValue());
t.getNode("timestamp-sec").setValue(f.getNode("timestamp-sec").getValue());
t.getNode("orientation-deg").setValue(f.getNode("orientation-deg").getValue());
t.getNode("code").setValue(f.getNode("code").getValue());
#if (f.getNode("code").getValue() == "")
# {print("Empty tile code copying from ", from_index," to ", to_index, "!");}
#if (f.getNode("code").getValue() != "") # we don't copy an empty code, that can trigger errors
# {t.getNode("code").setValue(f.getNode("code").getValue());}
}
#####################################
@ -530,11 +596,16 @@ if ((index == 6) or (index == 7) or (index == 8)) {y = -40000.0;}
var t = props.globals.getNode(lw~"tiles").getChild("tile",index,0);
# use the last built tile code as default, in case a tile isn't formed when reached,
# the code is not empty but has a plausible value
var default_code = getprop(lw~"tiles/code");
t.getNode("latitude-deg",1).setValue(blat + get_lat(x,y,phi));
t.getNode("longitude-deg",1).setValue(blon + get_lon(x,y,phi));
t.getNode("generated-flag",1).setValue(0);
t.getNode("tile-index",1).setValue(-1);
t.getNode("code",1).setValue("");
t.getNode("code",1).setValue(default_code);
t.getNode("timestamp-sec",1).setValue(weather_dynamics.time_lw);
t.getNode("orientation-deg",1).setValue(0.0);
}
@ -636,6 +707,233 @@ setprop(lw~"tiles/tile[8]/timestamp-sec",weather_dynamics.time_lw);
setprop(lw~"tiles/tile[8]/orientation-deg",0.0);
}
###############################
# buffer loop
###############################
var buffer_loop = func (index) {
var n = 5;
var n_max = size(cloudBufferArray);
var s = size(active_tile_list);
setprop(lw~"clouds/buffer-count",n_max);
# don't do anything as long as the buffer is empty
if (n_max == 0) # nothing to do, loop over
{if (getprop(lw~"buffer-loop-flag") ==1) {settimer( func {buffer_loop(index)}, 0);} return;}
# don't process the buffer if a tile call is writing clouds into the scenery
if (getprop(lw~"tmp/thread-status") == "placing")
{if (getprop(lw~"buffer-loop-flag") ==1) {settimer( func {buffer_loop(index)}, 0);} return;}
# lock the system status for buffer operations and get flags
setprop(lw~"tmp/buffer-status", "placing");
var asymmetric_buffering_flag = getprop(lw~"config/asymmetric-buffering-flag");
if (asymmetric_buffering_flag ==1)
{
var buffering_angle = getprop(lw~"config/asymmetric-buffering-angle-deg");
var buffering_reduction = getprop(lw~"config/asymmetric-buffering-reduction");
var current_heading = getprop("orientation/heading-deg");
}
# now process the buffer
if (index > n_max-1) {index = 0;}
var i_max = index + n;
if (i_max > n_max) {i_max = n_max;}
for (var i = index; i < i_max; i = i+1)
{
var c = cloudBufferArray[i];
# check if the cloud is still part of an active tile, if not remove from buffer
var flag = 0;
for (var j = 0; j < s; j = j+1)
{
if (active_tile_list[j] == c.index) {flag = 1; break;}
}
if (flag == 0)
{
cloudBufferArray = delete_from_vector(cloudBufferArray,i);
i = i -1; i_max = i_max - 1; n_max = n_max - 1;
continue;
}
# if wind drift is on, move the cloud
if (getprop(lw~"config/dynamics-flag") == 1)
{
c.move();
}
# check distance and decide if the cloud should be created
var d = c.get_distance();
var d_comp = cloud_view_distance + 1000.0;
if (asymmetric_buffering_flag == 1)
{
var dir = c.get_course();
var angle = abs(dir-current_heading);
if ((angle > 180.0 - 0.5 * buffering_angle) and (angle < 180 + 0.5 * buffering_angle))
{
d_comp = buffering_reduction * d_comp;
}
}
if (d < d_comp) # insert the cloud into scenery and delete from buffer
{
setprop(lw~"tmp/buffer-tile-index",c.index);
compat_layer.create_cloud(c.path, c.lat, c.lon, c.alt, c.orientation);
cloudBufferArray = delete_from_vector(cloudBufferArray,i);
i = i -1; i_max = i_max - 1; n_max = n_max - 1;
deleted_flag = 1;
}
} # end for i
# unlock the system status for buffer operations
setprop(lw~"tmp/buffer-status", "idle");
if (getprop(lw~"buffer-loop-flag") ==1) {settimer( func {buffer_loop(i)}, 0);}
}
###############################
# housekeeping loop
###############################
var housekeeping_loop = func (index) {
var n = 5;
var n_max = size(cloudSceneryArray);
var s = size(active_tile_list);
setprop(lw~"clouds/cloud-scenery-count",n_max);
# don't do anything as long as the array is empty
if (n_max == 0) # nothing to do, loop over
{if (getprop(lw~"housekeeping-loop-flag") ==1) {settimer( func {housekeeping_loop(index)}, 0);} return;}
# parse the flags
var asymmetric_buffering_flag = getprop(lw~"config/asymmetric-buffering-flag");
if (asymmetric_buffering_flag ==1)
{
var buffering_angle = getprop(lw~"config/asymmetric-buffering-angle-deg");
var buffering_reduction = getprop(lw~"config/asymmetric-buffering-reduction");
var current_heading = getprop("orientation/heading-deg");
}
# now process the array
if (index > n_max-1) {index = 0;}
var i_max = index + n;
if (i_max > n_max) {i_max = n_max;}
for (var i = index; i < i_max; i = i+1)
{
var c = cloudSceneryArray[i];
var flag = 0;
for (var j = 0; j < s; j = j+1)
{
if (active_tile_list[j] == c.index) {flag = 1; break;}
}
if (flag == 0)
{
c.removeNodes();
cloudSceneryArray = delete_from_vector(cloudSceneryArray,i);
i = i -1; i_max = i_max - 1; n_max = n_max - 1;
continue;
}
var d = c.get_distance();
var alt = c.get_altitude();
d_comp = cloud_view_distance + 1000.0;
if (asymmetric_buffering_flag == 1)
{
var dir = c.get_course();
var angle = abs(dir-current_heading);
if ((angle > 180.0 - 0.5 * buffering_angle) and (angle < 180 + 0.5 * buffering_angle))
{
d_comp = buffering_reduction * d_comp;
}
}
if ((d > d_comp) and (alt < 20000.0))
{
append(cloudBufferArray,c.to_buffer());
cloudSceneryArray = delete_from_vector(cloudSceneryArray,i);
i = i -1; i_max = i_max - 1; n_max = n_max - 1;
continue;
}
}
if (getprop(lw~"housekeeping-loop-flag") ==1) {settimer( func {housekeeping_loop(i)}, 0);}
}
###############################
# watchdog loop for debugging
###############################
var watchdog_loop = func {
var tNode = props.globals.getNode(lw~"tiles", 1).getChildren("tile");
var i = 0;
print("====================");
foreach(t; tNode)
{
var code = t.getNode("code").getValue();
var index = t.getNode("tile-index").getValue();
var flag = t.getNode("generated-flag").getValue();
print(i,": code: ", code, " unique id: ", index, " flag: ", flag);
i = i + 1;
}
print("====================");
settimer(watchdog_loop, 10.0);
}
###################
# global variables
###################
@ -652,9 +950,109 @@ var lon_to_m = 0.0; #local_weather.lon_to_m;
var m_to_lon = 0.0; # local_weather.m_to_lon;
var lw = "/local-weather/";
var cloud_view_distance = 20000.0;
var modelArrays = [];
var active_tile_list = [];
#####################################################
# hashes to manage clouds in scenery or in the buffer
#####################################################
var cloudBufferArray = [];
var cloudBuffer = {
new: func(lat, lon, alt, path, orientation, index) {
var c = { parents: [cloudBuffer] };
c.lat = lat;
c.lon = lon;
c.alt = alt;
c.path = path;
c.orientation = orientation;
c.index = index;
return c;
},
get_distance: func {
var pos = geo.aircraft_position();
var cpos = geo.Coord.new();
cpos.set_latlon(me.lat,me.lon,0.0);
return pos.distance_to(cpos);
},
get_course: func {
var pos = geo.aircraft_position();
var cpos = geo.Coord.new();
cpos.set_latlon(me.lat,me.lon,0.0);
return pos.course_to(cpos);
},
show: func {
print("lat: ",me.lat," lon: ",me.lon," alt: ",me.alt);
print("path: ",me.path);
},
move: func {
var windfield = weather_dynamics.get_windfield(me.index);
var dt = weather_dynamics.time_lw - me.timestamp;
me.lat = me.lat + windfield[1] * dt * local_weather.m_to_lat;
me.lon = me.lon + windfield[0] * dt * local_weather.m_to_lon;
me.timestamp = weather_dynamics.time_lw;
},
};
var cloudSceneryArray = [];
var cloudScenery = {
new: func(index, cloudNode, modelNode) {
var c = { parents: [cloudScenery] };
c.index = index;
c.cloudNode = cloudNode;
c.modelNode = modelNode;
return c;
},
removeNodes: func {
me.modelNode.remove();
me.cloudNode.remove();
},
to_buffer: func {
var lat = me.cloudNode.getNode("position/latitude-deg").getValue();
var lon = me.cloudNode.getNode("position/longitude-deg").getValue();
var alt = me.cloudNode.getNode("position/altitude-ft").getValue();
var path = me.modelNode.getNode("path").getValue();
var orientation = me.cloudNode.getNode("orientation/true-heading-deg").getValue();
var b = cloudBuffer.new(lat, lon, alt, path, orientation, me.index);
if (getprop(lw~"config/dynamics-flag") == 1)
{
var timestamp = me.cloudNode.getNode("timestamp-sec").getValue();
b.timestamp = timestamp;
}
me.removeNodes();
return b;
},
get_distance: func {
var pos = geo.aircraft_position();
var cpos = geo.Coord.new();
var lat = me.cloudNode.getNode("position/latitude-deg").getValue();
var lon = me.cloudNode.getNode("position/longitude-deg").getValue();
cpos.set_latlon(lat,lon,0.0);
return pos.distance_to(cpos);
},
get_course: func {
var pos = geo.aircraft_position();
var cpos = geo.Coord.new();
var lat = me.cloudNode.getNode("position/latitude-deg").getValue();
var lon = me.cloudNode.getNode("position/longitude-deg").getValue();
cpos.set_latlon(lat,lon,0.0);
return pos.course_to(cpos);
},
get_altitude: func {
return me.cloudNode.getNode("position/altitude-ft").getValue();
},
};
###################
# helper functions
@ -675,3 +1073,15 @@ var get_lon = func (x,y,phi) {
return (x * math.cos(phi) + y * math.sin(phi)) * m_to_lon;
}
var delete_from_vector = func(vec, index) {
var n = index+1;
var vec_end = subvec(vec, n);
setsize(vec, n-1);
return vec~vec_end;
}

View file

@ -21,8 +21,16 @@
var tile_start = func {
# set thread lock
if (getprop(lw~"tmp/thread-flag") == 1){setprop(lw~"tmp/thread-status","computing");}
# set the tile code
var current_code = getprop(lw~"tiles/code");
var dir_index = getprop(lw~"tiles/tmp/dir-index");
props.globals.getNode(lw~"tiles").getChild("tile",dir_index).getNode("code").setValue(current_code);
# generate a handling array for models
var array = [];
@ -39,14 +47,18 @@ setprop(lw~"clouds/placement-index",0);
setsize(elat,0); setsize(elon,0); setsize(erad,0);
var dir_index = getprop(lw~"tiles/tmp/dir-index");
props.globals.getNode(lw~"tiles").getChild("tile",dir_index).getNode("code").setValue(current_code);
#props.globals.getNode(lw~"tiles").getChild("tile",dir_index).getNode("code").setValue(current_code);
local_weather.assemble_effect_array();
print("Finished setting up tile type ",current_code, " in direction ",dir_index);
if (getprop(lw~"tmp/thread-flag") == 1){setprop(lw~"tmp/thread-status","placing");}
else {local_weather.assemble_effect_array();} # otherwise this is done at the end of the placement loop
if (getprop(lw~"tmp/thread-flag") == 1)
{setprop(lw~"tmp/thread-status","placing");}
else # without worker threads, tile generation is complete at this point
{props.globals.getNode(lw~"tiles").getChild("tile",dir_index).getNode("generated-flag").setValue(2);}
}
@ -59,10 +71,10 @@ else {local_weather.assemble_effect_array();} # otherwise this is done at the en
var set_4_8_stratus_tile = func {
tile_start();
setprop(lw~"tiles/code","test");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -87,6 +99,8 @@ local_weather.set_weather_station(blat, blon, 20000.0, 14.0, 12.0, 29.78);
create_4_8_cirrocumulus_bank(blat, blon, 6000.0, 0.0);
#create_detailed_stratocumulus_bank(blat, blon,5000.0+alt_offset,0.0);
tile_finished();
@ -99,10 +113,10 @@ tile_finished();
var set_high_pressure_core_tile = func {
tile_start();
setprop(lw~"tiles/code","high_pressure_core");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -148,10 +162,10 @@ tile_finished();
var set_high_pressure_tile = func {
tile_start();
setprop(lw~"tiles/code","high_pressure");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -186,36 +200,32 @@ var alt = spread * 1000;
var rn = rand();
if (rn > 0.5)
if (rn > 0.66)
{
# cloud scenario 1: possible Cirrus over Cumulus
var strength = 0.2 + rand() * 0.4;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
# if cumulus are weak, increase likelihood of Cirrus (the logic is the other way round
# but this makes no difference and is easier to implement)
# one or two Cirrus clouds
# try to place two spatially separated Cirrus clouds
if (rand() > 2.0 * strength)
{
x = 2000.0 + rand() * 16000.0;
y = 2.0 * (rand()-0.5) * 18000;
alt = 25000.0 + rand() * 5000.0;
var path = local_weather.select_cloud_model("Cirrus", "small");
compat_layer.create_cloud(path, blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), alt + alt_offset,alpha);
}
if (rand() > 2.0 * strength)
x = 2000.0 + rand() * 16000.0;
y = 2.0 * (rand()-0.5) * 18000;
alt = 25000.0 + rand() * 5000.0;
var path = local_weather.select_cloud_model("Cirrus", "small");
compat_layer.create_cloud(path, blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), alt + alt_offset,alpha);
if (rand() > 0.5)
{
x = -2000.0 - rand() * 16000.0;
y = 2.0 * (rand()-0.5) * 18000;
alt = 25000.0 + rand() * 5000.0;
var path = local_weather.select_cloud_model("Cirrus", "small");
compat_layer.create_cloud(path, blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), alt + alt_offset,alpha);
}
}
}
else if (rn > 0.0)
else if (rn > 0.33)
{
# cloud scenario 2: Cirrostratus over weak Cumulus
@ -225,6 +235,22 @@ else if (rn > 0.0)
create_2_8_cirrostratus(blat, blon, alt+alt_offset+25000.0, alpha);
}
else if (rn > 0.0)
{
# cloud scenario 3: Cirrocumulus sheet over Cumulus
var strength = 0.2 + rand() * 0.2;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
x = 2.0 * (rand()-0.5) * 5000;
y = 2.0 * (rand()-0.5) * 5000;
var path = local_weather.select_cloud_model("Cirrocumulus", "large");
compat_layer.create_cloud(path, blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), alt + alt_offset +24000,alpha);
}
tile_finished();
}
@ -236,10 +262,10 @@ tile_finished();
var set_high_pressure_border_tile = func {
tile_start();
setprop(lw~"tiles/code","high_pressure_border");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -340,17 +366,23 @@ else if (rn > 0.166)
}
else if (rn > 0.0)
{
# cloud scenario 6: Cirrocumulus
# cloud scenario 6: Cirrocumulus sheets
var strength = 0.2 + rand() * 0.2;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
x = 2.0 * (rand()-0.5) * 5000;
y = 2.0 * (rand()-0.5) * 5000;
for (var i = 0; i < 2; i = i + 1)
{
x = 2.0 * (rand()-0.5) * 10000;
y = -6000 + i * 12000 + 2.0 * (rand()-0.5) * 1000;
var path = local_weather.select_cloud_model("Cirrocumulus", "large");
compat_layer.create_cloud(path, blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), alt + alt_offset +22000,alpha);
var beta = rand() * 90;
var alt_variation = rand() * 2000;
var path = local_weather.select_cloud_model("Cirrocumulus", "large");
compat_layer.create_cloud(path, blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), alt + alt_offset +20000+ alt_variation,alpha+ beta);
}
}
@ -366,10 +398,10 @@ tile_finished();
var set_low_pressure_border_tile = func {
tile_start();
setprop(lw~"tiles/code","low_pressure_border");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -408,7 +440,7 @@ var alt = spread * 1000.0;
var rn = rand();
if (rn > 0.75)
if (rn > 0.8)
{
# cloud scenario 1: a low 4/8 stratus patches, thin patches above
@ -416,7 +448,7 @@ if (rn > 0.75)
create_4_8_stratus_patches(blat, blon, alt+alt_offset,alpha);
create_4_8_tstratus_patches(blat, blon, alt+alt_offset+6000,alpha);
}
else if (rn > 0.5)
else if (rn > 0.6)
{
# cloud scenario 2: a low 4/8 undulatus, thin patches above
@ -424,25 +456,33 @@ else if (rn > 0.5)
create_4_8_sstratus_undulatus(blat, blon, alt+alt_offset,alpha);
create_2_8_tstratus(blat, blon, alt+alt_offset+7000,alpha);
}
else if (rn > 0.25)
else if (rn > 0.4)
{
# cloud scenario 3: low Stratocumulus
alt = alt + local_weather.cloud_vertical_size_map["Stratus"] * 0.5 * m_to_ft;
create_stratocumulus_bank(blat, blon, alt+alt_offset,alpha);
create_2_8_sstratus(blat, blon, alt+alt_offset+3000,alpha);
# alt = alt + local_weather.cloud_vertical_size_map["Cumulus"] * 0.5 * m_to_ft;
create_detailed_stratocumulus_bank(blat, blon, alt+alt_offset,alpha);
create_2_8_sstratus(blat, blon, alt+alt_offset+6000,alpha);
create_2_8_tstratus(blat, blon, alt+alt_offset+9000,alpha);
}
else if (rn > 0.0)
else if (rn > 0.2)
{
# cloud scenario 4: dense low Stratocumulus
alt = alt + local_weather.cloud_vertical_size_map["Stratus"] * 0.5 * m_to_ft;
create_stratocumulus_bank(blat, blon, alt+alt_offset,alpha);
create_stratocumulus_bank(blat, blon, alt+alt_offset,alpha);
# alt = alt + local_weather.cloud_vertical_size_map["Cumulus"] * 0.5 * m_to_ft;
create_detailed_stratocumulus_bank(blat, blon, alt+alt_offset,alpha);
create_detailed_stratocumulus_bank(blat, blon, alt+alt_offset,alpha);
create_2_8_sstratus(blat, blon, alt+alt_offset+8000,alpha);
}
else if (rn > 0.0)
{
# cloud scenario 5: Cirrocumulus over 4/8 Stratus
alt = alt + local_weather.cloud_vertical_size_map["Stratus"] * 0.5 * m_to_ft;
create_4_8_sstratus_patches(blat, blon, alt+alt_offset,alpha);
create_4_8_cirrocumulus_bank(blat, blon, alt+alt_offset + 12000.0, alpha);
}
tile_finished();
@ -454,10 +494,10 @@ tile_finished();
var set_low_pressure_tile = func {
tile_start();
setprop(lw~"tiles/code","low_pressure");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -565,10 +605,10 @@ tile_finished();
var set_low_pressure_core_tile = func {
tile_start();
setprop(lw~"tiles/code","low_pressure_core");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -633,10 +673,10 @@ tile_finished();
var set_cold_sector_tile = func {
tile_start();
setprop(lw~"tiles/code","cold_sector");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -668,14 +708,37 @@ var alt = spread * 1000.0;
var rn = rand();
#rn = 0.1;
if (rn > 0.0)
if (rn > 0.5)
{
# cloud scenario 1: strong Cumulus development
var strength = 0.8 + rand() * 0.2;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
}
else if (rn > 0.0)
{
# cloud scenario 2: Cirrocumulus sheets over Cumulus
var strength = 0.6 + rand() * 0.2;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
for (var i = 0; i < 2; i = i + 1)
{
x = 2.0 * (rand()-0.5) * 10000;
y = -6000 + i * 12000 + 2.0 * (rand()-0.5) * 1000;
var beta = rand() * 90;
var alt_variation = rand() * 2000;
var path = local_weather.select_cloud_model("Cirrocumulus", "large");
compat_layer.create_cloud(path, blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), alt + alt_offset +20000+ alt_variation,alpha+ beta);
}
}
tile_finished();
}
@ -687,10 +750,10 @@ tile_finished();
var set_warm_sector_tile = func {
tile_start();
setprop(lw~"tiles/code","warm_sector");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -789,10 +852,10 @@ tile_finished();
var set_tropical_weather_tile = func {
tile_start();
setprop(lw~"tiles/code","tropical_weather");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -907,10 +970,10 @@ tile_finished();
var set_coldfront_tile = func {
tile_start();
setprop(lw~"tiles/code","coldfront");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -976,7 +1039,7 @@ y = 5000.0;
var strength = 0.3;
var n = int(4000 * strength) * 0.2;
local_weather.cumulus_exclusion_layer(blat+get_lat(x,y,phi), blon+ get_lon(x,y,phi), alt+alt_offset, n, 20000.0, 10000.0, alpha, 2.1,2.5 , size(elat), elat, elon, erad);
local_weather.cumulus_exclusion_layer(blat+get_lat(x,y,phi), blon+ get_lon(x,y,phi), alt+alt_offset, n, 20000.0, 10000.0, alpha, 1.5,2.5 , size(elat), elat, elon, erad);
# then leading and traling Cumulus
@ -985,14 +1048,14 @@ y = 15500.0;
strength = 1.0;
n = int(4000 * strength) * 0.15;
local_weather.cumulus_exclusion_layer(blat+get_lat(x,y,phi), blon+ get_lon(x,y,phi), alt+alt_offset, n, 20000.0, 2000.0, alpha, 0.5,1.4 , size(elat), elat, elon, erad);
local_weather.cumulus_exclusion_layer(blat+get_lat(x,y,phi), blon+ get_lon(x,y,phi), alt+alt_offset, n, 20000.0, 2000.0, alpha, 0.5,1.8 , size(elat), elat, elon, erad);
x = 0.0;
y = -5500.0;
strength = 1.0;
n = int(4000 * strength) * 0.15;
local_weather.cumulus_exclusion_layer(blat+get_lat(x,y,phi), blon+ get_lon(x,y,phi), alt+alt_offset, n, 20000.0, 2000.0, alpha, 0.5,1.4 , size(elat), elat, elon, erad);
local_weather.cumulus_exclusion_layer(blat+get_lat(x,y,phi), blon+ get_lon(x,y,phi), alt+alt_offset, n, 20000.0, 2000.0, alpha, 0.5,1.8 , size(elat), elat, elon, erad);
# finally some thin stratus underneath the Cumulus
@ -1028,10 +1091,10 @@ tile_finished();
var set_warmfront1_tile = func {
tile_start();
setprop(lw~"tiles/code","warmfront1");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -1084,11 +1147,11 @@ var alt = spread * 1000.0;
# high Cirrus leading
x = 2.0 * (rand()-0.5) * 3000;
y = 2.0 * (rand()-0.5) * 3000 - 12000.0;
x = 2.0 * (rand()-0.5) * 1000;
y = 2.0 * (rand()-0.5) * 1000 - 9000.0;
local_weather.create_streak("Cirrus",blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 25000.0+alt+alt_offset,1500.0,3,11000.0,0.0, 800.0, 1,8000.0,0.0,10000.0,alpha ,1.0);
local_weather.create_streak("Cirrus",blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 25000.0+alt+alt_offset,1500.0,3,11000.0,0.0, 3000.0, 2,11000.0,0.0,3000.0,alpha ,1.0);
# followed by random patches of Cirrostratus
@ -1114,10 +1177,10 @@ tile_finished();
var set_warmfront2_tile = func {
tile_start();
setprop(lw~"tiles/code","warmfront2");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -1223,10 +1286,10 @@ tile_finished();
var set_warmfront3_tile = func {
tile_start();
setprop(lw~"tiles/code","warmfront3");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -1320,10 +1383,10 @@ tile_finished();
var set_warmfront4_tile = func {
tile_start();
setprop(lw~"tiles/code","warmfront4");
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
@ -1405,242 +1468,11 @@ tile_finished();
}
####################################
# Altocumulus sky
# cloud count 1400/tile
####################################
var set_altocumulus_tile = func {
tile_start();
var alpha = getprop(lw~"tmp/tile-orientation-deg");
var phi = alpha * math.pi/180.0;
var alt_offset = getprop(lw~"tmp/tile-alt-offset-ft");
# get tile center coordinates
var blat = getprop(lw~"tiles/tmp/latitude-deg");
var blon = getprop(lw~"tiles/tmp/longitude-deg");
calc_geo(blat);
# first weather info for tile center (lat, lon, visibility, temperature, dew point, pressure)
local_weather.set_weather_station(blat, blon, 35000.0, 22.0, 14.0, 30.02);
# then draw the Altocumulus streaks, dense at 15.000 ft, sparse at 17.000 ft
local_weather.create_streak("Altocumulus",blat, blon, 15000.0+alt_offset,1500.0,40,1000.0,0.2,800.0, 40,1000.0,0.2,800.0,alpha ,1.0);
local_weather.create_streak("Altocumulus",blat, blon, 17000.0+alt_offset,1500.0,18,2000.0,0.35,800.0,18,2000.0,0.35,800.0,alpha,1.0);
tile_finished();
}
####################################
# Overcast stratus sky
# cloud count 1000/tile
####################################
var set_overcast_stratus_tile = func {
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
var lon = 0.0;
var alpha = getprop(lw~"tmp/tile-orientation-deg");
var phi = alpha * math.pi/180.0;
var alt_offset = getprop(lw~"tmp/tile-alt-offset-ft");
# get tile center coordinates
var blat = getprop(lw~"tiles/tmp/latitude-deg");
var blon = getprop(lw~"tiles/tmp/longitude-deg");
calc_geo(blat);
# first weather info for tile center (lat, lon, visibility, temperature, dew point, pressure)
local_weather.set_weather_station(blat, blon, 10000.0, 14.0, 12.0, 29.78);
# then draw the Stratus layers
var size_offset = 0.5 * m_to_ft * local_weather.cloud_vertical_size_map["Stratus"];
local_weather.create_streak("Stratus",blat, blon, 1500.0+alt_offset+size_offset,0.0,32,1250.0,0.2,600.0, 32,1250.0,0.2,600.0,0.0 ,1.0);
size_offset = 0.5 * m_to_ft * local_weather.cloud_vertical_size_map["Stratus_structured"];
local_weather.create_streak("Stratus (structured)",blat, blon, 5000.0+alt_offset+size_offset,0.0,16,2500.0,0.3,1200.0,16,2500.0,0.3,1200.0,0.0,1.0);
# reduce visibility even more below lowest layer
# and add a slight drizzle by a nested effect volume
local_weather.create_effect_volume(3, blat, blon, 18000.0, 18000.0, 0.0, 0.0, 1800.0, 8000.0, -1, -1, -1, -1, 0);
local_weather.create_effect_volume(3, blat, blon, 14000.0, 14000.0, 0.0, 0.0, 1500.0, 6000.0, 0.1, -1, -1, -1,0 );
tile_finished();
}
####################################
# Incoming rainfront
# cloud count 1500/tile
####################################
var set_rainfront_tile = func {
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
var lon = 0.0;
var alpha = getprop(lw~"tmp/tile-orientation-deg");
var phi = alpha * math.pi/180.0;
var alt_offset = getprop(lw~"tmp/tile-alt-offset-ft");
# get tile center coordinates
var blat = getprop(lw~"tiles/tmp/latitude-deg");
var blon = getprop(lw~"tiles/tmp/longitude-deg");
calc_geo(blat);
# first weather info for tile center (lat, lon, visibility, temperature, dew point, pressure)
local_weather.set_weather_station(blat, blon, 9000.0, 14.0, 12.0, 990 * hp_to_inhg);
x = 15000.0; y = 20000.0;
local_weather.set_weather_station(blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 6000.0, 12.0, 10.0, 985 * hp_to_inhg);
x = -15000.0; y = 20000.0;
local_weather.set_weather_station(blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 6000.0, 12.0, 10.0, 990 * hp_to_inhg);
# draw two Stratus layers
x = 0.0; y = -15000.0;
var size_offset = 0.5 * m_to_ft * local_weather.cloud_vertical_size_map["Stratus"];
local_weather.create_streak("Stratus",blat, blon, 3000.0+alt_offset+size_offset,500.0,17,2500.0,0.2,1100.0, 6,2000.0,0.2,1100.0,alpha ,1.0);
x = 0.0; y = 0.0;
var size_offset = 0.5 * m_to_ft * local_weather.cloud_vertical_size_map["Stratus"];
local_weather.create_streak("Stratus",blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 2000.0+alt_offset+size_offset,300.0,40,1000.0,0.2,600.0, 10,1000.0,0.2,600.0,alpha ,1.0);
# and a Nimbus layer with precipitation
x = 0.0; y = 15000.0;
var size_offset = 0.5 * m_to_ft * local_weather.cloud_vertical_size_map["Nimbus"];
local_weather.create_layer("Nimbus", blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 1000.0+alt_offset, 500.0, 22000.0, 13000.0, alpha, 1.0, 0.2, 1, 1.0);
# set visibility and rain inside the precipitation area
local_weather.create_effect_volume(2, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 19000.0, 10000.0, alpha, 0.0, 2000.0, 5000.0, 0.1, -1, -1, -1,0 );
local_weather.create_effect_volume(2, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 16000.0, 7000.0, alpha, 0.0, 1500.0, 1500.0, 0.5, -1, -1, -1,0 );
# set visibility good above the clouds
local_weather.create_effect_volume(3, blat, blon, 20000.0, 20000.0, 0.0, 2100.0, 85000.0, 18000.0, -1, -1, -1, -1,0 );
tile_finished();
}
####################################
# Broken layers
# cloud count 550/tile
####################################
var set_broken_layers_tile = func {
tile_start();
var alpha = getprop(lw~"tmp/tile-orientation-deg");
var phi = alpha * math.pi/180.0;
var alt_offset = getprop(lw~"tmp/tile-alt-offset-ft");
# get tile center coordinates
var blat = getprop(lw~"tiles/tmp/latitude-deg");
var blon = getprop(lw~"tiles/tmp/longitude-deg");
calc_geo(blat);
# first weather info for tile center (lat, lon, visibility, temperature, dew point, pressure)
local_weather.set_weather_station(blat, blon, 20000.0, 14.0, 12.0, 1005 * hp_to_inhg);
# set the broken stratus layers
size_offset = 0.5 * m_to_ft * local_weather.cloud_vertical_size_map["Stratus_structured"];
local_weather.create_streak("Stratus (structured)",blat, blon, 4000.0+alt_offset+size_offset,1000.0,22,0.0,0.3,20000.0,22,0.0,0.3,20000.0,0.0,1.0);
local_weather.create_streak("Stratus (structured)",blat, blon, 6000.0+alt_offset+size_offset,1000.0,16,0.0,0.4,20000.0,16,0.0,0.4,20000.0,0.0,1.0);
local_weather.create_streak("Stratus (structured)",blat, blon, 7000.0+alt_offset+size_offset,1000.0,11,0.0,0.5,20000.0,11,0.0,0.5,20000.0,0.0,1.0);
tile_finished();
}
####################################
# Fair weather and Cumulus
# cloud count max. 800/tile
####################################
var set_fair_weather_tile = func {
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
var lon = 0.0;
var alpha = getprop(lw~"tmp/tile-orientation-deg");
var phi = alpha * math.pi/180.0;
var alt_offset = getprop(lw~"tmp/tile-alt-offset-ft");
# get tile center coordinates
var blat = getprop(lw~"tiles/tmp/latitude-deg");
var blon = getprop(lw~"tiles/tmp/longitude-deg");
calc_geo(blat);
# first weather info for tile center (lat, lon, visibility, temperature, dew point, pressure)
local_weather.set_weather_station(blat, blon, 35000.0, 20.0, 16.0, 1018 * hp_to_inhg);
# add convective clouds
var strength = 1.0;
var n = int(4000 * strength); # calculate the number of placement tries from tile size 20x20km and strength
local_weather.create_cumosys(blat,blon, 3000.0 + alt_offset, n, 20000.0);
tile_finished();
}
####################################
@ -1649,6 +1481,8 @@ tile_finished();
var set_gliders_sky_tile = func {
setprop(lw~"tiles/code","glides_sky");
tile_start();
var x = 0.0;
@ -1691,6 +1525,8 @@ tile_finished();
var set_blue_thermals_tile = func {
setprop(lw~"tiles/code","blue_thermals");
tile_start();
var x = 0.0;
@ -1728,121 +1564,7 @@ tile_finished();
}
####################################
# Summer rain
# cloud count max. 1200/tile
####################################
var set_summer_rain_tile = func {
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
var lon = 0.0;
var alpha = getprop(lw~"tmp/tile-orientation-deg");
var phi = alpha * math.pi/180.0;
var alt_offset = getprop(lw~"tmp/tile-alt-offset-ft");
# get tile center coordinates
var blat = getprop(lw~"tiles/tmp/latitude-deg");
var blon = getprop(lw~"tiles/tmp/longitude-deg");
calc_geo(blat);
# first weather info for tile center (lat, lon, visibility, temperature, dew point, pressure)
local_weather.set_weather_station(blat, blon, 25000.0, 25.0, 22.0, 1013 * hp_to_inhg);
# then add some developing thunderstorms
local_weather.create_streak("Cumulonimbus (rain)",blat, blon, 3000.0+alt_offset,0.0,3,0.0,1.0,20000.0,3,0.0,1.0,20000.0,0.0,1.0);
# add overdeveloped convective clouds
var strength = 1.5;
var n = int(4000 * strength); # calculate the number of placement tries from tile size 20x20km and strength
local_weather.create_cumosys(blat,blon, 3000.0+alt_offset,n, 20000.0);
tile_finished();
}
####################################
# Cirrus sky
####################################
var set_cirrus_sky_tile = func {
tile_start();
var x = 0.0;
var y = 0.0;
var lat = 0.0;
var lon = 0.0;
var alpha = getprop(lw~"tmp/tile-orientation-deg");
var phi = alpha * math.pi/180.0;
var alt_offset = getprop(lw~"tmp/tile-alt-offset-ft");
# get tile center coordinates
var blat = getprop(lw~"tiles/tmp/latitude-deg");
var blon = getprop(lw~"tiles/tmp/longitude-deg");
calc_geo(blat);
# first weather info for tile center (lat, lon, visibility, temperature, dew point, pressure)
local_weather.set_weather_station(blat, blon, 20000.0, 20.0, 16.0, 29.80);
# visibility is slightly worse north, pressure is lower, so set additional stations
x = -10000.0; y = 18000.0;
lat = blat + (y * math.cos(phi) - x * math.sin(phi)) * m_to_lat;
lon = blon + (x * math.cos(phi) + y * math.sin(phi)) * m_to_lon;
local_weather.set_weather_station(lat, lon, 18000.0, 20.0, 16.0, 29.75);
x = 10000.0; y = 18000.0;
lat = blat + (y * math.cos(phi) - x * math.sin(phi)) * m_to_lat;
lon = blon + (x * math.cos(phi) + y * math.sin(phi)) * m_to_lon;
local_weather.set_weather_station(lat, lon, 18000.0, 20.0, 16.0, 29.75);
# now set up the clouds
x = 0.0; y = 0.0;
compat_layer.create_cloud("Models/Weather/cirrus1.xml", blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), 28000.0 + alt_offset,alpha);
x = 7500.0; y = 1000.0;
compat_layer.create_cloud("Models/Weather/cirrus2.xml", blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), 28500.0 + alt_offset,alpha);
x = 16000.0; y = -1000.0;
compat_layer.create_cloud("Models/Weather/cirrus1.xml", blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), 29500.0 + alt_offset,alpha);
x = -16000.0; y = 2500.0;
compat_layer.create_cloud("Models/Weather/cirrus1.xml",blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), 30000.0 + alt_offset,alpha);
x = 7000.0; y = 8000.0;
compat_layer.create_cloud("Models/Weather/cirrocumulus1.xml", blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), 22000.0 + alt_offset,alpha);
x = -3000.0; y = 9000.0;
compat_layer.create_cloud("Models/Weather/cirrocumulus1.xml", blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), 21000.0 + alt_offset,alpha);
x = -1000.0; y = 14000.0;
compat_layer.create_cloud("Models/Weather/cirrocumulus2.xml", blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), 20000.0 + alt_offset,alpha);
# add moderately strong convective clouds
var strength = 0.4;
var n = int(4000 * strength); # calculate the number of placement tries from tile size 20x20km and strength
local_weather.create_cumosys(blat,blon, 4000.0+alt_offset,n, 20000.0);
tile_finished();
}
####################################
@ -1851,6 +1573,9 @@ tile_finished();
var set_METAR_tile = func {
setprop(lw~"tiles/code","METAR"); # to be replaced
tile_start();
var x = 0.0;
@ -1858,7 +1583,7 @@ var y = 0.0;
var lat = 0.0;
var lon = 0.0;
setprop(lw~"tiles/code","METAR"); # to be replaced
var alpha = getprop(lw~"METAR/wind-direction-deg");
var phi = alpha * math.pi/180.0;
@ -2163,10 +1888,10 @@ var create_4_8_cirrocumulus_bank = func (lat, lon, alt, alpha) {
var phi = alpha * math.pi/180.0;
var x = 2.0 * (rand()-0.5) * 5000;
var y = 2.0 * (rand()-0.5) * 5000;
var tri = 1.4 + 0.6 *rand();
var tri = 1.5 + 1.5 *rand();
var beta = (rand() -0.5) * 60.0;
local_weather.create_streak("Cirrocumulus (cloudlet)",lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt,900.0,15,750.0,0.2,400.0,24,750.0,0.2,400.0,alpha+90.0+beta,tri);
local_weather.create_streak("Cirrocumulus (cloudlet)",lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt,400.0,12,750.0,0.25,400.0,24,750.0,0.2,400.0,alpha+90.0+beta,tri);
}
@ -2179,7 +1904,7 @@ var y = 2.0 * (rand()-0.5) * 5000;
var tri = 1.4 + 0.6 *rand();
var beta = (rand() -0.5) * 60.0;
local_weather.create_streak("Cirrocumulus (cloudlet)",lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt,900.0,25,300.0,0.0,900.0,15,1400.0,0.0,300.0,alpha+90.0+beta,tri);
local_weather.create_streak("Cirrocumulus (cloudlet)",lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt,400.0,25,300.0,0.0,900.0,15,1400.0,0.0,300.0,alpha+90.0+beta,tri);
}
@ -2293,6 +2018,28 @@ local_weather.create_streak("Cumulus",lat+get_lat(x,y-6000,phi), lon+get_lon(x,y
}
var create_detailed_stratocumulus_bank = func (lat, lon, alt, alpha) {
var phi = alpha * math.pi/180.0;
var x = 2.0 * (rand()-0.5) * 6000;
var y = 2.0 * (rand()-0.5) * 6000;
var tri = 1.5 + 1.5*rand();
var beta = (rand() -0.5) * 60.0;
var alt_offset = 0.5 * local_weather.cloud_vertical_size_map["Cumulus"] * ft_to_m;
local_weather.create_streak("Congestus",lat+get_lat(x,y+7500,phi), lon+get_lon(x,y+7500,phi), alt + alt_offset,500.0,12,1000.0,0.1,400.0,15,1000.0,0.1,400.0,alpha+90.0+beta,tri);
local_weather.create_streak("Congestus",lat+get_lat(x,y-7500,phi), lon+get_lon(x,y-7500,phi), alt + alt_offset,500.0,12,1000.0,0.1,400.0,15,1000.0,0.1,400.0,alpha+270.0+beta,tri);
local_weather.create_streak("Congestus bottom",lat+get_lat(x,y+5250,phi), lon+get_lon(x,y+5250,phi), alt,0.0,10,700.0,0.2,400.0,15,700.0,0.0,400.0,alpha+90.0+beta,tri);
local_weather.create_streak("Congestus bottom",lat+get_lat(x,y-5250,phi), lon+get_lon(x,y-5250,phi), alt,0.0,10,700.0,0.2,400.0,15,700.0,0.0,400.0,alpha+270.0+beta,tri);
}
var create_cloud_bank = func (type, lat, lon, alt, x1, x2, height, n, alpha) {
local_weather.create_streak(type,lat,lon, alt+ 0.5* height,height,n,0.0,0.0,x1,1,0.0,0.0,x2,alpha,1.0);

View file

@ -54,7 +54,7 @@ void main(void)
gl_FrontColor += gl_FrontLightModelProduct.sceneColor;
// As we get within 100m of the sprite, it is faded out. Equally at large distances it also fades out.
gl_FrontColor.a = min(smoothstep(100.0, 300.0, fogCoord), 1 - smoothstep(25000.0, 30000.0, fogCoord));
gl_FrontColor.a = min(smoothstep(100.0, 300.0, fogCoord), 1 - smoothstep(40000.0, 45000.0, fogCoord));
gl_BackColor = gl_FrontColor;
// Fog doesn't affect clouds as much as other objects.

View file

@ -3,7 +3,7 @@
varying float fogFactor;
float shade = 0.6;
float shade = 0.4;
float cloud_height = 1000.0;
void main(void)
@ -39,6 +39,7 @@ void main(void)
// Determine the position - used for fog and shading calculations
vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Position);
float fogCoord = abs(ecPosition.z);
//float fract = smoothstep(0.0, cloud_height, gl_Position.z + cloud_height);
float fract = smoothstep(0.0, cloud_height, gl_Position.z + cloud_height);
// Final position of the sprite
@ -53,7 +54,7 @@ void main(void)
gl_FrontColor += gl_FrontLightModelProduct.sceneColor;
// As we get within 100m of the sprite, it is faded out. Equally at large distances it also fades out.
gl_FrontColor.a = min(smoothstep(10.0, 100.0, fogCoord), 1 - smoothstep(15000.0, 20000.0, fogCoord));
gl_FrontColor.a = min(smoothstep(10.0, 100.0, fogCoord), 1 - smoothstep(40000.0, 45000.0, fogCoord));
gl_BackColor = gl_FrontColor;
// Fog doesn't affect clouds as much as other objects.

View file

@ -63,7 +63,7 @@ void main(void)
gl_FrontColor += gl_FrontLightModelProduct.sceneColor;
// As we get within 100m of the sprite, it is faded out. Equally at large distances it also fades out.
gl_FrontColor.a = min(smoothstep(10.0, 100.0, fogCoord), 1 - smoothstep(15000.0, 20000.0, fogCoord));
gl_FrontColor.a = min(smoothstep(10.0, 100.0, fogCoord), 1 - smoothstep(40000.0, 45000.0, fogCoord));
gl_BackColor = gl_FrontColor;
// Fog doesn't affect clouds as much as other objects.

View file

@ -54,7 +54,7 @@ void main(void)
gl_FrontColor += gl_FrontLightModelProduct.sceneColor;
// As we get within 100m of the sprite, it is faded out. Equally at large distances it also fades out.
gl_FrontColor.a = min(smoothstep(100.0, 300.0, fogCoord), 1 - smoothstep(25000.0, 30000.0, fogCoord));
gl_FrontColor.a = min(smoothstep(100.0, 300.0, fogCoord), 1 - smoothstep(40000.0, 45000.0, fogCoord));
gl_BackColor = gl_FrontColor;
// Fog doesn't affect clouds as much as other objects.

View file

@ -241,6 +241,7 @@
<property>/local-weather/tmp/cloud-type</property>
<value>Altocumulus</value>
<value>Cirrus</value>
<value>Cirrocumulus (cloudlet)</value>
<value>Cirrostratus</value>
<value>Cumulus</value>
<value>Cumulus (cloudlet)</value>

View file

@ -0,0 +1,273 @@
<?xml version="1.0"?>
<PropertyList>
<!-- Weather tiles -->
<name>local_weather_config</name>
<width>400</width>
<height>400</height>
<modal>false</modal>
<text>
<x>5</x>
<y>370</y>
<label>Tile creation settings </label>
</text>
<text>
<x>60</x>
<y>340</y>
<label>loading distance</label>
</text>
<text>
<x>10</x>
<y>320</y>
<label>25 km</label>
</text>
<slider>
<x>60</x>
<y>320</y>
<width>100</width>
<height>20</height>
<min>25000.0</min>
<max>55000.0</max>
<property>/local-weather/config/distance-to-load-tile-m</property>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<x>170</x>
<y>320</y>
<label>55 km</label>
</text>
<checkbox>
<x>250</x>
<y>350</y>
<width>15</width>
<height>15</height>
<label>asymmetric range</label>
<property>/local-weather/tmp/asymmetric-tile-loading-flag</property>
<binding>
<command>dialog-apply</command>
</binding>
</checkbox>
<text>
<x>220</x>
<y>320</y>
<label>0.5</label>
</text>
<slider>
<x>250</x>
<y>320</y>
<width>100</width>
<height>20</height>
<min>0.5</min>
<max>1.0</max>
<property>/local-weather/config/asymmetric-reduction</property>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<x>360</x>
<y>320</y>
<label>1.0</label>
</text>
<text>
<x>5</x>
<y>280</y>
<label>Cloud buffering settings</label>
</text>
<text>
<x>60</x>
<y>260</y>
<label>visible range</label>
</text>
<text>
<x>10</x>
<y>240</y>
<label>15 km</label>
</text>
<slider>
<x>60</x>
<y>240</y>
<width>100</width>
<height>20</height>
<min>15000.0</min>
<max>45000.0</max>
<property>/local-weather/config/clouds-visible-range-m</property>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<x>170</x>
<y>240</y>
<label>45 km</label>
</text>
<checkbox>
<x>250</x>
<y>270</y>
<width>15</width>
<height>15</height>
<label>asymmetric buffering</label>
<property>/local-weather/config/asymmetric-buffering-flag</property>
<binding>
<command>dialog-apply</command>
</binding>
</checkbox>
<text>
<x>220</x>
<y>240</y>
<label>0.2</label>
</text>
<slider>
<x>250</x>
<y>240</y>
<width>100</width>
<height>20</height>
<min>0.2</min>
<max>1.0</max>
<property>/local-weather/config/asymmetric-buffering-reduction</property>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<x>360</x>
<y>240</y>
<label>1.0</label>
</text>
<text>
<x>170</x>
<y>210</y>
<label>angle:</label>
</text>
<text>
<x>220</x>
<y>210</y>
<label>0.0</label>
</text>
<slider>
<x>250</x>
<y>210</y>
<width>100</width>
<height>20</height>
<min>0.0</min>
<max>180.0</max>
<property>/local-weather/config/asymmetric-buffering-angle-deg</property>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<x>360</x>
<y>210</y>
<label>180</label>
</text>
<text>
<x>5</x>
<y>160</y>
<label>Weather dynamics settings</label>
</text>
<text>
<x>60</x>
<y>140</y>
<label>max. clouds in loop</label>
</text>
<text>
<x>10</x>
<y>120</y>
<label>100</label>
</text>
<slider>
<x>60</x>
<y>120</y>
<width>100</width>
<height>20</height>
<min>100</min>
<max>400</max>
<property>/local-weather/config/clouds-in-dynamics-loop</property>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<x>170</x>
<y>120</y>
<label>400</label>
</text>
<group>
<x>10</x>
<y>10</y>
<button>
<x>0</x>
<y>0</y>
<legend>OK</legend>
<equal>true</equal>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>dialog-close</command>
</binding>
</button>
<button>
<x>135</x>
<y>0</y>
<legend>Cancel</legend>
<equal>true</equal>
<key>Esc</key>
<binding>
<command>dialog-close</command>
</binding>
</button>
</group>
</PropertyList>

View file

@ -333,6 +333,13 @@
<dialog-name>local_weather_tiles</dialog-name>
</binding>
</item>
<item>
<label>Local Weather Settings</label>
<binding>
<command>dialog-show</command>
<dialog-name>local_weather_config</dialog-name>
</binding>
</item>
</menu>
<menu>