# Общая работа с графиками Android и SETGUI Численная логика находится в `include/set_plot.h` и `src/set_plot.c`. Это модуль C99 без Qt, Android, транспорта, динамической памяти и глобального состояния. Он собирается в существующую библиотеку SETProtocol; отдельная DLL для графиков не требуется. Версия ABI графиков — `set_plot_abi_version() == 1`; новые операции добавляются без изменения существующих значений и сигнатур. | Общее в templates | Адаптер приложения | |---|---| | Нормализованная область просмотра, масштаб 1…128, ограничение панорамирования | Размер поля и отступы в пикселях | | Независимый масштаб X/Y с сохранением координаты под пальцами | События Compose или Qt, колесо, кнопки | | Выбор преобладающей оси по изменению расстояния между пальцами | Накопление движения до порога; фиксация выбранной оси до конца жеста | | Перевод значения в долю экрана и обратно, инверсия Y | Canvas/QPainter и оформление шкал | | Перемещение маркера от начальной координаты, ограничение видимой областью | Захват линии пальцем/мышью, редактор положения | | Разность B−A, D−C и множитель единиц, шаги шкалы 1/2/5 | Подписи, цвета, миллисекунды/герцы/единицы сигнала | | Проверка абсолютных границ X/Y для фиксации осей | Диалог ввода и хранение отдельных границ времени/FFT | | Модели маркеров и их размещение в Kotlin/Python-портах | Жизненный цикл экрана, очистка и выбор источника | Модель маркеров: A/B — координаты X и вертикальные линии во всю высоту поля; C/D — координаты Y и горизонтальные линии. Они могут пересекаться: отрицательная разность сохраняется. Начальные координаты — 1/3 и 2/3 диапазона. При изменении масштаба уже установленные координаты сохраняются. «Маркеры в видимую область» заново размещает их. Координаты и область просмотра времени/спектра независимы. `set_plot_eval()` принимает операцию из `enum set_plot_operation`, точное число входных `double` и буфер вывода. Контракт каждой операции указан в заголовке. Возвращает число записанных элементов, 0 — неправильные аргументы. Некорректный коэффициент масштабирования оставляет корректный viewport неизменным. NaN/Inf и вырожденные диапазоны не передаются дальше в отрисовку. FRACTION/VALUE не обрезают координаты: это позволяет правильно отсекать линии по границе поля, а не создавать ложные горизонтальные участки на его краю. DRAG, напротив, ограничивает положение маркера видимым диапазоном. ## Порты - Android/JVM: `ports/android/kotlin/ru/setcorp/setprotocol/trends/NativePlot.kt`, `PlotViewport.kt`, `TrendMarkers.kt`; тонкий JNI — `ports/android/set_plot_jni.c`. Android использует `System.loadLibrary("setprotocol")`. Для JVM-тестов можно передать абсолютный путь DLL/SO системным свойством `setplot.library`. - Python: `python/protocan/plot.py`: `PlotMath(library)`, `Viewport`, `Bounds`, `Markers`. Приложение передаёт уже загруженную SETProtocol `ctypes.CDLL`. Зависимости — стандартная библиотека; Qt в этот модуль не импортируется. Новые изменения не должны добавлять вторую реализацию численных операций в Kotlin/Python или в приложение. Состояние и адаптация событий остаются в портах. Добавление операции требует обновления C ABI, обоих портов и общих эталонов. ## Интеграция приложений Android: `TrendGraph` использует общие viewport, bounds и маркеры, а Compose рисует линии и панель. При измерениях время отображается в миллисекундах от начала выбранного участка; сохранённые X-координаты включают абсолютное начало. SETGUI: `ui/plot_interaction.py` адаптирует общий модуль к Qt. Его используют `SignalPlot` (ТМС и датчики), `TrendPlot` (логи) и `SpectrumPlot`. Колесо по вертикали масштабирует Y, Shift+колесо и горизонтальное колесо — X; сенсорный pinch выбирает ось по движению. Временные графики хранят метку приёма каждого отсчёта. Пропущенные значения не растягивают остальные серии: все сигналы имеют единую шкалу времени. При повторном построении ТМС из журнала используются исходные метки приёма. Дискретные дорожки имеют общую X-шкалу, а маркеры уровня Y относятся к аналоговому полю. Расчёт FFT не является частью этого модуля. Android и SETGUI вычисляют спектр через `set_spectrum.c`; там же находится общий поиск доминирующего узкополосного пика, а трёхсекундный таймер его отображения остаётся состоянием GUI. Вкладка спектра SETGUI получает готовые уровни в дБмВ от прибора. Общая интерактивная часть не меняет эти данные или единицы. ## Проверка и сборка - CMake/CTest: `shared_plot` проверяет ABI, размеры буферов и координаты. - `tests/fixtures/plot-v1.json` содержит общие численные эталоны. Их читают `PlotContractTest` (фактический JNI) и `python/tests/test_plot.py` (ctypes). - Host DLL/SO для Python: `python tools/build_host.py --output <путь>`. - Для JVM: та же команда с `--java-home ` добавляет JNI-порт графиков. Нужен C-компилятор (MSVC на Windows, cc/clang/gcc на Unix) и JDK с `jni.h`. - Android-проект автоматически собирает host-библиотеку перед JVM-тестами; интерпретатор Python можно задать свойством Gradle `setflash.python`. - SETGUI проверяет события мыши, колеса и двух пальцев через QtTest без физического прибора; численные тесты не требуют GUI. Исходники должны приходить из одного коммита подмодуля `templates` в обоих проектах. Локальная замена файлов без обновления gitlink не закрепляет версию.