mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-08 19:42:05 +00:00
M8: dots on the 1/65536 px rounding step stay put too
Review of #1796: rounding a mark's position to 1/65536 px with `round` sent the halves of that step away from zero, the asymmetry the PR set out to remove, one step further down. At a step of 25.5 - 2^-17 px, a pan by 26 pixels put the first mark a pixel off a full render. Both roundings now go half up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e39e563408
commit
c8f34acc59
2 files changed
+28
-5
No files matched your search
@@ -92,13 +92,14 @@ pub(crate) fn draw(pix: &mut Pixmap, view: &View, d: &Dots) {
|
||||
}
|
||||
}
|
||||
|
||||
/// The device pixel nearest `p` pixels from the view's top-left. A mark halfway between two pixels
|
||||
/// goes to the right (or lower) one on either side of the origin, and `p` is first rounded to
|
||||
/// 1/65536 px: a view a whole number of pixels off (a pan, a band, a patch) reaches it with another
|
||||
/// rounding error, and would otherwise put the marks that fall halfway on the other pixel.
|
||||
/// The first device pixel of a mark whose edge is `p` pixels from the view's top-left: the one
|
||||
/// whose left (or top) edge is nearest, and the right (or lower) one when two are as near. `p` is
|
||||
/// first rounded to 1/65536 px, halves up as well: a view a whole number of pixels off (a pan, a
|
||||
/// band, a patch) reaches it with another rounding error, and, rounded either way, would put the
|
||||
/// marks that fall halfway on the other pixel.
|
||||
fn nearest_px(p: f64) -> f64 {
|
||||
const STEPS: f64 = 65_536.0;
|
||||
((p * STEPS).round() / STEPS + 0.5).floor()
|
||||
((p * STEPS + 0.5).floor() / STEPS + 0.5).floor()
|
||||
}
|
||||
|
||||
/// Which line covers each device pixel along an axis: 0 none, 1 a faded one, 2 a strong one.
|
||||
|
||||
@@ -158,3 +158,25 @@ fn dots_halfway_between_pixels_stay_put() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A mark that rounds to a half step of 1/65536 px goes the same way on both sides of a view's
|
||||
/// origin too: at a step of 25.5 − 2⁻¹⁷ px, the first mark is where 1/65536 px rounds up.
|
||||
#[test]
|
||||
fn dots_on_the_rounding_step_stay_put() {
|
||||
let (d, page) = page_with_square();
|
||||
let step = 25.5 - 2f64.powi(-17);
|
||||
for lines in [false, true] {
|
||||
let opts = Options { dots: Some(Dots { step, lines, ..dots() }), ..Default::default() };
|
||||
let full = View { origin: (0.0, 0.0), scale: 1.0, width: 300, height: 200 };
|
||||
let a = render_view_single(&d, page, &full, &opts).unwrap();
|
||||
for pan in 1..60u32 {
|
||||
let v = View { origin: (f64::from(pan), f64::from(pan)), scale: 1.0, width: 200, height: 120 };
|
||||
let b = render_view_single(&d, page, &v, &opts).unwrap();
|
||||
for y in 0..120 {
|
||||
for x in 0..200 {
|
||||
assert_eq!(rgba(&b, x, y), rgba(&a, x + pan, y + pan), "lines {lines}, a pan by {pan}, at {x}, {y}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user