refactor(router::draw): turn Draw into a trait

This commit is contained in:
Ellen Emilia Anna Zscheile 2025-02-01 23:22:40 +01:00 committed by mikolaj
parent 869d63f7c0
commit 1d11011133
3 changed files with 143 additions and 97 deletions

View File

@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2024 Topola contributors // SPDX-FileCopyrightText: 2024 Topola contributors
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
//! router module's routines for drawing and erasing the primitives
//! to pull out or contract the currently routed band.
use contracts_try::debug_ensures; use contracts_try::debug_ensures;
use geo::Point; use geo::Point;
@ -20,7 +22,7 @@ use crate::{
seg::{LoneLooseSegWeight, SeqLooseSegWeight}, seg::{LoneLooseSegWeight, SeqLooseSegWeight},
DrawingException, Infringement, DrawingException, Infringement,
}, },
layout::{Layout, LayoutEdit}, layout::{CompoundWeight, Layout, LayoutEdit},
math::{Circle, NoTangents}, math::{Circle, NoTangents},
}; };
@ -35,25 +37,46 @@ 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 pub trait Draw {
/// file for the router module's routines for drawing and erasing the primitives fn start(&mut self, from: LooseDotIndex) -> Head;
/// to pull out or contract the currently routed band.
pub struct Draw<'a, R> { fn finish_in_dot(
layout: &'a mut Layout<R>, &mut self,
recorder: &mut LayoutEdit,
head: Head,
into: FixedDotIndex,
width: f64,
) -> Result<BandTermsegIndex, DrawException>;
fn cane_around_dot(
&mut self,
recorder: &mut LayoutEdit,
head: Head,
around: FixedDotIndex,
cw: bool,
width: f64,
) -> Result<CaneHead, DrawException>;
fn cane_around_bend(
&mut self,
recorder: &mut LayoutEdit,
head: Head,
around: BendIndex,
cw: bool,
width: f64,
) -> Result<CaneHead, DrawException>;
fn undo_cane(&mut self, recorder: &mut LayoutEdit, head: CaneHead) -> Option<Head>;
} }
impl<'a, R: AccessRules> Draw<'a, R> { impl<R: AccessRules> Draw for Layout<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, recorder: &mut LayoutEdit,
head: Head, head: Head,
@ -67,13 +90,12 @@ impl<'a, R: AccessRules> Draw<'a, R> {
let head = self let head = self
.extend_head(recorder, 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(
.add_lone_loose_seg(
recorder, recorder,
dot, dot,
into, into,
@ -86,8 +108,7 @@ impl<'a, R: AccessRules> Draw<'a, R> {
.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(
.add_seq_loose_seg(
recorder, recorder,
into.into(), into.into(),
dot, dot,
@ -102,9 +123,9 @@ impl<'a, R: AccessRules> Draw<'a, R> {
}) })
} }
#[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, recorder: &mut LayoutEdit,
head: Head, head: Head,
@ -131,9 +152,9 @@ 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, recorder: &mut LayoutEdit,
head: Head, head: Head,
@ -159,8 +180,60 @@ 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 undo_cane(&mut self, recorder: &mut LayoutEdit, head: CaneHead) -> Option<Head> {
let prev_dot = self
.drawing()
.primitive(head.cane.seg)
.other_joint(head.cane.dot.into());
self.remove_cane(recorder, &head.cane, head.face);
Some(self.guide().head(prev_dot))
}
}
trait DrawPrivate {
type R;
fn cane_around(
&mut self,
recorder: &mut LayoutEdit,
head: Head,
around: GearIndex,
from: Point,
to: Point,
cw: bool,
width: f64,
offset: f64,
) -> Result<CaneHead, DrawingException>;
fn extend_head(
&mut self,
recorder: &mut LayoutEdit,
head: Head,
to: Point,
) -> Result<Head, Infringement>;
fn cane(
&mut self,
recorder: &mut LayoutEdit,
head: Head,
around: GearIndex,
to: Point,
cw: bool,
width: f64,
offset: f64,
) -> Result<CaneHead, DrawingException>;
fn guide(&self) -> Guide<CompoundWeight, Self::R>;
}
impl<R: AccessRules> DrawPrivate for Layout<R> {
type R = R;
#[debug_ensures(ret.is_ok() -> self.drawing().node_count() == old(self.drawing().node_count() + 4))]
#[debug_ensures(ret.is_err() -> self.drawing().node_count() == old(self.drawing().node_count()))]
fn cane_around( fn cane_around(
&mut self, &mut self,
recorder: &mut LayoutEdit, recorder: &mut LayoutEdit,
@ -176,7 +249,7 @@ impl<'a, R: AccessRules> Draw<'a, R> {
self.cane(recorder, head, around, to, cw, width, offset) self.cane(recorder, head, around, to, cw, width, offset)
} }
#[debug_ensures(self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))] #[debug_ensures(self.drawing().node_count() == old(self.drawing().node_count()))]
fn extend_head( fn extend_head(
&mut self, &mut self,
recorder: &mut LayoutEdit, recorder: &mut LayoutEdit,
@ -184,15 +257,15 @@ impl<'a, R: AccessRules> Draw<'a, R> {
to: Point, to: Point,
) -> Result<Head, Infringement> { ) -> Result<Head, Infringement> {
if let Head::Cane(head) = head { if let Head::Cane(head) = head {
self.layout.move_dot(recorder, head.face.into(), to)?; self.move_dot(recorder, head.face.into(), to)?;
Ok(Head::Cane(head)) Ok(Head::Cane(head))
} else { } else {
Ok(head) Ok(head)
} }
} }
#[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()))]
fn cane( fn cane(
&mut self, &mut self,
recorder: &mut LayoutEdit, recorder: &mut LayoutEdit,
@ -203,9 +276,9 @@ impl<'a, R: AccessRules> Draw<'a, R> {
width: f64, width: f64,
offset: f64, offset: f64,
) -> Result<CaneHead, DrawingException> { ) -> Result<CaneHead, DrawingException> {
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();
let cane = self.layout.insert_cane( let cane = self.insert_cane(
recorder, recorder,
head.face(), head.face(),
around, around,
@ -231,29 +304,12 @@ impl<'a, R: AccessRules> Draw<'a, R> {
cw, cw,
)?; )?;
Ok(CaneHead { Ok(CaneHead {
face: self face: self.drawing().primitive(cane.bend).other_joint(cane.dot),
.layout
.drawing()
.primitive(cane.bend)
.other_joint(cane.dot),
cane, cane,
}) })
} }
#[debug_ensures(ret.is_some() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() - 4))] fn guide(&self) -> Guide<CompoundWeight, R> {
#[debug_ensures(ret.is_none() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))] Guide::new(self.drawing())
pub fn undo_cane(&mut self, recorder: &mut LayoutEdit, head: CaneHead) -> Option<Head> {
let prev_dot = self
.layout
.drawing()
.primitive(head.cane.seg)
.other_joint(head.cane.dot.into());
self.layout.remove_cane(recorder, &head.cane, head.face);
Some(self.guide().head(prev_dot))
}
fn guide(&self) -> Guide<impl Copy, R> {
Guide::new(self.layout.drawing())
} }
} }

View File

@ -85,13 +85,9 @@ 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, .cane_around_dot(&mut self.recorder, head, around, cw, width)?)
around,
cw,
width,
)?)
} }
fn wrap_around_loose_bend( fn wrap_around_loose_bend(
@ -102,13 +98,9 @@ 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, .cane_around_bend(&mut self.recorder, head, around.into(), cw, width)?)
around.into(),
cw,
width,
)?)
} }
fn binavvertex(&self, navmesh: &Navmesh, navvertex: NavvertexIndex) -> BinavvertexNodeIndex { fn binavvertex(&self, navmesh: &Navmesh, navvertex: NavvertexIndex) -> BinavvertexNodeIndex {
@ -159,7 +151,8 @@ 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
.layout
.undo_cane(&mut self.recorder, head) .undo_cane(&mut self.recorder, head)
.unwrap(); .unwrap();
} else { } else {

View File

@ -53,12 +53,9 @@ 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
&mut navcord.recorder, .layout
navcord.head, .finish_in_dot(&mut navcord.recorder, navcord.head, target, width)?)
target,
width,
)?)
} }
#[debug_requires(path[0] == navcord.path[0])] #[debug_requires(path[0] == navcord.path[0])]