From 68c286378423ea8c70cf717b90855f59046a13fa Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Tue, 25 Jul 2023 04:08:06 +0200 Subject: [PATCH] Implement basic shoving --- src/graph.rs | 4 +- src/layout.rs | 101 +++++++++++++++++++++++++++++++++++++++++------ src/main.rs | 41 ++++++++++++++++--- src/mesh.rs | 55 +++++++++++++++++--------- src/primitive.rs | 45 ++++++++++++++------- src/stretch.rs | 85 ++++++++++++++------------------------- src/weight.rs | 2 - 7 files changed, 223 insertions(+), 110 deletions(-) delete mode 100644 src/weight.rs diff --git a/src/graph.rs b/src/graph.rs index db6109e..26b3ab0 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -4,10 +4,10 @@ use petgraph::stable_graph::NodeIndex; use crate::math::Circle; -pub trait Set { +pub trait Path { fn interior(&self) -> Vec; fn closure(&self) -> Vec; - fn boundary(&self) -> Vec; + fn ends(&self) -> [DotIndex; 2]; } #[derive(Debug, EnumAsInner, Clone, Copy, PartialEq)] diff --git a/src/layout.rs b/src/layout.rs index 1e3ed23..0b588ad 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -4,7 +4,7 @@ use geo::geometry::Point; use crate::math::Circle; use crate::mesh::Mesh; -use crate::graph::{TaggedIndex, DotIndex, SegIndex, BendIndex}; +use crate::graph::{TaggedIndex, DotIndex, SegIndex, BendIndex, Path}; use crate::rules::{Rules, Conditions}; use crate::shape::Shape; use crate::graph::{TaggedWeight, DotWeight, SegWeight, BendWeight}; @@ -29,10 +29,18 @@ impl Layout { } pub fn route_start(&mut self, from: DotIndex) -> Head { - Head {dot: from, bend: None} + Head {dot: from, bend: self.mesh.primitive(from).bend()} } - pub fn route_stop(&mut self, head: Head, to: DotIndex, width: f64) { + pub fn route_finish(&mut self, head: Head, to: DotIndex, width: f64) { + if let Some(bend) = self.mesh.primitive(to).bend() { + self.route_finish_in_bend(head, bend, to, width); + } else { + self.route_finish_in_dot(head, to, width); + } + } + + fn route_finish_in_dot(&mut self, head: Head, to: DotIndex, width: f64) { let from_circle = self.head_guidecircle(&head, width); let conditions = Conditions { @@ -54,6 +62,37 @@ impl Layout { self.add_seg(head.dot, to, width); } + fn route_finish_in_bend(&mut self, head: Head, to_bend: BendIndex, to: DotIndex, width: f64) { + let from_circle = self.head_guidecircle(&head, width); + + let conditions = Conditions { + lower_net: None, + higher_net: None, + layer: None, + zone: None, + }; + + let to_circle = self.bend_circle(to_bend); + let from_cw = self.head_cw(&head); + + let to_head = Head {bend: Some(to_bend), dot: to}; + let to_cw = self.head_cw(&to_head); + + let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, to_cw); + let head = self.extend_head(head, tangent_points.0); + + let to_head = self.extend_head(to_head, tangent_points.1); + self.add_seg(head.dot, to, width); + } + + pub fn shove_around_dot(&mut self, head: Head, around: DotIndex, cw: bool, width: f64) -> Head { + let outer = self.mesh.primitive(around).outer().unwrap(); + let head = self.route_around_dot(head, around, cw, width); + self.mesh.reattach_bend(outer, head.bend.unwrap()); + self.displace_outers(head.bend.unwrap()); + head + } + pub fn route_around_dot(&mut self, head: Head, around: DotIndex, cw: bool, width: f64) -> Head { let from_circle = self.head_guidecircle(&head, width); @@ -73,6 +112,14 @@ impl Layout { self.route_seg_bend(head, TaggedIndex::Dot(around), tangent_points.1, cw, width) } + pub fn shove_around_bend(&mut self, head: Head, around: BendIndex, cw: bool, width: f64) -> Head { + let outer = self.mesh.primitive(around).outer().unwrap(); + let head = self.route_around_bend(head, around, cw, width); + self.mesh.reattach_bend(outer, head.bend.unwrap()); + self.displace_outers(head.bend.unwrap()); + head + } + pub fn route_around_bend(&mut self, head: Head, around: BendIndex, cw: bool, width: f64) -> Head { let from_circle = self.head_guidecircle(&head, width); @@ -101,6 +148,36 @@ impl Layout { Head {dot: bend_to, bend: Some(bend)} } + fn displace_outers(&mut self, bend: BendIndex) { + let mut endss: Vec<[DotIndex; 2]> = vec![]; + let mut interiors: Vec> = vec![]; + let cw = self.mesh.primitive(bend).weight().cw; + + let mut cur_bend = bend; + while let Some(outer) = self.mesh.primitive(cur_bend).outer() { + let stretch = self.mesh.stretch(outer); + endss.push(stretch.ends()); + interiors.push(stretch.interior()); + cur_bend = outer; + } + + for interior in interiors { + self.mesh.remove_open_set(interior); + } + + let mut cur_bend = bend; + for ends in endss { + let head = self.route_start(ends[0]); + //let width = self.mesh.primitive(head.dot).weight().circle.r * 2.0; + let width = 5.0; + + let head = self.route_around_bend(head, cur_bend, cw, width); + cur_bend = head.bend.unwrap(); + + self.route_finish(head, ends[1], width); + } + } + fn route_seg(&mut self, head: Head, to: Point, width: f64) -> Head { let net = self.mesh.primitive(head.dot).weight().net; @@ -110,7 +187,7 @@ impl Layout { net, circle: Circle {pos: to, r: width / 2.0}, }); - self.mesh.add_seg(head.dot, to_index, SegWeight {net, width}); + self.add_seg(head.dot, to_index, width); Head {dot: to_index, bend: None} } @@ -154,8 +231,8 @@ impl Layout { } } - fn bend_guidecircle(&self, bend: BendIndex, width: f64, conditions: Conditions) -> Circle { - let mut r = width + self.rules.ruleset(conditions).clearance.min; + fn bend_circle(&self, bend: BendIndex) -> Circle { + let mut r = 0.0; let mut layer = bend; while let Some(inner) = self.mesh.primitive(layer).inner() { @@ -166,10 +243,16 @@ impl Layout { let core_circle = self.mesh.primitive(self.mesh.primitive(bend).core().unwrap()).weight().circle; Circle { pos: core_circle.pos, - r: core_circle.r + r + 15.0 + r: core_circle.r + r } } + fn bend_guidecircle(&self, bend: BendIndex, width: f64, conditions: Conditions) -> Circle { + let mut circle = self.bend_circle(bend); + circle.r += width + self.rules.ruleset(conditions).clearance.min + 15.0; + circle + } + fn extend_head(&mut self, head: Head, to: Point) -> Head { if let Some(..) = head.bend { self.extend_head_bend(head, to) @@ -191,10 +274,6 @@ impl Layout { self.mesh.add_dot(weight) } - pub fn remove_dot(&mut self, index: DotIndex) { - self.mesh.remove_dot(index); - } - pub fn add_seg(&mut self, from: DotIndex, to: DotIndex, width: f64) -> SegIndex { let net = self.mesh.primitive(from).weight().net; self.mesh.add_seg(from, to, SegWeight {net, width}) diff --git a/src/main.rs b/src/main.rs index 7f1196e..a862813 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ mod mesh; mod stretch; mod primitive; mod shape; -mod weight; mod math; use std::time::Duration; @@ -38,7 +37,8 @@ fn main() { let mut event_pump = sdl_context.event_pump().unwrap(); let mut i = 0; let mut layout = Layout::new(); - + + /*let index = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (150.5, 80.5).into(), r: 8.0}}); //layout.route_seg(index, Point {x: 400.5, y: 350.5}, 6.0); @@ -56,7 +56,8 @@ fn main() { let index6 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (140.5, 300.5).into(), r: 8.0}}); let index7 = layout.route_to(index5, index6, 5.0);*/ - let dot1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (100.5, 150.5).into(), r: 8.0}}); + + /*let dot1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (100.5, 150.5).into(), r: 8.0}}); let dot2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (130.5, 150.5).into(), r: 8.0}}); let dot3 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (160.5, 150.5).into(), r: 8.0}}); @@ -72,7 +73,7 @@ fn main() { let head = layout.route_around_dot(head, obstacle_dot1, true, 5.0); let dot3_1 = head.dot; let bend3_1 = head.bend.unwrap(); - layout.route_stop(head, dot4, 5.0); + layout.route_finish(head, dot4, 5.0); let head = layout.route_start(dot2); let head = layout.route_around_dot(head, dot3, true, 5.0); @@ -81,12 +82,40 @@ fn main() { let head = layout.route_around_bend(head, bend3_1, true, 5.0); let dot2_2 = head.dot; let bend2_2 = head.bend.unwrap(); - layout.route_stop(head, dot5, 5.0); + layout.route_finish(head, dot5, 5.0); let head = layout.route_start(dot1); let head = layout.route_around_bend(head, bend2_1, true, 5.0); let head = layout.route_around_bend(head, bend2_2, true, 5.0); - layout.route_stop(head, dot6, 5.0); + layout.route_finish(head, dot6, 5.0);*/ + + + let dot1_1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (200.5, 200.5).into(), r: 8.0}}); + let dot2_1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (230.5, 230.5).into(), r: 8.0}}); + let dot3_1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (260.5, 260.5).into(), r: 8.0}}); + + let dot1_2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (500.5, 200.5).into(), r: 8.0}}); + let dot2_2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (470.5, 230.5).into(), r: 8.0}}); + let dot3_2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (440.5, 260.5).into(), r: 8.0}}); + + let barrier_dot1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (350.5, 150.5).into(), r: 8.0}}); + let barrier_dot2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (350.5, 500.5).into(), r: 8.0}}); + layout.add_seg(barrier_dot1, barrier_dot2, 16.0); + + let head = layout.route_start(dot1_1); + let head = layout.route_around_dot(head, barrier_dot1, true, 5.0); + layout.route_finish(head, dot1_2, 5.0); + + let head = layout.route_start(dot2_1); + //let head = layout.route_around_dot(head, barrier_dot1, true, 5.0); + let head = layout.shove_around_dot(head, barrier_dot1, true, 5.0); + layout.route_finish(head, dot2_2, 5.0); + + let head = layout.route_start(dot3_1); + //let head = layout.route_around_dot(head, barrier_dot1, true, 5.0); + let head = layout.shove_around_dot(head, barrier_dot1, true, 5.0); + layout.route_finish(head, dot3_2, 5.0); + 'running: loop { i = (i + 1) % 255; diff --git a/src/mesh.rs b/src/mesh.rs index 03f6980..8ade1e0 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -1,11 +1,14 @@ use geo::Point; +use petgraph::Direction::Incoming; use petgraph::stable_graph::StableDiGraph; +use petgraph::visit::EdgeRef; use rstar::RTree; use rstar::primitives::GeomWithData; use crate::primitive::Primitive; use crate::shape::Shape; -use crate::graph::{Tag, TaggedIndex, DotIndex, SegIndex, BendIndex, Index, TaggedWeight, DotWeight, SegWeight, BendWeight, Label}; +use crate::graph::{Tag, TaggedIndex, DotIndex, SegIndex, BendIndex, Index, TaggedWeight, DotWeight, SegWeight, BendWeight, Label, Path}; +use crate::stretch::Stretch; pub type RTreeWrapper = GeomWithData; @@ -22,17 +25,33 @@ impl Mesh { } } + pub fn remove_open_set(&mut self, open_set: Vec) { + for index in open_set.iter().filter(|index| !index.is_dot()) { + untag!(index, self.remove(*index)); + } + + // We must remove the dots only after the segs and bends because we need dots to calculate + // the shapes, which we need to remove the segs and bends from the R-tree. + + for index in open_set.iter().filter(|index| index.is_dot()) { + untag!(index, self.remove(*index)); + } + } + + pub fn remove(&mut self, index: Index) { + // Unnecessary retag. It should be possible to elide it. + let weight = *self.graph.node_weight(index.index).unwrap(); + self.rtree.remove(&RTreeWrapper::new(self.primitive(index).shape(), index.retag(weight))); + + self.graph.remove_node(index.index); + } + pub fn add_dot(&mut self, weight: DotWeight) -> DotIndex { let dot = DotIndex::new(self.graph.add_node(TaggedWeight::Dot(weight))); self.rtree.insert(RTreeWrapper::new(self.primitive(dot).shape(), TaggedIndex::Dot(dot))); dot } - pub fn remove_dot(&mut self, dot: DotIndex) { - self.rtree.remove(&RTreeWrapper::new(self.primitive(dot).shape(), TaggedIndex::Dot(dot))); - self.graph.remove_node(dot.index); - } - pub fn add_seg(&mut self, from: DotIndex, to: DotIndex, weight: SegWeight) -> SegIndex { let seg = SegIndex::new(self.graph.add_node(TaggedWeight::Seg(weight))); self.graph.add_edge(from.index, seg.index, Label::End); @@ -42,11 +61,6 @@ impl Mesh { seg } - pub fn remove_seg(&mut self, seg: SegIndex) { - self.rtree.remove(&RTreeWrapper::new(self.primitive(seg).shape(), TaggedIndex::Seg(seg))); - self.graph.remove_node(seg.index); - } - pub fn add_bend(&mut self, from: DotIndex, to: DotIndex, around: TaggedIndex, weight: BendWeight) -> BendIndex { match around { TaggedIndex::Dot(core) => @@ -79,9 +93,14 @@ impl Mesh { bend } - pub fn remove_bend(&mut self, bend: BendIndex) { - self.rtree.remove(&RTreeWrapper::new(self.primitive(bend).shape(), TaggedIndex::Bend(bend))); - self.graph.remove_node(bend.index); + pub fn reattach_bend(&mut self, bend: BendIndex, inner: BendIndex) { + if let Some(old_inner_edge) = self.graph.edges_directed(bend.index, Incoming) + .filter(|edge| *edge.weight() == Label::Outer) + .next() + { + self.graph.remove_edge(old_inner_edge.id()); + } + self.graph.add_edge(inner.index, bend.index, Label::Outer); } pub fn extend_bend(&mut self, bend: BendIndex, dot: DotIndex, to: Point) { @@ -95,10 +114,6 @@ impl Mesh { self.insert_into_rtree(dot.tag()); self.insert_into_rtree(bend.tag()); } - - pub fn reoffset_bend(&mut self, bend: BendIndex, offset: f64) { - - } pub fn nodes(&self) -> impl Iterator + '_ { self.rtree.iter().map(|wrapper| wrapper.data) @@ -108,6 +123,10 @@ impl Mesh { Primitive::new(index, &self.graph) } + pub fn stretch(&self, bend: BendIndex) -> Stretch { + Stretch::new(bend, &self.graph) + } + fn insert_into_rtree(&mut self, index: TaggedIndex) { let shape = untag!(index, self.primitive(index).shape()); self.rtree.insert(RTreeWrapper::new(shape, index)); diff --git a/src/primitive.rs b/src/primitive.rs index 373c08f..1ec2c28 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -3,7 +3,7 @@ use std::mem::swap; use petgraph::Direction::{Outgoing, Incoming}; use petgraph::stable_graph::StableDiGraph; -use crate::graph::{Set, DotIndex, SegIndex, BendIndex, TaggedIndex, Tag, Index, DotWeight, SegWeight, BendWeight, TaggedWeight, Label}; +use crate::graph::{Path, DotIndex, SegIndex, BendIndex, TaggedIndex, Tag, Index, DotWeight, SegWeight, BendWeight, TaggedWeight, Label}; use crate::shape::Shape; pub struct Primitive<'a, Weight> { @@ -17,7 +17,6 @@ impl<'a, Weight> Primitive<'a, Weight> { } pub fn shape(&self) -> Shape { - let ends = self.ends(); match self.tagged_weight() { TaggedWeight::Dot(dot) => Shape { width: dot.circle.r * 2.0, @@ -26,6 +25,7 @@ impl<'a, Weight> Primitive<'a, Weight> { center: None, }, TaggedWeight::Seg(seg) => { + let ends = self.ends(); Shape { width: seg.width, from: self.primitive(ends[0]).weight().circle.pos, @@ -34,6 +34,7 @@ impl<'a, Weight> Primitive<'a, Weight> { } } TaggedWeight::Bend(bend) => { + let ends = self.ends(); let mut shape = Shape { width: self.primitive(ends[0]).weight().circle.r * 2.0, from: self.primitive(ends[0]).weight().circle.pos, @@ -51,26 +52,18 @@ impl<'a, Weight> Primitive<'a, Weight> { pub fn next(&self) -> Option { self.graph.neighbors_directed(self.index.index, Outgoing) - .filter(|ni| self.graph.edge_weight(self.graph.find_edge(*ni, self.index.index).unwrap()).unwrap().is_end()) + .filter(|ni| self.graph.edge_weight(self.graph.find_edge(self.index.index, *ni).unwrap()).unwrap().is_end()) .map(|ni| Index::