Added environment panel for depth, pressure and outside temperature.
This commit is contained in:
1 parent
2d91487c6a
commit
92006372da
21 files changed
+2825
-1616
No files matched your search
@@ -0,0 +1,64 @@
|
||||
@tool
|
||||
extends Control
|
||||
|
||||
var depth_m := 0.0
|
||||
var maximum_depth_m := 1000.0
|
||||
var knee_m := 1.0
|
||||
var warning_fraction := 0.8
|
||||
var fault_fraction := 0.95
|
||||
var available := false
|
||||
|
||||
func _ready() -> void:
|
||||
resized.connect(queue_redraw)
|
||||
theme_changed.connect(queue_redraw)
|
||||
|
||||
# log(1 + depth / knee) includes zero and is nearly linear close to the surface.
|
||||
func normalized_depth(value: float) -> float:
|
||||
var knee := maxf(knee_m, 0.001)
|
||||
var maximum := maxf(maximum_depth_m, 0.001)
|
||||
return log(1 + clampf(value, 0, maximum) / knee) / log(1 + maximum / knee)
|
||||
|
||||
func severity() -> int:
|
||||
var ratio := depth_m / maxf(maximum_depth_m, 0.001)
|
||||
return 2 if ratio >= fault_fraction else (1 if ratio >= warning_fraction else 0)
|
||||
|
||||
func _draw() -> void:
|
||||
var top := 9.0
|
||||
var bottom := maxf(top + 1, size.y - 10)
|
||||
var track := get_theme_color("instrument_grid", "SurfaceSide")
|
||||
var ink := get_theme_color("font_color", "Label")
|
||||
var font := get_theme_default_font()
|
||||
draw_line(Vector2(17, top), Vector2(17, bottom), track, 2, true)
|
||||
var decade := maxf(knee_m, 0.001)
|
||||
while decade < maximum_depth_m:
|
||||
for multiplier in [1.0, 2.0, 5.0]:
|
||||
var tick: float = decade * multiplier
|
||||
if tick > 0 and tick < maximum_depth_m:
|
||||
var y: float = lerpf(top, bottom, normalized_depth(tick))
|
||||
draw_line(Vector2(14, y), Vector2(21, y), track, 1, true)
|
||||
decade *= 10
|
||||
var last_label_y := -100.0
|
||||
var last_label_value := -1.0
|
||||
var ticks: Array[float] = [0, maxf(knee_m, 0.001) * 2]
|
||||
decade = maxf(knee_m, 0.001) * 10
|
||||
while decade < maximum_depth_m:
|
||||
ticks.append(decade)
|
||||
decade *= 10
|
||||
ticks.append(maximum_depth_m)
|
||||
for tick in ticks:
|
||||
if tick < 0 or tick > maximum_depth_m or is_equal_approx(tick, last_label_value):
|
||||
continue
|
||||
var y := lerpf(top, bottom, normalized_depth(tick))
|
||||
if tick != maximum_depth_m and (y - last_label_y < 20 or (bottom - y < 20 and tick != 0)):
|
||||
continue
|
||||
draw_line(Vector2(12, y), Vector2(23, y), ink, 1, true)
|
||||
draw_string(font, Vector2(29, y + 5), String.num(tick, 3).trim_suffix(".0"), HORIZONTAL_ALIGNMENT_LEFT, -1, 14, ink)
|
||||
last_label_y = y
|
||||
last_label_value = tick
|
||||
if available:
|
||||
var y := lerpf(top, bottom, normalized_depth(depth_m))
|
||||
var role: String = ["instrument_accent", "warning", "fault"][severity()]
|
||||
var accent := get_theme_color(role, "SurfaceSide")
|
||||
draw_line(Vector2(17, top), Vector2(17, y), accent, 3, true)
|
||||
draw_colored_polygon(PackedVector2Array([Vector2(1, y - 5), Vector2(1, y + 5), Vector2(12, y)]), accent)
|
||||
draw_line(Vector2(12, y), Vector2(23, y), accent, 3, true)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cbobdfddbbddo
|
||||
@@ -0,0 +1,23 @@
|
||||
extends VBoxContainer
|
||||
|
||||
var elapsed := 0.0
|
||||
@onready var panel = $EnvironmentPanel
|
||||
|
||||
func _ready() -> void:
|
||||
$Controls/Contrast.toggled.connect(func(high: bool) -> void:
|
||||
theme = load("res://themes/theme_highcontrast.tres" if high else "res://themes/theme.tres")
|
||||
)
|
||||
$Controls/State.item_selected.connect(func(index: int) -> void:
|
||||
if index == 7: panel.clear_telemetry()
|
||||
)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
elapsed += delta
|
||||
match $Controls/State.selected:
|
||||
0: panel.set_telemetry(0, 0.10, 12.4)
|
||||
1: panel.set_telemetry(0.75 + sin(elapsed) * 0.25, 0.11, 12.4)
|
||||
2: panel.set_telemetry(248.6, 2.54, 7.4)
|
||||
3: panel.set_telemetry(850, 8.6, 4.2)
|
||||
4: panel.set_telemetry(400, 9.6, -1.5)
|
||||
5: panel.set_telemetry(1010, 10.1, 3.2)
|
||||
6, 7: pass
|
||||
@@ -0,0 +1 @@
|
||||
uid://5qywekq0w4ne
|
||||
@@ -0,0 +1,67 @@
|
||||
@tool
|
||||
extends PanelContainer
|
||||
|
||||
@export var maximum_depth_m := 1000.0
|
||||
@export var maximum_pressure_mpa := 10.0
|
||||
@export var shallow_scale_knee_m := 1.0
|
||||
@export_range(0, 1) var warning_fraction := 0.8
|
||||
@export_range(0, 1) var fault_fraction := 0.95
|
||||
@export var stale_after_seconds := 2.0
|
||||
|
||||
var _depth := 0.0
|
||||
var _pressure := 0.0
|
||||
var _temperature := 0.0
|
||||
var _received_ms := -1
|
||||
var _stale := false
|
||||
|
||||
func _ready() -> void:
|
||||
_refresh()
|
||||
|
||||
## Depth in metres, pressure in MPa, water temperature in Celsius; supplied independently.
|
||||
func set_telemetry(depth_m: float, pressure_mpa: float, water_temperature_c: float) -> bool:
|
||||
if not is_finite(depth_m) or not is_finite(pressure_mpa) or not is_finite(water_temperature_c) or pressure_mpa < 0:
|
||||
return false
|
||||
_depth = depth_m
|
||||
_pressure = pressure_mpa
|
||||
_temperature = water_temperature_c
|
||||
_received_ms = Time.get_ticks_msec()
|
||||
_refresh()
|
||||
return true
|
||||
|
||||
func clear_telemetry() -> void:
|
||||
_received_ms = -1
|
||||
_refresh()
|
||||
|
||||
func _severity(ratio: float) -> int:
|
||||
return 2 if ratio >= maxf(warning_fraction, fault_fraction) else (1 if ratio >= warning_fraction else 0)
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
var stale := _received_ms >= 0 and Time.get_ticks_msec() - _received_ms > stale_after_seconds * 1000
|
||||
if stale != _stale:
|
||||
_refresh()
|
||||
|
||||
func _refresh() -> void:
|
||||
if not is_node_ready():
|
||||
return
|
||||
var measured := _received_ms >= 0
|
||||
_stale = measured and Time.get_ticks_msec() - _received_ms > stale_after_seconds * 1000
|
||||
var depth_ratio := _depth / maxf(maximum_depth_m, 0.001)
|
||||
var pressure_ratio := _pressure / maxf(maximum_pressure_mpa, 0.001)
|
||||
var worst_ratio := maxf(depth_ratio, pressure_ratio)
|
||||
var variants := ["Label", "InstrumentWarning", "InstrumentFault"]
|
||||
%DepthValue.text = "%.2f m" % _depth if measured else "— m"
|
||||
%PressureValue.text = "%.2f MPa" % _pressure if measured else "— MPa"
|
||||
%TemperatureValue.text = "%.1f °C" % _temperature if measured else "— °C"
|
||||
%DepthReference.text = "/ %s m" % String.num(maximum_depth_m, 2).trim_suffix(".0")
|
||||
%PressureReference.text = "/ %s MPa" % String.num(maximum_pressure_mpa, 2).trim_suffix(".0")
|
||||
%DepthTitle.theme_type_variation = variants[_severity(depth_ratio)] if measured else "Label"
|
||||
%PressureTitle.theme_type_variation = variants[_severity(pressure_ratio)] if measured else "Label"
|
||||
%State.text = "NO TELEMETRY" if not measured else ("STALE" if _stale else ("OVER LIMIT" if worst_ratio > 1 else ("NEAR LIMIT" if _severity(worst_ratio) > 0 else "")))
|
||||
%State.theme_type_variation = "InstrumentMuted" if not measured else ("InstrumentWarning" if _stale else variants[_severity(worst_ratio)])
|
||||
%DepthScale.depth_m = _depth
|
||||
%DepthScale.maximum_depth_m = maxf(maximum_depth_m, 0.001)
|
||||
%DepthScale.knee_m = maxf(shallow_scale_knee_m, 0.001)
|
||||
%DepthScale.warning_fraction = warning_fraction
|
||||
%DepthScale.fault_fraction = maxf(warning_fraction, fault_fraction)
|
||||
%DepthScale.available = measured
|
||||
%DepthScale.queue_redraw()
|
||||
@@ -0,0 +1 @@
|
||||
uid://dnafkcowopwod
|
||||
@@ -5,7 +5,7 @@ const ENTRIES = {
|
||||
"camera": {"title": "Camera", "description": "16:9 video surface with a stream header.", "scene": preload("res://components/camera_layout_slot.tscn"), "size": Vector2i(16, 10), "minimum": Vector2i(8, 5), "reference": Vector2(960, 600)},
|
||||
"vehicle": {"title": "Vehicle status", "description": "Mode, faults, electrical readings and internal temperature.", "scene": preload("res://components/vehicle_status_panel.tscn"), "size": Vector2i(10, 8), "minimum": Vector2i(6, 4), "reference": Vector2(600, 440)},
|
||||
"motion": {"title": "Motion", "description": "Attitude, heading, acceleration and angular momentum.", "scene": preload("res://components/motion_panel.tscn"), "size": Vector2i(10, 7), "minimum": Vector2i(6, 4), "reference": Vector2(600, 410), "background": NodePath("Content/Background")},
|
||||
"environment": {"title": "Environment", "description": "Reserved for depth, pressure and water temperature.", "scene": preload("res://components/layout_slot.tscn"), "size": Vector2i(6, 5), "minimum": Vector2i(4, 3), "reference": Vector2(360, 240), "fill": true},
|
||||
"environment": {"title": "Environment", "description": "Depth with a shallow-expanded scale, outside pressure and water temperature.", "scene": preload("res://components/environment_panel.tscn"), "size": Vector2i(6, 5), "minimum": Vector2i(4, 3), "reference": Vector2(360, 240)},
|
||||
"link": {"title": "Link", "description": "Connection state, traffic utilization and packet loss.", "scene": preload("res://components/link_panel.tscn"), "size": Vector2i(6, 4), "minimum": Vector2i(4, 3), "reference": Vector2(360, 240)},
|
||||
"videovr": {"title": "Video / VR", "description": "Reserved for latency, headset connection and resolution.", "scene": preload("res://components/layout_slot.tscn"), "size": Vector2i(12, 8), "minimum": Vector2i(6, 4), "reference": Vector2(600, 400), "fill": true},
|
||||
"operatortools": {"title": "Operator tools", "description": "Reserved for recording, manipulator controls and terminal.", "scene": preload("res://components/layout_slot.tscn"), "size": Vector2i(10, 6), "minimum": Vector2i(6, 4), "reference": Vector2(600, 400), "fill": true},
|
||||
|
||||
Reference in new issue
Block a user