LED-mapper/README.md
Danil Iarosh 37fbb2c545 fix: isolate Windows build dependencies
- Ограничен поиск DLL при сборке каталогами Python, окружения и Windows.
- Добавлена проверка источников бинарных библиотек перед упаковкой.
- Добавлен режим --verify-bundle и регрессионный smoke-тест.
- Обновлены документация и версия приложения до 3.3.1.
2026-09-18 14:32:19 +03:00

203 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

# LED Mapper
LED Mapper — настольное приложение на Python и PySide6 для разметки LED-точек на схеме, распределения их по физическим линиям светодиодных лент и генерации `vm_map.h` для прошивки.
Приложение помогает вручную или полуавтоматически собрать адресацию светодиодов: выбрать точки на схеме, создать линии, разбить их на блоки, проверить индексацию и сгенерировать готовые файлы маппинга.
## Возможности
- Загрузка карты LED-точек из JSON.
- Отображение схемы в реальных координатах.
- Выделение точек мышью и работа через таблицу выбранных LED.
- До 4 физических линий светодиодных лент.
- Нумерация линий и блоков с `0`.
- Блоки внутри линий, включая пустые блоки.
- Индексация LED отдельно для каждой линии, начиная с `0`.
- Индексация внутри каждого блока.
- Добавление блоков вручную, из выделения, автоблоками и кистью.
- Продолжение существующего блока кистью от последней точки блока.
- Предпросмотр зоны действия кисти и точек, которые будут добавлены.
- Сетка с настраиваемым шагом (по умолчанию 34 мм) во всех режимах редактирования и генерации.
- Настраиваемый абсолютный диаметр LED-точек: визуальный размер не меняется при приближении.
- Undo/redo для операций разметки.
- Удаление назначений через `Del` и контекстные меню.
- Пакетное удаление выбранных блоков через дерево одной операцией с единым Undo.
- Сворачивание боковой панели.
- Сортировка таблицы выбранных точек по столбцам.
- Генерация `vm_map.h`, `ordered_circles.json`, `validation_report.txt` и README для результата.
- Сборка самостоятельного Windows EXE через PyInstaller.
- Проверка и установка Windows-обновлений из релизов Gitea.
## Структура приложения
```text
main.py Точка входа GUI-приложения
main_window.py Главное окно, меню, действия, таблица и дерево линий
canvas.py Холст схемы, выделение, кисть, сетка и связи
models.py Модель карты, линий, блоков и алгоритмы маршрутов
panel_mapping_generator.py Генерация файлов маппинга
update_service.py Проверка релизов и безопасная установка Windows EXE
version.py Базовая версия приложения при запуске из исходников
icons.py Встроенные lucide-иконки
unfolding.py Описание развертки линий и блоков
qa_smoke.py Smoke-тесты приложения
requirements.txt Runtime-зависимости
LEDMapper.spec PyInstaller-конфигурация для сборки EXE
```
## Требования
- Windows.
- Python 3.10 или новее.
- PySide6.
Для разработки и запуска используется локальное виртуальное окружение проекта.
## Быстрый старт
Из корневой папки проекта создайте окружение:
```powershell
python -m venv .venv
```
Установите зависимости:
```powershell
.\.venv\Scripts\python.exe -m pip install -r app\requirements.txt
```
Запустите приложение:
```powershell
.\.venv\Scripts\python.exe app\main.py
```
Если вы находитесь внутри папки `app`, запуск выглядит так:
```powershell
..\.venv\Scripts\python.exe main.py
```
## Основной сценарий работы
1. Откройте JSON-карту точек через `Файл -> Открыть`.
2. Создайте линию кнопкой `Линия` или через меню `Инструменты -> Новая линия`.
3. Выберите точки на схеме или в таблице.
4. Создайте блок из выбранных точек, автоблоки или включите инструмент `Кисть`.
5. Повторите разметку для остальных линий и блоков.
6. Проверьте счетчики в верхней части боковой панели: количество линий, блоков и назначенных LED.
7. Сгенерируйте скрипт через `Файл -> Сгенерировать скрипт`.
Шаг сетки и диаметр точек меняются в `Файл -> Параметры -> Внешний вид`. Для каждого значения рядом есть кнопка `Сбросить`. Шаг сетки сохраняется в JSON текущей схемы, а диаметр точек — в пользовательских параметрах приложения. Изменение шага не перемещает уже существующие LED автоматически.
Чтобы удалить несколько блоков, выделите их в дереве с `Ctrl` или `Shift`, затем нажмите `Ctrl+Del` или выберите удаление в контекстном меню. Приложение показывает одно подтверждение и создаёт одну операцию Undo.
В режиме редактирования выбранные светодиоды можно скопировать через `Ctrl+C` и вставить через `Ctrl+V`. Вставленные LED остаются свободными, сохраняют взаимное расположение и пользовательские поля исходных точек. Первая копия смещается на один шаг сетки вправо и вниз, а следующие вставки образуют каскад. Вся группа вставляется одной операцией Undo и сразу становится текущим выделением.
В собранном Windows EXE приложение проверяет наличие нового стабильного релиза после запуска. В меню `Справка` можно запустить проверку вручную и, если новая версия найдена, выбрать `Установить обновление`. Загружается только артефакт вида `LEDMapper-vX.Y.Z.exe` из репозитория `Robotail/LED-mapper` на `git.robotail.pro`. После проверки размера и формата EXE приложение предлагает сохранить изменённую схему, закрывается, а отдельный процесс заменяет EXE по прежнему пути и запускает новую версию — существующие ярлыки продолжают работать. Версия релизной сборки хранится внутри EXE, поэтому переименование файла не вызывает повторную установку того же обновления. При неудачном запуске старая версия восстанавливается; причина записывается рядом с EXE в `update-error.log`. Для обновления нужны доступ к серверу релизов и право записи в каталог приложения. Из исходников можно проверить наличие версии, но автоустановка недоступна.
Если не назначен ни один светодиод, генерация не запускается. Если назначены не все светодиоды, приложение показывает предупреждение и предлагает либо сгенерировать неполный маппинг, либо продолжить редактирование.
## Горячие клавиши
| Действие | Клавиши |
| --- | --- |
| Открыть | `Ctrl+O` |
| Сохранить | `Ctrl+S` |
| Сохранить как | `Ctrl+Shift+S` |
| Сгенерировать скрипт | `Ctrl+G` |
| Отменить | `Ctrl+Z` |
| Повторить | `Ctrl+Y` |
| Копировать выбранные LED | `Ctrl+C` |
| Вставить скопированные LED | `Ctrl+V` |
| Удалить фиксацию | `Del` |
| Удалить выбранные точки или блоки | `Ctrl+Del` |
| Удалить все | `Ctrl+Shift+Del` |
| Очистить выбор | `Esc` |
| Показать всю схему | `Ctrl+0` |
| Сетка | `G` |
| Стрелки направления | `Ctrl+Shift+A` |
| Скрыть/показать боковую панель | `F9` |
| Новая линия | `Ctrl+L` |
| Автоблоки | `Ctrl+Shift+B` |
| Кисть | `B` |
## Генерация файлов маппинга
Генератор создает:
- `vm_map.h` — основной header для прошивки.
- `ordered_circles.json` — нормализованные точки и координаты виртуальной матрицы.
- `validation_report.txt` — отчет о проверках маршрутов и ячеек.
- `README.md` — краткое описание результата генерации.
Устаревший `virtual_matrix_legacy.ino.txt` больше не создаётся. Если файл с этим точным именем остался в выходной папке от прежней версии, следующая успешная генерация удалит его. Другие `.ino`-файлы не затрагиваются.
JSON схемы хранит `coordinate_unit`, `grid_step_mm` и `index_base: 0`. При первом открытии старого файла без единицы координат приложение определяет её один раз и затем сохраняет явно. Старые схемы с 1-based ID линий и блоков при загрузке переводятся на 0-based; сохранение записывает маркер `index_base: 0`, чтобы повторная загрузка не сдвигала ID. Сохранение выполняется через временный файл и атомарную замену, поэтому исходный JSON не повреждается при ошибке записи.
Если у схемы есть подложка, при сохранении её исходное PNG- или JPEG-изображение встраивается в секцию `background.embedded_image` внутри JSON вместе с именем, MIME-типом и контрольной суммой. После этого схема не зависит от внешнего файла, а размеры и параметры подложки сохраняются при редактировании и переносе JSON. Для уже встроенного и не заменённого изображения диалог `Подложка` показывает в поле пути значение `Встроенная`. Чтобы заменить его, нажмите `Выбрать` и укажите новый файл; новое изображение будет встроено при следующем сохранении схемы.
В `vm_map.h` используются физические адреса из GUI:
- `strip = line_id`
- `led_id = line_index`
Неназначенные точки не попадают в рабочий `VM_MAPPINGS`, но исходные точки могут оставаться в служебных метаданных.
## Ориентация виртуальной матрицы
Текущий формат явно описывает преобразование координат:
```cpp
#define VM_ROW_FROM_GRID_COL(col) (GRID_COL_MAX - (col))
#define VM_COL_FROM_GRID_ROW(row) ((row) - GRID_ROW_MIN)
```
То есть строка виртуальной матрицы получается из исходной колонки с отражением, а колонка виртуальной матрицы получается из исходного ряда.
## Проверка качества
Из корня проекта:
```powershell
.\.venv\Scripts\python.exe app\qa_smoke.py
```
Проверка компиляции основных модулей:
```powershell
.\.venv\Scripts\python.exe -m py_compile app\main.py app\main_window.py app\canvas.py app\models.py app\panel_mapping_generator.py app\qa_smoke.py
```
## Сборка EXE
Установите PyInstaller в `.venv`:
```powershell
.\.venv\Scripts\python.exe -m pip install pyinstaller
```
Сборка из корня проекта:
```powershell
.\.venv\Scripts\python.exe -m PyInstaller --noconfirm --clean app\LEDMapper.spec
```
Сборочный `spec` ограничивает поиск DLL каталогами Python, виртуального окружения и Windows. Это защищает EXE от несовместимых системных библиотек сторонних программ, добавленных в `PATH`. После сборки проверяйте готовый файл командой `dist\LEDMapper-vX.Y.Z.exe --verify-bundle`: успешная проверка завершается с кодом `0` без открытия окна приложения.
В чистой сборке из релизного тега файл будет называться:
```text
dist/LEDMapper-vX.Y.Z.exe
```
`build/` и `dist/` не коммитятся, потому что это воспроизводимые артефакты сборки.
## Примечания для разработки
- Для работы с приложением использовать только Python из `.venv`.
- Не коммитить `.venv`, `build`, `dist`, `output` и `__pycache__`.
- Перед коммитом желательно запускать `app\qa_smoke.py`.
- Максимальное количество линий светодиодных лент: 4.