board,layout: rename "layout" to "drawing", "board" to "layout"

This commit is contained in:
Mikolaj Wielgus 2024-03-22 23:23:31 +00:00
parent 4cb429ca6d
commit ef823c1c27
32 changed files with 1152 additions and 1135 deletions

View File

@ -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<String>, Receiver<String>),
#[serde(skip)]
layout: Option<Layout<DsnRules>>,
drawing: Option<Drawing<DsnRules>>,
#[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));

View File

@ -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<R>),
Layout(&'a Layout<R>),
Layout(&'a Drawing<R>),
}
struct EmptyRouterObserver;
@ -129,7 +129,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> 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<R> 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<R> 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,
};

View File

@ -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<R: RulesTrait> {
layout: Layout<R>, // Shouldn't be public, but is for now because `Draw` needs it.
connectivity: StableDiGraph<ConnectivityWeight, ConnectivityLabel, usize>,
}
impl<R: RulesTrait> Board<R> {
pub fn new(layout: Layout<R>) -> 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<Segbend, LayoutException> {
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<LoneLooseSegIndex, Infringement> {
self.layout.add_lone_loose_seg(from, to, weight)
}
pub fn add_seq_loose_seg(
&mut self,
from: DotIndex,
to: LooseDotIndex,
weight: SeqLooseSegWeight,
) -> Result<SeqLooseSegIndex, Infringement> {
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<FixedDotIndex> {
todo!()
}
pub fn band_length(&self, band: BandIndex) -> f64 {
// TODO.
0.0
}
pub fn layout(&self) -> &Layout<R> {
&self.layout
}
pub fn continent(&self, dot: FixedDotIndex) -> ContinentIndex {
// TODO.
ContinentIndex::new(0.into())
}
}

View File

@ -1,4 +0,0 @@
mod board;
pub mod connectivity;
pub use board::*;

View File

@ -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<R>,
layout: &'a mut Layout<R>,
}
impl<'a, R: RulesTrait> Draw<'a, R> {
pub fn new(board: &'a mut Board<R>) -> Self {
Self { board }
pub fn new(layout: &'a mut Layout<R>) -> 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<Head, Infringement> {
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<SegbendHead, LayoutException> {
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, LayoutException>(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<Head> {
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<R> {
Guide::new(self.board.layout())
Guide::new(self.layout.layout())
}
}

View File

@ -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;

View File

@ -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<R>,
drawing: &'a Drawing<R>,
}
impl<'a, R: RulesTrait> Collect<'a, R> {
pub fn new(layout: &'a Layout<R>) -> Self {
Self { layout }
pub fn new(drawing: &'a Drawing<R>) -> Self {
Self { drawing }
}
pub fn bend_bow(&self, bend: LooseBendIndex) -> Vec<GeometryIndex> {
let mut v: Vec<GeometryIndex> = 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();
}

View File

@ -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,
};

823
src/drawing/drawing.rs Normal file
View File

@ -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<R: RulesTrait> {
geometry_with_rtree: GeometryWithRtree<
GeometryWeight,
DotWeight,
SegWeight,
BendWeight,
GeometryIndex,
DotIndex,
SegIndex,
BendIndex,
>,
rules: R,
}
impl<R: RulesTrait> Drawing<R> {
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<FixedDotIndex, Infringement> {
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<W: DotWeightTrait<GeometryWeight> + GetLayer>(
&mut self,
weight: W,
infringables: Option<&[GeometryIndex]>,
) -> Result<GenericIndex<W>, Infringement>
where
GenericIndex<W>: Into<GeometryIndex> + 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<FixedSegIndex, Infringement> {
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<Segbend, LayoutException> {
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, LayoutException>(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<LooseBendIndex>) {
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<Segbend, LayoutException> {
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<Segbend, LayoutException> {
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, LayoutException>(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<LoneLooseSegIndex, Infringement> {
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<SeqLooseSegIndex, Infringement> {
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<W: SegWeightTrait<GeometryWeight> + GetLayer>(
&mut self,
from: DotIndex,
to: DotIndex,
weight: W,
infringables: Option<&[GeometryIndex]>,
) -> Result<GenericIndex<W>, Infringement>
where
GenericIndex<W>: Into<GeometryIndex> + 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<LooseBendIndex, LayoutException> {
// 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<W: BendWeightTrait<GeometryWeight> + GetLayer>(
&mut self,
from: DotIndex,
to: DotIndex,
core: FixedDotIndex,
weight: W,
infringables: Option<&[GeometryIndex]>,
) -> Result<GenericIndex<W>, Infringement>
where
GenericIndex<W>: Into<GeometryIndex> + 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<GenericIndex<LooseBendWeight>, 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::<Vec<FixedDotIndex>>()
.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<Item = GeometryIndex> + '_ {
self.geometry_with_rtree
.rtree()
.iter()
.map(|wrapper| wrapper.data)
}
pub fn layer_nodes(&self, layer: u64) -> impl Iterator<Item = GeometryIndex> + '_ {
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<R: RulesTrait> Drawing<R> {
#[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<Infringement> {
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<Collision> {
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<R: RulesTrait> Drawing<R> {
#[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<R> {
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<R> {
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<W>(&self, index: GenericIndex<W>) -> GenericPrimitive<W, R> {
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<R> {
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<R> {
Loose::new(index, self)
}
}

View File

@ -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<R>) -> Primitive<'a, R>;
fn primitive<'a, R: RulesTrait>(&self, drawing: &'a Drawing<R>) -> 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<R>) -> Primitive<'a, R> {
Primitive::$weight_variant(GenericPrimitive::new(*self, layout))
fn primitive<'a, R: RulesTrait>(&self, drawing: &'a Drawing<R>) -> Primitive<'a, R> {
Primitive::$weight_variant(GenericPrimitive::new(*self, drawing))
}
}
};

8
src/drawing/groups.rs Normal file
View File

@ -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<GeometryIndex>;
}

View File

@ -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<R>,
drawing: &'a Drawing<R>,
}
impl<'a, R: RulesTrait> Guide<'a, R> {
pub fn new(layout: &'a Layout<R>) -> Self {
Self { layout }
pub fn new(drawing: &'a Drawing<R>) -> Self {
Self { drawing }
}
pub fn head_into_dot_segment(
@ -74,7 +73,7 @@ impl<'a, R: RulesTrait> Guide<'a, R> {
) -> Result<Line, NoTangents> {
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<bool> {
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()
}
}

View File

@ -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<R>) -> Self {
pub fn new(index: LooseIndex, drawing: &'a Drawing<R>) -> 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(),
}
}
}

14
src/drawing/mod.rs Normal file
View File

@ -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::*;

View File

@ -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<R>;
pub trait GetDrawing<'a, R: RulesTrait> {
fn drawing(&self) -> &Drawing<R>;
}
#[enum_dispatch]
@ -72,9 +72,9 @@ pub trait GetJoints<F, T> {
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<LooseBendIndex> {
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<LooseBendIndex> {
self.layout()
self.drawing()
.geometry()
.inner(self.bend_index())
.map(|ni| LooseBendIndex::new(ni.node_index()))
}
fn outer(&self) -> Option<LooseBendIndex> {
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<W>,
layout: &'a Layout<R>,
drawing: &'a Drawing<R>,
}
impl<'a, W, R: RulesTrait> GenericPrimitive<'a, W, R> {
pub fn new(index: GenericIndex<W>, layout: &'a Layout<R>) -> Self {
Self { index, layout }
pub fn new(index: GenericIndex<W>, drawing: &'a Drawing<R>) -> 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<WW>(&self, index: GenericIndex<WW>) -> GenericPrimitive<WW, R> {
GenericPrimitive::new(index, &self.layout)
GenericPrimitive::new(index, &self.drawing)
}
}
@ -200,9 +200,9 @@ impl<'a, W, R: RulesTrait> GetInterior<GeometryIndex> for GenericPrimitive<'a, W
}
}
impl<'a, W, R: RulesTrait> GetLayout<'a, R> for GenericPrimitive<'a, W, R> {
fn layout(&self) -> &Layout<R> {
self.layout
impl<'a, W, R: RulesTrait> GetDrawing<'a, R> for GenericPrimitive<'a, W, R> {
fn drawing(&self) -> &Drawing<R> {
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<LooseIndex> {
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<SegIndex> {
self.layout
self.drawing
.geometry()
.joined_segs(self.index.into())
.collect()
}
fn bends(&self) -> Vec<BendIndex> {
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<SeqLooseSegIndex> {
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<FixedDotIndex, FixedDotIndex> 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<FixedDotIndex, FixedDotIndex> 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<DotIndex, LooseDotIndex> 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<FixedDotIndex, FixedDotIndex> 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<LooseBend<'a, R>> 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<LooseDotIndex, LooseDotIndex> 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()),

View File

@ -1,6 +1,6 @@
use enum_dispatch::enum_dispatch;
use crate::layout::primitive::Primitive;
use crate::drawing::primitive::Primitive;
#[enum_dispatch]
pub trait GetConditions {

View File

@ -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;

View File

@ -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<impl RulesTrait>) -> 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<impl RulesTrait>) -> 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 }
}
}

View File

@ -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<DsnRules> {
pub fn make_drawing(&self) -> Drawing<DsnRules> {
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::<String, i64>::from_iter(
@ -287,12 +287,12 @@ impl DsnDesign {
}
fn layer(
layout: &Layout<DsnRules>,
drawing: &Drawing<DsnRules>,
layer_vec: &Vec<Layer>,
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<DsnRules>,
drawing: &mut Drawing<DsnRules>,
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<DsnRules>,
drawing: &mut Drawing<DsnRules>,
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<DsnRules>,
drawing: &mut Drawing<DsnRules>,
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();

14
src/dsn/groups.rs Normal file
View File

@ -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<GroupIndex> {
//
}
}

View File

@ -1,6 +1,6 @@
use std::collections::HashMap;
use crate::layout::rules::{Conditions, RulesTrait};
use crate::drawing::rules::{Conditions, RulesTrait};
use super::structure::Pcb;

View File

@ -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,
};

View File

@ -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::{

View File

@ -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<ConnectivityWeight, ConnectivityLabel, usize>;

View File

@ -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<R: RulesTrait> {
geometry_with_rtree: GeometryWithRtree<
GeometryWeight,
DotWeight,
SegWeight,
BendWeight,
GeometryIndex,
DotIndex,
SegIndex,
BendIndex,
>,
rules: R,
drawing: Drawing<R>, // Shouldn't be public, but is for now because `Draw` needs it.
connectivity: StableDiGraph<ConnectivityWeight, ConnectivityLabel, usize>,
}
impl<R: RulesTrait> Layout<R> {
pub fn new(rules: R) -> Self {
pub fn new(drawing: Drawing<R>) -> 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<FixedDotIndex, Infringement> {
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<W: DotWeightTrait<GeometryWeight> + GetLayer>(
&mut self,
weight: W,
infringables: Option<&[GeometryIndex]>,
) -> Result<GenericIndex<W>, Infringement>
where
GenericIndex<W>: Into<GeometryIndex> + 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<FixedSegIndex, Infringement> {
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<R: RulesTrait> Layout<R> {
bend_weight: LooseBendWeight,
cw: bool,
) -> Result<Segbend, LayoutException> {
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, LayoutException>(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<LooseBendIndex>) {
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<Segbend, LayoutException> {
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<Segbend, LayoutException> {
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, LayoutException>(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<LoneLooseSegIndex, Infringement> {
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<SeqLooseSegIndex, Infringement> {
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<W: SegWeightTrait<GeometryWeight> + GetLayer>(
&mut self,
from: DotIndex,
to: DotIndex,
weight: W,
infringables: Option<&[GeometryIndex]>,
) -> Result<GenericIndex<W>, Infringement>
where
GenericIndex<W>: Into<GeometryIndex> + 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<LooseBendIndex, LayoutException> {
// 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<W: BendWeightTrait<GeometryWeight> + GetLayer>(
&mut self,
from: DotIndex,
to: DotIndex,
core: FixedDotIndex,
weight: W,
infringables: Option<&[GeometryIndex]>,
) -> Result<GenericIndex<W>, Infringement>
where
GenericIndex<W>: Into<GeometryIndex> + 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<GenericIndex<LooseBendWeight>, 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::<Vec<FixedDotIndex>>()
.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<Item = GeometryIndex> + '_ {
self.geometry_with_rtree
.rtree()
.iter()
.map(|wrapper| wrapper.data)
}
pub fn layer_nodes(&self, layer: u64) -> impl Iterator<Item = GeometryIndex> + '_ {
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<R: RulesTrait> Layout<R> {
#[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<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 detect_infringement_except(
&self,
node: GeometryIndex,
maybe_except: Option<&[GeometryIndex]>,
) -> Option<Infringement> {
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<Collision> {
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<R> {
&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<R: RulesTrait> Layout<R> {
#[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<R> {
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<R> {
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<W>(&self, index: GenericIndex<W>) -> GenericPrimitive<W, R> {
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<R> {
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<R> {
Loose::new(index, self)
pub fn continent(&self, dot: FixedDotIndex) -> ContinentIndex {
// TODO.
ContinentIndex::new(0.into())
}
}

View File

@ -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::*;

View File

@ -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;

View File

@ -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<impl RulesTrait>) -> Self {
pub fn new(layout: &Drawing<impl RulesTrait>) -> 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<impl RulesTrait>) -> Result<(), InsertionError> {
for node in layout.nodes() {
let center = node.primitive(layout).shape().center();
pub fn generate(&mut self, drawing: &Drawing<impl RulesTrait>) -> 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());
}
_ => (),
}

View File

@ -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<R: RulesTrait> {
}
pub struct Router<R: RulesTrait> {
pub board: Board<R>,
pub layout: Layout<R>,
}
struct RouterAstarStrategy<'a, RO: RouterObserverTrait<R>, R: RulesTrait> {
@ -99,14 +99,14 @@ impl<'a, RO: RouterObserverTrait<R>, 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>, 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>, R: RulesTrait> AstarStrategy<&Mesh, f64>
}
impl<R: RulesTrait> Router<R> {
pub fn new(board: Board<R>) -> Self {
Router { board }
pub fn new(layout: Layout<R>) -> Self {
Router { layout }
}
pub fn route_band(
@ -148,8 +148,8 @@ impl<R: RulesTrait> Router<R> {
// 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<R: RulesTrait> Router<R> {
width: f64,
observer: &mut impl RouterObserverTrait<R>,
) -> Result<BandIndex, RoutingError> {
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<R> {
Tracer::new(&mut self.board, mesh)
Tracer::new(&mut self.layout, mesh)
}
}

View File

@ -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<R>,
pub layout: &'a mut Layout<R>,
pub mesh: &'a Mesh,
}
impl<'a, R: RulesTrait> Tracer<'a, R> {
pub fn new(board: &'a mut Board<R>, mesh: &'a Mesh) -> Self {
Tracer { board, mesh }
pub fn new(layout: &'a mut Layout<R>, 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<R> {
Draw::new(&mut self.board)
Draw::new(&mut self.layout)
}
}

View File

@ -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<I> {
@ -23,7 +23,7 @@ pub struct Triangulation<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I
impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>>
Triangulation<I, W>
{
pub fn new(layout: &Layout<impl RulesTrait>) -> Self {
pub fn new(layout: &Drawing<impl RulesTrait>) -> Self {
let mut this = Self {
triangulation: <DelaunayTriangulation<W> as spade::Triangulation>::new(),
vertex_to_handle: Vec::new(),

View File

@ -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<R>) -> Self {
pub fn new(index: WraparoundableIndex, drawing: &'a Drawing<R>) -> 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(),
}
}
}