Commit Graph

172 Commits

Author SHA1 Message Date
Ivan I. Ovchinnikov b37009a169 stations readable from MDM (raw). get by id ok 2026-07-07 22:17:44 +03:00
emelianov fe54c095ab Формат времени в UTC 2026-06-25 16:21:17 +03:00
emelianov d0ec0ef754 считывание точки прицеливания с карты 2026-06-23 17:13:30 +03:00
emelianov 1e8b9f6998 центрирование каты при тестовом расчете ПУУД 2026-06-18 12:13:50 +03:00
emelianov f0f39e784e Merge remote-tracking branch 'origin/dev' into dev 2026-06-17 15:28:09 +03:00
emelianov d38822db3e Расчет витков по TLE 2026-06-17 15:28:04 +03:00
Дмитрий Соловьев e015b8aa75 Merge branch 'feat/tgu-slots-filters' into 'dev'
fix(tgu-ui): таблица слотов — слить виток/цикл, секунды в начале, длительность

See merge request 2-6/2-6-4/missionis/observatio-terrae!3
2026-06-17 11:17:08 +00:00
Дмитрий Соловьев 354730fb6c feat(tgu-ui): запрет выбора конфликтных слотов + прохождение без подсветки
- конфликтные слоты нельзя добавить в выбор под бронь (клик по строке,
  Shift-диапазон, выбор полосы на карте, «выбрать все») — жёсткая блокировка;
  снятие выбора не блокируется (конфликт считается только для невыбранных)
- слоты одной полосы между собой не конфликтуют (groupOf) — иначе нельзя было
  бы набрать полосу поштучным кликом
- чекбокс «Конфликты» теперь и гасит, и блокирует выбор; выкл. — выбирать любые
- переход на прохождение (◀/▶) больше не подсвечивает никакой слот: активная
  подсветка строки — только по явному клику; добавлена прокрутка к началу прохода
- повторный Shift+клик по тому же концу снимает выделение (таблица и карта)
2026-06-17 14:07:03 +03:00
Дмитрий Соловьев c402f376c5 feat(tgu-ui): степпер по прохождениям и подсветка конфликтов выбора слотов
Степпер прохождений (виток как проход над районом):
- slotPasses.ts: группировка слотов в проходы (КА·cycle·revolution·sign) в
  хронологии по всем КА + юнит-тесты;
- PassStepper.tsx: ◀/▶ листают проходы, окно суток следует за курсором,
  таблица скроллится к проходу, карта не прыгает; выбранный проход
  изолирует отображение, «Все» — назад ко всему набору;
- дата/время прохождения отдельной строкой во всю ширину (видно целиком).

Подсветка конфликтов выбора (мягкая подсказка «станет недоступным»):
- slotConflicts.ts: тот же КА + недостаточный зазор на манёвр — 10 с при том
  же крене, 30 с при смене крена (ROLL_EPSILON); конфликтные слоты гаснут в
  таблице и на карте, остаются выбираемыми (жёсткая выполнимость — за бэком);
- производительность: оконный поиск по времени (~O(N·logM)), кандидаты —
  только видимые, выбор через useDeferredValue (не молотит во время drag);
- чекбокс «Гасить конфликты» в строке выбора: выключает и слой, и расчёт;
- юнит-тесты на правило зазора и оконный поиск.

Карта: проп dimmedObjectIds — серый «налёт» поверх конфликтных слотов в SVG
overlay (без изменения canvas).
2026-06-17 13:31:28 +03:00
Дмитрий Соловьев aabb550a0a fix(tgu-ui): бронь не сбрасывает окно фильтра по суткам
Слайдер «Сутки» раскрывался на весь диапазон после брони: bookedSlots менялся → новый референс days → эффект сбрасывал окно, хотя набор суток тот же. Завязал сброс на сигнатуру набора суток (границы дней), а не на референс массива.
2026-06-17 12:11:03 +03:00
Дмитрий Соловьев 653c930dd6 feat(tgu-ui): выбор полосы слотов мышью на карте (Shift+drag) 2026-06-17 11:31:21 +03:00
Дмитрий Соловьев 61a2c92d28 feat(tgu-ui): Shift+клик ближе к якорю сжимает выделение полосы 2026-06-17 10:20:19 +03:00
Дмитрий Соловьев b092e50dd8 feat(tgu-ui): выбор полосы слотов мышью «от первого к последнему»
Замена авто-чипа «полоса ×N» на ручной жест. Полоса переопределена:
один КА + один крен (ε) + подряд по времени; виток в границу не входит.

- slotStrips.ts: groupStrips → { idByKey, membersOf }; группировка по КА →
  кластеры по крену (ROLL_EPSILON=0.5) → деление по каденции (CADENCE_GAP_FACTOR=1.5)
- slotSelection.ts: selectStripRange вместо toggleStripSelection
- TguSlotsTab.tsx: клик по строке = якорь + выбор; Shift+клик тянет полосу
  между якорем и строкой; выход за полосу запрещён + подсказка; рельс полосы якоря
- tgu-planning.css: убраны стили чипа/hover; user-select:none на строках
- тесты обновлены (125 зелёных), tsc/build чисто
2026-06-17 10:13:11 +03:00
Дмитрий Соловьев 1f44c1a5bb feat(tgu-ui): #50 слой поддержки решений по слотам + выбор полосами
Поверх ручного бронирования — информационный слой (достаточность судит оператор).

M1 покрытие: coverage.ts (растровое Monte-Carlo % покрытия заявки, чистые функции
  + coverage.test.ts), CoveragePanel (живой % + бар), слой coverage на карте
  (drawCoverage, union контуров, клип по заявке).
M2 эргономика: сортировка списка по вкладу в покрытие (жадный маргинальный прирост),
  по крену; колонка «Вклад» (+N%).
M3 конфликты: бейдж держателя BUSY-слота (заявка + важность) из holders в SlotDTO.

Выбор полосами (TASK_slot-strip-selection it.1): slotStrips.ts (groupStrips —
  same-roll цепочки по-КА, ε=0.01 с якорным креном, тотальный порядок) +
  slotStrips.test.ts; toggleStripSelection в slotSelection.ts; чип «полоса ×N» в
  строке, рельс по StripId в сортировке «время», подсветка полосы при наведении.
  Физику выполнимости не дублируем на фронте — это backend validate (it.2).

Смежный баг: anchorIndexRef (якорь Shift-выбора) сбрасывается при смене видимого
набора (фильтры/окно суток), не только сортировки.
2026-06-17 09:06:25 +03:00
Дмитрий Соловьев bd35280691 feat(slots-service): #50 M3 — держатели BUSY-слотов в request-cover
reqCover(all=true) обогащает занятые (BUSY) слоты держателями: какие заявки
блокируют слот, с именем и важностью (обзор конфликтов при ручной броне).

- SlotHolderDTO (requestId + опц. name/importance), поле holders в SlotDTO
  (null для AVAILABLE/BOOKED и прочих путей — обратно совместимо).
- TestSatelliteImpl: для BUSY-слота собирает держателей по пересечению
  сдвинутых на cycle интервалов активных броней (та же логика, что band, с mmi),
  distinct по requestId (множественный держатель).
- EarthService.requestHolders: батч-резолв name/importance заявок; деградация
  через runCatching → emptyMap (request-service недоступен → только id, без падения).
- SlotService.enrichHolders: один батч-запрос на обзор, slot.copy(holders=...).
- SlotDTO переведён в data class (copy вместо ручного перечисления полей).
- Тест: BUSY несёт держателей, BOOKED/AVAILABLE — нет.
2026-06-17 09:05:52 +03:00
Дмитрий Соловьев 5869994690 feat(tgu-slots): подтверждение брони всегда + «Снять всё» снимает всю заявку
- Бронь теперь всегда через диалог подтверждения (симметрично «Снять всё»),
  убран порог в 500 слотов.
- «Снять всё» дочитывает брони заявки через by-request и снимает объединение
  локального и серверного наборов bookedSlotId — гарантированно вся заявка.
- Карта: забронированные слоты вне окна суток подчинены фильтрам видимости
  (статус «бронь»/КА/ветвь) — при выключенном фильтре брони их не видно.
2026-06-15 17:22:35 +03:00
Дмитрий Соловьев 3c94815ffc fix(slots-service): #48 by-request отдаёт бронь в базовом cycle-фрейме
GET booking/by-request/{id} возвращал tn/tk/revolution из базового
cycle-фрейма без сдвига (BookedSlotEntity.toViewDTO), тогда как все
остальные пути (toDetails, allByInterval→shiftedToCycle,
resolveBookedSlotStartTime) сдвигают на cycle*durationCalc и
cycle*cycleRevs. Для броней с cycle > 0 дата уходила на cycle*durationCalc
суток раньше расчётной (cycle=0 совпадал, поэтому баг прятался; #42
починил только ключ sat:slotNum:cycle, не время).

Сдвиг перенесён в SlotService.bookedByReqId через новый
toShiftedViewDTO(satellite); КА резолвится из каталога, нет в каталоге —
базовый фрейм без падения списка. Небезопасный базовый билдер в сущности
удалён. Контур/координаты не сдвигаются (наземный след повторяется
каждый цикл), симметрично shiftedToCycle.

Регрессия в SlotServiceCancelTest: сдвиг tn/tk/витка на cycle брони и
fallback без КА. Бэклог #48 помечен сделанным.
2026-06-15 17:22:25 +03:00
Дмитрий Соловьев b38a97b9a5 feat(tgu-ui): слоты — панель фильтров, показ всех слотов и статус «недоступен»
- Панель фильтров видимости (статус/КА/ветвь) над строкой выбора: единый
  filteredSlots сужает и таблицу, и карту; пустое состояние с «Сбросить».
- Убран потолок отрисовки карты — общую картину не режем, объём сужает оператор
  фильтрами.
- Карту не перецентрируем после расчёта (был прыжок на произвольный первый слот).
- «Показать все слоты» шлёт all=true и показывает занятые бронью (BUSY); бронь
  их не берёт (исключены из выбора/счётчика, чекбокс disabled).
- Починен мёртвый маппинг статуса: бэкенд шлёт BUSY, фронт ждал OCCUPIED.
- BUSY отображается как «недоступен» (конфликт с бронью), а не «занят» —
  чтобы не путать с самой бронью.
2026-06-15 16:45:28 +03:00
Дмитрий Соловьев 052ed5f04b feat(slots-service): параметр all у request-cover — возврат занятых бронью (BUSY) слотов
«Показать все слоты» должно показывать полный набор. При all=true reqCover
запрашивает статусы [AVAILABLE, BOOKED, BUSY], а selectCoverageSlots собирает
BUSY отдельно и добавляет в ответ только в ветке без покрытия — в solver
(«Подобрать покрытие») занятые слоты по-прежнему не попадают.
2026-06-15 16:45:14 +03:00
emelianov 1790192e06 Проверка на пересечение ЛВ Земли при расчете ПУУД 2026-06-15 16:44:51 +03:00
emelianov f49709d544 Расчет с выравниванием СДИ 2026-06-15 16:05:45 +03:00
emelianov 88fb380be4 Контур по параметрам съемочного устройства 2026-06-15 15:38:09 +03:00
emelianov 60ddec0928 fix в задании азимута 2026-06-15 15:11:20 +03:00
Дмитрий Соловьев bffb8e47b7 fix(tgu-ui): двуручейный слайдер — выбор ползунка по направлению при наложении
При наложении в крайней точке хват попадал на верхний ползунок to, который на
правом краю заперт fromIndex и не уходит влево, а нижний from был недоступен.
Теперь при fromIndex === toIndex управляемый ползунок выбирается по направлению
движения (влево → from, вправо → to). Чинит и «Сутки» (SlotDaySelector), и
«Витки» (MapPassSelector).
2026-06-15 14:38:34 +03:00
Дмитрий Соловьев 33b56ba951 feat(slots): снятие брони пачками с прогрессом (симметрично бронированию)
Бэк (slots-service):
- DELETE /booking/batch (cancelReqSlots) — снятие выбранных броней пачкой;
  одиночный DELETE теперь request-aware (нужен requestId), чтобы шаренный
  между заявками слот рвал только связь своей заявки, а не сносил бронь.
- BookedSlotViewDTO (+toViewDTO) с cycle БРОНИ — slotKey совпадает с ответом
  POST booking/request; GET booking/by-request отдаёт View.

Фронт (pcp-tgu-ui-service):
- runChunked + ChunkProgress: бронь и снятие идут пачками по 200 с общим
  прогресс-баром (стиль/позиция как у оверлея «Расчёт слотов…», сверху).
- «Снять выбранные», «Снять всё» и ✕ в строке — единый чанковый движок
  runCancel (а не bulk-запрос), брони слиты в строки таблицы и выбираемы.

Тесты: SlotServiceCancelTest (шаринг/единоличная/cycle-регрессия), runChunked,
slotsApi.cancelBookedSlots/fetchBookedSlotsByRequest.
2026-06-15 14:26:06 +03:00
emelianov 29b8206867 Контур для ПУУД 2026-06-15 12:49:45 +03:00
emelianov 7fdac8c71e Прототип страницы расчета ПУУД 2026-06-15 12:19:53 +03:00
emelianov 07ba650e03 Прототип страницы расчета ПУУД 2026-06-15 11:58:49 +03:00
Дмитрий Соловьев b9adbce207 style(design): FINDING-003 — занятый слот приглушённо-красным бейджем (статусы сканируются) 2026-06-15 11:45:51 +03:00
Дмитрий Соловьев 1c9cdf4ad2 style(design): FINDING-002 — заголовки таблицы слотов на --text-muted (контраст AA) 2026-06-15 11:43:36 +03:00
Дмитрий Соловьев 6db196066d style(design): FINDING-001 — числовые колонки слотов (Длит./Крен) по правому краю + tabular-nums 2026-06-15 11:43:00 +03:00
Дмитрий Соловьев 7f9cd34ae9 build(tgu-ui): lockfile для @tanstack/react-virtual; игнорировать requests.json (скретч) 2026-06-15 11:35:16 +03:00
Дмитрий Соловьев a5f3f0e375 fix(tgu-ui): таблица слотов — слить виток/цикл, секунды в начале, длительность
По замечаниям: Крен и Статус не помещались (8 колонок на узкую панель).
- «Виток» теперь = виток / ветвь / цикл (281 / восх / 1); отдельная «Слот/цикл» убрана
- «Начало» с секундами (formatLocalDateTimeSeconds) — слоты короткие, без секунд начало=конец
- «Конец» заменён на «Длит., с» (slotDurationSec); colSpan распорок 8→7
- Крен и Статус снова видны

Тесты 70/70, build чисто.
2026-06-15 11:10:49 +03:00
emelianov 3ab5b8860f Merge remote-tracking branch 'origin/dev' into dev 2026-06-15 10:13:33 +03:00
emelianov ce32a03072 Прототип страницы расчета ПУУД 2026-06-15 10:13:27 +03:00
Дмитрий Соловьев c64222a90d feat(tgu-ui): бронирование слотов — виртуализация, автоподбор покрытия, эргономичный мультивыбор
Вкладка «Слоты» масштабирована под ~20k слотов/мес без торможения:
- wktCache: контур слота парсится один раз (кэш по slotKey), не на каждый ререндер сцены
- виртуализация таблицы (@tanstack/react-virtual): в DOM только видимое окно строк
- автоподбор покрытия: проброс coverageStrategy (GREEDY/CONTINUOUS) в request-cover,
  результат — преднабор брони (solver не дублируется, используется бэкендный)
- мультивыбор: Shift-диапазон по отсортированному списку, «все сутки»/«видимые»,
  счётчик охвата выбора
- бронь крупных наборов чанками (по 200) + подтверждение выше 500 + прогресс
- отмена расчёта (AbortController), мягкая подсказка перегруза карты
- чистая логика выбора/чанкинга вынесена в slotSelection.ts + юнит-тесты

Тесты: 70/70 (17 новых). tsc -b и vite build чисто.
2026-06-11 17:09:58 +03:00
Дмитрий Соловьев 345529cde0 chore: сохранение текущих изменений (deploy local-bundle/local-jar, request-service, slots UI markedObjectIds)
Безопасный коммит незакоммиченной работы перед реализацией бронирования слотов.
Вне коммита оставлены: package-lock.json (пустой, мусор), requests.json (scratch-данные).
2026-06-11 14:00:12 +03:00
Дмитрий Соловьев 6689351ef0 feat(tgu-ui): вкладка «Слоты» — расчёт покрытия и бронирование слотов заявки
- новая вкладка: заявки интервала на карте, выбор заявки кликом/инспектором,
  расчёт слотов покрытия, бронирование и снятие брони
- выбор заявки без выпадающего списка (не масштабируется на ~10к): все заявки
  на карте, панель справа с кнопкой «Выбрать», имя выбранной заявки в тулбаре,
  кнопка «Сброс», фильтр заявок по интервалу
- бронь отмечаем по ответу POST booking/request (by-request отдаёт слот в чужом
  cycle-фрейме — ключ не совпадал, бейдж «бронь» не появлялся)
- подсветка и автоскролл активной строки по клику на слот (ручной scrollBy)
- меню выбора при плотном наложении слотов (SlotPickMenu); контур заявки
  pickable:false, чтобы не «съедать» меню; панель не закрывается при выборе
- фильтр отображения по суткам (SlotDaySelector)
- gateway: маршрут slots (/api/pcp-slots/**)
- карточка полосы обзора (swath): КА и виток в инспекторе
2026-06-11 12:20:28 +03:00
Дмитрий Соловьев 802c966347 fix(tgu-ui): подхватывать существующий черновик вместо ошибки «Conflict» при добавлении съёмки
При первой правке плана ensureDraft→createDraft(replace) падал 409, если по КА
уже есть открытый черновик на это окно (осиротевший с прошлой сессии — авто-отмена
best-effort). В UI это показывалось голым «Conflict» (на стенде не подхвачен
include-message у tgu).

Теперь на 409 от createDraft редактор подхватывает существующий черновик того же
КА с тем же окном (adoptExistingDraft через fetchDraftPlans, сверка окна ±2 c) и
продолжает в нём; если подходящего нет — читаемое сообщение со ссылкой на вкладку
«Планы» вместо «Conflict».
2026-06-10 16:13:59 +03:00
Дмитрий Соловьев 7202f7cb02 refactor(tgu-ui): единый инспектор объектов карты (MapObjectInspector) на вкладках «Карта» и «Комплексный план»
Обобщил ComplexInfoPanel в общий MapObjectInspector (tgu-map-2d): карточки для
всех типов объектов — заявка, включение комплексного плана, ячейка тепловой карты,
маршрут planWorks, станция, маркер КА, линия; список с раскрытием при наложении.

Вкладка «Карта» переведена на enableObjectChooser + onObjectsAtPoint + правый
инспектор — заменила разрозненные Tgu2DMapRequestsPanel/Tgu2DMapStationPanel (удалены)
и объектную часть нижней плашки (Tgu2DMapDetails ужат до контекста плана). Вкладка
«Комплексный план» использует тот же инспектор.

RequestAtPoint переехал в tgu-requests/RequestDetailsPanel (нужен вкладке «Заявки»).
2026-06-10 15:58:55 +03:00
Дмитрий Соловьев bdbc874f41 feat(tgu-ui): тепловая карта приоритетов и инспектор объектов на вкладке «Комплексный план»
Чекбокс «Тепловая карта» — фоновый слой-заливка ячеек сетки заданий по важности
(cool→hot), источник GET /api/pcp-request/v1/cells/priority-map (cellsApi + drawHeatmap).
Heatmap — полноценный слой MapPolygon (layer "heatmap", importance/cellNum), участвует
в spatial-индексе и chooser, рисуется под контурами плана/заявок.

Клик по объекту открывает правый инспектор ComplexInfoPanel (по аналогии с редактором):
карточки ячейки приоритета, включения комплексного плана и заявки; при наложении —
список объектов под точкой клика с раскрытием. При включённой тепловой карте ячейка
всегда идёт первой в списке и раскрыта по умолчанию.

Бэклог #44 отмечен сделанным.
2026-06-10 15:47:18 +03:00
Дмитрий Соловьев 11380fced5 fix(tgu-ui): гасить «Создать черновик» для стартовавшего плана (replace→422)
Кнопка предлагала replace-черновик для уже стартовавшего плана, хотя бэк
(CreateDraftUseCase.createReplaceDraft) возвращает 422 «окно выдачи заморожено».
Гард canCreateDraftFromPlan теперь требует startInFuture (зеркалит редактор);
для стартовавших eligible-планов вместо кнопки — amber-подсказка про fork-forward.
2026-06-10 15:46:57 +03:00
Дмитрий Соловьев 3765efb4fe feat(ui): перевести фронт с pcp-ui-service на источники, снять gateway catch-all
Запросы tguApi.ts (platforms/plans/decision/dismiss/restore/confirm-layin)
и flight-line переведены с прокси /api/tgu-planning через умирающий
pcp-ui-service на прямые вызовы pcp-tgu-service (/api/pcp-tgu, decision и
confirm-layin — на тест-контроллер /test/tgu/*) и pcp-ballistics-service.
flight-line перенесён в ballisticsApi.ts. editorApi.ts modes переведён с
/api/current-plans на /api/pcp-mission. UX-перевод ошибок решения уже жил во
фронте (errorMessage в tguApi.ts), серверная обвязка ui-service дублировала.

Из config-repo/pcp-gateway-service.yaml снят маршрут ui-catch-all: не-матчнутый
/api/** теперь отдаёт 404 на gateway, а не уходит в pcp-ui-service.

Шаг 8 (вывод сервиса из эксплуатации: compose/helm/CI/реестр + удаление кода)
отложен до проверки репойнта на живом стенде; сервис пока задеплоен без
маршрутов. См. docs/план-перевода-с-pcp-ui-service.md и задачу #40 бэклога.
2026-06-10 14:47:05 +03:00
Дмитрий Соловьев 3c4ebcd7d3 refactor(cors): централизовать CORS на gateway, убрать per-service из pcp-ui-service
CORS-политика (allowedOriginPatterns:* + allowCredentials) переезжает в единый
globalcors на pcp-gateway-service. После сворачивания фронта на gateway браузер
ходит к бэкендам только через него (same-origin via Vite/nginx), поэтому
per-service CORS в pcp-ui-service/WebConfig.kt стал мёртвым грузом. globalcors
оставлен как страховка от cross-origin напрямую к gateway.
2026-06-10 14:04:29 +03:00
Дмитрий Соловьев ab3a787da5 feat(gateway): сервис pcp-gateway-service + сворачивание маршрутизации фронта на него
- новый Spring Cloud Gateway (WebFlux): доменные маршруты /api/pcp-<x>/**
  со StripPrefix=2, /api/stations без среза пути, catch-all /api/** → ui-service;
  опциональная JWT-валидация на edge (gateway.security.jwt-enabled, по умолчанию off)
- config-repo: pcp-gateway-service.yaml (маршруты) + порт/адрес gateway в реестрах
  application-{local,docker-local,dev}
- build: репозитории переведены на mavenCentral (nstart-proxy закомментирован),
  включены mavenLocal/gradlePluginPortal; settings: include модуля
- pcp-tgu-ui-service: vite-proxy и nginx.conf свёрнуты на единый /api → gateway
  (вместо набора per-service правил)
- deploy: сервис gateway в docker-compose; helm-чарт pcp-gateway-service
- CI: .gitlab/ci/pcp-gateway-service.yml + проводка в .gitlab-ci.yml
2026-06-10 13:34:16 +03:00
Дмитрий Соловьев f292291e04 Удаление старого pcp-tgu-ops-ui: заменён на pcp-tgu-ui-service 2026-06-09 14:00:24 +03:00
Дмитрий Соловьев 505bf1f31c Новый сервис pcp-tgu-ui-service: ТГУ-фронт на headless-auth nstart + платформенный CI/деплой 2026-06-09 14:00:24 +03:00
Дмитрий Соловьев 1a0348cdeb merge: влить dev (ПУУД, angular-motion-lib, fix requests) в tgu-ops-ui 2026-06-08 14:25:29 +03:00
Дмитрий Соловьев 5fa3ceaac9 feat(группировка): реальная съёмка/сброс/связь и заполнение борта
Дашборд «Группировка» наполняется из плана: режимы SURVEY/DROP → интервалы
съёмки и сброса с контуром и станцией, окна ЗРВ выделены в отдельную «связь»
(раньше показывались как сброс). Заполнение бортового накопителя считается
из объёмов маршрутов (volumeMb) с модельной ёмкостью 500 ГБ
(ONBOARD_CAPACITY_MB) — memAt по таймлайну, подсветка контура/линии сброса
на карте.
2026-06-08 14:00:03 +03:00
Дмитрий Соловьев 2c8b317c42 fix(editor): зажим крена маршрута к ±45°
Бэкенд считает геометрию видимости/маршрута только в |крен| ≤ 45°,
поэтому предел снижен с 89° до 45°. Введён общий clampRoll (зажим +
округление до 0.1°), применён при ручной правке крена (кнопки ±,
прямой ввод) и при загрузке сохранённого маршрута в окно построения
(легаси-маршрут вне ±45° зажимается).
2026-06-08 13:59:53 +03:00