From 7fdf90b1262da37793346e51bb22a0dd23147872 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Thu, 8 Feb 2024 00:00:24 +0000 Subject: [PATCH] layout: fix misalignment of shifted bends --- src/layout/bend.rs | 16 +++++++++- src/layout/geometry/geometry.rs | 15 +++++++-- src/layout/geometry/with_rtree.rs | 34 ++++++++++++++++++++ src/layout/layout.rs | 53 ++++++++++++++++++++++++++++++- src/main.rs | 8 ++--- 5 files changed, 118 insertions(+), 8 deletions(-) diff --git a/src/layout/bend.rs b/src/layout/bend.rs index 9720295..15c4a46 100644 --- a/src/layout/bend.rs +++ b/src/layout/bend.rs @@ -17,6 +17,8 @@ use crate::{ use petgraph::stable_graph::NodeIndex; +use super::geometry::SetOffset; + #[enum_dispatch(GetNodeIndex, MakePrimitive)] #[derive(Debug, Clone, Copy, PartialEq)] pub enum BendIndex { @@ -45,7 +47,7 @@ impl TryFrom for BendIndex { } } -#[enum_dispatch(GetOffset, GetWidth)] +#[enum_dispatch(GetOffset, SetOffset, GetWidth)] #[derive(Debug, Clone, Copy, PartialEq)] pub enum BendWeight { Fixed(FixedBendWeight), @@ -91,6 +93,12 @@ impl GetOffset for FixedBendWeight { } } +impl SetOffset for FixedBendWeight { + fn set_offset(&mut self, offset: f64) { + self.offset = offset + } +} + impl GetWidth for FixedBendWeight { fn width(&self) -> f64 { self.width @@ -110,6 +118,12 @@ impl GetOffset for LooseBendWeight { } } +impl SetOffset for LooseBendWeight { + fn set_offset(&mut self, offset: f64) { + self.offset = offset + } +} + impl GetWidth for LooseBendWeight { fn width(&self) -> f64 { self.width diff --git a/src/layout/geometry/geometry.rs b/src/layout/geometry/geometry.rs index 32cd8de..0f31ce1 100644 --- a/src/layout/geometry/geometry.rs +++ b/src/layout/geometry/geometry.rs @@ -39,6 +39,11 @@ pub trait GetOffset { fn offset(&self) -> f64; } +#[enum_dispatch] +pub trait SetOffset { + fn set_offset(&mut self, offset: f64); +} + #[derive(Debug, Clone, Copy, PartialEq)] pub enum GeometryLabel { Connection, @@ -48,7 +53,7 @@ pub enum GeometryLabel { pub trait DotWeightTrait: GetPos + SetPos + GetWidth + Into + Copy {} pub trait SegWeightTrait: GetWidth + Into + Copy {} -pub trait BendWeightTrait: GetOffset + GetWidth + Into + Copy {} +pub trait BendWeightTrait: GetOffset + SetOffset + GetWidth + Into + Copy {} #[derive(Debug)] pub struct Geometry< @@ -152,7 +157,13 @@ impl< pub fn move_dot(&mut self, dot: DI, to: Point) { let mut weight = self.dot_weight(dot); weight.set_pos(to); - *self.graph.node_weight_mut(dot.node_index()).unwrap() = weight.into() + *self.graph.node_weight_mut(dot.node_index()).unwrap() = weight.into(); + } + + pub fn shift_bend(&mut self, bend: BI, offset: f64) { + let mut weight = self.bend_weight(bend); + weight.set_offset(offset); + *self.graph.node_weight_mut(bend.node_index()).unwrap() = weight.into(); } pub fn flip_bend(&mut self, bend: BI) { diff --git a/src/layout/geometry/with_rtree.rs b/src/layout/geometry/with_rtree.rs index 45e5de7..6c298f1 100644 --- a/src/layout/geometry/with_rtree.rs +++ b/src/layout/geometry/with_rtree.rs @@ -159,15 +159,49 @@ impl< } } + pub fn shift_bend(&mut self, bend: BI, offset: f64) { + let mut rail = bend; + + while let Some(outer) = self.geometry.outer(rail) { + self.rtree.remove(&self.make_bend_bbox(outer)); + rail = outer; + } + + self.rtree.remove(&self.make_bend_bbox(bend)); + self.geometry.shift_bend(bend, offset); + self.rtree.insert(self.make_bend_bbox(bend)); + + rail = bend; + + while let Some(outer) = self.geometry.outer(rail) { + self.rtree.insert(self.make_bend_bbox(outer)); + rail = outer; + } + } + pub fn flip_bend(&mut self, bend: BI) { // Does not affect the bbox because it covers the whole guidecircle. self.geometry.flip_bend(bend); } pub fn reattach_bend(&mut self, bend: BI, maybe_new_inner: Option) { + let mut rail = bend; + + while let Some(outer) = self.geometry.outer(rail) { + self.rtree.remove(&self.make_bend_bbox(outer)); + rail = outer; + } + self.rtree.remove(&self.make_bend_bbox(bend)); self.geometry.reattach_bend(bend, maybe_new_inner); self.rtree.insert(self.make_bend_bbox(bend)); + + rail = bend; + + while let Some(outer) = self.geometry.outer(rail) { + self.rtree.insert(self.make_bend_bbox(outer)); + rail = outer; + } } } diff --git a/src/layout/layout.rs b/src/layout/layout.rs index 3743a2c..002f1ff 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -20,7 +20,8 @@ use crate::graph::{GenericIndex, GetNodeIndex}; use crate::layout::bend::BendIndex; use crate::layout::dot::DotWeight; use crate::layout::geometry::{ - BendWeightTrait, DotWeightTrait, Geometry, GeometryLabel, GetPos, GetWidth, SegWeightTrait, + BendWeightTrait, DotWeightTrait, Geometry, GeometryLabel, GetOffset, GetPos, GetWidth, + SegWeightTrait, }; use crate::layout::guide::Guide; use crate::layout::rules::{Conditions, GetConditions}; @@ -436,6 +437,12 @@ impl Layout { 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, @@ -446,6 +453,14 @@ impl Layout { to, &self.inner_bow_and_outer_bows(rail), )?; + + self.shift_bend_infringably( + rail.into(), + offset, + &self.inner_bow_and_outer_bows(rail), + )?; + + // Update offsets in case the rule conditions changed. } else { let core = rail_primitive.core(); let from = guide @@ -464,6 +479,12 @@ impl Layout { 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, @@ -474,6 +495,12 @@ impl Layout { to, &self.inner_bow_and_outer_bows(rail), )?; + + self.shift_bend_infringably( + rail.into(), + offset, + &self.inner_bow_and_outer_bows(rail), + )?; } maybe_rail = self.primitive(rail).outer(); @@ -834,6 +861,30 @@ impl Layout { 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: &[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( diff --git a/src/main.rs b/src/main.rs index 3928c3d..07c6838 100644 --- a/src/main.rs +++ b/src/main.rs @@ -243,10 +243,10 @@ fn main() -> Result<(), anyhow::Error> { let _i = 0; let mut router = Router::new(SimpleRules { net_clearances: HashMap::from([ - ((1, 2), 5.0), - ((2, 1), 5.0), - ((2, 3), 10.0), - ((3, 2), 10.0), + ((1, 2), 8.0), + ((2, 1), 8.0), + ((2, 3), 3.0), + ((3, 2), 3.0), ((3, 4), 15.0), ((4, 3), 15.0), ]),