From 1a599951cd70a66ebb5b610f308bf6dccc32d5f8 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Tue, 15 Aug 2023 04:04:08 +0200 Subject: [PATCH] Implement basic failure for moving dot to obstructed place Intersection with bends isn't working yet. --- src/bow.rs | 8 +- src/graph.rs | 26 +++-- src/layout.rs | 212 +++++++++++++++++++++++------------ src/main.rs | 286 ++++++++++++++++++++++++++++++++++------------- src/math.rs | 58 ++++++---- src/mesh.rs | 136 +++++++++++++++++----- src/primitive.rs | 139 +++++++++++++++++------ src/rules.rs | 17 +-- src/shape.rs | 108 +++++++++--------- 9 files changed, 681 insertions(+), 309 deletions(-) diff --git a/src/bow.rs b/src/bow.rs index 72d2a9e..555e9b2 100644 --- a/src/bow.rs +++ b/src/bow.rs @@ -1,7 +1,7 @@ use petgraph::stable_graph::StableDiGraph; -use crate::primitive::{Dot, Seg, Bend}; -use crate::graph::{TaggedIndex, DotIndex, SegIndex, BendIndex, TaggedWeight, Label, Path}; +use crate::graph::{BendIndex, DotIndex, Label, Path, SegIndex, TaggedIndex, TaggedWeight}; +use crate::primitive::{Bend, Dot, Seg}; pub struct Bow<'a> { seg1_dot1: DotIndex, @@ -43,11 +43,9 @@ impl<'a> Path for Bow<'a> { fn interior(&self) -> Vec { vec![ TaggedIndex::Seg(self.seg1), - TaggedIndex::Dot(self.seg1_dot2), TaggedIndex::Bend(self.bend), TaggedIndex::Dot(self.seg2_dot1), - TaggedIndex::Seg(self.seg2), ] } @@ -56,11 +54,9 @@ impl<'a> Path for Bow<'a> { vec![ TaggedIndex::Dot(self.seg1_dot1), TaggedIndex::Seg(self.seg1), - TaggedIndex::Dot(self.seg1_dot2), TaggedIndex::Bend(self.bend), TaggedIndex::Dot(self.seg2_dot1), - TaggedIndex::Seg(self.seg2), TaggedIndex::Dot(self.seg2_dot2), ] diff --git a/src/graph.rs b/src/graph.rs index 26b3ab0..f38b5e3 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -1,6 +1,6 @@ -use std::marker::PhantomData; use enum_as_inner::EnumAsInner; use petgraph::stable_graph::NodeIndex; +use std::marker::PhantomData; use crate::math::Circle; @@ -42,14 +42,14 @@ pub enum Label { Core, } -#[derive(Debug, EnumAsInner, Copy, Clone, PartialEq)] +#[derive(Debug, EnumAsInner, Clone, Copy, PartialEq)] pub enum TaggedIndex { Dot(DotIndex), Seg(SegIndex), Bend(BendIndex), } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Index { pub index: NodeIndex, marker: PhantomData, @@ -65,12 +65,18 @@ impl Index { pub fn retag(&self, weight: TaggedWeight) -> TaggedIndex { match weight { - TaggedWeight::Dot(..) => - TaggedIndex::Dot(DotIndex {index: self.index, marker: PhantomData}), - TaggedWeight::Seg(..) => - TaggedIndex::Seg(SegIndex {index: self.index, marker: PhantomData}), - TaggedWeight::Bend(..) => - TaggedIndex::Bend(BendIndex {index: self.index, marker: PhantomData}), + TaggedWeight::Dot(..) => TaggedIndex::Dot(DotIndex { + index: self.index, + marker: PhantomData, + }), + TaggedWeight::Seg(..) => TaggedIndex::Seg(SegIndex { + index: self.index, + marker: PhantomData, + }), + TaggedWeight::Bend(..) => TaggedIndex::Bend(BendIndex { + index: self.index, + marker: PhantomData, + }), } } } @@ -86,7 +92,7 @@ macro_rules! untag { TaggedIndex::Seg($index) => $expr, TaggedIndex::Bend($index) => $expr, } - } + }; } pub type DotIndex = Index; diff --git a/src/layout.rs b/src/layout.rs index b60a117..0260f98 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1,14 +1,14 @@ -use std::cell::{RefCell, Ref}; -use std::rc::Rc; use geo::geometry::Point; +use std::cell::{Ref, RefCell}; +use std::rc::Rc; +use crate::graph::{BendIndex, DotIndex, Path, SegIndex, TaggedIndex}; +use crate::graph::{BendWeight, DotWeight, SegWeight, TaggedWeight}; +use crate::math; use crate::math::Circle; use crate::mesh::Mesh; -use crate::graph::{TaggedIndex, DotIndex, SegIndex, BendIndex, Path}; -use crate::rules::{Rules, Conditions}; +use crate::rules::{Conditions, Rules}; use crate::shape::Shape; -use crate::graph::{TaggedWeight, DotWeight, SegWeight, BendWeight}; -use crate::math; pub struct Layout { mesh: Mesh, @@ -29,20 +29,23 @@ impl Layout { } pub fn route_start(&mut self, from: DotIndex) -> Head { - Head {dot: from, bend: self.mesh.primitive(from).bend()} - } - - pub fn route_finish(&mut self, head: Head, to: DotIndex, width: f64) { - if let Some(bend) = self.mesh.primitive(to).bend() { - self.route_finish_in_bend(head, bend, to, width); - } else { - self.route_finish_in_dot(head, to, width); + Head { + dot: from, + bend: self.mesh.primitive(from).bend(), } } - fn route_finish_in_dot(&mut self, head: Head, to: DotIndex, width: f64) { + pub fn route_finish(&mut self, head: Head, to: DotIndex, width: f64) -> Result<(), ()> { + if let Some(bend) = self.mesh.primitive(to).bend() { + self.route_finish_in_bend(head, bend, to, width) + } else { + self.route_finish_in_dot(head, to, width) + } + } + + fn route_finish_in_dot(&mut self, head: Head, to: DotIndex, width: f64) -> Result<(), ()> { let from_circle = self.head_guidecircle(&head, width); - + let conditions = Conditions { lower_net: None, higher_net: None, @@ -58,11 +61,18 @@ impl Layout { let from_cw = self.head_cw(&head); let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, None); - let head = self.extend_head(head, tangent_points.0); - self.add_seg(head.dot, to, width); + let head = self.extend_head(head, tangent_points.0)?; + self.add_seg(head.dot, to, width)?; + Ok(()) } - fn route_finish_in_bend(&mut self, head: Head, to_bend: BendIndex, to: DotIndex, width: f64) { + fn route_finish_in_bend( + &mut self, + head: Head, + to_bend: BendIndex, + to: DotIndex, + width: f64, + ) -> Result<(), ()> { let from_circle = self.head_guidecircle(&head, width); let conditions = Conditions { @@ -75,26 +85,42 @@ impl Layout { let to_circle = self.bend_circle(to_bend, width); let from_cw = self.head_cw(&head); - let to_head = Head {bend: Some(to_bend), dot: to}; + let to_head = Head { + bend: Some(to_bend), + dot: to, + }; let to_cw = self.head_cw(&to_head); let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, to_cw); - let head = self.extend_head(head, tangent_points.0); + let head = self.extend_head(head, tangent_points.0)?; - let to_head = self.extend_head(to_head, tangent_points.1); - self.add_seg(head.dot, to, width); + let to_head = self.extend_head(to_head, tangent_points.1)?; + self.add_seg(head.dot, to, width)?; + Ok(()) } - pub fn shove_around_dot(&mut self, head: Head, around: DotIndex, cw: bool, width: f64) -> Head { + pub fn shove_around_dot( + &mut self, + head: Head, + around: DotIndex, + cw: bool, + width: f64, + ) -> Result { let outer = self.mesh.primitive(around).outer().unwrap(); - let head = self.route_around_dot(head, around, cw, width); + let head = self.route_around_dot(head, around, cw, width)?; self.mesh.reattach_bend(outer, head.bend.unwrap()); - self.reroute_outward(outer); - head + self.reroute_outward(outer)?; + Ok(head) } - pub fn route_around_dot(&mut self, head: Head, around: DotIndex, cw: bool, width: f64) -> Head { + pub fn route_around_dot( + &mut self, + head: Head, + around: DotIndex, + cw: bool, + width: f64, + ) -> Result { let from_circle = self.head_guidecircle(&head, width); let conditions = Conditions { @@ -109,22 +135,34 @@ impl Layout { let from_cw = self.head_cw(&head); let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw)); - let head = self.extend_head(head, tangent_points.0); + let head = self.extend_head(head, tangent_points.0)?; self.route_seg_bend(head, TaggedIndex::Dot(around), tangent_points.1, cw, width) } - pub fn shove_around_bend(&mut self, head: Head, around: BendIndex, cw: bool, width: f64) -> Head { + pub fn shove_around_bend( + &mut self, + head: Head, + around: BendIndex, + cw: bool, + width: f64, + ) -> Result { let outer = self.mesh.primitive(around).outer().unwrap(); - let head = self.route_around_bend(head, around, cw, width); + let head = self.route_around_bend(head, around, cw, width)?; self.mesh.reattach_bend(outer, head.bend.unwrap()); - self.reroute_outward(outer); - head + self.reroute_outward(outer)?; + Ok(head) } - pub fn route_around_bend(&mut self, head: Head, around: BendIndex, cw: bool, width: f64) -> Head { + pub fn route_around_bend( + &mut self, + head: Head, + around: BendIndex, + cw: bool, + width: f64, + ) -> Result { let from_circle = self.head_guidecircle(&head, width); - + let conditions = Conditions { lower_net: None, higher_net: None, @@ -137,20 +175,32 @@ impl Layout { let from_cw = self.head_cw(&head); let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw)); - let head = self.extend_head(head, tangent_points.0); + let head = self.extend_head(head, tangent_points.0)?; self.route_seg_bend(head, TaggedIndex::Bend(around), tangent_points.1, cw, width) } - fn route_seg_bend(&mut self, head: Head, around: TaggedIndex, to: Point, cw: bool, width: f64) -> Head { - let head = self.route_seg(head, to, width); - let bend_to = self.add_dot(self.mesh.primitive(head.dot).weight()); + fn route_seg_bend( + &mut self, + head: Head, + around: TaggedIndex, + to: Point, + cw: bool, + width: f64, + ) -> Result { + let head = self.route_seg(head, to, width)?; + let bend_to = self.add_dot(self.mesh.primitive(head.dot).weight())?; let net = self.mesh.primitive(head.dot).weight().net; - let bend = self.mesh.add_bend(head.dot, bend_to, around, BendWeight {net, cw}); - Head {dot: bend_to, bend: Some(bend)} + let bend = self + .mesh + .add_bend(head.dot, bend_to, around, BendWeight { net, cw })?; + Ok(Head { + dot: bend_to, + bend: Some(bend), + }) } - fn reroute_outward(&mut self, bend: BendIndex) { + fn reroute_outward(&mut self, bend: BendIndex) -> Result<(), ()> { let mut endss: Vec<[DotIndex; 2]> = vec![]; let mut interiors: Vec> = vec![]; let cw = self.mesh.primitive(bend).weight().cw; @@ -179,43 +229,51 @@ impl Layout { let width = 5.0; if let Some(inner) = maybe_inner { - head = self.route_around_bend(head, inner, cw, width); + head = self.route_around_bend(head, inner, cw, width)?; } else { - head = self.route_around_dot(head, core, cw, width); + head = self.route_around_dot(head, core, cw, width)?; } maybe_inner = head.bend; - self.route_finish(head, ends[1], width); + self.route_finish(head, ends[1], width)?; self.relax_band(maybe_inner.unwrap()); } + + Ok(()) } - fn route_seg(&mut self, head: Head, to: Point, width: f64) -> Head { + fn route_seg(&mut self, head: Head, to: Point, width: f64) -> Result { let net = self.mesh.primitive(head.dot).weight().net; - assert!(width <= self.mesh.primitive(head.dot).weight().circle.r * 2.0); + assert!(width <= self.mesh.primitive(head.dot).weight().circle.r * 2.); let to_index = self.mesh.add_dot(DotWeight { net, - circle: Circle {pos: to, r: width / 2.0}, - }); - self.add_seg(head.dot, to_index, width); - Head {dot: to_index, bend: None} + circle: Circle { + pos: to, + r: width / 2.0, + }, + })?; + self.add_seg(head.dot, to_index, width)?; + Ok(Head { + dot: to_index, + bend: None, + }) } fn relax_band(&mut self, bend: BendIndex) { let mut prev_bend = bend; while let Some(cur_bend) = self.mesh.primitive(prev_bend).prev_akin() { - if self.mesh.primitive(cur_bend).cross_product() >= 0.0 { + if self.mesh.primitive(cur_bend).cross_product() >= 0. { self.release_bow(cur_bend); } - + prev_bend = cur_bend; } let mut prev_bend = bend; while let Some(cur_bend) = self.mesh.primitive(prev_bend).next_akin() { - if self.mesh.primitive(cur_bend).cross_product() >= 0.0 { + if self.mesh.primitive(cur_bend).cross_product() >= 0. { self.release_bow(cur_bend); } @@ -230,15 +288,17 @@ impl Layout { self.mesh.remove_open_set(bow.interior()); let head = self.route_start(ends[0]); - self.route_finish(head, ends[1], 5.0); + let _ = self.route_finish(head, ends[1], 5.); } - pub fn move_dot(&mut self, dot: DotIndex, to: Point) { - self.mesh.move_dot(dot, to); + pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), ()> { + self.mesh.move_dot(dot, to)?; if let Some(outer) = self.mesh.primitive(dot).outer() { - self.reroute_outward(outer); + self.reroute_outward(outer)?; } + + Ok(()) } fn head_guidecircle(&self, head: &Head, width: f64) -> Circle { @@ -256,9 +316,13 @@ impl Layout { if let Some(inner) = self.mesh.primitive(bend).inner() { self.bend_guidecircle(inner, width, conditions) } else { - self.dot_guidecircle(self.mesh.primitive(bend).core().unwrap(), width + 5.0, conditions) + self.dot_guidecircle( + self.mesh.primitive(bend).core().unwrap(), + width + 5.0, + conditions, + ) } - }, + } None => Circle { pos: self.mesh.primitive(head.dot).weight().circle.pos, r: 0.0, @@ -290,7 +354,11 @@ impl Layout { layer = inner; } - let core_circle = self.mesh.primitive(self.mesh.primitive(bend).core().unwrap()).weight().circle; + let core_circle = self + .mesh + .primitive(self.mesh.primitive(bend).core().unwrap()) + .weight() + .circle; Circle { pos: core_circle.pos, r: core_circle.r + r + width + 5.0, @@ -303,11 +371,11 @@ impl Layout { circle } - fn extend_head(&mut self, head: Head, to: Point) -> Head { + fn extend_head(&mut self, head: Head, to: Point) -> Result { if let Some(..) = head.bend { self.extend_head_bend(head, to) } else { - head + Ok(head) // No assertion for now because we temporarily use floats. //println!("{:?} {:?}", self.mesh.weight(TaggedIndex::Dot(from)).as_dot().unwrap().circle.pos, to); @@ -315,21 +383,23 @@ impl Layout { } } - fn extend_head_bend(&mut self, head: Head, to: Point) -> Head { - self.mesh.extend_bend(head.bend.unwrap(), head.dot, to); - head + fn extend_head_bend(&mut self, head: Head, to: Point) -> Result { + self.mesh.extend_bend(head.bend.unwrap(), head.dot, to)?; + Ok(head) } - pub fn add_dot(&mut self, weight: DotWeight) -> DotIndex { + pub fn add_dot(&mut self, weight: DotWeight) -> Result { self.mesh.add_dot(weight) } - pub fn add_seg(&mut self, from: DotIndex, to: DotIndex, width: f64) -> SegIndex { + pub fn add_seg(&mut self, from: DotIndex, to: DotIndex, width: f64) -> Result { let net = self.mesh.primitive(from).weight().net; - self.mesh.add_seg(from, to, SegWeight {net, width}) + self.mesh.add_seg(from, to, SegWeight { net, width }) } - pub fn shapes(&self) -> impl Iterator + '_ { - self.mesh.nodes().map(|ni| untag!(ni, self.mesh.primitive(ni).shape())) + pub fn shapes(&self) -> impl Iterator + '_ { + self.mesh + .nodes() + .map(|ni| untag!(ni, self.mesh.primitive(ni).shape())) } } diff --git a/src/main.rs b/src/main.rs index 2632303..e05a6d2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,40 +4,42 @@ macro_rules! dbg_dot { ($graph:expr) => { use petgraph::dot::Dot; println!("{:?}", Dot::new(&$graph)); - } + }; } -#[macro_use] mod graph; -mod layout; -mod rules; -mod mesh; +#[macro_use] +mod graph; mod bow; -mod primitive; -mod shape; +mod layout; mod math; +mod mesh; +mod primitive; +mod rules; +mod shape; -use std::panic; -use std::time::Duration; use geo::EuclideanDistance; -use graph::{TaggedIndex, Tag}; -use sdl2::EventPump; -use sdl2::pixels::Color; +use graph::{Tag, TaggedIndex}; use sdl2::event::Event; -use sdl2::keyboard::Keycode; use sdl2::gfx::primitives::DrawRenderer; +use sdl2::keyboard::Keycode; +use sdl2::pixels::Color; use sdl2::render::Canvas; use sdl2::video::Window; +use sdl2::EventPump; use shape::Shape; +use std::panic; +use std::time::Duration; -use crate::layout::Layout; use crate::graph::DotWeight; +use crate::layout::Layout; use crate::math::Circle; fn main() { let sdl_context = sdl2::init().unwrap(); let video_subsystem = sdl_context.video().unwrap(); - let window = video_subsystem.window("rust-sdl2 demo", 800, 600) + let window = video_subsystem + .window("rust-sdl2 demo", 800, 600) .position_centered() .build() .unwrap(); @@ -52,7 +54,6 @@ fn main() { let mut i = 0; let mut layout = Layout::new(); - /*let index = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (150.5, 80.5).into(), r: 8.0}}); //layout.route_seg(index, Point {x: 400.5, y: 350.5}, 6.0); @@ -70,7 +71,6 @@ fn main() { let index6 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (140.5, 300.5).into(), r: 8.0}}); let index7 = layout.route_to(index5, index6, 5.0);*/ - /*let dot1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (100.5, 150.5).into(), r: 8.0}}); let dot2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (130.5, 150.5).into(), r: 8.0}}); let dot3 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (160.5, 150.5).into(), r: 8.0}}); @@ -103,86 +103,202 @@ fn main() { let head = layout.route_around_bend(head, bend2_2, true, 5.0); layout.route_finish(head, dot6, 5.0);*/ + let dot1_1 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (100.5, 400.5).into(), + r: 8.0, + }, + }) + .unwrap(); + let dot2_1 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (130.5, 430.5).into(), + r: 8.0, + }, + }) + .unwrap(); + let dot3_1 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (160.5, 460.5).into(), + r: 8.0, + }, + }) + .unwrap(); + let dot4_1 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (190.5, 490.5).into(), + r: 8.0, + }, + }) + .unwrap(); - let dot1_1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (100.5, 400.5).into(), r: 8.0}}); - let dot2_1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (130.5, 430.5).into(), r: 8.0}}); - let dot3_1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (160.5, 460.5).into(), r: 8.0}}); - let dot4_1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (190.5, 490.5).into(), r: 8.0}}); + let dot1_2 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (700.5, 400.5).into(), + r: 8.0, + }, + }) + .unwrap(); + let dot2_2 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (670.5, 430.5).into(), + r: 8.0, + }, + }) + .unwrap(); + let dot3_2 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (640.5, 460.5).into(), + r: 8.0, + }, + }) + .unwrap(); + let dot4_2 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (610.5, 490.5).into(), + r: 8.0, + }, + }) + .unwrap(); - let dot1_2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (700.5, 400.5).into(), r: 8.0}}); - let dot2_2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (670.5, 430.5).into(), r: 8.0}}); - let dot3_2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (640.5, 460.5).into(), r: 8.0}}); - let dot4_2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (610.5, 490.5).into(), r: 8.0}}); + let barrier1_dot1 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (250.5, 150.5).into(), + r: 8.0, + }, + }) + .unwrap(); + let barrier1_dot2 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (250.5, 700.5).into(), + r: 8.0, + }, + }) + .unwrap(); + let _ = layout.add_seg(barrier1_dot1, barrier1_dot2, 16.0); - let barrier1_dot1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (250.5, 150.5).into(), r: 8.0}}); - let barrier1_dot2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (250.5, 700.5).into(), r: 8.0}}); - layout.add_seg(barrier1_dot1, barrier1_dot2, 16.0); - - let barrier2_dot1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (450.5, 200.5).into(), r: 8.0}}); - let barrier2_dot2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (450.5, 700.5).into(), r: 8.0}}); - layout.add_seg(barrier2_dot1, barrier2_dot2, 16.0); - - render_times(&mut event_pump, &mut canvas, &mut layout, None, -1); + let barrier2_dot1 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (420.5, 200.5).into(), + r: 8.0, + }, + }) + .unwrap(); + let barrier2_dot2 = layout + .add_dot(DotWeight { + net: 0, + circle: Circle { + pos: (480.5, 700.5).into(), + r: 8.0, + }, + }) + .unwrap(); + let _ = layout.add_seg(barrier2_dot1, barrier2_dot2, 16.0); + /*render_times(&mut event_pump, &mut canvas, &mut layout, None, -1); let head = layout.route_start(dot1_1); - let head = layout.route_around_dot(head, barrier1_dot1, true, 5.0); + let head = layout + .route_around_dot(head, barrier1_dot1, true, 5.) + .unwrap(); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - let head = layout.route_around_dot(head, barrier2_dot1, true, 5.0); + let head = layout + .route_around_dot(head, barrier2_dot1, true, 5.) + .unwrap(); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - layout.route_finish(head, dot1_2, 5.0); + layout.route_finish(head, dot1_2, 5.0).unwrap(); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - let head = layout.route_start(dot2_1); - let head = layout.shove_around_dot(head, barrier1_dot1, true, 5.0); + let head = layout + .shove_around_dot(head, barrier1_dot1, true, 5.) + .unwrap(); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - let head = layout.shove_around_dot(head, barrier2_dot1, true, 5.0); + let head = layout + .shove_around_dot(head, barrier2_dot1, true, 5.) + .unwrap(); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - layout.route_finish(head, dot2_2, 5.0); + let _ = layout.route_finish(head, dot2_2, 5.0); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - let head = layout.route_start(dot3_1); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - let head = layout.shove_around_dot(head, barrier1_dot1, true, 5.0); + let head = layout + .shove_around_dot(head, barrier1_dot1, true, 5.) + .unwrap(); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - let head = layout.shove_around_dot(head, barrier2_dot1, true, 5.0); + let head = layout + .shove_around_dot(head, barrier2_dot1, true, 5.) + .unwrap(); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - layout.route_finish(head, dot3_2, 5.0); + let _ = layout.route_finish(head, dot3_2, 5.); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - let head = layout.route_start(dot4_1); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - let head = layout.shove_around_dot(head, barrier1_dot1, true, 5.0); + let head = layout + .shove_around_dot(head, barrier1_dot1, true, 5.) + .unwrap(); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - let head = layout.shove_around_dot(head, barrier2_dot1, true, 5.0); + let head = layout + .shove_around_dot(head, barrier2_dot1, true, 5.) + .unwrap(); render_times(&mut event_pump, &mut canvas, &mut layout, None, 50); - layout.route_finish(head, dot4_2, 5.0); - + let _ = layout.route_finish(head, dot4_2, 5.);*/ render_times(&mut event_pump, &mut canvas, &mut layout, None, -1); - render_times(&mut event_pump, &mut canvas, &mut layout, Some(barrier1_dot1.tag()), -1); + render_times( + &mut event_pump, + &mut canvas, + &mut layout, + Some(barrier1_dot1.tag()), + -1, + ); render_times(&mut event_pump, &mut canvas, &mut layout, None, -1); } -fn render_times(event_pump: &mut EventPump, canvas: &mut Canvas, layout: &mut Layout, - follower: Option, times: i64) -{ +fn render_times( + event_pump: &mut EventPump, + canvas: &mut Canvas, + layout: &mut Layout, + follower: Option, + times: i64, +) { let mut i = 0; 'running: loop { @@ -191,10 +307,11 @@ fn render_times(event_pump: &mut EventPump, canvas: &mut Canvas, layout: for event in event_pump.poll_iter() { match event { - Event::Quit {..} | - Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { - break 'running - } + Event::Quit { .. } + | Event::KeyDown { + keycode: Some(Keycode::Escape), + .. + } => break 'running, _ => {} } } @@ -202,26 +319,33 @@ fn render_times(event_pump: &mut EventPump, canvas: &mut Canvas, layout: if let Some(follower) = follower { let state = event_pump.mouse_state(); - layout.move_dot(*follower.as_dot().unwrap(), (state.x() as f64, state.y() as f64).into()); + let _ = layout.move_dot( + *follower.as_dot().unwrap(), + (state.x() as f64, state.y() as f64).into(), + ); } let result = panic::catch_unwind(|| { for shape in layout.shapes() { match shape { Shape::Dot(dot) => { - let _ = canvas.filled_circle(dot.c.pos.x() as i16, - dot.c.pos.y() as i16, - dot.c.r as i16, - Color::RGB(200, 52, 52)); - }, + let _ = canvas.filled_circle( + dot.c.pos.x() as i16, + dot.c.pos.y() as i16, + dot.c.r as i16, + Color::RGB(200, 52, 52), + ); + } Shape::Seg(seg) => { - let _ = canvas.thick_line(seg.from.x() as i16, - seg.from.y() as i16, - seg.to.x() as i16, - seg.to.y() as i16, - seg.width as u8, - Color::RGB(200, 52, 52)); - }, + let _ = canvas.thick_line( + seg.from.x() as i16, + seg.from.y() as i16, + seg.to.x() as i16, + seg.to.y() as i16, + seg.width as u8, + Color::RGB(200, 52, 52), + ); + } Shape::Bend(bend) => { let delta1 = bend.from - bend.center; let delta2 = bend.to - bend.center; @@ -240,17 +364,19 @@ fn render_times(event_pump: &mut EventPump, canvas: &mut Canvas, layout: (r + (d as f64)) as i16, angle1.to_degrees() as i16, angle2.to_degrees() as i16, - Color::RGB(200, 52, 52)); + Color::RGB(200, 52, 52), + ); } - }, + } } - /*let envelope = shape.envelope(); - let _ = canvas.rectangle(envelope.lower()[0] as i16, - envelope.lower()[1] as i16, - envelope.upper()[0] as i16, - envelope.upper()[1] as i16, - - Color::RGB(100, 100, 100));*/ + let envelope = shape.envelope(); + let _ = canvas.rectangle( + envelope.lower()[0] as i16, + envelope.lower()[1] as i16, + envelope.upper()[0] as i16, + envelope.upper()[1] as i16, + Color::RGB(100, 100, 100), + ); } }); diff --git a/src/math.rs b/src/math.rs index 1a0023b..a7f0937 100644 --- a/src/math.rs +++ b/src/math.rs @@ -1,5 +1,5 @@ +use geo::{geometry::Point, point, EuclideanDistance}; use std::ops::Sub; -use geo::{geometry::Point, EuclideanDistance, point}; #[derive(Debug, Clone, Copy, PartialEq)] pub struct Line { @@ -19,7 +19,10 @@ impl Sub for Circle { fn sub(self, other: Self) -> Self { //return Self{pos: Point{x: self.pos.x() - other.pos.x(), y: self.pos.y() - other.pos.y()}, r: self.r}; - return Self {pos: self.pos - other.pos, r: self.r}; + return Self { + pos: self.pos - other.pos, + r: self.r, + }; } } @@ -59,23 +62,43 @@ fn _tangents(circle1: Circle, circle2: Circle) -> [Line; 4] { fn cast_point_to_line(pt: Point, line: Line) -> Point { return ( - (line.b * (line.b * pt.x() - line.a * pt.y()) - line.a * line.c) / (line.a * line.a + line.b * line.b), - (line.a * (-line.b * pt.x() + line.a * pt.y()) - line.b * line.c) / (line.a * line.a + line.b * line.b), - ).into(); + (line.b * (line.b * pt.x() - line.a * pt.y()) - line.a * line.c) + / (line.a * line.a + line.b * line.b), + (line.a * (-line.b * pt.x() + line.a * pt.y()) - line.b * line.c) + / (line.a * line.a + line.b * line.b), + ) + .into(); } pub fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> [(Point, Point); 4] { let tgs = _tangents(circle1, circle2); [ - (cast_point_to_line(circle1.pos, tgs[0]), cast_point_to_line(circle2.pos, tgs[0])), - (cast_point_to_line(circle1.pos, tgs[1]), cast_point_to_line(circle2.pos, tgs[1])), - (cast_point_to_line(circle1.pos, tgs[2]), cast_point_to_line(circle2.pos, tgs[2])), - (cast_point_to_line(circle1.pos, tgs[3]), cast_point_to_line(circle2.pos, tgs[3])), + ( + cast_point_to_line(circle1.pos, tgs[0]), + cast_point_to_line(circle2.pos, tgs[0]), + ), + ( + cast_point_to_line(circle1.pos, tgs[1]), + cast_point_to_line(circle2.pos, tgs[1]), + ), + ( + cast_point_to_line(circle1.pos, tgs[2]), + cast_point_to_line(circle2.pos, tgs[2]), + ), + ( + cast_point_to_line(circle1.pos, tgs[3]), + cast_point_to_line(circle2.pos, tgs[3]), + ), ] } -pub fn tangent_point_pair(circle1: Circle, cw1: Option, circle2: Circle, cw2: Option) -> (Point, Point) { +pub fn tangent_point_pair( + circle1: Circle, + cw1: Option, + circle2: Circle, + cw2: Option, +) -> (Point, Point) { let tangent_point_pairs = tangent_point_pairs(circle1, circle2); for tangent_point_pair in tangent_point_pairs { @@ -116,22 +139,19 @@ pub fn circles_intersection(circle1: &Circle, circle2: &Circle) -> Vec { } // Distance from `circle1.pos` to the intersection of the diagonals. - let a = (circle1.r*circle1.r - circle2.r*circle2.r + d*d) / (2.0*d); + let a = (circle1.r * circle1.r - circle2.r * circle2.r + d * d) / (2.0 * d); // Intersection of the diagonals. - let p = circle1.pos + delta*(a/d); - let h = (circle1.r*circle1.r - a*a).sqrt(); + let p = circle1.pos + delta * (a / d); + let h = (circle1.r * circle1.r - a * a).sqrt(); if h == 0. { return [p].into(); } - let r = point! {x: -delta.x(), y: delta.y()} * (h/d); - - [ - p + r, - p - r, - ].into() + let r = point! {x: -delta.x(), y: delta.y()} * (h / d); + + [p + r, p - r].into() } pub fn between_vectors(v: Point, from: Point, to: Point) -> bool { diff --git a/src/mesh.rs b/src/mesh.rs index f5e8ece..e5d26aa 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -1,14 +1,17 @@ use geo::Point; -use petgraph::Direction::Incoming; use petgraph::stable_graph::StableDiGraph; use petgraph::visit::EdgeRef; -use rstar::RTree; +use petgraph::Direction::Incoming; use rstar::primitives::GeomWithData; +use rstar::RTree; +use crate::bow::Bow; +use crate::graph::{ + BendIndex, BendWeight, DotIndex, DotWeight, Index, Label, Path, SegIndex, SegWeight, Tag, + TaggedIndex, TaggedWeight, +}; use crate::primitive::Primitive; use crate::shape::Shape; -use crate::graph::{Tag, TaggedIndex, DotIndex, SegIndex, BendIndex, Index, TaggedWeight, DotWeight, SegWeight, BendWeight, Label, Path}; -use crate::bow::Bow; pub type RTreeWrapper = GeomWithData; @@ -32,7 +35,7 @@ impl Mesh { // We must remove the dots only after the segs and bends because we need dots to calculate // the shapes, which we need to remove the segs and bends from the R-tree. - + for index in open_set.iter().filter(|index| index.is_dot()) { untag!(index, self.remove(*index)); } @@ -47,55 +50,94 @@ impl Mesh { self.graph.remove_node(index.index); } - pub fn add_dot(&mut self, weight: DotWeight) -> DotIndex { + pub fn add_dot(&mut self, weight: DotWeight) -> Result { let dot = DotIndex::new(self.graph.add_node(TaggedWeight::Dot(weight))); - self.rtree.insert(RTreeWrapper::new(self.primitive(dot).shape(), TaggedIndex::Dot(dot))); - dot + self.fail_and_remove_if_collides(dot)?; + + self.rtree.insert(RTreeWrapper::new( + self.primitive(dot).shape(), + TaggedIndex::Dot(dot), + )); + Ok(dot) } - pub fn add_seg(&mut self, from: DotIndex, to: DotIndex, weight: SegWeight) -> SegIndex { + pub fn add_seg( + &mut self, + from: DotIndex, + to: DotIndex, + weight: SegWeight, + ) -> Result { let seg = SegIndex::new(self.graph.add_node(TaggedWeight::Seg(weight))); + self.fail_and_remove_if_collides(seg)?; + self.graph.add_edge(from.index, seg.index, Label::End); self.graph.add_edge(seg.index, to.index, Label::End); - self.rtree.insert(RTreeWrapper::new(self.primitive(seg).shape(), TaggedIndex::Seg(seg))); - seg + self.insert_into_rtree(seg.tag()); + Ok(seg) } - pub fn add_bend(&mut self, from: DotIndex, to: DotIndex, around: TaggedIndex, weight: BendWeight) -> BendIndex { + pub fn add_bend( + &mut self, + from: DotIndex, + to: DotIndex, + around: TaggedIndex, + weight: BendWeight, + ) -> Result { match around { - TaggedIndex::Dot(core) => - self.add_core_bend(from, to, core, weight), - TaggedIndex::Bend(around) => - self.add_outer_bend(from, to, around, weight), + TaggedIndex::Dot(core) => self.add_core_bend(from, to, core, weight), + TaggedIndex::Bend(around) => self.add_outer_bend(from, to, around, weight), TaggedIndex::Seg(..) => unreachable!(), } } - pub fn add_core_bend(&mut self, from: DotIndex, to: DotIndex, core: DotIndex, weight: BendWeight) -> BendIndex { + pub fn add_core_bend( + &mut self, + from: DotIndex, + to: DotIndex, + core: DotIndex, + weight: BendWeight, + ) -> Result { let bend = BendIndex::new(self.graph.add_node(TaggedWeight::Bend(weight))); + self.fail_and_remove_if_collides(bend)?; + self.graph.add_edge(from.index, bend.index, Label::End); self.graph.add_edge(bend.index, to.index, Label::End); self.graph.add_edge(bend.index, core.index, Label::Core); - self.rtree.insert(RTreeWrapper::new(self.primitive(bend).shape(), TaggedIndex::Bend(bend))); - bend + self.insert_into_rtree(bend.tag()); + Ok(bend) } - pub fn add_outer_bend(&mut self, from: DotIndex, to: DotIndex, inner: BendIndex, weight: BendWeight) -> BendIndex { - let core = *self.graph.neighbors(inner.index) - .filter(|ni| self.graph.edge_weight(self.graph.find_edge(inner.index, *ni).unwrap()).unwrap().is_core()) + pub fn add_outer_bend( + &mut self, + from: DotIndex, + to: DotIndex, + inner: BendIndex, + weight: BendWeight, + ) -> Result { + let core = *self + .graph + .neighbors(inner.index) + .filter(|ni| { + self.graph + .edge_weight(self.graph.find_edge(inner.index, *ni).unwrap()) + .unwrap() + .is_core() + }) .map(|ni| DotIndex::new(ni)) .collect::>() .first() .unwrap(); - let bend = self.add_core_bend(from, to, core, weight); + let bend = self.add_core_bend(from, to, core, weight)?; self.graph.add_edge(inner.index, bend.index, Label::Outer); - bend + Ok(bend) } pub fn reattach_bend(&mut self, bend: BendIndex, inner: BendIndex) { - if let Some(old_inner_edge) = self.graph.edges_directed(bend.index, Incoming) + if let Some(old_inner_edge) = self + .graph + .edges_directed(bend.index, Incoming) .filter(|edge| *edge.weight() == Label::Outer) .next() { @@ -104,13 +146,14 @@ impl Mesh { self.graph.add_edge(inner.index, bend.index, Label::Outer); } - pub fn extend_bend(&mut self, bend: BendIndex, dot: DotIndex, to: Point) { + pub fn extend_bend(&mut self, bend: BendIndex, dot: DotIndex, to: Point) -> Result<(), ()> { self.remove_from_rtree(bend.tag()); - self.move_dot(dot, to); + self.move_dot(dot, to)?; self.insert_into_rtree(bend.tag()); + Ok(()) } - pub fn move_dot(&mut self, dot: DotIndex, to: Point) { + pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), ()> { let mut cur_bend = self.primitive(dot).outer(); loop { match cur_bend { @@ -119,15 +162,25 @@ impl Mesh { } self.remove_from_rtree(cur_bend.unwrap().tag()); - cur_bend = self.primitive(cur_bend.unwrap()).outer() + cur_bend = self.primitive(cur_bend.unwrap()).outer(); } self.remove_from_rtree(dot.tag()); let mut dot_weight = self.primitive(dot).weight(); + let old_weight = dot_weight; + dot_weight.circle.pos = to; *self.graph.node_weight_mut(dot.index).unwrap() = TaggedWeight::Dot(dot_weight); + if let Some(..) = self.detect_collision(&self.primitive(dot).shape()) { + // Restore original state. + *self.graph.node_weight_mut(dot.index).unwrap() = TaggedWeight::Dot(old_weight); + self.insert_into_rtree(dot.tag()); + + return Err(()); + } + self.insert_into_rtree(dot.tag()); let mut cur_bend = self.primitive(dot).outer(); @@ -138,11 +191,13 @@ impl Mesh { } self.insert_into_rtree(cur_bend.unwrap().tag()); - cur_bend = self.primitive(cur_bend.unwrap()).outer() + cur_bend = self.primitive(cur_bend.unwrap()).outer(); } + + Ok(()) } - pub fn nodes(&self) -> impl Iterator + '_ { + pub fn nodes(&self) -> impl Iterator + '_ { self.rtree.iter().map(|wrapper| wrapper.data) } @@ -154,6 +209,25 @@ impl Mesh { Bow::new(bend, &self.graph) } + fn fail_and_remove_if_collides( + &mut self, + index: Index, + ) -> Result<(), ()> { + /*if self.detect_collision(&self.primitive(index).shape()) { + self.remove(index); + return Err(()); + }*/ + Ok(()) + } + + fn detect_collision(&self, shape: &Shape) -> Option { + self.rtree + .locate_in_envelope_intersecting(&shape.envelope()) + .filter(|wrapper| shape.intersects(wrapper.geom())) + .map(|wrapper| wrapper.data) + .next() + } + fn insert_into_rtree(&mut self, index: TaggedIndex) { let shape = untag!(index, self.primitive(index).shape()); self.rtree.insert(RTreeWrapper::new(shape, index)); diff --git a/src/primitive.rs b/src/primitive.rs index bef6efa..9d3de27 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -1,11 +1,14 @@ -use std::mem::{swap, self}; +use std::mem::{self, swap}; -use petgraph::Direction::{Outgoing, Incoming}; use petgraph::stable_graph::StableDiGraph; +use petgraph::Direction::{Incoming, Outgoing}; -use crate::graph::{Path, DotIndex, SegIndex, BendIndex, TaggedIndex, Tag, Index, DotWeight, SegWeight, BendWeight, TaggedWeight, Label}; +use crate::graph::{ + BendIndex, BendWeight, DotIndex, DotWeight, Index, Label, Path, SegIndex, SegWeight, Tag, + TaggedIndex, TaggedWeight, +}; use crate::math; -use crate::shape::{Shape, DotShape, SegShape, BendShape}; +use crate::shape::{BendShape, DotShape, SegShape, Shape}; #[derive(Debug)] pub struct Primitive<'a, Weight> { @@ -15,14 +18,12 @@ pub struct Primitive<'a, Weight> { impl<'a, Weight> Primitive<'a, Weight> { pub fn new(index: Index, graph: &'a StableDiGraph) -> Self { - Self {index, graph} + Self { index, graph } } pub fn shape(&self) -> Shape { match self.tagged_weight() { - TaggedWeight::Dot(dot) => Shape::Dot(DotShape { - c: dot.circle, - }), + TaggedWeight::Dot(dot) => Shape::Dot(DotShape { c: dot.circle }), TaggedWeight::Seg(seg) => { let ends = self.ends(); Shape::Seg(SegShape { @@ -30,7 +31,7 @@ impl<'a, Weight> Primitive<'a, Weight> { to: self.primitive(ends[1]).weight().circle.pos, width: seg.width, }) - }, + } TaggedWeight::Bend(bend) => { let ends = self.ends(); let mut bend_shape = BendShape { @@ -44,13 +45,19 @@ impl<'a, Weight> Primitive<'a, Weight> { swap(&mut bend_shape.from, &mut bend_shape.to); } Shape::Bend(bend_shape) - }, + } } } pub fn next(&self) -> Option { - self.graph.neighbors_directed(self.index.index, Outgoing) - .filter(|ni| self.graph.edge_weight(self.graph.find_edge(self.index.index, *ni).unwrap()).unwrap().is_end()) + self.graph + .neighbors_directed(self.index.index, Outgoing) + .filter(|ni| { + self.graph + .edge_weight(self.graph.find_edge(self.index.index, *ni).unwrap()) + .unwrap() + .is_end() + }) .map(|ni| Index::