refactor(router::draw): Draw should be an extension/wrapper trait around RecordingLayout

This commit is contained in:
Alain Emilia Anna Zscheile 2025-01-03 03:41:13 +01:00
parent b8cc0e0963
commit 26631ed6cd
4 changed files with 174 additions and 164 deletions

View File

@ -16,6 +16,7 @@ use crate::{
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
gear::GearIndex, gear::GearIndex,
graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight},
guide::Guide,
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
rules::AccessRules, rules::AccessRules,
seg::{ seg::{
@ -191,6 +192,10 @@ impl<R: AccessRules> Layout<R> {
self.drawing.rules_mut() self.drawing.rules_mut()
} }
pub fn guide(&self) -> Guide<CompoundWeight, R> {
Guide::new(&self.drawing)
}
pub fn poly(&self, index: GenericIndex<PolyWeight>) -> Poly<R> { pub fn poly(&self, index: GenericIndex<PolyWeight>) -> Poly<R> {
Poly::new(index, self) Poly::new(index, self)
} }
@ -200,11 +205,24 @@ impl<R: AccessRules> Layout<R> {
} }
} }
// this is a hack, but it allows us to not needing as much boilerplate for delegations
impl<R> core::ops::Deref for RecordingLayout<'_, R> {
type Target = Layout<R>;
fn deref(&self) -> &Layout<R> {
self.layout
}
}
impl<R: AccessRules> RecordingLayout<'_, R> { impl<R: AccessRules> RecordingLayout<'_, R> {
fn recording_drawing(&mut self) -> RecordingDrawing<'_, CompoundWeight, R> { fn recording_drawing(&mut self) -> RecordingDrawing<'_, CompoundWeight, R> {
self.layout.drawing.recording(self.recorder) self.layout.drawing.recording(self.recorder)
} }
pub fn rules_mut(&mut self) -> &mut R {
self.layout.drawing.rules_mut()
}
/// Insert [`Cane`] object into the [`Layout`] /// Insert [`Cane`] object into the [`Layout`]
pub fn insert_cane( pub fn insert_cane(
&mut self, &mut self,

View File

@ -18,9 +18,9 @@ use crate::{
primitive::GetOtherJoint, primitive::GetOtherJoint,
rules::AccessRules, rules::AccessRules,
seg::{LoneLooseSegWeight, SeqLooseSegWeight}, seg::{LoneLooseSegWeight, SeqLooseSegWeight},
DrawingException, Infringement, Drawing, DrawingException, Infringement,
}, },
layout::{Layout, LayoutEdit}, layout::{CompoundWeight, Layout, LayoutEdit, RecordingLayout},
math::{Circle, NoTangents}, math::{Circle, NoTangents},
}; };
@ -35,27 +35,47 @@ pub enum DrawException {
CannotWrapAround(GearIndex, #[source] DrawingException), CannotWrapAround(GearIndex, #[source] DrawingException),
} }
/// This struct is a simple wrapper whose sole purpose is to have a separate /// This trait is a simple wrapper whose sole purpose is to have a separate
/// file for the router module's routines for drawing and erasing the primitives /// file for the router module's routines for drawing and erasing the primitives
/// to pull out or contract the currently routed band. /// to pull out or contract the currently routed band.
pub struct Draw<'a, R> { pub trait Draw {
layout: &'a mut Layout<R>, fn start(&mut self, from: LooseDotIndex) -> Head;
fn finish_in_dot(
&mut self,
head: Head,
into: FixedDotIndex,
width: f64,
) -> Result<BandTermsegIndex, DrawException>;
fn cane_around_dot(
&mut self,
head: Head,
around: FixedDotIndex,
cw: bool,
width: f64,
) -> Result<CaneHead, DrawException>;
fn cane_around_bend(
&mut self,
head: Head,
around: BendIndex,
cw: bool,
width: f64,
) -> Result<CaneHead, DrawException>;
fn undo_cane(&mut self, head: CaneHead) -> Option<Head>;
} }
impl<'a, R: AccessRules> Draw<'a, R> { impl<'a, R: AccessRules> Draw for RecordingLayout<'a, R> {
pub fn new(layout: &'a mut Layout<R>) -> Self { fn start(&mut self, from: LooseDotIndex) -> Head {
Self { layout }
}
pub fn start(&mut self, from: LooseDotIndex) -> Head {
self.guide().cane_head(from).into() self.guide().cane_head(from).into()
} }
#[debug_ensures(ret.is_ok() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.drawing().node_count() == old(self.drawing().node_count() + 1))]
#[debug_ensures(ret.is_err() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))] #[debug_ensures(ret.is_err() -> self.drawing().node_count() == old(self.drawing().node_count()))]
pub fn finish_in_dot( fn finish_in_dot(
&mut self, &mut self,
recorder: &mut LayoutEdit,
head: Head, head: Head,
into: FixedDotIndex, into: FixedDotIndex,
width: f64, width: f64,
@ -64,49 +84,43 @@ impl<'a, R: AccessRules> Draw<'a, R> {
.guide() .guide()
.head_into_dot_segment(&head, into, width) .head_into_dot_segment(&head, into, width)
.map_err(Into::<DrawException>::into)?; .map_err(Into::<DrawException>::into)?;
let head = self let head = extend_head(self, head, tangent.start_point())
.extend_head(recorder, head, tangent.start_point())
.map_err(|err| DrawException::CannotFinishIn(into, err.into()))?; .map_err(|err| DrawException::CannotFinishIn(into, err.into()))?;
let layer = head.face().primitive(self.layout.drawing()).layer(); let layer = head.face().primitive(self.drawing()).layer();
let maybe_net = head.face().primitive(self.layout.drawing()).maybe_net(); let maybe_net = head.face().primitive(self.drawing()).maybe_net();
Ok(match head.face() { Ok(match head.face() {
DotIndex::Fixed(dot) => BandTermsegIndex::Straight( DotIndex::Fixed(dot) => BandTermsegIndex::Straight(
self.layout self.add_lone_loose_seg(
.recording(recorder) dot,
.add_lone_loose_seg( into,
dot, LoneLooseSegWeight {
into, width,
LoneLooseSegWeight { layer,
width, maybe_net,
layer, },
maybe_net, )
}, .map_err(|err| DrawException::CannotFinishIn(into, err.into()))?,
)
.map_err(|err| DrawException::CannotFinishIn(into, err.into()))?,
), ),
DotIndex::Loose(dot) => BandTermsegIndex::Bended( DotIndex::Loose(dot) => BandTermsegIndex::Bended(
self.layout self.add_seq_loose_seg(
.recording(recorder) into.into(),
.add_seq_loose_seg( dot,
into.into(), SeqLooseSegWeight {
dot, width,
SeqLooseSegWeight { layer,
width, maybe_net,
layer, },
maybe_net, )
}, .map_err(|err| DrawException::CannotFinishIn(into, err.into()))?,
)
.map_err(|err| DrawException::CannotFinishIn(into, err.into()))?,
), ),
}) })
} }
#[debug_ensures(ret.is_ok() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() + 4))] #[debug_ensures(ret.is_ok() -> self.drawing().node_count() == old(self.drawing().node_count() + 4))]
#[debug_ensures(ret.is_err() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))] #[debug_ensures(ret.is_err() -> self.drawing().node_count() == old(self.drawing().node_count()))]
pub fn cane_around_dot( fn cane_around_dot(
&mut self, &mut self,
recorder: &mut LayoutEdit,
head: Head, head: Head,
around: FixedDotIndex, around: FixedDotIndex,
cw: bool, cw: bool,
@ -118,8 +132,8 @@ impl<'a, R: AccessRules> Draw<'a, R> {
let offset = self let offset = self
.guide() .guide()
.head_around_dot_offset(&head, around.into(), width); .head_around_dot_offset(&head, around.into(), width);
self.cane_around( cane_around(
recorder, self,
head, head,
around.into(), around.into(),
tangent.start_point(), tangent.start_point(),
@ -131,11 +145,10 @@ impl<'a, R: AccessRules> Draw<'a, R> {
.map_err(|err| DrawException::CannotWrapAround(around.into(), err)) .map_err(|err| DrawException::CannotWrapAround(around.into(), err))
} }
#[debug_ensures(ret.is_ok() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() + 4))] #[debug_ensures(ret.is_ok() -> self.drawing().node_count() == old(self.drawing().node_count() + 4))]
#[debug_ensures(ret.is_err() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))] #[debug_ensures(ret.is_err() -> self.drawing().node_count() == old(self.drawing().node_count()))]
pub fn cane_around_bend( fn cane_around_bend(
&mut self, &mut self,
recorder: &mut LayoutEdit,
head: Head, head: Head,
around: BendIndex, around: BendIndex,
cw: bool, cw: bool,
@ -146,8 +159,8 @@ impl<'a, R: AccessRules> Draw<'a, R> {
.head_around_bend_segment(&head, around, cw, width)?; .head_around_bend_segment(&head, around, cw, width)?;
let offset = self.guide().head_around_bend_offset(&head, around, width); let offset = self.guide().head_around_bend_offset(&head, around, width);
self.cane_around( cane_around(
recorder, self,
head, head,
around.into(), around.into(),
tangent.start_point(), tangent.start_point(),
@ -159,104 +172,88 @@ impl<'a, R: AccessRules> Draw<'a, R> {
.map_err(|err| DrawException::CannotWrapAround(around.into(), err)) .map_err(|err| DrawException::CannotWrapAround(around.into(), err))
} }
#[debug_ensures(ret.is_ok() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() + 4))] #[debug_ensures(ret.is_some() -> self.drawing().node_count() == old(self.drawing().node_count() - 4))]
#[debug_ensures(ret.is_err() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))] #[debug_ensures(ret.is_none() -> self.drawing().node_count() == old(self.drawing().node_count()))]
fn cane_around( fn undo_cane(&mut self, head: CaneHead) -> Option<Head> {
&mut self,
recorder: &mut LayoutEdit,
head: Head,
around: GearIndex,
from: Point,
to: Point,
cw: bool,
width: f64,
offset: f64,
) -> Result<CaneHead, DrawingException> {
let head = self.extend_head(recorder, head, from)?;
self.cane(recorder, head, around, to, cw, width, offset)
}
#[debug_ensures(self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))]
fn extend_head(
&mut self,
recorder: &mut LayoutEdit,
head: Head,
to: Point,
) -> Result<Head, Infringement> {
if let Head::Cane(head) = head {
self.layout
.recording(recorder)
.move_dot(head.face.into(), to)?;
Ok(Head::Cane(head))
} else {
Ok(head)
}
}
#[debug_ensures(ret.is_ok() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() + 4))]
#[debug_ensures(ret.is_err() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))]
fn cane(
&mut self,
recorder: &mut LayoutEdit,
head: Head,
around: GearIndex,
to: Point,
cw: bool,
width: f64,
offset: f64,
) -> Result<CaneHead, DrawingException> {
let layer = head.face().primitive(self.layout.drawing()).layer();
let maybe_net = head.face().primitive(self.layout.drawing()).maybe_net();
let cane = self.layout.recording(recorder).insert_cane(
head.face(),
around,
LooseDotWeight {
circle: Circle {
pos: to,
r: width / 2.0,
},
layer,
maybe_net,
},
SeqLooseSegWeight {
width,
layer,
maybe_net,
},
LooseBendWeight {
width,
offset,
layer,
maybe_net,
},
cw,
)?;
Ok(CaneHead {
face: self
.layout
.drawing()
.primitive(cane.bend)
.other_joint(cane.dot),
cane,
})
}
#[debug_ensures(ret.is_some() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() - 4))]
#[debug_ensures(ret.is_none() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))]
pub fn undo_cane(&mut self, recorder: &mut LayoutEdit, head: CaneHead) -> Option<Head> {
let prev_dot = self let prev_dot = self
.layout
.drawing() .drawing()
.primitive(head.cane.seg) .primitive(head.cane.seg)
.other_joint(head.cane.dot.into()); .other_joint(head.cane.dot.into());
self.layout self.remove_cane(&head.cane, head.face);
.recording(recorder)
.remove_cane(&head.cane, head.face);
Some(self.guide().head(prev_dot)) Some(self.guide().head(prev_dot))
} }
}
fn guide(&self) -> Guide<impl Copy, R> { #[debug_ensures(ret.is_ok() -> this.drawing().node_count() == old(this.drawing().node_count() + 4))]
Guide::new(self.layout.drawing()) #[debug_ensures(ret.is_err() -> this.drawing().node_count() == old(this.drawing().node_count()))]
fn cane_around<R: AccessRules>(
this: &mut RecordingLayout<'_, R>,
head: Head,
around: GearIndex,
from: Point,
to: Point,
cw: bool,
width: f64,
offset: f64,
) -> Result<CaneHead, DrawingException> {
let head = extend_head(this, head, from)?;
cane(this, head, around, to, cw, width, offset)
}
#[debug_ensures(this.drawing().node_count() == old(this.drawing().node_count()))]
fn extend_head<R: AccessRules>(
this: &mut RecordingLayout<'_, R>,
head: Head,
to: Point,
) -> Result<Head, Infringement> {
if let Head::Cane(head) = head {
this.move_dot(head.face.into(), to)?;
Ok(Head::Cane(head))
} else {
Ok(head)
} }
} }
#[debug_ensures(ret.is_ok() -> this.drawing().node_count() == old(this.drawing().node_count() + 4))]
#[debug_ensures(ret.is_err() -> this.drawing().node_count() == old(this.drawing().node_count()))]
fn cane<R: AccessRules>(
this: &mut RecordingLayout<'_, R>,
head: Head,
around: GearIndex,
to: Point,
cw: bool,
width: f64,
offset: f64,
) -> Result<CaneHead, DrawingException> {
let layer = head.face().primitive(this.drawing()).layer();
let maybe_net = head.face().primitive(this.drawing()).maybe_net();
let cane = this.insert_cane(
head.face(),
around,
LooseDotWeight {
circle: Circle {
pos: to,
r: width / 2.0,
},
layer,
maybe_net,
},
SeqLooseSegWeight {
width,
layer,
maybe_net,
},
LooseBendWeight {
width,
offset,
layer,
maybe_net,
},
cw,
)?;
Ok(CaneHead {
face: this.drawing().primitive(cane.bend).other_joint(cane.dot),
cane,
})
}

View File

@ -85,13 +85,10 @@ impl NavcordStepper {
cw: bool, cw: bool,
width: f64, width: f64,
) -> Result<CaneHead, NavcorderException> { ) -> Result<CaneHead, NavcorderException> {
Ok(Draw::new(navcorder.layout).cane_around_dot( Ok(navcorder
&mut self.recorder, .layout
head, .recording(&mut self.recorder)
around, .cane_around_dot(head, around, cw, width)?)
cw,
width,
)?)
} }
fn wrap_around_loose_bend( fn wrap_around_loose_bend(
@ -102,13 +99,10 @@ impl NavcordStepper {
cw: bool, cw: bool,
width: f64, width: f64,
) -> Result<CaneHead, NavcorderException> { ) -> Result<CaneHead, NavcorderException> {
Ok(Draw::new(navcorder.layout).cane_around_bend( Ok(navcorder
&mut self.recorder, .layout
head, .recording(&mut self.recorder)
around.into(), .cane_around_bend(head, around.into(), cw, width)?)
cw,
width,
)?)
} }
fn binavvertex(&self, navmesh: &Navmesh, navvertex: NavvertexIndex) -> BinavvertexNodeIndex { fn binavvertex(&self, navmesh: &Navmesh, navvertex: NavvertexIndex) -> BinavvertexNodeIndex {
@ -159,8 +153,10 @@ impl NavcordStepper {
navcorder: &mut Navcorder<'a, R>, navcorder: &mut Navcorder<'a, R>,
) -> Result<(), NavcorderException> { ) -> Result<(), NavcorderException> {
if let Head::Cane(head) = self.head { if let Head::Cane(head) = self.head {
self.head = Draw::new(navcorder.layout) self.head = navcorder
.undo_cane(&mut self.recorder, head) .layout
.recording(&mut self.recorder)
.undo_cane(head)
.unwrap(); .unwrap();
} else { } else {
panic!(); panic!();

View File

@ -53,8 +53,7 @@ impl<'a, R: AccessRules> Navcorder<'a, R> {
target: FixedDotIndex, target: FixedDotIndex,
width: f64, width: f64,
) -> Result<BandTermsegIndex, NavcorderException> { ) -> Result<BandTermsegIndex, NavcorderException> {
Ok(Draw::new(self.layout).finish_in_dot( Ok(self.layout.recording(&mut navcord.recorder).finish_in_dot(
&mut navcord.recorder,
navcord.head, navcord.head,
target, target,
width, width,