Files
templates/c/set-protocol/src/set_plot.c
Andrey a5e46d4627 Расширить обмен по шинам, CAN-адаптеры и обработку графиков
Добавить очереди операций PBUS/SBUS, общую консоль, настройки Candle и SLCAN, декодеры DSView и обработку плотных графиков. Обновить протокол Бальзам и проверки общих компонентов.
2026-10-17 14:36:14 +03:00

88 lines
4.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Математика взаимодействия с графиком: области просмотра, масштабирование, перемещение и
* координатные преобразования. Расчёты общие для JNI и ctypes; цвета, события GUI и рисование
* остаются в приложении.
*/
#include "set_plot.h"
#include <math.h>
#define MIN_VIEW_SPAN 1e-12 /* Минимальная безразмерная доля полного диапазона по X и Y задаёт увеличение до 10^12 раз; запас относительно точности double сохраняет различимые границы нормированной области. */
static double clamp(double v, double lo, double hi) { return fmin(hi, fmax(lo, v)); }
static int finite_values(const double *v, size_t n) {
size_t i;
for (i = 0; i < n; ++i) if (!isfinite(v[i])) return 0;
return 1;
}
uint32_t set_plot_abi_version(void) { return 1U; }
size_t set_plot_eval(uint32_t op, const double *v, size_t n, double *out, size_t cap) {
static const size_t sizes[] = {10, 3, 4, 4, 6, 2, 3, 2, 4};
double span, fraction;
if (op > SET_PLOT_LIMITS || !v || !out || n != sizes[op] ||
cap < (op == SET_PLOT_TRANSFORM || op == SET_PLOT_LIMITS ? 4U : 1U)) return 0;
if (op == SET_PLOT_TRANSFORM) {
double w, h, fx, fy;
if (!finite_values(v, 4) || v[2] < MIN_VIEW_SPAN || v[2] > 1 || /* Проверяем конечность смещений и размеров, разрешая ширину до триллионной доли исходного диапазона X. */
v[3] < MIN_VIEW_SPAN || v[3] > 1 || v[0] < 0 || v[1] < 0 || /* Такой же предел для Y сохраняет возможность дальнейшего перемещения и увеличения уже приближённой области. */
v[0] + v[2] > 1.000000000001 || v[1] + v[3] > 1.000000000001) return 0;
out[0] = v[0]; out[1] = v[1]; out[2] = v[2]; out[3] = v[3];
if (!finite_values(v + 4, 6) || v[4] <= 0 || v[5] <= 0) return 4;
w = clamp(v[2] / v[4], MIN_VIEW_SPAN, 1); /* Делим текущую долю X на положительный коэффициент приближения; ограничиваем результат между новым пределом и полным диапазоном. */
h = clamp(v[3] / v[5], MIN_VIEW_SPAN, 1); /* Аналогично масштабируем Y, снимая прежнее ограничение 128 раз и сохраняя ненулевую высоту для координатных преобразований. */
fx = clamp(v[8], 0, 1); fy = clamp(v[9], 0, 1);
out[0] = clamp(v[0] + (v[2] - w) * fx - v[6] * w, 0, 1 - w);
out[1] = clamp(v[1] + (v[3] - h) * fy - v[7] * h, 0, 1 - h);
out[2] = w; out[3] = h;
return 4;
}
if (!finite_values(v, n)) return 0;
switch (op) {
case SET_PLOT_AXIS:
if (v[2] < 0) return 0;
out[0] = fmax(fabs(v[0]), fabs(v[1])) <= v[2] ? 0 :
(fabs(v[1]) > fabs(v[0]) ? 2 : 1);
break;
case SET_PLOT_FRACTION:
case SET_PLOT_VALUE:
span = v[2] - v[1];
if (!isfinite(span) || span <= 0 || (v[3] != 0 && v[3] != 1)) return 0;
if (op == SET_PLOT_FRACTION) {
fraction = (v[0] - v[1]) / span;
out[0] = v[3] ? 1 - fraction : fraction;
} else {
fraction = v[3] ? 1 - v[0] : v[0];
out[0] = v[1] + fraction * span;
}
break;
case SET_PLOT_DRAG:
span = v[4] - v[3];
if (!isfinite(span) || span <= 0 || v[2] <= 0 || (v[5] != 0 && v[5] != 1)) return 0;
out[0] = clamp(v[0] + (v[5] ? -1 : 1) * (v[1] / v[2]) * span, v[3], v[4]);
break;
case SET_PLOT_TICK_STEP: {
double raw, magnitude, scaled;
if (v[0] <= 0 || v[1] <= 0) return 0;
raw = v[0] / fmax(2, floor(v[1] / 100));
magnitude = pow(10, floor(log10(raw)));
if (magnitude <= 0 || !isfinite(magnitude)) return 0;
scaled = raw / magnitude;
out[0] = (scaled <= 1 ? 1 : scaled <= 2 ? 2 : scaled <= 5 ? 5 : 10) * magnitude;
break;
}
case SET_PLOT_DELTA: out[0] = (v[1] - v[0]) * v[2]; break;
case SET_PLOT_DB_DELTA:
if (v[0] == 0 || v[1] == 0) return 0;
out[0] = 20 * log10(fabs(v[1] / v[0]));
break;
case SET_PLOT_LIMITS:
if (v[0] >= v[1] || v[2] >= v[3]) return 0;
out[0] = v[0]; out[1] = v[1]; out[2] = v[2]; out[3] = v[3];
return 4;
default: return 0;
}
return isfinite(out[0]) ? 1 : 0;
}