From d826f8745c87b560247cc5e2075dc0dc440671f0 Mon Sep 17 00:00:00 2001 From: lepshiy Date: Thu, 25 Jul 2024 16:10:22 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0.=20=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/godot-logger/README.md | 2 +- addons/godot-logger/plugin.gd | 44 +- addons/godot-logger/scripts/logger.gd | 317 ++++--- addons/godot-logger/scripts/logger_output.gd | 89 +- project.godot | 23 + scenes/bip/bip.gd | 26 +- scenes/button-flat/nine-patch-button.gd | 66 +- scenes/cell/cell-front.gd | 4 +- scenes/diagram/diagram.gd | 30 +- scenes/frame-ecm-list/frm-ecm-list.gd | 12 +- scenes/frame-ecm-params/scroll-ecm-params.gd | 118 +-- scenes/frame-params/scroll-params.gd | 66 +- scenes/frame-threats/scroll-threats.gd | 112 +-- scenes/frame/frame.gd | 12 +- scenes/pribor-afsp/pribor-afsp.gd | 10 +- scenes/pribor-rtr/pribor-rtr.gd | 200 ++-- scenes/tabs-switch/tab-switch.gd | 6 +- scenes/tilemap/tilemap.gd | 267 +++--- scenes/tilemap/tilemap.tscn | 29 +- scenes/журнал/журнал.gd | 68 +- scenes/контроль/кассета.gd | 10 +- scenes/контроль/кнопка-прибора.gd | 8 +- scenes/контроль/контроль.gd | 76 +- scenes/контроль/прибор.gd | 18 +- scenes/настройки/настройки.gd | 24 +- scenes/работа/sld-mode.gd | 14 +- scenes/работа/работа.gd | 695 +++++++------- scenes/работа/работа.tscn | 31 +- scenes/эмс/кнопка-эмс.gd | 32 +- scenes/эмс/эмс.gd | 524 +++++------ scripts/capsrpb.gd | 80 +- scripts/file-table.gd | 54 +- scripts/hotkeys.gd | 22 +- scripts/interfer.gd | 414 ++++----- scripts/mercator.gd | 904 +++++++++---------- scripts/modbus.gd | 234 ++--- scripts/repnetwork.gd | 238 ++--- scripts/repsettings.gd | 69 +- scripts/signaller.gd | 42 +- scripts/tcp5p28.gd | 342 +++---- scripts/threats.gd | 188 ++-- scripts/tools.gd | 122 +-- scripts/yau07.gd | 404 ++++----- scripts/yems-boards.gd | 24 +- scripts/yems-consts.gd | 272 +++--- scripts/yems-devs.gd | 58 +- table/table.gd | 714 +++++++-------- 47 files changed, 3607 insertions(+), 3507 deletions(-) diff --git a/addons/godot-logger/README.md b/addons/godot-logger/README.md index 416382e0..0d6f5981 100644 --- a/addons/godot-logger/README.md +++ b/addons/godot-logger/README.md @@ -33,7 +33,7 @@ Log.fatal(text) const CUSTOM = Log.MAX << 1 # Bitwise left shift the MAX value for a custom level. func _ready() -> void: - Log.add_level(CUSTOM, "Level Name") + Log.add_level(CUSTOM, "Level Name") ``` ## Calling the custom level: diff --git a/addons/godot-logger/plugin.gd b/addons/godot-logger/plugin.gd index a6ff3f7f..116e5127 100644 --- a/addons/godot-logger/plugin.gd +++ b/addons/godot-logger/plugin.gd @@ -14,36 +14,36 @@ const LOGGER_OUTPUT_ICON = "res://addons/godot-logger/icons/logger.svg" func _def_settings(pname: String, default: Variant) -> void: - if not ProjectSettings.has_setting(pname): - ProjectSettings.set_setting(pname, default) + if not ProjectSettings.has_setting(pname): + ProjectSettings.set_setting(pname, default) - ProjectSettings.set_initial_value(pname, default) + ProjectSettings.set_initial_value(pname, default) func _enter_tree() -> void: - _def_settings("plugins/logger/log_enabled", true) - _def_settings("plugins/logger/default_output", false) + _def_settings("plugins/logger/log_enabled", true) + _def_settings("plugins/logger/default_output", false) - _def_settings("plugins/logger/level", 31) # The magic number is - INFO | DEBUG | WARNING | ERROR | FATAL - ProjectSettings.add_property_info( - { - "name": "plugins/logger/level", - "type": TYPE_INT, - "hint": PROPERTY_HINT_FLAGS, - "hint_string": "Info,Debug,Warning,Error,Fatal", - } - ) + _def_settings("plugins/logger/level", 31) # The magic number is - INFO | DEBUG | WARNING | ERROR | FATAL + ProjectSettings.add_property_info( + { + "name": "plugins/logger/level", + "type": TYPE_INT, + "hint": PROPERTY_HINT_FLAGS, + "hint_string": "Info,Debug,Warning,Error,Fatal", + } + ) - _def_settings("plugins/logger/file/file_path", "user://uarep-ctl.log") - _def_settings("plugins/logger/file/log_file_write", true) + _def_settings("plugins/logger/file/file_path", "user://uarep-ctl.log") + _def_settings("plugins/logger/file/log_file_write", true) - _def_settings("plugins/logger/default_output_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}") - _def_settings("plugins/logger/file_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}") + _def_settings("plugins/logger/default_output_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}") + _def_settings("plugins/logger/file_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}") - add_autoload_singleton(AUTOLOAD_NAME, AUTOLOAD_PATH) - add_custom_type(LOGGER_OUTPUT, "RichTextLabel", load(LOGGER_OUTPUT_SCRIPT), load(LOGGER_OUTPUT_ICON)) + add_autoload_singleton(AUTOLOAD_NAME, AUTOLOAD_PATH) + add_custom_type(LOGGER_OUTPUT, "RichTextLabel", load(LOGGER_OUTPUT_SCRIPT), load(LOGGER_OUTPUT_ICON)) func _exit_tree() -> void: - remove_custom_type(LOGGER_OUTPUT) - remove_autoload_singleton(AUTOLOAD_NAME) + remove_custom_type(LOGGER_OUTPUT) + remove_autoload_singleton(AUTOLOAD_NAME) diff --git a/addons/godot-logger/scripts/logger.gd b/addons/godot-logger/scripts/logger.gd index 1648f794..2f1ba8f6 100644 --- a/addons/godot-logger/scripts/logger.gd +++ b/addons/godot-logger/scripts/logger.gd @@ -1,21 +1,20 @@ # Copyright (c) 2020-2023 Mansur Isaev and contributors - MIT License # See `LICENSE.md` included in the source distribution for details. -## Logger class. -class_name Logger -extends Node +## Класс журнал событий. +class_name Logger extends Node -## Emitted when the logger create a message. +## Выдается, когда журнал событий создаёт сообщение. signal logged(message: Dictionary) enum { - INFO = 1, ## Info level. - DEBUG = 1<<1, ## Warning level. - WARNING = 1<<2, ## Debug level. - ERROR = 1<<3, ## Error level. - FATAL = 1<<4, ## Fatal level. - MAX = FATAL, ## Bitwise left shift for custom levels. + INFO = 1, ## Информационный уровень. + DEBUG = 1<<1, ## Уровень предупреждения. + WARNING = 1<<2, ## Уровень отладки. + ERROR = 1<<3, ## Уровень ошибок. + FATAL = 1<<4, ## Критический уровень. + MAX = FATAL, ## Побитовый сдвиг влево для пользовательских уровней. } @@ -32,235 +31,235 @@ var _format_default_output : String var _format_file : String var _names = { - INFO: "ИНФО", - DEBUG: "ОТЛАДКА", - WARNING: "ВНИМАНИЕ", - ERROR: "ОШИБКА", - FATAL: "АВАРИЯ" + INFO: "ИНФО", + DEBUG: "ОТЛАДКА", + WARNING: "ВНИМАНИЕ", + ERROR: "ОШИБКА", + FATAL: "АВАРИЯ" } var _msg_array: Array var _filters: Array -# Can be overridden to define custom default values. +## Преопределение пользовательских значений по умолчанию. func _enter_tree() -> void: - set_log_enabled(ProjectSettings.get_setting("plugins/logger/log_enabled", true)) - set_default_output_enabled(ProjectSettings.get_setting("plugins/logger/default_output", false)) + set_log_enabled(ProjectSettings.get_setting("plugins/logger/log_enabled", true)) + set_default_output_enabled(ProjectSettings.get_setting("plugins/logger/default_output", false)) - _level = ProjectSettings.get_setting("plugins/logger/level", INFO | DEBUG | WARNING | ERROR | FATAL) + _level = ProjectSettings.get_setting("plugins/logger/level", INFO | DEBUG | WARNING | ERROR | FATAL) - set_file_path(ProjectSettings.get_setting("plugins/logger/file/file_path", "user://uarep-ctl.log")) - set_file_write_enabled(ProjectSettings.get_setting("plugins/logger/file/log_file_write", true)) + set_file_path(ProjectSettings.get_setting("plugins/logger/file/file_path", "user://uarep-ctl.log")) + set_file_write_enabled(ProjectSettings.get_setting("plugins/logger/file/log_file_write", true)) - _format_default_output = ProjectSettings.get_setting("plugins/logger/default_output_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}") - _format_file = ProjectSettings.get_setting("plugins/logger/file_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}") + _format_default_output = ProjectSettings.get_setting("plugins/logger/default_output_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}") + _format_file = ProjectSettings.get_setting("plugins/logger/file_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}") func _exit_tree() -> void: - _close_file() + _close_file() -## Return [param true] if logger has level. +## Возвращает [param true], если у журнала события есть уровень. func has_level(level: int) -> bool: - return _names.has(level) + return _names.has(level) -## Set the level enabled. +## Установить включенный уровень. func set_level(level: int, enabled: bool) -> void: - assert(has_level(level), "Invalid level.") - if not has_level(level): - return + assert(has_level(level), "Invalid level.") + if not has_level(level): + return - if enabled: - _level |= level - else: - _level &= ~level + if enabled: + _level |= level + else: + _level &= ~level -## Add a custom log level. The level value must be unique and be greater than [member MAX]. -## To call the custom level use [method message] method. +## Добавить пользовательский уровень журнала. Значение уровня должно быть уникальным и превышать [member MAX]. +## Для вызова пользовательского уровня используйте метод - [method message]. func add_level(level: int, nm: String) -> void: - assert(not has_level(level), "Has level.") - assert(level > MAX and not level % 2, "Invalid level.") - assert(name, "Invalid name.") + assert(not has_level(level), "Has level.") + assert(level > MAX and not level % 2, "Invalid level.") + assert(name, "Invalid name.") - if not has_level(level) and level > MAX and not level % MAX and not name.is_empty(): - _names[level] = nm - set_level(level, true) + if not has_level(level) and level > MAX and not level % MAX and not name.is_empty(): + _names[level] = nm + set_level(level, true) -## Return the level name. +## Возвращает имя уровня. func get_level_name(level: int) -> String: - return _names[level] + return _names[level] -## Set Log enabled. Disable ALL messages. +## Установить включенный журнал. Отключить ВСЕ сообщения. func set_log_enabled(enabled: bool) -> void: - _log_enabled = enabled + _log_enabled = enabled -## Return [param true] if Log enabled. +## Возвращает [param true], если журнал включен. func is_log_enabled() -> bool: - return _log_enabled + return _log_enabled -## Set default output enabled. +## Установка выхода по умолчанию включена. func set_default_output_enabled(enabled: bool) -> void: - _default_output_enabled = enabled + _default_output_enabled = enabled -## Returns [param true] if default output is enabled. +## Возвращает [param true], если вывод по умолчанию включен. func is_default_output_enabled() -> bool: - return _default_output_enabled + return _default_output_enabled -## Set file write enabled. +## Установить разрешение на запись файла. func set_file_write_enabled(enabled: bool) -> void: - if _file_write_enabled == enabled: - return + if _file_write_enabled == enabled: + return - _file_write_enabled = enabled + _file_write_enabled = enabled - if enabled: - _open_file() - else: - _close_file() + if enabled: + _open_file() + else: + _close_file() -## Returns [param true] if write to a file is enabled. +## Возвращает [param true], если запись в файл разрешена. func is_file_write_enabled() -> bool: - return _file_write_enabled + return _file_write_enabled -## Set the path to the log file. +## Задать путь к файлу журнала. func set_file_path(path: String) -> void: - assert(path.is_absolute_path(), "Invalid path.") - if not path.is_absolute_path() or _file_path == path: - return + assert(path.is_absolute_path(), "Invalid path.") + if not path.is_absolute_path() or _file_path == path: + return - _file_path = path + _file_path = path - if is_file_write_enabled(): - _open_file() + if is_file_write_enabled(): + _open_file() -## Return path to log file. +## Возвращает путь к файлу журнала. func get_file_path() -> String: - return _file_path + return _file_path -## Create an info message. +## Создать информационное сообщение. func info(text: String) -> void: - message(INFO, text) + message(INFO, text) -## Create a debug message. Debug build only. +## Создать отладочное сообщение. Только для отладочной сборки. func debug(text: String) -> void: - if OS.is_debug_build(): - message(DEBUG, text) + if OS.is_debug_build(): + message(DEBUG, text) -## Create a warning message. +## Создать предупреждающее сообщение. func warning(text: String) -> void: - message(WARNING, text) + message(WARNING, text) -## Create an error message. +## Создать сообщение об ошибке. func error(text: String) -> void: - message(ERROR, text) + message(ERROR, text) -## Create a fatal error message. +## Создать сообщение о критической ошибке. func fatal(text: String) -> void: - message(FATAL, text) + message(FATAL, text) -## Format string for log file. +## Форматировать строку для файла. func format_file(msg: Dictionary) -> String: - return _format_file.format( - { - "year": "%02d" % msg["year"], - "month": "%02d" % msg["month"], - "day": "%02d" % msg["day"], - "hour": "%02d" % msg["hour"], - "minute":"%02d" % msg["minute"], - "second":"%02d" % msg["second"], - "level": _names[msg["level"]], - "text": msg["text"], - } - ) + return _format_file.format( + { + "year": "%02d" % msg["year"], + "month": "%02d" % msg["month"], + "day": "%02d" % msg["day"], + "hour": "%02d" % msg["hour"], + "minute":"%02d" % msg["minute"], + "second":"%02d" % msg["second"], + "level": _names[msg["level"]], + "text": msg["text"], + } + ) -## Format string for editor output. +## Форматировать строку для вывода редактора. func format_stdout(msg: Dictionary) -> String: - return _format_default_output.format( - { - "year": "%02d" % msg["year"], - "month": "%02d" % msg["month"], - "day": "%02d" % msg["day"], - "hour": "%02d" % msg["hour"], - "minute":"%02d" % msg["minute"], - "second":"%02d" % msg["second"], - "level": _names[msg["level"]], - "text": msg["text"], - } - ) + return _format_default_output.format( + { + "year": "%02d" % msg["year"], + "month": "%02d" % msg["month"], + "day": "%02d" % msg["day"], + "hour": "%02d" % msg["hour"], + "minute":"%02d" % msg["minute"], + "second":"%02d" % msg["second"], + "level": _names[msg["level"]], + "text": msg["text"], + } + ) -## Create a message with a custom level. +## Создать сообщение с пользовательским уровнем. func message(level: int, text: String) -> void: - assert(has_level(level), "Has not level.") - assert(text, "Invalid message text.") + assert(has_level(level), "Has not level.") + assert(text, "Invalid message text.") - if _log_enabled and _level & level: - var msg : Dictionary = Time.get_datetime_dict_from_system() - msg["level"] = level - msg["level_name"] = _names[level] - msg["text"] = " " + text + if _log_enabled and _level & level: + var msg : Dictionary = Time.get_datetime_dict_from_system() + msg["level"] = level + msg["level_name"] = _names[level] + msg["text"] = " " + text - _msg_array.append(msg) - if (_flt_msg(msg)): - logged.emit(msg) + _msg_array.append(msg) + if (_flt_msg(msg)): + logged.emit(msg) - if _file_write_enabled: - _file.store_line(format_file(msg)) - _file.call_deferred('flush') + if _file_write_enabled: + _file.store_line(format_file(msg)) + _file.call_deferred('flush') - if _default_output_enabled: - print(format_stdout(msg)) + if _default_output_enabled: + print(format_stdout(msg)) func _open_file() -> void: - if is_instance_valid(_file) and _file.is_open(): - _file.close() + if is_instance_valid(_file) and _file.is_open(): + _file.close() - _file = FileAccess.open(get_file_path(), FileAccess.READ_WRITE) + _file = FileAccess.open(get_file_path(), FileAccess.READ_WRITE) - var err := FileAccess.get_open_error() - if err: - _file = FileAccess.open(get_file_path(), FileAccess.WRITE) - _file.close() - _file = FileAccess.open(get_file_path(), FileAccess.READ_WRITE) - return print_debug(error_string(err)) + var err := FileAccess.get_open_error() + if err: + _file = FileAccess.open(get_file_path(), FileAccess.WRITE) + _file.close() + _file = FileAccess.open(get_file_path(), FileAccess.READ_WRITE) + return print_debug(error_string(err)) - err = _file.get_error() - if err: - return print_debug(error_string(err)) - _file.seek_end(0) + err = _file.get_error() + if err: + return print_debug(error_string(err)) + _file.seek_end(0) func _close_file() -> void: - if is_instance_valid(_file) and _file.is_open(): - _file = null + if is_instance_valid(_file) and _file.is_open(): + _file = null func save_file(path): - var f = FileAccess.open(path, FileAccess.WRITE) - var err := FileAccess.get_open_error() - if err: - print_debug(error_string(err)) - var log_text = _file.get_as_text() - f.store_line(log_text) - f.close() + var f = FileAccess.open(path, FileAccess.WRITE) + var err := FileAccess.get_open_error() + if err: + print_debug(error_string(err)) + var log_text = _file.get_as_text() + f.store_line(log_text) + f.close() func set_filtrs(flt_array: Array): - _filters = flt_array + _filters = flt_array func _flt_msg(msg): - var flt_arr: Array = [] - for item in _filters: - if item.button_pressed: - flt_arr.append(item.get_meta('filter')) - if msg['text'].find(item.get_meta('filter')) != -1: - return true - if msg['level_name'] in flt_arr: - return true - return false + var flt_arr: Array = [] + for item in _filters: + if item.button_pressed: + flt_arr.append(item.get_meta('filter')) + if msg['text'].find(item.get_meta('filter')) != -1: + return true + if msg['level_name'] in flt_arr: + return true + return false func add_msgs(): - for msg in _msg_array: - if (_flt_msg(msg)): - logged.emit(msg) + for msg in _msg_array: + if (_flt_msg(msg)): + logged.emit(msg) diff --git a/addons/godot-logger/scripts/logger_output.gd b/addons/godot-logger/scripts/logger_output.gd index 539daac2..768248a8 100644 --- a/addons/godot-logger/scripts/logger_output.gd +++ b/addons/godot-logger/scripts/logger_output.gd @@ -2,21 +2,20 @@ # See `LICENSE.md` included in the source distribution for details. @tool -## LoggerOutput class. -class_name LoggerOutput -extends RichTextLabel +## Класс вывода журнала событий. +class_name LoggerOutput extends RichTextLabel -## Emited when handle [signal Logger.logged] signal. +## Выдаётся при ошибке сигнала - [signal Logger.logged]. signal handled() @export var format_text : String = "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}" @export var colors : Dictionary = { - Logger.INFO: Color.WHITE, - Logger.DEBUG: Color.GRAY, - Logger.WARNING: Color.YELLOW, - Logger.ERROR: Color.RED, - Logger.FATAL: Color.RED, + Logger.INFO: Color.WHITE, + Logger.DEBUG: Color.GRAY, + Logger.WARNING: Color.YELLOW, + Logger.ERROR: Color.RED, + Logger.FATAL: Color.RED, } @@ -24,55 +23,55 @@ var _logger : Logger func _enter_tree() -> void: - var logger := get_node_or_null("/root/log") as Logger - if is_instance_valid(logger): - set_logger(logger) + var logger := get_node_or_null("/root/log") as Logger + if is_instance_valid(logger): + set_logger(logger) func _exit_tree() -> void: - if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message): - _logger.logged.disconnect(handle_message) + if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message): + _logger.logged.disconnect(handle_message) -## Return the level color or [member Color.WHITE]. +## Вернуть цвет уровня или [member Color.WHITE]. func get_color(level: int) -> Color: - return colors.get(level, Color.WHITE) + return colors.get(level, Color.WHITE) -## Set the logger. +## Установить журнал событий. func set_logger(logger: Logger) -> void: - assert(is_instance_valid(logger), "Invalid Logger.") - if not is_instance_valid(logger) or is_same(_logger, logger): - return + assert(is_instance_valid(logger), "Invalid Logger.") + if not is_instance_valid(logger) or is_same(_logger, logger): + return - if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message): - _logger.logged.disconnect(handle_message) + if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message): + _logger.logged.disconnect(handle_message) - if not logger.logged.is_connected(handle_message): - logger.logged.connect(handle_message) + if not logger.logged.is_connected(handle_message): + logger.logged.connect(handle_message) - _logger = logger + _logger = logger -## Return the logger. +## Вернуть журнал событий. func get_logger() -> Logger: - return _logger + return _logger -## Return formatted string from message. +## Вернуть строку после форматирования из сообщения. func format(message: Dictionary) -> String: - return format_text.format( - { - "year": "%02d" % message["year"], - "month": "%02d" % message["month"], - "day": "%02d" % message["day"], - "hour": "%02d" % message["hour"], - "minute": "%02d" % message["minute"], - "second": "%02d" % message["second"], - "level": message["level_name"], - "text": message["text"], - } - ) + return format_text.format( + { + "year": "%02d" % message["year"], + "month": "%02d" % message["month"], + "day": "%02d" % message["day"], + "hour": "%02d" % message["hour"], + "minute": "%02d" % message["minute"], + "second": "%02d" % message["second"], + "level": message["level_name"], + "text": message["text"], + } + ) -## Handle the message. +## Обработать сообщение. func handle_message(message: Dictionary) -> void: - push_color(get_color(message["level"])) - append_text(format(message) + "\n") - pop() - handled.emit() + push_color(get_color(message["level"])) + append_text(format(message) + "\n") + pop() + handled.emit() diff --git a/project.godot b/project.godot index c198b867..77b0bbbe 100644 --- a/project.godot +++ b/project.godot @@ -111,6 +111,29 @@ theme/default_font_subpixel_positioning=3 theme/lcd_subpixel_layout=0 common/drop_mouse_on_gui_input_disabled=true +[input] + +up={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null) +] +} +down={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"echo":false,"script":null) +] +} +left={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"echo":false,"script":null) +] +} +right={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null) +] +} + [input_devices] buffering/agile_event_flushing=true diff --git a/scenes/bip/bip.gd b/scenes/bip/bip.gd index ae49b23f..f3c5a29b 100644 --- a/scenes/bip/bip.gd +++ b/scenes/bip/bip.gd @@ -1,25 +1,25 @@ -extends Control +class_name bip_ extends Control var selected: bool -# Функция присваивает заданое значение видимости селектору +## Функция присваивает заданое значение видимости селектору. func set_sel_visible(value: bool): - selected = value - $selector.visible = value + selected = value + $selector.visible = value -# Функция присваивает заданое значение видимости селектору +## Функция присваивает заданое значение видимости селектору. func set_track_visible(value: bool): $track.visible = value -# Функция присваивает заданое значение видимости индикатору выполнения +## Функция присваивает заданое значение видимости индикатору выполнения. func set_ecm_visible(value: bool): $ecm_done.visible = value func _on_bip_gui_input(event): - if event is InputEventMouseButton and event.pressed: - match event.button_index: - MOUSE_BUTTON_LEFT: - signaller.emit_signal('bip_pressed', name.to_int()) - MOUSE_BUTTON_RIGHT: - if selected: - signaller.emit_signal('rto_threat_unsel', name.to_int()) + if event is InputEventMouseButton and event.pressed: + match event.button_index: + MOUSE_BUTTON_LEFT: + signaller.emit_signal('bip_pressed', name.to_int()) + MOUSE_BUTTON_RIGHT: + if selected: + signaller.emit_signal('rto_threat_unsel', name.to_int()) diff --git a/scenes/button-flat/nine-patch-button.gd b/scenes/button-flat/nine-patch-button.gd index 67189a3b..977151a4 100644 --- a/scenes/button-flat/nine-patch-button.gd +++ b/scenes/button-flat/nine-patch-button.gd @@ -12,66 +12,66 @@ func is_toggle_mode(): return $button.is_toggle_mode() @export var texture_state0: Texture2D = preload('res://data/кнопка-квадрат-0.png'): - set(val): $state.set_texture(val) + set(val): $state.set_texture(val) @export var texture_state1: Texture2D = preload('res://data/кнопка-квадрат-1.png'): - set(val): $state.set_texture(val) + set(val): $state.set_texture(val) @export var strips_rotation: float = 0.0: - set(val): - strips_rotation = val - $back.strips_rotation = deg_to_rad(val) - get: return strips_rotation + set(val): + strips_rotation = val + $back.strips_rotation = deg_to_rad(val) + get: return strips_rotation @export var text: String = '': - set(val): $button.set_text(val) - get: return $button.get_text() + set(val): $button.set_text(val) + get: return $button.get_text() @export var disabled: bool = false: - set(val): - disabled = val - $button.set_disabled(val) - $back.disabled = val - $state.modulate.a = 0.5 if val else 1.0 - get: return disabled + set(val): + disabled = val + $button.set_disabled(val) + $back.disabled = val + $state.modulate.a = 0.5 if val else 1.0 + get: return disabled @export var pressed: bool = false: - set(val): - pressed = val - $button.set_pressed(val) - get: - return pressed + set(val): + pressed = val + $button.set_pressed(val) + get: + return pressed @export var toggle_mode: bool = false: - set(val): - toggle_mode = val - $button.set_toggle_mode(val) - get: - return toggle_mode + set(val): + toggle_mode = val + $button.set_toggle_mode(val) + get: + return toggle_mode func _on_resized() -> void: - $back.scale = size - $back.material.set('shader_parameter/scale', size / Vector2(20.0, 20.0)) + $back.scale = size + $back.material.set('shader_parameter/scale', size / Vector2(20.0, 20.0)) func _enter_tree() -> void: - $back.scale = size - $back.material.set('shader_parameter/scale', size / Vector2(20.0, 20.0)) - $button.set_toggle_mode(true) - $button.connect('toggled', Callable(self, '_on_button_toggled')) + $back.scale = size + $back.material.set('shader_parameter/scale', size / Vector2(20.0, 20.0)) + $button.set_toggle_mode(true) + $button.connect('toggled', Callable(self, '_on_button_toggled')) func set_toggle_mode(val: bool): - $button.set_toggle_mode(val) + $button.set_toggle_mode(val) func _on_button_toggled(val: bool): - if val: $state.set_texture(texture_state1) - else: $state.set_texture(texture_state0) + if val: $state.set_texture(texture_state1) + else: $state.set_texture(texture_state0) diff --git a/scenes/cell/cell-front.gd b/scenes/cell/cell-front.gd index 0623b7a9..f0382a2a 100644 --- a/scenes/cell/cell-front.gd +++ b/scenes/cell/cell-front.gd @@ -1,5 +1,5 @@ extends Control @export var text: String = '': - set(val): $label.set_text(val) - get: return $label.get_text() + set(val): $label.set_text(val) + get: return $label.get_text() diff --git a/scenes/diagram/diagram.gd b/scenes/diagram/diagram.gd index 968c90db..f6af816e 100644 --- a/scenes/diagram/diagram.gd +++ b/scenes/diagram/diagram.gd @@ -1,10 +1,10 @@ -extends Sprite2D +class_name Diagram extends Sprite2D -var fs_default_colors: Array # Цвета по умолчанию для блоков ФС +var fs_default_colors: Array ## Цвета по умолчанию для блоков ФС. func _ready() -> void: - signaller.connect('map_mode_changed', Callable(self, 'set_view_mode')) - set_def_colors() + signaller.connect('map_mode_changed', Callable(self, 'set_view_mode')) + set_def_colors() func sv(val: float) -> float: return val / ($строб.scale.x / 2.0) * 0.125 @@ -30,15 +30,15 @@ func get_radius_inner_1() -> float: return material.get('shader_parameter/radiu func set_view_mode(val: int): material.set('shader_parameter/mode', val); func set_band_colors(val: Array): material.set('shader_parameter/ant_band_c', val) -## Закрашивание по умолчанию блоков ФС цветами из настроек +## Закрашивание по умолчанию блоков ФС цветами из настроек. func set_def_colors(): - var color0: Vector3 = ProjectSettings.get_setting('application/interfer/default_color0', Vector3(0.38, 0.47, 0.51)) - var color1: Vector3 = ProjectSettings.get_setting('application/interfer/default_color1', Vector3(0.39, 0.44, 0.50)) - var col_arr: Array = [color0, color1] - var col = false - for i in range(7): - for j in range (4): - fs_default_colors.append(col_arr[int(col)]) - col = not col - col = not col - set_band_colors(fs_default_colors) + var color0: Vector3 = ProjectSettings.get_setting('application/interfer/default_color0', Vector3(0.38, 0.47, 0.51)) + var color1: Vector3 = ProjectSettings.get_setting('application/interfer/default_color1', Vector3(0.39, 0.44, 0.50)) + var col_arr: Array = [color0, color1] + var col = false + for i in range(7): + for j in range (4): + fs_default_colors.append(col_arr[int(col)]) + col = not col + col = not col + set_band_colors(fs_default_colors) diff --git a/scenes/frame-ecm-list/frm-ecm-list.gd b/scenes/frame-ecm-list/frm-ecm-list.gd index c08ba4a9..c64bfce8 100644 --- a/scenes/frame-ecm-list/frm-ecm-list.gd +++ b/scenes/frame-ecm-list/frm-ecm-list.gd @@ -1,12 +1,12 @@ -extends NinePatchRect +class_name frm_ecm_list extends NinePatchRect -# Called when the node enters the scene tree for the first time. +## Called when the node enters the scene tree for the first time. func _ready(): - $grd_forced/btn_cancel.button_connect('pressed', Callable(self, 'on_btn_cancel_pressed').bind($grd_forced/btn_cancel)) + $grd_forced/btn_cancel.button_connect('pressed', Callable(self, 'on_btn_cancel_pressed').bind($grd_forced/btn_cancel)) func on_btn_cancel_pressed(btn): - signaller.emit_signal('interfer_off_all') - await get_tree().create_timer(0.1).timeout - btn.pressed = false + signaller.emit_signal('interfer_off_all') + await get_tree().create_timer(0.1).timeout + btn.pressed = false diff --git a/scenes/frame-ecm-params/scroll-ecm-params.gd b/scenes/frame-ecm-params/scroll-ecm-params.gd index f65b8635..2b8294a6 100644 --- a/scenes/frame-ecm-params/scroll-ecm-params.gd +++ b/scenes/frame-ecm-params/scroll-ecm-params.gd @@ -1,4 +1,4 @@ -extends ScrollContainer +class_name scroll_ecm_params extends ScrollContainer ## Отображает список параметров помехи в таблице. @@ -11,82 +11,82 @@ const TABLE_HEADERS_TEXT = ['Параметр', 'Значение' ] ## const TABLE_COLUMN_SIZE = [ 370, 85 ] ## Ширины колонок. const TABLE_PARAMS = { - 'kni': [0, 'Курсовой угол, гр.', false, 0.0, 360.0], - 'powp': [1, 'Мощность, %', true, 0.0, 100.0], - 'freq': [2, 'Частота, МГц', true, 400.0, 6000.0], - 'width': [3, 'Занимая полоса частот, МГц', true, 0.0, 120.0], - 'dur': [4, 'Длительность импульса, мкс', true, 0.0, 1000000.0], - 'period': [5, 'Период повтора, мкс', true, 0.0, 1000000.0] } + 'kni': [0, 'Курсовой угол, гр.', false, 0.0, 360.0], + 'powp': [1, 'Мощность, %', true, 0.0, 100.0], + 'freq': [2, 'Частота, МГц', true, 400.0, 6000.0], + 'width': [3, 'Занимая полоса частот, МГц', true, 0.0, 120.0], + 'dur': [4, 'Длительность импульса, мкс', true, 0.0, 1000000.0], + 'period': [5, 'Период повтора, мкс', true, 0.0, 1000000.0] } func init_table(): - for i in TABLE_PARAMS.size(): $table.add_row(TABLE_ROW) - for key in TABLE_PARAMS.keys(): - var p = TABLE_PARAMS[key] - $table.set_node_text(0, p[0], p[1]) - $table.set_node_alligment(0, p[0], HORIZONTAL_ALIGNMENT_LEFT) - $table.set_node_editable(0, p[0], false) - $table.set_node_editable(1, p[0], false) - $table.set_node_user_data(1, p[0], key) - $table.connect_columns(self, 'text_submitted', 'on_edit_entry', [1], []) - $table.set_columns_min_size(TABLE_COLUMN_SIZE) - $table.set_meta('id', 0) + for i in TABLE_PARAMS.size(): $table.add_row(TABLE_ROW) + for key in TABLE_PARAMS.keys(): + var p = TABLE_PARAMS[key] + $table.set_node_text(0, p[0], p[1]) + $table.set_node_alligment(0, p[0], HORIZONTAL_ALIGNMENT_LEFT) + $table.set_node_editable(0, p[0], false) + $table.set_node_editable(1, p[0], false) + $table.set_node_user_data(1, p[0], key) + $table.connect_columns(self, 'text_submitted', 'on_edit_entry', [1], []) + $table.set_columns_min_size(TABLE_COLUMN_SIZE) + $table.set_meta('id', 0) -# Called when the node enters the scene tree for the first time. +## Called when the node enters the scene tree for the first time. func _ready(): - signaller.connect('interfer_selected', Callable(self, 'on_interfer_selected')) - signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel')) - call_deferred('init_table') + signaller.connect('interfer_selected', Callable(self, 'on_interfer_selected')) + signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel')) + call_deferred('init_table') func on_edit_entry(text : String, entry): - var ecm = $table.get_meta('ecm') - if $table.has_meta('ecm') == false: return - var indexis = $table.get_key_indexes(entry[0].name) - var row_i = indexis[1] - var param = $table.get_node_user_data(1, row_i) - var p = TABLE_PARAMS[param] - var old_val = ecm.get_value(param) - var val = check_value(text, p[3], p[4], old_val) - ecm.set_value(val, param) - signaller.emit_signal('interfer_new', ecm) + var ecm = $table.get_meta('ecm') + if $table.has_meta('ecm') == false: return + var indexis = $table.get_key_indexes(entry[0].name) + var row_i = indexis[1] + var param = $table.get_node_user_data(1, row_i) + var p = TABLE_PARAMS[param] + var old_val = ecm.get_value(param) + var val = check_value(text, p[3], p[4], old_val) + ecm.set_value(val, param) + signaller.emit_signal('interfer_new', ecm) func check_value(val, min_val, max_val, old_val): - if val.is_valid_float(): - if float(val) < min_val: return min_val - if float(val) > max_val: return max_val - return float(val) - else: return old_val + if val.is_valid_float(): + if float(val) < min_val: return min_val + if float(val) > max_val: return max_val + return float(val) + else: return old_val func on_interfer_selected(ecm): - if ecm != null: - $table.set_meta('ecm', ecm) - else: - $table.set_meta('ecm', null) - on_ecm_update() + if ecm != null: + $table.set_meta('ecm', ecm) + else: + $table.set_meta('ecm', null) + on_ecm_update() func on_ecm_update(): - for item in len(TABLE_PARAMS): - $table.set_node_text(1, item, '') - $table.set_node_editable(1, item, false) - if $table.has_meta('ecm') == false: return - var ecm: interfer.Interfer = $table.get_meta('ecm') - var mnms = tools.get_members_names(ecm) - for item in ecm['params'].keys(): - mnms.append(item) - for member_name in mnms: - if not TABLE_PARAMS.has(member_name): continue - var p = TABLE_PARAMS[member_name] - var val = ecm.get_value(member_name) - $table.set_node_text(1, p[0], '%s' % val) - $table.set_node_editable(1, p[0], p[2]) + for item in len(TABLE_PARAMS): + $table.set_node_text(1, item, '') + $table.set_node_editable(1, item, false) + if $table.has_meta('ecm') == false: return + var ecm: interfer.Interfer = $table.get_meta('ecm') + var mnms = tools.get_members_names(ecm) + for item in ecm['params'].keys(): + mnms.append(item) + for member_name in mnms: + if not TABLE_PARAMS.has(member_name): continue + var p = TABLE_PARAMS[member_name] + var val = ecm.get_value(member_name) + $table.set_node_text(1, p[0], '%s' % val) + $table.set_node_editable(1, p[0], p[2]) func on_rto_threat_unsel(_th_id): - for item in range(len(TABLE_PARAMS)): - $table.set_node_text(1, item, '') - $table.set_node_editable(1, item, false) + for item in range(len(TABLE_PARAMS)): + $table.set_node_text(1, item, '') + $table.set_node_editable(1, item, false) diff --git a/scenes/frame-params/scroll-params.gd b/scenes/frame-params/scroll-params.gd index 45a6ce07..5a7c689a 100644 --- a/scenes/frame-params/scroll-params.gd +++ b/scenes/frame-params/scroll-params.gd @@ -1,6 +1,6 @@ -extends ScrollContainer +class_name scroll_params extends ScrollContainer -## Отображение параметров цели +## Отображение параметров цели. const CellLineEdit = preload('res://table/ячейка-2.tscn') ## Ячейка таблицы. const TableHeader = preload('res://table/header.tscn') ## Ячейка заголовок таблицы. @@ -15,51 +15,51 @@ const TABLE_COLUMN_SIZE = [ 370, 85 ] ## Ширины к ## Параметры цели для отображения в таблице.[br] ## [b]val[0][/b] - Индекс строки.[br][b]val[1][/b] - Содержание. const TABLE_PARAMS = { - 'baud': [0, 'Модуляционная скорость, бод'], - 'freqm': [1, 'Режим смены частоты.'], - 'power': [2, 'Уровень сигнала, дБм.'], - 'tmod': [3, 'Тип модуляции'], - 'width': [4, 'Занимая полоса частот, МГц.'], - 'rkrp': [5, 'Рекомендуемая помеха'] } + 'baud': [0, 'Модуляционная скорость, бод'], + 'freqm': [1, 'Режим смены частоты.'], + 'power': [2, 'Уровень сигнала, дБм.'], + 'tmod': [3, 'Тип модуляции'], + 'width': [4, 'Занимая полоса частот, МГц.'], + 'rkrp': [5, 'Рекомендуемая помеха'] } -## Обрабатывает сигнал [signal threats.threat_selected] +## Обрабатывает сигнал [signal threats.threat_selected]. func on_threat_selected(th): - $table.set_meta('id', th.id) - on_threat_update(th) + $table.set_meta('id', th.id) + on_threat_update(th) func init_table(): - for i in TABLE_PARAMS.size(): $table.add_row(TABLE_ROW) - for p in TABLE_PARAMS.values(): - $table.set_node_text(0, p[0], p[1]) - $table.set_node_alligment(0, p[0], HORIZONTAL_ALIGNMENT_LEFT) - $table.set_node_editable(0, p[0], false) - $table.set_node_editable(1, p[0], false) - $table.set_columns_min_size(TABLE_COLUMN_SIZE) - $table.set_meta('id', 0) + for i in TABLE_PARAMS.size(): $table.add_row(TABLE_ROW) + for p in TABLE_PARAMS.values(): + $table.set_node_text(0, p[0], p[1]) + $table.set_node_alligment(0, p[0], HORIZONTAL_ALIGNMENT_LEFT) + $table.set_node_editable(0, p[0], false) + $table.set_node_editable(1, p[0], false) + $table.set_columns_min_size(TABLE_COLUMN_SIZE) + $table.set_meta('id', 0) func _ready() -> void: - signaller.connect('threat_selected', Callable(self, 'on_threat_selected')) - signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel')) - threats.connect('threat_update', Callable(self, 'on_threat_update')) - call_deferred('init_table') + signaller.connect('threat_selected', Callable(self, 'on_threat_selected')) + signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel')) + threats.connect('threat_update', Callable(self, 'on_threat_update')) + call_deferred('init_table') ## Обрабатывает сигнал [signal threats.threat_update]. ## Обновляет отображение только для выбранной цели. func on_threat_update(th): - if th.selected == false: return - if th.id != $table.get_meta('id'): return - var mnms = tools.get_members_names(th) - for member_name in mnms: - if not TABLE_PARAMS.has(member_name): continue - var p = TABLE_PARAMS[member_name] - var val = th.get(member_name) - $table.set_node_text(1, p[0], '%s' % val) + if th.selected == false: return + if th.id != $table.get_meta('id'): return + var mnms = tools.get_members_names(th) + for member_name in mnms: + if not TABLE_PARAMS.has(member_name): continue + var p = TABLE_PARAMS[member_name] + var val = th.get(member_name) + $table.set_node_text(1, p[0], '%s' % val) func on_rto_threat_unsel(_th_id): - for item in range(len(TABLE_PARAMS)): - $table.set_node_text(1, item, '') + for item in range(len(TABLE_PARAMS)): + $table.set_node_text(1, item, '') diff --git a/scenes/frame-threats/scroll-threats.gd b/scenes/frame-threats/scroll-threats.gd index 3438a731..ea5136ba 100644 --- a/scenes/frame-threats/scroll-threats.gd +++ b/scenes/frame-threats/scroll-threats.gd @@ -1,4 +1,4 @@ -extends ScrollContainer +class_name scroll_threats extends ScrollContainer ## Отображает список целей в таблице. @@ -16,89 +16,89 @@ const TABLE_COLUMN_SIZE = [ 65, 145, 145, 90 ] ## Вызывается при нажатии указателем мыши на выбранный ряд. func on_row_pressed(i_row: int): - row_pressed(i_row) - signaller.emit_signal('rto_threat_sel', $table.get_node_user_data(0, i_row).id) + row_pressed(i_row) + signaller.emit_signal('rto_threat_sel', $table.get_node_user_data(0, i_row).id) func row_pressed(i_row: int): - $table.clear_rows_selected() - $table.set_row_selected(i_row, true) - $table.ensure_row_visible(i_row) - var threat = $table.get_node_user_data(0, i_row) - signaller.emit_signal('threat_selected', threat) + $table.clear_rows_selected() + $table.set_row_selected(i_row, true) + $table.ensure_row_visible(i_row) + var threat = $table.get_node_user_data(0, i_row) + signaller.emit_signal('threat_selected', threat) func init_table(): - $table.set_header(TABLE_HEADER) - $table.set_header_text(TABLE_HEADERS_TEXT) - $table.set_columns_min_size(TABLE_COLUMN_SIZE) - $table.pin_header(self, get_parent()) + $table.set_header(TABLE_HEADER) + $table.set_header_text(TABLE_HEADERS_TEXT) + $table.set_columns_min_size(TABLE_COLUMN_SIZE) + $table.pin_header(self, get_parent()) func _ready() -> void: - var table_index: = Dictionary() - threats.connect('threat_new', Callable(self, 'on_threat_new').bind(table_index)) - threats.connect('threat_lost', Callable(self, 'on_threat_lost').bind(table_index)) - threats.connect('threat_update', Callable(self, 'on_threat_update').bind(table_index)) - signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind($table)) - signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel')) - $table.connect('row_pressed', Callable(self, 'on_row_pressed')) - call_deferred('init_table') + var table_index: = Dictionary() + threats.connect('threat_new', Callable(self, 'on_threat_new').bind(table_index)) + threats.connect('threat_lost', Callable(self, 'on_threat_lost').bind(table_index)) + threats.connect('threat_update', Callable(self, 'on_threat_update').bind(table_index)) + signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind($table)) + signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel')) + $table.connect('row_pressed', Callable(self, 'on_row_pressed')) + call_deferred('init_table') -## Перестраивает индекс таблицы. Вызывать при удалении строки +## Перестраивает индекс таблицы. Вызывать при удалении строки. func rehash(table_index: Dictionary): - var rows_count = $table.get_rows_count() - for i_row in rows_count: - var item = $table.get_node2(0, i_row) - table_index[int(item.text)] = i_row + var rows_count = $table.get_rows_count() + for i_row in rows_count: + var item = $table.get_node2(0, i_row) + table_index[int(item.text)] = i_row -## Обрабатывает сигнал [b]threat_update[/b] +## Обрабатывает сигнал [b]threat_update[/b]. func on_threat_update(th, table_index: Dictionary): - var row = map_th_to_row(th) - var i_row = table_index[th.id] - $table.set_row_text(i_row, row) + var row = map_th_to_row(th) + var i_row = table_index[th.id] + $table.set_row_text(i_row, row) -## Обрабатывает сигнал [b]threat_lost[/b] +## Обрабатывает сигнал [b]threat_lost[/b]. func on_threat_lost(th, table_index: Dictionary): - $table.remove_row(table_index[th.id]) - table_index.clear() - rehash(table_index) + $table.remove_row(table_index[th.id]) + table_index.clear() + rehash(table_index) -## Обрабатывает сигнал [b]threat_new[/b] +## Обрабатывает сигнал [b]threat_new[/b]. func on_threat_new(th, table_index): - var i_row = $table.get_rows_count() - $table.add_row(TABLE_ROW) - var row = map_th_to_row(th) - $table.set_row_text(i_row, row) - $table.set_row_editable(i_row, false) - $table.set_node_user_data(0, i_row, th) - table_index[th.id] = i_row + var i_row = $table.get_rows_count() + $table.add_row(TABLE_ROW) + var row = map_th_to_row(th) + $table.set_row_text(i_row, row) + $table.set_row_editable(i_row, false) + $table.set_node_user_data(0, i_row, th) + table_index[th.id] = i_row -## Преобразует цель в строку таблицы +## Преобразует цель в строку таблицы. func map_th_to_row(th) -> Array: - var row: = Array() - row.resize(TABLE_COLUMN_PARAM.size()) - var i_col: int = 0 - for param_name in TABLE_COLUMN_PARAM: - row[i_col] = '%s' % th.get(param_name) - i_col += 1 - return row + var row: = Array() + row.resize(TABLE_COLUMN_PARAM.size()) + var i_col: int = 0 + for param_name in TABLE_COLUMN_PARAM: + row[i_col] = '%s' % th.get(param_name) + i_col += 1 + return row -## Выделяет выбранную цель в таблице +## Выделяет выбранную цель в таблице. func on_rto_threat_sel(th_id, tbl): - for i in tbl.get_rows_count(): - var node = tbl.get_node2(0, i) - if node.text.to_int() == th_id: - row_pressed(i) - break + for i in tbl.get_rows_count(): + var node = tbl.get_node2(0, i) + if node.text.to_int() == th_id: + row_pressed(i) + break -## Снимает выделение цели +## Снимает выделение цели. func on_rto_threat_unsel(_th_id): $table.clear_rows_selected() diff --git a/scenes/frame/frame.gd b/scenes/frame/frame.gd index f83e3a38..f51e0506 100644 --- a/scenes/frame/frame.gd +++ b/scenes/frame/frame.gd @@ -4,15 +4,15 @@ extends NinePatchRect @export var horizontal_alignment: HorizontalAlignment = HorizontalAlignment.HORIZONTAL_ALIGNMENT_CENTER: - get: return $header.horizontal_alignment if is_inside_tree() else HorizontalAlignment.HORIZONTAL_ALIGNMENT_CENTER - set(val): if is_inside_tree(): $header.horizontal_alignment = val + get: return $header.horizontal_alignment if is_inside_tree() else HorizontalAlignment.HORIZONTAL_ALIGNMENT_CENTER + set(val): if is_inside_tree(): $header.horizontal_alignment = val @export var vertical_alignment: VerticalAlignment = VerticalAlignment.VERTICAL_ALIGNMENT_CENTER: - get: return $header.vertical_alignment if is_inside_tree() else VerticalAlignment.VERTICAL_ALIGNMENT_CENTER - set(val): if is_inside_tree(): $header.vertical_alignment = val + get: return $header.vertical_alignment if is_inside_tree() else VerticalAlignment.VERTICAL_ALIGNMENT_CENTER + set(val): if is_inside_tree(): $header.vertical_alignment = val @export var text: String = 'caption text': - get: return $header.text if is_inside_tree() else '' - set(val): if is_inside_tree(): $header.text = val + get: return $header.text if is_inside_tree() else '' + set(val): if is_inside_tree(): $header.text = val diff --git a/scenes/pribor-afsp/pribor-afsp.gd b/scenes/pribor-afsp/pribor-afsp.gd index ba0c5654..fb4e4bca 100644 --- a/scenes/pribor-afsp/pribor-afsp.gd +++ b/scenes/pribor-afsp/pribor-afsp.gd @@ -6,13 +6,13 @@ var test_addr: = String() var test_data: = {} func _ready(): - test_req = HTTPRequest.new() - add_child(test_req) - test_req.request_completed.connect(_map_request_completed) + test_req = HTTPRequest.new() + add_child(test_req) + test_req.request_completed.connect(_map_request_completed) func _map_request_completed(): - pass + pass func on_req_test_data_timer(): - test_req.request(test_addr) + test_req.request(test_addr) diff --git a/scenes/pribor-rtr/pribor-rtr.gd b/scenes/pribor-rtr/pribor-rtr.gd index 11030370..e0bdd808 100644 --- a/scenes/pribor-rtr/pribor-rtr.gd +++ b/scenes/pribor-rtr/pribor-rtr.gd @@ -1,4 +1,4 @@ -extends "res://scenes/контроль/прибор.gd" +class_name pribor_rtr extends "res://scenes/контроль/прибор.gd" static var json_parser: JSON = JSON.new() @@ -9,94 +9,94 @@ static var json_parser: JSON = JSON.new() ## [param paths] - Массив содержащий отдельные элементы пути.[br] ## [param tokens] - Разделители используемые во входной строке для разделения элементов пути.[br] func map_solid_to_array(solid: String, paths: Array, tokens: Array = ['[', ']', '.']) -> void: - paths.clear() - var i_chs = [] - for sep in tokens: - var i = 0 - while i != -1: - i = solid.find(sep, i + 1) - i_chs.append(i) - i_chs.pop_back() - i_chs.sort() + paths.clear() + var i_chs = [] + for sep in tokens: + var i = 0 + while i != -1: + i = solid.find(sep, i + 1) + i_chs.append(i) + i_chs.pop_back() + i_chs.sort() - var i0 = 0 - for i1 in i_chs: - var ss: = [String()] - tools.get_string_slice(solid, ss, i0, i1) - if ss[0].is_valid_int(): - paths.append(ss[0].to_int()) - else: - if ss[0]: - paths.append(ss[0]) - i0 = i1 + 1 + var i0 = 0 + for i1 in i_chs: + var ss: = [String()] + tools.get_string_slice(solid, ss, i0, i1) + if ss[0].is_valid_int(): + paths.append(ss[0].to_int()) + else: + if ss[0]: + paths.append(ss[0]) + i0 = i1 + 1 func _on_request_rtr_request_completed(result, _response_code, headers, body: PackedByteArray): - if result != 0: - var rs = $request_rtr.get_result_string(result) - log.error('ошибка: \"%s\"' % rs) - return + if result != 0: + var rs = $request_rtr.get_result_string(result) + log.error('ошибка: \"%s\"' % rs) + return - var json_str: String = body.get_string_from_utf8() - if not json_str: - push_error('ошибка: не удаётся получить строку utf8 из данных (%s)' % headers) - return + var json_str: String = body.get_string_from_utf8() + if not json_str: + push_error('ошибка: не удаётся получить строку utf8 из данных (%s)' % headers) + return - var rc = json_parser.parse(json_str) - if rc != Error.OK: - var err = json_parser.get_error_message() - push_error('ошибка: разбор json прерван - \"%s\" (%s)' % [err, headers]) - return + var rc = json_parser.parse(json_str) + if rc != Error.OK: + var err = json_parser.get_error_message() + push_error('ошибка: разбор json прерван - \"%s\" (%s)' % [err, headers]) + return - var pp = ['DeviceDescription', 'DeviceName'] - var ret_val = [null, false] - var pp_copy = pp.duplicate(true) - tools.get_value_by_path(json_parser.data, pp, ret_val) - if not ret_val[1]: - push_error('ошибка: путь %s не найден (%s)' % [pp_copy, headers]) - return + var pp = ['DeviceDescription', 'DeviceName'] + var ret_val = [null, false] + var pp_copy = pp.duplicate(true) + tools.get_value_by_path(json_parser.data, pp, ret_val) + if not ret_val[1]: + push_error('ошибка: путь %s не найден (%s)' % [pp_copy, headers]) + return - var bort_rtr_name_left: StringName = $left.get_meta('DeviceName', '') - var bort_rtr_name_right: StringName = $right.get_meta('DeviceName', '') - var bb = {bort_rtr_name_left: $left, bort_rtr_name_right: $right} - if not bb.has(ret_val[0]): - return + var bort_rtr_name_left: StringName = $left.get_meta('DeviceName', '') + var bort_rtr_name_right: StringName = $right.get_meta('DeviceName', '') + var bb = {bort_rtr_name_left: $left, bort_rtr_name_right: $right} + if not bb.has(ret_val[0]): + return - var bort_rtr = bb[ret_val[0]] - for child in bort_rtr.get_node('konverter/grid').get_children(): - map_value_to_item(json_parser.data, child, 'value0') - map_value_to_item(json_parser.data, child, 'value1') - map_value_to_item(json_parser.data, child, 'value2') - map_error_codes_to_item(json_parser.data, child, 'state') - for child in bort_rtr.get_node('antenna1/grid').get_children(): - map_value_to_item(json_parser.data, child, 'value0') - map_value_to_item(json_parser.data, child, 'value1') - map_error_codes_to_item(json_parser.data, child, 'state') - for child in bort_rtr.get_node('antenna2/grid').get_children(): - map_value_to_item(json_parser.data, child, 'value0') - map_value_to_item(json_parser.data, child, 'value1') - map_error_codes_to_item(json_parser.data, child, 'state') - for child in bort_rtr.get_children(): - map_value_to_item(json_parser.data, child, 'value0') - map_value_to_item(json_parser.data, child, 'value1') - map_error_codes_to_item(json_parser.data, child, 'state') + var bort_rtr = bb[ret_val[0]] + for child in bort_rtr.get_node('konverter/grid').get_children(): + map_value_to_item(json_parser.data, child, 'value0') + map_value_to_item(json_parser.data, child, 'value1') + map_value_to_item(json_parser.data, child, 'value2') + map_error_codes_to_item(json_parser.data, child, 'state') + for child in bort_rtr.get_node('antenna1/grid').get_children(): + map_value_to_item(json_parser.data, child, 'value0') + map_value_to_item(json_parser.data, child, 'value1') + map_error_codes_to_item(json_parser.data, child, 'state') + for child in bort_rtr.get_node('antenna2/grid').get_children(): + map_value_to_item(json_parser.data, child, 'value0') + map_value_to_item(json_parser.data, child, 'value1') + map_error_codes_to_item(json_parser.data, child, 'state') + for child in bort_rtr.get_children(): + map_value_to_item(json_parser.data, child, 'value0') + map_value_to_item(json_parser.data, child, 'value1') + map_error_codes_to_item(json_parser.data, child, 'state') func map_value_to_item(data, item, value_name: StringName): - var meta = item.get_meta(value_name, '') - if meta == '': - return - if not (meta is String): - return - var paths: = Array() - map_solid_to_array(meta, paths) - var ret_val: = [null, false] - var paths_copy = paths.duplicate(true) - tools.get_value_by_path(data, paths, ret_val) - if ret_val[1]: - item.set(value_name, ret_val[0]) - else: - push_error('ошибка: путь %s для $%s.%s не найден' % [paths_copy, item.name, value_name]) + var meta = item.get_meta(value_name, '') + if meta == '': + return + if not (meta is String): + return + var paths: = Array() + map_solid_to_array(meta, paths) + var ret_val: = [null, false] + var paths_copy = paths.duplicate(true) + tools.get_value_by_path(data, paths, ret_val) + if ret_val[1]: + item.set(value_name, ret_val[0]) + else: + push_error('ошибка: путь %s для $%s.%s не найден' % [paths_copy, item.name, value_name]) ## 1. Поле [b]'ErCode'[/b] содержит [b]0[/b] - если нет ошибки, и другое значение - если есть ошибка.[br] @@ -105,29 +105,29 @@ func map_value_to_item(data, item, value_name: StringName): ## 4. [i]Нет результата порверки[/i] - поле [param state] принимает значение [b]0[/b], [i]всё ## исправно[/i] - [b]1[/b], [i]хотябы один[/i] параметр с ошибкой - [b]2[/b].[br] func map_error_codes_to_item(data, item, value_name: StringName): - var metas = item.get_meta(value_name, '') - if not (metas is Array): - return - var paths: = Array() - var values: = Array() - for meta in metas: - map_solid_to_array(meta, paths) - var ret_val: = [null, false] - var paths_copy = paths.duplicate(true) - tools.get_value_by_path(data, paths, ret_val) - if ret_val[1]: - values.append(int(ret_val[0])) - else: - push_error('ошибка: путь %s для $%s.%s не найден' % [paths_copy, item.name, value_name]) - var test_res = 1 if values.count(int(0)) == values.size() else 2 - item.set(value_name, test_res) + var metas = item.get_meta(value_name, '') + if not (metas is Array): + return + var paths: = Array() + var values: = Array() + for meta in metas: + map_solid_to_array(meta, paths) + var ret_val: = [null, false] + var paths_copy = paths.duplicate(true) + tools.get_value_by_path(data, paths, ret_val) + if ret_val[1]: + values.append(int(ret_val[0])) + else: + push_error('ошибка: путь %s для $%s.%s не найден' % [paths_copy, item.name, value_name]) + var test_res = 1 if values.count(int(0)) == values.size() else 2 + item.set(value_name, test_res) -## Вызывается при клике мыши на элементе контроля -## [param block_a] - Кликнутый элемент контроля +## Вызывается при клике мыши на элементе контроля. +## [param block_a] - Кликнутый элемент контроля. func _on_item_pressed(block_a: Control): - var metas = block_a.get_meta_list() - print_debug(block_a) - for n in metas: - var v = block_a.get_meta(n) - print('%s:%s' % [n, v]) + var metas = block_a.get_meta_list() + print_debug(block_a) + for n in metas: + var v = block_a.get_meta(n) + print('%s:%s' % [n, v]) diff --git a/scenes/tabs-switch/tab-switch.gd b/scenes/tabs-switch/tab-switch.gd index 31a8f966..d7715fe7 100644 --- a/scenes/tabs-switch/tab-switch.gd +++ b/scenes/tabs-switch/tab-switch.gd @@ -4,9 +4,9 @@ const TAB_TOSIGNAL_NAME = {0: 'режим_работа', 1: 'режим_конт func _enter_tree() -> void: - repnetwork.logger_page = $Журнал + repnetwork.logger_page = $Журнал func _on_tab_changed(tab) -> void: - if TAB_TOSIGNAL_NAME.has(tab): - signaller.emit_signal(TAB_TOSIGNAL_NAME[tab]) + if TAB_TOSIGNAL_NAME.has(tab): + signaller.emit_signal(TAB_TOSIGNAL_NAME[tab]) diff --git a/scenes/tilemap/tilemap.gd b/scenes/tilemap/tilemap.gd index 3920258b..4bd9c6d0 100644 --- a/scenes/tilemap/tilemap.gd +++ b/scenes/tilemap/tilemap.gd @@ -1,173 +1,174 @@ -extends Sprite2D +class_name main_tilemap extends Sprite2D -## Возможные состояния конечного автомата заданий +## Возможные состояния конечного автомата заданий. enum TASK_STATE { - DONE, ## Выполнено - WAIT, ## Ожидание плитки - RUN, ## Запуск выполнения - CHECK, ## Проверка пустого места - ERROR ## Ошибка + DONE, ## Выполнено. + WAIT, ## Ожидание плитки. + RUN, ## Запуск выполнения. + CHECK, ## Проверка пустого места. + ERROR ## Ошибка. } -## Координаты для проверок [lng, lat] +## Координаты для проверок [lng, lat]. const TEST_DATA: = { - 'Калиниград': [ 20.51095, 54.70649 ], - 'Москва': [ 37.6156, 55.7522 ], - 'Нью-Йорк': [ -74.006, 40.7143 ], - 'Сидней': [ 151.20732, -33.8678500 ], - 'Таганрог': [ 38.8969, 47.2362 ], - 'Хельсинки': [ 24.9354, 60.1695 ], - 'Азорские о-ва': [ 28.3996582, 38.5397568 ], - 'Мехико': [ -99.12766, 19.42847 ], - 'Белое море': [ 68.136606, 42.045546 ], - 'море Беллинсгаузена': [ -72.406587, -74.857997 ], - 'Фиджи': [ 178.065032, -17.713371 ], - 'Ноль': [ 0.0, 0.0 ], - 'Точка1': [ 170.0, 0.0 ], - 'Точка2': [-170.0, 0.0 ], - 'Море' : [ 19.4, 54.91 ] } + 'Калиниград': [ 20.51095, 54.70649 ], + 'Москва': [ 37.6156, 55.7522 ], + 'Нью-Йорк': [ -74.006, 40.7143 ], + 'Сидней': [ 151.20732, -33.8678500 ], + 'Таганрог': [ 38.8969, 47.2362 ], + 'Хельсинки': [ 24.9354, 60.1695 ], + 'Азорские о-ва': [ 28.3996582, 38.5397568 ], + 'Мехико': [ -99.12766, 19.42847 ], + 'Белое море': [ 68.136606, 42.045546 ], + 'море Беллинсгаузена': [ -72.406587, -74.857997 ], + 'Фиджи': [ 178.065032, -17.713371 ], + 'Ноль': [ 0.0, 0.0 ], + 'Точка1': [ 170.0, 0.0 ], + 'Точка2': [-170.0, 0.0 ], + 'Море' : [ 19.4, 54.91 ] } const MAP_MODES: = { - 0: 'application/config/map_image_size_rto', - 1: 'application/config/map_image_size_rls' } + 0: 'application/config/map_image_size_rto', + 1: 'application/config/map_image_size_rls' } const MAP_RELATIVE_RADIUSES: = { - 0: 0.39, - 1: 0.466 + 0: 0.39, + 1: 0.466 } -var map_image: Image ## Изображение с картой -var map_tile_state: TASK_STATE ## Текущее состояние конечного автомата плитки -var map_bcs: Vector3 ## Яркость, контраст насыщенность -var map_server_addr: String ## Адрес сервера изображений карт в проекции Меркатора +var map_image: Image ## Изображение с картой. +var map_tile_state: TASK_STATE ## Текущее состояние конечного автомата плитки. +var map_bcs: Vector3 ## Яркость, контраст насыщенность. +var map_server_addr: String ## Адрес сервера изображений карт в проекции Меркатора. var map_tile_format: String ## -var map_tile_stack: Array ## Стек для хранения плиток карты -var map_request: HTTPRequest ## Обработчик запросов http -var map_zoom: int ## Уровень детализации карты -var map_tile: Rect2i ## Область одной плитки: [x-координата области, y-координата области, x-индекс плитки, y-индекс плитки] -var map_mode: int ## Режим карты: 0 - приоритет РТО, 1 - приоритет РЛС +var map_tile_stack: Array ## Стек для хранения плиток карты. +var map_request: HTTPRequest ## Обработчик запросов http. +var map_zoom: int ## Уровень детализации карты. +var map_tile: Rect2i ## Область одной плитки: [x-координата области, y-координата области, x-индекс плитки, y-индекс плитки]. +var map_mode: int ## Режим карты: 0 - приоритет РТО, 1 - приоритет РЛС. var prev_tiles_dic: Dictionary ## -var lnglat: Array ## Текущие координаты +var lnglat: Array ## Текущие координаты. var root_rect: Rect2i - - + func _ready(): - lnglat = TEST_DATA['Таганрог'] - map_tile_state = TASK_STATE.DONE - map_request = HTTPRequest.new() - add_child(map_request) - map_request.request_completed.connect(self._map_request_completed) - map_bcs = ProjectSettings.get_setting('application/config/map_bcs', Vector3(1.0, 1.0, 1.0)) - map_server_addr = ProjectSettings.get_setting('application/config/map_server_addr') - map_tile_format = ProjectSettings.get_setting('application/config/map_tile_format', '%s/%d/%d/%d.png') - var map_image_size = ProjectSettings.get_setting(MAP_MODES[0], Vector2i(512, 512)) - var map_tile_size = ProjectSettings.get_setting('application/config/map_tile_size', 256) - map_image = Image.create(map_image_size.x, map_image_size.y, true, Image.FORMAT_RGB8) - map_tile = Rect2i(0, 0, map_tile_size, map_tile_size) - signaller.connect('zoom_changed', Callable(self, '_on_zoom_changed')) - signaller.connect('map_mode_changed', Callable(self, '_on_map_mode_changed')) - log.info('Адрес сервера поставщика карт: \"%s\"' % map_server_addr) - log.info('Модуль географической карты готов') + lnglat = TEST_DATA['Таганрог'] + map_tile_state = TASK_STATE.DONE + map_request = HTTPRequest.new() + add_child(map_request) + map_request.request_completed.connect(self._map_request_completed) + map_bcs = ProjectSettings.get_setting('application/config/map_bcs', Vector3(1.0, 1.0, 1.0)) + map_server_addr = ProjectSettings.get_setting('application/config/map_server_addr') + map_tile_format = ProjectSettings.get_setting('application/config/map_tile_format', '%s/%d/%d/%d.png') + var map_image_size = ProjectSettings.get_setting(MAP_MODES[0], Vector2i(512, 512)) + var map_tile_size = ProjectSettings.get_setting('application/config/map_tile_size', 256) + map_image = Image.create(map_image_size.x, map_image_size.y, true, Image.FORMAT_RGB8) + map_tile = Rect2i(0, 0, map_tile_size, map_tile_size) + signaller.connect('zoom_changed', Callable(self, '_on_zoom_changed')) + signaller.connect('map_mode_changed', Callable(self, '_on_map_mode_changed')) + log.info('Адрес сервера поставщика карт: \"%s\"' % map_server_addr) + log.info('Модуль географической карты готов') + func _on_map_mode_changed(mode: int) -> void: - var map_image_size = ProjectSettings.get_setting(MAP_MODES[mode]) - material.set('shader_parameter/radius', MAP_RELATIVE_RADIUSES[mode]) - map_image.fill(Color(0, 0, 0, 0)) - map_image.resize(map_image_size.x, map_image_size.y) - map_tile_state = TASK_STATE.DONE - map_mode = mode - var tile: = mercator.create_tile(lnglat[0], lnglat[1], map_zoom) - map_tile_stack.clear() - map_tile_stack.append(tile) - prev_tiles_dic.clear() + var map_image_size = ProjectSettings.get_setting(MAP_MODES[mode]) + material.set('shader_parameter/radius', MAP_RELATIVE_RADIUSES[mode]) + map_image.fill(Color(0, 0, 0, 0)) + map_image.resize(map_image_size.x, map_image_size.y) + map_tile_state = TASK_STATE.DONE + map_mode = mode + var tile: = mercator.create_tile(lnglat[0], lnglat[1], map_zoom) + map_tile_stack.clear() + map_tile_stack.append(tile) + prev_tiles_dic.clear() func mark_image_center(image: Image, color: Color = Color.RED): - var c = image.get_size() / 2 - map_image.set_pixel(c.x - 1, c.y - 1, color) - map_image.set_pixel(c.x - 1, c.y, color) - map_image.set_pixel(c.x, c.y - 1, color) - map_image.set_pixel(c.x, c.y, color) + var c = image.get_size() / 2 + map_image.set_pixel(c.x - 1, c.y - 1, color) + map_image.set_pixel(c.x - 1, c.y, color) + map_image.set_pixel(c.x, c.y - 1, color) + map_image.set_pixel(c.x, c.y, color) func _on_zoom_changed(zoom: int): - if map_tile_stack.size() != 0: - return - map_zoom = zoom - var tile: = mercator.create_tile(lnglat[0], lnglat[1], zoom) - map_tile_stack.clear() - map_tile_stack.append(tile) - prev_tiles_dic.clear() + if map_tile_stack.size() != 0: + return + map_zoom = zoom + var tile: = mercator.create_tile(lnglat[0], lnglat[1], zoom) + map_tile_stack.clear() + map_tile_stack.append(tile) + prev_tiles_dic.clear() func img_tile_to_map_image(image: Image, dst_pos: Vector2i): - image.adjust_bcs(map_bcs.x, map_bcs.y, map_bcs.z) - map_image.blit_rect(image, map_tile, dst_pos) + image.adjust_bcs(map_bcs.x, map_bcs.y, map_bcs.z) + map_image.blit_rect(image, map_tile, dst_pos) func _process(_delta: float): - if (map_tile_state == TASK_STATE.DONE) and map_tile_stack.size(): - var tile: mercator.Tile = map_tile_stack[-1] - var tile_addr: = map_tile_format % [map_server_addr, tile.z, tile.x , tile.y] - var rc = map_request.request(tile_addr) - if rc == OK: - map_tile_state = TASK_STATE.WAIT - else: - log.error('%s: Невозможно сформировать запрос HTTP' % self) - map_tile_state = TASK_STATE.ERROR - elif map_tile_state == TASK_STATE.CHECK: - var root_tile: = mercator.Tile.new(root_rect.size.x, root_rect.size.y, map_zoom) - var neighbors_tiles = mercator.get_perimetr_tiles(root_tile, (map_image.get_size().x / map_tile.size.x) / 2) - var neighbors_tiles_dic = {} - for tile in neighbors_tiles: - neighbors_tiles_dic[[tile.x, tile.y]] = false - if neighbors_tiles_dic != prev_tiles_dic: - for tile in neighbors_tiles: - tile.is_root = false - map_tile_stack.push_front(tile) - prev_tiles_dic[[tile.x, tile.y]] = false - else: - if map_tile_stack.size() == 0: - signaller.emit_signal('zoom_complete', map_zoom) - map_tile_state = TASK_STATE.DONE + if (map_tile_state == TASK_STATE.DONE) and map_tile_stack.size(): + var tile: mercator.Tile = map_tile_stack[-1] + var tile_addr: = map_tile_format % [map_server_addr, tile.z, tile.x , tile.y] + var rc = map_request.request(tile_addr) + if rc == OK: + map_tile_state = TASK_STATE.WAIT + else: + log.error('%s: Невозможно сформировать запрос HTTP' % self) + map_tile_state = TASK_STATE.ERROR + elif map_tile_state == TASK_STATE.CHECK: + var root_tile: = mercator.Tile.new(root_rect.size.x, root_rect.size.y, map_zoom) + var neighbors_tiles = mercator.get_perimetr_tiles(root_tile, (map_image.get_size().x / map_tile.size.x) / 2) + var neighbors_tiles_dic = {} + for tile in neighbors_tiles: + neighbors_tiles_dic[[tile.x, tile.y]] = false + if neighbors_tiles_dic != prev_tiles_dic: + for tile in neighbors_tiles: + tile.is_root = false + map_tile_stack.push_front(tile) + prev_tiles_dic[[tile.x, tile.y]] = false + else: + if map_tile_stack.size() == 0: + signaller.emit_signal('zoom_complete', map_zoom) + map_tile_state = TASK_STATE.DONE func _map_request_completed(result, response_code, headers, data): - if result != HTTPRequest.RESULT_SUCCESS: - log.error('%s: Запрос не обработан. result: \"%s\", response_code: \"%s\", headers: \"%s\"' % [self, result, response_code, headers]) - map_tile_state = TASK_STATE.ERROR - return + if result != HTTPRequest.RESULT_SUCCESS: + log.error('%s: Запрос не обработан. result: \"%s\", response_code: \"%s\", headers: \"%s\"' % [self, result, response_code, headers]) + map_tile_state = TASK_STATE.ERROR + return - var img_tile = Image.new() - var error = img_tile.load_png_from_buffer(data) - if error != OK: - log.error('%s: Полученые данные невозможно использовать для формироания изображения. result: \"%s\", response_code: \"%s\", headers: \"%s\"' % [self, result, response_code, headers]) - map_tile_state = TASK_STATE.ERROR - return + var img_tile = Image.new() + var error = img_tile.load_png_from_buffer(data) + if error != OK: + log.error('%s: Полученые данные невозможно использовать для формироания изображения. result: \"%s\", response_code: \"%s\", headers: \"%s\"' % [self, result, response_code, headers]) + map_tile_state = TASK_STATE.ERROR + return - var tile = map_tile_stack.pop_back() - map_tile_state = TASK_STATE.CHECK + var tile = map_tile_stack.pop_back() + map_tile_state = TASK_STATE.CHECK - if tile.is_root: - # Отображение корневой плитки - map_image.fill(Color(0, 0, 0, 0)) - var bounds: = mercator.bounds(tile) - var lng_c = (bounds.east + bounds.west) / 2.0 - var lat_c = (bounds.north + bounds.south) / 2.0 - var sx: float = float(map_tile.size.x) / (bounds.east - bounds.west) * (lng_c - tile.lng) + map_tile.size.x / 2.0 # Cмещение в пискселях центра плитки от заданной точки по горизонтали. - var sy: float = float(map_tile.size.y) / (bounds.north - bounds.south) * (lat_c - tile.lat) - map_tile.size.y / 2.0 # Cмещение в пискселях центра плитки от заданной точки по вертикали. - var dst_pos: Vector2i = Vector2i(int(sx), int(-sy)) + map_tile.size * map_mode - img_tile_to_map_image(img_tile, dst_pos) - root_rect = Rect2i(dst_pos.x, dst_pos.y, tile.x, tile.y) - else: - # Отображение соседних плиток - var delta: = Vector2i(tile.x - root_rect.size.x, tile.y - root_rect.size.y) - var dst_pos: Vector2i = root_rect.position + delta * map_tile.size - img_tile_to_map_image(img_tile, dst_pos) - mark_image_center(map_image) - texture = ImageTexture.create_from_image(map_image) + if tile.is_root: + # Отображение корневой плитки + map_image.fill(Color(0, 0, 0, 0)) + var bounds: = mercator.bounds(tile) + var lng_c = (bounds.east + bounds.west) / 2.0 + var lat_c = (bounds.north + bounds.south) / 2.0 + var sx: float = float(map_tile.size.x) / (bounds.east - bounds.west) * (lng_c - tile.lng) + map_tile.size.x / 2.0 # Cмещение в пискселях центра плитки от заданной точки по горизонтали. + var sy: float = float(map_tile.size.y) / (bounds.north - bounds.south) * (lat_c - tile.lat) - map_tile.size.y / 2.0 # Cмещение в пискселях центра плитки от заданной точки по вертикали. + var dst_pos: Vector2i = Vector2i(int(sx), int(-sy)) + map_tile.size * map_mode + img_tile_to_map_image(img_tile, dst_pos) + root_rect = Rect2i(dst_pos.x, dst_pos.y, tile.x, tile.y) + else: + # Отображение соседних плиток + var delta: = Vector2i(tile.x - root_rect.size.x, tile.y - root_rect.size.y) + var dst_pos: Vector2i = root_rect.position + delta * map_tile.size + img_tile_to_map_image(img_tile, dst_pos) + mark_image_center(map_image) + texture = ImageTexture.create_from_image(map_image) + diff --git a/scenes/tilemap/tilemap.tscn b/scenes/tilemap/tilemap.tscn index 406784f3..9dcc09b9 100644 --- a/scenes/tilemap/tilemap.tscn +++ b/scenes/tilemap/tilemap.tscn @@ -1,14 +1,41 @@ -[gd_scene load_steps=4 format=3 uid="uid://bbq6nklh36yij"] +[gd_scene load_steps=6 format=3 uid="uid://bbq6nklh36yij"] [ext_resource type="Script" path="res://scenes/tilemap/tilemap.gd" id="1_mkfgj"] [ext_resource type="Shader" path="res://shaders/tilemap.gdshader" id="1_tsdui"] +[ext_resource type="Script" path="res://scenes/tilemap/Node2D.gd" id="3_lr4ti"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_pmqvj"] resource_local_to_scene = true shader = ExtResource("1_tsdui") shader_parameter/radius = 0.39 +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ys5v4"] + [node name="tilemap" type="Sprite2D"] material = SubResource("ShaderMaterial_pmqvj") position = Vector2(560, 560) script = ExtResource("1_mkfgj") + +[node name="Panel" type="Panel" parent="."] +offset_left = -563.0 +offset_top = -557.0 +offset_right = 1022.0 +offset_bottom = 641.0 +theme_override_styles/panel = SubResource("StyleBoxEmpty_ys5v4") + +[node name="Node2D" type="Node2D" parent="."] +script = ExtResource("3_lr4ti") + +[node name="LineEdit" type="LineEdit" parent="Node2D"] +offset_left = -490.0 +offset_top = 518.0 +offset_right = -244.0 +offset_bottom = 565.0 + +[node name="VBoxContainer" type="VBoxContainer" parent="Node2D"] +offset_left = -499.0 +offset_top = 200.0 +offset_right = -239.0 +offset_bottom = 430.0 + +[connection signal="gui_input" from="Panel" to="." method="_on_panel_gui_input"] diff --git a/scenes/журнал/журнал.gd b/scenes/журнал/журнал.gd index ad400e81..1385bcd6 100644 --- a/scenes/журнал/журнал.gd +++ b/scenes/журнал/журнал.gd @@ -9,58 +9,58 @@ func on_interfer_off(ecm, _ecms, _thrs,msg: String): log.message(Logger.INFO, '% func on_set_program_mode(msg: String): log.message(Logger.INFO, msg) func on_interfer_new(ecm, msg: String): - if ecm.krp != interfer.INTERFER_OFF: - log.message(Logger.INFO, '%s: %s' % [msg, ecm.to_string()]) + if ecm.krp != interfer.INTERFER_OFF: + log.message(Logger.INFO, '%s: %s' % [msg, ecm.to_string()]) func _enter_tree(): - var flts: Array = [] - for item in $filtrs.get_children(): - flts.append(item) - log.set_filtrs(flts) + var flts: Array = [] + for item in $filtrs.get_children(): + flts.append(item) + log.set_filtrs(flts) func _ready() -> void: - log.info('Модуль журнала работы готов') - log.info('Аргументы коммандной строки: \"%s\"' % OS.get_cmdline_args()) - log.info('Операционная система: %s' % [OS.get_distribution_name()]) - log.info('Текущая версия ПО УАРЭП: %s' % commit.VCS_HEAD) - threats.connect('threat_new', Callable(self, 'on_threats_changed').bind('Цель обнаружена')) - threats.connect('threat_lost', Callable(self, 'on_threats_changed').bind('Цель потеряна')) - signaller.conn(signaller.interfer_new, Callable(self, 'on_interfer_new').bind('Создан сеанс помехи')) - signaller.conn(signaller.interfer_off, Callable(self, 'on_interfer_off').bind('Сеанс помехи отключен')) - signaller.conn(signaller.режим_работа, Callable(log, 'info').bind('Программа в режиме \"Работа\"')) - signaller.conn(signaller.режим_настройки, Callable(log, 'info').bind('Программа в режиме \"Настройки\"')) - signaller.conn(signaller.режим_эмс, Callable(log, 'info').bind('Программа в режиме \"ЭМС\"')) - signaller.conn(signaller.режим_журнал, Callable(log, 'info').bind('Программа в режиме \"Журнал\"')) - signaller.conn(signaller.режим_контроль, Callable(log, 'info').bind('Программа в режиме \"Контроль\"')) + log.info('Модуль журнала работы готов') + log.info('Аргументы коммандной строки: \"%s\"' % OS.get_cmdline_args()) + log.info('Операционная система: %s' % [OS.get_distribution_name()]) + log.info('Текущая версия ПО УАРЭП: %s' % commit.VCS_HEAD) + threats.connect('threat_new', Callable(self, 'on_threats_changed').bind('Цель обнаружена')) + threats.connect('threat_lost', Callable(self, 'on_threats_changed').bind('Цель потеряна')) + signaller.conn(signaller.interfer_new, Callable(self, 'on_interfer_new').bind('Создан сеанс помехи')) + signaller.conn(signaller.interfer_off, Callable(self, 'on_interfer_off').bind('Сеанс помехи отключен')) + signaller.conn(signaller.режим_работа, Callable(log, 'info').bind('Программа в режиме \"Работа\"')) + signaller.conn(signaller.режим_настройки, Callable(log, 'info').bind('Программа в режиме \"Настройки\"')) + signaller.conn(signaller.режим_эмс, Callable(log, 'info').bind('Программа в режиме \"ЭМС\"')) + signaller.conn(signaller.режим_журнал, Callable(log, 'info').bind('Программа в режиме \"Журнал\"')) + signaller.conn(signaller.режим_контроль, Callable(log, 'info').bind('Программа в режиме \"Контроль\"')) func _on_clear_button_down() -> void: - $content.clear() - log.info('Cодержание журнала очищено оператором') + $content.clear() + log.info('Cодержание журнала очищено оператором') func _on_btn_save_button_down() -> void: - $content.hide() - $btn_clear.hide() - $btn_save.hide() - $filtrs.hide() - $dlg_file.show() + $content.hide() + $btn_clear.hide() + $btn_save.hide() + $filtrs.hide() + $dlg_file.show() func _on_dlg_file_confirmed() -> void: - $content.show() - $btn_clear.show() - $btn_save.show() - $filtrs.show() - $dlg_file.hide() + $content.show() + $btn_clear.show() + $btn_save.show() + $filtrs.show() + $dlg_file.hide() func _on_dlg_file_file_selected(path): - log.save_file(path) + log.save_file(path) func _on_check_box_pressed(): - $content.clear() - log.add_msgs() + $content.clear() + log.add_msgs() diff --git a/scenes/контроль/кассета.gd b/scenes/контроль/кассета.gd index fb83827d..a8d394b0 100644 --- a/scenes/контроль/кассета.gd +++ b/scenes/контроль/кассета.gd @@ -7,11 +7,11 @@ extends NinePatchRect """ @export var fname: String: - set(v): - fname = v - $lbl_fname.text = v + set(v): + fname = v + $lbl_fname.text = v @export var rname: String: - set(v): - rname = v + set(v): + rname = v diff --git a/scenes/контроль/кнопка-прибора.gd b/scenes/контроль/кнопка-прибора.gd index 4575a6ca..e0f2369e 100644 --- a/scenes/контроль/кнопка-прибора.gd +++ b/scenes/контроль/кнопка-прибора.gd @@ -7,7 +7,7 @@ extends Node func _on_toggled(toggled_on): $frame.visible = toggled_on @export var state: int: - set(v): - v = 0 if v < 0 else v % state_colors.size() - state = v - $label.self_modulate = state_colors[v] + set(v): + v = 0 if v < 0 else v % state_colors.size() + state = v + $label.self_modulate = state_colors[v] diff --git a/scenes/контроль/контроль.gd b/scenes/контроль/контроль.gd index 562cb76b..295867b6 100644 --- a/scenes/контроль/контроль.gd +++ b/scenes/контроль/контроль.gd @@ -6,50 +6,50 @@ extends Panel const PRIBORS_RES = \ { - 'pribor_afsp_l': ['res://scenes/pribor-afsp/pribor-afsp.tscn', 'Контроль исправности прибора АФСП левый'], - 'pribor_afsp_r': ['res://scenes/pribor-afsp/pribor-afsp.tscn', 'Контроль исправности прибора АФСП правый'], - 'pribor_prd_k_1': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 1'], - 'pribor_prd_k_2': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 2'], - 'pribor_prd_k_3': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 3'], - 'pribor_prd_k_4': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 4'], - 'pribor_prd_n_1': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 1'], - 'pribor_prd_n_2': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 2'], - 'pribor_prd_n_3': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 3'], - 'pribor_prd_n_4': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 4'], - 'pribor_prd_v_1': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 1'], - 'pribor_prd_v_2': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 2'], - 'pribor_prd_v_3': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 3'], - 'pribor_prd_v_4': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 4'], - 'pribor_rtr': ['res://scenes/pribor-rtr/pribor-rtr.tscn', 'Контроль исправности прибора РТР'], - 'pribor_uf': ['res://scenes/pribor-uf/pribor-uf.tscn', 'Контроль исправности прибора УФ'], - 'pribor_uyep': ['res://scenes/pribor-uyep/pribor-uyep.tscn', 'Контроль исправности прибора УЭП'], - } + 'pribor_afsp_l': ['res://scenes/pribor-afsp/pribor-afsp.tscn', 'Контроль исправности прибора АФСП левый'], + 'pribor_afsp_r': ['res://scenes/pribor-afsp/pribor-afsp.tscn', 'Контроль исправности прибора АФСП правый'], + 'pribor_prd_k_1': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 1'], + 'pribor_prd_k_2': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 2'], + 'pribor_prd_k_3': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 3'], + 'pribor_prd_k_4': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 4'], + 'pribor_prd_n_1': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 1'], + 'pribor_prd_n_2': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 2'], + 'pribor_prd_n_3': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 3'], + 'pribor_prd_n_4': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 4'], + 'pribor_prd_v_1': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 1'], + 'pribor_prd_v_2': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 2'], + 'pribor_prd_v_3': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 3'], + 'pribor_prd_v_4': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 4'], + 'pribor_rtr': ['res://scenes/pribor-rtr/pribor-rtr.tscn', 'Контроль исправности прибора РТР'], + 'pribor_uf': ['res://scenes/pribor-uf/pribor-uf.tscn', 'Контроль исправности прибора УФ'], + 'pribor_uyep': ['res://scenes/pribor-uyep/pribor-uyep.tscn', 'Контроль исправности прибора УЭП'], + } func _ready(): - var group = ButtonGroup.new() - for k in PRIBORS_RES: - var pribor_node = get_node(k) - assert(pribor_node) - var pribor_path = PRIBORS_RES[k][0] - var header_text = PRIBORS_RES[k][1] - pribor_node.set_button_group(group) - pribor_node.connect('button_down', Callable(self, 'on_pribor_press').bind(pribor_path, header_text)) - log.info('Модуль контроля работы готов') + var group = ButtonGroup.new() + for k in PRIBORS_RES: + var pribor_node = get_node(k) + assert(pribor_node) + var pribor_path = PRIBORS_RES[k][0] + var header_text = PRIBORS_RES[k][1] + pribor_node.set_button_group(group) + pribor_node.connect('button_down', Callable(self, 'on_pribor_press').bind(pribor_path, header_text)) + log.info('Модуль контроля работы готов') func on_pribor_press(pribor_path, header_text): - clear_obj($mnemo_container) - var pribor_obj = load(pribor_path) - assert(pribor_obj) - var pribor = pribor_obj.instantiate() - assert(pribor) - pribor.set_header_text(header_text) - $mnemo_container.add_child(pribor) + clear_obj($mnemo_container) + var pribor_obj = load(pribor_path) + assert(pribor_obj) + var pribor = pribor_obj.instantiate() + assert(pribor) + pribor.set_header_text(header_text) + $mnemo_container.add_child(pribor) func clear_obj(obj: Object): - var items = obj.get_children() - for item in items: - obj.remove_child(item) - item.queue_free() + var items = obj.get_children() + for item in items: + obj.remove_child(item) + item.queue_free() diff --git a/scenes/контроль/прибор.gd b/scenes/контроль/прибор.gd index 09099753..80f630d0 100644 --- a/scenes/контроль/прибор.gd +++ b/scenes/контроль/прибор.gd @@ -7,20 +7,20 @@ extends Control """ @export var fname: String: - set(v): - fname = v - get: - return fname + set(v): + fname = v + get: + return fname @export var rname: String: - set(v): - rname = v - get: - return rname + set(v): + rname = v + get: + return rname func set_header_text(header_text: String): - $lbl_header.text = header_text + $lbl_header.text = header_text @export var nodes_mask: String = '' diff --git a/scenes/настройки/настройки.gd b/scenes/настройки/настройки.gd index 18b07fab..c7f05b08 100644 --- a/scenes/настройки/настройки.gd +++ b/scenes/настройки/настройки.gd @@ -1,18 +1,18 @@ -extends Panel +class_name setting extends Panel -# Called when the node enters the scene tree for the first time. +## Вызывается, когда узел впервые попадает в дерево сцены. func _ready() -> void: - $lbl_commit.text = 'Текущая версия ПО УАРЭП: \"%s\"' % commit.VCS_HEAD - if not OS.get_cmdline_args().has('++ограниченный'): - return - $Label2.text = 'Текущий режим доступа: ограниченный' - for node in $GridContainer.get_children().filter(func(b): return b is Button): - node.disabled = true + $lbl_commit.text = 'Текущая версия ПО УАРЭП: \"%s\"' % commit.VCS_HEAD + if not OS.get_cmdline_args().has('++ограниченный'): + return + $Label2.text = 'Текущий режим доступа: ограниченный' + for node in $GridContainer.get_children().filter(func(b): return b is Button): + node.disabled = true func _on_external_cu_btn_pressed() -> void: - var state = $GridContainer2/external_cu_btn.button_pressed - ProjectSettings.set_setting('application/config/external_cu', state) - if state: - signaller.emit_signal('interfer_off_all') + var state = $GridContainer2/external_cu_btn.button_pressed + ProjectSettings.set_setting('application/config/external_cu', state) + if state: + signaller.emit_signal('interfer_off_all') diff --git a/scenes/работа/sld-mode.gd b/scenes/работа/sld-mode.gd index f8e97d42..dc5e0063 100644 --- a/scenes/работа/sld-mode.gd +++ b/scenes/работа/sld-mode.gd @@ -7,10 +7,10 @@ func _ready(): _on_value_changed(3) func _on_value_changed(val): - val = int(val) - for nm in VAL_TO_LABEL.values(): - var lbl0 = get_node(nm) - lbl0.self_modulate.a = 0.45 - var lbl1 = get_node(VAL_TO_LABEL[val]) - lbl1.self_modulate.a = 1.0 - signaller.emit_signal(VAL_TO_EVENT[val]) + val = int(val) + for nm in VAL_TO_LABEL.values(): + var lbl0 = get_node(nm) + lbl0.self_modulate.a = 0.45 + var lbl1 = get_node(VAL_TO_LABEL[val]) + lbl1.self_modulate.a = 1.0 + signaller.emit_signal(VAL_TO_EVENT[val]) diff --git a/scenes/работа/работа.gd b/scenes/работа/работа.gd index 6e04b6c3..c2da2304 100644 --- a/scenes/работа/работа.gd +++ b/scenes/работа/работа.gd @@ -1,477 +1,492 @@ @tool -extends Panel +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 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 до количества созданных окон +@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 ## Ширина строба по углу в момент начала перетаскивания +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 ## Вызывается в момент завершения перетаскивания +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] } + 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] } + 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] } + 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] } + 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 ## Выключено - } + DRAG, ## В процессе. + IDLE, ## Не активно, ожидание. + OFF ## Выключено. + } -## Состояние перетаскивания +## Состояние перетаскивания. enum BtnSel { - SECTOR, ## В процессе - THREAT, ## Не активно, ожидание - FS ## Выключено - } + 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 + 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) + 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() + 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')) - + 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() + 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 + 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) + 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) + 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() + 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) + 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() + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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 + 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 + 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) + 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) + 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() + 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 +## Обработчик событий ввода. Вызывается 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) + 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 + 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) + 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) + 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) + 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() + 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) + 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) + 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) + 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] + 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() + 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 + 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) + 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) diff --git a/scenes/работа/работа.tscn b/scenes/работа/работа.tscn index b7359562..8c7d6a0f 100644 --- a/scenes/работа/работа.tscn +++ b/scenes/работа/работа.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=14 format=3 uid="uid://b276iygic5itk"] +[gd_scene load_steps=15 format=3 uid="uid://b276iygic5itk"] [ext_resource type="Script" path="res://scenes/работа/работа.gd" id="1_niok4"] [ext_resource type="PackedScene" uid="uid://nl1vklubr5kr" path="res://scenes/bip/bip.tscn" id="2_br3s6"] @@ -18,6 +18,8 @@ resource_local_to_scene = true shader = ExtResource("11_ekapd") shader_parameter/radius = 0.39 +[sub_resource type="ImageTexture" id="ImageTexture_cnmvt"] + [node name="Работа" type="Panel"] script = ExtResource("1_niok4") Bip = ExtResource("2_br3s6") @@ -120,6 +122,33 @@ size_flags_vertical = 3 text = "Подавление" toggle_mode = true +[node name="bt_navig_u" type="TextureButton" parent="."] +layout_mode = 0 +offset_left = 530.0 +offset_top = 428.0 +offset_right = 570.0 +offset_bottom = 468.0 + +[node name="bt_navig_l" type="TextureButton" parent="."] +layout_mode = 0 +offset_left = 410.0 +offset_top = 532.0 +offset_right = 460.0 +offset_bottom = 581.0 +texture_normal = SubResource("ImageTexture_cnmvt") + +[node name="bt_navig_r" type="TextureButton" parent="."] +layout_mode = 0 +offset_left = 651.0 +offset_top = 540.0 +offset_right = 691.0 +offset_bottom = 580.0 + +[node name="bt_navig_d" type="TextureButton" parent="."] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 + [node name="btn_zoom" parent="." instance=ExtResource("9_oey3x")] layout_mode = 0 offset_left = 12.0 diff --git a/scenes/эмс/кнопка-эмс.gd b/scenes/эмс/кнопка-эмс.gd index 37bcaf7d..e8aa9c4a 100644 --- a/scenes/эмс/кнопка-эмс.gd +++ b/scenes/эмс/кнопка-эмс.gd @@ -4,28 +4,28 @@ extends PanelContainer @export var texture_state0: Texture2D = preload('res://data/кнопка-эмс-1.png'): - set(val): $state.set_texture(val) + set(val): $state.set_texture(val) @export var texture_state1: Texture2D = preload('res://data/кнопка-эмс-0.png'): - set(val): $state.set_texture(val) + set(val): $state.set_texture(val) @export var text: String = '': - set(val): $button.set_text(val) - get: return $button.get_text() + set(val): $button.set_text(val) + get: return $button.get_text() @export var pressed: bool = false: - set(val): $button.set_pressed(val) - get: return $button.is_pressed() + set(val): $button.set_pressed(val) + get: return $button.is_pressed() @export var toggle_mode: bool = false: - set(val): - if is_inside_tree(): - $button.set_toggle_mode(val) - get: return $button.is_toggle_mode() + set(val): + if is_inside_tree(): + $button.set_toggle_mode(val) + get: return $button.is_toggle_mode() func set_text (val: String): $button.set_text(val) @@ -33,8 +33,8 @@ func set_pressed (val: bool): $button.set_pressed(val) func set_toggle_mode (val: bool): - if is_inside_tree(): - $button.set_toggle_mode(val) + if is_inside_tree(): + $button.set_toggle_mode(val) func get_text(): return $button.get_text() @@ -43,13 +43,13 @@ func is_toggle_mode(): return $button.is_toggle_mode() func _on_button_toggled(val: bool): - if val: $state.set_texture(texture_state1) - else: $state.set_texture(texture_state0) + if val: $state.set_texture(texture_state1) + else: $state.set_texture(texture_state0) func button_connect(button_signal: String, proc: Callable): - $button.connect(button_signal, proc) + $button.connect(button_signal, proc) func _on_button_mouse_entered(): - emit_signal("mouse_entered") + emit_signal("mouse_entered") diff --git a/scenes/эмс/эмс.gd b/scenes/эмс/эмс.gd index 054309bb..6b948e9b 100644 --- a/scenes/эмс/эмс.gd +++ b/scenes/эмс/эмс.gd @@ -1,6 +1,6 @@ -extends Panel +class_name ems extends Panel -# Предзагрузка ячеек таблиц +## Предзагрузка ячеек таблиц. const TableHeader = preload('res://table/header.tscn') const CellYemsButton = preload('res://scenes/эмс/кнопка-эмс.tscn') const CellLineEdit = preload('res://table/ячейка-2.tscn') @@ -10,7 +10,7 @@ const CellLEEmpty = preload('res://scenes/эмс/line-edit-empty.tscn') const CellFront = preload('res://scenes/cell/cell-front.tscn') const CellFrontRear = preload('res://scenes/cell/cell-front-rear.tscn') -# Режимы работы выходов +## Режимы работы выходов. const OUT_MODE: Array = ['Работа', 'Контроль', '1', '0'] # const COLUMN_OPTS_BTN: Array = [5] const TABLE_ENTRY_COLUMNS: Array = [2,3] @@ -18,339 +18,347 @@ const OUT_SET_ROW: Array = [CellLineEdit, CellLEEmpty, CellLEEmpty, CellLEEmpty, const IN_SET_ROW: Array = [CellLineEdit, CellLEEmpty, CellLEEmpty, CellLEEmpty, CellLEEmpty] -var g_boards: Dictionary # Словарь плат ЭМС -var posx: int = 125 # Позиция элементов по x -var posy: int = 70 # Позиция элементов по y +var g_boards: Dictionary ## Словарь плат ЭМС. +var posx: int = 125 ## Позиция элементов по x. +var posy: int = 70 ## Позиция элементов по y. func _ready() -> void: - call_deferred('init_boards') + call_deferred('init_boards') -## Инициализация основных элементов экрана ЭМС +## Инициализация основных элементов экрана ЭМС. func init_boards(): - # Выставление позиций элементов ЭМС на экране - $scrollin.set_position(Vector2(posx,posy)) - $scrollout.set_position(Vector2(posx+650,posy)) - $scrl_in_set.set_position(Vector2(posx,posy + 700)) - $scrl_out_set.set_position(Vector2(posx+650,posy + 700)) - $lbl_online.set_position(Vector2(posx,posy-60)) - $btn_flash_read.set_position(Vector2(posx,posy + 900)) - $btn_flash_write.set_position(Vector2(posx,posy+ 935)) - $btn_connect.set_position(Vector2(posx+590,posy-25)) - $btn_disconnect.set_position(Vector2(posx+587,posy + 675)) + # Выставление позиций элементов ЭМС на экране + $scrollin.set_position(Vector2(posx,posy)) + $scrollout.set_position(Vector2(posx+650,posy)) + $scrl_in_set.set_position(Vector2(posx,posy + 700)) + $scrl_out_set.set_position(Vector2(posx+650,posy + 700)) + $lbl_online.set_position(Vector2(posx,posy-60)) + $btn_flash_read.set_position(Vector2(posx,posy + 900)) + $btn_flash_write.set_position(Vector2(posx,posy+ 935)) + $btn_connect.set_position(Vector2(posx+590,posy-25)) + $btn_disconnect.set_position(Vector2(posx+587,posy + 675)) - g_boards['КЭМС'] = yemsboards.EmsBoard.new('КЭМС', 0x130, yemsconsts.INPUT_ROWS, yemsconsts.OUTPUT_ROWS) - g_boards['П5-28'] = yemsboards.EmsBoard.new('П5-28', 0x140, yemsconsts.INPUT_ROWS1, yemsconsts.OUTPUT_ROWS1) - init_tbl_in() - $scrollin/tbl_in.pin_header($scrollin, self) - init_tbl_out() - $scrollout/tbl_out.pin_header($scrollout, self) - $scrl_in_set/tbl_in_set.pin_header($scrl_in_set, self) - $scrl_out_set/tbl_out_set.pin_header($scrl_out_set, self) - init_tbl_files() - $scrl_files/tbl_files.pin_header($scrl_files, self) - $btn_connect.connect('pressed', Callable(self, 'on_btn_connect')) - $btn_disconnect.connect('pressed', Callable(self, 'on_btn_disconnect')) - $btn_flash_read.button_connect('pressed', Callable(self, 'on_btn_flash_read').bind($btn_flash_read)) - $btn_flash_write.button_connect('pressed', Callable(self, 'on_btn_flash_write').bind($btn_flash_write)) + g_boards['КЭМС'] = yemsboards.EmsBoard.new('КЭМС', 0x130, yemsconsts.INPUT_ROWS, yemsconsts.OUTPUT_ROWS) + g_boards['П5-28'] = yemsboards.EmsBoard.new('П5-28', 0x140, yemsconsts.INPUT_ROWS1, yemsconsts.OUTPUT_ROWS1) + init_tbl_in() + $scrollin/tbl_in.pin_header($scrollin, self) + init_tbl_out() + $scrollout/tbl_out.pin_header($scrollout, self) + $scrl_in_set/tbl_in_set.pin_header($scrl_in_set, self) + $scrl_out_set/tbl_out_set.pin_header($scrl_out_set, self) + init_tbl_files() + $scrl_files/tbl_files.pin_header($scrl_files, self) + $btn_connect.connect('pressed', Callable(self, 'on_btn_connect')) + $btn_disconnect.connect('pressed', Callable(self, 'on_btn_disconnect')) + $btn_flash_read.button_connect('pressed', Callable(self, 'on_btn_flash_read').bind($btn_flash_read)) + $btn_flash_write.button_connect('pressed', Callable(self, 'on_btn_flash_write').bind($btn_flash_write)) ## Обработчик нажатия кнопки disconnect. func on_btn_disconnect(): - var selected_rows_in: Array = [] - var selected_rows_out: Array = [] - $scrl_in_set/tbl_in_set.get_selected_rows(selected_rows_in) - $scrl_out_set/tbl_out_set.get_selected_rows(selected_rows_out) - if len(selected_rows_in): - on_disconnect($scrl_in_set/tbl_in_set, selected_rows_in, 'вход') - elif len(selected_rows_out): - on_disconnect($scrl_out_set/tbl_out_set, selected_rows_out, 'выход') + var selected_rows_in: Array = [] + var selected_rows_out: Array = [] + $scrl_in_set/tbl_in_set.get_selected_rows(selected_rows_in) + $scrl_out_set/tbl_out_set.get_selected_rows(selected_rows_out) + if len(selected_rows_in): + on_disconnect($scrl_in_set/tbl_in_set, selected_rows_in, 'вход') + elif len(selected_rows_out): + on_disconnect($scrl_out_set/tbl_out_set, selected_rows_out, 'выход') -## Разрывает связь входа и выхода, [param tbl] - таблица, [param selected_rows] - выбранные строки -## [param type_dev] - тип, 'вход' или 'выход' +## Разрывает связь входа и выхода, [param tbl] - таблица, [param selected_rows] - выбранные строки. +## [param type_dev] - тип, 'вход' или 'выход'. func on_disconnect(tbl, selected_rows, type_dev: String): - var dev = tbl.get_node_user_data(0, 0) - var user_data: Array = tbl.get_node_user_data(0, selected_rows[0]) - var con_dev = user_data[0] - var connector: String = con_dev.connector - dev.connect_devs.erase(con_dev.connector) - con_dev.connect_devs.erase(dev.connector) - if type_dev == 'вход': - set_in_dev(dev) - set_out_dev(con_dev) - elif type_dev == 'выход': - set_in_dev(con_dev) - set_out_dev(dev) + var dev = tbl.get_node_user_data(0, 0) + var user_data: Array = tbl.get_node_user_data(0, selected_rows[0]) + var con_dev = user_data[0] + var connector: String = con_dev.connector + dev.connect_devs.erase(con_dev.connector) + con_dev.connect_devs.erase(dev.connector) + if type_dev == 'вход': + set_in_dev(dev) + set_out_dev(con_dev) + elif type_dev == 'выход': + set_in_dev(con_dev) + set_out_dev(dev) -## Обработчик нажатия кнопки "Прочитать" +## Обработчик нажатия кнопки "Прочитать". func on_btn_flash_read(btn): - await get_tree().create_timer(0.1).timeout - btn.pressed = false + await get_tree().create_timer(0.1).timeout + btn.pressed = false -## Обработчик нажатия кнопки "Записать" +## Обработчик нажатия кнопки "Записать". func on_btn_flash_write(btn): - await get_tree().create_timer(0.1).timeout - btn.pressed = false + await get_tree().create_timer(0.1).timeout + btn.pressed = false -## Инициализация таблицы с файлами настроек ЭМС +## Инициализация таблицы с файлами настроек ЭМС. func init_tbl_files(): - $scrl_files/tbl_files.set_header([TableHeader, TableHeader, TableHeader]) - $scrl_files/tbl_files.set_header_text(['Имя файла', 'Дата изменения', 'Размер']) - $scrl_files/tbl_files.set_columns_min_size([200, 120, 70]) + $scrl_files/tbl_files.set_header([TableHeader, TableHeader, TableHeader]) + $scrl_files/tbl_files.set_header_text(['Имя файла', 'Дата изменения', 'Размер']) + $scrl_files/tbl_files.set_columns_min_size([200, 120, 70]) -## Инициализация таблиц входов +## Инициализация таблиц входов. func init_tbl_in(): - # Инициализация основной таблицы входов, в ней отображается информация о параметрах и состоянии - var header_type: Array = [TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader] - var header_text: Array = ['Входы', 'Соединитель', 'мкс', 'мкс', 'Состояние'] - var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState] - var yams_alligment_in: Array = [ HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER] - var column_size: Array = [250, 100, 70, 70, 50] - $scrollin/tbl_in.set_header(header_type) - $scrollin/tbl_in.set_header_text(header_text) - for board in g_boards: - for item in g_boards[board].in_tbl: - $scrollin/tbl_in.add_row(row_type) - var row_index : int = $scrollin/tbl_in.get_rows_count() - 1 - var params : Array = item[1] - var in_dev: yemsdevs.InDev = yemsdevs.InDev.new(item[0], params, row_index) - in_dev.board = board - for i in range(len(row_type)): - if i < len(params): - var node = $scrollin/tbl_in.get_node2(i, row_index) - node.text = params[i] - node.editable = false - $scrollin/tbl_in.set_node_user_data(i, row_index, [in_dev, board]) - $scrollin/tbl_in.set_columns_alignments(yams_alligment_in) - $scrollin/tbl_in.set_columns_min_size(column_size) - $scrollin/tbl_in.connect('row_pressed', Callable(self, 'on_row_pressed_in')) - $scrollin/tbl_in.connect('selected_changed', Callable(self, 'on_selected_changed_in')) + # Инициализация основной таблицы входов, в ней отображается информация о параметрах и состоянии + var header_type: Array = [TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader] + var header_text: Array = ['Входы', 'Соединитель', 'мкс', 'мкс', 'Состояние'] + var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState] + var yams_alligment_in: Array = [ HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER] + var column_size: Array = [250, 100, 70, 70, 50] + $scrollin/tbl_in.set_header(header_type) + $scrollin/tbl_in.set_header_text(header_text) + for board in g_boards: + for item in g_boards[board].in_tbl: + $scrollin/tbl_in.add_row(row_type) + var row_index : int = $scrollin/tbl_in.get_rows_count() - 1 + var params : Array = item[1] + var in_dev: yemsdevs.InDev = yemsdevs.InDev.new(item[0], params, row_index) + in_dev.board = board + for i in range(len(row_type)): + if i < len(params): + var node = $scrollin/tbl_in.get_node2(i, row_index) + node.text = params[i] + node.editable = false + $scrollin/tbl_in.set_node_user_data(i, row_index, [in_dev, board]) + $scrollin/tbl_in.set_columns_alignments(yams_alligment_in) + $scrollin/tbl_in.set_columns_min_size(column_size) + $scrollin/tbl_in.connect('row_pressed', Callable(self, 'on_row_pressed_in')) + $scrollin/tbl_in.connect('selected_changed', Callable(self, 'on_selected_changed_in')) - # Инициализация таблицы изменения параметров входа и списка выходов связанных с ним - header_text[0] = 'Вход' - $scrl_in_set/tbl_in_set.set_header(header_type) - $scrl_in_set/tbl_in_set.set_header_text(header_text) - $scrl_in_set/tbl_in_set.set_columns_alignments(yams_alligment_in) - $scrl_in_set/tbl_in_set.set_columns_min_size(column_size) - $scrl_in_set/tbl_in_set.connect('row_pressed', Callable(self, 'on_row_pressed_si')) - $scrl_in_set/tbl_in_set.connect('selected_changed', Callable(self, 'on_selected_changed_si')) + # Инициализация таблицы изменения параметров входа и списка выходов связанных с ним + header_text[0] = 'Вход' + $scrl_in_set/tbl_in_set.set_header(header_type) + $scrl_in_set/tbl_in_set.set_header_text(header_text) + $scrl_in_set/tbl_in_set.set_columns_alignments(yams_alligment_in) + $scrl_in_set/tbl_in_set.set_columns_min_size(column_size) + $scrl_in_set/tbl_in_set.connect('row_pressed', Callable(self, 'on_row_pressed_si')) + $scrl_in_set/tbl_in_set.connect('selected_changed', Callable(self, 'on_selected_changed_si')) -## Обработчик редактирования Entry в таблице параметров входов/выходов +## Обработчик редактирования Entry в таблице параметров входов/выходов. func on_edit_entry(text : String, entry): - print_debug(text, entry) + print_debug(text, entry) -## Обработчик выбора строки в таблице входов +## Обработчик выбора строки в таблице входов. func on_selected_changed_in(i_row: int): - var selecter_rows: Array = [] - $scrollin/tbl_in.get_selected_rows(selecter_rows) - var user_data = $scrollin/tbl_in.get_node_user_data(0, i_row) - var dev = user_data[0] - set_in_dev(dev) + var selecter_rows: Array = [] + $scrollin/tbl_in.get_selected_rows(selecter_rows) + var user_data = $scrollin/tbl_in.get_node_user_data(0, i_row) + var dev = user_data[0] + set_in_dev(dev) -## Обработчик нажатия на таблицу входов +## Обработчик нажатия на таблицу входов. func on_row_pressed_in(i_row: int): - on_row_pressed(i_row, $scrollin/tbl_in) - on_selected_changed_in(i_row) + on_row_pressed(i_row, $scrollin/tbl_in) + on_selected_changed_in(i_row) -## Выбор входного устройства, для отображения в таблице соединений входа и изменения параметров +## Выбор входного устройства, для отображения в таблице соединений входа и изменения параметров. func set_in_dev(dev): - var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState] - set_dev($scrl_in_set/tbl_in_set, dev, row_type, IN_SET_ROW, 'Список соединённых выходов :', [250, 100, 70, 70, 70]) + var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState] + set_dev($scrl_in_set/tbl_in_set, dev, row_type, IN_SET_ROW, 'Список соединённых выходов :', [250, 100, 70, 70, 70]) -## Обработчик выбора строки в таблице соединений входа и изменения параметров +## Обработчик выбора строки в таблице соединений входа и изменения параметров. func on_selected_changed_si(i_row: int): - if i_row < 2: - return - var out_user_data = $scrl_in_set/tbl_in_set.get_node_user_data(0, i_row) - var dev = out_user_data[0] - var connector = dev.connector - for i in range($scrollout/tbl_out.get_rows_count()): - var node = $scrollout/tbl_out.get_node2(1, i) - if connector == node.text: - on_row_pressed_out(i) + if i_row < 2: + return + var out_user_data = $scrl_in_set/tbl_in_set.get_node_user_data(0, i_row) + var dev = out_user_data[0] + var connector = dev.connector + for i in range($scrollout/tbl_out.get_rows_count()): + var node = $scrollout/tbl_out.get_node2(1, i) + if connector == node.text: + on_row_pressed_out(i) -## Обработчик нажатия на таблицу соединений входа и изменения параметров +## Обработчик нажатия на таблицу соединений входа и изменения параметров. func on_row_pressed_si(i_row: int): - if i_row < 2: - return - on_row_pressed(i_row, $scrl_in_set/tbl_in_set) - on_selected_changed_si(i_row) + if i_row < 2: + return + on_row_pressed(i_row, $scrl_in_set/tbl_in_set) + on_selected_changed_si(i_row) -## Инициализация таблиц выходов +## Инициализация таблиц выходов. func init_tbl_out(): - # Инициализация основной таблицы выходов, в ней отображается информация о параметрах и состоянии - var header_text = ['Выходы', 'Соединитель', 'мкс', 'мкс', 'Состояние', 'Режим'] - var yams_alligment_out: Array = [ HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER] - $scrollout/tbl_out.set_header([TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader, TableHeader]) - $scrollout/tbl_out.set_header_text(header_text) - for board in g_boards: - for item in g_boards[board].out_tbl: - $scrollout/tbl_out.add_row([CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState, CellLineEdit]) - var row_index : int = $scrollout/tbl_out.get_rows_count() - 1 - var params : Array = item[1] - var out_dev = yemsdevs.OutDev.new(item[0], params, row_index) - out_dev.board = board - for i in range(len(header_text)): - var cell = $scrollout/tbl_out.get_node2(i, row_index) - if i < len(params): - cell.text = params[i] - cell.editable = false - $scrollout/tbl_out.set_node_user_data(i, row_index, [out_dev, board]) - if i in COLUMN_OPTS_BTN: - cell.text = out_dev.mode - $scrollout/tbl_out.set_columns_min_size([250, 100, 70, 70, 70, 100]) - $scrollout/tbl_out.set_columns_alignments(yams_alligment_out) - $scrollout/tbl_out.connect('row_pressed', Callable(self, 'on_row_pressed_out')) - $scrollout/tbl_out.connect('selected_changed', Callable(self, 'on_selected_changed_out')) + # Инициализация основной таблицы выходов, в ней отображается информация о параметрах и состоянии + var header_text = ['Выходы', 'Соединитель', 'мкс', 'мкс', 'Состояние', 'Режим'] + var yams_alligment_out: Array = [ HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER] + $scrollout/tbl_out.set_header([TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader, TableHeader]) + $scrollout/tbl_out.set_header_text(header_text) + for board in g_boards: + for item in g_boards[board].out_tbl: + $scrollout/tbl_out.add_row([CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState, CellLineEdit]) + var row_index : int = $scrollout/tbl_out.get_rows_count() - 1 + var params : Array = item[1] + var out_dev = yemsdevs.OutDev.new(item[0], params, row_index) + out_dev.board = board + for i in range(len(header_text)): + var cell = $scrollout/tbl_out.get_node2(i, row_index) + if i < len(params): + cell.text = params[i] + cell.editable = false + $scrollout/tbl_out.set_node_user_data(i, row_index, [out_dev, board]) + if i in COLUMN_OPTS_BTN: + cell.text = out_dev.mode + $scrollout/tbl_out.set_columns_min_size([250, 100, 70, 70, 70, 100]) + $scrollout/tbl_out.set_columns_alignments(yams_alligment_out) + $scrollout/tbl_out.connect('row_pressed', Callable(self, 'on_row_pressed_out')) + $scrollout/tbl_out.connect('selected_changed', Callable(self, 'on_selected_changed_out')) - # Инициализация таблицы изменения параметров выхода и списка входов связанных с ним - header_text[0] = 'Выход' - $scrl_out_set/tbl_out_set.set_header([TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader, TableHeader]) - $scrl_out_set/tbl_out_set.set_header_text(header_text) - $scrl_out_set/tbl_out_set.set_columns_min_size([250, 100, 70, 70, 70, 100]) - $scrl_out_set/tbl_out_set.connect('row_pressed', Callable(self, 'on_row_pressed_so')) - $scrl_out_set/tbl_out_set.connect('selected_changed', Callable(self, 'on_selected_changed_so')) + # Инициализация таблицы изменения параметров выхода и списка входов связанных с ним + header_text[0] = 'Выход' + $scrl_out_set/tbl_out_set.set_header([TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader, TableHeader]) + $scrl_out_set/tbl_out_set.set_header_text(header_text) + $scrl_out_set/tbl_out_set.set_columns_min_size([250, 100, 70, 70, 70, 100]) + $scrl_out_set/tbl_out_set.connect('row_pressed', Callable(self, 'on_row_pressed_so')) + $scrl_out_set/tbl_out_set.connect('selected_changed', Callable(self, 'on_selected_changed_so')) -## Обработчик выбора строки в таблице соединений выхода и изменения параметров +## Обработчик выбора строки в таблице соединений выхода и изменения параметров. func on_selected_changed_so(i_row: int): - if i_row < 2: - return - var in_user_data = $scrl_out_set/tbl_out_set.get_node_user_data(0, i_row) - var dev = in_user_data[0] - var connector = dev.connector - for i in range($scrollin/tbl_in.get_rows_count()): - var node = $scrollin/tbl_in.get_node2(1, i) - if connector == node.text: - on_row_pressed_in(i) + if i_row < 2: + return + var in_user_data = $scrl_out_set/tbl_out_set.get_node_user_data(0, i_row) + var dev = in_user_data[0] + var connector = dev.connector + for i in range($scrollin/tbl_in.get_rows_count()): + var node = $scrollin/tbl_in.get_node2(1, i) + if connector == node.text: + on_row_pressed_in(i) -## Обработчик нажатия на таблицу соединений выхода и изменения параметров +## Обработчик нажатия на таблицу соединений выхода и изменения параметров. func on_row_pressed_so(i_row: int): - if i_row < 2: - return - on_row_pressed(i_row, $scrl_out_set/tbl_out_set) - on_selected_changed_so(i_row) + if i_row < 2: + return + on_row_pressed(i_row, $scrl_out_set/tbl_out_set) + on_selected_changed_so(i_row) -## Обработчик выбора строки в таблице выходов +## Обработчик выбора строки в таблице выходов. func on_selected_changed_out(i_row: int): - var selecter_rows: Array = [] - $scrollout/tbl_out.get_selected_rows(selecter_rows) - var user_data = $scrollout/tbl_out.get_node_user_data(0, i_row) - var dev = user_data[0] - set_out_dev(dev) + var selecter_rows: Array = [] + $scrollout/tbl_out.get_selected_rows(selecter_rows) + var user_data = $scrollout/tbl_out.get_node_user_data(0, i_row) + var dev = user_data[0] + set_out_dev(dev) -## Обработчик выбора строки в таблице выходов +## Обработчик выбора строки в таблице выходов. func on_row_pressed_out(i_row: int): - on_row_pressed(i_row, $scrollout/tbl_out) - on_selected_changed_out(i_row) + on_row_pressed(i_row, $scrollout/tbl_out) + on_selected_changed_out(i_row) -## Выбор выходного устройства, для отображения в таблице соединений выхода и изменения параметров +## Выбор выходного устройства, для отображения в таблице соединений выхода и изменения параметров. func set_out_dev(dev): - var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState, CellOptBtn] - set_dev($scrl_out_set/tbl_out_set, dev, row_type, OUT_SET_ROW, 'Список соединённых входов :', [250, 100, 70, 70, 70, 100]) - var mode = $scrl_out_set/tbl_out_set.get_node2(5, 0) - for opt in OUT_MODE: - mode.add_item(opt) - var mode_index: int = OUT_MODE.find(dev.mode) - if mode_index != -1: - mode.select(mode_index) + var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState, CellOptBtn] + set_dev($scrl_out_set/tbl_out_set, dev, row_type, OUT_SET_ROW, 'Список соединённых входов :', [250, 100, 70, 70, 70, 100]) + var mode = $scrl_out_set/tbl_out_set.get_node2(5, 0) + for opt in OUT_MODE: + mode.add_item(opt) + var mode_index: int = OUT_MODE.find(dev.mode) + if mode_index != -1: + mode.select(mode_index) -## Выбор входного или выходного устройства [param tbl] - таблица, [param dev] - устройство, -## [param row_type] - массив с типами колонок, [param row_type_conn] - массив с пустыми LineEdit -## [param lbl_text] - текст отображаемый во 2 строке: пример: ('Список соединённых входов :') +## Выбор входного или выходного устройства.[br] +## [param tbl] - таблица,[br] +## [param dev] - устройство,[br] +## [param row_type] - массив с типами колонок,[br] +## [param row_type_conn] - массив с пустыми LineEdit,[br] +## [param lbl_text] - текст отображаемый во 2 строке: пример: ('Список соединённых входов :').[br] func set_dev(tbl, dev, row_type, row_type_conn, lbl_text, row_size): - tbl.clear_rows() - tbl.add_row(row_type) - tbl.set_columns_min_size(row_size) - var le_name: LineEdit = tbl.get_node2(0, 0) - le_name.editable = false - le_name.text = dev.dev_name - var connector: LineEdit = tbl.get_node2(1, 0) - connector.editable = false - connector.text = dev.connector - var delay: LineEdit = tbl.get_node2(2, 0) - delay.text = '%4.2f'%dev.delay - var offset: LineEdit = tbl.get_node2(3, 0) - offset.text = '%4.2f'%dev.offset - var state = tbl.get_node2(4, 0) - state.set_frame(dev.state) - tbl.add_row(row_type_conn) - var lbl: LineEdit = tbl.get_node2(0, 1) - lbl.text = lbl_text - for i in len(row_type_conn): - var le: LineEdit = tbl.get_node2(i, 1) - tbl.set_node_user_data(i, 0, dev) - le.editable = false + tbl.clear_rows() + tbl.add_row(row_type) + tbl.set_columns_min_size(row_size) + var le_name: LineEdit = tbl.get_node2(0, 0) + le_name.editable = false + le_name.text = dev.dev_name + var connector: LineEdit = tbl.get_node2(1, 0) + connector.editable = false + connector.text = dev.connector + var delay: LineEdit = tbl.get_node2(2, 0) + delay.text = '%4.2f'%dev.delay + var offset: LineEdit = tbl.get_node2(3, 0) + offset.text = '%4.2f'%dev.offset + var state = tbl.get_node2(4, 0) + state.set_frame(dev.state) + tbl.add_row(row_type_conn) + var lbl: LineEdit = tbl.get_node2(0, 1) + lbl.text = lbl_text + for i in len(row_type_conn): + var le: LineEdit = tbl.get_node2(i, 1) + tbl.set_node_user_data(i, 0, dev) + le.editable = false - for i in dev.connect_devs: - var dev_con = dev.connect_devs[i][0] - tbl.add_row(row_type_conn) - var node_index: Array = [0, tbl.get_rows_count() -1] - var le_name_out: LineEdit = tbl.get_node2(node_index[0], node_index[1]) - disable_edit(tbl, len(row_type_conn), node_index[1]) - le_name_out.text = dev_con.dev_name - tbl.set_node_user_data(node_index[0], node_index[1], dev.connect_devs[i]) - tbl.connect_columns(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, []) + for i in dev.connect_devs: + var dev_con = dev.connect_devs[i][0] + tbl.add_row(row_type_conn) + var node_index: Array = [0, tbl.get_rows_count() -1] + var le_name_out: LineEdit = tbl.get_node2(node_index[0], node_index[1]) + disable_edit(tbl, len(row_type_conn), node_index[1]) + le_name_out.text = dev_con.dev_name + tbl.set_node_user_data(node_index[0], node_index[1], dev.connect_devs[i]) + tbl.connect_columns(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, []) -## Обработчик нажатия кнопки connect +## Обработчик нажатия кнопки connect. func on_btn_connect(): - var in_row_index: Array = [] - var out_row_index: Array = [] - $scrollin/tbl_in.get_selected_rows(in_row_index) - $scrollout/tbl_out.get_selected_rows(out_row_index) - if len(in_row_index) and len(out_row_index): - var in_user_data = $scrollin/tbl_in.get_node_user_data(0, in_row_index[0]) - var out_user_data = $scrollout/tbl_out.get_node_user_data(0, out_row_index[0]) - var in_dev = in_user_data[0] - var out_dev = out_user_data[0] - add_connection_dev($scrl_out_set/tbl_out_set, in_dev, out_dev, OUT_SET_ROW, in_user_data) - add_connection_dev($scrl_in_set/tbl_in_set, out_dev, in_dev, IN_SET_ROW, out_user_data) + var in_row_index: Array = [] + var out_row_index: Array = [] + $scrollin/tbl_in.get_selected_rows(in_row_index) + $scrollout/tbl_out.get_selected_rows(out_row_index) + if len(in_row_index) and len(out_row_index): + var in_user_data = $scrollin/tbl_in.get_node_user_data(0, in_row_index[0]) + var out_user_data = $scrollout/tbl_out.get_node_user_data(0, out_row_index[0]) + var in_dev = in_user_data[0] + var out_dev = out_user_data[0] + add_connection_dev($scrl_out_set/tbl_out_set, in_dev, out_dev, OUT_SET_ROW, in_user_data) + add_connection_dev($scrl_in_set/tbl_in_set, out_dev, in_dev, IN_SET_ROW, out_user_data) -## образовывает связь между выбранным входом и выходом [param tbl] - таблица, [param dev1] - устройство1, -## [param dev2] - устройство 2, [param set_row] - массив с пустыми LineEdit -## [param user_data] - пользовательские данные устройства1 +## Образовывает связь между выбранным входом и выходом.[br] +## [param tbl] - таблица,[br] +## [param dev1] - устройство1,[br] +## [param dev2] - устройство 2,[br] +## [param set_row] - массив с пустыми LineEdit,[br] +## [param user_data] - пользовательские данные устройства1.[br] func add_connection_dev(tbl, dev1, dev2, set_row, user_data): - if not dev1.connector in dev2.connect_devs: - tbl.add_row(set_row) - var node_index: Array = [0, tbl.get_rows_count() -1] - var le_name: LineEdit = tbl.get_node2(node_index[0], node_index[1]) - le_name.text = dev1.connector - disable_edit(tbl, len(set_row), node_index[1]) - tbl.set_node_user_data(node_index[0], node_index[1], user_data) - dev2.connect_devs[dev1.connector] = user_data + if not dev1.connector in dev2.connect_devs: + tbl.add_row(set_row) + var node_index: Array = [0, tbl.get_rows_count() -1] + var le_name: LineEdit = tbl.get_node2(node_index[0], node_index[1]) + le_name.text = dev1.connector + disable_edit(tbl, len(set_row), node_index[1]) + tbl.set_node_user_data(node_index[0], node_index[1], user_data) + dev2.connect_devs[dev1.connector] = user_data -## Отключает возможность редактирования LineEdit в таблице [param tbl] - таблица, -## [param num_col] - номер колонки, [param i_row] - номер столбца +## Отключает возможность редактирования LineEdit в таблице.[br] +## [param tbl] - таблица,[br] +## [param num_col] - номер колонки,[br] +## [param i_row] - номер столбца.[br] func disable_edit(tbl, num_col: int, i_row: int): - for col in range(num_col): - var node: LineEdit = tbl.get_node2(col, i_row) - node.editable = false + for col in range(num_col): + var node: LineEdit = tbl.get_node2(col, i_row) + node.editable = false -## Обработчик выбора строки с таблице +## Обработчик выбора строки с таблице. func on_row_pressed(i_row: int, tbl): - tbl.clear_rows_selected() - var is_row_selected = tbl.is_row_selected(i_row) - tbl.set_row_selected(i_row, not is_row_selected) + tbl.clear_rows_selected() + var is_row_selected = tbl.is_row_selected(i_row) + tbl.set_row_selected(i_row, not is_row_selected) diff --git a/scripts/capsrpb.gd b/scripts/capsrpb.gd index bf790dac..e4f4491d 100644 --- a/scripts/capsrpb.gd +++ b/scripts/capsrpb.gd @@ -1,50 +1,50 @@ -extends Node +class_name STC extends Node -## Реализация "Протокол информационного сопряжения -## СПО АСУ изделия «МП‑550» с СПО «Управления КАПС РПБ»" +## Реализация "Протокол информационного сопряжения. +## СПО АСУ изделия «МП‑550» с СПО «Управления КАПС РПБ». -const ONLINE_TIMEOUT = 3000 ## Время ожидания пакета от КАПС РПБ, мс -const BUFFER_SIZE = 2048 ## Размер приёмного буфера для датаграмм +const ONLINE_TIMEOUT = 3000 ## Время ожидания пакета от КАПС РПБ, мс. +const BUFFER_SIZE = 2048 ## Размер приёмного буфера для датаграмм. class CapsRpb: - signal line_changed(unit: CapsRpb) ## Сигнал состояние связи изменилось - signal data_received(unit: CapsRpb) ## Сигнал данные приняты - signal command_fail(unit: CapsRpb) ## Сигнал при не выполнении команды - signal parse_error(unit: CapsRpb, msg: String) ## Сигнал ошибки разбора сообщения + signal line_changed(unit: CapsRpb) ## Сигнал состояние связи изменилось. + signal data_received(unit: CapsRpb) ## Сигнал данные приняты. + signal command_fail(unit: CapsRpb) ## Сигнал при не выполнении команды. + signal parse_error(unit: CapsRpb, msg: String) ## Сигнал ошибки разбора сообщения. - static var json_conv: = JSON.new() - var online: = false ## Состояние связи с источником сообщений - var name: String ## Имя экземпляра - var json_dic: Dictionary ## Аппарат для разбора сообщений - var tick: = 0 ## Тик время последнего обновления, мс - var tx_data: = PackedByteArray() ## Пакет для отправки - var tx_stack: Array ## Массив пакетов для отправки + static var json_conv: = JSON.new() + var online: = false ## Состояние связи с источником сообщений. + var name: String ## Имя экземпляра. + var json_dic: Dictionary ## Аппарат для разбора сообщений. + var tick: = 0 ## Тик время последнего обновления, мс. + var tx_data: = PackedByteArray() ## Пакет для отправки. + var tx_stack: Array ## Массив пакетов для отправки. - func _to_string() -> String: return String('капсрпб: "%s" %s ' % [self.name, ['отключен', 'на связи'][int(online)]]) - func _init(nm): self.name = nm + func _to_string() -> String: return String('капсрпб: "%s" %s ' % [self.name, ['отключен', 'на связи'][int(online)]]) + func _init(nm): self.name = nm - func parse(data: PackedByteArray, now_tick: int): - tick = now_tick - if not online: - online = true - emit_signal('line_changed', self) - var utf8_data = data.get_string_from_utf8() - if Error.OK == json_conv.parse(utf8_data): - json_dic.merge(json_conv.get_data(), true) - emit_signal('data_received', self) - else: - var msg = json_conv.get_error_message() - emit_signal('parse_error', self, msg) + func parse(data: PackedByteArray, now_tick: int): + tick = now_tick + if not online: + online = true + emit_signal('line_changed', self) + var utf8_data = data.get_string_from_utf8() + if Error.OK == json_conv.parse(utf8_data): + json_dic.merge(json_conv.get_data(), true) + emit_signal('data_received', self) + else: + var msg = json_conv.get_error_message() + emit_signal('parse_error', self, msg) - func process(now_tick: int): - if online and ((now_tick - tick) > ONLINE_TIMEOUT): - online = false - emit_signal('line_changed', self) - if len(tx_stack): - tx_data = tx_stack[0] - tx_stack.remove_at(0) - return Error.OK - else: - return Error.ERR_UNAVAILABLE + func process(now_tick: int): + if online and ((now_tick - tick) > ONLINE_TIMEOUT): + online = false + emit_signal('line_changed', self) + if len(tx_stack): + tx_data = tx_stack[0] + tx_stack.remove_at(0) + return Error.OK + else: + return Error.ERR_UNAVAILABLE diff --git a/scripts/file-table.gd b/scripts/file-table.gd index d2012c5d..5b734926 100644 --- a/scripts/file-table.gd +++ b/scripts/file-table.gd @@ -9,30 +9,30 @@ var FILES_ROWS_ALIGNMENT = [ HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNM func fill_files_table(tbl: table, folder: String, rows_types: Array): - var dir: = DirAccess.open(folder) - if dir == null: - return - var files: = [] - var exclude_names: = ['.', '..'] - dir.list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547 - while true: - var file: = dir.get_next() - if file == '': - break - if file in exclude_names: - continue - var file_name = folder + '/' + file - var fd = FileAccess.open(file_name, FileAccess.READ) - if not fd: - continue - var glob_path = ProjectSettings.globalize_path(file_name) - var sz = fd.get_length() - var ut = fd.get_modified_time(file_name) - fd.close() - var mt = Time.get_datetime_dict_from_unix_time(ut) - var file_row = [file, '%d' % sz, '%d-%02d-%02d %02d:%02d' % [mt.year, mt.month, mt.day, mt.hour, mt.minute]] - tbl.add_row(rows_types) - var i_row = tbl.get_rows_count() - 1 - tbl.set_row_text(i_row, file_row) - tbl.set_node_meta(0, i_row, 'file_path', glob_path) - dir.list_dir_end() + var dir: = DirAccess.open(folder) + if dir == null: + return + var files: = [] + var exclude_names: = ['.', '..'] + dir.list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547 + while true: + var file: = dir.get_next() + if file == '': + break + if file in exclude_names: + continue + var file_name = folder + '/' + file + var fd = FileAccess.open(file_name, FileAccess.READ) + if not fd: + continue + var glob_path = ProjectSettings.globalize_path(file_name) + var sz = fd.get_length() + var ut = fd.get_modified_time(file_name) + fd.close() + var mt = Time.get_datetime_dict_from_unix_time(ut) + var file_row = [file, '%d' % sz, '%d-%02d-%02d %02d:%02d' % [mt.year, mt.month, mt.day, mt.hour, mt.minute]] + tbl.add_row(rows_types) + var i_row = tbl.get_rows_count() - 1 + tbl.set_row_text(i_row, file_row) + tbl.set_node_meta(0, i_row, 'file_path', glob_path) + dir.list_dir_end() diff --git a/scripts/hotkeys.gd b/scripts/hotkeys.gd index a75efc97..a01762c6 100644 --- a/scripts/hotkeys.gd +++ b/scripts/hotkeys.gd @@ -1,20 +1,20 @@ -extends Node +class_name HotKeys extends Node func _ready() -> void: - signaller.connect('full_screen', Callable(self, 'toggle_full_screen').bind(0)) + signaller.connect('full_screen', Callable(self, 'toggle_full_screen').bind(0)) func _input(event: InputEvent) -> void: - if event is InputEventKey: - if event.pressed and event.physical_keycode == KEY_F11: - signaller.emit_signal('full_screen') + if event is InputEventKey: + if event.pressed and event.physical_keycode == KEY_F11: + signaller.emit_signal('full_screen') -## Переключает режим окна программы полный - обычный экран +## Переключает режим окна программы полный - обычный экран. func toggle_full_screen(id: int) -> void: - var mode = DisplayServer.window_get_mode(id) - mode = DisplayServer.WINDOW_MODE_WINDOWED \ - if mode == DisplayServer.WINDOW_MODE_FULLSCREEN \ - else DisplayServer.WINDOW_MODE_FULLSCREEN - DisplayServer.window_set_mode(mode, id) + var mode = DisplayServer.window_get_mode(id) + mode = DisplayServer.WINDOW_MODE_WINDOWED \ + if mode == DisplayServer.WINDOW_MODE_FULLSCREEN \ + else DisplayServer.WINDOW_MODE_FULLSCREEN + DisplayServer.window_set_mode(mode, id) diff --git a/scripts/interfer.gd b/scripts/interfer.gd index f7a1f131..9de6555c 100644 --- a/scripts/interfer.gd +++ b/scripts/interfer.gd @@ -1,25 +1,25 @@ -extends Node +class_name Iterfer extends Node -## Представление помехи +## Представление помехи. -## Режимы помехи +## Режимы помехи. const ITERFER_MODE = { - 'off': ['Откл', ['freq', 'width'], 0], - 'auto': ['АВТО', ['freq', 'width'], 1000], - 'srni1': ['СРН-И1', ['freq', 'width'], 1], - 'srnm2': ['СРН-М2', ['freq', 'width'], 2], - 'srngps': ['СРН-GPS', ['freq', 'width'], 3], - 'lchm1': ['ЛЧМ-1', ['freq', 'width'], 10], - 'lchm2': ['ЛЧМ-2', ['freq', 'width'], 4], - 'mchm1': ['МЧМ-1', ['freq', 'width'], 11], - 'pdm2': ['ПД-М2', ['freq', 'width'], 12], - 'pdm4': ['ПД-М4', ['freq', 'width'], 13], - 'pdm4s': ['ПД-М4С', ['freq', 'width'], 14], - 'pdchm': ['ПД-ЧМ', ['freq', 'width'], 15], - 'svi1': ['СВ-И1', ['freq', 'width'], 20], - 'svm2': ['СВ-М2', ['freq', 'width'], 21], - 'k1': ['K1', ['freq', 'width', 'dur', 'period'], 50], - 'ozp1': ['ОЗП-1', ['freq', 'width'], 51] } + 'off': ['Откл', ['freq', 'width'], 0], + 'auto': ['АВТО', ['freq', 'width'], 1000], + 'srni1': ['СРН-И1', ['freq', 'width'], 1], + 'srnm2': ['СРН-М2', ['freq', 'width'], 2], + 'srngps': ['СРН-GPS', ['freq', 'width'], 3], + 'lchm1': ['ЛЧМ-1', ['freq', 'width'], 10], + 'lchm2': ['ЛЧМ-2', ['freq', 'width'], 4], + 'mchm1': ['МЧМ-1', ['freq', 'width'], 11], + 'pdm2': ['ПД-М2', ['freq', 'width'], 12], + 'pdm4': ['ПД-М4', ['freq', 'width'], 13], + 'pdm4s': ['ПД-М4С', ['freq', 'width'], 14], + 'pdchm': ['ПД-ЧМ', ['freq', 'width'], 15], + 'svi1': ['СВ-И1', ['freq', 'width'], 20], + 'svm2': ['СВ-М2', ['freq', 'width'], 21], + 'k1': ['K1', ['freq', 'width', 'dur', 'period'], 50], + 'ozp1': ['ОЗП-1', ['freq', 'width'], 51] } const FREQ_MAX = 6000 const FREQ_MIN = 400 @@ -27,63 +27,63 @@ const WIDTH_MAX = 120 const WIDTH_MIN = 0 const SOURCE_INTERFER = ['th','fs','cu'] -const ID_INTERFERS_LEN = 63 ## Размер пула номеров целей +const ID_INTERFERS_LEN = 63 ## Размер пула номеров целей. const INTERFER_OFF = 'off' -const STATE_TSMT = 5 ## Значение svk для цели, когда ответ ещё не получен -var msg_ss: int = 0 ## счётчик сообщений -var id_array: Array ## Массив id воздействий -var thrs: Dictionary ## Словарь воздействия для целей, ключ - id воздействия -var fs: Dictionary ## Словарь воздействий для секторов, ключ - id воздействия -var cu: Dictionary ## Словарь воздействий для 5П-28, ключ - id воздействия +const STATE_TSMT = 5 ## Значение svk для цели, когда ответ ещё не получен. +var msg_ss: int = 0 ## Счётчик сообщений. +var id_array: Array ## Массив id воздействий. +var thrs: Dictionary ## Словарь воздействия для целей, ключ - id воздействия. +var fs: Dictionary ## Словарь воздействий для секторов, ключ - id воздействия. +var cu: Dictionary ## Словарь воздействий для 5П-28, ключ - id воздействия. -## Сеанс помехи +## Сеанс помехи. class Interfer: - var ss: int = 0 ## Счётчик сообщений. - var ispp: int = 0 ## Индекс сеанса. - var svk: = 0 ## Состояние сеанса. Ответ КАПСРПБ. Возможные значения в [param ITERFER_STATE]. - var krp: String = '' ## Тип помехи. Возможные значения в [param INTERFER_MODE]. - var powp: float = 0.0 ## Мощность излучения выраженная в процентах. - var kni: = 0.0 ## Курсовой угол направления излучения. - var params: = {} ## Параметры помехи. - var get_params: Array[String] ## Запрос массива параметров (список запрошенных параметров). - var retss: int ## Значение счётчика сообщения в котором был произведён запрос массива параметров. - var tick_tx: int ## Тик время обновления цели, мс. - var source_interfer: String = '' ## Тип объекта по которой поставлена помеха + var ss: int = 0 ## Счётчик сообщений. + var ispp: int = 0 ## Индекс сеанса. + var svk: = 0 ## Состояние сеанса. Ответ КАПСРПБ. Возможные значения в [param ITERFER_STATE]. + var krp: String = '' ## Тип помехи. Возможные значения в [param INTERFER_MODE]. + var powp: float = 0.0 ## Мощность излучения выраженная в процентах. + var kni: = 0.0 ## Курсовой угол направления излучения. + var params: = {} ## Параметры помехи. + var get_params: Array[String] ## Запрос массива параметров (список запрошенных параметров). + var retss: int ## Значение счётчика сообщения в котором был произведён запрос массива параметров. + var tick_tx: int ## Тик время обновления цели, мс. + var source_interfer: String = '' ## Тип объекта по которой поставлена помеха. - func _to_string() -> String: - return 'номер: %d название: %s частота: %0.1f МГц пеленг: %0.1f гр.' % [ispp, ITERFER_MODE[krp][0], params['freq'], kni] + func _to_string() -> String: + return 'номер: %d название: %s частота: %0.1f МГц пеленг: %0.1f гр.' % [ispp, ITERFER_MODE[krp][0], params['freq'], kni] - func get_msg6_data(): - var data_to_json : Dictionary = {} - data_to_json['ts'] = 6 - data_to_json['ss'] = ss - data_to_json['ispp'] = ispp - data_to_json['krp'] = krp - if krp != INTERFER_OFF: - data_to_json['kni'] = kni - data_to_json['powp'] = powp # Необходимо добавить управление мощностью - data_to_json['get'] = [] - data_to_json['params'] = params - var json = JSON.stringify(data_to_json) - var pac = json.to_utf8_buffer() - return pac + func get_msg6_data(): + var data_to_json : Dictionary = {} + data_to_json['ts'] = 6 + data_to_json['ss'] = ss + data_to_json['ispp'] = ispp + data_to_json['krp'] = krp + if krp != INTERFER_OFF: + data_to_json['kni'] = kni + data_to_json['powp'] = powp # Необходимо добавить управление мощностью + data_to_json['get'] = [] + data_to_json['params'] = params + var json = JSON.stringify(data_to_json) + var pac = json.to_utf8_buffer() + return pac - func set_from_dic(dic: Dictionary): - var names: = tools.get_members_names(self) - names.any(func(vn): if dic.has(vn): set(vn, dic[vn]); return false) + func set_from_dic(dic: Dictionary): + var names: = tools.get_members_names(self) + names.any(func(vn): if dic.has(vn): set(vn, dic[vn]); return false) - func get_value(value_key): - var param = self.get(value_key) - if param == null: - if params.has(value_key): param = params[value_key] - return param + func get_value(value_key): + var param = self.get(value_key) + if param == null: + if params.has(value_key): param = params[value_key] + return param - func set_value(value, value_key): - var param = self.get(value_key) - if param == null: - params[value_key] = value - else: - self.set(value_key, value) + func set_value(value, value_key): + var param = self.get(value_key) + if param == null: + params[value_key] = value + else: + self.set(value_key, value) signal interfer_preparing(ecm: Interfer) ## Вызывается в момент запуска помехи. @@ -94,173 +94,173 @@ signal interfer_resized(ecms: Dictionary) ## Вызывается пр func _ready(): - var ecms: Dictionary = {} ## Словарь помех - for i in range(ID_INTERFERS_LEN): # Заполняет массив ID целей - id_array.append(i + 1) - var unit_key = repsettings.get_unit_key('уарэп-капсрпб-отп') - var unit = repnetwork.units[unit_key] - var unit_5p28_key = repsettings.get_unit_key('уарэп-5п28') - var unit_5p28 = repnetwork.units_tcp[unit_5p28_key] - var timer_check_state: = Timer.new() - add_child(timer_check_state) - var resend_timeout = ProjectSettings.get_setting('application/interfer/resend_timeout', 1000.0) - timer_check_state.connect('timeout', Callable(self, 'on_timer_check_state').bind(unit, ecms, resend_timeout)) - timer_check_state.start(resend_timeout / 1000.0) - unit.connect('data_received', Callable(self, 'on_data_capsrpb_received').bind(ecms)) - unit_5p28.connect('get_interfers', Callable(self, 'on_get_interfers').bind(unit_5p28, ecms)) - signaller.connect('interfer_create', Callable(self, 'on_interfer_create').bind(unit, ecms)) - signaller.connect('interfer_rcv', Callable(self, 'on_interfer_rcv').bind(unit_5p28, ecms)) - signaller.connect('interfer_new', Callable(self, 'send_ecm').bind(unit)) - signaller.connect('interfer_off_all', Callable(self, 'on_interfer_off_all').bind(unit, ecms)) + var ecms: Dictionary = {} ## Словарь помех. + for i in range(ID_INTERFERS_LEN): # Заполняет массив ID целей + id_array.append(i + 1) + var unit_key = repsettings.get_unit_key('уарэп-капсрпб-отп') + var unit = repnetwork.units[unit_key] + var unit_5p28_key = repsettings.get_unit_key('уарэп-5п28') + var unit_5p28 = repnetwork.units_tcp[unit_5p28_key] + var timer_check_state: = Timer.new() + add_child(timer_check_state) + var resend_timeout = ProjectSettings.get_setting('application/interfer/resend_timeout', 1000.0) + timer_check_state.connect('timeout', Callable(self, 'on_timer_check_state').bind(unit, ecms, resend_timeout)) + timer_check_state.start(resend_timeout / 1000.0) + unit.connect('data_received', Callable(self, 'on_data_capsrpb_received').bind(ecms)) + unit_5p28.connect('get_interfers', Callable(self, 'on_get_interfers').bind(unit_5p28, ecms)) + signaller.connect('interfer_create', Callable(self, 'on_interfer_create').bind(unit, ecms)) + signaller.connect('interfer_rcv', Callable(self, 'on_interfer_rcv').bind(unit_5p28, ecms)) + signaller.connect('interfer_new', Callable(self, 'send_ecm').bind(unit)) + signaller.connect('interfer_off_all', Callable(self, 'on_interfer_off_all').bind(unit, ecms)) -# Проверяет состояние отправки пакета и если не доставлен, повторяет отправку +## Проверяет состояние отправки пакета и если не доставлен, повторяет отправку. func on_timer_check_state(unit, ecms, resend_timeout): - var tick = Time.get_ticks_msec() - for ecm in ecms.values(): - if ecm.svk == STATE_TSMT: - if (tick - ecm.tick_tx) >= resend_timeout: - send_ecm(ecm, unit) - ecm.tick_tx = tick + var tick = Time.get_ticks_msec() + for ecm in ecms.values(): + if ecm.svk == STATE_TSMT: + if (tick - ecm.tick_tx) >= resend_timeout: + send_ecm(ecm, unit) + ecm.tick_tx = tick -## Производит приём состояния помех. [param unit] -> [param ecms] +## Производит приём состояния помех. [param unit] -> [param ecms]. func on_data_capsrpb_received(unit: capsrpb.CapsRpb, ecms: Dictionary): - if not unit.json_dic.has('ts'): return - if not (unit.json_dic['ts'] is float): return - if unit.json_dic['ts'] != 5: return - if not unit.json_dic.has('msvk'): return - if not (unit.json_dic['msvk'] is Array): return - var msvk = unit.json_dic['msvk'] - var sz: = ecms.size() - for dic_msvk in msvk: - if not (dic_msvk is Dictionary): continue - if dic_msvk.has('ispp'): - var ispp = int(dic_msvk['ispp']) - if ecms.has(ispp): - var ecm = ecms[ispp] - ecm.set_from_dic(dic_msvk) - call_deferred('emit_signal', 'interfer_update', ecm) - else: - var ecm = Interfer.new() - ecm.set_from_dic(dic_msvk) - ecm.krp = INTERFER_OFF - send_ecm(ecm, unit) - if sz != ecms.size(): - call_deferred('emit_signal', 'interfer_resized', ecms) + if not unit.json_dic.has('ts'): return + if not (unit.json_dic['ts'] is float): return + if unit.json_dic['ts'] != 5: return + if not unit.json_dic.has('msvk'): return + if not (unit.json_dic['msvk'] is Array): return + var msvk = unit.json_dic['msvk'] + var sz: = ecms.size() + for dic_msvk in msvk: + if not (dic_msvk is Dictionary): continue + if dic_msvk.has('ispp'): + var ispp = int(dic_msvk['ispp']) + if ecms.has(ispp): + var ecm = ecms[ispp] + ecm.set_from_dic(dic_msvk) + call_deferred('emit_signal', 'interfer_update', ecm) + else: + var ecm = Interfer.new() + ecm.set_from_dic(dic_msvk) + ecm.krp = INTERFER_OFF + send_ecm(ecm, unit) + if sz != ecms.size(): + call_deferred('emit_signal', 'interfer_resized', ecms) -## Вызыватся, когда пользователь выбрал помеху и выбраны цели +## Вызыватся, когда пользователь выбрал помеху и выбраны цели. func on_interfer_create(btn, sel_threats, fs_arr, _unit, ecms): - for item in sel_threats: - var param: Dictionary = {} - var kni: float = item.aoa - var id = item.id - var interfer_name: String = btn.get_meta('rfi_name') - param['freq'] = item.freq - param['width'] = item.width - interfer_create(interfer_name, ecms, param, kni, id, thrs, SOURCE_INTERFER[0]) + for item in sel_threats: + var param: Dictionary = {} + var kni: float = item.aoa + var id = item.id + var interfer_name: String = btn.get_meta('rfi_name') + param['freq'] = item.freq + param['width'] = item.width + interfer_create(interfer_name, ecms, param, kni, id, thrs, SOURCE_INTERFER[0]) - for item in fs_arr: - var param: Dictionary = {} - var kni: float = item[0] - var id = item[3] - var interfer_name: String = btn.get_meta('rfi_name') - param['freq'] = item[1] - param['width'] = item[2] - interfer_create(interfer_name, ecms, param, kni, id, fs, SOURCE_INTERFER[1]) + for item in fs_arr: + var param: Dictionary = {} + var kni: float = item[0] + var id = item[3] + var interfer_name: String = btn.get_meta('rfi_name') + param['freq'] = item[1] + param['width'] = item[2] + interfer_create(interfer_name, ecms, param, kni, id, fs, SOURCE_INTERFER[1]) func on_interfer_rcv(interfer_params: Array, unit, ecms): - var err: bool = false - var mode = interfer_params[0] - var id = interfer_params[1] - var aoa = interfer_params[2] - if (aoa < 0) and (aoa > 360): - err = true - var param: Dictionary = {} - param['freq'] = interfer_params[4] - if (param['freq'] < FREQ_MIN) and (param['freq'] > FREQ_MAX): - err = true - param['width'] = interfer_params[5] - if (param['width'] < WIDTH_MIN) and (param['width'] > WIDTH_MAX): - err = true - var interfer_name: String - for key in ITERFER_MODE: - if ITERFER_MODE[key][2] == mode: - interfer_name = key - break - if interfer_name == '': - err = true - if not err: - interfer_create(interfer_name, ecms, param, aoa, id, cu, SOURCE_INTERFER[2]) - unit.on_interfer_accept(err) + var err: bool = false + var mode = interfer_params[0] + var id = interfer_params[1] + var aoa = interfer_params[2] + if (aoa < 0) and (aoa > 360): + err = true + var param: Dictionary = {} + param['freq'] = interfer_params[4] + if (param['freq'] < FREQ_MIN) and (param['freq'] > FREQ_MAX): + err = true + param['width'] = interfer_params[5] + if (param['width'] < WIDTH_MIN) and (param['width'] > WIDTH_MAX): + err = true + var interfer_name: String + for key in ITERFER_MODE: + if ITERFER_MODE[key][2] == mode: + interfer_name = key + break + if interfer_name == '': + err = true + if not err: + interfer_create(interfer_name, ecms, param, aoa, id, cu, SOURCE_INTERFER[2]) + unit.on_interfer_accept(err) func interfer_create(interfer_name, ecms, param, kni, id, dict, source_interfer): - var ispp: int = 0 - if interfer_name == 'k1': - param['dur'] = 1.0 # Необходимо добавить параметры управления - param['period'] = 1.0 # Необходимо добавить параметры управления - var key = dict.find_key(id) - if source_interfer != SOURCE_INTERFER[2]: - if key != null: - ispp = key - else: - if interfer_name == 'off': - return - ispp = pop_id() - if ispp == 0: return - else: ispp = id - dict[ispp] = id - msg_ss += 1 - var ecm: Interfer - if ecms.has(ispp): - ecm = ecms[ispp] - else: - ecm = Interfer.new() - ecm.ispp = ispp - ecms[ispp] = ecm - ecm.svk = STATE_TSMT # Подготовка к передаче сообщения - ecm.ss = msg_ss - ecm.kni = kni - ecm.krp = interfer_name - ecm.params = param - ecm.powp = 100.0 # Необходимо добавить управление мощностью - ecm.source_interfer = source_interfer - signaller.emit_signal('interfer_new', ecm) - if interfer_name == 'off': - signaller.emit_signal('interfer_off', ecm, ecms, thrs) - push_id(ecm.ispp) - thrs.erase(ispp) - ecm.tick_tx = Time.get_ticks_msec() + var ispp: int = 0 + if interfer_name == 'k1': + param['dur'] = 1.0 # Необходимо добавить параметры управления + param['period'] = 1.0 # Необходимо добавить параметры управления + var key = dict.find_key(id) + if source_interfer != SOURCE_INTERFER[2]: + if key != null: + ispp = key + else: + if interfer_name == 'off': + return + ispp = pop_id() + if ispp == 0: return + else: ispp = id + dict[ispp] = id + msg_ss += 1 + var ecm: Interfer + if ecms.has(ispp): + ecm = ecms[ispp] + else: + ecm = Interfer.new() + ecm.ispp = ispp + ecms[ispp] = ecm + ecm.svk = STATE_TSMT # Подготовка к передаче сообщения + ecm.ss = msg_ss + ecm.kni = kni + ecm.krp = interfer_name + ecm.params = param + ecm.powp = 100.0 # Необходимо добавить управление мощностью + ecm.source_interfer = source_interfer + signaller.emit_signal('interfer_new', ecm) + if interfer_name == 'off': + signaller.emit_signal('interfer_off', ecm, ecms, thrs) + push_id(ecm.ispp) + thrs.erase(ispp) + ecm.tick_tx = Time.get_ticks_msec() func send_ecm(ecm, unit): - var json_data = ecm.get_msg6_data() - unit.tx_stack.append(json_data) + var json_data = ecm.get_msg6_data() + unit.tx_stack.append(json_data) func on_interfer_off_all(unit, ecms): - for ecm in ecms.values(): - ecm.krp = INTERFER_OFF - push_id(ecm.ispp) - send_ecm(ecm, unit) - signaller.emit_signal('interfer_off',ecm, ecms, thrs) + for ecm in ecms.values(): + ecm.krp = INTERFER_OFF + push_id(ecm.ispp) + send_ecm(ecm, unit) + signaller.emit_signal('interfer_off',ecm, ecms, thrs) func pop_id(): - var id = 0 - if len(id_array): - id = id_array[0] - id_array.remove_at(0) - return id + var id = 0 + if len(id_array): + id = id_array[0] + id_array.remove_at(0) + return id func push_id(id : int): - id_array.append(id) - id_array.sort() + id_array.append(id) + id_array.sort() -## отправляет словаhь помех в юнит, для запаковки и отправки в 5П28 +## Отправляет словарь помех в юнит, для запаковки и отправки в 5П28. func on_get_interfers(unit, ecms): unit.pack_interfers(cu, ecms) diff --git a/scripts/mercator.gd b/scripts/mercator.gd index c876d452..9a496d67 100644 --- a/scripts/mercator.gd +++ b/scripts/mercator.gd @@ -1,12 +1,12 @@ -extends Node +class_name Mercator extends Node ## Утилиты для работы с меркаторовскими XYZ-плитками. const R2D: = 180.0 / PI -const RE: = 6378137.0 ## Радиус Земли экваториальный в метрах -const RP: = 6356752.31424518 ## Радиус Земли полярный в метрах -const CE: = 2.0 * PI * RE ## Длина окружности Земли в метрах по экватору -const CP: = 2.0 * PI * RP ## Длина окружности Земли в метрах через полюсы +const RE: = 6378137.0 ## Радиус Земли экваториальный в метрах. +const RP: = 6356752.31424518 ## Радиус Земли полярный в метрах. +const CE: = 2.0 * PI * RE ## Длина окружности Земли в метрах по экватору. +const CP: = 2.0 * PI * RP ## Длина окружности Земли в метрах через полюсы. const EPSILON: = 1e-14 const LL_EPSILON: = 1e-11 const MAX_ZOOM: = 20 @@ -14,95 +14,95 @@ const MAX_NORTH = 85.051129 const MAX_SOUTH = -85.051129 -## XYZ-плитка веб-меркатора [param x], [param y], [param z] индексы -# [b]x[/b] и [b]y[/b] плитки и уровень масштабирования [b]z[/b]. +## XYZ-плитка веб-меркатора [param x], [param y], [param z] индексы. +## [b]x[/b] и [b]y[/b] плитки и уровень масштабирования [b]z[/b]. class Tile: - var x: int - var y: int - var z: int - var lng: float ## Координаты, которые плитка должна покрывать, долгота, градусы - var lat: float ## Широта, градусы - var is_root: bool ## Признак, что плитка корневая (покрывает координаты) + var x: int + var y: int + var z: int + var lng: float ## Координаты, которые плитка должна покрывать, долгота, градусы. + var lat: float ## Широта, градусы. + var is_root: bool ## Признак, что плитка корневая (покрывает координаты). - func as_array(): return [self.x, self.y, self.z] + func as_array(): return [self.x, self.y, self.z] - func _to_string() -> String: return '[%d, %d, %d]' % [self.x, self.y, self.z] + func _to_string() -> String: return '[%d, %d, %d]' % [self.x, self.y, self.z] - func _init(x0: int = 0, y0: int = 0, z0: int = 0, is_root0: bool = true): - x = x0 - y = y0 - z = z0 - is_root = is_root0 + func _init(x0: int = 0, y0: int = 0, z0: int = 0, is_root0: bool = true): + x = x0 + y = y0 + z = z0 + is_root = is_root0 - func is_valid() -> bool: - if (z >= 0) and (z < MAX_ZOOM): - var mz: int = 2 ** z - return (x >= 0) and (x < mz) \ - and (y >= 0) and (y < mz) - return false + func is_valid() -> bool: + if (z >= 0) and (z < MAX_ZOOM): + var mz: int = 2 ** z + return (x >= 0) and (x < mz) \ + and (y >= 0) and (y < mz) + return false - func _bound_index(index: int) -> int: - var mi: int = 2 ** z - if index < 0: - index *= -1 - index %= mi - index = mi - index - else: - index %= mi - return index + func _bound_index(index: int) -> int: + var mi: int = 2 ** z + if index < 0: + index *= -1 + index %= mi + index = mi - index + else: + index %= mi + return index - func fix_xy(): - x = _bound_index(x) - y = _bound_index(y) + func fix_xy(): + x = _bound_index(x) + y = _bound_index(y) ## Пара долготы и широты. class LngLat: - var lng: float = 0.0 ## Долгота в десятичных градусах восточной долготы. - var lat: float = 0.0 ## Широта в десятичных градусах северной широты. + var lng: float = 0.0 ## Долгота в десятичных градусах восточной долготы. + var lat: float = 0.0 ## Широта в десятичных градусах северной широты. - ## Возвращает в виде массива - func as_array() -> Array: return [self.lng, self.lat] + ## Возвращает в виде массива. + func as_array() -> Array: return [self.lng, self.lat] - func _to_string() -> String: return '[%f, %f, %f]' % [self.x, self.y, self.z] + func _to_string() -> String: return '[%f, %f, %f]' % [self.x, self.y, self.z] - func _init(lng0, lat0): - self.lng = lng0 - self.lat = lat0 + func _init(lng0, lat0): + self.lng = lng0 + self.lat = lat0 ## Географические границы. Хранит значения границ в десятичных градусах. class LngLatBbox: - var west: float ## Запад - var south: float ## Юг - var east: float ## Восток - var north: float ## Север + var west: float ## Запад + var south: float ## Юг + var east: float ## Восток + var north: float ## Север - ## Возвращает в виде массива - func as_array() -> Array: return [self.west, self.south, self.east, self.north] + ## Возвращает в виде массива. + func as_array() -> Array: return [self.west, self.south, self.east, self.north] - func _to_string() -> String: return '[%f, %f, %f, %f]' % [self.west, self.south, self.east, self.north] + func _to_string() -> String: return '[%f, %f, %f, %f]' % [self.west, self.south, self.east, self.north] - func _init(w: float = 0.0, s: float = 0.0, e: float = 0.0, n: float = 0.0): - self.west = w - self.south = s - self.east = e - self.north = n + func _init(w: float = 0.0, s: float = 0.0, e: float = 0.0, n: float = 0.0): + self.west = w + self.south = s + self.east = e + self.north = n ## Граничная область веб-меркатора. Хранит значения границ в метрах. class Bbox: - var left: float - var bottom: float - var right: float - var top: float - func as_array() -> Array: return [self.left, self.bottom, self.right, self.top] - func _init(l: float = 0.0, b: float = 0.0, r: float = 0.0, t: float = 0.0): - self.left = l - self.bottom = b - self.right = r - self.top = t + var left: float + var bottom: float + var right: float + var top: float + func as_array() -> Array: return [self.left, self.bottom, self.right, self.top] + func _init(l: float = 0.0, b: float = 0.0, r: float = 0.0, t: float = 0.0): + self.left = l + self.bottom = b + self.right = r + self.top = t func degrees(v: float) -> float: return (v * 180.0) / PI @@ -114,69 +114,69 @@ func radians(v: float) -> float: return (v * PI) / 180.0 func rshift(val: int, n: int) -> int: return (val % 0x100000000) >> n -# Возвращает арксинус гиперболический от значения [param val] +## Возвращает арксинус гиперболический от значения [param val]. func asinh(val: float): return log(val + sqrt(val * val + 1.0)) -# Преобразует [param lon] в градусах восточной долготы, [param lat] в градусах -# северной долготы, [param alt] высоты в метрах в фиксированные координаты (x, y, z) Земли. +## Преобразует [param lon] в градусах восточной долготы, [param lat] в градусах. +## северной долготы, [param alt] высоты в метрах в фиксированные координаты (x, y, z) Земли. func lnglat_to_ecef(lng: float, lat: float, alt: float = 0.0) -> Array: - alt += (RE + RP) / 2.0 - var latrad: float = radians(lat) - var lonrad: float = radians(lng) - var coslat: float = cos(latrad) - var sinlat: float = sin(latrad) - var coslon: float = cos(lonrad) - var sinlon: float = sin(lonrad) - var term1: float = (RE * coslat) / tools.hypot(RE * coslat, RP * sinlat) - var term2: float = alt * coslat + term1; - var x: float = coslon * term2 - var y: float = sinlon * term2 - var z: float = alt * sinlat + (RP * sinlat) / tools.hypot(RE * coslat, RP * sinlat) - return [x, y, z] + alt += (RE + RP) / 2.0 + var latrad: float = radians(lat) + var lonrad: float = radians(lng) + var coslat: float = cos(latrad) + var sinlat: float = sin(latrad) + var coslon: float = cos(lonrad) + var sinlon: float = sin(lonrad) + var term1: float = (RE * coslat) / tools.hypot(RE * coslat, RP * sinlat) + var term2: float = alt * coslat + term1; + var x: float = coslon * term2 + var y: float = sinlon * term2 + var z: float = alt * sinlat + (RP * sinlat) / tools.hypot(RE * coslat, RP * sinlat) + return [x, y, z] func find_up_left(tiles: Array): - var x = 0 - var y = 0 - for tile in tiles: - if x < tile.x: x = tile.x - if y < tile.y: y = tile.y - for tile in tiles: - if tile.x == x and tile.y == y: - return tile - return null + var x = 0 + var y = 0 + for tile in tiles: + if x < tile.x: x = tile.x + if y < tile.y: y = tile.y + for tile in tiles: + if tile.x == x and tile.y == y: + return tile + return null -## Lon./lat. to tile numbers +## [param lon]/[param lat]. для номера плитки. func deg2num(lng: float, lat: float, zoom: int): - var n: = float(1 << zoom) - var xtile: = int((lng + 180.0) / 360.0 * n) - var ytile: = int((1.0 - asinh(tan(radians(lat))) / PI) / 2.0 * n) - return [xtile, ytile] + var n: = float(1 << zoom) + var xtile: = int((lng + 180.0) / 360.0 * n) + var ytile: = int((1.0 - asinh(tan(radians(lat))) / PI) / 2.0 * n) + return [xtile, ytile] -## Tile numbers to lon./lat. +## Номера плитки для [param lon]/[param lat]. func num2deg(x: int, y: int, zoom: int): - var n: = float(1 << zoom) - var lng: = float(x) / n * 360.0 - 180.0 - var lat: = atan(sinh(PI * (1.0 - 2.0 * float(y) / n))) - return [lng, degrees(lat)] + var n: = float(1 << zoom) + var lng: = float(x) / n * 360.0 - 180.0 + var lat: = atan(sinh(PI * (1.0 - 2.0 * float(y) / n))) + return [lng, degrees(lat)] -## Расстояние по горизонтали в метрах, представленное одним пикселем +## Расстояние по горизонтали в метрах, представленное одним пикселем. ## [param lat] - Широта, градусы.[br] ## [param zoom] - Уровень детализации.[br] ## [param size] - Размер плитки в пикселях.[br] func dist_per_pixel(lat: float, zoom: int, size: int = 256) -> float: - return (CE / float(size)) * cos(radians(lat)) / float(2 ** zoom) + return (CE / float(size)) * cos(radians(lat)) / float(2 ** zoom) -## Расстояние по горизонтали в метрах, представленное одной плиткой +## Расстояние по горизонтали в метрах, представленное одной плиткой. ## [param lat] - Широта, градусы.[br] ## [param zoom] - Уровень детализации.[br] func dist_per_tile(lat: float, zoom: int) -> float: - return CE * cos(radians(lat)) / float(2 ** zoom) + return CE * cos(radians(lat)) / float(2 ** zoom) ## Возвращает плитки и занимаемый ими размер области в пикселях: @@ -188,21 +188,21 @@ func dist_per_tile(lat: float, zoom: int) -> float: ## [param size] - Размер плитки в пикселях.[br] ## [param zoom] - Детализация.[br] func get_tiles(west: float, south: float, east: float, north: float, zoom: int, size: int) -> Array: - var tiles: = create_tiles(west, south, east, north, zoom) + var tiles: = create_tiles(west, south, east, north, zoom) - var mm = [] - for t in tiles: mm.append(t.x) - var min_x = mm.min() - var max_x = mm.max() + var mm = [] + for t in tiles: mm.append(t.x) + var min_x = mm.min() + var max_x = mm.max() - mm.clear() - for t in tiles: mm.append(t.y) - var min_y = mm.min() - var max_y = mm.max() + mm.clear() + for t in tiles: mm.append(t.y) + var min_y = mm.min() + var max_y = mm.max() - var w = size * (max_x - min_x + 1) - var h = size * (max_y - min_y + 1) - return [w, h, min_x, min_y, tiles, max_x - min_x + 1] + var w = size * (max_x - min_x + 1) + var h = size * (max_y - min_y + 1) + return [w, h, min_x, min_y, tiles, max_x - min_x + 1] ## Возвращает размер области в метрах.[br] @@ -211,9 +211,9 @@ func get_tiles(west: float, south: float, east: float, north: float, zoom: int, ## [param south] - Южная граница области.[br] ## [param north] - Северная граница области.[br] func get_size_from_degrees(west: float, south: float, east: float, north: float) -> Array[float]: - var xy0: = xy(west, north, true) - var xy1: = xy(east, south, true) - return [xy0[0] - xy1[0], xy0[1] - xy1[1]] + var xy0: = xy(west, north, true) + var xy1: = xy(east, south, true) + return [xy0[0] - xy1[0], xy0[1] - xy1[1]] ## Возвращает границы области в градусах.[br] @@ -221,31 +221,31 @@ func get_size_from_degrees(west: float, south: float, east: float, north: float) ## [param lng] - Долгота центра области в градусах (-180...180).[br] ## [param lat] - Широта центра области в градусах (-90...90).[br] func get_degrees_bounds(m: float, lng: float, lat: float) -> Array[float]: - m /= 2.0 - var x_y = xy(lng, lat, true) - return [x_y[0] - m, x_y[1] - m, x_y[0] + m, x_y[1] + m] + m /= 2.0 + var x_y = xy(lng, lat, true) + return [x_y[0] - m, x_y[1] - m, x_y[0] + m, x_y[1] + m] -## Возвращает границы плиток в градусах +## Возвращает границы плиток в градусах. func get_tiles_bounds(tiles: Array[Tile]) -> Array: - var mm = [] - for t in tiles: mm.append(bounds(t).west) - var mmw = mm.min(); mm.clear() + var mm = [] + for t in tiles: mm.append(bounds(t).west) + var mmw = mm.min(); mm.clear() - for t in tiles: mm.append(bounds(t).south) - var mms = mm.min(); mm.clear() + for t in tiles: mm.append(bounds(t).south) + var mms = mm.min(); mm.clear() - for t in tiles: mm.append(bounds(t).east) - var mme = mm.max(); mm.clear() + for t in tiles: mm.append(bounds(t).east) + var mme = mm.max(); mm.clear() - for t in tiles: mm.append(bounds(t).north) - var mmn = mm.max(); mm.clear() + for t in tiles: mm.append(bounds(t).north) + var mmn = mm.max(); mm.clear() - return [mmw, mms, mme, mmn] + return [mmw, mms, mme, mmn] ## Возвращает левую верхнюю долготу и широту плитки.[br] -## [param tile] Плитка.[br] +## [param tile] - Плитка.[br] ## [codeblock] ## >>> ul(Tile(x=0, y=0, z=1)) ## LngLat(lng=-180.0, lat=85.0511287798066) @@ -253,11 +253,11 @@ func get_tiles_bounds(tiles: Array[Tile]) -> Array: ## LngLat(lng=0.0, lat=0.0) ## [/codeblock] func ul(tile: Tile, zoom: int) -> LngLat: - var Z2 = pow(2, zoom) - var lon_deg = tile.x / Z2 * 360.0 - 180.0 - var lat_rad = atan(sinh(PI * (1 - 2 * tile.y / Z2))) - var lat_deg = degrees(lat_rad) - return LngLat.new(lon_deg, lat_deg) + var Z2 = pow(2, zoom) + var lon_deg = tile.x / Z2 * 360.0 - 180.0 + var lat_rad = atan(sinh(PI * (1 - 2 * tile.y / Z2))) + var lat_deg = degrees(lat_rad) + return LngLat.new(lon_deg, lat_deg) ## Возвращает левую верхнюю долготу и широту плитки.[br] @@ -269,32 +269,32 @@ func ul(tile: Tile, zoom: int) -> LngLat: ## LngLat(lng=0.0, lat=0.0) ## [/codeblock] func ul2(tile: Tile) -> Array[float]: - var z2 = pow(2, tile.z) - var lon_deg = tile.x / z2 * 360.0 - 180.0 - var lat_rad = atan(sinh(PI * (1 - 2 * tile.y / z2))) - var lat_deg = degrees(lat_rad) - return [lon_deg, lat_deg] + var z2 = pow(2, tile.z) + var lon_deg = tile.x / z2 * 360.0 - 180.0 + var lat_rad = atan(sinh(PI * (1 - 2 * tile.y / z2))) + var lat_deg = degrees(lat_rad) + return [lon_deg, lat_deg] ## Возвращает граничную область плитки.[br] ## [param tile] - Плитка.[br] func bounds(tile: Tile) -> LngLatBbox: - var z2: = pow(2, tile.z) - var ul_lon_deg = float(tile.x) / z2 * 360.0 - 180.0 - var lr_lon_deg = (float(tile.x) + 1.0) / z2 * 360.0 - 180.0 - var ul_lat_rad = atan(sinh(PI * (1.0 - 2.0 * float(tile.y) / z2))) - var ul_lat_deg = degrees(ul_lat_rad) - var lr_lat_rad = atan(sinh(PI * (1.0 - 2.0 * (float(tile.y) + 1.0) / z2))) - var lr_lat_deg = degrees(lr_lat_rad) - return LngLatBbox.new(ul_lon_deg, lr_lat_deg, lr_lon_deg, ul_lat_deg) + var z2: = pow(2, tile.z) + var ul_lon_deg = float(tile.x) / z2 * 360.0 - 180.0 + var lr_lon_deg = (float(tile.x) + 1.0) / z2 * 360.0 - 180.0 + var ul_lat_rad = atan(sinh(PI * (1.0 - 2.0 * float(tile.y) / z2))) + var ul_lat_deg = degrees(ul_lat_rad) + var lr_lat_rad = atan(sinh(PI * (1.0 - 2.0 * (float(tile.y) + 1.0) / z2))) + var lr_lat_deg = degrees(lr_lat_rad) + return LngLatBbox.new(ul_lon_deg, lr_lat_deg, lr_lon_deg, ul_lat_deg) func truncate_lnglat(lng: float, lat: float) -> Array: - if lng > 180.0: lng = 180.0 - elif lng < -180.0: lng = -180.0 - if lat > 90.0: lat = 90.0 - elif lat < -90.0: lat = -90.0 - return [lng, lat] + if lng > 180.0: lng = 180.0 + elif lng < -180.0: lng = -180.0 + if lat > 90.0: lat = 90.0 + elif lat < -90.0: lat = -90.0 + return [lng, lat] ## Преобразование долготы и широты в веб-меркатор x, y в метрах.[br] @@ -303,159 +303,159 @@ func truncate_lnglat(lng: float, lat: float) -> Array: ## [param truncate] - Нужно ли усекать входные данные до пределов веб-меркатора.[br] ## ([param lat] >= 90) [b]inf[/b] на северном и [b]-inf[/b] на южном полюсе ([param lat] <= -90). func xy(lng: float, lat: float, truncate: bool = false) -> Array[float]: - var ll = truncate_lnglat(lng, lat) if truncate else [lng, lat] - var x: float = RE * radians(lng) - var y: float = 0.0 - if ll[1] <= -90.0: y = float('-inf') - elif ll[1] >= 90.0: y = float('inf') - else: y = RE * log(tan((PI * 0.25) + (0.5 * radians(lat)))) - return [x, y] + var ll = truncate_lnglat(lng, lat) if truncate else [lng, lat] + var x: float = RE * radians(lng) + var y: float = 0.0 + if ll[1] <= -90.0: y = float('-inf') + elif ll[1] >= 90.0: y = float('inf') + else: y = RE * log(tan((PI * 0.25) + (0.5 * radians(lat)))) + return [x, y] ## Преобразование координат веб-меркатора x, y в долготу и широту.[br] ## [param x], [param y] - Координаты веб-меркатора в метрах.[br] ## [param truncate] - Нужно ли усекать или обрезать входные данные до границ веб-меркатора. func lnglat(x: float, y: float, truncate: bool = false) -> LngLat: - var lng: = x * R2D / RE - var lat: = ((PI * 0.5) - 2.0 * atan(exp(-y / RE))) * R2D - var ll: = truncate_lnglat(lng, lat) if truncate else [lng, lat] - return LngLat.new(ll[0], ll[1]) + var lng: = x * R2D / RE + var lat: = ((PI * 0.5) - 2.0 * atan(exp(-y / RE))) * R2D + var ll: = truncate_lnglat(lng, lat) if truncate else [lng, lat] + return LngLat.new(ll[0], ll[1]) -## Соседи плитки. [method neighbors] возвращает до восьми -## соседних плиток, при этом плитки будут опущены, если они не являются действительными, например. -## Tile(-1, -1, z). [param tile]: Плитка или последовательность int -## Может быть либо экземпляр Tile, либо 3 ints, X, Y, Z. +## Соседи плитки. [method neighbors] возвращает до восьми.[br] +## Cоседних плиток, при этом плитки будут опущены, если они не являются действительными, например:[br] +## Tile(-1, -1, z). [param tile]: Плитка или последовательность int.[br] +## Может быть либо экземпляр Tile, либо 3 ints, X, Y, Z.[br] ## [return] Массив ## [codeblock] ## >>> neighbors(Tile(486, 332, 10)) ## [Tile(x=485, y=331, z=10), Tile(x=485, y=332, z=10), Tile(x=485, y=333, z=10), Tile(x=486, y=331, z=10), Tile(x=486, y=333, z=10), Tile(x=487, y=331, z=10), Tile(x=487, y=332, z=10), Tile(x=487, y=333, z=10)] ## [/codeblock] func neighbors(tile: Tile) -> Array: - var tiles: = [] - for i in [-1, 0, 1]: - for j in [-1, 0, 1]: - if i == 0 and j == 0: - continue - var t = Tile.new(tile.x + i, tile.y + j, tile.z) - t.fix_xy() - tiles.append(t) - return tiles + var tiles: = [] + for i in [-1, 0, 1]: + for j in [-1, 0, 1]: + if i == 0 and j == 0: + continue + var t = Tile.new(tile.x + i, tile.y + j, tile.z) + t.fix_xy() + tiles.append(t) + return tiles -## Возвращает все плитки в радиусе [param r] вокруг заданной плитки [param tile] +## Возвращает все плитки в радиусе [param r] вокруг заданной плитки [param tile]. func get_allaround_tiles(tile: Tile, mr: int = 1) -> Array: - var xys = {} - var mi: int = 2 ** tile.z - for r in mr: - for a in range(0, 360, 180 / mi): - var ra = radians(a) - var ix = roundi(r * cos(ra)) + tile.x - var iy = roundi(r * sin(ra)) + tile.y - var t = Tile.new(ix, iy, tile.z) - t.fix_xy() - xys[[t.x, t.y]] = false - var tiles = [] - for txy in xys.keys(): - tiles.append(Tile.new(txy[0], txy[1], tile.z)) - return tiles + var xys = {} + var mi: int = 2 ** tile.z + for r in mr: + for a in range(0, 360, 180 / mi): + var ra = radians(a) + var ix = roundi(r * cos(ra)) + tile.x + var iy = roundi(r * sin(ra)) + tile.y + var t = Tile.new(ix, iy, tile.z) + t.fix_xy() + xys[[t.x, t.y]] = false + var tiles = [] + for txy in xys.keys(): + tiles.append(Tile.new(txy[0], txy[1], tile.z)) + return tiles -## Возвращает все плитки по периметру заданной плитки +## Возвращает все плитки по периметру заданной плитки. func get_perimetr_tiles(tile: Tile, mr: int = 1) -> Array: - var tiles = [] - for i in range(-mr, mr + 1): - for j in range(-mr, mr + 1): - if i == 0 and j == 0: continue - var t = Tile.new(i + tile.x, j + tile.y, tile.z) - t.fix_xy() - tiles.append(t) - return tiles + var tiles = [] + for i in range(-mr, mr + 1): + for j in range(-mr, mr + 1): + if i == 0 and j == 0: continue + var t = Tile.new(i + tile.x, j + tile.y, tile.z) + t.fix_xy() + tiles.append(t) + return tiles ## Получение меркаторской граничной рамки веб-плитки.[br] ## [param tile] - Плитка.[br] -## [i]Эпсилон вычитается из правой границы и прибавляется к нижней[/i] +## [i]Эпсилон вычитается из правой границы и прибавляется к нижней.[/i] func xy_bounds(tile: Tile, zoom: int) -> Bbox: - var tile_size = CE / pow(2, zoom) - var left = tile.x * tile_size - CE / 2 - var right = left + tile_size - var top = CE / 2 - tile.y * tile_size - var bottom = top - tile_size - return Bbox.new(left, bottom, right, top) + var tile_size = CE / pow(2, zoom) + var left = tile.x * tile_size - CE / 2 + var right = left + tile_size + var top = CE / 2 - tile.y * tile_size + var bottom = top - tile_size + return Bbox.new(left, bottom, right, top) func _xy(lng: float, lat: float, truncate=false) -> Array: - var ll: = truncate_lnglat(lng, lat) if truncate else [lng, lat] - var x: float = ll[0] / 360.0 + 0.5 - var sinlat: = sin(radians(ll[1])) - var y: = 0.5 - 0.25 * log((1.0 + sinlat) / (1.0 - sinlat)) / PI - return [x, y] + var ll: = truncate_lnglat(lng, lat) if truncate else [lng, lat] + var x: float = ll[0] / 360.0 + 0.5 + var sinlat: = sin(radians(ll[1])) + var y: = 0.5 - 0.25 * log((1.0 + sinlat) / (1.0 - sinlat)) / PI + return [x, y] -## Получение плитки, содержащей долготу и широту +## Получение плитки, содержащей долготу и широту. ## [param lng], [param lat] - Пара долготы и широты в десятичных градусах.[br] ## [param zoom] - Уровень масштабирования веб-меркатора.[br] ## [param truncate] - Нужно ли усекать вводимые данные до границ веб-меркатора.[br] func create_tile(lng: float, lat: float, zoom: int, truncate: bool=false) -> Tile: - var xy0: = _xy(lng, lat, truncate) - var z2 = pow(2, zoom) + var xy0: = _xy(lng, lat, truncate) + var z2 = pow(2, zoom) - # Чтобы устранить потерю точности при переходе от одной плитки к другой - # и lng/lat, точки в пределах EPSILON от правой стороны плитки - # считаются в следующей за ней плитке. - var tile: = Tile.new() - if xy0[0] <= 0: tile.x = 0 - elif xy0[0] >= 1: tile.x = int(z2 - 1) - else: tile.x = int(floor((xy0[0] + EPSILON) * z2)) + # Чтобы устранить потерю точности при переходе от одной плитки к другой + # и lng/lat, точки в пределах EPSILON от правой стороны плитки + # считаются в следующей за ней плитке. + var tile: = Tile.new() + if xy0[0] <= 0: tile.x = 0 + elif xy0[0] >= 1: tile.x = int(z2 - 1) + else: tile.x = int(floor((xy0[0] + EPSILON) * z2)) - if xy0[1] <= 0: tile.y = 0 - elif xy0[1] >= 1: tile.y = int(z2 - 1) - else: tile.y = int(floor((xy0[1] + EPSILON) * z2)) - tile.z = zoom - tile.lng = lng - tile.lat = lat - return tile + if xy0[1] <= 0: tile.y = 0 + elif xy0[1] >= 1: tile.y = int(z2 - 1) + else: tile.y = int(floor((xy0[1] + EPSILON) * z2)) + tile.z = zoom + tile.lng = lng + tile.lat = lat + return tile ## Получение четверного ключа плитки.[br] -## [param tile] - Плитка +## [param tile] - Плитка. func quadkey(tile: Tile, zoom: int) -> String: - var rs: = '' - for z in range(zoom, 0, -1): - var digit = 0 - var mask = 1 << (z - 1) - if tile.x & mask: - digit += 1 - if tile.y & mask: - digit += 2 - rs += str(digit) - return rs + var rs: = '' + for z in range(zoom, 0, -1): + var digit = 0 + var mask = 1 << (z - 1) + if tile.x & mask: + digit += 1 + if tile.y & mask: + digit += 2 + rs += str(digit) + return rs ## Получение плитки, соответствующей четверному ключу.[br] ## [param qk] - Строка четверного ключа. func quadkey_to_tile(qk: Array) -> Tile: - var tile: = Tile.new() - if len(qk) == 0: return tile - var i = 0 - qk.reverse() - for digit in qk: - var mask = 1 << i - i += 1 - if digit == '1': - tile.x |= mask - elif digit == '2': - tile.y |= mask - elif digit == '3': - tile.x |= mask - tile.y |= mask - elif digit == '0': - continue - else: - push_error('Не ожидаемый четырёхзначный знак: \"%s\"' % digit) - tile.z = i - return tile + var tile: = Tile.new() + if len(qk) == 0: return tile + var i = 0 + qk.reverse() + for digit in qk: + var mask = 1 << i + i += 1 + if digit == '1': + tile.x |= mask + elif digit == '2': + tile.y |= mask + elif digit == '3': + tile.x |= mask + tile.y |= mask + elif digit == '0': + continue + else: + push_error('Не ожидаемый четырёхзначный знак: \"%s\"' % digit) + tile.z = i + return tile ## Получение плиток, перекрываемых географической рамкой.[br] @@ -465,27 +465,27 @@ func quadkey_to_tile(qk: Array) -> Tile: ## [i]В параметрах south и east используется небольшой эпсилон, чтобы ## функция выдавала ровно одну плитку при задании границ этой же плитки.[/i] func create_tiles(west: float, south: float, east: float, north: float, zooms) -> Array[Tile]: - var bboxes = [[west, south, east, north]] if west <= east else [[-180.0, south, east, north], [west, south, 180.0, north]] - var tiles = [] - if not is_instance_of(zooms, TYPE_ARRAY): - zooms = [zooms] - for box in bboxes: - var w = box[0] - var s = box[1] - var e = box[2] - var n = box[3] - # Зажим граничных значений. - w = max(-180.0, w) - s = max(MAX_SOUTH, s) - e = min(180.0, e) - n = min(85.051129, n) - for z in zooms: - var ul_tile = create_tile(w, n, z) - var lr_tile = create_tile(e - LL_EPSILON, s + LL_EPSILON, z) - for i in range(ul_tile.x, lr_tile.x + 1): - for j in range(ul_tile.y, lr_tile.y + 1): - tiles.append(Tile.new(i, j, z)) - return tiles + var bboxes = [[west, south, east, north]] if west <= east else [[-180.0, south, east, north], [west, south, 180.0, north]] + var tiles = [] + if not is_instance_of(zooms, TYPE_ARRAY): + zooms = [zooms] + for box in bboxes: + var w = box[0] + var s = box[1] + var e = box[2] + var n = box[3] + # Зажим граничных значений. + w = max(-180.0, w) + s = max(MAX_SOUTH, s) + e = min(180.0, e) + n = min(85.051129, n) + for z in zooms: + var ul_tile = create_tile(w, n, z) + var lr_tile = create_tile(e - LL_EPSILON, s + LL_EPSILON, z) + for i in range(ul_tile.x, lr_tile.x + 1): + for j in range(ul_tile.y, lr_tile.y + 1): + tiles.append(Tile.new(i, j, z)) + return tiles ## Получение родителя плитки. Родительская плитка - это плитка на один уровень масштабирования ниже, которая @@ -500,28 +500,28 @@ func create_tiles(west: float, south: float, east: float, north: float, zooms) - ## Tile(x=0, y=0, z=0) ## [/codeblock] func parent(tile: Tile, zoom=null) -> Tile: - if tile.z == 0: return null + if tile.z == 0: return null - assert((zoom != null) and (tile.z > zoom or zoom == int(zoom)), 'Масштаб (zoom) должен быть целым числом и меньше масштаба входной плитки (tile).') - assert(tile.x == int(tile.x) and tile.y == int(tile.y) and tile.z == int(tile.z), 'Родитель нецелочисленной плитки (tile) является неуточнённым') + assert((zoom != null) and (tile.z > zoom or zoom == int(zoom)), 'Масштаб (zoom) должен быть целым числом и меньше масштаба входной плитки (tile).') + assert(tile.x == int(tile.x) and tile.y == int(tile.y) and tile.z == int(tile.z), 'Родитель нецелочисленной плитки (tile) является неуточнённым') - var target_zoom = tile.z - 1 if zoom == null else zoom + var target_zoom = tile.z - 1 if zoom == null else zoom - # Алгоритм, в значительной степени вдохновленный https://github.com/mapbox/tilebelt - var return_tile = Tile.new(tile.x, tile.y, tile.z) - while return_tile.z > target_zoom: - tile.x = return_tile.x - tile.y = return_tile.y - tile.z = return_tile.z - if tile.x % 2 == 0 and tile.y % 2 == 0: - return_tile = Tile.new(tile.x / 2, tile.y / 2, tile.z - 1) - elif tile.x % 2 == 0: - return_tile = Tile.new(tile.x / 2, (tile.y - 1) / 2, tile.z - 1) - elif not tile.x % 2 == 0 and tile.y % 2 == 0: - return_tile = Tile.new((tile.x - 1) / 2, tile.y / 2, tile.z - 1) - else: - return_tile = Tile.new((tile.x - 1) / 2, (tile.y - 1) / 2, tile.z - 1) - return return_tile + # Алгоритм, в значительной степени вдохновленный https://github.com/mapbox/tilebelt + var return_tile = Tile.new(tile.x, tile.y, tile.z) + while return_tile.z > target_zoom: + tile.x = return_tile.x + tile.y = return_tile.y + tile.z = return_tile.z + if tile.x % 2 == 0 and tile.y % 2 == 0: + return_tile = Tile.new(tile.x / 2, tile.y / 2, tile.z - 1) + elif tile.x % 2 == 0: + return_tile = Tile.new(tile.x / 2, (tile.y - 1) / 2, tile.z - 1) + elif not tile.x % 2 == 0 and tile.y % 2 == 0: + return_tile = Tile.new((tile.x - 1) / 2, tile.y / 2, tile.z - 1) + else: + return_tile = Tile.new((tile.x - 1) / 2, (tile.y - 1) / 2, tile.z - 1) + return return_tile ## Получение дочерних элементов плитки. Дочерние элементы упорядочены: @@ -538,16 +538,16 @@ func parent(tile: Tile, zoom=null) -> Tile: ## [Tile(x=0, y=0, z=2), Tile(x=0, y=1, z=2), Tile(x=0, y=2, z=2), Tile(x=0, y=3, z=2), ...] ## [/codeblock] func children(tile: Tile, zoom: int) -> Array: - var target_zoom = zoom if zoom != null else tile.z + 1 - var tiles: Array[Tile] = [tile] - while tiles[0].z >= target_zoom: - tile = tiles.pop_at(0) - tiles += [ - Tile.new(tile.x * 2, tile.y * 2, tile.z + 1), - Tile.new(tile.x * 2 + 1, tile.y * 2, tile.z + 1), - Tile.new(tile.x * 2 + 1, tile.y * 2 + 1, tile.z + 1), - Tile.new(tile.x * 2, tile.y * 2 + 1, tile.z + 1) ] - return tiles + var target_zoom = zoom if zoom != null else tile.z + 1 + var tiles: Array[Tile] = [tile] + while tiles[0].z >= target_zoom: + tile = tiles.pop_at(0) + tiles += [ + Tile.new(tile.x * 2, tile.y * 2, tile.z + 1), + Tile.new(tile.x * 2 + 1, tile.y * 2, tile.z + 1), + Tile.new(tile.x * 2 + 1, tile.y * 2 + 1, tile.z + 1), + Tile.new(tile.x * 2, tile.y * 2 + 1, tile.z + 1) ] + return tiles ## Проверяется, есть ли в [param merge_set] 4 плитки, которые могут быть объединены. @@ -555,52 +555,52 @@ func children(tile: Tile, zoom: int) -> Array: ## число, указывающее, были ли они объединены. При многократном применяя ## [method merge], можно упростить набор плиток. func merge(merge_set) -> Array: - var upwards_merge: = {} - for tile in merge_set.keys(): - var tile_parent = parent(tile) - if not upwards_merge.has(tile_parent): - upwards_merge[tile_parent] = {} - upwards_merge[tile_parent].update({tile: false}) - var current_tileset: = [] - var changed: = false - for supertile in upwards_merge.keys(): - var tile_children = upwards_merge[supertile] - if len(tile_children) == 4: - current_tileset += [supertile] - changed = true - else: - current_tileset += [tile_children] - return [current_tileset, changed] + var upwards_merge: = {} + for tile in merge_set.keys(): + var tile_parent = parent(tile) + if not upwards_merge.has(tile_parent): + upwards_merge[tile_parent] = {} + upwards_merge[tile_parent].update({tile: false}) + var current_tileset: = [] + var changed: = false + for supertile in upwards_merge.keys(): + var tile_children = upwards_merge[supertile] + if len(tile_children) == 4: + current_tileset += [supertile] + changed = true + else: + current_tileset += [tile_children] + return [current_tileset, changed] ## Максимально уменьшает размер набора плиток путем слияния листьев с родителями. ## [param tiles] - Последовательность плиток для слияния. func simplify(tiles: Array) -> Array: - # Проверьте, существует ли уже плитка и ее родитель. - # Убедитесь, что плитки отсортированы по масштабу, поэтому родительские - # плитки встречаются первыми. Если да, отбросьте дочернюю плитку - # (она покрыта родительской). - var root_set = {} - tiles.sort_custom(func(a, b): return a[2] < b[2]) - for tile in tiles: - var is_new_tile: bool = true - var supertiles = [] - for i in tile.z: - supertiles.append(parent(tile, i)) - for supertile in supertiles: - if supertile in root_set: - is_new_tile = false - continue - if is_new_tile: - root_set.update({tile: false}) + # Проверьте, существует ли уже плитка и ее родитель. + # Убедитесь, что плитки отсортированы по масштабу, поэтому родительские + # плитки встречаются первыми. Если да, отбросьте дочернюю плитку + # (она покрыта родительской). + var root_set = {} + tiles.sort_custom(func(a, b): return a[2] < b[2]) + for tile in tiles: + var is_new_tile: bool = true + var supertiles = [] + for i in tile.z: + supertiles.append(parent(tile, i)) + for supertile in supertiles: + if supertile in root_set: + is_new_tile = false + continue + if is_new_tile: + root_set.update({tile: false}) - # Повторять слияние до тех пор, пока дальнейшее упрощение перестанет быть невозможным. - var is_merging: bool = true - while is_merging: - var root_set_is_merging = merge(root_set) - root_set = root_set_is_merging[0] - is_merging = root_set_is_merging[1] - return root_set + # Повторять слияние до тех пор, пока дальнейшее упрощение перестанет быть невозможным. + var is_merging: bool = true + while is_merging: + var root_set_is_merging = merge(root_set) + root_set = root_set_is_merging[0] + is_merging = root_set_is_merging[1] + return root_set ## Получение наименьшей плитки, содержащей географическую границу. @@ -610,139 +610,139 @@ func simplify(tiles: Array) -> Array: ## севера в десятичных градусах. func bounding_tile(bbox: Bbox, truncate: bool = false) -> Tile: - if truncate: - var w_s = truncate_lnglat(bbox.left, bbox.bottom) - bbox.left = w_s[0] - bbox.bottom = w_s[1] - var e_n = truncate_lnglat(bbox.right, bbox.north) - bbox.right = e_n[0] - bbox.top = e_n[1] + if truncate: + var w_s = truncate_lnglat(bbox.left, bbox.bottom) + bbox.left = w_s[0] + bbox.bottom = w_s[1] + var e_n = truncate_lnglat(bbox.right, bbox.north) + bbox.right = e_n[0] + bbox.top = e_n[1] - bbox.right -= LL_EPSILON - bbox.bottom += LL_EPSILON + bbox.right -= LL_EPSILON + bbox.bottom += LL_EPSILON - var tmin = create_tile(bbox.left, bbox.top, 32) - var tmax = create_tile(bbox.right, bbox.bottom, 32) - assert(tmin.is_valid()) - assert(tmax.is_valid()) + var tmin = create_tile(bbox.left, bbox.top, 32) + var tmax = create_tile(bbox.right, bbox.bottom, 32) + assert(tmin.is_valid()) + assert(tmax.is_valid()) - var cell = [tmin.x, tmin.y, tmax.x, tmax.y] - var z = _get_bbox_zoom(cell) + var cell = [tmin.x, tmin.y, tmax.x, tmax.y] + var z = _get_bbox_zoom(cell) - if z == 0: - return Tile.new() + if z == 0: + return Tile.new() - var x = rshift(cell[0], 32 - z) - var y = rshift(cell[1], 32 - z) + var x = rshift(cell[0], 32 - z) + var y = rshift(cell[1], 32 - z) - return Tile.new(x, y, z) + return Tile.new(x, y, z) func _get_bbox_zoom(bbox: Array): - for z in MAX_ZOOM: - var mask: int = 1 << (32 - (z + 1)) - if (bbox[0] & mask) != (bbox[2] & mask) or (bbox[1] & mask) != (bbox[3] & mask): - return z - return MAX_ZOOM + for z in MAX_ZOOM: + var mask: int = 1 << (32 - (z + 1)) + if (bbox[0] & mask) != (bbox[2] & mask) or (bbox[1] & mask) != (bbox[3] & mask): + return z + return MAX_ZOOM ## Получение GeoJSON-функции, соответствующей плитке.[br] ## [param tile] - Плитка.[br] ## [param fid] - Идентификатор объекта.[br] ## [param props] - Необязательные дополнительные свойства признака.[br] -## [param projected] - Можно создать нестандартный веб-меркатор GeoJSON передав 'mercator'[br] +## [param projected] - Можно создать нестандартный веб-меркатор GeoJSON передав 'mercator'.[br] ## [param buffer] - Необязательное буферное расстояние для полигона GeoJSON.[br] ## [param precision] - Координаты GeoJSON будут усечены до данного количества знаков после запятой.[br] func feature(tile: Tile, fid:String = 'null', props=null, projected='geographic', buffer=null) -> Dictionary: - var west_south_east_north = bounds(tile).as_array() - var west = west_south_east_north[0] - var south = west_south_east_north[1] - var east = west_south_east_north[2] - var north = west_south_east_north[3] - if projected == 'mercator': - var west_south = xy(west, south, false) - west = west_south[0] - south = west_south[1] - var east_north = xy(east, north, false) - east = east_north[0] - north = east_north[1] + var west_south_east_north = bounds(tile).as_array() + var west = west_south_east_north[0] + var south = west_south_east_north[1] + var east = west_south_east_north[2] + var north = west_south_east_north[3] + if projected == 'mercator': + var west_south = xy(west, south, false) + west = west_south[0] + south = west_south[1] + var east_north = xy(east, north, false) + east = east_north[0] + north = east_north[1] - if buffer: - west -= buffer - south -= buffer - east += buffer - north += buffer + if buffer: + west -= buffer + south -= buffer + east += buffer + north += buffer - west = round(west) - south = round(south) - east = round(east) - north = round(north) + west = round(west) + south = round(south) + east = round(east) + north = round(north) - var bbox: = [min(west, east), min(south, north), max(west, east), max(south, north)] - var geom: = {'type': 'Polygon', 'coordinates': [[[west, south], [west, north], [east, north], [east, south], [west, south]]] } - var xyz: = str(tile) - var feat: = { - 'type': 'Feature', - 'bbox': bbox, - 'id': xyz, - 'geometry': geom, - 'properties': {'title': 'XYZ tile %s' % xyz} } + var bbox: = [min(west, east), min(south, north), max(west, east), max(south, north)] + var geom: = {'type': 'Polygon', 'coordinates': [[[west, south], [west, north], [east, north], [east, south], [west, south]]] } + var xyz: = str(tile) + var feat: = { + 'type': 'Feature', + 'bbox': bbox, + 'id': xyz, + 'geometry': geom, + 'properties': {'title': 'XYZ tile %s' % xyz} } - if props: - feat['properties'].update(props) + if props: + feat['properties'].update(props) - if fid != 'null': - feat['id'] = fid + if fid != 'null': + feat['id'] = fid - return feat + return feat func isinstance(obj, types: Array) -> bool: - for type in types: - if is_instance_of(obj, type): - return true - return false + for type in types: + if is_instance_of(obj, type): + return true + return false ## Все кортежи координат из геометрии, объекта или коллекции.[br] ## [param lng] - Долгота.[br] ## [param lat] - широта.[br] func _coords(obj) -> Array: - var coordinates = [] - if is_instance_of(obj, TYPE_ARRAY): - coordinates = obj - elif 'features' in obj: - for feat in obj['features']: - coordinates = feat['geometry']['coordinates'] - elif 'geometry' in obj: - coordinates = obj['geometry']['coordinates'] - else: - coordinates = obj.get('coordinates', obj) + var coordinates = [] + if is_instance_of(obj, TYPE_ARRAY): + coordinates = obj + elif 'features' in obj: + for feat in obj['features']: + coordinates = feat['geometry']['coordinates'] + elif 'geometry' in obj: + coordinates = obj['geometry']['coordinates'] + else: + coordinates = obj.get('coordinates', obj) - var v: = [] - for e in coordinates: - if isinstance(e, [TYPE_FLOAT, TYPE_INT]): - v.append(coordinates) - break - else: - for f in _coords(e): - v.append([f[0], f[1]]) - return v + var v: = [] + for e in coordinates: + if isinstance(e, [TYPE_FLOAT, TYPE_INT]): + v.append(coordinates) + break + else: + for f in _coords(e): + v.append([f[0], f[1]]) + return v func _func1(bbox: Array, coords: Array) -> Array[float]: - var w = bbox[0] - var s = bbox[1] - var e = bbox[2] - var n = bbox[3] - var lng = coords[0] - var lat = coords[1] - return [min(w, lng), min(s, lat), max(e, lng), max(n, lat)] + var w = bbox[0] + var s = bbox[1] + var e = bbox[2] + var n = bbox[3] + var lng = coords[0] + var lat = coords[1] + return [min(w, lng), min(s, lat), max(e, lng), max(n, lat)] ## Возвращает граничную область объекта GeoJSON.[br] ## [param obj] - Отображение, геометрия GeoJSON, объект или коллекция объектов.[br] func geojson_bounds(obj) -> LngLatBbox: - var coords: Array = _coords(obj) - var wsen = coords.reduce(_func1, [180.0, 90.0, -180.0, -90.0]) - return LngLatBbox.new(wsen[0], wsen[1], wsen[2], wsen[3]) + var coords: Array = _coords(obj) + var wsen = coords.reduce(_func1, [180.0, 90.0, -180.0, -90.0]) + return LngLatBbox.new(wsen[0], wsen[1], wsen[2], wsen[3]) diff --git a/scripts/modbus.gd b/scripts/modbus.gd index b7fe105d..08ed3ed9 100644 --- a/scripts/modbus.gd +++ b/scripts/modbus.gd @@ -1,131 +1,131 @@ -extends Node +class_name mod_bus extends Node -const ONLINE_TIMEOUT = 5.0 ## Время ожидания пакета от ячейки, секунды +const ONLINE_TIMEOUT = 5.0 ## Время ожидания пакета от ячейки, секунды. class ModbusClient: - ## Состояние автомата выполнения команды - enum CmdState { - DONE, ## Команда выполнена - FAIL, ## Команда не выполнена - SEND, ## Буфер готов для отправки - WAIT ## Ожидание выполнения - } + ## Состояние автомата выполнения команды. + enum CmdState { + DONE, ## Команда выполнена. + FAIL, ## Команда не выполнена. + SEND, ## Буфер готов для отправки. + WAIT ## Ожидание выполнения. + } - var name: String - var unit: = 1 ## Адрес устройства Modbus - var cmd_state: = CmdState.DONE ## Код текущей команды - var tx_data: PackedByteArray ## Данные для отправки - var online: = false ## Флаг. Если установлен, устройство на связи. Активный уровень - [b]true[/b]. - var tick_rx: = 0 ## Время приёма крайнего сообщения - var tick_tx: = 0 ## Время отправки крайнего сообщения + var name: String + var unit: = 1 ## Адрес устройства Modbus. + var cmd_state: = CmdState.DONE ## Код текущей команды. + var tx_data: PackedByteArray ## Данные для отправки. + var online: = false ## Флаг. Если установлен, устройство на связи. Активный уровень - [b]true[/b]. + var tick_rx: = 0 ## Время приёма крайнего сообщения. + var tick_tx: = 0 ## Время отправки крайнего сообщения. - static var json_conv: = JSON.new() + static var json_conv: = JSON.new() - signal command_done() ## Вызывается при успешном выполнении команды - signal command_fail() ## Вызывается при возникновении ошибки во время выполнения команды - signal line_changed() ## Вызывается при смене состояния связи с ячейкой - signal data_received() ## Вызывается при приёме сообщения, до его разбора - signal parse_failed(msg: String) ## Вызывается при возникновении ошибки во время разбора пакета. Передаёт сообщение об ошибке + signal command_done() ## Вызывается при успешном выполнении команды. + signal command_fail() ## Вызывается при возникновении ошибки во время выполнения команды. + signal line_changed() ## Вызывается при смене состояния связи с ячейкой. + signal data_received() ## Вызывается при приёме сообщения, до его разбора. + signal parse_failed(msg: String) ## Вызывается при возникновении ошибки во время разбора пакета. Передаёт сообщение об ошибке. - signal holding_received(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров хранения - signal input_received(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров входов - signal info_received(msg: String) ## Вызывается при получении информационного сообщения - signal except_received(msg: String) ## Вызывается при получении сообщения об исключительной ситуации + signal holding_received(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров хранения. + signal input_received(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров входов. + signal info_received(msg: String) ## Вызывается при получении информационного сообщения. + signal except_received(msg: String) ## Вызывается при получении сообщения об исключительной ситуации. - func _init(nm: String, u: int = 1): - unit = u - name = nm + func _init(nm: String, u: int = 1): + unit = u + name = nm - ## Изменяет состояние. Вызывать периодически[br] - ## [param tick] - Текущщее время в мс[br] - func process(tick: int): - if online and ((tick - tick_rx) > ONLINE_TIMEOUT): - online = false - emit_signal('line_changed') - if (cmd_state == CmdState.WAIT) or (cmd_state == CmdState.SEND): - cmd_state = CmdState.FAIL - emit_signal('command_fail') - var rc = Error.ERR_BUSY - if cmd_state == CmdState.SEND: - rc = Error.OK - tick_tx = tick - cmd_state = CmdState.WAIT - return rc + ## Изменяет состояние. Вызывать периодически.[br] + ## [param tick] - Текущщее время в мс.[br] + func process(tick: int): + if online and ((tick - tick_rx) > ONLINE_TIMEOUT): + online = false + emit_signal('line_changed') + if (cmd_state == CmdState.WAIT) or (cmd_state == CmdState.SEND): + cmd_state = CmdState.FAIL + emit_signal('command_fail') + var rc = Error.ERR_BUSY + if cmd_state == CmdState.SEND: + rc = Error.OK + tick_tx = tick + cmd_state = CmdState.WAIT + return rc - ## Производит разбор принятых данных. Вызывать при приёме данных на сокете[br] - ## [param data] - Данные принятые на сокете[br] - ## [param tick] - Текущщее время в мс[br] - func parse(data: PackedByteArray, tick: int) -> bool: - tick_rx = tick - if not online: - online = true - emit_signal('line_changed') - var utf8_data = data.get_string_from_utf8() - if Error.OK == json_conv.parse(utf8_data): - emit_signal('data_received') - var message: Dictionary = json_conv.get_data() - if message.has('code') and message.has('data'): - var rc: = true - var message_code = message['code'] - var message_data = message['data'] - match message_code: - 'read_input': - var addr = message_data[0] - var regs = message_data.slice(1) - emit_signal('input_received', addr, regs) - 'read_holding': - var addr = message_data[0] - var regs = message_data.slice(1) - emit_signal('holding_received', addr, regs) - 'info': - var msg = message['data'] - emit_signal('info_received', msg) - 'exception': - var msg = message['data'] - emit_signal('except_received', msg) - rc = false - _: - var msg: String = 'код команды \"%s\" - не распознан' % message_code - emit_signal('parse_failed', msg) - rc = false - if (cmd_state == CmdState.WAIT) and rc: - cmd_state = CmdState.DONE - emit_signal('command_done') - elif (cmd_state == CmdState.WAIT) and (not rc): - cmd_state = CmdState.FAIL - emit_signal('command_fail') - else: - var message = json_conv.get_error_message() - emit_signal('parse_failed', message) - return true + ## Производит разбор принятых данных. Вызывать при приёме данных на сокете.[br] + ## [param data] - Данные принятые на сокете.[br] + ## [param tick] - Текущщее время в мс.[br] + func parse(data: PackedByteArray, tick: int) -> bool: + tick_rx = tick + if not online: + online = true + emit_signal('line_changed') + var utf8_data = data.get_string_from_utf8() + if Error.OK == json_conv.parse(utf8_data): + emit_signal('data_received') + var message: Dictionary = json_conv.get_data() + if message.has('code') and message.has('data'): + var rc: = true + var message_code = message['code'] + var message_data = message['data'] + match message_code: + 'read_input': + var addr = message_data[0] + var regs = message_data.slice(1) + emit_signal('input_received', addr, regs) + 'read_holding': + var addr = message_data[0] + var regs = message_data.slice(1) + emit_signal('holding_received', addr, regs) + 'info': + var msg = message['data'] + emit_signal('info_received', msg) + 'exception': + var msg = message['data'] + emit_signal('except_received', msg) + rc = false + _: + var msg: String = 'код команды \"%s\" - не распознан' % message_code + emit_signal('parse_failed', msg) + rc = false + if (cmd_state == CmdState.WAIT) and rc: + cmd_state = CmdState.DONE + emit_signal('command_done') + elif (cmd_state == CmdState.WAIT) and (not rc): + cmd_state = CmdState.FAIL + emit_signal('command_fail') + else: + var message = json_conv.get_error_message() + emit_signal('parse_failed', message) + return true - ## Отправляет команду "записать в регистры".[br] - ## [param addr] - Начальный адрес регистров.[br] - ## [param count] - Данные для записи в регистры от начального адреса.[br] - func write(addr: int, data: Array) -> bool: - if cmd_state != CmdState.DONE: return false - var json_dict = {'code': 'write', 'data': [addr] + data} - tx_data = JSON.stringify(json_dict).to_utf8_buffer() - cmd_state = CmdState.SEND - return true + ## Отправляет команду "записать в регистры".[br] + ## [param addr] - Начальный адрес регистров.[br] + ## [param count] - Данные для записи в регистры от начального адреса.[br] + func write(addr: int, data: Array) -> bool: + if cmd_state != CmdState.DONE: return false + var json_dict = {'code': 'write', 'data': [addr] + data} + tx_data = JSON.stringify(json_dict).to_utf8_buffer() + cmd_state = CmdState.SEND + return true - ## Отправляет команду "читать регистры хранения".[br] - ## [param addr] - Начальный адрес регистров.[br] - ## [param count] - Количество регистров от начального адреса.[br] - func read_holdind(addr: int, count: int = 1) -> bool: - if cmd_state != CmdState.DONE: return false - var json_dict = {'code': 'read_holding', 'data': [addr, count]} - tx_data = JSON.stringify(json_dict).to_utf8_buffer() - cmd_state = CmdState.SEND - return true + ## Отправляет команду "читать регистры хранения".[br] + ## [param addr] - Начальный адрес регистров.[br] + ## [param count] - Количество регистров от начального адреса.[br] + func read_holdind(addr: int, count: int = 1) -> bool: + if cmd_state != CmdState.DONE: return false + var json_dict = {'code': 'read_holding', 'data': [addr, count]} + tx_data = JSON.stringify(json_dict).to_utf8_buffer() + cmd_state = CmdState.SEND + return true - ## Отправляет команду "читать регистры входов".[br] - ## [param addr] - Начальный адрес регистров.[br] - ## [param count] - Количество регистров от начального адреса.[br] - func read_input(addr: int, count: int = 1) -> bool: - if cmd_state != CmdState.DONE: return false - var json_dict = {'code': 'read_input', 'data': [addr, count]} - tx_data = JSON.stringify(json_dict).to_utf8_buffer() - cmd_state = CmdState.SEND - return true + ## Отправляет команду "читать регистры входов".[br] + ## [param addr] - Начальный адрес регистров.[br] + ## [param count] - Количество регистров от начального адреса.[br] + func read_input(addr: int, count: int = 1) -> bool: + if cmd_state != CmdState.DONE: return false + var json_dict = {'code': 'read_input', 'data': [addr, count]} + tx_data = JSON.stringify(json_dict).to_utf8_buffer() + cmd_state = CmdState.SEND + return true diff --git a/scripts/repnetwork.gd b/scripts/repnetwork.gd index ffd8a7ff..3dcf65a2 100644 --- a/scripts/repnetwork.gd +++ b/scripts/repnetwork.gd @@ -1,31 +1,31 @@ -extends Node +class_name rep_network extends Node const PROTOCOL_TYPES: = {'yau07tx': yau07.YaU07, 'jsontx': capsrpb.CapsRpb, 'udp-json-mbcs': modbus.ModbusClient} const TCP_PROTO: = {'5p28': tcp5p28.TCP5P28} class Socket extends PacketPeerUDP: - func send_to(addr, data): - self.set_dest_address(addr[0], addr[1]) - self.put_packet(data) + func send_to(addr, data): + self.set_dest_address(addr[0], addr[1]) + self.put_packet(data) class SocketTCP extends TCPServer: - const RX_TIMEOUT: int = 1000 # Время сброса счётчика принятия части пакета - var peerstream: = PacketPeerStream.new() - var unit_key: Array # Клюс юнита - var head_len: int = 8 # Длинна заголовка команды - var len_place: int = 4 # Номер начального байта с длинной блока данных - var type_len: int = 4 # Количество байт в размере длинны - var rx_tick: int # Время приёма последнего пакета - var rx_all: bool = true # Флаг, что пакет принят полностью - var rx_len: int # Количество принятых байт - var rx_data: PackedByteArray # Принятые данные - var data_len: int # Размер ожидаемых данных + const RX_TIMEOUT: int = 1000 ## Время сброса счётчика принятия части пакета. + var peerstream: = PacketPeerStream.new() + var unit_key: Array ## Клюс юнита. + var head_len: int = 8 ## Длинна заголовка команды. + var len_place: int = 4 ## Номер начального байта с длинной блока данных. + var type_len: int = 4 ## Количество байт в размере длинны. + var rx_tick: int ## Время приёма последнего пакета. + var rx_all: bool = true ## Флаг, что пакет принят полностью. + var rx_len: int ## Количество принятых байт. + var rx_data: PackedByteArray ## Принятые данные. + var data_len: int ## Размер ожидаемых данных. - func send_to(data): - var peer = peerstream.get_stream_peer() - peer.put_data(data) + func send_to(data): + var peer = peerstream.get_stream_peer() + peer.put_data(data) var poll_sockets: Array[Socket] @@ -38,129 +38,129 @@ var logger_page: Node func create_socket(nm) -> Socket: - var addr = repsettings.UnitProfiles[nm][1] - var port = repsettings.UnitProfiles[nm][2] - var broad = repsettings.UnitProfiles[nm][3] - var bind = repsettings.UnitProfiles[nm][4] - var sock: = Socket.new() - sock.set_broadcast_enabled(broad) - var rc = Error.OK if not bind else sock.bind(port, addr) - var errlevel = log.INFO if rc == Error.OK else log.ERROR - log.message(errlevel, '%s: сокет:%s:%d привязанный:%s %s' % [nm, addr, port, ['нет', 'да'][int(bind)], error_string(rc)]) - return sock + var addr = repsettings.UnitProfiles[nm][1] + var port = repsettings.UnitProfiles[nm][2] + var broad = repsettings.UnitProfiles[nm][3] + var bind = repsettings.UnitProfiles[nm][4] + var sock: = Socket.new() + sock.set_broadcast_enabled(broad) + var rc = Error.OK if not bind else sock.bind(port, addr) + var errlevel = log.INFO if rc == Error.OK else log.ERROR + log.message(errlevel, '%s: сокет:%s:%d привязанный:%s %s' % [nm, addr, port, ['нет', 'да'][int(bind)], error_string(rc)]) + return sock func create_tcpsocket(nm) -> SocketTCP: - var addr = repsettings.UnitProfiles[nm][1] - var port = repsettings.UnitProfiles[nm][2] - var sock = SocketTCP.new() - sock.unit_key = repsettings.get_unit_key(nm) - sock.listen(port, addr) - log.message(log.INFO, '%s: сокет:%s:%d привязанный:' % [nm, addr, port]) - return sock + var addr = repsettings.UnitProfiles[nm][1] + var port = repsettings.UnitProfiles[nm][2] + var sock = SocketTCP.new() + sock.unit_key = repsettings.get_unit_key(nm) + sock.listen(port, addr) + log.message(log.INFO, '%s: сокет:%s:%d привязанный:' % [nm, addr, port]) + return sock func _ready() -> void: - log.info('Модуль работы с сетью готов') - poll_sockets.append(create_socket('уарэп-яу07-частный')) - poll_sockets.append(create_socket('уарэп-яу07-общий')) - poll_sockets.append(create_socket('уарэп-капсрпб-пол')) - sock_unicast = poll_sockets[0] - sock_capsrpb = poll_sockets[2] + log.info('Модуль работы с сетью готов') + poll_sockets.append(create_socket('уарэп-яу07-частный')) + poll_sockets.append(create_socket('уарэп-яу07-общий')) + poll_sockets.append(create_socket('уарэп-капсрпб-пол')) + sock_unicast = poll_sockets[0] + sock_capsrpb = poll_sockets[2] - for unit_name in repsettings.UnitProfiles: - var setting = repsettings.UnitProfiles[unit_name] - var proto = setting[0] - if proto in PROTOCOL_TYPES: - var unit = PROTOCOL_TYPES[proto].new(unit_name) - var unit_key = repsettings.get_unit_key(unit_name) - units[unit_key] = unit - if logger_page: - unit.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(unit_key)) - unit.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(unit_key)) + for unit_name in repsettings.UnitProfiles: + var setting = repsettings.UnitProfiles[unit_name] + var proto = setting[0] + if proto in PROTOCOL_TYPES: + var unit = PROTOCOL_TYPES[proto].new(unit_name) + var unit_key = repsettings.get_unit_key(unit_name) + units[unit_key] = unit + if logger_page: + unit.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(unit_key)) + unit.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(unit_key)) - if proto in TCP_PROTO: - var unit = TCP_PROTO[proto].new(unit_name) - var unit_key = repsettings.get_unit_key(unit_name) - units_tcp[unit_key] = unit - if logger_page: - unit.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(unit_key)) - unit.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(unit_key)) + if proto in TCP_PROTO: + var unit = TCP_PROTO[proto].new(unit_name) + var unit_key = repsettings.get_unit_key(unit_name) + units_tcp[unit_key] = unit + if logger_page: + unit.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(unit_key)) + unit.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(unit_key)) - tcp_sockets.append([create_tcpsocket('уарэп-5п28'), units_tcp[repsettings.get_unit_key('уарэп-5п28')]]) + tcp_sockets.append([create_tcpsocket('уарэп-5п28'), units_tcp[repsettings.get_unit_key('уарэп-5п28')]]) - for key in units: log.info('%s %s:%d' % [units[key].name, key[0], key[1]]) - for key in units_tcp: log.info('%s %s:%d' % [units_tcp[key].name, key[0], key[1]]) + for key in units: log.info('%s %s:%d' % [units[key].name, key[0], key[1]]) + for key in units_tcp: log.info('%s %s:%d' % [units_tcp[key].name, key[0], key[1]]) func poll_receive(sock: Socket, tick: int) -> bool: - while sock.get_available_packet_count() > 0: - var data: = sock.get_packet() - var addr: = sock.get_packet_ip() - var port: = sock.get_packet_port() - var addr_port: = [addr, port] - if addr_port in units: units[addr_port].parse(data, tick) - return false + while sock.get_available_packet_count() > 0: + var data: = sock.get_packet() + var addr: = sock.get_packet_ip() + var port: = sock.get_packet_port() + var addr_port: = [addr, port] + if addr_port in units: units[addr_port].parse(data, tick) + return false func poll_receive_tcp(sock: SocketTCP, tick: int) -> bool: - if sock.is_connection_available(): # check if someone's trying to connect - var client = sock.take_connection() # accept connection - sock.peerstream.set_stream_peer(client) # bind peerstream to new client - print_debug('client_is_connected') - var peer = sock.peerstream.get_stream_peer() - if peer: - var peer_len_data = peer.get_available_bytes() - if peer_len_data > 0: - get_client_data(sock, peer_len_data, peer, tick) - if sock.unit_key in units_tcp and sock.rx_all: units_tcp[sock.unit_key].parse(sock.rx_data, tick) - return false + if sock.is_connection_available(): # check if someone's trying to connect + var client = sock.take_connection() # accept connection + sock.peerstream.set_stream_peer(client) # bind peerstream to new client + print_debug('client_is_connected') + var peer = sock.peerstream.get_stream_peer() + if peer: + var peer_len_data = peer.get_available_bytes() + if peer_len_data > 0: + get_client_data(sock, peer_len_data, peer, tick) + if sock.unit_key in units_tcp and sock.rx_all: units_tcp[sock.unit_key].parse(sock.rx_data, tick) + return false func get_client_data(sock: SocketTCP, peer_len_data, peer, tick): - if tick - sock.rx_tick > sock.RX_TIMEOUT: - sock.rx_all = true - sock.rx_tick = tick - if sock.rx_all: - if peer_len_data >= sock.head_len: - sock.rx_all = false - sock.rx_len = sock.head_len - var head = peer.get_data(sock.head_len) - sock.data_len = head[1].decode_u32(sock.len_place) - var len_data_in_buf = peer.get_available_bytes() - if len_data_in_buf > 0: - sock.rx_data = head[1] - var len_rx = len_data_in_buf - if len_data_in_buf >= sock.data_len: - len_rx = sock.data_len - get_tcp_data(sock, peer, len_rx) - else: - var len_rx = (sock.head_len + sock.data_len) - sock.rx_len - if peer_len_data < len_rx: - len_rx = peer_len_data - get_tcp_data(sock, peer, len_rx) + if tick - sock.rx_tick > sock.RX_TIMEOUT: + sock.rx_all = true + sock.rx_tick = tick + if sock.rx_all: + if peer_len_data >= sock.head_len: + sock.rx_all = false + sock.rx_len = sock.head_len + var head = peer.get_data(sock.head_len) + sock.data_len = head[1].decode_u32(sock.len_place) + var len_data_in_buf = peer.get_available_bytes() + if len_data_in_buf > 0: + sock.rx_data = head[1] + var len_rx = len_data_in_buf + if len_data_in_buf >= sock.data_len: + len_rx = sock.data_len + get_tcp_data(sock, peer, len_rx) + else: + var len_rx = (sock.head_len + sock.data_len) - sock.rx_len + if peer_len_data < len_rx: + len_rx = peer_len_data + get_tcp_data(sock, peer, len_rx) func get_tcp_data(sock: SocketTCP, peer, len_rx): - var temp_data = peer.get_data(len_rx)[1] - sock.rx_data.append_array(temp_data) - sock.rx_len += len_rx - if sock.rx_len >= sock.head_len + sock.data_len: - sock.rx_all = true + var temp_data = peer.get_data(len_rx)[1] + sock.rx_data.append_array(temp_data) + sock.rx_len += len_rx + if sock.rx_len >= sock.head_len + sock.data_len: + sock.rx_all = true func _process(_delta: float) -> void: - var tick = Time.get_ticks_msec() - for addr in units: - var unit = units[addr] - match unit.process(tick): - Error.OK: sock_unicast.send_to(addr, unit.tx_data) - Error.FAILED: emit_signal('socket_error', 'ошибка: %s %s:%d' % [unit, addr[0], addr[1]]) - for sock_unit in tcp_sockets: - var sock = sock_unit[0] - var unit = sock_unit[1] - match unit.process(tick): - Error.OK: sock.send_to(unit.tx_data) - Error.FAILED: emit_signal('socket_error', 'ошибка: %s' %unit) - poll_receive_tcp(sock, tick) - poll_sockets.any(func(sock): poll_receive(sock, tick)) + var tick = Time.get_ticks_msec() + for addr in units: + var unit = units[addr] + match unit.process(tick): + Error.OK: sock_unicast.send_to(addr, unit.tx_data) + Error.FAILED: emit_signal('socket_error', 'ошибка: %s %s:%d' % [unit, addr[0], addr[1]]) + for sock_unit in tcp_sockets: + var sock = sock_unit[0] + var unit = sock_unit[1] + match unit.process(tick): + Error.OK: sock.send_to(unit.tx_data) + Error.FAILED: emit_signal('socket_error', 'ошибка: %s' %unit) + poll_receive_tcp(sock, tick) + poll_sockets.any(func(sock): poll_receive(sock, tick)) diff --git a/scripts/repsettings.gd b/scripts/repsettings.gd index 4ca1c06a..131afebc 100644 --- a/scripts/repsettings.gd +++ b/scripts/repsettings.gd @@ -1,50 +1,49 @@ -extends Node - -## Параметры +class_name rep_settings extends Node +## Параметры. @export var UnitProfiles: = { \ - # Название | Протокол | Адрес | Порт | Широковещательное | Привязывать к адресу | Комментарий - 'уарэп-яу07-частный': ['yau07rx', '10.1.1.2', 50002, false, true, 'IP-адрес на котором принимают частные сообщения от ЯУ-07'], - 'уарэп-яу07-общий': ['yau07rx', '10.1.1.255', 50000, true, true, 'IP-адрес на котором принимают широковещательные сообщения от ЯУ-07'], - 'уарэп-капсрпб-пол': ['jsonrx', '127.0.0.1', 42023, false, true, 'IP-адрес на котором принимают сообщения от КАПС РПБ'], - 'уарэп-капсрпб-отп': ['jsontx', '127.0.0.1', 42022, false, false, 'IP-адрес на который отправляют сообщения для КАПС РПБ'], - 'уарэп-эмс': ['yau07tx', '10.1.1.27', 50027, false, false, 'IP-адрес ЯУ-07 прибора УФ'], - 'уарэп-яу07-2в': ['yau07tx', '10.1.1.34', 50034, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], - 'уарэп-яу07-2н': ['yau07tx', '10.1.1.33', 50033, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], - 'уарэп-яу07-2к': ['yau07tx', '10.1.1.35', 50035, false, false, 'IP-адрес ЯУ-07 прибора ПРД-К'], - 'уарэп-яу07-4в': ['yau07tx', '10.1.1.66', 50066, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], - 'уарэп-яу07-4н': ['yau07tx', '10.1.1.65', 50065, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], - 'уарэп-яу07-4к': ['yau07tx', '10.1.1.67', 50067, false, false, 'IP-адрес ЯУ-07 прибора ПРД-К'], - 'уарэп-яу07-1в': ['yau07tx', '10.1.1.18', 50018, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], - 'уарэп-яу07-1н': ['yau07tx', '10.1.1.17', 50017, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], - 'уарэп-яу07-1к': ['yau07tx', '10.1.1.19', 50019, false, false, 'IP-адрес ЯУ-07 прибора ПРД-К'], - 'уарэп-яу07-3в': ['yau07tx', '10.1.1.50', 50050, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], - 'уарэп-яу07-3н': ['yau07tx', '10.1.1.49', 50049, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], - 'уарэп-яу07-3к': ['yau07tx', '10.1.1.51', 50051, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], + # Название | Протокол | Адрес | Порт | Широковещательное | Привязывать к адресу | Комментарий + 'уарэп-яу07-частный': ['yau07rx', '10.1.1.2', 50002, false, true, 'IP-адрес на котором принимают частные сообщения от ЯУ-07'], + 'уарэп-яу07-общий': ['yau07rx', '10.1.1.255', 50000, true, true, 'IP-адрес на котором принимают широковещательные сообщения от ЯУ-07'], + 'уарэп-капсрпб-пол': ['jsonrx', '127.0.0.1', 42023, false, true, 'IP-адрес на котором принимают сообщения от КАПС РПБ'], + 'уарэп-капсрпб-отп': ['jsontx', '127.0.0.1', 42022, false, false, 'IP-адрес на который отправляют сообщения для КАПС РПБ'], + 'уарэп-эмс': ['yau07tx', '10.1.1.27', 50027, false, false, 'IP-адрес ЯУ-07 прибора УФ'], + 'уарэп-яу07-2в': ['yau07tx', '10.1.1.34', 50034, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], + 'уарэп-яу07-2н': ['yau07tx', '10.1.1.33', 50033, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], + 'уарэп-яу07-2к': ['yau07tx', '10.1.1.35', 50035, false, false, 'IP-адрес ЯУ-07 прибора ПРД-К'], + 'уарэп-яу07-4в': ['yau07tx', '10.1.1.66', 50066, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], + 'уарэп-яу07-4н': ['yau07tx', '10.1.1.65', 50065, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], + 'уарэп-яу07-4к': ['yau07tx', '10.1.1.67', 50067, false, false, 'IP-адрес ЯУ-07 прибора ПРД-К'], + 'уарэп-яу07-1в': ['yau07tx', '10.1.1.18', 50018, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], + 'уарэп-яу07-1н': ['yau07tx', '10.1.1.17', 50017, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], + 'уарэп-яу07-1к': ['yau07tx', '10.1.1.19', 50019, false, false, 'IP-адрес ЯУ-07 прибора ПРД-К'], + 'уарэп-яу07-3в': ['yau07tx', '10.1.1.50', 50050, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], + 'уарэп-яу07-3н': ['yau07tx', '10.1.1.49', 50049, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], + 'уарэп-яу07-3к': ['yau07tx', '10.1.1.51', 50051, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], - # Название | Протокол | Адрес | Порт получения | Комментарий - 'уарэп-5п28': ['5p28', '127.0.0.1', 50000, 'IP-адрес комплекса 5П-28'], + # Название | Протокол | Адрес | Порт получения | Комментарий + 'уарэп-5п28': ['5p28', '127.0.0.1', 50000, 'IP-адрес комплекса 5П-28'], - # Название | Протокол | Адрес | Порт получения | Порт отправки | Комментарий - 'уарэп-щ3': ['udp-json-mbcs', 'localhost', 48000, 44100, 'IP-адрес и порты через которые производят обмен сообщения с драйвером клиента Modbus Serial'], + # Название | Протокол | Адрес | Порт получения | Порт отправки | Комментарий + 'уарэп-щ3': ['udp-json-mbcs', 'localhost', 48000, 44100, 'IP-адрес и порты через которые производят обмен сообщения с драйвером клиента Modbus Serial'], - # Название | Протокол | Имя порта | Скорость, бод | Чётность | Комментарий - 'уарэп-спт25-1': ['uart', '/dev/tty2', 115200, false, 'Адрес прибора СПТ-25 (G1)'], - 'уарэп-спт25-2': ['uart', '/dev/tty3', 115200, false, 'Адрес прибора СПТ-25 (G2)'], + # Название | Протокол | Имя порта | Скорость, бод | Чётность | Комментарий + 'уарэп-спт25-1': ['uart', '/dev/tty2', 115200, false, 'Адрес прибора СПТ-25 (G1)'], + 'уарэп-спт25-2': ['uart', '/dev/tty3', 115200, false, 'Адрес прибора СПТ-25 (G2)'], } -## Параметры цели +## Параметры цели. @export var ThreatParams = { - 'time_lost': 5000 ## Время после последнего обновления в мс, через которое цель считается потерянной. - } + 'time_lost': 5000 ## Время после последнего обновления в мс, через которое цель считается потерянной. + } func _ready() -> void: log.info('Модуль настроек готов') -## Возвращает ключ устройства +## Возвращает ключ устройства. func get_unit_key(unit_name: String) -> Array: - assert(UnitProfiles.has(unit_name), 'ошибка: нет такого устройства \"%s\"' % unit_name) - var item = UnitProfiles[unit_name] - return [item[1], item[2]] + assert(UnitProfiles.has(unit_name), 'ошибка: нет такого устройства \"%s\"' % unit_name) + var item = UnitProfiles[unit_name] + return [item[1], item[2]] diff --git a/scripts/signaller.gd b/scripts/signaller.gd index 77718839..05f9591a 100644 --- a/scripts/signaller.gd +++ b/scripts/signaller.gd @@ -1,43 +1,43 @@ class_name Signaller extends Node -## Обмен сигналами между узлами. Здесь объявлены сигналы, которые используют +## Обмен сигналами между узлами. Здесь объявлены сигналы, которые используют. ## два и более узла, из разных файлов. Должен быть помещён в автозагрузку. func conn(sgnl: Signal, clbl: Callable): connect(sgnl.get_name(), clbl) -## Вызывается при переходе в режим [b]Работа[/b] +## Вызывается при переходе в режим [b]Работа[/b]. signal режим_работа() -## Вызывается при переходе в режим [b]Контроль[/b] +## Вызывается при переходе в режим [b]Контроль[/b]. signal режим_контроль() -## Вызывается при переходе в режим [b]Журнал[/b] +## Вызывается при переходе в режим [b]Журнал[/b]. signal режим_журнал() -## Вызывается при переходе в режим [b]ЭМС[/b] +## Вызывается при переходе в режим [b]ЭМС[/b]. signal режим_эмс() -## Вызывается при переходе в режим [b]Настройка[/b] +## Вызывается при переходе в режим [b]Настройка[/b]. signal режим_настройки() -## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора цели и помехи[/b] +## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора цели и помехи[/b]. signal full_auto() -## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора цели[/b] +## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора цели[/b]. signal threat_auto() -## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора помехи[/b] +## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора помехи[/b]. signal interfer_auto() -## Вызывается, когда оператор переводит программу в режим [b]Ручной[/b] +## Вызывается, когда оператор переводит программу в режим [b]Ручной[/b]. signal manual_control() @@ -59,21 +59,21 @@ signal full_screen(id: int) ## Вызывается, когда пользователь выбирает цель.[br] -## [param th_id] - Отметка цели на экране +## [param th_id] - Отметка цели на экране. signal rto_threat_sel (th_id: int) ## Вызывается, когда пользователь нажимает на значёк цели.[br] -## [param th_id] - Отметка цели на экране +## [param th_id] - Отметка цели на экране. signal bip_pressed (th_id: int) ## Вызывается, когда пользователь снимает выделение с цели.[br] -## [param th_id] - Отметка цели на экране +## [param th_id] - Отметка цели на экране. signal rto_threat_unsel (th_id: int) -## Вызывается, когда пользователь снимает выделение со всех целей +## Вызывается, когда пользователь снимает выделение со всех целей. signal rto_threat_unsel_all () @@ -100,32 +100,32 @@ signal interfer_new (ecm: interfer.Interfer) signal interfer_off (ecm: interfer.Interfer, ecms: Dictionary, thrs: Dictionary) -## Вызывается при нажатии отключить все помехи +## Вызывается при нажатии отключить все помехи. signal interfer_off_all () -## Вызывается при получении внешнего целеуказания +## Вызывается при получении внешнего целеуказания. ## [param interfer_params] - Параметры полученной помехи от 5П-28.[br] signal interfer_rcv(interfer_params: Array) ## Вызывается, когда отключается действующая помеха.[br] -## [param ecm] - Выбранная помеха +## [param ecm] - Выбранная помеха. signal interfer_selected (ecm: interfer.Interfer) ## Вызывается, когда отключается выбираем помеху по сектору в таблице.[br] -## [param ecm] - Выбранная помеха +## [param ecm] - Выбранная помеха. signal fs_selected(ecm: interfer.Interfer) ## Вызывается при запросе изменения уровня детализации карты.[br] -## [param zoom] - Вновь установленный уровень детализации +## [param zoom] - Вновь установленный уровень детализации. signal zoom_changed(zoom: int) ## Вызывается при завершении изменения уровня детализации карты.[br] -## [param zoom] - Вновь установленный уровень детализации +## [param zoom] - Вновь установленный уровень детализации. signal zoom_complete(zoom: int) @@ -135,5 +135,5 @@ signal map_coords_changed(lan: float, lat: float) ## Вызывается при изменении размера изображения для отображения карты.[br] -## [param mode] - Вновь установленный режим +## [param mode] - Вновь установленный режим. signal map_mode_changed(mode: int) diff --git a/scripts/tcp5p28.gd b/scripts/tcp5p28.gd index cc7811bf..47bafdfc 100644 --- a/scripts/tcp5p28.gd +++ b/scripts/tcp5p28.gd @@ -1,193 +1,193 @@ -extends Node +class_name tcp5_p28 extends Node -## Реализация "Протокол информационного сопряжения -## СПО АСУ изделия «МП‑550» с СПО 5П-28" +## Реализация "Протокол информационного сопряжения. +## СПО АСУ изделия «МП‑550» с СПО 5П-28". -const ONLINE_TIMEOUT = 5000 ## Время ожидания пакета от 5П-28, мс -const BUFFER_SIZE = 2048 ## Размер приёмного буфера для датаграмм +const ONLINE_TIMEOUT = 5000 ## Время ожидания пакета от 5П-28, мс. +const BUFFER_SIZE = 2048 ## Размер приёмного буфера для датаграмм. -## Тип модуляции для запаковки в пакет для 5П-28 +## Тип модуляции для запаковки в пакет для 5П-28. const MOD_TYPES: Array = ['', - 'am', - 'ook', - 'ask', - 'fm', - 'qpsk', - 'oqpsk', - 'pi4qpsk', - 'qam16', - 'qam32', - 'qam64', - 'qam128', - 'qam256', - 'qam512', - 'cpfsk', - 'psk', - 'ofdm',] + 'am', + 'ook', + 'ask', + 'fm', + 'qpsk', + 'oqpsk', + 'pi4qpsk', + 'qam16', + 'qam32', + 'qam64', + 'qam128', + 'qam256', + 'qam512', + 'cpfsk', + 'psk', + 'ofdm',] const CU_STATE: Dictionary = { - 0:2, # Подготовка к выполнению - 1:1, # Выполняется - 2:9, # Ошибка в команде - 3:7, # Занят выполнением другого ЦУ - 4:9, # Неисправность - } + 0:2, # Подготовка к выполнению + 1:1, # Выполняется + 2:9, # Ошибка в команде + 3:7, # Занят выполнением другого ЦУ + 4:9, # Неисправность + } class TCP5P28: - const PACK_TYPE_CMD: int = 1 - const PACK_TYPE_RES: int = 2 - const CMD_TYPE_STATE: int = 1 - const CMD_TYPE_TH: int = 2 - const CMD_TYPE_IN: int = 3 + const PACK_TYPE_CMD: int = 1 + const PACK_TYPE_RES: int = 2 + const CMD_TYPE_STATE: int = 1 + const CMD_TYPE_TH: int = 2 + const CMD_TYPE_IN: int = 3 - signal line_changed(unit: TCP5P28) ## Сигнал состояние связи изменилось - signal data_received(unit: TCP5P28) ## Сигнал данные приняты - signal command_fail(unit: TCP5P28) ## Сигнал при не выполнении команды - signal parse_error(unit: TCP5P28, msg: String) ## Сигнал ошибки разбора сообщения - signal get_threats(unit: TCP5P28) ## Сигнал запрос целей - signal get_interfers(unit: TCP5P28) ## Запрос состояния выполнения целеуказания + signal line_changed(unit: TCP5P28) ## Сигнал состояние связи изменилось. + signal data_received(unit: TCP5P28) ## Сигнал данные приняты. + signal command_fail(unit: TCP5P28) ## Сигнал при не выполнении команды. + signal parse_error(unit: TCP5P28, msg: String) ## Сигнал ошибки разбора сообщения. + signal get_threats(unit: TCP5P28) ## Сигнал запрос целей. + signal get_interfers(unit: TCP5P28) ## Запрос состояния выполнения целеуказания. - var online: = false ## Состояние связи с источником сообщений - var name: String ## Имя экземпляра - var rx_tick: = 0 ## Тик время последнего приёма, мс - var tx_data: = PackedByteArray() ## Пакет для отправки - var tx_stack: Array ## Массив пакетов для отправки + var online: = false ## Состояние связи с источником сообщений. + var name: String ## Имя экземпляра. + var rx_tick: = 0 ## Тик время последнего приёма, мс. + var tx_data: = PackedByteArray() ## Пакет для отправки. + var tx_stack: Array ## Массив пакетов для отправки. - func _to_string() -> String: return String('капсрпб: "%s" %s ' % [self.name, ['отключен', 'на связи'][int(online)]]) - func _init(nm): self.name = nm + func _to_string() -> String: return String('капсрпб: "%s" %s ' % [self.name, ['отключен', 'на связи'][int(online)]]) + func _init(nm): self.name = nm - func parse(data: PackedByteArray, now_tick: int): - rx_tick = now_tick - if not online: - online = true - emit_signal('line_changed', self) - var pack_type = data.decode_u8(2) - if pack_type == PACK_TYPE_CMD: - var cmd_type = data.decode_u8(8) - if cmd_type == CMD_TYPE_TH: - emit_signal('get_threats') - if cmd_type == CMD_TYPE_STATE: - emit_signal('get_interfers') - var external_cu = ProjectSettings.get_setting('application/config/external_cu', false) - if cmd_type == CMD_TYPE_IN and external_cu: - set_interfer(data) + func parse(data: PackedByteArray, now_tick: int): + rx_tick = now_tick + if not online: + online = true + emit_signal('line_changed', self) + var pack_type = data.decode_u8(2) + if pack_type == PACK_TYPE_CMD: + var cmd_type = data.decode_u8(8) + if cmd_type == CMD_TYPE_TH: + emit_signal('get_threats') + if cmd_type == CMD_TYPE_STATE: + emit_signal('get_interfers') + var external_cu = ProjectSettings.get_setting('application/config/external_cu', false) + if cmd_type == CMD_TYPE_IN and external_cu: + set_interfer(data) - func process(now_tick: int): - if online and ((now_tick - rx_tick) > ONLINE_TIMEOUT): - online = false - emit_signal('line_changed', self) - if len(tx_stack): - tx_data = tx_stack[0] - tx_stack.remove_at(0) - return Error.OK - else: - return Error.ERR_UNAVAILABLE + func process(now_tick: int): + if online and ((now_tick - rx_tick) > ONLINE_TIMEOUT): + online = false + emit_signal('line_changed', self) + if len(tx_stack): + tx_data = tx_stack[0] + tx_stack.remove_at(0) + return Error.OK + else: + return Error.ERR_UNAVAILABLE - func pack_threats(ths): - var data = PackedByteArray() - var data_len = 4 + len(ths) * 80 # длинна блока данных в байтах - var tick = Time.get_ticks_msec() - data.resize(4) - data.encode_u16(0, 0) # Код ошибки - data.encode_u16(2, len(ths)) # Количество целей - for th in ths.values(): - data.append_array(get_threats_data(th, int(tick))) - var data_to_send: PackedByteArray = create_header(data_len) - data_to_send.append_array(data) - tx_stack.append(data_to_send) + func pack_threats(ths): + var data = PackedByteArray() + var data_len = 4 + len(ths) * 80 # длинна блока данных в байтах + var tick = Time.get_ticks_msec() + data.resize(4) + data.encode_u16(0, 0) # Код ошибки + data.encode_u16(2, len(ths)) # Количество целей + for th in ths.values(): + data.append_array(get_threats_data(th, int(tick))) + var data_to_send: PackedByteArray = create_header(data_len) + data_to_send.append_array(data) + tx_stack.append(data_to_send) - func pack_interfers(interfers, ecms): - var data = PackedByteArray() - var data_len = 12 # длинна блока данных в байтах - data.resize(data_len) - data.encode_u16(0, 0) # Код ошибки - data.encode_u16(2, len(interfers)) # Количество целей - data.encode_u32(4, 0) # Состояние УА-РЕП - data.encode_u32(8, 0) # Состояние линий связи - for id in interfers.values(): - var cu_data: PackedByteArray = [] - cu_data.resize(4) - var cu = ecms[id] - cu_data.encode_u16(0, cu.ispp) - var state: int - if CU_STATE.has(cu.svk): - state = CU_STATE[cu.svk] - else: - state = 9 - cu_data.encode_u8(2, state) # Состояние выполнения команды - cu_data.encode_u8(3, 0xFF) # Эффективность работы помехи - data.append_array(cu_data) - var data_to_send: PackedByteArray = create_header(data_len + 4 * len(interfers)) - data_to_send.append_array(data) - tx_stack.append(data_to_send) + func pack_interfers(interfers, ecms): + var data = PackedByteArray() + var data_len = 12 # длинна блока данных в байтах + data.resize(data_len) + data.encode_u16(0, 0) # Код ошибки + data.encode_u16(2, len(interfers)) # Количество целей + data.encode_u32(4, 0) # Состояние УА-РЕП + data.encode_u32(8, 0) # Состояние линий связи + for id in interfers.values(): + var cu_data: PackedByteArray = [] + cu_data.resize(4) + var cu = ecms[id] + cu_data.encode_u16(0, cu.ispp) + var state: int + if CU_STATE.has(cu.svk): + state = CU_STATE[cu.svk] + else: + state = 9 + cu_data.encode_u8(2, state) # Состояние выполнения команды + cu_data.encode_u8(3, 0xFF) # Эффективность работы помехи + data.append_array(cu_data) + var data_to_send: PackedByteArray = create_header(data_len + 4 * len(interfers)) + data_to_send.append_array(data) + tx_stack.append(data_to_send) - func create_header(data_len): - var head_data = PackedByteArray() - head_data.resize(8) # Размер заголовка - head_data.encode_u16(0, 0) # Код ошибки - head_data.encode_u8(2, 2) # Тип пакета, ответ на запрос - head_data.encode_u8(3, 5) # Версия протокола, всегда 5 - head_data.encode_u32(4, data_len) # Длинна пакета данных - return head_data + func create_header(data_len): + var head_data = PackedByteArray() + head_data.resize(8) # Размер заголовка + head_data.encode_u16(0, 0) # Код ошибки + head_data.encode_u8(2, 2) # Тип пакета, ответ на запрос + head_data.encode_u8(3, 5) # Версия протокола, всегда 5 + head_data.encode_u32(4, data_len) # Длинна пакета данных + return head_data - func get_threats_data(th, tick): - var th_data = PackedByteArray() - th_data.resize(80) # Количество байт в массиве - th_data.encode_u64(0, tick) - var flags: int = 0 # с 0 по 7 бит рекомендованная помеха - flags |= 0 << 8 # Флаг рекомендуемой помехи - flags |= int(th.fflags['aoa']) << 9 # Флаг доставерности пеленга - flags |= int(th.fflags['alt']) << 10 # Флаг доставерности высоты - flags |= int(th.fflags['power']) << 11 # Флаг доставерности мощности - flags |= int(th.fflags['baud']) << 12 # Флаг доставерности ск. мод. - flags |= int(th.fflags['slon']) << 13 # Флаг доставерности долготы ст. позиции - flags |= int(th.fflags['slat']) << 14 # Флаг доставерности широты ст. позиции - flags |= int(th.fflags['lon']) << 15 # Флаг доставерности долготы - flags |= int(th.fflags['lat']) << 16 # Флаг доставерности широты - flags |= int(0) << 30 # Флаг признак назначения помехи на цель - flags |= int(0) << 31 # Флаг признак назначения опасной цель - th_data.encode_u32(8, flags) # Флаги - th_data.encode_u16(12, th.id) # Идентификатор объекта - th_data.encode_u16(14, int(round(th.aoa/0.1))) # Пеленг объекта - th_data.encode_u16(16, int(th.alt)) # Высота объекта - th_data.encode_u16(18, int(th.freq)) # Частота объекта - th_data.encode_u16(20, int(th.width)) # Ширина частотной полосы объекта - th_data.encode_u8(22, int(th.power)) # Мощность излучения объекта - var mod = MOD_TYPES.find(th.tmod) - if mod == -1: mod = 0 - th_data.encode_u8(23, int(mod)) # Тип модуляции - th_data.encode_u32(24, int(th.baud)) # Скорость модуляции, бод - to_cp866(th.proto, th_data) - var c1 = pow(2, 30) / 180.0 - th_data.encode_s32(64, int(th.slon * c1)) - th_data.encode_s32(68, int(th.slat * c1)) - th_data.encode_s32(72, int(th.lon * c1)) - th_data.encode_s32(76, int(th.lat * c1)) - return th_data + func get_threats_data(th, tick): + var th_data = PackedByteArray() + th_data.resize(80) # Количество байт в массиве + th_data.encode_u64(0, tick) + var flags: int = 0 # с 0 по 7 бит рекомендованная помеха + flags |= 0 << 8 # Флаг рекомендуемой помехи + flags |= int(th.fflags['aoa']) << 9 # Флаг доставерности пеленга + flags |= int(th.fflags['alt']) << 10 # Флаг доставерности высоты + flags |= int(th.fflags['power']) << 11 # Флаг доставерности мощности + flags |= int(th.fflags['baud']) << 12 # Флаг доставерности ск. мод. + flags |= int(th.fflags['slon']) << 13 # Флаг доставерности долготы ст. позиции + flags |= int(th.fflags['slat']) << 14 # Флаг доставерности широты ст. позиции + flags |= int(th.fflags['lon']) << 15 # Флаг доставерности долготы + flags |= int(th.fflags['lat']) << 16 # Флаг доставерности широты + flags |= int(0) << 30 # Флаг признак назначения помехи на цель + flags |= int(0) << 31 # Флаг признак назначения опасной цель + th_data.encode_u32(8, flags) # Флаги + th_data.encode_u16(12, th.id) # Идентификатор объекта + th_data.encode_u16(14, int(round(th.aoa/0.1))) # Пеленг объекта + th_data.encode_u16(16, int(th.alt)) # Высота объекта + th_data.encode_u16(18, int(th.freq)) # Частота объекта + th_data.encode_u16(20, int(th.width)) # Ширина частотной полосы объекта + th_data.encode_u8(22, int(th.power)) # Мощность излучения объекта + var mod = MOD_TYPES.find(th.tmod) + if mod == -1: mod = 0 + th_data.encode_u8(23, int(mod)) # Тип модуляции + th_data.encode_u32(24, int(th.baud)) # Скорость модуляции, бод + to_cp866(th.proto, th_data) + var c1 = pow(2, 30) / 180.0 + th_data.encode_s32(64, int(th.slon * c1)) + th_data.encode_s32(68, int(th.slat * c1)) + th_data.encode_s32(72, int(th.lon * c1)) + th_data.encode_s32(76, int(th.lat * c1)) + return th_data - func to_cp866(proto: String, th_data): - var cp866_proto: PackedByteArray = proto.to_ascii_buffer() - cp866_proto.resize(36) - for i in len(cp866_proto): - th_data[28 + i] = cp866_proto[i] + func to_cp866(proto: String, th_data): + var cp866_proto: PackedByteArray = proto.to_ascii_buffer() + cp866_proto.resize(36) + for i in len(cp866_proto): + th_data[28 + i] = cp866_proto[i] - func set_interfer(data): - var mode = data.decode_u8(9) - var id = data.decode_u16(10) - var aoa = float(data.decode_u16(12)) / 10 - var ela = float(data.decode_u16(14)) / 10 - var freq = data.decode_u16(16) - var width = data.decode_u16(18) - var interfer_params: Array = [mode, id, aoa, ela, freq, width] - signaller.emit_signal('interfer_rcv', interfer_params) + func set_interfer(data): + var mode = data.decode_u8(9) + var id = data.decode_u16(10) + var aoa = float(data.decode_u16(12)) / 10 + var ela = float(data.decode_u16(14)) / 10 + var freq = data.decode_u16(16) + var width = data.decode_u16(18) + var interfer_params: Array = [mode, id, aoa, ela, freq, width] + signaller.emit_signal('interfer_rcv', interfer_params) - func on_interfer_accept(err: bool): - var data_tx = PackedByteArray() - var data_len = 2 # длинна блока данных в байтах - data_tx.resize(data_len) - data_tx.encode_u16(0, err) # Код ошибки - var data_to_send: PackedByteArray = create_header(data_len) - data_to_send.append_array(data_tx) - tx_stack.append(data_to_send) + func on_interfer_accept(err: bool): + var data_tx = PackedByteArray() + var data_len = 2 # длинна блока данных в байтах + data_tx.resize(data_len) + data_tx.encode_u16(0, err) # Код ошибки + var data_to_send: PackedByteArray = create_header(data_len) + data_to_send.append_array(data_tx) + tx_stack.append(data_to_send) diff --git a/scripts/threats.gd b/scripts/threats.gd index b26ae779..e5793da6 100644 --- a/scripts/threats.gd +++ b/scripts/threats.gd @@ -1,40 +1,40 @@ extends Node -## Работа с целями +## Работа с целями. ## Цель class Threat: - var alt: float ## Текущая высота, метры. - var aoa: float ## Курсовой угол на источник сигнала, градусы. - var atick: float ## Тик обнаружения. - var baud: float ## Модуляционная скорость. - var fflags: Dictionary ## Флаги достоверности полей. - var freq: float ## Частота несущей или центральная частота, МГц. - var freqm: String ## Режим смены частоты. - var id: int ## Идентификатор цели. - var lat: float ## Текущие координаты, широта в градусах. - var lon: float ## Текущие координаты, долгота в градусах. - var power: float ## Уровень принимаемого сигнала, дБм. - var proto: String ## Тип протокола источника сигнала. - var rkrp: String ## Рекомендуемый режим помехи. - var rparams: String ## Рекомендуемые параметры помехи. - var salt: float ## Координаты старта, высота от уровня моря, м. - var slat: float ## Координаты старта, широта в градусах. - var slon: float ## Координаты старта, долгота в градусах. - var tick: int ## Тик время приёма сигнала, мс. - var tick_rx: int ## Тик время обновления цели, мс. - var tmod: String ## Тип модуляции. - var width: float ## Ширина занимаемого диапазона частот, МГц. - var selected: bool ## Флаг, что цель выбрана + var alt: float ## Текущая высота, метры. + var aoa: float ## Курсовой угол на источник сигнала, градусы. + var atick: float ## Тик обнаружения. + var baud: float ## Модуляционная скорость. + var fflags: Dictionary ## Флаги достоверности полей. + var freq: float ## Частота несущей или центральная частота, МГц. + var freqm: String ## Режим смены частоты. + var id: int ## Идентификатор цели. + var lat: float ## Текущие координаты, широта в градусах. + var lon: float ## Текущие координаты, долгота в градусах. + var power: float ## Уровень принимаемого сигнала, дБм. + var proto: String ## Тип протокола источника сигнала. + var rkrp: String ## Рекомендуемый режим помехи. + var rparams: String ## Рекомендуемые параметры помехи. + var salt: float ## Координаты старта, высота от уровня моря, м. + var slat: float ## Координаты старта, широта в градусах. + var slon: float ## Координаты старта, долгота в градусах. + var tick: int ## Тик время приёма сигнала, мс. + var tick_rx: int ## Тик время обновления цели, мс. + var tmod: String ## Тип модуляции. + var width: float ## Ширина занимаемого диапазона частот, МГц. + var selected: bool ## Флаг, что цель выбрана. - func _init(): clear_fflags() - func _to_string() -> String: return 'номер: %d пеленг: %0.1f частота: %0.1f МГц' % [id, aoa, freq] - func clear_fflags(): tools.get_members_names(self).any(func(vn): fflags[vn] = false) + func _init(): clear_fflags() + func _to_string() -> String: return 'номер: %d пеленг: %0.1f частота: %0.1f МГц' % [id, aoa, freq] + func clear_fflags(): tools.get_members_names(self).any(func(vn): fflags[vn] = false) - func set_from_dic(dic: Dictionary): - var items: = fflags.keys().filter(func(vn): return dic.has(vn)) - items.any(func(vn): set(vn, dic[vn]); fflags[vn] = true; return false) + func set_from_dic(dic: Dictionary): + var items: = fflags.keys().filter(func(vn): return dic.has(vn)) + items.any(func(vn): set(vn, dic[vn]); fflags[vn] = true; return false) signal threat_new(th: Threat) @@ -44,37 +44,37 @@ signal threats_resized(th: Dictionary) func _ready() -> void: - log.info('Модуль обработки целей готов') - var threats = {} ## Список целей. Индекс - <номер цели> - var unit_key = repsettings.get_unit_key('уарэп-капсрпб-отп') - var unit = repnetwork.units[unit_key] - var unit_5p28_key = repsettings.get_unit_key('уарэп-5п28') - var unit_5p28 = repnetwork.units_tcp[unit_5p28_key] - var timer_check_lost: = Timer.new() - add_child(timer_check_lost) - unit.connect('data_received', Callable(self, 'on_data_capsrpb_received').bind(threats)) - unit_5p28.connect('get_threats', Callable(self, 'on_get_threats').bind(unit_5p28, threats)) - timer_check_lost.connect('timeout', Callable(self, 'on_timer_check_lost').bind(repsettings.ThreatParams.time_lost, threats)) - timer_check_lost.start(repsettings.ThreatParams.time_lost / 1000.0) - signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind(threats)) - signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel').bind(threats)) - signaller.connect('rto_threat_unsel_all', Callable(self, 'on_rto_threat_unsel_all').bind(threats)) - signaller.connect('threat_selected', Callable(self, 'on_threat_selected').bind(threats)) - signaller.connect('interfer_init', Callable(self, 'on_interfer_init').bind(threats)) + log.info('Модуль обработки целей готов') + var threats = {} ## Список целей. Индекс - <номер цели> + var unit_key = repsettings.get_unit_key('уарэп-капсрпб-отп') + var unit = repnetwork.units[unit_key] + var unit_5p28_key = repsettings.get_unit_key('уарэп-5п28') + var unit_5p28 = repnetwork.units_tcp[unit_5p28_key] + var timer_check_lost: = Timer.new() + add_child(timer_check_lost) + unit.connect('data_received', Callable(self, 'on_data_capsrpb_received').bind(threats)) + unit_5p28.connect('get_threats', Callable(self, 'on_get_threats').bind(unit_5p28, threats)) + timer_check_lost.connect('timeout', Callable(self, 'on_timer_check_lost').bind(repsettings.ThreatParams.time_lost, threats)) + timer_check_lost.start(repsettings.ThreatParams.time_lost / 1000.0) + signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind(threats)) + signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel').bind(threats)) + signaller.connect('rto_threat_unsel_all', Callable(self, 'on_rto_threat_unsel_all').bind(threats)) + signaller.connect('threat_selected', Callable(self, 'on_threat_selected').bind(threats)) + signaller.connect('interfer_init', Callable(self, 'on_interfer_init').bind(threats)) -## Периодически удаляет устаревшие цели +## Периодически удаляет устаревшие цели. func on_timer_check_lost(time_lost: int, threats: Dictionary): - var tick = Time.get_ticks_msec() - var sz: = threats.size() - for th in threats.values(): - if (tick - th.tick_rx) >= time_lost: - threats.erase(th.id) - call_deferred('emit_signal', 'threat_lost', th) - if sz != threats.size(): - call_deferred('emit_signal', 'threats_resized', threats) + var tick = Time.get_ticks_msec() + var sz: = threats.size() + for th in threats.values(): + if (tick - th.tick_rx) >= time_lost: + threats.erase(th.id) + call_deferred('emit_signal', 'threat_lost', th) + if sz != threats.size(): + call_deferred('emit_signal', 'threats_resized', threats) -## отправляет словарь целей в юнит, для запаковки и отправки в 5П28 +## отправляет словарь целей в юнит, для запаковки и отправки в 5П28. func on_get_threats(unit, threats): unit.pack_threats(threats) @@ -82,56 +82,56 @@ func on_get_threats(unit, threats): unit.pack_threats(threats) func on_rto_threat_unsel(th_id, threats): threats[th_id].selected = false -## Снимает выделение со всех целей +## Снимает выделение со всех целей. func on_rto_threat_unsel_all(threats): - for th in threats.values(): - signaller.emit_signal('rto_threat_unsel', th.id) + for th in threats.values(): + signaller.emit_signal('rto_threat_unsel', th.id) ## Выбирает цель, если нажать по отметке цели. func on_rto_threat_sel(th_id, threats): on_threat_selected(threats[th_id], threats) -## Выбирает цель, если выбрать в таблице +## Выбирает цель, если выбрать в таблице. func on_threat_selected(th, threats): - for threat in threats.values(): - threat.selected = false - th.selected = true + for threat in threats.values(): + threat.selected = false + th.selected = true -## Формирует список выбранных целей для включения помехи +## Формирует список выбранных целей для включения помехи. func on_interfer_init(btn, fs_arr, threats): - var sel_threats: Array = [] - for threat in threats.values(): - if threat.selected: - sel_threats.append(threat) - if len(sel_threats) or (len(fs_arr)): - signaller.emit_signal('interfer_create', btn, sel_threats, fs_arr) + var sel_threats: Array = [] + for threat in threats.values(): + if threat.selected: + sel_threats.append(threat) + if len(sel_threats) or (len(fs_arr)): + signaller.emit_signal('interfer_create', btn, sel_threats, fs_arr) -## Производит приём целей +## Производит приём целей. func on_data_capsrpb_received(unit: capsrpb.CapsRpb, threats: Dictionary): - if not unit.json_dic.has('ts'): return - if unit.json_dic['ts'] != 5: return - if not unit.json_dic.has('mis'): return + if not unit.json_dic.has('ts'): return + if unit.json_dic['ts'] != 5: return + if not unit.json_dic.has('mis'): return - var mis = unit.json_dic['mis'] - var sz: = threats.size() - for dic_th in mis: - if dic_th is Dictionary: - if dic_th.has('id'): - var id = int(dic_th['id']) - if threats.has(id): - var th = threats[id] - th.clear_fflags() - th.set_from_dic(dic_th) - th.tick_rx = unit.tick - call_deferred('emit_signal', 'threat_update', th) - else: - var th = Threat.new() - th.set_from_dic(dic_th) - threats[id] = th - th.tick_rx = unit.tick - call_deferred('emit_signal', 'threat_new', th) - if sz != threats.size(): - call_deferred('emit_signal', 'threats_resized', threats) + var mis = unit.json_dic['mis'] + var sz: = threats.size() + for dic_th in mis: + if dic_th is Dictionary: + if dic_th.has('id'): + var id = int(dic_th['id']) + if threats.has(id): + var th = threats[id] + th.clear_fflags() + th.set_from_dic(dic_th) + th.tick_rx = unit.tick + call_deferred('emit_signal', 'threat_update', th) + else: + var th = Threat.new() + th.set_from_dic(dic_th) + threats[id] = th + th.tick_rx = unit.tick + call_deferred('emit_signal', 'threat_new', th) + if sz != threats.size(): + call_deferred('emit_signal', 'threats_resized', threats) diff --git a/scripts/tools.gd b/scripts/tools.gd index 77fb48c7..d253490e 100644 --- a/scripts/tools.gd +++ b/scripts/tools.gd @@ -1,10 +1,10 @@ @tool -extends Node +class_name Tools extends Node -## Простые часто используемые функции +## Простые часто используемые функции. -## Возвращает округлённое значение [param v] с точностью [param a] +## Возвращает округлённое значение [param v] с точностью [param a]. func round_to(v: float, a: float) -> float: return snappedf(v, -a if v < 0 else a) @@ -21,7 +21,7 @@ func radians(val: float): return (val * PI) / 180.0 func ibytes_to_word(buf: PackedByteArray, i: int) -> int: return buf[i] + (buf[i + 1] * 256) -## Возвращает расстояние от центра координат до точки +## Возвращает расстояние от центра координат до точки. func hypot(x: float, y: float) -> float: return sqrt(x * x + y * y) @@ -30,14 +30,14 @@ func is_overlap(x1, x2, y1, y2) -> bool: return max(x1, y1) <= min(x2, y2) func _check_index(obj, index) -> bool: - if obj is Dictionary: - if obj.has(index): - return true - elif obj is Array: - if index is int: - if (index >= 0) and (index < obj.size()): - return true - return false + if obj is Dictionary: + if obj.has(index): + return true + elif obj is Array: + if index is int: + if (index >= 0) and (index < obj.size()): + return true + return false ## Возвращает значение поля хранящегося по указанному пути внутри объекта.[br] @@ -48,15 +48,15 @@ func _check_index(obj, index) -> bool: ## [param ret_val[1]] - устанвлено в [b]true[/b], если поле найдено, и установлено в [b]false[/b], ## если искомое поле не найдено. func get_value_by_path(obj, paths: Array, ret_val: Array): - var index = paths.pop_at(0) - ret_val[1] = false - if paths.size(): - if _check_index(obj, index): - get_value_by_path(obj[index], paths, ret_val) - else: - if _check_index(obj, index): - ret_val[0] = obj[index] - ret_val[1] = true + var index = paths.pop_at(0) + ret_val[1] = false + if paths.size(): + if _check_index(obj, index): + get_value_by_path(obj[index], paths, ret_val) + else: + if _check_index(obj, index): + ret_val[0] = obj[index] + ret_val[1] = true ## Возвращает часть от входной строки ограниченную индексами символов.[br] @@ -65,75 +65,75 @@ func get_value_by_path(obj, paths: Array, ret_val: Array): ## [param i0] - Индекс начала части строки.[br] ## [param i1] - Индекс конца части строки. Возвращает все символы до этого индекса. func get_string_slice(s_in: String, s_out: Array, i0: int, i1: int): - for i in range(i0, i1): - if s_in[i] != '\'': - s_out[0] += s_in[i] + for i in range(i0, i1): + if s_in[i] != '\'': + s_out[0] += s_in[i] -## Производит преобразование из декартовой в полярную систему координат +## Производит преобразование из декартовой в полярную систему координат. func pos_calc(freq: float, aoa: float, pos0: Vector2, r0: float, r1: float, f0: float, f1: float): - var r = ((freq - f0) / (f1 - f0)) * r1 + r0 - var aoa_rad = radians(aoa) - PI / 2.0 - return Vector2(cos(aoa_rad), sin(aoa_rad)) * r + pos0 + var r = ((freq - f0) / (f1 - f0)) * r1 + r0 + var aoa_rad = radians(aoa) - PI / 2.0 + return Vector2(cos(aoa_rad), sin(aoa_rad)) * r + pos0 -## Отсекает значение до заданного диапазона +## Отсекает значение до заданного диапазона. func clip_value(val, val_min, val_max): - if val < val_min: val = val_min - if val > val_max: val = val_max - return val + if val < val_min: val = val_min + if val > val_max: val = val_max + return val -## Возвращает массив с именами членов [param obj] +## Возвращает массив с именами членов [param obj]. func get_members_names(obj: Object) -> Array: - var pl = obj.get_property_list() - var names: = Array() - for item in pl: names.append(item.name) - return names + var pl = obj.get_property_list() + var names: = Array() + for item in pl: names.append(item.name) + return names -## Проверяет, что заданный массив [param val] похож на ip-адрес +## Проверяет, что заданный массив [param val] похож на ip-адрес. func is_array_ipaddr(val: Array): - return (val.size() == 2) \ - and (val[0] is String) \ - and (val[1] is int) \ - and (0 < val[1]) \ - and (val[1] < 65536) + return (val.size() == 2) \ + and (val[0] is String) \ + and (val[1] is int) \ + and (0 < val[1]) \ + and (val[1] < 65536) ## Преобразует декартовые координаты в полярные.[br] ## [param pos0] - координаты центра.[br] ## [param pos] - координаты точки.[br] func map_dec_to_rad(pos0: Vector2, pos: Vector2) -> Vector2: - var x1: float = pos.x - pos0.x - var y1: float = pos.y - pos0.y - var ang: float = (atan2(y1, x1) * 180.0) / PI - return Vector2(ang + 360.0 * float(ang < 0.0), hypot(x1, y1)) + var x1: float = pos.x - pos0.x + var y1: float = pos.y - pos0.y + var ang: float = (atan2(y1, x1) * 180.0) / PI + return Vector2(ang + 360.0 * float(ang < 0.0), hypot(x1, y1)) -## Переводит значение val из диапазона a0...a1 в диапазон b0...b1 +## Переводит значение val из диапазона a0...a1 в диапазон b0...b1. func map_range(val: float, a0: float, a1: float, b0: float, b1: float) -> float: - return (((val - a0) * (b1 - b0)) / (a1 - a0)) + b0 + return (((val - a0) * (b1 - b0)) / (a1 - a0)) + b0 ## Возвращает [b]true[/b], если точка внутри заданного полигона.[br] ## [param pos] - Проверяемая точка.[br] ## [param p] - Координаты вершин полигона.[br] func is_point_in_polygon(pos: Vector2, p: PackedVector2Array) -> bool: - var sz: = p.size() - assert(sz) - var j: int = sz - 1 - var odd_nodes: int = 0 - for i in sz: - if ((p[i].y < pos.y and p[j].y >= pos.y or p[j].y < pos.y and p[i].y >= pos.y) and (p[i].x <= pos.x or p[j].x <= pos.x)): - odd_nodes ^= int((p[i].x + (pos.y - p[i].y) / (p[j].y - p[i].y) * (p[j].x - p[i].x) < pos.x)) - j = i - return odd_nodes > 0 + var sz: = p.size() + assert(sz) + var j: int = sz - 1 + var odd_nodes: int = 0 + for i in sz: + if ((p[i].y < pos.y and p[j].y >= pos.y or p[j].y < pos.y and p[i].y >= pos.y) and (p[i].x <= pos.x or p[j].x <= pos.x)): + odd_nodes ^= int((p[i].x + (pos.y - p[i].y) / (p[j].y - p[i].y) * (p[j].x - p[i].x) < pos.x)) + j = i + return odd_nodes > 0 -## Записывает слово [param val] в элемент байтовго массива [param buf] +## Записывает слово [param val] в элемент байтовго массива [param buf]. ## расположенный по индексу [param index] (младшее слово).[br] ## [i]Следует использовать встроенные в[/i] [b]PackedByteArray[/b] [i]методы вместо этой функции.[/i] func set_wordi(buf: PackedByteArray, index: int, val: int) -> void: - buf[index] = val & 0xff - buf[index + 1] = (val >> 8) & 0xff + buf[index] = val & 0xff + buf[index + 1] = (val >> 8) & 0xff diff --git a/scripts/yau07.gd b/scripts/yau07.gd index e3832ad8..f5a43fa5 100644 --- a/scripts/yau07.gd +++ b/scripts/yau07.gd @@ -1,6 +1,6 @@ -extends Node +class_name yau_07 extends Node -## Протокол ячейки ЯУ-07 +## Протокол ячейки ЯУ-07. const ONLINE_TIMEOUT = 5.0 ## Время ожидания пакета от ячейки, секунды const RESEND_TIMEOUT = 0.3 ## Задержка для повторной отправки команды, секунды @@ -8,242 +8,242 @@ const RETRY_COUNT = 5 ## Количество повторных отпр const BUFFER_SIZE = 2048 ## Размер буфера для приёма датаграмм -## Ячейка ЯУ-07 +## Ячейка ЯУ-07. class YaU07: - ## Коды выполняемых команд - enum CmdCode { - READ_ISA = 0, ## Код команды "читать порт ISA" ячейки ЯУ-07 - WRITE_ISA = 1, ## Код команды "записать порт ISA" ячейки ЯУ-07 - WRITE_BLOCK = 60, ## Код команды "записать блок данных ISA" внешней шины ячейки ЯУ-07 - READ_BLOCK = 61, ## Код команды "читать блок данных ISA" внешней шины ячейки ЯУ-07 - } + ## Коды выполняемых команд. + enum CmdCode { + READ_ISA = 0, ## Код команды "читать порт ISA" ячейки ЯУ-07. + WRITE_ISA = 1, ## Код команды "записать порт ISA" ячейки ЯУ-07. + WRITE_BLOCK = 60, ## Код команды "записать блок данных ISA" внешней шины ячейки ЯУ-07. + READ_BLOCK = 61, ## Код команды "читать блок данных ISA" внешней шины ячейки ЯУ-07. + } - ## Состояние автомата выполнения команды - enum CmdState { - UNCK, ## Номер команды не ининциирован - SEND, ## Буфер готов для отправки - WAIT, ## Ожидание выполнения - DONE, ## Команда выполнена - FAIL ## Команда не выполнена - } + ## Состояние автомата выполнения команды. + enum CmdState { + UNCK, ## Номер команды не ининциирован. + SEND, ## Буфер готов для отправки. + WAIT, ## Ожидание выполнения. + DONE, ## Команда выполнена. + FAIL ## Команда не выполнена. + } - signal line_changed(unit: YaU07) ## Вызывается когда меняется состояние связи с ячейкой - signal command_done(unit: YaU07) ## Вызывается после выполнения команды - signal command_fail(unit: YaU07) ## Вызывается если возникла ошибка при выполнении команды и команда не выполнена - signal parse_failed(unit: YaU07) + signal line_changed(unit: YaU07) ## Вызывается когда меняется состояние связи с ячейкой. + signal command_done(unit: YaU07) ## Вызывается после выполнения команды. + signal command_fail(unit: YaU07) ## Вызывается если возникла ошибка при выполнении команды и команда не выполнена. + signal parse_failed(unit: YaU07) - var name: = String() - var cmd_num_rx: = 0 ## Номер команды принятый - var cmd_num_tx: = 0 ## Номер команды переданный - var cmd_state = CmdState.UNCK ## Состояние выполнения команды - var cmd_result: = 1 ## Результат выполнения команды. Устанавливается в ЯУ-07 - var cmd_data: = PackedByteArray() ## Данные команды. Устанавливается в ЯУ-07 - var cmd_retry = 0 ## Счётчик оставшихся попыток выполнить команду - var tick = 0.0 ## Текущее тик-время в мс - var cmd_tick_tx = 0.0 ## Время последней отправки команды - var cmd_tick_rx = 0.0 ## Время последнего приёма команды - var status: = PackedByteArray() ## Поле "состояние прибора" - var tx_data: = PackedByteArray() ## Буфер отправленный - var tx_len = 0 ## Длина последнего отправленного пакета - var isa_ports = {} ## Результат выполнения команды "читать порт" - var isa_block = {} ## Результат выполнения команды "читать массив из порта" - var online = false ## Состояние связи с ячейкой + var name: = String() + var cmd_num_rx: = 0 ## Номер команды принятый. + var cmd_num_tx: = 0 ## Номер команды переданный. + var cmd_state = CmdState.UNCK ## Состояние выполнения команды. + var cmd_result: = 1 ## Результат выполнения команды. Устанавливается в ЯУ-07. + var cmd_data: = PackedByteArray() ## Данные команды. Устанавливается в ЯУ-07. + var cmd_retry = 0 ## Счётчик оставшихся попыток выполнить команду. + var tick = 0.0 ## Текущее тик-время в мс. + var cmd_tick_tx = 0.0 ## Время последней отправки команды. + var cmd_tick_rx = 0.0 ## Время последнего приёма команды. + var status: = PackedByteArray() ## Поле "состояние прибора". + var tx_data: = PackedByteArray() ## Буфер отправленный. + var tx_len = 0 ## Длина последнего отправленного пакета. + var isa_ports = {} ## Результат выполнения команды "читать порт". + var isa_block = {} ## Результат выполнения команды "читать массив из порта". + var online = false ## Состояние связи с ячейкой. - func _to_string() -> String: return String('яу07: %s %s' % [self.name, ['отключен', 'на связи'][int(online)]]) + func _to_string() -> String: return String('яу07: %s %s' % [self.name, ['отключен', 'на связи'][int(online)]]) - func _init(nm): - self.name = nm - tx_data.resize(BUFFER_SIZE) - tx_data.fill(0) - tick = 0.0 + func _init(nm): + self.name = nm + tx_data.resize(BUFFER_SIZE) + tx_data.fill(0) + tick = 0.0 - func process(delta: float): - tick += delta - if online and ((tick - cmd_tick_rx) > ONLINE_TIMEOUT): - online = false - emit_signal('line_changed', self) + func process(delta: float): + tick += delta + if online and ((tick - cmd_tick_rx) > ONLINE_TIMEOUT): + online = false + emit_signal('line_changed', self) - var rc = Error.ERR_BUSY - if cmd_state == CmdState.SEND: - rc = Error.OK - cmd_tick_tx = tick - cmd_state = CmdState.WAIT - cmd_retry = RETRY_COUNT - elif cmd_state == CmdState.WAIT: - if cmd_retry: - if (tick - cmd_tick_tx) > RESEND_TIMEOUT: - rc = Error.OK - cmd_tick_tx = tick - cmd_retry -= 1 - else: - cmd_state = CmdState.FAIL - emit_signal('command_fail', self) - rc = Error.FAILED - return rc + var rc = Error.ERR_BUSY + if cmd_state == CmdState.SEND: + rc = Error.OK + cmd_tick_tx = tick + cmd_state = CmdState.WAIT + cmd_retry = RETRY_COUNT + elif cmd_state == CmdState.WAIT: + if cmd_retry: + if (tick - cmd_tick_tx) > RESEND_TIMEOUT: + rc = Error.OK + cmd_tick_tx = tick + cmd_retry -= 1 + else: + cmd_state = CmdState.FAIL + emit_signal('command_fail', self) + rc = Error.FAILED + return rc - func send_isa(cmd_code: int, ports_data: Array) -> bool: - if (cmd_state == CmdState.WAIT) \ - or (cmd_state == CmdState.SEND) \ - or (cmd_state == CmdState.UNCK): - return false - if not ((cmd_code == CmdCode.READ_ISA) or (cmd_code == CmdCode.WRITE_ISA)): - return false + func send_isa(cmd_code: int, ports_data: Array) -> bool: + if (cmd_state == CmdState.WAIT) \ + or (cmd_state == CmdState.SEND) \ + or (cmd_state == CmdState.UNCK): + return false + if not ((cmd_code == CmdCode.READ_ISA) or (cmd_code == CmdCode.WRITE_ISA)): + return false - cmd_num_tx = (cmd_num_rx + 1) % 0xffff + cmd_num_tx = (cmd_num_rx + 1) % 0xffff - var ports_count = ports_data.size() - tx_len = ports_count * 2 + 8 - tx_data.encode_u16(0, cmd_retry) # Исправление для сетевого стека "nm-callback" процессоров STM - tx_data.encode_u16(2, cmd_num_tx) + var ports_count = ports_data.size() + tx_len = ports_count * 2 + 8 + tx_data.encode_u16(0, cmd_retry) # Исправление для сетевого стека "nm-callback" процессоров STM + tx_data.encode_u16(2, cmd_num_tx) - if cmd_code == CmdCode.WRITE_ISA: - ports_count /= 2 - tx_data[6] = cmd_code - tx_data[7] = ports_count + if cmd_code == CmdCode.WRITE_ISA: + ports_count /= 2 + tx_data[6] = cmd_code + tx_data[7] = ports_count - var i: = 0 - for word in ports_data: - tx_data.encode_u16(8 + i, word) - i += 2 - cmd_state = CmdState.SEND - return true + var i: = 0 + for word in ports_data: + tx_data.encode_u16(8 + i, word) + i += 2 + cmd_state = CmdState.SEND + return true - func send_block(cmd_code: int, block_len: int, port: Array) -> bool: - if (cmd_state == CmdState.WAIT) \ - or (cmd_state == CmdState.SEND) \ - or (cmd_state == CmdState.UNCK): - return false - if not ((cmd_code == CmdCode.READ_BLOCK) or (cmd_code == CmdCode.WRITE_BLOCK)): - return false + func send_block(cmd_code: int, block_len: int, port: Array) -> bool: + if (cmd_state == CmdState.WAIT) \ + or (cmd_state == CmdState.SEND) \ + or (cmd_state == CmdState.UNCK): + return false + if not ((cmd_code == CmdCode.READ_BLOCK) or (cmd_code == CmdCode.WRITE_BLOCK)): + return false - cmd_num_tx = (cmd_num_rx + 1) % 0xffff + cmd_num_tx = (cmd_num_rx + 1) % 0xffff - tx_len = 11 - tx_data.encode_u16(0, cmd_retry) # Исправление для сетевого стека "nm-callback" процессоров STM - tx_data.encode_u16(2, cmd_num_tx) + tx_len = 11 + tx_data.encode_u16(0, cmd_retry) # Исправление для сетевого стека "nm-callback" процессоров STM + tx_data.encode_u16(2, cmd_num_tx) - if cmd_code == CmdCode.WRITE_BLOCK: - block_len /= 2 - tx_data[6] = cmd_code - tx_data.encode_u16(7, block_len) + if cmd_code == CmdCode.WRITE_BLOCK: + block_len /= 2 + tx_data[6] = cmd_code + tx_data.encode_u16(7, block_len) - tx_data.encode_u16(9, int(port[0])) - cmd_state = CmdState.SEND - return true - ## Возвращает код команды ЯУ-07 - ## rx_data - Принятые данные - ## Возвращает - Код команды не найден, 0...255 - код команды - func get_cmd_code(rx_data: PackedByteArray): + tx_data.encode_u16(9, int(port[0])) + cmd_state = CmdState.SEND + return true + ## Возвращает код команды ЯУ-07. + ## rx_data - Принятые данные. + ## Возвращает - Код команды не найден, 0...255 - код команды. + func get_cmd_code(rx_data: PackedByteArray): - var rx_data_len = rx_data.size() - if rx_data_len < 7: - return null - var status_len = rx_data.decode_u16(6) # Длина массива байтового "состояние прибора" - if rx_data_len <= (status_len + 6): # Нет поля "ответ на команду", разбор пакета завершить - return null - var cmd_code_pos = status_len + 8 # Положение в приёмном буфере "кода команды" - if rx_data_len <= cmd_code_pos: - return null - return rx_data[cmd_code_pos] # "код команды" + var rx_data_len = rx_data.size() + if rx_data_len < 7: + return null + var status_len = rx_data.decode_u16(6) # Длина массива байтового "состояние прибора" + if rx_data_len <= (status_len + 6): # Нет поля "ответ на команду", разбор пакета завершить + return null + var cmd_code_pos = status_len + 8 # Положение в приёмном буфере "кода команды" + if rx_data_len <= cmd_code_pos: + return null + return rx_data[cmd_code_pos] # "код команды" - func parse_isa(rx_data: PackedByteArray, status_len) -> bool: - var ports_count_pos = status_len + 10 # Положение в приёмном буфере количества портов - if rx_data.size() < ports_count_pos: - return false - var ports_count = rx_data[ports_count_pos] # Количество портов - var counted_len = status_len + (ports_count * 4) + 11 # Вычисленная длина пакета - if rx_data.size() < counted_len: - return false - var addr_pos = status_len + 11 # Смещение положения адреса в приёмном буфере - var data_pos = status_len + 13 # Смещение положения данных в приёмном буфере - var i: = 0 - while i < ports_count: - var shift: = i * 4 - var isa_addr = rx_data.decode_u16(addr_pos + shift) # Адрес порта ISA яу-07 - var isa_data = rx_data.decode_u16(data_pos + shift) # Данные порта ISA яу-07 - isa_ports[isa_addr] = isa_data - i += 1 - cmd_data = rx_data.slice(addr_pos, (addr_pos + ports_count * 4) - 1) - return i > 0 + func parse_isa(rx_data: PackedByteArray, status_len) -> bool: + var ports_count_pos = status_len + 10 # Положение в приёмном буфере количества портов + if rx_data.size() < ports_count_pos: + return false + var ports_count = rx_data[ports_count_pos] # Количество портов + var counted_len = status_len + (ports_count * 4) + 11 # Вычисленная длина пакета + if rx_data.size() < counted_len: + return false + var addr_pos = status_len + 11 # Смещение положения адреса в приёмном буфере + var data_pos = status_len + 13 # Смещение положения данных в приёмном буфере + var i: = 0 + while i < ports_count: + var shift: = i * 4 + var isa_addr = rx_data.decode_u16(addr_pos + shift) # Адрес порта ISA яу-07 + var isa_data = rx_data.decode_u16(data_pos + shift) # Данные порта ISA яу-07 + isa_ports[isa_addr] = isa_data + i += 1 + cmd_data = rx_data.slice(addr_pos, (addr_pos + ports_count * 4) - 1) + return i > 0 - func parse_block(rx_data: PackedByteArray, status_len) -> bool: - var ports_count_pos = status_len + 7 # Положение в приёмном буфере количества портов - if rx_data.size() < ports_count_pos: - return false - var block_len = rx_data.decode_u16(ports_count_pos + 3) - var block_adr = rx_data.decode_u16(ports_count_pos + 5) - var block_data = [] - for i in block_len: - var shift: int = i * 2 - block_data.append(rx_data.decode_u16(ports_count_pos + 7 + shift)) - isa_block[block_adr] = block_data - return true + func parse_block(rx_data: PackedByteArray, status_len) -> bool: + var ports_count_pos = status_len + 7 # Положение в приёмном буфере количества портов + if rx_data.size() < ports_count_pos: + return false + var block_len = rx_data.decode_u16(ports_count_pos + 3) + var block_adr = rx_data.decode_u16(ports_count_pos + 5) + var block_data = [] + for i in block_len: + var shift: int = i * 2 + block_data.append(rx_data.decode_u16(ports_count_pos + 7 + shift)) + isa_block[block_adr] = block_data + return true - ## Заполняет состояние прибора данными прочитанными из портов ЯУ-07 - ## для команд "читать порты" или "записать порты"[br] - ## [param rx_data] - Принятые данные[br] - ## Возвращает [b]true[/b] - Данные обработаны успешно[br] - ## Возвращает [b]false[/b] - Данные не обработаны из за ошибки[br] - func parse(rx_data: PackedByteArray) -> bool: + ## Заполняет состояние прибора данными прочитанными из портов ЯУ-07. + ## для команд "читать порты" или "записать порты".[br] + ## [param rx_data] - Принятые данные.[br] + ## Возвращает [b]true[/b] - Данные обработаны успешно.[br] + ## Возвращает [b]false[/b] - Данные не обработаны из за ошибки.[br] + func parse(rx_data: PackedByteArray) -> bool: - cmd_tick_rx = tick + cmd_tick_rx = tick - if not online: - online = true - emit_signal('line_changed', self) + if not online: + online = true + emit_signal('line_changed', self) - var rx_data_len = rx_data.size() - if rx_data_len < 10: - return false + var rx_data_len = rx_data.size() + if rx_data_len < 10: + return false - cmd_num_rx = rx_data.decode_u16(2) - if cmd_state == CmdState.UNCK: - cmd_state = CmdState.DONE + cmd_num_rx = rx_data.decode_u16(2) + if cmd_state == CmdState.UNCK: + cmd_state = CmdState.DONE - var status_len = rx_data.decode_u16(6) # Длина массива байтового "состояние прибора" - if rx_data_len < (status_len + 6): - return false - var i: = 0 - var len_rx_data: = rx_data.size() - status.resize(status_len) - while i < status_len: - var byte_i = i + 8 - if byte_i < len_rx_data: - status[i] = rx_data[byte_i] # Массив байтовый "состояние прибора" - i += 1 + var status_len = rx_data.decode_u16(6) # Длина массива байтового "состояние прибора" + if rx_data_len < (status_len + 6): + return false + var i: = 0 + var len_rx_data: = rx_data.size() + status.resize(status_len) + while i < status_len: + var byte_i = i + 8 + if byte_i < len_rx_data: + status[i] = rx_data[byte_i] # Массив байтовый "состояние прибора" + i += 1 - if rx_data_len == (status_len + 6): - return true # Нет поля "ответ на команду", разбор пакета завершить + if rx_data_len == (status_len + 6): + return true # Нет поля "ответ на команду", разбор пакета завершить - var cmd_code_pos = status_len + 8 # Положение в приёмном буфере "код команды" - if rx_data_len <= cmd_code_pos: - return false + var cmd_code_pos = status_len + 8 # Положение в приёмном буфере "код команды" + if rx_data_len <= cmd_code_pos: + return false - var cmd_status_pos = status_len + 9 # Положение в приёмном буфере "состояния выполнения команды" - if rx_data_len <= cmd_status_pos: - return false - cmd_result = rx_data[cmd_status_pos] - if cmd_result != 1: # Команда не выполнена - return false + var cmd_status_pos = status_len + 9 # Положение в приёмном буфере "состояния выполнения команды" + if rx_data_len <= cmd_status_pos: + return false + cmd_result = rx_data[cmd_status_pos] + if cmd_result != 1: # Команда не выполнена + return false - var cmd_code: CmdCode = rx_data[cmd_code_pos] as CmdCode # "код команды" - var rc = true - if (cmd_code == CmdCode.READ_ISA) or (cmd_code == CmdCode.WRITE_ISA): - rc = parse_isa(rx_data, status_len) + var cmd_code: CmdCode = rx_data[cmd_code_pos] as CmdCode # "код команды" + var rc = true + if (cmd_code == CmdCode.READ_ISA) or (cmd_code == CmdCode.WRITE_ISA): + rc = parse_isa(rx_data, status_len) - elif (cmd_code == CmdCode.READ_BLOCK) or (cmd_code == CmdCode.WRITE_BLOCK): - rc = parse_block(rx_data, status_len) + elif (cmd_code == CmdCode.READ_BLOCK) or (cmd_code == CmdCode.WRITE_BLOCK): + rc = parse_block(rx_data, status_len) - if rc: - if (cmd_state == CmdState.WAIT) and (cmd_num_rx == cmd_num_tx): - cmd_state = CmdState.DONE - emit_signal('command_done', self) - else: - emit_signal('parse_failed', self) - return true + if rc: + if (cmd_state == CmdState.WAIT) and (cmd_num_rx == cmd_num_tx): + cmd_state = CmdState.DONE + emit_signal('command_done', self) + else: + emit_signal('parse_failed', self) + return true diff --git a/scripts/yems-boards.gd b/scripts/yems-boards.gd index 347bea60..8e14f3d3 100644 --- a/scripts/yems-boards.gd +++ b/scripts/yems-boards.gd @@ -1,15 +1,15 @@ -extends Node +class_name yems_boards extends Node class EmsBoard: - var id_board: String - var in_devs: Dictionary ## Словарь с входными устройствами - var out_devs: Dictionary ## Словарь с выходными устройствами - var base_addr_isa: int ## Базовый адрес ячейки isa - var in_tbl: Array - var out_tbl: Array + var id_board: String + var in_devs: Dictionary ## Словарь с входными устройствами. + var out_devs: Dictionary ## Словарь с выходными устройствами. + var base_addr_isa: int ## Базовый адрес ячейки isa. + var in_tbl: Array + var out_tbl: Array - func _init(id, base_addr, in_table, out_table): - id_board = id - in_tbl = in_table - out_tbl = out_table - base_addr_isa = base_addr + func _init(id, base_addr, in_table, out_table): + id_board = id + in_tbl = in_table + out_tbl = out_table + base_addr_isa = base_addr diff --git a/scripts/yems-consts.gd b/scripts/yems-consts.gd index ac333c62..f4d56ee1 100644 --- a/scripts/yems-consts.gd +++ b/scripts/yems-consts.gd @@ -1,144 +1,144 @@ -extends Node +class_name yerms_consts extends Node -## +## Таблица с данными для входов, первое значение - индекс устройства в ячейке КЭМС. const INPUT_ROWS1 = [ - [12,['283333 МР-231S, Строб ЭМС', 'X52', '0.00', '0.00']], - [13,['29НРЛС МР-231-3, УИЗП', 'X54', '0.00', '0.00']], - [14,['30НРЛС МР-231-3, Строб ЭМС', 'X55', '0.00', '0.00']], - [15,['31ЦИСВС-1010, УИЗП', 'X23', '0.00', '0.00']], - [21,['32НРЛС МР-231S, УИЗП', 'X21', '0.00', '0.00']], - [22,['33НРЛС МР-231S, Строб ЭМС', 'X22', '0.00', '0.00']], - [23,['34НРЛС МР-231-3, УИЗП', 'X24', '0.00', '0.00']], - [32,['352222 МР-231S, Строб ЭМС', 'X32', '0.00', '0.00']], - [33,['36НРЛС МР-231-3, УИЗП', 'X34', '0.00', '0.00']], - [34,['37НРЛС МР-231-3, Строб ЭМС', 'X35', '0.00', '0.00']], - [35,['38ЦИСВС-1010, УИЗП', 'X43', '0.00', '0.00']], - [38,['394302-01, 4302-04, УИЗП', 'X46', '0.00', '0.00']], - [31,['40НРЛС МР-231S, УИЗП', 'X51', '0.00', '0.00']]] + [12,['283333 МР-231S, Строб ЭМС', 'X52', '0.00', '0.00']], + [13,['29НРЛС МР-231-3, УИЗП', 'X54', '0.00', '0.00']], + [14,['30НРЛС МР-231-3, Строб ЭМС', 'X55', '0.00', '0.00']], + [15,['31ЦИСВС-1010, УИЗП', 'X23', '0.00', '0.00']], + [21,['32НРЛС МР-231S, УИЗП', 'X21', '0.00', '0.00']], + [22,['33НРЛС МР-231S, Строб ЭМС', 'X22', '0.00', '0.00']], + [23,['34НРЛС МР-231-3, УИЗП', 'X24', '0.00', '0.00']], + [32,['352222 МР-231S, Строб ЭМС', 'X32', '0.00', '0.00']], + [33,['36НРЛС МР-231-3, УИЗП', 'X34', '0.00', '0.00']], + [34,['37НРЛС МР-231-3, Строб ЭМС', 'X35', '0.00', '0.00']], + [35,['38ЦИСВС-1010, УИЗП', 'X43', '0.00', '0.00']], + [38,['394302-01, 4302-04, УИЗП', 'X46', '0.00', '0.00']], + [31,['40НРЛС МР-231S, УИЗП', 'X51', '0.00', '0.00']]] -## Таблица с данными для выходов, первое значение - индекс устройства в ячейке КЭМС +## Таблица с данными для выходов, первое значение - индекс устройства в ячейке КЭМС. const OUTPUT_ROWS1 = [ - [41,['41НРЛС МР-231S, БИ', 'X61', '0.00', '0.00']], - [42,['42НРЛС МР-231S', 'X62', '0.00', '0.00']], - [43,['43НРЛС МР-231-3, БИ', 'X64', '0.00', '0.00']], - [44,['44НРЛС МР-231-3', 'X65', '0.00', '0.00']], - [45,['45ЦИСВС-1010, БИ', 'X63', '0.00', '0.00']], - [46,['464302-01, 4302-04, БИ', 'X66', '0.00', '0.00']], - [48,['47НРЛС 11111111', 'X69', '0.00', '0.00']], - [62,['48НРЛС МР-231S', 'X62', '0.00', '0.00']], - [63,['49НРЛС МР-231-3, БИ', 'X64', '0.00', '0.00']], - [64,['50НРЛС МР-231-3', 'X65', '0.00', '0.00']], - [65,['51ЦИСВС-1010, БИ', 'X63', '0.00', '0.00']], - [66,['524302-01, 4302-04, БИ', 'X66', '0.00', '0.00']], - [68,['53НРЛС 11111111', 'X69', '0.00', '0.00']]] + [41,['41НРЛС МР-231S, БИ', 'X61', '0.00', '0.00']], + [42,['42НРЛС МР-231S', 'X62', '0.00', '0.00']], + [43,['43НРЛС МР-231-3, БИ', 'X64', '0.00', '0.00']], + [44,['44НРЛС МР-231-3', 'X65', '0.00', '0.00']], + [45,['45ЦИСВС-1010, БИ', 'X63', '0.00', '0.00']], + [46,['464302-01, 4302-04, БИ', 'X66', '0.00', '0.00']], + [48,['47НРЛС 11111111', 'X69', '0.00', '0.00']], + [62,['48НРЛС МР-231S', 'X62', '0.00', '0.00']], + [63,['49НРЛС МР-231-3, БИ', 'X64', '0.00', '0.00']], + [64,['50НРЛС МР-231-3', 'X65', '0.00', '0.00']], + [65,['51ЦИСВС-1010, БИ', 'X63', '0.00', '0.00']], + [66,['524302-01, 4302-04, БИ', 'X66', '0.00', '0.00']], + [68,['53НРЛС 11111111', 'X69', '0.00', '0.00']]] -## Таблица с данными для входов, первое значение - индекс устройства в ячейке КЭМС +## Таблица с данными для входов, первое значение - индекс устройства в ячейке КЭМС. const INPUT_ROWS = [ - [1,['УИЗП №1', 'Х7', '0.00', '0.00']], - [2,['УИЗПФ №1', 'Х8', '0.00', '0.00']], - [3,['УИЗП №2', 'Х10', '0.00', '0.00']], - [4,['УИЗПФ №2', 'Х11', '0.00', '0.00']], - [5,['УИЗП №3', 'Х13', '0.00', '0.00']], - [6,['УИЗПФ №3', 'Х14', '0.00', '0.00']], - [7,['УИЗП №4', 'Х16', '0.00', '0.00']], - [8,['УИЗПФ №4', 'Х17', '0.00', '0.00']], - [9,['УИЗП №5', 'Х19', '0.00', '0.00']], - [10,['УИЗПФ №5', 'Х20', '0.00', '0.00']], - [11,['УИЗП №6', 'Х22', '0.00', '0.00']], - [12,['УИЗПФ №6','Х23', '0.00', '0.00']], - [13,['УИЗП №7','Х25', '0.00', '0.00']], - [14,['УИЗПФ №7','Х26', '0.00', '0.00']], - [15,['СИ1 Л1','X31 : 2', '0.00', '0.00']], - [16,['СИ1 Л6','X31 : 5', '0.00', '0.00']], - [17,['СИ1 Л7','X31 : 8', '0.00', '0.00']], - [18,['СИ2 Л1','X32 : 2', '0.00', '0.00']], - [19,['СИ2 Л6','X32 : 5', '0.00', '0.00']], - [20,['СИ2 Л7','X32 : 8', '0.00', '0.00']], - [21,['СИ3 Л1','X33 : 2', '0.00', '0.00']], - [22,['СИ3 Л6','X33 : 5', '0.00', '0.00']], - [23,['СИ3 Л7','X33 : 8', '0.00', '0.00']], - [24,['СИ4 Л1','X34 : 2', '0.00', '0.00']], - [25,['СИ4 Л6','X34 : 5', '0.00', '0.00']], - [26,['СИ4 Л7','X34 : 8', '0.00', '0.00']], - [27,['СИ1 Л2','X38 : 2', '0.00', '0.00']], - [28,['СИ1 Л3','X38 : 5', '0.00', '0.00']], - [29,['СИ2 Л2','X39 : 2', '0.00', '0.00']], - [30,['СИ2 Л3','X39 : 5', '0.00', '0.00']], - [31,['СИ3 Л2','X40 : 2', '0.00', '0.00']], - [32,['СИ3 Л3','X40 : 5', '0.00', '0.00']], - [33,['СИ4 Л2','X41 : 2', '0.00', '0.00']], - [34,['СИ4 Л3','X41 : 5', '0.00', '0.00']], - [35,['СИ1 Л4','X42 : 2', '0.00', '0.00']], - [36,['СИ1 Л5','X42 : 5', '0.00', '0.00']], - [37,['СИ2 Л4','X43 : 2', '0.00', '0.00']], - [38,['СИ2 Л5','X43 : 5', '0.00', '0.00']], - [39,['СИ3 Л4','X44 : 2', '0.00', '0.00']], - [40,['СИ3 Л5','X44 : 5', '0.00', '0.00']], - [41,['СИ4 Л4','X45 : 2', '0.00', '0.00']], - [42,['СИ4 Л5','X45 : 5', '0.00', '0.00']], - [43,['БИ В Лб','Х49 : 37', '0.00', '0.00']], - [44,['БИ В ПрБ','Х49 : 31', '0.00', '0.00']], - [45,['БИ Г Лб','Х49 : 15', '0.00', '0.00']], - [46,['БИ Г ПрБ','Х49 : 8', '0.00', '0.00']], - [47,['БИ Д Лб','Х49 : 6', '0.00', '0.00']], - [48,['БИ Д ПрБ','Х49 : 10', '0.00', '0.00']], - [49,['БИ Е Лб','Х49 : 25', '0.00', '0.00']], - [50,['БИ Е ПрБ','Х49 : 40', '0.00', '0.00']], - [51,['СЗИ В Лб','Х49 : 42', '0.00', '0.00']], - [52,['СЗИ В ПрБ','Х49 : 32', '0.00', '0.00']], - [53,['СЗИ Г Лб','Х49 : 46', '0.00', '0.00']], - [54,['СЗИ Г ПрБ','Х49 : 32', '0.00', '0.00']], - [55,['СЗИ Д Лб','Х49 : 16', '0.00', '0.00']], - [56,['СЗИ Д ПрБ','Х49 : 47', '0.00', '0.00']], - [57,['СЗИ Е Лб','Х49 : 1', '0.00', '0.00']], - [58,['СЗИ Е ПрБ','Х49 : 50', '0.00', '0.00']]] + [1,['УИЗП №1', 'Х7', '0.00', '0.00']], + [2,['УИЗПФ №1', 'Х8', '0.00', '0.00']], + [3,['УИЗП №2', 'Х10', '0.00', '0.00']], + [4,['УИЗПФ №2', 'Х11', '0.00', '0.00']], + [5,['УИЗП №3', 'Х13', '0.00', '0.00']], + [6,['УИЗПФ №3', 'Х14', '0.00', '0.00']], + [7,['УИЗП №4', 'Х16', '0.00', '0.00']], + [8,['УИЗПФ №4', 'Х17', '0.00', '0.00']], + [9,['УИЗП №5', 'Х19', '0.00', '0.00']], + [10,['УИЗПФ №5', 'Х20', '0.00', '0.00']], + [11,['УИЗП №6', 'Х22', '0.00', '0.00']], + [12,['УИЗПФ №6','Х23', '0.00', '0.00']], + [13,['УИЗП №7','Х25', '0.00', '0.00']], + [14,['УИЗПФ №7','Х26', '0.00', '0.00']], + [15,['СИ1 Л1','X31 : 2', '0.00', '0.00']], + [16,['СИ1 Л6','X31 : 5', '0.00', '0.00']], + [17,['СИ1 Л7','X31 : 8', '0.00', '0.00']], + [18,['СИ2 Л1','X32 : 2', '0.00', '0.00']], + [19,['СИ2 Л6','X32 : 5', '0.00', '0.00']], + [20,['СИ2 Л7','X32 : 8', '0.00', '0.00']], + [21,['СИ3 Л1','X33 : 2', '0.00', '0.00']], + [22,['СИ3 Л6','X33 : 5', '0.00', '0.00']], + [23,['СИ3 Л7','X33 : 8', '0.00', '0.00']], + [24,['СИ4 Л1','X34 : 2', '0.00', '0.00']], + [25,['СИ4 Л6','X34 : 5', '0.00', '0.00']], + [26,['СИ4 Л7','X34 : 8', '0.00', '0.00']], + [27,['СИ1 Л2','X38 : 2', '0.00', '0.00']], + [28,['СИ1 Л3','X38 : 5', '0.00', '0.00']], + [29,['СИ2 Л2','X39 : 2', '0.00', '0.00']], + [30,['СИ2 Л3','X39 : 5', '0.00', '0.00']], + [31,['СИ3 Л2','X40 : 2', '0.00', '0.00']], + [32,['СИ3 Л3','X40 : 5', '0.00', '0.00']], + [33,['СИ4 Л2','X41 : 2', '0.00', '0.00']], + [34,['СИ4 Л3','X41 : 5', '0.00', '0.00']], + [35,['СИ1 Л4','X42 : 2', '0.00', '0.00']], + [36,['СИ1 Л5','X42 : 5', '0.00', '0.00']], + [37,['СИ2 Л4','X43 : 2', '0.00', '0.00']], + [38,['СИ2 Л5','X43 : 5', '0.00', '0.00']], + [39,['СИ3 Л4','X44 : 2', '0.00', '0.00']], + [40,['СИ3 Л5','X44 : 5', '0.00', '0.00']], + [41,['СИ4 Л4','X45 : 2', '0.00', '0.00']], + [42,['СИ4 Л5','X45 : 5', '0.00', '0.00']], + [43,['БИ В Лб','Х49 : 37', '0.00', '0.00']], + [44,['БИ В ПрБ','Х49 : 31', '0.00', '0.00']], + [45,['БИ Г Лб','Х49 : 15', '0.00', '0.00']], + [46,['БИ Г ПрБ','Х49 : 8', '0.00', '0.00']], + [47,['БИ Д Лб','Х49 : 6', '0.00', '0.00']], + [48,['БИ Д ПрБ','Х49 : 10', '0.00', '0.00']], + [49,['БИ Е Лб','Х49 : 25', '0.00', '0.00']], + [50,['БИ Е ПрБ','Х49 : 40', '0.00', '0.00']], + [51,['СЗИ В Лб','Х49 : 42', '0.00', '0.00']], + [52,['СЗИ В ПрБ','Х49 : 32', '0.00', '0.00']], + [53,['СЗИ Г Лб','Х49 : 46', '0.00', '0.00']], + [54,['СЗИ Г ПрБ','Х49 : 32', '0.00', '0.00']], + [55,['СЗИ Д Лб','Х49 : 16', '0.00', '0.00']], + [56,['СЗИ Д ПрБ','Х49 : 47', '0.00', '0.00']], + [57,['СЗИ Е Лб','Х49 : 1', '0.00', '0.00']], + [58,['СЗИ Е ПрБ','Х49 : 50', '0.00', '0.00']]] -## Таблица с данными для выходов, первое значение - индекс устройства в ячейке КЭМС +## Таблица с данными для выходов, первое значение - индекс устройства в ячейке КЭМС. const OUTPUT_ROWS = [ - [11,['Бланк №1','Х6', '0.00', '0.00']], - [12,['Бланк №2','Х9', '0.00', '0.00']], - [13,['Бланк №3','Х12', '0.00', '0.00']], - [14,['Бланк №4','Х15', '0.00', '0.00']], - [15,['Бланк №5','Х18', '0.00', '0.00']], - [16,['Бланк №6','Х21', '0.00', '0.00']], - [17,['Бланк №7','Х24', '0.00', '0.00']], - [18,['СЗИ1 Л1','X31 : 11', '0.00', '0.00']], - [19,['СЗИ1 Л6','X31 :14', '0.00', '0.00']], - [20,['СЗИ1 Л7','X31 : 17', '0.00', '0.00']], - [21,['СЗИ2 Л1','X32 : 11', '0.00', '0.00']], - [22,['СЗИ2 Л6','X32 : 14', '0.00', '0.00']], - [23,['СЗИ2 Л7','X32: 17', '0.00', '0.00']], - [24,['СЗИ3 Л1','X33 : 11', '0.00', '0.00']], - [25,['СЗИ3 Л6','X33 :14', '0.00', '0.00']], - [26,['СЗИ3 Л7','X33: 17', '0.00', '0.00']], - [27,['СЗИ4 Л1','X34 : 11', '0.00', '0.00']], - [28,['СЗИ4 Л6','X34 :14', '0.00', '0.00']], - [29,['СЗИ4 Л7','X34: 17', '0.00', '0.00']], - [30,['СЗИ1 Л2','X38 : 11', '0.00', '0.00']], - [31,['СЗИ1 Л3','X38 : 14', '0.00', '0.00']], - [32,['СЗИ2 Л2','X39 : 11', '0.00', '0.00']], - [33,['СЗИ2 Л3','X39 : 14', '0.00', '0.00']], - [34,['СЗИ3 Л2','X40 : 11', '0.00', '0.00']], - [35,['СЗИ3 Л3','X40 : 14', '0.00', '0.00']], - [36,['СЗИ4 Л2','X41 : 11', '0.00', '0.00']], - [37,['СЗИ4 Л3','X41 :14', '0.00', '0.00']], - [38,['СЗИ1 Л4','X42 : 11', '0.00', '0.00']], - [39,['СЗИ1 Л5','X42 :14', '0.00', '0.00']], - [40,['СЗИ2 Л4','X43 : 11', '0.00', '0.00']], - [41,['СЗИ2 Л5','X43 : 14', '0.00', '0.00']], - [42,['СЗИ3 Л4','X44 : 11', '0.00', '0.00']], - [43,['СЗИ3 Л5','X44 :14', '0.00', '0.00']], - [44,['СЗИ4 Л4','X45 : 11', '0.00', '0.00']], - [45,['СЗИ4 Л5','X45 : 14', '0.00', '0.00']], - [46,['БИ РТР №1','X47 : 2', '0.00', '0.00']], - [47,['БИ РТР №2','X47 : 5', '0.00', '0.00']], - [48,['БИ РТР №3','X47 : 8', '0.00', '0.00']], - [49,['БИ РТР №4','X47 : 11', '0.00', '0.00']], - [50,['СИ В Лб','Х49 : 21', '0.00', '0.00']], - [51,['СИ В ПрБ','Х49 : 19', '0.00', '0.00']], - [52,['СИ Г Лб','Х49 : 28', '0.00', '0.00']], - [53,['СИ Г ПрБ','Х49 : 30', '0.00', '0.00']], - [54,['СИ Д Лб','Х49 : 13', '0.00', '0.00']], - [55,['СИ Д ПрБ','Х49 : 11', '0.00', '0.00']], - [56,['СИ Е Лб','Х49 : 26', '0.00', '0.00']], - [57,['СИ Е ПрБ','Х49 : 35', '0.00', '0.00']]] + [11,['Бланк №1','Х6', '0.00', '0.00']], + [12,['Бланк №2','Х9', '0.00', '0.00']], + [13,['Бланк №3','Х12', '0.00', '0.00']], + [14,['Бланк №4','Х15', '0.00', '0.00']], + [15,['Бланк №5','Х18', '0.00', '0.00']], + [16,['Бланк №6','Х21', '0.00', '0.00']], + [17,['Бланк №7','Х24', '0.00', '0.00']], + [18,['СЗИ1 Л1','X31 : 11', '0.00', '0.00']], + [19,['СЗИ1 Л6','X31 :14', '0.00', '0.00']], + [20,['СЗИ1 Л7','X31 : 17', '0.00', '0.00']], + [21,['СЗИ2 Л1','X32 : 11', '0.00', '0.00']], + [22,['СЗИ2 Л6','X32 : 14', '0.00', '0.00']], + [23,['СЗИ2 Л7','X32: 17', '0.00', '0.00']], + [24,['СЗИ3 Л1','X33 : 11', '0.00', '0.00']], + [25,['СЗИ3 Л6','X33 :14', '0.00', '0.00']], + [26,['СЗИ3 Л7','X33: 17', '0.00', '0.00']], + [27,['СЗИ4 Л1','X34 : 11', '0.00', '0.00']], + [28,['СЗИ4 Л6','X34 :14', '0.00', '0.00']], + [29,['СЗИ4 Л7','X34: 17', '0.00', '0.00']], + [30,['СЗИ1 Л2','X38 : 11', '0.00', '0.00']], + [31,['СЗИ1 Л3','X38 : 14', '0.00', '0.00']], + [32,['СЗИ2 Л2','X39 : 11', '0.00', '0.00']], + [33,['СЗИ2 Л3','X39 : 14', '0.00', '0.00']], + [34,['СЗИ3 Л2','X40 : 11', '0.00', '0.00']], + [35,['СЗИ3 Л3','X40 : 14', '0.00', '0.00']], + [36,['СЗИ4 Л2','X41 : 11', '0.00', '0.00']], + [37,['СЗИ4 Л3','X41 :14', '0.00', '0.00']], + [38,['СЗИ1 Л4','X42 : 11', '0.00', '0.00']], + [39,['СЗИ1 Л5','X42 :14', '0.00', '0.00']], + [40,['СЗИ2 Л4','X43 : 11', '0.00', '0.00']], + [41,['СЗИ2 Л5','X43 : 14', '0.00', '0.00']], + [42,['СЗИ3 Л4','X44 : 11', '0.00', '0.00']], + [43,['СЗИ3 Л5','X44 :14', '0.00', '0.00']], + [44,['СЗИ4 Л4','X45 : 11', '0.00', '0.00']], + [45,['СЗИ4 Л5','X45 : 14', '0.00', '0.00']], + [46,['БИ РТР №1','X47 : 2', '0.00', '0.00']], + [47,['БИ РТР №2','X47 : 5', '0.00', '0.00']], + [48,['БИ РТР №3','X47 : 8', '0.00', '0.00']], + [49,['БИ РТР №4','X47 : 11', '0.00', '0.00']], + [50,['СИ В Лб','Х49 : 21', '0.00', '0.00']], + [51,['СИ В ПрБ','Х49 : 19', '0.00', '0.00']], + [52,['СИ Г Лб','Х49 : 28', '0.00', '0.00']], + [53,['СИ Г ПрБ','Х49 : 30', '0.00', '0.00']], + [54,['СИ Д Лб','Х49 : 13', '0.00', '0.00']], + [55,['СИ Д ПрБ','Х49 : 11', '0.00', '0.00']], + [56,['СИ Е Лб','Х49 : 26', '0.00', '0.00']], + [57,['СИ Е ПрБ','Х49 : 35', '0.00', '0.00']]] diff --git a/scripts/yems-devs.gd b/scripts/yems-devs.gd index 00955865..4049bd5e 100644 --- a/scripts/yems-devs.gd +++ b/scripts/yems-devs.gd @@ -1,37 +1,37 @@ -extends Node +class_name yems_dev extends Node class InDev: - var id: int ## Идентификатор индекс устройства - var dev_name: String ## Имя подключаемого комплекса - var connector: String ## Номер разъёма в приборе - var delay: float ## Задержка фронта импульса - var offset: float ## Смещение фронта импульса - var state: int ## Состояние входа - var freq: int ## Предполагаемая частота на которой работает комплекс - var ports_data: Dictionary ## Словарь состояния портов устройства - var tbl_row_id: int ## Индекс устройства в таблице выходов - var out_dots: Array ## Список выходных устройств в порядке, как в таблице и точки матрицы - var connect_devs: Dictionary ## Список присоединённых устройств - var board: String ## Плата в которой находится устройство + var id: int ## Идентификатор индекс устройства. + var dev_name: String ## Имя подключаемого комплекса. + var connector: String ## Номер разъёма в приборе. + var delay: float ## Задержка фронта импульса. + var offset: float ## Смещение фронта импульса. + var state: int ## Состояние входа. + var freq: int ## Предполагаемая частота на которой работает комплекс. + var ports_data: Dictionary ## Словарь состояния портов устройства. + var tbl_row_id: int ## Индекс устройства в таблице выходов. + var out_dots: Array ## Список выходных устройств в порядке, как в таблице и точки матрицы. + var connect_devs: Dictionary ## Список присоединённых устройств. + var board: String ## Плата в которой находится устройство. - func _init(dev_id : int, params : Array, row_id : int): - id = dev_id - dev_name = String(params[0]) - connector = String(params[1]) - delay = float(params[2]) - offset = float(params[3]) - tbl_row_id = row_id + func _init(dev_id : int, params : Array, row_id : int): + id = dev_id + dev_name = String(params[0]) + connector = String(params[1]) + delay = float(params[2]) + offset = float(params[3]) + tbl_row_id = row_id class OutDev extends InDev: - var mode: String ## Режим работы выхода + var mode: String ## Режим работы выхода. - func _init(dev_id : int, params : Array, row_id : int): - id = dev_id - dev_name = String(params[0]) - connector = String(params[1]) - delay = float(params[2]) - offset = float(params[3]) - tbl_row_id = row_id - mode = 'Работа' + func _init(dev_id : int, params : Array, row_id : int): + id = dev_id + dev_name = String(params[0]) + connector = String(params[1]) + delay = float(params[2]) + offset = float(params[3]) + tbl_row_id = row_id + mode = 'Работа' diff --git a/table/table.gd b/table/table.gd index 9d9363d1..cd1dd1fc 100644 --- a/table/table.gd +++ b/table/table.gd @@ -57,94 +57,94 @@ func defaultselector_color_proc(_i_row: int): return selector_color ## [param scrl] - Прокрутка родитель таблицы.[br] ## [param prnt] - Родитель прокрутки.[br] func pin_header(scrl: ScrollContainer, prnt: Control): - scrl.remove_child(header) - prnt.add_child(header) - var v_separation = get_theme_constant('v_separation') - header.position = scrl.position - Vector2(0, header.size.y + v_separation) - scroll = scrl - scroll_adj = scrl.position + scrl.remove_child(header) + prnt.add_child(header) + var v_separation = get_theme_constant('v_separation') + header.position = scrl.position - Vector2(0, header.size.y + v_separation) + scroll = scrl + scroll_adj = scrl.position ## Перемещает указатель на одну строку вверх func selector_up(): - var i_rows: = [] - get_selected_rows(i_rows) - for i in i_rows: - set_row_selected(i, false) - var rows_count: = get_rows_count() - if not (i_rows.size() and (rows_count > 1)): - return - var i_row = i_rows[0] - i_row -= 1 - if i_row < 0: - i_row = rows_count - 1 - set_row_selected(i_row, true) - var node = get_node2(0, i_row) - if scroll is ScrollContainer: - scroll.ensure_control_visible(node) - emit_signal('selected_changed', i_row) + var i_rows: = [] + get_selected_rows(i_rows) + for i in i_rows: + set_row_selected(i, false) + var rows_count: = get_rows_count() + if not (i_rows.size() and (rows_count > 1)): + return + var i_row = i_rows[0] + i_row -= 1 + if i_row < 0: + i_row = rows_count - 1 + set_row_selected(i_row, true) + var node = get_node2(0, i_row) + if scroll is ScrollContainer: + scroll.ensure_control_visible(node) + emit_signal('selected_changed', i_row) ## Перемещает указатель на одну строку вниз func selector_down(): - var i_rows: = [] - get_selected_rows(i_rows) - for i in i_rows: - set_row_selected(i, false) - var rows_count: = get_rows_count() - if not (i_rows.size() and (rows_count > 1)): - return - var i_row = i_rows[0] - i_row += 1 - i_row %= rows_count - set_row_selected(i_row, true) - var node = get_node2(0, i_row) - if scroll is ScrollContainer: - scroll.ensure_control_visible(node) - emit_signal('selected_changed', i_row) + var i_rows: = [] + get_selected_rows(i_rows) + for i in i_rows: + set_row_selected(i, false) + var rows_count: = get_rows_count() + if not (i_rows.size() and (rows_count > 1)): + return + var i_row = i_rows[0] + i_row += 1 + i_row %= rows_count + set_row_selected(i_row, true) + var node = get_node2(0, i_row) + if scroll is ScrollContainer: + scroll.ensure_control_visible(node) + emit_signal('selected_changed', i_row) ## Делает ряд [param i_row] видимым. func ensure_row_visible(i_row: int): - assert(scroll is ScrollContainer, 'Таблица должна быть дочерней к ScrollContainer') - var key: = get_node_key(NODE_KEY_FORMAT, 0, i_row) - var node = nodes[key] - scroll.ensure_control_visible(node) + assert(scroll is ScrollContainer, 'Таблица должна быть дочерней к ScrollContainer') + var key: = get_node_key(NODE_KEY_FORMAT, 0, i_row) + var node = nodes[key] + scroll.ensure_control_visible(node) ## Устанавливает выравнивание из массива [param alignments] для всех колонок. func set_columns_alignments(alignments: Array): - assert(columns == alignments.size()) - var rows_count: = get_rows_count() - for i_row in rows_count: - for i_col in alignments.size(): - set_node_alligment(i_col, i_row, alignments[i_col]) + assert(columns == alignments.size()) + var rows_count: = get_rows_count() + for i_row in rows_count: + for i_col in alignments.size(): + set_node_alligment(i_col, i_row, alignments[i_col]) ## func load_selector_scene(file_name: String): - selector_type_file = file_name - ScnSelector = load(file_name) + selector_type_file = file_name + ScnSelector = load(file_name) ## func load_node_scene(file_name: String): - node_type_file = file_name - ScnNode = load(file_name) + node_type_file = file_name + ScnNode = load(file_name) ## func _ready(): - ScnSelector = load(selector_type_file) - ScnNode = load(node_type_file) - assert(ScnSelector is PackedScene) - assert(ScnNode is PackedScene) + ScnSelector = load(selector_type_file) + ScnNode = load(node_type_file) + assert(ScnSelector is PackedScene) + assert(ScnNode is PackedScene) ## Выравнивает по нижнему левому углу. Используется для выравнивания по заголовку. func align_to_left_bottompos(hdr: Control, gap: = Vector2(0, 0)): - position.x = hdr.position.x + gap.x - position.y = hdr.position.y + hdr.size.y + gap.y + position.x = hdr.position.x + gap.x + position.y = hdr.position.y + hdr.size.y + gap.y ## Устанавливает пользовательские данные для ячейки.[br] @@ -153,9 +153,9 @@ func align_to_left_bottompos(hdr: Control, gap: = Vector2(0, 0)): ## [param pname] - Имя пользовательских данных.[br] ## [param val] - Значение пользовательских данных.[br] func set_node_meta(i_col: int, i_row: int, pname: String, val) -> void: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - var node = nodes[key] - node.set_meta(pname, val) + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + var node = nodes[key] + node.set_meta(pname, val) ## Возвращает пользовательские данные для ячейки.[br] @@ -163,10 +163,10 @@ func set_node_meta(i_col: int, i_row: int, pname: String, val) -> void: ## [param i_row] - Индекс ряда.[br] ## [param pname] - Имя пользовательских данных.[br] func get_node_meta(i_col: int, i_row: int, pname: String): - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - var node = nodes[key] - assert_meta(i_col, i_row, pname, node) - return node.get_meta(pname) + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + var node = nodes[key] + assert_meta(i_col, i_row, pname, node) + return node.get_meta(pname) ## Устанавливает свойство ячейки.[br] @@ -176,9 +176,9 @@ func get_node_meta(i_col: int, i_row: int, pname: String): ## [param val] - Значение свойства.[br] ## [i]Свойство[/i] [param pname] [i]ячейки должно существовать.[/i] func set_node_property(i_col: int, i_row: int, pname: String, val) -> void: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - var node = nodes[key] - node.set(pname, val) + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + var node = nodes[key] + node.set(pname, val) ## Возвращает значение поля ячейки.[br] @@ -186,9 +186,9 @@ func set_node_property(i_col: int, i_row: int, pname: String, val) -> void: ## [param i_col] - Индекс колонки.[br] ## [param i_row] - Индекс ряда. func get_node_property(i_col: int, i_row: int, pname: String): - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - var node = nodes[key] - return node.get(pname) + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + var node = nodes[key] + return node.get(pname) ## Возвращает ключ для существующей ячейки. Если ячейки с заданными индексами нет, @@ -196,313 +196,313 @@ func get_node_property(i_col: int, i_row: int, pname: String): ## [param i_col] - Индекс колонки.[br] ## [param i_row] - Индекс ряда func get_node_key(format: String, i_col: int, i_row: int) -> String: - var key: String = format % [i_row, i_col] - assert(nodes.has(key), 'ошибка: нет такой ячейки - колонка:%d ряд:%d' % [i_col, i_row]) - return key + var key: String = format % [i_row, i_col] + assert(nodes.has(key), 'ошибка: нет такой ячейки - колонка:%d ряд:%d' % [i_col, i_row]) + return key ## Возвращает массив с индексом ячейки:[br] ## [b][0][/b] - индекс колонки,[br] ## [b][1][/b] - индекс строки. func get_key_indexes(key: String) -> Array: - var tokens: = key.split('_') - assert(tokens.size() == 3, 'ошибка: неверный ключ: \"%s\"' % key) - return [int(tokens[2]), int(tokens[1])] + var tokens: = key.split('_') + assert(tokens.size() == 3, 'ошибка: неверный ключ: \"%s\"' % key) + return [int(tokens[2]), int(tokens[1])] ## func set_columns_min_size(sizes: Array) -> void: - assert((columns == 1) or (columns == sizes.size())) - columns = sizes.size() - var rows_count: = get_rows_count() - columns_min_size.clear() - for sz in sizes: - columns_min_size.append(sz) - for i_row in rows_count: - set_nodes_min_size(i_row, sizes, NODE_KEY_FORMAT) - if nodes.has(HEAD_KEY_FORMAT % [0, 0]): - set_nodes_min_size(0, sizes, HEAD_KEY_FORMAT) + assert((columns == 1) or (columns == sizes.size())) + columns = sizes.size() + var rows_count: = get_rows_count() + columns_min_size.clear() + for sz in sizes: + columns_min_size.append(sz) + for i_row in rows_count: + set_nodes_min_size(i_row, sizes, NODE_KEY_FORMAT) + if nodes.has(HEAD_KEY_FORMAT % [0, 0]): + set_nodes_min_size(0, sizes, HEAD_KEY_FORMAT) ## func set_columns_aligment(alignments: Array) -> void: - var rows_count: = get_rows_count() - for i_row in rows_count: - for i_col in alignments.size(): - set_node_alligment(i_col, i_row, alignments[i_col]) + var rows_count: = get_rows_count() + for i_row in rows_count: + for i_col in alignments.size(): + set_node_alligment(i_col, i_row, alignments[i_col]) ## func _input(event) -> void: - if not is_visible_in_tree(): return - if event is InputEventKey: - if event.pressed and in_focus: - if event.keycode == selector_key_up: - selector_up() - elif event.keycode == selector_key_down: - selector_down() - elif event is InputEventMouseButton: - if not event.pressed: - return - if check_event_pos(event.position, scroll): - if not in_focus: - in_focus = true - emit_signal('focus_entered') - elif not check_event_pos(event.position, scroll): - if in_focus: - in_focus = false - emit_signal('focus_exited') + if not is_visible_in_tree(): return + if event is InputEventKey: + if event.pressed and in_focus: + if event.keycode == selector_key_up: + selector_up() + elif event.keycode == selector_key_down: + selector_down() + elif event is InputEventMouseButton: + if not event.pressed: + return + if check_event_pos(event.position, scroll): + if not in_focus: + in_focus = true + emit_signal('focus_entered') + elif not check_event_pos(event.position, scroll): + if in_focus: + in_focus = false + emit_signal('focus_exited') ## func _init() -> void: - selector_color_proc = Callable(self, 'defaultselector_color_proc') - assert(selector_color_proc.is_valid()) - selector_size_proc = Callable(self, 'default_selector_size_proc') - assert(selector_size_proc.is_valid()) - scroll = self + selector_color_proc = Callable(self, 'defaultselector_color_proc') + assert(selector_color_proc.is_valid()) + selector_size_proc = Callable(self, 'default_selector_size_proc') + assert(selector_size_proc.is_valid()) + scroll = self ## func check_event_pos(event_pos: Vector2, obj: Control): - return \ - (event_pos.x > obj.position.x) \ - and (event_pos.x < (obj.position.x + obj.size.x)) \ - and (event_pos.y > obj.position.y) \ - and (event_pos.y < (obj.position.y + obj.size.y)) + return \ + (event_pos.x > obj.position.x) \ + and (event_pos.x < (obj.position.x + obj.size.x)) \ + and (event_pos.y > obj.position.y) \ + and (event_pos.y < (obj.position.y + obj.size.y)) ## func setselector_color_proc(instance: Object, function: String) -> void: - selector_color_proc = Callable(instance, function) - assert(selector_color_proc.is_valid()) + selector_color_proc = Callable(instance, function) + assert(selector_color_proc.is_valid()) ## func set_selector_size_proc(instance: Object, function: String) -> void: - selector_size_proc = Callable(instance, function) - assert(selector_size_proc.is_valid()) + selector_size_proc = Callable(instance, function) + assert(selector_size_proc.is_valid()) ## [param i_row] - Индекс ряда func default_selector_size_proc(i_row: int, rect: Array) -> void: - get_row_rect(i_row, rect) - rect[0] += position.x - node_gap.x / 2.0 - rect[1] += position.y - node_gap.y / 2.0 - rect[2] += node_gap.x - rect[3] += node_gap.y + get_row_rect(i_row, rect) + rect[0] += position.x - node_gap.x / 2.0 + rect[1] += position.y - node_gap.y / 2.0 + rect[2] += node_gap.x + rect[3] += node_gap.y ## func clear_rows_selected(): - var rows_count: = get_rows_count() - for i_row in rows_count: - set_row_selected(i_row, false) + var rows_count: = get_rows_count() + for i_row in rows_count: + set_row_selected(i_row, false) ## [param i_row] - Индекс ряда. func set_row_selected(i_row: int, selected: bool = true) -> void: - call_deferred('_set_row_selected', i_row, selected) + call_deferred('_set_row_selected', i_row, selected) ## [param i_row] - Индекс ряда. func _set_row_selected(i_row: int, selected: bool = true) -> void: - var selector_key: = SELECTOR_KEY_FORMAT % [i_row, 0] - var node_key: = NODE_KEY_FORMAT % [i_row, 0] - if not nodes.has(node_key): - push_error('ошибка: нет такого ряда: %d' % i_row) - return - if nodes.has(selector_key) and (not selected): - var node = nodes[node_key] - var selector = nodes[selector_key] - node.remove_child(selector) - selector.queue_free() - nodes.erase(selector_key) - elif (not nodes.has(selector_key)) and selected: - var selector = ScnSelector.instantiate() - var rect: = [0, 0, 0, 0] - selector_size_proc.call(i_row, rect) - selector.size.x = rect[2] - selector.size.y = rect[3] - selector.modulate = selector_color_proc.call(i_row) - selector.z_index = z_index + 1 - nodes[selector_key] = selector - var node = nodes[node_key] - node.add_child(selector) + var selector_key: = SELECTOR_KEY_FORMAT % [i_row, 0] + var node_key: = NODE_KEY_FORMAT % [i_row, 0] + if not nodes.has(node_key): + push_error('ошибка: нет такого ряда: %d' % i_row) + return + if nodes.has(selector_key) and (not selected): + var node = nodes[node_key] + var selector = nodes[selector_key] + node.remove_child(selector) + selector.queue_free() + nodes.erase(selector_key) + elif (not nodes.has(selector_key)) and selected: + var selector = ScnSelector.instantiate() + var rect: = [0, 0, 0, 0] + selector_size_proc.call(i_row, rect) + selector.size.x = rect[2] + selector.size.y = rect[3] + selector.modulate = selector_color_proc.call(i_row) + selector.z_index = z_index + 1 + nodes[selector_key] = selector + var node = nodes[node_key] + node.add_child(selector) ## [param i_row] - Индекс ряда. func is_row_selected(i_row: int) -> bool: - var key: = SELECTOR_KEY_FORMAT % [i_row, 0] - return nodes.has(key) + var key: = SELECTOR_KEY_FORMAT % [i_row, 0] + return nodes.has(key) ## [param i_row] - Индексы рядов. func get_selected_rows(i_rows: Array) -> void: - for key in nodes.keys(): - if SLCT_PREFIX in key: - var indexes = get_key_indexes(key) - i_rows.append(indexes[1]) + for key in nodes.keys(): + if SLCT_PREFIX in key: + var indexes = get_key_indexes(key) + i_rows.append(indexes[1]) ## Возвращает количество рядов func get_rows_count() -> int: - var nodes_count: int = 0 - for key in nodes: - nodes_count += int(NODE_PREFIX in key) - return nodes_count / columns + var nodes_count: int = 0 + for key in nodes: + nodes_count += int(NODE_PREFIX in key) + return nodes_count / columns ## [param i_col] - Индекс колонки. [param i_row] - Индекс ряда. func get_node2(i_col: int, i_row: int) -> Node: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - return nodes[key] + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + return nodes[key] ## Добавляет ряд. [param row_types] - Массив типов ячеек ряда func add_row(row_types: Array) -> void: - assert(row_types.size() < MAX_INDEX, 'ошибка: слишком много колонок, больше %d' % (MAX_INDEX + 1)) - if columns == 1: - set_columns(row_types.size()) - else: - assert(columns == row_types.size(), 'ошибка: %s количество колонок установлено ранее - %d, но требуется %d' % [self, columns, row_types.size()]) - var i_row: int = get_rows_count() - assert(i_row < MAX_INDEX, 'ошибка: слишком много рядов, больше %d' % (MAX_INDEX + 1)) - var allow_set_size = columns_min_size.size() >= row_types.size() - for i_col in columns: - var node_type = row_types[i_col] - var node = node_type.instantiate() - assert(node.name == node.name, 'ошибка: экземпляр не имеет поля \"name\"') - var node_key: String = NODE_KEY_FORMAT % [i_row, i_col] - node.name = node_key - add_child(node) - if allow_set_size: - node.custom_minimum_size.x = columns_min_size[i_col] - node.set_deferred('size.x', columns_min_size[i_col]) - nodes[node_key] = node - var conn = Callable(self, '_on_focus_entered').bind(node) - node.connect('focus_entered', conn) - set_node_meta(i_col, i_row, 'callable_focus_entered', conn) + assert(row_types.size() < MAX_INDEX, 'ошибка: слишком много колонок, больше %d' % (MAX_INDEX + 1)) + if columns == 1: + set_columns(row_types.size()) + else: + assert(columns == row_types.size(), 'ошибка: %s количество колонок установлено ранее - %d, но требуется %d' % [self, columns, row_types.size()]) + var i_row: int = get_rows_count() + assert(i_row < MAX_INDEX, 'ошибка: слишком много рядов, больше %d' % (MAX_INDEX + 1)) + var allow_set_size = columns_min_size.size() >= row_types.size() + for i_col in columns: + var node_type = row_types[i_col] + var node = node_type.instantiate() + assert(node.name == node.name, 'ошибка: экземпляр не имеет поля \"name\"') + var node_key: String = NODE_KEY_FORMAT % [i_row, i_col] + node.name = node_key + add_child(node) + if allow_set_size: + node.custom_minimum_size.x = columns_min_size[i_col] + node.set_deferred('size.x', columns_min_size[i_col]) + nodes[node_key] = node + var conn = Callable(self, '_on_focus_entered').bind(node) + node.connect('focus_entered', conn) + set_node_meta(i_col, i_row, 'callable_focus_entered', conn) ## func _on_focus_entered(node): - var indexes = get_key_indexes(node.name) - emit_signal('row_pressed', indexes[1]) + var indexes = get_key_indexes(node.name) + emit_signal('row_pressed', indexes[1]) ## func set_header(header_types: Array): - assert(header_types.size() < MAX_INDEX, 'ошибка: количество колонок в заголовке: %d больше допустимого: %d' % [header_types.size(), MAX_INDEX + 1]) - if columns == 1: - set_columns(header_types.size()) - else: - assert(columns == header_types.size(), 'ошибка: количество колонок в заголовке %d, но ранее установлено: %d' % [header_types.size(), columns]) - var do_adj: = false - if not header: - header = GridContainer.new() - var parent = scroll.get_parent() - parent.add_child(header) - header.position = position - header.columns = header_types.size() - do_adj = true - else: - var childrens = header.get_children() - for node in childrens: - childrens.erase(node.name) - childrens.remove_child(node) - node.queue_free() - for i_col in columns: - var node = header_types[i_col].instantiate() - var key: String = HEAD_KEY_FORMAT % [0, i_col] - node.name = key - nodes[key] = node - header.add_child(node) - if do_adj: - var rect = [0, 0, 0, 0] - get_node_rect(0, 0, rect, HEAD_KEY_FORMAT) - position.y += rect[3] + assert(header_types.size() < MAX_INDEX, 'ошибка: количество колонок в заголовке: %d больше допустимого: %d' % [header_types.size(), MAX_INDEX + 1]) + if columns == 1: + set_columns(header_types.size()) + else: + assert(columns == header_types.size(), 'ошибка: количество колонок в заголовке %d, но ранее установлено: %d' % [header_types.size(), columns]) + var do_adj: = false + if not header: + header = GridContainer.new() + var parent = scroll.get_parent() + parent.add_child(header) + header.position = position + header.columns = header_types.size() + do_adj = true + else: + var childrens = header.get_children() + for node in childrens: + childrens.erase(node.name) + childrens.remove_child(node) + node.queue_free() + for i_col in columns: + var node = header_types[i_col].instantiate() + var key: String = HEAD_KEY_FORMAT % [0, i_col] + node.name = key + nodes[key] = node + header.add_child(node) + if do_adj: + var rect = [0, 0, 0, 0] + get_node_rect(0, 0, rect, HEAD_KEY_FORMAT) + position.y += rect[3] ## func set_header_text(headers: Array): - assert(columns == headers.size()) - set_row_text(0, headers, 0, HEAD_KEY_FORMAT) + assert(columns == headers.size()) + set_row_text(0, headers, 0, HEAD_KEY_FORMAT) ## [param i_row] - индекс ряда. func remove_row(i_row: int): - var sel_key: String = SELECTOR_KEY_FORMAT % [i_row, 0] + var sel_key: String = SELECTOR_KEY_FORMAT % [i_row, 0] - if nodes.has(sel_key): - var selector = nodes[sel_key] - var prnt = selector.get_parent() - prnt.remove_child(selector) - selector.queue_free() - nodes.erase(sel_key) + if nodes.has(sel_key): + var selector = nodes[sel_key] + var prnt = selector.get_parent() + prnt.remove_child(selector) + selector.queue_free() + nodes.erase(sel_key) - for i_col in columns: + for i_col in columns: - var node_key: String = NODE_KEY_FORMAT % [i_row, i_col] - var node = nodes[node_key] + var node_key: String = NODE_KEY_FORMAT % [i_row, i_col] + var node = nodes[node_key] - var conn = get_node_meta(i_col, i_row, 'callable_focus_entered') - node.disconnect('focus_entered', conn) + var conn = get_node_meta(i_col, i_row, 'callable_focus_entered') + node.disconnect('focus_entered', conn) - if node.has_meta(META_CALLABLE): - conn = node.get_meta(META_CALLABLE) - var event_name = node.get_meta(META_EVENT_NAME) - node.disconnect(event_name, conn) + if node.has_meta(META_CALLABLE): + conn = node.get_meta(META_CALLABLE) + var event_name = node.get_meta(META_EVENT_NAME) + node.disconnect(event_name, conn) - remove_child(node) - nodes.erase(node_key) - node.queue_free() - rehash() + remove_child(node) + nodes.erase(node_key) + node.queue_free() + rehash() ## func next_index(indexes: Array) -> void: - indexes[0].x += 1 - if indexes[0].x == columns: - indexes[0].x = 0 - indexes[0].y += 1 + indexes[0].x += 1 + if indexes[0].x == columns: + indexes[0].x = 0 + indexes[0].y += 1 ## func swap_nodes(nodes_copy, node_key_format, i0, i1) -> void: - var key0 = node_key_format % [i0.y, i0.x] - var key1 = node_key_format % [i1.y, i1.x] - nodes_copy[key1] = nodes[key0] - nodes_copy[key1].name = key1 + var key0 = node_key_format % [i0.y, i0.x] + var key1 = node_key_format % [i1.y, i1.x] + nodes_copy[key1] = nodes[key0] + nodes_copy[key1].name = key1 ## Переназначает ключи в соответствии с размерами таблицы. func rehash(): - var i_node: = [Vector2i()] - var i_hdr: = [Vector2i()] - var i_slct: = [Vector2i()] - var nodes_copy = {} - for key in nodes: - var iv = get_key_indexes(key) - var i0 = Vector2(iv[0], iv[1]) - if HEAD_PREFIX in key: - swap_nodes(nodes_copy, HEAD_KEY_FORMAT, i0, i_hdr[0]) - next_index(i_hdr) - elif NODE_PREFIX in key: - swap_nodes(nodes_copy, NODE_KEY_FORMAT, i0, i_node[0]) - next_index(i_node) - elif SLCT_PREFIX in key: - swap_nodes(nodes_copy, SELECTOR_KEY_FORMAT, i0, i_slct[0]) - next_index(i_slct) - nodes.clear() - nodes.merge(nodes_copy) + var i_node: = [Vector2i()] + var i_hdr: = [Vector2i()] + var i_slct: = [Vector2i()] + var nodes_copy = {} + for key in nodes: + var iv = get_key_indexes(key) + var i0 = Vector2(iv[0], iv[1]) + if HEAD_PREFIX in key: + swap_nodes(nodes_copy, HEAD_KEY_FORMAT, i0, i_hdr[0]) + next_index(i_hdr) + elif NODE_PREFIX in key: + swap_nodes(nodes_copy, NODE_KEY_FORMAT, i0, i_node[0]) + next_index(i_node) + elif SLCT_PREFIX in key: + swap_nodes(nodes_copy, SELECTOR_KEY_FORMAT, i0, i_slct[0]) + next_index(i_slct) + nodes.clear() + nodes.merge(nodes_copy) ## Удаляет все строки таблицы func clear_rows() -> void: - var rows_count: int = get_rows_count() - for i_row in range(rows_count - 1, -1, -1): - remove_row(i_row) + var rows_count: int = get_rows_count() + for i_row in range(rows_count - 1, -1, -1): + remove_row(i_row) ## Настраевает обратные вызовы для колонок.[br] @@ -512,57 +512,57 @@ func clear_rows() -> void: ## [param clmns] - Индексы колонок[br] ## [param user_data] - Аргументы функции получателя события[br] func connect_columns(dest_node: Node, event_name: String, callback: String, clmns: Array, user_data: Array = []) -> void: - var rows_count = get_rows_count() - for i_row in rows_count: - for i_col in clmns: - assert(i_col >= 0 and i_col < columns, 'ошибка: нет такой колонки: %d' % i_col) - var node = get_node2(i_col, i_row) - if node.has_meta(META_CALLABLE): - var conn_prev = node.get_meta(META_CALLABLE) - node.disconnect(event_name, conn_prev) - var conn = Callable(dest_node, callback).bind([node] + user_data) - var rc = node.connect(event_name, conn) - if rc == Error.OK: - node.set_meta(META_CALLABLE, conn) - node.set_meta(META_EVENT_NAME, event_name) - else: - var es = error_string(rc) - push_error('ошибка: событие \"%s\" не может быть подключено к %s: %s' % [event_name, node, es]) + var rows_count = get_rows_count() + for i_row in rows_count: + for i_col in clmns: + assert(i_col >= 0 and i_col < columns, 'ошибка: нет такой колонки: %d' % i_col) + var node = get_node2(i_col, i_row) + if node.has_meta(META_CALLABLE): + var conn_prev = node.get_meta(META_CALLABLE) + node.disconnect(event_name, conn_prev) + var conn = Callable(dest_node, callback).bind([node] + user_data) + var rc = node.connect(event_name, conn) + if rc == Error.OK: + node.set_meta(META_CALLABLE, conn) + node.set_meta(META_EVENT_NAME, event_name) + else: + var es = error_string(rc) + push_error('ошибка: событие \"%s\" не может быть подключено к %s: %s' % [event_name, node, es]) ## func set_rows_text(rows: Array) -> void: - for i_row in rows.size(): - for i_col in columns: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - var node = nodes[key] - node.text = rows[i_row][i_col] + for i_row in rows.size(): + for i_col in columns: + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + var node = nodes[key] + node.text = rows[i_row][i_col] ## [param i_row] - Индекс ряда. func set_nodes_min_size(i_row: int, sizes: Array, key_format: String = NODE_KEY_FORMAT) -> void: - columns_min_size.clear() - for sz in sizes: - columns_min_size.append(sz) - for i_col in columns: - var key: = get_node_key(key_format, i_col, i_row) - var node = nodes[key] - node.custom_minimum_size.x = sizes[i_col] - node.set_deferred('size.x', sizes[i_col]) + columns_min_size.clear() + for sz in sizes: + columns_min_size.append(sz) + for i_col in columns: + var key: = get_node_key(key_format, i_col, i_row) + var node = nodes[key] + node.custom_minimum_size.x = sizes[i_col] + node.set_deferred('size.x', sizes[i_col]) ## [param i_col] - Индекс колонки.[br][param i_row] - Индекс ряда. func set_node_text(i_col: int, i_row: int, val: String) -> void: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - nodes[key].text = val + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + nodes[key].text = val ## func set_rows_state(rows: Array) -> void: - for i_row in rows.size(): - for i_col in columns: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - nodes[key].button_pressed = rows[i_row][i_col] + for i_row in rows.size(): + for i_col in columns: + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + nodes[key].button_pressed = rows[i_row][i_col] ## Устанавливает состояние ячейки. @@ -571,59 +571,59 @@ func set_rows_state(rows: Array) -> void: ## [param val] - Новое состояние.[br] ## [i]Ячейка должна иметь свойство[/i] [param button_pressed] func set_node_state(i_col: int, i_row: int, val: bool) -> void: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - nodes[key].button_pressed = val + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + nodes[key].button_pressed = val ## [param i_col] - Индекс колонки.[br] ## [param i_row] - Индекс ряда. func set_node_frame(i_col: int, i_row: int, node_name: String, val: int) -> void: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - var node = nodes[key] - var sprite = node.get_node(node_name) - sprite.frame = val + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + var node = nodes[key] + var sprite = node.get_node(node_name) + sprite.frame = val ## Разрешает редактирование ячейки. Ячейка должна иметь свойство [param editable].[br] ## [param i_col] - Индекс колонки.[br] ## [param i_row] - Индекс ряда. func set_node_editable(i_col: int, i_row: int, val: bool) -> void: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - nodes[key].editable = val + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + nodes[key].editable = val ## Разрешает редактирование ряда. Ячейки ряда должны иметь свойство [param editable].[br] ## [param i_row] - Индекс ряда. func set_row_editable(i_row: int, val: bool) -> void: - for i_col in columns: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - nodes[key].editable = val + for i_col in columns: + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + nodes[key].editable = val ## [param i_col] - Индекс колонки.[br] ## [param i_row] - Индекс ряда. func set_node_alligment(i_col: int, i_row: int, val: int) -> void: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - if 'horizontal_alignment' in nodes[key]: - nodes[key].horizontal_alignment = val - elif 'alignment' in nodes[key]: - nodes[key].alignment = val + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + if 'horizontal_alignment' in nodes[key]: + nodes[key].horizontal_alignment = val + elif 'alignment' in nodes[key]: + nodes[key].alignment = val ## [param i_row] - Индекс ряда. func set_row_alligments(i_row: int, aligns: Array) -> void: - for i_col in columns: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - nodes[key].align = aligns[i_col] + for i_col in columns: + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + nodes[key].align = aligns[i_col] ## [param i_row] - Индекс ряда. func get_row_text(i_row: int) -> Array: - var row: = [] - for i_col in columns: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - row.append(nodes[key].text) - return row + var row: = [] + for i_col in columns: + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + row.append(nodes[key].text) + return row ## Устанавливает текст ячеек ряда.[br] @@ -632,51 +632,51 @@ func get_row_text(i_row: int) -> Array: ## [param i_begin] - Начальный индекс колонки начиная с которого установить новые значения.[br] ## [i]Ячейки ряда должны иметь свойство[/i] [param text] func set_row_text(i_row: int, row: Array, i_begin: int = 0, key_format: String = NODE_KEY_FORMAT) -> void: - assert((i_begin >= 0) and (i_begin < columns)) - assert((columns - i_begin) >= row.size()) - for i_col in row.size(): - var key: = get_node_key(key_format, i_col + i_begin, i_row) - nodes[key].text = row[i_col] + assert((i_begin >= 0) and (i_begin < columns)) + assert((columns - i_begin) >= row.size()) + for i_col in row.size(): + var key: = get_node_key(key_format, i_col + i_begin, i_row) + nodes[key].text = row[i_col] ## Возвращает все строки таблицы в двумерном массиве func get_rows_text() -> Array: - var rows_count: = get_rows_count() - var rows: = [] - for i_row in rows_count: - var row = get_row_text(i_row) - rows.append(row) - return rows + var rows_count: = get_rows_count() + var rows: = [] + for i_row in rows_count: + var row = get_row_text(i_row) + rows.append(row) + return rows ## Возвращает массив ячеек из ряда [param i_row] func get_row(i_row: int) -> Array: - var row: = [] - for i_col in columns: - var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) - row.append(nodes[key]) - return row + var row: = [] + for i_col in columns: + var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + row.append(nodes[key]) + return row ## Возвращает прямоугольник [param rect] занимаемый ячейкой в ряду [param i_row] и колонке [param i_col]. ## [param key_format] - Формат ключа ячейки func get_node_rect(i_col: int, i_row: int, rect: Array, key_format: String = NODE_KEY_FORMAT) -> void: - assert(rect.size() >= 4, 'ошибка: мало элементов для возврата результата') - var key: = get_node_key(key_format, i_col, i_row) - var cell = nodes[key] - rect[0] = cell.position.x - rect[1] = cell.position.y - rect[2] = cell.size.x - rect[3] = cell.size.y + assert(rect.size() >= 4, 'ошибка: мало элементов для возврата результата') + var key: = get_node_key(key_format, i_col, i_row) + var cell = nodes[key] + rect[0] = cell.position.x + rect[1] = cell.position.y + rect[2] = cell.size.x + rect[3] = cell.size.y ## Возвращает прямоугольник [param rect] занимаемый рядом [param i_row].[br] ## [param key_format] - Формат ключа ячейки func get_row_rect(i_row: int, rect: Array, key_format: String = NODE_KEY_FORMAT) -> void: - assert(rect.size() >= 4, 'ошибка: мало элементов для возврата результата') - var cell0 = nodes[get_node_key(key_format, 0, i_row)] - var cell1 = nodes[get_node_key(key_format, columns - 1, i_row)] - rect[0] = cell0.position.x + scroll_adj.x - rect[1] = cell0.position.y + scroll_adj.y - rect[2] = (cell1.position.x - cell0.position.x) + cell1.size.x - rect[3] = cell0.size.y + assert(rect.size() >= 4, 'ошибка: мало элементов для возврата результата') + var cell0 = nodes[get_node_key(key_format, 0, i_row)] + var cell1 = nodes[get_node_key(key_format, columns - 1, i_row)] + rect[0] = cell0.position.x + scroll_adj.x + rect[1] = cell0.position.y + scroll_adj.y + rect[2] = (cell1.position.x - cell0.position.x) + cell1.size.x + rect[3] = cell0.size.y