draw: Use `enum_dispatch` to dynamically dispatch `Head`

This commit is contained in:
Mikolaj Wielgus 2023-09-17 16:54:23 +02:00
parent d7b5640a25
commit efea917cb1
4 changed files with 112 additions and 73 deletions

View File

@ -20,10 +20,8 @@ version = "2.2.0"
[dependencies.fixedbitset] [dependencies.fixedbitset]
version = "0.4.0" version = "0.4.0"
[dependencies.sdl2] [dependencies.enum_dispatch]
version = "0.35.2" version = "0.3.12"
default-features = false
features = ["gfx"]
[dependencies.enum-as-inner] [dependencies.enum-as-inner]
version = "0.6.0" version = "0.6.0"
@ -31,5 +29,10 @@ version = "0.6.0"
[dependencies.contracts] [dependencies.contracts]
version = "0.6.3" version = "0.6.3"
[dependencies.sdl2]
version = "0.35.2"
default-features = false
features = ["gfx"]
[patch.crates-io] [patch.crates-io]
contracts = { path = "vendor/contracts" } contracts = { path = "vendor/contracts" }

View File

@ -1,4 +1,5 @@
use contracts::debug_ensures; use contracts::{debug_ensures, debug_requires};
use enum_dispatch::enum_dispatch;
use geo::{EuclideanLength, Point}; use geo::{EuclideanLength, Point};
use crate::{ use crate::{
@ -10,10 +11,39 @@ use crate::{
segbend::Segbend, segbend::Segbend,
}; };
#[enum_dispatch]
pub trait HeadDot {
fn dot(&self) -> DotIndex;
}
#[enum_dispatch(HeadDot)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Head { pub enum Head {
Bare(BareHead),
Segbend(SegbendHead),
}
#[derive(Debug, Clone, Copy)]
pub struct BareHead {
pub dot: DotIndex, pub dot: DotIndex,
pub segbend: Option<Segbend>, }
impl HeadDot for BareHead {
fn dot(&self) -> DotIndex {
self.dot
}
}
#[derive(Debug, Clone, Copy)]
pub struct SegbendHead {
pub dot: DotIndex,
pub segbend: Segbend,
}
impl HeadDot for SegbendHead {
fn dot(&self) -> DotIndex {
self.dot
}
} }
pub struct Draw<'a> { pub struct Draw<'a> {
@ -27,10 +57,7 @@ impl<'a> Draw<'a> {
} }
pub fn start(&mut self, from: DotIndex) -> Head { pub fn start(&mut self, from: DotIndex) -> Head {
Head { self.prev_head(from)
dot: from,
segbend: self.layout.prev_segbend(from),
}
} }
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 1))]
@ -52,9 +79,9 @@ impl<'a> Draw<'a> {
.head_into_dot_segment(&head, into, width); .head_into_dot_segment(&head, into, width);
let head = self.extend_head(head, tangent.start_point())?; let head = self.extend_head(head, tangent.start_point())?;
let net = self.layout.primitive(head.dot).weight().net; let net = self.layout.primitive(head.dot()).weight().net;
self.layout self.layout
.add_seg(head.dot, into, SegWeight { net, width })?; .add_seg(head.dot(), into, SegWeight { net, width })?;
Ok(()) Ok(())
} }
@ -67,10 +94,7 @@ impl<'a> Draw<'a> {
into: DotIndex, into: DotIndex,
width: f64, width: f64,
) -> Result<(), ()> { ) -> Result<(), ()> {
let to_head = Head { let to_head = self.next_head(into);
dot: into,
segbend: self.layout.next_segbend(into),
};
let to_cw = self.guide(&Default::default()).head_cw(&to_head).unwrap(); let to_cw = self.guide(&Default::default()).head_cw(&to_head).unwrap();
let tangent = self let tangent = self
.guide(&Default::default()) .guide(&Default::default())
@ -79,9 +103,9 @@ impl<'a> Draw<'a> {
let head = self.extend_head(head, tangent.start_point())?; let head = self.extend_head(head, tangent.start_point())?;
let _to_head = self.extend_head(to_head, tangent.end_point())?; let _to_head = self.extend_head(to_head, tangent.end_point())?;
let net = self.layout.primitive(head.dot).weight().net; let net = self.layout.primitive(head.dot()).weight().net;
self.layout self.layout
.add_seg(head.dot, into, SegWeight { net, width })?; .add_seg(head.dot(), into, SegWeight { net, width })?;
Ok(()) Ok(())
} }
@ -92,7 +116,7 @@ impl<'a> Draw<'a> {
head: Head, head: Head,
around: DotIndex, around: DotIndex,
width: f64, width: f64,
) -> Result<Head, ()> { ) -> Result<SegbendHead, ()> {
let mut tangents = self let mut tangents = self
.guide(&Default::default()) .guide(&Default::default())
.head_around_dot_segments(&head, around, width); .head_around_dot_segments(&head, around, width);
@ -133,7 +157,7 @@ impl<'a> Draw<'a> {
around: BendIndex, around: BendIndex,
cw: bool, cw: bool,
width: f64, width: f64,
) -> Result<Head, ()> { ) -> Result<SegbendHead, ()> {
let tangent = self let tangent = self
.guide(&Default::default()) .guide(&Default::default())
.head_around_bend_segment(&head, around, cw, width); .head_around_bend_segment(&head, around, cw, width);
@ -158,15 +182,15 @@ impl<'a> Draw<'a> {
to: Point, to: Point,
cw: bool, cw: bool,
width: f64, width: f64,
) -> Result<Head, ()> { ) -> Result<SegbendHead, ()> {
head = self.extend_head(head, from)?; head = self.extend_head(head, from)?;
self.segbend(head, around, to, cw, width) self.segbend(head, around, to, cw, width)
} }
#[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))] #[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))]
fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, ()> { fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, ()> {
if let Some(..) = head.segbend { if let Head::Segbend(head) = head {
self.extend_head_bend(head, to) Ok(Head::Segbend(self.extend_head_bend(head, to)?))
} else { } else {
Ok(head) Ok(head)
// No assertion for now because we temporarily use floats. // No assertion for now because we temporarily use floats.
@ -177,9 +201,8 @@ impl<'a> Draw<'a> {
} }
#[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))] #[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))]
fn extend_head_bend(&mut self, head: Head, to: Point) -> Result<Head, ()> { fn extend_head_bend(&mut self, head: SegbendHead, to: Point) -> Result<SegbendHead, ()> {
self.layout self.layout.extend_bend(head.segbend.bend, head.dot, to)?;
.extend_bend(head.segbend.as_ref().unwrap().bend, head.dot, to)?;
Ok(head) Ok(head)
} }
@ -192,7 +215,7 @@ impl<'a> Draw<'a> {
to: Point, to: Point,
cw: bool, cw: bool,
width: f64, width: f64,
) -> Result<Head, ()> { ) -> Result<SegbendHead, ()> {
let (head, seg) = self.seg(head, to, width)?; let (head, seg) = self.seg(head, to, width)?;
let dot = head.dot; let dot = head.dot;
let bend_to = self let bend_to = self
@ -213,37 +236,31 @@ impl<'a> Draw<'a> {
self.undo_seg(head, seg); self.undo_seg(head, seg);
err err
})?; })?;
Ok(Head { Ok(SegbendHead {
dot: bend_to, dot: bend_to,
segbend: Some(Segbend { bend, dot, seg }), segbend: Segbend { bend, dot, seg },
}) })
} }
#[debug_ensures(ret.is_some() -> self.layout.node_count() == old(self.layout.node_count() - 4))] #[debug_ensures(ret.is_some() -> self.layout.node_count() == old(self.layout.node_count() - 4))]
#[debug_ensures(ret.is_none() -> self.layout.node_count() == old(self.layout.node_count()))] #[debug_ensures(ret.is_none() -> self.layout.node_count() == old(self.layout.node_count()))]
pub fn undo_segbend(&mut self, head: Head) -> Option<Head> { pub fn undo_segbend(&mut self, head: SegbendHead) -> Option<Head> {
let segbend = head.segbend.unwrap();
self.layout self.layout
.primitive(segbend.ends().0) .primitive(head.segbend.ends().0)
.prev() .prev()
.map(|prev_dot| { .map(|prev_dot| {
self.layout.remove_interior(&segbend); self.layout.remove_interior(&head.segbend);
self.layout.remove(head.dot); self.layout.remove(head.dot());
Head { self.prev_head(prev_dot)
dot: prev_dot,
segbend: self.layout.prev_segbend(prev_dot),
}
}) })
} }
#[debug_requires(width <= self.layout.primitive(head.dot()).weight().circle.r * 2.0)]
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 2))] #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 2))]
#[debug_ensures(ret.is_err() -> self.layout.node_count() == old(self.layout.node_count()))] #[debug_ensures(ret.is_err() -> self.layout.node_count() == old(self.layout.node_count()))]
fn seg(&mut self, head: Head, to: Point, width: f64) -> Result<(Head, SegIndex), ()> { fn seg(&mut self, head: Head, to: Point, width: f64) -> Result<(BareHead, SegIndex), ()> {
debug_assert!(width <= self.layout.primitive(head.dot).weight().circle.r * 2.0); let net = self.layout.primitive(head.dot()).weight().net;
let net = self.layout.primitive(head.dot).weight().net;
let to_index = self.layout.add_dot(DotWeight { let to_index = self.layout.add_dot(DotWeight {
net, net,
circle: Circle { circle: Circle {
@ -253,26 +270,36 @@ impl<'a> Draw<'a> {
})?; })?;
let seg = self let seg = self
.layout .layout
.add_seg(head.dot, to_index, SegWeight { net, width }) .add_seg(head.dot(), to_index, SegWeight { net, width })
.map_err(|err| { .map_err(|err| {
self.layout.remove(to_index); self.layout.remove(to_index);
err err
})?; })?;
Ok(( Ok((BareHead { dot: to_index }, seg))
Head {
dot: to_index,
segbend: None,
},
seg,
))
} }
#[debug_ensures(self.layout.node_count() == old(self.layout.node_count() - 2))] #[debug_ensures(self.layout.node_count() == old(self.layout.node_count() - 2))]
fn undo_seg(&mut self, head: Head, seg: SegIndex) { fn undo_seg(&mut self, head: BareHead, seg: SegIndex) {
self.layout.remove(seg); self.layout.remove(seg);
self.layout.remove(head.dot); self.layout.remove(head.dot);
} }
fn prev_head(&self, dot: DotIndex) -> Head {
if let Some(segbend) = self.layout.prev_segbend(dot) {
Head::from(SegbendHead { dot, segbend })
} else {
Head::from(BareHead { dot })
}
}
fn next_head(&self, dot: DotIndex) -> Head {
if let Some(segbend) = self.layout.next_segbend(dot) {
Head::from(SegbendHead { dot, segbend })
} else {
Head::from(BareHead { dot })
}
}
fn guide(&'a self, conditions: &'a Conditions) -> Guide { fn guide(&'a self, conditions: &'a Conditions) -> Guide {
Guide::new(self.layout, self.rules, conditions) Guide::new(self.layout, self.rules, conditions)
} }

View File

@ -1,7 +1,7 @@
use geo::Line; use geo::Line;
use crate::{ use crate::{
draw::Head, draw::{Head, HeadDot, SegbendHead},
graph::{BendIndex, DotIndex}, graph::{BendIndex, DotIndex},
layout::Layout, layout::Layout,
math::{self, Circle}, math::{self, Circle},
@ -78,9 +78,11 @@ impl<'a, 'b> Guide<'a, 'b> {
} }
pub fn head_cw(&self, head: &Head) -> Option<bool> { pub fn head_cw(&self, head: &Head) -> Option<bool> {
head.segbend if let Head::Segbend(head) = head {
.as_ref() Some(self.layout.primitive(head.segbend.bend).weight().cw)
.map(|segbend| self.layout.primitive(segbend.bend).weight().cw) } else {
None
}
} }
fn head_circle(&self, head: &Head, width: f64) -> Circle { fn head_circle(&self, head: &Head, width: f64) -> Circle {
@ -91,18 +93,21 @@ impl<'a, 'b> Guide<'a, 'b> {
zone: None, zone: None,
}; };
match &head.segbend { match *head {
Some(segbend) => { Head::Bare(head) => Circle {
if let Some(inner) = self.layout.primitive(segbend.bend).inner() { pos: self.layout.primitive(head.dot()).weight().circle.pos,
self.bend_circle(inner, width)
} else {
self.dot_circle(self.layout.primitive(segbend.bend).core().unwrap(), width)
}
}
None => Circle {
pos: self.layout.primitive(head.dot).weight().circle.pos,
r: 0.0, r: 0.0,
}, },
Head::Segbend(head) => {
if let Some(inner) = self.layout.primitive(head.segbend.bend).inner() {
self.bend_circle(inner, width)
} else {
self.dot_circle(
self.layout.primitive(head.segbend.bend).core().unwrap(),
width,
)
}
}
} }
} }

View File

@ -1,7 +1,7 @@
use contracts::debug_ensures; use contracts::debug_ensures;
use crate::{ use crate::{
draw::{Draw, Head}, draw::{BareHead, Draw, Head},
layout::Layout, layout::Layout,
mesh::{Mesh, VertexIndex}, mesh::{Mesh, VertexIndex},
rules::Rules, rules::Rules,
@ -31,10 +31,9 @@ impl<'a> Route<'a> {
pub fn start(&mut self, from: VertexIndex) -> Trace { pub fn start(&mut self, from: VertexIndex) -> Trace {
Trace { Trace {
path: vec![from], path: vec![from],
head: Head { head: Head::from(BareHead {
dot: self.mesh.dot(from), dot: self.mesh.dot(from),
segbend: None, }),
},
} }
} }
@ -85,7 +84,7 @@ impl<'a> Route<'a> {
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))] #[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
pub fn step(&mut self, trace: &mut Trace, to: VertexIndex, width: f64) -> Result<(), ()> { pub fn step(&mut self, trace: &mut Trace, to: VertexIndex, width: f64) -> Result<(), ()> {
let to_dot = self.mesh.dot(to); let to_dot = self.mesh.dot(to);
trace.head = self.draw().segbend_around_dot(trace.head, to_dot, width)?; trace.head = Head::from(self.draw().segbend_around_dot(trace.head, to_dot, width)?);
trace.path.push(to); trace.path.push(to);
Ok(()) Ok(())
} }
@ -93,7 +92,12 @@ impl<'a> Route<'a> {
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() - 1))] #[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() - 1))]
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))] #[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
pub fn undo_step(&mut self, trace: &mut Trace) -> Result<(), ()> { pub fn undo_step(&mut self, trace: &mut Trace) -> Result<(), ()> {
trace.head = self.draw().undo_segbend(trace.head).unwrap(); if let Head::Segbend(head) = trace.head {
trace.head = self.draw().undo_segbend(head).unwrap();
} else {
return Err(());
}
trace.path.pop(); trace.path.pop();
Ok(()) Ok(())
} }