shape: Use `enum_dispatch` for `Shape`

This commit is contained in:
Mikolaj Wielgus 2023-10-18 02:33:03 +00:00
parent 26778e7d47
commit b7ff507302
8 changed files with 188 additions and 162 deletions

View File

@ -12,11 +12,11 @@ use crate::{
}; };
#[enum_dispatch] #[enum_dispatch]
pub trait HeadDot { pub trait HeadTrait {
fn dot(&self) -> DotIndex; fn dot(&self) -> DotIndex;
} }
#[enum_dispatch(HeadDot)] #[enum_dispatch(HeadTrait)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Head { pub enum Head {
Bare(BareHead), Bare(BareHead),
@ -28,7 +28,7 @@ pub struct BareHead {
pub dot: DotIndex, pub dot: DotIndex,
} }
impl HeadDot for BareHead { impl HeadTrait for BareHead {
fn dot(&self) -> DotIndex { fn dot(&self) -> DotIndex {
self.dot self.dot
} }
@ -40,7 +40,7 @@ pub struct SegbendHead {
pub segbend: Segbend, pub segbend: Segbend,
} }
impl HeadDot for SegbendHead { impl HeadTrait for SegbendHead {
fn dot(&self) -> DotIndex { fn dot(&self) -> DotIndex {
self.dot self.dot
} }

View File

@ -1,7 +1,7 @@
use geo::Line; use geo::Line;
use crate::{ use crate::{
draw::{Head, HeadDot, SegbendHead}, draw::{Head, HeadTrait, SegbendHead},
graph::{BendIndex, DotIndex}, graph::{BendIndex, DotIndex},
layout::Layout, layout::Layout,
math::{self, Circle}, math::{self, Circle},

View File

@ -4,7 +4,7 @@ use petgraph::stable_graph::StableDiGraph;
use petgraph::visit::EdgeRef; use petgraph::visit::EdgeRef;
use petgraph::Direction::Incoming; use petgraph::Direction::Incoming;
use rstar::primitives::GeomWithData; use rstar::primitives::GeomWithData;
use rstar::RTree; use rstar::{RTree, RTreeObject};
use spade::Triangulation; use spade::Triangulation;
use crate::band::Band; use crate::band::Band;
@ -15,7 +15,7 @@ use crate::graph::{
}; };
use crate::primitive::Primitive; use crate::primitive::Primitive;
use crate::segbend::Segbend; use crate::segbend::Segbend;
use crate::shape::Shape; use crate::shape::{Shape, ShapeTrait};
pub type RTreeWrapper = GeomWithData<Shape, TaggedIndex>; pub type RTreeWrapper = GeomWithData<Shape, TaggedIndex>;
@ -323,7 +323,7 @@ impl Layout {
let shape = primitive.shape(); let shape = primitive.shape();
self.rtree self.rtree
.locate_in_envelope_intersecting(&shape.envelope()) .locate_in_envelope_intersecting(&RTreeObject::envelope(&shape))
.filter(|wrapper| { .filter(|wrapper| {
let other_index = wrapper.data; let other_index = wrapper.data;
!untag!(other_index, primitive.connectable(other_index)) !untag!(other_index, primitive.connectable(other_index))
@ -358,7 +358,7 @@ impl Layout {
let wrapper = RTreeWrapper::new(shape, index); let wrapper = RTreeWrapper::new(shape, index);
!self !self
.rtree .rtree
.locate_in_envelope(&shape.envelope()) .locate_in_envelope(&RTreeObject::envelope(&shape))
.any(|w| *w == wrapper) .any(|w| *w == wrapper)
}) })
} }

View File

@ -30,6 +30,7 @@ use layout::Layout;
use mesh::{Mesh, MeshEdgeReference, VertexIndex}; use mesh::{Mesh, MeshEdgeReference, VertexIndex};
use petgraph::visit::{EdgeRef, IntoEdgeReferences}; use petgraph::visit::{EdgeRef, IntoEdgeReferences};
use router::RouterObserver; use router::RouterObserver;
use rstar::RTreeObject;
use sdl2::event::Event; use sdl2::event::Event;
use sdl2::gfx::primitives::DrawRenderer; use sdl2::gfx::primitives::DrawRenderer;
use sdl2::keyboard::Keycode; use sdl2::keyboard::Keycode;
@ -68,7 +69,7 @@ impl<'a> DebugRouterObserver<'a> {
impl<'a> RouterObserver for DebugRouterObserver<'a> { impl<'a> RouterObserver for DebugRouterObserver<'a> {
fn on_rework(&mut self, tracer: &Tracer, trace: &Trace) { fn on_rework(&mut self, tracer: &Tracer, trace: &Trace) {
/*render_times( render_times(
self.event_pump, self.event_pump,
self.canvas, self.canvas,
RouterOrLayout::Layout(tracer.layout), RouterOrLayout::Layout(tracer.layout),
@ -77,13 +78,13 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
Some(tracer.mesh.clone()), Some(tracer.mesh.clone()),
&trace.path, &trace.path,
20, 20,
);*/ );
} }
fn before_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) { fn before_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) {
let mut path = trace.path.clone(); let mut path = trace.path.clone();
path.push(edge.target()); path.push(edge.target());
/*render_times( render_times(
self.event_pump, self.event_pump,
self.canvas, self.canvas,
RouterOrLayout::Layout(tracer.layout), RouterOrLayout::Layout(tracer.layout),
@ -92,11 +93,11 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
Some(tracer.mesh.clone()), Some(tracer.mesh.clone()),
&path, &path,
5, 5,
);*/ );
} }
fn on_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) { fn on_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) {
/*render_times( render_times(
self.event_pump, self.event_pump,
self.canvas, self.canvas,
RouterOrLayout::Layout(tracer.layout), RouterOrLayout::Layout(tracer.layout),
@ -105,7 +106,7 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
Some(tracer.mesh.clone()), Some(tracer.mesh.clone()),
&trace.path, &trace.path,
5, 5,
);*/ );
} }
fn on_estimate(&mut self, _tracer: &Tracer, _vertex: VertexIndex) {} fn on_estimate(&mut self, _tracer: &Tracer, _vertex: VertexIndex) {}
@ -335,7 +336,7 @@ fn main() {
}, },
);*/ );*/
render_times( /*render_times(
&mut event_pump, &mut event_pump,
&mut canvas, &mut canvas,
RouterOrLayout::Layout(&router.layout), RouterOrLayout::Layout(&router.layout),
@ -355,6 +356,12 @@ fn main() {
None, None,
&[], &[],
-1, -1,
);*/
let _ = router.enroute(
dot1,
dot_end,
&mut DebugRouterObserver::new(&mut event_pump, &mut canvas),
); );
render_times( render_times(
@ -486,17 +493,17 @@ fn render_times(
} }
} }
} }
/*let envelope = shape.envelope(); let envelope = shape.envelope();
let _ = canvas.rectangle( let _ = canvas.rectangle(
envelope.lower()[0] as i16, envelope.lower()[0] as i16,
envelope.lower()[1] as i16, envelope.lower()[1] as i16,
envelope.upper()[0] as i16, envelope.upper()[0] as i16,
envelope.upper()[1] as i16, envelope.upper()[1] as i16,
Color::RGB(100, 100, 100), Color::RGB(100, 100, 100),
);*/ );
} }
/*if let Some(ref mesh) = mesh { if let Some(ref mesh) = mesh {
for edge in mesh.edge_references() { for edge in mesh.edge_references() {
let endpoints = (mesh.position(edge.source()), mesh.position(edge.target())); let endpoints = (mesh.position(edge.source()), mesh.position(edge.target()));
@ -514,7 +521,7 @@ fn render_times(
color, color,
); );
} }
}*/ }
//}); //});
canvas.present(); canvas.present();

View File

@ -7,11 +7,12 @@ use spade::{
DelaunayTriangulation, HasPosition, InsertionError, Point2, Triangulation, DelaunayTriangulation, HasPosition, InsertionError, Point2, Triangulation,
}; };
use crate::shape::ShapeTrait;
use crate::{graph::DotIndex, layout::Layout}; use crate::{graph::DotIndex, layout::Layout};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Vertex { struct Vertex {
pub dot: DotIndex, dot: DotIndex,
x: f64, x: f64,
y: f64, y: f64,
} }

View File

@ -8,7 +8,7 @@ use crate::graph::{
TaggedIndex, TaggedWeight, TaggedIndex, TaggedWeight,
}; };
use crate::math::{self, Circle}; use crate::math::{self, Circle};
use crate::shape::{BendShape, DotShape, SegShape, Shape}; use crate::shape::{BendShape, DotShape, SegShape, Shape, ShapeTrait};
#[derive(Debug)] #[derive(Debug)]
pub struct Primitive<'a, Weight> { pub struct Primitive<'a, Weight> {

View File

@ -1,14 +1,80 @@
use enum_as_inner::EnumAsInner; use enum_as_inner::EnumAsInner;
use enum_dispatch::enum_dispatch;
use geo::{point, polygon, EuclideanDistance, Intersects, Point, Polygon, Rotate}; use geo::{point, polygon, EuclideanDistance, Intersects, Point, Polygon, Rotate};
use rstar::{RTreeObject, AABB}; use rstar::{RTreeObject, AABB};
use crate::math::{self, Circle}; 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)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct DotShape { pub struct DotShape {
pub c: Circle, 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)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct SegShape { pub struct SegShape {
pub from: Point, 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)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct BendShape { pub struct BendShape {
pub from: Point, pub from: Point,
@ -69,172 +190,69 @@ impl BendShape {
} }
} }
// TODO: Use enum_dispatch. impl ShapeTrait for BendShape {
#[derive(Debug, Clone, Copy, EnumAsInner, PartialEq)] fn priority(&self) -> u64 {
pub enum Shape { 1
// Intentionally in different order to reorder `self.intersects(...)` properly.
Dot(DotShape),
Seg(SegShape),
Bend(BendShape),
} }
impl Shape { fn center(&self) -> Point {
pub fn principal_point(&self) -> Point { let sum = (self.from - self.c.pos) + (self.to - self.c.pos);
match self { self.c.pos + (sum / sum.euclidean_distance(&point! {x: 0.0, y: 0.0})) * self.c.r
Shape::Dot(dot) => dot.c.pos,
Shape::Seg(seg) => seg.from,
Shape::Bend(bend) => bend.from,
}
} }
pub fn center(&self) -> Point { fn intersects(&self, other: &Shape) -> bool {
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 priority(&self) -> i64 {
match self {
Shape::Dot(..) => 3,
Shape::Seg(..) => 2,
Shape::Bend(..) => 1,
}
}
pub fn intersects(&self, other: &Shape) -> bool {
if self.priority() < other.priority() { if self.priority() < other.priority() {
return other.intersects(self); return other.intersects(&Shape::from(*self));
} }
match self { match other {
Shape::Dot(dot) => match other {
Shape::Dot(other) => {
dot.c.pos.euclidean_distance(&other.c.pos) < dot.c.r + other.c.r
}
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;
}
}
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;
}
}
}
false
}
},
Shape::Bend(bend) => match other {
Shape::Dot(..) | Shape::Seg(..) => unreachable!(), Shape::Dot(..) | Shape::Seg(..) => unreachable!(),
Shape::Bend(other) => { Shape::Bend(other) => {
for point in for point in math::intersect_circles(&self.inner_circle(), &other.inner_circle()) {
math::intersect_circles(&bend.inner_circle(), &other.inner_circle()) if self.between_ends(point) && other.between_ends(point) {
{
if bend.between_ends(point) && other.between_ends(point) {
return true; return true;
} }
} }
for point in for point in math::intersect_circles(&self.inner_circle(), &other.outer_circle()) {
math::intersect_circles(&bend.inner_circle(), &other.outer_circle()) if self.between_ends(point) && other.between_ends(point) {
{
if bend.between_ends(point) && other.between_ends(point) {
return true; return true;
} }
} }
for point in for point in math::intersect_circles(&self.outer_circle(), &other.inner_circle()) {
math::intersect_circles(&bend.outer_circle(), &other.inner_circle()) if self.between_ends(point) && other.between_ends(point) {
{
if bend.between_ends(point) && other.between_ends(point) {
return true; return true;
} }
} }
for point in for point in math::intersect_circles(&self.outer_circle(), &other.outer_circle()) {
math::intersect_circles(&bend.outer_circle(), &other.outer_circle()) if self.between_ends(point) && other.between_ends(point) {
{
if bend.between_ends(point) && other.between_ends(point) {
return true; return true;
} }
} }
false false
} }
},
} }
} }
pub fn envelope(&self) -> AABB<[f64; 2]> { fn envelope(&self) -> AABB<[f64; 2]> {
match self { let halfwidth = self.c.r + self.width;
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( AABB::from_corners(
[bend.c.pos.x() - halfwidth, bend.c.pos.y() - halfwidth], [self.c.pos.x() - halfwidth, self.c.pos.y() - halfwidth],
[bend.c.pos.x() + halfwidth, bend.c.pos.y() + halfwidth], [self.c.pos.x() + halfwidth, self.c.pos.y() + halfwidth],
) )
} }
}
}
pub fn width(&self) -> f64 { fn width(&self) -> f64 {
match self { self.width
Shape::Dot(dot) => dot.c.r * 2.0,
Shape::Seg(seg) => seg.width,
Shape::Bend(bend) => bend.width,
}
} }
} }
impl RTreeObject for Shape { impl RTreeObject for Shape {
type Envelope = AABB<[f64; 2]>; type Envelope = AABB<[f64; 2]>;
fn envelope(&self) -> Self::Envelope { fn envelope(&self) -> Self::Envelope {
return self.envelope(); return ShapeTrait::envelope(self);
} }
} }

View File

@ -2,7 +2,7 @@ use contracts::debug_ensures;
use crate::{ use crate::{
bow::Bow, bow::Bow,
draw::{BareHead, Draw, Head, HeadDot, SegbendHead}, draw::{BareHead, Draw, Head, HeadTrait, SegbendHead},
graph::{BendIndex, DotIndex, Ends}, graph::{BendIndex, DotIndex, Ends},
layout::Layout, layout::Layout,
mesh::{Mesh, MeshEdgeReference, VertexIndex}, mesh::{Mesh, MeshEdgeReference, VertexIndex},