Files
uarep-ctl/scenes/работа/работа.gd

493 lines
18 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@tool
class_name work extends Panel
## Основной скрипт для режима "Работа".
@export var Bip: PackedScene ## Индикатор излучения цели.
@export var col_grey: Color ## Второй цвет для фона.
@export var col_red: Color ## Первый цвет для фона.
@export var drag_scale_band: float ## Масштаб изменения параметра от движения мыши для строба по радиальному размеру.
@export var drag_scale_width: float ## Масштаб изменения параметра от движения мыши для строба по угловому размеру.
@export var freq_high: float ## Верхняя рабочая частота, МГЦ.
@export var freq_low: float ## Нижняя рабочая частота, МГЦ.
@export var radius_center: Vector2 ## Координаты центра диаграммы пеленг-частота.
@export var radius_internal: float ## Внутренний радиус диаграммы пеленг-частота.
@export var radius_outter: float ## Внешний радиус диаграммы пеленг-частота.
@export var strob_max_band: float ## Максимальная ширина строба по углу.
@export var strob_max_width: float ## Максимальная ширина строба по углу.
@export var strob_min_band: float ## Минимальная ширина строба по частоте.
@export var strob_min_width: float ## Минимальная ширина строба по углу.
@export var window_0_id: int ## Идетификатор окна. Присваивается godot от 0 до количества созданных окон.
var drag_button: MouseButton ## Кнопка мыши нажатая при перетаскивании.
var drag_fsm: DragFSM = DragFSM.IDLE ## Текущее состояние перетаскивания.
var btn_select: BtnSel = BtnSel.THREAT ## Текущее состояние кнопки выбора цели.
var drag_pos_begin: Vector2 ## Точка начала перетаскивания.
var max_zoom: int ## Максимальный уровень детализации.
var min_zoom: int ## Минимальный уровень детализации.
var shift_pressed: bool ## Кнопка SHIFT нажата.
var strob_band_begin: float ## Ширина строба в момент начала перетаскивания.
var strob_dir_begin: float ## Направление антенны в момент начала перетаскивания.
var strob_width_begin: float ## Ширина строба по углу в момент начала перетаскивания.
signal drag_begin ## Вызывается в момент начала перетаскивания.
signal drag_continue ## Вызывается во время продолжения перетаскивания.
signal drag_end ## Вызывается в момент завершения перетаскивания.
## Границы секторов блоков ФС по частоте в режиме РТО.
const fs_band_rto: Dictionary = {
0: [200.0, 250.0],
1: [250.0, 300.0],
2: [300.0, 350.0],
3: [350.0, 400.0],
4: [400.0, 450.0],
5: [450.0, 500.0],
6: [500.0, 550.0] }
## Границы секторов блоков ФС по частоте в режиме РЛС.
const fs_band_rls: Dictionary = {
0: [480.0, 490.0],
1: [490.0, 500.0],
2: [500.0, 510.0],
3: [510.0, 520.0],
4: [520.0, 530.0],
5: [530.0, 540.0],
6: [540.0, 550.0] }
## Границы секторов блоков ФС по пеленгу.
const fs_sectors: Dictionary = {
0: [0.0, 90.0],
3: [90.0, 180.0],
2: [180.0, 270.0],
1: [270.0, 360.0] }
const fs_freq: Dictionary = {
0: [400.0, 1200.0],
1: [1200.0, 2000.0],
2: [2000.0, 2800.0],
3: [2800.0, 3600.0],
4: [3600.0, 4400.0],
5: [4400.0, 5200.0],
6: [5200.0, 6000.0] }
var fs_band = fs_band_rto # Текущий режим блоков ФС по частоте
var fs_selected: Dictionary # Словарь выбранных секторов
var fs_active: Dictionary # Словарь секторов назначенных на подавление
## Состояние перетаскивания.
enum DragFSM {
DRAG, ## В процессе.
IDLE, ## Не активно, ожидание.
OFF ## Выключено.
}
## Состояние перетаскивания.
enum BtnSel {
SECTOR, ## В процессе.
THREAT, ## Не активно, ожидание.
FS ## Выключено.
}
## Обработчик сигнала изменения списка целей.
func on_threats_resized(threats: Dictionary): $count_all_pad/count_all.text = '%02d' % threats.size()
## Обработчик выбора цели.
func on_threat_selected(th, ecm_btns): on_rto_threat_sel(th.id, ecm_btns)
## Обработчик нажатия на кнопку вид.
func on_button_view_toggled(toggled: bool):
signaller.emit_signal('map_mode_changed', int(toggled))
if toggled:
fs_band = fs_band_rls
else:
fs_band = fs_band_rto
##
func _enter_tree() -> void:
var timer1 = Timer.new()
timer1.name = 'timer1'
add_child(timer1)
timer1.one_shot = true
timer1.connect('timeout', Callable(self, 'on_enter_tree'))
timer1.start(1.0)
func _exit_tree() -> void:
var timer1 = get_node('timer1')
remove_child(timer1)
timer1.queue_free()
## Производит инициализацию.
func _ready():
min_zoom = ProjectSettings.get_setting('application/config/map_minimum_zoom', 5)
max_zoom = ProjectSettings.get_setting('application/config/map_maximum_zoom', 19)
drag_fsm = DragFSM.OFF
$btn_zoom.set_meta('zoom', min_zoom - 1)
var btns_select: Array = $btns_select.get_children()
btns_select.any(func(btn): btn.button_connect('pressed', Callable(self, 'on_button_select').bind(btn, btns_select)))
$btn_view.button_connect('toggled', Callable(self, 'on_button_view_toggled'))
var nodes: Array = get_tree().get_nodes_in_group('группа-режим-помехи')
nodes.any(func(btn): btn.button_connect('pressed', Callable(self, 'on_button_pressed').bind(btn, nodes)))
threats.connect('threat_new', Callable(self, 'on_threat_new'))
threats.connect('threat_lost', Callable(self, 'on_threat_lost'))
threats.connect('threats_resized', Callable(self, 'on_threats_resized'))
threats.connect('threat_update', Callable(self, 'on_threat_update'))
signaller.connect('zoom_complete', Callable(self, '_on_zoom_complete'))
signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind(nodes))
signaller.connect('bip_pressed', Callable(self, 'on_bip_pressed').bind(nodes))
signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel').bind(nodes))
signaller.connect('threat_selected', Callable(self, 'on_threat_selected').bind(nodes))
signaller.connect('interfer_selected', Callable(self, 'on_interfer_selected').bind(nodes))
signaller.connect('interfer_new', Callable(self, 'on_interfer_new'))
signaller.connect('interfer_off_all', Callable(self, 'on_interfer_off_all'))
signaller.connect('fs_selected', Callable(self, 'on_fs_selected'))
interfer.connect('interfer_update', Callable(self, 'on_interfer_new'))
var items_list = []
recurse(get_tree().get_root(), items_list)
print_debug(items_list)
func recurse(obj, items_list: Array):
var childrens = obj.get_children()
for ch in childrens:
items_list.append(ch)
recurse(ch, items_list)
func get_all_nodes(root):
var nodes = []
nodes.append(root)
for child in root.get_children():
nodes.append_array(get_all_nodes(child))
return nodes
func on_enter_tree() -> void:
call_deferred('_on_btn_scale_pressed')
call_deferred('on_button_strobe_pressed')
$tilemap.position = $canvas.get_strob_center()
## Производит отображение цели на диаграмму.
func map_threat_to_bip(th: threats.Threat, bip: Control):
bip.position = tools.pos_calc(
th.freq,
th.aoa,
radius_center,
radius_internal,
radius_outter,
freq_low,
freq_high) - bip.size / 2
## Обработчик сигнала обновления цели.
func on_threat_update(th):
var bip = get_node('%d' % th.id)
map_threat_to_bip(th, bip)
## Обработчик выбора помехи для цели.
func on_interfer_new(ecm):
if interfer.thrs.has(ecm.ispp):
if interfer.thrs.has(ecm.ispp):
var th_id = interfer.thrs[ecm.ispp]
var bip = get_node('%d' % th_id)
if ecm.krp != interfer.INTERFER_OFF:
bip.set_track_visible(true)
if ecm.svk == 1:
bip.set_ecm_visible(true)
else: bip.set_ecm_visible(false)
else:
bip.set_ecm_visible(false)
bip.set_track_visible(false)
set_fs_color(ecm)
## Обработчик выключения всех помех.
func on_interfer_off_all():
var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
for bip in bips:
bip.set_ecm_visible(false)
bip.set_track_visible(false)
fs_active.clear()
update_fs_colors()
## Обработчик сигнала обнаружения цели.
func on_threat_new(th) -> void:
var bip = Bip.instantiate()
bip.name = '%d' % th.id
map_threat_to_bip(th, bip)
add_child(bip)
## Обработчик сигнала потери цели.
func on_threat_lost(th) -> void:
var bip = get_node('%d' % th.id)
remove_child(bip)
bip.free()
## обработчик нажатия на цель на экране.
func on_bip_pressed(th_id, _ecm_btns):
if btn_select == BtnSel.THREAT:
signaller.emit_signal('rto_threat_sel', th_id)
## Обработчик выбора РТО цели.
func on_rto_threat_sel(th_id, ecm_btns):
var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
for item in bips:
if th_id == item.name.to_int():
item.set_sel_visible(true)
unsel_fs_all(false)
else:
item.set_sel_visible(false)
for btn in ecm_btns:
set_btns_disabled(false, btn)
## Обработчик снятия выбора РТО цели.
func on_rto_threat_unsel(th_id, _ecm_btns):
var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
for item in bips:
if th_id == item.name.to_int():
item.set_sel_visible(false)
break
set_ecm_btns_state(true)
## Обработчик нажатия кнопки "Строб". Управляет отображением строба.
func on_button_strobe_pressed() -> void:
drag_fsm = DragFSM.IDLE if $btns_select/btn_strob.is_pressed() else DragFSM.OFF
$canvas.set_strob_visible(drag_fsm == DragFSM.IDLE)
## Поведение радиокнопок в группе. Управляет состоянием кнопок выбора целей.
func on_button_select(btn_this, btn_others) -> void:
for btn_other in btn_others: btn_other.set_pressed(btn_this == btn_other)
btn_select = btn_this.get_meta('state')
on_button_strobe_pressed()
signaller.emit_signal('rto_threat_unsel_all')
unsel_fs_all(true)
set_ecm_btns_state(true)
## Поведение радиокнопок в группе. Управляет состоянием кнопок в радиогруппе.
func on_button_pressed(btn_this, btn_others) -> void:
var fs_arr: Array = []
for btn_other in btn_others: btn_other.set_pressed(btn_this == btn_other)
for key in fs_selected.keys():
fs_arr.append(get_fs_param(key))
signaller.emit_signal('interfer_init', btn_this, fs_arr)
## Управляет состоянием кнопок в радиогруппе при выборе помехи.
func on_interfer_selected(ecm, btns) -> void:
var ecm_name: String
if ecm != null:
ecm_name = ecm.krp
else:
ecm_name = interfer.INTERFER_OFF
for btn in btns:
set_btns_disabled(false, btn)
btn.get_meta('rfi_name')
if ecm_name == btn.get_meta('rfi_name'):
btn.set_pressed(true)
else:
btn.set_pressed(false)
## Возвращает ширину строба по направлению.
func get_strob_width(pos: Vector2, prev: float) -> float:
var strob_dir_width: float = prev + (drag_pos_begin.y - pos.y) * drag_scale_width
strob_dir_width = tools.clip_value(strob_dir_width, strob_min_width, strob_max_width)
return strob_dir_width
## Возвращает ширину строба по частоте.
func get_strob_band(pos: Vector2, prev: float) -> float:
var strob_dir_band: float = prev - (drag_pos_begin.y - pos.y) * drag_scale_band
strob_dir_band = tools.clip_value(strob_dir_band, strob_min_band, strob_max_band)
return strob_dir_band
## Устанавливает центр строба по частоте и направлению.
func set_strob(pos: Vector2) -> void:
var radp: Vector2 = tools.map_dec_to_rad(radius_center, pos)
if radp.y < $canvas.get_radius_outter():
$canvas.set_strob_dir(radp.x)
$canvas.set_strob_radius(radp.y)
## Обработка движения мыши для управления стробом. Вызывается во время движения мыши.
func _on_drag_continue(event) -> void:
if drag_button == MOUSE_BUTTON_RIGHT:
if shift_pressed:
var strob_width: float = get_strob_width(event.position, strob_width_begin)
$canvas.set_strob_width(strob_width)
else:
var strob_band: float = get_strob_band(event.position, strob_band_begin)
$canvas.set_strob_band(strob_band)
elif drag_button == MOUSE_BUTTON_LEFT:
set_strob(event.position)
## Обработка движения мыши для управления стробом. Вызывается при нажатии мыши.
func _on_drag_begin(event) -> void:
drag_pos_begin = event.position
if drag_button == MOUSE_BUTTON_LEFT:
set_strob(event.position)
elif drag_button == MOUSE_BUTTON_RIGHT:
strob_width_begin = $canvas.get_strob_width()
strob_band_begin = $canvas.get_strob_band()
## Обработчик событий ввода. Вызывается godot.
func _input(event) -> void:
if not is_visible_in_tree(): return
if event is InputEventMouseMotion:
if drag_fsm == DragFSM.DRAG:
emit_signal('drag_continue', event)
elif event is InputEventMouseButton:
drag_button = event.button_index
if event.pressed:
if drag_fsm == DragFSM.IDLE:
drag_fsm = DragFSM.DRAG
emit_signal('drag_begin', event)
else:
if btn_select == BtnSel.FS:
sel_fs_sector(event)
drag_fsm = DragFSM.IDLE
emit_signal('drag_end', event)
elif event is InputEventKey:
if event.physical_keycode == KEY_SHIFT:
shift_pressed = event.pressed
## Вызывается по нажатию кнопки "Детализация".
func _on_btn_scale_pressed() -> void:
var zoom = $btn_zoom.get_meta('zoom')
zoom = zoom + 1 if zoom < max_zoom else min_zoom
signaller.emit_signal('zoom_changed', zoom)
## Вызывается по завершению изменения детализации карты.
func _on_zoom_complete(zoom: int) -> void:
var prefix = $btn_zoom.get_meta('prefix')
$btn_zoom/lbl.text = '%s %d' % [prefix, zoom]
$btn_zoom.set_meta('zoom', zoom)
## Обработчик нажатия по сектору формирователя сигналов.
func sel_fs_sector(event):
if (event.button_index == MOUSE_BUTTON_LEFT) or (event.button_index == MOUSE_BUTTON_RIGHT):
var center: Vector2 = $tilemap.position
var center_offset: Vector2 = ProjectSettings.get_setting('application/interfer/center_offset', Vector2i(0, 25))
var angle: float = event.position.angle_to_point(center + center_offset) * 180/PI - 45.0
if angle < 0:
angle += 360
var distance: float = event.position.distance_to(center + center_offset)
var sector: int
var band: int
var has_band: bool = false
for sec in fs_sectors.values():
if angle >= sec[0] and angle <= sec[1]:
sector = fs_sectors.find_key(sec)
for diap in fs_band.values():
if distance >= diap[0] and distance <= diap[1]:
band = fs_band.find_key(diap)
has_band = true
if not has_band:
return
var fs_index = band * 4 + sector
if event.button_index == MOUSE_BUTTON_LEFT:
fs_selected[fs_index] = null
else:
fs_selected.erase(fs_index)
update_fs_colors()
signaller.emit_signal('rto_threat_unsel_all')
var btn_state = len(fs_selected) == 0
set_ecm_btns_state(btn_state)
func set_fs_color(ecm):
var fs_index = get_fs_index(ecm)
if ecm.krp != interfer.INTERFER_OFF:
fs_active[fs_index] = null
else:
fs_active.erase(fs_index)
update_fs_colors()
func update_fs_colors():
var fs_colors = $canvas.fs_default_colors.duplicate()
var color_ecm: Vector3 = ProjectSettings.get_setting('application/interfer/interfer_color', Vector3(0.58, 0.47, 0.51))
var color_select: Vector3 = ProjectSettings.get_setting('application/interfer/select_color', Vector3(1.0, 1.0, 1.0))
for key in fs_active.keys():
fs_colors[key] = color_ecm
for key in fs_selected.keys():
fs_colors[key] = color_select
$canvas.set_band_colors(fs_colors)
func unsel_fs_all(need_btns_off: bool):
fs_selected.clear()
update_fs_colors()
if need_btns_off:
set_ecm_btns_state(true)
func set_ecm_btns_state(value: bool):
var btns: Array = get_tree().get_nodes_in_group('группа-режим-помехи')
for btn in btns:
btn.set_pressed(false)
set_btns_disabled(value, btn)
func get_fs_param(index: int) -> Array:
var freq = (fs_freq[index / 4][0] + fs_freq[index / 4][1])/2
var sector = (fs_sectors[index % 4][0] + fs_sectors[index % 4][1])/2 - 45.0
if sector < 0:
sector += 360.0
var width = fs_freq[index / 4][1] - fs_freq[index / 4][0]
return [sector, freq, width, index]
func on_fs_selected(ecm):
var fs_index = get_fs_index(ecm)
fs_selected.clear()
fs_selected[fs_index] = null
update_fs_colors()
func get_fs_index(ecm):
var sector: int
var band: int
var angle: float = ecm.kni + 45.0
if angle > 360.0:
angle -= 360.0
for sec in fs_sectors.values():
if float(angle) >= sec[0] and float(angle) <= sec[1]:
sector = fs_sectors.find_key(sec)
for diap in fs_freq.values():
if ecm.params.has('freq'):
if ecm.params['freq'] >= diap[0] and ecm.params['freq'] <= diap[1]:
band = fs_freq.find_key(diap)
var fs_index = band * 4 + sector
return fs_index
func set_btns_disabled(value: bool, btn):
var external_cu = ProjectSettings.get_setting('application/config/external_cu', false)
if external_cu:
btn.set_pressed(false)
btn.set_disabled(true)
else:
btn.set_disabled(value)