layout: fix misalignment of shifted bends

This commit is contained in:
Mikolaj Wielgus 2024-02-08 00:00:24 +00:00
parent 850941715e
commit 7fdf90b126
5 changed files with 118 additions and 8 deletions

View File

@ -17,6 +17,8 @@ use crate::{
use petgraph::stable_graph::NodeIndex; use petgraph::stable_graph::NodeIndex;
use super::geometry::SetOffset;
#[enum_dispatch(GetNodeIndex, MakePrimitive)] #[enum_dispatch(GetNodeIndex, MakePrimitive)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum BendIndex { pub enum BendIndex {
@ -45,7 +47,7 @@ impl TryFrom<GeometryIndex> for BendIndex {
} }
} }
#[enum_dispatch(GetOffset, GetWidth)] #[enum_dispatch(GetOffset, SetOffset, GetWidth)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum BendWeight { pub enum BendWeight {
Fixed(FixedBendWeight), 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 { impl GetWidth for FixedBendWeight {
fn width(&self) -> f64 { fn width(&self) -> f64 {
self.width 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 { impl GetWidth for LooseBendWeight {
fn width(&self) -> f64 { fn width(&self) -> f64 {
self.width self.width

View File

@ -39,6 +39,11 @@ pub trait GetOffset {
fn offset(&self) -> f64; fn offset(&self) -> f64;
} }
#[enum_dispatch]
pub trait SetOffset {
fn set_offset(&mut self, offset: f64);
}
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum GeometryLabel { pub enum GeometryLabel {
Connection, Connection,
@ -48,7 +53,7 @@ pub enum GeometryLabel {
pub trait DotWeightTrait<GW>: GetPos + SetPos + GetWidth + Into<GW> + Copy {} pub trait DotWeightTrait<GW>: GetPos + SetPos + GetWidth + Into<GW> + Copy {}
pub trait SegWeightTrait<GW>: GetWidth + Into<GW> + Copy {} pub trait SegWeightTrait<GW>: GetWidth + Into<GW> + Copy {}
pub trait BendWeightTrait<GW>: GetOffset + GetWidth + Into<GW> + Copy {} pub trait BendWeightTrait<GW>: GetOffset + SetOffset + GetWidth + Into<GW> + Copy {}
#[derive(Debug)] #[derive(Debug)]
pub struct Geometry< pub struct Geometry<
@ -152,7 +157,13 @@ impl<
pub fn move_dot(&mut self, dot: DI, to: Point) { pub fn move_dot(&mut self, dot: DI, to: Point) {
let mut weight = self.dot_weight(dot); let mut weight = self.dot_weight(dot);
weight.set_pos(to); 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) { pub fn flip_bend(&mut self, bend: BI) {

View File

@ -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) { pub fn flip_bend(&mut self, bend: BI) {
// Does not affect the bbox because it covers the whole guidecircle. // Does not affect the bbox because it covers the whole guidecircle.
self.geometry.flip_bend(bend); self.geometry.flip_bend(bend);
} }
pub fn reattach_bend(&mut self, bend: BI, maybe_new_inner: Option<BI>) { pub fn reattach_bend(&mut self, bend: BI, maybe_new_inner: Option<BI>) {
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.rtree.remove(&self.make_bend_bbox(bend));
self.geometry.reattach_bend(bend, maybe_new_inner); self.geometry.reattach_bend(bend, maybe_new_inner);
self.rtree.insert(self.make_bend_bbox(bend)); 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;
}
} }
} }

View File

@ -20,7 +20,8 @@ use crate::graph::{GenericIndex, GetNodeIndex};
use crate::layout::bend::BendIndex; use crate::layout::bend::BendIndex;
use crate::layout::dot::DotWeight; use crate::layout::dot::DotWeight;
use crate::layout::geometry::{ 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::guide::Guide;
use crate::layout::rules::{Conditions, GetConditions}; use crate::layout::rules::{Conditions, GetConditions};
@ -436,6 +437,12 @@ impl<R: RulesTrait> Layout<R> {
self.primitive(rail).width(), self.primitive(rail).width(),
)? )?
.end_point(); .end_point();
let offset = guide.head_around_bend_offset(
&from_head.into(),
inner.into(),
self.primitive(rail).width(),
);
self.move_dot_infringably( self.move_dot_infringably(
joints.0.into(), joints.0.into(),
from, from,
@ -446,6 +453,14 @@ impl<R: RulesTrait> Layout<R> {
to, to,
&self.inner_bow_and_outer_bows(rail), &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 { } else {
let core = rail_primitive.core(); let core = rail_primitive.core();
let from = guide let from = guide
@ -464,6 +479,12 @@ impl<R: RulesTrait> Layout<R> {
self.primitive(rail).width(), self.primitive(rail).width(),
)? )?
.end_point(); .end_point();
let offset = guide.head_around_dot_offset(
&from_head.into(),
core.into(),
self.primitive(rail).width(),
);
self.move_dot_infringably( self.move_dot_infringably(
joints.0.into(), joints.0.into(),
from, from,
@ -474,6 +495,12 @@ impl<R: RulesTrait> Layout<R> {
to, to,
&self.inner_bow_and_outer_bows(rail), &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(); maybe_rail = self.primitive(rail).outer();
@ -834,6 +861,30 @@ impl<R: RulesTrait> Layout<R> {
Ok(()) 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().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()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
fn detect_infringement_except( fn detect_infringement_except(

View File

@ -243,10 +243,10 @@ fn main() -> Result<(), anyhow::Error> {
let _i = 0; let _i = 0;
let mut router = Router::new(SimpleRules { let mut router = Router::new(SimpleRules {
net_clearances: HashMap::from([ net_clearances: HashMap::from([
((1, 2), 5.0), ((1, 2), 8.0),
((2, 1), 5.0), ((2, 1), 8.0),
((2, 3), 10.0), ((2, 3), 3.0),
((3, 2), 10.0), ((3, 2), 3.0),
((3, 4), 15.0), ((3, 4), 15.0),
((4, 3), 15.0), ((4, 3), 15.0),
]), ]),