fix(plot,glfw): layer the crosshair under the handles, sync it across a figure, and harden the lookup

This commit is contained in:
Martino Ferrari committed 2026-09-28 19:22:29 +02:00
1 parent 8e27e22ebe
commit 29824b6919
5 files changed
+183 -63

No files matched your search

+19 -9
View File
@@ -1162,23 +1162,33 @@ CrosshairSpan crosshair_span(const data::Series& series, f64 x) noexcept {
if (x < x0 || x > newest) return span;
// Index arithmetic, not a search: the grid is uniform, so the sample at or before `x` is
// `floor((x - x0) / dx)` and there is nothing to look up. Two special cases keep the span
// honest at the ends and under rounding -- an index past the last sample collapses onto
// it, and a `t` that rounds up to 1.0 (a query one ulp above a sample) collapses onto the
// sample it has reached rather than reporting an interpolation of width zero.
// `floor((x - x0) / dx)` and there is nothing to look up. The two bounds are checked
// *before* the cast, which is also what keeps it defined: `index` is a quotient of two
// caller-supplied doubles and can overflow to infinity for an extreme origin and spacing,
// and casting that to `u64` is undefined. `!(index > 0.0)` is the NaN test as well.
const f64 index = (x - x0) / dx;
const u64 i = index <= 0.0 ? 0u : static_cast<u64>(std::floor(index));
if (i >= n - 1u) {
span.begin = span.end = n - 1u;
if (!(index > 0.0)) {
span.begin = span.end = 0u; // the oldest sample, or a rounding step below it
span.t = 0.0;
span.valid = true;
return span;
}
if (index >= static_cast<f64>(n - 1u)) {
span.begin = span.end = n - 1u; // the newest sample, or a step past it
span.t = 0.0;
span.valid = true;
return span;
}
// `index` is finite and inside `(0, n-1)`, so truncating it is a floor on a value a `u64`
// holds. Two rounding cases keep the span honest at a sample: a `t` that lands on 0 is the
// query sitting *on* sample `i`, and one that rounds up to 1.0 is it sitting on the sample
// after it -- neither is an interpolation with no width.
const u64 i = static_cast<u64>(index);
const f64 t = index - static_cast<f64>(i);
if (!(t > 0.0)) {
span.begin = span.end = i; // exactly on sample `i`
span.begin = span.end = i;
} else if (t >= 1.0) {
span.begin = span.end = i + 1u; // exactly on the sample after it
span.begin = span.end = i + 1u;
} else {
span.begin = i;
span.end = i + 1u;