diff --git a/src/bin/topola-egui/app.rs b/src/bin/topola-egui/app.rs index af43d7f..d6eefdf 100644 --- a/src/bin/topola-egui/app.rs +++ b/src/bin/topola-egui/app.rs @@ -5,9 +5,9 @@ use std::{ }; use topola::{ + drawing::{graph::MakePrimitive, primitive::MakeShape, Drawing}, dsn::{design::DsnDesign, rules::DsnRules}, geometry::shape::{BendShape, DotShape, SegShape, Shape}, - layout::{graph::MakePrimitive, primitive::MakeShape, Layout}, math::Circle, }; @@ -24,7 +24,7 @@ pub struct App { text_channel: (Sender, Receiver), #[serde(skip)] - layout: Option>, + drawing: Option>, #[serde(skip)] from_rect: egui::emath::Rect, @@ -36,7 +36,7 @@ impl Default for App { // Example stuff: label: "Hello World!".to_owned(), text_channel: channel(), - layout: None, + drawing: None, from_rect: egui::Rect::from_x_y_ranges(0.0..=1000000.0, 0.0..=500000.0), } } @@ -65,12 +65,12 @@ impl eframe::App for App { if cfg!(target_arch = "wasm32") { if let Ok(file_contents) = self.text_channel.1.try_recv() { let design = DsnDesign::load_from_string(file_contents).unwrap(); - self.layout = Some(design.make_layout()); + self.drawing = Some(design.make_drawing()); } } else { if let Ok(path) = self.text_channel.1.try_recv() { let design = DsnDesign::load_from_file(&path).unwrap(); - self.layout = Some(design.make_layout()); + self.drawing = Some(design.make_drawing()); } } @@ -138,7 +138,7 @@ impl eframe::App for App { let transform = egui::emath::RectTransform::from_to(self.from_rect, viewport_rect); let mut painter = Painter::new(ui, transform); - if let Some(layout) = &self.layout { + if let Some(layout) = &self.drawing { for node in layout.layer_nodes(1) { let shape = node.primitive(layout).shape(); painter.paint_shape(&shape, egui::Color32::from_rgb(52, 52, 200)); diff --git a/src/bin/topola-sdl2-demo/main.rs b/src/bin/topola-sdl2-demo/main.rs index 62050be..6ba516f 100644 --- a/src/bin/topola-sdl2-demo/main.rs +++ b/src/bin/topola-sdl2-demo/main.rs @@ -12,17 +12,17 @@ macro_rules! dbg_dot { use geo::point; use painter::Painter; use petgraph::visit::{EdgeRef, IntoEdgeReferences}; -use topola::board::connectivity::BandIndex; -use topola::board::Board; use topola::draw::DrawException; +use topola::drawing::dot::FixedDotWeight; +use topola::drawing::graph::{GeometryIndex, MakePrimitive}; +use topola::drawing::primitive::MakeShape; +use topola::drawing::rules::{Conditions, RulesTrait}; +use topola::drawing::seg::FixedSegWeight; +use topola::drawing::{Drawing, Infringement, LayoutException}; use topola::dsn::design::DsnDesign; use topola::geometry::shape::{Shape, ShapeTrait}; -use topola::layout::dot::FixedDotWeight; -use topola::layout::graph::{GeometryIndex, MakePrimitive}; -use topola::layout::primitive::MakeShape; -use topola::layout::rules::{Conditions, RulesTrait}; -use topola::layout::seg::FixedSegWeight; -use topola::layout::{Infringement, Layout, LayoutException}; +use topola::layout::connectivity::BandIndex; +use topola::layout::Layout; use topola::mesh::{Mesh, MeshEdgeReference, VertexIndex}; use topola::router::RouterObserverTrait; @@ -76,7 +76,7 @@ impl RulesTrait for SimpleRules { // Clunky enum to work around borrow checker. enum RouterOrLayout<'a, R: RulesTrait> { Router(&'a mut Router), - Layout(&'a Layout), + Layout(&'a Drawing), } struct EmptyRouterObserver; @@ -129,7 +129,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait for DebugRouterObserver<'a> { self.renderer, self.font_context, self.view, - RouterOrLayout::Layout(tracer.board.layout()), + RouterOrLayout::Layout(tracer.layout.layout()), None, Some(tracer.mesh.clone()), &trace.path, @@ -148,7 +148,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait for DebugRouterObserver<'a> { self.renderer, self.font_context, self.view, - RouterOrLayout::Layout(tracer.board.layout()), + RouterOrLayout::Layout(tracer.layout.layout()), None, Some(tracer.mesh.clone()), &path, @@ -180,7 +180,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait for DebugRouterObserver<'a> { self.renderer, self.font_context, self.view, - RouterOrLayout::Layout(tracer.board.layout()), + RouterOrLayout::Layout(tracer.layout.layout()), None, Some(tracer.mesh.clone()), &trace.path, @@ -256,9 +256,9 @@ fn main() -> Result<(), anyhow::Error> { )?; //let design = DsnDesign::load_from_file("tests/data/test/test.dsn")?; //dbg!(&design); - let layout = design.make_layout(); - let board = Board::new(layout); - let mut router = Router::new(board); + let drawing = design.make_drawing(); + let layout = Layout::new(drawing); + let mut router = Router::new(layout); let mut view = View { pan: vec2f(-80000.0, -60000.0), @@ -271,7 +271,7 @@ fn main() -> Result<(), anyhow::Error> { &mut renderer, &font_context, &mut view, - RouterOrLayout::Layout(router.board.layout()), + RouterOrLayout::Layout(router.layout.layout()), None, None, &[], @@ -295,7 +295,7 @@ fn main() -> Result<(), anyhow::Error> { &mut renderer, &font_context, &mut view, - RouterOrLayout::Layout(router.board.layout()), + RouterOrLayout::Layout(router.layout.layout()), None, None, &[], @@ -388,7 +388,7 @@ fn render_times( maybe_mesh = None; } - router.board.layout() + router.layout.layout() } RouterOrLayout::Layout(layout) => layout, }; diff --git a/src/board/board.rs b/src/board/board.rs deleted file mode 100644 index ebcc366..0000000 --- a/src/board/board.rs +++ /dev/null @@ -1,118 +0,0 @@ -use geo::Point; -use petgraph::stable_graph::StableDiGraph; - -use crate::{ - graph::GetNodeIndex, - layout::{ - bend::LooseBendWeight, - dot::{DotIndex, FixedDotIndex, LooseDotIndex, LooseDotWeight}, - rules::RulesTrait, - seg::{LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex, SeqLooseSegWeight}, - segbend::Segbend, - Infringement, Layout, LayoutException, - }, - wraparoundable::WraparoundableIndex, -}; - -use super::connectivity::{ - BandIndex, BandWeight, ConnectivityLabel, ConnectivityWeight, ContinentIndex, -}; - -pub struct Board { - layout: Layout, // Shouldn't be public, but is for now because `Draw` needs it. - connectivity: StableDiGraph, -} - -impl Board { - pub fn new(layout: Layout) -> Self { - Self { - layout, - connectivity: StableDiGraph::default(), - } - } - - pub fn remove_band(&mut self, band: BandIndex) { - todo!() - } - - pub fn remove_segbend(&mut self, segbend: &Segbend, face: LooseDotIndex) { - self.layout.remove_segbend(segbend, face) - } - - pub fn start_band(&mut self, from: FixedDotIndex) -> BandIndex { - let band = self - .connectivity - .add_node(ConnectivityWeight::Band(BandWeight { from, to: None })); - self.connectivity.update_edge( - self.continent(from.into()).node_index(), - band, - ConnectivityLabel::Band, - ); - BandIndex::new(band) - } - - pub fn finish_band(&mut self, band: BandIndex, to: FixedDotIndex) { - self.connectivity.update_edge( - band.node_index(), - self.continent(to.into()).node_index(), - ConnectivityLabel::Band, - ); - } - - pub fn insert_segbend( - &mut self, - from: DotIndex, - around: WraparoundableIndex, - dot_weight: LooseDotWeight, - seg_weight: SeqLooseSegWeight, - bend_weight: LooseBendWeight, - cw: bool, - ) -> Result { - self.layout - .insert_segbend(from, around, dot_weight, seg_weight, bend_weight, cw) - } - - pub fn add_lone_loose_seg( - &mut self, - from: FixedDotIndex, - to: FixedDotIndex, - weight: LoneLooseSegWeight, - ) -> Result { - self.layout.add_lone_loose_seg(from, to, weight) - } - - pub fn add_seq_loose_seg( - &mut self, - from: DotIndex, - to: LooseDotIndex, - weight: SeqLooseSegWeight, - ) -> Result { - self.layout.add_seq_loose_seg(from, to, weight) - } - - pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> { - self.layout.move_dot(dot, to) - } - - pub fn band_from(&self, band: BandIndex) -> FixedDotIndex { - todo!() - } - - pub fn band_to(&self, band: BandIndex) -> Option { - todo!() - } - - pub fn band_length(&self, band: BandIndex) -> f64 { - // TODO. - 0.0 - } - - pub fn layout(&self) -> &Layout { - &self.layout - } - - pub fn continent(&self, dot: FixedDotIndex) -> ContinentIndex { - // TODO. - ContinentIndex::new(0.into()) - } -} diff --git a/src/board/mod.rs b/src/board/mod.rs deleted file mode 100644 index 34c2521..0000000 --- a/src/board/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod board; -pub mod connectivity; - -pub use board::*; diff --git a/src/draw.rs b/src/draw.rs index 0a01938..59c81e5 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -3,8 +3,7 @@ use geo::{EuclideanLength, Point}; use thiserror::Error; use crate::{ - board::Board, - layout::{ + drawing::{ bend::{BendIndex, LooseBendWeight}, dot::{DotIndex, FixedDotIndex, LooseDotIndex, LooseDotWeight}, graph::{GetLayer, GetNet, MakePrimitive}, @@ -14,6 +13,7 @@ use crate::{ seg::{LoneLooseSegWeight, SeqLooseSegWeight}, Infringement, LayoutException, }, + layout::Layout, math::{Circle, NoTangents}, wraparoundable::WraparoundableIndex, }; @@ -31,20 +31,20 @@ pub enum DrawException { } pub struct Draw<'a, R: RulesTrait> { - board: &'a mut Board, + layout: &'a mut Layout, } impl<'a, R: RulesTrait> Draw<'a, R> { - pub fn new(board: &'a mut Board) -> Self { - Self { board } + pub fn new(layout: &'a mut Layout) -> Self { + Self { layout } } pub fn start(&mut self, from: LooseDotIndex) -> Head { self.guide().segbend_head(from).into() } - #[debug_ensures(ret.is_ok() -> self.board.layout().node_count() == old(self.board.layout().node_count() + 1))] - #[debug_ensures(ret.is_err() -> self.board.layout().node_count() == old(self.board.layout().node_count()))] + #[debug_ensures(ret.is_ok() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() + 1))] + #[debug_ensures(ret.is_err() -> self.layout.layout().node_count() == old(self.layout.layout().node_count()))] pub fn finish_in_dot( &mut self, head: Head, @@ -58,17 +58,17 @@ impl<'a, R: RulesTrait> Draw<'a, R> { let head = self .extend_head(head, tangent.start_point()) .map_err(|err| DrawException::CannotFinishIn(into, err.into()))?; - let layer = head.face().primitive(self.board.layout()).layer(); - let net = head.face().primitive(self.board.layout()).net(); + let layer = head.face().primitive(self.layout.layout()).layer(); + let net = head.face().primitive(self.layout.layout()).net(); match head.face() { DotIndex::Fixed(dot) => { - self.board + self.layout .add_lone_loose_seg(dot, into.into(), LoneLooseSegWeight { width, layer, net }) .map_err(|err| DrawException::CannotFinishIn(into, err.into()))?; } DotIndex::Loose(dot) => { - self.board + self.layout .add_seq_loose_seg(into.into(), dot, SeqLooseSegWeight { width, layer, net }) .map_err(|err| DrawException::CannotFinishIn(into, err.into()))?; } @@ -76,8 +76,8 @@ impl<'a, R: RulesTrait> Draw<'a, R> { Ok::<(), DrawException>(()) } - #[debug_ensures(ret.is_ok() -> self.board.layout().node_count() == old(self.board.layout().node_count() + 4))] - #[debug_ensures(ret.is_err() -> self.board.layout().node_count() == old(self.board.layout().node_count()))] + #[debug_ensures(ret.is_ok() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() + 4))] + #[debug_ensures(ret.is_err() -> self.layout.layout().node_count() == old(self.layout.layout().node_count()))] pub fn segbend_around_dot( &mut self, head: Head, @@ -121,8 +121,8 @@ impl<'a, R: RulesTrait> Draw<'a, R> { )) } - #[debug_ensures(ret.is_ok() -> self.board.layout().node_count() == old(self.board.layout().node_count() + 4))] - #[debug_ensures(ret.is_err() -> self.board.layout().node_count() == old(self.board.layout().node_count()))] + #[debug_ensures(ret.is_ok() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() + 4))] + #[debug_ensures(ret.is_err() -> self.layout.layout().node_count() == old(self.layout.layout().node_count()))] pub fn segbend_around_bend( &mut self, head: Head, @@ -166,8 +166,8 @@ impl<'a, R: RulesTrait> Draw<'a, R> { )) } - #[debug_ensures(ret.is_ok() -> self.board.layout().node_count() == old(self.board.layout().node_count() + 4))] - #[debug_ensures(ret.is_err() -> self.board.layout().node_count() == old(self.board.layout().node_count()))] + #[debug_ensures(ret.is_ok() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() + 4))] + #[debug_ensures(ret.is_err() -> self.layout.layout().node_count() == old(self.layout.layout().node_count()))] fn segbend_around( &mut self, head: Head, @@ -182,18 +182,18 @@ impl<'a, R: RulesTrait> Draw<'a, R> { self.segbend(head, around, to, cw, width, offset) } - #[debug_ensures(self.board.layout().node_count() == old(self.board.layout().node_count()))] + #[debug_ensures(self.layout.layout().node_count() == old(self.layout.layout().node_count()))] fn extend_head(&mut self, head: Head, to: Point) -> Result { if let Head::Segbend(head) = head { - self.board.move_dot(head.face.into(), to)?; + self.layout.move_dot(head.face.into(), to)?; Ok(Head::Segbend(head)) } else { Ok(head) } } - #[debug_ensures(ret.is_ok() -> self.board.layout().node_count() == old(self.board.layout().node_count() + 4))] - #[debug_ensures(ret.is_err() -> self.board.layout().node_count() == old(self.board.layout().node_count()))] + #[debug_ensures(ret.is_ok() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() + 4))] + #[debug_ensures(ret.is_err() -> self.layout.layout().node_count() == old(self.layout.layout().node_count()))] fn segbend( &mut self, head: Head, @@ -203,9 +203,9 @@ impl<'a, R: RulesTrait> Draw<'a, R> { width: f64, offset: f64, ) -> Result { - let layer = head.face().primitive(self.board.layout()).layer(); - let net = head.face().primitive(self.board.layout()).net(); - let segbend = self.board.insert_segbend( + let layer = head.face().primitive(self.layout.layout()).layer(); + let net = head.face().primitive(self.layout.layout()).net(); + let segbend = self.layout.insert_segbend( head.face(), around, LooseDotWeight { @@ -227,7 +227,7 @@ impl<'a, R: RulesTrait> Draw<'a, R> { )?; Ok::(SegbendHead { face: self - .board + .layout .layout() .primitive(segbend.bend) .other_joint(segbend.dot), @@ -235,20 +235,20 @@ impl<'a, R: RulesTrait> Draw<'a, R> { }) } - #[debug_ensures(ret.is_some() -> self.board.layout().node_count() == old(self.board.layout().node_count() - 4))] - #[debug_ensures(ret.is_none() -> self.board.layout().node_count() == old(self.board.layout().node_count()))] + #[debug_ensures(ret.is_some() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() - 4))] + #[debug_ensures(ret.is_none() -> self.layout.layout().node_count() == old(self.layout.layout().node_count()))] pub fn undo_segbend(&mut self, head: SegbendHead) -> Option { let prev_dot = self - .board + .layout .layout() .primitive(head.segbend.seg) .other_joint(head.segbend.dot.into()); - self.board.remove_segbend(&head.segbend, head.face); + self.layout.remove_segbend(&head.segbend, head.face); Some(self.guide().head(prev_dot)) } fn guide(&self) -> Guide { - Guide::new(self.board.layout()) + Guide::new(self.layout.layout()) } } diff --git a/src/layout/bend.rs b/src/drawing/bend.rs similarity index 99% rename from src/layout/bend.rs rename to src/drawing/bend.rs index 9535b50..90be194 100644 --- a/src/layout/bend.rs +++ b/src/drawing/bend.rs @@ -1,14 +1,14 @@ use enum_dispatch::enum_dispatch; use crate::{ - geometry::{BendWeightTrait, GetOffset, GetWidth, SetOffset}, - graph::{GenericIndex, GetNodeIndex}, - layout::{ + drawing::{ graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, MakePrimitive, Retag}, primitive::{GenericPrimitive, Primitive}, rules::RulesTrait, - Layout, + Drawing, }, + geometry::{BendWeightTrait, GetOffset, GetWidth, SetOffset}, + graph::{GenericIndex, GetNodeIndex}, }; use petgraph::stable_graph::NodeIndex; diff --git a/src/layout/collect.rs b/src/drawing/collect.rs similarity index 65% rename from src/layout/collect.rs rename to src/drawing/collect.rs index 6df03f6..e120888 100644 --- a/src/layout/collect.rs +++ b/src/drawing/collect.rs @@ -5,32 +5,32 @@ use super::{ graph::GeometryIndex, primitive::{GetInnerOuter, GetJoints}, rules::RulesTrait, - Layout, + Drawing, }; #[derive(Debug)] pub struct Collect<'a, R: RulesTrait> { - layout: &'a Layout, + drawing: &'a Drawing, } impl<'a, R: RulesTrait> Collect<'a, R> { - pub fn new(layout: &'a Layout) -> Self { - Self { layout } + pub fn new(drawing: &'a Drawing) -> Self { + Self { drawing } } pub fn bend_bow(&self, bend: LooseBendIndex) -> Vec { let mut v: Vec = vec![]; v.push(bend.into()); - let ends = self.layout.primitive(bend).joints(); + let ends = self.drawing.primitive(bend).joints(); v.push(ends.0.into()); v.push(ends.1.into()); - if let Some(seg0) = self.layout.primitive(ends.0).seg() { + if let Some(seg0) = self.drawing.primitive(ends.0).seg() { v.push(seg0.into()); } - if let Some(seg1) = self.layout.primitive(ends.1).seg() { + if let Some(seg1) = self.drawing.primitive(ends.1).seg() { v.push(seg1.into()); } @@ -41,7 +41,7 @@ impl<'a, R: RulesTrait> Collect<'a, R> { let mut v = vec![]; let mut rail = bend; - while let Some(outer) = self.layout.primitive(rail).outer() { + while let Some(outer) = self.drawing.primitive(rail).outer() { v.append(&mut self.bend_bow(outer.into())); rail = outer; } @@ -53,8 +53,8 @@ impl<'a, R: RulesTrait> Collect<'a, R> { let mut v = vec![]; let mut rail = around.into(); - while let Some(outer) = self.layout.wraparoundable(rail).wraparound() { - let primitive = self.layout.primitive(outer); + while let Some(outer) = self.drawing.wraparoundable(rail).wraparound() { + let primitive = self.drawing.primitive(outer); v.push(outer.into()); @@ -62,8 +62,8 @@ impl<'a, R: RulesTrait> Collect<'a, R> { v.push(ends.0.into()); v.push(ends.1.into()); - v.push(self.layout.primitive(ends.0).seg().unwrap().into()); - v.push(self.layout.primitive(ends.1).seg().unwrap().into()); + v.push(self.drawing.primitive(ends.0).seg().unwrap().into()); + v.push(self.drawing.primitive(ends.1).seg().unwrap().into()); rail = outer.into(); } diff --git a/src/layout/dot.rs b/src/drawing/dot.rs similarity index 98% rename from src/layout/dot.rs rename to src/drawing/dot.rs index 81d1a9c..9f6231f 100644 --- a/src/layout/dot.rs +++ b/src/drawing/dot.rs @@ -4,14 +4,14 @@ use geo::Point; use petgraph::stable_graph::NodeIndex; use crate::{ - geometry::{DotWeightTrait, GetPos, GetWidth, SetPos}, - graph::{GenericIndex, GetNodeIndex}, - layout::{ + drawing::{ graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, MakePrimitive, Retag}, primitive::{GenericPrimitive, Primitive}, rules::RulesTrait, - Layout, + Drawing, }, + geometry::{DotWeightTrait, GetPos, GetWidth, SetPos}, + graph::{GenericIndex, GetNodeIndex}, math::Circle, }; diff --git a/src/drawing/drawing.rs b/src/drawing/drawing.rs new file mode 100644 index 0000000..c844231 --- /dev/null +++ b/src/drawing/drawing.rs @@ -0,0 +1,823 @@ +use contracts::debug_ensures; +use enum_dispatch::enum_dispatch; +use geo::Point; + +use rstar::{RTreeObject, AABB}; +use thiserror::Error; + +use super::graph::GetLayer; +use super::loose::{GetNextLoose, Loose, LooseIndex}; +use super::rules::RulesTrait; +use super::segbend::Segbend; +use crate::drawing::bend::BendIndex; +use crate::drawing::collect::Collect; +use crate::drawing::dot::DotWeight; +use crate::drawing::graph::GetNet; +use crate::drawing::guide::Guide; +use crate::drawing::primitive::GetLimbs; +use crate::drawing::rules::GetConditions; +use crate::drawing::{ + bend::{FixedBendIndex, LooseBendIndex, LooseBendWeight}, + dot::{DotIndex, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, + graph::{GeometryIndex, GeometryWeight, MakePrimitive}, + primitive::{GenericPrimitive, GetCore, GetInnerOuter, GetJoints, GetOtherJoint, MakeShape}, + seg::{ + FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex, + SeqLooseSegIndex, SeqLooseSegWeight, + }, +}; +use crate::geometry::{ + shape::{Shape, ShapeTrait}, + with_rtree::GeometryWithRtree, + BendWeightTrait, DotWeightTrait, Geometry, GeometryLabel, GetOffset, GetPos, GetWidth, + SegWeightTrait, +}; +use crate::graph::{GenericIndex, GetNodeIndex}; +use crate::math::NoTangents; +use crate::wraparoundable::{GetWraparound, Wraparoundable, WraparoundableIndex}; + +use super::bend::BendWeight; +use super::seg::SegWeight; + +#[enum_dispatch] +#[derive(Error, Debug, Clone, Copy)] +pub enum LayoutException { + #[error(transparent)] + NoTangents(#[from] NoTangents), + #[error(transparent)] + Infringement(#[from] Infringement), + #[error(transparent)] + Collision(#[from] Collision), + #[error(transparent)] + AlreadyConnected(#[from] AlreadyConnected), +} + +// TODO add real error messages + these should eventually use Display +#[derive(Error, Debug, Clone, Copy)] +#[error("{0:?} infringes on {1:?}")] +pub struct Infringement(pub Shape, pub GeometryIndex); + +#[derive(Error, Debug, Clone, Copy)] +#[error("{0:?} collides with {1:?}")] +pub struct Collision(pub Shape, pub GeometryIndex); + +#[derive(Error, Debug, Clone, Copy)] +#[error("{1:?} is already connected to net {0}")] +pub struct AlreadyConnected(pub i64, pub GeometryIndex); + +#[derive(Debug)] +pub struct Drawing { + geometry_with_rtree: GeometryWithRtree< + GeometryWeight, + DotWeight, + SegWeight, + BendWeight, + GeometryIndex, + DotIndex, + SegIndex, + BendIndex, + >, + rules: R, +} + +impl Drawing { + pub fn new(rules: R) -> Self { + Self { + geometry_with_rtree: GeometryWithRtree::new(2), + rules, + } + } + + pub fn remove_band(&mut self, first_loose: SeqLooseSegIndex) { + let mut dots = vec![]; + let mut segs = vec![]; + let mut bends = vec![]; + let mut outers = vec![]; + + let mut maybe_loose = Some(first_loose.into()); + let mut prev = None; + + while let Some(loose) = maybe_loose { + match loose { + LooseIndex::Dot(dot) => { + dots.push(dot); + } + LooseIndex::LoneSeg(seg) => { + self.geometry_with_rtree.remove_seg(seg.into()); + break; + } + LooseIndex::SeqSeg(seg) => { + segs.push(seg); + } + LooseIndex::Bend(bend) => { + bends.push(bend); + + if let Some(outer) = self.primitive(bend).outer() { + outers.push(outer); + self.reattach_bend(outer, self.primitive(bend).inner()); + } + } + } + + let prev_prev = prev; + prev = maybe_loose; + maybe_loose = self.loose(loose).next_loose(prev_prev); + } + + for bend in bends { + self.geometry_with_rtree.remove_bend(bend.into()); + } + + for seg in segs { + self.geometry_with_rtree.remove_seg(seg.into()); + } + + // We must remove the dots only after the segs and bends because we need dots to calculate + // the shapes, which we first need unchanged to remove the segs and bends from the R-tree. + + for dot in dots { + self.geometry_with_rtree.remove_dot(dot.into()); + } + + for outer in outers { + self.update_this_and_outward_bows(outer).unwrap(); // Must never fail. + } + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 4))] + pub fn remove_segbend(&mut self, segbend: &Segbend, face: LooseDotIndex) { + let maybe_outer = self.primitive(segbend.bend).outer(); + + // Removing a loose bend affects its outer bends. + if let Some(outer) = maybe_outer { + self.reattach_bend(outer, self.primitive(segbend.bend).inner()); + } + + self.geometry_with_rtree.remove_bend(segbend.bend.into()); + self.geometry_with_rtree.remove_seg(segbend.seg.into()); + + // We must remove the dots only after the segs and bends because we need dots to calculate + // the shapes, which we first need unchanged to remove the segs and bends from the R-tree. + + self.geometry_with_rtree.remove_dot(face.into()); + self.geometry_with_rtree.remove_dot(segbend.dot.into()); + + if let Some(outer) = maybe_outer { + self.update_this_and_outward_bows(outer).unwrap(); // Must never fail. + } + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result { + self.add_dot_infringably(weight, None) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + fn add_dot_infringably + GetLayer>( + &mut self, + weight: W, + infringables: Option<&[GeometryIndex]>, + ) -> Result, Infringement> + where + GenericIndex: Into + Copy, + { + let dot = self.geometry_with_rtree.add_dot(weight); + self.fail_and_remove_if_infringes_except(dot.into(), infringables)?; + + Ok(dot) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn add_fixed_seg( + &mut self, + from: FixedDotIndex, + to: FixedDotIndex, + weight: FixedSegWeight, + ) -> Result { + self.add_seg_infringably(from.into(), to.into(), weight, None) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 4))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() >= old(self.geometry_with_rtree.graph().edge_count() + 5))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn insert_segbend( + &mut self, + from: DotIndex, + around: WraparoundableIndex, + dot_weight: LooseDotWeight, + seg_weight: SeqLooseSegWeight, + bend_weight: LooseBendWeight, + cw: bool, + ) -> Result { + let maybe_wraparound = self.wraparoundable(around).wraparound(); + let infringables = self.collect().wraparounded_bows(around); + + let segbend = self.add_segbend_infringably( + from, + around, + dot_weight, + seg_weight, + bend_weight, + cw, + Some(&infringables), + )?; + + if let Some(wraparound) = maybe_wraparound { + self.reattach_bend(wraparound, Some(segbend.bend)); + } + + if let Some(outer) = self.primitive(segbend.bend).outer() { + self.update_this_and_outward_bows(outer).map_err(|err| { + let joint = self.primitive(segbend.bend).other_joint(segbend.dot); + self.remove_segbend(&segbend, joint.into()); + err + })?; + } + + // Segs must not cross. + if let Some(collision) = self.detect_collision(segbend.seg.into()) { + let joint = self.primitive(segbend.bend).other_joint(segbend.dot); + self.remove_segbend(&segbend, joint.into()); + return Err(collision.into()); + } + + Ok::(segbend) + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()) + || self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() - 1) + || self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 1))] + fn reattach_bend(&mut self, bend: LooseBendIndex, maybe_new_inner: Option) { + self.geometry_with_rtree + .reattach_bend(bend.into(), maybe_new_inner.map(Into::into)); + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn update_this_and_outward_bows( + &mut self, + around: LooseBendIndex, + ) -> Result<(), LayoutException> { + // FIXME: Fail gracefully on infringement. + let mut maybe_rail = Some(around); + + while let Some(rail) = maybe_rail { + let rail_primitive = self.primitive(rail); + let joints = rail_primitive.joints(); + + let guide = Guide::new(self); + let from_head = guide.rear_head(joints.1); + let to_head = guide.rear_head(joints.0); + + if let Some(inner) = rail_primitive.inner() { + let from = guide + .head_around_bend_segment( + &from_head.into(), + inner.into(), + true, + self.primitive(rail).width(), + )? + .end_point(); + let to = guide + .head_around_bend_segment( + &to_head.into(), + inner.into(), + false, + self.primitive(rail).width(), + )? + .end_point(); + let offset = guide.head_around_bend_offset( + &from_head.into(), + inner.into(), + self.primitive(rail).width(), + ); + + self.move_dot_infringably( + joints.0.into(), + from, + Some(&self.collect().bend_outer_bows(rail)), + )?; + self.move_dot_infringably( + joints.1.into(), + to, + Some(&self.collect().bend_outer_bows(rail)), + )?; + + self.shift_bend_infringably( + rail.into(), + offset, + Some(&self.collect().bend_outer_bows(rail)), + )?; + + // Update offsets in case the rule conditions changed. + } else { + let core = rail_primitive.core(); + let from = guide + .head_around_dot_segment( + &from_head.into(), + core.into(), + true, + self.primitive(rail).width(), + )? + .end_point(); + let to = guide + .head_around_dot_segment( + &to_head.into(), + core.into(), + false, + self.primitive(rail).width(), + )? + .end_point(); + let offset = guide.head_around_dot_offset( + &from_head.into(), + core.into(), + self.primitive(rail).width(), + ); + + self.move_dot_infringably( + joints.0.into(), + from, + Some(&self.collect().bend_outer_bows(rail)), + )?; + self.move_dot_infringably( + joints.1.into(), + to, + Some(&self.collect().bend_outer_bows(rail)), + )?; + + self.shift_bend_infringably( + rail.into(), + offset, + Some(&self.collect().bend_outer_bows(rail)), + )?; + } + + maybe_rail = self.primitive(rail).outer(); + } + + Ok::<(), LayoutException>(()) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 4))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() >= old(self.geometry_with_rtree.graph().edge_count() + 5))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn add_segbend( + &mut self, + from: DotIndex, + around: WraparoundableIndex, + dot_weight: LooseDotWeight, + seg_weight: SeqLooseSegWeight, + bend_weight: LooseBendWeight, + cw: bool, + ) -> Result { + self.add_segbend_infringably( + from, + around, + dot_weight, + seg_weight, + bend_weight, + cw, + Some(&self.collect().wraparounded_bows(around)), + ) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 4))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() >= old(self.geometry_with_rtree.graph().edge_count() + 5))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn add_segbend_infringably( + &mut self, + from: DotIndex, + around: WraparoundableIndex, + dot_weight: LooseDotWeight, + seg_weight: SeqLooseSegWeight, + bend_weight: LooseBendWeight, + cw: bool, + infringables: Option<&[GeometryIndex]>, + ) -> Result { + let seg_to = self.add_dot_infringably(dot_weight, infringables)?; + let seg = self + .add_seg_infringably(from, seg_to.into(), seg_weight, infringables) + .map_err(|err| { + self.geometry_with_rtree.remove_dot(seg_to.into()); + err + })?; + + let to = self + .add_dot_infringably(dot_weight, infringables) + .map_err(|err| { + self.geometry_with_rtree.remove_seg(seg.into()); + self.geometry_with_rtree.remove_dot(seg_to.into()); + err + })?; + + let (bend_from, bend_to) = if cw { (to, seg_to) } else { (seg_to, to) }; + + let bend = self + .add_loose_bend_infringably(bend_from, bend_to, around, bend_weight, infringables) + .map_err(|err| { + self.geometry_with_rtree.remove_dot(to.into()); + self.geometry_with_rtree.remove_seg(seg.into()); + self.geometry_with_rtree.remove_dot(seg_to.into()); + err + })?; + + Ok::(Segbend { + seg, + dot: seg_to, + bend, + }) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn add_lone_loose_seg( + &mut self, + from: FixedDotIndex, + to: FixedDotIndex, + weight: LoneLooseSegWeight, + ) -> Result { + let seg = self.add_seg_infringably(from.into(), to.into(), weight, Some(&[]))?; + Ok(seg) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn add_seq_loose_seg( + &mut self, + from: DotIndex, + to: LooseDotIndex, + weight: SeqLooseSegWeight, + ) -> Result { + let seg = self.add_seg_infringably(from, to.into(), weight, Some(&[]))?; + Ok(seg) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn add_seg_infringably + GetLayer>( + &mut self, + from: DotIndex, + to: DotIndex, + weight: W, + infringables: Option<&[GeometryIndex]>, + ) -> Result, Infringement> + where + GenericIndex: Into + Copy, + { + let seg = self.geometry_with_rtree.add_seg(from, to, weight); + self.fail_and_remove_if_infringes_except(seg.into(), infringables)?; + + Ok(seg) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 3) + || self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 4))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn add_loose_bend_infringably( + &mut self, + from: LooseDotIndex, + to: LooseDotIndex, + around: WraparoundableIndex, + weight: LooseBendWeight, + infringables: Option<&[GeometryIndex]>, + ) -> Result { + // It makes no sense to wrap something around or under one of its connectables. + // + if weight.net == around.primitive(self).net() { + return Err(AlreadyConnected(weight.net, around.into()).into()); + } + // + if let Some(wraparound) = self.wraparoundable(around).wraparound() { + if weight.net == wraparound.primitive(self).net() { + return Err(AlreadyConnected(weight.net, wraparound.into()).into()); + } + } + + match around { + WraparoundableIndex::FixedDot(core) => self + .add_core_bend_infringably(from.into(), to.into(), core, weight, infringables) + .map_err(Into::into), + WraparoundableIndex::FixedBend(around) => self + .add_outer_bend_infringably(from, to, around.into(), weight, infringables) + .map_err(Into::into), + WraparoundableIndex::LooseBend(around) => self + .add_outer_bend_infringably(from, to, around.into(), weight, infringables) + .map_err(Into::into), + } + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 3))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn add_core_bend_infringably + GetLayer>( + &mut self, + from: DotIndex, + to: DotIndex, + core: FixedDotIndex, + weight: W, + infringables: Option<&[GeometryIndex]>, + ) -> Result, Infringement> + where + GenericIndex: Into + Copy, + { + let bend = self + .geometry_with_rtree + .add_bend(from, to, core.into(), weight); + + self.fail_and_remove_if_infringes_except(bend.into(), infringables)?; + Ok(bend) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 4))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn add_outer_bend_infringably( + &mut self, + from: LooseDotIndex, + to: LooseDotIndex, + inner: BendIndex, + weight: LooseBendWeight, + infringables: Option<&[GeometryIndex]>, + ) -> Result, Infringement> { + let core = *self + .geometry_with_rtree + .graph() + .neighbors(inner.node_index()) + .filter(|ni| { + matches!( + self.geometry_with_rtree + .graph() + .edge_weight( + self.geometry_with_rtree + .graph() + .find_edge(inner.node_index(), *ni) + .unwrap() + ) + .unwrap(), + GeometryLabel::Core + ) + }) + .map(|ni| FixedDotIndex::new(ni)) + .collect::>() + .first() + .unwrap(); + + let bend = self + .geometry_with_rtree + .add_bend(from.into(), to.into(), core.into(), weight); + self.geometry_with_rtree + .reattach_bend(bend.into(), Some(inner)); + + self.fail_and_remove_if_infringes_except(bend.into(), infringables)?; + Ok(bend) + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn flip_bend(&mut self, bend: FixedBendIndex) { + self.geometry_with_rtree.flip_bend(bend.into()); + } + + pub fn segbend(&self, dot: LooseDotIndex) -> Segbend { + Segbend::from_dot(dot, self) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))] + fn fail_and_remove_if_infringes_except( + &mut self, + node: GeometryIndex, + maybe_except: Option<&[GeometryIndex]>, + ) -> Result<(), Infringement> { + if let Some(infringement) = self.detect_infringement_except(node, maybe_except) { + if let Ok(dot) = node.try_into() { + self.geometry_with_rtree.remove_dot(dot); + } else if let Ok(seg) = node.try_into() { + self.geometry_with_rtree.remove_seg(seg); + } else if let Ok(bend) = node.try_into() { + self.geometry_with_rtree.remove_bend(bend); + } + return Err(infringement); + } + Ok(()) + } + + pub fn nodes(&self) -> impl Iterator + '_ { + self.geometry_with_rtree + .rtree() + .iter() + .map(|wrapper| wrapper.data) + } + + pub fn layer_nodes(&self, layer: u64) -> impl Iterator + '_ { + self.geometry_with_rtree + .rtree() + .locate_in_envelope_intersecting(&AABB::from_corners( + [-f64::INFINITY, -f64::INFINITY, layer as f64], + [f64::INFINITY, f64::INFINITY, layer as f64], + )) + .map(|wrapper| wrapper.data) + } + + pub fn node_count(&self) -> usize { + self.geometry_with_rtree.graph().node_count() + } +} + +impl Drawing { + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> { + match dot { + DotIndex::Fixed(..) => self.move_dot_infringably(dot, to, Some(&[])), + DotIndex::Loose(..) => self.move_dot_infringably(dot, to, Some(&[])), + } + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn move_dot_infringably( + &mut self, + dot: DotIndex, + to: Point, + infringables: Option<&[GeometryIndex]>, + ) -> Result<(), Infringement> { + let old_pos = self.geometry_with_rtree.geometry().dot_weight(dot).pos(); + self.geometry_with_rtree.move_dot(dot, to); + + for limb in dot.primitive(self).limbs() { + if let Some(infringement) = self.detect_infringement_except(limb.into(), infringables) { + // Restore original state. + self.geometry_with_rtree.move_dot(dot, old_pos); + return Err(infringement); + } + } + + if let Some(infringement) = self.detect_infringement_except(dot.into(), infringables) { + // Restore original state. + self.geometry_with_rtree.move_dot(dot, old_pos); + return Err(infringement); + } + + Ok(()) + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn shift_bend_infringably( + &mut self, + bend: BendIndex, + offset: f64, + infringables: Option<&[GeometryIndex]>, + ) -> Result<(), Infringement> { + let old_offset = self + .geometry_with_rtree + .geometry() + .bend_weight(bend) + .offset(); + self.geometry_with_rtree.shift_bend(bend, offset); + + if let Some(infringement) = self.detect_infringement_except(bend.into(), infringables) { + // Restore original state. + self.geometry_with_rtree.shift_bend(bend, old_offset); + return Err(infringement); + } + + Ok(()) + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn detect_infringement_except( + &self, + node: GeometryIndex, + maybe_except: Option<&[GeometryIndex]>, + ) -> Option { + let limiting_shape = node + .primitive(self) + .shape() + .inflate(self.rules.largest_clearance(node.primitive(self).net())); + let mut inflated_shape = limiting_shape; // Unused temporary value just for initialization. + let conditions = node.primitive(self).conditions(); + + self.geometry_with_rtree + .rtree() + .locate_in_envelope_intersecting(&limiting_shape.full_height_envelope_3d(0.0, 2)) + .filter(|wrapper| maybe_except.is_some_and(|except| !except.contains(&wrapper.data))) + .filter(|wrapper| !self.are_connectable(node, wrapper.data)) + .filter(|wrapper| { + let infringee_conditions = wrapper.data.primitive(self).conditions(); + + let epsilon = 1.0; + inflated_shape = node.primitive(self).shape().inflate( + (self.rules.clearance(&conditions, &infringee_conditions) - epsilon) + .clamp(0.0, f64::INFINITY), + ); + + inflated_shape.intersects(&wrapper.data.primitive(self).shape()) + }) + .map(|wrapper| wrapper.data) + .next() + .and_then(|infringee| Some(Infringement(inflated_shape, infringee))) + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn detect_collision(&self, node: GeometryIndex) -> Option { + let shape = node.primitive(self).shape(); + + self.geometry_with_rtree + .rtree() + .locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2)) + .filter(|wrapper| !self.are_connectable(node, wrapper.data)) + .filter(|wrapper| shape.intersects(&wrapper.data.primitive(self).shape())) + .map(|wrapper| wrapper.data) + .next() + .and_then(|collidee| Some(Collision(shape, collidee))) + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn are_connectable(&self, node1: GeometryIndex, node2: GeometryIndex) -> bool { + let node1_net = node1.primitive(self).net(); + let node2_net = node2.primitive(self).net(); + + (node1_net == node2_net) || node1_net == -1 || node2_net == -2 + } +} + +impl Drawing { + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn geometry( + &self, + ) -> &Geometry< + GeometryWeight, + DotWeight, + SegWeight, + BendWeight, + GeometryIndex, + DotIndex, + SegIndex, + BendIndex, + > { + self.geometry_with_rtree.geometry() + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn rules(&self) -> &R { + &self.rules + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn guide(&self) -> Guide { + Guide::new(self) + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn collect(&self) -> Collect { + Collect::new(self) + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn primitive(&self, index: GenericIndex) -> GenericPrimitive { + GenericPrimitive::new(index, self) + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn wraparoundable(&self, index: WraparoundableIndex) -> Wraparoundable { + Wraparoundable::new(index, self) + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn loose(&self, index: LooseIndex) -> Loose { + Loose::new(index, self) + } +} diff --git a/src/layout/graph.rs b/src/drawing/graph.rs similarity index 89% rename from src/layout/graph.rs rename to src/drawing/graph.rs index 2b398bf..15a7577 100644 --- a/src/layout/graph.rs +++ b/src/drawing/graph.rs @@ -2,11 +2,7 @@ use enum_dispatch::enum_dispatch; use petgraph::stable_graph::NodeIndex; -use crate::{ - board::connectivity::{BandIndex, ContinentIndex}, - graph::GetNodeIndex, - layout::Layout, -}; +use crate::{drawing::Drawing, graph::GetNodeIndex}; use super::{ bend::{FixedBendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight}, @@ -36,7 +32,7 @@ pub trait GetNet { #[enum_dispatch] pub trait MakePrimitive { - fn primitive<'a, R: RulesTrait>(&self, layout: &'a Layout) -> Primitive<'a, R>; + fn primitive<'a, R: RulesTrait>(&self, drawing: &'a Drawing) -> Primitive<'a, R>; } macro_rules! impl_weight { @@ -62,8 +58,8 @@ macro_rules! impl_weight { pub type $index_struct = GenericIndex<$weight_struct>; impl MakePrimitive for $index_struct { - fn primitive<'a, R: RulesTrait>(&self, layout: &'a Layout) -> Primitive<'a, R> { - Primitive::$weight_variant(GenericPrimitive::new(*self, layout)) + fn primitive<'a, R: RulesTrait>(&self, drawing: &'a Drawing) -> Primitive<'a, R> { + Primitive::$weight_variant(GenericPrimitive::new(*self, drawing)) } } }; diff --git a/src/drawing/groups.rs b/src/drawing/groups.rs new file mode 100644 index 0000000..a8e304c --- /dev/null +++ b/src/drawing/groups.rs @@ -0,0 +1,8 @@ +use enum_dispatch::enum_dispatch; + +use super::graph::GeometryIndex; + +#[enum_dispatch] +pub trait GetGroups< { + fn node_groups(&self, node: GeometryIndex) -> Vec; +} diff --git a/src/layout/guide.rs b/src/drawing/guide.rs similarity index 87% rename from src/layout/guide.rs rename to src/drawing/guide.rs index 867ec07..21b01f8 100644 --- a/src/layout/guide.rs +++ b/src/drawing/guide.rs @@ -2,16 +2,15 @@ use enum_dispatch::enum_dispatch; use geo::Line; use crate::{ - board::connectivity::BandIndex, - geometry::shape::{Shape, ShapeTrait}, - layout::{ + drawing::{ bend::BendIndex, dot::{DotIndex, FixedDotIndex, LooseDotIndex}, graph::MakePrimitive, primitive::{GetCore, GetInnerOuter, GetOtherJoint, GetWeight, MakeShape}, rules::GetConditions, - Layout, + Drawing, }, + geometry::shape::{Shape, ShapeTrait}, math::{self, Circle, NoTangents}, }; @@ -58,12 +57,12 @@ impl HeadTrait for SegbendHead { } pub struct Guide<'a, R: RulesTrait> { - layout: &'a Layout, + drawing: &'a Drawing, } impl<'a, R: RulesTrait> Guide<'a, R> { - pub fn new(layout: &'a Layout) -> Self { - Self { layout } + pub fn new(drawing: &'a Drawing) -> Self { + Self { drawing } } pub fn head_into_dot_segment( @@ -74,7 +73,7 @@ impl<'a, R: RulesTrait> Guide<'a, R> { ) -> Result { let from_circle = self.head_circle(head, width); let to_circle = Circle { - pos: self.layout.primitive(into).weight().circle.pos, + pos: self.drawing.primitive(into).weight().circle.pos, r: 0.0, }; @@ -112,7 +111,7 @@ impl<'a, R: RulesTrait> Guide<'a, R> { } pub fn head_around_dot_offset(&self, head: &Head, around: DotIndex, _width: f64) -> f64 { - self.layout.rules().clearance( + self.drawing.rules().clearance( &self.conditions(around.into()), &self.conditions(head.face().into()), ) @@ -148,7 +147,7 @@ impl<'a, R: RulesTrait> Guide<'a, R> { } pub fn head_around_bend_offset(&self, head: &Head, around: BendIndex, _width: f64) -> f64 { - self.layout.rules().clearance( + self.drawing.rules().clearance( &self.conditions(head.face().into()), &self.conditions(around.into()), ) @@ -156,7 +155,7 @@ impl<'a, R: RulesTrait> Guide<'a, R> { pub fn head_cw(&self, head: &Head) -> Option { if let Head::Segbend(head) = head { - let joints = self.layout.primitive(head.segbend.bend).joints(); + let joints = self.drawing.primitive(head.segbend.bend).joints(); if head.face() == joints.0.into() { Some(false) @@ -171,15 +170,15 @@ impl<'a, R: RulesTrait> Guide<'a, R> { fn head_circle(&self, head: &Head, width: f64) -> Circle { match *head { Head::Bare(head) => Circle { - pos: head.face().primitive(self.layout).shape().center(), // TODO. + pos: head.face().primitive(self.drawing).shape().center(), // TODO. r: 0.0, }, Head::Segbend(head) => { - if let Some(inner) = self.layout.primitive(head.segbend.bend).inner() { + if let Some(inner) = self.drawing.primitive(head.segbend.bend).inner() { self.bend_circle(inner.into(), width, &self.conditions(head.face().into())) } else { self.dot_circle( - self.layout.primitive(head.segbend.bend).core().into(), + self.drawing.primitive(head.segbend.bend).core().into(), width, &self.conditions(head.face().into()), ) @@ -189,7 +188,7 @@ impl<'a, R: RulesTrait> Guide<'a, R> { } fn bend_circle(&self, bend: BendIndex, width: f64, guide_conditions: &Conditions) -> Circle { - let outer_circle = match bend.primitive(self.layout).shape() { + let outer_circle = match bend.primitive(self.drawing).shape() { Shape::Bend(shape) => shape.outer_circle(), _ => unreachable!(), }; @@ -199,20 +198,20 @@ impl<'a, R: RulesTrait> Guide<'a, R> { r: outer_circle.r + width / 2.0 + self - .layout + .drawing .rules() .clearance(&self.conditions(bend.into()), guide_conditions), } } fn dot_circle(&self, dot: DotIndex, width: f64, guide_conditions: &Conditions) -> Circle { - let shape = dot.primitive(self.layout).shape(); + let shape = dot.primitive(self.drawing).shape(); Circle { pos: shape.center(), r: shape.width() / 2.0 + width / 2.0 + self - .layout + .drawing .rules() .clearance(&self.conditions(dot.into()), guide_conditions), } @@ -221,7 +220,7 @@ impl<'a, R: RulesTrait> Guide<'a, R> { pub fn segbend_head(&self, dot: LooseDotIndex) -> SegbendHead { SegbendHead { face: dot, - segbend: self.layout.segbend(dot), + segbend: self.drawing.segbend(dot), } } @@ -237,12 +236,12 @@ impl<'a, R: RulesTrait> Guide<'a, R> { } fn rear(&self, head: SegbendHead) -> DotIndex { - self.layout + self.drawing .primitive(head.segbend.seg) .other_joint(head.segbend.dot.into()) } fn conditions(&self, node: GeometryIndex) -> Conditions { - node.primitive(self.layout).conditions() + node.primitive(self.drawing).conditions() } } diff --git a/src/layout/loose.rs b/src/drawing/loose.rs similarity index 88% rename from src/layout/loose.rs rename to src/drawing/loose.rs index 623adad..0d82f05 100644 --- a/src/layout/loose.rs +++ b/src/drawing/loose.rs @@ -2,15 +2,15 @@ use enum_dispatch::enum_dispatch; use petgraph::stable_graph::NodeIndex; use crate::{ - graph::GetNodeIndex, - layout::Layout, - layout::{ + drawing::Drawing, + drawing::{ bend::LooseBendIndex, dot::{DotIndex, LooseDotIndex}, graph::{GeometryIndex, MakePrimitive}, primitive::{GetJoints, LoneLooseSeg, LooseBend, LooseDot, Primitive, SeqLooseSeg}, seg::{LoneLooseSegIndex, SeqLooseSegIndex}, }, + graph::GetNodeIndex, }; use super::rules::RulesTrait; @@ -49,12 +49,12 @@ pub enum Loose<'a, R: RulesTrait> { } impl<'a, R: RulesTrait> Loose<'a, R> { - pub fn new(index: LooseIndex, layout: &'a Layout) -> Self { + pub fn new(index: LooseIndex, drawing: &'a Drawing) -> Self { match index { - LooseIndex::Dot(dot) => layout.primitive(dot).into(), - LooseIndex::LoneSeg(seg) => layout.primitive(seg).into(), - LooseIndex::SeqSeg(seg) => layout.primitive(seg).into(), - LooseIndex::Bend(bend) => layout.primitive(bend).into(), + LooseIndex::Dot(dot) => drawing.primitive(dot).into(), + LooseIndex::LoneSeg(seg) => drawing.primitive(seg).into(), + LooseIndex::SeqSeg(seg) => drawing.primitive(seg).into(), + LooseIndex::Bend(bend) => drawing.primitive(bend).into(), } } } diff --git a/src/drawing/mod.rs b/src/drawing/mod.rs new file mode 100644 index 0000000..ddd431b --- /dev/null +++ b/src/drawing/mod.rs @@ -0,0 +1,14 @@ +#[macro_use] +pub mod graph; +pub mod bend; +pub mod collect; +pub mod dot; +mod drawing; +pub mod guide; +pub mod loose; +pub mod primitive; +pub mod rules; +pub mod seg; +pub mod segbend; + +pub use drawing::*; diff --git a/src/layout/primitive.rs b/src/drawing/primitive.rs similarity index 86% rename from src/layout/primitive.rs rename to src/drawing/primitive.rs index 0dd6ba9..3ec7b2a 100644 --- a/src/layout/primitive.rs +++ b/src/drawing/primitive.rs @@ -1,13 +1,7 @@ use enum_dispatch::enum_dispatch; use petgraph::stable_graph::NodeIndex; -use crate::board::connectivity::{BandIndex, ContinentIndex}; -use crate::geometry::{ - shape::{Shape, ShapeTrait}, - GetOffset, GetWidth, -}; -use crate::graph::{GenericIndex, GetNodeIndex}; -use crate::layout::{ +use crate::drawing::{ bend::{BendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight}, dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, Retag}, @@ -17,12 +11,18 @@ use crate::layout::{ FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex, SeqLooseSegIndex, SeqLooseSegWeight, }, - Layout, + Drawing, }; +use crate::geometry::{ + shape::{Shape, ShapeTrait}, + GetOffset, GetWidth, +}; +use crate::graph::{GenericIndex, GetNodeIndex}; +use crate::layout::connectivity::{BandIndex, ContinentIndex}; #[enum_dispatch] -pub trait GetLayout<'a, R: RulesTrait> { - fn layout(&self) -> &Layout; +pub trait GetDrawing<'a, R: RulesTrait> { + fn drawing(&self) -> &Drawing; } #[enum_dispatch] @@ -72,9 +72,9 @@ pub trait GetJoints { fn joints(&self) -> (F, T); } -pub trait GetFirstRail<'a, R: RulesTrait>: GetLayout<'a, R> + GetNodeIndex { +pub trait GetFirstRail<'a, R: RulesTrait>: GetDrawing<'a, R> + GetNodeIndex { fn first_rail(&self) -> Option { - self.layout() + self.drawing() .geometry() .first_rail(self.node_index()) .map(|ni| LooseBendIndex::new(ni.node_index())) @@ -85,10 +85,10 @@ pub trait GetBendIndex { fn bend_index(&self) -> BendIndex; } -pub trait GetCore<'a, R: RulesTrait>: GetLayout<'a, R> + GetBendIndex { +pub trait GetCore<'a, R: RulesTrait>: GetDrawing<'a, R> + GetBendIndex { fn core(&self) -> FixedDotIndex { FixedDotIndex::new( - self.layout() + self.drawing() .geometry() .core(self.bend_index()) .node_index(), @@ -96,16 +96,16 @@ pub trait GetCore<'a, R: RulesTrait>: GetLayout<'a, R> + GetBendIndex { } } -pub trait GetInnerOuter<'a, R: RulesTrait>: GetLayout<'a, R> + GetBendIndex { +pub trait GetInnerOuter<'a, R: RulesTrait>: GetDrawing<'a, R> + GetBendIndex { fn inner(&self) -> Option { - self.layout() + self.drawing() .geometry() .inner(self.bend_index()) .map(|ni| LooseBendIndex::new(ni.node_index())) } fn outer(&self) -> Option { - self.layout() + self.drawing() .geometry() .outer(self.bend_index()) .map(|ni| LooseBendIndex::new(ni.node_index())) @@ -172,17 +172,17 @@ pub enum Primitive<'a, R: RulesTrait> { #[derive(Debug)] pub struct GenericPrimitive<'a, W, R: RulesTrait> { pub index: GenericIndex, - layout: &'a Layout, + drawing: &'a Drawing, } impl<'a, W, R: RulesTrait> GenericPrimitive<'a, W, R> { - pub fn new(index: GenericIndex, layout: &'a Layout) -> Self { - Self { index, layout } + pub fn new(index: GenericIndex, drawing: &'a Drawing) -> Self { + Self { index, drawing } } fn tagged_weight(&self) -> GeometryWeight { *self - .layout + .drawing .geometry() .graph() .node_weight(self.index.node_index()) @@ -190,7 +190,7 @@ impl<'a, W, R: RulesTrait> GenericPrimitive<'a, W, R> { } fn primitive(&self, index: GenericIndex) -> GenericPrimitive { - GenericPrimitive::new(index, &self.layout) + GenericPrimitive::new(index, &self.drawing) } } @@ -200,9 +200,9 @@ impl<'a, W, R: RulesTrait> GetInterior for GenericPrimitive<'a, W } } -impl<'a, W, R: RulesTrait> GetLayout<'a, R> for GenericPrimitive<'a, W, R> { - fn layout(&self) -> &Layout { - self.layout +impl<'a, W, R: RulesTrait> GetDrawing<'a, R> for GenericPrimitive<'a, W, R> { + fn drawing(&self) -> &Drawing { + self.drawing } } @@ -239,13 +239,13 @@ impl_fixed_primitive!(FixedDot, FixedDotWeight); impl<'a, R: RulesTrait> FixedDot<'a, R> { pub fn first_loose(&self, _band: BandIndex) -> Option { - self.layout + self.drawing .geometry() .joineds(self.index.into()) .into_iter() .find_map(|ni| { let weight = self - .layout + .drawing .geometry() .graph() .node_weight(ni.node_index()) @@ -263,20 +263,20 @@ impl<'a, R: RulesTrait> FixedDot<'a, R> { impl<'a, R: RulesTrait> MakeShape for FixedDot<'a, R> { fn shape(&self) -> Shape { - self.layout.geometry().dot_shape(self.index.into()) + self.drawing.geometry().dot_shape(self.index.into()) } } impl<'a, R: RulesTrait> GetLimbs for FixedDot<'a, R> { fn segs(&self) -> Vec { - self.layout + self.drawing .geometry() .joined_segs(self.index.into()) .collect() } fn bends(&self) -> Vec { - self.layout + self.drawing .geometry() .joined_bends(self.index.into()) .collect() @@ -290,7 +290,7 @@ impl_loose_primitive!(LooseDot, LooseDotWeight); impl<'a, R: RulesTrait> LooseDot<'a, R> { pub fn seg(&self) -> Option { - self.layout + self.drawing .geometry() .joined_segs(self.index.into()) .map(|ni| SeqLooseSegIndex::new(ni.node_index())) @@ -298,7 +298,7 @@ impl<'a, R: RulesTrait> LooseDot<'a, R> { } pub fn bend(&self) -> LooseBendIndex { - self.layout + self.drawing .geometry() .joined_bends(self.index.into()) .map(|ni| LooseBendIndex::new(ni.node_index())) @@ -309,7 +309,7 @@ impl<'a, R: RulesTrait> LooseDot<'a, R> { impl<'a, R: RulesTrait> MakeShape for LooseDot<'a, R> { fn shape(&self) -> Shape { - self.layout.geometry().dot_shape(self.index.into()) + self.drawing.geometry().dot_shape(self.index.into()) } } @@ -332,7 +332,7 @@ impl_fixed_primitive!(FixedSeg, FixedSegWeight); impl<'a, R: RulesTrait> MakeShape for FixedSeg<'a, R> { fn shape(&self) -> Shape { - self.layout.geometry().seg_shape(self.index.into()) + self.drawing.geometry().seg_shape(self.index.into()) } } @@ -340,7 +340,7 @@ impl<'a, R: RulesTrait> GetLimbs for FixedSeg<'a, R> {} impl<'a, R: RulesTrait> GetJoints for FixedSeg<'a, R> { fn joints(&self) -> (FixedDotIndex, FixedDotIndex) { - let (from, to) = self.layout.geometry().seg_joints(self.index.into()); + let (from, to) = self.drawing.geometry().seg_joints(self.index.into()); ( FixedDotIndex::new(from.node_index()), FixedDotIndex::new(to.node_index()), @@ -355,7 +355,7 @@ impl_loose_primitive!(LoneLooseSeg, LoneLooseSegWeight); impl<'a, R: RulesTrait> MakeShape for LoneLooseSeg<'a, R> { fn shape(&self) -> Shape { - self.layout.geometry().seg_shape(self.index.into()) + self.drawing.geometry().seg_shape(self.index.into()) } } @@ -363,7 +363,7 @@ impl<'a, R: RulesTrait> GetLimbs for LoneLooseSeg<'a, R> {} impl<'a, R: RulesTrait> GetJoints for LoneLooseSeg<'a, R> { fn joints(&self) -> (FixedDotIndex, FixedDotIndex) { - let (from, to) = self.layout.geometry().seg_joints(self.index.into()); + let (from, to) = self.drawing.geometry().seg_joints(self.index.into()); ( FixedDotIndex::new(from.node_index()), FixedDotIndex::new(to.node_index()), @@ -378,7 +378,7 @@ impl_loose_primitive!(SeqLooseSeg, SeqLooseSegWeight); impl<'a, R: RulesTrait> MakeShape for SeqLooseSeg<'a, R> { fn shape(&self) -> Shape { - self.layout.geometry().seg_shape(self.index.into()) + self.drawing.geometry().seg_shape(self.index.into()) } } @@ -386,13 +386,13 @@ impl<'a, R: RulesTrait> GetLimbs for SeqLooseSeg<'a, R> {} impl<'a, R: RulesTrait> GetJoints for SeqLooseSeg<'a, R> { fn joints(&self) -> (DotIndex, LooseDotIndex) { - let joints = self.layout.geometry().seg_joints(self.index.into()); - if let DotWeight::Fixed(..) = self.layout.geometry().dot_weight(joints.0) { + let joints = self.drawing.geometry().seg_joints(self.index.into()); + if let DotWeight::Fixed(..) = self.drawing.geometry().dot_weight(joints.0) { ( FixedDotIndex::new(joints.0.node_index()).into(), LooseDotIndex::new(joints.1.node_index()).into(), ) - } else if let DotWeight::Fixed(..) = self.layout.geometry().dot_weight(joints.1) { + } else if let DotWeight::Fixed(..) = self.drawing.geometry().dot_weight(joints.1) { ( FixedDotIndex::new(joints.1.node_index()).into(), LooseDotIndex::new(joints.0.node_index()), @@ -419,7 +419,7 @@ impl<'a, R: RulesTrait> GetBendIndex for FixedBend<'a, R> { impl<'a, R: RulesTrait> MakeShape for FixedBend<'a, R> { fn shape(&self) -> Shape { - self.layout.geometry().bend_shape(self.index.into()) + self.drawing.geometry().bend_shape(self.index.into()) } } @@ -427,7 +427,7 @@ impl<'a, R: RulesTrait> GetLimbs for FixedBend<'a, R> {} impl<'a, R: RulesTrait> GetJoints for FixedBend<'a, R> { fn joints(&self) -> (FixedDotIndex, FixedDotIndex) { - let (from, to) = self.layout.geometry().bend_joints(self.index.into()); + let (from, to) = self.drawing.geometry().bend_joints(self.index.into()); ( FixedDotIndex::new(from.node_index()), FixedDotIndex::new(to.node_index()), @@ -457,7 +457,7 @@ impl<'a, R: RulesTrait> From> for BendIndex { impl<'a, R: RulesTrait> MakeShape for LooseBend<'a, R> { fn shape(&self) -> Shape { - self.layout.geometry().bend_shape(self.index.into()) + self.drawing.geometry().bend_shape(self.index.into()) } } @@ -471,7 +471,7 @@ impl<'a, R: RulesTrait> GetOffset for LooseBend<'a, R> { impl<'a, R: RulesTrait> GetJoints for LooseBend<'a, R> { fn joints(&self) -> (LooseDotIndex, LooseDotIndex) { - let (from, to) = self.layout.geometry().bend_joints(self.index.into()); + let (from, to) = self.drawing.geometry().bend_joints(self.index.into()); ( LooseDotIndex::new(from.node_index()), LooseDotIndex::new(to.node_index()), diff --git a/src/layout/rules.rs b/src/drawing/rules.rs similarity index 90% rename from src/layout/rules.rs rename to src/drawing/rules.rs index 094fab0..59283a8 100644 --- a/src/layout/rules.rs +++ b/src/drawing/rules.rs @@ -1,6 +1,6 @@ use enum_dispatch::enum_dispatch; -use crate::layout::primitive::Primitive; +use crate::drawing::primitive::Primitive; #[enum_dispatch] pub trait GetConditions { diff --git a/src/layout/seg.rs b/src/drawing/seg.rs similarity index 99% rename from src/layout/seg.rs rename to src/drawing/seg.rs index b887937..31f499f 100644 --- a/src/layout/seg.rs +++ b/src/drawing/seg.rs @@ -1,14 +1,14 @@ use enum_dispatch::enum_dispatch; use crate::{ - geometry::{GetWidth, SegWeightTrait}, - graph::{GenericIndex, GetNodeIndex}, - layout::{ + drawing::{ graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, MakePrimitive, Retag}, primitive::{GenericPrimitive, Primitive}, rules::RulesTrait, - Layout, + Drawing, }, + geometry::{GetWidth, SegWeightTrait}, + graph::{GenericIndex, GetNodeIndex}, }; use petgraph::stable_graph::NodeIndex; diff --git a/src/layout/segbend.rs b/src/drawing/segbend.rs similarity index 70% rename from src/layout/segbend.rs rename to src/drawing/segbend.rs index 9beda1c..775c267 100644 --- a/src/layout/segbend.rs +++ b/src/drawing/segbend.rs @@ -1,10 +1,10 @@ -use crate::layout::{ +use crate::drawing::{ bend::LooseBendIndex, dot::LooseDotIndex, graph::GeometryIndex, primitive::{GetInterior, GetJoints, GetOtherJoint, LooseBend, LooseDot}, seg::SeqLooseSegIndex, - Layout, + Drawing, }; use super::rules::RulesTrait; @@ -17,10 +17,10 @@ pub struct Segbend { } impl Segbend { - pub fn from_dot(dot: LooseDotIndex, layout: &Layout) -> Self { - let bend = LooseDot::new(dot, layout).bend(); - let dot = LooseBend::new(bend, layout).other_joint(dot); - let seg = LooseDot::new(dot, layout).seg().unwrap(); + pub fn from_dot(dot: LooseDotIndex, drawing: &Drawing) -> Self { + let bend = LooseDot::new(dot, drawing).bend(); + let dot = LooseBend::new(bend, drawing).other_joint(dot); + let seg = LooseDot::new(dot, drawing).seg().unwrap(); Self { bend, dot, seg } } } diff --git a/src/dsn/design.rs b/src/dsn/design.rs index f4b2e7c..76e7743 100644 --- a/src/dsn/design.rs +++ b/src/dsn/design.rs @@ -4,7 +4,7 @@ use geo::{point, Point, Rotate, Translate}; use thiserror::Error; use crate::{ - layout::{dot::FixedDotWeight, seg::FixedSegWeight, Layout}, + drawing::{dot::FixedDotWeight, seg::FixedSegWeight, Drawing}, math::Circle, }; @@ -41,9 +41,9 @@ impl DsnDesign { Ok(Self { pcb }) } - pub fn make_layout(&self) -> Layout { + pub fn make_drawing(&self) -> Drawing { let rules = DsnRules::from_pcb(&self.pcb); - let mut layout = Layout::new(rules); + let mut layout = Drawing::new(rules); // mapping of pin id -> net id prepared for adding pins let pin_nets = HashMap::::from_iter( @@ -287,12 +287,12 @@ impl DsnDesign { } fn layer( - layout: &Layout, + drawing: &Drawing, layer_vec: &Vec, layer_name: &str, front: bool, ) -> usize { - let image_layer = *layout.rules().layer_ids.get(layer_name).unwrap(); + let image_layer = *drawing.rules().layer_ids.get(layer_name).unwrap(); if front { image_layer as usize @@ -302,7 +302,7 @@ impl DsnDesign { } fn add_circle( - layout: &mut Layout, + drawing: &mut Drawing, place_pos: Point, place_rot: f64, pin_pos: Point, @@ -316,13 +316,13 @@ impl DsnDesign { r, }; - layout + drawing .add_fixed_dot(FixedDotWeight { circle, layer, net }) .unwrap(); } fn add_rect( - layout: &mut Layout, + drawing: &mut Drawing, place_pos: Point, place_rot: f64, pin_pos: Point, @@ -335,7 +335,7 @@ impl DsnDesign { net: i64, ) { // Corners. - let dot_1_1 = layout + let dot_1_1 = drawing .add_fixed_dot(FixedDotWeight { circle: Circle { pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x1, y1), @@ -345,7 +345,7 @@ impl DsnDesign { net, }) .unwrap(); - let dot_2_1 = layout + let dot_2_1 = drawing .add_fixed_dot(FixedDotWeight { circle: Circle { pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x2, y1), @@ -355,7 +355,7 @@ impl DsnDesign { net, }) .unwrap(); - let dot_2_2 = layout + let dot_2_2 = drawing .add_fixed_dot(FixedDotWeight { circle: Circle { pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x2, y2), @@ -365,7 +365,7 @@ impl DsnDesign { net, }) .unwrap(); - let dot_1_2 = layout + let dot_1_2 = drawing .add_fixed_dot(FixedDotWeight { circle: Circle { pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x1, y2), @@ -376,7 +376,7 @@ impl DsnDesign { }) .unwrap(); // Sides. - layout + drawing .add_fixed_seg( dot_1_1, dot_2_1, @@ -387,7 +387,7 @@ impl DsnDesign { }, ) .unwrap(); - layout + drawing .add_fixed_seg( dot_2_1, dot_2_2, @@ -398,7 +398,7 @@ impl DsnDesign { }, ) .unwrap(); - layout + drawing .add_fixed_seg( dot_2_2, dot_1_2, @@ -409,7 +409,7 @@ impl DsnDesign { }, ) .unwrap(); - layout + drawing .add_fixed_seg( dot_1_2, dot_1_1, @@ -423,7 +423,7 @@ impl DsnDesign { } fn add_path( - layout: &mut Layout, + drawing: &mut Drawing, place_pos: Point, place_rot: f64, pin_pos: Point, @@ -434,7 +434,7 @@ impl DsnDesign { net: i64, ) { // add the first coordinate in the wire path as a dot and save its index - let mut prev_index = layout + let mut prev_index = drawing .add_fixed_dot(FixedDotWeight { circle: Circle { pos: Self::pos( @@ -454,7 +454,7 @@ impl DsnDesign { // iterate through path coords starting from the second for coord in coords.iter().skip(1) { - let index = layout + let index = drawing .add_fixed_dot(FixedDotWeight { circle: Circle { pos: Self::pos( @@ -474,7 +474,7 @@ impl DsnDesign { .unwrap(); // add a seg between the current and previous coords - let _ = layout + let _ = drawing .add_fixed_seg(prev_index, index, FixedSegWeight { width, layer, net }) .unwrap(); diff --git a/src/dsn/groups.rs b/src/dsn/groups.rs new file mode 100644 index 0000000..ca2a2b1 --- /dev/null +++ b/src/dsn/groups.rs @@ -0,0 +1,14 @@ +use petgraph::stable_graph::StableGraph; + +use crate::layout::{graph::GeometryIndex, groups::GetGroups}; + +#[derive(Debug)] +pub struct DsnGroups { + map: BTreeMap< +} + +impl GetGroups for DsnGroups { + fn node_groups(&self, node: GeometryIndex) -> Vec { + // + } +} diff --git a/src/dsn/rules.rs b/src/dsn/rules.rs index bb31c01..2d36a4f 100644 --- a/src/dsn/rules.rs +++ b/src/dsn/rules.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::layout::rules::{Conditions, RulesTrait}; +use crate::drawing::rules::{Conditions, RulesTrait}; use super::structure::Pcb; diff --git a/src/geometry/geometry.rs b/src/geometry/geometry.rs index fc33a55..84e566e 100644 --- a/src/geometry/geometry.rs +++ b/src/geometry/geometry.rs @@ -9,9 +9,7 @@ use petgraph::{ }; use crate::{ - geometry::shape::{BendShape, DotShape, SegShape, Shape}, - graph::{GenericIndex, GetNodeIndex}, - layout::{ + drawing::{ bend::{BendWeight, FixedBendWeight, LooseBendWeight}, dot::{DotWeight, FixedDotWeight, LooseDotWeight}, graph::{GeometryWeight, Retag}, @@ -19,6 +17,8 @@ use crate::{ rules::RulesTrait, seg::{FixedSegWeight, LoneLooseSegWeight, SegWeight, SeqLooseSegWeight}, }, + geometry::shape::{BendShape, DotShape, SegShape, Shape}, + graph::{GenericIndex, GetNodeIndex}, math::Circle, }; diff --git a/src/geometry/with_rtree.rs b/src/geometry/with_rtree.rs index f5be78d..945c125 100644 --- a/src/geometry/with_rtree.rs +++ b/src/geometry/with_rtree.rs @@ -6,8 +6,8 @@ use petgraph::stable_graph::StableDiGraph; use rstar::{primitives::GeomWithData, RTree, RTreeObject, AABB}; use crate::{ + drawing::graph::{GetLayer, Retag}, graph::{GenericIndex, GetNodeIndex}, - layout::graph::{GetLayer, Retag}, }; use super::{ diff --git a/src/board/connectivity.rs b/src/layout/connectivity.rs similarity index 89% rename from src/board/connectivity.rs rename to src/layout/connectivity.rs index 47a345e..61d3d27 100644 --- a/src/board/connectivity.rs +++ b/src/layout/connectivity.rs @@ -2,8 +2,8 @@ use enum_dispatch::enum_dispatch; use petgraph::stable_graph::StableDiGraph; use crate::{ + drawing::{dot::FixedDotIndex, graph::GetNet, primitive::Primitive, rules::RulesTrait}, graph::GenericIndex, - layout::{dot::FixedDotIndex, graph::GetNet, primitive::Primitive, rules::RulesTrait}, }; pub type ConnectivityGraph = StableDiGraph; diff --git a/src/layout/layout.rs b/src/layout/layout.rs index b6bdddb..2e19058 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -1,212 +1,64 @@ -use contracts::debug_ensures; -use enum_dispatch::enum_dispatch; use geo::Point; +use petgraph::stable_graph::StableDiGraph; -use rstar::{RTreeObject, AABB}; -use thiserror::Error; - -use super::graph::GetLayer; -use super::loose::{GetNextLoose, Loose, LooseIndex}; -use super::rules::RulesTrait; -use super::segbend::Segbend; -use crate::geometry::{ - shape::{Shape, ShapeTrait}, - with_rtree::GeometryWithRtree, - BendWeightTrait, DotWeightTrait, Geometry, GeometryLabel, GetOffset, GetPos, GetWidth, - SegWeightTrait, -}; -use crate::graph::{GenericIndex, GetNodeIndex}; -use crate::layout::bend::BendIndex; -use crate::layout::collect::Collect; -use crate::layout::dot::DotWeight; -use crate::layout::graph::GetNet; -use crate::layout::guide::Guide; -use crate::layout::primitive::GetLimbs; -use crate::layout::rules::GetConditions; -use crate::layout::{ - bend::{FixedBendIndex, LooseBendIndex, LooseBendWeight}, - dot::{DotIndex, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, - graph::{GeometryIndex, GeometryWeight, MakePrimitive}, - primitive::{GenericPrimitive, GetCore, GetInnerOuter, GetJoints, GetOtherJoint, MakeShape}, - seg::{ - FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex, - SeqLooseSegIndex, SeqLooseSegWeight, +use crate::{ + drawing::{ + bend::LooseBendWeight, + dot::{DotIndex, FixedDotIndex, LooseDotIndex, LooseDotWeight}, + rules::RulesTrait, + seg::{LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex, SeqLooseSegWeight}, + segbend::Segbend, + Drawing, Infringement, LayoutException, }, + graph::GetNodeIndex, + wraparoundable::WraparoundableIndex, }; -use crate::math::NoTangents; -use crate::wraparoundable::{GetWraparound, Wraparoundable, WraparoundableIndex}; -use super::bend::BendWeight; -use super::seg::SegWeight; +use super::connectivity::{ + BandIndex, BandWeight, ConnectivityLabel, ConnectivityWeight, ContinentIndex, +}; -#[enum_dispatch] -#[derive(Error, Debug, Clone, Copy)] -pub enum LayoutException { - #[error(transparent)] - NoTangents(#[from] NoTangents), - #[error(transparent)] - Infringement(#[from] Infringement), - #[error(transparent)] - Collision(#[from] Collision), - #[error(transparent)] - AlreadyConnected(#[from] AlreadyConnected), -} - -// TODO add real error messages + these should eventually use Display -#[derive(Error, Debug, Clone, Copy)] -#[error("{0:?} infringes on {1:?}")] -pub struct Infringement(pub Shape, pub GeometryIndex); - -#[derive(Error, Debug, Clone, Copy)] -#[error("{0:?} collides with {1:?}")] -pub struct Collision(pub Shape, pub GeometryIndex); - -#[derive(Error, Debug, Clone, Copy)] -#[error("{1:?} is already connected to net {0}")] -pub struct AlreadyConnected(pub i64, pub GeometryIndex); - -#[derive(Debug)] pub struct Layout { - geometry_with_rtree: GeometryWithRtree< - GeometryWeight, - DotWeight, - SegWeight, - BendWeight, - GeometryIndex, - DotIndex, - SegIndex, - BendIndex, - >, - rules: R, + drawing: Drawing, // Shouldn't be public, but is for now because `Draw` needs it. + connectivity: StableDiGraph, } impl Layout { - pub fn new(rules: R) -> Self { + pub fn new(drawing: Drawing) -> Self { Self { - geometry_with_rtree: GeometryWithRtree::new(2), - rules, + drawing, + connectivity: StableDiGraph::default(), } } - pub fn remove_band(&mut self, first_loose: SeqLooseSegIndex) { - let mut dots = vec![]; - let mut segs = vec![]; - let mut bends = vec![]; - let mut outers = vec![]; - - let mut maybe_loose = Some(first_loose.into()); - let mut prev = None; - - while let Some(loose) = maybe_loose { - match loose { - LooseIndex::Dot(dot) => { - dots.push(dot); - } - LooseIndex::LoneSeg(seg) => { - self.geometry_with_rtree.remove_seg(seg.into()); - break; - } - LooseIndex::SeqSeg(seg) => { - segs.push(seg); - } - LooseIndex::Bend(bend) => { - bends.push(bend); - - if let Some(outer) = self.primitive(bend).outer() { - outers.push(outer); - self.reattach_bend(outer, self.primitive(bend).inner()); - } - } - } - - let prev_prev = prev; - prev = maybe_loose; - maybe_loose = self.loose(loose).next_loose(prev_prev); - } - - for bend in bends { - self.geometry_with_rtree.remove_bend(bend.into()); - } - - for seg in segs { - self.geometry_with_rtree.remove_seg(seg.into()); - } - - // We must remove the dots only after the segs and bends because we need dots to calculate - // the shapes, which we first need unchanged to remove the segs and bends from the R-tree. - - for dot in dots { - self.geometry_with_rtree.remove_dot(dot.into()); - } - - for outer in outers { - self.update_this_and_outward_bows(outer).unwrap(); // Must never fail. - } + pub fn remove_band(&mut self, band: BandIndex) { + todo!() } - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 4))] pub fn remove_segbend(&mut self, segbend: &Segbend, face: LooseDotIndex) { - let maybe_outer = self.primitive(segbend.bend).outer(); - - // Removing a loose bend affects its outer bends. - if let Some(outer) = maybe_outer { - self.reattach_bend(outer, self.primitive(segbend.bend).inner()); - } - - self.geometry_with_rtree.remove_bend(segbend.bend.into()); - self.geometry_with_rtree.remove_seg(segbend.seg.into()); - - // We must remove the dots only after the segs and bends because we need dots to calculate - // the shapes, which we first need unchanged to remove the segs and bends from the R-tree. - - self.geometry_with_rtree.remove_dot(face.into()); - self.geometry_with_rtree.remove_dot(segbend.dot.into()); - - if let Some(outer) = maybe_outer { - self.update_this_and_outward_bows(outer).unwrap(); // Must never fail. - } + self.drawing.remove_segbend(segbend, face) } - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result { - self.add_dot_infringably(weight, None) + pub fn start_band(&mut self, from: FixedDotIndex) -> BandIndex { + let band = self + .connectivity + .add_node(ConnectivityWeight::Band(BandWeight { from, to: None })); + self.connectivity.update_edge( + self.continent(from.into()).node_index(), + band, + ConnectivityLabel::Band, + ); + BandIndex::new(band) } - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - fn add_dot_infringably + GetLayer>( - &mut self, - weight: W, - infringables: Option<&[GeometryIndex]>, - ) -> Result, Infringement> - where - GenericIndex: Into + Copy, - { - let dot = self.geometry_with_rtree.add_dot(weight); - self.fail_and_remove_if_infringes_except(dot.into(), infringables)?; - - Ok(dot) + pub fn finish_band(&mut self, band: BandIndex, to: FixedDotIndex) { + self.connectivity.update_edge( + band.node_index(), + self.continent(to.into()).node_index(), + ConnectivityLabel::Band, + ); } - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn add_fixed_seg( - &mut self, - from: FixedDotIndex, - to: FixedDotIndex, - weight: FixedSegWeight, - ) -> Result { - self.add_seg_infringably(from.into(), to.into(), weight, None) - } - - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 4))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() >= old(self.geometry_with_rtree.graph().edge_count() + 5))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] pub fn insert_segbend( &mut self, from: DotIndex, @@ -216,608 +68,51 @@ impl Layout { bend_weight: LooseBendWeight, cw: bool, ) -> Result { - let maybe_wraparound = self.wraparoundable(around).wraparound(); - let infringables = self.collect().wraparounded_bows(around); - - let segbend = self.add_segbend_infringably( - from, - around, - dot_weight, - seg_weight, - bend_weight, - cw, - Some(&infringables), - )?; - - if let Some(wraparound) = maybe_wraparound { - self.reattach_bend(wraparound, Some(segbend.bend)); - } - - if let Some(outer) = self.primitive(segbend.bend).outer() { - self.update_this_and_outward_bows(outer).map_err(|err| { - let joint = self.primitive(segbend.bend).other_joint(segbend.dot); - self.remove_segbend(&segbend, joint.into()); - err - })?; - } - - // Segs must not cross. - if let Some(collision) = self.detect_collision(segbend.seg.into()) { - let joint = self.primitive(segbend.bend).other_joint(segbend.dot); - self.remove_segbend(&segbend, joint.into()); - return Err(collision.into()); - } - - Ok::(segbend) + self.drawing + .insert_segbend(from, around, dot_weight, seg_weight, bend_weight, cw) } - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()) - || self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() - 1) - || self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 1))] - fn reattach_bend(&mut self, bend: LooseBendIndex, maybe_new_inner: Option) { - self.geometry_with_rtree - .reattach_bend(bend.into(), maybe_new_inner.map(Into::into)); - } - - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn update_this_and_outward_bows( - &mut self, - around: LooseBendIndex, - ) -> Result<(), LayoutException> { - // FIXME: Fail gracefully on infringement. - let mut maybe_rail = Some(around); - - while let Some(rail) = maybe_rail { - let rail_primitive = self.primitive(rail); - let joints = rail_primitive.joints(); - - let guide = Guide::new(self); - let from_head = guide.rear_head(joints.1); - let to_head = guide.rear_head(joints.0); - - if let Some(inner) = rail_primitive.inner() { - let from = guide - .head_around_bend_segment( - &from_head.into(), - inner.into(), - true, - self.primitive(rail).width(), - )? - .end_point(); - let to = guide - .head_around_bend_segment( - &to_head.into(), - inner.into(), - false, - self.primitive(rail).width(), - )? - .end_point(); - let offset = guide.head_around_bend_offset( - &from_head.into(), - inner.into(), - self.primitive(rail).width(), - ); - - self.move_dot_infringably( - joints.0.into(), - from, - Some(&self.collect().bend_outer_bows(rail)), - )?; - self.move_dot_infringably( - joints.1.into(), - to, - Some(&self.collect().bend_outer_bows(rail)), - )?; - - self.shift_bend_infringably( - rail.into(), - offset, - Some(&self.collect().bend_outer_bows(rail)), - )?; - - // Update offsets in case the rule conditions changed. - } else { - let core = rail_primitive.core(); - let from = guide - .head_around_dot_segment( - &from_head.into(), - core.into(), - true, - self.primitive(rail).width(), - )? - .end_point(); - let to = guide - .head_around_dot_segment( - &to_head.into(), - core.into(), - false, - self.primitive(rail).width(), - )? - .end_point(); - let offset = guide.head_around_dot_offset( - &from_head.into(), - core.into(), - self.primitive(rail).width(), - ); - - self.move_dot_infringably( - joints.0.into(), - from, - Some(&self.collect().bend_outer_bows(rail)), - )?; - self.move_dot_infringably( - joints.1.into(), - to, - Some(&self.collect().bend_outer_bows(rail)), - )?; - - self.shift_bend_infringably( - rail.into(), - offset, - Some(&self.collect().bend_outer_bows(rail)), - )?; - } - - maybe_rail = self.primitive(rail).outer(); - } - - Ok::<(), LayoutException>(()) - } - - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 4))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() >= old(self.geometry_with_rtree.graph().edge_count() + 5))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn add_segbend( - &mut self, - from: DotIndex, - around: WraparoundableIndex, - dot_weight: LooseDotWeight, - seg_weight: SeqLooseSegWeight, - bend_weight: LooseBendWeight, - cw: bool, - ) -> Result { - self.add_segbend_infringably( - from, - around, - dot_weight, - seg_weight, - bend_weight, - cw, - Some(&self.collect().wraparounded_bows(around)), - ) - } - - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 4))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() >= old(self.geometry_with_rtree.graph().edge_count() + 5))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn add_segbend_infringably( - &mut self, - from: DotIndex, - around: WraparoundableIndex, - dot_weight: LooseDotWeight, - seg_weight: SeqLooseSegWeight, - bend_weight: LooseBendWeight, - cw: bool, - infringables: Option<&[GeometryIndex]>, - ) -> Result { - let seg_to = self.add_dot_infringably(dot_weight, infringables)?; - let seg = self - .add_seg_infringably(from, seg_to.into(), seg_weight, infringables) - .map_err(|err| { - self.geometry_with_rtree.remove_dot(seg_to.into()); - err - })?; - - let to = self - .add_dot_infringably(dot_weight, infringables) - .map_err(|err| { - self.geometry_with_rtree.remove_seg(seg.into()); - self.geometry_with_rtree.remove_dot(seg_to.into()); - err - })?; - - let (bend_from, bend_to) = if cw { (to, seg_to) } else { (seg_to, to) }; - - let bend = self - .add_loose_bend_infringably(bend_from, bend_to, around, bend_weight, infringables) - .map_err(|err| { - self.geometry_with_rtree.remove_dot(to.into()); - self.geometry_with_rtree.remove_seg(seg.into()); - self.geometry_with_rtree.remove_dot(seg_to.into()); - err - })?; - - Ok::(Segbend { - seg, - dot: seg_to, - bend, - }) - } - - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] pub fn add_lone_loose_seg( &mut self, from: FixedDotIndex, to: FixedDotIndex, weight: LoneLooseSegWeight, ) -> Result { - let seg = self.add_seg_infringably(from.into(), to.into(), weight, Some(&[]))?; - Ok(seg) + self.drawing.add_lone_loose_seg(from, to, weight) } - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] pub fn add_seq_loose_seg( &mut self, from: DotIndex, to: LooseDotIndex, weight: SeqLooseSegWeight, ) -> Result { - let seg = self.add_seg_infringably(from, to.into(), weight, Some(&[]))?; - Ok(seg) + self.drawing.add_seq_loose_seg(from, to, weight) } - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn add_seg_infringably + GetLayer>( - &mut self, - from: DotIndex, - to: DotIndex, - weight: W, - infringables: Option<&[GeometryIndex]>, - ) -> Result, Infringement> - where - GenericIndex: Into + Copy, - { - let seg = self.geometry_with_rtree.add_seg(from, to, weight); - self.fail_and_remove_if_infringes_except(seg.into(), infringables)?; - - Ok(seg) - } - - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 3) - || self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 4))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn add_loose_bend_infringably( - &mut self, - from: LooseDotIndex, - to: LooseDotIndex, - around: WraparoundableIndex, - weight: LooseBendWeight, - infringables: Option<&[GeometryIndex]>, - ) -> Result { - // It makes no sense to wrap something around or under one of its connectables. - // - if weight.net == around.primitive(self).net() { - return Err(AlreadyConnected(weight.net, around.into()).into()); - } - // - if let Some(wraparound) = self.wraparoundable(around).wraparound() { - if weight.net == wraparound.primitive(self).net() { - return Err(AlreadyConnected(weight.net, wraparound.into()).into()); - } - } - - match around { - WraparoundableIndex::FixedDot(core) => self - .add_core_bend_infringably(from.into(), to.into(), core, weight, infringables) - .map_err(Into::into), - WraparoundableIndex::FixedBend(around) => self - .add_outer_bend_infringably(from, to, around.into(), weight, infringables) - .map_err(Into::into), - WraparoundableIndex::LooseBend(around) => self - .add_outer_bend_infringably(from, to, around.into(), weight, infringables) - .map_err(Into::into), - } - } - - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 3))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn add_core_bend_infringably + GetLayer>( - &mut self, - from: DotIndex, - to: DotIndex, - core: FixedDotIndex, - weight: W, - infringables: Option<&[GeometryIndex]>, - ) -> Result, Infringement> - where - GenericIndex: Into + Copy, - { - let bend = self - .geometry_with_rtree - .add_bend(from, to, core.into(), weight); - - self.fail_and_remove_if_infringes_except(bend.into(), infringables)?; - Ok(bend) - } - - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 4))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn add_outer_bend_infringably( - &mut self, - from: LooseDotIndex, - to: LooseDotIndex, - inner: BendIndex, - weight: LooseBendWeight, - infringables: Option<&[GeometryIndex]>, - ) -> Result, Infringement> { - let core = *self - .geometry_with_rtree - .graph() - .neighbors(inner.node_index()) - .filter(|ni| { - matches!( - self.geometry_with_rtree - .graph() - .edge_weight( - self.geometry_with_rtree - .graph() - .find_edge(inner.node_index(), *ni) - .unwrap() - ) - .unwrap(), - GeometryLabel::Core - ) - }) - .map(|ni| FixedDotIndex::new(ni)) - .collect::>() - .first() - .unwrap(); - - let bend = self - .geometry_with_rtree - .add_bend(from.into(), to.into(), core.into(), weight); - self.geometry_with_rtree - .reattach_bend(bend.into(), Some(inner)); - - self.fail_and_remove_if_infringes_except(bend.into(), infringables)?; - Ok(bend) - } - - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn flip_bend(&mut self, bend: FixedBendIndex) { - self.geometry_with_rtree.flip_bend(bend.into()); - } - - pub fn segbend(&self, dot: LooseDotIndex) -> Segbend { - Segbend::from_dot(dot, self) - } - - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))] - fn fail_and_remove_if_infringes_except( - &mut self, - node: GeometryIndex, - maybe_except: Option<&[GeometryIndex]>, - ) -> Result<(), Infringement> { - if let Some(infringement) = self.detect_infringement_except(node, maybe_except) { - if let Ok(dot) = node.try_into() { - self.geometry_with_rtree.remove_dot(dot); - } else if let Ok(seg) = node.try_into() { - self.geometry_with_rtree.remove_seg(seg); - } else if let Ok(bend) = node.try_into() { - self.geometry_with_rtree.remove_bend(bend); - } - return Err(infringement); - } - Ok(()) - } - - pub fn nodes(&self) -> impl Iterator + '_ { - self.geometry_with_rtree - .rtree() - .iter() - .map(|wrapper| wrapper.data) - } - - pub fn layer_nodes(&self, layer: u64) -> impl Iterator + '_ { - self.geometry_with_rtree - .rtree() - .locate_in_envelope_intersecting(&AABB::from_corners( - [-f64::INFINITY, -f64::INFINITY, layer as f64], - [f64::INFINITY, f64::INFINITY, layer as f64], - )) - .map(|wrapper| wrapper.data) - } - - pub fn node_count(&self) -> usize { - self.geometry_with_rtree.graph().node_count() - } -} - -impl Layout { - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> { - match dot { - DotIndex::Fixed(..) => self.move_dot_infringably(dot, to, Some(&[])), - DotIndex::Loose(..) => self.move_dot_infringably(dot, to, Some(&[])), - } + self.drawing.move_dot(dot, to) } - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn move_dot_infringably( - &mut self, - dot: DotIndex, - to: Point, - infringables: Option<&[GeometryIndex]>, - ) -> Result<(), Infringement> { - let old_pos = self.geometry_with_rtree.geometry().dot_weight(dot).pos(); - self.geometry_with_rtree.move_dot(dot, to); - - for limb in dot.primitive(self).limbs() { - if let Some(infringement) = self.detect_infringement_except(limb.into(), infringables) { - // Restore original state. - self.geometry_with_rtree.move_dot(dot, old_pos); - return Err(infringement); - } - } - - if let Some(infringement) = self.detect_infringement_except(dot.into(), infringables) { - // Restore original state. - self.geometry_with_rtree.move_dot(dot, old_pos); - return Err(infringement); - } - - Ok(()) + pub fn band_from(&self, band: BandIndex) -> FixedDotIndex { + todo!() } - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn shift_bend_infringably( - &mut self, - bend: BendIndex, - offset: f64, - infringables: Option<&[GeometryIndex]>, - ) -> Result<(), Infringement> { - let old_offset = self - .geometry_with_rtree - .geometry() - .bend_weight(bend) - .offset(); - self.geometry_with_rtree.shift_bend(bend, offset); - - if let Some(infringement) = self.detect_infringement_except(bend.into(), infringables) { - // Restore original state. - self.geometry_with_rtree.shift_bend(bend, old_offset); - return Err(infringement); - } - - Ok(()) + pub fn band_to(&self, band: BandIndex) -> Option { + todo!() } - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn detect_infringement_except( - &self, - node: GeometryIndex, - maybe_except: Option<&[GeometryIndex]>, - ) -> Option { - let limiting_shape = node - .primitive(self) - .shape() - .inflate(self.rules.largest_clearance(node.primitive(self).net())); - let mut inflated_shape = limiting_shape; // Unused temporary value just for initialization. - let conditions = node.primitive(self).conditions(); - - self.geometry_with_rtree - .rtree() - .locate_in_envelope_intersecting(&limiting_shape.full_height_envelope_3d(0.0, 2)) - .filter(|wrapper| maybe_except.is_some_and(|except| !except.contains(&wrapper.data))) - .filter(|wrapper| !self.are_connectable(node, wrapper.data)) - .filter(|wrapper| { - let infringee_conditions = wrapper.data.primitive(self).conditions(); - - let epsilon = 1.0; - inflated_shape = node.primitive(self).shape().inflate( - (self.rules.clearance(&conditions, &infringee_conditions) - epsilon) - .clamp(0.0, f64::INFINITY), - ); - - inflated_shape.intersects(&wrapper.data.primitive(self).shape()) - }) - .map(|wrapper| wrapper.data) - .next() - .and_then(|infringee| Some(Infringement(inflated_shape, infringee))) + pub fn band_length(&self, band: BandIndex) -> f64 { + // TODO. + 0.0 } - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn detect_collision(&self, node: GeometryIndex) -> Option { - let shape = node.primitive(self).shape(); - - self.geometry_with_rtree - .rtree() - .locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2)) - .filter(|wrapper| !self.are_connectable(node, wrapper.data)) - .filter(|wrapper| shape.intersects(&wrapper.data.primitive(self).shape())) - .map(|wrapper| wrapper.data) - .next() - .and_then(|collidee| Some(Collision(shape, collidee))) + pub fn layout(&self) -> &Drawing { + &self.drawing } - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn are_connectable(&self, node1: GeometryIndex, node2: GeometryIndex) -> bool { - let node1_net = node1.primitive(self).net(); - let node2_net = node2.primitive(self).net(); - - (node1_net == node2_net) || node1_net == -1 || node2_net == -2 - } -} - -impl Layout { - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn geometry( - &self, - ) -> &Geometry< - GeometryWeight, - DotWeight, - SegWeight, - BendWeight, - GeometryIndex, - DotIndex, - SegIndex, - BendIndex, - > { - self.geometry_with_rtree.geometry() - } - - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn rules(&self) -> &R { - &self.rules - } - - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn guide(&self) -> Guide { - Guide::new(self) - } - - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn collect(&self) -> Collect { - Collect::new(self) - } - - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn primitive(&self, index: GenericIndex) -> GenericPrimitive { - GenericPrimitive::new(index, self) - } - - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn wraparoundable(&self, index: WraparoundableIndex) -> Wraparoundable { - Wraparoundable::new(index, self) - } - - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - pub fn loose(&self, index: LooseIndex) -> Loose { - Loose::new(index, self) + pub fn continent(&self, dot: FixedDotIndex) -> ContinentIndex { + // TODO. + ContinentIndex::new(0.into()) } } diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 9a3e2d2..fb19bf4 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1,14 +1,4 @@ -#[macro_use] -pub mod graph; -pub mod bend; -pub mod collect; -pub mod dot; -pub mod guide; +pub mod connectivity; mod layout; -pub mod loose; -pub mod primitive; -pub mod rules; -pub mod seg; -pub mod segbend; pub use layout::*; diff --git a/src/lib.rs b/src/lib.rs index 31dddbe..b16f3c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,10 +4,10 @@ pub mod astar; pub mod draw; pub mod graph; #[macro_use] -pub mod layout; -pub mod board; +pub mod drawing; pub mod dsn; pub mod geometry; +pub mod layout; pub mod math; pub mod mesh; pub mod router; diff --git a/src/mesh.rs b/src/mesh.rs index 1b42f88..7b953f8 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -7,18 +7,18 @@ use petgraph::visit::{self, NodeIndexable}; use petgraph::{stable_graph::NodeIndex, visit::EdgeRef}; use spade::{HasPosition, InsertionError, Point2}; -use crate::layout::rules::RulesTrait; +use crate::drawing::rules::RulesTrait; use crate::triangulation::TriangulationEdgeReference; use crate::{ - geometry::shape::ShapeTrait, - graph::GetNodeIndex, - layout::{ + drawing::{ bend::{FixedBendIndex, LooseBendIndex}, dot::FixedDotIndex, graph::{GeometryIndex, MakePrimitive}, primitive::{GetCore, MakeShape, Primitive}, - Layout, + Drawing, }, + geometry::shape::ShapeTrait, + graph::GetNodeIndex, triangulation::{GetVertexIndex, Triangulation}, }; @@ -83,7 +83,7 @@ pub struct Mesh { } impl Mesh { - pub fn new(layout: &Layout) -> Self { + pub fn new(layout: &Drawing) -> Self { let mut this = Self { triangulation: Triangulation::new(layout), vertex_to_triangulation_vertex: Vec::new(), @@ -93,9 +93,9 @@ impl Mesh { this } - pub fn generate(&mut self, layout: &Layout) -> Result<(), InsertionError> { - for node in layout.nodes() { - let center = node.primitive(layout).shape().center(); + pub fn generate(&mut self, drawing: &Drawing) -> Result<(), InsertionError> { + for node in drawing.nodes() { + let center = node.primitive(drawing).shape().center(); match node { GeometryIndex::FixedDot(dot) => { @@ -116,16 +116,16 @@ impl Mesh { } } - for node in layout.nodes() { + for node in drawing.nodes() { // Add rails as vertices. This is how the mesh differs from the triangulation. match node { GeometryIndex::LooseBend(bend) => { self.triangulation - .weight_mut(layout.primitive(bend).core().into()) + .weight_mut(drawing.primitive(bend).core().into()) .rails .push(bend.into()); self.vertex_to_triangulation_vertex[bend.node_index().index()] = - Some(layout.primitive(bend).core().into()); + Some(drawing.primitive(bend).core().into()); } _ => (), } diff --git a/src/router.rs b/src/router.rs index 7981ba6..819b288 100644 --- a/src/router.rs +++ b/src/router.rs @@ -5,16 +5,16 @@ use spade::InsertionError; use thiserror::Error; use crate::astar::{astar, AstarStrategy, PathTracker}; -use crate::board::connectivity::BandIndex; -use crate::board::Board; use crate::draw::DrawException; -use crate::geometry::shape::ShapeTrait; -use crate::layout::{ +use crate::drawing::{ dot::FixedDotIndex, graph::{GeometryIndex, MakePrimitive}, primitive::MakeShape, rules::RulesTrait, }; +use crate::geometry::shape::ShapeTrait; +use crate::layout::connectivity::BandIndex; +use crate::layout::Layout; use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex}; @@ -52,7 +52,7 @@ pub trait RouterObserverTrait { } pub struct Router { - pub board: Board, + pub layout: Layout, } struct RouterAstarStrategy<'a, RO: RouterObserverTrait, R: RulesTrait> { @@ -99,14 +99,14 @@ impl<'a, RO: RouterObserverTrait, R: RulesTrait> AstarStrategy<&Mesh, f64> return None; } - let before_probe_length = self.tracer.board.band_length(self.trace.band); + let before_probe_length = self.tracer.layout.band_length(self.trace.band); let width = self.trace.width; let result = self.tracer.step(&mut self.trace, edge.target(), width); self.observer .on_probe(&self.tracer, &self.trace, edge, result); - let probe_length = self.tracer.board.band_length(self.trace.band); + let probe_length = self.tracer.layout.band_length(self.trace.band); if result.is_ok() { self.tracer.undo_step(&mut self.trace); @@ -119,12 +119,12 @@ impl<'a, RO: RouterObserverTrait, R: RulesTrait> AstarStrategy<&Mesh, f64> fn estimate_cost(&mut self, vertex: VertexIndex) -> f64 { self.observer.on_estimate(&self.tracer, vertex); let start_point = GeometryIndex::from(vertex) - .primitive(self.tracer.board.layout()) + .primitive(self.tracer.layout.layout()) .shape() .center(); let end_point = self .tracer - .board + .layout .layout() .primitive(self.to) .shape() @@ -134,8 +134,8 @@ impl<'a, RO: RouterObserverTrait, R: RulesTrait> AstarStrategy<&Mesh, f64> } impl Router { - pub fn new(board: Board) -> Self { - Router { board } + pub fn new(layout: Layout) -> Self { + Router { layout } } pub fn route_band( @@ -148,8 +148,8 @@ impl Router { // XXX: Should we actually store the mesh? May be useful for debugging, but doesn't look // right. //self.mesh.triangulate(&self.layout)?; - let mut mesh = Mesh::new(self.board.layout()); - mesh.generate(self.board.layout()) + let mut mesh = Mesh::new(self.layout.layout()); + mesh.generate(self.layout.layout()) .map_err(|err| RoutingError { from, to, @@ -181,14 +181,14 @@ impl Router { width: f64, observer: &mut impl RouterObserverTrait, ) -> Result { - let from_dot = self.board.band_from(band); - let to_dot = self.board.band_to(band).unwrap(); - self.board.remove_band(band); - self.board.move_dot(to_dot.into(), to).unwrap(); // TODO: Remove `.unwrap()`. + let from_dot = self.layout.band_from(band); + let to_dot = self.layout.band_to(band).unwrap(); + self.layout.remove_band(band); + self.layout.move_dot(to_dot.into(), to).unwrap(); // TODO: Remove `.unwrap()`. self.route_band(from_dot, to_dot, width, observer) } pub fn tracer<'a>(&'a mut self, mesh: &'a Mesh) -> Tracer { - Tracer::new(&mut self.board, mesh) + Tracer::new(&mut self.layout, mesh) } } diff --git a/src/tracer.rs b/src/tracer.rs index babcb69..ecaa4cc 100644 --- a/src/tracer.rs +++ b/src/tracer.rs @@ -1,15 +1,15 @@ use contracts::debug_ensures; use crate::{ - board::{connectivity::BandIndex, Board}, draw::{Draw, DrawException}, - layout::{ + drawing::{ bend::LooseBendIndex, dot::FixedDotIndex, graph::{GetNet, MakePrimitive}, guide::{BareHead, Head, HeadTrait, SegbendHead}, rules::RulesTrait, }, + layout::{connectivity::BandIndex, Layout}, mesh::{Mesh, VertexIndex}, }; @@ -22,17 +22,17 @@ pub struct Trace { } pub struct Tracer<'a, R: RulesTrait> { - pub board: &'a mut Board, + pub layout: &'a mut Layout, pub mesh: &'a Mesh, } impl<'a, R: RulesTrait> Tracer<'a, R> { - pub fn new(board: &'a mut Board, mesh: &'a Mesh) -> Self { - Tracer { board, mesh } + pub fn new(layout: &'a mut Layout, mesh: &'a Mesh) -> Self { + Tracer { layout, mesh } } pub fn start(&mut self, from: FixedDotIndex, width: f64) -> Trace { - let band = self.board.start_band(from); + let band = self.layout.start_band(from); Trace { path: vec![from.into()], head: BareHead { dot: from }.into(), @@ -48,7 +48,7 @@ impl<'a, R: RulesTrait> Tracer<'a, R> { width: f64, ) -> Result<(), DrawException> { self.draw().finish_in_dot(trace.head, into, width)?; - Ok(self.board.finish_band(trace.band, into)) + Ok(self.layout.finish_band(trace.band, into)) } #[debug_ensures(ret.is_ok() -> trace.path.len() == path.len())] @@ -158,6 +158,6 @@ impl<'a, R: RulesTrait> Tracer<'a, R> { } fn draw(&mut self) -> Draw { - Draw::new(&mut self.board) + Draw::new(&mut self.layout) } } diff --git a/src/triangulation.rs b/src/triangulation.rs index 79d7dba..8586537 100644 --- a/src/triangulation.rs +++ b/src/triangulation.rs @@ -5,8 +5,8 @@ use petgraph::visit::{self, NodeIndexable}; use spade::{handles::FixedVertexHandle, DelaunayTriangulation, HasPosition, InsertionError}; use crate::{ + drawing::{rules::RulesTrait, Drawing}, graph::GetNodeIndex, - layout::{rules::RulesTrait, Layout}, }; pub trait GetVertexIndex { @@ -23,7 +23,7 @@ pub struct Triangulation + HasPosition> Triangulation { - pub fn new(layout: &Layout) -> Self { + pub fn new(layout: &Drawing) -> Self { let mut this = Self { triangulation: as spade::Triangulation>::new(), vertex_to_handle: Vec::new(), diff --git a/src/wraparoundable.rs b/src/wraparoundable.rs index cf3799a..5a19504 100644 --- a/src/wraparoundable.rs +++ b/src/wraparoundable.rs @@ -2,15 +2,15 @@ use enum_dispatch::enum_dispatch; use petgraph::stable_graph::NodeIndex; use crate::{ - graph::GetNodeIndex, - layout::{ + drawing::{ bend::{BendIndex, FixedBendIndex, LooseBendIndex}, dot::FixedDotIndex, graph::{GeometryIndex, MakePrimitive}, primitive::{FixedBend, FixedDot, GetFirstRail, GetInnerOuter, LooseBend, Primitive}, rules::RulesTrait, - Layout, + Drawing, }, + graph::GetNodeIndex, }; #[enum_dispatch] @@ -53,11 +53,11 @@ pub enum Wraparoundable<'a, R: RulesTrait> { } impl<'a, R: RulesTrait> Wraparoundable<'a, R> { - pub fn new(index: WraparoundableIndex, layout: &'a Layout) -> Self { + pub fn new(index: WraparoundableIndex, drawing: &'a Drawing) -> Self { match index { - WraparoundableIndex::FixedDot(dot) => layout.primitive(dot).into(), - WraparoundableIndex::FixedBend(bend) => layout.primitive(bend).into(), - WraparoundableIndex::LooseBend(bend) => layout.primitive(bend).into(), + WraparoundableIndex::FixedDot(dot) => drawing.primitive(dot).into(), + WraparoundableIndex::FixedBend(bend) => drawing.primitive(bend).into(), + WraparoundableIndex::LooseBend(bend) => drawing.primitive(bend).into(), } } }