1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
use piston_window::grid::Grid;
use piston_window::rectangle::{Border, Rectangle};
use piston_window::*;
use sdl2_window::Sdl2Window;
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<Sdl2Window> = WindowSettings::new("Hello there!", [1000, 1000])
.build()
.expect("Could not initialise window");
// 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 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]| {
let scale_changed = if y < 0. && MAX_PIXELS_PER_M > pixels_per_m {
pixels_per_m *= 1.2;
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);
}
}
// Abort drawing a rectangle when clicking with the right mouse button
if let Some(Button::Mouse(MouseButton::Right)) = e.press_args() {
starting_rect_point = None;
}
// 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,
rows: (win_size.height / pixels_per_m) as u32 + 1,
units: pixels_per_m,
};
window.draw_2d(&e, |c, g, _device| {
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,
);
}
});
}
}
|