Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| extern crate piston; | |
| extern crate opengl_graphics; | |
| extern crate graphics; | |
| extern crate touch_visualizer; | |
| #[cfg(feature = "include_sdl2")] | |
| extern crate sdl2_window; | |
| extern crate getopts; | |
| extern crate voronoi; | |
| extern crate rand; | |
| use touch_visualizer::TouchVisualizer; | |
| use opengl_graphics::{ GlGraphics, OpenGL }; | |
| use graphics::{ Context, Graphics }; | |
| use piston::window::{ Window, WindowSettings }; | |
| use piston::input::*; | |
| use piston::event_loop::*; | |
| #[cfg(feature = "include_sdl2")] | |
| use sdl2_window::Sdl2Window as AppWindow; | |
| use voronoi::{voronoi, Point, make_polygons}; | |
| use rand::Rng; | |
| static DEFAULT_WINDOW_HEIGHT: u32 = 600; | |
| static DEFAULT_WINDOW_WIDTH: u32 = 600; | |
| struct Settings { | |
| lines_only: bool, | |
| random_count: usize | |
| } | |
| fn main() { | |
| let args: Vec<String> = std::env::args().collect(); | |
| let mut opts = getopts::Options::new(); | |
| opts.optflag("l", "lines_only", "Don't color polygons, just outline them"); | |
| opts.optopt("r", "random_count", "On keypress \"R\", put this many random points on-screen", "RANDOMCOUNT"); | |
| let matches = opts.parse(&args[1..]).expect("Failed to parse args"); | |
| let settings = Settings{ | |
| lines_only: matches.opt_present("l"), | |
| random_count: match matches.opt_str("r") { | |
| None => { 50 }, | |
| Some(s) => { s.parse().expect("Random count of bad format") } | |
| } | |
| }; | |
| event_loop(&settings); | |
| } | |
| fn no_dot_there_yet(dot: &[f64;2], dots: &Vec<[f64;2]>) -> bool { | |
| let epsilon = 0.001; | |
| for &d in dots { | |
| if (dot[0] - d[0]).abs() < epsilon && (dot[1] - d[1]).abs() < epsilon { | |
| // println!("Point already there, did not add ({}, {})", dot[0], dot[1]); | |
| return false | |
| } | |
| } | |
| true | |
| } | |
| fn random_point() -> [f64; 2] { | |
| [rand::thread_rng().gen_range(0., DEFAULT_WINDOW_HEIGHT as f64), rand::thread_rng().gen_range(0., DEFAULT_WINDOW_WIDTH as f64)] | |
| } | |
| fn random_color() -> [f32; 4] { | |
| [rand::random::<f32>(), rand::random::<f32>(), rand::random::<f32>(), 1.0] | |
| } | |
| fn random_voronoi(dots: &mut Vec<[f64;2]>, colors: &mut Vec<[f32;4]>, num: usize) { | |
| dots.clear(); | |
| colors.clear(); | |
| for _ in 0..num { | |
| dots.push(random_point()); | |
| colors.push(random_color()); | |
| } | |
| } | |
| fn event_loop(settings: &Settings) { | |
| let opengl = OpenGL::V3_2; | |
| let mut window: AppWindow = WindowSettings::new("Interactive Voronoi", [DEFAULT_WINDOW_HEIGHT, DEFAULT_WINDOW_WIDTH]) | |
| .exit_on_esc(true).opengl(opengl).build().unwrap(); | |
| let ref mut gl = GlGraphics::new(opengl); | |
| let mut touch_visualizer = TouchVisualizer::new(); | |
| let mut events = Events::new(EventSettings::new().lazy(true)); | |
| let mut dots = Vec::new(); | |
| let mut colors = Vec::new(); | |
| let mut mx = 0.0; | |
| let mut my = 0.0; | |
| while let Some(e) = events.next(&mut window) { | |
| touch_visualizer.event(window.size(), &e); | |
| if let Some(button) = e.release_args() { | |
| match button { | |
| Button::Keyboard(key) => { | |
| if key == piston::input::keyboard::Key::N { dots.clear(); colors.clear(); } | |
| if key == piston::input::keyboard::Key::R { random_voronoi(&mut dots, &mut colors, settings.random_count); } | |
| } | |
| Button::Mouse(_) => { | |
| let dot = [mx, my]; | |
| // Two points at the same place lead to a problem in rust_voronoi | |
| if no_dot_there_yet(&dot, &dots) { | |
| dots.push(dot); | |
| colors.push(random_color()); | |
| } | |
| }, | |
| _ => () | |
| } | |
| }; | |
| e.mouse_cursor(|x, y| { | |
| mx = x; | |
| my = y; | |
| }); | |
| if let Some(args) = e.render_args() { | |
| gl.draw(args.viewport(), |c, g| { | |
| graphics::clear([1.0; 4], g); | |
| let mut vor_pts = Vec::new(); | |
| for d in &dots { | |
| vor_pts.push(Point::new(d[0], d[1])); | |
| } | |
| if vor_pts.len() > 0 { | |
| let vor_diagram = voronoi(vor_pts, DEFAULT_WINDOW_WIDTH as f64); | |
| let vor_polys = make_polygons(&vor_diagram); | |
| for (i, poly) in vor_polys.iter().enumerate() { | |
| if colors.len()-1 < i { | |
| colors.push(random_color()); | |
| } | |
| if settings.lines_only { | |
| draw_lines_in_polygon(poly, &c, g); | |
| } else { | |
| draw_polygon(poly, &c, g, colors[i]); | |
| } | |
| } | |
| } | |
| for d in &dots { | |
| draw_ellipse(&d, &c, g); | |
| } | |
| }); | |
| } | |
| } | |
| } | |
| fn draw_lines_in_polygon<G: Graphics>( | |
| poly: &Vec<Point>, | |
| c: &Context, | |
| g: &mut G, | |
| ) | |
| { | |
| let color = [0.0, 0.0, 1.0, 1.0]; | |
| for i in 0..poly.len()-1 { | |
| graphics::line( | |
| color, | |
| 2.0, | |
| [poly[i].x.into(), poly[i].y.into(), poly[i+1].x.into(), poly[i+1].y.into()], | |
| c.transform, | |
| g | |
| ) | |
| } | |
| } | |
| fn draw_polygon<G: Graphics>( | |
| poly: &Vec<Point>, | |
| c: &Context, | |
| g: &mut G, | |
| color: [f32; 4] | |
| ) { | |
| let mut polygon_points: Vec<[f64; 2]> = Vec::new(); | |
| for p in poly { | |
| polygon_points.push([p.x.into(), p.y.into()]); | |
| } | |
| graphics::polygon( | |
| color, | |
| polygon_points.as_slice(), | |
| c.transform, | |
| g | |
| ) | |
| } | |
| fn draw_ellipse<G: Graphics>( | |
| cursor: &[f64; 2], | |
| c: &Context, | |
| g: &mut G, | |
| ) { | |
| let color = [0.0, 0.0, 0.0, 1.0]; | |
| graphics::ellipse( | |
| color, | |
| graphics::ellipse::circle(cursor[0], cursor[1], 4.0), | |
| c.transform, | |
| g | |
| ); | |
| } |