diff options
| author | Arne Dußin | 2020-12-27 21:54:31 +0100 |
|---|---|---|
| committer | Arne Dußin | 2020-12-27 21:54:31 +0100 |
| commit | 53d376eaeef991850d35318b147f75c8f103319d (patch) | |
| tree | 7e95a1666818dc7a804b145f263bdb4b76fef83a /src/tool/polygon_room_tool.rs | |
| parent | 2d2f45df9d47db25ac5a91c8f926a025c3a5dc7a (diff) | |
| download | graf_karto-53d376eaeef991850d35318b147f75c8f103319d.tar.gz graf_karto-53d376eaeef991850d35318b147f75c8f103319d.zip | |
Change to polygongraph instead of polygon in roomtool
The polygon room tool used a convoluted process for determining what the
user actually wants to draw. I have changed to the polygon graph
instead, which makes the checks easier and restricts the user a bit
less. In the process however I found a serious problem with my handling
float, so everything needed to change to margin compares (which I of
course should have done in the beginning. Guys, take the warning
seriously and don't ignore it for ten years like I did. It will come
back to haunt you.. apparently) instead of direct equality.
Diffstat (limited to 'src/tool/polygon_room_tool.rs')
| -rw-r--r-- | src/tool/polygon_room_tool.rs | 223 |
1 files changed, 83 insertions, 140 deletions
diff --git a/src/tool/polygon_room_tool.rs b/src/tool/polygon_room_tool.rs index 33daaf5..d181669 100644 --- a/src/tool/polygon_room_tool.rs +++ b/src/tool/polygon_room_tool.rs @@ -3,189 +3,132 @@ use super::Tool; use crate::colours::DEFAULT_COLOURS; use crate::map::Map; -use crate::math::{self, Polygon, PolygonError, Vec2}; +use crate::math::{self, PolygonGraph, Vec2}; use crate::transform::Transform; +use crate::FLOAT_MARGIN; use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; -struct UnfinishedPolygon { - pub corners: Vec<Vec2<f64>>, - pub working_corner: Vec2<f64>, -} - /// The tool itself. pub struct PolygonRoomTool { - unfinished_polygon: Option<UnfinishedPolygon>, -} - -impl UnfinishedPolygon { - // Check the validity of the already completed corners only - pub fn check_validity_completed(&self) -> Result<(), PolygonError<f64>> { - Polygon::check_validity(&self.corners) - } - - // Check the validity of the already completed corners, but with the working corner wedged - // between the last and first corner (making it the new last corner). - pub fn check_validity_all(&self) -> Result<(), PolygonError<f64>> { - // TODO: Is this possible without changing the mutability of self and without reallocation? - let mut corners = self.corners.clone(); - corners.push(self.working_corner); - - Polygon::check_validity(&corners) - } - - pub fn try_into_completed(&mut self) -> Option<Polygon<f64>> { - match self.check_validity_completed() { - Ok(()) => Some(Polygon::new_unchecked(self.corners.drain(..).collect())), - Err(e) => { - warn!("Cannot turn placed corners into a polygon: {}", e); - None - } - } - } - - pub fn try_into_all(&mut self) -> Option<Polygon<f64>> { - match self.check_validity_all() { - Ok(()) => { - self.corners.push(self.working_corner); - Some(Polygon::new_unchecked(self.corners.drain(..).collect())) - } - Err(e) => { - warn!( - "Cannot turn corners with newest corner into a polygon: {}", - e - ); - None - } - } - } - - pub fn try_push_working(&mut self) -> Result<(), PolygonError<f64>> { - assert!(!self.corners.is_empty()); - - if self.corners.len() == 1 { - return if self.corners[0] != self.working_corner { - self.corners.push(self.working_corner); - Ok(()) - } else { - Err(PolygonError::VertexDoubling(self.corners[0], 0)) - }; - } - - self.check_validity_all()?; - self.corners.push(self.working_corner); - - Ok(()) - } + unfinished_room: Option<(PolygonGraph<f64>, Vec2<f64>)>, + last_mouse_pos_m: Vec2<f64>, } impl PolygonRoomTool { /// Create a new polygon room tool. There should be only one instance and it should be created /// in the editor. + #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { - unfinished_polygon: None, + unfinished_room: None, + last_mouse_pos_m: Vec2::new(0., 0.), + } + } + + /* Helper function to try and finish the currently drawn polygon. If successful, it will add it + * to the map, clear the currently drawn polygon and return bool. Otherwise it will leave the + * unfinished polygon as is and return false without pushing anything. + */ + fn try_push(&mut self, map: &mut Map) -> bool { + if self.unfinished_room.is_none() { + return false; + } + + match self + .unfinished_room + .as_ref() + .unwrap() + .0 + .clone() + .bounding_polygon(FLOAT_MARGIN) + { + Some(polygon) => { + map.push_polygon_room(polygon); + self.unfinished_room = None; + true + } + None => false, } } } impl Tool for PolygonRoomTool { fn deactivate(&mut self) { - self.unfinished_polygon = None; + self.unfinished_room = None; } fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) { - // Update the position of the node that would be placed into the polygon next. - if let Some(ref mut polygon) = &mut self.unfinished_polygon { - polygon.working_corner = *mouse_pos_m; - } + // Update the last mouse position that was seen for later use. + self.last_mouse_pos_m = *mouse_pos_m; } fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) { - if let Some(polygon) = &self.unfinished_polygon { - // The first corner is guaranteed to be set, so we can at least draw a line. - if polygon.corners.len() == 1 { - rld.draw_line_ex( - transform.point_m_to_px(&polygon.corners[0]), - transform.point_m_to_px(&polygon.working_corner), + if let Some((graph, last_node)) = &self.unfinished_room { + /* To turn the graph into a polygon, we need a copy, might as well do + * it now, so we can add the working corner to it. + */ + let mut graph = graph.clone(); + + // Add the current mouse position as the next position if possible. + graph.add_edge(&last_node, &self.last_mouse_pos_m); + + if graph.num_nodes() <= 1 { + // Only able to draw a point + rld.draw_circle_v( + transform.point_m_to_px(&self.last_mouse_pos_m), transform.length_m_to_px(0.1) as f32, DEFAULT_COLOURS.room_selected, ); - } else if polygon.corners.len() == 2 { - // We have three valid corners, so we can draw a triangle. - rld.draw_triangle( - transform.point_m_to_px(&polygon.corners[0]), - transform.point_m_to_px(&polygon.corners[1]), - transform.point_m_to_px(&polygon.working_corner), - DEFAULT_COLOURS.room_selected, - ) + } else if let Some(polygon) = graph.clone().bounding_polygon(FLOAT_MARGIN) { + let triangles = math::triangulate(polygon, FLOAT_MARGIN); + for triangle in triangles { + let triangle: [Vec2<f64>; 3] = triangle.into(); + rld.draw_triangle( + transform.point_m_to_px(&triangle[0]), + transform.point_m_to_px(&triangle[1]), + transform.point_m_to_px(&triangle[2]), + DEFAULT_COLOURS.room_selected, + ) + } } else { - // A proper polygon can be drawn. - if polygon.check_validity_all().is_ok() { - let mut corners = polygon.corners.clone(); - corners.push(polygon.working_corner); - let polygon = Polygon::new_unchecked(corners); - let triangles = math::triangulate(polygon); - for triangle in triangles { - let triangle: [Vec2<f64>; 3] = triangle.into(); - rld.draw_triangle( - transform.point_m_to_px(&triangle[0]), - transform.point_m_to_px(&triangle[1]), - transform.point_m_to_px(&triangle[2]), - DEFAULT_COLOURS.room_selected, - ) - } - } else if polygon.check_validity_completed().is_ok() { - let polygon = Polygon::new_unchecked(polygon.corners.clone()); - let triangles = math::triangulate(polygon); - for triangle in triangles { - let triangle: [Vec2<f64>; 3] = triangle.into(); - rld.draw_triangle( - transform.point_m_to_px(&triangle[0]), - transform.point_m_to_px(&triangle[1]), - transform.point_m_to_px(&triangle[2]), - DEFAULT_COLOURS.room_selected, - ) - } + // For some reason the polygon creation failed. Draw lines for the edges instead. + for edge in graph.edge_iter() { + rld.draw_line_ex( + transform.point_m_to_px(&edge.start), + transform.point_m_to_px(&edge.end), + transform.length_m_to_px(0.1) as f32, + DEFAULT_COLOURS.room_selected, + ); } } } } fn place_single(&mut self, map: &mut Map, mouse_pos_m: &Vec2<f64>) { - if let Some(ref mut polygon) = &mut self.unfinished_polygon { - if polygon.working_corner == polygon.corners[0] { - /* The working corner will be ignored, since it would double the vertex at the - * polygon starting position. - */ - if let Some(polygon) = polygon.try_into_completed() { - map.push_polygon_room(polygon); - self.unfinished_polygon = None; - } - } else { - // Check if we can add the corner to the polygon without ruining it. - if let Err(e) = polygon.try_push_working() { - error!("Cannot add corner to polygon: {}", e); - } + if let Some((ref mut graph, ref mut last_placed)) = &mut self.unfinished_room { + // If the corner already exists in the polygon, try to finish and push it after adding the + // next edge. + let try_finish = graph.has_node(&mouse_pos_m); + + // Add an edge from the last corner to the currently active position if possible. + if graph.add_edge(last_placed, &mouse_pos_m) { + *last_placed = *mouse_pos_m; + } + + if try_finish { + self.try_push(map); } } else { // Start a new unfinished polygon - self.unfinished_polygon = Some(UnfinishedPolygon { - corners: vec![*mouse_pos_m], - working_corner: *mouse_pos_m, - }); + self.unfinished_room = Some((PolygonGraph::new(), *mouse_pos_m)); } } fn finish(&mut self, map: &mut Map) { - if let Some(ref mut polygon) = self.unfinished_polygon { - if let Some(polygon) = polygon.try_into_completed() { - map.push_polygon_room(polygon); - self.unfinished_polygon = None; - } - } + self.try_push(map); } fn abort(&mut self) { - self.unfinished_polygon = None; + self.unfinished_room = None; } } |
