RosettaCodeData/Task/Xiaolin-Wus-line-algorithm/Rust/xiaolin-wus-line-algorithm.rs

121 lines
3.4 KiB
Rust

use std::cmp;
fn wu_draw_line(
mut x0: f32,
mut y0: f32,
mut x1: f32,
mut y1: f32,
mut plot: impl FnMut(i32, i32, f32),
) {
let ipart = |x: f32| -> i32 { x.floor() as i32 };
let round = |x: f32| -> f32 { x.round() };
let fpart = |x: f32| -> f32 { x - x.floor() };
let rfpart = |x: f32| -> f32 { 1.0 - fpart(x) };
let steep = (y1 - y0).abs() > (x1 - x0).abs();
if steep {
std::mem::swap(&mut x0, &mut y0);
std::mem::swap(&mut x1, &mut y1);
}
if x0 > x1 {
std::mem::swap(&mut x0, &mut x1);
std::mem::swap(&mut y0, &mut y1);
}
let dx = x1 - x0;
let dy = y1 - y0;
let gradient = if dx == 0.0 { 1.0 } else { dy / dx };
let xpx11: i32;
let mut intery: f32;
{
let xend = round(x0);
let yend = y0 + gradient * (xend - x0);
let xgap = rfpart(x0 + 0.5);
xpx11 = xend as i32;
let ypx11 = ipart(yend);
if steep {
plot(ypx11, xpx11, rfpart(yend) * xgap);
plot(ypx11 + 1, xpx11, fpart(yend) * xgap);
} else {
plot(xpx11, ypx11, rfpart(yend) * xgap);
plot(xpx11, ypx11 + 1, fpart(yend) * xgap);
}
intery = yend + gradient;
}
let xpx12: i32;
{
let xend = round(x1);
let yend = y1 + gradient * (xend - x1);
let xgap = rfpart(x1 + 0.5);
xpx12 = xend as i32;
let ypx12 = ipart(yend);
if steep {
plot(ypx12, xpx12, rfpart(yend) * xgap);
plot(ypx12 + 1, xpx12, fpart(yend) * xgap);
} else {
plot(xpx12, ypx12, rfpart(yend) * xgap);
plot(xpx12, ypx12 + 1, fpart(yend) * xgap);
}
}
if steep {
for x in xpx11 + 1..xpx12 {
let ipy = ipart(intery);
plot(ipy, x, rfpart(intery));
plot(ipy + 1, x, fpart(intery));
intery += gradient;
}
} else {
for x in xpx11 + 1..xpx12 {
let ipy = ipart(intery);
plot(x, ipy, rfpart(intery));
plot(x, ipy + 1, fpart(intery));
intery += gradient;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_wu_draw_line() {
let mut pixels = vec![vec![0.0; 10]; 10]; // Create a 10x10 grid of floats
let plot = |x: i32, y: i32, brightness: f32| {
if x >= 0 && x < 10 && y >= 0 && y < 10 {
pixels[x as usize][y as usize] = brightness;
}
};
wu_draw_line(1.0, 1.0, 8.0, 8.0, plot);
// Basic validation: Check that some pixels are lit up
assert!(pixels[1][1] > 0.0);
assert!(pixels[8][8] > 0.0);
// You can add more specific assertions here based on the expected output.
// For example, check the values of pixels along the expected line path.
// Be aware of floating point precision when comparing.
}
#[test]
fn test_wu_draw_line_steep() {
let mut pixels = vec![vec![0.0; 10]; 10]; // Create a 10x10 grid of floats
let plot = |x: i32, y: i32, brightness: f32| {
if x >= 0 && x < 10 && y >= 0 && y < 10 {
pixels[x as usize][y as usize] = brightness;
}
};
wu_draw_line(1.0, 1.0, 2.0, 8.0, plot);
// Basic validation: Check that some pixels are lit up
assert!(pixels[1][1] > 0.0);
assert!(pixels[2][8] > 0.0);
}
}
</syntaxhighlight >