aboutsummaryrefslogtreecommitdiff
path: root/src/tool/polygon_room_tool.rs
diff options
context:
space:
mode:
authorArne Dußin2020-11-25 21:38:38 +0100
committerArne Dußin2020-11-25 21:38:38 +0100
commit77f2d35cb52d9443e9a0e9250aa941fc3d7610b6 (patch)
tree55b48a4cb84d1fc057240919735ce5d2b59bca6e /src/tool/polygon_room_tool.rs
parent58ca28d4b21667e9b86939ad574f477e02f2b290 (diff)
downloadgraf_karto-77f2d35cb52d9443e9a0e9250aa941fc3d7610b6.tar.gz
graf_karto-77f2d35cb52d9443e9a0e9250aa941fc3d7610b6.zip
Add polygon rooms that can actually kind of be used
It's still kind of strange to use the polygon tool, but at least it seems stable enough so I'm confident enough (and sick enough of it) to release it into the wild.
Diffstat (limited to 'src/tool/polygon_room_tool.rs')
-rw-r--r--src/tool/polygon_room_tool.rs184
1 files changed, 149 insertions, 35 deletions
diff --git a/src/tool/polygon_room_tool.rs b/src/tool/polygon_room_tool.rs
index b37774b..58f326f 100644
--- a/src/tool/polygon_room_tool.rs
+++ b/src/tool/polygon_room_tool.rs
@@ -4,18 +4,85 @@ use crate::config::{PolygonRoomToolKeybindings, ToolKeybindings};
use crate::dimension_indicator::DimensionIndicator;
use crate::grid::{snap_to_grid, SNAP_SIZE};
use crate::map_data::MapData;
-use crate::math::{self, Polygon, Vec2};
+use crate::math::{self, Polygon, PolygonError, Vec2};
use crate::transform::Transform;
use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
use raylib::ffi::Color;
use raylib::RaylibHandle;
+struct UnfinishedPolygon {
+ pub corners: Vec<Vec2<f32>>,
+ pub working_corner: Vec2<f32>,
+}
+
pub struct PolygonRoomTool {
keybindings: PolygonRoomToolKeybindings,
- unfinished_polygon: Option<Vec<Vec2<f32>>>,
+ unfinished_polygon: Option<UnfinishedPolygon>,
dimension_indicator: DimensionIndicator,
}
+impl UnfinishedPolygon {
+ // Check the validity of the already completed corners only
+ pub fn check_validity_completed(&self) -> Result<(), PolygonError<f32>> {
+ 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<f32>> {
+ // TODO: Is this possible without changing the mutability of self and without reallocation?
+ let mut corners = self.corners.clone();
+ corners.push(self.working_corner);
+ let res = Polygon::check_validity(&corners);
+
+ res
+ }
+
+ pub fn try_into_completed(&mut self) -> Option<Polygon<f32>> {
+ 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<f32>> {
+ 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<f32>> {
+ assert!(self.corners.len() >= 1);
+
+ 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(())
+ }
+}
+
impl PolygonRoomTool {
pub fn new(keybindings: PolygonRoomToolKeybindings) -> Self {
Self {
@@ -42,40 +109,55 @@ impl Tool for PolygonRoomTool {
) {
let mouse_pos_m = transform.point_px_to_m(rl.get_mouse_position().into());
let snapped_mouse_pos_m = snap_to_grid(mouse_pos_m, SNAP_SIZE);
+
// Update the position of the node that would be placed into the polygon next.
- if let Some(ref mut corners) = &mut self.unfinished_polygon {
- let last_element = corners.len() - 1;
- corners[last_element] = snapped_mouse_pos_m;
- self.dimension_indicator.update_dimensions(&corners);
+ if let Some(ref mut polygon) = &mut self.unfinished_polygon {
+ polygon.working_corner = snapped_mouse_pos_m;
+
+ polygon.corners.push(polygon.working_corner);
+ self.dimension_indicator.update_dimensions(&polygon.corners);
+ polygon.working_corner = polygon.corners.pop().unwrap();
}
- if self.keybindings.finish.is_pressed(rl, mouse_blocked)
- && self.unfinished_polygon.is_some()
- {
- // Make sure the polygon is at least a triangle, so it can be drawn.
- if self.unfinished_polygon.as_ref().unwrap().len() >= 3 {
- let polygon = Polygon::new(self.unfinished_polygon.take().unwrap());
- self.dimension_indicator.clear_dimensions();
- map.polygons_mut().push(polygon);
+ /* Check if the finishing keybinding has been pressed. If so, try to turn the part of the
+ * polygon that is already completed into a proper polygon and push it into the map data.
+ */
+ if self.keybindings.finish.is_pressed(rl, mouse_blocked) {
+ if let Some(ref mut polygon) = self.unfinished_polygon {
+ if let Some(polygon) = polygon.try_into_completed() {
+ self.dimension_indicator.clear_dimensions();
+ map.polygons_mut().push(polygon);
+ self.unfinished_polygon = None;
+ }
}
}
+ /* Handle placing a new corner of the polygon. If the corner is placed on the first node,
+ * the polygon will be created.
+ */
if self.keybindings.place_node.is_pressed(rl, mouse_blocked) {
- if let Some(ref mut corners) = self.unfinished_polygon.as_mut() {
- if snapped_mouse_pos_m == corners[0] {
- // Make sure the polygon is at least a triangle, so it can be drawn.
- if corners.len() >= 3 {
- // The last corner is redundant.
- corners.pop();
- let polygon = Polygon::new(self.unfinished_polygon.take().unwrap());
+ 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() {
self.dimension_indicator.clear_dimensions();
map.polygons_mut().push(polygon);
+ self.unfinished_polygon = None;
}
} else {
- corners.push(snapped_mouse_pos_m);
+ // 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);
+ }
}
} else {
- self.unfinished_polygon = Some(vec![snapped_mouse_pos_m, snapped_mouse_pos_m]);
+ // Start a new unfinished polygon
+ self.unfinished_polygon = Some(UnfinishedPolygon {
+ corners: vec![snapped_mouse_pos_m],
+ working_corner: snapped_mouse_pos_m,
+ });
}
}
@@ -104,15 +186,12 @@ impl Tool for PolygonRoomTool {
}
}
- // Draw the current polygon
- if let Some(corners) = &self.unfinished_polygon {
- let mut corners = corners.clone();
- corners.dedup();
- match corners.len() {
- 0 | 1 => {}
- 2 => rld.draw_line_ex(
- transform.point_m_to_px(corners[0]),
- transform.point_m_to_px(corners[1]),
+ 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),
transform.length_m_to_px(0.1),
Color {
r: 150,
@@ -120,9 +199,43 @@ impl Tool for PolygonRoomTool {
b: 150,
a: 255,
},
- ),
- _ => {
- let polygon = Polygon::new(corners);
+ );
+ } 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),
+ Color {
+ r: 150,
+ g: 200,
+ b: 150,
+ a: 255,
+ },
+ )
+ } 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<f32>; 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]),
+ Color {
+ r: 150,
+ g: 200,
+ b: 150,
+ a: 255,
+ },
+ )
+ }
+ } 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<f32>; 3] = triangle.into();
@@ -140,6 +253,7 @@ impl Tool for PolygonRoomTool {
}
}
}
+
self.dimension_indicator.draw(rld, transform);
}
}