Files
templates/c/set-protocol/src/set_plot.c

80 lines
3.1 KiB
C

#include "set_plot.h"
#include <math.h>
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] < 1.0/128 || v[2] > 1 ||
v[3] < 1.0/128 || v[3] > 1 || v[0] < 0 || v[1] < 0 ||
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], 1.0/128, 1);
h = clamp(v[3] / v[5], 1.0/128, 1);
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;
}