fix(render): a dense trace is drawn one column at a time, not as a polyline
An LOD envelope staged as a polyline moirés. level_for() sizes a bucket at one to two pixel columns and Envelope emits two points per bucket, so a column carries three or four near-vertical hairlines at as many sub-pixel phases; under src-alpha compositing its brightness is then a non-linear function of those phases, the pattern repeats at the beat between the bucket pitch and the pixel pitch, and a pan sweeps the beat so the banding crawls. draw_traces now reduces such a window onto the pixel grid: one exactly vertical segment per integer column of the axes, from the lowest to the highest screen y any gathered point put in it, flushed in framebuffer pixels with the snap on. One phase for the whole trace, so there is nothing left to beat -- and the geometry becomes O(axes.w) rather than O(buckets). Gated on the gathered density rather than on the level (the raw path beats the same way), and on Envelope alone. A hole stays a hole, disjoint neighbours are joined so a fast edge keeps it, and a span under the stroke is drawn as the stroke since the shader caps nothing. It is the one carve-out in u_snap's data/chrome rule: a column is a pixel column, and the y bounds it reports are untouched. Measured by the new test as the number of distinct coverage levels in the ink -- 4 against the polyline's 126, with 627 segments against 60 054. A count of partially covered pixels was tried first and separates nothing (577 against 652): a 1.5 px stroke's fringe always spills into the next column. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
bee318870f
commit
e81e84645f
5 files changed
+301
-3
No files matched your search
@@ -37,6 +37,12 @@ run touched a GPU, so read it as an upper bound and a record of the software pat
|
||||
window's worth, the scroll offset is bounded by `retained - span`, so a pan or a zoom-in near an
|
||||
edge cannot leave the window's own span over data the scope never had (a window *wider* than the
|
||||
data keeps the older placement -- right edge on the newest sample);
|
||||
- a trace whose gathered window is denser than the axis is reduced **onto the pixel grid** --
|
||||
one snapped vertical segment per integer column, lit from that column's own extremes --
|
||||
because an LOD envelope staged as a polyline puts three or four near-vertical hairlines per
|
||||
column at as many sub-pixel phases, and the beat between the bucket pitch and the pixel pitch
|
||||
is a crawling moiré; one segment per column leaves one phase, so there is nothing to beat
|
||||
(`FrameStats::column_traces`, and `docs/data-and-performance.md` for the four rules it keeps);
|
||||
- sample **markers** when a window is sparse enough that its samples are the shape
|
||||
(`Style::marker_below_samples`, 50 by default, `marker_px` across, in the trace's own colour);
|
||||
- grid with independent major/minor line classes (`Style::grid_major_visible`,
|
||||
|
||||
Reference in new issue
Block a user