From b7ff5073028e6437723fd90c48e86d2a573d1cb0 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Wed, 18 Oct 2023 02:33:03 +0000 Subject: [PATCH] shape: Use `enum_dispatch` for `Shape` --- src/draw.rs | 8 +- src/guide.rs | 2 +- src/layout.rs | 8 +- src/main.rs | 29 +++-- src/mesh.rs | 3 +- src/primitive.rs | 2 +- src/shape.rs | 296 +++++++++++++++++++++++++---------------------- src/tracer.rs | 2 +- 8 files changed, 188 insertions(+), 162 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index a7bc975..1000a88 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -12,11 +12,11 @@ use crate::{ }; #[enum_dispatch] -pub trait HeadDot { +pub trait HeadTrait { fn dot(&self) -> DotIndex; } -#[enum_dispatch(HeadDot)] +#[enum_dispatch(HeadTrait)] #[derive(Debug, Clone, Copy)] pub enum Head { Bare(BareHead), @@ -28,7 +28,7 @@ pub struct BareHead { pub dot: DotIndex, } -impl HeadDot for BareHead { +impl HeadTrait for BareHead { fn dot(&self) -> DotIndex { self.dot } @@ -40,7 +40,7 @@ pub struct SegbendHead { pub segbend: Segbend, } -impl HeadDot for SegbendHead { +impl HeadTrait for SegbendHead { fn dot(&self) -> DotIndex { self.dot } diff --git a/src/guide.rs b/src/guide.rs index 4fad7b8..c8d524a 100644 --- a/src/guide.rs +++ b/src/guide.rs @@ -1,7 +1,7 @@ use geo::Line; use crate::{ - draw::{Head, HeadDot, SegbendHead}, + draw::{Head, HeadTrait, SegbendHead}, graph::{BendIndex, DotIndex}, layout::Layout, math::{self, Circle}, diff --git a/src/layout.rs b/src/layout.rs index 21be337..77209aa 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -4,7 +4,7 @@ use petgraph::stable_graph::StableDiGraph; use petgraph::visit::EdgeRef; use petgraph::Direction::Incoming; use rstar::primitives::GeomWithData; -use rstar::RTree; +use rstar::{RTree, RTreeObject}; use spade::Triangulation; use crate::band::Band; @@ -15,7 +15,7 @@ use crate::graph::{ }; use crate::primitive::Primitive; use crate::segbend::Segbend; -use crate::shape::Shape; +use crate::shape::{Shape, ShapeTrait}; pub type RTreeWrapper = GeomWithData; @@ -323,7 +323,7 @@ impl Layout { let shape = primitive.shape(); self.rtree - .locate_in_envelope_intersecting(&shape.envelope()) + .locate_in_envelope_intersecting(&RTreeObject::envelope(&shape)) .filter(|wrapper| { let other_index = wrapper.data; !untag!(other_index, primitive.connectable(other_index)) @@ -358,7 +358,7 @@ impl Layout { let wrapper = RTreeWrapper::new(shape, index); !self .rtree - .locate_in_envelope(&shape.envelope()) + .locate_in_envelope(&RTreeObject::envelope(&shape)) .any(|w| *w == wrapper) }) } diff --git a/src/main.rs b/src/main.rs index b21fc13..eda0a17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,6 +30,7 @@ use layout::Layout; use mesh::{Mesh, MeshEdgeReference, VertexIndex}; use petgraph::visit::{EdgeRef, IntoEdgeReferences}; use router::RouterObserver; +use rstar::RTreeObject; use sdl2::event::Event; use sdl2::gfx::primitives::DrawRenderer; use sdl2::keyboard::Keycode; @@ -68,7 +69,7 @@ impl<'a> DebugRouterObserver<'a> { impl<'a> RouterObserver for DebugRouterObserver<'a> { fn on_rework(&mut self, tracer: &Tracer, trace: &Trace) { - /*render_times( + render_times( self.event_pump, self.canvas, RouterOrLayout::Layout(tracer.layout), @@ -77,13 +78,13 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> { Some(tracer.mesh.clone()), &trace.path, 20, - );*/ + ); } fn before_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) { let mut path = trace.path.clone(); path.push(edge.target()); - /*render_times( + render_times( self.event_pump, self.canvas, RouterOrLayout::Layout(tracer.layout), @@ -92,11 +93,11 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> { Some(tracer.mesh.clone()), &path, 5, - );*/ + ); } fn on_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) { - /*render_times( + render_times( self.event_pump, self.canvas, RouterOrLayout::Layout(tracer.layout), @@ -105,7 +106,7 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> { Some(tracer.mesh.clone()), &trace.path, 5, - );*/ + ); } fn on_estimate(&mut self, _tracer: &Tracer, _vertex: VertexIndex) {} @@ -335,7 +336,7 @@ fn main() { }, );*/ - render_times( + /*render_times( &mut event_pump, &mut canvas, RouterOrLayout::Layout(&router.layout), @@ -355,6 +356,12 @@ fn main() { None, &[], -1, + );*/ + + let _ = router.enroute( + dot1, + dot_end, + &mut DebugRouterObserver::new(&mut event_pump, &mut canvas), ); render_times( @@ -486,17 +493,17 @@ fn render_times( } } } - /*let envelope = shape.envelope(); + 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), - );*/ + ); } - /*if let Some(ref mesh) = mesh { + if let Some(ref mesh) = mesh { for edge in mesh.edge_references() { let endpoints = (mesh.position(edge.source()), mesh.position(edge.target())); @@ -514,7 +521,7 @@ fn render_times( color, ); } - }*/ + } //}); canvas.present(); diff --git a/src/mesh.rs b/src/mesh.rs index 5de3d66..1244915 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -7,11 +7,12 @@ use spade::{ DelaunayTriangulation, HasPosition, InsertionError, Point2, Triangulation, }; +use crate::shape::ShapeTrait; use crate::{graph::DotIndex, layout::Layout}; #[derive(Debug, Clone)] struct Vertex { - pub dot: DotIndex, + dot: DotIndex, x: f64, y: f64, } diff --git a/src/primitive.rs b/src/primitive.rs index a8028aa..68db0e9 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -8,7 +8,7 @@ use crate::graph::{ TaggedIndex, TaggedWeight, }; use crate::math::{self, Circle}; -use crate::shape::{BendShape, DotShape, SegShape, Shape}; +use crate::shape::{BendShape, DotShape, SegShape, Shape, ShapeTrait}; #[derive(Debug)] pub struct Primitive<'a, Weight> { diff --git a/src/shape.rs b/src/shape.rs index 6da1250..90a9d30 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -1,14 +1,80 @@ use enum_as_inner::EnumAsInner; +use enum_dispatch::enum_dispatch; use geo::{point, polygon, EuclideanDistance, Intersects, Point, Polygon, Rotate}; use rstar::{RTreeObject, AABB}; use crate::math::{self, Circle}; +#[enum_dispatch] +pub trait ShapeTrait { + fn priority(&self) -> u64; + fn center(&self) -> Point; + fn intersects(&self, other: &Shape) -> bool; + fn envelope(&self) -> AABB<[f64; 2]>; + fn width(&self) -> f64; +} + +#[enum_dispatch(ShapeTrait)] +#[derive(Debug, Clone, Copy, EnumAsInner, PartialEq)] +pub enum Shape { + // Intentionally in different order to reorder `self.intersects(...)` properly. + Dot(DotShape), + Seg(SegShape), + Bend(BendShape), +} + #[derive(Debug, Clone, Copy, PartialEq)] pub struct DotShape { pub c: Circle, } +impl ShapeTrait for DotShape { + fn priority(&self) -> u64 { + 3 + } + + fn center(&self) -> Point { + self.c.pos + } + + fn intersects(&self, other: &Shape) -> bool { + if self.priority() < other.priority() { + return other.intersects(&Shape::from(*self)); + } + + match other { + Shape::Dot(other) => self.c.pos.euclidean_distance(&other.c.pos) < self.c.r + other.c.r, + Shape::Seg(other) => self.c.pos.euclidean_distance(&other.polygon()) < self.c.r, + Shape::Bend(other) => { + for point in math::intersect_circles(&self.c, &other.inner_circle()) { + if other.between_ends(point) { + return true; + } + } + + for point in math::intersect_circles(&self.c, &other.outer_circle()) { + if other.between_ends(point) { + return true; + } + } + + false + } + } + } + + fn envelope(&self) -> AABB<[f64; 2]> { + AABB::from_corners( + [self.c.pos.x() - self.c.r, self.c.pos.y() - self.c.r], + [self.c.pos.x() + self.c.r, self.c.pos.y() + self.c.r], + ) + } + + fn width(&self) -> f64 { + self.c.r * 2.0 + } +} + #[derive(Debug, Clone, Copy, PartialEq)] pub struct SegShape { pub from: Point, @@ -33,6 +99,61 @@ impl SegShape { } } +impl ShapeTrait for SegShape { + fn priority(&self) -> u64 { + 2 + } + + fn center(&self) -> Point { + (self.from + self.to) / 2.0 + } + + fn intersects(&self, other: &Shape) -> bool { + if self.priority() < other.priority() { + return other.intersects(&Shape::from(*self)); + } + + match other { + Shape::Dot(..) => unreachable!(), + Shape::Seg(other) => self.polygon().intersects(&other.polygon()), + Shape::Bend(other) => { + for segment in self.polygon().exterior().lines() { + let inner_circle = other.inner_circle(); + let outer_circle = other.outer_circle(); + + for point in math::intersect_circle_segment(&inner_circle, &segment) { + if other.between_ends(point) { + return true; + } + } + + for point in math::intersect_circle_segment(&outer_circle, &segment) { + if other.between_ends(point) { + return true; + } + } + } + + false + } + } + } + + fn envelope(&self) -> AABB<[f64; 2]> { + let points: Vec<[f64; 2]> = self + .polygon() + .exterior() + .points() + .map(|p| [p.x(), p.y()]) + .collect(); + AABB::<[f64; 2]>::from_points(points.iter()) + } + + fn width(&self) -> f64 { + self.width + } +} + #[derive(Debug, Clone, Copy, PartialEq)] pub struct BendShape { pub from: Point, @@ -69,172 +190,69 @@ impl BendShape { } } -// TODO: Use enum_dispatch. -#[derive(Debug, Clone, Copy, EnumAsInner, PartialEq)] -pub enum Shape { - // Intentionally in different order to reorder `self.intersects(...)` properly. - Dot(DotShape), - Seg(SegShape), - Bend(BendShape), -} - -impl Shape { - pub fn principal_point(&self) -> Point { - match self { - Shape::Dot(dot) => dot.c.pos, - Shape::Seg(seg) => seg.from, - Shape::Bend(bend) => bend.from, - } +impl ShapeTrait for BendShape { + fn priority(&self) -> u64 { + 1 } - pub fn center(&self) -> Point { - match self { - Shape::Dot(dot) => dot.c.pos, - Shape::Seg(seg) => (seg.from + seg.to) / 2.0, - Shape::Bend(bend) => { - let sum = (bend.from - bend.c.pos) + (bend.to - bend.c.pos); - bend.c.pos + (sum / sum.euclidean_distance(&point! {x: 0.0, y: 0.0})) * bend.c.r - } - } + fn center(&self) -> Point { + let sum = (self.from - self.c.pos) + (self.to - self.c.pos); + self.c.pos + (sum / sum.euclidean_distance(&point! {x: 0.0, y: 0.0})) * self.c.r } - fn priority(&self) -> i64 { - match self { - Shape::Dot(..) => 3, - Shape::Seg(..) => 2, - Shape::Bend(..) => 1, - } - } - - pub fn intersects(&self, other: &Shape) -> bool { + fn intersects(&self, other: &Shape) -> bool { if self.priority() < other.priority() { - return other.intersects(self); + return other.intersects(&Shape::from(*self)); } - match self { - Shape::Dot(dot) => match other { - Shape::Dot(other) => { - dot.c.pos.euclidean_distance(&other.c.pos) < dot.c.r + other.c.r + match other { + Shape::Dot(..) | Shape::Seg(..) => unreachable!(), + Shape::Bend(other) => { + for point in math::intersect_circles(&self.inner_circle(), &other.inner_circle()) { + if self.between_ends(point) && other.between_ends(point) { + return true; + } } - Shape::Seg(other) => dot.c.pos.euclidean_distance(&other.polygon()) < dot.c.r, - Shape::Bend(other) => { - for point in math::intersect_circles(&dot.c, &other.inner_circle()) { - if other.between_ends(point) { - return true; - } - } - for point in math::intersect_circles(&dot.c, &other.outer_circle()) { - if other.between_ends(point) { - return true; - } + for point in math::intersect_circles(&self.inner_circle(), &other.outer_circle()) { + if self.between_ends(point) && other.between_ends(point) { + return true; } - - false } - }, - Shape::Seg(seg) => match other { - Shape::Dot(..) => unreachable!(), - Shape::Seg(other) => seg.polygon().intersects(&other.polygon()), - Shape::Bend(other) => { - for segment in seg.polygon().exterior().lines() { - let inner_circle = other.inner_circle(); - let outer_circle = other.outer_circle(); - for point in math::intersect_circle_segment(&inner_circle, &segment) { - if other.between_ends(point) { - return true; - } - } - - for point in math::intersect_circle_segment(&outer_circle, &segment) { - if other.between_ends(point) { - return true; - } - } + for point in math::intersect_circles(&self.outer_circle(), &other.inner_circle()) { + if self.between_ends(point) && other.between_ends(point) { + return true; } - - false } - }, - Shape::Bend(bend) => match other { - Shape::Dot(..) | Shape::Seg(..) => unreachable!(), - Shape::Bend(other) => { - for point in - math::intersect_circles(&bend.inner_circle(), &other.inner_circle()) - { - if bend.between_ends(point) && other.between_ends(point) { - return true; - } - } - for point in - math::intersect_circles(&bend.inner_circle(), &other.outer_circle()) - { - if bend.between_ends(point) && other.between_ends(point) { - return true; - } + for point in math::intersect_circles(&self.outer_circle(), &other.outer_circle()) { + if self.between_ends(point) && other.between_ends(point) { + return true; } - - for point in - math::intersect_circles(&bend.outer_circle(), &other.inner_circle()) - { - if bend.between_ends(point) && other.between_ends(point) { - return true; - } - } - - for point in - math::intersect_circles(&bend.outer_circle(), &other.outer_circle()) - { - if bend.between_ends(point) && other.between_ends(point) { - return true; - } - } - - false } - }, - } - } - pub fn envelope(&self) -> AABB<[f64; 2]> { - match self { - Shape::Dot(dot) => AABB::from_corners( - [dot.c.pos.x() - dot.c.r, dot.c.pos.y() - dot.c.r], - [dot.c.pos.x() + dot.c.r, dot.c.pos.y() + dot.c.r], - ), - Shape::Seg(seg) => { - let points: Vec<[f64; 2]> = seg - .polygon() - .exterior() - .points() - .map(|p| [p.x(), p.y()]) - .collect(); - AABB::<[f64; 2]>::from_points(points.iter()) - } - Shape::Bend(bend) => { - let halfwidth = bend.c.r + bend.width; - AABB::from_corners( - [bend.c.pos.x() - halfwidth, bend.c.pos.y() - halfwidth], - [bend.c.pos.x() + halfwidth, bend.c.pos.y() + halfwidth], - ) + false } } } - pub fn width(&self) -> f64 { - match self { - Shape::Dot(dot) => dot.c.r * 2.0, - Shape::Seg(seg) => seg.width, - Shape::Bend(bend) => bend.width, - } + fn envelope(&self) -> AABB<[f64; 2]> { + let halfwidth = self.c.r + self.width; + AABB::from_corners( + [self.c.pos.x() - halfwidth, self.c.pos.y() - halfwidth], + [self.c.pos.x() + halfwidth, self.c.pos.y() + halfwidth], + ) + } + + fn width(&self) -> f64 { + self.width } } impl RTreeObject for Shape { type Envelope = AABB<[f64; 2]>; fn envelope(&self) -> Self::Envelope { - return self.envelope(); + return ShapeTrait::envelope(self); } } diff --git a/src/tracer.rs b/src/tracer.rs index 245085c..429c6e7 100644 --- a/src/tracer.rs +++ b/src/tracer.rs @@ -2,7 +2,7 @@ use contracts::debug_ensures; use crate::{ bow::Bow, - draw::{BareHead, Draw, Head, HeadDot, SegbendHead}, + draw::{BareHead, Draw, Head, HeadTrait, SegbendHead}, graph::{BendIndex, DotIndex, Ends}, layout::Layout, mesh::{Mesh, MeshEdgeReference, VertexIndex},