+The following pictures show possible results of tile setups 'High-pressure-border' and 'Low-pressure':
+Static clouds project textures onto curved sheets into the sky. The advantage of the technique is that cloud layers consisting of thousands of cloudlets with different sizes can be modelled. However, the sheets do not look equally well from all perspectives and somewhat unrealistic from close up.
+
+Rotated cloud models have the advantage that they look much better from close up and hardly unrealistic from any perspective, but the size distribution of cloudlets is somewhat restricted and they use a lot more performance than static clouds.
-These are rendered by a different technique: While the default Cumulus models consist of multiple layers rotated around the center of the model, the detailed Cumulus clouds consist of multiple (up to 24) individual cloudlets, rotating each around its own center, randomly distributed into a box. This not only improves the visual appearance, but also leads to a more realistic distribution of cloud sizes and shapes in the sky. In addition, when circling below the cloud (as done when soaring) the effect of the cloudlet rotation is less pronounced. The price to pay is that rendering detailed clouds costs about a factor 4 more performance, so they may not be suitable for all systems.
+These are rendered by different techniques. While the default Cumulus models consist of multiple layers rotated around the center of the model, the detailed Cumulus clouds consist of multiple (up to 24) individual cloudlets, rotating each around its own center, randomly distributed into a box with different texture types used for the cloud bottom. This not only improves the visual appearance, but also leads to a more realistic distribution of cloud sizes and shapes in the sky. In addition, when circling below the cloud (as done when soaring) the effect of the cloudlet rotation is less pronounced. The price to pay is that rendering detailed clouds costs more performance, so they may not be suitable for all systems.
More complex clouds are rendered in sandwitched layers of several different textures. An example are Cumulonimbus towers, which use diffuse textures on the bottom, changing to more structured textures in the upper part of the cloud. With up to 2000 cloudlets, skies with multiple thunderstorms may not render with sufficient framerates on every system.
@@ -178,7 +211,7 @@ The general problem is finding a good balance between spending a lot of CPU time
-Currently all clouds which need to be rotated are treated in the Shaders using a view-axis based rotation by two angles. This generally looks okay from a normal flight position, but rapid change of the view axis (looking around), especially straight up or down, causes unrealistic cloud movement. Any static picture of clouds however is (almost) guaranteed to look fine. This means that shader effects need to be 'on' in order to see most of the clouds.
+Currently all clouds which need to be rotated are treated in the shaders using a view-axis based rotation by two angles. This generally looks okay from a normal flight position, but rapid change of the view axis (looking around), especially straight up or down, causes unrealistic cloud movement. Any static picture of clouds however is (almost) guaranteed to look fine. This means that shader effects need to be 'on' in order to see most of the clouds.
-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.
+In version 0.9, thermal lift and wave lift are implemented by function (wave lift is not yet automatically placed, but can be easily from Nasal). There is no easy way to implement any weather parameter by function in an effect volume, as this requires some amount of Nasal coding.
@@ -261,7 +294,7 @@ The first important call sets up the conditions to be interpolated:
-The cloud placement calls should be reasonably familiar, as they closely resemble the structure by which they are accessible from the menu. Note that for (rather stupid reasons) currently a randomize_pos call must follow a create_streak call.
+The cloud placement calls should be reasonably familiar, as they closely resemble the structure by which they are accessible from the 'Local Weather' menu.
If the cloud layer has an orientation, then all placement coordinates should be rotated accordingly. Similarly, each placement call should include the altitude offset. Take care to nest effect volumes properly where possible, otherwise undesired effects might occur...
@@ -281,7 +314,8 @@ With default settings, the local weather package generates a 40x40 km weather ti
The thermals in the soaring scenarios need GIT to work.
@@ -314,9 +350,9 @@ With default settings, the local weather package generates a 40x40 km weather ti
This section describes the more complicated cloud placement algorithms in some detail. It is intended for readers who are interested in understanding (and possibly modifying) what creates the weather they get to see.
-
The convective algorithm and the properties of thermals
+The convective startup algorithm and the properties of thermals
-The convective algorithm is used to place Cumulus clouds as well as thermals. Thermals are by default not placed to save CPU time unless a tile designed for soaring is selected, but they can be generated for any weather tile by setting local-weather/tmp/generate-thermal-lift-flag to either 1 (constant-strength thermals) or 2 (detailed thermal model).
+The convective startup algorithm is used to place Cumulus clouds as well as thermals. Thermals are by default not placed to save CPU time unless the flag is set in the menu.
At the core of the convective algorithm is the concept of locally available thermal energy. The source of this energy is solar radiation. The flux of solar energy depends on the angle of incident sunlight with the terrain surface. It is possibly (though computationally very expensive) to compute this quantity, but the algorithm uses a proxy instead. The daily angle of the sun at the equator assuming flat terrain is modelled as 0.5 * (1.0-cos(t/24.0*2pi)) with t expressed in hours, a function that varies between zero at midnight and 1 at noon. There is a geographical correction to this formula which goes with cos(latitude) , taking care of the fact that the sun does not reach the zenith at higher latitudes. Both the yearly summer/winter variation of the solar position in the sky and the terrain slope are neglected.
@@ -368,6 +404,32 @@ At sunset around 19:00 pm, the number of clouds decreases quickly, but there is
While not accurate in every respect, the model works fairly well to reproduce the actual time dependence of convective clouds and thermal lift during the day.
+
The convective dynamics algorithm
+
+The convective dynamics algorithm is responsible for modelling the life cycle of convective clouds, dependent on the terrain type underneath. It meshes well with the convective startup algorithm, and its long-term zero wind limit is just the situation set up by the initial convective placement.
+
+At its heart is the idea of fractional cloud lifetime. A cloud is born with fractional lifetime zero, and it decays once its fractional lifetime reaces 1. The translation of real time to fractional lifetime is given by sqrt(p) where p is the landcover dependent probability defined above. A cloud over landcover with maximum p of 0.35 has a lifetime of 30 minutes, so if a cloud spends 10 minutes over this terrain type, its fractional lifetime is increased by 1/3. If the landcover is different, the lifetime is reduced according to sqrt(p_1/p_max) .
+
+A cloud field is initialized with fractional lifetimes randomly distributed between zero and 1. To compensate for the decay of clouds, clouds are periodically respawned as in the startup algorithm, but with placement probability sqrt(p) instead of p . In the limit of no wind, the cloud density over a terrain type is then given by placement probability times lifetime, i.e. sqrt(p) * sqrt(p) = p as it should be. The presence of a windfield distorts the cloud distribution, dense clouds are then found preferably downwind of suitable convection sources.
+
+
The thermal lift model
+
+The model of the distribution of lift inside a thermal is quite complex.
+
+
+
+
+
+Vertically, is is characterized in addition to height and radius by two parameters, 'coning' and 'shaping', which make it cone-shaped and wasp-waisted. From zero to 200 m above ground, the lift is smoothly fading in, above the cloudbase it is smoothly faded out to zero at 10% above the nominal altitude. Horizontally, there is an outer ring where the air becomes turbulent, followed by a region of sink which in turn is followed by the inner core of lift.
+
+The distribution of lift and sink is time dependent.
+
+
+
+
+
+In a young thermal, lift starts to develop from the ground, sink is initially absent. When the lift reaches the cloudbase, sink starts to develop from the ground and rises up as well. Only in a mature thermal are sink and lift in equilibrium. When the thermal starts to decay, lift initially decays from the ground upward, till it reaches the cloudbase. At this time the cap cloud dissolves. For a time there is a residual distribution of sink decaying from bottom to top till the thermal evolution is over and the thermal (and the associate turbulence field) is removed.
+
The terrain presampling and cloud altitude determination algorithm
While the meaning of a cloud layer altitude is rather obvious in level terrain, this quickly becomes a highly non-trivial question in mountaineous terrain where the elevation of the terrain is more difficult to define. Observation of weather patterns in mountain regions suggests that clouds follow changes in terrain elevation to some degree, but not all cloud types do to the same degree. While convective clouds follow a change in elevation more readily even on small distance scales, layered clouds don't do so. The purpose of the terrain presampling and cloud altitude determination algorithm is to capture this behaviour as closely as possible.
@@ -434,10 +496,10 @@ Realistically, the boundary layer should also depend on terrain coverage. Due to
Credits
-The model of a thermal has been developed by Patrice Poly. The shader code used to transform clouds is heavily based on prior work by Stuart Buchanan.
+The model of a thermal has been developed by Patrice Poly. The shader code used to transform clouds is heavily based on prior work by Stuart Buchanan. Hard-coding of some features by Torsten Dreyer is greatly appreciated.
-Thorsten Renk, June 2010
+Thorsten Renk, October 2010
diff --git a/Docs/clouds-detailed01.jpg b/Docs/clouds-detailed01.jpg
index e380880e3..4136b78b3 100644
Binary files a/Docs/clouds-detailed01.jpg and b/Docs/clouds-detailed01.jpg differ
diff --git a/Docs/clouds-static.jpg b/Docs/clouds-static.jpg
new file mode 100644
index 000000000..0ac9c194d
Binary files /dev/null and b/Docs/clouds-static.jpg differ
diff --git a/Docs/detailed_clouds04.jpg b/Docs/detailed_clouds04.jpg
new file mode 100644
index 000000000..5ac837f4e
Binary files /dev/null and b/Docs/detailed_clouds04.jpg differ
diff --git a/Docs/detailed_clouds05.jpg b/Docs/detailed_clouds05.jpg
new file mode 100644
index 000000000..a06faed01
Binary files /dev/null and b/Docs/detailed_clouds05.jpg differ
diff --git a/Docs/high_pressure_border.jpg b/Docs/high_pressure_border.jpg
new file mode 100644
index 000000000..e9b77f635
Binary files /dev/null and b/Docs/high_pressure_border.jpg differ
diff --git a/Docs/low_pressure.jpg b/Docs/low_pressure.jpg
new file mode 100644
index 000000000..5670c4123
Binary files /dev/null and b/Docs/low_pressure.jpg differ
diff --git a/Docs/menu2.jpg b/Docs/menu2.jpg
index 226d0a4b9..97714ac0c 100644
Binary files a/Docs/menu2.jpg and b/Docs/menu2.jpg differ
diff --git a/Docs/thermal_lift.gif b/Docs/thermal_lift.gif
new file mode 100644
index 000000000..dd35cdb6f
Binary files /dev/null and b/Docs/thermal_lift.gif differ
diff --git a/Docs/thermal_lift_time.gif b/Docs/thermal_lift_time.gif
new file mode 100644
index 000000000..e1b273f54
Binary files /dev/null and b/Docs/thermal_lift_time.gif differ
diff --git a/Effects/urban.eff b/Effects/urban.eff
index f8eecd141..d73d5b2ea 100644
--- a/Effects/urban.eff
+++ b/Effects/urban.eff
@@ -7,6 +7,7 @@
0.008
0.75 0.59 0.05
/sim/rendering/quality-level
+ 10
15
@@ -68,12 +69,24 @@
texture[2]/filter
texture[2]/wrap-s
texture[2]/wrap-t
-
- texture[2]/internal-format
-
+ texture[2]/internal-format
2
+ texture[2]/image
+ nearest-mipmap-nearest
+ texture[2]/wrap-s
+ texture[2]/wrap-t
+ texture[2]/internal-format
+
+ average
+ average
+ average
+ min
+
+
+
+ 3
noise
@@ -102,10 +115,15 @@
sampler-2d
1
+
+ QDMTex
+ sampler-2d
+ 2
+
NoiseTex
sampler-3d
- 2
+ 3
depth_factor
@@ -132,6 +150,11 @@
float
snow-level
+
+ max_lod_level
+ float
+ max-lod-level
+
diff --git a/Huds/Custom/default.xml b/Huds/Custom/default.xml
deleted file mode 100644
index d70f42710..000000000
--- a/Huds/Custom/default.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
- Fighter Hud
-
-
-
-
- Huds/Instruments/Custom/hudladder.xml
-
-
-
- Huds/Instruments/Custom/hudcard.xml
-
-
-
- Huds/Instruments/Custom/instrlabel.xml
-
-
-
-
-
diff --git a/Huds/Default/default.xml b/Huds/Default/default.xml
deleted file mode 100644
index 848f6203c..000000000
--- a/Huds/Default/default.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
-
-
- Default Aircraft Hud
-
-
-
-
- Huds/Instruments/Default/hudladder.xml
-
-
-
- Huds/Instruments/Default/hudcard.xml
-
-
-
-
- Huds/Instruments/Default/instrlabel.xml
-
-
-
- Huds/Instruments/Default/fgtbi.xml
-
-
-
- Huds/Instruments/Default/gload.xml
-
-
-
-
-
-
-
diff --git a/Huds/Engineering/default.xml b/Huds/Engineering/default.xml
deleted file mode 100644
index a84c28a34..000000000
--- a/Huds/Engineering/default.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
-
- Default Aircraft Hud
-
-
-
-
- Huds/Instruments/Default/hudladder.xml
-
-
-
- Huds/Instruments/Default/hudcard.xml
-
-
-
- Huds/Instruments/Engineering/instrlabel.xml
-
-
-
- Huds/Instruments/Default/fgtbi.xml
-
-
-
-
-
diff --git a/Huds/Instruments/Custom/fgtbi.xml b/Huds/Instruments/Custom/fgtbi.xml
deleted file mode 100644
index cde8f9f8f..000000000
--- a/Huds/Instruments/Custom/fgtbi.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- fgTBI_Instrument
- 290
- 200
- 60
- 10
- 45.0
- 5.0
- 5
- true
- true
- 150.0
-
-
-
-
-
-
diff --git a/Huds/Instruments/Custom/hudcard.xml b/Huds/Instruments/Custom/hudcard.xml
deleted file mode 100644
index fe1f08f61..000000000
--- a/Huds/Instruments/Custom/hudcard.xml
+++ /dev/null
@@ -1,183 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Gyrocompass
- 260
- 248
- 120
- 28
- heading
- 4
- 360.0
- 0.0
- 0.1
- 10
- 5
- 360
- 60.0
- tape
- false
- false
- false
- false
- false
- false
- false
- false
- 10.0
- false
- fixed
- line
- variable
- true
- 40.0
- 12
- 0
-
-
-
- AOA
- 180
- 100
- 28
- 100
- aoa
- 6
- 20.0
- 0.0
- 1.0
- 4
- 2
- 0
- 20.0
- tape
- false
- false
- false
- false
- false
- false
- false
- false
- 10.0
- true
- moving
- circle
- constant
- true
- 30.0
- 12
- 0
-
-
-
-
- NormalAcceleration
- 140
- 110
- 18
- 100
- anzg
- 6
- 9.0
- -3.0
- 1
- 2
- 1
- 0
- 12.0
- tape
- false
- false
- false
- false
- false
- false
- false
- false
- 10.0
- true
- moving
- line
- variable
- false
- 40.0
- 12
- 0
-
-
-
-
- VSI
- 430
- 50
- 28
- 150
- climb
- 10
- 1000.0
- -1000.0
- 1.0
- 200
- 100
- 0
- 2000.0
- tape
- false
- false
- false
- false
- false
- false
- false
- false
- 10.0
- true
- moving
- line
- variable
- true
- 40.0
- 12
- 1
-
-
-
-
-
-
diff --git a/Huds/Instruments/Custom/hudladder.xml b/Huds/Instruments/Custom/hudladder.xml
deleted file mode 100644
index dd09558a7..000000000
--- a/Huds/Instruments/Custom/hudladder.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
-
-
- Climb/Dive Ladder
- 260
- 150
- 120
- 180
- 12.6316
- roll
- pitch
- 45
- 5.0
- 70
- 0
- true
- false
- true
- true
- true
- true
- true
- true
- -4.0
- true
- true
- true
- 1
- 1
- 1
-
-
-
-
-
-
diff --git a/Huds/Instruments/Custom/instrlabel.xml b/Huds/Instruments/Custom/instrlabel.xml
deleted file mode 100644
index 00e0c3aa6..000000000
--- a/Huds/Instruments/Custom/instrlabel.xml
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
- digitalkias
- 130
- 265
- 40
- 30
- speed
- %5.0f
- NULL
- blank
- 1.0
- 4
- 2
- 0
- false
- false
- false
- true
-
-
-
- machno
- 140
- 245
- 40
- 30
- mach
- %5.2f
- NULL
- blank
- 1.0
- 4
- 2
- 0
- false
- false
- false
- true
-
-
-
- pressurealtitude
- 430
- 265
- 40
- 30
- altitude
- %5.0f
- NULL
- blank
- 1.0
- 4
- 0
- 0
- false
- false
- false
- true
- 1
-
-
-
- radioaltitude
- 430
- 245
- 40
- 30
- agl
- %5.0f
- NULL
- R
- 1.0
- 4
- 0
- 0
- false
- false
- false
- true
-
-
-
- xposn
- 560
- 440
- 40
- 30
- aux4
- %5.0f
- NULL
- m
- 1.0
- 4
- 0
- 0
- false
- false
- false
- true
-
-
-
- pla
- 560
- 430
- 40
- 30
- throttleval
- %5.0f
- NULL
- pla
- 130.0
- 4
- 0
- 0
- false
- false
- false
- true
-
-
-
- FrameRate
- 0
- 25
- 60
- 10
- framerate
- %3.1f
- NULL
- blank
- 1.0
- 4
- 1
- 0
- false
- false
- false
- true
-
-
-
- acceleration
- 140
- 90
- 20
- 30
- anzg
- %1.1f
- blank
- NULL
- 1.0
- 1
- 0
- 0
- false
- false
- true
- true
-
-
-
-
- lattitude
- 40
- 40
- 1
- 10
- latitude
- %s%
- blank
- blank
- 1.0
- 4
- 1
- 0
- true
- false
- false
- true
-
-
-
- longitude
- 550
- 40
- 1
- 10
- longitude
- %s%
- blank
- blank
- 1.0
- 4
- 1
- 0
- false
- true
- true
-
-
-
-
-
-
diff --git a/Huds/Instruments/Default/fgtbi.xml b/Huds/Instruments/Default/fgtbi.xml
deleted file mode 100644
index 522a76217..000000000
--- a/Huds/Instruments/Default/fgtbi.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
- fgTBI_Instrument
- 290
- 45
- 60
- 10
- roll
- sideslip
- 45.0
- 5.0
- 5
- true
-
-
-
-
-
diff --git a/Huds/Instruments/Default/gload.xml b/Huds/Instruments/Default/gload.xml
deleted file mode 100644
index f7ff03dee..000000000
--- a/Huds/Instruments/Default/gload.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
- G Load
- 41
- 345
- 40
- 30
- anzg
- %4.2f
- NULL
- g
- 1.0
- 4
- 0
- 0
- true
- false
- false
-
-
-
-
-
diff --git a/Huds/Instruments/Default/hudcard.xml b/Huds/Instruments/Default/hudcard.xml
deleted file mode 100644
index 932715265..000000000
--- a/Huds/Instruments/Default/hudcard.xml
+++ /dev/null
@@ -1,285 +0,0 @@
-
-
-
-
-
- Gyrocompass
- 220
- 430
- 200
- 28
- heading
- 4
- 360.0
- 0.0
- 1.0
- 5
- 1
- 360
- 25.0
- tape
- false
- false
- true
- true
- true
- false
- false
- false
- 0.0
- true
- fixed
- line
- variable
- true
-
-
-
- AMSL
- 565
- 140
- 35
- 200
- altitude
- 6
- 5000.0
- -1000.0
- 1.0
- 100
- 25
- 0
- 250.0
- tape
- true
- true
- false
- false
- false
- false
- true
- false
- 0.0
- true
- fixed
- line
- variable
- true
-
-
-
- RadioAltimeter
- 438
- 165
- 25
- 150
- agl
- 6
- 1000.0
- 0.0
- 1.0
- 25
- 5
- 0
- 200.0
- tape
- true
- true
- false
- false
- false
- false
- true
- false
- 0.0
- true
- fixed
- line
- variable
- true
-
-
-
- KIAS
- 40
- 140
- 28
- 200
- speed
- 10
- 200.0
- 0.0
- 1.0
- 10
- 5
- 0
- 50.0
- tape
- true
- true
- false
- false
- false
- false
- false
- true
- 0.0
- true
- fixed
- line
- variable
- true
-
-
-
- Gauge1
- 270
- 310
- 100
- 20
- aileronval
- 136
- +1.0
- -1.0
- 100.0
- 50
- 0
- 0
- 2.0
- gauge
- false
- false
- true
- true
- false
- true
- false
- false
- 0.0
- true
- fixed
- true
-
-
-
- Gauge2
- 182
- 190
- 20
- 100
- elevatorval
- 138
- -100.0
- +1.0
- -1.0
- 50
- 0
- 0
- 2.0
- 0.0
- gauge
- true
- true
- false
- false
- false
- false
- false
- true
- true
- fixed
- true
-
-
-
- Gauge3
- 270
- 150
- 100
- 20
- rudderval
- 132
- +1.0
- -1.0
- 100.0
- 50
- 0
- 0
- 2.0
- gauge
- false
- false
- true
- true
- true
- false
- false
- false
- 0.0
- true
- fixed
- true
-
-
-
- Gauge4
- 15
- 165
- 20
- 150
- throttleval
- 134
- 1.0
- 0.0
- 100.0
- 50
- 0
- 0
- 1.0
- gauge
- true
- true
- false
- false
- false
- false
- true
- false
- 0.0
- true
- fixed
- true
-
-
-
- Gauge5
- 172
- 190
- 10
- 100
- elevatortrimval
- 134
- -100.0
- +1.0
- -1.0
- 50
- 0
- 0
- 2.0
- 0.0
- gauge
- true
- true
- false
- false
- false
- false
- false
- false
- true
- fixed
- true
-
-
-
-
-
diff --git a/Huds/Instruments/Default/hudladder.xml b/Huds/Instruments/Default/hudladder.xml
deleted file mode 100644
index ca96a9b70..000000000
--- a/Huds/Instruments/Default/hudladder.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
- Pitch Ladder
- 260
- 150
- 120
- 180
- 2.68
- roll
- pitch
- 45.0
- 10.0
- 70
- 0
- false
- true
- false
- false
- false
- false
- false
- false
- 0.0
- false
- false
- true
-
-
-
-
-
diff --git a/Huds/Instruments/Default/instrlabel.xml b/Huds/Instruments/Default/instrlabel.xml
deleted file mode 100644
index af2a47cbf..000000000
--- a/Huds/Instruments/Default/instrlabel.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
- latitude
- 110
- 430
- 1
- 10
- latitude
- %s%
- blank
- blank
- 1.0
- 4
- 1
- 0
- true
- true
- false
-
-
-
- longitude
- 530
- 430
- 1
- 10
- longitude
- %s%
- blank
- blank
- 1.0
- 4
- 1
- 0
- true
- false
- true
-
-
-
-
-
diff --git a/Huds/Instruments/Default/runwayinstr.xml b/Huds/Instruments/Default/runwayinstr.xml
deleted file mode 100644
index fc474c8dc..000000000
--- a/Huds/Instruments/Default/runwayinstr.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
- Runway Hud
- 0
- 0
- 480
- 360
- true
- 5
- 5.0
- false
- 1.0
- 50.0
- -1
- 64250
-
-
-
diff --git a/Huds/Instruments/Engineering/fgtbi.xml b/Huds/Instruments/Engineering/fgtbi.xml
deleted file mode 100644
index 522a76217..000000000
--- a/Huds/Instruments/Engineering/fgtbi.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
- fgTBI_Instrument
- 290
- 45
- 60
- 10
- roll
- sideslip
- 45.0
- 5.0
- 5
- true
-
-
-
-
-
diff --git a/Huds/Instruments/Engineering/hudcard.xml b/Huds/Instruments/Engineering/hudcard.xml
deleted file mode 100644
index 7cd2402aa..000000000
--- a/Huds/Instruments/Engineering/hudcard.xml
+++ /dev/null
@@ -1,247 +0,0 @@
-
-
-
-
-
- Gyrocompass
- 220
- 430
- 200
- 28
- heading
- 4
- 360.0
- 0.0
- 1.0
- 5
- 1
- 360
- 25.0
- tape
- false
- false
- true
- true
- true
- false
- false
- false
- 0.0
- true
- fixed
- true
-
-
-
- AMSL
- 565
- 140
- 35
- 200
- altitude
- 6
- 5000.0
- -1000.0
- 1.0
- 100
- 25
- 0
- 250.0
- tape
- true
- true
- false
- false
- false
- false
- true
- false
- 0.0
- true
- fixed
- true
-
-
-
- RadioAltimeter
- 438
- 165
- 25
- 150
- agl
- 6
- 1000.0
- 0.0
- 1.0
- 25
- 5
- 0
- 200.0
- tape
- true
- true
- false
- false
- false
- false
- true
- false
- 0.0
- true
- fixed
- true
-
-
-
- KIAS
- 40
- 140
- 28
- 200
- speed
- 10
- 200.0
- 0.0
- 1.0
- 10
- 5
- 0
- 50.0
- tape
- true
- true
- false
- false
- false
- false
- false
- true
- 0.0
- true
- fixed
- true
-
-
-
- Gauge1
- 270
- 310
- 100
- 20
- aileronval
- 88
- +1.0
- -1.0
- 100.0
- 50
- 0
- 0
- 2.0
- gauge
- false
- false
- true
- true
- false
- true
- false
- false
- 0.0
- true
- fixed
- true
-
-
-
- Gauge2
- 182
- 190
- 20
- 100
- elevatorval
- 90
- +1.0
- -1.0
- -100.0
- 50
- 0
- 0
- 2.0
- gauge
- true
- true
- false
- false
- false
- false
- false
- true
- 0.0
- true
- fixed
- true
-
-
-
- Gauge3
- 270
- 150
- 100
- 20
- rudderval
- 84
- +1.0
- -1.0
- 100.0
- 50
- 0
- 0
- 2.0
- gauge
- false
- false
- true
- true
- true
- false
- false
- false
- 0.0
- true
- fixed
- true
-
-
-
- Gauge4
- 15
- 165
- 20
- 150
- throttleval
- 86
- 1.0
- 0.0
- 100.0
- 50
- 0
- 0
- 1.0
- gauge
- true
- true
- false
- false
- false
- false
- true
- false
- 0.0
- true
- fixed
- true
-
-
-
-
-
diff --git a/Huds/Instruments/Engineering/hudladder.xml b/Huds/Instruments/Engineering/hudladder.xml
deleted file mode 100644
index ca96a9b70..000000000
--- a/Huds/Instruments/Engineering/hudladder.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
- Pitch Ladder
- 260
- 150
- 120
- 180
- 2.68
- roll
- pitch
- 45.0
- 10.0
- 70
- 0
- false
- true
- false
- false
- false
- false
- false
- false
- 0.0
- false
- false
- true
-
-
-
-
-
diff --git a/Huds/Instruments/Engineering/instrlabel.xml b/Huds/Instruments/Engineering/instrlabel.xml
deleted file mode 100644
index e53139378..000000000
--- a/Huds/Instruments/Engineering/instrlabel.xml
+++ /dev/null
@@ -1,140 +0,0 @@
-
-
-
-
-
- machno
- 25
- 130
- 40
- 30
- mach
- %4.2f
- blank
- NULL
- 1.0
- 4
- 2
- 0
- true
- false
- false
-
-
-
- lattitude
- 110
- 430
- 1
- 10
- latitude
- %s%
- blank
- blank
- 1.0
- 4
- 1
- 0
- true
- true
- false
-
-
-
- longitude
- 530
- 430
- 1
- 10
- longitude
- %s%
- blank
- blank
- 1.0
- 4
- 1
- 0
- true
- false
- true
-
-
-
- alpha
- 530
- 70
- 1
- 10
- aoa
- %4.1f%
- alpha:
- blank
- 1.0
- 4
- 0
- 0
- true
- false
- false
-
-
-
- beta
- 530
- 55
- 1
- 10
- sideslip
- %4.1f%
- beta:
- blank
- 1.0
- 4
- 0
- 0
- true
- false
- false
-
-
-
- nlf
- 530
- 40
- 1
- 10
- nlf
- %4.1f%
- nlf:
- blank
- 1.0
- 4
- 0
- 0
- true
- false
- false
-
-
-
- framerate
- 530
- 25
- 1
- 10
- framerate
- %5.1f%
- framerate:
- blank
- 1.0
- 4
- 0
- 0
- true
- false
- false
-
-
-
-
-
diff --git a/Huds/Instruments/Minimal/fgtbi.xml b/Huds/Instruments/Minimal/fgtbi.xml
deleted file mode 100644
index a309996c7..000000000
--- a/Huds/Instruments/Minimal/fgtbi.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
- fgTBI_Instrument
- 290
- 55
- 60
- 10
- roll
- sideslip
- 45.0
- 5.0
- 5
- true
-
-
-
-
-
diff --git a/Huds/Instruments/Minimal/gload.xml b/Huds/Instruments/Minimal/gload.xml
deleted file mode 100644
index 6e17dd705..000000000
--- a/Huds/Instruments/Minimal/gload.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
- G Load
- 11
- 294
- 40
- 30
- anzg
- %4.2f
- NULL
- g
- 1.0
- 4
- 0
- 0
- true
- false
- false
-
-
-
-
-
diff --git a/Huds/Instruments/Minimal/hudcard.xml b/Huds/Instruments/Minimal/hudcard.xml
deleted file mode 100644
index 8b076b733..000000000
--- a/Huds/Instruments/Minimal/hudcard.xml
+++ /dev/null
@@ -1,189 +0,0 @@
-
-
-
-
-
- Gyrocompass
- 220
- 430
- 200
- 28
- view_direction
- 4
- 360.0
- 0.0
- 1.0
- 5
- 1
- 360
- 25.0
- tape
- false
- false
- true
- true
- true
- false
- false
- false
- 0.0
- true
- fixed
- line
- variable
- true
-
-
-
- Gauge1
- 270
- 390
- 100
- 20
- aileronval
- 136
- +1.0
- -1.0
- 100.0
- 50
- 0
- 0
- 2.0
- gauge
- false
- false
- true
- true
- false
- true
- false
- false
- 0.0
- true
- fixed
- true
-
-
-
- Gauge2
- 20
- 190
- 20
- 100
- elevatorval
- 138
- -100.0
- +1.0
- -1.0
- 50
- 0
- 0
- 2.0
- gauge
- true
- true
- false
- false
- false
- false
- false
- true
- 0.0
- true
- fixed
- true
-
-
-
- Gauge3
- 270
- 25
- 100
- 20
- rudderval
- 132
- 100.0
- +1.0
- -1.0
- 50
- 0
- 0
- 2.0
- 0.0
- gauge
- false
- false
- true
- true
- true
- false
- false
- false
- true
- fixed
- true
-
-
-
- Gauge4
- 600
- 160
- 20
- 160
- throttleval
- 134
- 100.0
- 1.0
- 0.0
- 50
- 0
- 0
- 1.0
- 0.0
- gauge
- true
- true
- false
- false
- false
- false
- true
- false
- true
- fixed
- true
-
-
-
- Gauge5
- 10
- 190
- 10
- 100
- elevatortrimval
- 134
- -100.0
- +1.0
- -1.0
- 50
- 0
- 0
- 2.0
- 0.0
- gauge
- true
- true
- false
- false
- false
- false
- false
- false
- true
- fixed
- true
-
-
-
-
-
diff --git a/Huds/Instruments/Minimal/hudladder.xml b/Huds/Instruments/Minimal/hudladder.xml
deleted file mode 100644
index d92c9db20..000000000
--- a/Huds/Instruments/Minimal/hudladder.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
- artificialhorizon
- 260
- 150
- 120
- 180
- 2.68
- roll
- pitch
- 45.0
- 0.0
- 0.0
- 70
- 0
- false
- true
- false
- false
- false
- false
- false
- false
- 0.0
- false
- false
- true
-
-
-
-
-
diff --git a/Huds/Instruments/Minimal/instrlabel.xml b/Huds/Instruments/Minimal/instrlabel.xml
deleted file mode 100644
index a25e07f30..000000000
--- a/Huds/Instruments/Minimal/instrlabel.xml
+++ /dev/null
@@ -1,160 +0,0 @@
-
-
-
-
-
- Label1
- 40
- 25
- 60
- 10
- framerate
- %7.1f
- Frame rate =
- NULL
- 1.0
- 4
- 0
- 0
- true
-
-
-
- Label2
- 40
- 40
- 90
- 10
- fov
- %7.1f
- FOV =
- NULL
- 1.0
- 4
- 0
- 0
- true
-
-
-
- Label3
- 480
- 70
- 60
- 10
- aoa
- %7.2f
- AOA =
- Deg
- 1.0
- 4
- 0
- 0
- true
-
-
-
- Label4
- 480
- 55
- 40
- 30
- speed
- %5.0f
- Airspeed
- Kts
- 1.0
- 4
- 0
- 0
- true
-
-
-
- Label5
- 480
- 40
- 40
- 10
- altitude
- %5.0f
- Altitude
- units
- 1.0
- 4
- 0
- 0
- true
-
-
-
- Label6
- 480
- 25
- 40
- 10
- agl
- %5.0f
- Elevation
- units
- 1.0
- 4
- 0
- 0
- true
-
-
-
- Label7
- 480
- 10
- 60
- 10
- heading
- %5.1f
- Heading
- Deg
- 1.0
- 4
- 0
- 0
- true
-
-
-
- lattitude
- 110
- 430
- 0
- latitude
- %s%
- blank
- blank
- 1.0
- 4
- 1
- 0
- true
- true
-
-
-
- longitude
- 530
- 430
- 1
- longitude
- %s%
- blank
- blank
- 1.0
- 4
- 1
- 0
- true
- true
-
-
-
-
-
diff --git a/Huds/Minimal/default.xml b/Huds/Minimal/default.xml
deleted file mode 100644
index 95d2de920..000000000
--- a/Huds/Minimal/default.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
- Minimal Aircraft Hud
-
-
-
-
- Huds/Instruments/Minimal/hudladder.xml
-
-
-
- Huds/Instruments/Minimal/hudcard.xml
-
-
-
- Huds/Instruments/Minimal/instrlabel.xml
-
-
-
- Huds/Instruments/Minimal/fgtbi.xml
-
-
-
- Huds/Instruments/Minimal/gload.xml
-
-
-
-
-
diff --git a/Huds/Sets/autopilot.xml b/Huds/Sets/autopilot.xml
index 512262d98..4be2ba32b 100644
--- a/Huds/Sets/autopilot.xml
+++ b/Huds/Sets/autopilot.xml
@@ -4,10 +4,26 @@
+
+ 60
+ 10
+ true
+ ROLL
+ left
+
+
+ /autopilot/locks/heading
+ wing-leveler
+
+
+
+
+
- 2
- 2
- hdg = %.1f
+ 60
+ 10
+ true
+ HDG %03d
left
/autopilot/settings/heading-bug-deg
@@ -21,9 +37,10 @@
- 2
- 2
- hdg = %.1f
+ 60
+ 10
+ true
+ HDG %03d
left
/autopilot/settings/true-heading-deg
@@ -36,217 +53,15 @@
-
-
-
- 0
- -15
- 2
- 2
- %5s
- left
-
- /autopilot/route-manager/wp[0]/id
-
-
-
- /autopilot/locks/heading
- true-heading-hold
-
-
-
-
-
- 35
- -15
- 2
- 2
- %6.1fnm
- left
-
- /autopilot/route-manager/wp[0]/dist
-
-
-
- /autopilot/locks/heading
- true-heading-hold
-
-
-
- /autopilot/route-manager/wp[0]/id
-
-
-
-
-
-
-
- 82
- -15
- 2
- 2
- %s
- left
-
- /autopilot/route-manager/wp[0]/eta
-
-
-
- /autopilot/locks/heading
- true-heading-hold
-
-
-
- /autopilot/route-manager/wp[0]/id
-
-
-
-
-
-
-
-
-
- 0
- -30
- 2
- 2
- %5s
- left
-
- /autopilot/route-manager/wp[1]/id
-
-
-
- /autopilot/locks/heading
- true-heading-hold
-
-
-
-
-
- 35
- -30
- 2
- 2
- %6.1fnm
- left
-
- /autopilot/route-manager/wp[1]/dist
-
-
-
- /autopilot/locks/heading
- true-heading-hold
-
-
-
- /autopilot/route-manager/wp[1]/id
-
-
-
-
-
-
-
- 82
- -30
- 2
- 2
- %s
- left
-
- /autopilot/route-manager/wp[1]/eta
-
-
-
- /autopilot/locks/heading
- true-heading-hold
-
-
-
- /autopilot/route-manager/wp[1]/id
-
-
-
-
-
-
-
-
-
- 0
- -45
- 2
- 2
- %5s
- left
-
- /autopilot/route-manager/wp[2]/id
-
-
-
- /autopilot/locks/heading
- true-heading-hold
-
-
-
-
-
- 35
- -45
- 2
- 2
- %6.1fnm
- left
-
- /autopilot/route-manager/wp[2]/dist
-
-
-
- /autopilot/locks/heading
- true-heading-hold
-
-
-
- /autopilot/route-manager/wp[2]/id
-
-
-
-
-
-
-
- 82
- -45
- 2
- 2
- %s
- left
-
- /autopilot/route-manager/wp[2]/eta
-
-
-
- /autopilot/locks/heading
- true-heading-hold
-
-
-
- /autopilot/route-manager/wp[2]/id
-
-
-
-
-
- -60
- 2
- 2
- alt = %.0f
+ 60
+ 60
+ 10
+ true
+ ALT %04d
left
/autopilot/settings/target-altitude-ft
@@ -259,12 +74,47 @@
-
- -60
- 2
- 2
- agl = %.0f
+
+ 60
+ 60
+ 10
+ true
+ PTCH
left
+
+
+ /autopilot/locks/altitude
+ pitch-hold
+
+
+
+
+
+
+ 60
+ 60
+ 10
+ true
+ V/S %d
+ left
+
+ /autopilot/settings/vertical-speed-fpm
+
+
+
+ /autopilot/locks/altitude
+ vertical-speed-hold
+
+
+
+
+
+ 60
+ 60
+ 10
+ AGL %04d
+ left
+ true
/autopilot/settings/target-agl-ft
@@ -276,4 +126,59 @@
+
+
+ 120
+ 60
+ 10
+ IAS %3dkt
+ left
+ true
+
+ /autopilot/settings/target-speed-kt
+
+
+
+ /autopilot/locks/speed
+ speed-with-throttle
+
+
+
+
+
+ 120
+ 60
+ 10
+ MACH %1.2f
+ left
+ true
+
+ /autopilot/settings/target-speed-mach
+
+
+
+ /autopilot/locks/speed
+ mach-with-throttle
+
+
+
+
+
+ 120
+ 60
+ 10
+ PITCH %3dkt
+ left
+ true
+
+ /autopilot/settings/target-speed-mach
+
+
+
+ /autopilot/locks/speed
+ speed-with-pitch-trim
+
+
+
+
diff --git a/Huds/Sets/gps.xml b/Huds/Sets/gps.xml
new file mode 100644
index 000000000..0e35e1b36
--- /dev/null
+++ b/Huds/Sets/gps.xml
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+ 2
+ 2
+ GPS OBS:%5s
+ left
+
+ /instrumentation/gps/wp/wp[1]/ID
+
+
+
+
+ /instrumentation/gps/mode
+ obs
+
+
+
+
+
+ 2
+ 2
+ 80
+ (TO)
+ left
+
+
+
+
+ /instrumentation/gps/mode
+ obs
+
+ /instrumentation/gps/from-flag
+
+
+
+
+
+ 2
+ 2
+ 80
+ (FROM)
+ left
+
+
+
+
+ /instrumentation/gps/mode
+ obs
+
+ /instrumentation/gps/from-flag
+
+
+
+
+
+ 2
+ 2
+ GPS DTO:%5s
+ left
+
+ /instrumentation/gps/wp/wp[1]/ID
+
+
+
+
+ /instrumentation/gps/mode
+ dto
+
+
+
+
+
+ 2
+ 2
+ GPS LEG:%5s
+ left
+
+ /instrumentation/gps/wp/wp[0]/ID
+
+
+
+
+ /instrumentation/gps/mode
+ leg
+
+
+
+
+
+
+ 2
+ 2
+ 80
+ ->%5s
+ left
+
+ /instrumentation/gps/wp/wp[1]/ID
+
+
+
+
+ /instrumentation/gps/mode
+ leg
+
+
+
+
+
+
+
+
+ 2
+ 2
+ -10
+ D: %4.1fnm
+ left
+
+ /instrumentation/gps/wp/wp[1]/distance-nm
+
+
+
+
+ 2
+ 2
+ 60
+ -10
+ TTW:%s
+ left
+
+ /instrumentation/gps/wp/wp[1]/TTW
+
+
+
+
+ 2
+ 2
+ -20
+ BRG:%03d
+ left
+
+ /instrumentation/gps/wp/wp[1]/bearing-mag-deg
+
+
+
+
+ 2
+ 2
+ -20
+ 60
+ XTK: %2.1fnm
+ left
+
+ /instrumentation/gps/wp/wp[1]/course-error-nm
+
+
+
+
+
+ /instrumentation/gps/wp/wp[1]/course-error-nm
+
+ 0.1
+
+
+
+
+
+ 2
+ 2
+ -30
+ GS:%3dkts
+ left
+
+ /instrumentation/gps/indicated-ground-speed-kt
+
+
+
+
\ No newline at end of file
diff --git a/Huds/default.xml b/Huds/default.xml
index 2c3201920..9643f2495 100644
--- a/Huds/default.xml
+++ b/Huds/default.xml
@@ -29,7 +29,13 @@
Huds/Sets/autopilot.xml
- -280
+ -100
+ 160
+
+
+
+ Huds/Sets/gps.xml
+ -300
160
diff --git a/Input/Joysticks/Saitek/Aviator.xml b/Input/Joysticks/Saitek/Aviator.xml
index 4d3febc29..1f0e6b23b 100644
--- a/Input/Joysticks/Saitek/Aviator.xml
+++ b/Input/Joysticks/Saitek/Aviator.xml
@@ -1,9 +1,8 @@
-
@@ -21,18 +20,27 @@
# TM0: All selected; TM1: #1 & #2; TM2: #3 & #4
var engine_axis_mode = 0;
# Valid only in TM1 and TM2.
- # EA0: throttle, +mod: propeller
- # EA1: propeller, +mod: throttle
+ # EA0: throttle
+ # EA1: mixture
+ # EA2: propeller
var quick_view_active = 0;
var old_view = view.point.save();
var pressed = [0,0,0,0,0,0,0,0,0,0,0,0];
+ # Map engines to throttles for TM1 (0, 1) and TM2 (2, 3)
var engine = [0, 1, 2, 3];
- # Do per-aircraft modifications
- if (getprop("/sim/model/path") ==
- "Aircraft/Short_Empire/Models/Short_Empire-model.xml") {
+ # Do per-aircraft modifications
+ if (contains({"Aircraft/Short_Empire/Models/Short_Empire-model.xml" : 0,
+ "Aircraft/Lockheed1049/Models/Lockheed1049_twa.xml" : 0},
+ getprop("/sim/model/path"))) {
+ # TM1: the outer engines, TM2: the inner engines
engine = [0, 3, 1, 2];
}
+ if (contains({"Aircraft/DO-X/Models/dox.xml" : 0},
+ getprop("/sim/model/path"))) {
+ engine = [[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11],
+ [0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]];
+ }
var goal_heading_offset =
@@ -46,7 +54,7 @@
var kbdalt = props.globals.getNode("/devices/status/keyboard/alt", 1);
var quick_view = func {
- dir = arg[0];
+ var dir = arg[0];
if (dir == 0) {
quick_view_active = 0;
view.point.move(old_view, 0.1);
@@ -99,7 +107,13 @@
-
+
+ Stick left/right
+
+ 0
+ 0
+ 0
+
aileron
property-scale
@@ -111,7 +125,13 @@
-
+
+ Stick forward/back
+
+ 1
+ 1
+ 1
+
elevator
property-scale
@@ -125,6 +145,7 @@
+ Stick twist
3
2
@@ -139,10 +160,18 @@
1.0
true
+
+ Left throttle
2
3
@@ -155,43 +184,43 @@
if (engine_select_mode == 0) {
controls.throttleAxis();
} else {
- var val = cmdarg().getNode("setting").getValue();
- var ctrl_pp =
- "/controls/engines/engine[" ~
- ((engine_select_mode == 1) ? engine[0] : engine[2]) ~ "]/" ~
- (engine_axis_mode ? "propeller-pitch" : "throttle");
- setprop(ctrl_pp, (1 - val)/2);
+ controls.perEngineSelectedAxisHandler(engine_axis_mode)
+ ((engine_select_mode == 1) ? engine[0] : engine[2]);
}
-
- TM0: mixture, +mod: propeller pitch, TM1: throttle/propeller 2, TM2: throttle/propeller 4
+
+ Right throttle
+
+ 4
+ 4
+ 4
+
+ TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4
nasal
-
+
+ Hat left/right
+
+ 5
+ 5
+ 5
+
quick view left/right, +mod: horizontal view pan
true
@@ -238,10 +267,12 @@
nasal
@@ -249,7 +280,13 @@
-
+
+ Hat up/down
+
+ 6
+ 6
+ 6
+
view reset/quick view front, +mod: vertical view pan
true
@@ -270,9 +307,11 @@
nasal
@@ -296,9 +335,11 @@
nasal
@@ -306,8 +347,13 @@
-
+
Trigger
+
+ 0
+ 0
+ 0
+
function modifier (mod)
nasal
@@ -327,8 +373,13 @@
-
+
Center button
+
+ 2
+ 2
+ 2
+
brakes, +mod: Toggle parking brake
nasal
@@ -352,8 +403,13 @@
-
+
Left button
+
+ 1
+ 1
+ 1
+
left brake, +mod: PTT
nasal
@@ -378,8 +434,13 @@
-
+
Right button
+
+ 3
+ 3
+ 3
+
right brake, +mod: trigger
nasal
@@ -404,8 +465,13 @@
-
+
T1
+
+ 4
+ 4
+ 4
+
next view, +mod: zoom in +Shift: next weapon
true
@@ -442,8 +508,13 @@
-
+
T2
+
+ 5
+ 5
+ 5
+
previous view, +mod: zoom out, +Shift: previous weapon
true
@@ -480,8 +551,13 @@
-
+
T3
+
+ 6
+ 6
+ 6
+
trim nose down, +mod: disarm speed brakes
true
@@ -498,8 +574,13 @@
-
+
T4
+
+ 7
+ 7
+ 7
+
trim nose up, +mod: deploy speed brakes
true
@@ -516,8 +597,13 @@
-
+
T5
+
+ 8
+ 8
+ 8
+
retract flaps one step, +mod: gear up
nasal
@@ -542,8 +628,13 @@
-
+
T6
+
+ 9
+ 9
+ 9
+
deploy flaps one step, +mod: gear down
nasal
@@ -568,8 +659,13 @@
-
+
T7
+
+ 10
+ 10
+ 10
+
Increase magnetos, +mod: Engine throttle/propeller axis swap
nasal
@@ -578,14 +674,19 @@
if (!modifier) {
controls.stepMagnetos(1);
} else {
- engine_axis_mode = !engine_axis_mode;
+ engine_axis_mode = 2*!engine_axis_mode;
}
-
+
+
+ 11
+ 11
+ 11
+
T8
Decrease magnetos, +mod: Engine throttle/propeller axis swap
@@ -595,15 +696,20 @@
if (!modifier) {
controls.stepMagnetos(-1);
} else {
- engine_axis_mode = !engine_axis_mode;
+ engine_axis_mode = 2*!engine_axis_mode;
}
-
+
Mode 1
+
+ 12
+ 12
+ 12
+
Engine 0/1 throttle mode
nasal
@@ -622,7 +728,13 @@
-
+
+ Mode 2
+
+ 13
+ 13
+ 13
+
Mode 2
Engine 2/3 throttle mode
diff --git a/Input/Joysticks/Saitek/Pro-Flight-Quadrant.xml b/Input/Joysticks/Saitek/Pro-Flight-Quadrant.xml
index a0ba91fee..bb9ac4ccd 100644
--- a/Input/Joysticks/Saitek/Pro-Flight-Quadrant.xml
+++ b/Input/Joysticks/Saitek/Pro-Flight-Quadrant.xml
@@ -1,35 +1,122 @@
Saitek Saitek Pro Flight Quadrant
Saitek Pro Flight Quadrant
Saitek Pro Flight Throttle Quadrant
-
- Throttle
+
+
+
+
+
+
+
+ Left lever
+
+ 0
+ 0
+ 0
+
+ TM0: throttle, TM1: throttle/propeller 1, TM2: throttle/propeller 4
nasal
-
+
-
- Prop Pitch
+
+ Middle lever
+
+ 1
+ 1
+ 1
+
+ TM0: propeller, TM1: throttle/propeller 2, TM2: throttle/propeller 5
nasal
-
+
-
- Mixture
+
+ Right lever
+
+ 2
+ 2
+ 2
+
+ TM0: mixture, TM1: throttle/propeller 3, TM2: throttle/propeller 6
nasal
-
+
-
+
+
+
+ Left button up
+
+ 0
+ 0
+ 0
+
Flaps up
false
@@ -42,14 +129,40 @@
+
+
+ nasal
+
+
+
+ Left button down
+
+ 1
+ 1
+ 1
+
Flaps down
false
nasal
+
+
+ nasal
+
+
+
nasal
@@ -57,23 +170,64 @@
-
+
+
+ Middle button up
+
+ 2
+ 2
+ 2
+
Elevator trim up
true
nasal
+
+
+ nasal
+
+
+
-
+
+ Middle button down
+
+ 3
+ 3
+ 3
+
Elevator trim down
true
nasal
+
+
+ nasal
+
+
+
-
+
+
+ Right button up
+
+ 4
+ 4
+ 4
+
Gear up
false
@@ -81,7 +235,13 @@
-
+
+ Right button down
+
+ 5
+ 5
+ 5
+
Gear down
false
@@ -89,4 +249,49 @@
+
+
+
+ Left lever reverse
+
+ 6
+ 6
+ 6
+
+
+ false
+
+ nasal
+
+
+
+
+ Middle lever reverse
+
+ 7
+ 7
+ 7
+
+
+ false
+
+ nasal
+
+
+
+
+ Right lever reverse
+
+ 8
+ 8
+ 8
+
+
+ false
+
+ nasal
+
+
+
+
diff --git a/Nasal/aircraft.nas b/Nasal/aircraft.nas
index 4c8580abc..d79768e6c 100644
--- a/Nasal/aircraft.nas
+++ b/Nasal/aircraft.nas
@@ -954,12 +954,11 @@ var kias_to_ktas = func(kias, altitude) {
#
var HUD = {
init: func {
- me.vis0N = props.globals.getNode("/sim/hud/visibility[0]", 1);
me.vis1N = props.globals.getNode("/sim/hud/visibility[1]", 1);
me.currcolN = props.globals.getNode("/sim/hud/current-color", 1);
me.paletteN = props.globals.getNode("/sim/hud/palette", 1);
me.brightnessN = props.globals.getNode("/sim/hud/color/brightness", 1);
- me.currentN = me.vis0N;
+ me.currentN = me.vis1N;
},
cycle_color: func { # h-key
if (!me.currentN.getBoolValue()) # if off, turn on
@@ -979,34 +978,14 @@ var HUD = {
var br = me.brightnessN.getValue() - 0.2;
me.brightnessN.setValue(br > 0.01 ? br : 1);
},
- normal_type: func { # i-key
- me.is_active() or return;
- me.oldinit1();
- me.vis0N.setBoolValue(1);
- me.vis1N.setBoolValue(0);
- me.currentN = me.vis0N;
- },
- cycle_type: func { # I-key
- me.is_active() or return;
- if (me.currentN == me.vis0N) {
- me.vis0N.setBoolValue(0);
- me.vis1N.setBoolValue(1);
- me.currentN = me.vis1N;
- } elsif (me.currentN == me.vis1N) {
- me.vis0N.setBoolValue(1);
- me.vis1N.setBoolValue(0);
- me.oldinit2();
- me.currentN = me.vis0N;
- }
- },
- oldinit1: func {
- fgcommand("hud-init");
- },
- oldinit2: func {
- fgcommand("hud-init2");
- },
+ normal_type: func { # i-key
+
+ },
+ cycle_type: func { # I-key
+
+ },
is_active: func {
- me.vis0N.getValue() or me.vis1N.getValue();
+ me.vis1N.getValue();
},
};
diff --git a/Nasal/compat_layer.nas b/Nasal/compat_layer.nas
index a91a0ccd7..dd90543f9 100644
--- a/Nasal/compat_layer.nas
+++ b/Nasal/compat_layer.nas
@@ -7,21 +7,19 @@
# function purpose
#
# setVisibility to set the visibility to a given value
+# setLift to set lift to given value
# setRain to set rain to a given value
# setSnow to set snow to a given value
# setTurbulence to set turbulence to a given value
# setTemperature to set temperature to a given value
# setPressure to set pressure to a given value
# setDewpoint to set the dewpoint to a given value
+# setLight to set light saturation to given value
# setWind to set wind
# setWindSmoothly to set the wind gradually across a second
-# smooth_wind_loop helper function for setWindSmoothly
+# smooth_wind_loop (helper function for setWindSmoothly)
# create_cloud to place a single cloud into the scenery
# create_cloud_array to place clouds from storage arrays into the scenery
-# move_cloud to move the cloud position
-# remove_clouds to remove clouds by tile index
-# waiting_loop to ensure tile removal calls do not overlap
-# remove_tile_loop to remove a fixed number of clouds per frame
# get_elevation to get the terrain elevation at given coordinates
# get_elevation_vector to get terrain elevation at given coordinate vector
@@ -68,72 +66,35 @@
# 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.");
+
+var result = "yes";
+
+print("Compatibility layer: testing for hard coded support");
+
+if (props.globals.getNode("/rendering/scene/saturation", 0) == nil)
+ {result = "no"; features.can_set_light = 0;}
+else
+ {result = "yes"; features.can_set_light = 1;}
+print("* can set light saturation: "~result);
+
+
+if (props.globals.getNode("/environment/terrain", 0) == nil)
+ {result = "no"; features.terrain_presampling = 0;}
+else
+ {result = "yes"; features.terrain_presampling = 1;}
+print("* hard coded terrain presampling: "~result);
+
+if (props.globals.getNode("/environment/config/enabled", 0) == nil)
+ {result = "no"; features.can_disable_environment = 0;}
+else
+ {result = "yes"; features.can_disable_environment = 1;}
+print("* can disable global weather: "~result);
+
+print("Compatibility layer: tests 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
@@ -143,20 +104,38 @@ _setlistener("/sim/signals/nasal-dir-initialized", func {
var setVisibility = func (vis) {
-# this is a rather dirty workaround till a better solution becomes available
-# essentially we update all entries in config and reinit environment
+if (features.can_disable_environment == 1)
+ {
+ setprop("/environment/visibility-m",vis);
+ }
+else
+ {
+ # this is a workaround for systems which lack hard-coded support
+ # essentially we update all entries in config and reinit environment
-var entries_aloft = props.globals.getNode("environment/config/aloft", 1).getChildren("entry");
-foreach (var e; entries_aloft) {
- e.getNode("visibility-m",1).setValue(vis);
- }
+ var entries_aloft = props.globals.getNode("environment/config/aloft", 1).getChildren("entry");
+ foreach (var e; entries_aloft) {
+ e.getNode("visibility-m",1).setValue(vis);
+ }
-var entries_boundary = props.globals.getNode("environment/config/boundary", 1).getChildren("entry");
-foreach (var e; entries_boundary) {
- e.getNode("visibility-m",1).setValue(vis);
- }
-fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+ var entries_boundary = props.globals.getNode("environment/config/boundary", 1).getChildren("entry");
+ foreach (var e; entries_boundary) {
+ e.getNode("visibility-m",1).setValue(vis);
+ }
+ fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+ }
+}
+####################################
+# set thermal lift to given value
+####################################
+
+var setLift = func (lift) {
+
+if (features.can_disable_environment == 1)
+ {
+ setprop("/environment/wind-from-down-fps",lift);
+ }
}
####################################
@@ -193,24 +172,36 @@ setprop("environment/metar/snow-norm",snow);
var setTurbulence = func (turbulence) {
-# this is a rather dirty workaround till a better solution becomes available
-# essentially we update all entries in config and reinit environment
+if (features.can_disable_environment == 1)
+ {
+ setprop("/environment/turbulence/magnitude-norm",turbulence);
+ setprop("/environment/turbulence/rate-hz",3.0);
+ }
-var entries_aloft = props.globals.getNode("environment/config/aloft", 1).getChildren("entry");
-foreach (var e; entries_aloft) {
- e.getNode("turbulence/magnitude-norm",1).setValue(turbulence);
- }
+else
+ {
+ # this is a workaround for systems which lack hard-coded support
+ # essentially we update all entries in config and reinit environment
-# turbulence is slightly reduced in boundary layers
+ var entries_aloft = props.globals.getNode("environment/config/aloft", 1).getChildren("entry");
+ foreach (var e; entries_aloft) {
+ e.getNode("turbulence/magnitude-norm",1).setValue(turbulence);
+ e.getNode("turbulence/rate-hz",1).setValue(3.0);
+ e.getNode("turbulence/factor",1).setValue(1.0);
+ }
-var entries_boundary = props.globals.getNode("environment/config/boundary", 1).getChildren("entry");
-var i = 1;
-foreach (var e; entries_boundary) {
- e.getNode("turbulence/magnitude-norm",1).setValue(turbulence * 0.25*i);
- i = i + 1;
- }
-fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+ # turbulence is slightly reduced in boundary layers
+ var entries_boundary = props.globals.getNode("environment/config/boundary", 1).getChildren("entry");
+ var i = 1;
+ foreach (var e; entries_boundary) {
+ e.getNode("turbulence/magnitude-norm",1).setValue(turbulence * 0.25*i);
+ e.getNode("turbulence/rate-hz",1).setValue(5.0);
+ e.getNode("turbulence/factor",1).setValue(1.0);
+ i = i + 1;
+ }
+ fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+ }
}
@@ -220,11 +211,18 @@ fgcommand("reinit", props.Node.new({subsystem:"environment"}));
var setTemperature = func (T) {
-# this is a rather dirty workaround till a better solution becomes available
-# essentially we update the entry in config and reinit environment
-
-setprop(ec~"boundary/entry[0]/temperature-degc",T);
-fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+if (features.can_disable_environment == 1)
+ {
+ setprop("/environment/temperature-sea-level-degc",T);
+ }
+else
+ {
+ # this is a workaround for systems which lack hard-coded support
+ # essentially we update the entry in config and reinit environment
+
+ setprop(ec~"boundary/entry[0]/temperature-degc",T);
+ fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+ }
}
####################################
@@ -233,12 +231,19 @@ fgcommand("reinit", props.Node.new({subsystem:"environment"}));
var setPressure = func (p) {
-# this is a rather dirty workaround till a better solution becomes available
-# essentially we update the entry in config and reinit environment
+if (features.can_disable_environment == 1)
+ {
+ setprop("/environment/pressure-sea-level-inhg",p);
+ }
+else
+ {
+ # this is a workaround for systems which lack hard-coded support
+ # essentially we update the entry in config and reinit environment
-setprop(ec~"boundary/entry[0]/pressure-sea-level-inhg",p);
-setprop(ec~"aloft/entry[0]/pressure-sea-level-inhg",p);
-fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+ setprop(ec~"boundary/entry[0]/pressure-sea-level-inhg",p);
+ setprop(ec~"aloft/entry[0]/pressure-sea-level-inhg",p);
+ fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+ }
}
####################################
@@ -247,11 +252,30 @@ fgcommand("reinit", props.Node.new({subsystem:"environment"}));
var setDewpoint = func (D) {
-# this is a rather dirty workaround till a better solution becomes available
-# essentially we update the entry in config and reinit environment
+if (features.can_disable_environment == 1)
+ {
+ setprop("/environment/dewpoint-sea-level-degc",D);
+ }
+else
+ {
+ # this is a workaround for systems which lack hard-coded support
+ # essentially we update the entry in config and reinit environment
-setprop(ec~"boundary/entry[0]/dewpoint-degc",D);
-fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+ setprop(ec~"boundary/entry[0]/dewpoint-degc",D);
+ fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+ }
+}
+
+####################################
+# set light saturation to given value
+####################################
+
+var setLight = func (s) {
+
+if (features.can_set_light == 1)
+ {
+ setprop("/rendering/scene/saturation",s);
+ }
}
###########################################################
@@ -261,23 +285,30 @@ fgcommand("reinit", props.Node.new({subsystem:"environment"}));
var setWind = func (dir, speed) {
-# this is a rather dirty workaround till a better solution becomes available
-# essentially we update all entries in config and reinit environment
+if (features.can_disable_environment == 1)
+ {
+ setprop("/environment/wind-from-heading-deg",dir);
+ setprop("/environment/wind-speed-kt",speed);
+ }
+else
+ {
+ # this is a workaround for systems which lack hard-coded support
+ # essentially we update all entries in config and reinit environment
+
+ var entries_aloft = props.globals.getNode("environment/config/aloft", 1).getChildren("entry");
+ foreach (var e; entries_aloft) {
+ e.getNode("wind-from-heading-deg",1).setValue(dir);
+ e.getNode("wind-speed-kt",1).setValue(speed);
+ }
-var entries_aloft = props.globals.getNode("environment/config/aloft", 1).getChildren("entry");
-foreach (var e; entries_aloft) {
- e.getNode("wind-from-heading-deg",1).setValue(dir);
- e.getNode("wind-speed-kt",1).setValue(speed);
- }
-
-var entries_boundary = props.globals.getNode("environment/config/boundary", 1).getChildren("entry");
-foreach (var e; entries_boundary) {
- e.getNode("wind-from-heading-deg",1).setValue(dir);
- e.getNode("wind-speed-kt",1).setValue(speed);
- }
-
-fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+ var entries_boundary = props.globals.getNode("environment/config/boundary", 1).getChildren("entry");
+ foreach (var e; entries_boundary) {
+ e.getNode("wind-from-heading-deg",1).setValue(dir);
+ e.getNode("wind-speed-kt",1).setValue(speed);
+ }
+ fgcommand("reinit", props.Node.new({subsystem:"environment"}));
+ }
}
###########################################################
@@ -288,21 +319,29 @@ fgcommand("reinit", props.Node.new({subsystem:"environment"}));
var setWindSmoothly = func (dir, speed) {
-var entries_aloft = props.globals.getNode("environment/config/aloft", 1).getChildren("entry");
+if (features.can_disable_environment == 1)
+ {
+ setWind(dir, speed);
+ }
+else
+ {
-var dir_old = entries_aloft[0].getNode("wind-from-heading-deg",1).getValue();
-var speed_old = entries_aloft[0].getNode("wind-speed-kt",1).getValue();
+ var entries_aloft = props.globals.getNode("environment/config/aloft", 1).getChildren("entry");
-var dir = dir * math.pi/180.0;
-var dir_old = dir_old * math.pi/180.0;
+ var dir_old = entries_aloft[0].getNode("wind-from-heading-deg",1).getValue();
+ var speed_old = entries_aloft[0].getNode("wind-speed-kt",1).getValue();
-var vx = speed * math.sin(dir);
-var vx_old = speed_old * math.sin(dir_old);
+ var dir = dir * math.pi/180.0;
+ var dir_old = dir_old * math.pi/180.0;
-var vy = speed * math.cos(dir);
-var vy_old = speed_old * math.cos(dir_old);
+ var vx = speed * math.sin(dir);
+ var vx_old = speed_old * math.sin(dir_old);
-smooth_wind_loop(vx,vy,vx_old, vy_old, 4, 4);
+ var vy = speed * math.cos(dir);
+ var vy_old = speed_old * math.cos(dir_old);
+
+ smooth_wind_loop(vx,vy,vx_old, vy_old, 4, 4);
+ }
}
@@ -335,10 +374,35 @@ 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;
+# check if we deal with a convective cloud
+
+var convective_flag = 0;
+
+if (find("cumulus",path) != -1)
+ {
+ if ((find("alto",path) != -1) or (find("cirro", path) != -1) or (find("strato", path) != -1))
+ {convective_flag = 0;}
+ else if ((find("small",path) != -1) or (find("whisp",path) != -1))
+ {convective_flag = 1;}
+ else if (find("bottom",path) != -1)
+ {convective_flag = 4;}
+ else
+ {convective_flag = 2;}
+
+ }
+else if (find("congestus",path) != -1)
+ {
+ if (find("bottom",path) != -1)
+ {convective_flag = 5;}
+ else
+ {convective_flag = 3;}
+ }
+
+#print("path: ", path, " flag: ", convective_flag);
+
# 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)
@@ -352,8 +416,17 @@ if (buffer_flag == 1)
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;}
+ var b = weather_tile_management.cloudBuffer.new(lat, long, alt, path, heading, tile_counter, convective_flag);
+ if (local_weather.dynamics_flag ==1)
+ {
+ b.timestamp = weather_dynamics.time_lw;
+ if (convective_flag !=0) # Cumulus clouds get some extra info
+ {
+ b.evolution_timestamp = cloud_evolution_timestamp;
+ b.flt = cloud_flt;
+ b.rel_alt = alt - cloud_mean_altitude;
+ }
+ }
append(weather_tile_management.cloudBufferArray,b);
return;
}
@@ -364,10 +437,12 @@ if (buffer_flag == 1)
if (getprop(lw~"tmp/buffer-status") == "placing")
{
- tile_counter = getprop(lw~"tmp/buffer-tile-index");
+ #tile_counter = getprop(lw~"tmp/buffer-tile-index");
+ tile_counter = buffered_tile_index;
}
+
# if the cloud is not buffered, get property tree nodes and write it
# into the scenery
@@ -382,6 +457,7 @@ var cloud_number = n.getNode("placement-index").getValue();
cl = c.getChild("cloud", i, 1);
n.getNode("placement-index").setValue(i);
+ var placement_index = i;
var model_number = n.getNode("model-placement-index").getValue();
var m = props.globals.getNode("models", 1);
@@ -397,8 +473,6 @@ var latN = cl.getNode("position/latitude-deg", 1); latN.setValue(lat);
var lonN = cl.getNode("position/longitude-deg", 1); lonN.setValue(long);
var altN = cl.getNode("position/altitude-ft", 1); altN.setValue(alt);
var hdgN = cl.getNode("orientation/true-heading-deg", 1); hdgN.setValue(heading);
-#var pitchN = cl.getNode("orientation/pitch-deg", 1); pitchN.setValue(0.0);
-#var rollN = cl.getNode("orientation/roll-deg", 1);rollN.setValue(0.0);
cl.getNode("tile-index",1).setValue(tile_counter);
@@ -407,35 +481,57 @@ model.getNode("latitude-deg-prop", 1).setValue(latN.getPath());
model.getNode("longitude-deg-prop", 1).setValue(lonN.getPath());
model.getNode("elevation-ft-prop", 1).setValue(altN.getPath());
model.getNode("heading-deg-prop", 1).setValue(hdgN.getPath());
-#model.getNode("pitch-deg-prop", 1).setValue(pitchN.getPath());
-#model.getNode("roll-deg-prop", 1).setValue(rollN.getPath());
model.getNode("tile-index",1).setValue(tile_counter);
model.getNode("load", 1).remove();
-n.getNode("cloud-number").setValue(n.getNode("cloud-number").getValue()+1);
# sort the model node into a vector for easy deletion
-
# append(weather_tile_management.modelArrays[tile_counter-1],model);
# sort the cloud into the cloud hash array
-if ((buffer_flag == 1) and (getprop(lw~"tmp/tile-management") != "single tile"))
+if (buffer_flag == 1)
{
- var cs = weather_tile_management.cloudScenery.new(tile_counter, cl, model);
+ var cs = weather_tile_management.cloudScenery.new(tile_counter, convective_flag, cl, model);
append(weather_tile_management.cloudSceneryArray,cs);
}
-# if weather dynamics is on, also create a timestamp property and sort the cloud node into quadtree
+# if weather dynamics is on, also create a timestamp property and sort the cloud hash into quadtree
-#if (getprop(lw~"config/dynamics-flag") == 1)
-if (dynamics_flag == 1)
+if (local_weather.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.cloudQuadtrees[tile_counter-1], cl);
+ cs.timestamp = weather_dynamics.time_lw;
+ cs.write_index = placement_index;
+
+ if (convective_flag !=0) # Cumulus clouds get some extra info
+ {
+ cs.evolution_timestamp = cloud_evolution_timestamp;
+ cs.flt = cloud_flt;
+ cs.rel_alt = alt - cloud_mean_altitude;
+ cs.target_alt = alt;
+ }
+
+ if (getprop(lw~"tmp/buffer-status") == "placing")
+ {
+ var blat = buffered_tile_latitude;
+ var blon = buffered_tile_longitude;
+ var alpha = buffered_tile_alpha;
+ #var blat1 = getprop(lw~"tiles/tmp/latitude-deg");
+ #var blon1 = getprop(lw~"tiles/tmp/longitude-deg");
+ #var alpha1 = getprop(lw~"tmp/tile-orientation-deg");
+
+ #print("Lat: ", blat1, " ", blat);
+ #print("Lon: ", blon1, " ", blon);
+ #print("Alp: ", alpha1, " ", alpha);
+
+ }
+ else
+ {
+ 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.cloudQuadtrees[tile_counter-1], cs);
}
}
@@ -451,12 +547,13 @@ if (getprop(lw~"tmp/thread-status") != "placing") {return;}
if (getprop(lw~"tmp/convective-status") != "idle") {return;}
if ((i < 0) or (i==0))
{
- print("Cloud placement from array finished!");
+ if (local_weather.debug_output_flag == 1)
+ {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;
@@ -470,6 +567,12 @@ if (s < k_max) {k_max = s;}
for (var k = 0; k < k_max; k = k+1)
{
+ if (getprop(lw~"config/dynamics-flag") ==1)
+ {
+ cloud_mean_altitude = local_weather.clouds_mean_alt[s-k-1];
+ cloud_flt = local_weather.clouds_flt[s-k-1];
+ cloud_evolution_timestamp = local_weather.clouds_evolution_timestamp[s-k-1];
+ }
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]);
}
@@ -479,144 +582,19 @@ setsize(clouds_lon,s-k_max);
setsize(clouds_alt,s-k_max);
setsize(clouds_orientation,s-k_max);
+if (getprop(lw~"config/dynamics-flag") ==1)
+ {
+ setsize(local_weather.clouds_mean_alt,s-k_max);
+ setsize(local_weather.clouds_flt,s-k_max);
+ setsize(local_weather.clouds_evolution_timestamp,s-k_max);
+ }
+
settimer( func {create_cloud_array(i - k, clouds_path, clouds_lat, clouds_lon, clouds_alt, clouds_orientation ) }, 0 );
};
-####################################################
-# move a cloud
-####################################################
-
-var move_cloud = func (c, tile_index) {
-
-# get the old spacetime position of the cloud
-
-var lat_old = c.getNode("position/latitude-deg").getValue();
-var lon_old = c.getNode("position/longitude-deg").getValue();
-var alt = c.getNode("position/altitude-ft").getValue();
-var timestamp = c.getNode("timestamp-sec").getValue();
-
-# get windfield and time since last update
-
-var windfield = weather_dynamics.get_windfield(tile_index);
-var dt = weather_dynamics.time_lw - timestamp;
-
-#print(dt * windfield[1]);
-
-# update the spacetime position of the cloud
-
-c.getNode("position/latitude-deg",1).setValue(lat_old + windfield[1] * dt * local_weather.m_to_lat);
-c.getNode("position/longitude-deg",1).setValue(lon_old + windfield[0] * dt * local_weather.m_to_lon);
-c.getNode("timestamp-sec",1).setValue(weather_dynamics.time_lw);
-
-}
-####################################################
-# remove clouds by tile index
-####################################################
-
-var remove_clouds = func (index) {
-
-var n = size(props.globals.getNode("local-weather/clouds").getChild("tile",index,1).getChildren("cloud"));
-props.globals.getNode("local-weather/clouds", 1).removeChild("tile",index);
-setprop(lw~"clouds/cloud-number",getprop(lw~"clouds/cloud-number")-n);
-
-if (getprop(lw~"tmp/thread-flag") == 1)
- {settimer( func {waiting_loop(index); },0);}
-else
- {
- var modelNode = props.globals.getNode("models", 1).getChildren("model");
- foreach (var m; modelNode)
- {
- if (m.getNode("tile-index",1).getValue() == index) {m.remove();}
- }
- }
-
-
-}
-
-
-
-# this is to avoid two tile removal loops starting at the same time
-
-var waiting_loop = func (index) {
-
-var status = getprop(lw~"tmp/thread-status");
-
-if (status == "idle") {remove_tile_loop(index);}
-
-else {
- print("Removal of ",index, " waiting for idle thread...");
- settimer( func {waiting_loop(index); },1.0);
- }
-}
-
-
-var remove_tile_loop = func (index) {
-
-var n = 100;
-
-var flag_mod = 0;
-
-
-var status = getprop(lw~"tmp/thread-status");
-
-if ((status == "computing") or (status == "placing")) # the array is blocked
- {
- settimer( func {remove_tile_loop(index); },0); # try again next frame
- return;
- }
-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");
- }
-
-var lastpos = getprop(lw~"tmp/last-reading-pos-mod");
-
-
-if (lastpos < (msize-1)) {var istart = lastpos;} else {var istart = (msize-1);}
-
-if (istart<0) {istart=0;}
-
-var i_min = istart - n;
-if (i_min < -1) {i_min =-1;}
-
-for (var i = istart; i > i_min; i = i- 1)
- {
- m = mvec[i];
- m.remove();
- }
-
-if (i<0) {flag_mod = 1;}
-
-
-if (flag_mod == 0) {setprop(lw~"tmp/last-reading-pos-mod",i); }
-
-if (flag_mod == 0) # we still have work to do
- {settimer( func {remove_tile_loop(index); },0);}
-else
- {
- 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);
- }
-
-}
@@ -629,7 +607,8 @@ var get_elevation = func (lat, lon) {
var info = geodinfo(lat, lon);
if (info != nil) {var elevation = info[0] * local_weather.m_to_ft;}
- else {var elevation = -1.0;}
+ else {var elevation = -1.0; }
+
return elevation;
}
@@ -643,17 +622,12 @@ var get_elevation_array = func (lat, lon) {
var elevation = [];
var n = size(lat);
-if (features.geodinfo_supports_vectors == 0)
+
+for(var i = 0; i < n; i=i+1)
{
- for(var i = 0; i < n; i=i+1)
- {
- append(elevation, get_elevation(lat[i], lon[i]));
- }
- }
-else
- {
- elevation = geodinfo(lat,10000);
+ append(elevation, get_elevation(lat[i], lon[i]));
}
+
return elevation;
}
@@ -673,3 +647,20 @@ var ec = "/environment/config/";
var mvec = [];
var msize = 0;
+
+# available hard-coded support
+
+var features = {};
+
+# globals to transmit info if clouds are written from buffer
+
+var buffered_tile_latitude = 0.0;
+var buffered_tile_longitude = 0.0;
+var buffered_tile_alpha = 0.0;
+var buffered_tile_index = 0;
+
+# globals to handle additional info for Cumulus cloud dynamics
+
+var cloud_mean_altitude = 0.0;
+var cloud_flt = 0.0;
+var cloud_evolution_timestamp = 0.0;
diff --git a/Nasal/controls.nas b/Nasal/controls.nas
index 016a35402..2d3f41441 100644
--- a/Nasal/controls.nas
+++ b/Nasal/controls.nas
@@ -74,6 +74,51 @@ var mixtureAxis = axisHandler("/controls/engines/engine[", "]/mixture");
var propellerAxis = axisHandler("/controls/engines/engine[", "]/propeller-pitch");
var carbHeatAxis = axisHandler("/controls/anti-ice/engine[", "]/carb-heat");
+# Joystick axis handler for controlling subsets of similar properties.
+# Shouldn't be called from other contexts.
+# The argument engine can be either an index number or a list of
+# index numbers.
+# Use only when perEngineSelectedAxisHandler() below will not do.
+var perIndexAxisHandler = func(pre, post) {
+ return
+ func(index, invert = 0) {
+ var val = cmdarg().getNode("setting").getValue();
+ if(invert) val = -val;
+ if (typeof(index) == "scalar") {
+ setprop(pre ~ index ~ post, (1 - val) / 2);
+ } else {
+ foreach (var e; index) {
+ setprop(pre ~ e ~ post, (1 - val) / 2);
+ }
+ }
+ };
+}
+
+# Joystick axis handler for controlling a selected axis on specific engines.
+# Shouldn't be called from other contexts.
+# The argument mode can be
+# 0 - throttle
+# 1 - mixture
+# 2 - propeller-pitch
+# The argument engine to the returned function can be either an
+# engine number or a list of engine numbers.
+# Usage example (controlling the mixture of engines 1 and 2):
+#
+var _axisMode = {
+ 0: perIndexAxisHandler("/controls/engines/engine[",
+ "]/throttle"),
+ 1: perIndexAxisHandler("/controls/engines/engine[",
+ "]/mixture"),
+ 2: perIndexAxisHandler("/controls/engines/engine[",
+ "]/propeller-pitch")
+};
+var perEngineSelectedAxisHandler = func(mode) {
+ return _axisMode[mode];
+}
+
+
##
# Wrapper around stepProps() which emulates the "old" flap behavior for
# configurations that aren't using the new mechanism.
diff --git a/Nasal/local_weather.nas b/Nasal/local_weather.nas
index 21badfc29..0b0240b2c 100644
--- a/Nasal/local_weather.nas
+++ b/Nasal/local_weather.nas
@@ -1,7 +1,7 @@
########################################################
# routines to set up, transform and manage local weather
-# Thorsten Renk, July 2010
+# Thorsten Renk, October 2010
# thermal model by Patrice Poly, April 2010
########################################################
@@ -10,19 +10,24 @@
# calc_geo to compute the latitude to meter conversion
# calc_d_sq to compute a distance square in local Cartesian approximation
# effect_volume_loop to check if the aircraft has entered an effect volume
-# assemble_effect_array to create a Nasal internal array with pointers to all effect volumes
+# assemble_effect_array to store the size of the effect volume array
# add_vectors to add two vectors in polar coordinates
# wind_altitude_interpolation to interpolate aloft winds in altitude
# wind_interpolation to interpolate aloft winds in altitude and position
# interpolation_loop to continuously interpolate weather parameters between stations
-# thermal_lift _loop to manage the detailed thermal lift model
# thermal_lift_start to start the detailed thermal model
+# thermal_lift_loop to manage the detailed thermal lift model
+# thermal_lift_stop to end the detailed thermal lift model
+# wave_lift_start to start the detailed wave lift model
+# wave_lift_loop to manage the detailed wave lift model
+# wave_lift_stop to end the detailed wave lift model
# effect_volume_start to manage parameters when an effect volume is entered
# effect_volume_stop to manage parameters when an effect volume is left
# ts_factor (helper function for thermal lift model)
# tl_factor (helper function for thermal lift model)
# calcLift_max to calculate the maximal available thermal lift for given altitude
# calcLift to calculate the thermal lift at aircraft position
+# calcWaveLift to calculate wave lift at aircraft position
# select_cloud_model to select a path to the cloud model, given the cloud type and subtype
# create_cloud_vec to place a single cloud into an array to be written later
# clear_all to remove all clouds, effect volumes and weather stations and stop loops
@@ -31,6 +36,7 @@
# create_cumosys wrapper to place a convective cloud system based on terrain coverage
# cumulus_loop to place 25 Cumulus clouds each frame
# create_cumulus to place a convective cloud system based on terrain coverage
+# recreate_cumulus to respawn convective clouds as part of the convective dynamics algorithm
# cumulus_exclusion_layer to create a layer with 'holes' left for thunderstorm placement
# create_rise_clouds to create a barrier cloud system
# create_streak to create a cloud streak
@@ -41,22 +47,33 @@
# terrain_presampling_loop to sample 25 terrain points per frame
# terrain_presampling to sample terrain elevation at a random point within specified area
# terrain_presampling_analysis to analyze terrain presampling results
+# wave_detection_loop to detect if and where wave lift should be placed (currently unfinished)
# get_convective_altitude to determine the altitude at which a Cumulus cloud is placed
# manage presampling to take proper action when a presampling call has been finished
# set_wind_model_flag to convert the wind model string into an integer flag
+# set_texture_mix to determine the texture mix between smooth and rough cloud appearance
# create_effect_volume to create an effect volume
# set_weather_station to specify a weather station for interpolation
# set_wind_ipoint to set an aloft wind interpolation point
# showDialog to pop up a dialog window
+# readFlags to read configuration flags from the property tree into Nasal variables at startup
# streak_wrapper wrapper to execute streak from menu
# convection wrapper wrapper to execute convective clouds from menu
# barrier wrapper wrapper to execute barrier clouds from menu
# single_cloud_wrapper wrapper to create single cloud from menu
# layer wrapper wrapper to create layer from menu
# box wrapper wrapper to create a cloudbox (experimental)
-# set aloft wrapper wrapper to create aloft winds from menu
+# set_aloft wrapper wrapper to create aloft winds from menu
# set_tile to call a weather tile creation from menu
# startup to prepare the package at startup
+# test to serve as a testbed for new functions
+
+# object purpose
+
+# weatherStation to store info about weather conditions
+# effectVolume to store effect volume info and provide methods to move and time-evolve effect volumes
+# thermalLift to store thermal info and provide methods to move and time-evolve a thermal
+# waveLift to store wave info
###################################
# geospatial helper functions
@@ -89,8 +106,7 @@ return (x*x + y*y);
var effect_volume_loop = func (index, n_active) {
var n = 25;
-#var evNode = props.globals.getNode("local-weather/effect-volumes", 1).getChildren("effect-volume");
-#var esize = size(evNode);
+
var esize = n_effectVolumeArray;
@@ -102,21 +118,22 @@ if (i_max > esize) {i_max = esize;}
for (var i = index; i < i_max; i = i+1)
{
- #e = evNode[i];
- e = effectVolumeArray[i];
+ var e = effectVolumeArray[i];
- var flag = 0; #default assumption is that we're not in the volume
- var ealt_min = e.getNode("position/min-altitude-ft").getValue() * ft_to_m;
- var ealt_max = e.getNode("position/max-altitude-ft").getValue() * ft_to_m;
+ var flag = 0; # default assumption is that we're not in the volume
+
+ var ealt_min = e.alt_low * ft_to_m;
+ var ealt_max = e.alt_high * ft_to_m;
+
if ((viewpos.alt() > ealt_min) and (viewpos.alt() < ealt_max)) # we are in the correct alt range
{
# so we load geometry next
- var geometry = e.getNode("geometry").getValue();
- var elat = e.getNode("position/latitude-deg").getValue();
- var elon = e.getNode("position/longitude-deg").getValue();
- var rx = e.getNode("volume/size-x").getValue();
-
+
+ var geometry = e.geometry;
+ var elat = e.lat;
+ var elon = e.lon;
+ var rx = e.r1;
if (geometry == 1) # we have a cylinder
{
@@ -126,23 +143,31 @@ for (var i = index; i < i_max; i = i+1)
else if (geometry == 2) # we have an elliptic shape
{
# get orientation
- var ry = e.getNode("volume/size-y").getValue();
- var phi = e.getNode("volume/orientation-deg").getValue();
+
+ var ry = e.r2;
+ var phi = e.phi;
+
phi = phi * math.pi/180.0;
+
+
# first get unrotated coordinates
var xx = (viewpos.lon() - elon) * lon_to_m;
var yy = (viewpos.lat() - elat) * lat_to_m;
+
# then rotate to align with the shape
var x = xx * math.cos(phi) - yy * math.sin(phi);
var y = yy * math.cos(phi) + xx * math.sin(phi);
+
# then check elliptic condition
if ((x*x)/(rx*rx) + (y*y)/(ry*ry) <1) {flag = 1;}
}
else if (geometry == 3) # we have a rectangular shape
{
# get orientation
- var ry = e.getNode("volume/size-y").getValue();
- var phi = e.getNode("volume/orientation-deg").getValue();
+
+ var ry = e.r2;
+ var phi = e.phi;
+
phi = phi * math.pi/180.0;
# first get unrotated coordinates
var xx = (viewpos.lon() - elon) * lon_to_m;
@@ -159,20 +184,20 @@ for (var i = index; i < i_max; i = i+1)
# if flag ==1 at this point, we are inside the effect volume
# but we only need to take action on entering and leaving, so we check also active_flag
- #if (flag==1) {print("Inside volume");}
+ # if (flag==1) {print("Inside volume");}
- var active_flag = e.getNode("active-flag").getValue(); # see if the node was active previously
+ var active_flag = e.active_flag;
if ((flag==1) and (active_flag ==0)) # we just entered the node
{
- #print("Entered volume");
- e.getNode("active-flag").setValue(1);
+ #print("Entered volume");
+ e.active_flag = 1;
effect_volume_start(e);
}
else if ((flag==0) and (active_flag ==1)) # we left an active node
{
#print("Left volume!");
- e.getNode("active-flag").setValue(0);
+ e.active_flag = 0;
effect_volume_stop(e);
}
if (flag==1) {active_counter = active_counter + 1;} # we still count the active volumes
@@ -184,7 +209,6 @@ for (var i = index; i < i_max; i = i+1)
# therefore we zero them for redundancy here so that the interpolation loop can take over
# and set the properties correctly for outside
-#print(i);
if (i == esize) # we check the number of actives and reset all counters
{
@@ -196,6 +220,7 @@ if (i == esize) # we check the number of actives and reset all counters
vNode.getChild("number-active-rain").setValue(0);
vNode.getChild("number-active-lift").setValue(0);
vNode.getChild("number-active-turb").setValue(0);
+ vNode.getChild("number-active-sat").setValue(0);
}
#print("n_active: ", active_counter);
active_counter = 0; i = 0;
@@ -215,10 +240,7 @@ if (getprop(lw~"effect-loop-flag") ==1) {settimer( func {effect_volume_loop(i, a
var assemble_effect_array = func {
-setsize(effectVolumeArray,0);
-effectVolumeArray = props.globals.getNode("local-weather/effect-volumes", 1).getChildren("effect-volume");
n_effectVolumeArray = size(effectVolumeArray);
-#print("Effect vector size: ",n_effectVolumeArray);
}
@@ -326,7 +348,6 @@ var interpolation_loop = func {
var iNode = props.globals.getNode(lw~"interpolation", 1);
var cNode = props.globals.getNode(lw~"current", 1);
-var stNode = iNode.getChildren("station");
var viewpos = geo.aircraft_position();
var sum_vis = 0.0;
@@ -338,33 +359,53 @@ var sum_norm = 0.0;
# get an inverse distance weighted average from all defined weather stations
-foreach (var s; stNode) {
+
+var n_stations = size(weatherStationArray);
+
+for (var i = 0; i < n_stations; i=i+1) {
- var slat = s.getNode("latitude-deg").getValue();
- var slon = s.getNode("longitude-deg").getValue();
+ s = weatherStationArray[i];
var stpos = geo.Coord.new();
- stpos.set_latlon(slat,slon,1000.0);
+ stpos.set_latlon(s.lat,s.lon,0.0);
var d = viewpos.distance_to(stpos);
if (d <100.0) {d = 100.0;} # to prevent singularity at zero
- sum_norm = sum_norm + 1./d;
- sum_vis = sum_vis + (s.getNode("visibility-m").getValue()/d);
- sum_T = sum_T + (s.getNode("temperature-degc").getValue()/d);
- sum_D = sum_D + (s.getNode("dewpoint-degc").getValue()/d);
- sum_p = sum_p + (s.getNode("pressure-sea-level-inhg").getValue()/d);
+ sum_norm = sum_norm + 1./d * s.weight;
+
+
+ sum_vis = sum_vis + (s.vis/d) * s.weight;
+ sum_T = sum_T + (s.T/d) * s.weight;
+ sum_D = sum_D + (s.D/d) * s.weight;
+ sum_p = sum_p + (s.p/d) * s.weight;
+
+ # gradually fade in the interpolation weight of newly added stations to
+ # avoid sudden jumps
+
+ if (s.weight < 1.0) {s.weight = s.weight + 0.1;}
# automatically delete stations out of range
# take care not to unload if weird values appear for a moment
- if ((d > 80000.0) and (d<100000.0)) {s.remove();}
+ if ((d > 80000.0) and (d<100000.0))
+ {
+ if (debug_output_flag == 1)
+ {print("Distance to weather station ", d, " m, unloading ...", i);}
+ weatherStationArray = weather_tile_management.delete_from_vector(weatherStationArray,i);
+ i = i-1; n_stations = n_stations -1;
+ }
}
+setprop(lwi~"station-number", i);
+
+
+
var vis = sum_vis/sum_norm;
var p = sum_p/sum_norm;
var D = sum_D/sum_norm;
var T = sum_T/sum_norm;
+
# a simple altitude model for visibility - increase it with increasing altitude
var altitude = getprop("position/altitude-ft");
@@ -446,7 +487,7 @@ else if (wind_model_flag == 5) # aloft waypoint interpolated
var altitude_agl = getprop("/position/altitude-agl-ft");
-if (getprop(lw~"tmp/presampling-flag") == 0)
+if (presampling_flag == 0)
{
var boundary_alt = 600.0;
var windspeed_ground = windspeed/3.0;
@@ -502,64 +543,40 @@ if (getprop(lw~"interpolation-loop-flag") ==1) {settimer(interpolation_loop, 1.0
}
-###################################
-# thermal lift loop
-###################################
-
-var thermal_lift_loop = func {
-
-var cNode = props.globals.getNode(lw~"current", 1);
-var lNode = props.globals.getNode(lw~"lift",1);
-
-var apos = geo.aircraft_position();
-
-var tlat = lNode.getNode("latitude-deg").getValue();
-var tlon = lNode.getNode("longitude-deg").getValue();
-var tpos = geo.Coord.new();
-tpos.set_latlon(tlat,tlon,0.0);
-
-var d = apos.distance_to(tpos);
-var alt = getprop("position/altitude-ft");
-
-
-var R = lNode.getNode("radius").getValue();
-var height = lNode.getNode("height").getValue();
-var cn = lNode.getNode("cn").getValue();
-var sh = lNode.getNode("sh").getValue();
-var max_lift = lNode.getNode("max_lift").getValue();
-var f_lift_radius = lNode.getNode("f_lift_radius").getValue();
-
-# print(d," ", alt, " ", R, " ", height, " ", cn, " ", sh," ", max_lift," ", f_lift_radius, " ",0.0);
-
-var lift = calcLift(d, alt, R, height, cn, sh, max_lift, f_lift_radius, 0.0);
-# print(lift);
-
-cNode.getChild("thermal-lift").setValue(lift);
-
-if (getprop(lw~"lift-loop-flag") ==1) {settimer(thermal_lift_loop, 0);}
-}
-
###################################
# thermal lift loop startup
###################################
var thermal_lift_start = func (ev) {
-# copy the properties from effect volume to the lift folder
+# copy the properties from effect volume to the lift object
-var lNode = props.globals.getNode(lw~"lift",1);
-lNode.getNode("radius",1).setValue(ev.getNode("effects/radius").getValue());
-lNode.getNode("height",1).setValue(ev.getNode("effects/height").getValue());
-lNode.getNode("cn",1).setValue(ev.getNode("effects/cn").getValue());
-lNode.getNode("sh",1).setValue(ev.getNode("effects/sh").getValue());
-lNode.getNode("max_lift",1).setValue(ev.getNode("effects/max_lift").getValue());
-lNode.getNode("f_lift_radius",1).setValue(ev.getNode("effects/f_lift_radius").getValue());
+l = thermalLift.new(ev.lat, ev.lon, ev.radius, ev.height, ev.cn, ev.sh, ev.max_lift, ev.f_lift_radius);
-#lNode.getNode("latitude-deg",1).setValue(ev.getNode("position/latitude-deg").getValue());
-#lNode.getNode("longitude-deg",1).setValue(ev.getNode("position/longitude-deg").getValue());
+l.index = ev.index;
-lNode.getNode("latitude-deg",1).alias(ev.getNode("position/latitude-deg"));
-lNode.getNode("longitude-deg",1).alias(ev.getNode("position/longitude-deg"));
+if (dynamics_flag == 1)
+ {
+ l.timestamp = weather_dynamics.time_lw;
+ if (dynamical_convection_flag == 1)
+ {
+ l.flt = ev.flt;
+ l.evolution_timestamp = ev.evolution_timestamp;
+ }
+ }
+
+
+
+thermal = l;
+
+if (debug_output_flag == 1)
+ {
+ print("Entering thermal lift...");
+ print("strength: ", thermal.max_lift, " radius: ", thermal.radius);
+ if (dynamical_convection_flag ==1)
+ {print("fractional lifetime: ", thermal.flt);}
+
+ }
# and start the lift loop, unless another one is already running
# so we block overlapping calls
@@ -569,23 +586,157 @@ if (getprop(lw~"lift-loop-flag") == 0)
}
+###################################
+# thermal lift loop
+###################################
+
+var thermal_lift_loop = func {
+
+var apos = geo.aircraft_position();
+
+var tlat = thermal.lat;
+var tlon = thermal.lon;
+
+var tpos = geo.Coord.new();
+tpos.set_latlon(tlat,tlon,0.0);
+
+var d = apos.distance_to(tpos);
+var alt = getprop("position/altitude-ft");
+
+if (dynamical_convection_flag == 1)
+ {var flt = thermal.flt;}
+else
+ {var flt = 0.5;}
+
+var lift = calcLift(d, alt, thermal.radius, thermal.height, thermal.cn, thermal.sh, thermal.max_lift, thermal.f_lift_radius, flt);
+
+if (getprop(lw~"wave-loop-flag") ==1)
+ {
+ lift = lift + getprop(lw~"current/wave-lift");
+ }
+
+
+setprop(lw~"current/thermal-lift",lift);
+compat_layer.setLift(lift);
+
+# if dynamics is on, move the thermal and occasionally compute altitude and age
+
+if (dynamics_flag == 1)
+ {
+ thermal.move();
+
+ if ((rand() < 0.01) and (presampling_flag == 1)) # check every 100 frames
+ {
+ if (dynamical_convection_flag == 1)
+ {
+ thermal.correct_altitude_and_age();
+ if (thermal.flt > 1.1)
+ {thermal_lift_stop();}
+ }
+ else
+ {
+ thermal.correct_altitude();
+ }
+ }
+ }
+
+
+if (getprop(lw~"lift-loop-flag") ==1) {settimer(thermal_lift_loop, 0);}
+}
+
+
+
+
+
###################################
# thermal lift loop stop
###################################
var thermal_lift_stop = func {
-# unalias later to avoid an error being generated
-
-settimer( func {
-var lNode = props.globals.getNode(lw~"lift",1);
-lNode.getNode("latitude-deg",1).unalias();
-lNode.getNode("longitude-deg",1).unalias(); },0.1);
-
setprop(lw~"lift-loop-flag",0);
setprop(lw~"current/thermal-lift",0.0);
+compat_layer.setLift(0.0);
+
+if (debug_output_flag == 1)
+ {
+ print("Leaving thermal lift...");
+ }
+
}
+
+###################################
+# wave lift loop startup
+###################################
+
+var wave_lift_start = func (ev) {
+
+# copy the properties from effect volume to the wave object
+
+
+w = waveLift.new (ev.lat, ev.lon, ev.r1, ev.r2, ev.phi, ev.height, ev.max_lift);
+w.index = ev.index;
+wave = w;
+
+# and start the lift loop, unless another one is already running
+# so we block overlapping calls
+
+if (getprop(lw~"wave-loop-flag") == 0)
+{setprop(lw~"wave-loop-flag",1); settimer(wave_lift_loop,0);}
+
+}
+
+###################################
+# wave lift loop
+###################################
+
+var wave_lift_loop = func {
+
+var lat = getprop("position/latitude-deg");
+var lon = getprop("position/longitude-deg");
+var alt = getprop("position/altitude-ft");
+
+
+var phi = wave.phi * math.pi/180.0;
+
+var xx = (lon - wave.lon) * lon_to_m;
+var yy = (lat - wave.lat) * lat_to_m;
+
+var x = xx * math.cos(phi) - yy * math.sin(phi);
+var y = yy * math.cos(phi) + xx * math.sin(phi);
+
+var lift = calcWaveLift(x,y,alt);
+
+# check if we are in a thermal, if so set wave lift and let the thermal lift loop add that
+
+if (getprop(lw~"lift-loop-flag") ==1)
+ {
+ setprop(lw~"current/wave-lift",lift);
+ }
+else
+ {
+ setprop(lw~"current/thermal-lift",lift);
+ }
+
+if (getprop(lw~"wave-loop-flag") ==1) {settimer(wave_lift_loop, 0);}
+}
+
+
+
+
+###################################
+# wave lift loop stop
+###################################
+
+var wave_lift_stop = func {
+
+setprop(lw~"wave-loop-flag",0);
+setprop(lw~"current/thermal-lift",0.0);
+}
+
+
+
####################################
# action taken when in effect volume
####################################
@@ -594,70 +745,86 @@ var effect_volume_start = func (ev) {
var cNode = props.globals.getNode(lw~"current");
-if (ev.getNode("effects/visibility-flag", 1).getValue()==1)
+
+if (ev.vis_flag ==1)
{
# first store the current setting in case we need to restore on leaving
- var vis = ev.getNode("effects/visibility-m").getValue();
- ev.getNode("restore/visibility-m",1).setValue(cNode.getNode("visibility-m").getValue());
+ var vis = ev.vis;
+ ev.vis_r = cNode.getNode("visibility-m").getValue();
+
# then set the new value in current and execute change
cNode.getNode("visibility-m").setValue(vis);
compat_layer.setVisibility(vis);
# then count the number of active volumes on entry (we need that to determine
# what to do on exit)
- ev.getNode("restore/number-entry-vis",1).setValue(getprop(lw~"effect-volumes/number-active-vis"));
-
+ ev.n_entry_vis = getprop(lw~"effect-volumes/number-active-vis");
+
# and add to the counter
setprop(lw~"effect-volumes/number-active-vis",getprop(lw~"effect-volumes/number-active-vis")+1);
}
-if (ev.getNode("effects/rain-flag", 1).getValue()==1)
+#if (ev.getNode("effects/rain-flag", 1).getValue()==1)
+if (ev.rain_flag == 1)
{
- var rain = ev.getNode("effects/rain-norm").getValue();
- ev.getNode("restore/rain-norm",1).setValue(cNode.getNode("rain-norm").getValue());
+ var rain = ev.rain;
+ ev.rain_r = cNode.getNode("rain-norm").getValue();
cNode.getNode("rain-norm").setValue(rain);
compat_layer.setRain(rain);
- ev.getNode("restore/number-entry-rain",1).setValue(getprop(lw~"effect-volumes/number-active-rain"));
+ ev.n_entry_rain = getprop(lw~"effect-volumes/number-active-rain");
setprop(lw~"effect-volumes/number-active-rain",getprop(lw~"effect-volumes/number-active-rain")+1);
}
-
-if (ev.getNode("effects/snow-flag", 1).getValue()==1)
+if (ev.snow_flag == 1)
{
- var snow = ev.getNode("effects/snow-norm").getValue();
- ev.getNode("restore/snow-norm",1).setValue(cNode.getNode("snow-norm").getValue());
+ var snow = ev.snow;
+ ev.snow_r = cNode.getNode("snow-norm").getValue();
cNode.getNode("snow-norm").setValue(snow);
compat_layer.setSnow(snow);
- ev.getNode("restore/number-entry-snow",1).setValue(getprop(lw~"effect-volumes/number-active-snow"));
+ ev.n_entry_snow = getprop(lw~"effect-volumes/number-active-snow");
setprop(lw~"effect-volumes/number-active-snow",getprop(lw~"effect-volumes/number-active-snow")+1);
}
-
-if (ev.getNode("effects/turbulence-flag", 1).getValue()==1)
+if (ev.turb_flag == 1)
{
- var turbulence = ev.getNode("effects/turbulence").getValue();
- ev.getNode("restore/turbulence",1).setValue(cNode.getNode("turbulence").getValue());
+ var turbulence = ev.turb;
+ ev.turb_r = cNode.getNode("turbulence").getValue();
cNode.getNode("turbulence").setValue(turbulence);
compat_layer.setTurbulence(turbulence);
- ev.getNode("restore/number-entry-turb",1).setValue(getprop(lw~"effect-volumes/number-active-turb"));
+ ev.n_entry_turb = getprop(lw~"effect-volumes/number-active-turb");
setprop(lw~"effect-volumes/number-active-turb",getprop(lw~"effect-volumes/number-active-turb")+1);
}
-
-if (ev.getNode("effects/thermal-lift-flag", 1).getValue()==1)
+if (ev.sat_flag == 1)
{
- var lift = ev.getNode("effects/thermal-lift").getValue();
- ev.getNode("restore/thermal-lift",1).setValue(cNode.getNode("thermal-lift").getValue());
+ var saturation = ev.sat;
+ ev.sat_r = getprop("/rendering/scene/saturation");
+ compat_layer.setLight(saturation);
+ ev.n_entry_sat = getprop(lw~"effect-volumes/number-active-sat");
+ setprop(lw~"effect-volumes/number-active-sat",getprop(lw~"effect-volumes/number-active-sat")+1);
+ }
+
+if (ev.lift_flag == 1)
+ {
+ var lift = ev.lift;
+ ev.lift_r = cNode.getNode("thermal-lift").getValue();
cNode.getNode("thermal-lift").setValue(lift);
- #setLift(ev.getNode("position/latitude-deg").getValue(),ev.getNode("position/longitude-deg").getValue(),1);
- ev.getNode("restore/number-entry-lift",1).setValue(getprop(lw~"effect-volumes/number-active-lift"));
+ compat_layer.setLift(lift);
+ ev.n_entry_lift = getprop(lw~"effect-volumes/number-active-lift");
setprop(lw~"effect-volumes/number-active-lift",getprop(lw~"effect-volumes/number-active-lift")+1);
}
-else if (ev.getNode("effects/thermal-lift-flag", 1).getValue()==2) # thermal by function
+else if (ev.lift_flag == 2)
{
- ev.getNode("restore/thermal-lift",1).setValue(cNode.getNode("thermal-lift").getValue());
- ev.getNode("restore/number-entry-lift",1).setValue(getprop(lw~"effect-volumes/number-active-lift"));
+ ev.lift_r = cNode.getNode("thermal-lift").getValue();
+ ev.n_entry_lift = getprop(lw~"effect-volumes/number-active-lift");
setprop(lw~"effect-volumes/number-active-lift",getprop(lw~"effect-volumes/number-active-lift")+1);
thermal_lift_start(ev);
}
+else if (ev.lift_flag == 3)
+ {
+ ev.lift_r = cNode.getNode("thermal-lift").getValue();
+ ev.n_entry_lift = getprop(lw~"effect-volumes/number-active-lift");
+ setprop(lw~"effect-volumes/number-active-lift",getprop(lw~"effect-volumes/number-active-lift")+1);
+ wave_lift_start(ev);
+ }
}
@@ -668,12 +835,14 @@ var effect_volume_stop = func (ev) {
var cNode = props.globals.getNode(lw~"current");
-if (ev.getNode("effects/visibility-flag", 1).getValue()==1)
+if (ev.vis_flag == 1)
{
var n_active = getprop(lw~"effect-volumes/number-active-vis");
- var n_entry = ev.getNode("restore/number-entry-vis").getValue();
+
+ var n_entry = ev.n_entry_vis;
+
# if no other nodes affecting property are active, restore to outside
# else restore settings as they have been when entering the volume when the number
# of active volumes is the same as on entry (i.e. volumes are nested), otherwise
@@ -681,7 +850,8 @@ if (ev.getNode("effects/visibility-flag", 1).getValue()==1)
# be cancelled
if (n_active ==1){var vis = props.globals.getNode(lw~"interpolation/visibility-m").getValue();}
- else if ((n_active -1) == n_entry) {var vis = ev.getNode("restore/visibility-m").getValue();}
+ else if ((n_active -1) == n_entry) #{var vis = ev.getNode("restore/visibility-m").getValue();}
+ {var vis = ev.vis_r;}
else {var vis = cNode.getNode("visibility-m").getValue();}
cNode.getNode("visibility-m").setValue(vis);
compat_layer.setVisibility(vis);
@@ -689,142 +859,145 @@ if (ev.getNode("effects/visibility-flag", 1).getValue()==1)
# and subtract from the counter
setprop(lw~"effect-volumes/number-active-vis",getprop(lw~"effect-volumes/number-active-vis")-1);
}
-
-if (ev.getNode("effects/rain-flag", 1).getValue()==1)
+if (ev.rain_flag == 1)
{
var n_active = getprop(lw~"effect-volumes/number-active-rain");
- var n_entry = ev.getNode("restore/number-entry-rain").getValue();
+ var n_entry = ev.n_entry_rain;
+
if (n_active ==1){var rain = props.globals.getNode(lw~"interpolation/rain-norm").getValue();}
- else if ((n_active -1) == n_entry) {var rain = ev.getNode("restore/rain-norm").getValue();}
+ else if ((n_active -1) == n_entry)# {var rain = ev.getNode("restore/rain-norm").getValue();}
+ {var rain = ev.rain_r;}
else {var rain = cNode.getNode("rain-norm").getValue();}
cNode.getNode("rain-norm").setValue(rain);
compat_layer.setRain(rain);
setprop(lw~"effect-volumes/number-active-rain",getprop(lw~"effect-volumes/number-active-rain")-1);
}
-if (ev.getNode("effects/snow-flag", 1).getValue()==1)
+if (ev.snow_flag == 1)
{
var n_active = getprop(lw~"effect-volumes/number-active-snow");
- var n_entry = ev.getNode("restore/number-entry-snow").getValue();
+ var n_entry = ev.n_entry_snow;
+
if (n_active ==1){var snow = props.globals.getNode(lw~"interpolation/snow-norm").getValue();}
- else if ((n_active -1) == n_entry) {var snow = ev.getNode("restore/snow-norm").getValue();}
+ else if ((n_active -1) == n_entry)
+ {var snow = ev.snow_r;}
else {var snow = cNode.getNode("snow-norm").getValue();}
cNode.getNode("snow-norm").setValue(snow);
compat_layer.setSnow(snow);
setprop(lw~"effect-volumes/number-active-snow",getprop(lw~"effect-volumes/number-active-snow")-1);
}
-if (ev.getNode("effects/turbulence-flag", 1).getValue()==1)
+if (ev.turb_flag == 1)
{
var n_active = getprop(lw~"effect-volumes/number-active-turb");
- var n_entry = ev.getNode("restore/number-entry-turb").getValue();
+ var n_entry = ev.n_entry_turb;
if (n_active ==1){var turbulence = props.globals.getNode(lw~"interpolation/turbulence").getValue();}
- else if ((n_active -1) == n_entry) {var turbulence = ev.getNode("restore/turbulence").getValue();}
+ else if ((n_active -1) == n_entry)
+ {var turbulence = ev.turb_r;}
else {var turbulence = cNode.getNode("turbulence").getValue();}
cNode.getNode("turbulence").setValue(turbulence);
compat_layer.setTurbulence(turbulence);
setprop(lw~"effect-volumes/number-active-turb",getprop(lw~"effect-volumes/number-active-turb")-1);
}
-if (ev.getNode("effects/thermal-lift-flag", 1).getValue()==1)
+if (ev.sat_flag == 1)
+ {
+ var n_active = getprop(lw~"effect-volumes/number-active-sat");
+ var n_entry = ev.n_entry_sat;
+ if (n_active ==1){var saturation = 1.0;}
+ else if ((n_active -1) == n_entry)
+ {var saturation = ev.sat_r;}
+ else {var saturation = getprop("/rendering/scene/saturation");}
+ compat_layer.setLight(saturation);
+ setprop(lw~"effect-volumes/number-active-sat",getprop(lw~"effect-volumes/number-active-sat")-1);
+ }
+
+if (ev.lift_flag == 1)
{
var n_active = getprop(lw~"effect-volumes/number-active-lift");
- var n_entry = ev.getNode("restore/number-entry-lift").getValue();
+ var n_entry = ev.n_entry_lift;
if (n_active ==1){var lift = props.globals.getNode(lw~"interpolation/thermal-lift").getValue();}
- else if ((n_active -1) == n_entry) {var lift = ev.getNode("restore/thermal-lift").getValue();}
+ else if ((n_active -1) == n_entry)
+ {var lift = ev.lift_r;}
else {var lift = cNode.getNode("thermal-lift").getValue();}
cNode.getNode("thermal-lift").setValue(lift);
- # some cheat code
- # setLift(ev.getNode("position/latitude-deg").getValue(),ev.getNode("position/longitude-deg").getValue(),0);
-
+ compat_layer.setLift(lift);
setprop(lw~"effect-volumes/number-active-lift",getprop(lw~"effect-volumes/number-active-lift")-1);
}
-else if (ev.getNode("effects/thermal-lift-flag", 1).getValue()==2) # thermal by function
+else if (ev.lift_flag == 2)
{
thermal_lift_stop();
setprop(lw~"effect-volumes/number-active-lift",getprop(lw~"effect-volumes/number-active-lift")-1);
}
-
-}
-
-
-
-
-
-
-
-####################################
-# set thermal lift to given value
-####################################
-
-var setLift = func (lat, lon, flag) {
-
-# this is a cheat - if you have an AI thermal present, this sets its coordinates to the
-# current position
-
-if (flag==1)
- {
- setprop("ai/models/thermal/position/latitude-deg",lat);
- setprop("ai/models/thermal/position/longitude-deg",lon);
- }
-else
+else if (ev.lift_flag == 3)
{
- setprop("ai/models/thermal/position/latitude-deg",0.1);
- setprop("ai/models/thermal/position/longitude-deg",0.1);
-
+ wave_lift_stop();
+ setprop(lw~"effect-volumes/number-active-lift",getprop(lw~"effect-volumes/number-active-lift")-1);
}
-#setprop("environment/thermal-lift",L);
}
+
+
#########################################
# compute thermal lift in detailed model
#########################################
var ts_factor = func (t, alt, height) {
+var t1 = 0.1; # fractional time at which lift is fully developed
+var t2 = 0.9; # fractional time at which lift starts to decay
+var t3 = 1.0; # fractional time at which lift is gone
+
# no time dependence modelled yet
-return 1.0;
+# return 1.0;
-var t_a = t - (alt/height) * t1 -t1;
+
+var t_a = t - (alt/height) * t1 - t1;
if (t_a<0) {return 0.0;}
else if (t_a= t1) and (t < t2)) {return 1.0;}
-else if (t_a >= t2) {return 0.5 - 0.5 * math.cos((1.0-(t2-t_a)/(t3-t2))*math.pi);}
+else if (t_a < t2) {return 1.0;}
+else {return 0.5 - 0.5 * math.cos((1.0-(t2-t_a)/(t3-t2))*math.pi);}
}
var tl_factor = func (t, alt, height) {
+var t1 = 0.1; # fractional time at which lift is fully developed
+var t2 = 0.9; # fractional time at which lift starts to decay
+var t3 = 1.0; # fractional time at which lift is gone
+
# no time dependence modelled yet
-return 1.0;
+# return 1.0;
var t_a = t - (alt/height) * t1;
if (t_a<0) {return 0.0;}
else if (t_a= t1) and (t < t2)) {return 1.0;}
-else if (t_a >= t2) {return 0.5 - 0.5 * math.cos((1.0-(t2-t_a)/(t3-t2))*math.pi);}
+else if (t_a < t2) {return 1.0;}
+else {return 0.5 - 0.5 * math.cos((1.0-(t2-t_a)/(t3-t2))*math.pi);}
}
var calcLift_max = func (alt, max_lift, height) {
+alt_agl = getprop("/position/altitude-agl-ft");
+
# no lift below ground
-if (alt < 0.0) {return 0.0;}
+if (alt_agl < 0.0) {return 0.0;}
# lift ramps up to full within 200 m
-else if (alt < 200.0*m_to_ft)
- {return max_lift * 0.5 * (1.0 + math.cos((1.0-alt/(200.0*m_to_ft))*math.pi));}
+else if (alt_agl < 200.0*m_to_ft)
+ {return max_lift * 0.5 * (1.0 + math.cos((1.0-alt_agl/(200.0*m_to_ft))*math.pi));}
# constant max. lift in main body
-else if ((alt > 200.0*m_to_ft) and (alt < height))
+else if ((alt_agl > 200.0*m_to_ft) and (alt < height))
{return max_lift;}
# decreasing lift from cloudbase to 10% above base
else if ((alt > height ) and (alt < height*1.1))
- {return max_lift * 0.5 * (1.0 - math.cos((1.0-10.0*alt/height)*math.pi));}
+ {return max_lift * 0.5 * (1.0 - math.cos((1.0-10.0*(alt-height)/height)*math.pi));}
# no lift available above
else {return 0.0;}
@@ -865,7 +1038,33 @@ else
}
}
+#########################################
+# compute wave lift in detailed model
+#########################################
+var calcWaveLift = func (x,y, alt) {
+
+var lift = wave.max_lift * math.cos((y/wave.y) * 1.5 * math.pi);
+
+if (abs(x)/wave.x > 0.9)
+ {
+ lift = lift * (abs(x) - 0.9 * wave.x)/(0.1 * wave.x);
+ }
+
+
+
+lift = lift * 2.71828 * math.exp(-alt/wave.height) * alt/wave.height;
+
+var alt_agl = getprop("/position/altitude-agl-ft");
+
+if (alt_agl < 1000.0)
+ {
+ lift = lift * (alt_agl/1000.0) * (alt_agl/1000.0);
+ }
+
+return lift;
+}
+
###########################################################
# select a cloud model
@@ -939,6 +1138,40 @@ else if (type == "Congestus"){
else {path = "Models/Weather/congestus_sl5.xml";}
}
+ }
+else if (type == "Stratocumulus"){
+ if (subtype == "small") {
+ if (rn > 0.8) {path = "Models/Weather/stratocumulus_small1.xml";}
+ else if (rn > 0.6) {path = "Models/Weather/stratocumulus_small2.xml";}
+ else if (rn > 0.4) {path = "Models/Weather/stratocumulus_small3.xml";}
+ else if (rn > 0.2) {path = "Models/Weather/stratocumulus_small4.xml";}
+ else {path = "Models/Weather/stratocumulus_small5.xml";}
+ }
+ else if (subtype == "large") {
+ if (rn > 0.8) {path = "Models/Weather/stratocumulus_sl1.xml";}
+ else if (rn > 0.6) {path = "Models/Weather/stratocumulus_sl2.xml";}
+ else if (rn > 0.4) {path = "Models/Weather/stratocumulus_sl3.xml";}
+ else if (rn > 0.2) {path = "Models/Weather/stratocumulus_sl4.xml";}
+ else {path = "Models/Weather/stratocumulus_sl5.xml";}
+ }
+
+ }
+else if (type == "Cumulus (whisp)"){
+ if (subtype == "small") {
+ if (rn > 0.8) {path = "Models/Weather/cumulus_whisp1.xml";}
+ else if (rn > 0.6) {path = "Models/Weather/cumulus_whisp2.xml";}
+ else if (rn > 0.4) {path = "Models/Weather/cumulus_whisp3.xml";}
+ else if (rn > 0.2) {path = "Models/Weather/cumulus_whisp4.xml";}
+ else {path = "Models/Weather/cumulus_whisp5.xml";}
+ }
+ else if (subtype == "large") {
+ if (rn > 0.8) {path = "Models/Weather/cumulus_whisp1.xml";}
+ else if (rn > 0.6) {path = "Models/Weather/cumulus_whisp2.xml";}
+ else if (rn > 0.4) {path = "Models/Weather/cumulus_whisp3.xml";}
+ else if (rn > 0.2) {path = "Models/Weather/cumulus_whisp4.xml";}
+ else {path = "Models/Weather/cumulus_whisp5.xml";}
+ }
+
}
else if (type == "Cumulus bottom"){
if (subtype == "small") {
@@ -958,7 +1191,15 @@ else if (type == "Congestus bottom"){
}
}
-
+else if (type == "Stratocumulus bottom"){
+ if (subtype == "small") {
+ if (rn > 0.0) {path = "Models/Weather/stratocumulus_bottom1.xml";}
+ }
+ else if (subtype == "large") {
+ if (rn > 0.0) {path = "Models/Weather/stratocumulus_bottom1.xml";}
+ }
+
+ }
else if (type == "Cumulonimbus (cloudlet)"){
if (subtype == "small") {
if (rn > 0.8) {path = "Models/Weather/cumulonimbus_sl1.xml";}
@@ -1010,6 +1251,22 @@ else if (type == "Stratus (structured)"){
else {path = "Models/Weather/altocumulus_layer5.xml";}
}
}
+else if (type == "Altocumulus perlucidus"){
+ if (subtype == "small") {
+ if (rn > 0.8) {path = "Models/Weather/altocumulus_thinlayer6.xml";}
+ else if (rn > 0.6) {path = "Models/Weather/altocumulus_thinlayer7.xml";}
+ else if (rn > 0.4) {path = "Models/Weather/altocumulus_thinlayer8.xml";}
+ else if (rn > 0.2) {path = "Models/Weather/altocumulus_thinlayer9.xml";}
+ else {path = "Models/Weather/altocumulus_thinlayer10.xml";}
+ }
+ else if (subtype == "large") {
+ if (rn > 0.8) {path = "Models/Weather/altocumulus_thinlayer1.xml";}
+ else if (rn > 0.6) {path = "Models/Weather/altocumulus_thinlayer2.xml";}
+ else if (rn > 0.4) {path = "Models/Weather/altocumulus_thinlayer3.xml";}
+ else if (rn > 0.2) {path = "Models/Weather/altocumulus_thinlayer4.xml";}
+ else {path = "Models/Weather/altocumulus_thinlayer5.xml";}
+ }
+ }
else if ((type == "Cumulonimbus") or (type == "Cumulonimbus (rain)")) {
if (subtype == "small") {
if (rn > 0.5) {path = "Models/Weather/cumulonimbus_small1.xml";}
@@ -1162,26 +1419,26 @@ else if (type == "Fog (thick)") {
else {path = "Models/Weather/stratus_thick5.xml";}
}
}
-else if (type == "Test") {path="Models/Weather/test.xml";}
+else if (type == "Test") {path="Models/Weather/single_cloud.xml";}
else if (type == "Box_test") {
if (subtype == "standard") {
- if (rn > 0.8) {path = "Models/Weather/test1.xml";}
- else if (rn > 0.6) {path = "Models/Weather/test2.xml";}
- else if (rn > 0.4) {path = "Models/Weather/test3.xml";}
- else if (rn > 0.2) {path = "Models/Weather/test4.xml";}
- else {path = "Models/Weather/test5.xml";}
+ if (rn > 0.8) {path = "Models/Weather/cloudbox1.xml";}
+ else if (rn > 0.6) {path = "Models/Weather/cloudbox2.xml";}
+ else if (rn > 0.4) {path = "Models/Weather/cloudbox3.xml";}
+ else if (rn > 0.2) {path = "Models/Weather/cloudbox4.xml";}
+ else {path = "Models/Weather/cloudbox5.xml";}
}
else if (subtype == "core") {
- if (rn > 0.8) {path = "Models/Weather/test_core1.xml";}
- else if (rn > 0.6) {path = "Models/Weather/test_core2.xml";}
- else if (rn > 0.4) {path = "Models/Weather/test_core3.xml";}
- else if (rn > 0.2) {path = "Models/Weather/test_core4.xml";}
- else {path = "Models/Weather/test_core5.xml";}
+ if (rn > 0.8) {path = "Models/Weather/cloudbox_core1.xml";}
+ else if (rn > 0.6) {path = "Models/Weather/cloudbox_core2.xml";}
+ else if (rn > 0.4) {path = "Models/Weather/cloudbox_core3.xml";}
+ else if (rn > 0.2) {path = "Models/Weather/cloudbox_core4.xml";}
+ else {path = "Models/Weather/cloudbox_core5.xml";}
}
else if (subtype == "bottom") {
- if (rn > 0.66) {path = "Models/Weather/test_bottom1.xml";}
- else if (rn > 0.33) {path = "Models/Weather/test_bottom2.xml";}
- else if (rn > 0.0) {path = "Models/Weather/test_bottom3.xml";}
+ if (rn > 0.66) {path = "Models/Weather/cloudbox_bottom1.xml";}
+ else if (rn > 0.33) {path = "Models/Weather/cloudbox_bottom2.xml";}
+ else if (rn > 0.0) {path = "Models/Weather/cloudbox_bottom3.xml";}
}
}
@@ -1207,6 +1464,15 @@ append(clouds_lon,long);
append(clouds_alt,alt);
append(clouds_orientation,heading);
+# globals (needed for Cumulus clouds) should be set if needed by the main cloud generating call
+
+if (dynamics_flag ==1)
+ {
+ append(clouds_mean_alt, cloud_mean_altitude);
+ append(clouds_flt, cloud_fractional_lifetime);
+ append(clouds_evolution_timestamp,cloud_evolution_timestamp);
+ }
+
}
###########################################################
# clear all clouds and effects
@@ -1230,36 +1496,32 @@ foreach (var m; modelNode)
}
}
-cloudNode.getNode("cloud-number",1).setValue(0);
+
# clear effect volumes
-props.globals.getNode("local-weather/effect-volumes", 1).removeChildren("effect-volume");
+#props.globals.getNode("local-weather/effect-volumes", 1).removeChildren("effect-volume");
-# clear weather stations
-props.globals.getNode("local-weather/interpolation", 1).removeChildren("station");
-
-# clear winds
-
-props.globals.getNode("local-weather/interpolation", 1).removeChildren("wind");
-setprop(lwi~"ipoint-number",0);
# reset pressure continuity
weather_tiles.last_pressure = 0.0;
-# stop all loops make sure thermal generation is off
+# stop all loops
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~"wave-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);
+setprop(lw~"convective-loop-flag",0);
+
+weather_dynamics.convective_loop_kill_flag = 1; # long-running loop needs a different scheme to end
# also remove rain and snow effects
@@ -1281,31 +1543,40 @@ settimer ( func { setsize(weather_dynamics.cloudQuadtrees,0);},0.1); # to avoid
setsize(effectVolumeArray,0);
n_effectVolumeArray = 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);
+ setsize(alt_20_array,0);
+ setsize(alt_50_array,0);
+ setsize(weather_dynamics.tile_convective_altitude,0);
+ setsize(weather_dynamics.tile_convective_strength,0);
+ setsize(weatherStationArray,0);
setprop(lw~"clouds/buffer-count",0);
setprop(lw~"clouds/cloud-scenery-count",0);
+ weather_tile_management.n_cloudSceneryArray = 0;
+ props.globals.getNode("local-weather/interpolation", 1).removeChildren("wind");
+ setprop(lwi~"ipoint-number",0);
},1.1);
+setprop(lw~"tmp/presampling-status", "idle");
+
}
+
###########################################################
# detailed Cumulus clouds created from multiple cloudlets
###########################################################
var create_detailed_cumulus_cloud = func (lat, lon, alt, size) {
-#print(size);
var edge_bias = convective_texture_mix;
-#print("edge_bias: ",edge_bias);
-
var size_bias = 0.0;
if (size > 2.0)
@@ -1343,7 +1614,7 @@ else if (size>0.8)
var y = 200.0;
var edge = 0.3;
}
-else
+else if (size>0.4)
{
var type = "Cumulus (cloudlet)";
var btype = "Cumulus bottom";
@@ -1353,6 +1624,16 @@ else
var y = 200.0;
var edge = 1.0;
}
+else
+ {
+ var type = "Cumulus (whisp)";
+ var btype = "Cumulus bottom";
+ var height = 100;
+ var n = 1;
+ var x = 100.0;
+ var y = 100.0;
+ var edge = 1.0;
+ }
var alpha = rand() * 180.0;
@@ -1390,16 +1671,18 @@ create_streak("Cumulonimbus",lat,lon, alt+ 0.5* height, height,8,0.0,0.0,1600.0,
var create_cumosys = func (blat, blon, balt, nc, size) {
# realistic Cumulus has somewhat larger models, so compensate to get the same coverage
-if (getprop(lw~"config/detailed-clouds-flag") == 1)
+if (detailed_clouds_flag == 1)
{nc = int(0.7 * nc);}
-if (getprop(lw~"tmp/thread-flag") == 1)
+if (thread_flag == 1)
{setprop(lw~"tmp/convective-status", "computing");
cumulus_loop(blat, blon, balt, nc, size);}
else
{create_cumulus(blat, blon, balt, nc, size);
- print("Convective system done!");}
+ if (debug_output_flag == 1)
+ {print("Convective system done!");}
+ }
}
@@ -1410,7 +1693,8 @@ var n = 25;
if (nc < 0)
{
- print("Convective system done!");
+ if (debug_output_flag == 1)
+ {print("Convective system done!");}
setprop(lw~"tmp/convective-status", "idle");
assemble_effect_array();
return;
@@ -1436,7 +1720,7 @@ var p = 0.0;
var rn = 0.0;
var place_lift_flag = 0;
var strength = 0.0;
-var detail_flag = getprop(lw~"config/detailed-clouds-flag");
+var detail_flag = detailed_clouds_flag;
var alpha = getprop(lw~"tmp/tile-orientation-deg") * math.pi/180.0; # the tile orientation
@@ -1459,7 +1743,6 @@ var t_factor1 = 0.5 * (1.0-math.cos((t * sec_to_rad)));
# daily variation in strength of thermals, peaks around 15:30
var t_factor2 = 0.5 * (1.0-math.cos((t * sec_to_rad)-0.9));
-#print("t-factor1 is now: ",t_factor1, " ",t_factor2);
# number of possible thermals equals overall strength times daily variation times geographic variation
# this is a proxy for solar thermal energy
@@ -1492,6 +1775,7 @@ while (i < nc) {
if (contains(landcover_map,landcover)) {p = p + landcover_map[landcover];}
else {print(p, " ", info[1].names[0]);}
}}
+ else {continue;}
# then decide if the thermal energy at the spot generates an updraft and a cloud
@@ -1508,16 +1792,19 @@ while (i < nc) {
# check if we have a terrain elevation analysis available and can use a
# detailed placement altitude correction
- if (getprop(lw~"tmp/presampling-flag") == 1)
+ if (presampling_flag == 1)
{
- var place_alt = get_convective_altitude(balt, elevation);
+ var place_alt = get_convective_altitude(balt, elevation, getprop(lw~"tiles/tile-counter"));
}
else {var place_alt = balt;}
+
+ cloud_mean_altitude = place_alt;
+ cloud_fractional_lifetime = rand();
+ cloud_evolution_timestamp = weather_dynamics.time_lw;
-
- if (getprop(lw~"tmp/generate-thermal-lift-flag") != 3) # no clouds if we produce blue thermals
+ if (generate_thermal_lift_flag != 3) # no clouds if we produce blue thermals
{
- if (getprop(lw~"tmp/thread-flag") == 1)
+ if (thread_flag == 1)
{
if (detail_flag == 0){create_cloud_vec(path,lat,lon, place_alt, 0.0);}
else {create_detailed_cumulus_cloud(lat, lon, place_alt, strength);}
@@ -1530,7 +1817,7 @@ while (i < nc) {
}
# now see if we need to create a thermal - first check the flag
- if (getprop(lw~"tmp/generate-thermal-lift-flag") == 1) # thermal by constant
+ if (generate_thermal_lift_flag == 1) # thermal by constant
{
# now check if convection is strong
if (place_lift_flag == 1)
@@ -1538,21 +1825,18 @@ while (i < nc) {
var lift = 3.0 + 10.0 * (strength -1.0);
var radius = 500 + 500 * rand();
#print("Lift: ", lift * ft_to_m - 1.0);
- create_effect_volume(1, lat, lon, radius, radius, 0.0, 0.0, place_alt+500.0, -1, -1, -1, -1, lift, 1);
+ create_effect_volume(1, lat, lon, radius, radius, 0.0, 0.0, place_alt+500.0, -1, -1, -1, -1, lift, 1,-1);
} # end if place_lift_flag
} # end if generate-thermal-lift-flag
- else if ((getprop(lw~"tmp/generate-thermal-lift-flag") == 2) or (getprop(lw~"tmp/generate-thermal-lift-flag") == 3)) # thermal by function
+ else if ((generate_thermal_lift_flag == 2) or (generate_thermal_lift_flag == 3)) # thermal by function
{
if (place_lift_flag == 1)
{
- #var lift = 3.0 + 20.0 * p * rand();
- #var radius = 500 + 500 * rand();
var lift = (3.0 + 10.0 * (strength -1.0))/thermal_conditions;
var radius = (500 + 500 * rand())*thermal_conditions;
- #print("Lift: ", lift * ft_to_m - 1.0, " strength: ",strength);
- create_effect_volume(1, lat, lon, 1.1*radius, 1.1*radius, 0.0, 0.0, place_alt+500.0, -1, -1, -1, lift*0.02, lift, -2);
+ create_effect_volume(1, lat, lon, 1.1*radius, 1.1*radius, 0.0, 0.0, place_alt*1.15, -1, -1, -1, lift*0.04, lift, -2,-1);
} # end if place_lift_flag
} # end if generate-thermal-lift-flag
@@ -1564,6 +1848,165 @@ while (i < nc) {
}
+
+
+
+
+#################################################################
+# respawn convective clouds to compensate for decay
+# the difference being that new clouds get zero fractional
+# lifetime and are placed based on terrain with a different weight
+##################################################################
+
+var recreate_cumulus = func (blat, blon, balt, alpha, nc, size, tile_index) {
+
+var path = "Models/Weather/blank.ac";
+var i = 0;
+var p = 0.0;
+var rn = 0.0;
+var place_lift_flag = 0;
+var strength = 0.0;
+var detail_flag = detailed_clouds_flag;
+
+alpha = alpha * math.pi/180.0; # the tile orientation
+
+var sec_to_rad = 2.0 * math.pi/86400; # conversion factor for sinusoidal dependence on daytime
+
+# current aircraft position
+
+var alat = getprop("position/latitude-deg");
+var alon = getprop("position/longitude-deg");
+
+# get the local time of the day in seconds
+
+var t = getprop("sim/time/utc/day-seconds");
+t = t + getprop("sim/time/local-offset");
+
+
+# and make a simple sinusoidal model of thermal strength
+
+# daily variation in number of thermals, peaks at noon
+var t_factor1 = 0.5 * (1.0-math.cos((t * sec_to_rad)));
+
+# daily variation in strength of thermals, peaks around 15:30
+var t_factor2 = 0.5 * (1.0-math.cos((t * sec_to_rad)-0.9));
+
+
+# number of possible thermals equals overall strength times daily variation times geographic variation
+# this is a proxy for solar thermal energy
+
+nc = t_factor1 * nc * math.cos(blat/180.0*math.pi);
+
+var thermal_conditions = getprop(lw~"config/thermal-properties");
+
+
+while (i < nc) {
+
+ p = 0.0;
+ place_lift_flag = 0;
+ strength = 0.0;
+
+ # pick a trial position inside the tile and rotate by tile orientation angle
+ var x = (2.0 * rand() - 1.0) * size;
+ var y = (2.0 * rand() - 1.0) * size;
+
+ var lat = blat + (y * math.cos(alpha) - x * math.sin(alpha)) * m_to_lat;
+ var lon = blon + (x * math.cos(alpha) + y * math.sin(alpha)) * m_to_lon;
+
+ # check if the cloud would be spawned in visual range, if not don't bother
+ var d_sq = calc_d_sq(alat, alon, lat, lon);
+
+ if (math.sqrt(d_sq) > weather_tile_management.cloud_view_distance)
+ {i = i+1; continue;}
+
+ # now check ground cover type on chosen spot
+ var info = geodinfo(lat, lon);
+
+ if (info != nil) {
+ var elevation = info[0] * m_to_ft;
+ if (info[1] != nil){
+ var landcover = info[1].names[0];
+ if (contains(landcover_map,landcover)) {p = p + landcover_map[landcover];}
+ else {print(p, " ", info[1].names[0]);}
+ }}
+ else {continue;}
+
+ # check if to place a cloud with weight sqrt(p), the lifetime gets another sqrt(p) factor
+
+ if (rand() > math.sqrt(p))
+ {i=i+1; continue;}
+
+
+ # then calculate the strength of the updraft
+
+ strength = (1.5 * rand() + (2.0 * p)) * t_factor2; # the strength of thermal activity at the spot
+ if (strength > 1.0)
+ {
+ path = select_cloud_model("Cumulus","large"); place_lift_flag = 1;
+ }
+ else {path = select_cloud_model("Cumulus","small");}
+
+ if (presampling_flag == 1)
+ {
+ var place_alt = get_convective_altitude(balt, elevation, tile_index);
+ }
+ else {var place_alt = balt;}
+
+ cloud_mean_altitude = place_alt;
+ cloud_fractional_lifetime = 0.0;
+ cloud_evolution_timestamp = weather_dynamics.time_lw;
+
+ compat_layer.cloud_mean_altitude = place_alt;
+ compat_layer.cloud_flt = cloud_fractional_lifetime;
+ compat_layer.cloud_evolution_timestamp = cloud_evolution_timestamp;
+
+ if (generate_thermal_lift_flag != 3) # no clouds if we produce blue thermals
+ {
+ if (thread_flag == 1)
+ {
+ thread_flag = 0; # create clouds immediately
+ if (detail_flag == 0){compat_layer.create_cloud(path,lat,lon, place_alt, 0.0);}
+ else {create_detailed_cumulus_cloud(lat, lon, place_alt, strength);}
+ thread_flag = 1; # and restore threading
+ }
+ else
+ {
+ if (detail_flag == 0){compat_layer.create_cloud(path, lat, lon, place_alt, 0.0);}
+ else {create_detailed_cumulus_cloud(lat, lon, place_alt, strength);}
+ }
+ }
+
+ if (generate_thermal_lift_flag == 1) # thermal by constant
+ {
+ if (place_lift_flag == 1)
+ {
+ var lift = 3.0 + 10.0 * (strength -1.0);
+ var radius = 500 + 500 * rand();
+ create_effect_volume(1, lat, lon, radius, radius, 0.0, 0.0, place_alt+500.0, -1, -1, -1, -1, lift, 1,-1);
+ } # end if place_lift_flag
+ } # end if generate-thermal-lift-flag
+ else if ((generate_thermal_lift_flag == 2) or (generate_thermal_lift_flag == 3)) # thermal by function
+ {
+ if (place_lift_flag == 1)
+ {
+ var lift = (3.0 + 10.0 * (strength -1.0))/thermal_conditions;
+ var radius = (500 + 500 * rand())*thermal_conditions;
+
+ create_effect_volume(1, lat, lon, 1.1*radius, 1.1*radius, 0.0, 0.0, place_alt*1.15, -1, -1, -1, lift*0.04, lift, -2,-1);
+ } # end if place_lift_flag
+
+ } # end if generate-thermal-lift-flag
+
+
+ i = i + 1;
+ } # end while
+
+}
+
+
+
+
+
###########################################################
# place a Cumulus layer with excluded regions
# to avoid placing cumulus underneath a thunderstorm
@@ -1576,7 +2019,7 @@ var strength = 0;
var flag = 1;
var phi = alpha * math.pi/180.0;
-var detail_flag = getprop(lw~"config/detailed-clouds-flag");
+var detail_flag = detailed_clouds_flag;
if (detail_flag == 1) {var i_max = int(0.25*n);} else {var i_max = int(1.0*n);}
@@ -1604,7 +2047,7 @@ for (var i =0; i< i_max; i=i+1)
if (strength > 1.0) {var path = select_cloud_model("Cumulus","large"); }
else {var path = select_cloud_model("Cumulus","small");}
- if (getprop(lw~"tmp/thread-flag") == 1)
+ if (thread_flag == 1)
{
if (detail_flag == 0){create_cloud_vec(path,lat,lon, balt, 0.0);}
else {create_detailed_cumulus_cloud(lat, lon, balt, strength);}
@@ -1634,7 +2077,6 @@ var p = 0.0;
var rn = 0.0;
var nsample = 10;
var counter = 0;
-var elevation = 0.0;
var dir = (winddir + 180.0) * math.pi/180.0;
var step = dist/nsample;
@@ -1644,7 +2086,6 @@ while (i < nc) {
counter = counter + 1;
p = 0.0;
- elevation=0.0;
var x = (2.0 * rand() - 1.0) * size;
var y = (2.0 * rand() - 1.0) * size;
@@ -1652,12 +2093,11 @@ while (i < nc) {
var lat = blat + y * m_to_lat;
var lon = blon + x * m_to_lon;
- var info = geodinfo(lat, lon);
- if (info != nil) {elevation = info[0] * m_to_ft;}
+ var elevation = compat_layer.get_elevation(lat, lon);
+ #print("elevation: ", elevation, "balt: ", balt);
-
- if ((elevation < balt) and (elevation != 0.0))
+ if ((elevation < balt) and (elevation != -1.0))
{
for (var j = 0; j balt)
+
+ #print("x: ", x, "y: ", y);
+
+ var elevation1 = compat_layer.get_elevation(tlat,tlon);
+ #print("elevation1: ", elevation1, "balt: ", balt);
+
+ if (elevation1 > balt)
{
p = 1.0 - j * (1.0/nsample);
+ #p = 1.0;
break;
}
@@ -1680,14 +2123,13 @@ while (i < nc) {
}
if (counter > 500) {print("Cannot place clouds - exiting..."); i = nc;}
if (rand() < p)
- {
- path = select_cloud_model("Altocumulus","large");
- #print("Cloud ",i, " after ",counter, " tries");
+ {
+ path = select_cloud_model("Stratus (structured)","large");
compat_layer.create_cloud(path, lat, lon, balt, 0.0);
- counter = 0;
- i = i+1;
- }
-
+ counter = 0;
+ i = i+1;
+ }
+
} # end while
}
@@ -1742,7 +2184,7 @@ for (var i=0; i 0.05) # we have below 5 fps
if (nc <= 0) # we're done and may analyze the result
{
terrain_presampling_analysis();
- print("Presampling done!");
+ if (debug_output_flag == 1)
+ {print("Presampling done!");}
setprop(lw~"tmp/presampling-status", "finished");
return;
}
@@ -2092,29 +2532,13 @@ for (var i=0; i 1.0) {shift_strength = 1.0;} # no enhancement for very low layers
-if (shift_strength < 0.0) {shift_strength = 0.0;} # this shouldn't happen, but just in case...
+if (shift_strength < 0.0) {shift_strength = 1.0;} # this shouldn't happen, but just in case...
+
+if (alt_diff > alt_variation) {alt_diff = alt_variation;} # maximal shift is given by alt_variation
return balt + shift_strength * alt_diff * fraction;
@@ -2309,84 +2766,57 @@ if (convective_texture_mix > 0.2) {convective_texture_mix = 0.2;}
# create an effect volume
###########################################################
-var create_effect_volume = func (geometry, lat, lon, r1, r2, phi, alt_low, alt_high, vis, rain, snow, turb, lift, lift_flag) {
-
-var flag = 0;
-
-var index = getprop(lw~"effect-volumes/effect-placement-index");
-
-var n = props.globals.getNode("local-weather/effect-volumes", 1);
- for (var i = index; 1; i += 1)
- if (n.getChild("effect-volume", i, 0) == nil)
- break;
-
- setprop(lw~"effect-volumes/effect-placement-index",i);
+var create_effect_volume = func (geometry, lat, lon, r1, r2, phi, alt_low, alt_high, vis, rain, snow, turb, lift, lift_flag, sat) {
-ev = n.getChild("effect-volume", i, 1);
+var ev = effectVolume.new (geometry, lat, lon, r1, r2, phi, alt_low, alt_high, vis, rain, snow, turb, lift, lift_flag, sat);
+ev.index = getprop(lw~"tiles/tile-counter");
+ev.active_flag = 0;
-ev.getNode("geometry", 1).setValue(geometry);
-ev.getNode("active-flag", 1).setValue(0);
-ev.getNode("position/latitude-deg", 1).setValue(lat);
-ev.getNode("position/longitude-deg", 1).setValue(lon);
-ev.getNode("position/min-altitude-ft", 1).setValue(alt_low);
-ev.getNode("position/max-altitude-ft", 1).setValue(alt_high);
-ev.getNode("volume/size-x", 1).setValue(r1);
-ev.getNode("volume/size-y", 1).setValue(r2);
-ev.getNode("volume/orientation-deg", 1).setValue(phi);
-ev.getNode("tile-index",1).setValue(getprop(lw~"tiles/tile-counter"));
-var flag = 1;
-if (vis < 0.0) {flag = 0;}
-ev.getNode("effects/visibility-flag", 1).setValue(flag);
-ev.getNode("effects/visibility-m", 1).setValue(vis);
+if (vis < 0.0) {ev.vis_flag = 0;} else {ev.vis_flag = 1;}
+if (rain < 0.0) {ev.rain_flag = 0;} else {ev.rain_flag = 1;}
+if (snow < 0.0) {ev.snow_flag = 0;} else {ev.snow_flag = 1;}
+if (turb < 0.0) {ev.turb_flag = 0;} else {ev.turb_flag = 1;}
+if (lift_flag == 0.0) {ev.lift_flag = 0;} else {ev.lift_flag = 1;}
+if (sat < 0.0) {ev.sat_flag = 0;} else {ev.sat_flag = 1;}
+if (sat > 1.0) {sat = 1.0;}
-flag = 1;
-if (rain < 0.0) {flag = 0;}
-ev.getNode("effects/rain-flag", 1).setValue(flag);
-ev.getNode("effects/rain-norm", 1).setValue(rain);
-
-flag = 1;
-if (snow < 0.0) {flag = 0;}
-ev.getNode("effects/snow-flag", 1).setValue(flag);
-ev.getNode("effects/snow-norm", 1).setValue(snow);
-
-flag = 1;
-if (snow < 0.0) {flag = 0;}
-ev.getNode("effects/snow-flag", 1).setValue(flag);
-ev.getNode("effects/snow-norm", 1).setValue(snow);
-
-flag = 1;
-if (turb < 0.0) {flag = 0;}
-ev.getNode("effects/turbulence-flag", 1).setValue(flag);
-ev.getNode("effects/turbulence", 1).setValue(turb);
-
-flag = 1;
-if (lift_flag == 0) {flag = 0;}
-ev.getNode("effects/thermal-lift-flag", 1).setValue(flag);
-ev.getNode("effects/thermal-lift", 1).setValue(lift);
-
-flag = 1;
if (lift_flag == -2) # we create a thermal by function
{
- ev.getNode("effects/thermal-lift-flag", 1).setValue(2);
- ev.getNode("effects/radius",1 ).setValue(0.8*r1);
- ev.getNode("effects/height",1).setValue(alt_high);
- ev.getNode("effects/cn",1).setValue(0.8);
- ev.getNode("effects/sh",1).setValue(0.8);
- ev.getNode("effects/max_lift",1).setValue(lift);
- ev.getNode("effects/f_lift_radius",1).setValue(0.8);
+ ev.lift_flag = 2;
+ ev.radius = 0.8 * r1;
+ ev.height = alt_high * 0.87;
+ ev.cn = 0.7 + rand() * 0.2;
+ ev.sh = 0.7 + rand() * 0.2;
+ ev.max_lift = lift;
+ ev.f_lift_radius = 0.7 + rand() * 0.2;
+ if (dynamics_flag == 1) # globals set by the convective system
+ {
+ ev.flt = cloud_fractional_lifetime;
+ ev.evolution_timestamp = cloud_evolution_timestamp;
+ }
+ }
+
+if (lift_flag == -3) # we create a wave lift
+ {
+ ev.lift_flag = 3;
+ ev.height = 10000.0; # scale height in ft
+ ev.max_lift = lift;
+ ev.index = 0; # static objects are assigned tile id zero
}
# set a timestamp if needed
-if (getprop(lw~"config/dynamics-flag") == 1)
+if (dynamics_flag == 1)
{
- ev.getNode("timestamp-sec",1).setValue(weather_dynamics.time_lw);
+ ev.timestamp = weather_dynamics.time_lw;
}
# and add to the counter
setprop(lw~"effect-volumes/number",getprop(lw~"effect-volumes/number")+1);
+
+append(effectVolumeArray,ev);
}
@@ -2399,27 +2829,17 @@ setprop(lw~"effect-volumes/number",getprop(lw~"effect-volumes/number")+1);
var set_weather_station = func (lat, lon, vis, T, D, p) {
-var n = props.globals.getNode(lwi, 1);
- for (var i = 0; 1; i += 1)
- if (n.getChild("station", i, 0) == nil)
- break;
-
-s = n.getChild("station", i, 1);
-
-s.getNode("latitude-deg",1).setValue(lat);
-s.getNode("longitude-deg",1).setValue(lon);
-s.getNode("visibility-m",1).setValue(vis);
-s.getNode("temperature-degc",1).setValue(T);
-s.getNode("dewpoint-degc",1).setValue(D);
-s.getNode("pressure-sea-level-inhg",1).setValue(p);
-s.getNode("tile-index",1).setValue(getprop(lw~"tiles/tile-counter"));
+var s = weatherStation.new (lat, lon, vis, T, D, p);
+s.index = getprop(lw~"tiles/tile-counter");
+s.weight = 0.1;
# set a timestamp if needed
-if (getprop(lw~"config/dynamics-flag") == 1)
+if (dynamics_flag == 1)
{
- s.getNode("timestamp-sec",1).setValue(weather_dynamics.time_lw);
+ s.timestamp = weather_dynamics.time_lw;
}
+append(weatherStationArray,s);
}
@@ -2477,6 +2897,29 @@ var showDialog = func (name) {
fgcommand("dialog-show", props.Node.new({"dialog-name":name}));
+}
+
+
+###########################################################
+# helper to transfer configuration flags in menu to Nasal
+###########################################################
+
+var readFlags = func {
+
+# thermal lift must be 1 for constant thermals (obsolete), 2 for thermals by model (menu default)
+# and 3 for blue thermals (set internally inside the tile only)
+
+if (getprop(lw~"config/generate-thermal-lift-flag") ==1) {generate_thermal_lift_flag = 2;}
+ else {generate_thermal_lift_flag = 0};
+
+thread_flag = getprop(lw~"config/thread-flag");
+dynamics_flag = getprop(lw~"config/dynamics-flag");
+presampling_flag = getprop(lw~"tmp/presampling-flag");
+detailed_clouds_flag = getprop(lw~"config/detailed-clouds-flag");
+dynamical_convection_flag = getprop(lw~"config/dynamical-convection-flag");
+debug_output_flag = getprop(lw~"config/debug-output-flag");
+
+
}
###########################################################
@@ -2485,8 +2928,9 @@ fgcommand("dialog-show", props.Node.new({"dialog-name":name}));
var streak_wrapper = func {
-setprop(lw~"tmp/thread-flag", 0);
-setprop(lw~"config/dynamics-flag",0);
+thread_flag = 0;
+dynamics_flag = 0;
+presampling_flag = 0;
var array = [];
append(weather_tile_management.modelArrays,array);
@@ -2514,8 +2958,10 @@ create_streak(type,lat,lon,alt,rnd_alt,nx,xoffset,xedge,rnd_pos_x,ny,yoffset,yed
var convection_wrapper = func {
-setprop(lw~"tmp/thread-flag", 0);
-setprop(lw~"config/dynamics-flag",0);
+thread_flag = 0;
+dynamics_flag = 0;
+presampling_flag = 0;
+
var array = [];
append(weather_tile_management.modelArrays,array);
@@ -2534,8 +2980,11 @@ create_cumosys(lat,lon,alt,n, size*1000.0);
var barrier_wrapper = func {
-setprop(lw~"tmp/thread-flag", 0);
-setprop(lw~"config/dynamics-flag",0);
+
+thread_flag = 0;
+dynamics_flag = 0;
+presampling_flag = 0;
+
var array = [];
append(weather_tile_management.modelArrays,array);
@@ -2555,7 +3004,11 @@ create_rise_clouds(lat, lon, alt, n, size, dir, dist);
var single_cloud_wrapper = func {
-setprop(lw~"config/dynamics-flag",0);
+thread_flag = 0;
+dynamics_flag = 0;
+presampling_flag = 0;
+
+
var array = [];
append(weather_tile_management.modelArrays,array);
@@ -2576,8 +3029,10 @@ compat_layer.create_cloud(path, lat, lon, alt, heading);
var layer_wrapper = func {
-setprop(lw~"config/dynamics-flag",0);
-setprop(lw~"tmp/thread-flag", 0);
+thread_flag = 0;
+dynamics_flag = 0;
+presampling_flag = 0;
+
var array = [];
append(weather_tile_management.modelArrays,array);
@@ -2602,8 +3057,10 @@ create_layer(type, lat, lon, alt, thick, rx, ry, phi, density, edge, rain_flag,
var box_wrapper = func {
-setprop(lw~"tmp/thread-flag", 0);
-setprop(lw~"config/dynamics-flag",0);
+thread_flag = 0;
+dynamics_flag = 0;
+presampling_flag = 0;
+
setprop(lw~"tiles/tile-counter",getprop(lw~"tiles/tile-counter")+1);
@@ -2679,6 +3136,7 @@ if (wind_model_flag == 5)
var set_tile = func {
+
var type = getprop("/local-weather/tmp/tile-type");
# set tile center coordinates to current position
@@ -2690,9 +3148,39 @@ setprop(lw~"tiles/tmp/latitude-deg",lat);
setprop(lw~"tiles/tmp/longitude-deg",lon);
setprop(lw~"tiles/tmp/dir-index",4);
+readFlags();
+
+# check consistency of flags
+
+if (dynamical_convection_flag == 1)
+ {
+ if (dynamics_flag == 0)
+ {
+ print("Dynamical convection needs weather dynamics to run! Aborting...");
+ setprop("/sim/messages/pilot", "Local weather: dynamical convection needs weather dynamics to run! Aborting...");
+ return;
+ }
+ if (presampling_flag == 0)
+ {
+ print("Dynamical convection needs terrain presampling to run! Aborting...");
+ setprop("/sim/messages/pilot", "Local weather: dynamical convection needs terrain presampling to run! Aborting...");
+ return;
+ }
+ }
+
+
+# if we can do so, we switch global weather off at this point
+
+if (compat_layer.features.can_disable_environment ==1)
+ {
+ props.globals.getNode("/environment/config/enabled").setBoolValue(0);
+ }
+
+
+
# now see if we need to presample the terrain
-if ((getprop(lw~"tmp/presampling-flag") == 1) and (getprop(lw~"tmp/presampling-status") == "idle"))
+if ((presampling_flag == 1) and (getprop(lw~"tmp/presampling-status") == "idle"))
{
terrain_presampling_start(lat, lon, 1000, 40000, getprop(lw~"tmp/tile-orientation-deg"));
return;
@@ -2759,7 +3247,7 @@ setprop(lw~"tiles/tile-counter",getprop(lw~"tiles/tile-counter")+1);
# see if we need to generate a quadtree structure for clouds
-if (getprop(lw~"config/dynamics-flag") ==1)
+if (dynamics_flag ==1)
{
var quadtree = [];
weather_dynamics.generate_quadtree_structure(0, quadtree);
@@ -2825,6 +3313,10 @@ else
{print("Tile not implemented.");setprop(lw~"tiles/tile-counter",getprop(lw~"tiles/tile-counter")-1);return();}
+# mark tile as active
+
+append(weather_tile_management.active_tile_list,1);
+
# start tile management loop if needed
if (getprop(lw~"tmp/tile-management") != "single tile") {
@@ -2848,7 +3340,7 @@ if (getprop(lw~"effect-loop-flag") == 0)
# start weather dynamics loops if needed
-if (getprop(lw~"config/dynamics-flag") ==1)
+if (dynamics_flag ==1)
{
if (getprop(lw~"timing-loop-flag") == 0)
{setprop(lw~"timing-loop-flag",1); weather_dynamics.timing_loop();}
@@ -2857,11 +3349,18 @@ if (getprop(lw~"config/dynamics-flag") ==1)
{
setprop(lw~"dynamics-loop-flag",1);
weather_dynamics.quadtree_loop();
- weather_dynamics.weather_dynamics_loop(0);
+ weather_dynamics.weather_dynamics_loop(0,0);
+ }
+ if ((getprop(lw~"convective-loop-flag") == 0) and (getprop(lw~"config/dynamical-convection-flag") ==1))
+ {
+ setprop(lw~"convective-loop-flag",1);
+ weather_dynamics.convective_loop();
}
-
}
+
+
+
# and start the buffer loop and housekeeping loop if needed
if (getprop(lw~"config/buffer-flag") ==1)
@@ -2873,7 +3372,7 @@ if (getprop(lw~"config/buffer-flag") ==1)
}
}
-#weather_tile_management.watchdog_loop();
+# weather_tile_management.watchdog_loop();
}
@@ -2969,67 +3468,186 @@ var test = func {
var lat = getprop("position/latitude-deg");
var lon = getprop("position/longitude-deg");
+var pos = geo.aircraft_position();
+
+props.globals.getNode("/environment/terrain/area/enabled",1).setBoolValue(1);
+
+setprop("/environment/terrain/area/input/analyse-every",200);
+setprop("/environment/terrain/area/input/elevation-histogram-count",20);
+setprop("/environment/terrain/area/input/elevation-histogram-max-ft",10000);
+setprop("/environment/terrain/area/input/elevation-histogram-step-ft",500);
+setprop("/environment/terrain/area/input/heading-deg",0.0);
+setprop("/environment/terrain/area/input/speed-kt",-.0);
+setprop("/environment/terrain/area/input/latitude-deg",lat);
+setprop("/environment/terrain/area/input/longitude-deg",lon);
+setprop("/environment/terrain/area/input/max-samples",1000);
+setprop("/environment/terrain/area/input/max-samples-per-frame",20);
+setprop("/environment/terrain/area/input/orientation-deg",0);
+setprop("/environment/terrain/area/input/radius-m",40000);
+
+props.globals.getNode("/environment/terrain/area/input/use-aircraft-position",1).setBoolValue(0);
-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;
-#weather_dynamics.tan_vangle = 0.3;
-
-#weather_dynamics.plane_x = 0.0;
-#weather_dynamics.plane_y = 0.0;
-
-
-
-#for (var i=0; i<16; i=i+1)
-# {
-# var pix = [];
-# for (var j=0; j<16; j=j+1)
-# {
-# var x = -18750.0 + j * 2500.0;
-# var y = 18750.0 - i * 2500.0;
-# append(pix,weather_dynamics.check_visibility(x,y,2500.0));
-# }
-# print(pix[0],pix[1],pix[2],pix[3],pix[4],pix[5],pix[6],pix[7],pix[8],pix[9],pix[10],pix[11],pix[12],pix[13],pix[14],pix[15]);
-# }
-
-#print(weather_dynamics.check_visibility(0,0,0,8000.0,10000));
-#print(weather_dynamics.check_visibility(0,0,0,15000.0,2500));
-#print(weather_dynamics.check_visibility(0,0,0,-15000.0,2500));
-#print(weather_dynamics.check_visibility(0,0,7000,5000.0,2500));
-
-
-
-
-#terrain_presampling_start(lat, lon, 10000, 20000, 0.0);
-
-#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,
-# 37.6489722, -122.3748889, 37.6189722, -122.3448889 ];
-#
-#var x=geodinfo(p, 10000); # passing in vector with position tuples
-
-#foreach(var e;x) {
-# print("Elevation:",e); # showing results
-#}
-
-
-
-
+fgcommand("reinit", props.Node.new({subsystem:"environment"}));
}
+
+
+
+
+#################################################################
+# object classes
+#################################################################
+
+var weatherStation = {
+ new: func (lat, lon, vis, T, D, p) {
+ var s = { parents: [weatherStation] };
+ s.lat = lat;
+ s.lon = lon;
+ s.vis = vis;
+ s.T = T;
+ s.D = D;
+ s.p = p;
+ return s;
+ },
+ 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 effectVolume = {
+ new: func (geometry, lat, lon, r1, r2, phi, alt_low, alt_high, vis, rain, snow, turb, lift, lift_flag, sat) {
+ var e = { parents: [effectVolume] };
+ e.geometry = geometry;
+ e.lat = lat;
+ e.lon = lon;
+ e.r1 = r1;
+ e.r2 = r2;
+ e.phi = phi;
+ e.alt_low = alt_low;
+ e.alt_high = alt_high;
+ e.vis = vis;
+ e.rain = rain;
+ e.snow = snow;
+ e.turb = turb;
+ e.lift = lift;
+ e.lift_flag = lift_flag;
+ e.sat = sat;
+ return e;
+ },
+ 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;
+ },
+ correct_altitude: func {
+ var convective_alt = weather_dynamics.tile_convective_altitude[me.index-1] + alt_20_array[me.index-1];
+ var elevation = compat_layer.get_elevation(me.lat, me.lon);
+ me.alt_high = local_weather.get_convective_altitude(convective_alt, elevation, me.index) *1.15;
+ me.height = me.alt_high * 0.87;
+ },
+ correct_altitude_and_age: func {
+ var convective_alt = weather_dynamics.tile_convective_altitude[me.index-1] + local_weather.alt_20_array[me.index-1];
+ var elevation = -1.0; var p_cover = 0.2;
+ var info = geodinfo(me.lat, me.lon);
+ if (info != nil)
+ {
+ elevation = info[0] * local_weather.m_to_ft;
+ if (info[1] != nil)
+ {
+ var landcover = info[1].names[0];
+ if (contains(landcover_map,landcover)) {p_cover = landcover_map[landcover];}
+ else {p_cover = 0.2;}
+ }
+ }
+ me.alt_high = get_convective_altitude(convective_alt, elevation, me.index) * 1.15;
+ me.height = me.alt_high * 0.87;
+ var current_lifetime = math.sqrt(p_cover)/math.sqrt(0.35) * weather_dynamics.cloud_convective_lifetime_s;
+ var fractional_increase = (weather_dynamics.time_lw - me.evolution_timestamp)/current_lifetime;
+ me.flt = me.flt + fractional_increase;
+ me.evolution_timestamp = weather_dynamics.time_lw;
+ },
+ get_distance: func {
+ var lat = getprop("position/latitude-deg");
+ var lon = getprop("position/longitude-deg");
+ return math.sqrt(calc_d_sq(lat, lon, me.lat, me.lon));
+ },
+};
+
+
+var thermalLift = {
+ new: func (lat, lon, radius, height, cn, sh, max_lift, f_lift_radius) {
+ var l = { parents: [thermalLift] };
+ l.lat = lat;
+ l.lon = lon;
+ l.radius = radius;
+ l.height = height;
+ l.cn = cn;
+ l.sh = sh;
+ l.max_lift = max_lift;
+ l.f_lift_radius = f_lift_radius;
+ return l;
+ },
+ 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;
+ },
+ correct_altitude: func {
+ var convective_alt = weather_dynamics.tile_convective_altitude[me.index-1] + alt_20_array[me.index-1];
+ var elevation = compat_layer.get_elevation(me.lat, me.lon);
+ me.height = local_weather.get_convective_altitude(convective_alt, elevation, me.index);
+ },
+ correct_altitude_and_age: func {
+ var convective_alt = weather_dynamics.tile_convective_altitude[me.index-1] + local_weather.alt_20_array[me.index-1];
+ var elevation = -1.0; var p_cover = 0.2;
+ var info = geodinfo(me.lat, me.lon);
+ if (info != nil)
+ {
+ elevation = info[0] * local_weather.m_to_ft;
+ if (info[1] != nil)
+ {
+ var landcover = info[1].names[0];
+ if (contains(landcover_map,landcover)) {p_cover = landcover_map[landcover];}
+ else {p_cover = 0.2;}
+ }
+ }
+ me.height = get_convective_altitude(convective_alt, elevation, me.index);
+ var current_lifetime = math.sqrt(p_cover)/math.sqrt(0.35) * weather_dynamics.cloud_convective_lifetime_s;
+ var fractional_increase = (weather_dynamics.time_lw - me.evolution_timestamp)/current_lifetime;
+ me.flt = me.flt + fractional_increase;
+ me.evolution_timestamp = weather_dynamics.time_lw;
+ },
+
+};
+
+
+var waveLift = {
+ new: func (lat, lon, x, y, phi, height, max_lift) {
+ var w = { parents: [waveLift] };
+ w.lat = lat;
+ w.lon = lon;
+ w.x = x;
+ w.y = y;
+ w.phi = phi;
+ w.height = height;
+ w.max_lift = max_lift;
+ w.phi = getprop(lw~"tmp/tile-orientation-deg");
+ return w;
+ },
+
+};
+
+
+
#################################################################
# global variable, property creation and the startup listener
#################################################################
@@ -3051,7 +3669,7 @@ var ec = "/environment/config/";
# a hash map of the strength for convection associated with terrain types
-var landcover_map = {BuiltUpCover: 0.35, Town: 0.35, Freeway:0.35, BarrenCover:0.3, HerbTundraCover: 0.25, GrassCover: 0.2, CropGrassCover: 0.2, Sand: 0.25, Grass: 0.2, Ocean: 0.01, Marsh: 0.05, Lake: 0.01, ShrubCover: 0.15, Landmass: 0.2, CropWoodCover: 0.15, MixedForestCover: 0.1, DryCropPastureCover: 0.25, MixedCropPastureCover: 0.2, IrrCropPastureCover: 0.15, DeciduousBroadCover: 0.1, pa_taxiway : 0.35, pa_tiedown: 0.35, pc_taxiway: 0.35, pc_tiedown: 0.35, Glacier: 0.01, DryLake: 0.3, IntermittentStream: 0.2};
+var landcover_map = {BuiltUpCover: 0.35, Town: 0.35, Freeway:0.35, BarrenCover:0.3, HerbTundraCover: 0.25, GrassCover: 0.2, CropGrassCover: 0.2, EvergreenBroadCover: 0.2, Sand: 0.25, Grass: 0.2, Ocean: 0.01, Marsh: 0.05, Lake: 0.01, ShrubCover: 0.15, Landmass: 0.2, CropWoodCover: 0.15, MixedForestCover: 0.1, DryCropPastureCover: 0.25, MixedCropPastureCover: 0.2, IrrCropPastureCover: 0.15, DeciduousBroadCover: 0.1, pa_taxiway : 0.35, pa_tiedown: 0.35, pc_taxiway: 0.35, pc_tiedown: 0.35, Glacier: 0.01, DryLake: 0.3, IntermittentStream: 0.2};
# a hash map of average vertical cloud model sizes
@@ -3069,8 +3687,15 @@ var clouds_lon = [];
var clouds_alt = [];
var clouds_orientation = [];
+# additional info needed for dynamical clouds: the base altitude around which cloudlets are distributed
+# and the fractional lifetime
-# storage arrays for terrain presampling and results
+var clouds_mean_alt = [];
+var clouds_flt = [];
+var clouds_evolution_timestamp = [];
+
+
+# storage arrays for terrain presampling and results by tile
var terrain_n = [];
var alt_50_array = [];
@@ -3081,6 +3706,16 @@ var alt_20_array = [];
var effectVolumeArray = [];
var n_effectVolumeArray = 0;
+# the thermal and the wave hash
+
+var thermal = {};
+var wave = {};
+
+
+# array of currently existing weather stations
+
+var weatherStationArray = [];
+
# a flag for the wind model (so we don't have to do string comparisons all the time)
# 1: constant 2: constant in tile 3: aloft interpolated 4: airmass interpolated
@@ -3090,6 +3725,25 @@ var wind_model_flag = 1;
var convective_texture_mix = 0.0;
+# a global keeping track of the mean cloud altitude when building a Cumulus from individual cloudlets
+
+var cloud_mean_altitude = 0.0;
+
+# globals keeping track of the lifetime when building a Cumulus from individual cloudlets
+
+var cloud_fractional_lifetime = 0.0;
+var cloud_evolution_timestamp = 0.0;
+
+# global flags mirroring property tree menu settings
+
+var generate_thermal_lift_flag = 0;
+var thread_flag = 1;
+var dynamics_flag = 1;
+var presampling_flag = 1;
+var detailed_clouds_flag = 1;
+var dynamical_convection_flag = 1;
+var debug_output_flag = 1;
+
# set all sorts of default properties for the menu
@@ -3142,16 +3796,14 @@ setprop(lw~"tmp/box-bottom-fraction",0.9);
setprop(lw~"tmp/box-bottom-thickness",0.5);
setprop(lw~"tmp/box-bottom-n",12);
setprop(lw~"tmp/tile-type", "High-pressure");
-setprop(lw~"tmp/tile-orientation-deg", 0.0);
+setprop(lw~"tmp/tile-orientation-deg", 260.0);
setprop(lw~"tmp/windspeed-kt", 8.0);
setprop(lw~"tmp/tile-alt-offset-ft", 0.0);
setprop(lw~"tmp/tile-alt-median-ft",0.0);
setprop(lw~"tmp/tile-alt-min-ft",0.0);
setprop(lw~"tmp/tile-management", "single tile");
-setprop(lw~"tmp/generate-thermal-lift-flag", 0);
setprop(lw~"tmp/presampling-flag", 1);
setprop(lw~"tmp/asymmetric-tile-loading-flag", 0);
-setprop(lw~"tmp/thread-flag", 1);
setprop(lw~"tmp/last-reading-pos-del",0);
setprop(lw~"tmp/last-reading-pos-mod",0);
setprop(lw~"tmp/thread-status", "idle");
@@ -3159,23 +3811,23 @@ 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-wind-from-heading-deg",260.0);
setprop(lw~"tmp/FL0-windspeed-kt",8.0);
-setprop(lw~"tmp/FL50-wind-from-heading-deg",2.0);
+setprop(lw~"tmp/FL50-wind-from-heading-deg",262.0);
setprop(lw~"tmp/FL50-windspeed-kt",11.0);
-setprop(lw~"tmp/FL100-wind-from-heading-deg",4.0);
+setprop(lw~"tmp/FL100-wind-from-heading-deg",264.0);
setprop(lw~"tmp/FL100-windspeed-kt",16.0);
-setprop(lw~"tmp/FL180-wind-from-heading-deg",5.0);
+setprop(lw~"tmp/FL180-wind-from-heading-deg",265.0);
setprop(lw~"tmp/FL180-windspeed-kt",24.0);
-setprop(lw~"tmp/FL240-wind-from-heading-deg",9.0);
+setprop(lw~"tmp/FL240-wind-from-heading-deg",269.0);
setprop(lw~"tmp/FL240-windspeed-kt",35.0);
-setprop(lw~"tmp/FL300-wind-from-heading-deg",13.0);
+setprop(lw~"tmp/FL300-wind-from-heading-deg",273.0);
setprop(lw~"tmp/FL300-windspeed-kt",45.0);
-setprop(lw~"tmp/FL340-wind-from-heading-deg",14.0);
+setprop(lw~"tmp/FL340-wind-from-heading-deg",274.0);
setprop(lw~"tmp/FL340-windspeed-kt",50.0);
-setprop(lw~"tmp/FL390-wind-from-heading-deg",13.0);
+setprop(lw~"tmp/FL390-wind-from-heading-deg",273.0);
setprop(lw~"tmp/FL390-windspeed-kt",56.0);
-setprop(lw~"tmp/FL450-wind-from-heading-deg",12.0);
+setprop(lw~"tmp/FL450-wind-from-heading-deg",272.0);
setprop(lw~"tmp/FL450-windspeed-kt",65.0);
setprop(lw~"tmp/ipoint-latitude-deg",getprop("position/latitude-deg"));
setprop(lw~"tmp/ipoint-longitude-deg",getprop("position/longitude-deg"));
@@ -3183,8 +3835,6 @@ 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",39000.0);
setprop(lw~"config/distance-to-remove-tile-m",39500.0);
setprop(lw~"config/detailed-clouds-flag",1);
@@ -3198,6 +3848,10 @@ 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);
+setprop(lw~"config/debug-output-flag",1);
+setprop(lw~"config/generate-thermal-lift-flag", 0);
+setprop(lw~"config/dynamical-convection-flag", 1);
+setprop(lw~"config/thread-flag", 1);
# set the default loop flags to loops inactive
@@ -3206,12 +3860,14 @@ 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~"wave-loop-flag",0);
setprop(lw~"buffer-loop-flag",0);
setprop(lw~"housekeeping-loop-flag",0);
+setprop(lw~"convective-loop-flag",0);
# create other management properties
-setprop(lw~"clouds/cloud-number",0);
+#setprop(lw~"clouds/cloud-number",0);
setprop(lw~"clouds/placement-index",0);
setprop(lw~"clouds/model-placement-index",0);
setprop(lw~"effect-volumes/effect-placement-index",0);
@@ -3224,7 +3880,7 @@ setprop(lw~"effect-volumes/number-active-rain",0);
setprop(lw~"effect-volumes/number-active-snow",0);
setprop(lw~"effect-volumes/number-active-turb",0);
setprop(lw~"effect-volumes/number-active-lift",0);
-
+setprop(lw~"effect-volumes/number-active-sat",0);
# create properties for tile management
diff --git a/Nasal/weather_dynamics.nas b/Nasal/weather_dynamics.nas
index c92e12095..b89e3448d 100644
--- a/Nasal/weather_dynamics.nas
+++ b/Nasal/weather_dynamics.nas
@@ -1,6 +1,6 @@
########################################################
# routines to simulate cloud wind drift and evolution
-# Thorsten Renk, July 2010
+# Thorsten Renk, October 2010
########################################################
# function purpose
@@ -9,18 +9,18 @@
# timing_loop to provide accurate timing information for wind drift calculations
# quadtree_loop to manage drift of clouds in the field of view
# weather_dynamics_loop to manage drift of weather effects, tile centers and interpolation points
+# convective_loop to regularly recreate convective clouds
# generate_quadtree_structure to generate a quadtree data structure used for managing the visual field
# sort_into_quadtree to sort objects into a quadtree structure
+# sorting_recursion to recursively sort into a quadree (helper)
# quadtree_recursion to search the quadtree for objects in the visual field
# check_visibility to check if a quadrant is currently visible
# move_tile to move tile coordinates in the wind
-# move_effect_volume to move an effect volume in the wind
-# move_weather_station to move a weather station in the wind
# get_cartesian to get local Cartesian coordinates out of coordinates
####################################################
-# get the windfield for a given locatio and altitude
+# get the windfield for a given location and altitude
# (currently constant, but supposed to be local later)
####################################################
@@ -63,7 +63,8 @@ return windfield;
var timing_loop = func {
-time_lw = time_lw + getprop("/sim/time/delta-sec");
+dt_lw = getprop("/sim/time/delta-sec");
+time_lw = time_lw + dt_lw;
if (getprop(lw~"timing-loop-flag") ==1) {settimer(timing_loop, 0);}
@@ -116,6 +117,8 @@ foreach (t; tiles)
cos_beta = math.cos(beta * math.pi/180.0);
sin_beta = math.sin(beta * math.pi/180.0);
plane_x = xy_vec[0]; plane_y = xy_vec[1];
+
+ windfield = get_windfield(index);
quadtree_recursion(cloudQuadtrees[index-1],0,1,0.0,0.0);
}
@@ -156,34 +159,172 @@ if (getprop(lw~"dynamics-loop-flag") ==1) {settimer(quadtree_loop, 0);}
-var weather_dynamics_loop = func (index) {
+var weather_dynamics_loop = func (index, cindex) {
var n = 20;
+var nc = 1;
+var csize = weather_tile_management.n_cloudSceneryArray;
var i_max = index + n;
if (i_max > local_weather.n_effectVolumeArray) {i_max = local_weather.n_effectVolumeArray;}
+var ecount = 0;
+
for (var i = index; i < i_max; i = i+1)
{
- move_effect_volume(local_weather.effectVolumeArray[i]);
+ var ev = local_weather.effectVolumeArray[i];
+ if (ev.index !=0)
+ {ev.move();}
+ if ((ev.lift_flag == 2) and (rand() < 0.05) and (local_weather.presampling_flag == 1))
+ {
+ if (local_weather.dynamical_convection_flag ==1)
+ {
+ ev.correct_altitude_and_age();
+
+ if (ev.flt > 1.2) # beyond 1.0, sink is still active
+ {
+ local_weather.effectVolumeArray = weather_tile_management.delete_from_vector(local_weather.effectVolumeArray,i);
+ local_weather.n_effectVolumeArray = local_weather.n_effectVolumeArray - 1;
+ i = i-1; i_max = i_max -1; ecount = ecount + 1;
+ }
+
+ }
+ else
+ {ev.correct_altitude();}
+ }
}
+setprop(lw~"effect-volumes/number",getprop(lw~"effect-volumes/number")- ecount);
index = index + n;
if (i >= local_weather.n_effectVolumeArray) {index = 0;}
-var stations = props.globals.getNode(lw~"interpolation").getChildren("station");
-foreach (s; stations)
+var ccount = 0;
+
+if (csize > 0)
{
- move_weather_station(s);
+
+ var j_max = cindex + nc;
+ if (j_max > csize -1) {j_max = csize-1;}
+
+
+ for (var j = cindex; j < j_max; j = j+1)
+ {
+ var cs = weather_tile_management.cloudSceneryArray[j];
+ #cs.move();
+ if (cs.type !=0)
+ {
+ if ((rand() < 0.1) and (local_weather.presampling_flag == 1))
+ {
+ if (local_weather.dynamical_convection_flag ==1)
+ {
+ cs.correct_altitude_and_age();
+ if (cs.flt > 1.0) # the cloud has reached its maximum age and decays
+ {
+ cs.removeNodes();
+ weather_tile_management.cloudSceneryArray = weather_tile_management.delete_from_vector(weather_tile_management.cloudSceneryArray,j);
+ ccount = ccount + 1;
+ }
+ }
+ else
+ {
+ cs.correct_altitude();
+ }
+ }
+ }
+ }
+
+cindex = cindex + nc;
+if (j >= csize) {cindex = 0;}
}
-if (getprop(lw~"dynamics-loop-flag") ==1) {settimer( func {weather_dynamics_loop(index); },0);}
+
+
+foreach (s; local_weather.weatherStationArray)
+ {
+ s.move();
+ }
+
+if (getprop(lw~"dynamics-loop-flag") ==1) {settimer( func {weather_dynamics_loop(index, cindex); },0);}
}
+###########################################################
+# convective evolution loop
+###########################################################
+
+var convective_loop = func {
+
+# a 30 second loop needs a different strategy to end, otherwise there is trouble if it is restarted while still running
+
+if (convective_loop_kill_flag == 1)
+ {convective_loop_kill_flag = 0; return;}
+
+var cloud_respawning_interval_s = 30.0;
+
+
+if (getprop(lw~"tmp/thread-status") == "placing")
+ {if (getprop(lw~"convective-loop-flag") ==1) {settimer( func {convective_loop()}, 5.0);} return;}
+
+# open the system for write status
+setprop(lw~"tmp/buffer-status","placing");
+
+if (local_weather.debug_output_flag == 1)
+ {print("Respawning convective clouds...");}
+
+for(var i = 0; i < 9; i = i + 1)
+ {
+ var index = getprop(lw~"tiles/tile["~i~"]/tile-index");
+ if ((index == -1) or (index == 0)) {continue;}
+ if (getprop(lw~"tiles/tile["~i~"]/generated-flag") != 2)
+ {continue;}
+
+ var strength = tile_convective_strength[index-1];
+ var alt = tile_convective_altitude[index-1];
+ var n = weather_tiles.get_n(strength);
+ if (local_weather.detailed_clouds_flag == 1)
+ {n = int(0.7 * n);}
+
+ n = n/cloud_convective_lifetime_s * cloud_respawning_interval_s * math.sqrt(0.35);
+
+ n_res = n - int(n);
+ n = int(n);
+ if (rand() < n_res) {n=n+1;}
+
+ if (local_weather.debug_output_flag == 1)
+ {print("Tile: ", index, " n: ", n);}
+
+ var lat = getprop(lw~"tiles/tile["~i~"]/latitude-deg");
+ var lon = getprop(lw~"tiles/tile["~i~"]/longitude-deg");
+ var alpha = getprop(lw~"tiles/tile["~i~"]/orientation-deg");
+
+ compat_layer.buffered_tile_latitude = lat;
+ compat_layer.buffered_tile_longitude = lon;
+ compat_layer.buffered_tile_alpha = alpha;
+ compat_layer.buffered_tile_index = index;
+
+ setprop(lw~"tmp/buffer-tile-index", index);
+
+ if (local_weather.presampling_flag == 1)
+ {var alt_offset = local_weather.alt_20_array[index -1];}
+ else
+ {var alt_offset = getprop(lw~"tmp/tile-alt-offset-ft");}
+
+ local_weather.recreate_cumulus(lat,lon, alt + alt_offset, alpha, n, 20000.0, index);
+
+ }
+
+# close the write process
+setprop(lw~"tmp/buffer-status","idle");
+
+
+
+if (getprop(lw~"convective-loop-flag") ==1) {settimer(convective_loop, cloud_respawning_interval_s);}
+
+}
+
###########################################################
# generate quadtree structure
###########################################################
@@ -266,7 +407,8 @@ if (depth == quadtree_depth +1)
{
foreach (var c; tree)
{
- compat_layer.move_cloud(c, current_tile_index_wd);
+ c.move();
+ c.to_target_alt();
cloud_counter = cloud_counter + 1;
}
return;
@@ -396,59 +538,6 @@ t.getNode("timestamp-sec",1).setValue(weather_dynamics.time_lw);
}
-####################################################
-# move an effect volume
-####################################################
-
-var move_effect_volume = func (e) {
-
-# get the old spacetime position of the effect
-
-var lat_old = e.getNode("position/latitude-deg").getValue();
-var lon_old = e.getNode("position/longitude-deg").getValue();
-var tile_index = e.getNode("tile-index").getValue();
-var timestamp = e.getNode("timestamp-sec").getValue();
-
-# get windfield and time since last update
-
-var windfield = weather_dynamics.get_windfield(tile_index);
-var dt = weather_dynamics.time_lw - timestamp;
-
-
-# update the spacetime position of the effect
-
-e.getNode("position/latitude-deg",1).setValue(lat_old + windfield[1] * dt * local_weather.m_to_lat);
-e.getNode("position/longitude-deg",1).setValue(lon_old + windfield[0] * dt * local_weather.m_to_lon);
-e.getNode("timestamp-sec",1).setValue(weather_dynamics.time_lw);
-}
-
-
-####################################################
-# move a weather station
-####################################################
-
-var move_weather_station = func (s) {
-
-# get the old spacetime position of the station
-
-var lat_old = s.getNode("latitude-deg").getValue();
-var lon_old = s.getNode("longitude-deg").getValue();
-var tile_index = s.getNode("tile-index").getValue();
-var timestamp = s.getNode("timestamp-sec").getValue();
-
-# get windfield and time since last update
-
-var windfield = weather_dynamics.get_windfield(tile_index);
-var dt = weather_dynamics.time_lw - timestamp;
-
-
-# update the spacetime position of the effect
-
-s.getNode("latitude-deg",1).setValue(lat_old + windfield[1] * dt * local_weather.m_to_lat);
-s.getNode("longitude-deg",1).setValue(lon_old + windfield[0] * dt * local_weather.m_to_lon);
-s.getNode("timestamp-sec",1).setValue(weather_dynamics.time_lw);
-}
-
###########################################################
# get local Cartesian coordinates
@@ -504,7 +593,12 @@ var lw = "/local-weather/";
# globals
var time_lw = 0.0;
+var dt_lw = 0.0;
var max_clouds_in_loop = 250;
+var cloud_max_vertical_speed_fts = 30.0;
+var cloud_convective_lifetime_s = 1800.0; # max. lifetime of convective clouds
+
+var convective_loop_kill_flag = 0;
# the quadtree structure
@@ -516,6 +610,8 @@ var quadtree_depth = 3;
var tile_wind_direction = [];
var tile_wind_speed = [];
+var tile_convective_altitude = [];
+var tile_convective_strength = [];
# define these as global, as we need to evaluate them only once per frame
# but use them over and over
@@ -525,6 +621,7 @@ var cos_beta = 0;
var sin_beta = 0;
var plane_x = 0;
var plane_y = 0;
+var windfield = [];
var current_tile_index_wd = 0;
diff --git a/Nasal/weather_tile_management.nas b/Nasal/weather_tile_management.nas
index b6090f3f9..32fc366e5 100644
--- a/Nasal/weather_tile_management.nas
+++ b/Nasal/weather_tile_management.nas
@@ -1,6 +1,6 @@
########################################################
# routines to set up, transform and manage weather tiles
-# Thorsten Renk, July 2010
+# Thorsten Renk, October 2010
########################################################
# function purpose
@@ -13,9 +13,17 @@
# 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
+# housekeeping_loop to shift clouds from the scenery into the buffer
+# wathcdog loop (debug helping structure)
# 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
+# delete_from_vector to delete an element 'n' from a vector
+
+# object purpose
+#
+# cloudBuffer to store a cloud in a Nasal buffer, to provide methods to move it
+# cloudScenery to store info for clouds in scenery, to provide methods to move and evolve them
###################################
@@ -38,11 +46,12 @@ var loading_flag = getprop(lw~"tmp/asymmetric-tile-loading-flag");
var this_frame_action_flag = 0; # use this flag to avoid overlapping tile operations
setsize(active_tile_list,0);
+#append(active_tile_list,0); # tile zero formally containing static objects is always active
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;}
+if (distance_to_load < 29000.0)
+ {distance_to_load = 29000.0;}
foreach (var t; tNode) {
@@ -77,10 +86,11 @@ foreach (var t; tNode) {
{
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);
+ if (local_weather.debug_output_flag == 1)
+ {print("Building tile unique index ",getprop(lw~"tiles/tile-counter"), " in direction ",i);}
append(active_tile_list,getprop(lw~"tiles/tile-counter"));
- if (getprop(lw~"config/dynamics-flag") == 1)
+ if (local_weather.dynamics_flag == 1)
{
var quadtree = [];
weather_dynamics.generate_quadtree_structure(0, quadtree);
@@ -97,7 +107,8 @@ foreach (var t; tNode) {
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()," direction ",i);
+ if (local_weather.debug_output_flag == 1)
+ {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;
@@ -132,7 +143,8 @@ foreach (var t; tNode) {
print("Flag: ",gen_flag);
}
- print("Changing active tile to direction ", i_min);
+ if (local_weather.debug_output_flag == 1)
+ {print("Changing active tile to direction ", i_min);}
change_active_tile(i_min);
}
@@ -169,28 +181,30 @@ setprop(lw~"tiles/tmp/dir-index",dir_index);
# do windspeed and orientation before presampling check, but test not to do it again
-if (((getprop(lw~"tmp/presampling-flag") == 1) and (getprop(lw~"tmp/presampling-status") == "idle")) or (getprop(lw~"tmp/presampling-flag") == 0))
+if (((local_weather.presampling_flag == 1) and (getprop(lw~"tmp/presampling-status") == "idle")) or (local_weather.presampling_flag == 0))
{
var alpha = getprop(lw~"tmp/tile-orientation-deg");
+
if ((local_weather.wind_model_flag == 2) or (local_weather.wind_model_flag ==4))
{
alpha = alpha + 2.0 * (rand()-0.5) * 10.0;
+
# account for the systematic spin of weather systems around a low pressure
# core dependent on hemisphere
if (lat >0.0) {alpha = alpha -3.0;}
else {alpha = alpha +3.0;}
setprop(lw~"tmp/tile-orientation-deg",alpha);
-
+
# compute the new windspeed
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", windspeed);
+ setprop(lw~"tmp/windspeed-kt",windspeed);
# store the tile orientation and wind strength in an array for fast processing
@@ -204,7 +218,6 @@ if (((getprop(lw~"tmp/presampling-flag") == 1) and (getprop(lw~"tmp/presampling-
alpha = res[0];
setprop(lw~"tmp/tile-orientation-deg",alpha);
-
var windspeed = res[1];
setprop(lw~"tmp/windspeed-kt",windspeed);
@@ -219,16 +232,17 @@ if (((getprop(lw~"tmp/presampling-flag") == 1) and (getprop(lw~"tmp/presampling-
-
# now see if we need to presample the terrain
-if ((getprop(lw~"tmp/presampling-flag") == 1) and (getprop(lw~"tmp/presampling-status") == "idle"))
+if ((local_weather.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"));
return;
}
-print("Current tile type: ", code);
+
+if (local_weather.debug_output_flag == 1)
+ {print("Current tile type: ", code);}
if (getprop(lw~"tmp/tile-management") == "repeat tile")
{
@@ -248,7 +262,11 @@ if (getprop(lw~"tmp/tile-management") == "repeat tile")
else if (code == "cold_sector") {weather_tiles.set_cold_sector_tile();}
else if (code == "warm_sector") {weather_tiles.set_warm_sector_tile();}
else if (code == "tropical_weather") {weather_tiles.set_tropical_weather_tile();}
- else {print("Repeat tile not implemented with this tile type!");}
+ else
+ {
+ print("Repeat tile not implemented with this tile type!");
+ setprop("/sim/messages/pilot", "Local weather: Repeat tile not implemented with this tile type!");
+ }
}
else if (getprop(lw~"tmp/tile-management") == "realistic weather")
{
@@ -370,6 +388,7 @@ else if (getprop(lw~"tmp/tile-management") == "realistic weather")
else
{
print("Realistic weather not implemented with this tile type!");
+ setprop("/sim/messages/pilot", "Local weather: Realistic weather not implemented with this tile type!");
}
} # end if mode == realistic weather
@@ -397,21 +416,34 @@ for (var j = 0; j < s; j=j+1)
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");
var ecount = 0;
-foreach (var e; effectNode)
+for (var i = 0; i < local_weather.n_effectVolumeArray; i = i + 1)
{
- if (e.getNode("tile-index").getValue() == index)
- {
- e.remove();
+ ev = local_weather.effectVolumeArray[i];
+ if (ev.index == index)
+ {
+ local_weather.effectVolumeArray = delete_from_vector(local_weather.effectVolumeArray,i);
+ local_weather.n_effectVolumeArray = local_weather.n_effectVolumeArray - 1;
+ i = i - 1;
ecount = ecount + 1;
}
+ else if (ev.index == 0) # use the opportunity to check if static effects should also be removed
+ {
+ if (ev.get_distance() > 80000.0)
+ {
+ local_weather.effectVolumeArray = delete_from_vector(local_weather.effectVolumeArray,i);
+ local_weather.n_effectVolumeArray = local_weather.n_effectVolumeArray - 1;
+ i = i - 1;
+ ecount = ecount + 1;
+ }
+ }
}
+
setprop(lw~"effect-volumes/number",getprop(lw~"effect-volumes/number")- ecount);
# set placement indices to zero to reinitiate search for free positions
@@ -422,7 +454,7 @@ setprop(lw~"effect-volumes/effect-placement-index",0);
# remove quadtree structures
-if (getprop(lw~"config/dynamics-flag") ==1)
+if (local_weather.dynamics_flag ==1)
{
settimer( func {setsize(weather_dynamics.cloudQuadtrees[index-1],0);},1.0);
}
@@ -568,11 +600,6 @@ 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());}
}
@@ -630,7 +657,7 @@ setprop(lw~"tiles/tile[0]/generated-flag",0);
setprop(lw~"tiles/tile[0]/tile-index",-1);
setprop(lw~"tiles/tile[0]/code","");
setprop(lw~"tiles/tile[0]/timestamp-sec",weather_dynamics.time_lw);
-setprop(lw~"tiles/tile[0]/orientation-deg",0.0);
+setprop(lw~"tiles/tile[0]/orientation-deg",alpha);
x = 0.0; y = 40000.0;
setprop(lw~"tiles/tile[1]/latitude-deg",blat + get_lat(x,y,phi));
@@ -639,7 +666,7 @@ setprop(lw~"tiles/tile[1]/generated-flag",0);
setprop(lw~"tiles/tile[1]/tile-index",-1);
setprop(lw~"tiles/tile[1]/code","");
setprop(lw~"tiles/tile[1]/timestamp-sec",weather_dynamics.time_lw);
-setprop(lw~"tiles/tile[1]/orientation-deg",0.0);
+setprop(lw~"tiles/tile[1]/orientation-deg",alpha);
x = 40000.0; y = 40000.0;
setprop(lw~"tiles/tile[2]/latitude-deg",blat + get_lat(x,y,phi));
@@ -648,7 +675,7 @@ setprop(lw~"tiles/tile[2]/generated-flag",0);
setprop(lw~"tiles/tile[2]/tile-index",-1);
setprop(lw~"tiles/tile[2]/code","");
setprop(lw~"tiles/tile[2]/timestamp-sec",weather_dynamics.time_lw);
-setprop(lw~"tiles/tile[2]/orientation-deg",0.0);
+setprop(lw~"tiles/tile[2]/orientation-deg",alpha);
x = -40000.0; y = 0.0;
setprop(lw~"tiles/tile[3]/latitude-deg",blat + get_lat(x,y,phi));
@@ -657,7 +684,7 @@ setprop(lw~"tiles/tile[3]/generated-flag",0);
setprop(lw~"tiles/tile[3]/tile-index",-1);
setprop(lw~"tiles/tile[3]/code","");
setprop(lw~"tiles/tile[3]/timestamp-sec",weather_dynamics.time_lw);
-setprop(lw~"tiles/tile[3]/orientation-deg",0.0);
+setprop(lw~"tiles/tile[3]/orientation-deg",alpha);
# this is the current tile
x = 0.0; y = 0.0;
@@ -677,7 +704,7 @@ setprop(lw~"tiles/tile[5]/generated-flag",0);
setprop(lw~"tiles/tile[5]/tile-index",-1);
setprop(lw~"tiles/tile[5]/code","");
setprop(lw~"tiles/tile[5]/timestamp-sec",weather_dynamics.time_lw);
-setprop(lw~"tiles/tile[5]/orientation-deg",0.0);
+setprop(lw~"tiles/tile[5]/orientation-deg",alpha);
x = -40000.0; y = -40000.0;
setprop(lw~"tiles/tile[6]/latitude-deg",blat + get_lat(x,y,phi));
@@ -686,7 +713,7 @@ setprop(lw~"tiles/tile[6]/generated-flag",0);
setprop(lw~"tiles/tile[6]/tile-index",-1);
setprop(lw~"tiles/tile[6]/code","");
setprop(lw~"tiles/tile[6]/timestamp-sec",weather_dynamics.time_lw);
-setprop(lw~"tiles/tile[6]/orientation-deg",0.0);
+setprop(lw~"tiles/tile[6]/orientation-deg",alpha);
x = 0.0; y = -40000.0;
setprop(lw~"tiles/tile[7]/latitude-deg",blat + get_lat(x,y,phi));
@@ -695,7 +722,7 @@ setprop(lw~"tiles/tile[7]/generated-flag",0);
setprop(lw~"tiles/tile[7]/tile-index",-1);
setprop(lw~"tiles/tile[7]/code","");
setprop(lw~"tiles/tile[7]/timestamp-sec",weather_dynamics.time_lw);
-setprop(lw~"tiles/tile[7]/orientation-deg",0.0);
+setprop(lw~"tiles/tile[7]/orientation-deg",alpha);
x = 40000.0; y = -40000.0;
setprop(lw~"tiles/tile[8]/latitude-deg",blat + get_lat(x,y,phi));
@@ -704,7 +731,7 @@ setprop(lw~"tiles/tile[8]/generated-flag",0);
setprop(lw~"tiles/tile[8]/tile-index",-1);
setprop(lw~"tiles/tile[8]/code","");
setprop(lw~"tiles/tile[8]/timestamp-sec",weather_dynamics.time_lw);
-setprop(lw~"tiles/tile[8]/orientation-deg",0.0);
+setprop(lw~"tiles/tile[8]/orientation-deg",alpha);
}
@@ -772,7 +799,7 @@ for (var i = index; i < i_max; i = i+1)
# if wind drift is on, move the cloud
- if (getprop(lw~"config/dynamics-flag") == 1)
+ if (local_weather.dynamics_flag == 1)
{
c.move();
}
@@ -797,8 +824,30 @@ for (var i = index; i < i_max; i = i+1)
if (d < d_comp) # insert the cloud into scenery and delete from buffer
{
- setprop(lw~"tmp/buffer-tile-index",c.index);
+ compat_layer.buffered_tile_index = c.index;
+
+ if (local_weather.dynamics_flag == 1) # assemble the current tile coordinates for insertion into quadtree
+ {
+ for (var j = 0; j < 9; j=j+1)
+ {
+ if (getprop(lw~"tiles/tile["~j~"]/tile-index") == c.index)
+ {
+ compat_layer.buffered_tile_latitude = getprop(lw~"tiles/tile["~j~"]/latitude-deg");
+ compat_layer.buffered_tile_longitude = getprop(lw~"tiles/tile["~j~"]/longitude-deg");
+ compat_layer.buffered_tile_alpha=getprop(lw~"tiles/tile["~j~"]/orientation-deg");
+ break;
+ }
+ }
+ }
+
+ if ((c.type !=0) and (local_weather.dynamics_flag == 1)) # set additional info for Cumulus clouds
+ {
+ compat_layer.cloud_mean_altitude = c.alt - c.rel_alt;
+ compat_layer.cloud_flt = c.flt;
+ compat_layer.cloud_evolution_timestamp = c.evolution_timestamp;
+ }
compat_layer.create_cloud(c.path, c.lat, c.lon, c.alt, c.orientation);
+ n_cloudSceneryArray = n_cloudSceneryArray +1;
cloudBufferArray = delete_from_vector(cloudBufferArray,i);
i = i -1; i_max = i_max - 1; n_max = n_max - 1;
deleted_flag = 1;
@@ -826,6 +875,7 @@ var housekeeping_loop = func (index) {
var n = 5;
var n_max = size(cloudSceneryArray);
+n_cloudSceneryArray = n_max;
var s = size(active_tile_list);
setprop(lw~"clouds/cloud-scenery-count",n_max);
@@ -869,6 +919,7 @@ for (var i = index; i < i_max; i = i+1)
c.removeNodes();
cloudSceneryArray = delete_from_vector(cloudSceneryArray,i);
i = i -1; i_max = i_max - 1; n_max = n_max - 1;
+ n_cloudSceneryArray = n_cloudSceneryArray -1;
continue;
}
@@ -893,6 +944,7 @@ for (var i = index; i < i_max; i = i+1)
append(cloudBufferArray,c.to_buffer());
cloudSceneryArray = delete_from_vector(cloudSceneryArray,i);
i = i -1; i_max = i_max - 1; n_max = n_max - 1;
+ n_cloudSceneryArray = n_cloudSceneryArray -1;
continue;
}
@@ -921,11 +973,13 @@ foreach(t; tNode)
var code = t.getNode("code").getValue();
var index = t.getNode("tile-index").getValue();
var flag = t.getNode("generated-flag").getValue();
+ var alpha = t.getNode("orientation-deg").getValue();
- print(i,": code: ", code, " unique id: ", index, " flag: ", flag);
+ print(i,": code: ", code, " unique id: ", index, " flag: ", flag, " alpha: ",alpha);
i = i + 1;
}
+print("alpha: ",getprop(lw~"tmp/tile-orientation-deg"));
print("====================");
@@ -963,8 +1017,9 @@ var active_tile_list = [];
var cloudBufferArray = [];
+
var cloudBuffer = {
- new: func(lat, lon, alt, path, orientation, index) {
+ new: func(lat, lon, alt, path, orientation, index, type) {
var c = { parents: [cloudBuffer] };
c.lat = lat;
c.lon = lon;
@@ -972,6 +1027,7 @@ var cloudBuffer = {
c.path = path;
c.orientation = orientation;
c.index = index;
+ c.type = type;
return c;
},
get_distance: func {
@@ -1003,13 +1059,21 @@ var cloudBuffer = {
var cloudSceneryArray = [];
+var n_cloudSceneryArray = 0;
var cloudScenery = {
- new: func(index, cloudNode, modelNode) {
+ new: func(index, type, cloudNode, modelNode) {
var c = { parents: [cloudScenery] };
c.index = index;
+ c.type = type;
c.cloudNode = cloudNode;
c.modelNode = modelNode;
+ c.calt = cloudNode.getNode("position/altitude-ft");
+ c.clat = cloudNode.getNode("position/latitude-deg");
+ c.clon = cloudNode.getNode("position/longitude-deg");
+ c.alt = c.calt.getValue();
+ c.lat = c.clat.getValue();
+ c.lon = c.clon.getValue();
return c;
},
removeNodes: func {
@@ -1017,17 +1081,20 @@ var cloudScenery = {
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);
+ var b = cloudBuffer.new(me.lat, me.lon, me.alt, path, orientation, me.index, me.type);
- if (getprop(lw~"config/dynamics-flag") == 1)
+ if (local_weather.dynamics_flag == 1)
{
- var timestamp = me.cloudNode.getNode("timestamp-sec").getValue();
- b.timestamp = timestamp;
+ b.timestamp = me.timestamp;
+
+ if (me.type !=0) # Cumulus clouds get some extra info
+ {
+ b.flt = me.flt;
+ b.rel_alt = me.rel_alt;
+ b.evolution_timestamp = me.evolution_timestamp;
+ }
}
me.removeNodes();
@@ -1036,21 +1103,106 @@ var cloudScenery = {
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();
+ var lat = me.clat.getValue();
+ var lon = me.clon.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();
+ var lat = me.clat.getValue();
+ var lon = me.clon.getValue();
cpos.set_latlon(lat,lon,0.0);
return pos.course_to(cpos);
},
get_altitude: func {
- return me.cloudNode.getNode("position/altitude-ft").getValue();
+ return me.calt.getValue();
+ },
+ correct_altitude: func {
+ var lat = me.clat.getValue();
+ var lon = me.clon.getValue();
+ var convective_alt = weather_dynamics.tile_convective_altitude[me.index-1] + local_weather.alt_20_array[me.index-1];
+ var elevation = compat_layer.get_elevation(lat, lon);
+ var alt_new = local_weather.get_convective_altitude(convective_alt, elevation, me.index);
+ me.target_alt = alt_new + me.rel_alt;
+ },
+ correct_altitude_and_age: func {
+ var lat = me.lat;
+ var lon = me.lon;
+ var convective_alt = weather_dynamics.tile_convective_altitude[me.index-1] + local_weather.alt_20_array[me.index-1];
+
+ # get terrain elevation and landcover
+
+ var elevation = -1.0; var p_cover = 0.2;# defaults if there is no info
+ var info = geodinfo(lat, lon);
+ if (info != nil)
+ {
+ elevation = info[0] * local_weather.m_to_ft;
+ if (info[1] != nil)
+ {
+ var landcover = info[1].names[0];
+ if (contains(local_weather.landcover_map,landcover)) {p_cover = local_weather.landcover_map[landcover];}
+ else {p_cover = 0.2;}
+ }
+ }
+
+
+ # correct the altitude
+ var alt_new = local_weather.get_convective_altitude(convective_alt, elevation, me.index);
+ me.target_alt = alt_new + me.rel_alt;
+
+ # correct fractional lifetime based on terrain below
+ var current_lifetime = math.sqrt(p_cover)/math.sqrt(0.35) * weather_dynamics.cloud_convective_lifetime_s;
+ var fractional_increase = (weather_dynamics.time_lw - me.evolution_timestamp)/current_lifetime;
+ me.flt = me.flt + fractional_increase;
+ me.evolution_timestamp = weather_dynamics.time_lw;
+ },
+ to_target_alt: func {
+ if (me.type ==0) {return;}
+ var alt_diff = me.target_alt - me.alt;
+ if (alt_diff == 0.0) {return;}
+ var max_vertical_movement_ft = weather_dynamics.dt_lw * weather_dynamics.cloud_max_vertical_speed_fts;
+ if (abs(alt_diff) < max_vertical_movement_ft)
+ {
+ me.alt = me.target_alt;
+ }
+ else if (alt_diff < 0)
+ {
+ me.alt = me.alt -max_vertical_movement_ft;
+ }
+ else
+ {
+ me.alt = me.alt + max_vertical_movement_ft;
+ }
+ setprop(lw~"clouds/tile["~me.index~"]/cloud["~me.write_index~"]/position/altitude-ft", me.alt);
+ },
+ move: func {
+
+
+ var windfield = weather_dynamics.windfield;
+ 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;
+
+ setprop(lw~"clouds/tile["~me.index~"]/cloud["~me.write_index~"]/position/latitude-deg", me.lat);
+ setprop(lw~"clouds/tile["~me.index~"]/cloud["~me.write_index~"]/position/longitude-deg", me.lon);
+
+ me.timestamp = weather_dynamics.time_lw;
+
+ },
+ show: func {
+ var lat = me.clat.getValue();
+ var lon = me.clon.getValue();
+ var alt = me.calt.getValue();
+
+ var convective_alt = weather_dynamics.tile_convective_altitude[me.index-1] + local_weather.alt_20_array[me.index-1];
+ var elevation = compat_layer.get_elevation(lat, lon);
+ print("lat :", lat, " lon: ", lon, " alt: ", alt);
+ print("path: ", me.modelNode.getNode("path").getValue());
+ print("elevation: ", compat_layer.get_elevation(lat, lon), " cloudbase: ", convective_alt);
+ if (me.type !=0) {print("relative: ", me.rel_alt, "target: ", me.target_alt);}
},
};
diff --git a/Nasal/weather_tiles.nas b/Nasal/weather_tiles.nas
index a7b7bc33d..c306709c4 100644
--- a/Nasal/weather_tiles.nas
+++ b/Nasal/weather_tiles.nas
@@ -1,7 +1,7 @@
########################################################
# routines to set up weather tiles
-# Thorsten Renk, July 2010
+# Thorsten Renk, October 2010
########################################################
# function purpose
@@ -22,7 +22,7 @@
var tile_start = func {
# set thread lock
-if (getprop(lw~"tmp/thread-flag") == 1){setprop(lw~"tmp/thread-status","computing");}
+if (local_weather.thread_flag == 1){setprop(lw~"tmp/thread-status","computing");}
# set the tile code
var current_code = getprop(lw~"tiles/code");
@@ -51,9 +51,10 @@ var dir_index = getprop(lw~"tiles/tmp/dir-index");
local_weather.assemble_effect_array();
-print("Finished setting up tile type ",current_code, " in direction ",dir_index);
+if (local_weather.debug_output_flag == 1)
+ {print("Finished setting up tile type ",current_code, " in direction ",dir_index);}
-if (getprop(lw~"tmp/thread-flag") == 1)
+if (local_weather.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);}
@@ -97,10 +98,17 @@ local_weather.set_weather_station(blat, blon, 20000.0, 14.0, 12.0, 29.78);
#create_2_8_sstratus_streak(blat, blon,5000.0,0.0);
-create_4_8_cirrocumulus_bank(blat, blon, 6000.0, 0.0);
+#create_4_8_cirrocumulus_bank(blat, blon, 6000.0, 0.0);
+
+#create_4_8_cirrocumulus_streaks(blat, blon, 6000.0, 0.0);
+
+# create_2_8_cirrocumulus(blat, blon, 6000.0, 0.0);
#create_detailed_stratocumulus_bank(blat, blon,5000.0+alt_offset,0.0);
+create_4_8_altocumulus_perlucidus(blat, blon, 10000.0, 0.0);
+
+local_weather.create_effect_volume(3, blat, blon, 20000.0, 7000.0, alpha, 0.0, 80000.0, -1, -1, -1, -1, 15.0, -3,-1);
tile_finished();
@@ -143,12 +151,43 @@ var p = 1025.0 + rand() * 6.0; p = adjust_p(p);
# and set them at the tile center
local_weather.set_weather_station(blat, blon, vis, T, D, p * hp_to_inhg);
-# weak cumulus development
var alt = spread * 1000;
-var strength = rand() * 0.05;
+var strength = 0.0;
-local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
+var rn = rand();
+
+
+if (rn > 0.5)
+ {
+ # cloud scenario 1: weak cumulus development and blue thermals
+
+ strength = rand() * 0.05;
+ local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
+
+ # generate a few blue thermals
+
+ if (local_weather.generate_thermal_lift_flag !=0)
+ {
+ local_weather.generate_thermal_lift_flag = 3;
+ strength = rand() * 0.4;
+ local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
+ local_weather.generate_thermal_lift_flag = 2;
+ }
+
+ }
+else if (rn > 0.0)
+ {
+ # cloud scenario 2: some Cirrocumulus patches
+
+ create_2_8_cirrocumulus(blat, blon, alt + alt_offset + 5000.0, alpha);
+ }
+
+
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
tile_finished();
@@ -192,36 +231,35 @@ var p = 1019.0 + rand() * 6.0; p = adjust_p(p);
# and set them at the tile center
local_weather.set_weather_station(blat, blon, vis, T, D, p * hp_to_inhg);
-# moderate cumulus development
var alt = spread * 1000;
+var strength = 0.0;
var rn = rand();
+
if (rn > 0.66)
{
# cloud scenario 1: possible Cirrus over Cumulus
- var strength = 0.2 + rand() * 0.4;
+ strength = 0.2 + rand() * 0.4;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
# one or two Cirrus clouds
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);
+ compat_layer.create_cloud(path, blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), alt + alt_offset + 25000.0 + rand() * 5000.0,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);
+ compat_layer.create_cloud(path, blat + get_lat(x,y,phi), blon+get_lon(x,y,phi), alt + alt_offset +25000.0 + rand() * 5000.0,alpha);
}
}
@@ -229,7 +267,7 @@ else if (rn > 0.33)
{
# cloud scenario 2: Cirrostratus over weak Cumulus
- var strength = 0.2 + rand() * 0.2;
+ strength = 0.2 + rand() * 0.2;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
create_2_8_cirrostratus(blat, blon, alt+alt_offset+25000.0, alpha);
@@ -239,7 +277,7 @@ else if (rn > 0.0)
{
# cloud scenario 3: Cirrocumulus sheet over Cumulus
- var strength = 0.2 + rand() * 0.2;
+ 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;
@@ -251,6 +289,12 @@ else if (rn > 0.0)
}
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
+
+
tile_finished();
}
@@ -296,25 +340,26 @@ local_weather.set_weather_station(blat, blon, vis, T, D, p * hp_to_inhg);
# now a random selection of different possible cloud configuration scenarios
var alt = spread * 1000;
+var strength = 0.0;
var rn = rand();
-if (rn > 0.833)
+if (rn > 0.875)
{
# cloud scenario 1: Altocumulus patch over weak Cumulus
- var strength = 0.1 + rand() * 0.1;
+ strength = 0.1 + rand() * 0.1;
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;
- local_weather.create_streak("Altocumulus",blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 12000.0+alt+alt_offset,1500.0,30,1000.0,0.2,800.0,30,1000.0,0.2,800.0,alpha ,1.0);
+ local_weather.create_streak("Altocumulus",blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 12000.0+alt+alt_offset,1500.0,30,1000.0,0.2,1200.0,30,1000.0,0.2,1200.0,alpha ,1.0);
}
-else if (rn > 0.666)
+else if (rn > 0.750)
{
# cloud scenario 2: Altocumulus streaks
- var strength = 0.15 + rand() * 0.2;
+ strength = 0.15 + rand() * 0.2;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
x = 2.0 * (rand()-0.5) * 10000;
@@ -322,14 +367,14 @@ else if (rn > 0.666)
local_weather.create_streak("Altocumulus",blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 12000.0+alt+alt_offset,1500.0,25,700.0,0.2,800.0,10,700.0,0.2,800.0,alpha ,1.4);
x = 2.0 * (rand()-0.5) * 10000;
y = 2.0 * (rand()-0.5) * 10000;
- local_weather.create_streak("Altocumulus",blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 12000.0+alt+alt_offset,1500.0,22,750.0,0.2,800.0,8,750.0,0.2,800.0,alpha ,1.1);
+ local_weather.create_streak("Altocumulus",blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 12000.0+alt+alt_offset,1500.0,22,750.0,0.2,1000.0,8,750.0,0.2,1000.0,alpha ,1.1);
}
-else if (rn > 0.5)
+else if (rn > 0.625)
{
# cloud scenario 3: Cirrus
- var strength = 0.1 + rand() * 0.1;
+ strength = 0.1 + rand() * 0.1;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
x = 2.0 * (rand()-0.5) * 3000;
@@ -337,11 +382,11 @@ else if (rn > 0.5)
local_weather.create_streak("Cirrus",blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 22000.0+alt+alt_offset,1500.0,3,9000.0,0.0, 800.0, 1,8000.0,0.0,800,0,alpha ,1.0);
}
-else if (rn > 0.333)
+else if (rn > 0.5)
{
# cloud scenario 4: Cumulonimbus banks
- var strength = 0.7 + rand() * 0.3;
+ strength = 0.7 + rand() * 0.3;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
for (var i = 0; i < 3; i = i + 1)
@@ -352,11 +397,11 @@ else if (rn > 0.333)
create_cloud_bank("Cumulonimbus", blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), alt+alt_offset, 1600.0, 800.0, 3000.0, 9, alpha);
}
}
-else if (rn > 0.166)
+else if (rn > 0.375)
{
# cloud scenario 5: scattered Stratus
- var strength = 0.4 + rand() * 0.2;
+ strength = 0.4 + rand() * 0.2;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
var size_offset = 0.5 * m_to_ft * local_weather.cloud_vertical_size_map["Stratus_structured"];
@@ -364,11 +409,11 @@ else if (rn > 0.166)
local_weather.create_streak("Stratus (structured)",blat, blon, alt+6000.0+alt_offset+size_offset,1000.0,18,0.0,0.3,20000.0,18,0.0,0.3,20000.0,0.0,1.0);
}
-else if (rn > 0.0)
+else if (rn > 0.250)
{
# cloud scenario 6: Cirrocumulus sheets
- var strength = 0.2 + rand() * 0.2;
+ strength = 0.2 + rand() * 0.2;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
@@ -383,10 +428,31 @@ else if (rn > 0.0)
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);
}
+ }
+else if (rn > 0.125)
+ {
+ # cloud scenario 7: Thin Cirrocumulus sheets over weak Cumulus
+
+ strength = 0.05 + rand() * 0.1;
+ local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
+
+ create_4_8_cirrocumulus_streaks(blat, blon, alt + 6000.0 + alt_offset, alpha);
+
+ }
+else if (rn > 0.0)
+ {
+ # cloud scenario 8: Altocumulus perlucidus
+
+ create_4_8_altocumulus_perlucidus(blat, blon, alt + 10000.0 + alt_offset, alpha);
}
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
+
tile_finished();
@@ -435,6 +501,7 @@ local_weather.set_weather_station(blat, blon, vis, T, D, p * hp_to_inhg);
# altitude for the lowest layer
var alt = spread * 1000.0;
+var strength = 0.0;
# now a random selection of different possible cloud configuration scenarios
@@ -484,6 +551,11 @@ else if (rn > 0.0)
create_4_8_cirrocumulus_bank(blat, blon, alt+alt_offset + 12000.0, alpha);
}
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
+
tile_finished();
}
@@ -531,6 +603,7 @@ local_weather.set_weather_station(blat, blon, vis, T, D, p * hp_to_inhg);
# altitude for the lowest layer
var alt = spread * 1000.0;
+var strength = 0.0;
var rn = rand();
@@ -547,16 +620,16 @@ if (rn > 0.75)
var beta = rand() * 360.0;
local_weather.create_layer("Nimbus", blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), alt+alt_offset, 500.0, 12000.0, 7000.0, beta, 1.0, 0.2, 1, 1.0);
- local_weather.create_effect_volume(2, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 10000.0, 6000.0, beta, 0.0, alt + alt_offset, 5000.0, 0.3, -1, -1, -1,0 );
- local_weather.create_effect_volume(2, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 9000.0, 5000.0, beta, 0.0, alt+alt_offset-300.0, 1500.0, 0.5, -1, -1, -1,0 );
+ local_weather.create_effect_volume(2, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 10000.0, 6000.0, beta, 0.0, alt + alt_offset, 5000.0, 0.3, -1, -1, -1,0,-1 );
+ local_weather.create_effect_volume(2, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 9000.0, 5000.0, beta, 0.0, alt+alt_offset-300.0, 1500.0, 0.5, -1, -1, -1,0,-1 );
x = 2.0 * (rand()-0.5) * 11000.0;
y = 2.0 * (rand()-0.5) * 11000.0;
var beta = rand() * 360.0;
local_weather.create_layer("Nimbus", blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), alt+alt_offset, 500.0, 10000.0, 6000.0, beta, 1.0, 0.2, 1, 1.0);
- local_weather.create_effect_volume(2, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 9000.0, 5000.0, beta, 0.0, alt + alt_offset, 5000.0, 0.3, -1, -1, -1,0 );
- local_weather.create_effect_volume(2, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 8000.0, 4000.0, beta, 0.0, alt+alt_offset-300.0, 1500.0, 0.5, -1, -1, -1,0 );
+ local_weather.create_effect_volume(2, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 9000.0, 5000.0, beta, 0.0, alt + alt_offset, 5000.0, 0.3, -1, -1, -1,0 ,-1);
+ local_weather.create_effect_volume(2, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 8000.0, 4000.0, beta, 0.0, alt+alt_offset-300.0, 1500.0, 0.5, -1, -1, -1,0,-1 );
create_4_8_sstratus_undulatus(blat, blon, alt+alt_offset +3000.0, alpha);
create_2_8_tstratus(blat, blon, alt+alt_offset +6000.0, alpha);
@@ -569,8 +642,8 @@ else if (rn >0.5)
alt = alt + local_weather.cloud_vertical_size_map["Stratus"] * 0.5 * m_to_ft;
create_8_8_stratus(blat, blon, alt+alt_offset,alpha);
- 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 );
+ 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,-1);
+ 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,-1 );
create_2_8_sstratus(blat, blon, alt+alt_offset+3000,alpha);
}
else if (rn >0.25)
@@ -594,6 +667,11 @@ else if (rn >0.0)
create_2_8_sstratus(blat, blon, alt+alt_offset+6000,alpha);
}
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
+
tile_finished();
}
@@ -643,15 +721,15 @@ local_weather.set_weather_station(blat, blon, vis, T, D, p * hp_to_inhg);
# set a closed Nimbostratus layer
var alt = spread * 1000.0 + local_weather.cloud_vertical_size_map["Nimbus"] * 0.5 * m_to_ft;
+var strength = 0.0;
-#print("alt: ",spread*1000);
create_8_8_nimbus(blat, blon, alt+alt_offset, alpha);
# and a precipitation layer below, more rain in the center of the tile
-local_weather.create_effect_volume(3, blat, blon, 20000.0, 20000.0, alpha, 0.0, alt + alt_offset, 3000.0, 0.3, -1, -1, -1,0 );
-local_weather.create_effect_volume(3, blat , blon, 16000.0, 16000.0, alpha, 0.0, alt + alt_offset - 300.0, 1500.0, 0.5, -1, -1, -1,0 );
+local_weather.create_effect_volume(3, blat, blon, 20000.0, 20000.0, alpha, 0.0, alt + alt_offset, 3000.0, 0.3, -1, -1, -1,0 ,0.95);
+local_weather.create_effect_volume(3, blat , blon, 16000.0, 16000.0, alpha, 0.0, alt + alt_offset - 300.0, 1500.0, 0.5, -1, -1, -1,0 ,0.8);
# and some broken Stratus cover above
@@ -661,6 +739,10 @@ var rn = rand();
if (rn > 0.5){create_4_8_stratus_patches(blat, blon, alt+alt_offset+3000.0, alpha);}
else {create_4_8_stratus(blat, blon, alt+alt_offset+3000.0, alpha);}
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
tile_finished();
@@ -705,6 +787,7 @@ local_weather.set_weather_station(blat, blon, vis, T, D, p * hp_to_inhg);
# altitude for the lowest layer
var alt = spread * 1000.0;
+var strength = 0.0;
var rn = rand();
@@ -713,7 +796,7 @@ var rn = rand();
if (rn > 0.5)
{
# cloud scenario 1: strong Cumulus development
- var strength = 0.8 + rand() * 0.2;
+ strength = 0.8 + rand() * 0.2;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
}
@@ -721,7 +804,7 @@ else if (rn > 0.0)
{
# cloud scenario 2: Cirrocumulus sheets over Cumulus
- var strength = 0.6 + rand() * 0.2;
+ 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)
@@ -738,6 +821,12 @@ else if (rn > 0.0)
}
+#local_weather.create_effect_volume(3, blat, blon, 20000.0, 7000.0, alpha, 0.0, 80000.0, -1, -1, -1, -1, 15.0, -3,-1);
+
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
tile_finished();
@@ -782,6 +871,7 @@ local_weather.set_weather_station(blat, blon, vis, T, D, p * hp_to_inhg);
# altitude for the lowest layer
var alt = spread * 1000.0;
+var strength = 0.0;
var rn = rand();
@@ -789,14 +879,14 @@ var rn = rand();
if (rn > 0.8)
{
# cloud scenario 1: weak Cumulus development, some Cirrostratus
- var strength = 0.3 + rand() * 0.2;
+ strength = 0.3 + rand() * 0.2;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
create_4_8_cirrostratus_patches(blat, blon, alt+alt_offset+25000.0, alpha);
}
else if (rn > 0.6)
{
# cloud scenario 2: weak Cumulus development under Altostratus streaks
- var strength = 0.1 + rand() * 0.1;
+ strength = 0.1 + rand() * 0.1;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
var size_offset = 0.5 * m_to_ft * local_weather.cloud_vertical_size_map["Stratus_structured"];
@@ -807,7 +897,7 @@ else if (rn > 0.6)
else if (rn > 0.4)
{
# cloud scenario 3: Cirrocumulus bank
- var strength = 0.05 + rand() * 0.05;
+ strength = 0.05 + rand() * 0.05;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
var size_offset = 0.5 * m_to_ft * local_weather.cloud_vertical_size_map["Cirrocumulus"];
@@ -818,7 +908,7 @@ else if (rn > 0.4)
else if (rn > 0.2)
{
# cloud scenario 4: Cirrocumulus undulatus
- var strength = 0.05 + rand() * 0.05;
+ strength = 0.05 + rand() * 0.05;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
var size_offset = 0.5 * m_to_ft * local_weather.cloud_vertical_size_map["Cirrocumulus"];
@@ -830,7 +920,7 @@ else if (rn > 0.0)
{
# cloud scenario 5: weak Cumulus development under scattered Altostratus
- var strength = 0.15 + rand() * 0.15;
+ strength = 0.15 + rand() * 0.15;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
var size_offset = 0.5 * m_to_ft * local_weather.cloud_vertical_size_map["Stratus_structured"];
@@ -839,6 +929,10 @@ else if (rn > 0.0)
}
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
tile_finished();
@@ -892,6 +986,7 @@ local_weather.set_weather_station(blat, blon, vis, T, D, p * hp_to_inhg);
# altitude for the lowest layer
var alt = spread * 1000.0;
+var strength = 0.0;
# tropical weather has a strong daily variation, call thunderstorm only in the correct afternoon time window
@@ -901,7 +996,7 @@ var rn = rand();
if (rn > (t_factor * t_factor * t_factor * t_factor)) # call a normal convective cloud system
{
-var strength = 1.0 + rand() * 0.2;
+strength = 1.0 + rand() * 0.2;
local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
}
@@ -954,10 +1049,15 @@ local_weather.cumulus_exclusion_layer(blat, blon, alt+alt_offset, n, 20000.0, 20
# some turbulence in the convection layer
-local_weather.create_effect_volume(3, blat, blon, 20000.0, 20000.0, alpha, 0.0, alt+3000.0+alt_offset, -1, -1, -1, 0.4, -1,0 );
+local_weather.create_effect_volume(3, blat, blon, 20000.0, 20000.0, alpha, 0.0, alt+3000.0+alt_offset, -1, -1, -1, 0.4, -1,0 ,-1);
} # end thundercloud placement
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
+
tile_finished();
}
@@ -1019,6 +1119,7 @@ local_weather.set_weather_station(blat +get_lat(x,y,phi), blon + get_lon(x,y,phi
# altitude for the lowest layer
var alt = spread * 1000.0;
+var strength = 0.0;
# thunderstorms first
@@ -1072,12 +1173,17 @@ local_weather.create_streak("Stratus (thin)",blat+get_lat(x,y,phi), blon+get_lon
# some turbulence in the convection layer
x=0.0; y = 5000.0;
-local_weather.create_effect_volume(3, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 20000.0, 11000.0, alpha, 0.0, alt+3000.0+alt_offset, -1, -1, -1, 0.4, -1,0 );
+local_weather.create_effect_volume(3, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 20000.0, 11000.0, alpha, 0.0, alt+3000.0+alt_offset, -1, -1, -1, 0.4, -1,0 ,-1);
# some rain and reduced visibility in its core
x=0.0; y = 5000.0;
-local_weather.create_effect_volume(3, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 20000.0, 8000.0, alpha, 0.0, alt+alt_offset, 10000.0, 0.1, -1, -1, -1,0 );
+local_weather.create_effect_volume(3, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 20000.0, 8000.0, alpha, 0.0, alt+alt_offset, 10000.0, 0.1, -1, -1, -1,0,-1 );
+
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
tile_finished();
@@ -1145,6 +1251,12 @@ local_weather.set_weather_station(blat +get_lat(x,y,phi), blon + get_lon(x,y,phi
# altitude for the lowest layer
var alt = spread * 1000.0;
+# some weak Cumulus development
+
+var strength = 0.1 + rand() * 0.1;
+local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0);
+
+
# high Cirrus leading
x = 2.0 * (rand()-0.5) * 1000;
@@ -1165,6 +1277,11 @@ for (var i=0; i<6; i=i+1)
}
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
+
tile_finished();
}
@@ -1230,7 +1347,7 @@ local_weather.set_weather_station(blat +get_lat(x,y,phi), blon + get_lon(x,y,phi
# altitude for the lowest layer
var alt = spread * 1000.0;
-
+var strength = 0.0;
# followed by random patches of Cirrostratus
@@ -1273,6 +1390,10 @@ var y = 8000.0;
local_weather.create_streak("Stratus",blat +get_lat(x,y,phi), blon+get_lon(x,y,phi), alt+alt_offset +5000.0,1000.0,30,0.0,0.2,20000.0,10,0.0,0.2,12000.0,alpha,1.0);
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
tile_finished();
@@ -1339,7 +1460,7 @@ local_weather.set_weather_station(blat +get_lat(x,y,phi), blon + get_lon(x,y,phi
# altitude for the lowest layer
var alt = spread * 1000.0 + local_weather.cloud_vertical_size_map["Nimbus"] * 0.5 * m_to_ft;
-
+var strength = 0.0;
# closed Stratus layer
@@ -1364,12 +1485,18 @@ local_weather.create_streak("Nimbus",blat +get_lat(x,y,phi), blon+get_lon(x,y,ph
# some rain beneath the stratus
x=0.0; y = -10000.0;
-local_weather.create_effect_volume(3, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 20000.0, 10000.0, alpha, 0.0, alt+alt_offset+1000, vis * 0.7, 0.1, -1, -1, -1,0 );
+local_weather.create_effect_volume(3, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 20000.0, 10000.0, alpha, 0.0, alt+alt_offset+1000, vis * 0.7, 0.1, -1, -1, -1,0 ,-1);
# heavier rain beneath the Nimbostratus
x=0.0; y = 10000.0;
-local_weather.create_effect_volume(3, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 20000.0, 10000.0, alpha, 0.0, alt+alt_offset, vis * 0.5, 0.3, -1, -1, -1,0 );
+local_weather.create_effect_volume(3, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 20000.0, 10000.0, alpha, 0.0, alt+alt_offset, vis * 0.5, 0.3, -1, -1, -1,0,-1 );
+
+
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
tile_finished();
@@ -1436,6 +1563,7 @@ local_weather.set_weather_station(blat +get_lat(x,y,phi), blon + get_lon(x,y,phi
# altitude for the lowest layer
var alt = spread * 1000.0 + local_weather.cloud_vertical_size_map["Nimbus"] * 0.5 * m_to_ft;
+var strength = 0.0;
# low Nimbostratus layer
@@ -1461,7 +1589,13 @@ local_weather.create_streak("Nimbus",blat +get_lat(x,y,phi), blon+get_lon(x,y,ph
# rain beneath the Nimbostratus
x=0.0; y = -5000.0;
-local_weather.create_effect_volume(3, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 20000.0, 15000.0, alpha, 0.0, alt+alt_offset, vis * 0.5, 0.3, -1, -1, -1,0 );
+local_weather.create_effect_volume(3, blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), 20000.0, 15000.0, alpha, 0.0, alt+alt_offset, vis * 0.5, 0.3, -1, -1, -1,0 ,-1);
+
+
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
tile_finished();
@@ -1481,7 +1615,7 @@ tile_finished();
var set_gliders_sky_tile = func {
-setprop(lw~"tiles/code","glides_sky");
+setprop(lw~"tiles/code","gliders_sky");
tile_start();
@@ -1503,16 +1637,20 @@ 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);
-# switch the placement of thermal effect volumes on: 1: constant lift 2: by function
-setprop(lw~"tmp/generate-thermal-lift-flag",2);
+var alt = 3000.0;
+
# add convective clouds
var strength = 0.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);
+local_weather.create_cumosys(blat,blon, alt+alt_offset,n, 20000.0);
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
tile_finished();
@@ -1547,16 +1685,28 @@ calc_geo(blat);
# first weather info for tile center (lat, lon, visibility, temperature, dew point, pressure)
local_weather.set_weather_station(blat, blon, 45000.0, 20.0, 15.0, 1018 * hp_to_inhg);
-# switch the placement of thermal effect volumes on: 1: constant lift 2: by function 3: blue
-setprop(lw~"tmp/generate-thermal-lift-flag",3);
+local_weather.generate_thermal_lift_flag = 3;
+var alt = 5000.0;
# add convective clouds
+# set flag to blue thermal generation
+if (local_weather.generate_thermal_lift_flag !=0)
+ {local_weather.generate_thermal_lift_flag = 3;}
+
var strength = 0.9;
var n = int(4000 * strength); # calculate the number of placement tries from tile size 20x20km and strength
local_weather.create_cumosys(blat,blon, 5000.0+alt_offset,n, 20000.0);
+# set flag back to normal thermal generation
+if (local_weather.generate_thermal_lift_flag !=0)
+ {local_weather.generate_thermal_lift_flag = 0;}
+
+# store convective altitude and strength
+
+append(weather_dynamics.tile_convective_altitude,alt);
+append(weather_dynamics.tile_convective_strength,strength);
tile_finished();
@@ -1723,6 +1873,10 @@ for (var i = n; i = 0.0 && GlobalIterationCount < gIterationCap)
{
- depth += size;
- float t = step(0.95, texture2D(reliefMap, dp + ds * depth).a);
- if(best_depth > 0.996)
- if(depth >= t)
- best_depth = depth;
- }
- depth = best_depth;
+ vec4 uv = vec4(p2.xyz, level);
+ d = texture2DLod(QDMTex, uv.xy, uv.w).w;
- const int binary_search_steps = 5;
-
- for(int i = 0; i < binary_search_steps; ++i)
- {
- size *= 0.5;
- float t = step(0.95, texture2D(reliefMap, dp + ds * depth).a);
- if(depth >= t)
+ if (d > p2.z)
{
- best_depth = depth;
- depth -= 2.0 * size;
+ //predictive point of ray traversal
+ vec3 tmpP2 = p + v * d;
+
+ //current node count
+ float nodeCount = pow(2.0, (MAX_LEVEL - level));
+ //current and predictive node ID
+ vec4 nodeID = floor(vec4(p2.xy, tmpP2.xy)*nodeCount);
+
+ //check if we are crossing the current cell
+ if (nodeID.x != nodeID.z || nodeID.y != nodeID.w)
+ {
+ //calculate distance to nearest bound
+ vec2 a = p2.xy - p.xy;
+ vec2 p3 = (nodeID.xy + dirSign) / nodeCount;
+ vec2 b = p3.xy - p.xy;
+
+ vec2 dNC = (b.xy * p2.z) / a.xy;
+ //take the nearest cell
+ d = min(d,min(dNC.x, dNC.y))+fDeltaNC;
+
+ level++;
+
+ //use additional convergence speed-up
+ #ifdef USE_QDM_ASCEND_INTERVAL
+ if(frac(level*0.5) > EPSILON)
+ level++;
+ #elseif USE_QDM_ASCEND_CONST
+ level++;
+ #endif
+ }
+ p2 = p + v * d;
}
- depth += size;
+ level--;
+ GlobalIterationCount++;
}
- return(best_depth);
+ //
+ // Manual Bilinear filtering
+ //
+ float rayLength = length(p2.xy - p.xy) + fDeltaNC;
+
+ float dA = p2.z * (rayLength - BILINEAR_SMOOTH_FACTOR * TEXEL_SPAN_HALF) / rayLength;
+ float dB = p2.z * (rayLength + BILINEAR_SMOOTH_FACTOR * TEXEL_SPAN_HALF) / rayLength;
+
+ vec4 p2a = vec4(p + v * dA, 0.0);
+ vec4 p2b = vec4(p + v * dB, 0.0);
+ dA = texture2DLod(NormalTex, p2a.xy, p2a.w).w;
+ dB = texture2DLod(NormalTex, p2b.xy, p2b.w).w;
+
+ dA = abs(p2a.z - dA);
+ dB = abs(p2b.z - dB);
+
+ p2 = mix(p2a.xyz, p2b.xyz, dA / (dA + dB));
+
+ p = p2;
+}
+
+float ray_intersect(vec2 dp, vec2 ds)
+{
+ vec3 p = vec3( dp, 0.0 );
+ vec3 v = vec3( ds, 1.0 );
+ QDM( p, v );
+ return p.z;
}
void main (void)
{
- if ( quality_level >= 3.5 ) {
- linear_search_steps = 20;
- }
vec3 ecPos3 = ecPosition.xyz / ecPosition.w;
vec3 V = normalize(ecPos3);
vec3 s = vec3(dot(V, VTangent), dot(V, VBinormal), dot(VNormal, -V));
vec2 ds = s.xy * depth_factor / s.z;
vec2 dp = gl_TexCoord[0].st - ds;
- float d = ray_intersect(NormalTex, dp, ds);
+ float d = ray_intersect(dp, ds);
vec2 uv = dp + ds * d;
vec3 N = texture2D(NormalTex, uv).xyz * 2.0 - 1.0;
@@ -89,7 +147,7 @@ void main (void)
vec3 sl = normalize( vec3( dot( l, VTangent ), dot( l, VBinormal ), dot( -l, VNormal ) ) );
ds = sl.xy * depth_factor / sl.z;
dp -= ds * d;
- float dl = ray_intersect(NormalTex, dp, ds);
+ float dl = ray_intersect(dp, ds);
if ( dl < d - 0.05 )
shadow_factor = dot( constantColor.xyz, vec3( 1.0, 1.0, 1.0 ) ) * 0.25;
}
diff --git a/gui/dialogs/local_weather_config.xml b/gui/dialogs/local_weather_config.xml
index 74eb35605..1be6c2729 100644
--- a/gui/dialogs/local_weather_config.xml
+++ b/gui/dialogs/local_weather_config.xml
@@ -33,7 +33,7 @@
320
100
20
- 25000.0
+ 29000.0
55000.0
/local-weather/config/distance-to-load-tile-m
diff --git a/gui/dialogs/local_weather_tiles.xml b/gui/dialogs/local_weather_tiles.xml
index 2d3b86397..770a45620 100644
--- a/gui/dialogs/local_weather_tiles.xml
+++ b/gui/dialogs/local_weather_tiles.xml
@@ -35,9 +35,6 @@
Coldfront
Warmfront
Tropical
- ---
- Glider's sky
- Blue thermals
dialog-apply
@@ -104,7 +101,7 @@
constant in tile
aloft interpolated
aloft waypoints
-
+
dialog-apply
@@ -150,8 +147,8 @@
150
15
15
- worker threads
- /local-weather/tmp/thread-flag
+ generate thermals
+ /local-weather/config/generate-thermal-lift-flag
dialog-apply
@@ -162,8 +159,8 @@
125
15
15
- asymmetric range
- /local-weather/tmp/asymmetric-tile-loading-flag
+ debug output
+ /local-weather/config/debug-output-flag
dialog-apply
@@ -193,6 +190,18 @@
+
+ 150
+ 100
+ 15
+ 15
+ dynamical convection
+ /local-weather/config/dynamical-convection-flag
+
+ dialog-apply
+
+
+
10
75
@@ -250,7 +259,7 @@
45
0
- Clear clouds
+ Clear / End
true
@@ -262,7 +271,7 @@
135
0
- Cancel
+ Close
true
Esc
diff --git a/gui/menubar.xml b/gui/menubar.xml
index d13b2877c..39045e82f 100644
--- a/gui/menubar.xml
+++ b/gui/menubar.xml
@@ -576,6 +576,15 @@
+ -
+
Reload HUD
+
+ reinit
+ hud
+
+
+
+
-
Reload Panel
diff --git a/preferences.xml b/preferences.xml
index fcb3db031..334cfa354 100644
--- a/preferences.xml
+++ b/preferences.xml
@@ -249,10 +249,8 @@ Started September 2000 by David Megginson, david@megginson.com
Aircraft/Generic/Panels/generic-trans-mini-panel.xml
- Huds/Default/default.xml
- Huds/NTPS.xml
- false
- false
+ Huds/default.xml
+ false
Helvetica.txf
8
@@ -598,7 +596,7 @@ Started September 2000 by David Megginson, david@megginson.com
- true
+ false
1
@@ -618,6 +616,7 @@ Started September 2000 by David Megginson, david@megginson.com
+