From 3ece8e36bd7c1aa08374ff8ffa0f7206976746fd Mon Sep 17 00:00:00 2001 From: Arne Dußin Date: Wed, 28 Oct 2020 20:49:51 +0100 Subject: Add possibility to draw rectangles --- src/main.rs | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index faa5b7d..e6c85ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,31 +1,102 @@ use piston_window::grid::Grid; +use piston_window::rectangle::{Border, Rectangle}; use piston_window::*; use sdl2_window::Sdl2Window; +use std::cmp; -pub const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 0.8]; +pub const MIN_PIXELS_PER_M: f64 = 0.5; +pub const MAX_PIXELS_PER_M: f64 = 10_000.; +pub const STANDARD_PIXELS_PER_M: f64 = 64.; + +/// Helper function to turn two given points into a rectangle. The order of the two points is not +/// important, they are considered two endpoints of a diagonal and therefore identify the rectangle +/// unambiguously. +fn bounding_box(p0: [f64; 2], p1: [f64; 2]) -> [f64; 4] { + let min_x = p0[0].min(p1[0]); + let min_y = p0[1].min(p1[1]); + let max_x = p0[0].max(p1[0]); + let max_y = p0[1].max(p1[1]); + + [min_x, min_y, max_x - min_x, max_y - min_y] +} fn main() { let mut window: PistonWindow = WindowSettings::new("Hello there!", [1000, 1000]) .build() .expect("Could not initialise window"); - let mut pixels_per_m = 64.; + // The amount of on-screen pixels used to represent a meter of actual terrain. + let mut pixels_per_m = STANDARD_PIXELS_PER_M; + + /* Create a rectangle that is used to draw all rectangles that were created by the user. It has + * a thicc blacc border and white colour. + */ + let render_rect = Rectangle::new([0.7, 0.7, 0.7, 1.]).border(Border { + color: [0.5, 0.5, 0.5, 1.], + radius: 2., + }); + // The point the user has clicked. This is where they want the rectangle to start. + let mut starting_rect_point: Option<[f64; 2]> = None; + let mut rectangles = Vec::new(); + + // Line used to draw the square grid. + let grid_line = Line::new([1., 1., 1., 0.3], 1.5); - let grid_line = Line::new(BLACK, 1.5); + let mut mouse_pos = [0., 0.]; let mut events = Events::new(EventSettings::new().lazy(true)); while let Some(e) = events.next(&mut window) { + // Update the mouse cursor position + e.mouse_cursor(|pos| { + mouse_pos = pos; + }); + + // The zoom factor is changed with the mouse wheel. e.mouse_scroll(|[_, y]| { - if y < 0. { + let scale_changed = if y < 0. && MAX_PIXELS_PER_M > pixels_per_m { pixels_per_m *= 1.2; - } else if y > 0. { + true + } else if y > 0. && MIN_PIXELS_PER_M < pixels_per_m { pixels_per_m /= 1.2; + true + } else { + false + }; + + /* Make sure that the scale factors stay very close to the normal scale factors, even + * when the user zooms in and out very often, at least when they zoom over the standard + * zoom factor. + */ + if pixels_per_m > STANDARD_PIXELS_PER_M - 5. + && pixels_per_m < STANDARD_PIXELS_PER_M + 5. + { + pixels_per_m = STANDARD_PIXELS_PER_M; + } + + // Notify the user of the change if there was any + if scale_changed { + println!("Changed scale to {} pixels per m.", pixels_per_m); } }); + // Handle drawing a rectangle or finishing the rectangle when clicking with the mouse. + if let Some(Button::Mouse(MouseButton::Left)) = e.press_args() { + if let Some(first_point) = starting_rect_point { + rectangles.push(bounding_box(first_point, mouse_pos)); + starting_rect_point = None; + } else { + starting_rect_point = Some(mouse_pos); + } + } + + // Close the window when the user presses escape if let Some(Button::Keyboard(Key::Escape)) = e.press_args() { window.set_should_close(true); } + /* Update the Grid draw size to the actual window draw size. + * TODO: Currently, the window canvas draw size is never updated. This has to be changed in + * order to deal with the user resizing the window. + */ let win_size = window.draw_size(); let grid = Grid { cols: (win_size.width / pixels_per_m) as u32 + 1, @@ -34,9 +105,24 @@ fn main() { }; window.draw_2d(&e, |c, g, _device| { - clear([1.0; 4], g); + clear([0.4, 0.2, 0., 1.], g); grid.draw(&grid_line, &c.draw_state, c.transform, g); + + // Draw all rectangles that are part of the map + for &rect in &rectangles { + render_rect.draw(rect, &c.draw_state, c.transform, g); + } + + // Draw the current rectangle that is being drawn, but not part of the map + if let Some(starting_rect_point) = starting_rect_point { + render_rect.draw( + bounding_box(starting_rect_point, mouse_pos), + &c.draw_state, + c.transform, + g, + ); + } }); } } -- cgit v1.2.3-70-g09d2