mirror of https://codeberg.org/topola/topola.git
draw: Use `enum_dispatch` to dynamically dispatch `Head`
This commit is contained in:
parent
d7b5640a25
commit
efea917cb1
11
Cargo.toml
11
Cargo.toml
|
|
@ -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" }
|
||||||
|
|
|
||||||
125
src/draw.rs
125
src/draw.rs
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
33
src/guide.rs
33
src/guide.rs
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
16
src/route.rs
16
src/route.rs
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue