// props to https://trmm.net/Asteroids_font // https://github.com/osresearch/vst/blob/master/teensyv/asteroids_font.c use geo::algorithm::translate::Translate; use geo::{Coordinate, LineString, MultiLineString}; use std::collections::HashMap; pub struct AsteroidFont { letters: HashMap>>, } impl AsteroidFont { #[rustfmt::skip] pub fn new() -> Self { let mut letters = HashMap::new(); letters.insert('0', vec![vec![(0, 0), (8, 0), (8, 12), (0, 12), (0, 0), (8, 12)]]); letters.insert('1', vec![vec![(4, 0), (4, 12), (3, 10)]]); letters.insert('2', vec![vec![(0, 12), (8, 12), (8, 7), (0, 5), (0, 0), (8, 0)]]); letters.insert('3', vec![vec![(0, 12), (8, 12), (8, 0), (0, 0), ], vec![(0, 6), (8, 6)]]); letters.insert('4', vec![vec![(0, 12), (0, 6), (8, 6), ], vec![(8, 12), (8, 0)]]); letters.insert('5', vec![vec![(0, 0), (8, 0), (8, 6), (0, 7), (0, 12), (8, 12)]]); letters.insert('6', vec![vec![(0, 12), (0, 0), (8, 0), (8, 5), (0, 7)]]); letters.insert('7', vec![vec![(0, 12), (8, 12), (8, 6), (4, 0)]]); letters.insert('8', vec![vec![(0, 0), (8, 0), (8, 12), (0, 12), (0, 0), ], vec![(0, 6), (8, 6)]]); letters.insert('9', vec![vec![(8, 0), (8, 12), (0, 12), (0, 7), (8, 5)]]); letters.insert(' ', vec![]); letters.insert('.', vec![vec![(3, 0), (4, 0)]]); letters.insert(',', vec![vec![(2, 0), (4, 2)]]); letters.insert('-', vec![vec![(2, 6), (6, 6)]]); letters.insert('+', vec![vec![(1, 6), (7, 6), ], vec![(4, 9), (4, 3)]]); letters.insert('!', vec![vec![(4, 0), (3, 2), (5, 2), (4, 0), ], vec![(4, 4), (4, 12)]]); letters.insert('#', vec![vec![(0, 4), (8, 4), (6, 2), (6, 10), (8, 8), (0, 8), (2, 10), (2, 2)]]); letters.insert('^', vec![vec![(2, 6), (4, 12), (6, 6)]]); letters.insert('=', vec![vec![(1, 4), (7, 4), ], vec![(1, 8), (7, 8)]]); letters.insert('*', vec![vec![(0, 0), (4, 12), (8, 0), (0, 8), (8, 8), (0, 0)]]); letters.insert('_', vec![vec![(0, 0), (8, 0)]]); letters.insert('/', vec![vec![(0, 0), (8, 12)]]); letters.insert('\\', vec![vec![(0, 12), (8, 0)]]); letters.insert('@', vec![vec![(8, 4), (4, 0), (0, 4), (0, 8), (4, 12), (8, 8), (4, 4), (3, 6)]]); letters.insert('$', vec![vec![(6, 2), (2, 6), (6, 10), ], vec![(4, 12), (4, 0)]]); letters.insert('&', vec![vec![(8, 0), (4, 12), (8, 8), (0, 4), (4, 0), (8, 4)]]); letters.insert('[', vec![vec![(6, 0), (2, 0), (2, 12), (6, 12)]]); letters.insert(']', vec![vec![(2, 0), (6, 0), (6, 12), (2, 12)]]); letters.insert('(', vec![vec![(6, 0), (2, 4), (2, 8), (6, 12)]]); letters.insert(')', vec![vec![(2, 0), (6, 4), (6, 8), (2, 12)]]); letters.insert('{', vec![vec![(6, 0), (4, 2), (4, 10), (6, 12), ], vec![(2, 6), (4, 6)]]); letters.insert('}', vec![vec![(4, 0), (6, 2), (6, 10), (4, 12), ], vec![(6, 6), (8, 6)]]); letters.insert('%', vec![vec![(0, 0), (8, 12), ], vec![(2, 10), (2, 8), ], vec![(6, 4), (6, 2)]]); letters.insert('<', vec![vec![(6, 0), (2, 6), (6, 12)]]); letters.insert('>', vec![vec![(2, 0), (6, 6), (2, 12)]]); letters.insert('|', vec![vec![(4, 0), (4, 5), ], vec![(4, 6), (4, 12)]]); letters.insert(':', vec![vec![(4, 9), (4, 7), ], vec![(4, 5), (4, 3)]]); letters.insert(';', vec![vec![(4, 9), (4, 7), ], vec![(4, 5), (1, 2)]]); letters.insert('"', vec![vec![(2, 10), (2, 6), ], vec![(6, 10), (6, 6)]]); letters.insert('\'', vec![vec![(2, 6), (6, 10)]]); letters.insert('`', vec![vec![(2, 10), (6, 6)]]); letters.insert('~', vec![vec![(0, 4), (2, 8), (6, 4), (8, 8)]]); letters.insert('?', vec![vec![(0, 8), (4, 12), (8, 8), (4, 4), ], vec![(4, 1), (4, 0)]]); letters.insert('a', vec![vec![(0, 0), (0, 8), (4, 12), (8, 8), (8, 0), ], vec![(0, 4), (8, 4)]]); letters.insert('b', vec![vec![(0, 0), (0, 12), (4, 12), (8, 10), (4, 6), (8, 2), (4, 0), (0, 0)]]); letters.insert('c', vec![vec![(8, 0), (0, 0), (0, 12), (8, 12)]]); letters.insert('d', vec![vec![(0, 0), (0, 12), (4, 12), (8, 8), (8, 4), (4, 0), (0, 0)]]); letters.insert('e', vec![vec![(8, 0), (0, 0), (0, 12), (8, 12), ], vec![(0, 6), (6, 6)]]); letters.insert('f', vec![vec![(0, 0), (0, 12), (8, 12), ], vec![(0, 6), (6, 6)]]); letters.insert('g', vec![vec![(6, 6), (8, 4), (8, 0), (0, 0), (0, 12), (8, 12)]]); letters.insert('h', vec![vec![(0, 0), (0, 12), ], vec![(0, 6), (8, 6), ], vec![(8, 12), (8, 0)]]); letters.insert('i', vec![vec![(0, 0), (8, 0), ], vec![(4, 0), (4, 12), ], vec![(0, 12), (8, 12)]]); letters.insert('j', vec![vec![(0, 4), (4, 0), (8, 0), (8, 12)]]); letters.insert('k', vec![vec![(0, 0), (0, 12), ], vec![(8, 12), (0, 6), (6, 0)]]); letters.insert('l', vec![vec![(8, 0), (0, 0), (0, 12)]]); letters.insert('m', vec![vec![(0, 0), (0, 12), (4, 8), (8, 12), (8, 0)]]); letters.insert('n', vec![vec![(0, 0), (0, 12), (8, 0), (8, 12)]]); letters.insert('o', vec![vec![(0, 0), (0, 12), (8, 12), (8, 0), (0, 0)]]); letters.insert('p', vec![vec![(0, 0), (0, 12), (8, 12), (8, 6), (0, 5)]]); letters.insert('q', vec![vec![(0, 0), (0, 12), (8, 12), (8, 4), (0, 0), ], vec![(4, 4), (8, 0)]]); letters.insert('r', vec![vec![(0, 0), (0, 12), (8, 12), (8, 6), (0, 5), ], vec![(4, 5), (8, 0)]]); letters.insert('s', vec![vec![(0, 2), (2, 0), (8, 0), (8, 5), (0, 7), (0, 12), (6, 12), (8, 10)]]); letters.insert('t', vec![vec![(0, 12), (8, 12), ], vec![(4, 12), (4, 0)]]); letters.insert('u', vec![vec![(0, 12), (0, 2), (4, 0), (8, 2), (8, 12)]]); letters.insert('v', vec![vec![(0, 12), (4, 0), (8, 12)]]); letters.insert('w', vec![vec![(0, 12), (2, 0), (4, 4), (6, 0), (8, 12)]]); letters.insert('x', vec![vec![(0, 0), (8, 12), ], vec![(0, 12), (8, 0)]]); letters.insert('y', vec![vec![(0, 12), (4, 6), (8, 12), ], vec![(4, 6), (4, 0)]]); letters.insert('z', vec![vec![(0, 12), (8, 12), (0, 0), (8, 0), ], vec![(2, 6), (6, 6)]]); AsteroidFont {letters } } pub fn get_letter(&self, letter: &char, size: f64) -> Vec> { let letter_coordinates = self.letters.get(&letter.to_ascii_lowercase()).unwrap(); let mut polygons: Vec> = Vec::new(); for letter_part in letter_coordinates.iter() { let coordinates: Vec> = letter_part .iter() .map(|&(x, y)| Coordinate { x: x as f64 * size / 12., y: (12. - y as f64) * size / 12., }) .collect(); polygons.push(LineString(coordinates)); } polygons } /// size of space (per letter) pub fn get_text_scale_factor(&self, size: f64) -> (f64, f64) { let scale_factor = size / 12.; (10.2 * scale_factor, 14.2 * scale_factor) } pub fn get_text( &self, text: String, size: f64, direction: FontDirection, ) -> MultiLineString { let mut letters: Vec> = Vec::new(); let mut count = 0.; for char in text.chars() { let letter = self.get_letter(&char, size); let (x_translate_factor, y_translate_factor) = self.get_text_scale_factor(size); for character in letter.iter() { match direction { FontDirection::LeftRight => { letters.push(character.translate(count * x_translate_factor, 0.)) } FontDirection::TopDown => { letters.push(character.translate(0., count * y_translate_factor)) } } } count = count + 1.; } MultiLineString(letters) } } pub enum FontDirection { LeftRight, TopDown, }