use crate::layout::Layout;
const MAX_SIDE: i32 = 512;
pub fn ascii(layout: &Layout) -> String {
let (w, h) = (layout.bounds.w, layout.bounds.h);
if w <= 0 || h <= 0 {
return String::from("(empty layout)");
}
if w > MAX_SIDE || h > MAX_SIDE {
return format!("(layout {w}x{h} exceeds the {MAX_SIDE}-cell ascii dump cap)");
}
let (w, h) = (w as usize, h as usize);
let mut canvas = vec![vec![b' '; w]; h];
let mut plot = |x: i32, y: i32, ch: u8| {
if x >= 0 && y >= 0 && (x as usize) < w && (y as usize) < h {
canvas[y as usize][x as usize] = ch;
}
};
for edge in &layout.edges {
let ch = if edge.broken { b'%' } else { b'*' };
for pair in edge.waypoints.windows(2) {
line(pair[0].x, pair[0].y, pair[1].x, pair[1].y, |x, y| {
plot(x, y, ch)
});
}
}
for node in &layout.nodes {
let r = node.rect;
for x in r.x..r.right() {
plot(x, r.y, b'#');
plot(x, r.bottom() - 1, b'#');
}
for y in r.y..r.bottom() {
plot(r.x, y, b'#');
plot(r.right() - 1, y, b'#');
}
let label_y = if r.h > 2 { r.y + 1 } else { r.y };
let max_len = (r.w - 2).max(1) as usize;
for (i, b) in node.id.bytes().take(max_len).enumerate() {
plot(r.x + 1 + i as i32, label_y, b);
}
}
let mut out = String::with_capacity(h * (w + 1));
for row in canvas {
out.push_str(std::str::from_utf8(&row).unwrap_or(""));
out.push('\n');
}
out
}
fn line(x0: i32, y0: i32, x1: i32, y1: i32, mut plot: impl FnMut(i32, i32)) {
let (dx, dy) = ((x1 - x0).abs(), -(y1 - y0).abs());
let (sx, sy) = (if x0 < x1 { 1 } else { -1 }, if y0 < y1 { 1 } else { -1 });
let (mut x, mut y, mut err) = (x0, y0, dx + dy);
loop {
plot(x, y);
if x == x1 && y == y1 {
break;
}
let e2 = 2 * err;
if e2 >= dy {
err += dy;
x += sx;
}
if e2 <= dx {
err += dx;
y += sy;
}
}
}