fix(data): the gather origin is the caller's, so a deep zoom draws on the sample
`Series::gather()` stages x as f32 relative to `x0()` -- the start of the *retained window* -- so the value's ULP was a fraction of data the view need not even hold: 1.9 us over a 20 s ring. A readout quotes `x_at()` in exact f64, so at a 10 us view across 700 px that put more than a hundred pixels between where a sample is drawn and the x reported for it. The origin is now a parameter, placed before `out_xy` so every call site is a type error rather than a silent change of behaviour. `Renderer::draw_traces` passes the visible range's minimum, which makes the error a fixed 2^-24 of the span on screen -- 4e-5 of a pixel over a 700 px axis -- at every zoom. `stage_xy()` loses its second origin as a consequence: the gather origin and the draw origin are now always the same value, so the linear case hands the gathered buffer straight to `add_polyline_xy()` with no per-point copy. `Plot::crosshair_point()` names the query itself, the one origin that cannot lose precision for a caller that might. Guarded by `a_gather_origin_at_the_view_keeps_a_deep_zoom_on_the_sample_it_quotes`, which measures the error in pixels both ways: under 0.05 px with the view's minimum, over 10 px with `x0()`.
This commit is contained in:
1 parent
59c2e45af7
commit
c2c8c596f3
15 files changed
+150
-95
No files matched your search
@@ -52,7 +52,8 @@ PLOT_TEST(xy_series_reports_its_own_grid) {
|
||||
PLOT_CHECK_NEAR(s.y_bounds().max, 48.0, 1e-6);
|
||||
|
||||
// Epoch-style offset: the same shape shifted by 1.7e9 keeps exact bounds, and
|
||||
// gather() emits x relative to x0() -- small numbers, not quantised epochs.
|
||||
// gather() emits x relative to the origin the caller names -- x0() here, so
|
||||
// small numbers, not quantised epochs.
|
||||
std::vector<f64> epoch = spread_x(500);
|
||||
const std::vector<f64> es = epoch; // un-moved copy for the expectations
|
||||
for (auto& v : epoch) v += 1.7e9;
|
||||
@@ -60,7 +61,7 @@ PLOT_TEST(xy_series_reports_its_own_grid) {
|
||||
PLOT_CHECK_NEAR(e.x_bounds().min, 1.7e9, 1e-3);
|
||||
PLOT_CHECK_NEAR(e.x_bounds().max, 1.7e9 + (xs.back() - xs.front()), 1e-3);
|
||||
std::vector<f32> out;
|
||||
e.gather(0, 0, 500, out);
|
||||
e.gather(0, 0, 500, e.x0(), out);
|
||||
PLOT_CHECK(out.size() == 1000);
|
||||
// x is relative to x0(): x_at(i) - x0(), the array's own offsets -- small
|
||||
// values even though the absolute epoch is 1.7e9. The expectations come from
|
||||
@@ -186,7 +187,7 @@ PLOT_TEST(xy_series_gather_envelope_matches_exact_reduces) {
|
||||
const u64 span = u64{kBucket} << level;
|
||||
const u64 b = 500 + 33, e = 3500 - 57; // unaligned on the bucket grid
|
||||
std::vector<f32> out;
|
||||
s.gather(level, b, e, out, plot::data::GatherMode::Envelope);
|
||||
s.gather(level, b, e, s.x0(), out, plot::data::GatherMode::Envelope);
|
||||
PLOT_CHECK(out.size() >= 8u);
|
||||
// Emitted x stays inside [x_at(begin), x_at(end)) and the geometry reaches
|
||||
// both the range's extremes (the lead/trail raw spans carry them).
|
||||
|
||||
Reference in new issue
Block a user