aboutsummaryrefslogtreecommitdiff
path: root/src/tool
diff options
context:
space:
mode:
authorArne Dußin2020-12-27 21:54:31 +0100
committerArne Dußin2020-12-27 21:54:31 +0100
commit53d376eaeef991850d35318b147f75c8f103319d (patch)
tree7e95a1666818dc7a804b145f263bdb4b76fef83a /src/tool
parent2d2f45df9d47db25ac5a91c8f926a025c3a5dc7a (diff)
downloadgraf_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')
-rw-r--r--src/tool/deletion_tool.rs3
-rw-r--r--src/tool/mod.rs12
-rw-r--r--src/tool/polygon_room_tool.rs223
-rw-r--r--src/tool/rect_room_tool.rs1
-rw-r--r--src/tool/selection_tool.rs3
-rw-r--r--src/tool/wall_tool.rs1
6 files changed, 95 insertions, 148 deletions
diff --git a/src/tool/deletion_tool.rs b/src/tool/deletion_tool.rs
index afd916a..da2090b 100644
--- a/src/tool/deletion_tool.rs
+++ b/src/tool/deletion_tool.rs
@@ -9,7 +9,7 @@
use super::Tool;
use crate::colours::DEFAULT_COLOURS;
use crate::map::Map;
-use crate::math::{Rect, Surface, Vec2};
+use crate::math::{ExactSurface, Rect, Vec2};
use crate::transform::Transform;
use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
@@ -21,6 +21,7 @@ pub struct DeletionTool {
impl DeletionTool {
/// Create a new deletion tool, there should only be one deletion tool and it should be created
/// by the editor.
+ #[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
deletion_rect: None,
diff --git a/src/tool/mod.rs b/src/tool/mod.rs
index 70534ac..4130244 100644
--- a/src/tool/mod.rs
+++ b/src/tool/mod.rs
@@ -31,17 +31,17 @@ use raylib::core::drawing::RaylibDrawHandle;
/// The types of tools available in graf karto. For information about the tool itself, please see the
/// referenced Tool's documentation.
pub enum ToolType {
- /// See [super::RectRoomTool] for information on this tool.
+ /// See [RectRoomTool] for information on this tool.
RectRoomTool,
- /// See [super::PolygonRoomTool] for information on this tool.
+ /// See [PolygonRoomTool] for information on this tool.
PolygonRoomTool,
- /// See [super::WallTool] for information on this tool.
+ /// See [WallTool] for information on this tool.
WallTool,
- /// See [super::IconTool] for information on this tool.
+ /// See [IconTool] for information on this tool.
IconTool,
- /// See [super::DeletionTool] for information on this tool.
+ /// See [DeletionTool] for information on this tool.
DeletionTool,
- /// See [super::SelectionTool] for information on this tool.
+ /// See [SelectionTool] for information on this tool.
SelectionTool,
/// Not a real tool but used to know how many tools are available. New tools must be added
/// above this variant.
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;
}
}
diff --git a/src/tool/rect_room_tool.rs b/src/tool/rect_room_tool.rs
index 7cb85bb..9445787 100644
--- a/src/tool/rect_room_tool.rs
+++ b/src/tool/rect_room_tool.rs
@@ -19,6 +19,7 @@ pub struct RectRoomTool {
impl RectRoomTool {
/// Create a new room tool where no rooms have been drawn yet. Should be created only once per
/// program instance and by the editor.
+ #[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
unfinished_rect: None,
diff --git a/src/tool/selection_tool.rs b/src/tool/selection_tool.rs
index c790734..4850a28 100644
--- a/src/tool/selection_tool.rs
+++ b/src/tool/selection_tool.rs
@@ -9,7 +9,7 @@
use super::Tool;
use crate::colours::DEFAULT_COLOURS;
use crate::map::Map;
-use crate::math::{Rect, Surface, Vec2};
+use crate::math::{ExactSurface, Rect, Vec2};
use crate::transform::Transform;
use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
@@ -21,6 +21,7 @@ pub struct SelectionTool {
impl SelectionTool {
/// Create a new selection tool. There should be only one such tool per program instance and it
/// should be created in the editor.
+ #[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
selection_rect: None,
diff --git a/src/tool/wall_tool.rs b/src/tool/wall_tool.rs
index 123171c..e79d815 100644
--- a/src/tool/wall_tool.rs
+++ b/src/tool/wall_tool.rs
@@ -16,6 +16,7 @@ pub struct WallTool {
impl WallTool {
/// Create a new wall tool. There should only be one wall tool per program instance, which should
/// be created inside of the editor.
+ #[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
unfinished_wall: None,