use std::collections::{BTreeMap, HashSet};
use std::sync::LazyLock;
use indoc::indoc;
use skia_safe::{Point, Rect};
static IGNOREABLE_CHARACTERS: LazyLock<HashSet<char>> =
LazyLock::new(|| ['-', '|', '*', '+', ' '].iter().cloned().collect());
pub fn ascii_to_rects(ascii: &str) -> Vec<Rect> {
let mut points_by_label = BTreeMap::new();
for (y, line) in ascii.lines().enumerate() {
for (x, c) in line.chars().enumerate() {
if IGNOREABLE_CHARACTERS.contains(&c) {
continue;
}
points_by_label.entry(c).or_insert_with(Vec::new).push((x, y));
}
}
let mut rects = vec![];
for points in points_by_label.values() {
let min_x = points.iter().map(|(x, _)| x).min().unwrap();
let min_y = points.iter().map(|(_, y)| y).min().unwrap();
let max_x = points.iter().map(|(x, _)| x).max().unwrap();
let max_y = points.iter().map(|(_, y)| y).max().unwrap();
rects.push(Rect::from_xywh(
*min_x as f32,
*min_y as f32,
(max_x - min_x + 1) as f32,
(max_y - min_y + 1) as f32,
));
}
rects
}
pub fn ascii_to_points(ascii: &str) -> Vec<Point> {
let mut points = BTreeMap::new();
for (y, line) in ascii.lines().enumerate() {
for (x, c) in line.chars().enumerate() {
if IGNOREABLE_CHARACTERS.contains(&c) {
continue;
}
points.entry(c).or_insert_with(Vec::new).push((x, y));
}
}
points
.values()
.flat_map(|points| points.iter().map(|(x, y)| Point::new(*x as f32, *y as f32)))
.collect()
}
#[test]
fn ascii_to_rect_works() {
assert_eq!(
ascii_to_rects(indoc! {"
1---1
| |
1---1
"}),
vec![Rect::from_xywh(0., 0., 5., 3.)]
);
assert_eq!(
ascii_to_rects(indoc! {"
1---1
| 2-+-2
1-+-1 |
2---2
"}),
vec![Rect::from_xywh(0., 0., 5., 3.), Rect::from_xywh(2., 1., 5., 3.),]
);
assert_eq!(
ascii_to_rects(indoc! {"
1----1
| |
*--2-1
| |
2--2
"}),
vec![Rect::from_xywh(0., 0., 6., 3.), Rect::from_xywh(0., 2., 4., 3.),]
);
assert_eq!(
ascii_to_rects(indoc! {"
1----1
| |
1----1
2--2
| |
2--2
"}),
vec![Rect::from_xywh(0., 0., 6., 3.), Rect::from_xywh(0., 3., 4., 3.),]
);
}
#[test]
fn ascii_to_points_works() {
assert_eq!(
ascii_to_points(indoc! {"
1
"}),
vec![Point::new(0., 0.)]
);
assert_eq!(
ascii_to_points(indoc! {"
1-2
| |
3-4
"}),
vec![Point::new(0., 0.), Point::new(2., 0.), Point::new(0., 2.), Point::new(2., 2.),]
);
assert_eq!(
ascii_to_points(indoc! {"
1-2
| |
| 3-4
| |
6---5
"}),
vec![
Point::new(0., 0.),
Point::new(2., 0.),
Point::new(2., 2.),
Point::new(4., 2.),
Point::new(4., 4.),
Point::new(0., 4.),
]
);
}