use rizzma::Figure;
fn pixel(r: &rizzma::skia::SkiaRenderer, x: u32, y: u32) -> [u8; 4] {
let p = r.pixmap().pixel(x, y).expect("pixel in bounds");
[p.red(), p.green(), p.blue(), p.alpha()]
}
fn ink_in(r: &rizzma::skia::SkiaRenderer, x0: u32, x1: u32, y0: u32, y1: u32) -> usize {
let mut n = 0;
for y in y0..y1 {
for x in x0..x1 {
if pixel(r, x, y) != [255, 255, 255, 255] {
n += 1;
}
}
}
n
}
fn twin_figure() -> Figure {
let mut fig = Figure::new(4.0, 3.0);
let ax = fig.add_axes(0.15, 0.15, 0.70, 0.75);
ax.plot(&[0.0, 5.0, 10.0], &[0.0, 4.0, 2.0]);
ax.set_xlim(0.0, 10.0);
ax.set_ylim(0.0, 5.0);
let twin = fig.twinx(0);
let tw = &mut fig.axes_mut()[twin];
tw.plot(&[0.0, 5.0, 10.0], &[100.0, 900.0, 400.0]);
tw.set_ylim(0.0, 1000.0);
fig
}
#[test]
fn twin_shares_the_source_x_pixel_mapping() {
let fig = twin_figure();
for x in [0.0, 2.5, 5.0, 10.0] {
let (px_src, _) = fig.data_to_pixel(0, x, 1.0).expect("primary maps");
let (px_twin, _) = fig.data_to_pixel(1, x, 500.0).expect("twin maps");
assert!(
(px_src - px_twin).abs() < 1e-9,
"x = {x}: primary px {px_src} != twin px {px_twin}"
);
}
}
#[test]
fn twin_tracks_later_source_limit_changes() {
let mut fig = twin_figure();
fig.axes_mut()[0].set_xlim(2.0, 4.0);
let (px_src, _) = fig.data_to_pixel(0, 3.0, 1.0).expect("primary maps");
let (px_twin, _) = fig.data_to_pixel(1, 3.0, 500.0).expect("twin maps");
assert!(
(px_src - px_twin).abs() < 1e-9,
"after set_xlim: primary px {px_src} != twin px {px_twin}"
);
let (edge_src, _) = fig.data_to_pixel(0, 4.0, 1.0).unwrap();
let (far_twin, _) = fig.data_to_pixel(1, 10.0, 500.0).unwrap();
assert!(far_twin > edge_src, "twin x mapping must be the zoomed one");
}
#[test]
fn twin_keeps_an_independent_y_mapping() {
let fig = twin_figure();
let (_, py_src) = fig.data_to_pixel(0, 5.0, 2.5).unwrap();
let (_, py_twin) = fig.data_to_pixel(1, 5.0, 500.0).unwrap();
assert!(
(py_src - py_twin).abs() < 1e-9,
"mid-scale rows must coincide: {py_src} vs {py_twin}"
);
}
#[test]
fn twin_draws_y_decoration_on_the_right() {
let fig = twin_figure();
let r = fig.render();
let right_ink = ink_in(&r, 345, 400, 30, 255);
assert!(
right_ink > 20,
"expected right-hand y tick labels, got {right_ink} ink px"
);
}
#[test]
fn secondary_xaxis_decorates_the_top_edge() {
let mut plain = Figure::new(4.0, 3.0);
let ax = plain.add_axes(0.15, 0.18, 0.70, 0.60);
ax.plot(&[0.0, 1.0, 2.0], &[0.0, 1.0, 0.0]);
let baseline = plain.render();
let mut fig = Figure::new(4.0, 3.0);
let ax = fig.add_axes(0.15, 0.18, 0.70, 0.60);
ax.plot(&[0.0, 1.0, 2.0], &[0.0, 1.0, 0.0]);
ax.secondary_xaxis_linear(25.4, 0.0, Some("mm"));
let r = fig.render();
let with = ink_in(&r, 60, 340, 10, 64);
let without = ink_in(&baseline, 60, 340, 10, 64);
assert!(
with > without + 20,
"expected secondary-axis ink above the spine: {with} vs {without}"
);
}