use std::f64; use std::fs::File; use std::io::prelude::*; use std::char::from_u32; use uuid::Uuid; use rand::prelude::*; use rand::distributions::{Normal, WeightedIndex}; use failure::Error; // use failure::err_msg; pub fn invader_write(id: Uuid) -> Result { let mut rng = thread_rng(); let mut svg = Vec::new(); // rounding ? // filters ? // distribution for lightness // bellcurve around 75% let l_dist = Normal::new(75.0, 10.0); let s_dist = Normal::new(25.0, 10.0); let mut colours = std::iter ::repeat_with(|| { let h = rng.gen_range(0, 360); let s = s_dist.sample(&mut rng) as usize; let l = l_dist.sample(&mut rng) as usize; format!("hsl({:}, {:}%, {:}%)", h, s, l) }) .take(3) .collect::>(); colours.push("none".to_string()); // add up to 100 for % let weights = [ 5, 5, 65, 25, // the transparent colour ]; let colour_dist = WeightedIndex::new(&weights)?; write!(&mut svg, "")?; for i in 0..50 { let x = (i % 5) * 50; let y = (i / 5) * 50; let colour = &colours[colour_dist.sample(&mut rng)]; write!(&mut svg, "", colour, x, y)?; write!(&mut svg, "", colour, 450 - x, y)?; } write!(&mut svg, "")?; let dest = format!("/var/lib/mnml/public/imgs/{}.svg", id); // info!("molecule dest={:?}", dest); let mut file = File::create(dest)?; file.write_all(&svg)?; Ok(id) } enum ConstructShapes { Square, Triangle, Circle, Line, V, Tri, // Plus, Blank, } // default ? shape pub fn shapes_write(id: Uuid) -> Result { let mut rng = thread_rng(); let mut svg = Vec::new(); // distribution for lightness // bellcurve around 75% let l_dist = Normal::new(50.0, 10.0); let s_dist = Normal::new(50.0, 20.0); // 8 6 or 4 points in shape // 1 head point // n / 2 shapes with a colour each // random size/radius props for each // add up to 100 for % let shapes = [ (ConstructShapes::Square, 10), (ConstructShapes::Triangle, 10), (ConstructShapes::Circle, 10), (ConstructShapes::Line, 10), (ConstructShapes::V, 10), (ConstructShapes::Tri, 10), // (ConstructShapes::Plus, 5), (ConstructShapes::Blank, 1), ]; let shape_dist = WeightedIndex::new(shapes.iter().map(|v| v.1))?; let n_shapes_items = [ (1, 1), (2, 2), (3, 5), (4, 10), (5, 10), ]; let num_dist = WeightedIndex::new(n_shapes_items.iter().map(|v| v.1))?; let n_shapes = num_dist.sample(&mut rng) as usize; write!(&mut svg, "")?; for i in 0..n_shapes + 1 { let h = rng.gen_range(0, 360); let s = s_dist.sample(&mut rng) as usize; let l = l_dist.sample(&mut rng) as usize; let colour = format!("hsl({:}, {:}%, {:}%)", h, s, l); let scalar = match i == n_shapes { true => 0.0, false => rng.gen_range(50.0, 200.0), }; let rotation = rng.gen_range(0, 180); let angle: f64 = i as f64 * (1.0 / n_shapes as f64) * f64::consts::PI; let x_translate = angle.cos() * scalar; let y_translate = angle.sin() * scalar; match shapes[shape_dist.sample(&mut rng)].0 { ConstructShapes::Square => { let size = rng.gen_range(20.0, 50.0); write!(&mut svg, "", fill = colour, x = size / 2.0, y = size / 2.0, width = size, height = size, x_t = x_translate, y_t = y_translate, rotation = rotation)?; if scalar == 0.0 && rng.gen_bool(0.5) { continue; } write!(&mut svg, "", fill = colour, x = size / 2.0, y = size / 2.0, width = size, height = size, x_t = -x_translate, y_t = -y_translate, rotation = rotation)?; }, ConstructShapes::Triangle => { let h = rng.gen_range(20.0, 50.0); let b = rng.gen_range(20.0, 50.0); write!(&mut svg, "", fill = colour, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation, x_translate = x_translate, y_translate = y_translate)?; if scalar == 0.0 && rng.gen_bool(0.5) { continue; } write!(&mut svg, "", fill = colour, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation + 180, x_translate = -x_translate, y_translate = -y_translate)?; }, ConstructShapes::Circle => { let r = rng.gen_range(10.0, 20.0); write!(&mut svg, "", fill = colour, r = r, x = x_translate, y = y_translate)?; write!(&mut svg, "", fill = colour, r = r, x = -x_translate, y = -y_translate)?; }, ConstructShapes::Line => { let width = rng.gen_range(2.0, 8.0); let height = rng.gen_range(20.0, 50.0); write!(&mut svg, "", fill = colour, x = width / 2.0, y = height / 2.0, width = width, height = height, x_t = x_translate, y_t = y_translate, rotation = rotation)?; if scalar == 0.0 && rng.gen_bool(0.5) { continue; } write!(&mut svg, "", fill = colour, x = width / 2.0, y = height / 2.0, width = width, height = height, x_t = -x_translate, y_t = -y_translate, rotation = rotation)?; }, ConstructShapes::V => { let h = rng.gen_range(20.0, 50.0); let b = rng.gen_range(20.0, 50.0); let width = rng.gen_range(2.0, 8.0); write!(&mut svg, "", fill = colour, width = width, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation, x_translate = x_translate, y_translate = y_translate)?; if scalar == 0.0 && rng.gen_bool(0.5) { continue; } write!(&mut svg, "", fill = colour, width = width, x = -b / 2.0, y = h / 2.0, x0 = -b / 2.0, y0 = -h / 2.0, x1 = 0, y1 = b / 2.0, x2 = b / 2.0, y2 = -h / 2.0, rotation = rotation + 180, x_translate = -x_translate, y_translate = -y_translate)?; }, ConstructShapes::Tri => { let width = rng.gen_range(2.0, 4.0); let length = rng.gen_range(12.5, 25.0); let x0 = (0.0 as f64).cos() * length; let y0 = (0.0 as f64).sin() * length; let x1 = ((f64::consts::PI * 2.0) / 3.0).cos() * length; let y1 = ((f64::consts::PI * 2.0) / 3.0).sin() * length; let x2 = ((f64::consts::PI * 4.0) / 3.0).cos() * length; let y2 = ((f64::consts::PI * 4.0) / 3.0).sin() * length; write!(&mut svg, "", fill = colour, width = width, x0 = x0, y0 = y0, x1 = x1, y1 = y1, x2 = x2, y2 = y2, rotation = rotation, x_translate = x_translate, y_translate = y_translate)?; if scalar == 0.0 && rng.gen_bool(0.5) { continue; } write!(&mut svg, "", fill = colour, width = width, x0 = x0, y0 = y0, x1 = x1, y1 = y1, x2 = x2, y2 = y2, rotation = rotation, x_translate = -x_translate, y_translate = -y_translate)?; }, // ConstructShapes::Plus => { }, ConstructShapes::Blank => (), } } write!(&mut svg, "")?; let dest = format!("/var/lib/mnml/public/imgs/{}.svg", id); // println!("/var/lib/mnml/public/imgs/{}.svg", id); let mut file = File::create(dest)?; file.write_all(&svg)?; Ok(id) } fn _hieroglyph() -> String { let mut rng = thread_rng(); let mut s = String::new(); for i in 0..4 { s.push(from_u32(rng.gen_range(0x13000, 0x1342E)).unwrap()); if i == 1 { // newline s.push(from_u32(0x000a).unwrap()); } } // println!("{:}", s); return s; } pub fn smile(id: Uuid) -> Result { let mut rng = thread_rng(); let mut svg = Vec::new(); // distribution for lightness // bellcurve around 75% let l_dist = Normal::new(50.0, 10.0); let s_dist = Normal::new(50.0, 20.0); // let stroke_width = rng.gen_range(1, 3); let stroke_width = 3; let h = rng.gen_range(0, 360); let s = s_dist.sample(&mut rng) as usize; let l = l_dist.sample(&mut rng) as usize; let eye_colour = format!("hsl({:}, {:}%, {:}%)", h, s, l); let h = rng.gen_range(0, 360); let s = s_dist.sample(&mut rng) as usize; let l = l_dist.sample(&mut rng) as usize; let mouth_colour = format!("hsl({:}, {:}%, {:}%)", h, s, l); // basic layout is 200x200 box w/ 100 padding // 2:1 for each x,y // left eye is at 0,0 // 50W 25H let eyes_left = [ ("M0,0 L25,25 L50,0", 1), // v ("M0,25 L25,0 L50,25", 1), // ^ ("M0,0 L50,0", 1), // - ("M0,25 L50,25", 1), // _ ("M0,0 L50,25 M50,0 L0,25", 1), // x ("M0,0 L50,12.5 L0,25", 1), // > ("M50,0 L0,12.5 L50,25", 1), // < ("M0,0 L0,25 L50,25", 1), // L ("M50,0 L50,25 L0,25", 1), // J ("M0,0 L50,0 M50,6.25 L50,12.5 M50,18.75 L50,25", 1), // ; ("M12.5,0 L37.5,0 L37.5,25 L12.5,25 L12.5,0", 1), // o ]; let eye_left_dist = WeightedIndex::new(eyes_left.iter().map(|v| v.1))?; // right eye is 150,0 // 50W 25H let eyes_right = [ ("M150,0 L175,25 L200,0", 1), // v ("M150,25 L175,0 L200,25", 1), // ^ ("M150,0 L200,0", 1), // - ("M150,25 L200,25", 1), // _ ("M150,0 L200,25 M200,0 L150,25", 1), // x ("M150,0 L200,12.5 L150,25", 1), // > ("M200,0 L150,12.5 L200,25", 1), // < ("M150,0 L150,25 L200,25", 1), // L ("M200,0 L200,25 L150,25", 1), // J ("M150,0 L200,0 M150,6.25 L150,12.5 M150,18.75 L150,25", 1), // ; ("M162.5,0 L187.5,0 L187.5,25 L162.5,25 L162.5,0", 1), // o ]; let eye_right_dist= WeightedIndex::new(eyes_right.iter().map(|v| v.1))?; // mouth is 50,75 // 100W 25H let mouths = [ ("M50,100 L150,100", 1), // _ ("M50,75 L150,75 L125,100 L75,100 L50,75", 1), // D ("M50,75 L75,100 L100,75 L125,100 L150,75", 1), // w ("M50,75 L75,75 L75,87.5 M75,75 L125,75 L125,87.5 M125,75 L150,75", 1), // vamp ("M50,75 L150,75 M50,75 L50,87.5 M75,75 L75,87.5 M100,75 L100,87.5 M125,75 L125,87.5 M150,75 L150,87.5", 1), // mm ("M75,75 L125,75 L125,100 L75,100 L75,75", 1), // o ("M50,75 L150,100 M150,75 L50,100", 1), // x ("M50,75 L150,75 L150,100 L125,100 L125,75", 1), // p ("M50,75 L150,75 M50,75 L50,100 L75,100 L75,75", 1), // d // ("M50,75 L50,100 L150,100 L150,75", 1), // u ("M50,100 L50,75 L150,75 L150,100", 1), // n ("M50,75 L50,100 L150,75 L150,100", 1), // Z ("M50,87.5 L100,75 L150,87.5 L100,100 L50,87.5", 1), // Z ]; let mouth_dist = WeightedIndex::new(mouths.iter().map(|v| v.1))?; write!(&mut svg, "")?; let left_eye_path = eyes_left[eye_left_dist.sample(&mut rng)].0; // left eye write!(&mut svg, "", eye_colour, stroke_width, left_eye_path)?; let right_eye_path = eyes_right[eye_right_dist.sample(&mut rng)].0; // right eye write!(&mut svg, "", eye_colour, stroke_width, right_eye_path)?; let mouth_path = mouths[mouth_dist.sample(&mut rng)].0; // mouth write!(&mut svg, "", mouth_colour, stroke_width, mouth_path)?; write!(&mut svg, "")?; // let dest = format!("/var/lib/mnml/face.svg"); let dest = format!("/var/lib/mnml/public/imgs/{}.svg", id); let mut file = File::create(dest)?; file.write_all(&svg)?; Ok(id) } pub fn exists(id: Uuid) -> bool { std::path::Path::new(&format!("/var/lib/mnml/public/imgs/{}.svg", id)).exists() } #[cfg(test)] mod tests { use super::*; // #[test] // fn invader_img_test() { // for i in 0..100 { // invader_img_write(Uuid::new_v4()).unwrap(); // } // } // #[test] // fn hieroglyph_test() { // hieroglyph(); // } // #[test] // fn shapes_img_test() { // for i in 0..100 { // shapes_write(Uuid::new_v4()).unwrap(); // } // } #[test] fn smile_test() { smile(Uuid::new_v4()).unwrap(); } }