tracer: Add some initial code for squeezing/tucking

Not functional yet.
This commit is contained in:
Mikolaj Wielgus 2023-10-17 03:16:02 +00:00
parent ce72a2ba4b
commit c9d0b2178e
7 changed files with 332 additions and 71 deletions

View File

@ -127,26 +127,21 @@ impl<'a> Draw<'a> {
dirs = [false, true];
}
for (i, tangent) in [tangents.0, tangents.1].iter().enumerate() {
match self.segbend_around(
[tangents.0, tangents.1]
.iter()
.enumerate()
.find_map(|(i, tangent)| {
self.segbend_around(
head,
TaggedIndex::Dot(around),
tangent.start_point(),
tangent.end_point(),
dirs[i],
width,
) {
Ok(head) => {
return Ok(head);
}
Err(err) => {
if i >= 1 {
return Err(err);
}
}
}
}
unreachable!();
)
.ok()
})
.ok_or(())
}
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))]
@ -155,21 +150,33 @@ impl<'a> Draw<'a> {
&mut self,
mut head: Head,
around: BendIndex,
cw: bool,
width: f64,
) -> Result<SegbendHead, ()> {
let tangent = self
let mut tangents = self
.guide(&Default::default())
.head_around_bend_segment(&head, around, cw, width);
.head_around_bend_segments(&head, around, width);
let mut dirs = [true, false];
head = self.extend_head(head, tangent.start_point())?;
self.segbend(
if tangents.1.euclidean_length() < tangents.0.euclidean_length() {
tangents = (tangents.1, tangents.0);
dirs = [false, true];
}
[tangents.0, tangents.1]
.iter()
.enumerate()
.find_map(|(i, tangent)| {
self.segbend_around(
head,
TaggedIndex::Bend(around),
tangent.start_point(),
tangent.end_point(),
cw,
dirs[i],
width,
)
.ok()
})
.ok_or(())
}
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))]

View File

@ -34,20 +34,6 @@ impl<'a, 'b> Guide<'a, 'b> {
math::tangent_segment(from_circle, from_cw, to_circle, None)
}
pub fn head_around_bend_segment(
&self,
head: &Head,
around: BendIndex,
cw: bool,
width: f64,
) -> Line {
let from_circle = self.head_circle(head, width);
let to_circle = self.bend_circle(around, width);
let from_cw = self.head_cw(head);
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
}
pub fn head_around_dot_segments(
&self,
head: &Head,
@ -77,6 +63,35 @@ impl<'a, 'b> Guide<'a, 'b> {
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
}
pub fn head_around_bend_segments(
&self,
head: &Head,
around: BendIndex,
width: f64,
) -> (Line, Line) {
let from_circle = self.head_circle(head, width);
let to_circle = self.bend_circle(around, width);
let from_cw = self.head_cw(head);
let tangents: Vec<Line> =
math::tangent_segments(from_circle, from_cw, to_circle, None).collect();
(tangents[0], tangents[1])
}
pub fn head_around_bend_segment(
&self,
head: &Head,
around: BendIndex,
cw: bool,
width: f64,
) -> Line {
let from_circle = self.head_circle(head, width);
let to_circle = self.bend_circle(around, width);
let from_cw = self.head_cw(head);
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
}
pub fn head_cw(&self, head: &Head) -> Option<bool> {
if let Head::Segbend(head) = head {
Some(self.layout.primitive(head.segbend.bend).weight().cw)

View File

@ -68,7 +68,7 @@ impl<'a> DebugRouterObserver<'a> {
impl<'a> RouterObserver for DebugRouterObserver<'a> {
fn on_rework(&mut self, tracer: &Tracer, trace: &Trace) {
render_times(
/*render_times(
self.event_pump,
self.canvas,
RouterOrLayout::Layout(tracer.layout),
@ -77,13 +77,13 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
Some(tracer.mesh.clone()),
&trace.path,
20,
);
);*/
}
fn before_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) {
let mut path = trace.path.clone();
path.push(edge.target());
render_times(
/*render_times(
self.event_pump,
self.canvas,
RouterOrLayout::Layout(tracer.layout),
@ -92,11 +92,11 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
Some(tracer.mesh.clone()),
&path,
5,
);
);*/
}
fn on_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) {
render_times(
/*render_times(
self.event_pump,
self.canvas,
RouterOrLayout::Layout(tracer.layout),
@ -105,7 +105,7 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
Some(tracer.mesh.clone()),
&trace.path,
5,
);
);*/
}
fn on_estimate(&mut self, _tracer: &Tracer, _vertex: VertexIndex) {}
@ -145,7 +145,18 @@ fn main() {
let dot2 = router
.layout
.add_dot(DotWeight {
net: 1,
net: 15,
circle: Circle {
pos: (100.5, 500.5).into(),
r: 8.0,
},
})
.unwrap();
let dot_end = router
.layout
.add_dot(DotWeight {
net: 10,
circle: Circle {
pos: (470.5, 350.5).into(),
r: 8.0,
@ -284,16 +295,90 @@ fn main() {
},
);
let dot6 = router
.layout
.add_dot(DotWeight {
net: 2,
circle: Circle {
pos: (530.5, 300.5).into(),
r: 8.0,
},
})
.unwrap();
let _ = router.layout.add_seg(
dot5,
dot6,
SegWeight {
net: 20,
width: 16.0,
},
);
/*let dot7 = router
.layout
.add_dot(DotWeight {
net: 2,
circle: Circle {
pos: (400.5, 440.5).into(),
r: 8.0,
},
})
.unwrap();
let _ = router.layout.add_seg(
dot4,
dot7,
SegWeight {
net: 20,
width: 16.0,
},
);*/
render_times(
&mut event_pump,
&mut canvas,
RouterOrLayout::Layout(&router.layout),
None,
None,
None,
&[],
-1,
);
render_times(
&mut event_pump,
&mut canvas,
RouterOrLayout::Router(&mut router),
Some(dot1),
Some(dot2),
Some(dot_end),
None,
&[],
-1,
);
render_times(
&mut event_pump,
&mut canvas,
RouterOrLayout::Layout(&router.layout),
None,
None,
None,
&[],
-1,
);
render_times(
&mut event_pump,
&mut canvas,
RouterOrLayout::Router(&mut router),
Some(dot2),
Some(dot_end),
None,
&[],
-1,
);
render_times(
&mut event_pump,
&mut canvas,
@ -338,11 +423,6 @@ fn render_times(
if let Some(follower) = follower {
let state = event_pump.mouse_state();
/*let _ = router.layout.move_dot(
follower.into_dot().unwrap(),
(state.x() as f64, state.y() as f64).into(),
);*/
if let Some(from) = from {
mesh = router
.reroute(
@ -351,6 +431,10 @@ fn render_times(
&mut DebugRouterObserver::new(event_pump, canvas),
)
.ok();
} else {
let _ = router
.layout
.move_dot(follower, (state.x() as f64, state.y() as f64).into());
}
}
@ -412,7 +496,7 @@ fn render_times(
);*/
}
if let Some(ref mesh) = mesh {
/*if let Some(ref mesh) = mesh {
for edge in mesh.edge_references() {
let endpoints = (mesh.position(edge.source()), mesh.position(edge.target()));
@ -430,7 +514,7 @@ fn render_times(
color,
);
}
}
}*/
//});
canvas.present();

View File

@ -153,7 +153,7 @@ pub fn intersect_circles(circle1: &Circle, circle2: &Circle) -> Vec<Point> {
let p = circle1.pos + delta * (a / d);
let h = (circle1.r * circle1.r - a * a).sqrt();
if h == 0. {
if h == 0.0 {
return [p].into();
}

View File

@ -71,7 +71,7 @@ impl<'a, Weight> Primitive<'a, Weight> {
.weight()
.circle;
core_circle.r + r + 5.0
core_circle.r + r + 3.0
}
pub fn neighbors(&self) -> impl Iterator<Item = TaggedIndex> + '_ {
@ -80,13 +80,15 @@ impl<'a, Weight> Primitive<'a, Weight> {
.map(|index| Index::<Label>::new(index).retag(self.graph.node_weight(index).unwrap()))
}
pub fn find_prev_akin(&self) -> Option<Index<Weight>> {
pub fn prev_bend(&self) -> Option<BendIndex> {
let mut prev_index = self.index.index;
while let Some(index) = self
.graph
.neighbors_directed(prev_index, Incoming)
// Ensure subsequent unwrap doesn't panic.
.filter(|ni| self.graph.find_edge(*ni, prev_index).is_some())
// Filter out non-End edges.
.filter(|ni| {
self.graph
.edge_weight(self.graph.find_edge(*ni, prev_index).unwrap())
@ -97,8 +99,8 @@ impl<'a, Weight> Primitive<'a, Weight> {
{
let weight = *self.graph.node_weight(index).unwrap();
if mem::discriminant(&self.tagged_weight()) == mem::discriminant(&weight) {
return Some(Index::<Weight>::new(index));
if let Some(TaggedWeight::Bend(..)) = self.graph.node_weight(index) {
return Some(BendIndex::new(index));
}
prev_index = index;
@ -124,13 +126,15 @@ impl<'a, Weight> Primitive<'a, Weight> {
.next()
}
pub fn find_next_akin(&self) -> Option<Index<Weight>> {
pub fn next_bend(&self) -> Option<BendIndex> {
let mut prev_index = self.index.index;
while let Some(index) = self
.graph
.neighbors_directed(prev_index, Outgoing)
// Ensure subsequent unwrap doesn't panic.
.filter(|ni| self.graph.find_edge(prev_index, *ni).is_some())
// Filter out non-End edges.
.filter(|ni| {
self.graph
.edge_weight(self.graph.find_edge(prev_index, *ni).unwrap())
@ -141,8 +145,8 @@ impl<'a, Weight> Primitive<'a, Weight> {
{
let weight = *self.graph.node_weight(index).unwrap();
if mem::discriminant(&self.tagged_weight()) == mem::discriminant(&weight) {
return Some(Index::<Weight>::new(index));
if let Some(TaggedWeight::Bend(..)) = self.graph.node_weight(index) {
return Some(BendIndex::new(index));
}
prev_index = index;

View File

@ -60,7 +60,7 @@ impl BendShape {
}
}
fn between_ends(&self, point: Point) -> bool {
pub fn between_ends(&self, point: Point) -> bool {
math::between_vectors(
point - self.c.pos,
self.from - self.c.pos,
@ -69,6 +69,7 @@ impl BendShape {
}
}
// TODO: Use enum_dispatch.
#[derive(Debug, Clone, Copy, EnumAsInner, PartialEq)]
pub enum Shape {
// Intentionally in different order to reorder `self.intersects(...)` properly.

View File

@ -1,7 +1,9 @@
use contracts::debug_ensures;
use crate::{
draw::{BareHead, Draw, Head},
bow::Bow,
draw::{BareHead, Draw, Head, HeadDot, SegbendHead},
graph::{BendIndex, DotIndex, Ends},
layout::Layout,
mesh::{Mesh, MeshEdgeReference, VertexIndex},
rules::Rules,
@ -84,11 +86,159 @@ impl<'a> Tracer<'a> {
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
pub fn step(&mut self, trace: &mut Trace, to: VertexIndex, width: f64) -> Result<(), ()> {
let to_dot = self.mesh.dot(to);
trace.head = Head::from(self.draw().segbend_around_dot(trace.head, to_dot, width)?);
trace.head = Head::from(self.wrap(trace.head, to_dot, width)?);
trace.path.push(to);
Ok(())
}
fn wrap(&mut self, head: Head, around: DotIndex, width: f64) -> Result<SegbendHead, ()> {
let around_pos = self.layout.primitive(around).weight().circle.pos;
let around_primitive = self.layout.primitive(around);
'blk: {
if let Some(mut layer) = self.layout.primitive(around).outer() {
match self.is_under(head, around, layer) {
Some(true) => return self.tuck_around_dot(head, around, width),
Some(false) => (),
None => break 'blk,
}
while let Some(outer) = self.layout.primitive(layer).outer() {
match self.is_under(head, around, outer) {
Some(true) => return self.tuck_around_bend(head, layer, width),
Some(false) => (),
None => break 'blk,
}
layer = outer;
}
return self.tuck_around_bend(head, layer, width);
}
}
self.draw().segbend_around_dot(head, around, width)
}
fn is_under(&mut self, head: Head, around: DotIndex, layer: BendIndex) -> Option<bool> {
let around_pos = self.layout.primitive(around).weight().circle.pos;
if Some(layer) != self.layout.primitive(head.dot()).prev_bend() {
Some(
self.layout
.primitive(layer)
.shape()
.into_bend()
.unwrap()
.between_ends(around_pos),
)
} else {
None
}
}
fn tuck_around_dot(
&mut self,
head: Head,
around: DotIndex,
width: f64,
) -> Result<SegbendHead, ()> {
let outer = self.layout.primitive(around).outer().unwrap();
let head = self
.draw()
.segbend_around_dot(Head::from(head), around, width)?;
self.layout.reattach_bend(outer, head.segbend.bend);
self.redraw_outward(outer)?;
Ok(head)
}
fn tuck_around_bend(
&mut self,
head: Head,
around: BendIndex,
width: f64,
) -> Result<SegbendHead, ()> {
let outer = self.layout.primitive(around).outer().unwrap();
let head = self
.draw()
.segbend_around_bend(Head::from(head), around, width)?;
self.layout.reattach_bend(outer, head.segbend.bend);
self.redraw_outward(outer)?;
Ok(head)
}
fn redraw_outward(&mut self, bend: BendIndex) -> Result<(), ()> {
let mut bows: Vec<Bow> = vec![];
let mut cur_bend = bend;
loop {
bows.push(self.layout.bow(cur_bend));
cur_bend = match self.layout.primitive(cur_bend).outer() {
Some(new_bend) => new_bend,
None => break,
}
}
let core = self.layout.primitive(bend).core().unwrap();
let mut maybe_inner = self.layout.primitive(bend).inner();
for bow in &bows {
self.layout.remove_interior(bow);
}
for bow in &bows {
let ends = bow.ends();
let head = self.draw().start(ends.0);
let width = 5.0;
let segbend_head = if let Some(inner) = maybe_inner {
self.draw().segbend_around_bend(head, inner, width)?
} else {
self.draw().segbend_around_dot(head, core, width)?
};
maybe_inner = Some(segbend_head.segbend.bend);
self.draw().finish(head, ends.1, width)?;
self.relax_band(maybe_inner.unwrap());
}
Ok(())
}
fn relax_band(&mut self, bend: BendIndex) {
let mut prev_bend = bend;
while let Some(cur_bend) = self.layout.primitive(prev_bend).prev_bend() {
if self.layout.primitive(cur_bend).cross_product() >= 0. {
self.release_bow(cur_bend);
}
prev_bend = cur_bend;
}
let mut prev_bend = bend;
while let Some(cur_bend) = self.layout.primitive(prev_bend).next_bend() {
if self.layout.primitive(cur_bend).cross_product() >= 0. {
self.release_bow(cur_bend);
}
prev_bend = cur_bend;
}
}
fn release_bow(&mut self, bend: BendIndex) {
let bow = self.layout.bow(bend);
let ends = bow.ends();
self.layout.remove_interior(&bow);
let head = self.draw().start(ends.0);
let _ = self.draw().finish(head, ends.1, 5.0);
}
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() - 1))]
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
pub fn undo_step(&mut self, trace: &mut Trace) -> Result<(), ()> {