diff options
| author | Arne Dußin | 2020-11-10 18:52:08 +0100 |
|---|---|---|
| committer | Arne Dußin | 2020-11-10 18:52:08 +0100 |
| commit | 178d716232468e5ae3292f39ccc5abd9c147094e (patch) | |
| tree | f262ee32f8d7407a460c578c0f027f5cc3f919cb /src/dimension_indicator.rs | |
| parent | f2caebd11512fce214338b054c1b061b86d84aee (diff) | |
| download | graf_karto-178d716232468e5ae3292f39ccc5abd9c147094e.tar.gz graf_karto-178d716232468e5ae3292f39ccc5abd9c147094e.zip | |
Add dimension indicator without direct value editing
Diffstat (limited to 'src/dimension_indicator.rs')
| -rw-r--r-- | src/dimension_indicator.rs | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/dimension_indicator.rs b/src/dimension_indicator.rs new file mode 100644 index 0000000..a08d22c --- /dev/null +++ b/src/dimension_indicator.rs @@ -0,0 +1,123 @@ +use crate::math::Vec2; +use crate::transform::Transform; +use raylib::drawing::RaylibDraw; +use raylib::ffi::Color; + +pub struct DimensionIndicator { + /// The lines that are used to draw the Dimension Indicator. For a rectangle for instance these + /// would be two. One for width and one for height. + length_lines: Vec<(Vec2<f32>, Vec2<f32>)>, +} + +impl DimensionIndicator { + pub fn new() -> Self { + Self { + length_lines: Vec::new(), + } + } + + pub fn from_corner_points(corner_points: &Vec<Vec2<f32>>) -> Self { + let mut this = Self::new(); + this.update_dimensions(corner_points); + + this + } + + /// Update the dimensions by analysing a given set of points and adjusting the internal + /// (measured) dimensions. + pub fn update_dimensions(&mut self, corner_points: &[Vec2<f32>]) { + if corner_points.len() < 2 { + warn!("Cannot discern dimensions when not at least two points are given. The dimensions were not updated."); + return; + } + + // Discern the bounding box for the given corner points. + let mut min = corner_points[0]; + let mut max = corner_points[0]; + for point in corner_points.iter().skip(1) { + if point.x < min.x { + min.x = point.x; + } + if point.x > max.x { + max.x = point.x; + } + + if point.y < min.y { + min.y = point.y; + } + if point.y > max.y { + max.y = point.y; + } + } + + // For now, only use the width and height vectors. + // TODO: Change to a more sophisticated approach. + self.length_lines.clear(); + // Horizontal dimensions, left to right. + self.length_lines + .push((Vec2::new(min.x, max.y), Vec2::new(max.x, max.y))); + // Vertical dimensions, bottom to top. + self.length_lines + .push((Vec2::new(max.x, max.y), Vec2::new(max.x, min.y))); + } + + pub fn draw(&self, rld: &mut impl RaylibDraw, transform: &Transform) { + // Draw all the dimension lines. + for (start, end) in &self.length_lines { + // Don't draw anything if the length is zero. + if start == end { + continue; + } + + /* Get the vector that is perpendicular and points right/down from the line, assuming + * the lines prefer left as start over right and bottom over top. + */ + let line_normal = { + // Start with the direction of the line vector. + let dir = *start - *end; + // Calculate perpendicular vec and normalise. + dir.rotated_90_clockwise() / dir.len() + }; + + // To not have the line directly in the rect, move start and end outside a bit. + let start_px = transform.point_m_to_px(*start) + line_normal * 10.; + let end_px = transform.point_m_to_px(*end) + line_normal * 10.; + + /* Draw the indicator line, with stubs at both ends. */ + let line_colour = Color { + r: 200, + g: 200, + b: 200, + a: 255, + }; + // First the two stubs. + rld.draw_line_ex( + start_px - line_normal * 5., + start_px + line_normal * 5., + 2., + line_colour, + ); + rld.draw_line_ex( + end_px - line_normal * 5., + end_px + line_normal * 5., + 2., + line_colour, + ); + // Then the actual indicator line. + rld.draw_line_ex(start_px, end_px, 2., line_colour); + + /* Draw the indicator text showing how long this line is in meters. + * It should be placed in the middle of the line, but not into the line directly, so it + * will be moved out by the normal. + */ + let text_pos = transform.point_m_to_px((*end + *start) / 2.) + line_normal * 20.; + rld.draw_text( + &format!("{}m", &(*end - *start).len()), + text_pos.x as i32, + text_pos.y as i32, + 20, + line_colour, + ); + } + } +} |
