mirror of https://codeberg.org/topola/topola.git
board,layout: rename "layout" to "drawing", "board" to "layout"
This commit is contained in:
parent
4cb429ca6d
commit
ef823c1c27
|
|
@ -5,9 +5,9 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use topola::{
|
use topola::{
|
||||||
|
drawing::{graph::MakePrimitive, primitive::MakeShape, Drawing},
|
||||||
dsn::{design::DsnDesign, rules::DsnRules},
|
dsn::{design::DsnDesign, rules::DsnRules},
|
||||||
geometry::shape::{BendShape, DotShape, SegShape, Shape},
|
geometry::shape::{BendShape, DotShape, SegShape, Shape},
|
||||||
layout::{graph::MakePrimitive, primitive::MakeShape, Layout},
|
|
||||||
math::Circle,
|
math::Circle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ pub struct App {
|
||||||
text_channel: (Sender<String>, Receiver<String>),
|
text_channel: (Sender<String>, Receiver<String>),
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
layout: Option<Layout<DsnRules>>,
|
drawing: Option<Drawing<DsnRules>>,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
from_rect: egui::emath::Rect,
|
from_rect: egui::emath::Rect,
|
||||||
|
|
@ -36,7 +36,7 @@ impl Default for App {
|
||||||
// Example stuff:
|
// Example stuff:
|
||||||
label: "Hello World!".to_owned(),
|
label: "Hello World!".to_owned(),
|
||||||
text_channel: channel(),
|
text_channel: channel(),
|
||||||
layout: None,
|
drawing: None,
|
||||||
from_rect: egui::Rect::from_x_y_ranges(0.0..=1000000.0, 0.0..=500000.0),
|
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 cfg!(target_arch = "wasm32") {
|
||||||
if let Ok(file_contents) = self.text_channel.1.try_recv() {
|
if let Ok(file_contents) = self.text_channel.1.try_recv() {
|
||||||
let design = DsnDesign::load_from_string(file_contents).unwrap();
|
let design = DsnDesign::load_from_string(file_contents).unwrap();
|
||||||
self.layout = Some(design.make_layout());
|
self.drawing = Some(design.make_drawing());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Ok(path) = self.text_channel.1.try_recv() {
|
if let Ok(path) = self.text_channel.1.try_recv() {
|
||||||
let design = DsnDesign::load_from_file(&path).unwrap();
|
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 transform = egui::emath::RectTransform::from_to(self.from_rect, viewport_rect);
|
||||||
let mut painter = Painter::new(ui, transform);
|
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) {
|
for node in layout.layer_nodes(1) {
|
||||||
let shape = node.primitive(layout).shape();
|
let shape = node.primitive(layout).shape();
|
||||||
painter.paint_shape(&shape, egui::Color32::from_rgb(52, 52, 200));
|
painter.paint_shape(&shape, egui::Color32::from_rgb(52, 52, 200));
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,17 @@ macro_rules! dbg_dot {
|
||||||
use geo::point;
|
use geo::point;
|
||||||
use painter::Painter;
|
use painter::Painter;
|
||||||
use petgraph::visit::{EdgeRef, IntoEdgeReferences};
|
use petgraph::visit::{EdgeRef, IntoEdgeReferences};
|
||||||
use topola::board::connectivity::BandIndex;
|
|
||||||
use topola::board::Board;
|
|
||||||
use topola::draw::DrawException;
|
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::dsn::design::DsnDesign;
|
||||||
use topola::geometry::shape::{Shape, ShapeTrait};
|
use topola::geometry::shape::{Shape, ShapeTrait};
|
||||||
use topola::layout::dot::FixedDotWeight;
|
use topola::layout::connectivity::BandIndex;
|
||||||
use topola::layout::graph::{GeometryIndex, MakePrimitive};
|
use topola::layout::Layout;
|
||||||
use topola::layout::primitive::MakeShape;
|
|
||||||
use topola::layout::rules::{Conditions, RulesTrait};
|
|
||||||
use topola::layout::seg::FixedSegWeight;
|
|
||||||
use topola::layout::{Infringement, Layout, LayoutException};
|
|
||||||
use topola::mesh::{Mesh, MeshEdgeReference, VertexIndex};
|
use topola::mesh::{Mesh, MeshEdgeReference, VertexIndex};
|
||||||
use topola::router::RouterObserverTrait;
|
use topola::router::RouterObserverTrait;
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ impl RulesTrait for SimpleRules {
|
||||||
// Clunky enum to work around borrow checker.
|
// Clunky enum to work around borrow checker.
|
||||||
enum RouterOrLayout<'a, R: RulesTrait> {
|
enum RouterOrLayout<'a, R: RulesTrait> {
|
||||||
Router(&'a mut Router<R>),
|
Router(&'a mut Router<R>),
|
||||||
Layout(&'a Layout<R>),
|
Layout(&'a Drawing<R>),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EmptyRouterObserver;
|
struct EmptyRouterObserver;
|
||||||
|
|
@ -129,7 +129,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> for DebugRouterObserver<'a> {
|
||||||
self.renderer,
|
self.renderer,
|
||||||
self.font_context,
|
self.font_context,
|
||||||
self.view,
|
self.view,
|
||||||
RouterOrLayout::Layout(tracer.board.layout()),
|
RouterOrLayout::Layout(tracer.layout.layout()),
|
||||||
None,
|
None,
|
||||||
Some(tracer.mesh.clone()),
|
Some(tracer.mesh.clone()),
|
||||||
&trace.path,
|
&trace.path,
|
||||||
|
|
@ -148,7 +148,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> for DebugRouterObserver<'a> {
|
||||||
self.renderer,
|
self.renderer,
|
||||||
self.font_context,
|
self.font_context,
|
||||||
self.view,
|
self.view,
|
||||||
RouterOrLayout::Layout(tracer.board.layout()),
|
RouterOrLayout::Layout(tracer.layout.layout()),
|
||||||
None,
|
None,
|
||||||
Some(tracer.mesh.clone()),
|
Some(tracer.mesh.clone()),
|
||||||
&path,
|
&path,
|
||||||
|
|
@ -180,7 +180,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> for DebugRouterObserver<'a> {
|
||||||
self.renderer,
|
self.renderer,
|
||||||
self.font_context,
|
self.font_context,
|
||||||
self.view,
|
self.view,
|
||||||
RouterOrLayout::Layout(tracer.board.layout()),
|
RouterOrLayout::Layout(tracer.layout.layout()),
|
||||||
None,
|
None,
|
||||||
Some(tracer.mesh.clone()),
|
Some(tracer.mesh.clone()),
|
||||||
&trace.path,
|
&trace.path,
|
||||||
|
|
@ -256,9 +256,9 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
)?;
|
)?;
|
||||||
//let design = DsnDesign::load_from_file("tests/data/test/test.dsn")?;
|
//let design = DsnDesign::load_from_file("tests/data/test/test.dsn")?;
|
||||||
//dbg!(&design);
|
//dbg!(&design);
|
||||||
let layout = design.make_layout();
|
let drawing = design.make_drawing();
|
||||||
let board = Board::new(layout);
|
let layout = Layout::new(drawing);
|
||||||
let mut router = Router::new(board);
|
let mut router = Router::new(layout);
|
||||||
|
|
||||||
let mut view = View {
|
let mut view = View {
|
||||||
pan: vec2f(-80000.0, -60000.0),
|
pan: vec2f(-80000.0, -60000.0),
|
||||||
|
|
@ -271,7 +271,7 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&font_context,
|
&font_context,
|
||||||
&mut view,
|
&mut view,
|
||||||
RouterOrLayout::Layout(router.board.layout()),
|
RouterOrLayout::Layout(router.layout.layout()),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
&[],
|
&[],
|
||||||
|
|
@ -295,7 +295,7 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&font_context,
|
&font_context,
|
||||||
&mut view,
|
&mut view,
|
||||||
RouterOrLayout::Layout(router.board.layout()),
|
RouterOrLayout::Layout(router.layout.layout()),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
&[],
|
&[],
|
||||||
|
|
@ -388,7 +388,7 @@ fn render_times(
|
||||||
maybe_mesh = None;
|
maybe_mesh = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
router.board.layout()
|
router.layout.layout()
|
||||||
}
|
}
|
||||||
RouterOrLayout::Layout(layout) => layout,
|
RouterOrLayout::Layout(layout) => layout,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
mod board;
|
|
||||||
pub mod connectivity;
|
|
||||||
|
|
||||||
pub use board::*;
|
|
||||||
60
src/draw.rs
60
src/draw.rs
|
|
@ -3,8 +3,7 @@ use geo::{EuclideanLength, Point};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
board::Board,
|
drawing::{
|
||||||
layout::{
|
|
||||||
bend::{BendIndex, LooseBendWeight},
|
bend::{BendIndex, LooseBendWeight},
|
||||||
dot::{DotIndex, FixedDotIndex, LooseDotIndex, LooseDotWeight},
|
dot::{DotIndex, FixedDotIndex, LooseDotIndex, LooseDotWeight},
|
||||||
graph::{GetLayer, GetNet, MakePrimitive},
|
graph::{GetLayer, GetNet, MakePrimitive},
|
||||||
|
|
@ -14,6 +13,7 @@ use crate::{
|
||||||
seg::{LoneLooseSegWeight, SeqLooseSegWeight},
|
seg::{LoneLooseSegWeight, SeqLooseSegWeight},
|
||||||
Infringement, LayoutException,
|
Infringement, LayoutException,
|
||||||
},
|
},
|
||||||
|
layout::Layout,
|
||||||
math::{Circle, NoTangents},
|
math::{Circle, NoTangents},
|
||||||
wraparoundable::WraparoundableIndex,
|
wraparoundable::WraparoundableIndex,
|
||||||
};
|
};
|
||||||
|
|
@ -31,20 +31,20 @@ pub enum DrawException {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Draw<'a, R: RulesTrait> {
|
pub struct Draw<'a, R: RulesTrait> {
|
||||||
board: &'a mut Board<R>,
|
layout: &'a mut Layout<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: RulesTrait> Draw<'a, R> {
|
impl<'a, R: RulesTrait> Draw<'a, R> {
|
||||||
pub fn new(board: &'a mut Board<R>) -> Self {
|
pub fn new(layout: &'a mut Layout<R>) -> Self {
|
||||||
Self { board }
|
Self { layout }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&mut self, from: LooseDotIndex) -> Head {
|
pub fn start(&mut self, from: LooseDotIndex) -> Head {
|
||||||
self.guide().segbend_head(from).into()
|
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_ok() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_err() -> self.board.layout().node_count() == old(self.board.layout().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.layout.layout().node_count() == old(self.layout.layout().node_count()))]
|
||||||
pub fn finish_in_dot(
|
pub fn finish_in_dot(
|
||||||
&mut self,
|
&mut self,
|
||||||
head: Head,
|
head: Head,
|
||||||
|
|
@ -58,17 +58,17 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
||||||
let head = self
|
let head = self
|
||||||
.extend_head(head, tangent.start_point())
|
.extend_head(head, tangent.start_point())
|
||||||
.map_err(|err| DrawException::CannotFinishIn(into, err.into()))?;
|
.map_err(|err| DrawException::CannotFinishIn(into, err.into()))?;
|
||||||
let layer = head.face().primitive(self.board.layout()).layer();
|
let layer = head.face().primitive(self.layout.layout()).layer();
|
||||||
let net = head.face().primitive(self.board.layout()).net();
|
let net = head.face().primitive(self.layout.layout()).net();
|
||||||
|
|
||||||
match head.face() {
|
match head.face() {
|
||||||
DotIndex::Fixed(dot) => {
|
DotIndex::Fixed(dot) => {
|
||||||
self.board
|
self.layout
|
||||||
.add_lone_loose_seg(dot, into.into(), LoneLooseSegWeight { width, layer, net })
|
.add_lone_loose_seg(dot, into.into(), LoneLooseSegWeight { width, layer, net })
|
||||||
.map_err(|err| DrawException::CannotFinishIn(into, err.into()))?;
|
.map_err(|err| DrawException::CannotFinishIn(into, err.into()))?;
|
||||||
}
|
}
|
||||||
DotIndex::Loose(dot) => {
|
DotIndex::Loose(dot) => {
|
||||||
self.board
|
self.layout
|
||||||
.add_seq_loose_seg(into.into(), dot, SeqLooseSegWeight { width, layer, net })
|
.add_seq_loose_seg(into.into(), dot, SeqLooseSegWeight { width, layer, net })
|
||||||
.map_err(|err| DrawException::CannotFinishIn(into, err.into()))?;
|
.map_err(|err| DrawException::CannotFinishIn(into, err.into()))?;
|
||||||
}
|
}
|
||||||
|
|
@ -76,8 +76,8 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
||||||
Ok::<(), DrawException>(())
|
Ok::<(), DrawException>(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.board.layout().node_count() == old(self.board.layout().node_count() + 4))]
|
#[debug_ensures(ret.is_ok() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() + 4))]
|
||||||
#[debug_ensures(ret.is_err() -> self.board.layout().node_count() == old(self.board.layout().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.layout.layout().node_count() == old(self.layout.layout().node_count()))]
|
||||||
pub fn segbend_around_dot(
|
pub fn segbend_around_dot(
|
||||||
&mut self,
|
&mut self,
|
||||||
head: Head,
|
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_ok() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() + 4))]
|
||||||
#[debug_ensures(ret.is_err() -> self.board.layout().node_count() == old(self.board.layout().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.layout.layout().node_count() == old(self.layout.layout().node_count()))]
|
||||||
pub fn segbend_around_bend(
|
pub fn segbend_around_bend(
|
||||||
&mut self,
|
&mut self,
|
||||||
head: Head,
|
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_ok() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() + 4))]
|
||||||
#[debug_ensures(ret.is_err() -> self.board.layout().node_count() == old(self.board.layout().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.layout.layout().node_count() == old(self.layout.layout().node_count()))]
|
||||||
fn segbend_around(
|
fn segbend_around(
|
||||||
&mut self,
|
&mut self,
|
||||||
head: Head,
|
head: Head,
|
||||||
|
|
@ -182,18 +182,18 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
||||||
self.segbend(head, around, to, cw, width, offset)
|
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> {
|
fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, Infringement> {
|
||||||
if let Head::Segbend(head) = head {
|
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))
|
Ok(Head::Segbend(head))
|
||||||
} else {
|
} else {
|
||||||
Ok(head)
|
Ok(head)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.board.layout().node_count() == old(self.board.layout().node_count() + 4))]
|
#[debug_ensures(ret.is_ok() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() + 4))]
|
||||||
#[debug_ensures(ret.is_err() -> self.board.layout().node_count() == old(self.board.layout().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.layout.layout().node_count() == old(self.layout.layout().node_count()))]
|
||||||
fn segbend(
|
fn segbend(
|
||||||
&mut self,
|
&mut self,
|
||||||
head: Head,
|
head: Head,
|
||||||
|
|
@ -203,9 +203,9 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
||||||
width: f64,
|
width: f64,
|
||||||
offset: f64,
|
offset: f64,
|
||||||
) -> Result<SegbendHead, LayoutException> {
|
) -> Result<SegbendHead, LayoutException> {
|
||||||
let layer = head.face().primitive(self.board.layout()).layer();
|
let layer = head.face().primitive(self.layout.layout()).layer();
|
||||||
let net = head.face().primitive(self.board.layout()).net();
|
let net = head.face().primitive(self.layout.layout()).net();
|
||||||
let segbend = self.board.insert_segbend(
|
let segbend = self.layout.insert_segbend(
|
||||||
head.face(),
|
head.face(),
|
||||||
around,
|
around,
|
||||||
LooseDotWeight {
|
LooseDotWeight {
|
||||||
|
|
@ -227,7 +227,7 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
||||||
)?;
|
)?;
|
||||||
Ok::<SegbendHead, LayoutException>(SegbendHead {
|
Ok::<SegbendHead, LayoutException>(SegbendHead {
|
||||||
face: self
|
face: self
|
||||||
.board
|
.layout
|
||||||
.layout()
|
.layout()
|
||||||
.primitive(segbend.bend)
|
.primitive(segbend.bend)
|
||||||
.other_joint(segbend.dot),
|
.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_some() -> self.layout.layout().node_count() == old(self.layout.layout().node_count() - 4))]
|
||||||
#[debug_ensures(ret.is_none() -> self.board.layout().node_count() == old(self.board.layout().node_count()))]
|
#[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> {
|
pub fn undo_segbend(&mut self, head: SegbendHead) -> Option<Head> {
|
||||||
let prev_dot = self
|
let prev_dot = self
|
||||||
.board
|
.layout
|
||||||
.layout()
|
.layout()
|
||||||
.primitive(head.segbend.seg)
|
.primitive(head.segbend.seg)
|
||||||
.other_joint(head.segbend.dot.into());
|
.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))
|
Some(self.guide().head(prev_dot))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guide(&self) -> Guide<R> {
|
fn guide(&self) -> Guide<R> {
|
||||||
Guide::new(self.board.layout())
|
Guide::new(self.layout.layout())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{BendWeightTrait, GetOffset, GetWidth, SetOffset},
|
drawing::{
|
||||||
graph::{GenericIndex, GetNodeIndex},
|
|
||||||
layout::{
|
|
||||||
graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, MakePrimitive, Retag},
|
graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, MakePrimitive, Retag},
|
||||||
primitive::{GenericPrimitive, Primitive},
|
primitive::{GenericPrimitive, Primitive},
|
||||||
rules::RulesTrait,
|
rules::RulesTrait,
|
||||||
Layout,
|
Drawing,
|
||||||
},
|
},
|
||||||
|
geometry::{BendWeightTrait, GetOffset, GetWidth, SetOffset},
|
||||||
|
graph::{GenericIndex, GetNodeIndex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use petgraph::stable_graph::NodeIndex;
|
use petgraph::stable_graph::NodeIndex;
|
||||||
|
|
@ -5,32 +5,32 @@ use super::{
|
||||||
graph::GeometryIndex,
|
graph::GeometryIndex,
|
||||||
primitive::{GetInnerOuter, GetJoints},
|
primitive::{GetInnerOuter, GetJoints},
|
||||||
rules::RulesTrait,
|
rules::RulesTrait,
|
||||||
Layout,
|
Drawing,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Collect<'a, R: RulesTrait> {
|
pub struct Collect<'a, R: RulesTrait> {
|
||||||
layout: &'a Layout<R>,
|
drawing: &'a Drawing<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: RulesTrait> Collect<'a, R> {
|
impl<'a, R: RulesTrait> Collect<'a, R> {
|
||||||
pub fn new(layout: &'a Layout<R>) -> Self {
|
pub fn new(drawing: &'a Drawing<R>) -> Self {
|
||||||
Self { layout }
|
Self { drawing }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bend_bow(&self, bend: LooseBendIndex) -> Vec<GeometryIndex> {
|
pub fn bend_bow(&self, bend: LooseBendIndex) -> Vec<GeometryIndex> {
|
||||||
let mut v: Vec<GeometryIndex> = vec![];
|
let mut v: Vec<GeometryIndex> = vec![];
|
||||||
v.push(bend.into());
|
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.0.into());
|
||||||
v.push(ends.1.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());
|
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());
|
v.push(seg1.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ impl<'a, R: RulesTrait> Collect<'a, R> {
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
let mut rail = bend;
|
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()));
|
v.append(&mut self.bend_bow(outer.into()));
|
||||||
rail = outer;
|
rail = outer;
|
||||||
}
|
}
|
||||||
|
|
@ -53,8 +53,8 @@ impl<'a, R: RulesTrait> Collect<'a, R> {
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
let mut rail = around.into();
|
let mut rail = around.into();
|
||||||
|
|
||||||
while let Some(outer) = self.layout.wraparoundable(rail).wraparound() {
|
while let Some(outer) = self.drawing.wraparoundable(rail).wraparound() {
|
||||||
let primitive = self.layout.primitive(outer);
|
let primitive = self.drawing.primitive(outer);
|
||||||
|
|
||||||
v.push(outer.into());
|
v.push(outer.into());
|
||||||
|
|
||||||
|
|
@ -62,8 +62,8 @@ impl<'a, R: RulesTrait> Collect<'a, R> {
|
||||||
v.push(ends.0.into());
|
v.push(ends.0.into());
|
||||||
v.push(ends.1.into());
|
v.push(ends.1.into());
|
||||||
|
|
||||||
v.push(self.layout.primitive(ends.0).seg().unwrap().into());
|
v.push(self.drawing.primitive(ends.0).seg().unwrap().into());
|
||||||
v.push(self.layout.primitive(ends.1).seg().unwrap().into());
|
v.push(self.drawing.primitive(ends.1).seg().unwrap().into());
|
||||||
|
|
||||||
rail = outer.into();
|
rail = outer.into();
|
||||||
}
|
}
|
||||||
|
|
@ -4,14 +4,14 @@ use geo::Point;
|
||||||
use petgraph::stable_graph::NodeIndex;
|
use petgraph::stable_graph::NodeIndex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{DotWeightTrait, GetPos, GetWidth, SetPos},
|
drawing::{
|
||||||
graph::{GenericIndex, GetNodeIndex},
|
|
||||||
layout::{
|
|
||||||
graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, MakePrimitive, Retag},
|
graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, MakePrimitive, Retag},
|
||||||
primitive::{GenericPrimitive, Primitive},
|
primitive::{GenericPrimitive, Primitive},
|
||||||
rules::RulesTrait,
|
rules::RulesTrait,
|
||||||
Layout,
|
Drawing,
|
||||||
},
|
},
|
||||||
|
geometry::{DotWeightTrait, GetPos, GetWidth, SetPos},
|
||||||
|
graph::{GenericIndex, GetNodeIndex},
|
||||||
math::Circle,
|
math::Circle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,11 +2,7 @@ use enum_dispatch::enum_dispatch;
|
||||||
|
|
||||||
use petgraph::stable_graph::NodeIndex;
|
use petgraph::stable_graph::NodeIndex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{drawing::Drawing, graph::GetNodeIndex};
|
||||||
board::connectivity::{BandIndex, ContinentIndex},
|
|
||||||
graph::GetNodeIndex,
|
|
||||||
layout::Layout,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
bend::{FixedBendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight},
|
bend::{FixedBendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight},
|
||||||
|
|
@ -36,7 +32,7 @@ pub trait GetNet {
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub trait MakePrimitive {
|
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 {
|
macro_rules! impl_weight {
|
||||||
|
|
@ -62,8 +58,8 @@ macro_rules! impl_weight {
|
||||||
pub type $index_struct = GenericIndex<$weight_struct>;
|
pub type $index_struct = GenericIndex<$weight_struct>;
|
||||||
|
|
||||||
impl MakePrimitive for $index_struct {
|
impl MakePrimitive for $index_struct {
|
||||||
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> {
|
||||||
Primitive::$weight_variant(GenericPrimitive::new(*self, layout))
|
Primitive::$weight_variant(GenericPrimitive::new(*self, drawing))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -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>;
|
||||||
|
}
|
||||||
|
|
@ -2,16 +2,15 @@ use enum_dispatch::enum_dispatch;
|
||||||
use geo::Line;
|
use geo::Line;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
board::connectivity::BandIndex,
|
drawing::{
|
||||||
geometry::shape::{Shape, ShapeTrait},
|
|
||||||
layout::{
|
|
||||||
bend::BendIndex,
|
bend::BendIndex,
|
||||||
dot::{DotIndex, FixedDotIndex, LooseDotIndex},
|
dot::{DotIndex, FixedDotIndex, LooseDotIndex},
|
||||||
graph::MakePrimitive,
|
graph::MakePrimitive,
|
||||||
primitive::{GetCore, GetInnerOuter, GetOtherJoint, GetWeight, MakeShape},
|
primitive::{GetCore, GetInnerOuter, GetOtherJoint, GetWeight, MakeShape},
|
||||||
rules::GetConditions,
|
rules::GetConditions,
|
||||||
Layout,
|
Drawing,
|
||||||
},
|
},
|
||||||
|
geometry::shape::{Shape, ShapeTrait},
|
||||||
math::{self, Circle, NoTangents},
|
math::{self, Circle, NoTangents},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -58,12 +57,12 @@ impl HeadTrait for SegbendHead {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Guide<'a, R: RulesTrait> {
|
pub struct Guide<'a, R: RulesTrait> {
|
||||||
layout: &'a Layout<R>,
|
drawing: &'a Drawing<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: RulesTrait> Guide<'a, R> {
|
impl<'a, R: RulesTrait> Guide<'a, R> {
|
||||||
pub fn new(layout: &'a Layout<R>) -> Self {
|
pub fn new(drawing: &'a Drawing<R>) -> Self {
|
||||||
Self { layout }
|
Self { drawing }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn head_into_dot_segment(
|
pub fn head_into_dot_segment(
|
||||||
|
|
@ -74,7 +73,7 @@ impl<'a, R: RulesTrait> Guide<'a, R> {
|
||||||
) -> Result<Line, NoTangents> {
|
) -> Result<Line, NoTangents> {
|
||||||
let from_circle = self.head_circle(head, width);
|
let from_circle = self.head_circle(head, width);
|
||||||
let to_circle = Circle {
|
let to_circle = Circle {
|
||||||
pos: self.layout.primitive(into).weight().circle.pos,
|
pos: self.drawing.primitive(into).weight().circle.pos,
|
||||||
r: 0.0,
|
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 {
|
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(around.into()),
|
||||||
&self.conditions(head.face().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 {
|
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(head.face().into()),
|
||||||
&self.conditions(around.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> {
|
pub fn head_cw(&self, head: &Head) -> Option<bool> {
|
||||||
if let Head::Segbend(head) = head {
|
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() {
|
if head.face() == joints.0.into() {
|
||||||
Some(false)
|
Some(false)
|
||||||
|
|
@ -171,15 +170,15 @@ impl<'a, R: RulesTrait> Guide<'a, R> {
|
||||||
fn head_circle(&self, head: &Head, width: f64) -> Circle {
|
fn head_circle(&self, head: &Head, width: f64) -> Circle {
|
||||||
match *head {
|
match *head {
|
||||||
Head::Bare(head) => Circle {
|
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,
|
r: 0.0,
|
||||||
},
|
},
|
||||||
Head::Segbend(head) => {
|
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()))
|
self.bend_circle(inner.into(), width, &self.conditions(head.face().into()))
|
||||||
} else {
|
} else {
|
||||||
self.dot_circle(
|
self.dot_circle(
|
||||||
self.layout.primitive(head.segbend.bend).core().into(),
|
self.drawing.primitive(head.segbend.bend).core().into(),
|
||||||
width,
|
width,
|
||||||
&self.conditions(head.face().into()),
|
&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 {
|
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(),
|
Shape::Bend(shape) => shape.outer_circle(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
@ -199,20 +198,20 @@ impl<'a, R: RulesTrait> Guide<'a, R> {
|
||||||
r: outer_circle.r
|
r: outer_circle.r
|
||||||
+ width / 2.0
|
+ width / 2.0
|
||||||
+ self
|
+ self
|
||||||
.layout
|
.drawing
|
||||||
.rules()
|
.rules()
|
||||||
.clearance(&self.conditions(bend.into()), guide_conditions),
|
.clearance(&self.conditions(bend.into()), guide_conditions),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dot_circle(&self, dot: DotIndex, width: f64, guide_conditions: &Conditions) -> Circle {
|
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 {
|
Circle {
|
||||||
pos: shape.center(),
|
pos: shape.center(),
|
||||||
r: shape.width() / 2.0
|
r: shape.width() / 2.0
|
||||||
+ width / 2.0
|
+ width / 2.0
|
||||||
+ self
|
+ self
|
||||||
.layout
|
.drawing
|
||||||
.rules()
|
.rules()
|
||||||
.clearance(&self.conditions(dot.into()), guide_conditions),
|
.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 {
|
pub fn segbend_head(&self, dot: LooseDotIndex) -> SegbendHead {
|
||||||
SegbendHead {
|
SegbendHead {
|
||||||
face: dot,
|
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 {
|
fn rear(&self, head: SegbendHead) -> DotIndex {
|
||||||
self.layout
|
self.drawing
|
||||||
.primitive(head.segbend.seg)
|
.primitive(head.segbend.seg)
|
||||||
.other_joint(head.segbend.dot.into())
|
.other_joint(head.segbend.dot.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conditions(&self, node: GeometryIndex) -> Conditions {
|
fn conditions(&self, node: GeometryIndex) -> Conditions {
|
||||||
node.primitive(self.layout).conditions()
|
node.primitive(self.drawing).conditions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,15 +2,15 @@ use enum_dispatch::enum_dispatch;
|
||||||
use petgraph::stable_graph::NodeIndex;
|
use petgraph::stable_graph::NodeIndex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
graph::GetNodeIndex,
|
drawing::Drawing,
|
||||||
layout::Layout,
|
drawing::{
|
||||||
layout::{
|
|
||||||
bend::LooseBendIndex,
|
bend::LooseBendIndex,
|
||||||
dot::{DotIndex, LooseDotIndex},
|
dot::{DotIndex, LooseDotIndex},
|
||||||
graph::{GeometryIndex, MakePrimitive},
|
graph::{GeometryIndex, MakePrimitive},
|
||||||
primitive::{GetJoints, LoneLooseSeg, LooseBend, LooseDot, Primitive, SeqLooseSeg},
|
primitive::{GetJoints, LoneLooseSeg, LooseBend, LooseDot, Primitive, SeqLooseSeg},
|
||||||
seg::{LoneLooseSegIndex, SeqLooseSegIndex},
|
seg::{LoneLooseSegIndex, SeqLooseSegIndex},
|
||||||
},
|
},
|
||||||
|
graph::GetNodeIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::rules::RulesTrait;
|
use super::rules::RulesTrait;
|
||||||
|
|
@ -49,12 +49,12 @@ pub enum Loose<'a, R: RulesTrait> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: RulesTrait> Loose<'a, R> {
|
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 {
|
match index {
|
||||||
LooseIndex::Dot(dot) => layout.primitive(dot).into(),
|
LooseIndex::Dot(dot) => drawing.primitive(dot).into(),
|
||||||
LooseIndex::LoneSeg(seg) => layout.primitive(seg).into(),
|
LooseIndex::LoneSeg(seg) => drawing.primitive(seg).into(),
|
||||||
LooseIndex::SeqSeg(seg) => layout.primitive(seg).into(),
|
LooseIndex::SeqSeg(seg) => drawing.primitive(seg).into(),
|
||||||
LooseIndex::Bend(bend) => layout.primitive(bend).into(),
|
LooseIndex::Bend(bend) => drawing.primitive(bend).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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::*;
|
||||||
|
|
@ -1,13 +1,7 @@
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use petgraph::stable_graph::NodeIndex;
|
use petgraph::stable_graph::NodeIndex;
|
||||||
|
|
||||||
use crate::board::connectivity::{BandIndex, ContinentIndex};
|
use crate::drawing::{
|
||||||
use crate::geometry::{
|
|
||||||
shape::{Shape, ShapeTrait},
|
|
||||||
GetOffset, GetWidth,
|
|
||||||
};
|
|
||||||
use crate::graph::{GenericIndex, GetNodeIndex};
|
|
||||||
use crate::layout::{
|
|
||||||
bend::{BendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight},
|
bend::{BendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight},
|
||||||
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
|
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
|
||||||
graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, Retag},
|
graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, Retag},
|
||||||
|
|
@ -17,12 +11,18 @@ use crate::layout::{
|
||||||
FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex, SeqLooseSegIndex,
|
FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex, SeqLooseSegIndex,
|
||||||
SeqLooseSegWeight,
|
SeqLooseSegWeight,
|
||||||
},
|
},
|
||||||
Layout,
|
Drawing,
|
||||||
};
|
};
|
||||||
|
use crate::geometry::{
|
||||||
|
shape::{Shape, ShapeTrait},
|
||||||
|
GetOffset, GetWidth,
|
||||||
|
};
|
||||||
|
use crate::graph::{GenericIndex, GetNodeIndex};
|
||||||
|
use crate::layout::connectivity::{BandIndex, ContinentIndex};
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub trait GetLayout<'a, R: RulesTrait> {
|
pub trait GetDrawing<'a, R: RulesTrait> {
|
||||||
fn layout(&self) -> &Layout<R>;
|
fn drawing(&self) -> &Drawing<R>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
|
|
@ -72,9 +72,9 @@ pub trait GetJoints<F, T> {
|
||||||
fn joints(&self) -> (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> {
|
fn first_rail(&self) -> Option<LooseBendIndex> {
|
||||||
self.layout()
|
self.drawing()
|
||||||
.geometry()
|
.geometry()
|
||||||
.first_rail(self.node_index())
|
.first_rail(self.node_index())
|
||||||
.map(|ni| LooseBendIndex::new(ni.node_index()))
|
.map(|ni| LooseBendIndex::new(ni.node_index()))
|
||||||
|
|
@ -85,10 +85,10 @@ pub trait GetBendIndex {
|
||||||
fn bend_index(&self) -> BendIndex;
|
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 {
|
fn core(&self) -> FixedDotIndex {
|
||||||
FixedDotIndex::new(
|
FixedDotIndex::new(
|
||||||
self.layout()
|
self.drawing()
|
||||||
.geometry()
|
.geometry()
|
||||||
.core(self.bend_index())
|
.core(self.bend_index())
|
||||||
.node_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> {
|
fn inner(&self) -> Option<LooseBendIndex> {
|
||||||
self.layout()
|
self.drawing()
|
||||||
.geometry()
|
.geometry()
|
||||||
.inner(self.bend_index())
|
.inner(self.bend_index())
|
||||||
.map(|ni| LooseBendIndex::new(ni.node_index()))
|
.map(|ni| LooseBendIndex::new(ni.node_index()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn outer(&self) -> Option<LooseBendIndex> {
|
fn outer(&self) -> Option<LooseBendIndex> {
|
||||||
self.layout()
|
self.drawing()
|
||||||
.geometry()
|
.geometry()
|
||||||
.outer(self.bend_index())
|
.outer(self.bend_index())
|
||||||
.map(|ni| LooseBendIndex::new(ni.node_index()))
|
.map(|ni| LooseBendIndex::new(ni.node_index()))
|
||||||
|
|
@ -172,17 +172,17 @@ pub enum Primitive<'a, R: RulesTrait> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GenericPrimitive<'a, W, R: RulesTrait> {
|
pub struct GenericPrimitive<'a, W, R: RulesTrait> {
|
||||||
pub index: GenericIndex<W>,
|
pub index: GenericIndex<W>,
|
||||||
layout: &'a Layout<R>,
|
drawing: &'a Drawing<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, W, R: RulesTrait> GenericPrimitive<'a, W, R> {
|
impl<'a, W, R: RulesTrait> GenericPrimitive<'a, W, R> {
|
||||||
pub fn new(index: GenericIndex<W>, layout: &'a Layout<R>) -> Self {
|
pub fn new(index: GenericIndex<W>, drawing: &'a Drawing<R>) -> Self {
|
||||||
Self { index, layout }
|
Self { index, drawing }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tagged_weight(&self) -> GeometryWeight {
|
fn tagged_weight(&self) -> GeometryWeight {
|
||||||
*self
|
*self
|
||||||
.layout
|
.drawing
|
||||||
.geometry()
|
.geometry()
|
||||||
.graph()
|
.graph()
|
||||||
.node_weight(self.index.node_index())
|
.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> {
|
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> {
|
impl<'a, W, R: RulesTrait> GetDrawing<'a, R> for GenericPrimitive<'a, W, R> {
|
||||||
fn layout(&self) -> &Layout<R> {
|
fn drawing(&self) -> &Drawing<R> {
|
||||||
self.layout
|
self.drawing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,13 +239,13 @@ impl_fixed_primitive!(FixedDot, FixedDotWeight);
|
||||||
|
|
||||||
impl<'a, R: RulesTrait> FixedDot<'a, R> {
|
impl<'a, R: RulesTrait> FixedDot<'a, R> {
|
||||||
pub fn first_loose(&self, _band: BandIndex) -> Option<LooseIndex> {
|
pub fn first_loose(&self, _band: BandIndex) -> Option<LooseIndex> {
|
||||||
self.layout
|
self.drawing
|
||||||
.geometry()
|
.geometry()
|
||||||
.joineds(self.index.into())
|
.joineds(self.index.into())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find_map(|ni| {
|
.find_map(|ni| {
|
||||||
let weight = self
|
let weight = self
|
||||||
.layout
|
.drawing
|
||||||
.geometry()
|
.geometry()
|
||||||
.graph()
|
.graph()
|
||||||
.node_weight(ni.node_index())
|
.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> {
|
impl<'a, R: RulesTrait> MakeShape for FixedDot<'a, R> {
|
||||||
fn shape(&self) -> Shape {
|
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> {
|
impl<'a, R: RulesTrait> GetLimbs for FixedDot<'a, R> {
|
||||||
fn segs(&self) -> Vec<SegIndex> {
|
fn segs(&self) -> Vec<SegIndex> {
|
||||||
self.layout
|
self.drawing
|
||||||
.geometry()
|
.geometry()
|
||||||
.joined_segs(self.index.into())
|
.joined_segs(self.index.into())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bends(&self) -> Vec<BendIndex> {
|
fn bends(&self) -> Vec<BendIndex> {
|
||||||
self.layout
|
self.drawing
|
||||||
.geometry()
|
.geometry()
|
||||||
.joined_bends(self.index.into())
|
.joined_bends(self.index.into())
|
||||||
.collect()
|
.collect()
|
||||||
|
|
@ -290,7 +290,7 @@ impl_loose_primitive!(LooseDot, LooseDotWeight);
|
||||||
|
|
||||||
impl<'a, R: RulesTrait> LooseDot<'a, R> {
|
impl<'a, R: RulesTrait> LooseDot<'a, R> {
|
||||||
pub fn seg(&self) -> Option<SeqLooseSegIndex> {
|
pub fn seg(&self) -> Option<SeqLooseSegIndex> {
|
||||||
self.layout
|
self.drawing
|
||||||
.geometry()
|
.geometry()
|
||||||
.joined_segs(self.index.into())
|
.joined_segs(self.index.into())
|
||||||
.map(|ni| SeqLooseSegIndex::new(ni.node_index()))
|
.map(|ni| SeqLooseSegIndex::new(ni.node_index()))
|
||||||
|
|
@ -298,7 +298,7 @@ impl<'a, R: RulesTrait> LooseDot<'a, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bend(&self) -> LooseBendIndex {
|
pub fn bend(&self) -> LooseBendIndex {
|
||||||
self.layout
|
self.drawing
|
||||||
.geometry()
|
.geometry()
|
||||||
.joined_bends(self.index.into())
|
.joined_bends(self.index.into())
|
||||||
.map(|ni| LooseBendIndex::new(ni.node_index()))
|
.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> {
|
impl<'a, R: RulesTrait> MakeShape for LooseDot<'a, R> {
|
||||||
fn shape(&self) -> Shape {
|
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> {
|
impl<'a, R: RulesTrait> MakeShape for FixedSeg<'a, R> {
|
||||||
fn shape(&self) -> Shape {
|
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> {
|
impl<'a, R: RulesTrait> GetJoints<FixedDotIndex, FixedDotIndex> for FixedSeg<'a, R> {
|
||||||
fn joints(&self) -> (FixedDotIndex, FixedDotIndex) {
|
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(from.node_index()),
|
||||||
FixedDotIndex::new(to.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> {
|
impl<'a, R: RulesTrait> MakeShape for LoneLooseSeg<'a, R> {
|
||||||
fn shape(&self) -> Shape {
|
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> {
|
impl<'a, R: RulesTrait> GetJoints<FixedDotIndex, FixedDotIndex> for LoneLooseSeg<'a, R> {
|
||||||
fn joints(&self) -> (FixedDotIndex, FixedDotIndex) {
|
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(from.node_index()),
|
||||||
FixedDotIndex::new(to.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> {
|
impl<'a, R: RulesTrait> MakeShape for SeqLooseSeg<'a, R> {
|
||||||
fn shape(&self) -> Shape {
|
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> {
|
impl<'a, R: RulesTrait> GetJoints<DotIndex, LooseDotIndex> for SeqLooseSeg<'a, R> {
|
||||||
fn joints(&self) -> (DotIndex, LooseDotIndex) {
|
fn joints(&self) -> (DotIndex, LooseDotIndex) {
|
||||||
let joints = self.layout.geometry().seg_joints(self.index.into());
|
let joints = self.drawing.geometry().seg_joints(self.index.into());
|
||||||
if let DotWeight::Fixed(..) = self.layout.geometry().dot_weight(joints.0) {
|
if let DotWeight::Fixed(..) = self.drawing.geometry().dot_weight(joints.0) {
|
||||||
(
|
(
|
||||||
FixedDotIndex::new(joints.0.node_index()).into(),
|
FixedDotIndex::new(joints.0.node_index()).into(),
|
||||||
LooseDotIndex::new(joints.1.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(),
|
FixedDotIndex::new(joints.1.node_index()).into(),
|
||||||
LooseDotIndex::new(joints.0.node_index()),
|
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> {
|
impl<'a, R: RulesTrait> MakeShape for FixedBend<'a, R> {
|
||||||
fn shape(&self) -> Shape {
|
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> {
|
impl<'a, R: RulesTrait> GetJoints<FixedDotIndex, FixedDotIndex> for FixedBend<'a, R> {
|
||||||
fn joints(&self) -> (FixedDotIndex, FixedDotIndex) {
|
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(from.node_index()),
|
||||||
FixedDotIndex::new(to.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> {
|
impl<'a, R: RulesTrait> MakeShape for LooseBend<'a, R> {
|
||||||
fn shape(&self) -> Shape {
|
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> {
|
impl<'a, R: RulesTrait> GetJoints<LooseDotIndex, LooseDotIndex> for LooseBend<'a, R> {
|
||||||
fn joints(&self) -> (LooseDotIndex, LooseDotIndex) {
|
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(from.node_index()),
|
||||||
LooseDotIndex::new(to.node_index()),
|
LooseDotIndex::new(to.node_index()),
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
|
|
||||||
use crate::layout::primitive::Primitive;
|
use crate::drawing::primitive::Primitive;
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub trait GetConditions {
|
pub trait GetConditions {
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{GetWidth, SegWeightTrait},
|
drawing::{
|
||||||
graph::{GenericIndex, GetNodeIndex},
|
|
||||||
layout::{
|
|
||||||
graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, MakePrimitive, Retag},
|
graph::{GeometryIndex, GeometryWeight, GetLayer, GetNet, MakePrimitive, Retag},
|
||||||
primitive::{GenericPrimitive, Primitive},
|
primitive::{GenericPrimitive, Primitive},
|
||||||
rules::RulesTrait,
|
rules::RulesTrait,
|
||||||
Layout,
|
Drawing,
|
||||||
},
|
},
|
||||||
|
geometry::{GetWidth, SegWeightTrait},
|
||||||
|
graph::{GenericIndex, GetNodeIndex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use petgraph::stable_graph::NodeIndex;
|
use petgraph::stable_graph::NodeIndex;
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::layout::{
|
use crate::drawing::{
|
||||||
bend::LooseBendIndex,
|
bend::LooseBendIndex,
|
||||||
dot::LooseDotIndex,
|
dot::LooseDotIndex,
|
||||||
graph::GeometryIndex,
|
graph::GeometryIndex,
|
||||||
primitive::{GetInterior, GetJoints, GetOtherJoint, LooseBend, LooseDot},
|
primitive::{GetInterior, GetJoints, GetOtherJoint, LooseBend, LooseDot},
|
||||||
seg::SeqLooseSegIndex,
|
seg::SeqLooseSegIndex,
|
||||||
Layout,
|
Drawing,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::rules::RulesTrait;
|
use super::rules::RulesTrait;
|
||||||
|
|
@ -17,10 +17,10 @@ pub struct Segbend {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Segbend {
|
impl Segbend {
|
||||||
pub fn from_dot(dot: LooseDotIndex, layout: &Layout<impl RulesTrait>) -> Self {
|
pub fn from_dot(dot: LooseDotIndex, drawing: &Drawing<impl RulesTrait>) -> Self {
|
||||||
let bend = LooseDot::new(dot, layout).bend();
|
let bend = LooseDot::new(dot, drawing).bend();
|
||||||
let dot = LooseBend::new(bend, layout).other_joint(dot);
|
let dot = LooseBend::new(bend, drawing).other_joint(dot);
|
||||||
let seg = LooseDot::new(dot, layout).seg().unwrap();
|
let seg = LooseDot::new(dot, drawing).seg().unwrap();
|
||||||
Self { bend, dot, seg }
|
Self { bend, dot, seg }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ use geo::{point, Point, Rotate, Translate};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{dot::FixedDotWeight, seg::FixedSegWeight, Layout},
|
drawing::{dot::FixedDotWeight, seg::FixedSegWeight, Drawing},
|
||||||
math::Circle,
|
math::Circle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -41,9 +41,9 @@ impl DsnDesign {
|
||||||
Ok(Self { pcb })
|
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 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
|
// mapping of pin id -> net id prepared for adding pins
|
||||||
let pin_nets = HashMap::<String, i64>::from_iter(
|
let pin_nets = HashMap::<String, i64>::from_iter(
|
||||||
|
|
@ -287,12 +287,12 @@ impl DsnDesign {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layer(
|
fn layer(
|
||||||
layout: &Layout<DsnRules>,
|
drawing: &Drawing<DsnRules>,
|
||||||
layer_vec: &Vec<Layer>,
|
layer_vec: &Vec<Layer>,
|
||||||
layer_name: &str,
|
layer_name: &str,
|
||||||
front: bool,
|
front: bool,
|
||||||
) -> usize {
|
) -> 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 {
|
if front {
|
||||||
image_layer as usize
|
image_layer as usize
|
||||||
|
|
@ -302,7 +302,7 @@ impl DsnDesign {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_circle(
|
fn add_circle(
|
||||||
layout: &mut Layout<DsnRules>,
|
drawing: &mut Drawing<DsnRules>,
|
||||||
place_pos: Point,
|
place_pos: Point,
|
||||||
place_rot: f64,
|
place_rot: f64,
|
||||||
pin_pos: Point,
|
pin_pos: Point,
|
||||||
|
|
@ -316,13 +316,13 @@ impl DsnDesign {
|
||||||
r,
|
r,
|
||||||
};
|
};
|
||||||
|
|
||||||
layout
|
drawing
|
||||||
.add_fixed_dot(FixedDotWeight { circle, layer, net })
|
.add_fixed_dot(FixedDotWeight { circle, layer, net })
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_rect(
|
fn add_rect(
|
||||||
layout: &mut Layout<DsnRules>,
|
drawing: &mut Drawing<DsnRules>,
|
||||||
place_pos: Point,
|
place_pos: Point,
|
||||||
place_rot: f64,
|
place_rot: f64,
|
||||||
pin_pos: Point,
|
pin_pos: Point,
|
||||||
|
|
@ -335,7 +335,7 @@ impl DsnDesign {
|
||||||
net: i64,
|
net: i64,
|
||||||
) {
|
) {
|
||||||
// Corners.
|
// Corners.
|
||||||
let dot_1_1 = layout
|
let dot_1_1 = drawing
|
||||||
.add_fixed_dot(FixedDotWeight {
|
.add_fixed_dot(FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x1, y1),
|
pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x1, y1),
|
||||||
|
|
@ -345,7 +345,7 @@ impl DsnDesign {
|
||||||
net,
|
net,
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let dot_2_1 = layout
|
let dot_2_1 = drawing
|
||||||
.add_fixed_dot(FixedDotWeight {
|
.add_fixed_dot(FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x2, y1),
|
pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x2, y1),
|
||||||
|
|
@ -355,7 +355,7 @@ impl DsnDesign {
|
||||||
net,
|
net,
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let dot_2_2 = layout
|
let dot_2_2 = drawing
|
||||||
.add_fixed_dot(FixedDotWeight {
|
.add_fixed_dot(FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x2, y2),
|
pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x2, y2),
|
||||||
|
|
@ -365,7 +365,7 @@ impl DsnDesign {
|
||||||
net,
|
net,
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let dot_1_2 = layout
|
let dot_1_2 = drawing
|
||||||
.add_fixed_dot(FixedDotWeight {
|
.add_fixed_dot(FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x1, y2),
|
pos: Self::pos(place_pos, place_rot, pin_pos, pin_rot, x1, y2),
|
||||||
|
|
@ -376,7 +376,7 @@ impl DsnDesign {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// Sides.
|
// Sides.
|
||||||
layout
|
drawing
|
||||||
.add_fixed_seg(
|
.add_fixed_seg(
|
||||||
dot_1_1,
|
dot_1_1,
|
||||||
dot_2_1,
|
dot_2_1,
|
||||||
|
|
@ -387,7 +387,7 @@ impl DsnDesign {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
layout
|
drawing
|
||||||
.add_fixed_seg(
|
.add_fixed_seg(
|
||||||
dot_2_1,
|
dot_2_1,
|
||||||
dot_2_2,
|
dot_2_2,
|
||||||
|
|
@ -398,7 +398,7 @@ impl DsnDesign {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
layout
|
drawing
|
||||||
.add_fixed_seg(
|
.add_fixed_seg(
|
||||||
dot_2_2,
|
dot_2_2,
|
||||||
dot_1_2,
|
dot_1_2,
|
||||||
|
|
@ -409,7 +409,7 @@ impl DsnDesign {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
layout
|
drawing
|
||||||
.add_fixed_seg(
|
.add_fixed_seg(
|
||||||
dot_1_2,
|
dot_1_2,
|
||||||
dot_1_1,
|
dot_1_1,
|
||||||
|
|
@ -423,7 +423,7 @@ impl DsnDesign {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_path(
|
fn add_path(
|
||||||
layout: &mut Layout<DsnRules>,
|
drawing: &mut Drawing<DsnRules>,
|
||||||
place_pos: Point,
|
place_pos: Point,
|
||||||
place_rot: f64,
|
place_rot: f64,
|
||||||
pin_pos: Point,
|
pin_pos: Point,
|
||||||
|
|
@ -434,7 +434,7 @@ impl DsnDesign {
|
||||||
net: i64,
|
net: i64,
|
||||||
) {
|
) {
|
||||||
// add the first coordinate in the wire path as a dot and save its index
|
// 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 {
|
.add_fixed_dot(FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(
|
pos: Self::pos(
|
||||||
|
|
@ -454,7 +454,7 @@ impl DsnDesign {
|
||||||
|
|
||||||
// iterate through path coords starting from the second
|
// iterate through path coords starting from the second
|
||||||
for coord in coords.iter().skip(1) {
|
for coord in coords.iter().skip(1) {
|
||||||
let index = layout
|
let index = drawing
|
||||||
.add_fixed_dot(FixedDotWeight {
|
.add_fixed_dot(FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(
|
pos: Self::pos(
|
||||||
|
|
@ -474,7 +474,7 @@ impl DsnDesign {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// add a seg between the current and previous coords
|
// add a seg between the current and previous coords
|
||||||
let _ = layout
|
let _ = drawing
|
||||||
.add_fixed_seg(prev_index, index, FixedSegWeight { width, layer, net })
|
.add_fixed_seg(prev_index, index, FixedSegWeight { width, layer, net })
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::layout::rules::{Conditions, RulesTrait};
|
use crate::drawing::rules::{Conditions, RulesTrait};
|
||||||
|
|
||||||
use super::structure::Pcb;
|
use super::structure::Pcb;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,7 @@ use petgraph::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::shape::{BendShape, DotShape, SegShape, Shape},
|
drawing::{
|
||||||
graph::{GenericIndex, GetNodeIndex},
|
|
||||||
layout::{
|
|
||||||
bend::{BendWeight, FixedBendWeight, LooseBendWeight},
|
bend::{BendWeight, FixedBendWeight, LooseBendWeight},
|
||||||
dot::{DotWeight, FixedDotWeight, LooseDotWeight},
|
dot::{DotWeight, FixedDotWeight, LooseDotWeight},
|
||||||
graph::{GeometryWeight, Retag},
|
graph::{GeometryWeight, Retag},
|
||||||
|
|
@ -19,6 +17,8 @@ use crate::{
|
||||||
rules::RulesTrait,
|
rules::RulesTrait,
|
||||||
seg::{FixedSegWeight, LoneLooseSegWeight, SegWeight, SeqLooseSegWeight},
|
seg::{FixedSegWeight, LoneLooseSegWeight, SegWeight, SeqLooseSegWeight},
|
||||||
},
|
},
|
||||||
|
geometry::shape::{BendShape, DotShape, SegShape, Shape},
|
||||||
|
graph::{GenericIndex, GetNodeIndex},
|
||||||
math::Circle,
|
math::Circle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ use petgraph::stable_graph::StableDiGraph;
|
||||||
use rstar::{primitives::GeomWithData, RTree, RTreeObject, AABB};
|
use rstar::{primitives::GeomWithData, RTree, RTreeObject, AABB};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
drawing::graph::{GetLayer, Retag},
|
||||||
graph::{GenericIndex, GetNodeIndex},
|
graph::{GenericIndex, GetNodeIndex},
|
||||||
layout::graph::{GetLayer, Retag},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ use enum_dispatch::enum_dispatch;
|
||||||
use petgraph::stable_graph::StableDiGraph;
|
use petgraph::stable_graph::StableDiGraph;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
drawing::{dot::FixedDotIndex, graph::GetNet, primitive::Primitive, rules::RulesTrait},
|
||||||
graph::GenericIndex,
|
graph::GenericIndex,
|
||||||
layout::{dot::FixedDotIndex, graph::GetNet, primitive::Primitive, rules::RulesTrait},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type ConnectivityGraph = StableDiGraph<ConnectivityWeight, ConnectivityLabel, usize>;
|
pub type ConnectivityGraph = StableDiGraph<ConnectivityWeight, ConnectivityLabel, usize>;
|
||||||
|
|
@ -1,212 +1,64 @@
|
||||||
use contracts::debug_ensures;
|
|
||||||
use enum_dispatch::enum_dispatch;
|
|
||||||
use geo::Point;
|
use geo::Point;
|
||||||
|
use petgraph::stable_graph::StableDiGraph;
|
||||||
|
|
||||||
use rstar::{RTreeObject, AABB};
|
use crate::{
|
||||||
use thiserror::Error;
|
drawing::{
|
||||||
|
bend::LooseBendWeight,
|
||||||
use super::graph::GetLayer;
|
dot::{DotIndex, FixedDotIndex, LooseDotIndex, LooseDotWeight},
|
||||||
use super::loose::{GetNextLoose, Loose, LooseIndex};
|
rules::RulesTrait,
|
||||||
use super::rules::RulesTrait;
|
seg::{LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex, SeqLooseSegWeight},
|
||||||
use super::segbend::Segbend;
|
segbend::Segbend,
|
||||||
use crate::geometry::{
|
Drawing, Infringement, LayoutException,
|
||||||
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,
|
|
||||||
},
|
},
|
||||||
|
graph::GetNodeIndex,
|
||||||
|
wraparoundable::WraparoundableIndex,
|
||||||
};
|
};
|
||||||
use crate::math::NoTangents;
|
|
||||||
use crate::wraparoundable::{GetWraparound, Wraparoundable, WraparoundableIndex};
|
|
||||||
|
|
||||||
use super::bend::BendWeight;
|
use super::connectivity::{
|
||||||
use super::seg::SegWeight;
|
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> {
|
pub struct Layout<R: RulesTrait> {
|
||||||
geometry_with_rtree: GeometryWithRtree<
|
drawing: Drawing<R>, // Shouldn't be public, but is for now because `Draw` needs it.
|
||||||
GeometryWeight,
|
connectivity: StableDiGraph<ConnectivityWeight, ConnectivityLabel, usize>,
|
||||||
DotWeight,
|
|
||||||
SegWeight,
|
|
||||||
BendWeight,
|
|
||||||
GeometryIndex,
|
|
||||||
DotIndex,
|
|
||||||
SegIndex,
|
|
||||||
BendIndex,
|
|
||||||
>,
|
|
||||||
rules: R,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: RulesTrait> Layout<R> {
|
impl<R: RulesTrait> Layout<R> {
|
||||||
pub fn new(rules: R) -> Self {
|
pub fn new(drawing: Drawing<R>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
geometry_with_rtree: GeometryWithRtree::new(2),
|
drawing,
|
||||||
rules,
|
connectivity: StableDiGraph::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_band(&mut self, first_loose: SeqLooseSegIndex) {
|
pub fn remove_band(&mut self, band: BandIndex) {
|
||||||
let mut dots = vec![];
|
todo!()
|
||||||
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) {
|
pub fn remove_segbend(&mut self, segbend: &Segbend, face: LooseDotIndex) {
|
||||||
let maybe_outer = self.primitive(segbend.bend).outer();
|
self.drawing.remove_segbend(segbend, face)
|
||||||
|
|
||||||
// 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());
|
pub fn start_band(&mut self, from: FixedDotIndex) -> BandIndex {
|
||||||
self.geometry_with_rtree.remove_seg(segbend.seg.into());
|
let band = self
|
||||||
|
.connectivity
|
||||||
// We must remove the dots only after the segs and bends because we need dots to calculate
|
.add_node(ConnectivityWeight::Band(BandWeight { from, to: None }));
|
||||||
// the shapes, which we first need unchanged to remove the segs and bends from the R-tree.
|
self.connectivity.update_edge(
|
||||||
|
self.continent(from.into()).node_index(),
|
||||||
self.geometry_with_rtree.remove_dot(face.into());
|
band,
|
||||||
self.geometry_with_rtree.remove_dot(segbend.dot.into());
|
ConnectivityLabel::Band,
|
||||||
|
);
|
||||||
if let Some(outer) = maybe_outer {
|
BandIndex::new(band)
|
||||||
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))]
|
pub fn finish_band(&mut self, band: BandIndex, to: FixedDotIndex) {
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
self.connectivity.update_edge(
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
band.node_index(),
|
||||||
pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result<FixedDotIndex, Infringement> {
|
self.continent(to.into()).node_index(),
|
||||||
self.add_dot_infringably(weight, None)
|
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_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(
|
pub fn insert_segbend(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
|
|
@ -216,608 +68,51 @@ impl<R: RulesTrait> Layout<R> {
|
||||||
bend_weight: LooseBendWeight,
|
bend_weight: LooseBendWeight,
|
||||||
cw: bool,
|
cw: bool,
|
||||||
) -> Result<Segbend, LayoutException> {
|
) -> Result<Segbend, LayoutException> {
|
||||||
let maybe_wraparound = self.wraparoundable(around).wraparound();
|
self.drawing
|
||||||
let infringables = self.collect().wraparounded_bows(around);
|
.insert_segbend(from, around, dot_weight, seg_weight, bend_weight, cw)
|
||||||
|
|
||||||
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(
|
pub fn add_lone_loose_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
to: FixedDotIndex,
|
to: FixedDotIndex,
|
||||||
weight: LoneLooseSegWeight,
|
weight: LoneLooseSegWeight,
|
||||||
) -> Result<LoneLooseSegIndex, Infringement> {
|
) -> Result<LoneLooseSegIndex, Infringement> {
|
||||||
let seg = self.add_seg_infringably(from.into(), to.into(), weight, Some(&[]))?;
|
self.drawing.add_lone_loose_seg(from, to, weight)
|
||||||
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(
|
pub fn add_seq_loose_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
to: LooseDotIndex,
|
to: LooseDotIndex,
|
||||||
weight: SeqLooseSegWeight,
|
weight: SeqLooseSegWeight,
|
||||||
) -> Result<SeqLooseSegIndex, Infringement> {
|
) -> Result<SeqLooseSegIndex, Infringement> {
|
||||||
let seg = self.add_seg_infringably(from, to.into(), weight, Some(&[]))?;
|
self.drawing.add_seq_loose_seg(from, to, weight)
|
||||||
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> 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> {
|
pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> {
|
||||||
match dot {
|
self.drawing.move_dot(dot, to)
|
||||||
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()))]
|
pub fn band_from(&self, band: BandIndex) -> FixedDotIndex {
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
todo!()
|
||||||
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) {
|
pub fn band_to(&self, band: BandIndex) -> Option<FixedDotIndex> {
|
||||||
// Restore original state.
|
todo!()
|
||||||
self.geometry_with_rtree.move_dot(dot, old_pos);
|
|
||||||
return Err(infringement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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()))]
|
pub fn layout(&self) -> &Drawing<R> {
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
&self.drawing
|
||||||
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 continent(&self, dot: FixedDotIndex) -> ContinentIndex {
|
||||||
}
|
// TODO.
|
||||||
|
ContinentIndex::new(0.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 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> 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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,4 @@
|
||||||
#[macro_use]
|
pub mod connectivity;
|
||||||
pub mod graph;
|
|
||||||
pub mod bend;
|
|
||||||
pub mod collect;
|
|
||||||
pub mod dot;
|
|
||||||
pub mod guide;
|
|
||||||
mod layout;
|
mod layout;
|
||||||
pub mod loose;
|
|
||||||
pub mod primitive;
|
|
||||||
pub mod rules;
|
|
||||||
pub mod seg;
|
|
||||||
pub mod segbend;
|
|
||||||
|
|
||||||
pub use layout::*;
|
pub use layout::*;
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ pub mod astar;
|
||||||
pub mod draw;
|
pub mod draw;
|
||||||
pub mod graph;
|
pub mod graph;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod layout;
|
pub mod drawing;
|
||||||
pub mod board;
|
|
||||||
pub mod dsn;
|
pub mod dsn;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
|
pub mod layout;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
pub mod router;
|
pub mod router;
|
||||||
|
|
|
||||||
24
src/mesh.rs
24
src/mesh.rs
|
|
@ -7,18 +7,18 @@ use petgraph::visit::{self, NodeIndexable};
|
||||||
use petgraph::{stable_graph::NodeIndex, visit::EdgeRef};
|
use petgraph::{stable_graph::NodeIndex, visit::EdgeRef};
|
||||||
use spade::{HasPosition, InsertionError, Point2};
|
use spade::{HasPosition, InsertionError, Point2};
|
||||||
|
|
||||||
use crate::layout::rules::RulesTrait;
|
use crate::drawing::rules::RulesTrait;
|
||||||
use crate::triangulation::TriangulationEdgeReference;
|
use crate::triangulation::TriangulationEdgeReference;
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::shape::ShapeTrait,
|
drawing::{
|
||||||
graph::GetNodeIndex,
|
|
||||||
layout::{
|
|
||||||
bend::{FixedBendIndex, LooseBendIndex},
|
bend::{FixedBendIndex, LooseBendIndex},
|
||||||
dot::FixedDotIndex,
|
dot::FixedDotIndex,
|
||||||
graph::{GeometryIndex, MakePrimitive},
|
graph::{GeometryIndex, MakePrimitive},
|
||||||
primitive::{GetCore, MakeShape, Primitive},
|
primitive::{GetCore, MakeShape, Primitive},
|
||||||
Layout,
|
Drawing,
|
||||||
},
|
},
|
||||||
|
geometry::shape::ShapeTrait,
|
||||||
|
graph::GetNodeIndex,
|
||||||
triangulation::{GetVertexIndex, Triangulation},
|
triangulation::{GetVertexIndex, Triangulation},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -83,7 +83,7 @@ pub struct Mesh {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mesh {
|
impl Mesh {
|
||||||
pub fn new(layout: &Layout<impl RulesTrait>) -> Self {
|
pub fn new(layout: &Drawing<impl RulesTrait>) -> Self {
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
triangulation: Triangulation::new(layout),
|
triangulation: Triangulation::new(layout),
|
||||||
vertex_to_triangulation_vertex: Vec::new(),
|
vertex_to_triangulation_vertex: Vec::new(),
|
||||||
|
|
@ -93,9 +93,9 @@ impl Mesh {
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(&mut self, layout: &Layout<impl RulesTrait>) -> Result<(), InsertionError> {
|
pub fn generate(&mut self, drawing: &Drawing<impl RulesTrait>) -> Result<(), InsertionError> {
|
||||||
for node in layout.nodes() {
|
for node in drawing.nodes() {
|
||||||
let center = node.primitive(layout).shape().center();
|
let center = node.primitive(drawing).shape().center();
|
||||||
|
|
||||||
match node {
|
match node {
|
||||||
GeometryIndex::FixedDot(dot) => {
|
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.
|
// Add rails as vertices. This is how the mesh differs from the triangulation.
|
||||||
match node {
|
match node {
|
||||||
GeometryIndex::LooseBend(bend) => {
|
GeometryIndex::LooseBend(bend) => {
|
||||||
self.triangulation
|
self.triangulation
|
||||||
.weight_mut(layout.primitive(bend).core().into())
|
.weight_mut(drawing.primitive(bend).core().into())
|
||||||
.rails
|
.rails
|
||||||
.push(bend.into());
|
.push(bend.into());
|
||||||
self.vertex_to_triangulation_vertex[bend.node_index().index()] =
|
self.vertex_to_triangulation_vertex[bend.node_index().index()] =
|
||||||
Some(layout.primitive(bend).core().into());
|
Some(drawing.primitive(bend).core().into());
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,16 @@ use spade::InsertionError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::astar::{astar, AstarStrategy, PathTracker};
|
use crate::astar::{astar, AstarStrategy, PathTracker};
|
||||||
use crate::board::connectivity::BandIndex;
|
|
||||||
use crate::board::Board;
|
|
||||||
use crate::draw::DrawException;
|
use crate::draw::DrawException;
|
||||||
use crate::geometry::shape::ShapeTrait;
|
use crate::drawing::{
|
||||||
use crate::layout::{
|
|
||||||
dot::FixedDotIndex,
|
dot::FixedDotIndex,
|
||||||
graph::{GeometryIndex, MakePrimitive},
|
graph::{GeometryIndex, MakePrimitive},
|
||||||
primitive::MakeShape,
|
primitive::MakeShape,
|
||||||
rules::RulesTrait,
|
rules::RulesTrait,
|
||||||
};
|
};
|
||||||
|
use crate::geometry::shape::ShapeTrait;
|
||||||
|
use crate::layout::connectivity::BandIndex;
|
||||||
|
use crate::layout::Layout;
|
||||||
|
|
||||||
use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex};
|
use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex};
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ pub trait RouterObserverTrait<R: RulesTrait> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Router<R: RulesTrait> {
|
pub struct Router<R: RulesTrait> {
|
||||||
pub board: Board<R>,
|
pub layout: Layout<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RouterAstarStrategy<'a, RO: RouterObserverTrait<R>, R: RulesTrait> {
|
struct RouterAstarStrategy<'a, RO: RouterObserverTrait<R>, R: RulesTrait> {
|
||||||
|
|
@ -99,14 +99,14 @@ impl<'a, RO: RouterObserverTrait<R>, R: RulesTrait> AstarStrategy<&Mesh, f64>
|
||||||
return None;
|
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 width = self.trace.width;
|
||||||
let result = self.tracer.step(&mut self.trace, edge.target(), width);
|
let result = self.tracer.step(&mut self.trace, edge.target(), width);
|
||||||
self.observer
|
self.observer
|
||||||
.on_probe(&self.tracer, &self.trace, edge, result);
|
.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() {
|
if result.is_ok() {
|
||||||
self.tracer.undo_step(&mut self.trace);
|
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 {
|
fn estimate_cost(&mut self, vertex: VertexIndex) -> f64 {
|
||||||
self.observer.on_estimate(&self.tracer, vertex);
|
self.observer.on_estimate(&self.tracer, vertex);
|
||||||
let start_point = GeometryIndex::from(vertex)
|
let start_point = GeometryIndex::from(vertex)
|
||||||
.primitive(self.tracer.board.layout())
|
.primitive(self.tracer.layout.layout())
|
||||||
.shape()
|
.shape()
|
||||||
.center();
|
.center();
|
||||||
let end_point = self
|
let end_point = self
|
||||||
.tracer
|
.tracer
|
||||||
.board
|
.layout
|
||||||
.layout()
|
.layout()
|
||||||
.primitive(self.to)
|
.primitive(self.to)
|
||||||
.shape()
|
.shape()
|
||||||
|
|
@ -134,8 +134,8 @@ impl<'a, RO: RouterObserverTrait<R>, R: RulesTrait> AstarStrategy<&Mesh, f64>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: RulesTrait> Router<R> {
|
impl<R: RulesTrait> Router<R> {
|
||||||
pub fn new(board: Board<R>) -> Self {
|
pub fn new(layout: Layout<R>) -> Self {
|
||||||
Router { board }
|
Router { layout }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn route_band(
|
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
|
// XXX: Should we actually store the mesh? May be useful for debugging, but doesn't look
|
||||||
// right.
|
// right.
|
||||||
//self.mesh.triangulate(&self.layout)?;
|
//self.mesh.triangulate(&self.layout)?;
|
||||||
let mut mesh = Mesh::new(self.board.layout());
|
let mut mesh = Mesh::new(self.layout.layout());
|
||||||
mesh.generate(self.board.layout())
|
mesh.generate(self.layout.layout())
|
||||||
.map_err(|err| RoutingError {
|
.map_err(|err| RoutingError {
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
|
|
@ -181,14 +181,14 @@ impl<R: RulesTrait> Router<R> {
|
||||||
width: f64,
|
width: f64,
|
||||||
observer: &mut impl RouterObserverTrait<R>,
|
observer: &mut impl RouterObserverTrait<R>,
|
||||||
) -> Result<BandIndex, RoutingError> {
|
) -> Result<BandIndex, RoutingError> {
|
||||||
let from_dot = self.board.band_from(band);
|
let from_dot = self.layout.band_from(band);
|
||||||
let to_dot = self.board.band_to(band).unwrap();
|
let to_dot = self.layout.band_to(band).unwrap();
|
||||||
self.board.remove_band(band);
|
self.layout.remove_band(band);
|
||||||
self.board.move_dot(to_dot.into(), to).unwrap(); // TODO: Remove `.unwrap()`.
|
self.layout.move_dot(to_dot.into(), to).unwrap(); // TODO: Remove `.unwrap()`.
|
||||||
self.route_band(from_dot, to_dot, width, observer)
|
self.route_band(from_dot, to_dot, width, observer)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tracer<'a>(&'a mut self, mesh: &'a Mesh) -> Tracer<R> {
|
pub fn tracer<'a>(&'a mut self, mesh: &'a Mesh) -> Tracer<R> {
|
||||||
Tracer::new(&mut self.board, mesh)
|
Tracer::new(&mut self.layout, mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
use contracts::debug_ensures;
|
use contracts::debug_ensures;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
board::{connectivity::BandIndex, Board},
|
|
||||||
draw::{Draw, DrawException},
|
draw::{Draw, DrawException},
|
||||||
layout::{
|
drawing::{
|
||||||
bend::LooseBendIndex,
|
bend::LooseBendIndex,
|
||||||
dot::FixedDotIndex,
|
dot::FixedDotIndex,
|
||||||
graph::{GetNet, MakePrimitive},
|
graph::{GetNet, MakePrimitive},
|
||||||
guide::{BareHead, Head, HeadTrait, SegbendHead},
|
guide::{BareHead, Head, HeadTrait, SegbendHead},
|
||||||
rules::RulesTrait,
|
rules::RulesTrait,
|
||||||
},
|
},
|
||||||
|
layout::{connectivity::BandIndex, Layout},
|
||||||
mesh::{Mesh, VertexIndex},
|
mesh::{Mesh, VertexIndex},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -22,17 +22,17 @@ pub struct Trace {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Tracer<'a, R: RulesTrait> {
|
pub struct Tracer<'a, R: RulesTrait> {
|
||||||
pub board: &'a mut Board<R>,
|
pub layout: &'a mut Layout<R>,
|
||||||
pub mesh: &'a Mesh,
|
pub mesh: &'a Mesh,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: RulesTrait> Tracer<'a, R> {
|
impl<'a, R: RulesTrait> Tracer<'a, R> {
|
||||||
pub fn new(board: &'a mut Board<R>, mesh: &'a Mesh) -> Self {
|
pub fn new(layout: &'a mut Layout<R>, mesh: &'a Mesh) -> Self {
|
||||||
Tracer { board, mesh }
|
Tracer { layout, mesh }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&mut self, from: FixedDotIndex, width: f64) -> Trace {
|
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 {
|
Trace {
|
||||||
path: vec![from.into()],
|
path: vec![from.into()],
|
||||||
head: BareHead { dot: from }.into(),
|
head: BareHead { dot: from }.into(),
|
||||||
|
|
@ -48,7 +48,7 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Result<(), DrawException> {
|
) -> Result<(), DrawException> {
|
||||||
self.draw().finish_in_dot(trace.head, into, width)?;
|
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())]
|
#[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> {
|
fn draw(&mut self) -> Draw<R> {
|
||||||
Draw::new(&mut self.board)
|
Draw::new(&mut self.layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ use petgraph::visit::{self, NodeIndexable};
|
||||||
use spade::{handles::FixedVertexHandle, DelaunayTriangulation, HasPosition, InsertionError};
|
use spade::{handles::FixedVertexHandle, DelaunayTriangulation, HasPosition, InsertionError};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
drawing::{rules::RulesTrait, Drawing},
|
||||||
graph::GetNodeIndex,
|
graph::GetNodeIndex,
|
||||||
layout::{rules::RulesTrait, Layout},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait GetVertexIndex<I> {
|
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>>
|
impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>>
|
||||||
Triangulation<I, W>
|
Triangulation<I, W>
|
||||||
{
|
{
|
||||||
pub fn new(layout: &Layout<impl RulesTrait>) -> Self {
|
pub fn new(layout: &Drawing<impl RulesTrait>) -> Self {
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
triangulation: <DelaunayTriangulation<W> as spade::Triangulation>::new(),
|
triangulation: <DelaunayTriangulation<W> as spade::Triangulation>::new(),
|
||||||
vertex_to_handle: Vec::new(),
|
vertex_to_handle: Vec::new(),
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@ use enum_dispatch::enum_dispatch;
|
||||||
use petgraph::stable_graph::NodeIndex;
|
use petgraph::stable_graph::NodeIndex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
graph::GetNodeIndex,
|
drawing::{
|
||||||
layout::{
|
|
||||||
bend::{BendIndex, FixedBendIndex, LooseBendIndex},
|
bend::{BendIndex, FixedBendIndex, LooseBendIndex},
|
||||||
dot::FixedDotIndex,
|
dot::FixedDotIndex,
|
||||||
graph::{GeometryIndex, MakePrimitive},
|
graph::{GeometryIndex, MakePrimitive},
|
||||||
primitive::{FixedBend, FixedDot, GetFirstRail, GetInnerOuter, LooseBend, Primitive},
|
primitive::{FixedBend, FixedDot, GetFirstRail, GetInnerOuter, LooseBend, Primitive},
|
||||||
rules::RulesTrait,
|
rules::RulesTrait,
|
||||||
Layout,
|
Drawing,
|
||||||
},
|
},
|
||||||
|
graph::GetNodeIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
|
|
@ -53,11 +53,11 @@ pub enum Wraparoundable<'a, R: RulesTrait> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: RulesTrait> Wraparoundable<'a, R> {
|
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 {
|
match index {
|
||||||
WraparoundableIndex::FixedDot(dot) => layout.primitive(dot).into(),
|
WraparoundableIndex::FixedDot(dot) => drawing.primitive(dot).into(),
|
||||||
WraparoundableIndex::FixedBend(bend) => layout.primitive(bend).into(),
|
WraparoundableIndex::FixedBend(bend) => drawing.primitive(bend).into(),
|
||||||
WraparoundableIndex::LooseBend(bend) => layout.primitive(bend).into(),
|
WraparoundableIndex::LooseBend(bend) => drawing.primitive(bend).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue