121 lines
3.4 KiB
Rust
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 >
|